summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/tdi
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/tdi')
-rw-r--r--private/ntos/tdi/acd/acddefs.h100
-rw-r--r--private/ntos/tdi/acd/api.c1556
-rw-r--r--private/ntos/tdi/acd/debug.h74
-rw-r--r--private/ntos/tdi/acd/makefile6
-rw-r--r--private/ntos/tdi/acd/mem.c289
-rw-r--r--private/ntos/tdi/acd/mem.h41
-rw-r--r--private/ntos/tdi/acd/ntdisp.c411
-rw-r--r--private/ntos/tdi/acd/ntinit.c223
-rw-r--r--private/ntos/tdi/acd/rasacd.rc12
-rw-r--r--private/ntos/tdi/acd/request.c303
-rw-r--r--private/ntos/tdi/acd/request.h31
-rw-r--r--private/ntos/tdi/acd/sources46
-rw-r--r--private/ntos/tdi/acd/table.c286
-rw-r--r--private/ntos/tdi/acd/table.h77
-rw-r--r--private/ntos/tdi/acd/timer.c145
-rw-r--r--private/ntos/tdi/dirs32
-rw-r--r--private/ntos/tdi/irda/dirs10
-rw-r--r--private/ntos/tdi/irda/driver/irda.c132
-rw-r--r--private/ntos/tdi/irda/driver/irndis.c706
-rw-r--r--private/ntos/tdi/irda/driver/makefile7
-rw-r--r--private/ntos/tdi/irda/driver/sources15
-rw-r--r--private/ntos/tdi/irda/inc/af_irda.h100
-rw-r--r--private/ntos/tdi/irda/inc/decdirda.h174
-rw-r--r--private/ntos/tdi/irda/inc/irda.h857
-rw-r--r--private/ntos/tdi/irda/inc/irdalink.h34
-rw-r--r--private/ntos/tdi/irda/inc/irerr.h110
-rw-r--r--private/ntos/tdi/irda/inc/irlap.h66
-rw-r--r--private/ntos/tdi/irda/inc/irlaplog.h44
-rw-r--r--private/ntos/tdi/irda/inc/irlmp.h60
-rw-r--r--private/ntos/tdi/irda/inc/irmac.h32
-rw-r--r--private/ntos/tdi/irda/inc/oscfg.h62
-rw-r--r--private/ntos/tdi/irda/inc/tmp.h31
-rw-r--r--private/ntos/tdi/irda/irlap/irlap.c4519
-rw-r--r--private/ntos/tdi/irda/irlap/irlapio.c900
-rw-r--r--private/ntos/tdi/irda/irlap/irlapio.h32
-rw-r--r--private/ntos/tdi/irda/irlap/irlaplog.c265
-rw-r--r--private/ntos/tdi/irda/irlap/irlapp.h299
-rw-r--r--private/ntos/tdi/irda/irlap/makefile6
-rw-r--r--private/ntos/tdi/irda/irlap/sources23
-rw-r--r--private/ntos/tdi/isn/dirs34
-rw-r--r--private/ntos/tdi/isn/flt/debug.c5
-rw-r--r--private/ntos/tdi/isn/flt/debug.h42
-rw-r--r--private/ntos/tdi/isn/flt/dirs22
-rw-r--r--private/ntos/tdi/isn/flt/driver.c443
-rw-r--r--private/ntos/tdi/isn/flt/filter.c856
-rw-r--r--private/ntos/tdi/isn/flt/filter.h288
-rw-r--r--private/ntos/tdi/isn/flt/flt.mak497
-rw-r--r--private/ntos/tdi/isn/flt/fwdbind.c161
-rw-r--r--private/ntos/tdi/isn/flt/fwdbind.h69
-rw-r--r--private/ntos/tdi/isn/flt/mp/makefile6
-rw-r--r--private/ntos/tdi/isn/flt/mp/sources29
-rw-r--r--private/ntos/tdi/isn/flt/nwlnkflt.rc12
-rw-r--r--private/ntos/tdi/isn/flt/precomp.h50
-rw-r--r--private/ntos/tdi/isn/flt/sources.inc51
-rw-r--r--private/ntos/tdi/isn/flt/up/makefile6
-rw-r--r--private/ntos/tdi/isn/flt/up/sources31
-rw-r--r--private/ntos/tdi/isn/fwd/ddreqs.c220
-rw-r--r--private/ntos/tdi/isn/fwd/ddreqs.h149
-rw-r--r--private/ntos/tdi/isn/fwd/debug.c7
-rw-r--r--private/ntos/tdi/isn/fwd/debug.h69
-rw-r--r--private/ntos/tdi/isn/fwd/dirs22
-rw-r--r--private/ntos/tdi/isn/fwd/driver.c1157
-rw-r--r--private/ntos/tdi/isn/fwd/driver.h102
-rw-r--r--private/ntos/tdi/isn/fwd/filterif.c211
-rw-r--r--private/ntos/tdi/isn/fwd/filterif.h126
-rw-r--r--private/ntos/tdi/isn/fwd/fwd.mak2427
-rw-r--r--private/ntos/tdi/isn/fwd/fwddefs.h125
-rw-r--r--private/ntos/tdi/isn/fwd/ipxbind.c462
-rw-r--r--private/ntos/tdi/isn/fwd/ipxbind.h75
-rw-r--r--private/ntos/tdi/isn/fwd/lineind.c323
-rw-r--r--private/ntos/tdi/isn/fwd/lineind.h116
-rw-r--r--private/ntos/tdi/isn/fwd/mp/makefile6
-rw-r--r--private/ntos/tdi/isn/fwd/mp/sources29
-rw-r--r--private/ntos/tdi/isn/fwd/netbios.c311
-rw-r--r--private/ntos/tdi/isn/fwd/netbios.h134
-rw-r--r--private/ntos/tdi/isn/fwd/nwlnkfwd.rc12
-rw-r--r--private/ntos/tdi/isn/fwd/packets.c528
-rw-r--r--private/ntos/tdi/isn/fwd/packets.h464
-rw-r--r--private/ntos/tdi/isn/fwd/precomp.h61
-rw-r--r--private/ntos/tdi/isn/fwd/rcvind.c825
-rw-r--r--private/ntos/tdi/isn/fwd/rcvind.h180
-rw-r--r--private/ntos/tdi/isn/fwd/registry.c273
-rw-r--r--private/ntos/tdi/isn/fwd/registry.h61
-rw-r--r--private/ntos/tdi/isn/fwd/rwlock.h179
-rw-r--r--private/ntos/tdi/isn/fwd/send.c1253
-rw-r--r--private/ntos/tdi/isn/fwd/send.h220
-rw-r--r--private/ntos/tdi/isn/fwd/sources.inc61
-rw-r--r--private/ntos/tdi/isn/fwd/tables.c1512
-rw-r--r--private/ntos/tdi/isn/fwd/tables.h708
-rw-r--r--private/ntos/tdi/isn/fwd/up/makefile6
-rw-r--r--private/ntos/tdi/isn/fwd/up/sources31
-rw-r--r--private/ntos/tdi/isn/inc/bind.h843
-rw-r--r--private/ntos/tdi/isn/inc/ioctls.h155
-rw-r--r--private/ntos/tdi/isn/inc/ipxfltif.h151
-rw-r--r--private/ntos/tdi/isn/inc/isn.h41
-rw-r--r--private/ntos/tdi/isn/ipx/action.c2921
-rw-r--r--private/ntos/tdi/isn/ipx/adapter.c804
-rw-r--r--private/ntos/tdi/isn/ipx/address.c1882
-rw-r--r--private/ntos/tdi/isn/ipx/config.c1715
-rw-r--r--private/ntos/tdi/isn/ipx/config.h132
-rw-r--r--private/ntos/tdi/isn/ipx/device.c612
-rw-r--r--private/ntos/tdi/isn/ipx/dirs22
-rw-r--r--private/ntos/tdi/isn/ipx/driver.c4447
-rw-r--r--private/ntos/tdi/isn/ipx/event.c143
-rw-r--r--private/ntos/tdi/isn/ipx/ind.c4417
-rw-r--r--private/ntos/tdi/isn/ipx/internal.c1342
-rw-r--r--private/ntos/tdi/isn/ipx/ipx.rc12
-rw-r--r--private/ntos/tdi/isn/ipx/ipxprocs.h1675
-rw-r--r--private/ntos/tdi/isn/ipx/ipxtypes.h2144
-rw-r--r--private/ntos/tdi/isn/ipx/isnipx.h554
-rw-r--r--private/ntos/tdi/isn/ipx/loopback.c280
-rw-r--r--private/ntos/tdi/isn/ipx/mac.c3940
-rw-r--r--private/ntos/tdi/isn/ipx/mac.h44
-rw-r--r--private/ntos/tdi/isn/ipx/mp/makefile6
-rw-r--r--private/ntos/tdi/isn/ipx/mp/nwlnkipx.prf89
-rw-r--r--private/ntos/tdi/isn/ipx/mp/sources29
-rw-r--r--private/ntos/tdi/isn/ipx/ndis.c2381
-rw-r--r--private/ntos/tdi/isn/ipx/nwlnkipx.ini191
-rw-r--r--private/ntos/tdi/isn/ipx/nwlnkipx.rc12
-rw-r--r--private/ntos/tdi/isn/ipx/packet.c1560
-rw-r--r--private/ntos/tdi/isn/ipx/precomp.h45
-rw-r--r--private/ntos/tdi/isn/ipx/query.c297
-rw-r--r--private/ntos/tdi/isn/ipx/receive.c493
-rw-r--r--private/ntos/tdi/isn/ipx/rip.c2700
-rw-r--r--private/ntos/tdi/isn/ipx/rt.c1311
-rw-r--r--private/ntos/tdi/isn/ipx/send.c2364
-rw-r--r--private/ntos/tdi/isn/ipx/sources.inc75
-rw-r--r--private/ntos/tdi/isn/ipx/up/makefile6
-rw-r--r--private/ntos/tdi/isn/ipx/up/nwlnkipx.prf89
-rw-r--r--private/ntos/tdi/isn/ipx/up/sources29
-rw-r--r--private/ntos/tdi/isn/ipxroute/ipxroute.c1822
-rw-r--r--private/ntos/tdi/isn/ipxroute/ipxroute.rc13
-rw-r--r--private/ntos/tdi/isn/ipxroute/ipxrtmsg.mc252
-rw-r--r--private/ntos/tdi/isn/ipxroute/makefile6
-rw-r--r--private/ntos/tdi/isn/ipxroute/makefile.inc13
-rw-r--r--private/ntos/tdi/isn/ipxroute/sources36
-rw-r--r--private/ntos/tdi/isn/ipxroute/utils.h55
-rw-r--r--private/ntos/tdi/isn/isnext/cteext.c155
-rw-r--r--private/ntos/tdi/isn/isnext/cteext.h33
-rw-r--r--private/ntos/tdi/isn/isnext/daytona/makefile6
-rw-r--r--private/ntos/tdi/isn/isnext/daytona/sources45
-rw-r--r--private/ntos/tdi/isn/isnext/dirs25
-rw-r--r--private/ntos/tdi/isn/isnext/ipxext.c1989
-rw-r--r--private/ntos/tdi/isn/isnext/ipxext.h16
-rw-r--r--private/ntos/tdi/isn/isnext/isnext.c345
-rw-r--r--private/ntos/tdi/isn/isnext/isnext.def33
-rw-r--r--private/ntos/tdi/isn/isnext/isnext.h306
-rw-r--r--private/ntos/tdi/isn/isnext/isnext.rc12
-rw-r--r--private/ntos/tdi/isn/isnext/nbext.c873
-rw-r--r--private/ntos/tdi/isn/isnext/precomp.h41
-rw-r--r--private/ntos/tdi/isn/isnext/spxext.c1035
-rw-r--r--private/ntos/tdi/isn/isnext/spxext.h16
-rw-r--r--private/ntos/tdi/isn/isnext/traverse.c419
-rw-r--r--private/ntos/tdi/isn/isnext/traverse.h55
-rw-r--r--private/ntos/tdi/isn/nb/action.c221
-rw-r--r--private/ntos/tdi/isn/nb/address.c2406
-rw-r--r--private/ntos/tdi/isn/nb/autodial.c526
-rw-r--r--private/ntos/tdi/isn/nb/bind.c594
-rw-r--r--private/ntos/tdi/isn/nb/cache.c2746
-rw-r--r--private/ntos/tdi/isn/nb/config.c661
-rw-r--r--private/ntos/tdi/isn/nb/config.h70
-rw-r--r--private/ntos/tdi/isn/nb/connect.c3628
-rw-r--r--private/ntos/tdi/isn/nb/datagram.c1089
-rw-r--r--private/ntos/tdi/isn/nb/device.c461
-rw-r--r--private/ntos/tdi/isn/nb/dirs22
-rw-r--r--private/ntos/tdi/isn/nb/driver.c1794
-rw-r--r--private/ntos/tdi/isn/nb/event.c117
-rw-r--r--private/ntos/tdi/isn/nb/frame.c1096
-rw-r--r--private/ntos/tdi/isn/nb/isnnb.h787
-rw-r--r--private/ntos/tdi/isn/nb/mp/makefile6
-rw-r--r--private/ntos/tdi/isn/nb/mp/sources29
-rw-r--r--private/ntos/tdi/isn/nb/nbcount/makefile6
-rw-r--r--private/ntos/tdi/isn/nb/nbcount/nbcount.c177
-rw-r--r--private/ntos/tdi/isn/nb/nbcount/nbcount.rc11
-rw-r--r--private/ntos/tdi/isn/nb/nbcount/sources29
-rw-r--r--private/ntos/tdi/isn/nb/nbiprocs.h1533
-rw-r--r--private/ntos/tdi/isn/nb/nbitypes.h1511
-rw-r--r--private/ntos/tdi/isn/nb/nwlnknb.ini43
-rw-r--r--private/ntos/tdi/isn/nb/nwlnknb.rc12
-rw-r--r--private/ntos/tdi/isn/nb/packet.c1482
-rw-r--r--private/ntos/tdi/isn/nb/precomp.h42
-rw-r--r--private/ntos/tdi/isn/nb/query.c1817
-rw-r--r--private/ntos/tdi/isn/nb/receive.c1307
-rw-r--r--private/ntos/tdi/isn/nb/send.c2886
-rw-r--r--private/ntos/tdi/isn/nb/session.c2450
-rw-r--r--private/ntos/tdi/isn/nb/sources.inc69
-rw-r--r--private/ntos/tdi/isn/nb/timer.c1233
-rw-r--r--private/ntos/tdi/isn/nb/up/makefile6
-rw-r--r--private/ntos/tdi/isn/nb/up/sources29
-rw-r--r--private/ntos/tdi/isn/rip/debug.h62
-rw-r--r--private/ntos/tdi/isn/rip/dirs22
-rw-r--r--private/ntos/tdi/isn/rip/driver.c1023
-rw-r--r--private/ntos/tdi/isn/rip/driver.h150
-rw-r--r--private/ntos/tdi/isn/rip/globals.c86
-rw-r--r--private/ntos/tdi/isn/rip/globals.h369
-rw-r--r--private/ntos/tdi/isn/rip/init.c174
-rw-r--r--private/ntos/tdi/isn/rip/ipxbind.c191
-rw-r--r--private/ntos/tdi/isn/rip/lineind.c430
-rw-r--r--private/ntos/tdi/isn/rip/mp/makefile6
-rw-r--r--private/ntos/tdi/isn/rip/mp/sources29
-rw-r--r--private/ntos/tdi/isn/rip/nbproc.c38
-rw-r--r--private/ntos/tdi/isn/rip/netbios.c155
-rw-r--r--private/ntos/tdi/isn/rip/nicman.c640
-rw-r--r--private/ntos/tdi/isn/rip/nwlnkrip.rc12
-rw-r--r--private/ntos/tdi/isn/rip/packet.h81
-rw-r--r--private/ntos/tdi/isn/rip/rcvind.c448
-rw-r--r--private/ntos/tdi/isn/rip/rcvpkt.c833
-rw-r--r--private/ntos/tdi/isn/rip/registry.c258
-rw-r--r--private/ntos/tdi/isn/rip/ripaux.c455
-rw-r--r--private/ntos/tdi/isn/rip/ripproc.c745
-rw-r--r--private/ntos/tdi/isn/rip/ripsend.c1176
-rw-r--r--private/ntos/tdi/isn/rip/riptimer.c221
-rw-r--r--private/ntos/tdi/isn/rip/route.c179
-rw-r--r--private/ntos/tdi/isn/rip/rtdefs.h327
-rw-r--r--private/ntos/tdi/isn/rip/rttest/makefile6
-rw-r--r--private/ntos/tdi/isn/rip/rttest/nwsap.h75
-rw-r--r--private/ntos/tdi/isn/rip/rttest/rttest.c426
-rw-r--r--private/ntos/tdi/isn/rip/rttest/sources42
-rw-r--r--private/ntos/tdi/isn/rip/rttest/utils.h55
-rw-r--r--private/ntos/tdi/isn/rip/send.c524
-rw-r--r--private/ntos/tdi/isn/rip/sources.inc60
-rw-r--r--private/ntos/tdi/isn/rip/start.c193
-rw-r--r--private/ntos/tdi/isn/rip/stubs.c38
-rw-r--r--private/ntos/tdi/isn/rip/timer.c140
-rw-r--r--private/ntos/tdi/isn/rip/up/makefile6
-rw-r--r--private/ntos/tdi/isn/rip/up/sources29
-rw-r--r--private/ntos/tdi/isn/rip/utils.h77
-rw-r--r--private/ntos/tdi/isn/sockhelp/makefile6
-rw-r--r--private/ntos/tdi/isn/sockhelp/sources32
-rw-r--r--private/ntos/tdi/isn/sockhelp/wshelper.c1778
-rw-r--r--private/ntos/tdi/isn/sockhelp/wshisn.c323
-rw-r--r--private/ntos/tdi/isn/sockhelp/wshisn.def21
-rw-r--r--private/ntos/tdi/isn/sockhelp/wshisn.rc11
-rw-r--r--private/ntos/tdi/isn/sockhelp/wshutil.c189
-rw-r--r--private/ntos/tdi/isn/spx/dirs22
-rw-r--r--private/ntos/tdi/isn/spx/globals.c87
-rw-r--r--private/ntos/tdi/isn/spx/h/fwddecls.h28
-rw-r--r--private/ntos/tdi/isn/spx/h/globals.h67
-rw-r--r--private/ntos/tdi/isn/spx/h/isnspx.h363
-rw-r--r--private/ntos/tdi/isn/spx/h/spxaddr.h426
-rw-r--r--private/ntos/tdi/isn/spx/h/spxbind.h32
-rw-r--r--private/ntos/tdi/isn/spx/h/spxconn.h1666
-rw-r--r--private/ntos/tdi/isn/spx/h/spxdev.h204
-rw-r--r--private/ntos/tdi/isn/spx/h/spxerror.h246
-rw-r--r--private/ntos/tdi/isn/spx/h/spxmem.h142
-rw-r--r--private/ntos/tdi/isn/spx/h/spxntdef.h72
-rw-r--r--private/ntos/tdi/isn/spx/h/spxpkt.h466
-rw-r--r--private/ntos/tdi/isn/spx/h/spxquery.h54
-rw-r--r--private/ntos/tdi/isn/spx/h/spxrecv.h91
-rw-r--r--private/ntos/tdi/isn/spx/h/spxreg.h65
-rw-r--r--private/ntos/tdi/isn/spx/h/spxsend.h34
-rw-r--r--private/ntos/tdi/isn/spx/h/spxtimer.h101
-rw-r--r--private/ntos/tdi/isn/spx/h/spxutils.h178
-rw-r--r--private/ntos/tdi/isn/spx/mp/makefile6
-rw-r--r--private/ntos/tdi/isn/spx/mp/sources29
-rw-r--r--private/ntos/tdi/isn/spx/nwlnkspx.rc12
-rw-r--r--private/ntos/tdi/isn/spx/precomp.h1
-rw-r--r--private/ntos/tdi/isn/spx/sources.inc65
-rw-r--r--private/ntos/tdi/isn/spx/spxaddr.c1729
-rw-r--r--private/ntos/tdi/isn/spx/spxbind.c602
-rw-r--r--private/ntos/tdi/isn/spx/spxconn.c3851
-rw-r--r--private/ntos/tdi/isn/spx/spxcpkt.c4131
-rw-r--r--private/ntos/tdi/isn/spx/spxcutil.c1736
-rw-r--r--private/ntos/tdi/isn/spx/spxdev.c242
-rw-r--r--private/ntos/tdi/isn/spx/spxdrvr.c1008
-rw-r--r--private/ntos/tdi/isn/spx/spxerror.c316
-rw-r--r--private/ntos/tdi/isn/spx/spxmem.c897
-rw-r--r--private/ntos/tdi/isn/spx/spxpkt.c1594
-rw-r--r--private/ntos/tdi/isn/spx/spxquery.c259
-rw-r--r--private/ntos/tdi/isn/spx/spxrecv.c2839
-rw-r--r--private/ntos/tdi/isn/spx/spxreg.c400
-rw-r--r--private/ntos/tdi/isn/spx/spxsend.c262
-rw-r--r--private/ntos/tdi/isn/spx/spxtimer.c637
-rw-r--r--private/ntos/tdi/isn/spx/spxutils.c484
-rw-r--r--private/ntos/tdi/isn/spx/up/makefile6
-rw-r--r--private/ntos/tdi/isn/spx/up/sources29
-rw-r--r--private/ntos/tdi/isnp/dirs28
-rw-r--r--private/ntos/tdi/isnp/inc/bind.h563
-rw-r--r--private/ntos/tdi/isnp/inc/ioctls.h155
-rw-r--r--private/ntos/tdi/isnp/inc/isn.h41
-rw-r--r--private/ntos/tdi/isnp/ipx/action.c1802
-rw-r--r--private/ntos/tdi/isnp/ipx/adapter.c636
-rw-r--r--private/ntos/tdi/isnp/ipx/address.c1843
-rw-r--r--private/ntos/tdi/isnp/ipx/config.c1715
-rw-r--r--private/ntos/tdi/isnp/ipx/config.h132
-rw-r--r--private/ntos/tdi/isnp/ipx/device.c599
-rw-r--r--private/ntos/tdi/isnp/ipx/dirs22
-rw-r--r--private/ntos/tdi/isnp/ipx/driver.c4219
-rw-r--r--private/ntos/tdi/isnp/ipx/event.c143
-rw-r--r--private/ntos/tdi/isnp/ipx/ind.c4047
-rw-r--r--private/ntos/tdi/isnp/ipx/internal.c1233
-rw-r--r--private/ntos/tdi/isnp/ipx/ipxprocs.h1525
-rw-r--r--private/ntos/tdi/isnp/ipx/ipxtypes.h1999
-rw-r--r--private/ntos/tdi/isnp/ipx/isnipx.h531
-rw-r--r--private/ntos/tdi/isnp/ipx/loopback.c280
-rw-r--r--private/ntos/tdi/isnp/ipx/mac.c3793
-rw-r--r--private/ntos/tdi/isnp/ipx/mac.h44
-rw-r--r--private/ntos/tdi/isnp/ipx/mp/makefile6
-rw-r--r--private/ntos/tdi/isnp/ipx/mp/nwlnkipx.prf89
-rw-r--r--private/ntos/tdi/isnp/ipx/mp/sources29
-rw-r--r--private/ntos/tdi/isnp/ipx/ndis.c2204
-rw-r--r--private/ntos/tdi/isnp/ipx/nwlnkipx.ini191
-rw-r--r--private/ntos/tdi/isnp/ipx/nwlnkipx.rc12
-rw-r--r--private/ntos/tdi/isnp/ipx/packet.c1560
-rw-r--r--private/ntos/tdi/isnp/ipx/precomp.h44
-rw-r--r--private/ntos/tdi/isnp/ipx/query.c297
-rw-r--r--private/ntos/tdi/isnp/ipx/receive.c466
-rw-r--r--private/ntos/tdi/isnp/ipx/rip.c2655
-rw-r--r--private/ntos/tdi/isnp/ipx/send.c1651
-rw-r--r--private/ntos/tdi/isnp/ipx/sources.inc74
-rw-r--r--private/ntos/tdi/isnp/ipx/up/makefile6
-rw-r--r--private/ntos/tdi/isnp/ipx/up/nwlnkipx.prf89
-rw-r--r--private/ntos/tdi/isnp/ipx/up/sources29
-rw-r--r--private/ntos/tdi/isnp/nb/action.c221
-rw-r--r--private/ntos/tdi/isnp/nb/address.c2406
-rw-r--r--private/ntos/tdi/isnp/nb/autodial.c526
-rw-r--r--private/ntos/tdi/isnp/nb/bind.c593
-rw-r--r--private/ntos/tdi/isnp/nb/cache.c2746
-rw-r--r--private/ntos/tdi/isnp/nb/config.c661
-rw-r--r--private/ntos/tdi/isnp/nb/config.h70
-rw-r--r--private/ntos/tdi/isnp/nb/connect.c3628
-rw-r--r--private/ntos/tdi/isnp/nb/datagram.c1089
-rw-r--r--private/ntos/tdi/isnp/nb/device.c461
-rw-r--r--private/ntos/tdi/isnp/nb/dirs22
-rw-r--r--private/ntos/tdi/isnp/nb/driver.c1794
-rw-r--r--private/ntos/tdi/isnp/nb/event.c117
-rw-r--r--private/ntos/tdi/isnp/nb/frame.c1095
-rw-r--r--private/ntos/tdi/isnp/nb/isnnb.h787
-rw-r--r--private/ntos/tdi/isnp/nb/mp/makefile6
-rw-r--r--private/ntos/tdi/isnp/nb/mp/sources29
-rw-r--r--private/ntos/tdi/isnp/nb/nbcount/makefile6
-rw-r--r--private/ntos/tdi/isnp/nb/nbcount/nbcount.c177
-rw-r--r--private/ntos/tdi/isnp/nb/nbcount/nbcount.rc11
-rw-r--r--private/ntos/tdi/isnp/nb/nbcount/sources29
-rw-r--r--private/ntos/tdi/isnp/nb/nbiprocs.h1530
-rw-r--r--private/ntos/tdi/isnp/nb/nbitypes.h1511
-rw-r--r--private/ntos/tdi/isnp/nb/nwlnknb.ini43
-rw-r--r--private/ntos/tdi/isnp/nb/nwlnknb.rc12
-rw-r--r--private/ntos/tdi/isnp/nb/packet.c1482
-rw-r--r--private/ntos/tdi/isnp/nb/precomp.h42
-rw-r--r--private/ntos/tdi/isnp/nb/query.c1817
-rw-r--r--private/ntos/tdi/isnp/nb/receive.c1303
-rw-r--r--private/ntos/tdi/isnp/nb/send.c2886
-rw-r--r--private/ntos/tdi/isnp/nb/session.c2450
-rw-r--r--private/ntos/tdi/isnp/nb/sources.inc69
-rw-r--r--private/ntos/tdi/isnp/nb/timer.c1233
-rw-r--r--private/ntos/tdi/isnp/nb/up/makefile6
-rw-r--r--private/ntos/tdi/isnp/nb/up/sources29
-rw-r--r--private/ntos/tdi/isnp/spx/dirs22
-rw-r--r--private/ntos/tdi/isnp/spx/globals.c87
-rw-r--r--private/ntos/tdi/isnp/spx/h/fwddecls.h28
-rw-r--r--private/ntos/tdi/isnp/spx/h/globals.h67
-rw-r--r--private/ntos/tdi/isnp/spx/h/isnspx.h363
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxaddr.h426
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxbind.h32
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxconn.h1666
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxdev.h204
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxerror.h246
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxmem.h142
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxntdef.h72
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxpkt.h466
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxquery.h54
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxrecv.h89
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxreg.h65
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxsend.h34
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxtimer.h101
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxutils.h178
-rw-r--r--private/ntos/tdi/isnp/spx/mp/makefile6
-rw-r--r--private/ntos/tdi/isnp/spx/mp/sources29
-rw-r--r--private/ntos/tdi/isnp/spx/nwlnkspx.rc12
-rw-r--r--private/ntos/tdi/isnp/spx/precomp.h1
-rw-r--r--private/ntos/tdi/isnp/spx/sources.inc65
-rw-r--r--private/ntos/tdi/isnp/spx/spxaddr.c1729
-rw-r--r--private/ntos/tdi/isnp/spx/spxbind.c600
-rw-r--r--private/ntos/tdi/isnp/spx/spxconn.c3862
-rw-r--r--private/ntos/tdi/isnp/spx/spxcpkt.c4131
-rw-r--r--private/ntos/tdi/isnp/spx/spxcutil.c1738
-rw-r--r--private/ntos/tdi/isnp/spx/spxdev.c242
-rw-r--r--private/ntos/tdi/isnp/spx/spxdrvr.c1008
-rw-r--r--private/ntos/tdi/isnp/spx/spxerror.c316
-rw-r--r--private/ntos/tdi/isnp/spx/spxmem.c897
-rw-r--r--private/ntos/tdi/isnp/spx/spxpkt.c1594
-rw-r--r--private/ntos/tdi/isnp/spx/spxquery.c259
-rw-r--r--private/ntos/tdi/isnp/spx/spxrecv.c2837
-rw-r--r--private/ntos/tdi/isnp/spx/spxreg.c400
-rw-r--r--private/ntos/tdi/isnp/spx/spxsend.c262
-rw-r--r--private/ntos/tdi/isnp/spx/spxtimer.c637
-rw-r--r--private/ntos/tdi/isnp/spx/spxutils.c484
-rw-r--r--private/ntos/tdi/isnp/spx/up/makefile6
-rw-r--r--private/ntos/tdi/isnp/spx/up/sources29
-rw-r--r--private/ntos/tdi/loopback/connect.c1593
-rw-r--r--private/ntos/tdi/loopback/datagram.c848
-rw-r--r--private/ntos/tdi/loopback/endpoint.c373
-rw-r--r--private/ntos/tdi/loopback/info.c183
-rw-r--r--private/ntos/tdi/loopback/loopback.c1284
-rw-r--r--private/ntos/tdi/loopback/loopback.h433
-rw-r--r--private/ntos/tdi/loopback/loopdbg.h58
-rw-r--r--private/ntos/tdi/loopback/loopsub.c379
-rw-r--r--private/ntos/tdi/loopback/makefile6
-rw-r--r--private/ntos/tdi/loopback/sources46
-rw-r--r--private/ntos/tdi/loopback/transfer.c859
-rw-r--r--private/ntos/tdi/nbf/action.c642
-rw-r--r--private/ntos/tdi/nbf/address.c3046
-rw-r--r--private/ntos/tdi/nbf/autodial.c502
-rw-r--r--private/ntos/tdi/nbf/connect.c1700
-rw-r--r--private/ntos/tdi/nbf/connobj.c2413
-rw-r--r--private/ntos/tdi/nbf/devctx.c408
-rw-r--r--private/ntos/tdi/nbf/dlc.c3270
-rw-r--r--private/ntos/tdi/nbf/event.c190
-rw-r--r--private/ntos/tdi/nbf/framecon.c1087
-rw-r--r--private/ntos/tdi/nbf/framesnd.c2504
-rw-r--r--private/ntos/tdi/nbf/iframes.c3339
-rw-r--r--private/ntos/tdi/nbf/info.c3487
-rw-r--r--private/ntos/tdi/nbf/link.c2315
-rw-r--r--private/ntos/tdi/nbf/linktree.c537
-rw-r--r--private/ntos/tdi/nbf/makefile6
-rw-r--r--private/ntos/tdi/nbf/nbf.h166
-rw-r--r--private/ntos/tdi/nbf/nbf.rc12
-rw-r--r--private/ntos/tdi/nbf/nbfcnfg.c1155
-rw-r--r--private/ntos/tdi/nbf/nbfcnfg.h102
-rw-r--r--private/ntos/tdi/nbf/nbfconst.h436
-rw-r--r--private/ntos/tdi/nbf/nbfdebug.c646
-rw-r--r--private/ntos/tdi/nbf/nbfdrvr.c2493
-rw-r--r--private/ntos/tdi/nbf/nbfhdrs.h257
-rw-r--r--private/ntos/tdi/nbf/nbfmac.c417
-rw-r--r--private/ntos/tdi/nbf/nbfmac.h766
-rw-r--r--private/ntos/tdi/nbf/nbfndis.c1956
-rw-r--r--private/ntos/tdi/nbf/nbfpnp.c210
-rw-r--r--private/ntos/tdi/nbf/nbfprocs.h2322
-rw-r--r--private/ntos/tdi/nbf/nbftypes.h2202
-rw-r--r--private/ntos/tdi/nbf/packet.c1808
-rw-r--r--private/ntos/tdi/nbf/precomp.h219
-rw-r--r--private/ntos/tdi/nbf/rcv.c309
-rw-r--r--private/ntos/tdi/nbf/rcveng.c823
-rw-r--r--private/ntos/tdi/nbf/request.c1376
-rw-r--r--private/ntos/tdi/nbf/send.c503
-rw-r--r--private/ntos/tdi/nbf/sendeng.c3657
-rw-r--r--private/ntos/tdi/nbf/sources79
-rw-r--r--private/ntos/tdi/nbf/spnlckdb.c156
-rw-r--r--private/ntos/tdi/nbf/testnbf.c1466
-rw-r--r--private/ntos/tdi/nbf/testtdi.c291
-rw-r--r--private/ntos/tdi/nbf/timer.c2762
-rw-r--r--private/ntos/tdi/nbf/uframes.c2974
-rw-r--r--private/ntos/tdi/st/address.c2247
-rw-r--r--private/ntos/tdi/st/connect.c1137
-rw-r--r--private/ntos/tdi/st/connobj.c1375
-rw-r--r--private/ntos/tdi/st/devctx.c256
-rw-r--r--private/ntos/tdi/st/event.c185
-rw-r--r--private/ntos/tdi/st/framesnd.c371
-rw-r--r--private/ntos/tdi/st/iframes.c808
-rw-r--r--private/ntos/tdi/st/ind.c829
-rw-r--r--private/ntos/tdi/st/info.c865
-rw-r--r--private/ntos/tdi/st/makefile6
-rw-r--r--private/ntos/tdi/st/oemnxpts.inf446
-rw-r--r--private/ntos/tdi/st/packet.c597
-rw-r--r--private/ntos/tdi/st/rcv.c247
-rw-r--r--private/ntos/tdi/st/rcveng.c383
-rw-r--r--private/ntos/tdi/st/request.c801
-rw-r--r--private/ntos/tdi/st/send.c385
-rw-r--r--private/ntos/tdi/st/sendeng.c1505
-rw-r--r--private/ntos/tdi/st/sources62
-rw-r--r--private/ntos/tdi/st/st.h46
-rw-r--r--private/ntos/tdi/st/st.rc12
-rw-r--r--private/ntos/tdi/st/stcnfg.c1277
-rw-r--r--private/ntos/tdi/st/stcnfg.h57
-rw-r--r--private/ntos/tdi/st/stconst.h127
-rw-r--r--private/ntos/tdi/st/stdrvr.c1627
-rw-r--r--private/ntos/tdi/st/sthdrs.h69
-rw-r--r--private/ntos/tdi/st/stmac.c356
-rw-r--r--private/ntos/tdi/st/stmac.h635
-rw-r--r--private/ntos/tdi/st/stndis.c986
-rw-r--r--private/ntos/tdi/st/stprocs.h923
-rw-r--r--private/ntos/tdi/st/sttypes.h1103
-rw-r--r--private/ntos/tdi/st/uframes.c980
-rw-r--r--private/ntos/tdi/tcpip/dirs28
-rw-r--r--private/ntos/tdi/tcpip/h/oscfg.h72
-rw-r--r--private/ntos/tdi/tcpip/h/packoff.h37
-rw-r--r--private/ntos/tdi/tcpip/h/packon.h35
-rw-r--r--private/ntos/tdi/tcpip/h/queue.h87
-rw-r--r--private/ntos/tdi/tcpip/h/tdint.h41
-rw-r--r--private/ntos/tdi/tcpip/ip/arp.c4839
-rw-r--r--private/ntos/tdi/tcpip/ip/arp.h21
-rw-r--r--private/ntos/tdi/tcpip/ip/arpdef.h340
-rw-r--r--private/ntos/tdi/tcpip/ip/dirs22
-rw-r--r--private/ntos/tdi/tcpip/ip/icmp.c1698
-rw-r--r--private/ntos/tdi/tcpip/ip/icmp.h70
-rw-r--r--private/ntos/tdi/tcpip/ip/igmp.c799
-rw-r--r--private/ntos/tdi/tcpip/ip/igmp.h42
-rw-r--r--private/ntos/tdi/tcpip/ip/info.c609
-rw-r--r--private/ntos/tdi/tcpip/ip/info.h22
-rw-r--r--private/ntos/tdi/tcpip/ip/init.c3509
-rw-r--r--private/ntos/tdi/tcpip/ip/ipdef.h371
-rw-r--r--private/ntos/tdi/tcpip/ip/ipinit.h155
-rw-r--r--private/ntos/tdi/tcpip/ip/iploop.c665
-rw-r--r--private/ntos/tdi/tcpip/ip/iprcv.c1145
-rw-r--r--private/ntos/tdi/tcpip/ip/iproute.c4703
-rw-r--r--private/ntos/tdi/tcpip/ip/iproute.h107
-rw-r--r--private/ntos/tdi/tcpip/ip/iprtdef.h135
-rw-r--r--private/ntos/tdi/tcpip/ip/ipstatus.c205
-rw-r--r--private/ntos/tdi/tcpip/ip/ipxmit.c1949
-rw-r--r--private/ntos/tdi/tcpip/ip/ipxmit.h34
-rw-r--r--private/ntos/tdi/tcpip/ip/mp/makefile6
-rw-r--r--private/ntos/tdi/tcpip/ip/mp/sources27
-rw-r--r--private/ntos/tdi/tcpip/ip/ntip.c3361
-rw-r--r--private/ntos/tdi/tcpip/ip/ntirp.c1458
-rw-r--r--private/ntos/tdi/tcpip/ip/ntreg.c672
-rw-r--r--private/ntos/tdi/tcpip/ip/sources.inc59
-rw-r--r--private/ntos/tdi/tcpip/ip/up/makefile6
-rw-r--r--private/ntos/tdi/tcpip/ip/up/sources27
-rw-r--r--private/ntos/tdi/tcpip/tcp/addr.c2061
-rw-r--r--private/ntos/tdi/tcpip/tcp/addr.h211
-rw-r--r--private/ntos/tdi/tcpip/tcp/alpha/sources3
-rw-r--r--private/ntos/tdi/tcpip/tcp/alpha/xsum.s271
-rw-r--r--private/ntos/tdi/tcpip/tcp/dgram.c990
-rw-r--r--private/ntos/tdi/tcpip/tcp/dgram.h89
-rw-r--r--private/ntos/tdi/tcpip/tcp/dirs22
-rw-r--r--private/ntos/tdi/tcpip/tcp/i386/sources4
-rw-r--r--private/ntos/tdi/tcpip/tcp/i386/xsum.asm259
-rw-r--r--private/ntos/tdi/tcpip/tcp/info.c917
-rw-r--r--private/ntos/tdi/tcpip/tcp/info.h51
-rw-r--r--private/ntos/tdi/tcpip/tcp/init.c597
-rw-r--r--private/ntos/tdi/tcpip/tcp/mips/sources4
-rw-r--r--private/ntos/tdi/tcpip/tcp/mips/xsum.s243
-rw-r--r--private/ntos/tdi/tcpip/tcp/mp/makefile6
-rw-r--r--private/ntos/tdi/tcpip/tcp/mp/sources30
-rw-r--r--private/ntos/tdi/tcpip/tcp/mp/tcpip.prf297
-rw-r--r--private/ntos/tdi/tcpip/tcp/ntautodl.c258
-rw-r--r--private/ntos/tdi/tcpip/tcp/ntdisp.c4063
-rw-r--r--private/ntos/tdi/tcpip/tcp/ntinit.c1038
-rw-r--r--private/ntos/tdi/tcpip/tcp/ppc/sources4
-rw-r--r--private/ntos/tdi/tcpip/tcp/ppc/xsum.s257
-rw-r--r--private/ntos/tdi/tcpip/tcp/raw.c693
-rw-r--r--private/ntos/tdi/tcpip/tcp/raw.h34
-rw-r--r--private/ntos/tdi/tcpip/tcp/secfltr.c1425
-rw-r--r--private/ntos/tdi/tcpip/tcp/secfltr.h61
-rw-r--r--private/ntos/tdi/tcpip/tcp/sources.inc67
-rw-r--r--private/ntos/tdi/tcpip/tcp/tcb.c1524
-rw-r--r--private/ntos/tdi/tcpip/tcp/tcb.h67
-rw-r--r--private/ntos/tdi/tcpip/tcp/tcp.h426
-rw-r--r--private/ntos/tdi/tcpip/tcp/tcpcfg.h86
-rw-r--r--private/ntos/tdi/tcpip/tcp/tcpconn.c2344
-rw-r--r--private/ntos/tdi/tcpip/tcp/tcpconn.h124
-rw-r--r--private/ntos/tdi/tcpip/tcp/tcpdeb.c169
-rw-r--r--private/ntos/tdi/tcpip/tcp/tcpdeb.h78
-rw-r--r--private/ntos/tdi/tcpip/tcp/tcpdeliv.c1971
-rw-r--r--private/ntos/tdi/tcpip/tcp/tcpdeliv.h44
-rw-r--r--private/ntos/tdi/tcpip/tcp/tcpip.def8
-rw-r--r--private/ntos/tdi/tcpip/tcp/tcpip.rc12
-rw-r--r--private/ntos/tdi/tcpip/tcp/tcprcv.c3397
-rw-r--r--private/ntos/tdi/tcpip/tcp/tcprcv.h74
-rw-r--r--private/ntos/tdi/tcpip/tcp/tcpsend.c2666
-rw-r--r--private/ntos/tdi/tcpip/tcp/tcpsend.h105
-rw-r--r--private/ntos/tdi/tcpip/tcp/tlcommon.c553
-rw-r--r--private/ntos/tdi/tcpip/tcp/tlcommon.h46
-rw-r--r--private/ntos/tdi/tcpip/tcp/udp.c673
-rw-r--r--private/ntos/tdi/tcpip/tcp/udp.h39
-rw-r--r--private/ntos/tdi/tcpip/tcp/up/makefile6
-rw-r--r--private/ntos/tdi/tcpip/tcp/up/sources30
-rw-r--r--private/ntos/tdi/tcpip/tcp/up/tcpip.prf297
-rw-r--r--private/ntos/tdi/wrapper/cxport.c723
-rw-r--r--private/ntos/tdi/wrapper/makefile6
-rw-r--r--private/ntos/tdi/wrapper/sources49
-rw-r--r--private/ntos/tdi/wrapper/tdi.c1737
-rw-r--r--private/ntos/tdi/wrapper/tdi.def44
-rw-r--r--private/ntos/tdi/wrapper/tdi.pnp44
-rw-r--r--private/ntos/tdi/wrapper/tdi.rc12
-rw-r--r--private/ntos/tdi/wrapper/tdidebug.h52
-rw-r--r--private/ntos/tdi/wrapper/tdipnp.c1029
-rw-r--r--private/ntos/tdi/wrapper/tdipnp.h163
569 files changed, 376041 insertions, 0 deletions
diff --git a/private/ntos/tdi/acd/acddefs.h b/private/ntos/tdi/acd/acddefs.h
new file mode 100644
index 000000000..0563e9926
--- /dev/null
+++ b/private/ntos/tdi/acd/acddefs.h
@@ -0,0 +1,100 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ acddefs.h
+
+Abstract:
+
+ Shared internal structure defintions for the Implicit
+ Connection Driver (acd.sys).
+
+Author:
+
+ Anthony Discolo (adiscolo) 23-Jun-1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+--*/
+
+#ifndef _ACDDEFS_
+#define _ACDDEFS_
+
+//
+// Min macro
+//
+#define MIN(a, b) (a) < (b) ? (a) : (b)
+
+//
+// List entry structure for the AcdCompletionQueue.
+//
+typedef struct _ACD_COMPLETION {
+ LIST_ENTRY ListEntry;
+ ULONG ulDriverId; // transport driver id
+ BOOLEAN fCanceled; // TRUE if request was canceled
+ BOOLEAN fCompleted; // TRUE if request was completed
+ ACD_NOTIFICATION notif;
+ ACD_CONNECT_CALLBACK pProc; // callback proc
+ USHORT nArgs; // argument count
+ PVOID pArgs[1]; // variable length arguments
+} ACD_COMPLETION, *PACD_COMPLETION;
+
+//
+// A connection block.
+//
+// For each pending connection, there is a
+// connection block that describes the current
+// state.
+//
+typedef struct _ACD_CONNECTION {
+ LIST_ENTRY ListEntry; // connection list
+ BOOLEAN fNotif; // TRUE if service has been notified
+ BOOLEAN fProgressPing; // TRUE if service has pinged
+ BOOLEAN fCompleting; // TRUE if in AcdSignalCompletionCommon
+ ULONG ulTimerCalls; // # of total pings
+ ULONG ulMissedPings; // # of missed pings
+ LIST_ENTRY CompletionList; // completion list
+} ACD_CONNECTION, *PACD_CONNECTION;
+
+//
+// Generic hash table entry.
+//
+typedef struct _HASH_ENTRY {
+ LIST_ENTRY ListEntry;
+ ACD_ADDR szKey;
+ ULONG ulData;
+} HASH_ENTRY, *PHASH_ENTRY;
+
+extern KSPIN_LOCK AcdSpinLockG;
+
+extern KEVENT AcdRequestThreadEventG;
+
+extern LIST_ENTRY AcdNotificationQueueG;
+extern LIST_ENTRY AcdCompletionQueueG;
+extern LIST_ENTRY AcdConnectionQueueG;
+extern LIST_ENTRY AcdDriverListG;
+
+extern BOOLEAN fConnectionInProgressG;
+extern BOOLEAN fProgressPingG;
+extern ULONG nTimerCallsG;
+extern ULONG nMissedPingsG;
+
+extern PDEVICE_OBJECT pAcdDeviceObjectG;
+
+extern ACD_ADDR szComputerName;
+
+//
+// Miscellaneous routines.
+//
+VOID
+AcdPrintAddress(
+ IN PACD_ADDR pAddr
+ );
+
+#endif // _ACDDEFS_
diff --git a/private/ntos/tdi/acd/api.c b/private/ntos/tdi/acd/api.c
new file mode 100644
index 000000000..4ad13b54f
--- /dev/null
+++ b/private/ntos/tdi/acd/api.c
@@ -0,0 +1,1556 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ api.c
+
+Abstract:
+
+ Exported routines to transports for automatic connection
+ management.
+
+Author:
+
+ Anthony Discolo (adiscolo) 17-Apr-1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+--*/
+
+#include <ntifs.h>
+#include <cxport.h>
+#include <tdi.h>
+#include <tdikrnl.h>
+#include <tdistat.h>
+#include <tdiinfo.h>
+#include <acd.h>
+
+#include "acdapi.h"
+#include "acddefs.h"
+#include "request.h"
+#include "mem.h"
+#include "debug.h"
+
+//
+// Driver enabled mode. The automatic
+// connection system service sets
+// this depending on whether a user
+// has logged in, and whether there's
+// general network connectivity.
+//
+BOOLEAN fAcdEnabledG;
+
+//
+// Spin lock for this module.
+//
+KSPIN_LOCK AcdSpinLockG;
+
+//
+// Event signaled when the AcdNotificationRequestThread
+// thread has a notification to process.
+//
+KEVENT AcdRequestThreadEventG;
+
+//
+// This is a list of one irp representing
+// a user-space process waiting to create a
+// new network connection given an address.
+//
+LIST_ENTRY AcdNotificationQueueG;
+
+//
+// This is a list of ACD_CONNECTION blocks representing
+// requests from transports about unsuccessful connection
+// attempts. There may be multiple ACD_COMPLETION block
+// linked onto the same ACD_CONNECTION, grouped by
+// address.
+//
+LIST_ENTRY AcdConnectionQueueG;
+
+//
+// This is a list of ACD_COMPLETION blocks representing
+// other requests from transports.
+//
+LIST_ENTRY AcdCompletionQueueG;
+
+//
+// The list of drivers that have binded
+// with us.
+//
+LIST_ENTRY AcdDriverListG;
+
+//
+// Statistics
+//
+typedef struct _ACD_STATS {
+ ULONG ulConnects; // connection attempts
+ ULONG ulCancels; // connection cancels
+} ACD_STATS;
+ACD_STATS AcdStatsG[ACD_ADDR_MAX];
+
+//
+// Forward declarations
+//
+VOID
+AcdPrintAddress(
+ IN PACD_ADDR pAddr
+ );
+
+VOID
+ClearRequests(
+ IN KIRQL irql
+ );
+
+//
+// External variables
+//
+extern ULONG ulAcdOpenCountG;
+
+
+
+VOID
+SetDriverMode(
+ IN BOOLEAN fEnable
+ )
+
+/*++
+
+DESCRIPTION
+ Set the global driver mode value, and inform
+ all bound transports of the change.
+
+ Note: this call assumes AcdSpinLockG is already
+ acquired.
+
+ARGUMENTS
+ fEnable: the new driver mode value
+
+RETURN VALUE
+ None.
+
+--*/
+
+{
+ KIRQL dirql;
+ PLIST_ENTRY pEntry;
+ PACD_DRIVER pDriver;
+
+ //
+ // Set the new global driver mode value.
+ //
+ fAcdEnabledG = fEnable;
+ //
+ // Inform all the drivers that have binded
+ // with us of the new enable mode.
+ //
+ for (pEntry = AcdDriverListG.Flink;
+ pEntry != &AcdDriverListG;
+ pEntry = pEntry->Flink)
+ {
+ pDriver = CONTAINING_RECORD(pEntry, ACD_DRIVER, ListEntry);
+
+ KeAcquireSpinLock(&pDriver->SpinLock, &dirql);
+ pDriver->fEnabled = fEnable;
+ KeReleaseSpinLock(&pDriver->SpinLock, dirql);
+ }
+} // SetDriverMode
+
+
+
+NTSTATUS
+AcdEnable(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ )
+
+/*++
+
+DESCRIPTION
+ Set the enable mode for the driver. This determines
+ which notifications it will pass up to the automatic
+ connection system service.
+
+ARGUMENTS
+ pIrp: a pointer to the irp to be enqueued.
+
+ pIrpSp: a pointer to the current irp stack.
+
+RETURN VALUE
+ STATUS_BUFFER_TOO_SMALL: the supplied user buffer is too small to hold
+ an ACD_ENABLE_MODE value.
+
+ STATUS_SUCCESS: if the enabled bit was set successfully.
+
+--*/
+
+{
+ KIRQL irql;
+ BOOLEAN fEnable;
+
+ //
+ // Verify the input buffer is sufficient to hold
+ // a BOOLEAN structure.
+ //
+ if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
+ sizeof (BOOLEAN))
+ {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ KeAcquireSpinLock(&AcdSpinLockG, &irql);
+ fEnable = *(BOOLEAN *)pIrp->AssociatedIrp.SystemBuffer;
+ SetDriverMode(fEnable);
+ //
+ // Clear all pending requests if
+ // we are disabling the driver.
+ //
+ if (!fEnable)
+ ClearRequests(irql);
+ KeReleaseSpinLock(&AcdSpinLockG, irql);
+
+ return STATUS_SUCCESS;
+} // AcdEnable
+
+
+
+VOID
+CancelNotification(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ )
+
+/*++
+
+DESCRIPTION
+ Generic cancel routine for irps on the AcdNotificationQueueG.
+
+ARGUMENTS
+ pDeviceObject: unused
+
+ pIrp: pointer to the irp to be cancelled.
+
+RETURN VALUE
+ None.
+
+--*/
+
+{
+ KIRQL irql;
+
+ UNREFERENCED_PARAMETER(pDeviceObject);
+ //
+ // Mark this irp as cancelled.
+ //
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+ pIrp->IoStatus.Information = 0;
+ //
+ // Release the spin lock the I/O system acquired.
+ //
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+ //
+ // Remove it from our list.
+ //
+ KeAcquireSpinLock(&AcdSpinLockG, &irql);
+ RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);
+ KeReleaseSpinLock(&AcdSpinLockG, irql);
+ //
+ // Complete the request.
+ //
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+} // CancelNotification
+
+
+
+VOID
+AcdCancelNotifications()
+
+/*++
+
+DESCRIPTION
+ Cancel all irps on the AcdNotification queue. Although
+ technically more than one user address space can be waiting
+ for these notifications, we allow only one at this time.
+
+ARGUMENTS
+ None.
+
+RETURN VALUE
+ None.
+
+--*/
+
+{
+ KIRQL irql;
+ PLIST_ENTRY pHead;
+ PIRP pIrp;
+ PIO_STACK_LOCATION pIrpSp;
+
+ //
+ // Complete all the irps in the list.
+ //
+ while ((pHead = ExInterlockedRemoveHeadList(
+ &AcdNotificationQueueG,
+ &AcdSpinLockG)) != NULL)
+ {
+ pIrp = CONTAINING_RECORD(pHead, IRP, Tail.Overlay.ListEntry);
+ //
+ // Mark this irp as cancelled.
+ //
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+ pIrp->IoStatus.Information = 0;
+ //
+ // Complete the irp.
+ //
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+ }
+} // AcdCancelNotifications
+
+
+
+NTSTATUS
+AcdWaitForNotification(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ )
+
+/*++
+
+DESCRIPTION
+ Enqueue an connection notification irp. This is done
+ done by the automatic connection system service.
+
+ARGUMENTS
+ pIrp: a pointer to the irp to be enqueued.
+
+ pIrpSp: a pointer to the current irp stack.
+
+RETURN VALUE
+ STATUS_BUFFER_TOO_SMALL: the supplied user buffer is too small to hold
+ an ACD_NOTIFICATION structure.
+
+ STATUS_PENDING: if the ioctl was successfully enqueued
+
+ STATUS_SUCCESS: if there is a notification already available
+
+--*/
+
+{
+ KIRQL irql, irql2;
+ PLIST_ENTRY pHead;
+ PACD_COMPLETION pCompletion;
+ PACD_NOTIFICATION pNotification;
+ PEPROCESS pProcess;
+
+ //
+ // Verify the output buffer is sufficient to hold
+ // an ACD_NOTIFICATION structure.
+ //
+ if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength <
+ sizeof (ACD_NOTIFICATION))
+ {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+ IoAcquireCancelSpinLock(&irql);
+ KeAcquireSpinLock(&AcdSpinLockG, &irql2);
+ //
+ // There is no notification available.
+ // Mark the irp as pending and wait for one.
+ //
+ pIrp->IoStatus.Status = STATUS_PENDING;
+ IoMarkIrpPending(pIrp);
+ //
+ // Set the irp's cancel routine.
+ //
+ IoSetCancelRoutine(pIrp, CancelNotification);
+ //
+ // Append the irp at the end of the
+ // connection notification list.
+ //
+ InsertTailList(&AcdNotificationQueueG, &pIrp->Tail.Overlay.ListEntry);
+ //
+ // Signal the request thread there is
+ // work to do.
+ //
+ KeSetEvent(&AcdRequestThreadEventG, 0, FALSE);
+
+ KeReleaseSpinLock(&AcdSpinLockG, irql2);
+ IoReleaseCancelSpinLock(irql);
+
+ return STATUS_PENDING;
+} // AcdWaitForNotification
+
+
+
+BOOLEAN
+EqualAddress(
+ IN PACD_ADDR p1,
+ IN PACD_ADDR p2
+ )
+{
+ ULONG i;
+
+ if (p1->fType != p2->fType)
+ return FALSE;
+
+ switch (p1->fType) {
+ case ACD_ADDR_IP:
+ return (p1->ulIpaddr == p2->ulIpaddr);
+ case ACD_ADDR_IPX:
+ return (BOOLEAN)RtlEqualMemory(
+ &p1->cNode,
+ &p2->cNode,
+ ACD_ADDR_IPX_LEN);
+ case ACD_ADDR_NB:
+ IF_ACDDBG(ACD_DEBUG_CONNECTION) {
+ AcdPrint((
+ "EqualAddress: NB: (%15s,%15s) result=%d\n",
+ p1->cNetbios,
+ p2->cNetbios,
+ RtlEqualMemory(&p1->cNetbios, &p2->cNetbios, ACD_ADDR_NB_LEN - 1)));
+ }
+ return (BOOLEAN)RtlEqualMemory(
+ &p1->cNetbios,
+ &p2->cNetbios,
+ ACD_ADDR_NB_LEN - 1);
+ case ACD_ADDR_INET:
+ for (i = 0; i < ACD_ADDR_INET_LEN; i++) {
+ if (p1->szInet[i] != p2->szInet[i])
+ return FALSE;
+ if (p1->szInet[i] == '\0' || p2->szInet[i] == '\0')
+ break;
+ }
+ return TRUE;
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+ return FALSE;
+} // EqualAddress
+
+
+
+PACD_CONNECTION
+FindConnection(
+ IN PACD_ADDR pAddr
+ )
+
+/*++
+
+DESCRIPTION
+ Search for a connection block with the specified
+ address.
+
+ARGUMENTS
+ pAddr: a pointer to the target ACD_ADDR
+
+RETURN VALUE
+ A PACD_CONNECTION with the specified address, if found;
+ otherwise NULL.
+
+--*/
+
+{
+ PLIST_ENTRY pEntry;
+ PACD_CONNECTION pConnection;
+ PACD_COMPLETION pCompletion;
+
+ for (pEntry = AcdConnectionQueueG.Flink;
+ pEntry != &AcdConnectionQueueG;
+ pEntry = pEntry->Flink)
+ {
+ pConnection = CONTAINING_RECORD(pEntry, ACD_CONNECTION, ListEntry);
+ pCompletion = CONTAINING_RECORD(pConnection->CompletionList.Flink, ACD_COMPLETION, ListEntry);
+
+ if (EqualAddress(pAddr, &pCompletion->notif.addr))
+ return pConnection;
+ }
+
+ return NULL;
+} // FindConnection
+
+
+
+NTSTATUS
+AcdConnectionInProgress(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ )
+
+/*++
+
+DESCRIPTION
+ Refresh the progress indicator for the connection
+ attempt. If the progress indicator is not updated
+ by the user
+
+ARGUMENTS
+ pIrp: a pointer to the irp to be enqueued.
+
+ pIrpSp: a pointer to the current irp stack.
+
+RETURN VALUE
+ STATUS_INVALID_CONNECTION: if there is no connection
+ attempt in progress.
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ KIRQL irql;
+ PACD_STATUS pStatus;
+ PACD_CONNECTION pConnection;
+
+ //
+ // Verify the input buffer is sufficient to hold
+ // a BOOLEAN structure.
+ //
+ if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
+ sizeof (ACD_STATUS))
+ {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Get the success code from the
+ // connection attempt and pass it
+ // to the completion routine.
+ //
+ pStatus = (PACD_STATUS)pIrp->AssociatedIrp.SystemBuffer;
+ KeAcquireSpinLock(&AcdSpinLockG, &irql);
+ pConnection = FindConnection(&pStatus->addr);
+ if (pConnection != NULL)
+ pConnection->fProgressPing = TRUE;
+ KeReleaseSpinLock(&AcdSpinLockG, irql);
+
+ return (pConnection != NULL) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
+} // AcdConnectionInProgress
+
+
+
+BOOLEAN
+AddCompletionToConnection(
+ IN PACD_COMPLETION pCompletion
+ )
+{
+ PACD_CONNECTION pConnection;
+
+ pConnection = FindConnection(&pCompletion->notif.addr);
+ //
+ // If the connection already exists, then add
+ // the completion request to its list.
+ //
+ if (pConnection != NULL) {
+ InsertTailList(&pConnection->CompletionList, &pCompletion->ListEntry);
+ return TRUE;
+ }
+ //
+ // This is a connection to a new address.
+ // Create the connection block, enqueue it,
+ // and start the connection timer.
+ //
+ ALLOCATE_MEMORY(ACD_OBJECT_CONNECTION, pConnection);
+ if (pConnection == NULL) {
+ DbgPrint("AddCompletionToConnection: ExAllocatePool failed\n");
+ return FALSE;
+ }
+ pConnection->fNotif = FALSE;
+ pConnection->fProgressPing = FALSE;
+ pConnection->fCompleting = FALSE;
+ pConnection->ulTimerCalls = 0;
+ pConnection->ulMissedPings = 0;
+ InitializeListHead(&pConnection->CompletionList);
+ InsertHeadList(&pConnection->CompletionList, &pCompletion->ListEntry);
+ InsertTailList(&AcdConnectionQueueG, &pConnection->ListEntry);
+ return TRUE;
+} // AddCompletionToConnection
+
+
+
+BOOLEAN
+AddCompletionBlock(
+ IN ULONG ulDriverId,
+ IN PACD_ADDR pAddr,
+ IN ULONG ulFlags,
+ IN PACD_ADAPTER pAdapter,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN USHORT nArgs,
+ IN PVOID *pArgs
+ )
+
+/*++
+
+DESCRIPTION
+ Create a block that represents an outstanding
+ transport request waiting for an automatic
+ connection. Link this block into the global
+ list of outstanding transport requests.
+
+ARGUMENTS
+ ulDriverId: a unique value for the transport driver
+
+ pAddr: the network address of the connection
+
+ ulFlags: connection flags
+
+ pAdapter: pointer to adapter identifier
+
+ pProc: a completion callback procedure
+
+ nArgs: the number of parameters passed in pArgs
+
+ pArgs: the parameters to pProc
+
+RETURN VALUE
+ TRUE if successful, FALSE otherwise
+
+--*/
+
+{
+ PACD_COMPLETION pCompletion;
+ ULONG i;
+
+ ALLOCATE_MEMORY(
+ sizeof (ACD_COMPLETION) + ((nArgs - 1) * sizeof (PVOID)),
+ pCompletion);
+ if (pCompletion == NULL) {
+ DbgPrint("AcdAddCompletionBlock: ExAllocatePool failed\n");
+ return FALSE;
+ }
+ //
+ // Copy the arguments into the information block.
+ //
+ pCompletion->ulDriverId = ulDriverId;
+ pCompletion->fCanceled = FALSE;
+ pCompletion->fCompleted = FALSE;
+ RtlCopyMemory(&pCompletion->notif.addr, pAddr, sizeof (ACD_ADDR));
+ pCompletion->notif.ulFlags = ulFlags;
+ if (pAdapter != NULL) {
+ RtlCopyMemory(
+ &pCompletion->notif.adapter,
+ pAdapter,
+ sizeof (ACD_ADAPTER));
+ }
+ else
+ RtlZeroMemory(&pCompletion->notif.adapter, sizeof (ACD_ADAPTER));
+ pCompletion->pProc = pProc;
+ pCompletion->nArgs = nArgs;
+ for (i = 0; i < nArgs; i++)
+ pCompletion->pArgs[i] = pArgs[i];
+ //
+ // If this is a unsuccessful connection request,
+ // then insert it onto the connection queue for
+ // that address; Otherwise, insert it into the list
+ // for all other requests.
+ //
+ if (ulFlags & ACD_NOTIFICATION_SUCCESS) {
+ InsertTailList(&AcdCompletionQueueG, &pCompletion->ListEntry);
+ }
+ else {
+ if (!AddCompletionToConnection(pCompletion)) {
+ FREE_MEMORY(pCompletion);
+ return FALSE;
+ }
+ }
+ //
+ // Inform the request thread
+ // there is new work to do.
+ //
+ KeSetEvent(&AcdRequestThreadEventG, 0, FALSE);
+
+ return TRUE;
+} // AddCompletionBlock
+
+
+
+VOID
+AcdNewConnection(
+ IN PACD_ADDR pAddr,
+ IN PACD_ADAPTER pAdapter
+ )
+{
+ KIRQL irql;
+
+ IF_ACDDBG(ACD_DEBUG_CONNECTION) {
+ AcdPrint(("AcdNewConnection: "));
+ AcdPrintAddress(pAddr);
+ AcdPrint(("\n"));
+ }
+ //
+ // If the driver is disabled, then fail
+ // all requests.
+ //
+ if (!fAcdEnabledG) {
+ IF_ACDDBG(ACD_DEBUG_CONNECTION) {
+ AcdPrint(("AcdNewConnection: driver disabled\n"));
+ }
+ return;
+ }
+ //
+ // Acquire our spin lock.
+ //
+ KeAcquireSpinLock(&AcdSpinLockG, &irql);
+ //
+ // Allocate a new completion block.
+ //
+ AddCompletionBlock(
+ 0,
+ pAddr,
+ ACD_NOTIFICATION_SUCCESS,
+ pAdapter,
+ NULL,
+ 0,
+ NULL);
+ //
+ // Release the spin lock.
+ //
+ KeReleaseSpinLock(&AcdSpinLockG, irql);
+} // AcdNewConnection
+
+
+
+BOOLEAN
+AcdStartConnection(
+ IN ULONG ulDriverId,
+ IN PACD_ADDR pAddr,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN USHORT nArgs,
+ IN PVOID *pArgs
+ )
+
+/*++
+
+DESCRIPTION
+ Create a new connection completion block, and enqueue
+ it on the list of network requests to be completed when
+ a new network connection has been created.
+
+ARGUMENTS
+ ulDriverId: a unique value for the transport driver
+
+ pAddr: the address of the connection attempt
+
+ ulFlags: connection flags
+
+ pProc: the transport callback to be called when a new
+ connection has been created.
+
+ nArgs: the number of arguments to pProc.
+
+ pArgs: a pointer to an array of pProc's parameters
+
+RETURN VALUE
+ TRUE if successful, FALSE otherwise.
+
+--*/
+
+{
+ BOOLEAN fSuccess = FALSE, fFound;
+ KIRQL irql;
+ ULONG ulAttributes = 0;
+ PACD_COMPLETION pCompletion;
+ PCHAR psz, pszOrg;
+ ACD_ADDR szOrgAddr;
+
+ IF_ACDDBG(ACD_DEBUG_CONNECTION) {
+ AcdPrint(("AcdStartConnection: "));
+ AcdPrintAddress(pAddr);
+ AcdPrint((", ulFlags=0x%x\n", ulFlags));
+ }
+ //
+ // If the driver is disabled, then fail
+ // all requests.
+ //
+ if (!fAcdEnabledG) {
+ IF_ACDDBG(ACD_DEBUG_CONNECTION) {
+ AcdPrint(("AcdStartConnection: driver disabled\n"));
+ }
+ return FALSE;
+ }
+ //
+ // Validate the address type.
+ //
+ if ((ULONG)pAddr->fType >= ACD_ADDR_MAX) {
+ AcdPrint(("AcdStartConnection: bad address type (%d)\n", pAddr->fType));
+ return FALSE;
+ }
+ //
+ // Acquire our spin lock.
+ //
+ KeAcquireSpinLock(&AcdSpinLockG, &irql);
+ //
+ // Update statistics.
+ //
+ AcdStatsG[pAddr->fType].ulConnects++;
+ //
+ // Allocate a new completion block.
+ //
+ fSuccess = AddCompletionBlock(
+ ulDriverId,
+ pAddr,
+ ulFlags,
+ NULL,
+ pProc,
+ nArgs,
+ pArgs);
+ //
+ // Release the spin lock.
+ //
+ KeReleaseSpinLock(&AcdSpinLockG, irql);
+
+ return fSuccess;
+} // AcdStartConnection
+
+
+
+BOOLEAN
+AcdCancelConnection(
+ IN ULONG ulDriverId,
+ IN PACD_ADDR pAddr,
+ IN ACD_CANCEL_CALLBACK pProc,
+ IN PVOID pArg
+ )
+
+/*++
+
+DESCRIPTION
+ Remove a previously enqueued connection information
+ block from the list.
+
+ARGUMENTS
+ ulDriverId: a unique value for the transport driver
+
+ pAddr: the address of the connection attempt
+
+ pProc: the enumerator procecdure
+
+ pArg: the enumerator procedure argument
+
+RETURN VALUE
+ None.
+
+--*/
+
+{
+ BOOLEAN fCanceled = FALSE;
+ KIRQL irql;
+ PLIST_ENTRY pEntry;
+ PACD_CONNECTION pConnection;
+ PACD_COMPLETION pCompletion;
+
+ IF_ACDDBG(ACD_DEBUG_CONNECTION) {
+ AcdPrint(("AcdCancelConnection: ulDriverId=0x%x, "));
+ AcdPrintAddress(pAddr);
+ AcdPrint(("\n"));
+ }
+ KeAcquireSpinLock(&AcdSpinLockG, &irql);
+ //
+ // Enumerate the list looking for
+ // the information block with the
+ // supplied parameters.
+ //
+ pConnection = FindConnection(pAddr);
+ if (pConnection != NULL) {
+ for (pEntry = pConnection->CompletionList.Flink;
+ pEntry != &pConnection->CompletionList;
+ pEntry = pEntry->Flink)
+ {
+ pCompletion = CONTAINING_RECORD(pEntry, ACD_COMPLETION, ListEntry);
+ //
+ // If we have a match, remove it from
+ // the list and free the information block.
+ //
+ if (pCompletion->ulDriverId == ulDriverId &&
+ !pCompletion->fCanceled &&
+ !pCompletion->fCompleted)
+ {
+ IF_ACDDBG(ACD_DEBUG_CONNECTION) {
+ AcdPrint((
+ "AcdCancelConnection: pCompletion=0x%x\n",
+ pCompletion));
+ }
+ if ((*pProc)(
+ pArg,
+ pCompletion->notif.ulFlags,
+ pCompletion->pProc,
+ pCompletion->nArgs,
+ pCompletion->pArgs))
+ {
+ pCompletion->fCanceled = TRUE;
+ fCanceled = TRUE;
+ //
+ // Update statistics.
+ //
+ AcdStatsG[pAddr->fType].ulCancels++;
+ break;
+ }
+ }
+ }
+ }
+ KeReleaseSpinLock(&AcdSpinLockG, irql);
+
+ return fCanceled;
+} // AcdCancelConnection
+
+
+
+VOID
+ConnectAddressComplete(
+ BOOLEAN fSuccess,
+ PVOID *pArgs
+ )
+{
+ PIRP pIrp = pArgs[0];
+ PIO_STACK_LOCATION pIrpSp = pArgs[1];
+ KIRQL irql;
+
+ //
+ // Complete the request.
+ //
+ pIrp->IoStatus.Status = fSuccess ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
+ pIrp->IoStatus.Information = 0;
+ IoAcquireCancelSpinLock(&irql);
+ IoSetCancelRoutine(pIrp, NULL);
+ IoReleaseCancelSpinLock(irql);
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+} // ConnectAddressComplete
+
+
+
+BOOLEAN
+CancelConnectAddressCallback(
+ IN PVOID pArg,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN USHORT nArgs,
+ IN PVOID *pArgs
+ )
+{
+ return (nArgs == 2 && pArgs[0] == pArg);
+} // CancelConnectAddressCallback
+
+
+
+VOID
+CancelConnectAddress(
+ PDEVICE_OBJECT pDevice,
+ PIRP pIrp
+ )
+{
+ KIRQL irql;
+ PACD_NOTIFICATION pNotification;
+
+ ASSERT(pIrp->Cancel);
+ //
+ // Remove our outstanding request.
+ //
+ pNotification = (PACD_NOTIFICATION)pIrp->AssociatedIrp.SystemBuffer;
+ //
+ // If we can't find the request on the connection
+ // list, then it has already been completed.
+ //
+ if (!AcdCancelConnection(
+ 0,
+ &pNotification->addr,
+ CancelConnectAddressCallback,
+ pIrp))
+ {
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+ return;
+ }
+ //
+ // Mark this irp as cancelled.
+ //
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+ pIrp->IoStatus.Information = 0;
+ IoSetCancelRoutine(pIrp, NULL);
+ //
+ // Release the spin lock the I/O system acquired.
+ //
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+ //
+ // Complete the I/O request.
+ //
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+} // CancelConnectAddress
+
+
+
+NTSTATUS
+AcdConnectAddress(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ )
+
+/*++
+
+DESCRIPTION
+ Manufacture a call to ourselves to simulate a transport
+ requesting an automatic connection. This allows a user
+ address space to initiate an automatic connection.
+
+ARGUMENTS
+ pIrp: a pointer to the irp to be enqueued.
+
+ pIrpSp: a pointer to the current irp stack.
+
+RETURN VALUE
+ STATUS_BUFFER_TOO_SMALL: the supplied user buffer is too small to hold
+ an ACD_NOTIFICATION structure.
+
+ STATUS_UNSUCCESSFUL: an error occurred initiating the
+ automatic connection.
+
+ STATUS_PENDING: success
+
+--*/
+
+{
+ NTSTATUS status = STATUS_UNSUCCESSFUL;
+ KIRQL irql;
+ PACD_NOTIFICATION pNotification;
+ PVOID pArgs[2];
+
+ //
+ // Verify the input buffer is sufficient to hold
+ // an ACD_NOTIFICATION structure.
+ //
+ if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
+ sizeof (ACD_NOTIFICATION))
+ {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ pNotification = (PACD_NOTIFICATION)pIrp->AssociatedIrp.SystemBuffer;
+ pArgs[0] = pIrp;
+ pArgs[1] = pIrpSp;
+ //
+ // Start the connection.
+ //
+ IF_ACDDBG(ACD_DEBUG_CONNECTION) {
+ AcdPrint(("AcdConnectAddress: "));
+ AcdPrintAddress(&pNotification->addr);
+ AcdPrint((", ulFlags=0x%x\n", pNotification->ulFlags));
+ }
+ if (pNotification->ulFlags & ACD_NOTIFICATION_SUCCESS) {
+ AcdNewConnection(
+ &pNotification->addr,
+ &pNotification->adapter);
+ status = STATUS_SUCCESS;
+ }
+ else {
+ IoAcquireCancelSpinLock(&irql);
+ if (AcdStartConnection(
+ 0,
+ &pNotification->addr,
+ pNotification->ulFlags,
+ ConnectAddressComplete,
+ 2,
+ pArgs))
+ {
+ //
+ // We enqueued the request successfully.
+ // Mark the irp as pending.
+ //
+ IoSetCancelRoutine(pIrp, CancelConnectAddress);
+ IoMarkIrpPending(pIrp);
+ status = STATUS_PENDING;
+ }
+ IoReleaseCancelSpinLock(irql);
+ }
+
+ return status;
+} // AcdConnectAddress
+
+
+
+VOID
+AcdSignalCompletionCommon(
+ IN PACD_CONNECTION pConnection,
+ IN BOOLEAN fSuccess
+ )
+{
+ KIRQL irql;
+ PLIST_ENTRY pEntry;
+ PACD_COMPLETION pCompletion;
+ BOOLEAN fFound;
+
+ IF_ACDDBG(ACD_DEBUG_CONNECTION) {
+ AcdPrint((
+ "AcdSignalCompletionCommon: pConnection=0x%x, fCompleting=%d\n",
+ pConnection,
+ pConnection->fCompleting));
+ }
+again:
+ fFound = FALSE;
+ //
+ // Acquire our lock and look for
+ // the next uncompleted request.
+ //
+ KeAcquireSpinLock(&AcdSpinLockG, &irql);
+ for (pEntry = pConnection->CompletionList.Flink;
+ pEntry != &pConnection->CompletionList;
+ pEntry = pEntry->Flink)
+ {
+ pCompletion = CONTAINING_RECORD(pEntry, ACD_COMPLETION, ListEntry);
+
+ IF_ACDDBG(ACD_DEBUG_CONNECTION) {
+ AcdPrint((
+ "AcdSignalCompletionCommon: pCompletion=0x%x, fCanceled=%d, fCompleted=%d\n",
+ pCompletion,
+ pCompletion->fCanceled,
+ pCompletion->fCompleted));
+ }
+ //
+ // Only complete this request if it
+ // hasn't already been completed
+ // or canceled.
+ //
+ if (!pCompletion->fCanceled && !pCompletion->fCompleted) {
+ pCompletion->fCompleted = TRUE;
+ fFound = TRUE;
+ break;
+ }
+ }
+ //
+ // If there are no more requests to
+ // complete then remove this connection
+ // from the connection list and free its
+ // memory.
+ //
+ if (!fFound) {
+ RemoveEntryList(&pConnection->ListEntry);
+ while (!IsListEmpty(&pConnection->CompletionList)) {
+ pEntry = RemoveHeadList(&pConnection->CompletionList);
+ pCompletion = CONTAINING_RECORD(pEntry, ACD_COMPLETION, ListEntry);
+
+ FREE_MEMORY(pCompletion);
+ }
+ FREE_MEMORY(pConnection);
+ //
+ // Signal the request thread that
+ // the connection list has changed.
+ //
+ KeSetEvent(&AcdRequestThreadEventG, 0, FALSE);
+ }
+ //
+ // Release our lock.
+ //
+ KeReleaseSpinLock(&AcdSpinLockG, irql);
+ //
+ // If we found a request, then
+ // call its completion proc.
+ //
+ if (fFound) {
+ IF_ACDDBG(ACD_DEBUG_CONNECTION) {
+ AcdPrint(("AcdSignalCompletionCommon: pCompletion=0x%x, ", pCompletion));
+ AcdPrintAddress(&pCompletion->notif.addr);
+ AcdPrint(("\n"));
+ }
+ (*pCompletion->pProc)(fSuccess, pCompletion->pArgs);
+ //
+ // Look for another request.
+ //
+ goto again;
+ }
+} // AcdSignalCompletionCommon
+
+
+
+NTSTATUS
+AcdSignalCompletion(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ )
+
+/*++
+
+DESCRIPTION
+ For each thread waiting on the AcdCompletionQueueG,
+ call the transport-dependent callback to retry the
+ connection attempt and complete the irp.
+
+ARGUMENTS
+ pIrp: unused
+
+ pIrpSp: unused
+
+RETURN VALUE
+ STATUS_SUCCESS
+
+--*/
+
+{
+ KIRQL irql;
+ PACD_STATUS pStatus;
+ PACD_CONNECTION pConnection;
+ BOOLEAN fFound = FALSE;
+
+ //
+ // Verify the input buffer is sufficient to hold
+ // a BOOLEAN structure.
+ //
+ if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
+ sizeof (ACD_STATUS))
+ {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Get the success code from the
+ // connection attempt and pass it
+ // to the completion routine.
+ //
+ pStatus = (PACD_STATUS)pIrp->AssociatedIrp.SystemBuffer;
+ KeAcquireSpinLock(&AcdSpinLockG, &irql);
+ pConnection = FindConnection(&pStatus->addr);
+ if (pConnection != NULL && !pConnection->fCompleting) {
+ //
+ // Set the completion-in-progress flag so
+ // this request cannot be timed-out after
+ // we release the spin lock.
+ //
+ pConnection->fCompleting = TRUE;
+ fFound = TRUE;
+ }
+ KeReleaseSpinLock(&AcdSpinLockG, irql);
+ //
+ // If we didn't find the connection block,
+ // or the completion was already in progress,
+ // then return an error.
+ //
+ if (!fFound)
+ return STATUS_UNSUCCESSFUL;
+
+ AcdSignalCompletionCommon(pConnection, pStatus->fSuccess);
+ return STATUS_SUCCESS;
+} // AcdSignalCompletion
+
+
+
+VOID
+ClearRequests(
+ IN KIRQL irql
+ )
+
+/*++
+
+DESCRIPTION
+ Complete all pending requests with failure status.
+ This call assumes the AcdSpinLockG is already held,
+ and it returns with it held.
+
+ARGUMENTS
+ None.
+
+RETURN VALUE
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY pHead, pEntry;
+ PACD_COMPLETION pCompletion;
+ PACD_CONNECTION pConnection;
+
+again:
+ //
+ // Complete all pending connections with
+ // an error.
+ //
+ for (pEntry = AcdConnectionQueueG.Flink;
+ pEntry != &AcdConnectionQueueG;
+ pEntry = pEntry->Flink)
+ {
+ pConnection = CONTAINING_RECORD(pEntry, ACD_CONNECTION, ListEntry);
+
+ if (!pConnection->fCompleting) {
+ pConnection->fCompleting = TRUE;
+ //
+ // We need to release our lock to
+ // complete the request.
+ //
+ KeReleaseSpinLock(&AcdSpinLockG, irql);
+ //
+ // Complete the request.
+ //
+ AcdSignalCompletionCommon(pConnection, FALSE);
+ //
+ // Check for more uncompleted requests.
+ //
+ KeAcquireSpinLock(&AcdSpinLockG, &irql);
+ goto again;
+ }
+ }
+ //
+ // Clear out all other pending requests.
+ //
+ while (!IsListEmpty(&AcdCompletionQueueG)) {
+ pHead = RemoveHeadList(&AcdCompletionQueueG);
+ pCompletion = CONTAINING_RECORD(pHead, ACD_COMPLETION, ListEntry);
+
+ FREE_MEMORY(pCompletion);
+ }
+} // ClearRequests
+
+
+
+VOID
+AcdReset()
+
+/*++
+
+DESCRIPTION
+ Complete all pending requests with failure status.
+ This is called when the reference count on the driver
+ object goes to zero, and prevents stale requests from
+ being presented to the system service if it is restarted
+ when there are pending completion requests.
+
+ARGUMENTS
+ None.
+
+RETURN VALUE
+ None.
+
+--*/
+
+{
+ KIRQL irql;
+ PLIST_ENTRY pHead, pEntry;
+ PACD_COMPLETION pCompletion;
+ PACD_CONNECTION pConnection;
+
+ KeAcquireSpinLock(&AcdSpinLockG, &irql);
+ //
+ // Reset the notification mode to disabled.
+ //
+ SetDriverMode(FALSE);
+ //
+ // Complete all pending connections with
+ // an error.
+ //
+ ClearRequests(irql);
+ KeReleaseSpinLock(&AcdSpinLockG, irql);
+} // AcdReset
+
+
+
+NTSTATUS
+AcdBind(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ )
+
+/*++
+
+DESCRIPTION
+ Return the list of entry points to a client
+ transport driver.
+
+ARGUMENTS
+ pIrp: a pointer to the irp to be enqueued.
+
+ pIrpSp: a pointer to the current irp stack.
+
+RETURN VALUE
+ STATUS_BUFFER_TOO_SMALL if the supplied SystemBuffer is too
+ small. STATUS_SUCCESS otherwise.
+
+--*/
+
+{
+ NTSTATUS status;
+ PACD_DRIVER *ppDriver, pDriver;
+ KIRQL irql, dirql;
+
+ //
+ // Verify the input buffer a pointer to
+ // the driver's ACD_DRIVER structure.
+ //
+ if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
+ sizeof (PACD_DRIVER))
+ {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+ ppDriver = (PACD_DRIVER *)pIrp->AssociatedIrp.SystemBuffer;
+ pDriver = *ppDriver;
+#if DBG
+ //
+ // Selectively bind with some transports.
+ //
+ switch (pDriver->ulDriverId) {
+ case 'Nbf ':
+ break;
+ case 'Tcp ':
+#ifdef notdef
+ DbgPrint("AcdBind: ignoring Tcp\n");
+ pDriver->fEnabled = FALSE;
+ pIrp->IoStatus.Information = 0;
+ return STATUS_SUCCESS;
+#endif
+ break;
+ case 'Nbi ':
+#ifdef notdef
+ DbgPrint("AcdBind: ignoring Nbi\n");
+ pDriver->fEnabled = FALSE;
+ pIrp->IoStatus.Information = 0;
+ return STATUS_SUCCESS;
+#endif
+ break;
+ }
+#endif
+ //
+ // Fill in the entry point structure.
+ //
+ pDriver->lpfnNewConnection = AcdNewConnection;
+ pDriver->lpfnStartConnection = AcdStartConnection;
+ pDriver->lpfnCancelConnection = AcdCancelConnection;
+ //
+ // Insert this block into our driver list.
+ //
+ KeAcquireSpinLock(&AcdSpinLockG, &irql);
+ KeAcquireSpinLock(&pDriver->SpinLock, &dirql);
+ pDriver->fEnabled = fAcdEnabledG;
+ KeReleaseSpinLock(&pDriver->SpinLock, dirql);
+ InsertTailList(&AcdDriverListG, &pDriver->ListEntry);
+ KeReleaseSpinLock(&AcdSpinLockG, irql);
+ //
+ // No data should be copied back.
+ //
+ pIrp->IoStatus.Information = 0;
+
+ return STATUS_SUCCESS;
+} // AcdBind
+
+
+
+NTSTATUS
+AcdUnbind(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ )
+
+/*++
+
+DESCRIPTION
+ Unbind a client transport driver.
+
+ARGUMENTS
+ pIrp: a pointer to the irp to be enqueued.
+
+ pIrpSp: a pointer to the current irp stack.
+
+RETURN VALUE
+ STATUS_BUFFER_TOO_SMALL if the supplied SystemBuffer is too
+ small. STATUS_SUCCESS otherwise.
+
+--*/
+
+{
+ KIRQL irql, dirql;
+ PLIST_ENTRY pEntry, pEntry2;
+ PACD_DRIVER *ppDriver, pDriver;
+ PACD_CONNECTION pConnection;
+ PACD_COMPLETION pCompletion;
+
+ //
+ // Verify the input buffer a pointer to
+ // the driver's ACD_DRIVER structure.
+ //
+ if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
+ sizeof (PACD_DRIVER))
+ {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+ ppDriver = (PACD_DRIVER *)pIrp->AssociatedIrp.SystemBuffer;
+ pDriver = *ppDriver;
+
+ KeAcquireSpinLock(&AcdSpinLockG, &irql);
+ //
+ // Enumerate the list looking for
+ // any connection request initiated by the
+ // specified driver.
+ //
+ for (pEntry = AcdConnectionQueueG.Flink;
+ pEntry != &AcdConnectionQueueG;
+ pEntry = pEntry->Flink)
+ {
+ pConnection = CONTAINING_RECORD(pEntry, ACD_CONNECTION, ListEntry);
+
+ for (pEntry2 = pConnection->CompletionList.Flink;
+ pEntry2 != &pConnection->CompletionList;
+ pEntry2 = pEntry2->Flink)
+ {
+ pCompletion = CONTAINING_RECORD(pEntry2, ACD_COMPLETION, ListEntry);
+
+ //
+ // If we have a match, cancel it.
+ //
+ if (pCompletion->ulDriverId == pDriver->ulDriverId)
+ pCompletion->fCanceled = TRUE;
+ }
+ }
+ //
+ // Set this driver's enable mode to ACD_ENABLE_NONE.
+ //
+ KeAcquireSpinLock(&pDriver->SpinLock, &dirql);
+ pDriver->fEnabled = FALSE;
+ KeReleaseSpinLock(&pDriver->SpinLock, dirql);
+ //
+ // Remove this driver from the list.
+ //
+ RemoveEntryList(&pDriver->ListEntry);
+ KeReleaseSpinLock(&AcdSpinLockG, irql);
+ //
+ // No data should be copied back.
+ //
+ pIrp->IoStatus.Information = 0;
+
+ return STATUS_SUCCESS;
+} // AcdUnbind
+
+
+VOID
+AcdPrintAddress(
+ IN PACD_ADDR pAddr
+ )
+{
+#if DBG
+ PUCHAR puc;
+
+ switch (pAddr->fType) {
+ case ACD_ADDR_IP:
+ puc = (PUCHAR)&pAddr->ulIpaddr;
+ AcdPrint(("IP: %d.%d.%d.%d", puc[0], puc[1], puc[2], puc[3]));
+ break;
+ case ACD_ADDR_IPX:
+ AcdPrint((
+ "IPX: %02x:%02x:%02x:%02x:%02x:%02x",
+ pAddr->cNode[0],
+ pAddr->cNode[1],
+ pAddr->cNode[2],
+ pAddr->cNode[3],
+ pAddr->cNode[4],
+ pAddr->cNode[5]));
+ break;
+ case ACD_ADDR_NB:
+ AcdPrint(("NB: %15.15s", pAddr->cNetbios));
+ break;
+ case ACD_ADDR_INET:
+ AcdPrint(("INET: %s", pAddr->szInet));
+ break;
+ default:
+ AcdPrint(("UNKNOWN: ????"));
+ break;
+ }
+#endif
+} // AcdPrintAddress
diff --git a/private/ntos/tdi/acd/debug.h b/private/ntos/tdi/acd/debug.h
new file mode 100644
index 000000000..421c43de6
--- /dev/null
+++ b/private/ntos/tdi/acd/debug.h
@@ -0,0 +1,74 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ debug.h
+
+Abstract:
+
+ Debugging defintions for the Automatic
+ Connection Driver (acd.sys).
+
+Author:
+
+ Anthony Discolo (adiscolo) 3-Aug-1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+--*/
+
+#ifndef _ACDDBG_
+#define _ACDDBG_
+
+//
+// Debug tracing flags.
+//
+// To enable debug tracing for a module, set the
+// appropriate bit in ntinit\AcdDebugG.
+//
+#if DBG
+
+#define ACD_DEBUG_IOCTL 0x00000001 // ntdisp.c/AcdDispatchDeviceControl()
+#define ACD_DEBUG_OPENCOUNT 0x00000002 // ntdisp.c/Acd{Open,Close}()
+#define ACD_DEBUG_TIMER 0x00000004 // timer.c
+#define ACD_DEBUG_CONNECTION 0x00000008 // api.c/AcdStartConnection()
+#define ACD_DEBUG_WORKER 0x00000010 // api.c/AcdNotificationRequestThread()
+#define ACD_DEBUG_RESET 0x00000020 // api.c/AcdReset()
+#define ACD_DEBUG_MEMORY 0x80000000 // memory alloc/free
+
+#define IF_ACDDBG(flag) if (AcdDebugG & flag)
+#define AcdPrint(many_args) DbgPrint many_args
+
+#define ALLOCATE_MEMORY(fObject, pObject) \
+ pObject = AllocateObjectMemory(fObject); \
+ IF_ACDDBG(ACD_DEBUG_MEMORY) \
+ AcdPrint(("ALLOCATE_MEMORY: %s(%d): fObject=%d, pObject=0x%x\n", __FILE__, __LINE__, fObject, pObject))
+
+#define FREE_MEMORY(pObject) \
+ IF_ACDDBG(ACD_DEBUG_MEMORY) \
+ AcdPrint(("FREE_MEMORY: %s(%d): pObject=0x%x\n", __FILE__, __LINE__, pObject)); \
+ FreeObjectMemory(pObject)
+
+extern ULONG AcdDebugG;
+
+#else
+
+#define IF_ACDDBG(flag) if (0)
+#define AcdPrint(many_args)
+
+#define ALLOCATE_MEMORY(fObject, pObject) \
+ pObject = AllocateObjectMemory(fObject);
+
+#define FREE_MEMORY(pObject) \
+ FreeObjectMemory(pObject)
+
+#endif
+
+
+#endif // _ACDDBG_
diff --git a/private/ntos/tdi/acd/makefile b/private/ntos/tdi/acd/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/acd/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/acd/mem.c b/private/ntos/tdi/acd/mem.c
new file mode 100644
index 000000000..e3c9166c1
--- /dev/null
+++ b/private/ntos/tdi/acd/mem.c
@@ -0,0 +1,289 @@
+/*++
+
+Copyright(c) 1995 Microsoft Corporation
+
+MODULE NAME
+ table.c
+
+ABSTRACT
+ Generic hash table manipulation routines.
+
+AUTHOR
+ Anthony Discolo (adiscolo) 28-Jul-1995
+
+REVISION HISTORY
+
+--*/
+
+#include <ndis.h>
+#include <cxport.h>
+#include <tdi.h>
+#include <tdikrnl.h>
+#include <tdistat.h>
+#include <tdiinfo.h>
+#include <acd.h>
+#include <acdapi.h>
+
+#include "acddefs.h"
+#include "mem.h"
+#include "debug.h"
+
+//
+// The maximum number of allocated
+// objects we allocate from outside
+// our zones.
+//
+#define MAX_ALLOCATED_OBJECTS 100
+
+//
+// Rounding up macro.
+//
+#define ROUNDUP(n, b) (((n) + ((b) - 1)) & ~((b) - 1))
+
+//
+// Map an object type to a zone.
+//
+#define OBJECT_INFO(fObject) \
+ (fObject < ACD_OBJECT_MAX) ? &AcdObjectInfoG[fObject] : &AcdObjectInfoG[ACD_OBJECT_MAX]
+
+//
+// The spin lock for this module.
+//
+KSPIN_LOCK AcdMemSpinLockG;
+
+//
+// Zone-based object information. One zone
+// per object type.
+//
+typedef struct _OBJECT_INFORMATION {
+ ZONE_HEADER zone;
+ ULONG ulSize; // object size
+ ULONG ulTag; // ExAllocateFromPoolWithTag() tag
+ ULONG ulCurrent; // # currently allocated in zone
+ ULONG ulTotal; // total # zone allocations
+} OBJECT_INFORMATION, *POBJECT_INFORMATION;
+
+OBJECT_INFORMATION AcdObjectInfoG[ACD_OBJECT_MAX + 1];
+
+//
+// Pool-based object allocation. This is for
+// objects that don't fit into any of the zones,
+// or when the zone is full.
+//
+typedef struct _POOL_INFORMATION {
+ ULONG cbMin; // minimum size
+ ULONG cbMax; // maximum size
+ ULONG ulCurrent; // # current allocations
+ ULONG ulTotal; // total allocations
+ ULONG ulFailures; // total failures
+} POOL_INFORMATION, *PPOOL_INFORMATION;
+
+POOL_INFORMATION AcdPoolInfoG;
+
+
+
+VOID
+InitializeObjectAllocator()
+{
+ NTSTATUS status;
+ PVOID pMem;
+ ULONG ulSize;
+
+ KeInitializeSpinLock(&AcdMemSpinLockG);
+ //
+ // Initialize zone 0 (ACD_OBJECT_CONNECTION).
+ //
+ AcdObjectInfoG[ACD_OBJECT_CONNECTION].ulTag = 'NdcA';
+ AcdObjectInfoG[ACD_OBJECT_CONNECTION].ulSize =
+ ROUNDUP(sizeof (ACD_CONNECTION), 8);
+ ulSize = PAGE_SIZE;
+ pMem = ExAllocatePoolWithTag(
+ NonPagedPool,
+ ulSize,
+ AcdObjectInfoG[ACD_OBJECT_CONNECTION].ulTag);
+ ASSERT(pMem != NULL);
+ status = ExInitializeZone(
+ &AcdObjectInfoG[ACD_OBJECT_CONNECTION].zone,
+ AcdObjectInfoG[ACD_OBJECT_CONNECTION].ulSize,
+ pMem,
+ ulSize);
+ IF_ACDDBG(ACD_DEBUG_MEMORY) {
+ AcdPrint((
+ "InitializeObjectAllocator: zone 0 created: blksiz=%d, size=%d (status=%d)\n",
+ AcdObjectInfoG[ACD_OBJECT_CONNECTION].ulSize,
+ ulSize,
+ status));
+ }
+ //
+ // Initialize zone 1 (ACD_OBJECT_COMPLETION).
+ //
+ AcdObjectInfoG[ACD_OBJECT_MAX].ulTag = 'MdcA';
+ //
+ // Allow for up to 6 parameters to a completion
+ // request (6 used by tcpip.sys).
+ //
+ AcdObjectInfoG[ACD_OBJECT_MAX].ulSize =
+ ROUNDUP(sizeof (ACD_COMPLETION) + (6 * sizeof (PVOID)), 8);
+ ulSize = ROUNDUP(6 * AcdObjectInfoG[ACD_OBJECT_MAX].ulSize, PAGE_SIZE),
+ pMem = ExAllocatePoolWithTag(
+ NonPagedPool,
+ ulSize,
+ AcdObjectInfoG[ACD_OBJECT_MAX].ulTag);
+ ASSERT(pMem != NULL);
+ status = ExInitializeZone(
+ &AcdObjectInfoG[ACD_OBJECT_MAX].zone,
+ AcdObjectInfoG[ACD_OBJECT_MAX].ulSize,
+ pMem,
+ ulSize);
+ IF_ACDDBG(ACD_DEBUG_MEMORY) {
+ AcdPrint((
+ "InitializeObjectAllocator: zone 1 created: blksiz=%d size=%d (status=%d)\n",
+ AcdObjectInfoG[ACD_OBJECT_MAX].ulSize,
+ ulSize,
+ status));
+ }
+ //
+ // Initialize the pool info.
+ //
+ AcdPoolInfoG.cbMin = 0xffffffff;
+ AcdPoolInfoG.cbMax = 0;
+ AcdPoolInfoG.ulCurrent = 0;
+ AcdPoolInfoG.ulTotal = 0;
+ AcdPoolInfoG.ulFailures = 0;
+} // InitializeObjectAllocator
+
+
+
+PVOID
+AllocateObjectMemory(
+ IN ULONG fObject
+ )
+{
+ KIRQL irql;
+ POBJECT_INFORMATION pObjectInfo = OBJECT_INFO(fObject);
+ PVOID pObject;
+ ULONG cbBytes = 0, ulTag;
+ static ULONG nAllocations = 0;
+
+ KeAcquireSpinLock(&AcdMemSpinLockG, &irql);
+ //
+ // If the zone is full, or the object
+ // size is greater than the zone object size,
+ // then use the pool allocator.
+ //
+ if (fObject > pObjectInfo->zone.BlockSize) {
+ cbBytes = fObject;
+ ulTag = 'PdcA';
+ }
+ else if (ExIsFullZone(&pObjectInfo->zone)) {
+ cbBytes = pObjectInfo->ulSize;
+ ulTag = pObjectInfo->ulTag;
+ }
+ if (cbBytes) {
+ //
+ // Limit memory usage under stress.
+ // If we have more than 100 outstanding
+ // requests, then we start dropping
+ // them.
+ //
+ if (AcdPoolInfoG.ulCurrent < MAX_ALLOCATED_OBJECTS)
+ pObject = ExAllocatePoolWithTag(NonPagedPool, cbBytes, ulTag);
+ else {
+ pObject = NULL;
+ AcdPoolInfoG.ulFailures++;
+ goto done;
+ }
+ if (cbBytes < AcdPoolInfoG.cbMin)
+ AcdPoolInfoG.cbMin = cbBytes;
+ if (cbBytes > AcdPoolInfoG.cbMax)
+ AcdPoolInfoG.cbMax = cbBytes;
+ AcdPoolInfoG.ulCurrent++;
+ AcdPoolInfoG.ulTotal++;
+ IF_ACDDBG(ACD_DEBUG_MEMORY) {
+ AcdPrint((
+ "AllocateObjectMemory: allocated type %d from pool: pObject=0x%x\n",
+ fObject,
+ pObject));
+ }
+ }
+ else {
+ pObject = ExAllocateFromZone(&pObjectInfo->zone);
+ pObjectInfo->ulCurrent++;
+ pObjectInfo->ulTotal++;
+ IF_ACDDBG(ACD_DEBUG_MEMORY) {
+ AcdPrint((
+ "AllocateObjectMemory: allocated type %d from zone: pObject=0x%x\n",
+ fObject,
+ pObject));
+ }
+ }
+#if DBG
+ IF_ACDDBG(ACD_DEBUG_MEMORY) {
+ INT i;
+
+ if (!(++nAllocations % 10)) {
+ for (i = 0; i <= ACD_OBJECT_MAX; i++) {
+ AcdPrint((
+ "Zone %d: ulCurrent=%d, ulTotal=%d\n",
+ i,
+ AcdObjectInfoG[i].ulCurrent,
+ AcdObjectInfoG[i].ulTotal));
+ }
+ AcdPrint((
+ "Pool: ulCurrent=%d, ulTotal=%d\n",
+ AcdPoolInfoG.ulCurrent,
+ AcdPoolInfoG.ulTotal));
+ }
+ }
+#endif
+done:
+ KeReleaseSpinLock(&AcdMemSpinLockG, irql);
+
+ return pObject;
+} // AllocateObjectMemory
+
+
+
+VOID
+FreeObjectMemory(
+ IN PVOID pObject
+ )
+{
+ KIRQL irql;
+ INT i;
+ POBJECT_INFORMATION pObjectInfo;
+
+ KeAcquireSpinLock(&AcdMemSpinLockG, &irql);
+ for (i = 0; i <= ACD_OBJECT_MAX; i++) {
+ pObjectInfo = &AcdObjectInfoG[i];
+
+ if (ExIsObjectInFirstZoneSegment(&pObjectInfo->zone, pObject)) {
+ ExFreeToZone(&pObjectInfo->zone, pObject);
+ pObjectInfo->ulCurrent--;
+ IF_ACDDBG(ACD_DEBUG_MEMORY) {
+ AcdPrint((
+ "FreeObjectMemory: freed type %d into zone: pObject=0x%x\n",
+ i,
+ pObject));
+ }
+ goto done;
+ }
+ }
+ ExFreePool(pObject);
+ AcdPoolInfoG.ulCurrent--;
+ IF_ACDDBG(ACD_DEBUG_MEMORY) {
+ AcdPrint((
+ "FreeObjectMemory: freed into pool: pObject=0x%x\n",
+ pObject));
+ }
+done:
+ KeReleaseSpinLock(&AcdMemSpinLockG, irql);
+} // FreeObjectMemory
+
+
+
+VOID
+FreeObjectAllocator()
+{
+ // Apparently, we can't do this?
+} // FreeObjectAllocator
diff --git a/private/ntos/tdi/acd/mem.h b/private/ntos/tdi/acd/mem.h
new file mode 100644
index 000000000..3811029e7
--- /dev/null
+++ b/private/ntos/tdi/acd/mem.h
@@ -0,0 +1,41 @@
+/*++
+
+Copyright(c) 1995 Microsoft Corporation
+
+MODULE NAME
+ mem.h
+
+ABSTRACT
+ Header file for memory allocation routines.
+
+AUTHOR
+ Anthony Discolo (adiscolo) 18-Aug-1995
+
+REVISION HISTORY
+
+--*/
+
+//
+// Pre-defined object types.
+// Any other value represents a
+// byte count.
+//
+#define ACD_OBJECT_CONNECTION 0
+#define ACD_OBJECT_MAX 1
+
+VOID
+InitializeObjectAllocator();
+
+PVOID
+AllocateObjectMemory(
+ IN ULONG fObject
+ );
+
+VOID
+FreeObjectMemory(
+ IN PVOID pObject
+ );
+
+VOID
+FreeObjectAllocator();
+
diff --git a/private/ntos/tdi/acd/ntdisp.c b/private/ntos/tdi/acd/ntdisp.c
new file mode 100644
index 000000000..5388656d2
--- /dev/null
+++ b/private/ntos/tdi/acd/ntdisp.c
@@ -0,0 +1,411 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntdisp.c
+
+Abstract:
+
+ NT specific routines for dispatching and handling automatic
+ connection notification IRPs.
+
+ The basic architecture involves a user address space,
+ a network transport, and this driver.
+
+ The user address space is responsible for creating a
+ new network connection given a notification from this
+ driver (IOCTL_ACD_NOTIFICATION). When it gets a
+ notification, it is also responsible for pinging the
+ this driver (IOCTL_ACD_KEEPALIVE) so it can be guaranteed
+ the connection is progressing. Once the connection is
+ created, it informs this driver of the success or
+ failure of the connection attempt (IOCTL_ACD_CONNECTION).
+
+ Network transports are responsible for informing this
+ driver of network unreachable errors via TdiConnect()
+ or TdiSendDatagram(). When this happens, the transport
+ is responsible for dequeueing the send request from any
+ of its internal queues and enqueueing the request in
+ this driver (AcdWaitForCompletion()), supplying a callback
+ to be called when the connection has been completed.
+
+Author:
+
+ Anthony Discolo (adiscolo) 18-Apr-1995
+
+Revision History:
+
+--*/
+#include <ndis.h>
+#include <cxport.h>
+#include <tdikrnl.h>
+#include <tdistat.h>
+#include <tdiinfo.h>
+#include <acd.h>
+
+#include "acdapi.h"
+#include "debug.h"
+
+//
+// Driver reference count
+//
+ULONG ulAcdOpenCountG;
+
+//
+// Imported routines
+//
+NTSTATUS
+AcdEnable(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ );
+
+VOID
+AcdCancelNotifications();
+
+NTSTATUS
+AcdWaitForNotification(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ );
+
+NTSTATUS
+AcdConnectionInProgress(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ );
+
+NTSTATUS
+AcdSignalCompletion(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ );
+
+NTSTATUS
+AcdConnectAddress(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ );
+
+VOID
+AcdReset();
+
+NTSTATUS
+AcdGetAddressAttributes(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ );
+
+NTSTATUS
+AcdSetAddressAttributes(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ );
+
+//
+// Internal function prototypes
+//
+NTSTATUS
+AcdCreate(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ );
+
+NTSTATUS
+AcdDispatchDeviceControl(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ );
+
+NTSTATUS
+AcdDispatchInternalDeviceControl(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ );
+
+NTSTATUS
+AcdCleanup(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ );
+
+NTSTATUS
+AcdClose(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ );
+
+NTSTATUS
+AcdBind(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ );
+
+NTSTATUS
+AcdUnbind(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ );
+
+//
+// All of this code is pageable.
+//
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, AcdCreate)
+#pragma alloc_text(PAGE, AcdDispatchDeviceControl)
+#pragma alloc_text(PAGE, AcdDispatchInternalDeviceControl)
+#pragma alloc_text(PAGE, AcdCleanup)
+#pragma alloc_text(PAGE, AcdClose)
+#endif // ALLOC_PRAGMA
+
+
+
+NTSTATUS
+AcdCreate(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ )
+{
+ ulAcdOpenCountG++;
+ IF_ACDDBG(ACD_DEBUG_OPENCOUNT) {
+ AcdPrint(("AcdCreate: ulAcdOpenCountG=%d\n", ulAcdOpenCountG));
+ }
+ return STATUS_SUCCESS;
+} // AcdCreate
+
+
+
+NTSTATUS
+AcdDispatchDeviceControl(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ )
+{
+ NTSTATUS status;
+
+
+ PAGED_CODE();
+ //
+ // Set this in advance. Any IOCTL dispatch routine that cares about it
+ // will modify it itself.
+ //
+ pIrp->IoStatus.Information = 0;
+
+ switch (pIrpSp->Parameters.DeviceIoControl.IoControlCode) {
+ case IOCTL_ACD_RESET:
+ IF_ACDDBG(ACD_DEBUG_IOCTL) {
+ AcdPrint(("AcdDispatchDeviceControl: IOCTL_ACD_RESET\n"));
+ }
+ AcdReset();
+ status = STATUS_SUCCESS;
+ break;
+ case IOCTL_ACD_ENABLE:
+ IF_ACDDBG(ACD_DEBUG_IOCTL) {
+ AcdPrint(("AcdDispatchDeviceControl: IOCTL_ACD_ENABLE\n"));
+ }
+ //
+ // Enable/disable requests to/from the driver.
+ //
+ status = AcdEnable(pIrp, pIrpSp);
+ break;
+ case IOCTL_ACD_NOTIFICATION:
+ IF_ACDDBG(ACD_DEBUG_IOCTL) {
+ AcdPrint(("AcdDispatchDeviceControl: IOCTL_ACD_NOTIFICATION\n"));
+ }
+ //
+ // This irp will be completed upon the
+ // next connection attempt to
+ // allow a user-space process to attempt
+ // to make a connection.
+ //
+ status = AcdWaitForNotification(pIrp, pIrpSp);
+ break;
+ case IOCTL_ACD_KEEPALIVE:
+ IF_ACDDBG(ACD_DEBUG_IOCTL) {
+ AcdPrint(("AcdDispatchDeviceControl: IOCTL_ACD_KEEPALIVE\n"));
+ }
+ //
+ // Inform the driver that the connection
+ // is in the process of being created.
+ //
+ status = AcdConnectionInProgress(pIrp, pIrpSp);
+ break;
+ case IOCTL_ACD_COMPLETION:
+ IF_ACDDBG(ACD_DEBUG_IOCTL) {
+ AcdPrint(("AcdDispatchDeviceControl: IOCTL_ACD_COMPLETION\n"));
+ }
+ //
+ // Complete all pending irps that initially
+ // encountered a network unreachable error,
+ // and have been waiting for a connection to be
+ // made.
+ //
+ status = AcdSignalCompletion(pIrp, pIrpSp);
+ break;
+ case IOCTL_ACD_CONNECT_ADDRESS:
+ IF_ACDDBG(ACD_DEBUG_IOCTL) {
+ AcdPrint(("AcdDispatchDeviceControl: IOCTL_ACD_CONNECT_ADDRESS\n"));
+ }
+ //
+ // This allows a user space application to
+ // generate the same automatic connection
+ // mechanism as a transport protocol.
+ //
+ status = AcdConnectAddress(pIrp, pIrpSp);
+ break;
+ default:
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ if (status != STATUS_PENDING) {
+ pIrp->IoStatus.Status = status;
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+ }
+
+ return status;
+} // AcdDispatchDeviceControl
+
+
+
+NTSTATUS
+AcdDispatchInternalDeviceControl(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ )
+{
+ NTSTATUS status;
+
+ PAGED_CODE();
+ //
+ // Set this in advance. Any IOCTL dispatch routine that cares about it
+ // will modify it itself.
+ //
+ pIrp->IoStatus.Information = 0;
+
+ switch (pIrpSp->Parameters.DeviceIoControl.IoControlCode) {
+ case IOCTL_INTERNAL_ACD_BIND:
+ IF_ACDDBG(ACD_DEBUG_IOCTL) {
+ AcdPrint(("AcdDispatchInternalDeviceControl: IOCTL_INTERNAL_ACD_BIND\n"));
+ }
+ //
+ // Transfer entrypoints to client.
+ //
+ status = AcdBind(pIrp, pIrpSp);
+ break;
+ case IOCTL_INTERNAL_ACD_UNBIND:
+ IF_ACDDBG(ACD_DEBUG_IOCTL) {
+ AcdPrint(("AcdDispatchInternalDeviceControl: IOCTL_INTERNAL_ACD_UNBIND\n"));
+ }
+ //
+ // Remove any pending requests from
+ // this driver.
+ //
+ status = AcdUnbind(pIrp, pIrpSp);
+ break;
+ default:
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ if (status != STATUS_PENDING) {
+ pIrp->IoStatus.Status = status;
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+ }
+
+ return status;
+} // AcdDispatchInternalDeviceControl
+
+
+
+NTSTATUS
+AcdCleanup(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ )
+{
+ return STATUS_SUCCESS;
+} // AcdCleanup
+
+
+
+NTSTATUS
+AcdClose(
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp
+ )
+{
+ ulAcdOpenCountG--;
+ IF_ACDDBG(ACD_DEBUG_OPENCOUNT) {
+ AcdPrint(("AcdClose: ulAcdOpenCountG=%d\n", ulAcdOpenCountG));
+ }
+ if (!ulAcdOpenCountG)
+ AcdReset();
+ return STATUS_SUCCESS;
+} // AcdClose
+
+
+
+NTSTATUS
+AcdDispatch(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ )
+
+/*++
+
+DESCRIPTION
+ This is the dispatch routine for the network connection
+ notification driver.
+
+ARGUMENTS
+ pDeviceObject: a pointer to device object for target device
+
+ pIrp: a pointer to I/O request packet
+
+Return Value:
+ NTSTATUS
+
+--*/
+
+{
+ NTSTATUS status;
+ PIO_STACK_LOCATION pIrpSp;
+
+ UNREFERENCED_PARAMETER(pDeviceObject);
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ switch (pIrpSp->MajorFunction) {
+ case IRP_MJ_CREATE:
+ status = AcdCreate(pIrp, pIrpSp);
+ break;
+ case IRP_MJ_DEVICE_CONTROL:
+ return AcdDispatchDeviceControl(pIrp, pIrpSp);
+ case IRP_MJ_INTERNAL_DEVICE_CONTROL:
+ return AcdDispatchInternalDeviceControl(pIrp, pIrpSp);
+ case IRP_MJ_CLEANUP:
+ status = AcdCleanup(pIrp, pIrpSp);
+ break;
+ case IRP_MJ_CLOSE:
+ status = AcdClose(pIrp, pIrpSp);
+ break;
+ default:
+ DbgPrint("AcdDispatch: Invalid major function %lx\n",
+ pIrpSp->MajorFunction);
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ if (status != STATUS_PENDING) {
+ pIrp->IoStatus.Status = status;
+ pIrp->IoStatus.Information = 0;
+
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+ }
+
+ return status;
+} // AcdDispatch
+
diff --git a/private/ntos/tdi/acd/ntinit.c b/private/ntos/tdi/acd/ntinit.c
new file mode 100644
index 000000000..24ad73ef0
--- /dev/null
+++ b/private/ntos/tdi/acd/ntinit.c
@@ -0,0 +1,223 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ntinit.c
+
+Abstract:
+
+ NT specific routines for loading and configuring the
+ automatic connection notification driver (acd.sys).
+
+Author:
+
+ Anthony Discolo (adiscolo) 18-Apr-1995
+
+Revision History:
+
+--*/
+#include <ndis.h>
+#include <cxport.h>
+#include <tdi.h>
+#include <tdikrnl.h>
+#include <tdistat.h>
+#include <tdiinfo.h>
+#include <acd.h>
+
+#include "acdapi.h"
+#include "acddefs.h"
+#include "mem.h"
+#include "debug.h"
+
+
+//
+// Global variables
+//
+#if DBG
+ULONG AcdDebugG = 0x0; // see debug.h for flags
+#endif
+
+PDRIVER_OBJECT pAcdDriverObjectG;
+PDEVICE_OBJECT pAcdDeviceObjectG;
+
+HANDLE hSignalNotificationThreadG;
+
+//
+// Imported routines
+//
+VOID
+AcdNotificationRequestThread(
+ PVOID context
+ );
+
+//
+// External function prototypes
+//
+NTSTATUS
+AcdDispatch(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ );
+
+VOID
+AcdConnectionTimer(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PVOID pContext
+ );
+
+//
+// Internal function prototypes
+//
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT pDriverObject,
+ IN PUNICODE_STRING pRegistryPath
+ );
+
+BOOLEAN
+GetComputerName(
+ IN PUCHAR szName,
+ IN USHORT cbName
+ );
+
+VOID
+AcdUnload(
+ IN PDRIVER_OBJECT pDriverObject
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT, DriverEntry)
+#pragma alloc_text(PAGE, AcdUnload)
+#endif // ALLOC_PRAGMA
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT pDriverObject,
+ IN PUNICODE_STRING pRegistryPath
+ )
+
+/*++
+
+DESCRIPTION
+ Initialization routine for the network connection notification driver.
+ It creates the device object and initializes the driver.
+
+ARGUMENTS
+ pDriverObject: a pointer to the driver object created by the system.
+
+ pRegistryPath - the name of the configuration node in the registry.
+
+RETURN VALUE
+ The final status from the initialization operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ UNICODE_STRING deviceName;
+ ULONG i;
+ OBJECT_ATTRIBUTES objectAttributes;
+ IO_STATUS_BLOCK ioStatusBlock;
+ PDEVICE_OBJECT pDeviceObject;
+ PFILE_OBJECT pFileObject;
+
+ //
+ // Initialize the spin lock.
+ //
+ KeInitializeSpinLock(&AcdSpinLockG);
+ //
+ // Initialize the notification and completion
+ // connection queues.
+ //
+ InitializeListHead(&AcdNotificationQueueG);
+ InitializeListHead(&AcdCompletionQueueG);
+ InitializeListHead(&AcdConnectionQueueG);
+ InitializeListHead(&AcdDriverListG);
+ //
+ // Initialize our zone allocator.
+ //
+ InitializeObjectAllocator();
+ //
+ // Create the device object.
+ //
+ pAcdDriverObjectG = pDriverObject;
+ RtlInitUnicodeString(&deviceName, ACD_DEVICE_NAME);
+ status = IoCreateDevice(
+ pDriverObject,
+ 0,
+ &deviceName,
+ FILE_DEVICE_ACD,
+ 0,
+ FALSE,
+ &pAcdDeviceObjectG);
+
+ if (!NT_SUCCESS(status)) {
+ DbgPrint(
+ "AcdDriverEntry: IoCreateDevice failed (status=0x%x)\n",
+ status);
+ return status;
+ }
+ //
+ // Initialize the driver object.
+ //
+ //pDriverObject->DriverUnload = AcdUnload;
+ pDriverObject->DriverUnload = NULL;
+ for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
+ pDriverObject->MajorFunction[i] = AcdDispatch;
+ pDriverObject->FastIoDispatch = NULL;
+ //
+ // Initialize the connection timer. This is
+ // used to make sure pending requests aren't
+ // blocked forever because the user-space
+ // process died trying to make a connection.
+ //
+ IoInitializeTimer(pAcdDeviceObjectG, AcdConnectionTimer, NULL);
+ //
+ // Create the worker thread. We need
+ // a thread because these operations can occur at
+ // DPC irql.
+ //
+ KeInitializeEvent(
+ &AcdRequestThreadEventG,
+ NotificationEvent,
+ FALSE);
+ status = PsCreateSystemThread(
+ &hSignalNotificationThreadG,
+ THREAD_ALL_ACCESS,
+ NULL,
+ NULL,
+ NULL,
+ AcdNotificationRequestThread,
+ NULL);
+ if (!NT_SUCCESS(status)) {
+ DbgPrint(
+ "AcdDriverEntry: PsCreateSystemThread failed (status=0x%x)\n",
+ status);
+ return status;
+ }
+
+ return STATUS_SUCCESS;
+} // DriverEntry
+
+
+
+VOID
+AcdUnload(
+ IN PDRIVER_OBJECT pDriverObject
+ )
+{
+ NTSTATUS status;
+
+ //
+ // BUGBUG: Make sure to unlink all driver
+ // blocks before unloading!
+ //
+ IoDeleteDevice(pAcdDeviceObjectG);
+ //
+ // Free zone allocator.
+ //
+ FreeObjectAllocator();
+} // AcdUnload
diff --git a/private/ntos/tdi/acd/rasacd.rc b/private/ntos/tdi/acd/rasacd.rc
new file mode 100644
index 000000000..d8c0d68bf
--- /dev/null
+++ b/private/ntos/tdi/acd/rasacd.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "RAS Automatic Connection Driver"
+#define VER_INTERNALNAME_STR "rasacd.sys"
+#define VER_ORIGINALFILENAME_STR "rasacd.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/tdi/acd/request.c b/private/ntos/tdi/acd/request.c
new file mode 100644
index 000000000..7976e733d
--- /dev/null
+++ b/private/ntos/tdi/acd/request.c
@@ -0,0 +1,303 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ request.c
+
+Abstract:
+
+ Worker thread for the automatic connection driver.
+
+Author:
+
+ Anthony Discolo (adiscolo) 17-Apr-1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+--*/
+
+#include <ndis.h>
+#include <cxport.h>
+#include <tdi.h>
+#include <tdikrnl.h>
+#include <tdistat.h>
+#include <tdiinfo.h>
+#include <acd.h>
+
+#include "acdapi.h"
+#include "acddefs.h"
+#include "mem.h"
+#include "debug.h"
+
+//
+// External declarations
+//
+VOID AcdPrintAddress(
+ IN PACD_ADDR pAddr
+ );
+
+
+
+VOID
+ProcessCompletion(
+ IN PACD_COMPLETION pCompletion,
+ IN KIRQL irqlCancel,
+ IN KIRQL irqlLock
+ )
+{
+ PLIST_ENTRY pHead;
+ KIRQL irql;
+ PIRP pIrp;
+ PIO_STACK_LOCATION pIrpSp;
+ PACD_NOTIFICATION pNotification;
+
+ ASSERT(!IsListEmpty(&AcdNotificationQueueG));
+ //
+ // Complete the next irp in the
+ // AcdNotificationQueueG queue. These
+ // represent the ioctl completions the
+ // system service has posted. Completing
+ // this request will start the system service
+ // to create a new RAS connection.
+ // Logically, there is always just one.
+ //
+ pHead = RemoveHeadList(&AcdNotificationQueueG);
+ pIrp = CONTAINING_RECORD(pHead, IRP, Tail.Overlay.ListEntry);
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ //
+ // Disable the irp's cancel routine.
+ //
+ IoSetCancelRoutine(pIrp, NULL);
+ //
+ // Copy the success flag and the address into the
+ // system buffer. This will get copied into the
+ // user's buffer on return.
+ //
+ pNotification = (PACD_NOTIFICATION)pIrp->AssociatedIrp.SystemBuffer;
+ RtlCopyMemory(
+ pNotification,
+ &pCompletion->notif,
+ sizeof (ACD_NOTIFICATION));
+ IF_ACDDBG(ACD_DEBUG_WORKER) {
+ AcdPrint(("AcdNotificationRequestThread: "));
+ AcdPrintAddress(&pCompletion->notif.addr);
+ AcdPrint((", ulFlags=0x%x\n", pCompletion->notif.ulFlags));
+ }
+ //
+ // We can release both the cancel lock
+ // and our lock now.
+ //
+ KeReleaseSpinLock(&AcdSpinLockG, irqlLock);
+ IoReleaseCancelSpinLock(irqlCancel);
+ //
+ // Set the status code and the number
+ // of bytes to be copied back to the user
+ // buffer.
+ //
+ pIrp->IoStatus.Status = STATUS_SUCCESS;
+ pIrp->IoStatus.Information = sizeof (ACD_NOTIFICATION);
+ //
+ // Complete the irp.
+ //
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+} // ProcessCompletion
+
+
+
+VOID
+AcdNotificationRequestThread(
+ PVOID context
+ )
+
+/*++
+
+DESCRIPTION
+ This thread handles the notification that an automatic
+ connection may need to be initiated. This needs to
+ happen in a separate thread, because the notification
+ may occur at DPC irql.
+
+ARGUMENTS
+ None.
+
+RETURN VALUE
+ None.
+
+--*/
+
+{
+ KIRQL irql, irql2;
+ PLIST_ENTRY pEntry, pEntry2;
+ PACD_CONNECTION pConnection;
+ PACD_COMPLETION pCompletion;
+ BOOLEAN bStartTimer, bStopTimer;
+
+ UNREFERENCED_PARAMETER(context);
+
+ IoStartTimer(pAcdDeviceObjectG);
+
+ for (;;) {
+ bStartTimer = bStopTimer = FALSE;
+ //
+ // Acquire our lock.
+ //
+ IoAcquireCancelSpinLock(&irql);
+ KeAcquireSpinLock(&AcdSpinLockG, &irql2);
+ //
+ // If there are no irps to complete,
+ // then go back to sleep.
+ //
+ if (IsListEmpty(&AcdNotificationQueueG)) {
+ IF_ACDDBG(ACD_DEBUG_WORKER) {
+ AcdPrint(("AcdNotificationRequestThread: no ioctl to complete\n"));
+ }
+ KeReleaseSpinLock(&AcdSpinLockG, irql2);
+ IoReleaseCancelSpinLock(irql);
+ goto again;
+ }
+ //
+ // Search for connections that haven't
+ // been processed yet.
+ //
+ for (pEntry = AcdConnectionQueueG.Flink;
+ pEntry != &AcdConnectionQueueG;
+ pEntry = pEntry->Flink)
+ {
+ pConnection = CONTAINING_RECORD(pEntry, ACD_CONNECTION, ListEntry);
+
+ //
+ // Don't issue a request to the service
+ // for more than one simultaneous connection.
+ //
+ IF_ACDDBG(ACD_DEBUG_WORKER) {
+ AcdPrint((
+ "AcdNotificationRequestThread: pConnection=0x%x, fNotif=%d, fCompleting=%d\n",
+ pConnection,
+ pConnection->fNotif,
+ pConnection->fCompleting));
+ }
+ if (pConnection->fNotif)
+ break;
+ //
+ // Skip all connections that are in
+ // the process of being completed.
+ //
+ if (pConnection->fCompleting)
+ continue;
+ //
+ // Make sure there is at least one
+ // request in this connection that
+ // hasn't been canceled.
+ //
+ for (pEntry2 = pConnection->CompletionList.Flink;
+ pEntry2 != &pConnection->CompletionList;
+ pEntry2 = pEntry2->Flink)
+ {
+ pCompletion = CONTAINING_RECORD(pEntry2, ACD_COMPLETION, ListEntry);
+
+ if (!pCompletion->fCanceled) {
+ IF_ACDDBG(ACD_DEBUG_WORKER) {
+ AcdPrint((
+ "AcdNotificationRequestThread: starting pConnection=0x%x, pCompletion=0x%x\n",
+ pConnection,
+ pCompletion));
+ }
+ pConnection->fNotif = TRUE;
+ //
+ // This call releases both the cancel lock
+ // and our lock.
+ //
+ ProcessCompletion(pCompletion, irql, irql2);
+ //
+ // Start the connection timer.
+ //
+ bStartTimer = TRUE;
+ //
+ // We can only process one completion
+ // at a time.
+ //
+ goto again;
+ }
+ }
+ }
+ //
+ // Complete other requests.
+ //
+ if (!IsListEmpty(&AcdCompletionQueueG)) {
+ pEntry = RemoveHeadList(&AcdCompletionQueueG);
+ pCompletion = CONTAINING_RECORD(pEntry, ACD_COMPLETION, ListEntry);
+
+ IF_ACDDBG(ACD_DEBUG_WORKER) {
+ AcdPrint((
+ "AcdNotificationRequestThread: starting pCompletion=0x%x\n",
+ pCompletion));
+ }
+ //
+ // This call releases both the cancel lock
+ // and our lock.
+ //
+ ProcessCompletion(pCompletion, irql, irql2);
+ //
+ // We are done with the completion,
+ // so we can free the memory now.
+ //
+ FREE_MEMORY(pCompletion);
+ //
+ // We can only process one completion
+ // at a time.
+ //
+ goto again;
+
+ }
+ //
+ // If there are no connections pending,
+ // then stop the connection timer.
+ //
+ if (IsListEmpty(&AcdConnectionQueueG))
+ bStopTimer = TRUE;
+ //
+ // Release our lock.
+ //
+ KeReleaseSpinLock(&AcdSpinLockG, irql2);
+ IoReleaseCancelSpinLock(irql);
+again:
+ //
+ // Start or stop the timer, depending
+ // on what we found while we had the
+ // spinlock. We can't hold our spin
+ // lock when we call the Io*Timer
+ // routines.
+ //
+#ifdef notdef
+ if (bStopTimer)
+ IoStopTimer(pAcdDeviceObjectG);
+ else if (bStartTimer)
+ IoStartTimer(pAcdDeviceObjectG);
+#endif
+ //
+ // Wait for something to do. This event
+ // will be signaled by AcdSignalNotification().
+ //
+ IF_ACDDBG(ACD_DEBUG_WORKER) {
+ AcdPrint(("AcdNotificationRequestThread: waiting on AcdPendingCompletionEventG\n"));
+ }
+ KeWaitForSingleObject(
+ &AcdRequestThreadEventG,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ KeClearEvent(&AcdRequestThreadEventG);
+ IF_ACDDBG(ACD_DEBUG_WORKER) {
+ AcdPrint(("AcdNotificationRequestThread: AcdPendingCompletionEventG signalled\n"));
+ }
+ }
+} // AcdNotificationRequestThread
+
+
diff --git a/private/ntos/tdi/acd/request.h b/private/ntos/tdi/acd/request.h
new file mode 100644
index 000000000..4d2c69824
--- /dev/null
+++ b/private/ntos/tdi/acd/request.h
@@ -0,0 +1,31 @@
+/*++
+
+Copyright(c) 1995 Microsoft Corporation
+
+MODULE NAME
+ request.h
+
+ABSTRACT
+ Header file for completion queue routines.
+
+AUTHOR
+ Anthony Discolo (adiscolo) 18-Aug-1995
+
+REVISION HISTORY
+
+--*/
+
+PACD_COMPLETION GetNextRequest();
+
+BOOLEAN
+EqualAddress(
+ PACD_ADDR pszAddr1,
+ PACD_ADDR pszAddr2
+ );
+
+PACD_COMPLETION GetNextRequestAddress(
+ IN PACD_ADDR pszAddr
+ );
+
+PACD_COMPLETION GetCurrentRequest();
+
diff --git a/private/ntos/tdi/acd/sources b/private/ntos/tdi/acd/sources
new file mode 100644
index 000000000..b787b8419
--- /dev/null
+++ b/private/ntos/tdi/acd/sources
@@ -0,0 +1,46 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=
+MINORCOMP=
+
+TARGETNAME=rasacd
+TARGETPATH=obj
+TARGETTYPE=DRIVER
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+INCLUDES=..\inc;..\..\inc;..\..\..\inc;..\..\..\..\inc
+
+C_DEFINES=-DNT -DNETSCAPE_HACK
+
+SOURCES= \
+ ntinit.c \
+ ntdisp.c \
+ api.c \
+ request.c \
+ timer.c \
+ mem.c \
+ rasacd.rc
+
diff --git a/private/ntos/tdi/acd/table.c b/private/ntos/tdi/acd/table.c
new file mode 100644
index 000000000..0846b97e6
--- /dev/null
+++ b/private/ntos/tdi/acd/table.c
@@ -0,0 +1,286 @@
+/*++
+
+Copyright(c) 1995 Microsoft Corporation
+
+MODULE NAME
+ table.c
+
+ABSTRACT
+ Generic hash table manipulation routines.
+
+AUTHOR
+ Anthony Discolo (adiscolo) 28-Jul-1995
+
+REVISION HISTORY
+
+--*/
+
+#include <ndis.h>
+#include <cxport.h>
+#include <tdi.h>
+#include <tdikrnl.h>
+#include <tdistat.h>
+#include <tdiinfo.h>
+#include <acd.h>
+#include <acdapi.h>
+
+#include "table.h"
+#include "acddefs.h"
+#include "mem.h"
+#include "debug.h"
+
+
+
+PHASH_TABLE
+NewTable()
+{
+ PHASH_TABLE pTable;
+ INT i;
+
+ ALLOCATE_MEMORY(sizeof (HASH_TABLE), pTable);
+ if (pTable == NULL) {
+ DbgPrint("AcdNewTable: ExAllocatePool failed\n");
+ return NULL;
+ }
+ KeInitializeSpinLock(&pTable->SpinLock);
+ for (i = 0; i < NBUCKETS; i++)
+ InitializeListHead(&pTable->ListEntry[i]);
+
+ return pTable;
+} // NewTable
+
+
+
+VOID
+FreeHashTableEntry(
+ PHASH_ENTRY pHashEntry
+ )
+{
+ FREE_MEMORY(pHashEntry);
+} // FreeHashTableEntry
+
+
+
+VOID
+ClearTable(
+ PHASH_TABLE pTable
+ )
+{
+ KIRQL irql;
+ INT i;
+ PLIST_ENTRY pHead;
+ PHASH_ENTRY pHashEntry;
+
+ KeAcquireSpinLock(&pTable->SpinLock, &irql);
+ for (i = 0; i < NBUCKETS; i++) {
+ while (!IsListEmpty(&pTable->ListEntry[i])) {
+ pHead = RemoveHeadList(&pTable->ListEntry[i]);
+ pHashEntry = CONTAINING_RECORD(pHead, HASH_ENTRY, ListEntry);
+
+ FreeHashTableEntry(pHashEntry);
+ }
+ }
+ KeReleaseSpinLock(&pTable->SpinLock, irql);
+} // ClearTable
+
+
+
+VOID
+FreeTable(
+ PHASH_TABLE pTable
+ )
+{
+ ClearTable(pTable);
+ FREE_MEMORY(pTable);
+} // FreeTable
+
+
+
+VOID
+EnumTable(
+ IN PHASH_TABLE pTable,
+ IN PHASH_TABLE_ENUM_PROC pProc,
+ IN PVOID pArg
+ )
+{
+ INT i;
+ PLIST_ENTRY pEntry;
+ PHASH_ENTRY pHashEntry;
+ KIRQL irql;
+
+ KeAcquireSpinLock(&pTable->SpinLock, &irql);
+ for (i = 0; i < NBUCKETS; i++) {
+ for (pEntry = pTable->ListEntry[i].Flink;
+ pEntry != &pTable->ListEntry[i];
+ pEntry = pEntry->Flink)
+ {
+ pHashEntry = CONTAINING_RECORD(pEntry, HASH_ENTRY, ListEntry);
+
+ //
+ // If the enumerator procedure
+ // returns FALSE, terminate the
+ // enumeration.
+ //
+ if (!pProc(pArg, &pHashEntry->szKey, pHashEntry->ulData))
+ goto done;
+ }
+ }
+done:
+ KeReleaseSpinLock(&pTable->SpinLock, irql);
+} // EnumTable
+
+
+
+INT
+HashString(
+ IN PACD_ADDR pszKey
+ )
+{
+ ULONG ulHashValue = 0;
+ CHAR ch;
+ PCSZ p = (PCSZ)pszKey;
+
+ while (*p != L'\0') {
+ ch = tolower(*p);
+ ulHashValue += (INT)(ch) * (INT)(ch);
+ p++;
+ }
+
+ return (INT)(ulHashValue % NBUCKETS);
+} // HashString
+
+
+
+BOOLEAN
+IsEqualKey(
+ PACD_ADDR pszKey1,
+ PACD_ADDR pszKey2
+ )
+{
+ BOOLEAN fFound;
+
+ fFound = (BOOLEAN)RtlEqualMemory(pszKey1, pszKey2, sizeof (ACD_ADDR));
+ IF_ACDDBG(ACD_DEBUG_TABLE) {
+ AcdPrint(("AcdIsEqualKey(%s, %s) returns %d\n", pszKey1, pszKey2, fFound));
+ }
+ return fFound;
+} // IsEqualKey
+
+
+
+PHASH_ENTRY
+GetTableEntryNL(
+ IN PHASH_TABLE pTable,
+ IN PACD_ADDR pszKey
+ )
+{
+ INT nBucket = HashString(pszKey);
+ PLIST_ENTRY pEntry;
+ PHASH_ENTRY pHashEntry;
+
+ for (pEntry = pTable->ListEntry[nBucket].Flink;
+ pEntry != &pTable->ListEntry[nBucket];
+ pEntry = pEntry->Flink)
+ {
+ pHashEntry = CONTAINING_RECORD(pEntry, HASH_ENTRY, ListEntry);
+
+ if (IsEqualKey(&pHashEntry->szKey, pszKey)) {
+ IF_ACDDBG(ACD_DEBUG_TABLE) {
+ AcdPrint(("AcdGetTableEntryNL(0x%x, %s) returns 0x%x\n", pTable, pszKey, pHashEntry));
+ }
+ return pHashEntry;
+ }
+ }
+
+ IF_ACDDBG(ACD_DEBUG_TABLE) {
+ AcdPrint(("AcdGetTableEntryNL(0x%x, %s) returns NULL\n", pTable, pszKey));
+ }
+ return NULL;
+} // GetTableEntryNL
+
+
+
+BOOLEAN
+GetTableEntry(
+ IN PHASH_TABLE pTable,
+ IN PACD_ADDR pszKey,
+ OUT PULONG pulData
+ )
+{
+ KIRQL irql;
+ PHASH_ENTRY pHashEntry;
+
+ KeAcquireSpinLock(&pTable->SpinLock, &irql);
+ pHashEntry = GetTableEntryNL(pTable, pszKey);
+ KeReleaseSpinLock(&pTable->SpinLock, irql);
+
+ if (pHashEntry != NULL) {
+ if (pulData != NULL)
+ *pulData = pHashEntry->ulData;
+ return TRUE;
+ }
+
+ return FALSE;
+} // GetTableEntry
+
+
+
+BOOLEAN
+PutTableEntry(
+ IN PHASH_TABLE pTable,
+ IN PACD_ADDR pszKey,
+ IN ULONG ulData
+ )
+{
+ KIRQL irql;
+ BOOLEAN fSuccess = FALSE;
+ INT nBucket = HashString(pszKey);
+ PHASH_ENTRY pHashEntry;
+
+ IF_ACDDBG(ACD_DEBUG_TABLE) {
+ AcdPrint(("AcdPutTableEntry(0x%x, %s)\n", pTable, pszKey));
+ }
+
+ KeAcquireSpinLock(&pTable->SpinLock, &irql);
+
+ pHashEntry = GetTableEntryNL(pTable, pszKey);
+ if (pHashEntry == NULL) {
+ ALLOCATE_MEMORY(ACD_OBJECT_HASHENTRY, pHashEntry);
+ if (pHashEntry == NULL) {
+ DbgPrint("PutTableEntry: ExAllocatePool failed\n");
+ goto done;
+ }
+ RtlCopyMemory(pHashEntry->szKey, pszKey, sizeof (ACD_ADDR));
+ InsertHeadList(
+ &pTable->ListEntry[nBucket],
+ &pHashEntry->ListEntry);
+ }
+ pHashEntry->ulData = ulData;
+ fSuccess = TRUE;
+
+done:
+ KeReleaseSpinLock(&pTable->SpinLock, irql);
+ return fSuccess;
+} // PutTableEntry
+
+
+
+BOOLEAN
+DeleteTableEntry(
+ IN PHASH_TABLE pTable,
+ IN PACD_ADDR pszKey
+ )
+{
+ KIRQL irql;
+ PHASH_ENTRY pHashEntry;
+
+ KeAcquireSpinLock(&pTable->SpinLock, &irql);
+ pHashEntry = GetTableEntryNL(pTable, pszKey);
+ if (pHashEntry != NULL) {
+ RemoveEntryList(&pHashEntry->ListEntry);
+ FreeHashTableEntry(pHashEntry);
+ }
+ KeReleaseSpinLock(&pTable->SpinLock, irql);
+
+ return (pHashEntry != NULL);
+} // DeleteTableEntry
diff --git a/private/ntos/tdi/acd/table.h b/private/ntos/tdi/acd/table.h
new file mode 100644
index 000000000..17a5ef1a0
--- /dev/null
+++ b/private/ntos/tdi/acd/table.h
@@ -0,0 +1,77 @@
+/*++
+
+Copyright(c) 1995 Microsoft Corporation
+
+MODULE NAME
+ table.h
+
+ABSTRACT
+ Header file for generic hash table routines.
+
+AUTHOR
+ Anthony Discolo (adiscolo) 28-Jul-1995
+
+REVISION HISTORY
+
+--*/
+
+//
+// Number of hash table buckets.
+//
+#define NBUCKETS 13
+
+//
+// Generic hash table structure.
+//
+typedef struct _HASH_TABLE {
+ LIST_ENTRY ListEntry[NBUCKETS];
+ KSPIN_LOCK SpinLock;
+} HASH_TABLE, *PHASH_TABLE;
+
+//
+// Hash table enumerator procedure.
+// Returns TRUE to continue enumeration,
+// FALSE to terminate enumeration.
+//
+typedef BOOLEAN (*PHASH_TABLE_ENUM_PROC)(PVOID, PACD_ADDR, ULONG);
+
+
+PHASH_TABLE
+NewTable();
+
+VOID
+ClearTable(
+ IN PHASH_TABLE pTable
+ );
+
+VOID
+FreeTable(
+ IN PHASH_TABLE pTable
+ );
+
+VOID
+EnumTable(
+ IN PHASH_TABLE pTable,
+ IN PHASH_TABLE_ENUM_PROC pProc,
+ IN PVOID pArg
+ );
+
+BOOLEAN
+GetTableEntry(
+ IN PHASH_TABLE pTable,
+ IN PACD_ADDR pszKey,
+ OUT PULONG pulData
+ );
+
+BOOLEAN
+PutTableEntry(
+ IN PHASH_TABLE pTable,
+ IN PACD_ADDR pszKey,
+ IN ULONG ulData
+ );
+
+BOOLEAN
+DeleteTableEntry(
+ IN PHASH_TABLE pTable,
+ IN PACD_ADDR pszKey
+ );
diff --git a/private/ntos/tdi/acd/timer.c b/private/ntos/tdi/acd/timer.c
new file mode 100644
index 000000000..cf4f3ab63
--- /dev/null
+++ b/private/ntos/tdi/acd/timer.c
@@ -0,0 +1,145 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ timer.c
+
+Abstract:
+
+ Timer thread to monitor connection progress in the
+ automatic connection driver (acd.sys).
+
+Author:
+
+ Anthony Discolo (adiscolo) 25-Apr-1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+--*/
+
+#include <ndis.h>
+#include <cxport.h>
+#include <tdi.h>
+#include <tdikrnl.h>
+#include <tdistat.h>
+#include <tdiinfo.h>
+#include <acd.h>
+
+#include "acdapi.h"
+#include "table.h"
+#include "acddefs.h"
+#include "debug.h"
+
+//
+// Imported routines.
+//
+VOID
+AcdSignalCompletionCommon(
+ IN PACD_CONNECTION pConnection,
+ IN BOOLEAN fSuccess
+ );
+
+//
+// Keep track how long the user-space
+// process has been attempting a connection.
+//
+#define ACD_MAX_TIMER_CALLS 3*60 // 3 minutes
+
+//
+// We give the user-space process
+// some slack on missed pings.
+//
+#define ACD_MAX_MISSED_PINGS 40 // 20 seconds
+
+
+
+VOID
+AcdConnectionTimer(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PVOID pContext
+ )
+{
+ PLIST_ENTRY pEntry;
+ PACD_CONNECTION pConnection;
+ BOOLEAN bCancel = FALSE;
+
+ //
+ // Acquire the spin lock.
+ // We're guaranteed to be at DPC
+ // since this is a timer routine.
+ //
+ KeAcquireSpinLockAtDpcLevel(&AcdSpinLockG);
+ //
+ // If the user-space process responsible
+ // for creating the connection hasn't
+ // pinged us in a while, or if it hasn't
+ // created a connection in 3 minutes,
+ // cancel all the pending requests.
+ //
+ for (pEntry = AcdConnectionQueueG.Flink;
+ pEntry != &AcdConnectionQueueG;
+ pEntry = pEntry->Flink)
+ {
+ pConnection = CONTAINING_RECORD(pEntry, ACD_CONNECTION, ListEntry);
+
+ IF_ACDDBG(ACD_DEBUG_TIMER) {
+ PACD_COMPLETION pCompletion;
+
+ AcdPrint((
+ "AcdConnectionTimer: pConnection=0x%x, fNotif=%d, szAddr=",
+ pConnection,
+ pConnection->fNotif));
+ pCompletion = CONTAINING_RECORD(pConnection->CompletionList.Flink, ACD_COMPLETION, ListEntry);
+ AcdPrintAddress(&pCompletion->notif.addr);
+ AcdPrint((", nTimerCalls=%d, nMissedPings=%d\n",
+ pConnection->ulTimerCalls,
+ pConnection->ulMissedPings));
+ }
+ //
+ // If we haven't reported the connection to
+ // user space yet, or it is in the process of
+ // being completed, then don't time it out.
+ //
+ if (!pConnection->fNotif || pConnection->fCompleting)
+ continue;
+
+ pConnection->ulTimerCalls++;
+ if (pConnection->fProgressPing)
+ pConnection->ulMissedPings = 0;
+ else
+ pConnection->ulMissedPings++;
+ if (pConnection->ulTimerCalls >= ACD_MAX_TIMER_CALLS ||
+ pConnection->ulMissedPings >= ACD_MAX_MISSED_PINGS)
+ {
+ IF_ACDDBG(ACD_DEBUG_TIMER) {
+ AcdPrint((
+ "AcdConnectionTimer: canceling pConnection=0x%x\n",
+ pConnection));
+ }
+ //
+ // Set the completion-in-progress flag so
+ // this request cannot be completed after
+ // we release the spin lock.
+ //
+ pConnection->fCompleting = TRUE;
+ bCancel = TRUE;
+ break;
+ }
+ }
+ //
+ // Release the spin lock.
+ //
+ KeReleaseSpinLockFromDpcLevel(&AcdSpinLockG);
+ //
+ // We now process all the canceled requests.
+ //
+ if (bCancel)
+ AcdSignalCompletionCommon(pConnection, FALSE);
+} // AcdConnectionTimer
+
diff --git a/private/ntos/tdi/dirs b/private/ntos/tdi/dirs
new file mode 100644
index 000000000..14819da36
--- /dev/null
+++ b/private/ntos/tdi/dirs
@@ -0,0 +1,32 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS= \
+ isn \
+ isnn \
+ nbf \
+ wrapper \
+ tcpip \
+ acd
+
+OPTIONAL_DIRS= \
+ loopback
diff --git a/private/ntos/tdi/irda/dirs b/private/ntos/tdi/irda/dirs
new file mode 100644
index 000000000..0ea6a777b
--- /dev/null
+++ b/private/ntos/tdi/irda/dirs
@@ -0,0 +1,10 @@
+DIRS= irlap \
+ driver
+
+
+
+
+
+
+
+
diff --git a/private/ntos/tdi/irda/driver/irda.c b/private/ntos/tdi/irda/driver/irda.c
new file mode 100644
index 000000000..72bdf3881
--- /dev/null
+++ b/private/ntos/tdi/irda/driver/irda.c
@@ -0,0 +1,132 @@
+/*
+ * IRDA.C
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+
+//#include <precomp.h>
+#include <irda.h>
+#include <irdalink.h>
+#include <irmac.h>
+#include <irlap.h>
+#include <irlmp.h>
+#include <tmp.h>
+
+int irdaDbgSettings = 1 + \
+ DBG_ERROR + \
+ DBG_WARN + \
+/*DBG_FUNCTION + */ \
+ /*DBG_NDIS +*/ \
+/* DBG_IRLAPLOG +*/ \
+ DBG_IRLAP;
+
+LIST_ENTRY IrdaLinkCbList;
+
+/*
+ ********************************************************************************
+ * DriverEntry
+ ********************************************************************************
+ *
+ *
+ *
+ */
+NTSTATUS DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath)
+{
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ DEBUGMSG(DBG_FUNCTION,("+DriverEntry(IRDA)\n"));
+
+ InitializeListHead(&IrdaLinkCbList);
+
+ // IRLMP initialize
+ // IRLAP initialize
+
+ if ((Status = IrdaNdisInitialize()) != STATUS_SUCCESS)
+ {
+ goto done;
+ }
+
+done:
+
+ DEBUGMSG(DBG_FUNCTION, ("-DriverEntry(IRDA), rc %x\n", Status));
+
+ return Status;
+}
+
+void
+IrdaTimerInitialize(PIRDA_TIMER pTimer,
+ VOID (*ExpFunc)(PVOID Context),
+ UINT Timeout,
+ PVOID Context)
+{
+ CTEInitTimer(&pTimer->CteTimer);
+ pTimer->ExpFunc = ExpFunc;
+ pTimer->Context = Context;
+ pTimer->Timeout = Timeout;
+
+ DEBUGMSG(DBG_FUNCTION, ("IrdaTimerIntialize %s\n", pTimer->pName));
+}
+
+void
+TimerFunc(CTEEvent *Event, void *Arg)
+{
+ PIRDA_TIMER pIrdaTimer = (PIRDA_TIMER) Arg;
+ int rc;
+
+ DEBUGMSG(DBG_FUNCTION, ("Timer expired, context %x\n",
+ pIrdaTimer));
+
+ if (pIrdaTimer->Late != TRUE)
+ {
+ pIrdaTimer->ExpFunc(pIrdaTimer->Context);
+ }
+ else
+ {
+ DEBUGMSG(DBG_WARN,
+ (TEXT("IRDA TIMER LATE, ignoring\r\n")));
+
+ pIrdaTimer->Late = FALSE;
+ }
+
+ return;
+}
+
+VOID
+IrdaTimerStart(PIRDA_TIMER pIrdaTimer)
+{
+
+ pIrdaTimer->Late = FALSE;
+ CTEStartTimer(&pIrdaTimer->CteTimer, pIrdaTimer->Timeout,
+ TimerFunc, (PVOID) pIrdaTimer);
+
+ DEBUGMSG(DBG_FUNCTION, ("Start timer %s (%dms) context %x\n",
+ pIrdaTimer->pName,
+ pIrdaTimer->Timeout,
+ pIrdaTimer));
+ return;
+}
+
+VOID
+IrdaTimerStop(PIRDA_TIMER pIrdaTimer)
+{
+ if (CTEStopTimer(&pIrdaTimer->CteTimer) == 0)
+ {
+ pIrdaTimer->Late = TRUE;
+ }
+ DEBUGMSG(DBG_FUNCTION, ("Timer %s stopped\n", pIrdaTimer->pName));
+
+ return;
+}
+
diff --git a/private/ntos/tdi/irda/driver/irndis.c b/private/ntos/tdi/irda/driver/irndis.c
new file mode 100644
index 000000000..903e53570
--- /dev/null
+++ b/private/ntos/tdi/irda/driver/irndis.c
@@ -0,0 +1,706 @@
+/*
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+
+//#include <precomp.h>
+#include <irda.h>
+#include <irdalink.h>
+#include <ntddndis.h>
+#include <ndis.h>
+#include <irlap.h>
+
+NDIS_HANDLE NdisIrdaHandle = NULL;
+
+// Translate an OID query to LAP definition
+VOID
+OidToLapQos(
+ UINT ParmTable[],
+ UINT ValArray[],
+ UINT Cnt,
+ PUINT pBitField)
+{
+ UINT i, j;
+
+ *pBitField = 0;
+ for (i = 0; i < Cnt; i++)
+ for (j = 0; j <= PV_TABLE_MAX_BIT; j++)
+ if (ValArray[i] == ParmTable[j])
+ *pBitField |= 1<<j;
+}
+
+// Synchronous request for an OID
+NDIS_STATUS
+IrdaQueryOid(
+ IN PIRDA_LINK_CB pIrdaLinkCb,
+ IN NDIS_OID Oid,
+ OUT PUINT pQBuf,
+ IN OUT PUINT pQBufLen)
+{
+ NDIS_REQUEST NdisRequest;
+ NDIS_STATUS Status;
+
+ NdisResetEvent(&pIrdaLinkCb->SyncEvent);
+
+ NdisRequest.RequestType = NdisRequestQueryInformation;
+ NdisRequest.DATA.QUERY_INFORMATION.Oid = Oid;
+ NdisRequest.DATA.QUERY_INFORMATION.InformationBuffer = pQBuf;
+ NdisRequest.DATA.QUERY_INFORMATION.InformationBufferLength =
+ *pQBufLen * sizeof(UINT);
+
+ NdisRequest(&Status, pIrdaLinkCb->NdisBindingHandle, &NdisRequest);
+
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ NdisWaitEvent(&pIrdaLinkCb->SyncEvent, 0);
+ Status = pIrdaLinkCb->SyncStatus;
+ }
+
+ *pQBufLen = NdisRequest.DATA.QUERY_INFORMATION.BytesWritten / sizeof(UINT);
+
+ return Status;
+}
+
+// Sync request to set an Oid
+NDIS_STATUS
+IrdaSetOid(
+ IN PIRDA_LINK_CB pIrdaLinkCb,
+ IN NDIS_OID Oid,
+ IN UINT Val)
+{
+ NDIS_REQUEST NdisRequest;
+ NDIS_STATUS Status;
+
+ NdisResetEvent(&pIrdaLinkCb->SyncEvent);
+
+ NdisRequest.RequestType = NdisRequestSetInformation;
+ NdisRequest.DATA.SET_INFORMATION.Oid = Oid;
+ NdisRequest.DATA.SET_INFORMATION.InformationBuffer = &Val;
+ NdisRequest.DATA.SET_INFORMATION.InformationBufferLength = sizeof(UINT);
+
+ NdisRequest(&Status, pIrdaLinkCb->NdisBindingHandle, &NdisRequest);
+
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ NdisWaitEvent(&pIrdaLinkCb->SyncEvent, 0);
+ Status = pIrdaLinkCb->SyncStatus;
+ }
+ return Status;
+}
+
+// Allocate a message for LAP to use for internally generated frames.
+IRDA_MSG *
+AllocMacIMsg(PIRDA_LINK_CB pIrdaLinkCb)
+{
+ NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+ IRDA_MSG *pIMsg;
+
+ pIMsg = (IRDA_MSG *) NdisInterlockedRemoveHeadList(
+ &pIrdaLinkCb->IMsgList, &pIrdaLinkCb->SpinLock);
+
+ if (pIMsg == NULL)
+ {
+ NdisAllocateMemory(&pIMsg, sizeof(IRDA_MSG) + IRDA_MSG_DATA_SIZE,
+ 0, pa);
+ if (pIMsg == NULL)
+ return NULL;
+ pIrdaLinkCb->IMsgListLen++;
+ }
+
+ // Indicate driver owns message
+ pIMsg->IRDA_MSG_pOwner = &pIrdaLinkCb->IMsgList;
+
+ // Setup the pointers
+ pIMsg->IRDA_MSG_pHdrWrite = \
+ pIMsg->IRDA_MSG_pHdrRead = pIMsg->IRDA_MSG_Header + IRDA_HEADER_LEN;
+ pIMsg->IRDA_MSG_pBase = \
+ pIMsg->IRDA_MSG_pRead = \
+ pIMsg->IRDA_MSG_pWrite = (BYTE *) pIMsg + sizeof(IRDA_MSG);
+ pIMsg->IRDA_MSG_pLimit = pIMsg->IRDA_MSG_pBase + IRDA_MSG_DATA_SIZE-1;
+
+ return pIMsg;
+}
+
+void IrdaRequestComplete(
+ IN NDIS_HANDLE IrdaBindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ )
+{
+ PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) IrdaBindingContext;
+
+ DEBUGMSG(DBG_NDIS, ("+IrdaRequestComplete()\n"));
+
+ pIrdaLinkCb->SyncStatus = Status;
+ NdisSetEvent(&pIrdaLinkCb->SyncEvent);
+
+ return;
+}
+
+VOID IrdaOpenAdapterComplete(
+ IN NDIS_HANDLE IrdaBindingContext,
+ IN NDIS_STATUS Status,
+ IN NDIS_STATUS OpenErrorStatus
+ )
+{
+ PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) IrdaBindingContext;
+
+ DEBUGMSG(DBG_NDIS, ("+IrdaOpenAdapterComplete() IrdaBindingContext %x, Status %x\n",
+ IrdaBindingContext, Status));
+
+ pIrdaLinkCb->SyncStatus = Status;
+ NdisSetEvent(&pIrdaLinkCb->SyncEvent);
+
+ DEBUGMSG(DBG_NDIS, ("-IrdaOpenAdapterComplete()\n"));
+
+ return;
+}
+
+VOID IrdaCloseAdapterComplete(
+ IN NDIS_HANDLE IrdaBindingContext,
+ IN NDIS_STATUS Status
+ )
+{
+ PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) IrdaBindingContext;
+
+ DEBUGMSG(DBG_NDIS, ("+IrdaCloseAdapterComplete()\n"));
+
+ pIrdaLinkCb->SyncStatus = Status;
+ NdisSetEvent(&pIrdaLinkCb->SyncEvent);
+
+ DEBUGMSG(DBG_NDIS, ("-IrdaCloseAdapterComplete()\n"));
+
+ return;
+}
+
+VOID IrdaSendComplete(
+ IN NDIS_HANDLE Context,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS Status
+ )
+{
+ PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) Context;
+ PIRDA_PROTOCOL_RESERVED ProtocolReserved = \
+ (PIRDA_PROTOCOL_RESERVED) NdisPacket->ProtocolReserved;
+ PIRDA_MSG pIMsg = ProtocolReserved->pIMsg;
+ PNDIS_BUFFER NdisBuffer;
+
+ if (pIMsg->IRDA_MSG_pOwner == &pIrdaLinkCb->IMsgList)
+ {
+ NdisInterlockedInsertTailList(&pIrdaLinkCb->IMsgList,
+ &pIMsg->Linkage,
+ &pIrdaLinkCb->SpinLock);
+ }
+
+ if (NdisPacket){
+ NdisUnchainBufferAtFront(NdisPacket, &NdisBuffer);
+ while (NdisBuffer){
+ NdisFreeBuffer(NdisBuffer);
+ NdisUnchainBufferAtFront(NdisPacket, &NdisBuffer);
+ }
+
+ NdisFreePacket(NdisPacket);
+ }
+
+ DEBUGMSG(DBG_NDIS, ("+IrdaSendComplete()\n"));
+ return;
+}
+
+VOID IrdaTransferDataComplete(
+ IN NDIS_HANDLE IrdaBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ )
+{
+ DEBUGMSG(DBG_NDIS, ("+IrdaTransferDataComplete()\n"));
+ return;
+}
+
+void IrdaResetComplete(
+ IN NDIS_HANDLE IrdaBindingContext,
+ IN NDIS_STATUS Status
+ )
+{
+ DEBUGMSG(DBG_NDIS, ("+IrdaResetComplete()\n"));
+ return;
+}
+
+NDIS_STATUS IrdaReceive(
+ IN NDIS_HANDLE IrdaBindingContext,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookAheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+{
+ DEBUGMSG(DBG_NDIS, ("+IrdaReceive()\n"));
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+VOID IrdaReceiveComplete(
+ IN NDIS_HANDLE IrdaBindingContext
+ )
+{
+ DEBUGMSG(DBG_NDIS, ("+IrdaReceiveComplete()\n"));
+
+ return;
+}
+
+VOID IrdaStatus(
+ IN NDIS_HANDLE IrdaBindingContext,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ )
+{
+ PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) IrdaBindingContext;
+
+ if (GeneralStatus == NDIS_STATUS_MEDIA_BUSY)
+ {
+ DEBUGMSG(DBG_NDIS, ("STATUS_MEDIA_BUSY\n"));
+ }
+#ifdef DEBUG
+ else
+ {
+ DEBUGMSG(DBG_NDIS, ("Unknown Status indication\n"));
+ }
+#endif
+
+ return;
+}
+
+VOID IrdaStatusComplete(
+ IN NDIS_HANDLE IrdaBindingContext
+ )
+{
+ DEBUGMSG(DBG_NDIS, ("IrdaStatusComplete()\n"));
+
+ return;
+}
+
+INT IrdaReceivePacket(
+ IN NDIS_HANDLE IrdaBindingContext,
+ IN PNDIS_PACKET Packet
+ )
+{
+ UINT BufCnt, TotalLen, BufLen;
+ PNDIS_BUFFER pNdisBuf;
+ IRDA_MSG IMsg;
+ BYTE *pData;
+ PIRDA_LINK_CB pIrdaLinkCb = IrdaBindingContext;
+
+ DEBUGMSG(DBG_NDIS, ("+IrdaReceivePacket(%x)\n", pIrdaLinkCb));
+
+ NdisQueryPacket(Packet, NULL, &BufCnt, &pNdisBuf, &TotalLen);
+
+ DEBUGMSG(DBG_NDIS, (" BufCnt %d, TotalLen %d\n", BufCnt, TotalLen));
+
+ NdisQueryBuffer(pNdisBuf, &pData, &BufLen);
+
+ IMsg.Prim = MAC_DATA_IND;
+ IMsg.IRDA_MSG_pRead = pData;
+ IMsg.IRDA_MSG_pWrite = pData + BufLen;
+
+ IrlapUp(pIrdaLinkCb->IrlapContext, &IMsg);
+
+ return 0;
+}
+
+VOID IrdaBindAdapter(
+ OUT PNDIS_STATUS pStatus,
+ IN NDIS_HANDLE BindContext,
+ IN PNDIS_STRING AdapterName,
+ IN PVOID SystemSpecific1,
+ IN PVOID SystemSpecific2
+ )
+{
+ NDIS_STATUS OpenErrorStatus;
+ NDIS_MEDIUM MediumArray[] = {NdisMediumIrda};
+ UINT SelectedMediumIndex;
+ PIRDA_LINK_CB pIrdaLinkCb;
+ NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+ UINT UintArray[8];
+ UINT UintArrayCnt;
+ IRDA_MSG *pIMsg;
+ // *******************************************************
+ // *******************************************************
+ // TEMP - some these will come out of the registry
+ IRDA_QOS_PARMS LocalQos;
+ BYTE DscvInfoBuf[64];
+ int DscvInfoLen;
+ DWORD Val, Mask;
+ int i;
+#define DISCOVERY_HINT_CHARSET 0x820400
+#define DISCOVERY_NICKNAME "Aoxomoxoa"
+#define DISCOVERY_NICKNAME_LEN 9
+#define DISCOVERY_SLOTS 8
+
+ LocalQos.bfBaud = BPS_9600 | BPS_19200 | BPS_115200;
+ LocalQos.bfMaxTurnTime = MAX_TAT_500;
+ LocalQos.bfDataSize = DATA_SIZE_64|DATA_SIZE_128|DATA_SIZE_256;
+ LocalQos.bfWindowSize = FRAMES_1|FRAMES_2|FRAMES_3;
+ LocalQos.bfBofs = BOFS_3;
+ LocalQos.bfMinTurnTime = MIN_TAT_10;
+ LocalQos.bfDisconnectTime = DISC_TIME_12;
+
+ Val = DISCOVERY_HINT_CHARSET;
+
+ // Build the discovery info
+ DscvInfoLen = 0;
+ for (i = 0, Mask = 0xFF000000; i < 4; i++, Mask >>= 8)
+ {
+ if (Mask & Val || DscvInfoLen > 0)
+ {
+ DscvInfoBuf[DscvInfoLen++] = (BYTE) ((Mask & Val) >> (8 * (3-i)));
+ }
+ }
+ memcpy(DscvInfoBuf+DscvInfoLen, DISCOVERY_NICKNAME, DISCOVERY_NICKNAME_LEN);
+ DscvInfoLen += DISCOVERY_NICKNAME_LEN;
+ // TEMP ******************************************************
+ // *******************************************************
+
+ DEBUGMSG(1, ("+IrdaBindAdapter() \"%ws\", BindContext %x\n",
+ AdapterName->Buffer, BindContext));
+
+ NdisAllocateMemory((PVOID *)&pIrdaLinkCb, sizeof(IRDA_LINK_CB), 0, pa);
+
+ if (!pIrdaLinkCb)
+ {
+ *pStatus = STATUS_INSUFFICIENT_RESOURCES;
+ goto exit10;
+ }
+
+ NdisZeroMemory(pIrdaLinkCb, sizeof(IRDA_LINK_CB));
+ // Add a signature
+ NdisInitializeEvent(&pIrdaLinkCb->SyncEvent);
+ NdisResetEvent(&pIrdaLinkCb->SyncEvent);
+ NdisAllocateSpinLock(&pIrdaLinkCb->SpinLock);
+
+ NdisAllocateBufferPool(pStatus,
+ &pIrdaLinkCb->BufferPool,
+ IRDA_NDIS_BUFFER_POOL_SIZE);
+ if (*pStatus != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGMSG(DBG_ERROR, ("NdisAllocateBufferPool failed\n"));
+ goto error10; // free pIrdaLinkCB
+ }
+
+ NdisAllocatePacketPool(pStatus,
+ &pIrdaLinkCb->PacketPool,
+ IRDA_NDIS_PACKET_POOL_SIZE,
+ sizeof(IRDA_PROTOCOL_RESERVED)-1 + \
+ sizeof(NDIS_IRDA_PACKET_INFO));
+ if (*pStatus != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGMSG(DBG_ERROR, ("NdisAllocatePacketPool failed\n"));
+ goto error20; // free pIrdaLinkCb, Buffer pool
+ }
+
+ NdisInitializeListHead(&pIrdaLinkCb->IMsgList);
+
+ // For internally generated LAP messages
+ pIrdaLinkCb->IMsgListLen = 0;
+ for (i = 0; i < IRDA_MSG_LIST_LEN; i++)
+ {
+ NdisAllocateMemory(&pIMsg, sizeof(IRDA_MSG) + IRDA_MSG_DATA_SIZE,
+ 0, pa);
+ if (pIMsg == NULL)
+ {
+ *pStatus = STATUS_INSUFFICIENT_RESOURCES;
+ goto error40;
+ }
+ NdisInterlockedInsertTailList(&pIrdaLinkCb->IMsgList,
+ &pIMsg->Linkage,
+ &pIrdaLinkCb->SpinLock);
+ pIrdaLinkCb->IMsgListLen++;
+ }
+
+ NdisOpenAdapter(
+ pStatus,
+ &OpenErrorStatus,
+ &pIrdaLinkCb->NdisBindingHandle,
+ &SelectedMediumIndex,
+ MediumArray,
+ 1,
+ NdisIrdaHandle,
+ pIrdaLinkCb,
+ AdapterName,
+ 0,
+ NULL);
+
+ DEBUGMSG(DBG_NDIS, ("NdisOpenAdapter(), status %x\n",
+ pIrdaLinkCb->NdisBindingHandle, *pStatus));
+
+ if (*pStatus == NDIS_STATUS_PENDING)
+ {
+ NdisWaitEvent(&pIrdaLinkCb->SyncEvent, 0);
+ *pStatus = pIrdaLinkCb->SyncStatus;
+ }
+
+ if (*pStatus != NDIS_STATUS_SUCCESS)
+ {
+ goto error30; // free pIrdaLinkCb, Buffer pool, Packet pool
+ }
+
+ // Query adapters capabilities
+
+ UintArrayCnt = sizeof(UintArray)/sizeof(UINT);
+ *pStatus = IrdaQueryOid(pIrdaLinkCb,
+ OID_IRDA_SUPPORTED_SPEEDS,
+ UintArray, &UintArrayCnt);
+ if (*pStatus != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGMSG(DBG_ERROR,
+ ("Query IRDA_SUPPORTED_SPEEDS failed %x\n",
+ *pStatus));
+ goto error30;
+ }
+
+ OidToLapQos(vBaudTable,
+ UintArray,
+ UintArrayCnt,
+ &LocalQos.bfBaud);
+
+ UintArrayCnt = sizeof(UintArray)/sizeof(UINT);
+ *pStatus = IrdaQueryOid(pIrdaLinkCb,
+ OID_IRDA_TURNAROUND_TIME,
+ UintArray, &UintArrayCnt);
+
+ if (*pStatus != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGMSG(DBG_ERROR,
+ ("Query IRDA_SUPPORTED_SPEEDS failed %x\n",
+ *pStatus));
+ goto error30;
+ }
+
+ OidToLapQos(vMinTATTable,
+ UintArray,
+ UintArrayCnt,
+ &LocalQos.bfMinTurnTime);
+
+ IrlapOpenLink(pStatus,
+ pIrdaLinkCb,
+ &LocalQos,
+ DscvInfoBuf,
+ DscvInfoLen,
+ DISCOVERY_SLOTS);
+
+ if (*pStatus != STATUS_SUCCESS)
+ {
+ goto error30;
+ }
+
+ InsertTailList(&IrdaLinkCbList, &pIrdaLinkCb->Linkage);
+
+ goto exit10;
+
+error40:
+
+ pIMsg = (IRDA_MSG *) NdisInterlockedRemoveHeadList(
+ &pIrdaLinkCb->IMsgList, &pIrdaLinkCb->SpinLock);
+
+ while (pIMsg != NULL)
+ {
+ NdisFreeMemory(pIMsg, sizeof(IRDA_MSG) + IRDA_MSG_DATA_SIZE, 0);
+ pIMsg = (IRDA_MSG *) NdisInterlockedRemoveHeadList(
+ &pIrdaLinkCb->IMsgList, &pIrdaLinkCb->SpinLock);
+ pIMsg = (IRDA_MSG *) RemoveHeadList(&pIrdaLinkCb->IMsgList);
+ }
+
+error30:
+ NdisFreePacketPool(pIrdaLinkCb->PacketPool);
+
+error20:
+ NdisFreeBufferPool(pIrdaLinkCb->BufferPool);
+
+error10:
+
+ NdisFreeMemory(pIrdaLinkCb, sizeof(IRDA_LINK_CB), 0);
+
+exit10:
+ DEBUGMSG(DBG_NDIS, ("-IrdaBindAdapter() status %x\n",
+ *pStatus));
+
+ return;
+}
+
+VOID IrdaUnbindAdapter(
+ OUT PNDIS_STATUS pStatus,
+ IN NDIS_HANDLE IrdaBindingContext,
+ IN NDIS_HANDLE UnbindContext
+ )
+{
+ PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) IrdaBindingContext;
+
+ DEBUGMSG(DBG_NDIS, ("+IrdaUnbindAdapter()\n"));
+
+ NdisInitializeEvent(&pIrdaLinkCb->SyncEvent);
+ NdisResetEvent(&pIrdaLinkCb->SyncEvent);
+
+ NdisCloseAdapter(pStatus, pIrdaLinkCb->NdisBindingHandle);
+
+ if(*pStatus == NDIS_STATUS_PENDING)
+ {
+ NdisWaitEvent(&pIrdaLinkCb->SyncEvent, 0);
+ *pStatus = pIrdaLinkCb->SyncStatus;
+ }
+
+ if (*pStatus == NDIS_STATUS_SUCCESS){
+ NdisFreeMemory(pIrdaLinkCb, sizeof(IRDA_LINK_CB), 0);
+ }
+
+ DEBUGMSG(DBG_NDIS, ("-IrdaUnbindAdapter() Status %x\n",
+ *pStatus));
+
+ return;
+}
+
+VOID IrdaUnload(
+ VOID
+ )
+{
+ DEBUGMSG(DBG_NDIS, ("+IrdaUnload()\n"));
+
+ return;
+}
+
+NTSTATUS IrdaNdisInitialize()
+{
+ NDIS_STATUS Status;
+ NDIS40_PROTOCOL_CHARACTERISTICS pc;
+ NDIS_STRING ProtocolName = NDIS_STRING_CONST("IRDA");
+ UINT ProtocolReservedLength;
+
+ DEBUGMSG(DBG_NDIS,("+IrdaNdisInitialize()\n"));
+
+ NdisZeroMemory((PVOID)&pc, sizeof(NDIS40_PROTOCOL_CHARACTERISTICS));
+ pc.MajorNdisVersion = 0x04;
+ pc.MinorNdisVersion = 0x00;
+ pc.OpenAdapterCompleteHandler = IrdaOpenAdapterComplete;
+ pc.CloseAdapterCompleteHandler = IrdaCloseAdapterComplete;
+ pc.SendCompleteHandler = IrdaSendComplete;
+ pc.TransferDataCompleteHandler = IrdaTransferDataComplete;
+ pc.ResetCompleteHandler = IrdaResetComplete;
+ pc.RequestCompleteHandler = IrdaRequestComplete;
+ pc.ReceiveHandler = IrdaReceive;
+ pc.ReceiveCompleteHandler = IrdaReceiveComplete;
+ pc.StatusHandler = IrdaStatus;
+ pc.StatusCompleteHandler = IrdaStatusComplete;
+ pc.BindAdapterHandler = IrdaBindAdapter;
+ pc.UnbindAdapterHandler = IrdaUnbindAdapter;
+ pc.UnloadHandler = IrdaUnload;
+ pc.Name = ProtocolName;
+ pc.ReceivePacketHandler = IrdaReceivePacket;
+ pc.TranslateHandler = NULL;
+
+ NdisRegisterProtocol(&Status,
+ &NdisIrdaHandle,
+ (PNDIS_PROTOCOL_CHARACTERISTICS)&pc,
+ sizeof(NDIS40_PROTOCOL_CHARACTERISTICS));
+
+ // Do any LAP/LMP initialization here
+
+ DEBUGMSG(DBG_NDIS, ("-IrdaNdisInitialize(), rc %x\n", Status));
+
+ return Status;
+}
+
+UINT
+MacConfigRequest(
+ PIRDA_LINK_CB pIrdaLinkCb,
+ PIRDA_MSG pMsg)
+{
+ switch (pMsg->IRDA_MSG_Op)
+ {
+ case MAC_INITIALIZE_LINK:
+ case MAC_RECONFIG_LINK:
+ pIrdaLinkCb->ExtraBofs = pMsg->IRDA_MSG_NumBOFs;
+ pIrdaLinkCb->MinTat = pMsg->IRDA_MSG_MinTat;
+ return IrdaSetOid(pIrdaLinkCb,
+ OID_IRDA_LINK_SPEED,
+ (UINT) pMsg->IRDA_MSG_Baud);
+
+ case MAC_MEDIA_SENSE:
+ ASSERT(0);
+
+ }
+
+ return SUCCESS;
+
+}
+UINT IrmacDown(
+ IN PVOID Context,
+ PIRDA_MSG pMsg)
+{
+ NDIS_STATUS Status;
+ PNDIS_PACKET NdisPacket = NULL;
+ PNDIS_BUFFER NdisBuffer = NULL;
+ PIRDA_PROTOCOL_RESERVED ProtocolReserved;
+ PNDIS_IRDA_PACKET_INFO IrdaPacketInfo;
+ PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) Context;
+
+ DEBUGMSG(DBG_FUNCTION, ("+IrmacDown()\n"));
+
+
+ if (pMsg->Prim == MAC_CONTROL_REQ)
+ {
+ return MacConfigRequest(pIrdaLinkCb, pMsg);
+ }
+
+ NdisAllocatePacket(&Status, &NdisPacket, pIrdaLinkCb->PacketPool);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return 1;
+ }
+
+ NdisAllocateBuffer(&Status, &NdisBuffer, pIrdaLinkCb->PacketPool,
+ pMsg->IRDA_MSG_pHdrRead,
+ pMsg->IRDA_MSG_pHdrWrite-pMsg->IRDA_MSG_pHdrRead);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return 1;
+ }
+ NdisChainBufferAtFront(NdisPacket, NdisBuffer);
+
+ NdisAllocateBuffer(&Status, &NdisBuffer, pIrdaLinkCb->PacketPool,
+ pMsg->IRDA_MSG_pRead,
+ pMsg->IRDA_MSG_pWrite-pMsg->IRDA_MSG_pRead);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return 1;
+ }
+ NdisChainBufferAtBack(NdisPacket, NdisBuffer);
+
+ ProtocolReserved = (PIRDA_PROTOCOL_RESERVED)(NdisPacket->ProtocolReserved);
+
+ ProtocolReserved->pIMsg = pMsg;
+
+ IrdaPacketInfo = (PNDIS_IRDA_PACKET_INFO) \
+ (ProtocolReserved->MediaInfo.ClassInformation);
+
+ IrdaPacketInfo->ExtraBOFs = pIrdaLinkCb->ExtraBofs;
+ IrdaPacketInfo->MinTurnAroundTime = pIrdaLinkCb->MinTat;
+
+ NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(NdisPacket,
+ &ProtocolReserved->MediaInfo,
+ sizeof(MEDIA_SPECIFIC_INFORMATION) -1 +
+ sizeof(NDIS_IRDA_PACKET_INFO));
+ NdisSend(&Status, pIrdaLinkCb->NdisBindingHandle, NdisPacket);
+
+ return 0;
+}
diff --git a/private/ntos/tdi/irda/driver/makefile b/private/ntos/tdi/irda/driver/makefile
new file mode 100644
index 000000000..58189757d
--- /dev/null
+++ b/private/ntos/tdi/irda/driver/makefile
@@ -0,0 +1,7 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the driver components of the Windows NT DDK
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/irda/driver/sources b/private/ntos/tdi/irda/driver/sources
new file mode 100644
index 000000000..70d52d5e4
--- /dev/null
+++ b/private/ntos/tdi/irda/driver/sources
@@ -0,0 +1,15 @@
+TARGETNAME=irda
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS= \
+ $(BASEDIR)\public\sdk\lib\*\ndis.lib \
+ $(BASEDIR)\public\sdk\lib\*\tdi.lib \
+ ..\lib\*\irlap.lib
+
+INCLUDES=$(BASEDIR)\private\inc;$(BASEDIR)\private\ntos\inc;..\..\inc;..\inc
+
+C_DEFINES=$(C_DEFINES) -DNT -D_NTDRIVER_ -DIRDA
+
+SOURCES= irda.c \
+ irndis.c
diff --git a/private/ntos/tdi/irda/inc/af_irda.h b/private/ntos/tdi/irda/inc/af_irda.h
new file mode 100644
index 000000000..5e5d36b0d
--- /dev/null
+++ b/private/ntos/tdi/irda/inc/af_irda.h
@@ -0,0 +1,100 @@
+//
+// this is the header file that describes the IRDA address family
+//
+// CREATED 4/28: AldenG
+//
+
+#ifndef __AFIRDA__
+#define __AFIRDA__
+
+#include <winsock.h>
+
+#define AF_IRDA 22 // see winsock.h
+#define PF_IRDA AF_IRDA
+
+#define SOL_IRLMP 0x00FF
+
+#define IRLMP_ENUMDEVICES 0x00000010
+#define IRLMP_IAS_SET 0x00000011
+#define IRLMP_IAS_QUERY 0x00000012
+#define IRLMP_SEND_PDU_LEN 0x00000013
+#define IRLMP_EXCLUSIVE_MODE 0x00000014
+#define IRLMP_IRLPT_MODE 0x00000015
+#define IRLMP_9WIRE_MODE 0x00000016
+
+#define IAS_ATTRIB_NO_CLASS 0x00000010
+#define IAS_ATTRIB_NO_ATTRIB 0x00000000
+#define IAS_ATTRIB_INT 0x00000001
+#define IAS_ATTRIB_OCTETSEQ 0x00000002
+#define IAS_ATTRIB_STR 0x00000003
+
+typedef struct _SOCKADDR_IRDA
+{
+ u_short irdaAddressFamily;
+ u_char irdaDeviceID[4];
+ char irdaServiceName[25];
+} SOCKADDR_IRDA, *PSOCKADDR_IRDA;
+
+typedef struct _IRDA_DEVICE_INFO
+{
+ u_char irdaDeviceID[4];
+ char irdaDeviceName[22];
+ u_char Reserved[2];
+} IRDA_DEVICE_INFO, *PIRDA_DEVICE_INFO, FAR *LPIRDA_DEVICE_INFO;
+
+typedef struct _DEVICELIST
+{
+ ULONG numDevice;
+ IRDA_DEVICE_INFO Device[1];
+} DEVICELIST, *PDEVICELIST, FAR *LPDEVICELIST;
+
+typedef struct _IAS_SET
+{
+ char irdaClassName[61];
+ char irdaAttribName[61];
+ u_short irdaAttribType;
+ union
+ {
+ int irdaAttribInt;
+ struct
+ {
+ int Len;
+ u_char OctetSeq[1];
+ u_char Reserved[3];
+ } irdaAttribOctetSeq;
+ struct
+ {
+ int Len;
+ u_char CharSet;
+ u_char UsrStr[1];
+ u_char Reserved[2];
+ } irdaAttribUsrStr;
+ } irdaAttribute;
+} IAS_SET, *PIAS_SET, FAR *LPIAS_SET;
+
+typedef struct _IAS_QUERY
+{
+ u_char irdaDeviceID[4];
+ char irdaClassName[61];
+ char irdaAttribName[61];
+ u_short irdaAttribType;
+ union
+ {
+ int irdaAttribInt;
+ struct
+ {
+ int Len;
+ u_char OctetSeq[1];
+ u_char Reserved[3];
+ } irdaAttribOctetSeq;
+ struct
+ {
+ int Len;
+ u_char CharSet;
+ u_char UsrStr[1];
+ u_char Reserved[2];
+ } irdaAttribUsrStr;
+ } irdaAttribute;
+} IAS_QUERY, *PIAS_QUERY, FAR *LPIAS_QUERY;
+
+#endif // __AFIRDA__
diff --git a/private/ntos/tdi/irda/inc/decdirda.h b/private/ntos/tdi/irda/inc/decdirda.h
new file mode 100644
index 000000000..d93b0d9e3
--- /dev/null
+++ b/private/ntos/tdi/irda/inc/decdirda.h
@@ -0,0 +1,174 @@
+// returns pointers pOutStr
+TCHAR *DecodeIRDA(int *pFrameType,// return frame type (-1 = bad frame)
+ BYTE *pFrameBuf, // pointer to buffer containing IRLAP frame
+ UINT FrameLen, // length of buffer
+ TCHAR *pOutStr, // string where decode packet is placed
+ UINT DecodeLayer,// 2-LAP only, 3-LAP/LMP, 4-LAP/LMP/TTP
+ BOOL fNoConnAddr,// TRUE->Don't show connection address in str
+ int DispMode // DISP_ASCII/HEX/BOTH
+);
+
+#define DISP_ASCII 1
+#define DISP_HEX 2
+#define DISP_BOTH 3
+
+extern int BaudBitMask;
+
+#define IRLAP_BOF 0xC0
+#define IRLAP_EOF 0xC1
+#define IRLAP_ESC 0x7D
+#define IRLAP_COMP_BIT 0x20
+
+#define IRLAP_BROADCAST 0xfe
+#define _IRLAP_CMD 0x01
+#define _IRLAP_RSP 0x00
+
+#define IRLAP_I_FRM 0x00
+#define IRLAP_S_FRM 0x01
+#define IRLAP_U_FRM 0x03
+
+/*
+** Unnumbered Frame types with P/F bit set to 0
+*/
+#define IRLAP_UI 0x03
+#define IRLAP_XID_CMD 0x2f
+#define IRLAP_TEST 0xe3
+#define IRLAP_SNRM 0x83
+#define IRLAP_DISC 0x43
+#define IRLAP_UA 0x63
+#define IRLAP_FRMR 0x87
+#define IRLAP_DM 0x0f
+#define IRLAP_XID_RSP 0xaf
+
+/*
+** Supervisory Frames
+*/
+#define IRLAP_RR 0x01
+#define IRLAP_RNR 0x05
+#define IRLAP_REJ 0x09
+#define IRLAP_SREJ 0x0d
+
+
+#define IRLAP_GET_ADDR(addr) (addr >> 1)
+#define IRLAP_GET_CRBIT(addr) (addr & 1)
+#define IRLAP_GET_PFBIT(cntl) ((cntl >>4) & 1)
+#define IRLAP_GET_UCNTL(cntl) (cntl & 0xEF)
+#define IRLAP_GET_SCNTL(cntl) (cntl & 0x0F)
+#define IRLAP_FRAME_TYPE(cntl) (cntl & 0x01 ? (cntl & 3) : 0)
+#define IRLAP_GET_NR(cntl) ((cntl & 0xE0) >> 5)
+#define IRLAP_GET_NS(cntl) ((cntl & 0xE) >> 1)
+
+/*
+** XID stuff
+*/
+#define XID_DISCV_FORMAT_ID 0x01
+#define XID_NEGPARMS_FORMAT_ID 0x02
+
+typedef struct
+{
+ BYTE SrcAddr[4];
+ BYTE DestAddr[4];
+ BYTE NoOfSlots:2;
+ BYTE GenNewAddr:1;
+ BYTE Reserved:5;
+ BYTE SlotNo;
+ BYTE Version;
+} XID_DISCV_FORMAT;
+
+/*
+** SNRM
+*/
+typedef struct
+{
+ BYTE SrcAddr[4];
+ BYTE DestAddr[4];
+ BYTE ConnAddr;
+ BYTE FirstPI;
+} SNRM_FORMAT;
+
+/*
+** UA
+*/
+typedef struct
+{
+ BYTE SrcAddr[4];
+ BYTE DestAddr[4];
+ BYTE FirstPI;
+} UA_FORMAT;
+
+/*
+** LM-PDU stuff
+*/
+typedef struct
+{
+ BYTE DLSAP_SEL:7;
+ BYTE CntlBit:1;
+ BYTE SLSAP_SEL:7;
+ BYTE RsvrdBi1:1;
+} LM_HEADER;
+
+/* LM-PDU frame types */
+#define LM_PDU_CNTL_FRAME 1
+#define LM_PDU_DATA_FRAME 0
+
+typedef struct
+{
+ BYTE OpCode:7;
+ BYTE ABit:1;
+} LM_CNTL_FORMAT;
+
+/* Opcodes */
+#define LM_PDU_CONNECT 1
+#define LM_PDU_DISCONNECT 2
+#define LM_PDU_ACCESSMODE 3
+
+#define LM_PDU_REQUEST 0
+#define LM_PDU_CONFIRM 1
+
+#define LM_PDU_SUCCESS 0
+#define LM_PDU_FAILURE 1
+#define LM_PDU_UNSUPPORTED 0xFF
+
+#define LM_PDU_MULTIPLEXED 0
+#define LM_PDU_EXCLUSIVE 1
+
+/* Max disconnect reason code, see _LM_PDU_DscReason[] in decdirda.c */
+#define LM_PDU_MAX_DSC_REASON 0x8
+
+/*
+** Negotiation Parameter Identifiers
+*/
+#define NEG_PI_BAUD 0x01
+#define NEG_PI_MAX_TAT 0x82
+#define NEG_PI_DATA_SZ 0x83
+#define NEG_PI_WIN_SZ 0x84
+#define NEG_PI_BOFS 0x85
+#define NEG_PI_MIN_TAT 0x86
+#define NEG_PI_DISC_THRESH 0x08
+
+// Tiny TP!
+
+#define TTP_PFLAG_NO_PARMS 0
+#define TTP_PFLAG_PARMS 1
+
+#define TTP_MBIT_NOT_FINAL 1
+#define TTP_MBIT_FINAL 0
+
+typedef struct
+{
+ BYTE InitialCredit : 7;
+ BYTE ParmFlag : 1;
+} TTP_CONN_HEADER;
+
+typedef struct
+{
+ BYTE AdditionalCredit : 7;
+ BYTE MoreBit : 1;
+} TTP_DATA_HEADER;
+
+#define net_short(x) ((((x)&0xff) << 8) | (((x)&0xff00) >> 8))
+
+#define net_long(x) (((((DWORD UNALIGNED)(x))&0xffL)<<24) | \
+ ((((DWORD UNALIGNED)(x))&0xff00L)<<8) | \
+ ((((DWORD UNALIGNED)(x))&0xff0000L)>>8) | \
+ ((((DWORD UNALIGNED)(x))&0xff000000L)>>24))
diff --git a/private/ntos/tdi/irda/inc/irda.h b/private/ntos/tdi/irda/inc/irda.h
new file mode 100644
index 000000000..ab9d55674
--- /dev/null
+++ b/private/ntos/tdi/irda/inc/irda.h
@@ -0,0 +1,857 @@
+/*****************************************************************************
+*
+* Copyright (c) 1995 Microsoft Corporation
+*
+* File: irda.h
+*
+* Description: Definitions used across the IRDA stack
+*
+* Author: mbert
+*
+* Date: 4/15/95
+*
+* This file primarily defines the IRDA message (IRDA_MSG) used for
+* communicating with the stack and communication between the layers
+* of the stack. IRDA_MSG provides the following services:
+* MAC_CONTROL_SERVICE
+* IRLAP_DISCOVERY_SERVICE
+* IRDA_DISCONNECT_SERVICE
+* IRDA_CONNECT_SERVICE
+* IRDA_DATA_SERVICE
+* IRLMP_ACCESSMODE_SERVICE
+* IRLMP_IAS_SERVICE
+*
+* IRDA_MSG usage:
+*
+* +-------+
+* | IRLAP |
+* +-------+
+* |
+* | IRMAC_Down(IRDA_MSG)
+* \|/
+* +-------+
+* | IRMAC |
+* +-------+
+* |**************************************************************************|
+* | Prim | MsgType and parameters |
+* |==========================================================================|
+* | MAC_DATA_REQ | IRDA_DATA_SERVICE |
+* | | o IRDA_MSG_pHdrRead = start of IRDA headers |
+* | | o IRDA_MSG_pHdrWrite = end of header |
+* | | o IRDA_MSG_pRead = start of data |
+* | | o IRDA_MSG_pWrite = end of data |
+* |--------------------------+-----------------------------------------------|
+* | MAC_CONTROL_REQ | MAC_CONTROL_SERVICE |
+* | | o IRDA_MSG_Op = MAC_INITIALIZIE_LINK |
+* | | - IRDA_MSG_Port |
+* | | - IRDA_MSG_Baud |
+* | | - IRDA_MSG_MinTat = min turn time |
+* | | - IRDA_MSG_NumBOFs = # added when tx'ing |
+* | | - IRDA_MSG_DataSize = max rx frame |
+* | | - IRDA_MSG_SetIR = TRUE/FALSE (does an |
+* | | EscapeComm(SETIR) to select int/ext |
+* | | dongle) |
+* | | o IRDA_MSG_Op = MAC_MEDIA_SENSE |
+* | | - IRDA_MSG_SenseTime (in ms) |
+* | | o IRDA_MSG_Op = MAC_RECONFIG_LINK |
+* | | - IRDA_MSG_Baud |
+* | | - IRDA_MSG_NumBOFs = # added when tx'ing |
+* | | - IRDA_MSG_DataSize = max rx frame |
+* | | - IRDA_MSG_MinTat = min turn time |
+* | | o IRDA_MSG_OP = MAC_SHUTDOWN_LINK |
+* |--------------------------------------------------------------------------|
+*
+* +-------+
+* | IRLAP |
+* +-------+
+* /|\
+* | IRLAP_Up(IRDA_MSG)
+* |
+* +-------+
+* | IRMAC |
+* +-------+
+* |**************************************************************************|
+* | Prim | MsgType and parameters |
+* |==========================================================================|
+* | MAC_DATA_IND | IRDA_DATA_SERVICE |
+* | | o IRDA_MSG_pRead = start of frame |
+* | | (includes IRLAP header) |
+* | | o IRDA_MSG_pWrite = end of frame |
+* | | (excludes FCS) |
+* |--------------------------+-----------------------------------------------|
+* | MAC_CONTROL_CONF | MAC_CONTROL_SERVICE |
+* | | o IRDA_MSG_Op = MAC_MEDIA_SENSE |
+* | | - IRDA_MSG_OpStatus = MAC_MEDIA_BUSY |
+* | | MAC_MEDIA_CLEAR |
+* |--------------------------------------------------------------------------|
+*
+* +-------+
+* | IRLMP |
+* +-------+
+* |
+* | IRLAP_Down(IRDA_MSG)
+* \|/
+* +-------+
+* | IRLAP |
+* +-------+
+* |**************************************************************************|
+* | Prim | MsgType and parameters |
+* |==========================================================================|
+* | IRLAP_DISCOVERY_REQ | IRLAP_DISCOVERY_SERVICE |
+* | IRLAP_Down() returns | o IRDA_MSG_SenseMedia = TRUE/FALSE |
+* | IRLAP_REMOTE_DISCOVERY_IN_PROGRESS_ERR or |
+* | IRLAP_REMOTE_CONNECT_IN_PROGRESS_ERR when indicated |
+* |--------------------------+-----------------------------------------------|
+* | IRLAP_CONNECT_REQ | IRDA_CONNECT_SERVICE |
+* | | o IRDA_MSG_RemoteDevAddr |
+* | IRLAP_Down() returns | |
+* | IRLAP_REMOTE_DISCOVERY_IN_PROGRESS_ERR when indicated |
+* |--------------------------+-----------------------------------------------|
+* | IRLAP_CONNECT_RESP | no parms |
+* |--------------------------+-----------------------------------------------|
+* | IRLAP_DISCONNECT_REQ | no parms |
+* |--------------------------+-----------------------------------------------|
+* | IRLAP_DATA_REQ | IRDA_DATA_SERVICE |
+* | IRLAP_UDATA_REQ | o IRDA_MSG_pHdrRead = start of IRLMP header |
+* | IRLAP_Down() returns | o IRDA_MSG_pHdrWrite = end of header |
+* | IRLAP_REMOTE_BUSY to | o IRDA_MSG_pRead = start of data |
+* | to flow off LMP. | o IRDA_MSG_pWrite = end of data |
+* |--------------------------------------------------------------------------|
+* | IRLAP_FLOWON_REQ | no parms |
+* |--------------------------------------------------------------------------|
+*
+* +-------+
+* | IRLMP |
+* +-------+
+* /|\
+* | IRLMP_Up(IRDA_MSG)
+* |
+* +-------+
+* | IRLAP |
+* +-------+
+* |**************************************************************************|
+* | Prim | MsgType and parameters |
+* |==========================================================================|
+* | IRLAP_DISCOVERY_IND | IRLAP_DISCOVERY_SERVICE |
+* | | o pDevList = Discovery info of device that |
+* | | initiated discovery |
+* |--------------------------+-----------------------------------------------|
+* | IRLAP_DISCOVERY_CONF | IRLAP_DISCOVERY_SERVICE |
+* | | o IRDA_MSG_pDevList = list of discovered |
+* | | devices, NULL when |
+* | | status != IRLAP_DISCOVERY_COMPLETED |
+* | | o IRDA_MSG_DscvStatus = |
+* | | MAC_MEDIA_BUSY |
+* | | IRLAP_REMOTE_DISCOVERY_IN_PROGRESS |
+* | | IRLAP_DISCOVERY_COLLISION |
+* | | IRLAP_REMOTE_CONNECTION_IN_PROGRESS |
+* | | IRLAP_DISCOVERY_COMPLETED |
+* |--------------------------+-----------------------------------------------|
+* | IRLAP_CONNECT_IND | IRDA_CONNECT_SERVICE |
+* | | o IRDA_MSG_RemoteDevAddr |
+* | | o IRDA_MSG_pQOS = Negotiated QOS |
+* |--------------------------------------------------------------------------|
+* | IRLAP_CONNECT_CONF | IRDA_CONNECT_SERVICE |
+* | | o IRDA_MSG_pQOS = Negotiated QOS, only when |
+* | | successful |
+* | | o IRDA_MSG_ConnStatus = |
+* | | IRLAP_CONNECTION_COMPLETE |
+* |--------------------------+-----------------------------------------------|
+* | IRLAP_DISCONNECT_IND | IRDA_DISCONNECT_SERVICE |
+* | | o IRDA_MSG_DiscStatus = |
+* | | IRLAP_DISCONNECT_COMPLETED |
+* | | IRLAP_REMOTED_INITIATED |
+* | | IRLAP_PRIMARY_CONFLICT |
+* | | IRLAP_REMOTE_DISCOVERY_IN_PROGRESS |
+* | | IRLAP_NO_RESPONSE |
+* | | IRLAP_DECLINE_RESET |
+* | | MAC_MEDIA_BUSY |
+* |--------------------------+-----------------------------------------------|
+* | IRLAP_DATA_IND | IRDA_DATA_SERVICE |
+* | IRLAP_UDATA_IND | o IRDA_MSG_pRead = start of IRLMP packet |
+* | | o IRDA_MSG_pWrite = end of IRLMP packet |
+* |--------------------------+-----------------------------------------------|
+* | IRLAP_DATA_CONF | IRDA_DATA_SERVICE |
+* | IRLAP_UDATA_CONF | o IRDA_MSG_DataStatus = |
+* | | ILAP_DATA_REQUEST_COMPLETED |
+* | | IRLAP_DATA_REQUEST_FAILED_LINK_RESET |
+* |--------------------------+-----------------------------------------------|
+* | IRLAP_STATUS_IND | no parms |
+* |--------------------------------------------------------------------------|
+*
+* +--------------+
+* | TransportAPI |
+* +--------------+
+* |
+* | IRLMP_Down(IRLMPContext, IRDA_MSG)
+* \|/
+* +-------+
+* | IRLMP |
+* +-------+
+* |**************************************************************************|
+* | Prim | MsgType and parameters |
+* |==========================================================================|
+* | IRLMP_DISCOVERY_REQ | no parms |
+* |--------------------------+-----------------------------------------------|
+* | IRLMP_CONNECT_REQ | IRDA_CONNECT_SERVICE |
+* | IRLMP_Down() returns | o IRDA_MSG_RemoteDevAddr |
+* | IRLMP_LINK_IN_USE | o IRDA_MSG_RemoteLSAPSel |
+* | when the requested | o IRDA_MSG_pQOS (may be NULL) |
+* | connection is to a | o IRDA_MSG_pConnData |
+* | remote device other | o IRDA_MSG_ConnDataLen |
+* | than the one the link | o IRDA_MSG_LocalLSAPSel |
+* | is currently connected | o IRDA_MSG_pContext |
+* | or connecting to. | o IRDA_MSG_UseTTP |
+* | | o IRDA_MSG_TTPCredits |
+* | | o IRDA_MSG_MaxSDUSize - Max size that this |
+* | | IRLMP client can receive. |
+* |--------------------------+-----------------------------------------------|
+* | IRLMP_CONNECT_RESP | IRDA_CONNECT_SERVICE |
+* | | o IRDA_MSG_pConnData |
+* | | o IRDA_MSG_ConnDataLen |
+* | | o IRDA_MSG_pContext |
+* | | o IRDA_MSG_MaxSDUSize - Max size that this |
+* | | IRLMP client can receive. |
+* | | o IRDA_MSG_TTPCredits |
+* |--------------------------+-----------------------------------------------|
+* | IRLMP_DISCONNECT_REQ | IRDA_DISCONNECT_SERVICE |
+* | | o IRDA_MSG_pDiscData |
+* | | o IRDA_MSG_DiscDataLen |
+* | | |
+* | | |
+* |--------------------------+-----------------------------------------------|
+* | IRLMP_DATA/UDATA_REQ | IRDA_DATA_SERVICE |
+* | IRLMP_Down() may return| o IRDA_MSG_pDataContext = ptr to NDIS_BUFFER|
+* | IRLMP_REMOTE_BUSY, | o IRDA_MSG_IrCOMM_9Wire = TRUE/FALSE |
+* | when tx cred exhausted| |
+* | in multiplexed mode. | |
+* | IRLAP_REMOTE_BUSY, | |
+* | when remote IRLAP | |
+* | flowed off in exclMode| |
+* | In either case the req | |
+* | was successful. | |
+* |--------------------------------------------------------------------------|
+* | IRLMP_ACCESSMODE_REQ | IRLMP_ACCESSMODE_SERVICE |
+* | IRLMP_Down() may return| o IRDA_MSG_AccessMode = IRLMP_MULTIPLEXED |
+* | IRLMP_IN_EXCLUSIVE_MODE| IRLMP_EXCLUSIVE |
+* | if already in excl-mode| o IRDA_MSG_IrLPTMode - TRUE, doesn't send |
+* | IRLMP_IN_MULTIPLEXED...| the Access PDU |
+* | if other LSAPs exist or| |
+* | requesting trans to this state when already in it. |
+* |--------------------------------------------------------------------------|
+* | IRLMP_FLOWON_REQ | no parms |
+* |--------------------------------------------------------------------------|
+* | IRLMP_MORECREDIT_REQ | IRDA_CONNECT_SERVICE (cuz parm is defined) |
+* | | o IRDA_MSG_TTPCredits |
+* |--------------------------------------------------------------------------|
+* | IRLMP_GETVALUEBYCLASS_REQ| IRDA_IAS_SERVICE |
+* | | o IRDA_MSG_pIASQuery |
+* | | o IRDA_MSG_AttribLen |
+* | | o IRDA_MSG_IASQueryPerms |
+* |--------------------------------------------------------------------------|
+*
+*
+* +--------------+
+* | TransportAPI |
+* +--------------+
+* /|\
+* | TransportAPI_Up(TransportAPIContext, IRDA_MSG)
+* |
+* +-------+
+* | IRLMP |
+* +-------+
+* |**************************************************************************|
+* | Prim | MsgType and parameters |
+* |==========================================================================|
+* | IRLAP_DISCOVERY_IND | IRLAP_DISCOVERY_SERVICE |
+* | | o pDevList = aged Discovery list |
+* |--------------------------+-----------------------------------------------|
+* | IRLMP_DISCOVERY_CONF | same as IRLAP_DISCOVERY_CONF. The device list |
+* | | however is the one maintained in IRLMP |
+* |--------------------------+-----------------------------------------------|
+* | IRLMP_DISCONNECT_IND | IRDA_DISCONNECT_SERVICE |
+* | | o IRDA_MSG_DiscReason = |
+* | | see IRLMP_DISC_REASON below |
+* | | o IRDA_MSG_pDiscData - may be NULL |
+* | | o IRDA_MSG_DiscDataLen |
+* |--------------------------+-----------------------------------------------|
+* | IRLMP_CONNECT_IND | IRDA_CONNECT_SERVICE |
+* | | o IRDA_MSG_RemoteDevAddr |
+* | | o IRDA_MSG_RemoteLSAPSel; |
+* | | o IRDA_MSG_LocalLSAPSel; |
+* | | o IRDA_MSG_pQOS |
+* | | o IRDA_MSG_pConnData |
+* | | o IRDA_MSG_ConnDataLen |
+* | | o IRDA_MSG_pContext |
+* | | o IRDA_MSG_MaxSDUSize - Max size that this |
+* | | IRLMP client can send to peer |
+* | | o IRDA_MSG_MaxPDUSize |
+* |--------------------------+-----------------------------------------------|
+* | IRLMP_CONNECT_CONF | IRDA_CONNECT_SERVICE |
+* | | o IRDA_MSG_pQOS |
+* | | o IRDA_MSG_pConnData |
+* | | o IRDA_MSG_ConnDataLen |
+* | | o IRDA_MSG_pContext |
+* | | o IRDA_MSG_MaxSDUSize - Max size that this |
+* | | IRLMP client can send to peer |
+* | | o IRDA_MSG_MaxPDUSize |
+* |--------------------------+-----------------------------------------------|
+* | IRLMP_DATA_IND | IRDA_DATA_SERVICE |
+* | | o IRDA_MSG_pRead = start of User Data |
+* | | o IRDA_MSG_pWrite = end of User Data |
+* | | o IRDA_MSG_FinalSeg = TRUE/FALSE |
+* |--------------------------+-----------------------------------------------|
+* | IRLMP_DATA_CONF | IRDA_DATA_SERVICE |
+* | | o IRDA_MSG_pDataContext = ptr to NDIS_BUFFER|
+* | | o IRDA_MSG_DataStatus = |
+* | | IRLMP_DATA_REQUEST_COMPLETED |
+* | | IRLMP_DATA_REQUEST_FAILED |
+* |--------------------------+-----------------------------------------------|
+* | IRLMP_ACCESSMODE_IND | IRLMP_ACCESSMODE_SERVICE |
+* | | o IRDA_MSG_AccessMode = |
+* | | IRLMP_EXCLUSIVE |
+* | | IRLMP_MULTIPLEXED |
+* |--------------------------+-----------------------------------------------|
+* | IRLMP_ACCESSMODE_CONF | IRLMP_ACCESSMODE_SERVICE |
+* | | o IRDA_MSG_AccessMode = |
+* | | IRLMP_EXCLUSIVE |
+* | | IRLMP_MULTIPLEXED |
+* | | o IRDA_MSG_ModeStatus = |
+* | | IRLMP_ACCESSMODE_SUCCESS |
+* | | IRLMP_ACCESSMODE_FAILURE |
+* |--------------------------+-----------------------------------------------|
+* |IRLMP_GETVALUEBYCLASS_CONF| IRDA_DATA_SERVICE |
+* | | o IRDA_MSG_pIASQuery |
+* | | o IRDA_MSG_IASStatus = An IRLMP_DISC_REASON |
+* | | (see below) |
+* |--------------------------------------------------------------------------|
+*/
+
+#include <nt.h>
+#include <ntos.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#include <windef.h>
+#include <winbase.h>
+#include <winsock.h>
+#include <wsahelp.h>
+#include <basetyps.h>
+
+#include <ndis.h>
+
+#include <af_irda.h>
+
+#include <cxport.h>
+
+#include <irerr.h>
+
+#include <tmp.h>
+
+#define TEMPERAMENTAL_SERIAL_DRIVER // drivers busted. intercharacter delays cause
+ // IrLAP to reset.
+
+#ifdef DEBUG
+// Prototypes for Debugging Output
+void IRDA_DebugOut (TCHAR *pFormat, ...);
+void IRDA_DebugStartLog (void);
+void IRDA_DebugEndLog (void *, void *);
+#endif
+
+// Debug zone definitions.
+/*
+#define ZONE_IRDA DEBUGZONE(0)
+#define ZONE_IRLAP DEBUGZONE(2)
+#ifdef PEG
+#define ZONE_IRMAC DEBUGZONE(1)
+#define ZONE_IRLMP DEBUGZONE(3)
+#define ZONE_IRLMP_CONN DEBUGZONE(4)
+#define ZONE_IRLMP_CRED DEBUGZONE(5)
+#else
+extern int ZONE_IRMAC;
+extern int ZONE_IRLMP;
+extern int ZONE_IRLMP_CONN;
+extern int ZONE_IRLMP_CRED;
+#endif
+#define ZONE_DISCOVER DEBUGZONE(8)
+#define ZONE_PRINT DEBUGZONE(9)
+#define ZONE_ADDR DEBUGZONE(10)
+#define ZONE_MISC DEBUGZONE(11)
+#define ZONE_ALLOC DEBUGZONE(12)
+#define ZONE_FUNCTION DEBUGZONE(13)
+#define ZONE_WARN DEBUGZONE(14)
+#define ZONE_ERROR DEBUGZONE(15)
+*/
+
+
+#define IRDA_ALLOC_MEM(ptr, sz, id) ((ptr) = CTEAllocMem(sz))
+#define IRDA_FREE_MEM(ptr) CTEFreeMem((ptr))
+
+//extern CRITICAL_SECTION IrdaCS;
+
+// Time how low we wait for the critical section
+/*
+#define ENTER_IRDA_WITH_CRITICAL_SECTION(s) do { \
+ LPWSTR Owner = IrdaCSOwner; \
+ DWORD StartTick = GetTickCount(); \
+ EnterCriticalSection (&IrdaCS); \
+ IrdaCSOwner = s; \
+ StartTick = GetTickCount() - StartTick; \
+ if (StartTick > MaxWaitIrdaCS) { \
+ DEBUGMSG (1, (TEXT("%s: IRDA Wait for CS %dms (Owner=%s)\r\n"), \
+ s, StartTick, Owner)); \
+ MaxWaitIrdaCS = StartTick; \
+ } \
+ } while (0)
+
+
+#define LEAVE_IRDA_WITH_CRITICAL_SECTION IrdaCSOwner = TEXT(""), LeaveCriticalSection(&IrdaCS)
+
+#else // TIME_CS
+#define ENTER_IRDA_WITH_CRITICAL_SECTION(s) EnterCriticalSection(&IrdaCS)
+
+#define LEAVE_IRDA_WITH_CRITICAL_SECTION LeaveCriticalSection(&IrdaCS)
+#endif // TIME_CS
+*/
+#define STATIC static
+
+#define RetOnErr(func) do {if((_rc = func) != SUCCESS) return _rc;} while(0)
+
+typedef struct
+{
+ CTETimer CteTimer;
+ VOID (*ExpFunc)(PVOID Context);
+ PVOID Context;
+ UINT Timeout;
+ BOOL Late;
+#ifdef DEBUG
+ char *pName;
+#endif
+} IRDA_TIMER, *PIRDA_TIMER;
+
+#define IRMAC_CONTEXT(ilcb) ((ilcb)->IrmacContext)
+#define IRLAP_CONTEXT(ilcb) ((ilcb)->IrlapContext)
+#define IRLMP_CONTEXT(ilcb) ((ilcb)->IrlmpContext)
+
+// Device/Discovery Information
+#define IRLAP_DSCV_INFO_LEN 32
+#define IRDA_DEV_ADDR_LEN 4
+
+typedef struct
+{
+ LIST_ENTRY Linkage;
+ BYTE DevAddr[IRDA_DEV_ADDR_LEN];
+ int DscvMethod;
+ int IRLAP_Version;
+ BYTE DscvInfo[IRLAP_DSCV_INFO_LEN];
+ int DscvInfoLen;
+ int NotSeenCnt; // used by IRLMP to determine when to remove
+ // the device from its list
+ PVOID LinkContext; // Link on which device was discovered
+} IRDA_DEVICE;
+
+// IRLAP Quality of Service
+#define BIT_0 1
+#define BIT_1 2
+#define BIT_2 4
+#define BIT_3 8
+#define BIT_4 16
+#define BIT_5 32
+#define BIT_6 64
+#define BIT_7 128
+#define BIT_8 256
+
+#define BPS_2400 BIT_0 // Baud Rates
+#define BPS_9600 BIT_1
+#define BPS_19200 BIT_2
+#define BPS_38400 BIT_3
+#define BPS_57600 BIT_4
+#define BPS_115200 BIT_5
+#define BPS_4000000 BIT_8
+
+#define MAX_TAT_500 BIT_0 // Maximum Turnaround Time (millisecs)
+#define MAX_TAT_250 BIT_1
+#define MAX_TAT_100 BIT_2
+#define MAX_TAT_50 BIT_3
+#define MAX_TAT_25 BIT_4
+#define MAX_TAT_10 BIT_5
+#define MAX_TAT_5 BIT_6
+
+#define DATA_SIZE_64 BIT_0 // Data Size (bytes)
+#define DATA_SIZE_128 BIT_1
+#define DATA_SIZE_256 BIT_2
+#define DATA_SIZE_512 BIT_3
+#define DATA_SIZE_1024 BIT_4
+#define DATA_SIZE_2048 BIT_5
+
+#define FRAMES_1 BIT_0 // Window Size
+#define FRAMES_2 BIT_1
+#define FRAMES_3 BIT_2
+#define FRAMES_4 BIT_3
+#define FRAMES_5 BIT_4
+#define FRAMES_6 BIT_5
+#define FRAMES_7 BIT_6
+
+#define BOFS_48 BIT_0 // Additional Beginning of Frame Flags
+#define BOFS_24 BIT_1
+#define BOFS_12 BIT_2
+#define BOFS_5 BIT_3
+#define BOFS_3 BIT_4
+#define BOFS_2 BIT_5
+#define BOFS_1 BIT_6
+#define BOFS_0 BIT_7
+
+#define MIN_TAT_10 BIT_0 // Minumum Turnaround Time (millisecs)
+#define MIN_TAT_5 BIT_1
+#define MIN_TAT_1 BIT_2
+#define MIN_TAT_0_5 BIT_3
+#define MIN_TAT_0_1 BIT_4
+#define MIN_TAT_0_05 BIT_5
+#define MIN_TAT_0_01 BIT_6
+#define MIN_TAT_0 BIT_7
+
+#define DISC_TIME_3 BIT_0 // Link Disconnect/Threshold Time (seconds)
+#define DISC_TIME_8 BIT_1
+#define DISC_TIME_12 BIT_2
+#define DISC_TIME_16 BIT_3
+#define DISC_TIME_20 BIT_4
+#define DISC_TIME_25 BIT_5
+#define DISC_TIME_30 BIT_6
+#define DISC_TIME_40 BIT_7
+
+typedef struct
+{
+ UINT bfBaud;
+ UINT bfMaxTurnTime;
+ UINT bfDataSize;
+ UINT bfWindowSize;
+ UINT bfBofs;
+ UINT bfMinTurnTime;
+ UINT bfDisconnectTime; // holds threshold time also
+} IRDA_QOS_PARMS;
+
+
+// IrDA Message Primitives
+typedef enum
+{
+ MAC_DATA_REQ = 0, // Keep in sync with table in irlaplog.c
+ MAC_DATA_IND,
+ MAC_CONTROL_REQ,
+ MAC_CONTROL_CONF,
+ IRLAP_DISCOVERY_REQ,
+ IRLAP_DISCOVERY_IND,
+ IRLAP_DISCOVERY_CONF,
+ IRLAP_CONNECT_REQ,
+ IRLAP_CONNECT_IND,
+ IRLAP_CONNECT_RESP,
+ IRLAP_CONNECT_CONF,
+ IRLAP_DISCONNECT_REQ,
+ IRLAP_DISCONNECT_IND,
+ IRLAP_DATA_REQ, // Don't fuss with the order, CONF must be 2 from REQ
+ IRLAP_DATA_IND,
+ IRLAP_DATA_CONF,
+ IRLAP_UDATA_REQ,
+ IRLAP_UDATA_IND,
+ IRLAP_UDATA_CONF,
+ IRLAP_STATUS_IND,
+ IRLAP_FLOWON_REQ,
+ IRLAP_FLOWON_IND,
+ IRLMP_DISCOVERY_REQ,
+ IRLMP_DISCOVERY_IND,
+ IRLMP_DISCOVERY_CONF,
+ IRLMP_CONNECT_REQ,
+ IRLMP_CONNECT_IND,
+ IRLMP_CONNECT_RESP,
+ IRLMP_CONNECT_CONF,
+ IRLMP_DISCONNECT_REQ,
+ IRLMP_DISCONNECT_IND,
+ IRLMP_DATA_REQ,
+ IRLMP_DATA_IND,
+ IRLMP_DATA_CONF,
+ IRLMP_UDATA_REQ,
+ IRLMP_UDATA_IND,
+ IRLMP_UDATA_CONF,
+ IRLMP_ACCESSMODE_REQ,
+ IRLMP_ACCESSMODE_IND,
+ IRLMP_ACCESSMODE_CONF,
+ IRLMP_FLOWON_REQ,
+ IRLMP_FLOWON_IND,
+ IRLMP_MORECREDIT_REQ,
+ IRLMP_GETVALUEBYCLASS_REQ,
+ IRLMP_GETVALUEBYCLASS_CONF
+} IRDA_SERVICE_PRIM;
+
+typedef enum
+{
+ MAC_MEDIA_BUSY, // keep in sync with IRDA_StatStr in irlaplog.c
+ MAC_MEDIA_CLEAR,
+ IRLAP_DISCOVERY_COLLISION,
+ IRLAP_REMOTE_DISCOVERY_IN_PROGRESS,
+ IRLAP_REMOTE_CONNECT_IN_PROGRSS,
+ IRLAP_DISCOVERY_COMPLETED,
+ IRLAP_REMOTE_CONNECTION_IN_PROGRESS,
+ IRLAP_CONNECTION_COMPLETED,
+ IRLAP_REMOTE_INITIATED,
+ IRLAP_PRIMARY_CONFLICT,
+ IRLAP_DISCONNECT_COMPLETED,
+ IRLAP_NO_RESPONSE,
+ IRLAP_DECLINE_RESET,
+ IRLAP_DATA_REQUEST_COMPLETED,
+ IRLAP_DATA_REQUEST_FAILED_LINK_RESET,
+ IRLAP_DATA_REQUEST_FAILED_REMOTE_BUSY,
+ IRLMP_NO_RESPONSE,
+ IRLMP_ACCESSMODE_SUCCESS,
+ IRLMP_ACCESSMODE_FAILURE,
+ IRLMP_DATA_REQUEST_COMPLETED,
+ IRLMP_DATA_REQUEST_FAILED
+} IRDA_SERVICE_STATUS;
+
+// MAC Control Service Request Message - MAC_CONTROL_REQ/CONF
+typedef enum
+{
+ MAC_INITIALIZE_LINK, // keep in sync with MAC_OpStr in irlaplog.c
+ MAC_SHUTDOWN_LINK,
+ MAC_RECONFIG_LINK,
+ MAC_MEDIA_SENSE,
+} MAC_CONTROL_OPERATION;
+
+typedef struct
+{
+ MAC_CONTROL_OPERATION Op;
+ int Port;
+ int Baud;
+ int NumBOFs;
+ int MinTat;
+ int DataSize;
+ int SenseTime;
+ IRDA_SERVICE_STATUS OpStatus;
+ BOOL SetIR;
+} MAC_CONTROL_SERVICE;
+
+// IRLAP Discovery Service Request Message - IRLAP_DISCOVERY_IND/CONF
+typedef struct
+{
+ LIST_ENTRY *pDevList;
+ IRDA_SERVICE_STATUS DscvStatus;
+ BOOL SenseMedia;
+} IRLAP_DISCOVERY_SERVICE;
+
+// IRDA Connection Service Request Message - IRLAP_CONNECT_REQ/IND/CONF
+// IRLMP_CONNECT_REQ/CONF
+typedef struct
+{
+ BYTE RemoteDevAddr[IRDA_DEV_ADDR_LEN];
+ IRDA_QOS_PARMS *pQOS;
+ int LocalLSAPSel;
+ int RemoteLSAPSel;
+ BYTE *pConnData;
+ int ConnDataLen;
+ void *pContext;
+ int MaxPDUSize;
+ int MaxSDUSize;
+ int TTPCredits;
+ IRDA_SERVICE_STATUS ConnStatus;
+ BOOL UseTTP;
+} IRDA_CONNECT_SERVICE;
+
+// IRDA Disconnection Service Request Message - IRLAP_DISCONNECT_REQ/IND
+// IRLMP_DISCONNECT_REQ/IND
+typedef enum
+{
+ IRLMP_USER_REQUEST = 1,
+ IRLMP_UNEXPECTED_IRLAP_DISC,
+ IRLMP_IRLAP_CONN_FAILED,
+ IRLMP_IRLAP_RESET,
+ IRLMP_LM_INITIATED_DISC,
+ IRLMP_DISC_LSAP,
+ IRLMP_NO_RESPONSE_LSAP,
+ IRLMP_NO_AVAILABLE_LSAP,
+ IRLMP_MAC_MEDIA_BUSY,
+ IRLMP_IRLAP_REMOTE_DISCOVERY_IN_PROGRESS,
+
+ IRLMP_IAS_NO_SUCH_OBJECT, // these are added for the IAS_GetValueByClass.Conf
+ IRLMP_IAS_NO_SUCH_ATTRIB,
+ IRLMP_IAS_SUCCESS,
+ IRLMP_IAS_SUCCESS_LISTLEN_GREATER_THAN_ONE,
+
+ IRLMP_UNSPECIFIED_DISC = 0xFF
+} IRLMP_DISC_REASON;
+
+typedef struct
+{
+ BYTE *pDiscData; // IRLMP_DISCONNECT_REQ/IND only
+ int DiscDataLen; // IRLMP_DISCONNECT_REQ/IND only
+ IRLMP_DISC_REASON DiscReason; // IRLMP_DISCONNECT_REQ/IND only
+ IRDA_SERVICE_STATUS DiscStatus; // Indication only
+} IRDA_DISCONNECT_SERVICE;
+
+// IRDA Data Service Request Message
+#define IRLAP_HEADER_LEN 2
+#define IRLMP_HEADER_LEN 6
+#define TTP_HEADER_LEN 8
+#define IRDA_HEADER_LEN IRLAP_HEADER_LEN+IRLMP_HEADER_LEN+TTP_HEADER_LEN+1
+ // + 1 IRComm WACK!!
+
+typedef struct
+{
+ void *pOwner;
+ void *pDataContext; // How IRDA gets user data
+ int SegCount; // Number of segments
+ BOOL FinalSeg;
+ BYTE *pBase;
+ BYTE *pLimit;
+ BYTE *pRead;
+ BYTE *pWrite;
+ void *pTdiSendComp;
+ void *pTdiSendCompCnxt;
+ BOOL IrCOMM_9Wire;
+#ifdef TEMPERAMENTAL_SERIAL_DRIVER
+ int FCS;
+#endif
+ IRDA_SERVICE_STATUS DataStatus; // for CONF
+ // |------------------------|
+ // | pRead o-------------
+ // |------------------------| |
+ // | pWrite o---------- |
+ // |------------------------| | |
+ // | pBase o------- | |
+ // |------------------------| | | |
+ // | pLimit o---- | | |
+ // |------------------------| | | | |
+ // | | | | |
+ // ------------------------ | | | |
+ // | |<---- | |
+ // | | | | |
+ // | |<--------<-
+ // | | |
+ // | |<-
+ // ------------------------
+ BYTE *pHdrRead;
+ BYTE *pHdrWrite;
+ BYTE Header[IRDA_HEADER_LEN];
+ // |------------------------|
+ // | pHdrRead o-------------
+ // |------------------------| |
+ // | pHdrWrite o---------- |
+ // |------------------------| | |
+ // Header--->| | | |
+ // | | | |
+ // | |<--------<-
+ // | | |
+ // | |<-------
+ // ------------------------
+ //
+ // On the receive side, all headers are contained
+ // at pRead, not in the above Header array
+ //
+} IRDA_DATA_SERVICE;
+
+typedef enum
+{
+ IRLMP_MULTIPLEXED,
+ IRLMP_EXCLUSIVE
+} IRLMP_ACCESSMODE;
+
+typedef struct
+{
+ IRLMP_ACCESSMODE AccessMode;
+ IRDA_SERVICE_STATUS ModeStatus;
+ BOOL IrLPTMode; // if true don't send PDU
+} IRLMP_ACCESSMODE_SERVICE;
+
+typedef struct
+{
+ IAS_QUERY *pIASQuery;
+ int AttribLen; // OctetSeq or UsrStr len
+ int IASQueryPerms;
+ IRLMP_DISC_REASON IASStatus;
+} IRLMP_IAS_SERVICE;
+
+typedef struct irda_msg
+{
+ LIST_ENTRY Linkage;
+ IRDA_SERVICE_PRIM Prim;
+ union
+ {
+ MAC_CONTROL_SERVICE MAC_ControlService;
+ IRLAP_DISCOVERY_SERVICE IRLAP_DiscoveryService;
+ IRDA_DISCONNECT_SERVICE IRDA_DisconnectService;
+ IRDA_CONNECT_SERVICE IRDA_ConnectService;
+ IRDA_DATA_SERVICE IRDA_DataService;
+ IRLMP_ACCESSMODE_SERVICE IRLMP_AccessModeService;
+ IRLMP_IAS_SERVICE IRLMP_IASService;
+ } MsgType;
+
+} IRDA_MSG, *PIRDA_MSG;
+
+#define IRDA_MSG_Op MsgType.MAC_ControlService.Op
+#define IRDA_MSG_Port MsgType.MAC_ControlService.Port
+#define IRDA_MSG_Baud MsgType.MAC_ControlService.Baud
+#define IRDA_MSG_NumBOFs MsgType.MAC_ControlService.NumBOFs
+#define IRDA_MSG_MinTat MsgType.MAC_ControlService.MinTat
+#define IRDA_MSG_DataSize MsgType.MAC_ControlService.DataSize
+#define IRDA_MSG_OpStatus MsgType.MAC_ControlService.OpStatus
+#define IRDA_MSG_SetIR MsgType.MAC_ControlService.SetIR
+#define IRDA_MSG_SenseTime MsgType.MAC_ControlService.SenseTime
+
+#define IRDA_MSG_pOwner MsgType.IRDA_DataService.pOwner
+#define IRDA_MSG_pDataContext MsgType.IRDA_DataService.pDataContext
+#define IRDA_MSG_SegCount MsgType.IRDA_DataService.SegCount
+#define IRDA_MSG_FinalSeg MsgType.IRDA_DataService.FinalSeg
+#define IRDA_MSG_pHdrRead MsgType.IRDA_DataService.pHdrRead
+#define IRDA_MSG_pHdrWrite MsgType.IRDA_DataService.pHdrWrite
+#define IRDA_MSG_Header MsgType.IRDA_DataService.Header
+#define IRDA_MSG_pBase MsgType.IRDA_DataService.pBase
+#define IRDA_MSG_pLimit MsgType.IRDA_DataService.pLimit
+#define IRDA_MSG_pRead MsgType.IRDA_DataService.pRead
+#define IRDA_MSG_pWrite MsgType.IRDA_DataService.pWrite
+#define IRDA_MSG_DataStatus MsgType.IRDA_DataService.DataStatus
+#define IRDA_MSG_pTdiSendComp MsgType.IRDA_DataService.pTdiSendComp
+#define IRDA_MSG_pTdiSendCompCnxt MsgType.IRDA_DataService.pTdiSendCompCnxt
+#define IRDA_MSG_IrCOMM_9Wire MsgType.IRDA_DataService.IrCOMM_9Wire
+#ifdef TEMPERAMENTAL_SERIAL_DRIVER
+#define IRDA_MSG_FCS MsgType.IRDA_DataService.FCS
+#endif
+
+#define IRDA_MSG_pDevList MsgType.IRLAP_DiscoveryService.pDevList
+#define IRDA_MSG_DscvStatus MsgType.IRLAP_DiscoveryService.DscvStatus
+#define IRDA_MSG_SenseMedia MsgType.IRLAP_DiscoveryService.SenseMedia
+
+#define IRDA_MSG_RemoteDevAddr MsgType.IRDA_ConnectService.RemoteDevAddr
+#define IRDA_MSG_pQOS MsgType.IRDA_ConnectService.pQOS
+#define IRDA_MSG_LocalLSAPSel MsgType.IRDA_ConnectService.LocalLSAPSel
+#define IRDA_MSG_RemoteLSAPSel MsgType.IRDA_ConnectService.RemoteLSAPSel
+#define IRDA_MSG_pConnData MsgType.IRDA_ConnectService.pConnData
+#define IRDA_MSG_ConnDataLen MsgType.IRDA_ConnectService.ConnDataLen
+#define IRDA_MSG_ConnStatus MsgType.IRDA_ConnectService.ConnStatus
+#define IRDA_MSG_pContext MsgType.IRDA_ConnectService.pContext
+#define IRDA_MSG_UseTTP MsgType.IRDA_ConnectService.UseTTP
+#define IRDA_MSG_MaxSDUSize MsgType.IRDA_ConnectService.MaxSDUSize
+#define IRDA_MSG_MaxPDUSize MsgType.IRDA_ConnectService.MaxPDUSize
+#define IRDA_MSG_TTPCredits MsgType.IRDA_ConnectService.TTPCredits
+
+#define IRDA_MSG_pDiscData MsgType.IRDA_DisconnectService.pDiscData
+#define IRDA_MSG_DiscDataLen MsgType.IRDA_DisconnectService.DiscDataLen
+#define IRDA_MSG_DiscReason MsgType.IRDA_DisconnectService.DiscReason
+#define IRDA_MSG_DiscStatus MsgType.IRDA_DisconnectService.DiscStatus
+
+#define IRDA_MSG_AccessMode MsgType.IRLMP_AccessModeService.AccessMode
+#define IRDA_MSG_ModeStatus MsgType.IRLMP_AccessModeService.ModeStatus
+#define IRDA_MSG_IrLPTMode MsgType.IRLMP_AccessModeService.IrLPTMode
+
+#define IRDA_MSG_pIASQuery MsgType.IRLMP_IASService.pIASQuery
+#define IRDA_MSG_AttribLen MsgType.IRLMP_IASService.AttribLen
+#define IRDA_MSG_IASQueryPerms MsgType.IRLMP_IASService.IASQueryPerms
+#define IRDA_MSG_IASStatus MsgType.IRLMP_IASService.IASStatus
+
+extern LIST_ENTRY IrdaLinkCbList;
+
+VOID IrdaTimerInitialize(PIRDA_TIMER pTimer,
+ VOID (*ExpFunc)(PVOID Context),
+ UINT Timeout,
+ PVOID Context);
+
+VOID IrdaTimerStart(PIRDA_TIMER pTimer);
+
+VOID IrdaTimerStop(PIRDA_TIMER pTimer);
+
diff --git a/private/ntos/tdi/irda/inc/irdalink.h b/private/ntos/tdi/irda/inc/irdalink.h
new file mode 100644
index 000000000..e96f13665
--- /dev/null
+++ b/private/ntos/tdi/irda/inc/irdalink.h
@@ -0,0 +1,34 @@
+NTSTATUS IrdaNdisInitialize();
+
+#define IRDA_NDIS_BUFFER_POOL_SIZE 4
+#define IRDA_NDIS_PACKET_POOL_SIZE 4
+#define IRDA_MSG_LIST_LEN 2
+#define IRDA_MSG_DATA_SIZE 64
+
+typedef struct
+{
+ PIRDA_MSG pIMsg;
+ MEDIA_SPECIFIC_INFORMATION MediaInfo;
+} IRDA_PROTOCOL_RESERVED, *PIRDA_PROTOCOL_RESERVED;
+
+typedef struct IrdaLinkControlBlock
+{
+ LIST_ENTRY Linkage;
+ NDIS_SPIN_LOCK SpinLock;
+ NDIS_HANDLE BindContext;
+ NDIS_HANDLE NdisBindingHandle;
+ NDIS_EVENT SyncEvent;
+ NDIS_STATUS SyncStatus;
+ int MediaBusy;
+ PVOID IrlapContext;
+ PVOID IrlmpContext;
+ NDIS_HANDLE BufferPool;
+ NDIS_HANDLE PacketPool;
+ LIST_ENTRY IMsgList;
+ int IMsgListLen;
+ UINT ExtraBofs; // These should be per connection for
+ UINT MinTat; // multipoint
+} IRDA_LINK_CB, *PIRDA_LINK_CB;
+
+IRDA_MSG *AllocMacIMsg(PIRDA_LINK_CB);
+
diff --git a/private/ntos/tdi/irda/inc/irerr.h b/private/ntos/tdi/irda/inc/irerr.h
new file mode 100644
index 000000000..7490c6fba
--- /dev/null
+++ b/private/ntos/tdi/irda/inc/irerr.h
@@ -0,0 +1,110 @@
+/*****************************************************************************
+*
+* Copyright (c) 1995 Microsoft Corporation
+*
+* File: irerr.h
+*
+* Description: IR error defines
+*
+* Author: mmiller
+*
+* Date: 4/25/95
+*
+*/
+
+#ifndef SUCCESS
+#define SUCCESS 0
+#endif
+
+#define IR_ERROR_BASE 20000
+#define IRLAP_ERROR_BASE IR_ERROR_BASE + 100
+#define IRLMP_ERROR_BASE IR_ERROR_BASE + 200
+
+#define IRMAC_TX_OVERFLOW (IR_ERROR_BASE+0)
+#define IRMAC_WRITE_FAILED (IR_ERROR_BASE+1)
+#define IRMAC_READ_FAILED (IR_ERROR_BASE+2)
+#define IRMAC_BAD_FCS (IR_ERROR_BASE+3)
+#define IRMAC_RX_OVERFLOW (IR_ERROR_BASE+4)
+#define IRMAC_TIMEOUT (IR_ERROR_BASE+5)
+#define IRMAC_BAD_PRIM (IR_ERROR_BASE+6)
+#define IRMAC_BAD_OP (IR_ERROR_BASE+7)
+#define IRMAC_OPEN_PORT_FAILED (IR_ERROR_BASE+8)
+#define IRMAC_SET_BAUD_FAILED (IR_ERROR_BASE+9)
+#define IRMAC_MALLOC_FAILED (IR_ERROR_BASE+10)
+#define IRMAC_ALREADY_INIT (IR_ERROR_BASE+11)
+#define IRMAC_BAD_TIMER (IR_ERROR_BASE+12)
+#define IRMAC_NOT_INITIALIZED (IR_ERROR_BASE+13)
+#define IRMAC_LINK_RESET (IR_ERROR_BASE+14)
+
+#define IRLAP_NOT_INITIALIZED (IRLAP_ERROR_BASE + 0)
+#define IRLAP_BAD_PRIM (IRLAP_ERROR_BASE + 1)
+#define IRLAP_BAD_STATE (IRLAP_ERROR_BASE + 2)
+#define IRLAP_BAD_OPSTATUS (IRLAP_ERROR_BASE + 3)
+#define IRLAP_BAD_OP (IRLAP_ERROR_BASE + 4)
+#define IRLAP_MALLOC_FAILED (IRLAP_ERROR_BASE + 5)
+#define IRLAP_BAUD_NEG_ERR (IRLAP_ERROR_BASE + 6)
+#define IRLAP_DISC_NEG_ERR (IRLAP_ERROR_BASE + 7)
+#define IRLAP_MAXTAT_NEG_ERR (IRLAP_ERROR_BASE + 8)
+#define IRLAP_MINTAT_NEG_ERR (IRLAP_ERROR_BASE + 9)
+#define IRLAP_DATASIZE_NEG_ERR (IRLAP_ERROR_BASE + 10)
+#define IRLAP_WINSIZE_NEG_ERR (IRLAP_ERROR_BASE + 11)
+#define IRLAP_BOFS_NEG_ERR (IRLAP_ERROR_BASE + 12)
+#define IRLAP_LINECAP_ERR (IRLAP_ERROR_BASE + 13)
+#define IRLAP_BAD_SLOTNO (IRLAP_ERROR_BASE + 14)
+#define IRLAP_XID_CMD_NOT_P (IRLAP_ERROR_BASE + 15)
+#define IRLAP_SNRM_NO_QOS (IRLAP_ERROR_BASE + 16)
+#define IRLAP_UA_NO_QOS (IRLAP_ERROR_BASE + 17)
+#define IRLAP_XID_CMD_RSP (IRLAP_ERROR_BASE + 18)
+#define IRLAP_SNRM_NOT_CMD (IRLAP_ERROR_BASE + 19)
+#define IRLAP_SNRM_NOT_P (IRLAP_ERROR_BASE + 20)
+#define IRLAP_UA_NOT_RSP (IRLAP_ERROR_BASE + 21)
+#define IRLAP_UA_NOT_F (IRLAP_ERROR_BASE + 22)
+#define IRLAP_MSG_LIST_EMPTY (IRLAP_ERROR_BASE + 23)
+#define IRLAP_MSG_LIST_FULL (IRLAP_ERROR_BASE + 24)
+#define IRLAP_RXD_BAD_FRAME (IRLAP_ERROR_BASE + 25)
+#define IRLAP_BAD_CRBIT_IFRAME (IRLAP_ERROR_BASE + 26)
+#define IRLAP_BAD_DATA_REQUEST (IRLAP_ERROR_BASE + 27)
+#define IRLAP_DISC_CMD_RSP (IRLAP_ERROR_BASE + 28)
+#define IRLAP_DISC_CMD_NOT_P (IRLAP_ERROR_BASE + 29)
+#define IRLAP_DM_RSP_NOT_F (IRLAP_ERROR_BASE + 30)
+#define IRLAP_DM_RSP_CMD (IRLAP_ERROR_BASE + 31)
+#define IRLAP_FRMR_RSP_CMD (IRLAP_ERROR_BASE + 32)
+#define IRLAP_FRMR_RSP_NOT_F (IRLAP_ERROR_BASE + 33)
+#define IRLAP_BAD_QOS (IRLAP_ERROR_BASE + 34)
+#define IRLAP_NULL_MSG (IRLAP_ERROR_BASE + 35)
+#define IRLAP_BAD_MAX_SLOT (IRLAP_ERROR_BASE + 36)
+#define IRLAP_REMOTE_DISCOVERY_IN_PROGRESS_ERR (IRLAP_ERROR_BASE + 37)
+#define IRLAP_REMOTE_CONNECTION_IN_PROGRESS_ERR (IRLAP_ERROR_BASE + 38)
+#define IRLAP_REMOTE_BUSY (IRLAP_ERROR_BASE + 39)
+
+#define IRLMP_NOT_INITIALIZED (IRLMP_ERROR_BASE + 0)
+#define IRLMP_LSAP_BAD_STATE (IRLMP_ERROR_BASE + 1)
+#define IRLMP_USER_DATA_LEN_EXCEEDED (IRLMP_ERROR_BASE + 2)
+#define IRLMP_LINK_IN_USE (IRLMP_ERROR_BASE + 3)
+#define IRLMP_TIMER_START_FAILED (IRLMP_ERROR_BASE + 4)
+#define IRLMP_ALLOC_FAILED (IRLMP_ERROR_BASE + 5)
+#define IRLMP_LINK_BAD_STATE (IRLMP_ERROR_BASE + 6)
+#define IRLMP_LSAP_SEL_IN_USE (IRLMP_ERROR_BASE + 7)
+#define IRLMP_CREDIT_CALC_ERROR (IRLMP_ERROR_BASE + 8)
+#define IRLMP_NO_TX_CREDIT (IRLMP_ERROR_BASE + 9)
+#define IRLMP_TX_DATA_LEN_EXCEEDED (IRLMP_ERROR_BASE + 10)
+#define IRLMP_DATA_IND_BAD_FRAME (IRLMP_ERROR_BASE + 11)
+#define IRLMP_SCHEDULE_EVENT_FAILED (IRLMP_ERROR_BASE + 12)
+#define IRLMP_LOCAL_BUSY (IRLMP_ERROR_BASE + 13)
+#define IRLMP_BAD_PRIM (IRLMP_ERROR_BASE + 14)
+#define IRLMP_BAD_ACCESSMODE (IRLMP_ERROR_BASE + 15)
+#define IRLMP_LINK_BUSY (IRLMP_ERROR_BASE + 16)
+#define IRLMP_IN_MULTIPLEXED_MODE (IRLMP_ERROR_BASE + 17)
+#define IRLMP_IN_EXCLUSIVE_MODE (IRLMP_ERROR_BASE + 18)
+#define IRLMP_NOT_LSAP_IN_EXCLUSIVE_MODE (IRLMP_ERROR_BASE + 19)
+#define IRLMP_INVALID_LSAP_CB (IRLMP_ERROR_BASE + 20)
+#define IRLMP_REMOTE_BUSY (IRLMP_ERROR_BASE + 21)
+#define IRLMP_TIMER_STOP_FAILED (IRLMP_ERROR_BASE + 22)
+#define IRLMP_BAD_IAS_OBJECT_ID (IRLMP_ERROR_BASE + 23)
+#define IRLMP_NO_SUCH_IAS_CLASS (IRLMP_ERROR_BASE + 24)
+#define IRLMP_NO_SUCH_IAS_ATTRIBUTE (IRLMP_ERROR_BASE + 25)
+#define IRLMP_UNSUPPORTED_IAS_OPERATION (IRLMP_ERROR_BASE + 26)
+#define IRLMP_BAD_IAS_QUERY_FROM_REMOTE (IRLMP_ERROR_BASE + 27)
+#define IRLMP_IAS_QUERY_IN_PROGRESS (IRLMP_ERROR_BASE + 28)
+#define IRLMP_UNSOLICITED_IAS_RESPONSE (IRLMP_ERROR_BASE + 29)
+#define IRLMP_SHUTDOWN_IN_PROGESS (IRLMP_ERROR_BASE + 30)
diff --git a/private/ntos/tdi/irda/inc/irlap.h b/private/ntos/tdi/irda/inc/irlap.h
new file mode 100644
index 000000000..dbcc68361
--- /dev/null
+++ b/private/ntos/tdi/irda/inc/irlap.h
@@ -0,0 +1,66 @@
+/*****************************************************************************
+*
+* Copyright (c) 1995 Microsoft Corporation
+*
+* File: irlap.h
+*
+* Description: IRLAP Protocol and control block definitions
+*
+* Author: mbert
+*
+* Date: 4/15/95
+*
+*/
+
+// Sequence number modulus
+#define IRLAP_MOD 8
+#define PV_TABLE_MAX_BIT 8
+
+extern UINT vBaudTable[];
+extern UINT vMaxTATTable[];
+extern UINT vMinTATTable[];
+extern UINT vDataSizeTable[];
+extern UINT vWinSizeTable[];
+extern UINT vBOFSTable[];
+extern UINT vDiscTable[];
+extern UINT vThreshTable[];
+extern UINT vBOFSDivTable[];
+
+VOID IrlapOpenLink(
+ OUT PNTSTATUS Status,
+ IN PIRDA_LINK_CB pIrdaLinkCb,
+ IN IRDA_QOS_PARMS *pQos,
+ IN BYTE *pDscvInfo,
+ IN int DscvInfoLen,
+ IN UINT MaxSlot);
+
+UINT IrlapDown(IN PVOID Context,
+ IN PIRDA_MSG);
+
+UINT IrlapUp(IN PVOID Context,
+ IN PIRDA_MSG);
+
+UINT IRLAP_Shutdown();
+
+UINT IrlapGetQosParmVal(UINT[], UINT, UINT *);
+
+void IRLAP_PrintState();
+
+
+
+typedef struct
+{
+ LIST_ENTRY ListHead;
+ int Len;
+} IRDA_MSG_LIST;
+
+// I've exported these for the tester
+UINT DequeMsgList(IRDA_MSG_LIST *, IRDA_MSG **);
+UINT EnqueMsgList(IRDA_MSG_LIST *, IRDA_MSG *, int);
+void InitMsgList(IRDA_MSG_LIST *);
+
+
+
+
+
+
diff --git a/private/ntos/tdi/irda/inc/irlaplog.h b/private/ntos/tdi/irda/inc/irlaplog.h
new file mode 100644
index 000000000..71f67866f
--- /dev/null
+++ b/private/ntos/tdi/irda/inc/irlaplog.h
@@ -0,0 +1,44 @@
+/*****************************************************************************
+*
+* Copyright (c) 1995 Microsoft Corporation
+*
+* File: irlaplog.h
+*
+* Description: IRLAP state machine logging and errors
+*
+* Author: mbert
+*
+* Date: 4/15/95
+*
+*/
+
+#ifdef DEBUG
+
+extern TCHAR *IRDA_PrimStr[];
+extern TCHAR *IRLAP_StateStr[];
+extern TCHAR *MAC_OpStr[];
+extern TCHAR *IRDA_TimerStr[];
+extern TCHAR *IRDA_StatStr[];
+
+#define SPRINT_BUF_LEN 1000
+
+#define EXPAND_ADDR(Addr) (Addr[0], Addr[1], Addr[2], Addr[3])
+
+void IRLAP_EventLogStart(PIRLAP_CB, TCHAR *pFormat, ...);
+void __cdecl IRLAP_LogAction(PIRLAP_CB, TCHAR *pFormat, ...);
+void IRLAP_EventLogComplete(PIRLAP_CB);
+TCHAR *FrameToStr(IRDA_MSG *);
+
+#define IRLAP_LOG_START(X) IRLAP_EventLogStart X
+#define IRLAP_LOG_ACTION(X) IRLAP_LogAction X
+#define IRLAP_LOG_COMPLETE(X) IRLAP_EventLogComplete(X)
+
+#else
+
+#define IRLAP_LOG_START(X) (0)
+#define IRLAP_LOG_ACTION(X) (0)
+#define IRLAP_LOG_COMPLETE(X) (0)
+
+#endif
+
+
diff --git a/private/ntos/tdi/irda/inc/irlmp.h b/private/ntos/tdi/irda/inc/irlmp.h
new file mode 100644
index 000000000..ac46e4107
--- /dev/null
+++ b/private/ntos/tdi/irda/inc/irlmp.h
@@ -0,0 +1,60 @@
+/*****************************************************************************
+*
+* Copyright (c) 1995 Microsoft Corporation
+*
+* File: irlmp.h
+*
+* Description: IRLMP Protocol and control block definitions
+*
+* Author: mbert
+*
+* Date: 4/15/95
+*
+*/
+
+#define IRLMP_MAX_USER_DATA_LEN 53
+
+// IrLMP Entry Points
+
+UINT IRLMP_Initialize(int Port, BOOL SetIR, BYTE DscvInfo[], int DscvInfoLen,
+ IRDA_QOS_PARMS *pQOS, int MaxSlot, CHAR *pDeviceName,
+ int DeviceNameLen);
+
+UINT IrlmpDown(PVOID IrlmpContext, PIRDA_MSG pIMsg);
+UINT IrlmpUp(PVOID IrlmpContext, PIRDA_MSG pIMsg);
+
+UINT IRLMP_RegisterLSAPProtocol(int LSAP, BOOL UseTTP);
+UINT IRLMP_Shutdown();
+
+#ifdef DEBUG
+void IRLMP_PrintState();
+#endif
+
+// IAS
+
+#define IAS_ASCII_CHAR_SET 0
+
+// IAS Attribute value types
+#define IAS_ATTRIB_VAL_MISSING 0
+#define IAS_ATTRIB_VAL_INTEGER 1
+#define IAS_ATTRIB_VAL_BINARY 2
+#define IAS_ATTRIB_VAL_STRING 3
+
+// IAS Operation codes
+#define IAS_OPCODE_GET_VALUE_BY_CLASS 4 // The only one I do
+
+extern const CHAR IAS_ClassName_Device[];
+extern const CHAR IAS_AttribName_DeviceName[];
+extern const CHAR IAS_AttribName_IrLMPSupport[];
+extern const CHAR IAS_AttribName_TTPLsapSel[];
+extern const CHAR IAS_AttribName_IrLMPLsapSel[];
+
+extern const BYTE IAS_ClassNameLen_Device;
+extern const BYTE IAS_AttribNameLen_DeviceName;
+extern const BYTE IAS_AttribNameLen_IRLMPSupport;
+extern const BYTE IAS_AttribNameLen_TTPLsapSel;
+extern const BYTE IAS_AttribNameLen_IrLMPLsapSel;
+
+UINT IAS_AddAttribute(IAS_SET *pIASSet);
+
+UINT IAS_DeleteObject(CHAR *pClassName);
diff --git a/private/ntos/tdi/irda/inc/irmac.h b/private/ntos/tdi/irda/inc/irmac.h
new file mode 100644
index 000000000..534e83525
--- /dev/null
+++ b/private/ntos/tdi/irda/inc/irmac.h
@@ -0,0 +1,32 @@
+/*****************************************************************************
+*
+* Copyright (c) 1995 Microsoft Corporation
+*
+* File: irmac.h
+*
+* Description: IRLAP MAC definitions and entry point prototypes
+*
+* Author: mbert
+*
+* Date: 4/15/95
+*
+*/
+
+// Entry Points
+
+UINT IrmacInitialize();
+
+UINT IrmacDown(
+ IN PVOID IrmacContext,
+ PIRDA_MSG pMsg);
+
+UINT IRMAC_RxFrame(IRDA_MSG *pMsg);
+UINT IRMAC_TimerExpired(IRDA_TIMER Timer);
+void IRMAC_PrintState();
+
+
+
+
+
+
+
diff --git a/private/ntos/tdi/irda/inc/oscfg.h b/private/ntos/tdi/irda/inc/oscfg.h
new file mode 100644
index 000000000..49eab5e00
--- /dev/null
+++ b/private/ntos/tdi/irda/inc/oscfg.h
@@ -0,0 +1,62 @@
+/*****************************************************************************
+*
+* Copyright (c) 1995 Microsoft Corporation
+*
+* File: oscfg.h
+*
+* Description: OS configuration section
+*
+* Author: mmiller
+*
+* Date: 4/25/95
+*
+*/
+#ifdef PEG
+
+// Pegasus specific includes/defines
+#include "peg.h"
+
+#define DbgPrint NKDbgPrintfW
+
+#else // PEG
+
+#include <ntos.h>
+//#include <nt.h>
+//#include <ntrtl.h>
+//#include <nturtl.h>
+
+//#include <zwapi.h>
+//#include <ntddk.h>
+//#include <windows.h>
+
+#define RETAILMSG(exp,p) (0)
+#define DEBUGMSG(exp,p) (0)
+
+// NT specific includes/defines
+//#include "windows.h"
+//#include "stdio.h"
+
+//#define DbgPrint printf
+//typedef char TCHAR;
+
+//#define RETAILMSG(exp,p) ((exp)?DbgPrint p,1:0)
+
+//#ifdef DEBUG
+
+//#define DEBUGMSG(exp,p) ((exp)?DbgPrint p,1:0)
+//#undef NDEBUG
+
+//#define DEBUGZONE(x) 1<<x
+
+//#else // DEBUG
+
+//#define DEBUGMSG(exp,p) (0)
+//#define NDEBUG
+
+//#endif // DEBUG
+
+//#define ASSERT assert
+//#include "assert.h"
+
+
+#endif // PEG
diff --git a/private/ntos/tdi/irda/inc/tmp.h b/private/ntos/tdi/irda/inc/tmp.h
new file mode 100644
index 000000000..85ca9f294
--- /dev/null
+++ b/private/ntos/tdi/irda/inc/tmp.h
@@ -0,0 +1,31 @@
+extern int irdaDbgSettings;
+
+#define DBG_NDIS (1 << 1)
+
+#define DBG_IRMAC (1 << 4)
+
+#define DBG_IRLAP (1 << 8)
+#define DBG_IRLAPLOG (1 << 9)
+
+#define DBG_IRLMP (1 << 12)
+#define DBG_IRLMP_CONN (1 << 13)
+#define DBG_IRLMP_CRED (1 << 14)
+
+#define DBG_DISCOVERY (1 << 16)
+#define DBG_PRINT (1 << 17)
+#define DBG_ADDR (1 << 18)
+
+#define DBG_MISC (1 << 27)
+#define DBG_ALLOC (1 << 28)
+#define DBG_FUNCTION (1 << 29)
+#define DBG_WARN (1 << 30)
+#define DBG_ERROR (1 << 31)
+
+
+#ifdef DEBUG
+#define DEBUGMSG(dbgs,format) ((dbgs & irdaDbgSettings)? DbgPrint format:0)
+#else
+#define DEBUGMSG(dbgs,format) (0)
+#endif
+
+
diff --git a/private/ntos/tdi/irda/irlap/irlap.c b/private/ntos/tdi/irda/irlap/irlap.c
new file mode 100644
index 000000000..c9978e60a
--- /dev/null
+++ b/private/ntos/tdi/irda/irlap/irlap.c
@@ -0,0 +1,4519 @@
+/*****************************************************************************
+*
+* Copyright (c) 1995 Microsoft Corporation
+*
+* @doc
+* @module irlap.c | Provides IrLAP API
+*
+* Author: mbert
+*
+* Date: 4/15/95
+*
+* @comm
+*
+* This module exports the following API's:
+*
+* IrlapDown(Message)
+* Receives from LMP:
+* - Discovery request
+* - Connect request/response
+* - Disconnect request
+* - Data/UData request
+*
+* IrlapUp(Message)
+* Receives from MAC:
+* - Data indications
+* - Control confirmations
+*
+* IRLAP_GetRxMsg(&Message)
+* MAC requesting a message buffer from IRLAP
+* to receive next frame in
+*
+* IRLAP_TimerExp(Timer)
+* Receives from timer thread timer expiration notifications
+*
+* IRLAP_Shutdown()
+* Shut down IRLAP and IRMAC.
+*
+* IRLAP_GetControlBlock()
+* Returns pointer to IRLAP control block.
+*
+* IrlapGetQosParmVal()
+* Allows IRLMP to decode Qos.
+*
+* |---------|
+* | IRLMP |
+* |---------|
+* /|\ |
+* | |
+* IrlmpUp() | | IrlapDown()
+* | |
+* | \|/
+* |---------| IRDA_TimerStart/Stop() |-------|
+* | |-------------------------->| |
+* | IRLAP | | TIMER |
+* | |<--------------------------| |
+* |---------| IRLAP_TimerExp() |-------|
+* /|\ |
+* | |
+* IrlapUp() | |IrmacDown()
+* IRLAP_GetRxMsg() | |
+* | \|/
+* |---------|
+* | IRMAC |
+* |---------|
+*
+*
+* Discovery Request
+*
+* |-------| IRLAP_DISCOVERY_REQ |-------|
+* | |---------------------------------------------------->| |
+* | IRLMP | | IRLAP |
+* | |<----------------------------------------------------| |
+* |-------| IRLAP_DISCOVERY_CONF |-------|
+* DscvStatus = IRLAP_DISCOVERY_COMPLETE
+* IRLAP_DISCOVERY_COLLISION
+* MAC_MEDIA_BUSY
+*
+* Connect Request
+*
+* |-------| IRLAP_CONNECT_REQ |-------|
+* | |---------------------------------------------------->| |
+* | IRLMP | | IRLAP |
+* | |<----------------------------------------------------| |
+* |-------| IRLAP_CONNECT_CONF |-------|
+* ConnStatus = IRLAP_CONNECTION_COMPLETE
+* IRLAP_DISCONNECT_IND
+* DiscStatus = IRLAP_NO_RESPONSE
+* MAC_MEDIA_BUSY
+*
+* Disconnect Request
+*
+* |-------| IRLAP_DISCONNECT_REQ |-------|
+* | |---------------------------------------------------->| |
+* | IRLMP | | IRLAP |
+* | |<----------------------------------------------------| |
+* |-------| IRLAP_DISCONNECT_IND |-------|
+* DiscStatus = IRLAP_DISCONNECT_COMPLETE
+* IRLAP_NO_RESPONSE
+*
+* UData/Data Request
+*
+* |-------| IRLAP_DATA/UDATA_REQ |-------|
+* | |---------------------------------------------------->| |
+* | IRLMP | | IRLAP |
+* | |<----------------------------------------------------| |
+* |-------| IRLAP_DATA_CONF |-------|
+* DataStatus = IRLAP_DATA_REQUEST_COMPLETED
+* IRLAP_DATA_REQUEST_FAILED_LINK_RESET
+*
+* See irda.h for complete message definitions
+*/
+
+#include <irda.h>
+#include <irdalink.h>
+#include <irmac.h>
+#include <irlap.h>
+#include <irlmp.h>
+#include <irlapp.h>
+#include <irlapio.h>
+#include <irlaplog.h>
+
+
+#ifdef TEMPERAMENTAL_SERIAL_DRIVER
+int TossedDups;
+#endif
+
+STATIC UINT _rc; // return code
+STATIC IRDA_MSG IMsg; // for locally generated messages to LMP/MAC
+STATIC UINT IRLAP_SlotTable[] = {1, 6, 8, 16};
+STATIC IRLAP_FRMR_FORMAT FrmRejFormat;
+
+BYTE IRLAP_BroadcastDevAddr[IRDA_DEV_ADDR_LEN] =
+ {0xFF,0xFF,0xFF,0xFF};
+
+// Parameter Value (PV) tables used for negotation
+// bit0 1 2 3 4 5 6 7 8
+// -------------------------------------------------------
+UINT vBaudTable[] = {2400, 9600, 19200, 38400, 57600, 115200,0, 0, 4000000};
+UINT vMaxTATTable[] = {500, 250, 100, 50, 25, 10, 5, 0, 0 };
+UINT vMinTATTable[] = {10000,5000, 1000, 500, 100, 50, 10,0, 0 };
+UINT vDataSizeTable[] = {64, 128, 256, 512, 1024, 2048, 0, 0, 0 };
+UINT vWinSizeTable[] = {1, 2, 3, 4, 5, 6, 7, 0, 0 };
+UINT vBOFSTable[] = {48, 24, 12, 5, 3, 2, 1, 0, 0 };
+UINT vDiscTable[] = {3, 8, 12, 16, 20, 25, 30,40,0 };
+UINT vThreshTable[] = {0, 3, 3, 3, 3, 3, 3, 3, 0 };
+UINT vBOFSDivTable[] = {48, 12, 6, 3, 2, 1, 1, 1, 0 };
+
+// Tables for determining number of BOFS for baud and min turn time
+// min turn time - 10ms 5ms 1ms 0.5ms 0.1ms 0.05ms 0.01ms
+// -------------------------------------------------------------
+UINT BOFS_9600[] = {10, 5, 1, 0, 0, 0, 0};
+UINT BOFS_19200[] = {20, 10, 2, 1, 0, 0, 0};
+UINT BOFS_38400[] = {40, 20, 4, 2, 0, 0, 0};
+UINT BOFS_57600[] = {58, 29, 6, 3, 1, 0, 0};
+UINT BOFS_115200[] = {115, 58, 12, 6, 1, 1, 0};
+
+// Tables for determining maximum line capacity for baud, max turn time
+// max turn time - 500ms 250ms 100ms 50ms 25ms 10ms 5ms
+// -------------------------------------------------------------
+UINT MAXCAP_9600[] = {400, 200, 80, 0, 0, 0, 0};
+UINT MAXCAP_19200[] = {800, 400, 160, 0, 0, 0, 0};
+UINT MAXCAP_38400[] = {1600, 800, 320, 0, 0, 0, 0};
+UINT MAXCAP_57600[] = {2360, 1180, 472, 0, 0, 0, 0};
+UINT MAXCAP_115200[] = {4800, 2400, 960, 480, 240, 96, 48};
+
+// prototypes
+STATIC UINT InitializeState(PIRLAP_CB, IRLAP_STN_TYPE);
+STATIC UINT ReturnTxMsgs(PIRLAP_CB);
+STATIC UINT ProcessConnectReq(PIRLAP_CB, PIRDA_MSG);
+STATIC UINT ProcessConnectResp(PIRLAP_CB, PIRDA_MSG);
+STATIC UINT ProcessDiscoveryReq(PIRLAP_CB, PIRDA_MSG);
+STATIC UINT ProcessDisconnectReq(PIRLAP_CB);
+STATIC UINT ProcessDataAndUDataReq(PIRLAP_CB, PIRDA_MSG);
+STATIC UINT XmitTxMsgList(PIRLAP_CB, BOOL, BOOL *);
+STATIC UINT GotoPCloseState(PIRLAP_CB);
+STATIC UINT GotoNDMThenDscvOrConn(PIRLAP_CB);
+STATIC UINT ProcessMACControlConf(PIRLAP_CB, PIRDA_MSG);
+STATIC UINT ProcessMACDataInd(PIRLAP_CB, PIRDA_MSG , BOOL *);
+STATIC UINT ProcessDscvXIDCmd(PIRLAP_CB, IRLAP_XID_DSCV_FORMAT *, BYTE *);
+STATIC UINT ProcessDscvXIDRsp(PIRLAP_CB, IRLAP_XID_DSCV_FORMAT *, BYTE *);
+STATIC void ExtractQosParms(IRDA_QOS_PARMS *, BYTE *, BYTE *);
+STATIC UINT InitDscvCmdProcessing(PIRLAP_CB, IRLAP_XID_DSCV_FORMAT *);
+STATIC void ExtractDeviceInfo(IRDA_DEVICE *, IRLAP_XID_DSCV_FORMAT *, BYTE *);
+STATIC BOOL DevInDevList(BYTE[], LIST_ENTRY *);
+STATIC UINT AddDevToList(PIRLAP_CB, IRLAP_XID_DSCV_FORMAT *, BYTE *);
+STATIC void ClearDevList(LIST_ENTRY *);
+STATIC UINT ProcessSNRM(PIRLAP_CB, IRLAP_SNRM_FORMAT *, BYTE *);
+STATIC UINT ProcessUA(PIRLAP_CB, IRLAP_UA_FORMAT *, BYTE *);
+STATIC UINT ProcessDISC(PIRLAP_CB);
+STATIC UINT ProcessRD(PIRLAP_CB);
+STATIC UINT ProcessRNRM(PIRLAP_CB);
+STATIC UINT ProcessDM(PIRLAP_CB);
+STATIC UINT ProcessFRMR(PIRLAP_CB);
+STATIC UINT ProcessTEST(PIRLAP_CB, PIRDA_MSG, IRLAP_UA_FORMAT *, int, int);
+STATIC UINT ProcessUI(PIRLAP_CB, PIRDA_MSG, int, int);
+STATIC UINT ProcessREJ_SREJ(PIRLAP_CB, int, PIRDA_MSG, int, int, UINT);
+STATIC UINT ProcessRR_RNR(PIRLAP_CB, int, PIRDA_MSG, int, int, UINT);
+STATIC UINT ProcessIFrame(PIRLAP_CB, PIRDA_MSG, int, int, UINT, UINT, BOOL *);
+STATIC BOOL InvalidNsOrNr(PIRLAP_CB, UINT, UINT);
+STATIC BOOL InvalidNr(PIRLAP_CB, UINT);
+STATIC BOOL InWindow(UINT, UINT, UINT);
+STATIC UINT ProcessInvalidNsOrNr(PIRLAP_CB, int);
+STATIC UINT ProcessInvalidNr(PIRLAP_CB, int);
+STATIC UINT InsertRxWinAndForward(PIRLAP_CB, PIRDA_MSG, UINT, BOOL *);
+STATIC UINT ResendRejects(PIRLAP_CB, UINT);
+STATIC UINT FreeAckedTxMsgs(PIRLAP_CB, UINT);
+STATIC UINT MissingRxFrames(PIRLAP_CB);
+STATIC UINT IFrameOtherStates(PIRLAP_CB, int, int);
+STATIC UINT NegotiateQosParms(PIRLAP_CB, IRDA_QOS_PARMS *);
+STATIC UINT ApplyQosParms(PIRLAP_CB);
+STATIC UINT StationConflict(PIRLAP_CB);
+STATIC UINT ApplyDefaultParms(PIRLAP_CB);
+STATIC UINT ResendDISC(PIRLAP_CB);
+STATIC BOOL IgnoreState(PIRLAP_CB);
+STATIC BOOL MyDevAddr(PIRLAP_CB, BYTE []);
+STATIC VOID SlotTimerExp(PVOID);
+STATIC VOID FinalTimerExp(PVOID);
+STATIC VOID PollTimerExp(PVOID);
+STATIC VOID BackoffTimerExp(PVOID);
+STATIC VOID WDogTimerExp(PVOID);
+STATIC VOID QueryTimerExp(PVOID);
+
+#ifdef DEBUG
+void _inline IRLAP_TimerStart(PIRLAP_CB pIrlapCb, PIRDA_TIMER pTmr)
+{
+ IRLAP_LOG_ACTION((pIrlapCb, "Start %s timer for %dms", pTmr->pName,
+ pTmr->Timeout));
+ IrdaTimerStart(pTmr);
+}
+
+void _inline IRLAP_TimerStop(PIRLAP_CB pIrlapCb, PIRDA_TIMER pTmr)
+{
+ IRLAP_LOG_ACTION((pIrlapCb, "Stop %s timer", pTmr->pName));
+ IrdaTimerStop(pTmr);
+}
+#else
+#define IRLAP_TimerStart(c,t) IrdaTimerStart(t)
+#define IRLAP_TimerStop(c,t) IrdaTimerStop(t)
+#endif
+
+VOID
+IrlapOpenLink(OUT PNTSTATUS Status,
+ IN PIRDA_LINK_CB pIrdaLinkCb,
+ IN IRDA_QOS_PARMS *pQos,
+ IN BYTE *pDscvInfo,
+ IN int DscvInfoLen,
+ IN UINT MaxSlot)
+{
+ UINT rc = SUCCESS;
+ int i;
+ IRDA_MSG *pMsg;
+ PIRLAP_CB pIrlapCb;
+
+ DEBUGMSG(DBG_IRLAP, ("IrlapOpenLink\n"));
+
+ if ((pIrlapCb = CTEAllocMem(sizeof(IRLAP_CB))) == NULL)
+ {
+ DEBUGMSG(DBG_ERROR, ("Alloc failed\n"));
+ *Status = STATUS_INSUFFICIENT_RESOURCES;
+ return;
+ }
+
+ pIrdaLinkCb->IrlapContext = pIrlapCb;
+
+ DscvInfoLen = DscvInfoLen > IRLAP_DSCV_INFO_LEN ?
+ IRLAP_DSCV_INFO_LEN : DscvInfoLen;
+
+ memcpy(pIrlapCb->LocalDevice.DscvInfo, pDscvInfo, DscvInfoLen);
+
+ pIrlapCb->LocalDevice.DscvInfoLen = DscvInfoLen;
+
+ memcpy(&pIrlapCb->LocalQos, pQos, sizeof(IRDA_QOS_PARMS));
+
+ pIrlapCb->Sig = IRLAP_CB_SIG;
+ pIrlapCb->pIrdaLinkCb = pIrdaLinkCb;
+
+ InitMsgList(&pIrlapCb->TxMsgList);
+
+ InitializeListHead(&pIrlapCb->DevList);
+
+ for (i = 0; i < IRLAP_MOD; i++)
+ {
+ pIrlapCb->TxWin.pMsg[i] = NULL;
+ pIrlapCb->RxWin.pMsg[i] = NULL;
+ }
+
+ // Get the local MAX TAT (for final timeout)
+ if ((pIrlapCb->LocalMaxTAT = IrlapGetQosParmVal(vMaxTATTable,
+ pIrlapCb->LocalQos.bfMaxTurnTime, NULL)) == -1)
+ {
+ *Status = STATUS_UNSUCCESSFUL;
+ return /*IRLAP_BAD_QOS*/;
+ }
+
+ // initialize as PRIMARY so UI frames in contention
+ // state sends CRBit = cmd
+ if ((rc = InitializeState(pIrlapCb, PRIMARY)) != SUCCESS)
+ {
+ CTEFreeMem(pIrlapCb);
+ *Status = STATUS_UNSUCCESSFUL;
+ return;
+ }
+
+ pIrlapCb->State = NDM;
+
+ // Generate random local address
+ StoreULAddr(pIrlapCb->LocalDevice.DevAddr, (ULONG) GetMyDevAddr(FALSE));
+
+ pIrlapCb->LocalDevice.IRLAP_Version = 1;
+
+ pIrlapCb->Baud = IRLAP_DEFAULT_BAUD;
+ pIrlapCb->RemoteMaxTAT = IRLAP_DEFAULT_MAX_TAT;
+ pIrlapCb->RemoteDataSize = IRLAP_DEFAULT_DATA_SIZE;
+ pIrlapCb->RemoteWinSize = IRLAP_DEFAULT_WIN_SIZE;
+ pIrlapCb->RemoteNumBOFS = IRLAP_DEFAULT_BOFS;
+
+ pIrlapCb->ConnAddr = IRLAP_BROADCAST_CONN_ADDR;
+
+ pIrlapCb->N1 = 0; // calculated at negotiation
+ pIrlapCb->N2 = 0;
+ pIrlapCb->N3 = 5; // recalculated after negotiation ??
+
+#ifdef DEBUG
+ pIrlapCb->PollTimer.pName = "Poll";
+ pIrlapCb->FinalTimer.pName = "Final" ;
+ pIrlapCb->SlotTimer.pName = "Slot";
+ pIrlapCb->QueryTimer.pName = "Query";
+ pIrlapCb->WDogTimer.pName = "WatchDog";
+ pIrlapCb->BackoffTimer.pName = "Backoff";
+#endif
+
+ IrdaTimerInitialize(&pIrlapCb->PollTimer,
+ PollTimerExp,
+ pIrlapCb->RemoteMaxTAT,
+ pIrlapCb);
+
+ IrdaTimerInitialize(&pIrlapCb->FinalTimer,
+ FinalTimerExp,
+ pIrlapCb->LocalMaxTAT,
+ pIrlapCb);
+
+ IrdaTimerInitialize(&pIrlapCb->SlotTimer,
+ SlotTimerExp,
+ IRLAP_SLOT_TIMEOUT,
+ pIrlapCb);
+
+ IrdaTimerInitialize(&pIrlapCb->QueryTimer,
+ QueryTimerExp,
+ (IRLAP_MAX_SLOTS + 4) * IRLAP_SLOT_TIMEOUT*2,
+ pIrlapCb);
+
+ IrdaTimerInitialize(&pIrlapCb->WDogTimer,
+ WDogTimerExp,
+ 3000,
+ pIrlapCb);
+
+ IrdaTimerInitialize(&pIrlapCb->BackoffTimer,
+ BackoffTimerExp,
+ 0,
+ pIrlapCb);
+
+ // Initialize Link
+ IMsg.Prim = MAC_CONTROL_REQ;
+ IMsg.IRDA_MSG_Op = MAC_INITIALIZE_LINK;
+ IMsg.IRDA_MSG_Baud = IRLAP_DEFAULT_BAUD;
+ IMsg.IRDA_MSG_NumBOFs = IRLAP_DEFAULT_BOFS;
+ IMsg.IRDA_MSG_DataSize = IRLAP_DEFAULT_DATA_SIZE;
+ IMsg.IRDA_MSG_MinTat = 0;
+
+ rc = IrmacDown(pIrlapCb->pIrdaLinkCb, &IMsg);
+
+ *Status = rc;
+ return;
+}
+
+
+VOID
+IrlapCloseLink(PIRLAP_CB pIrlapCb)
+{
+ return;
+}
+
+/*****************************************************************************
+*
+* @func UINT | InitializeState | resets link control block
+*
+* @parm IRLAP_STN_TYPE | StationType| sets station type and the CRBit
+* in the control block
+*/
+UINT
+InitializeState(PIRLAP_CB pIrlapCb,
+ IRLAP_STN_TYPE StationType)
+{
+ int i;
+
+ pIrlapCb->StationType = StationType;
+
+ if (StationType == PRIMARY)
+ pIrlapCb->CRBit = IRLAP_CMD;
+ else
+ pIrlapCb->CRBit = IRLAP_RSP;
+
+ pIrlapCb->RemoteBusy = FALSE;
+ pIrlapCb->LocalBusy = FALSE;
+ pIrlapCb->ClrLocalBusy = FALSE;
+ pIrlapCb->NoResponse = FALSE;
+ pIrlapCb->LocalDiscReq = FALSE;
+ pIrlapCb->ConnAfterClose = FALSE;
+ pIrlapCb->DscvAfterClose = FALSE;
+ pIrlapCb->GenNewAddr = FALSE;
+ pIrlapCb->StatusSent = FALSE;
+ pIrlapCb->Vs = 0;
+ pIrlapCb->Vr = 0;
+ pIrlapCb->WDogExpCnt = 0;
+
+ ClearDevList(&pIrlapCb->DevList);
+
+ memset(&pIrlapCb->RemoteQos, 0, sizeof(IRDA_QOS_PARMS));
+ memset(&pIrlapCb->NegotiatedQos, 0, sizeof(IRDA_QOS_PARMS));
+
+ // Return msgs on tx list and in tx window
+ RetOnErr(ReturnTxMsgs(pIrlapCb));
+
+ // Cleanup RxWin
+ pIrlapCb->RxWin.Start = 0;
+ pIrlapCb->RxWin.End = 0;
+ for (i = 0; i < IRLAP_MOD; i++)
+ {
+ // Receive window
+ if (pIrlapCb->RxWin.pMsg[i] != NULL)
+ {
+ /* RETURN THESE BACK TO NDIS
+ RetOnErr(EnqueMsgList(&pIrlapCb->RxMsgFreeList,
+ pIrlapCb->RxWin.pMsg[i],
+ pIrlapCb->MaxRxMsgFreeListLen));
+ */
+ pIrlapCb->RxWin.pMsg[i] = NULL;
+ }
+ }
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc return desc
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*/
+/*
+UINT
+IRLAP_Shutdown()
+{
+ UINT rc = SUCCESS;
+
+ IRLAP_LOG_START(pIrlapCb, (TEXT("IRLAP Shutdown")));
+
+ if ((rc = ReturnTxMsgs(pIrlapCb)) == SUCCESS)
+ {
+ // Shutdown Link
+ IMsg.Prim = MAC_CONTROL_REQ;
+ IMsg.IRDA_MSG_Op = MAC_SHUTDOWN_LINK;
+ rc = IrmacDown(pIrlapCb->pIrdaLinkCb,&IMsg);
+ }
+ if (pIrlapCb->pRxMsgOut != NULL)
+ {
+ IRDA_FREE_MEM(pIrlapCb->pRxMsgOut);
+ }
+
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->SlotTimer);
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->QueryTimer);
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->PollTimer);
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->BackoffTimer);
+ IRLAP_TimerStop(pIrlapCb, IRMAC_MediaSenseTimer);
+
+ IRLAP_LOG_COMPLETE(pIrlapCb);
+
+ return rc;
+}
+*/
+/*****************************************************************************
+*
+* @func UINT | IrlapDown | Entry point into IRLAP for LMP
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag IRLAP_BAD_PRIMITIVE | Received message that didn't contain one
+* of the primitives defined below
+* IRLAP_NOT_INITIALIZED | IRLAP has not been intialize with
+* IrlapInitialize()
+*
+* @parm IRDA_MSG * | pMsg | Pointer to an IRDA Message
+*
+* @comm Processes the following service requests:
+* IRLAP_DISCOVERY_REQ,
+* IRLAP_CONNECT_REQ,
+* IRLAP_CONNECT_RESP,
+* IRLAP_DISCONNECT_REQ,
+* IRLAP_DATA_REQ,
+* IRLAP_UDATA_REQ,
+*/
+UINT
+IrlapDown(PVOID Context,
+ PIRDA_MSG pMsg)
+{
+ PIRLAP_CB pIrlapCb = (PIRLAP_CB) Context;
+ UINT rc = SUCCESS;
+
+ IRLAP_LOG_START((pIrlapCb, IRDA_PrimStr[pMsg->Prim]));
+
+ switch (pMsg->Prim)
+ {
+ case IRLAP_DISCOVERY_REQ:
+ rc = ProcessDiscoveryReq(pIrlapCb, pMsg);
+ break;
+
+ case IRLAP_CONNECT_REQ:
+ rc = ProcessConnectReq(pIrlapCb, pMsg);
+ break;
+
+ case IRLAP_CONNECT_RESP:
+ rc = ProcessConnectResp(pIrlapCb, pMsg);
+ break;
+
+ case IRLAP_DISCONNECT_REQ:
+ rc = ProcessDisconnectReq(pIrlapCb);
+ break;
+
+ case IRLAP_DATA_REQ:
+ case IRLAP_UDATA_REQ:
+ rc = ProcessDataAndUDataReq(pIrlapCb, pMsg);
+ break;
+
+ case IRLAP_FLOWON_REQ:
+ if (pIrlapCb->LocalBusy)
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Local busy condition cleared")));
+ pIrlapCb->LocalBusy = FALSE;
+ pIrlapCb->ClrLocalBusy = TRUE;
+ }
+ break;
+
+ default:
+ rc = IRLAP_BAD_PRIM;
+
+ }
+
+ IRLAP_LOG_COMPLETE(pIrlapCb);
+
+ return (rc);
+}
+/*****************************************************************************
+*
+* @func UINT | IrlapUp | Entry point into IRLAP for MAC
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag IRLAP_BAD_PRIMITIVE | Received message that didn't contain one
+* of the primitives defined below
+* IRLAP_NOT_INITIALIZED | IRLAP has not been intialize with
+* IrlapInitialize()
+*
+* @parm IRDA_MSG * | pMsg | Pointer to an IRDA Message
+*
+* @comm Processes the following service requests:
+* MAC_DATA_IND
+* MAC_CONTROL_CONF
+*/
+UINT
+IrlapUp(PVOID Context, PIRDA_MSG pMsg)
+{
+ UINT rc = SUCCESS;
+ BOOL FreeMsg = TRUE;
+ PIRLAP_CB pIrlapCb = (PIRLAP_CB) Context;
+
+ // Whats this again ??? !!! pIrlapCb->pRxMsgOut = NULL;
+
+ ASSERT(pIrlapCb->Sig == IRLAP_CB_SIG);
+
+ switch (pMsg->Prim)
+ {
+ case MAC_DATA_IND:
+// IRLAP_LOG_START((pIrlapCb, TEXT("MAC_DATA_IND: %s"), FrameToStr(pMsg)));
+ IRLAP_LOG_START((pIrlapCb, TEXT("MAC_DATA_IND")));
+
+ rc = ProcessMACDataInd(pIrlapCb, pMsg, &FreeMsg);
+
+ /* What dis all about?
+ if (FreeMsg && SUCCESS == rc)
+ {
+ rc = EnqueMsgList(&pIrlapCb->RxMsgFreeList, pMsg,
+ pIrlapCb->MaxRxMsgFreeListLen);
+ }
+ */
+ break;
+
+ case MAC_CONTROL_CONF:
+ IRLAP_LOG_START((pIrlapCb, IRDA_PrimStr[pMsg->Prim]));
+ rc = ProcessMACControlConf(pIrlapCb, pMsg);
+ break;
+
+ default:
+ IRLAP_LOG_START((pIrlapCb, IRDA_PrimStr[pMsg->Prim]));
+ rc = IRLAP_BAD_PRIM;
+
+ }
+
+ IRLAP_LOG_COMPLETE(pIrlapCb);
+
+ return (rc);
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc return desc
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+
+/* THIS FUCKER GOES
+UINT
+IRLAP_GetRxMsg(IRDA_MSG **ppMsg)
+{
+ UINT rc = SUCCESS;
+
+ ASSERT(pIrlapCb->pRxMsgOut == NULL);
+
+ if ((rc = DequeMsgList(&pIrlapCb->RxMsgFreeList, ppMsg)) == SUCCESS)
+ {
+ (*ppMsg)->IRDA_MSG_pBase = ((BYTE *) (*ppMsg)) + sizeof(IRDA_MSG);
+ (*ppMsg)->IRDA_MSG_pLimit = ((BYTE *) (*ppMsg)) +
+ sizeof(IRDA_MSG)+ 5 + pIrlapCb->LocalDataSize;
+
+ pIrlapCb->pRxMsgOut = *ppMsg;
+ }
+
+ return rc;
+}
+*/
+
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+UINT
+ReturnTxMsgs(PIRLAP_CB pIrlapCb)
+{
+ int i;
+ IRDA_MSG *pMsg;
+
+ // Return messages on TxMsgList to LMP
+ while (DequeMsgList(&pIrlapCb->TxMsgList, &pMsg) == SUCCESS)
+ {
+ pMsg->Prim += 2; // make it a confirm
+ pMsg->IRDA_MSG_DataStatus = IRLAP_DATA_REQUEST_FAILED_LINK_RESET;
+ RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, pMsg));
+ }
+
+ pIrlapCb->TxWin.Start = 0;
+ pIrlapCb->TxWin.End = 0;
+ // Transmit window
+ for (i = 0; i < IRLAP_MOD; i++)
+ {
+ if (pIrlapCb->TxWin.pMsg[i] != NULL)
+ {
+ pIrlapCb->TxWin.pMsg[i]->Prim = IRLAP_DATA_CONF;
+ pIrlapCb->TxWin.pMsg[i]->IRDA_MSG_DataStatus =
+ IRLAP_DATA_REQUEST_FAILED_LINK_RESET;
+ RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, pIrlapCb->TxWin.pMsg[i]));
+
+ pIrlapCb->TxWin.pMsg[i] = NULL;
+ }
+ }
+
+ return SUCCESS;
+}
+
+/*****************************************************************************
+*
+* @func BOOL | MyDevAddr | Determines if DevAddr matches the local
+* device address or is the broadcast
+*
+* @rdesc TRUE if address is mine or broadcast else FALS
+*
+* @parm BYTE [] | DevAddr | Device Address
+*
+*/
+BOOL
+MyDevAddr(PIRLAP_CB pIrlapCb,
+ BYTE DevAddr[])
+{
+ if (memcmp(DevAddr, IRLAP_BroadcastDevAddr, IRDA_DEV_ADDR_LEN) != 0 &&
+ memcmp(DevAddr, pIrlapCb->LocalDevice.DevAddr, IRDA_DEV_ADDR_LEN) != 0)
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*****************************************************************************
+*
+* @func UINT | ProcessConnectReq | Process connect request from LMP
+*
+* @rdesc 0, otherwise one of the following errors:
+* @flag IRLAP_BAD_STATE | Requested connection in an invalid state
+*
+* @parm IRDA_MSG * | pMsg | pointer to an IRDA_MSG
+*
+* @comm
+* comments
+*/
+UINT
+ProcessConnectReq(PIRLAP_CB pIrlapCb,
+ PIRDA_MSG pMsg)
+{
+ switch (pIrlapCb->State)
+ {
+ case NDM:
+ // Save Remote Address for later use
+ memcpy(pIrlapCb->RemoteDevice.DevAddr, pMsg->IRDA_MSG_RemoteDevAddr,
+ IRDA_DEV_ADDR_LEN);
+
+ IMsg.Prim = MAC_CONTROL_REQ;
+ IMsg.IRDA_MSG_Op = MAC_MEDIA_SENSE;
+ IMsg.IRDA_MSG_SenseTime = IRLAP_MEDIA_SENSE_TIME;
+
+ RetOnErr(IrmacDown(pIrlapCb->pIrdaLinkCb,&IMsg));
+ pIrlapCb->State = CONN_MEDIA_SENSE;
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_CONTROL_REQ (media sense)")));
+ break;
+
+ case DSCV_REPLY:
+ return IRLAP_REMOTE_DISCOVERY_IN_PROGRESS_ERR;
+
+ case P_CLOSE:
+ memcpy(pIrlapCb->RemoteDevice.DevAddr,
+ pMsg->IRDA_MSG_RemoteDevAddr, IRDA_DEV_ADDR_LEN);
+ pIrlapCb->ConnAfterClose = TRUE;
+ break;
+
+ default:
+ return IRLAP_BAD_STATE;
+ }
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func UINT | ProcessConnectResp | Process connect response from LMP
+*
+* @rdesc 0, otherwise one of the following errors:
+* @flag IRLAP_BAD_STATE | Requested connection in an invalid state
+*
+* @parm IRDA_MSG * | pMsg | pointer to an IRDA_MSG
+*
+* @comm
+* comments
+*/
+UINT
+ProcessConnectResp(PIRLAP_CB pIrlapCb,
+ PIRDA_MSG pMsg)
+{
+
+ if (pIrlapCb->State != SNRM_RECEIVED)
+ {
+ return IRLAP_BAD_STATE;
+ }
+
+ pIrlapCb->ConnAddr = pIrlapCb->SNRMConnAddr;
+ RetOnErr(SendUA(pIrlapCb, TRUE));
+ RetOnErr(ApplyQosParms(pIrlapCb));
+
+ RetOnErr(InitializeState(pIrlapCb, SECONDARY));
+ // start watchdog timer with poll timeout
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
+ pIrlapCb->State = S_NRM;
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func UINT | ProcessDiscoveryReq | Process Discovery request from LMP
+*
+* @rdesc 0, otherwise one of the following errors:
+* @flag IRLAP_BAD_STATE | Requested discovery in an invalid state
+*
+* @comm
+* comments
+*/
+UINT
+ProcessDiscoveryReq(PIRLAP_CB pIrlapCb,
+ PIRDA_MSG pMsg)
+{
+ IRDA_MSG IMsg;
+
+ switch (pIrlapCb->State)
+ {
+ case NDM:
+ if (pMsg->IRDA_MSG_SenseMedia == TRUE)
+ {
+ IMsg.Prim = MAC_CONTROL_REQ;
+ IMsg.IRDA_MSG_Op = MAC_MEDIA_SENSE;
+ IMsg.IRDA_MSG_SenseTime = IRLAP_MEDIA_SENSE_TIME;
+ RetOnErr(IrmacDown(pIrlapCb->pIrdaLinkCb,&IMsg));
+ pIrlapCb->State = DSCV_MEDIA_SENSE;
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_CONTROL_REQ (media sense)")));
+ }
+ else
+ {
+ pIrlapCb->SlotCnt = 0;
+ pIrlapCb->GenNewAddr = FALSE;
+
+ ClearDevList(&pIrlapCb->DevList);
+
+ RetOnErr(SendDscvXIDCmd(pIrlapCb));
+
+ IMsg.Prim = MAC_CONTROL_REQ;
+ IMsg.IRDA_MSG_Op = MAC_MEDIA_SENSE;
+ IMsg.IRDA_MSG_SenseTime = IRLAP_DSCV_SENSE_TIME;
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_CONTROL_REQ (dscv sense)")));
+ RetOnErr(IrmacDown(pIrlapCb->pIrdaLinkCb,&IMsg));
+
+ pIrlapCb->State = DSCV_QUERY;
+ }
+ break;
+
+ case DSCV_REPLY:
+ return IRLAP_REMOTE_DISCOVERY_IN_PROGRESS_ERR;
+
+ case SNRM_RECEIVED:
+ return IRLAP_REMOTE_CONNECTION_IN_PROGRESS_ERR;
+
+ case P_CLOSE:
+ pIrlapCb->DscvAfterClose = TRUE;
+ break;
+
+ default:
+ return IRLAP_BAD_STATE;
+ }
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func UINT | ProcessDisconnectReq | Process disconnect request from LMP
+*
+* @rdesc 0, otherwise one of the following errors:
+* @flag IRLAP_BAD_STATE | Requested disconnect in an invalid state
+*
+* @comm
+* comments
+*/
+UINT
+ProcessDisconnectReq(PIRLAP_CB pIrlapCb)
+{
+ RetOnErr(ReturnTxMsgs(pIrlapCb));
+
+ switch (pIrlapCb->State)
+ {
+ case NDM:
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
+ break;
+
+ case SNRM_SENT:
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
+ case DSCV_MEDIA_SENSE:
+ case DSCV_QUERY:
+ case DSCV_REPLY:
+ case CONN_MEDIA_SENSE:
+ pIrlapCb->State = NDM;
+ break;
+
+ case BACKOFF_WAIT:
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->BackoffTimer);
+ pIrlapCb->State = NDM;
+ break;
+
+ case SNRM_RECEIVED:
+ pIrlapCb->ConnAddr = pIrlapCb->SNRMConnAddr;
+ RetOnErr(SendDM(pIrlapCb));
+ pIrlapCb->ConnAddr = IRLAP_BROADCAST_CONN_ADDR;
+ pIrlapCb->State = NDM;
+ break;
+
+ case P_XMIT:
+ pIrlapCb->LocalDiscReq = TRUE;
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->PollTimer);
+ RetOnErr(SendDISC(pIrlapCb));
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ pIrlapCb->RetryCnt = 0;
+ pIrlapCb->State = P_CLOSE;
+ break;
+
+ case P_RECV:
+ pIrlapCb->LocalDiscReq = TRUE;
+ pIrlapCb->State = P_DISCONNECT_PEND;
+ break;
+
+ case S_NRM:
+ pIrlapCb->LocalDiscReq = TRUE;
+ pIrlapCb->State = S_DISCONNECT_PEND;
+ break;
+
+ default:
+ return IRLAP_BAD_STATE;
+ }
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func UINT | ProcessDataReq | Process data request from LMP
+*
+* @rdesc 0, otherwise one of the following errors:
+* @flag IRLAP_BAD_STATE | Requested data in an invalid state
+* @flag IRLAP_TX_MSG_LIST_FULL | Tx Msg List has become full, can't process
+*
+* @comm
+* comments
+*/
+UINT
+ProcessDataAndUDataReq(PIRLAP_CB pIrlapCb,
+ PIRDA_MSG pMsg)
+{
+ BOOL LinkTurned;
+ int DataSize = (pMsg->IRDA_MSG_pHdrWrite - pMsg->IRDA_MSG_pHdrRead) +
+ (pMsg->IRDA_MSG_pWrite - pMsg->IRDA_MSG_pRead);
+
+ if (DataSize > pIrlapCb->RemoteDataSize)
+ {
+ return IRLAP_BAD_DATA_REQUEST;
+ }
+
+ switch (pIrlapCb->State)
+ {
+ case P_XMIT:
+ // Enque message, then drain the message list. If the link
+ // was turned in the process of draining messages stop Poll Timer,
+ // start Final Timer and enter P_RECV. Otherwise we'll stay in P_XMIT
+ // waiting for more data requests from LMP or Poll Timer expiration
+ RetOnErr(EnqueMsgList(&pIrlapCb->TxMsgList, pMsg, -1));
+
+ RetOnErr(XmitTxMsgList(pIrlapCb, FALSE, &LinkTurned));
+
+ if (LinkTurned)
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->PollTimer);
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ pIrlapCb->State = P_RECV;
+ }
+ return SUCCESS;
+
+ case P_DISCONNECT_PEND: // For pending disconnect states, take the message.
+ case S_DISCONNECT_PEND: // They will be returned when the link disconnects
+ case P_RECV:
+ case S_NRM:
+ // Que the message for later transmission
+
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Queueing request")));
+
+ RetOnErr(EnqueMsgList(&pIrlapCb->TxMsgList, pMsg, -1));
+
+ return SUCCESS;
+
+ default:
+ if (pMsg->Prim == IRLAP_DATA_REQ)
+ {
+ return IRLAP_BAD_STATE;
+ }
+ else
+ {
+ if (pIrlapCb->State == NDM)
+ {
+ return SendUIFrame(pIrlapCb, pMsg);
+ }
+ else
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
+ }
+ }
+ }
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+UINT
+XmitTxMsgList(PIRLAP_CB pIrlapCb, BOOL AlwaysTurnLink, BOOL *pLinkTurned)
+{
+ UINT rc = SUCCESS;
+ IRDA_MSG *pMsg;
+ UINT LinkTurned;
+
+ LinkTurned = FALSE;
+
+ // If the remote is not busy send data
+ // If we need to clear the local busy condition, don't send data send RR
+ if (!pIrlapCb->RemoteBusy && !pIrlapCb->ClrLocalBusy)
+ {
+ while ((rc == SUCCESS) && !LinkTurned &&
+ (DequeMsgList(&pIrlapCb->TxMsgList, &pMsg) == SUCCESS))
+ {
+ if (pMsg->Prim == IRLAP_DATA_REQ)
+ {
+ // Insert message into transmit window
+ pIrlapCb->TxWin.pMsg[pIrlapCb->Vs] = pMsg;
+
+ // Send message. If full window or there are no
+ // more data requests, send with PF Set (turns link).
+ if ((pIrlapCb->Vs == (pIrlapCb->TxWin.Start +
+ pIrlapCb->RemoteWinSize-1) % IRLAP_MOD) ||
+ (0 == pIrlapCb->TxMsgList.Len /*AlwaysTurnLink*/))
+ {
+ rc = SendIFrame(pIrlapCb,
+ pMsg,
+ pIrlapCb->Vs,
+ IRLAP_PFBIT_SET);
+ LinkTurned = TRUE;
+ }
+ else
+ {
+ rc = SendIFrame(pIrlapCb,
+ pMsg,
+ pIrlapCb->Vs,
+ IRLAP_PFBIT_CLEAR);
+ }
+ pIrlapCb->Vs = (pIrlapCb->Vs + 1) % IRLAP_MOD;
+ }
+ else // IRLAP_UDATA_REQUEST
+ {
+ // For now, always turn link
+ rc = SendUIFrame(pIrlapCb, pMsg);
+ pMsg->Prim = IRLAP_UDATA_CONF;
+ pMsg->IRDA_MSG_DataStatus = IRLAP_DATA_REQUEST_COMPLETED;
+ RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, pMsg));
+ LinkTurned = TRUE;
+ }
+ }
+ pIrlapCb->TxWin.End = pIrlapCb->Vs;
+ }
+
+ if (rc == SUCCESS)
+ {
+ if ((AlwaysTurnLink && !LinkTurned) || pIrlapCb->ClrLocalBusy)
+ {
+ rc = SendRR_RNR(pIrlapCb);
+ LinkTurned = TRUE;
+ if (pIrlapCb->ClrLocalBusy)
+ {
+ pIrlapCb->ClrLocalBusy = FALSE;
+ }
+ }
+ }
+
+ if (pLinkTurned != NULL)
+ {
+ *pLinkTurned = LinkTurned;
+ }
+
+ return (rc);
+}
+
+UINT
+GotoPCloseState(PIRLAP_CB pIrlapCb)
+{
+ if (!pIrlapCb->LocalDiscReq)
+ {
+ IMsg.Prim = IRLAP_DISCONNECT_IND;
+ IMsg.IRDA_MSG_DiscStatus = IRLAP_REMOTE_INITIATED;
+ RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
+ }
+
+ pIrlapCb->State = P_CLOSE;
+
+ return SUCCESS;
+}
+
+UINT
+GotoNDMThenDscvOrConn(PIRLAP_CB pIrlapCb)
+{
+ if (pIrlapCb->ConnAfterClose)
+ {
+ pIrlapCb->ConnAfterClose = FALSE;
+ IMsg.Prim = MAC_CONTROL_REQ;
+ IMsg.IRDA_MSG_Op = MAC_MEDIA_SENSE;
+ IMsg.IRDA_MSG_SenseTime = IRLAP_MEDIA_SENSE_TIME;
+
+ RetOnErr(IrmacDown(pIrlapCb->pIrdaLinkCb,&IMsg));
+ pIrlapCb->State = CONN_MEDIA_SENSE;
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_CONTROL_REQ (media sense)")));
+
+ return SUCCESS;
+ }
+
+ if (pIrlapCb->DscvAfterClose)
+ {
+ pIrlapCb->DscvAfterClose = FALSE;
+ IMsg.Prim = MAC_CONTROL_REQ;
+ IMsg.IRDA_MSG_Op = MAC_MEDIA_SENSE;
+ IMsg.IRDA_MSG_SenseTime = IRLAP_MEDIA_SENSE_TIME;
+ RetOnErr(IrmacDown(pIrlapCb->pIrdaLinkCb,&IMsg));
+ pIrlapCb->State = DSCV_MEDIA_SENSE;
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_CONTROL_REQ (media sense)")));
+ return SUCCESS;
+ }
+ pIrlapCb->State = NDM;
+ return SUCCESS;
+}
+
+/*****************************************************************************
+*
+* @func UINT | ProcessMACControlConf | Process a control confirm from MAC
+*
+* @rdesc SUCCESS, otherwise one of the following error codes
+* @flag IRLAP_BAD_OP | Bad Operation, must be MAC_MEDIA_SENSE
+* @flag IRLAP_BAD_OPSTATUS | Invalid return status for operation
+* @flag IRLAP_BAD_STATE | CONTROL_CONF in invalid state
+*
+* @parm IRDA_MSG * | pMsg | pointer to an IRDA_MSG
+*
+* @comm
+* comments
+*
+*/
+UINT
+ProcessMACControlConf(PIRLAP_CB pIrlapCb, PIRDA_MSG pMsg)
+{
+ if (pMsg->IRDA_MSG_Op != MAC_MEDIA_SENSE)
+ return IRLAP_BAD_OP;
+
+ switch (pIrlapCb->State)
+ {
+ case DSCV_MEDIA_SENSE:
+ switch (pMsg->IRDA_MSG_OpStatus)
+ {
+ case MAC_MEDIA_CLEAR:
+ pIrlapCb->SlotCnt = 0;
+ pIrlapCb->GenNewAddr = FALSE;
+
+ ClearDevList(&pIrlapCb->DevList);
+
+ RetOnErr(SendDscvXIDCmd(pIrlapCb));
+
+ pMsg->Prim = MAC_CONTROL_REQ;
+ pMsg->IRDA_MSG_Op = MAC_MEDIA_SENSE;
+ pMsg->IRDA_MSG_SenseTime = IRLAP_DSCV_SENSE_TIME;
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_CONTROL_REQ (dscv sense)")));
+ RetOnErr(IrmacDown(pIrlapCb->pIrdaLinkCb,pMsg));
+
+ pIrlapCb->State = DSCV_QUERY;
+ break;
+
+ case MAC_MEDIA_BUSY:
+ IMsg.Prim = IRLAP_DISCOVERY_CONF;
+ IMsg.IRDA_MSG_pDevList = NULL;
+ IMsg.IRDA_MSG_DscvStatus = MAC_MEDIA_BUSY;
+ RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
+ pIrlapCb->State = NDM;
+ break;
+
+ default:
+ return IRLAP_BAD_OPSTATUS;
+ }
+ break;
+
+ case CONN_MEDIA_SENSE:
+ switch (pMsg->IRDA_MSG_OpStatus)
+ {
+ case MAC_MEDIA_CLEAR:
+
+ // Generate a random connection address
+ pIrlapCb->ConnAddr = IRLAP_RAND(1, 0x7e);
+
+ pIrlapCb->RetryCnt = 0;
+
+ RetOnErr(SendSNRM(pIrlapCb, TRUE));
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ pIrlapCb->State = SNRM_SENT;
+ break;
+
+ case MAC_MEDIA_BUSY:
+ IMsg.Prim = IRLAP_DISCONNECT_IND;
+ IMsg.IRDA_MSG_DiscStatus = MAC_MEDIA_BUSY;
+ RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
+ pIrlapCb->State = NDM;
+ break;
+
+ default:
+ return IRLAP_BAD_OPSTATUS;
+ }
+ break;
+
+ case DSCV_QUERY:
+ switch (pMsg->IRDA_MSG_OpStatus)
+ {
+ case MAC_MEDIA_CLEAR:
+ // Nobody responded, procede as if the slot timer expired
+
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Media clear, making fake slot exp")));
+
+ SlotTimerExp(pIrlapCb);
+ break;
+
+ case MAC_MEDIA_BUSY:
+ // Some responding, give'm more time
+
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Media busy, starting slot timer")));
+
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->SlotTimer);
+ break;
+ }
+ break;
+
+ default:
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
+ }
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func UINT | ProcessMACDataInd | Processes MAC Data
+*
+* @rdesc SUCCESS, otherwise one of the following error codes
+* @flag ?? | invalid return status for operation
+*
+* @parm IRDA_MSG * | pMsg | pointer to an IRDA_MSG
+*
+* @comm
+*
+*/
+UINT
+ProcessMACDataInd(PIRLAP_CB pIrlapCb, PIRDA_MSG pMsg, BOOL *pFreeMsg)
+{
+ int Addr = (int) IRLAP_GET_ADDR(*(pMsg->IRDA_MSG_pRead));
+ int CRBit = (int) IRLAP_GET_CRBIT(*(pMsg->IRDA_MSG_pRead));
+ int Cntl = (int) *(pMsg->IRDA_MSG_pRead + 1);
+ int PFBit = IRLAP_GET_PFBIT(Cntl);
+ UINT Ns = IRLAP_GET_NS(Cntl);
+ UINT Nr = IRLAP_GET_NR(Cntl);
+ int XIDFormatID = (int) *(pMsg->IRDA_MSG_pRead+2);
+ IRLAP_XID_DSCV_FORMAT *pXIDFormat = (IRLAP_XID_DSCV_FORMAT *)
+ (pMsg->IRDA_MSG_pRead + 3);
+ IRLAP_SNRM_FORMAT *pSNRMFormat = (IRLAP_SNRM_FORMAT *)
+ (pMsg->IRDA_MSG_pRead + 2);
+ IRLAP_UA_FORMAT *pUAFormat = (IRLAP_UA_FORMAT *)
+ (pMsg->IRDA_MSG_pRead + 2);
+
+ if (Addr != pIrlapCb->ConnAddr && Addr != IRLAP_BROADCAST_CONN_ADDR)
+ {
+ IRLAP_LOG_ACTION((pIrlapCb,
+ TEXT("Ignoring, connection address %02X"), Addr));
+ return SUCCESS;
+ }
+
+ pIrlapCb->StatusSent = FALSE; // don't ask
+
+ FrmRejFormat.CntlField = Cntl; // for later maybe
+
+ // Peer has sent a frame so clear the NoResponse condition
+ if (pIrlapCb->NoResponse)
+ {
+ pIrlapCb->NoResponse = FALSE;
+ pIrlapCb->RetryCnt = 0;
+ pIrlapCb->WDogExpCnt = 0;
+ }
+
+ switch (IRLAP_FRAME_TYPE(Cntl))
+ {
+ /*****************/
+ case IRLAP_I_FRAME:
+ /*****************/
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("I-frame")));
+ return ProcessIFrame(pIrlapCb, pMsg,
+ CRBit, PFBit, Ns, Nr, pFreeMsg);
+
+ /*****************/
+ case IRLAP_S_FRAME:
+ /*****************/
+ switch (IRLAP_GET_SCNTL(Cntl))
+ {
+ /*-----------*/
+ case IRLAP_RR:
+ case IRLAP_RNR:
+ /*-----------*/
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("RR/RNR-frame")));
+ return ProcessRR_RNR(pIrlapCb,
+ IRLAP_GET_SCNTL(Cntl),
+ pMsg, CRBit, PFBit, Nr);
+ /*------------*/
+ case IRLAP_SREJ:
+ case IRLAP_REJ:
+ /*------------*/
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("SJREJ/REJ-frame")));
+ return ProcessREJ_SREJ(pIrlapCb,
+ IRLAP_GET_SCNTL(Cntl),
+ pMsg, CRBit, PFBit, Nr);
+ }
+ break;
+
+ /*****************/
+ case IRLAP_U_FRAME:
+ /*****************/
+ switch (IRLAP_GET_UCNTL(Cntl))
+ {
+ /*---------------*/
+ case IRLAP_XID_CMD:
+ /*---------------*/
+ // Should always be a command
+ if (CRBit != IRLAP_CMD)
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Received XID cmd with CRBit = rsp")));
+ return IRLAP_XID_CMD_RSP;
+ }
+ // Poll bit should always be set
+ if (PFBit != IRLAP_PFBIT_SET)
+ {
+ IRLAP_LOG_ACTION((pIrlapCb,
+ TEXT("Received XID command without Poll set")));
+ return IRLAP_XID_CMD_NOT_P;
+ }
+
+ if (XIDFormatID == IRLAP_XID_DSCV_FORMAT_ID)
+ {
+ // Slot No is less than max slot or 0xff
+ if (pXIDFormat->SlotNo>IRLAP_SlotTable[pXIDFormat->NoOfSlots]
+ && pXIDFormat->SlotNo != IRLAP_END_DSCV_SLOT_NO)
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Invalid slot number %d"),
+ pXIDFormat->SlotNo));
+ return IRLAP_BAD_SLOTNO;
+ }
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("DscvXIDCmd")));
+ return ProcessDscvXIDCmd(pIrlapCb,
+ pXIDFormat,
+ pMsg->IRDA_MSG_pWrite);
+ }
+ else
+ {
+ return SUCCESS; // ignore per errata
+ }
+
+ /*---------------*/
+ case IRLAP_XID_RSP:
+ /*---------------*/
+ if (XIDFormatID == IRLAP_XID_DSCV_FORMAT_ID)
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("DscvXIDRsp")));
+ return ProcessDscvXIDRsp(pIrlapCb,
+ pXIDFormat,pMsg->IRDA_MSG_pWrite);
+ }
+ else
+ {
+ return SUCCESS; // ignore per errata
+ }
+
+ /*------------*/
+ case IRLAP_SNRM: // or IRLAP_RNRM
+ /*------------*/
+ if (IRLAP_PFBIT_SET != PFBit)
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Received SNRM/RNRM without P set")));
+ return IRLAP_SNRM_NOT_P;
+ }
+ if (IRLAP_CMD == CRBit)
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("SNRM")));
+ return ProcessSNRM(pIrlapCb,
+ pSNRMFormat,
+ pMsg->IRDA_MSG_pWrite);
+ }
+ else
+ {
+ return ProcessRNRM(pIrlapCb);
+ }
+
+ /*----------*/
+ case IRLAP_UA:
+ /*----------*/
+ if (CRBit != IRLAP_RSP)
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Received UA as a command")));
+ return IRLAP_UA_NOT_RSP;
+ }
+ if (PFBit != IRLAP_PFBIT_SET)
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Received UA without F set")));
+ return IRLAP_UA_NOT_F;
+ }
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("UA")));
+ return ProcessUA(pIrlapCb, pUAFormat, pMsg->IRDA_MSG_pWrite);
+
+ /*------------*/
+ case IRLAP_DISC: // or IRLAP_RD
+ /*------------*/
+ if (IRLAP_PFBIT_SET != PFBit)
+ {
+ IRLAP_LOG_ACTION((pIrlapCb,
+ TEXT("Received DISC/RD command without Poll set")));
+ return IRLAP_DISC_CMD_NOT_P;
+ }
+ if (IRLAP_CMD == CRBit)
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("DISC")));
+ return ProcessDISC(pIrlapCb);
+ }
+ else
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("RD")));
+ return ProcessRD(pIrlapCb);
+ }
+
+ /*----------*/
+ case IRLAP_UI:
+ /*----------*/
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("UI")));
+ return ProcessUI(pIrlapCb, pMsg, CRBit, PFBit);
+
+ /*------------*/
+ case IRLAP_TEST:
+ /*------------*/
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("TEST")));
+ return ProcessTEST(pIrlapCb, pMsg, pUAFormat, CRBit, PFBit);
+
+ /*------------*/
+ case IRLAP_FRMR:
+ /*------------*/
+ if (IRLAP_RSP != CRBit)
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Received FRMR cmd (must be resp)")));
+ return IRLAP_FRMR_RSP_CMD;
+ }
+ if (IRLAP_PFBIT_SET != PFBit)
+ {
+ IRLAP_LOG_ACTION((pIrlapCb,
+ TEXT("Received FRMR resp without Final set")));
+ return IRLAP_FRMR_RSP_NOT_F;
+ }
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("FRMR")));
+ return ProcessFRMR(pIrlapCb);
+
+ /*----------*/
+ case IRLAP_DM:
+ /*----------*/
+ if (IRLAP_RSP != CRBit)
+ {
+ IRLAP_LOG_ACTION((pIrlapCb,
+ TEXT("Received DM command (must be response)")));
+ return IRLAP_DM_RSP_CMD;
+ }
+ if (IRLAP_PFBIT_SET != PFBit)
+ {
+ IRLAP_LOG_ACTION((pIrlapCb,
+ TEXT("Received DM response without Final set")));
+ return IRLAP_DM_RSP_NOT_F;
+ }
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("DM")));
+ return ProcessDM(pIrlapCb);
+ }
+ break;
+ }
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func UINT | ProcessDscvXIDCmd | Process received XID Discovery command
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*/
+UINT
+ProcessDscvXIDCmd(PIRLAP_CB pIrlapCb,
+ IRLAP_XID_DSCV_FORMAT *pXIDFormat,
+ BYTE *pEndDscvInfoByte)
+{
+ if (!MyDevAddr(pIrlapCb, pXIDFormat->DestAddr))
+ {
+/* IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring XID addressed to:%02X%02X%02X%02X"),
+ EXPAND_ADDR(pXIDFormat->DestAddr)));*/
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring XID addressed to %X"),
+ pXIDFormat->DestAddr));
+ return SUCCESS;
+ }
+
+ if (pXIDFormat->SlotNo == IRLAP_END_DSCV_SLOT_NO)
+ {
+ pIrlapCb->GenNewAddr = FALSE;
+ switch (pIrlapCb->State)
+ {
+ case DSCV_QUERY:
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->SlotTimer);
+
+ IMsg.Prim = IRLAP_DISCOVERY_CONF;
+ IMsg.IRDA_MSG_pDevList = NULL;
+ IMsg.IRDA_MSG_DscvStatus =
+ IRLAP_REMOTE_DISCOVERY_IN_PROGRESS;
+ RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
+ // fall through. Send indication to LMP
+
+ case DSCV_REPLY:
+ if (pIrlapCb->State == DSCV_REPLY)
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->QueryTimer);
+ }
+
+ // Place the device information in the control block
+ ExtractDeviceInfo(&pIrlapCb->RemoteDevice, pXIDFormat,
+ pEndDscvInfoByte);
+
+ if (!DevInDevList(pXIDFormat->SrcAddr, &pIrlapCb->DevList))
+ {
+ RetOnErr(AddDevToList(pIrlapCb,
+ pXIDFormat,
+ pEndDscvInfoByte));
+ }
+
+ // Notifiy LMP
+ IMsg.Prim = IRLAP_DISCOVERY_IND;
+ IMsg.IRDA_MSG_pDevList = &pIrlapCb->DevList;
+ RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
+ pIrlapCb->State = NDM;
+ break;
+
+ default:
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring End XID in this state")));
+ }
+ }
+ else // in middle of discovery process
+ {
+ switch (pIrlapCb->State)
+ {
+ case DSCV_MEDIA_SENSE:
+ IMsg.Prim = IRLAP_DISCOVERY_CONF;
+ IMsg.IRDA_MSG_pDevList = NULL;
+ IMsg.IRDA_MSG_DscvStatus =
+ IRLAP_REMOTE_DISCOVERY_IN_PROGRESS;
+ RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
+ // fall through
+
+ case NDM:
+ RetOnErr(InitDscvCmdProcessing(pIrlapCb, pXIDFormat));
+ pIrlapCb->State = DSCV_REPLY;
+ break;
+
+ case DSCV_QUERY:
+ IMsg.Prim = IRLAP_DISCOVERY_CONF;
+ IMsg.IRDA_MSG_pDevList = NULL;
+ IMsg.IRDA_MSG_DscvStatus = IRLAP_DISCOVERY_COLLISION;
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->SlotTimer);
+ RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
+ pIrlapCb->State = NDM;
+ break;
+
+ case DSCV_REPLY:
+ if (pXIDFormat->GenNewAddr)
+ {
+ pIrlapCb->GenNewAddr = TRUE;
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->QueryTimer);
+ RetOnErr(InitDscvCmdProcessing(pIrlapCb, pXIDFormat));
+ }
+ else
+ {
+ if (pIrlapCb->RespSlot <= pXIDFormat->SlotNo &&
+ !pIrlapCb->DscvRespSent)
+ {
+ RetOnErr(SendDscvXIDRsp(pIrlapCb));
+ pIrlapCb->DscvRespSent = TRUE;
+ }
+ }
+ break;
+
+ default:
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
+ }
+ }
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+void
+ExtractDeviceInfo(IRDA_DEVICE *pDevice, IRLAP_XID_DSCV_FORMAT *pXIDFormat,
+ BYTE *pEndDscvInfoByte)
+{
+ memcpy(pDevice->DevAddr, pXIDFormat->SrcAddr, IRDA_DEV_ADDR_LEN);
+ pDevice->IRLAP_Version = pXIDFormat->Version;
+
+ // ??? what about DscvMethod
+
+ pDevice->DscvInfoLen = pEndDscvInfoByte > &pXIDFormat->FirstDscvInfoByte ?
+ pEndDscvInfoByte-&pXIDFormat->FirstDscvInfoByte :
+ 0;
+ memcpy(pDevice->DscvInfo, &pXIDFormat->FirstDscvInfoByte,
+ pDevice->DscvInfoLen);
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+UINT
+InitDscvCmdProcessing(PIRLAP_CB pIrlapCb,
+ IRLAP_XID_DSCV_FORMAT *pXIDFormat)
+{
+ pIrlapCb->RemoteMaxSlot = IRLAP_SlotTable[pXIDFormat->NoOfSlots];
+
+ pIrlapCb->RespSlot = IRLAP_RAND(pXIDFormat->SlotNo,
+ pIrlapCb->RemoteMaxSlot - 1);
+
+ memcpy(pIrlapCb->RemoteDevice.DevAddr, pXIDFormat->SrcAddr, IRDA_DEV_ADDR_LEN);
+
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Responding in slot %d to device %02X%02X%02X%02X"),
+ pIrlapCb->RespSlot,
+ pIrlapCb->RemoteDevice.DevAddr[0],
+ pIrlapCb->RemoteDevice.DevAddr[1],
+ pIrlapCb->RemoteDevice.DevAddr[2],
+ pIrlapCb->RemoteDevice.DevAddr[3]));
+
+ if (pIrlapCb->RespSlot == pXIDFormat->SlotNo)
+ {
+ RetOnErr(SendDscvXIDRsp(pIrlapCb));
+ pIrlapCb->DscvRespSent = TRUE;
+ }
+ else
+ {
+ pIrlapCb->DscvRespSent = FALSE;
+ }
+
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->QueryTimer);
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func UINT | ProcessDscvXIDRsp | Process received XID Discovery response
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*/
+UINT
+ProcessDscvXIDRsp(PIRLAP_CB pIrlapCb,
+ IRLAP_XID_DSCV_FORMAT *pXIDFormat,
+ BYTE *pEndDscvInfoByte)
+{
+ if (pIrlapCb->State == DSCV_QUERY)
+ {
+
+ if (DevInDevList(pXIDFormat->SrcAddr, &pIrlapCb->DevList))
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->SlotTimer);
+ pIrlapCb->SlotCnt = 0;
+ pIrlapCb->GenNewAddr = TRUE;
+ ClearDevList(&pIrlapCb->DevList);
+ RetOnErr(SendDscvXIDCmd(pIrlapCb));
+
+ IMsg.Prim = MAC_CONTROL_REQ;
+ IMsg.IRDA_MSG_Op = MAC_MEDIA_SENSE;
+ IMsg.IRDA_MSG_SenseTime = IRLAP_DSCV_SENSE_TIME;
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_CONTROL_REQ (dscv sense)")));
+ RetOnErr(IrmacDown(pIrlapCb->pIrdaLinkCb,&IMsg));
+ }
+ else
+ {
+ RetOnErr(AddDevToList(pIrlapCb, pXIDFormat, pEndDscvInfoByte));
+ }
+ }
+ else
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
+ }
+
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func BOOL | DevInDevList | Determines if given device is already in list
+*
+* @rdesc returns:
+* @flag TRUE | if device is alreay in list
+* @flag FALSE | if device is not in list
+*
+* @parm BYTE | DevAddr[] | Device address
+* @parm IRDA_DEVICE * | pDevList | pointer to list of devices
+*
+*/
+BOOL
+DevInDevList(BYTE DevAddr[], LIST_ENTRY *pDevList)
+{
+ IRDA_DEVICE *pDevice;
+
+ pDevice = (IRDA_DEVICE *) pDevList->Flink;
+
+ while (pDevList != (LIST_ENTRY *) pDevice)
+ {
+ if (memcmp(pDevice->DevAddr, DevAddr, IRDA_DEV_ADDR_LEN) == 0)
+ return (TRUE);
+
+ pDevice = (IRDA_DEVICE *) pDevice->Linkage.Flink;
+ }
+ return (FALSE);
+}
+/*****************************************************************************
+*
+* @func void | AddDevToList | Adds elements in a device list
+*
+* @parm IRDA_DEVICE ** | ppDevList | address of pointer to an
+* IRDA device list
+*
+*/
+UINT
+AddDevToList(PIRLAP_CB pIrlapCb,
+ IRLAP_XID_DSCV_FORMAT *pXIDFormat,
+ BYTE *pEndDscvInfoByte)
+{
+ IRDA_DEVICE *pDevice;
+
+ if (IRDA_ALLOC_MEM(pDevice, sizeof(IRDA_DEVICE), MT_IRLAP_DEVICE) == NULL)
+ {
+ return (IRLAP_MALLOC_FAILED);
+ }
+ else
+ {
+ ExtractDeviceInfo(pDevice, pXIDFormat, pEndDscvInfoByte);
+
+ InsertTailList(&pIrlapCb->DevList, &(pDevice->Linkage));
+
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("%02X%02X%02X%02X added to Device List"),
+ EXPAND_ADDR(pDevice->DevAddr)));
+ }
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func void | ClearDevList | Frees elements in a device list
+*
+* @parm IRDA_DEVICE ** | ppDevList | address of pointer to an
+* IRDA device list
+*
+*/
+void
+ClearDevList(LIST_ENTRY *pDevList)
+{
+ IRDA_DEVICE *pDevice;
+
+ while (IsListEmpty(pDevList) == FALSE)
+ {
+ pDevice = (IRDA_DEVICE *) RemoveHeadList(pDevList);
+ IRDA_FREE_MEM(pDevice);
+ }
+
+ //IRLAP_LOG_ACTION((pIrlapCb, TEXT("Device list cleared")));
+}
+/*****************************************************************************
+*
+* @func UINT | ProcessSNRM | process received SNRM frame
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm IRLAP_SNRM_FORMAT * | pSNRMFormat | Pointer to SNRM frame
+* Information Field
+* BYTE * | pLastQosByte | Pointer to last byte in SNRM
+*
+* @comm
+* comments
+*/
+UINT
+ProcessSNRM(PIRLAP_CB pIrlapCb,
+ IRLAP_SNRM_FORMAT *pSNRMFormat,
+ BYTE *pEndQosByte)
+{
+ BOOL Qos_InSNRM = &pSNRMFormat->FirstQosByte < pEndQosByte;// Is there Qos?
+ BOOL Addrs_InSNRM = (BYTE *)pSNRMFormat < pEndQosByte;
+
+ if (Addrs_InSNRM)
+ {
+ if (!MyDevAddr(pIrlapCb, pSNRMFormat->DestAddr))
+ {
+ IRLAP_LOG_ACTION((pIrlapCb,
+ TEXT("Ignoring SNRM addressed to:%02X%02X%02X%02X"),
+ EXPAND_ADDR(pSNRMFormat->DestAddr)));
+ return SUCCESS;
+ }
+ memcpy(pIrlapCb->RemoteDevice.DevAddr,
+ pSNRMFormat->SrcAddr, IRDA_DEV_ADDR_LEN);
+ }
+
+ switch (pIrlapCb->State)
+ {
+ case DSCV_MEDIA_SENSE:
+ case DSCV_QUERY:
+ // In the middle of discovery... End discovery and reply to SNRM
+ IMsg.Prim = IRLAP_DISCOVERY_CONF;
+ IMsg.IRDA_MSG_pDevList = NULL;
+ IMsg.IRDA_MSG_DscvStatus = IRLAP_REMOTE_CONNECTION_IN_PROGRESS;
+ RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
+ // fall through and send connect indication
+ case DSCV_REPLY:
+ case NDM:
+ if (Addrs_InSNRM)
+ {
+ pIrlapCb->SNRMConnAddr = (int)IRLAP_GET_ADDR(pSNRMFormat->ConnAddr);
+ }
+ if (Qos_InSNRM)
+ {
+ ExtractQosParms(&pIrlapCb->RemoteQos, &pSNRMFormat->FirstQosByte,
+ pEndQosByte);
+
+ RetOnErr(NegotiateQosParms(pIrlapCb, &pIrlapCb->RemoteQos));
+ }
+
+ memcpy(IMsg.IRDA_MSG_RemoteDevAddr,
+ pIrlapCb->RemoteDevice.DevAddr, IRDA_DEV_ADDR_LEN);
+ IMsg.IRDA_MSG_pQOS = &pIrlapCb->NegotiatedQos;
+ IMsg.Prim = IRLAP_CONNECT_IND;
+ RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
+ pIrlapCb->State = SNRM_RECEIVED;
+ break;
+
+ case BACKOFF_WAIT: // CROSSED SNRM
+ // if Remote address greater than mine we'll respond to SNRM
+ if (Addrs_InSNRM)
+ {
+ if (memcmp(pSNRMFormat->SrcAddr,
+ pIrlapCb->LocalDevice.DevAddr, IRDA_DEV_ADDR_LEN) > 0)
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->BackoffTimer);
+ }
+ }
+ // fall through
+ case CONN_MEDIA_SENSE: // CROSSED SNRM
+ case SNRM_SENT:
+ // if Remote address greater than mine we'll respond to SNRM
+ if (Addrs_InSNRM &&
+ memcmp(pSNRMFormat->SrcAddr,
+ pIrlapCb->LocalDevice.DevAddr, IRDA_DEV_ADDR_LEN) > 0)
+ {
+ if (pIrlapCb->State != BACKOFF_WAIT)
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
+ }
+ InitializeState(pIrlapCb, SECONDARY);
+
+ if (Qos_InSNRM)
+ {
+ ExtractQosParms(&pIrlapCb->RemoteQos,
+ &pSNRMFormat->FirstQosByte, pEndQosByte);
+ RetOnErr(NegotiateQosParms(pIrlapCb,&pIrlapCb->RemoteQos));
+ }
+
+ if (Addrs_InSNRM)
+ {
+ pIrlapCb->ConnAddr = (int)IRLAP_GET_ADDR(pSNRMFormat->ConnAddr);
+ }
+
+ RetOnErr(SendUA(pIrlapCb, TRUE));
+
+ if (Qos_InSNRM)
+ {
+ RetOnErr(ApplyQosParms(pIrlapCb));
+ }
+
+ IMsg.IRDA_MSG_pQOS = &pIrlapCb->NegotiatedQos;
+ IMsg.Prim = IRLAP_CONNECT_CONF;
+ IMsg.IRDA_MSG_ConnStatus = IRLAP_CONNECTION_COMPLETED;
+ RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
+
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
+ pIrlapCb->State = S_NRM;
+ }
+ break;
+
+ case P_RECV:
+ case P_DISCONNECT_PEND:
+ case P_CLOSE:
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
+ RetOnErr(StationConflict(pIrlapCb));
+ RetOnErr(ReturnTxMsgs(pIrlapCb));
+ if (pIrlapCb->State == P_CLOSE)
+ {
+ RetOnErr(GotoNDMThenDscvOrConn(pIrlapCb));
+ }
+ else
+ {
+ pIrlapCb->State = NDM;
+ }
+ break;
+
+ case S_NRM:
+ case S_CLOSE:
+ case S_DISCONNECT_PEND:
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
+ RetOnErr(SendDM(pIrlapCb));
+ RetOnErr(ApplyDefaultParms(pIrlapCb));
+ IMsg.Prim = IRLAP_DISCONNECT_IND;
+ if (pIrlapCb->State == S_NRM)
+ {
+ IMsg.IRDA_MSG_DiscStatus = IRLAP_DECLINE_RESET;
+ }
+ else
+ {
+ IMsg.IRDA_MSG_DiscStatus = IRLAP_DISCONNECT_COMPLETED;
+ }
+ RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
+ pIrlapCb->State = NDM;
+ break;
+
+ case S_ERROR:
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
+ RetOnErr(SendFRMR(pIrlapCb, &FrmRejFormat));
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
+ pIrlapCb->State = S_NRM;
+ break;
+
+ default:
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("SNRM ignored in this state")));
+ }
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func UINT | ProcessUA | process received UA frame
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm IRLAP_UA_FORMAT * | pUAFormat | Pointer to UA frame
+* Information Field
+* BYTE * | pLastQosByte | Pointer to last byte in SNRM
+*
+* @comm
+* When &pUAFormat->FirstQosByte = pLastQosByte there is no Qos in UA
+*/
+UINT
+ProcessUA(PIRLAP_CB pIrlapCb,
+ IRLAP_UA_FORMAT *pUAFormat,
+ BYTE *pEndQosByte)
+{
+ BOOL Qos_InUA = &pUAFormat->FirstQosByte < pEndQosByte;// Is there QOS?
+ BOOL Addrs_InUA = (BYTE *)pUAFormat < pEndQosByte;
+ int Tmp;
+
+ if (Addrs_InUA && !MyDevAddr(pIrlapCb, pUAFormat->DestAddr))
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring UA addressed to:%02X%02X%02X%02X"),
+ EXPAND_ADDR(pUAFormat->DestAddr)));
+ return SUCCESS;
+ }
+
+ switch (pIrlapCb->State)
+ {
+ case BACKOFF_WAIT:
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->BackoffTimer);
+ // fall through
+ case SNRM_SENT:
+ if (pIrlapCb->State != BACKOFF_WAIT)
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
+ }
+
+ InitializeState(pIrlapCb, PRIMARY);
+
+ if (Qos_InUA)
+ {
+ ExtractQosParms(&pIrlapCb->RemoteQos, &pUAFormat->FirstQosByte,
+ pEndQosByte);
+
+ RetOnErr(NegotiateQosParms(pIrlapCb,&pIrlapCb->RemoteQos));
+
+ RetOnErr(ApplyQosParms(pIrlapCb));
+ }
+
+ IMsg.IRDA_MSG_pQOS = &pIrlapCb->NegotiatedQos;
+
+ IMsg.Prim = IRLAP_CONNECT_CONF;
+ IMsg.IRDA_MSG_ConnStatus = IRLAP_CONNECTION_COMPLETED;
+
+ // notify LMP of connection
+ RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
+
+ // send RR (turn link), start FinalTimer/2
+ RetOnErr(SendRR_RNR(pIrlapCb));
+
+ Tmp = pIrlapCb->FinalTimer.Timeout;
+ pIrlapCb->FinalTimer.Timeout = pIrlapCb->FinalTimer.Timeout/2;
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ pIrlapCb->FinalTimer.Timeout = Tmp;
+
+ pIrlapCb->State = P_RECV;
+ break;
+
+ case P_RECV: // Unsolicited UA, may want to do something else ???
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->PollTimer);
+ pIrlapCb->State = P_XMIT;
+ break;
+
+ case P_DISCONNECT_PEND:
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
+ RetOnErr(SendDISC(pIrlapCb));
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ pIrlapCb->RetryCnt = 0;
+ RetOnErr(GotoPCloseState(pIrlapCb));
+ break;
+
+ case P_CLOSE:
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
+ RetOnErr(ApplyDefaultParms(pIrlapCb));
+ if (pIrlapCb->LocalDiscReq == TRUE)
+ {
+ pIrlapCb->LocalDiscReq = FALSE;
+ IMsg.Prim = IRLAP_DISCONNECT_IND;
+ IMsg.IRDA_MSG_DiscStatus = IRLAP_DISCONNECT_COMPLETED;
+ RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
+ }
+ RetOnErr(GotoNDMThenDscvOrConn(pIrlapCb));
+ break;
+
+ case S_NRM:
+ case S_DISCONNECT_PEND:
+ case S_ERROR:
+ case S_CLOSE:
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
+ RetOnErr(StationConflict(pIrlapCb));
+ pIrlapCb->State = NDM;
+ break;
+
+ default:
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("UA ignored in this state")));
+ }
+
+ return SUCCESS;
+}
+
+BYTE *
+GetPv(BYTE *pQosByte,
+ UINT *pBitField)
+{
+ int Pl = (int) *pQosByte++;
+
+ *pBitField = 0;
+
+ if (Pl == 1)
+ {
+ *pBitField = (UINT) *pQosByte;
+ }
+ else
+ {
+ *pBitField = ((UINT) *pQosByte)<<8;
+ *pBitField |= (UINT) *(pQosByte+1);
+ }
+
+ return pQosByte + Pl;
+}
+/*****************************************************************************
+*
+* @func void | ExtractQosParms | Extracts Qos from SNRM/UA/XID and
+* places in an IRDA_QOS_PARM struct
+*
+* @parm IRDA_QOS_PARMS * | pIRDA_QOSParms | Pointer to QOS parm struct
+* BYTE * | pQOSByte | Pointer to first byte of
+* QOS in frame
+* BYTE * | pEndQOSByte | Pointer to last byte of
+* QOS in frame
+* @comm
+* THIS WILL BREAK IF PARAMETER LENGTH (PL) IS GREATER THAN 2
+*/
+void
+ExtractQosParms(IRDA_QOS_PARMS *pQos,
+ BYTE *pQosByte,
+ BYTE *pEndQosByte)
+{
+ while (pQosByte + 2 < pEndQosByte)
+ {
+ switch (*pQosByte)
+ {
+ case QOS_PI_BAUD:
+ pQosByte = GetPv(pQosByte, &pQos->bfBaud);
+ break;
+
+ case QOS_PI_MAX_TAT:
+ pQosByte = GetPv(pQosByte, &pQos->bfMaxTurnTime);
+ break;
+
+ case QOS_PI_DATA_SZ:
+ pQosByte = GetPv(pQosByte, &pQos->bfDataSize);
+ break;
+
+ case QOS_PI_WIN_SZ:
+ pQosByte = GetPv(pQosByte, &pQos->bfWindowSize);
+ break;
+
+ case QOS_PI_BOFS:
+ pQosByte = GetPv(pQosByte, &pQos->bfBofs);
+ break;
+
+ case QOS_PI_MIN_TAT:
+ pQosByte = GetPv(pQosByte, &pQos->bfMinTurnTime);
+ break;
+
+ case QOS_PI_DISC_THRESH:
+ pQosByte = GetPv(pQosByte, &pQos->bfDisconnectTime);
+ break;
+
+ default:
+ pQosByte += (*(pQosByte+1));
+ }
+ }
+}
+/*****************************************************************************
+*
+* @func UINT | NegotiateQosParms | Take the received Qos build
+* negotiated Qos.
+*
+* @rdesc SUCCESS, otherwise one of the folowing:
+* @flag IRLAP_BAUD_NEG_ERR | Failed to negotiate baud
+* @flag IRLAP_DISC_NEG_ERR | Failed to negotiate disconnect time
+* @flag IRLAP_MAXTAT_NEG_ERR | Failed to negotiate max turn time
+* @flag IRLAP_DATASIZE_NEG_ERR | Failed to negotiate data size
+* @flag IRLAP_WINSIZE_NEG_ERR | Failed to negotiate window size
+* @flag IRLAP_BOFS_NEG_ERR | Failed to negotiate number of BOFS
+* @flag IRLAP_WINSIZE_NEG_ERR | Failed to window size
+* @flag IRLAP_LINECAP_ERR | Failed to determine valid line capacity
+*
+* @parm IRDA_QOS_PARMS * | pRemoteQos | Pointer to QOS parm struct
+*/
+UINT
+NegotiateQosParms(PIRLAP_CB pIrlapCb,
+ IRDA_QOS_PARMS *pRemoteQos)
+{
+ UINT BitSet;
+ BOOL ParmSet = FALSE;
+ UINT BOFSDivisor = 1;
+ UINT MaxLineCap = 0;
+ UINT LineCapacity;
+ UINT DataSizeBit = 0;
+ UINT WinSizeBit = 0;
+ UINT WSBit;
+ int RemoteDataSize = 0;
+ int RemoteWinSize = 0;
+
+ // Baud rate is Type 0 parm
+ pIrlapCb->Baud = IrlapGetQosParmVal(vBaudTable,
+ (BYTE) (pIrlapCb->LocalQos.bfBaud & pRemoteQos->bfBaud),
+ &BitSet);
+ BOFSDivisor = IrlapGetQosParmVal(vBOFSDivTable,
+ (BYTE) (pIrlapCb->LocalQos.bfBaud & pRemoteQos->bfBaud),
+ &BitSet);
+ pIrlapCb->NegotiatedQos.bfBaud = BitSet;
+
+ if (-1 == pIrlapCb->Baud)
+ {
+ return (IRLAP_BAUD_NEG_ERR);
+ }
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Negotiated Baud:%d"), pIrlapCb->Baud));
+
+ // Disconnect/Threshold time is Type 0 parm
+ pIrlapCb->DisconnectTime = IrlapGetQosParmVal(vDiscTable,
+ (BYTE)(pIrlapCb->LocalQos.bfDisconnectTime &
+ pRemoteQos->bfDisconnectTime), &BitSet);
+ pIrlapCb->ThresholdTime = IrlapGetQosParmVal(vThreshTable,
+ (BYTE)(pIrlapCb->LocalQos.bfDisconnectTime &
+ pRemoteQos->bfDisconnectTime), &BitSet);
+ pIrlapCb->NegotiatedQos.bfDisconnectTime = BitSet;
+
+ if (-1 == pIrlapCb->DisconnectTime)
+ {
+ return (IRLAP_DISC_NEG_ERR);
+ }
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Negotiated Disconnect/Threshold time:%d/%d"),
+ pIrlapCb->DisconnectTime, pIrlapCb->ThresholdTime));
+
+ pIrlapCb->RemoteMaxTAT = IrlapGetQosParmVal(vMaxTATTable,
+ pRemoteQos->bfMaxTurnTime,
+ &BitSet);
+ pIrlapCb->NegotiatedQos.bfMaxTurnTime = BitSet;
+ if (-1 == pIrlapCb->RemoteMaxTAT)
+ {
+ return (IRLAP_MAXTAT_NEG_ERR);
+ }
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Remote max turnaround time:%d"),
+ pIrlapCb->RemoteMaxTAT));
+
+ pIrlapCb->RemoteMinTAT = IrlapGetQosParmVal(vMinTATTable,
+ pRemoteQos->bfMinTurnTime,
+ &BitSet);
+ pIrlapCb->NegotiatedQos.bfMinTurnTime = BitSet;
+ if (-1 == pIrlapCb->RemoteMinTAT)
+ {
+ return (IRLAP_MINTAT_NEG_ERR);
+ }
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Remote min turnaround time:%d"),
+ pIrlapCb->RemoteMinTAT));
+
+ // DataSize ISNOT A TYPE 0 PARAMETER. BUT WIN95's IRCOMM implementation
+ // ASSUMES THAT IT IS. SO FOR NOW, NEGOTIATE IT. grrrr..
+ /* WIN95 out
+ pIrlapCb->RemoteDataSize = IrlapGetQosParmVal(vDataSizeTable,
+ (BYTE) (pIrlapCb->LocalQos.bfDataSize &
+ pRemoteQos->bfDataSize), &BitSet);
+ */
+ pIrlapCb->RemoteDataSize = IrlapGetQosParmVal(vDataSizeTable,
+ pRemoteQos->bfDataSize, &BitSet);
+ DataSizeBit = BitSet;
+ pIrlapCb->NegotiatedQos.bfDataSize = BitSet;
+ if (-1 == pIrlapCb->RemoteDataSize)
+ {
+ return (IRLAP_DATASIZE_NEG_ERR);
+ }
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Remote data size:%d"), pIrlapCb->RemoteDataSize));
+
+ pIrlapCb->RemoteWinSize = IrlapGetQosParmVal(vWinSizeTable,
+ pRemoteQos->bfWindowSize, &BitSet);
+ WinSizeBit = BitSet;
+ pIrlapCb->NegotiatedQos.bfWindowSize = BitSet;
+ if (-1 == pIrlapCb->RemoteWinSize)
+ {
+ return (IRLAP_WINSIZE_NEG_ERR);
+ }
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Remote window size:%d"), pIrlapCb->RemoteWinSize));
+
+ pIrlapCb->RemoteNumBOFS=(IrlapGetQosParmVal(vBOFSTable,
+ pRemoteQos->bfBofs, &BitSet)
+ / BOFSDivisor)+1;
+ pIrlapCb->NegotiatedQos.bfBofs = BitSet;
+ if (-1 == pIrlapCb->RemoteNumBOFS)
+ {
+ return (IRLAP_BOFS_NEG_ERR);
+ }
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Remote number of BOFS:%d"),
+ pIrlapCb->RemoteNumBOFS));
+
+ // The maximum line capacity is in bytes and comes from a table in spec.
+ // (can't calc because table isn't linear). It is determined by the
+ // maximum line capacity and baud rate.
+ //
+ // Later note: Errata corrected table so values could be calculated.
+ // Could get rid of tables
+ switch (pIrlapCb->Baud)
+ {
+ case 9600:
+ MaxLineCap = IrlapGetQosParmVal(MAXCAP_9600,
+ pRemoteQos->bfMaxTurnTime, &BitSet);
+ break;
+
+ case 19200:
+ MaxLineCap = IrlapGetQosParmVal(MAXCAP_19200,
+ pRemoteQos->bfMaxTurnTime, &BitSet);
+ break;
+
+ case 38400:
+ MaxLineCap = IrlapGetQosParmVal(MAXCAP_38400,
+ pRemoteQos->bfMaxTurnTime, &BitSet);
+ break;
+
+ case 57600:
+ MaxLineCap = IrlapGetQosParmVal(MAXCAP_57600,
+ pRemoteQos->bfMaxTurnTime, &BitSet);
+ break;
+
+ case 115200:
+ MaxLineCap = IrlapGetQosParmVal(MAXCAP_115200,
+ pRemoteQos->bfMaxTurnTime, &BitSet);
+ break;
+ }
+
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Maximum line capacity:%d"), MaxLineCap));
+ LineCapacity = LINE_CAPACITY(pIrlapCb);
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Requested line capacity:%d"), LineCapacity));
+
+ if (LineCapacity > MaxLineCap)
+ {
+ ParmSet = FALSE;
+ // Adjust data and window size to fit within the line capacity.
+ // Get largest possible datasize
+ for (; DataSizeBit != 0 && !ParmSet; DataSizeBit >>= 1)
+ {
+ pIrlapCb->RemoteDataSize = IrlapGetQosParmVal(vDataSizeTable,
+ DataSizeBit, NULL);
+ // Start with smallest window
+ for (WSBit=1; WSBit <= WinSizeBit; WSBit <<=1)
+ {
+ pIrlapCb->RemoteWinSize = IrlapGetQosParmVal(vWinSizeTable,
+ WSBit, NULL);
+ LineCapacity = LINE_CAPACITY(pIrlapCb);
+
+ IRLAP_LOG_ACTION((pIrlapCb,
+ TEXT("adjusted data size=%d, window size= %d, line cap=%d"),
+ pIrlapCb->RemoteDataSize, pIrlapCb->RemoteWinSize,
+ LineCapacity));
+
+ if (LineCapacity > MaxLineCap)
+ {
+ break; // Get a smaller data size (only if ParmSet is false)
+ }
+ ParmSet = TRUE;
+ // Save the last good one,then loop and try a larger window
+ RemoteDataSize = pIrlapCb->RemoteDataSize;
+ RemoteWinSize = pIrlapCb->RemoteWinSize;
+ pIrlapCb->NegotiatedQos.bfWindowSize = WSBit;
+ pIrlapCb->NegotiatedQos.bfDataSize = DataSizeBit;
+ }
+ }
+ if (!ParmSet)
+ {
+ return (IRLAP_LINECAP_ERR);
+ }
+
+ pIrlapCb->RemoteDataSize = RemoteDataSize;
+ pIrlapCb->RemoteWinSize = RemoteWinSize;
+
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("final data size=%d, window size= %d, line cap=%d"),
+ pIrlapCb->RemoteDataSize, pIrlapCb->RemoteWinSize,
+ LINE_CAPACITY(pIrlapCb)));
+ }
+
+ return (SUCCESS);
+}
+/*****************************************************************************
+*
+* @func UINT | ApplyQosParms | Apply negotiated Qos in control block
+*
+* @rdesc return status from IrmacDown()
+*/
+UINT
+ApplyQosParms(PIRLAP_CB pIrlapCb)
+{
+ // convert disconnect/threshold time to ms and divide by turn around time
+ // to get number of retries
+ pIrlapCb->N1 = pIrlapCb->ThresholdTime * 1000 / pIrlapCb->RemoteMaxTAT;
+ pIrlapCb->N2 = pIrlapCb->DisconnectTime * 1000 / pIrlapCb->RemoteMaxTAT;
+
+ // hmmmm...???
+ pIrlapCb->PollTimer.Timeout = pIrlapCb->RemoteMaxTAT;
+ pIrlapCb->FinalTimer.Timeout = pIrlapCb->LocalMaxTAT;
+
+ IMsg.Prim = MAC_CONTROL_REQ;
+ IMsg.IRDA_MSG_Op = MAC_RECONFIG_LINK;
+ IMsg.IRDA_MSG_Baud = pIrlapCb->Baud;
+ IMsg.IRDA_MSG_NumBOFs = pIrlapCb->RemoteNumBOFS; // Number of BOFS
+ // to add to tx
+ IMsg.IRDA_MSG_DataSize = pIrlapCb->RemoteDataSize; // Max rx size packet
+ // causes major heap
+ // problems later
+ IMsg.IRDA_MSG_MinTat = pIrlapCb->RemoteMinTAT;
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Reconfig link for Baud:%d, Local data size:%d, Remote BOFS:%d"), pIrlapCb->Baud, pIrlapCb->LocalDataSize, pIrlapCb->RemoteNumBOFS));
+
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Retry counts N1=%d, N2=%d"), pIrlapCb->N1, pIrlapCb->N2));
+ return (IrmacDown(pIrlapCb->pIrdaLinkCb,&IMsg));
+}
+/*****************************************************************************
+*
+* @func UINT | IrlapGetQosParmVal |
+* retrieves the parameters value from table
+*
+* @rdesc value contained in parmeter value table, 0 if not found
+* (0 is a valid parameter in some tables though)
+*
+* @parm UINT [] | PVTable | table containing parm values
+* USHORT | BitField | contains bit indicating which parm to select
+*
+* @comm
+*/
+UINT
+IrlapGetQosParmVal(UINT PVTable[], UINT BitField, UINT *pBitSet)
+{
+ int i;
+ UINT Mask;
+
+ for (i = PV_TABLE_MAX_BIT, Mask = (1<<PV_TABLE_MAX_BIT);
+ Mask > 0; i--, Mask = Mask >> 1)
+ {
+ if (Mask & BitField)
+ {
+ if (pBitSet != NULL)
+ {
+ *pBitSet = Mask;
+ }
+ return (PVTable[i]);
+ }
+ }
+ return (UINT) -1;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+UINT
+ProcessTEST(PIRLAP_CB pIrlapCb,
+ PIRDA_MSG pMsg,
+ IRLAP_UA_FORMAT *pTestFormat,
+ int CRBit,
+ int PFBit)
+{
+ BYTE TmpAddr[IRDA_DEV_ADDR_LEN];
+
+ if (!MyDevAddr(pIrlapCb, pTestFormat->DestAddr))
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring XID addressed to:%02X%02X%02X%02X"),
+ EXPAND_ADDR(pTestFormat->DestAddr)));
+ return SUCCESS;
+ }
+
+ if (IRLAP_CMD == CRBit && IRLAP_PFBIT_SET == PFBit)
+ {
+ // bounce it back
+ memcpy(TmpAddr,pTestFormat->SrcAddr, IRDA_DEV_ADDR_LEN);
+ memcpy(pTestFormat->SrcAddr, pTestFormat->DestAddr, IRDA_DEV_ADDR_LEN);
+ memcpy(pTestFormat->DestAddr, TmpAddr, IRDA_DEV_ADDR_LEN);
+ *(pMsg->IRDA_MSG_pRead) ^= 1; // swap cr bit
+ return SendFrame(pIrlapCb, pMsg);
+ }
+ else
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring")));
+ }
+
+ // Not implementing TEST responses for now
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+UINT
+ProcessUI(PIRLAP_CB pIrlapCb,
+ PIRDA_MSG pMsg,
+ int CRBit,
+ int PFBit)
+{
+ BOOL LinkTurned = TRUE;
+
+ pMsg->IRDA_MSG_pRead += 2; // chop the IRLAP header
+
+ switch (pIrlapCb->State)
+ {
+ case NDM:
+ case DSCV_MEDIA_SENSE:
+ case DSCV_QUERY:
+ case DSCV_REPLY:
+ case CONN_MEDIA_SENSE:
+ case SNRM_SENT:
+ case BACKOFF_WAIT:
+ case SNRM_RECEIVED:
+ pMsg->Prim = IRLAP_UDATA_IND;
+ return (IrlmpUp(pIrlapCb->pIrdaLinkCb, pMsg));
+
+ case P_XMIT:
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
+ return SUCCESS;
+ }
+
+ if (PRIMARY == pIrlapCb->StationType)
+ {
+ // stop timers if PF bit set or invalid CRBit (matches mine)
+ if (IRLAP_PFBIT_SET == PFBit || pIrlapCb->CRBit == CRBit)
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
+ }
+ }
+ else
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
+ }
+
+ if (pIrlapCb->CRBit == CRBit)
+ {
+ RetOnErr(StationConflict(pIrlapCb));
+ pIrlapCb->State = NDM;
+ return SUCCESS;
+ }
+
+ // Send the Unnumber information to LMP
+ pMsg->Prim = IRLAP_UDATA_IND;
+ RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, pMsg));
+
+ if (IRLAP_PFBIT_SET == PFBit)
+ {
+ switch (pIrlapCb->State)
+ {
+ case P_RECV:
+ RetOnErr(XmitTxMsgList(pIrlapCb, FALSE, &LinkTurned));
+ break;
+
+ case P_DISCONNECT_PEND:
+ RetOnErr(SendDISC(pIrlapCb));
+ pIrlapCb->RetryCnt = 0;
+ RetOnErr(GotoPCloseState(pIrlapCb));
+ break;
+
+ case P_CLOSE:
+ RetOnErr(ResendDISC(pIrlapCb));
+ break;
+
+ case S_NRM:
+ RetOnErr(XmitTxMsgList(pIrlapCb, TRUE, NULL));
+ break;
+
+ case S_DISCONNECT_PEND:
+ RetOnErr(SendRD(pIrlapCb));
+ pIrlapCb->State = S_CLOSE;
+ break;
+
+ case S_ERROR:
+ RetOnErr(SendFRMR(pIrlapCb, &FrmRejFormat));
+ pIrlapCb->State = S_NRM;
+ break;
+
+ case S_CLOSE:
+ RetOnErr(SendRD(pIrlapCb));
+ }
+ }
+
+ if (PRIMARY == pIrlapCb->StationType)
+ {
+ if (IRLAP_PFBIT_SET == PFBit && pIrlapCb->State != NDM)
+ {
+ if (LinkTurned)
+ {
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ }
+ else
+ {
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->PollTimer);
+ pIrlapCb->State = P_XMIT;
+ }
+ }
+ }
+ else
+ {
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
+ }
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+UINT
+ProcessDM(PIRLAP_CB pIrlapCb)
+{
+ BOOL LinkTurned;
+
+ switch (pIrlapCb->State)
+ {
+ case NDM:
+ case DSCV_MEDIA_SENSE:
+ case DSCV_QUERY:
+ case DSCV_REPLY:
+ case CONN_MEDIA_SENSE:
+ case BACKOFF_WAIT:
+ case SNRM_RECEIVED:
+ case P_XMIT:
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
+ return TRUE;
+ }
+
+ if (PRIMARY != pIrlapCb->StationType)
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
+ RetOnErr(StationConflict(pIrlapCb));
+ pIrlapCb->State = NDM;
+ return SUCCESS;
+ }
+
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
+
+ switch (pIrlapCb->State)
+ {
+ case P_RECV: // I'm not sure why I am doing this ???
+ RetOnErr(XmitTxMsgList(pIrlapCb, FALSE, &LinkTurned));
+ if (LinkTurned)
+ {
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ }
+ else
+ {
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->PollTimer);
+ pIrlapCb->State = P_XMIT;
+ }
+ break;
+
+ case P_DISCONNECT_PEND:
+ pIrlapCb->RetryCnt = 0;
+ RetOnErr(SendDISC(pIrlapCb));
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ RetOnErr(GotoPCloseState(pIrlapCb));
+ break;
+
+ case SNRM_SENT:
+ case P_CLOSE:
+ RetOnErr(ApplyDefaultParms(pIrlapCb));
+ IMsg.Prim = IRLAP_DISCONNECT_IND;
+ if (pIrlapCb->State == P_CLOSE)
+ {
+ IMsg.IRDA_MSG_DiscStatus = IRLAP_DISCONNECT_COMPLETED;
+ }
+ else
+ {
+ IMsg.IRDA_MSG_DiscStatus = IRLAP_REMOTE_INITIATED;
+ }
+ if (pIrlapCb->LocalDiscReq || pIrlapCb->State == SNRM_SENT)
+ {
+ pIrlapCb->LocalDiscReq = FALSE;
+ RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
+ }
+
+ if (pIrlapCb->State == P_CLOSE)
+ {
+ return GotoNDMThenDscvOrConn(pIrlapCb);
+ }
+
+ pIrlapCb->State = NDM;
+ break;
+ }
+
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+UINT
+ProcessDISC(PIRLAP_CB pIrlapCb)
+{
+ if (IgnoreState(pIrlapCb))
+ {
+ return SUCCESS;
+ }
+
+ if (SECONDARY != pIrlapCb->StationType)
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
+ RetOnErr(StationConflict(pIrlapCb));
+ pIrlapCb->State = NDM;
+ return SUCCESS;
+ }
+
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
+
+ // Acknowledge primary's disconnect request
+ RetOnErr(SendUA(pIrlapCb, FALSE /* No Qos */));
+ RetOnErr(ApplyDefaultParms(pIrlapCb));
+
+ RetOnErr(ReturnTxMsgs(pIrlapCb));
+
+ // notify LMP of disconnect
+ IMsg.Prim = IRLAP_DISCONNECT_IND;
+ if (pIrlapCb->LocalDiscReq)
+ {
+ IMsg.IRDA_MSG_DiscStatus = IRLAP_DISCONNECT_COMPLETED;
+ pIrlapCb->LocalDiscReq = FALSE;
+ }
+ else
+ {
+ IMsg.IRDA_MSG_DiscStatus = IRLAP_REMOTE_INITIATED;
+ }
+
+ RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
+
+ pIrlapCb->State = NDM;
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+UINT
+ProcessRD(PIRLAP_CB pIrlapCb)
+{
+ if (IgnoreState(pIrlapCb))
+ {
+ return SUCCESS;
+ }
+
+ if (PRIMARY != pIrlapCb->StationType)
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
+ RetOnErr(StationConflict(pIrlapCb));
+ pIrlapCb->State = NDM;
+ return SUCCESS;
+ }
+
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
+
+ if (pIrlapCb->State == P_CLOSE)
+ {
+ RetOnErr(ResendDISC(pIrlapCb));
+ }
+ else
+ {
+ RetOnErr(ReturnTxMsgs(pIrlapCb));
+ pIrlapCb->RetryCnt = 0;
+ RetOnErr(SendDISC(pIrlapCb));
+ RetOnErr(GotoPCloseState(pIrlapCb));
+ }
+ if (pIrlapCb->State != NDM)
+ {
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ }
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+UINT
+ProcessFRMR(PIRLAP_CB pIrlapCb)
+{
+ if (IgnoreState(pIrlapCb))
+ {
+ return SUCCESS;
+ }
+
+ if (PRIMARY != pIrlapCb->StationType)
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
+ RetOnErr(StationConflict(pIrlapCb));
+ pIrlapCb->State = NDM;
+ return SUCCESS;
+ }
+
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
+
+ switch (pIrlapCb->State)
+ {
+ case P_RECV:
+ RetOnErr(ReturnTxMsgs(pIrlapCb));
+ // fall through
+
+ case P_DISCONNECT_PEND:
+ pIrlapCb->RetryCnt = 0;
+ RetOnErr(SendDISC(pIrlapCb));
+ RetOnErr(GotoPCloseState(pIrlapCb));
+ break;
+
+ case P_CLOSE:
+ RetOnErr(ResendDISC(pIrlapCb));
+ break;
+ }
+
+ if (pIrlapCb->State != NDM)
+ {
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ }
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+UINT
+ProcessRNRM(PIRLAP_CB pIrlapCb)
+{
+ if (IgnoreState(pIrlapCb))
+ {
+ return SUCCESS;
+ }
+
+ if (PRIMARY != pIrlapCb->StationType)
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
+ RetOnErr(StationConflict(pIrlapCb));
+ pIrlapCb->State = NDM;
+ return SUCCESS;
+ }
+
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
+
+ switch (pIrlapCb->State)
+ {
+ case P_RECV:
+ case P_DISCONNECT_PEND:
+ pIrlapCb->RetryCnt = 0;
+ RetOnErr(SendDISC(pIrlapCb));
+ RetOnErr(GotoPCloseState(pIrlapCb));
+ break;
+
+ case P_CLOSE:
+ RetOnErr(ResendDISC(pIrlapCb));
+ break;
+ }
+
+ if (pIrlapCb->State != NDM)
+ {
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ }
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+UINT
+ProcessREJ_SREJ(PIRLAP_CB pIrlapCb,
+ int FrameType,
+ PIRDA_MSG pMsg,
+ int CRBit,
+ int PFBit,
+ UINT Nr)
+{
+ if (IgnoreState(pIrlapCb))
+ {
+ return SUCCESS;
+ }
+
+ if (PRIMARY == pIrlapCb->StationType)
+ {
+ // stop timers if PF bit set or invalid CRBit (matches mine)
+ if (IRLAP_PFBIT_SET == PFBit || pIrlapCb->CRBit == CRBit)
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
+ }
+ }
+ else
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
+ }
+
+ if (pIrlapCb->CRBit == CRBit)
+ {
+ RetOnErr(StationConflict(pIrlapCb));
+ pIrlapCb->State = NDM;
+ return SUCCESS;
+ }
+
+ switch (pIrlapCb->State)
+ {
+ case P_RECV:
+ case S_NRM:
+ if (IRLAP_PFBIT_SET == PFBit)
+ {
+ if (InvalidNr(pIrlapCb,Nr) || Nr == pIrlapCb->TxWin.End)
+ {
+ RetOnErr(ProcessInvalidNr(pIrlapCb, PFBit));
+ }
+ else
+ {
+ RetOnErr(FreeAckedTxMsgs(pIrlapCb, Nr));
+ if (FrameType == IRLAP_REJ)
+ {
+ RetOnErr(ResendRejects(pIrlapCb, Nr)); // link turned here
+ }
+ else // selective reject
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("RETRANSMISSION:")));
+ RetOnErr(SendIFrame(pIrlapCb,
+ pIrlapCb->TxWin.pMsg[Nr],
+ Nr, IRLAP_PFBIT_SET));
+ }
+ }
+ }
+ break;
+
+ case P_DISCONNECT_PEND:
+ if (IRLAP_PFBIT_SET == PFBit)
+ {
+ pIrlapCb->RetryCnt = 0;
+ RetOnErr(SendDISC(pIrlapCb));
+ RetOnErr(GotoPCloseState(pIrlapCb));
+ }
+ break;
+
+ case P_CLOSE:
+ if (IRLAP_PFBIT_SET == PFBit)
+ {
+ RetOnErr(ResendDISC(pIrlapCb));
+ }
+ break;
+
+ case S_DISCONNECT_PEND:
+ if (IRLAP_PFBIT_SET == PFBit)
+ {
+ RetOnErr(SendRD(pIrlapCb));
+ pIrlapCb->State = S_CLOSE;
+ }
+ break;
+
+ case S_ERROR:
+ if (IRLAP_PFBIT_SET == PFBit)
+ {
+ RetOnErr(SendFRMR(pIrlapCb, &FrmRejFormat));
+ pIrlapCb->State = S_NRM;
+ }
+ break;
+
+ case S_CLOSE:
+ if (IRLAP_PFBIT_SET == PFBit)
+ {
+ RetOnErr(SendRD(pIrlapCb));
+ }
+ break;
+
+ }
+ if (PRIMARY == pIrlapCb->StationType)
+ {
+ if (IRLAP_PFBIT_SET == PFBit && pIrlapCb->State != NDM)
+ {
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ }
+ }
+ else
+ {
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
+ }
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+UINT
+ProcessRR_RNR(PIRLAP_CB pIrlapCb,
+ int FrameType,
+ PIRDA_MSG pMsg,
+ int CRBit,
+ int PFBit,
+ UINT Nr)
+{
+ BOOL LinkTurned = TRUE;
+
+ if (IgnoreState(pIrlapCb))
+ {
+ return SUCCESS;
+ }
+
+ if (PRIMARY == pIrlapCb->StationType)
+ {
+ // stop timers if PF bit set or invalid CRBit (matches mine)
+ if (IRLAP_PFBIT_SET == PFBit || pIrlapCb->CRBit == CRBit)
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
+ }
+ }
+ else // SECONDARY, restart WDog
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
+ if (pIrlapCb->CRBit != CRBit)
+ {
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
+ }
+ }
+
+ if (pIrlapCb->CRBit == CRBit)
+ {
+ RetOnErr(StationConflict(pIrlapCb));
+ pIrlapCb->State = NDM;
+ return SUCCESS;
+ }
+
+ if (FrameType == IRLAP_RR)
+ {
+ pIrlapCb->RemoteBusy = FALSE;
+ }
+ else // RNR
+ {
+ pIrlapCb->RemoteBusy = TRUE;
+ }
+
+ switch (pIrlapCb->State)
+ {
+ case P_RECV:
+ case S_NRM:
+ if (PFBit == IRLAP_PFBIT_SET)
+ {
+ if (InvalidNr(pIrlapCb, Nr))
+ {
+ RetOnErr(ProcessInvalidNr(pIrlapCb, PFBit));
+ }
+ else
+ {
+ RetOnErr(FreeAckedTxMsgs(pIrlapCb,Nr));
+
+ if (Nr != pIrlapCb->Vs) // Implicit reject
+ {
+ if (PRIMARY == pIrlapCb->StationType &&
+ IRLAP_RNR == FrameType)
+ {
+ LinkTurned = FALSE;
+ }
+ else
+ {
+ RetOnErr(ResendRejects(pIrlapCb,
+ Nr)); // always turns link
+ }
+ }
+ else
+ {
+ if (pIrlapCb->Vr != pIrlapCb->RxWin.End)
+ {
+ RetOnErr(MissingRxFrames(pIrlapCb)); // Send SREJ or REJ
+ }
+ else
+ {
+ if (PRIMARY == pIrlapCb->StationType)
+ {
+ LinkTurned = FALSE;
+ if (IRLAP_RR == FrameType)
+ {
+ RetOnErr(XmitTxMsgList(pIrlapCb,
+ FALSE, &LinkTurned));
+ }
+ }
+ else
+ {
+ // Always turn link if secondary
+ // with data or an RR if remote is busy
+ if (IRLAP_RR == FrameType)
+ {
+ RetOnErr(XmitTxMsgList(pIrlapCb, TRUE, NULL));
+ }
+ else
+ {
+ RetOnErr(SendRR_RNR(pIrlapCb));
+ }
+ }
+ }
+ }
+ }
+ // If the link was turned, restart Final timer,
+ // else start the Poll timer and enter the transmit state
+ if (PRIMARY == pIrlapCb->StationType)
+ {
+ if (LinkTurned)
+ {
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ }
+ else
+ {
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->PollTimer);
+ pIrlapCb->State = P_XMIT;
+ }
+ }
+ }
+ break;
+
+ case P_DISCONNECT_PEND:
+ RetOnErr(SendDISC(pIrlapCb));
+ pIrlapCb->RetryCnt = 0;
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ RetOnErr(GotoPCloseState(pIrlapCb));
+ break;
+
+ case P_CLOSE:
+ RetOnErr(ResendDISC(pIrlapCb));
+ if (pIrlapCb->State != NDM)
+ {
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ }
+ break;
+
+ case S_DISCONNECT_PEND:
+ case S_CLOSE:
+ if (IRLAP_PFBIT_SET == PFBit)
+ {
+ RetOnErr(SendRD(pIrlapCb));
+ if (pIrlapCb->State != S_CLOSE)
+ pIrlapCb->State = S_CLOSE;
+ }
+ break;
+
+ case S_ERROR:
+ if (IRLAP_PFBIT_SET == PFBit)
+ {
+ RetOnErr(SendFRMR(pIrlapCb, &FrmRejFormat));
+ pIrlapCb->State = S_NRM;
+ }
+ break;
+
+ default:
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
+
+ }
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+UINT
+ProcessInvalidNr(PIRLAP_CB pIrlapCb,
+ int PFBit)
+{
+ DEBUGMSG(DBG_ERROR, (TEXT("IRLAP: ERROR, Invalid Nr\r\n")));
+
+ RetOnErr(ReturnTxMsgs(pIrlapCb));
+
+ if (PRIMARY == pIrlapCb->StationType)
+ {
+ if (PFBit == IRLAP_PFBIT_SET)
+ {
+ RetOnErr(SendDISC(pIrlapCb));
+ pIrlapCb->RetryCnt = 0;
+ // F-timer will be started by caller
+ RetOnErr(GotoPCloseState(pIrlapCb));
+ }
+ else
+ {
+ pIrlapCb->State = P_DISCONNECT_PEND;
+ }
+ }
+ else // SECONDARY
+ {
+ if (PFBit == IRLAP_PFBIT_SET)
+ {
+ FrmRejFormat.Vs = pIrlapCb->Vs;
+ FrmRejFormat.Vr = pIrlapCb->Vr;
+ FrmRejFormat.W = 0;
+ FrmRejFormat.X = 0;
+ FrmRejFormat.Y = 0;
+ FrmRejFormat.Z = 1; // bad NR
+ RetOnErr(SendFRMR(pIrlapCb, &FrmRejFormat));
+ }
+ }
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+UINT
+ProcessIFrame(PIRLAP_CB pIrlapCb,
+ PIRDA_MSG pMsg,
+ int CRBit,
+ int PFBit,
+ UINT Ns,
+ UINT Nr,
+ BOOL *pFreeMsg)
+{
+#ifdef DEBUG
+ BYTE *p1, *p2;
+#endif
+
+ pMsg->IRDA_MSG_pRead += 2; // chop the IRLAP header
+
+ switch (pIrlapCb->State)
+ {
+ case S_NRM:
+ case P_RECV:
+ // Stop Timers: if PFSet stop Final (I frame from secondary)
+ // Always stop WDog (I from primary)
+ if (PRIMARY == pIrlapCb->StationType)
+ {
+ if (PFBit == IRLAP_PFBIT_SET)
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
+ }
+ }
+ else
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
+ }
+
+ if (pIrlapCb->CRBit == CRBit)
+ {
+ RetOnErr(StationConflict(pIrlapCb));
+ pIrlapCb->State = NDM;
+ return SUCCESS;
+ }
+
+ if (InvalidNsOrNr(pIrlapCb, Ns, Nr))
+ {
+#ifdef DEBUG
+ p1 = pMsg->IRDA_MSG_pRead - 2; // Get header back
+ p2 = pMsg->IRDA_MSG_pWrite + 2; // and FCS
+
+ while (p1 < p2)
+ DEBUGMSG(DBG_ERROR, (TEXT("%02X "), *p1++));
+ DEBUGMSG(DBG_ERROR, (TEXT("\n")));
+#endif
+
+#ifdef TEMPERAMENTAL_SERIAL_DRIVER
+ if (pIrlapCb->RxWin.FCS[Ns] == pMsg->IRDA_MSG_FCS)
+ TossedDups++;
+ else
+ RetOnErr(ProcessInvalidNsOrNr(pIrlapCb, PFBit));
+#else
+ RetOnErr(ProcessInvalidNsOrNr(pIrlapCb, PFBit));
+#endif
+ }
+ else
+ {
+ if (PFBit == IRLAP_PFBIT_SET)
+ {
+ RetOnErr(InsertRxWinAndForward(pIrlapCb,
+ pMsg, Ns, pFreeMsg));
+
+ if (Nr != pIrlapCb->Vs)
+ {
+ RetOnErr(ResendRejects(pIrlapCb, Nr)); // always turns link
+ }
+ else // Nr == Vs, Good Nr
+ {
+ RetOnErr(FreeAckedTxMsgs(pIrlapCb, Nr));
+ // Link will always be turned here
+ if (pIrlapCb->Vr != pIrlapCb->RxWin.End)
+ {
+ RetOnErr(MissingRxFrames(pIrlapCb));
+ }
+ else
+ {
+ RetOnErr(XmitTxMsgList(pIrlapCb, TRUE, NULL));
+ }
+ }
+ }
+ else // PF Bit not set
+ {
+ RetOnErr(InsertRxWinAndForward(pIrlapCb,
+ pMsg, Ns, pFreeMsg));
+ RetOnErr(FreeAckedTxMsgs(pIrlapCb, Nr));
+ }
+ }
+ // Start Timers: If PFBit set, link was turned so start final
+ // WDog is always stopped, so restart
+ if (PRIMARY == pIrlapCb->StationType)
+ {
+ if (PFBit == IRLAP_PFBIT_SET)
+ {
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ }
+ }
+ else // command from primary
+ {
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
+ }
+ break;
+
+ default:
+ RetOnErr(IFrameOtherStates(pIrlapCb, CRBit, PFBit));
+ }
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+*
+* @ex
+* example
+*/
+BOOL
+InvalidNsOrNr(PIRLAP_CB pIrlapCb,
+ UINT Ns,
+ UINT Nr)
+{
+ if (InvalidNr(pIrlapCb, Nr))
+ {
+ return TRUE;
+ }
+
+ // Valididate ns
+ if (!InWindow(pIrlapCb->Vr,
+ (pIrlapCb->RxWin.Start + pIrlapCb->LocalWinSize-1) % IRLAP_MOD, Ns)
+ || !InWindow(pIrlapCb->RxWin.Start,
+ (pIrlapCb->RxWin.Start + pIrlapCb->LocalWinSize-1) % IRLAP_MOD, Ns))
+ {
+ DEBUGMSG(DBG_ERROR,
+ (TEXT("IRLAP: ERROR, Invalid Ns=%d! Vr=%d, RxStrt=%d Win=%d\r\n"),
+ Ns, pIrlapCb->Vr, pIrlapCb->RxWin.Start, pIrlapCb->LocalWinSize));
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("** INVALID Ns **")));
+ return TRUE;
+ }
+ return FALSE;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+*
+* @ex
+* example
+*/
+BOOL
+InvalidNr(PIRLAP_CB pIrlapCb,
+ UINT Nr)
+{
+ if (!InWindow(pIrlapCb->TxWin.Start, pIrlapCb->Vs, Nr))
+ {
+ DEBUGMSG(DBG_ERROR,
+ (TEXT("IRLAP: ERROR, Invalid Nr=%d! Vs=%d, TxStrt=%d\r\n"),
+ Nr, pIrlapCb->Vs, pIrlapCb->TxWin.Start));
+ return TRUE; // Invalid Nr
+ }
+ return FALSE;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+BOOL
+InWindow(UINT Start, UINT End, UINT i)
+{
+ if (Start <= End)
+ {
+ if (i >= Start && i <= End)
+ return TRUE;
+ }
+ else
+ {
+ if (i >= Start || i <= End)
+ return TRUE;
+ }
+ return FALSE;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+UINT
+ProcessInvalidNsOrNr(PIRLAP_CB pIrlapCb,
+ int PFBit)
+{
+ RetOnErr(ReturnTxMsgs(pIrlapCb));
+
+ if (PRIMARY == pIrlapCb->StationType)
+ {
+ if (PFBit == IRLAP_PFBIT_SET)
+ {
+ RetOnErr(SendDISC(pIrlapCb));
+ pIrlapCb->RetryCnt = 0;
+ // F-timer will be started by caller
+ RetOnErr(GotoPCloseState(pIrlapCb));
+ }
+ else
+ {
+ pIrlapCb->State = P_DISCONNECT_PEND;
+ }
+ }
+ else // SECONDARY
+ {
+ FrmRejFormat.Vs = pIrlapCb->Vs;
+ FrmRejFormat.Vr = pIrlapCb->Vr;
+ FrmRejFormat.W = 0;
+ FrmRejFormat.X = 0;
+ FrmRejFormat.Y = 0;
+ FrmRejFormat.Z = 1; // bad NR
+ if (PFBit == IRLAP_PFBIT_SET)
+ {
+ RetOnErr(SendFRMR(pIrlapCb, &FrmRejFormat));
+ }
+ else
+ {
+ pIrlapCb->State = S_ERROR;
+ }
+ }
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+UINT
+InsertRxWinAndForward(PIRLAP_CB pIrlapCb,
+ PIRDA_MSG pMsg,
+ UINT Ns,
+ BOOL *pFreeMsg)
+{
+ UINT rc = SUCCESS;
+
+ // insert message into receive window
+ pIrlapCb->RxWin.pMsg[Ns] = pMsg;
+#ifdef TEMPERAMENTAL_SERIAL_DRIVER
+ pIrlapCb->RxWin.FCS[Ns] = pMsg->IRDA_MSG_FCS;
+#endif
+
+ // Advance RxWin.End to Ns+1 if Ns is at or beyond RxWin.End
+ if (!InWindow(pIrlapCb->RxWin.Start, pIrlapCb->RxWin.End, Ns) ||
+ Ns == pIrlapCb->RxWin.End)
+ {
+ pIrlapCb->RxWin.End = (Ns + 1) % IRLAP_MOD;
+ }
+
+ // Forward in sequence frames starting from Vr
+ while (pIrlapCb->RxWin.pMsg[pIrlapCb->Vr] != NULL && !pIrlapCb->LocalBusy)
+ {
+ pIrlapCb->RxWin.pMsg[pIrlapCb->Vr]->Prim = IRLAP_DATA_IND;
+
+ rc =IrlmpUp(pIrlapCb->pIrdaLinkCb, pIrlapCb->RxWin.pMsg[pIrlapCb->Vr]);
+
+ if (rc == SUCCESS || rc == IRLMP_LOCAL_BUSY)
+ {
+ // Delivered successfully. Done with this message. Remove it from
+ // the RxWin and return message to rx free list. Update Vr
+
+/* !!! here it is again
+ RetOnErr(EnqueMsgList(&pIrlapCb->RxMsgFreeList,
+ pIrlapCb->RxWin.pMsg[pIrlapCb->Vr],
+ pIrlapCb->MaxRxMsgFreeListLen));
+*/
+ pIrlapCb->RxWin.pMsg[pIrlapCb->Vr] = NULL;
+ pIrlapCb->Vr = (pIrlapCb->Vr + 1) % IRLAP_MOD;
+
+ // LMP doesn't want anymore messages
+ if (rc == IRLMP_LOCAL_BUSY)
+ {
+ // The receive window will be cleaned out when RNR is sent
+ pIrlapCb->LocalBusy = TRUE;
+ }
+ }
+ else
+ {
+ return rc;
+ }
+ }
+ *pFreeMsg = FALSE; // we either already freed it or placed it in the window
+ // i.e. the caller should not free the message
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+UINT
+ResendRejects(PIRLAP_CB pIrlapCb, UINT Nr)
+{
+ if (!pIrlapCb->RemoteBusy)
+ {
+ // Set Vs back
+
+ for (pIrlapCb->Vs = Nr;pIrlapCb->Vs != (pIrlapCb->TxWin.End-1)%IRLAP_MOD;
+ pIrlapCb->Vs = (pIrlapCb->Vs + 1) % IRLAP_MOD)
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("RETRANSMISSION:")));
+ RetOnErr(SendIFrame(pIrlapCb,
+ pIrlapCb->TxWin.pMsg[pIrlapCb->Vs],
+ pIrlapCb->Vs,
+ IRLAP_PFBIT_CLEAR));
+ }
+
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("RETRANSMISSION:")));
+ // Send last one with PFBit set
+ RetOnErr(SendIFrame(pIrlapCb, pIrlapCb->TxWin.pMsg[pIrlapCb->Vs],
+ pIrlapCb->Vs, IRLAP_PFBIT_SET));
+
+ pIrlapCb->Vs = (pIrlapCb->Vs + 1) % IRLAP_MOD; // Vs == TxWin.End
+ }
+ else
+ {
+ RetOnErr(SendRR_RNR(pIrlapCb));
+ }
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+UINT
+FreeAckedTxMsgs(PIRLAP_CB pIrlapCb,
+ UINT Nr)
+{
+ UINT i = pIrlapCb->TxWin.Start;
+
+ while (i != Nr)
+ {
+ if (pIrlapCb->TxWin.pMsg[i] != NULL)
+ {
+ pIrlapCb->TxWin.pMsg[i]->Prim = IRLAP_DATA_CONF;
+ pIrlapCb->TxWin.pMsg[i]->IRDA_MSG_DataStatus =
+ IRLAP_DATA_REQUEST_COMPLETED;
+ RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, pIrlapCb->TxWin.pMsg[i]));
+
+ pIrlapCb->TxWin.pMsg[i] = NULL;
+ }
+ i = (i + 1) % IRLAP_MOD;
+ }
+ pIrlapCb->TxWin.Start = i;
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+UINT
+MissingRxFrames(PIRLAP_CB pIrlapCb)
+{
+ int MissingFrameCnt = 0;
+ int MissingFrame = -1;
+ UINT i;
+
+ i = pIrlapCb->Vr;
+
+ // Count missing frame, determine first missing frame
+
+ for (i = pIrlapCb->Vr; (i + 1) % IRLAP_MOD != pIrlapCb->RxWin.End;
+ i = (i+1) % IRLAP_MOD)
+ {
+ if (pIrlapCb->RxWin.pMsg[i] == NULL)
+ {
+ MissingFrameCnt++;
+ if (MissingFrame == -1)
+ {
+ MissingFrame = i;
+ }
+ }
+ }
+
+ // if there are missing frames send SREJ (1) or RR (more than 1)
+ // and turn link around
+ if (MissingFrameCnt == 1 && !pIrlapCb->LocalBusy)
+ {
+ // we don't want to send the SREJ when local is busy because
+ // peer *MAY* interpret it as a clearing of the local busy condition
+ RetOnErr(SendSREJ(pIrlapCb, MissingFrame));
+ }
+ else
+ {
+ // The RR/RNR will serve as an implicit REJ
+ RetOnErr(SendRR_RNR(pIrlapCb));
+ }
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+UINT
+IFrameOtherStates(PIRLAP_CB pIrlapCb,
+ int CRBit,
+ int PFBit)
+{
+ switch (pIrlapCb->State)
+ {
+ case NDM:
+ case DSCV_MEDIA_SENSE:
+ case DSCV_QUERY:
+ case DSCV_REPLY:
+ case CONN_MEDIA_SENSE:
+ case SNRM_SENT:
+ case BACKOFF_WAIT:
+ case SNRM_RECEIVED:
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
+ return SUCCESS;
+ }
+
+ if (pIrlapCb->CRBit == CRBit) // should be opposite of mine
+ {
+ if (pIrlapCb->StationType == PRIMARY)
+ {
+ if (pIrlapCb->State == P_XMIT)
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->PollTimer);
+ }
+ else
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
+ }
+ }
+ else
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
+ }
+ RetOnErr(StationConflict(pIrlapCb));
+ pIrlapCb->State = NDM;
+
+ return SUCCESS;
+ }
+
+ if (pIrlapCb->StationType == PRIMARY) // I'm PRIMARY, this is a
+ { // response from secondary
+ switch (pIrlapCb->State)
+ {
+ case P_DISCONNECT_PEND:
+ if (PFBit == IRLAP_PFBIT_CLEAR)
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
+ }
+ else
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
+ RetOnErr(SendDISC(pIrlapCb));
+ pIrlapCb->RetryCnt = 0;
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ RetOnErr(GotoPCloseState(pIrlapCb));
+ }
+ break;
+
+ case P_CLOSE:
+ if (PFBit == IRLAP_PFBIT_CLEAR)
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
+ }
+ else
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
+ RetOnErr(ResendDISC(pIrlapCb));
+ if (pIrlapCb->State != NDM)
+ {
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ }
+ }
+ break;
+
+ case S_CLOSE:
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
+ break;
+
+ default:
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
+ }
+ }
+ else
+ {
+ switch (pIrlapCb->State)
+ {
+ case S_DISCONNECT_PEND:
+ if (IRLAP_PFBIT_SET == PFBit)
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
+ RetOnErr(SendRD(pIrlapCb));
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
+ pIrlapCb->State = S_CLOSE;
+ }
+ else
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
+ }
+ break;
+
+ case S_ERROR:
+ if (IRLAP_PFBIT_SET == PFBit)
+ {
+ RetOnErr(SendFRMR(pIrlapCb, &FrmRejFormat));
+ pIrlapCb->State = S_NRM;
+ }
+ else
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
+ }
+ break;
+
+ case S_CLOSE:
+ if (IRLAP_PFBIT_SET == PFBit)
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
+ RetOnErr(SendRD(pIrlapCb));
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
+ }
+ else
+ {
+ IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
+ }
+ default:
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignore in this state")));
+ }
+ }
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func UINT | StationConflict | Sends disconnect due to receipt of
+* by primary of frame with Poll
+*
+* @rdesc SUCCESS otherwise one of the following errors:
+* @flag val | desc
+*
+* @comm
+* comments
+*/
+UINT
+StationConflict(PIRLAP_CB pIrlapCb)
+{
+ InitializeState(pIrlapCb, PRIMARY); // Primary doesn't mean anything here
+
+ RetOnErr(ApplyDefaultParms(pIrlapCb));
+ IMsg.Prim = IRLAP_DISCONNECT_IND;
+ IMsg.IRDA_MSG_DiscStatus = IRLAP_PRIMARY_CONFLICT;
+ RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
+
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func UINT | ApplyDefaultParms | Apply default parameters and
+* reinitalize MAC
+*
+* @rdesc SUCCESS otherwise one of the following errors:
+* @flag val | desc
+*
+*/
+UINT
+ApplyDefaultParms(PIRLAP_CB pIrlapCb)
+{
+ pIrlapCb->Baud = IRLAP_DEFAULT_BAUD;
+
+ pIrlapCb->RemoteMaxTAT = IRLAP_DEFAULT_MAX_TAT;
+
+ pIrlapCb->RemoteDataSize = IRLAP_DEFAULT_DATA_SIZE;
+
+ pIrlapCb->RemoteWinSize = IRLAP_DEFAULT_WIN_SIZE;
+
+ pIrlapCb->RemoteNumBOFS = IRLAP_DEFAULT_BOFS;
+
+ pIrlapCb->ConnAddr = IRLAP_BROADCAST_CONN_ADDR;
+
+ IMsg.Prim = MAC_CONTROL_REQ;
+ IMsg.IRDA_MSG_Op = MAC_RECONFIG_LINK;
+ IMsg.IRDA_MSG_Baud = IRLAP_DEFAULT_BAUD;
+ IMsg.IRDA_MSG_NumBOFs = IRLAP_DEFAULT_BOFS;
+ IMsg.IRDA_MSG_DataSize = IRLAP_DEFAULT_DATA_SIZE;
+
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_CONTROL_REQ - reconfig link")));
+
+ return (IrmacDown(pIrlapCb->pIrdaLinkCb,&IMsg));
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+UINT
+ResendDISC(PIRLAP_CB pIrlapCb)
+{
+ if (pIrlapCb->RetryCnt >= pIrlapCb->N3)
+ {
+ RetOnErr(ApplyDefaultParms(pIrlapCb));
+ pIrlapCb->RetryCnt = 0;
+ IMsg.Prim = IRLAP_DISCONNECT_IND;
+ IMsg.IRDA_MSG_DiscStatus = IRLAP_NO_RESPONSE;
+ RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
+ pIrlapCb->State = NDM;
+ }
+ else
+ {
+ RetOnErr(SendDISC(pIrlapCb));
+ pIrlapCb->RetryCnt++;
+ }
+ return SUCCESS;
+}
+
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+BOOL
+IgnoreState(PIRLAP_CB pIrlapCb)
+{
+ switch (pIrlapCb->State)
+ {
+ case NDM:
+ case DSCV_MEDIA_SENSE:
+ case DSCV_QUERY:
+ case DSCV_REPLY:
+ case CONN_MEDIA_SENSE:
+ case SNRM_SENT:
+ case BACKOFF_WAIT:
+ case SNRM_RECEIVED:
+ case P_XMIT:
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+VOID
+QueryTimerExp(PVOID Context)
+{
+ PIRLAP_CB pIrlapCb = (PIRLAP_CB) Context;
+
+ IRLAP_LOG_START((pIrlapCb, "Query timer expired"));
+
+ if (pIrlapCb->State == DSCV_REPLY)
+ {
+ pIrlapCb->State = NDM;
+ }
+ else
+ {
+ IRLAP_LOG_ACTION((pIrlapCb,
+ TEXT("Ignoring QueryTimer Expriation in state %s"),
+ IRLAP_StateStr[pIrlapCb->State]));
+ }
+
+ IRLAP_LOG_COMPLETE(pIrlapCb);
+
+ return;
+}
+
+VOID
+SlotTimerExp(PVOID Context)
+{
+ PIRLAP_CB pIrlapCb = (PIRLAP_CB) Context;
+
+ IRLAP_LOG_START((pIrlapCb, "Slot timer expired"));
+
+ if (pIrlapCb->State == DSCV_QUERY)
+ {
+ pIrlapCb->SlotCnt++;
+ SendDscvXIDCmd(pIrlapCb);
+ if (pIrlapCb->SlotCnt < pIrlapCb->MaxSlot)
+ {
+ IMsg.Prim = MAC_CONTROL_REQ;
+ IMsg.IRDA_MSG_Op = MAC_MEDIA_SENSE;
+ IMsg.IRDA_MSG_SenseTime = IRLAP_DSCV_SENSE_TIME;
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_CONTROL_REQ (dscv sense)")));
+ IrmacDown(pIrlapCb->pIrdaLinkCb,&IMsg);
+ }
+ else
+ {
+ pIrlapCb->GenNewAddr = FALSE;
+
+ IMsg.Prim = IRLAP_DISCOVERY_CONF;
+ IMsg.IRDA_MSG_pDevList = &pIrlapCb->DevList;
+ IMsg.IRDA_MSG_DscvStatus = IRLAP_DISCOVERY_COMPLETED;
+
+ // Change state now so IRLMP can do DISCOVERY_REQ on this thread
+ pIrlapCb->State = NDM;
+
+ IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg);
+ }
+ }
+ else
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring SlotTimer Expriation in state %s"),
+ IRLAP_StateStr[pIrlapCb->State]));
+ ; // maybe return bad state ???
+ }
+ IRLAP_LOG_COMPLETE(pIrlapCb);
+ return;
+}
+
+VOID
+FinalTimerExp(PVOID Context)
+{
+ PIRLAP_CB pIrlapCb = (PIRLAP_CB) Context;
+
+ IRLAP_LOG_START((pIrlapCb, "Final timer expired"));
+
+ pIrlapCb->NoResponse = TRUE;
+
+ switch (pIrlapCb->State)
+ {
+ case SNRM_SENT:
+ if (pIrlapCb->RetryCnt < pIrlapCb->N3)
+ {
+ pIrlapCb->BackoffTimer.Timeout = IRLAP_BACKOFF_TIME();
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->BackoffTimer);
+ pIrlapCb->State = BACKOFF_WAIT;
+ }
+ else
+ {
+ ApplyDefaultParms(pIrlapCb);
+
+ pIrlapCb->RetryCnt = 0;
+ IMsg.Prim = IRLAP_DISCONNECT_IND;
+ IMsg.IRDA_MSG_DiscStatus = IRLAP_NO_RESPONSE;
+ IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg);
+ pIrlapCb->State = NDM;
+ }
+ break;
+
+ case P_RECV:
+ if (pIrlapCb->RetryCnt == pIrlapCb->N2)
+ {
+ ReturnTxMsgs(pIrlapCb);
+ ApplyDefaultParms(pIrlapCb);
+
+ pIrlapCb->RetryCnt = 0; // Don't have to, do it for logger
+ IMsg.Prim = IRLAP_DISCONNECT_IND;
+ IMsg.IRDA_MSG_DiscStatus = IRLAP_NO_RESPONSE;
+ IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg);
+ pIrlapCb->State = NDM;
+ }
+ else
+ {
+ pIrlapCb->RetryCnt++;
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ SendRR_RNR(pIrlapCb);
+ if (pIrlapCb->RetryCnt == pIrlapCb->N1)
+ {
+ IMsg.Prim = IRLAP_STATUS_IND;
+ IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg);
+ }
+ }
+ break;
+
+ case P_DISCONNECT_PEND:
+ SendDISC(pIrlapCb);
+ pIrlapCb->RetryCnt = 0;
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ GotoPCloseState(pIrlapCb);
+ break;
+
+ case P_CLOSE:
+ if (pIrlapCb->RetryCnt >= pIrlapCb->N3)
+ {
+ ApplyDefaultParms(pIrlapCb);
+
+ pIrlapCb->RetryCnt = 0; // Don't have to, do it for logger
+ IMsg.Prim = IRLAP_DISCONNECT_IND;
+ IMsg.IRDA_MSG_DiscStatus = IRLAP_NO_RESPONSE;
+ IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg);
+ GotoNDMThenDscvOrConn(pIrlapCb);
+ }
+ else
+ {
+ pIrlapCb->RetryCnt++;
+ SendDISC(pIrlapCb);
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ }
+ break;
+
+ default:
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring Final Expriation in state %s"),
+ IRLAP_StateStr[pIrlapCb->State]));
+ }
+
+ IRLAP_LOG_COMPLETE(pIrlapCb);
+ return;
+}
+
+VOID
+PollTimerExp(PVOID Context)
+{
+ PIRLAP_CB pIrlapCb = (PIRLAP_CB) Context;
+
+ IRLAP_LOG_START((pIrlapCb, "Poll timer expired"));
+
+ if (pIrlapCb->State == P_XMIT)
+ {
+ SendRR_RNR(pIrlapCb);
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ pIrlapCb->State = P_RECV;
+ }
+ else
+ {
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring Poll Expriation in state %s"),
+ IRLAP_StateStr[pIrlapCb->State]));
+ }
+
+ IRLAP_LOG_COMPLETE(pIrlapCb);
+ return;
+}
+
+VOID
+BackoffTimerExp(PVOID Context)
+{
+ PIRLAP_CB pIrlapCb = (PIRLAP_CB) Context;
+
+ IRLAP_LOG_START((pIrlapCb, "Backoff timer expired"));
+
+ if (pIrlapCb->State == BACKOFF_WAIT)
+ {
+ SendSNRM(pIrlapCb, TRUE);
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
+ pIrlapCb->RetryCnt += 1;
+ pIrlapCb->State = SNRM_SENT;
+ }
+ else
+ {
+ IRLAP_LOG_ACTION((pIrlapCb,
+ TEXT("Ignoring BackoffTimer Expriation in this state ")));
+ }
+ IRLAP_LOG_COMPLETE(pIrlapCb);
+ return;
+}
+
+VOID
+WDogTimerExp(PVOID Context)
+{
+ PIRLAP_CB pIrlapCb = (PIRLAP_CB) Context;
+
+ IRLAP_LOG_START((pIrlapCb, "WDog timer expired"));
+
+ pIrlapCb->NoResponse = TRUE;
+
+ switch (pIrlapCb->State)
+ {
+ case S_DISCONNECT_PEND:
+ case S_NRM:
+ pIrlapCb->WDogExpCnt++;
+ // Disconnect/threshold time is in seconds
+ if (pIrlapCb->WDogExpCnt * (int)pIrlapCb->WDogTimer.Timeout >=
+ pIrlapCb->DisconnectTime * 1000)
+ {
+ ReturnTxMsgs(pIrlapCb);
+ ApplyDefaultParms(pIrlapCb);
+
+ IMsg.Prim = IRLAP_DISCONNECT_IND;
+ IMsg.IRDA_MSG_DiscStatus = IRLAP_NO_RESPONSE;
+ IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg);
+ pIrlapCb->State = NDM;
+ }
+ else
+ {
+ if ((pIrlapCb->WDogExpCnt * (int) pIrlapCb->WDogTimer.Timeout >=
+ pIrlapCb->ThresholdTime * 1000) && !pIrlapCb->StatusSent)
+ {
+ IMsg.Prim = IRLAP_STATUS_IND;
+ IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg);
+ pIrlapCb->StatusSent = TRUE;
+ }
+ IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
+ }
+ break;
+
+ case S_CLOSE:
+ ApplyDefaultParms(pIrlapCb);
+
+ IMsg.Prim = IRLAP_DISCONNECT_IND;
+ IMsg.IRDA_MSG_DiscStatus = IRLAP_NO_RESPONSE;
+ IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg);
+ pIrlapCb->State = NDM;
+ break;
+
+ default:
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignore WDogTimer expiration in state %s"),
+ IRLAP_StateStr[pIrlapCb->State]));
+ }
+ IRLAP_LOG_COMPLETE(pIrlapCb);
+ return;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+UINT
+DequeMsgList(IRDA_MSG_LIST *pList, IRDA_MSG **ppMsg)
+{
+ if (pList->Len != 0)
+ {
+ *ppMsg = (IRDA_MSG *) RemoveHeadList(&pList->ListHead);
+/**
+ {
+ IRDA_MSG *pAMsg = pList->ListHead.Flink;
+
+ printf(TEXT("\nDEQUE: %x\n"), *ppMsg);
+
+ while (pAMsg != &(pList->ListHead))
+ {
+ printf(TEXT("%x->"),pAMsg);
+ pAMsg = pAMsg->Linkage.Flink;
+ }
+ printf(TEXT("\n"));
+ }
+**/
+ pList->Len--;
+ return SUCCESS;
+ }
+ return IRLAP_MSG_LIST_EMPTY;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+
+
+* @ex
+* example
+*/
+UINT
+EnqueMsgList(IRDA_MSG_LIST *pList, IRDA_MSG *pMsg, int MaxLen)
+{
+ if (MaxLen == -1 || pList->Len < MaxLen)
+ {
+ InsertTailList(&pList->ListHead, &(pMsg->Linkage));
+ pList->Len++;
+/**
+ {
+ IRDA_MSG *pAMsg = pList->ListHead.Flink;
+
+ printf(TEXT("\nENQUE: %x\n"), pMsg);
+ while (pAMsg != &(pList->ListHead))
+ {
+ printf(TEXT("%x->"),pAMsg);
+ pAMsg = pAMsg->Linkage.Flink;
+ }
+ printf(TEXT("\n"));
+ }
+**/
+ return SUCCESS;
+ }
+ return IRLAP_MSG_LIST_FULL;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+void
+InitMsgList(IRDA_MSG_LIST *pList)
+{
+ InitializeListHead(&pList->ListHead);
+ pList->Len = 0;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc return desc
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*
+* @ex
+* example
+*/
+/* !!!
+void
+IRLAP_PrintState()
+{
+#ifdef DEBUG
+ DEBUGMSG(1, (TEXT("IRLAP State %s\n"), IRLAP_StateStr[pIrlapCb->State]));
+#else
+ DEBUGMSG(1, (TEXT("IRLAP State %d\n"), pIrlapCb->State));
+#endif
+ DEBUGMSG(1,
+ (TEXT(" Vs=%d Vr=%d RxWin(%d,%d) TxWin(%d,%d) TxMsgListLen=%d RxMsgFreeListLen=%d\r\n"),
+ pIrlapCb->Vs, pIrlapCb->Vr,
+ pIrlapCb->RxWin.Start, pIrlapCb->RxWin.End,
+ pIrlapCb->TxWin.Start, pIrlapCb->TxWin.End,
+ pIrlapCb->TxMsgList.Len, pIrlapCb->RxMsgFreeList.Len));
+
+#ifdef TEMPERAMENTAL_SERIAL_DRIVER
+ DEBUGMSG(1, (TEXT(" Tossed duplicates %d\n"), TossedDups));
+#endif
+
+ IRMAC_PrintState();
+
+ return;
+}
+*/
+int
+GetMyDevAddr(BOOL New)
+{
+#ifdef PEG
+ HKEY hKey;
+ LONG hRes;
+ TCHAR KeyName[32];
+#endif
+ int DevAddr, NewDevAddr;
+ DWORD RegDevAddr = 0;
+ TCHAR ValName[] = TEXT("DevAddr");
+ LARGE_INTEGER li;
+
+ KeQueryTickCount(&li);
+
+ NewDevAddr = (int) li.LowPart;
+
+ // Get the device address from the registry. If the key exists and the
+ // value is 0, store a new random address. If no key, then return
+ // a random address.
+#ifdef PEG
+ _tcscpy (KeyName, COMM_REG_KEY);
+ _tcscat (KeyName, TEXT("IrDA"));
+
+ hRes = RegOpenKeyEx (HKEY_LOCAL_MACHINE, KeyName, 0, 0, &hKey);
+
+ if (hRes == ERROR_SUCCESS &&
+ GetRegDWORDValue(hKey, ValName, &RegDevAddr))
+ {
+ if (RegDevAddr == 0)
+ {
+ RegDevAddr = KeQueryTickCount();
+ SetRegDWORDValue(hKey, ValName, RegDevAddr);
+ }
+ RegCloseKey(hKey);
+
+ DevAddr = (int) RegDevAddr;
+ }
+#else
+ DevAddr = NewDevAddr;
+#endif
+ return DevAddr;
+}
+
diff --git a/private/ntos/tdi/irda/irlap/irlapio.c b/private/ntos/tdi/irda/irlap/irlapio.c
new file mode 100644
index 000000000..0c4a8361d
--- /dev/null
+++ b/private/ntos/tdi/irda/irlap/irlapio.c
@@ -0,0 +1,900 @@
+/*****************************************************************************
+*
+* Copyright (c) 1995 Microsoft Corporation
+*
+* File: irlapio.c
+*
+* Description: IRLAP I/O routines
+*
+* Author: mbert
+*
+* Date: 4/25/95
+*
+*/
+#include <irda.h>
+#include <irdalink.h>
+#include <irmac.h>
+#include <irlap.h>
+#include <irlmp.h>
+#include <irlapp.h>
+#include <irlapio.h>
+#include <irlaplog.h>
+
+extern BYTE IRLAP_BroadcastDevAddr[];
+
+// The largest MAC message is the XID Frame consisting of address,
+// control, XID Format ID, XID format, + Discovery Information
+#define _MAC_MSG_LEN 3+sizeof(IRLAP_XID_DSCV_FORMAT)+IRLAP_DSCV_INFO_LEN
+
+//static BYTE IRLAP_MAC_MsgData[_MAC_MSG_LEN];
+//static IRDA_MSG MAC_Message;
+//static PIRDA_MSG pMACMsg = &MAC_Message;
+
+UINT
+SendFrame(PIRLAP_CB, PIRDA_MSG );
+
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*/
+UINT
+ClearRxWindow(PIRLAP_CB pIrlapCb)
+{
+ UINT i, rc;
+
+ // Remove everything from Rx window
+ for (i = pIrlapCb->Vr; i != pIrlapCb->RxWin.End; i = (i+1) % IRLAP_MOD)
+ {
+ if (pIrlapCb->RxWin.pMsg[i] != NULL)
+ {
+ /* !!! fix this OH SHIT
+ if((rc = EnqueMsgList(&pIrlapCb->RxMsgFreeList,
+ pIrlapCb->RxWin.pMsg[i],
+ pIrlapCb->MaxRxMsgFreeListLen)) != SUCCESS)
+ {
+ return rc;
+ }
+ */
+ pIrlapCb->RxWin.pMsg[i] = NULL;
+ }
+ pIrlapCb->RxWin.End = pIrlapCb->Vr;
+ }
+ return SUCCESS;
+}
+/*****************************************************************************
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*/
+UINT
+SendDscvXIDCmd(PIRLAP_CB pIrlapCb)
+{
+ UINT rc = SUCCESS;
+ IRLAP_XID_DSCV_FORMAT XIDFormat;
+ CHAR *DscvInfo;
+ int DscvInfoLen;
+ IRDA_MSG *pIMsg;
+
+ pIMsg = AllocMacIMsg(pIrlapCb->pIrdaLinkCb);
+
+ memcpy(XIDFormat.SrcAddr, pIrlapCb->LocalDevice.DevAddr, IRDA_DEV_ADDR_LEN);
+ memcpy(XIDFormat.DestAddr, IRLAP_BroadcastDevAddr, IRDA_DEV_ADDR_LEN);
+
+ XIDFormat.NoOfSlots = IRLAP_SLOT_FLAG(pIrlapCb->MaxSlot);
+ XIDFormat.GenNewAddr = pIrlapCb->GenNewAddr;
+ XIDFormat.Reserved = 0;
+
+ if (pIrlapCb->SlotCnt == pIrlapCb->MaxSlot)
+ {
+ DscvInfo = pIrlapCb->LocalDevice.DscvInfo;
+ DscvInfoLen = pIrlapCb->LocalDevice.DscvInfoLen;
+ XIDFormat.SlotNo = IRLAP_END_DSCV_SLOT_NO;
+ }
+ else
+ {
+ DscvInfo = NULL;
+ DscvInfoLen = 0;
+ XIDFormat.SlotNo = pIrlapCb->SlotCnt;
+ }
+ XIDFormat.Version = pIrlapCb->LocalDevice.IRLAP_Version;
+
+ pIMsg->IRDA_MSG_pWrite = Format_DscvXID(pIMsg,
+ IRLAP_BROADCAST_CONN_ADDR,
+ IRLAP_CMD, IRLAP_PFBIT_SET,
+ &XIDFormat, DscvInfo,
+ DscvInfoLen);
+ return SendFrame(pIrlapCb, pIMsg);
+}
+/****************************************************************************S*
+*
+* @func ret_type | func_name | funcdesc
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm data_type | parm_name | description
+*
+* @comm
+* comments
+*/
+UINT
+SendDscvXIDRsp(PIRLAP_CB pIrlapCb)
+{
+ UINT rc = SUCCESS;
+ IRLAP_XID_DSCV_FORMAT XIDFormat;
+ IRDA_MSG *pIMsg;
+
+ pIMsg = AllocMacIMsg(pIrlapCb->pIrdaLinkCb);
+
+ XIDFormat.GenNewAddr = pIrlapCb->GenNewAddr;
+ if (pIrlapCb->GenNewAddr)
+ {
+ StoreULAddr(pIrlapCb->LocalDevice.DevAddr, GetMyDevAddr(TRUE));
+ pIrlapCb->GenNewAddr = FALSE;
+ }
+ memcpy(XIDFormat.SrcAddr, pIrlapCb->LocalDevice.DevAddr, IRDA_DEV_ADDR_LEN);
+ memcpy(XIDFormat.DestAddr, pIrlapCb->RemoteDevice.DevAddr, IRDA_DEV_ADDR_LEN);
+ XIDFormat.NoOfSlots = IRLAP_SLOT_FLAG(pIrlapCb->RemoteMaxSlot);
+ XIDFormat.Reserved = 0;
+ XIDFormat.SlotNo = pIrlapCb->RespSlot;
+ XIDFormat.Version = pIrlapCb->LocalDevice.IRLAP_Version;
+
+ pIMsg->IRDA_MSG_pWrite = Format_DscvXID(pIMsg,
+ IRLAP_BROADCAST_CONN_ADDR,
+ IRLAP_RSP, IRLAP_PFBIT_SET,
+ &XIDFormat,
+ pIrlapCb->LocalDevice.DscvInfo,
+ pIrlapCb->LocalDevice.DscvInfoLen);
+ return SendFrame(pIrlapCb, pIMsg);
+}
+/*****************************************************************************
+*
+* @func UINT | SendSNRM | formats a SNRM frame and sends it
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm BYTE | ConnAddr | Connection address
+*
+* @comm
+* The ConnAddr can be different than that in the control block.
+* For reset, its the same, but set to broadcast for initial
+* connection.
+*/
+UINT
+SendSNRM(PIRLAP_CB pIrlapCb, BOOL SendQos)
+{
+ IRDA_QOS_PARMS *pQos = NULL;
+ int ConnAddr = pIrlapCb->ConnAddr;
+ IRDA_MSG *pIMsg;
+
+ if (SendQos)
+ {
+ ConnAddr = IRLAP_BROADCAST_CONN_ADDR;
+ pQos = &pIrlapCb->LocalQos;
+ }
+
+ pIMsg = AllocMacIMsg(pIrlapCb->pIrdaLinkCb);
+
+ pIMsg->IRDA_MSG_pWrite = Format_SNRM(pIMsg, ConnAddr,
+ IRLAP_CMD,
+ IRLAP_PFBIT_SET,
+ pIrlapCb->LocalDevice.DevAddr,
+ pIrlapCb->RemoteDevice.DevAddr,
+ pIrlapCb->ConnAddr,
+ pQos);
+ return SendFrame(pIrlapCb, pIMsg);
+}
+/*****************************************************************************
+*
+* @func UINT | SendUA | formats a UA frame and sends it
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm BOOL | SendQos | Send the Qos
+*
+* @comm
+* comments
+*/
+UINT
+SendUA(PIRLAP_CB pIrlapCb, BOOL SendQos)
+{
+ IRDA_QOS_PARMS NegQos;
+ IRDA_QOS_PARMS *pNegQos = NULL;
+ BYTE *pSrcAddr = NULL;
+ BYTE *pDestAddr = NULL;
+ IRDA_MSG *pIMsg;
+
+ if (SendQos)
+ {
+ // Put all parms (type 0 and 1) in NegQos
+ memcpy(&NegQos, &pIrlapCb->LocalQos, sizeof(IRDA_QOS_PARMS));
+ // Overwrite type 0 parameters that have already been negotiated
+ NegQos.bfBaud = pIrlapCb->NegotiatedQos.bfBaud;
+ NegQos.bfDisconnectTime = pIrlapCb->NegotiatedQos.bfDisconnectTime;
+ pNegQos = &NegQos;
+ }
+
+ // This will be moved into the "if" above when the spec is clarified
+ pSrcAddr = pIrlapCb->LocalDevice.DevAddr;
+ pDestAddr = pIrlapCb->RemoteDevice.DevAddr;
+ //------------------------------------------------------------------
+ pIMsg = AllocMacIMsg(pIrlapCb->pIrdaLinkCb);
+
+ pIMsg->IRDA_MSG_pWrite = Format_UA(pIMsg,
+ pIrlapCb->ConnAddr,
+ IRLAP_RSP,
+ IRLAP_PFBIT_SET,
+ pSrcAddr, pDestAddr, pNegQos);
+ return SendFrame(pIrlapCb, pIMsg);
+}
+/*****************************************************************************
+*
+* @func UINT | SendDM | formats a DM frame and sends it
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+*
+* @comm
+* comments
+*/
+UINT
+SendDM(PIRLAP_CB pIrlapCb)
+{
+ IRDA_MSG *pIMsg;
+
+ pIMsg = AllocMacIMsg(pIrlapCb->pIrdaLinkCb);
+
+ pIMsg->IRDA_MSG_pWrite = Format_DM(pIMsg,
+ pIrlapCb->ConnAddr,
+ IRLAP_RSP,
+ IRLAP_PFBIT_SET);
+
+ return SendFrame(pIrlapCb, pIMsg);
+}
+/*****************************************************************************
+*
+* @func UINT | SendRD | formats a RD frame and sends it
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+*
+* @comm
+* comments
+*/
+UINT
+SendRD(PIRLAP_CB pIrlapCb)
+{
+ IRDA_MSG *pIMsg;
+
+ pIMsg = AllocMacIMsg(pIrlapCb->pIrdaLinkCb);
+
+ pIMsg->IRDA_MSG_pWrite = Format_RD(pIMsg,
+ pIrlapCb->ConnAddr,
+ IRLAP_RSP,
+ IRLAP_PFBIT_SET);
+
+ return SendFrame(pIrlapCb, pIMsg);
+}
+/*****************************************************************************
+*
+* @func UINT | SendRR | formats a RR frame and sends it
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+*
+* @comm
+* comments
+*/
+UINT
+SendRR(PIRLAP_CB pIrlapCb)
+{
+ IRDA_MSG *pIMsg;
+
+ pIMsg = AllocMacIMsg(pIrlapCb->pIrdaLinkCb);
+ ClearRxWindow(pIrlapCb);
+
+ pIrlapCb->RxWin.Start = pIrlapCb->Vr; // RxWin.Start = what we've acked
+
+ pIMsg->IRDA_MSG_pWrite = Format_RR(pIMsg, pIrlapCb->ConnAddr,
+ pIrlapCb->CRBit, IRLAP_PFBIT_SET,
+ pIrlapCb->Vr);
+
+ return SendFrame(pIrlapCb, pIMsg);
+}
+/*****************************************************************************
+*
+* @func UINT | SendRNR | formats a RNR frame and sends it
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+*
+* @comm
+* comments
+*/
+UINT
+SendRR_RNR(PIRLAP_CB pIrlapCb)
+{
+ IRDA_MSG *pIMsg;
+
+ BYTE *(*pFormatRR_RNR)();
+
+ if (pIrlapCb->LocalBusy)
+ {
+ pFormatRR_RNR = Format_RNR;
+ }
+ else
+ {
+ pFormatRR_RNR = Format_RR;
+ }
+
+ pIMsg = AllocMacIMsg(pIrlapCb->pIrdaLinkCb);
+ ClearRxWindow(pIrlapCb);
+
+
+ pIrlapCb->RxWin.Start = pIrlapCb->Vr; // RxWin.Start = what we've acked
+
+
+ pIMsg->IRDA_MSG_pWrite = (*pFormatRR_RNR)(pIMsg, pIrlapCb->ConnAddr,
+ pIrlapCb->CRBit, IRLAP_PFBIT_SET,
+ pIrlapCb->Vr);
+
+ return SendFrame(pIrlapCb, pIMsg);
+}
+/*****************************************************************************
+*
+* @func UINT | SendDISC | formats a DISC frame and sends it
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+*
+* @comm
+* comments
+*/
+UINT
+SendDISC(PIRLAP_CB pIrlapCb)
+{
+ IRDA_MSG *pIMsg;
+
+ pIMsg = AllocMacIMsg(pIrlapCb->pIrdaLinkCb);
+
+ pIMsg->IRDA_MSG_pWrite = Format_DISC(pIMsg, pIrlapCb->ConnAddr,
+ IRLAP_CMD, IRLAP_PFBIT_SET);
+
+ return SendFrame(pIrlapCb, pIMsg);
+}
+/*****************************************************************************
+*
+* @func UINT | SendRNRM | formats a RNRM frame and sends it
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+*
+* @comm
+* comments
+*/
+UINT
+SendRNRM(PIRLAP_CB pIrlapCb)
+{
+ IRDA_MSG *pIMsg;
+
+ pIMsg = AllocMacIMsg(pIrlapCb->pIrdaLinkCb);
+
+ pIMsg->IRDA_MSG_pWrite = Format_RNRM(pIMsg, pIrlapCb->ConnAddr,
+ IRLAP_RSP, IRLAP_PFBIT_SET);
+
+ return SendFrame(pIrlapCb, pIMsg);
+}
+/*****************************************************************************
+*
+* @func UINT | SendREJ | formats a REJ frame and sends it
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+*
+* @comm
+* comments
+*/
+UINT
+SendREJ(PIRLAP_CB pIrlapCb)
+{
+ IRDA_MSG *pIMsg;
+
+ pIMsg = AllocMacIMsg(pIrlapCb->pIrdaLinkCb);
+ ClearRxWindow(pIrlapCb);
+
+ pIrlapCb->RxWin.Start = pIrlapCb->Vr; // RxWin.Start = what we've acked
+
+ pIMsg->IRDA_MSG_pWrite = Format_REJ(pIMsg, pIrlapCb->ConnAddr,
+ pIrlapCb->CRBit, IRLAP_PFBIT_SET,
+ pIrlapCb->Vr);
+
+ return SendFrame(pIrlapCb, pIMsg);
+}
+/*****************************************************************************
+*
+* @func UINT | SendSREJ | formats a SREJ frame and sends it
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm int | Nr | Nr to be placed in SREJ frame
+*
+* @comm
+* comments
+*/
+UINT
+SendSREJ(PIRLAP_CB pIrlapCb, int Nr)
+{
+ IRDA_MSG *pIMsg;
+
+ pIMsg = AllocMacIMsg(pIrlapCb->pIrdaLinkCb);
+
+ pIMsg->IRDA_MSG_pWrite = Format_SREJ(pIMsg, pIrlapCb->ConnAddr,
+ pIrlapCb->CRBit, IRLAP_PFBIT_SET, Nr);
+
+ return SendFrame(pIrlapCb, pIMsg);
+}
+/*****************************************************************************
+*
+* @func UINT | SendFRMR | formats a FRMR frame and sends it
+*
+* @rdesc SUCCESS, otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm int | Nr | Nr to be placed in SREJ frame
+*
+* @comm
+* comments
+*/
+UINT
+SendFRMR(PIRLAP_CB pIrlapCb, IRLAP_FRMR_FORMAT *pFRMRFormat)
+{
+ IRDA_MSG *pIMsg;
+
+ pIMsg = AllocMacIMsg(pIrlapCb->pIrdaLinkCb);
+
+ pIMsg->IRDA_MSG_pWrite = Format_FRMR(pIMsg, pIrlapCb->ConnAddr,
+ pIrlapCb->CRBit, IRLAP_PFBIT_SET,
+ pFRMRFormat);
+
+ return SendFrame(pIrlapCb, pIMsg);
+}
+/*****************************************************************************
+*
+* @func UINT | SendIFrame | Builds and sends an I frame to MAC
+*
+* @rdesc SUCCESS otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm | |
+*
+* @comm
+* comments
+*/
+UINT
+SendIFrame(PIRLAP_CB pIrlapCb, PIRDA_MSG pMsg, int Ns, int PFBit)
+{
+ UINT rc;
+
+ if (NULL == pMsg)
+ {
+ return IRLAP_NULL_MSG;
+ }
+
+ ClearRxWindow(pIrlapCb);
+
+ pIrlapCb->RxWin.Start = pIrlapCb->Vr; // RxWin.Start = what we've acked
+
+ (void) Format_I(pMsg, pIrlapCb->ConnAddr, pIrlapCb->CRBit, PFBit,
+ pIrlapCb->Vr, Ns);
+
+ rc = SendFrame(pIrlapCb, pMsg);
+
+ pMsg->IRDA_MSG_pHdrRead +=2; // uglyness.. chop header in case frame
+ // requires retransmission
+ return rc;
+}
+/*****************************************************************************
+*
+* @func UINT | SendUIFrame | Builds and sends an UI frame to MAC
+*
+* @rdesc SUCCESS otherwise one of the following errors:
+* @flag val | desc
+*
+* @parm | |
+*
+* @comm
+* comments
+*/
+UINT
+SendUIFrame(PIRLAP_CB pIrlapCb, PIRDA_MSG pMsg)
+{
+ if (NULL == pMsg)
+ {
+ return IRLAP_NULL_MSG;
+ }
+ (void) Format_UI(pMsg, pIrlapCb->ConnAddr, pIrlapCb->CRBit,IRLAP_PFBIT_SET);
+
+ return SendFrame(pIrlapCb, pMsg);
+}
+/*****************************************************************************
+*
+* @func UINT | SendFrame | Builds and sends an Unnumbered frame to MAC
+*
+* @rdesc SUCCESS otherwise one of the following errors:
+* @flag val | desc
+*
+* @comm
+* comments
+*/
+UINT
+SendFrame(PIRLAP_CB pIrlapCb, PIRDA_MSG pMsg)
+{
+ UINT rc = SUCCESS;
+
+ pMsg->Prim = MAC_DATA_REQ;
+
+ rc = IrmacDown(pIrlapCb->pIrdaLinkCb, pMsg);
+
+ IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_DATA_REQ: %s"), FrameToStr(pMsg)));
+
+ return rc;
+}
+/*****************************************************************************
+*
+* @func UINT | _IRLMP_Up | Adds logging to the IRLMP_Up
+*
+* @rdesc returns of IRLMP_Up
+*
+* @parm PIRDA_MSG | pMsg | pointer to IRDA message
+*
+* @comm
+* comments
+*/
+/*
+UINT
+_IRLMP_Up(PIRDA_MSG pMsg)
+{
+ IRLAP_LOG_ACTION((TEXT("%s%s"), IRDA_PrimStr[pMsg->Prim],
+ pMsg->Prim == IRLAP_DISCOVERY_CONF ?
+ IRDA_StatStr[pMsg->IRDA_MSG_DscvStatus] :
+ pMsg->Prim == IRLAP_CONNECT_CONF ?
+ IRDA_StatStr[pMsg->IRDA_MSG_ConnStatus] :
+ pMsg->Prim == IRLAP_DISCONNECT_IND ?
+ IRDA_StatStr[pMsg->IRDA_MSG_DiscStatus] :
+ pMsg->Prim == IRLAP_DATA_CONF || pMsg->Prim == IRLAP_UDATA_CONF ?
+ IRDA_StatStr[pMsg->IRDA_MSG_DataStatus] : TEXT("")));
+
+ return (IRLMP_Up(pMsg));
+}
+*/
+
+BYTE *
+BuildTuple(BYTE *pBuf, BYTE Pi, UINT BitField)
+{
+ *pBuf++ = Pi;
+
+ if (BitField > 0xFF)
+ {
+ *pBuf++ = 2; // Pl
+ *pBuf++ = (BYTE) (BitField >> 8);
+ *pBuf++ = (BYTE) (BitField);
+ }
+ else
+ {
+ *pBuf++ = 1; // Pl
+ *pBuf++ = (BYTE) (BitField);
+ }
+ return pBuf;
+}
+
+BYTE *
+BuildNegParms(BYTE *pBuf, IRDA_QOS_PARMS *pQos)
+{
+ pBuf = BuildTuple(pBuf, QOS_PI_BAUD, pQos->bfBaud);
+ pBuf = BuildTuple(pBuf, QOS_PI_MAX_TAT, pQos->bfMaxTurnTime);
+ pBuf = BuildTuple(pBuf, QOS_PI_DATA_SZ, pQos->bfDataSize);
+ pBuf = BuildTuple(pBuf, QOS_PI_WIN_SZ, pQos->bfWindowSize);
+ pBuf = BuildTuple(pBuf, QOS_PI_BOFS, pQos->bfBofs);
+ pBuf = BuildTuple(pBuf, QOS_PI_MIN_TAT, pQos->bfMinTurnTime);
+ pBuf = BuildTuple(pBuf, QOS_PI_DISC_THRESH, pQos->bfDisconnectTime);
+
+ return pBuf;
+}
+
+void
+StoreULAddr(BYTE Addr[], ULONG ULAddr)
+{
+ Addr[0] = (BYTE) ( 0xFF & ULAddr);
+ Addr[1] = (BYTE) ((0xFF00 & ULAddr) >> 8);
+ Addr[2] = (BYTE) ((0xFF0000 & ULAddr) >> 16);
+ Addr[3] = (BYTE) ((0xFF000000 & ULAddr) >> 24);
+}
+
+BYTE *
+_PutAddr(BYTE *pBuf, BYTE Addr[])
+{
+ *pBuf++ = Addr[0];
+ *pBuf++ = Addr[1];
+ *pBuf++ = Addr[2];
+ *pBuf++ = Addr[3];
+
+ return (pBuf);
+}
+
+void
+BuildUHdr(IRDA_MSG *pMsg, int FrameType, int Addr, int CRBit, int PFBit)
+{
+ if (pMsg->IRDA_MSG_pHdrRead != NULL)
+ {
+ pMsg->IRDA_MSG_pHdrRead -= 2;
+
+ ASSERT(pMsg->IRDA_MSG_pHdrRead >= pMsg->IRDA_MSG_Header);
+
+ *(pMsg->IRDA_MSG_pHdrRead) = (BYTE) _MAKE_ADDR(Addr, CRBit);
+ *(pMsg->IRDA_MSG_pHdrRead+1) = (BYTE) _MAKE_UCNTL(FrameType, PFBit);
+ }
+ else
+ {
+ pMsg->IRDA_MSG_pRead -= 2;
+ *(pMsg->IRDA_MSG_pRead) = (BYTE) _MAKE_ADDR(Addr, CRBit);
+ *(pMsg->IRDA_MSG_pRead+1) = (BYTE) _MAKE_UCNTL(FrameType, PFBit);
+ }
+ return;
+}
+
+void
+BuildSHdr(IRDA_MSG *pMsg, int FrameType, int Addr, int CRBit, int PFBit, int Nr)
+{
+ if (pMsg->IRDA_MSG_pHdrRead != NULL)
+ {
+ pMsg->IRDA_MSG_pHdrRead -= 2;
+
+ ASSERT(pMsg->IRDA_MSG_pHdrRead >= pMsg->IRDA_MSG_Header);
+
+ *(pMsg->IRDA_MSG_pHdrRead) = (BYTE) _MAKE_ADDR(Addr, CRBit);
+ *(pMsg->IRDA_MSG_pHdrRead+1) = (BYTE) _MAKE_SCNTL(FrameType, PFBit, Nr);
+ }
+ else
+ {
+ pMsg->IRDA_MSG_pRead -= 2;
+ *(pMsg->IRDA_MSG_pRead) = (BYTE) _MAKE_ADDR(Addr, CRBit);
+ *(pMsg->IRDA_MSG_pRead+1) = (BYTE) _MAKE_SCNTL(FrameType, PFBit, Nr);
+ }
+ return;
+}
+
+BYTE *
+Format_SNRM(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit, BYTE SAddr[],
+ BYTE DAddr[], int CAddr, IRDA_QOS_PARMS *pQos)
+{
+ BuildUHdr(pMsg, IRLAP_SNRM, Addr, CRBit, PFBit);
+
+ if (pQos != NULL)
+ {
+ pMsg->IRDA_MSG_pWrite = _PutAddr(pMsg->IRDA_MSG_pWrite, SAddr);
+ pMsg->IRDA_MSG_pWrite = _PutAddr(pMsg->IRDA_MSG_pWrite, DAddr);
+ *pMsg->IRDA_MSG_pWrite++ = CAddr << 1; // Thats what the f'n spec says
+ pMsg->IRDA_MSG_pWrite = BuildNegParms(pMsg->IRDA_MSG_pWrite, pQos);
+ }
+
+ return (pMsg->IRDA_MSG_pWrite);
+}
+
+BYTE *
+Format_DISC(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit)
+{
+ BuildUHdr(pMsg, IRLAP_DISC, Addr, CRBit, PFBit);
+
+ return (pMsg->IRDA_MSG_pWrite);
+}
+
+BYTE *
+Format_UI(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit)
+{
+ BuildUHdr(pMsg, IRLAP_UI, Addr, CRBit, PFBit);
+
+ return (pMsg->IRDA_MSG_pWrite);
+}
+
+BYTE *
+Format_DscvXID(IRDA_MSG *pMsg, int ConnAddr, int CRBit, int PFBit,
+ IRLAP_XID_DSCV_FORMAT *pXIDFormat,
+ CHAR DscvInfo[], int DscvInfoLen)
+{
+ if (pMsg->IRDA_MSG_pHdrRead != NULL)
+ {
+ pMsg->IRDA_MSG_pHdrRead -= 2;
+
+ ASSERT(pMsg->IRDA_MSG_pHdrRead >= pMsg->IRDA_MSG_Header);
+
+ *(pMsg->IRDA_MSG_pHdrRead) = (BYTE) _MAKE_ADDR(ConnAddr, CRBit);
+ if (CRBit)
+ *(pMsg->IRDA_MSG_pHdrRead+1)=
+ (BYTE) _MAKE_UCNTL(IRLAP_XID_CMD, PFBit);
+ else
+ *(pMsg->IRDA_MSG_pHdrRead+1)=
+ (BYTE) _MAKE_UCNTL(IRLAP_XID_RSP, PFBit);
+ }
+ else
+ {
+ pMsg->IRDA_MSG_pRead -= 2;
+ *(pMsg->IRDA_MSG_pRead) = (BYTE) _MAKE_ADDR(ConnAddr, CRBit);
+ if (CRBit)
+ *(pMsg->IRDA_MSG_pRead+1)=
+ (BYTE) _MAKE_UCNTL(IRLAP_XID_CMD, PFBit);
+ else
+ *(pMsg->IRDA_MSG_pRead+1)=
+ (BYTE) _MAKE_UCNTL(IRLAP_XID_RSP, PFBit);
+ }
+
+ *pMsg->IRDA_MSG_pWrite++ = IRLAP_XID_DSCV_FORMAT_ID;
+
+ memcpy(pMsg->IRDA_MSG_pWrite, (CHAR *) pXIDFormat,
+ sizeof(IRLAP_XID_DSCV_FORMAT) - 1); // Subtract for FirstDscvByte
+ // in structure
+ pMsg->IRDA_MSG_pWrite += sizeof(IRLAP_XID_DSCV_FORMAT) - 1;
+
+ if (DscvInfo != NULL)
+ {
+ memcpy(pMsg->IRDA_MSG_pWrite, DscvInfo, DscvInfoLen);
+ pMsg->IRDA_MSG_pWrite += DscvInfoLen;
+ }
+
+ return (pMsg->IRDA_MSG_pWrite);
+}
+
+BYTE *
+Format_TEST(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit,
+ BYTE SAddr[], BYTE DAddr[])
+{
+ BuildUHdr(pMsg, IRLAP_TEST, Addr, CRBit, PFBit);
+
+ pMsg->IRDA_MSG_pWrite = _PutAddr(pMsg->IRDA_MSG_pWrite, SAddr);
+ pMsg->IRDA_MSG_pWrite = _PutAddr(pMsg->IRDA_MSG_pWrite, DAddr);
+
+ return (pMsg->IRDA_MSG_pWrite);
+}
+
+BYTE *
+Format_RNRM(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit)
+{
+ BuildUHdr(pMsg, IRLAP_RNRM, Addr, CRBit, PFBit);
+
+ return (pMsg->IRDA_MSG_pWrite);
+}
+
+BYTE *
+Format_UA(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit, BYTE SAddr[],
+ BYTE DAddr[], IRDA_QOS_PARMS *pQos)
+{
+ BuildUHdr(pMsg, IRLAP_UA, Addr, CRBit, PFBit);
+
+ if (SAddr != NULL)
+ {
+ pMsg->IRDA_MSG_pWrite = _PutAddr(pMsg->IRDA_MSG_pWrite, SAddr);
+ }
+ if (DAddr != NULL)
+ {
+ pMsg->IRDA_MSG_pWrite = _PutAddr(pMsg->IRDA_MSG_pWrite, DAddr);
+ }
+
+ if (pQos != NULL)
+ pMsg->IRDA_MSG_pWrite = BuildNegParms(pMsg->IRDA_MSG_pWrite, pQos);
+
+ return (pMsg->IRDA_MSG_pWrite);
+}
+
+BYTE *
+Format_FRMR(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit,
+ IRLAP_FRMR_FORMAT *pFormat)
+{
+ BuildUHdr(pMsg, IRLAP_FRMR, Addr, CRBit, PFBit);
+
+ memcpy(pMsg->IRDA_MSG_pWrite, (CHAR *)pFormat,sizeof(IRLAP_FRMR_FORMAT));
+ pMsg->IRDA_MSG_pWrite += sizeof(IRLAP_FRMR_FORMAT);
+
+ return (pMsg->IRDA_MSG_pWrite);
+}
+
+BYTE *
+Format_DM(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit)
+{
+ BuildUHdr(pMsg, IRLAP_DM, Addr, CRBit, PFBit);
+
+ return (pMsg->IRDA_MSG_pWrite);
+}
+
+BYTE *
+Format_RD(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit)
+{
+ BuildUHdr(pMsg, IRLAP_RD, Addr, CRBit, PFBit);
+
+ return (pMsg->IRDA_MSG_pWrite);
+}
+
+BYTE *
+Format_RR(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit, int Nr)
+{
+ BuildSHdr(pMsg, IRLAP_RR, Addr, CRBit, PFBit, Nr);
+
+ return (pMsg->IRDA_MSG_pWrite);
+}
+
+BYTE *
+Format_RNR(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit, int Nr)
+{
+ BuildSHdr(pMsg, IRLAP_RNR, Addr, CRBit, PFBit, Nr);
+
+ return (pMsg->IRDA_MSG_pWrite);
+}
+
+BYTE *
+Format_REJ(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit, int Nr)
+{
+ BuildSHdr(pMsg, IRLAP_REJ, Addr, CRBit, PFBit, Nr);
+
+ return (pMsg->IRDA_MSG_pWrite);
+}
+
+BYTE *
+Format_SREJ(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit, int Nr)
+{
+ BuildSHdr(pMsg, IRLAP_SREJ, Addr, CRBit, PFBit, Nr);
+
+ return (pMsg->IRDA_MSG_pWrite);
+}
+
+BYTE *
+Format_I(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit, int Nr, int Ns)
+{
+ if (pMsg->IRDA_MSG_pHdrRead != NULL)
+ {
+ pMsg->IRDA_MSG_pHdrRead -= 2;
+
+ ASSERT(pMsg->IRDA_MSG_pHdrRead >= pMsg->IRDA_MSG_Header);
+
+ *(pMsg->IRDA_MSG_pHdrRead) = (BYTE) _MAKE_ADDR(Addr, CRBit);
+ *(pMsg->IRDA_MSG_pHdrRead+1) = (BYTE) (((Ns & 7) << 1) +
+ ((PFBit & 1)<< 4) + (Nr <<5));
+ }
+ else
+ {
+ pMsg->IRDA_MSG_pRead -= 2;
+ *(pMsg->IRDA_MSG_pRead) = (BYTE) _MAKE_ADDR(Addr, CRBit);
+ *(pMsg->IRDA_MSG_pRead+1) = (BYTE) (((Ns & 7) << 1) +
+ ((PFBit & 1)<< 4) + (Nr <<5));
+ }
+ return (pMsg->IRDA_MSG_pWrite);
+}
+
+
+// TEMP
+UINT IrlmpUp(PVOID IrlmpContext, PIRDA_MSG pIMsg)
+{
+ return 0;
+}
diff --git a/private/ntos/tdi/irda/irlap/irlapio.h b/private/ntos/tdi/irda/irlap/irlapio.h
new file mode 100644
index 000000000..f65d390eb
--- /dev/null
+++ b/private/ntos/tdi/irda/irlap/irlapio.h
@@ -0,0 +1,32 @@
+/*****************************************************************************
+*
+* Copyright (c) 1995 Microsoft Corporation
+*
+* File: irlapio.h
+*
+* Description: prototypes for IRLAP I/O routines
+*
+* Author: mbert
+*
+* Date: 4/25/95
+*
+*/
+void SetMsgPointers(PIRLAP_CB, PIRDA_MSG);
+UINT SendDscvXIDCmd(PIRLAP_CB);
+UINT SendDscvXIDRsp(PIRLAP_CB);
+UINT SendSNRM(PIRLAP_CB, BOOL);
+UINT SendUA(PIRLAP_CB, BOOL);
+UINT SendDM(PIRLAP_CB);
+UINT SendRD(PIRLAP_CB);
+UINT SendRR(PIRLAP_CB);
+UINT SendRR_RNR(PIRLAP_CB);
+UINT SendDISC(PIRLAP_CB);
+UINT SendRNRM(PIRLAP_CB);
+UINT SendIFrame(PIRLAP_CB, PIRDA_MSG, int, int);
+UINT SendSREJ(PIRLAP_CB, int);
+UINT SendREJ(PIRLAP_CB);
+UINT SendFRMR(PIRLAP_CB, IRLAP_FRMR_FORMAT *);
+UINT SendUIFrame(PIRLAP_CB, PIRDA_MSG);
+UINT SendFrame(PIRLAP_CB, PIRDA_MSG);
+UINT _IRLMP_Up(PIRDA_MSG);
+
diff --git a/private/ntos/tdi/irda/irlap/irlaplog.c b/private/ntos/tdi/irda/irlap/irlaplog.c
new file mode 100644
index 000000000..ae95fa8c0
--- /dev/null
+++ b/private/ntos/tdi/irda/irlap/irlaplog.c
@@ -0,0 +1,265 @@
+/*****************************************************************************
+*
+* Copyright (c) 1995 Microsoft Corporation
+*
+* File: irlaplog.c
+*
+* Description: IRLAP state machine logging and errors
+*
+* Author: mbert
+*
+* Date: 4/15/95
+*
+*/
+#include <irda.h>
+#include <irdalink.h>
+#include <irlap.h>
+#include <irlapp.h>
+#include <irlaplog.h>
+#include <decdirda.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define _IRLAPLOG_C_
+
+#ifdef DEBUG
+
+
+TCHAR *DecodeIRDA(int *pFrameType,// returned frame type (-1=bad frame)
+ BYTE *pFrameBuf, // pointer to buffer containing IRLAP frame
+ UINT FrameLen, // length of buffer
+ TCHAR *pOutStr, // string where decoded packet is placed
+ UINT DecodeLayer,// 1,LAP only, 2 LAP/LMP, 3, LAP/LMP/TTP
+ BOOL fNoConnAddr,// TRUE->Don't show connection address in str
+ int DispMode )
+{
+ *pOutStr = TEXT('\0');
+
+ return pOutStr;
+}
+TCHAR _ABuf[512];
+
+#ifndef PEG
+TCHAR _DecodeStr1[1000];
+TCHAR _DecodeStr2[1000];
+#else
+TCHAR _DecodeStr1[] = TEXT("(null)");
+TCHAR _DecodeStr2[] = TEXT("(null)");
+#endif
+
+int _FrameType;
+
+int ActCnt[10];
+
+int vNestedEvent = 0;
+
+// Keep in sync with IRLAP_STATE in irlap.h
+TCHAR *IRLAP_StateStr[] = {
+ TEXT("NDM"),
+ TEXT("DSCV_MEDIA_SENSE"),
+ TEXT("DSCV_QUERY"),
+ TEXT("DSCV_REPLY"),
+ TEXT("CONN_MEDIA_SENSE"),
+ TEXT("SNRM_SENT"),
+ TEXT("BACKOFF_WAIT"),
+ TEXT("SNRM_RECEIVED"),
+ TEXT("P_XMIT"),
+ TEXT("P_RECV"),
+ TEXT("P_DISCONNECT_PEND"),
+ TEXT("P_CLOSE"),
+ TEXT("S_NRM"),
+ TEXT("S_DISCONNECT_PEND"),
+ TEXT("S_ERROR"),
+ TEXT("S_CLOSE")
+};
+
+// Keep in sync with IRDA_SERVICE_PRIM in irda.h
+TCHAR *IRDA_PrimStr[] =
+{
+ TEXT("MAC_DATA_REQ"),
+ TEXT("MAC_DATA_IND"),
+ TEXT("MAC_CONTROL_REQ"),
+ TEXT("MAC_CONTROL_CONF"),
+ TEXT("IRLAP_DISCOVERY_REQ"),
+ TEXT("IRLAP_DISCOVERY_IND"),
+ TEXT("IRLAP_DISCOVERY_CONF"),
+ TEXT("IRLAP_CONNECT_REQ"),
+ TEXT("IRLAP_CONNECT_IND"),
+ TEXT("IRLAP_CONNECT_RESP"),
+ TEXT("IRLAP_CONNECT_CONF"),
+ TEXT("IRLAP_DISCONNECT_REQ"),
+ TEXT("IRLAP_DISCONNECT_IND"),
+ TEXT("IRLAP_DATA_REQ"),
+ TEXT("IRLAP_DATA_IND"),
+ TEXT("IRLAP_DATA_CONF"),
+ TEXT("IRLAP_UDATA_REQ"),
+ TEXT("IRLAP_UDATA_IND"),
+ TEXT("IRLAP_UDATA_CONF"),
+ TEXT("IRLAP_STATUS_IND"),
+ TEXT("IRLAP_FLOWON_REQ"),
+ TEXT("IRLAP_FLOWON_IND")
+ TEXT("IRLMP_DISCOVERY_REQ"),
+ TEXT("IRLMP_DISCOVERY_CONF"),
+ TEXT("IRLMP_CONNECT_REQ"),
+ TEXT("IRLMP_CONNECT_IND"),
+ TEXT("IRLMP_CONNECT_RESP"),
+ TEXT("IRLMP_CONNECT_CONF"),
+ TEXT("IRLMP_DISCONNECT_REQ"),
+ TEXT("IRLMP_DISCONNECT_IND"),
+ TEXT("IRLMP_DATA_REQ"),
+ TEXT("IRLMP_DATA_IND"),
+ TEXT("IRLMP_DATA_CONF"),
+ TEXT("IRLMP_UDATA_REQ"),
+ TEXT("IRLMP_UDATA_IND"),
+ TEXT("IRLMP_UDATA_CONF"),
+ TEXT("IRLMP_ACCESSMODE_REQ"),
+ TEXT("IRLMP_ACCESSMODE_IND"),
+ TEXT("IRLMP_ACCESSMODE_CONF"),
+ TEXT("IRLMP_FLOWON_REQ"),
+ TEXT("IRLMP_FLOWON_IND")
+};
+
+// keep in sync with IRDA_ServiceStatus in irda.h
+TCHAR *IRDA_StatStr[] =
+{
+ TEXT(" - MEDIA_BUSY"),
+ TEXT(" - MEDIA_CLEAR"),
+ TEXT(" - DISCOVERY_COLLISION"),
+ TEXT(" - REMOTE_DISCOVERY_IN_PROGRESS"),
+ TEXT(" - REMOTE_CONNECT_IN_PROGRSS"),
+ TEXT(" - DISCOVERY_COMPLETED"),
+ TEXT(" - REMOTE_CONNECTION_IN_PROGRESS"),
+ TEXT(" - CONNECTION_COMPLETED"),
+ TEXT(" - REMOTE_INITIATED"),
+ TEXT(" - PRIMARY_CONFLICT"),
+ TEXT(" - DISCONNECT_COMPLETE"),
+ TEXT(" - NO_RESPONSE"),
+ TEXT(" - IRLAP_DECLINE_RESET"),
+ TEXT(" - DATA_REQUEST_COMPLETED"),
+ TEXT(" - DATA_REQUEST_FAILED_LINK_RESET"),
+ TEXT(" - DATA_REQUEST_FAILED_REMOTE_BUSY")
+};
+
+// Keep in sync with MAC_CONTROL_OPERATION in irda.h
+TCHAR *MAC_OpStr[] =
+{
+ TEXT("initialize link"),
+ TEXT("shutdown link"),
+ TEXT("reconfig link"),
+ TEXT("media sense")
+};
+
+TCHAR
+*FrameToStr(IRDA_MSG *pMsg)
+{
+#ifndef PEG
+ BYTE *ptr;
+ int i = 0;
+ int j;
+ TCHAR *pD1 = _DecodeStr1;
+ TCHAR *pD2 = _DecodeStr2;
+
+ // copy the frame to a contiguous buffer
+
+ ptr = pMsg->IRDA_MSG_pHdrRead;
+ while (ptr != pMsg->IRDA_MSG_pHdrWrite)
+ {
+ _ABuf[i++] = *ptr++;
+ }
+ ptr = pMsg->IRDA_MSG_pRead;
+ while (ptr != pMsg->IRDA_MSG_pWrite)
+ {
+ _ABuf[i++] = *ptr++;
+ }
+
+ DecodeIRDA(&_FrameType, (char *)_ABuf, i, _DecodeStr1, 2, FALSE, 1);
+
+ // insert spaces and break-up into multiple lines
+ i = 0;
+ do
+ {
+ if (i++%69 == 0)
+ {
+ *pD2++ = TEXT('\r');
+ *pD2++ = TEXT('\n');
+ for (j = 0; j<7;j++)
+ {
+ *pD2++ = TEXT(' ');
+ }
+ }
+ *pD2++ = *pD1++;
+ } while (*pD1 != TEXT('\0'));
+
+ *pD2 = TEXT('\0');
+#endif
+ return (_DecodeStr2);
+}
+void
+IRLAP_EventLogStart(PIRLAP_CB pIrlapCb, TCHAR *pFormat, ...)
+{
+ va_list ArgList;
+
+ va_start (ArgList, pFormat);
+
+ if (++vNestedEvent == 1)
+ {
+ DEBUGMSG(DBG_IRLAPLOG, (TEXT("----------------\r\n")));
+ }
+ else
+ {
+ DEBUGMSG(DBG_IRLAPLOG, (TEXT("!!!!!!!!!!!!!!!!\r\n")));
+ }
+
+ DEBUGMSG(DBG_IRLAPLOG, (TEXT("Ev%d: "), vNestedEvent));
+
+ ActCnt[vNestedEvent] = 0;
+
+ vsprintf(_ABuf, pFormat, ArgList);
+ DEBUGMSG(DBG_IRLAPLOG, (_ABuf));
+
+ DEBUGMSG(DBG_IRLAPLOG, (TEXT("\r\nStart State: %s\r\nActions:\r\n"),
+ IRLAP_StateStr[pIrlapCb->State]));
+
+ va_end (ArgList);
+}
+
+void __cdecl
+IRLAP_LogAction(PIRLAP_CB pIrlapCb, TCHAR *pFormat, ...)
+{
+ va_list ArgList;
+
+ va_start (ArgList, pFormat);
+
+ DEBUGMSG(DBG_IRLAPLOG, (TEXT(" %d. "), ++ActCnt[vNestedEvent]));
+
+ vsprintf(_ABuf, pFormat, ArgList);
+ DEBUGMSG(DBG_IRLAPLOG, (_ABuf));
+
+ DEBUGMSG(DBG_IRLAPLOG, (TEXT("\n")));
+
+ va_end (ArgList);
+}
+
+#define PRINT_IF_TRUE(bool, str) (bool == TRUE ? str : TEXT(""))
+
+void
+IRLAP_EventLogComplete(PIRLAP_CB pIrlapCb)
+{
+ DEBUGMSG(DBG_IRLAPLOG,
+ (TEXT("Vs=%d Vr=%d RxWin(%d,%d) TxWin(%d,%d) TxListLen=%d\r\n"),
+ pIrlapCb->Vs, pIrlapCb->Vr,
+ pIrlapCb->RxWin.Start, pIrlapCb->RxWin.End,
+ pIrlapCb->TxWin.Start, pIrlapCb->TxWin.End,
+ pIrlapCb->TxMsgList.Len));
+
+ DEBUGMSG(DBG_IRLAPLOG, (TEXT("Ev%d End St: %s\r\n"),
+ vNestedEvent--, IRLAP_StateStr[pIrlapCb->State]));
+
+ if (vNestedEvent > 0)
+ {
+ DEBUGMSG(DBG_IRLAPLOG, (TEXT("!!!!!!!!!!!!!!!!\r\n")));
+ }
+}
+
+#endif
diff --git a/private/ntos/tdi/irda/irlap/irlapp.h b/private/ntos/tdi/irda/irlap/irlapp.h
new file mode 100644
index 000000000..bd2498263
--- /dev/null
+++ b/private/ntos/tdi/irda/irlap/irlapp.h
@@ -0,0 +1,299 @@
+/*****************************************************************************
+*
+* Copyright (c) 1995 Microsoft Corporation
+*
+* File: irlap.h
+*
+* Description: IRLAP Protocol and control block definitions
+*
+* Author: mbert
+*
+* Date: 4/15/95
+*
+*/
+
+#define IRLAP_MEDIA_SENSE_TIME 500
+#define IRLAP_SLOT_TIMEOUT 50
+#define IRLAP_DSCV_SENSE_TIME 30
+
+// XID Format
+#define IRLAP_XID_DSCV_FORMAT_ID 0x01
+#define IRLAP_XID_NEGPARMS_FORMAT_ID 0x02
+typedef struct
+{
+ BYTE SrcAddr[IRDA_DEV_ADDR_LEN];
+ BYTE DestAddr[IRDA_DEV_ADDR_LEN];
+ BYTE NoOfSlots:2;
+ BYTE GenNewAddr:1;
+ BYTE Reserved:5;
+ BYTE SlotNo;
+ BYTE Version;
+ BYTE FirstDscvInfoByte;
+} IRLAP_XID_DSCV_FORMAT;
+
+// Frame Reject Format
+typedef struct
+{
+ BYTE CntlField;
+ BYTE Fill1:1;
+ BYTE Vs:3;
+ BYTE CRBit:1;
+ BYTE Vr:3;
+ BYTE W:1;
+ BYTE X:1;
+ BYTE Y:1;
+ BYTE Z:1;
+ BYTE Fill2:4;
+} IRLAP_FRMR_FORMAT;
+
+// SNRM Frame Format
+typedef struct
+{
+ BYTE SrcAddr[IRDA_DEV_ADDR_LEN];
+ BYTE DestAddr[IRDA_DEV_ADDR_LEN];
+ BYTE ConnAddr; // actually shifted for CRBit -> STUPID !!
+ BYTE FirstQosByte;
+} IRLAP_SNRM_FORMAT;
+
+// UA Frame Format
+typedef struct
+{
+ BYTE SrcAddr[IRDA_DEV_ADDR_LEN];
+ BYTE DestAddr[IRDA_DEV_ADDR_LEN];
+ BYTE FirstQosByte;
+} IRLAP_UA_FORMAT;
+
+#define IRLAP_MAX_TX_MSG_LIST_LEN 8
+#define IRLAP_MAX_DATA_SIZE 4096
+#define IRLAP_MAX_SLOTS 16
+#define IRLAP_DEFAULT_BAUD 9600
+#define IRLAP_DEFAULT_DATA_SIZE 64
+#define IRLAP_DEFAULT_MAX_TAT 500
+#define IRLAP_DEFAULT_BOFS 11
+#define IRLAP_DEFAULT_WIN_SIZE 1
+
+// Macros for extracting various fields
+#define IRLAP_GET_ADDR(addr) (addr >> 1)
+#define IRLAP_GET_CRBIT(addr) (addr & 1)
+#define IRLAP_GET_PFBIT(cntl) ((cntl >>4) & 1)
+#define IRLAP_GET_UCNTL(cntl) (cntl & 0xEF)
+#define IRLAP_GET_SCNTL(cntl) (cntl & 0x0F)
+#define IRLAP_FRAME_TYPE(cntl) (cntl & 0x01 ? (cntl & 3) : 0)
+#define IRLAP_GET_NR(cntl) ((cntl & 0xE0) >> 5)
+#define IRLAP_GET_NS(cntl) ((cntl & 0xE) >> 1)
+
+// IRLAP constants
+#define IRLAP_BROADCAST_CONN_ADDR 0x7F
+#define IRLAP_END_DSCV_SLOT_NO 0xFF
+#define IRLAP_CMD 1
+#define IRLAP_RSP 0
+#define IRLAP_PFBIT_SET 1
+#define IRLAP_PFBIT_CLEAR 0
+#define IRLAP_GEN_NEW_ADDR 1
+#define IRLAP_NO_NEW_ADDR 0
+
+// Macro for creating Number of Slots of Discovery Flags Field of XID Format
+// if S(Slots) <= 1 return 0, <= 6 return 1, <= 8 return 2, else return 3
+#define IRLAP_SLOT_FLAG(S) (S <= 1 ? 0 : (S <= 6 ? 1 : (S <= 8 ? 2 : 3)))
+
+int _inline IRLAP_RAND(int Min, int Max)
+{
+ LARGE_INTEGER li;
+
+ KeQueryTickCount(&li);
+
+ return ((li.LowPart % (Max+1-Min)) + Min);
+}
+
+// Backoff time is a random time between 0.5 and 1.5 times the time to
+// send a SNRM. _SNRM_TIME() is actually half (1000ms/2) time to send
+// SNRM_LEN of characters at 9600 (9600/10 bits per char).
+#define _SNRM_LEN 32
+#define _SNRM_TIME() (_SNRM_LEN*500/960)
+#define IRLAP_BACKOFF_TIME() IRLAP_RAND(_SNRM_TIME(), 3*_SNRM_TIME())
+
+#define QOS_PI_BAUD 0x01
+#define QOS_PI_MAX_TAT 0x82
+#define QOS_PI_DATA_SZ 0x83
+#define QOS_PI_WIN_SZ 0x84
+#define QOS_PI_BOFS 0x85
+#define QOS_PI_MIN_TAT 0x86
+#define QOS_PI_DISC_THRESH 0x08
+
+
+#define IRLAP_I_FRAME 0x00
+#define IRLAP_S_FRAME 0x01
+#define IRLAP_U_FRAME 0x03
+
+// Unnumbered Frame types with P/F bit set to 0
+#define IRLAP_UI 0x03
+#define IRLAP_XID_CMD 0x2f
+#define IRLAP_TEST 0xe3
+#define IRLAP_SNRM 0x83
+#define IRLAP_RNRM 0x83
+#define IRLAP_DISC 0x43
+#define IRLAP_RD 0x43
+#define IRLAP_UA 0x63
+#define IRLAP_FRMR 0x87
+#define IRLAP_DM 0x0f
+#define IRLAP_XID_RSP 0xaf
+
+// Supervisory Frames
+#define IRLAP_RR 0x01
+#define IRLAP_RNR 0x05
+#define IRLAP_REJ 0x09
+#define IRLAP_SREJ 0x0d
+
+#define _MAKE_ADDR(Addr, CRBit) ((Addr << 1) + (CRBit & 1))
+#define _MAKE_UCNTL(Cntl, PFBit) (Cntl + ((PFBit & 1)<< 4))
+#define _MAKE_SCNTL(Cntl, PFBit, Nr) (Cntl + ((PFBit & 1)<< 4) + (Nr <<5))
+
+#define IRLAP_CB_SIG 0x7f2a364bUL
+
+// IRLAP Control Block
+typedef struct
+{
+ IRDA_MSG *pMsg[IRLAP_MOD];
+ UINT Start;
+ UINT End;
+#ifdef TEMPERAMENTAL_SERIAL_DRIVER
+ int FCS[IRLAP_MOD];
+#endif
+} IRLAP_WINDOW;
+
+typedef enum
+{
+ PRIMARY,
+ SECONDARY
+} IRLAP_STN_TYPE;
+
+typedef enum // KEEP IN SYNC with IRLAP_StateStr in irlaplog.c
+{
+ NDM, // Normal Disconnect Mode
+ DSCV_MEDIA_SENSE, // Discovery Media Sense (Before Discovery)
+ DSCV_QUERY, // Discovery Query (Discovery initiated)
+ DSCV_REPLY, // Discovery Reply (Received DSCV XID cmd from Remote)
+ CONN_MEDIA_SENSE, // Connect Media Sense (Before connection estab)
+ SNRM_SENT, // SNRM sent - waiting for UA or DM from Remote
+ BACKOFF_WAIT, // Waiting random backoff before sending next SNRM
+ SNRM_RECEIVED, // SNRM rcvd - waiting for response from upper layer
+ P_XMIT, // Primary transmit
+ P_RECV, // Primary receive
+ P_DISCONNECT_PEND, // Upper layer request disconnect while in P_RECV
+ P_CLOSE, // Sent DISC, waiting for response
+ S_NRM, // Secondary Normal Response Mode XMIT/RECV
+ S_DISCONNECT_PEND, // Upper layer request disconnect while in S_NRM
+ S_ERROR, // Waiting for PF bit then send a FRMR
+ S_CLOSE, // Requested disconnect (RD) waiting for DISC command
+} IRLAP_STATE;
+
+typedef struct IrlapControlBlock
+{
+ IRLAP_STATE State;
+ IRDA_DEVICE LocalDevice;
+ IRDA_DEVICE RemoteDevice;
+ PIRDA_LINK_CB pIrdaLinkCb;
+ IRDA_QOS_PARMS LocalQos; // QOS from LMP
+ IRDA_QOS_PARMS RemoteQos; // QOS of remote taken from SNRM/UA
+ IRDA_QOS_PARMS NegotiatedQos; // Union of remote and local QOS
+ int Baud; // Type 0 negotiation parm
+ int DisconnectTime;// Type 0 negotiation parm
+ int ThresholdTime; // Type 0 negotiotion parm
+ int LocalMaxTAT; // Type 1 negotiation parm
+ int LocalDataSize; // Type 1 negotiation parm
+ int LocalWinSize; // Type 1 negotiation parm
+ int LocalNumBOFS; // Type 1 negotiation parm
+ int RemoteMaxTAT; // Type 1 negotiation parm
+ int RemoteDataSize;// Type 1 negotiation parm
+ int RemoteWinSize; // Type 1 negotiation parm
+ int RemoteNumBOFS; // Type 1 negotiation parm
+ int RemoteMinTAT; // Type 1 negotiation parm
+ IRLAP_STN_TYPE StationType; // PRIMARY or SECONDARY
+ int ConnAddr; // Connection Address
+ int SNRMConnAddr; // Connection address contained in SNRM
+ // save it until get CONNECT_RESP
+ int CRBit; // Primary = 1, Secondary = 0
+ int RespSlot; // Secondary. Slot to respond in
+ int SlotCnt; // Primary. Current slot number
+ int MaxSlot; // Maximum slots to send in Dscv
+ int RemoteMaxSlot; // Number of Dscv's remote will send
+ LIST_ENTRY DevList; // Discovered device list
+ UINT Vs; // send state variable
+ UINT Vr; // receive state variable
+ IRLAP_WINDOW RxWin; // Holds out of sequence rxd frames
+ IRLAP_WINDOW TxWin; // Holds unacked txd frames
+ IRDA_MSG_LIST TxMsgList; // DATA_REQ, UDATA_REQ queued here
+ int RetryCnt; // Count of number of retrans of DSCV,SNRM
+ int N1; // const# retries before sending status up
+ int N2; // const# retries before disconnecting
+ int N3; // const# of connection retries
+ IRDA_TIMER SlotTimer;
+ IRDA_TIMER QueryTimer;
+ IRDA_TIMER PollTimer;
+ IRDA_TIMER FinalTimer;
+ IRDA_TIMER WDogTimer;
+ IRDA_TIMER BackoffTimer;
+ int WDogExpCnt; // Count of WDog expirations
+ int StatusSent; // Status ind has been sent
+ CRITICAL_SECTION CS; // Control block synchronization
+ BOOL GenNewAddr; // Flag indicating whether to set new addr
+ BOOL DscvRespSent; // Secondary. Sent XID Discv response
+ BOOL RemoteBusy; // Remote has sent a RNR
+ BOOL LocalBusy; // Local busy condition, we sent RNR
+ BOOL ClrLocalBusy; // Send RR
+ BOOL LocalDiscReq; // why 2ndary got DISC
+ BOOL ConnAfterClose;// Conn req while in p_close
+ BOOL DscvAfterClose;// Dscv_req while in p_close
+ BOOL NoResponse; // Final/WD timer exp'd, used with RetryCnt
+ UINT Sig; // Signature
+} IRLAP_CB, *PIRLAP_CB;
+
+#define LINE_CAPACITY(icb) (icb->RemoteWinSize * \
+ (icb->RemoteDataSize + \
+ 6+icb->RemoteNumBOFS))
+
+BYTE *BuildNegParms(BYTE *pBuf, IRDA_QOS_PARMS *pQos);
+
+void StoreULAddr(BYTE Addr[], ULONG ULAddr);
+
+BYTE *Format_SNRM(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit,
+ BYTE SAddr[], BYTE DAddr[], int CAddr,
+ IRDA_QOS_PARMS *pQos);
+
+BYTE *Format_DISC(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit);
+
+BYTE *Format_UI(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit);
+
+BYTE *Format_DscvXID(IRDA_MSG *pMsg, int ConnAddr, int CRBit, int PFBit,
+ IRLAP_XID_DSCV_FORMAT *pXidFormat, CHAR DscvInfo[],
+ int Len);
+
+BYTE *Format_TEST(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit,
+ BYTE SAddr[], BYTE DAddr[]);
+
+BYTE *Format_RNRM(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit);
+
+BYTE *Format_UA(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit,
+ BYTE SAddr[], BYTE DAddr[], IRDA_QOS_PARMS *pQos);
+
+BYTE *Format_FRMR(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit,
+ IRLAP_FRMR_FORMAT *pFormat);
+
+BYTE *Format_DM(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit);
+
+BYTE *Format_RD(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit);
+
+BYTE *Format_RR(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit, int Nr);
+
+BYTE *Format_RNR(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit, int Nr);
+
+BYTE *Format_REJ(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit, int Nr);
+
+BYTE *Format_SREJ(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit, int Nr);
+
+BYTE * Format_I(IRDA_MSG *pMsg, int Addr, int CRBit,
+ int PFBit, int Nr, int Ns);
+
+int GetMyDevAddr(BOOL New);
+
+
diff --git a/private/ntos/tdi/irda/irlap/makefile b/private/ntos/tdi/irda/irlap/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/irda/irlap/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/irda/irlap/sources b/private/ntos/tdi/irda/irlap/sources
new file mode 100644
index 000000000..0f1ba5b0c
--- /dev/null
+++ b/private/ntos/tdi/irda/irlap/sources
@@ -0,0 +1,23 @@
+MAJORCOMP=ntos
+MINORCOMP=irda
+
+NTPROFILEINPUT=yes
+
+TARGETNAME=irlap
+TARGETTYPE=LIBRARY
+TARGETPATH=..\lib
+TARGETLIBS=
+
+
+INCLUDES=..\inc;..\..\..\inc;..\..\..\..\inc;
+
+C_DEFINES=$(C_DEFINES) -DNT -D_NTDRIVER_ -DRASAUTODIAL -D_PNP_POWER -DSECFLTR
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+
+SOURCES= irlap.c \
+ irlaplog.c \
+ irlapio.c
+
+
diff --git a/private/ntos/tdi/isn/dirs b/private/ntos/tdi/isn/dirs
new file mode 100644
index 000000000..8c61c4b61
--- /dev/null
+++ b/private/ntos/tdi/isn/dirs
@@ -0,0 +1,34 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS= \
+ ipx \
+ spx \
+ nb \
+ fwd \
+ rip \
+ flt \
+ sockhelp \
+ ipxroute
+# isnext
+
+OPTIONAL_DIRS=
diff --git a/private/ntos/tdi/isn/flt/debug.c b/private/ntos/tdi/isn/flt/debug.c
new file mode 100644
index 000000000..35ee3565f
--- /dev/null
+++ b/private/ntos/tdi/isn/flt/debug.c
@@ -0,0 +1,5 @@
+#include "precomp.h"
+
+#if DBG
+ULONG DbgLevel = DEF_DBG_LEVEL;
+#endif
diff --git a/private/ntos/tdi/isn/flt/debug.h b/private/ntos/tdi/isn/flt/debug.h
new file mode 100644
index 000000000..c69bf51a9
--- /dev/null
+++ b/private/ntos/tdi/isn/flt/debug.h
@@ -0,0 +1,42 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: debug.h
+//
+// Description: Debug macros definitions
+//
+// Author: Stefan Solomon (stefans) October 4, 1993.
+//
+// Revision History:
+//
+//***
+
+#ifndef _IPXFLT_DEBUG_
+#define _IPXFLT_DEBUG_
+
+#if DBG
+extern ULONG DbgLevel;
+#define DBG_IOCTLS 0x00000001
+#define DBG_FWDIF 0x00000002
+#define DBG_IFHASH 0x00000010
+#define DBG_PKTCACHE 0x00000020
+#define DBG_PKTLOGS 0x00000100
+#define DBG_ERRORS 0x10000000
+
+#define DEF_DBG_LEVEL (DBG_IOCTLS|DBG_FWDIF|DBG_ERRORS|DBG_IFHASH)
+
+#define IpxFltDbgPrint(LEVEL,ARGS) \
+ do { \
+ if (DbgLevel & (LEVEL)) { \
+ DbgPrint ARGS; \
+ } \
+ } while (0)
+
+#else
+#define IpxFltDbgPrint(LEVEL,ARGS) do {NOTHING;} while (0)
+#endif
+
+#endif
diff --git a/private/ntos/tdi/isn/flt/dirs b/private/ntos/tdi/isn/flt/dirs
new file mode 100644
index 000000000..0dab2f056
--- /dev/null
+++ b/private/ntos/tdi/isn/flt/dirs
@@ -0,0 +1,22 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=up mp
diff --git a/private/ntos/tdi/isn/flt/driver.c b/private/ntos/tdi/isn/flt/driver.c
new file mode 100644
index 000000000..b4b8dde9b
--- /dev/null
+++ b/private/ntos/tdi/isn/flt/driver.c
@@ -0,0 +1,443 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\flt\driver.c
+
+Abstract:
+ IPX Filter driver dispatch routines
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+
+PFILE_OBJECT RouterFile;
+
+NTSTATUS
+IpxFltDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+IpxFltUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+VOID
+IpxFltCancel (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP irp
+ );
+
+/*++
+ D r i v e r E n t r y
+
+Routine Description:
+
+ Installable driver initialization entry point.
+ This entry point is called directly by the I/O system.
+
+Arguments:
+
+ DriverObject - pointer to the driver object
+
+ RegistryPath - pointer to a unicode string representing the path
+ to driver-specific key in the registry
+
+Return Value:
+
+ STATUS_SUCCESS if successful,
+ STATUS_UNSUCCESSFUL otherwise
+
+--*/
+NTSTATUS
+DriverEntry (
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ ) {
+
+ PDEVICE_OBJECT deviceObject = NULL;
+ NTSTATUS status;
+ UNICODE_STRING deviceNameUnicodeString;
+
+ IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: Driver Entry.\n"));
+
+ RtlInitUnicodeString (&deviceNameUnicodeString,
+ IPXFLT_NAME);
+
+ status = IoCreateDevice (DriverObject,
+ 0,
+ &deviceNameUnicodeString,
+ FILE_DEVICE_IPXFLT,
+ 0,
+ FALSE, // Non-Exclusive
+ &deviceObject
+ );
+
+ if (NT_SUCCESS(status)) {
+ //
+ // Create dispatch points for device control, create, close.
+ //
+ DriverObject->MajorFunction[IRP_MJ_CREATE]
+ = DriverObject->MajorFunction[IRP_MJ_CLEANUP]
+ = DriverObject->MajorFunction[IRP_MJ_CLOSE]
+ = DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]
+ = IpxFltDispatch;
+ DriverObject->DriverUnload = IpxFltUnload;
+ status = BindToFwdDriver (KernelMode);
+ if (NT_SUCCESS (status)) {
+ RouterFile = NULL;
+ return STATUS_SUCCESS;
+ }
+ else {
+ IoDeleteDevice (DriverObject->DeviceObject);
+ }
+ }
+ else
+ IpxFltDbgPrint (DBG_IOCTLS|DBG_ERRORS,
+ ("IpxFlt: Could not create device object.\n"));
+
+ return status;
+}
+
+
+
+/*++
+
+Routine Description:
+
+ Process the IRPs sent to this device.
+
+Arguments:
+
+ DeviceObject - pointer to a device object
+
+ Irp - pointer to an I/O Request Packet
+
+Return Value:
+
+
+--*/
+NTSTATUS
+IpxFltDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ ) {
+ PIO_STACK_LOCATION IrpStack;
+ PVOID inBuffer, outBuffer;
+ ULONG inpBufLength;
+ ULONG outBufLength;
+ NTSTATUS status;
+ KIRQL cancelIRQL;
+
+
+ Irp->IoStatus.Information = 0;
+ status = STATUS_SUCCESS;
+
+ //
+ // Get a pointer to the current location in the Irp. This is where
+ // the function codes and parameters are located.
+ //
+
+ IrpStack = IoGetCurrentIrpStackLocation(Irp);
+
+
+ switch (IrpStack->MajorFunction) {
+ case IRP_MJ_CREATE:
+ IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: IRP_MJ_CREATE.\n"));
+ break;
+
+ case IRP_MJ_CLOSE:
+ IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: IRP_MJ_CLOSE.\n"));
+ if (IrpStack->FileObject == RouterFile) {
+ DeleteTables ();
+ RouterFile = NULL;
+ }
+ break;
+
+ case IRP_MJ_CLEANUP:
+ IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: IRP_MJ_CLEANUP.\n"));
+ if (IrpStack->FileObject==RouterFile) {
+ IoAcquireCancelSpinLock (&cancelIRQL);
+ while (!IsListEmpty (&LogIrpQueue)) {
+ PIRP irp = CONTAINING_RECORD (LogIrpQueue.Blink,
+ IRP, Tail.Overlay.ListEntry);
+ irp->Cancel = TRUE;
+ irp->CancelIrql = cancelIRQL;
+ irp->CancelRoutine = NULL;
+ IpxFltCancel(DeviceObject, irp);
+ IoAcquireCancelSpinLock (&cancelIRQL);
+ }
+ IoReleaseCancelSpinLock(cancelIRQL);
+ }
+ break;
+
+ case IRP_MJ_DEVICE_CONTROL:
+ //
+ // Get the pointer to the input/output buffer and it's length
+ //
+ status = STATUS_INVALID_PARAMETER;
+ inpBufLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
+ outBufLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
+ switch (IrpStack->Parameters.DeviceIoControl.IoControlCode&3) {
+ case METHOD_BUFFERED:
+ inBuffer = outBuffer = Irp->AssociatedIrp.SystemBuffer;
+ break;
+
+ case METHOD_IN_DIRECT:
+ case METHOD_OUT_DIRECT:
+ inBuffer = Irp->AssociatedIrp.SystemBuffer;
+ if (outBufLength>0) {
+ outBuffer = MmGetSystemAddressForMdl (Irp->MdlAddress);
+ }
+ else {
+ outBuffer = NULL;
+ }
+ break;
+ default:
+ IpxFltDbgPrint (DBG_IOCTLS|DBG_ERRORS, ("IpxFlt: Unsupported io method.\n"));
+ goto DispatchExit;
+ }
+
+
+ if (IrpStack->FileObject==RouterFile) {
+ switch (IrpStack->Parameters.DeviceIoControl.IoControlCode) {
+ case IOCTL_FLT_IF_SET_IN_FILTERS:
+ IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: IOCTL_FLT_IF_SET_IN_FILTERS.\n"));
+ if ((inpBufLength==sizeof (FLT_IF_SET_PARAMS))
+ && (((PFLT_IF_SET_PARAMS)inBuffer)->FilterSize
+ ==sizeof (IPX_TRAFFIC_FILTER_INFO)))
+ status = SetInFilters (
+ ((PFLT_IF_SET_PARAMS)inBuffer)->InterfaceIndex,
+ ((PFLT_IF_SET_PARAMS)inBuffer)->FilterAction,
+ outBufLength,
+ (PIPX_TRAFFIC_FILTER_INFO)outBuffer);
+
+ break;
+
+ case IOCTL_FLT_IF_SET_OUT_FILTERS:
+ IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: IOCTL_FLT_IF_SET_OUT_FILTERS.\n"));
+ if ((inpBufLength==sizeof (FLT_IF_SET_PARAMS))
+ && (((PFLT_IF_SET_PARAMS)inBuffer)->FilterSize
+ ==sizeof (IPX_TRAFFIC_FILTER_INFO)))
+ status = SetOutFilters (
+ ((PFLT_IF_SET_PARAMS)inBuffer)->InterfaceIndex,
+ ((PFLT_IF_SET_PARAMS)inBuffer)->FilterAction,
+ outBufLength,
+ (PIPX_TRAFFIC_FILTER_INFO)outBuffer);
+
+ break;
+ case IOCTL_FLT_IF_RESET_IN_FILTERS:
+ IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: IOCTL_FLT_IF_RESET_IN_FILTERS.\n"));
+ if ((inpBufLength==sizeof (ULONG))
+ && (outBufLength==0))
+ status = SetInFilters (
+ *((PULONG)inBuffer),
+ IPX_TRAFFIC_FILTER_ACTION_DENY,
+ 0, NULL);
+
+ break;
+ case IOCTL_FLT_IF_RESET_OUT_FILTERS:
+ IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: IOCTL_FLT_IF_RESET_OUT_FILTERS.\n"));
+ if ((inpBufLength==sizeof (ULONG))
+ && (outBufLength==0))
+ status = SetOutFilters (
+ *((PULONG)inBuffer),
+ IPX_TRAFFIC_FILTER_ACTION_DENY,
+ 0, NULL);
+
+ break;
+ case IOCTL_FLT_IF_GET_IN_FILTERS:
+ IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: IOCTL_FLT_IF_GET_IN_FILTERS.\n"));
+ if ((inpBufLength==sizeof (ULONG))
+ && (outBufLength>=sizeof (FLT_IF_GET_PARAMS))) {
+ Irp->IoStatus.Information
+ = outBufLength-sizeof (FLT_IF_GET_PARAMS);
+ status = GetInFilters (
+ *((PULONG)inBuffer),
+ &((PFLT_IF_GET_PARAMS)outBuffer)->FilterAction,
+ &((PFLT_IF_GET_PARAMS)outBuffer)->TotalSize,
+ (PIPX_TRAFFIC_FILTER_INFO)
+ ((PUCHAR)outBuffer+sizeof (FLT_IF_GET_PARAMS)),
+ &Irp->IoStatus.Information);
+ if (NT_SUCCESS (status)) {
+ Irp->IoStatus.Information += sizeof (FLT_IF_GET_PARAMS);
+ ((PFLT_IF_GET_PARAMS)outBuffer)->FilterSize
+ = sizeof (IPX_TRAFFIC_FILTER_INFO);
+ }
+ else
+ Irp->IoStatus.Information = 0;
+ }
+ break;
+ case IOCTL_FLT_IF_GET_OUT_FILTERS:
+ IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: IOCTL_FLT_IF_GET_OUT_FILTERS.\n"));
+ if ((inpBufLength==sizeof (ULONG))
+ && (outBufLength>=sizeof (FLT_IF_GET_PARAMS))) {
+ Irp->IoStatus.Information
+ = outBufLength-sizeof (FLT_IF_GET_PARAMS);
+ status = GetOutFilters (
+ *((PULONG)inBuffer),
+ &((PFLT_IF_GET_PARAMS)outBuffer)->FilterAction,
+ &((PFLT_IF_GET_PARAMS)outBuffer)->TotalSize,
+ (PIPX_TRAFFIC_FILTER_INFO)
+ ((PUCHAR)outBuffer+sizeof (FLT_IF_GET_PARAMS)),
+ &Irp->IoStatus.Information);
+ if (NT_SUCCESS (status)) {
+ Irp->IoStatus.Information += sizeof (FLT_IF_GET_PARAMS);
+ ((PFLT_IF_GET_PARAMS)outBuffer)->FilterSize
+ = sizeof (IPX_TRAFFIC_FILTER_INFO);
+ }
+ else
+ Irp->IoStatus.Information = 0;
+ }
+
+ break;
+ case IOCTL_FLT_GET_LOGGED_PACKETS:
+ IpxFltDbgPrint (DBG_PKTLOGS, ("IpxFlt: IOCTL_FLT_GET_LOGGED_PACKETS.\n"));
+ Irp->IoStatus.Status = status = STATUS_PENDING;
+ IoMarkIrpPending (Irp);
+ IoAcquireCancelSpinLock (&cancelIRQL);
+ InsertTailList (&LogIrpQueue,
+ &Irp->Tail.Overlay.ListEntry);
+ IoSetCancelRoutine (Irp, IpxFltCancel);
+ if (LogIrpQueue.Flink!=&Irp->Tail.Overlay.ListEntry) {
+ PIRP irp = CONTAINING_RECORD (
+ LogIrpQueue.Flink,
+ IRP,
+ Tail.Overlay.ListEntry);
+ if (irp->IoStatus.Information>0) {
+ RemoveEntryList (&irp->Tail.Overlay.ListEntry);
+ IoSetCancelRoutine (irp, NULL);
+ irp->IoStatus.Status = STATUS_SUCCESS;
+ IoReleaseCancelSpinLock (cancelIRQL);
+ IpxFltDbgPrint (DBG_PKTLOGS,
+ ("IpxFlt: completing logging request"
+ " with %d bytes of data.\n",
+ irp->IoStatus.Information));
+ IoCompleteRequest (irp, IO_NO_INCREMENT);
+ break;
+ }
+ }
+ IoReleaseCancelSpinLock (cancelIRQL);
+ break;
+ default:
+ IpxFltDbgPrint (DBG_IOCTLS|DBG_ERRORS,
+ ("IpxFlt: Unsupported IOCTL %lx.\n",
+ IrpStack->Parameters.DeviceIoControl.IoControlCode));
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+ }
+ else if (RouterFile==NULL) {
+ if (IrpStack->Parameters.DeviceIoControl.IoControlCode
+ ==IOCTL_FLT_START) {
+ IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: IOCTL_FLT_START.\n"));
+ status = InitializeTables ();
+ if (NT_SUCCESS (status)) {
+ RouterFile = IrpStack->FileObject;
+ status = STATUS_SUCCESS;
+ }
+ }
+ else {
+ IpxFltDbgPrint (DBG_IOCTLS|DBG_ERRORS,
+ ("IpxFlt: Unsupported IOCTL %lx (driver is not started yet)).\n",
+ IrpStack->Parameters.DeviceIoControl.IoControlCode));
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ }
+ else {
+ IpxFltDbgPrint (DBG_IOCTLS|DBG_ERRORS,
+ ("IpxFlt: Unsupported IOCTL %lx from non-router client.\n",
+ IrpStack->Parameters.DeviceIoControl.IoControlCode));
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ break;
+ default:
+ IpxFltDbgPrint (DBG_IOCTLS|DBG_ERRORS,
+ ("IpxFlt: Unsupported function %lx.\n",
+ IrpStack->MajorFunction));
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+DispatchExit:
+ if (status!=STATUS_PENDING) {
+ Irp->IoStatus.Status = status;
+ if (NT_SUCCESS (status))
+ ;
+ else
+ IpxFltDbgPrint (DBG_IOCTLS|DBG_ERRORS,
+ ("IpxFlt: Failed call with status %lx.\n",
+ status));
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ }
+
+ return status;
+}
+
+
+
+/*++
+
+Routine Description:
+ Cleans up on driver unload
+
+Arguments:
+
+ DriverObject - pointer to a driver object
+
+Return Value:
+
+
+--*/
+VOID
+IpxFltUnload(
+ IN PDRIVER_OBJECT DriverObject
+ ) {
+ IpxFltDbgPrint (DBG_IOCTLS, ("IpxFlt: Unloading\n"));
+ if (RouterFile!=NULL) {
+ DeleteTables ();
+ RouterFile = NULL;
+ }
+ UnbindFromFwdDriver (KernelMode);
+ IoDeleteDevice (DriverObject->DeviceObject);
+}
+
+
+/*++
+ I p x F l t C a n c e l
+
+Routine Description:
+ Cancels specified IRP
+
+Arguments:
+ DeviceObject - forwarder device object
+ irp - irp to cancel
+
+Return Value:
+ None
+--*/
+VOID
+IpxFltCancel (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP irp
+ ) {
+ RemoveEntryList (&irp->Tail.Overlay.ListEntry);
+ IoReleaseCancelSpinLock (irp->CancelIrql);
+
+ irp->IoStatus.Status = STATUS_CANCELLED;
+ IpxFltDbgPrint(DBG_IOCTLS, ("IpxFlt: completing cancelled irp.\n"));
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+}
+
diff --git a/private/ntos/tdi/isn/flt/filter.c b/private/ntos/tdi/isn/flt/filter.c
new file mode 100644
index 000000000..198f4addf
--- /dev/null
+++ b/private/ntos/tdi/isn/flt/filter.c
@@ -0,0 +1,856 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\flt\filter.c
+
+Abstract:
+ IPX Filter driver filtering and maintanance routines
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+
+ // Masks to test components of the filter descriptor
+ // (Have to use globals in lue of constants to get correct
+ // byte ordering)
+const union {
+ struct {
+ UCHAR Src[4];
+ UCHAR Dst[4];
+ } FD_Network;
+ ULONGLONG FD_NetworkSrcDst;
+ } FltSrcNetMask = {{{0xFF, 0xFF, 0xFF, 0xFF}, {0, 0, 0, 0}}};
+#define FLT_SRC_NET_MASK FltSrcNetMask.FD_NetworkSrcDst
+
+const union {
+ struct {
+ UCHAR Src[4];
+ UCHAR Dst[4];
+ } FD_Network;
+ ULONGLONG FD_NetworkSrcDst;
+ } FltDstNetMask = {{{0, 0, 0, 0}, {0xFF, 0xFF, 0xFF, 0xFF}}};
+#define FLT_DST_NET_MASK FltDstNetMask.FD_NetworkSrcDst
+
+const union {
+ struct {
+ UCHAR Node[6];
+ UCHAR Socket[2];
+ } FD_NS;
+ ULONGLONG FD_NodeSocket;
+ } FltNodeMask = {{{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0, 0}}};
+#define FLT_NODE_MASK FltNodeMask.FD_NodeSocket
+
+const union {
+ struct {
+ UCHAR Node[6];
+ UCHAR Socket[2];
+ } FD_NS;
+ ULONGLONG FD_NodeSocket;
+ } FltSocketMask = {{{0, 0, 0, 0, 0, 0}, {0xFF, 0xFF}}};
+#define FLT_SOCKET_MASK FltSocketMask.FD_NodeSocket
+
+ // Hash tables of interface control blocks with filter descriptions
+ // Input filters
+LIST_ENTRY InterfaceInHash[FLT_INTERFACE_HASH_SIZE];
+ // Output filters
+LIST_ENTRY InterfaceOutHash[FLT_INTERFACE_HASH_SIZE];
+ // Serializes access to interface table
+FAST_MUTEX InterfaceTableLock;
+LIST_ENTRY LogIrpQueue;
+USHORT LogSeqNum;
+
+
+ // Hash function for interface hash tables
+#define InterfaceIndexHash(Index) (Index%FLT_INTERFACE_HASH_SIZE)
+
+ // Packet descriptor block
+typedef struct _PACKET_DESCR {
+ union {
+ struct {
+ ULONG Src; // Source network
+ ULONG Dst; // Destination network
+ } PD_Network;
+ ULONGLONG PD_NetworkSrcDst; // Combined field
+ };
+ ULONGLONG PD_SrcNodeSocket; // Source node & socket
+ ULONGLONG PD_DstNodeSocket; // Destination node & socket
+ LONG PD_ReferenceCount; // Filter reference count
+ UCHAR PD_PacketType; // Packet type
+ BOOLEAN PD_LogMatches;
+} PACKET_DESCR, *PPACKET_DESCR;
+
+ // Packet cache (only though that pass the filter)
+PPACKET_DESCR PacketCache[FLT_PACKET_CACHE_SIZE];
+KSPIN_LOCK PacketCacheLock;
+
+
+/*++
+ A c q u i r e P a c k e t R e f e r e n c e
+
+Routine Description:
+
+ Returns reference to the packet descriptor in the cache
+
+Arguments:
+ idx - cache index
+ pd - pointer to packet descriptor to be returned
+
+Return Value:
+ None
+
+--*/
+//VOID
+//AcquirePacketReference (
+// IN UINT idx,
+// OUT PPACKET_DESCR pd
+// );
+#define AcquirePacketReference(idx,pd) { \
+ KIRQL oldIRQL; \
+ KeAcquireSpinLock (&PacketCacheLock, &oldIRQL); \
+ if ((pd=PacketCache[idx])!=NULL) \
+ InterlockedIncrement (&pd->PD_ReferenceCount); \
+ KeReleaseSpinLock (&PacketCacheLock, oldIRQL); \
+}
+
+/*++
+ R e l e a s e P a c k e t R e f e r e n c e
+
+Routine Description:
+
+ Releases reference to the cached packet descriptor
+
+Arguments:
+ pd - pointer to packet descriptor to release
+
+Return Value:
+ None
+
+--*/
+//VOID
+//ReleasePacketReference (
+// IN PPACKET_DESCR pd
+// );
+#define ReleasePacketReference(pd) { \
+ if (InterlockedDecrement (&pd->PD_ReferenceCount)>=0) \
+ NOTHING; \
+ else \
+ ExFreePool (pd); \
+}
+
+/*++
+ R e p l a c e P a c k e t R e f e r e n c e
+
+Routine Description:
+
+ Replaces packet cache entry
+
+Arguments:
+ idx - cache index
+ pd - pointer to packet descriptor to be installed in the cache
+
+Return Value:
+ None
+
+--*/
+//VOID
+//ReplacePacket (
+// IN UINT idx,
+// IN PPACKET_DESCR pd
+// );
+#define ReplacePacket(idx,pd) { \
+ KIRQL oldIRQL; \
+ PPACKET_DESCR oldPD; \
+ KeAcquireSpinLock (&PacketCacheLock, &oldIRQL); \
+ oldPD = PacketCache[idx]; \
+ PacketCache[idx] = pd; \
+ KeReleaseSpinLock (&PacketCacheLock, oldIRQL); \
+ IpxFltDbgPrint (DBG_PKTCACHE, \
+ ("IpxFlt: Replaced packet descriptor %08lx" \
+ " with %08lx in cache at index %ld.\n", \
+ oldPD, pd, idx)); \
+ if (oldPD!=NULL) { \
+ ReleasePacketReference(oldPD); \
+ } \
+}
+
+ // Defined below
+VOID
+FlushPacketCache (
+ VOID
+ );
+
+/*++
+ I n i t i a l i z e T a b l e s
+
+Routine Description:
+
+ Initializes hash and cash tables and protection stuff
+Arguments:
+ None
+Return Value:
+ STATUS_SUCCESS
+
+--*/
+NTSTATUS
+InitializeTables (
+ VOID
+ ) {
+ UINT i;
+ for (i=0; i<FLT_INTERFACE_HASH_SIZE; i++) {
+ InitializeListHead (&InterfaceInHash[i]);
+ InitializeListHead (&InterfaceOutHash[i]);
+ }
+
+ for (i=0; i<FLT_PACKET_CACHE_SIZE; i++) {
+ PacketCache[i] = NULL;
+ }
+ KeInitializeSpinLock (&PacketCacheLock);
+ ExInitializeFastMutex (&InterfaceTableLock);
+ InitializeListHead (&LogIrpQueue);
+ LogSeqNum = 0;
+ return STATUS_SUCCESS;
+}
+
+/*++
+ D e l e t e T a b l e s
+
+Routine Description:
+
+ Deletes hash and cash tables
+Arguments:
+ None
+Return Value:
+ None
+
+--*/
+VOID
+DeleteTables (
+ VOID
+ ) {
+ UINT i;
+
+ for (i=0; i<FLT_INTERFACE_HASH_SIZE; i++) {
+ while (!IsListEmpty (&InterfaceInHash[i])) {
+ NTSTATUS status;
+ PINTERFACE_CB ifCB = CONTAINING_RECORD (InterfaceInHash[i].Flink,
+ INTERFACE_CB, ICB_Link);
+ status = FwdSetFilterInContext (ifCB->ICB_Index, NULL);
+ ASSERT (status==STATUS_SUCCESS);
+ RemoveEntryList (&ifCB->ICB_Link);
+ ExFreePool (ifCB);
+ }
+ while (!IsListEmpty (&InterfaceOutHash[i])) {
+ NTSTATUS status;
+ PINTERFACE_CB ifCB = CONTAINING_RECORD (InterfaceOutHash[i].Flink,
+ INTERFACE_CB, ICB_Link);
+ status = FwdSetFilterOutContext (ifCB->ICB_Index, NULL);
+ ASSERT (status==STATUS_SUCCESS);
+ RemoveEntryList (&ifCB->ICB_Link);
+ ExFreePool (ifCB);
+ }
+ }
+ for (i=0; i<FLT_PACKET_CACHE_SIZE; i++) {
+ if (PacketCache[i] != NULL)
+ ExFreePool (PacketCache[i]);
+ }
+ return ;
+}
+
+
+/*++
+ S e t F i l t e r s
+
+Routine Description:
+
+ Sets/replaces filter information for an interface
+Arguments:
+ HashTable - input or output hash table
+ Index - interface index
+ FilterAction - default action if there is no filter match
+ FilterInfoSize - size of the info array
+ FilterInfo - array of filter descriptions (UI format)
+Return Value:
+ STATUS_SUCCESS - filter info was set/replaced ok
+ STATUS_UNSUCCESSFUL - could not set filter context in forwarder
+ STATUS_INSUFFICIENT_RESOURCES - not enough memory to allocate
+ filter info block for interface
+
+--*/
+NTSTATUS
+SetFilters (
+ IN PLIST_ENTRY HashTable,
+ IN ULONG Index,
+ IN ULONG FilterAction,
+ IN ULONG FilterInfoSize,
+ IN PIPX_TRAFFIC_FILTER_INFO FilterInfo
+ ) {
+ PINTERFACE_CB ifCB = NULL, oldCB = NULL;
+ ULONG FilterCount
+ = FilterInfoSize/sizeof (IPX_TRAFFIC_FILTER_INFO);
+ ULONG i;
+ PFILTER_DESCR fd;
+ PLIST_ENTRY HashBucket = &HashTable[InterfaceIndexHash(Index)], cur;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ if (FilterCount>0) {
+ ifCB = ExAllocatePoolWithTag (
+ NonPagedPool,
+ FIELD_OFFSET (INTERFACE_CB, ICB_Filters[FilterCount]),
+ IPX_FLT_TAG
+ );
+ if (ifCB==NULL) {
+ IpxFltDbgPrint (DBG_IFHASH|DBG_ERRORS,
+ ("IpxFlt: Could not allocate interface CB for if %ld.\n",
+ Index));
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ ifCB->ICB_Index = Index;
+ ifCB->ICB_FilterAction = (FilterAction==IPX_TRAFFIC_FILTER_ACTION_PERMIT)
+ ? FILTER_PERMIT : FILTER_DENY;
+ ifCB->ICB_FilterCount = FilterCount;
+ // Copy/Map UI filters to the internal format
+ for (i=0, fd = ifCB->ICB_Filters; i<FilterCount; i++, fd++, FilterInfo++) {
+ if (FilterInfo->FilterDefinition&IPX_TRAFFIC_FILTER_ON_SRCNET) {
+ memcpy (fd->FD_Network.Src, FilterInfo->SourceNetwork, 4);
+ memcpy (fd->FD_NetworkMask.Src, FilterInfo->SourceNetworkMask, 4);
+ }
+ else {
+ memset (fd->FD_Network.Src, 0, 4);
+ memset (fd->FD_NetworkMask.Src, 0, 4);
+ }
+
+ if (FilterInfo->FilterDefinition&IPX_TRAFFIC_FILTER_ON_DSTNET) {
+ memcpy (fd->FD_Network.Dst, FilterInfo->DestinationNetwork, 4);
+ memcpy (fd->FD_NetworkMask.Dst, FilterInfo->DestinationNetworkMask, 4);
+ }
+ else {
+ memset (fd->FD_Network.Dst, 0, 4);
+ memset (fd->FD_NetworkMask.Dst, 0, 4);
+ }
+
+ if (FilterInfo->FilterDefinition&IPX_TRAFFIC_FILTER_ON_SRCNODE) {
+ memcpy (fd->FD_SrcNS.Node, FilterInfo->SourceNode, 6);
+ memset (fd->FD_SrcNSMask.Node, 0xFF, 6);
+ }
+ else {
+ memset (fd->FD_SrcNS.Node, 0, 6);
+ memset (fd->FD_SrcNSMask.Node, 0, 6);
+ }
+
+ if (FilterInfo->FilterDefinition&IPX_TRAFFIC_FILTER_ON_SRCSOCKET) {
+ memcpy (fd->FD_SrcNS.Socket, FilterInfo->SourceSocket, 2);
+ memset (fd->FD_SrcNSMask.Socket, 0xFF, 2);
+ }
+ else {
+ memset (fd->FD_SrcNS.Socket, 0, 2);
+ memset (fd->FD_SrcNSMask.Socket, 0, 2);
+ }
+
+ if (FilterInfo->FilterDefinition&IPX_TRAFFIC_FILTER_ON_DSTNODE) {
+ memcpy (fd->FD_DstNS.Node, FilterInfo->DestinationNode, 6);
+ memset (fd->FD_DstNSMask.Node, 0xFF, 6);
+ }
+ else {
+ memset (fd->FD_DstNS.Node, 0, 6);
+ memset (fd->FD_DstNSMask.Node, 0, 6);
+ }
+
+ if (FilterInfo->FilterDefinition&IPX_TRAFFIC_FILTER_ON_DSTSOCKET) {
+ memcpy (fd->FD_DstNS.Socket, FilterInfo->DestinationSocket, 2);
+ memset (fd->FD_DstNSMask.Socket, 0xFF, 2);
+ }
+ else {
+ memset (fd->FD_DstNS.Socket, 0, 2);
+ memset (fd->FD_DstNSMask.Socket, 0, 2);
+ }
+ if (FilterInfo->FilterDefinition&IPX_TRAFFIC_FILTER_ON_PKTTYPE) {
+ fd->FD_PacketType = FilterInfo->PacketType;
+ fd->FD_PacketTypeMask = 0xFF;
+ }
+ else {
+ fd->FD_PacketType = 0;
+ fd->FD_PacketTypeMask = 0;
+ }
+
+ fd->FD_LogMatches = (FilterInfo->FilterDefinition&IPX_TRAFFIC_FILTER_LOG_MATCHES)!=0;
+ }
+ }
+
+ ExAcquireFastMutex (&InterfaceTableLock);
+
+ // Find the old block and/or a place for a new one
+ cur = HashBucket->Flink;
+ while (cur!=HashBucket) {
+ oldCB = CONTAINING_RECORD (cur, INTERFACE_CB, ICB_Link);
+ if (oldCB->ICB_Index==Index) {
+ // Found the old one, place new after it
+ cur = cur->Flink;
+ break;
+ }
+ else if (oldCB->ICB_Index>Index) {
+ // No chance to see the old one anymore, place where
+ // we are now
+ oldCB = NULL;
+ break;
+ }
+ cur = cur->Flink;
+ }
+
+ // Set context in forwarder
+ if (HashTable==InterfaceInHash) {
+ status = FwdSetFilterInContext (Index, ifCB);
+ }
+ else {
+ ASSERT (HashTable==InterfaceOutHash);
+ status = FwdSetFilterOutContext (Index, ifCB);
+ }
+
+ if (NT_SUCCESS (status)) {
+ // Update table if we succeded
+ IpxFltDbgPrint (DBG_IFHASH,
+ ("IpxFlt: Set filters for if %ld (ifCB:%08lx).\n",
+ Index, ifCB));
+
+ if (oldCB!=NULL) {
+ IpxFltDbgPrint (DBG_IFHASH,
+ ("IpxFlt: Deleting replaced filters for if %ld (ifCB:%08lx).\n",
+ Index, oldCB));
+ RemoveEntryList (&oldCB->ICB_Link);
+ ExFreePool (oldCB);
+ }
+
+
+
+ if (ifCB!=NULL) {
+ InsertTailList (cur, &ifCB->ICB_Link);
+ }
+
+ FlushPacketCache ();
+ }
+ else {
+ IpxFltDbgPrint (DBG_IFHASH|DBG_ERRORS,
+ ("IpxFlt: Failed to set context for if %ld (ifCB:%08lx).\n",
+ Index, ifCB));
+ }
+
+ ExReleaseFastMutex (&InterfaceTableLock);
+ return status;
+}
+
+/*++
+ G e t F i l t e r s
+
+Routine Description:
+
+ Gets filter information for an interface
+Arguments:
+ HashTable - input or output hash table
+ Index - interface index
+ FilterAction - default action if there is no filter match
+ TotalSize - total memory required to hold all filter descriptions
+ FilterInfo - array of filter descriptions (UI format)
+ FilterInfoSize - on input: size of the info array
+ on output: size of the info placed in the array
+Return Value:
+ STATUS_SUCCESS - filter info was returned ok
+ STATUS_BUFFER_OVERFLOW - array is not big enough to hold all
+ filter info, only placed the info that fit
+
+--*/
+NTSTATUS
+GetFilters (
+ IN PLIST_ENTRY HashTable,
+ IN ULONG Index,
+ OUT ULONG *FilterAction,
+ OUT ULONG *TotalSize,
+ OUT PIPX_TRAFFIC_FILTER_INFO FilterInfo,
+ IN OUT ULONG *FilterInfoSize
+ ) {
+ PINTERFACE_CB oldCB = NULL;
+ ULONG i, AvailBufCount =
+ (*FilterInfoSize)/sizeof (IPX_TRAFFIC_FILTER_INFO);
+ PFILTER_DESCR fd;
+ PLIST_ENTRY HashBucket = &HashTable[InterfaceIndexHash(Index)], cur;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ // Locate interface filters block
+ ExAcquireFastMutex (&InterfaceTableLock);
+ cur = HashBucket->Flink;
+ while (cur!=HashBucket) {
+ oldCB = CONTAINING_RECORD (cur, INTERFACE_CB, ICB_Link);
+ if (oldCB->ICB_Index==Index) {
+ cur = cur->Flink;
+ break;
+ }
+ else if (oldCB->ICB_Index>Index) {
+ oldCB = NULL;
+ break;
+ }
+ cur = cur->Flink;
+ }
+
+ if (oldCB!=NULL) {
+ *FilterAction = IS_FILTERED(oldCB->ICB_FilterAction)
+ ? IPX_TRAFFIC_FILTER_ACTION_DENY
+ : IPX_TRAFFIC_FILTER_ACTION_PERMIT;
+ *TotalSize = oldCB->ICB_FilterCount*sizeof (IPX_TRAFFIC_FILTER_INFO);
+ // Copy/Map as many descriptors as fit
+ for (i=0, fd = oldCB->ICB_Filters;
+ (i<oldCB->ICB_FilterCount) && (i<AvailBufCount);
+ i++, fd++, FilterInfo++) {
+ FilterInfo->FilterDefinition = 0;
+ if (fd->FD_NetworkMaskSrcDst&FLT_SRC_NET_MASK) {
+ memcpy (FilterInfo->SourceNetwork, fd->FD_Network.Src, 4);
+ memcpy (FilterInfo->SourceNetworkMask, fd->FD_NetworkMask.Src, 4);
+ FilterInfo->FilterDefinition |= IPX_TRAFFIC_FILTER_ON_SRCNET;
+ }
+
+ if (fd->FD_NetworkMaskSrcDst&FLT_DST_NET_MASK) {
+ memcpy (FilterInfo->DestinationNetwork, fd->FD_Network.Dst, 4);
+ memcpy (FilterInfo->DestinationNetworkMask, fd->FD_NetworkMask.Dst, 4);
+ FilterInfo->FilterDefinition |= IPX_TRAFFIC_FILTER_ON_DSTNET;
+ }
+
+ if (fd->FD_SrcNodeSocketMask&FLT_NODE_MASK) {
+ memcpy (FilterInfo->SourceNode, fd->FD_SrcNS.Node, 6);
+ FilterInfo->FilterDefinition |= IPX_TRAFFIC_FILTER_ON_SRCNODE;
+ }
+
+ if (fd->FD_DstNodeSocketMask&FLT_NODE_MASK) {
+ memcpy (FilterInfo->DestinationNode, fd->FD_DstNS.Node, 6);
+ FilterInfo->FilterDefinition |= IPX_TRAFFIC_FILTER_ON_DSTNODE;
+ }
+
+ if (fd->FD_SrcNodeSocketMask&FLT_SOCKET_MASK) {
+ memcpy (FilterInfo->SourceSocket, fd->FD_SrcNS.Socket, 2);
+ FilterInfo->FilterDefinition |= IPX_TRAFFIC_FILTER_ON_SRCSOCKET;
+ }
+ if (fd->FD_DstNodeSocketMask&FLT_SOCKET_MASK) {
+ memcpy (FilterInfo->DestinationSocket, fd->FD_DstNS.Socket, 2);
+ FilterInfo->FilterDefinition |= IPX_TRAFFIC_FILTER_ON_DSTSOCKET;
+ }
+ if (fd->FD_PacketTypeMask&0xFF) {
+ FilterInfo->PacketType = fd->FD_PacketType;
+ FilterInfo->FilterDefinition |= IPX_TRAFFIC_FILTER_ON_PKTTYPE;
+ }
+ if (fd->FD_LogMatches)
+ FilterInfo->FilterDefinition |= IPX_TRAFFIC_FILTER_LOG_MATCHES;
+ }
+
+ *FilterInfoSize = i*sizeof (IPX_TRAFFIC_FILTER_INFO);
+
+ IpxFltDbgPrint (DBG_IFHASH,
+ ("IpxFlt: Returning %d filters (%d available)"
+ " for interface %d (ifCB: %08lx).\n",
+ i, oldCB->ICB_FilterCount, Index));
+ if (i<oldCB->ICB_FilterCount)
+ status = STATUS_BUFFER_OVERFLOW;
+ ExReleaseFastMutex (&InterfaceTableLock);
+ }
+ else {
+ // No interface block -> we are passing all the packets
+ // unfiltered
+ ExReleaseFastMutex (&InterfaceTableLock);
+ IpxFltDbgPrint (DBG_IFHASH,
+ ("IpxFlt: No filters for interface %d.\n", Index));
+ *FilterAction = IPX_TRAFFIC_FILTER_ACTION_PERMIT;
+ *TotalSize = 0;
+ *FilterInfoSize = 0;
+ }
+ return status;
+}
+
+
+VOID
+LogPacket (
+ IN PUCHAR ipxHdr,
+ IN ULONG ipxHdrLength,
+ IN PVOID ifInContext,
+ IN PVOID ifOutContext
+ ) {
+ PIRP irp;
+ PIO_STACK_LOCATION irpStack;
+ ULONG outBufLength;
+ PUCHAR outBuffer;
+ ULONG offset;
+ KIRQL cancelIRQL;
+
+ IoAcquireCancelSpinLock (&cancelIRQL);
+ LogSeqNum += 1;
+ while (!IsListEmpty (&LogIrpQueue)) {
+ irp = CONTAINING_RECORD (LogIrpQueue.Flink,IRP,Tail.Overlay.ListEntry);
+ irpStack = IoGetCurrentIrpStackLocation(irp);
+ outBufLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
+ outBuffer = (PUCHAR)MmGetSystemAddressForMdl (irp->MdlAddress);
+ offset = (PUCHAR)ALIGN_UP (outBuffer+irp->IoStatus.Information, ULONG)-outBuffer;
+ if (offset+ipxHdrLength+FIELD_OFFSET (FLT_PACKET_LOG, Header)<outBufLength) {
+ PFLT_PACKET_LOG pLog = (PFLT_PACKET_LOG) (outBuffer+offset);
+ pLog->SrcIfIdx = ifInContext
+ ? ((PINTERFACE_CB)ifInContext)->ICB_Index
+ : -1;
+ pLog->DstIfIdx = ifOutContext
+ ? ((PINTERFACE_CB)ifOutContext)->ICB_Index
+ : -1;
+ pLog->DataSize = (USHORT)ipxHdrLength;
+ pLog->SeqNum = LogSeqNum;
+ memcpy (pLog->Header, ipxHdr, ipxHdrLength);
+ irp->IoStatus.Information = offset+FIELD_OFFSET (FLT_PACKET_LOG, Header[ipxHdrLength]);
+ if (irp->Tail.Overlay.ListEntry.Flink!=&LogIrpQueue) {
+ RemoveEntryList (&irp->Tail.Overlay.ListEntry);
+ IoSetCancelRoutine (irp, NULL);
+ irp->IoStatus.Status = STATUS_SUCCESS;
+ IoReleaseCancelSpinLock (cancelIRQL);
+ IpxFltDbgPrint (DBG_PKTLOGS,
+ ("IpxFlt: completing logging request"
+ " with %d bytes of data.\n",
+ irp->IoStatus.Information));
+ IoCompleteRequest (irp, IO_NO_INCREMENT);
+ return;
+ }
+ else
+ break;
+ }
+ RemoveEntryList (&irp->Tail.Overlay.ListEntry);
+ IoSetCancelRoutine (irp, NULL);
+ irp->IoStatus.Status = STATUS_SUCCESS;
+ IoReleaseCancelSpinLock (cancelIRQL);
+ IpxFltDbgPrint (DBG_ERRORS|DBG_PKTLOGS,
+ ("IpxFlt: completing logging request"
+ " with %d bytes of data (not enough space).\n",
+ irp->IoStatus.Information));
+ IoCompleteRequest (irp, IO_NO_INCREMENT);
+ IoAcquireCancelSpinLock (&cancelIRQL);
+ }
+ IoReleaseCancelSpinLock (cancelIRQL);
+}
+
+
+/*++
+ F i l t e r
+
+Routine Description:
+
+ Filters the packet supplied by the forwarder
+
+Arguments:
+ ipxHdr - pointer to packet header
+ ipxHdrLength - size of the header buffer (must be at least 30)
+ ifInContext - context associated with interface on which packet
+ was received
+ ifOutContext - context associated with interface on which packet
+ will be sent
+Return Value:
+ FILTER_PERMIT - packet should be passed on by the forwarder
+ FILTER_DENY_IN - packet should be dropped because of input filter
+ FILTER_DENY_OUT - packet should be dropped because of output filter
+--*/
+FILTER_ACTION
+Filter (
+ IN PUCHAR ipxHdr,
+ IN ULONG ipxHdrLength,
+ IN PVOID ifInContext,
+ IN PVOID ifOutContext
+ ) {
+ PACKET_DESCR pd;
+ FILTER_ACTION res = FILTER_PERMIT;
+ UINT idx;
+
+ ASSERT (ipxHdrLength>=IPXH_HDRSIZE);
+ // Copy packet to aligned buffer
+ pd.PD_Network.Dst = *((UNALIGNED ULONG *)(ipxHdr+IPXH_DESTNET));
+ pd.PD_Network.Src = *((UNALIGNED ULONG *)(ipxHdr+IPXH_SRCNET));
+ pd.PD_DstNodeSocket = *((UNALIGNED ULONGLONG *)(ipxHdr+IPXH_DESTNODE));
+ pd.PD_SrcNodeSocket = *((UNALIGNED ULONGLONG *)(ipxHdr+IPXH_SRCNODE));
+ pd.PD_PacketType = *(ipxHdr+IPXH_PKTTYPE);
+ pd.PD_LogMatches = FALSE;
+ // We do not cache netbios broadcast
+ if (pd.PD_PacketType!=IPX_NETBIOS_TYPE) {
+ PPACKET_DESCR cachedPD;
+ // Get cached packet
+ idx = (UINT)((pd.PD_Network.Dst
+ +pd.PD_DstNodeSocket
+ +pd.PD_PacketType)
+ %FLT_PACKET_CACHE_SIZE);
+ AcquirePacketReference (idx, cachedPD);
+ if (cachedPD!=NULL) {
+ // Fast path: packet in the cache matches
+ if ((pd.PD_NetworkSrcDst==cachedPD->PD_NetworkSrcDst)
+ && (pd.PD_SrcNodeSocket==cachedPD->PD_SrcNodeSocket)
+ && (pd.PD_DstNodeSocket==cachedPD->PD_DstNodeSocket)
+ && (pd.PD_PacketType==cachedPD->PD_PacketType)) {
+ if (cachedPD->PD_LogMatches)
+ LogPacket (ipxHdr,ipxHdrLength,ifInContext,ifOutContext);
+ ReleasePacketReference (cachedPD);
+ return FILTER_PERMIT;
+ }
+ // Do not need cached packet anymore
+ ReleasePacketReference (cachedPD);
+ }
+ }
+ // Slow path: check all filters
+ if (ifInContext!=NO_FILTER_CONTEXT) {
+ PFILTER_DESCR fd, fdEnd;
+ // Read default result (no filter match)
+ res = NOT_FILTER_ACTION(((PINTERFACE_CB)ifInContext)->ICB_FilterAction);
+ fd = ((PINTERFACE_CB)ifInContext)->ICB_Filters;
+ fdEnd = &((PINTERFACE_CB)ifInContext)->ICB_Filters
+ [((PINTERFACE_CB)ifInContext)->ICB_FilterCount];
+ while (fd<fdEnd) {
+ if ( ((pd.PD_NetworkSrcDst & fd->FD_NetworkMaskSrcDst)
+ == fd->FD_NetworkSrcDst)
+ && ((pd.PD_SrcNodeSocket & fd->FD_SrcNodeSocketMask)
+ == fd->FD_SrcNodeSocket)
+ && ((pd.PD_DstNodeSocket & fd->FD_DstNodeSocketMask)
+ == fd->FD_DstNodeSocket)
+ && ((pd.PD_PacketType & fd->FD_PacketTypeMask)
+ == fd->FD_PacketType) ) {
+ // Filter match: reverse the result
+ res = NOT_FILTER_ACTION(res);
+ if (fd->FD_LogMatches) {
+ pd.PD_LogMatches = TRUE;
+ LogPacket (ipxHdr,ipxHdrLength,ifInContext,ifOutContext);
+ }
+ break;
+ }
+ fd++;
+ }
+ // Return right away if told to drop
+ if (IS_FILTERED(res))
+ return FILTER_DENY_IN;
+ }
+
+ if (ifOutContext!=NO_FILTER_CONTEXT) {
+ PFILTER_DESCR fd, fdEnd;
+ // Read default result (no filter match)
+ res = NOT_FILTER_ACTION(((PINTERFACE_CB)ifOutContext)->ICB_FilterAction);
+ fd = ((PINTERFACE_CB)ifOutContext)->ICB_Filters;
+ fdEnd = &((PINTERFACE_CB)ifOutContext)->ICB_Filters
+ [((PINTERFACE_CB)ifOutContext)->ICB_FilterCount];
+ while (fd<fdEnd) {
+ if ( ((pd.PD_NetworkSrcDst & fd->FD_NetworkMaskSrcDst)
+ == fd->FD_NetworkSrcDst)
+ && ((pd.PD_SrcNodeSocket & fd->FD_SrcNodeSocketMask)
+ == fd->FD_SrcNodeSocket)
+ && ((pd.PD_DstNodeSocket & fd->FD_DstNodeSocketMask)
+ == fd->FD_DstNodeSocket)
+ && ((pd.PD_PacketType & fd->FD_PacketTypeMask)
+ == fd->FD_PacketType) ) {
+ // Filter match: reverse the result
+ res = NOT_FILTER_ACTION(res);
+ if (fd->FD_LogMatches&&!pd.PD_LogMatches) {
+ pd.PD_LogMatches = TRUE;
+ LogPacket (ipxHdr,ipxHdrLength,ifInContext,ifOutContext);
+ }
+ break;
+ }
+ fd++;
+ }
+ // Return right away if told to drop
+ if (IS_FILTERED(res))
+ return FILTER_DENY_OUT;
+ }
+
+ // Cache the packet (we know that it is a pass
+ // because we would have returned if it was a drop)
+ if (pd.PD_PacketType!=IPX_NETBIOS_TYPE) {
+ PPACKET_DESCR cachedPD;
+ cachedPD = ExAllocatePoolWithTag (
+ NonPagedPool,
+ sizeof (PACKET_DESCR),
+ IPX_FLT_TAG
+ );
+ if (cachedPD!=NULL) {
+ *cachedPD = pd;
+ cachedPD->PD_ReferenceCount = 0;
+ ReplacePacket (idx, cachedPD);
+ }
+ }
+
+ return res;
+}
+
+
+/*++
+ I n t e r f a c e D e l e t e d
+
+Routine Description:
+
+ Frees interface filters blocks when forwarder indicates that
+ interface is deleted
+Arguments:
+ ifInContext - context associated with input filters block
+ ifOutContext - context associated with output filters block
+Return Value:
+ None
+
+--*/
+VOID
+InterfaceDeleted (
+ IN PVOID ifInContext,
+ IN PVOID ifOutContext
+ ) {
+ IpxFltDbgPrint (DBG_FWDIF,
+ ("IpxFlt: InterfaceDeleted indication,"
+ "(inContext: %08lx, outContext: %08lx).\n",
+ ifInContext, ifOutContext));
+ ExAcquireFastMutex (&InterfaceTableLock);
+ if (ifInContext!=NULL) {
+ PINTERFACE_CB ifCB = (PINTERFACE_CB)ifInContext;
+ IpxFltDbgPrint (DBG_IFHASH,
+ ("IpxFlt: Deleting filters for if %ld (ifCB:%08lx)"
+ " on InterfaceDeleted indication from forwarder.\n",
+ ifCB->ICB_Index, ifCB));
+ RemoveEntryList (&ifCB->ICB_Link);
+ ExFreePool (ifCB);
+ }
+
+ if (ifOutContext!=NULL) {
+ PINTERFACE_CB ifCB = (PINTERFACE_CB)ifOutContext;
+ IpxFltDbgPrint (DBG_IFHASH,
+ ("IpxFlt: Deleting filters for if %ld (ifCB:%08lx)"
+ " on InterfaceDeleted indication from forwarder.\n",
+ ifCB->ICB_Index, ifCB));
+ RemoveEntryList (&ifCB->ICB_Link);
+ ExFreePool (ifCB);
+ }
+ ExReleaseFastMutex (&InterfaceTableLock);
+ FlushPacketCache ();
+ return ;
+}
+
+/*++
+ F l u s h P a c k e t C a c h e
+
+Routine Description:
+
+ Deletes all cached packet descriptions
+Arguments:
+ None
+Return Value:
+ None
+
+--*/
+VOID
+FlushPacketCache (
+ VOID
+ ) {
+ UINT i;
+ IpxFltDbgPrint (DBG_PKTCACHE, ("IpxFlt: Flushing packet chache.\n"));
+ for (i=0; i<FLT_PACKET_CACHE_SIZE; i++) {
+ ReplacePacket (i, NULL);
+ }
+}
+
+
+
diff --git a/private/ntos/tdi/isn/flt/filter.h b/private/ntos/tdi/isn/flt/filter.h
new file mode 100644
index 000000000..a4e3ff031
--- /dev/null
+++ b/private/ntos/tdi/isn/flt/filter.h
@@ -0,0 +1,288 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\flt\filter.h
+
+Abstract:
+ IPX Filter driver filtering and maintanance routines
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+#ifndef _IPXFLT_FILTER_
+#define _IPXFLT_FILTER_
+
+ // IPX header constants
+#define IPXH_HDRSIZE 30 // Size of the IPX header
+#define IPXH_CHECKSUM 0 // Checksum
+#define IPXH_LENGTH 2 // Length
+#define IPXH_XPORTCTL 4 // Transport Control
+#define IPXH_PKTTYPE 5 // Packet Type
+#define IPXH_DESTADDR 6 // Dest. Address (Total)
+#define IPXH_DESTNET 6 // Dest. Network Address
+#define IPXH_DESTNODE 10 // Dest. Node Address
+#define IPXH_DESTSOCK 16 // Dest. Socket Number
+#define IPXH_SRCADDR 18 // Source Address (Total)
+#define IPXH_SRCNET 18 // Source Network Address
+#define IPXH_SRCNODE 22 // Source Node Address
+#define IPXH_SRCSOCK 28 // Source Socket Number
+
+//*** Packet Types we care about
+#define IPX_NETBIOS_TYPE 20 // Netbios propagated packet
+
+// Conversions from/to on-the-wire format
+#define GETUSHORT(src) ( \
+ (USHORT)( \
+ (((UCHAR *)src)[0]<<8) \
+ + (((UCHAR *)src)[1]) \
+ ) \
+)
+
+#define GETULONG(src) ( \
+ (ULONG)( \
+ (((UCHAR *)src)[0]<<24) \
+ + (((UCHAR *)src)[1]<<16) \
+ + (((UCHAR *)src)[2]<<8) \
+ + (((UCHAR *)src)[3]) \
+ ) \
+)
+
+#define PUTUSHORT(src,dst) { \
+ ((UCHAR *)dst)[0] = ((UCHAR)(src>>8)); \
+ ((UCHAR *)dst)[1] = ((UCHAR)src); \
+}
+
+#define PUTULONG(src,dst) { \
+ ((UCHAR *)dst)[0] = ((UCHAR)(src>>24)); \
+ ((UCHAR *)dst)[1] = ((UCHAR)(src>>16)); \
+ ((UCHAR *)dst)[2] = ((UCHAR)(src>>8)); \
+ ((UCHAR *)dst)[3] = ((UCHAR)src); \
+}
+
+ // Other important constatns
+#define FLT_INTERFACE_HASH_SIZE 257
+#define FLT_PACKET_CACHE_SIZE 257
+#define IPX_FLT_TAG 'lFwN'
+
+
+ // Filter description
+typedef struct _FILTER_DESCR {
+ union {
+ struct {
+ UCHAR Src[4];
+ UCHAR Dst[4];
+ } FD_Network;
+ ULONGLONG FD_NetworkSrcDst;
+ };
+ union {
+ struct {
+ UCHAR Src[4];
+ UCHAR Dst[4];
+ } FD_NetworkMask;
+ ULONGLONG FD_NetworkMaskSrcDst;
+ };
+ union {
+ struct {
+ UCHAR Node[6];
+ UCHAR Socket[2];
+ } FD_SrcNS;
+ ULONGLONG FD_SrcNodeSocket;
+ };
+ union {
+ struct {
+ UCHAR Node[6];
+ UCHAR Socket[2];
+ } FD_SrcNSMask;
+ ULONGLONG FD_SrcNodeSocketMask;
+ };
+ union {
+ struct {
+ UCHAR Node[6];
+ UCHAR Socket[2];
+ } FD_DstNS;
+ ULONGLONG FD_DstNodeSocket;
+ };
+ union {
+ struct {
+ UCHAR Node[6];
+ UCHAR Socket[2];
+ } FD_DstNSMask;
+ ULONGLONG FD_DstNodeSocketMask;
+ };
+ UCHAR FD_PacketType;
+ UCHAR FD_PacketTypeMask;
+ BOOLEAN FD_LogMatches;
+} FILTER_DESCR, *PFILTER_DESCR;
+
+ // Interface filters block
+typedef struct _INTERFACE_CB {
+ LIST_ENTRY ICB_Link;
+ ULONG ICB_Index;
+ ULONG ICB_FilterAction;
+ ULONG ICB_FilterCount;
+ FILTER_DESCR ICB_Filters[1];
+} INTERFACE_CB, *PINTERFACE_CB;
+
+ // Interface hash tables
+extern LIST_ENTRY InterfaceInHash[FLT_INTERFACE_HASH_SIZE];
+extern LIST_ENTRY InterfaceOutHash[FLT_INTERFACE_HASH_SIZE];
+extern LIST_ENTRY LogIrpQueue;
+
+/*++
+ I n i t i a l i z e T a b l e s
+
+Routine Description:
+
+ Initializes hash and cash tables and protection stuff
+Arguments:
+ None
+Return Value:
+ STATUS_SUCCESS
+
+--*/
+NTSTATUS
+InitializeTables (
+ VOID
+ );
+
+/*++
+ D e l e t e T a b l e s
+
+Routine Description:
+
+ Deletes hash and cash tables
+Arguments:
+ None
+Return Value:
+ None
+
+--*/
+VOID
+DeleteTables (
+ VOID
+ );
+
+/*++
+ S e t F i l t e r s
+
+Routine Description:
+
+ Sets/replaces filter information for an interface
+Arguments:
+ HashTable - input or output hash table
+ Index - interface index
+ FilterAction - default action if there is no filter match
+ FilterInfoSize - size of the info array
+ FilterInfo - array of filter descriptions (UI format)
+Return Value:
+ STATUS_SUCCESS - filter info was set/replaced ok
+ STATUS_UNSUCCESSFUL - could not set filter context in forwarder
+ STATUS_INSUFFICIENT_RESOURCES - not enough memory to allocate
+ filter info block for interface
+
+--*/
+NTSTATUS
+SetFilters (
+ IN PLIST_ENTRY HashTable,
+ IN ULONG InterfaceIndex,
+ IN ULONG FilterAction,
+ IN ULONG FilterInfoSize,
+ IN PIPX_TRAFFIC_FILTER_INFO FilterInfo
+ );
+#define SetInFilters(Index,Action,InfoSize,Info) \
+ SetFilters(InterfaceInHash,Index,Action,InfoSize,Info)
+#define SetOutFilters(Index,Action,InfoSize,Info) \
+ SetFilters(InterfaceOutHash,Index,Action,InfoSize,Info)
+
+
+/*++
+ G e t F i l t e r s
+
+Routine Description:
+
+ Gets filter information for an interface
+Arguments:
+ HashTable - input or output hash table
+ Index - interface index
+ FilterAction - default action if there is no filter match
+ TotalSize - total memory required to hold all filter descriptions
+ FilterInfo - array of filter descriptions (UI format)
+ FilterInfoSize - on input: size of the info array
+ on output: size of the info placed in the array
+Return Value:
+ STATUS_SUCCESS - filter info was returned ok
+ STATUS_BUFFER_OVERFLOW - array is not big enough to hold all
+ filter info, only placed the info that fit
+
+--*/
+NTSTATUS
+GetFilters (
+ IN PLIST_ENTRY HashTable,
+ IN ULONG InterfaceIndex,
+ OUT ULONG *FilterAction,
+ OUT ULONG *TotalSize,
+ OUT PIPX_TRAFFIC_FILTER_INFO FilterInfo,
+ IN OUT ULONG *FilterInfoSize
+ );
+#define GetInFilters(Index,Action,TotalSize,Info,InfoSize) \
+ GetFilters(InterfaceInHash,Index,Action,TotalSize,Info,InfoSize)
+#define GetOutFilters(Index,Action,TotalSize,Info,InfoSize) \
+ GetFilters(InterfaceOutHash,Index,Action,TotalSize,Info,InfoSize)
+
+/*++
+ F i l t e r
+
+Routine Description:
+
+ Filters the packet supplied by the forwarder
+
+Arguments:
+ ipxHdr - pointer to packet header
+ ipxHdrLength - size of the header buffer (must be at least 30)
+ ifInContext - context associated with interface on which packet
+ was received
+ ifOutContext - context associated with interface on which packet
+ will be sent
+Return Value:
+ FILTER_PERMIT - packet should be passed on by the forwarder
+ FILTER_DEDY - packet should be dropped
+--*/
+FILTER_ACTION
+Filter (
+ IN PUCHAR ipxHdr,
+ IN ULONG ipxHdrLength,
+ IN PVOID ifInContext,
+ IN PVOID ifOutContext
+ );
+
+/*++
+ I n t e r f a c e D e l e t e d
+
+Routine Description:
+
+ Frees interface filters blocks when forwarder indicates that
+ interface is deleted
+Arguments:
+ ifInContext - context associated with input filters block
+ ifOutContext - context associated with output filters block
+Return Value:
+ None
+
+--*/
+VOID
+InterfaceDeleted (
+ IN PVOID ifInContext,
+ IN PVOID ifOutContext
+ );
+
+
+#endif
+
diff --git a/private/ntos/tdi/isn/flt/flt.mak b/private/ntos/tdi/isn/flt/flt.mak
new file mode 100644
index 000000000..760380500
--- /dev/null
+++ b/private/ntos/tdi/isn/flt/flt.mak
@@ -0,0 +1,497 @@
+# Microsoft Developer Studio Generated NMAKE File, Format Version 4.10
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+!IF "$(CFG)" == ""
+CFG=flt - Win32 Release
+!MESSAGE No configuration specified. Defaulting to flt - Win32 Release.
+!ENDIF
+
+!IF "$(CFG)" != "flt - Win32 Release"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE on this makefile
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "flt.mak" CFG="flt - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "flt - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+################################################################################
+# Begin Project
+# PROP Target_Last_Scanned "flt - Win32 Release"
+RSC=rc.exe
+CPP=cl.exe
+MTL=mktyplib.exe
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Target_Dir ""
+OUTDIR=.
+INTDIR=.
+
+ALL : "$(OUTDIR)\flt.dll"
+
+CLEAN :
+ -@erase "$(INTDIR)\debug.obj"
+ -@erase "$(INTDIR)\driver.obj"
+ -@erase "$(INTDIR)\filter.obj"
+ -@erase "$(INTDIR)\fwdbind.obj"
+ -@erase "$(INTDIR)\nwlnkflt.res"
+ -@erase "$(OUTDIR)\flt.dll"
+ -@erase "$(OUTDIR)\flt.exp"
+ -@erase "$(OUTDIR)\flt.lib"
+
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /Gz /MD /W3 /WX /Z7 /Oi /Gy /I "." /I "..\inc" /I "..\..\..\inc" /I "..\..\..\..\inc" /I "..\..\..\..\net\routing\inc" /FI"C:\NT\public\sdk\inc\warning.h" /D _X86_=1 /D i386=1 /D "STD_CALL" /D CONDITION_HANDLING=1 /D NT_INST=0 /D WIN32=100 /D _NT1X_=100 /D WINNT=1 /D WIN32_LEAN_AND_MEAN=1 /D DBG=1 /D DEVL=1 /D FPO=0 /D "_NTDRIVER_" /Fp"obj\i386\precomp.pch" /Yu"precomp.h" /Zel -cbstring /QIfdiv- /QI6 /QIf /GF /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/flt.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:I386
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo\
+ /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)/flt.pdb" /machine:I386\
+ /out:"$(OUTDIR)/flt.dll" /implib:"$(OUTDIR)/flt.lib"
+LINK32_OBJS= \
+ "$(INTDIR)\debug.obj" \
+ "$(INTDIR)\driver.obj" \
+ "$(INTDIR)\filter.obj" \
+ "$(INTDIR)\fwdbind.obj" \
+ "$(INTDIR)\nwlnkflt.res"
+
+"$(OUTDIR)\flt.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)/nwlnkflt.res" /d "NDEBUG"
+CPP_PROJ=/nologo /Gz /MD /W3 /WX /Z7 /Oi /Gy /I "." /I "..\inc" /I\
+ "..\..\..\inc" /I "..\..\..\..\inc" /I "..\..\..\..\net\routing\inc"\
+ /FI"C:\NT\public\sdk\inc\warning.h" /D _X86_=1 /D i386=1 /D "STD_CALL" /D\
+ CONDITION_HANDLING=1 /D NT_INST=0 /D WIN32=100 /D _NT1X_=100 /D WINNT=1 /D\
+ WIN32_LEAN_AND_MEAN=1 /D DBG=1 /D DEVL=1 /D FPO=0 /D "_NTDRIVER_"\
+ /Fp"$(INTDIR)/obj\i386\precomp.pch" /Yu"precomp.h" /Zel -cbstring /QIfdiv- /QI6\
+ /QIf /GF /c
+
+.c.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.c.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+MTL_PROJ=/nologo /D "NDEBUG" /win32
+################################################################################
+# Begin Target
+
+# Name "flt - Win32 Release"
+################################################################################
+# Begin Source File
+
+SOURCE=.\debug.c
+DEP_CPP_DEBUG=\
+ "..\..\..\..\inc\ipxfwd.h"\
+ "..\..\..\..\inc\ipxtfflt.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\ipxfltif.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\debug.h"\
+ ".\filter.h"\
+ ".\fwdbind.h"\
+ ".\precomp.h"\
+ {$(INCLUDE)}"\cfg.h"\
+ {$(INCLUDE)}"\devioctl.h"\
+ {$(INCLUDE)}"\mipsinst.h"\
+ {$(INCLUDE)}"\netevent.h"\
+ {$(INCLUDE)}"\nt.h"\
+ {$(INCLUDE)}"\ntalpha.h"\
+ {$(INCLUDE)}"\ntconfig.h"\
+ {$(INCLUDE)}"\ntddndis.h"\
+ {$(INCLUDE)}"\ntdef.h"\
+ {$(INCLUDE)}"\ntelfapi.h"\
+ {$(INCLUDE)}"\ntexapi.h"\
+ {$(INCLUDE)}"\nti386.h"\
+ {$(INCLUDE)}"\ntimage.h"\
+ {$(INCLUDE)}"\ntioapi.h"\
+ {$(INCLUDE)}"\ntiolog.h"\
+ {$(INCLUDE)}"\ntkeapi.h"\
+ {$(INCLUDE)}"\ntkxapi.h"\
+ {$(INCLUDE)}"\ntldr.h"\
+ {$(INCLUDE)}"\ntlpcapi.h"\
+ {$(INCLUDE)}"\ntmips.h"\
+ {$(INCLUDE)}"\ntmmapi.h"\
+ {$(INCLUDE)}"\ntnls.h"\
+ {$(INCLUDE)}"\ntobapi.h"\
+ {$(INCLUDE)}"\ntpnpapi.h"\
+ {$(INCLUDE)}"\ntpoapi.h"\
+ {$(INCLUDE)}"\ntppc.h"\
+ {$(INCLUDE)}"\ntpsapi.h"\
+ {$(INCLUDE)}"\ntregapi.h"\
+ {$(INCLUDE)}"\ntrtl.h"\
+ {$(INCLUDE)}"\ntseapi.h"\
+ {$(INCLUDE)}"\ntstatus.h"\
+ {$(INCLUDE)}"\ntxcapi.h"\
+ {$(INCLUDE)}"\ppcinst.h"\
+ {$(INCLUDE)}"\zwapi.h"\
+
+
+"$(INTDIR)\debug.obj" : $(SOURCE) $(DEP_CPP_DEBUG) "$(INTDIR)"\
+ "$(INTDIR)\obj\i386\precomp.pch"
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\driver.c
+DEP_CPP_DRIVE=\
+ "..\..\..\..\inc\ipxfwd.h"\
+ "..\..\..\..\inc\ipxtfflt.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\ipxfltif.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\debug.h"\
+ ".\filter.h"\
+ ".\fwdbind.h"\
+ ".\precomp.h"\
+ {$(INCLUDE)}"\cfg.h"\
+ {$(INCLUDE)}"\devioctl.h"\
+ {$(INCLUDE)}"\mipsinst.h"\
+ {$(INCLUDE)}"\netevent.h"\
+ {$(INCLUDE)}"\nt.h"\
+ {$(INCLUDE)}"\ntalpha.h"\
+ {$(INCLUDE)}"\ntconfig.h"\
+ {$(INCLUDE)}"\ntddndis.h"\
+ {$(INCLUDE)}"\ntdef.h"\
+ {$(INCLUDE)}"\ntelfapi.h"\
+ {$(INCLUDE)}"\ntexapi.h"\
+ {$(INCLUDE)}"\nti386.h"\
+ {$(INCLUDE)}"\ntimage.h"\
+ {$(INCLUDE)}"\ntioapi.h"\
+ {$(INCLUDE)}"\ntiolog.h"\
+ {$(INCLUDE)}"\ntkeapi.h"\
+ {$(INCLUDE)}"\ntkxapi.h"\
+ {$(INCLUDE)}"\ntldr.h"\
+ {$(INCLUDE)}"\ntlpcapi.h"\
+ {$(INCLUDE)}"\ntmips.h"\
+ {$(INCLUDE)}"\ntmmapi.h"\
+ {$(INCLUDE)}"\ntnls.h"\
+ {$(INCLUDE)}"\ntobapi.h"\
+ {$(INCLUDE)}"\ntpnpapi.h"\
+ {$(INCLUDE)}"\ntpoapi.h"\
+ {$(INCLUDE)}"\ntppc.h"\
+ {$(INCLUDE)}"\ntpsapi.h"\
+ {$(INCLUDE)}"\ntregapi.h"\
+ {$(INCLUDE)}"\ntrtl.h"\
+ {$(INCLUDE)}"\ntseapi.h"\
+ {$(INCLUDE)}"\ntstatus.h"\
+ {$(INCLUDE)}"\ntxcapi.h"\
+ {$(INCLUDE)}"\ppcinst.h"\
+ {$(INCLUDE)}"\zwapi.h"\
+
+
+"$(INTDIR)\driver.obj" : $(SOURCE) $(DEP_CPP_DRIVE) "$(INTDIR)"\
+ "$(INTDIR)\obj\i386\precomp.pch"
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\sources.inc
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\nwlnkflt.rc
+DEP_RSC_NWLNK=\
+ {$(INCLUDE)}"\common.ver"\
+ {$(INCLUDE)}"\ntverp.h"\
+
+
+"$(INTDIR)\nwlnkflt.res" : $(SOURCE) $(DEP_RSC_NWLNK) "$(INTDIR)"
+ $(RSC) $(RSC_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\filter.c
+DEP_CPP_FILTE=\
+ "..\..\..\..\inc\ipxfwd.h"\
+ "..\..\..\..\inc\ipxtfflt.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\ipxfltif.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\debug.h"\
+ ".\filter.h"\
+ ".\fwdbind.h"\
+ ".\precomp.h"\
+ {$(INCLUDE)}"\cfg.h"\
+ {$(INCLUDE)}"\devioctl.h"\
+ {$(INCLUDE)}"\mipsinst.h"\
+ {$(INCLUDE)}"\netevent.h"\
+ {$(INCLUDE)}"\nt.h"\
+ {$(INCLUDE)}"\ntalpha.h"\
+ {$(INCLUDE)}"\ntconfig.h"\
+ {$(INCLUDE)}"\ntddndis.h"\
+ {$(INCLUDE)}"\ntdef.h"\
+ {$(INCLUDE)}"\ntelfapi.h"\
+ {$(INCLUDE)}"\ntexapi.h"\
+ {$(INCLUDE)}"\nti386.h"\
+ {$(INCLUDE)}"\ntimage.h"\
+ {$(INCLUDE)}"\ntioapi.h"\
+ {$(INCLUDE)}"\ntiolog.h"\
+ {$(INCLUDE)}"\ntkeapi.h"\
+ {$(INCLUDE)}"\ntkxapi.h"\
+ {$(INCLUDE)}"\ntldr.h"\
+ {$(INCLUDE)}"\ntlpcapi.h"\
+ {$(INCLUDE)}"\ntmips.h"\
+ {$(INCLUDE)}"\ntmmapi.h"\
+ {$(INCLUDE)}"\ntnls.h"\
+ {$(INCLUDE)}"\ntobapi.h"\
+ {$(INCLUDE)}"\ntpnpapi.h"\
+ {$(INCLUDE)}"\ntpoapi.h"\
+ {$(INCLUDE)}"\ntppc.h"\
+ {$(INCLUDE)}"\ntpsapi.h"\
+ {$(INCLUDE)}"\ntregapi.h"\
+ {$(INCLUDE)}"\ntrtl.h"\
+ {$(INCLUDE)}"\ntseapi.h"\
+ {$(INCLUDE)}"\ntstatus.h"\
+ {$(INCLUDE)}"\ntxcapi.h"\
+ {$(INCLUDE)}"\ppcinst.h"\
+ {$(INCLUDE)}"\zwapi.h"\
+
+
+"$(INTDIR)\filter.obj" : $(SOURCE) $(DEP_CPP_FILTE) "$(INTDIR)"\
+ "$(INTDIR)\obj\i386\precomp.pch"
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\fwdbind.c
+DEP_CPP_FWDBI=\
+ "..\..\..\..\inc\ipxfwd.h"\
+ "..\..\..\..\inc\ipxtfflt.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\ipxfltif.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\debug.h"\
+ ".\filter.h"\
+ ".\fwdbind.h"\
+ ".\precomp.h"\
+ {$(INCLUDE)}"\cfg.h"\
+ {$(INCLUDE)}"\devioctl.h"\
+ {$(INCLUDE)}"\mipsinst.h"\
+ {$(INCLUDE)}"\netevent.h"\
+ {$(INCLUDE)}"\nt.h"\
+ {$(INCLUDE)}"\ntalpha.h"\
+ {$(INCLUDE)}"\ntconfig.h"\
+ {$(INCLUDE)}"\ntddndis.h"\
+ {$(INCLUDE)}"\ntdef.h"\
+ {$(INCLUDE)}"\ntelfapi.h"\
+ {$(INCLUDE)}"\ntexapi.h"\
+ {$(INCLUDE)}"\nti386.h"\
+ {$(INCLUDE)}"\ntimage.h"\
+ {$(INCLUDE)}"\ntioapi.h"\
+ {$(INCLUDE)}"\ntiolog.h"\
+ {$(INCLUDE)}"\ntkeapi.h"\
+ {$(INCLUDE)}"\ntkxapi.h"\
+ {$(INCLUDE)}"\ntldr.h"\
+ {$(INCLUDE)}"\ntlpcapi.h"\
+ {$(INCLUDE)}"\ntmips.h"\
+ {$(INCLUDE)}"\ntmmapi.h"\
+ {$(INCLUDE)}"\ntnls.h"\
+ {$(INCLUDE)}"\ntobapi.h"\
+ {$(INCLUDE)}"\ntpnpapi.h"\
+ {$(INCLUDE)}"\ntpoapi.h"\
+ {$(INCLUDE)}"\ntppc.h"\
+ {$(INCLUDE)}"\ntpsapi.h"\
+ {$(INCLUDE)}"\ntregapi.h"\
+ {$(INCLUDE)}"\ntrtl.h"\
+ {$(INCLUDE)}"\ntseapi.h"\
+ {$(INCLUDE)}"\ntstatus.h"\
+ {$(INCLUDE)}"\ntxcapi.h"\
+ {$(INCLUDE)}"\ppcinst.h"\
+ {$(INCLUDE)}"\zwapi.h"\
+
+
+"$(INTDIR)\fwdbind.obj" : $(SOURCE) $(DEP_CPP_FWDBI) "$(INTDIR)"\
+ "$(INTDIR)\obj\i386\precomp.pch"
+
+
+# End Source File
+# End Target
+# End Project
+################################################################################
diff --git a/private/ntos/tdi/isn/flt/fwdbind.c b/private/ntos/tdi/isn/flt/fwdbind.c
new file mode 100644
index 000000000..a1ec0ad5a
--- /dev/null
+++ b/private/ntos/tdi/isn/flt/fwdbind.c
@@ -0,0 +1,161 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\flt\fwdbind.c
+
+Abstract:
+ IPX Filter driver binding with forwarder routines
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+
+ // Buffer to keep forwarder entry points
+IPX_FLT_BIND_OUTPUT FltBindOutput;
+// global handle of the FWD driver
+HANDLE HdlFwdFile = NULL;
+
+
+/*++
+ B i n d T o F w d D r i v e r
+
+Routine Description:
+
+ Opens forwarder driver and exchages entry points
+Arguments:
+ None
+Return Value:
+ STATUS_SUCCESS if successful,
+ STATUS_UNSUCCESSFUL otherwise
+
+--*/
+NTSTATUS
+BindToFwdDriver (
+ KPROCESSOR_MODE requestorMode
+ ) {
+ NTSTATUS status;
+ IO_STATUS_BLOCK IoStatusBlock;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING UstrFwdFileName;
+ IPX_FLT_BIND_INPUT FltBindInput = {Filter, InterfaceDeleted};
+
+ ASSERT (HdlFwdFile == NULL);
+
+ RtlInitUnicodeString (&UstrFwdFileName, IPXFWD_NAME);
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &UstrFwdFileName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+ if (requestorMode==UserMode)
+ status = ZwCreateFile(&HdlFwdFile,
+ SYNCHRONIZE | GENERIC_READ,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0L);
+ else
+ status = NtCreateFile(&HdlFwdFile,
+ SYNCHRONIZE | GENERIC_READ,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0L);
+
+ if (NT_SUCCESS(status)) {
+
+ if (requestorMode==UserMode)
+ status = ZwDeviceIoControlFile(
+ HdlFwdFile, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_FWD_INTERNAL_BIND_FILTER, // IoControlCode
+ &FltBindInput, // Input Buffer
+ sizeof(FltBindInput), // Input Buffer Length
+ &FltBindOutput, // Output Buffer
+ sizeof(FltBindOutput));// Output Buffer Length
+ else
+ status = NtDeviceIoControlFile(
+ HdlFwdFile, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_FWD_INTERNAL_BIND_FILTER, // IoControlCode
+ &FltBindInput, // Input Buffer
+ sizeof(FltBindInput), // Input Buffer Length
+ &FltBindOutput, // Output Buffer
+ sizeof(FltBindOutput));// Output Buffer Length
+ if (NT_SUCCESS (status))
+ return STATUS_SUCCESS;
+ else
+ IpxFltDbgPrint (DBG_ERRORS,
+ ("IpxFlt: Failed to bind to forwarder %08lx.\n", status));
+ if (requestorMode==KernelMode)
+ ZwClose (HdlFwdFile);
+ else
+ NtClose (HdlFwdFile);
+
+ }
+ else
+ IpxFltDbgPrint (DBG_ERRORS,
+ ("IpxFlt: Failed create forwarder file %08lx.\n", status));
+ HdlFwdFile = NULL;
+ return status;
+}
+
+
+
+/*++
+ U n i n d T o F w d D r i v e r
+
+Routine Description:
+
+ Closes forwarder driver
+Arguments:
+ None
+Return Value:
+ None
+
+--*/
+VOID
+UnbindFromFwdDriver (
+ KPROCESSOR_MODE requestorMode
+ ) {
+ NTSTATUS status;
+
+ ASSERT (HdlFwdFile != NULL);
+
+ if (requestorMode==UserMode)
+ status = ZwClose (HdlFwdFile);
+ else
+ status = NtClose (HdlFwdFile);
+ ASSERT (NT_SUCCESS (status));
+ HdlFwdFile = NULL;
+}
+
diff --git a/private/ntos/tdi/isn/flt/fwdbind.h b/private/ntos/tdi/isn/flt/fwdbind.h
new file mode 100644
index 000000000..36f79f383
--- /dev/null
+++ b/private/ntos/tdi/isn/flt/fwdbind.h
@@ -0,0 +1,69 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\flt\fwdbind.h
+
+Abstract:
+ IPX Filter driver binding with forwarder routines
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+#ifndef _IPXFLT_FWDBIND_
+#define _IPXFLT_FWDBIND_
+
+
+ // Buffer to keep forwarder entry points
+extern IPX_FLT_BIND_OUTPUT FltBindOutput;
+
+ // Forwarder entry points macros
+#define FwdSetFilterInContext (FltBindOutput.SetIfInContextHandler)
+#define FwdSetFilterOutContext (FltBindOutput.SetIfOutContextHandler)
+
+
+/*++
+ B i n d T o F w d D r i v e r
+
+Routine Description:
+
+ Opens forwarder driver and exchages entry points
+Arguments:
+ None
+Return Value:
+ STATUS_SUCCESS if successful,
+ STATUS_UNSUCCESSFUL otherwise
+
+--*/
+NTSTATUS
+BindToFwdDriver (
+ KPROCESSOR_MODE requestorMode
+ );
+
+/*++
+ U n i n d T o F w d D r i v e r
+
+Routine Description:
+
+ Closes forwarder driver
+Arguments:
+ None
+Return Value:
+ None
+
+--*/
+VOID
+UnbindFromFwdDriver (
+ KPROCESSOR_MODE requestorMode
+ );
+
+#endif
+
diff --git a/private/ntos/tdi/isn/flt/mp/makefile b/private/ntos/tdi/isn/flt/mp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isn/flt/mp/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isn/flt/mp/sources b/private/ntos/tdi/isn/flt/mp/sources
new file mode 100644
index 000000000..dc48d81bb
--- /dev/null
+++ b/private/ntos/tdi/isn/flt/mp/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+NT_UP=0
+
+TARGETPATH=\nt\public\sdk\lib
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/isn/flt/nwlnkflt.rc b/private/ntos/tdi/isn/flt/nwlnkflt.rc
new file mode 100644
index 000000000..2de2483f2
--- /dev/null
+++ b/private/ntos/tdi/isn/flt/nwlnkflt.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "NWLINK2 Traffic Filter Driver"
+#define VER_INTERNALNAME_STR "nwlnkflt.sys"
+#define VER_ORIGINALFILENAME_STR "nwlnkflt.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/tdi/isn/flt/precomp.h b/private/ntos/tdi/isn/flt/precomp.h
new file mode 100644
index 000000000..9a9d9d54d
--- /dev/null
+++ b/private/ntos/tdi/isn/flt/precomp.h
@@ -0,0 +1,50 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\precomp.h
+
+Abstract:
+ IPX Forwarder driver precompiled header file
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+#define ISN_NT 1
+#define NT 1
+
+#if DBG
+#define DEBUG 1
+#endif
+
+// System includes
+#include <ntos.h>
+#include <ndis.h>
+#include <zwapi.h>
+#include <limits.h>
+
+// Routing includes
+#include "ipxtfflt.h"
+
+// IPX shared includes
+#include "ipxfwd.h"
+#include "ipxfltif.h"
+
+// Internal module prototypes
+#include "filter.h"
+#include "fwdbind.h"
+#include "debug.h"
+
+
+#pragma hdrstop
+
+
+
diff --git a/private/ntos/tdi/isn/flt/sources.inc b/private/ntos/tdi/isn/flt/sources.inc
new file mode 100644
index 000000000..4204e970c
--- /dev/null
+++ b/private/ntos/tdi/isn/flt/sources.inc
@@ -0,0 +1,51 @@
+!IF 0
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author: Vadim Eydelman
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=nwlnkflt
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..\;..\..\inc;..\..\..\..\inc;..\..\..\..\..\inc
+
+C_DEFINES=$(C_DEFINES) -D_NTDRIVER_
+
+!IFDEF BUILD_FOR_3_51
+C_DEFINES= $(C_DEFINES) -D_NTIFS_
+!ENDIF
+
+PRECOMPILED_INCLUDE=..\precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=..\driver.c \
+ ..\filter.c \
+ ..\fwdbind.c \
+ ..\debug.c \
+ ..\nwlnkflt.rc
+
+RELATIVE_DEPTH=..\..
+
+ALT_PROJECT_TARGET=Routing
+
diff --git a/private/ntos/tdi/isn/flt/up/makefile b/private/ntos/tdi/isn/flt/up/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isn/flt/up/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isn/flt/up/sources b/private/ntos/tdi/isn/flt/up/sources
new file mode 100644
index 000000000..229bd8e34
--- /dev/null
+++ b/private/ntos/tdi/isn/flt/up/sources
@@ -0,0 +1,31 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+UP_DRIVER=yes
+
+BINPLACE_FLAGS=$(BINPLACE_FLAGS) -d dump\up
+
+TARGETPATH=obj
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/isn/fwd/ddreqs.c b/private/ntos/tdi/isn/fwd/ddreqs.c
new file mode 100644
index 000000000..76ab93ea4
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/ddreqs.c
@@ -0,0 +1,220 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\ddreqs.c
+
+Abstract:
+ Management of demand dial request queues
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+
+LIST_ENTRY ConnectionIrpQueue;
+LIST_ENTRY ConnectionRequestQueue;
+
+/*++
+ Q u e u e C o n n e c t i o n R e q u e s t
+
+Routine Description:
+ Adds request to connected the interface to the queue
+
+Arguments:
+ ifCB - control block of the interface that needs to be
+ connected
+ packet - packet that prompted the connection request
+ data - pointer to actual data in the packet
+ oldIRQL - IRQL at which interface lock was acquired
+
+Return Value:
+ None
+
+ Note that interface lock must be acquired before calling this
+ routine which will release it
+
+--*/
+VOID
+QueueConnectionRequest (
+ PINTERFACE_CB ifCB,
+ PNDIS_PACKET packet,
+ PUCHAR data,
+ KIRQL oldIRQL
+ ) {
+ KIRQL cancelIRQL;
+
+ IoAcquireCancelSpinLock (&cancelIRQL);
+ SET_IF_CONNECTING (ifCB);
+ if (!IsListEmpty (&ConnectionIrpQueue)) {
+ PIRP irp = CONTAINING_RECORD (
+ ConnectionIrpQueue.Flink,
+ IRP,
+ Tail.Overlay.ListEntry);
+ PIO_STACK_LOCATION irpStack=IoGetCurrentIrpStackLocation(irp);
+ RemoveEntryList (&irp->Tail.Overlay.ListEntry);
+ ASSERT (irpStack->Parameters.DeviceIoControl.IoControlCode
+ ==IOCTL_FWD_GET_DIAL_REQUEST);
+ ASSERT ((irpStack->Parameters.DeviceIoControl.IoControlCode&3)
+ ==METHOD_BUFFERED);
+ IoSetCancelRoutine (irp, NULL);
+ IoReleaseCancelSpinLock (cancelIRQL);
+
+ FillConnectionRequest (
+ ifCB->ICB_Index,
+ packet,
+ data,
+ (PFWD_DIAL_REQUEST)irp->AssociatedIrp.SystemBuffer,
+ irpStack->Parameters.DeviceIoControl.OutputBufferLength,
+ &irp->IoStatus.Information);
+ irp->IoStatus.Status = STATUS_SUCCESS;
+
+ KeReleaseSpinLock (&ifCB->ICB_Lock, oldIRQL);
+ IpxFwdDbgPrint (DBG_DIALREQS, DBG_WARNING,
+ ("IpxFwd: Passing dial request for if %ld (icb:%08lx) with %d bytes of data.\n",
+ ifCB->ICB_Index, ifCB, irp->IoStatus.Information));
+ IoCompleteRequest (irp, IO_NO_INCREMENT);
+ }
+ else {
+ InsertTailList (&ConnectionRequestQueue, &ifCB->ICB_ConnectionLink);
+ IoReleaseCancelSpinLock (cancelIRQL);
+ ifCB->ICB_ConnectionPacket = packet;
+ ifCB->ICB_ConnectionData = data;
+ KeReleaseSpinLock (&ifCB->ICB_Lock, oldIRQL);
+ }
+}
+
+/*++
+ D e q u e u e C o n n e c t i o n R e q u e s t
+
+Routine Description:
+ Removes conection requset for the interface from the queue
+
+Arguments:
+ ifCB - control block of the interface that needs to be
+ removed
+
+Return Value:
+ None
+
+--*/
+VOID
+DequeueConnectionRequest (
+ PINTERFACE_CB ifCB
+ ) {
+ KIRQL cancelIRQL;
+ IoAcquireCancelSpinLock (&cancelIRQL);
+ if (IsListEntry (&ifCB->ICB_ConnectionLink)) {
+ RemoveEntryList (&ifCB->ICB_ConnectionLink);
+ InitializeListEntry (&ifCB->ICB_ConnectionLink);
+ }
+ IoReleaseCancelSpinLock (cancelIRQL);
+}
+
+/*++
+ F i l l C o n n e c t i o n R e q u e s t
+
+Routine Description:
+ Fills the provided buffer with index of interface that needs
+ to be connected and packet that prompted the request
+
+Arguments:
+ index - if index
+ packet - packet that prompted the request
+ data - pointer to IPX data (IPX header) inside of the packet
+ request - request buffer to fill
+ reqSize - size of request buffer
+ bytesCopied - bytesCopied into the request buffer
+
+Return Value:
+ STATUS_SUCCESS - array was filled successfully
+ This routine assumes that there it is called only when there
+ are outstanding requests in the request queue
+
+--*/
+VOID
+FillConnectionRequest (
+ IN ULONG index,
+ IN PNDIS_PACKET packet,
+ IN PUCHAR data,
+ IN OUT PFWD_DIAL_REQUEST request,
+ IN ULONG reqSize,
+ OUT PULONG bytesCopied
+ ) {
+ PNDIS_BUFFER buf;
+
+ *bytesCopied = 0;
+ request->IfIndex = index;
+ NdisQueryPacket (packet, NULL, NULL, &buf, NULL);
+ do {
+ PVOID va;
+ UINT length;
+
+ NdisQueryBuffer (buf, &va, &length);
+ if (((PUCHAR)va<=data)
+ && ((PUCHAR)va+length>data)) {
+ TdiCopyMdlToBuffer (buf,
+ data-(PUCHAR)va,
+ request,
+ FIELD_OFFSET (FWD_DIAL_REQUEST, Packet),
+ reqSize,
+ bytesCopied);
+ *bytesCopied += FIELD_OFFSET (FWD_DIAL_REQUEST, Packet);
+ break;
+ }
+ NdisGetNextBuffer (buf, &buf);
+ }
+ while (buf!=NULL);
+}
+
+/*++
+ F a i l C o n n e c t i o n R e q u e s t s
+
+Routine Description:
+ Cleans up on connection request failure
+
+Arguments:
+ InterfaceIndex - index of interface that could not be connected
+
+Return Value:
+ STATUS_SUCCESS - clean up was successfull
+ STATUS_UNSUCCESSFUL - interface with this index does not exist
+
+--*/
+NTSTATUS
+FailConnectionRequest (
+ IN ULONG InterfaceIndex
+ ) {
+ PINTERFACE_CB ifCB;
+ KIRQL oldIRQL;
+
+ ASSERT (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX);
+
+ ifCB = GetInterfaceReference (InterfaceIndex);
+ if (ifCB!=NULL) {
+ IpxFwdDbgPrint (DBG_DIALREQS, DBG_WARNING,
+ ("IpxFwd: Dial request failed for if %ld (icb:%08lx).\n",
+ ifCB->ICB_Index, ifCB));
+ ProcessInternalQueue (ifCB);
+ ProcessExternalQueue (ifCB);
+ KeAcquireSpinLock (&ifCB->ICB_Lock, &oldIRQL);
+ if (IS_IF_CONNECTING (ifCB)) {
+ SET_IF_NOT_CONNECTING (ifCB);
+ DequeueConnectionRequest (ifCB);
+ }
+ KeReleaseSpinLock (&ifCB->ICB_Lock, oldIRQL);
+ ReleaseInterfaceReference (ifCB);
+ return STATUS_SUCCESS;
+ }
+ else
+ return STATUS_UNSUCCESSFUL;
+}
+
diff --git a/private/ntos/tdi/isn/fwd/ddreqs.h b/private/ntos/tdi/isn/fwd/ddreqs.h
new file mode 100644
index 000000000..416091c92
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/ddreqs.h
@@ -0,0 +1,149 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\ddreqs.h
+
+Abstract:
+ Management of demand dial request queues
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+#ifndef _IPXFWD_DDREQS_
+#define _IPXFWD_DDREQS_
+
+// Connection requests to DIM
+// Queue of request that need to be satisfied by DIM
+extern LIST_ENTRY ConnectionRequestQueue;
+// Queue of request IRPs posted by the router manager
+extern LIST_ENTRY ConnectionIrpQueue;
+
+/*++
+ I n i t i a l i z e C o n n e c t i o n Q u e u e s
+
+Routine Description:
+ Initializes connection request and irp queues
+
+Arguments:
+ None
+
+Return Value:
+ None
+
+--*/
+//VOID
+//InitializeConnectionQueues (
+// void
+// );
+#define InitializeConnectionQueues() { \
+ InitializeListHead (&ConnectionIrpQueue); \
+ InitializeListHead (&ConnectionRequestQueue); \
+}
+
+/*++
+ F i l l C o n n e c t i o n R e q u e s t
+
+Routine Description:
+ Fills the provided buffer with index of interface that needs
+ to be connected and packet that prompted the request
+
+Arguments:
+ index - if index
+ packet - packet that prompted the request
+ data - pointer to IPX data (IPX header) inside of the packet
+ request - request buffer to fill
+ reqSize - size of request buffer
+ bytesCopied - bytesCopied into the request buffer
+
+Return Value:
+ STATUS_SUCCESS - array was filled successfully
+ This routine assumes that there it is called only when there
+ are outstanding requests in the request queue
+
+--*/
+VOID
+FillConnectionRequest (
+ IN ULONG index,
+ IN PNDIS_PACKET packet,
+ IN PUCHAR data,
+ IN OUT PFWD_DIAL_REQUEST request,
+ IN ULONG reqSize,
+ OUT PULONG bytesCopied
+ );
+
+/*++
+ F a i l C o n n e c t i o n R e q u e s t s
+
+Routine Description:
+ Cleans up on connection request failure
+
+Arguments:
+ InterfaceIndex - index of interface that could not be connected
+
+Return Value:
+ STATUS_SUCCESS - clean up was successfull
+ STATUS_UNSUCCESSFUL - interface with this index does not exist
+
+--*/
+NTSTATUS
+FailConnectionRequest (
+ IN ULONG InterfaceIndex
+ );
+
+/*++
+ Q u e u e C o n n e c t i o n R e q u e s t
+
+Routine Description:
+ Adds request to connected the interface to the queue
+
+Arguments:
+ ifCB - control block of the interface that needs to be
+ connected
+ packet - packet that prompted the connection request
+ data - pointer to actual data in the packet
+ oldIRQL - IRQL at which interface lock was acquired
+
+Return Value:
+ None
+
+ Note that interface lock must be acquired before calling this
+ routine which will release it
+
+--*/
+VOID
+QueueConnectionRequest (
+ PINTERFACE_CB ifCB,
+ PNDIS_PACKET packet,
+ PUCHAR data,
+ KIRQL oldIRQL
+ );
+
+/*++
+ D e q u e u e C o n n e c t i o n R e q u e s t
+
+Routine Description:
+ Removes conection requset for the interface from the queue
+
+Arguments:
+ ifCB - control block of the interface that needs to be
+ removed
+
+Return Value:
+ None
+
+--*/
+VOID
+DequeueConnectionRequest (
+ PINTERFACE_CB ifCB
+ );
+
+#endif
+
diff --git a/private/ntos/tdi/isn/fwd/debug.c b/private/ntos/tdi/isn/fwd/debug.c
new file mode 100644
index 000000000..9fa2f3f1c
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/debug.c
@@ -0,0 +1,7 @@
+#include "precomp.h"
+
+#if DBG
+ULONG DbgLevel = DEF_DBG_LEVEL;
+LONGLONG ActivityTreshhold = _I64_MAX;
+LARGE_INTEGER CounterFrequency;
+#endif
diff --git a/private/ntos/tdi/isn/fwd/debug.h b/private/ntos/tdi/isn/fwd/debug.h
new file mode 100644
index 000000000..251d23895
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/debug.h
@@ -0,0 +1,69 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: debug.h
+//
+// Description: Debug macros definitions
+//
+// Author: Stefan Solomon (stefans) October 4, 1993.
+//
+// Revision History:
+//
+//***
+
+#ifndef _IPXFWD_DEBUG_
+#define _IPXFWD_DEBUG_
+
+#if DBG
+#define DBG_PACKET_ALLOC ((ULONG)0x00000001)
+#define DBG_INTF_TABLE ((ULONG)0x00000002)
+#define DBG_ROUTE_TABLE ((ULONG)0x00000004)
+#define DBG_NBROUTE_TABLE ((ULONG)0x00000008)
+#define DBG_IOCTLS ((ULONG)0x00000010)
+#define DBG_LINEIND ((ULONG)0x00000020)
+#define DBG_IPXBIND ((ULONG)0x00000040)
+#define DBG_REGISTRY ((ULONG)0x00000080)
+#define DBG_INT_RECV ((ULONG)0x00000100)
+#define DBG_RECV ((ULONG)0x00000200)
+#define DBG_SEND ((ULONG)0x00000400)
+#define DBG_INT_SEND ((ULONG)0x00000800)
+#define DBG_NETBIOS ((ULONG)0x00001000)
+#define DBG_IPXROUTE ((ULONG)0x00002000)
+#define DBG_DIALREQS ((ULONG)0x00004000)
+#define DBG_SPOOFING ((ULONG)0x00008000)
+
+#define DBG_INFORMATION ((ULONG)0x10000000)
+#define DBG_WARNING ((ULONG)0x20000000)
+#define DBG_ERROR ((ULONG)0x40000000)
+
+#define DEF_DBG_LEVEL ( \
+ DBG_ERROR|DBG_WARNING \
+ | DBG_INTF_TABLE \
+ | DBG_LINEIND \
+ | DBG_IPXBIND \
+ | DBG_REGISTRY \
+ | DBG_IPXROUTE \
+ | DBG_IOCTLS \
+ | DBG_DIALREQS \
+ | DBG_SPOOFING \
+ )
+
+extern ULONG DbgLevel;
+extern LONGLONG ActivityTreshhold;
+extern LARGE_INTEGER CounterFrequency;
+
+#define IpxFwdDbgPrint(COMPONENT,LEVEL,ARGS) \
+ do { \
+ if ((DbgLevel & ((COMPONENT)|(LEVEL)))==((COMPONENT)|(LEVEL))){ \
+ DbgPrint ARGS; \
+ } \
+ } while (0)
+
+#else
+#define IpxFwdDbgPrint(COMPONENT,LEVEL,ARGS) do {NOTHING;} while (0)
+#endif
+
+#endif
diff --git a/private/ntos/tdi/isn/fwd/dirs b/private/ntos/tdi/isn/fwd/dirs
new file mode 100644
index 000000000..0dab2f056
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/dirs
@@ -0,0 +1,22 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=up mp
diff --git a/private/ntos/tdi/isn/fwd/driver.c b/private/ntos/tdi/isn/fwd/driver.c
new file mode 100644
index 000000000..ac03cb31e
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/driver.c
@@ -0,0 +1,1157 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\driver.c
+
+Abstract:
+ IPX Forwarder driver dispatch routines
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+
+const UCHAR BROADCAST_NODE[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+const LONGLONG WaitTimeout = -50000000i64;
+volatile BOOLEAN IpxFwdInitialized = FALSE;
+
+BOOLEAN MeasuringPerformance = FALSE;
+KSPIN_LOCK PerfCounterLock;
+FWD_PERFORMANCE PerfBlock;
+
+LONG ClientCount = 0;
+KEVENT ClientsGoneEvent;
+
+PFILE_OBJECT RouterFile, FilterFile;
+
+NTSTATUS
+IpxFwdDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+IpxFwdUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+NTSTATUS
+DoStart (
+ IN ULONG RouteHashTableSize,
+ IN BOOLEAN thisMachineOnly
+ );
+
+NTSTATUS
+DoStop (
+ void
+ );
+
+NTSTATUS
+DoSetInterface (
+ IN ULONG InterfaceIndex,
+ IN BOOLEAN NetbiosAccept,
+ IN UCHAR NetbiosDeliver
+ );
+
+NTSTATUS
+DoGetInterface (
+ IN ULONG InterfaceIndex,
+ OUT PFWD_IF_STATS stats,
+ OUT BOOLEAN *NetbiosAccept,
+ OUT UCHAR *NetbiosDeliver
+ );
+
+NTSTATUS
+DoSetNbNames (
+ IN ULONG InterfaceIndex,
+ IN ULONG Count,
+ IN PFWD_NB_NAME Names
+ );
+
+NTSTATUS
+DoGetNbNames (
+ IN ULONG InterfaceIndex,
+ IN OUT ULONG *BufferSize,
+ OUT ULONG *Count,
+ OUT PFWD_NB_NAME Names
+ );
+
+NTSTATUS
+DoBindInterface (
+ IN ULONG InterfaceIndex,
+ IN PFWD_ADAPTER_BINDING_INFO info
+ );
+
+NTSTATUS
+DoUnbindInterface (
+ IN ULONG InterfaceIndex
+ );
+
+NTSTATUS
+DoDisableInterface (
+ IN ULONG InterfaceIndex
+ );
+
+NTSTATUS
+DoEnableInterface (
+ IN ULONG InterfaceIndex
+ );
+
+NTSTATUS
+DoSetRoutes (
+ IN PFWD_ROUTE_SET_PARAMS routeArray,
+ IN ULONG nRoutes,
+ OUT PULONG nProcessed
+ );
+
+VOID
+IpxFwdCancel (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP irp
+ );
+
+NTSTATUS
+DoGetPerfCounters (
+ PFWD_PERFORMANCE_PARAMS perfParams
+ );
+
+/*++
+ D r i v e r E n t r y
+
+Routine Description:
+
+ Installable driver initialization entry point.
+ This entry point is called directly by the I/O system.
+
+Arguments:
+
+ DriverObject - pointer to the driver object
+
+ RegistryPath - pointer to a unicode string representing the path
+ to driver-specific key in the registry
+
+Return Value:
+
+ STATUS_SUCCESS if successful,
+ STATUS_UNSUCCESSFUL otherwise
+
+--*/
+NTSTATUS
+DriverEntry (
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ ) {
+
+ PDEVICE_OBJECT deviceObject = NULL;
+ NTSTATUS status;
+ WCHAR deviceNameBuffer[] = IPXFWD_NAME;
+ UNICODE_STRING deviceNameUnicodeString;
+
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION,
+ ("IpxFwd: Entering DriverEntry\n"));
+
+ //
+ // Create an non-EXCLUSIVE device object
+ //
+
+ RtlInitUnicodeString (&deviceNameUnicodeString,
+ deviceNameBuffer);
+
+ status = IoCreateDevice (DriverObject,
+ 0,
+ &deviceNameUnicodeString,
+ FILE_DEVICE_IPXFWD,
+ 0,
+ FALSE, // Non-Exclusive
+ &deviceObject
+ );
+
+ if (NT_SUCCESS(status)) {
+ //
+ // Create dispatch points for device control, create, close.
+ //
+ GetForwarderParameters (RegistryPath);
+ DriverObject->MajorFunction[IRP_MJ_CREATE]
+ = DriverObject->MajorFunction[IRP_MJ_CLEANUP]
+ = DriverObject->MajorFunction[IRP_MJ_CLOSE]
+ = DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]
+ = IpxFwdDispatch;
+ DriverObject->DriverUnload = IpxFwdUnload;
+ status = BindToIpxDriver (KernelMode);
+ if (NT_SUCCESS (status)) {
+
+#if DBG
+ KeQueryPerformanceCounter (&CounterFrequency);
+#endif
+ FilterFile = RouterFile = NULL;
+ ClientCount = 0;
+ return STATUS_SUCCESS;
+ }
+ IoDeleteDevice (DriverObject->DeviceObject);
+ }
+ else
+ IpxFwdDbgPrint (DBG_IOCTLS, DBG_ERROR,
+ ("IpxFwd: IoCreateDevice failed\n"));
+
+ return status;
+}
+
+
+
+/*++
+
+Routine Description:
+
+ Process the IRPs sent to this device.
+
+Arguments:
+
+ DeviceObject - pointer to a device object
+
+ Irp - pointer to an I/O Request Packet
+
+Return Value:
+
+
+--*/
+NTSTATUS
+IpxFwdDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ ) {
+ PIO_STACK_LOCATION IrpStack;
+ PVOID inBuffer, outBuffer;
+ ULONG inpBufLength;
+ ULONG outBufLength;
+ NTSTATUS status;
+ KIRQL cancelIRQL;
+
+
+ Irp->IoStatus.Information = 0;
+ status = STATUS_SUCCESS;
+
+ //
+ // Get a pointer to the current location in the Irp. This is where
+ // the function codes and parameters are located.
+ //
+
+ IrpStack = IoGetCurrentIrpStackLocation(Irp);
+
+
+ switch (IrpStack->MajorFunction) {
+ case IRP_MJ_CREATE:
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_WARNING, ("IpxFwd: IRP_MJ_CREATE\n"));
+ break;
+
+ case IRP_MJ_CLOSE:
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_WARNING, ("IpxFwd: IRP_MJ_CLOSE\n"));
+ if (EnterForwarder ()) {
+ if (IrpStack->FileObject==RouterFile) {
+ LeaveForwarder ();
+ IpxFwdInitialized = FALSE;
+ while (InterlockedDecrement (&ClientCount)>=0) {
+ KeWaitForSingleObject (&ClientsGoneEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ (PLARGE_INTEGER)&WaitTimeout);
+ InterlockedIncrement (&ClientCount);
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_ERROR,
+ ("IpxFwd: Waiting for all clients (%ld) to exit.\n",
+ ClientCount));
+ }
+ status = DoStop ();
+ ClientCount = 0;
+ RouterFile = NULL;
+ }
+ else if (IrpStack->FileObject==FilterFile) {
+ UnbindFilterDriver ();
+ FilterFile = NULL;
+ LeaveForwarder ();
+ }
+ else
+ LeaveForwarder ();
+ }
+ break;
+
+ case IRP_MJ_CLEANUP:
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_WARNING, ("IpxFwd: IRP_MJ_CLEANUP\n"));
+ if (EnterForwarder ()) {
+ if (IrpStack->FileObject==RouterFile) {
+ IoAcquireCancelSpinLock (&cancelIRQL);
+ while (!IsListEmpty (&ConnectionIrpQueue)) {
+ PIRP irp = CONTAINING_RECORD (ConnectionIrpQueue.Blink,
+ IRP, Tail.Overlay.ListEntry);
+ irp->Cancel = TRUE;
+ irp->CancelIrql = cancelIRQL;
+ irp->CancelRoutine = NULL;
+ IpxFwdCancel(DeviceObject, irp);
+ IoAcquireCancelSpinLock (&cancelIRQL);
+ }
+ IoReleaseCancelSpinLock(cancelIRQL);
+ }
+ LeaveForwarder ();
+ }
+ break;
+
+ case IRP_MJ_DEVICE_CONTROL:
+ //
+ // Get the pointer to the input/output buffer and it's length
+ //
+
+ status = STATUS_INVALID_PARAMETER;
+ inpBufLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
+ outBufLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
+ switch (IrpStack->Parameters.DeviceIoControl.IoControlCode&3) {
+ case METHOD_BUFFERED:
+ inBuffer = outBuffer = Irp->AssociatedIrp.SystemBuffer;
+ break;
+
+ case METHOD_IN_DIRECT:
+ case METHOD_OUT_DIRECT:
+ inBuffer = Irp->AssociatedIrp.SystemBuffer;
+ if (outBufLength>0) {
+ outBuffer = MmGetSystemAddressForMdl (Irp->MdlAddress);
+ }
+ else {
+ outBuffer = NULL;
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_ERROR,
+ ("IpxFwd: IOCTL...METHOD_DIRECT with 0 output buffer ???\n"));
+ }
+ break;
+ default:
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_ERROR,
+ ("IpxFwd: IOCTL...METHOD_NEITHER ???\n"));
+ goto DispatchExit;
+ }
+
+
+ if (EnterForwarder ()) {
+ if (IrpStack->FileObject==RouterFile) {
+ switch (IrpStack->Parameters.DeviceIoControl.IoControlCode) {
+ case IOCTL_FWD_SET_ROUTES:
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_SET_ROUTES\n"));
+ if (inpBufLength>=sizeof (FWD_ROUTE_SET_PARAMS))
+ status = DoSetRoutes (
+ (PFWD_ROUTE_SET_PARAMS)inBuffer,
+ inpBufLength/sizeof(FWD_ROUTE_SET_PARAMS),
+ &Irp->IoStatus.Information);
+
+ break;
+
+ case IOCTL_FWD_SET_NB_NAMES:
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_SET_NB_NAMES\n"));
+ if (inpBufLength==sizeof (ULONG))
+ status = DoSetNbNames (
+ *((PULONG)inBuffer),
+ outBufLength/sizeof (FWD_NB_NAME),
+ (PFWD_NB_NAME)outBuffer);
+ break;
+
+ case IOCTL_FWD_RESET_NB_NAMES:
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_RESET_NB_NAMES\n"));
+ if (inpBufLength==sizeof (ULONG))
+ status = DoSetNbNames (*((PULONG)inBuffer), 0, NULL);
+
+ break;
+ case IOCTL_FWD_GET_NB_NAMES:
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_GET_NB_NAMES\n"));
+ if ((inpBufLength==sizeof (ULONG))
+ && (outBufLength>=sizeof(ULONG))) {
+ Irp->IoStatus.Information = outBufLength
+ -FIELD_OFFSET (FWD_NB_NAMES_PARAMS, Names);
+ status = DoGetNbNames (
+ *((PULONG)inBuffer),
+ &Irp->IoStatus.Information,
+ &((PFWD_NB_NAMES_PARAMS)outBuffer)->TotalCount,
+ ((PFWD_NB_NAMES_PARAMS)outBuffer)->Names);
+ if (NT_SUCCESS (status)) {
+ Irp->IoStatus.Information += FIELD_OFFSET (
+ FWD_NB_NAMES_PARAMS, Names);
+ }
+ }
+ break;
+
+ case IOCTL_FWD_CREATE_INTERFACE:
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_CREATE_INTERFACE\n"));
+ if (inpBufLength==sizeof(FWD_IF_CREATE_PARAMS))
+ status = AddInterface (
+ ((PFWD_IF_CREATE_PARAMS)inBuffer)->Index,
+ ((PFWD_IF_CREATE_PARAMS)inBuffer)->InterfaceType,
+ ((PFWD_IF_CREATE_PARAMS)inBuffer)->NetbiosAccept,
+ ((PFWD_IF_CREATE_PARAMS)inBuffer)->NetbiosDeliver);
+ break;
+
+ case IOCTL_FWD_DELETE_INTERFACE:
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_DELETE_INTERFACE\n"));
+ if (inpBufLength==sizeof(ULONG))
+ status = DeleteInterface (
+ *((PULONG)inBuffer));
+
+ break;
+
+ case IOCTL_FWD_SET_INTERFACE:
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_SET_INTERFACE\n"));
+ if (inpBufLength==sizeof(FWD_IF_SET_PARAMS))
+ status = DoSetInterface (
+ ((PFWD_IF_SET_PARAMS)inBuffer)->Index,
+ ((PFWD_IF_SET_PARAMS)inBuffer)->NetbiosAccept,
+ ((PFWD_IF_SET_PARAMS)inBuffer)->NetbiosDeliver);
+ break;
+
+ case IOCTL_FWD_GET_INTERFACE:
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_GET_INTERFACE\n"));
+ if ((inpBufLength==sizeof(ULONG))
+ && (outBufLength==sizeof(FWD_IF_GET_PARAMS))) {
+ status = DoGetInterface (
+ *((PULONG)inBuffer),
+ &((PFWD_IF_GET_PARAMS)outBuffer)->Stats,
+ &((PFWD_IF_GET_PARAMS)outBuffer)->NetbiosAccept,
+ &((PFWD_IF_GET_PARAMS)outBuffer)->NetbiosDeliver);
+ if (NT_SUCCESS (status))
+ Irp->IoStatus.Information = sizeof(FWD_IF_GET_PARAMS);
+ }
+ break;
+
+ case IOCTL_FWD_BIND_INTERFACE:
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_BIND_INTERFACE\n"));
+ if (inpBufLength==sizeof(FWD_IF_BIND_PARAMS))
+ status = DoBindInterface (
+ ((PFWD_IF_BIND_PARAMS)inBuffer)->Index,
+ &((PFWD_IF_BIND_PARAMS)inBuffer)->Info);
+ break;
+
+ case IOCTL_FWD_UNBIND_INTERFACE:
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_UNBIND_INTERFACE\n"));
+ if (inpBufLength==sizeof(ULONG))
+ status = DoUnbindInterface (*((PULONG)inBuffer));
+ break;
+
+ case IOCTL_FWD_GET_DIAL_REQUEST:
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_GET_DIAL_REQUEST\n"));
+ if (outBufLength>=sizeof (ULONG)) {
+ IoAcquireCancelSpinLock (&cancelIRQL);
+ if (!IsListEmpty (&ConnectionRequestQueue)) {
+ PINTERFACE_CB ifCB = CONTAINING_RECORD (
+ ConnectionRequestQueue.Flink,
+ INTERFACE_CB,
+ ICB_ConnectionLink);
+ RemoveEntryList (&ifCB->ICB_ConnectionLink);
+ InitializeListEntry (&ifCB->ICB_ConnectionLink);
+ IoReleaseCancelSpinLock (cancelIRQL);
+ KeAcquireSpinLock (&ifCB->ICB_Lock, &cancelIRQL);
+ FillConnectionRequest (
+ ifCB->ICB_Index,
+ ifCB->ICB_ConnectionPacket,
+ ifCB->ICB_ConnectionData,
+ (PFWD_DIAL_REQUEST)outBuffer,
+ outBufLength,
+ &Irp->IoStatus.Information);
+ status = STATUS_SUCCESS;
+ KeReleaseSpinLock (&ifCB->ICB_Lock, cancelIRQL);
+ }
+ else {
+ InsertTailList (&ConnectionIrpQueue,
+ &Irp->Tail.Overlay.ListEntry);
+ IoSetCancelRoutine (Irp, IpxFwdCancel);
+ IoReleaseCancelSpinLock (cancelIRQL);
+ IoMarkIrpPending (Irp);
+ Irp->IoStatus.Status = status = STATUS_PENDING;
+ }
+ }
+ break;
+ case IOCTL_FWD_DIAL_REQUEST_FAILED:
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_DIAL_REQUEST_FAILED\n"));
+ if (inpBufLength==sizeof (ULONG))
+ status = FailConnectionRequest (
+ *((PULONG)inBuffer));
+ break;
+ case IOCTL_FWD_DISABLE_INTERFACE:
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_DISABLE_INTERFACE\n"));
+ if (inpBufLength==sizeof (ULONG))
+ status = DoDisableInterface (
+ *((PULONG)inBuffer));
+ break;
+ case IOCTL_FWD_ENABLE_INTERFACE:
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_ENABLE_INTERFACE\n"));
+ if (inpBufLength==sizeof (ULONG))
+ status = DoEnableInterface (
+ *((PULONG)inBuffer));
+ break;
+ default:
+ IpxFwdDbgPrint (DBG_IOCTLS, DBG_WARNING, ("IpxFwd: unknown IRP_MJ_DEVICE_CONTROL\n"));
+ break;
+
+ }
+ }
+ else if (IrpStack->Parameters.DeviceIoControl.IoControlCode
+ ==IOCTL_FWD_INTERNAL_BIND_FILTER) {
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_INTERNAL_BIND_FILTER\n"));
+ if ((inpBufLength==sizeof (IPX_FLT_BIND_INPUT))
+ && (outBufLength>=sizeof (ULONG))) {
+ if (outBufLength>=sizeof (IPX_FLT_BIND_OUTPUT)) {
+ BindFilterDriver (
+ (PIPX_FLT_BIND_INPUT)inBuffer,
+ (PIPX_FLT_BIND_OUTPUT)outBuffer);
+ Irp->IoStatus.Information = sizeof (IPX_FLT_BIND_OUTPUT);
+ FilterFile = IrpStack->FileObject;
+ status = STATUS_SUCCESS;
+ }
+ else {
+ IPX_FLT_BIND_OUTPUT bindOutput;
+ BindFilterDriver (
+ (PIPX_FLT_BIND_INPUT)inBuffer,
+ &bindOutput);
+ memcpy (outBuffer, &bindOutput, outBufLength);
+ Irp->IoStatus.Information = outBufLength;
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+ }
+ }
+ else if (IrpStack->Parameters.DeviceIoControl.IoControlCode
+ ==IOCTL_FWD_GET_PERF_COUNTERS) {
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_GET_PERF_COUNTERS\n"));
+ if (outBufLength==sizeof (FWD_PERFORMANCE_PARAMS))
+ status = DoGetPerfCounters (
+ ((PFWD_PERFORMANCE_PARAMS)outBuffer));
+ }
+ else {
+ status = STATUS_ACCESS_DENIED;
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_WARNING,
+ ("IpxFwd: IOCTL: %08lx on non-router file object!\n",
+ IrpStack->Parameters.DeviceIoControl.IoControlCode));
+ }
+ LeaveForwarder ();
+ } else {
+ if (IrpStack->Parameters.DeviceIoControl.IoControlCode==IOCTL_FWD_START) {
+ IpxFwdDbgPrint (DBG_IOCTLS, DBG_WARNING,
+ ("IpxFwd: IOCTL_FWD_START\n"));
+ if (inpBufLength==sizeof (FWD_START_PARAMS)) {
+ KeInitializeEvent (&ClientsGoneEvent,
+ SynchronizationEvent,
+ FALSE);
+ status = DoStart (
+ ((PFWD_START_PARAMS)inBuffer)->RouteHashTableSize,
+ ((PFWD_START_PARAMS)inBuffer)->ThisMachineOnly);
+ if (NT_SUCCESS (status)) {
+ RouterFile = IrpStack->FileObject;
+ IpxFwdInitialized = TRUE;
+ }
+ }
+ }
+ else {
+ IpxFwdDbgPrint (DBG_IOCTLS, DBG_ERROR,
+ ("IpxFwd: IOCTL: %08lx but fwd not started.\n",
+ IrpStack->Parameters.DeviceIoControl.IoControlCode));
+ }
+ }
+ break;
+ default:
+ IpxFwdDbgPrint (DBG_IOCTLS, DBG_ERROR,
+ ("IpxFwd: unknown MajorFunction.\n"));
+ break;
+ }
+
+DispatchExit:
+ if (status!=STATUS_PENDING) {
+ IpxFwdDbgPrint(DBG_IOCTLS,
+ NT_ERROR(status) ? DBG_WARNING : DBG_INFORMATION,
+ ("IpxFwd: completing IOCTL %08lx with status %08lx.\n",
+ IrpStack->Parameters.DeviceIoControl.IoControlCode,
+ status));
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ }
+
+ return status;
+}
+
+
+
+/*++
+
+Routine Description:
+ Cleans up on driver unload
+
+Arguments:
+
+ DriverObject - pointer to a driver object
+
+Return Value:
+
+
+--*/
+VOID
+IpxFwdUnload(
+ IN PDRIVER_OBJECT DriverObject
+ ) {
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_WARNING, ("IpxFwd: unloading\n"));
+ if (EnterForwarder ()) {
+ LeaveForwarder ();
+ IpxFwdInitialized = FALSE;
+ while (InterlockedDecrement (&ClientCount)>=0) {
+ KeWaitForSingleObject (&ClientsGoneEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ (PLARGE_INTEGER)&WaitTimeout);
+ InterlockedIncrement (&ClientCount);
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_ERROR,
+ ("IpxFwd: Waiting for all clients (%ld) to exit.\n",
+ ClientCount));
+ }
+ DoStop ();
+ }
+
+ UnbindFromIpxDriver (KernelMode);
+ IoDeleteDevice (DriverObject->DeviceObject);
+}
+
+
+
+/*++
+ D o S t a r t
+
+Routine Description:
+ Initializes all driver components and binds to IPX
+ stack driver at strat up
+
+Arguments:
+ RouteHashTableSize - size of route hash table
+ thisMachineOnly - whether to forward dialin client packets
+ to other dests on the net
+
+Return Value:
+ STATUS_SUCCESS - initialization succeded
+ STATUS_UNSUCCESSFULL - failure
+
+--*/
+NTSTATUS
+DoStart (
+ IN ULONG RouteHashTableSize,
+ IN BOOLEAN thisMachineOnly
+ ) {
+ NTSTATUS status;
+
+ InitializeConnectionQueues ();
+ RouteHashSize = RouteHashTableSize;
+ status = CreateTables ();
+ if (NT_SUCCESS (status)) {
+ InitializePacketAllocator ();
+ InitializeNetbiosQueue ();
+ InitializeRecvQueue ();
+ InitializeSendQueue ();
+ MeasuringPerformance = FALSE;
+ KeInitializeSpinLock (&PerfCounterLock);
+ ThisMachineOnly = thisMachineOnly;
+
+ return STATUS_SUCCESS;
+ }
+ return status;
+}
+
+/*++
+ D o S t o p
+
+Routine Description:
+ Cleans up allocated resources and unbinds from IPX stack
+ driver when forwarder is stopped
+
+Arguments:
+ None
+
+Return Value:
+ STATUS_SUCCESS - cleanup succeded
+
+--*/
+NTSTATUS
+DoStop (
+ void
+ ) {
+ if (FilterFile!=NULL) {
+ UnbindFilterDriver ();
+ FilterFile = NULL;
+ }
+ DeleteSendQueue ();
+ DeleteRecvQueue ();
+ DeleteNetbiosQueue ();
+ DeleteTables (); // Unbinds all bound interfaces
+ if (WanPacketListId!=-1) {
+ DeregisterPacketConsumer (WanPacketListId);
+ WanPacketListId = -1;
+ }
+ DeletePacketAllocator ();
+ return STATUS_SUCCESS;
+}
+
+/*++
+ D o S e t R o u t e s
+
+Routine Description:
+ Updates route table with supplied routes
+
+Arguments:
+ routeArray - array of routes to add/de;ete/update
+ nRoutes - number of routes in the array
+ nProcessed - number of routes that were processed successfully
+
+Return Value:
+ STATUS_SUCCESS - all routes were processed ok
+ error status - reason of failure for the first unprocessed route
+
+--*/
+NTSTATUS
+DoSetRoutes (
+ IN PFWD_ROUTE_SET_PARAMS routeArray,
+ IN ULONG nRoutes,
+ OUT PULONG nProcessed
+ ) {
+ NTSTATUS status=STATUS_SUCCESS;
+ UINT i;
+
+ for (i=0; i<nRoutes; i++, routeArray++) {
+ switch (routeArray->Action) {
+ case FWD_ADD_ROUTE:
+ status = AddRoute (routeArray->Network,
+ routeArray->NextHopAddress,
+ routeArray->TickCount,
+ routeArray->HopCount,
+ routeArray->InterfaceIndex);
+ break;
+ case FWD_DELETE_ROUTE:
+ status = DeleteRoute (routeArray->Network);
+ break;
+ case FWD_UPDATE_ROUTE:
+ status = UpdateRoute (routeArray->Network,
+ routeArray->NextHopAddress,
+ routeArray->TickCount,
+ routeArray->HopCount,
+ routeArray->InterfaceIndex);
+ break;
+ default:
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ if (!NT_SUCCESS (status))
+ break;
+ }
+ *nProcessed = i;
+ return status;
+}
+
+
+/*++
+ D o S e t N b N a m e s
+
+Routine Description:
+ Sets static Netbios Names on the interface
+
+Arguments:
+ InterfaceIndex - index oc interface on which to set names
+ Count - number of names to set
+ Names - array of netbios names
+
+Return Value:
+ STATUS_SUCCESS - names were set OK
+ STATUS_UNSUCCESSFULL - interface does not exist
+ STATUS_INSUFFICIENT_RESOURCES - not enough resources to complete
+ the operation
+
+--*/
+NTSTATUS
+DoSetNbNames (
+ IN ULONG InterfaceIndex,
+ IN ULONG Count,
+ IN PFWD_NB_NAME Names
+ ) {
+ PINTERFACE_CB ifCB;
+ KIRQL oldIRQL;
+ PNB_ROUTE nbRoutes;
+ NTSTATUS status=STATUS_SUCCESS;
+
+ ifCB = GetInterfaceReference (InterfaceIndex);
+ if (ifCB!=NULL) {
+ if (ifCB->ICB_NBRoutes!=NULL) {
+ DeleteNBRoutes (ifCB->ICB_NBRoutes, ifCB->ICB_NBRouteCount);
+ ifCB->ICB_NBRoutes = NULL;
+ ifCB->ICB_NBRouteCount = 0;
+ }
+ if (Count>0) {
+ status = AddNBRoutes (ifCB, Names, Count, &nbRoutes);
+ if (NT_SUCCESS (status)) {
+ ifCB->ICB_NBRoutes = nbRoutes;
+ ifCB->ICB_NBRouteCount = Count;
+ }
+ }
+ ReleaseInterfaceReference (ifCB);
+ }
+ else
+ status = STATUS_UNSUCCESSFUL;
+
+ return status;
+}
+
+
+/*++
+ D o G e t N b N a m e s
+
+Routine Description:
+ Gets all static Netbios Names on the interface
+
+Arguments:
+ InterfaceIndex - index of interface from which to get names
+ ArraySize - on input: size of the buffer to put names into
+ on output: size of data put into the array
+ Names - buffer to put names into names, if buffer
+ is to small to hold all names, this orutine stuffs
+ total number of names into the first ULONG in the
+ array (this is the only way to return in to the
+ caller through the IOCTL interface)
+
+Return Value:
+ STATUS_SUCCESS - names were copied into the array
+ STATUS_UNSUCCESSFULL - interface does not exist
+ STATUS_BUFFER_OVERFLOW - buffer is too small to copy all the
+ names, number of names are in the first ULONG of
+ the buffer
+
+--*/
+NTSTATUS
+DoGetNbNames (
+ IN ULONG InterfaceIndex,
+ IN OUT ULONG *ArraySize,
+ OUT ULONG *TotalCount,
+ OUT PFWD_NB_NAME Names
+ ) {
+ PINTERFACE_CB ifCB;
+ KIRQL oldIRQL;
+ NTSTATUS status=STATUS_SUCCESS;
+
+ ifCB = GetInterfaceReference (InterfaceIndex);
+ if (ifCB!=NULL) {
+ if (ifCB->ICB_NBRoutes!=NULL) {
+ ULONG i;
+ PFWD_NB_NAME nameLM = Names+(*ArraySize/sizeof(FWD_NB_NAME));
+ for (i=0; (i<ifCB->ICB_NBRouteCount)&&(Names<nameLM); i++, Names++)
+ NB_NAME_CPY (Names, &ifCB->ICB_NBRoutes[i].NBR_Name);
+ *ArraySize = sizeof (FWD_NB_NAME)*i;
+ *TotalCount = ifCB->ICB_NBRouteCount;
+ }
+ else {
+ *ArraySize = 0;
+ *TotalCount = 0;
+ }
+ ReleaseInterfaceReference (ifCB);
+ }
+ else
+ status = STATUS_UNSUCCESSFUL;
+
+ return status;
+}
+
+
+/*++
+ D o S e t I n t e r f a c e
+
+Routine Description:
+ Sets interface configurable parameters
+
+Arguments:
+ InterfaceIndex - index of interface to set
+ NetbiosAccept - whether to accept nb packets on the interface
+ NetbiosDeliver - whether to deliver nb packets on the interface
+
+Return Value:
+ STATUS_SUCCESS - interface was set OK
+ STATUS_UNSUCCESSFULL - interface does not exist
+
+--*/
+NTSTATUS
+DoSetInterface (
+ IN ULONG InterfaceIndex,
+ IN BOOLEAN NetbiosAccept,
+ IN UCHAR NetbiosDeliver
+ ) {
+ PINTERFACE_CB ifCB;
+ KIRQL oldIRQL;
+
+ ifCB = GetInterfaceReference (InterfaceIndex);
+ if (ifCB!=NULL) {
+ KeAcquireSpinLock (&ifCB->ICB_Lock, &oldIRQL);
+ ifCB->ICB_NetbiosAccept = NetbiosAccept;
+ ifCB->ICB_NetbiosDeliver = NetbiosDeliver;
+ KeReleaseSpinLock (&ifCB->ICB_Lock, oldIRQL);
+ ReleaseInterfaceReference (ifCB);
+ return STATUS_SUCCESS;
+ }
+ else
+ return STATUS_UNSUCCESSFUL;
+}
+
+
+/*++
+ D o G e t I n t e r f a c e
+
+Routine Description:
+ Gets interface configurable parameters and statistics
+
+Arguments:
+ InterfaceIndex - index of interface to query
+ stats - interface statistics
+ NetbiosAccept - whether nb packets accepter on the interface
+ NetbiosDeliver - whether nb packets delivered on the interface
+
+Return Value:
+ STATUS_SUCCESS - interface data was queried OK
+ STATUS_UNSUCCESSFULL - interface does not exist
+
+--*/
+NTSTATUS
+DoGetInterface (
+ IN ULONG InterfaceIndex,
+ OUT PFWD_IF_STATS stats,
+ OUT BOOLEAN *NetbiosAccept,
+ OUT UCHAR *NetbiosDeliver
+ ) {
+ PINTERFACE_CB ifCB;
+ KIRQL oldIRQL;
+
+ ifCB = GetInterfaceReference (InterfaceIndex);
+ if (ifCB!=NULL) {
+ *NetbiosAccept = ifCB->ICB_NetbiosAccept;
+ *NetbiosDeliver = ifCB->ICB_NetbiosDeliver;
+ IF_STATS_CPY (stats, &ifCB->ICB_Stats);
+ if (!IS_IF_ENABLED(ifCB))
+ stats->OperationalState = FWD_OPER_STATE_DOWN;
+ ReleaseInterfaceReference (ifCB);
+ return STATUS_SUCCESS;
+ }
+ else
+ return STATUS_UNSUCCESSFUL;
+}
+
+/*++
+ D o B i n d I n t e r f a c e
+
+Routine Description:
+ Binds interface to the specified adapter and sets binding
+ parameters
+
+Arguments:
+ InterfaceIndex - index of interface to bind
+ info - binding info
+
+Return Value:
+ STATUS_SUCCESS - interface was bound OK
+ STATUS_UNSUCCESSFULL - interface does not exist or could not be
+ bound
+--*/
+NTSTATUS
+DoBindInterface (
+ IN ULONG InterfaceIndex,
+ IN PFWD_ADAPTER_BINDING_INFO info
+ ) {
+ PINTERFACE_CB ifCB;
+ NTSTATUS status;
+
+ ifCB = GetInterfaceReference (InterfaceIndex);
+ if (ifCB!=NULL) {
+ if (ifCB->ICB_InterfaceType==FWD_IF_PERMANENT)
+ status = BindInterface (ifCB,
+ (USHORT)info->AdapterIndex,
+ info->MaxPacketSize,
+ info->Network,
+ info->LocalNode,
+ info->RemoteNode);
+ else
+ status = STATUS_SUCCESS;
+ ReleaseInterfaceReference (ifCB);
+ return status;
+ }
+ else
+ return STATUS_UNSUCCESSFUL;
+}
+
+
+/*++
+ D o U n b i n d I n t e r f a c e
+
+Routine Description:
+ Unbinds interface from the adapter and invalidates binding
+ parameters
+
+Arguments:
+ InterfaceIndex - index of interface to unbind
+
+Return Value:
+ STATUS_SUCCESS - interface was unbound OK
+ STATUS_UNSUCCESSFULL - interface does not exist
+--*/
+NTSTATUS
+DoUnbindInterface (
+ IN ULONG InterfaceIndex
+ ) {
+ PINTERFACE_CB ifCB;
+
+ ifCB = GetInterfaceReference (InterfaceIndex);
+ if (ifCB!=NULL) {
+ if (ifCB->ICB_InterfaceType==FWD_IF_PERMANENT)
+ UnbindInterface (ifCB);
+
+ ReleaseInterfaceReference (ifCB);
+ return STATUS_SUCCESS;
+ }
+ else
+ return STATUS_UNSUCCESSFUL;
+}
+
+/*++
+ D o D i s a b l e I n t e r f a c e
+
+Routine Description:
+ Disables all packet traffic through the interface
+
+Arguments:
+ InterfaceIndex - index of interface to disable
+
+Return Value:
+ STATUS_SUCCESS - interface was disabled OK
+ STATUS_UNSUCCESSFULL - interface does not exist
+--*/
+NTSTATUS
+DoDisableInterface (
+ IN ULONG InterfaceIndex
+ ) {
+ PINTERFACE_CB ifCB;
+
+ ifCB = GetInterfaceReference (InterfaceIndex);
+ if (ifCB!=NULL) {
+ KIRQL oldIRQL;
+ KeAcquireSpinLock (&ifCB->ICB_Lock, &oldIRQL);
+ if (IS_IF_ENABLED (ifCB)) {
+ SET_IF_DISABLED (ifCB);
+ KeReleaseSpinLock (&ifCB->ICB_Lock, oldIRQL);
+ if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX) {
+ ProcessInternalQueue (ifCB);
+ ProcessExternalQueue (ifCB);
+ }
+ }
+ else
+ KeReleaseSpinLock (&ifCB->ICB_Lock, oldIRQL);
+ ReleaseInterfaceReference (ifCB);
+ return STATUS_SUCCESS;
+ }
+ else
+ return STATUS_UNSUCCESSFUL;
+}
+
+
+/*++
+ D o E n a b l e I n t e r f a c e
+
+Routine Description:
+ Enables all packet traffic through the interface
+
+Arguments:
+ InterfaceIndex - index of interface to enable
+
+Return Value:
+ STATUS_SUCCESS - interface was disabled OK
+ STATUS_UNSUCCESSFULL - interface does not exist
+--*/
+NTSTATUS
+DoEnableInterface (
+ IN ULONG InterfaceIndex
+ ) {
+ PINTERFACE_CB ifCB;
+
+ ifCB = GetInterfaceReference (InterfaceIndex);
+ if (ifCB!=NULL) {
+ SET_IF_ENABLED (ifCB);
+ ReleaseInterfaceReference (ifCB);
+ return STATUS_SUCCESS;
+ }
+ else
+ return STATUS_UNSUCCESSFUL;
+}
+
+
+
+/*++
+ I p x F w d C a n c e l
+
+Routine Description:
+ Cancels specified IRP
+
+Arguments:
+ DeviceObject - forwarder device object
+ irp - irp to cancel
+
+Return Value:
+ None
+--*/
+VOID
+IpxFwdCancel (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP irp
+ ) {
+ RemoveEntryList (&irp->Tail.Overlay.ListEntry);
+ IoReleaseCancelSpinLock (irp->CancelIrql);
+
+ irp->IoStatus.Information = 0;
+ irp->IoStatus.Status = STATUS_CANCELLED;
+ IpxFwdDbgPrint(DBG_IOCTLS, DBG_WARNING, ("IpxFwd: completing cancelled irp.\n"));
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+}
+
+/*++
+ D o G e t P e r f C o u n t e r s
+
+Routine Description:
+ Gets performance counters
+
+Arguments:
+ perfParams - buffer ot pu counters into
+
+Return Value:
+ STATUS_SUCCESS - counter were copied ok
+ STATUS_UNSUCCESSFULL - performance measurement were not enabled
+--*/
+NTSTATUS
+DoGetPerfCounters (
+ OUT PFWD_PERFORMANCE_PARAMS perfParams
+ ) {
+ LONGLONG lTotalPacketProcessingTime;
+ LONGLONG lMaxPacketProcessingTime;
+ LONG lPacketCounter;
+ LONGLONG lTotalNbPacketProcessingTime;
+ LONGLONG lMaxNbPacketProcessingTime;
+ LONG lNbPacketCounter;
+ KIRQL oldIRQL;
+
+ if (!MeasuringPerformance)
+ return STATUS_UNSUCCESSFUL;
+
+ KeAcquireSpinLock (&PerfCounterLock, &oldIRQL);
+ *perfParams = PerfBlock;
+ memset (&PerfBlock, 0, sizeof (PerfBlock));
+ KeReleaseSpinLock (&PerfCounterLock, oldIRQL);
+ return STATUS_SUCCESS;
+}
+
+
+BOOLEAN
+DoLeaveForwarder (
+ VOID
+ ) {
+ return LeaveForwarder ();
+}
diff --git a/private/ntos/tdi/isn/fwd/driver.h b/private/ntos/tdi/isn/fwd/driver.h
new file mode 100644
index 000000000..ecc298345
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/driver.h
@@ -0,0 +1,102 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\driver.h
+
+Abstract:
+ IPX Forwarder driver dispatch routines
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+
+#ifndef _IPXFWD_DRIVER_
+#define _IPXFWD_DRIVER_
+
+// Pseudo constant 0xFFFFFFFFFFFFF
+extern const UCHAR BROADCAST_NODE[6];
+
+// Performance measurement:
+// Enabling flag
+extern BOOLEAN MeasuringPerformance;
+// Access control
+extern KSPIN_LOCK PerfCounterLock;
+// Statistic accumulators (counters)
+extern FWD_PERFORMANCE PerfBlock;
+
+// Access control for external callers (ipx stack, filter driver)
+// Flag set upon completion of initialization of all components
+extern volatile BOOLEAN IpxFwdInitialized;
+// Number of clients executing forwarder code (if -1, the forwarder
+// is being stopped)
+extern LONG ClientCount;
+// Event to be signalled by the last client inside forwarder
+extern KEVENT ClientsGoneEvent;
+
+
+/*++
+ E n t e r F o r w a r d e r
+
+Routine Description:
+ Checks if forwarder is initialized and grants access
+ to it (records the entrance as well
+
+Arguments:
+ None
+
+Return Value:
+ TRUE - access granted
+ FALSE - forwarder is not yet initialized or is being stopped
+
+--*/
+//BOOLEAN
+//EnterForwarder (
+// void
+// );
+#define EnterForwarder() ( \
+ (InterlockedIncrement(&ClientCount), IpxFwdInitialized) \
+ ? TRUE \
+ : (DoLeaveForwarder(), FALSE) \
+ )
+
+/*++
+ L e a v e F o r w a r d e r
+
+Routine Description:
+ Records the fact that external client stopped using forwarder
+
+Arguments:
+ None
+
+Return Value:
+ None
+
+--*/
+//BOOLEAN
+//EnterForwarder (
+// void
+// );
+#define LeaveForwarder() \
+ ((InterlockedDecrement(&ClientCount)<0) \
+ ? KeSetEvent (&ClientsGoneEvent,0,FALSE) \
+ : 0 \
+ )
+
+// Same as above but implemented as a routine to be used in
+// the EnterForwarder macro above (this reduces code size
+// and aids in debugging by improving readability of disassembly
+BOOLEAN
+DoLeaveForwarder (
+ VOID
+ );
+
+#endif
diff --git a/private/ntos/tdi/isn/fwd/filterif.c b/private/ntos/tdi/isn/fwd/filterif.c
new file mode 100644
index 000000000..f1fa584a3
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/filterif.c
@@ -0,0 +1,211 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\filterif.c
+
+Abstract:
+ IPX Forwarder driver interface with filter driver
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+
+ // Filter driver entry points
+IPX_FLT_BIND_INPUT FltBindInput = {NULL, NULL};
+ // Protects access to filter driver contexts
+RW_LOCK FltLock;
+
+
+/*++
+ D o F i l t e r
+
+Routine Description:
+
+ Calls filter driver entry point while holding reader access
+ to interface contexts
+
+Arguments:
+ ipxHdr - pointer to packet header
+ ipxHdrLength - size of the header buffer (must be at least 30)
+ ifInContext - context associated with interface on which packet
+ was received
+ ifOutContext - context associated with interface on which packet
+ will be sent
+Return Value:
+ FILTER_PERMIT - packet should be passed on by the forwarder
+ FILTER_DENY - packet should be dropped
+
+--*/
+FILTER_ACTION
+DoFilter (
+ IN PUCHAR ipxHdr,
+ IN ULONG ipxHdrLength,
+ IN PVOID ifInContext,
+ IN PVOID ifOutContex
+ ) {
+ RWCOOKIE cookie;
+ FILTER_ACTION result;
+ AcquireReaderAccess (&FltLock, cookie);
+ result = FltBindInput.FilterHandler (ipxHdr,
+ ipxHdrLength,
+ ifInContext,
+ ifOutContex);
+ ReleaseReaderAccess (&FltLock, cookie);
+ return result;
+}
+
+/*++
+ D o I n t e r f a c e D e l e t e d
+
+Routine Description:
+ Resets interface contexts and calls filter dirver entry point
+ making sure that all no one holds reader access to filter driver
+ interface contexts
+Arguments:
+ ifCB - interface to be deleted
+Return Value:
+ None
+
+--*/
+VOID
+DoInterfaceDeleted (
+ PINTERFACE_CB ifCB
+ ) {
+ PVOID inContext = ifCB->ICB_FilterInContext,
+ outContext = ifCB->ICB_FilterOutContext;
+ ifCB->ICB_FilterInContext = NO_FILTER_CONTEXT;
+ ifCB->ICB_FilterOutContext = NO_FILTER_CONTEXT;
+ WaitForAllReaders (&FltLock);
+ FltBindInput.InterfaceDeletedHandler(inContext,
+ outContext);
+}
+
+/*++
+ S e t I f I n C o n t e x t
+
+Routine Description:
+ Associates filter driver context with
+ the packets received on the interface
+Arguments:
+ InterfaceIndex - index of the interface
+ ifInContext - filter driver context
+Return Value:
+ STATUS_SUCCESS - context associated ok
+ STATUS_UNSUCCESSFUL - interface does not exist
+--*/
+NTSTATUS
+SetIfInContext (
+ IN ULONG InterfaceIndex,
+ IN PVOID ifInContext
+ ) {
+ PINTERFACE_CB ifCB;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ if (EnterForwarder ()) {
+ ifCB = GetInterfaceReference (InterfaceIndex);
+ if (ifCB!=NULL) {
+ ifCB->ICB_FilterInContext = ifInContext;
+ WaitForAllReaders (&FltLock);
+ }
+ else
+ status = STATUS_UNSUCCESSFUL;
+ LeaveForwarder ();
+ }
+ return status;
+}
+
+/*++
+ S e t I f O u t C o n t e x t
+
+Routine Description:
+ Associates filter driver context with
+ the packets sent on the interface
+Arguments:
+ InterfaceIndex - index of the interface
+ ifOutContext - filter driver context
+Return Value:
+ STATUS_SUCCESS - context associated ok
+ STATUS_UNSUCCESSFUL - interface does not exist
+--*/
+NTSTATUS
+SetIfOutContext (
+ IN ULONG InterfaceIndex,
+ IN PVOID ifOutContext
+ ) {
+ PINTERFACE_CB ifCB;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ if (EnterForwarder ()) {
+ ifCB = GetInterfaceReference (InterfaceIndex);
+ if (ifCB!=NULL) {
+ ifCB->ICB_FilterOutContext = ifOutContext;
+ WaitForAllReaders (&FltLock);
+ }
+ else
+ status = STATUS_UNSUCCESSFUL;
+ LeaveForwarder ();
+ }
+ return status;
+}
+
+/*++
+ B i n d F i l t e r D r i v e r
+
+Routine Description:
+ Exchanges entry points with filter driver
+Arguments:
+ bindInput - filter driver entry points
+ bindOutput - forwarder driver entry points
+Return Value:
+ None
+--*/
+VOID
+BindFilterDriver (
+ IN PIPX_FLT_BIND_INPUT bindInput,
+ OUT PIPX_FLT_BIND_OUTPUT bindOutput
+ ) {
+ memcpy (&FltBindInput, bindInput, sizeof (IPX_FLT_BIND_INPUT));
+ bindOutput->Size = sizeof (IPX_FLT_BIND_OUTPUT);
+ bindOutput->SetIfInContextHandler = SetIfInContext;
+ bindOutput->SetIfOutContextHandler = SetIfOutContext;
+ InitializeRWLock (&FltLock);
+}
+
+/*++
+ U n b i n d F i l t e r D r i v e r
+
+Routine Description:
+ Resets locally stored filter driver entry points
+ and resets filter driver contexts on all interfaces
+Arguments:
+ None
+Return Value:
+ None
+--*/
+VOID
+UnbindFilterDriver (
+ VOID
+ ) {
+ PINTERFACE_CB ifCB = NULL;
+ FltBindInput.FilterHandler = NULL;
+ FltBindInput.InterfaceDeletedHandler = NULL;
+
+ while ((ifCB=GetNextInterfaceReference (ifCB))!=NULL) {
+ ifCB->ICB_FilterInContext = NO_FILTER_CONTEXT;
+ ifCB->ICB_FilterOutContext = NO_FILTER_CONTEXT;
+ }
+ InternalInterface->ICB_FilterInContext = NO_FILTER_CONTEXT;
+ InternalInterface->ICB_FilterOutContext = NO_FILTER_CONTEXT;
+ WaitForAllReaders (&FltLock);
+}
+
diff --git a/private/ntos/tdi/isn/fwd/filterif.h b/private/ntos/tdi/isn/fwd/filterif.h
new file mode 100644
index 000000000..0e09df1de
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/filterif.h
@@ -0,0 +1,126 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\filterif.h
+
+Abstract:
+ IPX Forwarder interface with filter driver
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+
+#ifndef _IPXFWD_FILTERIF_
+#define _IPXFWD_FILTERIF_
+ // Filter driver entry points
+extern IPX_FLT_BIND_INPUT FltBindInput;
+
+ // Macros to improve performance when filter driver
+ // is not bound or has not associated its contexts
+ // with interfaces of interest
+#define FltFilter(hdr,hdrSize,inContext,outContext) ( \
+ ((FltBindInput.FilterHandler==NULL) \
+ || ((inContext==NO_FILTER_CONTEXT) \
+ &&(outContext==NO_FILTER_CONTEXT))) \
+ ? FILTER_PERMIT \
+ : DoFilter (hdr,hdrSize,inContext,outContext) \
+)
+
+#define FltInterfaceDeleted(ifCB) { \
+ if ((FltBindInput.InterfaceDeletedHandler!=NULL) \
+ && ((ifCB->ICB_FilterInContext!=NO_FILTER_CONTEXT) \
+ ||(ifCB->ICB_FilterOutContext!=NO_FILTER_CONTEXT))) \
+ DoInterfaceDeleted (ifCB); \
+}
+
+/*++
+ B i n d F i l t e r D r i v e r
+
+Routine Description:
+ Exchanges entry points with filter driver
+Arguments:
+ bindInput - filter driver entry points
+ bindOutput - forwarder driver entry points
+Return Value:
+ None
+--*/
+VOID
+BindFilterDriver (
+ IN PIPX_FLT_BIND_INPUT bindInput,
+ OUT PIPX_FLT_BIND_OUTPUT bindOutput
+ );
+
+/*++
+ U n b i n d F i l t e r D r i v e r
+
+Routine Description:
+ Resets locally stored filter driver entry points
+ and resets filter driver contexts on all interfaces
+Arguments:
+ None
+Return Value:
+ None
+--*/
+VOID
+UnbindFilterDriver (
+ VOID
+ );
+
+
+/*++
+ D o F i l t e r
+
+Routine Description:
+
+ Calls filter driver entry point while holding reader access
+ to interface contexts
+
+Arguments:
+ ipxHdr - pointer to packet header
+ ipxHdrLength - size of the header buffer (must be at least 30)
+ ifInContext - context associated with interface on which packet
+ was received
+ ifOutContext - context associated with interface on which packet
+ will be sent
+Return Value:
+ FILTER_PERMIT - packet should be passed on by the forwarder
+ FILTER_DENY - packet should be dropped
+
+--*/
+FILTER_ACTION
+DoFilter (
+ IN PUCHAR ipxHdr,
+ IN ULONG ipxHdrLength,
+ IN PVOID ifInContext,
+ IN PVOID ifOutContex
+ );
+
+/*++
+ D o I n t e r f a c e D e l e t e d
+
+Routine Description:
+ Resets interface contexts and calls filter dirver entry point
+ making sure that all no one holds reader access to filter driver
+ interface contexts
+Arguments:
+ ifCB - interface to be deleted
+Return Value:
+ None
+
+--*/
+VOID
+DoInterfaceDeleted (
+ PINTERFACE_CB ifCB
+ );
+
+#endif
+
diff --git a/private/ntos/tdi/isn/fwd/fwd.mak b/private/ntos/tdi/isn/fwd/fwd.mak
new file mode 100644
index 000000000..e47660250
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/fwd.mak
@@ -0,0 +1,2427 @@
+# Microsoft Developer Studio Generated NMAKE File, Format Version 4.10
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (PPC) Dynamic-Link Library" 0x0702
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+!IF "$(CFG)" == ""
+CFG=fwd - Win32 Release
+!MESSAGE No configuration specified. Defaulting to fwd - Win32 Release.
+!ENDIF
+
+!IF "$(CFG)" != "fwd - Win32 Release" && "$(CFG)" !=\
+ "fwd - Win32 (PPC) Release"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE on this makefile
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "fwd.mak" CFG="fwd - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "fwd - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "fwd - Win32 (PPC) Release" (based on\
+ "Win32 (PPC) Dynamic-Link Library")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+################################################################################
+# Begin Project
+# PROP Target_Last_Scanned "fwd - Win32 Release"
+
+!IF "$(CFG)" == "fwd - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL : "$(OUTDIR)\fwd.dll"
+
+CLEAN :
+ -@erase "$(INTDIR)\ddreqs.obj"
+ -@erase "$(INTDIR)\debug.obj"
+ -@erase "$(INTDIR)\driver.obj"
+ -@erase "$(INTDIR)\filterif.obj"
+ -@erase "$(INTDIR)\ipxbind.obj"
+ -@erase "$(INTDIR)\lineind.obj"
+ -@erase "$(INTDIR)\netbios.obj"
+ -@erase "$(INTDIR)\nwlnkfwd.res"
+ -@erase "$(INTDIR)\packets.obj"
+ -@erase "$(INTDIR)\rcvind.obj"
+ -@erase "$(INTDIR)\registry.obj"
+ -@erase "$(INTDIR)\send.obj"
+ -@erase "$(INTDIR)\tables.obj"
+ -@erase "$(OUTDIR)\fwd.dll"
+ -@erase "$(OUTDIR)\fwd.exp"
+ -@erase "$(OUTDIR)\fwd.lib"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\inc" /I "..\..\inc" /I "..\..\..\inc" /I "..\..\..\..\net\routing\inc" /I "..\..\..\..\inc" /D _X86_=1 /D i386=1 /D "STD_CALL" /D CONDITION_HANDLING=1 /D NT_UP=1 /D NT_INST=0 /D WIN32=100 /D _NT1X_=100 /D WINNT=1 /D WIN32_LEAN_AND_MEAN=1 /D DBG=1 /D DEVL=1 /D FPO=0 /D "_NTDRIVER_" /YX /c
+CPP_PROJ=/nologo /MT /W3 /GX /O2 /I "..\inc" /I "..\..\inc" /I "..\..\..\inc"\
+ /I "..\..\..\..\net\routing\inc" /I "..\..\..\..\inc" /D _X86_=1 /D i386=1 /D\
+ "STD_CALL" /D CONDITION_HANDLING=1 /D NT_UP=1 /D NT_INST=0 /D WIN32=100 /D\
+ _NT1X_=100 /D WINNT=1 /D WIN32_LEAN_AND_MEAN=1 /D DBG=1 /D DEVL=1 /D FPO=0 /D\
+ "_NTDRIVER_" /Fp"$(INTDIR)/fwd.pch" /YX /Fo"$(INTDIR)/" /c
+CPP_OBJS=.\Release/
+CPP_SBRS=.\.
+
+.c{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.c{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+MTL=mktyplib.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /win32
+MTL_PROJ=/nologo /D "NDEBUG" /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)/nwlnkfwd.res" /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/fwd.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:I386
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo\
+ /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)/fwd.pdb" /machine:I386\
+ /out:"$(OUTDIR)/fwd.dll" /implib:"$(OUTDIR)/fwd.lib"
+LINK32_OBJS= \
+ "$(INTDIR)\ddreqs.obj" \
+ "$(INTDIR)\debug.obj" \
+ "$(INTDIR)\driver.obj" \
+ "$(INTDIR)\filterif.obj" \
+ "$(INTDIR)\ipxbind.obj" \
+ "$(INTDIR)\lineind.obj" \
+ "$(INTDIR)\netbios.obj" \
+ "$(INTDIR)\nwlnkfwd.res" \
+ "$(INTDIR)\packets.obj" \
+ "$(INTDIR)\rcvind.obj" \
+ "$(INTDIR)\registry.obj" \
+ "$(INTDIR)\send.obj" \
+ "$(INTDIR)\tables.obj"
+
+"$(OUTDIR)\fwd.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "fwd - Win32 (PPC) Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "fwd___Wi"
+# PROP BASE Intermediate_Dir "fwd___Wi"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "fwd___Wi"
+# PROP Intermediate_Dir "fwd___Wi"
+# PROP Target_Dir ""
+OUTDIR=.\fwd___Wi
+INTDIR=.\fwd___Wi
+
+ALL : "$(OUTDIR)\fwd.dll"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CLEAN :
+ -@erase ".\fwd___Wi\fwd.dll"
+ -@erase ".\fwd___Wi\Tables.obj"
+ -@erase ".\fwd___Wi\rcvind.obj"
+ -@erase ".\fwd___Wi\packets.obj"
+ -@erase ".\fwd___Wi\ipxbind.obj"
+ -@erase ".\fwd___Wi\driver.obj"
+ -@erase ".\fwd___Wi\send.obj"
+ -@erase ".\fwd___Wi\registry.obj"
+ -@erase ".\fwd___Wi\netbios.obj"
+ -@erase ".\fwd___Wi\lineind.obj"
+ -@erase ".\fwd___Wi\nwlnkfwd.res"
+ -@erase ".\fwd___Wi\fwd.lib"
+ -@erase ".\fwd___Wi\fwd.exp"
+
+MTL=mktyplib.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /PPC32
+# ADD MTL /nologo /D "NDEBUG" /PPC32
+MTL_PROJ=/nologo /D "NDEBUG" /PPC32
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /W3 /Z7 /Oi /Gy /I "..\inc" /I "..\..\..\inc" /I "..\..\..\..\inc" /I "e:\NT\public\oak\inc" /I "e:\NT\public\sdk\inc" /I "e:\NT\public\sdk\inc\crt" /FI"e:\NT\public\sdk\inc\warning.h" /D PPC=1 /D _PPC_=1 /D "NO_EXT_KEYS" /D CONDITION_HANDLING=1 /D NT_UP=1 /D NT_INST=0 /D WIN32=100 /D _NT1X_=100 /D WINNT=1 /D WIN32_LEAN_AND_MEAN=1 /D _M_PPC=1 /D DBG=1 /D DEVL=1 /D "_NTDRIVER_" /D __stdcall= /D __cdecl= /D _cdecl= /D cdecl= /D FPO=1 /D "LANGUAGE_C" -Zel -ZB64 /c
+CPP_PROJ=/nologo /ML /W3 /Z7 /Oi /Gy /I "..\inc" /I "..\..\..\inc" /I\
+ "..\..\..\..\inc" /I "e:\NT\public\oak\inc" /I "e:\NT\public\sdk\inc" /I\
+ "e:\NT\public\sdk\inc\crt" /FI"e:\NT\public\sdk\inc\warning.h" /D PPC=1 /D\
+ _PPC_=1 /D "NO_EXT_KEYS" /D CONDITION_HANDLING=1 /D NT_UP=1 /D NT_INST=0 /D\
+ WIN32=100 /D _NT1X_=100 /D WINNT=1 /D WIN32_LEAN_AND_MEAN=1 /D _M_PPC=1 /D\
+ DBG=1 /D DEVL=1 /D "_NTDRIVER_" /D __stdcall= /D __cdecl= /D _cdecl= /D cdecl=\
+ /D FPO=1 /D "LANGUAGE_C" /Fo"$(INTDIR)/" -Zel -ZB64 /c
+CPP_OBJS=.\fwd___Wi/
+CPP_SBRS=
+
+.c{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.c{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)/nwlnkfwd.res" /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/fwd.bsc"
+BSC32_SBRS=
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:PPC
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:PPC
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo\
+ /subsystem:windows /dll /pdb:"$(OUTDIR)/fwd.pdb" /machine:PPC\
+ /out:"$(OUTDIR)/fwd.dll" /implib:"$(OUTDIR)/fwd.lib"
+LINK32_OBJS= \
+ "$(INTDIR)/Tables.obj" \
+ "$(INTDIR)/rcvind.obj" \
+ "$(INTDIR)/packets.obj" \
+ "$(INTDIR)/ipxbind.obj" \
+ "$(INTDIR)/driver.obj" \
+ "$(INTDIR)/send.obj" \
+ "$(INTDIR)/registry.obj" \
+ "$(INTDIR)/netbios.obj" \
+ "$(INTDIR)/lineind.obj" \
+ "$(INTDIR)/nwlnkfwd.res"
+
+"$(OUTDIR)\fwd.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF
+
+################################################################################
+# Begin Target
+
+# Name "fwd - Win32 Release"
+# Name "fwd - Win32 (PPC) Release"
+
+!IF "$(CFG)" == "fwd - Win32 Release"
+
+!ELSEIF "$(CFG)" == "fwd - Win32 (PPC) Release"
+
+!ENDIF
+
+################################################################################
+# Begin Source File
+
+SOURCE=.\sources.inc
+
+!IF "$(CFG)" == "fwd - Win32 Release"
+
+!ELSEIF "$(CFG)" == "fwd - Win32 (PPC) Release"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\send.c
+
+!IF "$(CFG)" == "fwd - Win32 Release"
+
+DEP_CPP_SEND_=\
+ "..\..\..\..\inc\ipxfwd.h"\
+ "..\..\..\..\inc\nettypes.h"\
+ "..\..\..\..\inc\packoff.h"\
+ "..\..\..\..\inc\packon.h"\
+ "..\..\..\..\inc\tdi.h"\
+ "..\..\..\..\inc\tdikrnl.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\bind.h"\
+ "..\inc\ipxfltif.h"\
+ "..\inc\isnkrnl.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\ddreqs.h"\
+ ".\debug.h"\
+ ".\driver.h"\
+ ".\filterif.h"\
+ ".\fwddefs.h"\
+ ".\ipxbind.h"\
+ ".\lineind.h"\
+ ".\netbios.h"\
+ ".\packets.h"\
+ ".\precomp.h"\
+ ".\rcvind.h"\
+ ".\registry.h"\
+ ".\rwlock.h"\
+ ".\send.h"\
+ ".\tables.h"\
+ "c:\nt\public\sdk\inc\mipsinst.h"\
+ "c:\nt\public\sdk\inc\ntalpha.h"\
+ "c:\nt\public\sdk\inc\nti386.h"\
+ "c:\nt\public\sdk\inc\ntmips.h"\
+ "c:\nt\public\sdk\inc\ntppc.h"\
+ "c:\nt\public\sdk\inc\ppcinst.h"\
+ {$(INCLUDE)}"\cfg.h"\
+ {$(INCLUDE)}"\devioctl.h"\
+ {$(INCLUDE)}"\netevent.h"\
+ {$(INCLUDE)}"\nt.h"\
+ {$(INCLUDE)}"\ntconfig.h"\
+ {$(INCLUDE)}"\ntddndis.h"\
+ {$(INCLUDE)}"\ntddtdi.h"\
+ {$(INCLUDE)}"\ntdef.h"\
+ {$(INCLUDE)}"\ntelfapi.h"\
+ {$(INCLUDE)}"\ntexapi.h"\
+ {$(INCLUDE)}"\ntimage.h"\
+ {$(INCLUDE)}"\ntioapi.h"\
+ {$(INCLUDE)}"\ntiolog.h"\
+ {$(INCLUDE)}"\ntkeapi.h"\
+ {$(INCLUDE)}"\ntkxapi.h"\
+ {$(INCLUDE)}"\ntldr.h"\
+ {$(INCLUDE)}"\ntlpcapi.h"\
+ {$(INCLUDE)}"\ntmmapi.h"\
+ {$(INCLUDE)}"\ntnls.h"\
+ {$(INCLUDE)}"\ntobapi.h"\
+ {$(INCLUDE)}"\ntpnpapi.h"\
+ {$(INCLUDE)}"\ntpoapi.h"\
+ {$(INCLUDE)}"\ntpsapi.h"\
+ {$(INCLUDE)}"\ntregapi.h"\
+ {$(INCLUDE)}"\ntrtl.h"\
+ {$(INCLUDE)}"\ntseapi.h"\
+ {$(INCLUDE)}"\ntstatus.h"\
+ {$(INCLUDE)}"\ntxcapi.h"\
+ {$(INCLUDE)}"\zwapi.h"\
+
+
+"$(INTDIR)\send.obj" : $(SOURCE) $(DEP_CPP_SEND_) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "fwd - Win32 (PPC) Release"
+
+DEP_CPP_SEND_=\
+ "..\..\..\..\inc\nettypes.h"\
+ "..\..\..\..\inc\packoff.h"\
+ "..\..\..\..\inc\packon.h"\
+ "..\..\..\..\inc\tdi.h"\
+ "..\..\..\..\inc\tdikrnl.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\bind.h"\
+ "..\inc\isnkrnl.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntmp.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\..\inc\ipxfwd.h"\
+ ".\debug.h"\
+ ".\driver.h"\
+ ".\ipxbind.h"\
+ ".\lineind.h"\
+ ".\netbios.h"\
+ ".\packets.h"\
+ ".\rcvind.h"\
+ ".\registry.h"\
+ ".\send.h"\
+ ".\tables.h"\
+ "e:\NT\public\oak\inc\zwapi.h"\
+ "e:\NT\public\sdk\inc\cfg.h"\
+ "e:\NT\public\sdk\inc\devioctl.h"\
+ "E:\NT\public\sdk\inc\mipsinst.h"\
+ "e:\NT\public\sdk\inc\netevent.h"\
+ "e:\NT\public\sdk\inc\nt.h"\
+ "E:\nt\public\sdk\inc\ntalpha.h"\
+ "e:\NT\public\sdk\inc\ntconfig.h"\
+ "e:\NT\public\sdk\inc\ntddndis.h"\
+ "e:\NT\public\sdk\inc\ntddtdi.h"\
+ "e:\NT\public\sdk\inc\ntdef.h"\
+ "e:\NT\public\sdk\inc\ntelfapi.h"\
+ "e:\NT\public\sdk\inc\ntexapi.h"\
+ "E:\nt\public\sdk\inc\nti386.h"\
+ "e:\NT\public\sdk\inc\ntimage.h"\
+ "e:\NT\public\sdk\inc\ntioapi.h"\
+ "e:\NT\public\sdk\inc\ntiolog.h"\
+ "e:\NT\public\sdk\inc\ntkeapi.h"\
+ "e:\NT\public\sdk\inc\ntkxapi.h"\
+ "e:\NT\public\sdk\inc\ntldr.h"\
+ "e:\NT\public\sdk\inc\ntlpcapi.h"\
+ "E:\nt\public\sdk\inc\ntmips.h"\
+ "e:\NT\public\sdk\inc\ntmmapi.h"\
+ "e:\NT\public\sdk\inc\ntnls.h"\
+ "e:\NT\public\sdk\inc\ntobapi.h"\
+ "e:\NT\public\sdk\inc\ntpnpapi.h"\
+ "e:\NT\public\sdk\inc\ntpoapi.h"\
+ "E:\nt\public\sdk\inc\ntppc.h"\
+ "e:\NT\public\sdk\inc\ntpsapi.h"\
+ "e:\NT\public\sdk\inc\ntregapi.h"\
+ "e:\NT\public\sdk\inc\ntrtl.h"\
+ "e:\NT\public\sdk\inc\ntseapi.h"\
+ "e:\NT\public\sdk\inc\ntstatus.h"\
+ "e:\NT\public\sdk\inc\ntxcapi.h"\
+ "E:\NT\public\sdk\inc\ppcinst.h"\
+
+
+"$(INTDIR)\send.obj" : $(SOURCE) $(DEP_CPP_SEND_) "$(INTDIR)"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\rcvind.c
+
+!IF "$(CFG)" == "fwd - Win32 Release"
+
+DEP_CPP_RCVIN=\
+ "..\..\..\..\inc\ipxfwd.h"\
+ "..\..\..\..\inc\nettypes.h"\
+ "..\..\..\..\inc\packoff.h"\
+ "..\..\..\..\inc\packon.h"\
+ "..\..\..\..\inc\tdi.h"\
+ "..\..\..\..\inc\tdikrnl.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\bind.h"\
+ "..\inc\ipxfltif.h"\
+ "..\inc\isnkrnl.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\ddreqs.h"\
+ ".\debug.h"\
+ ".\driver.h"\
+ ".\filterif.h"\
+ ".\fwddefs.h"\
+ ".\ipxbind.h"\
+ ".\lineind.h"\
+ ".\netbios.h"\
+ ".\packets.h"\
+ ".\precomp.h"\
+ ".\rcvind.h"\
+ ".\registry.h"\
+ ".\rwlock.h"\
+ ".\send.h"\
+ ".\tables.h"\
+ "c:\nt\public\sdk\inc\mipsinst.h"\
+ "c:\nt\public\sdk\inc\ntalpha.h"\
+ "c:\nt\public\sdk\inc\nti386.h"\
+ "c:\nt\public\sdk\inc\ntmips.h"\
+ "c:\nt\public\sdk\inc\ntppc.h"\
+ "c:\nt\public\sdk\inc\ppcinst.h"\
+ {$(INCLUDE)}"\cfg.h"\
+ {$(INCLUDE)}"\devioctl.h"\
+ {$(INCLUDE)}"\netevent.h"\
+ {$(INCLUDE)}"\nt.h"\
+ {$(INCLUDE)}"\ntconfig.h"\
+ {$(INCLUDE)}"\ntddndis.h"\
+ {$(INCLUDE)}"\ntddtdi.h"\
+ {$(INCLUDE)}"\ntdef.h"\
+ {$(INCLUDE)}"\ntelfapi.h"\
+ {$(INCLUDE)}"\ntexapi.h"\
+ {$(INCLUDE)}"\ntimage.h"\
+ {$(INCLUDE)}"\ntioapi.h"\
+ {$(INCLUDE)}"\ntiolog.h"\
+ {$(INCLUDE)}"\ntkeapi.h"\
+ {$(INCLUDE)}"\ntkxapi.h"\
+ {$(INCLUDE)}"\ntldr.h"\
+ {$(INCLUDE)}"\ntlpcapi.h"\
+ {$(INCLUDE)}"\ntmmapi.h"\
+ {$(INCLUDE)}"\ntnls.h"\
+ {$(INCLUDE)}"\ntobapi.h"\
+ {$(INCLUDE)}"\ntpnpapi.h"\
+ {$(INCLUDE)}"\ntpoapi.h"\
+ {$(INCLUDE)}"\ntpsapi.h"\
+ {$(INCLUDE)}"\ntregapi.h"\
+ {$(INCLUDE)}"\ntrtl.h"\
+ {$(INCLUDE)}"\ntseapi.h"\
+ {$(INCLUDE)}"\ntstatus.h"\
+ {$(INCLUDE)}"\ntxcapi.h"\
+ {$(INCLUDE)}"\zwapi.h"\
+
+
+"$(INTDIR)\rcvind.obj" : $(SOURCE) $(DEP_CPP_RCVIN) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "fwd - Win32 (PPC) Release"
+
+DEP_CPP_RCVIN=\
+ "..\..\..\..\inc\nettypes.h"\
+ "..\..\..\..\inc\packoff.h"\
+ "..\..\..\..\inc\packon.h"\
+ "..\..\..\..\inc\tdi.h"\
+ "..\..\..\..\inc\tdikrnl.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\bind.h"\
+ "..\inc\isnkrnl.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntmp.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\..\inc\ipxfwd.h"\
+ ".\debug.h"\
+ ".\driver.h"\
+ ".\ipxbind.h"\
+ ".\lineind.h"\
+ ".\netbios.h"\
+ ".\packets.h"\
+ ".\rcvind.h"\
+ ".\registry.h"\
+ ".\send.h"\
+ ".\tables.h"\
+ "e:\NT\public\oak\inc\zwapi.h"\
+ "e:\NT\public\sdk\inc\cfg.h"\
+ "e:\NT\public\sdk\inc\devioctl.h"\
+ "E:\NT\public\sdk\inc\mipsinst.h"\
+ "e:\NT\public\sdk\inc\netevent.h"\
+ "e:\NT\public\sdk\inc\nt.h"\
+ "E:\nt\public\sdk\inc\ntalpha.h"\
+ "e:\NT\public\sdk\inc\ntconfig.h"\
+ "e:\NT\public\sdk\inc\ntddndis.h"\
+ "e:\NT\public\sdk\inc\ntddtdi.h"\
+ "e:\NT\public\sdk\inc\ntdef.h"\
+ "e:\NT\public\sdk\inc\ntelfapi.h"\
+ "e:\NT\public\sdk\inc\ntexapi.h"\
+ "E:\nt\public\sdk\inc\nti386.h"\
+ "e:\NT\public\sdk\inc\ntimage.h"\
+ "e:\NT\public\sdk\inc\ntioapi.h"\
+ "e:\NT\public\sdk\inc\ntiolog.h"\
+ "e:\NT\public\sdk\inc\ntkeapi.h"\
+ "e:\NT\public\sdk\inc\ntkxapi.h"\
+ "e:\NT\public\sdk\inc\ntldr.h"\
+ "e:\NT\public\sdk\inc\ntlpcapi.h"\
+ "E:\nt\public\sdk\inc\ntmips.h"\
+ "e:\NT\public\sdk\inc\ntmmapi.h"\
+ "e:\NT\public\sdk\inc\ntnls.h"\
+ "e:\NT\public\sdk\inc\ntobapi.h"\
+ "e:\NT\public\sdk\inc\ntpnpapi.h"\
+ "e:\NT\public\sdk\inc\ntpoapi.h"\
+ "E:\nt\public\sdk\inc\ntppc.h"\
+ "e:\NT\public\sdk\inc\ntpsapi.h"\
+ "e:\NT\public\sdk\inc\ntregapi.h"\
+ "e:\NT\public\sdk\inc\ntrtl.h"\
+ "e:\NT\public\sdk\inc\ntseapi.h"\
+ "e:\NT\public\sdk\inc\ntstatus.h"\
+ "e:\NT\public\sdk\inc\ntxcapi.h"\
+ "E:\NT\public\sdk\inc\ppcinst.h"\
+
+
+"$(INTDIR)\rcvind.obj" : $(SOURCE) $(DEP_CPP_RCVIN) "$(INTDIR)"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\netbios.c
+
+!IF "$(CFG)" == "fwd - Win32 Release"
+
+DEP_CPP_NETBI=\
+ "..\..\..\..\inc\ipxfwd.h"\
+ "..\..\..\..\inc\nettypes.h"\
+ "..\..\..\..\inc\packoff.h"\
+ "..\..\..\..\inc\packon.h"\
+ "..\..\..\..\inc\tdi.h"\
+ "..\..\..\..\inc\tdikrnl.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\bind.h"\
+ "..\inc\ipxfltif.h"\
+ "..\inc\isnkrnl.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\ddreqs.h"\
+ ".\debug.h"\
+ ".\driver.h"\
+ ".\filterif.h"\
+ ".\fwddefs.h"\
+ ".\ipxbind.h"\
+ ".\lineind.h"\
+ ".\netbios.h"\
+ ".\packets.h"\
+ ".\precomp.h"\
+ ".\rcvind.h"\
+ ".\registry.h"\
+ ".\rwlock.h"\
+ ".\send.h"\
+ ".\tables.h"\
+ "c:\nt\public\sdk\inc\mipsinst.h"\
+ "c:\nt\public\sdk\inc\ntalpha.h"\
+ "c:\nt\public\sdk\inc\nti386.h"\
+ "c:\nt\public\sdk\inc\ntmips.h"\
+ "c:\nt\public\sdk\inc\ntppc.h"\
+ "c:\nt\public\sdk\inc\ppcinst.h"\
+ {$(INCLUDE)}"\cfg.h"\
+ {$(INCLUDE)}"\devioctl.h"\
+ {$(INCLUDE)}"\netevent.h"\
+ {$(INCLUDE)}"\nt.h"\
+ {$(INCLUDE)}"\ntconfig.h"\
+ {$(INCLUDE)}"\ntddndis.h"\
+ {$(INCLUDE)}"\ntddtdi.h"\
+ {$(INCLUDE)}"\ntdef.h"\
+ {$(INCLUDE)}"\ntelfapi.h"\
+ {$(INCLUDE)}"\ntexapi.h"\
+ {$(INCLUDE)}"\ntimage.h"\
+ {$(INCLUDE)}"\ntioapi.h"\
+ {$(INCLUDE)}"\ntiolog.h"\
+ {$(INCLUDE)}"\ntkeapi.h"\
+ {$(INCLUDE)}"\ntkxapi.h"\
+ {$(INCLUDE)}"\ntldr.h"\
+ {$(INCLUDE)}"\ntlpcapi.h"\
+ {$(INCLUDE)}"\ntmmapi.h"\
+ {$(INCLUDE)}"\ntnls.h"\
+ {$(INCLUDE)}"\ntobapi.h"\
+ {$(INCLUDE)}"\ntpnpapi.h"\
+ {$(INCLUDE)}"\ntpoapi.h"\
+ {$(INCLUDE)}"\ntpsapi.h"\
+ {$(INCLUDE)}"\ntregapi.h"\
+ {$(INCLUDE)}"\ntrtl.h"\
+ {$(INCLUDE)}"\ntseapi.h"\
+ {$(INCLUDE)}"\ntstatus.h"\
+ {$(INCLUDE)}"\ntxcapi.h"\
+ {$(INCLUDE)}"\zwapi.h"\
+
+
+"$(INTDIR)\netbios.obj" : $(SOURCE) $(DEP_CPP_NETBI) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "fwd - Win32 (PPC) Release"
+
+DEP_CPP_NETBI=\
+ "..\..\..\..\inc\nettypes.h"\
+ "..\..\..\..\inc\packoff.h"\
+ "..\..\..\..\inc\packon.h"\
+ "..\..\..\..\inc\tdi.h"\
+ "..\..\..\..\inc\tdikrnl.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\bind.h"\
+ "..\inc\isnkrnl.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntmp.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\..\inc\ipxfwd.h"\
+ ".\debug.h"\
+ ".\driver.h"\
+ ".\ipxbind.h"\
+ ".\lineind.h"\
+ ".\netbios.h"\
+ ".\packets.h"\
+ ".\rcvind.h"\
+ ".\registry.h"\
+ ".\send.h"\
+ ".\tables.h"\
+ "e:\NT\public\oak\inc\zwapi.h"\
+ "e:\NT\public\sdk\inc\cfg.h"\
+ "e:\NT\public\sdk\inc\devioctl.h"\
+ "E:\NT\public\sdk\inc\mipsinst.h"\
+ "e:\NT\public\sdk\inc\netevent.h"\
+ "e:\NT\public\sdk\inc\nt.h"\
+ "E:\nt\public\sdk\inc\ntalpha.h"\
+ "e:\NT\public\sdk\inc\ntconfig.h"\
+ "e:\NT\public\sdk\inc\ntddndis.h"\
+ "e:\NT\public\sdk\inc\ntddtdi.h"\
+ "e:\NT\public\sdk\inc\ntdef.h"\
+ "e:\NT\public\sdk\inc\ntelfapi.h"\
+ "e:\NT\public\sdk\inc\ntexapi.h"\
+ "E:\nt\public\sdk\inc\nti386.h"\
+ "e:\NT\public\sdk\inc\ntimage.h"\
+ "e:\NT\public\sdk\inc\ntioapi.h"\
+ "e:\NT\public\sdk\inc\ntiolog.h"\
+ "e:\NT\public\sdk\inc\ntkeapi.h"\
+ "e:\NT\public\sdk\inc\ntkxapi.h"\
+ "e:\NT\public\sdk\inc\ntldr.h"\
+ "e:\NT\public\sdk\inc\ntlpcapi.h"\
+ "E:\nt\public\sdk\inc\ntmips.h"\
+ "e:\NT\public\sdk\inc\ntmmapi.h"\
+ "e:\NT\public\sdk\inc\ntnls.h"\
+ "e:\NT\public\sdk\inc\ntobapi.h"\
+ "e:\NT\public\sdk\inc\ntpnpapi.h"\
+ "e:\NT\public\sdk\inc\ntpoapi.h"\
+ "E:\nt\public\sdk\inc\ntppc.h"\
+ "e:\NT\public\sdk\inc\ntpsapi.h"\
+ "e:\NT\public\sdk\inc\ntregapi.h"\
+ "e:\NT\public\sdk\inc\ntrtl.h"\
+ "e:\NT\public\sdk\inc\ntseapi.h"\
+ "e:\NT\public\sdk\inc\ntstatus.h"\
+ "e:\NT\public\sdk\inc\ntxcapi.h"\
+ "E:\NT\public\sdk\inc\ppcinst.h"\
+
+
+"$(INTDIR)\netbios.obj" : $(SOURCE) $(DEP_CPP_NETBI) "$(INTDIR)"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\lineind.c
+
+!IF "$(CFG)" == "fwd - Win32 Release"
+
+DEP_CPP_LINEI=\
+ "..\..\..\..\inc\ipxfwd.h"\
+ "..\..\..\..\inc\nettypes.h"\
+ "..\..\..\..\inc\packoff.h"\
+ "..\..\..\..\inc\packon.h"\
+ "..\..\..\..\inc\tdi.h"\
+ "..\..\..\..\inc\tdikrnl.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\bind.h"\
+ "..\inc\ipxfltif.h"\
+ "..\inc\isnkrnl.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\ddreqs.h"\
+ ".\debug.h"\
+ ".\driver.h"\
+ ".\filterif.h"\
+ ".\fwddefs.h"\
+ ".\ipxbind.h"\
+ ".\lineind.h"\
+ ".\netbios.h"\
+ ".\packets.h"\
+ ".\precomp.h"\
+ ".\rcvind.h"\
+ ".\registry.h"\
+ ".\rwlock.h"\
+ ".\send.h"\
+ ".\tables.h"\
+ "c:\nt\public\sdk\inc\mipsinst.h"\
+ "c:\nt\public\sdk\inc\ntalpha.h"\
+ "c:\nt\public\sdk\inc\nti386.h"\
+ "c:\nt\public\sdk\inc\ntmips.h"\
+ "c:\nt\public\sdk\inc\ntppc.h"\
+ "c:\nt\public\sdk\inc\ppcinst.h"\
+ {$(INCLUDE)}"\cfg.h"\
+ {$(INCLUDE)}"\devioctl.h"\
+ {$(INCLUDE)}"\netevent.h"\
+ {$(INCLUDE)}"\nt.h"\
+ {$(INCLUDE)}"\ntconfig.h"\
+ {$(INCLUDE)}"\ntddndis.h"\
+ {$(INCLUDE)}"\ntddtdi.h"\
+ {$(INCLUDE)}"\ntdef.h"\
+ {$(INCLUDE)}"\ntelfapi.h"\
+ {$(INCLUDE)}"\ntexapi.h"\
+ {$(INCLUDE)}"\ntimage.h"\
+ {$(INCLUDE)}"\ntioapi.h"\
+ {$(INCLUDE)}"\ntiolog.h"\
+ {$(INCLUDE)}"\ntkeapi.h"\
+ {$(INCLUDE)}"\ntkxapi.h"\
+ {$(INCLUDE)}"\ntldr.h"\
+ {$(INCLUDE)}"\ntlpcapi.h"\
+ {$(INCLUDE)}"\ntmmapi.h"\
+ {$(INCLUDE)}"\ntnls.h"\
+ {$(INCLUDE)}"\ntobapi.h"\
+ {$(INCLUDE)}"\ntpnpapi.h"\
+ {$(INCLUDE)}"\ntpoapi.h"\
+ {$(INCLUDE)}"\ntpsapi.h"\
+ {$(INCLUDE)}"\ntregapi.h"\
+ {$(INCLUDE)}"\ntrtl.h"\
+ {$(INCLUDE)}"\ntseapi.h"\
+ {$(INCLUDE)}"\ntstatus.h"\
+ {$(INCLUDE)}"\ntxcapi.h"\
+ {$(INCLUDE)}"\zwapi.h"\
+
+
+"$(INTDIR)\lineind.obj" : $(SOURCE) $(DEP_CPP_LINEI) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "fwd - Win32 (PPC) Release"
+
+DEP_CPP_LINEI=\
+ "..\..\..\..\inc\nettypes.h"\
+ "..\..\..\..\inc\packoff.h"\
+ "..\..\..\..\inc\packon.h"\
+ "..\..\..\..\inc\tdi.h"\
+ "..\..\..\..\inc\tdikrnl.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\bind.h"\
+ "..\inc\isnkrnl.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntmp.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\..\inc\ipxfwd.h"\
+ ".\debug.h"\
+ ".\driver.h"\
+ ".\ipxbind.h"\
+ ".\lineind.h"\
+ ".\netbios.h"\
+ ".\packets.h"\
+ ".\rcvind.h"\
+ ".\registry.h"\
+ ".\send.h"\
+ ".\tables.h"\
+ "e:\NT\public\oak\inc\zwapi.h"\
+ "e:\NT\public\sdk\inc\cfg.h"\
+ "e:\NT\public\sdk\inc\devioctl.h"\
+ "E:\NT\public\sdk\inc\mipsinst.h"\
+ "e:\NT\public\sdk\inc\netevent.h"\
+ "e:\NT\public\sdk\inc\nt.h"\
+ "E:\nt\public\sdk\inc\ntalpha.h"\
+ "e:\NT\public\sdk\inc\ntconfig.h"\
+ "e:\NT\public\sdk\inc\ntddndis.h"\
+ "e:\NT\public\sdk\inc\ntddtdi.h"\
+ "e:\NT\public\sdk\inc\ntdef.h"\
+ "e:\NT\public\sdk\inc\ntelfapi.h"\
+ "e:\NT\public\sdk\inc\ntexapi.h"\
+ "E:\nt\public\sdk\inc\nti386.h"\
+ "e:\NT\public\sdk\inc\ntimage.h"\
+ "e:\NT\public\sdk\inc\ntioapi.h"\
+ "e:\NT\public\sdk\inc\ntiolog.h"\
+ "e:\NT\public\sdk\inc\ntkeapi.h"\
+ "e:\NT\public\sdk\inc\ntkxapi.h"\
+ "e:\NT\public\sdk\inc\ntldr.h"\
+ "e:\NT\public\sdk\inc\ntlpcapi.h"\
+ "E:\nt\public\sdk\inc\ntmips.h"\
+ "e:\NT\public\sdk\inc\ntmmapi.h"\
+ "e:\NT\public\sdk\inc\ntnls.h"\
+ "e:\NT\public\sdk\inc\ntobapi.h"\
+ "e:\NT\public\sdk\inc\ntpnpapi.h"\
+ "e:\NT\public\sdk\inc\ntpoapi.h"\
+ "E:\nt\public\sdk\inc\ntppc.h"\
+ "e:\NT\public\sdk\inc\ntpsapi.h"\
+ "e:\NT\public\sdk\inc\ntregapi.h"\
+ "e:\NT\public\sdk\inc\ntrtl.h"\
+ "e:\NT\public\sdk\inc\ntseapi.h"\
+ "e:\NT\public\sdk\inc\ntstatus.h"\
+ "e:\NT\public\sdk\inc\ntxcapi.h"\
+ "E:\NT\public\sdk\inc\ppcinst.h"\
+
+
+"$(INTDIR)\lineind.obj" : $(SOURCE) $(DEP_CPP_LINEI) "$(INTDIR)"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ipxbind.c
+
+!IF "$(CFG)" == "fwd - Win32 Release"
+
+DEP_CPP_IPXBI=\
+ "..\..\..\..\inc\ipxfwd.h"\
+ "..\..\..\..\inc\nettypes.h"\
+ "..\..\..\..\inc\packoff.h"\
+ "..\..\..\..\inc\packon.h"\
+ "..\..\..\..\inc\tdi.h"\
+ "..\..\..\..\inc\tdikrnl.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\bind.h"\
+ "..\inc\ipxfltif.h"\
+ "..\inc\isnkrnl.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\ddreqs.h"\
+ ".\debug.h"\
+ ".\driver.h"\
+ ".\filterif.h"\
+ ".\fwddefs.h"\
+ ".\ipxbind.h"\
+ ".\lineind.h"\
+ ".\netbios.h"\
+ ".\packets.h"\
+ ".\precomp.h"\
+ ".\rcvind.h"\
+ ".\registry.h"\
+ ".\rwlock.h"\
+ ".\send.h"\
+ ".\tables.h"\
+ "c:\nt\public\sdk\inc\mipsinst.h"\
+ "c:\nt\public\sdk\inc\ntalpha.h"\
+ "c:\nt\public\sdk\inc\nti386.h"\
+ "c:\nt\public\sdk\inc\ntmips.h"\
+ "c:\nt\public\sdk\inc\ntppc.h"\
+ "c:\nt\public\sdk\inc\ppcinst.h"\
+ {$(INCLUDE)}"\cfg.h"\
+ {$(INCLUDE)}"\devioctl.h"\
+ {$(INCLUDE)}"\netevent.h"\
+ {$(INCLUDE)}"\nt.h"\
+ {$(INCLUDE)}"\ntconfig.h"\
+ {$(INCLUDE)}"\ntddndis.h"\
+ {$(INCLUDE)}"\ntddtdi.h"\
+ {$(INCLUDE)}"\ntdef.h"\
+ {$(INCLUDE)}"\ntelfapi.h"\
+ {$(INCLUDE)}"\ntexapi.h"\
+ {$(INCLUDE)}"\ntimage.h"\
+ {$(INCLUDE)}"\ntioapi.h"\
+ {$(INCLUDE)}"\ntiolog.h"\
+ {$(INCLUDE)}"\ntkeapi.h"\
+ {$(INCLUDE)}"\ntkxapi.h"\
+ {$(INCLUDE)}"\ntldr.h"\
+ {$(INCLUDE)}"\ntlpcapi.h"\
+ {$(INCLUDE)}"\ntmmapi.h"\
+ {$(INCLUDE)}"\ntnls.h"\
+ {$(INCLUDE)}"\ntobapi.h"\
+ {$(INCLUDE)}"\ntpnpapi.h"\
+ {$(INCLUDE)}"\ntpoapi.h"\
+ {$(INCLUDE)}"\ntpsapi.h"\
+ {$(INCLUDE)}"\ntregapi.h"\
+ {$(INCLUDE)}"\ntrtl.h"\
+ {$(INCLUDE)}"\ntseapi.h"\
+ {$(INCLUDE)}"\ntstatus.h"\
+ {$(INCLUDE)}"\ntxcapi.h"\
+ {$(INCLUDE)}"\zwapi.h"\
+
+
+"$(INTDIR)\ipxbind.obj" : $(SOURCE) $(DEP_CPP_IPXBI) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "fwd - Win32 (PPC) Release"
+
+DEP_CPP_IPXBI=\
+ "..\..\..\..\inc\nettypes.h"\
+ "..\..\..\..\inc\packoff.h"\
+ "..\..\..\..\inc\packon.h"\
+ "..\..\..\..\inc\tdi.h"\
+ "..\..\..\..\inc\tdikrnl.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\bind.h"\
+ "..\inc\isnkrnl.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntmp.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\..\inc\ipxfwd.h"\
+ ".\debug.h"\
+ ".\driver.h"\
+ ".\ipxbind.h"\
+ ".\lineind.h"\
+ ".\netbios.h"\
+ ".\packets.h"\
+ ".\rcvind.h"\
+ ".\registry.h"\
+ ".\send.h"\
+ ".\tables.h"\
+ "e:\NT\public\oak\inc\zwapi.h"\
+ "e:\NT\public\sdk\inc\cfg.h"\
+ "e:\NT\public\sdk\inc\devioctl.h"\
+ "E:\NT\public\sdk\inc\mipsinst.h"\
+ "e:\NT\public\sdk\inc\netevent.h"\
+ "e:\NT\public\sdk\inc\nt.h"\
+ "E:\nt\public\sdk\inc\ntalpha.h"\
+ "e:\NT\public\sdk\inc\ntconfig.h"\
+ "e:\NT\public\sdk\inc\ntddndis.h"\
+ "e:\NT\public\sdk\inc\ntddtdi.h"\
+ "e:\NT\public\sdk\inc\ntdef.h"\
+ "e:\NT\public\sdk\inc\ntelfapi.h"\
+ "e:\NT\public\sdk\inc\ntexapi.h"\
+ "E:\nt\public\sdk\inc\nti386.h"\
+ "e:\NT\public\sdk\inc\ntimage.h"\
+ "e:\NT\public\sdk\inc\ntioapi.h"\
+ "e:\NT\public\sdk\inc\ntiolog.h"\
+ "e:\NT\public\sdk\inc\ntkeapi.h"\
+ "e:\NT\public\sdk\inc\ntkxapi.h"\
+ "e:\NT\public\sdk\inc\ntldr.h"\
+ "e:\NT\public\sdk\inc\ntlpcapi.h"\
+ "E:\nt\public\sdk\inc\ntmips.h"\
+ "e:\NT\public\sdk\inc\ntmmapi.h"\
+ "e:\NT\public\sdk\inc\ntnls.h"\
+ "e:\NT\public\sdk\inc\ntobapi.h"\
+ "e:\NT\public\sdk\inc\ntpnpapi.h"\
+ "e:\NT\public\sdk\inc\ntpoapi.h"\
+ "E:\nt\public\sdk\inc\ntppc.h"\
+ "e:\NT\public\sdk\inc\ntpsapi.h"\
+ "e:\NT\public\sdk\inc\ntregapi.h"\
+ "e:\NT\public\sdk\inc\ntrtl.h"\
+ "e:\NT\public\sdk\inc\ntseapi.h"\
+ "e:\NT\public\sdk\inc\ntstatus.h"\
+ "e:\NT\public\sdk\inc\ntxcapi.h"\
+ "E:\NT\public\sdk\inc\ppcinst.h"\
+
+
+"$(INTDIR)\ipxbind.obj" : $(SOURCE) $(DEP_CPP_IPXBI) "$(INTDIR)"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\driver.c
+
+!IF "$(CFG)" == "fwd - Win32 Release"
+
+DEP_CPP_DRIVE=\
+ "..\..\..\..\inc\ipxfwd.h"\
+ "..\..\..\..\inc\nettypes.h"\
+ "..\..\..\..\inc\packoff.h"\
+ "..\..\..\..\inc\packon.h"\
+ "..\..\..\..\inc\tdi.h"\
+ "..\..\..\..\inc\tdikrnl.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\bind.h"\
+ "..\inc\ipxfltif.h"\
+ "..\inc\isnkrnl.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\ddreqs.h"\
+ ".\debug.h"\
+ ".\driver.h"\
+ ".\filterif.h"\
+ ".\fwddefs.h"\
+ ".\ipxbind.h"\
+ ".\lineind.h"\
+ ".\netbios.h"\
+ ".\packets.h"\
+ ".\precomp.h"\
+ ".\rcvind.h"\
+ ".\registry.h"\
+ ".\rwlock.h"\
+ ".\send.h"\
+ ".\tables.h"\
+ "c:\nt\public\sdk\inc\mipsinst.h"\
+ "c:\nt\public\sdk\inc\ntalpha.h"\
+ "c:\nt\public\sdk\inc\nti386.h"\
+ "c:\nt\public\sdk\inc\ntmips.h"\
+ "c:\nt\public\sdk\inc\ntppc.h"\
+ "c:\nt\public\sdk\inc\ppcinst.h"\
+ {$(INCLUDE)}"\cfg.h"\
+ {$(INCLUDE)}"\devioctl.h"\
+ {$(INCLUDE)}"\netevent.h"\
+ {$(INCLUDE)}"\nt.h"\
+ {$(INCLUDE)}"\ntconfig.h"\
+ {$(INCLUDE)}"\ntddndis.h"\
+ {$(INCLUDE)}"\ntddtdi.h"\
+ {$(INCLUDE)}"\ntdef.h"\
+ {$(INCLUDE)}"\ntelfapi.h"\
+ {$(INCLUDE)}"\ntexapi.h"\
+ {$(INCLUDE)}"\ntimage.h"\
+ {$(INCLUDE)}"\ntioapi.h"\
+ {$(INCLUDE)}"\ntiolog.h"\
+ {$(INCLUDE)}"\ntkeapi.h"\
+ {$(INCLUDE)}"\ntkxapi.h"\
+ {$(INCLUDE)}"\ntldr.h"\
+ {$(INCLUDE)}"\ntlpcapi.h"\
+ {$(INCLUDE)}"\ntmmapi.h"\
+ {$(INCLUDE)}"\ntnls.h"\
+ {$(INCLUDE)}"\ntobapi.h"\
+ {$(INCLUDE)}"\ntpnpapi.h"\
+ {$(INCLUDE)}"\ntpoapi.h"\
+ {$(INCLUDE)}"\ntpsapi.h"\
+ {$(INCLUDE)}"\ntregapi.h"\
+ {$(INCLUDE)}"\ntrtl.h"\
+ {$(INCLUDE)}"\ntseapi.h"\
+ {$(INCLUDE)}"\ntstatus.h"\
+ {$(INCLUDE)}"\ntxcapi.h"\
+ {$(INCLUDE)}"\zwapi.h"\
+
+
+"$(INTDIR)\driver.obj" : $(SOURCE) $(DEP_CPP_DRIVE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "fwd - Win32 (PPC) Release"
+
+DEP_CPP_DRIVE=\
+ "..\..\..\..\inc\nettypes.h"\
+ "..\..\..\..\inc\packoff.h"\
+ "..\..\..\..\inc\packon.h"\
+ "..\..\..\..\inc\tdi.h"\
+ "..\..\..\..\inc\tdikrnl.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\bind.h"\
+ "..\inc\isnkrnl.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntmp.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\..\inc\ipxfwd.h"\
+ ".\debug.h"\
+ ".\driver.h"\
+ ".\ipxbind.h"\
+ ".\lineind.h"\
+ ".\netbios.h"\
+ ".\packets.h"\
+ ".\rcvind.h"\
+ ".\registry.h"\
+ ".\send.h"\
+ ".\tables.h"\
+ "e:\NT\public\oak\inc\zwapi.h"\
+ "e:\NT\public\sdk\inc\cfg.h"\
+ "e:\NT\public\sdk\inc\devioctl.h"\
+ "E:\NT\public\sdk\inc\mipsinst.h"\
+ "e:\NT\public\sdk\inc\netevent.h"\
+ "e:\NT\public\sdk\inc\nt.h"\
+ "E:\nt\public\sdk\inc\ntalpha.h"\
+ "e:\NT\public\sdk\inc\ntconfig.h"\
+ "e:\NT\public\sdk\inc\ntddndis.h"\
+ "e:\NT\public\sdk\inc\ntddtdi.h"\
+ "e:\NT\public\sdk\inc\ntdef.h"\
+ "e:\NT\public\sdk\inc\ntelfapi.h"\
+ "e:\NT\public\sdk\inc\ntexapi.h"\
+ "E:\nt\public\sdk\inc\nti386.h"\
+ "e:\NT\public\sdk\inc\ntimage.h"\
+ "e:\NT\public\sdk\inc\ntioapi.h"\
+ "e:\NT\public\sdk\inc\ntiolog.h"\
+ "e:\NT\public\sdk\inc\ntkeapi.h"\
+ "e:\NT\public\sdk\inc\ntkxapi.h"\
+ "e:\NT\public\sdk\inc\ntldr.h"\
+ "e:\NT\public\sdk\inc\ntlpcapi.h"\
+ "E:\nt\public\sdk\inc\ntmips.h"\
+ "e:\NT\public\sdk\inc\ntmmapi.h"\
+ "e:\NT\public\sdk\inc\ntnls.h"\
+ "e:\NT\public\sdk\inc\ntobapi.h"\
+ "e:\NT\public\sdk\inc\ntpnpapi.h"\
+ "e:\NT\public\sdk\inc\ntpoapi.h"\
+ "E:\nt\public\sdk\inc\ntppc.h"\
+ "e:\NT\public\sdk\inc\ntpsapi.h"\
+ "e:\NT\public\sdk\inc\ntregapi.h"\
+ "e:\NT\public\sdk\inc\ntrtl.h"\
+ "e:\NT\public\sdk\inc\ntseapi.h"\
+ "e:\NT\public\sdk\inc\ntstatus.h"\
+ "e:\NT\public\sdk\inc\ntxcapi.h"\
+ "E:\NT\public\sdk\inc\ppcinst.h"\
+
+
+"$(INTDIR)\driver.obj" : $(SOURCE) $(DEP_CPP_DRIVE) "$(INTDIR)"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\mp\sources
+
+!IF "$(CFG)" == "fwd - Win32 Release"
+
+!ELSEIF "$(CFG)" == "fwd - Win32 (PPC) Release"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\up\sources
+
+!IF "$(CFG)" == "fwd - Win32 Release"
+
+!ELSEIF "$(CFG)" == "fwd - Win32 (PPC) Release"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\registry.c
+
+!IF "$(CFG)" == "fwd - Win32 Release"
+
+DEP_CPP_REGIS=\
+ "..\..\..\..\inc\ipxfwd.h"\
+ "..\..\..\..\inc\nettypes.h"\
+ "..\..\..\..\inc\packoff.h"\
+ "..\..\..\..\inc\packon.h"\
+ "..\..\..\..\inc\tdi.h"\
+ "..\..\..\..\inc\tdikrnl.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\bind.h"\
+ "..\inc\ipxfltif.h"\
+ "..\inc\isnkrnl.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\ddreqs.h"\
+ ".\debug.h"\
+ ".\driver.h"\
+ ".\filterif.h"\
+ ".\fwddefs.h"\
+ ".\ipxbind.h"\
+ ".\lineind.h"\
+ ".\netbios.h"\
+ ".\packets.h"\
+ ".\precomp.h"\
+ ".\rcvind.h"\
+ ".\registry.h"\
+ ".\rwlock.h"\
+ ".\send.h"\
+ ".\tables.h"\
+ "c:\nt\public\sdk\inc\mipsinst.h"\
+ "c:\nt\public\sdk\inc\ntalpha.h"\
+ "c:\nt\public\sdk\inc\nti386.h"\
+ "c:\nt\public\sdk\inc\ntmips.h"\
+ "c:\nt\public\sdk\inc\ntppc.h"\
+ "c:\nt\public\sdk\inc\ppcinst.h"\
+ {$(INCLUDE)}"\cfg.h"\
+ {$(INCLUDE)}"\devioctl.h"\
+ {$(INCLUDE)}"\netevent.h"\
+ {$(INCLUDE)}"\nt.h"\
+ {$(INCLUDE)}"\ntconfig.h"\
+ {$(INCLUDE)}"\ntddndis.h"\
+ {$(INCLUDE)}"\ntddtdi.h"\
+ {$(INCLUDE)}"\ntdef.h"\
+ {$(INCLUDE)}"\ntelfapi.h"\
+ {$(INCLUDE)}"\ntexapi.h"\
+ {$(INCLUDE)}"\ntimage.h"\
+ {$(INCLUDE)}"\ntioapi.h"\
+ {$(INCLUDE)}"\ntiolog.h"\
+ {$(INCLUDE)}"\ntkeapi.h"\
+ {$(INCLUDE)}"\ntkxapi.h"\
+ {$(INCLUDE)}"\ntldr.h"\
+ {$(INCLUDE)}"\ntlpcapi.h"\
+ {$(INCLUDE)}"\ntmmapi.h"\
+ {$(INCLUDE)}"\ntnls.h"\
+ {$(INCLUDE)}"\ntobapi.h"\
+ {$(INCLUDE)}"\ntpnpapi.h"\
+ {$(INCLUDE)}"\ntpoapi.h"\
+ {$(INCLUDE)}"\ntpsapi.h"\
+ {$(INCLUDE)}"\ntregapi.h"\
+ {$(INCLUDE)}"\ntrtl.h"\
+ {$(INCLUDE)}"\ntseapi.h"\
+ {$(INCLUDE)}"\ntstatus.h"\
+ {$(INCLUDE)}"\ntxcapi.h"\
+ {$(INCLUDE)}"\zwapi.h"\
+
+
+"$(INTDIR)\registry.obj" : $(SOURCE) $(DEP_CPP_REGIS) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "fwd - Win32 (PPC) Release"
+
+DEP_CPP_REGIS=\
+ "..\..\..\..\inc\nettypes.h"\
+ "..\..\..\..\inc\packoff.h"\
+ "..\..\..\..\inc\packon.h"\
+ "..\..\..\..\inc\tdi.h"\
+ "..\..\..\..\inc\tdikrnl.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\bind.h"\
+ "..\inc\isnkrnl.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntmp.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\..\inc\ipxfwd.h"\
+ ".\debug.h"\
+ ".\driver.h"\
+ ".\ipxbind.h"\
+ ".\lineind.h"\
+ ".\netbios.h"\
+ ".\packets.h"\
+ ".\rcvind.h"\
+ ".\registry.h"\
+ ".\send.h"\
+ ".\tables.h"\
+ "e:\NT\public\oak\inc\zwapi.h"\
+ "e:\NT\public\sdk\inc\cfg.h"\
+ "e:\NT\public\sdk\inc\devioctl.h"\
+ "E:\NT\public\sdk\inc\mipsinst.h"\
+ "e:\NT\public\sdk\inc\netevent.h"\
+ "e:\NT\public\sdk\inc\nt.h"\
+ "E:\nt\public\sdk\inc\ntalpha.h"\
+ "e:\NT\public\sdk\inc\ntconfig.h"\
+ "e:\NT\public\sdk\inc\ntddndis.h"\
+ "e:\NT\public\sdk\inc\ntddtdi.h"\
+ "e:\NT\public\sdk\inc\ntdef.h"\
+ "e:\NT\public\sdk\inc\ntelfapi.h"\
+ "e:\NT\public\sdk\inc\ntexapi.h"\
+ "E:\nt\public\sdk\inc\nti386.h"\
+ "e:\NT\public\sdk\inc\ntimage.h"\
+ "e:\NT\public\sdk\inc\ntioapi.h"\
+ "e:\NT\public\sdk\inc\ntiolog.h"\
+ "e:\NT\public\sdk\inc\ntkeapi.h"\
+ "e:\NT\public\sdk\inc\ntkxapi.h"\
+ "e:\NT\public\sdk\inc\ntldr.h"\
+ "e:\NT\public\sdk\inc\ntlpcapi.h"\
+ "E:\nt\public\sdk\inc\ntmips.h"\
+ "e:\NT\public\sdk\inc\ntmmapi.h"\
+ "e:\NT\public\sdk\inc\ntnls.h"\
+ "e:\NT\public\sdk\inc\ntobapi.h"\
+ "e:\NT\public\sdk\inc\ntpnpapi.h"\
+ "e:\NT\public\sdk\inc\ntpoapi.h"\
+ "E:\nt\public\sdk\inc\ntppc.h"\
+ "e:\NT\public\sdk\inc\ntpsapi.h"\
+ "e:\NT\public\sdk\inc\ntregapi.h"\
+ "e:\NT\public\sdk\inc\ntrtl.h"\
+ "e:\NT\public\sdk\inc\ntseapi.h"\
+ "e:\NT\public\sdk\inc\ntstatus.h"\
+ "e:\NT\public\sdk\inc\ntxcapi.h"\
+ "E:\NT\public\sdk\inc\ppcinst.h"\
+
+
+"$(INTDIR)\registry.obj" : $(SOURCE) $(DEP_CPP_REGIS) "$(INTDIR)"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\packets.c
+
+!IF "$(CFG)" == "fwd - Win32 Release"
+
+DEP_CPP_PACKE=\
+ "..\..\..\..\inc\ipxfwd.h"\
+ "..\..\..\..\inc\nettypes.h"\
+ "..\..\..\..\inc\packoff.h"\
+ "..\..\..\..\inc\packon.h"\
+ "..\..\..\..\inc\tdi.h"\
+ "..\..\..\..\inc\tdikrnl.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\bind.h"\
+ "..\inc\ipxfltif.h"\
+ "..\inc\isnkrnl.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\ddreqs.h"\
+ ".\debug.h"\
+ ".\driver.h"\
+ ".\filterif.h"\
+ ".\fwddefs.h"\
+ ".\ipxbind.h"\
+ ".\lineind.h"\
+ ".\netbios.h"\
+ ".\packets.h"\
+ ".\precomp.h"\
+ ".\rcvind.h"\
+ ".\registry.h"\
+ ".\rwlock.h"\
+ ".\send.h"\
+ ".\tables.h"\
+ "c:\nt\public\sdk\inc\mipsinst.h"\
+ "c:\nt\public\sdk\inc\ntalpha.h"\
+ "c:\nt\public\sdk\inc\nti386.h"\
+ "c:\nt\public\sdk\inc\ntmips.h"\
+ "c:\nt\public\sdk\inc\ntppc.h"\
+ "c:\nt\public\sdk\inc\ppcinst.h"\
+ {$(INCLUDE)}"\cfg.h"\
+ {$(INCLUDE)}"\devioctl.h"\
+ {$(INCLUDE)}"\netevent.h"\
+ {$(INCLUDE)}"\nt.h"\
+ {$(INCLUDE)}"\ntconfig.h"\
+ {$(INCLUDE)}"\ntddndis.h"\
+ {$(INCLUDE)}"\ntddtdi.h"\
+ {$(INCLUDE)}"\ntdef.h"\
+ {$(INCLUDE)}"\ntelfapi.h"\
+ {$(INCLUDE)}"\ntexapi.h"\
+ {$(INCLUDE)}"\ntimage.h"\
+ {$(INCLUDE)}"\ntioapi.h"\
+ {$(INCLUDE)}"\ntiolog.h"\
+ {$(INCLUDE)}"\ntkeapi.h"\
+ {$(INCLUDE)}"\ntkxapi.h"\
+ {$(INCLUDE)}"\ntldr.h"\
+ {$(INCLUDE)}"\ntlpcapi.h"\
+ {$(INCLUDE)}"\ntmmapi.h"\
+ {$(INCLUDE)}"\ntnls.h"\
+ {$(INCLUDE)}"\ntobapi.h"\
+ {$(INCLUDE)}"\ntpnpapi.h"\
+ {$(INCLUDE)}"\ntpoapi.h"\
+ {$(INCLUDE)}"\ntpsapi.h"\
+ {$(INCLUDE)}"\ntregapi.h"\
+ {$(INCLUDE)}"\ntrtl.h"\
+ {$(INCLUDE)}"\ntseapi.h"\
+ {$(INCLUDE)}"\ntstatus.h"\
+ {$(INCLUDE)}"\ntxcapi.h"\
+ {$(INCLUDE)}"\zwapi.h"\
+
+
+"$(INTDIR)\packets.obj" : $(SOURCE) $(DEP_CPP_PACKE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "fwd - Win32 (PPC) Release"
+
+DEP_CPP_PACKE=\
+ "..\..\..\..\inc\nettypes.h"\
+ "..\..\..\..\inc\packoff.h"\
+ "..\..\..\..\inc\packon.h"\
+ "..\..\..\..\inc\tdi.h"\
+ "..\..\..\..\inc\tdikrnl.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\bind.h"\
+ "..\inc\isnkrnl.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntmp.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\..\inc\ipxfwd.h"\
+ ".\debug.h"\
+ ".\driver.h"\
+ ".\ipxbind.h"\
+ ".\lineind.h"\
+ ".\netbios.h"\
+ ".\packets.h"\
+ ".\rcvind.h"\
+ ".\registry.h"\
+ ".\send.h"\
+ ".\tables.h"\
+ "e:\NT\public\oak\inc\zwapi.h"\
+ "e:\NT\public\sdk\inc\cfg.h"\
+ "e:\NT\public\sdk\inc\devioctl.h"\
+ "E:\NT\public\sdk\inc\mipsinst.h"\
+ "e:\NT\public\sdk\inc\netevent.h"\
+ "e:\NT\public\sdk\inc\nt.h"\
+ "E:\nt\public\sdk\inc\ntalpha.h"\
+ "e:\NT\public\sdk\inc\ntconfig.h"\
+ "e:\NT\public\sdk\inc\ntddndis.h"\
+ "e:\NT\public\sdk\inc\ntddtdi.h"\
+ "e:\NT\public\sdk\inc\ntdef.h"\
+ "e:\NT\public\sdk\inc\ntelfapi.h"\
+ "e:\NT\public\sdk\inc\ntexapi.h"\
+ "E:\nt\public\sdk\inc\nti386.h"\
+ "e:\NT\public\sdk\inc\ntimage.h"\
+ "e:\NT\public\sdk\inc\ntioapi.h"\
+ "e:\NT\public\sdk\inc\ntiolog.h"\
+ "e:\NT\public\sdk\inc\ntkeapi.h"\
+ "e:\NT\public\sdk\inc\ntkxapi.h"\
+ "e:\NT\public\sdk\inc\ntldr.h"\
+ "e:\NT\public\sdk\inc\ntlpcapi.h"\
+ "E:\nt\public\sdk\inc\ntmips.h"\
+ "e:\NT\public\sdk\inc\ntmmapi.h"\
+ "e:\NT\public\sdk\inc\ntnls.h"\
+ "e:\NT\public\sdk\inc\ntobapi.h"\
+ "e:\NT\public\sdk\inc\ntpnpapi.h"\
+ "e:\NT\public\sdk\inc\ntpoapi.h"\
+ "E:\nt\public\sdk\inc\ntppc.h"\
+ "e:\NT\public\sdk\inc\ntpsapi.h"\
+ "e:\NT\public\sdk\inc\ntregapi.h"\
+ "e:\NT\public\sdk\inc\ntrtl.h"\
+ "e:\NT\public\sdk\inc\ntseapi.h"\
+ "e:\NT\public\sdk\inc\ntstatus.h"\
+ "e:\NT\public\sdk\inc\ntxcapi.h"\
+ "E:\NT\public\sdk\inc\ppcinst.h"\
+
+
+"$(INTDIR)\packets.obj" : $(SOURCE) $(DEP_CPP_PACKE) "$(INTDIR)"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\nwlnkfwd.rc
+
+!IF "$(CFG)" == "fwd - Win32 Release"
+
+DEP_RSC_NWLNK=\
+ {$(INCLUDE)}"\common.ver"\
+ {$(INCLUDE)}"\ntverp.h"\
+
+
+"$(INTDIR)\nwlnkfwd.res" : $(SOURCE) $(DEP_RSC_NWLNK) "$(INTDIR)"
+ $(RSC) $(RSC_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "fwd - Win32 (PPC) Release"
+
+DEP_RSC_NWLNK=\
+ ".\common.ver"\
+ ".\ntverp.h"\
+
+
+"$(INTDIR)\nwlnkfwd.res" : $(SOURCE) $(DEP_RSC_NWLNK) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)/nwlnkfwd.res" /d "NDEBUG" $(SOURCE)
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\tables.c
+
+!IF "$(CFG)" == "fwd - Win32 Release"
+
+DEP_CPP_TABLE=\
+ "..\..\..\..\inc\ipxfwd.h"\
+ "..\..\..\..\inc\nettypes.h"\
+ "..\..\..\..\inc\packoff.h"\
+ "..\..\..\..\inc\packon.h"\
+ "..\..\..\..\inc\tdi.h"\
+ "..\..\..\..\inc\tdikrnl.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\bind.h"\
+ "..\inc\ipxfltif.h"\
+ "..\inc\isnkrnl.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\ddreqs.h"\
+ ".\debug.h"\
+ ".\driver.h"\
+ ".\filterif.h"\
+ ".\fwddefs.h"\
+ ".\ipxbind.h"\
+ ".\lineind.h"\
+ ".\netbios.h"\
+ ".\packets.h"\
+ ".\precomp.h"\
+ ".\rcvind.h"\
+ ".\registry.h"\
+ ".\rwlock.h"\
+ ".\send.h"\
+ ".\tables.h"\
+ "c:\nt\public\sdk\inc\mipsinst.h"\
+ "c:\nt\public\sdk\inc\ntalpha.h"\
+ "c:\nt\public\sdk\inc\nti386.h"\
+ "c:\nt\public\sdk\inc\ntmips.h"\
+ "c:\nt\public\sdk\inc\ntppc.h"\
+ "c:\nt\public\sdk\inc\ppcinst.h"\
+ {$(INCLUDE)}"\cfg.h"\
+ {$(INCLUDE)}"\devioctl.h"\
+ {$(INCLUDE)}"\netevent.h"\
+ {$(INCLUDE)}"\nt.h"\
+ {$(INCLUDE)}"\ntconfig.h"\
+ {$(INCLUDE)}"\ntddndis.h"\
+ {$(INCLUDE)}"\ntddtdi.h"\
+ {$(INCLUDE)}"\ntdef.h"\
+ {$(INCLUDE)}"\ntelfapi.h"\
+ {$(INCLUDE)}"\ntexapi.h"\
+ {$(INCLUDE)}"\ntimage.h"\
+ {$(INCLUDE)}"\ntioapi.h"\
+ {$(INCLUDE)}"\ntiolog.h"\
+ {$(INCLUDE)}"\ntkeapi.h"\
+ {$(INCLUDE)}"\ntkxapi.h"\
+ {$(INCLUDE)}"\ntldr.h"\
+ {$(INCLUDE)}"\ntlpcapi.h"\
+ {$(INCLUDE)}"\ntmmapi.h"\
+ {$(INCLUDE)}"\ntnls.h"\
+ {$(INCLUDE)}"\ntobapi.h"\
+ {$(INCLUDE)}"\ntpnpapi.h"\
+ {$(INCLUDE)}"\ntpoapi.h"\
+ {$(INCLUDE)}"\ntpsapi.h"\
+ {$(INCLUDE)}"\ntregapi.h"\
+ {$(INCLUDE)}"\ntrtl.h"\
+ {$(INCLUDE)}"\ntseapi.h"\
+ {$(INCLUDE)}"\ntstatus.h"\
+ {$(INCLUDE)}"\ntxcapi.h"\
+ {$(INCLUDE)}"\zwapi.h"\
+
+
+"$(INTDIR)\tables.obj" : $(SOURCE) $(DEP_CPP_TABLE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "fwd - Win32 (PPC) Release"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ddreqs.c
+
+!IF "$(CFG)" == "fwd - Win32 Release"
+
+DEP_CPP_DDREQ=\
+ "..\..\..\..\inc\ipxfwd.h"\
+ "..\..\..\..\inc\nettypes.h"\
+ "..\..\..\..\inc\packoff.h"\
+ "..\..\..\..\inc\packon.h"\
+ "..\..\..\..\inc\tdi.h"\
+ "..\..\..\..\inc\tdikrnl.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\bind.h"\
+ "..\inc\ipxfltif.h"\
+ "..\inc\isnkrnl.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\ddreqs.h"\
+ ".\debug.h"\
+ ".\driver.h"\
+ ".\filterif.h"\
+ ".\fwddefs.h"\
+ ".\ipxbind.h"\
+ ".\lineind.h"\
+ ".\netbios.h"\
+ ".\packets.h"\
+ ".\precomp.h"\
+ ".\rcvind.h"\
+ ".\registry.h"\
+ ".\rwlock.h"\
+ ".\send.h"\
+ ".\tables.h"\
+ "c:\nt\public\sdk\inc\mipsinst.h"\
+ "c:\nt\public\sdk\inc\ntalpha.h"\
+ "c:\nt\public\sdk\inc\nti386.h"\
+ "c:\nt\public\sdk\inc\ntmips.h"\
+ "c:\nt\public\sdk\inc\ntppc.h"\
+ "c:\nt\public\sdk\inc\ppcinst.h"\
+ {$(INCLUDE)}"\cfg.h"\
+ {$(INCLUDE)}"\devioctl.h"\
+ {$(INCLUDE)}"\netevent.h"\
+ {$(INCLUDE)}"\nt.h"\
+ {$(INCLUDE)}"\ntconfig.h"\
+ {$(INCLUDE)}"\ntddndis.h"\
+ {$(INCLUDE)}"\ntddtdi.h"\
+ {$(INCLUDE)}"\ntdef.h"\
+ {$(INCLUDE)}"\ntelfapi.h"\
+ {$(INCLUDE)}"\ntexapi.h"\
+ {$(INCLUDE)}"\ntimage.h"\
+ {$(INCLUDE)}"\ntioapi.h"\
+ {$(INCLUDE)}"\ntiolog.h"\
+ {$(INCLUDE)}"\ntkeapi.h"\
+ {$(INCLUDE)}"\ntkxapi.h"\
+ {$(INCLUDE)}"\ntldr.h"\
+ {$(INCLUDE)}"\ntlpcapi.h"\
+ {$(INCLUDE)}"\ntmmapi.h"\
+ {$(INCLUDE)}"\ntnls.h"\
+ {$(INCLUDE)}"\ntobapi.h"\
+ {$(INCLUDE)}"\ntpnpapi.h"\
+ {$(INCLUDE)}"\ntpoapi.h"\
+ {$(INCLUDE)}"\ntpsapi.h"\
+ {$(INCLUDE)}"\ntregapi.h"\
+ {$(INCLUDE)}"\ntrtl.h"\
+ {$(INCLUDE)}"\ntseapi.h"\
+ {$(INCLUDE)}"\ntstatus.h"\
+ {$(INCLUDE)}"\ntxcapi.h"\
+ {$(INCLUDE)}"\zwapi.h"\
+
+
+"$(INTDIR)\ddreqs.obj" : $(SOURCE) $(DEP_CPP_DDREQ) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "fwd - Win32 (PPC) Release"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\debug.c
+
+!IF "$(CFG)" == "fwd - Win32 Release"
+
+DEP_CPP_DEBUG=\
+ "..\..\..\..\inc\ipxfwd.h"\
+ "..\..\..\..\inc\nettypes.h"\
+ "..\..\..\..\inc\packoff.h"\
+ "..\..\..\..\inc\packon.h"\
+ "..\..\..\..\inc\tdi.h"\
+ "..\..\..\..\inc\tdikrnl.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\bind.h"\
+ "..\inc\ipxfltif.h"\
+ "..\inc\isnkrnl.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\ddreqs.h"\
+ ".\debug.h"\
+ ".\driver.h"\
+ ".\filterif.h"\
+ ".\fwddefs.h"\
+ ".\ipxbind.h"\
+ ".\lineind.h"\
+ ".\netbios.h"\
+ ".\packets.h"\
+ ".\precomp.h"\
+ ".\rcvind.h"\
+ ".\registry.h"\
+ ".\rwlock.h"\
+ ".\send.h"\
+ ".\tables.h"\
+ "c:\nt\public\sdk\inc\mipsinst.h"\
+ "c:\nt\public\sdk\inc\ntalpha.h"\
+ "c:\nt\public\sdk\inc\nti386.h"\
+ "c:\nt\public\sdk\inc\ntmips.h"\
+ "c:\nt\public\sdk\inc\ntppc.h"\
+ "c:\nt\public\sdk\inc\ppcinst.h"\
+ {$(INCLUDE)}"\cfg.h"\
+ {$(INCLUDE)}"\devioctl.h"\
+ {$(INCLUDE)}"\netevent.h"\
+ {$(INCLUDE)}"\nt.h"\
+ {$(INCLUDE)}"\ntconfig.h"\
+ {$(INCLUDE)}"\ntddndis.h"\
+ {$(INCLUDE)}"\ntddtdi.h"\
+ {$(INCLUDE)}"\ntdef.h"\
+ {$(INCLUDE)}"\ntelfapi.h"\
+ {$(INCLUDE)}"\ntexapi.h"\
+ {$(INCLUDE)}"\ntimage.h"\
+ {$(INCLUDE)}"\ntioapi.h"\
+ {$(INCLUDE)}"\ntiolog.h"\
+ {$(INCLUDE)}"\ntkeapi.h"\
+ {$(INCLUDE)}"\ntkxapi.h"\
+ {$(INCLUDE)}"\ntldr.h"\
+ {$(INCLUDE)}"\ntlpcapi.h"\
+ {$(INCLUDE)}"\ntmmapi.h"\
+ {$(INCLUDE)}"\ntnls.h"\
+ {$(INCLUDE)}"\ntobapi.h"\
+ {$(INCLUDE)}"\ntpnpapi.h"\
+ {$(INCLUDE)}"\ntpoapi.h"\
+ {$(INCLUDE)}"\ntpsapi.h"\
+ {$(INCLUDE)}"\ntregapi.h"\
+ {$(INCLUDE)}"\ntrtl.h"\
+ {$(INCLUDE)}"\ntseapi.h"\
+ {$(INCLUDE)}"\ntstatus.h"\
+ {$(INCLUDE)}"\ntxcapi.h"\
+ {$(INCLUDE)}"\zwapi.h"\
+
+
+"$(INTDIR)\debug.obj" : $(SOURCE) $(DEP_CPP_DEBUG) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "fwd - Win32 (PPC) Release"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\filterif.c
+
+!IF "$(CFG)" == "fwd - Win32 Release"
+
+DEP_CPP_FILTE=\
+ "..\..\..\..\inc\ipxfwd.h"\
+ "..\..\..\..\inc\nettypes.h"\
+ "..\..\..\..\inc\packoff.h"\
+ "..\..\..\..\inc\packon.h"\
+ "..\..\..\..\inc\tdi.h"\
+ "..\..\..\..\inc\tdikrnl.h"\
+ "..\..\..\inc\afilter.h"\
+ "..\..\..\inc\bugcodes.h"\
+ "..\..\..\inc\efilter.h"\
+ "..\..\..\inc\exlevels.h"\
+ "..\..\..\inc\ffilter.h"\
+ "..\..\..\inc\ndis.h"\
+ "..\..\..\inc\ntddk.h"\
+ "..\..\..\inc\ntiologc.h"\
+ "..\..\..\inc\ntos.h"\
+ "..\..\..\inc\tfilter.h"\
+ "..\inc\bind.h"\
+ "..\inc\ipxfltif.h"\
+ "..\inc\isnkrnl.h"\
+ ".\..\..\..\inc\alpha.h"\
+ ".\..\..\..\inc\alpharef.h"\
+ ".\..\..\..\inc\arc.h"\
+ ".\..\..\..\inc\cache.h"\
+ ".\..\..\..\inc\cm.h"\
+ ".\..\..\..\inc\dbgk.h"\
+ ".\..\..\..\inc\ex.h"\
+ ".\..\..\..\inc\exboosts.h"\
+ ".\..\..\..\inc\hal.h"\
+ ".\..\..\..\inc\i386.h"\
+ ".\..\..\..\inc\init.h"\
+ ".\..\..\..\inc\kd.h"\
+ ".\..\..\..\inc\ke.h"\
+ ".\..\..\..\inc\lfs.h"\
+ ".\..\..\..\inc\lpc.h"\
+ ".\..\..\..\inc\mips.h"\
+ ".\..\..\..\inc\mm.h"\
+ ".\..\..\..\inc\ntosdef.h"\
+ ".\..\..\..\inc\ob.h"\
+ ".\..\..\..\inc\pnp.h"\
+ ".\..\..\..\inc\po.h"\
+ ".\..\..\..\inc\ppc.h"\
+ ".\..\..\..\inc\ps.h"\
+ ".\..\..\..\inc\se.h"\
+ ".\..\..\..\inc\v86emul.h"\
+ ".\ddreqs.h"\
+ ".\debug.h"\
+ ".\driver.h"\
+ ".\filterif.h"\
+ ".\fwddefs.h"\
+ ".\ipxbind.h"\
+ ".\lineind.h"\
+ ".\netbios.h"\
+ ".\packets.h"\
+ ".\precomp.h"\
+ ".\rcvind.h"\
+ ".\registry.h"\
+ ".\rwlock.h"\
+ ".\send.h"\
+ ".\tables.h"\
+ "c:\nt\public\sdk\inc\mipsinst.h"\
+ "c:\nt\public\sdk\inc\ntalpha.h"\
+ "c:\nt\public\sdk\inc\nti386.h"\
+ "c:\nt\public\sdk\inc\ntmips.h"\
+ "c:\nt\public\sdk\inc\ntppc.h"\
+ "c:\nt\public\sdk\inc\ppcinst.h"\
+ {$(INCLUDE)}"\cfg.h"\
+ {$(INCLUDE)}"\devioctl.h"\
+ {$(INCLUDE)}"\netevent.h"\
+ {$(INCLUDE)}"\nt.h"\
+ {$(INCLUDE)}"\ntconfig.h"\
+ {$(INCLUDE)}"\ntddndis.h"\
+ {$(INCLUDE)}"\ntddtdi.h"\
+ {$(INCLUDE)}"\ntdef.h"\
+ {$(INCLUDE)}"\ntelfapi.h"\
+ {$(INCLUDE)}"\ntexapi.h"\
+ {$(INCLUDE)}"\ntimage.h"\
+ {$(INCLUDE)}"\ntioapi.h"\
+ {$(INCLUDE)}"\ntiolog.h"\
+ {$(INCLUDE)}"\ntkeapi.h"\
+ {$(INCLUDE)}"\ntkxapi.h"\
+ {$(INCLUDE)}"\ntldr.h"\
+ {$(INCLUDE)}"\ntlpcapi.h"\
+ {$(INCLUDE)}"\ntmmapi.h"\
+ {$(INCLUDE)}"\ntnls.h"\
+ {$(INCLUDE)}"\ntobapi.h"\
+ {$(INCLUDE)}"\ntpnpapi.h"\
+ {$(INCLUDE)}"\ntpoapi.h"\
+ {$(INCLUDE)}"\ntpsapi.h"\
+ {$(INCLUDE)}"\ntregapi.h"\
+ {$(INCLUDE)}"\ntrtl.h"\
+ {$(INCLUDE)}"\ntseapi.h"\
+ {$(INCLUDE)}"\ntstatus.h"\
+ {$(INCLUDE)}"\ntxcapi.h"\
+ {$(INCLUDE)}"\zwapi.h"\
+
+
+"$(INTDIR)\filterif.obj" : $(SOURCE) $(DEP_CPP_FILTE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "fwd - Win32 (PPC) Release"
+
+!ENDIF
+
+# End Source File
+# End Target
+# End Project
+################################################################################
diff --git a/private/ntos/tdi/isn/fwd/fwddefs.h b/private/ntos/tdi/isn/fwd/fwddefs.h
new file mode 100644
index 000000000..af862b3b5
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/fwddefs.h
@@ -0,0 +1,125 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\fwddefs.h
+
+Abstract:
+ IPX Forwarder driver constants and general macro definitions
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+#ifndef _IPXFWD_FWDDEFS_
+#define _IPXFWD_FWDDEFS_
+
+
+// Forwarder tag used in memory allocations
+#define FWD_POOL_TAG 'wFwN'
+
+//*** Offsets into the IPX header
+#define IPXH_HDRSIZE 30 // Size of the IPX header
+#define IPXH_CHECKSUM 0 // Checksum
+#define IPXH_LENGTH 2 // Length
+#define IPXH_XPORTCTL 4 // Transport Control
+#define IPXH_PKTTYPE 5 // Packet Type
+#define IPXH_DESTADDR 6 // Dest. Address (Total)
+#define IPXH_DESTNET 6 // Dest. Network Address
+#define IPXH_DESTNODE 10 // Dest. Node Address
+#define IPXH_DESTSOCK 16 // Dest. Socket Number
+#define IPXH_SRCADDR 18 // Source Address (Total)
+#define IPXH_SRCNET 18 // Source Network Address
+#define IPXH_SRCNODE 22 // Source Node Address
+#define IPXH_SRCSOCK 28 // Source Socket Number
+
+//*** Packet Types we care about
+#define IPX_NETBIOS_TYPE 20 // Netbios propagated packet
+
+//*** Socket Numbers we care about
+#define IPX_NETBIOS_SOCKET ((USHORT)0x0455)
+#define IPX_SAP_SOCKET ((USHORT)0x0452)
+#define IPX_SMB_NAME_SOCKET ((USHORT)0x0551)
+
+//*** maximum nr of hops for a normal packet ***
+#define IPX_MAX_HOPS 16
+
+//*** offsets into the netbios name frames ***
+#define NB_NAME_TYPE_FLAG 62
+#define NB_DATA_STREAM_TYPE2 63
+#define NB_NAME 64
+#define NB_TOTAL_DATA_LENGTH 80
+// *** offsets into smb name claim/query frames
+#define SMB_OPERATION 62
+#define SMB_NAME_TYPE 63
+#define SMB_MESSAGE_IF 64
+#define SMB_NAME 66
+
+
+// Some commonly used macros
+#define IPX_NODE_CPY(dst,src) memcpy(dst,src,6)
+#define IPX_NODE_CMP(node1,node2) memcmp(node1,node2,6)
+
+#define IPX_NET_CPY(dst,src) memcpy(dst,src,4)
+#define IPX_NET_CMP(net1,net2) memcmp(net1,net2,4)
+
+#define NB_NAME_CPY(dst,src) strncpy((char *)dst,(char *)src,16)
+#define NB_NAME_CMP(name1,name2) strncmp((char *)name1,(char *)name2,16)
+
+// Make sure the structure is copied with DWORD granularity
+#define IF_STATS_CPY(dst,src) \
+ (dst)->OperationalState = (src)->OperationalState; \
+ (dst)->MaxPacketSize = (src)->MaxPacketSize; \
+ (dst)->InHdrErrors = (src)->InHdrErrors; \
+ (dst)->InFiltered = (src)->InFiltered; \
+ (dst)->InNoRoutes = (src)->InNoRoutes; \
+ (dst)->InDiscards = (src)->InDiscards; \
+ (dst)->InDelivers = (src)->InDelivers; \
+ (dst)->OutFiltered = (src)->OutFiltered; \
+ (dst)->OutDiscards = (src)->OutDiscards; \
+ (dst)->OutDelivers = (src)->OutDelivers; \
+ (dst)->NetbiosReceived = (src)->NetbiosReceived; \
+ (dst)->NetbiosSent = (src)->NetbiosSent;
+
+// Extensions to list macros
+#define InitializeListEntry(entry) InitializeListHead(entry)
+#define IsListEntry(entry) IsListEmpty(entry)
+#define IsSingleEntry(head) ((head)->Flink==(head)->Blink)
+
+// Conversions from/to on-the-wire format
+#define GETUSHORT(src) ( \
+ (USHORT)( \
+ (((UCHAR *)src)[0]<<8) \
+ + (((UCHAR *)src)[1]) \
+ ) \
+)
+
+#define GETULONG(src) ( \
+ (ULONG)( \
+ (((UCHAR *)src)[0]<<24) \
+ + (((UCHAR *)src)[1]<<16) \
+ + (((UCHAR *)src)[2]<<8) \
+ + (((UCHAR *)src)[3]) \
+ ) \
+)
+
+#define PUTUSHORT(src,dst) { \
+ ((UCHAR *)dst)[0] = ((UCHAR)(src>>8)); \
+ ((UCHAR *)dst)[1] = ((UCHAR)src); \
+}
+
+#define PUTULONG(src,dst) { \
+ ((UCHAR *)dst)[0] = ((UCHAR)(src>>24)); \
+ ((UCHAR *)dst)[1] = ((UCHAR)(src>>16)); \
+ ((UCHAR *)dst)[2] = ((UCHAR)(src>>8)); \
+ ((UCHAR *)dst)[3] = ((UCHAR)src); \
+}
+
+
+#endif
diff --git a/private/ntos/tdi/isn/fwd/ipxbind.c b/private/ntos/tdi/isn/fwd/ipxbind.c
new file mode 100644
index 000000000..71c7a37b3
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/ipxbind.c
@@ -0,0 +1,462 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\ipxbind.c
+
+Abstract:
+ IPX Forwarder Driver interface with IPX stack driver
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+
+
+// global handle of the IPX driver
+HANDLE HdlIpxFile;
+
+
+// Buffer for IPX binding output structure
+PIPX_INTERNAL_BIND_RIP_OUTPUT IPXBindOutput=NULL;
+
+NTSTATUS
+IpxFwdFindRoute (
+ IN PUCHAR Network,
+ IN PUCHAR Node,
+ OUT PIPX_FIND_ROUTE_REQUEST RouteEntry
+ );
+
+/*++
+*******************************************************************
+ B i n d T o I p x D r i v e r
+
+Routine Description:
+ Exchanges binding information with IPX stack driver
+Arguments:
+ None
+Return Value:
+ STATUS_SUCCESS - exchange was done OK
+ STATUS_INSUFFICIENT_RESOURCES - could not allocate buffers for
+ info exchange
+ error status returned by IPX stack driver
+
+*******************************************************************
+--*/
+NTSTATUS
+BindToIpxDriver (
+ KPROCESSOR_MODE requestorMode
+ ) {
+ NTSTATUS status;
+ IO_STATUS_BLOCK IoStatusBlock;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PIPX_INTERNAL_BIND_INPUT bip;
+ UNICODE_STRING UstrIpxFileName;
+ PWSTR WstrIpxFileName;
+
+ ASSERT (IPXBindOutput==NULL);
+
+ // Read Ipx exported device name from the registry
+ status = ReadIpxDeviceName (&WstrIpxFileName);
+ if (!NT_SUCCESS (status))
+ return status;
+
+ RtlInitUnicodeString (&UstrIpxFileName, WstrIpxFileName);
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &UstrIpxFileName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+ if (requestorMode==UserMode)
+ status = ZwCreateFile(&HdlIpxFile,
+ SYNCHRONIZE | GENERIC_READ,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0L);
+ else
+ status = NtCreateFile(&HdlIpxFile,
+ SYNCHRONIZE | GENERIC_READ,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0L);
+
+ if (!NT_SUCCESS(status)) {
+ IpxFwdDbgPrint (DBG_IPXBIND, DBG_ERROR,
+ ("IpxFwd: Open of the IPX driver failed with %lx\n", status));
+ return status;
+ }
+
+ IpxFwdDbgPrint (DBG_IPXBIND, DBG_INFORMATION,
+ ("IpxFwd: Open of the IPX driver was successful.\n"));
+
+ // First, send a IOCTL to find out how much data we need to allocate
+ if ((bip = ExAllocatePoolWithTag (
+ PagedPool,
+ sizeof(IPX_INTERNAL_BIND_INPUT),
+ FWD_POOL_TAG)) == NULL) {
+
+ if (KeGetPreviousMode()!=KernelMode)
+ ZwClose (HdlIpxFile);
+ else
+ NtClose (HdlIpxFile);
+ IpxFwdDbgPrint (DBG_IPXBIND, DBG_ERROR,
+ ("IpxFwd: Could not allocate input binding buffer!\n"));
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // fill in our bind data
+ // bip->Version = 1;
+ bip->Version = ISN_VERSION;
+ bip->Identifier = IDENTIFIER_RIP;
+ bip->BroadcastEnable = TRUE;
+ bip->LookaheadRequired = IPXH_HDRSIZE;
+ bip->ProtocolOptions = 0;
+ bip->ReceiveHandler = IpxFwdReceive;
+ bip->ReceiveCompleteHandler = IpxFwdReceiveComplete;
+ bip->SendCompleteHandler = IpxFwdSendComplete;
+ bip->TransferDataCompleteHandler = IpxFwdTransferDataComplete;
+ bip->FindRouteCompleteHandler = NULL;
+ bip->LineUpHandler = IpxFwdLineUp;
+ bip->LineDownHandler = IpxFwdLineDown;
+ bip->InternalSendHandler = IpxFwdInternalSend;
+ bip->FindRouteHandler = IpxFwdFindRoute;
+ bip->InternalReceiveHandler = IpxFwdInternalReceive;
+// bip->RipParameters = GlobalWanNetwork ? IPX_RIP_PARAM_GLOBAL_NETWORK : 0;
+
+
+ if (requestorMode==UserMode)
+ status = ZwDeviceIoControlFile(
+ HdlIpxFile, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPX_INTERNAL_BIND, // IoControlCode
+ bip, // Input Buffer
+ sizeof(IPX_INTERNAL_BIND_INPUT),// Input Buffer Length
+ NULL, // Output Buffer
+ 0); // Output Buffer Length
+ else
+ status = NtDeviceIoControlFile(
+ HdlIpxFile, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPX_INTERNAL_BIND, // IoControlCode
+ bip, // Input Buffer
+ sizeof(IPX_INTERNAL_BIND_INPUT),// Input Buffer Length
+ NULL, // Output Buffer
+ 0); // Output Buffer Length
+
+
+ if (status == STATUS_PENDING) {
+ if (requestorMode==UserMode)
+ status = ZwWaitForSingleObject(
+ HdlIpxFile,
+ FALSE,
+ NULL);
+ else
+ status = NtWaitForSingleObject(
+ HdlIpxFile,
+ FALSE,
+ NULL);
+ if (NT_SUCCESS(status))
+ status = IoStatusBlock.Status;
+ }
+
+ if (status != STATUS_BUFFER_TOO_SMALL) {
+ IpxFwdDbgPrint (DBG_IPXBIND, DBG_ERROR,
+ ("IpxFwd: Ioctl to the IPX driver failed with %lx\n", status));
+
+ ExFreePool(bip);
+ if (requestorMode==UserMode)
+ ZwClose (HdlIpxFile);
+ else
+ NtClose (HdlIpxFile);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if ((IPXBindOutput = (PIPX_INTERNAL_BIND_RIP_OUTPUT)
+ ExAllocatePoolWithTag(NonPagedPool,
+ IoStatusBlock.Information,
+ FWD_POOL_TAG)) == NULL) {
+
+ ExFreePool(bip);
+ if (requestorMode==UserMode)
+ ZwClose (HdlIpxFile);
+ else
+ NtClose (HdlIpxFile);
+ IpxFwdDbgPrint (DBG_IPXBIND, DBG_ERROR,
+ ("IpxFwd: Could not allocate output binding buffer!\n"));
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ if (requestorMode==UserMode)
+ status = ZwDeviceIoControlFile(
+ HdlIpxFile, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPX_INTERNAL_BIND, // IoControlCode
+ bip, // Input Buffer
+ sizeof(IPX_INTERNAL_BIND_INPUT),// Input Buffer Length
+ IPXBindOutput, // Output Buffer
+ IoStatusBlock.Information); // Output Buffer Length
+ else
+ status = NtDeviceIoControlFile(
+ HdlIpxFile, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPX_INTERNAL_BIND, // IoControlCode
+ bip, // Input Buffer
+ sizeof(IPX_INTERNAL_BIND_INPUT),// Input Buffer Length
+ IPXBindOutput, // Output Buffer
+ IoStatusBlock.Information); // Output Buffer Length
+
+
+ if (status == STATUS_PENDING) {
+ if (requestorMode==UserMode)
+ status = ZwWaitForSingleObject(
+ HdlIpxFile,
+ (BOOLEAN)FALSE,
+ NULL);
+ else
+ status = NtWaitForSingleObject(
+ HdlIpxFile,
+ (BOOLEAN)FALSE,
+ NULL);
+ if (NT_SUCCESS(status))
+ status = IoStatusBlock.Status;
+ }
+
+ if (!NT_SUCCESS (status)) {
+ IpxFwdDbgPrint (DBG_IPXBIND, DBG_ERROR,
+ ("IpxFwd: Ioctl to the IPX driver failed with %lx\n", IoStatusBlock.Status));
+
+ ExFreePool(bip);
+ ExFreePool(IPXBindOutput);
+ IPXBindOutput = NULL;
+ if (requestorMode==UserMode)
+ ZwClose (HdlIpxFile);
+ else
+ NtClose (HdlIpxFile);
+ return status;
+ }
+
+ IpxFwdDbgPrint (DBG_IPXBIND, DBG_INFORMATION,
+ ("IpxFwd: Succesfuly bound to the IPX driver\n"));
+
+ ExFreePool (bip);
+ ExFreePool (WstrIpxFileName);
+
+ return status;
+}
+
+
+/*++
+*******************************************************************
+ U n b i n d F r o m I p x D r i v e r
+
+Routine Description:
+ Closes connection to IPX stack driver
+Arguments:
+ None
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+UnbindFromIpxDriver (
+ KPROCESSOR_MODE requestorMode
+ ) {
+ // Free binding output buffer and close driver handle
+ ASSERT (IPXBindOutput!=NULL);
+ ExFreePool (IPXBindOutput);
+ IPXBindOutput = NULL;
+ IpxFwdDbgPrint (DBG_IPXBIND, DBG_WARNING,
+ ("IpxFwd: Closing IPX driver handle\n"));
+ if (requestorMode==UserMode)
+ ZwClose (HdlIpxFile);
+ else
+ NtClose (HdlIpxFile);
+}
+
+
+/*++
+*******************************************************************
+ F w F i n d R o u t e
+
+Routine Description:
+ This routine is provided by the Kernel Forwarder to find the route
+ to a given node and network
+Arguments:
+ Network - the destination network
+ Node - destination node
+ RouteEntry - filled in by the Forwarder if a route exists
+Return Value:
+ STATUS_SUCCESS
+ STATUS_NETWORK_UNREACHABLE - if the findroute failed
+*******************************************************************
+--*/
+NTSTATUS
+IpxFwdFindRoute (
+ IN PUCHAR Network,
+ IN PUCHAR Node,
+ OUT PIPX_FIND_ROUTE_REQUEST RouteEntry
+ ) {
+ PINTERFACE_CB ifCB;
+ ULONG net;
+ KIRQL oldIRQL;
+ NTSTATUS status;
+ PFWD_ROUTE fwRoute;
+
+ if (!EnterForwarder ())
+ return STATUS_UNSUCCESSFUL;
+
+ net = GETULONG (Network);
+
+ ifCB = FindDestination (net, Node, &fwRoute);
+ if (ifCB!=NULL) {
+ if (IS_IF_ENABLED(ifCB)) {
+ KeAcquireSpinLock (&ifCB->ICB_Lock, &oldIRQL);
+ switch (ifCB->ICB_Stats.OperationalState) {
+ case FWD_OPER_STATE_UP:
+ IPX_NET_CPY (&RouteEntry->Network, Network);
+ if (fwRoute->FR_Network==ifCB->ICB_Network) {
+ if (Node!=NULL) {
+ IPX_NODE_CPY (RouteEntry->LocalTarget.MacAddress, Node);
+ }
+ else {
+ IPX_NODE_CPY (RouteEntry->LocalTarget.MacAddress,
+ BROADCAST_NODE);
+ }
+ }
+ else {
+ IPX_NODE_CPY (RouteEntry->LocalTarget.MacAddress,
+ fwRoute->FR_NextHopAddress);
+ }
+ if (ifCB!=InternalInterface) {
+ ADAPTER_CONTEXT_TO_LOCAL_TARGET (
+ ifCB->ICB_AdapterContext,
+ &RouteEntry->LocalTarget);
+ }
+ else {
+ CONSTANT_ADAPTER_CONTEXT_TO_LOCAL_TARGET (
+ VIRTUAL_NET_ADAPTER_CONTEXT,
+ &RouteEntry->LocalTarget);
+ }
+ status = STATUS_SUCCESS;
+ break;
+ case FWD_OPER_STATE_SLEEPING:
+ IPX_NODE_CPY (&RouteEntry->LocalTarget.MacAddress,
+ fwRoute->FR_NextHopAddress);
+ CONSTANT_ADAPTER_CONTEXT_TO_LOCAL_TARGET (DEMAND_DIAL_ADAPTER_CONTEXT,
+ &RouteEntry->LocalTarget);
+ status = STATUS_SUCCESS;
+ break;
+ case FWD_OPER_STATE_DOWN:
+ status = STATUS_NETWORK_UNREACHABLE;
+ break;
+ default:
+ ASSERTMSG ("Inavalid operational state", FALSE);
+ }
+ KeReleaseSpinLock (&ifCB->ICB_Lock, oldIRQL);
+ #if DBG
+ if (Node!=NULL) {
+ if (NT_SUCCESS (status)) {
+ IpxFwdDbgPrint (DBG_IPXBIND, DBG_INFORMATION,
+ ("IpxFwd: Found route for IPX driver:"
+ " %08lX:%02X%02X%02X%02X%02X%02X"
+ " -> %ld(%ld):%02X%02X%02X%02X%02X%02X\n",
+ net, Node[0],Node[1],Node[2],Node[3],Node[4],Node[5],
+ ifCB->ICB_Index, RouteEntry->LocalTarget.NicId,
+ RouteEntry->LocalTarget.MacAddress[0],
+ RouteEntry->LocalTarget.MacAddress[1],
+ RouteEntry->LocalTarget.MacAddress[2],
+ RouteEntry->LocalTarget.MacAddress[3],
+ RouteEntry->LocalTarget.MacAddress[4],
+ RouteEntry->LocalTarget.MacAddress[5]));
+ }
+ else {
+ IpxFwdDbgPrint (DBG_IPXROUTE, DBG_WARNING,
+ ("IpxFwd: Network unreachable for:"
+ " %08lX:%02X%02X%02X%02X%02X%02X -> %ld.\n",
+ net, Node[0],Node[1],Node[2],Node[3],Node[4],Node[5],
+ ifCB->ICB_Index));
+ }
+ }
+ else {
+ if (NT_SUCCESS (status)) {
+ IpxFwdDbgPrint (DBG_IPXBIND, DBG_INFORMATION,
+ ("IpxFwd: Found route for IPX driver:"
+ " %08lX"
+ " -> %ld(%ld):%02X%02X%02X%02X%02X%02X\n",
+ net, ifCB->ICB_Index, RouteEntry->LocalTarget.NicId,
+ RouteEntry->LocalTarget.MacAddress[0],
+ RouteEntry->LocalTarget.MacAddress[1],
+ RouteEntry->LocalTarget.MacAddress[2],
+ RouteEntry->LocalTarget.MacAddress[3],
+ RouteEntry->LocalTarget.MacAddress[4],
+ RouteEntry->LocalTarget.MacAddress[5]));
+ }
+ else {
+ IpxFwdDbgPrint (DBG_IPXROUTE, DBG_WARNING,
+ ("IpxFwd: Network unreachable for:"
+ " %08lX -> %ld.\n", net));
+ }
+ }
+ #endif
+ ReleaseInterfaceReference (ifCB);
+ ReleaseRouteReference (fwRoute);
+
+ }
+ }
+ else {
+#if DBG
+ if (Node!=NULL) {
+ IpxFwdDbgPrint (DBG_IPXROUTE, DBG_WARNING,
+ ("IpxFwd: No route for:"
+ " %08lX:%02X%02X%02X%02X%02X%02X.\n",
+ net, Node[0],Node[1],Node[2],Node[3],Node[4],Node[5]));
+ }
+ else {
+ IpxFwdDbgPrint (DBG_IPXROUTE, DBG_WARNING,
+ ("IpxFwd: No route for: %08lX.\n", net));
+ }
+#endif
+ status = STATUS_NETWORK_UNREACHABLE;
+ }
+ LeaveForwarder ();
+ return status;
+}
+
+
diff --git a/private/ntos/tdi/isn/fwd/ipxbind.h b/private/ntos/tdi/isn/fwd/ipxbind.h
new file mode 100644
index 000000000..7cf367a2b
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/ipxbind.h
@@ -0,0 +1,75 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\ipxbind.h
+
+Abstract:
+ IPX Forwarder Driver interface with IPX stack driver
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+
+#ifndef _IPXFWD_IPXBIND_
+#define _IPXFWD_IPXBIND_
+
+extern PIPX_INTERNAL_BIND_RIP_OUTPUT IPXBindOutput;
+#define IPXMacHeaderSize (IPXBindOutput->MacHeaderNeeded)
+#define IPXOpenAdapterProc (IPXBindOutput->OpenAdapterHandler)
+#define IPXCloseAdapterProc (IPXBindOutput->CloseAdapterHandler)
+#define IPXInternalSendCompletProc (IPXBindOutput->InternalSendCompleteHandler)
+#define IPXSendProc (IPXBindOutput->SendHandler)
+#define IPXTransferData (IPXBindOutput->TransferDataHandler)
+
+
+/*++
+*******************************************************************
+ B i n d T o I p x D r i v e r
+
+Routine Description:
+ Exchanges binding information with IPX stack driver
+Arguments:
+Return Value:
+ STATUS_SUCCESS - exchange was done OK
+ STATUS_INSUFFICIENT_RESOURCES - could not allocate buffers for
+ info exchange
+ error status returned by IPX stack driver
+
+*******************************************************************
+--*/
+NTSTATUS
+BindToIpxDriver (
+ KPROCESSOR_MODE requestorMode
+ );
+
+
+/*++
+*******************************************************************
+ U n b i n d T o I p x D r i v e r
+
+Routine Description:
+ Closes connection to IPX stack driver
+Arguments:
+ None
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+UnbindFromIpxDriver (
+ KPROCESSOR_MODE requestorMode
+ );
+
+
+#endif
+
diff --git a/private/ntos/tdi/isn/fwd/lineind.c b/private/ntos/tdi/isn/fwd/lineind.c
new file mode 100644
index 000000000..e00518d6a
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/lineind.c
@@ -0,0 +1,323 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\lineind.c
+
+Abstract:
+ Processing line indication (bind/unbind)
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+
+
+/*++
+*******************************************************************
+ B i n d I n t e r f a c e
+
+Routine Description:
+ Binds interface to physical adapter and exchanges contexts
+ with IPX stack
+Arguments:
+ ifCB - interface to bind
+ NicId - id of an adapter
+ MaxPacketSize - max size of packet allowed
+ Network - adapter network address
+ LocalNode - adapter local node address
+ RemoteNode - peer node address (for clients on global
+ net)
+Return Value:
+ STATUS_SUCCESS - interface was bound OK
+ error status returned by IPX stack driver
+
+*******************************************************************
+--*/
+NTSTATUS
+BindInterface (
+ IN PINTERFACE_CB ifCB,
+ IN USHORT NicId,
+ IN ULONG MaxPacketSize,
+ IN ULONG Network,
+ IN PUCHAR LocalNode,
+ IN PUCHAR RemoteNode
+ ) {
+ KIRQL oldIRQL;
+ NTSTATUS status;
+ NIC_HANDLE NicHandle={0};
+
+ KeAcquireSpinLock (&ifCB->ICB_Lock, &oldIRQL);
+ if (ifCB->ICB_Stats.OperationalState!=FWD_OPER_STATE_UP) {
+ switch (ifCB->ICB_InterfaceType) {
+ case FWD_IF_PERMANENT:
+ if (ifCB->ICB_Index!=FWD_INTERNAL_INTERFACE_INDEX)
+ status = RegisterPacketConsumer (MaxPacketSize,
+ &ifCB->ICB_PacketListId);
+ else
+ status = STATUS_SUCCESS;
+ break;
+ case FWD_IF_DEMAND_DIAL:
+ case FWD_IF_LOCAL_WORKSTATION:
+ case FWD_IF_REMOTE_WORKSTATION:
+ if (IS_IF_CONNECTING (ifCB)) {
+ SET_IF_NOT_CONNECTING (ifCB);
+ DequeueConnectionRequest (ifCB);
+ }
+ status = STATUS_SUCCESS;
+ break;
+ default:
+ ASSERTMSG ("Invalid interface type ", FALSE);
+ break;
+ }
+ if (NT_SUCCESS (status)) {
+ if (Network==GlobalNetwork) {
+ ASSERT (ifCB->ICB_Index!=FWD_INTERNAL_INTERFACE_INDEX);
+ IPX_NODE_CPY (ifCB->ICB_RemoteNode, RemoteNode);
+ status = AddGlobalNetClient (ifCB);
+ ASSERT (status==STATUS_SUCCESS);
+ }
+ KeReleaseSpinLock (&ifCB->ICB_Lock, oldIRQL);
+
+ if (ifCB->ICB_Index!=FWD_INTERNAL_INTERFACE_INDEX) {
+ NIC_HANDLE_FROM_NIC(NicHandle, NicId);
+ status = IPXOpenAdapterProc (NicHandle, (ULONG)ifCB,
+ &ifCB->ICB_AdapterContext);
+ }
+
+ if (NT_SUCCESS (status)) {
+ ifCB->ICB_Network = Network;
+ IPX_NODE_CPY (ifCB->ICB_RemoteNode, RemoteNode);
+ IPX_NODE_CPY (ifCB->ICB_LocalNode, LocalNode);
+ if (ifCB->ICB_InterfaceType==FWD_IF_PERMANENT)
+ ifCB->ICB_Stats.MaxPacketSize = MaxPacketSize;
+ else
+ ifCB->ICB_Stats.MaxPacketSize = WAN_PACKET_SIZE;
+ ifCB->ICB_NicId = NicId;
+ ifCB->ICB_Stats.OperationalState = FWD_OPER_STATE_UP;
+
+ AcquireInterfaceReference (ifCB);
+ IpxFwdDbgPrint (DBG_LINEIND, DBG_INFORMATION,
+ ("IpxFwd: Bound interface %ld (icb: %08lx):"
+ " Nic-%d, Net-%08lx,"
+ " LocalNode-%02x%02x%02x%02x%02x%02x,"
+ " RemoteNode-%02x%02x%02x%02x%02x%02x.\n",
+ ifCB->ICB_Index, ifCB, NicId, Network,
+ LocalNode[0], LocalNode[1], LocalNode[2],
+ LocalNode[3], LocalNode[4], LocalNode[5],
+ RemoteNode[0], RemoteNode[1], RemoteNode[2],
+ RemoteNode[3], RemoteNode[4], RemoteNode[5]));
+
+ if (ifCB->ICB_Index!=FWD_INTERNAL_INTERFACE_INDEX) {
+ ProcessInternalQueue (ifCB);
+ ProcessExternalQueue (ifCB);
+ }
+ return STATUS_SUCCESS;
+ }
+
+ IpxFwdDbgPrint (DBG_LINEIND, DBG_ERROR,
+ ("IpxFwd: Could not open adapter %d to bind"
+ " interface %ld (icb: %08lx)!\n",
+ NicId, ifCB->ICB_Index, ifCB));
+
+ KeAcquireSpinLock (&ifCB->ICB_Lock, &oldIRQL);
+ if (Network==GlobalNetwork) {
+ DeleteGlobalNetClient (ifCB);
+ }
+
+ switch (ifCB->ICB_InterfaceType) {
+ case FWD_IF_PERMANENT:
+ DeregisterPacketConsumer (ifCB->ICB_PacketListId);
+ break;
+ case FWD_IF_DEMAND_DIAL:
+ case FWD_IF_LOCAL_WORKSTATION:
+ case FWD_IF_REMOTE_WORKSTATION:
+ break;
+ }
+ }
+ ifCB->ICB_Stats.OperationalState = FWD_OPER_STATE_DOWN;
+ KeReleaseSpinLock (&ifCB->ICB_Lock, oldIRQL);
+
+ ProcessInternalQueue (ifCB);
+ ProcessExternalQueue (ifCB);
+ }
+ else {
+ ASSERT (Network==ifCB->ICB_Network);
+ ASSERT (NicId==(USHORT)ifCB->ICB_AdapterContext.NicId);
+ KeReleaseSpinLock (&ifCB->ICB_Lock, oldIRQL);
+ status = STATUS_SUCCESS; // Report success if already
+ // connected
+ IpxFwdDbgPrint (DBG_LINEIND, DBG_WARNING,
+ ("IpxFwd: Interface %ld (icb: %08lx) is already bound to Nic %d.\n",
+ ifCB->ICB_Index, ifCB, NicId));
+ }
+ return status;
+}
+
+
+/*++
+*******************************************************************
+ U n b i n d I n t e r f a c e
+
+Routine Description:
+ Unbinds interface from physical adapter and breaks connection
+ with IPX stack
+Arguments:
+ ifCB - interface to unbind
+Return Value:
+ None
+*******************************************************************
+--*/
+VOID
+UnbindInterface (
+ PINTERFACE_CB ifCB
+ ) {
+ KIRQL oldIRQL;
+ KeAcquireSpinLock (&ifCB->ICB_Lock, &oldIRQL);
+ if (ifCB->ICB_Stats.OperationalState==FWD_OPER_STATE_UP) {
+ switch (ifCB->ICB_InterfaceType) {
+ case FWD_IF_PERMANENT:
+ ifCB->ICB_Stats.OperationalState = FWD_OPER_STATE_DOWN;
+ if (ifCB->ICB_Index!=FWD_INTERNAL_INTERFACE_INDEX)
+ DeregisterPacketConsumer (ifCB->ICB_PacketListId);
+ break;
+ case FWD_IF_DEMAND_DIAL:
+ case FWD_IF_LOCAL_WORKSTATION:
+ case FWD_IF_REMOTE_WORKSTATION:
+ ifCB->ICB_Stats.OperationalState = FWD_OPER_STATE_SLEEPING;
+ KeQuerySystemTime ((PLARGE_INTEGER)&ifCB->ICB_DisconnectTime);
+ break;
+ default:
+ ASSERTMSG ("Invalid interface type ", FALSE);
+ break;
+ }
+ if (ifCB->ICB_CashedInterface!=NULL)
+ ReleaseInterfaceReference (ifCB->ICB_CashedInterface);
+ ifCB->ICB_CashedInterface = NULL;
+ if (ifCB->ICB_CashedRoute!=NULL)
+ ReleaseRouteReference (ifCB->ICB_CashedRoute);
+ ifCB->ICB_CashedRoute = NULL;
+ if (ifCB->ICB_Network==GlobalNetwork)
+ DeleteGlobalNetClient (ifCB);
+ KeReleaseSpinLock (&ifCB->ICB_Lock, oldIRQL);
+
+ IpxFwdDbgPrint (DBG_LINEIND, DBG_INFORMATION,
+ ("IpxFwd: Unbinding interface %ld (icb: %08lx) from Nic %ld.\n",
+ ifCB->ICB_Index, ifCB, ifCB->ICB_AdapterContext));
+ if (ifCB->ICB_Index!=FWD_INTERNAL_INTERFACE_INDEX) {
+ IPXCloseAdapterProc (ifCB->ICB_AdapterContext);
+ ProcessInternalQueue (ifCB);
+ ProcessExternalQueue (ifCB);
+ }
+ ReleaseInterfaceReference (ifCB);
+ }
+ else {
+ KeReleaseSpinLock (&ifCB->ICB_Lock, oldIRQL);
+ IpxFwdDbgPrint (DBG_LINEIND, DBG_WARNING,
+ ("IpxFwd: Interface %ld (icb: %08lx) is already unbound.\n",
+ ifCB->ICB_Index, ifCB));
+ }
+}
+
+
+
+/*++
+*******************************************************************
+ F w L i n e U p
+
+Routine Description:
+ Process line up indication delivered by IPX stack
+Arguments:
+ NicId - adapter ID on which connection was established
+ LineInfo - NDIS/IPX line information
+ DeviceType - medium specs
+ ConfigurationData - IPX CP configuration data
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+IpxFwdLineUp (
+ IN USHORT NicId,
+ IN PIPX_LINE_INFO LineInfo,
+ IN NDIS_MEDIUM DeviceType,
+ IN PVOID ConfigurationData
+ ) {
+ PINTERFACE_CB ifCB;
+ if (ConfigurationData==NULL) // This is just an update for multilink
+ // connections
+ return;
+
+ if (!EnterForwarder()) {
+ return;
+ }
+ IpxFwdDbgPrint (DBG_LINEIND, DBG_INFORMATION, ("IpxFwd: FwdLineUp.\n"));
+
+ ifCB = GetInterfaceReference (
+ ((PIPXCP_CONFIGURATION)ConfigurationData)->InterfaceIndex);
+ if (ifCB!=NULL) {
+ LONG Net = GETULONG (((PIPXCP_CONFIGURATION)ConfigurationData)->Network);
+
+ ASSERT (ifCB->ICB_Index!=FWD_INTERNAL_INTERFACE_INDEX);
+ ASSERT (ifCB->ICB_InterfaceType!=FWD_IF_PERMANENT);
+
+ BindInterface (ifCB,
+ NicId,
+ LineInfo->MaximumPacketSize,
+ Net,
+ ((PIPXCP_CONFIGURATION)ConfigurationData)->LocalNode,
+ ((PIPXCP_CONFIGURATION)ConfigurationData)->RemoteNode
+ );
+ ReleaseInterfaceReference (ifCB);
+ }
+ LeaveForwarder ();
+}
+
+
+
+
+/*++
+*******************************************************************
+ F w L i n e D o w n
+
+Routine Description:
+ Process line down indication delivered by IPX stack
+Arguments:
+ NicId - disconnected adapter ID
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+IpxFwdLineDown (
+ IN USHORT NicId,
+ IN ULONG Context
+ ) {
+ PINTERFACE_CB ifCB;
+
+ if (!EnterForwarder()) {
+ return;
+ }
+ IpxFwdDbgPrint (DBG_LINEIND, DBG_INFORMATION, ("IpxFwd: FwdLineDown.\n"));
+
+
+ ifCB = InterfaceContextToReference ((PVOID)Context, NicId);
+ if (ifCB!=NULL) {
+ ASSERT (ifCB->ICB_Index!=FWD_INTERNAL_INTERFACE_INDEX);
+ ASSERT (ifCB->ICB_InterfaceType!=FWD_IF_PERMANENT);
+ UnbindInterface (ifCB);
+ ReleaseInterfaceReference (ifCB);
+ }
+ LeaveForwarder ();
+}
+
diff --git a/private/ntos/tdi/isn/fwd/lineind.h b/private/ntos/tdi/isn/fwd/lineind.h
new file mode 100644
index 000000000..bbc8df7ac
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/lineind.h
@@ -0,0 +1,116 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\lineind.h
+
+Abstract:
+ Processing line indication (bind/unbind)
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+#ifndef _IPXFWD_LINEIND_
+#define _IPXFWD_LINEIND_
+
+/*++
+*******************************************************************
+ B i n d I n t e r f a c e
+
+Routine Description:
+ Binds interface to physical adapter and exchanges contexts
+ with IPX stack
+Arguments:
+ ifCB - interface to bind
+ NicId - id of an adapter
+ MaxPacketSize - max size of packet allowed
+ Network - adapter network address
+ LocalNode - adapter local node address
+ RemoteNode - peer node address (for clients on global
+ net)
+Return Value:
+ STATUS_SUCCESS - interface was bound OK
+ error status returned by IPX stack driver
+
+*******************************************************************
+--*/
+NTSTATUS
+BindInterface (
+ IN PINTERFACE_CB ifCB,
+ IN USHORT NicId,
+ IN ULONG MaxPacketSize,
+ IN ULONG Network,
+ IN PUCHAR LocalNode,
+ IN PUCHAR RemoteNode
+ );
+
+/*++
+*******************************************************************
+ U n b i n d I n t e r f a c e
+
+Routine Description:
+ Unbinds interface from physical adapter and breaks connection
+ with IPX stack
+Arguments:
+ ifCB - interface to unbind
+Return Value:
+ None
+*******************************************************************
+--*/
+VOID
+UnbindInterface (
+ PINTERFACE_CB ifCB
+ );
+
+/*++
+*******************************************************************
+ F w L i n e U p
+
+Routine Description:
+ Process line up indication delivered by IPX stack
+Arguments:
+ NicId - adapter ID on which connection was established
+ LineInfo - NDIS/IPX line information
+ DeviceType - medium specs
+ ConfigurationData - IPX CP configuration data
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+IpxFwdLineUp (
+ IN USHORT NicId,
+ IN PIPX_LINE_INFO LineInfo,
+ IN NDIS_MEDIUM DeviceType,
+ IN PVOID ConfigurationData
+ );
+
+/*++
+*******************************************************************
+ F w L i n e D o w n
+
+Routine Description:
+ Process line down indication delivered by IPX stack
+Arguments:
+ NicId - disconnected adapter ID
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+IpxFwdLineDown (
+ IN USHORT NicId,
+ IN ULONG Context
+ );
+
+#endif
diff --git a/private/ntos/tdi/isn/fwd/mp/makefile b/private/ntos/tdi/isn/fwd/mp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/mp/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isn/fwd/mp/sources b/private/ntos/tdi/isn/fwd/mp/sources
new file mode 100644
index 000000000..dc48d81bb
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/mp/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+NT_UP=0
+
+TARGETPATH=\nt\public\sdk\lib
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/isn/fwd/netbios.c b/private/ntos/tdi/isn/fwd/netbios.c
new file mode 100644
index 000000000..4a1f9b84b
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/netbios.c
@@ -0,0 +1,311 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\netbios.c
+
+Abstract:
+ Netbios packet processing
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+#include "precomp.h"
+
+LIST_ENTRY NetbiosQueue;
+KSPIN_LOCK NetbiosQueueLock;
+WORK_QUEUE_ITEM NetbiosWorker;
+BOOLEAN NetbiosWorkerScheduled=FALSE;
+ULONG NetbiosPacketsQuota;
+ULONG MaxNetbiosPacketsQueued = DEF_MAX_NETBIOS_PACKETS_QUEUED;
+
+
+/*++
+*******************************************************************
+ P r o c e s s N e t b i o s Q u e u e
+
+Routine Description:
+ Process packets in the netbios broadcast queue (sends them on
+ all interfaces in sequence)
+Arguments:
+ Context - unused
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+ProcessNetbiosQueue (
+ PVOID Context
+ ) {
+ KIRQL oldIRQL;
+ LIST_ENTRY tempQueue;
+
+ KeAcquireSpinLock (&NetbiosQueueLock, &oldIRQL);
+ // Check if there is something in the queue
+ if (!IsListEmpty (&NetbiosQueue)) {
+ // Move the queue to local variable
+ InsertHeadList (&NetbiosQueue, &tempQueue);
+ RemoveEntryList (&NetbiosQueue);
+ InitializeListHead (&NetbiosQueue);
+
+ KeReleaseSpinLock (&NetbiosQueueLock, oldIRQL);
+ do {
+ PLIST_ENTRY cur;
+ PPACKET_TAG pktTag;
+
+ cur = RemoveHeadList (&tempQueue);
+ pktTag = CONTAINING_RECORD (cur, PACKET_TAG, PT_QueueLink);
+ // Check if this packet has to be sent on other
+ // interfaces
+ if (!(pktTag->PT_Flags&PT_NB_DESTROY)) {
+ PINTERFACE_CB dstIf = pktTag->PT_InterfaceReference;
+ PUCHAR dataPtr = pktTag->PT_Data;
+ UINT rtCount = *(dataPtr+IPXH_XPORTCTL);
+ PUCHAR netListPtr;
+ UINT i;
+
+ if (dstIf==NULL) {
+ // This is a brand new packet: not sent on any
+ // interface yet
+ USHORT dstSock = GETUSHORT (dataPtr+IPXH_DESTSOCK);
+ // Check if we have a static route for this name
+ // (offset to name depends on packet dest socket)
+ if (dstSock==IPX_NETBIOS_SOCKET)
+ dstIf = FindNBDestination (dataPtr+NB_NAME);
+ else if (dstSock==IPX_SMB_NAME_SOCKET)
+ dstIf = FindNBDestination (dataPtr+SMB_NAME);
+ else
+ dstIf = NULL;
+
+ if (dstIf!=NULL) {
+ // Static route found, make sure this packet
+ // won't be sent on any other interface
+ pktTag->PT_Flags |= PT_NB_DESTROY;
+ InterlockedIncrement (&NetbiosPacketsQuota);
+ // Make sure the packet has not traversed
+ // this network already
+ for (i=0, netListPtr=dataPtr+IPXH_HDRSIZE; i<rtCount; i++,netListPtr+=4) {
+ if (GETULONG (netListPtr)==dstIf->ICB_Network)
+ break;
+ }
+ // Make sure we are allowed to send on this
+ // interface
+ if ((dstIf!=InternalInterface)
+ && (i==rtCount) // Has not already traversed
+ // this network
+ && IS_IF_ENABLED (dstIf)
+ && ((dstIf->ICB_NetbiosDeliver==FWD_NB_DELIVER_ALL)
+ || (dstIf->ICB_NetbiosDeliver
+ ==FWD_NB_DELIVER_STATIC)
+ || ((dstIf->ICB_NetbiosDeliver
+ ==FWD_NB_DELIVER_IF_UP)
+ && (dstIf->ICB_Stats.OperationalState
+ ==FWD_OPER_STATE_UP)))) {
+ NOTHING;
+ }
+ else {
+ // We have static route, but can't send it,
+ // no point to propagate in on other interfaces
+ // as well
+ ReleaseInterfaceReference (dstIf);
+ dstIf = NULL;
+ goto FreePacket;
+ }
+ }
+ else { // no static route
+ goto FindNextInterface;
+ }
+ }
+ else { // not a brand new packet (already sent on some
+ // interfaces)
+
+ FindNextInterface:
+
+ // Loop through the interface list till we find
+ // the one on which we can send
+ while ((dstIf=GetNextInterfaceReference (dstIf))!=NULL) {
+ // Check if we allowed to send on this interface
+ if (IS_IF_ENABLED (dstIf)
+ && ((dstIf->ICB_NetbiosDeliver==FWD_NB_DELIVER_ALL)
+ || ((dstIf->ICB_NetbiosDeliver
+ ==FWD_NB_DELIVER_IF_UP)
+ && (dstIf->ICB_Stats.OperationalState
+ ==FWD_OPER_STATE_UP)))) {
+ // Make sure the packet has not traversed
+ // this network already
+ for (i=0, netListPtr=dataPtr+IPXH_HDRSIZE; i<rtCount; i++,netListPtr+=4) {
+ if (GETULONG (netListPtr)==dstIf->ICB_Network)
+ break;
+ }
+ // Network was not in the list
+ if (i==rtCount)
+ break;
+ }
+ }
+ }
+ // Save the destination interface in the packet
+ pktTag->PT_InterfaceReference = dstIf;
+ // Go ahead and send if we have a valid destination
+ if (dstIf!=NULL) {
+ SendPacket (dstIf, pktTag);
+ // The rest does not apply: if the packet was sent or
+ // failed, it will be queued back to NetbiosQueue;
+ // if it was queued to interface to be connected,
+ // a copy of it will be queued to NetbiosQueue
+ continue;
+ }
+ // else no more destinations to send this packet on
+ }
+ else { // Packet has to be destroyed
+ if (pktTag->PT_InterfaceReference!=NULL)
+ ReleaseInterfaceReference (pktTag->PT_InterfaceReference);
+ }
+
+ FreePacket:
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
+ ("IpxFwd: No more interfaces for nb packet %08lx.\n",
+ pktTag));
+ if (MeasuringPerformance
+ && (pktTag->PT_PerfCounter!=0)) {
+ LARGE_INTEGER PerfCounter = KeQueryPerformanceCounter (NULL);
+ PerfCounter.QuadPart -= pktTag->PT_PerfCounter;
+ KeAcquireSpinLock (&PerfCounterLock, &oldIRQL);
+ PerfBlock.TotalNbPacketProcessingTime += PerfCounter.QuadPart;
+ PerfBlock.NbPacketCounter += 1;
+ if (PerfBlock.MaxNbPacketProcessingTime < PerfCounter.QuadPart)
+ PerfBlock.MaxNbPacketProcessingTime = PerfCounter.QuadPart;
+ KeReleaseSpinLock (&PerfCounterLock, oldIRQL);
+ }
+ if (!(pktTag->PT_Flags&PT_NB_DESTROY))
+ InterlockedIncrement (&NetbiosPacketsQuota);
+ FreePacket (pktTag);
+ } while (!IsListEmpty (&tempQueue));
+
+ KeAcquireSpinLock (&NetbiosQueueLock, &oldIRQL);
+ if (IsListEmpty (&NetbiosQueue)
+ || !EnterForwarder ()) {
+ NetbiosWorkerScheduled = FALSE;
+ }
+ else {
+ ExQueueWorkItem (&NetbiosWorker, DelayedWorkQueue);
+ }
+ }
+ KeReleaseSpinLock (&NetbiosQueueLock, oldIRQL);
+ LeaveForwarder ();
+}
+
+/*++
+*******************************************************************
+ P r o c e s s N e t b i o s P a c k e t
+
+Routine Description:
+ Processes received netbios broadcast packet (checks network list
+ and source filter, updates input statistics)
+Arguments:
+ srcIf - interfae on which packet was received
+ pktTag - netbios packet
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+ProcessNetbiosPacket (
+ PINTERFACE_CB srcIf,
+ PPACKET_TAG pktTag
+ ) {
+ PUCHAR dataPtr;
+ UINT rtCount;
+ UINT i;
+ KIRQL oldIRQL;
+
+
+ dataPtr = pktTag->PT_Data;
+ rtCount = *(dataPtr+IPXH_XPORTCTL);
+
+ // Check if source network is already in the packet network list
+ for (i=0, dataPtr+=IPXH_HDRSIZE; i<rtCount; i++, dataPtr+=4) {
+ if (srcIf->ICB_Network==GETULONG (dataPtr))
+ break;
+ }
+ // We scaned the whole list and we haven't found it
+ if (i==rtCount) {
+ FILTER_ACTION action;
+ action = FltFilter (pktTag->PT_Data,
+ GETUSHORT (pktTag->PT_Data+IPXH_LENGTH),
+ srcIf->ICB_FilterInContext, NULL);
+ // Apply the input filter
+ if (action==FILTER_PERMIT) {
+ InterlockedIncrement (&srcIf->ICB_Stats.NetbiosReceived);
+ InterlockedIncrement (&srcIf->ICB_Stats.InDelivers);
+ PUTULONG (srcIf->ICB_Network, dataPtr);
+ *(pktTag->PT_Data+IPXH_XPORTCTL) += 1;
+ IPX_NODE_CPY (pktTag->PT_Target.MacAddress, BROADCAST_NODE);
+ // Initialize the packet
+ pktTag->PT_InterfaceReference = NULL; // not yet sent on any
+ // interfaces
+ pktTag->PT_Flags = 0; // No flags
+ QueueNetbiosPacket (pktTag);
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
+ ("IpxFwd: Queued nb packet %08lx from if %ld.\n",
+ pktTag, srcIf->ICB_Index));
+ }
+ else {
+ ASSERT (action==FILTER_DENY_IN);
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_WARNING,
+ ("IpxFwd: Filtered out nb packet %08lx"
+ " from if %ld.\n", pktTag, srcIf->ICB_Index));
+ InterlockedIncrement (&NetbiosPacketsQuota);
+ InterlockedIncrement (&srcIf->ICB_Stats.InFiltered);
+ FreePacket (pktTag);
+ }
+ }
+ else {
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_WARNING,
+ ("IpxFwd: Source net is already in nb packet %08lx"
+ " from if %ld.\n", pktTag, srcIf->ICB_Index));
+ InterlockedIncrement (&NetbiosPacketsQuota);
+ InterlockedIncrement (&srcIf->ICB_Stats.InDiscards);
+ FreePacket (pktTag);
+ }
+ ReleaseInterfaceReference (srcIf);
+
+}
+
+
+/*++
+*******************************************************************
+ D e l e t e N e t b i o s Q u e u e
+
+Routine Description:
+ Deletes the netbios bradcast queue
+Arguments:
+ None
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+DeleteNetbiosQueue (
+ void
+ ) {
+ while (!IsListEmpty (&NetbiosQueue)) {
+ PPACKET_TAG pktTag = CONTAINING_RECORD (NetbiosQueue.Flink,
+ PACKET_TAG,
+ PT_QueueLink);
+ RemoveEntryList (&pktTag->PT_QueueLink);
+ if (pktTag->PT_InterfaceReference!=NULL) {
+ ReleaseInterfaceReference (pktTag->PT_InterfaceReference);
+ }
+ FreePacket (pktTag);
+ }
+}
+
diff --git a/private/ntos/tdi/isn/fwd/netbios.h b/private/ntos/tdi/isn/fwd/netbios.h
new file mode 100644
index 000000000..ffa6da1c4
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/netbios.h
@@ -0,0 +1,134 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\netbios.h
+
+Abstract:
+ Netbios packet processing
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+#ifndef IPXFWD_NETBIOS
+#define IPXFWD_NETBIOS
+
+extern LIST_ENTRY NetbiosQueue;
+extern KSPIN_LOCK NetbiosQueueLock;
+extern WORK_QUEUE_ITEM NetbiosWorker;
+extern BOOLEAN NetbiosWorkerScheduled;
+extern ULONG NetbiosPacketsQuota;
+extern ULONG MaxNetbiosPacketsQueued;
+#define DEF_MAX_NETBIOS_PACKETS_QUEUED 256
+
+
+/*++
+*******************************************************************
+ I n i t i a l i z e N e t b i o s Q u e u e
+
+Routine Description:
+ Initializes the netbios bradcast queue
+Arguments:
+ None
+Return Value:
+ None
+
+*******************************************************************
+--*/
+//VOID
+//InitializeNetbiosQueue (
+// void
+// )
+#define InitializeNetbiosQueue() { \
+ InitializeListHead (&NetbiosQueue); \
+ KeInitializeSpinLock (&NetbiosQueueLock); \
+ ExInitializeWorkItem (&NetbiosWorker, &ProcessNetbiosQueue, NULL);\
+ NetbiosWorkerScheduled = FALSE; \
+ NetbiosPacketsQuota = MaxNetbiosPacketsQueued; \
+}
+
+/*++
+*******************************************************************
+ D e l e t e N e t b i o s Q u e u e
+
+Routine Description:
+ Deletes the netbios bradcast queue
+Arguments:
+ None
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+DeleteNetbiosQueue (
+ void
+ );
+
+
+/*++
+*******************************************************************
+ P r o c e s s N e t b i o s Q u e u e
+
+Routine Description:
+ Process packets in the netbios bradcast queue
+Arguments:
+ Context - unused
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+ProcessNetbiosQueue (
+ PVOID Context
+ );
+
+/*++
+*******************************************************************
+ P r o c e s s N e t b i o s P a c k e t
+
+Routine Description:
+ Processes received netbios broadcast packet
+Arguments:
+ None
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+ProcessNetbiosPacket (
+ PINTERFACE_CB srcIf,
+ PPACKET_TAG pktTag
+ );
+
+
+#define QueueNetbiosPacket(pktTag) { \
+ KIRQL oldIRQL; \
+ KeAcquireSpinLock (&NetbiosQueueLock, &oldIRQL); \
+ InsertTailList (&NetbiosQueue, &pktTag->PT_QueueLink); \
+ KeReleaseSpinLock (&NetbiosQueueLock, oldIRQL); \
+}
+
+#define ScheduleNetbiosWorker() { \
+ KIRQL oldIRQL; \
+ KeAcquireSpinLock (&NetbiosQueueLock, &oldIRQL); \
+ if (!NetbiosWorkerScheduled \
+ && !IsListEmpty (&NetbiosQueue) \
+ && EnterForwarder ()) { \
+ NetbiosWorkerScheduled = TRUE; \
+ ExQueueWorkItem (&NetbiosWorker, DelayedWorkQueue); \
+ } \
+ KeReleaseSpinLock (&NetbiosQueueLock, oldIRQL); \
+}
+
+#endif
+
diff --git a/private/ntos/tdi/isn/fwd/nwlnkfwd.rc b/private/ntos/tdi/isn/fwd/nwlnkfwd.rc
new file mode 100644
index 000000000..477fd6e01
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/nwlnkfwd.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "NWLINK2 Forwarder Driver"
+#define VER_INTERNALNAME_STR "nwlnkfwd.sys"
+#define VER_ORIGINALFILENAME_STR "nwlnkfwd.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/tdi/isn/fwd/packets.c b/private/ntos/tdi/isn/fwd/packets.c
new file mode 100644
index 000000000..9577a6d2c
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/packets.c
@@ -0,0 +1,528 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\packets.c
+
+Abstract:
+ IPX Forwarder Driver packet allocator
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+
+ULONG RcvPktsPerSegment = DEF_RCV_PKTS_PER_SEGMENT;
+ULONG MaxRcvPktsPoolSize =0;
+ULONG RcvPktsPoolSize = 0;
+KSPIN_LOCK AllocatorLock;
+const LONGLONG SegmentTimeout = -10i64*10000000i64;
+
+SEGMENT_LIST ListEther={1500};
+SEGMENT_LIST ListTR4={4500};
+SEGMENT_LIST ListTR16={17986};
+
+PSEGMENT_LIST SegmentMap[FRAME_SIZE_VARIATIONS][FRAME_SIZE_VARIATIONS] = {
+ {&ListEther, &ListEther, &ListEther},
+ {&ListEther, &ListTR4, &ListTR4},
+ {&ListEther, &ListTR4, &ListTR16}
+};
+
+VOID
+AllocationWorker (
+ PVOID Context
+ );
+
+VOID
+SegmentTimeoutDpc (
+ PKDPC dpc,
+ PVOID Context,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2
+ );
+
+/*++
+*******************************************************************
+ C r e a t e S e g m e n t
+
+Routine Description:
+ Allocates and initializes packet segment
+Arguments:
+ list - segment list to which new segment will be added
+Return Value:
+ Pointer to allocated segment, NULL if fails
+
+*******************************************************************
+--*/
+PPACKET_SEGMENT
+CreateSegment (
+ PSEGMENT_LIST list
+ ) {
+ KIRQL oldIRQL;
+ NDIS_STATUS status;
+ PPACKET_SEGMENT segment;
+ ULONG segmentsize = list->SL_BlockCount*list->SL_BlockSize
+ +FIELD_OFFSET(PACKET_SEGMENT,PS_Buffers);
+ if (MaxRcvPktsPoolSize!=0) {
+ // Check if this allocation would exceed the limit
+ KeAcquireSpinLock (&AllocatorLock, &oldIRQL);
+ if (RcvPktsPoolSize+segmentsize<MaxRcvPktsPoolSize) {
+ RcvPktsPoolSize += segmentsize;
+ KeReleaseSpinLock (&AllocatorLock, oldIRQL);
+ }
+ else {
+ KeReleaseSpinLock (&AllocatorLock, oldIRQL);
+ return NULL;
+ }
+ }
+
+ // Allocate chunk of memory to hold segment header and buffers
+ segment = ExAllocatePoolWithTag (
+ NonPagedPool,
+ segmentsize,
+ FWD_POOL_TAG);
+ if (segment!=NULL) {
+ segment->PS_SegmentList = list;
+ segment->PS_FreeHead = NULL;
+ segment->PS_BusyCount = 0;
+ KeQuerySystemTime ((PLARGE_INTEGER)&segment->PS_FreeStamp);
+ NdisAllocatePacketPool (
+ &status,
+ &segment->PS_PacketPool,
+ list->SL_BlockCount,
+ IPXMacHeaderSize
+ +FIELD_OFFSET (PACKET_TAG, PT_MacHeader));
+ if (status==NDIS_STATUS_SUCCESS) {
+ NdisAllocateBufferPool (
+ &status,
+ &segment->PS_BufferPool,
+ list->SL_BlockCount*2);
+ if (status==NDIS_STATUS_SUCCESS) {
+ PUCHAR bufferptr = segment->PS_Buffers;
+ PNDIS_PACKET packetDscr;
+ PNDIS_BUFFER bufferDscr;
+ PPACKET_TAG packetTag;
+ ULONG i;
+
+ for (i=0; i<list->SL_BlockCount; i++,
+ bufferptr+=list->SL_BlockSize) {
+ NdisAllocatePacket (
+ &status,
+ &packetDscr,
+ segment->PS_PacketPool);
+ ASSERT (status==NDIS_STATUS_SUCCESS);
+
+ packetTag = (PPACKET_TAG)packetDscr->ProtocolReserved;
+ packetTag->PT_Segment = segment;
+ packetTag->PT_Data = bufferptr;
+ packetTag->PT_InterfaceReference = NULL;
+
+ NdisAllocateBuffer (
+ &status,
+ &packetTag->PT_MacHdrBufDscr,
+ segment->PS_BufferPool,
+ packetTag->PT_MacHeader,
+ IPXMacHeaderSize);
+ ASSERT (status==NDIS_STATUS_SUCCESS);
+
+ NdisAllocateBuffer (
+ &status,
+ &bufferDscr,
+ segment->PS_BufferPool,
+ bufferptr,
+ list->SL_BlockSize);
+ ASSERT (status==NDIS_STATUS_SUCCESS);
+ NdisChainBufferAtFront (packetDscr, bufferDscr);
+
+ packetTag->PT_Next = segment->PS_FreeHead;
+ segment->PS_FreeHead = packetTag;
+ }
+ IpxFwdDbgPrint (DBG_PACKET_ALLOC, DBG_WARNING,
+ ("IpxFwd: Allocated packet segment %08lx for list %ld.\n",
+ segment, list->SL_BlockSize));
+ return segment;
+ }
+ else {
+ IpxFwdDbgPrint (DBG_PACKET_ALLOC, DBG_ERROR,
+ ("IpxFwd: Failed to allocate buffer pool"
+ " for new segment in list %ld.\n",
+ list->SL_BlockSize));
+ }
+ NdisFreePacketPool (segment->PS_PacketPool);
+ }
+ else {
+ IpxFwdDbgPrint (DBG_PACKET_ALLOC, DBG_ERROR,
+ ("IpxFwd: Failed to allocate packet pool"
+ " for new segment in list %ld.\n",
+ list->SL_BlockSize));
+ }
+ ExFreePool (segment);
+ }
+ else {
+ IpxFwdDbgPrint (DBG_PACKET_ALLOC, DBG_ERROR,
+ ("IpxFwd: Failed to allocate new segment for list %ld.\n",
+ list->SL_BlockSize));
+ }
+
+ return NULL;
+}
+
+
+/*++
+*******************************************************************
+ D e l e t e S e g m e n t
+
+Routine Description:
+ Frees packet segment
+Arguments:
+ segment - segment to free
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+DeleteSegment (
+ PPACKET_SEGMENT segment
+ ) {
+ PSEGMENT_LIST list = segment->PS_SegmentList;
+
+ ASSERT (segment->PS_BusyCount == 0);
+ // Free all NDIS packet and buffer descriptors first
+ while (segment->PS_FreeHead!=NULL) {
+ PNDIS_BUFFER bufferDscr;
+ PPACKET_TAG packetTag = segment->PS_FreeHead;
+ PNDIS_PACKET packetDscr = CONTAINING_RECORD (packetTag,
+ NDIS_PACKET, ProtocolReserved);
+
+ segment->PS_FreeHead = packetTag->PT_Next;
+
+ ASSERT (packetTag->PT_MacHdrBufDscr!=NULL);
+ NdisFreeBuffer (packetTag->PT_MacHdrBufDscr);
+
+ NdisUnchainBufferAtFront (packetDscr, &bufferDscr);
+ ASSERT (bufferDscr!=NULL);
+ NdisFreeBuffer (bufferDscr);
+
+ NdisFreePacket (packetDscr);
+ }
+ NdisFreeBufferPool (segment->PS_BufferPool);
+ NdisFreePacketPool (segment->PS_PacketPool);
+
+ // Decrement memory used if we have a quota
+ if (MaxRcvPktsPoolSize!=0) {
+ KIRQL oldIRQL;
+ ULONG segmentsize = list->SL_BlockCount*list->SL_BlockSize
+ +FIELD_OFFSET(PACKET_SEGMENT,PS_Buffers);
+ KeAcquireSpinLock (&AllocatorLock, &oldIRQL);
+ RcvPktsPoolSize -= segmentsize;
+ KeReleaseSpinLock (&AllocatorLock, oldIRQL);
+ }
+ ExFreePool (segment);
+ IpxFwdDbgPrint (DBG_PACKET_ALLOC, DBG_WARNING,
+ ("IpxFwd: Deleting segment %08lx in list %ld.\n",
+ segment, list->SL_BlockSize));
+}
+
+
+/*++
+*******************************************************************
+ R e g i s t e r P a c k e t C o n s u m e r
+
+Routine Description:
+ Registers a consumer (bound interface) of packets of the
+ given size
+Arguments:
+ pktsize - maximum size of packets needed
+ listId - buffer to return packet list id where packets
+ of required size are located
+Return Value:
+ STATUS_SUCCESS - registration succeded
+ STATUS_INSUFFICIENT_RESOURCES - not enogh resources to register
+
+*******************************************************************
+--*/
+NTSTATUS
+RegisterPacketConsumer (
+ IN ULONG pktsize,
+ OUT INT *listID
+ ) {
+ NTSTATUS status=STATUS_SUCCESS;
+ KIRQL oldIRQL;
+ PSEGMENT_LIST list;
+ INT i;
+ LONG addRefCount = 1;
+
+ KeAcquireSpinLock (&AllocatorLock, &oldIRQL);
+ ASSERT (pktsize<=SegmentMap[FRAME_SIZE_VARIATIONS-1]
+ [FRAME_SIZE_VARIATIONS-1]->SL_BlockSize);
+
+ for (i=0; i<FRAME_SIZE_VARIATIONS; i++) {
+ list = SegmentMap[i][i];
+ if (pktsize<=list->SL_BlockSize) {
+ list->SL_RefCount += 1;
+ *listID = i;
+ break;
+ }
+ }
+ KeReleaseSpinLock (&AllocatorLock, oldIRQL);
+ IpxFwdDbgPrint (DBG_PACKET_ALLOC, DBG_WARNING,
+ ("IpxFwd: Registered packet consumer, pktsz: %ld, list: %ld.\n",
+ pktsize, list->SL_BlockSize));
+ return status;
+}
+
+/*++
+*******************************************************************
+ D e r e g i s t e r P a c k e t C o n s u m e r
+
+Routine Description:
+ Deregisters a consumer (bound interface) of packets of the
+ given size
+Arguments:
+ listId - packet list id used by the consumer
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+DeregisterPacketConsumer (
+ IN INT listID
+ ) {
+ KIRQL oldIRQL;
+ PSEGMENT_LIST list;
+
+ ASSERT ((listID>=0) && (listID<FRAME_SIZE_VARIATIONS));
+
+ KeAcquireSpinLock (&AllocatorLock, &oldIRQL);
+ list = SegmentMap[listID][listID];
+
+ ASSERT (list->SL_RefCount>0);
+
+ list->SL_RefCount -= 1;
+
+ KeReleaseSpinLock (&AllocatorLock, oldIRQL);
+ IpxFwdDbgPrint (DBG_PACKET_ALLOC, DBG_WARNING,
+ ("IpxFwd: Deregistered packet consumer, list: %ld.\n",
+ list->SL_BlockSize));
+
+ }
+
+/*++
+*******************************************************************
+ I n i t i a l i z e S e g m e n t L i s t
+
+Routine Description:
+ Initializes list of packet segments
+Arguments:
+ list - list to initalize
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+InitializeSegmentList(
+ PSEGMENT_LIST list
+ ) {
+ InitializeListHead (&list->SL_Head);
+ list->SL_FreeCount = 0;
+ // Make sure we don't have any leftover larger than
+ // the buffer size (kernel memory allocator
+ // allocates full pages)
+ list->SL_BlockCount =
+ (ROUND_TO_PAGES (
+ list->SL_BlockSize*RcvPktsPerSegment
+ +FIELD_OFFSET(PACKET_SEGMENT,PS_Buffers))
+ -FIELD_OFFSET(PACKET_SEGMENT,PS_Buffers))
+ /list->SL_BlockSize;
+ list->SL_LowCount = list->SL_BlockCount/2;
+ list->SL_RefCount = 0;
+ list->SL_AllocatorPending = FALSE;
+ list->SL_TimerDpcPending = FALSE;
+ KeInitializeSpinLock (&list->SL_Lock);
+ KeInitializeTimer (&list->SL_Timer);
+ KeInitializeDpc (&list->SL_TimerDpc, SegmentTimeoutDpc, list);
+ ExInitializeWorkItem (&list->SL_Allocator, AllocationWorker, list);
+}
+
+/*++
+*******************************************************************
+ D e l e t e S e g m e n t L i s t
+
+Routine Description:
+ Deletes list of packet segments
+Arguments:
+ list - list to delete
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+DeleteSegmentList (
+ PSEGMENT_LIST list
+ ) {
+ KeCancelTimer (&list->SL_Timer);
+ while (!IsListEmpty (&list->SL_Head)) {
+ PPACKET_SEGMENT segment;
+ segment = CONTAINING_RECORD (list->SL_Head.Blink,
+ PACKET_SEGMENT, PS_Link);
+
+ RemoveEntryList (&segment->PS_Link);
+ DeleteSegment (segment);
+ }
+}
+
+
+/*++
+*******************************************************************
+ S e g m e n t T i m e o u t D p c
+
+Routine Description:
+ Timer DPC that launches allocator worker to get rid of unused
+ segments
+Arguments:
+ Context - segment list to check for unused segments
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+SegmentTimeoutDpc (
+ PKDPC dpc,
+ PVOID Context,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2
+ ) {
+#define list ((PSEGMENT_LIST)Context)
+ KIRQL oldIRQL;
+ IpxFwdDbgPrint (DBG_PACKET_ALLOC, DBG_INFORMATION,
+ ("IpxFwd: Segment timed out in list: %ld.\n",
+ list->SL_BlockSize));
+ KeAcquireSpinLock (&list->SL_Lock, &oldIRQL);
+ list->SL_TimerDpcPending = FALSE;
+ if (!list->SL_AllocatorPending
+ && (list->SL_FreeCount>=list->SL_BlockCount)
+ && EnterForwarder ()) {
+ list->SL_AllocatorPending = TRUE;
+ KeReleaseSpinLock (&list->SL_Lock, oldIRQL);
+ ExQueueWorkItem (&list->SL_Allocator, DelayedWorkQueue);
+ }
+ else {
+ KeReleaseSpinLock (&list->SL_Lock, oldIRQL);
+ }
+ LeaveForwarder ();
+#undef list
+}
+
+
+/*++
+*******************************************************************
+ A l l o c a t i o n W o r k e r
+
+Routine Description:
+ Adds new segment or releases unused segments from the list
+ depending on the free packet count and time that segments
+ are not used
+Arguments:
+ Context - packet list to process
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+AllocationWorker (
+ PVOID Context
+ ) {
+#define list ((PSEGMENT_LIST)Context)
+ KIRQL oldIRQL;
+ PPACKET_SEGMENT segment = NULL;
+ LONGLONG curTime;
+
+ IpxFwdDbgPrint (DBG_PACKET_ALLOC, DBG_INFORMATION,
+ ("IpxFwd: Allocating/scavenging segment(s) in list: %ld.\n",
+ list->SL_BlockSize));
+ KeQuerySystemTime ((PLARGE_INTEGER)&curTime);
+ KeAcquireSpinLock (&list->SL_Lock, &oldIRQL);
+ list->SL_AllocatorPending = FALSE;
+ if (list->SL_FreeCount<list->SL_BlockCount) {
+ KeReleaseSpinLock (&list->SL_Lock, oldIRQL);
+ // First allocate a segment
+ segment = CreateSegment (list);
+ if (segment!=NULL) {
+ KeAcquireSpinLock (&list->SL_Lock, &oldIRQL);
+ InsertTailList (&list->SL_Head, &segment->PS_Link);
+ list->SL_FreeCount += list->SL_BlockCount;
+ if (!list->SL_TimerDpcPending
+ && EnterForwarder ()) {
+ list->SL_TimerDpcPending = TRUE;
+ KeReleaseSpinLock (&list->SL_Lock, oldIRQL);
+ KeSetTimer (&list->SL_Timer, *((PLARGE_INTEGER)&SegmentTimeout), &list->SL_TimerDpc);
+ }
+ else {
+ KeReleaseSpinLock (&list->SL_Lock, oldIRQL);
+ }
+ }
+ }
+ else {
+ // Make sure that there is either more than segment in the list
+ // or there is one and no registered users
+ if (!IsListEmpty (&list->SL_Head)) {
+ segment = CONTAINING_RECORD (list->SL_Head.Blink,
+ PACKET_SEGMENT, PS_Link);
+ // Check for all segments with no used blocks
+ // except for the last one (delete event the last
+ // one if there are no clients)
+ while ((segment->PS_BusyCount==0)
+ && ((list->SL_Head.Flink!=&segment->PS_Link)
+ || (list->SL_RefCount<=0))) {
+ LONGLONG timeDiff;
+ // Check if it has not been used for long enough
+ timeDiff = SegmentTimeout - (segment->PS_FreeStamp-curTime);
+ if (timeDiff>=0) {
+ // Delete the segment
+ RemoveEntryList (&segment->PS_Link);
+ list->SL_FreeCount -= list->SL_BlockCount;
+ KeReleaseSpinLock (&list->SL_Lock, oldIRQL);
+ DeleteSegment (segment);
+ KeAcquireSpinLock (&list->SL_Lock, &oldIRQL);
+ if (!IsListEmpty (&list->SL_Head)) {
+ segment = CONTAINING_RECORD (list->SL_Head.Blink,
+ PACKET_SEGMENT, PS_Link);
+ continue;
+ }
+ }
+ else { // Reschedule the timer otherwise
+ if (!list->SL_TimerDpcPending
+ && EnterForwarder ()) {
+ list->SL_TimerDpcPending = TRUE;
+ KeReleaseSpinLock (&list->SL_Lock, oldIRQL);
+ KeSetTimer (&list->SL_Timer,
+ *((PLARGE_INTEGER)&timeDiff),
+ &list->SL_TimerDpc);
+ goto ExitAllocator; // Spinlock is already released
+ }
+ }
+ break;
+ } // while
+ } // if (IsListEmpty)
+ KeReleaseSpinLock (&list->SL_Lock, oldIRQL);
+ }
+ExitAllocator:
+ LeaveForwarder ();
+#undef list
+}
+
+
diff --git a/private/ntos/tdi/isn/fwd/packets.h b/private/ntos/tdi/isn/fwd/packets.h
new file mode 100644
index 000000000..98de68377
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/packets.h
@@ -0,0 +1,464 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\packets.h
+
+Abstract:
+ IPX Forwarder Driver packet allocator
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+#ifndef _IPXFWD_PACKETS_
+#define _IPXFWD_PACKETS_
+
+// Forward structure prototypes
+struct _SEGMENT_LIST;
+typedef struct _SEGMENT_LIST SEGMENT_LIST, *PSEGMENT_LIST;
+struct _PACKET_SEGMENT;
+typedef struct _PACKET_SEGMENT PACKET_SEGMENT, *PPACKET_SEGMENT;
+struct _PACKET_TAG;
+typedef struct _PACKET_TAG PACKET_TAG, *PPACKET_TAG;
+
+// Forwarder data associated with each packet it allocates
+struct _PACKET_TAG {
+ union {
+ UCHAR PT_Identifier; // this should be IDENTIFIER_RIP
+ PPACKET_TAG PT_Next; // link in packet segment
+ };
+ union {
+ PVOID SEND_RESERVED[SEND_RESERVED_COMMON_SIZE]; // needed by ipx
+ // for padding on ethernet
+ PINTERFACE_CB PT_SourceIf; // Source interface reference needed
+ // for spoofing keep-alives and
+ // queuing connection requests
+ };
+ PPACKET_SEGMENT PT_Segment; // segment where it belongs
+ LONGLONG PT_PerfCounter;
+ ULONG PT_Flags;
+#define PT_NB_DESTROY 0x1 // NB packet to be not requeued
+#define PT_SOURCE_IF 0x2 // Spoofing packet with src if reference
+ PUCHAR PT_Data; // Data buffer
+ PNDIS_BUFFER PT_MacHdrBufDscr; // buffer descriptor for
+ // mac header buffer required
+ // by IPX
+ PINTERFACE_CB PT_InterfaceReference; // points to the interface CB where
+ // it is queued
+ LIST_ENTRY PT_QueueLink; // links this packet in send queue
+ IPX_LOCAL_TARGET PT_Target; // destination target for ipx
+ // stack
+ UCHAR PT_MacHeader[1];// Mac header buffer reserved for IPX
+};
+
+// Segment of preallocated packets complete with buffers
+struct _PACKET_SEGMENT {
+ LIST_ENTRY PS_Link; // Link in segment list
+ PSEGMENT_LIST PS_SegmentList; // Segment list we belong to
+ PPACKET_TAG PS_FreeHead; // List of free packets in
+ // this segment
+ ULONG PS_BusyCount; // Count of packets allocated
+ // from this segment
+ NDIS_HANDLE PS_PacketPool; // Pool of NDIS packet
+ // descriptors used by the
+ // packets in this segment
+ NDIS_HANDLE PS_BufferPool; // Pool of NDIS buffer
+ // descriptors used by the
+ // packets in this segment
+ LONGLONG PS_FreeStamp; // Time when last packet was freed
+ union {
+ UCHAR PS_Buffers[1]; // Memory used by buffers
+ LONGLONG PS_BuffersAlign;
+ };
+};
+
+
+// List of segment with preallocated packets
+struct _SEGMENT_LIST {
+ const ULONG SL_BlockSize; // Size of packet's buffer
+ LIST_ENTRY SL_Head; // Head of the segment list
+ ULONG SL_FreeCount; // Total number of free packets
+ // in all segment in the list
+ ULONG SL_BlockCount; // Number of packets per segment
+ ULONG SL_LowCount; // Free count at which we
+ // will preallocate new segment
+ LONG SL_RefCount; // Number of consumers that are
+ // using packets in this list
+ BOOLEAN SL_TimerDpcPending;
+ BOOLEAN SL_AllocatorPending;
+ WORK_QUEUE_ITEM SL_Allocator; // Allocation work item
+ KTIMER SL_Timer; // Timer to free unused segments
+ KDPC SL_TimerDpc; // DPC of the timer of unused segments
+ KSPIN_LOCK SL_Lock; // Access control
+};
+
+
+// The number of rcv packets per segment (config parameter)
+#define MIN_RCV_PKTS_PER_SEGMENT 8
+#define DEF_RCV_PKTS_PER_SEGMENT 64
+#define MAX_RCV_PKTS_PER_SEGMENT 256
+extern ULONG RcvPktsPerSegment;
+
+// Maximum size of memory that can be used to allocate packets (config
+// param). 0 means no limit
+extern ULONG MaxRcvPktsPoolSize;
+
+// There are currently three known frame sizes: ethernet-1500,
+// token ring 4k - 4500, token ring 16k - 17986
+#define FRAME_SIZE_VARIATIONS 3
+
+// List of packet segments for Ethernet packets
+extern SEGMENT_LIST ListEther;
+// List of packet segments for Token Ring 4K packets
+extern SEGMENT_LIST ListTR4;
+// List of packet segments for Token Ring 16K packets
+extern SEGMENT_LIST ListTR16;
+// Mapping from src and destination packet size requirments
+// to the appropriate segment list
+extern PSEGMENT_LIST SegmentMap[FRAME_SIZE_VARIATIONS][FRAME_SIZE_VARIATIONS];
+// Timeout for unused segment
+extern const LONGLONG SegmentTimeout;
+extern KSPIN_LOCK AllocatorLock;
+
+/*++
+*******************************************************************
+ I n i t i a l i z e P a c k e t A l l o c a t o r
+
+Routine Description:
+ Initializes packet allocator
+Arguments:
+ None
+Return Value:
+ None
+
+*******************************************************************
+--*/
+// VOID
+// InitializePacketAllocator (
+// void
+// );
+#define InitializePacketAllocator() { \
+ KeInitializeSpinLock(&AllocatorLock); \
+ InitializeSegmentList(&ListEther); \
+ InitializeSegmentList(&ListTR4); \
+ InitializeSegmentList(&ListTR16); \
+}
+
+/*++
+*******************************************************************
+ D e l e t e P a c k e t A l l o c a t o r
+
+Routine Description:
+ Disposes of all resources in packet allocator
+Arguments:
+ None
+Return Value:
+ None
+
+*******************************************************************
+--*/
+// VOID
+// DeletePacketAllocator (
+// void
+// );
+#define DeletePacketAllocator() { \
+ DeleteSegmentList(&ListEther); \
+ DeleteSegmentList(&ListTR4); \
+ DeleteSegmentList(&ListTR16); \
+}
+
+
+/*++
+*******************************************************************
+ A l l o c a t e P a c k e t
+
+Routine Description:
+ Allocate packet for source - destination combination
+Arguments:
+ srcListId - identifies max frame size for source interface
+ dstListId - identifies max frame size for destination
+ packet - receives pointer to allocated packet or NULL if allocation
+ fails
+Return Value:
+ None
+
+*******************************************************************
+--*/
+// VOID
+// AllocatePacket (
+// IN INT srcListId,
+// IN INT dstListId,
+// OUT PPACKET_TAG packet
+// );
+#define AllocatePacket(srcListId,dstListId,packet) { \
+ PSEGMENT_LIST list; \
+ ASSERT ((srcListId>=0) && (srcListId<FRAME_SIZE_VARIATIONS)); \
+ ASSERT ((dstListId>=0) && (dstListId<FRAME_SIZE_VARIATIONS)); \
+ list = SegmentMap[srcListId][dstListId]; \
+ AllocatePacketFromList(list,packet); \
+}
+
+/*++
+*******************************************************************
+ D u p l i c a t e P a c k e t
+
+Routine Description:
+ Duplicates packet
+Arguments:
+ src - source packet
+ dst - receives pointer to duplicated packet or NUUL if operation
+ failed
+Return Value:
+ None
+
+*******************************************************************
+--*/
+// VOID
+// DuplicatePacket (
+// IN PPACKET_TAG src
+// OUT PPACKET_TAG dst
+// );
+#define DuplicatePacket(src,dst) { \
+ PSEGMENT_LIST list; \
+ list = src->PT_Segment->PS_SegmentList; \
+ AllocatePacketFromList(list,dst); \
+}
+
+
+/*++
+*******************************************************************
+ A l l o c a t e P a c k e t F r o m L i s t
+
+Routine Description:
+ Allocate packet from specified packet segment list
+Arguments:
+ list - list from which to allocate
+ packet - receives pointer to allocated packet or NULL if allocation
+ fails
+Return Value:
+ None
+
+*******************************************************************
+--*/
+// VOID
+// AllocatePacketFromList (
+// IN PSEGMENT_LIST list
+// OUT PPACKET_TAG packet
+// );
+#define AllocatePacketFromList(list,packet) { \
+ PPACKET_SEGMENT segment; \
+ KIRQL oldIRQL; \
+ KeAcquireSpinLock (&list->SL_Lock, &oldIRQL); \
+ do { \
+ if (list->SL_FreeCount>0) { \
+ segment = CONTAINING_RECORD (list->SL_Head.Flink, \
+ PACKET_SEGMENT, PS_Link); \
+ while (segment->PS_FreeHead==NULL) { \
+ segment = CONTAINING_RECORD (segment->PS_Link.Flink, \
+ PACKET_SEGMENT, PS_Link); \
+ ASSERT (&segment->PS_Link!=&list->SL_Head); \
+ } \
+ list->SL_FreeCount -= 1; \
+ if ((list->SL_FreeCount<list->SL_LowCount) \
+ && !list->SL_AllocatorPending \
+ && EnterForwarder ()) { \
+ list->SL_AllocatorPending = TRUE; \
+ ExQueueWorkItem (&list->SL_Allocator, DelayedWorkQueue);\
+ } \
+ } \
+ else { \
+ segment = CreateSegment (list); \
+ if (segment!=NULL) { \
+ InsertTailList (&list->SL_Head, &segment->PS_Link); \
+ segment->PS_SegmentList = list; \
+ list->SL_FreeCount = list->SL_BlockCount-1; \
+ } \
+ else { \
+ packet = NULL; \
+ break; \
+ } \
+ } \
+ packet = segment->PS_FreeHead; \
+ segment->PS_FreeHead = packet->PT_Next; \
+ segment->PS_BusyCount += 1; \
+ packet->PT_Identifier = IDENTIFIER_RIP; \
+ packet->PT_Flags = 0; \
+ } \
+ while (FALSE); \
+ KeReleaseSpinLock (&list->SL_Lock, oldIRQL); \
+}
+
+/*++
+*******************************************************************
+ F r e e P a c k e t
+
+Routine Description:
+ Free allocated packet
+Arguments:
+ packet - packet to free
+Return Value:
+ None
+
+*******************************************************************
+--*/
+// VOID
+// FreePacket (
+// IN PPACKET_TAG packet
+// );
+#define FreePacket(packet) { \
+ PPACKET_SEGMENT segment=packet->PT_Segment; \
+ PSEGMENT_LIST list; \
+ KIRQL oldIRQL; \
+ list = segment->PS_SegmentList; \
+ KeAcquireSpinLock (&list->SL_Lock, &oldIRQL); \
+ packet->PT_Next = segment->PS_FreeHead; \
+ segment->PS_FreeHead = packet; \
+ list->SL_FreeCount += 1; \
+ segment->PS_BusyCount -= 1; \
+ if (segment->PS_BusyCount==0) { \
+ if (list->SL_TimerDpcPending) { \
+ KeQuerySystemTime ((PLARGE_INTEGER)&segment->PS_FreeStamp); \
+ KeReleaseSpinLock (&list->SL_Lock, oldIRQL);\
+ } \
+ else if (EnterForwarder ()) { \
+ list->SL_TimerDpcPending = TRUE; \
+ KeReleaseSpinLock (&list->SL_Lock, oldIRQL);\
+ KeSetTimer (&list->SL_Timer, \
+ *((PLARGE_INTEGER)&SegmentTimeout), \
+ &list->SL_TimerDpc); \
+ } \
+ else { \
+ KeReleaseSpinLock (&list->SL_Lock, oldIRQL);\
+ } \
+ } \
+ else { \
+ KeReleaseSpinLock (&list->SL_Lock, oldIRQL); \
+ } \
+}
+
+
+/*++
+*******************************************************************
+ C r e a t e S e g m e n t
+
+Routine Description:
+ Allocates and initializes packet segment
+Arguments:
+ list - segment list to which new segment will be added
+Return Value:
+ Pointer to allocated segment, NULL if fails
+
+*******************************************************************
+--*/
+PPACKET_SEGMENT
+CreateSegment (
+ PSEGMENT_LIST list
+ );
+
+/*++
+*******************************************************************
+ D e l e t e S e g m e n t
+
+Routine Description:
+ Frees packet segment
+Arguments:
+ segment - segment to free
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+DeleteSegment (
+ PPACKET_SEGMENT segment
+ );
+
+/*++
+*******************************************************************
+ R e g i s t e r P a c k e t C o n s u m e r
+
+Routine Description:
+ Registers a consumer (bound interface) of packets of the
+ given size
+Arguments:
+ pktsize - maximum size of packets needed
+ listId - buffer to return packet list id where packets
+ of required size are located
+Return Value:
+ STATUS_SUCCESS - registration succeded
+ STATUS_INSUFFICIENT_RESOURCES - not enogh resources to register
+
+*******************************************************************
+--*/
+NTSTATUS
+RegisterPacketConsumer (
+ IN ULONG pktsize,
+ OUT INT *listID
+ );
+
+/*++
+*******************************************************************
+ D e r e g i s t e r P a c k e t C o n s u m e r
+
+Routine Description:
+ Deregisters a consumer (bound interface) of packets of the
+ given size
+Arguments:
+ listId - packet list id used by the consumer
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+DeregisterPacketConsumer (
+ IN INT listID
+ );
+
+/*++
+*******************************************************************
+ I n i t i a l i z e S e g m e n t L i s t
+
+Routine Description:
+ Initializes list of packet segments
+Arguments:
+ list - list to initalize
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+InitializeSegmentList(
+ PSEGMENT_LIST list
+ );
+
+
+/*++
+*******************************************************************
+ D e l e t e S e g m e n t L i s t
+
+Routine Description:
+ Deletes list of packet segments
+Arguments:
+ list - list to delete
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+DeleteSegmentList (
+ PSEGMENT_LIST list
+ );
+
+#endif
+
diff --git a/private/ntos/tdi/isn/fwd/precomp.h b/private/ntos/tdi/isn/fwd/precomp.h
new file mode 100644
index 000000000..bc471bd40
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/precomp.h
@@ -0,0 +1,61 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\precomp.h
+
+Abstract:
+ IPX Forwarder driver precompiled header file
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+#define ISN_NT 1
+#define NT 1
+
+#if DBG
+#define DEBUG 1
+#endif
+
+// System includes
+#include <ntos.h>
+#include <tdikrnl.h>
+#include <ndis.h>
+#include <zwapi.h>
+#include <limits.h>
+
+// IPX shared includes
+#include "bind.h"
+#include "ipxfwd.h"
+#include "ipxfltif.h"
+
+// Constants and macros
+#include "fwddefs.h"
+#include "rwlock.h"
+
+// Internal module prototypes
+#include "tables.h"
+#include "registry.h"
+#include "packets.h"
+#include "ipxbind.h"
+#include "rcvind.h"
+#include "send.h"
+#include "netbios.h"
+#include "lineind.h"
+#include "ddreqs.h"
+#include "driver.h"
+#include "filterif.h"
+#include "debug.h"
+
+#pragma hdrstop
+
+
+
diff --git a/private/ntos/tdi/isn/fwd/rcvind.c b/private/ntos/tdi/isn/fwd/rcvind.c
new file mode 100644
index 000000000..7c4bc2d39
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/rcvind.c
@@ -0,0 +1,825 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\rcvind.c
+
+Abstract:
+ Receive indication processing
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+#include "precomp.h"
+
+#if DBG
+VOID
+DbgFilterReceivedPacket(PUCHAR hdrp);
+#endif
+
+// Doesn't allow accepting packets (for routing) from dial-in clients
+BOOLEAN ThisMachineOnly = FALSE;
+
+/*++
+*******************************************************************
+ F w R e c e i v e
+
+Routine Description:
+ Called by the IPX stack to indicate that the IPX packet was
+ received by the NIC dirver. Only external destined packets are
+ indicated by this routine (with the exception of Netbios boradcasts
+ that indicated both for internal and external handlers)
+Arguments:
+ MacBindingHandle - handle of NIC driver
+ MaxReceiveContext - NIC driver context
+ RemoteAddress - sender's address
+ MacOptions -
+ LookaheadBuffer - packet lookahead buffer that contains complete
+ IPX header
+ LookaheadBufferSize - its size (at least 30 bytes)
+ LookaheadBufferOffset - offset of lookahead buffer in the physical
+ packet
+Return Value:
+ TRUE if we take the MDL chain to return later with NdisReturnPacket
+
+*******************************************************************
+--*/
+BOOLEAN
+IpxFwdReceive (
+ NDIS_HANDLE MacBindingHandle,
+ NDIS_HANDLE MacReceiveContext,
+ ULONG Context,
+ PIPX_LOCAL_TARGET RemoteAddress,
+ ULONG MacOptions,
+ PUCHAR LookaheadBuffer,
+ UINT LookaheadBufferSize,
+ UINT LookaheadBufferOffset,
+ UINT PacketSize,
+ PMDL pMdl
+ ) {
+ PINTERFACE_CB srcIf, dstIf;
+ PPACKET_TAG pktTag;
+ PNDIS_PACKET pktDscr;
+ NDIS_STATUS status;
+ UINT BytesTransferred;
+ LARGE_INTEGER PerfCounter;
+
+ // check that our configuration process has terminated OK
+ if (!EnterForwarder ()) {
+ return FALSE;
+ }
+
+ if (!MeasuringPerformance) {
+ PerfCounter.QuadPart = 0;
+ }
+ else {
+#if DBG
+ static LONGLONG LastCall = 0;
+ KIRQL oldIRQL;
+#endif
+ PerfCounter = KeQueryPerformanceCounter (NULL);
+#if DBG
+ KeAcquireSpinLock (&PerfCounterLock, &oldIRQL);
+ ASSERT (PerfCounter.QuadPart-LastCall<ActivityTreshhold);
+ LastCall = PerfCounter.QuadPart;
+ KeReleaseSpinLock (&PerfCounterLock, oldIRQL);
+#endif
+ }
+
+ IpxFwdDbgPrint (DBG_RECV, DBG_INFORMATION,
+ ("IpxFwd: FwdReceive on %0lx,"
+ " dst-%08lx:%02x%02x%02x%02x%02x%02x, type-%02x.\n",
+ Context, GETULONG (LookaheadBuffer+IPXH_DESTNET),
+ LookaheadBuffer[IPXH_DESTNODE], LookaheadBuffer[IPXH_DESTNODE+1],
+ LookaheadBuffer[IPXH_DESTNODE+2], LookaheadBuffer[IPXH_DESTNODE+3],
+ LookaheadBuffer[IPXH_DESTNODE+4], LookaheadBuffer[IPXH_DESTNODE+5],
+ LookaheadBuffer[IPXH_PKTTYPE]));
+
+#if DBG
+ DbgFilterReceivedPacket (LookaheadBuffer);
+#endif
+ srcIf = InterfaceContextToReference ((PVOID)Context, RemoteAddress->NicId);
+ // Check if interface is valid
+ if (srcIf!=NULL) {
+ USHORT pktlen;
+ ULONG dstNet;
+ KIRQL oldIRQL;
+
+ dstNet = GETULONG (LookaheadBuffer + IPXH_DESTNET);
+ pktlen = GETUSHORT(LookaheadBuffer + IPXH_LENGTH);
+
+ // check if we got the whole IPX header in the lookahead buffer
+ if ((LookaheadBufferSize >= IPXH_HDRSIZE)
+ && (*(LookaheadBuffer + IPXH_XPORTCTL) < 16)
+ && (pktlen<=PacketSize)) {
+ // Lock interface CB to ensure coherency of information in it
+ KeAcquireSpinLock(&srcIf->ICB_Lock, &oldIRQL);
+ // Check if shoud accept packets on this interface
+ if (IS_IF_ENABLED(srcIf)
+ && (srcIf->ICB_Stats.OperationalState!=FWD_OPER_STATE_DOWN)
+ && (!ThisMachineOnly
+ || (srcIf->ICB_InterfaceType
+ !=FWD_IF_REMOTE_WORKSTATION))) {
+ // Check for looped back packets
+ if (IPX_NODE_CMP (RemoteAddress->MacAddress,
+ srcIf->ICB_LocalNode)!=0) {
+
+ // Separate processing of netbios broadcast packets (20)
+ if (*(LookaheadBuffer + IPXH_PKTTYPE) != IPX_NETBIOS_TYPE) {
+ PFWD_ROUTE dstRoute;
+ INT srcListId, dstListId;
+ // Temp IPX bug fix, they shou;d ensure that
+ // we only get packets that can be routed
+ if ((dstNet==srcIf->ICB_Network)
+ || (dstNet==InternalInterface->ICB_Network)) {
+ InterlockedIncrement (&srcIf->ICB_Stats.InDiscards);
+ KeReleaseSpinLock(&srcIf->ICB_Lock, oldIRQL);
+ ReleaseInterfaceReference (srcIf);
+ LeaveForwarder ();
+ return FALSE;
+ }
+// ASSERT (dstNet!=srcIf->ICB_Network);
+// ASSERT ((InternalInterface==NULL)
+// || (InternalInterface->ICB_Network==0)
+// || (dstNet!=InternalInterface->ICB_Network));
+ // Check if needed route is in cash
+ if ((srcIf->ICB_CashedRoute!=NULL)
+ && (dstNet==srcIf->ICB_CashedRoute->FR_Network)
+ // If route was changed or deleted, this will fail
+ && (srcIf->ICB_CashedRoute->FR_InterfaceReference
+ ==srcIf->ICB_CashedInterface)) {
+ dstIf = srcIf->ICB_CashedInterface;
+ dstRoute = srcIf->ICB_CashedRoute;
+ AcquireInterfaceReference (dstIf);
+ AcquireRouteReference (dstRoute);
+ IpxFwdDbgPrint (DBG_RECV, DBG_INFORMATION,
+ ("IpxFwd: Destination in cash.\n"));
+ }
+ else { // Find and cash the route
+ dstIf = FindDestination (dstNet,
+ LookaheadBuffer+IPXH_DESTNODE,
+ &dstRoute
+ );
+
+ if (dstIf!=NULL) { // If route is found
+ IpxFwdDbgPrint (DBG_RECV, DBG_INFORMATION,
+ ("IpxFwd: Found destination %0lx.\n", dstIf));
+ // Don't cash global wan clients and
+ // routes to the same net
+ if ((dstNet!=GlobalNetwork)
+ && (dstIf!=srcIf)) {
+ if (srcIf->ICB_CashedInterface!=NULL)
+ ReleaseInterfaceReference (srcIf->ICB_CashedInterface);
+ if (srcIf->ICB_CashedRoute!=NULL)
+ ReleaseRouteReference (srcIf->ICB_CashedRoute);
+ srcIf->ICB_CashedInterface = dstIf;
+ srcIf->ICB_CashedRoute = dstRoute;
+ AcquireInterfaceReference (dstIf);
+ AcquireRouteReference (dstRoute);
+ }
+ }
+ else { // No route
+ InterlockedIncrement (&srcIf->ICB_Stats.InNoRoutes);
+ KeReleaseSpinLock(&srcIf->ICB_Lock, oldIRQL);
+ IpxFwdDbgPrint (DBG_RECV, DBG_WARNING,
+ ("IpxFwd: No route for packet on interface %ld (icb:%0lx),"
+ " dst-%08lx:%02x%02x%02x%02x%02x%02x, type-%02x.\n",
+ srcIf->ICB_Index, srcIf, dstNet,
+ LookaheadBuffer[IPXH_DESTNODE], LookaheadBuffer[IPXH_DESTNODE+1],
+ LookaheadBuffer[IPXH_DESTNODE+2], LookaheadBuffer[IPXH_DESTNODE+3],
+ LookaheadBuffer[IPXH_DESTNODE+4], LookaheadBuffer[IPXH_DESTNODE+5],
+ LookaheadBuffer[IPXH_PKTTYPE]));
+ ReleaseInterfaceReference (srcIf);
+ LeaveForwarder ();
+ return FALSE;
+ }
+ }
+ srcListId = srcIf->ICB_PacketListId;
+ KeReleaseSpinLock(&srcIf->ICB_Lock, oldIRQL);
+
+ // Check if destination if can take the packet
+ if (IS_IF_ENABLED (dstIf)
+ // If interface is UP check packet againts actual size limit
+ && (((dstIf->ICB_Stats.OperationalState==FWD_OPER_STATE_UP)
+ && (PacketSize<=dstIf->ICB_Stats.MaxPacketSize))
+ // if sleeping (WAN), check we can allocate it from WAN list
+ || ((dstIf->ICB_Stats.OperationalState==FWD_OPER_STATE_SLEEPING)
+ && (PacketSize<=WAN_PACKET_SIZE))
+ // otherwise, interface is down and we can't take the packet
+ ) ){
+ FILTER_ACTION action;
+ action = FltFilter (LookaheadBuffer, LookaheadBufferSize,
+ srcIf->ICB_FilterInContext,
+ dstIf->ICB_FilterOutContext);
+ if (action==FILTER_PERMIT) {
+ InterlockedIncrement (&srcIf->ICB_Stats.InDelivers);
+ dstListId = dstIf->ICB_PacketListId;
+ // try to get a packet from the rcv pkt pool
+ AllocatePacket (srcListId, dstListId, pktTag);
+ if (pktTag!=NULL) {
+ // Set destination mac in local target if
+ // possible
+ KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
+ if (dstIf->ICB_InterfaceType==FWD_IF_PERMANENT) {
+ // Permanent interface: send to the next
+ // hop router if net is not directly connected
+ // or to the dest node otherwise
+ if (dstNet!=dstIf->ICB_Network) {
+ IPX_NODE_CPY (pktTag->PT_Target.MacAddress,
+ dstRoute->FR_NextHopAddress);
+ }
+ else {
+ IPX_NODE_CPY (pktTag->PT_Target.MacAddress,
+ LookaheadBuffer+IPXH_DESTNODE);
+ }
+ }
+ else { // Demand dial interface: assumed to be
+ // point to point connection -> send to
+ // the other party if connection has already
+ // been made, otherwise wait till connected
+ if (dstIf->ICB_Stats.OperationalState
+ == FWD_OPER_STATE_UP) {
+ IPX_NODE_CPY (pktTag->PT_Target.MacAddress,
+ dstIf->ICB_RemoteNode);
+ } // Copy source mac address and nic id in case
+ // we need to spoof this packet
+ else if ((*(LookaheadBuffer+IPXH_PKTTYPE)==0)
+ && (pktlen==IPXH_HDRSIZE+2)
+ && ((LookaheadBufferSize<IPXH_HDRSIZE+2)
+ ||(*(LookaheadBuffer+IPXH_HDRSIZE+1)=='?'))) {
+ IPX_NODE_CPY (pktTag->PT_Target.MacAddress,
+ RemoteAddress->MacAddress);
+ pktTag->PT_SourceIf = srcIf;
+ AcquireInterfaceReference (srcIf);
+ pktTag->PT_Flags |= PT_SOURCE_IF;
+ }
+
+ }
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ ReleaseRouteReference (dstRoute);
+ goto GetPacket;
+ }
+ else { // Allocation failure
+ InterlockedIncrement (&dstIf->ICB_Stats.OutDiscards);
+ }
+ }
+ else {// Filtered out
+ if (action==FILTER_DENY_OUT)
+ InterlockedIncrement (&dstIf->ICB_Stats.OutFiltered);
+ else {
+ ASSERT (action==FILTER_DENY_IN);
+ InterlockedIncrement (&srcIf->ICB_Stats.InFiltered);
+ }
+ IpxFwdDbgPrint (DBG_RECV, DBG_WARNING,
+ ("IpxFwd: Filtered out"
+ " packet on interface %ld (icb:%0lx),"
+ " dst-%ld (icb %08lx) %08lx:%02x%02x%02x%02x%02x%02x, type-%02x.\n",
+ srcIf->ICB_Index, srcIf, dstIf->ICB_Index, dstIf, dstNet,
+ LookaheadBuffer[IPXH_DESTNODE], LookaheadBuffer[IPXH_DESTNODE+1],
+ LookaheadBuffer[IPXH_DESTNODE+2], LookaheadBuffer[IPXH_DESTNODE+3],
+ LookaheadBuffer[IPXH_DESTNODE+4], LookaheadBuffer[IPXH_DESTNODE+5],
+ LookaheadBuffer[IPXH_PKTTYPE]));
+ }
+ }
+ else { // Destination interface is down
+ InterlockedIncrement (&srcIf->ICB_Stats.InDelivers);
+ InterlockedIncrement (&dstIf->ICB_Stats.OutDiscards);
+ IpxFwdDbgPrint (DBG_RECV, DBG_WARNING,
+ ("IpxFwd: Dest interface %ld (icb %08lx) down"
+ " for packet on interface %ld (icb:%0lx),"
+ " dst-%08lx:%02x%02x%02x%02x%02x%02x, type-%02x.\n",
+ dstIf->ICB_Index, dstIf, srcIf->ICB_Index, srcIf, dstNet,
+ LookaheadBuffer[IPXH_DESTNODE], LookaheadBuffer[IPXH_DESTNODE+1],
+ LookaheadBuffer[IPXH_DESTNODE+2], LookaheadBuffer[IPXH_DESTNODE+3],
+ LookaheadBuffer[IPXH_DESTNODE+4], LookaheadBuffer[IPXH_DESTNODE+5],
+ LookaheadBuffer[IPXH_PKTTYPE]));
+ }
+ ReleaseInterfaceReference (dstIf);
+ ReleaseRouteReference (dstRoute);
+ }
+ else { // if netbios
+ // check that this is a netbios bcast packet and
+ // didnt exceed the limit of routers to traverse
+ // and we can accept it on this interface
+ if (srcIf->ICB_NetbiosAccept
+ && (*(LookaheadBuffer + IPXH_XPORTCTL) < 8)) {
+ INT srcListId;
+ srcListId = srcIf->ICB_PacketListId;
+ KeReleaseSpinLock(&srcIf->ICB_Lock, oldIRQL);
+ // Check if packet is valid
+ if (IPX_NODE_CMP (LookaheadBuffer + IPXH_DESTNODE,
+ BROADCAST_NODE)==0) {
+ // Check if we haven't exceeded the quota
+ if (InterlockedDecrement (&NetbiosPacketsQuota)>=0) {
+ // try to get a packet from the rcv pkt pool
+ AllocatePacket (srcListId, srcListId, pktTag);
+ if (pktTag!=NULL) {
+ dstIf = srcIf;
+ AcquireInterfaceReference (dstIf);
+ goto GetPacket;
+ }
+ }
+ else {// Netbios quota exceded
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_WARNING,
+ ("IpxFwd: Netbios quota exceded"
+ " for packet on interface %ld (icb:%0lx),"
+ " dst-%08lx:%02x%02x%02x%02x%02x%02x, type-%02x.\n",
+ srcIf->ICB_Index, srcIf, dstNet,
+ LookaheadBuffer[IPXH_DESTNODE], LookaheadBuffer[IPXH_DESTNODE+1],
+ LookaheadBuffer[IPXH_DESTNODE+2], LookaheadBuffer[IPXH_DESTNODE+3],
+ LookaheadBuffer[IPXH_DESTNODE+4], LookaheadBuffer[IPXH_DESTNODE+5],
+ LookaheadBuffer[IPXH_PKTTYPE]));
+ InterlockedIncrement (&srcIf->ICB_Stats.InDiscards);
+ }
+ InterlockedIncrement (&NetbiosPacketsQuota);
+ }
+ else { // Bad netbios packet
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_WARNING,
+ ("IpxFwd: Bad nb packet on interface %ld (icb:%0lx),"
+ " dst-%08lx:%02x%02x%02x%02x%02x%02x, type-%02x.\n",
+ srcIf->ICB_Index, srcIf, dstNet,
+ LookaheadBuffer[IPXH_DESTNODE], LookaheadBuffer[IPXH_DESTNODE+1],
+ LookaheadBuffer[IPXH_DESTNODE+2], LookaheadBuffer[IPXH_DESTNODE+3],
+ LookaheadBuffer[IPXH_DESTNODE+4], LookaheadBuffer[IPXH_DESTNODE+5],
+ LookaheadBuffer[IPXH_PKTTYPE]));
+ InterlockedIncrement (&srcIf->ICB_Stats.InHdrErrors);
+ }
+ }
+ else { // Netbios accept disabled or to many routers crossed
+ KeReleaseSpinLock(&srcIf->ICB_Lock, oldIRQL);
+ InterlockedIncrement (&srcIf->ICB_Stats.InDiscards);
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_WARNING,
+ ("IpxFwd: NB packet dropped on disabled interface %ld (icb:%0lx),"
+ " dst-%08lx:%02x%02x%02x%02x%02x%02x, type-%02x.\n",
+ srcIf->ICB_Index, srcIf, dstNet,
+ LookaheadBuffer[IPXH_DESTNODE], LookaheadBuffer[IPXH_DESTNODE+1],
+ LookaheadBuffer[IPXH_DESTNODE+2], LookaheadBuffer[IPXH_DESTNODE+3],
+ LookaheadBuffer[IPXH_DESTNODE+4], LookaheadBuffer[IPXH_DESTNODE+5],
+ LookaheadBuffer[IPXH_PKTTYPE]));
+ }
+ } // End netbios specific processing (else if netbios)
+ }
+ else { // Looped back packets discarded without counting
+ // (We shouldn't get them in IPX stack does the right job)
+ KeReleaseSpinLock(&srcIf->ICB_Lock, oldIRQL);
+ }
+ }
+ else { // Interface is down or disabled
+ KeReleaseSpinLock(&srcIf->ICB_Lock, oldIRQL);
+ InterlockedIncrement (&srcIf->ICB_Stats.InDiscards);
+ IpxFwdDbgPrint (DBG_RECV, DBG_WARNING,
+ ("IpxFwd: Packet dropped on disabled interface %ld (icb:%0lx),"
+ " dst-%08lx:%02x%02x%02x%02x%02x%02x, type-%02x.\n",
+ srcIf->ICB_Index, srcIf, dstNet,
+ LookaheadBuffer[IPXH_DESTNODE], LookaheadBuffer[IPXH_DESTNODE+1],
+ LookaheadBuffer[IPXH_DESTNODE+2], LookaheadBuffer[IPXH_DESTNODE+3],
+ LookaheadBuffer[IPXH_DESTNODE+4], LookaheadBuffer[IPXH_DESTNODE+5],
+ LookaheadBuffer[IPXH_PKTTYPE]));
+ }
+ }
+ else { // Obvious header errors (shouldn't IPX do this for us ?
+ InterlockedIncrement (&srcIf->ICB_Stats.InHdrErrors);
+ IpxFwdDbgPrint (DBG_RECV, DBG_ERROR,
+ ("IpxFwd: Header errors in packet on interface %ld (icb:%0lx),"
+ " dst-%08lx:%02x%02x%02x%02x%02x%02x, type-%02x.\n",
+ srcIf->ICB_Index, srcIf, dstNet,
+ LookaheadBuffer[IPXH_DESTNODE], LookaheadBuffer[IPXH_DESTNODE+1],
+ LookaheadBuffer[IPXH_DESTNODE+2], LookaheadBuffer[IPXH_DESTNODE+3],
+ LookaheadBuffer[IPXH_DESTNODE+4], LookaheadBuffer[IPXH_DESTNODE+5],
+ LookaheadBuffer[IPXH_PKTTYPE]));
+ }
+ ReleaseInterfaceReference (srcIf);
+ } // We could not locate the interface from IPX supplied context: there
+ // is just a little time window when interface is deleted
+ // but IPX had already pushed the context on the stack
+ else {
+ IpxFwdDbgPrint (DBG_RECV, DBG_ERROR,
+ ("IpxFwd: Receive, type-%02x"
+ " - src interface context is invalid.\n",
+ LookaheadBuffer[IPXH_PKTTYPE]));
+ }
+ LeaveForwarder ();
+ return FALSE ;
+
+GetPacket:
+
+ InterlockedIncrement (&srcIf->ICB_Stats.InDelivers);
+ ReleaseInterfaceReference (srcIf);
+
+ pktDscr = CONTAINING_RECORD (pktTag, NDIS_PACKET, ProtocolReserved);
+ pktTag->PT_InterfaceReference = dstIf;
+ pktTag->PT_PerfCounter = PerfCounter.QuadPart;
+
+ // try to get the packet data
+ IPXTransferData(&status,
+ MacBindingHandle,
+ MacReceiveContext,
+ LookaheadBufferOffset, // start of IPX header
+ PacketSize, // packet size starting at IPX header
+ pktDscr,
+ &BytesTransferred);
+
+ if (status != NDIS_STATUS_PENDING) {
+ // complete the frame processing (LeaveForwarder will be called there)
+ IpxFwdTransferDataComplete(pktDscr, status, BytesTransferred);
+ }
+ return FALSE;
+}
+
+
+/*++
+*******************************************************************
+ F w T r a n s f e r D a t a C o m p l e t e
+
+Routine Description:
+ Called by the IPX stack when NIC driver completes data transger.
+Arguments:
+ pktDscr - handle of NIC driver
+ status - result of the transfer
+ bytesTransferred - number of bytest trasferred
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+IpxFwdTransferDataComplete (
+ PNDIS_PACKET pktDscr,
+ NDIS_STATUS status,
+ UINT bytesTransferred
+ ) {
+ PPACKET_TAG pktTag;
+
+ pktTag = (PPACKET_TAG)(&pktDscr->ProtocolReserved);
+
+ // If transfer failed, release the packet and interface
+ if (status==NDIS_STATUS_SUCCESS) {
+ if (*(pktTag->PT_Data + IPXH_PKTTYPE) != IPX_NETBIOS_TYPE)
+ SendPacket (pktTag->PT_InterfaceReference, pktTag);
+ else
+ ProcessNetbiosPacket (pktTag->PT_InterfaceReference, pktTag);
+
+ }
+ else {
+ IpxFwdDbgPrint (DBG_RECV, DBG_ERROR,
+ ("IpxFwd: Transfer data failed for packet %08lx on interface %08lx!\n",
+ pktTag, pktTag->PT_InterfaceReference));
+ if (*(pktTag->PT_Data + IPXH_PKTTYPE) != IPX_NETBIOS_TYPE) {
+ InterlockedIncrement (
+ &pktTag->PT_InterfaceReference->ICB_Stats.OutDiscards);
+ }
+ else { // For netbios packets interface reference is
+ // actually a source interface
+ InterlockedIncrement (&NetbiosPacketsQuota);
+ InterlockedIncrement (
+ &pktTag->PT_InterfaceReference->ICB_Stats.InDiscards);
+ }
+ ReleaseInterfaceReference (pktTag->PT_InterfaceReference);
+ FreePacket (pktTag);
+ }
+
+ LeaveForwarder ();
+ return;
+}
+
+
+/*++
+*******************************************************************
+ F w R e c e i v e C o m p l e t e
+
+Routine Description:
+
+ This routine receives control from the IPX driver after one or
+ more receive operations have completed and no receive is in progress.
+ It is called under less severe time constraints than IpxFwdReceive.
+ It is used to process netbios queue
+
+Arguments:
+ None
+Return Value:
+ None
+*******************************************************************
+--*/
+VOID
+IpxFwdReceiveComplete (
+ USHORT NicId
+ ) {
+
+ // check that our configuration process has terminated OK
+ if(!EnterForwarder ()) {
+ return;
+ }
+ IpxFwdDbgPrint (DBG_RECV, DBG_INFORMATION, ("IpxFwd: FwdReceiveComplete.\n"));
+ ScheduleNetbiosWorker ();
+ LeaveForwarder ();
+}
+
+/*++
+*******************************************************************
+ I p x F w d I n t e r n a l R e c e i v e
+
+Routine Description:
+ Called by the IPX stack to indicate that the IPX packet destined
+ to local client was received by the NIC dirver.
+Arguments:
+ Context - forwarder context associated with
+ the NIC (interface block pointer)
+ RemoteAddress - sender's address
+ LookaheadBuffer - packet lookahead buffer that contains complete
+ IPX header
+ LookaheadBufferSize - its size (at least 30 bytes)
+Return Value:
+ STATUS_SUCCESS - the packet will be delivered to local destination
+ STATUS_UNSUCCESSFUL - the packet will be dropped
+
+*******************************************************************
+--*/
+NTSTATUS
+IpxFwdInternalReceive (
+ IN ULONG Context,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN PUCHAR LookAheadBuffer,
+ IN UINT LookAheadBufferSize
+ ) {
+ NTSTATUS status = STATUS_SUCCESS;
+ PINTERFACE_CB srcIf;
+
+ if (!EnterForwarder ()) {
+ return STATUS_UNSUCCESSFUL;
+ }
+ if (Context!=VIRTUAL_NET_FORWARDER_CONTEXT) {
+ // Check if interface context supplied by IPX driver is valid
+ srcIf = InterfaceContextToReference ((PVOID)Context, RemoteAddress->NicId);
+ }
+ else {
+ srcIf = InternalInterface;
+ AcquireInterfaceReference (srcIf);
+ }
+
+ if (srcIf!=NULL) {
+ // Check if we can accept on this interface
+ if (IS_IF_ENABLED (srcIf)
+ && (srcIf->ICB_Stats.OperationalState!=FWD_OPER_STATE_DOWN)
+ && ((*(LookAheadBuffer + IPXH_PKTTYPE) != IPX_NETBIOS_TYPE)
+ || srcIf->ICB_NetbiosAccept)) {
+ // Check if we can accept on internal interface
+ if (IS_IF_ENABLED(InternalInterface)) {
+ FILTER_ACTION action;
+ action = FltFilter (LookAheadBuffer, LookAheadBufferSize,
+ srcIf->ICB_FilterInContext,
+ InternalInterface->ICB_FilterOutContext);
+ // Check the filter
+ if (action==FILTER_PERMIT) {
+ // Update source interface statistics
+ InterlockedIncrement (&srcIf->ICB_Stats.InDelivers);
+ // Handle NB packets separatedly
+ if (*(LookAheadBuffer + IPXH_PKTTYPE) != IPX_NETBIOS_TYPE) {
+ InterlockedIncrement (
+ &InternalInterface->ICB_Stats.OutDelivers);
+ IpxFwdDbgPrint (DBG_INT_RECV, DBG_INFORMATION,
+ ("IpxFwd: FwdInternalReceive,"
+ " from %d(%lx)-%.2x%.2x%.2x%.2x:%.2x%.2x%.2x%.2x%.2x%.2x,"
+ " type-%02x.\n",
+ srcIf->ICB_Index, srcIf,
+ LookAheadBuffer[IPXH_SRCNET],LookAheadBuffer[IPXH_SRCNET+1],
+ LookAheadBuffer[IPXH_SRCNET+2],LookAheadBuffer[IPXH_SRCNET+3],
+ LookAheadBuffer[IPXH_SRCNODE],LookAheadBuffer[IPXH_SRCNODE+1],
+ LookAheadBuffer[IPXH_SRCNODE+2],LookAheadBuffer[IPXH_SRCNODE+3],
+ LookAheadBuffer[IPXH_SRCNODE+4],LookAheadBuffer[IPXH_SRCNODE+5],
+ LookAheadBuffer[IPXH_PKTTYPE]));
+ }
+ else {
+ // Check if destination netbios name is staticly assigned to
+ // an external interface or netbios delivery options do not
+ // allow us to deliver this packet
+ PINTERFACE_CB dstIf;
+ USHORT dstSock = GETUSHORT (LookAheadBuffer+IPXH_DESTSOCK);
+
+ InterlockedIncrement (&srcIf->ICB_Stats.NetbiosReceived);
+ // First try to find a static name if we have enough data
+ // in the lookahead buffer
+ if ((dstSock==IPX_NETBIOS_SOCKET)
+ && (LookAheadBufferSize>(NB_NAME+16)))
+ dstIf = FindNBDestination (LookAheadBuffer+(NB_NAME-IPXH_HDRSIZE));
+ else if ((dstSock==IPX_SMB_NAME_SOCKET)
+ && (LookAheadBufferSize>(SMB_NAME+16)))
+ dstIf = FindNBDestination (LookAheadBuffer+(SMB_NAME-IPXH_HDRSIZE));
+ else
+ dstIf = NULL;
+ // Now see, if we can deliver the packet
+ if ((((dstIf==NULL) || (dstIf==InternalInterface))
+ && (InternalInterface->ICB_NetbiosDeliver==FWD_NB_DELIVER_ALL))
+ || ((dstIf==InternalInterface)
+ && (InternalInterface->ICB_NetbiosDeliver==FWD_NB_DELIVER_STATIC))) {
+ InterlockedIncrement (
+ &InternalInterface->ICB_Stats.NetbiosSent);
+ InterlockedIncrement (
+ &InternalInterface->ICB_Stats.OutDelivers);
+ IpxFwdDbgPrint (DBG_INT_RECV, DBG_INFORMATION,
+ ("IpxFwd: FwdInternalReceive, NB"
+ " from %d(%lx)-%.2x%.2x%.2x%.2x:%.2x%.2x%.2x%.2x%.2x%.2x\n",
+ srcIf->ICB_Index, srcIf,
+ LookAheadBuffer[IPXH_SRCNET],LookAheadBuffer[IPXH_SRCNET+1],
+ LookAheadBuffer[IPXH_SRCNET+2],LookAheadBuffer[IPXH_SRCNET+3],
+ LookAheadBuffer[IPXH_SRCNODE],LookAheadBuffer[IPXH_SRCNODE+1],
+ LookAheadBuffer[IPXH_SRCNODE+2],LookAheadBuffer[IPXH_SRCNODE+3],
+ LookAheadBuffer[IPXH_SRCNODE+4],LookAheadBuffer[IPXH_SRCNODE+5]));
+ }
+ else {
+ InterlockedIncrement (
+ &InternalInterface->ICB_Stats.OutDiscards);
+ IpxFwdDbgPrint (DBG_INT_RECV, DBG_WARNING,
+ ("IpxFwd: FwdInternalReceive, NB dropped because delivery disabled"
+ " from %d(%lx)-%.2x%.2x%.2x%.2x:%.2x%.2x%.2x%.2x%.2x%.2x\n",
+ srcIf->ICB_Index, srcIf,
+ LookAheadBuffer[IPXH_SRCNET],LookAheadBuffer[IPXH_SRCNET+1],
+ LookAheadBuffer[IPXH_SRCNET+2],LookAheadBuffer[IPXH_SRCNET+3],
+ LookAheadBuffer[IPXH_SRCNODE],LookAheadBuffer[IPXH_SRCNODE+1],
+ LookAheadBuffer[IPXH_SRCNODE+2],LookAheadBuffer[IPXH_SRCNODE+3],
+ LookAheadBuffer[IPXH_SRCNODE+4],LookAheadBuffer[IPXH_SRCNODE+5]));
+ status = STATUS_UNSUCCESSFUL;
+ }
+ if (dstIf!=NULL)
+ ReleaseInterfaceReference (dstIf);
+ }
+ }
+ else {// Filtered Out
+ if (action==FILTER_DENY_OUT)
+ InterlockedIncrement (
+ &InternalInterface->ICB_Stats.OutFiltered);
+ else {
+ ASSERT (action==FILTER_DENY_IN);
+ InterlockedIncrement (&srcIf->ICB_Stats.InFiltered);
+ }
+ IpxFwdDbgPrint (DBG_INT_RECV, DBG_WARNING,
+ ("IpxFwd: FwdInternalReceive, filtered out"
+ " from %d(%lx)-%.2x%.2x%.2x%.2x:%.2x%.2x%.2x%.2x%.2x%.2x,"
+ " type-%02x.\n",
+ srcIf->ICB_Index, srcIf,
+ LookAheadBuffer[IPXH_SRCNET],LookAheadBuffer[IPXH_SRCNET+1],
+ LookAheadBuffer[IPXH_SRCNET+2],LookAheadBuffer[IPXH_SRCNET+3],
+ LookAheadBuffer[IPXH_SRCNODE],LookAheadBuffer[IPXH_SRCNODE+1],
+ LookAheadBuffer[IPXH_SRCNODE+2],LookAheadBuffer[IPXH_SRCNODE+3],
+ LookAheadBuffer[IPXH_SRCNODE+4],LookAheadBuffer[IPXH_SRCNODE+5],
+ LookAheadBuffer[IPXH_PKTTYPE]));
+ }
+ }
+ else {// Internal interface is disabled
+ InterlockedIncrement (
+ &InternalInterface->ICB_Stats.OutDiscards);
+ status = STATUS_UNSUCCESSFUL;
+ IpxFwdDbgPrint (DBG_INT_RECV, DBG_WARNING,
+ ("IpxFwd: FwdInternalReceive, internal if disabled"
+ " from %d(%lx)-%.2x%.2x%.2x%.2x:%.2x%.2x%.2x%.2x%.2x%.2x,"
+ " type-%02x.\n",
+ srcIf->ICB_Index, srcIf,
+ LookAheadBuffer[IPXH_SRCNET],LookAheadBuffer[IPXH_SRCNET+1],
+ LookAheadBuffer[IPXH_SRCNET+2],LookAheadBuffer[IPXH_SRCNET+3],
+ LookAheadBuffer[IPXH_SRCNODE],LookAheadBuffer[IPXH_SRCNODE+1],
+ LookAheadBuffer[IPXH_SRCNODE+2],LookAheadBuffer[IPXH_SRCNODE+3],
+ LookAheadBuffer[IPXH_SRCNODE+4],LookAheadBuffer[IPXH_SRCNODE+5],
+ LookAheadBuffer[IPXH_PKTTYPE]));
+ }
+ }
+ else { // Disabled source interface
+ InterlockedIncrement (&srcIf->ICB_Stats.InDiscards);
+ IpxFwdDbgPrint (DBG_INT_RECV, DBG_ERROR,
+ ("IpxFwd: FwdInternalReceive, source if disabled"
+ " from %d(%lx)-%.2x%.2x%.2x%.2x:%.2x%.2x%.2x%.2x%.2x%.2x,"
+ " type-%02x.\n",
+ srcIf->ICB_Index, srcIf,
+ LookAheadBuffer[IPXH_SRCNET],LookAheadBuffer[IPXH_SRCNET+1],
+ LookAheadBuffer[IPXH_SRCNET+2],LookAheadBuffer[IPXH_SRCNET+3],
+ LookAheadBuffer[IPXH_SRCNODE],LookAheadBuffer[IPXH_SRCNODE+1],
+ LookAheadBuffer[IPXH_SRCNODE+2],LookAheadBuffer[IPXH_SRCNODE+3],
+ LookAheadBuffer[IPXH_SRCNODE+4],LookAheadBuffer[IPXH_SRCNODE+5],
+ LookAheadBuffer[IPXH_PKTTYPE]));
+ status = STATUS_UNSUCCESSFUL;
+ }
+ ReleaseInterfaceReference (srcIf);
+ }
+ else { // Invalid source interface context
+ IpxFwdDbgPrint (DBG_INT_RECV, DBG_ERROR,
+ ("IpxFwd: FwdInternalReceive, source if context is invalid"
+ " from (%lx:%d)-%.2x%.2x%.2x%.2x:%.2x%.2x%.2x%.2x%.2x%.2x,"
+ " type-%02x.\n",
+ Context, RemoteAddress->NicId,
+ LookAheadBuffer[IPXH_SRCNET],LookAheadBuffer[IPXH_SRCNET+1],
+ LookAheadBuffer[IPXH_SRCNET+2],LookAheadBuffer[IPXH_SRCNET+3],
+ LookAheadBuffer[IPXH_SRCNODE],LookAheadBuffer[IPXH_SRCNODE+1],
+ LookAheadBuffer[IPXH_SRCNODE+2],LookAheadBuffer[IPXH_SRCNODE+3],
+ LookAheadBuffer[IPXH_SRCNODE+4],LookAheadBuffer[IPXH_SRCNODE+5],
+ LookAheadBuffer[IPXH_PKTTYPE]));
+ status = STATUS_UNSUCCESSFUL;
+ }
+ LeaveForwarder ();
+ return status;
+}
+
+/*++
+*******************************************************************
+ D e l e t e R e c v Q u e u e
+
+Routine Description:
+ Initializes the netbios bradcast queue
+Arguments:
+ None
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+DeleteRecvQueue (
+ void
+ ) {
+// while (!IsListEmpty (&RecvQueue)) {
+// PPACKET_TAG pktTag = CONTAINING_RECORD (RecvQueue.Flink,
+// PACKET_TAG,
+// PT_QueueLink);
+// RemoveEntryList (&pktTag->PT_QueueLink);
+// if (pktTag->PT_InterfaceReference!=NULL) {
+// ReleaseInterfaceReference (pktTag->PT_InterfaceReference);
+// }
+// FreePacket (pktTag);
+// }
+}
+#if DBG
+
+ULONG DbgFilterTrap = 0; // 1 - on dst and src (net + node),
+ // 2 - on dst (net + node),
+ // 3 - on src (net + node),
+ // 4 - on dst (net + node + socket)
+
+UCHAR DbgFilterDstNet[4];
+UCHAR DbgFilterDstNode[6];
+UCHAR DbgFilterDstSocket[2];
+UCHAR DbgFilterSrcNet[4];
+UCHAR DbgFilterSrcNode[6];
+UCHAR DbgFilterSrcSocket[2];
+PUCHAR DbgFilterFrame;
+
+VOID
+DbgFilterReceivedPacket(PUCHAR hdrp)
+{
+ switch(DbgFilterTrap) {
+
+ case 1:
+
+ if(!memcmp(hdrp + IPXH_DESTNET, DbgFilterDstNet, 4) &&
+ !memcmp(hdrp + IPXH_DESTNODE, DbgFilterDstNode, 6) &&
+ !memcmp(hdrp + IPXH_SRCNET, DbgFilterSrcNet, 4) &&
+ !memcmp(hdrp + IPXH_SRCNODE, DbgFilterSrcNode, 6)) {
+
+ DbgBreakPoint();
+ }
+
+ break;
+
+ case 2:
+
+ if(!memcmp(hdrp + IPXH_DESTNET, DbgFilterDstNet, 4) &&
+ !memcmp(hdrp + IPXH_DESTNODE, DbgFilterDstNode, 6)) {
+
+ DbgBreakPoint();
+ }
+
+ break;
+
+ case 3:
+
+ if(!memcmp(hdrp + IPXH_SRCNET, DbgFilterSrcNet, 4) &&
+ !memcmp(hdrp + IPXH_SRCNODE, DbgFilterSrcNode, 6)) {
+
+ DbgBreakPoint();
+ }
+
+ break;
+
+ case 4:
+
+ if(!memcmp(hdrp + IPXH_DESTNET, DbgFilterDstNet, 4) &&
+ !memcmp(hdrp + IPXH_DESTNODE, DbgFilterDstNode, 6) &&
+ !memcmp(hdrp + IPXH_DESTSOCK, DbgFilterDstSocket, 2)) {
+
+ DbgBreakPoint();
+ }
+
+ break;
+
+ default:
+
+ break;
+ }
+
+ DbgFilterFrame = hdrp;
+}
+
+#endif
+
diff --git a/private/ntos/tdi/isn/fwd/rcvind.h b/private/ntos/tdi/isn/fwd/rcvind.h
new file mode 100644
index 000000000..50f240bdd
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/rcvind.h
@@ -0,0 +1,180 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\rcvind.h
+
+Abstract:
+ Receive indication processing
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+#ifndef _IPXFWD_RCVIND
+#define _IPXFWD_RCVIND
+
+// Doesn't allow accepting packets (for routing) from dial-in clients
+extern BOOLEAN ThisMachineOnly;
+
+/*++
+*******************************************************************
+ I n i t i a l i z e R e c v Q u e u e
+
+Routine Description:
+ Initializes recv queue
+Arguments:
+ None
+Return Value:
+ None
+
+*******************************************************************
+--*/
+//VOID
+//DeleteRecvQueue (
+// void
+// )
+#define InitializeRecvQueue() { \
+}
+
+/*++
+*******************************************************************
+ D e l e t e R e c v Q u e u e
+
+Routine Description:
+ Deletes recv queue
+Arguments:
+ None
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+DeleteRecvQueue (
+ void
+ );
+
+/*++
+*******************************************************************
+ F w R e c e i v e
+
+Routine Description:
+ Called by the IPX stack to indicate that the IPX packet was
+ received by the NIC dirver. Only external destined packets are
+ indicated by this routine (with the exception of Netbios boradcasts
+ that indicated both for internal and external handlers)
+Arguments:
+ MacBindingHandle - handle of NIC driver
+ MaxReceiveContext - NIC driver context
+ Context - forwarder context associated with
+ the NIC (interface block pointer)
+ RemoteAddress - sender's address
+ MacOptions -
+ LookaheadBuffer - packet lookahead buffer that contains complete
+ IPX header
+ LookaheadBufferSize - its size (at least 30 bytes)
+ LookaheadBufferOffset - offset of lookahead buffer in the physical
+ packet
+Return Value:
+ None
+
+*******************************************************************
+--*/
+BOOLEAN
+IpxFwdReceive (
+ NDIS_HANDLE MacBindingHandle,
+ NDIS_HANDLE MacReceiveContext,
+ ULONG Context,
+ PIPX_LOCAL_TARGET RemoteAddress,
+ ULONG MacOptions,
+ PUCHAR LookaheadBuffer,
+ UINT LookaheadBufferSize,
+ UINT LookaheadBufferOffset,
+ UINT PacketSize,
+ PMDL pMdl
+
+ );
+
+
+/*++
+*******************************************************************
+ F w T r a n s f e r D a t a C o m p l e t e
+
+Routine Description:
+ Called by the IPX stack when NIC driver completes data transger.
+Arguments:
+ pktDscr - handle of NIC driver
+ status - result of the transfer
+ bytesTransferred - number of bytest trasferred
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+IpxFwdTransferDataComplete (
+ PNDIS_PACKET pktDscr,
+ NDIS_STATUS status,
+ UINT bytesTransferred
+ );
+
+
+/*++
+*******************************************************************
+ F w T r a n s f e r D a t a C o m p l e t e
+
+Routine Description:
+
+ This routine receives control from the IPX driver after one or
+ more receive operations have completed and no receive is in progress.
+ It is called under less severe time constraints than IpxFwdReceive.
+ It is used to process netbios queue
+
+Arguments:
+ None
+Return Value:
+ None
+*******************************************************************
+--*/
+VOID
+IpxFwdReceiveComplete (
+ USHORT NicId
+ );
+
+/*++
+*******************************************************************
+ F w R e c e i v e
+
+Routine Description:
+ Called by the IPX stack to indicate that the IPX packet destined
+ to local client was received by the NIC dirver.
+Arguments:
+ Context - forwarder context associated with
+ the NIC (interface block pointer)
+ RemoteAddress - sender's address
+ LookaheadBuffer - packet lookahead buffer that contains complete
+ IPX header
+ LookaheadBufferSize - its size (at least 30 bytes)
+Return Value:
+ STATUS_SUCCESS - the packet will be delivered to local destination
+ STATUS_UNSUCCESSFUL - the packet will be dropped
+
+*******************************************************************
+--*/
+NTSTATUS
+IpxFwdInternalReceive (
+ IN ULONG FwdAdapterContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN PUCHAR LookAheadBuffer,
+ IN UINT LookAheadBufferSize
+ );
+
+#endif
+
diff --git a/private/ntos/tdi/isn/fwd/registry.c b/private/ntos/tdi/isn/fwd/registry.c
new file mode 100644
index 000000000..b38a3b4e1
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/registry.c
@@ -0,0 +1,273 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: registry.c
+//
+// Description: routines for reading the registry configuration
+//
+// Author: Stefan Solomon (stefans) November 9, 1993.
+//
+// Revision History:
+// Updated to read parameters of new forwarder driver (11/95)
+//
+//***
+
+#include "precomp.h"
+
+NTSTATUS
+SetIpxDeviceName(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+/*++
+*******************************************************************
+ R e a d I p x D e v i c e N a m e
+
+Routine Description:
+ Allocates buffer and reads device name exported by the IPX stack
+ into it
+Arguments:
+ FileName - pointer to buffer to hold the name
+Return Value:
+ STATUS_SUCCESS - tables were created ok
+ STATUS_INSUFFICIENT_RESOURCES - resource allocation failed
+ STATUS_OBJECT_NAME_NOT_FOUND - if name value is not found
+*******************************************************************
+--*/
+NTSTATUS
+ReadIpxDeviceName (
+ PWSTR *FileName
+ ) {
+ NTSTATUS Status;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+ PWSTR Export = L"Export";
+ PWSTR IpxRegistryPath = L"NwLnkIpx\\Linkage";
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Call SetIpxDeviceName for the string in "Export"
+ //
+
+ QueryTable[0].QueryRoutine = SetIpxDeviceName;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[0].Name = Export;
+ QueryTable[0].EntryContext = FileName;
+ QueryTable[0].DefaultType = 0;
+
+ //
+ // 2) Stop
+ //
+
+ QueryTable[1].QueryRoutine = NULL;
+ QueryTable[1].Flags = 0;
+ QueryTable[1].Name = NULL;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ IpxRegistryPath,
+ QueryTable,
+ NULL,
+ NULL);
+
+ return Status;
+}
+
+
+/*++
+*******************************************************************
+ S e t I p x D e v i c e N a m e
+
+Routine Description:
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Export" multi-string and
+ saves the information in a ConfigurationInfo structure.
+Arguments:
+ ValueName - The name of the value ("Export" -- ignored).
+ ValueType - The type of the value (REG_SZ -- ignored).
+ ValueData - The null-terminated data for the value.
+ ValueLength - The length of ValueData.
+ Context - NULL.
+ EntryContext - file name pointer.
+Return Value:
+ STATUS_SUCCESS - name was allocated and copied OK
+ STATUS_INSUFFICIENT_RESOURCES - name allocation failed
+*******************************************************************
+--*/
+NTSTATUS
+SetIpxDeviceName(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ ) {
+ PWSTR *FileName = (PWSTR *)EntryContext;
+
+ ASSERT (ValueType==REG_SZ);
+ *FileName = (PWSTR)ExAllocatePoolWithTag(NonPagedPool,
+ ValueLength, FWD_POOL_TAG);
+ if (*FileName != NULL) {
+ RtlCopyMemory (*FileName, ValueData, ValueLength);
+ return STATUS_SUCCESS;
+ }
+ else
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+}
+
+/*++
+*******************************************************************
+ G e t R o u t e r P a r a m e t e r s
+
+Routine Description:
+ Reads the parameters from the registry or sets the defaults
+Arguments:
+ RegistryPath - where to read from.
+Return Value:
+ STATUS_SUCCESS
+*******************************************************************
+--*/
+NTSTATUS
+GetForwarderParameters (
+ IN PUNICODE_STRING RegistryPath
+ ) {
+ NTSTATUS Status;
+ PWSTR RegistryPathBuffer;
+ PWSTR Parameters = L"Parameters";
+ RTL_QUERY_REGISTRY_TABLE paramTable[11]; // table size = nr of params + 1
+
+ RegistryPathBuffer = (PWSTR)ExAllocatePool(NonPagedPool, RegistryPath->Length + sizeof(WCHAR));
+
+ if (RegistryPathBuffer == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (RegistryPathBuffer, RegistryPath->Buffer, RegistryPath->Length);
+ *(PWCHAR)(((PUCHAR)RegistryPathBuffer)+RegistryPath->Length) = (WCHAR)'\0';
+
+ RtlZeroMemory(&paramTable[0], sizeof(paramTable));
+
+ paramTable[0].QueryRoutine = NULL;
+ paramTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ paramTable[0].Name = Parameters;
+
+ paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ paramTable[1].Name = L"MaxRcvPktPoolSize";
+ paramTable[1].EntryContext = &MaxRcvPktsPoolSize;
+ paramTable[1].DefaultType = REG_DWORD;
+ paramTable[1].DefaultData = &MaxRcvPktsPoolSize;
+ paramTable[1].DefaultLength = sizeof(ULONG);
+
+ paramTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ paramTable[2].Name = L"RcvPktsPerSegment";
+ paramTable[2].EntryContext = &RcvPktsPerSegment;
+ paramTable[2].DefaultType = REG_DWORD;
+ paramTable[2].DefaultData = &RcvPktsPerSegment;
+ paramTable[2].DefaultLength = sizeof(ULONG);
+
+ paramTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ paramTable[3].Name = L"RouteTableSegmentSize";
+ paramTable[3].EntryContext = &RouteSegmentSize;
+ paramTable[3].DefaultType = REG_DWORD;
+ paramTable[3].DefaultData = &RouteSegmentSize;
+ paramTable[3].DefaultLength = sizeof(ULONG);
+
+ paramTable[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ paramTable[4].Name = L"MaxSendPktsQueued";
+ paramTable[4].EntryContext = &MaxSendPktsQueued;
+ paramTable[4].DefaultType = REG_DWORD;
+ paramTable[4].DefaultData = &MaxSendPktsQueued;
+ paramTable[4].DefaultLength = sizeof(ULONG);
+
+ paramTable[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ paramTable[5].Name = L"ClientHashSize";
+ paramTable[5].EntryContext = &ClientHashSize;
+ paramTable[5].DefaultType = REG_DWORD;
+ paramTable[5].DefaultData = &ClientHashSize;
+ paramTable[5].DefaultLength = sizeof(ULONG);
+
+ paramTable[6].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ paramTable[6].Name = L"InterfaceHashSize";
+ paramTable[6].EntryContext = &InterfaceHashSize;
+ paramTable[6].DefaultType = REG_DWORD;
+ paramTable[6].DefaultData = &InterfaceHashSize;
+ paramTable[6].DefaultLength = sizeof(ULONG);
+
+ paramTable[7].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ paramTable[7].Name = L"MaxNetbiosPacketsQueued";
+ paramTable[7].EntryContext = &MaxNetbiosPacketsQueued;
+ paramTable[7].DefaultType = REG_DWORD;
+ paramTable[7].DefaultData = &MaxNetbiosPacketsQueued;
+ paramTable[7].DefaultLength = sizeof(ULONG);
+
+ paramTable[8].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ paramTable[8].Name = L"SpoofingTimeout";
+ paramTable[8].EntryContext = &SpoofingTimeout;
+ paramTable[8].DefaultType = REG_DWORD;
+ paramTable[8].DefaultData = &SpoofingTimeout;
+ paramTable[8].DefaultLength = sizeof(ULONG);
+
+ paramTable[9].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ paramTable[9].Name = L"DontSuppressNonAgentSapAdvertisements";
+ paramTable[9].EntryContext = &DontSuppressNonAgentSapAdvertisements;
+ paramTable[9].DefaultType = REG_DWORD;
+ paramTable[9].DefaultData = &DontSuppressNonAgentSapAdvertisements;
+ paramTable[9].DefaultLength = sizeof(ULONG);
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ RegistryPathBuffer,
+ paramTable,
+ NULL,
+ NULL);
+
+ if(!NT_SUCCESS(Status)) {
+
+ IpxFwdDbgPrint (DBG_REGISTRY, DBG_WARNING,
+ ("IpxFwd: Missing Parameters key in the registry\n"));
+ }
+
+ ExFreePool(RegistryPathBuffer);
+
+ if ((RcvPktsPerSegment > MAX_RCV_PKTS_PER_SEGMENT) ||
+ (RcvPktsPerSegment < MIN_RCV_PKTS_PER_SEGMENT)) {
+
+ RcvPktsPerSegment = DEF_RCV_PKTS_PER_SEGMENT;
+ }
+
+ if ((RouteSegmentSize > MAX_ROUTE_SEGMENT_SIZE) ||
+ (RouteSegmentSize < MIN_ROUTE_SEGMENT_SIZE)) {
+
+ RouteSegmentSize = DEF_ROUTE_SEGMENT_SIZE;
+ }
+ else
+ RouteSegmentSize = ROUND_TO_PAGES(RouteSegmentSize);
+
+ if ((InterfaceHashSize > MAX_INTERFACE_HASH_SIZE) ||
+ (InterfaceHashSize < MIN_INTERFACE_HASH_SIZE)) {
+
+ InterfaceHashSize = DEF_INTERFACE_HASH_SIZE;
+ }
+
+ if ((ClientHashSize > MAX_CLIENT_HASH_SIZE) ||
+ (ClientHashSize < MIN_CLIENT_HASH_SIZE)) {
+
+ ClientHashSize = DEF_CLIENT_HASH_SIZE;
+ }
+ // even if the RtlQueryRegistryValues has failed, we return success and will
+ // use the defaults.
+ return STATUS_SUCCESS;
+}
+
diff --git a/private/ntos/tdi/isn/fwd/registry.h b/private/ntos/tdi/isn/fwd/registry.h
new file mode 100644
index 000000000..6cff0eef2
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/registry.h
@@ -0,0 +1,61 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\registry.h
+
+Abstract:
+ IPX Forwarder Driver registry interface
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+#ifndef _IPXFWD_REGISTRY_
+#define _IPXFWD_REGISTRY_
+
+/*++
+*******************************************************************
+ R e a d I p x D e v i c e N a m e
+
+Routine Description:
+ Allocates buffer and reads device name exported by the IPX stack
+ into it
+Arguments:
+ FileName - pointer to variable to hold the name buffer
+Return Value:
+ STATUS_SUCCESS - tables were created ok
+ STATUS_INSUFFICIENT_RESOURCES - resource allocation failed
+ STATUS_OBJECT_NAME_NOT_FOUND - if name value is not found
+*******************************************************************
+--*/
+NTSTATUS
+ReadIpxDeviceName (
+ PWSTR *FileName
+ );
+
+/*++
+*******************************************************************
+ G e t R o u t e r P a r a m e t e r s
+
+Routine Description:
+ Reads the parameters from the registry or sets the defaults
+Arguments:
+ RegistryPath - where to read from.
+Return Value:
+ STATUS_SUCCESS
+*******************************************************************
+--*/
+NTSTATUS
+GetForwarderParameters (
+ IN PUNICODE_STRING RegistryPath
+ );
+
+#endif
+
diff --git a/private/ntos/tdi/isn/fwd/rwlock.h b/private/ntos/tdi/isn/fwd/rwlock.h
new file mode 100644
index 000000000..d1a390651
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/rwlock.h
@@ -0,0 +1,179 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\rwlock.h
+
+Abstract:
+ Reader-Writer lock macros
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+#ifndef _IPXFWD_RWLOCK_
+#define _IPXFWD_RWLOCK_
+
+typedef volatile LONG VOLCTR, *PVOLCTR;
+typedef PVOLCTR RWCOOKIE, *PRWCOOKIE;
+
+// Reader- writer lock.
+// Allows no-lock access to the tables for readers - they merely
+// increment the counter to record their presence upon entrance
+// and decrement the same counter as they leave.
+// Writers are supposed to be serialized (externally) and their
+// actions are limited to ATOMIC insertions of new elements and
+// ATOMIC removals/replacements. The removals/replacements MUST
+// be followed by a wait for all potential readers who might still
+// be using the element that was removed/replaced
+
+typedef struct _RW_LOCK {
+ KEVENT Event; // Event to release waiting writer
+ VOLCTR Ctr1; // Two alternating
+ VOLCTR Ctr2; // reader counters
+ volatile PVOLCTR CurCtr; // Counter currently in use
+} RW_LOCK, *PRW_LOCK;
+
+
+/*++
+*******************************************************************
+ I n i t i a l i z e R W L o c k
+
+Routine Description:
+ Initializes RW lock
+Arguments:
+ lock - pointer to lock to initialize
+Return Value:
+ None
+*******************************************************************
+--*/
+//VOID
+//InitializeRWLock (
+// PRW_LOCK lock
+// );
+#define InitializeRWLock(lock) { \
+ KeInitializeEvent (&(lock)->Event, \
+ SynchronizationEvent, \
+ FALSE); \
+ (lock)->Ctr1 = (lock)->Ctr2 = 0; \
+ (lock)->CurCtr = &(lock)->Ctr1; \
+}
+
+/*++
+*******************************************************************
+ A c q u i r e R e a d e r A c c e s s
+
+Routine Description:
+ Acquires reader access to resource protected by the lock
+Arguments:
+ lock - pointer to lock
+ cookie - pointer to buffer to store lock state for subsequent
+ release operation
+Return Value:
+ None
+*******************************************************************
+--*/
+//VOID
+//AcquireReaderAccess (
+// IN PRW_LOCK lock,
+// OUT RWCOOKIE cookie
+// );
+#define AcquireReaderAccess(lock,cookie) \
+ do { \
+ register LONG local,local1; \
+ cookie = (lock)->CurCtr; /*Get current counter pointer*/ \
+ local = *(cookie); /*Copy counter value*/ \
+ local1 = local + 1; \
+ if ((local>=0) /*If counter is valid*/ \
+ /*and it hasn't changed while*/ \
+ /*we were checking and trying*/ \
+ /*to increment it,*/ \
+ && (InterlockedCompareExchange ( \
+ (PVOID *)(cookie), \
+ (PVOID)(local1), \
+ (PVOID)local) \
+ ==(PVOID)local)) \
+ break; /*then we obtained the access*/ \
+ } while (1) /*otherwise, we have to do it again (possibly with*/\
+ /*the other counter if writer switched it on us)*/
+
+
+/*++
+*******************************************************************
+ R e l e a s e R e a d e r A c c e s s
+
+Routine Description:
+ Releases reader access to resource protected by the lock
+Arguments:
+ lock - pointer to lock
+ cookie - lock state for subsequent stored during acquire operation
+Return Value:
+ None
+*******************************************************************
+--*/
+//VOID
+//ReleaseReaderAccess (
+// IN PRW_LOCK lock,
+// IN RWCOOKIE cookie
+// );
+#define ReleaseReaderAccess(lock,cookie) { \
+ /*If counter drops below 0, we have to signal the writer*/ \
+ if (InterlockedDecrement((PLONG)cookie)<0) { \
+ LONG res; \
+ ASSERT (*(cookie)==-1); \
+ res = KeSetEvent (&(lock)->Event, 0, FALSE); \
+ ASSERT (res==0); \
+ } \
+}
+
+/*++
+*******************************************************************
+ W a i t F o r A l l R e a d e r s
+
+Routine Description:
+ Waits for all readers that were accessing the resource prior
+ to the call to exit (New readers are not included)
+Arguments:
+ lock - pointer to lock
+Return Value:
+ None
+*******************************************************************
+--*/
+//VOID
+//WaitForAllReaders (
+// PRW_LOCK lock
+// );
+#define WaitForAllReaders(lock) { \
+ RWCOOKIE prevCtr = (lock)->CurCtr; \
+ /*Switch the counter first*/ \
+ if (prevCtr==&(lock)->Ctr1) { \
+ (lock)->Ctr2 = 0; \
+ (lock)->CurCtr = &(lock)->Ctr2; \
+ } \
+ else { \
+ ASSERT (prevCtr==&(lock)->Ctr2); \
+ (lock)->Ctr1 = 0; \
+ (lock)->CurCtr = &(lock)->Ctr1; \
+ } \
+ /* If not all readers are gone, we'll have to wait for them*/ \
+ if (InterlockedDecrement((PLONG)prevCtr)>=0) { \
+ NTSTATUS status \
+ = KeWaitForSingleObject ( \
+ &(lock)->Event, \
+ Executive, \
+ KeGetPreviousMode(),\
+ FALSE, \
+ 0); \
+ ASSERT (NT_SUCCESS(status)); \
+ ASSERT (*prevCtr==-1); \
+ } \
+}
+
+#endif
diff --git a/private/ntos/tdi/isn/fwd/send.c b/private/ntos/tdi/isn/fwd/send.c
new file mode 100644
index 000000000..35c3ea2d6
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/send.c
@@ -0,0 +1,1253 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\send.c
+
+Abstract:
+ Send routines
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+
+
+ULONG SpoofingTimeout=DEF_SPOOFING_TIMEOUT;
+LIST_ENTRY SpoofingQueue;
+KSPIN_LOCK SpoofingQueueLock;
+WORK_QUEUE_ITEM SpoofingWorker;
+BOOLEAN SpoofingWorkerActive = FALSE;
+ULONG DontSuppressNonAgentSapAdvertisements = 0;
+
+#define IsLocalSapNonAgentAdvertisement(hdr,data,ln,ifCB) ( \
+ (DontSuppressNonAgentSapAdvertisements==0) \
+ && (GETUSHORT(hdr+IPXH_DESTSOCK)==IPX_SAP_SOCKET) \
+ && (GETUSHORT(hdr+IPXH_SRCSOCK)!=IPX_SAP_SOCKET) \
+ && (ln>=IPXH_HDRSIZE+2) \
+ && (GETUSHORT(data)==2) \
+ && ((IPX_NODE_CMP(hdr+IPXH_DESTNODE,BROADCAST_NODE)==0) \
+ || (IPX_NODE_CMP(hdr+IPXH_DESTNODE,ifCB->ICB_RemoteNode)==0)) \
+)
+
+/*++
+*******************************************************************
+ D o S e n d
+
+Routine Description:
+ Prepares and sends packet. Interface lock must be help while
+ callin this routine
+Arguments:
+ dstIf - over which interface to send
+ pktTag - packet to send
+Return Value:
+ result returned by IPX
+
+*******************************************************************
+--*/
+NDIS_STATUS
+DoSend (
+ PINTERFACE_CB dstIf,
+ PPACKET_TAG pktTag,
+ KIRQL oldIRQL
+ ) {
+ NDIS_STATUS status;
+ PNDIS_PACKET pktDscr;
+ PNDIS_BUFFER bufDscr, aDscr;
+ UINT dataLen;
+ ULONG dstNet = GETULONG (pktTag->PT_Data+IPXH_DESTNET);
+
+ if (dstIf!=InternalInterface) {
+ ADAPTER_CONTEXT_TO_LOCAL_TARGET (dstIf->ICB_AdapterContext,
+ &pktTag->PT_Target);
+ }
+ else {
+ CONSTANT_ADAPTER_CONTEXT_TO_LOCAL_TARGET (
+ VIRTUAL_NET_ADAPTER_CONTEXT,
+ &pktTag->PT_Target);
+ }
+
+#if DBG
+ // Keep track of packets being processed by IPX stack
+ InsertTailList (&dstIf->ICB_InSendQueue, &pktTag->PT_QueueLink);
+#endif
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+
+ if (pktTag->PT_Flags&PT_SOURCE_IF)
+ ReleaseInterfaceReference (pktTag->PT_SourceIf);
+ pktTag->SEND_RESERVED[0] = pktTag->SEND_RESERVED[1] = 0;
+ pktDscr = CONTAINING_RECORD(pktTag, NDIS_PACKET, ProtocolReserved);
+ NdisQueryPacket(pktDscr, NULL, NULL, &bufDscr, NULL);
+#if DBG
+ { // Verify packet integrity
+ PUCHAR dataPtr;
+ UINT bufLen;
+ ASSERT (NDIS_BUFFER_LINKAGE (bufDscr)==NULL);
+ NdisQueryBuffer (bufDscr, &dataPtr, &bufLen);
+ ASSERT (dataPtr==pktTag->PT_Data);
+ ASSERT (bufLen==pktTag->PT_Segment->PS_SegmentList->SL_BlockSize);
+ }
+#endif
+ // Prepare packet for IPX stack (mac header buffer goes in
+ // front and packet length adjusted to reflect the size of the data
+ dataLen = GETUSHORT(pktTag->PT_Data+IPXH_LENGTH);
+ NdisAdjustBufferLength(bufDscr, dataLen);
+ NdisChainBufferAtFront(pktDscr, pktTag->PT_MacHdrBufDscr);
+
+
+ if (EnterForwarder ()) {// To make sure that we won't unload
+ // until IPX driver has a chance to call us back
+ status = IPXSendProc (&pktTag->PT_Target, pktDscr, dataLen, 0);
+
+ if (status!=NDIS_STATUS_PENDING) {
+ LeaveForwarder (); // No callback
+
+ // Restore original packet structure
+ NdisUnchainBufferAtFront (pktDscr, &aDscr);
+#if DBG
+ // Make sure IPX stack did not mess our packet
+ ASSERT (aDscr==pktTag->PT_MacHdrBufDscr);
+ NdisQueryPacket(pktDscr, NULL, NULL, &aDscr, NULL);
+ ASSERT (aDscr==bufDscr);
+ ASSERT (NDIS_BUFFER_LINKAGE (aDscr)==NULL);
+#endif
+ // Restore original packet size
+ NdisAdjustBufferLength(bufDscr,
+ pktTag->PT_Segment->PS_SegmentList->SL_BlockSize);
+#if DBG
+ // Remove packet from temp queue
+ KeAcquireSpinLock (&pktTag->PT_InterfaceReference->ICB_Lock, &oldIRQL);
+ RemoveEntryList (&pktTag->PT_QueueLink);
+ KeReleaseSpinLock (&pktTag->PT_InterfaceReference->ICB_Lock, oldIRQL);
+#endif
+ }
+ }
+ else {
+ // We are going down, restore the packet
+ NdisUnchainBufferAtFront (pktDscr, &aDscr);
+ NdisAdjustBufferLength(bufDscr,
+ pktTag->PT_Segment->PS_SegmentList->SL_BlockSize);
+ NdisRecalculatePacketCounts (pktDscr);
+ status = STATUS_UNSUCCESSFUL;
+#if DBG
+ KeAcquireSpinLock (&pktTag->PT_InterfaceReference->ICB_Lock, &oldIRQL);
+ RemoveEntryList (&pktTag->PT_QueueLink);
+ KeReleaseSpinLock (&pktTag->PT_InterfaceReference->ICB_Lock, oldIRQL);
+#endif
+ }
+ return status;
+}
+
+
+/*++
+*******************************************************************
+ P r o c e s s S e n t P a c k e t
+
+Routine Description:
+ Process completed sent packets
+Arguments:
+ dstIf - interface over which packet was sent
+ pktTag - completed packet
+ status - result of send operation
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+ProcessSentPacket (
+ PINTERFACE_CB dstIf,
+ PPACKET_TAG pktTag,
+ NDIS_STATUS status
+ ) {
+ KIRQL oldIRQL;
+
+ // Packet processing is completed -> can take more packets
+ InterlockedIncrement (&dstIf->ICB_PendingQuota);
+
+ if (*(pktTag->PT_Data+IPXH_PKTTYPE) == IPX_NETBIOS_TYPE) {
+ // Continue processing netbios packets
+ if (status==NDIS_STATUS_SUCCESS) {
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
+ ("IpxFwd: NB Packet %08lx sent.", pktTag));
+ InterlockedIncrement (&dstIf->ICB_Stats.OutDelivers);
+ InterlockedIncrement (&dstIf->ICB_Stats.NetbiosSent);
+ }
+ else {
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_ERROR,
+ ("IpxFwd: NB Packet %08lx send failed with error: %08lx.\n",
+ pktTag, status));
+ }
+ // Queue nb packet for further processing (broadcast on all interfaces)
+ QueueNetbiosPacket (pktTag);
+ }
+ else {
+ // Destroy completed packet
+ if (status==NDIS_STATUS_SUCCESS) {
+ InterlockedIncrement (&dstIf->ICB_Stats.OutDelivers);
+ IpxFwdDbgPrint (DBG_SEND, DBG_INFORMATION,
+ ("IpxFwd: Packet %08lx sent.", pktTag));
+ }
+ else {
+ InterlockedIncrement (&dstIf->ICB_Stats.OutDiscards);
+ IpxFwdDbgPrint (DBG_SEND, DBG_ERROR,
+ ("IpxFwd: Packet %08lx send failed with error: %08lx.\n",
+ pktTag, status));
+ }
+ ReleaseInterfaceReference (dstIf);
+ if (MeasuringPerformance
+ && (pktTag->PT_PerfCounter!=0)) {
+ LARGE_INTEGER PerfCounter = KeQueryPerformanceCounter (NULL);
+ PerfCounter.QuadPart -= pktTag->PT_PerfCounter;
+ KeAcquireSpinLock (&PerfCounterLock, &oldIRQL);
+ ASSERT (PerfCounter.QuadPart<ActivityTreshhold);
+ PerfBlock.TotalPacketProcessingTime += PerfCounter.QuadPart;
+ PerfBlock.PacketCounter += 1;
+ if (PerfBlock.MaxPacketProcessingTime < PerfCounter.QuadPart)
+ PerfBlock.MaxPacketProcessingTime = PerfCounter.QuadPart;
+ KeReleaseSpinLock (&PerfCounterLock, oldIRQL);
+ }
+ FreePacket (pktTag);
+ }
+}
+
+/*++
+*******************************************************************
+ S e n d P a c k e t
+
+Routine Description:
+ Enqueues packets to be sent by IPX stack
+Arguments:
+ dstIf - over which interface to send
+ pktTag - packet to send
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+SendPacket (
+ PINTERFACE_CB dstIf,
+ PPACKET_TAG pktTag
+ ) {
+ NDIS_STATUS status;
+ KIRQL oldIRQL;
+
+
+ ASSERT (dstIf->ICB_Index!=FWD_INTERNAL_INTERFACE_INDEX);
+ // Make sure we have not exceded the quota of pending packets on the interface
+ if (InterlockedDecrement (&dstIf->ICB_PendingQuota)>=0) {
+ KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
+ // Decide what to do with the packet based on the interface state
+ switch (dstIf->ICB_Stats.OperationalState) {
+ case FWD_OPER_STATE_UP:
+ if (*(pktTag->PT_Data + IPXH_PKTTYPE) != IPX_NETBIOS_TYPE)
+ NOTHING;
+ else {
+ PUTULONG (dstIf->ICB_Network, pktTag->PT_Data+IPXH_DESTNET);
+ }
+ status = DoSend (dstIf, pktTag, oldIRQL);
+ IpxFwdDbgPrint (DBG_SEND, DBG_INFORMATION,
+ ("IpxFwd: Sent external packet %08lx on if %ld.\n",
+ pktTag, dstIf->ICB_Index));
+ break;
+ case FWD_OPER_STATE_SLEEPING:
+ if ((*(pktTag->PT_Data+IPXH_PKTTYPE)!=0)
+ || (GETUSHORT(pktTag->PT_Data+IPXH_LENGTH)!=IPXH_HDRSIZE+2)
+ || (*(pktTag->PT_Data+IPXH_HDRSIZE+1)!='?')) {
+ // Queue this packet on the interface until it is connected
+ // by Router Manager (DIM) if this is not a NCP keepalive
+ // (watchdog)
+ InsertTailList (&dstIf->ICB_ExternalQueue, &pktTag->PT_QueueLink);
+ if (!IS_IF_CONNECTING (dstIf)) {
+ // Ask for connection if interface is not in the connection
+ // queue yet
+ QueueConnectionRequest (dstIf,
+ CONTAINING_RECORD (pktTag,
+ NDIS_PACKET,
+ ProtocolReserved),
+ pktTag->PT_Data,
+ oldIRQL);
+ IpxFwdDbgPrint (DBG_DIALREQS, DBG_WARNING,
+ ("IpxFwd: Queued dd request on if %ld (ifCB:%08lx)"
+ " for packet to %02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%02x%02x"
+ " from %02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%02x%02x\n",
+ dstIf->ICB_Index, dstIf,
+ *(pktTag->PT_Data+6),*(pktTag->PT_Data+7),
+ *(pktTag->PT_Data+8),*(pktTag->PT_Data+9),
+ *(pktTag->PT_Data+10),*(pktTag->PT_Data+11),
+ *(pktTag->PT_Data+12),*(pktTag->PT_Data+13),
+ *(pktTag->PT_Data+14),*(pktTag->PT_Data+15),
+ *(pktTag->PT_Data+16),*(pktTag->PT_Data+17),
+ *(pktTag->PT_Data+18),*(pktTag->PT_Data+19),
+ *(pktTag->PT_Data+20),*(pktTag->PT_Data+21),
+ *(pktTag->PT_Data+22),*(pktTag->PT_Data+23),
+ *(pktTag->PT_Data+24),*(pktTag->PT_Data+25),
+ *(pktTag->PT_Data+26),*(pktTag->PT_Data+27),
+ *(pktTag->PT_Data+28),*(pktTag->PT_Data+29)));
+ }
+ else
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ IpxFwdDbgPrint (DBG_SEND, DBG_INFORMATION,
+ ("IpxFwd: Queued external packet %08lx on if %ld.\n",
+ pktTag, dstIf->ICB_Index));
+ if (*(pktTag->PT_Data + IPXH_PKTTYPE) != IPX_NETBIOS_TYPE)
+ NOTHING;
+ else if (!(pktTag->PT_Flags&PT_NB_DESTROY)) {
+ // If this nb packet is not to be destroyed after this
+ // send, we have to make a copy of it to send on
+ // other interfaces while the original is waiting
+ // for connection
+ PPACKET_TAG newPktTag;
+ DuplicatePacket (pktTag, newPktTag);
+ if (newPktTag!=NULL) {
+ UINT bytesCopied;
+ PNDIS_PACKET packet = CONTAINING_RECORD (pktTag,
+ NDIS_PACKET,
+ ProtocolReserved);
+ PNDIS_PACKET newPacket = CONTAINING_RECORD (newPktTag,
+ NDIS_PACKET,
+ ProtocolReserved);
+ NdisCopyFromPacketToPacket (newPacket, 0,
+ GETUSHORT(pktTag->PT_Data+IPXH_LENGTH),
+ packet, 0, &bytesCopied);
+
+ ASSERT (bytesCopied==GETUSHORT(pktTag->PT_Data+IPXH_LENGTH));
+ IpxFwdDbgPrint (DBG_NETBIOS,
+ DBG_INFORMATION,
+ ("IpxFwd: Duplicated queued nb packet"
+ " %08lx -> %08lx on if %ld.\n",
+ pktTag, newPktTag, dstIf->ICB_Index));
+ AcquireInterfaceReference (dstIf);
+ newPktTag->PT_InterfaceReference = dstIf;
+ newPktTag->PT_PerfCounter = pktTag->PT_PerfCounter;
+ QueueNetbiosPacket (newPktTag);
+ // The original copy will have to be
+ // destroyed after it is sent on the
+ // connected interface
+ pktTag->PT_Flags |= PT_NB_DESTROY;
+ }
+ }
+ status = NDIS_STATUS_PENDING;
+ break;
+ }
+ else { // Process keepalives
+ LONGLONG curTime;
+ KeQuerySystemTime ((PLARGE_INTEGER)&curTime);
+ if (((curTime-dstIf->ICB_DisconnectTime)/10000000) < SpoofingTimeout) {
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ IpxFwdDbgPrint (DBG_SPOOFING, DBG_INFORMATION,
+ ("IpxFwd: Queueing reply to keepalive from server"
+ " on if %ld (ifCB %lx)"
+ " at %02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%02x%02x.\n",
+ dstIf->ICB_Index, dstIf,
+ *(pktTag->PT_Data+IPXH_SRCNET),*(pktTag->PT_Data+IPXH_SRCNET+1),
+ *(pktTag->PT_Data+IPXH_SRCNET+2),*(pktTag->PT_Data+IPXH_SRCNET+3),
+ *(pktTag->PT_Data+IPXH_SRCNODE),*(pktTag->PT_Data+IPXH_SRCNODE+1),
+ *(pktTag->PT_Data+IPXH_SRCNODE+2),*(pktTag->PT_Data+IPXH_SRCNODE+3),
+ *(pktTag->PT_Data+IPXH_SRCNODE+4),*(pktTag->PT_Data+IPXH_SRCNODE+5),
+ *(pktTag->PT_Data+IPXH_SRCSOCK),*(pktTag->PT_Data+IPXH_SRCNODE+1)));
+ // Spoof the packet if timeout has not been exceeded
+ KeAcquireSpinLock (&SpoofingQueueLock, &oldIRQL);
+ InsertTailList (&SpoofingQueue, &pktTag->PT_QueueLink);
+ if (!SpoofingWorkerActive
+ && EnterForwarder()) {
+ SpoofingWorkerActive = TRUE;
+ ExQueueWorkItem (&SpoofingWorker, DelayedWorkQueue);
+ }
+ KeReleaseSpinLock (&SpoofingQueueLock, oldIRQL);
+ // We will actually send this packet though
+ // in other direction, so mark it as pending
+ // to prevent ProcessSentPacket to be called
+ status = NDIS_STATUS_PENDING;
+ break;
+ }
+ // else don't spoof (fall through and fail the packet)
+ }
+ case FWD_OPER_STATE_DOWN:
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ status = NDIS_STATUS_ADAPTER_NOT_READY;
+ IpxFwdDbgPrint (DBG_SEND, DBG_WARNING,
+ ("IpxFwd: Failed external packet %08lx on if %ld(down?).\n",
+ pktTag, dstIf->ICB_Index));
+ break;
+ default:
+ ASSERTMSG ("Invalid operational state ", FALSE);
+ }
+ }
+ else {
+ IpxFwdDbgPrint (DBG_SEND, DBG_WARNING,
+ ("IpxFwd: Could not send packet %08lx on if %ld (quota exceeded).\n",
+ pktTag, dstIf->ICB_Index));
+ status = NDIS_STATUS_RESOURCES;
+ }
+
+ if (status!=NDIS_STATUS_PENDING)
+ ProcessSentPacket (dstIf, pktTag, status);
+}
+
+/*++
+*******************************************************************
+ F w S e n d C o m p l e t e
+
+Routine Description:
+ Called by IPX stack when send completes asynchronously
+Arguments:
+ pktDscr - descriptor of the completed packet
+ status - result of send operation
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+IpxFwdSendComplete (
+ PNDIS_PACKET pktDscr,
+ NDIS_STATUS status
+ ) {
+ PPACKET_TAG pktTag;
+ PNDIS_BUFFER bufDscr;
+
+ pktTag = (PPACKET_TAG)pktDscr->ProtocolReserved;
+
+ NdisUnchainBufferAtFront (pktDscr, &bufDscr);
+ ASSERT (bufDscr==pktTag->PT_MacHdrBufDscr);
+
+ NdisQueryPacket(pktDscr,
+ NULL,
+ NULL,
+ &bufDscr,
+ NULL);
+ NdisAdjustBufferLength(bufDscr,
+ pktTag->PT_Segment->PS_SegmentList->SL_BlockSize);
+ NdisRecalculatePacketCounts (pktDscr);
+#if DBG
+ {
+ KIRQL oldIRQL;
+ KeAcquireSpinLock (&pktTag->PT_InterfaceReference->ICB_Lock, &oldIRQL);
+ RemoveEntryList (&pktTag->PT_QueueLink);
+ KeReleaseSpinLock (&pktTag->PT_InterfaceReference->ICB_Lock, oldIRQL);
+ }
+#endif
+ ProcessSentPacket (pktTag->PT_InterfaceReference, pktTag, status);
+ LeaveForwarder (); // Entered before calling IpxSendPacket
+}
+
+
+/*++
+*******************************************************************
+
+ F w I n t e r n a l S e n d
+
+Routine Description:
+ Filter and routes packets sent by IPX stack
+Arguments:
+ LocalTarget - the NicId and next hop router MAC address
+ Context - preferred interface on which to send
+ Packet - packet to be sent
+ ipxHdr - pointer to ipx header inside the packet
+ PacketLength - length of the packet
+ fIterate - a flag to indicate if this is a packet for the
+ iteration of which the Fwd takes responsibility
+ - typically type 20 NetBIOS frames
+Return Value:
+
+ STATUS_SUCCESS - if the preferred NIC was OK and packet passed filtering
+ STATUS_NETWORK_UNREACHABLE - if the preferred was not OK or packet failed filtering
+ STATUS_PENDING - packet was queued until connection is established
+*******************************************************************
+--*/
+NTSTATUS
+IpxFwdInternalSend (
+ IN OUT PIPX_LOCAL_TARGET LocalTarget,
+ IN ULONG Context,
+ IN PNDIS_PACKET pktDscr,
+ IN PUCHAR ipxHdr,
+ IN PUCHAR data,
+ IN ULONG PacketLength,
+ IN BOOLEAN fIterate
+ ) {
+ PINTERFACE_CB dstIf = NULL, // Initialized to indicate
+ // first path through the iteration
+ // as well as the fact the we do not
+ // know it initially
+ stDstIf; // Static destination for
+ // NetBIOS names
+ PFWD_ROUTE fwRoute = NULL;
+ ULONG dstNet;
+ USHORT dstSock;
+ NTSTATUS status;
+
+ if (!EnterForwarder())
+ return STATUS_NETWORK_UNREACHABLE;
+
+ if (IS_IF_ENABLED(InternalInterface)
+ && ((*(ipxHdr+IPXH_PKTTYPE) != IPX_NETBIOS_TYPE)
+ || InternalInterface->ICB_NetbiosAccept)) {
+
+ do { // Big loop used to iterate over interfaces
+ status = STATUS_SUCCESS; // Assume success
+ if (!fIterate) {
+ dstNet = GETULONG (ipxHdr+IPXH_DESTNET);
+
+ if (Context!=INVALID_CONTEXT_VALUE) {
+ if (Context!=VIRTUAL_NET_FORWARDER_CONTEXT) {
+ // IPX driver supplied interface context, just verify that it
+ // exists and can be used to reach the destination network
+ dstIf = InterfaceContextToReference ((PVOID)Context,
+ LocalTarget->NicId);
+ }
+ else {
+ dstIf = InternalInterface;
+ AcquireInterfaceReference (dstIf);
+ }
+ if (dstIf!=NULL) {
+ // It does exist
+ // First process direct connections
+ if ((dstNet==0)
+ || (dstNet==dstIf->ICB_Network)) {
+ NOTHING;
+ }
+ else { // Network is not connected directly
+ PINTERFACE_CB dstIf2;
+ // Verify the route
+ dstIf2 = FindDestination (dstNet,
+ ipxHdr+IPXH_DESTNODE,
+ &fwRoute);
+ if (dstIf==dstIf2) {
+ // Route OK, release the extra interface reference
+ ReleaseInterfaceReference (dstIf2);
+ }
+ else {
+ // Route not OK, release interface/route references
+ InterlockedIncrement (&InternalInterface->ICB_Stats.InNoRoutes);
+ IpxFwdDbgPrint (DBG_INT_SEND, DBG_WARNING,
+ ("IpxFwd: Failed direct internal send on"
+ " if %ld to %08lx:%02x%02x%02x%02x%02x%02x"
+ " (no route).\n",
+ dstIf->ICB_Index, dstNet,
+ LocalTarget->MacAddress[0],
+ LocalTarget->MacAddress[1],
+ LocalTarget->MacAddress[2],
+ LocalTarget->MacAddress[3],
+ LocalTarget->MacAddress[4],
+ LocalTarget->MacAddress[5]));
+ if (dstIf2!=NULL) {
+ ReleaseInterfaceReference (dstIf2);
+ }
+ status = STATUS_NETWORK_UNREACHABLE;
+ break;
+ }
+ }
+ }
+ else {
+ InterlockedIncrement (&InternalInterface->ICB_Stats.InDiscards);
+ IpxFwdDbgPrint (DBG_INT_SEND, DBG_WARNING,
+ ("IpxFwd: Invalid interface context (%08lx)"
+ " from IPX driver on internal send to"
+ " %08lx:%02x%02x%02x%02x%02x%02x.\n",
+ Context, dstNet,
+ LocalTarget->MacAddress[0],
+ LocalTarget->MacAddress[1],
+ LocalTarget->MacAddress[2],
+ LocalTarget->MacAddress[3],
+ LocalTarget->MacAddress[4],
+ LocalTarget->MacAddress[5]));
+ status = STATUS_NO_SUCH_DEVICE;
+ break;
+ }
+ }
+ else {// No interface context supplied by IPX driver, have to find the route
+ dstIf = FindDestination (dstNet, ipxHdr+IPXH_DESTNODE,
+ &fwRoute);
+ if (dstIf!=NULL)
+ NOTHING;
+ else {
+ InterlockedIncrement (&InternalInterface->ICB_Stats.InNoRoutes);
+ IpxFwdDbgPrint (DBG_INT_SEND, DBG_WARNING,
+ ("IpxFwd: Failed internal send because no route to"
+ " %08lx:%02x%02x%02x%02x%02x%02x exists.\n",
+ LocalTarget->MacAddress[0],
+ LocalTarget->MacAddress[1],
+ LocalTarget->MacAddress[2],
+ LocalTarget->MacAddress[3],
+ LocalTarget->MacAddress[4],
+ LocalTarget->MacAddress[5]));
+ status = STATUS_NETWORK_UNREACHABLE;
+ break;
+ }
+ }
+ InterlockedIncrement (&InternalInterface->ICB_Stats.InDelivers);
+ }
+ else { // Iterative sends
+ dstNet = 0; // Don't care, it must be a local send
+ if (*(ipxHdr+IPXH_PKTTYPE) == IPX_NETBIOS_TYPE) {
+ if (dstIf==NULL) { // First time through internal loop
+ dstSock = GETUSHORT (ipxHdr+IPXH_DESTSOCK);
+
+ // See if we can get a static route for this packet
+ if (dstSock==IPX_NETBIOS_SOCKET)
+ stDstIf = FindNBDestination (data+(NB_NAME-IPXH_HDRSIZE));
+ else if (dstSock==IPX_SMB_NAME_SOCKET)
+ stDstIf = FindNBDestination (data+(SMB_NAME-IPXH_HDRSIZE));
+ else
+ stDstIf = NULL;
+ }
+
+ if ((Context==INVALID_CONTEXT_VALUE) && (dstIf==NULL)) {
+ // First time through the loop, increment counters
+ InterlockedIncrement (&InternalInterface->ICB_Stats.InDelivers);
+ InterlockedIncrement (&InternalInterface->ICB_Stats.NetbiosSent);
+
+ if (stDstIf!=NULL) {
+ dstIf = stDstIf;
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
+ ("IpxFwd: Allowed internal NB broadcast (1st iteration) on if %d (%lx)"
+ " to static name %.16s.\n",
+ dstIf->ICB_Index, dstIf,
+ (dstSock==IPX_NETBIOS_SOCKET)
+ ? data+(NB_NAME-IPXH_HDRSIZE)
+ : ((dstSock==IPX_SMB_NAME_SOCKET)
+ ? data+(SMB_NAME-IPXH_HDRSIZE)
+ : "Not a name frame")
+ ));
+ }
+ else { // No static route
+ dstIf = GetNextInterfaceReference (NULL);
+ if (dstIf!=NULL)
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
+ ("IpxFwd: Allowed internal nb broadcast (1st iteration) on if %d (%lx),"
+ " to name %.16s.\n",
+ dstIf->ICB_Index, dstIf,
+ (dstSock==IPX_NETBIOS_SOCKET)
+ ? data+(NB_NAME-IPXH_HDRSIZE)
+ : ((dstSock==IPX_SMB_NAME_SOCKET)
+ ? data+(SMB_NAME-IPXH_HDRSIZE)
+ : "Not a name frame")
+ ));
+ else {
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
+ ("IpxFwd: Nb broadcast no destinations"
+ " to name %.16s.\n",
+ (dstSock==IPX_NETBIOS_SOCKET)
+ ? data+(NB_NAME-IPXH_HDRSIZE)
+ : ((dstSock==IPX_SMB_NAME_SOCKET)
+ ? data+(SMB_NAME-IPXH_HDRSIZE)
+ : "Not a name frame")
+ ));
+ status = STATUS_NETWORK_UNREACHABLE;
+ break;
+ }
+ }
+ }
+ else {
+ // N-th iteration
+ if (stDstIf==NULL) {
+ if (dstIf==NULL)
+ dstIf = InterfaceContextToReference ((PVOID)Context,
+ LocalTarget->NicId);
+ dstIf = GetNextInterfaceReference (dstIf);
+ if (dstIf!=NULL) {
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
+ ("IpxFwd: Allowed internal NB broadcast (1+ iteration)"
+ " on if %d (%lx, ctx: %08lx, nic: %d)"
+ " to name %.16s.\n",
+ dstIf->ICB_Index, dstIf,
+ Context, LocalTarget->NicId,
+ (dstSock==IPX_NETBIOS_SOCKET)
+ ? data+(NB_NAME-IPXH_HDRSIZE)
+ : ((dstSock==IPX_SMB_NAME_SOCKET)
+ ? data+(SMB_NAME-IPXH_HDRSIZE)
+ : "Not a name frame")
+ ));
+ }
+ else {
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
+ ("IpxFwd: NB broadcast no more iterations"
+ " for ctx: %08lx, nic: %d"
+ " to name %.16s.\n",
+ Context, LocalTarget->NicId,
+ (dstSock==IPX_NETBIOS_SOCKET)
+ ? data+(NB_NAME-IPXH_HDRSIZE)
+ : ((dstSock==IPX_SMB_NAME_SOCKET)
+ ? data+(SMB_NAME-IPXH_HDRSIZE)
+ : "Not a name frame")
+ ));
+ status = STATUS_NETWORK_UNREACHABLE;
+ break;
+ }
+ }
+ else {
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
+ ("IpxFwd: Static NB broadcast (1+ iteration)"
+ " on if %d (%lx, ctx: %08lx, nic: %d)"
+ " to name %.16s.\n",
+ stDstIf->ICB_Index, stDstIf,
+ Context, LocalTarget->NicId,
+ (dstSock==IPX_NETBIOS_SOCKET)
+ ? data+(NB_NAME-IPXH_HDRSIZE)
+ : ((dstSock==IPX_SMB_NAME_SOCKET)
+ ? data+(SMB_NAME-IPXH_HDRSIZE)
+ : "Not a name frame")
+ ));
+ ReleaseInterfaceReference (stDstIf);
+ status = STATUS_NETWORK_UNREACHABLE;
+ break;
+ }
+ }
+ }
+ else {
+ if ((dstIf==NULL)
+ && (Context!=INVALID_CONTEXT_VALUE))
+ dstIf = InterfaceContextToReference ((PVOID)Context,
+ LocalTarget->NicId);
+ dstIf = GetNextInterfaceReference (dstIf);
+ if (dstIf!=NULL) {
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
+ ("IpxFwd: Allowed internal iterative send"
+ " on if %d (%lx, ctx: %08lx, nic: %d)"
+ " to %02x%02x%02x%02x%02x%02x.\n",
+ dstIf->ICB_Index, dstIf,
+ Context, LocalTarget->NicId,
+ LocalTarget->MacAddress[0],
+ LocalTarget->MacAddress[1],
+ LocalTarget->MacAddress[2],
+ LocalTarget->MacAddress[3],
+ LocalTarget->MacAddress[4],
+ LocalTarget->MacAddress[5]));
+
+ }
+ else {
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
+ ("IpxFwd: No destinations to internal iterative send"
+ " for ctx: %08lx, nic: %d"
+ " to %02x%02x%02x%02x%02x%02x.\n",
+ Context, LocalTarget->NicId,
+ LocalTarget->MacAddress[0],
+ LocalTarget->MacAddress[1],
+ LocalTarget->MacAddress[2],
+ LocalTarget->MacAddress[3],
+ LocalTarget->MacAddress[4],
+ LocalTarget->MacAddress[5]));
+ status = STATUS_NETWORK_UNREACHABLE;
+ break;
+ }
+ }
+
+ } // End iterative send processing
+
+ // We were able to find a destination interface
+ if (IS_IF_ENABLED (dstIf)
+ && ((*(ipxHdr+IPXH_PKTTYPE) != IPX_NETBIOS_TYPE)
+ || (dstIf->ICB_NetbiosDeliver==FWD_NB_DELIVER_ALL)
+ || ((dstIf->ICB_NetbiosDeliver==FWD_NB_DELIVER_IF_UP)
+ && (dstIf->ICB_Stats.OperationalState==FWD_OPER_STATE_UP))
+ || ((stDstIf!=NULL)
+ && (dstIf->ICB_NetbiosDeliver==FWD_NB_DELIVER_STATIC)))) {
+ KIRQL oldIRQL;
+ FILTER_ACTION action;
+
+ // In/Out filter check and statistics update
+
+ action = FltFilter (ipxHdr, IPXH_HDRSIZE,
+ InternalInterface->ICB_FilterInContext,
+ dstIf->ICB_FilterOutContext);
+ if (action==FILTER_PERMIT) {
+ NOTHING;
+ }
+ else {
+ InterlockedIncrement (&dstIf->ICB_Stats.OutFiltered);
+ status = STATUS_NETWORK_UNREACHABLE;
+ break;
+ }
+
+ KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
+ // All set, try to send now
+ switch (dstIf->ICB_Stats.OperationalState) {
+ case FWD_OPER_STATE_UP:
+ // Interface is up, let it go right away
+ // Set NIC ID
+ if (dstIf!=InternalInterface) {
+ ADAPTER_CONTEXT_TO_LOCAL_TARGET (
+ dstIf->ICB_AdapterContext,
+ LocalTarget);
+ }
+ else {
+ CONSTANT_ADAPTER_CONTEXT_TO_LOCAL_TARGET (
+ VIRTUAL_NET_ADAPTER_CONTEXT,
+ LocalTarget);
+ }
+ // Set destination node
+ if (IsLocalSapNonAgentAdvertisement (ipxHdr,data,PacketLength,dstIf)) {
+ // Loop back sap ads from non-sap socket
+ IPX_NODE_CPY (&LocalTarget->MacAddress,
+ dstIf->ICB_LocalNode);
+ }
+ else if ((dstNet==0) || (dstNet==dstIf->ICB_Network)) {
+ // Direct connection: send to destination specified
+ // in the header
+ IPX_NODE_CPY (LocalTarget->MacAddress,
+ ipxHdr+IPXH_DESTNODE);
+ }
+ else { // Indirect connection: send to next hop router
+ if (dstIf->ICB_InterfaceType==FWD_IF_PERMANENT) {
+ ASSERT (fwRoute!=NULL);
+ IPX_NODE_CPY (LocalTarget->MacAddress,
+ fwRoute->FR_NextHopAddress);
+ }
+ else {
+ // Only one peer on the other side
+ IPX_NODE_CPY (LocalTarget->MacAddress,
+ dstIf->ICB_RemoteNode);
+ }
+ }
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ // Update statistics
+ InterlockedIncrement (
+ &dstIf->ICB_Stats.OutDelivers);
+ if (*(ipxHdr+IPXH_PKTTYPE)==IPX_NETBIOS_TYPE)
+ InterlockedIncrement (
+ &dstIf->ICB_Stats.NetbiosSent);
+
+ IpxFwdDbgPrint (DBG_INT_SEND, DBG_INFORMATION,
+ ("IpxFwd: Allowed internal send:"
+ " %ld-%08lx:%02x%02x%02x%02x%02x%02x.\n",
+ dstIf->ICB_Index, dstNet,
+ LocalTarget->MacAddress[0],
+ LocalTarget->MacAddress[1],
+ LocalTarget->MacAddress[2],
+ LocalTarget->MacAddress[3],
+ LocalTarget->MacAddress[4],
+ LocalTarget->MacAddress[5]));
+ // status = STATUS_SUCCESS; // Let it go
+ break;
+ case FWD_OPER_STATE_SLEEPING:
+ // Interface is disconnected, queue the packet and try to connecte
+ if ((*(ipxHdr+IPXH_PKTTYPE)!=0)
+ || (*(ipxHdr+IPXH_LENGTH)!=IPXH_HDRSIZE+2)
+ || (*(data+1)!='?')) {
+ // Not a keep-alive packet,
+ if (((*(ipxHdr+IPXH_PKTTYPE)!=IPX_NETBIOS_TYPE))
+ || (dstIf->ICB_NetbiosDeliver!=FWD_NB_DELIVER_IF_UP)) {
+ // Not a netbios broadcast or we are allowed to connect
+ // the interface to deliver netbios broadcasts
+ if (InterlockedDecrement (&dstIf->ICB_PendingQuota)>=0) {
+ PINTERNAL_PACKET_TAG pktTag;
+ // Create a queue element to enqueue the packet
+ pktTag = (PINTERNAL_PACKET_TAG)ExAllocatePoolWithTag (
+ NonPagedPool,
+ sizeof (INTERNAL_PACKET_TAG),
+ FWD_POOL_TAG);
+ if (pktTag!=NULL) {
+ pktTag->IPT_Packet = pktDscr;
+ pktTag->IPT_Length = PacketLength;
+ pktTag->IPT_DataPtr = ipxHdr;
+ // Save next hop address if after connection is
+ // established we determine that destination net
+ // is not connected directly
+ if (fwRoute!=NULL)
+ IPX_NODE_CPY (pktTag->IPT_Target.MacAddress,
+ fwRoute->FR_NextHopAddress);
+ AcquireInterfaceReference (dstIf); // To make sure interface
+ // block won't go away until we are done with
+ // the packet
+ pktTag->IPT_InterfaceReference = dstIf;
+ InsertTailList (&dstIf->ICB_InternalQueue,
+ &pktTag->IPT_QueueLink);
+ if (!IS_IF_CONNECTING (dstIf)) {
+ QueueConnectionRequest (dstIf, pktDscr, ipxHdr, oldIRQL);
+ IpxFwdDbgPrint (DBG_DIALREQS, DBG_WARNING,
+ ("IpxFwd: Queued dd request on if %ld (ifCB:%08lx)"
+ " for internal packet"
+ " to %02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%02x%02x"
+ " from socket:%02x%02x\n",
+ dstIf->ICB_Index, dstIf,
+ *(ipxHdr+6),*(ipxHdr+7),
+ *(ipxHdr+8),*(ipxHdr+9),
+ *(ipxHdr+10),*(ipxHdr+11),
+ *(ipxHdr+12),*(ipxHdr+13),
+ *(ipxHdr+14),*(ipxHdr+15),
+ *(ipxHdr+16),*(ipxHdr+17),
+ *(ipxHdr+28),*(ipxHdr+29)));
+ }
+ else
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ IpxFwdDbgPrint (DBG_INT_SEND, DBG_INFORMATION,
+ ("IpxFwd: Queueing internal send packet %08lx on if %ld.\n",
+ pktTag, dstIf->ICB_Index));
+ status = STATUS_PENDING;
+ break;
+ }
+ else {
+ IpxFwdDbgPrint (DBG_INT_SEND, DBG_ERROR,
+ ("IpxFwd: Could not allocate"
+ " internal packet tag.\n"));
+ }
+ }
+ InterlockedIncrement (&dstIf->ICB_PendingQuota);
+ }
+ else {
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_WARNING,
+ ("IpxFwd: Droped internal NB packet"
+ " because FWD_NB_DELIVER_IF_UP.\n"));
+ }
+ }
+ else { // Process keep-alives
+ LONGLONG curTime;
+ KeQuerySystemTime ((PLARGE_INTEGER)&curTime);
+ if (((curTime-dstIf->ICB_DisconnectTime)/10000000) < SpoofingTimeout) {
+ PPACKET_TAG pktTag;
+ // Spoofing timeout has not been exceeded,
+ // Create a reply packet
+ AllocatePacket (WanPacketListId,
+ WanPacketListId,
+ pktTag);
+ if (pktTag!=NULL) {
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ PUTUSHORT (0xFFFF, pktTag->PT_Data+IPXH_CHECKSUM);
+ PUTUSHORT (IPXH_HDRSIZE+2, pktTag->PT_Data+IPXH_LENGTH);
+ *(pktTag->PT_Data+IPXH_XPORTCTL) = 0;
+ *(pktTag->PT_Data+IPXH_PKTTYPE) = 0;
+ memcpy (pktTag->PT_Data+IPXH_DESTADDR,
+ ipxHdr+IPXH_SRCADDR,
+ 12);
+ memcpy (pktTag->PT_Data+IPXH_SRCADDR,
+ ipxHdr+IPXH_DESTADDR,
+ 12);
+ *(pktTag->PT_Data+IPXH_HDRSIZE) = *data;
+ *(pktTag->PT_Data+IPXH_HDRSIZE+1) = 'Y';
+ // Destination for this packet will have to
+ // be the first active LAN adapter in the system
+ // SHOULD BE REMOVED WHEN LOOPBACK SUPPORT US ADDED BY IPX
+
+ pktTag->PT_InterfaceReference = NULL;
+ IpxFwdDbgPrint (DBG_SPOOFING, DBG_INFORMATION,
+ ("IpxFwd: Queueing reply to keepalive from internal server"
+ " at %02x%02x.\n",*(ipxHdr+IPXH_DESTSOCK),*(ipxHdr+IPXH_DESTSOCK+1)));
+ // Enqueue to spoofing queue to be sent back
+ // to the server
+ KeAcquireSpinLock (&SpoofingQueueLock, &oldIRQL);
+ InsertTailList (&SpoofingQueue, &pktTag->PT_QueueLink);
+ // Start worker if not running already
+ if (!SpoofingWorkerActive
+ && EnterForwarder()) {
+ SpoofingWorkerActive = TRUE;
+ ExQueueWorkItem (&SpoofingWorker, DelayedWorkQueue);
+ }
+ KeReleaseSpinLock (&SpoofingQueueLock, oldIRQL);
+ status = STATUS_DROP_SILENTLY;
+ break;
+ }
+ else {
+ IpxFwdDbgPrint (DBG_SPOOFING, DBG_ERROR,
+ ("IpxFwd: Could not allocate"
+ " packet tag for spoofing.\n"));
+ }
+ }
+ else {
+ IpxFwdDbgPrint (DBG_SPOOFING, DBG_WARNING,
+ ("IpxFwd: Internal spoofing"
+ " timeout exceded.\n"));
+ }
+ }
+ case FWD_OPER_STATE_DOWN:
+ // Interface down or send failed
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ if (*(ipxHdr+IPXH_PKTTYPE)!=IPX_NETBIOS_TYPE)
+ InterlockedIncrement (
+ &dstIf->ICB_Stats.OutDiscards);
+ IpxFwdDbgPrint (DBG_INT_SEND, DBG_WARNING,
+ ("IpxFwd: Internal send not allowed"
+ " on if %ld (down?).\n", dstIf->ICB_Index));
+ status = STATUS_NETWORK_UNREACHABLE;
+ break;
+ default:
+ ASSERTMSG ("Invalid operational state ", FALSE);
+ }
+ }
+ else {// Interface is disabled
+ if (*(ipxHdr+IPXH_PKTTYPE)!=IPX_NETBIOS_TYPE)
+ InterlockedIncrement (&dstIf->ICB_Stats.OutDiscards);
+ IpxFwdDbgPrint (DBG_INT_SEND, DBG_WARNING,
+ ("IpxFwd: Internal send not allowed"
+ " on because dst if (or Netbios deliver on it) %ld (ifCB: %08lx) is disabled.\n",
+ dstIf->ICB_Index, dstIf));
+ status = STATUS_NETWORK_UNREACHABLE;
+ }
+
+
+ }
+ while (fIterate && (status!=STATUS_SUCCESS) && (status!=STATUS_PENDING));
+
+ if (dstIf!=NULL)
+ ReleaseInterfaceReference (dstIf);
+ if (fwRoute!=NULL)
+ ReleaseRouteReference (fwRoute);
+ }
+ else { // Internal interface is disabled
+ IpxFwdDbgPrint (DBG_INT_SEND, DBG_WARNING,
+ ("IpxFwd: Internal send not allowed"
+ " because internal if (or Netbios accept on it) is disabled.\n"));
+ InterlockedIncrement (
+ &InternalInterface->ICB_Stats.InDiscards);
+ status = STATUS_NETWORK_UNREACHABLE;
+ }
+
+ LeaveForwarder ();
+ return status;
+}
+
+
+/*++
+*******************************************************************
+
+ P r o c e s s I n t e r n a l Q u e u e
+
+Routine Description:
+ Processes packets in the interface internal queue.
+ Called when connection request completes
+Arguments:
+ dstIf - interface to process
+Return Value:
+ None
+*******************************************************************
+--*/
+VOID
+ProcessInternalQueue (
+ PINTERFACE_CB dstIf
+ ) {
+ KIRQL oldIRQL;
+ LIST_ENTRY tempQueue;
+
+ KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
+ InsertHeadList (&dstIf->ICB_InternalQueue, &tempQueue);
+ RemoveEntryList (&dstIf->ICB_InternalQueue);
+ InitializeListHead (&dstIf->ICB_InternalQueue);
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+
+ while (!IsListEmpty (&tempQueue)) {
+ PINTERNAL_PACKET_TAG pktTag;
+ PLIST_ENTRY cur;
+ NTSTATUS status;
+
+ cur = RemoveHeadList (&tempQueue);
+ pktTag = CONTAINING_RECORD (cur, INTERNAL_PACKET_TAG, IPT_QueueLink);
+ InterlockedIncrement (&dstIf->ICB_PendingQuota);
+
+ KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
+ if (IS_IF_ENABLED(dstIf)
+ && (dstIf->ICB_Stats.OperationalState==FWD_OPER_STATE_UP)) {
+ IPX_NODE_CPY (pktTag->IPT_Target.MacAddress,
+ dstIf->ICB_RemoteNode);
+ ADAPTER_CONTEXT_TO_LOCAL_TARGET (
+ dstIf->ICB_AdapterContext,
+ &pktTag->IPT_Target);
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ InterlockedIncrement (&dstIf->ICB_Stats.OutDelivers);
+ if (*(pktTag->IPT_DataPtr + IPXH_PKTTYPE) == IPX_NETBIOS_TYPE) {
+ InterlockedIncrement (&dstIf->ICB_Stats.NetbiosSent);
+ }
+ status = STATUS_SUCCESS;
+ }
+ else {
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ InterlockedIncrement (&dstIf->ICB_Stats.OutDiscards);
+ status = STATUS_NETWORK_UNREACHABLE;
+ }
+
+ IPXInternalSendCompletProc (&pktTag->IPT_Target,
+ pktTag->IPT_Packet,
+ pktTag->IPT_Length,
+ status);
+ IpxFwdDbgPrint (DBG_INT_SEND,
+ NT_SUCCESS (status) ? DBG_INFORMATION : DBG_WARNING,
+ ("IpxFwd: Returned internal packet %08lx"
+ " for send on if %ld with status %08lx.\n",
+ pktTag, dstIf->ICB_Index, status));
+ ReleaseInterfaceReference (pktTag->IPT_InterfaceReference);
+ ExFreePool (pktTag);
+ }
+}
+
+
+
+/*++
+*******************************************************************
+
+ P r o c e s s E x t e r n a l Q u e u e
+
+Routine Description:
+ Processes packets in the interface external queue.
+ Called when connection request completes
+Arguments:
+ dstIf - interface to process
+Return Value:
+ None
+*******************************************************************
+--*/
+VOID
+ProcessExternalQueue (
+ PINTERFACE_CB dstIf
+ ) {
+ KIRQL oldIRQL;
+ LIST_ENTRY tempQueue;
+
+ KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
+ InsertHeadList (&dstIf->ICB_ExternalQueue, &tempQueue);
+ RemoveEntryList (&dstIf->ICB_ExternalQueue);
+ InitializeListHead (&dstIf->ICB_ExternalQueue);
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+
+ while (!IsListEmpty (&tempQueue)) {
+ PPACKET_TAG pktTag;
+ PLIST_ENTRY cur;
+ NDIS_STATUS status;
+
+ cur = RemoveHeadList (&tempQueue);
+ pktTag = CONTAINING_RECORD (cur, PACKET_TAG, PT_QueueLink);
+
+ KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
+ if (IS_IF_ENABLED(dstIf)
+ && (dstIf->ICB_Stats.OperationalState==FWD_OPER_STATE_UP)) {
+ IPX_NODE_CPY (pktTag->PT_Target.MacAddress,
+ dstIf->ICB_RemoteNode);
+ if (*(pktTag->PT_Data + IPXH_PKTTYPE) == IPX_NETBIOS_TYPE) {
+ PUTULONG (dstIf->ICB_Network, pktTag->PT_Data+IPXH_DESTNET);
+ }
+ status = DoSend (dstIf, pktTag, oldIRQL);
+ IpxFwdDbgPrint (DBG_SEND, DBG_INFORMATION,
+ ("IpxFwd: Sent queued external packet %08lx if %ld.\n",
+ pktTag, dstIf->ICB_Index));
+ }
+ else {
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ IpxFwdDbgPrint (DBG_SEND, DBG_WARNING,
+ ("IpxFwd: Dropped queued external packet %08lx on dead if %ld.\n",
+ pktTag, dstIf->ICB_Index));
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ if (status!=STATUS_PENDING)
+ ProcessSentPacket (dstIf, pktTag, status);
+ }
+}
+
+
+/*++
+*******************************************************************
+
+ S p o o f e r
+
+Routine Description:
+ Processes packets in spoofing queue
+Arguments:
+ None
+Return Value:
+ None
+*******************************************************************
+--*/
+VOID
+Spoofer (
+ PVOID Context
+ ) {
+ KIRQL oldIRQL;
+ NTSTATUS status;
+ UNREFERENCED_PARAMETER (Context);
+
+ KeAcquireSpinLock (&SpoofingQueueLock, &oldIRQL);
+ // Keep going till queue is empty
+ while (!IsListEmpty (&SpoofingQueue)) {
+ PINTERFACE_CB dstIf;
+ PPACKET_TAG pktTag = CONTAINING_RECORD (SpoofingQueue.Flink,
+ PACKET_TAG,
+ PT_QueueLink);
+ RemoveEntryList (&pktTag->PT_QueueLink);
+ KeReleaseSpinLock (&SpoofingQueueLock, oldIRQL);
+ dstIf = pktTag->PT_InterfaceReference;
+ if (dstIf==NULL) {
+ // Replies for internal server require first active LAN adapter
+ // SHOULD BE REMOVED WHEN LOOPBACK SUPPORT US ADDED BY IPX
+ while ((dstIf=GetNextInterfaceReference (dstIf))!=NULL) {
+ KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
+ if (IS_IF_ENABLED (dstIf)
+ && (dstIf->ICB_Stats.OperationalState==FWD_OPER_STATE_UP)
+ && (dstIf->ICB_InterfaceType==FWD_IF_PERMANENT)) {
+ pktTag->PT_InterfaceReference = dstIf;
+ IPX_NODE_CPY (&pktTag->PT_Target.MacAddress, dstIf->ICB_LocalNode);
+ status = DoSend (dstIf, pktTag, oldIRQL); // releases spin lock
+ if (status!=STATUS_PENDING)
+ ProcessSentPacket (dstIf, pktTag, status);
+ break;
+ }
+ else
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ }
+ if (dstIf==NULL) {
+ FreePacket (pktTag);
+ }
+
+ }
+ else { // Reply for external server, interface is already known
+ UCHAR addr[12];
+ FILTER_ACTION action;
+ pktTag->PT_Flags &= (~PT_SOURCE_IF);
+
+ // Switch source and destination
+ memcpy (addr, pktTag->PT_Data+IPXH_DESTADDR, 12);
+ memcpy (pktTag->PT_Data+IPXH_DESTADDR,
+ pktTag->PT_Data+IPXH_SRCADDR, 12);
+ memcpy (pktTag->PT_Data+IPXH_SRCADDR, addr, 12);
+ // Say yes in reply
+ *(pktTag->PT_Data+IPXH_HDRSIZE+1) = 'Y';
+
+ action = FltFilter (pktTag->PT_Data,
+ GETUSHORT (pktTag->PT_Data+IPXH_LENGTH),
+ dstIf->ICB_FilterInContext,
+ pktTag->PT_SourceIf->ICB_FilterOutContext);
+ if (action==FILTER_PERMIT) {
+
+ // Release destination if and use source as destination
+ ReleaseInterfaceReference (dstIf);
+ dstIf = pktTag->PT_InterfaceReference = pktTag->PT_SourceIf;
+ // Send the packet if we can
+ KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
+ if (IS_IF_ENABLED (dstIf)
+ && (dstIf->ICB_Stats.OperationalState==FWD_OPER_STATE_UP)) {
+ status = DoSend (dstIf, pktTag, oldIRQL);
+ if (status!=STATUS_PENDING)
+ ProcessSentPacket (dstIf, pktTag, status);
+ }
+ else {
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ InterlockedIncrement (&dstIf->ICB_Stats.OutDiscards);
+ ReleaseInterfaceReference (dstIf);
+ FreePacket (pktTag);
+ }
+ }
+ else {
+ if (action==FILTER_DENY_OUT)
+ InterlockedIncrement (&pktTag->PT_SourceIf->ICB_Stats.OutFiltered);
+ else {
+ ASSERT (action==FILTER_DENY_IN);
+ InterlockedIncrement (&dstIf->ICB_Stats.InFiltered);
+ }
+ ReleaseInterfaceReference (dstIf);
+ ReleaseInterfaceReference (pktTag->PT_SourceIf);
+ FreePacket (pktTag);
+ }
+ }
+ KeAcquireSpinLock (&SpoofingQueueLock, &oldIRQL);
+ } // end while
+ SpoofingWorkerActive = FALSE;
+ KeReleaseSpinLock (&SpoofingQueueLock, oldIRQL);
+ LeaveForwarder ();
+}
+
+
diff --git a/private/ntos/tdi/isn/fwd/send.h b/private/ntos/tdi/isn/fwd/send.h
new file mode 100644
index 000000000..e46651e13
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/send.h
@@ -0,0 +1,220 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\send.c
+
+Abstract:
+ Send routines
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+#ifndef IPXFWD_SEND
+#define IPXFWD_SEND
+
+typedef struct _INTERNAL_PACKET_TAG {
+ LIST_ENTRY IPT_QueueLink;
+ PNDIS_PACKET IPT_Packet;
+ PUCHAR IPT_DataPtr;
+ ULONG IPT_Length;
+ PINTERFACE_CB IPT_InterfaceReference;
+ IPX_LOCAL_TARGET IPT_Target;
+} INTERNAL_PACKET_TAG, *PINTERNAL_PACKET_TAG;
+
+
+#define DEF_SPOOFING_TIMEOUT (120*60) // Seconds
+extern ULONG SpoofingTimeout;
+extern LIST_ENTRY SpoofingQueue;
+extern KSPIN_LOCK SpoofingQueueLock;
+extern WORK_QUEUE_ITEM SpoofingWorker;
+extern BOOLEAN SpoofingWorkerActive;
+extern ULONG DontSuppressNonAgentSapAdvertisements;
+VOID
+Spoofer (
+ PVOID Context
+ );
+
+#define InitializeSendQueue() { \
+ InitializeListHead (&SpoofingQueue); \
+ KeInitializeSpinLock (&SpoofingQueueLock); \
+ ExInitializeWorkItem (&SpoofingWorker, Spoofer, NULL); \
+ SpoofingWorkerActive = FALSE; \
+}
+
+#define DeleteSendQueue() { \
+ while (!IsListEmpty (&SpoofingQueue)) { \
+ PPACKET_TAG pktTag = CONTAINING_RECORD (SpoofingQueue.Flink, \
+ PACKET_TAG, \
+ PT_QueueLink); \
+ RemoveEntryList (&pktTag->PT_QueueLink); \
+ if (pktTag->PT_InterfaceReference!=NULL) \
+ ReleaseInterfaceReference (pktTag->PT_InterfaceReference); \
+ FreePacket (pktTag); \
+ } \
+}
+
+
+/*++
+*******************************************************************
+ S e n d P a c k e t
+
+Routine Description:
+ Enqueues packets to be sent by IPX stack
+Arguments:
+ dstIf - over which interface to send
+ pktTag - packet to send
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+SendPacket (
+ PINTERFACE_CB dstIf,
+ PPACKET_TAG pktTag
+ );
+
+/*++
+*******************************************************************
+ F w S e n d C o m p l e t e
+
+Routine Description:
+ Called by IPX stack when send completes asynchronously
+Arguments:
+ pktDscr - descriptor of the completed packet
+ status - result of send operation
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+IpxFwdSendComplete (
+ PNDIS_PACKET pktDscr,
+ NDIS_STATUS NdisStatus
+ );
+
+/*++
+*******************************************************************
+
+ F w I n t e r n a l S e n d
+
+Routine Description:
+ Filter and routes packets sent by IPX stack
+Arguments:
+ LocalTarget - the NicId and next hop router MAC address
+ Context - preferred interface on which to send
+ Packet - packet to be sent
+ ipxHdr - pointer to ipx header inside the packet
+ PacketLength - length of the packet
+ fIterate - a flag to indicate if this is a packet for the
+ iteration of which the Fwd takes responsibility
+ - typically type 20 NetBIOS frames
+
+Return Value:
+
+ STATUS_SUCCESS - if the preferred NIC was OK and packet passed filtering
+ STATUS_NETWORK_UNREACHABLE - if the preferred was not OK or packet failed filtering
+ STATUS_PENDING - packet was queued until connection is established
+*******************************************************************
+--*/
+NTSTATUS
+IpxFwdInternalSend (
+ IN OUT PIPX_LOCAL_TARGET LocalTarget,
+ IN ULONG Context,
+ IN PNDIS_PACKET pktDscr,
+ IN PUCHAR ipxHdr,
+ IN PUCHAR data,
+ IN ULONG PacketLength,
+ IN BOOLEAN fIterate
+ );
+
+/*++
+*******************************************************************
+
+ P r o c e s s I n t e r n a l Q u e u e
+
+Routine Description:
+ Processes packets in the interface internal queue.
+ Called when connection request completes
+Arguments:
+ dstIf - interface to process
+Return Value:
+ None
+*******************************************************************
+--*/
+VOID
+ProcessInternalQueue (
+ PINTERFACE_CB dstIf
+ );
+
+
+/*++
+*******************************************************************
+
+ P r o c e s s E x t e r n a l Q u e u e
+
+Routine Description:
+ Processes packets in the interface external queue.
+ Called when connection request completes
+Arguments:
+ dstIf - interface to process
+Return Value:
+ None
+*******************************************************************
+--*/
+VOID
+ProcessExternalQueue (
+ PINTERFACE_CB dstIf
+ );
+/*++
+*******************************************************************
+ D o S e n d
+
+Routine Description:
+ Prepares and sends packet. Interface lock must be help while
+ callin this routine
+Arguments:
+ dstIf - over which interface to send
+ pktTag - packet to send
+Return Value:
+ result returned by IPX
+
+*******************************************************************
+--*/
+NDIS_STATUS
+DoSend (
+ PINTERFACE_CB dstIf,
+ PPACKET_TAG pktTag,
+ KIRQL oldIRQL
+ );
+
+/*++
+*******************************************************************
+ P r o c e s s S e n t P a c k e t
+
+Routine Description:
+ Process completed sent packets
+Arguments:
+ dstIf - interface over which packet was sent
+ pktTag - completed packet
+ status - result of send operation
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+ProcessSentPacket (
+ PINTERFACE_CB dstIf,
+ PPACKET_TAG pktTag,
+ NDIS_STATUS status
+ );
+#endif
diff --git a/private/ntos/tdi/isn/fwd/sources.inc b/private/ntos/tdi/isn/fwd/sources.inc
new file mode 100644
index 000000000..3a7cd7ab5
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/sources.inc
@@ -0,0 +1,61 @@
+!IF 0
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author: Vadim Eydelman
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=nwlnkfwd
+TARGETTYPE=DRIVER
+
+TARGETLIBS=\
+ $(BASEDIR)\public\sdk\lib\*\tdi.lib \
+ $(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..\;..\..\inc;..\..\..\..\inc;..\..\..\..\..\inc
+
+C_DEFINES=$(C_DEFINES) -D_NTDRIVER_ -D_PNP_POWER
+
+!IFDEF BUILD_FOR_3_51
+C_DEFINES= $(C_DEFINES) -D_NTIFS_
+!ENDIF
+
+PRECOMPILED_INCLUDE=..\precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=..\driver.c \
+ ..\ipxbind.c \
+ ..\rcvind.c \
+ ..\send.c \
+ ..\registry.c \
+ ..\lineind.c \
+ ..\ddreqs.c \
+ ..\netbios.c \
+ ..\packets.c \
+ ..\tables.c \
+ ..\debug.c \
+ ..\filterif.c \
+ ..\nwlnkfwd.rc
+
+RELATIVE_DEPTH=..\..
+ALT_PROJECT_TARGET=Routing
+
+ \ No newline at end of file
diff --git a/private/ntos/tdi/isn/fwd/tables.c b/private/ntos/tdi/isn/fwd/tables.c
new file mode 100644
index 000000000..baec3cced
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/tables.c
@@ -0,0 +1,1512 @@
+
+#include "precomp.h"
+
+// Memory zone for interfaces
+ZONE_HEADER InterfaceZone;
+// Segment size in interface sone
+ULONG InterfaceSegmentSize=
+ sizeof(INTERFACE_CB)*NUM_INTERFACES_PER_SEGMENT
+ +sizeof (ZONE_SEGMENT_HEADER);
+KSPIN_LOCK InterfaceZoneLock;
+
+// Interface tables
+LIST_ENTRY *InterfaceIndexHash; // Hash by interface index
+PINTERFACE_CB *ClientNodeHash; // Hash by node on qlobal net
+INTERFACE_CB TheInternalInterface; // The internal interface
+PINTERFACE_CB InternalInterface=&TheInternalInterface;
+KSPIN_LOCK InterfaceTableLock; // Protection for interface hash tables
+
+// Memory Zone for routes
+ZONE_HEADER RouteZone;
+// Segment size in route sone
+ULONG RouteSegmentSize=DEF_ROUTE_SEGMENT_SIZE;
+KSPIN_LOCK RouteZoneLock;
+
+// Route tables
+PFWD_ROUTE *RouteHash;
+PFWD_ROUTE GlobalRoute;
+ULONG GlobalNetwork;
+
+
+// NB Route table
+PNB_ROUTE *NBRouteHash;
+
+
+// Reader-writer lock to wait for all readers to drain when
+// updating the route tables
+RW_LOCK RWLock;
+// Mutex to serialize writers to route tables
+FAST_MUTEX WriterMutex;
+
+
+// Sizes of the tables
+ULONG RouteHashSize; // Must be specified
+ULONG InterfaceHashSize=DEF_INTERFACE_HASH_SIZE;
+ULONG ClientHashSize=DEF_CLIENT_HASH_SIZE;
+ULONG NBRouteHashSize=DEF_NB_ROUTE_HASH_SIZE;
+
+//*** max send pkts queued limit: over this limit the send pkts get discarded
+ULONG MaxSendPktsQueued = MAX_SEND_PKTS_QUEUED;
+INT WanPacketListId = -1;
+
+// Initial memory block allocated for the tables
+CHAR *TableBlock = NULL;
+
+// Hash functions
+#define InterfaceIndexHashFunc(Interface) (Interface%InterfaceHashSize)
+#define ClientNodeHashFunc(Node64) ((UINT)(Node64%ClientHashSize))
+#define NetworkNumberHashFunc(Network) (Network%RouteHashSize)
+#define NetbiosNameHashFunc(Name128) ((UINT)(Name128[0]+Name128[1])%NBRouteHashSize)
+
+/*++
+*******************************************************************
+ A l l o c a t e R o u t e
+
+Routine Description:
+ Allocates memory for route from memory zone reserved
+ for route storage. Extends zone if there are no
+ free blocks in currently allocated segements.
+Arguments:
+ None
+Return Value:
+ Pointer to allocated route
+
+*******************************************************************
+--*/
+PFWD_ROUTE
+AllocateRoute (
+ void
+ ) {
+ PFWD_ROUTE fwRoute;
+ KIRQL oldIRQL;
+
+ KeAcquireSpinLock (&RouteZoneLock, &oldIRQL);
+ // Check if there are free blocks in the zone
+ if (ExIsFullZone (&RouteZone)) {
+ // Try to allocate new segment if not
+ NTSTATUS status;
+ PVOID segment = ExAllocatePoolWithTag
+ (NonPagedPool, RouteSegmentSize, FWD_POOL_TAG);
+ if (segment==NULL) {
+ KeReleaseSpinLock (&RouteZoneLock, oldIRQL);
+ IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_ERROR,
+ ("IpxFwd: Can't allocate route zone segment.\n"));
+ return NULL;
+ }
+ status = ExExtendZone (&RouteZone, segment, RouteSegmentSize);
+ ASSERTMSG ("Could not extend RouteZone ", NT_SUCCESS (status));
+ }
+ fwRoute = (PFWD_ROUTE)ExAllocateFromZone (&RouteZone);
+ KeReleaseSpinLock (&RouteZoneLock, oldIRQL);
+ return fwRoute;
+}
+
+/*++
+*******************************************************************
+ F r e e R o u t e
+
+Routine Description:
+ Releases memory allocated for route to route memory
+ zone.
+Arguments:
+ fwRoute - route block to release
+Return Value:
+ None
+*******************************************************************
+--*/
+VOID
+FreeRoute (
+ PFWD_ROUTE fwRoute
+ ) {
+ IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_INFORMATION,
+ ("IpxFwd: Freeing route block %08lx.\n", fwRoute));
+ ASSERT (fwRoute->FR_InterfaceReference==NULL);
+ ExInterlockedFreeToZone(&RouteZone,fwRoute,&RouteZoneLock);
+}
+
+
+/*++
+*******************************************************************
+ A l l o c a t e I n t e r f a c e
+
+Routine Description:
+ Allocates memory for interface from memory zone reserved
+ for interface storage. Extends zone if there are no
+ free blocks in currently allocated segements.
+Arguments:
+ None
+Return Value:
+ Pointer to allocated route
+
+*******************************************************************
+--*/
+PINTERFACE_CB
+AllocateInterface (
+ void
+ ) {
+ PINTERFACE_CB ifCB;
+ KIRQL oldIRQL;
+
+ KeAcquireSpinLock (&RouteZoneLock, &oldIRQL);
+ // Check if there are free blocks in the zone
+ if (ExIsFullZone (&InterfaceZone)) {
+ // Try to allocate new segment if not
+ NTSTATUS status;
+ PVOID segment = ExAllocatePoolWithTag
+ (NonPagedPool, InterfaceSegmentSize, FWD_POOL_TAG);
+ if (segment==NULL) {
+ KeReleaseSpinLock (&RouteZoneLock, oldIRQL);
+ IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR,
+ ("IpxFwd: Can't allocate interface zone segment.\n"));
+ return NULL;
+ }
+ status = ExExtendZone (&InterfaceZone, segment, InterfaceSegmentSize);
+ ASSERTMSG ("Could not extend InterfaceZone ", NT_SUCCESS (status));
+ }
+ ifCB = (PINTERFACE_CB)ExAllocateFromZone (&InterfaceZone);
+ KeReleaseSpinLock (&RouteZoneLock, oldIRQL);
+ return ifCB;
+}
+
+/*++
+*******************************************************************
+ F r e e I n t e r f a c e
+
+Routine Description:
+ Releases memory allocated for interface to interface memory
+ zone.
+Arguments:
+ fwRoute - route block to release
+Return Value:
+ None
+*******************************************************************
+--*/
+VOID
+FreeInterface (
+ PINTERFACE_CB ifCB
+ ) {
+ KIRQL oldIRQL;
+
+ IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
+ ("IpxFwd: Freeing icb %08lx.\n", ifCB));
+
+ ASSERT(ifCB->ICB_Stats.OperationalState==FWD_OPER_STATE_DOWN);
+ KeAcquireSpinLock (&InterfaceZoneLock, &oldIRQL);
+ ExFreeToZone(&InterfaceZone, ifCB);
+ KeReleaseSpinLock (&InterfaceZoneLock, oldIRQL);
+}
+
+/*++
+*******************************************************************
+ C r e a t e T a b l e s
+
+Routine Description:
+ Allocates and intializes all hash tables and related structures
+Arguments:
+ None
+Return Value:
+ STATUS_SUCCESS - tables were created ok
+ STATUS_INSUFFICIENT_RESOURCES - resource allocation failed
+*******************************************************************
+--*/
+NTSTATUS
+CreateTables (
+ void
+ ) {
+ UINT i;
+ CHAR *segment;
+ NTSTATUS status;
+ ULONG blockSize;
+
+ ASSERT (TableBlock==NULL);
+
+ blockSize = ROUND_TO_PAGES (
+ InterfaceHashSize*sizeof(*InterfaceIndexHash)
+ +ClientHashSize*sizeof(*ClientNodeHash)
+ +RouteHashSize*sizeof(*RouteHash)
+ +NBRouteHashSize*sizeof(*NBRouteHash)
+ +InterfaceSegmentSize
+ +RouteSegmentSize
+ );
+
+ // Allocate first segment for route zone
+ TableBlock = segment = (CHAR *)ExAllocatePoolWithTag (
+ NonPagedPool, blockSize, FWD_POOL_TAG);
+ if (segment!=NULL) {
+ InterfaceIndexHash = (LIST_ENTRY *)segment;
+ segment = (CHAR *)ALIGN_UP((ULONG)(InterfaceIndexHash+InterfaceHashSize),ULONGLONG);
+
+ ClientNodeHash = (PINTERFACE_CB *)segment;
+ segment = (CHAR *)ALIGN_UP((ULONG)(ClientNodeHash+ClientHashSize),ULONGLONG);
+
+ RouteHash = (PFWD_ROUTE *)segment;
+ segment = (CHAR *)ALIGN_UP((ULONG)(RouteHash + RouteHashSize),ULONGLONG);
+
+ NBRouteHash = (PNB_ROUTE *)segment;
+ segment = (CHAR *)ALIGN_UP((ULONG)(NBRouteHash + NBRouteHashSize),ULONGLONG);
+
+ status = ExInitializeZone (&InterfaceZone,
+ ALIGN_UP(sizeof (INTERFACE_CB),ULONGLONG),
+ segment,
+ InterfaceSegmentSize);
+ ASSERTMSG ("Could not initalize InterfaceZone ",
+ NT_SUCCESS (status));
+ segment = (CHAR *)ALIGN_UP((ULONG)(segment+InterfaceSegmentSize),ULONGLONG);
+
+ status = ExInitializeZone (&RouteZone,
+ ALIGN_UP(sizeof (FWD_ROUTE), ULONGLONG),
+ segment,
+ blockSize - (segment - TableBlock));
+
+ ASSERTMSG ("Could not initalize RouteZone ", NT_SUCCESS (status));
+
+
+ // No global route yet
+ GlobalRoute = NULL;
+ GlobalNetwork = 0xFFFFFFFF;
+
+ InternalInterface = &TheInternalInterface;
+ InitICB (InternalInterface,
+ FWD_INTERNAL_INTERFACE_INDEX,
+ FWD_IF_PERMANENT,
+ TRUE,
+ FWD_NB_DELIVER_ALL);
+#if DBG
+ InitializeListHead (&InternalInterface->ICB_InSendQueue);
+#endif
+
+ KeInitializeSpinLock (&InterfaceTableLock);
+ KeInitializeSpinLock (&InterfaceZoneLock);
+ KeInitializeSpinLock (&RouteZoneLock);
+ InitializeRWLock (&RWLock);
+ ExInitializeFastMutex (&WriterMutex);
+
+ // Initialize hash tables buckets
+ for (i=0; i<InterfaceHashSize; i++)
+ InitializeListHead (&InterfaceIndexHash[i]);
+
+ for (i=0; i<ClientHashSize; i++) {
+ ClientNodeHash[i] = NULL;
+ }
+
+ for (i=0; i<RouteHashSize; i++) {
+ RouteHash[i] = NULL;
+ }
+
+ for (i=0; i<NBRouteHashSize; i++) {
+ NBRouteHash[i] = NULL;
+ }
+ return STATUS_SUCCESS;
+ }
+ else {
+ IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR,
+ ("IpxFwd: Could not allocate table block!\n"));
+ }
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+}
+
+/*++
+*******************************************************************
+ D e l e t e T a b l e s
+
+Routine Description:
+ Releases resources allocated for all hash tables
+Arguments:
+ None
+Return Value:
+ STATUS_SUCCESS - tables were freed ok
+*******************************************************************
+--*/
+NTSTATUS
+DeleteTables (
+ void
+ ) {
+ UINT i;
+ PVOID segment;
+
+
+ if (TableBlock==NULL) {
+ IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR, ("Tables already deleted.\n"));
+ return STATUS_SUCCESS;
+ }
+ // First get rid of all routes
+ // (that should release all references to interface
+ // control blocks
+ for (i=0; i<RouteHashSize; i++) {
+ while (RouteHash[i]!=NULL) {
+ PFWD_ROUTE fwRoute = RouteHash[i];
+ RouteHash[i] = fwRoute->FR_Next;
+ if (fwRoute->FR_InterfaceReference!=GLOBAL_INTERFACE_REFERENCE) {
+ ReleaseInterfaceReference (fwRoute->FR_InterfaceReference);
+ }
+ fwRoute->FR_InterfaceReference = NULL;
+ ReleaseRouteReference (fwRoute);
+ }
+ }
+ // Don't forget about global route
+ if (GlobalRoute!=NULL) {
+ GlobalRoute->FR_InterfaceReference = NULL;
+ ReleaseRouteReference (GlobalRoute);
+ GlobalRoute = NULL;
+ GlobalNetwork = 0xFFFFFFFF;
+ }
+
+ // Now we should be able to release all interfaces
+ for (i=0; i<InterfaceHashSize; i++) {
+ while (!IsListEmpty (&InterfaceIndexHash[i])) {
+ PINTERFACE_CB ifCB = CONTAINING_RECORD (InterfaceIndexHash[i].Flink,
+ INTERFACE_CB,
+ ICB_IndexHashLink);
+ RemoveEntryList (&ifCB->ICB_IndexHashLink);
+ if (ifCB->ICB_Stats.OperationalState==FWD_OPER_STATE_UP) {
+ switch (ifCB->ICB_InterfaceType) {
+ case FWD_IF_PERMANENT:
+ DeregisterPacketConsumer (ifCB->ICB_PacketListId);
+ break;
+ case FWD_IF_DEMAND_DIAL:
+ case FWD_IF_LOCAL_WORKSTATION:
+ case FWD_IF_REMOTE_WORKSTATION:
+ break;
+ default:
+ ASSERTMSG ("Invalid interface type ", FALSE);
+ break;
+ }
+ if (ifCB->ICB_CashedInterface!=NULL)
+ ReleaseInterfaceReference (ifCB->ICB_CashedInterface);
+ ifCB->ICB_CashedInterface = NULL;
+ if (ifCB->ICB_CashedRoute!=NULL)
+ ReleaseRouteReference (ifCB->ICB_CashedRoute);
+ ifCB->ICB_CashedRoute = NULL;
+ if (ifCB->ICB_Network==GlobalNetwork)
+ DeleteGlobalNetClient (ifCB);
+ IPXCloseAdapterProc (ifCB->ICB_AdapterContext);
+ ReleaseInterfaceReference (ifCB); // Binding reference
+ }
+
+ if (IS_IF_CONNECTING (ifCB)) {
+ SET_IF_NOT_CONNECTING (ifCB);
+ DequeueConnectionRequest (ifCB);
+ }
+
+ while (!IsListEmpty (&ifCB->ICB_ExternalQueue)) {
+ PPACKET_TAG pktTag;
+
+ pktTag = CONTAINING_RECORD (ifCB->ICB_ExternalQueue.Flink,
+ PACKET_TAG, PT_QueueLink);
+ RemoveEntryList (&pktTag->PT_QueueLink);
+ ReleaseInterfaceReference (pktTag->PT_InterfaceReference);
+ FreePacket (pktTag);
+ }
+
+ while (!IsListEmpty (&ifCB->ICB_InternalQueue)) {
+ PINTERNAL_PACKET_TAG pktTag;
+
+ pktTag = CONTAINING_RECORD (ifCB->ICB_InternalQueue.Flink,
+ INTERNAL_PACKET_TAG, IPT_QueueLink);
+ RemoveEntryList (&pktTag->IPT_QueueLink);
+ IPXInternalSendCompletProc (&pktTag->IPT_Target,
+ pktTag->IPT_Packet,
+ pktTag->IPT_Length,
+ STATUS_NETWORK_UNREACHABLE);
+ ReleaseInterfaceReference (pktTag->IPT_InterfaceReference);
+ ExFreePool (pktTag);
+ }
+
+ ifCB->ICB_Stats.OperationalState = FWD_OPER_STATE_DOWN;
+ if (ifCB->ICB_NBRoutes!=NULL) {
+ DeleteNBRoutes (ifCB->ICB_NBRoutes, ifCB->ICB_NBRouteCount);
+ ifCB->ICB_NBRoutes = NULL;
+ }
+ ReleaseInterfaceReference (ifCB);
+ }
+ }
+
+ if (InternalInterface->ICB_NBRoutes!=NULL) {
+ DeleteNBRoutes (InternalInterface->ICB_NBRoutes,
+ InternalInterface->ICB_NBRouteCount);
+ InternalInterface->ICB_NBRoutes = NULL;
+ }
+ if (InternalInterface->ICB_Stats.OperationalState==FWD_OPER_STATE_UP) {
+ InternalInterface->ICB_Stats.OperationalState = FWD_OPER_STATE_DOWN;
+ ReleaseInterfaceReference (InternalInterface); // Binding reference
+ }
+ ReleaseInterfaceReference (InternalInterface);
+
+
+
+ // Release extra memory segments used for route table entries
+ segment = PopEntryList (&RouteZone.SegmentList);
+ while (RouteZone.SegmentList.Next!=NULL) {
+ ExFreePool (segment);
+ segment = PopEntryList (&RouteZone.SegmentList);
+ }
+
+ // Release extra memory segments used for interface table entries
+ segment = PopEntryList (&InterfaceZone.SegmentList);
+ while (InterfaceZone.SegmentList.Next!=NULL) {
+ ExFreePool (segment);
+ segment = PopEntryList (&InterfaceZone.SegmentList);
+ }
+
+ ExFreePool (TableBlock);
+ TableBlock = NULL;
+ return STATUS_SUCCESS;
+}
+
+/*++
+*******************************************************************
+ L o c a t e I n t e r f a c e
+
+Routine Description:
+ Finds interface control block in interface
+ index hash table. Optionally returns the
+ insertion point pointer if interface block
+ with given index is not in the table.
+Arguments:
+ InterfaceIndex - unique id of the interface
+ insertBefore - buffer to place the pointer to
+ hash table element where interface
+ block should be inserted if it is not
+ already in the table
+Return Value:
+ Pointer to interface control block if found
+ NULL otherwise
+*******************************************************************
+--*/
+PINTERFACE_CB
+LocateInterface (
+ ULONG InterfaceIndex,
+ PLIST_ENTRY *insertBefore OPTIONAL
+ ) {
+ PLIST_ENTRY cur;
+ PINTERFACE_CB ifCB;
+ PLIST_ENTRY HashList;
+
+ ASSERT (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX);
+
+ // Find hash bucket
+ HashList = &InterfaceIndexHash[InterfaceIndexHashFunc(InterfaceIndex)];
+ cur = HashList->Flink;
+ // Walk the list
+ while (cur!=HashList) {
+ ifCB = CONTAINING_RECORD(cur, INTERFACE_CB, ICB_IndexHashLink);
+
+ if (ifCB->ICB_Index==InterfaceIndex)
+ // Found, return it (insertion point is irrelevant)
+ return ifCB;
+ else if (ifCB->ICB_Index>InterfaceIndex)
+ // No chance to find it
+ break;
+ cur = cur->Flink;
+ }
+ // Return insertion point if asked
+ if (ARGUMENT_PRESENT(insertBefore))
+ *insertBefore = cur;
+ return NULL;
+}
+
+/*++
+*******************************************************************
+ L o c a t e C l i e n t I n t e r f a c e
+
+Routine Description:
+ Finds interface control block in client
+ node hash bucket. Optionally returns the
+ insertion point pointer if interface block
+ with given node is not in the table
+Arguments:
+ ClientNode - node address of the client on global network
+ insertBefore - buffer to place the pointer to
+ hash table element where interface
+ block should be inserted if it is not
+ already in the table
+Return Value:
+ Pointer to interface control block if found
+ NULL otherwise
+*******************************************************************
+--*/
+PINTERFACE_CB
+LocateClientInterface (
+ ULONGLONG *NodeAddress64,
+ PINTERFACE_CB **prevLink OPTIONAL
+ ) {
+ PINTERFACE_CB cur, *prev;
+
+ prev = &ClientNodeHash[ClientNodeHashFunc (*NodeAddress64)];
+ cur = *prev;
+ while (cur!=NULL) {
+ if (*NodeAddress64==cur->ICB_ClientNode64[0])
+ break;
+ else if (*NodeAddress64>cur->ICB_ClientNode64[0]) {
+ // No chance to find it
+ cur = NULL;
+ break;
+ }
+ prev = &cur->ICB_NodeHashLink;
+ cur = cur->ICB_NodeHashLink;
+ }
+ if (ARGUMENT_PRESENT(prevLink))
+ *prevLink = prev;
+ return cur;
+}
+
+/*++
+*******************************************************************
+ L o c a t e R o u t e
+
+Routine Description:
+ Finds route block in network number
+ hash table. Optionally returns the
+ insertion point pointer if route
+ for given destination netowrk is not in the table
+Arguments:
+ Network - destination netowork number
+ insertBefore - buffer to place the pointer to
+ hash table element where route
+ block should be inserted if it is not
+ already in the table
+Return Value:
+ Pointer to route block if found
+ NULL otherwise
+*******************************************************************
+--*/
+PFWD_ROUTE
+LocateRoute (
+ ULONG Network,
+ PFWD_ROUTE **prevLink OPTIONAL
+ ) {
+ PFWD_ROUTE cur, *prev;
+
+ prev = &RouteHash[NetworkNumberHashFunc(Network)];
+ cur = *prev;
+
+ while (cur!=NULL) {
+ if (cur->FR_Network==Network)
+ break;
+ else if (cur->FR_Network>Network) {
+ cur = NULL;
+ // No chance to find it
+ break;
+ }
+ prev = &cur->FR_Next;
+ cur = *prev;
+ }
+ if (ARGUMENT_PRESENT(prevLink))
+ *prevLink = prev;
+
+ return cur;
+}
+
+/*++
+*******************************************************************
+ L o c a t e N B R o u t e
+
+Routine Description:
+ Finds nb route block in nb name
+ hash table. Optionally returns the
+ insertion point pointer if nb route
+ for given name is not in the table
+Arguments:
+ Name - netbios name
+ insertBefore - buffer to place the pointer to
+ hash table element where route
+ block should be inserted if it is not
+ already in the table
+Return Value:
+ Pointer to nb route block if found
+ NULL otherwise
+*******************************************************************
+--*/
+PNB_ROUTE
+LocateNBRoute (
+ ULONGLONG *Name128,
+ PNB_ROUTE **prevLink OPTIONAL
+ ) {
+ PNB_ROUTE cur, *prev;
+
+ prev = &NBRouteHash[NetbiosNameHashFunc(Name128)];
+ cur = *prev;
+
+ while (cur!=NULL) {
+ if ((cur->NBR_Name128[0]==Name128[0])
+ && (cur->NBR_Name128[1]==Name128[1]))
+ break;
+ else if ((cur->NBR_Name128[0]>Name128[0])
+ || ((cur->NBR_Name128[0]==Name128[0])
+ && (cur->NBR_Name128[1]>Name128[1]))) {
+ cur = NULL;
+ // No chance to find it
+ break;
+ }
+ prev = &cur->NBR_Next;
+ cur = *prev;
+ }
+ if (ARGUMENT_PRESENT(prevLink))
+ *prevLink = prev;
+
+ return cur;
+}
+
+/*++
+*******************************************************************
+ G e t I n t e r f a c e R e f e r e n c e
+
+Routine Description:
+ Returns reference interface based on its index
+Arguments:
+ InterfaceIndex - unique id of the interface
+Return Value:
+ Pointer to interface control block if there is one in the table
+ NULL otherwise
+*******************************************************************
+--*/
+PINTERFACE_CB
+GetInterfaceReference (
+ ULONG InterfaceIndex
+ ) {
+ KIRQL oldIRQL;
+ PINTERFACE_CB ifCB;
+
+ KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL);
+ if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX)
+ ifCB = LocateInterface (InterfaceIndex, NULL);
+ else
+ ifCB = InternalInterface;
+
+ if (ifCB!=NULL)
+ AcquireInterfaceReference (ifCB);
+ else {
+ IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR,
+ ("IpxFwd: Could not get interface reference %ld.\n", InterfaceIndex));
+ }
+ KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
+ return ifCB;
+}
+
+/*++
+*******************************************************************
+ G e t N e x t I n t e r f a c e R e f e r e n c e
+
+Routine Description:
+ Returns reference to the next interface in the table
+ Reference to the provided interface is released
+Arguments:
+ ifCB - interface to start with or NULL to start from the
+ beginning of the interface table
+Return Value:
+ Pointer to interface control block if thare are any more interfaces
+ in the table
+ NULL otherwise
+*******************************************************************
+--*/
+PINTERFACE_CB
+GetNextInterfaceReference (
+ PINTERFACE_CB ifCB
+ ) {
+ PLIST_ENTRY cur;
+ PLIST_ENTRY HashList;
+ KIRQL oldIRQL;
+
+ KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL);
+ if (ifCB!=NULL) {
+ // Find hash bucket
+ ASSERT (ifCB->ICB_Index!=FWD_INTERNAL_INTERFACE_INDEX);
+ HashList = &InterfaceIndexHash[InterfaceIndexHashFunc(ifCB->ICB_Index)];
+ if (LocateInterface (ifCB->ICB_Index, &cur)!=NULL)
+ cur = ifCB->ICB_IndexHashLink.Flink;
+ ReleaseInterfaceReference (ifCB);
+ ifCB = NULL;
+ }
+ else
+ cur = HashList = InterfaceIndexHash-1;
+
+ if (cur==HashList) {
+ do {
+ HashList += 1;
+ if (HashList==&InterfaceIndexHash[InterfaceHashSize]) {
+ KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
+ return NULL;
+ }
+ } while (IsListEmpty (HashList));
+ cur = HashList->Flink;
+ }
+ ifCB = CONTAINING_RECORD (cur, INTERFACE_CB, ICB_IndexHashLink);
+ AcquireInterfaceReference (ifCB);
+ KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
+
+ return ifCB;
+}
+
+
+/*++
+*******************************************************************
+ A d d I n t e r f a c e
+
+Routine Description:
+ Adds interface control block to the table.
+Arguments:
+ InterfaceIndex - unique if of the interface
+ Info - interface paramters
+Return Value:
+ STATUS_SUCCESS - interface added ok
+ STATUS_UNSUCCESSFUL - interface is already in the table
+ STATUS_INSUFFICIENT_RESOURCES - can't allocate memory for
+ interface CB
+*******************************************************************
+--*/
+NTSTATUS
+AddInterface (
+ ULONG InterfaceIndex,
+ UCHAR InterfaceType,
+ BOOLEAN NetbiosAccept,
+ UCHAR NetbiosDeliver
+ ) {
+ PINTERFACE_CB ifCB;
+ PLIST_ENTRY cur;
+ KIRQL oldIRQL;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL);
+ if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX) {
+ ifCB = LocateInterface (InterfaceIndex, &cur);
+ if (ifCB==NULL) {
+ ifCB = AllocateInterface ();
+ if (ifCB!=NULL)
+ NOTHING;
+ else {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto AddEnd;
+ }
+ }
+ else {
+ IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR,
+ ("IpxFwd: Interface %ld is already in the table!\n", InterfaceIndex));
+ status = STATUS_UNSUCCESSFUL;
+ goto AddEnd;
+ }
+ }
+ else
+ ifCB = InternalInterface;
+
+ InitICB (ifCB, InterfaceIndex,InterfaceType,NetbiosAccept,NetbiosDeliver);
+#if DBG
+ InitializeListHead (&ifCB->ICB_InSendQueue);
+#endif
+
+ switch (InterfaceType) {
+ case FWD_IF_PERMANENT:
+ break;
+ case FWD_IF_DEMAND_DIAL:
+ case FWD_IF_LOCAL_WORKSTATION:
+ case FWD_IF_REMOTE_WORKSTATION:
+ ASSERT (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX);
+ if (WanPacketListId==-1) {
+ status = RegisterPacketConsumer (
+ WAN_PACKET_SIZE,
+ &WanPacketListId);
+ if (!NT_SUCCESS (status)) {
+ WanPacketListId = -1;
+ break;
+ }
+ }
+ ifCB->ICB_PacketListId = WanPacketListId;
+ break;
+ }
+
+ if (NT_SUCCESS (status)) {
+ if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX) {
+ InsertTailList (cur, &ifCB->ICB_IndexHashLink);
+ }
+ IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
+ ("IpxFwd: Adding interface %d (icb: %08lx, plid: %d)\n",
+ InterfaceIndex, ifCB, ifCB->ICB_PacketListId));
+ }
+ else
+ FreeInterface (ifCB);
+
+AddEnd:
+ KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
+ return status;
+}
+
+
+/*++
+*******************************************************************
+ A d d G l o b a l N e t C l i e n t
+
+Routine Description:
+ Adds interface control block to the table of
+ clients on the global network (should be done when
+ client connects)
+Arguments:
+ ifCB - interface control block to add to the table
+Return Value:
+ STATUS_SUCCESS - interface was added ok
+ STATUS_UNSUCCESSFUL - another interface with the same
+ node address is already in the table
+*******************************************************************
+--*/
+NTSTATUS
+AddGlobalNetClient (
+ PINTERFACE_CB ifCB
+ ) {
+ KIRQL oldIRQL;
+ RWCOOKIE cookie;
+ PINTERFACE_CB *prev;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ ASSERT (ifCB->ICB_Index!=FWD_INTERNAL_INTERFACE_INDEX);
+
+ AcquireReaderAccess (&RWLock, cookie);
+ KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL);
+ if (LocateClientInterface (ifCB->ICB_ClientNode64, &prev)==NULL) {
+ ifCB->ICB_NodeHashLink = *prev;
+ *prev = ifCB;
+ KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
+ ReleaseReaderAccess (&RWLock, cookie);
+ AcquireInterfaceReference (ifCB); // To make sure that
+ // interface block does not
+ // get deleted until it is
+ // removed from the node table
+ IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
+ ("IpxFwd: Adding interface %ld (icb: %08lx)"
+ " to global client table.\n", ifCB->ICB_Index, ifCB));
+ }
+ else {
+ KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
+ ReleaseReaderAccess (&RWLock, cookie);
+ IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR,
+ ("IpxFwd: Interface %ld (icb: %08lx)"
+ " is already in the global client table.\n",
+ ifCB->ICB_Index, ifCB));
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ return status;
+}
+
+/*++
+*******************************************************************
+ D e l e t e G l o b a l N e t C l i e n t
+
+Routine Description:
+ Removes interface control block from the table of
+ clients on the global network (should be done when
+ client disconnects)
+Arguments:
+ ifCB - interface control block to remove from the table
+Return Value:
+ STATUS_SUCCESS - interface was removed ok
+*******************************************************************
+--*/
+NTSTATUS
+DeleteGlobalNetClient (
+ PINTERFACE_CB ifCB
+ ) {
+ KIRQL oldIRQL;
+ RWCOOKIE cookie;
+ PINTERFACE_CB cur, *prev;
+
+ IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
+ ("IpxFwd: Deleting interface %ld (icb: %08lx)"
+ " from global client table.\n", ifCB->ICB_Index, ifCB));
+
+ ASSERT (ifCB->ICB_Index!=FWD_INTERNAL_INTERFACE_INDEX);
+
+ AcquireReaderAccess (&RWLock, cookie);
+ KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL);
+ cur = LocateClientInterface (ifCB->ICB_ClientNode64, &prev);
+ ASSERT (cur==ifCB);
+ *prev = ifCB->ICB_NodeHashLink;
+ KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
+ ReleaseReaderAccess (&RWLock, cookie);
+
+ ReleaseInterfaceReference (ifCB);
+ return STATUS_SUCCESS;
+}
+
+
+/*++
+*******************************************************************
+ D e l e t e I n t e r f a c e
+
+Routine Description:
+ Deletes interface control block (the block is not actually
+ disposed of until all references to it are released).
+Arguments:
+ InterfaceIndex - unique if of the interface
+Return Value:
+ STATUS_SUCCESS - interface info retreived ok
+ STATUS_UNSUCCESSFUL - interface is not in the table
+*******************************************************************
+--*/
+NTSTATUS
+DeleteInterface (
+ ULONG InterfaceIndex
+ ) {
+ PINTERFACE_CB ifCB;
+ KIRQL oldIRQL;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL);
+
+ if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX)
+ ifCB = LocateInterface (InterfaceIndex, NULL);
+ else
+ ifCB = InternalInterface;
+ if (ifCB!=NULL) {
+ if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX) {
+ RemoveEntryList (&ifCB->ICB_IndexHashLink);
+ }
+ KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
+ if (ifCB->ICB_Stats.OperationalState == FWD_OPER_STATE_UP) {
+ IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR,
+ ("IpxFwd: Interface %ld (icb: %08lx) was still bound"
+ " when asked to delete it.\n",
+ ifCB->ICB_Index, ifCB));
+ UnbindInterface (ifCB);
+ }
+ else if (IS_IF_CONNECTING (ifCB)) {
+ IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR,
+ ("IpxFwd: Interface %ld (icb: %08lx) was still being connected"
+ " when asked to delete it.\n",
+ ifCB->ICB_Index, ifCB));
+ SET_IF_NOT_CONNECTING (ifCB);
+ DequeueConnectionRequest (ifCB);
+ ProcessInternalQueue (ifCB);
+ ProcessExternalQueue (ifCB);
+ }
+
+ ifCB->ICB_Stats.OperationalState = FWD_OPER_STATE_DOWN;
+
+ IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
+ ("IpxFwd: Deleting interface %ld (icb: %08lx).\n",
+ ifCB->ICB_Index, ifCB));
+
+ if (ifCB->ICB_NBRoutes!=NULL) {
+ DeleteNBRoutes (ifCB->ICB_NBRoutes, ifCB->ICB_NBRouteCount);
+ ifCB->ICB_NBRoutes = NULL;
+ }
+
+ FltInterfaceDeleted (ifCB);
+ ReleaseInterfaceReference (ifCB);
+ }
+ else {
+ KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
+ IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR,
+ ("IpxFwd: Could not delete interface %ld because it is not found.\n",
+ InterfaceIndex));
+ status = STATUS_UNSUCCESSFUL;
+ }
+ return status;
+
+}
+
+/*++
+*******************************************************************
+ A d d R o u t e
+
+Routine Description:
+ Adds route to the hash table and finds and stores the reference
+ to the associated interface control block in the route.
+Arguments:
+ Network - route's destination network
+ NextHopAddress - mac address of next hop router if network is not
+ directly connected
+ TickCount - ticks to reach the destination net
+ HopCount - hopss to reach the destination net
+ InterfaceIndex - index of the associated interface (through which
+ packets destined to the network are to be sent)
+Return Value:
+ STATUS_SUCCESS - route was added ok
+ STATUS_UNSUCCESSFUL - route is already in the table
+ STATUS_INSUFFICIENT_RESOURCES - can't allocate memory for
+ route block
+*******************************************************************
+--*/
+NTSTATUS
+AddRoute (
+ ULONG Network,
+ UCHAR *NextHopAddress,
+ USHORT TickCount,
+ USHORT HopCount,
+ ULONG InterfaceIndex
+ ) {
+ PFWD_ROUTE fwRoute;
+ PFWD_ROUTE *prev;
+ NTSTATUS status = STATUS_SUCCESS;
+ KIRQL oldIRQL;
+
+ // Assume success, allocate route and intialize it
+ // (the goal is to spend as little time as possible
+ // inside exclusive usage zone)
+ fwRoute = AllocateRoute ();
+ if (fwRoute!=NULL) {
+ fwRoute->FR_Network = Network;
+ IPX_NODE_CPY (fwRoute->FR_NextHopAddress, NextHopAddress);
+ fwRoute->FR_TickCount = TickCount;
+ fwRoute->FR_HopCount = HopCount;
+ fwRoute->FR_ReferenceCount = 0;
+
+ if (InterfaceIndex!=0xFFFFFFFF) {
+ // See if interface is there
+ KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL);
+ if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX)
+ fwRoute->FR_InterfaceReference
+ = LocateInterface (InterfaceIndex, NULL);
+ else
+ fwRoute->FR_InterfaceReference = InternalInterface;
+ if (fwRoute->FR_InterfaceReference!=NULL) {
+ AcquireInterfaceReference (fwRoute->FR_InterfaceReference);
+ KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
+
+ ExAcquireFastMutex (&WriterMutex);
+ // Check if route is already there
+ if (LocateRoute (Network, &prev)==NULL) {
+ fwRoute->FR_Next = *prev;
+ *prev = fwRoute;
+ }
+ else {
+ ReleaseInterfaceReference (fwRoute->FR_InterfaceReference);
+ fwRoute->FR_InterfaceReference = NULL;
+ IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_ERROR,
+ ("IpxFwd: Route for net %08lx"
+ " is already in the table!\n", Network));
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ ExReleaseFastMutex (&WriterMutex);
+ }
+ else {
+ KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
+ IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_ERROR,
+ ("IpxFwd: Interface %ld for route for net %08lx"
+ " is not in the table!\n", InterfaceIndex, Network));
+ status = STATUS_UNSUCCESSFUL;
+ }
+ }
+ else {
+ ExAcquireFastMutex (&WriterMutex);
+ // Just check if we do not have it already
+ if (GlobalRoute==NULL) {
+ fwRoute->FR_InterfaceReference = GLOBAL_INTERFACE_REFERENCE;
+ GlobalNetwork = Network;
+ GlobalRoute = fwRoute;
+ }
+ else {
+ IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_ERROR,
+ ("IpxFwd: Route for global net %08lx"
+ " is already in the table!\n", Network));
+ status = STATUS_UNSUCCESSFUL;
+ }
+ ExReleaseFastMutex (&WriterMutex);
+ }
+
+ if (NT_SUCCESS (status)) {
+ IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_WARNING,
+ ("IpxFwd: Adding route for net %08lx"
+ " (rb: %08lx, NHA: %02x%02x%02x%02x%02x%02x,"
+ " if: %ld, icb: %08lx).\n",
+ Network, fwRoute,
+ NextHopAddress[0], NextHopAddress[1],
+ NextHopAddress[2], NextHopAddress[3],
+ NextHopAddress[4], NextHopAddress[5],
+ InterfaceIndex, fwRoute->FR_InterfaceReference));
+ }
+ else {
+ FreeRoute (fwRoute);
+ }
+ }
+ else
+ status = STATUS_INSUFFICIENT_RESOURCES;
+
+ return status;
+}
+
+/*++
+*******************************************************************
+ D e l e t e R o u t e
+
+Routine Description:
+ Deletes route from the hash table and releases the reference
+ to the interface control block associated with the route.
+Arguments:
+ Network - route's destination network
+Return Value:
+ STATUS_SUCCESS - route was deleted ok
+ STATUS_UNSUCCESSFUL - route is not in the table
+*******************************************************************
+--*/
+NTSTATUS
+DeleteRoute (
+ ULONG Network
+ ) {
+ PFWD_ROUTE fwRoute, *prev;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ ExAcquireFastMutex (&WriterMutex);
+
+ if ((GlobalRoute!=NULL)
+ && (GlobalNetwork==Network)) {
+ fwRoute = GlobalRoute;
+ GlobalNetwork = 0xFFFFFFFF;
+ GlobalRoute = NULL;
+ }
+ else if ((fwRoute=LocateRoute (Network, &prev))!=NULL) {
+ *prev = fwRoute->FR_Next;
+ }
+
+ if (fwRoute!=NULL) {
+ IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_WARNING,
+ ("IpxFwd: Deleting route for net %08lx (rb: %08lx).\n",
+ Network, fwRoute));
+ WaitForAllReaders (&RWLock);
+ if (fwRoute->FR_InterfaceReference!=GLOBAL_INTERFACE_REFERENCE) {
+ ReleaseInterfaceReference (fwRoute->FR_InterfaceReference);
+ }
+ fwRoute->FR_InterfaceReference = NULL;
+ ReleaseRouteReference (fwRoute);
+ }
+ else {
+ IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_ERROR,
+ ("IpxFwd: Could not delete route for net %08lx because it is not in the table.\n",
+ Network));
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ ExReleaseFastMutex (&WriterMutex);
+ return status;
+}
+
+
+/*++
+*******************************************************************
+ U p d a t e R o u t e
+
+Routine Description:
+ Updates route in the hash table
+Arguments:
+ Network - route's destination network
+ NextHopAddress - mac address of next hop router if network is not
+ directly connected
+ TickCount - ticks to reach the destination net
+ HopCount - hopss to reach the destination net
+ InterfaceIndex - index of the associated interface (through which
+ packets destined to the network are to be sent)
+Return Value:
+ STATUS_SUCCESS - interface info retreived ok
+ STATUS_UNSUCCESSFUL - interface is not in the table
+*******************************************************************
+--*/
+NTSTATUS
+UpdateRoute (
+ ULONG Network,
+ UCHAR *NextHopAddress,
+ USHORT TickCount,
+ USHORT HopCount,
+ ULONG InterfaceIndex
+ ) {
+ PFWD_ROUTE fwRoute = NULL, newRoute, *prev;
+ PINTERFACE_CB ifCB = NULL;
+ KIRQL oldIRQL;
+ NTSTATUS status = STATUS_SUCCESS;
+
+
+ ExAcquireFastMutex (&WriterMutex);
+
+ if ((GlobalRoute!=NULL)
+ && (GlobalNetwork==Network)) {
+ ASSERT (InterfaceIndex==0xFFFFFFFF);
+ fwRoute = GlobalRoute;
+ }
+ else {
+ ASSERT (InterfaceIndex!=0xFFFFFFFF);
+ fwRoute = LocateRoute (Network, &prev);
+ }
+
+ if (fwRoute!=NULL) {
+ if (InterfaceIndex!=0xFFFFFFFF) {
+ if (fwRoute->FR_InterfaceReference->ICB_Index!=InterfaceIndex) {
+ // Get a reference to new interface
+ KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL);
+ if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX)
+ ifCB = LocateInterface (InterfaceIndex, NULL);
+ else
+ ifCB = InternalInterface;
+ if (ifCB!=NULL) {
+ AcquireInterfaceReference (ifCB);
+ }
+ else {
+ KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
+ status = STATUS_UNSUCCESSFUL;
+ goto ExitUpdate;
+ }
+ KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
+ }
+ else {
+ ifCB = fwRoute->FR_InterfaceReference;
+ AcquireInterfaceReference (ifCB);
+ }
+ }
+ else
+ ifCB = GLOBAL_INTERFACE_REFERENCE;
+ newRoute = AllocateRoute ();
+ if (newRoute!=NULL) {
+ newRoute->FR_Network = Network;
+ IPX_NODE_CPY (newRoute->FR_NextHopAddress, NextHopAddress);
+ newRoute->FR_TickCount = TickCount;
+ newRoute->FR_HopCount = HopCount;
+ newRoute->FR_ReferenceCount = 0;
+ newRoute->FR_InterfaceReference = ifCB;
+ // Lock the table only when updating it
+ if (InterfaceIndex!=0xFFFFFFFF) {
+ newRoute->FR_Next = fwRoute->FR_Next;
+ *prev = newRoute;
+ }
+ else
+ GlobalRoute = newRoute;
+
+ WaitForAllReaders (&RWLock)
+ if (fwRoute->FR_InterfaceReference!=GLOBAL_INTERFACE_REFERENCE) {
+ ReleaseInterfaceReference (fwRoute->FR_InterfaceReference);
+ }
+ fwRoute->FR_InterfaceReference = NULL;
+ ReleaseRouteReference (fwRoute);
+
+ }
+ else
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ status = STATUS_UNSUCCESSFUL;
+
+ExitUpdate:
+ ExReleaseFastMutex (&WriterMutex);
+ return status;
+}
+
+
+/*++
+*******************************************************************
+ F i n d D e s t i n a t i o n
+
+Routine Description:
+ Finds destination interface for IPX address and
+ returns reference to its control block.
+Arguments:
+ Network - destination network
+ Node - destination node (needed in case of global client)
+ Route - buffer to hold reference to route block
+Return Value:
+ Reference to destination interface CB
+ NULL if route it not found
+*******************************************************************
+--*/
+PINTERFACE_CB
+FindDestination (
+ IN ULONG Network,
+ IN PUCHAR Node,
+ OUT PFWD_ROUTE *Route
+ ) {
+ PFWD_ROUTE fwRoute;
+ PINTERFACE_CB ifCB;
+ RWCOOKIE cookie;
+
+ AcquireReaderAccess (&RWLock, cookie);
+ if ((GlobalRoute!=NULL)
+ && (GlobalNetwork==Network)) {
+ if (Node!=NULL) { // If caller did not specify node,
+ // we can't find the route
+ union {
+ ULONGLONG Node64[1];
+ UCHAR Node[6];
+ } u;
+ u.Node64[0] = 0;
+ IPX_NODE_CPY (u.Node, Node);
+
+ ifCB = LocateClientInterface (u.Node64, NULL);
+ if (ifCB!=NULL) {
+ AcquireRouteReference (GlobalRoute);
+ *Route = GlobalRoute;
+ AcquireInterfaceReference (ifCB);
+ }
+ else
+ *Route = NULL;
+ }
+ else {
+ ifCB = NULL;
+ *Route = NULL;
+ }
+ }
+ else {
+ *Route = fwRoute = LocateRoute (Network, NULL);
+ if (fwRoute!=NULL) {
+ AcquireRouteReference (fwRoute);
+ ifCB = fwRoute->FR_InterfaceReference;
+ AcquireInterfaceReference (ifCB);
+ }
+ else
+ ifCB = NULL;
+ }
+ ReleaseReaderAccess (&RWLock, cookie);
+ return ifCB;
+}
+
+/*++
+*******************************************************************
+ A d d N B R o u t e s
+
+Routine Description:
+ Adds netbios names associated with interface to netbios
+ route hash table
+Arguments:
+ ifCB - interface with which names are associated
+ Names - array of names
+ Count - number of names in the array
+ routeArray - buffer to place allocated array of routes
+Return Value:
+ STATUS_SUCCESS - names were added ok
+ STATUS_UNSUCCESSFUL - one of the names is already in the table
+ STATUS_INSUFFICIENT_RESOURCES - can't allocate memory for
+ route array
+*******************************************************************
+--*/
+NTSTATUS
+AddNBRoutes (
+ PINTERFACE_CB ifCB,
+ FWD_NB_NAME Names[],
+ ULONG Count,
+ PNB_ROUTE *routeArray
+ ) {
+ PNB_ROUTE nbRoutes, *prev;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ nbRoutes = (PNB_ROUTE)ExAllocatePoolWithTag (
+ NonPagedPool, sizeof (NB_ROUTE)*Count, FWD_POOL_TAG);
+ if (nbRoutes!=NULL) {
+ ULONG i;
+
+ ExAcquireFastMutex (&WriterMutex);
+
+ for (i=0; i<Count; i++) {
+ nbRoutes[i].NBR_Name128[0] = nbRoutes[i].NBR_Name128[1] = 0;
+ NB_NAME_CPY (nbRoutes[i].NBR_Name, &Names[i]);
+ // Check if route is already there
+ if (LocateNBRoute (nbRoutes[i].NBR_Name128, &prev)==NULL) {
+ nbRoutes[i].NBR_Destination = ifCB;
+ nbRoutes[i].NBR_Next = *prev;
+ *prev = &nbRoutes[i];
+ IpxFwdDbgPrint (DBG_NBROUTE_TABLE, DBG_WARNING,
+ ("IpxFwd: Adding nb route for name %16s.\n",Names[i]));
+ }
+ else {
+ IpxFwdDbgPrint (DBG_NBROUTE_TABLE, DBG_ERROR,
+ ("IpxFwd: Route for nb name %16s"
+ " is already in the table!\n", Names[i]));
+ break;
+ }
+ }
+ ExReleaseFastMutex (&WriterMutex);
+ if (i==Count) {
+ *routeArray = nbRoutes;
+ status = STATUS_SUCCESS;
+
+ }
+ else {
+ status = STATUS_UNSUCCESSFUL;
+ DeleteNBRoutes (nbRoutes, i);
+ }
+ }
+ else {
+ IpxFwdDbgPrint (DBG_NBROUTE_TABLE, DBG_ERROR,
+ ("IpxFwd: Could allocate nb route array for if: %ld"
+ " (icb: %08lx).\n", ifCB->ICB_Index, ifCB));
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ return status;
+}
+
+/*++
+*******************************************************************
+ D e l e t e N B R o u t e s
+
+Routine Description:
+ Deletes nb routes in the array from the route table and frees
+ the array
+Arguments:
+ nbRoutes - array of routes
+ Count - number of routes in the array
+Return Value:
+ STATUS_SUCCESS - route was deleted ok
+ STATUS_UNSUCCESSFUL - route is not in the table
+*******************************************************************
+--*/
+NTSTATUS
+DeleteNBRoutes (
+ PNB_ROUTE nbRoutes,
+ ULONG Count
+ ) {
+ PNB_ROUTE *prev;
+ NTSTATUS status = STATUS_SUCCESS;
+ ULONG i;
+
+ ExAcquireFastMutex (&WriterMutex);
+ for (i=0; i<Count; i++) {
+ PNB_ROUTE cur = LocateNBRoute (nbRoutes[i].NBR_Name128, &prev);
+ ASSERT (cur==&nbRoutes[i]);
+ *prev = nbRoutes[i].NBR_Next;
+ IpxFwdDbgPrint (DBG_NBROUTE_TABLE, DBG_WARNING,
+ ("IpxFwd: Deleting nb route for name %16s.\n",
+ nbRoutes[i].NBR_Name));
+ }
+
+ WaitForAllReaders (&RWLock);
+ ExReleaseFastMutex (&WriterMutex);
+
+ ExFreePool (nbRoutes);
+
+ return STATUS_SUCCESS;
+}
+
+
+/*++
+*******************************************************************
+ F i n d N B D e s t i n a t i o n
+
+Routine Description:
+ Finds destination interface for nb name and
+ returns reference to its control block.
+Arguments:
+ Name - name to look for
+Return Value:
+ Reference to destination interface CB
+ NULL if route it not found
+*******************************************************************
+--*/
+PINTERFACE_CB
+FindNBDestination (
+ IN PUCHAR Name
+ ) {
+ PNB_ROUTE nbRoute;
+ PINTERFACE_CB ifCB;
+ RWCOOKIE cookie;
+ union {
+ ULONGLONG Name128[2];
+ UCHAR Name[16];
+ } u;
+ u.Name128[0] = u.Name128[1] = 0;
+ NB_NAME_CPY (u.Name, Name);
+
+ AcquireReaderAccess (&RWLock, cookie);
+ nbRoute = LocateNBRoute (u.Name128, NULL);
+ if (nbRoute!=NULL) {
+ ifCB = nbRoute->NBR_Destination;
+ AcquireInterfaceReference (ifCB);
+ }
+ else
+ ifCB = NULL;
+ ReleaseReaderAccess (&RWLock, cookie);
+ return ifCB;
+}
+
diff --git a/private/ntos/tdi/isn/fwd/tables.h b/private/ntos/tdi/isn/fwd/tables.h
new file mode 100644
index 000000000..6f86e52a8
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/tables.h
@@ -0,0 +1,708 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\tables.h
+
+Abstract:
+ IPX Forwarder Driver Tables
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+#ifndef _IPXFWD_TABLES_
+#define _IPXFWD_TABLES_
+
+// Ranges and defaults for registry configurable parameters
+#define MIN_ROUTE_SEGMENT_SIZE PAGE_SIZE
+#define MAX_ROUTE_SEGMENT_SIZE (PAGE_SIZE*8)
+#define DEF_ROUTE_SEGMENT_SIZE MIN_ROUTE_SEGMENT_SIZE
+
+#define MIN_INTERFACE_HASH_SIZE 31
+#define MAX_INTERFACE_HASH_SIZE 257
+#define DEF_INTERFACE_HASH_SIZE MAX_INTERFACE_HASH_SIZE
+
+#define MIN_CLIENT_HASH_SIZE 31
+#define MAX_CLIENT_HASH_SIZE 257
+#define DEF_CLIENT_HASH_SIZE MAX_CLIENT_HASH_SIZE
+
+#define MIN_NB_ROUTE_HASH_SIZE 31
+#define MAX_NB_ROUTE_HASH_SIZE 1023
+#define DEF_NB_ROUTE_HASH_SIZE 257
+
+#define MAX_SEND_PKTS_QUEUED 256 // No defined range
+
+#define NUM_INTERFACES_PER_SEGMENT 16 // Not configurable currently
+#define NUM_NB_ROUTES_PER_SEGMENT 16 // Not configurable currently
+
+
+// Special number reserved for routes that point to
+// client on global net
+#define GLOBAL_INTERFACE_REFERENCE ((PINTERFACE_CB)-1)
+
+// All types of WAN are emulated as ETHERNET by NDIS
+#define WAN_PACKET_SIZE 1500
+
+
+#define INVALID_NETWORK_NUMBER 0xFFFFFFFF
+#define INVALID_NIC_ID 0xFFFF
+
+
+// Interface control block
+struct _INTERFACE_CB;
+typedef struct _INTERFACE_CB INTERFACE_CB, *PINTERFACE_CB;
+struct _FWD_ROUTE;
+typedef struct _FWD_ROUTE FWD_ROUTE, *PFWD_ROUTE;
+struct _NB_ROUTE;
+typedef struct _NB_ROUTE NB_ROUTE, *PNB_ROUTE;
+
+struct _FWD_ROUTE {
+ ULONG FR_Network; // Dest network
+ USHORT FR_TickCount; // Route params
+ USHORT FR_HopCount; //
+ UCHAR FR_NextHopAddress[6]; // Next hop router
+ PINTERFACE_CB FR_InterfaceReference; // Associated if CB
+ // or NULL if global
+ // network for clients
+ LONG FR_ReferenceCount; // Number of external
+ // references for this
+ // block (must keep the
+ // it till all of them
+ // are released
+ PFWD_ROUTE FR_Next; // Next route in the
+ // table
+};
+
+struct _INTERFACE_CB {
+ ULONG ICB_Index; // Unique ID
+ ULONG ICB_Network; // Network we boud to
+ union {
+ ULONGLONG ICB_ClientNode64[1];// For clients on
+ // global net (faster
+ // comparisons and
+ // hashing using 64
+ // bit support)
+ UCHAR ICB_RemoteNode[6]; // Peer node for demand
+ // dial connections
+ };
+ UCHAR ICB_LocalNode[6]; // Node we bound to
+ USHORT ICB_Flags;
+#define FWD_IF_ENABLED 0x0001
+#define SET_IF_ENABLED(ifCB) ifCB->ICB_Flags |= FWD_IF_ENABLED;
+#define SET_IF_DISABLED(ifCB) ifCB->ICB_Flags &= ~FWD_IF_ENABLED;
+#define IS_IF_ENABLED(ifCB) (ifCB->ICB_Flags&FWD_IF_ENABLED)
+
+#define FWD_IF_CONNECTING 0x0002
+#define SET_IF_CONNECTING(ifCB) ifCB->ICB_Flags |= FWD_IF_CONNECTING;
+#define SET_IF_NOT_CONNECTING(ifCB) ifCB->ICB_Flags &= ~FWD_IF_CONNECTING;
+#define IS_IF_CONNECTING(ifCB) (ifCB->ICB_Flags&FWD_IF_CONNECTING)
+ USHORT ICB_NicId; // Nic id we bound to
+ UCHAR ICB_InterfaceType;
+ UCHAR ICB_NetbiosDeliver;
+ BOOLEAN ICB_NetbiosAccept;
+
+ PNB_ROUTE ICB_NBRoutes; // Array of associated
+ // NB routes
+ ULONG ICB_NBRouteCount; // Number of nb routes
+
+ LONGLONG ICB_DisconnectTime; // Time when if was disconnected
+ FWD_IF_STATS ICB_Stats; // Accumulated
+ PFWD_ROUTE ICB_CashedRoute; // MRU dest route
+ PINTERFACE_CB ICB_CashedInterface;// MRU dest if
+ NIC_HANDLE ICB_AdapterContext; // IPX stack supplied
+ PVOID ICB_FilterInContext;
+ PVOID ICB_FilterOutContext;
+ LONG ICB_PendingQuota; // Remaining quota of
+ // packets that can be
+ // pending on
+ // the interface
+ LIST_ENTRY ICB_ExternalQueue; // Queue of external (received)
+ // packets
+ LIST_ENTRY ICB_InternalQueue; // Queue of internal (send)
+ // requests
+#if DBG
+ LIST_ENTRY ICB_InSendQueue; // packets being
+ // sent by ipx
+#endif
+ INT ICB_PacketListId; // ID of the packet list
+ // (for the max frame size
+ // on this interface)
+ LIST_ENTRY ICB_IndexHashLink; // Link in interface idx hash
+ LIST_ENTRY ICB_ConnectionLink; // Link in connection queue
+ PNDIS_PACKET ICB_ConnectionPacket; // Packet that caused connection
+ // request
+ PUCHAR ICB_ConnectionData; // Pointer into packet to
+ // place where actual data
+ // (header) starts
+ PINTERFACE_CB ICB_NodeHashLink; // Link in client node hash
+ ULONG ICB_ReferenceCount; // Number of routes that
+ // point to this CB
+ KSPIN_LOCK ICB_Lock; // Protects state,
+ // queues
+};
+
+#define InitICB(ifCB,IfIndex,IfType,NbAccept,NbDeliver) { \
+ (ifCB)->ICB_Index = IfIndex; \
+ (ifCB)->ICB_Network = INVALID_NETWORK_NUMBER; \
+ (ifCB)->ICB_Flags = 0; \
+ (ifCB)->ICB_NicId = INVALID_NIC_ID; \
+ (ifCB)->ICB_InterfaceType = IfType; \
+ (ifCB)->ICB_NetbiosAccept = NbAccept; \
+ (ifCB)->ICB_NetbiosDeliver = NbDeliver; \
+ memset (&(ifCB)->ICB_Stats, 0, sizeof (FWD_IF_STATS));\
+ KeInitializeSpinLock (&(ifCB)->ICB_Lock); \
+ (ifCB)->ICB_CashedInterface = NULL; \
+ (ifCB)->ICB_CashedRoute = NULL; \
+ (ifCB)->ICB_ReferenceCount = 0; \
+ (ifCB)->ICB_FilterInContext = NULL; \
+ (ifCB)->ICB_FilterOutContext = NULL; \
+ (ifCB)->ICB_ClientNode64[0] = 0; \
+ (ifCB)->ICB_NBRoutes = NULL; \
+ (ifCB)->ICB_PacketListId = -1; \
+ InitializeListHead (&(ifCB)->ICB_InternalQueue); \
+ InitializeListHead (&(ifCB)->ICB_ExternalQueue); \
+ (ifCB)->ICB_PendingQuota = MaxSendPktsQueued; \
+ switch ((ifCB)->ICB_InterfaceType) { \
+ case FWD_IF_PERMANENT: \
+ (ifCB)->ICB_Stats.OperationalState = FWD_OPER_STATE_DOWN;\
+ break; \
+ case FWD_IF_DEMAND_DIAL: \
+ case FWD_IF_LOCAL_WORKSTATION: \
+ case FWD_IF_REMOTE_WORKSTATION: \
+ (ifCB)->ICB_Stats.OperationalState = FWD_OPER_STATE_SLEEPING;\
+ KeQuerySystemTime ((PLARGE_INTEGER)&(ifCB)->ICB_DisconnectTime);\
+ (ifCB)->ICB_DisconnectTime -= (LONGLONG)SpoofingTimeout*10000000;\
+ break; \
+ } \
+}
+
+
+// Routes for netbios names (staticly seeded to reduce
+// internet broadcast traffic)
+struct _NB_ROUTE {
+ union {
+ ULONGLONG NBR_Name128[2];
+ UCHAR NBR_Name[16]; // Netbios name of destination
+ };
+ PINTERFACE_CB NBR_Destination; // Interface to send to
+ PNB_ROUTE NBR_Next; // Next route in the name list
+};
+
+
+// List used to allocate packets destined to WAN interfaces
+extern INT WanPacketListId;
+// Max number of outstanding sends
+extern ULONG MaxSendPktsQueued;
+
+// Segment sizes
+extern ULONG RouteSegmentSize;
+extern ULONG InterfaceSegmentSize;
+extern ULONG NBNameSegementSize;
+
+// Sizes of hash tables
+extern ULONG RouteHashSize;
+extern ULONG InterfaceHashSize;
+extern ULONG ClientHashSize;
+extern ULONG NBRouteHashSize;
+
+// Number of global client network
+extern ULONG GlobalNetwork;
+// Interface reserved for internal network
+extern PINTERFACE_CB InternalInterface;
+
+/*++
+*******************************************************************
+ C r e a t e T a b l e s
+
+Routine Description:
+ Allocates and intializes all hash tables and related structures
+Arguments:
+ None
+Return Value:
+ STATUS_SUCCESS - tables were created ok
+ STATUS_INSUFFICIENT_RESOURCES - resource allocation failed
+*******************************************************************
+--*/
+NTSTATUS
+CreateTables (
+ void
+ );
+
+/*++
+*******************************************************************
+ D e l e t e T a b l e s
+
+Routine Description:
+ Releases resources allocated for all hash tables
+Arguments:
+ None
+Return Value:
+ STATUS_SUCCESS - tables were freed ok
+*******************************************************************
+--*/
+NTSTATUS
+DeleteTables (
+ void
+ );
+
+/*++
+*******************************************************************
+ F r e e I n t e r f a c e
+
+Routine Description:
+ Releases memory allocated for interface to interface memory
+ zone.
+Arguments:
+ fwRoute - route block to release
+Return Value:
+ None
+*******************************************************************
+--*/
+VOID
+FreeInterface (
+ PINTERFACE_CB ifCB
+ );
+
+/*++
+*******************************************************************
+ F r e e R o u t e
+
+Routine Description:
+ Releases memory allocated for route to route memory
+ zone.
+Arguments:
+ fwRoute - route block to release
+Return Value:
+ None
+*******************************************************************
+--*/
+VOID
+FreeRoute (
+ PFWD_ROUTE fwRoute
+ );
+/*++
+*******************************************************************
+ A c q u i r e I n t e r f a c e R e f e r e n c e
+
+Routine Description:
+ Increments refernce count of interface control block
+ ICB can't be freed until all references to it are released.
+ The caller of this routine should have already had a reference
+ to the interface or must hold an InterfaceLock
+Arguments:
+ ifCB - interface control block to reference
+Return Value:
+ None
+*******************************************************************
+--*/
+//VOID
+//AcquireInterfaceReference (
+// PINTERFACE_CB ifCB
+// );
+#if DBG
+#define AcquireInterfaceReference(ifCB) \
+ do { \
+ ASSERTMSG ("Referenced ifCB is dead ", \
+ InterlockedIncrement(&ifCB->ICB_ReferenceCount)>0); \
+ } while (0)
+#else
+#define AcquireInterfaceReference(ifCB) \
+ InterlockedIncrement(&ifCB->ICB_ReferenceCount)
+#endif
+/*++
+*******************************************************************
+ R e l e a s e I n t e r f a c e R e f e r e n c e
+
+Routine Description:
+ Decrements refernce count of interface control block
+Arguments:
+ ifCB - interface control block to release
+Return Value:
+ None
+*******************************************************************
+--*/
+//PINTERFACE_CB
+//ReleaseInterfaceReference (
+// PINTERFACE_CB ifCB
+// );
+// if it drops below 0, it has alredy been removed from the table
+#define ReleaseInterfaceReference(ifCB) ( \
+ (InterlockedDecrement (&ifCB->ICB_ReferenceCount)>=0) \
+ ? ifCB \
+ : (FreeInterface (ifCB), (ifCB = NULL)) \
+)
+
+/*++
+*******************************************************************
+ I n t e r f a c e C o n t e x t T o R e f e r e n c e
+
+Routine Description:
+ Verifies that context supplied by the IPX stack is a valid
+ interface block and is still bound to the adapter with which
+ it is associated in the IPX stack
+Arguments:
+ ifCB - interface control block to reference
+ NicId - id of the adapter to which interface is bound
+Return Value:
+ None
+*******************************************************************
+--*/
+//PINTERFACE_CB
+//InterfaceContextToReference (
+// PVOID Context
+// );
+#define InterfaceContextToReference(Context,NicId) ( \
+ (InterlockedIncrement(&((PINTERFACE_CB)Context)->ICB_ReferenceCount)>0) \
+ ? ((NicId==((PINTERFACE_CB)Context)->ICB_NicId) \
+ ? (PINTERFACE_CB)Context \
+ : (ReleaseInterfaceReference(((PINTERFACE_CB)Context)), NULL)) \
+ : NULL \
+ )
+
+/*++
+*******************************************************************
+ G e t I n t e r f a c e R e f e r e n c e
+
+Routine Description:
+ Returns reference interface based on its index
+Arguments:
+ InterfaceIndex - unique id of the interface
+Return Value:
+ Pointer to interface control block if there is one in the table
+ NULL otherwise
+*******************************************************************
+--*/
+PINTERFACE_CB
+GetInterfaceReference (
+ ULONG InterfaceIndex
+ );
+
+
+/*++
+*******************************************************************
+ G e t N e x t I n t e r f a c e R e f e r e n c e
+
+Routine Description:
+ Returns reference to the next interface in the table
+ Reference to the provided interface is released
+Arguments:
+ ifCB - interface to start with or NULL to start from the
+ beginning of the interface table
+Return Value:
+ Pointer to interface control block if thare are any more interfaces
+ in the table
+ NULL otherwise
+*******************************************************************
+--*/
+PINTERFACE_CB
+GetNextInterfaceReference (
+ PINTERFACE_CB ifCB
+ );
+
+/*++
+*******************************************************************
+ A d d I n t e r f a c e
+
+Routine Description:
+ Adds interface control block to the table.
+Arguments:
+ InterfaceIndex - unique if of the interface
+ Info - interface paramters
+Return Value:
+ STATUS_SUCCESS - interface added ok
+ STATUS_UNSUCCESSFULL - interface is already in the table
+ STATUS_INSUFFICIENT_RESOURCES - can't allocate memory for
+ interface CB
+*******************************************************************
+--*/
+NTSTATUS
+AddInterface (
+ ULONG InterfaceIndex,
+ UCHAR InterfaceType,
+ BOOLEAN NetbiosAccept,
+ UCHAR NetbiosDeliver
+ );
+
+/*++
+*******************************************************************
+ A d d G l o b a l N e t C l i e n t
+
+Routine Description:
+ Adds interface control block to the table of
+ clients on the global network (should be done when
+ client connects)
+Arguments:
+ ifCB - interface control block to add to the table
+Return Value:
+ STATUS_SUCCESS - interface was added ok
+ STATUS_UNSUCCESSFULL - another interface with the same
+ node address is already in the table
+*******************************************************************
+--*/
+NTSTATUS
+AddGlobalNetClient (
+ PINTERFACE_CB ifCB
+ );
+
+/*++
+*******************************************************************
+ D e l e t e G l o b a l N e t C l i e n t
+
+Routine Description:
+ Removes interface control block from the table of
+ clients on the global network (should be done when
+ client disconnects)
+Arguments:
+ ifCB - interface control block to remove from the table
+Return Value:
+ STATUS_SUCCESS - interface was removed ok
+*******************************************************************
+--*/
+NTSTATUS
+DeleteGlobalNetClient (
+ PINTERFACE_CB ifCB
+ );
+
+/*++
+*******************************************************************
+ D e l e t e I n t e r f a c e
+
+Routine Description:
+ Deletes interface control block (the block is not actually
+ disposed of until all references to it are released).
+Arguments:
+ InterfaceIndex - unique if of the interface
+Return Value:
+ STATUS_SUCCESS - interface info retreived ok
+ STATUS_UNSUCCESSFULL - interface is not in the table
+*******************************************************************
+--*/
+NTSTATUS
+DeleteInterface (
+ ULONG InterfaceIndex
+ );
+
+/*++
+*******************************************************************
+ A d d R o u t e
+
+Routine Description:
+ Adds route to the hash table and finds and stores the reference
+ to the associated interface control block in the route.
+Arguments:
+ Network - route's destination network
+ NextHopAddress - mac address of next hop router if network is not
+ directly connected
+ TickCount - ticks to reach the destination net
+ HopCount - hopss to reach the destination net
+ InterfaceIndex - index of the associated interface (through which
+ packets destined to the network are to be sent)
+Return Value:
+ STATUS_SUCCESS - route was added ok
+ STATUS_UNSUCCESSFUL - route is already in the table
+ STATUS_INSUFFICIENT_RESOURCES - can't allocate memory for
+ route block
+*******************************************************************
+--*/
+NTSTATUS
+AddRoute (
+ ULONG Network,
+ UCHAR *NextHopAddress,
+ USHORT TickCount,
+ USHORT HopCount,
+ ULONG InterfaceIndex
+ );
+
+/*++
+*******************************************************************
+ D e l e t e R o u t e
+
+Routine Description:
+ Deletes route from the hash table and releases the reference
+ to the interface control block associated with the route.
+Arguments:
+ Network - route's destination network
+Return Value:
+ STATUS_SUCCESS - route was deleted ok
+ STATUS_UNSUCCESSFUL - route is not in the table
+*******************************************************************
+--*/
+NTSTATUS
+DeleteRoute (
+ ULONG Network
+ );
+
+/*++
+*******************************************************************
+ U p d a t e R o u t e
+
+Routine Description:
+ Updates route in the hash table
+Arguments:
+ Network - route's destination network
+ NextHopAddress - mac address of next hop router if network is not
+ directly connected
+ TickCount - ticks to reach the destination net
+ HopCount - hopss to reach the destination net
+ InterfaceIndex - index of the associated interface (through which
+ packets destined to the network are to be sent)
+Return Value:
+ STATUS_SUCCESS - interface info retreived ok
+ STATUS_UNSUCCESSFUL - interface is not in the table
+*******************************************************************
+--*/
+NTSTATUS
+UpdateRoute (
+ ULONG Network,
+ UCHAR *NextHopAddress,
+ USHORT TickCount,
+ USHORT HopCount,
+ ULONG InterfaceIndex
+ );
+
+/*++
+*******************************************************************
+ F i n d D e s t i n a t i o n
+
+Routine Description:
+ Finds destination interface for IPX address and
+ returns reference to its control block.
+Arguments:
+ Network - destination network
+ Node - destination node (needed in case of global client)
+ Route - buffer to place route reference
+Return Value:
+ Reference to destination interface CB
+ NULL if route it not found
+*******************************************************************
+--*/
+PINTERFACE_CB
+FindDestination (
+ IN ULONG Network,
+ IN PUCHAR Node,
+ OUT PFWD_ROUTE *Route
+ );
+/*++
+*******************************************************************
+ A c q u i r e R o u t e R e f e r e n c e
+
+Routine Description:
+ Increments refernce count of the route block
+ Route block can't be freed until all references to it are released.
+ The caller of this routine should have already had a reference
+ to the route or must hold an TableWriteLock
+Arguments:
+ fwRoute - route block to reference
+Return Value:
+ None
+*******************************************************************
+--*/
+//VOID
+//AcquireRouteReference (
+// PFW+ROUTE fwRoute
+// );
+#define AcquireRouteReference(fwRoute) \
+ InterlockedIncrement(&fwRoute->FR_ReferenceCount)
+
+
+
+/*++
+*******************************************************************
+ R e l e a s e R o u t e R e f e r e n c e
+
+Routine Description:
+ Decrements refernce count of route block
+Arguments:
+ fwRoute - route block to release
+Return Value:
+ None
+*******************************************************************
+--*/
+//VOID
+//ReleaseRouteReference (
+// PFW_ROUTE fwRoute
+// );
+// if it drops below 0, it has alredy been removed from the table
+#define ReleaseRouteReference(fwRoute) { \
+ if (InterlockedDecrement (&fwRoute->FR_ReferenceCount)<0) { \
+ FreeRoute (fwRoute); \
+ fwRoute = NULL; \
+ } \
+}
+
+
+/*++
+*******************************************************************
+ A d d N B R o u t e s
+
+Routine Description:
+ Adds netbios names associated with interface to netbios
+ route hash table
+Arguments:
+ ifCB - interface with which names are associated
+ Names - array of names
+ Count - number of names in the array
+ routeArray - buffer to place pointer to allocated array of routes
+Return Value:
+ STATUS_SUCCESS - names were added ok
+ STATUS_UNSUCCESSFUL - one of the names is already in the table
+ STATUS_INSUFFICIENT_RESOURCES - can't allocate memory for
+ route array
+*******************************************************************
+--*/
+NTSTATUS
+AddNBRoutes (
+ PINTERFACE_CB ifCB,
+ FWD_NB_NAME Names[],
+ ULONG Count,
+ PNB_ROUTE *routeArray
+ );
+
+/*++
+*******************************************************************
+ D e l e t e N B R o u t e s
+
+Routine Description:
+ Deletes nb routes in the array from the route table and frees
+ the array
+Arguments:
+ nbRoutes - array of routes
+ Count - number of routes in the array
+Return Value:
+ STATUS_SUCCESS - route was deleted ok
+ STATUS_UNSUCCESSFUL - route is not in the table
+*******************************************************************
+--*/
+NTSTATUS
+DeleteNBRoutes (
+ PNB_ROUTE nbRoutes,
+ ULONG Count
+ );
+
+/*++
+*******************************************************************
+ F i n d N B D e s t i n a t i o n
+
+Routine Description:
+ Finds destination interface for nb name and
+ returns reference to its control block.
+Arguments:
+ Name - name to look for
+Return Value:
+ Reference to destination interface CB
+ NULL if route it not found
+*******************************************************************
+--*/
+PINTERFACE_CB
+FindNBDestination (
+ IN PUCHAR Name
+ );
+#endif
diff --git a/private/ntos/tdi/isn/fwd/up/makefile b/private/ntos/tdi/isn/fwd/up/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/up/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isn/fwd/up/sources b/private/ntos/tdi/isn/fwd/up/sources
new file mode 100644
index 000000000..229bd8e34
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/up/sources
@@ -0,0 +1,31 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+UP_DRIVER=yes
+
+BINPLACE_FLAGS=$(BINPLACE_FLAGS) -d dump\up
+
+TARGETPATH=obj
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/isn/inc/bind.h b/private/ntos/tdi/isn/inc/bind.h
new file mode 100644
index 000000000..27a98d7c5
--- /dev/null
+++ b/private/ntos/tdi/isn/inc/bind.h
@@ -0,0 +1,843 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ bind.h
+
+Abstract:
+
+ Private include file for the ISN transport. It defines the
+ structures used for binding between IPX and the upper drivers.
+
+Author:
+
+ Adam Barr (adamba) 04-Oct-1993
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 5-July-1995
+ Bug fixes - tagged [SA]
+
+--*/
+
+#ifndef _ISN_BIND_
+#define _ISN_BIND_
+
+//
+// Retrieve the common definitions.
+//
+
+#include <isnkrnl.h>
+
+
+//
+// Define the IOCTL used for binding between the upper
+// drivers and IPX.
+//
+
+#define _IPX_CONTROL_CODE(request,method) \
+ CTL_CODE(FILE_DEVICE_TRANSPORT, request, method, FILE_ANY_ACCESS)
+
+#define IOCTL_IPX_INTERNAL_BIND _IPX_CONTROL_CODE( 0x1234, METHOD_BUFFERED )
+
+
+//
+// [FW] Error codes - reusing NTSTATUS codes
+//
+
+#define STATUS_ADAPTER_ALREADY_OPENED STATUS_UNSUCCESSFUL
+#define STATUS_ADAPTER_ALREADY_CLOSED STATUS_UNSUCCESSFUL
+#define STATUS_FILTER_FAILED STATUS_UNSUCCESSFUL
+#define STATUS_DROP_SILENTLY STATUS_UNSUCCESSFUL
+
+//
+// Identifier for the drivers in ISN.
+//
+
+#define IDENTIFIER_NB 0
+#define IDENTIFIER_SPX 1
+#define IDENTIFIER_RIP 2
+#define IDENTIFIER_IPX 3
+
+#ifdef _PNP_POWER
+//
+// This the number of PVOIDs in the beginning of the SEND_RESERVED
+// section of a packet header, to be set aside by the ISN clients (NB/SPX)
+// for IPX's private use.
+//
+#define SEND_RESERVED_COMMON_SIZE 8
+#endif
+
+//
+// Definition of a RIP router table entry.
+//
+
+typedef struct _IPX_ROUTE_ENTRY {
+ UCHAR Network[4];
+ USHORT NicId;
+ UCHAR NextRouter[6];
+ NDIS_HANDLE NdisBindingContext;
+ USHORT Flags;
+ USHORT Timer;
+ UINT Segment;
+ USHORT TickCount;
+ USHORT HopCount;
+ LIST_ENTRY AlternateRoute;
+ LIST_ENTRY NicLinkage;
+ struct {
+ LIST_ENTRY Linkage;
+ ULONG Reserved[1];
+ } PRIVATE;
+} IPX_ROUTE_ENTRY, * PIPX_ROUTE_ENTRY;
+
+//
+// Definition of the Flags values.
+//
+
+#define IPX_ROUTER_PERMANENT_ENTRY 0x0001 // entry should never be deleted
+#define IPX_ROUTER_LOCAL_NET 0x0002 // locally attached network
+#define IPX_ROUTER_SCHEDULE_ROUTE 0x0004 // call ScheduleRouteHandler after using
+#define IPX_ROUTER_GLOBAL_WAN_NET 0x0008 // this is for rip's global network number
+
+
+//
+// Definition of the structure provided on a find
+// route/find route completion call.
+//
+
+//
+// [SA] Bug #15094 added node number to the structure.
+//
+
+//
+// [FW] Added Hop and Tick counts so this structure can be passed
+// as such to the Forwarder - hop and tick counts are queried in actions
+//
+
+typedef struct _IPX_FIND_ROUTE_REQUEST {
+ UCHAR Network[4];
+ UCHAR Node[6] ;
+ IPX_LOCAL_TARGET LocalTarget;
+ USHORT TickCount; // [FW]
+ USHORT HopCount; // [FW]
+ UCHAR Identifier;
+ UCHAR Type;
+ UCHAR Reserved1[2];
+ PVOID Reserved2;
+ LIST_ENTRY Linkage;
+} IPX_FIND_ROUTE_REQUEST, *PIPX_FIND_ROUTE_REQUEST;
+
+//
+// Definitions for the Type value.
+//
+
+#define IPX_FIND_ROUTE_NO_RIP 1 // fail if net is not in database
+#define IPX_FIND_ROUTE_RIP_IF_NEEDED 2 // return net if in database, otherwise RIP out
+#define IPX_FIND_ROUTE_FORCE_RIP 3 // re-RIP even if net is in database
+
+
+//
+// Structure used when querying the line information
+// for a specific NID ID.
+//
+
+typedef struct _IPX_LINE_INFO {
+ UINT LinkSpeed;
+ UINT MaximumPacketSize;
+ UINT MaximumSendSize;
+ UINT MacOptions;
+} IPX_LINE_INFO, *PIPX_LINE_INFO;
+
+
+
+//
+// Functions provided by the upper driver.
+//
+
+//
+// [FW] Added the ForwarderAdapterContext to the paramters
+// SPX/NB can ignore this for now
+//
+
+typedef BOOLEAN
+(*IPX_INTERNAL_RECEIVE) (
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN ULONG FwdAdapterContext, // [FW]
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize,
+ IN PMDL pMdl
+);
+
+typedef VOID
+(*IPX_INTERNAL_RECEIVE_COMPLETE) (
+ IN USHORT NicId
+);
+
+//
+// [FW] Status and ScheduleRoute removed from the bind input
+// [ZZZZZZZZZ]
+
+typedef VOID
+(*IPX_INTERNAL_STATUS) (
+ IN USHORT NicId,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength
+);
+
+typedef VOID
+(*IPX_INTERNAL_SCHEDULE_ROUTE) (
+ IN PIPX_ROUTE_ENTRY RouteEntry
+);
+
+typedef VOID
+(*IPX_INTERNAL_SEND_COMPLETE) (
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+);
+
+typedef VOID
+(*IPX_INTERNAL_TRANSFER_DATA_COMPLETE) (
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+);
+
+typedef VOID
+(*IPX_INTERNAL_FIND_ROUTE_COMPLETE) (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute
+);
+
+typedef VOID
+(*IPX_INTERNAL_LINE_UP) (
+ IN USHORT NicId,
+ IN PIPX_LINE_INFO LineInfo,
+ IN NDIS_MEDIUM DeviceType,
+ IN PVOID ConfigurationData
+);
+
+typedef VOID
+(*IPX_INTERNAL_LINE_DOWN) (
+ IN USHORT NicId,
+ IN ULONG FwdAdapterContext
+);
+
+#if defined(_PNP_POWER)
+
+//
+// following opcodes are used when calling the
+// above handler.
+//
+typedef enum _IPX_PNP_OPCODE {
+ IPX_PNP_ADD_DEVICE, // 0 - addition of the first adapter
+ IPX_PNP_DELETE_DEVICE, // 1 - deletion of the last adapter
+ IPX_PNP_TRANSLATE_DEVICE, // 2 - translate device resource
+ IPX_PNP_TRANSLATE_ADDRESS, // 3 - translate address resource
+ IPX_PNP_ADDRESS_CHANGE, // 4 - Adapter address or Reserved address changed
+ IPX_PNP_MAX_OPCODES, // 5
+} IPX_PNP_OPCODE, *PIPX_PNP_OPCODE;
+
+//
+// PnP event notification handler.
+//
+typedef VOID
+(*IPX_INTERNAL_PNP_NOTIFICATION) (
+ IN IPX_PNP_OPCODE PnPOpcode,
+ IN OUT PVOID PnpData
+);
+
+//
+// Pointer to this structure is passed in PnPData portion of
+// the above handler when the opcode is ADD_DEVICE or DELETE_DEVICE.
+//
+typedef struct _IPX_PNP_INFO {
+ ULONG NetworkAddress;
+ UCHAR NodeAddress[6];
+ BOOLEAN NewReservedAddress; // where the above is a new reserved
+ // address for the Ipx clients.
+ BOOLEAN FirstORLastDevice; // is this a first card arrival or last card deletion.
+ IPX_LINE_INFO LineInfo; // New LineInfo.
+ NIC_HANDLE NicHandle;
+} IPX_PNP_INFO, *PIPX_PNP_INFO;
+
+#endif _PNP_POWER
+
+//
+// [FW] New entry points provided by the Kernel Forwarder.
+// These are not filled in by NB and SPX.
+//
+
+/*++
+
+Routine Description:
+
+ This routine is provided by the Kernel Forwarder to filter packets being sent out
+ by NB/SPX/TDI thru' IPX - does not include those sent out by the Forwarder (external sends)
+
+Arguments:
+
+ LocalTarget - the NicId and next hop router MAC address
+
+ FwdAdapterContext - Forwarder's context - preferred NIC if not INVALID_CONTEXT_VALUE
+
+ Packet - packet to be sent out
+
+ IpxHeader - points to the IPX header
+
+ Data - points to after the IPX header - needed in spoofing of keepalives.
+
+ PacketLength - length of the packet
+
+ fIterate - a flag to indicate if this is a packet for the iteration of which the
+ Fwd takes responsibility - typically type 20 NetBIOS frames
+
+
+Return Value:
+
+ STATUS_SUCCESS - if the preferred NIC was OK and packet passed filtering
+ STATUS_NETWORK_UNREACHABLE - if the preferred was not OK or packet failed filtering
+ STATUS_PENDING - if preferred NIC was OK but line down
+
+ BUGBUG: Forwarder should give us a different status than STATUS_NETWORK_UNREACHABLE for changed NIC
+--*/
+typedef NTSTATUS
+(*IPX_FW_INTERNAL_SEND) (
+ IN OUT PIPX_LOCAL_TARGET LocalTarget,
+ IN ULONG FwdAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN PUCHAR IpxHeader,
+ IN PUCHAR Data,
+ IN ULONG PacketLength,
+ IN BOOLEAN fIterate
+);
+
+/*++
+
+Routine Description:
+
+ This routine is provided by the Kernel Forwarder to find the route to a given node and network
+
+Arguments:
+
+ Network - the destination network
+
+ Node - destination node
+
+ RouteEntry - filled in by the Forwarder if a route exists
+
+Return Value:
+
+ STATUS_SUCCESS
+ STATUS_NETWORK_UNREACHABLE - if the findroute failed
+
+--*/
+typedef NTSTATUS
+(*IPX_FW_FIND_ROUTE) (
+ IN PUCHAR Network,
+ IN PUCHAR Node,
+ OUT PIPX_FIND_ROUTE_REQUEST RouteEntry
+);
+
+/*++
+
+Routine Description:
+
+ This routine is provided by the Kernel Forwarder to find the route to a given node and network
+
+Arguments:
+
+ FwdAdapterContext - Forwarder's context
+
+ RemoteAddress - the address the packet came on
+
+ LookAheadBuffer - packet header that came in
+
+ LookAheadBufferSize - size of the lookaheadbuffer
+
+Return Value:
+
+ STATUS_SUCCESS
+ STATUS_FILTER_FAILED - if the packet was not allowed by the filter
+
+--*/
+typedef NTSTATUS
+(*IPX_FW_INTERNAL_RECEIVE) (
+ IN ULONG FwdAdapterContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN PUCHAR LookAheadBuffer,
+ IN UINT LookAheadBufferSize
+);
+
+//
+// Input to the bind IOCTL
+//
+
+//
+// [FW] Removed the status and schedule route handlers
+//
+typedef struct _IPX_INTERNAL_BIND_INPUT {
+ USHORT Version;
+ UCHAR Identifier;
+ BOOLEAN BroadcastEnable;
+ UINT LookaheadRequired;
+ UINT ProtocolOptions;
+ IPX_INTERNAL_RECEIVE ReceiveHandler;
+ IPX_INTERNAL_RECEIVE_COMPLETE ReceiveCompleteHandler;
+ IPX_INTERNAL_STATUS StatusHandler;
+ IPX_INTERNAL_SEND_COMPLETE SendCompleteHandler;
+ IPX_INTERNAL_TRANSFER_DATA_COMPLETE TransferDataCompleteHandler;
+ IPX_INTERNAL_FIND_ROUTE_COMPLETE FindRouteCompleteHandler;
+ IPX_INTERNAL_LINE_UP LineUpHandler;
+ IPX_INTERNAL_LINE_DOWN LineDownHandler;
+ IPX_INTERNAL_SCHEDULE_ROUTE ScheduleRouteHandler;
+#if defined(_PNP_POWER)
+ IPX_INTERNAL_PNP_NOTIFICATION PnPHandler;
+#endif _PNP_POWER
+ IPX_FW_INTERNAL_SEND InternalSendHandler;
+ IPX_FW_FIND_ROUTE FindRouteHandler;
+ IPX_FW_INTERNAL_RECEIVE InternalReceiveHandler;
+ ULONG RipParameters;
+} IPX_INTERNAL_BIND_INPUT, * PIPX_INTERNAL_BIND_INPUT;
+
+#if defined(_PNP_POWER)
+#define ISN_VERSION 2
+#endif _PNP_POWER
+
+
+//
+// Bit mask values for RipParameters.
+//
+
+#define IPX_RIP_PARAM_GLOBAL_NETWORK 0x00000001 // single network for all WANS
+
+
+
+//
+// Functions provided by the lower driver.
+//
+
+typedef NDIS_STATUS
+(*IPX_INTERNAL_SEND) (
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+);
+
+typedef VOID
+(*IPX_INTERNAL_FIND_ROUTE) (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest
+);
+
+typedef NTSTATUS
+(*IPX_INTERNAL_QUERY) (
+ IN ULONG InternalQueryType,
+#if defined(_PNP_POWER)
+ IN PNIC_HANDLE NicHandle OPTIONAL,
+#else
+ IN USHORT NicId OPTIONAL,
+#endif _PNP_POWER
+ IN OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG BufferLengthNeeded OPTIONAL
+);
+
+typedef VOID
+(*IPX_INTERNAL_TRANSFER_DATA)(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+//
+// Definitions of the internal query types. In all cases
+// STATUS_SUCCESS is returned if the request succeeds, and
+// STATUS_BUFFER_TOO_SMALL is returned, and BufferLengthNeeded
+// set if specified, if the buffer is too short. Other
+// return codes are defined below. The routine never pends.
+//
+
+//
+// This is used to query the line info. NicId specifies which one
+// to query. Buffer contains an IPX_LINE_INFO structure which is
+// used to return the information. Other return values:
+//
+// STATUS_INVALID_PARAMETER - NicId is invalid.
+//
+
+#define IPX_QUERY_LINE_INFO 1
+
+//
+// This is used to query the maximum NicId. NicId is unused. The
+// Buffer contains a USHORT which is used to return the information.
+//
+
+#define IPX_QUERY_MAXIMUM_NIC_ID 2
+
+//
+// This is used to determine if the IPX address specified was sent
+// by our local machine. If the address is the source address of a
+// received frame, NicId should be the ID that was indicated; otherwise
+// it should be set to 0. Buffer holds a TDI_ADDRESS_IPX. This
+// call returns STATUS_SUCCESS if the address is local, and
+// STATUS_NO_SUCH_DEVICE if not.
+//
+
+#define IPX_QUERY_IS_ADDRESS_LOCAL 3
+
+//
+// This is used to query the receive buffer space of a given NicId.
+// Buffer contains a ULONG which is used to return the information.
+// It returns STATUS_INVALID_PARAMETER if NicId is invalid.
+//
+
+#define IPX_QUERY_RECEIVE_BUFFER_SPACE 4
+
+//
+// This is used to query the local IPX address of a given NicId.
+// Buffer contains a TDI_ADDRESS_IPX structure (the Socket is
+// returned as 0). If it is queried on net 0 it returns the
+// virtual network if there is one, otherwise STATUS_INVALID_PARAMETER.
+// It returns STATUS_INVALID_PARAMETER if NicId is invalid.
+//
+
+#define IPX_QUERY_IPX_ADDRESS 5
+
+//
+// This is used to return the source routing information for
+// a give remote address. NicId will be the NIC the packet was
+// received from. The IPX_SOURCE_ROUTING_QUERY is contained
+// in Buffer. Always returns STATUS_SUCCESS, although the
+// SourceRoutingLength may be 0 for unknown remotes.
+//
+// The source routing is return in the direction it was received
+// from the remote, not the direction used in replying. The
+// MaximumSendSize includes the IPX header (as it does in
+// IPX_LINE_INFO).
+//
+
+#define IPX_QUERY_SOURCE_ROUTING 6
+
+typedef struct _IPX_SOURCE_ROUTING_INFO {
+ USHORT Identifier; // input: the caller's IDENTIFIER_SPX, _NB, etc.
+ UCHAR RemoteAddress[6]; // input: the remote address
+ UCHAR SourceRouting[18]; // output: room for the maximum source route
+ USHORT SourceRoutingLength; // output: the valid length of source route
+ ULONG MaximumSendSize; // output: based on nic and source routing
+} IPX_SOURCE_ROUTING_INFO, * PIPX_SOURCE_ROUTING_INFO;
+
+//
+// This is used to query the maximum NicId over which outgoing type
+// 20 packets should be sent. It will be less than or equal to
+// the IPX_QUERY_MAXIMUM_NIC_ID value. What's excluded are down wan
+// lines and dialin wan lines if DisableDialinNetbios bit 1 is set.
+//
+
+#define IPX_QUERY_MAX_TYPE_20_NIC_ID 7
+
+#if defined(_PNP_POWER)
+
+//
+// This are used by NB to pass down these TDI queries which cannot
+// be completed in NB.
+//
+
+#define IPX_QUERY_DATA_LINK_ADDRESS 8
+#define IPX_QUERY_NETWORK_ADDRESS 9
+
+#endif _PNP_POWER
+
+//
+// Output of a non-RIP bind.
+//
+
+typedef struct _IPX_INTERNAL_BIND_OUTPUT {
+ USHORT Version;
+ UCHAR Node[6];
+ UCHAR Network[4];
+ USHORT MacHeaderNeeded;
+ USHORT IncludedHeaderOffset;
+ IPX_LINE_INFO LineInfo;
+ IPX_INTERNAL_SEND SendHandler;
+ IPX_INTERNAL_FIND_ROUTE FindRouteHandler;
+ IPX_INTERNAL_QUERY QueryHandler;
+ IPX_INTERNAL_TRANSFER_DATA TransferDataHandler;
+} IPX_INTERNAL_BIND_OUTPUT, * PIPX_INTERNAL_BIND_OUTPUT;
+
+
+
+//
+// Lower driver functions provided only for RIP.
+//
+
+typedef UINT
+(*IPX_INTERNAL_GET_SEGMENT) (
+ IN UCHAR Network[4]
+);
+
+typedef PIPX_ROUTE_ENTRY
+(*IPX_INTERNAL_GET_ROUTE) (
+ IN UINT Segment,
+ IN UCHAR Network[4]
+);
+
+typedef BOOLEAN
+(*IPX_INTERNAL_ADD_ROUTE) (
+ IN UINT Segment,
+ IN PIPX_ROUTE_ENTRY RouteEntry
+);
+
+typedef BOOLEAN
+(*IPX_INTERNAL_DELETE_ROUTE) (
+ IN UINT Segment,
+ IN PIPX_ROUTE_ENTRY RouteEntry
+);
+
+typedef PIPX_ROUTE_ENTRY
+(*IPX_INTERNAL_GET_FIRST_ROUTE) (
+ IN UINT Segment
+);
+
+typedef PIPX_ROUTE_ENTRY
+(*IPX_INTERNAL_GET_NEXT_ROUTE) (
+ IN UINT Segment
+);
+
+typedef VOID
+(*IPX_INTERNAL_INCREMENT_WAN_INACTIVITY) (
+#ifdef _PNP_LATER
+ IN NIC_HANDLE NicHandle
+#else
+ IN USHORT NicId
+#endif
+);
+
+typedef ULONG
+(*IPX_INTERNAL_QUERY_WAN_INACTIVITY) (
+#ifdef _PNP_LATER
+ IN NIC_HANDLE NicHandle
+#else
+ IN USHORT NicId
+#endif
+
+);
+
+/*++
+
+Routine Description:
+
+ This routine is called by the Kernel Forwarder to open an adapter
+
+Arguments:
+
+ AdapterIndex - index of the adapter to open (NICid for now - will change to a struct
+ with a version number, signature and the NicId
+ FwdAdapterContext - Forwarder's context
+ IpxAdapterContext - our context (for now we use the NICid - for pnp will change
+ this to contain a signature and version #)
+
+Return Value:
+
+ STATUS_INVALID_HANDLE if the AdapterIndex handle was invalid
+ STATUS_ADAPTER_ALREADY_OPENED if the Adapter is being opened a second time
+ STATUS_SUCCESS
+
+--*/
+typedef NTSTATUS
+(*IPX_FW_OPEN_ADAPTER) (
+ IN NIC_HANDLE AdapterIndex,
+ IN ULONG FwdAdapterContext,
+ OUT PNIC_HANDLE IpxAdapterContext
+);
+
+/*++
+
+Routine Description:
+
+ This routine is called by the Kernel Forwarder to close an adapter
+
+Arguments:
+
+ IpxAdapterContext - our context (for now we use the NICid - for pnp will change
+ this to contain a signature and version#)
+
+Return Value:
+
+ STATUS_ADAPTER_ALREADY_CLOSED - if the adapter is being closed a second time
+ STATUS_SUCCESS
+
+--*/
+typedef NTSTATUS
+(*IPX_FW_CLOSE_ADAPTER) (
+ IN NIC_HANDLE IpxAdapterContext
+);
+
+/*++
+
+Routine Description:
+
+ This routine is called by the Kernel Forwarder to indicate that a pending
+ internal send to it has completed.
+
+Arguments:
+
+ LocalTarget - if Status is OK, this has the local target for the send.
+
+ Packet - A pointer to the NDIS_PACKET that we sent.
+
+ PacketLength - length of the packet (including the IPX header)
+
+ Status - the completion status of the send - STATUS_SUCCESS or STATUS_NETWORK_UNREACHABLE
+
+Return Value:
+
+ none.
+
+--*/
+typedef VOID
+(*IPX_FW_INTERNAL_SEND_COMPLETE) (
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN NTSTATUS Status
+);
+
+//
+// Describes a single network.
+//
+
+typedef struct _IPX_NIC_DATA {
+ USHORT NicId;
+ UCHAR Node[6];
+ UCHAR Network[4];
+ IPX_LINE_INFO LineInfo;
+ NDIS_MEDIUM DeviceType;
+ ULONG EnableWanRouter;
+} IPX_NIC_DATA, * PIPX_NIC_DATA;
+
+
+//
+// Describes all networks.
+//
+
+typedef struct _IPX_NIC_INFO_BUFFER {
+ USHORT NicCount;
+ USHORT VirtualNicId;
+ UCHAR VirtualNetwork[4];
+ IPX_NIC_DATA NicData[1];
+} IPX_NIC_INFO_BUFFER, * PIPX_NIC_INFO_BUFFER;
+
+
+//
+// Output from a RIP bind (the actual structure size is
+// based on the number of IPX_NIC_DATA elements in the
+// final IPX_NIC_INFO_BUFFER structure).
+//
+
+typedef struct _IPX_INTERNAL_BIND_RIP_OUTPUT {
+ USHORT Version;
+ USHORT MaximumNicCount;
+ USHORT MacHeaderNeeded;
+ USHORT IncludedHeaderOffset;
+ IPX_INTERNAL_SEND SendHandler;
+ UINT SegmentCount;
+ KSPIN_LOCK * SegmentLocks;
+ IPX_INTERNAL_GET_SEGMENT GetSegmentHandler;
+ IPX_INTERNAL_GET_ROUTE GetRouteHandler;
+ IPX_INTERNAL_ADD_ROUTE AddRouteHandler;
+ IPX_INTERNAL_DELETE_ROUTE DeleteRouteHandler;
+ IPX_INTERNAL_GET_FIRST_ROUTE GetFirstRouteHandler;
+ IPX_INTERNAL_GET_NEXT_ROUTE GetNextRouteHandler;
+ IPX_INTERNAL_INCREMENT_WAN_INACTIVITY IncrementWanInactivityHandler;
+ IPX_INTERNAL_QUERY_WAN_INACTIVITY QueryWanInactivityHandler;
+ IPX_INTERNAL_TRANSFER_DATA TransferDataHandler;
+ IPX_FW_OPEN_ADAPTER OpenAdapterHandler;
+ IPX_FW_CLOSE_ADAPTER CloseAdapterHandler;
+ IPX_FW_INTERNAL_SEND_COMPLETE InternalSendCompleteHandler;
+ IPX_NIC_INFO_BUFFER NicInfoBuffer;
+} IPX_INTERNAL_BIND_RIP_OUTPUT, * PIPX_INTERNAL_BIND_RIP_OUTPUT;
+
+//
+// [FW] Used by the forwarder to fill up the localtarget
+//
+
+#ifdef _PNP_LATER
+#define NIC_HANDLE_FROM_NIC(_nichandle, _nic) \
+ _nichandle.NicId = _nic; \
+ _nichandle.Signature = IPX_BINDING_SIGNATURE; \
+ if (_nic == 0) { \
+ _nichandle.Version = 0; \
+ } else { \
+ _nichandle.Version = IpxDevice->Bindings[_nic].Version; \
+ }
+
+#else
+
+#define NIC_HANDLE_FROM_NIC(_nichandle, _nic) \
+ _nichandle.NicId = (USHORT)_nic;
+
+#endif
+
+//
+// VOID
+// ADAPTER_CONTEXT_TO_LOCAL_TARGET(
+// IN NIC_HANDLE _context;
+// IN PIPX_LOCAL_TARGET _localtarget;
+// );
+//
+#define ADAPTER_CONTEXT_TO_LOCAL_TARGET(_context, _localtarget) \
+ (_localtarget)->NicHandle.NicId = (_context).NicId;
+
+//
+// VOID
+// CONSTANT_ADAPTER_CONTEXT_TO_LOCAL_TARGET(
+// IN NIC_HANDLE _context;
+// IN PIPX_LOCAL_TARGET _localtarget;
+// );
+//
+#define CONSTANT_ADAPTER_CONTEXT_TO_LOCAL_TARGET(_context, _localtarget) \
+ (_localtarget)->NicHandle.NicId = (USHORT)(_context);
+
+
+//
+// [FW] Used to indicate to the Forwarder that a preferred NIC is not given
+// in InternalSend
+//
+#define INVALID_CONTEXT_VALUE 0xffffffff
+
+//
+// [FW] This is the value returned (in FindRoute) to IPX from the Forwarder in case of a demand dial Nic.
+// On an InternalSend, this is passed up to the FWD, which brings up the line and returns the good LocalTarget
+//
+#define DEMAND_DIAL_ADAPTER_CONTEXT 0xffffffff
+
+//
+// Adapter context used by the FWD to represent a send to the virtual net.
+// IPX maps this to the loopback adapter.
+//
+#define VIRTUAL_NET_ADAPTER_CONTEXT 0xfffffffe // -2
+
+//
+// Context passed up to the FWD on a loopback send.
+//
+#define VIRTUAL_NET_FORWARDER_CONTEXT 0xfffffffe // -2
+
+//
+// Special NIC id used by NB/SPX to send packets over all NICs.
+//
+#define ITERATIVE_NIC_ID 0xfffd // -3
+
+#endif // _ISN_BIND_
+
diff --git a/private/ntos/tdi/isn/inc/ioctls.h b/private/ntos/tdi/isn/inc/ioctls.h
new file mode 100644
index 000000000..e7dd7b81a
--- /dev/null
+++ b/private/ntos/tdi/isn/inc/ioctls.h
@@ -0,0 +1,155 @@
+#define VER_IOCH "@(#)MCS ipx/h/ioctls.h 1.00.00 - 08 APR 1993";
+
+/****************************************************************************
+* (c) Copyright 1990, 1993 Micro Computer Systems, Inc. All rights reserved.
+*****************************************************************************
+*
+* Title: IPX/SPX Driver for Windows NT
+*
+* Module: ipx/h/ioctls.h
+*
+* Version: 1.00.00
+*
+* Date: 04-08-93
+*
+* Author: Brian Walker
+*
+*****************************************************************************
+*
+* Change Log:
+*
+* Date DevSFC Comment
+* -------- ------ -------------------------------------------------------
+*****************************************************************************
+*
+* Functional Description:
+*
+* IOCTL defines
+*
+****************************************************************************/
+
+/** Ioctls for IPX - (X) = User callable **/
+
+/**
+ ioctls will values 100 - 150 were added for the NT port.
+**/
+
+#define I_MIPX (('I' << 24) | ('D' << 16) | ('P' << 8))
+#define MIPX_SETNODEADDR I_MIPX | 0 /* Set the node address */
+#define MIPX_SETNETNUM I_MIPX | 1 /* Set the network number */
+#define MIPX_SETPTYPE I_MIPX | 2 /* (X) Set the packet type */
+#define MIPX_SENTTYPE I_MIPX | 3 /* (X) Set the xport type */
+#define MIPX_SETPKTSIZE I_MIPX | 4 /* Set the packet size */
+#define MIPX_SETSAP I_MIPX | 5 /* Set the sap/type field */
+#define MIPX_SENDOPTS I_MIPX | 6 /* (X) Send options on recv */
+#define MIPX_NOSENDOPTS I_MIPX | 7 /* (X) Don't send options on recv */
+#define MIPX_SENDSRC I_MIPX | 8 /* (X) Send source address up */
+#define MIPX_NOSENDSRC I_MIPX | 9 /* (X) Don't Send source address up */
+#define MIPX_CONVBCAST I_MIPX | 10 /* Convert TKR bcast to func addr */
+#define MIPX_NOCONVBCAST I_MIPX | 11 /* Don't cnvrt TKR bcast to funcaddr */
+#define MIPX_SETCARDTYPE I_MIPX | 12 /* Set 802.3 or ETH type */
+#define MIPX_STARGROUP I_MIPX | 13 /* This is stargroup */
+#define MIPX_SWAPLENGTH I_MIPX | 14 /* Set flag for swapping 802.3 length */
+#define MIPX_SENDDEST I_MIPX | 15 /* (X) Send dest. address up */
+#define MIPX_NOSENDDEST I_MIPX | 16 /* (X) Don't send dest. address up */
+#define MIPX_SENDFDEST I_MIPX | 17 /* (X) Send final dest. address up */
+#define MIPX_NOSENDFDEST I_MIPX | 18 /* (X) Don't send final dest. up */
+
+/** Added for NT port **/
+
+#define MIPX_SETVERSION I_MIPX | 100 /* Set card version */
+#define MIPX_GETSTATUS I_MIPX | 101
+#define MIPX_SENDADDROPT I_MIPX | 102 /* (X) Send ptype w/addr on recv */
+#define MIPX_NOSENDADDROPT I_MIPX | 103 /* (X) Stop sending ptype on recv */
+#define MIPX_CHECKSUM I_MIPX | 104 /* Enable/Disable checksum */
+#define MIPX_GETPKTSIZE I_MIPX | 105 /* Get max packet size */
+#define MIPX_SENDHEADER I_MIPX | 106 /* Send header with data */
+#define MIPX_NOSENDHEADER I_MIPX | 107 /* Don't send header with data */
+#define MIPX_SETCURCARD I_MIPX | 108 /* Set current card for IOCTLs */
+#define MIPX_SETMACTYPE I_MIPX | 109 /* Set the Cards MAC type */
+#define MIPX_DOSROUTE I_MIPX | 110 /* Do source routing on this card*/
+#define MIPX_NOSROUTE I_MIPX | 111 /* Don't source routine the card*/
+#define MIPX_SETRIPRETRY I_MIPX | 112 /* Set RIP retry count */
+#define MIPX_SETRIPTO I_MIPX | 113 /* Set RIP timeout */
+#define MIPX_SETTKRSAP I_MIPX | 114 /* Set the token ring SAP */
+#define MIPX_SETUSELLC I_MIPX | 115 /* Put LLC hdr on packets */
+#define MIPX_SETUSESNAP I_MIPX | 116 /* Put SNAP hdr on packets */
+#define MIPX_8023LEN I_MIPX | 117 /* 1=make even, 0=dont make even*/
+#define MIPX_SENDPTYPE I_MIPX | 118 /* Send ptype in options on recv*/
+#define MIPX_NOSENDPTYPE I_MIPX | 119 /* Don't send ptype in options */
+#define MIPX_FILTERPTYPE I_MIPX | 120 /* Filter on recv ptype */
+#define MIPX_NOFILTERPTYPE I_MIPX | 121 /* Don't Filter on recv ptype */
+#define MIPX_SETSENDPTYPE I_MIPX | 122 /* Set pkt type to send with */
+#define MIPX_GETCARDINFO I_MIPX | 123 /* Get info on a card */
+#define MIPX_SENDCARDNUM I_MIPX | 124 /* Send card num up in options */
+#define MIPX_NOSENDCARDNUM I_MIPX | 125 /* Dont send card num in options*/
+#define MIPX_SETROUTER I_MIPX | 126 /* Set router enabled flag */
+#define MIPX_SETRIPAGE I_MIPX | 127 /* Set RIP age timeout */
+#define MIPX_SETRIPUSAGE I_MIPX | 128 /* Set RIP usage timeout */
+#define MIPX_SETSROUTEUSAGE I_MIPX| 129 /* Set the SROUTE usage timeout */
+#define MIPX_SETINTNET I_MIPX | 130 /* Set internal network number */
+#define MIPX_NOVIRTADDR I_MIPX | 131 /* Turn off virtual net num */
+#define MIPX_VIRTADDR I_MIPX | 132 /* Turn on virtual net num */
+#define MIPX_SETBCASTFLAG I_MIPX | 133 /* Turn on bcast flag in addr */
+#define MIPX_NOBCASTFLAG I_MIPX | 134 /* Turn off bcast flag in addr */
+#define MIPX_GETNETINFO I_MIPX | 135 /* Get info on a network num */
+#define MIPX_SETDELAYTIME I_MIPX | 136 /* Set cards delay time */
+#define MIPX_SETROUTEADV I_MIPX | 137 /* Route advertise timeout */
+#define MIPX_SETSOCKETS I_MIPX | 138 /* Set default sockets */
+#define MIPX_SETLINKSPEED I_MIPX | 139 /* Set the link speed for a card*/
+#define MIPX_SETWANFLAG I_MIPX | 140
+#define MIPX_GETCARDCHANGES I_MIPX | 141 /* Wait for card changes */
+#define MIPX_GETMAXADAPTERS I_MIPX | 142
+#define MIPX_REUSEADDRESS I_MIPX | 143
+#define MIPX_RERIPNETNUM I_MIPX | 144 /* ReRip a network */
+
+/** For Source Routing Support **/
+
+#define MIPX_SRCLEAR I_MIPX | 200 /* Clear the source routing table*/
+#define MIPX_SRDEF I_MIPX | 201 /* 0=Single Rte, 1=All Routes */
+#define MIPX_SRBCAST I_MIPX | 202 /* 0=Single Rte, 1=All Routes */
+#define MIPX_SRMULTI I_MIPX | 203 /* 0=Single Rte, 1=All Routes */
+#define MIPX_SRREMOVE I_MIPX | 204 /* Remove a node from the table */
+#define MIPX_SRLIST I_MIPX | 205 /* Get the source routing table */
+#define MIPX_SRGETPARMS I_MIPX | 206 /* Get source routing parms */
+
+#define MIPX_SETSHOULDPUT I_MIPX | 210 /* Turn on should put call */
+#define MIPX_DELSHOULDPUT I_MIPX | 211 /* Turn off should put call */
+#define MIPX_GETSHOULDPUT I_MIPX | 212 /* Get ptr to mipx_shouldput */
+
+/** Added for ISN **/
+
+#define MIPX_RCVBCAST I_MIPX | 300 /* (X) Enable broadcast reception */
+#define MIPX_NORCVBCAST I_MIPX | 301 /* (X) Disable broadcast reception */
+#define MIPX_ADAPTERNUM I_MIPX | 302 /* Get maximum adapter number */
+#define MIPX_NOTIFYCARDINFO I_MIPX | 303 /* Pend until card info changes */
+#define MIPX_LOCALTARGET I_MIPX | 304 /* Get local target for address */
+#define MIPX_NETWORKINFO I_MIPX | 305 /* Return info about remote net */
+#define MIPX_ZEROSOCKET I_MIPX | 306 /* Use 0 as source socket on sends */
+
+/** Ioctls for SPX **/
+
+#define I_MSPX (('S' << 24) | ('P' << 16) | ('P' << 8))
+#define MSPX_SETADDR I_MSPX | 0 /* Set the network address */
+#define MSPX_SETPKTSIZE I_MSPX | 1 /* Set the packet size per card */
+#define MSPX_SETDATASTREAM I_MSPX | 2 /* Set datastream type */
+
+/** Added for NT port **/
+
+#define MSPX_SETASLISTEN I_MSPX | 100 /* Set as a listen socket */
+#define MSPX_GETSTATUS I_MSPX | 101 /* Get running status */
+#define MSPX_GETQUEUEPTR I_MSPX | 102 /* Get ptr to the streams queue */
+#define MSPX_SETDATAACK I_MSPX | 103 /* Set DATA ACK option */
+#define MSPX_NODATAACK I_MSPX | 104 /* Turn off DATA ACK option */
+#define MSPX_SETMAXPKTSOCK I_MSPX | 105 /* Set the packet size per socket */
+#define MSPX_SETWINDOWCARD I_MSPX | 106 /* Set window size for card */
+#define MSPX_SETWINDOWSOCK I_MSPX | 107 /* Set window size for 1 socket */
+#define MSPX_SENDHEADER I_MSPX | 108 /* Send header with data */
+#define MSPX_NOSENDHEADER I_MSPX | 109 /* Don't send header with data */
+#define MSPX_GETPKTSIZE I_MSPX | 110 /* Get the packet size per card */
+#define MSPX_SETCONNCNT I_MSPX | 111 /* Set the conn req count */
+#define MSPX_SETCONNTO I_MSPX | 112 /* Set the conn req timeout */
+#define MSPX_SETALIVECNT I_MSPX | 113 /* Set the keepalive count */
+#define MSPX_SETALIVETO I_MSPX | 114 /* Set the keepalive timeout */
+#define MSPX_SETALWAYSEOM I_MSPX | 115 /* Turn on always EOM flag */
+#define MSPX_NOALWAYSEOM I_MSPX | 116 /* Turn off always EOM flag */
diff --git a/private/ntos/tdi/isn/inc/ipxfltif.h b/private/ntos/tdi/isn/inc/ipxfltif.h
new file mode 100644
index 000000000..e02591e61
--- /dev/null
+++ b/private/ntos/tdi/isn/inc/ipxfltif.h
@@ -0,0 +1,151 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ private\inc\ipxfltif.h
+
+Abstract:
+ IPX Filter driver interface with forwarder
+
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+#ifndef _IPXFLTIF_
+#define _IPXFLTIF_
+
+ // No filter context means that packets should not
+ // be passed for filtering
+#define NO_FILTER_CONTEXT ((PVOID)0)
+
+
+ // Forwarder Driver Entry Points:
+ // ==============================
+/*++
+ S E T _ I F _ I N _ C O N T E X T _ H A N D L E R
+
+Routine Description:
+ Associates filter driver context with
+ the packets received on the interface
+Arguments:
+ InterfaceIndex - index of the interface
+ ifInContext - filter driver context
+Return Value:
+ STATUS_SUCCESS - context associated ok
+ STATUS_UNSUCCESSFUL - interface does not exist
+--*/
+typedef
+NTSTATUS
+(*PSET_IF_IN_CONTEXT_HANDLER) (
+ IN ULONG InterfaceIndex,
+ IN PVOID ifInContext
+ );
+
+/*++
+ S E T _ I F _ O U T _ C O N T E X T _ H A N D L E R
+
+Routine Description:
+ Associates filter driver context with
+ the packets sent on the interface
+Arguments:
+ InterfaceIndex - index of the interface
+ ifOutContext - filter driver context
+Return Value:
+ STATUS_SUCCESS - context associated ok
+ STATUS_UNSUCCESSFUL - interface does not exist
+--*/
+typedef
+NTSTATUS
+(*PSET_IF_OUT_CONTEXT_HANDLER) (
+ IN ULONG InterfaceIndex,
+ IN PVOID ifOutContext
+ );
+
+typedef enum {
+ FILTER_DENY_IN = -2,
+ FILTER_DENY_OUT = -1,
+ FILTER_DENY = 1,
+ FILTER_PERMIT = 0
+} FILTER_ACTION;
+#define NOT_FILTER_ACTION(action) (!action)
+#define IS_FILTERED(action) (action!=FILTER_PERMIT)
+
+
+ // Forwarder Driver Entry Points:
+ // ==============================
+/*++
+ F i l t e r H a n d l e r
+
+Routine Description:
+
+ Filters the packet supplied by the forwarder
+
+Arguments:
+ ipxHdr - pointer to packet header
+ ipxHdrLength - size of the header buffer (must be at least 30)
+ ifInContext - context associated with interface on which packet
+ was received
+ ifOutContext - context associated with interface on which packet
+ will be sent
+Return Value:
+ FILTER_PERMIT - packet should be passed on by the forwarder
+ FILTER_DENY_IN - packet should be dropped because of input filter
+ FILTER_DENY_OUT - packet should be dropped because of output filter
+
+--*/
+typedef
+FILTER_ACTION
+(*PFILTER_HANDLER) (
+ IN PUCHAR ipxHdr,
+ IN ULONG ipxHdrLength,
+ IN PVOID ifInContext,
+ IN PVOID ifOutContex
+ );
+
+/*++
+ I n t e r f a c e D e l e t e d H a n d l e r
+
+Routine Description:
+
+ Frees interface filters blocks when forwarder indicates that
+ interface is deleted
+Arguments:
+ ifInContext - context associated with input filters block
+ ifOutContext - context associated with output filters block
+Return Value:
+ None
+
+--*/
+typedef
+VOID
+(*PINTERFACE_DELETED_HANDLER) (
+ IN PVOID ifInContext,
+ IN PVOID ifOutContext
+ );
+
+// Binds filter driver to forwarder
+// IPX_FLT_BIND_INPUT should be passed in the input buffer and
+// IPX_FLT_BINF_OUTPUT will be returned in the output buffer
+#define IOCTL_FWD_INTERNAL_BIND_FILTER \
+ CTL_CODE(FILE_DEVICE_IPXFWD,IPXFWD_IOCTL_INDEX+16,METHOD_BUFFERED,FILE_ANY_ACCESS)
+
+typedef struct _IPX_FLT_BIND_INPUT {
+ PFILTER_HANDLER FilterHandler;
+ PINTERFACE_DELETED_HANDLER InterfaceDeletedHandler;
+} IPX_FLT_BIND_INPUT, *PIPX_FLT_BIND_INPUT;
+
+typedef struct _IPX_FLT_BIND_OUTPUT {
+ ULONG Size;
+ PSET_IF_IN_CONTEXT_HANDLER SetIfInContextHandler;
+ PSET_IF_OUT_CONTEXT_HANDLER SetIfOutContextHandler;
+} IPX_FLT_BIND_OUTPUT, *PIPX_FLT_BIND_OUTPUT;
+
+#endif
+
diff --git a/private/ntos/tdi/isn/inc/isn.h b/private/ntos/tdi/isn/inc/isn.h
new file mode 100644
index 000000000..7b7e23601
--- /dev/null
+++ b/private/ntos/tdi/isn/inc/isn.h
@@ -0,0 +1,41 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ isn.h
+
+Abstract:
+
+ Private include file for the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 08-Sep-1993
+
+Revision History:
+
+--*/
+
+
+#define ISN_NT 1
+
+
+//
+// These are needed for CTE
+//
+
+#if DBG
+#define DEBUG 1
+#endif
+
+#define NT 1
+
+
+#include <ntddk.h>
+#include <tdikrnl.h>
+#include <ndis.h>
+#include <cxport.h>
+#include <bind.h>
+
diff --git a/private/ntos/tdi/isn/ipx/action.c b/private/ntos/tdi/isn/ipx/action.c
new file mode 100644
index 000000000..0a57bad98
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/action.c
@@ -0,0 +1,2921 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ action.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiAction
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#include <packon.h>
+
+//
+// Line ups when indicated up should have this length subtracted from the
+// max. send size that ndis indicated to us for the line
+//
+#define HDR_LEN_802_3 14
+#define ASYNC_MEDIUM_HDR_LEN HDR_LEN_802_3
+
+typedef struct _GET_PKT_SIZE {
+ ULONG Unknown;
+ ULONG MaxDatagramSize;
+} GET_PKT_SIZE, *PGET_PKT_SIZE;
+
+
+//
+// These structures are used to set and query information
+// about our source routing table.
+//
+
+typedef struct _SR_GET_PARAMETERS {
+ ULONG BoardNumber; // 0-based
+ ULONG SrDefault; // 0 = single route, 1 = all routes
+ ULONG SrBroadcast;
+ ULONG SrMulticast;
+} SR_GET_PARAMETERS, *PSR_GET_PARAMETERS;
+
+typedef struct _SR_SET_PARAMETER {
+ ULONG BoardNumber; // 0-based
+ ULONG Parameter; // 0 = single route, 1 = all routes
+} SR_SET_PARAMETER, *PSR_SET_PARAMETER;
+
+typedef struct _SR_SET_REMOVE {
+ ULONG BoardNumber; // 0-based
+ UCHAR MacAddress[6]; // remote to drop routing for
+} SR_SET_REMOVE, *PSR_SET_REMOVE;
+
+typedef struct _SR_SET_CLEAR {
+ ULONG BoardNumber; // 0-based
+} SR_SET_CLEAR, *PSR_SET_CLEAR;
+
+#include <packoff.h>
+
+typedef struct _ISN_ACTION_GET_DETAILS {
+ USHORT NicId; // passed by caller, returns count if it is 0
+ BOOLEAN BindingSet; // returns TRUE if in a set
+ UCHAR Type; // 1 = lan, 2 = up wan, 3 = down wan
+ ULONG FrameType; // returns 0 through 3
+ ULONG NetworkNumber; // returns virtual net if NicId is 0
+ UCHAR Node[6]; // adapter MAC address
+ WCHAR AdapterName[64]; // terminated with Unicode NULL
+} ISN_ACTION_GET_DETAILS, *PISN_ACTION_GET_DETAILS;
+
+
+
+NTSTATUS
+IpxTdiAction(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiAction request for the transport
+ provider.
+
+Arguments:
+
+ Device - The device for the operation.
+
+ Request - Describes the action request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PADDRESS_FILE AddressFile;
+ UINT BufferLength;
+ UINT DataLength;
+ PNDIS_BUFFER NdisBuffer;
+ CTELockHandle LockHandle;
+ PBINDING Binding, MasterBinding;
+ PADAPTER Adapter;
+ union {
+ PISN_ACTION_GET_LOCAL_TARGET GetLocalTarget;
+ PISN_ACTION_GET_NETWORK_INFO GetNetworkInfo;
+ PISN_ACTION_GET_DETAILS GetDetails;
+ PSR_GET_PARAMETERS GetSrParameters;
+ PSR_SET_PARAMETER SetSrParameter;
+ PSR_SET_REMOVE SetSrRemove;
+ PSR_SET_CLEAR SetSrClear;
+ PIPX_ADDRESS_DATA IpxAddressData;
+ PGET_PKT_SIZE GetPktSize;
+ PIPX_NETNUM_DATA IpxNetnumData;
+ PIPX_QUERY_WAN_INACTIVITY QueryWanInactivity;
+ PIPXWAN_CONFIG_DONE IpxwanConfigDone;
+ } u; // BUGBUG: Make these unaligned??
+ PIPX_ROUTE_ENTRY RouteEntry;
+ PNWLINK_ACTION NwlinkAction;
+ ULONG Segment;
+ ULONG AdapterNum;
+ static UCHAR BogusId[4] = { 0x01, 0x00, 0x00, 0x00 }; // old nwrdr uses this
+ IPX_FIND_ROUTE_REQUEST routeEntry;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ //
+ // To maintain some compatibility with the NWLINK streams-
+ // based transport, we use the streams header format for
+ // our actions. The old transport expected the action header
+ // to be in InputBuffer and the output to go in OutputBuffer.
+ // We follow the TDI spec, which states that OutputBuffer
+ // is used for both input and output. Since IOCTL_TDI_ACTION
+ // is method out direct, this means that the output buffer
+ // is mapped by the MDL chain; for action the chain will
+ // only have one piece so we use it for input and output.
+ //
+
+ NdisBuffer = REQUEST_NDIS_BUFFER(Request);
+ if (NdisBuffer == NULL) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ NdisQueryBuffer (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength);
+
+ if ((!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MISN", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MIPX", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "XPIM", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), BogusId, 4))) {
+
+ return STATUS_NOT_SUPPORTED;
+ }
+
+
+ //
+ // Make sure we have enough room for just the header not
+ // including the data.
+ //
+
+ if (BufferLength < (UINT)(FIELD_OFFSET(NWLINK_ACTION, Data[0]))) {
+ IPX_DEBUG (ACTION, ("Nwlink action failed, buffer too small\n"));
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ DataLength = BufferLength - FIELD_OFFSET(NWLINK_ACTION, Data[0]);
+
+
+ //
+ // Make sure that the correct file object is being used.
+ //
+
+ if (NwlinkAction->OptionType == NWLINK_OPTION_ADDRESS) {
+
+ if (REQUEST_OPEN_TYPE(Request) != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
+ IPX_DEBUG (ACTION, ("Nwlink action failed, not address file\n"));
+ return STATUS_INVALID_HANDLE;
+ }
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ if ((AddressFile->Size != sizeof (ADDRESS_FILE)) ||
+ (AddressFile->Type != IPX_ADDRESSFILE_SIGNATURE)) {
+
+ IPX_DEBUG (ACTION, ("Nwlink action failed, bad address file\n"));
+ return STATUS_INVALID_HANDLE;
+ }
+
+ } else if (NwlinkAction->OptionType != NWLINK_OPTION_CONTROL) {
+
+ IPX_DEBUG (ACTION, ("Nwlink action failed, option type %d\n", NwlinkAction->OptionType));
+ return STATUS_NOT_SUPPORTED;
+ }
+
+
+ //
+ // Handle the requests based on the action code. For these
+ // requests ActionHeader->ActionCode is 0, we use the
+ // Option field in the streams header instead.
+ //
+
+
+ Status = STATUS_SUCCESS;
+
+ switch (NwlinkAction->Option) {
+
+ //DbgPrint("NwlinkAction->Option is (%x)\n", NwlinkAction->Option);
+ //
+ // This first group support the winsock helper dll.
+ // In most cases the corresponding sockopt is shown in
+ // the comment, as well as the contents of the Data
+ // part of the action buffer.
+ //
+
+ case MIPX_SETSENDPTYPE:
+
+ //
+ // IPX_PTYPE: Data is a single byte packet type.
+ //
+
+ if (DataLength >= 1) {
+ IPX_DEBUG (ACTION, ("%lx: MIPX_SETSENDPTYPE %x\n", AddressFile, NwlinkAction->Data[0]));
+ AddressFile->DefaultPacketType = NwlinkAction->Data[0];
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case MIPX_FILTERPTYPE:
+
+ //
+ // IPX_FILTERPTYPE: Data is a single byte to filter on.
+ //
+
+ if (DataLength >= 1) {
+ IPX_DEBUG (ACTION, ("%lx: MIPX_FILTERPTYPE %x\n", AddressFile, NwlinkAction->Data[0]));
+ AddressFile->FilteredType = NwlinkAction->Data[0];
+ AddressFile->FilterOnPacketType = TRUE;
+ AddressFile->SpecialReceiveProcessing = TRUE;
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case MIPX_NOFILTERPTYPE:
+
+ //
+ // IPX_STOPFILTERPTYPE.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NOFILTERPTYPE\n", AddressFile));
+ AddressFile->FilterOnPacketType = FALSE;
+ AddressFile->SpecialReceiveProcessing = (BOOLEAN)
+ (AddressFile->ExtendedAddressing || AddressFile->ReceiveFlagsAddressing ||
+ AddressFile->ReceiveIpxHeader || AddressFile->IsSapSocket);
+ break;
+
+ case MIPX_SENDADDROPT:
+
+ //
+ // IPX_EXTENDED_ADDRESS (TRUE).
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_SENDADDROPT\n", AddressFile));
+ AddressFile->ExtendedAddressing = TRUE;
+ AddressFile->SpecialReceiveProcessing = TRUE;
+ break;
+
+ case MIPX_NOSENDADDROPT:
+
+ //
+ // IPX_EXTENDED_ADDRESS (FALSE).
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NOSENDADDROPT\n", AddressFile));
+ AddressFile->ExtendedAddressing = FALSE;
+ AddressFile->SpecialReceiveProcessing = (BOOLEAN)
+ (AddressFile->ReceiveFlagsAddressing || AddressFile->ReceiveIpxHeader ||
+ AddressFile->FilterOnPacketType || AddressFile->IsSapSocket);
+ break;
+
+#if 0
+ case MIPX_SETNIC:
+
+ //
+ // IPX_NIC_ADDRESS TRUE
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_SETNIC\n", AddressFile));
+ AddressFile->NicAddressing = TRUE;
+ AddressFile->SpecialReceiveProcessing = TRUE;
+ break;
+
+ case MIPX_NOSETNIC:
+
+ //
+ // IPX_NIC_ADDRESS (FALSE).
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NOSETNIC\n", AddressFile));
+ AddressFile->NicAddressing = FALSE;
+ AddressFile->SpecialReceiveProcessing = (BOOLEAN)
+ (AddressFile->ReceiveFlagsAddressing ||
+ AddressFile->ReceiveIpxHeader ||
+ AddressFile->FilterOnPacketType || AddressFile->IsSapSocket ||
+ AddressFile->NicAddressing);
+ break;
+#endif
+
+ case MIPX_SETRCVFLAGS:
+
+ //
+ // No sockopt yet.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_SETRCVFLAGS\n", AddressFile));
+ AddressFile->ReceiveFlagsAddressing = TRUE;
+ AddressFile->SpecialReceiveProcessing = TRUE;
+ break;
+
+ case MIPX_NORCVFLAGS:
+
+ //
+ // No sockopt yet.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NORCVFLAGS\n", AddressFile));
+ AddressFile->ReceiveFlagsAddressing = FALSE;
+ AddressFile->SpecialReceiveProcessing = (BOOLEAN)
+ (AddressFile->ExtendedAddressing || AddressFile->ReceiveIpxHeader ||
+ AddressFile->FilterOnPacketType || AddressFile->IsSapSocket);
+ break;
+
+ case MIPX_SENDHEADER:
+
+ //
+ // IPX_RECVHDR (TRUE);
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_SENDHEADER\n", AddressFile));
+ AddressFile->ReceiveIpxHeader = TRUE;
+ AddressFile->SpecialReceiveProcessing = TRUE;
+ break;
+
+ case MIPX_NOSENDHEADER:
+
+ //
+ // IPX_RECVHDR (FALSE);
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NOSENDHEADER\n", AddressFile));
+ AddressFile->ReceiveIpxHeader = FALSE;
+ AddressFile->SpecialReceiveProcessing = (BOOLEAN)
+ (AddressFile->ExtendedAddressing || AddressFile->ReceiveFlagsAddressing ||
+ AddressFile->FilterOnPacketType || AddressFile->IsSapSocket);
+ break;
+
+ case MIPX_RCVBCAST:
+
+ //
+ // Broadcast reception enabled.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_RCVBCAST\n", AddressFile));
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ if (!AddressFile->EnableBroadcast) {
+
+ AddressFile->EnableBroadcast = TRUE;
+ IpxAddBroadcast (Device);
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ break;
+
+ case MIPX_NORCVBCAST:
+
+ //
+ // Broadcast reception disabled.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NORCVBCAST\n", AddressFile));
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ if (AddressFile->EnableBroadcast) {
+
+ AddressFile->EnableBroadcast = FALSE;
+ IpxRemoveBroadcast (Device);
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ break;
+
+ case MIPX_GETPKTSIZE:
+
+ //
+ // IPX_MAXSIZE.
+ //
+ // BUGBUG: Figure out what the first length is for.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_GETPKTSIZE\n", AddressFile));
+ if (DataLength >= sizeof(GET_PKT_SIZE)) {
+ u.GetPktSize = (PGET_PKT_SIZE)(NwlinkAction->Data);
+ u.GetPktSize->Unknown = 0;
+ u.GetPktSize->MaxDatagramSize = Device->Information.MaxDatagramSize;
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case MIPX_ADAPTERNUM:
+
+ //
+ // IPX_MAX_ADAPTER_NUM.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_ADAPTERNUM\n", AddressFile));
+ if (DataLength >= sizeof(ULONG)) {
+ *(UNALIGNED ULONG *)(NwlinkAction->Data) = Device->SapNicCount;
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case MIPX_ADAPTERNUM2:
+
+ //
+ // IPX_MAX_ADAPTER_NUM.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_ADAPTERNUM2\n", AddressFile));
+ if (DataLength >= sizeof(ULONG)) {
+ *(UNALIGNED ULONG *)(NwlinkAction->Data) = MIN (Device->MaxBindings, Device->ValidBindings);
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case MIPX_GETCARDINFO:
+ case MIPX_GETCARDINFO2:
+
+ //
+ // GETCARDINFO is IPX_ADDRESS.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_GETCARDINFO (%d)\n",
+ AddressFile, *(UNALIGNED UINT *)NwlinkAction->Data));
+ if (DataLength >= sizeof(IPX_ADDRESS_DATA)) {
+ u.IpxAddressData = (PIPX_ADDRESS_DATA)(NwlinkAction->Data);
+ AdapterNum = u.IpxAddressData->adapternum+1;
+
+ if (((AdapterNum >= 1) && (AdapterNum <= Device->SapNicCount)) ||
+ ((NwlinkAction->Option == MIPX_GETCARDINFO2) && (AdapterNum <= (ULONG) MIN (Device->MaxBindings, Device->ValidBindings)))) {
+
+#ifdef _PNP_POWER
+// Get lock
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_ID_TO_BINDING(Device, AdapterNum);
+#else
+ Binding = Device->Bindings[AdapterNum];
+#endif
+ if (Binding == NULL) {
+
+ //
+ // This should be a binding in the WAN range
+ // of an adapter which is currently not
+ // allocated. We scan back to the previous
+ // non-NULL binding, which should be on the
+ // same adapter, and return a down line with
+ // the same characteristics as that binding.
+ //
+
+ UINT i = AdapterNum;
+
+ do {
+ --i;
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ } while (Binding == NULL);
+
+ CTEAssert (Binding->Adapter->MacInfo.MediumAsync);
+ CTEAssert (i >= Binding->Adapter->FirstWanNicId);
+ CTEAssert (AdapterNum <= Binding->Adapter->LastWanNicId);
+
+ u.IpxAddressData->status = FALSE;
+ *(UNALIGNED ULONG *)u.IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+
+ } else {
+
+ if ((Binding->Adapter->MacInfo.MediumAsync) &&
+ (Device->WanGlobalNetworkNumber)) {
+
+ //
+ // In this case we make it look like one big wan
+ // net, so the line is "up" or "down" depending
+ // on whether we have given him the first indication
+ // or not.
+ //
+
+ u.IpxAddressData->status = Device->GlobalNetworkIndicated;
+ *(UNALIGNED ULONG *)u.IpxAddressData->netnum = Device->GlobalWanNetwork;
+
+ } else {
+
+ u.IpxAddressData->status = Binding->LineUp;
+ *(UNALIGNED ULONG *)u.IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+ }
+
+ }
+
+ RtlCopyMemory(u.IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
+
+ Adapter = Binding->Adapter;
+ u.IpxAddressData->wan = Adapter->MacInfo.MediumAsync;
+ u.IpxAddressData->maxpkt =
+ (NwlinkAction->Option == MIPX_GETCARDINFO) ?
+ Binding->AnnouncedMaxDatagramSize :
+ Binding->RealMaxDatagramSize;
+ u.IpxAddressData->linkspeed = Binding->MediumSpeed;
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ } else {
+
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ } else {
+#if 1
+ //
+ // Support the old format query for now.
+ //
+
+ typedef struct _IPX_OLD_ADDRESS_DATA {
+ UINT adapternum;
+ UCHAR netnum[4];
+ UCHAR nodenum[6];
+ } IPX_OLD_ADDRESS_DATA, *PIPX_OLD_ADDRESS_DATA;
+
+ if (DataLength >= sizeof(IPX_OLD_ADDRESS_DATA)) {
+ u.IpxAddressData = (PIPX_ADDRESS_DATA)(NwlinkAction->Data);
+ AdapterNum = u.IpxAddressData->adapternum+1;
+
+ if ((AdapterNum >= 1) && (AdapterNum <= Device->SapNicCount)) {
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ if (Binding = NIC_ID_TO_BINDING(Device, AdapterNum)) {
+ *(UNALIGNED ULONG *)u.IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(u.IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (Binding = Device->Bindings[AdapterNum]) {
+ *(UNALIGNED ULONG *)u.IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(u.IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+#endif
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+#else
+ Status = STATUS_BUFFER_TOO_SMALL;
+#endif
+ }
+ break;
+
+ case MIPX_NOTIFYCARDINFO:
+
+ //
+ // IPX_ADDRESS_NOTIFY.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NOTIFYCARDINFO (%lx)\n", AddressFile, Request));
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ //
+ // If the device is open and there is room in the
+ // buffer for the data, insert it in our queue.
+ // It will be completed when a change happens or
+ // the driver is unloaded.
+ //
+
+ if (Device->State == DEVICE_STATE_OPEN) {
+ if (DataLength >= sizeof(IPX_ADDRESS_DATA)) {
+ InsertTailList(
+ &Device->AddressNotifyQueue,
+ REQUEST_LINKAGE(Request)
+ );
+ IoSetCancelRoutine (Request, IpxCancelAction);
+ if (Request->Cancel) {
+ (VOID)RemoveTailList (&Device->AddressNotifyQueue);
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ Status = STATUS_CANCELLED;
+ } else {
+ IpxReferenceDevice (Device, DREF_ADDRESS_NOTIFY);
+ Status = STATUS_PENDING;
+ }
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ } else {
+ Status = STATUS_DEVICE_NOT_READY;
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ break;
+
+ case MIPX_LINECHANGE:
+
+ //
+ // IPX_ADDRESS_NOTIFY.
+ //
+
+ IPX_DEBUG (ACTION, ("MIPX_LINECHANGE (%lx)\n", Request));
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ //
+ // If the device is open and there is room in the
+ // buffer for the data, insert it in our queue.
+ // It will be completed when a change happens or
+ // the driver is unloaded.
+ //
+
+ if (Device->State == DEVICE_STATE_OPEN) {
+
+ InsertTailList(
+ &Device->LineChangeQueue,
+ REQUEST_LINKAGE(Request)
+ );
+
+ IoSetCancelRoutine (Request, IpxCancelAction);
+ if (Request->Cancel) {
+ (VOID)RemoveTailList (&Device->LineChangeQueue);
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ Status = STATUS_CANCELLED;
+ } else {
+ IpxReferenceDevice (Device, DREF_LINE_CHANGE);
+ Status = STATUS_PENDING;
+ }
+ } else {
+ Status = STATUS_DEVICE_NOT_READY;
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ break;
+
+ case MIPX_GETNETINFO_NR:
+
+ //
+ // A request for network information about the immediate
+ // route to a network (this is called by sockets apps).
+ //
+
+ if (DataLength < sizeof(IPX_NETNUM_DATA)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.IpxNetnumData = (PIPX_NETNUM_DATA)(NwlinkAction->Data);
+
+ //
+ // A query on network 0 means that the caller wants
+ // information about our directly attached net.
+ //
+
+ if (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum == 0) {
+
+ //
+ // The tick count is the number of 1/18.21 second ticks
+ // it takes to deliver a 576-byte packet. Our link speed
+ // is in 100 bit-per-second units. We calculate it as
+ // follows (LS is the LinkSpeed):
+ //
+ // 576 bytes 8 bits 1 second 1821 ticks
+ // * ------ * ------------- * ----------
+ // 1 byte LS * 100 bits 100 seconds
+ //
+ // which becomes 839 / LinkSpeed -- we add LinkSpeed
+ // to the top to round up.
+ //
+
+ if (Device->LinkSpeed == 0) {
+ u.IpxNetnumData->netdelay = 16;
+ } else {
+ u.IpxNetnumData->netdelay = (USHORT)((839 + Device->LinkSpeed) /
+ (Device->LinkSpeed));
+ }
+ u.IpxNetnumData->hopcount = 0;
+ u.IpxNetnumData->cardnum = 0;
+ RtlMoveMemory (u.IpxNetnumData->router, Device->SourceAddress.NodeAddress, 6);
+
+ } else {
+
+
+#ifdef _PNP_POWER
+ if (Device->ForwarderBound) {
+ //
+ // [FW] Call the Forwarder's FindRoute if installed
+ //
+
+ //
+ // BUGBUG: What about the node number here?
+ //
+ Status = (*Device->UpperDrivers[IDENTIFIER_RIP].FindRouteHandler) (
+ u.IpxNetnumData->netnum,
+ NULL, // FindRouteRequest->Node,
+ &routeEntry);
+
+ if (Status != STATUS_SUCCESS) {
+ IPX_DEBUG (ACTION, (" MIPX_GETNETINFO_NR failed net %lx",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+ Status = STATUS_BAD_NETWORK_PATH;
+ } else {
+ //
+ // Fill in the information
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ if (Binding = NIC_ID_TO_BINDING(Device, routeEntry.LocalTarget.NicId)) {
+ u.IpxNetnumData->hopcount = routeEntry.HopCount;
+ u.IpxNetnumData->netdelay = routeEntry.TickCount;
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(Binding->MasterBinding->NicId - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(routeEntry.LocalTarget.NicId - 1);
+ }
+
+ // RtlMoveMemory (u.IpxNetnumData->router, routeEntry.LocalTarget.MacAddress, 6);
+
+ *((UNALIGNED ULONG *)u.IpxNetnumData->router) =
+ *((UNALIGNED ULONG *)routeEntry.LocalTarget.MacAddress);
+ *((UNALIGNED ULONG *)(u.IpxNetnumData->router+4)) =
+ *((UNALIGNED ULONG *)(routeEntry.LocalTarget.MacAddress+4));
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+
+
+ } else {
+ Segment = RipGetSegment(u.IpxNetnumData->netnum);
+
+ //
+ // To maintain the lock order: BindAccessLock > RIP table
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+ if ((RouteEntry != NULL) &&
+ (Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId))) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(MIN (Device->MaxBindings, Binding->MasterBinding->NicId) - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // Fail the call, we don't have a route yet.
+ //
+
+ IPX_DEBUG (ACTION, ("MIPX_GETNETINFO_NR failed net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+ Status = STATUS_BAD_NETWORK_PATH;
+
+ }
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+#else
+ Segment = RipGetSegment(u.IpxNetnumData->netnum);
+
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+ if ((RouteEntry != NULL) &&
+ (Binding = Device->Bindings[RouteEntry->NicId])) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(Binding->MasterBinding->NicId - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // Fail the call, we don't have a route yet.
+ //
+
+ IPX_DEBUG (ACTION, ("MIPX_GETNETINFO_NR failed net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+ Status = STATUS_BAD_NETWORK_PATH;
+
+ }
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+#endif
+
+ }
+
+ break;
+
+ case MIPX_RERIPNETNUM:
+
+ //
+ // BUGBUG We dont really support Re-RIP in the case of Forwarder above us
+ //
+
+ //
+ // A request for network information about the immediate
+ // route to a network (this is called by sockets apps).
+ //
+
+ if (DataLength < sizeof(IPX_NETNUM_DATA)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.IpxNetnumData = (PIPX_NETNUM_DATA)(NwlinkAction->Data);
+
+ //
+ // BUGBUG: Allow net 0 queries??
+ //
+
+ if (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum == 0) {
+
+ if (Device->LinkSpeed == 0) {
+ u.IpxNetnumData->netdelay = 16;
+ } else {
+ u.IpxNetnumData->netdelay = (USHORT)((839 + Device->LinkSpeed) /
+ (Device->LinkSpeed));
+ }
+ u.IpxNetnumData->hopcount = 0;
+ u.IpxNetnumData->cardnum = 0;
+ RtlMoveMemory (u.IpxNetnumData->router, Device->SourceAddress.NodeAddress, 6);
+
+ } else {
+
+#ifdef _PNP_POWER
+
+ if (Device->ForwarderBound) {
+
+ //
+ // [FW] Call the Forwarder's FindRoute if installed
+ //
+
+ //
+ // BUGBUG: What about the node number here?
+ //
+ Status = (*Device->UpperDrivers[IDENTIFIER_RIP].FindRouteHandler) (
+ u.IpxNetnumData->netnum,
+ NULL, // FindRouteRequest->Node,
+ &routeEntry);
+
+ if (Status != STATUS_SUCCESS) {
+ IPX_DEBUG (ACTION, (" MIPX_RERIPNETNUM failed net %lx",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+ Status = STATUS_BAD_NETWORK_PATH;
+ } else {
+ //
+ // Fill in the information
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ if (Binding = NIC_ID_TO_BINDING(Device, routeEntry.LocalTarget.NicId)) {
+ u.IpxNetnumData->hopcount = routeEntry.HopCount;
+ u.IpxNetnumData->netdelay = routeEntry.TickCount;
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(Binding->MasterBinding->NicId - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(routeEntry.LocalTarget.NicId - 1);
+ }
+
+ // RtlMoveMemory (u.IpxNetnumData->router, routeEntry.LocalTarget.MacAddress, 6);
+
+ *((UNALIGNED ULONG *)u.IpxNetnumData->router) =
+ *((UNALIGNED ULONG *)routeEntry.LocalTarget.MacAddress);
+ *((UNALIGNED ULONG *)(u.IpxNetnumData->router+4)) =
+ *((UNALIGNED ULONG *)(routeEntry.LocalTarget.MacAddress+4));
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+
+ } else {
+ Segment = RipGetSegment(u.IpxNetnumData->netnum);
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+
+ if ((RouteEntry != NULL) &&
+ (Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId)) &&
+ (RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY)) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(MIN (Device->MaxBindings, Binding->MasterBinding->NicId) - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // This call will return STATUS_PENDING if we successfully
+ // queue a RIP request for the packet.
+ //
+
+ Status = RipQueueRequest (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum, RIP_REQUEST);
+ CTEAssert (Status != STATUS_SUCCESS);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this request for completion when the RIP response
+ // arrives. We save the network in the information
+ // field for easier retrieval later.
+ //
+
+ REQUEST_INFORMATION(Request) = (ULONG)u.IpxNetnumData;
+ InsertTailList(
+ &Device->Segments[Segment].WaitingReripNetnum,
+ REQUEST_LINKAGE(Request));
+
+ IPX_DEBUG (ACTION, ("MIPX_RERIPNETNUM queued net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+
+ }
+
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+#else
+ Segment = RipGetSegment(u.IpxNetnumData->netnum);
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+
+ if ((RouteEntry != NULL) &&
+ (Binding = Device->Bindings[RouteEntry->NicId]) &&
+ (RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY)) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(Binding->MasterBinding->NicId - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // This call will return STATUS_PENDING if we successfully
+ // queue a RIP request for the packet.
+ //
+
+ Status = RipQueueRequest (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum, RIP_REQUEST);
+ CTEAssert (Status != STATUS_SUCCESS);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this request for completion when the RIP response
+ // arrives. We save the network in the information
+ // field for easier retrieval later.
+ //
+
+ REQUEST_INFORMATION(Request) = (ULONG)u.IpxNetnumData;
+ InsertTailList(
+ &Device->Segments[Segment].WaitingReripNetnum,
+ REQUEST_LINKAGE(Request));
+
+ IPX_DEBUG (ACTION, ("MIPX_RERIPNETNUM queued net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+
+ }
+
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+#endif
+ }
+
+ break;
+
+ case MIPX_GETNETINFO:
+
+ //
+ // A request for network information about the immediate
+ // route to a network (this is called by sockets apps).
+ //
+
+ if (DataLength < sizeof(IPX_NETNUM_DATA)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.IpxNetnumData = (PIPX_NETNUM_DATA)(NwlinkAction->Data);
+
+ //
+ // BUGBUG: Allow net 0 queries??
+ //
+
+ if (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum == 0) {
+
+ if (Device->LinkSpeed == 0) {
+ u.IpxNetnumData->netdelay = 16;
+ } else {
+ u.IpxNetnumData->netdelay = (USHORT)((839 + Device->LinkSpeed) /
+ (Device->LinkSpeed));
+ }
+ u.IpxNetnumData->hopcount = 0;
+ u.IpxNetnumData->cardnum = 0;
+ RtlMoveMemory (u.IpxNetnumData->router, Device->SourceAddress.NodeAddress, 6);
+
+ } else {
+
+#ifdef _PNP_POWER
+
+ if (Device->ForwarderBound) {
+
+ //
+ // [FW] Call the Forwarder's FindRoute if installed
+ //
+
+ //
+ // BUGBUG: What about the node number here?
+ //
+ Status = (*Device->UpperDrivers[IDENTIFIER_RIP].FindRouteHandler) (
+ u.IpxNetnumData->netnum,
+ NULL, // FindRouteRequest->Node,
+ &routeEntry);
+
+ if (Status != STATUS_SUCCESS) {
+ IPX_DEBUG (ACTION, (" MIPX_GETNETINFO failed net %lx",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+ Status = STATUS_BAD_NETWORK_PATH;
+ } else {
+ //
+ // Fill in the information
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ if (Binding = NIC_ID_TO_BINDING(Device, routeEntry.LocalTarget.NicId)) {
+ u.IpxNetnumData->hopcount = routeEntry.HopCount;
+ u.IpxNetnumData->netdelay = routeEntry.TickCount;
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(Binding->MasterBinding->NicId - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(routeEntry.LocalTarget.NicId - 1);
+ }
+
+ // RtlMoveMemory (u.IpxNetnumData->router, routeEntry.LocalTarget.MacAddress, 6);
+
+ *((UNALIGNED ULONG *)u.IpxNetnumData->router) =
+ *((UNALIGNED ULONG *)routeEntry.LocalTarget.MacAddress);
+ *((UNALIGNED ULONG *)(u.IpxNetnumData->router+4)) =
+ *((UNALIGNED ULONG *)(routeEntry.LocalTarget.MacAddress+4));
+ }
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+ } else {
+ Segment = RipGetSegment(u.IpxNetnumData->netnum);
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+
+ if ((RouteEntry != NULL) &&
+ (Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId))) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(MIN (Device->MaxBindings, Binding->MasterBinding->NicId) - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // This call will return STATUS_PENDING if we successfully
+ // queue a RIP request for the packet.
+ //
+
+ Status = RipQueueRequest (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum, RIP_REQUEST);
+ CTEAssert (Status != STATUS_SUCCESS);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this request for completion when the RIP response
+ // arrives. We save the network in the information
+ // field for easier retrieval later.
+ //
+
+ REQUEST_INFORMATION(Request) = (ULONG)u.IpxNetnumData;
+ InsertTailList(
+ &Device->Segments[Segment].WaitingReripNetnum,
+ REQUEST_LINKAGE(Request));
+
+ IPX_DEBUG (ACTION, ("MIPX_GETNETINFO queued net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+
+ }
+
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+#else
+ Segment = RipGetSegment(u.IpxNetnumData->netnum);
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+
+ if ((RouteEntry != NULL) &&
+ (Binding = Device->Bindings[RouteEntry->NicId])) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(Binding->MasterBinding->NicId - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // This call will return STATUS_PENDING if we successfully
+ // queue a RIP request for the packet.
+ //
+
+ Status = RipQueueRequest (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum, RIP_REQUEST);
+ CTEAssert (Status != STATUS_SUCCESS);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this request for completion when the RIP response
+ // arrives. We save the network in the information
+ // field for easier retrieval later.
+ //
+
+ REQUEST_INFORMATION(Request) = (ULONG)u.IpxNetnumData;
+ InsertTailList(
+ &Device->Segments[Segment].WaitingReripNetnum,
+ REQUEST_LINKAGE(Request));
+
+ IPX_DEBUG (ACTION, ("MIPX_GETNETINFO queued net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+
+ }
+
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+#endif
+ }
+
+ break;
+
+ case MIPX_SENDPTYPE:
+ case MIPX_NOSENDPTYPE:
+
+ //
+ // For the moment just use OptionsLength >= 1 to indicate
+ // that the send options include the packet type.
+ //
+ // BUGBUG: Do we need to worry about card num being there?
+ //
+
+#if 0
+ IPX_DEBUG (ACTION, ("%lx: MIPS_%sSENDPTYPE\n", AddressFile,
+ NwlinkAction->Option == MIPX_SENDPTYPE ? "" : "NO"));
+#endif
+ break;
+
+ case MIPX_ZEROSOCKET:
+
+ //
+ // Sends from this address should be from socket 0;
+ // This is done the simple way by just putting the
+ // information in the address itself, instead of
+ // making it per address file (this is OK since
+ // this call is not exposed through winsock).
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_ZEROSOCKET\n", AddressFile));
+ AddressFile->Address->SendSourceSocket = 0;
+ AddressFile->Address->LocalAddress.Socket = 0;
+ break;
+
+
+ //
+ // This next batch are the source routing options. They
+ // are submitted by the IPXROUTE program.
+ //
+ // BUGBUG: Do we expose all binding set members to this?
+
+ case MIPX_SRGETPARMS:
+
+ if (DataLength >= sizeof(SR_GET_PARAMETERS)) {
+ u.GetSrParameters = (PSR_GET_PARAMETERS)(NwlinkAction->Data);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ if (Binding = NIC_ID_TO_BINDING(Device, u.GetSrParameters->BoardNumber+1)) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRGETPARMS (%d)\n", u.GetSrParameters->BoardNumber+1));
+ u.GetSrParameters->SrDefault = (Binding->AllRouteDirected) ? 1 : 0;
+ u.GetSrParameters->SrBroadcast = (Binding->AllRouteBroadcast) ? 1 : 0;
+ u.GetSrParameters->SrMulticast = (Binding->AllRouteMulticast) ? 1 : 0;
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (Binding = Device->Bindings[u.GetSrParameters->BoardNumber+1]) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRGETPARMS (%d)\n", u.GetSrParameters->BoardNumber+1));
+ u.GetSrParameters->SrDefault = (Binding->AllRouteDirected) ? 1 : 0;
+ u.GetSrParameters->SrBroadcast = (Binding->AllRouteBroadcast) ? 1 : 0;
+ u.GetSrParameters->SrMulticast = (Binding->AllRouteMulticast) ? 1 : 0;
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+#endif
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+
+ case MIPX_SRDEF:
+ case MIPX_SRBCAST:
+ case MIPX_SRMULTI:
+
+ if (DataLength >= sizeof(SR_SET_PARAMETER)) {
+ u.SetSrParameter = (PSR_SET_PARAMETER)(NwlinkAction->Data);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ if (Binding = NIC_ID_TO_BINDING(Device, u.SetSrParameter->BoardNumber+1)) {
+ if (NwlinkAction->Option == MIPX_SRDEF) {
+
+ //
+ // BUGBUG: The compiler generates strange
+ // code which always makes this path be
+ // taken????
+ //
+
+ IPX_DEBUG (ACTION, ("MIPX_SRDEF %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteDirected = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ } else if (NwlinkAction->Option == MIPX_SRBCAST) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRBCAST %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteBroadcast = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ } else {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRMCAST %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteMulticast = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ }
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (Binding = Device->Bindings[u.SetSrParameter->BoardNumber+1]) {
+ if (NwlinkAction->Option == MIPX_SRDEF) {
+
+ //
+ // BUGBUG: The compiler generates strange
+ // code which always makes this path be
+ // taken????
+ //
+
+ IPX_DEBUG (ACTION, ("MIPX_SRDEF %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteDirected = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ } else if (NwlinkAction->Option == MIPX_SRBCAST) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRBCAST %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteBroadcast = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ } else {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRMCAST %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteMulticast = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ }
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+#endif
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+
+ case MIPX_SRREMOVE:
+
+ if (DataLength >= sizeof(SR_SET_REMOVE)) {
+ u.SetSrRemove = (PSR_SET_REMOVE)(NwlinkAction->Data);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ if (Binding = NIC_ID_TO_BINDING(Device, u.SetSrRemove->BoardNumber+1)) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRREMOVE %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x (%d)\n",
+ u.SetSrRemove->MacAddress[0],
+ u.SetSrRemove->MacAddress[1],
+ u.SetSrRemove->MacAddress[2],
+ u.SetSrRemove->MacAddress[3],
+ u.SetSrRemove->MacAddress[4],
+ u.SetSrRemove->MacAddress[5],
+ u.SetSrRemove->BoardNumber+1));
+ MacSourceRoutingRemove (Binding, u.SetSrRemove->MacAddress);
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (Binding = Device->Bindings[u.SetSrRemove->BoardNumber+1]) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRREMOVE %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x (%d)\n",
+ u.SetSrRemove->MacAddress[0],
+ u.SetSrRemove->MacAddress[1],
+ u.SetSrRemove->MacAddress[2],
+ u.SetSrRemove->MacAddress[3],
+ u.SetSrRemove->MacAddress[4],
+ u.SetSrRemove->MacAddress[5],
+ u.SetSrRemove->BoardNumber+1));
+ MacSourceRoutingRemove (Binding, u.SetSrRemove->MacAddress);
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+#endif
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+
+ case MIPX_SRCLEAR:
+
+ if (DataLength >= sizeof(SR_SET_CLEAR)) {
+ u.SetSrClear = (PSR_SET_CLEAR)(NwlinkAction->Data);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ if (Binding = NIC_ID_TO_BINDING(Device, u.SetSrClear->BoardNumber+1)) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRCLEAR (%d)\n", u.SetSrClear->BoardNumber+1));
+ MacSourceRoutingClear (Binding);
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (Binding = Device->Bindings[u.SetSrClear->BoardNumber+1]) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRCLEAR (%d)\n", u.SetSrClear->BoardNumber+1));
+ MacSourceRoutingClear (Binding);
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+#endif
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+
+
+ //
+ // These are new for ISN (not supported in NWLINK).
+ //
+
+ case MIPX_LOCALTARGET:
+
+ //
+ // A request for the local target for an IPX address.
+ //
+
+ if (DataLength < sizeof(ISN_ACTION_GET_LOCAL_TARGET)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.GetLocalTarget = (PISN_ACTION_GET_LOCAL_TARGET)(NwlinkAction->Data);
+
+ if (Device->ForwarderBound) {
+
+ //
+ // [FW] Call the Forwarder's FindRoute if installed
+ //
+
+ //
+ // BUGBUG: What about the node number here?
+ //
+ Status = (*Device->UpperDrivers[IDENTIFIER_RIP].FindRouteHandler) (
+ (PUCHAR)&u.GetLocalTarget->IpxAddress.NetworkAddress,
+ NULL, // FindRouteRequest->Node,
+ &routeEntry);
+
+ if (Status != STATUS_SUCCESS) {
+ IPX_DEBUG (ACTION, (" MIPX_LOCALTARGET failed net %lx",
+ REORDER_ULONG(u.GetLocalTarget->IpxAddress.NetworkAddress)));
+ Status = STATUS_BAD_NETWORK_PATH;
+ } else {
+ //
+ // Fill in the information
+ //
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ //
+ // BUGBUG What about check for IPX_ROUTER_LOCAL_NET
+ //
+ if (Binding = NIC_ID_TO_BINDING(Device, routeEntry.LocalTarget.NicId)) {
+ if (Binding->BindingSetMember) {
+
+ //
+ // It's a binding set member, we round-robin the
+ // responses across all the cards to distribute
+ // the traffic.
+ //
+
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+
+ u.GetLocalTarget->LocalTarget.NicId = Binding->NicId;
+
+ } else {
+
+ u.GetLocalTarget->LocalTarget.NicId = routeEntry.LocalTarget.NicId;
+ }
+
+ *((UNALIGNED ULONG *)u.GetLocalTarget->LocalTarget.MacAddress) =
+ *((UNALIGNED ULONG *)routeEntry.LocalTarget.MacAddress);
+ *((UNALIGNED ULONG *)(u.GetLocalTarget->LocalTarget.MacAddress+4)) =
+ *((UNALIGNED ULONG *)(routeEntry.LocalTarget.MacAddress+4));
+ }
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+ } else {
+ Segment = RipGetSegment((PUCHAR)&u.GetLocalTarget->IpxAddress.NetworkAddress);
+
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See if this route is local.
+ //
+
+ RouteEntry = RipGetRoute (Segment, (PUCHAR)&u.GetLocalTarget->IpxAddress.NetworkAddress);
+
+ if ((RouteEntry != NULL) &&
+ (RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY)) {
+
+ //
+ // This is a local net, to send to it you just use
+ // the appropriate NIC ID and the real MAC address.
+ //
+
+ if ((RouteEntry->Flags & IPX_ROUTER_LOCAL_NET) == 0) {
+
+ //
+ // It's the virtual net, send via the first card.
+ //
+ #ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&u.GetLocalTarget->LocalTarget, 1);
+ #else
+ u.GetLocalTarget->LocalTarget.NicId = 1;
+ #endif
+
+ } else {
+
+ #ifdef _PNP_POWER
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId);
+
+ if (Binding->BindingSetMember) {
+
+ //
+ // It's a binding set member, we round-robin the
+ // responses across all the cards to distribute
+ // the traffic.
+ //
+
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+
+ FILL_LOCAL_TARGET(&u.GetLocalTarget->LocalTarget, MIN( Device->MaxBindings, Binding->NicId));
+
+ } else {
+
+ FILL_LOCAL_TARGET(&u.GetLocalTarget->LocalTarget, RouteEntry->NicId);
+
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ #else
+ Binding = Device->Bindings[RouteEntry->NicId];
+ if (Binding->BindingSetMember) {
+
+ //
+ // It's a binding set member, we round-robin the
+ // responses across all the cards to distribute
+ // the traffic.
+ //
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+
+ u.GetLocalTarget->LocalTarget.NicId = Binding->NicId;
+ } else {
+
+ u.GetLocalTarget->LocalTarget.NicId = RouteEntry->NicId;
+
+ }
+ #endif
+
+ }
+
+ RtlCopyMemory(
+ u.GetLocalTarget->LocalTarget.MacAddress,
+ u.GetLocalTarget->IpxAddress.NodeAddress,
+ 6);
+
+ } else {
+
+ //
+ // This call will return STATUS_PENDING if we successfully
+ // queue a RIP request for the packet.
+ //
+
+ Status = RipQueueRequest (u.GetLocalTarget->IpxAddress.NetworkAddress, RIP_REQUEST);
+ CTEAssert (Status != STATUS_SUCCESS);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this request for completion when the RIP response
+ // arrives. We save the network in the information
+ // field for easier retrieval later.
+ //
+
+ REQUEST_INFORMATION(Request) = (ULONG)u.GetLocalTarget;
+ InsertTailList(
+ &Device->Segments[Segment].WaitingLocalTarget,
+ REQUEST_LINKAGE(Request));
+
+ }
+
+ #ifdef _PNP_POWER
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+ #endif
+ }
+ #ifndef _PNP_POWER
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+ #endif
+
+ }
+
+ break;
+
+ case MIPX_NETWORKINFO:
+
+ //
+ // A request for network information about the immediate
+ // route to a network.
+ //
+
+ if (DataLength < sizeof(ISN_ACTION_GET_NETWORK_INFO)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.GetNetworkInfo = (PISN_ACTION_GET_NETWORK_INFO)(NwlinkAction->Data);
+
+ if (u.GetNetworkInfo->Network == 0) {
+
+ //
+ // This is information about the local card.
+ //
+
+ u.GetNetworkInfo->LinkSpeed = Device->LinkSpeed * 12;
+ u.GetNetworkInfo->MaximumPacketSize = Device->Information.MaxDatagramSize;
+
+ } else {
+
+ if (Device->ForwarderBound) {
+
+ //
+ // [FW] Call the Forwarder's FindRoute if installed
+ //
+
+ //
+ // BUGBUG: What about the node number here?
+ //
+ Status = (*Device->UpperDrivers[IDENTIFIER_RIP].FindRouteHandler) (
+ (PUCHAR)&u.GetNetworkInfo->Network,
+ NULL, // FindRouteRequest->Node,
+ &routeEntry);
+
+ if (Status != STATUS_SUCCESS) {
+ IPX_DEBUG (ACTION, (" MIPX_GETNETINFO_NR failed net %lx",
+ REORDER_ULONG(u.GetNetworkInfo->Network)));
+ Status = STATUS_BAD_NETWORK_PATH;
+ } else {
+ //
+ // Fill in the information
+ //
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ if (Binding = NIC_ID_TO_BINDING(Device, routeEntry.LocalTarget.NicId)) {
+ //
+ // Our medium speed is stored in 100 bps, we
+ // convert to bytes/sec by multiplying by 12
+ // (should really be 100/8 = 12.5).
+ //
+
+ u.GetNetworkInfo->LinkSpeed = Binding->MediumSpeed * 12;
+ u.GetNetworkInfo->MaximumPacketSize = Binding->AnnouncedMaxDatagramSize;
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+ } else {
+ Segment = RipGetSegment((PUCHAR)&u.GetNetworkInfo->Network);
+
+ #ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ #endif
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, (PUCHAR)&u.GetNetworkInfo->Network);
+
+ if ((RouteEntry != NULL) &&
+ #ifdef _PNP_POWER
+ (Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId))) {
+ #else
+ (Binding = Device->Bindings[RouteEntry->NicId])) {
+ #endif
+
+ //
+ // Our medium speed is stored in 100 bps, we
+ // convert to bytes/sec by multiplying by 12
+ // (should really be 100/8 = 12.5).
+ //
+
+ u.GetNetworkInfo->LinkSpeed = Binding->MediumSpeed * 12;
+ u.GetNetworkInfo->MaximumPacketSize = Binding->AnnouncedMaxDatagramSize;
+
+ } else {
+
+ //
+ // Fail the call, we don't have a route yet.
+ // BUGBUG: This requires that a packet has been
+ // sent to this net already; nwrdr says this is
+ // OK, they will send their connect request
+ // before they query. On the server it should
+ // have RIP running so all nets should be in
+ // the database.
+ //
+
+ Status = STATUS_BAD_NETWORK_PATH;
+
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+ #ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ #endif
+ }
+ }
+
+ break;
+
+ case MIPX_CONFIG:
+
+ //
+ // A request for details on every binding.
+ //
+
+ if (DataLength < sizeof(ISN_ACTION_GET_DETAILS)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.GetDetails = (PISN_ACTION_GET_DETAILS)(NwlinkAction->Data);
+
+ if (u.GetDetails->NicId == 0) {
+
+ //
+ // This is information about the local card. We also
+ // tell him the total number of bindings in NicId.
+ //
+
+ u.GetDetails->NetworkNumber = Device->VirtualNetworkNumber;
+ u.GetDetails->NicId = (USHORT)MIN (Device->MaxBindings, Device->ValidBindings);
+
+ } else {
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ Binding = NIC_ID_TO_BINDING(Device, u.GetDetails->NicId);
+#else
+ Binding = Device->Bindings[u.GetDetails->NicId];
+#endif
+
+ if ((Binding != NULL) &&
+ (u.GetDetails->NicId <= MIN (Device->MaxBindings, Device->ValidBindings))) {
+
+ ULONG StringLoc;
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ u.GetDetails->NetworkNumber = Binding->LocalAddress.NetworkAddress;
+ if (Binding->Adapter->MacInfo.MediumType == NdisMediumArcnet878_2) {
+ u.GetDetails->FrameType = ISN_FRAME_TYPE_ARCNET;
+ } else {
+ u.GetDetails->FrameType = Binding->FrameType;
+ }
+ u.GetDetails->BindingSet = Binding->BindingSetMember;
+ if (Binding->Adapter->MacInfo.MediumAsync) {
+ if (Binding->LineUp) {
+ u.GetDetails->Type = 2;
+ } else {
+ u.GetDetails->Type = 3;
+ }
+ } else {
+ u.GetDetails->Type = 1;
+ }
+
+ RtlCopyMemory (u.GetDetails->Node, Binding->LocalMacAddress.Address, 6);
+
+ //
+ // Copy the adapter name, including the final NULL.
+ //
+
+ StringLoc = (Binding->Adapter->AdapterNameLength / sizeof(WCHAR)) - 2;
+ while (Binding->Adapter->AdapterName[StringLoc] != L'\\') {
+ --StringLoc;
+ }
+ RtlCopyMemory(
+ u.GetDetails->AdapterName,
+ &Binding->Adapter->AdapterName[StringLoc+1],
+ Binding->Adapter->AdapterNameLength - ((StringLoc+1) * sizeof(WCHAR)));
+
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ } else {
+
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ Status = STATUS_INVALID_PARAMETER;
+
+ }
+ }
+
+ break;
+
+
+ //
+ // Return new nic info to the requestor. Currently, no check for
+ // who retrieved the info earlier.
+ //
+ case MIPX_GETNEWNICINFO:
+
+ DbgPrint("GetNewNicInfo case entered\n");
+ IPX_DEBUG (ACTION, ("%lx: MIPX_GETNEWNICINFO (%lx)\n", AddressFile,
+ Request));
+ //
+ // a request for details on new bindings.
+ //
+ Status = GetNewNics(Device, Request, TRUE, NwlinkAction, BufferLength, FALSE);
+ break;
+
+ //
+ // In case a LineUp occurs with the IpxwanConfigRequired, this is used
+ // to indicate to IPX that the config is done and that the LineUp
+ // can be indicated to the other clients.
+ //
+ case MIPX_IPXWAN_CONFIG_DONE:
+
+ DbgPrint("IPXWAN_CONFIG_DONE case entered\n");
+ IPX_DEBUG (ACTION, ("MIPX_IPXWAN_CONFIG_DONE (%lx)\n", Request));
+
+ if (DataLength < sizeof(IPXWAN_CONFIG_DONE)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.IpxwanConfigDone = (PIPXWAN_CONFIG_DONE)(NwlinkAction->Data);
+ Status = IpxIndicateLineUp( IpxDevice,
+ u.IpxwanConfigDone->NicId,
+ u.IpxwanConfigDone->Network,
+ u.IpxwanConfigDone->LocalNode,
+ u.IpxwanConfigDone->RemoteNode);
+ break;
+
+ //
+ // Used to query the WAN inactivity counter for a given NicId
+ //
+ case MIPX_QUERY_WAN_INACTIVITY: {
+
+ USHORT NicId;
+
+ DbgPrint("QUERY_WAN_INACTIVITY case entered\n");
+ IPX_DEBUG (ACTION, ("MIPX_QUERY_WAN_INACTIVITY (%lx)\n", Request));
+
+ if (DataLength < sizeof(IPX_QUERY_WAN_INACTIVITY)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.QueryWanInactivity = (PIPX_QUERY_WAN_INACTIVITY)(NwlinkAction->Data);
+
+ //
+ // If this is an invalid Nic, then we need to associate a Nic with the ConnectionId that
+ // was passed in.
+ // This should happen only once per line up.
+ //
+ if (u.QueryWanInactivity->NicId == INVALID_NICID) {
+ PBINDING Binding;
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ for ( NicId = Device->HighestLanNicId+1;NicId < Index;NicId++ ) {
+ Binding = NIC_ID_TO_BINDING(Device, NicId);
+ if (Binding && (Binding->ConnectionId == u.QueryWanInactivity->ConnectionId)) {
+ CTEAssert(Binding->Adapter->MacInfo.MediumAsync);
+ if (Binding->LineUp != LINE_CONFIG) {
+ IPX_DEBUG (WAN, ("Binding is not in config state yet got QUERY_WAN_INACTIVITY %lx %lx", Binding, Request));
+ NicId = 0;
+ }
+ u.QueryWanInactivity->NicId = NicId;
+ break;
+ }
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+ }
+
+ if (NicId) {
+ u.QueryWanInactivity->WanInactivityCounter = IpxInternalQueryWanInactivity(NicId);
+ Status = STATUS_SUCCESS;
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ break;
+ }
+
+ //
+ // The Option was not supported, so fail.
+ //
+
+ default:
+
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+
+
+ } // end of the long switch on NwlinkAction->Option
+
+
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ IPX_DEBUG (ACTION, ("Nwlink action %lx failed, status %lx\n", NwlinkAction->Option, Status));
+ }
+#endif
+
+ return Status;
+
+} /* IpxTdiAction */
+
+
+VOID
+IpxCancelAction(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel an Action.
+ What is done to cancel it is specific to each action.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ PREQUEST Request = (PREQUEST)Irp;
+ CTELockHandle LockHandle;
+ PLIST_ENTRY p;
+ BOOLEAN Found;
+ UINT IOCTLType;
+
+ ASSERT( DeviceObject->DeviceExtension == IpxDevice );
+
+ //
+ // Find the request on the address notify queue.
+ //
+
+ Found = FALSE;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (p = Device->AddressNotifyQueue.Flink;
+ p != &Device->AddressNotifyQueue;
+ p = p->Flink) {
+
+ if (LIST_ENTRY_TO_REQUEST(p) == Request) {
+
+ RemoveEntryList (p);
+ Found = TRUE;
+ IOCTLType = MIPX_NOTIFYCARDINFO;
+ break;
+ }
+ }
+
+ if (!Found) {
+ for (p = Device->LineChangeQueue.Flink;
+ p != &Device->LineChangeQueue;
+ p = p->Flink) {
+
+ if (LIST_ENTRY_TO_REQUEST(p) == Request) {
+
+ RemoveEntryList (p);
+ Found = TRUE;
+ IOCTLType = MIPX_LINECHANGE;
+ break;
+ }
+ }
+ }
+
+ if (!Found) {
+ for (p = Device->NicNtfQueue.Flink;
+ p != &Device->NicNtfQueue;
+ p = p->Flink) {
+
+ if (LIST_ENTRY_TO_REQUEST(p) == Request) {
+
+ RemoveEntryList (p);
+ Found = TRUE;
+ IOCTLType = MIPX_GETNEWNICINFO;
+ break;
+ }
+ }
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ if (Found) {
+
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ IpxCompleteRequest (Request);
+ IpxFreeRequest(Device, Request);
+ if (IOCTLType == MIPX_NOTIFYCARDINFO) {
+ IPX_DEBUG(ACTION, ("Cancelled action NOTIFYCARDINFO %lx\n", Request));
+ IpxDereferenceDevice (Device, DREF_ADDRESS_NOTIFY);
+ } else {
+ if (IOCTLType == MIPX_LINECHANGE) {
+ IPX_DEBUG(ACTION, ("Cancelled action LINECHANGE %lx\n", Request));
+ IpxDereferenceDevice (Device, DREF_LINE_CHANGE);
+ } else {
+ IPX_DEBUG(ACTION, ("Cancelled action LINECHANGE %lx\n", Request));
+ IpxDereferenceDevice (Device, DREF_LINE_CHANGE);
+ }
+ }
+
+ }
+#if DBG
+ else {
+ IPX_DEBUG(ACTION, ("Cancelled action orphan %lx\n", Request));
+ }
+#endif
+
+} /* IpxCancelAction */
+
+
+VOID
+IpxAbortLineChanges(
+ IN PVOID ControlChannelContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine aborts any line change IRPs posted by the
+ control channel with the specified open context. It is
+ called when a control channel is being shut down.
+
+Arguments:
+
+ ControlChannelContext - The context assigned to the control
+ channel when it was opened.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ CTELockHandle LockHandle;
+ LIST_ENTRY AbortList;
+ PLIST_ENTRY p;
+ PREQUEST Request;
+ KIRQL irql;
+
+
+ InitializeListHead (&AbortList);
+
+ IoAcquireCancelSpinLock( &irql );
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ p = Device->LineChangeQueue.Flink;
+
+ while (p != &Device->LineChangeQueue) {
+ LARGE_INTEGER ControlChId;
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ CCID_FROM_REQUEST(ControlChId, Request);
+
+ p = p->Flink;
+
+ if (ControlChId.QuadPart == ((PLARGE_INTEGER)ControlChannelContext)->QuadPart) {
+ RemoveEntryList (REQUEST_LINKAGE(Request));
+ InsertTailList (&AbortList, REQUEST_LINKAGE(Request));
+ }
+ }
+
+ while (!IsListEmpty (&AbortList)) {
+
+ p = RemoveHeadList (&AbortList);
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ IPX_DEBUG(ACTION, ("Aborting line change %lx\n", Request));
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ CTEFreeLock(&Device->Lock, LockHandle);
+ IoReleaseCancelSpinLock( irql );
+
+ IpxCompleteRequest (Request);
+ IpxFreeRequest(Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_LINE_CHANGE);
+
+ IoAcquireCancelSpinLock( &irql );
+ CTEGetLock(&Device->Lock, &LockHandle);
+ }
+
+ CTEFreeLock(&Device->Lock, LockHandle);
+ IoReleaseCancelSpinLock( irql );
+} /* IpxAbortLineChanges */
+
+
+NTSTATUS
+GetNewNics(
+ PDEVICE Device,
+ IN PREQUEST Request,
+ BOOLEAN fCheck,
+ PNWLINK_ACTION NwlinkAction,
+ UINT BufferLength,
+ BOOLEAN OldIrp
+)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ UINT DataLength;
+ PNDIS_BUFFER NdisBuffer;
+ CTELockHandle LockHandle;
+ CTELockHandle LockHandle1;
+ PBINDING Binding;
+ ULONG NoOfNullNics = 0;
+ PIPX_NICS pNics;
+ PIPX_NIC_INFO pNicInfo;
+ PIPX_NIC_INFO pLastNicInfo;
+ UINT LengthOfHeader;
+ ULONG n, i;
+ KIRQL OldIrql;
+
+
+ LengthOfHeader = (UINT)(FIELD_OFFSET(NWLINK_ACTION, Data[0]));
+ if (fCheck)
+ {
+ if (BufferLength < (LengthOfHeader + FIELD_OFFSET(IPX_NICS, Data[0]) + sizeof(IPX_NIC_INFO)))
+ {
+ IPX_DEBUG (ACTION, ("Nwlink action failed, buffer too small for even one NICs info\n"));
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+ }
+ else
+ {
+ NdisQueryBuffer (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength);
+
+ }
+ pNics = (PIPX_NICS)(NwlinkAction->Data);
+ pNicInfo = (PIPX_NIC_INFO)(pNics->Data);
+ pLastNicInfo = pNicInfo + ((BufferLength - LengthOfHeader - FIELD_OFFSET(IPX_NICS, Data[0]))/sizeof(IPX_NIC_INFO)) - 1;
+
+ DbgPrint("GetNewNicInfo: pNicInfo=(%x), pLastNicInfo=(%x),LengthOfHeader=(%x), BindingCount=(%x)\n", pNicInfo, pLastNicInfo, LengthOfHeader, Device->ValidBindings);
+ DbgPrint("BufferLength is (%d). Length for storing NICS is (%d)\n", BufferLength, (BufferLength - LengthOfHeader - FIELD_OFFSET(IPX_NICS, Data[0])));
+ //
+ // Optimize since we don't want to go over the array all the time.
+ //
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->ValidBindings);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ for (n=0, i=1; i<=Index; i++)
+ {
+ Binding = NIC_ID_TO_BINDING(Device, i);
+
+ if (!Binding)
+ {
+ NoOfNullNics++;
+ continue;
+ }
+ //
+ // If we have already indicated info about this NIC, go on to the
+ // next nic.
+ //
+ if ((Binding->fInfoIndicated && !pNics->fAllNicsDesired)
+ || (pNicInfo > pLastNicInfo))
+ {
+ continue;
+ }
+
+ //
+ // If we have a WAN nic, indicate the line up/down status. Also,
+ // copy the remote address into the app. field
+ //
+ if (Binding->Adapter->MacInfo.MediumAsync)
+ {
+ RtlCopyMemory(pNicInfo->RemoteNodeAddress, Binding->WanRemoteNode, HARDWARE_ADDRESS_LENGTH);
+ if (Binding->LineUp)
+ {
+ // pNicInfo->Status = NIC_LINE_UP;
+
+ pNicInfo->Status = NIC_CREATED;
+ }
+ else
+ {
+ // pNicInfo->Status = NIC_LINE_DOWN;
+
+ pNicInfo->Status = NIC_DELETED;
+ }
+
+ pNicInfo->InterfaceIndex = Binding->InterfaceIndex;
+ pNicInfo->MaxPacketSize =
+ Binding->MaxSendPacketSize - ASYNC_MEDIUM_HDR_LEN;
+ }
+ else
+ {
+ if (Binding->LocalAddress.NetworkAddress == 0)
+ {
+ pNicInfo->Status = NIC_CREATED;
+ }
+ else
+ {
+ pNicInfo->Status = NIC_CONFIGURED;
+ }
+
+ //
+ // RealMaxDatagramSize does not include space for ipx
+ // header. The forwarder needs to have it included since
+ // we give the entire packet (mimus the mac header) to
+ // the forwarder
+ //
+ pNicInfo->MaxPacketSize =
+ Binding->RealMaxDatagramSize + sizeof(IPX_HEADER);
+ }
+ pNicInfo->NdisMediumType= Binding->Adapter->MacInfo.RealMediumType;
+ pNicInfo->LinkSpeed = Binding->MediumSpeed;
+ pNicInfo->PacketType = Binding->FrameType;
+ pNicInfo->NetworkAddress= Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(pNicInfo->LocalNodeAddress, Binding->LocalAddress.NodeAddress, HARDWARE_ADDRESS_LENGTH);
+ pNicInfo->NicId = Binding->NicId;
+ pNicInfo->ConnectionId = Binding->ConnectionId;
+ pNicInfo->IpxwanConfigRequired = Binding->IpxwanConfigRequired;
+
+ pNicInfo++; //increment to store next nic info
+ n++; //indicates the # of nics processed so far.
+ Binding->fInfoIndicated = TRUE;
+ DbgPrint("Iteration no = (%d) complete\n", n);
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ pNics->NoOfNics = n;
+ pNics->TotalNoOfNics = Device->ValidBindings - NoOfNullNics;
+
+ //
+ // If no nics. to report, queue the request
+ //
+ if (!n) {
+
+ DbgPrint("GetNewNicInfo: Inserting Irp\n");
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ InsertTailList( &Device->NicNtfQueue, REQUEST_LINKAGE(Request) );
+
+ if (!OldIrp)
+ {
+ CTEFreeLock (&Device->Lock, LockHandle);
+ IoAcquireCancelSpinLock(&OldIrql);
+ IoSetCancelRoutine (Request, IpxCancelAction);
+ IoReleaseCancelSpinLock(OldIrql);
+ CTEGetLock (&Device->Lock, &LockHandle);
+ }
+ if (Request->Cancel) {
+ DbgPrint("GetNewNicInfo:Cancelling Irp\n");
+
+ (VOID)RemoveTailList (&Device->NicNtfQueue);
+ CTEFreeLock (&Device->Lock, LockHandle);
+ IoAcquireCancelSpinLock(&OldIrql);
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ IoReleaseCancelSpinLock(OldIrql);
+ Status = STATUS_CANCELLED;
+ } else {
+ if (!OldIrp)
+ {
+ IpxReferenceDevice (Device, DREF_NIC_NOTIFY);
+ }
+ Status = STATUS_PENDING;
+ CTEFreeLock (&Device->Lock, LockHandle);
+ }
+ }
+ else
+ {
+ DbgPrint("Reporting (%d) nics\n", n);
+ }
+
+ return(Status);
+}
+
+
+VOID
+IpxAbortNtfChanges(
+ IN PVOID ControlChannelContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine aborts any line change IRPs posted by the
+ control channel with the specified open context. It is
+ called when a control channel is being shut down.
+
+Arguments:
+
+ ControlChannelContext - The context assigned to the control
+ channel when it was opened.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ CTELockHandle LockHandle;
+ LIST_ENTRY AbortList;
+ PLIST_ENTRY p;
+ PREQUEST Request;
+ KIRQL irql;
+
+
+ InitializeListHead (&AbortList);
+
+ IoAcquireCancelSpinLock( &irql );
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ p = Device->NicNtfQueue.Flink;
+
+ while (p != &Device->NicNtfQueue) {
+ LARGE_INTEGER ControlChId;
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ CCID_FROM_REQUEST(ControlChId, Request);
+
+ DbgPrint("IpxAbortNtfChange: There is at least one IRP in the queue\n");
+ p = p->Flink;
+
+ if (ControlChId.QuadPart == ((PLARGE_INTEGER)ControlChannelContext)->QuadPart) {
+ DbgPrint("IpxAbortNtfChanges: Dequeing an Irp\n");
+ RemoveEntryList (REQUEST_LINKAGE(Request));
+ InsertTailList (&AbortList, REQUEST_LINKAGE(Request));
+ }
+ }
+
+ while (!IsListEmpty (&AbortList)) {
+
+ p = RemoveHeadList (&AbortList);
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ IPX_DEBUG(ACTION, ("Aborting line change %lx\n", Request));
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ CTEFreeLock(&Device->Lock, LockHandle);
+ IoReleaseCancelSpinLock( irql );
+
+ DbgPrint("IpxAbortNtfChanges: Cancelling the dequeued Irp\n");
+ IpxCompleteRequest (Request);
+ IpxFreeRequest(Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_NIC_NOTIFY);
+
+ IoAcquireCancelSpinLock( &irql );
+ CTEGetLock(&Device->Lock, &LockHandle);
+ }
+
+ CTEFreeLock(&Device->Lock, LockHandle);
+ IoReleaseCancelSpinLock( irql );
+} /* IpxAbortNtfChanges */
+
+NTSTATUS
+IpxIndicateLineUp(
+ IN PDEVICE Device,
+ IN USHORT NicId,
+ IN ULONG Network,
+ IN UCHAR LocalNode[6],
+ IN UCHAR RemoteNode[6]
+ )
+/*++
+
+Routine Description:
+
+ This routine indicates a line-up to all the concerned clients once
+ the line is up.
+ For now, called only if the MIPX_IPXWAN_CONFIG_DONE IOCTL is received.
+
+
+Arguments:
+
+ Device - The device for the operation.
+
+ NicId - The NicId corresponding to the binding that is up.
+
+ Network, LocalNode, RemoteNode - addresses corresponding to this lineup.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+{
+ PBINDING Binding = NIC_ID_TO_BINDING(Device, NicId);
+ IPX_LINE_INFO LineInfo;
+ USHORT i;
+ PLIST_ENTRY p;
+ PREQUEST Request;
+ PNDIS_BUFFER NdisBuffer;
+ PNWLINK_ACTION NwlinkAction;
+ UINT BufferLength;
+ PIPX_ADDRESS_DATA IpxAddressData;
+ IPXCP_CONFIGURATION Configuration;
+ KIRQL irql, OldIrq;
+ NTSTATUS Status;
+ NTSTATUS ntStatus;
+ KIRQL OldIrql;
+
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ if (!(Binding &&
+ Binding->Adapter->MacInfo.MediumAsync &&
+ Binding->LineUp == LINE_CONFIG)) {
+ IPX_DEBUG(WAN, ("Indicate line up on invalid line: %lu\n", NicId));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // [BUGBUG] take bindaccesslock here...
+ //
+
+ //
+ // If we are here, then this flag was set on a line up.
+ // We turn it off now so that the adapter dll above us can decide
+ // to indicate this lineup to the router module instead of the IpxWan module
+ //
+
+ CTEAssert(Binding->IpxwanConfigRequired);
+
+ Binding->IpxwanConfigRequired = 0;
+
+ Binding->LineUp = LINE_UP;
+
+ //
+ // Indicate to the upper drivers.
+ //
+
+ LineInfo.LinkSpeed = Binding->MediumSpeed;
+ LineInfo.MaximumPacketSize = Binding->MaxSendPacketSize - 14;
+ LineInfo.MaximumSendSize = Binding->MaxSendPacketSize - 14;
+ LineInfo.MacOptions = Binding->Adapter->MacInfo.MacOptions;
+
+ //
+ // Fill-in the addresses into the bindings
+ //
+ Binding->LocalAddress.NetworkAddress = Network;
+
+ *(UNALIGNED ULONG *)Binding->LocalAddress.NodeAddress = *(UNALIGNED ULONG *)LocalNode;
+ *(UNALIGNED ULONG *)(Binding->LocalAddress.NodeAddress+4) = *(UNALIGNED ULONG *)(LocalNode+4);
+
+ *(UNALIGNED ULONG *)Binding->WanRemoteNode = *(UNALIGNED ULONG *)RemoteNode;
+ *(UNALIGNED ULONG *)(Binding->WanRemoteNode+4) = *(UNALIGNED ULONG *)(RemoteNode+4);
+
+ //
+ // Fill in the IPXCP_CONFIGURATION structure from the binding.
+ //
+ *(UNALIGNED ULONG *)Configuration.Network = Binding->LocalAddress.NetworkAddress;
+
+ *(UNALIGNED ULONG *)Configuration.LocalNode = *(UNALIGNED ULONG *)Binding->LocalAddress.NodeAddress;
+ *(UNALIGNED USHORT *)(Configuration.LocalNode+4) = *(UNALIGNED USHORT *)(Binding->LocalAddress.NodeAddress+4);
+
+ *(UNALIGNED ULONG *)Configuration.RemoteNode = *(UNALIGNED ULONG *)RemoteNode;
+ *(UNALIGNED USHORT *)(Configuration.RemoteNode+4) = *(UNALIGNED USHORT *)(RemoteNode+4);
+
+ Configuration.InterfaceIndex = Binding->InterfaceIndex;
+ Configuration.ConnectionClient = Binding->DialOutAsync;
+
+#ifdef _PNP_POWER
+
+ //
+ // We dont give lineups; instead indicate only if the PnP reserved address
+ // changed to SPX. NB gets all PnP indications with the reserved address case
+ // marked out.
+ //
+ {
+ IPX_PNP_INFO NBPnPInfo;
+
+ if ((!Device->MultiCardZeroVirtual) || (Binding->NicId == 1)) {
+
+ //
+ // NB's reserved address changed.
+ //
+ NBPnPInfo.NewReservedAddress = TRUE;
+
+ if (!Device->VirtualNetwork) {
+ //
+ // Let SPX know because it fills in its own headers.
+ //
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_PNP_INFO IpxPnPInfo;
+
+ IpxPnPInfo.NewReservedAddress = TRUE;
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_ADDRESS_CHANGE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_ADDRESS_CHANGED to SPX: net addr: %lx\n", Binding->LocalAddress.NetworkAddress));
+ }
+ }
+ } else {
+ NBPnPInfo.NewReservedAddress = FALSE;
+ }
+
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ Binding->IsnInformed[IDENTIFIER_NB] = TRUE;
+
+ NBPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ NBPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ NBPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ NBPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ NBPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ NBPnPInfo.FirstORLastDevice = FALSE;
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ RtlCopyMemory(NBPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(NBPnPInfo.NicHandle, Binding->NicId);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &NBPnPInfo);
+
+ IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_ADD_DEVICE (lineup) to NB: net addr: %lx\n", Binding->LocalAddress.NetworkAddress));
+ }
+
+ //
+ // Register this address with the TDI clients.
+ //
+ RtlCopyMemory (Device->TdiRegistrationAddress->Address, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
+
+ if ((ntStatus = TdiRegisterNetAddress(
+ Device->TdiRegistrationAddress,
+ &Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+
+ IPX_DEBUG(PNP, ("TdiRegisterNetAddress failed: %lx", ntStatus));
+ }
+ }
+
+ //
+ // Indicate to the upper drivers.
+ //
+ //
+ // Give line up to RIP as it is not PnP aware.
+ //
+ if (Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ Binding->IsnInformed[IDENTIFIER_RIP] = TRUE;
+ (*Device->UpperDrivers[IDENTIFIER_RIP].LineUpHandler)(
+ Binding->NicId,
+ &LineInfo,
+ NdisMediumWan,
+ &Configuration);
+ }
+#else
+ //
+ // Indicate to the upper drivers.
+ //
+ LineInfo.LinkSpeed = LineUp->LinkSpeed;
+ LineInfo.MaximumPacketSize = LineUp->MaximumTotalSize - 14;
+ LineInfo.MaximumSendSize = LineUp->MaximumTotalSize - 14;
+ LineInfo.MacOptions = Adapter->MacInfo.MacOptions;
+ for (i = 0; i < UPPER_DRIVER_COUNT; i++) {
+
+ if (Device->UpperDriverBound[i]) {
+ (*Device->UpperDrivers[i].LineUpHandler)(
+ Binding->NicId,
+ &LineInfo,
+ NdisMediumWan,
+ &Configuration);
+ }
+ }
+#endif
+
+ //
+ // Add router entry for this net since it was not done on LineUp.
+ // Also, update the addresses' pre-constructed local IPX address.
+ //
+ {
+ ULONG CurrentHash;
+ PADAPTER Adapter = Binding->Adapter;
+ PADDRESS Address;
+
+ //
+ // Add a router entry for this net if there is no router.
+ // We want the number of ticks for a 576-byte frame,
+ // given the link speed in 100 bps units, so we calculate
+ // as:
+ //
+ // seconds 18.21 ticks 4608 bits
+ // --------------------- * ----------- * ---------
+ // link_speed * 100 bits second frame
+ //
+ // to get the formula
+ //
+ // ticks/frame = 839 / link_speed.
+ //
+ // We add link_speed to the numerator also to ensure
+ // that the value is at least 1.
+ //
+
+ if ((!Device->UpperDriverBound[IDENTIFIER_RIP]) &&
+ (*(UNALIGNED ULONG *)Configuration.Network != 0)) {
+
+ if (RipInsertLocalNetwork(
+ *(UNALIGNED ULONG *)Configuration.Network,
+ Binding->NicId,
+ Adapter->NdisBindingHandle,
+ (USHORT)((839 + Binding->MediumSpeed) / Binding->MediumSpeed)) != STATUS_SUCCESS) {
+
+ //
+ // This means we couldn't allocate memory, or
+ // the entry already existed. If it already
+ // exists we can ignore it for the moment.
+ //
+ // BUGBUG: Now it will succeed if the network
+ // exists.
+ //
+
+ IPX_DEBUG (WAN, ("Line up, could not insert local network\n"));
+ // [FW] Binding->LineUp = FALSE;
+ Binding->LineUp = LINE_DOWN;
+ return STATUS_SUCCESS;
+ }
+ }
+
+ //
+ // Update the device node and all the address
+ // nodes if we have only one bound, or this is
+ // binding one.
+ //
+
+ if (!Device->VirtualNetwork) {
+
+ if ((!Device->MultiCardZeroVirtual) || (Binding->NicId == 1)) {
+ Device->SourceAddress.NetworkAddress = *(UNALIGNED ULONG *)(Configuration.Network);
+ RtlCopyMemory (Device->SourceAddress.NodeAddress, Configuration.LocalNode, 6);
+ }
+
+ //
+ // Scan through all the addresses that exist and modify
+ // their pre-constructed local IPX address to reflect
+ // the new local net and node.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (CurrentHash = 0; CurrentHash < IPX_ADDRESS_HASH_COUNT; CurrentHash++) {
+
+ for (p = Device->AddressDatabases[CurrentHash].Flink;
+ p != &Device->AddressDatabases[CurrentHash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ Address->LocalAddress.NetworkAddress = *(UNALIGNED ULONG *)Configuration.Network;
+ RtlCopyMemory (Address->LocalAddress.NodeAddress, Configuration.LocalNode, 6);
+ }
+ }
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+ }
+
+
+
+ //
+ // [FW] IpxWan config state will not be entered if only the line params are getting
+ // updated.
+ //
+ // if (!UpdateLineUp) {
+
+ //
+ // Instead of the check for ConnectionClient, use the DialOutAsync flag
+ //
+ if ((Device->SingleNetworkActive) &&
+ /*(LineUp->Configuration.ConnectionClient == 1)*/
+ Binding->DialOutAsync) {
+
+ //
+ // Drop all entries in the database if rip is not bound.
+ //
+
+ if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ RipDropRemoteEntries();
+ }
+
+ Device->ActiveNetworkWan = TRUE;
+
+ //
+ // Find a queued line change and complete it.
+ //
+
+ if ((p = ExInterlockedRemoveHeadList(
+ &Device->LineChangeQueue,
+ &Device->Lock)) != NULL) {
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ IoAcquireCancelSpinLock( &irql );
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ IoReleaseCancelSpinLock( irql );
+
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+
+ //
+ // BUGBUG:NwRdr assumes that Line-up completions are at DPC
+ //
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ IpxCompleteRequest (Request);
+ KeLowerIrql(OldIrql);
+
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_LINE_CHANGE);
+
+ }
+
+ //
+ // If we have a virtual net, do a broadcast now so
+ // the router on the other end will know about us.
+ //
+ // BUGBUG: Use RipSendResponse, and do it even
+ // if SingleNetworkActive is FALSE??
+ //
+
+ if (Device->RipResponder) {
+ (VOID)RipQueueRequest (Device->VirtualNetworkNumber, RIP_RESPONSE);
+ }
+
+ }
+
+ //
+ // Find a queued address notify and complete it.
+ // If WanGlobalNetworkNumber is TRUE, we only do
+ // this when the first dialin line comes up.
+ //
+
+ if ((!Device->WanGlobalNetworkNumber ||
+ (!Device->GlobalNetworkIndicated && !Binding->DialOutAsync))
+ &&
+ ((p = ExInterlockedRemoveHeadList(
+ &Device->AddressNotifyQueue,
+ &Device->Lock)) != NULL)) {
+
+ if (Device->WanGlobalNetworkNumber) {
+ Device->GlobalWanNetwork = Binding->LocalAddress.NetworkAddress;
+ Device->GlobalNetworkIndicated = TRUE;
+ }
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+ NdisBuffer = REQUEST_NDIS_BUFFER(Request);
+ NdisQueryBuffer (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength);
+
+ IpxAddressData = (PIPX_ADDRESS_DATA)(NwlinkAction->Data);
+
+ if (Device->WanGlobalNetworkNumber) {
+ IpxAddressData->adapternum = Device->SapNicCount - 1;
+ } else {
+ IpxAddressData->adapternum = Binding->NicId - 1;
+ }
+ *(UNALIGNED ULONG *)IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
+ IpxAddressData->wan = TRUE;
+ IpxAddressData->status = TRUE;
+ IpxAddressData->maxpkt = Binding->AnnouncedMaxDatagramSize; // BUGBUG: Use real?
+ IpxAddressData->linkspeed = Binding->MediumSpeed;
+
+ IoAcquireCancelSpinLock( &irql );
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ IoReleaseCancelSpinLock( irql );
+
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_ADDRESS_NOTIFY);
+ }
+
+ Binding->fInfoIndicated = FALSE;
+ if ((p = ExInterlockedRemoveHeadList(
+ &Device->NicNtfQueue,
+ &Device->Lock)) != NULL)
+ {
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ DbgPrint("IpxStatus: WAN LINE UP\n");
+ Status = GetNewNics(Device, Request, FALSE, NULL, 0, FALSE);
+ if (Status != STATUS_SUCCESS)
+ {
+ DbgPrint("WAN Line up screw up\n");
+ }
+ else
+ {
+ IoAcquireCancelSpinLock(&OldIrq);
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ IoReleaseCancelSpinLock(OldIrq);
+
+ REQUEST_STATUS(Request) = Status;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+ IpxDereferenceDevice (Device, DREF_NIC_NOTIFY);
+ }
+ }
+// }
+
+ return STATUS_SUCCESS;
+}
diff --git a/private/ntos/tdi/isn/ipx/adapter.c b/private/ntos/tdi/isn/ipx/adapter.c
new file mode 100644
index 000000000..4dc3799aa
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/adapter.c
@@ -0,0 +1,804 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ adapter.c
+
+Abstract:
+
+ This module contains code which implements the ADAPTER object.
+ Routines are provided to reference, and dereference transport
+ adapter objects.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// These are init only until binding is really dynamic.
+//
+#ifndef _PNP_POWER
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,IpxCreateAdapter)
+#endif
+#endif _PNP_POWER
+
+//
+// [FW] So, later we can change this to pnp-compatible value
+//
+
+//
+// ULONG
+// ADAPTER_INDEX_TO_FWCONTEXT(
+// IN ULONG _adapterindex;
+// );
+//
+
+#define ADAPTER_INDEX_TO_FWCONTEXT(_adapterindex) _adapterindex
+
+
+VOID
+IpxRefBinding(
+ IN PBINDING Binding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a device context.
+
+Arguments:
+
+ Binding - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ CTEAssert (Binding->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement (&Binding->ReferenceCount);
+
+} /* IpxRefBinding */
+
+
+VOID
+IpxDerefBinding(
+ IN PBINDING Binding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a device context by decrementing the
+ reference count contained in the structure. Currently, we don't
+ do anything special when the reference count drops to zero, but
+ we could dynamically unload stuff then.
+
+Arguments:
+
+ Binding - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&Binding->ReferenceCount);
+
+ CTEAssert (result >= 0);
+
+ if (result == 0) {
+ IpxDestroyBinding (Binding);
+ }
+
+} /* IpxDerefBinding */
+
+
+NTSTATUS
+IpxCreateAdapter(
+ IN PDEVICE Device,
+ IN PUNICODE_STRING AdapterName,
+ IN OUT PADAPTER *AdapterPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates and initializes a device context structure.
+
+Arguments:
+
+
+ DriverObject - pointer to the IO subsystem supplied driver object.
+
+ Adapter - Pointer to a pointer to a transport device context object.
+
+ AdapterName - pointer to the name of the device this device object points to.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
+
+--*/
+
+{
+ PADAPTER Adapter;
+#if 0
+ UINT i, j;
+#endif
+
+ Adapter = (PADAPTER)IpxAllocateMemory (sizeof(ADAPTER) + AdapterName->Length + sizeof(WCHAR), MEMORY_ADAPTER, "Adapter");
+
+#ifdef _PNP_POWER
+ if (Adapter == NULL) {
+ if (KeGetCurrentIrql() == 0) {
+ IPX_DEBUG (ADAPTER, ("Create adapter %ws failed\n", AdapterName));
+ } else {
+ IPX_DEBUG (ADAPTER, ("Create adapter %lx failed\n", AdapterName));
+ }
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ IPX_DEBUG (ADAPTER, ("Create adapter %lx %lx succeeded\n", Adapter, AdapterName));
+#else
+ if (Adapter == NULL) {
+ IPX_DEBUG (ADAPTER, ("Create adapter %ws failed\n", AdapterName->Buffer));
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ IPX_DEBUG (ADAPTER, ("Create adapter %ws succeeded\n", AdapterName->Buffer));
+#endif
+
+ RtlZeroMemory(Adapter, sizeof(ADAPTER));
+
+ //
+ // Copy over the adapter name.
+ //
+
+ Adapter->AdapterNameLength = AdapterName->Length + sizeof(WCHAR);
+ Adapter->AdapterName = (PWCHAR)(Adapter+1);
+ RtlCopyMemory(
+ Adapter->AdapterName,
+ AdapterName->Buffer,
+ AdapterName->Length);
+ Adapter->AdapterName[AdapterName->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+
+#if DBG
+ RtlCopyMemory(Adapter->Signature1, "IAD1", 4);
+#endif
+
+ Adapter->Type = IPX_ADAPTER_SIGNATURE;
+ Adapter->Size = sizeof(ADAPTER);
+
+ CTEInitLock (&Adapter->Lock);
+
+ InitializeListHead (&Adapter->RequestCompletionQueue);
+
+ InitializeListHead (&Adapter->ReceiveBufferPoolList);
+
+ ExInitializeSListHead (&Adapter->ReceiveBufferList);
+
+ Adapter->Device = Device;
+ Adapter->DeviceLock = &Device->Lock;
+ IpxReferenceDevice (Device, DREF_ADAPTER);
+
+#if 0
+ Adapter->ReceiveBufferPool.Next = NULL;
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+ Adapter->Bindings[i] = NULL;
+ }
+ Adapter->BindingCount = 0;
+
+ for (i = 0; i < IDENTIFIER_TOTAL; i++) {
+ for (j = 0; j < SOURCE_ROUTE_HASH_SIZE; j++) {
+ Adapter->SourceRoutingHeads[i][j] = (PSOURCE_ROUTE)NULL;
+ }
+ }
+#endif
+
+ //
+ // BUGBUG: For the moment, we have to do the source
+ // routing operation on any type where broadcast
+ // may not be used for discovery -- improve this
+ // hopefully.
+ //
+
+ Adapter->SourceRoutingEmpty[IDENTIFIER_RIP] = FALSE;
+ Adapter->SourceRoutingEmpty[IDENTIFIER_IPX] = FALSE;
+ Adapter->SourceRoutingEmpty[IDENTIFIER_SPX] = FALSE;
+ Adapter->SourceRoutingEmpty[IDENTIFIER_NB] = TRUE;
+
+#ifdef _PNP_POWER
+ //
+ // Lock here? [BUGBUGZZ]
+ //
+ Adapter->ReferenceCount = 1;
+#endif
+
+ *AdapterPtr = Adapter;
+
+ return STATUS_SUCCESS;
+
+} /* IpxCreateAdapter */
+
+
+VOID
+IpxDestroyAdapter(
+ IN PADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a device context structure.
+
+Arguments:
+
+ Adapter - Pointer to a pointer to a transport device context object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Database, Hash;
+ PSOURCE_ROUTE Current;
+ ULONG ReceiveBufferPoolSize;
+ PIPX_RECEIVE_BUFFER ReceiveBuffer;
+ PIPX_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ PDEVICE Device = Adapter->Device;
+ PLIST_ENTRY p;
+ UINT i;
+
+ IPX_DEBUG (ADAPTER, ("Destroy adapter %lx\n", Adapter));
+
+ //
+ // Free any receive buffer pools this adapter has.
+ //
+
+ ReceiveBufferPoolSize = FIELD_OFFSET (IPX_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(IPX_RECEIVE_BUFFER) * Device->InitReceiveBuffers) +
+ (Adapter->MaxReceivePacketSize * Device->InitReceiveBuffers);
+
+ while (!IsListEmpty (&Adapter->ReceiveBufferPoolList)) {
+
+ p = RemoveHeadList (&Adapter->ReceiveBufferPoolList);
+ ReceiveBufferPool = CONTAINING_RECORD (p, IPX_RECEIVE_BUFFER_POOL, Linkage);
+
+ for (i = 0; i < ReceiveBufferPool->BufferCount; i++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[i];
+ IpxDeinitializeReceiveBuffer (Adapter, ReceiveBuffer, Adapter->MaxReceivePacketSize);
+
+ }
+
+ IPX_DEBUG (PACKET, ("Free buffer pool %lx\n", ReceiveBufferPool));
+ IpxFreeMemory (ReceiveBufferPool, ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+ }
+
+ //
+ // Free all the source routing information for this adapter.
+ //
+
+ for (Database = 0; Database < IDENTIFIER_TOTAL; Database++) {
+
+ for (Hash = 0; Hash < SOURCE_ROUTE_HASH_SIZE; Hash++) {
+
+ while (Adapter->SourceRoutingHeads[Database][Hash]) {
+
+ Current = Adapter->SourceRoutingHeads[Database][Hash];
+ Adapter->SourceRoutingHeads[Database][Hash] = Current->Next;
+
+ IpxFreeMemory (Current, SOURCE_ROUTE_SIZE (Current->SourceRoutingLength), MEMORY_SOURCE_ROUTE, "SourceRouting");
+ }
+ }
+ }
+
+ IpxDereferenceDevice (Adapter->Device, DREF_ADAPTER);
+ IpxFreeMemory (Adapter, sizeof(ADAPTER) + Adapter->AdapterNameLength, MEMORY_ADAPTER, "Adapter");
+
+} /* IpxDestroyAdapter */
+
+
+NTSTATUS
+IpxCreateBinding(
+ IN PDEVICE Device,
+ IN PBINDING_CONFIG ConfigBinding OPTIONAL,
+ IN ULONG NetworkNumberIndex,
+ IN PWCHAR AdapterName,
+ IN OUT PBINDING *BindingPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates and initializes a binding structure.
+
+Arguments:
+
+ Device - The device.
+
+ ConfigBinding - Information about this binding. If this is
+ NULL then this is a WAN binding and all the relevant
+ information will be filled in by the caller.
+
+ NetworkNumberIndex - The index in the frame type array for
+ ConfigBinding indicating which frame type this binding is for.
+ Not used if ConfigBinding is not provided.
+
+ AdapterName - Used for error logging.
+
+ BindingPtr - Returns the allocated binding structure.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
+
+--*/
+
+{
+ PBINDING Binding;
+#ifdef _PNP_POWER
+ PSINGLE_LIST_ENTRY s;
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BindingList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ goto GotBinding;
+ }
+
+ //
+ // This function tries to allocate another packet pool.
+ //
+
+ s = IpxPopBinding(Device);
+
+ //
+ // Possibly we should queue the packet up to wait
+ // for one to become free.
+ //
+
+ if (s == NULL) {
+
+#if DBG
+ if (KeGetCurrentIrql() == 0) {
+ IPX_DEBUG (ADAPTER, ("Create binding %ws failed\n", AdapterName));
+ } else {
+ IPX_DEBUG (ADAPTER, ("Create binding WAN failed\n"));
+ }
+#endif
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+GotBinding:
+
+ Binding = CONTAINING_RECORD (s, BINDING, PoolLinkage);
+
+#else
+ Binding = (PBINDING)IpxAllocateMemory (sizeof(BINDING), MEMORY_ADAPTER, "Binding");
+
+ //
+ // We can't vsprintf a %ws at DPC level, so we check for
+ // that. Only WAN bindings will be created then.
+ //
+
+ if (Binding == NULL) {
+#if DBG
+ if (KeGetCurrentIrql() == 0) {
+ IPX_DEBUG (ADAPTER, ("Create binding %ws failed\n", AdapterName));
+ } else {
+ IPX_DEBUG (ADAPTER, ("Create binding WAN failed\n"));
+ }
+#endif
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+#endif
+
+#if DBG
+ if (KeGetCurrentIrql() == 0) {
+ IPX_DEBUG (ADAPTER, ("Create binding %ws succeeded, %lx\n", AdapterName, Binding));
+ } else {
+ IPX_DEBUG (ADAPTER, ("Create binding WAN succeeded\n"));
+ }
+#endif
+
+ RtlZeroMemory(Binding, sizeof(BINDING));
+
+ //
+ // Initialize the reference count.
+ //
+
+ Binding->ReferenceCount = 1;
+#if DBG
+ Binding->RefTypes[BREF_BOUND] = 1;
+#endif
+
+#if DBG
+ RtlCopyMemory(Binding->Signature1, "IBI1", 4);
+#endif
+
+ Binding->Type = IPX_BINDING_SIGNATURE;
+ Binding->Size = sizeof(BINDING);
+
+ Binding->Device = Device;
+ Binding->DeviceLock = &Device->Lock;
+
+ if (ConfigBinding != NULL) {
+
+ ULONG Temp = ConfigBinding->NetworkNumber[NetworkNumberIndex];
+ Binding->ConfiguredNetworkNumber = REORDER_ULONG (Temp);
+
+ Binding->AutoDetect = ConfigBinding->AutoDetect[NetworkNumberIndex];
+ Binding->DefaultAutoDetect = ConfigBinding->DefaultAutoDetect[NetworkNumberIndex];
+
+ Binding->AllRouteDirected = (BOOLEAN)ConfigBinding->Parameters[BINDING_ALL_ROUTE_DEF];
+ Binding->AllRouteBroadcast = (BOOLEAN)ConfigBinding->Parameters[BINDING_ALL_ROUTE_BC];
+ Binding->AllRouteMulticast = (BOOLEAN)ConfigBinding->Parameters[BINDING_ALL_ROUTE_MC];
+
+ }
+
+ Binding->ReceiveBroadcast = TRUE;
+#if 0
+ Binding->BindingSetMember = FALSE;
+ Binding->NextBinding = (PBINDING)NULL;
+ Binding->DialOutAsync = FALSE;
+#endif
+
+ //
+ // We set Binding->FrameType later, after we can map it based on the
+ // media type of the adapter we bind to.
+ //
+
+ *BindingPtr = Binding;
+
+ return STATUS_SUCCESS;
+
+} /* IpxCreateBinding */
+
+
+VOID
+IpxDestroyBinding(
+ IN PBINDING Binding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a binding structure.
+
+Arguments:
+
+ Binding - Pointer to a transport binding structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IPX_DEBUG (ADAPTER, ("Destroy binding %lx\n", Binding));
+
+#ifdef _PNP_POWER
+
+ IPX_PUSH_ENTRY_LIST(
+ &IpxDevice->BindingList,
+ &Binding->PoolLinkage,
+ &IpxDevice->SListsLock);
+#else
+ IpxFreeMemory (Binding, sizeof(BINDING), MEMORY_ADAPTER, "Binding");
+#endif
+
+} /* IpxDestroyBinding */
+
+
+#ifdef _PNP_POWER
+VOID
+IpxAllocateBindingPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 bindings to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_BINDING_POOL BindingPool;
+ UINT BindingPoolSize;
+ UINT BindingNum;
+ PBINDING Binding;
+ CTELockHandle LockHandle;
+
+ BindingPoolSize = FIELD_OFFSET (IPX_BINDING_POOL, Bindings[0]) +
+ (sizeof(BINDING) * Device->InitBindings);
+
+ BindingPool = (PIPX_BINDING_POOL)IpxAllocateMemory (BindingPoolSize, MEMORY_PACKET, "BindingPool");
+
+ if (BindingPool == NULL) {
+ IPX_DEBUG (PNP, ("Could not allocate binding pool memory\n"));
+ return;
+ }
+
+
+ IPX_DEBUG (PNP, ("Initializing Binding pool %lx, %d bindings\n",
+ BindingPool, Device->InitBindings));
+
+ BindingPool->BindingCount = Device->InitBindings;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (BindingNum = 0; BindingNum < BindingPool->BindingCount; BindingNum++) {
+
+ Binding = &BindingPool->Bindings[BindingNum];
+ IPX_PUSH_ENTRY_LIST (&Device->BindingList, &Binding->PoolLinkage, &Device->SListsLock);
+
+#ifdef IPX_TRACK_POOL
+ Binding->Pool = BindingPool;
+#endif
+ }
+
+ InsertTailList (&Device->BindingPoolList, &BindingPool->Linkage);
+
+ Device->AllocatedBindings += BindingPool->BindingCount;
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+} /* IpxAllocateBindingPool */
+
+
+PSINGLE_LIST_ENTRY
+IpxPopBinding(
+ PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a binding from the device context's pool.
+ If there are no bindings in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated binding.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BindingList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedBindings < Device->MaxPoolBindings) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ IpxAllocateBindingPool (Device);
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BindingList,
+ &Device->SListsLock);
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* IpxPopBinding */
+#endif
+
+//
+// [FW]
+//
+
+NTSTATUS
+IpxOpenAdapter(
+ IN NIC_HANDLE AdapterIndex1,
+ IN ULONG FwdAdapterContext,
+ OUT PNIC_HANDLE IpxAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the Kernel Forwarder to open an adapter
+
+Arguments:
+
+ AdapterIndex - index of the adapter to open (NICid for now - will change to a struct
+ with a version number, signature and the NicId
+ FwdAdapterContext - Forwarder's context
+ IpxAdapterContext - our context (for now we use the NICid - for pnp will change
+ this to contain a signature and version #)
+
+Return Value:
+
+ STATUS_INVALID_HANDLE if the AdapterIndex handle was invalid
+ STATUS_ADAPTER_ALREADY_OPENED if the Adapter is being opened a second time
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PBINDING Binding;
+ PDEVICE Device = IpxDevice;
+ USHORT AdapterIndex = AdapterIndex1.NicId;
+
+#if DBG
+ DbgPrint ("IPX: Entered IpxOpenAdapter\n");
+#endif
+
+ //
+ // Return error if the AdapterIndex is out of range.
+ // We do indicate the slave bindings to NB/SPX (but not to RIP)
+ // Hence, the index should be less than HighestExternalNicId (not ValidBindings)
+ //
+
+ if (AdapterIndex > Device->HighestExternalNicId) {
+ return STATUS_INVALID_HANDLE;
+ }
+
+
+ //
+ // Fill up our context to be returned to the Forwarder
+ //
+ NIC_HANDLE_FROM_NIC((*IpxAdapterContext), AdapterIndex);
+
+ //
+ // If AdapterIndex is 0, it is for the virtual net
+ // BUGBUG: Will the forwarder open this at all?
+ //
+
+ if (AdapterIndex == 0) {
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Get the binding pointer
+ //
+
+ Binding = NIC_ID_TO_BINDING(IpxDevice, AdapterIndex);
+
+ //
+ // Return error if adapter is being opened a second time (or more times)
+ //
+
+ if (GET_VALUE(Binding->ReferenceCount) >= 2) {
+ return STATUS_ADAPTER_ALREADY_OPENED;
+ }
+
+ //
+ // Store the Forwarder's Adapter Context in the binding
+ //
+
+ Binding->FwdAdapterContext = FwdAdapterContext;
+
+ //
+ // Reference the Binding
+ //
+
+ IpxReferenceBinding(Binding, BREF_FWDOPEN);
+
+ return STATUS_SUCCESS;
+
+}
+
+NTSTATUS
+IpxCloseAdapter(
+ IN NIC_HANDLE IpxAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the Kernel Forwarder to close an adapter
+
+Arguments:
+
+ IpxAdapterContext - our context (for now we use the NICid - for pnp will change
+ this to contain a signature and version#)
+
+Return Value:
+
+ STATUS_ADAPTER_ALREADY_CLOSED - if the adapter is being closed a second time
+ STATUS_SUCCESS
+
+--*/
+
+{
+
+ PBINDING Binding;
+
+#if DBG
+ DbgPrint ("IPX: Entered IpxCloseAdapter\n");
+#endif
+
+ Binding = NIC_ID_TO_BINDING(IpxDevice, IpxAdapterContext.NicId);
+
+ //
+ // Either the adapter is around (count = 2)
+ // or it went away (count = 1). The latter cannot happen now.
+ //
+
+ if (GET_VALUE(Binding->ReferenceCount) <= 1) {
+ return STATUS_ADAPTER_ALREADY_CLOSED;
+ }
+
+ //
+ // Dereference the Binding so it can be deleted
+ //
+
+ IpxDereferenceBinding(Binding, BREF_FWDOPEN);
+
+
+ //
+ // Clear the Forwarder's Adapter Context in the binding
+ //
+
+ Binding->FwdAdapterContext = 0;
+
+ return STATUS_SUCCESS;
+}
+
diff --git a/private/ntos/tdi/isn/ipx/address.c b/private/ntos/tdi/isn/ipx/address.c
new file mode 100644
index 000000000..c7e1e0f38
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/address.c
@@ -0,0 +1,1882 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ address.c
+
+Abstract:
+
+ This module contains code which implements the ADDRESS object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport address objects.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports - tagged [CH]
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Map all generic accesses to the same one.
+//
+
+static GENERIC_MAPPING AddressGenericMapping =
+ { READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL };
+
+
+
+TDI_ADDRESS_IPX UNALIGNED *
+IpxParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, looking for an address
+ of type TDI_ADDRESS_TYPE_IPX.
+
+Arguments:
+
+ Transport - The generic TDI address.
+
+Return Value:
+
+ A pointer to the IPX address, or NULL if none is found.
+
+--*/
+
+{
+ TA_ADDRESS UNALIGNED * addressName;
+ INT i;
+
+ addressName = &TransportAddress->Address[0];
+
+ //
+ // The name can be passed with multiple entries; we'll take and use only
+ // the IPX one.
+ //
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++) {
+ if (addressName->AddressType == TDI_ADDRESS_TYPE_IPX) {
+ if (addressName->AddressLength >= sizeof(TDI_ADDRESS_IPX)) {
+ return ((TDI_ADDRESS_IPX UNALIGNED *)(addressName->Address));
+ }
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+ return NULL;
+
+} /* IpxParseTdiAddress */
+
+
+BOOLEAN
+IpxValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, verifying that the
+ components of the address do not extend past the specified
+ length.
+
+Arguments:
+
+ TransportAddress - The generic TDI address.
+
+ TransportAddressLength - The specific length of TransportAddress.
+
+Return Value:
+
+ TRUE if the address is valid, FALSE otherwise.
+
+--*/
+
+{
+ PUCHAR AddressEnd = ((PUCHAR)TransportAddress) + TransportAddressLength;
+ TA_ADDRESS UNALIGNED * addressName;
+ INT i;
+
+ if (TransportAddressLength < sizeof(TransportAddress->TAAddressCount)) {
+ IpxPrint0 ("IpxValidateTdiAddress: runt address\n");
+ return FALSE;
+ }
+
+ addressName = &TransportAddress->Address[0];
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++) {
+ if (addressName->Address > AddressEnd) {
+ IpxPrint0 ("IpxValidateTdiAddress: address too short\n");
+ return FALSE;
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+
+ if ((PUCHAR)addressName > AddressEnd) {
+ IpxPrint0 ("IpxValidateTdiAddress: address too short\n");
+ return FALSE;
+ }
+ return TRUE;
+
+} /* IpxValidateTdiAddress */
+
+#if DBG
+
+VOID
+IpxBuildTdiAddress(
+ IN PVOID AddressBuffer,
+ IN ULONG Network,
+ IN UCHAR Node[6],
+ IN USHORT Socket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine fills in a TRANSPORT_ADDRESS in the specified
+ buffer, given the socket, network and node.
+
+Arguments:
+
+ AddressBuffer - The buffer that will hold the address.
+
+ Network - The network number.
+
+ Node - The node address.
+
+ Socket - The socket.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ TA_IPX_ADDRESS UNALIGNED * IpxAddress;
+
+ IpxAddress = (TA_IPX_ADDRESS UNALIGNED *)AddressBuffer;
+
+ IpxAddress->TAAddressCount = 1;
+ IpxAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX);
+ IpxAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
+ IpxAddress->Address[0].Address[0].NetworkAddress = Network;
+ IpxAddress->Address[0].Address[0].Socket = Socket;
+ RtlCopyMemory(IpxAddress->Address[0].Address[0].NodeAddress, Node, 6);
+
+} /* IpxBuildTdiAddress */
+#endif
+
+
+NTSTATUS
+IpxOpenAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+{
+ return(IpxOpenAddressM(Device, Request, 0));
+}
+
+
+
+NTSTATUS
+IpxOpenAddressM(
+ IN PDEVICE Device,
+ IN PREQUEST Request,
+ IN ULONG Index
+ )
+/*++
+
+Routine Description:
+
+ This routine opens a file that points to an existing address object, or, if
+ the object doesn't exist, creates it (note that creation of the address
+ object includes registering the address, and may take many seconds to
+ complete, depending upon system configuration).
+
+ If the address already exists, and it has an ACL associated with it, the
+ ACL is checked for access rights before allowing creation of the address.
+
+Arguments:
+
+ Device - pointer to the device describing the IPX transport.
+
+ Request - a pointer to the request used for the creation of the address.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ PFILE_FULL_EA_INFORMATION ea;
+ TRANSPORT_ADDRESS UNALIGNED *name;
+ TA_ADDRESS UNALIGNED *AddressName;
+ USHORT Socket;
+ ULONG DesiredShareAccess;
+ CTELockHandle LockHandle;
+ PACCESS_STATE AccessState;
+ ACCESS_MASK GrantedAccess;
+ BOOLEAN AccessAllowed;
+ int i;
+ BOOLEAN found = FALSE;
+#ifdef ISN_NT
+ PIRP Irp = (PIRP)Request;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+#endif
+
+
+ //
+ // If we are a dedicated router, we cannot let addresses
+ // be opened.
+ //
+
+ if (Device->DedicatedRouter && (REQUEST_CODE(Request) != MIPX_RT_CREATE)) {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ //
+ // The network name is in the EA, passed in the request.
+ //
+
+ ea = OPEN_REQUEST_EA_INFORMATION(Request);
+ if (ea == NULL) {
+ IpxPrint1("OpenAddress: REQUEST %lx has no EA\n", Request);
+ return STATUS_NONEXISTENT_EA_ENTRY;
+ }
+
+ //
+ // this may be a valid name; parse the name from the EA and use it if OK.
+ //
+
+ name = (PTRANSPORT_ADDRESS)&ea->EaName[ea->EaNameLength+1];
+ AddressName = (PTA_ADDRESS)&name->Address[0];
+
+ //
+ // The name can be passed with multiple entries; we'll take and use only
+ // the first one of type IPX.
+ //
+
+ for (i=0;i<name->TAAddressCount;i++) {
+ if (AddressName->AddressType == TDI_ADDRESS_TYPE_IPX) {
+ if (AddressName->AddressLength >= sizeof(TDI_ADDRESS_IPX)) {
+ Socket = ((TDI_ADDRESS_IPX UNALIGNED *)&AddressName->Address[0])->Socket;
+ found = TRUE;
+ }
+ break;
+
+ } else {
+
+ AddressName = (PTA_ADDRESS)(AddressName->Address +
+ AddressName->AddressLength);
+
+ }
+
+ }
+
+ if (!found) {
+ IPX_DEBUG (ADDRESS, ("OpenAddress, request %lx has no IPX Address\n", Request));
+ return STATUS_NONEXISTENT_EA_ENTRY;
+ }
+
+ if (Socket == 0) {
+
+ Socket = IpxAssignSocket (Device);
+
+ if (Socket == 0) {
+ IPX_DEBUG (ADDRESS, ("OpenAddress, no unique socket found\n"));
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysOpenSocketFails);
+#endif SNMP
+ return STATUS_INSUFFICIENT_RESOURCES;
+ } else {
+ IPX_DEBUG (ADDRESS, ("OpenAddress, assigned socket %lx\n", REORDER_USHORT(Socket)));
+ }
+
+ } else {
+
+ IPX_DEBUG (ADDRESS, ("OpenAddress, socket %lx\n", REORDER_USHORT(Socket)));
+
+ }
+
+ //
+ // get an address file structure to represent this address.
+ //
+
+ AddressFile = IpxCreateAddressFile (Device);
+
+ if (AddressFile == (PADDRESS_FILE)NULL) {
+ return status;
+ }
+
+ //
+ // We mark this socket specially.
+ //
+
+ if (Socket == SAP_SOCKET) {
+ AddressFile->IsSapSocket = TRUE;
+ AddressFile->SpecialReceiveProcessing = TRUE;
+ }
+
+ //
+ // See if this address is already established. This call automatically
+ // increments the reference count on the address so that it won't disappear
+ // from underneath us after this call but before we have a chance to use it.
+ //
+ // To ensure that we don't create two address objects for the
+ // same address, we hold the device context addressResource until
+ // we have found the address or created a new one.
+ //
+
+ ExAcquireResourceExclusive (&Device->AddressResource, TRUE);
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ Address = IpxLookupAddress (Device, Socket);
+
+ if (Address == NULL) {
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ //
+ // This address doesn't exist. Create it.
+ // registering it.
+ //
+
+ Address = IpxCreateAddress (
+ Device,
+ Socket);
+
+ if (Address != (PADDRESS)NULL) {
+
+ //
+ // Set this now in case we have to deref.
+ //
+
+ AddressFile->AddressLock = &Address->Lock;
+
+ if (REQUEST_CODE(Request) == MIPX_RT_CREATE) {
+ Address->RtAdd = TRUE;
+ Address->Index = Index;
+ } else {
+ Address->RtAdd = FALSE;
+ }
+
+#ifdef ISN_NT
+
+ //
+ // Initialize the shared access now. We use read access
+ // to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ IoSetShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &Address->u.ShareAccess);
+
+
+ //
+ // Assign the security descriptor (need to do this with
+ // the spinlock released because the descriptor is not
+ // mapped).
+ //
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ status = SeAssignSecurity(
+ NULL, // parent descriptor
+ AccessState->SecurityDescriptor,
+ &Address->SecurityDescriptor,
+ FALSE, // is directory
+ &AccessState->SubjectSecurityContext,
+ &AddressGenericMapping,
+ NonPagedPool);
+
+ if (!NT_SUCCESS(status)) {
+
+ //
+ // Error, return status.
+ //
+
+ IoRemoveShareAccess (IrpSp->FileObject, &Address->u.ShareAccess);
+ ExReleaseResource (&Device->AddressResource);
+ IpxDereferenceAddress (Address, AREF_ADDRESS_FILE);
+ IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ return status;
+
+ }
+
+#endif
+
+ ExReleaseResource (&Device->AddressResource);
+
+ //
+ // if the adapter isn't ready, we can't do any of this; get out
+ //
+
+ if (Device->State == DEVICE_STATE_STOPPING) {
+ IpxDereferenceAddress (Address, AREF_ADDRESS_FILE);
+ IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ status = STATUS_DEVICE_NOT_READY;
+
+ } else {
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+#ifdef ISN_NT
+ AddressFile->FileObject = IrpSp->FileObject;
+#endif
+ AddressFile->Request = Request;
+ AddressFile->Address = Address;
+
+ CTEGetLock (&Address->Lock, &LockHandle);
+ InsertTailList (&Address->AddressFileDatabase, &AddressFile->Linkage);
+ CTEFreeLock (&Address->Lock, LockHandle);
+
+ AddressFile->Request = NULL;
+ AddressFile->State = ADDRESSFILE_STATE_OPEN;
+ status = STATUS_SUCCESS;
+
+ }
+
+ } else {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ //
+ // If the address could not be created, and is not in the
+ // process of being created, then we can't open up an address.
+ // Since we can't use the AddressLock to deref, we just destroy
+ // the address file.
+ //
+
+ IpxDestroyAddressFile (AddressFile);
+
+ }
+
+ } else {
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ IPX_DEBUG (ADDRESS, ("Add to address %lx\n", Address));
+
+ //
+ // We never allow shared access to a RT address. So, check that
+ // we don't have a "RT address create" request and also that the
+ // address has not only been taken up by a RT Address request. If
+ // and only if both the above
+ //
+ if ((REQUEST_CODE(Request) != MIPX_RT_CREATE) && (!Address->RtAdd))
+ {
+ //
+ // Set this now in case we have to deref.
+ //
+
+ AddressFile->AddressLock = &Address->Lock;
+
+ //
+ // The address already exists. Check the ACL and see if we
+ // can access it. If so, simply use this address as our address.
+ //
+
+#ifdef ISN_NT
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ AccessAllowed = SeAccessCheck(
+ Address->SecurityDescriptor,
+ &AccessState->SubjectSecurityContext,
+ FALSE, // tokens locked
+ IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
+ (ACCESS_MASK)0, // previously granted
+ NULL, // privileges
+ &AddressGenericMapping,
+ Irp->RequestorMode,
+ &GrantedAccess,
+ &status);
+
+#else // ISN_NT
+
+ AccessAllowed = TRUE;
+
+#endif // ISN_NT
+
+ if (!AccessAllowed) {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ } else {
+
+#ifdef ISN_NT
+
+ //
+ // Now check that we can obtain the desired share
+ // access. We use read access to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ status = IoCheckShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &Address->u.ShareAccess,
+ TRUE);
+
+#else // ISN_NT
+
+ status = STATUS_SUCCESS;
+
+#endif // ISN_NT
+
+ if (!NT_SUCCESS (status)) {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ } else {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ CTEGetLock (&Address->Lock, &LockHandle);
+
+ InsertTailList (
+ &Address->AddressFileDatabase,
+ &AddressFile->Linkage);
+
+ AddressFile->Request = NULL;
+ AddressFile->Address = Address;
+#ifdef ISN_NT
+ AddressFile->FileObject = IrpSp->FileObject;
+#endif
+ AddressFile->State = ADDRESSFILE_STATE_OPEN;
+
+ IpxReferenceAddress (Address, AREF_ADDRESS_FILE);
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ CTEFreeLock (&Address->Lock, LockHandle);
+
+ status = STATUS_SUCCESS;
+
+ }
+ }
+ }
+ else
+ {
+ DbgPrint("IpxOpenAddress: ACCESS DENIED - duplicate address\n");
+ status = STATUS_ACCESS_DENIED;
+ ExReleaseResource (&Device->AddressResource);
+ IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ }
+
+ //
+ // Remove the reference from IpxLookupAddress.
+ //
+
+ IpxDereferenceAddress (Address, AREF_LOOKUP);
+ }
+
+ return status;
+
+} /* IpxOpenAddress */
+
+
+USHORT
+IpxAssignSocket(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine assigns a socket that is unique within a range
+ of SocketUniqueness.
+
+Arguments:
+
+ Device - Pointer to the device context.
+
+Return Value:
+
+ The assigned socket number, or 0 if a unique one cannot
+ be found.
+
+--*/
+
+{
+ USHORT InitialSocket, CurrentSocket, AddressSocket;
+ ULONG CurrentHash;
+ BOOLEAN Conflict;
+ PLIST_ENTRY p;
+ PADDRESS Address;
+ CTELockHandle LockHandle;
+
+ //
+ // Loop through all possible sockets, starting at
+ // Device->CurrentSocket, looking for a suitable one.
+ // Device->CurrentSocket rotates through the possible
+ // sockets to improve the chances of finding one
+ // quickly.
+ //
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ InitialSocket = Device->CurrentSocket;
+ Device->CurrentSocket = (USHORT)(Device->CurrentSocket + Device->SocketUniqueness);
+ if ((USHORT)(Device->CurrentSocket+Device->SocketUniqueness) > Device->SocketEnd) {
+ Device->CurrentSocket = Device->SocketStart;
+ }
+
+ CurrentSocket = InitialSocket;
+
+ do {
+
+ //
+ // Scan all addresses; if we find one with a socket
+ // that conflicts with this one, we can't use it.
+ //
+ // NOTE: Device->Lock is acquired here.
+ //
+
+ Conflict = FALSE;
+
+ for (CurrentHash = 0; CurrentHash < IPX_ADDRESS_HASH_COUNT; CurrentHash++) {
+
+ for (p = Device->AddressDatabases[CurrentHash].Flink;
+ p != &Device->AddressDatabases[CurrentHash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+ AddressSocket = REORDER_USHORT(Address->Socket);
+
+ if ((AddressSocket + Device->SocketUniqueness > CurrentSocket) &&
+ (AddressSocket < CurrentSocket + Device->SocketUniqueness)) {
+ Conflict = TRUE;
+ break;
+ }
+ }
+
+ //
+ // If we've found a conflict, no need to check the other
+ // queues.
+ //
+
+ if (Conflict) {
+ break;
+ }
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ //
+ // We intentionally free the lock here so that we
+ // never spend too much time with it held.
+ //
+
+ if (!Conflict) {
+
+ //
+ // We went through the address list without
+ // finding a conflict; use this socket.
+ //
+
+ return REORDER_USHORT(CurrentSocket);
+ }
+
+ CurrentSocket = (USHORT)(CurrentSocket + Device->SocketUniqueness);
+ if ((USHORT)(CurrentSocket+Device->SocketUniqueness) > Device->SocketEnd) {
+ CurrentSocket = Device->SocketStart;
+ }
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ } while (CurrentSocket != InitialSocket);
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ //
+ // Could not find one to assign.
+ //
+
+ return (USHORT)0;
+
+} /* IpxAssignSocket */
+
+
+PADDRESS
+IpxCreateAddress(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a transport address and associates it with
+ the specified transport device context. The reference count in the
+ address is automatically set to 1, and the reference count of the
+ device context is incremented.
+
+ NOTE: This routine must be called with the Device
+ spinlock held.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ Socket - The socket to assign to this address.
+
+Return Value:
+
+ The newly created address, or NULL if none can be allocated.
+
+--*/
+
+{
+ PADDRESS Address;
+ PIPX_SEND_RESERVED SendReserved;
+ PIPX_RECEIVE_RESERVED ReceiveReserved;
+ NDIS_STATUS Status;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ Address = (PADDRESS)IpxAllocateMemory (sizeof(ADDRESS), MEMORY_ADDRESS, "Address");
+ if (Address == NULL) {
+ IPX_DEBUG (ADDRESS, ("Create address %lx failed\n", REORDER_USHORT(Socket)));
+ return NULL;
+ }
+
+ IPX_DEBUG (ADDRESS, ("Create address %lx (%lx)\n", Address, REORDER_USHORT(Socket)));
+ RtlZeroMemory (Address, sizeof(ADDRESS));
+
+#ifndef IPX_OWN_PACKETS
+ IpxAllocateSingleSendPacket(Device, &Address->SendPacket, &Status);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ goto Fail1;
+ }
+#endif
+
+ if (IpxInitializeSendPacket (Device, &Address->SendPacket, Address->SendPacketHeader) != STATUS_SUCCESS) {
+#ifndef IPX_OWN_PACKETS
+Fail1:
+#endif
+ Address->SendPacketInUse = TRUE;
+ } else {
+ SendReserved = SEND_RESERVED(&Address->SendPacket);
+ SendReserved->Address = Address;
+ SendReserved->OwnedByAddress = TRUE;
+ Address->SendPacketInUse = FALSE;
+#ifdef IPX_TRACK_POOL
+ SendReserved->Pool = NULL;
+#endif
+ }
+
+
+#if BACK_FILL
+ {
+ PIPX_SEND_RESERVED BackFillReserved;
+
+#ifndef IPX_OWN_PACKETS
+ IpxAllocateSingleSendPacket(Device, &Address->BackFillPacket, &Status);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ goto Fail2;
+ }
+#endif
+ if (IpxInitializeBackFillPacket (Device, &Address->BackFillPacket, NULL) != STATUS_SUCCESS) {
+#ifndef IPX_OWN_PACKETS
+Fail2:
+#endif
+ Address->BackFillPacketInUse = TRUE;
+ } else {
+ BackFillReserved = SEND_RESERVED(&Address->BackFillPacket);
+ BackFillReserved->Address = Address;
+ Address->BackFillPacketInUse = FALSE;
+ BackFillReserved->OwnedByAddress = TRUE;
+#ifdef IPX_TRACK_POOL
+ BackFillReserved->Pool = NULL;
+#endif
+ }
+ }
+#endif
+
+#ifndef IPX_OWN_PACKETS
+ IpxAllocateSingleReceivePacket(Device, &Address->ReceivePacket, &Status);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ goto Fail3;
+ }
+#endif
+ if (IpxInitializeReceivePacket (Device, &Address->ReceivePacket) != STATUS_SUCCESS) {
+#ifndef IPX_OWN_PACKETS
+Fail3:
+#endif
+ Address->ReceivePacketInUse = TRUE;
+ } else {
+ ReceiveReserved = RECEIVE_RESERVED(&Address->ReceivePacket);
+ ReceiveReserved->Address = Address;
+ ReceiveReserved->OwnedByAddress = TRUE;
+ Address->ReceivePacketInUse = FALSE;
+#ifdef IPX_TRACK_POOL
+ ReceiveReserved->Pool = NULL;
+#endif
+ }
+
+ Address->Type = IPX_ADDRESS_SIGNATURE;
+ Address->Size = sizeof (ADDRESS);
+
+ Address->Device = Device;
+ Address->DeviceLock = &Device->Lock;
+ CTEInitLock (&Address->Lock);
+
+ InitializeListHead (&Address->AddressFileDatabase);
+
+ Address->ReferenceCount = 1;
+#if DBG
+ Address->RefTypes[AREF_ADDRESS_FILE] = 1;
+#endif
+ Address->Socket = Socket;
+ Address->SendSourceSocket = Socket;
+
+ //
+ // Save our local address for building datagrams quickly.
+ //
+
+ RtlCopyMemory (&Address->LocalAddress, &Device->SourceAddress, FIELD_OFFSET(TDI_ADDRESS_IPX,Socket));
+ Address->LocalAddress.Socket = Socket;
+
+ //
+ // Now link this address into the specified device context's
+ // address database. To do this, we need to acquire the spin lock
+ // on the device context.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+ InsertTailList (&Device->AddressDatabases[IPX_HASH_SOCKET(Socket)], &Address->Linkage);
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ IpxReferenceDevice (Device, DREF_ADDRESS);
+
+ return Address;
+
+} /* IpxCreateAddress */
+
+
+NTSTATUS
+IpxVerifyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to verify that the pointer given us in a file
+ object is in fact a valid address file object. We also verify that the
+ address object pointed to by it is a valid address object, and reference
+ it to keep it from disappearing while we use it.
+
+Arguments:
+
+ AddressFile - potential pointer to a ADDRESS_FILE object
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_ADDRESS otherwise
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ NTSTATUS status = STATUS_SUCCESS;
+ PADDRESS Address;
+
+ //
+ // try to verify the address file signature. If the signature is valid,
+ // verify the address pointed to by it and get the address spinlock.
+ // check the address's state, and increment the reference count if it's
+ // ok to use it. Note that the only time we return an error for state is
+ // if the address is closing.
+ //
+
+ try {
+
+ if ((AddressFile->Size == sizeof (ADDRESS_FILE)) &&
+ (AddressFile->Type == IPX_ADDRESSFILE_SIGNATURE) ) {
+// (AddressFile->State != ADDRESSFILE_STATE_CLOSING) ) {
+
+ Address = AddressFile->Address;
+
+ if ((Address->Size == sizeof (ADDRESS)) &&
+ (Address->Type == IPX_ADDRESS_SIGNATURE) ) {
+
+ CTEGetLock (&Address->Lock, &LockHandle);
+
+ if (!Address->Stopping) {
+
+ IpxReferenceAddressFileLock (AddressFile, AFREF_VERIFY);
+
+ } else {
+
+ IpxPrint1("IpxVerifyAddressFile: A %lx closing\n", Address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ CTEFreeLock (&Address->Lock, LockHandle);
+
+ } else {
+
+ IpxPrint1("IpxVerifyAddressFile: A %lx bad signature\n", Address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } else {
+
+ IpxPrint1("IpxVerifyAddressFile: AF %lx bad signature\n", AddressFile);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ IpxPrint1("IpxVerifyAddressFile: AF %lx exception\n", Address);
+ return GetExceptionCode();
+ }
+
+ return status;
+
+} /* IpxVerifyAddressFile */
+
+
+VOID
+IpxDestroyAddress(
+ IN PVOID Parameter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a transport address and removes all references
+ made by it to other objects in the transport. The address structure
+ is returned to nonpaged system pool. It is assumed
+ that the caller has already removed all addressfile structures associated
+ with this address.
+
+ It is called from a worker thread queue by IpxDerefAddress when
+ the reference count goes to 0.
+
+ This thread is only queued by IpxDerefAddress. The reason for
+ this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ Address - Pointer to a transport address structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PADDRESS Address = (PADDRESS)Parameter;
+ PDEVICE Device = Address->Device;
+ CTELockHandle LockHandle;
+
+ IPX_DEBUG (ADDRESS, ("Destroy address %lx (%lx)\n", Address, REORDER_USHORT(Address->Socket)));
+
+ SeDeassignSecurity (&Address->SecurityDescriptor);
+
+ //
+ // Delink this address from its associated device context's address
+ // database. To do this we must spin lock on the device context object,
+ // not on the address.
+ //
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Address->Linkage);
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ if (!Address->SendPacketInUse) {
+ IpxDeinitializeSendPacket (Device, &Address->SendPacket);
+#ifndef IPX_OWN_PACKETS
+ IpxFreeSingleSendPacket (Device, Address->SendPacket);
+#endif
+ }
+
+ if (!Address->ReceivePacketInUse) {
+ IpxDeinitializeReceivePacket (Device, &Address->ReceivePacket);
+#ifndef IPX_OWN_PACKETS
+ IpxFreeSingleReceivePacket (Device, Address->ReceivePacket);
+#endif
+ }
+
+#if BACK_FILL
+ if (!Address->BackFillPacketInUse) {
+ IpxDeinitializeBackFillPacket (Device, &Address->BackFillPacket);
+#ifndef IPX_OWN_PACKETS
+ IpxFreeSingleSendPacket (Device, Address->BackFillPacket);
+#endif
+ }
+#endif
+ IpxFreeMemory (Address, sizeof(ADDRESS), MEMORY_ADDRESS, "Address");
+
+ IpxDereferenceDevice (Device, DREF_ADDRESS);
+
+} /* IpxDestroyAddress */
+
+
+#if DBG
+VOID
+IpxRefAddress(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (Address->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement(&Address->ReferenceCount);
+
+} /* IpxRefAddress */
+
+
+VOID
+IpxRefAddressLock(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address
+ when the device lock is already held.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (Address->ReferenceCount > 0); // not perfect, but...
+
+ // ++Address->ReferenceCount;
+ (VOID)InterlockedIncrement(&Address->ReferenceCount);
+
+} /* IpxRefAddressLock */
+#endif
+
+
+VOID
+IpxDerefAddress(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport address by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IpxDestroyAddress to remove it from the system.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+
+ oldvalue = IPX_ADD_ULONG (
+ &Address->ReferenceCount,
+ (ULONG)-1,
+ Address->DeviceLock);
+
+ //
+ // If we have deleted all references to this address, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ CTEAssert (oldvalue != 0);
+
+ if (oldvalue == 1) {
+
+#if ISN_NT
+ ExInitializeWorkItem(
+ &Address->u.DestroyAddressQueueItem,
+ IpxDestroyAddress,
+ (PVOID)Address);
+ ExQueueWorkItem(&Address->u.DestroyAddressQueueItem, DelayedWorkQueue);
+#else
+ IpxDestroyAddress(Address);
+#endif
+
+ }
+
+} /* IpxDerefAddress */
+
+
+VOID
+IpxDerefAddressSync(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport address by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IpxDestroyAddress to remove it from the system. This routine can
+ only be called when we are synchronized (inside an IPX_SYNC_START/
+ IPX_SYNC_END pair, with a lock held, or in an indication).
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+
+ oldvalue = IPX_ADD_ULONG (
+ &Address->ReferenceCount,
+ (ULONG)-1,
+ Address->DeviceLock);
+
+ //
+ // If we have deleted all references to this address, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ CTEAssert (oldvalue != 0);
+
+ if (oldvalue == 1) {
+
+#if ISN_NT
+ ExInitializeWorkItem(
+ &Address->u.DestroyAddressQueueItem,
+ IpxDestroyAddress,
+ (PVOID)Address);
+ ExQueueWorkItem(&Address->u.DestroyAddressQueueItem, DelayedWorkQueue);
+#else
+ IpxDestroyAddress(Address);
+#endif
+
+ }
+
+} /* IpxDerefAddressSync */
+
+
+PADDRESS_FILE
+IpxCreateAddressFile(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates an address file from the pool of ther
+ specified device context. The reference count in the
+ address is automatically set to 1.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+Return Value:
+
+ The allocate address file or NULL.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PADDRESS_FILE AddressFile;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ AddressFile = (PADDRESS_FILE)IpxAllocateMemory (sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile");
+ if (AddressFile == NULL) {
+ IPX_DEBUG (ADDRESS, ("Create address file failed\n"));
+ CTEFreeLock (&Device->Lock, LockHandle);
+ return NULL;
+ }
+
+ IPX_DEBUG (ADDRESS, ("Create address file %lx\n", AddressFile));
+
+ RtlZeroMemory (AddressFile, sizeof(ADDRESS_FILE));
+
+ AddressFile->Type = IPX_ADDRESSFILE_SIGNATURE;
+ AddressFile->Size = sizeof (ADDRESS_FILE);
+
+ InitializeListHead (&AddressFile->ReceiveDatagramQueue);
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+#if 0
+ AddressFile->SpecialReceiveProcessing = FALSE;
+ AddressFile->ExtendedAddressing = FALSE;
+ AddressFile->ReceiveIpxHeader = FALSE;
+ AddressFile->FilterOnPacketType = FALSE;
+ AddressFile->DefaultPacketType = 0;
+ AddressFile->Address = NULL;
+#ifdef ISN_NT
+ AddressFile->FileObject = NULL;
+#endif
+#endif
+
+ AddressFile->Device = Device;
+ AddressFile->State = ADDRESSFILE_STATE_OPENING;
+ AddressFile->ReferenceCount = 1;
+#if DBG
+ AddressFile->RefTypes[AFREF_CREATE] = 1;
+#endif
+ AddressFile->CloseRequest = (PREQUEST)NULL;
+
+ //
+ // Initialize the request handlers.
+ //
+
+ AddressFile->RegisteredReceiveDatagramHandler = FALSE;
+ AddressFile->ReceiveDatagramHandler = TdiDefaultRcvDatagramHandler;
+ AddressFile->ReceiveDatagramHandlerContext = NULL;
+
+ //
+ // [CH] Added these handlers for chained buffer receives
+ //
+ AddressFile->RegisteredChainedReceiveDatagramHandler = FALSE;
+ AddressFile->ChainedReceiveDatagramHandler = TdiDefaultChainedRcvDatagramHandler;
+ AddressFile->ChainedReceiveDatagramHandlerContext = NULL;
+
+ AddressFile->RegisteredErrorHandler = FALSE;
+ AddressFile->ErrorHandler = TdiDefaultErrorHandler;
+ AddressFile->ErrorHandlerContext = NULL;
+
+ return AddressFile;
+
+} /* IpxCreateAddressFile */
+
+
+NTSTATUS
+IpxDestroyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys an address file and removes all references
+ made by it to other objects in the transport.
+
+ This routine is only called by IpxDereferenceAddressFile. The reason
+ for this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address file object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ AddressFile Pointer to a transport address file structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ CTELockHandle LockHandle, LockHandle1;
+ PADDRESS Address;
+ PDEVICE Device;
+ PREQUEST CloseRequest;
+
+ IPX_DEBUG (ADDRESS, ("Destroy address file %lx\n", AddressFile));
+
+ Address = AddressFile->Address;
+ Device = AddressFile->Device;
+
+ if (Address) {
+
+ //
+ // This addressfile was associated with an address.
+ //
+
+ CTEGetLock (&Address->Lock, &LockHandle);
+
+ //
+ // remove this addressfile from the address list and disassociate it from
+ // the file handle.
+ //
+
+ RemoveEntryList (&AddressFile->Linkage);
+ InitializeListHead (&AddressFile->Linkage);
+
+ if (Address->AddressFileDatabase.Flink == &Address->AddressFileDatabase) {
+
+ //
+ // This is the last open of this address, it will close
+ // due to normal dereferencing but we have to set the
+ // CLOSING flag too to stop further references.
+ //
+
+ CTEGetLock (&Device->Lock, &LockHandle1);
+ Address->Stopping = TRUE;
+ if (Device->LastAddress == Address) {
+ Device->LastAddress = NULL;
+ }
+ CTEFreeLock (&Device->Lock, LockHandle1);
+
+ }
+
+ AddressFile->Address = NULL;
+
+#ifdef ISN_NT
+ AddressFile->FileObject->FsContext = NULL;
+ AddressFile->FileObject->FsContext2 = NULL;
+#endif
+
+ CTEFreeLock (&Address->Lock, LockHandle);
+
+ //
+ // We will already have been removed from the ShareAccess
+ // of the owning address.
+ //
+
+ //
+ // Now dereference the owning address.
+ //
+
+ IpxDereferenceAddress (Address, AREF_ADDRESS_FILE);
+
+ }
+
+ //
+ // Save this for later completion.
+ //
+
+ CloseRequest = AddressFile->CloseRequest;
+
+ //
+ // return the addressFile to the pool of address files
+ //
+
+ IpxFreeMemory (AddressFile, sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile");
+
+ if (CloseRequest != (PREQUEST)NULL) {
+ REQUEST_INFORMATION(CloseRequest) = 0;
+ REQUEST_STATUS(CloseRequest) = STATUS_SUCCESS;
+ IpxCompleteRequest (CloseRequest);
+ IpxFreeRequest (Device, CloseRequest);
+ }
+
+ return STATUS_SUCCESS;
+
+} /* IpxDestroyAddressFile */
+
+
+#if DBG
+VOID
+IpxRefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)IPX_ADD_ULONG (
+ &AddressFile->ReferenceCount,
+ 1,
+ AddressFile->AddressLock);
+
+} /* IpxRefAddressFile */
+
+
+VOID
+IpxRefAddressFileLock(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+ IT IS CALLED WITH THE ADDRESS LOCK HELD.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+ //++AddressFile->ReferenceCount;
+ (VOID)InterlockedIncrement(&AddressFile->ReferenceCount);
+
+} /* IpxRefAddressFileLock */
+
+
+VOID
+IpxRefAddressFileSync(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)IPX_ADD_ULONG (
+ &AddressFile->ReferenceCount,
+ 1,
+ AddressFile->AddressLock);
+
+} /* IpxRefAddressFileSync */
+
+
+VOID
+IpxDerefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences an address file by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IpxDestroyAddressFile to remove it from the system.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+
+ oldvalue = IPX_ADD_ULONG (
+ &AddressFile->ReferenceCount,
+ (ULONG)-1,
+ AddressFile->AddressLock);
+
+ //
+ // If we have deleted all references to this address file, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ CTEAssert (oldvalue > 0);
+
+ if (oldvalue == 1) {
+ IpxDestroyAddressFile (AddressFile);
+ }
+
+} /* IpxDerefAddressFile */
+
+
+VOID
+IpxDerefAddressFileSync(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences an address file by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IpxDestroyAddressFile to remove it from the system. This routine
+ can only be called when we are synchronized (inside an IPX_SYNC_START/
+ IPX_SYNC_END pair, with a lock held, or in an indication).
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+
+ oldvalue = IPX_ADD_ULONG (
+ &AddressFile->ReferenceCount,
+ (ULONG)-1,
+ AddressFile->AddressLock);
+
+ //
+ // If we have deleted all references to this address file, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ CTEAssert (oldvalue > 0);
+
+ if (oldvalue == 1) {
+ IpxDestroyAddressFile (AddressFile);
+ }
+
+} /* IpxDerefAddressFileSync */
+#endif
+
+
+PADDRESS
+IpxLookupAddress(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the transport addresses defined for the given
+ device context and compares them with the specified NETWORK
+ NAME values. If an exact match is found, then a pointer to the
+ ADDRESS object is returned, and as a side effect, the reference
+ count to the address object is incremented. If the address is not
+ found, then NULL is returned.
+
+ NOTE: This routine must be called with the Device
+ spinlock held.
+
+Arguments:
+
+ Device - Pointer to the device object and its extension.
+
+ Socket - The socket to look up.
+
+Return Value:
+
+ Pointer to the ADDRESS object found, or NULL if not found.
+
+--*/
+
+{
+ PADDRESS Address;
+ PLIST_ENTRY p;
+ ULONG Hash = IPX_HASH_SOCKET (Socket);
+
+ p = Device->AddressDatabases[Hash].Flink;
+
+ for (p = Device->AddressDatabases[Hash].Flink;
+ p != &Device->AddressDatabases[Hash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ if (Address->Stopping) {
+ continue;
+ }
+
+ if (Address->Socket == Socket) {
+
+ //
+ // We found the match. Bump the reference count on the address, and
+ // return a pointer to the address object for the caller to use.
+ //
+
+ IpxReferenceAddressLock (Address, AREF_LOOKUP);
+ return Address;
+
+ }
+
+ }
+
+ //
+ // The specified address was not found.
+ //
+
+ return NULL;
+
+} /* IpxLookupAddress */
+
+
+NTSTATUS
+IpxStopAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to terminate all activity on an AddressFile and
+ destroy the object. We remove every connection and datagram associated
+ with this addressfile from the address database and terminate their
+ activity. Then, if there are no other outstanding addressfiles open on
+ this address, the address will go away.
+
+Arguments:
+
+ AddressFile - pointer to the addressFile to be stopped
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the request
+ is not for a real address.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PREQUEST Request;
+ PADDRESS Address = AddressFile->Address;
+ PLIST_ENTRY p;
+ KIRQL irql;
+
+
+ IoAcquireCancelSpinLock( &irql );
+ CTEGetLock (&Address->Lock, &LockHandle);
+
+ if (AddressFile->State == ADDRESSFILE_STATE_CLOSING) {
+ CTEFreeLock (&Address->Lock, LockHandle);
+ IoReleaseCancelSpinLock( irql );
+ return STATUS_SUCCESS;
+ }
+
+
+ AddressFile->State = ADDRESSFILE_STATE_CLOSING;
+
+ while (!(IsListEmpty(&AddressFile->ReceiveDatagramQueue))) {
+
+ p = RemoveHeadList (&AddressFile->ReceiveDatagramQueue);
+ Request = LIST_ENTRY_TO_REQUEST (p);
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_NETWORK_NAME_DELETED;
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+
+ CTEFreeLock(&Address->Lock, LockHandle);
+ IoReleaseCancelSpinLock( irql );
+
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
+
+ IoAcquireCancelSpinLock( &irql );
+ CTEGetLock(&Address->Lock, &LockHandle);
+
+ }
+
+ CTEFreeLock(&Address->Lock, LockHandle);
+ IoReleaseCancelSpinLock( irql );
+
+} /* IpxStopAddressFile */
+
+
+NTSTATUS
+IpxCloseAddressFile(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to close the addressfile pointed to by a file
+ object. If there is any activity to be run down, we will run it down
+ before we terminate the addressfile. We remove every connection and
+ datagram associated with this addressfile from the address database
+ and terminate their activity. Then, if there are no other outstanding
+ addressfiles open on this address, the address will go away.
+
+Arguments:
+
+ Request - the close request.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the
+ request does not point to a real address.
+
+--*/
+
+{
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ CTELockHandle LockHandle;
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+ AddressFile->CloseRequest = Request;
+
+ //
+ // We assume that addressFile has already been verified
+ // at this point.
+ //
+
+ Address = AddressFile->Address;
+ CTEAssert (Address);
+
+ //
+ // Remove us from the access info for this address.
+ //
+
+ ExAcquireResourceExclusive (&Device->AddressResource, TRUE);
+#ifdef ISN_NT
+ IoRemoveShareAccess (AddressFile->FileObject, &Address->u.ShareAccess);
+#endif
+ ExReleaseResource (&Device->AddressResource);
+
+ //
+ // If this address file had broadcasts enabled, turn it off.
+ //
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ if (AddressFile->EnableBroadcast) {
+ AddressFile->EnableBroadcast = FALSE;
+ IpxRemoveBroadcast (Device);
+ }
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ IpxStopAddressFile (AddressFile);
+ IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ return STATUS_PENDING;
+
+} /* IpxCloseAddressFile */
+
+
diff --git a/private/ntos/tdi/isn/ipx/config.c b/private/ntos/tdi/isn/ipx/config.c
new file mode 100644
index 000000000..f5d8aefbf
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/config.c
@@ -0,0 +1,1715 @@
+/*++
+
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ config.c
+
+Abstract:
+
+ This contains all routines necessary for the support of the dynamic
+ configuration of the ISN IPX module.
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 19-Sept-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Local functions used to access the registry.
+//
+
+NTSTATUS
+IpxGetConfigValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+IpxGetBindingValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+IpxGetFrameType(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+IpxAddBind(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+IpxAddExport(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+IpxReadLinkageInformation(
+ IN PCONFIG Config
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,IpxGetConfiguration)
+#pragma alloc_text(INIT,IpxFreeConfiguration)
+
+#ifndef _PNP_POWER
+#pragma alloc_text(INIT,IpxGetConfigValue)
+#pragma alloc_text(INIT,IpxGetBindingValue)
+#pragma alloc_text(INIT,IpxGetFrameType)
+#pragma alloc_text(INIT,IpxWriteDefaultAutoDetectType)
+#endif
+
+#pragma alloc_text(INIT,IpxAddBind)
+#pragma alloc_text(INIT,IpxAddExport)
+#pragma alloc_text(INIT,IpxReadLinkageInformation)
+#endif
+
+
+
+NTSTATUS
+IpxGetConfiguration (
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath,
+ OUT PCONFIG * ConfigPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by IPX to get information from the configuration
+ management routines. We read the registry, starting at RegistryPath,
+ to get the parameters. If they don't exist, we use the defaults
+ set in ipxcnfg.h file. A list of adapters to bind to is chained
+ on to the config information.
+
+Arguments:
+
+ DriverObject - Used for logging errors.
+
+ RegistryPath - The name of IPX's node in the registry.
+
+ ConfigPtr - Returns the configuration information.
+
+Return Value:
+
+ Status - STATUS_SUCCESS if everything OK, STATUS_INSUFFICIENT_RESOURCES
+ otherwise.
+
+--*/
+
+{
+ PWSTR RegistryPathBuffer;
+ PCONFIG Config;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[CONFIG_PARAMETERS+2];
+ NTSTATUS Status;
+ ULONG Zero = 0;
+ ULONG One = 1;
+ ULONG Five = 5;
+ ULONG Eight = 8;
+ ULONG Ten = 10;
+ ULONG Fifteen = 15;
+ ULONG Fifty = 50;
+ ULONG DefaultSocketStart = 0x4000;
+ ULONG DefaultSocketEnd = 0x8000;
+ ULONG RipSegments = RIP_SEGMENTS;
+ PWSTR Parameters = L"Parameters";
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[CONFIG_PARAMETERS] = {
+ { L"DedicatedRouter", &Zero } ,
+ { L"InitDatagrams", &Ten } ,
+ { L"MaxDatagrams", &Fifty } ,
+ { L"RipAgeTime", &Five } , // minutes
+ { L"RipCount", &Five } ,
+ { L"RipTimeout", &One } , // half-second
+ { L"RipUsageTime", &Fifteen } , // minutes
+ { L"SourceRouteUsageTime", &Ten } , // minutes
+ { L"SocketUniqueness", &Eight } ,
+ { L"SocketStart", &DefaultSocketStart } ,
+ { L"SocketEnd", &DefaultSocketEnd } ,
+ { L"VirtualNetworkNumber", &Zero } ,
+ { L"MaxMemoryUsage", &Zero } ,
+ { L"RipTableSize", &RipSegments } ,
+ { L"VirtualNetworkOptional", &One } ,
+ { L"EthernetPadToEven", &One } ,
+ { L"EthernetExtraPadding", &Zero } ,
+ { L"SingleNetworkActive", &Zero } ,
+ { L"DisableDialoutSap", &Zero } ,
+ { L"DisableDialinNetbios", &One } ,
+ { L"VerifySourceAddress", &One } };
+ UINT i;
+
+
+ //
+ // Allocate memory for the main config structure.
+ //
+
+ Config = IpxAllocateMemory (sizeof(CONFIG), MEMORY_CONFIG, "Config");
+ if (Config == NULL) {
+ IpxWriteResourceErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ sizeof(CONFIG),
+ MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Config->DeviceName.Buffer = NULL;
+ InitializeListHead (&Config->BindingList);
+ Config->DriverObject = DriverObject;
+
+ //
+ // Read in the NDIS binding information.
+ //
+ // IpxReadLinkageInformation expects a null-terminated path,
+ // so we have to create one from the UNICODE_STRING.
+ //
+
+ RegistryPathBuffer = (PWSTR)IpxAllocateMemory(RegistryPath->Length + sizeof(WCHAR),
+ MEMORY_CONFIG, "RegistryPathBuffer");
+ if (RegistryPathBuffer == NULL) {
+ IpxFreeConfiguration(Config);
+ IpxWriteResourceErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ RegistryPath->Length + sizeof(WCHAR),
+ MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ RtlCopyMemory (RegistryPathBuffer, RegistryPath->Buffer, RegistryPath->Length);
+ *(PWCHAR)(((PUCHAR)RegistryPathBuffer)+RegistryPath->Length) = (WCHAR)'\0';
+
+ Config->RegistryPathBuffer = RegistryPathBuffer;
+
+ //
+ // Determine what name to export and who to bind to.
+ //
+
+ Status = IpxReadLinkageInformation (Config);
+ if (Status != STATUS_SUCCESS) {
+
+ //
+ // It logged an error if it failed.
+ //
+
+ IpxFreeConfiguration(Config);
+ return Status;
+ }
+
+ //
+ // Read the per-transport (as opposed to per-binding)
+ // parameters.
+ //
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Parameters key below IPX
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Parameters;
+
+ //
+ // 2-14) Call IpxGetConfigValue for each of the keys we
+ // care about.
+ //
+
+ for (i = 0; i < CONFIG_PARAMETERS; i++) {
+
+ QueryTable[i+1].QueryRoutine = IpxGetConfigValue;
+ QueryTable[i+1].Flags = 0;
+ QueryTable[i+1].Name = ParameterValues[i].KeyName;
+ QueryTable[i+1].EntryContext = (PVOID)i;
+ QueryTable[i+1].DefaultType = REG_DWORD;
+ QueryTable[i+1].DefaultData = (PVOID)(ParameterValues[i].DefaultValue);
+ QueryTable[i+1].DefaultLength = sizeof(ULONG);
+
+ }
+
+ //
+ // 15) Stop
+ //
+
+ QueryTable[CONFIG_PARAMETERS+1].QueryRoutine = NULL;
+ QueryTable[CONFIG_PARAMETERS+1].Flags = 0;
+ QueryTable[CONFIG_PARAMETERS+1].Name = NULL;
+
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+
+ IpxFreeConfiguration(Config);
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 905,
+ Status,
+ Parameters,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ //
+ // For PnP, we need to keep this path around
+ //
+#ifndef _PNP_POWER
+ IpxFreeMemory (RegistryPathBuffer, RegistryPath->Length + sizeof(WCHAR), MEMORY_CONFIG, "RegistryPathBuffer");
+#endif _PNP_POWER
+
+ *ConfigPtr = Config;
+
+ return STATUS_SUCCESS;
+
+} /* IpxGetConfiguration */
+
+
+VOID
+IpxFreeConfiguration (
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by IPX to get free any storage that was allocated
+ by IpxGetConfiguration in producing the specified CONFIG structure.
+
+Arguments:
+
+ Config - A pointer to the configuration information structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PBINDING_CONFIG Binding;
+
+ while (!IsListEmpty (&Config->BindingList)) {
+ p = RemoveHeadList (&Config->BindingList);
+ Binding = CONTAINING_RECORD (p, BINDING_CONFIG, Linkage);
+ IpxFreeMemory (Binding->AdapterName.Buffer, Binding->AdapterName.MaximumLength, MEMORY_CONFIG, "NameBuffer");
+ IpxFreeMemory (Binding, sizeof(BINDING_CONFIG), MEMORY_CONFIG, "Binding");
+ }
+
+ if (Config->DeviceName.Buffer) {
+ IpxFreeMemory (Config->DeviceName.Buffer, Config->DeviceName.MaximumLength, MEMORY_CONFIG, "DeviceName");
+ }
+
+ IpxFreeMemory (Config, sizeof(CONFIG), MEMORY_CONFIG, "Config");
+
+} /* IpxFreeConfiguration */
+
+
+NTSTATUS
+IpxGetConfigValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each entry in the Parameters
+ node to set the config values. The table is set up
+ so that this function will be called with correct default
+ values for keys that are not present.
+
+Arguments:
+
+ ValueName - The name of the value (ignored).
+
+ ValueType - The type of the value (REG_DWORD -- ignored).
+
+ ValueData - The data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to the CONFIG structure.
+
+ EntryContext - The index in Config->Parameters to save the value.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+
+ if ((ValueType != REG_DWORD) || (ValueLength != sizeof(ULONG))) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 904,
+ STATUS_INVALID_PARAMETER,
+ ValueName,
+ 0,
+ NULL);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IPX_DEBUG (CONFIG, ("Config parameter %d, value %lx\n",
+ (ULONG)EntryContext, *(UNALIGNED ULONG *)ValueData));
+ Config->Parameters[(ULONG)EntryContext] = *(UNALIGNED ULONG *)ValueData;
+
+ return STATUS_SUCCESS;
+
+} /* IpxGetConfigValue */
+
+
+NTSTATUS
+IpxGetBindingValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each entry in the NetConfig\DriverNN
+ node to set the per-binding values. The table is set up
+ so that this function will be called with correct default
+ values for keys that are not present.
+
+Arguments:
+
+ ValueName - The name of the value (ignored).
+
+ ValueType - The type of the value (REG_DWORD -- ignored).
+
+ ValueData - The data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to the BINDING_CONFIG structure.
+
+ EntryContext - The index in Binding->Parameters to save the value.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PBINDING_CONFIG Binding = (PBINDING_CONFIG)Context;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+
+ if ((ValueType != REG_DWORD) || (ValueLength != sizeof(ULONG))) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Binding->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 903,
+ STATUS_INVALID_PARAMETER,
+ ValueName,
+ 0,
+ NULL);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IPX_DEBUG (CONFIG, ("Binding parameter %d, value %lx\n",
+ (ULONG)EntryContext, *(UNALIGNED ULONG *)ValueData));
+ Binding->Parameters[(ULONG)EntryContext] = *(UNALIGNED ULONG *)ValueData;
+
+ return STATUS_SUCCESS;
+
+} /* IpxGetBindingValue */
+
+
+NTSTATUS
+IpxGetFrameType(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues.
+ It is called for each of the entry in the "PktType" and
+ "NetworkNumber" multi-strings for a given binding.
+
+Arguments:
+
+ ValueName - The name of the value ("PktType" or "NetworkNumber" -- ignored).
+
+ ValueType - The type of the value (REG_MULTI_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - A pointer to the BINDING_CONFIG structure.
+
+ EntryContext - A pointer to a count of multi-string entries.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PBINDING_CONFIG Binding = (PBINDING_CONFIG)Context;
+ ULONG IntegerValue;
+ PWCHAR Cur;
+ PULONG Count = (PULONG)EntryContext;
+
+ if ((ValueType != REG_SZ) ||
+ (*Count >= 4)) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Binding->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 903,
+ STATUS_INVALID_PARAMETER,
+ ValueName,
+ 0,
+ NULL);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IntegerValue = 0;
+ for (Cur = (PWCHAR)(ValueData); ; Cur++) {
+ if (*Cur >= L'0' && *Cur <= L'9') {
+ IntegerValue = (IntegerValue * 16) + (*Cur - L'0');
+ } else if (*Cur >= L'A' && *Cur <= L'F') {
+ IntegerValue = (IntegerValue * 16) + (*Cur - L'A' + 10);
+ } else if (*Cur >= L'a' && *Cur <= L'f') {
+ IntegerValue = (IntegerValue * 16) + (*Cur - L'a' + 10);
+ } else {
+ break;
+ }
+ }
+
+ if (((PWCHAR)ValueName)[0] == L'P') {
+
+ //
+ // PktType. We map arcnet to 802_3 so the code around
+ // here can assume there are only four packets type --
+ // the frame type is ignored later for arcnet.
+ //
+
+ if ((IntegerValue > ISN_FRAME_TYPE_ARCNET) &&
+ (IntegerValue != ISN_FRAME_TYPE_AUTO)) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Binding->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 903,
+ STATUS_INVALID_PARAMETER,
+ ValueName,
+ 0,
+ NULL);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IPX_DEBUG (CONFIG, ("PktType(%d) is %lx\n", *Count, IntegerValue));
+ if (IntegerValue == ISN_FRAME_TYPE_ARCNET) {
+ Binding->FrameType[*Count] = ISN_FRAME_TYPE_802_3;
+ } else {
+ Binding->FrameType[*Count] = IntegerValue;
+ }
+
+ } else {
+
+ //
+ // NetworkNumber
+ //
+
+ IPX_DEBUG (CONFIG, ("NetworkNumber(%d) is %d\n", *Count, IntegerValue));
+ Binding->NetworkNumber[*Count] = IntegerValue;
+
+ }
+
+ ++(*Count);
+
+ return STATUS_SUCCESS;
+
+} /* IpxGetFrameType */
+
+
+NTSTATUS
+IpxAddBind(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Bind" multi-string and
+ saves the information in a Config structure. It
+ also queries the per-binding information and stores it.
+
+Arguments:
+
+ ValueName - The name of the value ("Bind" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - A pointer to the Config structure.
+
+ EntryContext - A pointer to a count of binds that is incremented.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+ PBINDING_CONFIG Binding;
+ PULONG CurBindNum = ((PULONG)EntryContext);
+ RTL_QUERY_REGISTRY_TABLE QueryTable[BINDING_PARAMETERS+4];
+ ULONG FrameTypeCount, NetworkNumberCount;
+ ULONG StringLoc;
+ BOOLEAN AutoDetect;
+ ULONG AutoDetectLoc;
+ ULONG SlideCount;
+ PWCHAR NameBuffer;
+ NTSTATUS Status;
+ BOOLEAN FrameTypeUsed[ISN_FRAME_TYPE_MAX];
+ ULONG Zero = 0;
+ ULONG One = 1;
+ ULONG DefaultBindSap = 0x8137;
+ ULONG DefaultAutoDetectType = ISN_FRAME_TYPE_802_2;
+ PWSTR Subkey = L"NetConfig\\12345678901234567890"; // BUGBUG: hack
+ PWSTR ValueDataWstr = (PWSTR)ValueData;
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[BINDING_PARAMETERS] = {
+ { L"MaxPktSize", &Zero } ,
+ { L"BindSap", &DefaultBindSap } ,
+ { L"DefaultAutoDetectType", &DefaultAutoDetectType } ,
+ { L"SourceRouting", &One } ,
+ { L"SourceRouteDef", &Zero } ,
+ { L"SourceRouteBcast", &Zero } ,
+ { L"SourceRouteMcast", &Zero } ,
+ { L"EnableFuncaddr", &One } ,
+ { L"EnableWanRouter", &One } };
+ ULONG BindingPreference[ISN_FRAME_TYPE_MAX] = {
+ ISN_FRAME_TYPE_802_2,
+ ISN_FRAME_TYPE_802_3,
+ ISN_FRAME_TYPE_ETHERNET_II,
+ ISN_FRAME_TYPE_SNAP };
+
+ UINT i, j, k;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+
+
+ Binding = (PBINDING_CONFIG)IpxAllocateMemory (sizeof(BINDING_CONFIG), MEMORY_CONFIG, "Binding");
+ if (Binding == NULL) {
+ IpxWriteResourceErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ sizeof(BINDING_CONFIG),
+ MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NameBuffer = (PWCHAR)IpxAllocateMemory (ValueLength, MEMORY_CONFIG, "NameBuffer");
+ if (NameBuffer == NULL) {
+ IpxFreeMemory (Binding, sizeof(BINDING_CONFIG), MEMORY_CONFIG, "Binding");
+ IpxWriteResourceErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ ValueLength,
+ MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (NameBuffer, ValueData, ValueLength);
+ Binding->AdapterName.Buffer = NameBuffer;
+ Binding->AdapterName.Length = (USHORT)(ValueLength - sizeof(WCHAR));
+ Binding->AdapterName.MaximumLength = (USHORT)ValueLength;
+
+ Binding->DriverObject = Config->DriverObject;
+
+ FrameTypeCount = 0;
+ NetworkNumberCount = 0;
+
+ //
+ // The structure is allocated OK, insert it into the list.
+ //
+
+ InsertTailList (&Config->BindingList, &Binding->Linkage);
+ ++(*CurBindNum);
+
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the NetConfig\XXXX key below IPX
+ // (we construct the right name in Subkey,
+ // first scan back to find the \, then copy
+ // the rest over, including the final '\0').
+ //
+
+ StringLoc = (ValueLength / sizeof(WCHAR)) - 2;
+ while (ValueDataWstr[StringLoc] != L'\\') {
+ --StringLoc;
+ }
+ RtlCopyMemory(&Subkey[10], &ValueDataWstr[StringLoc+1], ValueLength - ((StringLoc+1) * sizeof(WCHAR)));
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Subkey;
+
+ //
+ // 2) Call IpxGetFrameType for each part of the
+ // "PktType" multi-string.
+ //
+
+ QueryTable[1].QueryRoutine = IpxGetFrameType;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[1].Name = L"PktType";
+ QueryTable[1].EntryContext = &FrameTypeCount;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Call IpxGetFrameType for each part of the
+ // "NetworkNumber" multi-string.
+ //
+
+ QueryTable[2].QueryRoutine = IpxGetFrameType;
+ QueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[2].Name = L"NetworkNumber";
+ QueryTable[2].EntryContext = &NetworkNumberCount;
+ QueryTable[2].DefaultType = REG_NONE;
+
+ //
+ // 4-11) Call IpxGetBindingValue for each of the keys we
+ // care about.
+ //
+
+ for (i = 0; i < BINDING_PARAMETERS; i++) {
+
+ QueryTable[i+3].QueryRoutine = IpxGetBindingValue;
+ QueryTable[i+3].Flags = 0;
+ QueryTable[i+3].Name = ParameterValues[i].KeyName;
+ QueryTable[i+3].EntryContext = (PVOID)i;
+ QueryTable[i+3].DefaultType = REG_DWORD;
+ QueryTable[i+3].DefaultData = (PVOID)(ParameterValues[i].DefaultValue);
+ QueryTable[i+3].DefaultLength = sizeof(ULONG);
+
+ }
+
+ //
+ // 12) Stop
+ //
+
+ QueryTable[BINDING_PARAMETERS+3].QueryRoutine = NULL;
+ QueryTable[BINDING_PARAMETERS+3].Flags = 0;
+ QueryTable[BINDING_PARAMETERS+3].Name = NULL;
+
+
+ IPX_DEBUG (CONFIG, ("Read bind key for %ws (%ws)\n", ValueData, Subkey));
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Binding,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+
+ //
+ // The binding will get freed during cleanup.
+ //
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 906,
+ Status,
+ Subkey,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ if (FrameTypeCount == 0) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_NO_FRAME_TYPES,
+ 907,
+ Status,
+ Subkey + 10,
+ 0,
+ NULL);
+ }
+
+ if (FrameTypeCount > NetworkNumberCount) {
+ for (i = NetworkNumberCount; i <FrameTypeCount; i++) {
+ Binding->NetworkNumber[i] = 0;
+ }
+ }
+ Binding->FrameTypeCount = FrameTypeCount;
+
+ //
+ // Go through and eliminate duplicates from the frame
+ // type array.
+ //
+
+ for (i = 0; i < Binding->FrameTypeCount; i++) {
+
+ for (j = i+1; j < Binding->FrameTypeCount; j++) {
+
+ if (Binding->FrameType[j] == Binding->FrameType[i]) {
+
+ IPX_DEBUG (CONFIG, ("Frame types %d and %d identical\n", i, j));
+
+ //
+ // A duplicate, slide everything else down.
+ //
+
+ for (k = j+1; k < Binding->FrameTypeCount; k++) {
+ Binding->FrameType[k-1] = Binding->FrameType[k];
+ Binding->NetworkNumber[k-1] = Binding->NetworkNumber[k];
+ }
+ --Binding->FrameTypeCount;
+
+ --j; // so we check whoever just moved into this spot.
+ }
+ }
+ }
+
+
+ //
+ // Mark all the explicitly configured frame types, and
+ // see if we have to auto-detect.
+ //
+
+ for (i = 0; i < 4; i++) {
+ FrameTypeUsed[i] = FALSE;
+ }
+
+ AutoDetect = FALSE;
+ for (i = 0; i < Binding->FrameTypeCount; i++) {
+ if (Binding->FrameType[i] == ISN_FRAME_TYPE_AUTO) {
+ AutoDetectLoc = i;
+ AutoDetect = TRUE;
+ } else {
+ Binding->AutoDetect[i] = FALSE;
+ Binding->DefaultAutoDetect[i] = FALSE;
+ FrameTypeUsed[Binding->FrameType[i]] = TRUE;
+ }
+ }
+
+ if (!AutoDetect) {
+ IPX_DEBUG (AUTO_DETECT, ("No bindings auto-detected\n"));
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Slide everything that is past the auto-detect point up
+ // to the end.
+ //
+
+ SlideCount = Binding->FrameTypeCount - AutoDetectLoc - 1;
+ for (j = 3; j > 3 - SlideCount; j--) {
+ Binding->FrameType[j] = Binding->FrameType[j-(3-Binding->FrameTypeCount)];
+ Binding->NetworkNumber[j] = Binding->NetworkNumber[j-(3-Binding->FrameTypeCount)];
+ Binding->AutoDetect[j] = Binding->AutoDetect[j-(3-Binding->FrameTypeCount)];
+ Binding->DefaultAutoDetect[j] = Binding->DefaultAutoDetect[j-(3-Binding->FrameTypeCount)];
+ }
+
+ //
+ // Now fill in any frame types that are not hard-coded,
+ // this will start at AutoDetectLoc and exactly fill up
+ // the gap created when we slid things up above. We
+ // first put the default auto-detect at the first spot.
+ //
+
+ if (!FrameTypeUsed[Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT]]) {
+ Binding->FrameType[AutoDetectLoc] = Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT];
+ Binding->NetworkNumber[AutoDetectLoc] = 0;
+ Binding->AutoDetect[AutoDetectLoc] = TRUE;
+ Binding->DefaultAutoDetect[AutoDetectLoc] = TRUE;
+ ++AutoDetectLoc;
+ FrameTypeUsed[Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT]] = TRUE;
+ }
+
+ //
+ // Now fill in the array, using the preference order in
+ // the BindingPreference array (this comes into effect
+ // because the first frame type in our list that we
+ // find is used).
+ //
+
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+
+ if (!FrameTypeUsed[BindingPreference[i]]) {
+ Binding->FrameType[AutoDetectLoc] = BindingPreference[i];
+ Binding->NetworkNumber[AutoDetectLoc] = 0;
+ Binding->AutoDetect[AutoDetectLoc] = TRUE;
+ Binding->DefaultAutoDetect[AutoDetectLoc] = FALSE;
+ ++AutoDetectLoc;
+ }
+ }
+
+ Binding->FrameTypeCount = ISN_FRAME_TYPE_MAX;
+
+#if DBG
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+ IPX_DEBUG (AUTO_DETECT, ("%d: type %d, net %d, auto %d\n",
+ i, Binding->FrameType[i], Binding->NetworkNumber[i], Binding->AutoDetect[i]));
+ }
+#endif
+
+ return STATUS_SUCCESS;
+
+} /* IpxAddBind */
+
+
+NTSTATUS
+IpxAddExport(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Export" multi-string. It
+ saves the first callback string in the Config structure.
+
+Arguments:
+
+ ValueName - The name of the value ("Export" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - A pointer to the Config structure.
+
+ EntryContext - A pointer to a ULONG that goes to 1 after the
+ first call to this routine (so we know to ignore other ones).
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+ PULONG ValueReadOk = ((PULONG)EntryContext);
+ PWCHAR NameBuffer;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+
+ if (*ValueReadOk == 0) {
+
+ IPX_DEBUG (CONFIG, ("Read export value %ws\n", ValueData));
+
+ NameBuffer = (PWCHAR)IpxAllocateMemory (ValueLength, MEMORY_CONFIG, "DeviceName");
+ if (NameBuffer == NULL) {
+ IpxWriteResourceErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ ValueLength,
+ MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (NameBuffer, ValueData, ValueLength);
+ Config->DeviceName.Buffer = NameBuffer;
+ Config->DeviceName.Length = (USHORT)(ValueLength - sizeof(WCHAR));
+ Config->DeviceName.MaximumLength = (USHORT)ValueLength;
+
+ //
+ // Set this to ignore any other callbacks and let the
+ // caller know we read something.
+ //
+
+ *ValueReadOk = 1;
+
+ }
+
+ return STATUS_SUCCESS;
+
+} /* IpxAddExport */
+
+
+NTSTATUS
+IpxReadLinkageInformation(
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by IPX to read its linkage information
+ from the registry.
+
+Arguments:
+
+ Config - The config structure which will have per-binding information
+ linked on to it.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[3];
+ PWSTR Subkey = L"Linkage";
+ PWSTR Bind = L"Bind";
+ PWSTR Export = L"Export";
+ ULONG ValueReadOk;
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Linkage key below IPX
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Subkey;
+
+ //
+ // 1) Call IpxAddExport for each string in "Export"
+ //
+
+ QueryTable[1].QueryRoutine = IpxAddExport;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[1].Name = Export;
+ QueryTable[1].EntryContext = (PVOID)&ValueReadOk;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 2) Stop
+ //
+
+ QueryTable[2].QueryRoutine = NULL;
+ QueryTable[2].Flags = 0;
+ QueryTable[2].Name = NULL;
+
+
+ ValueReadOk = 0;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if ((Status != STATUS_SUCCESS) || (ValueReadOk == 0)) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 901,
+ Status,
+ Export,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+#ifndef _PNP_POWER
+//
+// This will be done as and when adapters appear.
+//
+ //
+ // 1) Change to call IpxAddBind for each string in "Bind"
+ //
+
+ QueryTable[1].QueryRoutine = IpxAddBind;
+ QueryTable[1].Flags = 0; // not required
+ QueryTable[1].Name = Bind;
+ QueryTable[1].EntryContext = (PVOID)&Config->BindCount;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ Config->BindCount = 0;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ //
+ // For the moment fail if we find no bindings -- eventually when
+ // we support dynamic binding we should stick around in this case.
+ //
+
+ if ((Status != STATUS_SUCCESS) || (Config->BindCount == 0)) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 902,
+ Status,
+ Bind,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+#endif
+ return STATUS_SUCCESS;
+
+} /* IpxReadLinkageInformation */
+
+
+VOID
+IpxWriteDefaultAutoDetectType(
+ IN PUNICODE_STRING RegistryPath,
+ IN struct _ADAPTER * Adapter,
+ IN ULONG FrameType
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when we were unable to detect the default
+ auto-detect type and instead found a different one. We update
+ the "DefaultAutoDetectType" in the registry.
+
+Arguments:
+
+ RegistryPath - The name of IPX's node in the registry.
+
+ Adapter - The adapter which we auto-detected on.
+
+ FrameType - The new auto-detected value.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PWSTR FullRegistryPath;
+ PUCHAR CurRegistryPath;
+ ULONG FullRegistryPathLength;
+ ULONG AdapterNameLength;
+ WCHAR NetConfigName[] = L"\\NetConfig";
+ static PWCHAR FrameTypeNames[4] = { L"Ethernet II", L"802.3", L"802.2", L"SNAP" };
+ PWCHAR CurAdapterName;
+ NTSTATUS Status;
+
+
+ //
+ // We need to allocate a buffer which contains the registry path,
+ // followed by "NetConfig", followed by the adapter name, and
+ // then NULL-terminated.
+ //
+
+ CurAdapterName = &Adapter->AdapterName[(Adapter->AdapterNameLength/sizeof(WCHAR))-2];
+ while (*CurAdapterName != L'\\') {
+ --CurAdapterName;
+ }
+ CurAdapterName;
+ AdapterNameLength = Adapter->AdapterNameLength - ((CurAdapterName - Adapter->AdapterName) * sizeof(WCHAR)) - sizeof(WCHAR);
+
+ FullRegistryPathLength = RegistryPath->Length + sizeof(NetConfigName) + AdapterNameLength;
+
+ FullRegistryPath = (PWSTR)IpxAllocateMemory (FullRegistryPathLength, MEMORY_CONFIG, "FullRegistryPath");
+ if (FullRegistryPath == NULL) {
+ IpxWriteResourceErrorLog(
+ IpxDevice->DeviceObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ FullRegistryPathLength,
+ MEMORY_CONFIG);
+ return;
+ }
+
+ CurRegistryPath = (PUCHAR)FullRegistryPath;
+ RtlCopyMemory (CurRegistryPath, RegistryPath->Buffer, RegistryPath->Length);
+ CurRegistryPath += RegistryPath->Length;
+ RtlCopyMemory (CurRegistryPath, NetConfigName, sizeof(NetConfigName) - sizeof(WCHAR));
+ CurRegistryPath += (sizeof(NetConfigName) - sizeof(WCHAR));
+ RtlCopyMemory (CurRegistryPath, CurAdapterName, AdapterNameLength);
+ CurRegistryPath += AdapterNameLength;
+ *(PWCHAR)CurRegistryPath = L'\0';
+
+ Status = RtlWriteRegistryValue(
+ RTL_REGISTRY_ABSOLUTE,
+ FullRegistryPath,
+ L"DefaultAutoDetectType",
+ REG_DWORD,
+ &FrameType,
+ sizeof(ULONG));
+
+ IpxFreeMemory (FullRegistryPath, FullRegistryPathLength, MEMORY_CONFIG, "FullRegistryPath");
+
+ IpxWriteGeneralErrorLog(
+ IpxDevice->DeviceObject,
+ EVENT_IPX_NEW_DEFAULT_TYPE,
+ 888,
+ STATUS_SUCCESS,
+ FrameTypeNames[FrameType],
+ 0,
+ NULL);
+
+} /* IpxWriteDefaultAutoDetectType */
+
+
+#ifdef _PNP_POWER
+//
+// Vnet# and VnetOptional
+//
+#define VIRTUAL_NETWORK_PARAMETERS 2
+
+NTSTATUS
+IpxPnPGetVirtualNetworkNumber (
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by IPX to read the virtual network number
+ from the registry. This is called on appearance/disappearance of an
+ adapter from the system. We read the registry, starting at RegistryPath,
+ to get the value of the VirtualNetworkNumber parameter. If it doesn't
+ exist, we use the default set in ipxcnfg.h file.
+ Adapted from IpxGetConfiguration().
+
+Arguments:
+
+ Config - Contians the configuration information.
+
+Return Value:
+
+ Status - STATUS_SUCCESS if everything OK, STATUS_DEVICE_CONFIGURATION_ERROR
+ otherwise.
+
+--*/
+
+{
+ RTL_QUERY_REGISTRY_TABLE QueryTable[VIRTUAL_NETWORK_PARAMETERS+2];
+ NTSTATUS Status;
+ ULONG Zero = 0;
+ ULONG One = 1;
+ PWSTR Parameters = L"Parameters";
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[VIRTUAL_NETWORK_PARAMETERS] = {
+ { L"VirtualNetworkNumber", &Zero } ,
+ { L"VirtualNetworkOptional", &One } };
+ UINT i;
+
+ //
+ // Read the virtual net number from the parameters.
+ //
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Parameters key below IPX
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Parameters;
+
+ //
+ // 2) Call IpxGetConfigValue for the virtual net number key
+ //
+
+ QueryTable[1].QueryRoutine = IpxGetConfigValue;
+ QueryTable[1].Flags = 0;
+ QueryTable[1].Name = ParameterValues[0].KeyName;
+ QueryTable[1].EntryContext = (PVOID)CONFIG_VIRTUAL_NETWORK;
+ QueryTable[1].DefaultType = REG_DWORD;
+ QueryTable[1].DefaultData = (PVOID)(ParameterValues[0].DefaultValue);
+ QueryTable[1].DefaultLength = sizeof(ULONG);
+
+ //
+ // 2) Call IpxGetConfigValue for the virtual net optional key
+ //
+
+ QueryTable[2].QueryRoutine = IpxGetConfigValue;
+ QueryTable[2].Flags = 0;
+ QueryTable[2].Name = ParameterValues[1].KeyName;
+ QueryTable[2].EntryContext = (PVOID)CONFIG_VIRTUAL_OPTIONAL;
+ QueryTable[2].DefaultType = REG_DWORD;
+ QueryTable[2].DefaultData = (PVOID)(ParameterValues[1].DefaultValue);
+ QueryTable[2].DefaultLength = sizeof(ULONG);
+
+ //
+ // 15) Stop
+ //
+
+ QueryTable[3].QueryRoutine = NULL;
+ QueryTable[3].Flags = 0;
+ QueryTable[3].Name = NULL;
+
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 905,
+ Status,
+ Parameters,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ return STATUS_SUCCESS;
+
+} /* IpxPnPGetNetworkNumber */
+
+
+NTSTATUS
+IpxPnPGetAdapterParameters(
+ IN PCONFIG Config,
+ IN PNDIS_STRING DeviceName,
+ IN OUT PBINDING_CONFIG Binding
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by IPX to read the adapter-specific parameters
+ from the registry on PnP appearance of an adapter in the system.
+ We read the registry, starting at RegistryPath\NetConfig\DeviceName.
+
+ Adapted from IpxAddBind().
+
+Arguments:
+
+ Config - Config structure - supplies the DeviceObject and RegistryPathBuffer.
+
+ DeviceName - name of the adapter that was added.
+
+ Binding - Returns the configuration information per adapter.
+
+Return Value:
+
+ Status - STATUS_SUCCESS if everything OK, STATUS_DEVICE_CONFIGURATION_ERROR
+ otherwise.
+
+--*/
+{
+ RTL_QUERY_REGISTRY_TABLE QueryTable[BINDING_PARAMETERS+4];
+ ULONG FrameTypeCount, NetworkNumberCount;
+ ULONG StringLoc;
+ BOOLEAN AutoDetect;
+ ULONG AutoDetectLoc;
+ ULONG SlideCount;
+ PWCHAR NameBuffer;
+ NTSTATUS Status;
+ BOOLEAN FrameTypeUsed[ISN_FRAME_TYPE_MAX];
+ ULONG Zero = 0;
+ ULONG One = 1;
+ ULONG DefaultBindSap = 0x8137;
+ ULONG DefaultAutoDetectType = ISN_FRAME_TYPE_802_2;
+ PWSTR Subkey = L"NetConfig\\12345678901234567890"; // BUGBUG: hack
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[BINDING_PARAMETERS] = {
+ { L"MaxPktSize", &Zero } ,
+ { L"BindSap", &DefaultBindSap } ,
+ { L"DefaultAutoDetectType", &DefaultAutoDetectType } ,
+ { L"SourceRouting", &One } ,
+ { L"SourceRouteDef", &Zero } ,
+ { L"SourceRouteBcast", &Zero } ,
+ { L"SourceRouteMcast", &Zero } ,
+ { L"EnableFuncaddr", &One } ,
+ { L"EnableWanRouter", &One } };
+ ULONG BindingPreference[ISN_FRAME_TYPE_MAX] = {
+ ISN_FRAME_TYPE_802_2,
+ ISN_FRAME_TYPE_802_3,
+ ISN_FRAME_TYPE_ETHERNET_II,
+ ISN_FRAME_TYPE_SNAP };
+
+ UINT i, j, k;
+
+ FrameTypeCount = 0;
+ NetworkNumberCount = 0;
+
+ //
+ // The structure is allocated OK, insert it into the list.
+ //
+
+// InsertTailList (&Config->BindingList, &Binding->Linkage);
+// ++(*CurBindNum);
+
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the NetConfig\XXXX key below IPX
+ // (we construct the right name in Subkey,
+ // first scan back to find the \, then copy
+ // the rest over, including the final '\0').
+ //
+ StringLoc = (DeviceName->MaximumLength / sizeof(WCHAR)) - 2;
+ while (DeviceName->Buffer[StringLoc] != L'\\') {
+ --StringLoc;
+ }
+ RtlCopyMemory(&Subkey[10], &DeviceName->Buffer[StringLoc+1], DeviceName->MaximumLength - ((StringLoc+1) * sizeof(WCHAR)));
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Subkey;
+
+ //
+ // 2) Call IpxGetFrameType for each part of the
+ // "PktType" multi-string.
+ //
+
+ QueryTable[1].QueryRoutine = IpxGetFrameType;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[1].Name = L"PktType";
+ QueryTable[1].EntryContext = &FrameTypeCount;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Call IpxGetFrameType for each part of the
+ // "NetworkNumber" multi-string.
+ //
+
+ QueryTable[2].QueryRoutine = IpxGetFrameType;
+ QueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[2].Name = L"NetworkNumber";
+ QueryTable[2].EntryContext = &NetworkNumberCount;
+ QueryTable[2].DefaultType = REG_NONE;
+
+ //
+ // 4-11) Call IpxGetBindingValue for each of the keys we
+ // care about.
+ //
+
+ for (i = 0; i < BINDING_PARAMETERS; i++) {
+
+ QueryTable[i+3].QueryRoutine = IpxGetBindingValue;
+ QueryTable[i+3].Flags = 0;
+ QueryTable[i+3].Name = ParameterValues[i].KeyName;
+ QueryTable[i+3].EntryContext = (PVOID)i;
+ QueryTable[i+3].DefaultType = REG_DWORD;
+ QueryTable[i+3].DefaultData = (PVOID)(ParameterValues[i].DefaultValue);
+ QueryTable[i+3].DefaultLength = sizeof(ULONG);
+
+ }
+
+ //
+ // 12) Stop
+ //
+
+ QueryTable[BINDING_PARAMETERS+3].QueryRoutine = NULL;
+ QueryTable[BINDING_PARAMETERS+3].Flags = 0;
+ QueryTable[BINDING_PARAMETERS+3].Name = NULL;
+
+
+ IPX_DEBUG (CONFIG, ("Read bind key for %ws (%ws)\n", DeviceName->Buffer, Subkey));
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Binding,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+
+ //
+ // The binding will get freed during cleanup.
+ //
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 906,
+ Status,
+ Subkey,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ if (FrameTypeCount == 0) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_NO_FRAME_TYPES,
+ 907,
+ Status,
+ Subkey + 10,
+ 0,
+ NULL);
+ }
+
+ if (FrameTypeCount > NetworkNumberCount) {
+ for (i = NetworkNumberCount; i <FrameTypeCount; i++) {
+ Binding->NetworkNumber[i] = 0;
+ }
+ }
+ Binding->FrameTypeCount = FrameTypeCount;
+
+ //
+ // Go through and eliminate duplicates from the frame
+ // type array.
+ //
+
+ for (i = 0; i < Binding->FrameTypeCount; i++) {
+
+ for (j = i+1; j < Binding->FrameTypeCount; j++) {
+
+ if (Binding->FrameType[j] == Binding->FrameType[i]) {
+
+ IPX_DEBUG (CONFIG, ("Frame types %d and %d identical\n", i, j));
+
+ //
+ // A duplicate, slide everything else down.
+ //
+
+ for (k = j+1; k < Binding->FrameTypeCount; k++) {
+ Binding->FrameType[k-1] = Binding->FrameType[k];
+ Binding->NetworkNumber[k-1] = Binding->NetworkNumber[k];
+ }
+ --Binding->FrameTypeCount;
+
+ --j; // so we check whoever just moved into this spot.
+ }
+ }
+ }
+
+
+ //
+ // Mark all the explicitly configured frame types, and
+ // see if we have to auto-detect.
+ //
+
+ for (i = 0; i < 4; i++) {
+ FrameTypeUsed[i] = FALSE;
+ }
+
+ AutoDetect = FALSE;
+ for (i = 0; i < Binding->FrameTypeCount; i++) {
+ if ((Binding->FrameType[i] == ISN_FRAME_TYPE_AUTO)) {
+ AutoDetectLoc = i;
+ AutoDetect = TRUE;
+ } else {
+ Binding->AutoDetect[i] = FALSE;
+ Binding->DefaultAutoDetect[i] = FALSE;
+ FrameTypeUsed[Binding->FrameType[i]] = TRUE;
+ }
+ }
+
+ if (!AutoDetect) {
+ IPX_DEBUG (AUTO_DETECT, ("No bindings auto-detected\n"));
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Slide everything that is past the auto-detect point up
+ // to the end.
+ //
+
+ //
+ // Fixed this loop which can spill over if the FrameTypeCount is 4 and the SlideCount > 0.
+ // Here, the FrameTypeCount is 1-based, whereas the indices are 0-based, we need to make
+ // the index 1-based for this to work. So, instead of (3-Binding->FrameTypeCount), we use
+ // (4-Binding->FrameTypeCount). This loop copies all the non-auto-detect frametypes down to
+ // the bottom of the array to make space after the last auto-detect frame-type for filling
+ // in the frametypes in the preference order.
+ //
+#if 0
+ SlideCount = Binding->FrameTypeCount - AutoDetectLoc - 1;
+ for (j = 3; j > 3 - SlideCount; j--) {
+ Binding->FrameType[j] = Binding->FrameType[j-(3-Binding->FrameTypeCount)];
+ Binding->NetworkNumber[j] = Binding->NetworkNumber[j-(3-Binding->FrameTypeCount)];
+ Binding->AutoDetect[j] = Binding->AutoDetect[j-(3-Binding->FrameTypeCount)];
+ Binding->DefaultAutoDetect[j] = Binding->DefaultAutoDetect[j-(3-Binding->FrameTypeCount)];
+ }
+#else
+ SlideCount = Binding->FrameTypeCount - AutoDetectLoc - 1;
+ for (j = 3; j > 3 - SlideCount; j--) {
+ Binding->FrameType[j] = Binding->FrameType[j-(4-Binding->FrameTypeCount)];
+ Binding->NetworkNumber[j] = Binding->NetworkNumber[j-(4-Binding->FrameTypeCount)];
+ Binding->AutoDetect[j] = Binding->AutoDetect[j-(4-Binding->FrameTypeCount)];
+ Binding->DefaultAutoDetect[j] = Binding->DefaultAutoDetect[j-(4-Binding->FrameTypeCount)];
+ }
+#endif
+
+ //
+ // Now fill in any frame types that are not hard-coded,
+ // this will start at AutoDetectLoc and exactly fill up
+ // the gap created when we slid things up above. We
+ // first put the default auto-detect at the first spot.
+ //
+
+ if (!FrameTypeUsed[Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT]]) {
+ Binding->FrameType[AutoDetectLoc] = Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT];
+ Binding->NetworkNumber[AutoDetectLoc] = 0;
+ Binding->AutoDetect[AutoDetectLoc] = TRUE;
+ Binding->DefaultAutoDetect[AutoDetectLoc] = TRUE;
+ ++AutoDetectLoc;
+ FrameTypeUsed[Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT]] = TRUE;
+ }
+
+ //
+ // Now fill in the array, using the preference order in
+ // the BindingPreference array (this comes into effect
+ // because the first frame type in our list that we
+ // find is used).
+ //
+
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+
+ if (!FrameTypeUsed[BindingPreference[i]]) {
+ Binding->FrameType[AutoDetectLoc] = BindingPreference[i];
+ Binding->NetworkNumber[AutoDetectLoc] = 0;
+ Binding->AutoDetect[AutoDetectLoc] = TRUE;
+ Binding->DefaultAutoDetect[AutoDetectLoc] = FALSE;
+ ++AutoDetectLoc;
+ }
+ }
+
+ Binding->FrameTypeCount = ISN_FRAME_TYPE_MAX;
+
+#if DBG
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+ IPX_DEBUG (AUTO_DETECT, ("%d: type %d, net %d, auto %d\n",
+ i, Binding->FrameType[i], Binding->NetworkNumber[i], Binding->AutoDetect[i]));
+ }
+#endif
+
+ return STATUS_SUCCESS;
+} /* IpxPnPGetAdapterParameters */
+
+#endif _PNP_POWER
+
diff --git a/private/ntos/tdi/isn/ipx/config.h b/private/ntos/tdi/isn/ipx/config.h
new file mode 100644
index 000000000..ba6e76d83
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/config.h
@@ -0,0 +1,132 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ config.h
+
+Abstract:
+
+ Private include file for the ISN IPX module.
+ file defines all constants and structures necessary for support of
+ the dynamic configuration of ST.
+
+Revision History:
+
+--*/
+
+
+//
+// These are used to index into the Parameters array in CONFIG.
+//
+
+#define CONFIG_DEDICATED_ROUTER 0
+#define CONFIG_INIT_DATAGRAMS 1
+#define CONFIG_MAX_DATAGRAMS 2
+#define CONFIG_RIP_AGE_TIME 3
+#define CONFIG_RIP_COUNT 4
+#define CONFIG_RIP_TIMEOUT 5
+#define CONFIG_RIP_USAGE_TIME 6
+#define CONFIG_ROUTE_USAGE_TIME 7
+#define CONFIG_SOCKET_UNIQUENESS 8
+#define CONFIG_SOCKET_START 9
+#define CONFIG_SOCKET_END 10
+#define CONFIG_VIRTUAL_NETWORK 11
+#define CONFIG_MAX_MEMORY_USAGE 12
+#define CONFIG_RIP_TABLE_SIZE 13
+#define CONFIG_VIRTUAL_OPTIONAL 14
+#define CONFIG_ETHERNET_PAD 15
+#define CONFIG_ETHERNET_LENGTH 16
+#define CONFIG_SINGLE_NETWORK 17
+#define CONFIG_DISABLE_DIALOUT_SAP 18
+#define CONFIG_DISABLE_DIALIN_NB 19
+#define CONFIG_VERIFY_SOURCE_ADDRESS 20
+
+#define CONFIG_PARAMETERS 21
+
+//
+// Main configuration structure.
+//
+
+typedef struct _CONFIG {
+
+ ULONG Parameters[CONFIG_PARAMETERS]; // index defined above
+ NDIS_STRING DeviceName; // device name exported
+ PWSTR RegistryPathBuffer; // path to config info
+ ULONG BindCount; // entries in BindingList
+ LIST_ENTRY BindingList; // one per binding
+ PDRIVER_OBJECT DriverObject; // used for logging errors
+
+} CONFIG, * PCONFIG;
+
+
+//
+// These are used to index into the Parameters array in BINDING_CONFIG.
+//
+
+#define BINDING_MAX_PKT_SIZE 0
+#define BINDING_BIND_SAP 1
+#define BINDING_DEFAULT_AUTO_DETECT 2
+#define BINDING_SOURCE_ROUTE 3
+#define BINDING_ALL_ROUTE_DEF 4
+#define BINDING_ALL_ROUTE_BC 5
+#define BINDING_ALL_ROUTE_MC 6
+#define BINDING_ENABLE_FUNC_ADDR 7
+#define BINDING_ENABLE_WAN 8
+
+#define BINDING_PARAMETERS 9
+
+
+//
+// One of these is allocated per adapter we are to bind to.
+//
+
+typedef struct _BINDING_CONFIG {
+
+ LIST_ENTRY Linkage; // for chaining on BindingList
+ NDIS_STRING AdapterName; // NDIS adapter to bind to
+ ULONG FrameTypeCount; // number of frame types defined (max. 4)
+ // == number of valid entries in arrays:
+ ULONG FrameType[ISN_FRAME_TYPE_MAX]; // ISN_FRAME_TYPE_XXX
+ ULONG NetworkNumber[ISN_FRAME_TYPE_MAX]; // may be 0
+ BOOLEAN AutoDetect[ISN_FRAME_TYPE_MAX]; // remove if net number can't be found
+ BOOLEAN DefaultAutoDetect[ISN_FRAME_TYPE_MAX]; // use this if multiple or none found
+ ULONG Parameters[BINDING_PARAMETERS]; // index defined above
+ PDRIVER_OBJECT DriverObject; // used for logging errors
+
+} BINDING_CONFIG, * PBINDING_CONFIG;
+
+
+NTSTATUS
+IpxGetConfiguration (
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath,
+ OUT PCONFIG * ConfigPtr
+ );
+
+VOID
+IpxFreeConfiguration (
+ IN PCONFIG Config
+ );
+
+VOID
+IpxWriteDefaultAutoDetectType(
+ IN PUNICODE_STRING RegistryPath,
+ IN struct _ADAPTER * Adapter,
+ IN ULONG FrameType
+ );
+
+#ifdef _PNP_POWER
+NTSTATUS
+IpxPnPGetVirtualNetworkNumber (
+ IN PCONFIG Config
+ );
+
+NTSTATUS
+IpxPnPGetAdapterParameters(
+ IN PCONFIG Config,
+ IN PNDIS_STRING DeviceName,
+ IN OUT PBINDING_CONFIG Binding
+ );
+#endif _PNP_POWER
diff --git a/private/ntos/tdi/isn/ipx/device.c b/private/ntos/tdi/isn/ipx/device.c
new file mode 100644
index 000000000..f6cb2d302
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/device.c
@@ -0,0 +1,612 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ device.c
+
+Abstract:
+
+ This module contains code which implements the DEVICE_CONTEXT object.
+ Routines are provided to reference, and dereference transport device
+ context objects.
+
+ The transport device context object is a structure which contains a
+ system-defined DEVICE_OBJECT followed by information which is maintained
+ by the transport provider, called the context.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,IpxCreateDevice)
+#endif
+
+
+
+VOID
+IpxRefDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a device context.
+
+Arguments:
+
+ Device - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ CTEAssert (Device->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement(&Device->ReferenceCount);
+
+} /* IpxRefDevice */
+
+
+VOID
+IpxDerefDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a device context by decrementing the
+ reference count contained in the structure. Currently, we don't
+ do anything special when the reference count drops to zero, but
+ we could dynamically unload stuff then.
+
+Arguments:
+
+ Device - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&Device->ReferenceCount);
+
+ CTEAssert (result >= 0);
+
+ if (result == 0) {
+ IpxDestroyDevice (Device);
+ }
+
+} /* IpxDerefDevice */
+
+
+NTSTATUS
+IpxCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN ULONG SegmentCount,
+ IN OUT PDEVICE *DevicePtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates and initializes a device context structure.
+
+Arguments:
+
+
+ DriverObject - pointer to the IO subsystem supplied driver object.
+
+ Device - Pointer to a pointer to a transport device context object.
+
+ SegmentCount - The number of segments in the RIP router table.
+
+ DeviceName - pointer to the name of the device this device object points to.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
+
+--*/
+
+{
+ NTSTATUS status;
+ PDEVICE_OBJECT deviceObject;
+ PDEVICE Device;
+ ULONG DeviceSize;
+ ULONG LocksOffset;
+ ULONG SegmentsOffset;
+ ULONG DeviceNameOffset;
+ UINT i;
+
+
+ //
+ // Create the device object for the sample transport, allowing
+ // room at the end for the device name to be stored (for use
+ // in logging errors) and the RIP fields.
+ //
+
+ DeviceSize = sizeof(DEVICE) +
+ (sizeof(CTELock) * SegmentCount) +
+ (sizeof(ROUTER_SEGMENT) * SegmentCount) +
+ DeviceName->Length + sizeof(UNICODE_NULL);
+
+ status = IoCreateDevice(
+ DriverObject,
+ DeviceSize,
+ DeviceName,
+ FILE_DEVICE_TRANSPORT,
+ 0,
+ FALSE,
+ &deviceObject);
+
+ if (!NT_SUCCESS(status)) {
+ IPX_DEBUG(DEVICE, ("Create device %ws failed %lx\n", DeviceName->Buffer, status));
+ return status;
+ }
+
+ deviceObject->Flags |= DO_DIRECT_IO;
+
+ Device = (PDEVICE)deviceObject->DeviceExtension;
+
+ IPX_DEBUG(DEVICE, ("Create device %ws succeeded %lx\n", DeviceName->Buffer));
+
+ //
+ // Initialize our part of the device context.
+ //
+
+ RtlZeroMemory(
+ ((PUCHAR)Device) + sizeof(DEVICE_OBJECT),
+ sizeof(DEVICE) - sizeof(DEVICE_OBJECT));
+
+ Device->DeviceObject = deviceObject;
+
+ LocksOffset = sizeof(DEVICE);
+ SegmentsOffset = LocksOffset + (sizeof(CTELock) * SegmentCount);
+ DeviceNameOffset = SegmentsOffset + (sizeof(ROUTER_SEGMENT) * SegmentCount);
+
+ //
+ // Set some internal pointers.
+ //
+
+ Device->SegmentLocks = (CTELock *)(((PUCHAR)Device) + LocksOffset);
+ Device->Segments = (PROUTER_SEGMENT)(((PUCHAR)Device) + SegmentsOffset);
+ Device->SegmentCount = SegmentCount;
+
+ for (i = 0; i < SegmentCount; i++) {
+
+ CTEInitLock (&Device->SegmentLocks[i]);
+ InitializeListHead (&Device->Segments[i].WaitingForRoute);
+ InitializeListHead (&Device->Segments[i].FindWaitingForRoute);
+ InitializeListHead (&Device->Segments[i].WaitingLocalTarget);
+ InitializeListHead (&Device->Segments[i].WaitingReripNetnum);
+ InitializeListHead (&Device->Segments[i].Entries);
+ Device->Segments[i].EnumerateLocation = &Device->Segments[i].Entries;
+
+ }
+
+ //
+ // Copy over the device name.
+ //
+
+ Device->DeviceNameLength = DeviceName->Length + sizeof(WCHAR);
+ Device->DeviceName = (PWCHAR)(((PUCHAR)Device) + DeviceNameOffset);
+ RtlCopyMemory(
+ Device->DeviceName,
+ DeviceName->Buffer,
+ DeviceName->Length);
+ Device->DeviceName[DeviceName->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ //
+ // Initialize the reference count.
+ //
+
+ Device->ReferenceCount = 1;
+#if DBG
+ Device->RefTypes[DREF_CREATE] = 1;
+#endif
+
+#if DBG
+ RtlCopyMemory(Device->Signature1, "IDC1", 4);
+ RtlCopyMemory(Device->Signature2, "IDC2", 4);
+#endif
+
+ Device->Information.Version = 0x0100;
+ Device->Information.MaxSendSize = 0; // no sends allowed
+ Device->Information.MaxConnectionUserData = 0;
+ Device->Information.ServiceFlags =
+ TDI_SERVICE_CONNECTIONLESS_MODE | TDI_SERVICE_BROADCAST_SUPPORTED |
+ TDI_SERVICE_ROUTE_DIRECTED;
+ Device->Information.MinimumLookaheadData = 128;
+ Device->Information.NumberOfResources = IPX_TDI_RESOURCES;
+ KeQuerySystemTime (&Device->Information.StartTime);
+
+ Device->Statistics.Version = 0x0100;
+
+#if 0
+ //
+ // These will be filled in after all the binding is done.
+ //
+
+ Device->Information.MaxDatagramSize = 0;
+ Device->Information.MaximumLookaheadData = 0;
+
+
+ Device->SourceRoutingUsed = FALSE;
+ Device->SourceRoutingTime = 0;
+ Device->RipPacketCount = 0;
+
+ Device->RipShortTimerActive = FALSE;
+ Device->RipSendTime = 0;
+#endif
+
+
+ //
+ // Initialize the resource that guards address ACLs.
+ //
+
+ ExInitializeResource (&Device->AddressResource);
+
+#ifdef _PNP_POWER
+ //
+ // Init the resource that guards the binding array/indices
+ //
+ CTEInitLock (&Device->BindAccessLock);
+#endif _PNP_POWER
+
+ InitializeListHead (&Device->WaitingRipPackets);
+ CTEInitTimer (&Device->RipShortTimer);
+ CTEInitTimer (&Device->RipLongTimer);
+
+ CTEInitTimer (&Device->SourceRoutingTimer);
+
+ //
+ // [FW] Initialize the timer used to update inactivity counters
+ // on WAN lines.
+ //
+ CTEInitTimer (&Device->WanInactivityTimer);
+
+ //
+ // initialize the various fields in the device context
+ //
+
+ CTEInitLock (&Device->Interlock);
+ CTEInitLock (&Device->Lock);
+ CTEInitLock (&Device->SListsLock);
+
+ Device->ControlChannelIdentifier.QuadPart = 1;
+
+ InitializeListHead (&Device->GlobalSendPacketList);
+ InitializeListHead (&Device->GlobalReceivePacketList);
+ InitializeListHead (&Device->GlobalReceiveBufferList);
+#if BACK_FILL
+ InitializeListHead (&Device->GlobalBackFillPacketList);
+#endif
+
+ InitializeListHead (&Device->AddressNotifyQueue);
+ InitializeListHead (&Device->LineChangeQueue);
+
+ for (i = 0; i < IPX_ADDRESS_HASH_COUNT; i++) {
+ InitializeListHead (&Device->AddressDatabases[i]);
+ }
+
+#if BACK_FILL
+ InitializeListHead (&Device->BackFillPoolList);
+#endif
+ InitializeListHead (&Device->SendPoolList);
+ InitializeListHead (&Device->ReceivePoolList);
+
+#ifdef _PNP_POWER
+ InitializeListHead (&Device->BindingPoolList);
+#endif
+
+ ExInitializeSListHead (&Device->SendPacketList);
+ ExInitializeSListHead (&Device->ReceivePacketList);
+#if BACK_FILL
+ ExInitializeSListHead (&Device->BackFillPacketList);
+#endif
+
+#ifdef _PNP_POWER
+ ExInitializeSListHead (&Device->BindingList);
+#endif
+
+#if 0
+ Device->MemoryUsage = 0;
+ Device->SendPacketList.Next = NULL;
+ Device->ReceivePacketList.Next = NULL;
+ Device->Bindings = NULL;
+ Device->BindingCount = 0;
+#endif
+
+ KeQuerySystemTime (&Device->IpxStartTime);
+
+ Device->State = DEVICE_STATE_CLOSED;
+ Device->AutoDetectState = AUTO_DETECT_STATE_INIT;
+
+ Device->Type = IPX_DEVICE_SIGNATURE;
+ Device->Size = sizeof (DEVICE);
+
+#ifdef SNMP
+ //
+ // BUGBUGZZ: what are the values for these?
+ //
+ IPX_MIB_ENTRY(Device, SysInstance) = 0;
+ IPX_MIB_ENTRY(Device, SysExistState) = 0;
+#endif SNMP
+
+ *DevicePtr = Device;
+ return STATUS_SUCCESS;
+
+} /* IpxCreateDevice */
+
+
+VOID
+IpxDestroyDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a device context structure.
+
+Arguments:
+
+ Device - Pointer to a pointer to a transport device context object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY s;
+ PIPX_SEND_POOL SendPool;
+ PIPX_SEND_PACKET SendPacket;
+ PIPX_RECEIVE_POOL ReceivePool;
+ PIPX_RECEIVE_PACKET ReceivePacket;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ UINT SendPoolSize;
+ UINT ReceivePoolSize;
+ UINT i;
+#if BACK_FILL
+ PIPX_SEND_POOL BackFillPool;
+ UINT BackFillPoolSize;
+ PIPX_SEND_PACKET BackFillPacket;
+#endif
+
+#ifdef _PNP_POWER
+ PIPX_BINDING_POOL BindingPool;
+ UINT BindingPoolSize;
+ PBINDING Binding;
+#endif
+
+ IPX_DEBUG (DEVICE, ("Destroy device %lx\n", Device));
+
+ //
+ // Take all the packets out of its pools.
+ //
+
+#if _PNP_POWER
+ BindingPoolSize = FIELD_OFFSET (IPX_BINDING_POOL, Bindings[0]) +
+ (sizeof(BINDING) * Device->InitBindings);
+
+ while (!IsListEmpty (&Device->BindingPoolList)) {
+
+ p = RemoveHeadList (&Device->BindingPoolList);
+ BindingPool = CONTAINING_RECORD (p, IPX_BINDING_POOL, Linkage);
+ IPX_DEBUG (PACKET, ("Free binding pool %lx\n", BindingPool));
+ IpxFreeMemory (BindingPool, BindingPoolSize, MEMORY_PACKET, "BindingPool");
+
+ }
+#endif
+
+#ifdef IPX_OWN_PACKETS
+
+#if BACK_FILL
+ BackFillPoolSize = FIELD_OFFSET (IPX_SEND_POOL, Packets[0]) +
+ (sizeof(IPX_SEND_PACKET) * Device->InitDatagrams);
+ while (!IsListEmpty (&Device->BackFillPoolList)) {
+
+ p = RemoveHeadList (&Device->BackFillPoolList);
+ BackFillPool = CONTAINING_RECORD (p, IPX_SEND_POOL, Linkage);
+
+ for (i = 0; i < BackFillPool->PacketCount; i++) {
+ BackFillPacket = &BackFillPool->Packets[i];
+ IpxDeinitializeBackFillPacket (Device, BackFillPacket);
+ }
+
+ IPX_DEBUG (PACKET, ("Free packet pool %lx\n", BackFillPool));
+ IpxFreeMemory (BackFillPool, BackFillPoolSize, MEMORY_PACKET, "BackPool");
+ }
+#endif
+
+ SendPoolSize = FIELD_OFFSET (IPX_SEND_POOL, Packets[0]) +
+ (sizeof(IPX_SEND_PACKET) * Device->InitDatagrams) +
+ (((IPX_MAXIMUM_MAC + sizeof(IPX_HEADER) + 3) & ~3) * Device->InitDatagrams);
+
+ while (!IsListEmpty (&Device->SendPoolList)) {
+
+ p = RemoveHeadList (&Device->SendPoolList);
+ SendPool = CONTAINING_RECORD (p, IPX_SEND_POOL, Linkage);
+
+ for (i = 0; i < SendPool->PacketCount; i++) {
+
+ SendPacket = &SendPool->Packets[i];
+ IpxDeinitializeSendPacket (Device, SendPacket);
+
+ }
+
+ IPX_DEBUG (PACKET, ("Free packet pool %lx\n", SendPool));
+ IpxFreeMemory (SendPool, SendPoolSize, MEMORY_PACKET, "SendPool");
+ }
+
+ ReceivePoolSize = FIELD_OFFSET (IPX_RECEIVE_POOL, Packets[0]) +
+ (sizeof(IPX_RECEIVE_PACKET) * Device->InitReceivePackets);
+
+ while (!IsListEmpty (&Device->ReceivePoolList)) {
+
+ p = RemoveHeadList (&Device->ReceivePoolList);
+ ReceivePool = CONTAINING_RECORD (p, IPX_RECEIVE_POOL, Linkage);
+
+ for (i = 0; i < ReceivePool->PacketCount; i++) {
+
+ ReceivePacket = &ReceivePool->Packets[i];
+ IpxDeinitializeReceivePacket (Device, ReceivePacket);
+
+ }
+
+ IPX_DEBUG (PACKET, ("Free receive packet pool %lx\n", ReceivePool));
+ IpxFreeMemory (ReceivePool, ReceivePoolSize, MEMORY_PACKET, "ReceivePool");
+ }
+#else
+
+#if BACK_FILL
+
+ while (s = IPX_POP_ENTRY_LIST(&Device->BackFillPacketList, &Device->Lock)) {
+ PIPX_SEND_RESERVED Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+ IPX_SEND_PACKET BackFillPacket;
+
+ BackFillPacket.Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ IpxDeinitializeBackFillPacket (Device, &BackFillPacket);
+ Device->MemoryUsage -= (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_SEND_RESERVED));
+ }
+
+ while (!IsListEmpty (&Device->BackFillPoolList)) {
+
+ p = RemoveHeadList (&Device->BackFillPoolList);
+ BackFillPool = CONTAINING_RECORD (p, IPX_SEND_POOL, Linkage);
+
+ IPX_DEBUG (PACKET, ("Free packet pool %lx\n", BackFillPool));
+ NdisFreePacketPool (BackFillPool->PoolHandle);
+ Device->MemoryUsage -= FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]);
+
+ IpxFreeMemory (BackFillPool, sizeof(IPX_SEND_POOL), MEMORY_PACKET, "BafiPool");
+ }
+#endif
+
+ while (s = IPX_POP_ENTRY_LIST(&Device->SendPacketList, &Device->Lock)){
+ PIPX_SEND_RESERVED Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+ IPX_SEND_PACKET SendPacket;
+ PUCHAR Header = Reserved->Header;
+
+ SendPacket.Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ IpxDeinitializeSendPacket (Device, &SendPacket);
+ Device->MemoryUsage -= (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_SEND_RESERVED));
+ }
+
+ while (!IsListEmpty (&Device->SendPoolList)) {
+
+ p = RemoveHeadList (&Device->SendPoolList);
+ SendPool = CONTAINING_RECORD (p, IPX_SEND_POOL, Linkage);
+
+ IPX_DEBUG (PACKET, ("Free packet pool %lx\n", SendPool));
+ NdisFreePacketPool (SendPool->PoolHandle);
+ Device->MemoryUsage -= FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]);
+
+ IpxFreeMemory (SendPool->Header, PACKET_HEADER_SIZE * Device->InitDatagrams, MEMORY_PACKET, "SendPool");
+
+ IpxFreeMemory (SendPool, sizeof(IPX_SEND_POOL), MEMORY_PACKET, "SendPool");
+ }
+
+ while (s = IPX_POP_ENTRY_LIST(&Device->ReceivePacketList, &Device->Lock)){
+ PIPX_RECEIVE_RESERVED Reserved = CONTAINING_RECORD (s, IPX_RECEIVE_RESERVED, PoolLinkage);
+ IPX_RECEIVE_PACKET ReceivePacket;
+
+ ReceivePacket.Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ IpxDeinitializeReceivePacket (Device, &ReceivePacket);
+ Device->MemoryUsage -= (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_RECEIVE_RESERVED));
+ }
+
+ while (!IsListEmpty (&Device->ReceivePoolList)) {
+
+ p = RemoveHeadList (&Device->ReceivePoolList);
+ ReceivePool = CONTAINING_RECORD (p, IPX_RECEIVE_POOL, Linkage);
+
+ IPX_DEBUG (PACKET, ("Free packet pool %lx\n", ReceivePool));
+ NdisFreePacketPool (ReceivePool->PoolHandle);
+ Device->MemoryUsage -= FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]);
+
+ IpxFreeMemory (ReceivePool, sizeof(IPX_RECEIVE_POOL), MEMORY_PACKET, "ReceivePool");
+ }
+
+#endif IPX_OWN_PACKETS
+ //
+ // Destroy all rip table entries.
+ //
+
+ for (i = 0; i < Device->SegmentCount; i++) {
+
+ RouteEntry = RipGetFirstRoute(i);
+ while (RouteEntry != NULL) {
+
+ (VOID)RipDeleteRoute(i, RouteEntry);
+ IpxFreeMemory(RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ RouteEntry = RipGetNextRoute(i);
+
+ }
+
+ }
+
+ IPX_DEBUG (DEVICE, ("Final memory use is %d\n", Device->MemoryUsage));
+#if DBG
+ for (i = 0; i < MEMORY_MAX; i++) {
+ if (IpxMemoryTag[i].BytesAllocated != 0) {
+ IPX_DEBUG (DEVICE, ("Tag %d: %d bytes left\n", i, IpxMemoryTag[i].BytesAllocated));
+ }
+ }
+#endif
+
+ //
+ // If we are being unloaded then someone is waiting for this
+ // event to finish the cleanup, since we may be at DISPATCH_LEVEL;
+ // otherwise it is during load and we can just kill ourselves here.
+ //
+
+ if (Device->UnloadWaiting) {
+
+ KeSetEvent(
+ &Device->UnloadEvent,
+ 0L,
+ FALSE);
+
+ } else {
+
+ CTEAssert (KeGetCurrentIrql() < DISPATCH_LEVEL);
+ ExDeleteResource (&Device->AddressResource);
+ IoDeleteDevice (Device->DeviceObject);
+ }
+
+} /* IpxDestroyDevice */
+
diff --git a/private/ntos/tdi/isn/ipx/dirs b/private/ntos/tdi/isn/ipx/dirs
new file mode 100644
index 000000000..0dab2f056
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/dirs
@@ -0,0 +1,22 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=up mp
diff --git a/private/ntos/tdi/isn/ipx/driver.c b/private/ntos/tdi/isn/ipx/driver.c
new file mode 100644
index 000000000..5db05660a
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/driver.c
@@ -0,0 +1,4447 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ driver.c
+
+Abstract:
+
+ This module contains the DriverEntry and other initialization
+ code for the IPX module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+ Sanjay Anand (SanjayAn) 18-Sept-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+PDEVICE IpxDevice = NULL;
+PIPX_PADDING_BUFFER IpxPaddingBuffer = NULL;
+
+#if DBG
+
+UCHAR IpxTempDebugBuffer[150];
+ULONG IpxDebug = 0x0;
+ULONG IpxMemoryDebug = 0xffffffd3;
+UCHAR IpxDebugMemory[IPX_MEMORY_LOG_SIZE][64];
+PUCHAR IpxDebugMemoryLoc = IpxDebugMemory[0];
+PUCHAR IpxDebugMemoryEnd = IpxDebugMemory[IPX_MEMORY_LOG_SIZE];
+
+VOID
+IpxDebugMemoryLog(
+ IN PUCHAR FormatString,
+ ...
+)
+
+{
+ INT ArgLen;
+ va_list ArgumentPointer;
+
+ va_start(ArgumentPointer, FormatString);
+
+ //
+ // To avoid any overflows, copy this in a temp buffer first.
+ RtlZeroMemory (IpxTempDebugBuffer, 150);
+ ArgLen = vsprintf(IpxTempDebugBuffer, FormatString, ArgumentPointer);
+ va_end(ArgumentPointer);
+
+ if ( ArgLen > 64 ) {
+ CTEAssert( FALSE );
+ } else {
+ RtlZeroMemory (IpxDebugMemoryLoc, 64);
+ RtlCopyMemory( IpxDebugMemoryLoc, IpxTempDebugBuffer, ArgLen );
+
+ IpxDebugMemoryLoc += 64;
+ if (IpxDebugMemoryLoc >= IpxDebugMemoryEnd) {
+ IpxDebugMemoryLoc = IpxDebugMemory[0];
+ }
+ }
+}
+
+
+DEFINE_LOCK_STRUCTURE(IpxMemoryInterlock);
+MEMORY_TAG IpxMemoryTag[MEMORY_MAX];
+
+DEFINE_LOCK_STRUCTURE(IpxGlobalInterlock);
+
+#endif
+
+#if DBG
+
+//
+// Use for debug printouts
+//
+
+PUCHAR FrameTypeNames[5] = { "Ethernet II", "802.3", "802.2", "SNAP", "Arcnet" };
+#define OutputFrameType(_Binding) \
+ (((_Binding)->Adapter->MacInfo.MediumType == NdisMediumArcnet878_2) ? \
+ FrameTypeNames[4] : \
+ FrameTypeNames[(_Binding)->FrameType])
+#endif
+
+
+#ifdef IPX_PACKET_LOG
+
+ULONG IpxPacketLogDebug = IPX_PACKET_LOG_RCV_OTHER | IPX_PACKET_LOG_SEND_OTHER;
+USHORT IpxPacketLogSocket = 0;
+DEFINE_LOCK_STRUCTURE(IpxPacketLogLock);
+IPX_PACKET_LOG_ENTRY IpxPacketLog[IPX_PACKET_LOG_LENGTH];
+PIPX_PACKET_LOG_ENTRY IpxPacketLogLoc = IpxPacketLog;
+PIPX_PACKET_LOG_ENTRY IpxPacketLogEnd = &IpxPacketLog[IPX_PACKET_LOG_LENGTH];
+
+VOID
+IpxLogPacket(
+ IN BOOLEAN Send,
+ IN PUCHAR DestMac,
+ IN PUCHAR SrcMac,
+ IN USHORT Length,
+ IN PVOID IpxHeader,
+ IN PVOID Data
+ )
+
+{
+
+ CTELockHandle LockHandle;
+ PIPX_PACKET_LOG_ENTRY PacketLog;
+ LARGE_INTEGER TickCount;
+ ULONG DataLength;
+
+ CTEGetLock (&IpxPacketLogLock, &LockHandle);
+
+ PacketLog = IpxPacketLogLoc;
+
+ ++IpxPacketLogLoc;
+ if (IpxPacketLogLoc >= IpxPacketLogEnd) {
+ IpxPacketLogLoc = IpxPacketLog;
+ }
+ *(UNALIGNED ULONG *)IpxPacketLogLoc->TimeStamp = 0x3e3d3d3d; // "===>"
+
+ CTEFreeLock (&IpxPacketLogLock, LockHandle);
+
+ RtlZeroMemory (PacketLog, sizeof(IPX_PACKET_LOG_ENTRY));
+
+ PacketLog->SendReceive = Send ? '>' : '<';
+
+ KeQueryTickCount(&TickCount);
+ _itoa (TickCount.LowPart % 100000, PacketLog->TimeStamp, 10);
+
+ RtlCopyMemory(PacketLog->DestMac, DestMac, 6);
+ RtlCopyMemory(PacketLog->SrcMac, SrcMac, 6);
+ PacketLog->Length[0] = Length / 256;
+ PacketLog->Length[1] = Length % 256;
+
+ if (Length < sizeof(IPX_HEADER)) {
+ RtlCopyMemory(&PacketLog->IpxHeader, IpxHeader, Length);
+ } else {
+ RtlCopyMemory(&PacketLog->IpxHeader, IpxHeader, sizeof(IPX_HEADER));
+ }
+
+ DataLength = Length - sizeof(IPX_HEADER);
+ if (DataLength < 14) {
+ RtlCopyMemory(PacketLog->Data, Data, DataLength);
+ } else {
+ RtlCopyMemory(PacketLog->Data, Data, 14);
+ }
+
+} /* IpxLogPacket */
+
+#endif // IPX_PACKET_LOG
+
+
+//
+// Forward declaration of various routines used in this module.
+//
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+//
+// This is now shared with other modules
+//
+#ifndef _PNP_POWER
+ULONG
+IpxResolveAutoDetect(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+VOID
+IpxResolveBindingSets(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings
+ );
+
+NTSTATUS
+IpxBindToAdapter(
+ IN PDEVICE Device,
+ IN PBINDING_CONFIG ConfigAdapter,
+ IN ULONG FrameTypeIndex
+ );
+
+NTSTATUS
+IpxUnBindFromAdapter(
+ IN PBINDING Binding
+ );
+#endif _PNP_POWER
+
+VOID
+IpxUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+NTSTATUS
+IpxDispatchDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+IpxDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+IpxDispatchInternal (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,DriverEntry)
+
+//
+// These routines can be called at any time in case of PnP.
+//
+#ifndef _PNP_POWER
+#pragma alloc_text(INIT,IpxResolveAutoDetect)
+#pragma alloc_text(INIT,IpxResolveBindingSets)
+#pragma alloc_text(INIT,IpxBindToAdapter)
+#endif
+
+#endif
+
+UCHAR VirtualNode[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
+
+//
+// This prevents us from having a bss section.
+//
+
+ULONG _setjmpexused = 0;
+
+ULONG IpxFailLoad = FALSE;
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs initialization of the IPX ISN module.
+ It creates the device objects for the transport
+ provider and performs other driver initialization.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+ RegistryPath - The name of IPX's node in the registry.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ UINT SuccessfulOpens, ValidBindings;
+#ifdef _PNP_POWER
+ static const NDIS_STRING ProtocolName = NDIS_STRING_CONST("NWLNKIPX");
+#else
+ static const NDIS_STRING ProtocolName = NDIS_STRING_CONST("IPX Transport");
+#endif
+ PDEVICE Device;
+ PBINDING Binding;
+ PADAPTER Adapter;
+ ULONG BindingCount, BindingIndex;
+ PBINDING * BindingArray;
+ PLIST_ENTRY p;
+ ULONG AnnouncedMaxDatagram, RealMaxDatagram, MaxLookahead;
+ ULONG LinkSpeed, MacOptions;
+ ULONG Temp;
+ UINT i;
+ BOOLEAN CountedWan;
+
+ PCONFIG Config = NULL;
+ PBINDING_CONFIG ConfigBinding;
+
+#if 0
+ DbgPrint ("IPX: FailLoad at %lx\n", &IpxFailLoad);
+
+ if (IpxFailLoad) {
+ return STATUS_UNSUCCESSFUL;
+ }
+#endif
+
+
+ //
+ // This ordering matters because we use it to quickly
+ // determine if packets are internally generated or not.
+ //
+
+ CTEAssert (IDENTIFIER_NB < IDENTIFIER_IPX);
+ CTEAssert (IDENTIFIER_SPX < IDENTIFIER_IPX);
+ CTEAssert (IDENTIFIER_RIP < IDENTIFIER_IPX);
+ CTEAssert (IDENTIFIER_RIP_INTERNAL > IDENTIFIER_IPX);
+
+ //
+ // We assume that this structure is not packet in between
+ // the fields.
+ //
+
+ CTEAssert (FIELD_OFFSET (TDI_ADDRESS_IPX, Socket) + sizeof(USHORT) == 12);
+
+
+ //
+ // Initialize the Common Transport Environment.
+ //
+
+ if (CTEInitialize() == 0) {
+
+ IPX_DEBUG (DEVICE, ("CTEInitialize() failed\n"));
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_REGISTER_FAILED,
+ 101,
+ STATUS_UNSUCCESSFUL,
+ NULL,
+ 0,
+ NULL);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+#if DBG
+ CTEInitLock (&IpxGlobalInterlock);
+ CTEInitLock (&IpxMemoryInterlock);
+ for (i = 0; i < MEMORY_MAX; i++) {
+ IpxMemoryTag[i].Tag = i;
+ IpxMemoryTag[i].BytesAllocated = 0;
+ }
+#endif
+#ifdef IPX_PACKET_LOG
+ CTEInitLock (&IpxPacketLogLock);
+#endif
+
+#ifdef IPX_OWN_PACKETS
+ CTEAssert (NDIS_PACKET_SIZE == FIELD_OFFSET(NDIS_PACKET, ProtocolReserved[0]));
+#endif
+
+ IPX_DEBUG (DEVICE, ("IPX loaded\n"));
+
+ //
+ // This allocates the CONFIG structure and returns
+ // it in Config.
+ //
+
+ status = IpxGetConfiguration(DriverObject, RegistryPath, &Config);
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // If it failed, it logged an error.
+ //
+
+ PANIC (" Failed to initialize transport, IPX initialization failed.\n");
+ return status;
+
+ }
+
+#ifdef _PNP_POWER
+ //
+ // Initialize the TDI layer.
+ //
+ TdiInitialize();
+#endif
+
+ //
+ // make ourselves known to the NDIS wrapper.
+ //
+
+ status = IpxRegisterProtocol ((PNDIS_STRING)&ProtocolName);
+
+ if (!NT_SUCCESS (status)) {
+
+ IpxFreeConfiguration(Config);
+ PANIC ("IpxInitialize: RegisterProtocol failed!\n");
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_REGISTER_FAILED,
+ 607,
+ status,
+ NULL,
+ 0,
+ NULL);
+
+ return status;
+
+ }
+
+
+ //
+ // Initialize the driver object with this driver's entry points.
+ //
+
+ DriverObject->MajorFunction [IRP_MJ_CREATE] = IpxDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLOSE] = IpxDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLEANUP] = IpxDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL] = IpxDispatchInternal;
+ DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = IpxDispatchDeviceControl;
+
+ DriverObject->DriverUnload = IpxUnload;
+
+ SuccessfulOpens = 0;
+
+ status = IpxCreateDevice(
+ DriverObject,
+ &Config->DeviceName,
+ Config->Parameters[CONFIG_RIP_TABLE_SIZE],
+ &Device);
+
+ if (!NT_SUCCESS (status)) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_CREATE_DEVICE,
+ 801,
+ status,
+ NULL,
+ 0,
+ NULL);
+
+ IpxFreeConfiguration(Config);
+ IpxDeregisterProtocol();
+ return status;
+ }
+
+ IpxDevice = Device;
+
+
+ //
+ // Save the relevant configuration parameters.
+ //
+
+ Device->DedicatedRouter = (BOOLEAN)(Config->Parameters[CONFIG_DEDICATED_ROUTER] != 0);
+ Device->InitDatagrams = Config->Parameters[CONFIG_INIT_DATAGRAMS];
+ Device->MaxDatagrams = Config->Parameters[CONFIG_MAX_DATAGRAMS];
+ Device->RipAgeTime = Config->Parameters[CONFIG_RIP_AGE_TIME];
+ Device->RipCount = Config->Parameters[CONFIG_RIP_COUNT];
+ Device->RipTimeout =
+ ((Config->Parameters[CONFIG_RIP_TIMEOUT] * 500) + (RIP_GRANULARITY/2)) /
+ RIP_GRANULARITY;
+ Device->RipUsageTime = Config->Parameters[CONFIG_RIP_USAGE_TIME];
+ Device->SourceRouteUsageTime = Config->Parameters[CONFIG_ROUTE_USAGE_TIME];
+ Device->SocketUniqueness = Config->Parameters[CONFIG_SOCKET_UNIQUENESS];
+ Device->SocketStart = (USHORT)Config->Parameters[CONFIG_SOCKET_START];
+ Device->SocketEnd = (USHORT)Config->Parameters[CONFIG_SOCKET_END];
+ Device->MemoryLimit = Config->Parameters[CONFIG_MAX_MEMORY_USAGE];
+ Device->VerifySourceAddress = (BOOLEAN)(Config->Parameters[CONFIG_VERIFY_SOURCE_ADDRESS] != 0);
+
+ Device->InitReceivePackets = (Device->InitDatagrams + 1) / 2;
+ Device->InitReceiveBuffers = (Device->InitDatagrams + 1) / 2;
+
+ Device->MaxReceivePackets = 10; // BUGBUG: config this?
+ Device->MaxReceiveBuffers = 10;
+
+ InitializeListHead(&Device->NicNtfQueue);
+ InitializeListHead(&Device->NicNtfComplQueue);
+
+#ifdef _PNP_POWER
+ Device->InitBindings = 5; // BUGBUG: config this?
+
+ //
+ // RAS max is 240 (?) + 10 max LAN
+ //
+ Device->MaxPoolBindings = 250; // BUGBUG: config this?
+#endif
+
+#ifdef SNMP
+ IPX_MIB_ENTRY(Device, SysConfigSockets) = (Device->SocketEnd - Device->SocketStart)
+ / ((Device->SocketUniqueness > 1) ? Device->SocketUniqueness : 1);
+ ;
+#endif SNMP
+
+ //
+ // Have to reverse this.
+ //
+#ifndef _PNP_POWER
+//
+// Look at this only when the first adapter appears.
+//
+ Temp = Config->Parameters[CONFIG_VIRTUAL_NETWORK];
+ Device->VirtualNetworkNumber = REORDER_ULONG (Temp);
+#endif
+
+ Device->VirtualNetworkOptional = (BOOLEAN)(Config->Parameters[CONFIG_VIRTUAL_OPTIONAL] != 0);
+
+ Device->CurrentSocket = Device->SocketStart;
+
+ Device->EthernetPadToEven = (BOOLEAN)(Config->Parameters[CONFIG_ETHERNET_PAD] != 0);
+ Device->EthernetExtraPadding = (Config->Parameters[CONFIG_ETHERNET_LENGTH] & 0xfffffffe) + 1;
+
+ Device->SingleNetworkActive = (BOOLEAN)(Config->Parameters[CONFIG_SINGLE_NETWORK] != 0);
+ Device->DisableDialoutSap = (BOOLEAN)(Config->Parameters[CONFIG_DISABLE_DIALOUT_SAP] != 0);
+ Device->DisableDialinNetbios = (UCHAR)(Config->Parameters[CONFIG_DISABLE_DIALIN_NB]);
+
+#ifdef _PNP_POWER
+//
+// Used later to access the registry.
+//
+ Device->RegistryPathBuffer = Config->RegistryPathBuffer;
+ Device->RegistryPath.Length = RegistryPath->Length;
+ Device->RegistryPath.MaximumLength = RegistryPath->MaximumLength;
+ Device->RegistryPath.Buffer = Device->RegistryPathBuffer;
+#endif _PNP_POWER
+
+ //
+ // ActiveNetworkWan will start as FALSE, which is correct.
+ //
+
+ //
+ // Allocate our initial packet pool. We do not allocate
+ // receive and receive buffer pools until we need them,
+ // because in many cases we never do.
+ //
+
+#if BACK_FILL
+ IpxAllocateBackFillPool (Device);
+#endif
+
+ IpxAllocateSendPool (Device);
+
+#ifdef _PNP_POWER
+ IpxAllocateBindingPool (Device);
+#endif
+
+ //
+ // Allocate one 1-byte buffer for odd length packets.
+ //
+
+ IpxPaddingBuffer = IpxAllocatePaddingBuffer(Device);
+
+ if ( IpxPaddingBuffer == (PIPX_PADDING_BUFFER)NULL ) {
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 801,
+ STATUS_INSUFFICIENT_RESOURCES,
+ NULL,
+ 0,
+ NULL);
+
+ IpxFreeConfiguration(Config);
+ IpxDeregisterProtocol();
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Initialize the loopback structures
+ //
+ IpxInitLoopback();
+
+//
+// All this will be done on appearance of adapters.
+//
+
+#ifndef _PNP_POWER
+
+ //
+ // Bind to all the configured adapters.
+ //
+
+ InitializeListHead (&Device->InitialBindingList);
+
+ p = Config->BindingList.Flink;
+
+ while (p != &Config->BindingList) {
+
+ ConfigBinding = CONTAINING_RECORD (p, BINDING_CONFIG, Linkage);
+ p = p->Flink;
+
+ for (i = 0; i < ConfigBinding->FrameTypeCount; i++) {
+
+ //
+ // If successful, this queues them on Device->InitialBindingList.
+ //
+
+ status = IpxBindToAdapter (Device, ConfigBinding, i);
+
+ //
+ // If this failed because the adapter could not be bound
+ // to, then don't try any more frame types on this adapter.
+ // For other failures we do try the other frame types.
+ //
+
+ if (status == STATUS_DEVICE_DOES_NOT_EXIST) {
+ break;
+ }
+
+ if (status != STATUS_SUCCESS) {
+ continue;
+ }
+
+ if (ConfigBinding->AutoDetect[i]) {
+ Device->AutoDetect = TRUE;
+ }
+
+ ++SuccessfulOpens;
+
+ }
+
+ }
+
+
+ IpxFreeConfiguration(Config);
+
+ if (SuccessfulOpens == 0) {
+
+ IpxDereferenceDevice (Device, DREF_CREATE);
+
+ } else {
+
+ IPX_DEFINE_SYNC_CONTEXT (SyncContext);
+
+ //
+ // Allocate the device binding array and transfer those
+ // on the list to it. First count up the bindings.
+ //
+
+ BindingCount = 0;
+
+ for (p = Device->InitialBindingList.Flink;
+ p != &Device->InitialBindingList;
+ p = p->Flink) {
+
+ Binding = CONTAINING_RECORD (p, BINDING, InitialLinkage);
+ Adapter = Binding->Adapter;
+
+ if (Adapter->MacInfo.MediumAsync) {
+ Adapter->FirstWanNicId = (USHORT)(BindingCount+1);
+ Adapter->LastWanNicId = (USHORT)(BindingCount + Adapter->WanNicIdCount);
+ BindingCount += Adapter->WanNicIdCount;
+ } else {
+ ++BindingCount;
+ }
+ }
+
+ BindingArray = (PBINDING *)IpxAllocateMemory ((BindingCount+1) * sizeof(BINDING), MEMORY_BINDING, "Binding array");
+
+ if (BindingArray == NULL) {
+
+ while (!IsListEmpty (&Device->InitialBindingList)) {
+ p = RemoveHeadList (&Device->InitialBindingList);
+ Binding = CONTAINING_RECORD (p, BINDING, InitialLinkage);
+ IpxDestroyBinding (Binding);
+ }
+
+ IpxDereferenceDevice (Device, DREF_CREATE);
+ SuccessfulOpens = 0;
+ goto InitFailed;
+ }
+
+ RtlZeroMemory (BindingArray, (BindingCount+1) * sizeof(BINDING));
+
+ //
+ // Now walk the list transferring bindings to the array.
+ //
+
+ BindingIndex = 1;
+
+ for (p = Device->InitialBindingList.Flink;
+ p != &Device->InitialBindingList;
+ ) {
+
+ Binding = CONTAINING_RECORD (p, BINDING, InitialLinkage);
+
+ p = p->Flink; // we overwrite the linkage in here, so save it.
+
+ BindingArray[BindingIndex] = Binding;
+ Binding->NicId = (USHORT)BindingIndex;
+
+ if (Binding->ConfiguredNetworkNumber != 0) {
+
+ //
+ // If the configured network number is non-zero, then
+ // use it, unless we are unable to insert a rip table
+ // entry for it (duplicates are OK because they will
+ // become binding set members -- BUGBUG: What if the
+ // duplicate is a different media or frame type, then
+ // it won't get noted as a binding set).
+ //
+
+ status = RipInsertLocalNetwork(
+ Binding->ConfiguredNetworkNumber,
+ Binding->NicId,
+ Binding->Adapter->NdisBindingHandle,
+ (USHORT)((839 + Binding->Adapter->MediumSpeed) / Binding->Adapter->MediumSpeed));
+
+ if ((status == STATUS_SUCCESS) ||
+ (status == STATUS_DUPLICATE_NAME)) {
+
+ Binding->LocalAddress.NetworkAddress = Binding->ConfiguredNetworkNumber;
+ }
+ }
+
+ //
+ // These are a union with the InitialLinkage fields.
+ //
+
+ Binding->NextBinding = NULL;
+ Binding->CurrentSendBinding = NULL;
+
+ Adapter = Binding->Adapter;
+
+ if (Adapter->MacInfo.MediumAsync) {
+ CTEAssert (Adapter->FirstWanNicId == BindingIndex);
+ BindingIndex += Adapter->WanNicIdCount;
+ } else {
+ ++BindingIndex;
+ }
+ }
+
+ CTEAssert (BindingIndex == BindingCount+1);
+
+ Device->Bindings = BindingArray;
+ Device->BindingCount = BindingCount;
+
+
+ //
+ // Queue a request to discover our locally attached
+ // adapter addresses. This must succeed because we
+ // just allocated our send packet pool. We need
+ // to wait for this, either because we are
+ // auto-detecting or because we need to determine
+ // if there are multiple cards on the same network.
+ //
+
+ KeInitializeEvent(
+ &Device->AutoDetectEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ Device->AutoDetectState = AUTO_DETECT_STATE_RUNNING;
+
+ //
+ // Make this 0; after we are done waiting, which means
+ // the packet has been completed, we set it to the
+ // correct value.
+ //
+
+ Device->IncludedHeaderOffset = 0;
+
+ IPX_BEGIN_SYNC (&SyncContext);
+ status = RipQueueRequest (0xffffffff, RIP_REQUEST);
+ IPX_END_SYNC (&SyncContext);
+
+ CTEAssert (status == STATUS_PENDING);
+
+ //
+ // This is set when this rip send completes.
+ //
+
+ IPX_DEBUG (AUTO_DETECT, ("Waiting for AutoDetectEvent\n"));
+
+ KeWaitForSingleObject(
+ &Device->AutoDetectEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ Device->AutoDetectState = AUTO_DETECT_STATE_PROCESSING;
+
+ //
+ // Now that we are done receiving responses, insert the
+ // current network number for every auto-detect binding
+ // to the rip database.
+ //
+
+ for (i = 1; i <= Device->BindingCount; i++) {
+
+ Binding = Device->Bindings[i];
+
+ //
+ // Skip empty WAN slots or bindings that were configured
+ // for a certain network number, we inserted those above.
+ // If no network number was detected, also skip it.
+ //
+
+ if ((!Binding) ||
+ (Binding->ConfiguredNetworkNumber != 0) ||
+ (Binding->TentativeNetworkAddress == 0)) {
+
+ continue;
+ }
+
+ IPX_DEBUG (AUTO_DETECT, ("Final score for %lx on %lx is %d - %d\n",
+ REORDER_ULONG(Binding->TentativeNetworkAddress),
+ Binding,
+ Binding->MatchingResponses,
+ Binding->NonMatchingResponses));
+
+ //
+ // We don't care about the status.
+ //
+
+ status = RipInsertLocalNetwork(
+ Binding->TentativeNetworkAddress,
+ Binding->NicId,
+ Binding->Adapter->NdisBindingHandle,
+ (USHORT)((839 + Binding->MediumSpeed) / Binding->MediumSpeed));
+
+ if ((status != STATUS_SUCCESS) &&
+ (status != STATUS_DUPLICATE_NAME)) {
+
+ //
+ // We failed to insert, keep it at zero, hopefully
+ // we will be able to update later.
+ //
+
+#if DBG
+ DbgPrint ("IPX: Could not insert net %lx for binding %lx\n",
+ REORDER_ULONG(Binding->LocalAddress.NetworkAddress),
+ Binding);
+#endif
+ CTEAssert (Binding->LocalAddress.NetworkAddress == 0);
+
+ } else {
+
+ Binding->LocalAddress.NetworkAddress = Binding->TentativeNetworkAddress;
+ }
+
+ }
+
+ ValidBindings = Device->BindingCount;
+
+ if (Device->AutoDetect) {
+
+ ValidBindings = IpxResolveAutoDetect (Device, ValidBindings, RegistryPath);
+
+ }
+
+ Device->ValidBindings = ValidBindings;
+
+ //
+ // Now see if any bindings are actually on the same
+ // network. This sets Device->HighestExternalNicId
+ // and Device->HighestType20NicId.
+ //
+
+ IpxResolveBindingSets (Device, ValidBindings);
+
+
+ //
+ // For multiple adapters, use the offset of the first...why not.
+ //
+
+#if 0
+ Device->IncludedHeaderOffset = Device->Bindings[1]->DefHeaderSize;
+#endif
+
+ Device->IncludedHeaderOffset = MAC_HEADER_SIZE;
+
+ //
+ // Success; see if there is a virtual network configured.
+ //
+
+ if (Device->VirtualNetworkNumber != 0) {
+
+ status = RipInsertLocalNetwork(
+ Device->VirtualNetworkNumber,
+ 0, // NIC ID
+ Device->Bindings[1]->Adapter->NdisBindingHandle,
+ 1);
+
+ if (status != STATUS_SUCCESS) {
+
+ //
+ // Log the appropriate error, then ignore the
+ // virtual network. If the error was
+ // INSUFFICIENT_RESOURCES, the RIP module
+ // will have already logged an error.
+ //
+
+ if (status == STATUS_DUPLICATE_NAME) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Ignoring virtual network %lx, conflict\n", REORDER_ULONG (Device->VirtualNetworkNumber)));
+
+ IpxWriteResourceErrorLog(
+ Device->DeviceObject,
+ EVENT_IPX_INTERNAL_NET_INVALID,
+ 0,
+ REORDER_ULONG (Device->VirtualNetworkNumber));
+ }
+
+ Device->VirtualNetworkNumber = 0;
+ goto NoVirtualNetwork;
+
+ }
+
+ Device->VirtualNetwork = TRUE;
+ Device->MultiCardZeroVirtual = FALSE;
+ RtlCopyMemory(Device->SourceAddress.NodeAddress, VirtualNode, 6);
+ Device->SourceAddress.NetworkAddress = Device->VirtualNetworkNumber;
+
+ //
+ // This will get set to FALSE if RIP binds.
+ //
+
+ Device->RipResponder = TRUE;
+
+ } else {
+
+NoVirtualNetwork:
+
+ Device->VirtualNetwork = FALSE;
+
+ //
+ // See if we need to be set up for the fake
+ // virtual network.
+ //
+
+ if (ValidBindings > 1) {
+
+ CTEAssert (Device->VirtualNetworkOptional);
+
+ //
+ // In this case we return as our local node the
+ // address of the first card. We will also only
+ // direct SAP sends to that card.
+ //
+
+ Device->MultiCardZeroVirtual = TRUE;
+
+ } else {
+
+ Device->MultiCardZeroVirtual = FALSE;
+ }
+
+ RtlCopyMemory(&Device->SourceAddress, &Device->Bindings[1]->LocalAddress, FIELD_OFFSET(TDI_ADDRESS_IPX,Socket));
+
+ }
+
+
+ //
+ // Now get SapNicCount -- regular adapters are counted
+ // as one, but all the WAN lines together only count for one.
+ // We also calculate FirstLanNicId and FirstWanNicId here.
+ //
+
+ CountedWan = FALSE;
+ Device->SapNicCount = 0;
+
+ Device->FirstLanNicId = (USHORT)-1;
+ Device->FirstWanNicId = (USHORT)-1;
+
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+
+ if (Device->Bindings[i]) {
+
+ if (Device->Bindings[i]->Adapter->MacInfo.MediumAsync) {
+
+ if (Device->FirstWanNicId == (USHORT)-1) {
+ Device->FirstWanNicId = i;
+ }
+
+ if (CountedWan) {
+ continue;
+ } else {
+ CountedWan = TRUE;
+ }
+
+ } else {
+
+ if (Device->FirstLanNicId == (USHORT)-1) {
+ Device->FirstLanNicId = i;
+ }
+
+ }
+
+ } else {
+
+ //
+ // NULL bindings are WANs and are not the first one,
+ // so don't count them.
+ //
+
+ CTEAssert (Device->FirstWanNicId != -1);
+ CTEAssert (CountedWan);
+ continue;
+ }
+
+ ++Device->SapNicCount;
+
+ }
+ }
+
+ if (Device->FirstLanNicId == (USHORT)-1) {
+ Device->FirstLanNicId = 1;
+ }
+ if (Device->FirstWanNicId == (USHORT)-1) {
+ Device->FirstWanNicId = 1;
+ }
+
+
+ //
+ // Calculate some values based on all the bindings.
+ //
+
+ MaxLookahead = Device->Bindings[1]->MaxLookaheadData; // largest binding value
+ AnnouncedMaxDatagram = Device->Bindings[1]->AnnouncedMaxDatagramSize; // smallest binding value
+ RealMaxDatagram = Device->Bindings[1]->RealMaxDatagramSize; // smallest binding value
+
+ if (Device->Bindings[1]->LineUp) {
+ LinkSpeed = Device->Bindings[1]->MediumSpeed; // smallest binding value
+ } else {
+ LinkSpeed = 0xffffffff;
+ }
+ MacOptions = Device->Bindings[1]->Adapter->MacInfo.MacOptions; // AND of binding values
+
+ for (i = 2; i <= ValidBindings; i++) {
+
+ Binding = Device->Bindings[i];
+
+ if (!Binding) {
+ continue;
+ }
+
+ if (Binding->MaxLookaheadData > MaxLookahead) {
+ MaxLookahead = Binding->MaxLookaheadData;
+ }
+ if (Binding->AnnouncedMaxDatagramSize < AnnouncedMaxDatagram) {
+ AnnouncedMaxDatagram = Binding->AnnouncedMaxDatagramSize;
+ }
+ if (Binding->RealMaxDatagramSize < RealMaxDatagram) {
+ RealMaxDatagram = Binding->RealMaxDatagramSize;
+ }
+
+ if (Binding->LineUp && (Binding->MediumSpeed < LinkSpeed)) {
+ LinkSpeed = Binding->MediumSpeed;
+ }
+ MacOptions &= Binding->Adapter->MacInfo.MacOptions;
+
+ }
+
+ Device->Information.MaxDatagramSize = AnnouncedMaxDatagram;
+ Device->RealMaxDatagramSize = RealMaxDatagram;
+ Device->Information.MaximumLookaheadData = MaxLookahead;
+
+ //
+ // If we couldn't find anything better, use the speed from
+ // the first binding.
+ //
+
+ if (LinkSpeed == 0xffffffff) {
+ Device->LinkSpeed = Device->Bindings[1]->MediumSpeed;
+ } else {
+ Device->LinkSpeed = LinkSpeed;
+ }
+ Device->MacOptions = MacOptions;
+
+ Device->State = DEVICE_STATE_OPEN;
+ Device->AutoDetectState = AUTO_DETECT_STATE_DONE;
+
+ IPX_DEBUG (DEVICE, ("Node is %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x, ",
+ Device->SourceAddress.NodeAddress[0], Device->SourceAddress.NodeAddress[1],
+ Device->SourceAddress.NodeAddress[2], Device->SourceAddress.NodeAddress[3],
+ Device->SourceAddress.NodeAddress[4], Device->SourceAddress.NodeAddress[5]));
+ IPX_DEBUG (DEVICE, ("Network is %lx\n",
+ REORDER_ULONG (Device->SourceAddress.NetworkAddress)));
+
+
+ //
+ // Start the timer which updates the RIP database
+ // periodically. For the first one we do a ten
+ // second timeout (hopefully this is enough time
+ // for RIP to start if it is going to).
+ //
+
+ IpxReferenceDevice (Device, DREF_LONG_TIMER);
+
+ CTEStartTimer(
+ &Device->RipLongTimer,
+ 10000,
+ RipLongTimeout,
+ (PVOID)Device);
+
+ //
+ // We use this event when unloading to signal that we
+ // can proceed...initialize it here so we know it is
+ // ready to go when unload is called.
+ //
+
+ KeInitializeEvent(
+ &IpxDevice->UnloadEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ }
+
+InitFailed:
+
+ if (SuccessfulOpens == 0) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_NO_ADAPTERS,
+ 802,
+ STATUS_DEVICE_DOES_NOT_EXIST,
+ NULL,
+ 0,
+ NULL);
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+
+ } else {
+
+ return STATUS_SUCCESS;
+ }
+
+#else // _PNP_POWER
+{
+ PBIND_ARRAY_ELEM BindingArray;
+ PTA_ADDRESS TdiRegistrationAddress;
+
+ //
+ // Pre-allocate the binding array
+ // Later, we will allocate the LAN/WAN and SLAVE bindings separately
+ // [BUGBUGZZ] Read the array size from registry?
+ //
+ BindingArray = (PBIND_ARRAY_ELEM)IpxAllocateMemory (
+ MAX_BINDINGS * sizeof(BIND_ARRAY_ELEM),
+ MEMORY_BINDING,
+ "Binding array");
+
+ if (BindingArray == NULL) {
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_NO_ADAPTERS,
+ 802,
+ STATUS_DEVICE_DOES_NOT_EXIST,
+ NULL,
+ 0,
+ NULL);
+ IpxDereferenceDevice (Device, DREF_CREATE);
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ }
+
+ Device->MaxBindings = MAX_BINDINGS - EXTRA_BINDINGS;
+
+ //
+ // Allocate the TA_ADDRESS structure - this will be used in all TdiRegisterNetAddress
+ // notifications.
+ //
+ TdiRegistrationAddress = (PTA_ADDRESS)IpxAllocateMemory (
+ (2 * sizeof(USHORT) + sizeof(TDI_ADDRESS_IPX)),
+ MEMORY_ADDRESS,
+ "Tdi Address");
+
+ if (TdiRegistrationAddress == NULL) {
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_NO_ADAPTERS,
+ 802,
+ STATUS_DEVICE_DOES_NOT_EXIST,
+ NULL,
+ 0,
+ NULL);
+ IpxFreeMemory(BindingArray, sizeof(BindingArray), MEMORY_BINDING, "Binding Array");
+ IpxDereferenceDevice (Device, DREF_CREATE);
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ }
+
+ RtlZeroMemory (BindingArray, MAX_BINDINGS * sizeof(BIND_ARRAY_ELEM));
+ RtlZeroMemory (TdiRegistrationAddress, 2 * sizeof(USHORT) + sizeof(TDI_ADDRESS_IPX));
+
+ //
+ // We keep BindingArray[-1] as a placeholder for demand dial bindings.
+ // This NicId is returned by the Fwd when a FindRoute is done on a demand
+ // dial Nic. At the time of the InternalSend, the true Nic is returned.
+ // We create a placeholder here to avoid special checks in the critical send path.
+ //
+ // NOTE: we need to free this demand dial binding as well as ensure that the
+ // true binding array pointer is freed at Device Destroy time.
+ //
+ //
+ // Increment beyond the first pointer - we will refer to the just incremented
+ // one as Device->Bindings[-1].
+ //
+ BindingArray += EXTRA_BINDINGS;
+
+ Device->Bindings = BindingArray;
+
+ TdiRegistrationAddress->AddressLength = sizeof(TDI_ADDRESS_IPX);
+ TdiRegistrationAddress->AddressType = TDI_ADDRESS_TYPE_IPX;
+
+ //
+ // Store the pointer in the Device.
+ //
+ Device->TdiRegistrationAddress = TdiRegistrationAddress;
+
+ //
+ // Device state is loaded, but not opened. It is opened when at least
+ // one adapter has appeared.
+ //
+ Device->State = DEVICE_STATE_LOADED;
+
+ Device->FirstLanNicId = Device->FirstWanNicId = (USHORT)1; // will be changed later
+
+ IpxFreeConfiguration(Config);
+
+ //
+ // We use this event when unloading to signal that we
+ // can proceed...initialize it here so we know it is
+ // ready to go when unload is called.
+ //
+
+ KeInitializeEvent(
+ &IpxDevice->UnloadEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ return STATUS_SUCCESS;
+}
+#endif // _PNP_POWER
+} /* DriverEntry */
+
+
+ULONG
+IpxResolveAutoDetect(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings,
+#ifdef _PNP_POWER
+ IN CTELockHandle *LockHandle1,
+#endif
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called for auto-detect bindings to
+ remove any bindings that were not successfully found.
+ It also updates "DefaultAutoDetectType" in the registry
+ if needed.
+
+Arguments:
+
+ Device - The IPX device object.
+
+ ValidBindings - The total number of bindings present.
+
+ RegistryPath - The path to the ipx registry, used if we have
+ to write a value back.
+
+Return Value:
+
+ The updated number of bindings.
+
+--*/
+
+{
+ PBINDING Binding, TmpBinding;
+ UINT i, j;
+
+ //
+ // Get rid of any auto-detect devices which we
+ // could not find nets for. We also remove any
+ // devices which are not the first ones
+ // auto-detected on a particular adapter.
+ //
+
+ for (i = 1; i <= ValidBindings; i++) {
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+
+ if (!Binding) {
+ continue;
+ }
+
+ //
+ // If this was auto-detected and was not the default,
+ // or it was the default, but nothing was detected for
+ // it *and* something else *was* detected (which means
+ // we will use that frame type when we get to it),
+ // we may need to remove this binding.
+ //
+
+ if (Binding->AutoDetect &&
+ (!Binding->DefaultAutoDetect ||
+ (Binding->DefaultAutoDetect &&
+ (Binding->LocalAddress.NetworkAddress == 0) &&
+ Binding->Adapter->AutoDetectResponse))) {
+
+ if ((Binding->LocalAddress.NetworkAddress == 0) ||
+ (Binding->Adapter->AutoDetectFound)) {
+
+ //
+ // Remove this binding.
+ //
+
+ if (Binding->LocalAddress.NetworkAddress == 0) {
+ IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) no net found\n",
+ i, Binding->FrameType));
+ } else {
+ IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) adapter already auto-detected\n",
+ i, Binding->FrameType));
+ }
+
+ CTEAssert (Binding->NicId == i);
+ CTEAssert (!Binding->Adapter->MacInfo.MediumAsync);
+
+ //
+ // Remove any routes through this NIC, and
+ // adjust any NIC ID's above this one in the
+ // database down by one.
+ //
+
+ RipAdjustForBindingChange (Binding->NicId, 0, IpxBindingDeleted);
+
+ Binding->Adapter->Bindings[Binding->FrameType] = NULL;
+ for (j = i+1; j <= ValidBindings; j++) {
+#ifndef _PNP_POWER
+ TmpBinding = Device->Bindings[j];
+ Device->Bindings[j-1] = TmpBinding;
+#else
+ TmpBinding = NIC_ID_TO_BINDING(Device, j);
+ INSERT_BINDING(Device, j-1, TmpBinding);
+#endif _PNP_POWER
+ if (TmpBinding) {
+ if ((TmpBinding->Adapter->MacInfo.MediumAsync) &&
+ (TmpBinding->Adapter->FirstWanNicId == TmpBinding->NicId)) {
+ --TmpBinding->Adapter->FirstWanNicId;
+ --TmpBinding->Adapter->LastWanNicId;
+ }
+ --TmpBinding->NicId;
+ }
+ }
+#ifdef _PNP_POWER
+ INSERT_BINDING(Device, ValidBindings, NULL);
+#else
+ Device->Bindings[ValidBindings] = NULL;
+#endif
+ --Binding->Adapter->BindingCount;
+ --ValidBindings;
+
+ --i; // so we check the binding that was just moved.
+
+ //
+ // Wait 100 ms before freeing the binding,
+ // in case an indication is using it.
+ //
+
+ KeStallExecutionProcessor(100000);
+
+ IpxDestroyBinding (Binding);
+
+ } else {
+
+ IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) auto-detected OK\n",
+ i, Binding->FrameType));
+
+#if DBG
+ DbgPrint ("IPX: Auto-detected non-default frame type %s, net %lx\n",
+ OutputFrameType(Binding),
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+#endif
+
+ //
+ // Save it in the registry for the next boot.
+ //
+#ifdef _PNP_POWER
+//
+// This cannot be done at DPC, so, drop the IRQL
+//
+ IPX_FREE_LOCK1(&Device->BindAccessLock, *LockHandle1);
+ IpxWriteDefaultAutoDetectType(
+ RegistryPath,
+ Binding->Adapter,
+ Binding->FrameType);
+ IPX_GET_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ IpxWriteDefaultAutoDetectType(
+ RegistryPath,
+ Binding->Adapter,
+ Binding->FrameType);
+#endif
+
+ Binding->Adapter->AutoDetectFound = TRUE;
+ }
+
+ } else {
+
+ if (Binding->AutoDetect) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) auto-detect default\n",
+ i, Binding->FrameType));
+
+#if DBG
+ if (Binding->LocalAddress.NetworkAddress != 0) {
+ DbgPrint ("IPX: Auto-detected default frame type %s, net %lx\n",
+ OutputFrameType(Binding),
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+ } else {
+ DbgPrint ("IPX: Using default auto-detect frame type %s\n",
+ OutputFrameType(Binding));
+ }
+#endif
+
+ Binding->Adapter->AutoDetectFound = TRUE;
+
+ } else {
+
+ IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) not auto-detected\n",
+ i, Binding->FrameType));
+ }
+
+ }
+
+ }
+
+
+ for (i = 1; i <= ValidBindings; i++) {
+#ifdef _PNP_POWER
+ if (Binding = NIC_ID_TO_BINDING(Device, i)) {
+#else
+ if (Binding = Device->Bindings[i]) {
+#endif
+ CTEAssert (Binding->NicId == i);
+ IPX_DEBUG (AUTO_DETECT, ("Binding %lx, type %d, auto %d\n",
+ Binding, Binding->FrameType, Binding->AutoDetect));
+ }
+
+ }
+
+ return ValidBindings;
+
+} /* IpxResolveAutoDetect */
+
+
+VOID
+IpxResolveBindingSets(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to determine if we have any
+ binding sets and rearrange the bindings the way we
+ like. The order is as follows:
+
+ - First comes the first binding to each LAN network
+ - Following that are all WAN bindings
+ - Following that are any duplicate bindings to LAN networks
+ (the others in the "binding set").
+
+ If "global wan net" is true we will advertise up to
+ and including the first wan binding as the highest nic
+ id; otherwise we advertise up to and including the last
+ wan binding. In all cases the duplicate bindings are
+ hidden.
+
+Arguments:
+
+ Device - The IPX device object.
+
+ ValidBindings - The total number of bindings present.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PBINDING Binding, MasterBinding, TmpBinding;
+ UINT i, j;
+ ULONG WanCount, DuplicateCount;
+
+ //
+ // First loop through and push all the wan bindings
+ // to the end.
+ //
+#ifdef _PNP_POWER
+
+ WanCount = Device->HighestExternalNicId - Device->HighestLanNicId;
+
+#else
+
+ WanCount = 0;
+
+ //
+ // For PnP, we dont do this as the bindings are in order
+ // at the time of insertion
+ //
+ for (i = 1; i <= (ValidBindings-WanCount); ) {
+
+ Binding = Device->Bindings[i];
+
+ if ((Binding == NULL) || Binding->Adapter->MacInfo.MediumAsync) {
+
+ //
+ // Put this binding at the end, and slide all the
+ // others down. If it is a NULL WAN binding then we
+ // don't have to do some of this.
+ //
+
+#if DBG
+ //
+ // Any non-NULL bindings should be correct in this
+ // respect at any point.
+ //
+
+ if (Binding != NULL) {
+ CTEAssert (Binding->NicId == i);
+ }
+#endif
+
+ //
+ // If the Binding is NULL we won't have anything in the
+ // database at this binding, but we still need to adjust
+ // any NIC ID's in the database which are above this.
+ //
+
+ RipAdjustForBindingChange ((USHORT)i, (USHORT)ValidBindings, IpxBindingMoved);
+
+ //
+ // Slide the bindings above this down.
+ //
+
+ for (j = i+1; j <= ValidBindings; j++) {
+ TmpBinding = Device->Bindings[j];
+ Device->Bindings[j-1] = TmpBinding;
+ if (TmpBinding) {
+ if ((TmpBinding->Adapter->MacInfo.MediumAsync) &&
+ (TmpBinding->Adapter->FirstWanNicId == TmpBinding->NicId)) {
+ --TmpBinding->Adapter->FirstWanNicId;
+ --TmpBinding->Adapter->LastWanNicId;
+ }
+ --TmpBinding->NicId;
+ }
+ }
+
+ //
+ // Put this binding at the end.
+ //
+
+ Device->Bindings[ValidBindings] = Binding;
+ if (Binding != NULL) {
+ if ((Binding->Adapter->MacInfo.MediumAsync) &&
+ (Binding->Adapter->FirstWanNicId == Binding->NicId)) {
+ Binding->Adapter->FirstWanNicId = (USHORT)ValidBindings;
+ Binding->Adapter->LastWanNicId += (USHORT)(ValidBindings - Binding->NicId);
+ }
+ Binding->NicId = (USHORT)ValidBindings;
+ }
+ ++WanCount;
+
+ //
+ // Keep i the same, to check the new binding at
+ // this position.
+ //
+
+ } else {
+
+ i++;
+
+ }
+
+ }
+#endif _PNP_POWER
+ //
+ // Now go through and find the LAN duplicates and
+ // create binding sets from them.
+ //
+
+ DuplicateCount = 0;
+
+ for (i = 1; i <= (ValidBindings-(WanCount+DuplicateCount)); ) {
+
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ CTEAssert (Binding != NULL); // because we are only looking at LAN bindings
+
+ CTEAssert (!Binding->Adapter->MacInfo.MediumAsync);
+
+ if (Binding->LocalAddress.NetworkAddress == 0) {
+ i++;
+ continue;
+ }
+
+ //
+ // See if any previous bindings match the
+ // frame type, medium type, and number of
+ // this network (for the moment we match on
+ // frame type and medium type too so that we
+ // don't have to worry about different frame
+ // formats and header offsets within a set).
+ //
+
+ for (j = 1; j < i; j++) {
+#ifdef _PNP_POWER
+ MasterBinding = NIC_ID_TO_BINDING(Device, j);
+#else
+ MasterBinding = Device->Bindings[j];
+#endif
+ if ((MasterBinding->LocalAddress.NetworkAddress == Binding->LocalAddress.NetworkAddress) &&
+ (MasterBinding->FrameType == Binding->FrameType) &&
+ (MasterBinding->Adapter->MacInfo.MediumType == Binding->Adapter->MacInfo.MediumType)) {
+ break;
+ }
+
+ }
+
+ if (j == i) {
+ i++;
+ continue;
+ }
+
+ //
+ // We have a duplicate. First slide it down to the
+ // end. Note that we change any router entries that
+ // use our real NicId to use the real NicId of the
+ // master (there should be no entries in the rip
+ // database that have the NicId of a binding slave).
+ //
+
+ RipAdjustForBindingChange (Binding->NicId, MasterBinding->NicId, IpxBindingMoved);
+
+ for (j = i+1; j <= ValidBindings; j++) {
+#ifdef _PNP_POWER
+ TmpBinding = NIC_ID_TO_BINDING(Device, j);
+ INSERT_BINDING(Device, j-1, TmpBinding);
+#else
+ TmpBinding = Device->Bindings[j];
+ Device->Bindings[j-1] = TmpBinding;
+#endif
+ if (TmpBinding) {
+ if ((TmpBinding->Adapter->MacInfo.MediumAsync) &&
+ (TmpBinding->Adapter->FirstWanNicId == TmpBinding->NicId)) {
+ --TmpBinding->Adapter->FirstWanNicId;
+ --TmpBinding->Adapter->LastWanNicId;
+ }
+ --TmpBinding->NicId;
+ }
+ }
+#ifdef _PNP_POWER
+ INSERT_BINDING(Device, ValidBindings, Binding);
+#else
+ Device->Bindings[ValidBindings] = Binding;
+#endif
+
+ Binding->NicId = (USHORT)ValidBindings;
+ ++DuplicateCount;
+
+ //
+ // Now make MasterBinding the head of a binding set.
+ //
+
+ if (MasterBinding->BindingSetMember) {
+
+ //
+ // Just insert ourselves in the chain.
+ //
+
+#if DBG
+ DbgPrint ("IPX: %lx is also on network %lx\n",
+ Binding->Adapter->AdapterName,
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+#endif
+ IPX_DEBUG (AUTO_DETECT, ("Add %lx to binding set of %lx\n", Binding, MasterBinding));
+
+ CTEAssert (MasterBinding->CurrentSendBinding);
+ Binding->NextBinding = MasterBinding->NextBinding;
+
+ } else {
+
+ //
+ // Start the chain with the two bindings in it.
+ //
+
+#if DBG
+ DbgPrint ("IPX: %lx and %lx are on the same network %lx, will load balance\n",
+ MasterBinding->Adapter->AdapterName, Binding->Adapter->AdapterName,
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+#endif
+ IPX_DEBUG (AUTO_DETECT, ("Create new %lx in binding set of %lx\n", Binding, MasterBinding));
+
+ MasterBinding->BindingSetMember = TRUE;
+ MasterBinding->CurrentSendBinding = MasterBinding;
+ MasterBinding->MasterBinding = MasterBinding;
+ Binding->NextBinding = MasterBinding;
+
+ }
+
+ MasterBinding->NextBinding = Binding;
+ Binding->BindingSetMember = TRUE;
+ Binding->ReceiveBroadcast = FALSE;
+ Binding->CurrentSendBinding = NULL;
+ Binding->MasterBinding = MasterBinding;
+
+ //
+ // Since the master binding looks like all members of
+ // the binding set to people querying from above, we have
+ // to make it the worst-case of all the elements. Generally
+ // these will be equal since the frame type and media is
+ // the same.
+ //
+
+ if (Binding->MaxLookaheadData > MasterBinding->MaxLookaheadData) {
+ MasterBinding->MaxLookaheadData = Binding->MaxLookaheadData;
+ }
+ if (Binding->AnnouncedMaxDatagramSize < MasterBinding->AnnouncedMaxDatagramSize) {
+ MasterBinding->AnnouncedMaxDatagramSize = Binding->AnnouncedMaxDatagramSize;
+ }
+ if (Binding->RealMaxDatagramSize < MasterBinding->RealMaxDatagramSize) {
+ MasterBinding->RealMaxDatagramSize = Binding->RealMaxDatagramSize;
+ }
+ if (Binding->MediumSpeed < MasterBinding->MediumSpeed) {
+ MasterBinding->MediumSpeed = Binding->MediumSpeed;
+ }
+
+ //
+ // Keep i the same, to check the new binding at
+ // this position.
+ //
+
+ }
+#ifndef _PNP_POWER
+ Device->HighestExternalNicId = (USHORT)(ValidBindings - DuplicateCount);
+ Device->HighestType20NicId = (USHORT)(ValidBindings-(WanCount+DuplicateCount));
+#else
+ Device->HighestLanNicId -= (USHORT)DuplicateCount;
+
+ if (Device->HighestLanNicId == 0) {
+ CTEAssert(FALSE);
+ }
+
+ Device->HighestExternalNicId -= (USHORT)DuplicateCount;
+ Device->HighestType20NicId -= (USHORT)DuplicateCount;
+ Device->SapNicCount -= (USHORT)DuplicateCount;
+#endif _PNP_POWER
+} /* IpxResolveBindingSets */
+
+
+NTSTATUS
+IpxBindToAdapter(
+ IN PDEVICE Device,
+ IN PBINDING_CONFIG ConfigBinding,
+#ifdef _PNP_POWER
+ IN PADAPTER *AdapterPtr,
+#endif
+ IN ULONG FrameTypeIndex
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles binding the transport to a new
+ adapter. It can be called at any point during the life
+ of the transport.
+
+Arguments:
+
+ Device - The IPX device object.
+
+ ConfigBinding - The configuration info for this binding.
+
+ AdapterPtr - pointer to the adapter to bind to in case of PnP.
+
+ FrameTypeIndex - The index into ConfigBinding's array of frame
+ types for this adapter. The routine is called once for
+ every valid frame type.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ NTSTATUS status;
+
+#ifndef _PNP_POWER
+ //
+ // Adapter came in as a parameter
+ //
+ PADAPTER Adapter = NULL;
+#else
+ PADAPTER Adapter = *AdapterPtr;
+#endif
+
+ PBINDING Binding, OldBinding;
+ ULONG FrameType, MappedFrameType;
+ PLIST_ENTRY p;
+
+ //
+ // We can't bind more than one adapter unless we have a
+ // virtual network configured or we are allowed to run
+ // with a virtual network of 0.
+ //
+
+ if (Device->BindingCount == 1) {
+ if ((Device->VirtualNetworkNumber == 0) &&
+ (!Device->VirtualNetworkOptional)) {
+
+ IPX_DEBUG (ADAPTER, ("Cannot bind to more than one adapter\n"));
+ DbgPrint ("IPX: Disallowing multiple bind ==> VirtualNetwork is 0\n");
+ IpxWriteGeneralErrorLog(
+ Device->DeviceObject,
+ EVENT_TRANSPORT_BINDING_FAILED,
+ 666,
+ STATUS_NOT_SUPPORTED,
+ ConfigBinding->AdapterName.Buffer,
+ 0,
+ NULL);
+
+ return STATUS_NOT_SUPPORTED;
+ }
+ }
+
+
+ //
+ // First allocate the memory for the binding.
+ //
+
+ status = IpxCreateBinding(
+ Device,
+ ConfigBinding,
+ FrameTypeIndex,
+ ConfigBinding->AdapterName.Buffer,
+ &Binding);
+
+ if (status != STATUS_SUCCESS) {
+ return status;
+ }
+
+ FrameType = ConfigBinding->FrameType[FrameTypeIndex];
+
+//
+// In PnP case, we dont need to check for existing adapters since
+// we supply a NULL adapter in the parameters if it needs to be created
+//
+#ifndef _PNP_POWER
+
+ //
+ // Check if there is already an NDIS binding to this adapter,
+ // and if so, that there is not already a binding with this
+ // frame type.
+ //
+
+
+ for (p = Device->InitialBindingList.Flink;
+ p != &Device->InitialBindingList;
+ p = p->Flink) {
+
+ OldBinding = CONTAINING_RECORD (p, BINDING, InitialLinkage);
+
+ if (RtlEqualMemory(
+ OldBinding->Adapter->AdapterName,
+ ConfigBinding->AdapterName.Buffer,
+ OldBinding->Adapter->AdapterNameLength)) {
+
+ Adapter = OldBinding->Adapter;
+
+ MacMapFrameType(
+ Adapter->MacInfo.RealMediumType,
+ FrameType,
+ &MappedFrameType);
+
+ if (Adapter->Bindings[MappedFrameType] != NULL) {
+
+ IPX_DEBUG (ADAPTER, ("Bind to adapter %ws, type %d exists\n",
+ Adapter->AdapterName,
+ MappedFrameType));
+
+ //
+ // If this was the auto-detect default for this
+ // adapter and it failed, we need to make the
+ // previous one the default, so that at least
+ // one binding will stick around.
+ //
+
+ if (ConfigBinding->DefaultAutoDetect[FrameTypeIndex]) {
+ IPX_DEBUG (ADAPTER, ("Default auto-detect changed from %d to %d\n",
+ FrameType, MappedFrameType));
+ Adapter->Bindings[MappedFrameType]->DefaultAutoDetect = TRUE;
+ }
+
+ IpxDestroyBinding (Binding);
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ IPX_DEBUG (ADAPTER, ("Using existing bind to adapter %ws, type %d\n",
+ Adapter->AdapterName,
+ MappedFrameType));
+ break;
+
+ }
+ }
+#endif _PNP_POWER
+
+ if (Adapter == NULL) {
+
+ //
+ // No binding to this adapter exists, so create a
+ // new one.
+ //
+
+ status = IpxCreateAdapter(
+ Device,
+ &ConfigBinding->AdapterName,
+ &Adapter);
+
+ if (status != STATUS_SUCCESS) {
+ IpxDestroyBinding(Binding);
+ return status;
+ }
+
+ //
+ // Save these now (they will be the same for all bindings
+ // on this adapter).
+ //
+
+ Adapter->ConfigMaxPacketSize = ConfigBinding->Parameters[BINDING_MAX_PKT_SIZE];
+ Adapter->SourceRouting = (BOOLEAN)ConfigBinding->Parameters[BINDING_SOURCE_ROUTE];
+ Adapter->EnableFunctionalAddress = (BOOLEAN)ConfigBinding->Parameters[BINDING_ENABLE_FUNC_ADDR];
+ Adapter->EnableWanRouter = (BOOLEAN)ConfigBinding->Parameters[BINDING_ENABLE_WAN];
+
+ Adapter->BindSap = (USHORT)ConfigBinding->Parameters[BINDING_BIND_SAP];
+ Adapter->BindSapNetworkOrder = REORDER_USHORT(Adapter->BindSap);
+ CTEAssert (Adapter->BindSap == 0x8137);
+ CTEAssert (Adapter->BindSapNetworkOrder == 0x3781);
+
+ //
+ // Now fire up NDIS so this adapter talks
+ //
+
+ status = IpxInitializeNdis(
+ Adapter,
+ ConfigBinding);
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // Log an error.
+ //
+
+ IpxWriteGeneralErrorLog(
+ Device->DeviceObject,
+ EVENT_TRANSPORT_BINDING_FAILED,
+ 601,
+ status,
+ ConfigBinding->AdapterName.Buffer,
+ 0,
+ NULL);
+
+ IpxDestroyAdapter (Adapter);
+ IpxDestroyBinding (Binding);
+
+ //
+ // Returning this status informs the caller to not
+ // try any more frame types on this adapter.
+ //
+
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+
+ }
+
+ //
+ // For 802.5 bindings we need to start the source routing
+ // timer to time out old entries.
+ //
+
+ if ((Adapter->MacInfo.MediumType == NdisMedium802_5) &&
+ (Adapter->SourceRouting)) {
+
+ if (!Device->SourceRoutingUsed) {
+
+ Device->SourceRoutingUsed = TRUE;
+ IpxReferenceDevice (Device, DREF_SR_TIMER);
+
+ CTEStartTimer(
+ &Device->SourceRoutingTimer,
+ 60000, // one minute timeout
+ MacSourceRoutingTimeout,
+ (PVOID)Device);
+ }
+ }
+
+ MacMapFrameType(
+ Adapter->MacInfo.RealMediumType,
+ FrameType,
+ &MappedFrameType);
+
+ IPX_DEBUG (ADAPTER, ("Create new bind to adapter %ws, type %d\n",
+ ConfigBinding->AdapterName.Buffer,
+ MappedFrameType));
+
+ IpxAllocateReceiveBufferPool (Adapter);
+
+#ifdef _PNP_POWER
+ *AdapterPtr = Adapter;
+#endif
+ }
+#ifdef _PNP_POWER
+ else {
+ //
+ // get the mapped frame type
+ //
+ MacMapFrameType(
+ Adapter->MacInfo.RealMediumType,
+ FrameType,
+ &MappedFrameType);
+
+ if (Adapter->Bindings[MappedFrameType] != NULL) {
+
+ IPX_DEBUG (ADAPTER, ("Bind to adapter %ws, type %d exists\n",
+ Adapter->AdapterName,
+ MappedFrameType));
+
+ //
+ // If this was the auto-detect default for this
+ // adapter and it failed, we need to make the
+ // previous one the default, so that at least
+ // one binding will stick around.
+ //
+
+ if (ConfigBinding->DefaultAutoDetect[FrameTypeIndex]) {
+ IPX_DEBUG (ADAPTER, ("Default auto-detect changed from %d to %d\n",
+ FrameType, MappedFrameType));
+ Adapter->Bindings[MappedFrameType]->DefaultAutoDetect = TRUE;
+ }
+
+ IpxDestroyBinding (Binding);
+
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ IPX_DEBUG (ADAPTER, ("Using existing bind to adapter %ws, type %d\n",
+ Adapter->AdapterName,
+ MappedFrameType));
+ }
+#endif _PNP_POWER
+
+ //
+ // The local node address starts out the same as the
+ // MAC address of the adapter (on WAN this will change).
+ // The local MAC address can also change for WAN.
+ //
+
+ RtlCopyMemory (Binding->LocalAddress.NodeAddress, Adapter->LocalMacAddress.Address, 6);
+ RtlCopyMemory (Binding->LocalMacAddress.Address, Adapter->LocalMacAddress.Address, 6);
+
+
+ //
+ // Save the send handler.
+ //
+
+ Binding->SendFrameHandler = NULL;
+ Binding->FrameType = MappedFrameType;
+
+ //
+ // BUGBUG: Put this in InitializeBindingInfo.
+ //
+
+ switch (Adapter->MacInfo.RealMediumType) {
+ case NdisMedium802_3:
+ switch (MappedFrameType) {
+ case ISN_FRAME_TYPE_802_3: Binding->SendFrameHandler = IpxSendFrame802_3802_3; break;
+ case ISN_FRAME_TYPE_802_2: Binding->SendFrameHandler = IpxSendFrame802_3802_2; break;
+ case ISN_FRAME_TYPE_ETHERNET_II: Binding->SendFrameHandler = IpxSendFrame802_3EthernetII; break;
+ case ISN_FRAME_TYPE_SNAP: Binding->SendFrameHandler = IpxSendFrame802_3Snap; break;
+ }
+ break;
+ case NdisMedium802_5:
+ switch (MappedFrameType) {
+ case ISN_FRAME_TYPE_802_2: Binding->SendFrameHandler = IpxSendFrame802_5802_2; break;
+ case ISN_FRAME_TYPE_SNAP: Binding->SendFrameHandler = IpxSendFrame802_5Snap; break;
+ }
+ break;
+ case NdisMediumFddi:
+ switch (MappedFrameType) {
+ case ISN_FRAME_TYPE_802_3: Binding->SendFrameHandler = IpxSendFrameFddi802_3; break;
+ case ISN_FRAME_TYPE_802_2: Binding->SendFrameHandler = IpxSendFrameFddi802_2; break;
+ case ISN_FRAME_TYPE_SNAP: Binding->SendFrameHandler = IpxSendFrameFddiSnap; break;
+ }
+ break;
+ case NdisMediumArcnet878_2:
+ switch (MappedFrameType) {
+ case ISN_FRAME_TYPE_802_3: Binding->SendFrameHandler = IpxSendFrameArcnet878_2; break;
+ }
+ break;
+ case NdisMediumWan:
+ switch (MappedFrameType) {
+ case ISN_FRAME_TYPE_ETHERNET_II: Binding->SendFrameHandler = IpxSendFrameWanEthernetII; break;
+ }
+ break;
+ }
+
+ if (Binding->SendFrameHandler == NULL) {
+ DbgPrint ("BUGBUG!: SendFrameHandler is NULL\n");
+ }
+
+ Adapter->Bindings[MappedFrameType] = Binding;
+ ++Adapter->BindingCount;
+
+ Binding->Adapter = Adapter;
+
+#ifndef _PNP_POWER
+ InsertTailList (&Device->InitialBindingList, &Binding->InitialLinkage);
+#endif _PNP_POWER
+
+ //
+ // NicId and ExternalNicId will be filled in later when the binding
+ // is assigned a spot in the Device->Bindings array.
+ //
+
+ //
+ // Initialize the per-binding MAC information
+ //
+
+ if ((Adapter->ConfigMaxPacketSize == 0) ||
+ (Adapter->MaxSendPacketSize < Adapter->ConfigMaxPacketSize)) {
+ Binding->MaxSendPacketSize = Adapter->MaxSendPacketSize;
+ } else {
+ Binding->MaxSendPacketSize = Adapter->ConfigMaxPacketSize;
+ }
+ Binding->MediumSpeed = Adapter->MediumSpeed;
+ if (Adapter->MacInfo.MediumAsync) {
+ Binding->LineUp = FALSE;
+ } else {
+ Binding->LineUp = TRUE;
+ }
+
+ MacInitializeBindingInfo(
+ Binding,
+ Adapter);
+
+ return STATUS_SUCCESS;
+
+} /* IpxBindToAdapter */
+
+
+BOOLEAN
+IpxIsAddressLocal(
+ IN TDI_ADDRESS_IPX UNALIGNED * SourceAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns TRUE if the specified SourceAddress indicates
+ the packet was sent by us, and FALSE otherwise.
+
+Arguments:
+
+ SourceAddress - The source IPX address.
+
+Return Value:
+
+ TRUE if the address is local.
+
+--*/
+
+{
+ PBINDING Binding;
+ UINT i;
+
+ //
+ // First see if it is a virtual network address or not.
+ //
+
+ if (RtlEqualMemory (VirtualNode, SourceAddress->NodeAddress, 6)) {
+
+ //
+ // This is us if we have a virtual network configured.
+ // If we don't have a virtual node, we fall through to the
+ // other check -- an arcnet card configured as node 1 will
+ // have what we think of as the "virtual node" as its
+ // real node address.
+ //
+
+ if ((IpxDevice->VirtualNetwork) &&
+ (IpxDevice->VirtualNetworkNumber == SourceAddress->NetworkAddress)) {
+ return TRUE;
+ }
+
+ }
+
+ //
+ // Check through our list of adapters to see if one of
+ // them is the source node.
+ //
+ {
+ ULONG Index = MIN (IpxDevice->MaxBindings, IpxDevice->ValidBindings);
+
+ for (i = 1; i <= Index; i++) {
+#ifdef _PNP_POWER
+ if (((Binding = NIC_ID_TO_BINDING(IpxDevice, i)) != NULL) &&
+#else
+ if (((Binding = IpxDevice->Bindings[i]) != NULL) &&
+#endif _PNP_POWER
+ (RtlEqualMemory (Binding->LocalAddress.NodeAddress, SourceAddress->NodeAddress, 6))) {
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+
+} /* IpxIsAddressLocal */
+
+
+NTSTATUS
+IpxUnBindFromAdapter(
+ IN PBINDING Binding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles unbinding the transport from an
+ adapter. It can be called at any point during the life
+ of the transport.
+
+Arguments:
+
+ Binding - The adapter to unbind.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ PADAPTER Adapter = Binding->Adapter;
+
+ Adapter->Bindings[Binding->FrameType] = NULL;
+ --Adapter->BindingCount;
+
+ IpxDereferenceBinding (Binding, BREF_BOUND);
+
+ if (Adapter->BindingCount == 0) {
+
+ //
+ // DereferenceAdapter is a NULL macro for load-only.
+ //
+ // BUGBUG: Revisit Post 4.0
+ //
+#ifdef _PNP_LATER
+ //
+ // Take away the creation reference. When the in-use ref is taken off,
+ // we destroy this adapter.
+ //
+ IpxDereferenceAdapter(Adapter);
+#else
+ //
+ // Free the packet pools, etc. and close the
+ // adapter.
+ //
+
+ IpxCloseNdis (Adapter);
+
+ IpxDestroyAdapter (Adapter);
+#endif
+ }
+
+ return STATUS_SUCCESS;
+
+} /* IpxUnBindFromAdapter */
+
+
+VOID
+IpxUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unloads the sample transport driver.
+ It unbinds from any NDIS drivers that are open and frees all resources
+ associated with the transport. The I/O system will not call us until
+ nobody above has IPX open.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ None. When the function returns, the driver is unloaded.
+
+--*/
+
+{
+
+ PBINDING Binding;
+ PREQUEST Request;
+ PLIST_ENTRY p;
+ UINT i;
+
+
+ UNREFERENCED_PARAMETER (DriverObject);
+
+ IpxDevice->State = DEVICE_STATE_STOPPING;
+
+
+ //
+ // Complete any pending address notify requests.
+ //
+
+ while ((p = ExInterlockedRemoveHeadList(
+ &IpxDevice->AddressNotifyQueue,
+ &IpxDevice->Lock)) != NULL) {
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+ REQUEST_STATUS(Request) = STATUS_DEVICE_NOT_READY;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (IpxDevice, Request);
+
+ IpxDereferenceDevice (IpxDevice, DREF_ADDRESS_NOTIFY);
+ }
+
+
+ //
+ // Cancel the source routing timer if used.
+ //
+
+ if (IpxDevice->SourceRoutingUsed) {
+
+ IpxDevice->SourceRoutingUsed = FALSE;
+ if (CTEStopTimer (&IpxDevice->SourceRoutingTimer)) {
+ IpxDereferenceDevice (IpxDevice, DREF_SR_TIMER);
+ }
+ }
+
+
+ //
+ // Cancel the RIP long timer, and if we do that then
+ // send a RIP DOWN message if needed.
+ //
+
+ if (CTEStopTimer (&IpxDevice->RipLongTimer)) {
+
+ if (IpxDevice->RipResponder) {
+
+ if (RipQueueRequest (IpxDevice->VirtualNetworkNumber, RIP_DOWN) == STATUS_PENDING) {
+
+ //
+ // If we queue a request, it will stop the timer.
+ //
+
+ KeWaitForSingleObject(
+ &IpxDevice->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+ }
+ }
+
+ IpxDereferenceDevice (IpxDevice, DREF_LONG_TIMER);
+
+ } else {
+
+ //
+ // We couldn't stop the timer, which means it is running,
+ // so we need to wait for the event that is kicked when
+ // the RIP DOWN messages are done.
+ //
+
+ if (IpxDevice->RipResponder) {
+
+ KeWaitForSingleObject(
+ &IpxDevice->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+ }
+ }
+
+
+ //
+ // Walk the list of device contexts.
+ //
+
+ for (i = 1; i <= IpxDevice->BindingCount; i++) {
+#ifdef _PNP_POWER
+ if ((Binding = NIC_ID_TO_BINDING(IpxDevice, i)) != NULL) {
+ INSERT_BINDING(IpxDevice, i, NULL);
+#else
+ if (IpxDevice->Bindings[i] != NULL) {
+ Binding = IpxDevice->Bindings[i];
+ IpxDevice->Bindings[i] = NULL;
+#endif _PNP_POWER
+
+ IpxUnBindFromAdapter (Binding);
+
+ }
+
+ }
+
+ //
+ // Backup the pointer to free the demand dial location.
+ //
+ IpxDevice->Bindings -= EXTRA_BINDINGS;
+
+#ifdef _PNP_POWER
+
+ IpxFreeMemory ( IpxDevice->Bindings,
+ IpxDevice->MaxBindings * sizeof(BIND_ARRAY_ELEM),
+ MEMORY_BINDING,
+ "Binding array");
+
+ //
+ // Deallocate the TdiRegistrationAddress and RegistryPathBuffer.
+ //
+ IpxFreeMemory ( IpxDevice->TdiRegistrationAddress,
+ (2 * sizeof(USHORT) + sizeof(TDI_ADDRESS_IPX)),
+ MEMORY_ADDRESS,
+ "Tdi Address");
+
+ IpxFreeMemory ( IpxDevice->RegistryPathBuffer,
+ IpxDevice->RegistryPath.Length + sizeof(WCHAR),
+ MEMORY_CONFIG,
+ "RegistryPathBuffer");
+
+#endif
+
+ KeResetEvent(
+ &IpxDevice->UnloadEvent
+ );
+ IpxDevice->UnloadWaiting = TRUE;
+
+ //
+ // Remove the reference for us being loaded.
+ //
+
+ IpxDereferenceDevice (IpxDevice, DREF_CREATE);
+
+ //
+ // Wait for our count to drop to zero.
+ //
+
+ KeWaitForSingleObject(
+ &IpxDevice->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ //
+ // Now free the padding buffer.
+ //
+
+ IpxFreePaddingBuffer (IpxDevice);
+
+ //
+ // Now do the cleanup that has to happen at IRQL 0.
+ //
+
+ ExDeleteResource (&IpxDevice->AddressResource);
+ IoDeleteDevice (IpxDevice->DeviceObject);
+
+ //
+ // Finally, remove ourselves as an NDIS protocol.
+ //
+
+ IpxDeregisterProtocol();
+
+} /* IpxUnload */
+
+
+NTSTATUS
+IpxDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the IPX device driver.
+ It accepts an I/O Request Packet, performs the request, and then
+ returns with the appropriate status.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PDEVICE Device = IpxDevice;
+ NTSTATUS Status;
+ PFILE_FULL_EA_INFORMATION openType;
+ BOOLEAN found;
+ PADDRESS_FILE AddressFile;
+ PREQUEST Request;
+ UINT i;
+ ULONG Type;
+
+ ASSERT( DeviceObject->DeviceExtension == IpxDevice );
+
+#ifdef _PNP_POWER
+ if ((Device->State == DEVICE_STATE_CLOSED) ||
+ (Device->State == DEVICE_STATE_STOPPING)) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+#else
+ if (Device->State != DEVICE_STATE_OPEN) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+#endif
+ //
+ // Allocate a request to track this IRP.
+ //
+
+ Request = IpxAllocateRequest (Device, Irp);
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ MARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = STATUS_PENDING;
+ REQUEST_INFORMATION(Request) = 0;
+
+ //
+ // Case on the function that is being performed by the requestor. If the
+ // operation is a valid one for this device, then make it look like it was
+ // successfully completed, where possible.
+ //
+
+
+ switch (REQUEST_MAJOR_FUNCTION(Request)) {
+
+ //
+ // The Create function opens a transport object (either address or
+ // connection). Access checking is performed on the specified
+ // address to ensure security of transport-layer addresses.
+ //
+
+ case IRP_MJ_CREATE:
+
+ openType = OPEN_REQUEST_EA_INFORMATION(Request);
+
+ if (openType != NULL) {
+
+ found = TRUE;
+
+ for (i=0;i<openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiTransportAddress[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = IpxOpenAddress (Device, Request);
+ break;
+ }
+
+ //
+ // Router
+ //
+ if (strncmp(openType->EaName, ROUTER_INTERFACE,
+ openType->EaNameLength) == 0)
+ {
+ found = TRUE;
+ }
+
+ if (found) {
+ Status = OpenRtAddress (Device, Request);
+ break;
+ }
+ //
+ // Connection?
+ //
+
+ found = TRUE;
+
+ for (i=0;i<openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiConnectionContext[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+ }
+ else
+ {
+ Status = STATUS_NONEXISTENT_EA_ENTRY;
+
+ }
+
+ } else {
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ //
+ // LowPart is in the OPEN_CONTEXT directly.
+ // HighPart goes into the upper 2 bytes of the OPEN_TYPE.
+ //
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)(Device->ControlChannelIdentifier.LowPart);
+
+ (ULONG)(REQUEST_OPEN_TYPE(Request)) = (Device->ControlChannelIdentifier.HighPart << 16);
+ (ULONG)(REQUEST_OPEN_TYPE(Request)) |= IPX_FILE_TYPE_CONTROL;
+
+ ++(Device->ControlChannelIdentifier.QuadPart);
+
+ if (Device->ControlChannelIdentifier.QuadPart > MAX_CCID) {
+ Device->ControlChannelIdentifier.QuadPart = 1;
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case IRP_MJ_CLOSE:
+
+ //
+ // The Close function closes a transport endpoint, terminates
+ // all outstanding transport activity on the endpoint, and unbinds
+ // the endpoint from its transport address, if any. If this
+ // is the last transport endpoint bound to the address, then
+ // the address is removed from the provider.
+ //
+
+ switch (Type = ((ULONG)(REQUEST_OPEN_TYPE(Request)) & IPX_CC_MASK)) {
+ default:
+ if ((Type >= ROUTER_ADDRESS_FILE) &&
+ (Type <= (ROUTER_ADDRESS_FILE + IPX_RT_MAX_ADDRESSES)))
+ {
+ CloseRtAddress(Device, Request);
+ }
+ else
+ {
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ // fall through
+ case TDI_TRANSPORT_ADDRESS_FILE:
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ //
+ // This creates a reference to AddressFile->Address
+ // which is removed by IpxCloseAddressFile.
+ //
+
+ Status = IpxVerifyAddressFile(AddressFile);
+
+ if (!NT_SUCCESS (Status)) {
+ Status = STATUS_INVALID_HANDLE;
+ } else {
+ Status = IpxCloseAddressFile (Device, Request);
+ IpxDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ }
+
+ break;
+
+ case IPX_FILE_TYPE_CONTROL:
+ {
+ LARGE_INTEGER ControlChannelId;
+
+ CCID_FROM_REQUEST(ControlChannelId, Request);
+
+ //
+ // See if it is one of the upper driver's control channels.
+ //
+
+ Status = STATUS_SUCCESS;
+
+ IPX_DEBUG (DEVICE, ("CCID: (%d, %d)\n", ControlChannelId.HighPart, ControlChannelId.LowPart));
+
+ for (i = 0; i < UPPER_DRIVER_COUNT; i++) {
+ if (Device->UpperDriverControlChannel[i].QuadPart ==
+ ControlChannelId.QuadPart) {
+ Status = IpxInternalUnbind (Device, i);
+ break;
+ }
+ }
+
+ break;
+ }
+ }
+
+ break;
+
+ case IRP_MJ_CLEANUP:
+
+ //
+ // Handle the two stage IRP for a file close operation. When the first
+ // stage hits, run down all activity on the object of interest. This
+ // do everything to it but remove the creation hold. Then, when the
+ // CLOSE irp hits, actually close the object.
+ //
+
+ switch (Type = ((ULONG)(REQUEST_OPEN_TYPE(Request)) & IPX_CC_MASK)) {
+ default:
+
+ if ((Type >= ROUTER_ADDRESS_FILE) &&
+ (Type <= (ROUTER_ADDRESS_FILE + IPX_RT_MAX_ADDRESSES)))
+ {
+ CleanupRtAddress(Device, Request);
+ }
+ else
+ {
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+
+ //
+ // fall through
+ //
+ case TDI_TRANSPORT_ADDRESS_FILE:
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+ Status = IpxVerifyAddressFile(AddressFile);
+ if (!NT_SUCCESS (Status)) {
+
+ Status = STATUS_INVALID_HANDLE;
+
+ } else {
+
+ IpxStopAddressFile (AddressFile);
+ IpxDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case IPX_FILE_TYPE_CONTROL:
+ {
+ LARGE_INTEGER ControlChannelId;
+
+ CCID_FROM_REQUEST(ControlChannelId, Request);
+
+ //
+ // Check for any line change IRPs submitted by this
+ // address.
+ //
+
+ IpxAbortLineChanges ((PVOID)&ControlChannelId);
+ IpxAbortNtfChanges ((PVOID)&ControlChannelId);
+
+ Status = STATUS_SUCCESS;
+ break;
+ }
+ }
+
+ break;
+
+ default:
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ } /* major function switch */
+
+ if (Status != STATUS_PENDING) {
+ UNMARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = Status;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ return Status;
+
+} /* IpxDispatchOpenClose */
+
+#define IOCTL_IPX_LOAD_SPX _IPX_CONTROL_CODE( 0x5678, METHOD_BUFFERED )
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+ZwLoadDriver(
+ IN PUNICODE_STRING DriverServiceName
+ );
+
+
+NTSTATUS
+IpxDispatchDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE Device = IpxDevice;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (Irp);
+ static NDIS_STRING SpxServiceName = NDIS_STRING_CONST ("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\NwlnkSpx");
+
+ ASSERT( DeviceObject->DeviceExtension == IpxDevice );
+
+ //
+ // Branch to the appropriate request handler. Preliminary checking of
+ // the size of the request block is performed here so that it is known
+ // in the handlers that the minimum input parameters are readable. It
+ // is *not* determined here whether variable length input fields are
+ // passed correctly; this is a check which must be made within each routine.
+ //
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+
+ case IOCTL_TDI_QUERY_DIRECT_SENDDG_HANDLER: {
+
+ PULONG EntryPoint;
+
+ //
+ // This is the LanmanServer trying to get the send
+ // entry point.
+ //
+
+ IPX_DEBUG (BIND, ("Direct send entry point being returned\n"));
+
+ EntryPoint = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+ *EntryPoint = (ULONG)IpxTdiSendDatagram;
+
+ Status = STATUS_SUCCESS;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ break;
+ }
+
+ case IOCTL_IPX_INTERNAL_BIND:
+
+ //
+ // This is a client trying to bind.
+ //
+
+ CTEAssert ((IOCTL_IPX_INTERNAL_BIND & 0x3) == METHOD_BUFFERED);
+ CTEAssert (IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL);
+
+#ifdef _PNP_POWER
+
+ if ((Device->State == DEVICE_STATE_CLOSED) ||
+ (Device->State == DEVICE_STATE_STOPPING)) {
+#else
+ if (Device->State != DEVICE_STATE_OPEN) {
+#endif
+ Status = STATUS_INVALID_DEVICE_STATE;
+
+ } else {
+
+ Status = IpxInternalBind (Device, Irp);
+
+ }
+
+ CTEAssert (Status != STATUS_PENDING);
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ break;
+
+ case IOCTL_IPX_LOAD_SPX:
+
+ //
+ // The SPX helper dll is asking us to load SPX.
+ //
+
+ Status = ZwLoadDriver (&SpxServiceName);
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ break;
+
+#ifdef SNMP
+ case IOCTL_IPX_MIB_GET: {
+
+ //
+ // Get the Base MIB entries out of the device. All Host-side
+ // entries, appearing in the MS and Novell MIBs are returned.
+ //
+ PNOVIPXMIB_BASE UserBuffer;
+
+ UserBuffer = (PNOVIPXMIB_BASE)Irp->AssociatedIrp.SystemBuffer;
+
+ Irp->IoStatus.Information = sizeof(NOVIPXMIB_BASE);
+
+ RtlCopyMemory( UserBuffer,
+ &Device->MibBase,
+ sizeof(NOVIPXMIB_BASE));
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ Status = STATUS_SUCCESS;
+
+ break;
+ }
+#endif SNMP
+
+ case MIPX_SEND_DATAGRAM:
+ MARK_REQUEST_PENDING(Irp);
+ Status = SendIrpFromRt (Device, Irp);
+ if (Status == STATUS_PENDING) {
+ return STATUS_PENDING;
+ } else {
+ UNMARK_REQUEST_PENDING(Irp);
+ REQUEST_STATUS(Irp) = Status;
+ IpxCompleteRequest (Irp);
+ IpxFreeRequest (Device, Irp);
+ return Status;
+ }
+
+ break;
+
+ case MIPX_RCV_DATAGRAM:
+ MARK_REQUEST_PENDING(Irp);
+ Status = RcvIrpFromRt (Device, Irp);
+ if (Status == STATUS_PENDING) {
+ return STATUS_PENDING;
+ } else {
+ UNMARK_REQUEST_PENDING(Irp);
+ REQUEST_STATUS(Irp) = Status;
+ IpxCompleteRequest (Irp);
+ IpxFreeRequest (Device, Irp);
+ return Status;
+ }
+
+ break;
+
+
+ default:
+
+ //
+ // Convert the user call to the proper internal device call.
+ //
+
+ Status = TdiMapUserRequest (DeviceObject, Irp, IrpSp);
+
+ if (Status == STATUS_SUCCESS) {
+
+ //
+ // If TdiMapUserRequest returns SUCCESS then the IRP
+ // has been converted into an IRP_MJ_INTERNAL_DEVICE_CONTROL
+ // IRP, so we dispatch it as usual. The IRP will
+ // be completed by this call.
+ //
+
+ Status = IpxDispatchInternal (DeviceObject, Irp);
+
+ } else {
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ }
+
+ break;
+ }
+ return Status;
+
+} /* IpxDispatchDeviceControl */
+
+
+NTSTATUS
+IpxDispatchInternal (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE Device = IpxDevice;
+ PREQUEST Request;
+
+ ASSERT( DeviceObject->DeviceExtension == IpxDevice );
+
+ if (Device->State == DEVICE_STATE_OPEN) {
+
+ //
+ // Allocate a request to track this IRP.
+ //
+
+ Request = IpxAllocateRequest (Device, Irp);
+
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ MARK_REQUEST_PENDING(Request);
+#if DBG
+ REQUEST_STATUS(Request) = STATUS_PENDING;
+ REQUEST_INFORMATION(Request) = 0;
+#endif
+
+ //
+ // Branch to the appropriate request handler. Preliminary checking of
+ // the size of the request block is performed here so that it is known
+ // in the handlers that the minimum input parameters are readable. It
+ // is *not* determined here whether variable length input fields are
+ // passed correctly; this is a check which must be made within each routine.
+ //
+
+ switch (REQUEST_MINOR_FUNCTION(Request)) {
+
+ case TDI_SEND_DATAGRAM:
+ Status = IpxTdiSendDatagram (DeviceObject, Request);
+ break;
+
+ case TDI_ACTION:
+ Status = IpxTdiAction (Device, Request);
+ break;
+
+ case TDI_QUERY_INFORMATION:
+ Status = IpxTdiQueryInformation (Device, Request);
+ break;
+
+ case TDI_RECEIVE_DATAGRAM:
+ Status = IpxTdiReceiveDatagram (Request);
+ break;
+
+ case TDI_SET_EVENT_HANDLER:
+ Status = IpxTdiSetEventHandler (Request);
+ break;
+
+ case TDI_SET_INFORMATION:
+ Status = IpxTdiSetInformation (Device, Request);
+ break;
+
+
+ //
+ // Something we don't know about was submitted.
+ //
+
+ default:
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ if (Status == STATUS_PENDING) {
+
+ return STATUS_PENDING;
+
+ } else {
+
+ UNMARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = Status;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+ return Status;
+ }
+
+ } else {
+
+ //
+ // The device was not open.
+ //
+
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+} /* IpxDispatchInternal */
+
+
+PVOID
+IpxpAllocateMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN BOOLEAN ChargeDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory, making sure it is within
+ the limit allowed by the device.
+
+Arguments:
+
+ BytesNeeded - The number of bytes to allocated.
+
+ ChargeDevice - TRUE if the device should be charged.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PVOID Memory;
+ PDEVICE Device = IpxDevice;
+
+ if (ChargeDevice) {
+ if ((Device->MemoryLimit != 0) &&
+ (((LONG)(Device->MemoryUsage + BytesNeeded) >
+ Device->MemoryLimit))) {
+
+ IpxPrint1 ("IPX: Could not allocate %d: limit\n", BytesNeeded);
+ IpxWriteResourceErrorLog(
+ Device->DeviceObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ BytesNeeded,
+ Tag);
+
+ return NULL;
+ }
+ }
+
+#if ISN_NT
+ Memory = ExAllocatePoolWithTag (NonPagedPool, BytesNeeded, ' XPI');
+#else
+ Memory = CTEAllocMem (BytesNeeded);
+#endif
+
+ if (Memory == NULL) {
+
+ IpxPrint1("IPX: Could not allocate %d: no pool\n", BytesNeeded);
+ if (ChargeDevice) {
+ IpxWriteResourceErrorLog(
+ Device->DeviceObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ BytesNeeded,
+ Tag);
+ }
+
+ return NULL;
+ }
+
+ if (ChargeDevice) {
+ Device->MemoryUsage += BytesNeeded;
+ }
+
+ return Memory;
+} /* IpxpAllocateMemory */
+
+
+VOID
+IpxpFreeMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN BOOLEAN ChargeDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees memory allocated with IpxpAllocateMemory.
+
+Arguments:
+
+ Memory - The memory allocated.
+
+ BytesAllocated - The number of bytes to freed.
+
+ ChargeDevice - TRUE if the device should be charged.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+
+#if ISN_NT
+ ExFreePool (Memory);
+#else
+ CTEFreeMem (Memory);
+#endif
+ if (ChargeDevice) {
+ Device->MemoryUsage -= BytesAllocated;
+ }
+
+} /* IpxpFreeMemory */
+
+#if DBG
+
+
+PVOID
+IpxpAllocateTaggedMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory, charging it to the device.
+ If it cannot allocate memory it uses the Tag and Descriptor
+ to log an error.
+
+Arguments:
+
+ BytesNeeded - The number of bytes to allocated.
+
+ Tag - A unique ID used in the error log.
+
+ Description - A text description of the allocation.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PVOID Memory;
+
+ UNREFERENCED_PARAMETER(Description);
+
+ Memory = IpxpAllocateMemory(BytesNeeded, Tag, (BOOLEAN)(Tag != MEMORY_CONFIG));
+
+ if (Memory) {
+ (VOID)IPX_ADD_ULONG(
+ &IpxMemoryTag[Tag].BytesAllocated,
+ BytesNeeded,
+ &IpxMemoryInterlock);
+ }
+
+ return Memory;
+
+} /* IpxpAllocateTaggedMemory */
+
+
+VOID
+IpxpFreeTaggedMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees memory allocated with IpxpAllocateTaggedMemory.
+
+Arguments:
+
+ Memory - The memory allocated.
+
+ BytesAllocated - The number of bytes to freed.
+
+ Tag - A unique ID used in the error log.
+
+ Description - A text description of the allocation.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UNREFERENCED_PARAMETER(Description);
+
+ (VOID)IPX_ADD_ULONG(
+ &IpxMemoryTag[Tag].BytesAllocated,
+ (ULONG)(-(LONG)BytesAllocated),
+ &IpxMemoryInterlock);
+
+ IpxpFreeMemory (Memory, BytesAllocated, (BOOLEAN)(Tag != MEMORY_CONFIG));
+
+} /* IpxpFreeTaggedMemory */
+
+#endif
+
+
+VOID
+IpxWriteResourceErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry which has
+ a %3 value that needs to be converted to a string. It is currently
+ used for EVENT_TRANSPORT_RESOURCE_POOL and EVENT_IPX_INTERNAL_NET_
+ INVALID.
+
+Arguments:
+
+ DeviceObject - Pointer to the system device object.
+
+ ErrorCode - The transport event code.
+
+ BytesNeeded - If applicable, the number of bytes that could not
+ be allocated -- will be put in the dump data.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet and converted for use as the %3 string.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ PUCHAR StringLoc;
+ ULONG TempUniqueError;
+ PDEVICE Device = IpxDevice;
+ static WCHAR UniqueErrorBuffer[9] = L"00000000";
+ UINT CurrentDigit;
+ INT i;
+
+
+ //
+ // Convert the error value into a buffer.
+ //
+
+ TempUniqueError = UniqueErrorValue;
+ i = 8;
+ do {
+ CurrentDigit = TempUniqueError & 0xf;
+ TempUniqueError >>= 4;
+ i--;
+ if (CurrentDigit >= 0xa) {
+ UniqueErrorBuffer[i] = (WCHAR)(CurrentDigit - 0xa + L'A');
+ } else {
+ UniqueErrorBuffer[i] = (WCHAR)(CurrentDigit + L'0');
+ }
+ } while (TempUniqueError);
+
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ Device->DeviceNameLength +
+ sizeof(UniqueErrorBuffer) - (i * sizeof(WCHAR));
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ DeviceObject,
+ EntrySize
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = sizeof(ULONG);
+ errorLogEntry->NumberOfStrings = 2;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+ errorLogEntry->DumpData[0] = BytesNeeded;
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
+
+ StringLoc += Device->DeviceNameLength;
+ RtlCopyMemory (StringLoc, UniqueErrorBuffer + i, sizeof(UniqueErrorBuffer) - (i * sizeof(WCHAR)));
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* IpxWriteResourceErrorLog */
+
+
+VOID
+IpxWriteGeneralErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN ULONG DumpDataCount,
+ IN ULONG DumpData[]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ a general problem as indicated by the parameters. It handles
+ event codes REGISTER_FAILED, BINDING_FAILED, ADAPTER_NOT_FOUND,
+ TRANSFER_DATA, TOO_MANY_LINKS, and BAD_PROTOCOL. All these
+ events have messages with one or two strings in them.
+
+Arguments:
+
+ DeviceObject - Pointer to the system device object, or this may be
+ a driver object instead.
+
+ ErrorCode - The transport event code.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet.
+
+ FinalStatus - Used as the FinalStatus in the error log packet.
+
+ SecondString - If not NULL, the string to use as the %3
+ value in the error log packet.
+
+ DumpDataCount - The number of ULONGs of dump data.
+
+ DumpData - Dump data for the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG SecondStringSize;
+ PUCHAR StringLoc;
+ PDEVICE Device = IpxDevice;
+ static WCHAR DriverName[9] = L"NwlnkIpx";
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ (DumpDataCount * sizeof(ULONG));
+
+ if (DeviceObject->Type == IO_TYPE_DEVICE) {
+ EntrySize += (UCHAR)Device->DeviceNameLength;
+ } else {
+ EntrySize += sizeof(DriverName);
+ }
+
+ if (SecondString) {
+ SecondStringSize = (wcslen(SecondString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize += (UCHAR)SecondStringSize;
+ }
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ DeviceObject,
+ EntrySize
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = (USHORT)(DumpDataCount * sizeof(ULONG));
+ errorLogEntry->NumberOfStrings = (SecondString == NULL) ? 1 : 2;
+ errorLogEntry->StringOffset =
+ sizeof(IO_ERROR_LOG_PACKET) + ((DumpDataCount-1) * sizeof(ULONG));
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ if (DumpDataCount) {
+ RtlCopyMemory(errorLogEntry->DumpData, DumpData, DumpDataCount * sizeof(ULONG));
+ }
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ if (DeviceObject->Type == IO_TYPE_DEVICE) {
+ RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
+ StringLoc += Device->DeviceNameLength;
+ } else {
+ RtlCopyMemory (StringLoc, DriverName, sizeof(DriverName));
+ StringLoc += sizeof(DriverName);
+ }
+ if (SecondString) {
+ RtlCopyMemory (StringLoc, SecondString, SecondStringSize);
+ }
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* IpxWriteGeneralErrorLog */
+
+
+VOID
+IpxWriteOidErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR AdapterString,
+ IN ULONG OidValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ a problem querying or setting an OID on an adapter. It handles
+ event codes SET_OID_FAILED and QUERY_OID_FAILED.
+
+Arguments:
+
+ DeviceObject - Pointer to the system device object.
+
+ ErrorCode - Used as the ErrorCode in the error log packet.
+
+ FinalStatus - Used as the FinalStatus in the error log packet.
+
+ AdapterString - The name of the adapter we were bound to.
+
+ OidValue - The OID which could not be set or queried.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG AdapterStringSize;
+ PUCHAR StringLoc;
+ PDEVICE Device = IpxDevice;
+ static WCHAR OidBuffer[9] = L"00000000";
+ INT i;
+ UINT CurrentDigit;
+
+ AdapterStringSize = (wcslen(AdapterString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) -
+ sizeof(ULONG) +
+ Device->DeviceNameLength +
+ AdapterStringSize +
+ sizeof(OidBuffer);
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ DeviceObject,
+ EntrySize
+ );
+
+ //
+ // Convert the OID into a buffer.
+ //
+
+ for (i=7; i>=0; i--) {
+ CurrentDigit = OidValue & 0xf;
+ OidValue >>= 4;
+ if (CurrentDigit >= 0xa) {
+ OidBuffer[i] = (WCHAR)(CurrentDigit - 0xa + L'A');
+ } else {
+ OidBuffer[i] = (WCHAR)(CurrentDigit + L'0');
+ }
+ }
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = 0;
+ errorLogEntry->NumberOfStrings = 3;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) - sizeof(ULONG);
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
+ StringLoc += Device->DeviceNameLength;
+
+ RtlCopyMemory (StringLoc, OidBuffer, sizeof(OidBuffer));
+ StringLoc += sizeof(OidBuffer);
+
+ RtlCopyMemory (StringLoc, AdapterString, AdapterStringSize);
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* IpxWriteOidErrorLog */
+
+
+#ifdef _PNP_POWER
+VOID
+IpxPnPUpdateDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ Updates datagram sizes, lookahead sizes, etc. in the Device as a result
+ of a new binding coming in.
+
+Arguments:
+
+ Device - The IPX device object.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG AnnouncedMaxDatagram, RealMaxDatagram, MaxLookahead;
+ ULONG LinkSpeed, MacOptions;
+ ULONG i;
+ PBINDING Binding;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ IPX_GET_LOCK(&Device->BindAccessLock, &LockHandle);
+
+ //
+ // Calculate some values based on all the bindings.
+ //
+
+ MaxLookahead = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->MaxLookaheadData; // largest binding value
+ AnnouncedMaxDatagram = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->AnnouncedMaxDatagramSize; // smallest binding value
+ RealMaxDatagram = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->RealMaxDatagramSize; // smallest binding value
+
+ if (NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->LineUp) {
+ LinkSpeed = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->MediumSpeed; // smallest binding value
+ } else {
+ LinkSpeed = 0xffffffff;
+ }
+ MacOptions = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->Adapter->MacInfo.MacOptions; // AND of binding values
+
+ for (i = 2; i <= Device->ValidBindings; i++) {
+
+ Binding = NIC_ID_TO_BINDING_NO_ILOCK(Device, i);
+
+ if (!Binding) {
+ continue;
+ }
+
+ if (Binding->MaxLookaheadData > MaxLookahead) {
+ MaxLookahead = Binding->MaxLookaheadData;
+ }
+ if (Binding->AnnouncedMaxDatagramSize < AnnouncedMaxDatagram) {
+ AnnouncedMaxDatagram = Binding->AnnouncedMaxDatagramSize;
+ }
+ if (Binding->RealMaxDatagramSize < RealMaxDatagram) {
+ RealMaxDatagram = Binding->RealMaxDatagramSize;
+ }
+
+ if (Binding->LineUp && (Binding->MediumSpeed < LinkSpeed)) {
+ LinkSpeed = Binding->MediumSpeed;
+ }
+ MacOptions &= Binding->Adapter->MacInfo.MacOptions;
+
+ }
+
+ Device->Information.MaxDatagramSize = AnnouncedMaxDatagram;
+ Device->RealMaxDatagramSize = RealMaxDatagram;
+ Device->Information.MaximumLookaheadData = MaxLookahead;
+
+ //
+ // If we couldn't find anything better, use the speed from
+ // the first binding.
+ //
+
+ if (LinkSpeed == 0xffffffff) {
+ Device->LinkSpeed = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->MediumSpeed;
+ } else {
+ Device->LinkSpeed = LinkSpeed;
+ }
+ Device->MacOptions = MacOptions;
+
+ IPX_FREE_LOCK(&Device->BindAccessLock, LockHandle);
+}
+
+VOID
+IpxPnPUpdateBindingArray(
+ IN PDEVICE Device,
+ IN PADAPTER Adapter,
+ IN PBINDING_CONFIG ConfigBinding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to update the binding array to
+ add the new bindings that appeared in this PnP event.
+ The order of bindings in the array is as follows:
+
+ - First comes the first binding to each LAN network
+ - Following that are all WAN bindings
+ - Following that are any duplicate bindings to LAN networks
+ (the others in the "binding set").
+
+ This routine inserts the bindings while maintaining this
+ order by resolving binding sets.
+
+ The bindings are also inserted into the RIP database.
+
+ If "global wan net" is true we will advertise up to
+ and including the first wan binding as the highest nic
+ id; otherwise we advertise up to and including the last
+ wan binding. In all cases the duplicate bindings are
+ hidden.
+
+ Updates the SapNicCount, Device->FirstLanNicId and Device->FirstWanNicId
+
+Arguments:
+
+ Device - The IPX device object.
+
+ Adapter - The adapter added in this PnP event
+
+ ValidBindings - the number of bindings valid for this adapter (if LAN)
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG i, j;
+ PBINDING Binding, MasterBinding;
+ NTSTATUS status;
+
+ //
+ // Insert in proper place; if WAN, after all the WAN bindings
+ // If LAN, check for binding sets and insert in proper place
+ // Also, insert into the Rip Tables.
+ //
+
+ //
+ // Go thru' the bindings for this adapter, inserting into the
+ // binding array in place
+ //
+ for (i = 0; i < ConfigBinding->FrameTypeCount; i++) {
+ ULONG MappedFrameType;
+
+ //
+ // Store in the preference order.
+ // Map the frame types since we could have a case where the user selects a FrameType (say, EthernetII on FDDI)
+ // which maps to a different FrameType (802.2). Then we would fail to find the binding in the adapter array;
+ // we could potentialy add a binding twice (if two frame types map to the same Frame, then we would go to the
+ // mapped one twice). This is taken care of by purging dups from the ConfigBinding->FrameType array when we
+ // create the bindings off of the Adapter (see call to IpxBindToAdapter).
+ //
+
+ MacMapFrameType(
+ Adapter->MacInfo.RealMediumType,
+ ConfigBinding->FrameType[i],
+ &MappedFrameType);
+
+ Binding = Adapter->Bindings[MappedFrameType];
+
+ if (!Binding){
+ continue;
+ }
+
+ CTEAssert(Binding->FrameType == MappedFrameType);
+
+ Binding->fInfoIndicated = FALSE;
+
+ if (Adapter->MacInfo.MediumAsync) {
+ PBINDING DemandDialBinding;
+
+ //
+ // WAN: Place after the HighestExternalNicId, with space for WanLine # of bindings.
+ // Update the First/LastWanNicId.
+ //
+ Adapter->FirstWanNicId = (USHORT)Device->HighestExternalNicId+1;
+ Adapter->LastWanNicId = (USHORT)(Device->HighestExternalNicId + Adapter->WanNicIdCount);
+
+ //
+ // Make sure we dont overflow the array
+ // Re-alloc the array to fit the new bindings
+ //
+ if (Device->ValidBindings+Adapter->WanNicIdCount >= Device->MaxBindings) {
+ status = IpxPnPReallocateBindingArray(Device, Adapter->WanNicIdCount);
+ CTEAssert(status == STATUS_SUCCESS);
+ }
+
+ //
+ // Move Slaves down by WanNicIdCount# of entries
+ //
+ for (j = Device->ValidBindings; j > Device->HighestExternalNicId; j--) {
+ INSERT_BINDING(Device, j+Adapter->WanNicIdCount, NIC_ID_TO_BINDING_NO_ILOCK(Device, j));
+ if (NIC_ID_TO_BINDING_NO_ILOCK(Device, j+Adapter->WanNicIdCount)) {
+ NIC_ID_TO_BINDING_NO_ILOCK(Device, j+Adapter->WanNicIdCount)->NicId += (USHORT)Adapter->WanNicIdCount;
+ }
+ }
+
+ //
+ // Insert the WAN binding in the place just allocated
+ //
+ INSERT_BINDING(Device, Device->HighestExternalNicId+1, Binding);
+ SET_VERSION(Device, Device->HighestExternalNicId+1);
+
+ Binding->NicId = (USHORT)Device->HighestExternalNicId+1;
+
+ //
+ // Update the indices
+ //
+ Device->HighestExternalNicId += (USHORT)Adapter->WanNicIdCount;
+ Device->ValidBindings += (USHORT)Adapter->WanNicIdCount;
+ Device->BindingCount += (USHORT)Adapter->WanNicIdCount;
+ Device->SapNicCount++;
+
+ //
+ // Since we initialize FirstWanNicId to 1, we need to compare against that.
+ // In case of no LAN bindings, we are fine since we have only one WAN binding initally
+ // (all the other WAN lines have place holders).
+ //
+ if (Device->FirstWanNicId == (USHORT)1) {
+ Device->FirstWanNicId = Binding->NicId;
+ }
+
+ //
+ // Prime the DemandDial binding too.
+ //
+
+ //
+ // First allocate the memory for the binding.
+ //
+ status = IpxCreateBinding(
+ Device,
+ NULL,
+ 0,
+ Adapter->AdapterName,
+ &DemandDialBinding);
+
+ if (status != STATUS_SUCCESS) {
+ CTEAssert(FALSE);
+ }
+
+ //
+ // Copy over all the values from the first WAN binding created above.
+ //
+ RtlCopyMemory(DemandDialBinding, Binding, sizeof(BINDING));
+ INSERT_BINDING(Device, (SHORT)DEMAND_DIAL_ADAPTER_CONTEXT, DemandDialBinding);
+ DemandDialBinding->NicId = (USHORT)DEMAND_DIAL_ADAPTER_CONTEXT;
+ DemandDialBinding->FwdAdapterContext = INVALID_CONTEXT_VALUE;
+ IpxReferenceBinding(DemandDialBinding, BREF_FWDOPEN); // so it appears the FWD opened it.
+
+ //
+ // BUGBUGZZ Make this inline later
+ //
+ // This should be done after all the auto-detect bindings have been thrown away.
+ //
+ // IpxPnPUpdateDevice(Device, Binding);
+
+ //
+ // Since WAN can have only one frame type, break
+ //
+ break;
+
+ } else {
+
+ Device->BindingCount++;
+
+ //
+ // Make sure we dont overflow the array
+ // Re-alloc the array to fit the new bindings
+ //
+ if (Device->ValidBindings+1 >= Device->MaxBindings) {
+ status = IpxPnPReallocateBindingArray(Device, 1);
+ CTEAssert(status == STATUS_SUCCESS);
+ }
+
+ //
+ // LAN: Figure out if it is a slave binding only for non-auto-detect bindings.
+ //
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (j = 1; j < Index; j++) {
+ MasterBinding = NIC_ID_TO_BINDING_NO_ILOCK(Device, j);
+ if (MasterBinding &&
+ (MasterBinding->ConfiguredNetworkNumber) &&
+ (MasterBinding->ConfiguredNetworkNumber == Binding->ConfiguredNetworkNumber) &&
+ (MasterBinding->FrameType == Binding->FrameType) &&
+ (MasterBinding->Adapter->MacInfo.MediumType == Binding->Adapter->MacInfo.MediumType)) {
+
+ CTEAssert(Binding->ConfiguredNetworkNumber);
+ break;
+ }
+ }
+ }
+
+ if (j < Device->HighestExternalNicId) {
+ //
+ // Slave binding
+ //
+
+ //
+ // Now make MasterBinding the head of a binding set.
+ //
+
+ if (MasterBinding->BindingSetMember) {
+
+ //
+ // Just insert ourselves in the chain.
+ //
+
+#if DBG
+ DbgPrint ("IPX: %ws is also on network %lx\n",
+ Binding->Adapter->AdapterName,
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+#endif
+ IPX_DEBUG (AUTO_DETECT, ("Add %lx to binding set of %lx\n", Binding, MasterBinding));
+
+ CTEAssert (MasterBinding->CurrentSendBinding);
+ Binding->NextBinding = MasterBinding->NextBinding;
+
+ } else {
+
+ //
+ // Start the chain with the two bindings in it.
+ //
+
+#if DBG
+ DbgPrint ("IPX: %lx and %lx are on the same network %lx, will load balance\n",
+ MasterBinding->Adapter->AdapterName, Binding->Adapter->AdapterName,
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+#endif
+ IPX_DEBUG (AUTO_DETECT, ("Create new %lx in binding set of %lx\n", Binding, MasterBinding));
+
+ MasterBinding->BindingSetMember = TRUE;
+ MasterBinding->CurrentSendBinding = MasterBinding;
+ MasterBinding->MasterBinding = MasterBinding;
+ Binding->NextBinding = MasterBinding;
+
+ }
+
+ MasterBinding->NextBinding = Binding;
+ Binding->BindingSetMember = TRUE;
+ Binding->ReceiveBroadcast = FALSE;
+ Binding->CurrentSendBinding = NULL;
+ Binding->MasterBinding = MasterBinding;
+
+ //
+ // Since the master binding looks like all members of
+ // the binding set to people querying from above, we have
+ // to make it the worst-case of all the elements. Generally
+ // these will be equal since the frame type and media is
+ // the same.
+ //
+
+ if (Binding->MaxLookaheadData > MasterBinding->MaxLookaheadData) {
+ MasterBinding->MaxLookaheadData = Binding->MaxLookaheadData;
+ }
+ if (Binding->AnnouncedMaxDatagramSize < MasterBinding->AnnouncedMaxDatagramSize) {
+ MasterBinding->AnnouncedMaxDatagramSize = Binding->AnnouncedMaxDatagramSize;
+ }
+ if (Binding->RealMaxDatagramSize < MasterBinding->RealMaxDatagramSize) {
+ MasterBinding->RealMaxDatagramSize = Binding->RealMaxDatagramSize;
+ }
+ if (Binding->MediumSpeed < MasterBinding->MediumSpeed) {
+ MasterBinding->MediumSpeed = Binding->MediumSpeed;
+ }
+
+ //
+ // Place the binding after the last slave binding
+ //
+ INSERT_BINDING(Device, Device->ValidBindings+1, Binding);
+ SET_VERSION(Device, Device->ValidBindings+1);
+
+ Binding->NicId = (USHORT)Device->ValidBindings+1;
+
+ //
+ // Update the indices
+ //
+ Device->ValidBindings++;
+
+ } else {
+
+ PBINDING WanBinding=NIC_ID_TO_BINDING_NO_ILOCK(Device, Device->HighestLanNicId+1);
+
+ if (WanBinding) {
+ WanBinding->Adapter->LastWanNicId++;
+ WanBinding->Adapter->FirstWanNicId++;
+ }
+
+ //
+ // Not a binding set slave binding - just add it after the last LAN binding
+ //
+
+ //
+ // Move WAN and Slaves down by 1 entry
+ //
+ for (j = Device->ValidBindings; j > Device->HighestLanNicId; j--) {
+ INSERT_BINDING(Device, j+1, NIC_ID_TO_BINDING_NO_ILOCK(Device, j));
+ if (NIC_ID_TO_BINDING_NO_ILOCK(Device, j+1)) {
+ NIC_ID_TO_BINDING_NO_ILOCK(Device, j+1)->NicId++;
+ }
+ }
+
+ //
+ // Increment the WAN counters in the adapter.
+ //
+
+
+ //
+ // Insert the LAN binding in the place just allocated
+ //
+ INSERT_BINDING(Device, Device->HighestLanNicId+1, Binding);
+ SET_VERSION(Device, Device->HighestLanNicId+1);
+ Binding->NicId = (USHORT)Device->HighestLanNicId+1;
+
+ //
+ // Update the indices
+ //
+ Device->HighestLanNicId++;
+ Device->HighestExternalNicId++;
+ Device->ValidBindings++;
+ Device->HighestType20NicId++;
+ Device->SapNicCount++;
+
+ if (Device->FirstLanNicId == (USHORT)-1) {
+ Device->FirstLanNicId = Binding->NicId;
+ }
+
+ if (!NIC_ID_TO_BINDING(Device, (SHORT)LOOPBACK_NIC_ID)) {
+ PBINDING LoopbackBinding;
+
+ //
+ // Prime the Loopback binding too.
+ //
+
+ //
+ // First allocate the memory for the binding.
+ //
+ status = IpxCreateBinding(
+ Device,
+ NULL,
+ 0,
+ Adapter->AdapterName,
+ &LoopbackBinding);
+
+ if (status != STATUS_SUCCESS) {
+ CTEAssert(FALSE);
+ }
+
+ //
+ // Copy over all the values from the first WAN binding created above.
+ //
+ RtlCopyMemory(LoopbackBinding, Binding, sizeof(BINDING));
+ INSERT_BINDING(Device, (SHORT)LOOPBACK_NIC_ID, LoopbackBinding);
+ LoopbackBinding->NicId = (USHORT)LOOPBACK_NIC_ID;
+ LoopbackBinding->FwdAdapterContext = VIRTUAL_NET_FORWARDER_CONTEXT;
+ IpxReferenceBinding(LoopbackBinding, BREF_FWDOPEN); // so it appears the FWD opened it.
+ }
+ }
+
+ }
+
+ //
+ // Insert this binding in the RIP Tables
+ //
+ if (Binding->ConfiguredNetworkNumber != 0) {
+ status = RipInsertLocalNetwork(
+ Binding->ConfiguredNetworkNumber,
+ Binding->NicId,
+ Binding->Adapter->NdisBindingHandle,
+ (USHORT)((839 + Binding->Adapter->MediumSpeed) / Binding->Adapter->MediumSpeed));
+
+ if ((status == STATUS_SUCCESS) ||
+ (status == STATUS_DUPLICATE_NAME)) {
+
+ Binding->LocalAddress.NetworkAddress = Binding->ConfiguredNetworkNumber;
+ }
+ }
+
+ //
+ // BUGBUGZZ Make this inline later
+ //
+ // This should be done after all the auto-detect bindings have been thrown away.
+ //
+ // IpxPnPUpdateDevice(Device, Binding);
+ }
+} /* IpxPnPUpdateBindingArray */
+
+
+VOID
+IpxPnPToLoad()
+/*++
+
+Routine Description:
+
+ This routine takes the driver to LOADED state (from OPEN) when all
+ PnP adapters have been removed from the machine.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None. When the function returns, the driver is in LOADED state.
+
+--*/
+
+{
+ PBINDING Binding;
+ PREQUEST Request;
+ PLIST_ENTRY p;
+ UINT i;
+ NTSTATUS ntStatus;
+
+ IPX_DEBUG(PNP, ("Going back to loaded state\n"));
+
+ //
+ // Inform TDI clients about the close of our device object.
+ //
+ if ((ntStatus = TdiDeregisterDeviceObject(IpxDevice->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("TdiDeRegisterDeviceObject failed: %lx", ntStatus));
+ }
+
+ //
+ // Complete any pending address notify requests.
+ //
+
+ while ((p = ExInterlockedRemoveHeadList(
+ &IpxDevice->AddressNotifyQueue,
+ &IpxDevice->Lock)) != NULL) {
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+ REQUEST_STATUS(Request) = STATUS_DEVICE_NOT_READY;
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (IpxDevice, Request);
+
+ IpxDereferenceDevice (IpxDevice, DREF_ADDRESS_NOTIFY);
+ }
+
+ //
+ // Cancel the source routing timer if used.
+ //
+
+ if (IpxDevice->SourceRoutingUsed) {
+
+ IpxDevice->SourceRoutingUsed = FALSE;
+ if (CTEStopTimer (&IpxDevice->SourceRoutingTimer)) {
+ IpxDereferenceDevice (IpxDevice, DREF_SR_TIMER);
+ }
+ }
+
+
+ //
+ // Cancel the RIP long timer, and if we do that then
+ // send a RIP DOWN message if needed.
+ //
+
+ if (CTEStopTimer (&IpxDevice->RipLongTimer)) {
+
+ if (IpxDevice->RipResponder) {
+
+ if (RipQueueRequest (IpxDevice->VirtualNetworkNumber, RIP_DOWN) == STATUS_PENDING) {
+
+ //
+ // If we queue a request, it will stop the timer.
+ //
+
+ KeWaitForSingleObject(
+ &IpxDevice->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+ }
+ }
+
+ IpxDereferenceDevice (IpxDevice, DREF_LONG_TIMER);
+
+ } else {
+
+ //
+ // We couldn't stop the timer, which means it is running,
+ // so we need to wait for the event that is kicked when
+ // the RIP DOWN messages are done.
+ //
+
+ if (IpxDevice->RipResponder) {
+
+ KeWaitForSingleObject(
+ &IpxDevice->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+ }
+ }
+} /* IpxPnPToLoad */
+
+
+NTSTATUS
+IpxPnPReallocateBindingArray(
+ IN PDEVICE Device,
+ IN ULONG Size
+ )
+/*++
+
+Routine Description:
+
+ This routine reallocates the binding array when the number of bindings go above
+ Device->MaxBindings.
+
+Arguments:
+
+ Device - pointer to the device.
+ Size - the number of new entries required.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PBIND_ARRAY_ELEM BindingArray;
+ PBIND_ARRAY_ELEM OldBindingArray;
+ ULONG Pad=2; // extra bindings we keep around
+ ULONG NewSize = Size + Pad + Device->MaxBindings;
+
+ //
+ // The absolute max WAN bindings.
+ //
+ CTEAssert(Size < 2048);
+
+ //
+ // Re-allocate the new array
+ //
+ BindingArray = (PBIND_ARRAY_ELEM)IpxAllocateMemory (
+ NewSize * sizeof(BIND_ARRAY_ELEM),
+ MEMORY_BINDING,
+ "Binding array");
+
+ if (BindingArray == NULL) {
+ IpxWriteGeneralErrorLog(
+ (PVOID)Device->DeviceObject,
+ EVENT_IPX_NO_ADAPTERS,
+ 802,
+ STATUS_DEVICE_DOES_NOT_EXIST,
+ NULL,
+ 0,
+ NULL);
+ IpxDereferenceDevice (Device, DREF_CREATE);
+
+ DbgPrint ("Failed to allocate memory in binding array expansion\n");
+
+ //
+ // Unload the driver here? In case of WAN, we can tolerate this failure. What about LAN? [BUGBUGZZ]
+ //
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory (BindingArray, NewSize * sizeof(BIND_ARRAY_ELEM));
+
+ //
+ // Backup the pointer to free the demand dial location.
+ //
+ OldBindingArray = Device->Bindings - EXTRA_BINDINGS;
+
+ //
+ // Copy the old array into the new one.
+ //
+ RtlCopyMemory (BindingArray, OldBindingArray, (Device->ValidBindings+1+EXTRA_BINDINGS) * sizeof(BIND_ARRAY_ELEM));
+
+ //
+ // Free the old one.
+ //
+ IpxFreeMemory ( OldBindingArray,
+ (Device->MaxBindings+EXTRA_BINDINGS) * sizeof(BIND_ARRAY_ELEM),
+ MEMORY_BINDING,
+ "Binding array");
+
+ IPX_DEBUG(PNP, ("Expand bindarr old: %lx, new: %lx, oldsize: %lx\n",
+ Device->Bindings, BindingArray, Device->MaxBindings));
+
+
+ //
+ // We keep BindingArray[-1] as a placeholder for demand dial bindings.
+ // This NicId is returned by the Fwd when a FindRoute is done on a demand
+ // dial Nic. At the time of the InternalSend, the true Nic is returned.
+ // We create a placeholder here to avoid special checks in the critical send path.
+ //
+ // NOTE: we need to free this demand dial binding as well as ensure that the
+ // true binding array pointer is freed at Device Destroy time.
+ //
+ //
+ // Increment beyond the first pointer - we will refer to the just incremented
+ // one as Device->Bindings[-1].
+ //
+ BindingArray += EXTRA_BINDINGS;
+
+ //
+ // Use interlocked exchange to assign this since we dont take the BindAccessLock anymore.
+ //
+ // Device->Bindings = BindingArray;
+ SET_VALUE(Device->Bindings, BindingArray);
+
+ Device->MaxBindings = (USHORT)NewSize - EXTRA_BINDINGS;
+
+ return STATUS_SUCCESS;
+}
+#endif _PNP_POWER
+
diff --git a/private/ntos/tdi/isn/ipx/event.c b/private/ntos/tdi/isn/ipx/event.c
new file mode 100644
index 000000000..a64f85d34
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/event.c
@@ -0,0 +1,143 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ event.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiSetEventHandler
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports
+
+ 1. Added a new event type - TDI_EVENT_CHAINED_RECEIVE_DATAGRAM
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+NTSTATUS
+IpxTdiSetEventHandler(
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetEventHandler request for the
+ transport provider. The caller (request dispatcher) verifies
+ that this routine will not be executed on behalf of a user-mode
+ client, as this request enables direct callouts at DISPATCH_LEVEL.
+
+Arguments:
+
+ Request - Pointer to the request
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ CTELockHandle LockHandle;
+ PTDI_REQUEST_KERNEL_SET_EVENT Parameters;
+ PADDRESS_FILE AddressFile;
+
+ //
+ // Get the Address this is associated with; if there is none, get out.
+ //
+
+ AddressFile = REQUEST_OPEN_CONTEXT(Request);
+ Status = IpxVerifyAddressFile (AddressFile);
+
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ CTEGetLock (&AddressFile->Address->Lock, &LockHandle);
+
+ Parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)REQUEST_PARAMETERS(Request);
+
+ switch (Parameters->EventType) {
+
+ case TDI_EVENT_RECEIVE_DATAGRAM:
+
+ if (Parameters->EventHandler == NULL) {
+ AddressFile->ReceiveDatagramHandler =
+ (PTDI_IND_RECEIVE_DATAGRAM)TdiDefaultRcvDatagramHandler;
+ AddressFile->ReceiveDatagramHandlerContext = NULL;
+ AddressFile->RegisteredReceiveDatagramHandler = FALSE;
+ } else {
+ AddressFile->ReceiveDatagramHandler =
+ (PTDI_IND_RECEIVE_DATAGRAM)Parameters->EventHandler;
+ AddressFile->ReceiveDatagramHandlerContext = Parameters->EventContext;
+ AddressFile->RegisteredReceiveDatagramHandler = TRUE;
+ }
+
+ break;
+ //
+ // [SA] New event handler to receive chained buffers
+ //
+ case TDI_EVENT_CHAINED_RECEIVE_DATAGRAM:
+
+ if (Parameters->EventHandler == NULL) {
+ AddressFile->ChainedReceiveDatagramHandler =
+ (PTDI_IND_CHAINED_RECEIVE_DATAGRAM)TdiDefaultChainedRcvDatagramHandler;
+ AddressFile->ChainedReceiveDatagramHandlerContext = NULL;
+ AddressFile->RegisteredChainedReceiveDatagramHandler = FALSE;
+ } else {
+ AddressFile->ChainedReceiveDatagramHandler =
+ (PTDI_IND_CHAINED_RECEIVE_DATAGRAM)Parameters->EventHandler;
+ AddressFile->ChainedReceiveDatagramHandlerContext = Parameters->EventContext;
+ AddressFile->RegisteredChainedReceiveDatagramHandler = TRUE;
+ }
+
+ break;
+
+ case TDI_EVENT_ERROR:
+
+ if (Parameters->EventHandler == NULL) {
+ AddressFile->ErrorHandler =
+ (PTDI_IND_ERROR)TdiDefaultErrorHandler;
+ AddressFile->ErrorHandlerContext = NULL;
+ AddressFile->RegisteredErrorHandler = FALSE;
+ } else {
+ AddressFile->ErrorHandler =
+ (PTDI_IND_ERROR)Parameters->EventHandler;
+ AddressFile->ErrorHandlerContext = Parameters->EventContext;
+ AddressFile->RegisteredErrorHandler = TRUE;
+ }
+
+ break;
+
+ default:
+
+ Status = STATUS_INVALID_PARAMETER;
+
+ } /* switch */
+
+ CTEFreeLock (&AddressFile->Address->Lock, LockHandle);
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ REQUEST_INFORMATION(Request) = 0;
+
+ return Status;
+
+} /* IpxTdiSetEventHandler */
+
diff --git a/private/ntos/tdi/isn/ipx/ind.c b/private/ntos/tdi/isn/ipx/ind.c
new file mode 100644
index 000000000..c670c3a59
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/ind.c
@@ -0,0 +1,4417 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ ind.c
+
+Abstract:
+
+ This module contains code which implements the indication handler
+ for the IPX transport provider.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports
+
+ 1. Added IpxReceivePacket which receives buffers that can be owned
+ 2. Changed IpxReceiveIndication to call a new function IpxReceiveIndicationCommon
+ which takes an extra parameter to indicate whether this is a chained receive or
+ not.
+ 3. Changed IpxProcessDatagram to take the MDL ptr to indicate chained receive,
+ a client count and the headerbuffersize as params.
+
+ Sanjay Anand (SanjayAn) 27-Oct-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// This is declared here so it will be in the same function
+// as IpxReceiveIndication and we can inline it.
+//
+
+
+#if defined(_M_IX86)
+_inline
+#endif
+VOID
+IpxProcessDatagram(
+ IN PDEVICE Device,
+ IN PADAPTER Adapter,
+ IN PBINDING Binding,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_DATAGRAM_OPTIONS DatagramOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize,
+ IN BOOLEAN Broadcast,
+ IN PINT pTdiClientCount,
+ IN UINT HeaderBufferSize,
+ IN PMDL pMdl,
+ IN NDIS_HANDLE BindingContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routing handles incoming IPX datagrams.
+
+Arguments:
+
+ Device - The IPX device.
+
+ Adapter - The adapter the frame was received on.
+
+ Binding - The binding of the adapter it was received on.
+
+ MacReceiveContext - The context to use when calling
+ NdisTransferData.
+
+ DatagramOptions - Contains the datagram options, which
+ consists of room for the packet type, padding, and
+ the local target of the remote the frame was received from.
+
+ LookaheadBuffer - The lookahead data.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The length of the packet, starting at the IPX
+ header.
+
+ Broadcast - TRUE if the packet was broadcast.
+
+ pTdiClientCount - to return count of the number of TDI clients above us
+ so NDIS can obtain that many ref counts on the buffer.
+
+ HeaderBufferSize - the size of the MAC header buffer - used to determine
+ the offsets into the TSDU.
+
+ pMdl - Mdl chain pointer - non-NULL if chained receive
+
+ BindingContext - In case of loopback, this contains IPX_LOOPBACK_COOKIE
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ PIPX_HEADER IpxHeader = (PIPX_HEADER)LookaheadBuffer;
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ PADDRESS_FILE ReferencedAddressFile;
+ PREQUEST Request;
+ PIPX_RECEIVE_BUFFER ReceiveBuffer;
+ PTDI_CONNECTION_INFORMATION DatagramInformation;
+ TDI_ADDRESS_IPX UNALIGNED * DatagramAddress;
+ ULONG IndicateBytesCopied;
+ IPX_ADDRESS_EXTENDED_FLAGS SourceAddress;
+ ULONG SourceAddressLength;
+ ULONG RequestCount;
+ PNDIS_BUFFER NdisBuffer;
+ NDIS_STATUS NdisStatus;
+ NTSTATUS Status;
+ PIRP Irp;
+ UINT ByteOffset, BytesToTransfer;
+ ULONG BytesTransferred;
+ BOOLEAN LastAddressFile;
+ ULONG IndicateOffset;
+ PNDIS_PACKET ReceivePacket;
+ PIPX_RECEIVE_RESERVED Reserved;
+ PLIST_ENTRY p, q;
+ PSINGLE_LIST_ENTRY s;
+ USHORT DestinationSocket;
+ USHORT SourceSocket;
+ ULONG Hash;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+ PIPX_DATAGRAM_OPTIONS2 Options2;
+ BOOLEAN RtProc = FALSE;
+
+ //
+ // First scan the device's address database, looking for
+ // the destination socket of this frame.
+ //
+
+ DestinationSocket = *(USHORT UNALIGNED *)&IpxHeader->DestinationSocket;
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if ((Address = Device->LastAddress) &&
+ (Address->Socket == DestinationSocket)) {
+
+ //
+ // Device->LastAddress cannot be stopping, so
+ // we use it.
+ //
+
+ IpxReferenceAddressLock (Address, AREF_RECEIVE);
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ goto FoundAddress;
+ }
+
+ Hash = IPX_DEST_SOCKET_HASH (IpxHeader);
+
+ for (p = Device->AddressDatabases[Hash].Flink;
+ p != &Device->AddressDatabases[Hash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ if ((Address->Socket == DestinationSocket) &&
+ (!Address->Stopping)) {
+ IpxReferenceAddressLock (Address, AREF_RECEIVE);
+ Device->LastAddress = Address;
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ goto FoundAddress;
+ }
+ }
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // If we had found an address we would have jumped
+ // past here.
+ //
+
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysInUnknownSockets);
+#endif SNMP
+
+ return;
+
+FoundAddress:
+
+ SourceSocket = *(USHORT UNALIGNED *)&IpxHeader->SourceSocket;
+ IpxBuildTdiAddress(
+ &SourceAddress.IpxAddress,
+ (*(ULONG UNALIGNED *)(IpxHeader->SourceNetwork) == 0) ?
+ Binding->LocalAddress.NetworkAddress :
+ *(UNALIGNED ULONG *)(IpxHeader->SourceNetwork),
+ IpxHeader->SourceNode,
+ SourceSocket);
+
+ DatagramOptions->PacketType = IpxHeader->PacketType;
+
+
+ //
+ // Now that we have found the address, scan its list of
+ // address files for clients that want this datagram.
+ //
+ // If we have to release the address lock to indicate to
+ // a client, we reference the current address file. If
+ // we get an IRP we transfer the reference to that;
+ // otherwise we store the address file in ReferencedAddressFile
+ // and deref it the next time we release the lock.
+ //
+
+ ReferencedAddressFile = NULL;
+ RequestCount = 0;
+
+ ++Device->TempDatagramsReceived;
+ Device->TempDatagramBytesReceived += (PacketSize - sizeof(IPX_HEADER));
+
+ //
+ // If LastAddressFile is TRUE, it means we did an indication
+ // to the client on the last address file in the address'
+ // list, and we did not reacquire the lock when we were
+ // done.
+ //
+
+ LastAddressFile = FALSE;
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+
+ //
+ // If this is RtAdd, skip the entire body
+ //
+ if (!Address->RtAdd)
+ {
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+
+ AddressFile = CONTAINING_RECORD (p, ADDRESS_FILE, Linkage);
+
+ if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
+ continue; // next address file
+ }
+
+ //
+ // Set these to the common values, then change them.
+ //
+
+ SourceAddressLength = sizeof(TA_IPX_ADDRESS);
+ IndicateOffset = sizeof(IPX_HEADER);
+
+ if (AddressFile->SpecialReceiveProcessing) {
+
+ //
+ // On dial out lines, we don't indicate packets to
+ // the SAP socket if DisableDialoutSap is set.
+ //
+
+ //
+ // [FW] no need to check if the FWD is bound
+ //
+ if (!Device->ForwarderBound &&
+ (AddressFile->IsSapSocket) &&
+ (Binding->DialOutAsync) &&
+ (Device->DisableDialoutSap || Device->SingleNetworkActive)) {
+
+ //
+ // Go to the next address file (although it will
+ // likely fail this test too).
+ //
+
+ continue;
+
+ }
+
+ //
+ // Set this, since generally we want it.
+ //
+
+ SourceAddress.PacketType = IpxHeader->PacketType;
+
+ //
+ // See if we fail a packet type filter.
+ //
+
+ if (AddressFile->FilterOnPacketType) {
+ if (AddressFile->FilteredType != IpxHeader->PacketType) {
+ continue;
+ }
+ }
+
+ //
+ // Calculate how long the addresses expected are.
+ //
+
+ if (AddressFile->ReceiveFlagsAddressing ||
+ AddressFile->ExtendedAddressing) {
+
+ SourceAddress.Flags = 0;
+ if (Broadcast) {
+ SourceAddress.Flags = IPX_EXTENDED_FLAG_BROADCAST;
+ }
+ if (IpxIsAddressLocal((TDI_ADDRESS_IPX UNALIGNED *)
+ &SourceAddress.IpxAddress.Address[0].Address[0])) {
+ SourceAddress.Flags |= IPX_EXTENDED_FLAG_LOCAL;
+ }
+ SourceAddressLength = sizeof(IPX_ADDRESS_EXTENDED_FLAGS);
+ SourceAddress.IpxAddress.Address[0].AddressLength +=
+ (sizeof(IPX_ADDRESS_EXTENDED_FLAGS) - sizeof(TA_IPX_ADDRESS));
+
+ }
+
+ //
+ // Determine how much of the packet the client wants.
+ //
+
+ if (AddressFile->ReceiveIpxHeader) {
+ IndicateOffset = 0;
+ }
+ }
+
+ //
+ // First scan the address' receive datagram queue
+ // for datagrams that match. We do a quick check
+ // to see if the list is empty.
+ //
+
+ q = AddressFile->ReceiveDatagramQueue.Flink;
+ if (q != &AddressFile->ReceiveDatagramQueue) {
+
+ do {
+
+ Request = LIST_ENTRY_TO_REQUEST(q);
+
+ DatagramInformation =
+ ((PTDI_REQUEST_KERNEL_RECEIVEDG)(REQUEST_PARAMETERS(Request)))->
+ ReceiveDatagramInformation;
+
+ if ((DatagramInformation != NULL) &&
+ (DatagramInformation->RemoteAddress != NULL) &&
+ (DatagramAddress = IpxParseTdiAddress(DatagramInformation->RemoteAddress)) &&
+ (DatagramAddress->Socket != SourceSocket)) {
+
+ //
+ // The address that this datagram is looking for is
+ // not satisfied by this frame.
+ //
+ // BUGBUG: Speed this up; worry about node and network?
+ //
+
+ q = q->Flink;
+ continue; // next receive datagram on this address file
+
+ } else {
+
+ //
+ // We found a datagram on the queue.
+ //
+
+ IPX_DEBUG (RECEIVE, ("Found RDG on %lx\n", AddressFile));
+ RemoveEntryList (q);
+ REQUEST_INFORMATION(Request) = 0;
+
+ goto HandleDatagram;
+
+ }
+
+ } while (q != &AddressFile->ReceiveDatagramQueue);
+
+ }
+
+ //
+ // If we found a datagram we would have jumped past here,
+ // so looking for a datagram failed; see if the
+ // client has a receive datagram handler registered.
+ //
+
+ //
+ // Look for the chained receive handler if the MDL is not NULL
+ //
+ if (pMdl && AddressFile->RegisteredChainedReceiveDatagramHandler) {
+
+ //
+ // Chained receive both above and below => we indicate the entire MDL up.
+ // Offset the LookaheadBuffer by the size of the MAC header.
+ //
+ LookaheadBufferOffset += HeaderBufferSize;
+
+ IpxReferenceAddressFileLock (AddressFile, AFREF_INDICATION);
+
+ //
+ // Set this so we can exit without reacquiring
+ // the lock.
+ //
+
+ if (p == &Address->AddressFileDatabase) {
+ LastAddressFile = TRUE;
+ }
+
+ IndicateBytesCopied = 0;
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile) {
+ IpxDereferenceAddressFileSync (ReferencedAddressFile, AFREF_INDICATION);
+ ReferencedAddressFile = NULL;
+ }
+
+ IPX_DEBUG(RECEIVE, ("ChainedIndicate RecvLen: %d, StartOffset: %d, Tsdu: %lx\n",
+ PacketSize - IndicateOffset, IndicateOffset, pMdl));
+
+ //
+ // Will return SUCCESS if the client did not take ownership of the Tsdu
+ // PENDING if the client took ownership and will free it later (using TdiFreeReceiveChain).
+ // DATA_NOT_ACCEPTED if the client did not take ownership and did not copy the data.
+ //
+
+ //
+ // Since NDIS needs an array of PNDIS_PACKETs when the TDI client returns this packet,
+ // we pass the Packet as the ReceiveContext here. The TDI client will pass in the address
+ // of this context on a ReturnPacket.
+ // Also, NDIS needs the PacketArray (not to be confused with the array of packetptrs. mentioned
+ // above) on an NdisTransferData call. These clients dont do this, but other clients like
+ // NB, SPX, RIP or TDI clients that do not have this new interface, can call NdisTransferData
+ // so we pass in the PacketArray as a parameter to them.
+ //
+ Status = (*AddressFile->ChainedReceiveDatagramHandler)(
+ AddressFile->ChainedReceiveDatagramHandlerContext,
+ SourceAddressLength,
+ &SourceAddress,
+ sizeof(IPX_DATAGRAM_OPTIONS),
+ DatagramOptions,
+ Adapter->MacInfo.CopyLookahead, // TdiRcvFlags|Adapter->MacInfo.CopyLookahead, Receive datagram flags
+ PacketSize - IndicateOffset, // ReceiveLength
+ IndicateOffset+LookaheadBufferOffset, // StartingOffset
+ pMdl, // Tsdu - MDL chain
+ (PNDIS_PACKET)MacReceiveContext); // TransportContext - pointer to the packet
+
+ if (Status != STATUS_DATA_NOT_ACCEPTED) {
+
+ if (Status == STATUS_PENDING) {
+ //
+ // We assume here that the client referenced the packet which will
+ // be removed when the packet is freed.
+ // Increment the Tdi client count
+ //
+ (*pTdiClientCount)++;
+ }
+
+ //
+ // The handler accepted the data or did not
+ // return an IRP; in either case there is
+ // nothing else to do, so go to the next
+ // address file.
+ //
+
+ ReferencedAddressFile = AddressFile;
+ if (!LastAddressFile) {
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+
+ } else {
+
+ //
+ // In this case we have no cleanup, so just leave
+ // if there are no datagrams pending.
+ //
+ // RequestCount should always be 0 here.
+ //
+
+
+ //if (RequestCount == 0) {
+ // return;
+ //}
+ goto BreakWithoutLock;
+ }
+
+ } else {
+ //
+ // Since no IRP can be returned here, we continue to the next addressfile
+ //
+
+ ReferencedAddressFile = AddressFile;
+ if (!LastAddressFile) {
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+
+ } else {
+
+ //
+ // In this case we have no cleanup, so just leave
+ // if there are no datagrams pending.
+ //
+
+ //if (RequestCount == 0) {
+ // return;
+ //}
+ goto BreakWithoutLock;
+ }
+ }
+
+ } else if (AddressFile->RegisteredReceiveDatagramHandler) {
+
+ IpxReferenceAddressFileLock (AddressFile, AFREF_INDICATION);
+
+ //
+ // Set this so we can exit without reacquiring
+ // the lock.
+ //
+
+ if (p == &Address->AddressFileDatabase) {
+ LastAddressFile = TRUE;
+ }
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile) {
+ IpxDereferenceAddressFileSync (ReferencedAddressFile, AFREF_INDICATION);
+ ReferencedAddressFile = NULL;
+ }
+
+ IndicateBytesCopied = 0;
+
+ if (PacketSize > LookaheadBufferSize) {
+ IPX_DEBUG(RECEIVE, ("Indicate %d/%d to %lx on %lx\n",
+ LookaheadBufferSize, PacketSize,
+ AddressFile->ReceiveDatagramHandler, AddressFile));
+ }
+
+ Status = (*AddressFile->ReceiveDatagramHandler)(
+ AddressFile->ReceiveDatagramHandlerContext,
+ SourceAddressLength,
+ &SourceAddress,
+ sizeof(IPX_DATAGRAM_OPTIONS),
+ DatagramOptions,
+ Adapter->MacInfo.CopyLookahead,
+ LookaheadBufferSize - IndicateOffset, // indicated
+ PacketSize - IndicateOffset, // available
+ &IndicateBytesCopied, // taken
+ LookaheadBuffer + IndicateOffset, // data
+ &Irp);
+
+
+ if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
+
+ //
+ // The handler accepted the data or did not
+ // return an IRP; in either case there is
+ // nothing else to do, so go to the next
+ // address file.
+ //
+
+ ReferencedAddressFile = AddressFile;
+ if (!LastAddressFile) {
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+
+ } else {
+
+ //
+ // In this case we have no cleanup, so just leave
+ // if there are no datagrams pending.
+ //
+
+ if (RequestCount == 0) {
+ return;
+ }
+ goto BreakWithoutLock;
+ }
+
+ } else {
+
+ //
+ // The client returned an IRP.
+ //
+
+ IPX_DEBUG (RECEIVE, ("Indicate IRP %lx, taken %d\n", Irp, IndicateBytesCopied));
+
+ Request = IpxAllocateRequest (Device, Irp);
+
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ ReferencedAddressFile = AddressFile;
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+ }
+
+ if (!LastAddressFile) {
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+ }
+
+ #if DBG
+ //
+ // Make sure the IRP file object is right.
+ //
+
+ if (IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext != AddressFile) {
+ DbgPrint ("IRP %lx does not match AF %lx, H %lx C %lx\n",
+ Irp, AddressFile,
+ AddressFile->ReceiveDatagramHandler,
+ AddressFile->ReceiveDatagramHandlerContext);
+ DbgBreakPoint();
+ }
+ #endif
+ //
+ // Set up the information field so we know
+ // how much to skip in it.
+ //
+
+ IpxTransferReferenceAddressFile (AddressFile, AFREF_INDICATION, AFREF_RCV_DGRAM);
+ REQUEST_INFORMATION(Request) = IndicateBytesCopied;
+
+ //
+ // Fall out of the if and continue via
+ // HandleDatagram...
+ //
+
+ }
+
+ } else {
+
+ //
+ // No posted datagram, no handler; go to the next
+ // address file.
+ //
+
+ continue; // next address file
+
+ }
+
+ HandleDatagram:
+
+ //
+ // At this point, Request is set to the request
+ // that will hold for this address file, and
+ // REQUEST_INFORMATION() is the offset to start
+ // the transfer at.
+ //
+
+ //
+ // First copy over the source address while it is handy.
+ //
+
+ DatagramInformation =
+ ((PTDI_REQUEST_KERNEL_RECEIVEDG)(REQUEST_PARAMETERS(Request)))->
+ ReturnDatagramInformation;
+
+ if (DatagramInformation != NULL) {
+
+ RtlCopyMemory(
+ DatagramInformation->RemoteAddress,
+ &SourceAddress,
+ (ULONG)DatagramInformation->RemoteAddressLength < SourceAddressLength ?
+ DatagramInformation->RemoteAddressLength : SourceAddressLength);
+ RtlCopyMemory(
+ DatagramInformation->Options,
+ &DatagramOptions,
+ (ULONG)DatagramInformation->OptionsLength < sizeof(IPX_DATAGRAM_OPTIONS) ?
+ DatagramInformation->OptionsLength : sizeof(IPX_DATAGRAM_OPTIONS));
+
+ }
+
+ //
+ // Now check if this is the first request that will
+ // take the data, otherwise queue it up.
+ //
+
+ if (RequestCount == 0) {
+
+ //
+ // First one; we need to allocate a packet for the transfer.
+ //
+
+ //if (Address->ReceivePacketInUse) {
+ if (InterlockedExchangeAdd(&Address->ReceivePacketInUse, 0) != 0) {
+ //
+ // Need a packet, check the pool.
+ //
+
+ s = IpxPopReceivePacket (Device);
+
+ if (s == NULL) {
+
+ //
+ // None in pool, fail the request.
+ //
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_INSUFFICIENT_RESOURCES;
+ IPX_INSERT_TAIL_LIST(
+ &Adapter->RequestCompletionQueue,
+ REQUEST_LINKAGE(Request),
+ Adapter->DeviceLock);
+
+ if (!LastAddressFile) {
+ continue;
+ } else {
+ goto BreakWithoutLock;
+ }
+
+ }
+
+ Reserved = CONTAINING_RECORD (s, IPX_RECEIVE_RESERVED, PoolLinkage);
+ ReceivePacket = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ } else {
+
+ // Address->ReceivePacketInUse = TRUE;
+ InterlockedIncrement(&Address->ReceivePacketInUse);
+
+ ReceivePacket = PACKET(&Address->ReceivePacket);
+ Reserved = RECEIVE_RESERVED(&Address->ReceivePacket);
+
+ }
+
+ CTEAssert (IsListEmpty(&Reserved->Requests));
+
+ Reserved->SingleRequest = Request;
+ NdisBuffer = REQUEST_NDIS_BUFFER(Request);
+
+ ByteOffset = REQUEST_INFORMATION(Request) + LookaheadBufferOffset + IndicateOffset;
+ BytesToTransfer =
+ ((PTDI_REQUEST_KERNEL_RECEIVEDG)(REQUEST_PARAMETERS(Request)))->ReceiveLength;
+
+ if (BytesToTransfer > (PacketSize - IndicateOffset)) {
+ BytesToTransfer = PacketSize - IndicateOffset;
+ }
+
+ } else {
+
+ if (RequestCount == 1) {
+
+ //
+ // There is already one request. We need to
+ // allocate a buffer.
+ //
+
+ s = IpxPopReceiveBuffer (Adapter);
+
+ if (s == NULL) {
+
+ //
+ // No buffers, fail the request.
+ //
+ // BUGBUG: Should we fail the transfer for the
+ // first request too?
+ //
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_INSUFFICIENT_RESOURCES;
+ IPX_INSERT_TAIL_LIST(
+ &Adapter->RequestCompletionQueue,
+ REQUEST_LINKAGE(Request),
+ Adapter->DeviceLock);
+
+ if (!LastAddressFile) {
+ continue;
+ } else {
+ goto BreakWithoutLock;
+ }
+ }
+
+ ReceiveBuffer = CONTAINING_RECORD(s, IPX_RECEIVE_BUFFER, PoolLinkage);
+ NdisBuffer = ReceiveBuffer->NdisBuffer;
+
+ //
+ // Convert this to a queued multiple piece request.
+ //
+
+ InsertTailList(&Reserved->Requests, REQUEST_LINKAGE(Reserved->SingleRequest));
+ Reserved->SingleRequest = NULL;
+ Reserved->ReceiveBuffer = ReceiveBuffer;
+
+ ByteOffset = LookaheadBufferOffset;
+ BytesToTransfer = PacketSize;
+
+ }
+
+ InsertTailList(&Reserved->Requests, REQUEST_LINKAGE(Request));
+
+ }
+
+ //
+ // We are done setting up this address file's transfer,
+ // proceed to the next one.
+ //
+
+ ++RequestCount;
+
+ if (LastAddressFile) {
+ goto BreakWithoutLock;
+ }
+
+ }
+ } else {
+
+ //IpxPrint0("IpxProcessDatagram: Rt packet\n");
+ if (Address->ReceivePacketInUse) {
+ //
+ // Need a packet, check the pool.
+ //
+
+ s = IpxPopReceivePacket (Device);
+
+ if (s == NULL) {
+
+ goto BreakWithLock;
+ }
+
+
+ Reserved = CONTAINING_RECORD (s, IPX_RECEIVE_RESERVED, PoolLinkage);
+ ReceivePacket = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ } else {
+
+ Address->ReceivePacketInUse = TRUE;
+ ReceivePacket = PACKET(&Address->ReceivePacket);
+ Reserved = RECEIVE_RESERVED(&Address->ReceivePacket);
+
+ }
+ //IpxPrint0("IpxProcessDatagram: Rt packet reserved\n");
+ s = IpxPopReceiveBuffer (Adapter);
+
+ if (s == NULL) {
+
+ //
+ // No buffers, fail the request.
+ //
+ // BUGBUG: Should we fail the transfer for the
+ // first request too?
+ //
+ goto BreakWithLock;
+ }
+
+ ReceiveBuffer = CONTAINING_RECORD(s, IPX_RECEIVE_BUFFER, PoolLinkage);
+ NdisBuffer = ReceiveBuffer->NdisBuffer;
+ Reserved->ReceiveBuffer = ReceiveBuffer;
+ ByteOffset = LookaheadBufferOffset;
+ BytesToTransfer = PacketSize;
+ //IpxPrint0("IpxProcessDatagram: Rt packet buffer reserved\n");
+ RtProc = TRUE;
+ Reserved->Index = Address->Index;
+
+ }
+
+BreakWithLock:
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+
+BreakWithoutLock:
+
+ if (ReferencedAddressFile) {
+ IpxDereferenceAddressFileSync (ReferencedAddressFile, AFREF_INDICATION);
+ ReferencedAddressFile = NULL;
+ }
+
+
+ //
+ // We can be transferring directly into a request's buffer,
+ // transferring into an intermediate buffer, or not
+ // receiving the packet at all.
+ //
+
+ if (RequestCount > 0 || RtProc) {
+
+ if (RtProc) {
+ Reserved->pContext = IpxAllocateMemory(sizeof(IPX_DATAGRAM_OPTIONS2), MEMORY_PACKET, "RT Options");
+ if (!Reserved->pContext) {
+
+ ASSERTMSG("Out of resources\n", 1);
+ goto GetOut;
+ } else {
+ //IpxPrint1("IpxProcessDatagram: Nic Id is (%d)\n", DatagramOptions->LocalTarget.NicId);
+ RtlCopyMemory(
+ &((PIPX_DATAGRAM_OPTIONS2)(Reserved->pContext))->DgrmOptions,
+ DatagramOptions,
+ sizeof(IPX_DATAGRAM_OPTIONS));
+ //IpxPrint1("IpxProcessDatagram: Nic Id is (%d)\n",
+ // ((PIPX_DATAGRAM_OPTIONS2)(Reserved->pContext))->DgrmOptions.LocalTarget.NicId);
+ }
+ } else {
+ Reserved->pContext = NULL;
+ }
+
+ //
+ // If this is true, then ReceivePacket, Reserved,
+ // and NdisBuffer are all set up correctly.
+ //
+
+ CTEAssert (ReceivePacket);
+ CTEAssert (Reserved == (PIPX_RECEIVE_RESERVED)(ReceivePacket->ProtocolReserved));
+
+
+ NdisChainBufferAtFront(ReceivePacket, NdisBuffer);
+
+ IPX_DEBUG (RECEIVE, ("Transfer into %lx, offset %d bytes %d\n",
+ NdisBuffer, ByteOffset, BytesToTransfer));
+
+ if (BindingContext == (PVOID)IPX_LOOPBACK_COOKIE) {
+
+ IPX_DEBUG (LOOPB, ("Loopback Copy from packet: %lx to packet: %lx\n", ReceivePacket, MacReceiveContext));
+
+ NdisCopyFromPacketToPacket(
+ ReceivePacket, // Destination
+ 0, // DestinationOffset
+ BytesToTransfer, // BytesToCopy
+ (PNDIS_PACKET)MacReceiveContext, // Source
+ ByteOffset, // SourceOffset - loopback packet
+ &BytesTransferred); // BytesCopied
+
+ NdisStatus = NDIS_STATUS_SUCCESS;
+
+ } else {
+ NdisTransferData(
+ &NdisStatus,
+ Adapter->NdisBindingHandle,
+ MacReceiveContext,
+ ByteOffset,
+ BytesToTransfer,
+ ReceivePacket,
+ &BytesTransferred);
+ }
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+
+ IpxTransferDataComplete(
+ (NDIS_HANDLE)Adapter,
+ ReceivePacket,
+ NdisStatus,
+ BytesTransferred);
+ }
+ }
+#ifdef SNMP
+ else {
+ ++IPX_MIB_ENTRY(Device, SysInUnknownSockets);
+ }
+#endif SNMP
+
+GetOut:
+
+ IpxDereferenceAddressSync (Address, AREF_RECEIVE);
+
+} /* IpxProcessDatagram */
+
+
+
+NDIS_STATUS
+IpxReceiveIndication(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a frame has been received on the physical link.
+ This routine is time critical, so we only allocate a
+ buffer and copy the packet into it. We also perform minimal
+ validation on this packet. It gets queued to the device context
+ to allow for processing later.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+ ReceiveContext - A magic cookie for the MAC.
+
+ HeaderBuffer - pointer to a buffer containing the packet header.
+
+ HeaderBufferSize - the size of the header.
+
+ LookaheadBuffer - pointer to a buffer containing the negotiated minimum
+ amount of buffer I get to look at (not including header).
+
+ LookaheadBufferSize - the size of the above. May be less than asked
+ for, if that's all there is.
+
+ PacketSize - Overall size of the packet (not including header).
+
+Return Value:
+
+ NDIS_STATUS - status of operation, one of:
+
+ NDIS_STATUS_SUCCESS if packet accepted,
+ NDIS_STATUS_NOT_RECOGNIZED if not recognized by protocol,
+ NDIS_any_other_thing if I understand, but can't handle.
+
+--*/
+{
+ //
+ // Call the actual receive indication handler and indicate that this is not a
+ // chained receive
+ //
+
+ return IpxReceiveIndicationCommon (
+ BindingContext,
+ ReceiveContext, // ReceiveContext
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize, // PacketSize
+ NULL, // pMdl - non-NULL => chained receive.
+ NULL // pTdiClientCount - used in chained recv case to keep count of TDI clients
+ );
+
+}
+
+
+NDIS_STATUS
+IpxReceiveIndicationCommon(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize,
+ IN PMDL pMdl,
+ IN PINT pTdiClientCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a frame has been received on the physical link.
+ This routine is time critical, so we only allocate a
+ buffer and copy the packet into it. We also perform minimal
+ validation on this packet. It gets queued to the device context
+ to allow for processing later.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+ ReceiveContext - A magic cookie for the MAC.
+
+ HeaderBuffer - pointer to a buffer containing the packet header.
+
+ HeaderBufferSize - the size of the header.
+
+ LookaheadBuffer - pointer to a buffer containing the negotiated minimum
+ amount of buffer I get to look at (not including header).
+
+ LookaheadBufferSize - the size of the above. May be less than asked
+ for, if that's all there is.
+
+ PacketSize - Overall size of the packet (not including header).
+
+ pMdl - pointer to MDL chain if chained, NULL if this came from indication.
+
+Return Value:
+
+ NDIS_STATUS - status of operation, one of:
+
+ NDIS_STATUS_SUCCESS if packet accepted,
+ NDIS_STATUS_NOT_RECOGNIZED if not recognized by protocol,
+ NDIS_any_other_thing if I understand, but can't handle.
+
+--*/
+{
+
+ IPX_DATAGRAM_OPTIONS DatagramOptions;
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+ PBINDING Binding;
+ PDEVICE Device = IpxDevice;
+ PUCHAR Header = (PUCHAR)HeaderBuffer;
+ PUCHAR Lookahead = (PUCHAR)LookaheadBuffer;
+ ULONG PacketLength;
+ UINT IpxPacketSize;
+ ULONG Length802_3;
+ USHORT Saps;
+ ULONG DestinationNetwork;
+ ULONG SourceNetwork;
+ PUCHAR DestinationNode;
+ USHORT DestinationSocket;
+ ULONG IpxHeaderOffset;
+ PIPX_HEADER IpxHeader;
+ UINT i;
+ BOOLEAN IsBroadcast;
+ BOOLEAN IsLoopback = FALSE;
+#if DBG
+ PUCHAR DestMacAddress;
+ ULONG ReceiveFlag;
+#endif
+ BOOLEAN fCallProcessDatagram = FALSE;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif _PNP_POWER
+
+ //
+ // Reject packets that are too short to hold even the
+ // basic IPX header (this ignores any extra 802.2 etc.
+ // headers but is good enough because a runt will fail
+ // the IPX header packet length check).
+ //
+
+ if (PacketSize < sizeof(IPX_HEADER)) {
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysInReceives);
+ ++IPX_MIB_ENTRY(Device, SysInHdrErrors);
+#endif SNMP
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // If this is a loopback packet, no need to do figure out the
+ // MAC header.
+ //
+ if (BindingContext == (PVOID)IPX_LOOPBACK_COOKIE) {
+
+#ifdef _PNP_POWER
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_ID_TO_BINDING(IpxDevice, 1);
+
+ if (!Binding) {
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ goto NotValidLoopback;
+ }
+
+ Adapter = Binding->Adapter;
+
+ //
+ // Bump up the ref count so the adapter doesn't disappear from under
+ // us.
+ //
+ IpxReferenceAdapter(Adapter);
+
+ IpxReferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ FILL_LOCAL_TARGET(&DatagramOptions.LocalTarget, LOOPBACK_NIC_ID);
+#else
+ if ((Binding = IpxDevice->Bindings[1]) == NULL) {
+ goto NotValidLoopback;
+ }
+
+ Adapter = Binding->Adapter;
+
+ DatagramOptions.LocalTarget.NicId = 0;
+#endif
+
+ //
+ // Do this copy later, from the IpxHeader.
+ //
+ // RtlCopyMemory (DatagramOptions.LocalTarget.MacAddress, Binding->LocalAddress.NodeAddress, 6);
+
+ if (Binding->Adapter->MacInfo.MediumType == NdisMedium802_5) {
+ DatagramOptions.LocalTarget.MacAddress[0] &= 0x7f;
+ }
+
+ //
+ // Ipx header starts at the top of the LookAheadBuffer
+ //
+ IpxHeaderOffset = 0;
+
+ IPX_DEBUG (LOOPB, ("Loopback packet received: %lx\n", ReceiveContext));
+
+#if DBG
+ DestMacAddress = DatagramOptions.LocalTarget.MacAddress;
+#endif
+
+ IsLoopback = TRUE;
+ goto Loopback;
+ }
+
+#ifdef _PNP_POWER
+ //
+ // Bump up the ref count so the adapter doesn't disappear from under
+ // us.
+ //
+ IpxReferenceAdapter(Adapter);
+#endif
+
+ //
+ // The first step is to construct the 8-byte local
+ // target from the packet. We store it in the 9-byte
+ // datagram options, leaving one byte at the front
+ // for use by IpxProcessDatagram when indicating to
+ // its TDI clients.
+ //
+
+#if DBG
+ Binding = NULL;
+#endif
+
+ if (Adapter->MacInfo.MediumType == NdisMedium802_3) {
+
+ //
+ // Try to figure out what the packet type is.
+ //
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+
+ if (Header[12] < 0x06) {
+
+ //
+ // An 802.3 header; check the next bytes. They may
+ // be E0/E0 (802.2), FFFF (raw 802.3) or A0/A0 (SNAP).
+ //
+
+ Saps = *(UNALIGNED USHORT *)(Lookahead);
+
+ if (Saps == 0xffff) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_3]) == NULL) {
+ goto NotValid802_3;
+ }
+ IpxHeaderOffset = 0;
+ Length802_3 = ((Header[12] << 8) | Header[13]);
+ goto Valid802_3;
+
+ } else if (Saps == 0xe0e0) {
+ if (Lookahead[2] == 0x03) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_2]) == NULL) {
+ goto NotValid802_3;
+ }
+ IpxHeaderOffset = 3;
+ Length802_3 = ((Header[12] << 8) | Header[13]);
+ goto Valid802_3;
+ }
+
+ } else if (Saps == 0xaaaa) {
+
+ if ((Lookahead[2] == 0x03) &&
+ (*(UNALIGNED USHORT *)(Lookahead+6) == Adapter->BindSapNetworkOrder)) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_SNAP]) == NULL) {
+ goto NotValid802_3;
+ }
+ IpxHeaderOffset = 8;
+ Length802_3 = ((Header[12] << 8) | Header[13]);
+ goto Valid802_3;
+ }
+ }
+
+ goto NotValid802_3;
+
+ } else {
+
+ //
+ // It has an ethertype, see if it is ours.
+ //
+
+ if (*(UNALIGNED USHORT *)(Header+12) == Adapter->BindSapNetworkOrder) {
+
+ if (Adapter->MacInfo.MediumAsync) {
+
+ *((ULONG UNALIGNED *)(&Binding)) = *((ULONG UNALIGNED *)(&Header[2]));
+
+ CTEAssert(Binding != NULL);
+
+ if ((Binding != NULL) &&
+ (Binding->LineUp)) {
+
+ IpxHeaderOffset = 0;
+ Length802_3 = PacketSize; // set this so the check succeeds
+
+ //
+ // Check if this is a type 20 packet and
+ // we are disabling them on dialin lines -- we do
+ // this check here to avoid impacting the main
+ // indication path for LANs.
+ //
+ // The 0x02 bit of DisableDialinNetbios controls
+ // WAN->LAN packets, which we handle here.
+ //
+
+ //
+ // [FW] If FWD bound, no need to check since the FWD does the checks
+ //
+ if (!Device->ForwarderBound &&
+ (!Binding->DialOutAsync) &&
+ ((Device->DisableDialinNetbios & 0x02) != 0)) {
+
+ IpxHeader = (PIPX_HEADER)Lookahead; // IpxHeaderOffset is 0
+ if (IpxHeader->PacketType == 0x14) {
+#ifdef _PNP_POWER
+ IpxDereferenceAdapter(Adapter);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ return STATUS_SUCCESS;
+ }
+ }
+
+ goto Valid802_3;
+ }
+ goto NotValid802_3;
+
+ } else if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_ETHERNET_II]) == NULL) {
+ goto NotValid802_3;
+ }
+
+ IpxHeaderOffset = 0;
+ Length802_3 = PacketSize; // set this so the check succeeds
+ goto Valid802_3;
+
+ }
+ }
+
+ goto NotValid802_3;
+
+Valid802_3:
+
+ if (Length802_3 > PacketSize) {
+ goto NotValid802_3;
+ } else if (Length802_3 < PacketSize) {
+ PacketSize = Length802_3;
+ if (LookaheadBufferSize > Length802_3) {
+ LookaheadBufferSize = Length802_3;
+ }
+ }
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ RtlCopyMemory (DatagramOptions.LocalTarget.MacAddress, Header+6, 6);
+#if DBG
+ DestMacAddress = Header;
+#endif
+
+ } else if (Adapter->MacInfo.MediumType == NdisMedium802_5) {
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ Saps = *(USHORT UNALIGNED *)(Lookahead);
+
+ if (Saps == 0xe0e0) {
+
+ if (Lookahead[2] == 0x03) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_2]) == NULL) {
+ goto NotValid802_5;
+ }
+
+ IpxHeaderOffset = 3;
+ goto Valid802_5;
+ }
+
+ } else if (Saps == 0xaaaa) {
+
+ if ((Lookahead[2] == 0x03) &&
+ (*(UNALIGNED USHORT *)(Lookahead+6) == Adapter->BindSapNetworkOrder)) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_SNAP]) == NULL) {
+ goto NotValid802_5;
+ }
+ IpxHeaderOffset = 8;
+ goto Valid802_5;
+ }
+ }
+
+ goto NotValid802_5;
+
+Valid802_5:
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ RtlCopyMemory (DatagramOptions.LocalTarget.MacAddress, Header+8, 6);
+ DatagramOptions.LocalTarget.MacAddress[0] &= 0x7f;
+
+#if DBG
+ DestMacAddress = Header+2;
+#endif
+
+ } else if (Adapter->MacInfo.MediumType == NdisMediumFddi) {
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ Saps = *(USHORT UNALIGNED *)(Lookahead);
+
+ if (Saps == 0xe0e0) {
+
+ if (Lookahead[2] == 0x03) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_2]) == NULL) {
+ goto NotValidFddi;
+ }
+ IpxHeaderOffset = 3;
+ goto ValidFddi;
+ }
+
+ } else if (Saps == 0xffff) {
+
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_3]) == NULL) {
+ goto NotValidFddi;
+ }
+ IpxHeaderOffset = 0;
+ goto ValidFddi;
+
+ } else if (Saps == 0xaaaa) {
+
+ if ((Lookahead[2] == 0x03) &&
+ (*(UNALIGNED USHORT *)(Lookahead+6) == Adapter->BindSapNetworkOrder)) {
+
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_SNAP]) == NULL) {
+ goto NotValidFddi;
+ }
+ IpxHeaderOffset = 8;
+ goto ValidFddi;
+ }
+ }
+
+ goto NotValidFddi;
+
+ValidFddi:
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ RtlCopyMemory (DatagramOptions.LocalTarget.MacAddress, Header+7, 6);
+
+#if DBG
+ DestMacAddress = Header+1;
+#endif
+
+
+ } else {
+
+ //
+ // NdisMediumArcnet878_2
+ //
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ if ((Header[2] == ARCNET_PROTOCOL_ID) &&
+ ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_3]) != NULL)) {
+
+ IpxHeaderOffset = 0;
+ RtlZeroMemory (DatagramOptions.LocalTarget.MacAddress, 5);
+ DatagramOptions.LocalTarget.MacAddress[5] = Header[0];
+
+ } else {
+
+#ifdef _PNP_POWER
+ IpxDereferenceAdapter(Adapter);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(IPX_PACKET_LOG_RCV_ALL)) {
+ IpxLogPacket(FALSE, Header+2, Header+1, (USHORT)PacketSize, LookaheadBuffer, (PUCHAR)LookaheadBuffer + sizeof(IPX_HEADER));
+ }
+#endif
+ return NDIS_STATUS_SUCCESS;
+ }
+
+#if DBG
+ DestMacAddress = Header+2; // BUGBUG Need to log less than six bytes
+#endif
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ }
+
+ //
+ // Make sure this didn't slip through.
+ //
+
+ CTEAssert (Binding != NULL);
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&DatagramOptions.LocalTarget, MIN( Device->MaxBindings, Binding->NicId));
+#else
+ DatagramOptions.LocalTarget.NicId = Binding->NicId;
+#endif
+
+Loopback:
+
+ //
+ // Now that we have validated the header and constructed
+ // the local target, indicate the packet to the correct
+ // client.
+ //
+
+ IpxHeader = (PIPX_HEADER)(Lookahead + IpxHeaderOffset);
+
+ PacketLength = (IpxHeader->PacketLength[0] << 8) | IpxHeader->PacketLength[1];
+
+ IpxPacketSize = PacketSize - IpxHeaderOffset;
+
+ if (PacketLength > IpxPacketSize) {
+
+#ifdef _PNP_POWER
+ IpxDereferenceAdapter(Adapter);
+ IpxDereferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+#endif
+
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(IPX_PACKET_LOG_RCV_ALL)) {
+ IpxLogPacket(FALSE, DestMacAddress, DatagramOptions.LocalTarget.MacAddress, (USHORT)PacketSize, IpxHeader, IpxHeader+1);
+ }
+#endif
+ IPX_DEBUG (BAD_PACKET, ("Packet len %d, IPX len %d\n",
+ PacketLength, IpxPacketSize));
+
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysInReceives);
+
+#endif SNMP
+
+ return NDIS_STATUS_SUCCESS;
+
+ } else if (PacketLength < IpxPacketSize) {
+
+ IpxPacketSize = PacketLength;
+ if (LookaheadBufferSize > (PacketLength + IpxHeaderOffset)) {
+ LookaheadBufferSize = PacketLength + IpxHeaderOffset;
+ }
+
+ }
+
+ //
+ // Bug #33595 - (hotfixed in 3.51, checked into 4.0 beta2)
+ // Customer problem where NT allowed RIP/SAP to reply to an 802.5 functional address in the IPX source node. The source
+ // MAC address was proper in this case. We need to check for the case where if the packet's source network is the same
+ // as that of the binding it came on (=> did not come thru a router), then the SourceNodeAddress in the IPX header
+ // should be equal to the SourceAddress in the MAC header.
+ //
+ // This check is controlled through a registry value - VerifySourceAddress.
+ // In case of Arcnet, this check will not succeed.
+ // Also, for WAN, the node addresses will not match, so avoid check for those.
+
+ //
+ // If the source network is 0, we drop it. Auto-detect frames should have matching node (MAC) addresses.
+ // Loopback packets dont have a valid header, so skip this test for them.
+ //
+ // BUGBUG: For loopback pkts, do all the processing above, so we can avoid all these checks for IsLoopback here.
+ // Also, to prevent the RtlCopyMemory into the localtarget above, try to use the MAC header to indicate the
+ // correct binding to us so we dont use the first one always.
+ //
+ // CAVEAT:: when using the MAC header as a binding pointer, ensure that we use the adapter corresp, to that binding
+ // to enque all the receive requests. currently we enqueue them onto the first bindings adapter.
+ //
+ if (((*(UNALIGNED ULONG *)IpxHeader->SourceNetwork == Binding->LocalAddress.NetworkAddress) ||
+ (*(UNALIGNED ULONG *)IpxHeader->SourceNetwork == 0)) &&
+ (!IPX_NODE_EQUAL (IpxHeader->SourceNode, DatagramOptions.LocalTarget.MacAddress)) &&
+ Device->VerifySourceAddress &&
+ !IsLoopback &&
+ !Adapter->MacInfo.MediumAsync &&
+ (Adapter->MacInfo.MediumType != NdisMediumArcnet878_2)) {
+
+ IPX_DEBUG(BAD_PACKET, ("Local packet: Src MAC %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x ",
+ DatagramOptions.LocalTarget.MacAddress[0],
+ DatagramOptions.LocalTarget.MacAddress[1],
+ DatagramOptions.LocalTarget.MacAddress[2],
+ DatagramOptions.LocalTarget.MacAddress[3],
+ DatagramOptions.LocalTarget.MacAddress[4],
+ DatagramOptions.LocalTarget.MacAddress[5]));
+
+ IPX_DEBUG(BAD_PACKET, ("IPX Src Node %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ IpxHeader->SourceNode[0],
+ IpxHeader->SourceNode[1],
+ IpxHeader->SourceNode[2],
+ IpxHeader->SourceNode[3],
+ IpxHeader->SourceNode[4],
+ IpxHeader->SourceNode[5]));
+
+#ifdef IPX_PACKET_LOG
+ ReceiveFlag = IPX_PACKET_LOG_RCV_ALL;
+ if (PACKET_LOG(ReceiveFlag)) {
+ IpxLogPacket(
+ FALSE,
+ DestMacAddress,
+ DatagramOptions.LocalTarget.MacAddress,
+ (USHORT)IpxPacketSize,
+ IpxHeader,
+ IpxHeader+1);
+ }
+#endif
+
+#ifdef _PNP_POWER
+ IpxDereferenceAdapter(Adapter);
+ IpxDereferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+#endif
+
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysInReceives);
+
+#endif SNMP
+
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ DestinationSocket = *(USHORT UNALIGNED *)&IpxHeader->DestinationSocket;
+
+ //
+ // In order to have consistent local targets, copy over the target from the IpxHeader.
+ //
+ if (IsLoopback) {
+ IPX_DEBUG (LOOPB, ("Loopback packet copied the localtarget: %lx\n", IpxHeader->DestinationNode));
+ // RtlCopyMemory (DatagramOptions.LocalTarget.MacAddress, IpxHeader->DestinationNode, 6);
+
+ *((UNALIGNED ULONG *)DatagramOptions.LocalTarget.MacAddress) =
+ *((UNALIGNED ULONG *)IpxHeader->DestinationNode);
+
+ *((UNALIGNED USHORT *)(DatagramOptions.LocalTarget.MacAddress+4)) =
+ *((UNALIGNED USHORT *)(IpxHeader->DestinationNode+4));
+ }
+
+ ++Device->Statistics.PacketsReceived;
+
+ DestinationNode = IpxHeader->DestinationNode;
+
+ if (DestinationSocket != RIP_SOCKET) {
+
+ DestinationNetwork = *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork;
+
+RecheckPacket:
+
+ if (Device->MultiCardZeroVirtual) {
+
+ if ((DestinationNetwork == Binding->LocalAddress.NetworkAddress) ||
+ (DestinationNetwork == 0)) {
+
+ if (IPX_NODE_EQUAL (DestinationNode, Binding->LocalAddress.NodeAddress)) {
+ IsBroadcast = FALSE;
+ goto DestinationOk;
+ } else {
+ if ((IsBroadcast = IPX_NODE_BROADCAST(DestinationNode)) &&
+ (Binding->ReceiveBroadcast)) {
+ goto DestinationOk;
+ }
+ }
+
+ //
+ // If this is a binding set slave, check for the master's
+ // address.
+ //
+
+ if ((Binding->BindingSetMember) &&
+ (IPX_NODE_EQUAL (DestinationNode, Binding->MasterBinding->LocalAddress.NodeAddress))) {
+ goto DestinationOk;
+ }
+
+ } else {
+ IsBroadcast = IPX_NODE_BROADCAST(DestinationNode);
+ }
+
+ } else {
+
+ if ((DestinationNetwork == Device->SourceAddress.NetworkAddress) ||
+ (DestinationNetwork == 0)) {
+
+ if (IPX_NODE_EQUAL (DestinationNode, Device->SourceAddress.NodeAddress)) {
+ IsBroadcast = FALSE;
+ goto DestinationOk;
+ } else {
+ if ((IsBroadcast = IPX_NODE_BROADCAST(DestinationNode)) &&
+ (Binding->ReceiveBroadcast)) {
+ goto DestinationOk;
+ }
+ }
+ } else {
+ IsBroadcast = IPX_NODE_BROADCAST(DestinationNode);
+ }
+
+ //
+ // We need to check for frames that are sent to the
+ // binding node and net, because if we have a virtual
+ // net we won't catch them in the check above. This
+ // will include any Netbios frames, since they don't
+ // use the virtual net. Doing the check like this will slow
+ // down netbios indications just a bit on a machine with
+ // a virtual network, but it saves a jump for other traffic
+ // vs. adding the check up there (the assumption is if we
+ // have a virtual net most traffic is NCP).
+ //
+ // Note that IsBroadcast is already set, so we don't have
+ // to do that.
+ //
+
+ if ((Device->VirtualNetwork) &&
+ ((DestinationNetwork == Binding->LocalAddress.NetworkAddress) ||
+ (DestinationNetwork == 0))) {
+
+ if (IPX_NODE_EQUAL (DestinationNode, Binding->LocalAddress.NodeAddress)) {
+ goto DestinationOk;
+ } else {
+ if (IsBroadcast && (Binding->ReceiveBroadcast)) {
+ goto DestinationOk;
+ }
+
+ }
+
+ //
+ // If this is a binding set slave, check for the master's
+ // address.
+ //
+
+ if ((Binding->BindingSetMember) &&
+ (IPX_NODE_EQUAL (DestinationNode, Binding->MasterBinding->LocalAddress.NodeAddress))) {
+ goto DestinationOk;
+ }
+ }
+ }
+
+ //
+ // If this was a loopback packet that was sent on the second binding (but showed back up on the first one),
+ // then the networknumbers will not match. Allow the receive on the first binding itself.
+ //
+ if (IsLoopback) {
+ IPX_DEBUG (LOOPB, ("Loopback packet forced on first binding: %lx\n", ReceiveContext));
+ goto DestinationOk;
+ }
+
+ //
+ // If we did not receive this packet, it might be because
+ // our network is still 0 and this packet was actually
+ // sent to the real network number. If so we try to
+ // update our local address, and if successful we
+ // re-check the packet. We don't insert if we are
+ // not done with auto detection, to avoid colliding
+ // with that.
+ //
+ // To avoid problems if we are a router, we only update
+ // on packets that are broadcast or sent to us.
+ //
+
+ if ((Binding->LocalAddress.NetworkAddress == 0) &&
+ (Device->AutoDetectState == AUTO_DETECT_STATE_DONE) &&
+ (DestinationNetwork != 0) &&
+ (IsBroadcast ||
+ IPX_NODE_EQUAL (DestinationNode, Binding->LocalAddress.NodeAddress))) {
+
+ CTEAssert (Binding->NicId != 0);
+
+ if (IpxUpdateBindingNetwork(
+ Device,
+ Binding,
+ DestinationNetwork) == STATUS_SUCCESS) {
+
+ IPX_DEBUG (RIP, ("Binding %d reconfigured to network %lx\n",
+ Binding->NicId,
+ REORDER_ULONG(Binding->LocalAddress.NetworkAddress)));
+
+ //
+ // Jump back and re-process the packet; we know
+ // we won't loop through here again because the
+ // binding's network is now non-zero.
+ //
+
+ goto RecheckPacket;
+
+ }
+ }
+
+
+ //
+ // The only frames that will not already have jumped to
+ // DestinationOk are those to or from the SAP socket,
+ // so we check for those.
+ //
+
+ if ((*(USHORT UNALIGNED *)&IpxHeader->SourceSocket == SAP_SOCKET) ||
+ (DestinationSocket == SAP_SOCKET)) {
+
+DestinationOk:
+
+ //
+ // [FW] For internally destined packets, call the Forwarder's internal
+ // receive handler to filter the packets.
+ //
+ // STEFAN: 3/28/96:
+ // Dont filter IPXWAN config packets since the FWD does not have this adapter opened.
+ //
+
+ IPX_DEBUG(RECEIVE, ("DestSocket: %lx\n", DestinationSocket));
+
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysInDelivers);
+#endif SNMP
+
+ if (DestinationSocket != IPXWAN_SOCKET &&
+ Device->ForwarderBound) {
+
+ NDIS_STATUS NdisStatus;
+
+ IPX_DEBUG(RECEIVE, ("Internal packet, sending up to the Forwarder\n"));
+
+ //
+ // We should pass up the correct Fwd ctx for loopback ptks
+ //
+
+ //
+ // Indicate this up only if the adapter the packet came on was opened by the Forwarder
+ //
+ if (GET_VALUE(Binding->ReferenceCount) == 2) {
+
+ NdisStatus = (*Device->UpperDrivers[IDENTIFIER_RIP].InternalReceiveHandler) (
+ (IsLoopback) ?
+ VIRTUAL_NET_FORWARDER_CONTEXT :
+ Binding->FwdAdapterContext, // ForwarderAdapterContext
+ &DatagramOptions.LocalTarget, // Remote Address
+ (PUCHAR) IpxHeader, // Lookahead buffer
+ LookaheadBufferSize - IpxHeaderOffset // Lookahead buffer size
+ );
+
+ IPX_DEBUG(RECEIVE, ("Internal packet, Forwarder returned %lx\n", NdisStatus));
+
+ if (NdisStatus != STATUS_SUCCESS) {
+ //
+ // BUGBUG: Log this packet
+ //
+ IPX_DEBUG(RECEIVE, ("Internal packet, failed the filter: ipxheader: %lx\n", IpxHeader));
+
+ //
+ // The router needs to see Netbios type 20 broadcasts.
+ //
+
+ if (IsBroadcast &&
+ (IpxHeader->PacketType == 0x14) &&
+ (Binding->ReceiveBroadcast) &&
+ (!fCallProcessDatagram)) {
+
+ goto RipIndication;
+ }
+ // else
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ } else {
+ IPX_DEBUG(RECEIVE, ("Internal packet, Forwarder has not opened the adapter yet\n"));
+ return NDIS_STATUS_SUCCESS;
+ }
+ }
+
+ //
+ // An IPX packet sent to us, or a SAP packet (which
+ // are not sent to the virtual address but still need
+ // to be indicated and not forwarded to RIP).
+ //
+
+ if (DestinationSocket == NB_SOCKET) {
+#if DBG
+ ReceiveFlag = IPX_PACKET_LOG_RCV_NB | IPX_PACKET_LOG_RCV_ALL;
+#endif
+ if (((!IsBroadcast) || (Device->UpperDrivers[IDENTIFIER_NB].BroadcastEnable)) &&
+ (Device->UpperDriverBound[IDENTIFIER_NB])) {
+
+ if (!IsLoopback && Adapter->MacInfo.MediumType == NdisMedium802_5) {
+ MacUpdateSourceRouting (IDENTIFIER_NB, Adapter, Header, HeaderBufferSize);
+ }
+
+ //
+ // We add HeaderBufferSize to the IpxHeaderOffset field since we do an NdisCopyFromPacketToPacket
+ // in IpxTransferData, which needs offset from the beginning of the packet.
+ // NdisTransferData adds the offset passed in to the beginning of the IPX packet.
+ //
+ if ((*Device->UpperDrivers[IDENTIFIER_NB].ReceiveHandler)(
+ (IsLoopback) ? BindingContext : Adapter->NdisBindingHandle,
+ ReceiveContext,
+ Binding->FwdAdapterContext,
+ &DatagramOptions.LocalTarget,
+ Adapter->MacInfo.MacOptions,
+ (PUCHAR)IpxHeader,
+ LookaheadBufferSize - IpxHeaderOffset,
+ (IsLoopback) ? IpxHeaderOffset+HeaderBufferSize : IpxHeaderOffset,
+ IpxPacketSize,
+ pMdl)) {
+
+ CTEAssert(FALSE);
+ (*pTdiClientCount)++;
+ }
+
+ Device->ReceiveCompletePending[IDENTIFIER_NB] = TRUE;
+ }
+
+ //
+ // The router needs to see Netbios type 20 broadcasts.
+ //
+
+ if (IsBroadcast &&
+ (IpxHeader->PacketType == 0x14) &&
+ (Binding->ReceiveBroadcast) &&
+ (!fCallProcessDatagram)) {
+ goto RipIndication;
+ }
+
+ } else if (IpxHeader->PacketType == SPX_PACKET_TYPE) {
+
+#if DBG
+ ReceiveFlag = IPX_PACKET_LOG_RCV_SPX | IPX_PACKET_LOG_RCV_ALL;
+#endif
+
+ if (((!IsBroadcast) || (Device->UpperDrivers[IDENTIFIER_SPX].BroadcastEnable)) &&
+ (Device->UpperDriverBound[IDENTIFIER_SPX])) {
+
+ if (!IsLoopback && Adapter->MacInfo.MediumType == NdisMedium802_5) {
+ MacUpdateSourceRouting (IDENTIFIER_SPX, Adapter, Header, HeaderBufferSize);
+ }
+
+ if ((*Device->UpperDrivers[IDENTIFIER_SPX].ReceiveHandler)(
+ (IsLoopback) ? BindingContext : Adapter->NdisBindingHandle,
+ ReceiveContext,
+ Binding->FwdAdapterContext,
+ &DatagramOptions.LocalTarget,
+ Adapter->MacInfo.MacOptions,
+ (PUCHAR)IpxHeader,
+ LookaheadBufferSize - IpxHeaderOffset,
+ (IsLoopback) ? IpxHeaderOffset+HeaderBufferSize : IpxHeaderOffset,
+ IpxPacketSize,
+ pMdl)) {
+
+ CTEAssert(FALSE);
+ (*pTdiClientCount)++;
+ }
+
+ Device->ReceiveCompletePending[IDENTIFIER_SPX] = TRUE;
+ }
+
+ } else {
+
+ IPX_DEBUG (RECEIVE, ("Received packet type %d, length %d\n",
+ Binding->FrameType,
+ IpxPacketSize));
+ IPX_DEBUG (RECEIVE, ("Source %lx %2.2x-%2.2x-%2.2x-%2.2x %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ *(USHORT UNALIGNED *)&IpxHeader->SourceSocket,
+ IpxHeader->SourceNetwork[0],
+ IpxHeader->SourceNetwork[1],
+ IpxHeader->SourceNetwork[2],
+ IpxHeader->SourceNetwork[3],
+ IpxHeader->SourceNode[0],
+ IpxHeader->SourceNode[1],
+ IpxHeader->SourceNode[2],
+ IpxHeader->SourceNode[3],
+ IpxHeader->SourceNode[4],
+ IpxHeader->SourceNode[5]));
+ IPX_DEBUG (RECEIVE, ("Destination %d %2.2x-%2.2x-%2.2x-%2.2x %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ DestinationSocket,
+ IpxHeader->DestinationNetwork[0],
+ IpxHeader->DestinationNetwork[1],
+ IpxHeader->DestinationNetwork[2],
+ IpxHeader->DestinationNetwork[3],
+ IpxHeader->DestinationNode[0],
+ IpxHeader->DestinationNode[1],
+ IpxHeader->DestinationNode[2],
+ IpxHeader->DestinationNode[3],
+ IpxHeader->DestinationNode[4],
+ IpxHeader->DestinationNode[5]));
+
+#if DBG
+ if (IpxHeader->DestinationSocket == IpxPacketLogSocket) {
+ ReceiveFlag = IPX_PACKET_LOG_RCV_SOCKET | IPX_PACKET_LOG_RCV_OTHER | IPX_PACKET_LOG_RCV_ALL;
+ } else {
+ ReceiveFlag = IPX_PACKET_LOG_RCV_OTHER | IPX_PACKET_LOG_RCV_ALL;
+ }
+#endif
+
+ //
+ // Fiddle with this if so in the general case
+ // the jump is not made (BUGBUG the compiler
+ // still rearranges it).
+ //
+
+ if (Adapter->MacInfo.MediumType != NdisMedium802_5) {
+
+CallProcessDatagram:
+ //
+ // [SA] Returns a status now which needs to be returned to NDIS
+ // Also, MDL is passed in.
+ // We need to pass in the HeaderBufferSize too....
+ //
+ IpxProcessDatagram(
+ Device,
+ Adapter,
+ Binding,
+ ReceiveContext,
+ &DatagramOptions,
+ (PUCHAR)IpxHeader,
+ LookaheadBufferSize - IpxHeaderOffset,
+ (IsLoopback) ? IpxHeaderOffset+HeaderBufferSize : IpxHeaderOffset, // lookaheadbufferoffset
+ IpxPacketSize,
+ IsBroadcast,
+ pTdiClientCount,
+ HeaderBufferSize,
+ pMdl,
+ BindingContext);
+
+ } else {
+ if (!IsLoopback) {
+ MacUpdateSourceRouting (IDENTIFIER_IPX, Adapter, Header, HeaderBufferSize);
+ }
+ goto CallProcessDatagram;
+ }
+
+ //
+ // The router needs to see type 20 broadcasts.
+ //
+
+ if (IsBroadcast &&
+ (IpxHeader->PacketType == 0x14) &&
+ (Binding->ReceiveBroadcast) &&
+ (!fCallProcessDatagram)) {
+ goto RipIndication;
+ }
+ }
+
+ } else {
+
+#if DBG
+ ReceiveFlag = IPX_PACKET_LOG_RCV_ALL;
+#endif
+
+ //
+ // We need to let non-type 20 broadcast frames go to RIP to allow for lan-specific
+ // broadcasts. For logon over IPX, this allows the logon request to get thru the WAN
+ // line.
+ //
+ // if ( !IsBroadcast ) {
+
+RipIndication:;
+
+ if (Device->ForwarderBound) {
+ //
+ // FWD ....
+ //
+
+ if (DestinationSocket == RIP_SOCKET) {
+ //
+ // [FW] Since RIP is now a user app with the same socket #, we inform thru'
+ // the ProcessDatagram path. And only if the Forwarder is installed.
+ //
+
+ IsBroadcast = IPX_NODE_BROADCAST(DestinationNode);
+ fCallProcessDatagram = TRUE;
+ goto CallProcessDatagram;
+ } else {
+ if (!IsLoopback && Adapter->MacInfo.MediumType == NdisMedium802_5) {
+ MacUpdateSourceRouting (IDENTIFIER_RIP, Adapter, Header, HeaderBufferSize);
+ }
+
+ //
+ // We hide binding sets from the router, to avoid
+ // misordering packets which it routes.
+ //
+
+ if (!IsLoopback && Binding->BindingSetMember) {
+ #ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&DatagramOptions.LocalTarget, MIN (Device->MaxBindings, Binding->MasterBinding->NicId));
+ #else
+ DatagramOptions.LocalTarget.NicId = Binding->MasterBinding->NicId;
+ #endif
+ }
+
+ if (GET_VALUE(Binding->ReferenceCount) == 2) {
+ if ((*Device->UpperDrivers[IDENTIFIER_RIP].ReceiveHandler)(
+ (IsLoopback) ? BindingContext : Adapter->NdisBindingHandle,
+ ReceiveContext,
+ Binding->FwdAdapterContext,
+ &DatagramOptions.LocalTarget,
+ Adapter->MacInfo.MacOptions,
+ (PUCHAR)IpxHeader,
+ LookaheadBufferSize - IpxHeaderOffset,
+ (IsLoopback) ? IpxHeaderOffset+HeaderBufferSize : IpxHeaderOffset,
+ IpxPacketSize,
+ pMdl)) {
+
+ (*pTdiClientCount)++;
+ }
+
+ Device->ReceiveCompletePending[IDENTIFIER_RIP] = TRUE;
+ } else {
+ IPX_DEBUG(RECEIVE, ("External packet, Forwarder has not opened the adapter yet\n"));
+ }
+ }
+ } else if (Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ //
+ // Old RIP...
+ //
+ if (!IsLoopback && Adapter->MacInfo.MediumType == NdisMedium802_5) {
+ MacUpdateSourceRouting (IDENTIFIER_RIP, Adapter, Header, HeaderBufferSize);
+ }
+
+ //
+ // We hide binding sets from the router, to avoid
+ // misordering packets which it routes.
+ //
+
+ if (!IsLoopback && Binding->BindingSetMember) {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&DatagramOptions.LocalTarget, MIN (Device->MaxBindings, Binding->MasterBinding->NicId));
+#else
+ DatagramOptions.LocalTarget.NicId = Binding->MasterBinding->NicId;
+#endif
+ }
+
+
+ if ((*Device->UpperDrivers[IDENTIFIER_RIP].ReceiveHandler)(
+ (IsLoopback) ? BindingContext : Adapter->NdisBindingHandle,
+ ReceiveContext,
+ Binding->FwdAdapterContext,
+ &DatagramOptions.LocalTarget,
+ Adapter->MacInfo.MacOptions,
+ (PUCHAR)IpxHeader,
+ LookaheadBufferSize - IpxHeaderOffset,
+ (IsLoopback) ? IpxHeaderOffset+HeaderBufferSize : IpxHeaderOffset,
+ IpxPacketSize,
+ pMdl)) {
+
+ CTEAssert(FALSE);
+ (*pTdiClientCount)++;
+ }
+
+ Device->ReceiveCompletePending[IDENTIFIER_RIP] = TRUE;
+ }
+ // }
+ }
+
+ } else {
+
+ if ((Binding->ReceiveBroadcast) ||
+ (!IPX_NODE_BROADCAST(IpxHeader->DestinationNode))) {
+
+ SourceNetwork = *(UNALIGNED LONG *)IpxHeader->SourceNetwork;
+
+ //
+ // Sent to the RIP socket; check if this binding needs a
+ // network number.
+ //
+
+ if ((Binding->LocalAddress.NetworkAddress == 0) &&
+ ((SourceNetwork = *(UNALIGNED LONG *)IpxHeader->SourceNetwork) != 0)) {
+
+ switch (Device->AutoDetectState) {
+
+ case AUTO_DETECT_STATE_DONE:
+
+ //
+ // We are done with auto-detect and running.
+ // Make sure this packet is useful. If the source
+ // MAC address and source IPX node are the same then
+ // it was not routed, and we also check that it is not
+ // an IPX broadcast (otherwise a misconfigured client
+ // might confuse us).
+ //
+
+ if ((RtlEqualMemory(
+ IpxHeader->SourceNode,
+ DatagramOptions.LocalTarget.MacAddress,
+ 6)) &&
+ (*(UNALIGNED ULONG *)(IpxHeader->DestinationNode) != 0xffffffff) &&
+ (*(UNALIGNED USHORT *)(IpxHeader->DestinationNode+4) != 0xffff)) {
+
+ CTEAssert (Binding->NicId != 0);
+
+ if (IpxUpdateBindingNetwork(
+ Device,
+ Binding,
+ *(UNALIGNED LONG *)IpxHeader->SourceNetwork) == STATUS_SUCCESS) {
+
+ IPX_DEBUG (RIP, ("Binding %d is network %lx\n",
+ Binding->NicId,
+ REORDER_ULONG(Binding->LocalAddress.NetworkAddress)));
+
+ }
+ }
+
+ break;
+
+ case AUTO_DETECT_STATE_RUNNING:
+
+ //
+ // We are waiting for rip responses to figure out our
+ // network number. We count the responses that match
+ // and do not match our current value; when the non-
+ // matching number exceeds it we switch (to whatever
+ // this frame happens to have). Note that on the first
+ // non-zero response this will be the case and we will
+ // switch to that network.
+ //
+ // After auto-detect is done we call RipInsertLocalNetwork
+ // for whatever the current network is on each binding.
+ //
+
+ if (SourceNetwork == Binding->TentativeNetworkAddress) {
+
+ ++Binding->MatchingResponses;
+
+ } else {
+
+ ++Binding->NonMatchingResponses;
+
+ if (Binding->NonMatchingResponses > Binding->MatchingResponses) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Switching to net %lx on %lx (%d - %d)\n",
+ REORDER_ULONG(SourceNetwork),
+ Binding,
+ Binding->NonMatchingResponses,
+ Binding->MatchingResponses));
+
+ Binding->TentativeNetworkAddress = SourceNetwork;
+ Binding->MatchingResponses = 1;
+ Binding->NonMatchingResponses = 0;
+ }
+
+ }
+
+ //
+ // If we are auto-detecting and we have just found
+ // a default, set this so that RIP stops trying
+ // to auto-detect on other nets. BUGBUG: Unless we
+ // are on a server doing multiple detects.
+ //
+
+ if (Binding->DefaultAutoDetect) {
+ Adapter->DefaultAutoDetected = TRUE;
+ }
+ Adapter->AutoDetectResponse = TRUE;
+
+ break;
+
+ default:
+
+ //
+ // We are still initializing, or are processing auto-detect
+ // responses, not the right time to start updating stuff.
+ //
+
+ break;
+
+ }
+
+ }
+
+
+ //
+ // See if any packets are waiting for a RIP response.
+ //
+
+ if (Device->RipPacketCount > 0) {
+
+ RIP_PACKET UNALIGNED * RipPacket = (RIP_PACKET UNALIGNED *)(IpxHeader+1);
+
+ if ((IpxPacketSize >= sizeof(IPX_HEADER) + sizeof(RIP_PACKET)) &&
+ (RipPacket->Operation == RIP_RESPONSE) &&
+ (RipPacket->NetworkEntry.NetworkNumber != 0xffffffff)) {
+
+ RipProcessResponse(
+ Device,
+ &DatagramOptions.LocalTarget,
+ RipPacket);
+ }
+ }
+
+
+ //
+ // See if this is a RIP response for our virtual network
+ // and we are the only person who could respond to it.
+ // We also respond to general queries on WAN lines since
+ // we are the only machine on it.
+ //
+
+ if (Device->RipResponder) {
+
+ PRIP_PACKET RipPacket =
+ (PRIP_PACKET)(IpxHeader+1);
+
+ if ((IpxPacketSize >= sizeof(IPX_HEADER) + sizeof(RIP_PACKET)) &&
+ (RipPacket->Operation == RIP_REQUEST) &&
+ ((RipPacket->NetworkEntry.NetworkNumber == Device->VirtualNetworkNumber) ||
+ (Adapter->MacInfo.MediumAsync && (RipPacket->NetworkEntry.NetworkNumber == 0xffffffff)))) {
+
+ //
+ // Update this so our response goes out correctly.
+ //
+
+ if (!IsLoopback && Adapter->MacInfo.MediumType == NdisMedium802_5) {
+ MacUpdateSourceRouting (IDENTIFIER_IPX, Adapter, Header, HeaderBufferSize);
+ }
+
+ RipSendResponse(
+ Binding,
+ (TDI_ADDRESS_IPX UNALIGNED *)(IpxHeader->SourceNetwork),
+ &DatagramOptions.LocalTarget);
+ }
+ }
+
+#if DBG
+ ReceiveFlag = IPX_PACKET_LOG_RCV_RIP | IPX_PACKET_LOG_RCV_ALL;
+#endif
+
+ //
+ // See if the RIP upper driver wants it too.
+ //
+
+ goto RipIndication;
+ }
+
+ }
+
+
+#ifdef _PNP_POWER
+ IpxDereferenceAdapter(Adapter);
+ IpxDereferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+#endif
+
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(ReceiveFlag)) {
+ IpxLogPacket(
+ FALSE,
+ DestMacAddress,
+ DatagramOptions.LocalTarget.MacAddress,
+ (USHORT)IpxPacketSize,
+ IpxHeader,
+ IpxHeader+1);
+ }
+#endif
+ return NDIS_STATUS_SUCCESS;
+
+ //
+ // These are the failure routines for the various media types.
+ // They only differ in the debug logging.
+ //
+
+NotValid802_3:
+
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysInReceives);
+ ++IPX_MIB_ENTRY(Device, SysInHdrErrors);
+#endif SNMP
+
+#ifdef _PNP_POWER
+
+ IpxDereferenceAdapter(Adapter);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(IPX_PACKET_LOG_RCV_ALL)) {
+ IpxLogPacket(FALSE, Header, Header+6, (USHORT)PacketSize, LookaheadBuffer, (PUCHAR)LookaheadBuffer + sizeof(IPX_HEADER));
+ }
+#endif
+ return NDIS_STATUS_SUCCESS;
+
+NotValid802_5:
+
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysInReceives);
+ ++IPX_MIB_ENTRY(Device, SysInHdrErrors);
+#endif SNMP
+
+#ifdef _PNP_POWER
+
+ IpxDereferenceAdapter(Adapter);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(IPX_PACKET_LOG_RCV_ALL)) {
+ IpxLogPacket(FALSE, Header+2, Header+8, (USHORT)PacketSize, LookaheadBuffer, (PUCHAR)LookaheadBuffer + sizeof(IPX_HEADER));
+ }
+#endif
+ return NDIS_STATUS_SUCCESS;
+
+NotValidFddi:
+
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysInReceives);
+ ++IPX_MIB_ENTRY(Device, SysInHdrErrors);
+#endif SNMP
+
+#ifdef _PNP_POWER
+
+ IpxDereferenceAdapter(Adapter);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+NotValidLoopback:
+
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysInReceives);
+ ++IPX_MIB_ENTRY(Device, SysInHdrErrors);
+#endif SNMP
+
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(IPX_PACKET_LOG_RCV_ALL)) {
+ IpxLogPacket(FALSE, Header+1, Header+7, (USHORT)PacketSize, LookaheadBuffer, (PUCHAR)LookaheadBuffer + sizeof(IPX_HEADER));
+ }
+#endif
+
+ return NDIS_STATUS_SUCCESS;
+
+} /* IpxReceiveIndication */
+
+
+VOID
+IpxReceiveComplete(
+ IN NDIS_HANDLE BindingContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a connection(less) frame has been received on the
+ physical link. We dispatch to the correct packet handler here.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+ PREQUEST Request;
+ PADDRESS_FILE AddressFile;
+ PLIST_ENTRY linkage;
+ CTELockHandle OldIrq;
+ PDEVICE Device = IpxDevice;
+ PIRP pIrp;
+ PLIST_ENTRY pLE;
+
+
+ //
+ // Complete all pending receives. Do a quick check
+ // without the lock.
+ //
+
+ while (!IsListEmpty (&Adapter->RequestCompletionQueue)) {
+
+ linkage = IPX_REMOVE_HEAD_LIST(
+ &Adapter->RequestCompletionQueue,
+ Adapter->DeviceLock);
+
+ if (!IPX_LIST_WAS_EMPTY (&Adapter->RequestCompletionQueue, linkage)) {
+
+ Request = LIST_ENTRY_TO_REQUEST(linkage);
+ AddressFile = REQUEST_OPEN_CONTEXT(Request);
+
+ IPX_DEBUG (RECEIVE, ("Completing RDG on %lx\n", AddressFile));
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ IpxCompleteRequest(Request);
+ IpxFreeRequest(Adapter->Device, Request);
+
+ IpxDereferenceAddressFileSync (AddressFile, AFREF_RCV_DGRAM);
+
+ } else {
+
+ //
+ // IPX_REMOVE_HEAD_LIST returned nothing, so don't
+ // bother looping back.
+ //
+
+ break;
+
+ }
+
+ }
+
+ //
+ // Unwind this loop for speed.
+ //
+
+ if (IpxDevice->AnyUpperDriverBound) {
+
+ // PDEVICE Device = IpxDevice;
+
+ if ((Device->UpperDriverBound[0]) &&
+ (Device->ReceiveCompletePending[0])) {
+
+ (*Device->UpperDrivers[0].ReceiveCompleteHandler)(
+ (USHORT)1); // BUGBUG: Fix NIC ID or remove.
+ Device->ReceiveCompletePending[0] = FALSE;
+
+ }
+
+ if ((Device->UpperDriverBound[1]) &&
+ (Device->ReceiveCompletePending[1])) {
+
+ (*Device->UpperDrivers[1].ReceiveCompleteHandler)(
+ (USHORT)1); // BUGBUG: Fix NIC ID or remove.
+ Device->ReceiveCompletePending[1] = FALSE;
+
+ }
+
+ if ((Device->UpperDriverBound[2]) &&
+ (Device->ReceiveCompletePending[2])) {
+
+ (*Device->UpperDrivers[2].ReceiveCompleteHandler)(
+ (USHORT)1); // BUGBUG: Fix NIC ID or remove.
+ Device->ReceiveCompletePending[2] = FALSE;
+
+ }
+
+ }
+
+ CTEGetLock(&Device->Lock, &OldIrq);
+ if (pRtInfo)
+ {
+ CTEFreeLock(&Device->Lock, OldIrq);
+ IpxReferenceRt(pRtInfo, RT_EXTRACT);
+ while((pLE = ExInterlockedRemoveHeadList(&pRtInfo->CompletedIrps,
+ &pRtInfo->Lock)) != NULL)
+ {
+ pIrp = LIST_ENTRY_TO_REQUEST(pLE);
+ CTEAssert(pIrp);
+ IpxPrint0("IpxReceiveComplete: Completing extracted irp\n");
+ NTIoComplete(pIrp, (NTSTATUS)-1,(ULONG)-1);
+ }
+ IpxDereferenceRt(pRtInfo, RT_EXTRACT);
+
+ } else {
+ CTEFreeLock(&Device->Lock, OldIrq);
+ }
+
+ //
+ // If there are any Ntf completions, do them. These ntf completions
+ // are only if we discovered the address of one of our adapters.
+ //
+
+ while((pLE = ExInterlockedRemoveHeadList(&Device->NicNtfComplQueue, &Device ->Lock)) != NULL)
+ {
+ pIrp = LIST_ENTRY_TO_REQUEST(pLE);
+ CTEAssert(pIrp);
+ IpxPrint0("IpxReceiveComplete: Completing Nic Ntf irp\n");
+ NTIoComplete(pIrp, (NTSTATUS)-1, (ULONG)-1);
+ IpxDereferenceDevice (Device, DREF_NIC_NOTIFY);
+ }
+
+} /* IpxReceiveComplete */
+
+
+NTSTATUS
+IpxUpdateBindingNetwork(
+ IN PDEVICE Device,
+ IN PBINDING Binding,
+ IN ULONG Network
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when we have decided that we now know
+ the network number for a binding which we previously thought
+ was zero.
+
+Arguments:
+
+ Device - The IPX device.
+
+ Binding - The binding being updated.
+
+ Network - The new network number.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PADDRESS Address;
+ ULONG CurrentHash;
+ PLIST_ENTRY p;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // Only binding set members should have these different,
+ // and they will not have a network of 0.
+ //
+
+ Status = RipInsertLocalNetwork(
+ Network,
+ Binding->NicId,
+ Binding->Adapter->NdisBindingHandle,
+ (USHORT)((839 + Binding->MediumSpeed) / Binding->MediumSpeed));
+
+ if (Status == STATUS_SUCCESS) {
+
+ Binding->LocalAddress.NetworkAddress = Network;
+
+ //
+ // Update the device address if we have no virtual net
+ // and there is one binding (!Device->MultiCardZeroVirtual)
+ // or this is the first binding, which is the one we
+ // appear to be if a) we have no virtual net defined and
+ // b) we are bound to multiple cards.
+ //
+#ifdef _PNP_POWER
+
+ if ((!Device->MultiCardZeroVirtual) || (Binding->NicId == 1)) {
+
+ if (!Device->VirtualNetwork) {
+
+ Device->SourceAddress.NetworkAddress = Network;
+
+ //
+ // Scan through all the addresses that exist and modify
+ // their pre-constructed local IPX address to reflect
+ // the new local net and node.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (CurrentHash = 0; CurrentHash < IPX_ADDRESS_HASH_COUNT; CurrentHash++) {
+
+ for (p = Device->AddressDatabases[CurrentHash].Flink;
+ p != &Device->AddressDatabases[CurrentHash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ Address->LocalAddress.NetworkAddress = Network;
+ }
+ }
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Let SPX know because it fills in its own headers.
+ //
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_PNP_INFO IpxPnPInfo;
+
+ IpxPnPInfo.NewReservedAddress = TRUE;
+ IpxPnPInfo.NetworkAddress = Network;
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_ADDRESS_CHANGE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_ADDRESS_CHANGED to SPX: net addr: %lx\n", Network));
+ }
+
+ }
+ }
+#else
+ if ((!Device->VirtualNetwork) &&
+ ((!Device->MultiCardZeroVirtual) || (Binding->NicId == 1))) {
+
+ Device->SourceAddress.NetworkAddress = Network;
+
+ //
+ // Scan through all the addresses that exist and modify
+ // their pre-constructed local IPX address to reflect
+ // the new local net and node.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (CurrentHash = 0; CurrentHash < IPX_ADDRESS_HASH_COUNT; CurrentHash++) {
+
+ for (p = Device->AddressDatabases[CurrentHash].Flink;
+ p != &Device->AddressDatabases[CurrentHash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ Address->LocalAddress.NetworkAddress = Network;
+ }
+ }
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Let SPX know because it fills in its own
+ // headers. When we indicate a line up on NIC ID
+ // 0 it knows to requery the local address.
+ //
+ // BUGBUG: Line up indication to RIP/NB??
+ //
+
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+
+ IPX_LINE_INFO LineInfo;
+ LineInfo.LinkSpeed = Device->LinkSpeed;
+ LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ LineInfo.MacOptions = Device->MacOptions;
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].LineUpHandler)(
+ 0,
+ &LineInfo,
+ Binding->Adapter->MacInfo.RealMediumType,
+ NULL);
+
+ }
+ }
+#endif
+ } else if (Status == STATUS_DUPLICATE_NAME) {
+
+ //
+ // If it was a duplicate we still set the binding's local
+ // address to the value so we can detect binding sets.
+ //
+
+ Binding->LocalAddress.NetworkAddress = Network;
+
+ }
+
+ Binding->fInfoIndicated = FALSE;
+ if ((p = ExInterlockedRemoveHeadList(
+ &Device->NicNtfQueue,
+ &Device->Lock)) != NULL)
+ {
+ PREQUEST Request;
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ DbgPrint("IpxStatus: Got address of binding\n");
+ Status = GetNewNics(Device, Request, FALSE, NULL, 0, TRUE);
+
+ //
+ // If not success, we don't queue back the irp. It has
+ // already been queued or completed
+ //
+ if (Status != STATUS_SUCCESS)
+ {
+ DbgPrint("New address Irp screw up. Status = (%lx)\n",
+ Status);
+ }
+ else
+ {
+ KIRQL OldIrq;
+ //
+ // Status is SUCCESS
+ //
+ IoAcquireCancelSpinLock(&OldIrq);
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ IoReleaseCancelSpinLock(OldIrq);
+ REQUEST_STATUS(Request) = Status;
+ ExInterlockedInsertTailList(&Device->NicNtfComplQueue,REQUEST_LINKAGE(Request), &Device->Lock);
+ }
+
+ }
+
+ return Status;
+
+} /* IpxUpdateBindingNetwork */
+
+
+INT
+IpxReceivePacket (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a frame has been received on the physical link.
+ The packet passed up from NDIS can be held on to by the TDI clients
+ that request TDI_EVENT_RECEIVE_EX_DATAGRAM events with us.
+
+Arguments:
+
+ ProtocolBindingContext - The Adapter Binding specified at initialization time.
+
+ Packet - contains the packet received as well as some mediaspecific info.
+
+Return Value:
+
+ return of IpxReceiveIndicationCommon(),
+
+--*/
+{
+ UINT HeaderBufferSize = NDIS_GET_PACKET_HEADER_SIZE(Packet);
+ UINT firstbufferLength, bufferLength;
+ PNDIS_BUFFER pFirstBuffer;
+ PUCHAR headerBuffer;
+ NTSTATUS ntStatus;
+ INT tdiClientCount = 0;
+
+ //
+ // Query the number of buffers, the first MDL's descriptor and the packet length
+ //
+ NdisGetFirstBufferFromPacket(Packet, // packet
+ &pFirstBuffer, // first buffer descriptor
+ &headerBuffer, // ptr to the start of packet
+ &firstbufferLength,// length of the header+lookahead
+ &bufferLength); // length of the bytes in the buffers
+
+ //
+ // ReceiveContext is the packet itself
+ //
+
+ ntStatus = IpxReceiveIndicationCommon (
+ ProtocolBindingContext,
+ Packet, // ReceiveContext
+ headerBuffer,
+ HeaderBufferSize,
+ headerBuffer + HeaderBufferSize, // LookaheadBuffer
+ bufferLength - HeaderBufferSize, // LookaheadBufferSize
+ bufferLength - HeaderBufferSize, // PacketSize - since the whole packet is indicated
+ pFirstBuffer, // pMdl
+ &tdiClientCount // tdi client count
+ );
+
+ IPX_DEBUG(RECEIVE, ("IpxReceivePacket: Tdi Client Count is: %lx\n", tdiClientCount));
+
+ return tdiClientCount;
+} /* IpxReceivePacket */
+
+
+#ifdef _PNP_POWER
+
+#if defined(_M_IX86)
+_inline
+#endif
+BOOLEAN
+IpxNewVirtualNetwork(
+ IN PDEVICE Device,
+ IN BOOLEAN NewVirtualNetwork
+ )
+/*++
+
+Routine Description:
+
+ If the virtualnetwork number changed, this function records this fact
+ in the device.
+
+ Called with the BINDACCESSLOCK held.
+Arguments:
+
+ Device - Pointer to the Device.
+
+ NewVirtualNetwork - boolean to indicate if the virtual net# changed.
+
+Return Value:
+
+ BOOLEAN - to indicate whether SPX's reserved address was changed.
+
+--*/
+{
+ NTSTATUS ntStatus;
+ UCHAR VirtualNode[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
+ BOOLEAN ReservedAddrChanged = FALSE;
+
+ if (Device->VirtualNetworkNumber) {
+
+ if (NewVirtualNetwork) {
+ //
+ // If a new one appeared.
+ //
+
+ ntStatus = RipInsertLocalNetwork(
+ Device->VirtualNetworkNumber,
+ 0, // NIC ID
+ NIC_ID_TO_BINDING(Device, 1)->Adapter->NdisBindingHandle,
+ 1);
+
+ if (ntStatus != STATUS_SUCCESS) {
+
+ //
+ // Log the appropriate error, then ignore the
+ // virtual network. If the error was
+ // INSUFFICIENT_RESOURCES, the RIP module
+ // will have already logged an error.
+ //
+
+ if (ntStatus == STATUS_DUPLICATE_NAME) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Ignoring virtual network %lx, conflict\n", REORDER_ULONG (Device->VirtualNetworkNumber)));
+
+ IpxWriteResourceErrorLog(
+ Device->DeviceObject,
+ EVENT_IPX_INTERNAL_NET_INVALID,
+ 0,
+ REORDER_ULONG (Device->VirtualNetworkNumber));
+ }
+
+ Device->VirtualNetworkNumber = 0;
+ goto NoVirtualNetwork;
+
+ }
+
+ //
+ // If the number is non-zero now, a new one appeared
+ //
+ Device->VirtualNetwork = TRUE;
+ Device->MultiCardZeroVirtual = FALSE;
+ RtlCopyMemory(Device->SourceAddress.NodeAddress, VirtualNode, 6);
+ Device->SourceAddress.NetworkAddress = Device->VirtualNetworkNumber;
+ ReservedAddrChanged = TRUE;
+
+ //
+ // If RIP is not bound, then this node is a RipResponder
+ //
+ if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ Device->RipResponder = TRUE;
+ }
+ }
+
+ } else {
+NoVirtualNetwork:
+ Device->VirtualNetwork = FALSE;
+
+ //
+ // See if we need to be set up for the fake
+ // virtual network.
+ //
+
+ if (Device->ValidBindings > 1) {
+
+ CTEAssert (Device->VirtualNetworkOptional);
+
+ //
+ // In this case we return as our local node the
+ // address of the first card. We will also only
+ // direct SAP sends to that card.
+ //
+
+ Device->MultiCardZeroVirtual = TRUE;
+
+ } else {
+
+ Device->MultiCardZeroVirtual = FALSE;
+ }
+
+ if (NewVirtualNetwork) {
+ //
+ // The virtual network number disappeared this time
+ //
+
+ //
+ // Remove the prev. net # from the RIP tables here
+ //
+ RipAdjustForBindingChange (0, 0, IpxBindingDeleted);
+
+ //
+ // If we were a RipResponder, we are not anymore
+ //
+ if (Device->RipResponder) {
+ Device->RipResponder = FALSE;
+ }
+ }
+
+ //
+ // Since there is not virtual network number, SPX's reserved address is
+ // the address of the first binding. This could have changed because of
+ // several reasons: if there was a WAN binding only earlier and this time
+ // a LAN binding appeared, or if the first LAN binding disappeared. Instead
+ // of checking for all these conditions, check if the Device's sourceaddress
+ // and that of the first mis-match.
+ // NB uses the address of the first device always and hence does not need
+ // this mechanism to determine if this is a reserved address change.
+ //
+ if (!RtlEqualMemory( &Device->SourceAddress,
+ &NIC_ID_TO_BINDING(Device, 1)->LocalAddress,
+ FIELD_OFFSET(TDI_ADDRESS_IPX,Socket))) {
+
+ RtlCopyMemory( &Device->SourceAddress,
+ &NIC_ID_TO_BINDING(Device, 1)->LocalAddress,
+ FIELD_OFFSET(TDI_ADDRESS_IPX,Socket));
+
+ ReservedAddrChanged = TRUE;
+ }
+ }
+
+#ifdef SNMP
+ *(UNALIGNED ULONG *)(IPX_MIB_ENTRY(Device, SysNetNumber)) = Device->SourceAddress.NetworkAddress;
+
+ *(UNALIGNED ULONG *)(IPX_MIB_ENTRY(Device, SysNode)) =
+ *(UNALIGNED ULONG *)(Device->SourceAddress.NodeAddress);
+ *(UNALIGNED USHORT *)(IPX_MIB_ENTRY(Device, SysNode)+4) =
+ *(UNALIGNED USHORT *)(Device->SourceAddress.NodeAddress+4);
+#endif
+ return ReservedAddrChanged;
+}
+
+
+VOID
+IpxBindAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE BindContext,
+ IN PNDIS_STRING DeviceName,
+ IN PVOID SystemSpecific1,
+ IN PVOID SystemSpecific2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives a Plug and Play notification about a new
+ adapter in the machine. We are called here only if this adapter
+ is to be bound to us, so we don't make any checks for this.
+
+Arguments:
+
+ Status - NDIS_STATUS_SUCCESS, NDIS_STATUS_PENDING
+
+ BindContext - context to represent this bind indication
+
+ DeviceName - Name of the adapter that appeared (e.g. \Device\Lance1)
+
+ SystemSpecific1/2 - Not used here
+
+Return Value:
+
+ Status - NDIS_STATUS_SUCCESS
+
+--*/
+{
+ NTSTATUS ntStatus;
+ PDEVICE Device = IpxDevice;
+ PADAPTER Adapter = NULL;
+ CONFIG Config;
+ UINT i;
+ ULONG Temp, SuccessfulOpens=0;
+ PBINDING Binding;
+ BINDING_CONFIG ConfigBinding;
+ ULONG ValidBindings;
+ USHORT AutoDetectReject;
+ BOOLEAN NewVirtualNetwork = FALSE;
+ BOOLEAN FirstDevice = FALSE;
+ BOOLEAN ReservedAddrChanged = FALSE;
+ IPX_PNP_INFO IpxPnPInfo;
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_DEFINE_LOCK_HANDLE(LockHandle)
+
+ //
+ // Used for error logging
+ //
+ Config.DriverObject = (PDRIVER_OBJECT)Device->DeviceObject;
+
+ Config.RegistryPathBuffer = Device->RegistryPathBuffer;
+ ConfigBinding.AdapterName = *DeviceName;
+
+ //
+ // Read the registry to see if a virtual network number appeared/disappeared
+ //
+ ntStatus = IpxPnPGetVirtualNetworkNumber(&Config);
+
+ if (ntStatus != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("Could not read the vnet#: registrypathbuffer: %lx\n", Device->RegistryPathBuffer));
+ *Status = NDIS_STATUS_SUCCESS;
+ return;
+ }
+
+ Temp = REORDER_ULONG (Config.Parameters[CONFIG_VIRTUAL_NETWORK]);
+
+ //
+ // If the virtual network number changed, record this fact.
+ //
+ if (Device->VirtualNetworkNumber != Temp) {
+ NewVirtualNetwork = TRUE;
+ Device->VirtualNetworkNumber = Temp;
+ }
+
+ Device->VirtualNetworkOptional = (BOOLEAN)(Config.Parameters[CONFIG_VIRTUAL_OPTIONAL] != 0);
+
+ IPX_DEBUG(PNP, ("Virtual net # is: %lx\n", Temp));
+
+ //
+ // For each FrameType and Network Number configured, initialize the
+ // FrameType array in the CONFIG_BINDING
+ //
+ ntStatus = IpxPnPGetAdapterParameters(
+ &Config,
+ DeviceName,
+ &ConfigBinding);
+
+ if (ntStatus != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("Could not read the adapter params: DeviceName: %lx\n", DeviceName->Buffer));
+ *Status = NDIS_STATUS_SUCCESS;
+ return;
+ }
+
+ IPX_DEBUG(PNP, ("ConfigBinding.FrameTypeCount: %lx\n", ConfigBinding.FrameTypeCount));
+
+ //
+ // Reset the auto-detect state to init so that if a receive occurs on this binding
+ // before we can place this binding in the device's binding array, we know of it.
+ //
+ Device->AutoDetectState = AUTO_DETECT_STATE_INIT;
+
+ //
+ // Register adapter with NDIS; query the various parameters; get the WAN line count
+ // if this is a WAN adapter.
+ // Allocate the bindings corresponding to this adapter
+ //
+ for (i = 0; i < ConfigBinding.FrameTypeCount; i++) {
+
+ //
+ // If successful, this queues them on Device->InitialBindingList. [BUGBUGZZ] not right now
+ // Adapter is NULL first time and is allocated then. In subsequent calls,
+ // it is not NULL and the bindings are hooked to this adapter.
+
+ ntStatus = IpxBindToAdapter (Device, &ConfigBinding, &Adapter, i);
+
+ //
+ // If this failed because the adapter could not be bound
+ // to, then don't try any more frame types on this adapter.
+ // For other failures we do try the other frame types.
+ //
+
+ if (ntStatus == STATUS_DEVICE_DOES_NOT_EXIST) {
+ break;
+ }
+
+ //
+ // If the status is STATUS_NOT_SUPPORTED, then this frametype mapped to a previously
+ // initialized one. In this case, remove this index fron the FrameType array so that
+ // when we try to update the binding array, we dont have duplicates.
+ //
+ if (ntStatus == STATUS_NOT_SUPPORTED) {
+ ULONG j;
+
+ //
+ // Remove this frametype from the FrameType array.
+ //
+ for (j = i+1; j < ConfigBinding.FrameTypeCount; j++) {
+ ConfigBinding.FrameType[j-1] = ConfigBinding.FrameType[j];
+ }
+
+ --ConfigBinding.FrameTypeCount;
+
+ //
+ // Decrement so we see the one just moved up.
+ //
+ --i;
+
+#if DBG
+ for (j = 0; j < ISN_FRAME_TYPE_MAX; j++) {
+ IPX_DEBUG (AUTO_DETECT, ("%d: type %d, net %d, auto %d\n",
+ j, ConfigBinding.FrameType[j], ConfigBinding.NetworkNumber[j], ConfigBinding.AutoDetect[j]));
+ }
+#endif
+ continue;
+ }
+
+ if (ntStatus != STATUS_SUCCESS) {
+ continue;
+ }
+
+ if (ConfigBinding.AutoDetect[i]) {
+ Device->AutoDetect = TRUE;
+ }
+
+ CTEAssert(Adapter);
+
+ ++SuccessfulOpens;
+
+ //
+ // Even for WAN adapters, the FrameTypeCount is set to 4. We only need to
+ // allocate one binding for WAN; the others come later.
+ //
+ if (Adapter->MacInfo.MediumAsync) {
+ break;
+ }
+ }
+
+ if (SuccessfulOpens == 0) {
+ goto InitFailed;
+ }
+
+ //
+ // Place all the bindings corresponding to this adapter in the binding array
+ // Also resolve binding sets for non-autodetect bindings.
+ //
+
+ //
+ // Obtain lock to the Binding related stuff.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ IpxPnPUpdateBindingArray (Device, Adapter, &ConfigBinding);
+
+ //
+ // Release access to the Binding related stuff.
+ //
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // If at least one card appeared here, set our state
+ // to open
+ //
+ // [BUGBUGZZ]: what if all these bindings are eliminated - then
+ // the state is not open...
+ //
+ if (Device->ValidBindings > 0) {
+ if (Device->State == DEVICE_STATE_LOADED) {
+ FirstDevice = TRUE;
+ Device->State = DEVICE_STATE_OPEN;
+ }
+ }
+
+ //
+ // We don't do auto-detect/bindingsets for WAN lines: skip over.
+ //
+ if (Adapter->MacInfo.MediumAsync) {
+ goto jump_wan;
+ }
+
+ //
+ // Auto-detect the network number. Update the results for only the
+ // bindings corresponding to this adapter
+ //
+
+ //
+ // Queue a request to discover our locally attached
+ // adapter addresses. This must succeed because we
+ // just allocated our send packet pool. We need
+ // to wait for this, either because we are
+ // auto-detecting or because we need to determine
+ // if there are multiple cards on the same network.
+ //
+
+ KeInitializeEvent(
+ &Device->AutoDetectEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ Device->AutoDetectState = AUTO_DETECT_STATE_RUNNING;
+
+ //
+ // Make this 0; after we are done waiting, which means
+ // the packet has been completed, we set it to the
+ // correct value.
+ //
+
+ // Device->IncludedHeaderOffset = 0;
+
+ IPX_BEGIN_SYNC (&SyncContext);
+ ntStatus = RipQueueRequest (0xffffffff, RIP_REQUEST);
+ IPX_END_SYNC (&SyncContext);
+
+ CTEAssert (ntStatus == STATUS_PENDING);
+
+ //
+ // This is set when this rip send completes.
+ //
+
+ IPX_DEBUG (AUTO_DETECT, ("Waiting for AutoDetectEvent\n"));
+
+ KeWaitForSingleObject(
+ &Device->AutoDetectEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ Device->AutoDetectState = AUTO_DETECT_STATE_PROCESSING;
+
+ //
+ // Now that we are done receiving responses, insert the
+ // current network number for every auto-detect binding
+ // to the rip database.
+ //
+
+ //
+ // Obtain exclusive access to the Binding related stuff.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ //
+ // Note, here we go thru' only the bindings corresponding to this adapter
+ //
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+
+ Binding = Adapter->Bindings[i];
+
+ //
+ // Skip empty binding slots or bindings that were configured
+ // for a certain network number, we inserted those above.
+ // If no network number was detected, also skip it.
+ //
+
+ if ((!Binding) ||
+ (Binding->ConfiguredNetworkNumber != 0) ||
+ (Binding->TentativeNetworkAddress == 0)) {
+
+ continue;
+ }
+
+ IPX_DEBUG (AUTO_DETECT, ("Final score for %lx on %lx is %d - %d\n",
+ REORDER_ULONG(Binding->TentativeNetworkAddress),
+ Binding,
+ Binding->MatchingResponses,
+ Binding->NonMatchingResponses));
+
+ //
+ // We don't care about the status.
+ //
+
+ ntStatus = RipInsertLocalNetwork(
+ Binding->TentativeNetworkAddress,
+ Binding->NicId,
+ Binding->Adapter->NdisBindingHandle,
+ (USHORT)((839 + Binding->MediumSpeed) / Binding->MediumSpeed));
+
+ if ((ntStatus != STATUS_SUCCESS) &&
+ (ntStatus != STATUS_DUPLICATE_NAME)) {
+
+ //
+ // We failed to insert, keep it at zero, hopefully
+ // we will be able to update later.
+ //
+
+#if DBG
+ DbgPrint ("IPX: Could not insert net %lx for binding %lx\n",
+ REORDER_ULONG(Binding->LocalAddress.NetworkAddress),
+ Binding);
+#endif
+ CTEAssert (Binding->LocalAddress.NetworkAddress == 0);
+
+ } else {
+
+ Binding->LocalAddress.NetworkAddress = Binding->TentativeNetworkAddress;
+ }
+
+ Binding->LocalAddress.NetworkAddress = Binding->TentativeNetworkAddress;
+ }
+
+ // ValidBindings = Device->BindingCount;
+
+ ValidBindings = Device->ValidBindings;
+
+ // [BUGBUGZZ] if (Device->AutoDetect) {
+
+ ValidBindings = IpxResolveAutoDetect (Device, ValidBindings, &LockHandle1, &Device->RegistryPath);
+
+ //}
+
+ //
+ // Adjust all the indices by the number of AutoDetect bindings thrown away
+ //
+ // AutoDetectReject = (USHORT)(Device->BindingCount - ValidBindings);
+
+ AutoDetectReject = (USHORT)(Device->ValidBindings - ValidBindings);
+
+ Device->HighestLanNicId -= AutoDetectReject;
+ Device->HighestExternalNicId -= AutoDetectReject;
+ Device->HighestType20NicId -= AutoDetectReject;
+ Device->SapNicCount -= AutoDetectReject;
+
+ Device->ValidBindings = (USHORT)ValidBindings;
+
+ //
+ // Now see if any bindings are actually on the same
+ // network. This updates the Device->HighestExternalNicId
+ // and Device->HighestType20NicId, SapNicCount, HighestLanNicId
+ //
+
+ //
+ // Do this only for the auto-detect bindings
+ // [BUGBUGZZ] check this
+ //
+
+ //if (Device->AutoDetect) {
+ IpxResolveBindingSets (Device, Device->HighestExternalNicId);
+ //}
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+jump_wan:
+
+ IPX_DEBUG(PNP, ("BindingCount: %lu\n", Device->BindingCount));
+ IPX_DEBUG(PNP, ("ValidBindings: %lu\n", Device->ValidBindings));
+ IPX_DEBUG(PNP, ("HighestLanNicId: %lu\n", Device->HighestLanNicId));
+ IPX_DEBUG(PNP, ("HighestExternalNicId: %lu\n", Device->HighestExternalNicId));
+ IPX_DEBUG(PNP, ("HighestType20NicId: %lu\n", Device->HighestType20NicId));
+ IPX_DEBUG(PNP, ("SapNicCount: %lu\n", Device->SapNicCount));
+ IPX_DEBUG(PNP, ("BindingArray: %lx\n", Device->Bindings));
+
+ //
+ // Enable this regardless of whether any of our clients enabled b'cast.
+ // NB always enables it, so we are fine.
+ //
+ // Since we dont increment the Broadcast count in the device, we will disable b'casts
+ // correctly if the count drops to 0.
+ //
+ // If the ISN clients appear before the adapters, they increment the BCount, but
+ // since the ValidBindings is 0, all works. Then, when the adapters appear, we enable
+ // the broadcasts here.
+ //
+ // If the adapters appear before the ISN clients, then the broadcast is enabled on
+ // the adapters here and the adapter's flag is set to indicate this, which will prevent
+ // any further calls to NDIS when the ISN clients force an IpxAddBroadcast.
+ //
+ Device->EnableBroadcastPending = TRUE;
+ IpxBroadcastOperation((PVOID)TRUE);
+
+ //
+ // For multiple adapters, use the offset of the first...why not.
+ //
+
+#if 0
+ Device->IncludedHeaderOffset = Device->Bindings[1]->DefHeaderSize;
+#endif
+
+ Device->IncludedHeaderOffset = MAC_HEADER_SIZE;
+
+ //
+ // This function updates flags like RipResponder, MultiCardZeroVirtual, etc.
+ // If the VirtualNetwork number changed (NewVirtualNetwork is TRUE), it updates
+ // the Device structure and the RIP tables accordingly.
+ // It returns a boolean to indicate if SPX's reserved address changed.
+ //
+ ReservedAddrChanged = IpxNewVirtualNetwork(Device, NewVirtualNetwork);
+
+ //
+ // Update the values once the auto-detect bindings have been thrown away...
+ //
+ IpxPnPUpdateDevice(Device);
+
+ Device->AutoDetectState = AUTO_DETECT_STATE_DONE;
+
+ IPX_DEBUG (DEVICE, ("Node is %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x, ",
+ Device->SourceAddress.NodeAddress[0], Device->SourceAddress.NodeAddress[1],
+ Device->SourceAddress.NodeAddress[2], Device->SourceAddress.NodeAddress[3],
+ Device->SourceAddress.NodeAddress[4], Device->SourceAddress.NodeAddress[5]));
+ IPX_DEBUG (DEVICE, ("Network is %lx\n",
+ REORDER_ULONG (Device->SourceAddress.NetworkAddress)));
+
+ //
+ // Start the timer which updates the RIP database
+ // periodically. For the first one we do a ten
+ // second timeout (hopefully this is enough time
+ // for RIP to start if it is going to).
+ //
+ if (FirstDevice) {
+ UNICODE_STRING devicename;
+
+ //
+ // Inform TDI clients about the open of our device object.
+ //
+ devicename.MaximumLength = (USHORT)Device->DeviceNameLength;
+ devicename.Length = (USHORT)Device->DeviceNameLength - sizeof(WCHAR);
+ devicename.Buffer = Device->DeviceName;
+
+ if ((ntStatus = TdiRegisterDeviceObject(
+ &devicename,
+ &Device->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+
+ IPX_DEBUG(PNP, ("TdiRegisterDeviceObject failed: %lx", ntStatus));
+ }
+
+ IpxReferenceDevice (Device, DREF_LONG_TIMER);
+
+ CTEStartTimer(
+ &Device->RipLongTimer,
+ 10000,
+ RipLongTimeout,
+ (PVOID)Device);
+
+ }
+
+ //
+ // Set up the LineInfo struct.
+ //
+ IpxPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ IpxPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ //
+ // Inform NB and TDI of all the bindings corresponding to this adapter
+ //
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+ Binding = Adapter->Bindings[i];
+
+ //
+ // If a NULL binding or a binding set slave, dont inform NB about it.
+ //
+ if (!Binding || (Binding->NicId > Device->HighestExternalNicId)) {
+#if DBG
+ if (Binding) {
+ IPX_DEBUG(PNP, ("Binding: %lx, Binding set slave\n", Binding));
+ }
+#endif
+ continue;
+ }
+
+ //
+ // Register this address with the TDI clients.
+ //
+ RtlCopyMemory (Device->TdiRegistrationAddress->Address, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
+
+ if ((ntStatus = TdiRegisterNetAddress(
+ Device->TdiRegistrationAddress,
+ &Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+
+ IPX_DEBUG(PNP, ("TdiRegisterNetAddress failed: %lx", ntStatus));
+ }
+
+ //
+ // Lock taken to check the UpperDriverBound flag.
+ // We already have the BindAccessLock at this point.
+ //
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ //
+ // We could have informed the upper driver from IpxPnPIsnIndicate
+ // Ensure that we dont do it twice.
+ //
+ if (!Binding->IsnInformed[IDENTIFIER_NB]) {
+
+ //
+ // Also, to ensure that the indications are done in the right order,
+ // check if the first card has been indicated yet.
+ //
+ if ((Binding->NicId != 1) &&
+ !NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->IsnInformed[IDENTIFIER_NB]) {
+
+ break;
+ }
+
+ Binding->IsnInformed[IDENTIFIER_NB] = TRUE;
+
+ if (Binding->NicId == 1) {
+ IpxPnPInfo.NewReservedAddress = TRUE;
+
+ if (FirstDevice) {
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+ } else {
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+ }
+ } else {
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+ IpxPnPInfo.NewReservedAddress = FALSE;
+ }
+
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(PNP, ("PnP to NB add: %lx\n", Binding));
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+ }
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ //
+ // Always true for SPX
+ //
+ IpxPnPInfo.NewReservedAddress = TRUE;
+
+ if (FirstDevice) {
+
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+
+ //
+ // We could have informed the upper driver from IpxPnPIsnIndicate
+ //
+ if (!NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->IsnInformed[IDENTIFIER_SPX]) {
+
+ NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->IsnInformed[IDENTIFIER_SPX] = TRUE;
+ //
+ // Inform SPX - the network/node address is the Virtual one if it exists
+ // else the address of the first binding
+ //
+ IpxPnPInfo.NetworkAddress = Device->SourceAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Device->SourceAddress.NodeAddress, 6);
+
+ if (Device->VirtualNetwork) {
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 0);
+ } else {
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 1);
+ }
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(PNP, ("PnP to SPX add: %lx\n", Binding));
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ } else {
+
+ //
+ // Not the first device - inform if the reserved address changed.
+ //
+ if (ReservedAddrChanged) {
+ if (!NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->IsnInformed[IDENTIFIER_SPX]) {
+ NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->IsnInformed[IDENTIFIER_SPX] = TRUE;
+ IPX_DEBUG(PNP, ("Reserved addr changed; SPX not told of first one yet\n"));
+ }
+
+ IpxPnPInfo.NetworkAddress = Device->SourceAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Device->SourceAddress.NodeAddress, 6);
+
+ if (Device->VirtualNetwork) {
+ //
+ // new one appeared
+ //
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 0);
+ } else {
+ //
+ // Old one disappeared
+ //
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 1);
+ }
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("PnP to SPX add (res. addr change): %lx\n", Binding));
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+
+ //
+ // Release access to the Binding related stuff.
+ //
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+InitFailed:
+ *Status = NDIS_STATUS_SUCCESS;
+ return;
+
+} /* IpxBindAdapter */
+
+
+VOID
+IpxUnbindAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE UnbindContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives a Plug and Play notification about the removal
+ of an existing adapter from the machine. We are called here only if
+ this adapter is to be bound to us, so we don't make any checks for this.
+
+Arguments:
+
+ Status - NDIS_STATUS_SUCCESS, NDIS_STATUS_PENDING.
+
+ ProtocolBindingContext - the adapter that got removed.
+
+ UnbindContext - context to represent this bind indication.
+
+Return Value:
+
+ Void - return thru' Status above.
+
+--*/
+{
+ NTSTATUS ntStatus;
+ PADAPTER Adapter=(PADAPTER)ProtocolBindingContext;
+ CONFIG Config;
+ PBINDING Binding;
+ PDEVICE Device=IpxDevice;
+ ULONG i, Temp;
+ BOOLEAN NewVirtualNetwork = FALSE;
+ BOOLEAN NBReservedAddrChanged = FALSE;
+ BOOLEAN SPXInformed = FALSE;
+ IPX_PNP_INFO IpxPnPInfo;
+ PBINDING newMasterBinding;
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_DEFINE_LOCK_HANDLE(LockHandle)
+
+ //
+ // Used for error logging
+ //
+ Config.DriverObject = (PDRIVER_OBJECT)Device->DeviceObject;
+
+ Config.RegistryPathBuffer = Device->RegistryPathBuffer;
+
+ //
+ // Read the registry to see if a virtual network number appeared/disappeared
+ //
+ ntStatus = IpxPnPGetVirtualNetworkNumber(&Config);
+
+ if (ntStatus != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("Could not read the vnet#: registrypathbuffer: %lx\n", Device->RegistryPathBuffer));
+ *Status = NDIS_STATUS_SUCCESS;
+ return;
+ }
+
+ Temp = REORDER_ULONG (Config.Parameters[CONFIG_VIRTUAL_NETWORK]);
+
+ //
+ // If the VirtualNetwork number changed, record it.
+ //
+ if (Device->VirtualNetworkNumber != Temp) {
+ NewVirtualNetwork = TRUE;
+ }
+
+ Device->VirtualNetworkOptional = (BOOLEAN)(Config.Parameters[CONFIG_VIRTUAL_OPTIONAL] != 0);
+
+ IPX_DEBUG(PNP, ("Virtual net # is: %lx\n", Temp));
+
+ //
+ // If the WAN adapter disappeared, we can simply remove all the WAN bindings since
+ // all of them correspond to this single WAN adapter. Since we tell NB only about
+ // the first one of these, we need to indicate removal of only one binding to NB.
+ //
+ if (Adapter->MacInfo.MediumAsync) {
+ USHORT wanLineCount = (USHORT)Adapter->WanNicIdCount;
+
+ CTEAssert(wanLineCount == (Device->HighestExternalNicId - Device->HighestLanNicId));
+
+ //
+ // If no more bindings remain, tell upper driver of the same.
+ // We go back to the loaded state.
+ //
+
+ if ((Device->ValidBindings - wanLineCount) == 0) {
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+ Device->State = DEVICE_STATE_LOADED;
+
+ //
+ // Shut down RIP timers, complete address notify requests, etc.
+ //
+ IpxPnPToLoad();
+ } else {
+ CTEAssert(Device->State == DEVICE_STATE_OPEN);
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+ }
+
+ //
+ // DeRegister this address with the TDI clients.
+ //
+
+ //
+ // Get to the first WAN binding - this is always the one after the last LAN binding.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_ID_TO_BINDING_NO_ILOCK(Device, Device->HighestLanNicId+1);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ CTEAssert(Binding->TdiRegistrationHandle);
+
+ if ((ntStatus = TdiDeregisterNetAddress(Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("TdiDeRegisterNetAddress failed: %lx", ntStatus));
+ }
+
+ //
+ // Set up the LineInfo struct.
+ //
+ IpxPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ IpxPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ //
+ // Give the PnP indication to indicate the deletion only if it was
+ // added before.
+ //
+ if (Binding->IsnInformed[IDENTIFIER_NB]) {
+
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform NB: delete WAN device\n"));
+
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_DELETE_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(PNP, ("PnP to NB delete: %lx\n", Binding));
+ }
+#if DBG
+ else {
+ DbgPrint("WAN adapter id: %lx not indicated to NB\n", Binding->NicId);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+#endif
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+
+ //
+ // Inform SPX only if this is the last device.
+ //
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ if (IpxPnPInfo.FirstORLastDevice && Binding->IsnInformed[IDENTIFIER_SPX]) {
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ CTEAssert(Device->HighestLanNicId == 0);
+
+ //
+ // Get to the first WAN binding - this is always the one after the last LAN binding.
+ //
+ Binding = NIC_ID_TO_BINDING_NO_ILOCK(Device, Device->HighestLanNicId+1);
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform SPX: delete WAN device\n"));
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_DELETE_DEVICE,
+ &IpxPnPInfo);
+ }
+
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+
+ //
+ // Now remove these WAN bindings from the array. Move all the Slave bindings
+ // up to where the WAN bindings were.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ for (i = Device->HighestLanNicId+1; i <= Device->HighestExternalNicId; i++) {
+ //
+ // Unbind from the adapter - if it is not referenced by any other thread, it will
+ // be deleted at this point.
+ //
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ IpxUnBindFromAdapter(NIC_ID_TO_BINDING_NO_ILOCK(Device, i));
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ //
+ // Move the slave binding here.
+ //
+ INSERT_BINDING(Device, i, NIC_ID_TO_BINDING_NO_ILOCK(Device, i+wanLineCount));
+ }
+
+ //
+ // Free the demand dial binding place holder.
+ //
+ IpxUnBindFromAdapter(NIC_ID_TO_BINDING(IpxDevice, DEMAND_DIAL_ADAPTER_CONTEXT));
+
+ //
+ // Update the indices
+ //
+ Device->HighestExternalNicId -= wanLineCount;
+ Device->ValidBindings -= wanLineCount;
+ Device->BindingCount -= wanLineCount;
+ Device->SapNicCount = Device->HighestType20NicId = Device->HighestLanNicId;
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ CTEAssert(Device->HighestLanNicId == Device->HighestExternalNicId);
+
+ } else {
+ //
+ // LAN adapter disappeared.
+ //
+
+ //
+ // Set up the LineInfo struct.
+ //
+ IpxPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ IpxPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ //
+ // For each binding corresponding to this adapter, inform NB only
+ // if the binding addition was indicated.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+ Binding = Adapter->Bindings[i];
+
+ if (!Binding) {
+ continue;
+ }
+
+ //
+ // We cannot receive on this binding anymore
+ //
+ Adapter->Bindings[i] = NULL;
+
+ //
+ // If this was a slave binding, dont inform of the deletion.
+ // Just remove the binding from the binding array and the bindingset list.
+ //
+
+ if (Binding->NicId > Device->HighestExternalNicId) {
+ PBINDING MasterBinding, tempBinding;
+
+ CTEAssert(Binding->BindingSetMember);
+ CTEAssert(Binding->CurrentSendBinding == NULL);
+
+ //
+ // Traverse the bindingset list and remove this binding from there.
+ //
+ tempBinding = MasterBinding = Binding->MasterBinding;
+
+ while (tempBinding->NextBinding != MasterBinding) {
+ if (tempBinding->NextBinding == Binding) {
+ tempBinding->NextBinding = tempBinding->NextBinding->NextBinding;
+ break;
+ }
+ tempBinding = tempBinding->NextBinding;
+ }
+
+ //
+ // If no more slaves, this is no longer a bindingset.
+ //
+ if (MasterBinding->NextBinding == MasterBinding) {
+ MasterBinding->BindingSetMember = FALSE;
+ MasterBinding->CurrentSendBinding = NULL;
+ MasterBinding->ReceiveBroadcast = TRUE;
+
+ IPX_DEBUG(PNP, ("Slave binding: %lx removed, no master: %lx\n", Binding, MasterBinding));
+ }
+
+ //
+ // Change the slave binding entries to have the master's NicId
+ //
+ RipAdjustForBindingChange (Binding->NicId, MasterBinding->NicId, IpxBindingMoved);
+ IPX_DEBUG(PNP, ("RipAdjustForBindingChange (%d, %d, IpxBindingMoved)\n", Binding->NicId, MasterBinding->NicId));
+
+ //
+ // Null out the Slave binding.
+ //
+ INSERT_BINDING(Device, Binding->NicId, NULL);
+
+ --Device->ValidBindings;
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ IpxUnBindFromAdapter(Binding);
+
+ continue;
+ }
+
+ //
+ // If this was the last binding, go back to loaded state and shut down the RIP timers.
+ //
+ if (Device->ValidBindings == 1) {
+ CTEAssert(Device->HighestExternalNicId == 1);
+ CTEAssert(Device->HighestLanNicId == 1);
+ CTEAssert(Device->SapNicCount == 1);
+ CTEAssert(Device->HighestType20NicId == 1);
+
+ Device->State = DEVICE_STATE_LOADED;
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+
+ //
+ // Free the loopback binding place holder.
+ //
+ IpxUnBindFromAdapter(NIC_ID_TO_BINDING(IpxDevice, LOOPBACK_NIC_ID));
+
+ //
+ // Shut down RIP timers, complete address notify requests, etc.
+ //
+ IpxPnPToLoad();
+
+ } else {
+ CTEAssert(Device->State == DEVICE_STATE_OPEN);
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+ }
+
+ //
+ // If this was a master binding, promote a slave binding to master.
+ //
+ if (Binding->BindingSetMember) {
+
+ CTEAssert(Binding->CurrentSendBinding);
+ CTEAssert(Binding->MasterBinding == Binding);
+
+ //
+ // Promote the next slave to Master.
+ //
+ newMasterBinding = Binding->NextBinding;
+ INSERT_BINDING(Device, Binding->NicId, newMasterBinding);
+ newMasterBinding->CurrentSendBinding = newMasterBinding;
+ newMasterBinding->MasterBinding = newMasterBinding;
+
+ //
+ // If this is the only binding remaining out of its set,
+ // it is no longer part of a set.
+ //
+ if (newMasterBinding->NextBinding == Binding) {
+ newMasterBinding->NextBinding = newMasterBinding->CurrentSendBinding = NULL;
+ newMasterBinding->BindingSetMember = FALSE;
+ newMasterBinding->ReceiveBroadcast = TRUE;
+
+ IPX_DEBUG(PNP, ("Master binding: %lx removed, no master: %lx\n", Binding, newMasterBinding));
+ }
+
+ //
+ // Change the slave binding entries to have the master's NicId
+ //
+ RipAdjustForBindingChange (newMasterBinding->NicId, Binding->NicId, IpxBindingMoved);
+ IPX_DEBUG(PNP, ("RipAdjustForBindingChange (%d, %d, IpxBindingMoved)\n", newMasterBinding->NicId, Binding->NicId));
+
+ //
+ // Register slave's address with the TDI clients.
+ //
+ CTEAssert(!newMasterBinding->TdiRegistrationHandle);
+
+ RtlCopyMemory ( Device->TdiRegistrationAddress->Address,
+ &newMasterBinding->LocalAddress,
+ sizeof(TDI_ADDRESS_IPX));
+
+ if ((ntStatus = TdiRegisterNetAddress(
+ Device->TdiRegistrationAddress,
+ &newMasterBinding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+
+ IPX_DEBUG(PNP, ("TdiRegisterNetAddress failed: %lx", ntStatus));
+ }
+
+ //
+ // Null out the slave binding
+ //
+ INSERT_BINDING(Device, newMasterBinding->NicId, NULL);
+
+ newMasterBinding->NicId = Binding->NicId;
+
+ IPX_DEBUG(PNP, ("Promoted a master binding: %lx, old master: %lx\n", newMasterBinding, Binding));
+ } else {
+
+ ULONG j;
+ PBINDING WanBinding=NIC_ID_TO_BINDING_NO_ILOCK(Device, Device->HighestLanNicId+1);
+
+ if (WanBinding) {
+ --WanBinding->Adapter->LastWanNicId;
+ --WanBinding->Adapter->FirstWanNicId;
+ }
+
+ //
+ // Remove the binding from the array
+ //
+ RipAdjustForBindingChange (Binding->NicId, 0, IpxBindingDeleted);
+
+ for (j = Binding->NicId+1; j <= Device->HighestExternalNicId; j++) {
+ INSERT_BINDING(Device, j-1, NIC_ID_TO_BINDING_NO_ILOCK(Device, j));
+ --NIC_ID_TO_BINDING_NO_ILOCK(Device, j)->NicId;
+ }
+
+ INSERT_BINDING(Device, Device->HighestExternalNicId, NULL);
+
+ --Device->HighestExternalNicId;
+ --Device->HighestLanNicId;
+ --Device->HighestType20NicId;
+ --Device->SapNicCount;
+ }
+
+ --Device->ValidBindings;
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+
+ //
+ // If this is the first binding, NB's reserved will change.
+ // When we inform SPX of an address change later, we dont have
+ // this binding to know if this binding was indicated to SPX earlier.
+ // So, set SPXInformed, which is used later to determine if an address
+ // change is to be indicated to SPX later.
+ //
+ // Since NB is informed of all adapters, we inform of the reserved address
+ // change to NB if the new Binding (now at NicId 1) was indicated earlier.
+ //
+ if (Binding->NicId == 1) {
+ NBReservedAddrChanged = TRUE;
+ if (Binding->IsnInformed[IDENTIFIER_SPX]) {
+ SPXInformed = TRUE;
+ }
+ }
+
+ CTEAssert(Binding->TdiRegistrationHandle);
+
+ //
+ // DeRegister this address with the TDI clients.
+ //
+ if ((ntStatus = TdiDeregisterNetAddress(Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("TdiDeRegisterNetAddress failed: %lx", ntStatus));
+ }
+
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ //
+ // If this binding's addition was indicated earlier, indicate its deletion to NB.
+ //
+ if (Binding->IsnInformed[IDENTIFIER_NB]) {
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform NB: delete LAN device: %lx\n", Binding));
+
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_DELETE_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ //
+ // If this was a Master, indicate the addition of the (promoted) slave
+ //
+ if (Binding->BindingSetMember) {
+ IpxPnPInfo.NetworkAddress = newMasterBinding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, newMasterBinding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, newMasterBinding->NicId);
+
+ //
+ // In this case, we set the ReservedAddrChanged bit here itself so dont need
+ // to indicate a separate address changed.
+ //
+ IpxPnPInfo.NewReservedAddress = (NBReservedAddrChanged) ? TRUE : FALSE;
+ NBReservedAddrChanged = FALSE;
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform NB: add slave device: NicId: %lx\n", Binding->NicId));
+
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ newMasterBinding->IsnInformed[IDENTIFIER_NB] = TRUE;
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ }
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+
+ //
+ // Last device - inform SPX if it is bound and this device was added earlier.
+ //
+ if (IpxPnPInfo.FirstORLastDevice) {
+ IPX_DEBUG(PNP, ("Last device - inform SPX\n"));
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ if (Binding->IsnInformed[IDENTIFIER_SPX]) {
+
+ IpxPnPInfo.NetworkAddress = Device->SourceAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Device->SourceAddress.NodeAddress, 6);
+
+ if (Device->VirtualNetwork) {
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 0);
+ } else {
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 1);
+ }
+
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform SPX: last LAN device\n"));
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_DELETE_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+ }
+
+ //
+ // Unbind from the adapter so it can be deleted
+ //
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ IpxUnBindFromAdapter(Binding);
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+
+ //
+ // Update the Device and RIP tables if this is not the last device.
+ // If the reserved address changed, inform NB and SPX of this change.
+ //
+ if (!IpxPnPInfo.FirstORLastDevice) {
+
+ Binding = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1);
+
+ if (IpxNewVirtualNetwork(Device, NewVirtualNetwork)) {
+
+ IPX_DEBUG(PNP, ("SPX's reserved address changed\n"));
+
+ //
+ // SPX's reserved address changed
+ //
+ IpxPnPInfo.NewReservedAddress = TRUE;
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ //
+ // If this binding's addition was indicated earlier, indicate change of address.
+ //
+ if (SPXInformed) {
+ Binding->IsnInformed[IDENTIFIER_SPX] = TRUE;
+
+ IPX_DEBUG(PNP, ("Inform SPX: reserved address changed\n"));
+ IpxPnPInfo.NetworkAddress = Device->SourceAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Device->SourceAddress.NodeAddress, 6);
+
+ if (Device->VirtualNetwork) {
+ //
+ // new one appeared
+ //
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 0);
+ } else {
+ //
+ // Old one disappeared
+ //
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 1);
+ }
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+ } else {
+
+ //
+ // Set the first binding's flag so that when this binding goes away, we remember
+ // to inform SPX of this device's removal.
+ //
+
+ IPX_DEBUG(PNP, ("Transfer SPX informed flag to NicId: %lx\n", Binding->NicId));
+ Binding->IsnInformed[IDENTIFIER_SPX] = TRUE;
+ }
+
+ if (NBReservedAddrChanged) {
+ //
+ // NB's reserved address changed.
+ //
+ IpxPnPInfo.NewReservedAddress = TRUE;
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ //
+ // If this binding's addition was indicated earlier, indicate the change of reserved address.
+ //
+ if (Binding->IsnInformed[IDENTIFIER_NB]) {
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform NB: reserved address changed\n"));
+
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_ADDRESS_CHANGE,
+ &IpxPnPInfo);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+ }
+ }
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+
+ //
+ // Re-calculate the values of datagram sizes in the Device.
+ //
+ IpxPnPUpdateDevice(Device);
+
+ IPX_DEBUG(PNP, ("BindingCount: %lu\n", Device->BindingCount));
+ IPX_DEBUG(PNP, ("ValidBindings: %lu\n", Device->ValidBindings));
+ IPX_DEBUG(PNP, ("HighestLanNicId: %lu\n", Device->HighestLanNicId));
+ IPX_DEBUG(PNP, ("HighestExternalNicId: %lu\n", Device->HighestExternalNicId));
+ IPX_DEBUG(PNP, ("HighestType20NicId: %lu\n", Device->HighestType20NicId));
+ IPX_DEBUG(PNP, ("SapNicCount: %lu\n", Device->SapNicCount));
+ IPX_DEBUG(PNP, ("BindingArray: %lx\n", Device->Bindings));
+} /* IpxUnbindAdapter */
+
+
+VOID
+IpxTranslate(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ OUT PNET_PNP_ID IdList,
+ IN ULONG IdListLength,
+ OUT PULONG BytesReturned
+ )
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a frame has been received on the physical link.
+ The packet passed up from NDIS can be held on to by the TDI clients
+ that request TDI_EVENT_RECEIVE_EX_DATAGRAM events with us.
+
+Arguments:
+
+ ProtocolBindingContext - The Adapter Binding specified at initialization time.
+
+ ReceivedPacket - The packet received
+
+ MediaSpecificInformation - Used for media such as Irda, wireless, etc. Not used here.
+
+ HeaderBufferSize - Size of the MAC header
+
+Return Value:
+
+
+--*/
+{
+} /* IpxTranslate */
+
+#endif _PNP_POWER
+
+
diff --git a/private/ntos/tdi/isn/ipx/internal.c b/private/ntos/tdi/isn/ipx/internal.c
new file mode 100644
index 000000000..a0721679a
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/internal.c
@@ -0,0 +1,1342 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ internal.c
+
+Abstract:
+
+ This module contains the code to handle the internal
+ binding of the upper drivers to IPX.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 25-August-1995
+ Bug Fixes - tagged [SA]
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+
+NTSTATUS
+IpxInternalBind(
+ IN PDEVICE Device,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used when one of the upper drivers submits
+ a request to bind to IPX.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (Irp);
+ PIPX_INTERNAL_BIND_INPUT BindInput;
+ PIPX_INTERNAL_BIND_OUTPUT BindOutput;
+ PIPX_INTERNAL_BIND_RIP_OUTPUT BindRipOutput;
+ CTELockHandle LockHandle;
+ PIPX_NIC_DATA NicData;
+ PBINDING Binding, LastRealBinding;
+ PADAPTER Adapter;
+ ULONG Identifier;
+ ULONG BindOutputSize;
+ BOOLEAN BroadcastEnable;
+ UINT i;
+#if DBG
+ PUCHAR IdStrings[] = { "NB", "SPX", "RIP" };
+#endif
+ BOOLEAN fFwdBindAttempt = FALSE;
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
+ (sizeof(IPX_INTERNAL_BIND_INPUT) - sizeof(ULONG))) {
+
+ IPX_DEBUG (BIND, ("Bind received, bad input length %d/%d\n",
+ IrpSp->Parameters.DeviceIoControl.InputBufferLength,
+ sizeof (IPX_INTERNAL_BIND_INPUT)));
+ return STATUS_INVALID_PARAMETER;
+
+ }
+
+ BindInput = (PIPX_INTERNAL_BIND_INPUT)(Irp->AssociatedIrp.SystemBuffer);
+
+ if (BindInput->Identifier >= UPPER_DRIVER_COUNT) {
+ IPX_DEBUG (BIND, ("Bind received, bad id %d\n", BindInput->Identifier));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IPX_DEBUG (BIND, ("Bind received from id %d (%s)\n",
+ BindInput->Identifier,
+ IdStrings[BindInput->Identifier]));
+
+#ifdef _PNP_POWER
+//
+// RIP gives us version == 1 whereas Forwarder gives us 2 (ISN_VERSION).
+//
+ if (BindInput->Identifier == IDENTIFIER_RIP) {
+ if (BindInput->Version == ISN_VERSION) {
+ fFwdBindAttempt = TRUE;
+ } else {
+ CTEAssert(!Device->ForwarderBound);
+
+ if (BindInput->Version != 1) {
+ IPX_DEBUG (BIND, ("Bind: bad version %d/%d\n",
+ BindInput->Version, 1));
+ return STATUS_INVALID_PARAMETER;
+ }
+ }
+ } else {
+ if (BindInput->Version != ISN_VERSION) {
+ IPX_DEBUG (BIND, ("Bind: bad version %d/%d\n",
+ BindInput->Version, 1));
+ return STATUS_INVALID_PARAMETER;
+ }
+ }
+
+#else
+ if (BindInput->Version != 1) {
+ IPX_DEBUG (BIND, ("Bind: bad version %d/%d\n",
+ BindInput->Version, 1));
+ return STATUS_INVALID_PARAMETER;
+ }
+#endif
+
+ if (BindInput->Identifier != IDENTIFIER_RIP) {
+ BindOutputSize = sizeof(IPX_INTERNAL_BIND_OUTPUT);
+ } else {
+ BindOutputSize = FIELD_OFFSET (IPX_INTERNAL_BIND_RIP_OUTPUT, NicInfoBuffer.NicData[0]) +
+ (MIN (Device->MaxBindings, Device->HighestExternalNicId) * sizeof(IPX_NIC_DATA));
+ }
+
+ Irp->IoStatus.Information = BindOutputSize;
+
+ if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
+ BindOutputSize) {
+
+ IPX_DEBUG (BIND, ("Bind: bad output length %d/%d\n",
+ IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
+ BindOutputSize));
+
+ //
+ // Fail this request with BUFFER_TOO_SMALL. Since the
+ // I/O system may not copy the status block back to
+ // the user's status block, do that here so that
+ // he gets IoStatus.Information.
+ //
+
+ try {
+ *Irp->UserIosb = Irp->IoStatus;
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+ NOTHING;
+ }
+
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // We have verified the length, make sure we are not
+ // already bound.
+ //
+
+ Identifier = BindInput->Identifier;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ if (Device->UpperDriverBound[Identifier]) {
+ IPX_DEBUG (BIND, ("Bind: already bound\n"));
+ CTEFreeLock (&Device->Lock, LockHandle);
+ return STATUS_REQUEST_NOT_ACCEPTED;
+ }
+
+ {
+ LARGE_INTEGER ControlChId;
+
+ CCID_FROM_REQUEST(ControlChId, Irp);
+
+ IPX_DEBUG (BIND, ("Control ChId: (%d, %d) for Id: %d\n", ControlChId.HighPart, ControlChId.LowPart, Identifier));
+ Device->UpperDriverControlChannel[Identifier].QuadPart = ControlChId.QuadPart;
+ }
+
+ RtlCopyMemory(
+ &Device->UpperDrivers[Identifier],
+ BindInput,
+ sizeof (IPX_INTERNAL_BIND_INPUT)
+ );
+
+ BroadcastEnable = BindInput->BroadcastEnable;
+
+ //
+ // Now construct the output buffer.
+ //
+
+ if (Identifier != IDENTIFIER_RIP) {
+
+ BindOutput = (PIPX_INTERNAL_BIND_OUTPUT)Irp->AssociatedIrp.SystemBuffer;
+
+ BindOutput->Version = 1;
+
+ //
+ // Tell netbios our first binding's net/node instead of the
+ // virtual one.
+ //
+#ifdef _PNP_POWER
+//
+// Fill the fields in only if the adapters have already appeared
+// Else, set NodeNumber to 0 so NB/SPX know of it.
+//
+ if ((*(UNALIGNED USHORT *)(Device->SourceAddress.NodeAddress+4) != 0) ||
+ (*(UNALIGNED ULONG *)Device->SourceAddress.NodeAddress != 0)) {
+
+ IPX_DEBUG(BIND, ("Device already opened\n"));
+ CTEAssert(Device->ValidBindings);
+
+ if (Identifier == IDENTIFIER_SPX) {
+
+ //
+ // For SPX, inform directly.
+ //
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ if (!NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier]) {
+ NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier] = TRUE;
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IpxPnPIsnIndicate((PVOID)Identifier);
+
+ } else {
+ CTEAssert(FALSE);
+
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+ } else {
+ //
+ // For NB, queue a work item which will go thru' the adapters list and
+ // inform the upper drivers about each of them.
+ //
+ ExInitializeWorkItem(
+ &Device->PnPIndicationsQueueItem,
+ IpxPnPIsnIndicate,
+ (PVOID)Identifier);
+ ExQueueWorkItem(&Device->PnPIndicationsQueueItem, DelayedWorkQueue);
+ }
+
+ } else {
+ IPX_DEBUG(BIND, ("Device not open\n"));
+ *((UNALIGNED ULONG *)BindOutput->Node) = 0;
+ *((UNALIGNED USHORT *)(BindOutput->Node+4)) = 0;
+ RtlZeroMemory(&BindOutput->LineInfo, sizeof(BindOutput->LineInfo));
+ }
+
+ BindOutput->MacHeaderNeeded = MAC_HEADER_SIZE; //40;
+ BindOutput->IncludedHeaderOffset = MAC_HEADER_SIZE; // (USHORT)Device->IncludedHeaderOffset;
+
+ BindOutput->SendHandler = IpxSendFramePreFwd;
+ BindOutput->FindRouteHandler = IpxInternalFindRoute;
+ BindOutput->QueryHandler = IpxInternalQuery;
+
+#else
+ if ((Identifier == IDENTIFIER_NB) &&
+ (Device->VirtualNetwork)) {
+ RtlCopyMemory(BindOutput->Node, Device->Bindings[1]->LocalAddress.NodeAddress, 6);
+ *(UNALIGNED ULONG *)(BindOutput->Network) = Device->Bindings[1]->LocalAddress.NetworkAddress;
+ } else {
+
+ RtlCopyMemory(BindOutput->Node, Device->SourceAddress.NodeAddress, 6);
+ *(UNALIGNED ULONG *)(BindOutput->Network) = Device->SourceAddress.NetworkAddress;
+ }
+
+ BindOutput->MacHeaderNeeded = MAC_HEADER_SIZE; //40;
+
+ BindOutput->IncludedHeaderOffset = (USHORT)Device->IncludedHeaderOffset;
+
+ BindOutput->LineInfo.LinkSpeed = Device->LinkSpeed;
+ BindOutput->LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ BindOutput->LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ BindOutput->LineInfo.MacOptions = Device->MacOptions;
+
+ BindOutput->SendHandler = IpxSendFrame;
+ BindOutput->FindRouteHandler = IpxInternalFindRoute;
+ BindOutput->QueryHandler = IpxInternalQuery;
+#endif
+ BindOutput->TransferDataHandler = IpxTransferData;
+ } else {
+ //
+ // Set this so we stop RIPping for our virtual network (if
+ // we have one).
+ //
+
+ Device->RipResponder = FALSE;
+
+ //
+ // See if he wants a single wan network number.
+ //
+
+ if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength <
+ sizeof(IPX_INTERNAL_BIND_INPUT)) ||
+ ((BindInput->RipParameters & IPX_RIP_PARAM_GLOBAL_NETWORK) == 0)) {
+
+ Device->WanGlobalNetworkNumber = FALSE;
+ Device->SapNicCount = Device->HighestExternalNicId;
+
+ } else {
+
+ Device->WanGlobalNetworkNumber = TRUE;
+
+ }
+
+ BindRipOutput = (PIPX_INTERNAL_BIND_RIP_OUTPUT)Irp->AssociatedIrp.SystemBuffer;
+
+ BindRipOutput->Version = 1;
+ BindRipOutput->MaximumNicCount = MIN (Device->MaxBindings, Device->HighestExternalNicId) + 1;
+
+ BindRipOutput->MacHeaderNeeded = MAC_HEADER_SIZE; //40;
+ BindRipOutput->IncludedHeaderOffset = (USHORT)Device->IncludedHeaderOffset;
+
+ BindRipOutput->SendHandler = IpxSendFrame;
+
+ if (!fFwdBindAttempt) {
+ BindRipOutput->SegmentCount = Device->SegmentCount;
+ BindRipOutput->SegmentLocks = Device->SegmentLocks;
+
+ BindRipOutput->GetSegmentHandler = RipGetSegment;
+ BindRipOutput->GetRouteHandler = RipGetRoute;
+ BindRipOutput->AddRouteHandler = RipAddRoute;
+ BindRipOutput->DeleteRouteHandler = RipDeleteRoute;
+ BindRipOutput->GetFirstRouteHandler = RipGetFirstRoute;
+ BindRipOutput->GetNextRouteHandler = RipGetNextRoute;
+
+ //
+ // [BUGBUGZZ] remove this...
+ //
+ BindRipOutput->IncrementWanInactivityHandler = IpxInternalIncrementWanInactivity;
+ BindRipOutput->QueryWanInactivityHandler = IpxInternalQueryWanInactivity;
+ } else {
+ //
+ // [FW] New routines provided for the Forwarder
+ //
+ BindRipOutput->OpenAdapterHandler = IpxOpenAdapter;
+ BindRipOutput->CloseAdapterHandler = IpxCloseAdapter;
+ BindRipOutput->InternalSendCompleteHandler = IpxInternalSendComplete;
+ }
+
+ BindRipOutput->TransferDataHandler = IpxTransferData;
+
+ BindRipOutput->NicInfoBuffer.NicCount = (USHORT)MIN (Device->MaxBindings, Device->HighestExternalNicId);
+ BindRipOutput->NicInfoBuffer.VirtualNicId = 0;
+ if (Device->VirtualNetwork || Device->MultiCardZeroVirtual) {
+ *(UNALIGNED ULONG *)(BindRipOutput->NicInfoBuffer.VirtualNetwork) = Device->SourceAddress.NetworkAddress;
+ } else if (Device->DedicatedRouter) {
+ *(UNALIGNED ULONG *)(BindRipOutput->NicInfoBuffer.VirtualNetwork) = 0x0;
+ }
+
+ NicData = &BindRipOutput->NicInfoBuffer.NicData[0];
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+
+ //
+ // NULL bindings are WAN bindings, so we return the
+ // information from the last non-NULL binding found,
+ // which will be the first one on this adapter.
+ // Otherwise we save this as the last non-NULL one.
+ //
+
+ if (Binding == NULL) {
+ Binding = LastRealBinding;
+ } else {
+ LastRealBinding = Binding;
+ }
+
+ Adapter = Binding->Adapter;
+ NicData->NicId = i;
+ RtlCopyMemory (NicData->Node, Binding->LocalAddress.NodeAddress, 6);
+ *(UNALIGNED ULONG *)NicData->Network = Binding->LocalAddress.NetworkAddress;
+ NicData->LineInfo.LinkSpeed = Binding->MediumSpeed;
+ NicData->LineInfo.MaximumPacketSize =
+ Binding->MaxLookaheadData + sizeof(IPX_HEADER);
+ NicData->LineInfo.MaximumSendSize =
+ Binding->AnnouncedMaxDatagramSize + sizeof(IPX_HEADER);
+ NicData->LineInfo.MacOptions = Adapter->MacInfo.MacOptions;
+ NicData->DeviceType = Adapter->MacInfo.RealMediumType;
+ NicData->EnableWanRouter = Adapter->EnableWanRouter;
+
+ ++NicData;
+ }
+ }
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ }
+ if (BroadcastEnable) {
+ IpxAddBroadcast (Device);
+ }
+
+ Device->UpperDriverBound[Identifier] = TRUE;
+
+ Device->ForwarderBound = fFwdBindAttempt;
+
+ Device->AnyUpperDriverBound = TRUE;
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ return STATUS_SUCCESS;
+
+} /* IpxInternalBind */
+
+
+NTSTATUS
+IpxInternalUnbind(
+ IN PDEVICE Device,
+ IN UINT Identifier
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used when one of the upper drivers submits
+ a request to unbind from IPX. It does this by closing the
+ control channel on which the bind ioctl was submitted.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+#if DBG
+ PUCHAR IdStrings[] = { "NB", "SPX", "RIP" };
+#endif
+
+ IPX_DEBUG (BIND, ("Unbind received from id %d (%s)\n",
+ Identifier,
+ IdStrings[Identifier]));
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ if (!Device->UpperDriverBound[Identifier]) {
+ CTEFreeLock (&Device->Lock, LockHandle);
+ IPX_DEBUG (BIND, ("No existing binding\n"));
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // [FW] If RIP is unbinding, restart the long timer
+ // Also, set the RipResponder flag if virutal net configured
+
+ //
+ // BUGBUG: Deref all bindings that RIP did not close
+ //
+ if (Identifier == IDENTIFIER_RIP &&
+ Device->ForwarderBound) {
+ UINT i;
+
+ Device->ForwarderBound = FALSE;
+
+ //
+ // [FW] Walk the binding list, to deref all bindings not closed by
+ // the forwarder before it unbound from us.
+ //
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+ PBINDING Binding = NIC_ID_TO_BINDING(Device, i);
+
+ if (Binding && (Binding->FwdAdapterContext != 0)) {
+ IpxDereferenceBinding(Binding, BREF_FWDOPEN);
+ }
+ }
+ }
+
+ if (Device->VirtualNetwork) {
+ Device->RipResponder = TRUE;
+ }
+
+ //
+ // Start the timer which updates the RIP database
+ // periodically.
+ //
+
+ IpxReferenceDevice (Device, DREF_LONG_TIMER);
+
+ CTEStartTimer(
+ &Device->RipLongTimer,
+ 10000,
+ RipLongTimeout,
+ (PVOID)Device);
+
+ }
+
+ Device->UpperDriverBound[Identifier] = FALSE;
+ Device->AnyUpperDriverBound = (BOOLEAN)
+ (Device->UpperDriverBound[IDENTIFIER_RIP] ||
+ Device->UpperDriverBound[IDENTIFIER_SPX] ||
+ Device->UpperDriverBound[IDENTIFIER_NB]);
+
+ if (Device->UpperDrivers[Identifier].BroadcastEnable) {
+ IpxRemoveBroadcast (Device);
+ }
+
+#ifdef _PNP_POWER
+ if (Device->ValidBindings > 0) {
+ //
+ // If SPX went away, reset the IsnIndicate flag in the first binding
+ //
+ if (Identifier == IDENTIFIER_SPX) {
+ CTEAssert(NIC_ID_TO_BINDING(Device, 1));
+
+ if (NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier]) {
+ NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier] = FALSE;
+ IPX_DEBUG(PNP, ("SPX unbound: IsnInformed turned off\n"));
+ }
+ }
+
+ //
+ // If NB went away, reset all the Binding's flags
+ //
+ if (Identifier == IDENTIFIER_SPX) {
+ PBINDING Binding;
+ UINT i;
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i < Index; i++) {
+ Binding = NIC_ID_TO_BINDING(Device, i);
+ if (Binding && Binding->IsnInformed[Identifier]) {
+ Binding->IsnInformed[Identifier] = FALSE;
+ IPX_DEBUG(PNP, ("NB unbound: IsnInformed off for NicId: %lx\n", i));
+ }
+ }
+ }
+ }
+#endif
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ //
+ // BUGBUG: Ensure that no calls are made to bogus
+ // handlers.
+ //
+
+ return STATUS_SUCCESS;
+
+} /* IpxInternalUnbind */
+
+
+VOID
+IpxInternalFindRoute (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the entry point for upper drivers to submit
+ requests to find a remote network, which is contained in
+ FindRouteRequest->Network. FindRouteRequest->Identifier must
+ contain the identifier of the upper driver.
+
+ This request is always asynchronous and is completed by
+ a call to the FindRouteComplete handler of the upper driver.
+
+ NOTE: As a currently unspecified extension to this call,
+ we returns the tick and hop counts as two USHORTs in the
+ PVOID Reserved2 structure of the request.
+
+Arguments:
+
+ FindRouteRequest - Describes the request and contains
+ storage for IPX to use while processing it.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ ULONG Segment;
+ TDI_ADDRESS_IPX TempAddress;
+ PBINDING Binding, MasterBinding;
+ NTSTATUS Status;
+ IPX_DEFINE_SYNC_CONTEXT (SyncContext)
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ //
+ // [FW] Call the Forwarder's FindRoute if installed
+ //
+
+ if (Device->ForwarderBound) {
+ // IPX_ROUTE_ENTRY routeEntry;
+
+ Status = (*Device->UpperDrivers[IDENTIFIER_RIP].FindRouteHandler) (
+ FindRouteRequest->Network,
+ FindRouteRequest->Node,
+ FindRouteRequest);
+
+ if (Status != STATUS_SUCCESS) {
+ IPX_DEBUG (RIP, ("RouteHandler returned: %lx\n", Status));
+ } else {
+
+#if DBG
+ //
+ // If a demand-dial NIC was returned, we should have a WAN adapter. In PnP we can check this
+ // by making sure that Device->HighestLanNicId < Device->HighestExternalNicId.
+ //
+ if (FindRouteRequest->LocalTarget.NicId == DEMAND_DIAL_ADAPTER_CONTEXT) {
+ CTEAssert(Device->HighestLanNicId < Device->HighestExternalNicId);
+ }
+#endif
+
+ IPX_DEBUG(RIP, ("FindRoute for %02x-%02x-%02x-%02x-%02x-%02x returned %lx",
+ FindRouteRequest->LocalTarget.MacAddress[0],
+ FindRouteRequest->LocalTarget.MacAddress[1],
+ FindRouteRequest->LocalTarget.MacAddress[2],
+ FindRouteRequest->LocalTarget.MacAddress[3],
+ FindRouteRequest->LocalTarget.MacAddress[4],
+ FindRouteRequest->LocalTarget.MacAddress[5],
+ Status));
+
+ }
+
+ } else {
+ //
+ // First see if we have a route to this network in our
+ // table.
+ //
+
+ TempAddress.NetworkAddress = *(UNALIGNED ULONG *)(FindRouteRequest->Network);
+ //
+ // [SA] Bug #15094 Copy over the Node address so it can be used in WAN cases
+ //
+
+ // RtlZeroMemory (TempAddress.NodeAddress, 6);
+
+ *((UNALIGNED ULONG *)TempAddress.NodeAddress) = *((UNALIGNED ULONG *)FindRouteRequest->Node);
+ *((UNALIGNED USHORT *)(TempAddress.NodeAddress+4)) = *((UNALIGNED USHORT *)(FindRouteRequest->Node+4));
+
+ Segment = RipGetSegment(FindRouteRequest->Network);
+ #ifdef _PNP_POWER
+ //
+ // Since we maintain the order of locks as Bind > Device > RIP table
+ // Get the lock up-front.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ #endif
+ IPX_BEGIN_SYNC (&SyncContext);
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // This call will return STATUS_PENDING if we need to
+ // RIP for the packet.
+ //
+
+ CTEAssert ((sizeof(USHORT)*2) <= sizeof(PVOID));
+
+ Status = RipGetLocalTarget(
+ Segment,
+ &TempAddress,
+ FindRouteRequest->Type,
+ &FindRouteRequest->LocalTarget,
+ (PUSHORT)&FindRouteRequest->Reserved2);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this find route request for completion when the
+ // RIP response arrives.
+ //
+
+ CTEAssert (FindRouteRequest->Type != IPX_FIND_ROUTE_NO_RIP); // should never pend
+
+ InsertTailList(
+ &Device->Segments[Segment].FindWaitingForRoute,
+ &FindRouteRequest->Linkage);
+
+ }
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_END_SYNC (&SyncContext);
+ #ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ #endif
+ }
+
+ if (Status != STATUS_PENDING) {
+
+ if (Status == STATUS_SUCCESS && FindRouteRequest->LocalTarget.NicId) {
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_HANDLE_TO_BINDING(Device, &FindRouteRequest->LocalTarget.NicHandle);
+
+ if (Binding->BindingSetMember) {
+
+ //
+ // It's a binding set member, we round-robin the
+ // responses across all the cards to distribute
+ // the traffic.
+ //
+
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+
+ FILL_LOCAL_TARGET(&FindRouteRequest->LocalTarget, Binding->NicId);
+
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ Binding = Device->Bindings[FindRouteRequest->LocalTarget.NicId];
+
+ if (Binding->BindingSetMember) {
+
+ //
+ // It's a binding set member, we round-robin the
+ // responses across all the cards to distribute
+ // the traffic.
+ //
+
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+
+ FindRouteRequest->LocalTarget.NicId = Binding->NicId;
+
+ }
+#endif
+ }
+
+ (*Device->UpperDrivers[FindRouteRequest->Identifier].FindRouteCompleteHandler)(
+ FindRouteRequest,
+ (BOOLEAN)((Status == STATUS_SUCCESS) ? TRUE : FALSE));
+
+ }
+
+} /* IpxInternalFindRoute */
+
+
+NTSTATUS
+IpxInternalQuery(
+ IN ULONG InternalQueryType,
+#ifdef _PNP_POWER
+ IN PNIC_HANDLE NicHandle OPTIONAL,
+#else
+ IN USHORT NicId OPTIONAL,
+#endif
+ IN OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG BufferLengthNeeded OPTIONAL
+)
+
+/*++
+
+Routine Description:
+
+ This routine is the entry point for upper drivers to query
+ information from us.
+
+Arguments:
+
+ InternalQueryType - Identifies the type of the query.
+
+ NicId - The ID to query, if needed
+
+ Buffer - Input or output buffer for the query.
+
+ BufferLength - The length of the buffer.
+
+ BufferLengthNeeded - If the buffer is too short, this returns
+ the length needed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PBINDING Binding;
+ BOOLEAN BindingNeeded;
+ ULONG LengthNeeded;
+ PIPX_LINE_INFO LineInfo;
+ PUSHORT MaximumNicId;
+ PULONG ReceiveBufferSpace;
+ TDI_ADDRESS_IPX UNALIGNED * IpxAddress;
+ IPX_SOURCE_ROUTING_INFO UNALIGNED * SourceRoutingInfo;
+ ULONG SourceRoutingLength;
+ UINT MaxUserData;
+ PDEVICE Device = IpxDevice;
+#ifdef _PNP_POWER
+ USHORT NicId = NicHandle->NicId;
+
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ //
+ // First verify the parameters.
+ //
+
+ switch (InternalQueryType) {
+
+ case IPX_QUERY_LINE_INFO:
+
+ BindingNeeded = TRUE;
+ LengthNeeded = sizeof(IPX_LINE_INFO);
+ break;
+
+ case IPX_QUERY_MAXIMUM_NIC_ID:
+ case IPX_QUERY_MAX_TYPE_20_NIC_ID:
+
+ BindingNeeded = FALSE;
+ LengthNeeded = sizeof(USHORT);
+ break;
+
+ case IPX_QUERY_IS_ADDRESS_LOCAL:
+
+ BindingNeeded = FALSE; // for now we don't need it
+ LengthNeeded = sizeof(TDI_ADDRESS_IPX);
+ break;
+
+ case IPX_QUERY_RECEIVE_BUFFER_SPACE:
+
+ BindingNeeded = TRUE;
+ LengthNeeded = sizeof(ULONG);
+ break;
+
+ case IPX_QUERY_IPX_ADDRESS:
+
+ if ((NicId == 0) &&
+ (BufferLength >= sizeof(TDI_ADDRESS_IPX))) {
+
+ RtlCopyMemory (Buffer, &Device->SourceAddress, sizeof(TDI_ADDRESS_IPX));
+ return STATUS_SUCCESS;
+
+ }
+
+ BindingNeeded = TRUE;
+ LengthNeeded = sizeof(TDI_ADDRESS_IPX);
+ break;
+
+ case IPX_QUERY_SOURCE_ROUTING:
+
+ BindingNeeded = TRUE;
+ LengthNeeded = sizeof(IPX_SOURCE_ROUTING_INFO);
+ break;
+
+#ifdef _PNP_POWER
+ //
+ // These are moved down from NB/SPX to IPX. LengthNeeded is set to 0
+ // so we dont return BUFFER_TOO_SMALL here; we assume here that
+ // Bufferlength is also 0.
+ // Buffer is actually the IRP here.
+ //
+ case IPX_QUERY_DATA_LINK_ADDRESS:
+ case IPX_QUERY_NETWORK_ADDRESS:
+
+ BindingNeeded = FALSE;
+ LengthNeeded = 0;
+ break;
+#endif
+ default:
+
+ return STATUS_NOT_SUPPORTED;
+
+ }
+
+
+ if (LengthNeeded > BufferLength) {
+ if (BufferLengthNeeded != NULL) {
+ *BufferLengthNeeded = LengthNeeded;
+ }
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ if (BindingNeeded) {
+
+ if (NicId == 0) {
+ NicId = 1;
+ }
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_ID_TO_BINDING(IpxDevice, NicId);
+ if ((Binding == NULL) ||
+ (!Binding->LineUp)) {
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ Binding = IpxDevice->Bindings[NicId];
+ if ((Binding == NULL) ||
+ (!Binding->LineUp)) {
+ return STATUS_INVALID_PARAMETER;
+ }
+#endif
+ }
+
+
+ //
+ // Now return the data.
+ //
+
+ switch (InternalQueryType) {
+
+ case IPX_QUERY_LINE_INFO:
+
+ LineInfo = (PIPX_LINE_INFO)Buffer;
+ LineInfo->LinkSpeed = Binding->MediumSpeed;
+ LineInfo->MaximumPacketSize = Binding->MaxLookaheadData + sizeof(IPX_HEADER);
+ LineInfo->MaximumSendSize = Binding->AnnouncedMaxDatagramSize + sizeof(IPX_HEADER);
+ LineInfo->MacOptions = Binding->Adapter->MacInfo.MacOptions;
+ break;
+
+ case IPX_QUERY_MAXIMUM_NIC_ID:
+
+ MaximumNicId = (PUSHORT)Buffer;
+ *MaximumNicId = MIN (Device->MaxBindings, IpxDevice->HighestExternalNicId);
+ break;
+
+ case IPX_QUERY_IS_ADDRESS_LOCAL:
+
+ IpxAddress = (TDI_ADDRESS_IPX UNALIGNED *)Buffer;
+ if (!IpxIsAddressLocal(IpxAddress)) {
+ return STATUS_NO_SUCH_DEVICE;
+ }
+ break;
+
+ case IPX_QUERY_RECEIVE_BUFFER_SPACE:
+
+ ReceiveBufferSpace = (PULONG)Buffer;
+ *ReceiveBufferSpace = Binding->Adapter->ReceiveBufferSpace;
+ break;
+
+ case IPX_QUERY_IPX_ADDRESS:
+
+ RtlCopyMemory (Buffer, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
+ break;
+
+ case IPX_QUERY_SOURCE_ROUTING:
+
+ SourceRoutingInfo = (IPX_SOURCE_ROUTING_INFO UNALIGNED *)Buffer;
+
+ MacLookupSourceRouting(
+ SourceRoutingInfo->Identifier,
+ Binding,
+ SourceRoutingInfo->RemoteAddress,
+ SourceRoutingInfo->SourceRouting,
+ &SourceRoutingLength);
+
+ //
+ // Reverse the direction of the source routing since it
+ // is returned in the outgoing order.
+ //
+
+ if (SourceRoutingLength > 0) {
+ SourceRoutingInfo->SourceRouting[0] &= 0x7f;
+ }
+ SourceRoutingInfo->SourceRoutingLength = (USHORT)SourceRoutingLength;
+
+ MacReturnMaxDataSize(
+ &Binding->Adapter->MacInfo,
+ SourceRoutingInfo->SourceRouting,
+ SourceRoutingLength,
+ Binding->MaxSendPacketSize,
+ &MaxUserData);
+
+ //
+ // MaxUserData does not include the MAC header but does include
+ // any extra 802.2 etc. headers, so we adjust for that to get the
+ // size starting at the IPX header.
+ //
+
+ SourceRoutingInfo->MaximumSendSize =
+ MaxUserData -
+ (Binding->DefHeaderSize - Binding->Adapter->MacInfo.MinHeaderLength);
+
+ break;
+
+ case IPX_QUERY_MAX_TYPE_20_NIC_ID:
+
+ MaximumNicId = (PUSHORT)Buffer;
+ *MaximumNicId = MIN (Device->MaxBindings, IpxDevice->HighestType20NicId);
+ break;
+
+#ifdef _PNP_POWER
+ case IPX_QUERY_DATA_LINK_ADDRESS:
+ case IPX_QUERY_NETWORK_ADDRESS:
+ //
+ // Call the TDI query equivalent here.
+ //
+ return IpxTdiQueryInformation(Device, (PREQUEST)Buffer);
+
+#endif
+ }
+
+#ifdef _PNP_POWER
+ //
+ // If Binding was needed earlier, it was referenced, deref it now.
+ //
+ if (BindingNeeded) {
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ }
+#endif
+
+ //
+ // If we haven't returned failure by now, succeed.
+ //
+
+ return STATUS_SUCCESS;
+
+} /* IpxInternalQuery */
+
+
+VOID
+IpxInternalIncrementWanInactivity(
+#ifdef _PNP_LATER
+// RIP not converted yet...
+//
+ IN NIC_HANDLE NicHandle
+#else
+ IN USHORT NicId
+#endif
+)
+
+/*++
+
+Routine Description:
+
+ This routine is the entry point where rip calls us to increment
+ the inactivity counter on a wan binding. This is done every
+ minute.
+
+Arguments:
+
+ NicId - The NIC ID of the wan binding.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+#ifdef _PNP_POWER
+ PBINDING Binding;
+
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ IPX_GET_LOCK1(&IpxDevice->BindAccessLock, &LockHandle1);
+ //
+ // [BUGBUGZZ] Change to NIC_HANDLE_TO_BINDING later. Not done yet since RIP not changed to
+ // use NICHANDLE instead of NicId
+ //
+ Binding = NIC_ID_TO_BINDING(IpxDevice, NicId);
+
+ if ((Binding != NULL) &&
+ (Binding->Adapter->MacInfo.MediumAsync)) {
+
+ ++Binding->WanInactivityCounter;
+
+ } else {
+
+ CTEAssert (FALSE);
+
+ }
+ IPX_FREE_LOCK1(&IpxDevice->BindAccessLock, LockHandle1);
+#else
+ PBINDING Binding = IpxDevice->Bindings[NicId];
+
+ if ((Binding != NULL) &&
+ (Binding->Adapter->MacInfo.MediumAsync)) {
+
+ ++Binding->WanInactivityCounter;
+
+ } else {
+
+ CTEAssert (FALSE);
+
+ }
+#endif
+
+} /* IpxInternalIncrementWanInactivity */
+
+
+ULONG
+IpxInternalQueryWanInactivity(
+#ifdef _PNP_LATER
+ IN NIC_HANDLE NicHandle
+#else
+ IN USHORT NicId
+#endif
+)
+
+/*++
+
+Routine Description:
+
+ This routine is the entry point where rip calls us to query
+ the inactivity counter on a wan binding.
+
+Arguments:
+
+ NicId - The NIC ID of the wan binding.
+
+Return Value:
+
+ The inactivity counter for this binding.
+
+--*/
+
+{
+#ifdef _PNP_POWER
+ PBINDING Binding;
+
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ IPX_GET_LOCK1(&IpxDevice->BindAccessLock, &LockHandle1);
+ // Binding = NIC_HANDLE_TO_BINDING(IpxDevice, &NicHandle);
+
+ Binding = NIC_ID_TO_BINDING(IpxDevice, NicId);
+ if ((Binding != NULL) &&
+ (Binding->Adapter->MacInfo.MediumAsync)) {
+ IPX_FREE_LOCK1(&IpxDevice->BindAccessLock, LockHandle1);
+ return Binding->WanInactivityCounter;
+
+ } else {
+ IPX_FREE_LOCK1(&IpxDevice->BindAccessLock, LockHandle1);
+ CTEAssert (FALSE);
+ return 0;
+
+ }
+
+#else
+ PBINDING Binding = IpxDevice->Bindings[NicId];
+
+ if ((Binding != NULL) &&
+ (Binding->Adapter->MacInfo.MediumAsync)) {
+
+ return Binding->WanInactivityCounter;
+
+ } else {
+
+ CTEAssert (FALSE);
+ return 0;
+
+ }
+#endif
+
+} /* IpxInternalQueryWanInactivity */
+
+#ifdef _PNP_POWER
+
+VOID
+IpxPnPIsnIndicate(
+ IN PVOID Param
+)
+
+/*++
+
+Routine Description:
+
+ This routine goes through the list of adapters and informs (thru' PnP indications)
+ the ISN drivers bound to IPX about any new adapters that have appeared before the
+ bind took place.
+
+ This is queued as a work item in the InternalBind routine.
+
+Arguments:
+
+ Param - the upper driver identifier.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Identifier = (ULONG)Param;
+ PDEVICE Device=IpxDevice;
+ ULONG i;
+ PBINDING Binding;
+ IPX_PNP_INFO IpxPnPInfo;
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ //
+ // Set up the LineInfo struct.
+ //
+
+ //
+ // BUGBUG: Do we give Binding-specific information here?
+ //
+ IpxPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ IpxPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ switch(Identifier) {
+ case IDENTIFIER_NB:
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ //
+ // Inform about all the adapters
+ //
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+ Binding = NIC_ID_TO_BINDING(Device, i);
+
+ if (!Binding) {
+ continue;
+ }
+
+ //
+ // We could have informed the upper driver from IpxBindAdapter
+ //
+ if (!Binding->IsnInformed[Identifier]) {
+ Binding->IsnInformed[Identifier] = TRUE;
+
+ //
+ // Inform NB - the reserved network/node address is always that of the first
+ // binding
+ //
+ if (i==1) {
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+ IpxPnPInfo.NewReservedAddress = TRUE;
+ } else {
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+ IpxPnPInfo.NewReservedAddress = FALSE;
+ }
+
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, (USHORT)i);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[Identifier].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(PNP, ("IpxPnPIsnIndicate: PnP to NB add: %lx\n", Binding));
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ }
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ break;
+
+ case IDENTIFIER_SPX:
+ //
+ // For SPX this is called directly, with the IsnInformed flag appropriately set.
+ // This is done so that the IsnInformed flag cannot be changed under
+ // us by the BindAdapter routine.
+ //
+#if 0
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ if (!NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier]) {
+ NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier] = TRUE;
+#endif
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+ //
+ // Inform of the reserved address only
+ //
+ if (Device->VirtualNetwork) {
+ IpxPnPInfo.NetworkAddress = Device->SourceAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Device->SourceAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 0);
+ } else {
+ IpxPnPInfo.NetworkAddress = NIC_ID_TO_BINDING(Device, 1)->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, NIC_ID_TO_BINDING(Device, 1)->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 1);
+ }
+
+ IpxPnPInfo.NewReservedAddress = TRUE;
+
+ // IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ (*Device->UpperDrivers[Identifier].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(PNP, ("IpxPnPIsnIndicate: PnP to SPX add: %lx\n", NIC_ID_TO_BINDING(Device, 1)));
+#if 0
+ } else {
+ CTEAssert(FALSE);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+#endif
+
+ }
+}
+#endif
diff --git a/private/ntos/tdi/isn/ipx/ipx.rc b/private/ntos/tdi/isn/ipx/ipx.rc
new file mode 100644
index 000000000..3c403b684
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/ipx.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "ISN IPX Protocol Driver"
+#define VER_INTERNALNAME_STR "isnipx.sys"
+#define VER_ORIGINALFILENAME_STR "isnipx.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/tdi/isn/ipx/ipxprocs.h b/private/ntos/tdi/isn/ipx/ipxprocs.h
new file mode 100644
index 000000000..0b43029db
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/ipxprocs.h
@@ -0,0 +1,1675 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ ipxprocs.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ IPX module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports - tagged [CH]
+ 1. Added new functions - IpxReceivePacket, IpxReceiveIndicationCommon
+
+ Sanjay Anand (SanjayAn) 27-Oct-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+--*/
+
+
+//
+// MACROS.
+//
+//
+// Debugging aids
+//
+
+//
+// VOID
+// PANIC(
+// IN PSZ Message
+// );
+//
+
+#if DBG
+#define PANIC(Msg) \
+ CTEPrint ((Msg))
+#else
+#define PANIC(Msg)
+#endif
+
+
+//
+// These are define to allow CTEPrints that disappear when
+// DBG is 0.
+//
+
+#if STEFAN_DBG
+//#if DBG
+#define IpxPrint0(fmt) DbgPrint(fmt)
+#define IpxPrint1(fmt,v0) DbgPrint(fmt,v0)
+#define IpxPrint2(fmt,v0,v1) DbgPrint(fmt,v0,v1)
+#define IpxPrint3(fmt,v0,v1,v2) DbgPrint(fmt,v0,v1,v2)
+#define IpxPrint4(fmt,v0,v1,v2,v3) DbgPrint(fmt,v0,v1,v2,v3)
+#define IpxPrint5(fmt,v0,v1,v2,v3,v4) DbgPrint(fmt,v0,v1,v2,v3,v4)
+#define IpxPrint6(fmt,v0,v1,v2,v3,v4,v5) DbgPrint(fmt,v0,v1,v2,v3,v4,v5)
+#else
+#define IpxPrint0(fmt)
+#define IpxPrint1(fmt,v0)
+#define IpxPrint2(fmt,v0,v1)
+#define IpxPrint3(fmt,v0,v1,v2)
+#define IpxPrint4(fmt,v0,v1,v2,v3)
+#define IpxPrint5(fmt,v0,v1,v2,v3,v4)
+#define IpxPrint6(fmt,v0,v1,v2,v3,v4,v5)
+#endif
+
+
+//
+// Routines to log packets to a buffer.
+//
+
+#if DBG
+#define IPX_PACKET_LOG 1
+#endif
+
+#ifdef IPX_PACKET_LOG
+
+//
+// The size of this is 64 bytes for easy display.
+//
+
+typedef struct _IPX_PACKET_LOG_ENTRY {
+ UCHAR SendReceive;
+ UCHAR TimeStamp[5]; // low 5 digits of tick count.
+ UCHAR DestMac[6];
+ UCHAR SrcMac[6];
+ UCHAR Length[2];
+ IPX_HEADER IpxHeader;
+ UCHAR Data[14];
+} IPX_PACKET_LOG_ENTRY, *PIPX_PACKET_LOG_ENTRY;
+
+#define IPX_PACKET_LOG_LENGTH 128
+extern ULONG IpxPacketLogDebug;
+extern USHORT IpxPacketLogSocket;
+EXTERNAL_LOCK(IpxPacketLogLock);
+extern IPX_PACKET_LOG_ENTRY IpxPacketLog[IPX_PACKET_LOG_LENGTH];
+extern PIPX_PACKET_LOG_ENTRY IpxPacketLogLoc;
+extern PIPX_PACKET_LOG_ENTRY IpxPacketLogEnd;
+
+//
+// Bit fields in IpxPacketLogDebug
+//
+
+#define IPX_PACKET_LOG_RCV_RIP 0x0001 // All RIP packets
+#define IPX_PACKET_LOG_RCV_SPX 0x0002 // All SPX packets
+#define IPX_PACKET_LOG_RCV_NB 0x0004 // All Netbios packets
+#define IPX_PACKET_LOG_RCV_OTHER 0x0008 // All TDI client packets
+#define IPX_PACKET_LOG_RCV_SOCKET 0x0010 // All packets to IpxPacketLogSocket
+#define IPX_PACKET_LOG_RCV_ALL 0x0020 // All packets (even non-IPX)
+
+#define IPX_PACKET_LOG_SEND_RIP 0x0001 // All RIP packets
+#define IPX_PACKET_LOG_SEND_SPX 0x0002 // All SPX packets
+#define IPX_PACKET_LOG_SEND_NB 0x0004 // All Netbios packets
+#define IPX_PACKET_LOG_SEND_OTHER 0x0008 // All TDI client packets
+#define IPX_PACKET_LOG_SEND_SOCKET 0x0010 // All packets from IpxPacketLogSocket
+
+VOID
+IpxLogPacket(
+ IN BOOLEAN Send,
+ IN PUCHAR DestMac,
+ IN PUCHAR SrcMac,
+ IN USHORT Length,
+ IN PVOID IpxHeader,
+ IN PVOID Data
+ );
+
+#define PACKET_LOG(_Bit) (IpxPacketLogDebug & (_Bit))
+
+#else // IPX_PACKET_LOG
+
+#define IpxLogPacket(_MacHeader,_Length,_IpxHeader,_Data)
+#define PACKET_LOG(_Bit) 0
+
+#endif // IPX_PACKET_LOG
+
+#ifdef _PNP_POWER
+//
+// In load-only PnP, references are not needed on adapters. This should be changed
+// to actually take the reference post 4.0.
+//
+// BUGBUG: Revisit Post 4.0 - Keep the actual instructions around for ease of activation later.
+//
+#define IpxReferenceAdapter(_adapter)
+ // InterlockedIncrement(&(_adapter)->ReferenceCount)
+
+#define IpxDereferenceAdapter(_adapter)
+/*
+ if (InterlockedDecrement(&(_adapter)->ReferenceCount) == 0) {\
+ IpxCloseNdis(_adapter); \
+ IpxDestroyAdapter(_adapter);\
+ }\
+*/
+#endif
+
+//
+// In load-only PnP case, we dont need the references on bindings. All such references
+// have been changed to this macro.
+//
+#define IpxReferenceBinding1(_Binding, _Type)
+
+#define IpxDereferenceBinding1(_Binding, _Type)
+
+#if DBG
+
+#define IpxReferenceBinding(_Binding, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Binding)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefBinding (_Binding)
+
+#define IpxDereferenceBinding(_Binding, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Binding)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefBinding (_Binding)
+
+#define IpxReferenceDevice(_Device, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Device)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefDevice (_Device)
+
+#define IpxDereferenceDevice(_Device, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Device)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefDevice (_Device)
+
+
+#define IpxReferenceAddress(_Address, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Address)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefAddress (_Address)
+
+#define IpxReferenceAddressLock(_Address, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Address)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefAddressLock (_Address)
+
+#define IpxDereferenceAddress(_Address, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Address)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefAddress (_Address)
+
+#define IpxDereferenceAddressSync(_Address, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Address)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefAddressSync (_Address)
+
+
+#define IpxReferenceAddressFile(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefAddressFile (_AddressFile)
+
+#define IpxReferenceAddressFileLock(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefAddressFileLock (_AddressFile)
+
+#define IpxReferenceAddressFileSync(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefAddressFileSync (_AddressFile)
+
+#define IpxDereferenceAddressFile(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefAddressFile (_AddressFile)
+
+#define IpxDereferenceAddressFileSync(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefAddressFileSync (_AddressFile)
+
+#define IpxTransferReferenceAddressFile(_AddressFile, _OldType, _NewType) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_NewType], \
+ 1, \
+ &IpxGlobalInterlock); \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_OldType], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock);
+
+#define IpxReferenceRt(_Rt, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Rt)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefRt (_Rt)
+
+#define IpxDereferenceRt(_Rt, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Rt)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefRt (_Rt)
+
+#else // DBG
+
+#define IpxReferenceBinding(_Binding, _Type) \
+ InterlockedIncrement(&(_Binding)->ReferenceCount)
+
+#define IpxDereferenceBinding(_Binding, _Type) \
+ IpxDerefBinding (_Binding)
+
+#define IpxReferenceDevice(_Device, _Type) \
+ InterlockedIncrement(&(_Device)->ReferenceCount)
+
+#define IpxDereferenceDevice(_Device, _Type) \
+ IpxDerefDevice (_Device)
+
+#define IpxReferenceAddress(_Address, _Type) \
+ InterlockedIncrement(&(_Address)->ReferenceCount)
+
+#define IpxReferenceAddressLock(_Address, _Type) \
+ InterlockedIncrement(&(_Address)->ReferenceCount)
+
+#define IpxDereferenceAddress(_Address, _Type) \
+ IpxDerefAddress (_Address)
+
+#define IpxDereferenceAddressSync(_Address, _Type) \
+ IpxDerefAddressSync (_Address)
+
+#define IpxReferenceAddressFile(_AddressFile, _Type) \
+ InterlockedIncrement(&(_AddressFile)->ReferenceCount)
+
+#define IpxReferenceAddressFileLock(_AddressFile, _Type) \
+ InterlockedIncrement(&(_AddressFile)->ReferenceCount)
+
+#define IpxReferenceAddressFileSync(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG( \
+ &(_AddressFile)->ReferenceCount, \
+ 1, \
+ (_AddressFile)->AddressLock)
+
+#define IpxDereferenceAddressFile(_AddressFile, _Type) \
+ if (InterlockedDecrement(&(_AddressFile)->ReferenceCount) == 0) { \
+ IpxDestroyAddressFile (_AddressFile); \
+ }
+
+#define IpxDereferenceAddressFileSync(_AddressFile, _Type) \
+ if (InterlockedDecrement(&(_AddressFile)->ReferenceCount) == 0) { \
+ IpxDestroyAddressFile (_AddressFile); \
+ }
+
+#define IpxTransferReferenceAddressFile(_AddressFile, _OldType, _NewType)
+
+#define IpxReferenceRt(_Rt, _Type) \
+ InterlockedIncrement(&(_Rt)->ReferenceCount)
+
+#define IpxDereferenceRt(_Rt, _Type) \
+ IpxDerefRt (_Rt)
+
+#endif // DBG
+
+
+
+#if DBG
+
+#define IpxAllocateMemory(_BytesNeeded,_Tag,_Description) \
+ IpxpAllocateTaggedMemory(_BytesNeeded,_Tag,_Description)
+
+#define IpxFreeMemory(_Memory,_BytesAllocated,_Tag,_Description) \
+ IpxpFreeTaggedMemory(_Memory,_BytesAllocated,_Tag,_Description)
+
+#else // DBG
+
+#define IpxAllocateMemory(_BytesNeeded,_Tag,_Description) \
+ IpxpAllocateMemory(_BytesNeeded,_Tag,(BOOLEAN)((_Tag) != MEMORY_CONFIG))
+
+#define IpxFreeMemory(_Memory,_BytesAllocated,_Tag,_Description) \
+ IpxpFreeMemory(_Memory,_BytesAllocated,(BOOLEAN)((_Tag) != MEMORY_CONFIG))
+
+
+#endif // DBG
+
+
+//
+// This routine compares two node addresses.
+//
+
+#define IPX_NODE_EQUAL(_A,_B) \
+ ((*(UNALIGNED ULONG *)((PUCHAR)(_A)) == *(UNALIGNED ULONG *)((PUCHAR)(_B))) && \
+ (*(UNALIGNED USHORT *)(((PUCHAR)(_A))+4) == *(UNALIGNED USHORT *)(((PUCHAR)(_B))+4)))
+
+//
+// This routine checks if an address is the broadcast address.
+//
+
+#define IPX_NODE_BROADCAST(_A) \
+ ((*(UNALIGNED ULONG *)((PUCHAR)(_A)) == 0xffffffff) && \
+ (*(UNALIGNED USHORT *)(((PUCHAR)(_A))+4) == 0xffff))
+
+//
+// This routine does an ordered compare of two node addresses. It
+// can handle the first address having the source-routing bit on.
+//
+
+#define IPX_NODE_COMPARE(_A,_B,_R) \
+ if ((*(_R) = (*(UNALIGNED SHORT *)(((PUCHAR)(_A))+4) - *(UNALIGNED SHORT *)(((PUCHAR)(_B))+4))) == 0) { \
+ *(_R) = ((*(UNALIGNED LONG *)((PUCHAR)(_A)) & 0xffffff7f) - *(UNALIGNED LONG *)((PUCHAR)(_B))); \
+ }
+
+
+
+//
+// Routines in action.c
+//
+
+NTSTATUS
+IpxTdiAction(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+IpxCancelAction(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+IpxAbortLineChanges(
+ IN PVOID ControlChannelContext
+ );
+
+VOID
+IpxAbortNtfChanges(
+ IN PVOID ControlChannelContext
+ );
+
+NTSTATUS
+IpxIndicateLineUp(
+ IN PDEVICE Device,
+ IN USHORT NicId,
+ IN ULONG Network,
+ IN UCHAR LocalNode[6],
+ IN UCHAR RemoteNode[6]
+ );
+
+//
+// Routines in adapter.c
+//
+
+VOID
+IpxRefBinding(
+ IN PBINDING Binding
+ );
+
+VOID
+IpxDerefBinding(
+ IN PBINDING Binding
+ );
+
+NTSTATUS
+IpxCreateAdapter(
+ IN PDEVICE Device,
+ IN PUNICODE_STRING AdapterName,
+ IN OUT PADAPTER *AdapterPtr
+ );
+
+VOID
+IpxDestroyAdapter(
+ IN PADAPTER Adapter
+ );
+
+NTSTATUS
+IpxCreateBinding(
+ IN PDEVICE Device,
+ IN PBINDING_CONFIG ConfigBinding OPTIONAL,
+ IN ULONG NetworkNumberIndex,
+ IN PWCHAR AdapterName,
+ IN OUT PBINDING *BindingPtr
+ );
+
+VOID
+IpxDestroyBinding(
+ IN PBINDING Binding
+ );
+
+#ifdef _PNP_POWER
+VOID
+IpxAllocateBindingPool(
+ IN PDEVICE Device
+ );
+
+PSINGLE_LIST_ENTRY
+IpxPopBinding(
+ PDEVICE Device
+ );
+#endif
+
+//
+// [FW] New functions added for Forwarder support
+//
+
+NTSTATUS
+IpxOpenAdapter(
+ IN NIC_HANDLE AdapterIndex,
+ IN ULONG FwdAdapterContext,
+ OUT PNIC_HANDLE IpxAdapterContext
+ );
+
+NTSTATUS
+IpxCloseAdapter(
+ IN NIC_HANDLE IpxAdapterContext
+ );
+
+//
+// Routines in address.c
+//
+
+TDI_ADDRESS_IPX UNALIGNED *
+IpxParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress
+ );
+
+BOOLEAN
+IpxValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength
+ );
+
+#if DBG
+
+VOID
+IpxBuildTdiAddress(
+ IN PVOID AddressBuffer,
+ IN ULONG Network,
+ IN UCHAR Node[6],
+ IN USHORT Socket
+ );
+
+#else
+
+#define IpxBuildTdiAddress(_AddressBuffer,_Network,_Node,_Socket) { \
+ TA_IPX_ADDRESS UNALIGNED * _IpxAddress = (TA_IPX_ADDRESS UNALIGNED *)(_AddressBuffer); \
+ _IpxAddress->TAAddressCount = 1; \
+ _IpxAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX); \
+ _IpxAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX; \
+ _IpxAddress->Address[0].Address[0].NetworkAddress = (_Network); \
+ _IpxAddress->Address[0].Address[0].Socket = (_Socket); \
+ RtlCopyMemory(_IpxAddress->Address[0].Address[0].NodeAddress, (_Node), 6); \
+}
+
+#endif
+
+NTSTATUS
+IpxOpenAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+IpxOpenAddressM(
+ IN PDEVICE Device,
+ IN PREQUEST Request,
+ IN ULONG Index
+ );
+
+USHORT
+IpxAssignSocket(
+ IN PDEVICE Device
+ );
+
+PADDRESS
+IpxCreateAddress(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ );
+
+NTSTATUS
+IpxVerifyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+IpxDestroyAddress(
+ IN PVOID Parameter
+ );
+
+#if DBG
+
+VOID
+IpxRefAddress(
+ IN PADDRESS Address
+ );
+
+VOID
+IpxRefAddressLock(
+ IN PADDRESS Address
+ );
+
+#endif
+
+VOID
+IpxDerefAddress(
+ IN PADDRESS Address
+ );
+
+VOID
+IpxDerefAddressSync(
+ IN PADDRESS Address
+ );
+
+PADDRESS_FILE
+IpxCreateAddressFile(
+ IN PDEVICE Device
+ );
+
+NTSTATUS
+IpxDestroyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+#if DBG
+
+VOID
+IpxRefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+IpxRefAddressFileLock(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+IpxRefAddressFileSync(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+IpxDerefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+IpxDerefAddressFileSync(
+ IN PADDRESS_FILE AddressFile
+ );
+
+#endif
+
+PADDRESS
+IpxLookupAddress(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ );
+
+NTSTATUS
+IpxStopAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+NTSTATUS
+IpxCloseAddressFile(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+//
+// Routines in device.c
+//
+
+VOID
+IpxRefDevice(
+ IN PDEVICE Device
+ );
+
+VOID
+IpxDerefDevice(
+ IN PDEVICE Device
+ );
+
+NTSTATUS
+IpxCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN ULONG SegmentCount,
+ IN OUT PDEVICE *DevicePtr
+ );
+
+VOID
+IpxDestroyDevice(
+ IN PDEVICE Device
+ );
+
+
+//
+// Routines in driver.c
+//
+#ifdef _PNP_POWER
+VOID
+IpxPnPUpdateDevice(
+ IN PDEVICE Device
+ );
+#endif
+
+BOOLEAN
+IpxIsAddressLocal(
+ IN TDI_ADDRESS_IPX UNALIGNED * SourceAddress
+ );
+
+PVOID
+IpxpAllocateMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN BOOLEAN ChargeDevice
+ );
+
+VOID
+IpxpFreeMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN BOOLEAN ChargeDevice
+ );
+
+#if DBG
+
+PVOID
+IpxpAllocateTaggedMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ );
+
+VOID
+IpxpFreeTaggedMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ );
+
+#endif
+
+VOID
+IpxWriteResourceErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue
+ );
+
+VOID
+IpxWriteGeneralErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN ULONG DumpDataCount,
+ IN ULONG DumpData[]
+ );
+
+VOID
+IpxWriteOidErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR AdapterString,
+ IN ULONG OidValue
+ );
+
+#ifdef _PNP_POWER
+ULONG
+IpxResolveAutoDetect(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings,
+ IN CTELockHandle *LockHandle1,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+VOID
+IpxResolveBindingSets(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings
+ );
+
+NTSTATUS
+IpxBindToAdapter(
+ IN PDEVICE Device,
+ IN PBINDING_CONFIG ConfigAdapter,
+ IN PADAPTER *AdapterPtr,
+ IN ULONG FrameTypeIndex
+ );
+
+NTSTATUS
+IpxUnBindFromAdapter(
+ IN PBINDING Binding
+ );
+
+VOID
+IpxPnPUpdateBindingArray(
+ IN PDEVICE Device,
+ IN PADAPTER Adapter,
+ IN PBINDING_CONFIG ConfigBinding
+ );
+
+VOID
+IpxPnPToLoad();
+
+NTSTATUS
+IpxPnPReallocateBindingArray(
+ IN PDEVICE Device,
+ IN ULONG Size
+ );
+
+#endif _PNP_POWER
+
+//
+// Routines in event.c
+//
+
+NTSTATUS
+IpxTdiSetEventHandler(
+ IN PREQUEST Request
+ );
+
+
+//
+// Routines in ind.c
+//
+
+//
+// [CH] Added these two functions
+//
+INT
+IpxReceivePacket (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet
+ );
+
+NDIS_STATUS
+IpxReceiveIndicationCommon(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize,
+ IN PMDL pMdl,
+ IN PINT pTdiClientCount
+ );
+
+NDIS_STATUS
+IpxReceiveIndication(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+VOID
+IpxReceiveComplete(
+ IN NDIS_HANDLE BindingContext
+ );
+
+NTSTATUS
+IpxUpdateBindingNetwork(
+ IN PDEVICE Device,
+ IN PBINDING Binding,
+ IN ULONG Network
+ );
+
+
+//
+// Routines in internal.c
+//
+
+NTSTATUS
+IpxInternalBind(
+ IN PDEVICE Device,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+IpxInternalUnbind(
+ IN PDEVICE Device,
+ IN UINT Identifier
+ );
+
+VOID
+IpxInternalFindRoute(
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest
+ );
+
+NTSTATUS
+IpxInternalQuery(
+ IN ULONG InternalQueryType,
+#ifdef _PNP_POWER
+ IN PNIC_HANDLE NicHandle OPTIONAL,
+#else
+ IN USHORT NicId OPTIONAL,
+#endif
+ IN OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG BufferLengthNeeded OPTIONAL
+);
+
+VOID
+IpxInternalIncrementWanInactivity(
+#ifdef _PNP_LATER
+ IN NIC_HANDLE NicHandle
+#else
+ IN USHORT NicId
+#endif
+);
+
+ULONG
+IpxInternalQueryWanInactivity(
+#ifdef _PNP_LATER
+ IN NIC_HANDLE NicHandle
+#else
+ IN USHORT NicId
+#endif
+);
+
+#ifdef _PNP_POWER
+VOID
+IpxPnPIsnIndicate(
+ IN PVOID Param
+);
+#endif
+
+//
+// Routines in ndis.c
+//
+
+NTSTATUS
+IpxRegisterProtocol(
+ IN PNDIS_STRING NameString
+ );
+
+VOID
+IpxDeregisterProtocol(
+ VOID
+ );
+
+NTSTATUS
+IpxInitializeNdis(
+ IN PADAPTER Adapter,
+ IN PBINDING_CONFIG ConfigBinding
+ );
+
+VOID
+IpxAddBroadcast(
+ IN PDEVICE Device
+ );
+
+VOID
+IpxRemoveBroadcast(
+ IN PDEVICE Device
+ );
+
+VOID
+IpxBroadcastOperation(
+ IN PVOID Parameter
+ );
+
+BOOLEAN
+IpxIsAddressLocal(
+ IN TDI_ADDRESS_IPX UNALIGNED * SourceAddress
+ );
+
+VOID
+IpxCloseNdis(
+ IN PADAPTER Adapter
+ );
+
+VOID
+IpxOpenAdapterComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN NDIS_STATUS OpenErrorStatus
+ );
+
+VOID
+IpxCloseAdapterComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus
+ );
+
+VOID
+IpxResetComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus
+ );
+
+VOID
+IpxRequestComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS NdisStatus
+ );
+
+VOID
+IpxStatus(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ );
+
+VOID
+IpxStatusComplete(
+ IN NDIS_HANDLE NdisBindingContext
+ );
+
+
+#ifdef _PNP_POWER
+VOID
+IpxBindAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE BindContext,
+ IN PNDIS_STRING DeviceName,
+ IN PVOID SystemSpecific1,
+ IN PVOID SystemSpecific2
+ );
+
+VOID
+IpxUnbindAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE UnbindContext
+ );
+
+VOID
+IpxTranslate(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ OUT PNET_PNP_ID IdList,
+ IN ULONG IdListLength,
+ OUT PULONG BytesReturned
+ );
+#endif // _PNP_POWER
+
+//
+// Routines in mac.c
+//
+
+VOID
+MacInitializeBindingInfo(
+ IN struct _BINDING * Binding,
+ IN struct _ADAPTER * Adapter
+ );
+
+VOID
+MacInitializeMacInfo(
+ IN NDIS_MEDIUM MacType,
+ OUT PNDIS_INFORMATION MacInfo
+ );
+
+VOID
+MacMapFrameType(
+ IN NDIS_MEDIUM MacType,
+ IN ULONG FrameType,
+ OUT ULONG * MappedFrameType
+ );
+
+VOID
+MacReturnMaxDataSize(
+ IN PNDIS_INFORMATION MacInfo,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN UINT DeviceMaxFrameSize,
+ OUT PUINT MaxFrameSize
+ );
+
+#ifdef _PNP_POWER
+NDIS_STATUS
+IpxSendFramePreFwd(
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+#endif
+
+NDIS_STATUS
+IpxSendFrame(
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_3802_3(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_3802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_3EthernetII(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_3Snap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_5802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_5Snap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrameFddi802_3(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrameFddi802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrameFddiSnap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrameArcnet878_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrameWanEthernetII(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+VOID
+MacUpdateSourceRouting(
+ IN ULONG Database,
+ IN PADAPTER Adapter,
+ IN PUCHAR MacHeader,
+ IN ULONG MacHeaderLength
+ );
+
+VOID
+MacLookupSourceRouting(
+ IN ULONG Database,
+ IN PBINDING Binding,
+ IN UCHAR NextRouter[6],
+ IN OUT UCHAR SourceRouting[18],
+ OUT PULONG SourceRoutingLength
+ );
+
+VOID
+MacSourceRoutingTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ );
+
+VOID
+MacSourceRoutingRemove(
+ IN PBINDING Binding,
+ IN UCHAR MacAddress[6]
+ );
+
+VOID
+MacSourceRoutingClear(
+ IN PBINDING Binding
+ );
+
+
+//
+// Routines in packet.c
+//
+
+NTSTATUS
+IpxInitializeSendPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet,
+ IN PUCHAR Header
+ );
+
+#if BACK_FILL
+NTSTATUS
+IpxInitializeBackFillPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet,
+ IN PUCHAR Header
+ );
+#endif
+
+NTSTATUS
+IpxInitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PIPX_RECEIVE_PACKET Packet
+ );
+
+NTSTATUS
+NbiInitializeReceiveBuffer(
+ IN PADAPTER Adapter,
+ IN PIPX_RECEIVE_BUFFER ReceiveBuffer,
+ IN PUCHAR DataBuffer,
+ IN ULONG DataBufferLength
+ );
+
+NTSTATUS
+IpxInitializePaddingBuffer(
+ IN PDEVICE Device,
+ IN PIPX_PADDING_BUFFER PaddingBuffer,
+ IN ULONG DataBufferLength
+ );
+
+VOID
+IpxDeinitializeSendPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet
+ );
+
+#if BACK_FILL
+VOID
+IpxDeinitializeBackFillPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet
+ );
+#endif
+
+VOID
+IpxDeinitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PIPX_RECEIVE_PACKET Packet
+ );
+
+VOID
+IpxDeinitializeReceiveBuffer(
+ IN PADAPTER Adapter,
+ IN PIPX_RECEIVE_BUFFER ReceiveBuffer,
+ IN ULONG DataBufferLength
+ );
+
+VOID
+IpxDeinitializePaddingBuffer(
+ IN PDEVICE Device,
+ IN PIPX_PADDING_BUFFER PaddingBuffer,
+ IN ULONG DataBufferLength
+ );
+
+VOID
+IpxAllocateSendPool(
+ IN PDEVICE Device
+ );
+
+#if BACK_FILL
+VOID
+IpxAllocateBackFillPool(
+ IN PDEVICE Device
+ );
+#endif
+
+VOID
+IpxAllocateReceivePool(
+ IN PDEVICE Device
+ );
+
+VOID
+IpxAllocateReceiveBufferPool(
+ IN PADAPTER Adapter
+ );
+
+PSINGLE_LIST_ENTRY
+IpxPopSendPacket(
+ IN PDEVICE Device
+ );
+
+#if BACK_FILL
+PSINGLE_LIST_ENTRY
+IpxPopBackFillPacket(
+ IN PDEVICE Device
+ );
+#endif
+
+PSINGLE_LIST_ENTRY
+IpxPopReceivePacket(
+ IN PDEVICE Device
+ );
+
+PSINGLE_LIST_ENTRY
+IpxPopReceiveBuffer(
+ IN PADAPTER Adapter
+ );
+
+PIPX_PADDING_BUFFER
+IpxAllocatePaddingBuffer(
+ IN PDEVICE Device
+ );
+
+VOID
+IpxFreePaddingBuffer(
+ IN PDEVICE Device
+ );
+
+
+
+//
+// Routines in query.c
+//
+
+NTSTATUS
+IpxTdiQueryInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+IpxTdiSetInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+//
+// Routines in receive.c
+//
+
+VOID
+IpxTransferDataComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus,
+ IN UINT BytesTransferred
+ );
+
+
+VOID
+IpxTransferData(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+NTSTATUS
+IpxTdiReceiveDatagram(
+ IN PREQUEST Request
+ );
+
+VOID
+IpxCancelReceiveDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+
+//
+// Routines in rip.c
+//
+
+NTSTATUS
+RipGetLocalTarget(
+ IN ULONG Segment,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN UCHAR Type,
+ OUT PIPX_LOCAL_TARGET LocalTarget,
+ OUT USHORT Counts[2] OPTIONAL
+ );
+
+NTSTATUS
+RipQueueRequest(
+ IN ULONG Network,
+ IN USHORT Operation
+ );
+
+VOID
+RipSendResponse(
+ IN PBINDING Binding,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PIPX_LOCAL_TARGET LocalTarget
+ );
+
+VOID
+RipShortTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ );
+
+VOID
+RipLongTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ );
+
+VOID
+RipCleanupPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_RESERVED RipReserved
+ );
+
+VOID
+RipProcessResponse(
+ IN PDEVICE Device,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN RIP_PACKET UNALIGNED * RipPacket
+ );
+
+VOID
+RipHandleRoutePending(
+ IN PDEVICE Device,
+ IN UCHAR Network[4],
+ IN CTELockHandle LockHandle,
+ IN BOOLEAN Success,
+ IN OPTIONAL PIPX_LOCAL_TARGET LocalTarget,
+ IN OPTIONAL USHORT HopCount,
+ IN OPTIONAL USHORT TickCount
+ );
+
+NTSTATUS
+RipInsertLocalNetwork(
+ IN ULONG Network,
+ IN USHORT NicId,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN USHORT Count
+ );
+
+VOID
+RipAdjustForBindingChange(
+ IN USHORT NicId,
+ IN USHORT NewNicId,
+ IN IPX_BINDING_CHANGE_TYPE ChangeType
+ );
+
+UINT
+RipGetSegment(
+ IN UCHAR Network[4]
+ );
+
+PIPX_ROUTE_ENTRY
+RipGetRoute(
+ IN UINT Segment,
+ IN UCHAR Network[4]
+ );
+
+BOOLEAN
+RipAddRoute(
+ IN UINT Segment,
+ IN PIPX_ROUTE_ENTRY RouteEntry
+ );
+
+BOOLEAN
+RipDeleteRoute(
+ IN UINT Segment,
+ IN PIPX_ROUTE_ENTRY RouteEntry
+ );
+
+PIPX_ROUTE_ENTRY
+RipGetFirstRoute(
+ IN UINT Segment
+ );
+
+PIPX_ROUTE_ENTRY
+RipGetNextRoute(
+ IN UINT Segment
+ );
+
+VOID
+RipDropRemoteEntries(
+ VOID
+ );
+
+
+//
+// Routines in send.c
+//
+
+VOID
+IpxSendComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ );
+
+NTSTATUS
+IpxTdiSendDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PREQUEST Request
+ );
+
+
+//
+// Routines in rt.c
+//
+
+
+NTSTATUS
+GetNewNics(
+ PDEVICE,
+ PREQUEST,
+ BOOLEAN,
+ PNWLINK_ACTION,
+ UINT,
+ BOOLEAN OldIrp
+);
+
+NTSTATUS
+OpenRtAddress(
+ IN PDEVICE Device,
+ IN PIRP Request
+ );
+
+NTSTATUS
+CloseRtAddress(
+ IN PDEVICE pDevice,
+ IN PIRP pIrp
+ );
+
+NTSTATUS
+CleanupRtAddress(
+ IN PDEVICE pDevice,
+ IN PIRP pIrp
+ );
+
+NTSTATUS
+SendIrpFromRt (
+ IN PDEVICE pDevice,
+ IN PIRP pIrp
+ );
+
+NTSTATUS
+RcvIrpFromRt (
+ IN PDEVICE pDevice,
+ IN PIRP pIrp
+ );
+NTSTATUS
+PassDgToRt (
+ IN PDEVICE pDevice,
+ IN PIPX_DATAGRAM_OPTIONS2 pContext,
+ IN ULONG Index,
+ IN VOID UNALIGNED *pDgrm,
+ IN ULONG uNumBytes
+ );
+
+NTSTATUS
+NTCheckSetCancelRoutine(
+ IN PIRP pIrp,
+ IN PVOID CancelRoutine,
+ IN PDEVICE pDevice
+ );
+
+
+VOID
+NTIoComplete(
+ IN PIRP pIrp,
+ IN NTSTATUS Status,
+ IN ULONG SentLength);
+
+VOID
+IpxRefRt(
+ PRT_INFO pRt);
+
+VOID
+IpxDerefRt(
+ PRT_INFO pRt);
+
+VOID
+IpxDestroyRt(
+ PRT_INFO pRt);
+
+#if DBG
+VOID
+IpxConstructHeader(
+ IN PUCHAR Header,
+ IN USHORT PacketLength,
+ IN UCHAR PacketType,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PTDI_ADDRESS_IPX LocalAddress
+ );
+#else
+#define IpxConstructHeader(_Header,_PacketLength,_PacketType,_RemoteAddress,_LocalAddress) { \
+ PIPX_HEADER _IpxHeader = (PIPX_HEADER)(_Header); \
+ _IpxHeader->CheckSum = 0xffff; \
+ _IpxHeader->PacketLength[0] = (UCHAR)((_PacketLength) / 256); \
+ _IpxHeader->PacketLength[1] = (UCHAR)((_PacketLength) % 256); \
+ _IpxHeader->TransportControl = 0; \
+ _IpxHeader->PacketType = (_PacketType); \
+ RtlCopyMemory(_IpxHeader->DestinationNetwork, (PVOID)(_RemoteAddress), 12); \
+ RtlCopyMemory(_IpxHeader->SourceNetwork, (_LocalAddress), 12); \
+}
+#endif
+
+//
+// Routines in loopback.c
+//
+
+VOID
+IpxDoLoopback(
+ IN CTEEvent *Event,
+ IN PVOID Context
+ );
+
+VOID
+IpxInitLoopback();
+
+VOID
+IpxLoopbackEnque(
+ IN PNDIS_PACKET Packet,
+ IN PVOID Context
+ );
+
+
+//
+// [FW] InternalSendCompletion from Forwarder
+//
+
+// [FW] Added length here
+VOID
+IpxInternalSendComplete(
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN NTSTATUS Status
+ );
diff --git a/private/ntos/tdi/isn/ipx/ipxtypes.h b/private/ntos/tdi/isn/ipx/ipxtypes.h
new file mode 100644
index 000000000..a353a65b4
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/ipxtypes.h
@@ -0,0 +1,2144 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ ipxtypes.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ IPX module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports - tagged [CH]
+
+ Sanjay Anand (SanjayAn) 27-Oct-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+--*/
+
+#ifdef SNMP
+#include <hipxmib.h>
+#endif SNMP
+
+//
+// Definition of the protocol reserved field of a send packet.
+//
+
+typedef struct _IPX_SEND_RESERVED {
+ UCHAR Identifier; // 0 for IPX packets
+ BOOLEAN SendInProgress; // used in an NdisSend
+ BOOLEAN OwnedByAddress; // packet is owned by an address
+ UCHAR DestinationType; // one of DEF, BCAST, MCAST
+ struct _IPX_PADDING_BUFFER * PaddingBuffer; // if one was allocated
+ PNDIS_BUFFER PreviousTail; // if padding buffer was appended
+#ifdef _PNP_POWER
+ IPX_LOCAL_TARGET LocalTarget;
+ USHORT CurrentNicId; // current binding being tried for net 0 sends
+ ULONG PacketLength; // length that comes into IpxSendFrame initially
+ BOOLEAN Net0SendSucceeded; // at least one NdisSend succeeded for net 0 sends
+#endif
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free queue
+ LIST_ENTRY GlobalLinkage; // all packets are on this
+ LIST_ENTRY WaitLinkage; // when on WaitingForRoute/WaitingRipPackets
+#ifdef IPX_TRACK_POOL
+ PVOID Pool; // send pool it was allocated from
+#endif
+ struct _ADDRESS * Address; // that owns this packet, if ones does
+
+ //
+ // The next fields are used differently depending on whether
+ // the packet is being used for a datagram send or a rip request.
+ //
+
+ union {
+ struct {
+ PREQUEST Request; // send datagram request
+ struct _ADDRESS_FILE * AddressFile; // that this send is on
+ USHORT CurrentNicId; // current binding being tried for net 0 sends
+ BOOLEAN Net0SendSucceeded; // at least one NdisSend succeeded for net 0 sends
+ BOOLEAN OutgoingSap; // packet is sent from the SAP socket
+ } SR_DG;
+ struct {
+ ULONG Network; // net we are looking for
+ USHORT CurrentNicId; // current binding being tried
+ UCHAR RetryCount; // number of times sent; 0xfe = response, 0xff = down
+ BOOLEAN RouteFound; // network has been found
+ USHORT SendTime; // timer expirations when sent.
+ BOOLEAN NoIdAdvance; // don't advance CurrentNicId this time.
+ } SR_RIP;
+ } u;
+
+ PUCHAR Header; // points to the MAC/IPX header
+ PNDIS_BUFFER HeaderBuffer; // the NDIS_BUFFER describing Header;
+#if BACK_FILL
+ BOOLEAN BackFill; // 1 if we are using SMB's extended header
+ PNDIS_BUFFER IpxHeader; // Place holder for our IpxHeader
+ PNDIS_BUFFER MacHeader; // Place holder for our mac header
+ PVOID MappedSystemVa;
+ PVOID ByteOffset;
+ LONG UserLength;
+#endif
+} IPX_SEND_RESERVED, *PIPX_SEND_RESERVED;
+
+//
+// Values for the DestinationType field.
+//
+
+#define DESTINATION_DEF 1
+#define DESTINATION_BCAST 2
+#define DESTINATION_MCAST 3
+
+//
+// Used to indicate to IpxReceiveIndication that this is a loopback packet
+// Assumption: Ndis cannot return this as the NdisBindingHandle value since
+// that is a pointer (our pointers shd in kernel space, if not in Nonpaged pool).
+//
+#define IPX_LOOPBACK_COOKIE 0x00460007
+
+//
+// MIN/MAX macros
+//
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+#ifdef _PNP_POWER
+
+//
+// In order to avoid a lock to read a value, this is used.
+// As long as the final value has made it to _b by the time
+// the check is made, this works fine.
+//
+
+#define ASSIGN_LOOP(_a, _b) \
+ do { \
+ _a = _b; \
+ } while ( _a != _b );
+
+//
+// Gets the value of a Ulong (possibly a pointer) by adding 0 in an interlocked manner.
+// This relies on the fact that the return of the ExchangeAdd will be the value prior to
+// addition. Since the value added is 0, the final value stays the same.
+//
+#define GET_VALUE(x) \
+ InterlockedExchangeAdd((PULONG)&(x), 0)
+
+#define SET_VALUE(x,y) \
+ InterlockedExchange((PLONG)&(x), (LONG)(y))
+
+/*
+PBINDING
+NIC_ID_TO_BINDING (
+ IN PDEVICE _device,
+ IN USHORT _nicid
+ );
+*/
+//
+// We need to ensure that the binding array pointer is valid hence use the interlocked operation.
+// Also, the binding pointer read out of the array should be valid. Since the bindings are never
+// freed (IPX maintains a pool of bindings), the pointer thus retrieved will always point to
+// memory that belongs to us, which in the worst case could point to a re-claimed binding block.
+//
+// BUGBUGZZ: we can eliminate the second interlock if we always ensure that the bindings in an array
+// dont change i.e. when we move around bindings, do them in a copy and make that the master (thru'
+// a single ulong exchange).
+//
+// A problem that still remains here is that even if we get a valid (IPX owned non-paged) ptr out of
+// the array, we still cannot atomically get a ref on the binding
+// We might need those locks after all.... (revisit post SUR when the delete is enabled).
+//
+
+//
+// NicId cast to SHORT so DemandDial Nic (0xffff) maps to -1.
+//
+#define NIC_ID_TO_BINDING(_device, _nicid) \
+ ((PBINDING)GET_VALUE( ((PBIND_ARRAY_ELEM) GET_VALUE( (_device)->Bindings) )[(SHORT)_nicid].Binding ))
+
+/*
+PBINDING
+NIC_ID_TO_BINDING_NO_ILOCK (
+ IN PDEVICE _device,
+ IN USHORT _nicid
+ );
+*/
+//
+// No interlocked operations are used here to get to the binding. This is used in the PnP add/delete
+// adapter paths on the assumption that NDIS will serialize the addition/deletion of cards. [JammelH: 5/15/96]
+//
+#define NIC_ID_TO_BINDING_NO_ILOCK(_device, _nicid) \
+ ((_device)->Bindings[_nicid].Binding)
+
+/*
+VOID
+INSERT_BINDING(
+ IN PDEVICE _device,
+ IN USHORT _nicid,
+ IN PBINDING _binding
+ )
+*/
+//
+// We dont do a get_value for the first arg of the macro since we are the writer and
+// this value cannot change from under us here (NDIS will not give us two PnP Add adapter
+// indications simultaneously).
+//
+#define INSERT_BINDING(_device, _nicid, _binding) \
+ SET_VALUE((_device)->Bindings[_nicid].Binding, (_binding));
+
+/*
+VOID
+SET_VERSION(
+ IN PDEVICE _device,
+ IN USHORT _nicid
+ )
+*/
+#define SET_VERSION(_device, _nicid) \
+ SET_VALUE((_device)->Bindings[_nicid].Version, ++(_device)->BindingVersionNumber);
+
+/*
+PBINDING
+NIC_HANDLE_TO_BINDING (
+ IN PDEVICE _device,
+ IN PNIC_HANDLE _nichandle,
+ );
+*/
+#ifdef _PNP_LATER
+#define NIC_HANDLE_TO_BINDING(_device, _nichandle) \
+ (((_nichandle)->Signature == IPX_BINDING_SIGNATURE) && \
+ ((_nichandle)->Version == (_device)->Bindings[(_nichandle)->NicId].Version)) ? \
+ (_device)->Bindings[(_nichandle)->NicId].Binding : NULL;
+#else
+
+#define NIC_HANDLE_TO_BINDING(_device, _nichandle) \
+ NIC_ID_TO_BINDING(_device, (_nichandle)->NicId);
+#endif
+
+/*
+VOID
+FILL_LOCAL_TARGET(
+ IN PLOCAL_TARGET _localtarget,
+ IN USHORT _nicid
+ )
+*/
+
+#define FILL_LOCAL_TARGET(_localtarget, _nicid) \
+ NIC_HANDLE_FROM_NIC((_localtarget)->NicHandle, _nicid)
+
+#define NIC_FROM_LOCAL_TARGET(_localtarget) \
+ (_localtarget)->NicHandle.NicId
+
+#endif _PNP_POWER
+
+//
+// Definition of the protocol reserved field of a receive packet.
+//
+
+typedef struct _IPX_RECEIVE_RESERVED {
+ UCHAR Identifier; // 0 for IPX packets
+ BOOLEAN TransferInProgress; // used in an NdisTransferData
+ BOOLEAN OwnedByAddress; // packet is owned by an address
+#ifdef IPX_TRACK_POOL
+ PVOID Pool; // send pool it was allocated from
+#endif
+ struct _ADDRESS * Address; // that owns this packet, if ones does
+ PREQUEST SingleRequest; // if transfer is for one only
+ struct _IPX_RECEIVE_BUFFER * ReceiveBuffer; // if transfer is for multiple requests
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free queue
+ LIST_ENTRY GlobalLinkage; // all packets are on this
+ LIST_ENTRY Requests; // waiting on this transfer
+ PVOID pContext;
+ ULONG Index;
+} IPX_RECEIVE_RESERVED, *PIPX_RECEIVE_RESERVED;
+
+//
+// The amount of data we need in our standard header, rounded up
+// to the next longword bounday.
+//
+// [BUGBUGZZ] Make this declaration in one place
+//
+#define PACKET_HEADER_SIZE (MAC_HEADER_SIZE + IPX_HEADER_SIZE + RIP_PACKET_SIZE)
+
+//
+// Types to abstract NDIS packets. This is to allow us to
+// switch from using our own memory for packets to using
+// authentically allocated NDIS packets.
+//
+
+// #define IPX_OWN_PACKETS 1
+
+#define IpxAllocateSendPacket(_Device,_SendPacket,_Status) { \
+ NdisReinitializePacket((PNDIS_PACKET)(PACKET(_SendPacket))); \
+ *(_Status) = STATUS_SUCCESS; \
+}
+
+#define IpxAllocateReceivePacket(_Device,_ReceivePacket,_Status) { \
+ NdisReinitializePacket((PNDIS_PACKET)(PACKET(_ReceivePacket))); \
+ *(_Status) = STATUS_SUCCESS; \
+}
+
+#ifdef IPX_OWN_PACKETS
+
+#define NDIS_PACKET_SIZE 48
+// #define NDIS_PACKET_SIZE FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])
+
+typedef struct _IPX_SEND_PACKET {
+ UCHAR Data[NDIS_PACKET_SIZE+sizeof(IPX_SEND_RESERVED)];
+} IPX_SEND_PACKET, *PIPX_SEND_PACKET;
+
+typedef struct _IPX_RECEIVE_PACKET {
+ UCHAR Data[NDIS_PACKET_SIZE+sizeof(IPX_RECEIVE_RESERVED)];
+} IPX_RECEIVE_PACKET, *PIPX_RECEIVE_PACKET;
+
+#define PACKET(_Packet) ((PNDIS_PACKET)((_Packet)->Data))
+
+#define IpxFreeSendPacket(_Device,_Packet)
+
+#define IpxFreeReceivePacket(_Device,_Packet)
+
+#else // IPX_OWN_PACKETS
+
+typedef struct _IPX_SEND_PACKET {
+ PNDIS_PACKET Packet;
+ NDIS_HANDLE PoolHandle;
+} IPX_SEND_PACKET, *PIPX_SEND_PACKET;
+
+typedef struct _IPX_RECEIVE_PACKET {
+ PNDIS_PACKET Packet;
+ NDIS_HANDLE PoolHandle;
+} IPX_RECEIVE_PACKET, *PIPX_RECEIVE_PACKET;
+
+#define PACKET(_Packet) ((_Packet)->Packet)
+
+#define IpxAllocateSingleSendPacket(_Device,_SendPacket,_Status) { \
+ NdisAllocatePacketPool(_Status, &(_SendPacket)->PoolHandle,1,sizeof(IPX_SEND_RESERVED)); \
+ if (*(_Status) == NDIS_STATUS_SUCCESS) { \
+ NdisAllocatePacket(_Status, &(_SendPacket)->Packet, (_SendPacket)->PoolHandle); \
+ if (*(_Status) == NDIS_STATUS_SUCCESS) { \
+ (_Device)->MemoryUsage += \
+ (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0])+ \
+ FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])+ \
+ sizeof(IPX_SEND_RESERVED)); \
+ } else {\
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis packet memory\n"));\
+ }\
+ } else {\
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis pool memory\n"));\
+ }\
+}
+
+#define IpxAllocateSingleReceivePacket(_Device,_ReceivePacket,_Status) { \
+ NdisAllocatePacketPool(_Status, &(_ReceivePacket)->PoolHandle,1,sizeof(IPX_RECEIVE_RESERVED)); \
+ if (*(_Status) == NDIS_STATUS_SUCCESS) { \
+ NdisAllocatePacket(_Status, &(_ReceivePacket)->Packet, (_ReceivePacket)->PoolHandle); \
+ if (*(_Status) == NDIS_STATUS_SUCCESS) { \
+ (_Device)->MemoryUsage += \
+ (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0])+ \
+ FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])+ \
+ sizeof(IPX_RECEIVE_RESERVED)); \
+ } else {\
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis packet memory\n"));\
+ }\
+ } else {\
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis pool memory\n"));\
+ }\
+}
+
+#define IpxFreeSingleSendPacket(_Device,_Packet) { \
+ NdisFreePacket((_Packet).Packet); \
+ NdisFreePacketPool((_Packet).PoolHandle); \
+ (_Device)->MemoryUsage -= \
+ (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0])+ \
+ FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])+ \
+ sizeof(IPX_SEND_RESERVED)); \
+}
+#define IpxFreeSingleReceivePacket(_Device,_Packet) { \
+ NdisFreePacket((_Packet).Packet); \
+ NdisFreePacketPool((_Packet).PoolHandle); \
+ (_Device)->MemoryUsage -= \
+ (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0])+ \
+ FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])+ \
+ sizeof(IPX_RECEIVE_RESERVED)); \
+}
+
+#define IpxFreeSendPacket(_Device,_Packet) NdisFreePacket(PACKET(_Packet))
+
+#define IpxFreeReceivePacket(_Device,_Packet) NdisFreePacket(PACKET(_Packet))
+
+#endif // IPX_OWN_PACKETS
+
+#define SEND_RESERVED(_Packet) ((PIPX_SEND_RESERVED)((PACKET(_Packet))->ProtocolReserved))
+#define RECEIVE_RESERVED(_Packet) ((PIPX_RECEIVE_RESERVED)((PACKET(_Packet))->ProtocolReserved))
+
+
+//
+// This is the structure that contains a receive buffer for
+// datagrams that are going to multiple recipients.
+//
+
+typedef struct _IPX_RECEIVE_BUFFER {
+ LIST_ENTRY GlobalLinkage; // all buffers are on this
+#ifdef IPX_TRACK_POOL
+ PVOID Pool; // receive buffer pool was allocated from
+#endif
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free list
+ PNDIS_BUFFER NdisBuffer; // length of the NDIS buffer
+ ULONG DataLength; // length of the data
+ PUCHAR Data; // the actual data
+} IPX_RECEIVE_BUFFER, *PIPX_RECEIVE_BUFFER;
+
+
+//
+// This is the structure that contains a padding buffer for
+// padding ethernet frames out to an even number of bytes.
+//
+
+typedef struct _IPX_PADDING_BUFFER {
+ LIST_ENTRY GlobalLinkage; // all buffers are on this
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free list
+ PNDIS_BUFFER NdisBuffer; // length of the NDIS buffer
+ ULONG DataLength; // length of the data
+ UCHAR Data[1]; // the actual pad data
+} IPX_PADDING_BUFFER, *PIPX_PADDING_BUFFER;
+
+#ifdef IPX_OWN_PACKETS
+
+typedef struct _IPX_SEND_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ IPX_SEND_PACKET Packets[1];
+} IPX_SEND_POOL, *PIPX_SEND_POOL;
+
+typedef struct _IPX_RECEIVE_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ IPX_RECEIVE_PACKET Packets[1];
+} IPX_RECEIVE_POOL, *PIPX_RECEIVE_POOL;
+#else
+
+typedef struct _IPX_PACKET_POOL {
+ LIST_ENTRY Linkage;
+ PUCHAR Header;
+ NDIS_HANDLE PoolHandle;
+} IPX_PACKET_POOL, *PIPX_PACKET_POOL;
+
+typedef IPX_PACKET_POOL IPX_RECEIVE_POOL, *PIPX_RECEIVE_POOL;
+typedef IPX_PACKET_POOL IPX_SEND_POOL, *PIPX_SEND_POOL;
+
+#endif // IPX_OWN_PACKETS
+
+typedef struct _IPX_RECEIVE_BUFFER_POOL {
+ LIST_ENTRY Linkage;
+ UINT BufferCount;
+ UINT BufferFree;
+ IPX_RECEIVE_BUFFER Buffers[1];
+ // after the packets the data buffers are allocated also.
+} IPX_RECEIVE_BUFFER_POOL, *PIPX_RECEIVE_BUFFER_POOL;
+
+//
+// Number of upper drivers we support.
+//
+
+#define UPPER_DRIVER_COUNT 3
+
+
+
+//
+// Tags for memory allocation.
+//
+
+#define MEMORY_CONFIG 0
+#define MEMORY_ADAPTER 1
+#define MEMORY_ADDRESS 2
+#define MEMORY_PACKET 3
+#define MEMORY_RIP 4
+#define MEMORY_SOURCE_ROUTE 5
+#define MEMORY_BINDING 6
+#define MEMORY_QUERY 7
+
+#define MEMORY_MAX 8
+
+#if DBG
+
+//
+// Holds the allocations for a specific memory type.
+//
+
+typedef struct _MEMORY_TAG {
+ ULONG Tag;
+ ULONG BytesAllocated;
+} MEMORY_TAG, *PMEMORY_TAG;
+
+EXTERNAL_LOCK(IpxMemoryInterlock);
+extern MEMORY_TAG IpxMemoryTag[MEMORY_MAX];
+
+#endif
+
+
+//
+// This defines the reasons we delete rip entries for a binding.
+//
+
+typedef enum _IPX_BINDING_CHANGE_TYPE {
+ IpxBindingDeleted,
+ IpxBindingMoved,
+ IpxBindingDown
+} IPX_BINDING_CHANGE_TYPE, *PIPX_BINDING_CHANGE_TYPE;
+
+
+//
+// This structure contains information about a single
+// source routing entry.
+//
+
+typedef struct _SOURCE_ROUTE {
+
+ struct _SOURCE_ROUTE * Next; // next in hash list
+
+ UCHAR MacAddress[6]; // remote MAC address
+ UCHAR TimeSinceUsed; // timer expirations since last used
+ UCHAR SourceRoutingLength; // length of the data
+
+ UCHAR SourceRouting[1]; // source routing data, stored as received in
+
+} SOURCE_ROUTE, *PSOURCE_ROUTE;
+
+#define SOURCE_ROUTE_SIZE(_SourceRoutingLength) \
+ (FIELD_OFFSET(SOURCE_ROUTE, SourceRouting[0]) + (_SourceRoutingLength))
+
+#define SOURCE_ROUTE_HASH_SIZE 16
+
+//
+// ULONG
+// MacSourceRoutingHash(
+// IN PUCHAR MacAddress
+// )
+//
+// /*++
+//
+// Routine Description:
+//
+// This routine returns a hash value based on the MAC address
+// that is pointed to. It will be between 0 and SOURCE_ROUTE_HASH_SIZE.
+//
+// Arguments:
+//
+// MacAddress - The MAC address. NOTE: The source-routing bit may
+// or may not be on in the first byte, this routine will handle
+// that.
+//
+// Return Value:
+//
+// The hash value.
+//
+// --*/
+//
+
+#define MacSourceRoutingHash(_MacAddress) \
+ ((ULONG)((_MacAddress)[5] % SOURCE_ROUTE_HASH_SIZE))
+
+
+
+//
+// this structure describes a single NDIS adapter that IPX is
+// bound to.
+//
+
+struct _DEVICE;
+
+typedef struct _ADAPTER {
+
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+#if DBG
+ UCHAR Signature1[4]; // contains "IAD1"
+#endif
+
+#ifdef _PNP_POWER
+ ULONG ReferenceCount;
+#endif
+
+ ULONG BindingCount; // number bound to this adapter
+
+ //
+ // Handle returned by the NDIS wrapper after we bind to it.
+ //
+
+ NDIS_HANDLE NdisBindingHandle;
+
+ //
+ // The queue of (currently receive only) requests waiting to complete.
+ //
+
+ LIST_ENTRY RequestCompletionQueue;
+
+ //
+ // IPX header normal offsets for directed and
+ // broadcast/multicast frames.
+ //
+
+ ULONG DefHeaderSizes[ISN_FRAME_TYPE_MAX];
+ ULONG BcMcHeaderSizes[ISN_FRAME_TYPE_MAX];
+
+ //
+ // List of buffers to be used for transfers.
+ //
+
+ ULONG AllocatedReceiveBuffers;
+ LIST_ENTRY ReceiveBufferPoolList;
+ SLIST_HEADER ReceiveBufferList;
+
+ //
+ // List of ethernet padding buffers.
+ //
+
+ ULONG AllocatedPaddingBuffers;
+ SINGLE_LIST_ENTRY PaddingBufferList;
+
+ struct _BINDING * Bindings[ISN_FRAME_TYPE_MAX]; // the binding for each frame type.
+
+ //
+ // TRUE if broadcast reception is enabled on this adapter.
+ //
+
+ BOOLEAN BroadcastEnabled;
+
+ //
+ // TRUE if we have enabled an auto-detected frame type
+ // on this adapter -- used to prevent multiple ones.
+ //
+
+ BOOLEAN AutoDetectFound;
+
+ //
+ // TRUE if we got a response to at least one of our
+ // auto-detect frames.
+ //
+
+ BOOLEAN AutoDetectResponse;
+
+ //
+ // This is TRUE if we are auto-detecting and we have
+ // found the default auto-detect type on the net.
+ //
+
+ BOOLEAN DefaultAutoDetected;
+
+ //
+ // For WAN adapters, we support multiple bindings per
+ // adapter, all with the same frame type. For them we
+ // demultiplex using the local mac address. This stores
+ // the range of device NIC IDs associated with this
+ // particular address.
+ //
+
+ USHORT FirstWanNicId;
+ USHORT LastWanNicId;
+ ULONG WanNicIdCount;
+
+ //
+ // This is based on the configuration.
+ //
+
+ USHORT BindSap; // usually 0x8137
+ USHORT BindSapNetworkOrder; // usually 0x3781
+ BOOLEAN SourceRouting;
+ BOOLEAN EnableFunctionalAddress;
+ BOOLEAN EnableWanRouter;
+ ULONG ConfigMaxPacketSize;
+
+ //
+ // TRUE if the tree is empty, so we can check quickly.
+ //
+
+ BOOLEAN SourceRoutingEmpty[IDENTIFIER_TOTAL];
+
+ //
+ // These are kept around for error logging, and stored right
+ // after this structure.
+ //
+
+ PWCHAR AdapterName;
+ ULONG AdapterNameLength;
+
+ struct _DEVICE * Device;
+
+ CTELock Lock;
+ CTELock * DeviceLock;
+
+ //
+ // some MAC addresses we use in the transport
+ //
+
+ HARDWARE_ADDRESS LocalMacAddress; // our local hardware address.
+
+ //
+ // The value of Device->SourceRoutingTime the last time
+ // we checked the list for timeouts (this is so we can
+ // tell in the timeout code when two bindings point to the
+ // same adapter).
+ //
+
+ CHAR LastSourceRoutingTime;
+
+ //
+ // These are used while initializing the MAC driver.
+ //
+
+ KEVENT NdisRequestEvent; // used for pended requests.
+ NDIS_STATUS NdisRequestStatus; // records request status.
+ NDIS_STATUS OpenErrorStatus; // if Status is NDIS_STATUS_OPEN_FAILED.
+
+ //
+ // This is the Mac type we must build the packet header for and know the
+ // offsets for.
+ //
+
+ NDIS_INFORMATION MacInfo;
+
+ ULONG MaxReceivePacketSize; // does not include the MAC header
+ ULONG MaxSendPacketSize; // includes the MAC header
+ ULONG ReceiveBufferSpace; // as queried from the card
+
+ //
+ // This information is used to keep track of the speed of
+ // the underlying medium.
+ //
+
+ ULONG MediumSpeed; // in units of 100 bytes/sec
+
+ //
+ // The source routing tree for each of the identifiers
+ //
+
+ PSOURCE_ROUTE SourceRoutingHeads[IDENTIFIER_TOTAL][SOURCE_ROUTE_HASH_SIZE];
+
+} ADAPTER, * PADAPTER;
+
+#define ASSERT_ADAPTER(_Adapter) \
+ CTEAssert (((_Adapter)->Type == IPX_ADAPTER_SIGNATURE) && ((_Adapter)->Size == sizeof(ADAPTER)))
+
+
+//
+// These are the media and frame type specific MAC header
+// constructors that we call in the main TDI send path.
+//
+
+typedef NDIS_STATUS
+(*IPX_SEND_FRAME_HANDLER) (
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+//
+// These are the states a WAN line can be in.
+//
+typedef enum _WAN_LINE_STATE{
+ LINE_DOWN,
+ LINE_UP,
+ LINE_CONFIG
+} WAN_LINE_STATE, *PWAN_LINE_STATE;
+
+#define BREF_BOUND 1
+#ifdef _PNP_POWER
+#define BREF_DEVICE_ACCESS 2
+#define BREF_ADAPTER_ACCESS 3
+#endif
+
+//
+// [FW] New flag to indicate the KFWD opened an adapter
+//
+#define BREF_FWDOPEN 4
+
+#define BREF_TOTAL 5
+
+typedef struct _BINDING {
+
+#if DBG
+ ULONG RefTypes[BREF_TOTAL];
+#endif
+
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+#if DBG
+ UCHAR Signature1[4]; // contains "IBI1"
+#endif
+
+ ULONG ReferenceCount;
+
+#ifdef _PNP_POWER
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free queue
+#endif
+
+ //
+ // Adapter this binding is on.
+ //
+
+ PADAPTER Adapter;
+
+ //
+ // ID identifying us to the system (will be the index
+ // in Device->Bindings[]).
+ //
+
+ USHORT NicId;
+
+ //
+ // For LANs these will be the same as the adapter's, for WANs
+ // they change on line up indications.
+ //
+
+ ULONG MaxSendPacketSize;
+ ULONG MediumSpeed; // in units of 100 bytes/sec
+ HARDWARE_ADDRESS LocalMacAddress; // our local hardware address.
+
+ //
+ // This is used for WAN lines, all sends go to this address
+ // which is given on line up.
+ //
+
+ HARDWARE_ADDRESS RemoteMacAddress;
+
+ //
+ // For WAN lines, holds the remote address indicated to us
+ // in the IPXCP_CONFIGURATION structure -- this is used to
+ // select a binding to send to when WanGlobalNetworkNumber
+ // is TRUE.
+ //
+
+ UCHAR WanRemoteNode[6];
+
+ //
+ // TRUE if this binding was set up to allow auto-detection,
+ // instead of being configured explicitly in the registry.
+ //
+
+ BOOLEAN AutoDetect;
+
+ //
+ // TRUE if this binding was set up for auto-detection AND
+ // was the default in the registry.
+ //
+
+ BOOLEAN DefaultAutoDetect;
+
+ //
+ // During auto-detect when we are processing responses from
+ // various networks, these keep track of how many responses
+ // we have received that match the current guess at the
+ // network number, and how many don't (the current guess
+ // is stored in TentativeNetworkAddress).
+ //
+
+ USHORT MatchingResponses;
+ USHORT NonMatchingResponses;
+
+ //
+ // During auto-detect, stores the current guess at the
+ // network number.
+ //
+
+ ULONG TentativeNetworkAddress;
+
+ //
+ // TRUE if this binding is part of a binding set.
+ //
+
+ BOOLEAN BindingSetMember;
+
+ //
+ // TRUE if this binding should receive broadcasts (this
+ // rotates through the members of a binding set).
+ //
+
+ BOOLEAN ReceiveBroadcast;
+
+ //
+ // TRUE for WAN lines if we are up.
+ //
+ // BOOLEAN LineUp;
+ WAN_LINE_STATE LineUp;
+
+ //
+ // TRUE if this is a WAN line and is dialout.
+ //
+
+ BOOLEAN DialOutAsync;
+
+ union {
+
+ //
+ // Used when a binding is active, if it is a member
+ // of a binding set.
+ //
+
+ struct {
+
+ //
+ // Used to link members of a binding set in a circular list.
+ // NULL for non-set members.
+ //
+
+ struct _BINDING * NextBinding;
+
+ //
+ // If this binding is a master of a binding set, this points
+ // to the binding to use for the next send. For other members
+ // of a binding set it is NULL. We use this to determine
+ // if a binding is a master or not.
+ //
+
+ struct _BINDING * CurrentSendBinding;
+
+ //
+ // For binding set members, points to the master binding
+ // (if this is the master it points to itself).
+ //
+
+ struct _BINDING * MasterBinding;
+
+ };
+
+ //
+ // This is used when we are first binding to adapters,
+ // and the device's Bindings array is not yet allocated.
+ //
+
+ LIST_ENTRY InitialLinkage;
+
+ };
+
+ //
+ // Used by rip to keep track of unused wan lines.
+ //
+
+ ULONG WanInactivityCounter;
+
+ //
+ // Our local address, we don't use the socket but we keep
+ // it here so we can do quick copies. It contains the
+ // real network that we are bound to and our node
+ // address on that net (typically the adapter's MAC
+ // address but it will change for WANs).
+ //
+
+ TDI_ADDRESS_IPX LocalAddress;
+
+ IPX_SEND_FRAME_HANDLER SendFrameHandler;
+
+ struct _DEVICE * Device;
+
+ CTELock * DeviceLock;
+
+ ULONG DefHeaderSize; // IPX header offset for directed frames
+ ULONG BcMcHeaderSize; // IPX header offset for broadcast/multicast
+
+ ULONG AnnouncedMaxDatagramSize; // what we advertise -- assumes worst-case SR
+ ULONG RealMaxDatagramSize; // what will really break the card
+ ULONG MaxLookaheadData;
+
+ //
+ // Configuration parameters. We overlay all of them except
+ // FrameType over the worker thread item we use to delay
+ // deletion -- all the others are not needed once the
+ // binding is up. Some of the config parameters are stored
+ // in the adapter, these are the ones that are modified
+ // per-binding.
+ //
+
+ ULONG FrameType;
+ union {
+ struct {
+ ULONG ConfiguredNetworkNumber;
+ BOOLEAN AllRouteDirected;
+ BOOLEAN AllRouteBroadcast;
+ BOOLEAN AllRouteMulticast;
+ };
+ WORK_QUEUE_ITEM WanDelayedQueueItem;
+ };
+
+ ULONG FwdAdapterContext; // [FW]
+
+ ULONG InterfaceIndex; // [FW]
+
+ ULONG ConnectionId; // [FW] used to match TimeSinceLastActivity IOCtls
+
+ ULONG IpxwanConfigRequired; // [FW] used to indicate to the adapter dll whether the line up is for Router or IpxWan.
+
+ BOOLEAN fInfoIndicated; //Info indicated to user app
+
+#ifdef _PNP_POWER
+ //
+ // Indicates whether this binding was indicated to the ISN driver
+ //
+ BOOLEAN IsnInformed[UPPER_DRIVER_COUNT];
+
+ //
+ // Keeps the NetAddressRegistrationHandle.
+ //
+ HANDLE TdiRegistrationHandle;
+#endif
+} BINDING, * PBINDING;
+
+
+#ifdef _PNP_POWER
+typedef struct _IPX_BINDING_POOL {
+ LIST_ENTRY Linkage;
+ UINT BindingCount;
+ BINDING Bindings[1];
+} IPX_BINDING_POOL, *PIPX_BINDING_POOL;
+#endif
+
+//
+// This structure defines the control structure for a single
+// router table segment.
+//
+
+typedef struct _ROUTER_SEGMENT {
+ LIST_ENTRY WaitingForRoute; // packets waiting for a route in this segment
+ LIST_ENTRY FindWaitingForRoute; // find route requests waiting for a route in this segment
+ LIST_ENTRY WaitingLocalTarget; // QUERY_IPX_LOCAL_TARGETs waiting for a route in this segment
+ LIST_ENTRY WaitingReripNetnum; // MIPX_RERIPNETNUMs waiting for a route in this segment
+ LIST_ENTRY Entries;
+ PLIST_ENTRY EnumerateLocation;
+} ROUTER_SEGMENT, *PROUTER_SEGMENT;
+
+
+//
+// Number of buckets in the address hash table. This is
+// a multiple of 2 so hashing is quick.
+//
+
+#define IPX_ADDRESS_HASH_COUNT 16
+
+//
+// Routine to convert a socket to a hash index. We use the
+// high bits because it is stored reversed.
+//
+
+#define IPX_HASH_SOCKET(_S) ((((_S) & 0xff00) >> 8) % IPX_ADDRESS_HASH_COUNT)
+
+//
+// This macro gets the socket hash right out of the IPX header.
+//
+
+#define IPX_DEST_SOCKET_HASH(_IpxHeader) (((PUCHAR)&(_IpxHeader)->DestinationSocket)[1] % IPX_ADDRESS_HASH_COUNT)
+
+
+//
+// This structure defines the per-device structure for IPX
+// (one of these is allocated globally).
+//
+
+#define DREF_CREATE 0
+#define DREF_LOADED 1
+#define DREF_ADAPTER 2
+#define DREF_ADDRESS 3
+#define DREF_SR_TIMER 4
+#define DREF_RIP_TIMER 5
+#define DREF_LONG_TIMER 6
+#define DREF_RIP_PACKET 7
+#define DREF_ADDRESS_NOTIFY 8
+#define DREF_LINE_CHANGE 9
+#define DREF_NIC_NOTIFY 10
+
+#define DREF_TOTAL 12
+
+#ifdef _PNP_POWER
+//
+// Pre-allocated binding array size
+//
+#define MAX_BINDINGS 50
+#endif _PNP_POWER
+
+#ifdef _PNP_POWER
+//
+// Our new binding array is composed of the following binding
+// array element
+//
+typedef struct _BIND_ARRAY_ELEM {
+ PBINDING Binding;
+ ULONG Version;
+} BIND_ARRAY_ELEM, *PBIND_ARRAY_ELEM;
+
+#endif _PNP_POWER
+
+typedef struct _DEVICE {
+
+#if DBG
+ ULONG RefTypes[DREF_TOTAL];
+#endif
+
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+#if DBG
+ UCHAR Signature1[4]; // contains "IDC1"
+#endif
+
+ CTELock Interlock; // GLOBAL lock for reference count.
+ // (used in ExInterlockedXxx calls)
+
+ //
+ // These are temporary versions of these counters, during
+ // timer expiration we update the real ones.
+ //
+
+ ULONG TempDatagramBytesSent;
+ ULONG TempDatagramsSent;
+ ULONG TempDatagramBytesReceived;
+ ULONG TempDatagramsReceived;
+
+ //
+ // Configuration parameters.
+ //
+
+ BOOLEAN EthernetPadToEven;
+ BOOLEAN SingleNetworkActive;
+ BOOLEAN DisableDialoutSap;
+
+ //
+ // TRUE if we have multiple cards but a virtual network of 0.
+ //
+
+ BOOLEAN MultiCardZeroVirtual;
+
+ CTELock Lock;
+
+ //
+ // Lock to access the sequenced lists in the device.
+ //
+ CTELock SListsLock;
+
+ LONG ReferenceCount; // activity count/this provider.
+
+#ifdef _PNP_POWER
+
+ //
+ // Lock used to control the access to a binding (either from the
+ // binding array in the device or from the binding array in the
+ // adapter.
+ //
+ CTELock BindAccessLock;
+
+ //
+ // Registry Path for use when PnP adapters appear.
+ //
+ PWSTR RegistryPathBuffer;
+
+ UNICODE_STRING RegistryPath;
+
+ //
+ // Binding array has the Version number too
+ //
+ PBIND_ARRAY_ELEM Bindings; // allocated when number is determined.
+ ULONG BindingCount; // total allocated in Bindings.
+
+ //
+ // Monotonically increasing version number kept in bindings.
+ // Hopefully this will not wrap around...
+ //
+ ULONG BindingVersionNumber;
+#else
+ //
+ // During init we hold all bindings in a queue, but after we
+ // know the approximate number we allocate an array.
+ //
+
+ union {
+ LIST_ENTRY InitialBindingList; // only used during init.
+ struct {
+ PBINDING * Bindings; // allocated when number is determined.
+ ULONG BindingCount; // total allocated in Bindings.
+ };
+ };
+#endif _PNP_POWER
+
+
+ //
+ // ValidBindings is the number of bindings in the array which may
+ // be valid (they are lan bindings or down wan binding placeholders).
+ // It will be less than BindingCount by the number of auto-detect
+ // bindings that are thrown away. HighestExternalNicId is ValidBindings
+ // minus any binding set slaves which are moved to the end of the
+ // array. SapNicCount is like HighestExternalNicId except that
+ // if WanGlobalNetworkNumber is TRUE it will count all WAN bindings
+ // as one. HighestExternalType20NicId is like HighestExternalNicId
+ // except it stops when all the remaining bindings are down wan
+ // lines, or dialin wan lines if DisableDialinNetbios bit 1 is on.
+ //
+
+ USHORT ValidBindings;
+ USHORT HighestExternalNicId;
+ USHORT SapNicCount;
+ USHORT HighestType20NicId;
+#ifdef _PNP_POWER
+ //
+ // Keeps track of the last LAN binding's position in the binding array
+ //
+ USHORT HighestLanNicId;
+
+ //
+ // This keeps track of the current size of the binding array
+ //
+ USHORT MaxBindings;
+#endif _PNP_POWER
+
+ //
+ // [FW] To keep track of the number of WAN lines currently UP
+ //
+ USHORT UpWanLineCount;
+
+ LIST_ENTRY GlobalSendPacketList;
+ LIST_ENTRY GlobalReceivePacketList;
+ LIST_ENTRY GlobalReceiveBufferList;
+
+#if BACK_FILL
+ LIST_ENTRY GlobalBackFillPacketList;
+#endif
+
+ //
+ // Action requests from SAP waiting for an adapter status to change.
+ //
+
+ LIST_ENTRY AddressNotifyQueue;
+
+ //
+ // Action requests from nwrdr waiting for the WAN line
+ // to go up/down.
+ //
+
+ LIST_ENTRY LineChangeQueue;
+
+ //
+ // Action requests from forwarder waiting for the NIC change notification
+ //
+ LIST_ENTRY NicNtfQueue;
+ LIST_ENTRY NicNtfComplQueue;
+
+ //
+ // All packet pools are chained on these lists.
+ //
+
+ LIST_ENTRY SendPoolList;
+ LIST_ENTRY ReceivePoolList;
+
+
+#if BACK_FILL
+ LIST_ENTRY BackFillPoolList;
+ SLIST_HEADER BackFillPacketList;
+#endif
+
+#ifdef _PNP_POWER
+ LIST_ENTRY BindingPoolList;
+ SLIST_HEADER BindingList;
+#endif
+
+ SLIST_HEADER SendPacketList;
+ SLIST_HEADER ReceivePacketList;
+ PIPX_PADDING_BUFFER PaddingBuffer;
+
+ UCHAR State;
+
+ UCHAR FrameTypeDefault;
+
+ //
+ // This holds state if SingleNetworkActive is TRUE. If
+ // it is TRUE then WAN nets are active; if it is FALSE
+ // then LAN nets are active.
+ //
+
+ BOOLEAN ActiveNetworkWan;
+
+ //
+ // TRUE if we have a virtual network.
+ //
+
+ BOOLEAN VirtualNetwork;
+
+ //
+ // If we are set up for SingleNetworkActive, we may have
+ // to start our broadcast of net 0 frames somewhere other
+ // than NIC ID 1, so that we don't send to the wrong type.
+ //
+
+ USHORT FirstLanNicId;
+ USHORT FirstWanNicId;
+
+ //
+ // This holds the total memory allocated for the above structures.
+ //
+
+ LONG MemoryUsage;
+ LONG MemoryLimit;
+
+ //
+ // How many of various resources have been allocated.
+ //
+
+ ULONG AllocatedDatagrams;
+ ULONG AllocatedReceivePackets;
+ ULONG AllocatedPaddingBuffers;
+
+ //
+ // Other configuration parameters.
+ //
+
+ ULONG InitDatagrams;
+ ULONG MaxDatagrams;
+ ULONG RipAgeTime;
+ ULONG RipCount;
+ ULONG RipTimeout;
+ ULONG RipUsageTime;
+ ULONG SourceRouteUsageTime;
+ USHORT SocketStart;
+ USHORT SocketEnd;
+ ULONG SocketUniqueness;
+ ULONG VirtualNetworkNumber;
+ ULONG EthernetExtraPadding;
+ BOOLEAN DedicatedRouter;
+ BOOLEAN VirtualNetworkOptional;
+ UCHAR DisableDialinNetbios;
+
+ //
+ // These are currently not read from the registry.
+ //
+
+ ULONG InitReceivePackets;
+ ULONG InitReceiveBuffers;
+ ULONG MaxReceivePackets;
+ ULONG MaxReceiveBuffers;
+
+#ifdef _PNP_POWER
+ ULONG MaxPoolBindings;
+ ULONG AllocatedBindings;
+ ULONG InitBindings;
+#endif
+
+ //
+ // This contains the next unique indentified to use as
+ // the FsContext in the file object associated with an
+ // open of the control channel.
+ //
+
+ LARGE_INTEGER ControlChannelIdentifier;
+
+ //
+ // This registry parameter controls whether IPX checks (and discards)
+ // packets with mismatched Source addresses in the receive path.
+ //
+ BOOLEAN VerifySourceAddress;
+
+ //
+ // Where the current socket allocation is.
+ //
+ USHORT CurrentSocket;
+
+ //
+ // Number of segments in the RIP database.
+ //
+
+ ULONG SegmentCount;
+
+ //
+ // Points to an array of locks for the RIP database (these
+ // are stored outside of the ROUTER_SEGMENT so the array
+ // can be exposed to the RIP upper driver as one piece).
+ //
+
+ CTELock *SegmentLocks;
+
+ //
+ // Points to an array of ROUTER_SEGMENT fields for
+ // various RIP control fields.
+ //
+
+ ROUTER_SEGMENT *Segments;
+
+ //
+ // Queue of RIP packets waiting to be sent.
+ //
+
+ LIST_ENTRY WaitingRipPackets;
+ ULONG RipPacketCount;
+
+ //
+ // Timer that keeps RIP requests RIP_GRANULARITY ms apart.
+ //
+
+ BOOLEAN RipShortTimerActive;
+ USHORT RipSendTime;
+ CTETimer RipShortTimer;
+
+ //
+ // Timer that runs to age out unused rip entries (if the
+ // router is not bound) and re-rip every so often for
+ // active entries.
+ //
+
+ CTETimer RipLongTimer;
+
+ //
+ // This controls the source routing timeout code.
+ //
+
+ BOOLEAN SourceRoutingUsed; // TRUE if any 802.5 bindings exist.
+ CHAR SourceRoutingTime; // incremented each time timer fires.
+ CTETimer SourceRoutingTimer; // runs every minute.
+
+ //
+ // [FW] Kicks in every minute if at least one WAN line is up. Increments
+ // the WAN incativity counter on all UP WAN bindings.
+ //
+ CTETimer WanInactivityTimer;
+
+ //
+ // These are the merging of the binding values.
+ //
+
+ ULONG LinkSpeed;
+ ULONG MacOptions;
+
+ //
+ // Where we tell upper drivers to put their headers.
+ //
+
+ ULONG IncludedHeaderOffset;
+
+ //
+ // A pre-allocated header containing our node and network,
+ // plus an unused socket (so the structure is a known size
+ // for easy copying).
+ //
+
+ TDI_ADDRESS_IPX SourceAddress;
+
+ //
+ // The following field is an array of list heads of ADDRESS objects that
+ // are defined for this transport provider. To edit the list, you must
+ // hold the spinlock of the device context object.
+ //
+
+ LIST_ENTRY AddressDatabases[IPX_ADDRESS_HASH_COUNT]; // list of defined transport addresses.
+
+ //
+ // Holds the last address we looked up.
+ //
+
+ PVOID LastAddress;
+
+ NDIS_HANDLE NdisBufferPoolHandle;
+
+ //
+ // The following structure contains statistics counters for use
+ // by TdiQueryInformation and TdiSetInformation. They should not
+ // be used for maintenance of internal data structures.
+ //
+
+ TDI_PROVIDER_INFO Information; // information about this provider.
+
+ //
+ // Information.MaxDatagramSize is the minimum size we can
+ // send to all bindings assuming worst-case source routing;
+ // this is the value that won't break any network drivers.
+ //
+
+ ULONG RealMaxDatagramSize;
+
+#if DBG
+ UCHAR Signature2[4]; // contains "IDC2"
+#endif
+
+ //
+ // Indicates whether each upper driver is bound
+ // (Netbios = 0, SPX = 1, RIP = 2).
+ //
+
+ BOOLEAN ForwarderBound;
+
+ BOOLEAN UpperDriverBound[UPPER_DRIVER_COUNT];
+
+ //
+ // TRUE if any driver is bound.
+ //
+
+ BOOLEAN AnyUpperDriverBound;
+
+ //
+ // Whether a receive complete should be indicated to
+ // this upper driver.
+ //
+
+ BOOLEAN ReceiveCompletePending[UPPER_DRIVER_COUNT];
+
+ //
+ // Control channel identifier for each of the upper
+ // drivers' bindings.
+ //
+
+ LARGE_INTEGER UpperDriverControlChannel[UPPER_DRIVER_COUNT];
+
+ //
+ // Entry points and other information for each of the
+ // upper drivers.
+ //
+
+ IPX_INTERNAL_BIND_INPUT UpperDrivers[UPPER_DRIVER_COUNT];
+
+ //
+ // How many upper drivers want broadcast enabled.
+ //
+
+ ULONG EnableBroadcastCount;
+
+ //
+ // Indicates if an enable broadcast operation is in
+ // progress.
+ //
+
+ BOOLEAN EnableBroadcastPending;
+
+ //
+ // Indicates if a disable broadcast operation is in
+ // progress.
+ //
+
+ BOOLEAN DisableBroadcastPending;
+
+ //
+ // Indicates if the current operation should be
+ // reversed when it is finished.
+ //
+
+ BOOLEAN ReverseBroadcastOperation;
+
+ //
+ // TRUE if RIP wants a single network number for all WANs
+ //
+
+ BOOLEAN WanGlobalNetworkNumber;
+
+ //
+ // If WanGlobalNetworkNumber is TRUE, then this holds the
+ // actual value of the network number, once we know it.
+ //
+
+ ULONG GlobalWanNetwork;
+
+ //
+ // Set to TRUE if WanGlobalNetworkNumber is TRUE and we
+ // have already completed a queued notify from SAP. In
+ // this case GlobalWanNetwork will be set correctly.
+ //
+
+ BOOLEAN GlobalNetworkIndicated;
+
+ //
+ // TRUE if we need to act as a RIP announcer/responder
+ // for our virtual net.
+ //
+
+ BOOLEAN RipResponder;
+
+ //
+ // TRUE if we have already logged an error because someone
+ // sent a SAP response but we have multiple cards with no
+ // virtual network.
+ //
+
+ BOOLEAN SapWarningLogged;
+
+ //
+ // Used to queue up a worker thread to perform
+ // broadcast operations.
+ //
+
+ WORK_QUEUE_ITEM BroadcastOperationQueueItem;
+
+#ifdef _PNP_POWER
+ //
+ // Used to queue up a worker thread to perform
+ // PnP indications to upper drivers.
+ //
+
+ WORK_QUEUE_ITEM PnPIndicationsQueueItem;
+#endif
+
+ //
+ // This event is used when unloading to signal that
+ // the reference count is now 0.
+ //
+
+ KEVENT UnloadEvent;
+ BOOLEAN UnloadWaiting;
+
+ //
+ // Counters for most of the statistics that IPX maintains;
+ // some of these are kept elsewhere. Including the structure
+ // itself wastes a little space but ensures that the alignment
+ // inside the structure is correct.
+ //
+
+ TDI_PROVIDER_STATISTICS Statistics;
+
+
+ //
+ // This is TRUE if we have any adapters where we are
+ // auto-detecting the frame type.
+ //
+
+ BOOLEAN AutoDetect;
+
+ //
+ // This is TRUE if we are auto-detecting and we have
+ // found the default auto-detect type on the net.
+ //
+
+ BOOLEAN DefaultAutoDetected;
+
+ //
+ // Our state during auto-detect. After we are done this
+ // will stay at AutoDetectDone;
+ //
+
+ UCHAR AutoDetectState;
+
+ //
+ // If we are auto-detecting, this event is used to stall
+ // our initialization code while we do auto-detection --
+ // this is so we have a constant view of the world once
+ // we return from DriverEntry.
+ //
+
+ KEVENT AutoDetectEvent;
+
+ //
+ // Counters for "active" time.
+ //
+
+ LARGE_INTEGER IpxStartTime;
+
+ //
+ // This resource guards access to the ShareAccess
+ // and SecurityDescriptor fields in addresses.
+ //
+
+ ERESOURCE AddressResource;
+
+ //
+ // Points back to the system device object.
+ //
+
+ PDEVICE_OBJECT DeviceObject;
+
+#ifdef _PNP_POWER
+ //
+ // Used to store the Tdi registration handle for deviceobject notifications.
+ //
+ HANDLE TdiRegistrationHandle;
+
+ //
+ // Used to store the TA_ADDRESS which is indicated up to Tdi clients as adapters appear.
+ //
+ PTA_ADDRESS TdiRegistrationAddress;
+#endif
+
+#ifdef SNMP
+ NOVIPXMIB_BASE MibBase;
+#endif SNMP
+
+ //
+ // These are kept around for error logging, and stored right
+ // after this structure.
+ //
+
+ PWCHAR DeviceName;
+ ULONG DeviceNameLength;
+
+} DEVICE, * PDEVICE;
+
+
+extern PDEVICE IpxDevice;
+extern PIPX_PADDING_BUFFER IpxPaddingBuffer;
+#if DBG
+EXTERNAL_LOCK(IpxGlobalInterlock);
+#endif
+
+#ifdef SNMP
+#define IPX_MIB_ENTRY(Device, Variable) ((Device)->MibBase.Variable)
+#endif SNMP
+
+//
+// device state definitions
+//
+
+#define DEVICE_STATE_CLOSED 0x00
+#define DEVICE_STATE_OPEN 0x01
+#define DEVICE_STATE_STOPPING 0x02
+
+#ifdef _PNP_POWER
+
+//
+// New state which comes between CLOSED and OPEN. At this state,
+// there are no adapters in the system and so no network activity
+// is possible.
+//
+#define DEVICE_STATE_LOADED 0x03
+#endif _PNP_POWER
+
+//
+// This is the state of our auto-detect if we do it.
+//
+
+#define AUTO_DETECT_STATE_INIT 0x00 // still initializing the device
+#define AUTO_DETECT_STATE_RUNNING 0x01 // sent ffffffff query, waiting for responses
+#define AUTO_DETECT_STATE_PROCESSING 0x02 // processing the responses
+#define AUTO_DETECT_STATE_DONE 0x03 // detection is done, IPX is active
+
+
+
+#define IPX_TDI_RESOURCES 9
+
+
+//
+// This structure is pointed to by the FsContext field in the FILE_OBJECT
+// for this Address. This structure is the base for all activities on
+// the open file object within the transport provider. All active connections
+// on the address point to this structure, although no queues exist here to do
+// work from. This structure also maintains a reference to an ADDRESS
+// structure, which describes the address that it is bound to.
+//
+
+#define AFREF_CREATE 0
+#define AFREF_RCV_DGRAM 1
+#define AFREF_SEND_DGRAM 2
+#define AFREF_VERIFY 3
+#define AFREF_INDICATION 4
+
+#define AFREF_TOTAL 8
+
+typedef struct _ADDRESS_FILE {
+
+#if DBG
+ ULONG RefTypes[AFREF_TOTAL];
+#endif
+
+ CSHORT Type;
+ CSHORT Size;
+
+ LIST_ENTRY Linkage; // next address file on this address.
+ // also used for linkage in the
+ // look-aside list
+
+ ULONG ReferenceCount; // number of references to this object.
+
+ //
+ // the current state of the address file structure; this is either open or
+ // closing
+ //
+
+ UCHAR State;
+
+ CTELock * AddressLock;
+
+ //
+ // The following fields are kept for housekeeping purposes.
+ //
+
+ PREQUEST Request; // the request used for open or close
+ struct _ADDRESS *Address; // address to which we are bound.
+#ifdef ISN_NT
+ PFILE_OBJECT FileObject; // easy backlink to file object.
+#endif
+ struct _DEVICE *Device; // device to which we are attached.
+
+ //
+ //
+ // TRUE if ExtendedAddressing, ReceiveIpxHeader,
+ // FilterOnPacketType, or ReceiveFlagAddressing is TRUE.
+ //
+
+ BOOLEAN SpecialReceiveProcessing;
+
+ //
+ // The remote address of a send datagram includes the
+ // packet type. and on a receive datagram includes
+ // the packet type AND a flags byte indicating information
+ // about the frame (was it broadcast, was it sent from
+ // this machine).
+ //
+
+ BOOLEAN ExtendedAddressing;
+
+ //
+ // TRUE if the address on a receive datagram includes
+ // the packet type and a flags byte (like ExtendedAddressing),
+ // but on send the address is normal (no packet type).
+ //
+
+ BOOLEAN ReceiveFlagsAddressing;
+
+ //
+ // Is the IPX header received with the data.
+ //
+
+ BOOLEAN ReceiveIpxHeader;
+
+ //
+ // The packet type to use if it is unspecified in the send.
+ //
+
+ UCHAR DefaultPacketType;
+
+ //
+ // TRUE if packet type filtering is enabled.
+ //
+
+ BOOLEAN FilterOnPacketType;
+
+ //
+ // The packet type to filter on.
+ //
+
+ UCHAR FilteredType;
+
+ //
+ // Does this address file want broadcast packets.
+ //
+
+ BOOLEAN EnableBroadcast;
+
+ //
+ // This is set to TRUE if this is the SAP socket -- we
+ // put this under SpecialReceiveProcessing to avoid
+ // hitting the main path.
+ //
+
+ BOOLEAN IsSapSocket;
+
+ //
+ // The following queue is used to queue receive datagram requests
+ // on this address file. Send datagram requests are queued on the
+ // address itself. These queues are managed by the EXECUTIVE interlocked
+ // list management routines. The actual objects which get queued to this
+ // structure are request control blocks (RCBs).
+ //
+
+ LIST_ENTRY ReceiveDatagramQueue; // FIFO of outstanding TdiReceiveDatagrams.
+
+ //
+ // This holds the request used to close this address file,
+ // for pended completion.
+ //
+
+ PREQUEST CloseRequest;
+
+ //
+ // handler for kernel event actions. First we have a set of booleans that
+ // indicate whether or not this address has an event handler of the given
+ // type registered.
+ //
+
+ //
+ // [CH] Added the chained receive handlers.
+ //
+
+ BOOLEAN RegisteredReceiveDatagramHandler;
+ BOOLEAN RegisteredChainedReceiveDatagramHandler;
+ BOOLEAN RegisteredErrorHandler;
+
+ //
+ // The following function pointer always points to a TDI_IND_RECEIVE_DATAGRAM
+ // event handler for the address. If the NULL handler is specified in a
+ // TdiSetEventHandler, this this points to an internal routine which does
+ // not accept the incoming data.
+ //
+
+ PTDI_IND_RECEIVE_DATAGRAM ReceiveDatagramHandler;
+ PVOID ReceiveDatagramHandlerContext;
+ PTDI_IND_CHAINED_RECEIVE_DATAGRAM ChainedReceiveDatagramHandler;
+ PVOID ChainedReceiveDatagramHandlerContext;
+
+ //
+ // The following function pointer always points to a TDI_IND_ERROR
+ // handler for the address. If the NULL handler is specified in a
+ // TdiSetEventHandler, this this points to an internal routine which
+ // simply returns successfully.
+ //
+
+ PTDI_IND_ERROR ErrorHandler;
+ PVOID ErrorHandlerContext;
+
+} ADDRESS_FILE, *PADDRESS_FILE;
+
+#define ADDRESSFILE_STATE_OPENING 0x00 // not yet open for business
+#define ADDRESSFILE_STATE_OPEN 0x01 // open for business
+#define ADDRESSFILE_STATE_CLOSING 0x02 // closing
+
+
+//
+// This structure defines an ADDRESS, or active transport address,
+// maintained by the transport provider. It contains all the visible
+// components of the address (such as the TSAP and network name components),
+// and it also contains other maintenance parts, such as a reference count,
+// ACL, and so on. All outstanding connection-oriented and connectionless
+// data transfer requests are queued here.
+//
+
+#define AREF_ADDRESS_FILE 0
+#define AREF_LOOKUP 1
+#define AREF_RECEIVE 2
+
+#define AREF_TOTAL 4
+
+typedef struct _ADDRESS {
+
+#if DBG
+ ULONG RefTypes[AREF_TOTAL];
+#endif
+
+ USHORT Size;
+ CSHORT Type;
+
+/* ULONGs to allow for Interlocked operations.
+
+ BOOLEAN SendPacketInUse; // put these after so header is aligned.
+
+ BOOLEAN ReceivePacketInUse;
+#if BACK_FILL
+ BOOLEAN BackFillPacketInUse;
+#endif
+*/
+
+ ULONG SendPacketInUse; // put these after so header is aligned.
+
+ ULONG ReceivePacketInUse;
+#if BACK_FILL
+ ULONG BackFillPacketInUse;
+#endif
+
+ LIST_ENTRY Linkage; // next address/this device object.
+ ULONG ReferenceCount; // number of references to this object.
+
+ CTELock Lock;
+
+ //
+ // The following fields comprise the actual address itself.
+ //
+
+ PREQUEST Request; // pointer to address creation request.
+
+ USHORT Socket; // the socket this address corresponds to.
+ USHORT SendSourceSocket; // used for sends; may be == Socket or 0
+
+ //
+ // The following fields are used to maintain state about this address.
+ //
+
+ BOOLEAN Stopping;
+ ULONG Flags; // attributes of the address.
+ struct _DEVICE *Device; // device context to which we are attached.
+ CTELock * DeviceLock;
+
+ //
+ // The following queues is used to hold send datagrams for this
+ // address. Receive datagrams are queued to the address file. Requests are
+ // processed in a first-in, first-out manner, so that the very next request
+ // to be serviced is always at the head of its respective queue. These
+ // queues are managed by the EXECUTIVE interlocked list management routines.
+ // The actual objects which get queued to this structure are request control
+ // blocks (RCBs).
+ //
+
+ LIST_ENTRY AddressFileDatabase; // list of defined address file objects
+
+ //
+ // Holds our source address, used for construcing datagrams
+ // quickly.
+ //
+
+ TDI_ADDRESS_IPX LocalAddress;
+
+ IPX_SEND_PACKET SendPacket;
+ IPX_RECEIVE_PACKET ReceivePacket;
+
+#if BACK_FILL
+ IPX_SEND_PACKET BackFillPacket;
+#endif
+
+
+ UCHAR SendPacketHeader[IPX_MAXIMUM_MAC + sizeof(IPX_HEADER)];
+
+#ifdef ISN_NT
+
+ //
+ // These two can be a union because they are not used
+ // concurrently.
+ //
+
+ union {
+
+ //
+ // This structure is used for checking share access.
+ //
+
+ SHARE_ACCESS ShareAccess;
+
+ //
+ // Used for delaying IpxDestroyAddress to a thread so
+ // we can access the security descriptor.
+ //
+
+ WORK_QUEUE_ITEM DestroyAddressQueueItem;
+
+ } u;
+
+ //
+ // This structure is used to hold ACLs on the address.
+
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+
+#endif
+
+ ULONG Index;
+ BOOLEAN RtAdd;
+
+} ADDRESS, *PADDRESS;
+
+#define ADDRESS_FLAGS_STOPPING 0x00000001
+
+//
+// In order to increase the range of ControlChannelIds, we have a large integer to represent
+// monotonically increasing ControlChannelIdentifiers. This large integer is packed into the
+// 6 Bytes as follows:
+//
+// REQUEST_OPEN_CONTEXT(_Request) - 4 bytes
+// Upper 2 bytes of REQUEST_OPEN_TYPE(_Request) - 2 bytes
+//
+// IPX_CC_MASK is used to mask out the upper 2 bytes of the OPEN_TYPE.
+// MAX_CCID is 2^48.
+//
+#define IPX_CC_MASK 0x0000ffff
+
+#define MAX_CCID 0xffffffffffff
+
+#define CCID_FROM_REQUEST(_ccid, _Request) \
+ (_ccid).LowPart = (ULONG)(REQUEST_OPEN_CONTEXT(_Request)); \
+ (_ccid).HighPart = ((ULONG)(REQUEST_OPEN_TYPE(_Request)) >> 16);
+
+//#define USER_BUFFER_OFFSET FIELD_OFFSET(RTRCV_BUFFER, DgrmLength)
+#define USER_BUFFER_OFFSET FIELD_OFFSET(RTRCV_BUFFER, Options)
+//
+// This structure keeps track of the WINS recv Irp and any datagram
+// queued to go up to WINS (name service datagrams)
+//
+#define REFRT_TOTAL 8
+
+#define RT_CREATE 0
+#define RT_CLEANUP 1
+#define RT_CLOSE 2
+#define RT_SEND 3
+#define RT_RCV 4
+#define RT_IRPIN 5
+#define RT_BUFF 6
+#define RT_EXTRACT 7
+
+
+#define RT_EMPTY 0
+#define RT_OPEN 1
+#define RT_CLOSING 2
+#define RT_CLOSED 3
+
+
+#define RT_IRP_MAX 1000
+#define RT_BUFF_MAX 1000
+
+//
+// Max. memory allocated for queueing buffers to be received by the RT
+// manager
+//
+#define RT_MAX_BUFF_MEM 65000 //bytes
+
+//
+// Get Index corresponding to the address object opened by RT. BTW We
+// can not have more than one Address file (client) for a RT address.
+//
+#define RT_ADDRESS_INDEX(_pIrp) (((ULONG)REQUEST_OPEN_TYPE(_pIrp)) - ROUTER_ADDRESS_FILE)
+
+typedef struct _RT_IRP {
+ PADDRESS_FILE AddressFile;
+ LIST_ENTRY RcvIrpList;
+ ULONG NoOfRcvIrps;
+ LIST_ENTRY RcvList; // linked list of Datagrams Q'd to rcv
+ ULONG NoOfRcvBuffs; // linked list of Datagrams Q'd to rcv
+ BOOLEAN State;
+ } RT_IRP, *PRT_IRP;
+
+typedef struct
+{
+#if DBG
+ ULONG RefTypes[REFRT_TOTAL];
+#endif
+
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+#if DBG
+ UCHAR Signature[4]; // contains "IBI1"
+#endif
+ LIST_ENTRY CompletedIrps; // linked list of Datagrams Q'd to rcv
+ LIST_ENTRY HolderIrpsList; // Holds Irps
+ CTELock Lock;
+ ULONG ReferenceCount;
+ ULONG RcvMemoryAllocated; // bytes buffered so far
+ ULONG RcvMemoryMax; // max # of bytes to buffer on Rcv
+ PDEVICE pDevice; // the devicecontext used by wins
+ UCHAR NoOfAdds;
+ RT_IRP AddFl[IPX_RT_MAX_ADDRESSES];
+} RT_INFO, *PRT_INFO;
+
+//
+// RT Rcv Buffer structure
+//
+typedef struct
+{
+ LIST_ENTRY Linkage;
+ ULONG TotalAllocSize;
+ ULONG UserBufferLengthToPass;
+ IPX_DATAGRAM_OPTIONS2 Options;
+
+} RTRCV_BUFFER, *PRTRCV_BUFFER;
+
+#define OFFSET_OPTIONS_IN_RCVBUFF FIELD_OFFSET(RTRCV_BUFFER, Options)
+#define OFFSET_PKT_IN_RCVBUFF (FIELD_OFFSET(RTRCV_BUFFER, Options) + FIELD_OFFSET(IPX_DATAGRAM_OPTIONS2, Data))
+#define OFFSET_PKT_IN_OPTIONS FIELD_OFFSET(IPX_DATAGRAM_OPTIONS2, Data)
+
+extern PRT_INFO pRtInfo;
+
+//
+// We keep the demand-dial binding at the beginning of the binding array; this keeps
+// track of the number of extra bindings that we have.
+// Currently 1 (for demand-dial), we could also keep other bindings like the loopback
+// binding, etc.
+//
+#define DEMAND_DIAL_NIC_ID DEMAND_DIAL_ADAPTER_CONTEXT
+#define LOOPBACK_NIC_ID VIRTUAL_NET_ADAPTER_CONTEXT
+
+#define EXTRA_BINDINGS 2
diff --git a/private/ntos/tdi/isn/ipx/isnipx.h b/private/ntos/tdi/isn/ipx/isnipx.h
new file mode 100644
index 000000000..ae48d1449
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/isnipx.h
@@ -0,0 +1,554 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ isnipx.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ IPX module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#ifndef _ISNIPX_
+#define _ISNIPX_
+
+#define MAC_HEADER_SIZE ((IPX_MAXIMUM_MAC + 3) & ~3)
+#define RIP_PACKET_SIZE ((sizeof(RIP_PACKET) + 3) & ~3)
+#define IPX_HEADER_SIZE ((sizeof(IPX_HEADER) + 3) & ~3)
+
+//
+// Frame type definitions
+//
+
+#define ISN_FRAME_TYPE_ETHERNET_II 0
+#define ISN_FRAME_TYPE_802_3 1
+#define ISN_FRAME_TYPE_802_2 2
+#define ISN_FRAME_TYPE_SNAP 3
+#define ISN_FRAME_TYPE_ARCNET 4 // we ignore this
+#define ISN_FRAME_TYPE_MAX 4 // of the four standard ones
+
+#define ISN_FRAME_TYPE_AUTO 0xff
+
+
+//
+// This defines the size of the maximum MAC header required
+// (token-ring: MAC 14 bytes, RI 18 bytes, LLC 3 bytes, SNAP 5 bytes).
+//
+
+#define IPX_MAXIMUM_MAC 40
+
+//
+// This is an internal identifier used for RIP query packets.
+//
+
+#define IDENTIFIER_RIP_INTERNAL 4
+
+//
+// This is an internal identifier used for RIP response packets.
+//
+
+#define IDENTIFIER_RIP_RESPONSE 5
+
+
+//
+// This is the total number of "real" identifiers.
+//
+
+#define IDENTIFIER_TOTAL 4
+
+
+//
+// Some definitions (in the correct on-the-wire order).
+//
+
+#define RIP_PACKET_TYPE 0x01
+#define RIP_SOCKET 0x5304
+#define RIP_REQUEST 0x0100
+#define RIP_RESPONSE 0x0200
+#define RIP_DOWN 0x8200 // use high bit to indicate it
+
+#define SAP_PACKET_TYPE 0x04
+#define SAP_SOCKET 0x5204
+
+#define SPX_PACKET_TYPE 0x05
+
+#define NB_SOCKET 0x5504
+
+
+#include <packon.h>
+
+//
+// Definition of the IPX header.
+//
+
+typedef struct _IPX_HEADER {
+ USHORT CheckSum;
+ UCHAR PacketLength[2];
+ UCHAR TransportControl;
+ UCHAR PacketType;
+ UCHAR DestinationNetwork[4];
+ UCHAR DestinationNode[6];
+ USHORT DestinationSocket;
+ UCHAR SourceNetwork[4];
+ UCHAR SourceNode[6];
+ USHORT SourceSocket;
+} IPX_HEADER, *PIPX_HEADER;
+
+
+//
+// Definition of a RIP network entry.
+//
+
+typedef struct _RIP_NETWORK_ENTRY {
+ ULONG NetworkNumber;
+ USHORT HopCount;
+ USHORT TickCount;
+} RIP_NETWORK_ENTRY, *PRIP_NETWORK_ENTRY;
+
+//
+// Definition of a single entry rip packet.
+//
+
+typedef struct _RIP_PACKET {
+ USHORT Operation;
+ RIP_NETWORK_ENTRY NetworkEntry;
+} RIP_PACKET, *PRIP_PACKET;
+
+#include <packoff.h>
+
+
+#define IPX_DEVICE_SIGNATURE 0x1401
+#define IPX_ADAPTER_SIGNATURE 0x1402
+#define IPX_BINDING_SIGNATURE 0x1403
+#define IPX_ADDRESS_SIGNATURE 0x1404
+#define IPX_ADDRESSFILE_SIGNATURE 0x1405
+#define IPX_RT_SIGNATURE 0x1406
+
+#define IPX_FILE_TYPE_CONTROL (ULONG)0x4701 // file is type control
+
+
+//
+// Defined granularity of RIP timeouts in milliseconds
+//
+
+#define RIP_GRANULARITY 55
+
+
+//
+// The default number of segments in the RIP table.
+//
+
+#define RIP_SEGMENTS 7
+
+
+
+//
+// Convert a ushort netware order <-> machine order
+//
+
+#define REORDER_USHORT(_Ushort) ((((_Ushort) & 0xff00) >> 8) | (((_Ushort) & 0x00ff) << 8))
+
+//
+// Convert a ulong netware order <-> machine order
+//
+
+#define REORDER_ULONG(_Ulong) \
+ ((((_Ulong) & 0xff000000) >> 24) | \
+ (((_Ulong) & 0x00ff0000) >> 8) | \
+ (((_Ulong) & 0x0000ff00) << 8) | \
+ (((_Ulong) & 0x000000ff) << 24))
+
+
+
+#if DBG
+
+extern ULONG IpxDebug;
+extern ULONG IpxMemoryDebug;
+
+#define IPX_MEMORY_LOG_SIZE 128
+extern UCHAR IpxDebugMemory[IPX_MEMORY_LOG_SIZE][64];
+extern PUCHAR IpxDebugMemoryLoc;
+extern PUCHAR IpxDebugMemoryEnd;
+
+VOID
+IpxDebugMemoryLog(
+ IN PUCHAR FormatString,
+ ...
+);
+
+#define IPX_DEBUG(_Flag, _Print) { \
+ if (IpxDebug & (IPX_DEBUG_ ## _Flag)) { \
+ DbgPrint ("IPX: "); \
+ DbgPrint _Print; \
+ } \
+ if (IpxMemoryDebug & (IPX_DEBUG_ ## _Flag)) { \
+ IpxDebugMemoryLog _Print; \
+ } \
+}
+
+#else
+
+#define IPX_DEBUG(_Flag, _Print)
+
+#endif
+
+
+//
+// These definitions are for abstracting IRPs from the
+// transport for portability.
+//
+
+#if ISN_NT
+
+typedef IRP REQUEST, *PREQUEST;
+
+
+//
+// PREQUEST
+// IpxAllocateRequest(
+// IN PDEVICE Device,
+// IN PIRP Irp
+// );
+//
+// Allocates a request for the system-specific request structure.
+//
+
+#define IpxAllocateRequest(_Device,_Irp) \
+ (_Irp)
+
+
+//
+// BOOLEAN
+// IF_NOT_ALLOCATED(
+// IN PREQUEST Request
+// );
+//
+// Checks if a request was not successfully allocated.
+//
+
+#define IF_NOT_ALLOCATED(_Request) \
+ if (0)
+
+
+//
+// VOID
+// IpxFreeRequest(
+// IN PDEVICE Device,
+// IN PREQUEST Request
+// );
+//
+// Frees a previously allocated request.
+//
+
+#define IpxFreeRequest(_Device,_Request) \
+ ;
+
+
+//
+// VOID
+// MARK_REQUEST_PENDING(
+// IN PREQUEST Request
+// );
+//
+// Marks that a request will pend.
+//
+
+#define MARK_REQUEST_PENDING(_Request) \
+ IoMarkIrpPending(_Request)
+
+
+//
+// VOID
+// UNMARK_REQUEST_PENDING(
+// IN PREQUEST Request
+// );
+//
+// Marks that a request will not pend.
+//
+
+#define UNMARK_REQUEST_PENDING(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->Control) &= ~SL_PENDING_RETURNED)
+
+
+//
+// UCHAR
+// REQUEST_MAJOR_FUNCTION
+// IN PREQUEST Request
+// );
+//
+// Returns the major function code of a request.
+//
+
+#define REQUEST_MAJOR_FUNCTION(_Request) \
+ ((IoGetCurrentIrpStackLocation(_Request))->MajorFunction)
+
+
+//
+// UCHAR
+// REQUEST_MINOR_FUNCTION
+// IN PREQUEST Request
+// );
+//
+// Returns the minor function code of a request.
+//
+
+#define REQUEST_MINOR_FUNCTION(_Request) \
+ ((IoGetCurrentIrpStackLocation(_Request))->MinorFunction)
+
+
+//
+// PNDIS_BUFFER
+// REQUEST_NDIS_BUFFER
+// IN PREQUEST Request
+// );
+//
+// Returns the NDIS buffer chain associated with a request.
+//
+
+#define REQUEST_NDIS_BUFFER(_Request) \
+ ((PNDIS_BUFFER)((_Request)->MdlAddress))
+
+
+//
+// PVOID
+// REQUEST_OPEN_CONTEXT(
+// IN PREQUEST Request
+// );
+//
+// Gets the context associated with an opened address/connection/control channel.
+//
+
+#define REQUEST_OPEN_CONTEXT(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->FileObject)->FsContext)
+
+
+//
+// PVOID
+// REQUEST_OPEN_TYPE(
+// IN PREQUEST Request
+// );
+//
+// Gets the type associated with an opened address/connection/control channel.
+//
+
+#define REQUEST_OPEN_TYPE(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->FileObject)->FsContext2)
+
+
+//
+// PFILE_FULL_EA_INFORMATION
+// OPEN_REQUEST_EA_INFORMATION(
+// IN PREQUEST Request
+// );
+//
+// Returns the EA information associated with an open/close request.
+//
+
+#define OPEN_REQUEST_EA_INFORMATION(_Request) \
+ ((PFILE_FULL_EA_INFORMATION)((_Request)->AssociatedIrp.SystemBuffer))
+
+
+#define OPEN_REQUEST_EA_LENGTH(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->Parameters.DeviceIoControl.InputBufferLength))
+
+#define OPEN_REQUEST_RCV_LEN(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->Parameters.DeviceIoControl.OutputBufferLength))
+
+#define REQUEST_SPECIAL_RECV(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->Parameters.DeviceIoControl.IoControlCode) == MIPX_RCV_DATAGRAM)
+
+#define REQUEST_SPECIAL_SEND(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->Parameters.DeviceIoControl.IoControlCode) == MIPX_SEND_DATAGRAM)
+
+
+#define REQUEST_CODE(_Request) \
+ ((IoGetCurrentIrpStackLocation(_Request))->Parameters.DeviceIoControl.IoControlCode)
+
+//
+// The following value does not clash with TDI_TRANSPORT_ADDRESS_FILE value of
+// 0x1
+//
+#define ROUTER_ADDRESS_FILE 0x4
+
+//
+// PTDI_REQUEST_KERNEL
+// REQUEST_PARAMETERS(
+// IN PREQUEST Request
+// );
+//
+// Obtains a pointer to the parameters of a request.
+//
+
+#define REQUEST_PARAMETERS(_Request) \
+ (&((IoGetCurrentIrpStackLocation(_Request))->Parameters))
+
+
+//
+// VOID
+// REQUEST_OPEN_CONTEXT_AND_PARAMS(
+// IN PREQUEST Request
+// OUT PVOID * OpenContext,
+// OUT PTDI_REQUEST_KERNEL * Parameters
+// );
+//
+// Simultaneously returns the open context and the parameters
+// for a request (this is an optimization since the send
+// datagram code needs them both).
+//
+
+#define REQUEST_OPEN_CONTEXT_AND_PARAMS(_Request,_OpenContext,_Parameters) { \
+ PIO_STACK_LOCATION _IrpSp = IoGetCurrentIrpStackLocation(_Request); \
+ *(_OpenContext) = _IrpSp->FileObject->FsContext; \
+ *(_Parameters) = (PTDI_REQUEST_KERNEL)(&_IrpSp->Parameters); \
+}
+
+
+//
+// PLIST_ENTRY
+// REQUEST_LINKAGE(
+// IN PREQUEST Request
+// );
+//
+// Returns a pointer to a linkage field in the request.
+//
+
+#define REQUEST_LINKAGE(_Request) \
+ (&((_Request)->Tail.Overlay.ListEntry))
+
+
+//
+// PREQUEST
+// LIST_ENTRY_TO_REQUEST(
+// IN PLIST_ENTRY ListEntry
+// );
+//
+// Returns a request given a linkage field in it.
+//
+
+#define LIST_ENTRY_TO_REQUEST(_ListEntry) \
+ ((PREQUEST)(CONTAINING_RECORD(_ListEntry, REQUEST, Tail.Overlay.ListEntry)))
+
+
+//
+// NTSTATUS
+// REQUEST_STATUS(
+// IN PREQUEST Request
+// );
+//
+// Used to access the status field of a request.
+//
+
+#define REQUEST_STATUS(_Request) \
+ (_Request)->IoStatus.Status
+
+
+//
+// ULONG
+// REQUEST_INFORMATION(
+// IN PREQUEST Request)
+// );
+//
+// Used to access the information field of a request.
+//
+
+#define REQUEST_INFORMATION(_Request) \
+ (_Request)->IoStatus.Information
+
+
+//
+// VOID
+// IpxCompleteRequest(
+// IN PREQUEST Request
+// );
+//
+// Completes a request whose status and information fields have
+// been filled in.
+//
+
+#define IpxCompleteRequest(_Request) \
+ IoCompleteRequest (_Request, IO_NETWORK_INCREMENT)
+
+#else
+
+//
+// These routines must be defined for portability to a VxD.
+//
+
+#endif
+
+
+#define IPX_INCREMENT(_Long, _Lock) InterlockedIncrement(_Long)
+#define IPX_DECREMENT(_Long, _Lock) InterlockedDecrement(_Long)
+
+#define IPX_ADD_ULONG(_Pulong, _Ulong, _Lock) InterlockedExchangeAdd(_Pulong, _Ulong)
+
+#define IPX_DEFINE_SYNC_CONTEXT(_SyncContext)
+#define IPX_BEGIN_SYNC(_SyncContext)
+#define IPX_END_SYNC(_SyncContext)
+
+#define IPX_DEFINE_LOCK_HANDLE(_LockHandle) CTELockHandle _LockHandle;
+#define IPX_DEFINE_LOCK_HANDLE_PARAM(_LockHandle) CTELockHandle _LockHandle;
+
+#define IPX_GET_LOCK(_Lock, _LockHandle) \
+ CTEGetLock(_Lock, _LockHandle)
+
+#define IPX_FREE_LOCK(_Lock, _LockHandle) \
+ CTEFreeLock(_Lock, _LockHandle)
+
+#define IPX_GET_LOCK1(_Lock, _LockHandle)
+
+#define IPX_FREE_LOCK1(_Lock, _LockHandle)
+
+#define IPX_REMOVE_HEAD_LIST(_Queue, _Lock) ExInterlockedRemoveHeadList(_Queue, _Lock)
+#define IPX_LIST_WAS_EMPTY(_Queue, _OldHead) ((_OldHead) == NULL)
+#define IPX_INSERT_HEAD_LIST(_Queue, _Entry, _Lock) ExInterlockedInsertHeadList(_Queue, _Entry, _Lock)
+#define IPX_INSERT_TAIL_LIST(_Queue, _Entry, _Lock) ExInterlockedInsertTailList(_Queue, _Entry, _Lock)
+
+#define IPX_POP_ENTRY_LIST(_Queue, _Lock) ExInterlockedPopEntrySList(_Queue, _Lock)
+#define IPX_PUSH_ENTRY_LIST(_Queue, _Entry, _Lock) ExInterlockedPushEntrySList(_Queue, _Entry, _Lock)
+
+//
+// This macro adds a ULONG to a LARGE_INTEGER.
+//
+
+#define ADD_TO_LARGE_INTEGER(_LargeInteger,_Ulong) \
+ ExInterlockedAddLargeStatistic((_LargeInteger),(ULONG)(_Ulong))
+
+#define IPX_DEBUG_DEVICE 0x00000001
+#define IPX_DEBUG_ADAPTER 0x00000002
+#define IPX_DEBUG_ADDRESS 0x00000004
+#define IPX_DEBUG_SEND 0x00000008
+#define IPX_DEBUG_NDIS 0x00000010
+#define IPX_DEBUG_RECEIVE 0x00000020
+#define IPX_DEBUG_CONFIG 0x00000040
+#define IPX_DEBUG_PACKET 0x00000080
+#define IPX_DEBUG_RIP 0x00000100
+#define IPX_DEBUG_BIND 0x00000200
+#define IPX_DEBUG_ACTION 0x00000400
+#define IPX_DEBUG_BAD_PACKET 0x00000800
+#define IPX_DEBUG_SOURCE_ROUTE 0x00001000
+#define IPX_DEBUG_WAN 0x00002000
+#define IPX_DEBUG_AUTO_DETECT 0x00004000
+
+#ifdef _PNP_POWER
+#define IPX_DEBUG_PNP 0x00008000
+#endif
+
+#define IPX_DEBUG_LOOPB 0x00010000
+
+#endif
diff --git a/private/ntos/tdi/isn/ipx/loopback.c b/private/ntos/tdi/isn/ipx/loopback.c
new file mode 100644
index 000000000..be44bae5b
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/loopback.c
@@ -0,0 +1,280 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ loopback.c
+
+Abstract:
+
+ This module contains the routines to implement loopback
+
+Author:
+
+ Sanjay Anand (SanjayAn) 2/6/96
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Global lock to control access to the Loopback queue
+//
+DEFINE_LOCK_STRUCTURE(LoopLock)
+
+//
+// Head and tail of the Loopback queue
+//
+PNDIS_PACKET LoopXmitHead = (PNDIS_PACKET)NULL;
+PNDIS_PACKET LoopXmitTail = (PNDIS_PACKET)NULL;
+
+CTEEvent LoopXmitEvent;
+BOOLEAN LoopXmitRtnRunning = 0;
+
+//
+// MaximumPacket sized buffer to hold the lookahead data.
+//
+// ZZBUGBUG: In PnP this value can change
+//
+// PUCHAR LookaheadBuffer=NULL;
+#define LOOP_LOOKAHEAD_SIZE 128 + sizeof(IPX_HEADER) + 8 + 34
+
+
+VOID
+IpxDoLoopback(
+ IN CTEEvent *Event,
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ Does the actual loopback.
+
+Arguments:
+
+ Event - Pointer to event structure.
+
+ Context - Pointer to ZZ
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_PACKET Packet; // Pointer to packet being transmitted
+ PNDIS_BUFFER Buffer; // Current NDIS buffer being processed.
+ ULONG TotalLength; // Total length of send.
+ ULONG LookaheadLength; // Bytes in lookahead.
+ ULONG Copied; // Bytes copied so far.
+ PUCHAR CopyPtr; // Pointer to buffer being copied into.
+ PUCHAR SrcPtr; // Pointer to buffer being copied from.
+ ULONG SrcLength; // Length of src buffer.
+ BOOLEAN Rcvd = FALSE;
+ PIPX_SEND_RESERVED Reserved;
+ ULONG MacSize;
+ PNDIS_PACKET *PacketPtr;
+ UCHAR LookaheadBuffer[LOOP_LOOKAHEAD_SIZE];
+
+ IPX_DEFINE_LOCK_HANDLE(Handle)
+
+ KIRQL OldIrql;
+
+ CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ //
+ // Raise IRQL so we can acquire locks at DPC level in the receive code.
+ // Also to be able to ReceiveIndicate at DPC
+ //
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ IPX_GET_LOCK(&LoopLock, &Handle);
+
+ if (LoopXmitRtnRunning) {
+ IPX_FREE_LOCK(&LoopLock, Handle);
+ KeLowerIrql(OldIrql);
+ return;
+ }
+
+ LoopXmitRtnRunning = 1;
+
+ for (;;) {
+
+ //
+ // Get the next packet from the list.
+ //
+ Packet = LoopXmitHead;
+
+ if (Packet != (PNDIS_PACKET)NULL) {
+ Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ LoopXmitHead = (PNDIS_PACKET)(Reserved->PaddingBuffer);
+ IPX_FREE_LOCK(&LoopLock, Handle);
+ } else { // Nothing left to do.
+ LoopXmitRtnRunning = 0;
+ IPX_FREE_LOCK(&LoopLock, Handle);
+ break;
+ }
+
+ //
+ // We use the PaddingBuffer section as the next ptr.
+ //
+ Reserved->PaddingBuffer = NULL;
+
+ IPX_DEBUG(LOOPB, ("Packet: %lx\n", Packet));
+
+ NdisQueryPacket(Packet, NULL, NULL, &Buffer, &TotalLength);
+
+ NdisQueryBuffer(Buffer, NULL, &MacSize);
+
+ IPX_DEBUG(LOOPB, ("Buffer: %lx Totalpktlen: %lx MacSize: %lx\n", Buffer, TotalLength, MacSize));
+
+ LookaheadLength = MIN(LOOP_LOOKAHEAD_SIZE, TotalLength);
+ Copied = 0;
+ CopyPtr = LookaheadBuffer;
+ while (Copied < LookaheadLength) {
+ ULONG ThisCopy; // Bytes to copy this time.
+
+#ifdef DBG
+ if (!Buffer) {
+ DbgBreakPoint();
+ IPX_GET_LOCK(&LoopLock, &Handle);
+ LoopXmitRtnRunning = 0;
+ IPX_FREE_LOCK(&LoopLock, Handle);
+ KeLowerIrql(OldIrql);
+ return;
+ }
+#endif
+
+ NdisQueryBuffer(Buffer, &SrcPtr, &SrcLength);
+ ThisCopy = MIN(SrcLength, LookaheadLength - Copied);
+ CTEMemCopy(CopyPtr, SrcPtr, ThisCopy);
+ Copied += ThisCopy;
+ CopyPtr += ThisCopy;
+ NdisGetNextBuffer(Buffer, &Buffer);
+ }
+
+ Rcvd = TRUE;
+
+#ifdef BACK_FILL
+ //
+ // For Backfill packets, the MAC header is not yet set up; for others, it is the size
+ // of the first MDL (17).
+ //
+ if ((Reserved->Identifier == IDENTIFIER_IPX) &&
+ (Reserved->BackFill)) {
+ MacSize = 0;
+ }
+#endif
+ IpxReceiveIndication( (NDIS_HANDLE)IPX_LOOPBACK_COOKIE, // BindingContext
+ Packet, // ReceiveContext
+ (MacSize) ? LookaheadBuffer : NULL, // HeaderBuffer
+ MacSize, // HeaderBufferSize
+ LookaheadBuffer+MacSize, // LookAheadBuffer
+ LookaheadLength-MacSize, // LookAheadBufferSize
+ TotalLength-MacSize); // PacketSize
+
+ IpxSendComplete(Context, Packet, NDIS_STATUS_SUCCESS);
+
+ //
+ // Give other threads a chance to run.
+ //
+ KeLowerIrql(OldIrql);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ IPX_GET_LOCK(&LoopLock, &Handle);
+ }
+
+ if (Rcvd) {
+ IpxReceiveComplete(Context);
+ }
+
+ KeLowerIrql(OldIrql);
+}
+
+
+VOID
+IpxInitLoopback()
+/*++
+
+Routine Description:
+
+ Initializes various loopback structures.
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+{
+ CTEInitLock(&LoopLock);
+ CTEInitEvent(&LoopXmitEvent, IpxDoLoopback);
+ return;
+}
+
+
+VOID
+IpxLoopbackEnque(
+ IN PNDIS_PACKET Packet,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ Enqueues a packet to the loopbackQ
+
+Arguments:
+
+ Packet - The packet to be enqueued.
+
+ Context - Pointer to the adapter corresp to the first binding.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ IPX_DEFINE_LOCK_HANDLE(LockHandle)
+
+ //
+ // We use the PaddingBuffer as the next ptr.
+ //
+ Reserved->PaddingBuffer = NULL;
+
+ IPX_GET_LOCK(&LoopLock, &LockHandle);
+
+ //
+ // LoopbackQ is empty
+ //
+ if (LoopXmitHead == (PNDIS_PACKET)NULL) {
+ LoopXmitHead = Packet;
+ } else {
+ Reserved = (PIPX_SEND_RESERVED)(LoopXmitTail->ProtocolReserved);
+ (PNDIS_PACKET)(Reserved->PaddingBuffer) = Packet;
+ }
+ LoopXmitTail = Packet;
+
+ IPX_DEBUG(LOOPB, ("Enqued packet: %lx, Reserved: %lx\n", Packet, Reserved));
+
+ //
+ // If this routine is not already running, schedule it as a work item.
+ //
+ if (!LoopXmitRtnRunning) {
+ CTEScheduleEvent(&LoopXmitEvent, Context);
+ }
+
+ IPX_FREE_LOCK(&LoopLock, LockHandle);
+}
diff --git a/private/ntos/tdi/isn/ipx/mac.c b/private/ntos/tdi/isn/ipx/mac.c
new file mode 100644
index 000000000..a8f2e3b5d
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/mac.c
@@ -0,0 +1,3940 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ mac.c
+
+Abstract:
+
+ This module contains code which implements Mac type dependent code for
+ the IPX transport.
+
+Environment:
+
+ Kernel mode (Actually, unimportant)
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#define TR_LENGTH_MASK 0x1F // low 5 bits in byte
+#define TR_DIRECTION_MASK 0x80 // returns direction bit
+#define TR_DEFAULT_LENGTH 0x70 // default for outgoing
+#define TR_MAX_SIZE_MASK 0x70
+
+#define TR_PREAMBLE_AC 0x10
+#define TR_PREAMBLE_FC 0x40
+
+#define FDDI_HEADER_BYTE 0x57
+
+
+static UCHAR AllRouteSourceRouting[2] = { 0x82, TR_DEFAULT_LENGTH };
+static UCHAR SingleRouteSourceRouting[2] = { 0xc2, TR_DEFAULT_LENGTH };
+
+#define ROUTE_EQUAL(_A,_B) { \
+ (*(UNALIGNED USHORT *)(_A) == *(UNALIGNED USHORT *)(_B)) \
+}
+
+//
+// For back-fillable packets, chains the back-fill space as a MAC header
+// to the packet and sets the header pointer.
+//
+
+//
+// BUGBUG: We dont need to test for IDENTIFIER_IPX since it will always be
+// true for the mediumframe specific send handlers.
+//
+#define BACK_FILL_HEADER(_header, _reserved, _headerlength, _packet) \
+ if ((_reserved)->Identifier == IDENTIFIER_IPX) { \
+ if((_reserved)->BackFill) { \
+ CTEAssert ((_reserved)->HeaderBuffer); \
+ CTEAssert ((_reserved)->HeaderBuffer->MdlFlags & MDL_NETWORK_HEADER); \
+ _header = (PCHAR)(_reserved)->HeaderBuffer->MappedSystemVa - _headerlength; \
+ (_reserved)->HeaderBuffer->MappedSystemVa = (PCHAR)(_reserved)->HeaderBuffer->MappedSystemVa - _headerlength; \
+ (_reserved)->HeaderBuffer->ByteOffset -= _headerlength; \
+ NdisChainBufferAtFront(_packet,(PNDIS_BUFFER)(_reserved)->HeaderBuffer); \
+ } \
+ }
+
+//
+// In case of back-fillable packets, the adjusted length should include
+// the prev. bytecount of the headerbuffer.
+//
+#define BACK_FILL_ADJUST_BUFFER_LENGTH(_reserved, _headerlength) \
+ if((_reserved)->BackFill){ \
+ NdisAdjustBufferLength ((_reserved)->HeaderBuffer, _headerlength+(_reserved)->HeaderBuffer->ByteCount); \
+ IPX_DEBUG(SEND,("mac user mdl %x\n", (_reserved)->HeaderBuffer)); \
+ } else { \
+ NdisAdjustBufferLength ((_reserved)->HeaderBuffer, _headerlength); \
+ }
+
+//
+// This is the interpretation of the length bits in
+// the 802.5 source-routing information.
+//
+
+ULONG SR802_5Lengths[8] = { 516, 1500, 2052, 4472,
+ 8144, 11407, 17800, 17800 };
+
+#ifndef _PNP_POWER
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,MacInitializeMacInfo)
+#endif
+
+#endif
+
+
+VOID
+MacInitializeBindingInfo(
+ IN struct _BINDING * Binding,
+ IN struct _ADAPTER * Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Fills in the binding info based on the adapter's MacInfo
+ and the frame type of the binding.
+
+Arguments:
+
+ Binding - The newly created binding.
+
+ Adapter - The adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG MaxUserData;
+
+ Binding->DefHeaderSize = Adapter->DefHeaderSizes[Binding->FrameType];
+ Binding->BcMcHeaderSize = Adapter->BcMcHeaderSizes[Binding->FrameType];
+
+ MacReturnMaxDataSize(
+ &Adapter->MacInfo,
+ NULL,
+ 0,
+ Binding->MaxSendPacketSize,
+ &MaxUserData);
+
+ Binding->MaxLookaheadData =
+ Adapter->MaxReceivePacketSize -
+ sizeof(IPX_HEADER) -
+ (Binding->DefHeaderSize - Adapter->MacInfo.MinHeaderLength);
+
+ Binding->AnnouncedMaxDatagramSize =
+ MaxUserData -
+ sizeof(IPX_HEADER) -
+ (Binding->DefHeaderSize - Adapter->MacInfo.MinHeaderLength);
+
+ Binding->RealMaxDatagramSize =
+ Binding->MaxSendPacketSize -
+ Adapter->MacInfo.MaxHeaderLength -
+ sizeof(IPX_HEADER) -
+ (Binding->DefHeaderSize - Adapter->MacInfo.MinHeaderLength);
+
+} /* MacInitializeBindingInfo */
+
+
+VOID
+MacInitializeMacInfo(
+ IN NDIS_MEDIUM MacType,
+ OUT PNDIS_INFORMATION MacInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Fills in the MacInfo table based on MacType.
+
+Arguments:
+
+ MacType - The MAC type we wish to decode.
+
+ MacInfo - The MacInfo structure to fill in.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ switch (MacType) {
+ case NdisMedium802_3:
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->MediumAsync = FALSE;
+ MacInfo->BroadcastMask = 0x01;
+ MacInfo->MaxHeaderLength = 14;
+ MacInfo->MinHeaderLength = 14;
+ MacInfo->MediumType = NdisMedium802_3;
+ break;
+ case NdisMedium802_5:
+ MacInfo->SourceRouting = TRUE;
+ MacInfo->MediumAsync = FALSE;
+ MacInfo->BroadcastMask = 0x80;
+ MacInfo->MaxHeaderLength = 32;
+ MacInfo->MinHeaderLength = 14;
+ MacInfo->MediumType = NdisMedium802_5;
+ break;
+ case NdisMediumFddi:
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->MediumAsync = FALSE;
+ MacInfo->BroadcastMask = 0x01;
+ MacInfo->MaxHeaderLength = 13;
+ MacInfo->MinHeaderLength = 13;
+ MacInfo->MediumType = NdisMediumFddi;
+ break;
+ case NdisMediumArcnet878_2:
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->MediumAsync = FALSE;
+ MacInfo->BroadcastMask = 0x00;
+ MacInfo->MaxHeaderLength = 3;
+ MacInfo->MinHeaderLength = 3;
+ MacInfo->MediumType = NdisMediumArcnet878_2;
+ break;
+ case NdisMediumWan:
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->MediumAsync = TRUE;
+ MacInfo->BroadcastMask = 0x01;
+ MacInfo->MaxHeaderLength = 14;
+ MacInfo->MinHeaderLength = 14;
+ MacInfo->MediumType = NdisMedium802_3;
+ break;
+ default:
+ CTEAssert(FALSE);
+ }
+ MacInfo->RealMediumType = MacType;
+
+} /* MacInitializeMacInfo */
+
+
+VOID
+MacMapFrameType(
+ IN NDIS_MEDIUM MacType,
+ IN ULONG FrameType,
+ OUT ULONG * MappedFrameType
+ )
+
+/*++
+
+Routine Description:
+
+ Maps the specified frame type to a value which is
+ valid for the medium.
+
+Arguments:
+
+ MacType - The MAC type we wish to map for.
+
+ FrameType - The frame type in question.
+
+ MappedFrameType - Returns the mapped frame type.
+
+Return Value:
+
+--*/
+
+{
+ switch (MacType) {
+
+ //
+ // Ethernet accepts all values, the default is 802.2.
+ //
+
+ case NdisMedium802_3:
+ if (FrameType >= ISN_FRAME_TYPE_MAX) {
+ *MappedFrameType = ISN_FRAME_TYPE_802_2;
+ } else {
+ *MappedFrameType = FrameType;
+ }
+ break;
+
+ //
+ // Token-ring supports SNAP and 802.2 only.
+ //
+
+ case NdisMedium802_5:
+ if (FrameType == ISN_FRAME_TYPE_SNAP) {
+ *MappedFrameType = ISN_FRAME_TYPE_SNAP;
+ } else {
+ *MappedFrameType = ISN_FRAME_TYPE_802_2;
+ }
+ break;
+
+ //
+ // FDDI supports SNAP, 802.2, and 802.3 only.
+ //
+
+ case NdisMediumFddi:
+ if ((FrameType == ISN_FRAME_TYPE_SNAP) || (FrameType == ISN_FRAME_TYPE_802_3)) {
+ *MappedFrameType = FrameType;
+ } else {
+ *MappedFrameType = ISN_FRAME_TYPE_802_2;
+ }
+ break;
+
+ //
+ // On arcnet there is only one frame type, use 802.3
+ // (it doesn't matter what we use).
+ //
+
+ case NdisMediumArcnet878_2:
+ *MappedFrameType = ISN_FRAME_TYPE_802_3;
+ break;
+
+ //
+ // WAN uses ethernet II because it includes the ethertype.
+ //
+
+ case NdisMediumWan:
+ *MappedFrameType = ISN_FRAME_TYPE_ETHERNET_II;
+ break;
+
+ default:
+ CTEAssert(FALSE);
+ }
+
+} /* MacMapFrameType */
+
+//
+// BUGBUG -- use symbols instead of hardcoded values for mac header lengths
+// --pradeepb
+//
+
+VOID
+MacReturnMaxDataSize(
+ IN PNDIS_INFORMATION MacInfo,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN UINT DeviceMaxFrameSize,
+ OUT PUINT MaxFrameSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the space available for user data in a MAC packet.
+ This will be the available space after the MAC header; all headers
+ headers will be included in this space.
+
+Arguments:
+
+ MacInfo - Describes the MAC we wish to decode.
+
+ SourceRouting - If we are concerned about a reply to a specific
+ frame, then this information is used.
+
+ SourceRouting - The length of SourceRouting.
+
+ MaxFrameSize - The maximum frame size as returned by the adapter.
+
+ MaxDataSize - The maximum data size computed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ switch (MacInfo->MediumType) {
+
+ case NdisMedium802_3:
+
+ //
+ // For 802.3, we always have a 14-byte MAC header.
+ //
+
+ *MaxFrameSize = DeviceMaxFrameSize - 14;
+ break;
+
+ case NdisMedium802_5:
+
+ //
+ // For 802.5, if we have source routing information then
+ // use that, otherwise assume the worst.
+ //
+
+ if (SourceRouting && SourceRoutingLength >= 2) {
+
+ UINT SRLength;
+
+ SRLength = SR802_5Lengths[(SourceRouting[1] & TR_MAX_SIZE_MASK) >> 4];
+ DeviceMaxFrameSize -= (SourceRoutingLength + 14);
+
+ if (DeviceMaxFrameSize < SRLength) {
+ *MaxFrameSize = DeviceMaxFrameSize;
+ } else {
+ *MaxFrameSize = SRLength;
+ }
+
+ } else {
+
+#if 0
+ if (DeviceMaxFrameSize < 608) {
+ *MaxFrameSize = DeviceMaxFrameSize - 32;
+ } else {
+ *MaxFrameSize = 576;
+ }
+#endif
+ //
+ // bug # 6192. There is no point in assuming the worst. It only
+ // leads to lower throughput. Packets can get dropped by an
+ // an intermediate router for both cases (this one and the one
+ // above where 576 is chosen). In the above case, they will
+ // get dropped if two ethernet machines are communicating via
+ // a token ring. In this case, they will if two token ring
+ // machines with a frame size > max ethernet frame size are
+ // going over an ethernet. To fix the packet drop case, one
+ // should adjust the MaxPktSize Parameter of the card.
+ //
+ *MaxFrameSize = DeviceMaxFrameSize - 32;
+ }
+
+ break;
+
+ case NdisMediumFddi:
+
+ //
+ // For FDDI, we always have a 13-byte MAC header.
+ //
+
+ *MaxFrameSize = DeviceMaxFrameSize - 13;
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ //
+ // For Arcnet, we always have a 3-byte MAC header.
+ //
+
+ *MaxFrameSize = DeviceMaxFrameSize - 3;
+ break;
+
+ }
+
+} /* MacReturnMaxDataSize */
+
+#if 0
+
+VOID
+IpxUpdateWanInactivityCounter(
+ IN PBINDING Binding,
+ IN IPX_HEADER UNALIGNED * IpxHeader,
+ IN ULONG IncludedHeaderLength,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a frame is being sent on a WAN
+ line. It updates the inactivity counter for this binding
+ unless:
+
+ - The frame is from the RIP socket
+ - The frame is from the SAP socket
+ - The frame is a netbios keep alive
+ - The frame is an NCP keep alive
+
+ BUGBUG: Take the identifier as a parameter to optimize.
+
+Arguments:
+
+ Binding - The binding the frame is sent on.
+
+ IpxHeader - May contain the first bytes of the packet.
+
+ IncludedHeaderLength - The number of packet bytes at IpxHeader.
+
+ Packet - The full NDIS packet.
+
+ PacketLength - The length of the packet.
+
+Return Value:
+
+ None, but in some cases we return without resetting the
+ inactivity counter.
+
+Comments: THIS FUNCTION IS REAL HACKY AND NEEDS TO BE WORKED AT. WE CAN
+ Improve the instruction count here - pradeepb
+
+--*/
+
+{
+ PNDIS_BUFFER SecondBuffer = NULL;
+ PUCHAR SecondBufferData;
+ UINT SecondBufferLength;
+ USHORT SourceSocket;
+ PNDIS_BUFFER ThirdBuffer = NULL;
+ PUCHAR ThirdBufferData;
+ UINT ThirdBufferLength;
+
+ UNREFERENCED_PARAMETER (PacketLength);
+
+ //
+ // First get the source socket.
+ //
+
+#if 0
+ //
+ // Only time IncludedHeaderLength is less than the offset of
+ // SourceSocket in IPX header is when it 0 (from rip)
+ //
+ if (IncludedHeaderLength <= FIELD_OFFSET (IPX_HEADER, SourceSocket)) {
+#endif
+
+ //
+ // Get the second buffer in the packet (the ipx header is always in
+ // the second buffer - pradeepb.
+ //
+ // In this case
+ // there must be a second buffer or the packet is too
+ // short, so we don't check for NULL.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, &SecondBuffer, NULL);
+ SecondBuffer = NDIS_BUFFER_LINKAGE(SecondBuffer);
+ NdisQueryBuffer (SecondBuffer, (PVOID *)&SecondBufferData, &SecondBufferLength);
+
+ SourceSocket = *(UNALIGNED USHORT *)
+ (&SecondBufferData[FIELD_OFFSET(IPX_HEADER, SourceSocket) - IncludedHeaderLength]);
+
+#if 0
+ }
+else {
+
+ SourceSocket = IpxHeader->SourceSocket;
+ }
+#endif
+ if ((SourceSocket == RIP_SOCKET) ||
+ (SourceSocket == SAP_SOCKET)) {
+
+ return;
+
+ }
+
+ if (SourceSocket == NB_SOCKET) {
+
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ USHORT TotalDataLength;
+
+#if 0
+ //
+ // We assume the connection control flag and data stream type
+ // are in the same buffer.
+ //
+
+ if (IncludedHeaderLength < sizeof(IPX_HEADER) + 2) {
+
+ if (SecondBuffer == NULL) {
+
+ //
+ // Get the second buffer in the packet.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, &SecondBuffer, NULL);
+ SecondBuffer = NDIS_BUFFER_LINKAGE(SecondBuffer);
+ NdisQueryBuffer (ThirdBuffer, (PVOID *)&SecondBufferData, &SecondBufferLength);
+
+ }
+#endif
+
+ ConnectionControlFlag = *(SecondBufferData + (sizeof(IPX_HEADER) - IncludedHeaderLength));
+ DataStreamType = *(SecondBufferData + (sizeof(IPX_HEADER) + 1 - IncludedHeaderLength));
+
+
+#if 0
+ } else {
+
+ ConnectionControlFlag = ((PUCHAR)(IpxHeader+1))[0];
+ DataStreamType = ((PUCHAR)(IpxHeader+1))[1];
+ }
+
+#endif
+
+ //
+ // If this is a SYS packet with or without a request for ACK and
+ // has session data in it.
+ //
+ if (((ConnectionControlFlag == 0x80) || (ConnectionControlFlag == 0xc0)) &&
+ (DataStreamType == 0x06)) {
+
+ //
+ // This would be from the rip driver, if IncludedHeaderLength is
+ // 0. -- pradeepb
+ //
+ // At this point, we assume that total data length is in
+ // the same buffer as the others.
+ //
+ //
+ // real hacky way of doing things. One should be using
+ // FIELD_OFFSET(NB_SESSION, TotalDataLength) instead of 8.
+ // -- pradeepb
+ //
+
+ if (IncludedHeaderLength < sizeof(IPX_HEADER) + 2) {
+ TotalDataLength = *(USHORT UNALIGNED *)(SecondBufferData + (sizeof(IPX_HEADER) + 8 - IncludedHeaderLength));
+ } else {
+ TotalDataLength = ((USHORT UNALIGNED *)(IpxHeader+1))[4];
+ }
+
+ if (TotalDataLength == 0) {
+ return;
+ }
+ }
+
+ } else {
+
+ UCHAR KeepAliveSignature;
+
+
+ //
+ // Now see if it is an NCP keep alive.
+ //
+
+ if (PacketLength == sizeof(IPX_HEADER) + 2) {
+
+ //
+ // if from rip
+ //
+ if (IncludedHeaderLength <= sizeof(IPX_HEADER) + 1) {
+
+
+ //
+ // Get the second buffer
+ //
+#if 0
+ if (SecondBuffer == NULL) {
+
+ //
+ // Get the second buffer in the packet.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, &SecondBuffer, NULL);
+ ThirdBuffer = NDIS_BUFFER_LINKAGE(SecondBuffer);
+ NdisQueryBuffer (ThirdBuffer, (PVOID *)&ThirdBufferData, &ThirdBufferLength);
+
+ }
+#endif
+ KeepAliveSignature = SecondBufferData[sizeof(IPX_HEADER) + 1 - IncludedHeaderLength];
+
+ } else {
+
+ //
+ // will we ever come here - pradeepb?
+ //
+ KeepAliveSignature = SecondBufferData[sizeof(IPX_HEADER) + 1 - IncludedHeaderLength];
+#if 0
+ KeepAliveSignature = ((PUCHAR)(IpxHeader+1))[1];
+#endif
+
+ }
+
+ if ((KeepAliveSignature == '?') ||
+ (KeepAliveSignature == 'Y')) {
+ return;
+ }
+
+ }
+
+ }
+
+ //
+ // This was a normal packet, so reset this.
+ //
+
+ Binding->WanInactivityCounter = 0;
+
+} /* IpxUpdateWanInactivityCounter */
+#endif
+
+
+VOID
+IpxUpdateWanInactivityCounter(
+ IN PBINDING Binding,
+ IN IPX_HEADER UNALIGNED * IpxHeader,
+ IN ULONG IncludedHeaderLength,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a frame is being sent on a WAN
+ line. It updates the inactivity counter for this binding
+ unless:
+
+ - The frame is from the RIP socket
+ - The frame is from the SAP socket
+ - The frame is a netbios keep alive
+ - The frame is an NCP keep alive
+
+ BUGBUG: Take the identifier as a parameter to optimize.
+
+Arguments:
+
+ Binding - The binding the frame is sent on.
+
+ IpxHeader - May contain the first bytes of the packet.
+
+ IncludedHeaderLength - The number of packet bytes at IpxHeader.
+
+ Packet - The full NDIS packet.
+
+ PacketLength - The length of the packet.
+
+Return Value:
+
+ None, but in some cases we return without resetting the
+ inactivity counter.
+
+Comments: Improve the instruction count here - pradeepb
+
+--*/
+
+{
+ USHORT SourceSocket;
+ PNDIS_BUFFER DataBuffer = NULL;
+ PUCHAR DataBufferData;
+ UINT DataBufferLength;
+
+
+ //
+ // First get the source socket.
+ //
+ SourceSocket = IpxHeader->SourceSocket;
+ if ((SourceSocket == RIP_SOCKET) ||
+ (SourceSocket == SAP_SOCKET)) {
+
+ return;
+
+ }
+
+ if (SourceSocket == NB_SOCKET) {
+
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ USHORT TotalDataLength;
+
+ //
+ // ConnectionControlFlag and DataStreamType will always follow
+ // IpxHeader
+ //
+ ConnectionControlFlag = ((PUCHAR)(IpxHeader+1))[0];
+ DataStreamType = ((PUCHAR)(IpxHeader+1))[1];
+
+ //
+ // If this is a SYS packet with or without a request for ACK and
+ // has session data in it.
+ //
+ if (((ConnectionControlFlag == 0x80) || (ConnectionControlFlag == 0xc0)) &&
+ (DataStreamType == 0x06)) {
+
+ //
+ // TotalDataLength is in the same buffer.
+ //
+ TotalDataLength = ((USHORT UNALIGNED *)(IpxHeader+1))[4];
+
+ //
+ // No need to update the WAN activity counter
+ //
+ if (TotalDataLength == 0) {
+ return;
+ }
+ }
+
+ } else {
+
+ UCHAR KeepAliveSignature;
+
+
+ //
+ // Now see if it is an NCP keep alive. It can be from rip or from
+ // NCP on this machine
+ //
+ // NOTE: We cannot come here for an SMB packet - [IsaacHe - 12/15].
+ //
+ if (PacketLength == sizeof(IPX_HEADER) + 2) {
+
+ //
+ // Get the client data buffer
+ //
+ NdisQueryPacket(Packet, NULL, NULL, &DataBuffer, NULL);
+
+ //
+ // If the included header length is 0, it is from rip
+ //
+ if (IncludedHeaderLength == 0) {
+
+ //
+ // Get the second buffer in the packet. The second buffer
+ // contains the IPX header + other stuff
+ //
+ DataBuffer = NDIS_BUFFER_LINKAGE(DataBuffer);
+ } else {
+ //
+ // Get the third buffer in the packet.
+ //
+ DataBuffer = NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE(DataBuffer));
+ }
+
+ NdisQueryBuffer (DataBuffer, (PVOID *)&DataBufferData, &DataBufferLength);
+ CTEAssert(DataBufferData);
+
+ if (IncludedHeaderLength == 0) {
+ KeepAliveSignature = DataBufferData[sizeof(IPX_HEADER) + 1];
+ } else {
+ KeepAliveSignature = DataBufferData[1];
+ }
+
+ if ((KeepAliveSignature == '?') ||
+ (KeepAliveSignature == 'Y')) {
+ return;
+ }
+ }
+ }
+
+
+ //
+ // This was a normal packet, so reset this.
+ //
+
+ Binding->WanInactivityCounter = 0;
+
+} /* IpxUpdateWanInactivityCounter */
+
+#if DBG
+ULONG IpxPadCount = 0;
+#endif
+
+#ifdef _PNP_POWER
+
+NDIS_STATUS
+IpxSendFramePreFwd(
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NB/SPX to send a frame.
+
+Arguments:
+
+ LocalTarget - The local target of the send - NB will have the LocalTarget in the Send_Reserved part
+ of the packet; SPX will not now, but will later.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ Return of IpxSendFrame
+
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ PNDIS_BUFFER HeaderBuffer;
+ PUCHAR IpxHeader;
+ UINT TempHeaderBufferLength;
+ PDEVICE Device = IpxDevice;
+ PIPX_HEADER TempHeader;
+ NTSTATUS ret;
+ BOOLEAN fIterate=FALSE;
+
+ //
+ // Figure out the IpxHeader - it is always at the top of the second MDL.
+ //
+ NdisQueryPacket (Packet, NULL, NULL, &HeaderBuffer, NULL);
+ NdisQueryBuffer (NDIS_BUFFER_LINKAGE(HeaderBuffer), &IpxHeader, &TempHeaderBufferLength);
+
+ //
+ // Set this now, will change later
+ //
+ Reserved->CurrentNicId = 0;
+
+ //
+ // Copy the LocalTarget into the send reserved area of the packet.
+ //
+ Reserved->LocalTarget = *LocalTarget;
+
+ //
+ // If the NicId in the handle is ITERATIVE_NIC_ID, then this could be a send
+ // over all NICs in the case of NB/SPX.
+ //
+ if (NIC_FROM_LOCAL_TARGET(LocalTarget) == (USHORT)ITERATIVE_NIC_ID) {
+ CTEAssert(Reserved->Identifier == IDENTIFIER_NB ||
+ Reserved->Identifier == IDENTIFIER_SPX);
+ //
+ // Start with the first NIC
+ //
+ IPX_DEBUG(SEND, ("Iteration over NICs started, reserved: %lx\n", Reserved));
+ Reserved->CurrentNicId = 1;
+ Reserved->Net0SendSucceeded = FALSE;
+ FILL_LOCAL_TARGET(&Reserved->LocalTarget, 1);
+ Reserved->PacketLength = PacketLength;
+ fIterate = TRUE;
+ }
+
+ //
+ // If the Forwarder is installed, send the packet out for filtering
+ //
+ if (Device->ForwarderBound) {
+ ULONG FwdAdapterContext = INVALID_CONTEXT_VALUE;
+ PBINDING Binding;
+
+ //
+ // Figure out the FwdAdapterContext; if the NicId is 0
+ // then no NicId is specified (since we never return a
+ // NicId of 0 in a FindRoute).
+ //
+
+ //
+ // We need to fix the following problems with respect to type 20 iterative bcasts :
+ // 1. IPX will not bcast on a down WAN line (thus the Fwd cannot bring up a demand-dial line).
+ // 2. IPX bcasts on every Nic (since it is not any wiser about selecting relevant Nics).
+ // 3. If the first bcast fails, the whole send fails.
+ //
+ // All the above (except 3.) occur because the Fwd knows more about the Nics than IPX does; hence
+ // we let the Fwd decide which lines he wants to send a bcast on. Thus, for Type20 pkts, we pass
+ // up the invalid Fwd context so the Fwd decides the next Nic to send on.
+ //
+ if (!((((PIPX_HEADER)IpxHeader)->PacketType == 0x14) && fIterate) &&
+ Reserved->LocalTarget.NicId &&
+ (Binding = NIC_ID_TO_BINDING(Device, Reserved->LocalTarget.NicId)) &&
+ (GET_VALUE(Binding->ReferenceCount) == 2)) {
+ //
+ // If proper NicId specified, and the adapter has been opened by
+ // the forwarder, set the FwdAdapterContext.
+ //
+ FwdAdapterContext = Binding->FwdAdapterContext;
+ }
+#if DBG
+ else {
+ if (((PIPX_HEADER)IpxHeader)->PacketType == 0x14) {
+ IPX_DEBUG(SEND, ("SendComplete: IpxHeader has Type20: %lx\n", IpxHeader));
+ }
+ }
+#endif
+
+ //
+ // Call the InternalSend to filter the packet and get to know
+ // the correct adapter context
+ //
+ ret = (*Device->UpperDrivers[IDENTIFIER_RIP].InternalSendHandler)(
+ &Reserved->LocalTarget,
+ FwdAdapterContext,
+ Packet,
+ IpxHeader,
+ IpxHeader+sizeof(IPX_HEADER), // the data starts after the IPX Header.
+ PacketLength,
+ fIterate);
+
+ if (ret == STATUS_SUCCESS) {
+ //
+ // The adapter could have gone away and we have indicated to the Forwarder
+ // but the Forwarder has not yet closed the adapter.
+ // [ZZ] adapters do not go away now.
+ //
+ // BUGBUG: what if the binding is NULL here? Can we trust the Forwarder to
+ // give us a non-NULL binding?
+ //
+
+ if (GET_VALUE(NIC_ID_TO_BINDING(Device, Reserved->LocalTarget.NicId)->ReferenceCount) == 1) {
+ IPX_DEBUG(SEND, ("IPX: SendFramePreFwd: FWD returned SUCCESS, Ref count is 1\n"));
+ return NDIS_STATUS_SUCCESS;
+ } else {
+
+ //
+ // Fill up the changed LocalTarget for the client except in the ITERATE case.
+ //
+ if (!fIterate) {
+ *LocalTarget = Reserved->LocalTarget;
+ }
+
+ IPX_DEBUG(SEND, ("IPX: SendFramePreFwd: FWD returned SUCCESS, sending out on wire\n"));
+ goto SendPkt;
+ }
+ } else if (ret == STATUS_PENDING) {
+ //
+ // LocalTarget will get filled up in InternalSendComplete
+ //
+ IPX_DEBUG(SEND, ("SendFramePreFwd: FWD returned PENDING\n"));
+ return NDIS_STATUS_PENDING;
+ } else if (ret == STATUS_DROP_SILENTLY) {
+ //
+ // This was a keepalive which the router is spoofing. Drop it silently.
+ //
+ IPX_DEBUG(SEND, ("IPX: SendFramePreFwd: FWD returned STATUS_DROP_SILENTLY - dropping pkt.\n"));
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ //
+ // else DISCARD - this means that either the packet failed the send
+ // or that the preferred NicId was not good.
+ //
+ return STATUS_NETWORK_UNREACHABLE;
+
+ } else {
+
+SendPkt:
+ if (NIC_FROM_LOCAL_TARGET(LocalTarget) == (USHORT)LOOPBACK_NIC_ID) {
+ //
+ // Enque this packet to the LoopbackQueue on the binding.
+ // If the LoopbackRtn is not already scheduled, schedule it.
+ //
+ IPX_DEBUG(LOOPB, ("Mac.c: Packet: %x\n", Packet));
+
+ //
+ // Recalculate packet counts here.
+ // Assume an 802_3802_2 header and use that length.
+ // Adjust the MAC header's length to the right value
+ //
+ NdisAdjustBufferLength (HeaderBuffer, 17);
+ NdisRecalculatePacketCounts (Packet);
+ IpxLoopbackEnque(Packet, NIC_ID_TO_BINDING(Device, 1)->Adapter);
+
+ //
+ // The upper driver waits for the SendComplete.
+ //
+ return STATUS_PENDING;
+ }
+
+ return IpxSendFrame (
+ &Reserved->LocalTarget,
+ Packet,
+ PacketLength,
+ IncludedHeaderLength);
+
+ }
+}
+#endif
+
+
+NDIS_STATUS
+IpxSendFrame(
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ BUGBUG: Check that Binding is not NULL.
+
+Arguments:
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PDEVICE Device = IpxDevice;
+ PUCHAR Header;
+ PBINDING Binding, MasterBinding;
+ PADAPTER Adapter;
+ ULONG TwoBytes;
+ PNDIS_BUFFER HeaderBuffer;
+ UINT TempHeaderBufferLength;
+ ULONG HeaderLength=0;
+ UCHAR SourceRoutingBuffer[18];
+ PUCHAR SourceRouting;
+ ULONG SourceRoutingLength;
+ NDIS_STATUS Status;
+ ULONG BufferLength;
+ UCHAR DestinationType;
+ UCHAR SourceRoutingIdentifier;
+ ULONG HeaderSizeRequired;
+ PIPX_HEADER TempHeader;
+ USHORT PktLength;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+#ifdef SNMP
+//
+// This should not include the forwarded packets; on host side, it is 0.
+// On router, the AdvSysForwPackets are subtracted in the sub-agent code.
+//
+ ++IPX_MIB_ENTRY(Device, SysOutRequests);
+#endif SNMP
+
+ //
+ // Get the lock on the binding array
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_HANDLE_TO_BINDING(Device, &LocalTarget->NicHandle);
+
+ if (Binding == NULL) {
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ IPX_DEBUG(PNP, ("Invalid NIC handle: %lx\n", LocalTarget->NicHandle));
+ //
+ // [BUGBUGZZ] Return a unique error that NB/SPX see and re-query the NicId.
+ //
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysOutMalformedRequests);
+#endif SNMP
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ }
+
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+
+ Adapter = Binding->Adapter;
+
+ IpxReferenceAdapter(Adapter);
+
+ //
+ // Release the lock
+ //
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+
+ //
+ // If this is on the loopback adapter (Nic 0), queue it on the LoopbackQueue;
+ // if the LoopbackRtn is not started, start it now.
+ //
+ if (LocalTarget->NicId == 0) {
+
+ //
+ // Enque this packet to the LoopbackQueue on the binding.
+ // If the LoopbackRtn is not already scheduled, schedule it.
+ //
+
+ IPX_DEBUG(LOOPB, ("Mac.c: Packet: %x\n", Packet));
+
+ //
+ // Assume an 802_3802_2 header and use that length.
+ //
+
+ //
+ // Adjust the MAC header's length to the right value
+ //
+ // NdisAdjustBufferLength (HeaderBuffer, 17);
+
+ NdisRecalculatePacketCounts (Packet);
+
+ IpxLoopbackEnque(Packet, Device->Bindings[1]->Adapter);
+
+ //
+ // The upper driver waits for the SendComplete.
+ //
+ return STATUS_PENDING;
+ }
+
+ Binding = Device->Bindings[LocalTarget->NicId];
+
+ if (Binding == NULL) {
+ return STATUS_DEVICE_DOES_NOT_EXIST; // BUGBUG: Make this a separate switch that generally falls through?
+ }
+ Adapter = Binding->Adapter;
+#endif _PNP_POWER
+
+ //
+ // For IPX and other protocols that are guaranteed to have allocated
+ // the header from non-paged pool, use the buffer directly. For others,
+ // query the packet for the pointer to the MDL.
+ //
+ if (Reserved->Identifier >= IDENTIFIER_IPX) {
+ HeaderBuffer = Reserved->HeaderBuffer;
+ Header = Reserved->Header;
+
+ } else {
+ NdisQueryPacket (Packet, NULL, NULL, &HeaderBuffer, NULL);
+ NdisQueryBuffer(HeaderBuffer, &Header, &TempHeaderBufferLength);
+ }
+
+ CTEAssert (Reserved->PaddingBuffer == NULL);
+
+ //
+ // First move the packet around if needed.
+ //
+
+ if (Reserved->Identifier < IDENTIFIER_IPX) {
+
+ //
+ // Only RIP will have IncludedHeaderLength as 0. I don't know
+ // why we have the comment about RIP inside this if statement.
+ //
+ if (IncludedHeaderLength > 0) {
+
+ //
+ // Spx can handle a virtual net as long as it is
+ // not 0. Netbios always needs to use the real address.
+ // We need to hack the ipx source address for packets
+ // which are sent by spx if we have a fake virtual
+ // net, and packets sent by netbios unless we are
+ // bound to only one card.
+ //
+
+ //
+ // We handle binding sets as follows, based on who
+ // sent the frame to us:
+ //
+ // RIP: Since we only tell RIP about the masters at
+ // bind time, and hide slaves on indications, it should
+ // never be sending on a slave binding. Since RIP knows
+ // the real net and node of every binding we don't
+ // need to modify the packet at all.
+ //
+ // NB: For broadcasts we want to put the first card's
+ // address in the IPX source but round-robin the
+ // actual sends over all cards (broadcasts shouldn't
+ // be passed in with a slave's NIC ID). For directed
+ // packets, which may come in on a slave, we should
+ // put the slave's address in the IPX source.
+ //
+ // SPX: SPX does not send broadcasts. For directed
+ // frames we want to use the slave's net and node
+ // in the IPX source.
+ //
+
+ if (Reserved->Identifier == IDENTIFIER_NB) {
+
+ CTEAssert (IncludedHeaderLength >= sizeof(IPX_HEADER));
+
+ //
+ // Get the packet length from the ipx header. Compare with
+ // the max. allowed datagram size.
+ //
+ TempHeader = (PIPX_HEADER)(&Header[Device->IncludedHeaderOffset]);
+ PktLength = ((TempHeader->PacketLength[0] << 8) |
+ (TempHeader->PacketLength[1]));
+
+//
+// BUGBUG - Not the most efficient way to do this. NWLNKNB should do this.
+// Doing it in ipx means doing it for all packets (even those sent on
+// connections). Will remove this later when nwlnknb change has been
+// tested.
+//
+
+
+ if (PktLength > (Binding->AnnouncedMaxDatagramSize + sizeof(IPX_HEADER))) {
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ PktLength,
+ Binding->AnnouncedMaxDatagramSize + sizeof(IPX_HEADER)));
+
+#ifdef _PNP_POWER
+ //
+ // Dereference the binding and adapter
+ //
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxDereferenceAdapter(Adapter);
+#endif _PNP_POWER
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysOutMalformedRequests);
+#endif SNMP
+ return STATUS_INVALID_BUFFER_SIZE;
+ }
+
+ if (Device->ValidBindings > 1) {
+
+
+ //
+ // Store this now, since even if we round-robin the
+ // actual send we want the binding set master's net
+ // and node in the IPX source address.
+ //
+
+ *(UNALIGNED ULONG *)TempHeader->SourceNetwork = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory (TempHeader->SourceNode, Binding->LocalAddress.NodeAddress, 6);
+
+ if (Binding->BindingSetMember) {
+
+ if (IPX_NODE_BROADCAST(LocalTarget->MacAddress)) {
+
+ //
+ // This is a broadcast, so we round-robin the
+ // sends through the binding set.
+ //
+#ifdef _PNP_POWER
+ //
+ // [BUGBUGZZ]: We dont have a lock here - the masterbinding could be bogus
+ //
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxDereferenceAdapter(Adapter);
+#endif
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+ Adapter = Binding->Adapter;
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxReferenceAdapter(Adapter);
+#endif
+ }
+
+ }
+ }
+
+ //
+ // [STEFANS]: Replace all source addresses with the virtualnet# to allow for sends
+ // on 0 network number WAN lines (typically between routers).
+ //
+ if (Device->VirtualNetwork) {
+ *(UNALIGNED ULONG *)TempHeader->SourceNetwork = Device->SourceAddress.NetworkAddress;
+ RtlCopyMemory (TempHeader->SourceNode, Device->SourceAddress.NodeAddress, 6);
+ }
+
+ } else if (Reserved->Identifier == IDENTIFIER_SPX) {
+
+ //
+ // Need to update this if we have multiple cards but
+ // a zero virtual net.
+ //
+
+ if (Device->MultiCardZeroVirtual) {
+
+ CTEAssert (IncludedHeaderLength >= sizeof(IPX_HEADER));
+
+ TempHeader = (PIPX_HEADER)(&Header[Device->IncludedHeaderOffset]);
+
+ *(UNALIGNED ULONG *)TempHeader->SourceNetwork = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory (TempHeader->SourceNode, Binding->LocalAddress.NodeAddress, 6);
+
+ }
+
+ } else {
+
+ //
+ // For a rip packet it should not be in a binding set,
+ // or if it is it should be the master.
+ //
+#if DBG
+ CTEAssert ((!Binding->BindingSetMember) ||
+ (Binding->CurrentSendBinding));
+#endif
+ }
+
+
+#if 0
+ //
+ // There is a header included, we need to adjust it.
+ // The header will be at Device->IncludedHeaderOffset.
+ //
+
+ if (LocalTarget->MacAddress[0] & Adapter->MacInfo.BroadcastMask) {
+ HeaderSizeRequired = Adapter->BcMcHeaderSizes[Binding->FrameType];
+ } else {
+ HeaderSizeRequired = Adapter->DefHeaderSizes[Binding->FrameType];
+ }
+
+ if (HeaderSizeRequired != Device->IncludedHeaderOffset) {
+
+ RtlMoveMemory(
+ &Header[HeaderSizeRequired],
+ &Header[Device->IncludedHeaderOffset],
+ IncludedHeaderLength);
+ }
+#endif
+ }
+ }
+
+
+
+ switch (Adapter->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+
+ //
+ // [FW] This will allow both LINE_UP and LINE_CONFIG states
+ //
+ if (!Binding->LineUp) {
+ //
+ // Bug #17273 return proper error message
+ //
+ // return STATUS_DEVICE_DOES_NOT_EXIST; // BUGBUG: Make this a separate switch that generally falls through?
+#ifdef _PNP_POWER
+ //
+ // Derefernce the binding and adapter
+ //
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxDereferenceAdapter(Adapter);
+#endif _PNP_POWER
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysOutDiscards);
+#endif SNMP
+ return STATUS_NETWORK_UNREACHABLE;
+ }
+
+ if (Adapter->MacInfo.MediumAsync) {
+
+ IPX_HEADER UNALIGNED * IpxHeader;
+ PNDIS_BUFFER IpxNdisBuff;
+ UINT IpxHeaderLen;
+
+#if 0
+ //
+ // The header should have been moved here.
+ //
+
+ CTEAssert(Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] ==
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II]);
+
+
+ IpxHeader = (IPX_HEADER UNALIGNED *)
+ (&Header[Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II]]);
+#endif
+ //
+ // The Ipx header is always the second ndis buffer in the mdl
+ // chain. Get it and then query the va of the same.
+ //
+ IpxNdisBuff = NDIS_BUFFER_LINKAGE(HeaderBuffer);
+ NdisQueryBuffer (IpxNdisBuff, (PVOID *)&IpxHeader, &IpxHeaderLen);
+// IpxHeader = (IPX_HEADER UNALIGNED *) (&Header[MAC_HEADER_SIZE]);
+
+ //
+ // If this is a type 20 name frame from Netbios and we are
+ // on a dialin WAN line, drop it if configured to.
+ //
+ // The 0x01 bit of DisableDialinNetbios controls
+ // internal->WAN packets, which we handle here.
+ //
+ //
+
+ //
+ // SS# 33592: In case of iterative sends, the IncludedHeaderLength is not set properly
+ // since we dont keep track of the length that came in the first time (we track the PacketLength
+ // however). The included length field is used here for checking for NB_NAME_FRAMES, but elsewhere
+ // used only to distinguish between whether RIP or NB/SPX sent the packet (IncludedHeaderLen ==0 for RIP)
+ // The ideal solution here is to do way with this field altogether, but for the beta we will just use the
+ // PacketLength field for comparison here since we are assured that this will be equal to the InclHeaderLen
+ // for any type 0x14 packet that comes down from NB.
+ //
+ // BUGBUGZZ: Remove the IncludedHeaderLength field.
+ //
+
+ //
+ // [FW] do this only if the forwarder is not bound
+ //
+ if (!Device->ForwarderBound &&
+ (!Binding->DialOutAsync) &&
+ (Reserved->Identifier == IDENTIFIER_NB) &&
+ // (IncludedHeaderLength == sizeof(IPX_HEADER) + 50) && // 50 == sizeof(NB_NAME_FRAME)
+ (PacketLength == sizeof(IPX_HEADER) + 50) && // 50 == sizeof(NB_NAME_FRAME)
+ ((Device->DisableDialinNetbios & 0x01) != 0) &&
+ (IpxHeader->PacketType == 0x14)) {
+#ifdef _PNP_POWER
+ //
+ // Derefernce the binding and adapter
+ //
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxDereferenceAdapter(Adapter);
+#endif _PNP_POWER
+ return STATUS_SUCCESS;
+ }
+
+
+ //
+ // We do checks to see if we should reset the inactivity
+ // counter. We normally need to check for netbios
+ // session alives, packets from rip, packets from
+ // sap, and ncp keep alives. In fact sap and ncp
+ // packets don't come through here.
+ //
+
+ IpxUpdateWanInactivityCounter(
+ Binding,
+ IpxHeader,
+ IncludedHeaderLength,
+ Packet,
+ PacketLength);
+
+
+ //
+ // In order for loopback to work properly, we need to put the local MAC address for locally destined
+ // pkts so NdisWAN can loop them back.
+ //
+ if (IPX_NODE_EQUAL(LocalTarget->MacAddress, Binding->LocalAddress.NodeAddress)) {
+ RtlCopyMemory (Header, Binding->LocalMacAddress.Address, 6);
+ } else {
+ RtlCopyMemory (Header, Binding->RemoteMacAddress.Address, 6);
+ }
+
+ } else {
+
+ RtlCopyMemory (Header, LocalTarget->MacAddress, 6);
+ }
+
+ RtlCopyMemory (Header+6, Binding->LocalMacAddress.Address, 6);
+
+ switch (Binding->FrameType) {
+
+ case ISN_FRAME_TYPE_802_2:
+ TwoBytes = PacketLength + 3;
+ Header[14] = 0xe0;
+ Header[15] = 0xe0;
+ Header[16] = 0x03;
+ HeaderLength = 17;
+ break;
+ case ISN_FRAME_TYPE_802_3:
+ TwoBytes = PacketLength;
+ HeaderLength = 14;
+ break;
+ case ISN_FRAME_TYPE_ETHERNET_II:
+ TwoBytes = Adapter->BindSap;
+ HeaderLength = 14;
+ break;
+ case ISN_FRAME_TYPE_SNAP:
+ TwoBytes = PacketLength + 8;
+ Header[14] = 0xaa;
+ Header[15] = 0xaa;
+ Header[16] = 0x03;
+ Header[17] = 0x00;
+ Header[18] = 0x00;
+ Header[19] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[20]) = Adapter->BindSapNetworkOrder;
+ HeaderLength = 22;
+ break;
+ }
+
+ Header[12] = (UCHAR)(TwoBytes / 256);
+ Header[13] = (UCHAR)(TwoBytes % 256);
+
+ //BufferLength = IncludedHeaderLength + HeaderLength;
+ BufferLength = HeaderLength;
+
+ //
+ // Pad odd-length packets if needed.
+ //
+
+ if ((((PacketLength + HeaderLength) & 1) != 0) &&
+ (Device->EthernetPadToEven) &&
+ (!Adapter->MacInfo.MediumAsync)) {
+
+ PNDIS_BUFFER CurBuffer;
+ PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer;
+ UINT Offset;
+ UINT LastBufferLength;
+
+ //
+ // Find the tail of the current packet.
+ //
+
+ CurBuffer = HeaderBuffer;
+ while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) {
+ CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer);
+ }
+
+ //
+ // If the last byte of the last NDIS_BUFFER is not at the end of
+ // the page, then we can simply increase the NDIS_BUFFER ByteCount
+ // by one.
+ // Otherwise, we must use the global padding buffer.
+ //
+
+ NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength );
+
+ if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0) {
+ if ( CurBuffer == HeaderBuffer ) {
+ BufferLength++; // Just bump this length
+ } else {
+ NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) );
+
+ Reserved->PreviousTail = NULL;
+ Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer;
+ }
+
+ } else {
+
+ CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL);
+
+ Reserved->PreviousTail = CurBuffer;
+ NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer;
+ Reserved->PaddingBuffer = PaddingBuffer;
+
+ }
+
+ if (TwoBytes != Adapter->BindSap) {
+ CTEAssert(TwoBytes & 1);
+ TwoBytes += 1;
+ Header[12] = (UCHAR)(TwoBytes / 256);
+ Header[13] = (UCHAR)(TwoBytes % 256);
+ }
+
+#if DBG
+ ++IpxPadCount;
+#endif
+ }
+
+ break;
+
+ case NdisMedium802_5:
+
+ if (Reserved->Identifier >= IDENTIFIER_IPX) {
+
+ DestinationType = Reserved->DestinationType;
+ SourceRoutingIdentifier = IDENTIFIER_IPX;
+
+ } else {
+
+ if (LocalTarget->MacAddress[0] & 0x80) {
+ if (*(UNALIGNED ULONG *)(&LocalTarget->MacAddress[2]) != 0xffffffff) {
+ DestinationType = DESTINATION_MCAST;
+ } else {
+ DestinationType = DESTINATION_BCAST;
+ }
+ } else {
+ DestinationType = DESTINATION_DEF;
+ }
+ SourceRoutingIdentifier = Reserved->Identifier;
+
+ }
+
+ if (DestinationType == DESTINATION_DEF) {
+
+ MacLookupSourceRouting(
+ SourceRoutingIdentifier,
+ Binding,
+ LocalTarget->MacAddress,
+ SourceRoutingBuffer,
+ &SourceRoutingLength);
+
+ if (SourceRoutingLength != 0) {
+
+// PUCHAR IpxHeader = Header + Binding->DefHeaderSize;
+ PUCHAR IpxHeader = Header + MAC_HEADER_SIZE;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ SourceRouting = SourceRoutingBuffer;
+// RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+
+ } else {
+
+ //
+ // For these packets we assume that the header is in the
+ // right place.
+ //
+
+ if (!Adapter->SourceRouting) {
+
+ SourceRoutingLength = 0;
+
+ } else {
+
+ if (DestinationType == DESTINATION_BCAST) {
+
+ if (Binding->AllRouteBroadcast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ } else {
+
+ CTEAssert (DestinationType == DESTINATION_MCAST);
+
+ if (Binding->AllRouteMulticast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ }
+ }
+
+#if 0
+ if (SourceRoutingLength != 0) {
+
+ // PUCHAR IpxHeader = Header + Binding->BcMcHeaderSize;
+ PUCHAR IpxHeader = Header + MAC_HEADER_SIZE;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+#endif
+
+ }
+
+ Header[0] = TR_PREAMBLE_AC;
+ Header[1] = TR_PREAMBLE_FC;
+ RtlCopyMemory (Header+2, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+8, Binding->LocalMacAddress.Address, 6);
+
+ if (SourceRoutingLength != 0) {
+ Header[8] |= TR_SOURCE_ROUTE_FLAG;
+ RtlCopyMemory (Header+14, SourceRouting, SourceRoutingLength);
+ }
+
+ Header += (14 + SourceRoutingLength);
+
+ switch (Binding->FrameType) {
+ case ISN_FRAME_TYPE_802_2:
+ case ISN_FRAME_TYPE_802_3:
+ case ISN_FRAME_TYPE_ETHERNET_II:
+ Header[0] = 0xe0;
+ Header[1] = 0xe0;
+ Header[2] = 0x03;
+ HeaderLength = 17;
+ break;
+ case ISN_FRAME_TYPE_SNAP:
+ Header[0] = 0xaa;
+ Header[1] = 0xaa;
+ Header[2] = 0x03;
+ Header[3] = 0x00;
+ Header[4] = 0x00;
+ Header[5] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[6]) = Adapter->BindSapNetworkOrder;
+ HeaderLength = 22;
+ break;
+ }
+
+// BufferLength = IncludedHeaderLength + HeaderLength + SourceRoutingLength;
+ BufferLength = HeaderLength + SourceRoutingLength;
+
+ break;
+
+ case NdisMediumFddi:
+
+ Header[0] = FDDI_HEADER_BYTE;
+ RtlCopyMemory (Header+1, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+7, Binding->LocalMacAddress.Address, 6);
+
+ switch (Binding->FrameType) {
+ case ISN_FRAME_TYPE_802_3:
+ HeaderLength = 13;
+ break;
+ case ISN_FRAME_TYPE_802_2:
+ case ISN_FRAME_TYPE_ETHERNET_II:
+ Header[13] = 0xe0;
+ Header[14] = 0xe0;
+ Header[15] = 0x03;
+ HeaderLength = 16;
+ break;
+ case ISN_FRAME_TYPE_SNAP:
+ Header[13] = 0xaa;
+ Header[14] = 0xaa;
+ Header[15] = 0x03;
+ Header[16] = 0x00;
+ Header[17] = 0x00;
+ Header[18] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[19]) = Adapter->BindSapNetworkOrder;
+ HeaderLength = 21;
+ break;
+ }
+
+// BufferLength = IncludedHeaderLength + HeaderLength;
+ BufferLength = HeaderLength;
+
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ //
+ // Convert broadcast address to 0 (the arcnet broadcast).
+ //
+
+ Header[0] = Binding->LocalMacAddress.Address[5];
+ if (LocalTarget->MacAddress[5] == 0xff) {
+ Header[1] = 0x00;
+ } else {
+ Header[1] = LocalTarget->MacAddress[5];
+ }
+ Header[2] = ARCNET_PROTOCOL_ID;
+
+ //
+ // Binding->FrameType is not used.
+ //
+
+ HeaderLength = 3;
+// BufferLength = IncludedHeaderLength + HeaderLength;
+ BufferLength = HeaderLength;
+
+ break;
+
+ }
+
+ //
+ // Adjust the MAC header's length to the right value
+ //
+ NdisAdjustBufferLength (HeaderBuffer, BufferLength);
+ NdisRecalculatePacketCounts (Packet);
+
+#if 0
+ {
+ PMDL mdl;
+ mdl = (PMDL)NDIS_BUFFER_LINKAGE(HeaderBuffer);
+ if (mdl) {
+
+ KdPrint(("**Bytecount %x %x\n",mdl->ByteCount, mdl));
+ if ((LONG)mdl->ByteCount < 0) {
+ DbgBreakPoint();
+ }
+ }
+ }
+#endif
+
+#if DBG
+ {
+ ULONG SendFlag;
+ ULONG Temp;
+ PNDIS_BUFFER FirstPacketBuffer;
+ PNDIS_BUFFER SecondPacketBuffer;
+ IPX_HEADER DumpHeader;
+ UCHAR DumpData[14];
+
+ NdisQueryPacket (Packet, NULL, NULL, &FirstPacketBuffer, NULL);
+ SecondPacketBuffer = NDIS_BUFFER_LINKAGE(FirstPacketBuffer);
+ TdiCopyMdlToBuffer(SecondPacketBuffer, 0, &DumpHeader, 0, sizeof(IPX_HEADER), &Temp);
+ if (Reserved->Identifier == IDENTIFIER_NB) {
+ SendFlag = IPX_PACKET_LOG_SEND_NB;
+ } else if (Reserved->Identifier == IDENTIFIER_SPX) {
+ SendFlag = IPX_PACKET_LOG_SEND_SPX;
+ } else if (Reserved->Identifier == IDENTIFIER_RIP) {
+ SendFlag = IPX_PACKET_LOG_SEND_RIP;
+ } else {
+ if (DumpHeader.SourceSocket == IpxPacketLogSocket) {
+ SendFlag = IPX_PACKET_LOG_SEND_SOCKET | IPX_PACKET_LOG_SEND_OTHER;
+ } else {
+ SendFlag = IPX_PACKET_LOG_SEND_OTHER;
+ }
+ }
+
+#if 0
+ if (PACKET_LOG(SendFlag)) {
+
+ TdiCopyMdlToBuffer(SecondPacketBuffer, sizeof(IPX_HEADER), &DumpData, 0, 14, &Temp);
+
+ IpxLogPacket(
+ TRUE,
+ LocalTarget->MacAddress,
+ Binding->LocalMacAddress.Address,
+ (USHORT)PacketLength,
+ &DumpHeader,
+ DumpData);
+
+ }
+#endif
+ }
+#endif
+
+ ++Device->Statistics.PacketsSent;
+
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+#ifdef _PNP_POWER
+ if (Status != STATUS_PENDING) {
+
+ if (Reserved->PaddingBuffer) {
+
+ //
+ // Remove padding if it was done.
+ //
+
+ if ( Reserved->PreviousTail ) {
+ NDIS_BUFFER_LINKAGE (Reserved->PreviousTail) = (PNDIS_BUFFER)NULL;
+ } else {
+ PNDIS_BUFFER LastBuffer = (PNDIS_BUFFER)Reserved->PaddingBuffer;
+ UINT LastBufferLength;
+
+ NdisQueryBuffer( LastBuffer, NULL, &LastBufferLength );
+ NdisAdjustBufferLength( LastBuffer, (LastBufferLength - 1) );
+#if DBG
+ if ((Reserved->Identifier == IDENTIFIER_RIP) &&
+ (LastBufferLength == 1500)) {
+ DbgPrint("Packet: %lx\n", Packet);
+ DbgBreakPoint();
+ }
+#endif DBG
+ }
+
+ Reserved->PaddingBuffer = NULL;
+
+ if (Reserved->Identifier < IDENTIFIER_IPX) {
+ NdisRecalculatePacketCounts (Packet);
+ }
+ }
+
+ //
+ // If this was an NB/SPX packet, and there was an
+ // iterative send going on, then call the SendComplete
+ // handler.
+ //
+ if ((Reserved->Identifier == IDENTIFIER_NB ||
+ Reserved->Identifier == IDENTIFIER_SPX) &&
+ (Reserved->CurrentNicId)) {
+
+ IpxSendComplete(
+ (NDIS_HANDLE)Binding->Adapter,
+ Packet,
+ Status);
+
+ Status = STATUS_PENDING;
+ }
+ }
+#else
+ if ((Status != STATUS_PENDING) &&
+ (Reserved->PaddingBuffer)) {
+
+ //
+ // Remove padding if it was done.
+ //
+
+ if ( Reserved->PreviousTail ) {
+ NDIS_BUFFER_LINKAGE (Reserved->PreviousTail) = (PNDIS_BUFFER)NULL;
+ } else {
+ PNDIS_BUFFER LastBuffer = (PNDIS_BUFFER)Reserved->PaddingBuffer;
+ UINT LastBufferLength;
+
+ NdisQueryBuffer( LastBuffer, NULL, &LastBufferLength );
+ NdisAdjustBufferLength( LastBuffer, (LastBufferLength - 1) );
+ }
+
+ Reserved->PaddingBuffer = NULL;
+
+ if (Reserved->Identifier < IDENTIFIER_IPX) {
+ NdisRecalculatePacketCounts (Packet);
+ }
+ }
+#endif
+
+#ifdef _PNP_POWER
+ //
+ // Derefernce the binding and adapter
+ //
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxDereferenceAdapter(Adapter);
+#endif _PNP_POWER
+
+ return Status;
+
+} /* IpxSendFrame */
+
+
+NDIS_STATUS
+IpxSendFrame802_3802_3(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_3 FRAMES IN
+ THE ISN_FRAME_TYPE_802_3 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+ //
+ // BUGBUG: Remove the IncludedHeaderLength parameter from here
+ //
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+ LONG HeaderLength;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 14, Packet);
+ IPX_DEBUG(SEND,("Backfill request 802_3802_3!! %x %x %x\n", Packet, Reserved, Reserved->HeaderBuffer));
+#endif
+
+ RtlCopyMemory (Header, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+6, Adapter->LocalMacAddress.Address, 6);
+
+ //
+ // Pad odd-length packets if needed.
+ //
+
+ if (((PacketLength & 1) != 0) &&
+ (IpxDevice->EthernetPadToEven)) {
+
+ PNDIS_BUFFER CurBuffer;
+ PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer;
+ UINT Offset;
+ UINT LastBufferLength;
+
+ //
+ // Find the tail of the current packet.
+ //
+
+ CurBuffer = Reserved->HeaderBuffer;
+ while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) {
+ CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer);
+ }
+
+ //
+ // If the last byte of the last NDIS_BUFFER is not at the end of
+ // the page, then we can simply increase the NDIS_BUFFER ByteCount
+ // by one.
+ // Otherwise, we must use the global padding buffer.
+ //
+
+ NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength );
+
+ if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0) {
+#if BACK_FILL
+ if (0) {
+
+#else
+ if ( CurBuffer == Reserved->HeaderBuffer ) {
+ IncludedHeaderLength++; // Just bump this length
+#endif
+ } else {
+ NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) );
+
+ Reserved->PreviousTail = NULL;
+ Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer;
+ }
+
+ } else {
+
+ CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL);
+
+ Reserved->PreviousTail = CurBuffer;
+ NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer;
+ Reserved->PaddingBuffer = PaddingBuffer;
+
+ }
+
+ ++PacketLength;
+#if DBG
+ ++IpxPadCount;
+#endif
+
+ }
+
+ Header[12] = (UCHAR)(PacketLength / 256);
+ Header[13] = (UCHAR)(PacketLength % 256);
+
+ //NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 14);
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 14);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 14);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_3802_3 */
+
+
+NDIS_STATUS
+IpxSendFrame802_3802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_3 FRAMES IN
+ THE ISN_FRAME_TYPE_802_2 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ ULONG TwoBytes;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 17, Packet);
+ IPX_DEBUG(SEND, ("Backfill request 802_3802_3!! %x %x %x\n", Packet, Reserved, Reserved->HeaderBuffer));
+ IPX_DEBUG(SEND, ("packet=%x, usermdl %x\n",Packet,Reserved->HeaderBuffer));
+#endif
+
+ RtlCopyMemory (Header, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+6, Adapter->LocalMacAddress.Address, 6);
+
+ TwoBytes = PacketLength + 3;
+ Header[14] = 0xe0;
+ Header[15] = 0xe0;
+ Header[16] = 0x03;
+
+ //
+ // Pad odd-length packets if needed.
+ //
+
+ if (((PacketLength & 1) == 0) &&
+ (IpxDevice->EthernetPadToEven)) {
+
+ PNDIS_BUFFER CurBuffer;
+ PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer;
+ UINT Offset;
+ UINT LastBufferLength;
+
+ //
+ // Find the tail of the current packet.
+ //
+
+ CurBuffer = Reserved->HeaderBuffer;
+ while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) {
+ CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer);
+ }
+
+ //
+ // If the last byte of the last NDIS_BUFFER is not at the end of
+ // the page, then we can simply increase the NDIS_BUFFER ByteCount
+ // by one.
+ // Otherwise, we must use the global padding buffer.
+ //
+
+ NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength );
+
+ if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0 ) {
+#if BACK_FILL
+ if (0) {
+#else
+ if ( CurBuffer == Reserved->HeaderBuffer ) {
+
+ IncludedHeaderLength++; // Just bump this length
+#endif
+ } else {
+ NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) );
+
+ Reserved->PreviousTail = NULL;
+ Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer;
+ }
+
+ } else {
+
+ CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL);
+
+ Reserved->PreviousTail = CurBuffer;
+ NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer;
+ Reserved->PaddingBuffer = PaddingBuffer;
+
+ }
+
+ ++TwoBytes;
+#if DBG
+ ++IpxPadCount;
+#endif
+
+ }
+
+ Header[12] = (UCHAR)(TwoBytes / 256);
+ Header[13] = (UCHAR)(TwoBytes % 256);
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 17);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 17);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 17);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_3802_2 */
+
+
+NDIS_STATUS
+IpxSendFrame802_3EthernetII(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_3 FRAMES IN
+ THE ISN_FRAME_TYPE_ETHERNET_II FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 14, Packet);
+#endif BACK_FILL
+
+ RtlCopyMemory (Header, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+6, Adapter->LocalMacAddress.Address, 6);
+
+ *(UNALIGNED USHORT *)(&Header[12]) = Adapter->BindSapNetworkOrder;
+
+ //
+ // Pad odd-length packets if needed.
+ //
+
+ if (((PacketLength & 1) != 0) &&
+ (IpxDevice->EthernetPadToEven)) {
+
+ PNDIS_BUFFER CurBuffer;
+ PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer;
+ UINT Offset;
+ UINT LastBufferLength;
+
+ //
+ // Find the tail of the current packet.
+ //
+
+ CurBuffer = Reserved->HeaderBuffer;
+ while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) {
+ CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer);
+ }
+
+ //
+ // If the last byte of the last NDIS_BUFFER is not at the end of
+ // the page, then we can simply increase the NDIS_BUFFER ByteCount
+ // by one.
+ // Otherwise, we must use the global padding buffer.
+ //
+
+ NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength );
+
+ if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0) {
+
+#if BACK_FILL
+ if (0) {
+
+#else
+ if ( CurBuffer == Reserved->HeaderBuffer ) {
+ IncludedHeaderLength++; // Just bump this length
+#endif
+ } else {
+ NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) );
+
+ Reserved->PreviousTail = NULL;
+ Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer;
+ }
+
+ } else {
+
+ CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL);
+
+ Reserved->PreviousTail = CurBuffer;
+ NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer;
+ Reserved->PaddingBuffer = PaddingBuffer;
+
+ }
+
+#if DBG
+ ++IpxPadCount;
+#endif
+
+ }
+
+ // NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 14);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 14);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 14);
+#endif
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_3EthernetII */
+
+
+NDIS_STATUS
+IpxSendFrame802_3Snap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_3 FRAMES IN
+ THE ISN_FRAME_TYPE_SNAP FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ ULONG TwoBytes;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 22, Packet);
+#endif BACK_FILL
+
+ RtlCopyMemory (Header, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+6, Adapter->LocalMacAddress.Address, 6);
+
+ TwoBytes = PacketLength + 8;
+ Header[14] = 0xaa;
+ Header[15] = 0xaa;
+ Header[16] = 0x03;
+ Header[17] = 0x00;
+ Header[18] = 0x00;
+ Header[19] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[20]) = Adapter->BindSapNetworkOrder;
+
+ //
+ // Pad odd-length packets if needed.
+ //
+
+ if (((PacketLength & 1) == 0) &&
+ (IpxDevice->EthernetPadToEven)) {
+
+ PNDIS_BUFFER CurBuffer;
+ PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer;
+ UINT Offset;
+ UINT LastBufferLength;
+
+ //
+ // Find the tail of the current packet.
+ //
+
+ CurBuffer = Reserved->HeaderBuffer;
+ while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) {
+ CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer);
+ }
+
+ //
+ // If the last byte of the last NDIS_BUFFER is not at the end of
+ // the page, then we can simply increase the NDIS_BUFFER ByteCount
+ // by one.
+ // Otherwise, we must use the global padding buffer.
+ //
+
+ NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength );
+
+ if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0) {
+
+#if BACK_FILL
+ if (0) {
+
+#else
+ if ( CurBuffer == Reserved->HeaderBuffer ) {
+ IncludedHeaderLength++; // Just bump this length
+#endif
+ } else {
+ NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) );
+
+ Reserved->PreviousTail = NULL;
+ Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer;
+ }
+
+ } else {
+
+ CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL);
+
+ Reserved->PreviousTail = CurBuffer;
+ NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer;
+ Reserved->PaddingBuffer = PaddingBuffer;
+
+ }
+
+ ++TwoBytes;
+#if DBG
+ ++IpxPadCount;
+#endif
+
+ }
+
+ Header[12] = (UCHAR)(TwoBytes / 256);
+ Header[13] = (UCHAR)(TwoBytes % 256);
+
+ // NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 22);
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 22);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 22);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_3Snap */
+
+
+NDIS_STATUS
+IpxSendFrame802_5802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_5 FRAMES IN
+ THE ISN_FRAME_TYPE_802_2 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PBINDING Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_2];
+ PUCHAR Header;
+ ULONG HeaderLength;
+ UCHAR SourceRoutingBuffer[18];
+ PUCHAR SourceRouting;
+ ULONG SourceRoutingLength;
+ NDIS_STATUS Status;
+ ULONG BufferLength;
+ UCHAR DestinationType;
+
+ Header = Reserved->Header;
+
+ DestinationType = Reserved->DestinationType;
+
+ if (DestinationType == DESTINATION_DEF) {
+
+ MacLookupSourceRouting(
+ Reserved->Identifier,
+ Binding,
+ LocalTarget->MacAddress,
+ SourceRoutingBuffer,
+ &SourceRoutingLength);
+
+ if (SourceRoutingLength != 0) {
+
+ //PUCHAR IpxHeader = Header + Binding->DefHeaderSize;
+ PUCHAR IpxHeader = Header + MAC_HEADER_SIZE;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ SourceRouting = SourceRoutingBuffer;
+// RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+
+ } else {
+
+ //
+ // For these packets we assume that the header is in the
+ // right place.
+ //
+
+ if (!Adapter->SourceRouting) {
+
+ SourceRoutingLength = 0;
+
+ } else {
+
+ if (DestinationType == DESTINATION_BCAST) {
+
+ if (Binding->AllRouteBroadcast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ } else {
+
+ CTEAssert (DestinationType == DESTINATION_MCAST);
+
+ if (Binding->AllRouteMulticast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ }
+ }
+
+#if 0
+ if (SourceRoutingLength != 0) {
+
+ PUCHAR IpxHeader = Header + Binding->BcMcHeaderSize;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+#endif
+ }
+
+ //
+ // Create space for the source routing information
+ //
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 17+SourceRoutingLength, Packet);
+#endif BACK_FILL
+
+ Header[0] = TR_PREAMBLE_AC;
+ Header[1] = TR_PREAMBLE_FC;
+ RtlCopyMemory (Header+2, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+8, Adapter->LocalMacAddress.Address, 6);
+
+ if (SourceRoutingLength != 0) {
+ Header[8] |= TR_SOURCE_ROUTE_FLAG;
+ RtlCopyMemory (Header+14, SourceRouting, SourceRoutingLength);
+ }
+
+ Header += (14 + SourceRoutingLength);
+
+ Header[0] = 0xe0;
+ Header[1] = 0xe0;
+ Header[2] = 0x03;
+ HeaderLength = 17;
+
+ //BufferLength = IncludedHeaderLength + HeaderLength + SourceRoutingLength;
+ BufferLength = HeaderLength + SourceRoutingLength;
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, BufferLength);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, BufferLength);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_5802_2 */
+
+
+NDIS_STATUS
+IpxSendFrame802_5Snap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_5 FRAMES IN
+ THE ISN_FRAME_TYPE_SNAP FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PBINDING Binding = Adapter->Bindings[ISN_FRAME_TYPE_SNAP];
+ PUCHAR Header;
+ ULONG HeaderLength;
+ UCHAR SourceRoutingBuffer[18];
+ PUCHAR SourceRouting;
+ ULONG SourceRoutingLength;
+ NDIS_STATUS Status;
+ ULONG BufferLength;
+ UCHAR DestinationType;
+
+ Header = Reserved->Header;
+
+ DestinationType = Reserved->DestinationType;
+
+ if (DestinationType == DESTINATION_DEF) {
+
+ MacLookupSourceRouting(
+ Reserved->Identifier,
+ Binding,
+ LocalTarget->MacAddress,
+ SourceRoutingBuffer,
+ &SourceRoutingLength);
+
+ if (SourceRoutingLength != 0) {
+
+// PUCHAR IpxHeader = Header + Binding->DefHeaderSize;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ SourceRouting = SourceRoutingBuffer;
+ // RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+
+ } else {
+
+ //
+ // For these packets we assume that the header is in the
+ // right place.
+ //
+
+ if (!Adapter->SourceRouting) {
+
+ SourceRoutingLength = 0;
+
+ } else {
+
+ if (DestinationType == DESTINATION_BCAST) {
+
+ if (Binding->AllRouteBroadcast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ } else {
+
+ CTEAssert (DestinationType == DESTINATION_MCAST);
+
+ if (Binding->AllRouteMulticast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ }
+
+ if (SourceRoutingLength != 0) {
+
+ // PUCHAR IpxHeader = Header + Binding->BcMcHeaderSize;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ // RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+ }
+ }
+
+ //
+ // Create space for sourcerouting headers
+ //
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 22+SourceRoutingLength, Packet);
+#endif BACK_FILL
+
+ Header[0] = TR_PREAMBLE_AC;
+ Header[1] = TR_PREAMBLE_FC;
+ RtlCopyMemory (Header+2, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+8, Adapter->LocalMacAddress.Address, 6);
+
+ if (SourceRoutingLength != 0) {
+ Header[8] |= TR_SOURCE_ROUTE_FLAG;
+ RtlCopyMemory (Header+14, SourceRouting, SourceRoutingLength);
+ }
+
+ Header += (14 + SourceRoutingLength);
+
+ Header[0] = 0xaa;
+ Header[1] = 0xaa;
+ Header[2] = 0x03;
+ Header[3] = 0x00;
+ Header[4] = 0x00;
+ Header[5] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[6]) = Adapter->BindSapNetworkOrder;
+ HeaderLength = 22;
+
+ //BufferLength = IncludedHeaderLength + HeaderLength + SourceRoutingLength;
+ BufferLength = HeaderLength + SourceRoutingLength;
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, BufferLength);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, BufferLength);
+#endif
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_5Snap */
+
+
+NDIS_STATUS
+IpxSendFrameFddi802_3(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMFDDI FRAMES IN
+ THE ISN_FRAME_TYPE_802_3 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 13, Packet);
+#endif BACK_FILL
+
+ Header[0] = FDDI_HEADER_BYTE;
+ RtlCopyMemory (Header+1, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+7, Adapter->LocalMacAddress.Address, 6);
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 13);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 13);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 13);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrameFddi802_3 */
+
+
+NDIS_STATUS
+IpxSendFrameFddi802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMFDDI FRAMES IN
+ THE ISN_FRAME_TYPE_802_2 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 16, Packet);
+#endif BACK_FILL
+
+ Header[0] = FDDI_HEADER_BYTE;
+ RtlCopyMemory (Header+1, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+7, Adapter->LocalMacAddress.Address, 6);
+
+ Header[13] = 0xe0;
+ Header[14] = 0xe0;
+ Header[15] = 0x03;
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 16);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 16);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 16);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrameFddi802_2 */
+
+
+NDIS_STATUS
+IpxSendFrameFddiSnap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMFDDI FRAMES IN
+ THE ISN_FRAME_TYPE_SNAP FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 21, Packet);
+#endif BACK_FILL
+
+ Header[0] = FDDI_HEADER_BYTE;
+ RtlCopyMemory (Header+1, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+7, Adapter->LocalMacAddress.Address, 6);
+
+ Header[13] = 0xaa;
+ Header[14] = 0xaa;
+ Header[15] = 0x03;
+ Header[16] = 0x00;
+ Header[17] = 0x00;
+ Header[18] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[19]) = Adapter->BindSapNetworkOrder;
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 21);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 21);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 21);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrameFddiSnap */
+
+
+NDIS_STATUS
+IpxSendFrameArcnet878_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMARCNET878_2 FRAMES IN
+ THE ISN_FRAME_TYPE_802_2 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 3, Packet);
+#endif BACK_FILL
+ //
+ // Convert broadcast address to 0 (the arcnet broadcast).
+ //
+
+ Header[0] = Adapter->LocalMacAddress.Address[5];
+ if (LocalTarget->MacAddress[5] == 0xff) {
+ Header[1] = 0x00;
+ } else {
+ Header[1] = LocalTarget->MacAddress[5];
+ }
+ Header[2] = ARCNET_PROTOCOL_ID;
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 3);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 3);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 3);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrameFddiArcnet878_2 */
+
+
+NDIS_STATUS
+IpxSendFrameWanEthernetII(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMWAN FRAMES IN
+ THE ISN_FRAME_TYPE_ETHERNET_II FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+#ifdef _PNP_POWER
+ PBINDING Binding;
+
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_GET_LOCK1(&IpxDevice->BindAccessLock, &LockHandle1);
+ Binding = NIC_ID_TO_BINDING(IpxDevice, NIC_FROM_LOCAL_TARGET(LocalTarget));
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+
+ IPX_FREE_LOCK1(&IpxDevice->BindAccessLock, LockHandle1);
+
+#else
+ PBINDING Binding = IpxDevice->Bindings[LocalTarget->NicId];
+#endif _PNP_POWER
+
+ //
+ // [FW] This will allow both LINE_UP and LINE_CONFIG states
+ //
+ if (Binding->LineUp) {
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 14, Packet);
+
+ //
+ // Call UpdateWanInactivity only if this is not a backfill packet, since
+ // SMB server does not do KeepAlives. In case, of backfilled packets, reset
+ // the counter regardless.
+ //
+ if (!Reserved->BackFill) {
+ IpxUpdateWanInactivityCounter(
+ Binding,
+ (IPX_HEADER UNALIGNED *)(Header + IpxDevice->IncludedHeaderOffset),
+ IncludedHeaderLength,
+ Packet,
+ PacketLength);
+ } else {
+ Binding->WanInactivityCounter = 0;
+ }
+
+#else
+ //
+ // We do checks to see if we should reset the inactivity
+ // counter. We normally need to check for netbios
+ // session alives, packets from rip, packets from
+ // sap, and ncp keep alives. In fact netbios packets
+ // and rip packets don't come through here.
+ //
+
+ IpxUpdateWanInactivityCounter(
+ Binding,
+ (IPX_HEADER UNALIGNED *)(Header + IpxDevice->IncludedHeaderOffset),
+ IncludedHeaderLength,
+ Packet,
+ PacketLength);
+#endif BACK_FILL
+
+ //
+ // In order for loopback to work properly, we need to put the local MAC address for locally destined
+ // pkts so NdisWAN can loop them back.
+ //
+ if (IPX_NODE_EQUAL(LocalTarget->MacAddress, Binding->LocalAddress.NodeAddress)) {
+ RtlCopyMemory (Header, Binding->LocalMacAddress.Address, 6);
+ } else {
+ RtlCopyMemory (Header, Binding->RemoteMacAddress.Address, 6);
+ }
+ // RtlCopyMemory (Header, Binding->RemoteMacAddress.Address, 6);
+ RtlCopyMemory (Header+6, Binding->LocalMacAddress.Address, 6);
+
+ *(UNALIGNED USHORT *)(&Header[12]) = Adapter->BindSapNetworkOrder;
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 14);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 14);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 14);
+#endif
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ return Status;
+
+ } else {
+
+ //
+ // Bug #17273 return proper error message
+ //
+
+ // return STATUS_DEVICE_DOES_NOT_EXIST;
+
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ return STATUS_NETWORK_UNREACHABLE;
+ }
+
+} /* IpxSendFrameWanEthernetII */
+
+
+VOID
+MacUpdateSourceRouting(
+ IN ULONG Database,
+ IN PADAPTER Adapter,
+ IN PUCHAR MacHeader,
+ IN ULONG MacHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a valid IPX frame is received from
+ a remote. It gives the source routing database a change to
+ update itself to include information about this remote.
+
+Arguments:
+
+ Database - The "database" to use (IPX, SPX, NB, RIP).
+
+ Adapter - The adapter the frame was received on.
+
+ MacHeader - The MAC header of the received frame.
+
+ MacHeaderLength - The length of the MAC header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSOURCE_ROUTE Current;
+ ULONG Hash;
+ LONG Result;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ CTEAssert ((Database >= 0) && (Database <= 3));
+
+ //
+ // If this adapter is configured for no source routing, don't
+ // need to do anything.
+ //
+
+ if (!Adapter->SourceRouting) {
+ return;
+ }
+
+ //
+ // See if this source routing is relevant. We don't
+ // care about two-byte source routing since that
+ // indicates it did not cross a router. If there
+ // is nothing in the database, then don't add
+ // this if it is minimal (if it is not, we need
+ // to add it so we will find it on sending).
+ //
+
+ if ((Adapter->SourceRoutingEmpty[Database]) &&
+ (MacHeaderLength <= 16)) {
+ return;
+ }
+
+ IPX_GET_LOCK (&Adapter->Lock, &LockHandle);
+
+ //
+ // Try to find this address in the database.
+ //
+
+ Hash = MacSourceRoutingHash (MacHeader+8);
+ Current = Adapter->SourceRoutingHeads[Database][Hash];
+
+ while (Current != (PSOURCE_ROUTE)NULL) {
+
+ IPX_NODE_COMPARE (MacHeader+8, Current->MacAddress, &Result);
+
+ if (Result == 0) {
+
+ //
+ // We found routing for this node. If the data is the
+ // same as what we have, update the time since used to
+ // prevent aging.
+ //
+
+ if ((Current->SourceRoutingLength == MacHeaderLength-14) &&
+ (RtlEqualMemory (Current->SourceRouting, MacHeader+14, MacHeaderLength-14))) {
+
+ Current->TimeSinceUsed = 0;
+ }
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+ return;
+
+ } else {
+
+ Current = Current->Next;
+ }
+
+ }
+
+ //
+ // Not found, insert a new node at the front of the list.
+ //
+
+ Current = (PSOURCE_ROUTE)IpxAllocateMemory (SOURCE_ROUTE_SIZE(MacHeaderLength-14), MEMORY_SOURCE_ROUTE, "SourceRouting");
+
+ if (Current == (PSOURCE_ROUTE)NULL) {
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+ return;
+ }
+
+ Current->Next = Adapter->SourceRoutingHeads[Database][Hash];
+ Adapter->SourceRoutingHeads[Database][Hash] = Current;
+
+ Adapter->SourceRoutingEmpty[Database] = FALSE;
+
+ RtlCopyMemory (Current->MacAddress, MacHeader+8, 6);
+ Current->MacAddress[0] &= 0x7f;
+ Current->SourceRoutingLength = (UCHAR)(MacHeaderLength - 14);
+ RtlCopyMemory (Current->SourceRouting, MacHeader+14, MacHeaderLength - 14);
+
+ Current->TimeSinceUsed = 0;
+
+ IPX_DEBUG (SOURCE_ROUTE, ("Adding source route %lx for %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ Current, Current->MacAddress[0], Current->MacAddress[1],
+ Current->MacAddress[2], Current->MacAddress[3],
+ Current->MacAddress[4], Current->MacAddress[5]));
+
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+
+} /* MacUpdateSourceRouting */
+
+
+VOID
+MacLookupSourceRouting(
+ IN ULONG Database,
+ IN PBINDING Binding,
+ IN UCHAR MacAddress[6],
+ IN OUT UCHAR SourceRouting[18],
+ OUT PULONG SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine looks up a target address in the adapter's
+ source routing database to see if source routing information
+ needs to be added to the frame.
+
+Arguments:
+
+ Database - The "database" to use (IPX, SPX, NB, RIP).
+
+ Binding - The binding the frame is being sent on.
+
+ MacAddress - The destination address.
+
+ SourceRouting - Buffer to hold the returned source routing info.
+
+ SourceRoutingLength - The returned source routing length.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSOURCE_ROUTE Current;
+ PADAPTER Adapter = Binding->Adapter;
+ ULONG Hash;
+ LONG Result;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ //
+ // If this adapter is configured for no source routing, don't
+ // insert any.
+ //
+
+ if (!Adapter->SourceRouting) {
+ *SourceRoutingLength = 0;
+ return;
+ }
+
+ //
+ // See if source routing has not been important so far.
+ //
+ // BUGBUG: This is wrong because we may be sending a directed
+ // packet to somebody on the other side of a router, without
+ // ever having received a routed packet. We fix this for the
+ // moment by only setting SourceRoutingEmpty for netbios
+ // which uses broadcasts for discovery.
+ //
+
+ if (Adapter->SourceRoutingEmpty[Database]) {
+ *SourceRoutingLength = 0;
+ return;
+ }
+
+ Hash = MacSourceRoutingHash (MacAddress);
+
+ IPX_GET_LOCK (&Adapter->Lock, &LockHandle);
+ Current = Adapter->SourceRoutingHeads[Database][Hash];
+
+ while (Current != (PSOURCE_ROUTE)NULL) {
+
+ IPX_NODE_COMPARE (MacAddress, Current->MacAddress, &Result);
+
+ if (Result == 0) {
+
+ //
+ // We found routing for this node.
+ //
+
+ if (Current->SourceRoutingLength <= 2) {
+ *SourceRoutingLength = 0;
+ } else {
+ RtlCopyMemory (SourceRouting, Current->SourceRouting, Current->SourceRoutingLength);
+ SourceRouting[0] = (SourceRouting[0] & TR_LENGTH_MASK);
+ SourceRouting[1] = (SourceRouting[1] ^ TR_DIRECTION_MASK);
+ *SourceRoutingLength = Current->SourceRoutingLength;
+ }
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+ return;
+
+ } else {
+
+ Current = Current->Next;
+
+ }
+
+ }
+
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+
+ //
+ // We did not find this node, use the default.
+ //
+
+ if (Binding->AllRouteDirected) {
+ RtlCopyMemory (SourceRouting, AllRouteSourceRouting, 2);
+ } else {
+ RtlCopyMemory (SourceRouting, SingleRouteSourceRouting, 2);
+ }
+ *SourceRoutingLength = 2;
+
+} /* MacLookupSourceRouting */
+
+
+VOID
+MacSourceRoutingTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the source routing timer expires.
+ It is called every minute.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the device pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)Context;
+ PADAPTER Adapter;
+ PBINDING Binding;
+ PSOURCE_ROUTE Current, OldCurrent, Previous;
+ UINT i, j, k;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+#ifdef _PNP_POWER
+
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ //
+ // Get a lock on the access path.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ ++Device->SourceRoutingTime;
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->ValidBindings);
+
+ for (i = 1; i <= Index; i++) {
+
+ if (Binding = NIC_ID_TO_BINDING(Device, i)) {
+#else
+ ++Device->SourceRoutingTime;
+
+ for (i = 1; i <= Device->ValidBindings; i++) {
+
+ if (Binding = Device->Bindings[i]) {
+#endif _PNP_POWER
+
+ Adapter = Binding->Adapter;
+
+ if (Adapter->LastSourceRoutingTime != Device->SourceRoutingTime) {
+
+ //
+ // We need to scan this adapter's source routing
+ // tree for stale routes. To simplify the scan we
+ // only delete entries that have at least one
+ // child that is NULL.
+ //
+
+ Adapter->LastSourceRoutingTime = Device->SourceRoutingTime;
+
+ for (j = 0; j < IDENTIFIER_TOTAL; j++) {
+
+ for (k = 0; k < SOURCE_ROUTE_HASH_SIZE; k++) {
+
+ if (Adapter->SourceRoutingHeads[j][k] == (PSOURCE_ROUTE)NULL) {
+ continue;
+ }
+
+ IPX_GET_LOCK (&Adapter->Lock, &LockHandle);
+
+ Current = Adapter->SourceRoutingHeads[j][k];
+ Previous = (PSOURCE_ROUTE)NULL;
+
+ while (Current != (PSOURCE_ROUTE)NULL) {
+
+ ++Current->TimeSinceUsed;
+
+ if (Current->TimeSinceUsed >= Device->SourceRouteUsageTime) {
+
+ //
+ // A stale entry needs to be aged.
+ //
+
+ if (Previous) {
+ Previous->Next = Current->Next;
+ } else {
+ Adapter->SourceRoutingHeads[j][k] = Current->Next;
+ }
+
+ OldCurrent = Current;
+ Current = Current->Next;
+
+ IPX_DEBUG (SOURCE_ROUTE, ("Aging out source-route entry %lx\n", OldCurrent));
+ IpxFreeMemory (OldCurrent, SOURCE_ROUTE_SIZE (OldCurrent->SourceRoutingLength), MEMORY_SOURCE_ROUTE, "SourceRouting");
+
+ } else {
+
+ Previous = Current;
+ Current = Current->Next;
+ }
+
+ }
+
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+
+ } // for loop through the database's hash list
+
+ } // for loop through the adapter's four databases
+
+ } // if adapter's database needs to be checked
+
+ } // if binding exists
+
+ } // for loop through every binding
+ }
+
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif _PNP_POWER
+
+ //
+ // Now restart the timer unless we should not (which means
+ // we are being unloaded).
+ //
+
+ if (Device->SourceRoutingUsed) {
+
+ CTEStartTimer(
+ &Device->SourceRoutingTimer,
+ 60000, // one minute timeout
+ MacSourceRoutingTimeout,
+ (PVOID)Device);
+
+ } else {
+
+ IpxDereferenceDevice (Device, DREF_SR_TIMER);
+ }
+
+} /* MacSourceRoutingTimeout */
+
+
+VOID
+MacSourceRoutingRemove(
+ IN PBINDING Binding,
+ IN UCHAR MacAddress[6]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the IPX action handler when an
+ IPXROUTE use has specified that source routing for a given
+ MAC address should be removed.
+
+Arguments:
+
+ Binding - The binding to modify.
+
+ MacAddress - The MAC address to remove.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PSOURCE_ROUTE Current, Previous;
+ PADAPTER Adapter = Binding->Adapter;
+ ULONG Hash;
+ ULONG Database;
+ LONG Result;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // Scan through to find the matching entry in each database.
+ //
+
+ Hash = MacSourceRoutingHash (MacAddress);
+
+ IPX_GET_LOCK (&Adapter->Lock, &LockHandle);
+
+ for (Database = 0; Database < IDENTIFIER_TOTAL; Database++) {
+
+ Current = Adapter->SourceRoutingHeads[Database][Hash];
+ Previous = NULL;
+
+ while (Current != (PSOURCE_ROUTE)NULL) {
+
+ IPX_NODE_COMPARE (MacAddress, Current->MacAddress, &Result);
+
+ if (Result == 0) {
+
+ if (Previous) {
+ Previous->Next = Current->Next;
+ } else {
+ Adapter->SourceRoutingHeads[Database][Hash] = Current->Next;
+ }
+
+ IPX_DEBUG (SOURCE_ROUTE, ("IPXROUTE freeing source-route entry %lx\n", Current));
+ IpxFreeMemory (Current, SOURCE_ROUTE_SIZE (Current->SourceRoutingLength), MEMORY_SOURCE_ROUTE, "SourceRouting");
+
+ break;
+
+ } else {
+
+ Previous = Current;
+ Current = Current->Next;
+
+ }
+
+ }
+
+ }
+
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+
+} /* MacSourceRoutingRemove */
+
+
+VOID
+MacSourceRoutingClear(
+ IN PBINDING Binding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the IPX action handler when an
+ IPXROUTE use has specified that source routing for a given
+ binding should be cleared entirely.
+
+Arguments:
+
+ Binding - The binding to be cleared.
+
+ MacAddress - The MAC address to remove.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSOURCE_ROUTE Current;
+ PADAPTER Adapter = Binding->Adapter;
+ ULONG Database, Hash;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // Scan through and remove every entry in the database.
+ //
+
+ IPX_GET_LOCK (&Adapter->Lock, &LockHandle);
+
+ for (Database = 0; Database < IDENTIFIER_TOTAL; Database++) {
+
+ for (Hash = 0; Hash < SOURCE_ROUTE_HASH_SIZE; Hash++) {
+
+ while (Adapter->SourceRoutingHeads[Database][Hash]) {
+
+ Current = Adapter->SourceRoutingHeads[Database][Hash];
+ Adapter->SourceRoutingHeads[Database][Hash] = Current->Next;
+
+ IpxFreeMemory (Current, SOURCE_ROUTE_SIZE (Current->SourceRoutingLength), MEMORY_SOURCE_ROUTE, "SourceRouting");
+
+ }
+ }
+ }
+
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+
+} /* MacSourceRoutingClear */
+
+
+
diff --git a/private/ntos/tdi/isn/ipx/mac.h b/private/ntos/tdi/isn/ipx/mac.h
new file mode 100644
index 000000000..a88e77ecd
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/mac.h
@@ -0,0 +1,44 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ mac.h
+
+Abstract:
+
+ This header file defines manifest constants and necessary macros for use
+ by transports dealing with multiple MAC cards through the NDIS interface.
+
+Revision History:
+
+--*/
+
+
+//
+// We need this to define information about the MAC. Note that
+// it is a strange structure in that the first four elements
+// are for use internally by the mac.c routines, while the
+// DeviceContext knows about and uses the last two.
+//
+
+typedef struct _NDIS_INFORMATION {
+
+ NDIS_MEDIUM MediumType;
+ NDIS_MEDIUM RealMediumType;
+ BOOLEAN SourceRouting;
+ BOOLEAN MediumAsync;
+ UCHAR BroadcastMask;
+ ULONG CopyLookahead;
+ ULONG MacOptions;
+ ULONG MinHeaderLength;
+ ULONG MaxHeaderLength;
+
+} NDIS_INFORMATION, * PNDIS_INFORMATION;
+
+
+#define TR_SOURCE_ROUTE_FLAG 0x80
+
+#define ARCNET_PROTOCOL_ID 0xFA
+
diff --git a/private/ntos/tdi/isn/ipx/mp/makefile b/private/ntos/tdi/isn/ipx/mp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/mp/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isn/ipx/mp/nwlnkipx.prf b/private/ntos/tdi/isn/ipx/mp/nwlnkipx.prf
new file mode 100644
index 000000000..0c4359235
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/mp/nwlnkipx.prf
@@ -0,0 +1,89 @@
+IpxTdiSendDatagram@8
+IpxReceiveIndicationNew@36
+IpxSendFrame@16
+IpxReceiveComplete@4
+IpxSendFrame802_3802_2@20
+IpxReceivePacket@8
+IpxDerefAddressSync@4
+IpxSendComplete@12
+IpxSendFramePreFwd@16
+IpxReceiveIndication@28
+IpxInitializeBackFillPacket@12
+IpxpAllocateMemory@12
+IpxPopBackFillPacket@4
+IpxAllocateBackFillPool@4
+RipLongTimeout@8
+CTEStartTimer@16
+TdiCopyBufferToMdl@24
+IpxTdiQueryInformation@8
+IpxVerifyAddressFile@4
+IpxDispatchInternal@8
+IpxTransferData@28
+IpxInitLoopback@0
+RipGetFirstRoute@4
+IpxCreateAddress@8
+MacReturnMaxDataSize@20
+IpxLookupAddress@8
+IpxAbortLineChanges@4
+MacMapFrameType@12
+IpxInitializeReceiveBuffer@16
+IpxDispatchOpenClose@8
+IpxTdiSetEventHandler@4
+IpxCreateAddressFile@4
+IpxInternalBind@8
+IpxInitializeReceivePacket@8
+IpxIsAddressLocal@4
+IpxOpenAddress@8
+IpxAllocateReceiveBufferPool@4
+IpxSubmitNdisRequest@12
+IpxAddBroadcast@4
+IpxDestroyBinding@4
+RipAdjustForBindingChange@12
+IpxDispatchDeviceControl@8
+IpxAllocatePaddingBuffer@4
+TdiMapUserRequest@12
+CTEInitialize@0
+IpxInitializeSendPacket@12
+IpxpFreeMemory@12
+IpxInitializePaddingBuffer@12
+IpxAllocateSendPool@4
+RipCleanupPacket@8
+TdiRegisterDeviceObject@8
+TdiRegisterNetAddress@8
+IpxTdiAction@8
+IpxCreateBinding@20
+IpxDerefDevice@4
+MacInitializeBindingInfo@8
+IpxRegisterProtocol@4
+IpxInitializeNdis@8
+IpxGetConfigValue@24
+IpxCreateAdapter@12
+IpxResolveBindingSets@8
+IpxGetFrameType@24
+MacInitializeMacInfo@8
+IpxGetBindingValue@24
+RipQueueRequest@8
+RipShortTimeout@8
+IpxPopSendPacket@4
+IpxAllocateBindingPool@4
+IpxInternalQuery@20
+CTEInitTimer@4
+IpxRequestComplete@12
+IpxBroadcastOperation@4
+CTEInitEvent@8
+IpxPnPGetVirtualNetworkNumber@4
+IpxPnPGetAdapterParameters@12
+IpxOpenAdapterComplete@12
+IpxResolveAutoDetect@16
+IpxBindToAdapter@16
+TdiInitialize@0
+IpxPnPIsnIndicate@4
+IpxPnPUpdateBindingArray@12
+IpxBindAdapter@20
+IpxPnPUpdateDevice@4
+IpxGetConfiguration@12
+IpxAddExport@24
+IpxCreateDevice@16
+DriverEntry@8
+IpxReadLinkageInformation@4
+IpxFreeConfiguration@4
diff --git a/private/ntos/tdi/isn/ipx/mp/sources b/private/ntos/tdi/isn/ipx/mp/sources
new file mode 100644
index 000000000..dc48d81bb
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/mp/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+NT_UP=0
+
+TARGETPATH=\nt\public\sdk\lib
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/isn/ipx/ndis.c b/private/ntos/tdi/isn/ipx/ndis.c
new file mode 100644
index 000000000..db1d41e13
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/ndis.c
@@ -0,0 +1,2381 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ ndis.c
+
+Abstract:
+
+ This module contains code which implements the routines used to
+ initialize the IPX <-> NDIS interface, as well as most of the
+ interface routines.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports
+ 1. Added the ReceivePacketHandler to the ProtChars.
+
+ Sanjay Anand (SanjayAn) 27-Oct-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+ Tony Bell (TonyBe) 10-Dec-1995
+ Changes to support new NdisWan Lineup.
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// This is a one-per-driver variable used in binding
+// to the NDIS interface.
+//
+
+NDIS_HANDLE IpxNdisProtocolHandle = (NDIS_HANDLE)NULL;
+
+NDIS_STATUS
+IpxSubmitNdisRequest(
+ IN PADAPTER Adapter,
+ IN PNDIS_REQUEST NdisRequest,
+ IN PNDIS_STRING AdapterString
+ );
+
+#ifndef _PNP_POWER
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,IpxRegisterProtocol)
+#pragma alloc_text(INIT,IpxInitializeNdis)
+#endif
+#endif
+
+
+NTSTATUS
+IpxRegisterProtocol(
+ IN PNDIS_STRING NameString
+ )
+
+/*++
+
+Routine Description:
+
+ This routine introduces this transport to the NDIS interface.
+
+Arguments:
+
+ NameString - The name of the transport.
+
+Return Value:
+
+ The function value is the status of the operation.
+ STATUS_SUCCESS if all goes well,
+ Failure status if we tried to register and couldn't,
+ STATUS_INSUFFICIENT_RESOURCES if we couldn't even try to register.
+
+--*/
+
+{
+ NDIS_STATUS ndisStatus;
+
+ NDIS_PROTOCOL_CHARACTERISTICS ProtChars; // Used temporarily to register
+
+
+ //
+ // Set up the characteristics of this protocol
+ //
+#if NDIS40
+ ProtChars.MajorNdisVersion = 4;
+
+ ProtChars.ReceivePacketHandler = IpxReceivePacket;
+#else
+ ProtChars.MajorNdisVersion = 3;
+#endif
+ ProtChars.MinorNdisVersion = 0;
+
+ ProtChars.Name = *NameString;
+
+ ProtChars.OpenAdapterCompleteHandler = IpxOpenAdapterComplete;
+ ProtChars.CloseAdapterCompleteHandler = IpxCloseAdapterComplete;
+ ProtChars.ResetCompleteHandler = IpxResetComplete;
+ ProtChars.RequestCompleteHandler = IpxRequestComplete;
+
+ ProtChars.SendCompleteHandler = IpxSendComplete;
+ ProtChars.TransferDataCompleteHandler = IpxTransferDataComplete;
+
+ ProtChars.ReceiveHandler = IpxReceiveIndication;
+ ProtChars.ReceiveCompleteHandler = IpxReceiveComplete;
+ ProtChars.StatusHandler = IpxStatus;
+ ProtChars.StatusCompleteHandler = IpxStatusComplete;
+
+#ifdef _PNP_POWER
+ ProtChars.BindAdapterHandler = IpxBindAdapter;
+ ProtChars.UnbindAdapterHandler = IpxUnbindAdapter;
+ ProtChars.TranslateHandler = IpxTranslate;
+#endif // _PNP_POWER
+
+ NdisRegisterProtocol (
+ &ndisStatus,
+ &IpxNdisProtocolHandle,
+ &ProtChars,
+ (UINT)sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + NameString->Length);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS) {
+ return (NTSTATUS)ndisStatus;
+ }
+
+ return STATUS_SUCCESS;
+
+} /* IpxRegisterProtocol */
+
+
+VOID
+IpxDeregisterProtocol (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes this transport to the NDIS interface.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS ndisStatus;
+
+ if (IpxNdisProtocolHandle != (NDIS_HANDLE)NULL) {
+ NdisDeregisterProtocol (
+ &ndisStatus,
+ IpxNdisProtocolHandle);
+ IpxNdisProtocolHandle = (NDIS_HANDLE)NULL;
+ }
+
+} /* IpxDeregisterProtocol */
+
+
+NDIS_STATUS
+IpxSubmitNdisRequest(
+ IN PADAPTER Adapter,
+ IN PNDIS_REQUEST NdisRequest,
+ IN PNDIS_STRING AdapterString
+ )
+
+/*++
+
+Routine Description:
+
+ This routine passed an NDIS_REQUEST to the MAC and waits
+ until it has completed before returning the final status.
+
+Arguments:
+
+ Adapter - Pointer to the device context for this driver.
+
+ NdisRequest - Pointer to the NDIS_REQUEST to submit.
+
+ AdapterString - The name of the adapter, in case an error needs
+ to be logged.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NDIS_STATUS NdisStatus;
+
+ NdisRequest(
+ &NdisStatus,
+ Adapter->NdisBindingHandle,
+ NdisRequest);
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &Adapter->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = Adapter->NdisRequestStatus;
+
+ KeResetEvent(
+ &Adapter->NdisRequestEvent
+ );
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ IPX_DEBUG (NDIS, ("%s on OID %8.8lx failed %lx\n",
+ NdisRequest->RequestType == NdisRequestSetInformation ? "Set" : "Query",
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ NdisStatus));
+
+ IpxWriteOidErrorLog(
+ Adapter->Device->DeviceObject,
+ NdisRequest->RequestType == NdisRequestSetInformation ?
+ EVENT_TRANSPORT_SET_OID_FAILED : EVENT_TRANSPORT_QUERY_OID_FAILED,
+ NdisStatus,
+ AdapterString->Buffer,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid);
+
+ } else {
+
+ IPX_DEBUG (NDIS, ("%s on OID %8.8lx succeeded\n",
+ NdisRequest->RequestType == NdisRequestSetInformation ? "Set" : "Query",
+ NdisRequest->DATA.QUERY_INFORMATION.Oid));
+ }
+
+ return NdisStatus;
+
+} /* IpxSubmitNdisRequest */
+
+
+NTSTATUS
+IpxInitializeNdis(
+ IN PADAPTER Adapter,
+ IN PBINDING_CONFIG ConfigBinding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine introduces this transport to the NDIS interface and sets up
+ any necessary NDIS data structures (Buffer pools and such). It will be
+ called for each adapter opened by this transport.
+
+Arguments:
+
+ Adapter - Structure describing this binding.
+
+ ConfigAdapter - Configuration information for this binding.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NDIS_STATUS NdisStatus;
+ NDIS_STATUS OpenErrorStatus;
+ NDIS_MEDIUM IpxSupportedMedia[] = { NdisMedium802_3, NdisMedium802_5, NdisMediumFddi, NdisMediumArcnet878_2, NdisMediumWan };
+ UINT SelectedMedium;
+ NDIS_REQUEST IpxRequest;
+ ULONG MinimumLookahead;
+ UCHAR WanProtocolId[6] = { 0x80, 0x00, 0x00, 0x00, 0x81, 0x37 };
+ UCHAR FunctionalAddress[4] = { 0x00, 0x80, 0x00, 0x00 };
+ ULONG WanHeaderFormat = NdisWanHeaderEthernet;
+ NDIS_OID IpxOid;
+ ULONG MacOptions;
+ ULONG PacketFilter;
+ PNDIS_STRING AdapterString = &ConfigBinding->AdapterName;
+
+ //
+ // Initialize this adapter for IPX use through NDIS
+ //
+
+ //
+ // This event is used in case any of the NDIS requests
+ // pend; we wait until it is set by the completion
+ // routine, which also sets NdisRequestStatus.
+ //
+
+ KeInitializeEvent(
+ &Adapter->NdisRequestEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ Adapter->NdisBindingHandle = NULL;
+
+ OpenErrorStatus = 0;
+
+ NdisOpenAdapter (
+ &NdisStatus,
+ &OpenErrorStatus,
+ &Adapter->NdisBindingHandle,
+ &SelectedMedium,
+ IpxSupportedMedia,
+ sizeof (IpxSupportedMedia) / sizeof(NDIS_MEDIUM),
+ IpxNdisProtocolHandle,
+ (NDIS_HANDLE)Adapter,
+ &ConfigBinding->AdapterName,
+ 0,
+ NULL);
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &Adapter->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = Adapter->NdisRequestStatus;
+ OpenErrorStatus = Adapter->OpenErrorStatus;
+
+ KeResetEvent(
+ &Adapter->NdisRequestEvent
+ );
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ IPX_DEBUG (NDIS, ("Open %ws failed %lx\n", ConfigBinding->AdapterName.Buffer, NdisStatus));
+
+ IpxWriteGeneralErrorLog(
+ Adapter->Device->DeviceObject,
+ EVENT_TRANSPORT_ADAPTER_NOT_FOUND,
+ 807,
+ NdisStatus,
+ AdapterString->Buffer,
+ 1,
+ &OpenErrorStatus);
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ IPX_DEBUG (NDIS, ("Open %ws succeeded\n", ConfigBinding->AdapterName.Buffer));
+ }
+
+
+ //
+ // Get the information we need about the adapter, based on
+ // the media type.
+ //
+
+ MacInitializeMacInfo(
+ IpxSupportedMedia[SelectedMedium],
+ &Adapter->MacInfo);
+
+
+ switch (Adapter->MacInfo.RealMediumType) {
+
+ case NdisMedium802_3:
+
+ IpxOid = OID_802_3_CURRENT_ADDRESS;
+ break;
+
+ case NdisMedium802_5:
+
+ IpxOid = OID_802_5_CURRENT_ADDRESS;
+ break;
+
+ case NdisMediumFddi:
+
+ IpxOid = OID_FDDI_LONG_CURRENT_ADDR;
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ IpxOid = OID_ARCNET_CURRENT_ADDRESS;
+ break;
+
+ case NdisMediumWan:
+
+ IpxOid = OID_WAN_CURRENT_ADDRESS;
+ break;
+
+ default:
+
+ NdisStatus = NDIS_STATUS_FAILURE;
+ break;
+
+ }
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = IpxOid;
+
+ if (IpxOid != OID_ARCNET_CURRENT_ADDRESS) {
+
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = Adapter->LocalMacAddress.Address;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 6;
+
+ } else {
+
+ //
+ // We take the arcnet single-byte address and right-justify
+ // it in a field of zeros.
+ //
+
+ RtlZeroMemory (Adapter->LocalMacAddress.Address, 5);
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &Adapter->LocalMacAddress.Address[5];
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 1;
+
+ }
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now query the maximum packet sizes.
+ //
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_FRAME_SIZE;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(Adapter->MaxReceivePacketSize);
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(Adapter->MaxSendPacketSize);
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Query the receive buffer space.
+ //
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_RECEIVE_BUFFER_SPACE;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(Adapter->ReceiveBufferSpace);
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now set the minimum lookahead size. The value we choose
+ // here is the 128 needed for TDI indications, plus the size
+ // of the IPX header, plus the largest extra header possible
+ // (a SNAP header, 8 bytes), plus the largest higher-level
+ // header (I think it is a Netbios datagram, 34 bytes).
+ //
+ // BETABUGBUG: Adapt this based on higher-level bindings and
+ // configured frame types.
+ //
+
+ MinimumLookahead = 128 + sizeof(IPX_HEADER) + 8 + 34;
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_CURRENT_LOOKAHEAD;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &MinimumLookahead;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now query the link speed
+ //
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_LINK_SPEED;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(Adapter->MediumSpeed);
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // For wan, specify our protocol ID and header format.
+ // We don't query the medium subtype because we don't
+ // case (since we require ethernet emulation).
+ //
+
+ if (Adapter->MacInfo.MediumAsync) {
+
+ if (Adapter->BindSap != 0x8137) {
+ *(UNALIGNED USHORT *)(&WanProtocolId[4]) = Adapter->BindSapNetworkOrder;
+ }
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_PROTOCOL_TYPE;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = WanProtocolId;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 6;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_HEADER_FORMAT;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &WanHeaderFormat;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Now query the line count.
+ //
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_LINE_COUNT;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &Adapter->WanNicIdCount;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ Adapter->WanNicIdCount = 1;
+ }
+
+ if (Adapter->WanNicIdCount == 0) {
+
+ IPX_DEBUG (NDIS, ("OID_WAN_LINE_COUNT returned 0 lines\n"));
+
+ IpxWriteOidErrorLog(
+ Adapter->Device->DeviceObject,
+ EVENT_TRANSPORT_QUERY_OID_FAILED,
+ NDIS_STATUS_INVALID_DATA,
+ AdapterString->Buffer,
+ OID_WAN_LINE_COUNT);
+
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+ }
+
+
+ //
+ // For 802.5 adapter's configured that way, we enable the
+ // functional address (C0-00-00-80-00-00).
+ //
+
+ if ((Adapter->MacInfo.MediumType == NdisMedium802_5) &&
+ (Adapter->EnableFunctionalAddress)) {
+
+ //
+ // For token-ring, we pass the last four bytes of the
+ // Netbios functional address.
+ //
+
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_802_5_CURRENT_FUNCTIONAL;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = FunctionalAddress;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+
+ //
+ // Now query the MAC's optional characteristics.
+ //
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAC_OPTIONS;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &MacOptions;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Adapter->MacInfo.CopyLookahead =
+ ((MacOptions & NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA) != 0) ?
+ TDI_RECEIVE_COPY_LOOKAHEAD : 0;
+ Adapter->MacInfo.MacOptions = MacOptions;
+
+
+ switch (Adapter->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_2] = 17;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_3] = 14;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 14;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_SNAP] = 22;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_2] = 17;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_3] = 14;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 14;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_SNAP] = 22;
+ break;
+
+ case NdisMedium802_5:
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_2] = 17;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_3] = 17;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 17;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_SNAP] = 22;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_2] = 17;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_3] = 17;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 17;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_SNAP] = 22;
+ break;
+
+ case NdisMediumFddi:
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_2] = 16;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_3] = 13;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 16;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_SNAP] = 21;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_2] = 16;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_3] = 13;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 16;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_SNAP] = 21;
+ break;
+
+ case NdisMediumArcnet878_2:
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_2] = 3;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_3] = 3;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 3;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_SNAP] = 3;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_2] = 3;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_3] = 3;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 3;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_SNAP] = 3;
+ break;
+
+ }
+
+ //
+ // BUGBUG: If functional filtering is set, set the address
+ // for the appropriate binding.
+ //
+
+ //
+ // Now that everything is set up, we enable the filter
+ // for packet reception.
+ //
+
+ switch (Adapter->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+ case NdisMediumFddi:
+ case NdisMedium802_5:
+ case NdisMediumArcnet878_2:
+
+ //
+ // If we have a virtual network number we need to receive
+ // broadcasts (either the router will be bound in which
+ // case we want them, or we need to respond to rip requests
+ // ourselves).
+ //
+
+ PacketFilter = NDIS_PACKET_TYPE_DIRECTED;
+
+ if (Adapter->Device->VirtualNetworkNumber != 0) {
+
+ Adapter->BroadcastEnabled = TRUE;
+ Adapter->Device->EnableBroadcastCount = 1;
+ PacketFilter |= NDIS_PACKET_TYPE_BROADCAST;
+
+ if ((Adapter->MacInfo.MediumType == NdisMedium802_5) && (Adapter->EnableFunctionalAddress)) {
+ PacketFilter |= NDIS_PACKET_TYPE_FUNCTIONAL;
+ }
+
+ } else {
+
+ Adapter->BroadcastEnabled = FALSE;
+ Adapter->Device->EnableBroadcastCount = 0;
+
+ }
+
+ break;
+
+ default:
+
+ CTEAssert (FALSE);
+ break;
+
+ }
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ IpxRequest.DATA.SET_INFORMATION.InformationBuffer = &PacketFilter;
+ IpxRequest.DATA.SET_INFORMATION.InformationBufferLength = sizeof(ULONG);
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ return STATUS_SUCCESS;
+
+} /* IpxInitializeNdis */
+
+
+VOID
+IpxAddBroadcast(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when another reason for enabling
+ broadcast reception is added. If it is the first, then
+ reception on the card is enabled by queueing a call to
+ IpxBroadcastOperation.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD.
+
+Arguments:
+
+ Device - The IPX device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ++Device->EnableBroadcastCount;
+
+ if (Device->EnableBroadcastCount == 1) {
+
+ //
+ // Broadcasts should be enabled.
+ //
+
+ if (!Device->EnableBroadcastPending) {
+
+ if (Device->DisableBroadcastPending) {
+ Device->ReverseBroadcastOperation = TRUE;
+ } else {
+ Device->EnableBroadcastPending = TRUE;
+ ExInitializeWorkItem(
+ &Device->BroadcastOperationQueueItem,
+ IpxBroadcastOperation,
+ (PVOID)TRUE);
+ ExQueueWorkItem(&Device->BroadcastOperationQueueItem, DelayedWorkQueue);
+ }
+ }
+ }
+
+} /* IpxAddBroadcast */
+
+
+VOID
+IpxRemoveBroadcast(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a reason for enabling
+ broadcast reception is removed. If it is the last, then
+ reception on the card is disabled by queueing a call to
+ IpxBroadcastOperation.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD.
+
+Arguments:
+
+ Device - The IPX device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ --Device->EnableBroadcastCount;
+
+ if (Device->EnableBroadcastCount == 0) {
+
+ //
+ // Broadcasts should be disabled.
+ //
+
+ if (!Device->DisableBroadcastPending) {
+
+ if (Device->EnableBroadcastPending) {
+ Device->ReverseBroadcastOperation = TRUE;
+ } else {
+ Device->DisableBroadcastPending = TRUE;
+ ExInitializeWorkItem(
+ &Device->BroadcastOperationQueueItem,
+ IpxBroadcastOperation,
+ (PVOID)FALSE);
+ ExQueueWorkItem(&Device->BroadcastOperationQueueItem, DelayedWorkQueue);
+ }
+ }
+ }
+
+} /* IpxRemoveBroadcast */
+
+
+VOID
+IpxBroadcastOperation(
+ IN PVOID Parameter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to change whether broadcast reception
+ is enabled or disabled. It performs the requested operation
+ on every adapter bound to by IPX.
+
+ This routine is called by a worker thread queued when a
+ bind/unbind operation changes the broadcast state.
+
+Arguments:
+
+ Parameter - TRUE if broadcasts should be enabled, FALSE
+ if they should be disabled.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ BOOLEAN Enable = (BOOLEAN)Parameter;
+ UINT i;
+ PBINDING Binding;
+ PADAPTER Adapter;
+ ULONG PacketFilter;
+ NDIS_REQUEST IpxRequest;
+ NDIS_STRING AdapterName;
+ CTELockHandle LockHandle;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ IPX_DEBUG (NDIS, ("%s operation started\n", Enable ? "Enable" : "Disable"));
+
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->ValidBindings);
+
+ for (i = 1; i <= Index; i++) {
+
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ IPX_DEBUG (NDIS, ("%s operation started\n", Enable ? "Enable" : "Disable"));
+
+ for (i = 1; i <= Device->ValidBindings; i++) {
+
+ Binding = Device->Bindings[i];
+#endif
+ if (Binding == NULL) {
+ continue;
+ }
+
+ Adapter = Binding->Adapter;
+ if (Adapter->BroadcastEnabled == Enable) {
+ continue;
+ }
+
+ if (Enable) {
+ if ((Adapter->MacInfo.MediumType == NdisMedium802_5) && (Adapter->EnableFunctionalAddress)) {
+ PacketFilter = (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_FUNCTIONAL);
+ } else {
+ PacketFilter = (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST);
+ }
+ } else {
+ PacketFilter = NDIS_PACKET_TYPE_DIRECTED;
+ }
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ IpxRequest.DATA.SET_INFORMATION.InformationBuffer = &PacketFilter;
+ IpxRequest.DATA.SET_INFORMATION.InformationBufferLength = sizeof(ULONG);
+
+ AdapterName.Buffer = Adapter->AdapterName;
+ AdapterName.Length = (USHORT)Adapter->AdapterNameLength;
+ AdapterName.MaximumLength = (USHORT)(Adapter->AdapterNameLength + sizeof(WCHAR));
+
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ (VOID)IpxSubmitNdisRequest (Adapter, &IpxRequest, &AdapterName);
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+
+ Adapter->BroadcastEnabled = Enable;
+
+ }
+ }
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ if (Enable) {
+
+ CTEAssert (Device->EnableBroadcastPending);
+ Device->EnableBroadcastPending = FALSE;
+
+ if (Device->ReverseBroadcastOperation) {
+ Device->ReverseBroadcastOperation = FALSE;
+ Device->DisableBroadcastPending = TRUE;
+ ExInitializeWorkItem(
+ &Device->BroadcastOperationQueueItem,
+ IpxBroadcastOperation,
+ (PVOID)FALSE);
+ ExQueueWorkItem(&Device->BroadcastOperationQueueItem, DelayedWorkQueue);
+ }
+
+ } else {
+
+ CTEAssert (Device->DisableBroadcastPending);
+ Device->DisableBroadcastPending = FALSE;
+
+ if (Device->ReverseBroadcastOperation) {
+ Device->ReverseBroadcastOperation = FALSE;
+ Device->EnableBroadcastPending = TRUE;
+ ExInitializeWorkItem(
+ &Device->BroadcastOperationQueueItem,
+ IpxBroadcastOperation,
+ (PVOID)TRUE);
+ ExQueueWorkItem(&Device->BroadcastOperationQueueItem, DelayedWorkQueue);
+ }
+
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+}/* IpxBroadcastOperation */
+
+
+VOID
+IpxCloseNdis(
+ IN PADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unbinds the transport from the NDIS interface and does
+ any other work required to undo what was done in IpxInitializeNdis.
+ It is written so that it can be called from within IpxInitializeNdis
+ if it fails partway through.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NDIS_STATUS ndisStatus;
+
+ //
+ // Close the NDIS binding.
+ //
+
+ if (Adapter->NdisBindingHandle != (NDIS_HANDLE)NULL) {
+
+ //
+ // This event is used in case any of the NDIS requests
+ // pend; we wait until it is set by the completion
+ // routine, which also sets NdisRequestStatus.
+ //
+
+ KeInitializeEvent(
+ &Adapter->NdisRequestEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ NdisCloseAdapter(
+ &ndisStatus,
+ Adapter->NdisBindingHandle);
+
+ if (ndisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &Adapter->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ ndisStatus = Adapter->NdisRequestStatus;
+
+ KeResetEvent(
+ &Adapter->NdisRequestEvent
+ );
+
+ }
+
+ //
+ // We ignore ndisStatus.
+ //
+
+ }
+
+#if 0
+ if (Adapter->SendPacketPoolHandle != NULL) {
+ NdisFreePacketPool (Adapter->SendPacketPoolHandle);
+ }
+
+ if (Adapter->ReceivePacketPoolHandle != NULL) {
+ NdisFreePacketPool (Adapter->ReceivePacketPoolHandle);
+ }
+
+ if (Adapter->NdisBufferPoolHandle != NULL) {
+ NdisFreeBufferPool (Adapter->NdisBufferPoolHandle);
+ }
+#endif
+
+} /* IpxCloseNdis */
+
+
+VOID
+IpxOpenAdapterComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN NDIS_STATUS OpenErrorStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that an open adapter
+ is complete. Since we only ever have one outstanding, and then only
+ during initialization, all we do is record the status and set
+ the event to signalled to unblock the initialization thread.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+ OpenErrorStatus - More status information.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+
+ Adapter->NdisRequestStatus = NdisStatus;
+ Adapter->OpenErrorStatus = OpenErrorStatus;
+
+ KeSetEvent(
+ &Adapter->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+} /* IpxOpenAdapterComplete */
+
+VOID
+IpxCloseAdapterComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a close adapter
+ is complete. Currently we don't close adapters, so this is not
+ a problem.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+
+ Adapter->NdisRequestStatus = NdisStatus;
+
+ KeSetEvent(
+ &Adapter->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+} /* IpxCloseAdapterComplete */
+
+
+VOID
+IpxResetComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a reset adapter
+ is complete. Currently we don't reset adapters, so this is not
+ a problem.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(BindingContext);
+ UNREFERENCED_PARAMETER(NdisStatus);
+
+} /* IpxResetComplete */
+
+
+VOID
+IpxRequestComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a request is complete.
+ Since we only ever have one request outstanding, and then only
+ during initialization, all we do is record the status and set
+ the event to signalled to unblock the initialization thread.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisRequest - The object describing the request.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+
+ Adapter->NdisRequestStatus = NdisStatus;
+
+ KeSetEvent(
+ &Adapter->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+} /* IpxRequestComplete */
+
+
+VOID
+IpxStatus(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ )
+
+{
+ PADAPTER Adapter, TmpAdapter;
+
+ PNDIS_WAN_LINE_UP LineUp;
+ PNDIS_WAN_LINE_DOWN LineDown;
+ PIPXCP_CONFIGURATION Configuration; // contains ipx net and node
+
+ BOOLEAN UpdateLineUp;
+ PBINDING Binding, TmpBinding;
+ PDEVICE Device;
+ PADDRESS Address;
+ ULONG CurrentHash;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ PNDIS_BUFFER NdisBuffer;
+ PNWLINK_ACTION NwlinkAction;
+ PIPX_ADDRESS_DATA IpxAddressData;
+ PREQUEST Request;
+ UINT BufferLength;
+ IPX_LINE_INFO LineInfo;
+ ULONG Segment;
+ ULONG LinkSpeed;
+ PLIST_ENTRY p;
+ NTSTATUS Status;
+ UINT i, j;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+ IPX_DEFINE_LOCK_HANDLE (OldIrq)
+ NTSTATUS ntStatus;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ Adapter = (PADAPTER)NdisBindingContext;
+
+ IpxReferenceAdapter(Adapter);
+#else
+ Adapter = (PADAPTER)NdisBindingContext;
+#endif
+
+ Device = Adapter->Device;
+
+ switch (NdisStatus) {
+
+ case NDIS_STATUS_WAN_LINE_UP:
+
+
+ //
+ // If the line is already up, then we are just getting
+ // a change in line conditions, and the IPXCP_CONFIGURATION
+ // information is not included. If it turns out we need
+ // all the info, we check the size again later.
+ //
+
+ if (StatusBufferSize < sizeof(NDIS_WAN_LINE_UP)) {
+ IPX_DEBUG (WAN, ("Line up, status buffer size wrong %d/%d\n", StatusBufferSize, sizeof(NDIS_WAN_LINE_UP)));
+#ifdef _PNP_POWER
+ goto error_no_lock;
+#else
+ return;
+#endif
+ }
+
+ LineUp = (PNDIS_WAN_LINE_UP)StatusBuffer;
+
+ //
+ // We scan through the adapter's NIC ID range looking
+ // for an active binding with the same remote address.
+ //
+
+ UpdateLineUp = FALSE;
+
+ //
+ // See if this is a new lineup or not
+ //
+ *((ULONG UNALIGNED *)(&Binding)) =
+ *((ULONG UNALIGNED *)(&LineUp->LocalAddress[2]));
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+
+ if (Binding != NULL) {
+ UpdateLineUp = TRUE;
+ }
+
+ if (LineUp->ProtocolType != Adapter->BindSap) {
+ IPX_DEBUG (WAN, ("Line up, wrong protocol type %lx\n", LineUp->ProtocolType));
+
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ goto error_no_lock;
+#else
+ return;
+#endif
+ }
+
+ Configuration = (PIPXCP_CONFIGURATION)LineUp->ProtocolBuffer;
+
+ //
+ // PNP_POWER - We hold the exclusive lock to the binding array (thru both the device and adapter)
+ // and the reference to the adapter at this point.
+ //
+
+ //
+ // If this line was previously down, create a new binding
+ // if needed.
+ //
+
+ if (!UpdateLineUp) {
+
+ //
+ // We look for a binding that is allocated but down, if
+ // we can't find that then we look for any empty spot in
+ // the adapter's NIC ID range and allocate a binding in it.
+ // Since we always allocate this way, the allocated
+ // bindings are all clumped at the beginning and once
+ // we find a NULL spot we know there are no more
+ // allocated ones.
+ //
+ // We keep track of the first binding on this adapter
+ // in TmpBinding in case we need config info from it.
+ //
+
+ TmpBinding = NULL;
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (i = Adapter->FirstWanNicId;
+ i <= Adapter->LastWanNicId;
+ i++) {
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ if (TmpBinding == NULL) {
+ TmpBinding = Binding;
+ }
+
+ if ((Binding == NULL) ||
+ (!Binding->LineUp)) {
+ break;
+ }
+ }
+
+ if (i > Adapter->LastWanNicId) {
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IPX_DEBUG (WAN, ("Line up, no WAN binding available\n"));
+ return;
+ }
+
+ if (Binding == NULL) {
+
+ //
+ // We need to allocate one.
+ //
+
+ CTEAssert (TmpBinding != NULL);
+
+#ifdef _PNP_POWER
+ //
+ // CreateBinding does an InterLockedPop with the DeviceLock.
+ // So, release the lock here.
+ //
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+#endif
+ Status = IpxCreateBinding(
+ Device,
+ NULL,
+ 0,
+ Adapter->AdapterName,
+ &Binding);
+
+ if (Status != STATUS_SUCCESS) {
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ IPX_DEBUG (WAN, ("Line up, could not create WAN binding\n"));
+ goto error_no_lock;
+#else
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IPX_DEBUG (WAN, ("Line up, could not create WAN binding\n"));
+ return;
+#endif
+ }
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+#endif
+ //
+ // Binding->AllRouteXXX doesn't matter for WAN.
+ //
+
+ Binding->FrameType = ISN_FRAME_TYPE_ETHERNET_II;
+ Binding->SendFrameHandler = IpxSendFrameWanEthernetII;
+ ++Adapter->BindingCount;
+ Binding->Adapter = Adapter;
+
+ Binding->NicId = i;
+#ifdef _PNP_POWER
+ INSERT_BINDING(Device, i, Binding);
+#else
+ Device->Bindings[i] = Binding;
+#endif
+
+ //
+ // Other fields are filled in below.
+ //
+
+ }
+
+ //
+ // This is not an update, so note that the line is active.
+ //
+ // [FW] Binding->LineUp = TRUE;
+ Binding->LineUp = LINE_UP;
+
+ if (Configuration->ConnectionClient == 1) {
+ Binding->DialOutAsync = TRUE;
+ } else {
+ Binding->DialOutAsync = FALSE;
+ }
+
+ //
+ // Keep track of the highest NIC ID that we should
+ // send type 20s out on.
+ //
+
+ if (i > (UINT)MIN (Device->MaxBindings, Device->HighestType20NicId)) {
+
+ if ((Binding->DialOutAsync) ||
+ ((Device->DisableDialinNetbios & 0x01) == 0)) {
+
+ Device->HighestType20NicId = i;
+ }
+ }
+
+ //
+ // We could error out below, trying to insert this network number. In RipShortTimeout
+ // we dont check for LineUp when calculating the tick counts; set this before the insert
+ // attempt.
+ //
+ Binding->MediumSpeed = LineUp->LinkSpeed;
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // [FW] No need to update these if this flag is on since these values will be
+ // provided with IPX_WAN_CONFIG_DONE ioctl; instead we zero out the fields so that
+ // IPXWAN packets have proper source addresses.
+ //
+ if (Device->ForwarderBound &&
+ Configuration->IpxwanConfigRequired) {
+ Binding->LocalAddress.NetworkAddress = 0;
+ RtlZeroMemory (Binding->LocalAddress.NodeAddress, 6);
+
+ } else {
+
+ //
+ // Add a router entry for this net if there is no router.
+ // We want the number of ticks for a 576-byte frame,
+ // given the link speed in 100 bps units, so we calculate
+ // as:
+ //
+ // seconds 18.21 ticks 4608 bits
+ // --------------------- * ----------- * ---------
+ // link_speed * 100 bits second frame
+ //
+ // to get the formula
+ //
+ // ticks/frame = 839 / link_speed.
+ //
+ // We add link_speed to the numerator also to ensure
+ // that the value is at least 1.
+ //
+
+ if ((!Device->UpperDriverBound[IDENTIFIER_RIP]) &&
+ (*(UNALIGNED ULONG *)Configuration->Network != 0)) {
+ if (RipInsertLocalNetwork(
+ *(UNALIGNED ULONG *)Configuration->Network,
+ Binding->NicId,
+ Adapter->NdisBindingHandle,
+ (USHORT)((839 + LineUp->LinkSpeed) / LineUp->LinkSpeed)) != STATUS_SUCCESS) {
+ //
+ // This means we couldn't allocate memory, or
+ // the entry already existed. If it already
+ // exists we can ignore it for the moment.
+ //
+ // BUGBUG: Now it will succeed if the network
+ // exists.
+ //
+
+ IPX_DEBUG (WAN, ("Line up, could not insert local network\n"));
+ // [FW] Binding->LineUp = FALSE;
+ Binding->LineUp = LINE_DOWN;
+
+ #ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ goto error_no_lock;
+ #else
+ return;
+ #endif
+ }
+ }
+
+
+ //
+ // Update our addresses.
+ //
+ Binding->LocalAddress.NetworkAddress = *(UNALIGNED ULONG *)Configuration->Network;
+ RtlCopyMemory (Binding->LocalAddress.NodeAddress, Configuration->LocalNode, 6);
+ RtlCopyMemory (Binding->WanRemoteNode, Configuration->RemoteNode, 6);
+
+ //
+ // Update the device node and all the address
+ // nodes if we have only one bound, or this is
+ // binding one.
+ //
+
+ if (!Device->VirtualNetwork) {
+
+ if ((!Device->MultiCardZeroVirtual) || (Binding->NicId == 1)) {
+ Device->SourceAddress.NetworkAddress = *(UNALIGNED ULONG *)(Configuration->Network);
+ RtlCopyMemory (Device->SourceAddress.NodeAddress, Configuration->LocalNode, 6);
+ }
+
+ //
+ // Scan through all the addresses that exist and modify
+ // their pre-constructed local IPX address to reflect
+ // the new local net and node.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (CurrentHash = 0; CurrentHash < IPX_ADDRESS_HASH_COUNT; CurrentHash++) {
+
+ for (p = Device->AddressDatabases[CurrentHash].Flink;
+ p != &Device->AddressDatabases[CurrentHash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ Address->LocalAddress.NetworkAddress = *(UNALIGNED ULONG *)Configuration->Network;
+ RtlCopyMemory (Address->LocalAddress.NodeAddress, Configuration->LocalNode, 6);
+ }
+ }
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+ }
+
+ //
+ // Return the binding context for this puppy!
+ //
+ *((ULONG UNALIGNED *)(&LineUp->LocalAddress[2])) =
+ *((ULONG UNALIGNED *)(&Binding));
+
+ RtlCopyMemory (Binding->LocalMacAddress.Address, LineUp->LocalAddress, 6);
+ RtlCopyMemory (Binding->RemoteMacAddress.Address, LineUp->RemoteAddress, 6);
+
+ //
+ // Reset this since the line just came up.
+ //
+
+ Binding->WanInactivityCounter = 0;
+
+ //
+ // [FW] Update the InterfaceIndex and ConnectionId.
+ //
+ Binding->InterfaceIndex = Configuration->InterfaceIndex;
+ Binding->ConnectionId = Configuration->ConnectionId;
+ Binding->IpxwanConfigRequired = Configuration->IpxwanConfigRequired;
+
+ //
+ // [FW] We need to keep track of WAN inactivity counters ourselves.
+ // Every minute, the wan inactivity counters are incremented for all
+ // UP WAN lines.
+ //
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+ if (Device->UpWanLineCount == 0) {
+/*
+ //
+ // [BUGBUGZZ] remove this...
+ //
+ CTEStartTimer(
+ &Device->WanInactivityTimer,
+ 60000, // 1 minute
+ IpxInternalIncrementWanInactivity,
+ (PVOID)Device);
+*/
+ }
+
+ Device->UpWanLineCount++;
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+
+ LinkSpeed = LineUp->LinkSpeed;
+
+ //
+ // Scan through bindings to update Device->LinkSpeed.
+ // If SingleNetworkActive is set, we only count WAN
+ // bindings when doing this (although it is unlikely
+ // a LAN binding would be the winner).
+ //
+ // BUGBUG: Update other device information?
+ //
+
+ for (i = 1; i <= Device->ValidBindings; i++) {
+#ifdef _PNP_POWER
+ if (TmpBinding = NIC_ID_TO_BINDING(Device, i)) {
+#else
+ if (TmpBinding = Device->Bindings[i]) {
+#endif
+ TmpAdapter = TmpBinding->Adapter;
+ if (TmpBinding->LineUp &&
+ (!Device->SingleNetworkActive || TmpAdapter->MacInfo.MediumAsync) &&
+ (TmpBinding->MediumSpeed < LinkSpeed)) {
+ LinkSpeed = TmpBinding->MediumSpeed;
+ }
+ }
+ }
+
+#ifdef _PNP_POWER
+ //
+ // Release the lock after incrementing the reference count
+ //
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ Device->LinkSpeed = LinkSpeed;
+
+ if ((Adapter->ConfigMaxPacketSize == 0) ||
+ (LineUp->MaximumTotalSize < Adapter->ConfigMaxPacketSize)) {
+ Binding->MaxSendPacketSize = LineUp->MaximumTotalSize;
+ } else {
+ Binding->MaxSendPacketSize = Adapter->ConfigMaxPacketSize;
+ }
+ MacInitializeBindingInfo (Binding, Adapter);
+
+ //
+ // [FW] If the IpxwanConfigRequired flag is true, we don't inform
+ // the upper layers until IPXWAN sends down the ioctl to do so.
+ //
+ // Inform IpxWan only if this is not an Update; it will be an update in
+ // the case of multilink. In fact, do not access the Configuration param in
+ // case UpdateLineUp is TRUE.
+ //
+ if (!UpdateLineUp &&
+ Configuration->IpxwanConfigRequired) {
+
+ IPX_DEBUG(WAN, ("IPXWAN configuration required on LineUp: %lx\n", LineUp));
+ CTEAssert(!UpdateLineUp);
+ Binding->LineUp = LINE_CONFIG;
+ goto InformIpxWan;
+ }
+
+#ifdef _PNP_POWER
+
+ //
+ // We dont give lineups; instead indicate only if the PnP reserved address
+ // changed to SPX. NB gets all PnP indications with the reserved address case
+ // marked out.
+ //
+ {
+ IPX_PNP_INFO NBPnPInfo;
+
+ if ((!Device->MultiCardZeroVirtual) || (Binding->NicId == 1)) {
+
+ //
+ // NB's reserved address changed.
+ //
+ NBPnPInfo.NewReservedAddress = TRUE;
+
+ if (!Device->VirtualNetwork) {
+ //
+ // Let SPX know because it fills in its own headers.
+ //
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_PNP_INFO IpxPnPInfo;
+
+ IpxPnPInfo.NewReservedAddress = TRUE;
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_ADDRESS_CHANGE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_ADDRESS_CHANGED to SPX: net addr: %lx\n", Binding->LocalAddress.NetworkAddress));
+ }
+ }
+ } else {
+ NBPnPInfo.NewReservedAddress = FALSE;
+ }
+
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ Binding->IsnInformed[IDENTIFIER_NB] = TRUE;
+
+ NBPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ NBPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ NBPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ NBPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ NBPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ NBPnPInfo.FirstORLastDevice = FALSE;
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ RtlCopyMemory(NBPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(NBPnPInfo.NicHandle, Binding->NicId);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &NBPnPInfo);
+
+ IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_ADD_DEVICE (lineup) to NB: net addr: %lx\n", Binding->LocalAddress.NetworkAddress));
+ }
+
+ //
+ // Register this address with the TDI clients.
+ //
+ RtlCopyMemory (Device->TdiRegistrationAddress->Address, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
+
+ if ((ntStatus = TdiRegisterNetAddress(
+ Device->TdiRegistrationAddress,
+ &Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+
+ IPX_DEBUG(PNP, ("TdiRegisterNetAddress failed: %lx", ntStatus));
+ }
+ }
+
+ //
+ // Indicate to the upper drivers.
+ //
+ LineInfo.LinkSpeed = LineUp->LinkSpeed;
+ LineInfo.MaximumPacketSize = LineUp->MaximumTotalSize - 14;
+ LineInfo.MaximumSendSize = LineUp->MaximumTotalSize - 14;
+ LineInfo.MacOptions = Adapter->MacInfo.MacOptions;
+
+ //
+ // Give line up to RIP as it is not PnP aware.
+ // Give lineup to FWD only if it opened this adapter first.
+ //
+ if (Device->UpperDriverBound[IDENTIFIER_RIP]) {
+
+ //
+ // Line status, after lineup.
+ //
+ if (UpdateLineUp) {
+ //
+ // was the lineup given earlier? if not, then dont send this up.
+ //
+ if (Binding->IsnInformed[IDENTIFIER_RIP]) {
+ CTEAssert(Binding->FwdAdapterContext);
+
+ (*Device->UpperDrivers[IDENTIFIER_RIP].LineUpHandler)(
+ Binding->NicId,
+ &LineInfo,
+ NdisMediumWan,
+ NULL);
+ }
+
+ } else {
+ Binding->IsnInformed[IDENTIFIER_RIP] = TRUE;
+ (*Device->UpperDrivers[IDENTIFIER_RIP].LineUpHandler)(
+ Binding->NicId,
+ &LineInfo,
+ NdisMediumWan,
+ Configuration);
+ }
+ }
+#else
+ //
+ // Indicate to the upper drivers.
+ //
+ LineInfo.LinkSpeed = LineUp->LinkSpeed;
+ LineInfo.MaximumPacketSize = LineUp->MaximumTotalSize - 14;
+ LineInfo.MaximumSendSize = LineUp->MaximumTotalSize - 14;
+ LineInfo.MacOptions = Adapter->MacInfo.MacOptions;
+ for (i = 0; i < UPPER_DRIVER_COUNT; i++) {
+
+ if (Device->UpperDriverBound[i]) {
+ (*Device->UpperDrivers[i].LineUpHandler)(
+ Binding->NicId,
+ &LineInfo,
+ NdisMediumWan,
+ UpdateLineUp ? NULL : Configuration);
+ }
+ }
+#endif
+ if (!UpdateLineUp) {
+
+ if ((Device->SingleNetworkActive) &&
+ (Configuration->ConnectionClient == 1)) {
+ //
+ // Drop all entries in the database if rip is not bound.
+ //
+
+ if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ RipDropRemoteEntries();
+ }
+
+ Device->ActiveNetworkWan = TRUE;
+
+ //
+ // Find a queued line change and complete it.
+ //
+
+ if ((p = ExInterlockedRemoveHeadList(
+ &Device->LineChangeQueue,
+ &Device->Lock)) != NULL) {
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_LINE_CHANGE);
+
+ }
+
+ //
+ // If we have a virtual net, do a broadcast now so
+ // the router on the other end will know about us.
+ //
+ // BUGBUG: Use RipSendResponse, and do it even
+ // if SingleNetworkActive is FALSE??
+ //
+
+ if (Device->RipResponder) {
+ (VOID)RipQueueRequest (Device->VirtualNetworkNumber, RIP_RESPONSE);
+ }
+
+ }
+
+ //
+ // Find a queued address notify and complete it.
+ // If WanGlobalNetworkNumber is TRUE, we only do
+ // this when the first dialin line comes up.
+ //
+
+ if ((!Device->WanGlobalNetworkNumber ||
+ (!Device->GlobalNetworkIndicated && !Binding->DialOutAsync))
+ &&
+ ((p = ExInterlockedRemoveHeadList(
+ &Device->AddressNotifyQueue,
+ &Device->Lock)) != NULL)) {
+
+ if (Device->WanGlobalNetworkNumber) {
+ Device->GlobalWanNetwork = Binding->LocalAddress.NetworkAddress;
+ Device->GlobalNetworkIndicated = TRUE;
+ }
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+ NdisBuffer = REQUEST_NDIS_BUFFER(Request);
+ NdisQueryBuffer (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength);
+
+ IpxAddressData = (PIPX_ADDRESS_DATA)(NwlinkAction->Data);
+
+ if (Device->WanGlobalNetworkNumber) {
+ IpxAddressData->adapternum = Device->SapNicCount - 1;
+ } else {
+ IpxAddressData->adapternum = Binding->NicId - 1;
+ }
+ *(UNALIGNED ULONG *)IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
+ IpxAddressData->wan = TRUE;
+ IpxAddressData->status = TRUE;
+ IpxAddressData->maxpkt = Binding->AnnouncedMaxDatagramSize; // BUGBUG: Use real?
+ IpxAddressData->linkspeed = Binding->MediumSpeed;
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_ADDRESS_NOTIFY);
+ }
+
+InformIpxWan:
+ Binding->fInfoIndicated = FALSE;
+ if ((p = ExInterlockedRemoveHeadList(
+ &Device->NicNtfQueue,
+ &Device->Lock)) != NULL)
+ {
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ DbgPrint("IpxStatus: WAN LINE UP\n");
+ Status = GetNewNics(Device, Request, FALSE, NULL, 0, FALSE);
+ if (Status != STATUS_SUCCESS)
+ {
+ DbgPrint("WAN Line up screw up\n");
+ }
+ else
+ {
+ IoAcquireCancelSpinLock(&OldIrq);
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ IoReleaseCancelSpinLock(OldIrq);
+
+ REQUEST_STATUS(Request) = Status;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+ IpxDereferenceDevice (Device, DREF_NIC_NOTIFY);
+ }
+
+ }
+ }
+
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ break;
+
+ case NDIS_STATUS_WAN_LINE_DOWN:
+
+ if (StatusBufferSize < sizeof(NDIS_WAN_LINE_DOWN)) {
+ IPX_DEBUG (WAN, ("Line down, status buffer size wrong %d/%d\n", StatusBufferSize, sizeof(NDIS_WAN_LINE_DOWN)));
+ return;
+ }
+
+ LineDown = (PNDIS_WAN_LINE_DOWN)StatusBuffer;
+
+ *((ULONG UNALIGNED*)(&Binding)) = *((ULONG UNALIGNED*)(&LineDown->LocalAddress[2]));
+
+ CTEAssert(Binding != NULL);
+
+ //
+ // Note that the WAN line is down.
+ //
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+
+ // [FW] Binding->LineUp = FALSE;
+ Binding->LineUp = LINE_DOWN;
+
+ //
+ // PNP_POWER - we hold the exclusive lock to the binding
+ // and reference to the adapter at this point.
+ //
+
+ //
+ // Keep track of the highest NIC ID that we should
+ // send type 20s out on.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (Binding->NicId == MIN (Device->MaxBindings, Device->HighestType20NicId)) {
+
+ //
+ // This was the old limit, so we have to scan
+ // backwards to update it -- we stop when we hit
+ // a non-WAN binding, or a wan binding that is up and
+ // dialout, or any wan binding if bit 1 in
+ // DisableDialinNetbios is off.
+ //
+
+ for (i = Binding->NicId-1; i >= 1; i--) {
+#ifdef _PNP_POWER
+ TmpBinding = NIC_ID_TO_BINDING(Device, i);
+#else
+ TmpBinding = Device->Bindings[i];
+#endif
+
+ if ((TmpBinding != NULL) &&
+ ((!TmpBinding->Adapter->MacInfo.MediumAsync) ||
+ (TmpBinding->LineUp &&
+ ((Binding->DialOutAsync) ||
+ ((Device->DisableDialinNetbios & 0x01) == 0))))) {
+
+ break;
+ }
+ }
+
+ Device->HighestType20NicId = i;
+
+ }
+
+
+ //
+ // Scan through bindings to update Device->LinkSpeed.
+ // If SingleNetworkActive is set, we only count LAN
+ // bindings when doing this.
+ //
+ // BUGBUG: Update other device information?
+ //
+
+ LinkSpeed = 0xffffffff;
+ for (i = 1; i <= Device->ValidBindings; i++) {
+#ifdef _PNP_POWER
+ if (TmpBinding = NIC_ID_TO_BINDING(Device, i)) {
+#else
+ if (TmpBinding = Device->Bindings[i]) {
+#endif
+ TmpAdapter = TmpBinding->Adapter;
+ if (TmpBinding->LineUp &&
+ (!Device->SingleNetworkActive || !TmpAdapter->MacInfo.MediumAsync) &&
+ (TmpBinding->MediumSpeed < LinkSpeed)) {
+ LinkSpeed = TmpBinding->MediumSpeed;
+ }
+ }
+ }
+
+ if (LinkSpeed != 0xffffffff) {
+ Device->LinkSpeed = LinkSpeed;
+ }
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ //
+ // Remove our router entry for this net.
+ //
+
+ //
+ // [FW] if this was a line on which IPXWAN config was happening, then we dont do this.
+ //
+ if (!Binding->IpxwanConfigRequired &&
+ !Device->UpperDriverBound[IDENTIFIER_RIP]) {
+
+ Segment = RipGetSegment ((PUCHAR)&Binding->LocalAddress.NetworkAddress);
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ RouteEntry = RipGetRoute (Segment, (PUCHAR)&Binding->LocalAddress.NetworkAddress);
+
+ if (RouteEntry != (PIPX_ROUTE_ENTRY)NULL) {
+
+ RipDeleteRoute (Segment, RouteEntry);
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ IpxFreeMemory (RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+
+ } else {
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ }
+
+ RipAdjustForBindingChange (Binding->NicId, 0, IpxBindingDown);
+
+ }
+
+ //
+ // [FW] If this was the last UpWanLine, cancel the inactivity timer.
+ //
+ /*
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+ if (--Device->UpWanLineCount == 0) {
+ if (!CTEStopTimer (&IpxDevice->WanInactivityTimer)) {
+ DbgPrint("Could not stop the WanInactivityTimer\n");
+ DbgBreakPoint();
+ }
+ }
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ */
+
+ //
+ // If this was a line on which IPXWAN config was going on, then we need to tell only the
+ // IPXWAN layer that the line went down since none of the other clients were informed of
+ // the line up in the first place.
+ //
+ if (Binding->IpxwanConfigRequired) {
+ goto InformIpxWan1;
+ }
+
+ //
+ // Indicate to the upper drivers.
+ //
+#ifdef _PNP_POWER
+
+ //
+ // DeRegister this address with the TDI clients.
+ //
+ {
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ CTEAssert(Binding->TdiRegistrationHandle);
+
+ if ((ntStatus = TdiDeregisterNetAddress(Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("TdiDeRegisterNetAddress failed: %lx", ntStatus));
+ }
+
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_PNP_INFO NBPnPInfo;
+
+ CTEAssert(Binding->IsnInformed[IDENTIFIER_NB]);
+
+ NBPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ NBPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ NBPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ NBPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ NBPnPInfo.NewReservedAddress = FALSE;
+ NBPnPInfo.FirstORLastDevice = FALSE;
+
+ NBPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+
+ RtlCopyMemory(NBPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(NBPnPInfo.NicHandle, Binding->NicId);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_DELETE_DEVICE,
+ &NBPnPInfo);
+
+ IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_DELETE_DEVICE (linedown) to NB: addr: %lx\n", Binding->LocalAddress.NetworkAddress));
+ } else {
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+ }
+
+ //
+ // Indicate to the Fwd only if it opened this adapter first.
+ //
+ if (Device->UpperDriverBound[IDENTIFIER_RIP] &&
+ (!Device->ForwarderBound || Binding->FwdAdapterContext)) {
+
+ (*Device->UpperDrivers[IDENTIFIER_RIP].LineDownHandler)(
+ Binding->NicId,
+ Binding->FwdAdapterContext);
+
+ CTEAssert(Binding->IsnInformed[IDENTIFIER_RIP]);
+
+ Binding->IsnInformed[IDENTIFIER_RIP] = FALSE;
+ }
+#else
+ for (i = 0; i < UPPER_DRIVER_COUNT; i++) {
+
+ if (Device->UpperDriverBound[i]) {
+ (*Device->UpperDrivers[i].LineDownHandler)(
+ Binding->NicId);
+ }
+ }
+#endif
+
+ if ((Device->SingleNetworkActive) &&
+ (Binding->DialOutAsync)) {
+
+ //
+ // Drop all entries in the database if rip is not bound.
+ //
+
+ if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ RipDropRemoteEntries();
+ }
+
+ Device->ActiveNetworkWan = FALSE;
+
+ //
+ // Find a queued line change and complete it.
+ //
+
+ if ((p = ExInterlockedRemoveHeadList(
+ &Device->LineChangeQueue,
+ &Device->Lock)) != NULL) {
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_LINE_CHANGE);
+
+ }
+
+ }
+
+ //
+ // Find a queued address notify and complete it.
+ //
+
+ if ((!Device->WanGlobalNetworkNumber) &&
+ ((p = ExInterlockedRemoveHeadList(
+ &Device->AddressNotifyQueue,
+ &Device->Lock)) != NULL)) {
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+ NdisBuffer = REQUEST_NDIS_BUFFER(Request);
+ NdisQueryBuffer (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength);
+
+ IpxAddressData = (PIPX_ADDRESS_DATA)(NwlinkAction->Data);
+
+ IpxAddressData->adapternum = Binding->NicId - 1;
+ *(UNALIGNED ULONG *)IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
+ IpxAddressData->wan = TRUE;
+ IpxAddressData->status = FALSE;
+ IpxAddressData->maxpkt = Binding->AnnouncedMaxDatagramSize; // BUGBUG: Use real?
+ IpxAddressData->linkspeed = Binding->MediumSpeed;
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_ADDRESS_NOTIFY);
+ }
+
+InformIpxWan1:
+ Binding->fInfoIndicated = FALSE;
+ if ((p = ExInterlockedRemoveHeadList(
+ &Device->NicNtfQueue,
+ &Device->Lock)) != NULL)
+ {
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+ DbgPrint("IpxStatus: WAN LINE DOWN\n");
+
+ Status = GetNewNics(Device, Request, FALSE, NULL, 0, FALSE);
+ if (Status != STATUS_SUCCESS)
+ {
+ DbgPrint("WAN Line down screw up\n");
+ }
+ else
+ {
+ IoAcquireCancelSpinLock(&OldIrq);
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ IoReleaseCancelSpinLock(OldIrq);
+
+ REQUEST_STATUS(Request) = Status;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request); //noop
+ IpxDereferenceDevice (Device, DREF_NIC_NOTIFY);
+ }
+ }
+
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ break;
+
+ case NDIS_STATUS_WAN_FRAGMENT:
+
+ //
+ // No response needed, IPX is a datagram service.
+ //
+ // BUGBUG: What about telling Netbios/SPX?
+ //
+
+ break;
+
+ default:
+
+ break;
+
+ }
+
+#ifdef _PNP_POWER
+error_no_lock:
+ IpxDereferenceAdapter(Adapter);
+#endif
+
+} /* IpxStatus */
+
+
+VOID
+IpxStatusComplete(
+ IN NDIS_HANDLE NdisBindingContext
+ )
+{
+ UNREFERENCED_PARAMETER (NdisBindingContext);
+
+} /* IpxStatusComplete */
+
+
+
diff --git a/private/ntos/tdi/isn/ipx/nwlnkipx.ini b/private/ntos/tdi/isn/ipx/nwlnkipx.ini
new file mode 100644
index 000000000..416f0c6b7
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/nwlnkipx.ini
@@ -0,0 +1,191 @@
+\Registry\Machine\System\CurrentControlSet\Services\NwlnkIpx
+ Type = REG_DWORD 0x00000001
+ Start = REG_DWORD 0x00000003
+ ErrorControl = REG_DWORD 0x00000001
+ ImagePath = REG_EXPAND_SZ \SystemRoot\System32\drivers\nwlnkipx.sys
+ DisplayName = NWLINK2 IPX Protocol
+ Group = TDI
+ DependOnService = REG_MULTI_SZ
+ DependOnGroup = REG_MULTI_SZ "NDIS"
+ Linkage
+ Bind = REG_MULTI_SZ "\Device\Elnkii1"
+ Export = REG_MULTI_SZ "\Device\NwlnkIpx"
+ Route = REG_MULTI_SZ ""Elnkii" "Elnkii1""
+ Disabled
+ Bind = REG_MULTI_SZ
+ Export = REG_MULTI_SZ
+ Route = REG_MULTI_SZ
+ NetConfig
+ Elnkii1
+ NetworkNumber = REG_MULTI_SZ "0"
+ PktType = REG_MULTI_SZ "1"
+ BindSap = REG_DWORD 0x00008137
+ SourceRouting = REG_DWORD 0x00000001
+ SourceRouteDef = REG_DWORD 0x00000000
+ SourceRouteBcast = REG_DWORD 0x00000000
+ SourceRouteMcast = REG_DWORD 0x00000000
+ EnableFuncaddr = REG_DWORD 0x00000001
+ MaxPktSize = REG_DWORD 0x00000000
+ Netcard2
+ NetworkNumber = REG_MULTI_SZ "0"
+ PktType = REG_MULTI_SZ "1"
+ BindSap = REG_DWORD 0x00008137
+ SourceRouting = REG_DWORD 0x00000001
+ SourceRouteDef = REG_DWORD 0x00000000
+ SourceRouteBcast = REG_DWORD 0x00000000
+ SourceRouteMcast = REG_DWORD 0x00000000
+ EnableFuncaddr = REG_DWORD 0x00000001
+ MaxPktSize = REG_DWORD 0x00000000
+ Netcard3
+ NetworkNumber = REG_MULTI_SZ "0"
+ PktType = REG_MULTI_SZ "1"
+ BindSap = REG_DWORD 0x00008137
+ SourceRouting = REG_DWORD 0x00000001
+ SourceRouteDef = REG_DWORD 0x00000000
+ SourceRouteBcast = REG_DWORD 0x00000000
+ SourceRouteMcast = REG_DWORD 0x00000000
+ EnableFuncaddr = REG_DWORD 0x00000001
+ MaxPktSize = REG_DWORD 0x00000000
+ Netcard4
+ NetworkNumber = REG_MULTI_SZ "0"
+ PktType = REG_MULTI_SZ "1"
+ BindSap = REG_DWORD 0x00008137
+ SourceRouting = REG_DWORD 0x00000001
+ SourceRouteDef = REG_DWORD 0x00000000
+ SourceRouteBcast = REG_DWORD 0x00000000
+ SourceRouteMcast = REG_DWORD 0x00000000
+ EnableFuncaddr = REG_DWORD 0x00000001
+ MaxPktSize = REG_DWORD 0x00000000
+ Netcard5
+ NetworkNumber = REG_MULTI_SZ "0"
+ PktType = REG_MULTI_SZ "1"
+ BindSap = REG_DWORD 0x00008137
+ SourceRouting = REG_DWORD 0x00000001
+ SourceRouteDef = REG_DWORD 0x00000000
+ SourceRouteBcast = REG_DWORD 0x00000000
+ SourceRouteMcast = REG_DWORD 0x00000000
+ EnableFuncaddr = REG_DWORD 0x00000001
+ MaxPktSize = REG_DWORD 0x00000000
+ Parameters
+ DedicatedRouter = REG_DWORD 0x00000000
+ InitDatagrams = REG_DWORD 0x0000000a
+ MaxDatagrams = REG_DWORD 0x00000032
+ RipAgeTime = REG_DWORD 0x00000005
+ RipCount = REG_DWORD 0x00000005
+ RipTimeout = REG_DWORD 0x00000001
+ RipUsageTime = REG_DWORD 0x0000000f
+ SourceRouteUsageTime = REG_DWORD 0x0000000a
+ SocketUniqueness = REG_DWORD 0x00000008
+ VirtualNetworkNumber = REG_DWORD 0x00000000
+ VirtualNetworkOptional = REG_DWORD 0x00000001
+ Winsock
+ Mapping = REG_BINARY 0x00000c08
+ 0x00000100 0x00000003 0x00000006 0x00000002 0x000003e8 0x00000006 0x00000002 0x000003e9
+ 0x00000006 0x00000002 0x000003ea 0x00000006 0x00000002 0x000003eb 0x00000006 0x00000002
+ 0x000003ec 0x00000006 0x00000002 0x000003ed 0x00000006 0x00000002 0x000003ee 0x00000006
+ 0x00000002 0x000003ef 0x00000006 0x00000002 0x000003f0 0x00000006 0x00000002 0x000003f1
+ 0x00000006 0x00000002 0x000003f2 0x00000006 0x00000002 0x000003f3 0x00000006 0x00000002
+ 0x000003f4 0x00000006 0x00000002 0x000003f5 0x00000006 0x00000002 0x000003f6 0x00000006
+ 0x00000002 0x000003f7 0x00000006 0x00000002 0x000003f8 0x00000006 0x00000002 0x000003f9
+ 0x00000006 0x00000002 0x000003fa 0x00000006 0x00000002 0x000003fb 0x00000006 0x00000002
+ 0x000003fc 0x00000006 0x00000002 0x000003fd 0x00000006 0x00000002 0x000003fe 0x00000006
+ 0x00000002 0x000003ff 0x00000006 0x00000002 0x00000400 0x00000006 0x00000002 0x00000401
+ 0x00000006 0x00000002 0x00000402 0x00000006 0x00000002 0x00000403 0x00000006 0x00000002
+ 0x00000404 0x00000006 0x00000002 0x00000405 0x00000006 0x00000002 0x00000406 0x00000006
+ 0x00000002 0x00000407 0x00000006 0x00000002 0x00000408 0x00000006 0x00000002 0x00000409
+ 0x00000006 0x00000002 0x0000040a 0x00000006 0x00000002 0x0000040b 0x00000006 0x00000002
+ 0x0000040c 0x00000006 0x00000002 0x0000040d 0x00000006 0x00000002 0x0000040e 0x00000006
+ 0x00000002 0x0000040f 0x00000006 0x00000002 0x00000410 0x00000006 0x00000002 0x00000411
+ 0x00000006 0x00000002 0x00000412 0x00000006 0x00000002 0x00000413 0x00000006 0x00000002
+ 0x00000414 0x00000006 0x00000002 0x00000415 0x00000006 0x00000002 0x00000416 0x00000006
+ 0x00000002 0x00000417 0x00000006 0x00000002 0x00000418 0x00000006 0x00000002 0x00000419
+ 0x00000006 0x00000002 0x0000041a 0x00000006 0x00000002 0x0000041b 0x00000006 0x00000002
+ 0x0000041c 0x00000006 0x00000002 0x0000041d 0x00000006 0x00000002 0x0000041e 0x00000006
+ 0x00000002 0x0000041f 0x00000006 0x00000002 0x00000420 0x00000006 0x00000002 0x00000421
+ 0x00000006 0x00000002 0x00000422 0x00000006 0x00000002 0x00000423 0x00000006 0x00000002
+ 0x00000424 0x00000006 0x00000002 0x00000425 0x00000006 0x00000002 0x00000426 0x00000006
+ 0x00000002 0x00000427 0x00000006 0x00000002 0x00000428 0x00000006 0x00000002 0x00000429
+ 0x00000006 0x00000002 0x0000042a 0x00000006 0x00000002 0x0000042b 0x00000006 0x00000002
+ 0x0000042c 0x00000006 0x00000002 0x0000042d 0x00000006 0x00000002 0x0000042e 0x00000006
+ 0x00000002 0x0000042f 0x00000006 0x00000002 0x00000430 0x00000006 0x00000002 0x00000431
+ 0x00000006 0x00000002 0x00000432 0x00000006 0x00000002 0x00000433 0x00000006 0x00000002
+ 0x00000434 0x00000006 0x00000002 0x00000435 0x00000006 0x00000002 0x00000436 0x00000006
+ 0x00000002 0x00000437 0x00000006 0x00000002 0x00000438 0x00000006 0x00000002 0x00000439
+ 0x00000006 0x00000002 0x0000043a 0x00000006 0x00000002 0x0000043b 0x00000006 0x00000002
+ 0x0000043c 0x00000006 0x00000002 0x0000043d 0x00000006 0x00000002 0x0000043e 0x00000006
+ 0x00000002 0x0000043f 0x00000006 0x00000002 0x00000440 0x00000006 0x00000002 0x00000441
+ 0x00000006 0x00000002 0x00000442 0x00000006 0x00000002 0x00000443 0x00000006 0x00000002
+ 0x00000444 0x00000006 0x00000002 0x00000445 0x00000006 0x00000002 0x00000446 0x00000006
+ 0x00000002 0x00000447 0x00000006 0x00000002 0x00000448 0x00000006 0x00000002 0x00000449
+ 0x00000006 0x00000002 0x0000044a 0x00000006 0x00000002 0x0000044b 0x00000006 0x00000002
+ 0x0000044c 0x00000006 0x00000002 0x0000044d 0x00000006 0x00000002 0x0000044e 0x00000006
+ 0x00000002 0x0000044f 0x00000006 0x00000002 0x00000450 0x00000006 0x00000002 0x00000451
+ 0x00000006 0x00000002 0x00000452 0x00000006 0x00000002 0x00000453 0x00000006 0x00000002
+ 0x00000454 0x00000006 0x00000002 0x00000455 0x00000006 0x00000002 0x00000456 0x00000006
+ 0x00000002 0x00000457 0x00000006 0x00000002 0x00000458 0x00000006 0x00000002 0x00000459
+ 0x00000006 0x00000002 0x0000045a 0x00000006 0x00000002 0x0000045b 0x00000006 0x00000002
+ 0x0000045c 0x00000006 0x00000002 0x0000045d 0x00000006 0x00000002 0x0000045e 0x00000006
+ 0x00000002 0x0000045f 0x00000006 0x00000002 0x00000460 0x00000006 0x00000002 0x00000461
+ 0x00000006 0x00000002 0x00000462 0x00000006 0x00000002 0x00000463 0x00000006 0x00000002
+ 0x00000464 0x00000006 0x00000002 0x00000465 0x00000006 0x00000002 0x00000466 0x00000006
+ 0x00000002 0x00000467 0x00000006 0x00000002 0x00000468 0x00000006 0x00000002 0x00000469
+ 0x00000006 0x00000002 0x0000046a 0x00000006 0x00000002 0x0000046b 0x00000006 0x00000002
+ 0x0000046c 0x00000006 0x00000002 0x0000046d 0x00000006 0x00000002 0x0000046e 0x00000006
+ 0x00000002 0x0000046f 0x00000006 0x00000002 0x00000470 0x00000006 0x00000002 0x00000471
+ 0x00000006 0x00000002 0x00000472 0x00000006 0x00000002 0x00000473 0x00000006 0x00000002
+ 0x00000474 0x00000006 0x00000002 0x00000475 0x00000006 0x00000002 0x00000476 0x00000006
+ 0x00000002 0x00000477 0x00000006 0x00000002 0x00000478 0x00000006 0x00000002 0x00000479
+ 0x00000006 0x00000002 0x0000047a 0x00000006 0x00000002 0x0000047b 0x00000006 0x00000002
+ 0x0000047c 0x00000006 0x00000002 0x0000047d 0x00000006 0x00000002 0x0000047e 0x00000006
+ 0x00000002 0x0000047f 0x00000006 0x00000002 0x00000480 0x00000006 0x00000002 0x00000481
+ 0x00000006 0x00000002 0x00000482 0x00000006 0x00000002 0x00000483 0x00000006 0x00000002
+ 0x00000484 0x00000006 0x00000002 0x00000485 0x00000006 0x00000002 0x00000486 0x00000006
+ 0x00000002 0x00000487 0x00000006 0x00000002 0x00000488 0x00000006 0x00000002 0x00000489
+ 0x00000006 0x00000002 0x0000048a 0x00000006 0x00000002 0x0000048b 0x00000006 0x00000002
+ 0x0000048c 0x00000006 0x00000002 0x0000048d 0x00000006 0x00000002 0x0000048e 0x00000006
+ 0x00000002 0x0000048f 0x00000006 0x00000002 0x00000490 0x00000006 0x00000002 0x00000491
+ 0x00000006 0x00000002 0x00000492 0x00000006 0x00000002 0x00000493 0x00000006 0x00000002
+ 0x00000494 0x00000006 0x00000002 0x00000495 0x00000006 0x00000002 0x00000496 0x00000006
+ 0x00000002 0x00000497 0x00000006 0x00000002 0x00000498 0x00000006 0x00000002 0x00000499
+ 0x00000006 0x00000002 0x0000049a 0x00000006 0x00000002 0x0000049b 0x00000006 0x00000002
+ 0x0000049c 0x00000006 0x00000002 0x0000049d 0x00000006 0x00000002 0x0000049e 0x00000006
+ 0x00000002 0x0000049f 0x00000006 0x00000002 0x000004a0 0x00000006 0x00000002 0x000004a1
+ 0x00000006 0x00000002 0x000004a2 0x00000006 0x00000002 0x000004a3 0x00000006 0x00000002
+ 0x000004a4 0x00000006 0x00000002 0x000004a5 0x00000006 0x00000002 0x000004a6 0x00000006
+ 0x00000002 0x000004a7 0x00000006 0x00000002 0x000004a8 0x00000006 0x00000002 0x000004a9
+ 0x00000006 0x00000002 0x000004aa 0x00000006 0x00000002 0x000004ab 0x00000006 0x00000002
+ 0x000004ac 0x00000006 0x00000002 0x000004ad 0x00000006 0x00000002 0x000004ae 0x00000006
+ 0x00000002 0x000004af 0x00000006 0x00000002 0x000004b0 0x00000006 0x00000002 0x000004b1
+ 0x00000006 0x00000002 0x000004b2 0x00000006 0x00000002 0x000004b3 0x00000006 0x00000002
+ 0x000004b4 0x00000006 0x00000002 0x000004b5 0x00000006 0x00000002 0x000004b6 0x00000006
+ 0x00000002 0x000004b7 0x00000006 0x00000002 0x000004b8 0x00000006 0x00000002 0x000004b9
+ 0x00000006 0x00000002 0x000004ba 0x00000006 0x00000002 0x000004bb 0x00000006 0x00000002
+ 0x000004bc 0x00000006 0x00000002 0x000004bd 0x00000006 0x00000002 0x000004be 0x00000006
+ 0x00000002 0x000004bf 0x00000006 0x00000002 0x000004c0 0x00000006 0x00000002 0x000004c1
+ 0x00000006 0x00000002 0x000004c2 0x00000006 0x00000002 0x000004c3 0x00000006 0x00000002
+ 0x000004c4 0x00000006 0x00000002 0x000004c5 0x00000006 0x00000002 0x000004c6 0x00000006
+ 0x00000002 0x000004c7 0x00000006 0x00000002 0x000004c8 0x00000006 0x00000002 0x000004c9
+ 0x00000006 0x00000002 0x000004ca 0x00000006 0x00000002 0x000004cb 0x00000006 0x00000002
+ 0x000004cc 0x00000006 0x00000002 0x000004cd 0x00000006 0x00000002 0x000004ce 0x00000006
+ 0x00000002 0x000004cf 0x00000006 0x00000002 0x000004d0 0x00000006 0x00000002 0x000004d1
+ 0x00000006 0x00000002 0x000004d2 0x00000006 0x00000002 0x000004d3 0x00000006 0x00000002
+ 0x000004d4 0x00000006 0x00000002 0x000004d5 0x00000006 0x00000002 0x000004d6 0x00000006
+ 0x00000002 0x000004d7 0x00000006 0x00000002 0x000004d8 0x00000006 0x00000002 0x000004d9
+ 0x00000006 0x00000002 0x000004da 0x00000006 0x00000002 0x000004db 0x00000006 0x00000002
+ 0x000004dc 0x00000006 0x00000002 0x000004dd 0x00000006 0x00000002 0x000004de 0x00000006
+ 0x00000002 0x000004df 0x00000006 0x00000002 0x000004e0 0x00000006 0x00000002 0x000004e1
+ 0x00000006 0x00000002 0x000004e2 0x00000006 0x00000002 0x000004e3 0x00000006 0x00000002
+ 0x000004e4 0x00000006 0x00000002 0x000004e5 0x00000006 0x00000002 0x000004e6 0x00000006
+ 0x00000002 0x000004e7
+
+ HelperDllName = REG_EXPAND_SZ %SystemRoot%\system32\wshisn.dll
+ MinSockaddrLength = REG_DWORD 0x0000000e
+ MaxSockaddrLength = REG_DWORD 0x00000010
+ Performance
+ Library = Perfctrs.dll
+ Open = OpenNbfPerformanceData
+ Collect = CollectNbfPerformanceData
+ Close = CloseNbfPerformanceData
+\Registry\Machine\System\CurrentControlSet\Services\EventLog\System\NwlnkIpx
+ EventMessageFile = REG_EXPAND_SZ %SystemRoot%\System32\netevent.dll
+ TypesSupported = REG_DWORD 0x00000007
diff --git a/private/ntos/tdi/isn/ipx/nwlnkipx.rc b/private/ntos/tdi/isn/ipx/nwlnkipx.rc
new file mode 100644
index 000000000..0f437a15d
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/nwlnkipx.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "NWLINK2 IPX Protocol Driver"
+#define VER_INTERNALNAME_STR "nwlnkipx.sys"
+#define VER_ORIGINALFILENAME_STR "nwlnkipx.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/tdi/isn/ipx/packet.c b/private/ntos/tdi/isn/ipx/packet.c
new file mode 100644
index 000000000..f70154b03
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/packet.c
@@ -0,0 +1,1560 @@
+/*++
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ packet.c
+
+Abstract:
+
+ This module contains code that implements the SEND_PACKET and
+ RECEIVE_PACKET objects, which describe NDIS packets used
+ by the transport.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+NTSTATUS
+IpxInitializeSendPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet,
+ IN PUCHAR Header
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a send packet by chaining the
+ buffer for the header on it.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to initialize.
+
+ Header - Points to storage for the header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ NTSTATUS Status;
+ PNDIS_BUFFER NdisMacBuffer;
+ PNDIS_BUFFER NdisIpxBuffer;
+ PIPX_SEND_RESERVED Reserved;
+
+ IpxAllocateSendPacket (Device, Packet, &Status);
+
+ if (Status != STATUS_SUCCESS) {
+ // ERROR LOG
+ return Status;
+ }
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisMacBuffer,
+ Device->NdisBufferPoolHandle,
+ Header,
+ MAC_HEADER_SIZE);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxFreeSendPacket (Device, Packet);
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisIpxBuffer,
+ Device->NdisBufferPoolHandle,
+ Header + MAC_HEADER_SIZE,
+ IPX_HEADER_SIZE + RIP_PACKET_SIZE);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxFreeSendPacket (Device, Packet);
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NdisChainBufferAtFront (PACKET(Packet), NdisMacBuffer);
+ NdisChainBufferAtBack (PACKET(Packet), NdisIpxBuffer);
+
+ //
+ // This flag optimizes the virtual to physical address X-ln
+ // in the MAC drivers on x86
+ //
+ NdisMacBuffer->MdlFlags|=MDL_NETWORK_HEADER;
+ NdisIpxBuffer->MdlFlags|=MDL_NETWORK_HEADER;
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->Identifier = IDENTIFIER_IPX;
+ Reserved->SendInProgress = FALSE;
+ Reserved->Header = Header;
+ Reserved->HeaderBuffer = NdisMacBuffer;
+ Reserved->PaddingBuffer = NULL;
+#if BACK_FILL
+ Reserved->BackFill = FALSE;
+#endif
+
+ ExInterlockedInsertHeadList(
+ &Device->GlobalSendPacketList,
+ &Reserved->GlobalLinkage,
+ &Device->Lock);
+
+ return STATUS_SUCCESS;
+
+} /* IpxInitializeSendPacket */
+
+#if BACK_FILL
+NTSTATUS
+IpxInitializeBackFillPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet,
+ IN PUCHAR Header
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a send packet by chaining the
+ buffer for the header on it.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to initialize.
+
+ Header - Points to storage for the header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ NTSTATUS Status;
+ PNDIS_BUFFER NdisMacBuffer;
+ PNDIS_BUFFER NdisIpxBuffer;
+ PIPX_SEND_RESERVED Reserved;
+
+
+ IPX_DEBUG (PACKET, ("Initializing backfill packet\n"));
+ IpxAllocateSendPacket (Device, Packet, &Status);
+
+ if (Status != STATUS_SUCCESS) {
+ // ERROR LOG
+ return Status;
+ }
+
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->Identifier = IDENTIFIER_IPX;
+ Reserved->SendInProgress = FALSE;
+ Reserved->Header = NULL;
+ Reserved->HeaderBuffer = NULL;
+ Reserved->PaddingBuffer = NULL;
+ Reserved->BackFill = TRUE;
+
+ ExInterlockedInsertHeadList(
+ &Device->GlobalBackFillPacketList,
+ &Reserved->GlobalLinkage,
+ &Device->Lock);
+
+ IPX_DEBUG (PACKET, ("Initializing backfill packet Done\n"));
+ return STATUS_SUCCESS;
+
+} /* IpxInitializeBackFillPacket */
+#endif
+
+
+NTSTATUS
+IpxInitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PIPX_RECEIVE_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to initialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ PIPX_RECEIVE_RESERVED Reserved;
+
+ IpxAllocateReceivePacket (Device, Packet, &Status);
+
+ if (Status != STATUS_SUCCESS) {
+ // ERROR LOG
+ return Status;
+ }
+
+ Reserved = RECEIVE_RESERVED(Packet);
+ Reserved->Identifier = IDENTIFIER_IPX;
+ Reserved->TransferInProgress = FALSE;
+ Reserved->SingleRequest = NULL;
+ Reserved->ReceiveBuffer = NULL;
+ InitializeListHead (&Reserved->Requests);
+
+ ExInterlockedInsertHeadList(
+ &Device->GlobalReceivePacketList,
+ &Reserved->GlobalLinkage,
+ &Device->Lock);
+
+ return STATUS_SUCCESS;
+
+} /* IpxInitializeReceivePacket */
+
+
+NTSTATUS
+IpxInitializeReceiveBuffer(
+ IN PADAPTER Adapter,
+ IN PIPX_RECEIVE_BUFFER ReceiveBuffer,
+ IN PUCHAR DataBuffer,
+ IN ULONG DataBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive buffer by allocating
+ an NDIS_BUFFER to describe the data buffer.
+
+Arguments:
+
+ Adapter - The adapter.
+
+ ReceiveBuffer - The receive buffer to initialize.
+
+ DataBuffer - The data buffer.
+
+ DataBufferLength - The length of the data buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ PNDIS_BUFFER NdisBuffer;
+ PDEVICE Device = Adapter->Device;
+
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Device->NdisBufferPoolHandle,
+ DataBuffer,
+ DataBufferLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ ReceiveBuffer->NdisBuffer = NdisBuffer;
+ ReceiveBuffer->Data = DataBuffer;
+ ReceiveBuffer->DataLength = 0;
+
+ ExInterlockedInsertHeadList(
+ &Device->GlobalReceiveBufferList,
+ &ReceiveBuffer->GlobalLinkage,
+ &Device->Lock);
+
+ return STATUS_SUCCESS;
+
+} /* IpxInitializeReceiveBuffer */
+
+
+NTSTATUS
+IpxInitializePaddingBuffer(
+ IN PDEVICE Device,
+ IN PIPX_PADDING_BUFFER PaddingBuffer,
+ IN ULONG DataBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a padding buffer by allocating
+ an NDIS_BUFFER to describe the data buffer.
+
+Arguments:
+
+ Adapter - The adapter.
+
+ PaddingBuffer - The receive buffer to initialize.
+
+ DataBufferLength - The length of the data buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ PNDIS_BUFFER NdisBuffer;
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Device->NdisBufferPoolHandle,
+ PaddingBuffer->Data,
+ DataBufferLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NDIS_BUFFER_LINKAGE(NdisBuffer) = (PNDIS_BUFFER)NULL;
+ PaddingBuffer->NdisBuffer = NdisBuffer;
+ PaddingBuffer->DataLength = DataBufferLength;
+ RtlZeroMemory (PaddingBuffer->Data, DataBufferLength);
+
+ return STATUS_SUCCESS;
+
+} /* IpxInitializePaddingBuffer */
+
+
+VOID
+IpxDeinitializeSendPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a send packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to deinitialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_BUFFER NdisBuffer;
+ PNDIS_BUFFER NdisIpxBuffer;
+ PIPX_SEND_RESERVED Reserved;
+ CTELockHandle LockHandle;
+
+
+ Reserved = SEND_RESERVED(Packet);
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Reserved->GlobalLinkage);
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ //
+ // Free the packet in a slightly unconventional way; this
+ // allows us to not have to NULL out HeaderBuffer's linkage
+ // field during normal operations when we put it back in
+ // the free pool.
+ //
+
+ NdisBuffer = Reserved->HeaderBuffer;
+ NdisIpxBuffer = NDIS_BUFFER_LINKAGE(NdisBuffer);
+ NDIS_BUFFER_LINKAGE (NdisBuffer) = NULL;
+ NDIS_BUFFER_LINKAGE (NdisIpxBuffer) = NULL;
+
+#if 0
+ NdisAdjustBufferLength (NdisBuffer, PACKET_HEADER_SIZE);
+#endif
+ NdisAdjustBufferLength (NdisBuffer, MAC_HEADER_SIZE);
+ NdisAdjustBufferLength (NdisIpxBuffer, IPX_HEADER_SIZE + RIP_PACKET_SIZE);
+
+ NdisFreeBuffer (NdisBuffer);
+ NdisFreeBuffer (NdisIpxBuffer);
+
+ NdisReinitializePacket (PACKET(Packet));
+ IpxFreeSendPacket (Device, Packet);
+
+} /* IpxDeinitializeSendPacket */
+
+#if BACK_FILL
+VOID
+IpxDeinitializeBackFillPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a back fill packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to deinitialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_BUFFER NdisBuffer;
+ PNDIS_BUFFER NdisIpxBuffer;
+ PIPX_SEND_RESERVED Reserved;
+ CTELockHandle LockHandle;
+
+ IPX_DEBUG (PACKET, ("DeInitializing backfill packet\n"));
+
+ Reserved = SEND_RESERVED(Packet);
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Reserved->GlobalLinkage);
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+
+
+ NdisReinitializePacket (PACKET(Packet));
+ IpxFreeSendPacket (Device, Packet);
+ IPX_DEBUG (PACKET, ("DeInitializing backfill packet Done\n"));
+
+
+} /* IpxDeinitializeBackFillPacket */
+#endif
+
+
+VOID
+IpxDeinitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PIPX_RECEIVE_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to initialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PIPX_RECEIVE_RESERVED Reserved;
+ CTELockHandle LockHandle;
+
+ Reserved = RECEIVE_RESERVED(Packet);
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Reserved->GlobalLinkage);
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ IpxFreeReceivePacket (Device, Packet);
+
+} /* IpxDeinitializeReceivePacket */
+
+
+VOID
+IpxDeinitializeReceiveBuffer(
+ IN PADAPTER Adapter,
+ IN PIPX_RECEIVE_BUFFER ReceiveBuffer,
+ IN ULONG DataBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a receive buffer.
+
+Arguments:
+
+ Device - The device.
+
+ ReceiveBuffer - The receive buffer.
+
+ DataBufferLength - The allocated length of the receive buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PDEVICE Device = Adapter->Device;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ RemoveEntryList (&ReceiveBuffer->GlobalLinkage);
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ NdisAdjustBufferLength (ReceiveBuffer->NdisBuffer, DataBufferLength);
+ NdisFreeBuffer (ReceiveBuffer->NdisBuffer);
+
+} /* IpxDeinitializeReceiveBuffer */
+
+
+VOID
+IpxDeinitializePaddingBuffer(
+ IN PDEVICE Device,
+ IN PIPX_PADDING_BUFFER PaddingBuffer,
+ IN ULONG DataBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a padding buffer.
+
+Arguments:
+
+ Device - The device.
+
+ PaddingBuffer - The padding buffer.
+
+ DataBufferLength - The allocated length of the padding buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NdisAdjustBufferLength (PaddingBuffer->NdisBuffer, DataBufferLength);
+ NdisFreeBuffer (PaddingBuffer->NdisBuffer);
+
+} /* IpxDeinitializePaddingBuffer */
+
+
+
+#ifdef IPX_OWN_PACKETS
+VOID
+IpxAllocateSendPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_POOL SendPool;
+ UINT SendPoolSize;
+ UINT PacketNum;
+ PIPX_SEND_PACKET Packet;
+ PIPX_SEND_RESERVED Reserved;
+ PUCHAR Header;
+ CTELockHandle LockHandle;
+
+
+ SendPoolSize = FIELD_OFFSET (IPX_SEND_POOL, Packets[0]) +
+ (sizeof(IPX_SEND_PACKET) * Device->InitDatagrams) +
+ (PACKET_HEADER_SIZE * Device->InitDatagrams);
+
+
+ SendPool = (PIPX_SEND_POOL)IpxAllocateMemory (SendPoolSize, MEMORY_PACKET, "SendPool");
+ if (SendPool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate send pool memory\n"));
+ return;
+ }
+
+
+ IPX_DEBUG (PACKET, ("Initializing send pool %lx, %d packets\n",
+ SendPool, Device->InitDatagrams));
+
+ Header = (PUCHAR)(&SendPool->Packets[Device->InitDatagrams]);
+
+ for (PacketNum = 0; PacketNum < Device->InitDatagrams; PacketNum++) {
+
+ Packet = &SendPool->Packets[PacketNum];
+
+ if (IpxInitializeSendPacket (Device, Packet, Header) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = SendPool;
+#endif
+
+ Header += PACKET_HEADER_SIZE;
+
+ }
+
+ SendPool->PacketCount = PacketNum;
+ SendPool->PacketFree = PacketNum;
+
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (PacketNum = 0; PacketNum < SendPool->PacketCount; PacketNum++) {
+
+ Packet = &SendPool->Packets[PacketNum];
+ Reserved = SEND_RESERVED(Packet);
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+
+ }
+
+ InsertTailList (&Device->SendPoolList, &SendPool->Linkage);
+
+ Device->AllocatedDatagrams += SendPool->PacketCount;
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+} /* IpxAllocateSendPool */
+
+#if BACK_FILL
+
+VOID
+IpxAllocateBackFillPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_POOL SendPool;
+ UINT SendPoolSize;
+ UINT PacketNum;
+ PIPX_SEND_PACKET Packet;
+ PIPX_SEND_RESERVED Reserved;
+ PUCHAR Header;
+ CTELockHandle LockHandle;
+
+ PIPX_SEND_POOL BackFillPool;
+ UINT BackFillPoolSize;
+
+ IPX_DEBUG (PACKET, ("Allocating backfill pool\n"));
+
+
+ BackFillPoolSize = FIELD_OFFSET (IPX_SEND_POOL, Packets[0]) +
+ (sizeof(IPX_SEND_PACKET) * Device->InitDatagrams);
+
+
+ // Allocate pool for back fillable packets
+
+ BackFillPool = (PIPX_SEND_POOL)IpxAllocateMemory (BackFillPoolSize, MEMORY_PACKET, "BafiPool");
+
+ if (BackFillPool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate BackFill pool memory\n"));
+ return;
+ }
+
+
+
+
+
+ for (PacketNum = 0; PacketNum < Device->InitDatagrams; PacketNum++) {
+
+ Packet = &BackFillPool->Packets[PacketNum];
+
+ if (IpxInitializeBackFillPacket (Device, Packet, NULL) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = BackFillPool;
+#endif
+
+
+ }
+
+ BackFillPool->PacketCount = PacketNum;
+ BackFillPool->PacketFree = PacketNum;
+
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (PacketNum = 0; PacketNum < BackFillPool->PacketCount; PacketNum++) {
+
+ Packet = &BackFillPool->Packets[PacketNum];
+ Reserved = SEND_RESERVED(Packet);
+ IPX_PUSH_ENTRY_LIST (&Device->BackFillPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+
+ }
+
+ InsertTailList (&Device->BackFillPoolList, &BackFillPool->Linkage);
+
+
+ IPX_DEBUG (PACKET, ("Allocation of backfill pool done\n"));
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+} /* IpxAllocateBackFillPool */
+
+#endif
+
+
+VOID
+IpxAllocateReceivePool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds receive packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_RECEIVE_POOL ReceivePool;
+ UINT ReceivePoolSize;
+ UINT PacketNum;
+ PIPX_RECEIVE_PACKET Packet;
+ PIPX_RECEIVE_RESERVED Reserved;
+ CTELockHandle LockHandle;
+
+ ReceivePoolSize = FIELD_OFFSET (IPX_RECEIVE_POOL, Packets[0]) +
+ (sizeof(IPX_RECEIVE_PACKET) * Device->InitReceivePackets);
+
+ ReceivePool = (PIPX_RECEIVE_POOL)IpxAllocateMemory (ReceivePoolSize, MEMORY_PACKET, "ReceivePool");
+ if (ReceivePool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate receive pool memory\n"));
+ return;
+ }
+
+ IPX_DEBUG (PACKET, ("Initializing receive pool %lx, %d packets\n",
+ ReceivePool, Device->InitReceivePackets));
+
+ for (PacketNum = 0; PacketNum < Device->InitReceivePackets; PacketNum++) {
+
+ Packet = &ReceivePool->Packets[PacketNum];
+
+ if (IpxInitializeReceivePacket (Device, Packet) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = RECEIVE_RESERVED(Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = ReceivePool;
+#endif
+
+ }
+
+ ReceivePool->PacketCount = PacketNum;
+ ReceivePool->PacketFree = PacketNum;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (PacketNum = 0; PacketNum < ReceivePool->PacketCount; PacketNum++) {
+
+ Packet = &ReceivePool->Packets[PacketNum];
+ Reserved = RECEIVE_RESERVED(Packet);
+ IPX_PUSH_ENTRY_LIST (&Device->ReceivePacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+
+ }
+
+ InsertTailList (&Device->ReceivePoolList, &ReceivePool->Linkage);
+
+ Device->AllocatedReceivePackets += ReceivePool->PacketCount;
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+} /* IpxAllocateReceivePool */
+
+
+#else // IPX_OWN_PACKETS
+VOID
+IpxAllocateSendPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_POOL SendPool;
+ UINT HeaderSize;
+ UINT PacketNum;
+ IPX_SEND_PACKET Packet;
+ PIPX_SEND_RESERVED Reserved;
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ CTELockHandle LockHandle;
+
+ SendPool = (PIPX_SEND_POOL)IpxAllocateMemory (sizeof(IPX_SEND_POOL), MEMORY_PACKET, "SendPool");
+
+ if (SendPool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate send pool memory\n"));
+ return;
+ }
+
+ HeaderSize = PACKET_HEADER_SIZE * Device->InitDatagrams;
+
+ Header = (PUCHAR)IpxAllocateMemory (HeaderSize, MEMORY_PACKET, "SendPool");
+
+ if (Header == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate header memory\n"));
+ return;
+ }
+
+ NdisAllocatePacketPool(&Status, &SendPool->PoolHandle, Device->InitDatagrams, sizeof(IPX_SEND_RESERVED));
+
+ if (Status == NDIS_STATUS_RESOURCES) {
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis pool memory\n"));
+ return;
+ }
+
+ Device->MemoryUsage += (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]) +
+ Device->InitDatagrams * (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_SEND_RESERVED)));
+
+ IPX_DEBUG (PACKET, ("Initializing send pool %lx, %d packets\n",
+ SendPool, Device->InitDatagrams));
+
+ SendPool->Header = Header;
+
+ for (PacketNum = 0; PacketNum < Device->InitDatagrams; PacketNum++) {
+
+ NdisAllocatePacket(&Status, &PACKET(&Packet), SendPool->PoolHandle);
+
+ if (IpxInitializeSendPacket (Device, &Packet, Header) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = SEND_RESERVED(&Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = SendPool;
+#endif
+
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+
+ Header += PACKET_HEADER_SIZE;
+
+ }
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ Device->AllocatedDatagrams += PacketNum;
+ InsertTailList (&Device->SendPoolList, &SendPool->Linkage);
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+} /* IpxAllocateSendPool */
+
+
+#if BACK_FILL
+
+VOID
+IpxAllocateBackFillPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT PacketNum;
+ IPX_SEND_PACKET Packet;
+ PIPX_SEND_RESERVED Reserved;
+ CTELockHandle LockHandle;
+ PIPX_SEND_POOL BackFillPool;
+ NDIS_STATUS Status;
+
+ IPX_DEBUG (PACKET, ("Allocating backfill pool\n"));
+
+ // Allocate pool for back fillable packets
+
+ BackFillPool = (PIPX_SEND_POOL)IpxAllocateMemory (sizeof(IPX_SEND_POOL), MEMORY_PACKET, "BafiPool");
+
+ if (BackFillPool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate backfill pool memory\n"));
+ return;
+ }
+
+ NdisAllocatePacketPool(&Status, &BackFillPool->PoolHandle, Device->InitDatagrams, sizeof(IPX_SEND_RESERVED));
+
+ if (Status == NDIS_STATUS_RESOURCES) {
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis pool memory\n"));
+ return;
+ }
+
+ Device->MemoryUsage += (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]) +
+ Device->InitDatagrams * (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_SEND_RESERVED)));
+
+ for (PacketNum = 0; PacketNum < Device->InitDatagrams; PacketNum++) {
+
+ NdisAllocatePacket(&Status, &PACKET(&Packet), BackFillPool->PoolHandle);
+
+ if (IpxInitializeBackFillPacket (Device, &Packet, NULL) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = SEND_RESERVED(&Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = BackFillPool;
+#endif
+
+ IPX_PUSH_ENTRY_LIST (&Device->BackFillPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+ }
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ InsertTailList (&Device->BackFillPoolList, &BackFillPool->Linkage);
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+} /* IpxAllocateBackFillPool */
+
+#endif
+
+
+VOID
+IpxAllocateReceivePool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds receive packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_RECEIVE_POOL ReceivePool;
+ UINT PacketNum;
+ IPX_RECEIVE_PACKET Packet;
+ PIPX_RECEIVE_RESERVED Reserved;
+ CTELockHandle LockHandle;
+ NDIS_STATUS Status;
+
+ ReceivePool = (PIPX_SEND_POOL)IpxAllocateMemory (sizeof(IPX_RECEIVE_POOL), MEMORY_PACKET, "ReceivePool");
+
+ if (ReceivePool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate receive pool memory\n"));
+ return;
+ }
+
+ NdisAllocatePacketPool(&Status, &ReceivePool->PoolHandle, Device->InitDatagrams, sizeof(IPX_SEND_RESERVED));
+
+ if (Status == NDIS_STATUS_RESOURCES) {
+ IPX_DEBUG (PACKET, ("Could not allocate receive pool memory\n"));
+ return;
+ }
+
+ IPX_DEBUG (PACKET, ("Initializing receive pool %lx, %d packets\n",
+ ReceivePool, Device->InitReceivePackets));
+
+ Device->MemoryUsage += (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]) +
+ Device->InitReceivePackets * (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_RECEIVE_RESERVED)));
+
+ for (PacketNum = 0; PacketNum < Device->InitReceivePackets; PacketNum++) {
+
+ NdisAllocatePacket(&Status, &PACKET(&Packet), ReceivePool->PoolHandle);
+
+ if (IpxInitializeReceivePacket (Device, &Packet) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = RECEIVE_RESERVED(&Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = ReceivePool;
+#endif
+
+ IPX_PUSH_ENTRY_LIST (&Device->ReceivePacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+
+ }
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ Device->AllocatedReceivePackets += PacketNum;
+
+ InsertTailList (&Device->ReceivePoolList, &ReceivePool->Linkage);
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+} /* IpxAllocateReceivePool */
+#endif // IPX_OWN_PACKETS
+
+VOID
+IpxAllocateReceiveBufferPool(
+ IN PADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds receive buffers to the pool for this adapter.
+
+Arguments:
+
+ Adapter - The adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_RECEIVE_BUFFER ReceiveBuffer;
+ UINT ReceiveBufferPoolSize;
+ UINT BufferNum;
+ PIPX_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ PDEVICE Device = Adapter->Device;
+ UINT DataLength;
+ PUCHAR Data;
+ CTELockHandle LockHandle;
+
+ DataLength = Adapter->MaxReceivePacketSize;
+
+ ReceiveBufferPoolSize = FIELD_OFFSET (IPX_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(IPX_RECEIVE_BUFFER) * Device->InitReceiveBuffers) +
+ (DataLength * Device->InitReceiveBuffers);
+
+ ReceiveBufferPool = (PIPX_RECEIVE_BUFFER_POOL)IpxAllocateMemory (ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+ if (ReceiveBufferPool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate receive buffer pool memory\n"));
+ return;
+ }
+
+ IPX_DEBUG (PACKET, ("Init recv buffer pool %lx, %d buffers, data %d\n",
+ ReceiveBufferPool, Device->InitReceiveBuffers, DataLength));
+
+ Data = (PUCHAR)(&ReceiveBufferPool->Buffers[Device->InitReceiveBuffers]);
+
+
+ for (BufferNum = 0; BufferNum < Device->InitReceiveBuffers; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+
+ if (IpxInitializeReceiveBuffer (Adapter, ReceiveBuffer, Data, DataLength) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize buffer %lx\n", ReceiveBuffer));
+ break;
+ }
+
+#ifdef IPX_TRACK_POOL
+ ReceiveBuffer->Pool = ReceiveBufferPool;
+#endif
+
+ Data += DataLength;
+
+ }
+
+ ReceiveBufferPool->BufferCount = BufferNum;
+ ReceiveBufferPool->BufferFree = BufferNum;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (BufferNum = 0; BufferNum < ReceiveBufferPool->BufferCount; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+ IPX_PUSH_ENTRY_LIST (&Adapter->ReceiveBufferList, &ReceiveBuffer->PoolLinkage, &Device->SListsLock);
+
+ }
+
+ InsertTailList (&Adapter->ReceiveBufferPoolList, &ReceiveBufferPool->Linkage);
+
+ Adapter->AllocatedReceiveBuffers += ReceiveBufferPool->BufferCount;
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+} /* IpxAllocateReceiveBufferPool */
+
+
+PSINGLE_LIST_ENTRY
+IpxPopSendPacket(
+ PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool.
+ If there are no packets in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedDatagrams < Device->MaxDatagrams) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ IpxAllocateSendPool (Device);
+ s = IPX_POP_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Device->SListsLock);
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* IpxPopSendPacket */
+
+#if BACK_FILL
+
+PSINGLE_LIST_ENTRY
+IpxPopBackFillPacket(
+ PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool.
+ If there are no packets in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+
+ IPX_DEBUG (PACKET, ("Popping backfill packet\n"));
+
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BackFillPacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedDatagrams < Device->MaxDatagrams) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ IpxAllocateBackFillPool (Device);
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BackFillPacketList,
+ &Device->SListsLock);
+
+
+ IPX_DEBUG (PACKET, ("Popping backfill packet done\n"));
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* IpxPopBackFillPacket */
+#endif //BackFill
+
+
+PSINGLE_LIST_ENTRY
+IpxPopReceivePacket(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool.
+ If there are no packets in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->ReceivePacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedReceivePackets < Device->MaxReceivePackets) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ IpxAllocateReceivePool (Device);
+ s = IPX_POP_ENTRY_LIST(
+ &Device->ReceivePacketList,
+ &Device->SListsLock);
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* IpxPopReceivePacket */
+
+
+PSINGLE_LIST_ENTRY
+IpxPopReceiveBuffer(
+ IN PADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a receive buffer from the adapter's pool.
+ If there are no buffers in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Adapter - Pointer to our adapter to charge the buffer to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated receive buffer.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PDEVICE Device = Adapter->Device;
+
+ s = IPX_POP_ENTRY_LIST(
+ &Adapter->ReceiveBufferList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No buffer in the pool, see if we can allocate more.
+ //
+
+ if (Adapter->AllocatedReceiveBuffers < Device->MaxReceiveBuffers) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ IpxAllocateReceiveBufferPool (Adapter);
+ s = IPX_POP_ENTRY_LIST(
+ &Adapter->ReceiveBufferList,
+ &Device->SListsLock);
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* IpxPopReceiveBuffer */
+
+
+PIPX_PADDING_BUFFER
+IpxAllocatePaddingBuffer(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a padding buffer for use by all devices.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the allocated padding buffer.
+
+--*/
+
+{
+ PIPX_PADDING_BUFFER PaddingBuffer;
+ ULONG PaddingBufferSize;
+
+ //
+ // We are assuming that we can use 1 global padding buffer for ALL
+ // transmits! We must therefore test to make sure that EthernetExtraPadding
+ // is not greater than 1. Otherwise, we must assume that the extra padding
+ // is being used for something and we therefore cannot share across all
+ // transmit requests.
+ //
+
+ //
+ // We cannot support more than 1 byte padding space, since we allocate only
+ // one buffer for all transmit requests.
+ //
+
+ if ( Device->EthernetExtraPadding > 1 ) {
+ IPX_DEBUG (PACKET, ("Padding buffer cannot be more than 1 byte\n"));
+ DbgBreakPoint();
+ }
+
+ //
+ // Allocate a padding buffer if possible.
+ //
+
+ PaddingBufferSize = FIELD_OFFSET (IPX_PADDING_BUFFER, Data[0]) + Device->EthernetExtraPadding;
+
+ PaddingBuffer = IpxAllocateMemory (PaddingBufferSize, MEMORY_PACKET, "PaddingBuffer");
+
+ if (PaddingBuffer != NULL) {
+
+ if (IpxInitializePaddingBuffer (Device, PaddingBuffer, Device->EthernetExtraPadding) !=
+ STATUS_SUCCESS) {
+ IpxFreeMemory (PaddingBuffer, PaddingBufferSize, MEMORY_PACKET, "Padding Buffer");
+ } else {
+ IPX_DEBUG (PACKET, ("Allocate padding buffer %lx\n", PaddingBuffer));
+ return PaddingBuffer;
+ }
+ }
+
+ return NULL;
+
+} /* IpxAllocatePaddingBuffer */
+
+
+VOID
+IpxFreePaddingBuffer(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deallocates the padding buffer.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG PaddingBufferSize;
+
+ if ( IpxPaddingBuffer == (PIPX_PADDING_BUFFER)NULL ) {
+ return;
+ }
+
+ PaddingBufferSize = FIELD_OFFSET (IPX_PADDING_BUFFER, Data[0]) + Device->EthernetExtraPadding;
+ IpxFreeMemory( IpxPaddingBuffer, PaddingBufferSize, MEMORY_PACKET, "Padding Buffer" );
+ IpxPaddingBuffer = (PIPX_PADDING_BUFFER)NULL;
+
+} /* IpxFreePaddingBuffer */
+
diff --git a/private/ntos/tdi/isn/ipx/precomp.h b/private/ntos/tdi/isn/ipx/precomp.h
new file mode 100644
index 000000000..21775002a
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/precomp.h
@@ -0,0 +1,45 @@
+/*++
+
+Copyright (c) 1993-1995 Microsoft Corporation
+
+Module Name:
+
+ precomp.h
+
+Abstract:
+
+ Precompilation header file.
+
+Author:
+
+ Adam Barr (adamba) 08-Sep-1993
+
+Revision History:
+
+--*/
+
+
+#define ISN_NT 1
+
+//
+// These are needed for CTE
+//
+
+#if DBG
+#define DEBUG 1
+#endif
+
+#define NT 1
+#define _HIPX_SUBAGNT
+
+#include <ntos.h>
+#include <tdikrnl.h>
+#include <ndis.h>
+#include <cxport.h>
+#include <bind.h>
+#include "isnipx.h"
+#include "config.h"
+#include "mac.h"
+#include "ipxtypes.h"
+#include "ipxprocs.h"
+#include <wsnwlink.h>
diff --git a/private/ntos/tdi/isn/ipx/query.c b/private/ntos/tdi/isn/ipx/query.c
new file mode 100644
index 000000000..28b38df5c
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/query.c
@@ -0,0 +1,297 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ query.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiQueryInformation
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Useful macro to obtain the total length of an MDL chain.
+//
+
+#define IpxGetMdlChainLength(Mdl, Length) { \
+ PMDL _Mdl = (Mdl); \
+ *(Length) = 0; \
+ while (_Mdl) { \
+ *(Length) += MmGetMdlByteCount(_Mdl); \
+ _Mdl = _Mdl->Next; \
+ } \
+}
+
+
+
+NTSTATUS
+IpxTdiQueryInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiQueryInformation request for the transport
+ provider.
+
+Arguments:
+
+ Request - the request for the operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTDI_REQUEST_KERNEL_QUERY_INFORMATION query;
+ PADDRESS_FILE AddressFile;
+ ULONG ElementSize, TransportAddressSize;
+ PTRANSPORT_ADDRESS TransportAddress;
+ TA_ADDRESS UNALIGNED * CurAddress;
+ PBINDING Binding;
+ union {
+ struct {
+ ULONG ActivityCount;
+ TA_IPX_ADDRESS IpxAddress;
+ } AddressInfo;
+ TDI_DATAGRAM_INFO DatagramInfo;
+ TDI_ADDRESS_IPX IpxAddress;
+ } TempBuffer;
+ UINT i;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ //
+ // what type of status do we want?
+ //
+
+ query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)REQUEST_PARAMETERS(Request);
+
+ switch (query->QueryType) {
+
+ case TDI_QUERY_ADDRESS_INFO:
+
+ //
+ // The caller wants the exact address value.
+ //
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ status = IpxVerifyAddressFile (AddressFile);
+
+ if (status == STATUS_SUCCESS) {
+
+ TempBuffer.AddressInfo.ActivityCount = 0;
+
+ IpxBuildTdiAddress(
+ &TempBuffer.AddressInfo.IpxAddress,
+ Device->SourceAddress.NetworkAddress,
+ Device->SourceAddress.NodeAddress,
+ AddressFile->Address->Socket);
+
+ status = TdiCopyBufferToMdl(
+ &TempBuffer.AddressInfo,
+ 0,
+ sizeof(TempBuffer.AddressInfo),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ }
+
+ break;
+
+ case TDI_QUERY_PROVIDER_INFO:
+
+ status = TdiCopyBufferToMdl (
+ &(Device->Information),
+ 0,
+ sizeof (TDI_PROVIDER_INFO),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_PROVIDER_STATISTICS:
+
+ status = TdiCopyBufferToMdl (
+ &Device->Statistics,
+ 0,
+ FIELD_OFFSET (TDI_PROVIDER_STATISTICS, ResourceStats[0]),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_DATAGRAM_INFO:
+
+ TempBuffer.DatagramInfo.MaximumDatagramBytes = 0;
+ TempBuffer.DatagramInfo.MaximumDatagramCount = 0;
+
+ status = TdiCopyBufferToMdl (
+ &TempBuffer.DatagramInfo,
+ 0,
+ sizeof(TempBuffer.DatagramInfo),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_DATA_LINK_ADDRESS:
+ case TDI_QUERY_NETWORK_ADDRESS:
+
+ if (query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
+ ElementSize = (2 * sizeof(USHORT)) + 6;
+ } else {
+ ElementSize = (2 * sizeof(USHORT)) + sizeof(TDI_ADDRESS_IPX);
+ }
+
+ TransportAddress = IpxAllocateMemory(sizeof(int) + (ElementSize * MIN (Device->MaxBindings, Device->ValidBindings)), MEMORY_QUERY, "NetworkAddress");
+
+ if (TransportAddress == NULL) {
+
+ status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ TransportAddress->TAAddressCount = 0;
+ TransportAddressSize = sizeof(int);
+ CurAddress = (TA_ADDRESS UNALIGNED *)TransportAddress->Address;
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->ValidBindings);
+
+ for (i = 1; i <= Index; i++) {
+
+ Binding = NIC_ID_TO_BINDING(Device, i);
+ if ((Binding == NULL) ||
+ (!Binding->LineUp)) {
+ continue;
+ }
+
+ if (query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
+ CurAddress->AddressLength = 6;
+ CurAddress->AddressType = Binding->Adapter->MacInfo.RealMediumType;
+ RtlCopyMemory (CurAddress->Address, Binding->LocalAddress.NodeAddress, 6);
+ } else {
+ CurAddress->AddressLength = sizeof(TDI_ADDRESS_IPX);
+ CurAddress->AddressType = TDI_ADDRESS_TYPE_IPX;
+ RtlCopyMemory (CurAddress->Address, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
+ }
+ ++TransportAddress->TAAddressCount;
+ TransportAddressSize += ElementSize;
+ CurAddress = (TA_ADDRESS UNALIGNED *)(((PUCHAR)CurAddress) + ElementSize);
+
+ }
+ }
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ for (i = 1; i <= Device->ValidBindings; i++) {
+
+ Binding = Device->Bindings[i];
+ if ((Binding == NULL) ||
+ (!Binding->LineUp)) {
+ continue;
+ }
+
+ if (query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
+ CurAddress->AddressLength = 6;
+ CurAddress->AddressType = Binding->Adapter->MacInfo.RealMediumType;
+ RtlCopyMemory (CurAddress->Address, Binding->LocalAddress.NodeAddress, 6);
+ } else {
+ CurAddress->AddressLength = sizeof(TDI_ADDRESS_IPX);
+ CurAddress->AddressType = TDI_ADDRESS_TYPE_IPX;
+ RtlCopyMemory (CurAddress->Address, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
+ }
+ ++TransportAddress->TAAddressCount;
+ TransportAddressSize += ElementSize;
+ CurAddress = (TA_ADDRESS UNALIGNED *)(((PUCHAR)CurAddress) + ElementSize);
+
+ }
+#endif
+ status = TdiCopyBufferToMdl (
+ TransportAddress,
+ 0,
+ TransportAddressSize,
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ CTEFreeMem (TransportAddress);
+
+ }
+
+ break;
+
+ default:
+
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ return status;
+
+} /* IpxTdiQueryInformation */
+
+
+NTSTATUS
+IpxTdiSetInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetInformation request for the transport
+ provider.
+
+Arguments:
+
+ Device - the device.
+
+ Request - the request for the operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (Device);
+ UNREFERENCED_PARAMETER (Request);
+
+ return STATUS_NOT_IMPLEMENTED;
+
+} /* IpxTdiSetInformation */
+
+
diff --git a/private/ntos/tdi/isn/ipx/receive.c b/private/ntos/tdi/isn/ipx/receive.c
new file mode 100644
index 000000000..6bed71e3c
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/receive.c
@@ -0,0 +1,493 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ receive.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiReceiveDatagram
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+
+VOID
+IpxTransferDataComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus,
+ IN UINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that an NdisTransferData has completed. We use this indication
+ to complete any pended requests to our clients.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+ NdisPacket/RequestHandle - An identifier for the request that completed.
+
+ NdisStatus - The completion status for the request.
+
+ BytesTransferred - Number of bytes actually transferred.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+ PIPX_RECEIVE_RESERVED Reserved = (PIPX_RECEIVE_RESERVED)(NdisPacket->ProtocolReserved);
+ PREQUEST Request, LastRequest;
+ PADDRESS_FILE AddressFile;
+ ULONG ByteOffset;
+ PLIST_ENTRY p;
+ PDEVICE Device;
+
+
+ switch (Reserved->Identifier) {
+
+ case IDENTIFIER_IPX:
+
+ if (!Reserved->pContext) {
+
+ if (Reserved->SingleRequest) {
+
+ //
+ // The transfer was directly into the client buffer,
+ // so simply complete the request.
+ //
+
+ Request = Reserved->SingleRequest;
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ IPX_DEBUG (RECEIVE, ("Transferred %d bytes\n", BytesTransferred));
+ REQUEST_INFORMATION(Request) = BytesTransferred;
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+
+ } else {
+
+ IPX_DEBUG (RECEIVE, ("Transfer failed\n"));
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_ADAPTER_HARDWARE_ERROR;
+
+ }
+
+ LastRequest = Request;
+ Reserved->SingleRequest = NULL;
+
+ } else {
+
+ //
+ // Multiple clients requested this datagram. Save
+ // the last one to delay queueing it for completion.
+ //
+
+ LastRequest = LIST_ENTRY_TO_REQUEST (Reserved->Requests.Blink);
+
+ while (TRUE) {
+
+ p = RemoveHeadList (&Reserved->Requests);
+ if (p == &Reserved->Requests) {
+ break;
+ }
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+ AddressFile = REQUEST_OPEN_CONTEXT(Request);
+
+ if (AddressFile->ReceiveIpxHeader) {
+ ByteOffset = 0;
+ } else {
+ ByteOffset = sizeof(IPX_HEADER);
+ }
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ REQUEST_STATUS(Request) =
+ TdiCopyBufferToMdl(
+ Reserved->ReceiveBuffer->Data,
+ ByteOffset + REQUEST_INFORMATION(Request),
+ ((PTDI_REQUEST_KERNEL_RECEIVEDG)(REQUEST_PARAMETERS(Request)))->ReceiveLength,
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ } else {
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_ADAPTER_HARDWARE_ERROR;
+
+ }
+
+ if (Request != LastRequest) {
+
+ IPX_INSERT_TAIL_LIST(
+ &Adapter->RequestCompletionQueue,
+ REQUEST_LINKAGE(Request),
+ Adapter->DeviceLock);
+
+ }
+
+ }
+
+ //
+ // Now free the receive buffer back.
+ //
+
+ IPX_PUSH_ENTRY_LIST(
+ &Adapter->ReceiveBufferList,
+ &Reserved->ReceiveBuffer->PoolLinkage,
+ &Adapter->Device->SListsLock);
+
+ Reserved->ReceiveBuffer = NULL;
+
+ }
+
+ } else {
+ //IpxPrint0("IpxTransferDataComplete: Calling PassDgToRt\n");
+ //ByteOffset = sizeof(IPX_HEADER);
+ ByteOffset = 0;
+ PassDgToRt(IpxDevice, Reserved->pContext, Reserved->Index,
+ &Reserved->ReceiveBuffer->Data[ByteOffset],
+ BytesTransferred);
+
+ //
+ // Free the memory allocated for options.
+ //
+ IpxFreeMemory(Reserved->pContext, sizeof(IPX_DATAGRAM_OPTIONS2),
+ MEMORY_PACKET, "RT OPTIONS");
+ //
+ // Now free the receive buffer back.
+ //
+
+ IPX_PUSH_ENTRY_LIST(
+ &Adapter->ReceiveBufferList,
+ &Reserved->ReceiveBuffer->PoolLinkage,
+ Adapter->DeviceLock);
+
+ Reserved->ReceiveBuffer = NULL;
+ }
+
+ //
+ // Now free the packet.
+ //
+
+ NdisReinitializePacket (NdisPacket);
+
+ if (Reserved->OwnedByAddress) {
+
+ // Reserved->Address->ReceivePacketInUse = FALSE;
+ InterlockedDecrement(&Reserved->Address->ReceivePacketInUse);
+
+ } else {
+
+ Device = Adapter->Device;
+
+ IPX_PUSH_ENTRY_LIST(
+ &Device->ReceivePacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+
+ }
+
+ if (!Reserved->pContext) {
+ //
+ // We Delay inserting the last request (or the only one)
+ // until after we have put the packet back, to keep the
+ // address around if needed (the address won't go away
+ // until the last address file does, and the address file
+ // won't go away until the datagram is completed).
+ //
+
+ IPX_INSERT_TAIL_LIST(
+ &Adapter->RequestCompletionQueue,
+ REQUEST_LINKAGE(LastRequest),
+ Adapter->DeviceLock);
+ }
+
+ IpxReceiveComplete ((NDIS_HANDLE)Adapter);
+
+ break;
+
+ default:
+
+ Device = Adapter->Device;
+
+ (*Device->UpperDrivers[Reserved->Identifier].TransferDataCompleteHandler)(
+ NdisPacket,
+ NdisStatus,
+ BytesTransferred);
+
+ break;
+
+ }
+
+} /* IpxTransferDataComplete */
+
+
+VOID
+IpxTransferData(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by all tightly bound clients instead of NdisTransferData.
+ If this is a loopback packet, the transfer is done directly here, else NdisTransferData
+ is called.
+
+Arguments:
+
+ Status - status of operation
+ NdisBindingHandle - Loopback cookie or Ndis context
+ MacReceiveContext - Loopback packet or Mac context
+ ByteOffset - Source offset
+ BytesToTransfer - length of the transfer desired
+ Packet - dest packet
+ BytesTransferred - length of successful transfer
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ //
+ // If this is a loopback packet, copy the data directly
+ //
+ if (NdisBindingHandle == (PVOID)IPX_LOOPBACK_COOKIE) {
+
+ IPX_DEBUG (LOOPB, ("LoopbXfer: src: %lx, dest: %lx, bytestoxfer: %lx\n",
+ MacReceiveContext, Packet, BytesToTransfer));
+
+ NdisCopyFromPacketToPacket(
+ Packet, // Destination
+ 0, // DestinationOffset
+ BytesToTransfer, // BytesToCopy
+ (PNDIS_PACKET)MacReceiveContext, // Source
+ ByteOffset, // SourceOffset
+ BytesTransferred); // BytesCopied
+
+ *Status = NDIS_STATUS_SUCCESS;
+ } else {
+ NdisTransferData(
+ Status,
+ NdisBindingHandle,
+ MacReceiveContext,
+ ByteOffset,
+ BytesToTransfer,
+ Packet,
+ BytesTransferred);
+ }
+}
+
+
+
+NTSTATUS
+IpxTdiReceiveDatagram(
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiReceiveDatagram request for the transport
+ provider. Receive datagrams just get queued up to an address, and are
+ completed when a DATAGRAM or DATAGRAM_BROADCAST frame is received at
+ the address.
+
+Arguments:
+
+ Irp - I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ IPX_DEFINE_SYNC_CONTEXT (SyncContext)
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ //
+ // Do a quick check of the validity of the address.
+ //
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ if ((AddressFile->Size != sizeof (ADDRESS_FILE)) ||
+ (AddressFile->Type != IPX_ADDRESSFILE_SIGNATURE)) {
+
+ return STATUS_INVALID_HANDLE;
+ }
+
+ Address = AddressFile->Address;
+
+ if ((Address == NULL) ||
+ (Address->Size != sizeof (ADDRESS)) ||
+ (Address->Type != IPX_ADDRESS_SIGNATURE)) {
+
+ return STATUS_INVALID_HANDLE;
+ }
+
+ IPX_BEGIN_SYNC (&SyncContext);
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ IPX_END_SYNC (&SyncContext);
+ return STATUS_INVALID_HANDLE;
+ }
+
+
+ InsertTailList (&AddressFile->ReceiveDatagramQueue, REQUEST_LINKAGE(Request));
+
+ IoSetCancelRoutine (Request, IpxCancelReceiveDatagram);
+
+ if (Request->Cancel) {
+
+ (VOID)RemoveTailList (&AddressFile->ReceiveDatagramQueue);
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ IPX_END_SYNC (&SyncContext);
+ return STATUS_CANCELLED;
+ }
+
+ IPX_DEBUG (RECEIVE, ("RDG posted on %lx\n", AddressFile));
+
+ IpxReferenceAddressFileLock (AddressFile, AFREF_RCV_DGRAM);
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+
+ IPX_END_SYNC (&SyncContext);
+
+ return STATUS_PENDING;
+
+} /* IpxTdiReceiveDatagram */
+
+
+VOID
+IpxCancelReceiveDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a receive
+ datagram. The datagram is found on the address file's receive
+ datagram queue.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PLIST_ENTRY p;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PREQUEST Request = (PREQUEST)Irp;
+ BOOLEAN Found;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_RECEIVE_DATAGRAM));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_TRANSPORT_ADDRESS_FILE);
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+ Address = AddressFile->Address;
+
+ Found = FALSE;
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+
+ for (p = AddressFile->ReceiveDatagramQueue.Flink;
+ p != &AddressFile->ReceiveDatagramQueue;
+ p = p->Flink) {
+
+ if (LIST_ENTRY_TO_REQUEST(p) == Request) {
+
+ RemoveEntryList (p);
+ Found = TRUE;
+ break;
+ }
+ }
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ if (Found) {
+
+ IPX_DEBUG(RECEIVE, ("Cancelled datagram on %lx\n", AddressFile));
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ IpxCompleteRequest (Request);
+ ASSERT( DeviceObject->DeviceExtension == IpxDevice );
+ IpxFreeRequest(IpxDevice, Request);
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
+
+ }
+
+} /* IpxCancelReceiveDatagram */
+
+
diff --git a/private/ntos/tdi/isn/ipx/rip.c b/private/ntos/tdi/isn/ipx/rip.c
new file mode 100644
index 000000000..950949ca0
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/rip.c
@@ -0,0 +1,2700 @@
+/*++
+
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ rip.c
+
+Abstract:
+
+ This module contains code that implements the client-side
+ RIP support and simple router table support.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+UCHAR BroadcastAddress[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+
+NTSTATUS
+RipGetLocalTarget(
+ IN ULONG Segment,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN UCHAR Type,
+ OUT PIPX_LOCAL_TARGET LocalTarget,
+ OUT USHORT Counts[2] OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine looks up the proper route for the specified remote
+ address. If a RIP request needs to be generated it does so.
+
+ NOTE: THIS REQUEST IS CALLED WITH THE SEGMENT LOCK HELD.
+ NOTE: IN THE CASE OF PnP, THIS COMES WITH THE BIND LOCK SHARED.
+
+Arguments:
+
+ Segment - The segment associate with the remote address.
+
+ RemoteAddress - The IPX address of the remote.
+
+ Type - One of IPX_FIND_ROUTE_NO_RIP, IPX_FIND_ROUTE_RIP_IF_NEEDED,
+ or IPX_FIND_ROUTE_FORCE_RIP.
+
+ LocalTarget - Returns the next router information.
+
+ Counts - If specified, used to return the tick and hop count.
+
+Return Value:
+
+ STATUS_SUCCESS if a route is found, STATUS_PENDING if a
+ RIP request needs to be generated, failure status if a
+ RIP request packet cannot be allocated.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ PBINDING Binding;
+ UINT i;
+
+
+ //
+ // Packets sent to network 0 go on the first adapter also.
+ //
+
+ if (RemoteAddress->NetworkAddress == 0) {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, 1);
+
+ RtlCopyMemory (LocalTarget->MacAddress, RemoteAddress->NodeAddress, 6);
+ if (ARGUMENT_PRESENT(Counts)) {
+ Counts[0] = (USHORT)((839 + NIC_ID_TO_BINDING(Device, 1)->MediumSpeed) /
+ NIC_ID_TO_BINDING(Device, 1)->MediumSpeed); // tick count
+ Counts[1] = 1; // hop count
+ }
+#else
+ LocalTarget->NicId = 1;
+
+ RtlCopyMemory (LocalTarget->MacAddress, RemoteAddress->NodeAddress, 6);
+ if (ARGUMENT_PRESENT(Counts)) {
+ Counts[0] = (USHORT)((839 + Device->Bindings[1]->MediumSpeed) /
+ Device->Bindings[1]->MediumSpeed); // tick count
+ Counts[1] = 1; // hop count
+ }
+#endif
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // See if this is a packet sent to our virtual network.
+ //
+
+ if (Device->VirtualNetwork &&
+ (RemoteAddress->NetworkAddress == Device->SourceAddress.NetworkAddress)) {
+
+ //
+ // Send it through adapter 1.
+ // BUGBUG: Do real loopback.
+ //
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, LOOPBACK_NIC_ID);
+ RtlCopyMemory (LocalTarget->MacAddress, NIC_ID_TO_BINDING(Device, 1)->LocalMacAddress.Address, 6);
+#else
+ //
+ // Loopback this packet
+ //
+ LocalTarget->NicId = 0;
+ RtlCopyMemory (LocalTarget->MacAddress, Device->Bindings[1]->LocalMacAddress.Address, 6);
+#endif
+
+ IPX_DEBUG (LOOPB, ("Loopback Nic returned for net: %lx\n", RemoteAddress->NetworkAddress));
+ if (ARGUMENT_PRESENT(Counts)) {
+ Counts[0] = 1; // tick count
+ Counts[1] = 1; // hop count
+ }
+ return STATUS_SUCCESS;
+
+ }
+
+ //
+ // Look up the route in the table. If the net is one
+ // of the ones we are directly attached to, this will
+ // return an entry with the correct flag set.
+ //
+
+ RouteEntry = RipGetRoute(Segment, (PUCHAR)&(RemoteAddress->NetworkAddress));
+
+ if (RouteEntry != NULL) {
+
+ RouteEntry->Timer = 0;
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, RouteEntry->NicId);
+#else
+ LocalTarget->NicId = RouteEntry->NicId;
+#endif
+ if (RouteEntry->Flags & IPX_ROUTER_LOCAL_NET) {
+
+ //
+ // The machine is on the same net, so send it directly.
+ //
+
+ RtlCopyMemory (LocalTarget->MacAddress, RemoteAddress->NodeAddress, 6);
+
+ if (RouteEntry->Flags & IPX_ROUTER_GLOBAL_WAN_NET) {
+
+ //
+ // The NicId here is bogus, we have to scan through
+ // our bindings until we find one whose indicated
+ // IPX remote node matches the destination node of
+ // this frame. We don't scan into the duplicate
+ // binding set members since they won't be WANs.
+ //
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ if ((Binding != (PBINDING)NULL) &&
+ (Binding->Adapter->MacInfo.MediumAsync) &&
+ (RtlEqualMemory(
+ Binding->WanRemoteNode,
+ RemoteAddress->NodeAddress,
+ 6))) {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, MIN( Device->MaxBindings, Binding->NicId));
+#else
+ LocalTarget->NicId = Binding->NicId;
+#endif
+ break;
+
+ }
+ }
+ }
+
+ if (i > (UINT)MIN (Device->MaxBindings, Device->HighestExternalNicId)) {
+ //
+ // Bug #17273 return proper error message
+ //
+
+ // return STATUS_DEVICE_DOES_NOT_EXIST;
+ return STATUS_NETWORK_UNREACHABLE;
+ }
+
+ } else {
+ //
+ // Find out if this is a loopback packet. If so, return NicId 0
+ //
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ //
+ // Self-directed - loopback
+ //
+ if ((Binding != (PBINDING)NULL) &&
+ (RtlEqualMemory(
+ Binding->LocalAddress.NodeAddress,
+ RemoteAddress->NodeAddress,
+ 6))) {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, LOOPBACK_NIC_ID);
+#else
+ LocalTarget->NicId = 0;
+#endif
+
+ IPX_DEBUG (LOOPB, ("2.Loopback Nic returned for net: %lx\n", RemoteAddress->NetworkAddress));
+ break;
+
+ }
+ }
+ }
+ }
+
+ } else {
+
+ CTEAssert ((RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY) == 0);
+
+ //
+ // This is not a locally attached net, so if the caller
+ // is forcing a re-RIP then do that.
+ //
+
+ if (Type == IPX_FIND_ROUTE_FORCE_RIP) {
+ goto QueueUpRequest;
+ }
+
+ //
+ // Fill in the address of the next router in the route.
+ //
+
+ RtlCopyMemory (LocalTarget->MacAddress, RouteEntry->NextRouter, 6);
+
+ }
+
+ if (ARGUMENT_PRESENT(Counts)) {
+ Counts[0] = RouteEntry->TickCount;
+ Counts[1] = RouteEntry->HopCount;
+ }
+
+ return STATUS_SUCCESS;
+
+ }
+
+QueueUpRequest:
+
+ if (Type == IPX_FIND_ROUTE_NO_RIP) {
+
+ //
+ // Bug #17273 return proper error message
+ //
+
+ // return STATUS_DEVICE_DOES_NOT_EXIST;
+ return STATUS_NETWORK_UNREACHABLE;
+
+ } else {
+
+ return RipQueueRequest (RemoteAddress->NetworkAddress, RIP_REQUEST);
+
+ }
+
+} /* RipGetLocalTarget */
+
+
+NTSTATUS
+RipQueueRequest(
+ IN ULONG Network,
+ IN USHORT Operation
+ )
+
+/*++
+
+Routine Description:
+
+ This routine queues up a request for a RIP route. It can be
+ used to find a specific route or to discover the locally
+ attached network (if Network is 0). It can also be used
+ to do a periodic announcement of the virtual net, which
+ we do once a minute if the router is not bound.
+
+ NOTE: THIS REQUEST IS CALLED WITH THE SEGMENT LOCK HELD
+ IF IT IS A REQUEST AND THE NETWORK IS NOT 0xffffffff.
+
+Arguments:
+
+ Network - The network to discover.
+
+ Operation - One of RIP_REQUEST, RIP_RESPONSE, or RIP_DOWN.
+
+Return Value:
+
+ STATUS_PENDING if the request is queued, failure status
+ if it could not be.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ PIPX_SEND_RESERVED Reserved;
+ PSINGLE_LIST_ENTRY s;
+ PLIST_ENTRY p;
+ PRIP_PACKET RipPacket;
+ TDI_ADDRESS_IPX RemoteAddress;
+ TDI_ADDRESS_IPX LocalAddress;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+ PNDIS_BUFFER pNdisIpxBuff;
+
+
+ //
+ // Make sure we only queue a request for net 0xffffffff if we
+ // are auto-detecting, because we assume that in other places.
+ //
+
+ if ((Network == 0xffffffff) &&
+ (Device->AutoDetectState != AUTO_DETECT_STATE_RUNNING)) {
+
+ return STATUS_BAD_NETWORK_PATH;
+
+ }
+
+ //
+ // Try to get a packet to use for the RIP request. We
+ // allocate this now, but check if it succeeded later,
+ // to make the locking work better (we need to keep
+ // the lock between when we check for an existing
+ // request on this network and when we queue this
+ // request).
+ //
+
+ s = IpxPopSendPacket (Device);
+
+ //
+ // There was no router table entry for this network, first see
+ // if there is already a pending request for this route.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (Operation == RIP_REQUEST) {
+
+ for (p = Device->WaitingRipPackets.Flink;
+ p != &Device->WaitingRipPackets;
+ p = p->Flink) {
+
+ Reserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
+
+ //
+ // Skip responses.
+ //
+
+ if (Reserved->u.SR_RIP.RetryCount >= 0xfe) {
+ continue;
+ }
+
+ if (Reserved->u.SR_RIP.Network == Network &&
+ !Reserved->u.SR_RIP.RouteFound) {
+
+ //
+ // There is already one pending, put back the packet if
+ // we got one (we hold the lock already).
+ //
+
+ if (s != NULL) {
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, s, &Device->SListsLock);
+ }
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ return STATUS_PENDING;
+ }
+ }
+
+ }
+
+
+ if (s == NULL) {
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+
+ //
+ // We have the packet, fill it in for this request.
+ //
+
+ Reserved->Identifier = IDENTIFIER_RIP_INTERNAL;
+ Reserved->SendInProgress = FALSE;
+ Reserved->DestinationType = DESTINATION_BCAST;
+ Reserved->u.SR_RIP.CurrentNicId = 0;
+ Reserved->u.SR_RIP.NoIdAdvance = FALSE;
+ switch (Operation) {
+ case RIP_REQUEST: Reserved->u.SR_RIP.RetryCount = 0; break;
+ case RIP_RESPONSE: Reserved->u.SR_RIP.RetryCount = 0xfe; break;
+ case RIP_DOWN: Reserved->u.SR_RIP.RetryCount = 0xff; break;
+ }
+ Reserved->u.SR_RIP.RouteFound = FALSE;
+ Reserved->u.SR_RIP.Network = Network;
+ Reserved->u.SR_RIP.SendTime = Device->RipSendTime;
+
+ //
+ // We aren't guaranteed that this is the case for packets
+ // on the free list.
+ //
+
+ pNdisIpxBuff = NDIS_BUFFER_LINKAGE (Reserved->HeaderBuffer);
+ NDIS_BUFFER_LINKAGE (pNdisIpxBuff) = NULL;
+
+ //
+ // Fill in the IPX header at the standard offset (for sending
+ // to actual bindings it will be moved around if needed). We
+ // have to construct the local and remote addresses so they
+ // are in the format that IpxConstructHeader expects.
+ //
+
+ RemoteAddress.NetworkAddress = Network;
+ RtlCopyMemory (RemoteAddress.NodeAddress, BroadcastAddress, 6);
+ RemoteAddress.Socket = RIP_SOCKET;
+
+ RtlCopyMemory (&LocalAddress, &Device->SourceAddress, FIELD_OFFSET(TDI_ADDRESS_IPX,Socket));
+ LocalAddress.Socket = RIP_SOCKET;
+
+ IpxConstructHeader(
+// &Reserved->Header[Device->IncludedHeaderOffset],
+ &Reserved->Header[MAC_HEADER_SIZE],
+ sizeof(IPX_HEADER) + sizeof (RIP_PACKET),
+ RIP_PACKET_TYPE,
+ &RemoteAddress,
+ &LocalAddress);
+
+ //
+ // Fill in the RIP request also.
+ //
+
+#if 0
+ RipPacket = (PRIP_PACKET)(&Reserved->Header[Device->IncludedHeaderOffset + sizeof(IPX_HEADER)]);
+#endif
+ RipPacket = (PRIP_PACKET)(&Reserved->Header[MAC_HEADER_SIZE + sizeof(IPX_HEADER)]);
+ RipPacket->Operation = Operation & 0x7fff;
+ RipPacket->NetworkEntry.NetworkNumber = Network;
+
+ if (Operation == RIP_REQUEST) {
+ RipPacket->NetworkEntry.HopCount = REORDER_USHORT(0xffff);
+ RipPacket->NetworkEntry.TickCount = REORDER_USHORT(0xffff);
+ } else if (Operation == RIP_RESPONSE) {
+ RipPacket->NetworkEntry.HopCount = REORDER_USHORT(1);
+ RipPacket->NetworkEntry.TickCount = REORDER_USHORT(2); // will be modified when sent
+ } else {
+ RipPacket->NetworkEntry.HopCount = REORDER_USHORT(16);
+ RipPacket->NetworkEntry.TickCount = REORDER_USHORT(16);
+ }
+
+ NdisAdjustBufferLength(pNdisIpxBuff, sizeof(IPX_HEADER) + sizeof(RIP_PACKET));
+ //
+ // Now insert this packet in the queue of pending RIP
+ // requests and start the timer if needed (this is done
+ // to ensure the RIP_GRANULARITY milliseconds inter-RIP-packet
+ // delay).
+ //
+
+ IPX_DEBUG (RIP, ("RIP %s for network %lx\n",
+ (Operation == RIP_REQUEST) ? "request" : ((Operation == RIP_RESPONSE) ? "announce" : "down"),
+ REORDER_ULONG(Network)));
+
+ InsertHeadList(
+ &Device->WaitingRipPackets,
+ &Reserved->WaitLinkage);
+
+ ++Device->RipPacketCount;
+
+ if (!Device->RipShortTimerActive) {
+
+ Device->RipShortTimerActive = TRUE;
+ IpxReferenceDevice (Device, DREF_RIP_TIMER);
+
+ CTEStartTimer(
+ &Device->RipShortTimer,
+ 1, // 1 ms, i.e. expire immediately
+ RipShortTimeout,
+ (PVOID)Device);
+ }
+
+ IpxReferenceDevice (Device, DREF_RIP_PACKET);
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ return STATUS_PENDING;
+
+} /* RipQueueRequest */
+
+
+VOID
+RipSendResponse(
+ IN PBINDING Binding,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PIPX_LOCAL_TARGET LocalTarget
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a respond to a RIP request from a client --
+ this is only used if we have a virtual network and the router
+ is not bound, and somebody queries on the virtual network.
+
+Arguments:
+
+ Binding - The binding on which the request was received.
+
+ RemoteAddress - The IPX source address of the request.
+
+ LocalTarget - The local target of the received packet.
+
+Return Value:
+
+ STATUS_PENDING if the request is queued, failure status
+ if it could not be.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PIPX_SEND_RESERVED Reserved;
+ TDI_ADDRESS_IPX LocalAddress;
+ PNDIS_PACKET Packet;
+ PIPX_HEADER IpxHeader;
+ PRIP_PACKET RipPacket;
+ PDEVICE Device = IpxDevice;
+ PBINDING MasterBinding;
+ NDIS_STATUS NdisStatus;
+ USHORT TickCount;
+ PNDIS_BUFFER pNdisIpxBuff;
+
+ //
+ // Get a packet to use for the RIP response.
+ //
+
+ s = IpxPopSendPacket (Device);
+
+ if (s == NULL) {
+ return;
+ }
+
+ IpxReferenceDevice (Device, DREF_RIP_PACKET);
+
+ Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+
+ //
+ // We have the packet, fill it in for this request.
+ //
+
+ Reserved->Identifier = IDENTIFIER_RIP_RESPONSE;
+ Reserved->DestinationType = DESTINATION_DEF;
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ //
+ // We aren't guaranteed that this is the case for packets
+ // on the free list.
+ //
+
+ pNdisIpxBuff = NDIS_BUFFER_LINKAGE (Reserved->HeaderBuffer);
+ NDIS_BUFFER_LINKAGE (pNdisIpxBuff) = NULL;
+
+ //
+ // If this binding is a binding set member, round-robin through
+ // the various bindings when responding. We will get some natural
+ // round-robinning because broadcast requests are received on
+ // binding set members in turn, but they are only rotated once
+ // a second.
+ //
+
+ if (Binding->BindingSetMember) {
+
+ //
+ // It's a binding set member, we round-robin the
+ // responses across all the cards to distribute
+ // the traffic.
+ //
+
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ }
+
+ //
+ // Fill in the IPX header at the correct offset.
+ //
+
+ LocalAddress.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory (LocalAddress.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ LocalAddress.Socket = RIP_SOCKET;
+#if 0
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[Binding->DefHeaderSize]);
+#endif
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[MAC_HEADER_SIZE]);
+
+ IpxConstructHeader(
+ (PUCHAR)IpxHeader,
+ sizeof(IPX_HEADER) + sizeof (RIP_PACKET),
+ RIP_PACKET_TYPE,
+ RemoteAddress,
+ &LocalAddress);
+
+ //
+ // In case the request comes from net 0, fill that in too.
+ //
+
+ *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork = Binding->LocalAddress.NetworkAddress;
+
+
+ //
+ // Fill in the RIP request.
+ //
+
+ RipPacket = (PRIP_PACKET)(IpxHeader+1);
+
+ RipPacket->Operation = RIP_RESPONSE;
+ RipPacket->NetworkEntry.NetworkNumber = Device->VirtualNetworkNumber;
+
+ RipPacket->NetworkEntry.HopCount = REORDER_USHORT(1);
+ TickCount = (USHORT)(((839 + Binding->MediumSpeed) / Binding->MediumSpeed) + 1);
+ RipPacket->NetworkEntry.TickCount = REORDER_USHORT(TickCount);
+
+ IPX_DEBUG (RIP, ("RIP response for virtual network %lx\n",
+ REORDER_ULONG(Device->VirtualNetworkNumber)));
+
+ NdisAdjustBufferLength(pNdisIpxBuff, sizeof(IPX_HEADER) + sizeof(RIP_PACKET));
+ //
+ // Now submit the packet to NDIS.
+ //
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ if ((NdisStatus = IpxSendFrame(
+ LocalTarget,
+ Packet,
+ sizeof(RIP_PACKET) + sizeof(IPX_HEADER),
+ sizeof(RIP_PACKET) + sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ IpxSendComplete(
+ (NDIS_HANDLE)Binding->Adapter,
+ Packet,
+ NdisStatus);
+ }
+
+#ifdef _PNP_POWER
+ if (Binding->BindingSetMember) {
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ }
+#endif
+ return;
+
+} /* RipSendResponse */
+
+
+VOID
+RipShortTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the RIP short timer expires.
+ It is called every RIP_GRANULARITY milliseconds unless there
+ is nothing to do.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the device pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)Context;
+ PLIST_ENTRY p;
+ PIPX_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ USHORT OldNicId, NewNicId;
+ ULONG OldOffset, NewOffset;
+ PIPX_HEADER IpxHeader;
+ PBINDING Binding, MasterBinding;
+ NDIS_STATUS NdisStatus;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+#ifdef _PNP_LATER
+ static IPX_LOCAL_TARGET BroadcastTarget = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, {0, 0, 0} };
+#else
+ static IPX_LOCAL_TARGET BroadcastTarget = { 0, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
+#endif
+
+ static ULONG ZeroNetwork = 0;
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ ++Device->RipSendTime;
+
+ if (Device->RipPacketCount == 0) {
+
+ Device->RipShortTimerActive = FALSE;
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IpxDereferenceDevice (Device, DREF_RIP_TIMER);
+
+ return;
+ }
+
+ //
+ // Check what is on the queue; this is set up as a
+ // loop but in fact it rarely does (under no
+ // circumstances can we send more than one packet
+ // each time this function executes).
+ //
+
+ while (TRUE) {
+
+ p = Device->WaitingRipPackets.Flink;
+ if (p == &Device->WaitingRipPackets) {
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ Reserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
+
+ if ((Reserved->u.SR_RIP.RouteFound) && (!Reserved->SendInProgress)) {
+
+ (VOID)RemoveHeadList (&Device->WaitingRipPackets);
+ Reserved->Identifier = IDENTIFIER_IPX;
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+ --Device->RipPacketCount;
+
+ //
+ // It is OK to do this with the lock held because
+ // it won't be the last one (we have the RIP_TIMER ref).
+ //
+
+ IpxDereferenceDevice (Device, DREF_RIP_PACKET);
+ continue;
+ }
+
+ if ((((SHORT)(Device->RipSendTime - Reserved->u.SR_RIP.SendTime)) < 0) ||
+ Reserved->SendInProgress) {
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ (VOID)RemoveHeadList (&Device->WaitingRipPackets);
+
+ //
+ // Find the right binding to send to. If NoIdAdvance
+ // is set, then the binding doesn't need to be changed
+ // this time (this means we wrapped last time).
+ //
+
+ OldNicId = Reserved->u.SR_RIP.CurrentNicId;
+
+ if (!Reserved->u.SR_RIP.NoIdAdvance) {
+
+ BOOLEAN FoundNext = FALSE;
+
+#ifdef _PNP_POWER
+//
+// To maintain the lock order, release Device lock here and re-acquire later
+//
+ USHORT StartId;
+
+ if (Device->ValidBindings == 0) {
+ IPX_DEBUG(PNP, ("ValidBindings 0 in RipShortTimeOut\n"));
+
+ Device->RipShortTimerActive = FALSE;
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IpxDereferenceDevice (Device, DREF_RIP_TIMER);
+ return;
+ }
+
+ StartId = (USHORT)((OldNicId % MIN (Device->MaxBindings, Device->ValidBindings)) + 1);
+
+ NewNicId = StartId;
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#else
+
+ USHORT StartId = (USHORT)((OldNicId % Device->BindingCount) + 1);
+
+ NewNicId = StartId;
+#endif
+ do {
+
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, NewNicId);
+#else
+ Binding = Device->Bindings[NewNicId];
+#endif
+ if (Reserved->u.SR_RIP.Network != 0xffffffff) {
+
+ //
+ // We are looking for a real net; check that
+ // the next binding is valid. If it is a WAN
+ // binding, we don't send queries if the router
+ // is bound. If it is a LAN binding, we don't
+ // send queries if we are configured for
+ // SingleNetworkActive and the WAN is up.
+ // We also don't send queries on binding set
+ // members which aren't masters.
+ //
+
+ if ((Binding != NULL)
+ &&
+ ((!Binding->Adapter->MacInfo.MediumAsync) ||
+ (!Device->UpperDriverBound[IDENTIFIER_RIP]))
+ &&
+ ((Binding->Adapter->MacInfo.MediumAsync) ||
+ (!Device->SingleNetworkActive) ||
+ (!Device->ActiveNetworkWan))
+ &&
+ ((!Binding->BindingSetMember) ||
+ (Binding->CurrentSendBinding))) {
+
+ FoundNext = TRUE;
+ break;
+ }
+
+ } else {
+
+ //
+ // We are sending out the initial request to net
+ // 0xffffffff, to generate traffic so we can figure
+ // out our real network number. We don't do this
+ // to nets that already have a number and we don't
+ // do it on WAN links. We also don't do it on
+ // auto-detect nets if we have found the default.
+ //
+
+
+ if ((Binding != NULL) &&
+ (Binding->TentativeNetworkAddress == 0) &&
+ (!Binding->Adapter->MacInfo.MediumAsync) &&
+ (!Binding->AutoDetect || !Binding->Adapter->DefaultAutoDetected)) {
+ FoundNext = TRUE;
+ break;
+ }
+ }
+#ifdef _PNP_POWER
+ //
+ // [BUGBUGZZ] Why cycle thru the entire list?
+ //
+ NewNicId = (USHORT)((NewNicId % MIN (Device->MaxBindings, Device->ValidBindings)) + 1);
+#else
+ NewNicId = (USHORT)((NewNicId % Device->BindingCount) + 1);
+#endif
+ } while (NewNicId != StartId);
+
+ if (!FoundNext) {
+
+ //
+ // Nothing more needs to be done with this packet,
+ // leave it off the queue and since we didn't send
+ // a packet we can check for more.
+ //
+#ifndef _PNP_POWER
+ //
+ // This was released above (before the BindAccessLock was taken
+ //
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+#endif
+ RipCleanupPacket(Device, Reserved);
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+ --Device->RipPacketCount;
+ IpxDereferenceDevice (Device, DREF_RIP_PACKET);
+ continue;
+
+ }
+
+#ifdef _PNP_POWER
+
+ IPX_DEBUG(RIP, ("RIP: FoundNext: %lx, StartId: %lx, OldNicId: %lx, NewNicId: %lx\n", FoundNext, StartId, OldNicId, NewNicId));
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // Re-acquire the Device lock
+ //
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+#endif
+
+ Reserved->u.SR_RIP.CurrentNicId = NewNicId;
+
+ //
+ // Move the data around if needed.
+ //
+
+#if 0
+ if (OldNicId != NewNicId) {
+
+ if (OldNicId == 0) {
+ OldOffset = Device->IncludedHeaderOffset;
+ } else {
+ OldOffset = Device->Bindings[OldNicId]->BcMcHeaderSize;
+ }
+
+ NewOffset = Binding->BcMcHeaderSize;
+
+ if (OldOffset != NewOffset) {
+
+ RtlMoveMemory(
+ &Reserved->Header[NewOffset],
+ &Reserved->Header[OldOffset],
+ sizeof(IPX_HEADER) + sizeof(RIP_PACKET));
+
+ }
+
+ }
+#endif
+
+ if (NewNicId <= OldNicId) {
+
+ //
+ // We found a new binding but we wrapped, so increment
+ // the counter. If we have done all the resends, or
+ // this is a response (indicated by retry count of 0xff;
+ // they are only sent once) then clean up.
+ //
+
+ if ((Reserved->u.SR_RIP.RetryCount >= 0xfe) ||
+ ((++Reserved->u.SR_RIP.RetryCount) == Device->RipCount)) {
+
+ //
+ // This packet is stale, clean it up and continue.
+ //
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ RipCleanupPacket(Device, Reserved);
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+ --Device->RipPacketCount;
+ IpxDereferenceDevice (Device, DREF_RIP_PACKET);
+
+ } else {
+
+ //
+ // We wrapped, so put ourselves back in the queue
+ // at the end.
+ //
+
+ Reserved->u.SR_RIP.SendTime = (USHORT)(Device->RipSendTime + Device->RipTimeout - 1);
+ Reserved->u.SR_RIP.NoIdAdvance = TRUE;
+ InsertTailList (&Device->WaitingRipPackets, &Reserved->WaitLinkage);
+
+#ifdef _PNP_POWER
+ //
+ // Free the Device lock before deref'ing the Binding so we maintain
+ // the lock order: BindingAccess > GlobalInterLock > Device
+ //
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+#endif
+ }
+
+ continue;
+
+ }
+#ifdef _PNP_POWER
+//
+// To prevent the re-acquire of the device lock, this is moved up...
+//
+ //
+ // Send it again as soon as possible (it we just wrapped, then
+ // we will have put ourselves at the tail and won't get here).
+ //
+
+ InsertHeadList (&Device->WaitingRipPackets, &Reserved->WaitLinkage);
+
+ CTEAssert (Reserved->Identifier == IDENTIFIER_RIP_INTERNAL);
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+#endif
+ } else {
+
+ //
+ // Next time we need to advance the binding.
+ //
+
+ Reserved->u.SR_RIP.NoIdAdvance = FALSE;
+ NewNicId = OldNicId;
+#ifdef _PNP_POWER
+ //
+ // Send it again as soon as possible (it we just wrapped, then
+ // we will have put ourselves at the tail and won't get here).
+ //
+
+ InsertHeadList (&Device->WaitingRipPackets, &Reserved->WaitLinkage);
+
+ CTEAssert (Reserved->Identifier == IDENTIFIER_RIP_INTERNAL);
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ Binding = NIC_ID_TO_BINDING(Device, NewNicId);
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ Binding = Device->Bindings[NewNicId];
+#endif
+
+ }
+#ifndef _PNP_POWER
+ //
+ // Send it again as soon as possible (it we just wrapped, then
+ // we will have put ourselves at the tail and won't get here).
+ //
+
+ InsertHeadList (&Device->WaitingRipPackets, &Reserved->WaitLinkage);
+
+ CTEAssert (Reserved->Identifier == IDENTIFIER_RIP_INTERNAL);
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+#endif
+ //
+ // This packet should be sent on binding NewNicId; first
+ // move the data to the right location for the current
+ // binding.
+ //
+#ifdef _PNP_POWER
+ CTEAssert (Binding == NIC_ID_TO_BINDING(Device, NewNicId)); // temp, just to make sure
+#else
+ CTEAssert (Binding == Device->Bindings[NewNicId]); // temp, just to make sure
+#endif
+// NewOffset = Binding->BcMcHeaderSize;
+
+ //
+ // Now submit the packet to NDIS.
+ //
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&BroadcastTarget, NewNicId);
+#else
+ BroadcastTarget.NicId = NewNicId;
+#endif
+
+ //
+ // Modify the header so the packet comes from this
+ // specific adapter, not the virtual network.
+ //
+
+ // IpxHeader = (PIPX_HEADER)(&Reserved->Header[NewOffset]);
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[MAC_HEADER_SIZE]);
+
+ if (Reserved->u.SR_RIP.Network == 0xffffffff) {
+ *(UNALIGNED ULONG *)IpxHeader->SourceNetwork = 0;
+ } else {
+ *(UNALIGNED ULONG *)IpxHeader->SourceNetwork = Binding->LocalAddress.NetworkAddress;
+ }
+
+ if (Reserved->u.SR_RIP.RetryCount < 0xfe) {
+
+ //
+ // This is an outgoing query. We round-robin these through
+ // binding sets.
+ //
+
+ if (Binding->BindingSetMember) {
+
+ //
+ // Shouldn't have any binding sets during initial
+ // discovery.
+ //
+
+ CTEAssert (Reserved->u.SR_RIP.Network != 0xffffffff);
+
+ //
+ // If we are in a binding set, then use the current binding
+ // in the set for this send, and advance the current binding.
+ // The places we have used Binding before here will be fine
+ // since the binding set members all have the same media
+ // and frame type.
+ //
+
+ CTEAssert (Binding->CurrentSendBinding); // should be a master.
+ MasterBinding = Binding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+#ifdef _PNP_POWER
+ //
+ // [BUGBUGZZ]: We dont have a lock here - the masterbinding could be bogus
+ //
+ IpxDereferenceBinding1(MasterBinding, BREF_DEVICE_ACCESS);
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ }
+ }
+
+
+ RtlCopyMemory (IpxHeader->SourceNode, Binding->LocalAddress.NodeAddress, 6);
+
+ //
+ // Bug# 6485
+ // Rip request, general or specific, is putting the network of the
+ // node to which the route has to be found in the ipx header remote
+ // network field. Some novell routers don't like that. This network
+ // field should be 0.
+ //
+ {
+ PRIP_PACKET RipPacket = (PRIP_PACKET)(&Reserved->Header[MAC_HEADER_SIZE + sizeof(IPX_HEADER)]);
+
+ if (RipPacket->Operation != RIP_REQUEST) {
+ *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork = Binding->LocalAddress.NetworkAddress;
+ } else {
+ *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork = 0;
+ }
+ }
+
+ //
+ // If this is a RIP_RESPONSE, set the tick count for this
+ // binding.
+ //
+
+ if (Reserved->u.SR_RIP.RetryCount == 0xfe) {
+
+ PRIP_PACKET RipPacket = (PRIP_PACKET)(IpxHeader+1);
+ USHORT TickCount = (USHORT)
+ (((839 + Binding->MediumSpeed) / Binding->MediumSpeed) + 1);
+
+ RipPacket->NetworkEntry.TickCount = REORDER_USHORT(TickCount);
+
+ }
+
+ if ((NdisStatus = IpxSendFrame(
+ &BroadcastTarget,
+ Packet,
+ sizeof(RIP_PACKET) + sizeof(IPX_HEADER),
+ sizeof(RIP_PACKET) + sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ IpxSendComplete(
+ (NDIS_HANDLE)Binding->Adapter,
+ Packet,
+ NdisStatus);
+ }
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+
+ break;
+
+ }
+
+ CTEStartTimer(
+ &Device->RipShortTimer,
+ RIP_GRANULARITY,
+ RipShortTimeout,
+ (PVOID)Device);
+
+} /* RipShortTimeout */
+
+
+VOID
+RipLongTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the RIP long timer expires.
+ It is called every minute and handles periodic re-RIPping
+ to ensure that entries are accurate, as well as aging out
+ of entries if the rip router is not bound.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the device pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)Context;
+ PROUTER_SEGMENT RouterSegment;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ UINT Segment;
+ UINT i;
+ PBINDING Binding;
+ IPX_DEFINE_LOCK_HANDLE(LockHandle)
+
+ //
+ // [FW] TRUE if there are no more entries to age out.
+ //
+ BOOLEAN fMoreToAge=FALSE;
+
+ //
+ // Rotate the broadcast receiver on all binding sets.
+ // We can loop up to HighestExternal only since we
+ // are only interested in finding binding set masters.
+ //
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ if ((Binding != NULL) &&
+ (Binding->CurrentSendBinding)) {
+
+ //
+ // It is a master, so find the current broadcast
+ // receiver, then advance it.
+ //
+
+ while (TRUE) {
+ if (Binding->ReceiveBroadcast) {
+ Binding->ReceiveBroadcast = FALSE;
+ Binding->NextBinding->ReceiveBroadcast = TRUE;
+ break;
+ } else {
+ Binding = Binding->NextBinding;
+ }
+ }
+ }
+ }
+ }
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+
+ //
+ // If RIP is bound, we don't do any of this, and
+ // we stop the timer from running.
+ //
+
+ if (Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ //
+ // [FW] For the case when the Forwarder appears after our table has
+ // been primed, we need to age out these entries....
+ //
+ if (Device->ForwarderBound) {
+ goto ageout;
+ }
+
+ IpxDereferenceDevice (Device, DREF_LONG_TIMER);
+ return;
+ }
+
+
+ //
+ // If we have a virtual net, do our periodic broadcast.
+ //
+
+ if (Device->RipResponder) {
+ (VOID)RipQueueRequest (Device->VirtualNetworkNumber, RIP_RESPONSE);
+ }
+
+
+ //
+ // Update the real counters from the temp ones.
+ //
+
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DatagramBytesSent,
+ Device->TempDatagramBytesSent);
+ Device->Statistics.DatagramsSent += Device->TempDatagramsSent;
+
+ Device->TempDatagramBytesSent = 0;
+ Device->TempDatagramsSent = 0;
+
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DatagramBytesReceived,
+ Device->TempDatagramBytesReceived);
+ Device->Statistics.DatagramsReceived += Device->TempDatagramsReceived;
+
+ Device->TempDatagramBytesReceived = 0;
+ Device->TempDatagramsReceived = 0;
+
+
+ //
+ // We need to scan each hash bucket to see if there
+ // are any active entries which need to be re-RIPped
+ // for. We also scan for entries that should be timed
+ // out.
+ //
+
+ageout:
+ for (Segment = 0; Segment < Device->SegmentCount; Segment++) {
+
+ RouterSegment = &IpxDevice->Segments[Segment];
+
+ //
+ // Don't take the lock if the bucket is empty.
+ //
+
+ if (RouterSegment->Entries.Flink == &RouterSegment->Entries) {
+ continue;
+ }
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Scan through each entry looking for ones to age.
+ //
+
+ for (RouteEntry = RipGetFirstRoute (Segment);
+ RouteEntry != (PIPX_ROUTE_ENTRY)NULL;
+ RouteEntry = RipGetNextRoute (Segment)) {
+
+ if (RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY) {
+ continue;
+ }
+
+ //
+ // [FW] There are more entries to age
+ //
+ fMoreToAge = TRUE;
+
+ ++RouteEntry->Timer;
+ if (RouteEntry->Timer >= Device->RipUsageTime) {
+
+ RipDeleteRoute (Segment, RouteEntry);
+ IpxFreeMemory(RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ continue;
+
+ }
+
+ //
+ // See if we should re-RIP for this segment. It has
+ // to have been around for RipAgeTime, and we also
+ // make sure that the Timer is not too high to
+ // prevent us from re-RIPping on unused routes.
+ //
+
+ ++RouteEntry->PRIVATE.Reserved[0];
+
+ if ((RouteEntry->PRIVATE.Reserved[0] >= Device->RipAgeTime) &&
+ (RouteEntry->Timer <= Device->RipAgeTime) &&
+ !Device->ForwarderBound) {
+
+ //
+ // If we successfully queue a request, then reset
+ // Reserved[0] so we don't re-RIP for a while.
+ //
+
+ if (RipQueueRequest (*(UNALIGNED ULONG *)RouteEntry->Network, RIP_REQUEST) == STATUS_PENDING) {
+ RouteEntry->PRIVATE.Reserved[0] = 0;
+ }
+ }
+ }
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+
+ }
+
+
+ //
+ // [FW] If RIP installed, restart the timer only if there was at least
+ // one entry which could be aged.
+ //
+
+ if (Device->ForwarderBound) {
+
+ if (fMoreToAge) {
+
+ IPX_DEBUG(RIP, ("More entries to age - restarting long timer\n"));
+ CTEStartTimer(
+ &Device->RipLongTimer,
+ 60000, // one minute timeout
+ RipLongTimeout,
+ (PVOID)Device);
+
+ } else {
+
+ //
+ // Else, dont restart the timer and deref the device
+ //
+
+ IPX_DEBUG(RIP, ("No more entries to age - derefing the device\n"));
+ IpxDereferenceDevice (Device, DREF_LONG_TIMER);
+ }
+ } else {
+ //
+ // Now restart the timer for the next timeout.
+ //
+
+ if (Device->State == DEVICE_STATE_OPEN) {
+
+ CTEStartTimer(
+ &Device->RipLongTimer,
+ 60000, // one minute timeout
+ RipLongTimeout,
+ (PVOID)Device);
+
+ } else {
+
+ //
+ // Send a DOWN packet if needed, then stop ourselves.
+ //
+
+ if (Device->RipResponder) {
+
+ if (RipQueueRequest (Device->VirtualNetworkNumber, RIP_DOWN) != STATUS_PENDING) {
+
+ //
+ // We need to kick this event because the packet completion
+ // won't.
+ //
+
+ KeSetEvent(
+ &Device->UnloadEvent,
+ 0L,
+ FALSE);
+ }
+ }
+
+ IpxDereferenceDevice (Device, DREF_LONG_TIMER);
+ }
+ }
+
+} /* RipLongTimeout */
+
+
+VOID
+RipCleanupPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_RESERVED RipReserved
+ )
+
+/*++
+
+Routine Description:
+
+ This routine cleans up when a RIP packet times out.
+
+Arguments:
+
+ Device - The device.
+
+ RipReserved - The ProtocolReserved section of the RIP packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Segment;
+ IPX_DEFINE_LOCK_HANDLE_PARAM (LockHandle)
+
+ if (RipReserved->u.SR_RIP.RetryCount < 0xfe) {
+
+ if (RipReserved->u.SR_RIP.Network != 0xffffffff) {
+
+ IPX_DEBUG (RIP, ("Timing out RIP for network %lx\n",
+ REORDER_ULONG(RipReserved->u.SR_RIP.Network)));
+
+ Segment = RipGetSegment ((PUCHAR)&RipReserved->u.SR_RIP.Network);
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Fail all datagrams, etc. that were waiting for
+ // this route. This call releases the lock.
+ //
+
+ RipHandleRoutePending(
+ Device,
+ (PUCHAR)&(RipReserved->u.SR_RIP.Network),
+ LockHandle,
+ FALSE,
+ NULL,
+ 0,
+ 0);
+
+ } else {
+
+ //
+ // This was the initial query looking for networks --
+ // signal the init thread which is waiting.
+ //
+
+ IPX_DEBUG (AUTO_DETECT, ("Signalling auto-detect event\n"));
+ KeSetEvent(
+ &Device->AutoDetectEvent,
+ 0L,
+ FALSE);
+
+ }
+
+ } else if (RipReserved->u.SR_RIP.RetryCount == 0xff) {
+
+ //
+ // This is a DOWN message, set the device event that
+ // is waiting for it to complete.
+ //
+
+ KeSetEvent(
+ &Device->UnloadEvent,
+ 0L,
+ FALSE);
+ }
+
+ //
+ // Put the RIP packet back in the pool.
+ //
+
+ RipReserved->Identifier = IDENTIFIER_IPX;
+
+} /* RipCleanupPacket */
+
+
+VOID
+RipProcessResponse(
+ IN PDEVICE Device,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN RIP_PACKET UNALIGNED * RipPacket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a RIP response from the specified
+ local target, indicating a route to the network in the RIP
+ header.
+
+Arguments:
+
+ Device - The device.
+
+ LocalTarget - The router that the frame was received from.
+
+ RipPacket - The RIP response header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED RipReserved; // ProtocolReserved of RIP packet
+ ULONG Segment;
+ PIPX_ROUTE_ENTRY RouteEntry, OldRouteEntry;
+ PLIST_ENTRY p;
+ IPX_DEFINE_LOCK_HANDLE_PARAM (LockHandle)
+
+ //
+ // Since we have received a RIP response for this network.
+ // kill the waiting RIP packets for it if it exists.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (p = Device->WaitingRipPackets.Flink;
+ p != &Device->WaitingRipPackets;
+ p = p->Flink) {
+
+ RipReserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
+
+ if (RipReserved->u.SR_RIP.RetryCount >= 0xfe) {
+ continue;
+ }
+
+ if (RipReserved->u.SR_RIP.Network ==
+ RipPacket->NetworkEntry.NetworkNumber) {
+ break;
+ }
+
+ }
+
+ if (p == &Device->WaitingRipPackets) {
+
+ //
+ // No packets pending on this, return.
+ //
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+
+ //
+ // Put the RIP packet back in the pool.
+ //
+
+ IPX_DEBUG (RIP, ("Got RIP response for network %lx\n",
+ REORDER_ULONG(RipPacket->NetworkEntry.NetworkNumber)));
+
+ RipReserved->u.SR_RIP.RouteFound = TRUE;
+ if (!RipReserved->SendInProgress) {
+
+ //
+ // If the send is done destroy it now, otherwise
+ // when it pops up in RipShortTimeout it will get
+ // destroyed because RouteFound is TRUE.
+ //
+
+ RemoveEntryList (p);
+ RipReserved->Identifier = IDENTIFIER_IPX;
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &RipReserved->PoolLinkage, &Device->SListsLock);
+ --Device->RipPacketCount;
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ IpxDereferenceDevice (Device, DREF_RIP_PACKET);
+
+ } else {
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+
+
+ //
+ // Try to allocate and add a router segment unless the
+ // RIP router is active...if we don't that is fine, we'll
+ // just re-RIP later.
+ //
+
+ Segment = RipGetSegment ((PUCHAR)&RipPacket->NetworkEntry.NetworkNumber);
+
+ if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
+
+ RouteEntry = IpxAllocateMemory(sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ if (RouteEntry != (PIPX_ROUTE_ENTRY)NULL) {
+
+ *(UNALIGNED LONG *)RouteEntry->Network = RipPacket->NetworkEntry.NetworkNumber;
+#ifdef _PNP_POWER
+ RouteEntry->NicId = NIC_FROM_LOCAL_TARGET(LocalTarget);
+ RouteEntry->NdisBindingContext = NIC_ID_TO_BINDING(Device, RouteEntry->NicId)->Adapter->NdisBindingHandle;
+ // BUGBUG: What if this is NULL??
+#else
+ RouteEntry->NicId = LocalTarget->NicId;
+ RouteEntry->NdisBindingContext = Device->Bindings[LocalTarget->NicId]->Adapter->NdisBindingHandle; // BUGBUG: What if this is NULL??
+#endif
+ RouteEntry->Flags = 0;
+ RouteEntry->Timer = 0;
+ RouteEntry->PRIVATE.Reserved[0] = 0;
+ RouteEntry->Segment = Segment;
+ RouteEntry->HopCount = REORDER_USHORT(RipPacket->NetworkEntry.HopCount);
+ RouteEntry->TickCount = REORDER_USHORT(RipPacket->NetworkEntry.TickCount);
+ InitializeListHead (&RouteEntry->AlternateRoute);
+ InitializeListHead (&RouteEntry->NicLinkage);
+ RtlCopyMemory (RouteEntry->NextRouter, LocalTarget->MacAddress, 6);
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Replace any existing routes. This is OK because once
+ // we get the first response to a RIP packet on a given
+ // route, we will take the packet out of the queue and
+ // ignore further responses. We will only get a bad route
+ // if we do two requests really quickly and there
+ // are two routes, and the second response to the first
+ // request is picked up as the first response to the second
+ // request.
+ //
+
+ if ((OldRouteEntry = RipGetRoute (Segment, (PUCHAR)&(RipPacket->NetworkEntry.NetworkNumber))) != NULL) {
+
+ //
+ // These are saved so timeouts etc. happen right.
+ //
+
+ RouteEntry->Flags = OldRouteEntry->Flags;
+ RouteEntry->Timer = OldRouteEntry->Timer;
+
+ RipDeleteRoute (Segment, OldRouteEntry);
+ IpxFreeMemory(OldRouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+
+ }
+
+ RipAddRoute (Segment, RouteEntry);
+
+ } else {
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+ }
+
+ } else {
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+ }
+
+ //
+ // Complete all datagrams etc. that were waiting
+ // for this route. This call releases the lock.
+ //
+
+ RipHandleRoutePending(
+ Device,
+ (PUCHAR)&(RipPacket->NetworkEntry.NetworkNumber),
+ LockHandle,
+ TRUE,
+ LocalTarget,
+ (USHORT)(REORDER_USHORT(RipPacket->NetworkEntry.HopCount)),
+ (USHORT)(REORDER_USHORT(RipPacket->NetworkEntry.TickCount))
+ );
+
+} /* RipProcessResponse */
+
+VOID
+RipHandleRoutePending(
+ IN PDEVICE Device,
+ IN UCHAR Network[4],
+ IN CTELockHandle LockHandle,
+ IN BOOLEAN Success,
+ IN OPTIONAL PIPX_LOCAL_TARGET LocalTarget,
+ IN OPTIONAL USHORT HopCount,
+ IN OPTIONAL USHORT TickCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine cleans up pending datagrams, find route
+ requests, and GET_LOCAL_TARGET ioctls that were
+ waiting for a route to be found.
+
+ THIS ROUTINE IS CALLED WITH THE SEGMENT LOCK HELD AND
+ RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Device - The device.
+
+ Network - The network in question.
+
+ LockHandle - The handle used to acquire the lock.
+
+ Success - TRUE if the route was successfully found.
+
+ LocalTarget - If Success is TRUE, the local target for the route.
+
+ HopCount - If Success is TRUE, the hop count for the route,
+ in machine order.
+
+ TickCount - If Success is TRUE, the tick count for the route,
+ in machine order.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ LIST_ENTRY DatagramList;
+ LIST_ENTRY FindRouteList;
+ LIST_ENTRY GetLocalTargetList;
+ LIST_ENTRY ReripNetnumList;
+ PIPX_SEND_RESERVED WaitReserved; // ProtocolReserved of waiting packet
+ PIPX_FIND_ROUTE_REQUEST FindRouteRequest;
+ PREQUEST GetLocalTargetRequest;
+ PREQUEST ReripNetnumRequest;
+ PISN_ACTION_GET_LOCAL_TARGET GetLocalTarget;
+ PIPX_NETNUM_DATA NetnumData;
+ ULONG Segment;
+ PBINDING Binding, SendBinding;
+ PLIST_ENTRY p;
+ PNDIS_PACKET Packet;
+ PIPX_HEADER IpxHeader;
+ ULONG HeaderSize;
+ NDIS_STATUS NdisStatus;
+ ULONG NetworkUlong = *(UNALIGNED ULONG *)Network;
+
+
+ InitializeListHead (&DatagramList);
+ InitializeListHead (&FindRouteList);
+ InitializeListHead (&GetLocalTargetList);
+ InitializeListHead (&ReripNetnumList);
+
+
+ //
+ // Put all packets that were waiting for a route to
+ // this network on DatagramList. They will be sent
+ // or failed later in the routine.
+ //
+
+ Segment = RipGetSegment (Network);
+
+ p = Device->Segments[Segment].WaitingForRoute.Flink;
+
+ while (p != &Device->Segments[Segment].WaitingForRoute) {
+
+ WaitReserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
+ p = p->Flink;
+#if 0
+ if (*(UNALIGNED ULONG *)(((PIPX_HEADER)(&WaitReserved->Header[Device->IncludedHeaderOffset]))->DestinationNetwork) ==
+ NetworkUlong) {
+#endif
+ if (*(UNALIGNED ULONG *)(((PIPX_HEADER)(&WaitReserved->Header[MAC_HEADER_SIZE]))->DestinationNetwork) ==
+ NetworkUlong) {
+
+ RemoveEntryList (&WaitReserved->WaitLinkage);
+ InsertTailList (&DatagramList, &WaitReserved->WaitLinkage);
+ }
+
+ }
+
+ //
+ // Put all find route requests for this network on
+ // FindRouteList. They will be completed later in the
+ // routine.
+ //
+
+ p = Device->Segments[Segment].FindWaitingForRoute.Flink;
+
+ while (p != &Device->Segments[Segment].FindWaitingForRoute) {
+
+ FindRouteRequest = CONTAINING_RECORD (p, IPX_FIND_ROUTE_REQUEST, Linkage);
+ p = p->Flink;
+ if (*(UNALIGNED ULONG *)(FindRouteRequest->Network) ==
+ NetworkUlong) {
+
+ RemoveEntryList (&FindRouteRequest->Linkage);
+ InsertTailList (&FindRouteList, &FindRouteRequest->Linkage);
+ }
+
+ }
+
+ //
+ // Put all get local target action requests for this
+ // network on GetLocalTargetList. They will be completed
+ // later in the routine.
+ //
+
+ p = Device->Segments[Segment].WaitingLocalTarget.Flink;
+
+ while (p != &Device->Segments[Segment].WaitingLocalTarget) {
+
+ GetLocalTargetRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+ GetLocalTarget = (PISN_ACTION_GET_LOCAL_TARGET)REQUEST_INFORMATION(GetLocalTargetRequest);
+ if (GetLocalTarget->IpxAddress.NetworkAddress == NetworkUlong) {
+
+ RemoveEntryList (REQUEST_LINKAGE(GetLocalTargetRequest));
+ InsertTailList (&GetLocalTargetList, REQUEST_LINKAGE(GetLocalTargetRequest));
+ }
+
+ }
+
+ //
+ // Put all MIPX_RERIPNETNUM action requests for this
+ // network on ReripNetnumList. They will be completed
+ // later in the routine.
+ //
+
+ p = Device->Segments[Segment].WaitingReripNetnum.Flink;
+
+ while (p != &Device->Segments[Segment].WaitingReripNetnum) {
+
+ ReripNetnumRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+ NetnumData = (PIPX_NETNUM_DATA)REQUEST_INFORMATION(ReripNetnumRequest);
+ if (*(UNALIGNED ULONG *)NetnumData->netnum == NetworkUlong) {
+
+ RemoveEntryList (REQUEST_LINKAGE(ReripNetnumRequest));
+ InsertTailList (&ReripNetnumList, REQUEST_LINKAGE(ReripNetnumRequest));
+ }
+
+ }
+
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+
+ //
+ // For sends we will use the master binding of a binding
+ // set, but we'll return the real NicId for people who
+ // want that.
+ //
+
+ if (Success) {
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget));
+
+ if (Binding->BindingSetMember) {
+ SendBinding = Binding->MasterBinding;
+ FILL_LOCAL_TARGET(LocalTarget, MIN( Device->MaxBindings, SendBinding->NicId));
+ } else {
+ SendBinding = Binding;
+ }
+#else
+ Binding = Device->Bindings[LocalTarget->NicId];
+
+ if (Binding->BindingSetMember) {
+ SendBinding = Binding->MasterBinding;
+ LocalTarget->NicId = SendBinding->NicId;
+ } else {
+ SendBinding = Binding;
+ }
+#endif
+ }
+
+
+ //
+ // Now that the lock is free, process all packets on
+ // DatagramList.
+ //
+ // NOTE: May misorder packets if they come in right now...
+ //
+
+ for (p = DatagramList.Flink; p != &DatagramList ; ) {
+
+ WaitReserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
+ p = p->Flink;
+ Packet = CONTAINING_RECORD (WaitReserved, NDIS_PACKET, ProtocolReserved[0]);
+
+#if DBG
+ CTEAssert (!WaitReserved->SendInProgress);
+ WaitReserved->SendInProgress = TRUE;
+#endif
+
+ if (Success) {
+
+ IPX_DEBUG (RIP, ("Found queued packet %lx\n", WaitReserved));
+
+ if (REQUEST_INFORMATION(WaitReserved->u.SR_DG.Request) >
+ SendBinding->RealMaxDatagramSize) {
+
+ IPX_DEBUG (SEND, ("Queued send %d bytes too large (%d)\n",
+ REQUEST_INFORMATION(WaitReserved->u.SR_DG.Request),
+ SendBinding->RealMaxDatagramSize));
+
+ IpxSendComplete(
+ (NDIS_HANDLE)NULL,
+ Packet,
+ STATUS_INVALID_BUFFER_SIZE);
+
+ } else {
+
+#if 0
+ if (WaitReserved->DestinationType == DESTINATION_DEF) {
+ HeaderSize = SendBinding->DefHeaderSize;
+ } else {
+ HeaderSize = SendBinding->BcMcHeaderSize;
+ }
+
+ IpxHeader = (PIPX_HEADER)
+ (&WaitReserved->Header[HeaderSize]);
+#endif
+ IpxHeader = (PIPX_HEADER)
+ (&WaitReserved->Header[MAC_HEADER_SIZE]);
+
+ //
+ // Move the header to the correct location now that
+ // we know the NIC ID to send to.
+ //
+#if 0
+ if (HeaderSize != Device->IncludedHeaderOffset) {
+
+ RtlMoveMemory(
+ IpxHeader,
+ &WaitReserved->Header[Device->IncludedHeaderOffset],
+ sizeof(IPX_HEADER));
+
+ }
+#endif
+
+ if (Device->MultiCardZeroVirtual ||
+ (IpxHeader->DestinationSocket == SAP_SOCKET)) {
+
+ //
+ // These frames need to look like they come from the
+ // local network, not the virtual one.
+ //
+
+ *(UNALIGNED ULONG *)IpxHeader->SourceNetwork = SendBinding->LocalAddress.NetworkAddress;
+ RtlCopyMemory (IpxHeader->SourceNode, SendBinding->LocalAddress.NodeAddress, 6);
+ }
+
+ //
+ // Fill in the MAC header and submit the frame to NDIS.
+ //
+
+ if ((NdisStatus = IpxSendFrame(
+ LocalTarget,
+ Packet,
+ REQUEST_INFORMATION(WaitReserved->u.SR_DG.Request) + sizeof(IPX_HEADER),
+ sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ IpxSendComplete(
+ (NDIS_HANDLE)SendBinding->Adapter,
+ Packet,
+ NdisStatus);
+ }
+
+ }
+
+ } else {
+
+ IPX_DEBUG (RIP, ("Timing out packet %lx\n", WaitReserved));
+
+ IpxSendComplete(
+ (NDIS_HANDLE)NULL,
+ Packet,
+ STATUS_BAD_NETWORK_PATH);
+
+ }
+
+ }
+
+
+ //
+ // Since we round-robin outgoing rip packets, we just use the
+ // real NicId here for find route and get local target requests.
+ // We changed LocalTarget->NicId to be the master above.
+ //
+
+ if (Success) {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, MIN( Device->MaxBindings, Binding->NicId));
+#else
+ LocalTarget->NicId = Binding->NicId;
+#endif
+ }
+
+ for (p = FindRouteList.Flink; p != &FindRouteList ; ) {
+
+ FindRouteRequest = CONTAINING_RECORD (p, IPX_FIND_ROUTE_REQUEST, Linkage);
+ p = p->Flink;
+
+ if (Success) {
+
+ PUSHORT Counts;
+
+ IPX_DEBUG (RIP, ("Found queued find route %lx\n", FindRouteRequest));
+ FindRouteRequest->LocalTarget = *LocalTarget;
+
+ Counts = (PUSHORT)&FindRouteRequest->Reserved2;
+ Counts[0] = TickCount;
+ Counts[1] = HopCount;
+
+ } else {
+
+ IPX_DEBUG (RIP, ("Timing out find route %lx\n", FindRouteRequest));
+
+ }
+
+ (*Device->UpperDrivers[FindRouteRequest->Identifier].FindRouteCompleteHandler)(
+ FindRouteRequest,
+ Success);
+
+ }
+
+ for (p = GetLocalTargetList.Flink; p != &GetLocalTargetList ; ) {
+
+ GetLocalTargetRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+ GetLocalTarget = (PISN_ACTION_GET_LOCAL_TARGET)REQUEST_INFORMATION(GetLocalTargetRequest);
+
+ if (Success) {
+
+ IPX_DEBUG (RIP, ("Found queued LOCAL_TARGET action %lx\n", GetLocalTargetRequest));
+ GetLocalTarget->LocalTarget = *LocalTarget;
+ REQUEST_INFORMATION(GetLocalTargetRequest) = sizeof(ISN_ACTION_GET_LOCAL_TARGET);
+ REQUEST_STATUS(GetLocalTargetRequest) = STATUS_SUCCESS;
+
+ } else {
+
+ IPX_DEBUG (RIP, ("Timing out LOCAL_TARGET action %lx\n", GetLocalTargetRequest));
+ REQUEST_INFORMATION(GetLocalTargetRequest) = 0;
+ REQUEST_STATUS(GetLocalTargetRequest) = STATUS_BAD_NETWORK_PATH;
+ }
+
+ IpxCompleteRequest(GetLocalTargetRequest);
+ IpxFreeRequest(Device, GetLocalTargetRequest);
+
+ }
+
+ //
+ // NOTE: LocalTarget->NicId now points to the real binding
+ // not the master, so we use SendBinding->NicId below.
+ //
+
+ for (p = ReripNetnumList.Flink; p != &ReripNetnumList ; ) {
+
+ ReripNetnumRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+ NetnumData = (PIPX_NETNUM_DATA)REQUEST_INFORMATION(ReripNetnumRequest);
+
+ if (Success) {
+
+ IPX_DEBUG (RIP, ("Found queued MIPX_RERIPNETNUM action %lx\n", ReripNetnumRequest));
+ NetnumData->hopcount = HopCount;
+ NetnumData->netdelay = TickCount;
+ NetnumData->cardnum = (INT)(MIN( Device->MaxBindings, SendBinding->NicId) - 1);
+ RtlMoveMemory (NetnumData->router, LocalTarget->MacAddress, 6);
+
+ REQUEST_INFORMATION(ReripNetnumRequest) =
+ FIELD_OFFSET(NWLINK_ACTION, Data[0]) + sizeof(IPX_NETNUM_DATA);
+ REQUEST_STATUS(ReripNetnumRequest) = STATUS_SUCCESS;
+
+ } else {
+
+ IPX_DEBUG (RIP, ("Timing out MIPX_RERIPNETNUM action %lx\n", ReripNetnumRequest));
+ REQUEST_INFORMATION(ReripNetnumRequest) = 0;
+ REQUEST_STATUS(ReripNetnumRequest) = STATUS_BAD_NETWORK_PATH;
+ }
+
+ IpxCompleteRequest(ReripNetnumRequest);
+ IpxFreeRequest(Device, ReripNetnumRequest);
+
+ }
+
+} /* RipHandleRoutePending */
+
+
+NTSTATUS
+RipInsertLocalNetwork(
+ IN ULONG Network,
+ IN USHORT NicId,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN USHORT Count
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a router entry for a local network
+ and inserts it in the table.
+
+Arguments:
+
+ Network - The network.
+
+ NicId - The NIC ID used to route packets
+
+ NdisBindingHandle - The binding handle used for NdisSend
+
+ Count - The tick and hop count for this network (will be
+ 0 for the virtual net and 1 for attached nets)
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+ PIPX_ROUTE_ENTRY RouteEntry;
+ PDEVICE Device = IpxDevice;
+ ULONG Segment;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // BUGBUG: We should allocate the memory in the binding/device
+ // structure itself.
+ //
+
+ RouteEntry = IpxAllocateMemory(sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ if (RouteEntry == (PIPX_ROUTE_ENTRY)NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Segment = RipGetSegment ((PUCHAR)&Network);
+
+ *(UNALIGNED LONG *)RouteEntry->Network = Network;
+ RouteEntry->NicId = NicId;
+ RouteEntry->NdisBindingContext = NdisBindingContext;
+
+ if (NicId == 0) {
+ RouteEntry->Flags = IPX_ROUTER_PERMANENT_ENTRY;
+ } else {
+ RouteEntry->Flags = IPX_ROUTER_PERMANENT_ENTRY | IPX_ROUTER_LOCAL_NET;
+ }
+ RouteEntry->Segment = Segment;
+ RouteEntry->TickCount = Count;
+ RouteEntry->HopCount = 1;
+ InitializeListHead (&RouteEntry->AlternateRoute);
+ InitializeListHead (&RouteEntry->NicLinkage);
+
+ //
+ // RouteEntry->NextRouter is not used for the virtual net or
+ // when LOCAL_NET is set (i.e. every net that we will add here).
+ //
+
+ RtlZeroMemory (RouteEntry->NextRouter, 6);
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Make sure one doesn't exist.
+ //
+
+ if (RipGetRoute(Segment, (PUCHAR)&Network) != NULL) {
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ IpxFreeMemory (RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ return STATUS_DUPLICATE_NAME;
+ }
+
+ //
+ // Add this new entry.
+ //
+
+ if (RipAddRoute (Segment, RouteEntry)) {
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ return STATUS_SUCCESS;
+
+ } else {
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ IpxFreeMemory (RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+} /* RipInsertLocalNetwork */
+
+
+VOID
+RipAdjustForBindingChange(
+ IN USHORT NicId,
+ IN USHORT NewNicId,
+ IN IPX_BINDING_CHANGE_TYPE ChangeType
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when an auto-detect binding is
+ deleted or moved, or a WAN line goes down.
+
+ It scans the RIP database for routes equal to this NIC ID
+ and modifies them appropriately. If ChangeType is
+ IpxBindingDeleted it will subract one from any NIC IDs
+ in the database that are higher than NicId. It is assumed
+ that other code is readjusting the Device->Bindings
+ array.
+
+Arguments:
+
+ NicId - The NIC ID of the deleted binding.
+
+ NewNicId - The new NIC ID, for IpxBindingMoved changes.
+
+ ChangeType - Either IpxBindingDeleted, IpxBindingMoved,
+ or IpxBindingDown.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ UINT Segment;
+ CTELockHandle LockHandle;
+
+ for (Segment = 0; Segment < Device->SegmentCount; Segment++) {
+
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Scan through each entry comparing the NIC ID.
+ //
+
+ for (RouteEntry = RipGetFirstRoute (Segment);
+ RouteEntry != (PIPX_ROUTE_ENTRY)NULL;
+ RouteEntry = RipGetNextRoute (Segment)) {
+
+ if (RouteEntry->NicId == NicId) {
+
+ if (ChangeType != IpxBindingMoved) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Deleting route entry %lx, binding deleted\n", RouteEntry));
+ RipDeleteRoute (Segment, RouteEntry);
+
+ } else {
+
+ IPX_DEBUG (AUTO_DETECT, ("Changing NIC ID for route entry %lx\n", RouteEntry));
+ RouteEntry->NicId = NewNicId;
+
+ }
+#ifdef _PNP_POWER
+ //
+ // If the NicId is 0, we dont adjust the other entries' NicId's - this is to support the removal
+ // of the Virtual Net # which resides at NicId=0.
+ //
+ } else if (NicId && (ChangeType != IpxBindingDown) && (RouteEntry->NicId > NicId)) {
+#else
+ } else if ((ChangeType != IpxBindingDown) && (RouteEntry->NicId > NicId)) {
+#endif
+ IPX_DEBUG (AUTO_DETECT, ("Decrementing NIC ID for route entry %lx\n", RouteEntry));
+ --RouteEntry->NicId;
+
+ }
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+
+ }
+
+} /* RipAdjustForBindingChange */
+
+
+UINT
+RipGetSegment(
+ IN UCHAR Network[4]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the correct segment for the specified
+ network.
+
+Arguments:
+
+ Network - The network.
+
+Return Value:
+
+ The segment.
+
+--*/
+
+{
+
+ ULONG Total;
+
+ Total = Network[0] ^ Network[1] ^ Network[2] ^ Network[3];
+ return (Total % IpxDevice->SegmentCount);
+
+} /* RipGetSegment */
+
+
+PIPX_ROUTE_ENTRY
+RipGetRoute(
+ IN UINT Segment,
+ IN UCHAR Network[4]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the router table entry for the given
+ network, which is in the specified segment of the table.
+ THE SEGMENT LOCK MUST BE HELD. The returned data is valid
+ until the segment lock is released or other operations
+ (add/delete) are performed on the segment.
+
+Arguments:
+
+ Segment - The segment corresponding to the network.
+
+ Network - The network.
+
+Return Value:
+
+ The router table entry, or NULL if none exists for this network.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PROUTER_SEGMENT RouterSegment;
+ PIPX_ROUTE_ENTRY RouteEntry;
+
+ RouterSegment = &IpxDevice->Segments[Segment];
+
+ for (p = RouterSegment->Entries.Flink;
+ p != &RouterSegment->Entries;
+ p = p->Flink) {
+
+ RouteEntry = CONTAINING_RECORD(
+ p,
+ IPX_ROUTE_ENTRY,
+ PRIVATE.Linkage);
+
+ if ((*(UNALIGNED LONG *)RouteEntry->Network) ==
+ (*(UNALIGNED LONG *)Network)) {
+ return RouteEntry;
+ }
+ }
+
+ return NULL;
+
+} /* RipGetRoute */
+
+
+BOOLEAN
+RipAddRoute(
+ IN UINT Segment,
+ IN PIPX_ROUTE_ENTRY RouteEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stores a router table entry in the
+ table, which must belong in the specified segment.
+ THE SEGMENT LOCK MUST BE HELD. Storage for the entry
+ is allocated and filled in by the caller.
+
+Arguments:
+
+ Segment - The segment corresponding to the network.
+
+ RouteEntry - The router table entry.
+
+Return Value:
+
+ TRUE if the entry was successfully inserted.
+
+--*/
+
+{
+
+ IPX_DEBUG (RIP, ("Adding route for network %lx (%d)\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)RouteEntry->Network), Segment));
+ InsertTailList(
+ &IpxDevice->Segments[Segment].Entries,
+ &RouteEntry->PRIVATE.Linkage);
+
+ return TRUE;
+
+} /* RipAddRoute */
+
+
+BOOLEAN
+RipDeleteRoute(
+ IN UINT Segment,
+ IN PIPX_ROUTE_ENTRY RouteEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deletes a router table entry in the
+ table, which must belong in the specified segment.
+ THE SEGMENT LOCK MUST BE HELD. Storage for the entry
+ is freed by the caller.
+
+Arguments:
+
+ Segment - The segment corresponding to the network.
+
+ RouteEntry - The router table entry.
+
+Return Value:
+
+ TRUE if the entry was successfully deleted.
+
+--*/
+
+{
+
+ PROUTER_SEGMENT RouterSegment = &IpxDevice->Segments[Segment];
+
+ IPX_DEBUG (RIP, ("Deleting route for network %lx (%d)\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)RouteEntry->Network), Segment));
+
+ //
+ // If the current enumeration point for this segment is here,
+ // adjust the pointer before deleting the entry. We make it
+ // point to the previous entry so GetNextRoute will work.
+ //
+
+ if (RouterSegment->EnumerateLocation == &RouteEntry->PRIVATE.Linkage) {
+ RouterSegment->EnumerateLocation = RouterSegment->EnumerateLocation->Blink;
+ }
+
+ RemoveEntryList (&RouteEntry->PRIVATE.Linkage);
+
+ return TRUE;
+
+} /* RipDeleteRoute */
+
+
+PIPX_ROUTE_ENTRY
+RipGetFirstRoute(
+ IN UINT Segment
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the first router table entry in the
+ segment. THE SEGMENT LOCK MUST BE HELD. It is used in
+ conjunction with RipGetNextRoute to enumerate all the
+ entries in a segment.
+
+Arguments:
+
+ Segment - The segment being enumerated.
+
+Return Value:
+
+ The first router table entry, or NULL if the segment is empty.
+
+--*/
+
+{
+ PIPX_ROUTE_ENTRY FirstEntry;
+ PROUTER_SEGMENT RouterSegment = &IpxDevice->Segments[Segment];
+
+ RouterSegment->EnumerateLocation = RouterSegment->Entries.Flink;
+
+ if (RouterSegment->EnumerateLocation == &RouterSegment->Entries) {
+
+ return NULL;
+
+ } else {
+
+ FirstEntry = CONTAINING_RECORD(
+ RouterSegment->EnumerateLocation,
+ IPX_ROUTE_ENTRY,
+ PRIVATE.Linkage);
+
+ return FirstEntry;
+
+ }
+
+} /* RipGetFirstRoute */
+
+
+PIPX_ROUTE_ENTRY
+RipGetNextRoute(
+ IN UINT Segment
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the next router table entry in the
+ segment. THE SEGMENT LOCK MUST BE HELD. It is used in
+ conjunction with RipGetFirstRoute to enumerate all the
+ entries in a segment.
+
+ It is illegal to call RipGetNextRoute on a segment
+ without first calling RipGetFirstRoute. The segment
+ lock must be held for the duration of the enumeration
+ of a single segment. It is legal to stop enumerating
+ the segment in the middle.
+
+Arguments:
+
+ Segment - The segment being enumerated.
+
+Return Value:
+
+ The next router table entry, or NULL if the end of the
+ segment is reached.
+
+--*/
+
+{
+ PIPX_ROUTE_ENTRY NextEntry;
+ PROUTER_SEGMENT RouterSegment = &IpxDevice->Segments[Segment];
+
+ RouterSegment->EnumerateLocation = RouterSegment->EnumerateLocation->Flink;
+
+ if (RouterSegment->EnumerateLocation == &RouterSegment->Entries) {
+
+ return NULL;
+
+ } else {
+
+ NextEntry = CONTAINING_RECORD(
+ RouterSegment->EnumerateLocation,
+ IPX_ROUTE_ENTRY,
+ PRIVATE.Linkage);
+
+ return NextEntry;
+
+ }
+
+} /* RipGetNextRoute */
+
+
+VOID
+RipDropRemoteEntries(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deletes all non-local entries from the
+ RIP database. It is called when the WAN line goes up
+ or down and we want to remove all existing entries.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ UINT Segment;
+ CTELockHandle LockHandle;
+
+ for (Segment = 0; Segment < Device->SegmentCount; Segment++) {
+
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Scan through, deleting everything but local entries.
+ //
+
+ for (RouteEntry = RipGetFirstRoute (Segment);
+ RouteEntry != (PIPX_ROUTE_ENTRY)NULL;
+ RouteEntry = RipGetNextRoute (Segment)) {
+
+ if ((RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY) == 0) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Deleting route entry %lx, dropping remote entries\n", RouteEntry));
+ RipDeleteRoute (Segment, RouteEntry);
+
+ }
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+
+ }
+
+} /* RipDropRemoteEntries */
+
diff --git a/private/ntos/tdi/isn/ipx/rt.c b/private/ntos/tdi/isn/ipx/rt.c
new file mode 100644
index 000000000..8881f03fa
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/rt.c
@@ -0,0 +1,1311 @@
+/*++
+
+Copyright (c) 1989-1994 Microsoft Corporation
+
+Module Name;
+
+ Rt.c
+
+Abstract;
+
+
+Author;
+
+
+Revision History;
+
+TODO: Get rid of ref/Deref since the RTINFO structure will not be destroyed
+ Use a common alloc/free function (with the rest of ipx)
+ Allocate tagged memory
+ Optimize code more
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// function prototypes
+//
+
+VOID
+RtIrpCancel(
+ IN PDEVICE_OBJECT Device,
+ IN PIRP pIrp
+ );
+
+
+PVOID
+RtAllocMem(
+ IN ULONG Size
+ );
+
+VOID
+RtFreeMem(
+ IN PVOID pBuffer,
+ IN ULONG Size
+ );
+
+NTSTATUS
+NTCheckSetCancelRoutine(
+ IN PIRP pIrp,
+ IN PVOID CancelRoutine,
+ IN PDEVICE pDevice
+ );
+VOID
+NTIoComplete(
+ IN PIRP pIrp,
+ IN NTSTATUS Status,
+ IN ULONG SentLength);
+
+NTSTATUS
+CleanupRtAddress(
+ IN PDEVICE pDevice,
+ IN PIRP pIrp);
+
+NTSTATUS
+CloseRtAddress(
+ IN PDEVICE pDevice,
+ IN PIRP pIrp);
+
+NTSTATUS
+SendIrpFromRt (
+ IN PDEVICE pDevice,
+ IN PIRP pIrp
+ );
+
+NTSTATUS
+RcvIrpFromRt (
+ IN PDEVICE pDevice,
+ IN PIRP pIrp
+ );
+NTSTATUS
+PassDgToRt (
+ IN PDEVICE pDevice,
+ IN PIPX_DATAGRAM_OPTIONS2 pContext,
+ IN ULONG Index,
+ IN VOID UNALIGNED *pDgrm,
+ IN ULONG uNumBytes
+ );
+
+VOID
+IpxDerefRt(
+ PRT_INFO pRt
+ );
+
+VOID
+IpxRefRt(
+ PRT_INFO pRt
+ );
+
+VOID
+IpxDestroyRt(
+ IN PRT_INFO pRt
+ );
+
+#define ALLOC_PRAGMA 1
+#define CTEMakePageable(x, y) alloc_text(x,y)
+
+#define AllocMem(_BytesToAlloc) IpxAllocateMemory(_BytesToAlloc, MEMORY_PACKET, "RT MEMORY")
+
+#define FreeMem(_Memory, _BytesAllocated) IpxFreeMemory(_Memory, _BytesAllocated, MEMORY_PACKET, "RT MEMORY")
+
+
+#define IpxVerifyRt(pRt) // \
+ // if ((pRt->Type != IPX_RT_SIGNATURE) || (pRt->Size != sizeof(RT_INFO))) { return STATUS_INVALID_ADDRESS; }
+
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(PAGERT, CloseRtAddress)
+#pragma CTEMakePageable(PAGERT, CleanupRtAddress)
+#pragma CTEMakePageable(PAGERT, RcvIrpFromRt)
+#pragma CTEMakePageable(PAGERT, SendIrpFromRt)
+#pragma CTEMakePageable(PAGERT, PassDgToRt)
+#pragma CTEMakePageable(PAGERT, RtIrpCancel)
+#pragma CTEMakePageable(PAGERT, NTCheckSetCancelRoutine)
+#pragma CTEMakePageable(PAGERT, NTIoComplete)
+#pragma CTEMakePageable(PAGERT, RtFreeMem)
+#pragma CTEMakePageable(PAGERT, RtAllocMem)
+#pragma CTEMakePageable(PAGERT, IpxRefRt)
+#pragma CTEMakePageable(PAGERT, IpxDerefRt)
+#pragma CTEMakePageable(PAGERT, IpxDestroyRt)
+#endif
+//******************* Pageable Routine Declarations ****************
+
+
+HANDLE IpxRtDiscardableCodeHandle={0};
+
+PRT_INFO pRtInfo; //contains info about all rt opened end points
+
+
+NTSTATUS
+OpenRtAddress(
+ IN PDEVICE pDevice,
+ IN PREQUEST pIrp
+ )
+{
+ PRT_INFO pRt;
+ CTELockHandle OldIrq;
+ NTSTATUS status;
+ ULONG SaveReqCode;
+
+
+ IpxPrint0("OpenRtAddress - entered\n");
+
+ //
+ // if the RTINFO endpoint structure is not allocated, then allocate it
+ // and initialize it. But first get the device lock. This gurantees that
+ // we can not have two irps doing the creation at the same time
+ //
+ CTEGetLock(&pDevice->Lock, &OldIrq);
+ if (!pRtInfo)
+ {
+
+ pRt = AllocMem(sizeof(RT_INFO));
+
+ //
+ // Do this after locking the pagable rtns.
+ //
+ // pRtInfo = pRt; //store it in pRtInfo. When irps come down from RM,
+ // we can compare pRt passed in them with pRtInfo
+ if (pRt)
+ {
+ RtlZeroMemory(pRt,sizeof(RT_INFO));
+ IpxPrint1("OpenRtAddress: Initializing CompletedIrps for pRt=(%lx)\n", pRt);
+ pRt->RcvMemoryMax = RT_MAX_BUFF_MEM; // max. memory we can allocate
+ pRt->Type = IPX_RT_SIGNATURE;
+ pRt->Size = sizeof(RT_INFO);
+ pRt->pDevice = pDevice;
+ IpxPrint1("OpenRtAddress: pRtInfo=(%lx)\n", pRt);
+ IpxPrint1("Completed Irp list is (%lx)\n", IsListEmpty(&pRt->CompletedIrps));
+
+#if DBG
+ RtlCopyMemory(pRt->Signature, "RTIF", sizeof("RTIF") - 1);
+#endif
+ InitializeListHead(&pRt->CompletedIrps);
+ InitializeListHead(&pRt->HolderIrpsList);
+ }
+ CTEFreeLock(&pDevice->Lock, OldIrq);
+ }
+ else
+ {
+ pRt = pRtInfo;
+ CTEFreeLock(&pDevice->Lock, OldIrq);
+ IpxPrint1("OpenRtAddress: RTINFO found = (%lx)\n", pRtInfo);
+ }
+
+ if (pRt)
+ {
+
+ // Page in the Rt Code, if it hasn't already been paged in.
+ //
+ if (!IpxRtDiscardableCodeHandle)
+ {
+ IpxRtDiscardableCodeHandle = MmLockPagableCodeSection( CloseRtAddress );
+
+ pRtInfo = pRt; //store it in pRtInfo. When irps come down from RM,
+ // we can compare pRt passed in them with pRtInfo
+ }
+
+ //
+ // it could fail to lock the pages so check for that
+ //
+ if (IpxRtDiscardableCodeHandle)
+ {
+
+ ULONG i;
+ status = STATUS_SUCCESS;
+
+ IpxReferenceRt(pRtInfo, RT_CREATE);
+
+ //
+ // Find an empty slot and mark it open
+ //
+ CTEGetLock(&pRt->Lock, &OldIrq);
+ for (i=0; i<IPX_RT_MAX_ADDRESSES; i++)
+ {
+ if (pRt->AddFl[i].State == RT_EMPTY)
+ {
+ break;
+ }
+ }
+ if (i < IPX_RT_MAX_ADDRESSES)
+ {
+ pRt->AddFl[i].State = RT_OPEN;
+ pRt->NoOfAdds++;
+ InitializeListHead(&pRt->AddFl[i].RcvList);
+ InitializeListHead(&pRt->AddFl[i].RcvIrpList);
+ }
+ else
+ {
+ CTEFreeLock(&pRt->Lock, OldIrq);
+ IpxPrint1("OpenRtAddress; All %d slots used up\n", IPX_RT_MAX_ADDRESSES);
+ IpxDereferenceRt(pRtInfo, RT_CREATE);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto RET;
+ }
+ CTEFreeLock(&pRt->Lock, OldIrq);
+
+ //
+ // Found an empty slot. Initialize all relevant info. and then
+ // open an address object.
+ //
+ SaveReqCode = REQUEST_CODE(pIrp);
+ REQUEST_CODE(pIrp) = MIPX_RT_CREATE;
+ status = IpxOpenAddressM(pDevice, pIrp, i);
+ REQUEST_CODE(pIrp) = SaveReqCode;
+
+ IpxPrint1("After IpxOpenAddressM: Completed Irp list is (%lx)\n", IsListEmpty(&pRtInfo->CompletedIrps));
+ if (status != STATUS_SUCCESS)
+ {
+ IpxPrint0("OpenRtAddress; Access Denied due to OpenAddress\n");
+ IpxDereferenceRt(pRtInfo, RT_CREATE);
+ CTEGetLock(&pRt->Lock, &OldIrq);
+ pRt->AddFl[i].State = RT_EMPTY;
+ pRt->NoOfAdds--;
+ CTEFreeLock(&pRt->Lock, OldIrq);
+ }
+ else
+ {
+ CTEGetLock(&pRt->Lock, &OldIrq);
+ pRt->AddFl[i].AddressFile = REQUEST_OPEN_CONTEXT(pIrp);
+ CTEFreeLock(&pRt->Lock, OldIrq);
+
+ //
+ // No need to put pRt since it is global. We stick with the addressfile here.
+ //
+
+ // REQUEST_OPEN_CONTEXT(pIrp) = (PVOID)pRt;
+ REQUEST_OPEN_TYPE(pIrp) = (PVOID)(ROUTER_ADDRESS_FILE + i);
+ IpxPrint1("OpenRtAdd: Index = (%d)\n", RT_ADDRESS_INDEX(pIrp));
+ }
+ }
+ else
+ {
+ IpxPrint1("OpenRtAddress; All %d slots used up\n", IPX_RT_MAX_ADDRESSES);
+
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ else
+ {
+ IpxPrint0("OpenRtCreate; Couldn't allocate a RT_INFO structure\n");
+ CTEAssert(FALSE); //should never happen unless system is running
+ //out of non-paged pool
+ status = STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+RET:
+ IpxPrint1("OpenRtAddress status prior to return= %X\n",status);
+ return(status);
+}
+
+
+NTSTATUS
+CleanupRtAddress(
+ IN PDEVICE pDevice,
+ IN PIRP pIrp)
+
+/*++
+Routine Description;
+
+ This Routine handles closing the Rt Object that is used by
+ by RT to send and receive name service datagrams on port 137.
+
+
+Arguments;
+
+ pIrp - a ptr to an IRP
+
+Return Value;
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status;
+ PRT_INFO pRt;
+ CTELockHandle OldIrq;
+ PLIST_ENTRY pHead;
+ ULONG Index;
+ PLIST_ENTRY pLE;
+ PIRP pTmpIrp;
+
+
+
+ IpxPrint0("CleanupRtAddress - entered\n");
+
+ //
+ // if the endpoint structure is allocated, then deallocate it
+ //
+ // pRt = REQUEST_OPEN_CONTEXT(pIrp);
+ pRt = pRtInfo;
+
+ Index = RT_ADDRESS_INDEX(pIrp);
+ IpxPrint1("CleanupRtAdd: Index = (%d)\n", Index);
+
+ IpxVerifyRt(pRt);
+ CTEAssert(pRt && (pRt == pRtInfo));
+ CTEAssert(Index < IPX_RT_MAX_ADDRESSES);
+
+ do
+ {
+ PLIST_ENTRY pRcvEntry;
+ PRTRCV_BUFFER pRcv;
+ PRT_IRP pRtAddFl = &pRt->AddFl[Index];
+
+ CTEAssert(pRtAddFl->State == RT_OPEN);
+ IpxPrint1("CleanupRtAddress: Got AF handle = (%lx)\n", pRtAddFl);
+ IpxReferenceRt(pRt, RT_CLEANUP);
+ status = STATUS_SUCCESS;
+
+ CTEGetLock (&pRt->Lock, &OldIrq);
+
+ //
+ // prevent any more dgram getting queued up
+ //
+ pRtAddFl->State = RT_CLOSING;
+ CTEFreeLock (&pRt->Lock, OldIrq);
+
+ //
+ // free any rcv buffers that may be queued up
+ //
+ pHead = &pRtAddFl->RcvList;
+ while (pRcvEntry = ExInterlockedRemoveHeadList(pHead, &pRt->Lock))
+ {
+ pRcv = CONTAINING_RECORD(pRcvEntry,RTRCV_BUFFER,Linkage);
+
+ CTEAssert(pRcv);
+ IpxPrint1("CleanupRtAddress:Freeing buffer = (%lx)\n", pRcv);
+ RtFreeMem(pRcv,pRcv->TotalAllocSize);
+ }
+
+ //
+ // Complete all irps that are queued
+ //
+ while (pLE = ExInterlockedRemoveHeadList(&pRtAddFl->RcvIrpList, &pRt->Lock)) {
+
+ //
+ // The recv irp is here so copy the data to its buffer and
+ // pass it up to RT
+ //
+ pTmpIrp = CONTAINING_RECORD(pLE, IRP, Tail.Overlay.ListEntry);
+ IpxPrint1("CleanupRtAddress: Completing Rt rcv Irp from AdFl queue pIrp=%X\n" ,pTmpIrp);
+ pTmpIrp->IoStatus.Information = 0;
+ pTmpIrp->IoStatus.Status = STATUS_CANCELLED;
+
+ NTIoComplete(pTmpIrp, (NTSTATUS)-1, (ULONG)-1);
+
+ } //end of while
+
+ //
+ // dequeue and complete any irps on the complete queue.
+ //
+
+ while (pLE = ExInterlockedRemoveHeadList(&pRt->CompletedIrps, &pRt->Lock))
+ {
+ pTmpIrp = CONTAINING_RECORD(pLE, IRP, Tail.Overlay.ListEntry);
+ if (RT_ADDRESS_INDEX(pTmpIrp) == Index)
+ {
+ IpxPrint1("CleanupRtAddress:Completing Rt rcv Irp from CompleteIrps queue pIrp=%X\n" ,pTmpIrp);
+
+ pTmpIrp->IoStatus.Information = 0;
+ pTmpIrp->IoStatus.Status = STATUS_CANCELLED;
+ NTIoComplete(pTmpIrp, (NTSTATUS)-1, (ULONG)-1);
+ }
+ else
+ {
+ ExInterlockedInsertHeadList(&pRt->HolderIrpsList, pLE, &pRt->Lock);
+ }
+ }
+ CTEGetLock(&pRt->Lock, &OldIrq);
+ while(!IsListEmpty(&pRt->HolderIrpsList))
+ {
+ pLE = RemoveHeadList(&pRt->HolderIrpsList);
+ InsertHeadList(&pRt->CompletedIrps, pLE);
+ }
+ CTEFreeLock(&pRt->Lock, OldIrq);
+
+ //
+ // Store AF pointer in Irp since we will now be freeing the address file
+ // (in driver.c).
+ //
+
+ //
+ // We always have addressfile in the Irp
+ //
+
+ // REQUEST_OPEN_CONTEXT(pIrp) = (PVOID)(pRtAddFl->AddressFile);
+
+ IpxDereferenceRt(pRt, RT_CLEANUP);
+ } while (FALSE);
+
+ IpxPrint0("CleanupRtAddress: Return\n");
+ return(status);
+}
+
+NTSTATUS
+CloseRtAddress(
+ IN PDEVICE pDevice,
+ IN PIRP pIrp)
+{
+
+ NTSTATUS status;
+ PRT_INFO pRt;
+ CTELockHandle OldIrq;
+ PLIST_ENTRY pHead;
+ ULONG Index;
+
+ IpxPrint0("CloseRtAddress - entered\n");
+
+ // pRt = REQUEST_OPEN_CONTEXT(pIrp);
+ pRt = pRtInfo;
+
+ Index = RT_ADDRESS_INDEX(pIrp);
+ IpxPrint1("CloseRtAdd: Index = (%d)\n", Index);
+
+ IpxVerifyRt(pRt);
+ CTEAssert(pRt && (pRt == pRtInfo));
+ CTEAssert(Index < IPX_RT_MAX_ADDRESSES);
+ CTEAssert(pRt->AddFl[Index].State == RT_CLOSING);
+
+ // REQUEST_OPEN_CONTEXT(pIrp) = (PVOID)(pRt->AddFl[Index].AddressFile);
+ //REQUEST_OPEN_TYPE(pIrp) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ CTEGetLock(&pRt->Lock, &OldIrq);
+ pRt->AddFl[Index].State = RT_EMPTY;
+ pRt->NoOfAdds--;
+ CTEFreeLock(&pRt->Lock, OldIrq);
+
+ //
+ // THis is a counter to the RT_CREATE
+ //
+ IpxDereferenceRt(pRt, RT_CLOSE);
+
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+SendIrpFromRt (
+ IN PDEVICE pDevice,
+ IN PIRP pIrp
+ )
+{
+ CTELockHandle OldIrq;
+ NTSTATUS Status;
+ ULONG Index;
+ PRT_INFO pRt;
+
+ IpxPrint0("SendIrpfromRt - entered\n");
+ // pRt = REQUEST_OPEN_CONTEXT(pIrp);
+ pRt = pRtInfo;
+
+ Index = RT_ADDRESS_INDEX(pIrp);
+ IpxVerifyRt(pRt);
+ CTEAssert(pRt && (pRt == pRtInfo));
+ do {
+ //
+ // Check if the add. file slot indicates that it is OPEN. If it is
+ // not open, then we should return STATUS_INVALID_HANDLE. The
+ // reason why it may not be open is if we got a cleanup/close before
+ // this irp.
+ //
+ CTEGetLock(&pRt->Lock, &OldIrq);
+ if (pRt->AddFl[Index].State != RT_OPEN)
+ {
+
+ //
+ // free the lock, set the status and break out
+ //
+ CTEFreeLock (&pRt->Lock, OldIrq);
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+ //
+ // Let us reference the RtInfo structure so that it does not dissapear
+ // and also for some accounting
+ //
+ IpxReferenceRt(pRt, RT_SEND);
+
+
+ IpxPrint1("SendIrpFromRt: Index = (%d)\n", Index);
+
+ //
+ // Store the AF pointer since IpxTdiSendDatagram will use it. Free
+ // the device lock since we have nothing more to do with our structures
+ // here.
+ //
+ // REQUEST_OPEN_CONTEXT(pIrp) = (PVOID)(pRtInfo->AddFl[Index].AddressFile);
+ CTEFreeLock (&pRt->Lock, OldIrq);
+
+ Status = IpxTdiSendDatagram(pDevice->DeviceObject, pIrp);
+
+ //
+ // All done with this send. Derefernce the RtInfo structure.
+ //
+ IpxDereferenceRt(pRtInfo, RT_SEND);
+ } while(FALSE);
+
+ IpxPrint0("SendIrpfromRt - leaving\n");
+ return(Status);
+}
+
+ NTSTATUS
+RcvIrpFromRt (
+ IN PDEVICE pDevice,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description;
+
+ This function takes the rcv irp posted by RT and decides if there are
+ any datagram queued waiting to go up to RT. If so then the datagram
+ is copied to the RT buffer and passed back up. Otherwise the irp is
+ held by Netbt until a datagram does come in.
+
+Arguments;
+
+ pDevice - not used
+ pIrp - Rt Rcv Irp
+
+Return Value;
+
+ STATUS_PENDING if the buffer is to be held on to , the normal case.
+
+Notes;
+
+
+--*/
+
+{
+ NTSTATUS status;
+ PRTRCV_BUFFER pBuffer;
+ PLIST_ENTRY pEntry;
+ CTELockHandle OldIrq;
+ PRT_INFO pRt;
+ PIPX_DATAGRAM_OPTIONS2 pRtBuffer;
+ PRT_IRP pRtAF;
+ ULONG Index;
+#if DBG
+ ULONG NoOfRcvIrp;
+#endif
+
+ IpxPrint0("RcvIrpfromRt - Entered\n");
+
+ // pRt = REQUEST_OPEN_CONTEXT(pIrp);
+ pRt = pRtInfo;
+
+ Index = RT_ADDRESS_INDEX(pIrp);
+
+ IpxPrint1("RcvIrpFromRt: Index = (%d)\n", Index);
+
+ IpxVerifyRt(pRt);
+ CTEAssert(pRt && (pRt == pRtInfo));
+ CTEAssert(Index < IPX_RT_MAX_ADDRESSES);
+
+ CTEGetLock (&pRt->Lock, &OldIrq);
+ do
+ {
+ pRtAF = &pRt->AddFl[Index];
+ if (pRtAF->State != RT_OPEN)
+ {
+ status = STATUS_INVALID_HANDLE;
+ CTEFreeLock (&pRt->Lock, OldIrq);
+ break;
+ }
+ IpxReferenceRt(pRt, RT_IRPIN);
+
+ if (!IsListEmpty(&pRtAF->RcvList))
+ {
+ PMDL pMdl;
+ ULONG CopyLength;
+ ULONG UserBufferLengthToPass;
+ ULONG MdlLength;
+
+ //
+ // There is at least one datagram waiting to be received
+ //
+ pEntry = RemoveHeadList(&pRtAF->RcvList);
+
+ pBuffer = (PRTRCV_BUFFER)CONTAINING_RECORD(pEntry,RTRCV_BUFFER,
+ Linkage);
+
+ IpxPrint0("RcvIrpFromRt: Buffer dequeued\n");
+ //
+ // Copy the datagram and the source address to RT buffer and
+ // return to RT
+ //
+ pMdl = pIrp->MdlAddress;
+ IpxPrint2("RcvIrpFromRt: Irp=(%lx); Mdl=(%lx)\n", pIrp, pMdl);
+ CTEAssert(pMdl);
+ if (!pMdl)
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ CTEFreeLock (&pRt->Lock, OldIrq);
+ IpxDereferenceRt(pRtInfo, RT_IRPIN);
+ break;
+
+ }
+ pRtBuffer = MmGetSystemAddressForMdl(pMdl);
+ MdlLength = MmGetMdlByteCount(pMdl);
+
+ UserBufferLengthToPass = pBuffer->UserBufferLengthToPass;
+
+ CopyLength = (UserBufferLengthToPass <= MdlLength) ? UserBufferLengthToPass : MdlLength;
+ IpxPrint0("RcvIrpFromRt: Copying Options\n");
+ RtlCopyMemory((PVOID)pRtBuffer,
+ (PVOID)&pBuffer->Options,
+ CopyLength);
+
+ //
+ // subtract from the total amount buffered for RT since we are
+ // passing a datagram up to RT now.
+ //
+ pRtInfo->RcvMemoryAllocated -= pBuffer->TotalAllocSize;
+ RtFreeMem(pBuffer, pBuffer->TotalAllocSize);
+
+ CTEAssert(pRtBuffer->DgrmOptions.LocalTarget.NicId);
+
+ //
+ // pass the irp up to RT
+ //
+ if (CopyLength < UserBufferLengthToPass)
+ {
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+ else
+ {
+ status = STATUS_SUCCESS;
+ }
+#if DBG
+ NoOfRcvIrp = pRtAF->NoOfRcvIrps;
+#endif
+
+ CTEFreeLock (&pRt->Lock, OldIrq);
+
+
+ IpxPrint3("Returning Rt rcv Irp immediately with queued dgram, status=%X,pIrp=%X. NoOfRcvIrp=(%d)\n" ,status,pIrp, NoOfRcvIrp);
+
+ pIrp->IoStatus.Information = CopyLength;
+ pIrp->IoStatus.Status = status;
+ }
+ else
+ {
+
+ status = NTCheckSetCancelRoutine(pIrp,RtIrpCancel,pDevice);
+
+ if (!NT_SUCCESS(status))
+ {
+ CTEFreeLock (&pRt->Lock, OldIrq);
+ }
+ else
+ {
+ if (pRtAF->NoOfRcvIrps++ > RT_IRP_MAX)
+ {
+ IpxPrint1("RcvIrpFromRt; REACHED LIMIT OF IRPS. NoOfRcvIrp=(%d)\n", pRtAF->NoOfRcvIrps);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ pRtAF->NoOfRcvIrps--;
+ CTEFreeLock (&pRt->Lock, OldIrq);
+
+ }
+ else
+ {
+ InsertTailList(&pRtAF->RcvIrpList,REQUEST_LINKAGE(pIrp));
+ IpxPrint2("IpxRt;Holding onto Rt Rcv Irp, pIrp =%Xstatus=%X\n", status,pIrp);
+
+ status = STATUS_PENDING;
+ CTEFreeLock(&pRt->Lock,OldIrq);
+ }
+ }
+
+
+ }
+ IpxDereferenceRt(pRtInfo, RT_IRPIN);
+ } while(FALSE);
+
+ IpxPrint0("RcvIrpfromRt - Leaving\n");
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+PassDgToRt (
+ IN PDEVICE pDevice,
+ IN PIPX_DATAGRAM_OPTIONS2 pContext,
+ IN ULONG Index,
+ IN VOID UNALIGNED *pDgrm,
+ IN ULONG uNumBytes
+ )
+/*++
+
+Routine Description;
+
+ This function is used to allow NBT to pass name query service Pdu's to
+ RT. Rt posts a Rcv irp to Netbt. If the Irp is here then simply
+ copy the data to the irp and return it, otherwise buffer the data up
+ to a maximum # of bytes. Beyond that limit the datagrams are discarded.
+
+ If Retstatus is not success then the pdu will also be processed by
+ nbt. This allows nbt to process packets when wins pauses and
+ its list of queued buffers is exceeded.
+
+Arguments;
+
+ pDevice - card that the request can in on
+ pSrcAddress - source address
+ pDgrm - ptr to the datagram
+ uNumBytes - length of datagram
+
+Return Value;
+
+ STATUS_PENDING if the buffer is to be held on to , the normal case.
+
+Notes;
+
+
+--*/
+
+{
+ NTSTATUS status;
+ PIPX_DATAGRAM_OPTIONS2 pRtBuffer;
+ PIRP pIrp;
+ CTELockHandle OldIrq;
+
+
+ IpxPrint0("PassDgToRt - Entered\n");
+
+ //
+ // Get the source port and ip address, since RT needs this information.
+ //
+ IpxPrint1("PassDgToRt: Index = (%d)\n", Index);
+ CTEGetLock(&pRtInfo->Lock,&OldIrq);
+
+ do
+ {
+ PRT_IRP pRtAF = &pRtInfo->AddFl[Index];
+ if (pRtAF->State != RT_OPEN)
+ {
+ CTEFreeLock(&pRtInfo->Lock,OldIrq);
+ break;
+ }
+ IpxReferenceRt(pRtInfo, RT_BUFF);
+ if (IsListEmpty(&pRtAF->RcvIrpList))
+ {
+ IpxPrint0("PassDgToRt: No Rcv Irp\n");
+ if (pRtInfo->RcvMemoryAllocated < pRtInfo->RcvMemoryMax)
+ {
+ PRTRCV_BUFFER pBuffer;
+
+ pBuffer = RtAllocMem(uNumBytes + sizeof(RTRCV_BUFFER));
+ if (pBuffer)
+ {
+ pBuffer->TotalAllocSize = uNumBytes + sizeof(RTRCV_BUFFER);
+
+ //
+ // Copy the user data
+ //
+ RtlCopyMemory(
+ (PUCHAR)((PUCHAR)pBuffer + OFFSET_PKT_IN_RCVBUFF),
+ (PVOID)pDgrm,uNumBytes);
+
+
+ pBuffer->Options.DgrmOptions.LocalTarget.NicId =
+ pContext->DgrmOptions.LocalTarget.NicId;
+ pBuffer->Options.LengthOfExtraOpInfo = 0;
+
+ //
+ // total amount allocated for user
+ //
+ pBuffer->UserBufferLengthToPass = uNumBytes + OFFSET_PKT_IN_OPTIONS;
+
+ CTEAssert(pContext->DgrmOptions.LocalTarget.NicId);
+ IpxPrint2("PassDgToRt: Nic Id is (%d). BufferLength is (%lx)\n", pContext->DgrmOptions.LocalTarget.NicId, uNumBytes);
+
+
+
+ //
+ // Keep track of the total amount buffered so that we don't
+ // eat up all non-paged pool buffering for RT
+ //
+ pRtInfo->RcvMemoryAllocated += pBuffer->TotalAllocSize;
+
+ IpxPrint0("IpxRt;Buffering Rt Rcv - no Irp, status=%X\n");
+ InsertTailList(&pRtAF->RcvList,&pBuffer->Linkage);
+ IpxPrint0("PassDgToRt: Buffer Queued\n");
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+ IpxPrint0("PassDgToRt; Could not allocate buffer\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ else
+ {
+ // this ret status will allow netbt to process the packet.
+ //
+ IpxPrint0("PassDgToRt; Dropping Pkt\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ CTEFreeLock(&pRtInfo->Lock,OldIrq);
+ }
+ else
+ {
+ PMDL pMdl;
+ ULONG CopyLength;
+ ULONG DgrmLength;
+ ULONG MdlBufferLength;
+ ULONG BytesToCopy;
+ PLIST_ENTRY pLE;
+
+ //
+ // The recv irp is here so copy the data to its buffer and
+ // pass it up to RT
+ //
+ pLE = RemoveHeadList(&pRtAF->RcvIrpList);
+ pIrp = CONTAINING_RECORD(pLE, IRP, Tail.Overlay.ListEntry);
+
+ (*(REQUEST_LINKAGE(pIrp))).Flink = NULL;
+ (*(REQUEST_LINKAGE(pIrp))).Blink = NULL;
+
+ //
+ // Copy the datagram and the source address to RT buffer and
+ // return to RT
+ //
+ pMdl = pIrp->MdlAddress;
+ IpxPrint2("PassDgToRt: Irp=(%lx); Mdl=(%lx)\n", pIrp, pMdl);
+ CTEAssert(pMdl);
+
+ pRtBuffer = MmGetSystemAddressForMdl(pIrp->MdlAddress);
+
+ MdlBufferLength = MmGetMdlByteCount(pMdl);
+ DgrmLength = uNumBytes;
+ BytesToCopy = DgrmLength + OFFSET_PKT_IN_OPTIONS;
+
+ CopyLength = (BytesToCopy <= MdlBufferLength) ? BytesToCopy : MdlBufferLength;
+ IpxPrint2("PassDgToRt: Copy Length = (%d); Mdl Buffer Length is (%d)\n", CopyLength, MdlBufferLength);
+
+ //
+ // Copy user datagram into pRtBuffer
+ //
+ RtlCopyMemory((PVOID)((PUCHAR)pRtBuffer + OFFSET_PKT_IN_OPTIONS),
+ (PVOID)pDgrm,
+ CopyLength-OFFSET_PKT_IN_OPTIONS);
+
+ IpxPrint1("Data copied is (%.12s)\n", (PUCHAR)((PUCHAR)pRtBuffer + OFFSET_PKT_IN_OPTIONS + sizeof(IPX_HEADER)));
+
+ pRtBuffer->DgrmOptions.LocalTarget.NicId = pContext->DgrmOptions.LocalTarget.NicId;
+ pRtBuffer->LengthOfExtraOpInfo = 0;
+
+ IpxPrint3("PassDgToRt: Copy to RcvIrp;Nic Id is (%d/%d). BufferLength is (%lx)\n", pContext->DgrmOptions.LocalTarget.NicId, pRtBuffer->DgrmOptions.LocalTarget.NicId, uNumBytes);
+
+
+ CTEAssert(pContext->DgrmOptions.LocalTarget.NicId);
+
+ //
+ // pass the irp up to RT
+ //
+ if (CopyLength < BytesToCopy)
+ {
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+ else
+ {
+ status = STATUS_SUCCESS;
+ }
+
+ InsertTailList(&pRtInfo->CompletedIrps, REQUEST_LINKAGE(pIrp));
+ pRtAF->NoOfRcvIrps--;
+ IpxPrint4("PassDgToRt;Returning Rt Rcv Irp - data from net, Length=%X,pIrp=%X; status = (%d). NoOfRcvIrp = (%d)\n" ,uNumBytes,pIrp, status, pRtAF->NoOfRcvIrps);
+
+ pIrp->IoStatus.Status = status;
+ pIrp->IoStatus.Information = CopyLength;
+ CTEFreeLock(&pRtInfo->Lock,OldIrq);
+
+ }
+ IpxDereferenceRt(pRtInfo, RT_BUFF);
+ } while (FALSE);
+
+
+ IpxPrint0("PassDgToRt - Entered\n");
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+RtIrpCancel(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description;
+
+ This routine handles the cancelling a RtRcv Irp. It must release the
+ cancel spin lock before returning re; IoCancelIrp().
+
+Arguments;
+
+
+Return Value;
+
+ The final status from the operation.
+
+--*/
+{
+ KIRQL OldIrq;
+ PRT_INFO pRt;
+ PDEVICE pDevice = IpxDevice;
+ ULONG Index;
+ PIRP pTmpIrp;
+
+ IpxPrint0("RtIrpCancel;Got a Rt Irp Cancel !!! *****************\n");
+
+ Index = RT_ADDRESS_INDEX(pIrp);
+ IpxPrint1("RtIrpCancel: Index = (%d)\n", Index);
+ // pRt = (PRT_INFO)REQUEST_OPEN_CONTEXT(pIrp);
+ pRt = pRtInfo;
+
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+ if ((pRt->Type != IPX_RT_SIGNATURE) || (pRt->Size != sizeof(RT_INFO))) {
+ return;
+ }
+
+
+ //
+ // Be sure that PassNamePduToRt has not taken the RcvIrp for a
+ // Rcv just now.
+ //
+ CTEGetLock(&pRt->Lock,&OldIrq);
+ if (pRt && (pRt == pRtInfo) && (*(REQUEST_LINKAGE(pIrp))).Flink != NULL)
+ {
+
+ PRT_IRP pRtAF = &pRt->AddFl[Index];
+
+ RemoveEntryList(REQUEST_LINKAGE(pIrp));
+
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+ pRtAF->NoOfRcvIrps--;
+ CTEFreeLock(&pRt->Lock,OldIrq);
+ IpxPrint1("RtIrpCancel;Completing Request. NoOfRcvIrp = (%d)\n", pRtAF->NoOfRcvIrps);
+ IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
+ } else {
+ CTEFreeLock(&pRt->Lock,OldIrq);
+ }
+}
+//----------------------------------------------------------------------------
+ PVOID
+RtAllocMem(
+ IN ULONG Size
+ )
+
+/*++
+Routine Description;
+
+ This Routine handles allocating memory and keeping track of how
+ much has been allocated.
+
+Arguments;
+
+ Size - number of bytes to allocate
+ Rcv - boolean that indicates if it is rcv or send buffering
+
+Return Value;
+
+ ptr to the memory allocated
+
+--*/
+
+{
+ if (pRtInfo->RcvMemoryAllocated > pRtInfo->RcvMemoryMax)
+ {
+ return NULL;
+ }
+ else
+ {
+ pRtInfo->RcvMemoryAllocated += Size;
+ return (AllocMem(Size));
+ }
+}
+//----------------------------------------------------------------------------
+ VOID
+RtFreeMem(
+ IN PVOID pBuffer,
+ IN ULONG Size
+ )
+
+/*++
+Routine Description;
+
+ This Routine handles freeing memory and keeping track of how
+ much has been allocated.
+
+Arguments;
+
+ pBuffer - buffer to free
+ Size - number of bytes to allocate
+ Rcv - boolean that indicates if it is rcv or send buffering
+
+Return Value;
+
+ none
+
+--*/
+
+{
+ if (pRtInfo)
+ {
+ pRtInfo->RcvMemoryAllocated -= Size;
+ }
+
+ FreeMem(pBuffer, Size);
+}
+
+
+
+//----------------------------------------------------------------------------
+
+VOID
+NTIoComplete(
+ IN PIRP pIrp,
+ IN NTSTATUS Status,
+ IN ULONG SentLength)
+
+/*++
+Routine Description;
+
+ This Routine handles calling the NT I/O system to complete an I/O.
+
+Arguments;
+
+ status - a completion status for the Irp
+
+Return Value;
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ KIRQL OldIrq;
+
+ if (Status != -1)
+ {
+ pIrp->IoStatus.Status = Status;
+ }
+ // use -1 as a flag to mean do not adjust the sent length since it is
+ // already set
+ if (SentLength != -1)
+ {
+ pIrp->IoStatus.Information = SentLength;
+ }
+
+#if DBG
+ if (SentLength != -1)
+ {
+ if ( (Status != STATUS_SUCCESS) &&
+ (Status != STATUS_PENDING) &&
+ (Status != STATUS_INVALID_DEVICE_REQUEST) &&
+ (Status != STATUS_INVALID_PARAMETER) &&
+ (Status != STATUS_IO_TIMEOUT) &&
+ (Status != STATUS_BUFFER_OVERFLOW) &&
+ (Status != STATUS_BUFFER_TOO_SMALL) &&
+ (Status != STATUS_INVALID_HANDLE) &&
+ (Status != STATUS_INSUFFICIENT_RESOURCES) &&
+ (Status != STATUS_CANCELLED) &&
+ (Status != STATUS_DUPLICATE_NAME) &&
+ (Status != STATUS_TOO_MANY_NAMES) &&
+ (Status != STATUS_TOO_MANY_SESSIONS) &&
+ (Status != STATUS_REMOTE_NOT_LISTENING) &&
+ (Status != STATUS_BAD_NETWORK_PATH) &&
+ (Status != STATUS_HOST_UNREACHABLE) &&
+ (Status != STATUS_CONNECTION_REFUSED) &&
+ (Status != STATUS_WORKING_SET_QUOTA) &&
+ (Status != STATUS_REMOTE_DISCONNECT) &&
+ (Status != STATUS_LOCAL_DISCONNECT) &&
+ (Status != STATUS_LINK_FAILED) &&
+ (Status != STATUS_SHARING_VIOLATION) &&
+ (Status != STATUS_UNSUCCESSFUL) &&
+ (Status != STATUS_ACCESS_VIOLATION) &&
+ (Status != STATUS_NONEXISTENT_EA_ENTRY) )
+ {
+ IpxPrint1("returning unusual status = %X\n",Status);
+ }
+ }
+#endif
+ IpxPrint1("Irp Status is %d\n", pIrp->IoStatus.Status);
+
+ //
+ // set the Irps cancel routine to null or the system may bugcheck
+ // with a bug code of CANCEL_STATE_IN_COMPLETED_IRP
+ //
+ // refer to IoCancelIrp() ..\ntos\io\iosubs.c
+ //
+ IoAcquireCancelSpinLock(&OldIrq);
+ IoSetCancelRoutine(pIrp,NULL);
+ IoReleaseCancelSpinLock(OldIrq);
+
+ IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTCheckSetCancelRoutine(
+ IN PIRP pIrp,
+ IN PVOID CancelRoutine,
+ IN PDEVICE pDevice
+ )
+
+/*++
+Routine Description;
+
+ This Routine sets the cancel routine for an Irp.
+
+Arguments;
+
+ status - a completion status for the Irp
+
+Return Value;
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status;
+
+ IpxPrint1("CheckSetCancelRoutine: Entered. Irp = (%lx)\n", pIrp);
+ //
+ // Check if the irp was cancelled yet and if not, then set the
+ // irp cancel routine.
+ //
+ IoAcquireCancelSpinLock(&pIrp->CancelIrql);
+ if (pIrp->Cancel)
+ {
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+ status = STATUS_CANCELLED;
+
+ }
+ else
+ {
+ // setup the cancel routine
+ IoMarkIrpPending(pIrp);
+ IoSetCancelRoutine(pIrp,CancelRoutine);
+ status = STATUS_SUCCESS;
+ }
+
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+ return(status);
+
+}
+
+
+
+
+VOID
+IpxRefRt(
+ PRT_INFO pRt
+ )
+
+/*++
+
+Routine Description;
+
+ This routine increments the reference count on a device context.
+
+Arguments;
+
+ Binding - Pointer to a transport device context object.
+
+Return Value;
+
+ none.
+
+--*/
+
+{
+
+ (VOID)InterlockedIncrement (&pRt->ReferenceCount);
+// CTEAssert (pRt->ReferenceCount > 0); // not perfect, but...
+// IpxPrint1("RefRt: RefCount is (%d)\n", pRt->ReferenceCount);
+
+} /* IpxRefRt */
+
+
+VOID
+IpxDerefRt(
+ PRT_INFO pRt
+ )
+
+/*++
+
+Routine Description;
+
+ This routine dereferences a device context by decrementing the
+ reference count contained in the structure. Currently, we don't
+ do anything special when the reference count drops to zero, but
+ we could dynamically unload stuff then.
+
+Arguments;
+
+ Binding - Pointer to a transport device context object.
+
+Return Value;
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&pRt->ReferenceCount);
+// IpxPrint1("DerefRt: RefCount is (%d)\n", pRt->ReferenceCount);
+
+// CTEAssert (result >= 0);
+
+#if 0
+ if (result == 0) {
+ IpxDestroyRt (pRt);
+ }
+#endif
+
+} /* IpxDerefRt */
+
+
+
+
+VOID
+IpxDestroyRt(
+ IN PRT_INFO pRt
+ )
+
+/*++
+
+Routine Description;
+
+ This routine destroys a binding structure.
+
+Arguments;
+
+ Binding - Pointer to a transport binding structure.
+
+Return Value;
+
+ None.
+
+--*/
+
+{
+ IpxPrint0("Destroying Rt\n");
+ FreeMem (pRt, sizeof(RT_INFO));
+ pRtInfo = NULL;
+ return;
+} /* IpxDestroyRt */
+
diff --git a/private/ntos/tdi/isn/ipx/send.c b/private/ntos/tdi/isn/ipx/send.c
new file mode 100644
index 000000000..b4e885c48
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/send.c
@@ -0,0 +1,2364 @@
+
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ This module contains code that implements the send engine for the
+ IPX transport provider.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - August-25-1995
+ Bug Fixes - tagged [SA]
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// BUGBUG Using the macro for performance reasons. Should be taken out
+// when NdisQueryPacket is optimized. In the near future (after PPC release)
+// move this to a header file and use it at other places.
+//
+#define IPX_PACKET_HEAD(Pkt) (Pkt)->Private.Head
+
+#if 0
+#define IpxGetMdlChainLength(Mdl, Length) { \
+ PMDL _Mdl = (Mdl); \
+ *(Length) = 0; \
+ while (_Mdl) { \
+ *(Length) += MmGetMdlByteCount(_Mdl); \
+ _Mdl = _Mdl->Next; \
+ } \
+}
+#endif
+
+VOID
+IpxSendComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to indicate that a connection-
+ oriented packet has been shipped and is no longer needed by the Physical
+ Provider.
+
+Arguments:
+
+ ProtocolBindingContext - The ADAPTER structure for this binding.
+
+ NdisPacket/RequestHandle - A pointer to the NDIS_PACKET that we sent.
+
+ NdisStatus - the completion status of the send.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(NdisPacket->ProtocolReserved);
+ PADAPTER Adapter = (PADAPTER)ProtocolBindingContext;
+ PREQUEST Request;
+ PADDRESS_FILE AddressFile;
+ PDEVICE Device = IpxDevice;
+ PBINDING Binding;
+ USHORT NewId, OldId;
+ ULONG NewOffset, OldOffset;
+ PIPX_HEADER IpxHeader;
+ IPX_LOCAL_TARGET LocalTarget;
+ PIO_STACK_LOCATION irpSp;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+#if DBG
+ if (Adapter != NULL) {
+ ASSERT_ADAPTER(Adapter);
+ }
+#endif
+
+ //
+ // See if this send was padded.
+ //
+RealFunctionStart:;
+ if (Reserved->PaddingBuffer) {
+
+ UINT Offset;
+ //
+ // Check if we simply need to re-adjust the buffer length. This will
+ // happen if we incremented the buffer length in MAC.C.
+ //
+
+ if (Reserved->PreviousTail) {
+ CTEAssert (NDIS_BUFFER_LINKAGE(Reserved->PaddingBuffer->NdisBuffer) == NULL);
+ NDIS_BUFFER_LINKAGE (Reserved->PreviousTail) = (PNDIS_BUFFER)NULL;
+ } else {
+ PNDIS_BUFFER LastBuffer = (PNDIS_BUFFER)Reserved->PaddingBuffer;
+ UINT BufferLength;
+
+ NdisQueryBufferOffset( LastBuffer, &Offset, &BufferLength );
+ NdisAdjustBufferLength( LastBuffer, (BufferLength - 1) );
+ }
+
+ Reserved->PaddingBuffer = NULL;
+
+ if (Reserved->Identifier < IDENTIFIER_IPX) {
+ NdisRecalculatePacketCounts (NdisPacket);
+ }
+ }
+
+FunctionStart:;
+
+ switch (Reserved->Identifier) {
+
+ case IDENTIFIER_IPX:
+
+// #if DBG
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+// #endif
+
+ //
+ // Check if this packet should be sent to all
+ // networks.
+ //
+
+ if (Reserved->u.SR_DG.CurrentNicId) {
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+ Reserved->u.SR_DG.Net0SendSucceeded = TRUE;
+ }
+
+ OldId = Reserved->u.SR_DG.CurrentNicId;
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (NewId = OldId+1; NewId <= Index; NewId++) {
+ if ((Binding = NIC_ID_TO_BINDING(Device, NewId))
+#else
+ for (NewId = OldId+1; NewId <= Device->HighestExternalNicId; NewId++) {
+ if ((Binding = Device->Bindings[NewId])
+#endif _PNP_POWER
+ &&
+ ((!Device->SingleNetworkActive) ||
+ (Device->ActiveNetworkWan == Binding->Adapter->MacInfo.MediumAsync))
+ &&
+ (Device->ForwarderBound ||
+ (!Device->DisableDialoutSap) ||
+ (!Binding->DialOutAsync) ||
+ (!Reserved->u.SR_DG.OutgoingSap))) {
+
+ //
+ // The binding exists, and we either are not configured
+ // for "SingleNetworkActive", or we are and this binding
+ // is the right type (i.e. the active network is wan and
+ // this is a wan binding, or the active network is not
+ // wan and this is not a wan binding), and if the FWD is
+ // not bound; and this is not an outgoing sap that we are
+ // trying to send with "DisableDialoutSap" set.
+ //
+
+ break;
+ }
+ }
+ }
+
+ if (NewId <= MIN (Device->MaxBindings, Device->HighestExternalNicId)) {
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif _PNP_POWER
+
+ //
+ // Yes, we found another net to send it on, so
+ // move the header around if needed and do so.
+ //
+
+ Reserved->u.SR_DG.CurrentNicId = NewId;
+ CTEAssert ((Reserved->DestinationType == DESTINATION_BCAST) ||
+ (Reserved->DestinationType == DESTINATION_MCAST));
+
+#if 0
+ NewOffset = Binding->BcMcHeaderSize;
+ OldOffset = Device->Bindings[OldId]->BcMcHeaderSize;
+
+ if (OldOffset != NewOffset) {
+
+ RtlMoveMemory(
+ &Reserved->Header[NewOffset],
+ &Reserved->Header[OldOffset],
+ sizeof(IPX_HEADER));
+
+ }
+
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[NewOffset]);
+#endif
+
+
+
+#if BACK_FILL
+ // This should be a normal packet. Backfill packet is never used for
+ // reserved other than IPX type
+
+ CTEAssert(!Reserved->BackFill);
+#endif
+
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[MAC_HEADER_SIZE]);
+
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&LocalTarget, NewId);
+#else
+ LocalTarget.NicId = NewId;
+#endif
+ RtlCopyMemory(LocalTarget.MacAddress, IpxHeader->DestinationNode, 6);
+
+ if (Device->MultiCardZeroVirtual ||
+ (IpxHeader->DestinationSocket == SAP_SOCKET)) {
+
+ //
+ // SAP frames need to look like they come from the
+ // local network, not the virtual one. The same is
+ // true if we are running multiple nets without
+ // a virtual net.
+ //
+
+ *(UNALIGNED ULONG *)IpxHeader->SourceNetwork = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory (IpxHeader->SourceNode, Binding->LocalAddress.NodeAddress, 6);
+ }
+
+ //
+ // Fill in the MAC header and submit the frame to NDIS.
+ //
+
+// #if DBG
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+// #endif
+
+ //
+ // [FW] Call the InternalSendHandler of the Forwarder
+ //
+
+ if (Device->ForwarderBound) {
+
+ //
+ // Call the InternalSend to filter the packet and get to know
+ // the correct adapter context
+ //
+
+ NTSTATUS ret;
+ PUCHAR IpxHeader;
+ PUCHAR Data;
+ PNDIS_BUFFER HeaderBuffer;
+ UINT TempHeaderBufferLength;
+ UINT DataLength;
+ ULONG FwdAdapterCtx = INVALID_CONTEXT_VALUE;
+
+ if (GET_VALUE(Binding->ReferenceCount) == 2) {
+ FwdAdapterCtx = Binding->FwdAdapterContext;
+ }
+
+ //
+ // Figure out the IpxHeader - it is always at the top of the second MDL.
+ //
+ NdisQueryPacket (NdisPacket, NULL, NULL, &HeaderBuffer, NULL);
+ NdisQueryBuffer (NDIS_BUFFER_LINKAGE(HeaderBuffer), &IpxHeader, &TempHeaderBufferLength);
+
+ //
+ // Data is always at the top of the third MDL.
+ //
+ NdisQueryBuffer (NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE(HeaderBuffer)), &Data, &DataLength);
+
+ ret = (*Device->UpperDrivers[IDENTIFIER_RIP].InternalSendHandler)(
+ &LocalTarget,
+ FwdAdapterCtx,
+ NdisPacket,
+ IpxHeader,
+ Data,
+ REQUEST_INFORMATION(Reserved->u.SR_DG.Request) + sizeof(IPX_HEADER),
+ FALSE);
+
+ //
+ // The return shd not be a silent drop - we dont broadcast keepalives.
+ //
+ CTEAssert(ret != STATUS_DROP_SILENTLY);
+
+ if (ret == STATUS_SUCCESS) {
+ //
+ // The adapter could have gone away and we have indicated to the Forwarder
+ // but the Forwarder has not yet closed the adapter.
+ // [ZZ] adapters do not go away now.
+ //
+ // BUGBUG: what if the binding is NULL here? Can we trust the Forwarder to
+ // give us a non-NULL binding?
+ //
+ Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(&LocalTarget));
+
+ if (GET_VALUE(Binding->ReferenceCount) == 1) {
+ Adapter = Binding->Adapter;
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif _PNP_POWER
+ goto FunctionStart;
+ } else {
+ goto send_packet;
+ }
+
+ } else if (ret == STATUS_PENDING) {
+ //
+ // LocalTarget will get filled up in InternalSendComplete
+ //
+ return;
+ }
+ //
+ // else DISCARD
+ //
+ Adapter = Binding->Adapter;
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif _PNP_POWER
+ goto FunctionStart;
+
+ } else {
+send_packet:
+ //
+ // [FW] Use the frametype specific send handler
+ //
+
+ // if ((NdisStatus = IpxSendFrame(
+ // &LocalTarget,
+ // NdisPacket,
+ // REQUEST_INFORMATION(Reserved->u.SR_DG.Request) + sizeof(IPX_HEADER),
+ // sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+ //
+ // Adapter = Binding->Adapter;
+ // goto FunctionStart;
+ // }
+ //
+ // return;
+
+ if ((NdisStatus = (*Binding->SendFrameHandler)(
+ Binding->Adapter,
+ &LocalTarget,
+ NdisPacket,
+ REQUEST_INFORMATION(Reserved->u.SR_DG.Request) + sizeof(IPX_HEADER),
+ sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ Adapter = Binding->Adapter;
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif _PNP_POWER
+ goto RealFunctionStart;
+ }
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif _PNP_POWER
+ return;
+ }
+ } else {
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif _PNP_POWER
+ //
+ // If any of the sends succeeded then return
+ // success on the datagram send, otherwise
+ // use the most recent failure status.
+ //
+
+ if (Reserved->u.SR_DG.Net0SendSucceeded) {
+ NdisStatus = NDIS_STATUS_SUCCESS;
+ }
+
+ }
+
+ }
+
+
+#if 0
+ //
+ // NOTE: We don't NULL out the linkage field of the
+ // HeaderBuffer, which will leave the old buffer chain
+ // hanging off it; but that is OK because if we reuse
+ // this packet we will replace that chain with the new
+ // one, and before we free it we NULL it out.
+ //
+ // I.e. we don't do this:
+ //
+
+ NDIS_BUFFER_LINKAGE (Reserved->HeaderBuffer) = NULL;
+ NdisRecalculatePacketCounts (NdisPacket);
+#endif
+
+#if 0
+ {
+ ULONG ActualLength;
+ IpxGetMdlChainLength(NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer), &ActualLength);
+ if (ActualLength != REQUEST_INFORMATION(Reserved->u.SR_DG.Request)) {
+ DbgPrint ("IPX: At completion, IRP %lx has parameter length %d, buffer chain length %d\n",
+ Reserved->u.SR_DG.Request, REQUEST_INFORMATION(Reserved->u.SR_DG.Request), ActualLength);
+ DbgBreakPoint();
+ }
+ }
+#endif
+
+ //
+ // Save these so we can free the packet.
+ //
+
+ Request = Reserved->u.SR_DG.Request;
+ AddressFile = Reserved->u.SR_DG.AddressFile;
+
+
+#if BACK_FILL
+ // Check if this is backfilled. If so restore users Mdl back to its original shape
+ // Also, push the packet on to backfillpacket queue if the packet is not owned by the address
+
+ if (Reserved->BackFill) {
+
+ Reserved->HeaderBuffer->MappedSystemVa = Reserved->MappedSystemVa;
+ Reserved->HeaderBuffer->ByteCount = Reserved->UserLength;
+ Reserved->HeaderBuffer->StartVa = (PCHAR)((ULONG)Reserved->HeaderBuffer->MappedSystemVa & ~(PAGE_SIZE-1));
+ Reserved->HeaderBuffer->ByteOffset = (ULONG)Reserved->HeaderBuffer->MappedSystemVa & (PAGE_SIZE-1);
+
+ IPX_DEBUG(SEND, ("completeing back filled userMdl %x\n",Reserved->HeaderBuffer));
+
+ NdisPacket->Private.ValidCounts = FALSE;
+
+ NdisPacket->Private.Head = NULL;
+ NdisPacket->Private.Tail = NULL;
+
+ Reserved->HeaderBuffer = NULL;
+
+ if (Reserved->OwnedByAddress) {
+
+ // Reserved->Address->BackFillPacketInUse = FALSE;
+ InterlockedDecrement(&Reserved->Address->BackFillPacketInUse);
+
+ IPX_DEBUG(SEND, ("Freeing owned backfill %x\n", Reserved));
+
+ } else {
+
+ IPX_PUSH_ENTRY_LIST(
+ &Device->BackFillPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+ }
+ }
+ // not a back fill packet. Push it on sendpacket pool
+ else {
+
+ if (Reserved->OwnedByAddress) {
+
+ // Reserved->Address->SendPacketInUse = FALSE;
+ InterlockedDecrement(&Reserved->Address->SendPacketInUse);
+
+ } else {
+
+ IPX_PUSH_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+
+ }
+
+
+ }
+
+#else
+
+ if (Reserved->OwnedByAddress) {
+
+
+ Reserved->Address->SendPacketInUse = FALSE;
+
+ } else {
+
+ IPX_PUSH_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+
+ }
+#endif
+
+ ++Device->Statistics.PacketsSent;
+
+ //
+ // If this is a fast send irp, we bypass the file system and
+ // call the completion routine directly.
+ //
+
+ REQUEST_STATUS(Request) = NdisStatus;
+ irpSp = IoGetCurrentIrpStackLocation( Request );
+
+ if ( irpSp->MinorFunction == TDI_DIRECT_SEND_DATAGRAM ) {
+
+ Request->CurrentLocation++,
+ Request->Tail.Overlay.CurrentStackLocation++;
+
+ (VOID) irpSp->CompletionRoutine(
+ NULL,
+ Request,
+ irpSp->Context
+ );
+
+ } else {
+ IpxCompleteRequest (Request);
+ }
+
+ IpxFreeRequest(Device, Request);
+
+ IpxDereferenceAddressFileSync (AddressFile, AFREF_SEND_DGRAM);
+
+ break;
+
+ case IDENTIFIER_RIP_INTERNAL:
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+ break;
+
+ case IDENTIFIER_RIP_RESPONSE:
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ Reserved->Identifier = IDENTIFIER_IPX;
+ IPX_PUSH_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+
+ IpxDereferenceDevice (Device, DREF_RIP_PACKET);
+ break;
+
+#ifdef _PNP_POWER
+ case IDENTIFIER_NB:
+ case IDENTIFIER_SPX:
+
+ //
+ // See if this is an iterative send
+ //
+ if (OldId = Reserved->CurrentNicId) {
+
+ PNDIS_BUFFER HeaderBuffer;
+ UINT TempHeaderBufferLength;
+ PUCHAR Header;
+ PIPX_HEADER IpxHeader;
+ BOOLEAN fFwdDecides=FALSE;
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+ Reserved->Net0SendSucceeded = TRUE;
+ }
+
+ //
+ // Figure out the IpxHeader - it is always at the top of the second MDL.
+ //
+ NdisQueryPacket (NdisPacket, NULL, NULL, &HeaderBuffer, NULL);
+ NdisQueryBuffer (NDIS_BUFFER_LINKAGE(HeaderBuffer), &IpxHeader, &TempHeaderBufferLength);
+
+ //
+ // For Type 20 pkts, we let the Fwd decide the next Nic to send on, so we pass
+ // the old Nic itself and let the Fwd change it for us.
+ //
+ if ((Device->ForwarderBound) &&
+ (IpxHeader->PacketType == 0x14)) {
+ NewId = NIC_FROM_LOCAL_TARGET(&Reserved->LocalTarget);
+ fFwdDecides=TRUE;
+ Binding = NIC_ID_TO_BINDING(Device, NewId);
+ IPX_DEBUG(SEND, ("SendComplete: IpxHeader has Type20: %lx\n", IpxHeader));
+ } else {
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (NewId = OldId+1; NewId <= Index; NewId++) {
+ if (Binding = NIC_ID_TO_BINDING(Device, NewId)) {
+ //
+ // Found next NIC to send on
+ //
+ break;
+ }
+ }
+ }
+ }
+
+ if (NewId <= MIN (Device->MaxBindings, Device->HighestExternalNicId)) {
+
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // Yes, we found another net to send it on, so
+ // move the header around if needed and do so.
+ //
+ IPX_DEBUG(SEND, ("ISN iteration: OldId: %lx, NewId: %lx\n", OldId, NewId));
+ Reserved->CurrentNicId = NewId;
+
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&LocalTarget, NewId);
+#else
+ LocalTarget.NicId = NewId;
+#endif
+ RtlCopyMemory(LocalTarget.MacAddress, IpxHeader->DestinationNode, 6);
+
+ //
+ // [FW] Call the InternalSendHandler of the Forwarder
+ //
+
+ if (Device->ForwarderBound) {
+
+ //
+ // Call the InternalSend to filter the packet and get to know
+ // the correct adapter context
+ //
+
+ NTSTATUS ret;
+ PUCHAR Data;
+ UINT DataLength;
+ ULONG FwdAdapterCtx = INVALID_CONTEXT_VALUE;
+
+ if (GET_VALUE(Binding->ReferenceCount) == 2) {
+ FwdAdapterCtx = Binding->FwdAdapterContext;
+ }
+
+ ret = (*Device->UpperDrivers[IDENTIFIER_RIP].InternalSendHandler)(
+ &LocalTarget,
+ FwdAdapterCtx,
+ NdisPacket,
+ (PUCHAR)IpxHeader,
+ ((PUCHAR)IpxHeader)+sizeof(IPX_HEADER), // the data starts after the IPX Header.
+ Reserved->PacketLength,
+ TRUE); // iterate is true
+
+ //
+ // The return shd not be a silent drop - we dont broadcast keepalives.
+ //
+ CTEAssert(ret != STATUS_DROP_SILENTLY);
+
+ if (ret == STATUS_SUCCESS) {
+ //
+ // The adapter could have gone away and we have indicated to the Forwarder
+ // but the Forwarder has not yet closed the adapter.
+ // [ZZ] adapters do not go away now.
+ //
+ // BUGBUG: what if the binding is NULL here? Can we trust the Forwarder to
+ // give us a non-NULL binding?
+ //
+ Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(&LocalTarget));
+
+ if (GET_VALUE(Binding->ReferenceCount) == 1) {
+ Adapter = Binding->Adapter;
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ goto FunctionStart;
+ } else {
+ NewId = NIC_FROM_LOCAL_TARGET(&LocalTarget);
+ goto send_packet1;
+ }
+
+ } else if (ret == STATUS_PENDING) {
+ //
+ // LocalTarget will get filled up in InternalSendComplete
+ //
+ return;
+ }
+ //
+ // else DISCARD
+ //
+ Adapter = Binding->Adapter;
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+
+ //
+ // If Fwd decides, then this is end of Nic list - complete the send.
+ //
+ if (fFwdDecides) {
+ goto NoMoreSends;
+ } else {
+ goto FunctionStart;
+ }
+
+ } else {
+#if DBG
+ NdisQueryPacket (NdisPacket, NULL, NULL, &HeaderBuffer, NULL);
+ NdisQueryBuffer(HeaderBuffer, &Header, &TempHeaderBufferLength);
+
+ IpxHeader = (PIPX_HEADER)(&Header[Device->IncludedHeaderOffset]);
+
+ IPX_DEBUG(SEND, ("SendComplete: IpxHeader: %lx\n", IpxHeader));
+#endif
+
+send_packet1:
+
+ FILL_LOCAL_TARGET(&Reserved->LocalTarget, NewId);
+
+ //
+ // We don't need to so this since the macaddress is replaced in
+ // IpxSendFrame anyway. The LocalTarget is the same as the one on
+ // the original send - this is passed down for further sends.
+ //
+ // RtlCopyMemory(LocalTarget.MacAddress, IpxHeader->DestinationNode, 6);
+
+ //
+ // Fill in the MAC header and submit the frame to NDIS.
+ //
+
+ if ((NdisStatus = IpxSendFrame(
+ &Reserved->LocalTarget,
+ NdisPacket,
+ Reserved->PacketLength,
+ sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ Adapter = Binding->Adapter;
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ goto FunctionStart;
+ }
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+
+ return;
+ }
+ } else {
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+NoMoreSends:
+ //
+ // If any of the sends succeeded then return
+ // success on the datagram send, otherwise
+ // use the most recent failure status.
+ //
+ if (Reserved->Net0SendSucceeded) {
+ NdisStatus = NDIS_STATUS_SUCCESS;
+ }
+
+ }
+ }
+
+ //
+ // fall thru'
+ //
+#endif
+ default:
+
+ (*Device->UpperDrivers[Reserved->Identifier].SendCompleteHandler)(
+ NdisPacket,
+ NdisStatus);
+ break;
+ }
+
+} /* IpxSendComplete */
+
+
+NTSTATUS
+IpxTdiSendDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSendDatagram request for the transport
+ provider.
+
+Arguments:
+
+ Request - Pointer to the request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PNDIS_PACKET Packet;
+ PIPX_SEND_RESERVED Reserved;
+ PSINGLE_LIST_ENTRY s;
+ TDI_ADDRESS_IPX UNALIGNED * RemoteAddress;
+ TDI_ADDRESS_IPX TempAddress;
+ TA_ADDRESS UNALIGNED * AddressName;
+ PTDI_CONNECTION_INFORMATION Information;
+ PTDI_REQUEST_KERNEL_SENDDG Parameters;
+ PBINDING Binding;
+ IPX_LOCAL_TARGET TempLocalTarget;
+ PIPX_LOCAL_TARGET LocalTarget;
+ PDEVICE Device = IpxDevice;
+ UCHAR PacketType;
+ NTSTATUS Status;
+ PIPX_HEADER IpxHeader;
+ NDIS_STATUS NdisStatus;
+ USHORT LengthIncludingHeader;
+ IPX_DEFINE_SYNC_CONTEXT (SyncContext)
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+ PIO_STACK_LOCATION irpSp; \
+ BOOLEAN IsLoopback = FALSE;
+ IPX_FIND_ROUTE_REQUEST routeEntry;
+ PIPX_DATAGRAM_OPTIONS2 Options;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysOutRequests);
+#endif SNMP
+
+ //
+ // Do a quick check of the validity of the address.
+ //
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ IPX_BEGIN_SYNC (&SyncContext);
+
+ if ((AddressFile->Size == sizeof (ADDRESS_FILE)) &&
+ (AddressFile->Type == IPX_ADDRESSFILE_SIGNATURE) &&
+ ((Address = AddressFile->Address) != NULL)) {
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (AddressFile->State != ADDRESSFILE_STATE_CLOSING) {
+
+ Parameters = (PTDI_REQUEST_KERNEL_SENDDG)REQUEST_PARAMETERS(Request);
+ Information = Parameters->SendDatagramInformation;
+
+ //
+ // Do a quick check if this address has only one entry.
+ //
+
+ if (!REQUEST_SPECIAL_SEND(Request)) {
+ AddressName = &((TRANSPORT_ADDRESS UNALIGNED *)(Information->RemoteAddress))->Address[0];
+
+ if ((AddressName->AddressType == TDI_ADDRESS_TYPE_IPX) &&
+ (AddressName->AddressLength >= sizeof(TDI_ADDRESS_IPX))) {
+
+ RemoteAddress = (TDI_ADDRESS_IPX UNALIGNED *)(AddressName->Address);
+
+ } else if ((RemoteAddress = IpxParseTdiAddress (Information->RemoteAddress)) == NULL) {
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INVALID_ADDRESS;
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysOutDiscards);
+#endif SNMP
+ goto error_send_no_packet;
+ }
+ } else {
+ ASSERT(OPEN_REQUEST_EA_LENGTH(Request) == sizeof(IPX_DATAGRAM_OPTIONS2));
+ Options = ((PIPX_DATAGRAM_OPTIONS2)(OPEN_REQUEST_EA_INFORMATION(Request)));
+ RemoteAddress = (TDI_ADDRESS_IPX UNALIGNED *)(&Options->RemoteAddress);
+ IPX_DEBUG(SEND, ("IpxTdiSendDatagram: Options buffer supplied as input buffer\n"));
+ }
+
+ IPX_DEBUG (SEND, ("Send on %lx, network %lx socket %lx\n",
+ Address, RemoteAddress->NetworkAddress, RemoteAddress->Socket));
+
+#if 0
+ if (Parameters->SendLength > IpxDevice->RealMaxDatagramSize) {
+
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ Parameters->SendLength,
+ IpxDevice->RealMaxDatagramSize));
+
+ REQUEST_INFORMATION(Request) = 0;
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto error_send_no_packet;
+ }
+#endif
+ //
+ // Every address has one packet committed to it, use that
+ // if possible, otherwise take one out of the pool.
+ //
+
+
+#if BACK_FILL
+
+ // If the request is coming from the server, which resrves transport header space
+ // build the header in its space. Allocate a special packet to which does not contain
+ // mac and ipx headers in its reserved space.
+
+ if ((PMDL)REQUEST_NDIS_BUFFER(Request) &&
+ (((PMDL)REQUEST_NDIS_BUFFER(Request))->MdlFlags & MDL_NETWORK_HEADER) &&
+ (!(Information->OptionsLength < sizeof(IPX_DATAGRAM_OPTIONS))) &&
+ (RemoteAddress->NodeAddress[0] != 0xff)) {
+
+ //if (!Address->BackFillPacketInUse) {
+ if (InterlockedExchangeAdd(&Address->BackFillPacketInUse, 0) == 0) {
+ //Address->BackFillPacketInUse = TRUE;
+ InterlockedIncrement(&Address->BackFillPacketInUse);
+
+ Packet = PACKET(&Address->BackFillPacket);
+ Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ IPX_DEBUG(SEND, ("Getting owned backfill %x %x \n", Packet,Reserved));
+
+ }else {
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BackFillPacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ goto GotBackFillPacket;
+ }
+
+ //
+ // This function tries to allocate another packet pool.
+ //
+
+ s = IpxPopBackFillPacket(Device);
+
+ //
+ // Possibly we should queue the packet up to wait
+ // for one to become free.
+ //
+
+ if (s == NULL) {
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysOutDiscards);
+#endif SNMP
+ goto error_send_no_packet;
+ }
+
+GotBackFillPacket:
+
+ Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+ IPX_DEBUG(SEND, ("getting backfill packet %x %x %x\n", s, Reserved, RemoteAddress->NodeAddress));
+ if(!Reserved->BackFill)DbgBreakPoint();
+
+ }
+
+ }else {
+
+ // if (!Address->SendPacketInUse) {
+ if (InterlockedExchangeAdd(&Address->SendPacketInUse, 0) == 0) {
+ // Address->SendPacketInUse = TRUE;
+ InterlockedIncrement(&Address->SendPacketInUse);
+
+ Packet = PACKET(&Address->SendPacket);
+ Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+
+ } else {
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ goto GotPacket;
+ }
+
+ //
+ // This function tries to allocate another packet pool.
+ //
+
+ s = IpxPopSendPacket(Device);
+
+ //
+ // Possibly we should queue the packet up to wait
+ // for one to become free.
+ //
+
+ if (s == NULL) {
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysOutDiscards);
+#endif SNMP
+ goto error_send_no_packet;
+ }
+
+GotPacket:
+
+ Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+ Reserved->BackFill = FALSE;
+
+ }
+
+ }
+
+
+#else
+
+ if (!Address->SendPacketInUse) {
+
+ Address->SendPacketInUse = TRUE;
+ Packet = PACKET(&Address->SendPacket);
+ Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+
+ } else {
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ goto GotPacket;
+ }
+
+ //
+ // This function tries to allocate another packet pool.
+ //
+
+ s = IpxPopSendPacket(Device);
+
+ //
+ // Possibly we should queue the packet up to wait
+ // for one to become free.
+ //
+
+ if (s == NULL) {
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto error_send_no_packet;
+ }
+
+GotPacket:
+
+ Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ }
+
+
+#endif
+
+ IpxReferenceAddressFileLock (AddressFile, AFREF_SEND_DGRAM);
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+
+ //
+ // Save this now while we have Parameters available.
+ //
+
+ REQUEST_INFORMATION(Request) = Parameters->SendLength;
+ LengthIncludingHeader = (USHORT)(Parameters->SendLength + sizeof(IPX_HEADER));
+
+#if 0
+ {
+ ULONG ActualLength;
+ IpxGetMdlChainLength(REQUEST_NDIS_BUFFER(Request), &ActualLength);
+ if (ActualLength != Parameters->SendLength) {
+ DbgPrint ("IPX: IRP %lx has parameter length %d, buffer chain length %d\n",
+ Request, Parameters->SendLength, ActualLength);
+ DbgBreakPoint();
+ }
+ }
+#endif
+
+ Reserved->u.SR_DG.AddressFile = AddressFile;
+ Reserved->u.SR_DG.Request = Request;
+ CTEAssert (Reserved->Identifier == IDENTIFIER_IPX);
+
+
+ //
+ // Set this to 0; this means the packet is not one that
+ // should be broadcast on all nets. We will change it
+ // later if it turns out this is the case.
+ //
+
+ Reserved->u.SR_DG.CurrentNicId = 0;
+
+ //
+ // We need this to track these packets specially.
+ //
+
+ Reserved->u.SR_DG.OutgoingSap = AddressFile->IsSapSocket;
+
+ //
+ // Add the MDL chain after the pre-allocated header buffer.
+ // NOTE: THIS WILL ONLY WORK IF WE EVENTUALLY CALL
+ // NDISRECALCULATEPACKETCOUNTS (which we do in IpxSendFrame).
+ //
+ //
+#if BACK_FILL
+
+ if (Reserved->BackFill) {
+ Reserved->HeaderBuffer = REQUEST_NDIS_BUFFER(Request);
+
+ //remove the ipx mdl from the packet.
+ Reserved->UserLength = Reserved->HeaderBuffer->ByteCount;
+
+ IPX_DEBUG(SEND, ("back filling userMdl Reserved %x %x\n", Reserved->HeaderBuffer, Reserved));
+ } else {
+ NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = REQUEST_NDIS_BUFFER(Request);
+ }
+#else
+ NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = REQUEST_NDIS_BUFFER(Request);
+#endif
+
+
+ //
+ // If IrpSp does not have a buffer for the right size for
+ // datagram options and there is no input buffer
+ //
+ if (!REQUEST_SPECIAL_SEND(Request) &&
+ (Information->OptionsLength < sizeof(IPX_DATAGRAM_OPTIONS))) {
+
+ //
+ // The caller did not supply the local target for this
+ // send, so we look it up ourselves.
+ //
+
+ UINT Segment;
+
+ //
+ // We calculate this now since we need to know
+ // if it is directed below.
+ //
+
+ if (RemoteAddress->NodeAddress[0] == 0xff) {
+ // BUGBUG: What about multicast?
+ if ((*(UNALIGNED ULONG *)(RemoteAddress->NodeAddress) != 0xffffffff) ||
+ (*(UNALIGNED USHORT *)(RemoteAddress->NodeAddress+4) != 0xffff)) {
+ Reserved->DestinationType = DESTINATION_MCAST;
+ } else {
+ Reserved->DestinationType = DESTINATION_BCAST;
+ }
+ } else {
+ Reserved->DestinationType = DESTINATION_DEF; // directed send
+ }
+
+ //
+ // If there are no options, then check if the
+ // caller is passing the packet type as a final byte
+ // in the remote address; if not use the default.
+ //
+
+ if (Information->OptionsLength == 0) {
+ if (AddressFile->ExtendedAddressing) {
+ PacketType = ((PUCHAR)(RemoteAddress+1))[0];
+ } else {
+ PacketType = AddressFile->DefaultPacketType;
+ }
+ } else {
+ PacketType = ((PUCHAR)(Information->Options))[0];
+ }
+
+ if ((Reserved->DestinationType != DESTINATION_DEF) &&
+ ((RemoteAddress->NetworkAddress == 0) ||
+ (Device->VirtualNetwork &&
+ (RemoteAddress->NetworkAddress == Device->SourceAddress.NetworkAddress)))) {
+
+ //
+ // This packet needs to be broadcast to all networks.
+ // Make sure it is not too big for any of them.
+ //
+
+ if (Parameters->SendLength > Device->RealMaxDatagramSize) {
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ Parameters->SendLength, Device->RealMaxDatagramSize));
+ Status = STATUS_INVALID_BUFFER_SIZE;
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysOutMalformedRequests);
+#endif SNMP
+ goto error_send_with_packet;
+ }
+
+ //
+ // If this is a broadcast to the virtual net, we
+ // need to construct a fake remote address which
+ // has network 0 in there instead.
+ //
+
+ if (Device->VirtualNetwork &&
+ (RemoteAddress->NetworkAddress == Device->SourceAddress.NetworkAddress)) {
+
+ RtlCopyMemory (&TempAddress, (PVOID)RemoteAddress, sizeof(TDI_ADDRESS_IPX));
+ TempAddress.NetworkAddress = 0;
+ RemoteAddress = (TDI_ADDRESS_IPX UNALIGNED *)&TempAddress;
+ }
+
+ //
+ // If someone is sending to the SAP socket and
+ // we are running with multiple cards without a
+ // virtual network, AND this packet is a SAP response,
+ // then we log an error to warn them that the
+ // system may not work as they like (since there
+ // is no virtual network to advertise, we use
+ // the first card's net/node as our local address).
+ // We only do this once per boot, using the
+ // SapWarningLogged variable to control that.
+ //
+
+ if ((RemoteAddress->Socket == SAP_SOCKET) &&
+ (!Device->SapWarningLogged) &&
+ (Device->MultiCardZeroVirtual)) {
+
+ PNDIS_BUFFER FirstBuffer;
+ UINT FirstBufferLength;
+ USHORT UNALIGNED * FirstBufferData;
+
+ if ((FirstBuffer = REQUEST_NDIS_BUFFER(Request)) != NULL) {
+
+ NdisQueryBuffer(
+ FirstBuffer,
+ (PVOID *)&FirstBufferData,
+ &FirstBufferLength);
+
+ //
+ // The first two bytes of a SAP packet are the
+ // operation, 0x2 (in network order) is response.
+ //
+
+ if ((FirstBufferLength >= sizeof(USHORT)) &&
+ (*FirstBufferData == 0x0200)) {
+
+ Device->SapWarningLogged = TRUE;
+
+ IpxWriteGeneralErrorLog(
+ Device->DeviceObject,
+ EVENT_IPX_SAP_ANNOUNCE,
+ 777,
+ STATUS_NOT_SUPPORTED,
+ NULL,
+ 0,
+ NULL);
+ }
+ }
+ }
+
+
+ //
+ // In this case we do not RIP but instead set the
+ // packet up so it is sent to each network in turn.
+ //
+ // Special case: If this packet is from the SAP
+ // socket and we are running with multiple cards
+ // without a virtual network, we only send this
+ // on the card with NIC ID 1, so we leave
+ // CurrentNicId set to 0.
+ //
+
+ //
+ // BUGBUG: What if NicId 1 is invalid? Should scan
+ // for first valid one, fail send if none.
+ //
+
+ if ((Address->Socket != SAP_SOCKET) ||
+ (!Device->MultiCardZeroVirtual)) {
+
+ if (Device->SingleNetworkActive) {
+
+ if (Device->ActiveNetworkWan) {
+ Reserved->u.SR_DG.CurrentNicId = Device->FirstWanNicId;
+ } else {
+ Reserved->u.SR_DG.CurrentNicId = Device->FirstLanNicId;
+ }
+
+ } else {
+
+ Reserved->u.SR_DG.CurrentNicId = 1;
+
+ }
+
+ Reserved->u.SR_DG.Net0SendSucceeded = FALSE;
+
+ //
+ // In this case, we need to scan for the first
+ // non-dialout wan socket.
+ //
+
+ if ((Device->DisableDialoutSap) &&
+ (Address->Socket == SAP_SOCKET)) {
+
+ PBINDING TempBinding;
+
+ CTEAssert (Reserved->u.SR_DG.CurrentNicId <= Device->ValidBindings);
+ while (Reserved->u.SR_DG.CurrentNicId <= MIN (Device->MaxBindings, Device->ValidBindings)) {
+#ifdef _PNP_POWER
+// No need to lock the access path since he just looks at it
+//
+ TempBinding = NIC_ID_TO_BINDING(Device, Reserved->u.SR_DG.CurrentNicId);
+#else
+ TempBinding = Device->Bindings[Reserved->u.SR_DG.CurrentNicId];
+#endif _PNP_POWER
+ if ((TempBinding != NULL) &&
+ (!TempBinding->DialOutAsync)) {
+ break;
+ }
+ ++Reserved->u.SR_DG.CurrentNicId;
+ }
+ if (Reserved->u.SR_DG.CurrentNicId > MIN (Device->MaxBindings, Device->ValidBindings)) {
+ //
+ // [SA] Bug #17273 return proper error mesg.
+ //
+
+ // Status = STATUS_DEVICE_DOES_NOT_EXIST;
+ Status = STATUS_NETWORK_UNREACHABLE;
+
+ goto error_send_with_packet;
+ }
+ }
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&TempLocalTarget, Reserved->u.SR_DG.CurrentNicId);
+#else
+ TempLocalTarget.NicId = Reserved->u.SR_DG.CurrentNicId;
+#endif
+
+ } else {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&TempLocalTarget, 1);
+#else
+ TempLocalTarget.NicId = 1;
+#endif
+ }
+
+ RtlCopyMemory(TempLocalTarget.MacAddress, RemoteAddress->NodeAddress, 6);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(&TempLocalTarget));
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ //
+ // [FW] the localtarget shd be in the packet's reserved section
+ //
+ LocalTarget = &Reserved->LocalTarget;
+ Reserved->LocalTarget = TempLocalTarget;
+ } else {
+
+ //
+ // [FW] If router installed, call the Forwarder's FindRouteHandler.
+ // This returns a STATUS_SUCCESS if a route is available
+ //
+ if (Device->ForwarderBound) {
+
+ Status = (*Device->UpperDrivers[IDENTIFIER_RIP].FindRouteHandler) (
+ (PUCHAR)&RemoteAddress->NetworkAddress,
+ RemoteAddress->NodeAddress,
+ &routeEntry);
+
+ if (Status != STATUS_SUCCESS) {
+
+ IPX_DEBUG (SEND, ("RouteHandler failed, network: %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)RemoteAddress->NetworkAddress)));
+ goto error_send_with_packet;
+
+ } else {
+
+ //
+ // Fill in the LocalTarget from the RouteEntry
+ //
+
+ LocalTarget = &Reserved->LocalTarget;
+
+ Reserved->LocalTarget = routeEntry.LocalTarget;
+
+ IPX_DEBUG(SEND, ("IPX: SendFramePreFwd: LocalTarget is: %lx\n", Reserved->LocalTarget));
+
+ if (GET_VALUE(NIC_ID_TO_BINDING(Device, LocalTarget->NicId)->ReferenceCount) == 1) {
+ IPX_DEBUG(SEND, ("IPX: SendFramePreFwd: FWD returned SUCCESS, Ref count is 1\n"));
+ Status = NDIS_STATUS_SUCCESS;
+ goto error_send_with_packet;
+ }
+
+ if (Parameters->SendLength >
+ NIC_ID_TO_BINDING(Device, LocalTarget->NicId)->RealMaxDatagramSize) {
+
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ Parameters->SendLength,
+ NIC_ID_TO_BINDING(Device, LocalTarget->NicId)->RealMaxDatagramSize));
+
+ REQUEST_INFORMATION(Request) = 0;
+ Status = STATUS_INVALID_BUFFER_SIZE;
+
+ goto error_send_with_packet;
+ }
+
+ //
+ // [FW] we dont need to check this since the FWD does it for us.
+ //
+
+ /*
+ if ((Device->DisableDialoutSap) &&
+ (Address->Socket == SAP_SOCKET) &&
+ (NIC_ID_TO_BINDING(Device, LocalTarget->NicId)->DialOutAsync)) {
+
+ REQUEST_INFORMATION(Request) = 0;
+ Status = STATUS_NETWORK_UNREACHABLE;
+ goto error_send_with_packet;
+ }
+ */
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget));
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ IPX_DEBUG(SEND, ("FindRoute for %02x-%02x-%02x-%02x-%02x-%02x returned %lx\n",
+ LocalTarget->MacAddress[0],
+ LocalTarget->MacAddress[1],
+ LocalTarget->MacAddress[2],
+ LocalTarget->MacAddress[3],
+ LocalTarget->MacAddress[4],
+ LocalTarget->MacAddress[5],
+ Status));
+
+ }
+
+ } else {
+ Segment = RipGetSegment((PUCHAR)&RemoteAddress->NetworkAddress);
+
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // This call will return STATUS_PENDING if we need to
+ // RIP for the packet.
+ //
+
+ Status = RipGetLocalTarget(
+ Segment,
+ RemoteAddress,
+ IPX_FIND_ROUTE_RIP_IF_NEEDED,
+ &TempLocalTarget,
+ NULL);
+
+ if (Status == STATUS_SUCCESS) {
+
+ //
+ // We found the route, TempLocalTarget is filled in.
+ //
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ #ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ if (NIC_FROM_LOCAL_TARGET(&TempLocalTarget) == (USHORT)LOOPBACK_NIC_ID) {
+ IPX_DEBUG(LOOPB, ("Loopback TDI packet: remoteaddr: %lx\n", RemoteAddress));
+ IsLoopback = TRUE;
+ FILL_LOCAL_TARGET(&TempLocalTarget, 1);
+ }
+ Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(&TempLocalTarget));
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ if (Parameters->SendLength >
+ Binding->RealMaxDatagramSize) {
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ Parameters->SendLength,
+ Binding->RealMaxDatagramSize));
+
+ REQUEST_INFORMATION(Request) = 0;
+ Status = STATUS_INVALID_BUFFER_SIZE;
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysOutMalformedRequests);
+#endif SNMP
+ goto error_send_with_packet;
+ }
+
+ if (!Device->ForwarderBound &&
+ (Device->DisableDialoutSap) &&
+ (Address->Socket == SAP_SOCKET) &&
+ (Binding->DialOutAsync)) {
+
+ REQUEST_INFORMATION(Request) = 0;
+ //
+ // [SA] Bug #17273 return proper error mesg.
+ //
+
+ // Status = STATUS_DEVICE_DOES_NOT_EXIST;
+ Status = STATUS_NETWORK_UNREACHABLE;
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysOutDiscards);
+#endif SNMP
+ goto error_send_with_packet;
+ }
+ #else
+ if (TempLocalTarget.NicId == 0) {
+ IPX_DEBUG(LOOPB, ("Loopback TDI packet: remoteaddr: %lx\n", RemoteAddress));
+ IsLoopback = TRUE;
+ TempLocalTarget.NicId = 1;
+ }
+
+ if (Parameters->SendLength >
+ Device->Bindings[TempLocalTarget.NicId]->RealMaxDatagramSize) {
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ Parameters->SendLength,
+ Device->Bindings[TempLocalTarget.NicId]->RealMaxDatagramSize));
+
+ REQUEST_INFORMATION(Request) = 0;
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto error_send_with_packet;
+ }
+
+ if ((Device->DisableDialoutSap) &&
+ (Address->Socket == SAP_SOCKET) &&
+ (Device->Bindings[TempLocalTarget.NicId]->DialOutAsync)) {
+
+ REQUEST_INFORMATION(Request) = 0;
+ //
+ // [SA] Bug #17273 return proper error mesg.
+ //
+
+ // Status = STATUS_DEVICE_DOES_NOT_EXIST;
+ Status = STATUS_NETWORK_UNREACHABLE;
+ goto error_send_with_packet;
+ }
+ #endif _PNP_POWER
+
+ } else if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this packet for transmission when the RIP
+ // response arrives. First we fill in the IPX
+ // header; the only thing we don't know is where
+ // exactly to fill it in, so we choose
+ // the most common location.
+ //
+
+ IpxConstructHeader(
+ &Reserved->Header[Device->IncludedHeaderOffset],
+ LengthIncludingHeader,
+ PacketType,
+ RemoteAddress,
+ &Address->LocalAddress);
+
+ //
+ // Adjust the 2nd mdl's size
+ //
+ NdisAdjustBufferLength(NDIS_BUFFER_LINKAGE(IPX_PACKET_HEAD(Packet)), sizeof(IPX_HEADER));
+
+ IPX_DEBUG (RIP, ("Queueing packet %lx\n", Reserved));
+
+ InsertTailList(
+ &Device->Segments[Segment].WaitingForRoute,
+ &Reserved->WaitLinkage);
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_END_SYNC (&SyncContext);
+
+ return STATUS_PENDING;
+
+ } else {
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysOutDiscards);
+#endif SNMP
+ goto error_send_with_packet;
+
+ }
+
+ //
+ // [FW] The localtarget shd be in the reserved section.
+ //
+ LocalTarget = &Reserved->LocalTarget;
+ Reserved->LocalTarget = TempLocalTarget;
+ }
+ }
+
+ //
+ // [FW] moved to the conditions above so we save a copy in the RIP case
+ //
+
+ // LocalTarget = &TempLocalTarget;
+
+ //
+ // Now we know the local target, we can figure out
+ // the offset for the IPX header.
+ //
+#ifdef _PNP_POWER
+// Remember that we have got the binding with ref above....
+
+#else
+ Binding = Device->Bindings[LocalTarget->NicId];
+#endif
+ IpxHeader = (PIPX_HEADER)&Reserved->Header[MAC_HEADER_SIZE];
+#if 0
+ if (Reserved->DestinationType == DESTINATION_DEF) {
+ IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->DefHeaderSize];
+ } else {
+ IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->BcMcHeaderSize];
+ }
+#endif
+
+ } else {
+
+ if (!REQUEST_SPECIAL_SEND(Request)) {
+ PacketType = ((PUCHAR)(Information->Options))[0];
+ LocalTarget = &((PIPX_DATAGRAM_OPTIONS)(Information->Options))->LocalTarget;
+ } else {
+ ASSERT(OPEN_REQUEST_EA_LENGTH(Request) == sizeof(IPX_DATAGRAM_OPTIONS2));
+ if (OPEN_REQUEST_EA_LENGTH(Request) == sizeof(IPX_DATAGRAM_OPTIONS2)) {
+ //IpxPrint0("IpxTdiSendDatagram: We have an input buffer of the right size\n");
+ } else {
+ //IpxPrint1("IpxTdiSendDatagram: Wrong sized buffer. Buff size is =(%d)\n", OPEN_REQUEST_EA_LENGTH(Request));
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto error_send_with_packet;
+ }
+
+ PacketType = Options->DgrmOptions.PacketType;
+ LocalTarget = &Options->DgrmOptions.LocalTarget;
+ if (NIC_ID_TO_BINDING(Device, LocalTarget->NicId) == NULL) {
+ Status = STATUS_NOT_FOUND;
+ goto error_send_with_packet;
+ }
+ }
+
+ //
+ // Calculate the binding and the correct location
+ // for the IPX header. We can do this at the same
+ // time as we calculate the DestinationType which
+ // saves an if like the one 15 lines up.
+ //
+
+#ifdef _PNP_POWER
+// Get lock to ref.
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ //
+ // If a loopback packet, use the first binding as place holder
+ //
+ if (NIC_FROM_LOCAL_TARGET(LocalTarget) == (USHORT)LOOPBACK_NIC_ID) {
+ Binding = NIC_ID_TO_BINDING(Device, 1);
+ IsLoopback = TRUE;
+ } else {
+ Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget));
+ }
+
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (LocalTarget->NicId == 0) {
+ Binding = Device->Bindings[1];
+ IsLoopback = TRUE;
+ } else {
+ Binding = Device->Bindings[LocalTarget->NicId];
+ }
+#endif _PNP_POWER
+ if (Parameters->SendLength > Binding->RealMaxDatagramSize) {
+
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ Parameters->SendLength,
+ Binding->RealMaxDatagramSize));
+
+ REQUEST_INFORMATION(Request) = 0;
+ Status = STATUS_INVALID_BUFFER_SIZE;
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysOutMalformedRequests);
+#endif SNMP
+ goto error_send_with_packet;
+ }
+
+#if 0
+ //
+ // This shouldn't be needed because even WAN bindings
+ // don't go away once they are added.
+ //
+
+ if (Binding == NULL) {
+ Status = STATUS_DEVICE_DOES_NOT_EXIST;
+ goto error_send_with_packet;
+ }
+#endif
+
+ if (RemoteAddress->NodeAddress[0] == 0xff) {
+ // BUGBUG: What about multicast?
+ if ((*(UNALIGNED ULONG *)(RemoteAddress->NodeAddress) != 0xffffffff) ||
+ (*(UNALIGNED USHORT *)(RemoteAddress->NodeAddress+4) != 0xffff)) {
+ Reserved->DestinationType = DESTINATION_MCAST;
+ } else {
+ Reserved->DestinationType = DESTINATION_BCAST;
+ }
+// IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->BcMcHeaderSize];
+ } else {
+ Reserved->DestinationType = DESTINATION_DEF; // directed send
+// IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->DefHeaderSize];
+ }
+ IpxHeader = (PIPX_HEADER)&Reserved->Header[MAC_HEADER_SIZE];
+
+ }
+
+
+ ++Device->TempDatagramsSent;
+ Device->TempDatagramBytesSent += Parameters->SendLength;
+
+
+#if BACK_FILL
+
+ if (Reserved->BackFill) {
+ Reserved->MappedSystemVa = Reserved->HeaderBuffer->MappedSystemVa;
+ IpxHeader = (PIPX_HEADER)((PCHAR)Reserved->HeaderBuffer->MappedSystemVa - sizeof(IPX_HEADER));
+ Reserved->HeaderBuffer->ByteOffset -= sizeof(IPX_HEADER);
+ (ULONG)Reserved->HeaderBuffer->MappedSystemVa-= sizeof(IPX_HEADER);
+ IPX_DEBUG(SEND, ("Adjusting backfill userMdl Ipxheader %x %x \n",Reserved->HeaderBuffer,IpxHeader));
+ }
+#endif
+
+ //
+ // In case the packet is being sent to a SAP socket or
+ // we have multiple cards and a zero virtual net or
+ // it is a special send (on a nic), we need to use
+ // the binding's address instead of the virtual address.
+ //
+ if (Device->MultiCardZeroVirtual ||
+ (Address->LocalAddress.Socket == SAP_SOCKET) ||
+ (RemoteAddress->Socket == SAP_SOCKET) ||
+ (REQUEST_SPECIAL_SEND(Request))) {
+
+ //
+ // SAP frames need to look like they come from the
+ // local network, not the virtual one. The same is
+ // true if we are running multiple nets without
+ // a virtual network number.
+ //
+ // If this is a binding set member and a local target
+ // was provided we will send using the real node of
+ // the binding, even if it was a slave. This is
+ // intentional. If no local target was provided then
+ // this will not be a binding slave.
+ //
+
+ IpxConstructHeader(
+ (PUCHAR)IpxHeader,
+ LengthIncludingHeader,
+ PacketType,
+ RemoteAddress,
+ &Binding->LocalAddress);
+
+ IpxHeader->SourceSocket = Address->SendSourceSocket;
+
+ } else {
+
+ IpxConstructHeader(
+ (PUCHAR)IpxHeader,
+ LengthIncludingHeader,
+ PacketType,
+ RemoteAddress,
+ &Address->LocalAddress);
+
+ }
+
+
+ //
+ // Fill in the MAC header and submit the frame to NDIS.
+ //
+
+// #if DBG
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+// #endif
+ //
+ // Adjust the 2nd mdl's size
+ //
+#if BACK_FILL
+ if (Reserved->BackFill) {
+ NdisAdjustBufferLength(Reserved->HeaderBuffer, (Reserved->HeaderBuffer->ByteCount+sizeof(IPX_HEADER)));
+ } else {
+ NdisAdjustBufferLength(NDIS_BUFFER_LINKAGE(IPX_PACKET_HEAD(Packet)), sizeof(IPX_HEADER));
+ }
+#else
+ NdisAdjustBufferLength(NDIS_BUFFER_LINKAGE(IPX_PACKET_HEAD(Packet)), sizeof(IPX_HEADER));
+#endif
+
+ IPX_DEBUG(SEND, ("Packet Head %x\n",IPX_PACKET_HEAD(Packet)));
+
+ /*
+ if (Address->RtAdd)
+ {
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)(pRtInfo);
+ }
+ */
+
+ //
+ // [FW] If Forwarder installed, send the packet out for filtering
+ //
+ // STEFAN: 3/28/96:
+ // Dont filter IPXWAN config packets since the FWD does not have this adapter opened yet.
+ //
+
+ IPX_DEBUG(SEND, ("LocalAddress.Socket %x, IPXWAN_SOCKET\n", Address->LocalAddress.Socket, IPXWAN_SOCKET));
+ if (Address->LocalAddress.Socket != IPXWAN_SOCKET &&
+ Device->ForwarderBound) {
+
+ //
+ // Call the InternalSend to filter the packet and get to know
+ // the correct adapter context
+ //
+
+ NTSTATUS ret;
+ ULONG FwdAdapterCtx = INVALID_CONTEXT_VALUE;
+ PUCHAR Data;
+ UINT DataLength;
+
+ if (GET_VALUE(Binding->ReferenceCount) == 2) {
+ FwdAdapterCtx = Binding->FwdAdapterContext;
+ }
+
+ //
+ // Figure out the location of the data in the packet
+ // For BackFill packets, the data is in the first (and only) MDL.
+ // For others, it is in the third MDL.
+ //
+#if BACK_FILL
+ if (Reserved->BackFill) {
+ Data = (PUCHAR)(IpxHeader+sizeof(IPX_HEADER));
+ } else {
+ NdisQueryBuffer(NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)), &Data, &DataLength);
+ }
+#else
+ NdisQueryBuffer(NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)), &Data, &DataLength);
+#endif
+
+ ret = (*Device->UpperDrivers[IDENTIFIER_RIP].InternalSendHandler)(
+ LocalTarget,
+ FwdAdapterCtx,
+ Packet,
+ (PUCHAR)IpxHeader,
+ Data,
+ LengthIncludingHeader,
+ FALSE);
+
+ if (ret == STATUS_SUCCESS) {
+ //
+ // The adapter could have gone away and we have indicated to the Forwarder
+ // but the Forwarder has not yet closed the adapter.
+ //
+ // BUGBUG: what if the binding is NULL here? Can we trust the Forwarder to
+ // give us a non-NULL binding?
+ //
+
+ Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget));
+
+ if (GET_VALUE(Binding->ReferenceCount) == 1) {
+ Status = NDIS_STATUS_SUCCESS;
+// #if DBG
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+// #endif
+ goto error_send_with_packet;
+ } else {
+ IsLoopback = (NIC_FROM_LOCAL_TARGET(LocalTarget) == (USHORT)LOOPBACK_NIC_ID);
+ goto send_packet;
+ }
+ } else if (ret == STATUS_PENDING) {
+ //
+ // LocalTarget will get filled up in InternalSendComplete
+ //
+
+ //
+ // BUGBUG: this is a NULL macro - include this?
+ //
+ IPX_END_SYNC (&SyncContext);
+
+ return STATUS_PENDING;
+ } else if (ret == STATUS_DROP_SILENTLY) {
+ IPX_DEBUG(SEND, ("IPX: SendFramePreFwd: FWD returned STATUS_DROP_SILENTLY - dropping pkt.\n"));
+ Status = NDIS_STATUS_SUCCESS;
+
+// #if DBG
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+// #endif
+ goto error_send_with_packet;
+ }
+
+ //
+ // else DISCARD
+ //
+
+// #if DBG
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+// #endif
+ Status = STATUS_NETWORK_UNREACHABLE;
+ goto error_send_with_packet;
+
+ } else {
+
+ //
+ // [FW] Jump here if the Forwarder gave us the go ahead on this send.
+ // We also come here to send if the Forwarder is not installed.
+ //
+
+send_packet:
+ if (IsLoopback) {
+ //
+ // Enque this packet to the LoopbackQueue on the binding.
+ // If the LoopbackRtn is not already scheduled, schedule it.
+ //
+
+ IPX_DEBUG(LOOPB, ("Packet: %lx, Addr: %lx, Addr->SendPacket: %lx\n", Packet, Address, Address->SendPacket));
+
+ //
+ // Recalculate packet counts here.
+ //
+ // NdisAdjustBufferLength (Reserved->HeaderBuffer, 17);
+#if BACK_FILL
+
+ if (Reserved->BackFill) {
+ //
+ // Set the Header pointer and chain the first MDL
+ //
+ Reserved->Header = (PCHAR)Reserved->HeaderBuffer->MappedSystemVa;
+ NdisChainBufferAtFront(Packet,(PNDIS_BUFFER)Reserved->HeaderBuffer);
+ }
+#endif
+ NdisRecalculatePacketCounts (Packet);
+#ifdef _PNP_POWER
+ IpxLoopbackEnque(Packet, NIC_ID_TO_BINDING(Device, 1)->Adapter);
+#else
+ IpxLoopbackEnque(Packet, Device->Bindings[1]->Adapter);
+#endif
+
+ } else {
+ if ((NdisStatus = (*Binding->SendFrameHandler)(
+ Binding->Adapter,
+ LocalTarget,
+ Packet,
+ Parameters->SendLength + sizeof(IPX_HEADER),
+ sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ IpxSendComplete(
+ (NDIS_HANDLE)Binding->Adapter,
+ Packet,
+ NdisStatus);
+ }
+ }
+
+ IPX_END_SYNC (&SyncContext);
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ return STATUS_PENDING;
+ }
+
+ } else {
+
+ //
+ // The address file state was closing.
+ //
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INVALID_HANDLE;
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysOutDiscards);
+#endif SNMP
+ goto error_send_no_packet;
+
+ }
+
+ } else {
+
+ //
+ // The address file didn't look like one.
+ //
+
+ Status = STATUS_INVALID_HANDLE;
+#ifdef SNMP
+ ++IPX_MIB_ENTRY(Device, SysOutDiscards);
+#endif SNMP
+ goto error_send_no_packet;
+ }
+
+ //
+ // Jump here if we want to fail the send and we have already
+ // allocated the packet and ref'ed the address file.
+ //
+
+error_send_with_packet:
+
+#if BACK_FILL
+ //
+ // Check if this is backfilled. If so, set the headerbuffer to NULL. Note that we dont need
+ // restore to restore the user's MDL since it was never touched when this error occurred.
+ // Also, push the packet on to backfillpacket queue if the packet is not owned by the address
+ //
+ if (Reserved->BackFill) {
+
+ Reserved->HeaderBuffer = NULL;
+
+ if (Reserved->OwnedByAddress) {
+ // Reserved->Address->BackFillPacketInUse = FALSE;
+ InterlockedDecrement(&Reserved->Address->BackFillPacketInUse);
+
+ IPX_DEBUG(SEND, ("Freeing owned backfill %x\n", Reserved));
+ } else {
+ IPX_PUSH_ENTRY_LIST(
+ &Device->BackFillPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+ }
+ } else {
+ // not a back fill packet. Push it on sendpacket pool
+ if (Reserved->OwnedByAddress) {
+ // Reserved->Address->SendPacketInUse = FALSE;
+ InterlockedDecrement(&Reserved->Address->SendPacketInUse);
+
+ } else {
+ IPX_PUSH_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+
+ }
+ }
+#else
+ if (Reserved->OwnedByAddress) {
+ Reserved->Address->SendPacketInUse = FALSE;
+ } else {
+ IPX_PUSH_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+ }
+#endif
+
+ IpxDereferenceAddressFileSync (AddressFile, AFREF_SEND_DGRAM);
+
+error_send_no_packet:
+
+ //
+ // Jump here if we fail before doing any of that.
+ //
+
+ IPX_END_SYNC (&SyncContext);
+
+ irpSp = IoGetCurrentIrpStackLocation( Request );
+ if ( irpSp->MinorFunction == TDI_DIRECT_SEND_DATAGRAM ) {
+
+ REQUEST_STATUS(Request) = Status;
+ Request->CurrentLocation++,
+ Request->Tail.Overlay.CurrentStackLocation++;
+
+ (VOID) irpSp->CompletionRoutine(
+ NULL,
+ Request,
+ irpSp->Context
+ );
+
+ IpxFreeRequest (DeviceObject, Request);
+ }
+
+ return Status;
+
+} /* IpxTdiSendDatagram */
+
+
+#if DBG
+VOID
+IpxConstructHeader(
+ IN PUCHAR Header,
+ IN USHORT PacketLength,
+ IN UCHAR PacketType,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PTDI_ADDRESS_IPX LocalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an IPX header in a packet.
+
+Arguments:
+
+ Header - The location at which the header should be built.
+
+ PacketLength - The length of the packet, including the IPX header.
+
+ PacketType - The packet type of the frame.
+
+ RemoteAddress - The remote IPX address.
+
+ LocalAddress - The local IPX address.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PIPX_HEADER IpxHeader = (PIPX_HEADER)Header;
+
+ IpxHeader->CheckSum = 0xffff;
+ IpxHeader->PacketLength[0] = (UCHAR)(PacketLength / 256);
+ IpxHeader->PacketLength[1] = (UCHAR)(PacketLength % 256);
+ IpxHeader->TransportControl = 0;
+ IpxHeader->PacketType = PacketType;
+
+ //
+ // These copies depend on the fact that the destination
+ // network is the first field in the 12-byte address.
+ //
+
+ RtlCopyMemory(IpxHeader->DestinationNetwork, (PVOID)RemoteAddress, 12);
+ RtlCopyMemory(IpxHeader->SourceNetwork, LocalAddress, 12);
+
+} /* IpxConstructHeader */
+#endif
+
+
+
+//
+// [FW]
+//
+
+VOID
+IpxInternalSendComplete(
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN NTSTATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by the Kernel Forwarder to indicate that a pending
+ internal send to it has completed.
+
+Arguments:
+
+ LocalTarget - if Status is OK, this has the local target for the send.
+
+ Packet - A pointer to the NDIS_PACKET that we sent.
+
+ PacketLength - length of the packet (including the IPX header)
+
+ BUGBUG: Can IpxSendFrame use the local var. PktLength instead? What about IpxSendFrameXXX (frame specific)
+
+ Status - the completion status of the send - STATUS_SUCCESS or STATUS_NETWORK_UNREACHABLE
+
+Return Value:
+
+ none.
+
+--*/
+{
+ PDEVICE Device=IpxDevice;
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PBINDING Binding;
+ NDIS_STATUS NdisStatus;
+ PIO_STACK_LOCATION irpSp;
+ PREQUEST Request;
+ PADDRESS_FILE AddressFile;
+
+ switch (Reserved->Identifier)
+ {
+ case IDENTIFIER_IPX:
+
+ //
+ // datagrams can be sent to the frame-specific handlers directly
+ //
+ // BUGBUG: Make this change in SendComplete too
+ //
+
+ if ((Status == STATUS_SUCCESS) &&
+ (Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget))) &&
+ (GET_VALUE(Binding->ReferenceCount) == 2)) {
+
+ if (NIC_FROM_LOCAL_TARGET(LocalTarget) == (USHORT)LOOPBACK_NIC_ID) {
+
+ //
+ // Enque this packet to the LoopbackQueue on the binding.
+ // If the LoopbackRtn is not already scheduled, schedule it.
+ //
+
+ IPX_DEBUG(LOOPB, ("Packet: %lx \n", Packet));
+
+ //
+ // Recalculate packet counts here.
+ //
+ // NdisAdjustBufferLength (Reserved->HeaderBuffer, 17);
+#if BACK_FILL
+
+ if (Reserved->BackFill) {
+ //
+ // Set the Header pointer and chain the first MDL
+ //
+ Reserved->Header = (PCHAR)Reserved->HeaderBuffer->MappedSystemVa;
+ NdisChainBufferAtFront(Packet,(PNDIS_BUFFER)Reserved->HeaderBuffer);
+ }
+#endif
+ NdisRecalculatePacketCounts (Packet);
+#ifdef _PNP_POWER
+ IpxLoopbackEnque(Packet, NIC_ID_TO_BINDING(Device, 1)->Adapter);
+#else
+ IpxLoopbackEnque(Packet, Device->Bindings[1]->Adapter);
+#endif
+
+ } else {
+ if ((NdisStatus = (*Binding->SendFrameHandler)(
+ Binding->Adapter,
+ LocalTarget,
+ Packet,
+ PacketLength,
+ sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+ //
+ // Call SendComplete here so it can send broadcasts over other
+ // Nic's and remove any padding if used.
+ //
+
+ IpxSendComplete((NDIS_HANDLE)Binding->Adapter,
+ Packet,
+ NdisStatus);
+ }
+ }
+ } else {
+ //
+ // DISCARD was returned - complete the IRP
+ //
+ NdisStatus = STATUS_NETWORK_UNREACHABLE;
+
+
+ //
+ // We need to free the packet and deref the addressfile...
+ //
+
+ // #if DBG
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+ // #endif
+
+ if (Reserved->OwnedByAddress) {
+ Reserved->Address->SendPacketInUse = FALSE;
+ } else {
+ IPX_PUSH_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &Device->Lock);
+ }
+
+ AddressFile = Reserved->u.SR_DG.AddressFile;
+ IpxDereferenceAddressFileSync (AddressFile, AFREF_SEND_DGRAM);
+
+ Request = Reserved->u.SR_DG.Request;
+ REQUEST_STATUS(Request) = NdisStatus;
+ irpSp = IoGetCurrentIrpStackLocation( Request );
+
+ //
+ // If this is a fast send irp, we bypass the file system and
+ // call the completion routine directly.
+ //
+
+ if ( irpSp->MinorFunction == TDI_DIRECT_SEND_DATAGRAM ) {
+ Request->CurrentLocation++,
+ Request->Tail.Overlay.CurrentStackLocation++;
+
+ (VOID) irpSp->CompletionRoutine(
+ NULL,
+ Request,
+ irpSp->Context
+ );
+
+ } else {
+ IpxCompleteRequest (Request);
+ }
+ IpxFreeRequest(Device, Request);
+ }
+
+ break;
+
+ default:
+ //
+ // for all other packet types
+ //
+
+ if ((Status == STATUS_SUCCESS) &&
+ (Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget))) &&
+ (GET_VALUE(Binding->ReferenceCount) == 2)) {
+ //
+ // BUGBUG: IncludedHeaderLength is only used to check for RIP packets (==0)
+ // so IPX_HEADER size is OK. Should finally remove this parameter.
+ //
+
+ if (NIC_FROM_LOCAL_TARGET(LocalTarget) == (USHORT)LOOPBACK_NIC_ID) {
+
+ //
+ // Enque this packet to the LoopbackQueue on the binding.
+ // If the LoopbackRtn is not already scheduled, schedule it.
+ //
+
+ IPX_DEBUG(LOOPB, ("Packet: %lx\n", Packet));
+
+ //
+ // Recalculate packet counts here.
+ //
+ // NdisAdjustBufferLength (Reserved->HeaderBuffer, 17);
+#if BACK_FILL
+
+ if (Reserved->BackFill) {
+ //
+ // Set the Header pointer and chain the first MDL
+ //
+ Reserved->Header = (PCHAR)Reserved->HeaderBuffer->MappedSystemVa;
+ NdisChainBufferAtFront(Packet,(PNDIS_BUFFER)Reserved->HeaderBuffer);
+ }
+#endif
+ NdisRecalculatePacketCounts (Packet);
+#ifdef _PNP_POWER
+ IpxLoopbackEnque(Packet, NIC_ID_TO_BINDING(Device, 1)->Adapter);
+#else
+ IpxLoopbackEnque(Packet, Device->Bindings[1]->Adapter);
+#endif
+
+ } else {
+ NdisStatus = IpxSendFrame(LocalTarget, Packet, PacketLength, sizeof(IPX_HEADER));
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+ IPX_DEBUG (SEND, ("IpxSendFrame status %lx on NICid %lx, packet %lx \n",
+ NdisStatus, LocalTarget->NicId, Packet));
+ goto error_complete;
+ }
+ }
+ } else {
+ //
+ // DISCARD was returned - call the upper driver's sendcomplete with error
+ //
+
+ //
+ // Else return STATUS_NETWORK_UNREACHABLE
+ //
+
+ NdisStatus = STATUS_NETWORK_UNREACHABLE;
+
+ error_complete:
+
+ IPX_DEBUG (SEND, ("Calling the SendCompleteHandler of tightly bound driver with status: %lx\n", NdisStatus));
+ (*Device->UpperDrivers[Reserved->Identifier].SendCompleteHandler)(
+ Packet,
+ NdisStatus);
+ }
+ }
+}
+
+
diff --git a/private/ntos/tdi/isn/ipx/sources.inc b/private/ntos/tdi/isn/ipx/sources.inc
new file mode 100644
index 000000000..9e78c5493
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/sources.inc
@@ -0,0 +1,75 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=nwlnkipx
+
+TARGETNAME=nwlnkipx
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\tdi.lib \
+ $(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..;..\..\inc;..\..\..\..\inc;..\..\..\..\..\inc
+
+NTPROFILEINPUT=yes
+
+
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+C_DEFINES=$(C_DEFINES) -D_NTDRIVER_ -DBACK_FILL=1 -DNDIS40=1 -D_PNP_POWER=1
+
+!IFDEF BUILD_FOR_3_51
+C_DEFINES=$(C_DEFINES) -D_NTIFS_
+!ENDIF
+
+SOURCES= \
+ ..\action.c \
+ ..\adapter.c \
+ ..\address.c \
+ ..\config.c \
+ ..\device.c \
+ ..\driver.c \
+ ..\event.c \
+ ..\ind.c \
+ ..\internal.c \
+ ..\nwlnkipx.rc \
+ ..\mac.c \
+ ..\ndis.c \
+ ..\packet.c \
+ ..\query.c \
+ ..\receive.c \
+ ..\rip.c \
+ ..\send.c \
+ ..\loopback.c \
+ ..\rt.c
+
+PRECOMPILED_INCLUDE=..\precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
+
+SOURCES_USED=..\sources.inc
+
+
diff --git a/private/ntos/tdi/isn/ipx/up/makefile b/private/ntos/tdi/isn/ipx/up/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/up/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isn/ipx/up/nwlnkipx.prf b/private/ntos/tdi/isn/ipx/up/nwlnkipx.prf
new file mode 100644
index 000000000..0c4359235
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/up/nwlnkipx.prf
@@ -0,0 +1,89 @@
+IpxTdiSendDatagram@8
+IpxReceiveIndicationNew@36
+IpxSendFrame@16
+IpxReceiveComplete@4
+IpxSendFrame802_3802_2@20
+IpxReceivePacket@8
+IpxDerefAddressSync@4
+IpxSendComplete@12
+IpxSendFramePreFwd@16
+IpxReceiveIndication@28
+IpxInitializeBackFillPacket@12
+IpxpAllocateMemory@12
+IpxPopBackFillPacket@4
+IpxAllocateBackFillPool@4
+RipLongTimeout@8
+CTEStartTimer@16
+TdiCopyBufferToMdl@24
+IpxTdiQueryInformation@8
+IpxVerifyAddressFile@4
+IpxDispatchInternal@8
+IpxTransferData@28
+IpxInitLoopback@0
+RipGetFirstRoute@4
+IpxCreateAddress@8
+MacReturnMaxDataSize@20
+IpxLookupAddress@8
+IpxAbortLineChanges@4
+MacMapFrameType@12
+IpxInitializeReceiveBuffer@16
+IpxDispatchOpenClose@8
+IpxTdiSetEventHandler@4
+IpxCreateAddressFile@4
+IpxInternalBind@8
+IpxInitializeReceivePacket@8
+IpxIsAddressLocal@4
+IpxOpenAddress@8
+IpxAllocateReceiveBufferPool@4
+IpxSubmitNdisRequest@12
+IpxAddBroadcast@4
+IpxDestroyBinding@4
+RipAdjustForBindingChange@12
+IpxDispatchDeviceControl@8
+IpxAllocatePaddingBuffer@4
+TdiMapUserRequest@12
+CTEInitialize@0
+IpxInitializeSendPacket@12
+IpxpFreeMemory@12
+IpxInitializePaddingBuffer@12
+IpxAllocateSendPool@4
+RipCleanupPacket@8
+TdiRegisterDeviceObject@8
+TdiRegisterNetAddress@8
+IpxTdiAction@8
+IpxCreateBinding@20
+IpxDerefDevice@4
+MacInitializeBindingInfo@8
+IpxRegisterProtocol@4
+IpxInitializeNdis@8
+IpxGetConfigValue@24
+IpxCreateAdapter@12
+IpxResolveBindingSets@8
+IpxGetFrameType@24
+MacInitializeMacInfo@8
+IpxGetBindingValue@24
+RipQueueRequest@8
+RipShortTimeout@8
+IpxPopSendPacket@4
+IpxAllocateBindingPool@4
+IpxInternalQuery@20
+CTEInitTimer@4
+IpxRequestComplete@12
+IpxBroadcastOperation@4
+CTEInitEvent@8
+IpxPnPGetVirtualNetworkNumber@4
+IpxPnPGetAdapterParameters@12
+IpxOpenAdapterComplete@12
+IpxResolveAutoDetect@16
+IpxBindToAdapter@16
+TdiInitialize@0
+IpxPnPIsnIndicate@4
+IpxPnPUpdateBindingArray@12
+IpxBindAdapter@20
+IpxPnPUpdateDevice@4
+IpxGetConfiguration@12
+IpxAddExport@24
+IpxCreateDevice@16
+DriverEntry@8
+IpxReadLinkageInformation@4
+IpxFreeConfiguration@4
diff --git a/private/ntos/tdi/isn/ipx/up/sources b/private/ntos/tdi/isn/ipx/up/sources
new file mode 100644
index 000000000..85cdb3764
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/up/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+UP_DRIVER=yes
+
+TARGETPATH=obj
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/isn/ipxroute/ipxroute.c b/private/ntos/tdi/isn/ipxroute/ipxroute.c
new file mode 100644
index 000000000..d4e327f12
--- /dev/null
+++ b/private/ntos/tdi/isn/ipxroute/ipxroute.c
@@ -0,0 +1,1822 @@
+/****************************************************************************
+* (c) Copyright 1990, 1993 Micro Computer Systems, Inc. All rights reserved.
+*****************************************************************************
+*
+* Title: IPX/SPX Compatible Source Routing Daemon for Windows NT
+*
+* Module: ipx/route/ipxroute.c
+*
+* Version: 1.00.00
+*
+* Date: 04-08-93
+*
+* Author: Brian Walker
+*
+*****************************************************************************
+*
+* Change Log:
+*
+* Date DevSFC Comment
+* -------- ------ -------------------------------------------------------
+* 02-14-95 RamC Added command line options to support displaying
+* Router Table, Router Statistics and SAP information.
+* Basically a merge of ipxroute and Stefan's rttest.
+*****************************************************************************
+*
+* Functional Description:
+*
+*
+****************************************************************************/
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <process.h>
+#include <ntstapi.h>
+#include <sys/stropts.h>
+#include <windows.h>
+#include "errno.h"
+#include "tdi.h"
+#include "isnkrnl.h"
+#include "ipxrtmsg.h"
+#include "..\rip\driver.h"
+#include "utils.h"
+#include "nwsap.h"
+
+typedef struct _IPX_ROUTE_ENTRY {
+ UCHAR Network[4];
+ USHORT NicId;
+ UCHAR NextRouter[6];
+ PVOID NdisBindingContext;
+ USHORT Flags;
+ USHORT Timer;
+ UINT Segment;
+ USHORT TickCount;
+ USHORT HopCount;
+ PVOID AlternateRoute[2];
+ PVOID NicLinkage[2];
+ struct {
+ PVOID Linkage[2];
+ ULONG Reserved[1];
+ } PRIVATE;
+} IPX_ROUTE_ENTRY, * PIPX_ROUTE_ENTRY;
+
+
+
+
+IPX_ROUTE_ENTRY rte;
+
+/** Global Variables **/
+
+int sr_def = 0;
+int sr_bcast = 0;
+int sr_multi = 0;
+int boardnum = 0;
+int clear = 0;
+int config = 0;
+int showtable = 0;
+int showservers = 0;
+int showstats = 0;
+int clearstats = 0;
+int servertype;
+char nodeaddr[6]; /* Node address to remove */
+HANDLE nwlinkfd;
+HANDLE isnipxfd;
+HANDLE isnripfd;
+char ebuffer[128];
+
+char nwlinkname[] = "\\Device\\Streams\\NWLinkIpx";
+wchar_t isnipxname[] = L"\\Device\\NwlnkIpx";
+wchar_t isnripname[] = L"\\Device\\Ipxroute";
+char pgmname[] = "IPXROUTE";
+#define SHOW_ALL_SERVERS 0XFFFF
+
+/** **/
+
+#define INVALID_HANDLE (HANDLE)(-1)
+
+/** Structure to send REMOVE with **/
+
+typedef struct rterem {
+ int rterem_bnum; /* Board number */
+ char rterem_node[6]; /* Node to remove */
+} rterem;
+
+typedef int (_CRTAPI1 * PQSORT_COMPARE)(const void * p0, const void * p1);
+
+/** Internal Function Prototypes **/
+
+extern void print_table(int);
+extern void usage(void);
+extern void print_version(void);
+extern char *print_type(int);
+extern int my_strncmp(char *, char *, int);
+extern int get_board_num(char *, int *);
+extern int get_node_num(char *, char *);
+extern int get_server_type(char *, int *);
+extern unsigned char get_hex_byte(char *);
+extern int get_driver_parms(void);
+extern int set_driver_parms(void);
+extern int do_strioctl(HANDLE, int, char *, int, int);
+extern void remove_address(char *);
+extern void clear_table(void);
+extern void print_config(void);
+extern unsigned long get_emsg(int);
+int do_isnipxioctl(HANDLE fd, int cmd, char *datap, int dlen);
+unsigned long put_msg(BOOLEAN error, unsigned long MsgNum, ... );
+char *load_msg( unsigned long MsgNum, ... );
+extern void show_router_table(PHANDLE, PIO_STATUS_BLOCK);
+extern void show_stats(HANDLE, PIO_STATUS_BLOCK);
+extern void clear_stats(HANDLE, PIO_STATUS_BLOCK);
+extern void show_servers(int);
+extern int _CRTAPI1 CompareServerNames( void * p0, void * p1);
+extern int _CRTAPI1 CompareNetNumber( void * p0, void * p1);
+
+/*page*************************************************************
+ m a i n
+
+ This is the main routine that gets executed when a NET START
+ happens.
+
+ Arguments - None
+
+ Returns - Nothing
+********************************************************************/
+void _CRTAPI1 main(int argc, char **argv)
+{
+ char *p;
+ int todo;
+ int remove_flag;
+ UNICODE_STRING FileString;
+ OBJECT_ATTRIBUTES ObjectAttributes, RouterObjectAttributes;
+ IO_STATUS_BLOCK IoStatusBlock, RouterIoStatusBlock;
+ NTSTATUS Status;
+
+ /** **/
+
+ print_version();
+
+ /** Open the nwlink driver **/
+
+ nwlinkfd = s_open(nwlinkname, 0, 0);
+
+ /** Open the isnipx driver **/
+
+ RtlInitUnicodeString (&FileString, isnipxname);
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &FileString,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenFile(
+ &isnipxfd,
+ SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT);
+
+ if (!NT_SUCCESS(Status)) {
+ isnipxfd = INVALID_HANDLE;
+ put_msg (TRUE, MSG_OPEN_FAILED, "\\Device\\NwlnkIpx");
+ }
+
+ /** Open the isnrip driver **/
+
+ RtlInitUnicodeString (&FileString, isnripname);
+
+ InitializeObjectAttributes(
+ &RouterObjectAttributes,
+ &FileString,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenFile(
+ &isnripfd,
+ SYNCHRONIZE | GENERIC_READ,
+ &RouterObjectAttributes,
+ &RouterIoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_NONALERT);
+
+ if (!NT_SUCCESS(Status)) {
+ isnripfd = INVALID_HANDLE;
+ // don't display any error message, but display the
+ // message that the IPX router is not started when
+ // the user actually tries to look at the router.
+ }
+
+ if ((nwlinkfd == INVALID_HANDLE) &&
+ (isnipxfd == INVALID_HANDLE) &&
+ (isnripfd == INVALID_HANDLE))
+ {
+ exit(1);
+ }
+
+
+ /** Go thru the command line and set it up **/
+
+ argc--;
+ argv++;
+
+ /** Parse the command line **/
+
+ todo = 0;
+ remove_flag = 0;
+ while (argc--) {
+
+ /** Uppercase the arg **/
+
+ p = *argv;
+ _strupr(p);
+
+ /** Parse the argument **/
+
+ if (!strcmp(p, "CLEAR")) {
+ todo = 1;
+ clear = 1;
+ }
+ else if (!strcmp(p, "DEF")) {
+ todo = 1;
+ sr_def = 1;
+ }
+ else if (!strcmp(p, "GBR")) {
+ todo = 1;
+ sr_bcast = 1;
+ }
+ else if (!strcmp(p, "MBR")) {
+ todo = 1;
+ sr_multi = 1;
+ }
+ else if (!strcmp(p, "CONFIG")) {
+ todo = 1;
+ config = 1;
+ }
+ else if (!my_strncmp(p, "BOARD=", 6))
+ get_board_num(p + 6, &boardnum);
+ else if (!my_strncmp(p, "REMOVE=", 7)) {
+ remove_flag = 1;
+ get_node_num(p + 7, nodeaddr);
+ }
+ else if (!strcmp(p, "TABLE")) {
+ todo = 1;
+ showtable = 1;
+ }
+ else if (!strcmp(p, "SERVERS")) {
+ todo = 1;
+ showservers = 1;
+ /** default is to show all server types **/
+ servertype = SHOW_ALL_SERVERS;
+ argv++;
+ if(argc--) {
+ p = *argv;
+ _strupr(p);
+ if (!my_strncmp(p, "/TYPE=", 6)) {
+ get_server_type(p + 6, &servertype);
+ }
+ else
+ usage();
+ }
+ /** no more arguments - break out of while lop **/
+ else
+ break;
+ }
+ else if (!strcmp(p, "STATS")) {
+ todo = 1;
+ /** default is to show the router statistics **/
+ showstats = 1;
+ argv++;
+ if(argc--) {
+ p = *argv;
+ _strupr(p);
+ if (!strcmp(p, "/CLEAR")) {
+ clearstats = 1;
+ showstats = 0;
+ }
+ else if (!strcmp(p, "/SHOW")) {
+ showstats = 1;
+ }
+ else
+ usage;
+ }
+ /** no more arguments - break out of while lop **/
+ else
+ break;
+ }
+ else
+ usage();
+
+ /** Goto the next entry **/
+
+ argv++;
+ }
+
+ /** Go update the driver **/
+
+#if 0
+ printf("todo = %d\n", todo);
+ printf("remove_flag= %d\n", remove_flag);
+ printf("Clear flag = %d\n", clear);
+ printf("Config flag = %d\n", config);
+ printf("SR_DEF = %d\n", sr_def);
+ printf("SR_BCAST = %d\n", sr_bcast);
+ printf("SR_MULTI = %d\n", sr_multi);
+ printf("Board = %d\n", boardnum);
+ printf("Node = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ (unsigned char)nodeaddr[0],
+ (unsigned char)nodeaddr[1],
+ (unsigned char)nodeaddr[2],
+ (unsigned char)nodeaddr[3],
+ (unsigned char)nodeaddr[4],
+ (unsigned char)nodeaddr[5]);
+#endif
+
+ /** If we have a remove - go remove it and leave **/
+
+ if (remove_flag)
+ remove_address(nodeaddr); /* Does not return */
+
+ /** If clear - go clear the source routing table **/
+
+ if (clear)
+ clear_table(); /* Does not return */
+
+ /** If config - print out config **/
+
+ if (config)
+ print_config(); /* Does not return */
+
+ /** If showtable - print out routing table **/
+
+ if (showtable)
+ show_router_table(&isnripfd, &RouterIoStatusBlock); /* Does not return */
+
+ /** If showservers - print out selected servers list **/
+
+ if (showservers)
+ show_servers(servertype); /* Does not return */
+
+ /** If showstats - print out statistics **/
+
+ if (showstats)
+ show_stats(&isnripfd, &RouterIoStatusBlock); /* Does not return */
+
+ /** If clearstats - go clear statistics **/
+
+ if (clearstats)
+ clear_stats(&isnripfd, &RouterIoStatusBlock); /* Does not return */
+
+ /** If there is nothing to do - just print out everything **/
+
+ if (!todo) {
+
+ /** Get the driver parms **/
+
+ if (get_driver_parms()) {
+ if (isnipxfd != INVALID_HANDLE) NtClose(isnipxfd);
+ if (nwlinkfd != INVALID_HANDLE) NtClose(nwlinkfd);
+ if (isnripfd != INVALID_HANDLE) NtClose(isnripfd);
+ exit(1);
+ }
+
+ /** Print out the table (Never comes back) **/
+
+ print_table(1);
+ }
+
+ /** Go set the parameters **/
+
+ set_driver_parms();
+
+ /** Print the table out **/
+
+ print_table(0);
+
+ /** All Done **/
+
+ if (isnipxfd != INVALID_HANDLE) NtClose(isnipxfd);
+ if (nwlinkfd != INVALID_HANDLE) NtClose(nwlinkfd);
+ if (isnripfd != INVALID_HANDLE) NtClose(isnripfd);
+ exit(0);
+}
+
+/*page*************************************************************
+ p r i n t _ t a b l e
+
+ Print out the status of the source routing.
+
+ Arguments - flag = 0 - Do NOT print the table
+ 1 - Do print the table (Never returns)
+
+ Returns - Nothing
+********************************************************************/
+void print_table(int flag)
+{
+ /** Print the information **/
+
+ char * ptype;
+
+ printf("\n");
+ ptype = print_type(sr_def);
+ put_msg (FALSE, MSG_DEFAULT_NODE, ptype);
+ LocalFree (ptype);
+ printf("\n");
+
+ ptype = print_type(sr_bcast);
+ put_msg (FALSE, MSG_BROADCAST, ptype);
+ LocalFree (ptype);
+ printf("\n");
+
+ ptype = print_type(sr_multi);
+ put_msg (FALSE, MSG_MULTICAST, ptype);
+ LocalFree (ptype);
+ printf("\n");
+
+ if (!flag)
+ return;
+
+#if 0
+ printf("\n");
+ printf(" Node Address Source Route\n");
+ printf("\n");
+#endif
+
+ /** All Done **/
+
+ if (isnipxfd != INVALID_HANDLE) NtClose(isnipxfd);
+ if (nwlinkfd != INVALID_HANDLE) NtClose(nwlinkfd);
+ if (isnripfd != INVALID_HANDLE) NtClose(isnripfd);
+ exit(0);
+}
+
+/*page*************************************************************
+ u s a g e
+
+ Print the usage message.
+
+ Arguments - None
+
+ Returns - Nothing
+********************************************************************/
+void usage(void)
+{
+ put_msg( FALSE, MSG_USAGE, pgmname );
+
+ /** All Done **/
+
+ if (isnipxfd != INVALID_HANDLE) NtClose(isnipxfd);
+ if (nwlinkfd != INVALID_HANDLE) NtClose(nwlinkfd);
+ if (isnripfd != INVALID_HANDLE) NtClose(isnripfd);
+ exit(0);
+}
+
+/*page*************************************************************
+ p r i n t _ v e r s i o n
+
+ Print the version number
+
+ Arguments - None
+
+ Returns - Nothing
+********************************************************************/
+void print_version(void)
+{
+ printf("\n");
+ put_msg (FALSE, MSG_VERSION);
+ return;
+}
+
+/*page*************************************************************
+ p r i n t _ t y p e
+
+ Returns the broadcast type given in a string, the caller
+ must free the string.
+
+ Arguments - 0 = SINGLE ROUTE
+ Else = ALL ROUTES
+
+ Returns - Nothing
+********************************************************************/
+char *print_type(int flag)
+{
+ if (flag)
+ return load_msg (MSG_ALL_ROUTE);
+ else
+ return load_msg (MSG_SINGLE_ROUTE);
+
+}
+
+/*page*************************************************************
+ m y _ s t r n c m p
+
+ Given a string (p), see if the first len chars are the same
+ as those of the 2nd string (s).
+
+ Arguments - p = Ptr to first string
+ s = Ptr to 2nd string
+ len = Length to check
+
+ Returns - 0 = Matched
+ Else = Not matched
+********************************************************************/
+int my_strncmp(char *p, char *s, int len)
+{
+ /** **/
+
+ while (len--) {
+ if (*p++ != *s++)
+ return 1;
+ }
+
+ /** They matched **/
+
+ return 0;
+}
+
+/*page*************************************************************
+ g e t _ b o a r d _ n u m
+
+ Get the decimal number from the command line
+
+ Arguments - p = Ptr to the ASCII number
+ nump = Store the number here
+
+ Returns - 0 = Got the number OK
+ Else = Bad number
+********************************************************************/
+int get_board_num(char *p, int *nump)
+{
+ *nump = atoi(p);
+ return 0;
+}
+
+/*page*************************************************************
+ g e t _ n o d e _ n u m
+
+ Get a node address from the command line
+
+ Arguments - p = Ptr to the ASCII number
+ nodep = Store the node number here
+
+ Returns - 0 = Got the number OK
+ Else = Bad number
+********************************************************************/
+int get_node_num(char *p, char *nodep)
+{
+ int i;
+ unsigned char c1;
+ unsigned char c2;
+
+ /** **/
+
+ if (strlen(p) != 12) {
+ put_msg (TRUE, MSG_INVALID_REMOVE);
+ exit(1);
+ }
+
+ /** Get the number **/
+
+ for (i = 0 ; i < 6 ; i++) {
+
+ /** Get the next 2 digits **/
+
+ c1 = get_hex_byte(p++);
+ c2 = get_hex_byte(p++);
+
+ /** If we got a bad number - return error **/
+
+ if ((c1 == 0xFF) || (c2 == 0xFF)) {
+ put_msg (TRUE, MSG_INVALID_REMOVE);
+ exit(1);
+ }
+
+ /** Set the next byte **/
+
+ *nodep++ = (c1 << 4) + c2;
+ }
+
+ /** Return OK **/
+
+ return 0;
+}
+
+/*page*************************************************************
+ g e t _ s e r v e r _ t y p e
+
+ Get the decimal number from the command line
+
+ Arguments - p = Ptr to the ASCII number
+ nump = Store the number here
+
+ Returns - 0 = Got the number OK
+ Else = Bad number
+********************************************************************/
+int get_server_type(char *p, int *nump)
+{
+ *nump = atoi(p);
+ return 0;
+}
+
+/*page*************************************************************
+ g e t _ h e x _ b y t e
+
+ Take 1 ascii hex chars and convert to a hex byte
+
+ Arguments - p = Ptr to the ASCII number
+
+ Returns - The number
+ (0xFF = Error)
+********************************************************************/
+unsigned char get_hex_byte(char *p)
+{
+ unsigned char c;
+
+ /** Get the char **/
+
+ c = *(unsigned char *)p;
+
+ /** If 0-9 handle it **/
+
+ if ((c >= '0') && (c <= '9')) {
+ c -= '0';
+ return c;
+ }
+
+ /** If A-F handle it **/
+
+ if ((c >= 'A') && (c <= 'F')) {
+ c -= ('A' - 10);
+ return c;
+ }
+
+ /** This is a bad number **/
+
+ return 0xFF;
+}
+
+
+/*page***************************************************************
+ g e t _ d r i v e r _ p a r m s
+
+ Get the parameters from the driver
+
+ Arguments - None
+
+ Returns - 0 = OK
+ else = Error
+********************************************************************/
+int get_driver_parms()
+{
+ int rc;
+ int buffer[4];
+
+ /** Set the board number **/
+
+ buffer[0] = boardnum;
+
+ /** Get the parms **/
+
+ if (nwlinkfd != INVALID_HANDLE) {
+ rc = do_strioctl(nwlinkfd, MIPX_SRGETPARMS, (char *)buffer, 4*sizeof(int), 0);
+ if (rc) {
+
+ /** Get the error code **/
+
+ rc = GetLastError();
+ put_msg (TRUE, MSG_BAD_PARAMETERS, "nwlink");
+ put_msg (TRUE, get_emsg(rc));
+
+ /** Return the error **/
+
+ return rc;
+ }
+ }
+
+ if (isnipxfd != INVALID_HANDLE) {
+ rc = do_isnipxioctl(isnipxfd, MIPX_SRGETPARMS, (char *)buffer, 4*sizeof(int));
+ if (rc) {
+
+ put_msg (TRUE, MSG_BAD_PARAMETERS, "nwlnkipx");
+ put_msg (TRUE, get_emsg(rc));
+
+ /** Return the error **/
+
+ return rc;
+ }
+ }
+
+ /** Get the variables **/
+
+ sr_def = buffer[1];
+ sr_bcast = buffer[2];
+ sr_multi = buffer[3];
+
+ /** Return OK **/
+
+ return 0;
+}
+
+/*page***************************************************************
+ s e t _ d r i v e r _ p a r m s
+
+ Set the parameters for the driver
+
+ Arguments - None
+
+ Returns - 0 = OK
+ else = Error
+********************************************************************/
+int set_driver_parms()
+{
+ int rc;
+ int buffer[2];
+
+ /** Set the DEFAULT parm **/
+
+ buffer[0] = boardnum;
+ buffer[1] = sr_def;
+
+ if (nwlinkfd != INVALID_HANDLE) {
+ rc = do_strioctl(nwlinkfd, MIPX_SRDEF, (char *)buffer, 2 * sizeof(int), 0);
+ if (rc) {
+ rc = GetLastError();
+ put_msg (TRUE, MSG_SET_DEFAULT_ERROR, "nwlink");
+ put_msg (TRUE, get_emsg(rc));
+ return rc;
+ }
+ }
+ if (isnipxfd != INVALID_HANDLE) {
+ rc = do_isnipxioctl(isnipxfd, MIPX_SRDEF, (char *)buffer, 2 * sizeof(int));
+ if (rc) {
+ put_msg (TRUE, MSG_SET_DEFAULT_ERROR, "nwlnkipx");
+ put_msg (TRUE, get_emsg(rc));
+ return rc;
+ }
+ }
+
+ /** Set the BROADCAST parm **/
+
+ buffer[0] = boardnum;
+ buffer[1] = sr_bcast;
+
+ if (nwlinkfd != INVALID_HANDLE) {
+ rc = do_strioctl(nwlinkfd, MIPX_SRBCAST, (char *)buffer, 2 * sizeof(int), 0);
+ if (rc) {
+ rc = GetLastError();
+ put_msg (TRUE, MSG_SET_BROADCAST_ERROR, "nwlink");
+ put_msg (TRUE, get_emsg(rc));
+ return rc;
+ }
+ }
+ if (isnipxfd != INVALID_HANDLE) {
+ rc = do_isnipxioctl(isnipxfd, MIPX_SRBCAST, (char *)buffer, 2 * sizeof(int));
+ if (rc) {
+ put_msg (TRUE, MSG_SET_BROADCAST_ERROR, "nwlnkipx");
+ put_msg (TRUE, get_emsg(rc));
+ return rc;
+ }
+ }
+
+ /** Set the MULTICAST parm **/
+
+ buffer[0] = boardnum;
+ buffer[1] = sr_multi;
+
+ if (nwlinkfd != INVALID_HANDLE) {
+ rc = do_strioctl(nwlinkfd, MIPX_SRMULTI, (char *)buffer, 2 * sizeof(int), 0);
+ if (rc) {
+ rc = GetLastError();
+ put_msg (TRUE, MSG_SET_MULTICAST_ERROR, "nwlink");
+ put_msg (TRUE, get_emsg(rc));
+ return rc;
+ }
+ }
+ if (isnipxfd != INVALID_HANDLE) {
+ rc = do_isnipxioctl(isnipxfd, MIPX_SRMULTI, (char *)buffer, 2 * sizeof(int));
+ if (rc) {
+ put_msg (TRUE, MSG_SET_MULTICAST_ERROR, "nwlnkipx");
+ put_msg (TRUE, get_emsg(rc));
+ return rc;
+ }
+ }
+
+ /** Return OK **/
+
+ return 0;
+}
+
+/*page***************************************************************
+ d o _ s t r i o c t l
+
+ Do a stream ioctl
+
+ Arguments - fd = Handle to put on
+ cmd = Command to send
+ datap = Ptr to ctrl buffer
+ dlen = Ptr to len of data buffer
+ timout = Timeout value
+
+ Returns - 0 = OK
+ else = Error
+********************************************************************/
+int do_strioctl(HANDLE fd, int cmd, char *datap, int dlen, int timout)
+{
+ int rc;
+ struct strioctl io;
+
+ /** Fill out the structure **/
+
+ io.ic_cmd = cmd;
+ io.ic_dp = datap;
+ io.ic_len = dlen;
+ io.ic_timout = timout;
+
+ /** Issue the ioctl **/
+
+ rc = s_ioctl(fd, I_STR, &io);
+
+ /** All Done **/
+
+ return rc;
+}
+
+/*page***************************************************************
+ r e m o v e _ a d d r e s s
+
+ Remove an address from the source routing table.
+
+ Arguments - nodep = Ptr to node address to remove
+
+ Returns - Does not return
+********************************************************************/
+void remove_address(char *nodep)
+{
+ int rc;
+ int len;
+ rterem buf;
+
+ /** Build the area to send down to the driver **/
+
+ buf.rterem_bnum = boardnum;
+ memcpy(buf.rterem_node, nodep, 6);
+ len = sizeof(int) + 6;
+
+ /** Send the ioctl to remove the address **/
+
+ if (nwlinkfd != INVALID_HANDLE) {
+ rc = do_strioctl(nwlinkfd, MIPX_SRREMOVE, (char *)&buf, len, 0);
+ if (rc) {
+ rc = GetLastError();
+ put_msg (TRUE, MSG_REMOVE_ADDRESS_ERROR, "nwlink");
+ put_msg (TRUE, get_emsg(rc));
+ }
+ }
+ if (isnipxfd != INVALID_HANDLE) {
+ rc = do_isnipxioctl(isnipxfd, MIPX_SRREMOVE, (char *)&buf, len);
+ if (rc) {
+ put_msg (TRUE, MSG_REMOVE_ADDRESS_ERROR, "nwlnkipx");
+ if (rc == EINVAL) {
+ put_msg (TRUE, MSG_ADDRESS_NOT_FOUND);
+ } else {
+ put_msg (TRUE, get_emsg(rc));
+ }
+ }
+ }
+
+ /** Close up and exit **/
+
+ if (isnipxfd != INVALID_HANDLE) NtClose(isnipxfd);
+ if (nwlinkfd != INVALID_HANDLE) NtClose(nwlinkfd);
+ if (isnripfd != INVALID_HANDLE) NtClose(isnripfd);
+ exit(0);
+}
+
+/*page***************************************************************
+ c l e a r _ t a b l e
+
+ Clear out the routing table
+
+ Arguments - None
+
+ Returns - Does not return
+********************************************************************/
+void clear_table(void)
+{
+ int rc;
+
+ /** Send the ioctl to clear the table **/
+
+ if (nwlinkfd != INVALID_HANDLE) {
+ rc = do_strioctl(nwlinkfd, MIPX_SRCLEAR, (char *)&boardnum, sizeof(int), 0);
+ if (rc) {
+ rc= GetLastError();
+ put_msg (TRUE, MSG_CLEAR_TABLE_ERROR, "nwlink");
+ put_msg (TRUE, get_emsg(rc));
+ }
+ }
+ if (isnipxfd != INVALID_HANDLE) {
+ rc = do_isnipxioctl(isnipxfd, MIPX_SRCLEAR, (char *)&boardnum, sizeof(int));
+ if (rc) {
+ put_msg (TRUE, MSG_CLEAR_TABLE_ERROR, "nwlnkipx");
+ put_msg (TRUE, get_emsg(rc));
+ }
+ }
+
+ /** Close up and exit **/
+
+ if (isnipxfd != INVALID_HANDLE) NtClose(isnipxfd);
+ if (nwlinkfd != INVALID_HANDLE) NtClose(nwlinkfd);
+ if (isnripfd != INVALID_HANDLE) NtClose(isnripfd);
+ exit(0);
+}
+
+typedef struct _ISN_ACTION_GET_DETAILS {
+ USHORT NicId; // passed by caller
+ BOOLEAN BindingSet; // returns TRUE if in set
+ UCHAR Type; // 1 = lan, 2 = up wan, 3 = down wan
+ ULONG FrameType; // returns 0 through 3
+ ULONG NetworkNumber; // returns virtual net if NicId is 0
+ UCHAR Node[6]; // adapter's MAC address.
+ WCHAR AdapterName[64]; // terminated with Unicode NULL
+} ISN_ACTION_GET_DETAILS, *PISN_ACTION_GET_DETAILS;
+
+#define REORDER_ULONG(_Ulong) \
+ ((((_Ulong) & 0xff000000) >> 24) | \
+ (((_Ulong) & 0x00ff0000) >> 8) | \
+ (((_Ulong) & 0x0000ff00) << 8) | \
+ (((_Ulong) & 0x000000ff) << 24))
+
+
+/*page***************************************************************
+ p r i n t _ c o n f i g
+
+ Prints out the current config
+
+ Arguments - None
+
+ Returns - Does not return
+********************************************************************/
+void print_config(void)
+{
+ int rc;
+ int nicid, nicidcount;
+ int showlegend = 0;
+ char nicidbuf[6];
+ char network[9];
+ char * frametype;
+ char node[13];
+ char special[2];
+ char adaptername[64];
+ ISN_ACTION_GET_DETAILS getdetails;
+
+
+ if (isnipxfd != INVALID_HANDLE) {
+
+ /** First query nicid 0 **/
+
+ getdetails.NicId = 0;
+
+ rc = do_isnipxioctl(isnipxfd, MIPX_CONFIG, (char *)&getdetails, sizeof(getdetails));
+ if (rc) {
+ put_msg (TRUE, MSG_QUERY_CONFIG_ERROR, "nwlnkipx");
+ put_msg (TRUE, get_emsg(rc));
+ goto errorexit;
+ }
+
+ printf("\n");
+
+ if (getdetails.NetworkNumber != 0) {
+ sprintf (network, "%.8x", REORDER_ULONG(getdetails.NetworkNumber));
+ put_msg (FALSE, MSG_SHOW_INTERNAL_NET, network);
+ }
+
+ //
+ // The NicId 0 query returns the total number.
+ //
+
+ nicidcount = getdetails.NicId;
+
+ for (nicid = 1; nicid <= nicidcount; nicid++) {
+
+ getdetails.NicId = nicid;
+
+ rc = do_isnipxioctl(isnipxfd, MIPX_CONFIG, (char *)&getdetails, sizeof(getdetails));
+ if (rc) {
+ continue;
+ }
+
+ sprintf (nicidbuf, "%d", nicid);
+ sprintf (network, "%.8x", REORDER_ULONG(getdetails.NetworkNumber));
+
+ switch (getdetails.FrameType) {
+ case 0: frametype = load_msg (MSG_ETHERNET_II); break;
+ case 1: frametype = load_msg (MSG_802_3); break;
+ case 2: frametype = load_msg (MSG_802_2); break;
+ case 3: frametype = load_msg (MSG_SNAP); break;
+ case 4: frametype = load_msg (MSG_ARCNET); break;
+ default: frametype = load_msg (MSG_UNKNOWN); break;
+ }
+ sprintf (adaptername, "%ws", getdetails.AdapterName);
+
+ sprintf (node, "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
+ getdetails.Node[0],
+ getdetails.Node[1],
+ getdetails.Node[2],
+ getdetails.Node[3],
+ getdetails.Node[4],
+ getdetails.Node[5]);
+
+ special[1] = '\0';
+ if (getdetails.BindingSet) {
+ special[0] = '*';
+ showlegend |= 1;
+ } else if (getdetails.Type == 2) {
+ special[0] = '+';
+ showlegend |= 2;
+ } else if (getdetails.Type == 3) {
+ special[0] = '-';
+ showlegend |= 4;
+ } else {
+ special[0] = '\0';
+ }
+
+ put_msg (FALSE, MSG_SHOW_NET_NUMBER,
+ nicidbuf,
+ network,
+ frametype,
+ adaptername,
+ node,
+ special);
+
+ LocalFree (frametype);
+
+ }
+
+ if (showlegend) {
+ if (showlegend & 1) {
+ put_msg (FALSE, MSG_LEGEND_BINDING_SET);
+ }
+ if (showlegend & 2) {
+ put_msg (FALSE, MSG_LEGEND_ACTIVE_WAN);
+ }
+ if (showlegend & 4) {
+ put_msg (FALSE, MSG_LEGEND_DOWN_WAN);
+ }
+ printf("\n");
+ }
+
+ }
+
+errorexit:
+
+ /** Close up and exit **/
+
+ if (isnipxfd != INVALID_HANDLE) NtClose(isnipxfd);
+ if (nwlinkfd != INVALID_HANDLE) NtClose(nwlinkfd);
+ if (isnripfd != INVALID_HANDLE) NtClose(isnripfd);
+ exit(0);
+}
+
+/*page***************************************************************
+ g e t _ e m s g
+
+ Get an error message for an error
+
+ Arguments - None
+
+ Returns - Does not return
+********************************************************************/
+unsigned long get_emsg(int rc)
+{
+ /**
+ We have 3 defined error codes that can come back.
+
+ 1 - EINVAL means that we sent down parameters wrong
+ (SHOULD NEVER HAPPEN)
+
+ 2 - ERANGE means that the board number is invalid
+ (CAN HAPPEN IF USER ENTERS BAD BOARD)
+
+ 3 - ENOENT means that on remove - the address given
+ is not in the source routing table.
+ **/
+
+ switch (rc) {
+
+ case EINVAL:
+ return MSG_INTERNAL_ERROR;
+
+ case ERANGE:
+ return MSG_INVALID_BOARD;
+
+ case ENOENT:
+ return MSG_ADDRESS_NOT_FOUND;
+
+ default:
+ return MSG_UNKNOWN_ERROR;
+ }
+
+}
+
+/*page***************************************************************
+ d o _ i s n i p x i o c t l
+
+ Do the equivalent of a stream ioctl to isnipx
+
+ Arguments - fd = Handle to put on
+ cmd = Command to send
+ datap = Ptr to ctrl buffer
+ dlen = Ptr to len of data buffer
+
+ Returns - 0 = OK
+ else = Error
+********************************************************************/
+int do_isnipxioctl(HANDLE fd, int cmd, char *datap, int dlen)
+{
+ NTSTATUS Status;
+ UCHAR buffer[sizeof(NWLINK_ACTION) + sizeof(ISN_ACTION_GET_DETAILS) - 1];
+ PNWLINK_ACTION action;
+ IO_STATUS_BLOCK IoStatusBlock;
+ int rc;
+
+ /** Fill out the structure **/
+
+ action = (PNWLINK_ACTION)buffer;
+
+ action->Header.TransportId = ISN_ACTION_TRANSPORT_ID;
+ action->OptionType = NWLINK_OPTION_CONTROL;
+ action->BufferLength = sizeof(ULONG) + dlen;
+ action->Option = cmd;
+ RtlMoveMemory(action->Data, datap, dlen);
+
+ /** Issue the ioctl **/
+
+ Status = NtDeviceIoControlFile(
+ fd,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ IOCTL_TDI_ACTION,
+ NULL,
+ 0,
+ action,
+ FIELD_OFFSET(NWLINK_ACTION,Data) + dlen);
+
+ if (Status != STATUS_SUCCESS) {
+ if (Status == STATUS_INVALID_PARAMETER) {
+ rc = ERANGE;
+ } else {
+ rc = EINVAL;
+ }
+ } else {
+ if (dlen > 0) {
+ RtlMoveMemory (datap, action->Data, dlen);
+ }
+ rc = 0;
+ }
+
+ return rc;
+
+}
+
+
+//*****************************************************************************
+//
+// Name: put_msg
+//
+// Description: Reads a message resource, formats it in the current language
+// and displays the message.
+//
+// NOTE: This routine was stolen from net\sockets\tcpcmd\common2\util.c.
+//
+// Parameters: error - TRUE if this is an error message.
+// unsigned long MsgNum: ID of the message resource.
+//
+// Returns: unsigned long: number of characters displayed.
+//
+// History:
+// 01/05/93 JayPh Created.
+//
+//*****************************************************************************
+
+unsigned long put_msg(BOOLEAN error, unsigned long MsgNum, ... )
+{
+ unsigned long msglen;
+ char *vp;
+ va_list arglist;
+
+ va_start( arglist, MsgNum );
+ msglen = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_HMODULE,
+ NULL,
+ MsgNum,
+ 0L, // Default country ID.
+ (LPTSTR)&vp,
+ 0,
+ &arglist );
+ if ( msglen == 0 )
+ {
+ return ( 0 );
+ }
+
+ fprintf( error ? stderr : stdout, "%s", vp );
+ LocalFree( vp );
+
+ return ( msglen );
+}
+
+
+//*****************************************************************************
+//
+// Name: load_msg
+//
+// Description: Reads and formats a message resource and returns a pointer
+// to the buffer containing the formatted message. It is the
+// responsibility of the caller to free the buffer.
+//
+// NOTE: This routine was stolen from net\sockets\tcpcmd\common2\util.c.
+//
+// Parameters: unsigned long MsgNum: ID of the message resource.
+//
+// Returns: char *: pointer to the message buffer, NULL if error.
+//
+// History:
+// 01/05/93 JayPh Created.
+//
+//*****************************************************************************
+
+char *load_msg( unsigned long MsgNum, ... )
+{
+ unsigned long msglen;
+ char *vp;
+ va_list arglist;
+
+ va_start( arglist, MsgNum );
+ msglen = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_HMODULE,
+ NULL,
+ MsgNum,
+ 0L, // Default country ID.
+ (LPTSTR)&vp,
+ 0,
+ &arglist );
+ if ( msglen == 0 )
+ {
+ return(0);
+ }
+
+ return ( vp );
+}
+
+
+#define MAX_NETWORK_INTERFACES 255
+
+typedef struct router_info
+{
+ ULONG NetNumber;
+ USHORT TickCount;
+ USHORT HopCount;
+ USHORT NicId;
+ UCHAR InterfaceNumber[10];
+} ROUTER_INFO, *PROUTER_INFO;
+
+/*page***************************************************************
+ s h o w _ r o u t e r _ t a b l e
+
+ Display the IPX routing table
+
+ Arguments - FileHandle = Router File Handle
+ IoStatusBlock = Device IO Status Block
+
+ Returns - Does not return
+********************************************************************/
+VOID
+show_router_table(
+ PHANDLE FileHandle,
+ PIO_STATUS_BLOCK IoStatusBlock
+)
+{
+ SHOW_NIC_INFO nis[MAX_NETWORK_INTERFACES];
+ ULONG NetNumber;
+ char InterfaceNumber[10];
+ NTSTATUS Status;
+ USHORT index, i, NumEntries, count;
+ char router_entry[128];
+ char buffer[32];
+ PROUTER_INFO RouterInfo = NULL;
+
+ if (*FileHandle == INVALID_HANDLE) {
+ put_msg(TRUE, MSG_IPXROUTER_NOT_STARTED );
+ goto exit_show_table;
+ }
+ /** First get the Network numbers for all interfaces **/
+
+ index = 0;
+ while(TRUE) {
+
+ Status = NtDeviceIoControlFile(
+ *FileHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPXROUTER_SHOWNICINFO, // IoControlCode
+ &index, // Input Buffer
+ sizeof(USHORT), // Input Buffer Length
+ &nis[index], // Output Buffer
+ sizeof(SHOW_NIC_INFO)); // Output Buffer Length
+
+ if(IoStatusBlock->Status == STATUS_NO_MORE_ENTRIES) {
+ break;
+ }
+
+ index ++;
+
+ if(Status != STATUS_SUCCESS) {
+ sprintf(buffer, "%x", Status);
+ put_msg(TRUE, MSG_SHOWSTATS_FAILED, buffer);
+ goto exit_show_table;
+ }
+
+ if (index >= MAX_NETWORK_INTERFACES) {
+ // break out of this loop if there are more than 255 network
+ // interfaces because we only have storage for 255.
+
+ break;
+ }
+
+ }
+
+ Status = NtDeviceIoControlFile(
+ *FileHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPXROUTER_SNAPROUTES, // IoControlCode
+ NULL, // Input Buffer
+ 0, // Input Buffer Length
+ NULL, // Output Buffer
+ 0); // Output Buffer Length
+
+ if (IoStatusBlock->Status != STATUS_SUCCESS) {
+ sprintf(buffer, "%x", Status);
+ put_msg(TRUE, MSG_SNAPROUTES_FAILED, buffer);
+ goto exit_show_table;
+ }
+
+ // first determine the number of router table entries to
+ // allocate sufficient storage
+
+ NumEntries = 0;
+ while(TRUE) {
+
+ Status = NtDeviceIoControlFile(
+ *FileHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPXROUTER_GETNEXTROUTE, // IoControlCode
+ NULL, // Input Buffer
+ 0, // Input Buffer Length
+ &rte, // Output Buffer
+ sizeof(IPX_ROUTE_ENTRY)); // Output Buffer Length
+
+ if(IoStatusBlock->Status == STATUS_NO_MORE_ENTRIES) {
+ break;
+ }
+
+ if(Status != STATUS_SUCCESS) {
+ sprintf(buffer,"%x",Status);
+ put_msg(TRUE, MSG_GETNEXTROUTE_FAILED, buffer);
+ goto exit_show_table;
+ }
+
+ NumEntries ++;
+ }
+
+ RouterInfo = (PROUTER_INFO) LocalAlloc(LPTR, sizeof(ROUTER_INFO) * NumEntries);
+ if(!RouterInfo) {
+ put_msg(FALSE, MSG_INSUFFICIENT_MEMORY);
+ goto exit_show_table;
+ }
+
+ Status = NtDeviceIoControlFile(
+ *FileHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPXROUTER_SNAPROUTES, // IoControlCode
+ NULL, // Input Buffer
+ 0, // Input Buffer Length
+ NULL, // Output Buffer
+ 0); // Output Buffer Length
+
+ if (IoStatusBlock->Status != STATUS_SUCCESS) {
+ sprintf(buffer, "%x", Status);
+ put_msg(TRUE, MSG_SNAPROUTES_FAILED, buffer);
+ goto exit_show_table;
+ }
+
+ index = 0;
+
+ while(TRUE) {
+
+ Status = NtDeviceIoControlFile(
+ *FileHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPXROUTER_GETNEXTROUTE, // IoControlCode
+ NULL, // Input Buffer
+ 0, // Input Buffer Length
+ &rte, // Output Buffer
+ sizeof(IPX_ROUTE_ENTRY)); // Output Buffer Length
+
+ if(IoStatusBlock->Status == STATUS_NO_MORE_ENTRIES) {
+ break;
+ }
+
+ if(Status != STATUS_SUCCESS) {
+ sprintf(buffer,"%x",Status);
+ put_msg(TRUE, MSG_GETNEXTROUTE_FAILED, buffer);
+ goto exit_show_table;
+ }
+
+ // make sure we don't exceed the number of entries
+ if (index > NumEntries) {
+ break;
+ }
+
+ // get net nr in "on the wire" order
+
+ GETLONG2ULONG(&(RouterInfo[index].NetNumber), rte.Network);
+
+ // find out the matching Network number based on NIC ID
+ for(i=0; i < MAX_NETWORK_INTERFACES; i++) {
+ if(rte.NicId == nis[i].NicId) {
+ sprintf(RouterInfo[index].InterfaceNumber, "%.2x%.2x%.2x%.2x",
+ nis[i].Network[0],
+ nis[i].Network[1],
+ nis[i].Network[2],
+ nis[i].Network[3]);
+ break;
+ }
+ }
+ RouterInfo[index].TickCount = rte.TickCount;
+ RouterInfo[index].HopCount = rte.HopCount;
+ RouterInfo[index].NicId = rte.NicId;
+
+ index++;
+ }
+
+ // Now sort the entries by net number
+ qsort( (void*) RouterInfo,
+ NumEntries,
+ sizeof(ROUTER_INFO),
+ (PQSORT_COMPARE)CompareNetNumber );
+
+ put_msg(FALSE, MSG_ROUTER_TABLE_HEADER);
+ for(index =0, count = 0; index < NumEntries; index++, count++)
+ {
+ if (count > 50) {
+ count = 0;
+ // display router table header every 25 entries
+ // to make reading the table easier.
+ put_msg(FALSE, MSG_ROUTER_TABLE_HEADER);
+ }
+ printf("%.8x %6d %2d %-16s %d\n",
+ RouterInfo[index].NetNumber,
+ RouterInfo[index].TickCount,
+ RouterInfo[index].HopCount,
+ RouterInfo[index].InterfaceNumber,
+ RouterInfo[index].NicId );
+ }
+ /** Close up and exit **/
+exit_show_table:
+ if (RouterInfo) LocalFree(RouterInfo);
+ if (isnipxfd != INVALID_HANDLE) NtClose(isnipxfd);
+ if (nwlinkfd != INVALID_HANDLE) NtClose(nwlinkfd);
+ if (isnripfd != INVALID_HANDLE) NtClose(isnripfd);
+ exit(0);
+}
+
+int _CRTAPI1 CompareNetNumber( void * p0, void * p1)
+{
+ PROUTER_INFO pLeft = (PROUTER_INFO) p0;
+ PROUTER_INFO pRight = (PROUTER_INFO) p1;
+
+ if(pLeft->NetNumber == pRight->NetNumber)
+ return(0);
+ if(pLeft->NetNumber > pRight->NetNumber)
+ return(1);
+ else
+ return(-1);
+}
+
+PUCHAR DeviceType[2] = { "LAN", "WAN" };
+PUCHAR NicState[4] = { "CLOSED", "CLOSING", "ACTIVE", "PENDING_OPEN" };
+
+/*page***************************************************************
+ s h o w _ s t a t s
+
+ Displays IPX internal routing statistics
+
+ Arguments - FileHandle = Router File Handle
+ IoStatusBlock = Device IO Status Block
+
+ Returns - Does not return
+********************************************************************/
+VOID
+show_stats(
+ PHANDLE FileHandle,
+ PIO_STATUS_BLOCK IoStatusBlock
+)
+{
+ SHOW_NIC_INFO nis;
+ USHORT index, i;
+ char NicId[4];
+ char NetworkNumber[10];
+ char RipRcvd[32], RipSent[32];
+ char RoutedRcvd[32], RoutedSent[32];
+ char Type20Rcvd[32], Type20Sent[32];
+ char BadRcvd[32];
+ char buffer[32];
+
+ NTSTATUS Status;
+
+ if (*FileHandle == INVALID_HANDLE) {
+ put_msg(TRUE, MSG_IPXROUTER_NOT_STARTED );
+ goto end_stats;
+ }
+
+ index = 0;
+
+ while(TRUE) {
+
+ Status = NtDeviceIoControlFile(
+ *FileHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPXROUTER_SHOWNICINFO, // IoControlCode
+ &index, // Input Buffer
+ sizeof(USHORT), // Input Buffer Length
+ &nis, // Output Buffer
+ sizeof(nis)); // Output Buffer Length
+
+ if(IoStatusBlock->Status == STATUS_NO_MORE_ENTRIES) {
+ goto end_stats;
+ }
+
+ index ++;
+
+ if(Status != STATUS_SUCCESS) {
+ sprintf(buffer, "%x", Status);
+ put_msg(TRUE, MSG_SHOWSTATS_FAILED, buffer);
+ goto end_stats;
+ }
+
+ sprintf(NicId, "%d", nis.NicId);
+
+ sprintf(NetworkNumber,
+ "%.2x%.2x%.2x%.2x",
+ nis.Network[0],
+ nis.Network[1],
+ nis.Network[2],
+ nis.Network[3]);
+
+ sprintf(RipRcvd, "%-8d", nis.StatRipReceived);
+
+ sprintf(RipSent, "%-8d", nis.StatRipSent);
+
+ sprintf(RoutedRcvd, "%-8d", nis.StatRoutedReceived);
+
+ sprintf(RoutedSent, "%-8d", nis.StatRoutedSent);
+
+ sprintf(Type20Rcvd, "%-8d", nis.StatType20Received);
+
+ sprintf(Type20Sent, "%-8d", nis.StatType20Sent);
+
+ sprintf(BadRcvd, "%-8d", nis.StatBadReceived);
+
+ put_msg(FALSE,
+ MSG_SHOW_STATISTICS,
+ NicId,
+ NetworkNumber,
+ RipRcvd,
+ RipSent,
+ Type20Rcvd,
+ Type20Sent,
+ RoutedRcvd,
+ RoutedSent,
+ BadRcvd);
+
+ }
+
+ /** Close up and exit **/
+
+end_stats:
+ if (isnipxfd != INVALID_HANDLE) NtClose(isnipxfd);
+ if (nwlinkfd != INVALID_HANDLE) NtClose(nwlinkfd);
+ if (isnripfd != INVALID_HANDLE) NtClose(isnripfd);
+ exit(0);
+}
+
+/*page***************************************************************
+ c l e a r _ s t a t s
+
+ Clears the IPX internal routing statistics
+
+ Arguments - FileHandle = Router File Handle
+ IoStatusBlock = Device IO Status Block
+
+ Returns - Does not return
+********************************************************************/
+VOID
+clear_stats(
+ PHANDLE FileHandle,
+ PIO_STATUS_BLOCK IoStatusBlock
+)
+{
+ NTSTATUS Status;
+ char buffer[32];
+
+ if (*FileHandle == INVALID_HANDLE) {
+ put_msg(TRUE, MSG_IPXROUTER_NOT_STARTED );
+ goto end_clearstats;
+ }
+
+ Status = NtDeviceIoControlFile(
+ *FileHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPXROUTER_ZERONICSTATISTICS, // IoControlCode
+ NULL, // Input Buffer
+ 0, // Input Buffer Length
+ NULL, // Output Buffer
+ 0); // Output Buffer Length
+
+ if(Status != STATUS_SUCCESS) {
+ sprintf(buffer, "%x", Status);
+ put_msg(TRUE, MSG_CLEAR_STATS_FAILED, buffer);
+ }
+ /** Close up and exit **/
+end_clearstats:
+ if (isnipxfd != INVALID_HANDLE) NtClose(isnipxfd);
+ if (nwlinkfd != INVALID_HANDLE) NtClose(nwlinkfd);
+ if (isnripfd != INVALID_HANDLE) NtClose(isnripfd);
+ exit(0);
+}
+
+typedef struct server_info
+{
+ USHORT ObjectType;
+ UCHAR ObjectName[100];
+ UCHAR IpxAddress[12];
+} SERVER_INFO, *PSERVER_INFO;
+
+/*page***************************************************************
+ s h o w _ s e r v e r s
+
+ Display the servers from the SAP table
+
+ Arguments - servertype = Type of servers to display
+ Defaults to show all server types
+
+ Returns - Does not return
+********************************************************************/
+VOID
+show_servers(int servertype)
+{
+ INT rc;
+ ULONG ObjectID = 0xFFFFFFFF;
+ UCHAR ObjectName[100];
+ USHORT ObjectType;
+ USHORT ScanType = servertype;
+ UCHAR IpxAddress[12];
+ USHORT i;
+ USHORT index, count, NumServers;
+
+ PSERVER_INFO ServerInfo = NULL;
+
+ if(rc = SapLibInit() != SAPRETURN_SUCCESS) {
+ put_msg(TRUE, MSG_SAP_NOT_STARTED);
+ goto show_servers_end;
+ }
+
+ memset(&ObjectName, 0, 100);
+
+ // find out how many servers are there so that we can allocate
+ // sufficient storage
+ NumServers = 0;
+
+ while((rc = SapScanObject(&ObjectID,
+ ObjectName,
+ &ObjectType,
+ ScanType)) == SAPRETURN_SUCCESS)
+ {
+ NumServers++;
+ }
+
+ ServerInfo = (PSERVER_INFO) LocalAlloc(LPTR, sizeof(SERVER_INFO) * NumServers);
+ if(!ServerInfo)
+ {
+ put_msg(FALSE, MSG_INSUFFICIENT_MEMORY);
+ goto show_servers_end;
+ }
+
+ index = 0;
+ ObjectID = 0xFFFFFFFF;
+
+ while((rc = SapScanObject(&ObjectID,
+ ObjectName,
+ &ObjectType,
+ ScanType)) == SAPRETURN_SUCCESS)
+ {
+ if (index > NumServers) {
+ break;
+ }
+
+ // get object address
+ SapGetObjectName(ObjectID,
+ ObjectName,
+ &ObjectType,
+ IpxAddress);
+
+ ServerInfo[index].ObjectType = ObjectType;
+ strcpy(ServerInfo[index].ObjectName, ObjectName);
+ CopyMemory(ServerInfo[index].IpxAddress, IpxAddress, 12);
+
+ index++;
+ }
+
+ // Now sort the entries by server name
+ qsort( (void*) ServerInfo,
+ NumServers,
+ sizeof(SERVER_INFO),
+ (PQSORT_COMPARE)CompareServerNames );
+
+ if(servertype == SHOW_ALL_SERVERS)
+ put_msg(FALSE, MSG_SHOW_ALL_SERVERS_HEADER);
+ else
+ put_msg(FALSE, MSG_SHOW_SPECIFIC_SERVER_HEADER);
+
+ for(index = 0, count = 0; index < NumServers; index++, count++)
+ {
+ if (count > 50) {
+ // write the table header for every 50 entries
+ // to make this more readable.
+ count = 0;
+
+ if(servertype == SHOW_ALL_SERVERS)
+ put_msg(FALSE, MSG_SHOW_ALL_SERVERS_HEADER);
+ else
+ put_msg(FALSE, MSG_SHOW_SPECIFIC_SERVER_HEADER);
+ }
+
+ for(i=0; i<4; i++) {
+ printf("%.2x", ServerInfo[index].IpxAddress[i]);
+ }
+ printf(".");
+ for(i=4; i<10; i++) {
+ printf("%.2x", ServerInfo[index].IpxAddress[i]);
+ }
+
+ if(servertype == SHOW_ALL_SERVERS) {
+ printf(" %-6d", ServerInfo[index].ObjectType);
+ }
+
+ printf(" %s\n", ServerInfo[index].ObjectName);
+ }
+
+ /** Close up and exit **/
+show_servers_end:
+ if (ServerInfo) LocalFree(ServerInfo);
+ if (isnipxfd != INVALID_HANDLE) NtClose(isnipxfd);
+ if (nwlinkfd != INVALID_HANDLE) NtClose(nwlinkfd);
+ if (isnripfd != INVALID_HANDLE) NtClose(isnripfd);
+ exit(0);
+}
+
+int _CRTAPI1 CompareServerNames( void * p0, void * p1)
+{
+ PSERVER_INFO pLeft = (PSERVER_INFO) p0;
+ PSERVER_INFO pRight = (PSERVER_INFO) p1;
+
+ return(strcmp(pLeft->ObjectName, pRight->ObjectName));
+}
+
diff --git a/private/ntos/tdi/isn/ipxroute/ipxroute.rc b/private/ntos/tdi/isn/ipxroute/ipxroute.rc
new file mode 100644
index 000000000..e56b3d767
--- /dev/null
+++ b/private/ntos/tdi/isn/ipxroute/ipxroute.rc
@@ -0,0 +1,13 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "NWLink Source Routing Application"
+#define VER_INTERNALNAME_STR "ipxroute.exe"
+#define VER_ORIGINALFILENAME_STR "ipxroute.exe"
+
+#include "common.ver"
+
+1 11 MSG00001.BIN
diff --git a/private/ntos/tdi/isn/ipxroute/ipxrtmsg.mc b/private/ntos/tdi/isn/ipxroute/ipxrtmsg.mc
new file mode 100644
index 000000000..47203d60e
--- /dev/null
+++ b/private/ntos/tdi/isn/ipxroute/ipxrtmsg.mc
@@ -0,0 +1,252 @@
+; //***************************************************************************
+; //
+; // Name: ipxroute.mc
+; //
+; // Description: Message file for ipxroute.exe
+; //
+; // History:
+; // 07/14/94 AdamBa Created.
+; //
+; //***************************************************************************
+;
+; //***************************************************************************
+; //
+; // Copyright (c) 1994 by Microsoft Corp. All rights reserved.
+; //
+; //***************************************************************************
+
+MessageId=10000 SymbolicName=MSG_USAGE
+Language=English
+
+Display and modify information about the routing tables
+used by IPX.
+
+IPX Routing Options
+-------------------
+
+%1 servers [/type=xxxx]
+%1 stats [/show] [/clear]
+%1 table
+
+ servers Displays the SAP table for the specified
+ server type. Server type is an integer value.
+ For example use %1 servers /type=4 to display
+ all file servers. If no type is specified,
+ servers of all types are shown. The displayed
+ list is sorted by server name.
+
+ stats Displays or clears IPX router interface statistics.
+ If no option is specified, statistics are shown.
+ To clear the statistics specify /clear.
+
+ table Displays the IPX routing table. The displayed
+ list is sorted by network number.
+
+Source Routing Options
+----------------------
+
+%1 board=n clear def gbr mbr remove=xxxxxxxxxxxx
+%1 config
+
+ board=n Specify the board number to check.
+ clear Clear the source routing table.
+ def Send packets that are destined for an
+ unknown address to the ALL ROUTES broadcast
+ (Default is SINGLE ROUTE broadcast).
+ gbr Send packets that are destined for the
+ broadcast address (FFFF FFFF FFFF) to the
+ ALL ROUTES broadcast
+ (Default is SINGLE ROUTE broadcast).
+ mbr Send packets that are destined for a
+ multicast address (C000 xxxx xxxx) to the
+ ALL ROUTES broadcast
+ (Default is SINGLE ROUTE broadcast).
+ remove=xxxx Remove the given mac address from the
+ source routing table.
+
+ config Displays information on all the bindings
+ that IPX is configured for.
+
+All parameters should be separated by spaces.
+.
+MessageId=10001 SymbolicName=MSG_INTERNAL_ERROR
+Language=English
+Invalid parameters (internal error).
+.
+MessageId=10002 SymbolicName=MSG_INVALID_BOARD
+Language=English
+Invalid board number.
+.
+MessageId=10003 SymbolicName=MSG_ADDRESS_NOT_FOUND
+Language=English
+Address not in table.
+.
+MessageId=10004 SymbolicName=MSG_UNKNOWN_ERROR
+Language=English
+Unknown error.
+.
+MessageId=10005 SymbolicName=MSG_OPEN_FAILED
+Language=English
+Unable to open transport %1.
+.
+MessageId=10006 SymbolicName=MSG_VERSION
+Language=English
+NWLink IPX Routing and Source Routing Control Program v2.00
+.
+MessageId=10007 SymbolicName=MSG_DEFAULT_NODE
+Language=English
+ DEFault Node (Unknown) Addresses are sent %1
+.
+MessageId=10008 SymbolicName=MSG_BROADCAST
+Language=English
+ Broadcast (FFFF FFFF FFFF) Addresses are sent %1
+.
+MessageId=10009 SymbolicName=MSG_MULTICAST
+Language=English
+ Multicast (C000 xxxx xxxx) Addresses are sent %1
+.
+MessageId=10010 SymbolicName=MSG_ALL_ROUTE
+Language=English
+ALL ROUTE BROADCAST%0
+.
+MessageId=10011 SymbolicName=MSG_SINGLE_ROUTE
+Language=English
+SINGLE ROUTE BROADCAST%0
+.
+MessageId=10012 SymbolicName=MSG_INVALID_REMOVE
+Language=English
+Invalid value for the remove node number.
+.
+MessageId=10013 SymbolicName=MSG_BAD_PARAMETERS
+Language=English
+Error getting parameters from IPX (%1): %0
+.
+MessageId=10014 SymbolicName=MSG_SET_DEFAULT_ERROR
+Language=English
+Error setting DEFAULT flag to IPX (%1): %0
+.
+MessageId=10015 SymbolicName=MSG_SET_BROADCAST_ERROR
+Language=English
+Error setting BROADCAST flag to IPX (%1): %0
+.
+MessageId=10016 SymbolicName=MSG_SET_MULTICAST_ERROR
+Language=English
+Error setting MULTICAST flag to IPX (%1): %0
+.
+MessageId=10017 SymbolicName=MSG_REMOVE_ADDRESS_ERROR
+Language=English
+Error removing address from source routing table (%1): %0
+.
+MessageId=10018 SymbolicName=MSG_CLEAR_TABLE_ERROR
+Language=English
+Error clearing source routing table (%1): %0
+.
+MessageId=10019 SymbolicName=MSG_QUERY_CONFIG_ERROR
+Language=English
+Error querying config (%1): %0
+.
+MessageId=10020 SymbolicName=MSG_SHOW_INTERNAL_NET
+Language=English
+IPX internal network number %1
+.
+MessageId=10021 SymbolicName=MSG_SHOW_NET_NUMBER
+Language=English
+net %1: network number %2, frame type %3, device %4 (%5)%6
+.
+MessageId=10022 SymbolicName=MSG_ETHERNET_II
+Language=English
+ethernet ii%0
+.
+MessageId=10023 SymbolicName=MSG_802_3
+Language=English
+802.3%0
+.
+MessageId=10024 SymbolicName=MSG_802_2
+Language=English
+802.2%0
+.
+MessageId=10025 SymbolicName=MSG_SNAP
+Language=English
+snap%0
+.
+MessageId=10026 SymbolicName=MSG_ARCNET
+Language=English
+arcnet%0
+.
+MessageId=10027 SymbolicName=MSG_UNKNOWN
+Language=English
+unknown%0
+.
+MessageId=10028 SymbolicName=MSG_LEGEND_BINDING_SET
+Language=English
+* binding set member %0
+.
+MessageId=10029 SymbolicName=MSG_LEGEND_ACTIVE_WAN
+Language=English
++ active wan line %0
+.
+MessageId=10030 SymbolicName=MSG_LEGEND_DOWN_WAN
+Language=English
+- down wan line %0
+.
+MessageId=10031 SymbolicName=MSG_ROUTER_TABLE_HEADER
+Language=English
+
+Net Number Ticks Hops Interface Net Number Interface ID
+-------------------------------------------------------------------------
+.
+MessageId=10032 SymbolicName=MSG_SNAPROUTES_FAILED
+Language=English
+Ioctl snap routes to IPX router failed with error %1.
+.
+MessageId=10033 SymbolicName=MSG_GETNEXTROUTE_FAILED
+Language=English
+Failed to get the next route from the IPX router with error %1.
+.
+MessageId=10034 SymbolicName=MSG_SHOWSTATS_FAILED
+Language=English
+Failed to get the internal router statistics with error %1.
+.
+MessageId=10035 SymbolicName=MSG_SHOW_STATISTICS
+Language=English
+
+Network Interface ID = %1
+Network Interface Number = %2
+RIP packets: received = %3 sent = %4
+Type 20 packets: received = %5 sent = %6
+Forwarded packets: received = %7 sent = %8
+Discarded packets: received = %9
+.
+MessageId=10036 SymbolicName=MSG_CLEAR_STATS_FAILED
+Language=English
+Ioctl to clear statistics failed with error %1.
+.
+MessageId=10037 SymbolicName=MSG_SHOW_ALL_SERVERS_HEADER
+Language=English
+
+IPX Address Server Type Server Name
+-------------------------------------------------------
+.
+MessageId=10038 SymbolicName=MSG_SHOW_SPECIFIC_SERVER_HEADER
+Language=English
+
+IPX Address Server Name
+----------------------------------------
+.
+MessageId=10039 SymbolicName=MSG_IPXROUTER_NOT_STARTED
+Language=English
+
+Unable to set/get information from the IPX router.
+Make sure that the IPX router service (NWLNKRIP) is started.
+.
+MessageId=10040 SymbolicName=MSG_SAP_NOT_STARTED
+Language=English
+
+Unable to get information from the SAP agent.
+Make sure that the SAP agent service (NWSAPAGENT) is started.
+.
+MessageId=10041 SymbolicName=MSG_INSUFFICIENT_MEMORY
+Language=English
+Cannot allocate sufficient memory. Close other applications and try this operation.
+.
+ \ No newline at end of file
diff --git a/private/ntos/tdi/isn/ipxroute/makefile b/private/ntos/tdi/isn/ipxroute/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isn/ipxroute/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isn/ipxroute/makefile.inc b/private/ntos/tdi/isn/ipxroute/makefile.inc
new file mode 100644
index 000000000..ce99ed09d
--- /dev/null
+++ b/private/ntos/tdi/isn/ipxroute/makefile.inc
@@ -0,0 +1,13 @@
+IPX_BASENAME = $(TARGETNAME).exe
+
+NLINKEXENAME = obj\$(TARGET_DIRECTORY)\$(IPX_BASENAME)
+
+NLINKBINNAME = $(BASEDIR)\public\sdk\lib\$(TARGET_DIRECTORY)\$(IPX_BASENAME)
+
+$(NLINKBINNAME): $(NLINKEXENAME)
+ copy $(NLINKEXENAME) $(NLINKBINNAME)
+
+ipxroute.rc: ipxrtmsg.rc msg00001.bin
+
+ipxrtmsg.h ipxrtmsg.rc msg00001.bin: ipxrtmsg.mc
+ mc -v ipxrtmsg.mc
diff --git a/private/ntos/tdi/isn/ipxroute/sources b/private/ntos/tdi/isn/ipxroute/sources
new file mode 100644
index 000000000..de1fcda6b
--- /dev/null
+++ b/private/ntos/tdi/isn/ipxroute/sources
@@ -0,0 +1,36 @@
+!IF 0
+
+Copyright (c) 1993 Micro Computer Systems, Inc.
+
+!ENDIF
+
+MAJORCOMP=nwlink
+MINORCOMP=ipxroute
+
+TARGETNAME=ipxroute
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=UMAPPL_NOLIB
+
+USE_CRTDLL=1
+
+C_DEFINES=$(C_DEFINES)
+
+!IF 0
+INCLUDES=..\h;..\..\..\..\..\inc;..\..\..\..\inc;..\..\..\inc
+!ELSE
+INCLUDES=..\h;$(BASEDIR)\private\inc;$(BASEDIR)\private\ntos\inc;$(BASEDIR)\private\ntos\streams\inc;$(BASEDIR)\private\net\inc
+!ENDIF
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES= ipxroute.rc
+
+UMTYPE=console
+UMAPPL=$(TARGETNAME)
+UMLIBS=$(BASEDIR)\public\sdk\lib\*\ntdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\winstrm.lib \
+ $(BASEDIR)\public\sdk\lib\*\nwsaplib.lib
+
+UMRES=obj\*\ipxroute.res
+
+NTTARGETFILE0=ipxrtmsg.h ipxrtmsg.mc ipxroute.rc
diff --git a/private/ntos/tdi/isn/ipxroute/utils.h b/private/ntos/tdi/isn/ipxroute/utils.h
new file mode 100644
index 000000000..afacd2a35
--- /dev/null
+++ b/private/ntos/tdi/isn/ipxroute/utils.h
@@ -0,0 +1,55 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: utils.h
+//
+// Description: Contains miscellaneous utilities
+//
+// Author: Stefan Solomon (stefans) October 4, 1993.
+//
+// Revision History:
+//
+//***
+
+#ifndef _UTILS_
+#define _UTILS_
+
+/*
+ * The following macros deal with on-the-wire short and long values
+ *
+ * On the wire format is big-endian i.e. a long value of 0x01020304 is
+ * represented as 01 02 03 04.
+ * Similarly a short value of 0x0102 is represented as 01 02.
+ *
+ * The host format is not assumed since it will vary from processor to
+ * processor.
+ */
+
+// Get a short from on-the-wire format to a USHORT in the host format
+#define GETSHORT2USHORT(DstPtr, SrcPtr) \
+ *(PUSHORT)(DstPtr) = ((*((PUCHAR)(SrcPtr)+0) << 8) + \
+ (*((PUCHAR)(SrcPtr)+1) ))
+
+// Get a long from on-the-wire format to a ULONG in the host format
+#define GETLONG2ULONG(DstPtr, SrcPtr) \
+ *(PULONG)(DstPtr) = ((*((PUCHAR)(SrcPtr)+0) << 24) + \
+ (*((PUCHAR)(SrcPtr)+1) << 16) + \
+ (*((PUCHAR)(SrcPtr)+2) << 8) + \
+ (*((PUCHAR)(SrcPtr)+3) ))
+
+// Put a USHORT from the host format to a short to on-the-wire format
+#define PUTUSHORT2SHORT(DstPtr, Src) \
+ *((PUCHAR)(DstPtr)+0) = (UCHAR) ((USHORT)(Src) >> 8), \
+ *((PUCHAR)(DstPtr)+1) = (UCHAR)(Src)
+
+// Put a ULONG from the host format to an array of 4 UCHARs on-the-wire format
+#define PUTULONG2LONG(DstPtr, Src) \
+ *((PUCHAR)(DstPtr)+0) = (UCHAR) ((ULONG)(Src) >> 24), \
+ *((PUCHAR)(DstPtr)+1) = (UCHAR) ((ULONG)(Src) >> 16), \
+ *((PUCHAR)(DstPtr)+2) = (UCHAR) ((ULONG)(Src) >> 8), \
+ *((PUCHAR)(DstPtr)+3) = (UCHAR) (Src)
+
+#endif // _UTILS_
diff --git a/private/ntos/tdi/isn/isnext/cteext.c b/private/ntos/tdi/isn/isnext/cteext.c
new file mode 100644
index 000000000..6a790e89c
--- /dev/null
+++ b/private/ntos/tdi/isn/isnext/cteext.c
@@ -0,0 +1,155 @@
+#include "precomp.h"
+#pragma hdrstop
+
+
+#ifdef _obj
+# undef _obj
+# undef _objAddr
+# undef _objType
+#endif
+
+#define _obj Mdl
+#define _objAddr MdlToDump
+#define _objType MDL
+
+VOID
+DumpMdlChain
+(
+ ULONG _objAddr,
+ VERBOSITY Verbosity
+)
+{
+ _objType _obj;
+ ULONG result;
+
+ if ( !ReadMemory( _objAddr,
+ &_obj,
+ sizeof( _obj ),
+ &result ))
+ {
+ dprintf("%08lx: Could not read MDL structure\n", _objAddr );
+ return;
+ }
+
+ PrintStartStruct();
+ PrintPtr( Next );
+ PrintUShort( Size );
+ PrintXUShort( MdlFlags );
+ PrintPtr( Process );
+ PrintPtr( MappedSystemVa );
+ PrintPtr( StartVa );
+ PrintULong( ByteCount );
+ PrintULong( ByteOffset );
+ return;
+}
+
+VOID
+DumpCTELock
+(
+ ULONG LockToDump,
+ VERBOSITY Verbosity
+)
+{
+ CTELock Lock;
+ CTELock *pLock;
+ ULONG result;
+
+ pLock = ( CTELock * )LockToDump;
+
+ if ( !ReadMemory( LockToDump,
+ &Lock,
+ sizeof( Lock ),
+ &result ))
+ {
+ dprintf("%08lx: Could not read CTELock structure\n", LockToDump );
+ return;
+ }
+
+ dprintf( "{ Lock = %d }", Lock );
+ return;
+}
+
+#ifdef _obj
+# undef _obj
+# undef _objAddr
+# undef _objType
+#endif
+
+#define _obj Timer
+#define _objAddr pItem
+#define _objType CTETimer
+
+VOID
+DumpCTETimer
+(
+ ULONG TimerToDump,
+ VERBOSITY Verbosity
+)
+{
+ CTETimer Timer;
+ CTETimer *prTimer;
+ ULONG result;
+
+ prTimer = ( CTETimer * )TimerToDump;
+
+ if ( !ReadMemory( TimerToDump,
+ &Timer,
+ sizeof( Timer ),
+ &result ))
+ {
+ dprintf("%08lx: Could not read CTETimer structure\n", TimerToDump );
+ return;
+ }
+
+ PrintStart;
+ PrintULong( t_running );
+ PrintLock( t_lock );
+ PrintSymbolPtr( t_handler );
+ PrintXULong( t_arg );
+ // DPC
+ // KTIMER
+ PrintEnd;
+ return;
+}
+
+#ifdef _obj
+# undef _obj
+# undef _objAddr
+# undef _objType
+#endif
+
+#define _obj QItem
+#define _objAddr prQItem
+#define _objType WORK_QUEUE_ITEM
+
+VOID
+DumpWorkQueueItem
+(
+ ULONG ItemToDump,
+ VERBOSITY Verbosity
+)
+{
+ _objType _obj;
+ _objType *_objAddr;
+ ULONG result;
+
+ _objAddr = ( _objType * )ItemToDump;
+
+ if ( !ReadMemory( ItemToDump,
+ &_obj,
+ sizeof( _obj ),
+ &result ))
+ {
+ dprintf( "%08lx: Could not read %s structure\n",
+ ItemToDump,
+ "WORK_QUEUE_ITEM" );
+ return;
+ }
+
+ PrintStart;
+ PrintLL( List );
+ PrintSymbolPtr( WorkerRoutine );
+ PrintXULong( Parameter );
+ PrintEnd;
+ return;
+}
diff --git a/private/ntos/tdi/isn/isnext/cteext.h b/private/ntos/tdi/isn/isnext/cteext.h
new file mode 100644
index 000000000..dce46b350
--- /dev/null
+++ b/private/ntos/tdi/isn/isnext/cteext.h
@@ -0,0 +1,33 @@
+#if !defined( _INCLUDED_CTEEXT_H_ )
+#define _INCLUDED_CTEEXT_H_
+
+VOID
+DumpCTELock
+(
+ ULONG LockToDump,
+ VERBOSITY Verbosity
+);
+
+VOID
+DumpCTETimer
+(
+ ULONG TimerToDump,
+ VERBOSITY Verbosity
+);
+
+VOID
+DumpWorkQueueItem
+(
+ ULONG ItemToDump,
+ VERBOSITY Verbosity
+);
+
+
+VOID
+DumpMdlChain
+(
+ ULONG MdlToDump,
+ VERBOSITY Verbosity
+);
+
+#endif
diff --git a/private/ntos/tdi/isn/isnext/daytona/makefile b/private/ntos/tdi/isn/isnext/daytona/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isn/isnext/daytona/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isn/isnext/daytona/sources b/private/ntos/tdi/isn/isnext/daytona/sources
new file mode 100644
index 000000000..032c146bb
--- /dev/null
+++ b/private/ntos/tdi/isn/isnext/daytona/sources
@@ -0,0 +1,45 @@
+MAJORCOMP=isn
+MINORCOMP=isnext
+
+TARGETNAME=isnext
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+
+DLLDEF=obj\*\isnext.def
+
+SOURCES=\
+ ..\isnext.c \
+ ..\nbext.c \
+ ..\isnext.rc \
+ ..\ipxext.c \
+ ..\traverse.c \
+ ..\spxext.c \
+ ..\cteext.c
+
+UMTYPE=windows
+
+INCLUDES=\
+ ..\;\
+ $(BASEDIR)\private\ntos\tdi\isn\inc;\
+ $(BASEDIR)\private\ntos\tdi\isn\nb;\
+ $(BASEDIR)\private\ntos\tdi\isn\spx;\
+ $(BASEDIR)\private\ntos\tdi\isn\spx\h;\
+ $(BASEDIR)\private\ntos\tdi\isn\ipx;\
+ $(BASEDIR)\private\ntos\inc;\
+ $(BASEDIR)\private\inc
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+C_DEFINES=$(C_DEFINES) -D_PNP_POWER=1 -DBACK_FILL=1
+#-DRSRC_TIMEOUT_DBG
+
+#C_DEFINES=$(C_DEFINES)
+
+TARGETLIBS=\
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib
+
+USE_NTDLL=1
+
+PRECOMPILED_INCLUDE=..\precomp.h
+PRECOMPILED_PCH=..\precomp.pch
+PRECOMPILED_OBJ=..\precomp.obj
diff --git a/private/ntos/tdi/isn/isnext/dirs b/private/ntos/tdi/isn/isnext/dirs
new file mode 100644
index 000000000..ae926322e
--- /dev/null
+++ b/private/ntos/tdi/isn/isnext/dirs
@@ -0,0 +1,25 @@
+!IF 0
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles. This was necessitated by the need to
+ build a cairo and nt srv.
+
+Author:
+
+ Isaac Heizer
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=daytona
+
+OPTIONAL_DIRS=cairo
diff --git a/private/ntos/tdi/isn/isnext/ipxext.c b/private/ntos/tdi/isn/isnext/ipxext.c
new file mode 100644
index 000000000..6a6e5e0e1
--- /dev/null
+++ b/private/ntos/tdi/isn/isnext/ipxext.c
@@ -0,0 +1,1989 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ ipxext.c
+
+Abstract:
+
+ This file contains kernel debugger extensions for examining the
+ IPX structures.
+
+Author:
+
+ Heath Hunnicutt (T-HeathH) 3-Aug-1995
+
+Environment:
+
+ User Mode
+
+--*/
+#include "precomp.h"
+#pragma hdrstop
+
+#include "isnipx.h"
+#include "config.h"
+#include "mac.h"
+#include "ipxtypes.h"
+//#include "ipxprocs.h"
+
+#define LIMIT_BINDINGS 10
+
+//
+// Local function prototypes
+//
+VOID DumpDeviceObject
+(
+ ULONG DevObjToDump,
+ VERBOSITY Verbosity
+);
+
+VOID
+DumpIpxDevice
+(
+ ULONG DeviceToDump,
+ VERBOSITY Verbosity
+);
+
+VOID
+DumpIpxSend
+(
+ ULONG IpxSendToDump,
+ VERBOSITY Verbosity
+);
+
+VOID
+DumpIpxReceive
+(
+ ULONG IpxReceiveToDump,
+ VERBOSITY Verbosity
+);
+
+VOID
+DumpIpxAddress
+(
+ ULONG AddressToDump,
+ VERBOSITY Verbosity
+);
+
+VOID
+DumpIpxAddressFile
+(
+ ULONG AddressFileToDump,
+ VERBOSITY Verbosity
+);
+
+VOID
+DumpIpxBinding
+(
+ ULONG BindingToDump,
+ VERBOSITY Verbosity
+);
+
+VOID
+DumpIpxRequest
+(
+ ULONG RequestToDump,
+ VERBOSITY Verbosity
+);
+
+VOID
+DumpIpxAdapter
+(
+ ULONG AdapterToDump,
+ VERBOSITY Verbosity
+);
+
+VOID
+DumpIpxIrpStack
+(
+ PREQUEST pRequest,
+ VERBOSITY Verbosity
+);
+
+
+ENUM_INFO EnumIrpMajorFunction[] =
+{
+ EnumString( IRP_MJ_CREATE ),
+ EnumString( IRP_MJ_CREATE_NAMED_PIPE ),
+ EnumString( IRP_MJ_CLOSE ),
+ EnumString( IRP_MJ_READ ),
+ EnumString( IRP_MJ_WRITE ),
+ EnumString( IRP_MJ_QUERY_INFORMATION ),
+ EnumString( IRP_MJ_SET_INFORMATION ),
+ EnumString( IRP_MJ_QUERY_EA ),
+ EnumString( IRP_MJ_SET_EA ),
+ EnumString( IRP_MJ_FLUSH_BUFFERS ),
+ EnumString( IRP_MJ_QUERY_VOLUME_INFORMATION ),
+ EnumString( IRP_MJ_SET_VOLUME_INFORMATION ),
+ EnumString( IRP_MJ_DIRECTORY_CONTROL ),
+ EnumString( IRP_MJ_FILE_SYSTEM_CONTROL ),
+ EnumString( IRP_MJ_DEVICE_CONTROL ),
+ EnumString( IRP_MJ_INTERNAL_DEVICE_CONTROL ),
+ EnumString( IRP_MJ_SHUTDOWN ),
+ EnumString( IRP_MJ_LOCK_CONTROL ),
+ EnumString( IRP_MJ_CLEANUP ),
+ EnumString( IRP_MJ_CREATE_MAILSLOT ),
+ EnumString( IRP_MJ_QUERY_SECURITY ),
+ EnumString( IRP_MJ_SET_SECURITY ),
+ EnumString( IRP_MJ_QUERY_POWER ),
+ EnumString( IRP_MJ_NOT_DEFINED ),
+ EnumString( IRP_MJ_DEVICE_CHANGE ),
+ EnumString( IRP_MJ_QUERY_QUOTA ),
+ EnumString( IRP_MJ_SET_QUOTA ),
+ { 0, NULL }
+};
+
+ENUM_INFO EnumIrpMinorFunction[ IRP_MJ_MAXIMUM_FUNCTION + 1 ][ 18 ] =
+{
+ {{ 0, NULL}}, // IRP_MJ_CREATE
+ {{ 0, NULL}}, // IRP_MJ_CREATE_NAMED_PIPE
+ {{ 0, NULL}}, // IRP_MJ_CLOSE
+ {{ 0, NULL}}, // IRP_MJ_READ
+ {{ 0, NULL}}, // IRP_MJ_WRITE
+ {{ 0, NULL}}, // IRP_MJ_QUERY_INFORMATION
+ {{ 0, NULL}}, // IRP_MJ_SET_INFORMATION
+ {{ 0, NULL}}, // IRP_MJ_QUERY_EA
+ {{ 0, NULL}}, // IRP_MJ_SET_EA
+ {{ 0, NULL}}, // IRP_MJ_FLUSH_BUFFERS
+ {{ 0, NULL}}, // IRP_MJ_QUERY_VOLUME_INFORMATION
+ {{ 0, NULL}}, // IRP_MJ_SET_VOLUME_INFORMATION
+ {{ 0, NULL}}, // IRP_MJ_DIRECTORY_CONTROL
+ {{ 0, NULL}}, // IRP_MJ_FILE_SYSTEM_CONTROL
+ {{ 0, NULL}}, // IRP_MJ_DEVICE_CONTROL
+ { // IRP_MJ_INTERNAL_DEVICE_CONTROL
+ EnumString( TDI_ASSOCIATE_ADDRESS ),
+ EnumString( TDI_DISASSOCIATE_ADDRESS ),
+ EnumString( TDI_CONNECT ),
+ EnumString( TDI_LISTEN ),
+ EnumString( TDI_ACCEPT ),
+ EnumString( TDI_DISCONNECT ),
+ EnumString( TDI_SEND ),
+ EnumString( TDI_RECEIVE ),
+ EnumString( TDI_SEND_DATAGRAM ),
+ EnumString( TDI_RECEIVE_DATAGRAM ),
+ EnumString( TDI_SET_EVENT_HANDLER ),
+ EnumString( TDI_QUERY_INFORMATION ),
+ EnumString( TDI_SET_INFORMATION ),
+ EnumString( TDI_ACTION ),
+ EnumString( TDI_DIRECT_SEND ),
+ EnumString( TDI_DIRECT_SEND_DATAGRAM ),
+ { 0, NULL }
+ },
+ {{ 0, NULL}}, // IRP_MJ_SHUTDOWN
+ {{ 0, NULL}}, // IRP_MJ_LOCK_CONTROL
+ {{ 0, NULL}}, // IRP_MJ_CLEANUP
+ {{ 0, NULL}}, // IRP_MJ_CREATE_MAILSLOT
+ {{ 0, NULL}}, // IRP_MJ_QUERY_SECURITY
+ {{ 0, NULL}}, // IRP_MJ_SET_SECURITY
+ {{ 0, NULL}}, // IRP_MJ_QUERY_POWER
+ {{ 0, NULL}}, // IRP_MJ_SET_POWER
+ {{ 0, NULL}}, // IRP_MJ_DEVICE_CHANGE
+ {{ 0, NULL}}, // IRP_MJ_QUERY_QUOTA
+ {{ 0, NULL}}, // IRP_MJ_SET_QUOTA
+};
+
+
+ENUM_INFO EnumAddressFileState[] =
+{
+ EnumString( ADDRESSFILE_STATE_OPENING ),
+ EnumString( ADDRESSFILE_STATE_OPEN ),
+ EnumString( ADDRESSFILE_STATE_CLOSING ),
+ { 0, NULL }
+};
+
+
+ENUM_INFO EnumBindingFrameType[] =
+{
+ EnumString( ISN_FRAME_TYPE_802_2 ),
+ EnumString( ISN_FRAME_TYPE_802_3 ),
+ EnumString( ISN_FRAME_TYPE_ETHERNET_II ),
+ EnumString( ISN_FRAME_TYPE_SNAP ),
+ { 0, NULL }
+};
+
+ENUM_INFO EnumSendReservedIdentifier[] =
+{
+ EnumString( IDENTIFIER_NB ),
+ EnumString( IDENTIFIER_SPX ),
+ EnumString( IDENTIFIER_RIP ),
+ EnumString( IDENTIFIER_IPX ),
+ EnumString( IDENTIFIER_RIP_INTERNAL ),
+ EnumString( IDENTIFIER_RIP_RESPONSE ),
+
+ { 0, NULL }
+};
+
+ENUM_INFO EnumSendReservedDestinationType[] =
+{
+ EnumString( DESTINATION_DEF ),
+ EnumString( DESTINATION_BCAST ),
+ EnumString( DESTINATION_MCAST ),
+ { 0, NULL }
+};
+
+MEMBER_TABLE IpxDeviceMembers[] =
+{
+ { "GlobalSendPacketList",
+ FIELD_OFFSET( DEVICE, GlobalSendPacketList ),
+ DumpIpxSend,
+ NextListEntry,
+ PrevListEntry,
+ FIELD_OFFSET( NDIS_PACKET, ProtocolReserved ) + FIELD_OFFSET( IPX_SEND_RESERVED, GlobalLinkage )
+ },
+
+ { "GlobalReceivePacketList",
+ FIELD_OFFSET( DEVICE, GlobalReceivePacketList ),
+ DumpIpxReceive,
+ NextListEntry,
+ PrevListEntry,
+ FIELD_OFFSET( NDIS_PACKET, ProtocolReserved ) + FIELD_OFFSET( IPX_RECEIVE_RESERVED, GlobalLinkage )
+ },
+
+ { NULL }
+};
+
+
+///////////////////////////////////////////////////////////////////////
+// DEVICE
+//////////////////////////////////////////////////////////////////////
+
+
+//
+// Exported functions
+//
+
+
+
+VOID ipxdev_usage( VOID )
+{
+ dprintf( "Use me!\n" );
+}
+
+DECLARE_API( ipxdev )
+
+/*++
+
+Routine Description:
+
+ Dumps the most important fields of the specified DEVICE_CONTEXT object
+
+Arguments:
+
+ args - Address
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG deviceToDump = 0;
+ ULONG pDevice = 0;
+ ULONG result;
+ char VarName[ MAX_LIST_VARIABLE_NAME_LENGTH + 1 ];
+ MEMBER_VARIABLE_INFO MemberInfo;
+ BOOL bFocusOnMemberVariable = FALSE;
+
+ if ( *args )
+ {
+ bFocusOnMemberVariable = ReadArgsForTraverse( args, VarName );
+ }
+
+ if ( *args && *args!='-' )
+ {
+ sscanf(args, "%lx", &deviceToDump);
+ }
+
+ if ( deviceToDump == 0 ) {
+
+ pDevice = GetExpression( "nwlnkipx!IpxDevice" );
+
+ if ( !pDevice ) {
+ dprintf("Could not get nwlnkipx!IpxDevice, Try !reload\n");
+ return;
+ } else {
+
+ if (!ReadMemory(pDevice,
+ &deviceToDump,
+ sizeof(deviceToDump),
+ &result
+ )
+ )
+ {
+ dprintf("%08lx: Could not read device address\n", pDevice);
+ return;
+ }
+ }
+
+ }
+
+ if ( bFocusOnMemberVariable )
+ {
+ if ( !LocateMemberVariable( "IpxDevice", VarName, ( PVOID )deviceToDump, &MemberInfo ))
+ {
+ return;
+ }
+
+ WriteMemberInfo( &MemberInfo );
+ next( hCurrentProcess, hCurrentThread, dwCurrentPc, dwProcessor, "" );
+ return;
+ }
+
+ DumpIpxDevice(deviceToDump, VERBOSITY_NORMAL );
+
+ return;
+}
+
+
+
+#ifdef _obj
+# undef _obj
+# undef _objAddr
+# undef _objType
+#endif
+
+#define _obj Device
+#define _objAddr DeviceToDump
+#define _objType DEVICE
+//
+// Local functions
+//
+
+VOID
+DumpIpxDevice
+(
+ ULONG DeviceToDump,
+ VERBOSITY Verbosity
+)
+
+/*++
+
+Routine Description:
+
+ Dumps the fields of the specified DEVICE_CONTEXT structure
+
+Arguments:
+
+ DeviceToDump - The device context object to display
+ Full - Display a partial listing if 0, full listing otherwise.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ DEVICE Device;
+ ULONG result;
+ unsigned int index;
+ BIND_ARRAY_ELEM Bindings[ LIMIT_BINDINGS ];
+ WCHAR Buffer[ 1000 ];
+ PWCHAR pDeviceName = NULL;
+
+ if (!ReadMemory(
+ DeviceToDump,
+ &Device,
+ sizeof(Device),
+ &result
+ )
+ )
+ {
+ dprintf("%08lx: Could not read device context\n", DeviceToDump);
+ return;
+ }
+ if (Device.Type != IPX_DEVICE_SIGNATURE)
+ {
+ dprintf( "Signature does not match, probably not a device object %lx\n", DeviceToDump);
+ dprintf( "Device.Type == %04X, and I think it should be %04X\n", Device.Type, IPX_DEVICE_SIGNATURE );
+ dprintf( "DeviceToDump = %08X\n", DeviceToDump );
+ dprintf( "Offset to Device.Type = %d\n", FIELD_OFFSET( DEVICE, Type ) );
+ return;
+ }
+
+ if ( !ReadMemory( ( ULONG )Device.DeviceName,
+ Buffer,
+ sizeof( WCHAR ) * Device.DeviceNameLength,
+ &result ))
+ {
+ dprintf("%08lx: Could not read device name buffer\n", Device.DeviceName );
+ }
+ else
+ {
+ pDeviceName = Buffer;
+ }
+
+ if ( Verbosity == VERBOSITY_ONE_LINER )
+ {
+ dprintf( "\"%S\"", pDeviceName );
+ return;
+ }
+
+ dprintf("Device General Info ");
+ PrintStartStruct();
+
+#if DBG
+# if DREF_TOTAL != 12
+# error The DREF_TOTAL constant has changed, and so must ipxext.c
+# endif
+
+ PrintULong( RefTypes[ DREF_CREATE ] );
+ PrintULong( RefTypes[ DREF_LOADED ] );
+ PrintULong( RefTypes[ DREF_ADAPTER ] );
+ PrintULong( RefTypes[ DREF_ADDRESS ] );
+ PrintULong( RefTypes[ DREF_SR_TIMER ] );
+ PrintULong( RefTypes[ DREF_RIP_TIMER ] );
+ PrintULong( RefTypes[ DREF_LONG_TIMER ] );
+ PrintULong( RefTypes[ DREF_RIP_PACKET ] );
+ PrintULong( RefTypes[ DREF_ADDRESS_NOTIFY ] );
+ PrintULong( RefTypes[ DREF_LINE_CHANGE ] );
+ PrintULong( RefTypes[ 10 ] );
+ PrintULong( RefTypes[ 11 ] );
+#endif
+
+ PrintEnum( Type, EnumStructureType );
+ PrintUShort( Size );
+
+#if DBG
+ PrintNChar( Signature1, sizeof( Device.Signature1 ));
+#endif
+
+ PrintLock( Interlock );
+
+ PrintULong( TempDatagramBytesSent );
+ PrintULong( TempDatagramsSent );
+ PrintULong( TempDatagramBytesReceived );
+ PrintULong( TempDatagramsReceived );
+
+ PrintBool( EthernetPadToEven );
+ PrintBool( SingleNetworkActive );
+ PrintBool( DisableDialoutSap );
+ PrintBool( MultiCardZeroVirtual );
+
+ PrintLock( Lock );
+
+ PrintULong( ReferenceCount );
+
+ PrintStartStruct();
+ dprintf( " ( We are assumed not to be at init time )\n" );
+ PrintULong( BindingCount );
+
+ if ( Device.BindingCount > LIMIT_BINDINGS )
+ {
+ dprintf(" isnext can only display the first %d bindings, because malloc() always crashed under the kernel debugger.\n", LIMIT_BINDINGS );
+ dprintf(" This device struct has more bindings than that, but you're only going to see some of them.\n" );
+ dprintf(" You could always change LIMIT_BINDINGS in ipxext.c and recompile isnext\n" );
+
+ Device.BindingCount = LIMIT_BINDINGS;
+ }
+
+ if ( !ReadMemory( ( ULONG )Device.Bindings,
+ Bindings,
+ sizeof( PBIND_ARRAY_ELEM ) * Device.BindingCount,
+ &result ) )
+ {
+ dprintf( "Could not read Bindings array.\n" );
+ }
+ else
+ {
+ for( index = 0; index <= Device.ValidBindings; index ++ )
+ {
+ dprintf( " Bindings[ %d ] = %-10X", index, Bindings[ index ].Binding );
+ if ( Bindings[ index ].Binding != NULL )
+ {
+ DumpIpxBinding( ( ULONG )Bindings[ index ].Binding, VERBOSITY_ONE_LINER );
+ }
+ dprintf( "\n" );
+ }
+ }
+ PrintEndStruct();
+
+ PrintUShort( ValidBindings );
+ PrintUShort( HighestExternalNicId );
+ PrintUShort( SapNicCount );
+ PrintUShort( HighestType20NicId );
+
+ PrintLL( GlobalSendPacketList );
+ PrintLL( GlobalReceivePacketList );
+ PrintLL( GlobalReceiveBufferList );
+
+ PrintLL( AddressNotifyQueue );
+
+ PrintLL( LineChangeQueue );
+ PrintLL( SendPoolList );
+ PrintLL( ReceivePoolList );
+
+ PrintL( SendPacketList );
+ PrintL( ReceivePacketList );
+
+ PrintUChar( State );
+ PrintUChar( FrameTypeDefault );
+
+ PrintBool( ActiveNetworkWan );
+ PrintBool( VirtualNetwork );
+ PrintUShort( FirstLanNicId );
+ PrintUShort( FirstWanNicId );
+ PrintULong( MemoryUsage );
+ PrintULong( MemoryLimit );
+ PrintULong( AllocatedDatagrams );
+ PrintULong( AllocatedReceivePackets );
+ PrintULong( AllocatedPaddingBuffers );
+ PrintULong( InitDatagrams );
+ PrintULong( MaxDatagrams );
+ PrintULong( RipAgeTime );
+ PrintULong( RipCount );
+ PrintULong( RipTimeout );
+ PrintULong( RipUsageTime );
+ PrintULong( SourceRouteUsageTime );
+ PrintUShort( SocketStart );
+ PrintUShort( SocketEnd );
+ PrintULong( SocketUniqueness );
+ PrintULong( VirtualNetworkNumber );
+ PrintULong( EthernetExtraPadding );
+ PrintBool( DedicatedRouter );
+ PrintBool( VirtualNetworkOptional );
+ PrintUChar( DisableDialinNetbios );
+ PrintULong( InitReceivePackets );
+ PrintULong( InitReceiveBuffers );
+ PrintULong( MaxReceivePackets );
+ PrintULong( MaxReceiveBuffers );
+ PrintUShort( ControlChannelIdentifier );
+ PrintUShort( CurrentSocket );
+ PrintULong( SegmentCount );
+
+ // MORE - dump actual locks
+ PrintPtr( SegmentLocks );
+
+ PrintLL( WaitingRipPackets );
+ PrintULong( RipPacketCount );
+ PrintBool( RipShortTimerActive );
+ PrintUShort( RipSendTime );
+
+ PrintCTETimer( RipShortTimer );
+ PrintCTETimer( RipLongTimer );
+
+ PrintBool( SourceRoutingUsed ); // TRUE if any 802.5 bindings exist.
+ PrintUChar( SourceRoutingTime ); // incremented each time timer fires.
+ PrintCTETimer( SourceRoutingTimer );
+ PrintULong( LinkSpeed );
+ PrintULong( MacOptions );
+ PrintULong( IncludedHeaderOffset );
+ PrintTDIAddress( SourceAddress );
+
+#if IPX_ADDRESS_HASH_COUNT != 16
+# error An assumption is made here concerning the value of IPX_ADDRESS_HASH_COUNT
+#endif
+
+ PrintLL( AddressDatabases[ 0 ] );
+ PrintLL( AddressDatabases[ 1 ] );
+ PrintLL( AddressDatabases[ 2 ] );
+ PrintLL( AddressDatabases[ 3 ] );
+ PrintLL( AddressDatabases[ 4 ] );
+ PrintLL( AddressDatabases[ 5 ] );
+ PrintLL( AddressDatabases[ 6 ] );
+ PrintLL( AddressDatabases[ 7 ] );
+ PrintLL( AddressDatabases[ 8 ] );
+ PrintLL( AddressDatabases[ 9 ] );
+ PrintLL( AddressDatabases[ 10 ] );
+ PrintLL( AddressDatabases[ 11 ] );
+ PrintLL( AddressDatabases[ 12 ] );
+ PrintLL( AddressDatabases[ 13 ] );
+ PrintLL( AddressDatabases[ 14 ] );
+ PrintLL( AddressDatabases[ 15 ] );
+
+ PrintPtr( LastAddress );
+
+ PrintPtr( NdisBufferPoolHandle );
+ PrintAddr( Information );
+ PrintULong( RealMaxDatagramSize );
+
+#if DBG
+ PrintNChar( Signature2, sizeof( Device.Signature2 ));
+#endif
+
+ PrintFlushLeft();
+ PrintBool( AnyUpperDriverBound );
+ PrintBool( ForwarderBound );
+
+ if ( Device.AnyUpperDriverBound )
+ {
+ for ( index = 0; index < UPPER_DRIVER_COUNT; index ++ )
+ {
+ PrintFlushLeft();
+
+ dprintf( "UpperDriver...[ %d ] = ", index );
+ PrintStartStruct();
+
+ PrintFieldName( "UpperDriverBound" );
+ PrintRawBool( UpperDriverBound[ index ] );
+
+ if ( !Device.UpperDriverBound[ index ] )
+ {
+ PrintEndStruct();
+ continue;
+ }
+
+ PrintFieldName( "ReceiveCompletePending" );
+ PrintRawBool( ReceiveCompletePending[ index ] );
+ PrintPtr( UpperDriverControlChannel[ index ] );
+
+ PrintSymbolPtr( UpperDrivers[ index ].ReceiveHandler );
+
+ PrintEndStruct();
+ }
+ }
+
+ PrintFlushLeft();
+
+ PrintULong( EnableBroadcastCount );
+ PrintBool( EnableBroadcastPending );
+ PrintBool( DisableBroadcastPending );
+ PrintBool( ReverseBroadcastOperation );
+ PrintBool( WanGlobalNetworkNumber );
+ PrintULong( GlobalWanNetwork );
+ PrintBool( GlobalNetworkIndicated );
+ PrintBool( RipResponder );
+ PrintBool( SapWarningLogged );
+
+ PrintWorkQueueItem( BroadcastOperationQueueItem );
+ PrintAddr( UnloadEvent );
+ PrintBool( UnloadWaiting );
+ PrintAddr( Statistics );
+ PrintBool( AutoDetect );
+ PrintBool( DefaultAutoDetected );
+ PrintUChar( AutoDetectState );
+
+ PrintAddr( AutoDetectEvent );
+ PrintAddr( IpxStartTime );
+ PrintAddr( AddressResource );
+ PrintPtr( DeviceObject );
+
+ PrintJoin();
+ PrintPtr( DeviceName );
+ dprintf( "\"%S\"\n", pDeviceName );
+
+ PrintULong( DeviceNameLength );
+
+
+
+ PrintEndStruct();
+ PrintEnd
+
+ return;
+}
+
+
+#ifdef _obj
+# undef _obj
+# undef _objAddr
+# undef _objType
+#endif
+
+#define _obj Reserved
+#define _objAddr pReserved
+#define _objType IPX_SEND_RESERVED
+
+VOID
+DumpIpxSend
+(
+ ULONG IpxSendToDump,
+ VERBOSITY Verbosity
+)
+{
+ PIPX_SEND_RESERVED pReserved;
+ IPX_SEND_RESERVED Reserved;
+ ULONG result;
+
+
+ pReserved = SEND_RESERVED(( PIPX_SEND_PACKET )IpxSendToDump );
+
+ if ( !ReadMemory( ( ULONG )pReserved,
+ &Reserved,
+ sizeof( Reserved ),
+ &result ))
+ {
+ dprintf("%08lx: Could not read IPX_SEND_RESERVED structure\n", pReserved );
+ return;
+ }
+
+ dprintf( "NDIS_PACKET @(0x%08X) ", IpxSendToDump );
+
+ if ( Verbosity == VERBOSITY_ONE_LINER )
+ {
+ dprintf( "{ " );
+ if ( Reserved.Address != NULL )
+ {
+ DumpIpxAddress( ( ULONG )( Reserved.Address ), VERBOSITY_ONE_LINER );
+ }
+ else
+ {
+ dprintf( "(NULL Address)" );
+ }
+
+ dprintf( " (" );
+ dprint_enum_name( (ULONG) _obj.Identifier, EnumSendReservedIdentifier );
+ dprintf( ") }" );
+ return;
+ }
+
+
+ PrintStart;
+ PrintStartStruct();
+
+ PrintEnum( Identifier, EnumSendReservedIdentifier );
+
+ PrintBool( SendInProgress );
+ PrintBool( OwnedByAddress );
+
+ PrintEnum( DestinationType, EnumSendReservedDestinationType );
+
+ PrintPtr( PaddingBuffer );
+ PrintPtr( PreviousTail );
+ PrintL( PoolLinkage );
+
+ PrintLL( GlobalLinkage );
+ PrintLL( WaitLinkage );
+#ifdef IPX_TRACK_POOL
+ PrintPtr( Pool );
+#endif
+ PrintJoin();
+ PrintPtr( Address );
+
+ if ( Reserved.Address != NULL )
+ {
+ DumpIpxAddress( ( ULONG )( Reserved.Address ), VERBOSITY_ONE_LINER );
+ }
+
+ dprintf( "\n" );
+
+ PrintFlushLeft();
+
+ switch ( Reserved.Identifier )
+ {
+ case IDENTIFIER_NB:
+ case IDENTIFIER_IPX:
+ case IDENTIFIER_SPX:
+ dprintf( " --- SR_DG part of union ---------------------------\n");
+ PrintPtr( u.SR_DG.Request );
+ PrintJoin();
+ PrintPtr( u.SR_DG.AddressFile );
+ if ( Reserved.u.SR_DG.AddressFile != NULL )
+ {
+ DumpIpxAddressFile( ( ULONG )( Reserved.u.SR_DG.AddressFile ), VERBOSITY_ONE_LINER );
+ }
+
+ dprintf( "\n" );
+
+ PrintUShort( u.SR_DG.CurrentNicId );
+ PrintBool( u.SR_DG.Net0SendSucceeded );
+ PrintBool( u.SR_DG.OutgoingSap );
+ break;
+ case IDENTIFIER_RIP:
+ case IDENTIFIER_RIP_INTERNAL:
+ case IDENTIFIER_RIP_RESPONSE:
+ PrintStartStruct();
+ dprintf( " --- SR_RIP part of union ---------------------------\n");
+ PrintULong( u.SR_RIP.Network );
+ PrintUShort( u.SR_RIP.CurrentNicId );
+ PrintUChar( u.SR_RIP.RetryCount );
+ PrintBool( u.SR_RIP.RouteFound );
+ PrintUShort( u.SR_RIP.SendTime );
+ PrintBool( u.SR_RIP.NoIdAdvance );
+ break;
+ default:
+ dprintf( "*** Couldn't determine which part of union to display.\n" );
+ }
+
+ PrintFlushLeft();
+
+ PrintPtr( Header );
+
+ PrintJoin();
+ PrintPtr( HeaderBuffer );
+ DumpMdlChain( ( ULONG )_obj.HeaderBuffer, VERBOSITY_ONE_LINER );
+ dprintf( "\n" );
+
+ PrintEndStruct();
+
+ PrintEnd;
+}
+
+#ifdef _obj
+# undef _obj
+# undef _objAddr
+# undef _objType
+#endif
+
+#define _obj Reserved
+#define _objAddr pReserved
+#define _objType IPX_RECEIVE_RESERVED
+
+VOID
+DumpIpxReceive
+(
+ ULONG IpxReceiveToDump,
+ VERBOSITY Verbosity
+)
+{
+ _objType *_objAddr;
+ _objType _obj;
+ ULONG result;
+
+ dprintf( "NDIS_PACKET at 0x%08X\n", IpxReceiveToDump );
+
+ pReserved = RECEIVE_RESERVED(( PIPX_SEND_PACKET )IpxReceiveToDump );
+
+ if ( !ReadMemory( IpxReceiveToDump,
+ &_obj,
+ sizeof( _obj ),
+ &result ))
+ {
+ dprintf("%08lx: Could not read IPX_SEND_RESERVED structure\n", _objAddr );
+ return;
+ }
+
+ PrintStartStruct();
+
+ PrintEnum( Identifier, EnumSendReservedIdentifier );
+
+ PrintBool( TransferInProgress );
+ PrintBool( OwnedByAddress );
+
+#ifdef IPX_TRACK_POOL
+ PrintPtr( Pool );
+#endif
+ PrintJoin();
+ PrintPtr( Address );
+ if ( Reserved.Address != NULL )
+ {
+ DumpIpxAddress( ( ULONG )( Reserved.Address ), VERBOSITY_ONE_LINER );
+ }
+ dprintf( "\n" );
+
+ PrintPtr( SingleRequest );
+ PrintPtr( ReceiveBuffer );
+
+ PrintL( PoolLinkage );
+
+ PrintLL( GlobalLinkage );
+ PrintLL( Requests );
+
+ PrintEndStruct();
+}
+
+
+DECLARE_API( ipxaddrfile )
+{
+ ULONG AddressFileToDump = 0;
+ ULONG result;
+ char VarName[ MAX_LIST_VARIABLE_NAME_LENGTH + 1 ];
+ MEMBER_VARIABLE_INFO MemberInfo;
+ BOOL bFocusOnMemberVariable = FALSE;
+
+ if ( *args )
+ {
+ bFocusOnMemberVariable = ReadArgsForTraverse( args, VarName );
+ }
+
+ if ( *args && *args!='-' )
+ {
+ sscanf(args, "%lx", &AddressFileToDump);
+ }
+
+ if ( AddressFileToDump == 0 )
+ {
+ dprintf( "Please specify an address.\n" );
+ }
+
+ if ( bFocusOnMemberVariable )
+ {
+ if ( !LocateMemberVariable( "IpxAddressFile", VarName, ( PVOID )AddressFileToDump, &MemberInfo ))
+ {
+ return;
+ }
+
+ WriteMemberInfo( &MemberInfo );
+ next( hCurrentProcess, hCurrentThread, dwCurrentPc, dwProcessor, "" );
+ return;
+ }
+
+ DumpIpxAddressFile( AddressFileToDump, VERBOSITY_FULL );
+
+ return;
+}
+
+#ifdef _obj
+# undef _obj
+# undef _objAddr
+# undef _objType
+#endif
+
+#define _obj AddressFile
+#define _objAddr prAddressFile
+#define _objType ADDRESS_FILE
+
+VOID
+DumpIpxAddressFile
+(
+ ULONG AddressFileToDump,
+ VERBOSITY Verbosity
+)
+{
+ _objType _obj;
+ _objType *_objAddr;
+ ULONG result;
+
+ _objAddr = ( _objType * )AddressFileToDump;
+
+ if ( !ReadMemory( AddressFileToDump,
+ &_obj,
+ sizeof( _obj ),
+ &result ))
+ {
+ dprintf( "%08lx: Could not read %s structure\n",
+ AddressFileToDump,
+ "ADDRESS_FILE" );
+ return;
+ }
+
+ if ( Verbosity == VERBOSITY_ONE_LINER )
+ {
+ switch ( _obj.State )
+ {
+ case ADDRESSFILE_STATE_OPENING:
+ dprintf( "OPENING " );
+ break;
+ case ADDRESSFILE_STATE_OPEN:
+ dprintf( "OPEN " );
+ break;
+ case ADDRESSFILE_STATE_CLOSING:
+ dprintf( "CLOSING " );
+ break;
+ default:
+ dprintf( "Bogus state " );
+ break;
+ }
+ DumpIpxAddress( ( ULONG )( AddressFile.Address ), VERBOSITY_ONE_LINER );
+ return;
+ }
+
+ PrintStartStruct();
+
+#if DBG
+# if AFREF_TOTAL != 8
+# error AFREF_TOTAL was assumed to equal 8
+# endif
+
+ PrintULong( RefTypes[ AFREF_CREATE ] );
+ PrintULong( RefTypes[ AFREF_RCV_DGRAM ] );
+ PrintULong( RefTypes[ AFREF_SEND_DGRAM ] );
+ PrintULong( RefTypes[ AFREF_VERIFY ] );
+ PrintULong( RefTypes[ AFREF_INDICATION ] );
+ PrintULong( RefTypes[ 5 ] );
+ PrintULong( RefTypes[ 6 ] );
+ PrintULong( RefTypes[ 7 ] );
+#endif
+
+ PrintEnum( Type, EnumStructureType );
+ PrintUShort( Size );
+
+ PrintLL( Linkage );
+
+ PrintULong( ReferenceCount );
+
+ PrintEnum( State, EnumAddressFileState );
+
+ PrintPtr( AddressLock );
+
+ PrintPtr( Request );
+
+ PrintJoin();
+ PrintPtr( Address );
+ if ( AddressFile.Address != NULL )
+ {
+ dprintf( "(" );
+ DumpIpxAddress( ( ULONG )( AddressFile.Address ), VERBOSITY_ONE_LINER );
+ dprintf( ")" );
+ }
+ dprintf( "\n" );
+
+#ifdef ISN_NT
+ PrintPtr( FileObject );
+#endif
+
+ PrintJoin();
+ PrintPtr( Device );
+ if ( AddressFile.Device != NULL )
+ {
+ DumpIpxDevice( ( ULONG )( AddressFile.Device ), VERBOSITY_ONE_LINER );
+ }
+ dprintf( "\n" );
+
+ PrintBool( SpecialReceiveProcessing );
+
+ PrintBool( ExtendedAddressing );
+ PrintBool( ReceiveFlagsAddressing );
+
+ PrintBool( ReceiveIpxHeader );
+
+ PrintUChar( DefaultPacketType );
+
+ PrintBool( FilterOnPacketType );
+
+ PrintUChar( FilteredType );
+
+ PrintBool( EnableBroadcast );
+
+ PrintBool( IsSapSocket );
+
+ PrintLL( ReceiveDatagramQueue );
+
+ PrintPtr( CloseRequest );
+
+ PrintBool( RegisteredReceiveDatagramHandler );
+ PrintBool( RegisteredErrorHandler );
+
+ PrintSymbolPtr( ReceiveDatagramHandler );
+ PrintXULong( ReceiveDatagramHandlerContext );
+
+ PrintSymbolPtr( ErrorHandler );
+ PrintXULong( ErrorHandlerContext );
+ PrintEndStruct();
+}
+
+DECLARE_API( ipxaddr )
+{
+ ULONG AddressToDump = 0;
+ ULONG result;
+ char VarName[ MAX_LIST_VARIABLE_NAME_LENGTH + 1 ];
+ MEMBER_VARIABLE_INFO MemberInfo;
+ BOOL bFocusOnMemberVariable = FALSE;
+
+ if ( *args )
+ {
+ bFocusOnMemberVariable = ReadArgsForTraverse( args, VarName );
+ }
+
+ if ( *args && *args!='-' )
+ {
+ sscanf(args, "%lx", &AddressToDump);
+ }
+
+ if ( AddressToDump == 0 )
+ {
+ dprintf( "Please specify an address.\n" );
+ }
+
+ if ( bFocusOnMemberVariable )
+ {
+ if ( !LocateMemberVariable( "IpxBinding", VarName, ( PVOID )AddressToDump, &MemberInfo ))
+ {
+ return;
+ }
+
+ WriteMemberInfo( &MemberInfo );
+ next( hCurrentProcess, hCurrentThread, dwCurrentPc, dwProcessor, "" );
+ return;
+ }
+
+ DumpIpxAddress( AddressToDump, VERBOSITY_FULL );
+
+ return;
+}
+
+#ifdef _obj
+# undef _obj
+# undef _objAddr
+# undef _objType
+#endif
+
+#define _obj Address
+#define _objAddr prAddress
+#define _objType ADDRESS
+
+VOID
+DumpIpxAddress
+(
+ ULONG AddressToDump,
+ VERBOSITY Verbosity
+)
+{
+ _objType _obj;
+ _objType *_objAddr;
+ ULONG result;
+
+ _objAddr = ( _objType * )AddressToDump;
+
+ if ( !ReadMemory( AddressToDump,
+ &_obj,
+ sizeof( _obj ),
+ &result ))
+ {
+ dprintf( "%08lx: Could not read %s structure\n",
+ AddressToDump,
+ "ADDRESS" );
+ return;
+ }
+
+ if ( Verbosity == VERBOSITY_ONE_LINER )
+ {
+ dprint_hardware_address( _obj.LocalAddress.NodeAddress );
+ dprintf( ".%d", Address.LocalAddress.Socket );
+ return;
+ }
+
+ PrintStartStruct();
+#if DBG
+# if AREF_TOTAL != 4
+# error AREF_TOTAL was assumed to equal 4
+# endif
+
+ PrintULong( RefTypes[ AREF_ADDRESS_FILE ] );
+ PrintULong( RefTypes[ AREF_LOOKUP ] );
+ PrintULong( RefTypes[ AREF_RECEIVE ] );
+ PrintULong( RefTypes[ 3 ] );
+#endif
+
+ PrintEnum( Type, EnumStructureType );
+ PrintUShort( Size );
+
+ PrintLL( Linkage );
+ PrintULong( ReferenceCount );
+ PrintLock( Lock );
+
+ PrintPtr( Request );
+
+ PrintUShort( Socket );
+ PrintUShort( SendSourceSocket );
+
+
+ PrintBool( Stopping );
+ PrintULong( Flags );
+
+ PrintJoin();
+ PrintPtr( Device );
+ if ( Address.Device != NULL )
+ {
+ DumpIpxDevice( ( ULONG )( Address.Device ), VERBOSITY_ONE_LINER );
+ }
+ dprintf( "\n" );
+
+ PrintPtr( DeviceLock );
+
+ PrintLL( AddressFileDatabase );
+
+ PrintTDIAddress( LocalAddress );
+
+ PrintAddr( SendPacket );
+ PrintAddr( ReceivePacket );
+
+ PrintAddr( SendPacketHeader );
+
+#ifdef ISN_NT
+ PrintStartStruct();
+
+ if ( Address.ReferenceCount )
+ {
+ PrintULong( u.ShareAccess.OpenCount );
+ PrintULong( u.ShareAccess.Readers );
+ PrintULong( u.ShareAccess.Writers );
+ PrintULong( u.ShareAccess.Deleters );
+ PrintULong( u.ShareAccess.SharedRead );
+ PrintULong( u.ShareAccess.SharedWrite );
+ PrintULong( u.ShareAccess.SharedDelete );
+ }
+ else
+ {
+ PrintWorkQueueItem( u.DestroyAddressQueueItem );
+ }
+
+ PrintEndStruct();
+
+ PrintPtr( SecurityDescriptor );
+#endif
+
+ PrintEndStruct();
+}
+
+
+DECLARE_API( ipxadapter )
+{
+ ULONG AdapterToDump = 0;
+ ULONG result;
+ char VarName[ MAX_LIST_VARIABLE_NAME_LENGTH + 1 ];
+ MEMBER_VARIABLE_INFO MemberInfo;
+ BOOL bFocusOnMemberVariable = FALSE;
+
+ if ( *args )
+ {
+ bFocusOnMemberVariable = ReadArgsForTraverse( args, VarName );
+ }
+
+ if ( *args && *args!='-' )
+ {
+ sscanf(args, "%lx", &AdapterToDump );
+ }
+
+ if ( AdapterToDump == 0 )
+ {
+ dprintf( "Please specify an address.\n" );
+ }
+
+ if ( bFocusOnMemberVariable )
+ {
+ if ( !LocateMemberVariable( "IpxAdapter", VarName, ( PVOID )AdapterToDump, &MemberInfo ))
+ {
+ return;
+ }
+
+ WriteMemberInfo( &MemberInfo );
+ next( hCurrentProcess, hCurrentThread, dwCurrentPc, dwProcessor, "" );
+ return;
+ }
+
+ DumpIpxAdapter( AdapterToDump, VERBOSITY_FULL );
+
+ return;
+}
+
+#ifdef _obj
+# undef _obj
+# undef _objAddr
+# undef _objType
+#endif
+
+#define _obj Adapter
+#define _objAddr prAdapter
+#define _objType ADAPTER
+
+VOID
+DumpIpxAdapter
+(
+ ULONG AdapterToDump,
+ VERBOSITY Verbosity
+)
+{
+ _objType _obj;
+ _objType *_objAddr;
+ ULONG result;
+ WCHAR Buffer[ 1000 ];
+ PWCHAR pAdapterName = NULL;
+
+ _objAddr = ( _objType * )AdapterToDump;
+
+ if ( !ReadMemory( AdapterToDump,
+ &_obj,
+ sizeof( _obj ),
+ &result ))
+ {
+ dprintf( "%08lx: Could not read %s structure\n",
+ AdapterToDump,
+ "ADAPTER" );
+ return;
+ }
+
+ if ( !ReadMemory( ( ULONG )Adapter.AdapterName,
+ Buffer,
+ sizeof( WCHAR ) * Adapter.AdapterNameLength,
+ &result ))
+ {
+ dprintf("%08lx: Could not read adapter name structure\n", Adapter.AdapterName );
+ }
+ else
+ {
+ pAdapterName = Buffer;
+ }
+
+ if ( Verbosity == VERBOSITY_ONE_LINER )
+ {
+ dprintf( "\"%S\"", pAdapterName );
+ return;
+ }
+
+ dprintf( "Adapter at 0x%08X\n", AdapterToDump );
+
+ PrintStart;
+
+ PrintEnum( Type, EnumStructureType );
+ PrintUShort( Size );
+#if DBG
+ PrintNChar( Signature1, sizeof( Adapter.Signature1 ));
+#endif
+
+ PrintULong( BindingCount );
+ PrintPtr( NdisBindingHandle );
+ PrintLL( RequestCompletionQueue );
+
+#if ISN_FRAME_TYPE_MAX !=4
+# error ISN_FRAME_TYPE_MAX is no longer 4.
+#endif
+
+ PrintULong( DefHeaderSizes[ ISN_FRAME_TYPE_ETHERNET_II ] );
+ PrintULong( BcMcHeaderSizes[ ISN_FRAME_TYPE_ETHERNET_II ] );
+ PrintPtr( Bindings[ ISN_FRAME_TYPE_ETHERNET_II ] );
+
+ PrintULong( DefHeaderSizes[ ISN_FRAME_TYPE_802_3 ] );
+ PrintULong( BcMcHeaderSizes[ ISN_FRAME_TYPE_802_3 ] );
+ PrintPtr( Bindings[ ISN_FRAME_TYPE_802_3 ] );
+
+ PrintULong( DefHeaderSizes[ ISN_FRAME_TYPE_802_2 ] );
+ PrintULong( BcMcHeaderSizes[ ISN_FRAME_TYPE_802_2 ] );
+ PrintPtr( Bindings[ ISN_FRAME_TYPE_802_2 ] );
+
+ PrintULong( DefHeaderSizes[ ISN_FRAME_TYPE_SNAP ] );
+ PrintULong( BcMcHeaderSizes[ ISN_FRAME_TYPE_SNAP ] );
+ PrintPtr( Bindings[ ISN_FRAME_TYPE_SNAP ] );
+
+ PrintULong( AllocatedReceiveBuffers );
+ PrintLL( ReceiveBufferPoolList );
+ PrintL( ReceiveBufferList );
+ PrintULong( AllocatedPaddingBuffers );
+ PrintL( PaddingBufferList );
+
+ PrintBool( BroadcastEnabled );
+ PrintBool( AutoDetectFound );
+ PrintBool( AutoDetectResponse );
+ PrintBool( DefaultAutoDetected );
+ PrintUShort( FirstWanNicId );
+ PrintUShort( LastWanNicId );
+ PrintULong( WanNicIdCount );
+ PrintUShort( BindSap );
+ PrintUShort( BindSapNetworkOrder );
+ PrintBool( SourceRouting );
+ PrintBool( EnableFunctionalAddress );
+ PrintBool( EnableWanRouter );
+ PrintULong( ConfigMaxPacketSize );
+
+ PrintJoin();
+ PrintPtr( AdapterName );
+ if ( pAdapterName != NULL )
+ {
+ dprintf( "\"%S\"", pAdapterName );
+ }
+ dprintf( "\n" );
+ PrintULong( AdapterNameLength );
+
+ PrintJoin();
+ PrintPtr( Device );
+ if ( Adapter.Device != NULL )
+ {
+ DumpIpxDevice( ( ULONG )( Adapter.Device ), VERBOSITY_ONE_LINER );
+ }
+ dprintf( "\n" );
+
+ PrintLock( Lock );
+ PrintPtr( DeviceLock );
+ PrintHardwareAddress( LocalMacAddress );
+ PrintUChar( LastSourceRoutingTime );
+
+ PrintAddr( NdisRequestEvent );
+ PrintXULong( NdisRequestStatus );
+ PrintXULong( OpenErrorStatus );
+
+ PrintStartStruct();
+
+ PrintULong( MacInfo.MediumType );
+ PrintULong( MacInfo.RealMediumType );
+ PrintBool( MacInfo.SourceRouting );
+ PrintBool( MacInfo.MediumAsync );
+ PrintUChar( MacInfo.BroadcastMask );
+ PrintULong( MacInfo.CopyLookahead );
+ PrintULong( MacInfo.MacOptions );
+ PrintULong( MacInfo.MinHeaderLength );
+ PrintULong( MacInfo.MaxHeaderLength );
+
+ PrintEndStruct();
+
+ PrintULong( MaxReceivePacketSize );
+ PrintULong( MaxSendPacketSize );
+ PrintULong( ReceiveBufferSpace );
+ PrintULong( MediumSpeed );
+
+#if IDENTIFIER_TOTAL != 4
+# error IDENTIFIER_TOTAL is assumed to equal 4
+#endif
+
+ PrintBool( SourceRoutingEmpty[IDENTIFIER_NB] );
+ PrintPtr( SourceRoutingHeads[IDENTIFIER_NB] );
+
+ PrintBool( SourceRoutingEmpty[IDENTIFIER_IPX] );
+ PrintPtr( SourceRoutingHeads[IDENTIFIER_IPX] );
+
+ PrintBool( SourceRoutingEmpty[IDENTIFIER_SPX] );
+ PrintPtr( SourceRoutingHeads[IDENTIFIER_SPX] );
+
+ PrintBool( SourceRoutingEmpty[IDENTIFIER_RIP] );
+ PrintPtr( SourceRoutingHeads[IDENTIFIER_RIP] );
+
+ PrintEnd;
+}
+
+DECLARE_API( ipxbinding )
+{
+ ULONG BindingToDump = 0;
+ ULONG result;
+ char VarName[ MAX_LIST_VARIABLE_NAME_LENGTH + 1 ];
+ MEMBER_VARIABLE_INFO MemberInfo;
+ BOOL bFocusOnMemberVariable = FALSE;
+
+ if ( *args )
+ {
+ bFocusOnMemberVariable = ReadArgsForTraverse( args, VarName );
+ }
+
+ if ( *args && *args!='-' )
+ {
+ sscanf(args, "%lx", &BindingToDump);
+ }
+
+ if ( BindingToDump == 0 )
+ {
+ dprintf( "Please specify an address.\n" );
+ }
+
+ if ( bFocusOnMemberVariable )
+ {
+ if ( !LocateMemberVariable( "IpxBinding", VarName, ( PVOID )BindingToDump, &MemberInfo ))
+ {
+ return;
+ }
+
+ WriteMemberInfo( &MemberInfo );
+ next( hCurrentProcess, hCurrentThread, dwCurrentPc, dwProcessor, "" );
+ return;
+ }
+
+ DumpIpxBinding( BindingToDump, VERBOSITY_FULL );
+
+ return;
+}
+
+#ifdef _obj
+# undef _obj
+# undef _objAddr
+# undef _objType
+#endif
+
+#define _obj Binding
+#define _objAddr pBinding
+#define _objType BINDING
+
+VOID
+DumpIpxBinding
+(
+ ULONG BindingToDump,
+ VERBOSITY Verbosity
+)
+{
+ BINDING Binding;
+ PBINDING pBinding;
+ ULONG result;
+
+ pBinding = ( PBINDING )BindingToDump;
+
+ if ( !ReadMemory( BindingToDump,
+ &Binding,
+ sizeof( Binding ),
+ &result ))
+ {
+ dprintf("%08lx: Could not read BINDING structure\n", BindingToDump );
+ return;
+ }
+
+ if ( Verbosity == VERBOSITY_ONE_LINER )
+ {
+ if ( Binding.Adapter != NULL )
+ {
+ DumpIpxAdapter( ( ULONG )( Binding.Adapter ), VERBOSITY_ONE_LINER );
+ }
+
+ dprintf( " %s\n", Binding.LineUp ? "UP" : "DOWN" );
+ return;
+ }
+
+ dprintf( "Binding at 0x%08X\n", BindingToDump );
+
+ PrintStart;
+ PrintStartStruct();
+
+#if DBG
+# if BREF_TOTAL != 5
+# error The BREF_TOTAL constant has changed, and so must ipxext.c
+# endif
+
+ PrintULong( RefTypes[ 0 ] );
+ PrintULong( RefTypes[ BREF_BOUND ] );
+ PrintULong( RefTypes[ 2 ] );
+ PrintULong( RefTypes[ 3 ] );
+ PrintULong( RefTypes[ 4 ] );
+#endif
+
+ PrintEnum( Type, EnumStructureType );
+ PrintUShort( Size );
+
+#if DBG
+ PrintNChar( Signature1, sizeof( Binding.Signature1 ));
+#endif
+
+ PrintULong( ReferenceCount );
+ PrintJoin();
+ PrintPtr( Adapter );
+
+ if ( Binding.Adapter != NULL )
+ {
+ DumpIpxAdapter( ( ULONG )( Binding.Adapter ), VERBOSITY_ONE_LINER );
+ }
+ dprintf( "\n" );
+
+ PrintUShort( NicId );
+
+ PrintULong( MaxSendPacketSize );
+
+ PrintJoin();
+ PrintULong( MediumSpeed ); // in units of 100 bytes/sec
+ dprintf( "(In units of 100 bytes/sec)\n" );
+
+ PrintHardwareAddress( LocalMacAddress );
+ PrintHardwareAddress( RemoteMacAddress );
+
+ PrintFieldName( "WanRemoteNode" );
+ dprint_hardware_address( Binding.WanRemoteNode );
+ dprintf( "\n" );
+
+ PrintBool( AutoDetect );
+
+ PrintBool( DefaultAutoDetect );
+
+ PrintUShort( MatchingResponses );
+ PrintUShort( NonMatchingResponses );
+ PrintXULong( TentativeNetworkAddress );
+ PrintBool( BindingSetMember );
+ PrintBool( ReceiveBroadcast );
+ PrintBool( LineUp );
+ PrintBool( DialOutAsync );
+
+ if ( Binding.BindingSetMember )
+ {
+ PrintPtr( NextBinding );
+ PrintPtr( CurrentSendBinding );
+ PrintPtr( MasterBinding );
+ }
+
+ PrintULong( WanInactivityCounter );
+
+ PrintTDIAddress( LocalAddress );
+
+ PrintSymbolPtr( SendFrameHandler );
+
+ PrintPtr( Device );
+
+ PrintJoin();
+ PrintPtr( DeviceLock );
+ if ( Binding.DeviceLock != NULL )
+ {
+ DumpCTELock( ( ULONG )Binding.DeviceLock, VERBOSITY_ONE_LINER );
+ }
+ dprintf( "\n" );
+
+ PrintULong( DefHeaderSize );
+ PrintULong( BcMcHeaderSize );
+
+ PrintULong( AnnouncedMaxDatagramSize );
+ PrintULong( RealMaxDatagramSize );
+ PrintULong( MaxLookaheadData );
+ PrintXULong( FwdAdapterContext );
+ PrintULong( InterfaceIndex );
+ PrintULong( ConnectionId );
+ PrintULong( IpxwanConfigRequired );
+
+ {
+ ULONG i;
+
+ for (i=0; i<UPPER_DRIVER_COUNT; i++) {
+ PrintBool( IsnInformed[i] );
+ }
+ }
+
+ PrintEnum( FrameType, EnumBindingFrameType );
+
+ PrintWorkQueueItem( WanDelayedQueueItem );
+ PrintEndStruct();
+ PrintEnd;
+}
+
+DECLARE_API( ipxrequest )
+{
+ ULONG RequestToDump = 0;
+ ULONG result;
+ char VarName[ MAX_LIST_VARIABLE_NAME_LENGTH + 1 ];
+ MEMBER_VARIABLE_INFO MemberInfo;
+ BOOL bFocusOnMemberVariable = FALSE;
+
+ if ( *args )
+ {
+ bFocusOnMemberVariable = ReadArgsForTraverse( args, VarName );
+ }
+
+ if ( *args && *args!='-' )
+ {
+ sscanf(args, "%lx", &RequestToDump);
+ }
+
+ if ( RequestToDump == 0 )
+ {
+ dprintf( "Please specify an address.\n" );
+ }
+
+ if ( bFocusOnMemberVariable )
+ {
+ if ( !LocateMemberVariable( "IpxRequest", VarName, ( PVOID )RequestToDump, &MemberInfo ))
+ {
+ return;
+ }
+
+ WriteMemberInfo( &MemberInfo );
+ next( hCurrentProcess, hCurrentThread, dwCurrentPc, dwProcessor, "" );
+ return;
+ }
+
+ DumpIpxRequest( RequestToDump, VERBOSITY_FULL );
+
+ return;
+}
+
+#ifdef _obj
+# undef _obj
+# undef _objAddr
+# undef _objType
+#endif
+
+#define _obj Request
+#define _objAddr prRequest
+#define _objType REQUEST
+
+VOID
+DumpIpxRequest
+(
+ ULONG RequestToDump,
+ VERBOSITY Verbosity
+)
+{
+ _objType _obj;
+ _objType *_objAddr;
+ ULONG result;
+
+ _objAddr = ( _objType * )RequestToDump;
+
+ if ( !ReadMemory( RequestToDump,
+ &_obj,
+ sizeof( _obj ),
+ &result ))
+ {
+ dprintf( "%08lx: Could not read %s structure\n",
+ RequestToDump,
+ "REQUEST" );
+ return;
+ }
+
+ PrintStartStruct();
+
+ DumpIpxIrpStack( &Request, VERBOSITY_FULL );
+
+ PrintEndStruct();
+}
+
+
+PDEVICE_OBJECT GetIpxDeviceObject( VOID )
+{
+ ULONG deviceToDump = 0;
+ ULONG prDevice = 0;
+ ULONG result;
+ DEVICE Device;
+
+ prDevice = GetExpression( "nwlnkipx!IpxDevice" );
+
+ if ( !prDevice )
+ {
+ dprintf("Could not get nwlnkipx!IpxDevice, Try !reload\n");
+ return( NULL );
+ }
+
+ if (!ReadMemory( prDevice,
+ &deviceToDump,
+ sizeof(deviceToDump),
+ &result ))
+ {
+ dprintf("%08lx: Could not read device address\n", prDevice);
+ return( NULL );
+ }
+
+ if ( !ReadMemory( deviceToDump,
+ &Device,
+ sizeof(Device),
+ &result ))
+ {
+ dprintf("%08lx: Could not read device context\n", deviceToDump);
+ return( NULL );
+ }
+
+ return( Device.DeviceObject );
+}
+
+#ifdef _obj
+# undef _obj
+# undef _objAddr
+# undef _objType
+#endif
+
+#define _obj ConnInfo
+#define _objAddr prConnInfo
+#define _objType TDI_CONNECTION_INFORMATION
+
+VOID
+DumpTdiConnectionInformation
+(
+ ULONG InformationToDump,
+ VERBOSITY Verbosity
+)
+{
+ _objType _obj;
+ _objType *_objAddr;
+ ULONG result;
+
+ _objAddr = ( _objType * )InformationToDump;
+
+ if ( !ReadMemory( InformationToDump,
+ &_obj,
+ sizeof( _obj ),
+ &result ))
+ {
+ dprintf( "%08lx: Could not read %s structure\n",
+ InformationToDump,
+ "TDI_CONNECTION_INFORMATION" );
+ return;
+ }
+
+ PrintStartStruct();
+ PrintULong( UserDataLength ); // length of user data buffer
+ PrintPtr( UserData ); // pointer to user data buffer
+ PrintULong( OptionsLength ); // length of follwoing buffer
+ PrintPtr( Options ); // pointer to buffer containing options
+ PrintULong( RemoteAddressLength ); // length of following buffer
+ PrintPtr( RemoteAddress ); // buffer containing the remote address
+ PrintEndStruct();
+}
+
+#ifdef _obj
+# undef _obj
+# undef _objAddr
+# undef _objType
+#endif
+
+#define _obj Parameters
+#define _objAddr prParameters
+#define _objType TDI_REQUEST_KERNEL_SENDDG
+
+VOID
+DumpTdiSendParameters
+(
+ ULONG ParametersToDump,
+ VERBOSITY Verbosity
+)
+{
+ _objType _obj;
+ _objType *_objAddr;
+ ULONG result;
+
+ _objAddr = ( _objType * )ParametersToDump;
+
+ if ( !ReadMemory( ParametersToDump,
+ &_obj,
+ sizeof( _obj ),
+ &result ))
+ {
+ dprintf( "%08lx: Could not read %s structure\n",
+ ParametersToDump,
+ "TDI_REQUEST_KERNEL_SENDDG" );
+ return;
+ }
+
+ PrintStartStruct();
+ PrintULong( SendLength );
+ PrintPtr( SendDatagramInformation );
+ DumpTdiConnectionInformation(( ULONG )_obj.SendDatagramInformation, Verbosity );
+
+ PrintEndStruct();
+}
+
+#ifdef _obj
+# undef _obj
+# undef _objAddr
+# undef _objType
+#endif
+
+#define _obj Stack
+#define _objAddr prStack
+#define _objType IO_STACK_LOCATION
+
+
+VOID
+DumpIpxIrpStack
+(
+ PREQUEST pRequest,
+ VERBOSITY Verbosity
+)
+/*++
+
+Routine Description:
+
+ Given an IRP of interest to the debugger, this routine will search that IRP's
+ stacks for the stack location that involves IPX. This stack location will be
+ dumped, and the file object contained in it will be followed. The file object
+ will then be used to ....
+
+ Matching the IRP stack locations to IPX requires finding the IPX device object
+ pointer from the ipxdev structure, and looking in the devobjects referred to
+ by the IRP to see if they refer to ipx.
+
+--*/
+{
+ _objType _obj;
+ _objType *_objAddr;
+ ULONG result;
+ PIO_STACK_LOCATION pStack;
+ ULONG StackToDump;
+ PDEVICE_OBJECT IpxDeviceObject;
+
+ CHAR idxStack;
+
+ IpxDeviceObject = GetIpxDeviceObject();
+
+ if ( IpxDeviceObject == NULL )
+ {
+ return;
+ }
+
+ prStack = pRequest->Tail.Overlay.CurrentStackLocation;
+
+ for ( idxStack = 0; idxStack < pRequest->StackCount; idxStack ++ )
+ {
+ StackToDump = ( ULONG )prStack;
+
+ if ( !ReadMemory( StackToDump,
+ &Stack,
+ sizeof( Stack ),
+ &result ))
+ {
+ dprintf( "%08lx: Could not read %s structure\n",
+ StackToDump,
+ "STACK" );
+ return;
+ }
+
+ if ( Stack.DeviceObject == IpxDeviceObject )
+ {
+ break;
+ }
+
+ prStack --;
+ }
+
+ if ( Stack.DeviceObject != IpxDeviceObject )
+ {
+ dprintf( "None of the device objects in this IRP's stacks seem to match the IPX device object.\n ");
+ return;
+ }
+
+ PrintStartStruct();
+
+ PrintXEnum( MajorFunction, EnumIrpMajorFunction );
+ PrintXEnum( MinorFunction, EnumIrpMinorFunction[ _obj.MajorFunction ] );
+
+ // Send? Dump Parameters
+
+ PrintAddr( Parameters );
+ DumpTdiSendParameters( AddressOf( Parameters ), VERBOSITY_FULL );
+
+ PrintXULong( Flags );
+ PrintXULong( Control );
+
+ PrintJoin();
+ PrintPtr( DeviceObject );
+ DumpDeviceObject(( ULONG ) Stack.DeviceObject, VERBOSITY_ONE_LINER );
+
+ PrintJoin();
+ PrintPtr( FileObject );
+
+ if ( Stack.FileObject != NULL )
+ {
+ FILE_OBJECT FileObject;
+ if ( !ReadMemory( ( ULONG )Stack.FileObject,
+ &FileObject,
+ sizeof( FileObject ),
+ &result ))
+ {
+ dprintf( "%08lx: Could not read FileObject", Stack.FileObject );
+ }
+ else
+ {
+ dprintf( "Addressfile at %8X: ", ( ULONG )FileObject.FsContext );
+ DumpIpxAddressFile( ( ULONG )FileObject.FsContext, VERBOSITY_ONE_LINER );
+ }
+ }
+ dprintf( "\n" );
+
+ PrintSymbolPtr( CompletionRoutine );
+ PrintXULong( Context );
+
+ PrintEndStruct();
+}
+
+#ifdef _obj
+# undef _obj
+# undef _objAddr
+# undef _objType
+#endif
+
+#define _obj DevObj
+#define _objAddr prDevObj
+#define _objType DEVICE_OBJECT
+
+VOID DumpDeviceObject
+(
+ ULONG DevObjToDump,
+ VERBOSITY Verbosity
+)
+{
+ _objType _obj;
+ _objType *_objAddr;
+ ULONG result;
+ PIO_STACK_LOCATION pStack;
+
+ _objAddr = ( _objType * )DevObjToDump;
+
+ if ( !ReadMemory( DevObjToDump,
+ &_obj,
+ sizeof( _obj ),
+ &result ))
+ {
+ dprintf( "%08lx: Could not read %s structure\n",
+ DevObjToDump,
+ "DEVICE_OBJECT" );
+ return;
+ }
+
+ if ( Verbosity != VERBOSITY_ONE_LINER )
+ {
+ dprintf( "DumpDeviceObject only support VERBOSITY_ONE_LINER.\n" );
+ }
+
+ dprintf( "Ref = %d, Driver = %08X, CurrentIrp = %08X\n",
+ _obj.ReferenceCount,
+ _obj.DriverObject,
+ _obj.CurrentIrp );
+}
+
diff --git a/private/ntos/tdi/isn/isnext/ipxext.h b/private/ntos/tdi/isn/isnext/ipxext.h
new file mode 100644
index 000000000..2b8dfac92
--- /dev/null
+++ b/private/ntos/tdi/isn/isnext/ipxext.h
@@ -0,0 +1,16 @@
+#if !defined( INCLUDED_IPXEXT_H )
+#define INCLUDED_IPXEXT_H
+
+extern MEMBER_TABLE IpxDeviceMembers[];
+
+VOID
+DumpIpxDevice
+(
+ ULONG DeviceToDump,
+ VERBOSITY Verbosity
+);
+
+#define IPX_MAJOR_STRUCTURES \
+{ "IpxDevice", IpxDeviceMembers, DumpIpxDevice }
+
+#endif
diff --git a/private/ntos/tdi/isn/isnext/isnext.c b/private/ntos/tdi/isn/isnext/isnext.c
new file mode 100644
index 000000000..5246508ad
--- /dev/null
+++ b/private/ntos/tdi/isn/isnext/isnext.c
@@ -0,0 +1,345 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ isnext.c
+
+Abstract:
+
+ This file contains the generic routines and initialization code
+ for the kernel debugger extensions dll.
+
+Author:
+
+ Munil Shah
+
+Environment:
+
+ User Mode
+
+--*/
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// globals
+//
+
+#include "isnipx.h"
+#include "isnspx.h"
+
+ENUM_INFO EnumStructureType[] =
+{
+ EnumString( IPX_DEVICE_SIGNATURE ),
+ EnumString( IPX_ADAPTER_SIGNATURE ),
+ EnumString( IPX_BINDING_SIGNATURE ),
+ EnumString( IPX_ADDRESS_SIGNATURE ),
+ EnumString( IPX_ADDRESSFILE_SIGNATURE ),
+ { 0x4453, "SPX_DEVICE_SIGNATURE" },
+ { 0x4441, "SPX_ADDRESS_SIGNATURE" },
+ { 0x4641, "SPX_ADDRESSFILE_SIGNATURE" },
+ { 0x4643, "SPX_CONNFILE_SIGNATURE" },
+ { 0, NULL }
+};
+
+EXT_API_VERSION ApiVersion = { 3, 5, EXT_API_VERSION_NUMBER, 0 };
+WINDBG_EXTENSION_APIS ExtensionApis;
+USHORT SavedMajorVersion;
+USHORT SavedMinorVersion;
+BOOLEAN ChkTarget;
+INT Item;
+
+HANDLE _hInstance;
+HANDLE _hAdditionalReference;
+HANDLE _hProcessHeap;
+
+int _Indent = 0;
+char IndentBuf[ 80 ]={"\0 "};
+
+DllInit(
+ HANDLE hModule,
+ DWORD dwReason,
+ DWORD dwReserved
+ )
+{
+ switch (dwReason) {
+ case DLL_THREAD_ATTACH:
+ break;
+
+ case DLL_THREAD_DETACH:
+ break;
+
+ case DLL_PROCESS_DETACH:
+ break;
+
+ case DLL_PROCESS_ATTACH:
+ _hInstance = hModule;
+ _hAdditionalReference = NULL;
+ break;
+ }
+
+ return TRUE;
+}
+
+
+VOID
+WinDbgExtensionDllInit(
+ PWINDBG_EXTENSION_APIS lpExtensionApis,
+ USHORT MajorVersion,
+ USHORT MinorVersion
+ )
+{
+ ExtensionApis = *lpExtensionApis;
+
+ SavedMajorVersion = MajorVersion;
+ SavedMinorVersion = MinorVersion;
+ ChkTarget = SavedMajorVersion == 0x0c ? TRUE : FALSE;
+ return;
+}
+
+DECLARE_API( version )
+{
+#if DBG
+ PCHAR DebuggerType = "Checked";
+#else
+ PCHAR DebuggerType = "Free";
+#endif
+
+ dprintf( "%s Extension dll for Build %d debugging %s kernel for Build %d\n",
+ DebuggerType,
+ VER_PRODUCTBUILD,
+ SavedMajorVersion == 0x0c ? "Checked" : "Free",
+ SavedMinorVersion
+ );
+}
+
+VOID
+CheckVersion(
+ VOID
+ )
+{
+
+ return;
+
+#if DBG
+ if ((SavedMajorVersion != 0x0c) || (SavedMinorVersion != VER_PRODUCTBUILD)) {
+ dprintf("\r\n*** Extension DLL(%d Checked) does not match target system(%d %s)\r\n\r\n",
+ VER_PRODUCTBUILD, SavedMinorVersion, (SavedMajorVersion==0x0f) ? "Free" : "Checked" );
+ }
+#else
+ if ((SavedMajorVersion != 0x0f) || (SavedMinorVersion != VER_PRODUCTBUILD)) {
+ dprintf("\r\n*** Extension DLL(%d Free) does not match target system(%d %s)\r\n\r\n",
+ VER_PRODUCTBUILD, SavedMinorVersion, (SavedMajorVersion==0x0f) ? "Free" : "Checked" );
+ }
+#endif
+}
+
+LPEXT_API_VERSION
+ExtensionApiVersion(
+ VOID
+ )
+{
+ return &ApiVersion;
+}
+
+//
+// Exported functions
+//
+DECLARE_API( help )
+
+/*++
+
+Routine Description:
+
+ Command help for ISN debugger extensions.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ dprintf("NB debugger extension commands:\n\n");
+ dprintf("\tnbaddr <ptr> - Dump an NB ADDRESS object\n");
+ dprintf("\tnbaddrfile <ptr> - Dump an NB ADDRESS_FILE object\n");
+ dprintf("\tnbconn <ptr> - Dump key fields of an NB CONNECTION object\n");
+ dprintf("\tnbconnfull <ptr> - Dump all fields of an NB CONNECTION object\n");
+ dprintf("\tnbdev [ptr] - Dump key fields of an NB DEVICE object\n");
+ dprintf("\tnbdevfull [ptr] - Dump all fields of an NB DEVICE object\n");
+ dprintf("\n");
+
+ dprintf("SPX debugger extension commands:\n\n");
+ dprintf("\tspxdev [ptr] [-l var] - Dump all fields of an IPX DEVICE object\n" );
+ dprintf("\tspxaddr <ptr>\n" );
+ dprintf("\tspxaddrfile <ptr>\n" );
+ dprintf("\tspxconnfile <ptr>\n" );
+ dprintf("\n");
+
+ dprintf("IPX debugger extension commands:\n\n");
+ dprintf("\tipxdev [ptr] [-l var] - Dump all fields of an IPX DEVICE object\n" );
+ dprintf("\tipxaddr <ptr>\n" );
+ dprintf("\tipxaddrfile <ptr>\n" );
+ dprintf("\tipxbinding <ptr>\n" );
+ dprintf("\tipxadapter <ptr>\n" );
+ dprintf("\tipxrequest <ptr> - Turn an IRP into an IPX_ADDRESS_FILE\n" );
+ dprintf("\n");
+
+ dprintf("\tnext - Advance to next element in currently focused list.\n\n" );
+ dprintf("\tprev - Advance to previous element in currently focused list.\n\n" );
+
+ dprintf( "Compiled on " __DATE__ " at " __TIME__ "\n" );
+ return;
+}
+
+
+
+VOID
+dprintSymbolPtr
+(
+ PVOID Pointer,
+ PCHAR EndOfLine
+)
+{
+ UCHAR SymbolName[ 80 ];
+ ULONG Displacement;
+
+ dprintf("%-10lx", ( ULONG )Pointer );
+
+ GetSymbol( Pointer, SymbolName, &Displacement );
+
+ if ( Displacement == 0 )
+ {
+ dprintf( "(%s)%s", SymbolName, EndOfLine );
+ }
+ else
+ {
+ dprintf( "(%s + 0x%X)%s", SymbolName, Displacement, EndOfLine );
+ }
+}
+
+VOID
+dprint_nchar
+(
+ PCHAR pch,
+ int cch
+)
+{
+ CHAR ch;
+ int index;
+
+ for ( index = 0; index < cch; index ++ )
+ {
+ ch = pch[ index ];
+ dprintf( "%c", ( ch >= 32 ) ? ch : '.' );
+ }
+}
+
+VOID
+dprint_hardware_address
+(
+ PUCHAR Address
+)
+{
+ dprintf( "%02x-%02x-%02x-%02x-%02x-%02x",
+ Address[ 0 ],
+ Address[ 1 ],
+ Address[ 2 ],
+ Address[ 3 ],
+ Address[ 4 ],
+ Address[ 5 ] );
+}
+
+BOOL
+dprint_enum_name
+(
+ ULONG Value,
+ PENUM_INFO pEnumInfo
+)
+{
+ while ( pEnumInfo->pszDescription != NULL )
+ {
+ if ( pEnumInfo->Value == Value )
+ {
+ dprintf( "%.40s", pEnumInfo->pszDescription );
+ return( TRUE );
+ }
+ pEnumInfo ++;
+ }
+
+ dprintf( "Unknown enumeration value." );
+ return( FALSE );
+}
+
+BOOL
+dprint_flag_names
+(
+ ULONG Value,
+ PFLAG_INFO pFlagInfo
+)
+{
+ BOOL bFoundOne = FALSE;
+
+ while ( pFlagInfo->pszDescription != NULL )
+ {
+ if ( pFlagInfo->Value & Value )
+ {
+ if ( bFoundOne )
+ {
+ dprintf( " | " );
+ }
+ bFoundOne = TRUE;
+
+ dprintf( "%.15s", pFlagInfo->pszDescription );
+ }
+ pFlagInfo ++;
+ }
+
+ return( bFoundOne );
+}
+
+BOOL
+dprint_masked_value
+(
+ ULONG Value,
+ ULONG Mask
+)
+{
+ CHAR Buf[ 9 ];
+ ULONG nibble;
+ int index;
+
+ for ( index = 0; index < 8; index ++ )
+ {
+ nibble = ( Mask & 0xF0000000 );
+/*
+ dprintf( "#%d: nibble == %08X\n"
+ " Mask == %08X\n"
+ " Value == %08X\n", index, nibble, Mask, Value );
+
+*/
+ if ( nibble )
+ {
+ Buf[ index ] = "0123456789abcdef"[ (( nibble & Value ) >> 28) & 0xF ];
+ }
+ else
+ {
+ Buf[ index ] = ' ';
+ }
+
+ Mask <<= 4;
+ Value <<= 4;
+ }
+
+ Buf[ 8 ] = '\0';
+
+ dprintf( "%s", Buf );
+
+ return( TRUE );
+}
diff --git a/private/ntos/tdi/isn/isnext/isnext.def b/private/ntos/tdi/isn/isnext/isnext.def
new file mode 100644
index 000000000..d43dc97ef
--- /dev/null
+++ b/private/ntos/tdi/isn/isnext/isnext.def
@@ -0,0 +1,33 @@
+LIBRARY ISNEXT
+
+DESCRIPTION 'KD Extensions for isn'
+
+EXPORTS
+
+ CheckVersion
+ WinDbgExtensionDllInit
+ ExtensionApiVersion
+
+ help
+
+ next
+ prev
+
+ nbaddrfile
+ nbaddr
+ nbconn
+ nbconnfull
+ nbdev
+ nbdevfull
+
+ ipxdev
+ ipxbinding
+ ipxaddr
+ ipxaddrfile
+ ipxadapter
+ ipxrequest
+
+ spxdev
+ spxaddr
+ spxaddrfile
+ spxconnfile
diff --git a/private/ntos/tdi/isn/isnext/isnext.h b/private/ntos/tdi/isn/isnext/isnext.h
new file mode 100644
index 000000000..f0222ca21
--- /dev/null
+++ b/private/ntos/tdi/isn/isnext/isnext.h
@@ -0,0 +1,306 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ isnext.h
+
+Abstract:
+
+ This file is a common header file for isnext.dll
+
+Author:
+
+ Munil Shah (munils) 18-May-1995
+
+Environment:
+
+ User Mode
+
+--*/
+
+#define ITEMSIZE 25
+
+typedef struct
+{
+ ULONG Value;
+ PCHAR pszDescription;
+} ENUM_INFO, *PENUM_INFO, FLAG_INFO, *PFLAG_INFO;
+
+#define EnumString( Value ) { Value, #Value }
+
+extern ENUM_INFO EnumStructureType[];
+
+//#define EOL ( (Item++ & 1) ? "\n":"" )
+typedef enum
+{
+ VERBOSITY_ONE_LINER = 0,
+ VERBOSITY_NORMAL,
+ VERBOSITY_FULL
+} VERBOSITY;
+
+#define PrintStart Item = 0;
+
+extern int _Indent;
+extern char IndentBuf[ 80 ];
+
+#define IndentChange( cch ) { IndentBuf[_Indent]=' '; _Indent += ( cch ); IndentBuf[_Indent]='\0';}
+#define Indent( cch ) IndentChange( cch )
+#define Outdent( cch ) IndentChange( -( cch ) )
+
+#define PrintStartStruct() { PrintStart; dprintf( "%s{\n", IndentBuf ); Indent( 2 ); }
+
+#define PrintStartNamedStruct( _name ) { PrintStart; dprintf( "%s%s {\n", IndentBuf, _name ); Indent( 2 ); }
+
+static PCHAR pchEol = "\n";
+static PCHAR pchBlank = "";
+static PCHAR * ppchCurrentEol = &pchEol;
+static PCHAR * ppchTempEol = &pchEol;
+
+#define PrintJoin() { ppchCurrentEol = &pchBlank; }
+
+#define EOL (( ppchTempEol = ppchCurrentEol ), ( ppchCurrentEol = &pchEol ), ( *ppchTempEol ))
+
+VOID
+dprintSymbolPtr
+(
+ PVOID Pointer,
+ PCHAR EndOfLine
+);
+
+VOID
+dprint_nchar
+(
+ PCHAR pch,
+ int cch
+);
+
+VOID
+dprint_hardware_address
+(
+ PUCHAR Address
+);
+
+BOOL
+dprint_enum_name
+(
+ ULONG Value,
+ PENUM_INFO pEnumInfo
+);
+
+
+BOOL
+dprint_flag_names
+(
+ ULONG Value,
+ PFLAG_INFO pFlagInfo
+);
+
+BOOL
+dprint_masked_value
+(
+ ULONG Value,
+ ULONG Mask
+);
+
+/*
+#define PrintEnd \
+ dprintf( "%s", EOL ); \
+ Item = 0;
+*/
+
+#define PrintEnd \
+ Item = 0;
+
+#define PrintEndStruct() { Outdent( 2 ); PrintEnd; dprintf( "%s}\n", IndentBuf ); }
+
+#define PrintFlushLeft() PrintEnd
+
+#define PRINTBOOL(var) ( (var) ? "True" : "False")
+
+#define PrintFieldName(_fieldName) \
+ if ( strlen(_fieldName) > 35 ) { \
+ dprintf("%s%-.25s..%s = ",IndentBuf,_fieldName, &(_fieldName[strlen(_fieldName)-8])); \
+ }else { \
+ dprintf("%s%-35.35s = ",IndentBuf,_fieldName ); \
+ }
+
+#define PrintFieldNameAt(_fieldName) \
+ if ( strlen(_fieldName) > 35 ) { \
+ dprintf("%s%-.25s..%s @ ",IndentBuf,_fieldName, &(_fieldName[strlen(_fieldName)-8])); \
+ }else { \
+ dprintf("%s%-35.35s @ ",IndentBuf,_fieldName ); \
+ }
+
+#define PrintListFieldName(_fieldName) \
+ if ( strlen(_fieldName) > 40 ) { \
+ dprintf("%s%-.30s...%s Flink = ",IndentBuf,_fieldName, &(_fieldName[strlen(_fieldName)-7])); \
+ }else { \
+ dprintf("%s%-40.40s Flink = ",IndentBuf,_fieldName ); \
+ }
+
+#define PrintIndent() dprintf( "%s", IndentBuf );
+/* #define PrintFieldName(_fieldName) \
+ dprintf(" %-25.25s = ",_fieldName );*/
+
+#define PrintRawBool( _bValue ) \
+ dprintf("%-10s%s", (_obj._bValue) ? "True" : "False", EOL)
+
+#define PrintBool(_field) \
+ PrintFieldName(#_field) \
+ dprintf("%-10s%s", (_obj._field) ? "True" : "False", EOL)
+
+#define PrintULong(_field) \
+ PrintFieldName(#_field) \
+ dprintf("%-10lu%s", _obj._field, EOL)
+
+#define PrintXULong(_field) \
+ PrintFieldName(#_field) \
+ dprintf("0x%08lx%s", _obj._field, EOL)
+
+#define PrintUShort(_field) \
+ PrintFieldName(#_field) \
+ dprintf("%-10hu%s", _obj._field, EOL)
+
+#define PrintXUShort(_field) \
+ PrintFieldName(#_field) \
+ dprintf("0x%04hx%s", _obj._field, EOL)
+
+#define PrintNChar( _field, count ) \
+ PrintFieldName(#_field) \
+ dprint_nchar( ( PCHAR )_obj._field, count ); \
+ dprintf("%s", EOL)
+
+#define PrintUChar(_field) \
+ PrintFieldName(#_field) \
+ dprintf("%-10lu%s", (ULONG) _obj._field, EOL)
+
+#define PrintXUChar(_field) \
+ PrintFieldName(#_field) \
+ dprintf("0x%-8lx%s", (ULONG) _obj._field, EOL)
+
+#define PrintPtr(_field) \
+ PrintFieldName(#_field) \
+ dprintf("%-10lx%s", _obj._field, EOL)
+
+#define PrintSymbolPtr( _field ) \
+ PrintFieldName(#_field) \
+ dprintSymbolPtr( (( PVOID )_obj._field), EOL );
+
+#define AddressOf( _field ) ((( ULONG )_objAddr) + FIELD_OFFSET( _objType, _field ))
+
+#define PrintAddr(_field) \
+ PrintFieldNameAt(#_field) \
+ dprintf("%-10lx%s", AddressOf( _field ), EOL)
+
+#define PrintL(_field) \
+ PrintFieldName(#_field##".Next") \
+ dprintf("%-10lx%s", _obj._field.Next, EOL )
+
+#define PrintLL(_field) \
+ PrintEnd; \
+ PrintListFieldName(#_field ); \
+ dprintf("%-10lx", _obj._field.Flink ); \
+ dprintf("Blink = %-10lx", _obj._field.Blink ); \
+ dprintf("%s\n", ( _obj._field.Flink == _obj._field.Blink ) ? " (Empty)" : "" );
+
+#define PrintIrpQ(_field) \
+ PrintEnd; \
+ PrintFieldName(#_field##".Head"); \
+ dprintf("%-10lx", _obj._field.Head ); \
+ PrintFieldName(#_field##".Tail"); \
+ dprintf("%-10lx\n", _obj._field.Tail );
+
+#define PrintFlags( _field, _pFlagStruct ) \
+ PrintEnd; \
+ PrintFieldName(#_field); \
+ dprintf("0x%08lx (", (ULONG) _obj._field ); \
+ dprint_flag_names( (ULONG) _obj._field, _pFlagStruct ); \
+ dprintf( ")\n" );
+
+#define PrintFlagsMask( _field, _pFlagStruct, _Mask ) \
+ PrintEnd; \
+ PrintFieldName(" & " ## #_Mask ); \
+ dprintf("0x"); \
+ dprint_masked_value((ULONG) _obj._field, _Mask ); \
+ dprintf("("); \
+ dprint_flag_names( (ULONG) _obj._field, _pFlagStruct ); \
+ dprintf( ")\n" );
+
+#define PrintEnum( _field, _pEnumStruct ) \
+ PrintEnd; \
+ PrintFieldName(#_field); \
+ dprintf("%lu (", (ULONG) _obj._field ); \
+ dprint_enum_name( (ULONG) _obj._field, _pEnumStruct ); \
+ dprintf( ")\n" );
+
+#define PrintXEnum( _field, _pEnumStruct ) \
+ PrintEnd; \
+ PrintFieldName(#_field); \
+ dprintf("0x%08lx (", (ULONG) _obj._field ); \
+ dprint_enum_name( (ULONG) _obj._field, _pEnumStruct ); \
+ dprintf( ")\n" );
+
+#define PrintXEnumMask( _field, _pEnumStruct, _Mask ) \
+ PrintEnd; \
+ PrintFieldName(" & " ## #_Mask ); \
+ dprintf("0x"); \
+ dprint_masked_value((ULONG) _obj._field, _Mask ); \
+ dprintf("("); \
+ dprint_enum_name((ULONG) _obj._field & _Mask, _pEnumStruct ); \
+ dprintf( ")\n" );
+
+
+#define PrintHardwareAddress( _field ) \
+ PrintFieldName(#_field); \
+ dprint_hardware_address( _obj._field.Address ); \
+ dprintf( "%s", EOL );
+
+#define PrintIpxLocalTarget( _field ) \
+ PrintStartNamedStruct( #_field ); \
+ PrintFieldName( "NicId" ); \
+ dprintf("%-10u%s", _obj._field.NicId, EOL); \
+ PrintFieldName( "MacAddress" ); \
+ dprint_hardware_address( _obj._field.MacAddress ); \
+ dprintf( "%s", EOL ); \
+ PrintEndStruct();
+
+
+#define PrintLock( _field ) \
+ PrintULong( _field )
+
+#define PrintTDIAddress( _field ) \
+ PrintFieldName( #_field ); \
+ dprintf( "{ NetworkAddress = %X, NodeAddress = ", _obj._field.NetworkAddress );\
+ dprint_hardware_address( _obj._field.NodeAddress );\
+ dprintf( ", Socket = %d }%s", _obj._field.Socket, EOL );
+
+#define PrintCTETimer( _field ) \
+ dprintf( "%s", #_field ); \
+ PrintStartStruct(); \
+ DumpCTETimer ( ((ULONG)_objAddr) +FIELD_OFFSET( _objType, _field ), VERBOSITY_NORMAL );\
+ PrintEndStruct();
+
+#define PrintWorkQueueItem( _field ) \
+ dprintf( "%s", #_field ); \
+ PrintStartStruct(); \
+ DumpWorkQueueItem ( ((ULONG)_objAddr) +FIELD_OFFSET( _objType, _field ), VERBOSITY_NORMAL );\
+ PrintEndStruct();
+
+
+extern BOOLEAN ChkTarget;
+extern INT Item;
+
+#define CHECK_SIGNATURE( _field, _signature ) \
+ if ( _obj._field != _signature ) \
+ { \
+ dprintf( "Object at %08X doesn't have signature %s at %08X\n", \
+ _objAddr, \
+ #_signature, \
+ (( ULONG )_objAddr) + FIELD_OFFSET( _objType, _field ));\
+ }
+
+
+
+
diff --git a/private/ntos/tdi/isn/isnext/isnext.rc b/private/ntos/tdi/isn/isnext/isnext.rc
new file mode 100644
index 000000000..e69368262
--- /dev/null
+++ b/private/ntos/tdi/isn/isnext/isnext.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "kernel debugger extension dll"
+#define VER_INTERNALNAME_STR "isnext.dll"
+#define VER_ORIGINALFILENAME_STR "isnext.dll"
+
+#include <common.ver>
+
diff --git a/private/ntos/tdi/isn/isnext/nbext.c b/private/ntos/tdi/isn/isnext/nbext.c
new file mode 100644
index 000000000..053025fb7
--- /dev/null
+++ b/private/ntos/tdi/isn/isnext/nbext.c
@@ -0,0 +1,873 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ nbext.c
+
+Abstract:
+
+ This file contains kernel debugger extensions for examining the
+ NB structure.
+
+Author:
+
+ Munil Shah (munils) 18-May-1995
+
+Environment:
+
+ User Mode
+
+--*/
+#include "precomp.h"
+#pragma hdrstop
+#include "isn.h"
+#include "isnnb.h"
+#include "zwapi.h"
+#include "config.h"
+#include "nbitypes.h"
+
+
+PCHAR HandlerNames[] = { "Connection", "Disconnect", "Error", "Receive", "ReceiveDatagram", "ExpeditedData" };
+
+//
+// Local function prototypes
+//
+VOID
+DumpAddrFile(
+ ULONG AddrFileToDump
+ );
+
+
+VOID
+DumpAddrObj(
+ ULONG AddrObjToDump
+ );
+
+VOID
+DumpConn(
+ ULONG ConnToDump,
+ BOOLEAN Full
+ );
+
+VOID
+Dumpdevice(
+ ULONG deviceToDump,
+ BOOLEAN Full
+ );
+
+
+///////////////////////////////////////////////////////////////////////
+// ADDRESS_FILE
+//////////////////////////////////////////////////////////////////////
+
+#define _obj addrfile
+#define _objAddr AddrFileToDump
+#define _objType ADDRESS_FILE
+
+//
+// Exported functions
+//
+
+DECLARE_API( nbaddrfile )
+
+/*++
+
+Routine Description:
+
+ Dumps the most important fields of the specified ADDRESS_FILE object
+
+Arguments:
+
+ args - Address of args string
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG addrFileToDump = 0;
+
+ if (!*args) {
+ dprintf("No address_file object specified\n");
+ }
+ else {
+ sscanf(args, "%lx", &addrFileToDump);
+ DumpAddrFile(addrFileToDump);
+ }
+
+ return;
+}
+
+
+//
+// Local functions
+//
+
+VOID
+DumpAddrFile(
+ ULONG AddrFileToDump
+ )
+
+/*++
+
+Routine Description:
+
+ Dumps the fields of the specified ADDRESS_FILE object
+
+Arguments:
+
+ AddrFileToDump - The ADDRESS_FILE object to display
+ Full - Display a partial listing if 0, full listing otherwise.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ADDRESS_FILE addrfile;
+ ULONG result;
+ UCHAR i;
+
+ if (!ReadMemory(
+ AddrFileToDump,
+ &addrfile,
+ sizeof(addrfile),
+ &result
+ )
+ )
+ {
+ dprintf("%08lx: Could not read address object\n", AddrFileToDump);
+ return;
+ }
+
+ if (addrfile.Type != NB_ADDRESSFILE_SIGNATURE) {
+ dprintf("Signature does not match, probably not an address object\n");
+ return;
+ }
+
+ dprintf("NBI AddressFile:\n");
+
+ PrintStart
+ PrintXUChar(State);
+ PrintXULong(ReferenceCount);
+ PrintPtr(FileObject);
+ PrintPtr(Address);
+ PrintPtr(OpenRequest);
+ PrintPtr(CloseRequest);
+ PrintLL(Linkage);
+ PrintLL(ConnectionDatabase);
+ PrintLL(ReceiveDatagramQueue);
+ PrintEnd
+
+ for ( i= TDI_EVENT_CONNECT; i < TDI_EVENT_SEND_POSSIBLE ; i++ ) {
+ dprintf(" %sHandler = %lx, Registered = %s, Context = %lx\n",
+ HandlerNames[i], addrfile.Handlers[i], PRINTBOOL(addrfile.RegisteredHandler[i]),addrfile.HandlerContexts[i] );
+ }
+ return;
+}
+
+///////////////////////////////////////////////////////////////////////
+// ADDRESS
+//////////////////////////////////////////////////////////////////////
+
+#undef _obj
+#undef _objAddr
+#undef _objType
+#define _obj addrobj
+#define _objAddr AddrObjToDump
+#define _objType ADDRESS
+
+DECLARE_API( nbaddr )
+
+/*++
+
+Routine Description:
+
+ Dumps the most important fields of the specified ADDRESS object
+
+Arguments:
+
+ args - Address of args string
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG addrobjToDump = 0;
+
+ if (!*args) {
+ dprintf("No address object specified\n");
+ }
+ else {
+ sscanf(args, "%lx", &addrobjToDump);
+ DumpAddrObj(addrobjToDump);
+ }
+
+ return;
+}
+
+
+//
+// Local functions
+//
+
+VOID
+PrintNetbiosName(
+ PUCHAR Name
+ )
+/*++
+
+Routine Description:
+
+ Prints out a Netbios name.
+
+Arguments:
+
+ Name - The array containing the name to print.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG i;
+
+ for (i=0; i<16; i++) {
+ dprintf("%c", Name[i]);
+ }
+ return;
+}
+
+
+VOID
+DumpAddrObj(
+ ULONG AddrObjToDump
+ )
+
+/*++
+
+Routine Description:
+
+ Dumps the fields of the specified ADDRESS object
+
+Arguments:
+
+ AddrObjToDump - The address object to display
+ Full - Display a partial listing if 0, full listing otherwise.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ADDRESS addrobj;
+ ULONG result;
+ NBI_NETBIOS_ADDRESS nbaddr;
+
+
+ if (!ReadMemory(
+ AddrObjToDump,
+ &addrobj,
+ sizeof(addrobj),
+ &result
+ )
+ )
+ {
+ dprintf("%08lx: Could not read address object\n", AddrObjToDump);
+ return;
+ }
+
+ if (addrobj.Type != NB_ADDRESS_SIGNATURE) {
+ dprintf("Signature does not match, probably not an address object\n");
+ return;
+ }
+
+ dprintf("NB Address:\n");
+ PrintStart
+ PrintXULong(State);
+ PrintXULong(Flags);
+ PrintULong(ReferenceCount);
+ PrintLL(Linkage);
+ PrintEnd
+
+ // Print the netbiosname info.
+ PrintFieldName("NetbiosName");
+ PrintNetbiosName(addrobj.NetbiosAddress.NetbiosName); dprintf("\n");
+ dprintf(" %25s = 0x%8x %25s = %10s\n", "NetbiosNameType",addrobj.NetbiosAddress.NetbiosNameType,"Broadcast",PRINTBOOL(addrobj.NetbiosAddress.Broadcast));
+
+ PrintStart
+ PrintLL(AddressFileDatabase);
+ PrintAddr(RegistrationTimer);
+ PrintXULong(RegistrationCount);
+ PrintPtr(SecurityDescriptor);
+ PrintEnd
+ return;
+}
+
+
+///////////////////////////////////////////////////////////////////////
+// CONNECTION_FILE
+//////////////////////////////////////////////////////////////////////
+#undef _obj
+#undef _objAddr
+#undef _objType
+#define _obj conn
+#define _objAddr ConnToDump
+#define _objType CONNECTION
+
+
+DECLARE_API( nbconn )
+
+/*++
+
+Routine Description:
+
+ Dumps the most important fields of the specified CONNECTION object
+
+Arguments:
+
+ args - Address
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG connToDump = 0;
+
+ if (!*args) {
+ dprintf("No conn specified\n");
+ }
+ else {
+ sscanf(args, "%lx", &connToDump);
+ DumpConn(connToDump, FALSE);
+ }
+
+ return;
+}
+
+
+DECLARE_API( nbconnfull )
+
+/*++
+
+Routine Description:
+
+ Dumps all of the fields of the specified CONNECTION object
+
+Arguments:
+
+ args - Address
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG connToDump = 0;
+
+ if (!*args) {
+ dprintf("No conn specified\n");
+ }
+ else {
+ sscanf(args, "%lx", &connToDump);
+ DumpConn(connToDump, TRUE);
+ }
+
+ return;
+}
+
+
+//
+// Local functions
+//
+VOID
+printSendPtr(
+ PSEND_POINTER SendPtr,
+ PSEND_POINTER UnAckedPtr
+ )
+{
+ dprintf(" CurrentSend UnackedSend\n");
+ dprintf(" MessageOffset 0x%-8lx 0x%-8lx\n", SendPtr->MessageOffset,UnAckedPtr->MessageOffset);
+ dprintf(" Request 0x%-8lx 0x%-8lx\n", SendPtr->Request,UnAckedPtr->Request);
+ dprintf(" Buffer 0x%-8lx 0x%-8lx\n", SendPtr->Buffer,UnAckedPtr->Buffer);
+ dprintf(" BufferOffset 0x%-8lx 0x%-8lx\n", SendPtr->BufferOffset,UnAckedPtr->BufferOffset);
+ dprintf(" SendSequence 0x%-8x 0x%-8x\n", SendPtr->SendSequence,UnAckedPtr->SendSequence);
+}
+
+VOID
+printRcvPtr(
+ PRECEIVE_POINTER CurrentPtr,
+ PRECEIVE_POINTER PreviousPtr
+ )
+{
+ dprintf(" CurrentReceive PreviousReceive\n");
+ dprintf(" MessageOffset 0x%-8lx 0x%-8lx\n", CurrentPtr->MessageOffset,PreviousPtr->MessageOffset);
+ dprintf(" Offset 0x%-8lx 0x%-8lx\n", CurrentPtr->Offset,PreviousPtr->Offset);
+ dprintf(" Buffer 0x%-8lx 0x%-8lx\n", CurrentPtr->Buffer,PreviousPtr->Buffer);
+ dprintf(" BufferOffset 0x%-8lx 0x%-8lx\n", CurrentPtr->BufferOffset,PreviousPtr->BufferOffset);
+}
+
+VOID
+DumpConn(
+ ULONG ConnToDump,
+ BOOLEAN Full
+ )
+
+/*++
+
+Routine Description:
+
+ Dumps the fields of the specified CONNECTION object
+
+Arguments:
+
+ ConnToDump - The conn object to display
+ Full - Display a partial listing if 0, full listing otherwise.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ CONNECTION conn;
+ ULONG result;
+
+
+ if (!ReadMemory(
+ ConnToDump,
+ &conn,
+ sizeof(conn),
+ &result
+ )
+ )
+ {
+ dprintf("%08lx: Could not read conn\n", ConnToDump);
+ return;
+ }
+
+ if (conn.Type != NB_CONNECTION_SIGNATURE) {
+ dprintf("Signature does not match, probably not a conn\n");
+ return;
+ }
+
+ dprintf("NBI Connection General:\n");
+ PrintStart
+ PrintXULong(State);
+ PrintXULong(SubState);
+ PrintXULong(ReceiveState);
+ PrintXULong(ReferenceCount);
+ PrintXUShort(LocalConnectionId);
+ PrintXUShort(RemoteConnectionId);
+ PrintAddr(LocalTarget);
+ PrintAddr(RemoteHeader);
+ PrintPtr(Context);
+ PrintPtr(AddressFile);
+ PrintXULong(AddressFileLinked);
+ PrintPtr(NextConnection);
+
+ PrintEnd
+
+ dprintf(" RemoteName = ");PrintNetbiosName((PUCHAR)conn.RemoteName);dprintf("\n");
+
+ dprintf("\n\nConnection Send Info:\n");
+
+ PrintStart
+ PrintIrpQ(SendQueue);
+ PrintXUShort(SendWindowSequenceLimit);
+ PrintXUShort(SendWindowSize);
+ PrintEnd
+
+ printSendPtr( &conn.CurrentSend, &conn.UnAckedSend );
+
+ if( Full ) {
+ PrintStart
+ PrintXUShort(MaxSendWindowSize);
+ PrintBool(RetransmitThisWindow);
+ PrintBool(SendWindowIncrease);
+ PrintBool(ResponseTimeout);
+ PrintBool(SendBufferInUse);
+ PrintPtr(FirstMessageRequest);
+ PrintPtr(LastMessageRequest);
+ PrintXULong(MaximumPacketSize);
+ PrintXULong(CurrentMessageLength);
+ PrintEnd
+ }
+
+ dprintf("\n\nConnection Receive Info:\n");
+ PrintStart
+ PrintIrpQ(ReceiveQueue);
+ PrintXUShort(ReceiveSequence);
+ PrintXUShort(ReceiveWindowSize);
+ PrintXUShort(LocalRcvSequenceMax);
+ PrintXUShort(RemoteRcvSequenceMax);
+ PrintPtr(ReceiveRequest);
+ PrintXULong(ReceiveLength);
+ PrintEnd
+
+ printRcvPtr( &conn.CurrentReceive, &conn.PreviousReceive );
+
+ if( Full ) {
+ PrintStart
+ PrintXULong(ReceiveUnaccepted);
+ PrintXULong(CurrentIndicateOffset);
+ PrintBool(NoPiggybackHeuristic);
+ PrintBool(PiggybackAckTimeout);
+ PrintBool(CurrentReceiveNoPiggyback);
+ PrintBool(DataAckPending);
+ PrintEnd
+ }
+
+ if( Full ) {
+ PrintStart
+ PrintPtr(ListenRequest);
+ PrintPtr(AcceptRequest);
+ PrintPtr(ClosePending);
+ PrintPtr(DisassociatePending);
+ PrintPtr(DisconnectWaitRequest);
+ PrintPtr(DisconnectRequest);
+ PrintPtr(ConnectRequest);
+ PrintEnd
+
+ PrintStart
+ PrintLL(PacketizeLinkage);
+ PrintBool(OnPacketizeQueue);
+ PrintLL(WaitPacketLinkage);
+ PrintBool(OnWaitPacketQueue);
+ PrintLL(DataAckLinkage);
+ PrintBool(OnDataAckQueue);
+ PrintBool(IgnoreNextDosProbe);
+ PrintXULong(NdisSendsInProgress);
+ PrintLL(NdisSendQueue);
+ PrintPtr(NdisSendReference);
+ PrintXULong(Retries);
+ PrintXULong(Status);
+ PrintBool(FindRouteInProgress);
+ PrintXULong(CanBeDestroyed);
+ PrintBool(OnShortList);
+ PrintLL(ShortList);
+ PrintLL(LongList);
+ PrintBool(OnLongList);
+ PrintXULong(BaseRetransmitTimeout);
+ PrintXULong(CurrentRetransmitTimeout);
+ PrintXULong(WatchdogTimeout);
+ PrintXULong(Retransmit);
+ PrintXULong(Watchdog);
+
+
+ PrintEnd
+
+ PrintStart
+ PrintAddr(ConnectionInfo);
+ PrintAddr(Timer);
+ PrintAddr(FindRouteRequest);
+ PrintPtr(NextConnection);
+ PrintAddr(SessionInitAckData);
+ PrintXULong(SessionInitAckDataLength);
+ PrintAddr(SendPacket);
+ PrintAddr(SendPacketHeader);
+ PrintBool(SendPacketInUse);
+ PrintAddr(LineInfo);
+
+#ifdef RSRC_TIMEOUT_DBG
+ PrintXULong(FirstMessageRequestTime.HighPart);
+ PrintXULong(FirstMessageRequestTime.LowPart);
+#endif RSRC_TIMEOUT_DBG
+ }
+ return;
+}
+
+///////////////////////////////////////////////////////////////////////
+// DEVICE
+//////////////////////////////////////////////////////////////////////
+
+
+#undef _obj
+#undef _objAddr
+#undef _objType
+#define _obj device
+#define _objAddr deviceToDump
+#define _objType DEVICE
+
+//
+// Exported functions
+//
+
+DECLARE_API( nbdev )
+
+/*++
+
+Routine Description:
+
+ Dumps the most important fields of the specified DEVICE_CONTEXT object
+
+Arguments:
+
+ args - Address
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG deviceToDump = 0;
+ ULONG pDevice = 0;
+ ULONG result;
+
+ if (!*args) {
+
+ pDevice = GetExpression( "nwlnknb!NbiDevice" );
+
+ if ( !pDevice ) {
+ dprintf("Could not get NbiDevice, Try !reload\n");
+ return;
+ } else {
+
+ if (!ReadMemory(pDevice,
+ &deviceToDump,
+ sizeof(deviceToDump),
+ &result
+ )
+ )
+ {
+ dprintf("%08lx: Could not read device address\n", pDevice);
+ return;
+ }
+ }
+
+ }
+ else {
+ sscanf(args, "%lx", &deviceToDump);
+ }
+
+
+ Dumpdevice(deviceToDump, FALSE);
+
+ return;
+}
+
+
+DECLARE_API( nbdevfull )
+
+/*++
+
+Routine Description:
+
+ Dumps all of the fields of the specified DEVICE_CONTEXT object
+
+Arguments:
+
+ args - Address
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG deviceToDump = 0;
+ ULONG pDevice = 0;
+ ULONG result;
+
+ if (!*args) {
+
+ pDevice = GetExpression( "nwlnknb!NbiDevice" );
+
+ if ( !pDevice ) {
+ dprintf("Could not get NbiDevice, Try !reload\n");
+ return;
+ } else {
+
+ if (!ReadMemory(pDevice,
+ &deviceToDump,
+ sizeof(deviceToDump),
+ &result
+ )
+ )
+ {
+ dprintf("%08lx: Could not read device address\n", pDevice);
+ return;
+ }
+ }
+
+ }
+ else {
+ sscanf(args, "%lx", &deviceToDump);
+ }
+
+
+ Dumpdevice(deviceToDump, TRUE);
+
+ return;
+}
+
+//
+// Local functions
+//
+
+VOID
+Dumpdevice(
+ ULONG deviceToDump,
+ BOOLEAN Full
+ )
+
+/*++
+
+Routine Description:
+
+ Dumps the fields of the specified DEVICE_CONTEXT structure
+
+Arguments:
+
+ deviceToDump - The device context object to display
+ Full - Display a partial listing if 0, full listing otherwise.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ DEVICE device;
+ ULONG result;
+
+
+ if (!ReadMemory(
+ deviceToDump,
+ &device,
+ sizeof(device),
+ &result
+ )
+ )
+ {
+ dprintf("%08lx: Could not read device context\n", deviceToDump);
+ return;
+ }
+
+ if (device.Type != NB_DEVICE_SIGNATURE) {
+ dprintf("Signature does not match, probably not a device object %lx\n",deviceToDump);
+ return;
+ }
+
+ dprintf("Device General Info:\n");
+ PrintStart
+ PrintXUChar(State);
+ PrintXULong(ReferenceCount);
+ PrintXUShort(MaximumNicId);
+ PrintXULong(MemoryUsage);
+ PrintXULong(MemoryLimit);
+ PrintXULong(AddressCount);
+ PrintXULong(AllocatedSendPackets);
+ PrintXULong(AllocatedReceivePackets);
+ PrintXULong(AllocatedReceiveBuffers);
+ PrintXULong(MaxReceiveBuffers);
+ PrintLL(AddressDatabase);
+ PrintL(SendPacketList);
+ PrintL(ReceivePacketList);
+ PrintLL(GlobalReceiveBufferList);
+ PrintLL(GlobalSendPacketList);
+ PrintLL(GlobalReceivePacketList);
+ PrintLL(GlobalReceiveBufferList);
+ PrintLL(SendPoolList);
+ PrintLL(ReceivePoolList);
+ PrintLL(ReceiveBufferPoolList);
+ PrintLL(ReceiveCompletionQueue);
+ PrintLL(WaitPacketConnections);
+ PrintLL(PacketizeConnections);
+ PrintLL(WaitingConnects);
+ PrintLL(WaitingDatagrams);
+ PrintLL(WaitingAdapterStatus);
+ PrintLL(WaitingNetbiosFindName);
+ PrintLL(ActiveAdapterStatus);
+ PrintLL(ReceiveDatagrams);
+ PrintLL(ConnectIndicationInProgress);
+ PrintLL(ListenQueue);
+ PrintLL(WaitingFindNames);
+ if ( Full ) {
+ PrintStart
+ PrintBool(UnloadWaiting);
+ PrintBool(DataAckQueueChanged);
+ PrintBool(ShortListActive);
+ PrintBool(DataAckActive);
+ PrintBool(TimersInitialized);
+ PrintBool(ProcessingShortTimer);
+ PrintAddr(ShortTimerStart);
+ PrintAddr(ShortTimer);
+ PrintXULong(ShortAbsoluteTime);
+ PrintAddr(LongTimer);
+ PrintXULong(LongAbsoluteTime);
+ PrintLL(ShortList);
+ PrintLL(LongList);
+ PrintAddr(TimerLock);
+ PrintEnd
+ }
+
+ if ( Full ) {
+ PrintStart
+ PrintXUShort(FindNameTime);
+ PrintBool(FindNameTimerActive);
+ PrintAddr(FindNameTimer);
+ PrintXULong(FindNameTimeout);
+ PrintXULong(FindNamePacketCount);
+ PrintLL(WaitingFindNames);
+ PrintEnd
+
+ PrintStart
+ PrintXULong(AckDelayTime );
+ PrintXULong(AckWindow );
+ PrintXULong(AckWindowThreshold );
+ PrintXULong(EnablePiggyBackAck );
+ PrintXULong(Extensions );
+ PrintXULong(RcvWindowMax );
+ PrintXULong(BroadcastCount );
+ PrintXULong(BroadcastTimeout );
+ PrintXULong(ConnectionCount );
+ PrintXULong(ConnectionTimeout );
+ PrintXULong(InitPackets );
+ PrintXULong(MaxPackets );
+ PrintXULong(InitialRetransmissionTime);
+ PrintXULong(Internet );
+ PrintXULong(KeepAliveCount );
+ PrintXULong(KeepAliveTimeout );
+ PrintXULong(RetransmitMax );
+ PrintXULong(RouterMtu);
+ PrintEnd
+ }
+
+ PrintPtr(NameCache);
+ PrintXUShort(CacheTimeStamp);
+ PrintAddr(Bind);
+ PrintAddr( ConnectionHash);
+ PrintAddr( ConnectionlessHeader );
+ PrintAddr( UnloadEvent );
+ PrintAddr(Information);
+ PrintAddr(Statistics);
+
+ PrintEnd
+
+ return;
+}
+
diff --git a/private/ntos/tdi/isn/isnext/precomp.h b/private/ntos/tdi/isn/isnext/precomp.h
new file mode 100644
index 000000000..a9b5cc014
--- /dev/null
+++ b/private/ntos/tdi/isn/isnext/precomp.h
@@ -0,0 +1,41 @@
+#define ISN_NT 1
+
+//
+// These are needed for CTE
+//
+
+#if DBG
+#define DEBUG 1
+#endif
+
+#define NT 1
+
+
+#include <ntverp.h>
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+//
+// Prevent hal.h, included in ntos.h from overriding _BUS_DATA_TYPE
+// enum found in ntioapi.h, included from nt.h.
+//
+#define _HAL_
+#include <ntos.h>
+
+#include <windows.h>
+#include <wdbgexts.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <nb30.h>
+#include <ndis.h>
+#include <tdikrnl.h>
+#include <isnext.h>
+#include <wsnwlink.h>
+#include <bind.h>
+
+#include <traverse.h>
+#include <ipxext.h>
+#include <spxext.h>
+#include <cxport.h>
+#include <cteext.h>
diff --git a/private/ntos/tdi/isn/isnext/spxext.c b/private/ntos/tdi/isn/isnext/spxext.c
new file mode 100644
index 000000000..429b80a80
--- /dev/null
+++ b/private/ntos/tdi/isn/isnext/spxext.c
@@ -0,0 +1,1035 @@
+#include "precomp.h"
+#pragma hdrstop
+
+#include <isnspx.h>
+
+VOID
+DumpSpxDevice
+(
+ ULONG DeviceToDump,
+ VERBOSITY Verbosity
+);
+
+VOID
+DumpSpxAddress
+(
+ ULONG _objAddr,
+ VERBOSITY Verbosity
+);
+
+VOID
+DumpSpxAddressFile
+(
+ ULONG _objAddr,
+ VERBOSITY Verbosity
+);
+
+VOID
+DumpSpxConnFile
+(
+ ULONG _objAddr,
+ VERBOSITY Verbosity
+);
+
+PSPX_ADDR
+NextSpxAddr
+(
+ PSPX_ADDR pAddr
+);
+
+ENUM_INFO EnumConnFileMain[] =
+{
+ { SPX_CONNFILE_ACTIVE, "Active" },
+ { SPX_CONNFILE_CONNECTING, "Connecting" },
+ { SPX_CONNFILE_LISTENING, "Listening" },
+ { SPX_CONNFILE_DISCONN, "Disconn" },
+ { 0, NULL }
+};
+
+ENUM_INFO EnumConnFileConnecting[] =
+{
+ { SPX_CONNECT_SENTREQ, "SentReq" },
+ { SPX_CONNECT_NEG, "Neg" },
+ { SPX_CONNECT_W_SETUP, "W_Setup" },
+ { 0, NULL }
+};
+
+ENUM_INFO EnumConnFileListening[] =
+{
+ { SPX_LISTEN_RECDREQ, "RecdReq" },
+ { SPX_LISTEN_SENTACK, "SentAck" },
+ { SPX_LISTEN_NEGACK, "NegAck" },
+ { SPX_LISTEN_SETUP, "Setup" },
+ { 0, NULL }
+};
+
+ENUM_INFO EnumConnFileSend[] =
+{
+ { SPX_SEND_IDLE, "Idle" },
+ { SPX_SEND_PACKETIZE, "Packetize" },
+ { SPX_SEND_RETRY, "Retry" },
+ { SPX_SEND_RETRYWD, "RetryWd" },
+ { SPX_SEND_RENEG, "Reneg" },
+ { SPX_SEND_RETRY2, "Retry2" },
+ { SPX_SEND_RETRY3, "Retry3" },
+ { SPX_SEND_WD, "Wd" },
+ { SPX_SEND_NAK_RECD, "Nak_Recd" },
+ { 0, NULL }
+};
+
+ENUM_INFO EnumConnFileReceive[] =
+{
+ { SPX_RECV_IDLE, "Idle" },
+ { SPX_RECV_POSTED, "Posted" },
+ { SPX_RECV_PROCESS_PKTS, "Process_Pkts" },
+ { 0, NULL }
+};
+
+ENUM_INFO EnumConnFileDisconnect[] =
+{
+ { SPX_DISC_IDLE, "Idle" },
+ { SPX_DISC_ABORT, "Abort" },
+ { SPX_DISC_SENT_IDISC, "Sent_IDisc" },
+ { SPX_DISC_POST_ORDREL, "Post_OrdRel" },
+ { SPX_DISC_SENT_ORDREL, "Sent_OrdRel" },
+ { SPX_DISC_ORDREL_ACKED, "OrdRel_Acked" },
+ { SPX_DISC_POST_IDISC, "Post_IDisc" },
+ { SPX_DISC_INACTIVATED, "Inactivated" },
+ { 0, NULL }
+};
+
+FLAG_INFO FlagsConnFile[] =
+{
+ { SPX_CONNFILE_RECVQ, "RecvQ" },
+ { SPX_CONNFILE_RENEG_SIZE, "Reneg_Size" },
+ { SPX_CONNFILE_ACKQ, "AckQ" },
+ { SPX_CONNFILE_PKTQ, "PktQ" },
+ { SPX_CONNFILE_ASSOC, "Assoc" },
+ { SPX_CONNFILE_NEG, "Neg" },
+ { SPX_CONNFILE_SPX2, "SPX2" },
+ { SPX_CONNFILE_STREAM, "Stream" },
+ { SPX_CONNFILE_R_TIMER, "R_Timer" },
+ { SPX_CONNFILE_C_TIMER, "C_Timer" },
+ { SPX_CONNFILE_W_TIMER, "W_Timer" },
+ { SPX_CONNFILE_T_TIMER, "T_Timer" },
+ { SPX_CONNFILE_RENEG_PKT, "Reneg_Pkt" },
+ { SPX_CONNFILE_IND_IDISC, "Ind_IDisc" },
+ { SPX_CONNFILE_IND_ODISC, "Ind_ODisc" },
+ { SPX_CONNFILE_STOPPING, "Stopping" },
+ { SPX_CONNFILE_CLOSING, "Closing" },
+ { 0, NULL }
+};
+
+FLAG_INFO Flags2ConnFile[] =
+{
+ { SPX_CONNFILE2_PKT_NOIND, "Pkt_Noind" },
+ { SPX_CONNFILE2_RENEGRECD, "RenegRecd" },
+ { SPX_CONNFILE2_PKT, "Pkt" },
+ { SPX_CONNFILE2_FINDROUTE, "FindRoute" },
+ { SPX_CONNFILE2_NOACKWAIT, "NoAckWait" },
+ { SPX_CONNFILE2_IMMED_ACK, "Immed_Ack" },
+ { SPX_CONNFILE2_IPXHDR, "IpxHdr" },
+ { 0, NULL }
+};
+
+MEMBER_TABLE SpxConnFileMembers[] =
+{
+ /*
+ { "scf_DiscLinkage",
+ FIELD_OFFSET( SPX_CONN_FILE, scf_DiscLinkage ),
+ xxxxxxx,
+ FIELD_OFFSET( NDIS_PACKET, ProtocolReserved ) + FIELD_OFFSET( IPX_SEND_RESERVED, GlobalLinkage )
+ },
+ */
+ { NULL }
+};
+
+ENUM_INFO EnumSpxSendReqType[] =
+{
+ EnumString( SPX_REQ_DATA ),
+ EnumString( SPX_REQ_ORDREL ),
+ EnumString( SPX_REQ_DISC ),
+ { 0, NULL }
+};
+
+VOID dprint_addr_list( ULONG FirstAddress, ULONG OffsetToNextPtr )
+{
+ ULONG Address;
+ ULONG result;
+ int index;
+
+ Address = FirstAddress;
+
+ if ( Address == (ULONG)NULL )
+ {
+ dprintf( "%08X (Empty)\n", Address );
+ return;
+ }
+
+ dprintf( "{ " );
+
+ for ( index = 0; Address != (ULONG)NULL; index ++ )
+ {
+ if ( index != 0 )
+ {
+ dprintf( ", ");
+ }
+ dprintf( "%08X", Address );
+
+ if ( !ReadMemory( Address + OffsetToNextPtr,
+ &Address,
+ sizeof( Address ),
+ &result ))
+ {
+ dprintf( "ReadMemory() failed." );
+ Address = (ULONG)NULL;
+ }
+ }
+ dprintf( " }\n" );
+}
+
+DECLARE_API( spxdev )
+/*++
+
+Routine Description:
+
+ Dumps the most important fields of the specified DEVICE_CONTEXT object
+
+Arguments:
+
+ args - Address
+
+Return Value:
+
+ None
+
+--*/
+{
+ ULONG deviceToDump = 0;
+ ULONG pDevice = 0;
+ ULONG result;
+ char VarName[ MAX_LIST_VARIABLE_NAME_LENGTH + 1 ];
+ MEMBER_VARIABLE_INFO MemberInfo;
+ BOOL bFocusOnMemberVariable = FALSE;
+
+ if ( *args )
+ {
+ bFocusOnMemberVariable = ReadArgsForTraverse( args, VarName );
+ }
+
+ if ( *args && *args!='-' )
+ {
+ sscanf(args, "%lx", &deviceToDump);
+ }
+
+ if ( deviceToDump == 0 ) {
+
+ pDevice = GetExpression( "nwlnkspx!SpxDevice" );
+
+ if ( !pDevice ) {
+ dprintf("Could not get nwlnkspx!SpxDevice, Try !reload\n");
+ return;
+ } else {
+
+ if ( !ReadMemory( pDevice,
+ &deviceToDump,
+ sizeof(deviceToDump),
+ &result ))
+ {
+ dprintf("%08lx: Could not read device address\n", pDevice);
+ return;
+ }
+ }
+ }
+
+ if ( bFocusOnMemberVariable )
+ {
+// if ( !LocateMemberVariable( "IpxDevice", VarName, ( PVOID )deviceToDump, &MemberInfo ))
+ {
+ return;
+ }
+
+ WriteMemberInfo( &MemberInfo );
+ next( hCurrentProcess, hCurrentThread, dwCurrentPc, dwProcessor, "" );
+ return;
+ }
+
+ DumpSpxDevice( deviceToDump, VERBOSITY_NORMAL );
+
+ return;
+}
+
+#ifdef _obj
+# undef _obj
+# undef _objAddr
+# undef _objType
+# undef _objTypeName
+#endif
+
+#define _obj Device
+#define _objAddr DeviceToDump
+#define _objType DEVICE
+#define _objTypeName "DEVICE"
+
+VOID
+DumpSpxDevice
+(
+ ULONG DeviceToDump,
+ VERBOSITY Verbosity
+)
+/*++
+
+Routine Description:
+
+ Dumps the fields of the specified DEVICE_CONTEXT structure
+
+Arguments:
+
+ DeviceToDump - The device context object to display
+ Full - Display a partial listing if 0, full listing otherwise.
+
+Return Value:
+
+ None
+
+--*/
+{
+ _objType _obj;
+ ULONG result;
+ unsigned int index;
+ WCHAR Buffer[ 1000 ];
+ PWCHAR pDeviceName = NULL;
+ PSPX_ADDR pAddr;
+
+ if ( !ReadMemory( _objAddr,
+ &_obj,
+ sizeof( _obj ),
+ &result ))
+ {
+ dprintf("%08lx: Could not read %s structure.\n", _objAddr, _objTypeName );
+ return;
+ }
+
+ if (Device.dev_Type != SPX_DEVICE_SIGNATURE)
+ {
+ dprintf( "Signature does not match, probably not a device object %lx\n", DeviceToDump);
+ dprintf( "Device.Type == %04X, and I think it should be %04X\n", Device.dev_Type, SPX_DEVICE_SIGNATURE );
+ dprintf( "DeviceToDump = %08X\n", DeviceToDump );
+ dprintf( "Offset to Device.Type = %d\n", FIELD_OFFSET( DEVICE, dev_Type ) );
+ return;
+ }
+
+ if ( !ReadMemory( ( ULONG )_obj.dev_DeviceName,
+ Buffer,
+ sizeof( WCHAR ) * _obj.dev_DeviceNameLen,
+ &result ))
+ {
+ dprintf("%08lx: Could not read device name buffer\n", _obj.dev_DeviceName );
+ }
+ else
+ {
+ pDeviceName = Buffer;
+ }
+
+ if ( Verbosity == VERBOSITY_ONE_LINER )
+ {
+ dprintf( "\"%S\"", pDeviceName );
+ return;
+ }
+
+ PrintStartStruct();
+
+ PrintPtr( dev_DevObj );
+
+#if DBG
+# if DREF_TOTAL != 5
+# error DREF_TOTAL is assumed to equal 5
+# endif
+ PrintULong( dev_RefTypes[ DREF_CREATE ] );
+ PrintULong( dev_RefTypes[ DREF_LOADED ] );
+ PrintULong( dev_RefTypes[ DREF_ADAPTER ] );
+ PrintULong( dev_RefTypes[ DREF_ADDRESS ] );
+ PrintULong( dev_RefTypes[ DREF_ORPHAN ] );
+#endif
+
+ PrintUShort( dev_Type );
+ PrintUShort( dev_Size );
+
+#if DBG
+ PrintNChar( dev_Signature1, sizeof( _obj.dev_Signature1 ));
+#endif
+
+ PrintULong( dev_RefCount );
+ PrintUChar( dev_State );
+
+ PrintUShort( dev_Adapters );
+
+ PrintLock( dev_Interlock );
+ PrintLock( dev_Lock );
+
+ for ( index = 0; index < NUM_SPXADDR_HASH_BUCKETS; index ++ )
+ {
+ PrintIndent();
+ dprintf( "dev_AddrHashTable[ %d ] = ", index );
+
+ dprint_addr_list( ( ULONG )_obj.dev_AddrHashTable[ index ],
+ FIELD_OFFSET( SPX_ADDR, sa_Next ));
+ }
+
+ for ( index = 0; index < NUM_SPXCONN_HASH_BUCKETS; index ++ )
+ {
+ PrintIndent();
+ dprintf( "dev_GlobalActiveConnList[ %d ] = ", index );
+
+ dprint_addr_list( ( ULONG )_obj.dev_GlobalActiveConnList[ index ],
+ FIELD_OFFSET( SPX_CONN_FILE, scf_Next ));
+ }
+
+ PrintUShort( dev_NextConnId );
+
+ PrintUShort( dev_CurrentSocket );
+
+ PrintFieldName( "dev_Network" );
+ dprintf("0x%-8hx%s", *(( ULONG *)_obj.dev_Network ), EOL);
+
+ PrintFieldName( "dev_Node" );
+ dprint_hardware_address( _obj.dev_Node );
+ dprintf( "%s", EOL );
+
+ PrintPtr( dev_ConfigInfo );
+
+ PrintULong( dev_CcId );
+
+ PrintJoin();
+ PrintPtr( dev_DeviceName );
+ dprintf( "\"%S\"\n", pDeviceName );
+
+ PrintULong( dev_DeviceNameLen );
+
+#if DBG
+ PrintNChar( dev_Signature2, sizeof( _obj.dev_Signature2 ));
+#endif
+
+ PrintAddr( dev_NdisBufferPoolHandle );
+
+ PrintAddr( dev_StatInterlock );
+ PrintAddr( dev_StatSpinLock );
+
+ PrintAddr( dev_Stat );
+ PrintAddr( dev_AddrResource );
+
+ PrintAddr( dev_ProviderInfo );
+
+ PrintEndStruct();
+}
+
+DECLARE_API( spxaddr )
+/*++
+
+Routine Description:
+
+ Dumps the most important fields of the specified DEVICE_CONTEXT object
+
+Arguments:
+
+ args - Address
+
+Return Value:
+
+ None
+
+--*/
+{
+ ULONG addressToDump = 0;
+ ULONG result;
+ char VarName[ MAX_LIST_VARIABLE_NAME_LENGTH + 1 ];
+ MEMBER_VARIABLE_INFO MemberInfo;
+ BOOL bFocusOnMemberVariable = FALSE;
+
+ if ( *args )
+ {
+ bFocusOnMemberVariable = ReadArgsForTraverse( args, VarName );
+ }
+
+ if ( *args && *args!='-' )
+ {
+ sscanf(args, "%lx", &addressToDump);
+ }
+
+ if ( bFocusOnMemberVariable )
+ {
+// if ( !LocateMemberVariable( "IpxDevice", VarName, ( PVOID )deviceToDump, &MemberInfo ))
+ {
+ return;
+ }
+
+ WriteMemberInfo( &MemberInfo );
+ next( hCurrentProcess, hCurrentThread, dwCurrentPc, dwProcessor, "" );
+ return;
+ }
+
+ DumpSpxAddress( addressToDump, VERBOSITY_NORMAL );
+
+ return;
+}
+
+#ifdef _obj
+# undef _obj
+# undef _objAddr
+# undef _objType
+# undef _objTypeName
+#endif
+
+#define _obj Address
+#define _objAddr AddressToDump
+#define _objType SPX_ADDR
+#define _objTypeName "SPX_ADDR"
+
+VOID
+DumpSpxAddress
+(
+ ULONG _objAddr,
+ VERBOSITY Verbosity
+)
+/*++
+
+Routine Description:
+
+ Dumps the fields of the specified DEVICE_CONTEXT structure
+
+Arguments:
+
+ DeviceToDump - The device context object to display
+ Full - Display a partial listing if 0, full listing otherwise.
+
+Return Value:
+
+ None
+
+--*/
+{
+ _objType _obj;
+ ULONG result;
+ unsigned int index;
+
+ if ( !ReadMemory( _objAddr,
+ &_obj,
+ sizeof( _obj ),
+ &result ))
+ {
+ dprintf("%08lx: Could not read %s structure.\n", _objAddr, _objTypeName );
+ return;
+ }
+
+ CHECK_SIGNATURE( sa_Type, SPX_ADDRESS_SIGNATURE );
+
+ if ( Verbosity == VERBOSITY_ONE_LINER )
+ {
+ dprintf( "Socket = %d", _obj.sa_Socket );
+ if ( _obj.sa_Flags & SPX_ADDR_CLOSING )
+ {
+ dprintf(" (CLOSING)");
+ }
+ return;
+ }
+
+ PrintStartStruct();
+
+#if DBG
+# if AREF_TOTAL !=4
+# error AREF_TOTAL is assumed to equal 4
+# endif
+
+ PrintULong( sa_RefTypes[ AREF_ADDR_FILE ] );
+ PrintULong( sa_RefTypes[ AREF_LOOKUP ] );
+ PrintULong( sa_RefTypes[ AREF_RECEIVE ] );
+ PrintULong( sa_RefTypes[ 3 ] );
+#endif
+
+ PrintUShort( sa_Size );
+ PrintXEnum( sa_Type, EnumStructureType );
+
+ PrintULong( sa_RefCount );
+
+ PrintPtr( sa_Next );
+ PrintXULong( sa_Flags );
+
+ PrintFieldName( "sa_AddrFileList" );
+ dprint_addr_list( ( ULONG )_obj.sa_AddrFileList,
+ FIELD_OFFSET( SPX_ADDR_FILE, saf_Next ));
+
+ PrintFieldName( "sa_InactiveConnList" );
+ dprint_addr_list( ( ULONG )_obj.sa_InactiveConnList,
+ FIELD_OFFSET( SPX_CONN_FILE, scf_Next ));
+
+ PrintFieldName( "sa_ActiveConnList" );
+ dprint_addr_list( ( ULONG )_obj.sa_ActiveConnList,
+ FIELD_OFFSET( SPX_CONN_FILE, scf_Next ));
+
+ PrintFieldName( "sa_ListenConnList" );
+ dprint_addr_list( ( ULONG )_obj.sa_ListenConnList,
+ FIELD_OFFSET( SPX_CONN_FILE, scf_Next ));
+
+ PrintLock( sa_Lock );
+ PrintUShort( sa_Socket );
+ PrintPtr( sa_Device );
+ PrintPtr( sa_DeviceLock );
+
+ PrintStartNamedStruct( "union" );
+
+ PrintAddr( u.sa_ShareAccess );
+ PrintAddr( u.sa_DestroyAddrQueueItem );
+
+ PrintEndStruct();
+
+ PrintPtr( sa_SecurityDescriptor );
+ PrintEndStruct();
+}
+
+DECLARE_API( spxaddrfile )
+{
+ ULONG addressToDump = 0;
+ ULONG result;
+ char VarName[ MAX_LIST_VARIABLE_NAME_LENGTH + 1 ];
+ MEMBER_VARIABLE_INFO MemberInfo;
+ BOOL bFocusOnMemberVariable = FALSE;
+
+ if ( *args )
+ {
+ bFocusOnMemberVariable = ReadArgsForTraverse( args, VarName );
+ }
+
+ if ( *args && *args!='-' )
+ {
+ sscanf(args, "%lx", &addressToDump);
+ }
+
+ if ( bFocusOnMemberVariable )
+ {
+// if ( !LocateMemberVariable( "IpxDevice", VarName, ( PVOID )deviceToDump, &MemberInfo ))
+ {
+ return;
+ }
+
+ WriteMemberInfo( &MemberInfo );
+ next( hCurrentProcess, hCurrentThread, dwCurrentPc, dwProcessor, "" );
+ return;
+ }
+
+ DumpSpxAddressFile( addressToDump, VERBOSITY_NORMAL );
+
+ return;
+}
+
+#ifdef _obj
+# undef _obj
+# undef _objAddr
+# undef _objType
+# undef _objTypeName
+#endif
+
+#define _obj AddressFile
+#define _objAddr AddressFileToDump
+#define _objType SPX_ADDR_FILE
+#define _objTypeName "SPX_ADDR_FILE"
+
+VOID
+DumpSpxAddressFile
+(
+ ULONG _objAddr,
+ VERBOSITY Verbosity
+)
+/*++
+
+Routine Description:
+
+ Dumps the fields of the specified DEVICE_CONTEXT structure
+
+Arguments:
+
+ DeviceToDump - The device context object to display
+ Full - Display a partial listing if 0, full listing otherwise.
+
+Return Value:
+
+ None
+
+--*/
+{
+ _objType _obj;
+ ULONG result;
+ unsigned int index;
+
+ if ( !ReadMemory( _objAddr,
+ &_obj,
+ sizeof( _obj ),
+ &result ))
+ {
+ dprintf("%08lx: Could not read %s structure.\n", _objAddr, _objTypeName );
+ return;
+ }
+
+ CHECK_SIGNATURE( saf_Type, SPX_ADDRESSFILE_SIGNATURE );
+
+ if ( Verbosity == VERBOSITY_ONE_LINER )
+ {
+ switch ( _obj.saf_Flags & 0x03 )
+ {
+ case SPX_ADDRFILE_OPENING:
+ dprintf( "OPENING " );
+ break;
+ case SPX_ADDRFILE_OPEN:
+ dprintf( "OPEN " );
+ break;
+ case SPX_ADDRFILE_CLOSING:
+ dprintf( "CLOSING " );
+ break;
+ }
+ DumpSpxAddress( ( ULONG )_obj.saf_Addr, VERBOSITY_ONE_LINER );
+ return;
+ }
+
+ PrintStartStruct();
+#if DBG
+# if AFREF_TOTAL !=4
+# error AFREF_TOTAL is assumed equal to 4.
+# endif
+
+ PrintULong( saf_RefTypes[ AFREF_CREATE ] );
+ PrintULong( saf_RefTypes[ AFREF_VERIFY ] );
+ PrintULong( saf_RefTypes[ AFREF_INDICATION ] );
+ PrintULong( saf_RefTypes[ AFREF_CONN_ASSOC ] );
+#endif
+
+ PrintXEnum( saf_Type, EnumStructureType );
+ PrintUShort( saf_Size );
+
+ PrintULong( saf_RefCount );
+ PrintFieldName( "saf_Next" );
+ dprint_addr_list( ( ULONG )_obj.saf_Next,
+ FIELD_OFFSET( SPX_ADDR_FILE, saf_Next ));
+
+ PrintFieldName( "saf_GlobalNext" );
+ dprint_addr_list( ( ULONG )_obj.saf_GlobalNext,
+ FIELD_OFFSET( SPX_ADDR_FILE, saf_GlobalNext));
+
+ PrintFieldName( "saf_AssocConnList" );
+ dprint_addr_list( ( ULONG )_obj.saf_AssocConnList,
+ FIELD_OFFSET( SPX_CONN_FILE, scf_AssocNext ));
+
+ PrintXUShort( saf_Flags );
+ PrintPtr( saf_Addr );
+ PrintPtr( saf_AddrLock );
+
+ PrintPtr( saf_FileObject );
+ PrintPtr( saf_Device );
+ PrintPtr( saf_CloseReq );
+
+ PrintSymbolPtr( saf_ConnHandler );
+ PrintXULong( saf_ConnHandlerCtx );
+
+ PrintSymbolPtr( saf_DiscHandler );
+ PrintXULong( saf_DiscHandlerCtx );
+
+ PrintSymbolPtr( saf_RecvHandler );
+ PrintXULong( saf_RecvHandlerCtx );
+
+ PrintSymbolPtr( saf_SendPossibleHandler );
+ PrintXULong( saf_SendPossibleHandlerCtx );
+
+ PrintSymbolPtr( saf_ErrHandler );
+ PrintXULong( saf_ErrHandlerCtx );
+
+ PrintPtr( saf_ErrHandlerOwner );
+
+ PrintEndStruct();
+}
+
+DECLARE_API( spxconnfile )
+{
+ ULONG addressToDump = 0;
+ ULONG result;
+ char VarName[ MAX_LIST_VARIABLE_NAME_LENGTH + 1 ];
+ MEMBER_VARIABLE_INFO MemberInfo;
+ BOOL bFocusOnMemberVariable = FALSE;
+
+ if ( *args )
+ {
+ bFocusOnMemberVariable = ReadArgsForTraverse( args, VarName );
+ }
+
+ if ( *args && *args!='-' )
+ {
+ sscanf(args, "%lx", &addressToDump);
+ }
+
+ if ( bFocusOnMemberVariable )
+ {
+ if ( !LocateMemberVariable( "SpxConnFile", VarName, ( PVOID )addressToDump, &MemberInfo ))
+ {
+ return;
+ }
+
+ WriteMemberInfo( &MemberInfo );
+ next( hCurrentProcess, hCurrentThread, dwCurrentPc, dwProcessor, "" );
+ return;
+ }
+
+ DumpSpxConnFile( addressToDump, VERBOSITY_NORMAL );
+
+ return;
+}
+
+#ifdef _obj
+# undef _obj
+# undef _objAddr
+# undef _objType
+# undef _objTypeName
+#endif
+
+#define _obj ConnFile
+#define _objAddr ConnFileToDump
+#define _objType SPX_CONN_FILE
+#define _objTypeName "SPX_CONN_FILE"
+
+VOID
+DumpSpxConnFile
+(
+ ULONG _objAddr,
+ VERBOSITY Verbosity
+)
+/*++
+
+Routine Description:
+
+ Dumps the fields of the specified DEVICE_CONTEXT structure
+
+Arguments:
+
+ DeviceToDump - The device context object to display
+ Full - Display a partial listing if 0, full listing otherwise.
+
+Return Value:
+
+ None
+
+--*/
+{
+ _objType _obj;
+ ULONG result;
+ unsigned int index;
+ BOOL bActive;
+
+ if ( !ReadMemory( _objAddr,
+ &_obj,
+ sizeof( _obj ),
+ &result ))
+ {
+ dprintf("%08lx: Could not read %s structure.\n", _objAddr, _objTypeName );
+ return;
+ }
+
+ CHECK_SIGNATURE( scf_Type, SPX_CONNFILE_SIGNATURE );
+
+ if ( Verbosity = VERBOSITY_ONE_LINER )
+ {
+ dprintf( "NOT IMPLEMENTED" );
+ return;
+ }
+
+ PrintStartStruct();
+
+#if DBG
+# if CFREF_TOTAL != 14
+# error CFREF_TOTAL is assumed equal to 13.
+# endif
+
+ PrintULong( scf_RefTypes[ CFREF_CREATE ] );
+ PrintULong( scf_RefTypes[ CFREF_VERIFY ] );
+ PrintULong( scf_RefTypes[ CFREF_INDICATION ] );
+ PrintULong( scf_RefTypes[ CFREF_BYCTX ] );
+ PrintULong( scf_RefTypes[ CFREF_BYID ] );
+ PrintULong( scf_RefTypes[ CFREF_ADDR ] );
+ PrintULong( scf_RefTypes[ CFREF_REQ ] );
+ PrintULong( scf_RefTypes[ CFREF_TIMER ] );
+ PrintULong( scf_RefTypes[ CFREF_PKTIZE ] );
+ PrintULong( scf_RefTypes[ CFREF_RECV ] );
+ PrintULong( scf_RefTypes[ CFREF_ABORTPKT ] );
+ PrintULong( scf_RefTypes[ CFREF_ERRORSTATE ] );
+ PrintULong( scf_RefTypes[ CFREF_FINDROUTE ] );
+ PrintULong( scf_RefTypes[ CFREF_DISCWAITSPX ] );
+#endif
+
+ PrintXEnum( scf_Type, EnumStructureType );
+ PrintUShort( scf_Size );
+
+ PrintULong( scf_RefCount );
+
+ PrintFieldName( "scf_Next" );
+ dprint_addr_list( ( ULONG )_obj.scf_Next,
+ FIELD_OFFSET( SPX_CONN_FILE, scf_Next ));
+
+ PrintFieldName( "scf_AssocNext" );
+ dprint_addr_list( ( ULONG )_obj.scf_AssocNext,
+ FIELD_OFFSET( SPX_CONN_FILE, scf_AssocNext ));
+
+ PrintFieldName( "scf_GlobalActiveNext" );
+ dprint_addr_list( ( ULONG )_obj.scf_GlobalActiveNext,
+ FIELD_OFFSET( SPX_CONN_FILE, scf_GlobalActiveNext ));
+
+ PrintFieldName( "scf_GlobalNext" );
+ dprint_addr_list( ( ULONG )_obj.scf_GlobalNext,
+ FIELD_OFFSET( SPX_CONN_FILE, scf_GlobalNext ));
+
+ PrintFieldName( "scf_PktNext" );
+ dprint_addr_list( ( ULONG )_obj.scf_PktNext,
+ FIELD_OFFSET( SPX_CONN_FILE, scf_PktNext ));
+
+ PrintFieldName( "scf_ProcessRcvNext" );
+ dprint_addr_list( ( ULONG )_obj.scf_ProcessRecvNext,
+ FIELD_OFFSET( SPX_CONN_FILE, scf_ProcessRecvNext ));
+
+ bActive = ( _obj.scf_Flags & SPX_CONNFILE_MAINMASK ) == SPX_CONNFILE_ACTIVE;
+
+ PrintXULong( scf_Flags );
+ PrintXEnumMask( scf_Flags, EnumConnFileMain, SPX_CONNFILE_MAINMASK );
+
+ if (( _obj.scf_Flags & SPX_CONNFILE_MAINMASK ) == SPX_CONNFILE_LISTENING )
+ {
+ PrintXEnumMask( scf_Flags, EnumConnFileListening, SPX_LISTEN_MASK );
+ }
+
+ if (( _obj.scf_Flags & SPX_CONNFILE_MAINMASK ) == SPX_CONNFILE_CONNECTING )
+ {
+ PrintXEnumMask( scf_Flags, EnumConnFileConnecting, SPX_CONNECT_MASK );
+ }
+
+ if ( bActive )
+ {
+ PrintXEnumMask( scf_Flags, EnumConnFileSend, SPX_SEND_MASK );
+ PrintXEnumMask( scf_Flags, EnumConnFileReceive, SPX_RECV_MASK );
+ }
+
+ if ( (( _obj.scf_Flags & SPX_CONNFILE_MAINMASK ) == SPX_CONNFILE_LISTENING ) ||
+ bActive )
+ {
+ PrintXEnumMask( scf_Flags, EnumConnFileDisconnect, SPX_DISC_MASK );
+ }
+
+ PrintFlagsMask( scf_Flags, FlagsConnFile, 0xFFFF0000 );
+
+ PrintFlags( scf_Flags2, Flags2ConnFile );
+
+#if DBG
+ PrintXULong( scf_GhostFlags );
+ PrintXULong( scf_GhostFlags2 );
+ PrintULong( scf_GhostRefCount );
+ PrintPtr( scf_GhostDiscReq );
+#endif
+
+ if ( bActive )
+ {
+ PrintULong( scf_WRetryCount );
+ }
+ else
+ {
+ PrintULong( scf_CRetryCount );
+ }
+
+ PrintULong( scf_RRetryCount );
+ PrintXUShort( scf_RRetrySeqNum );
+
+ if ( bActive )
+ {
+ PrintULong( scf_RTimerId );
+ }
+ else
+ {
+ PrintULong( scf_CTimerId );
+ }
+
+
+ PrintULong( scf_WTimerId );
+ PrintULong( scf_TTimerId );
+ PrintULong( scf_ATimerId );
+
+ PrintULong( scf_BaseT1 );
+ PrintULong( scf_AveT1 );
+ PrintULong( scf_DevT1 );
+
+ PrintUShort( scf_LocalConnId );
+ PrintUShort( scf_SendSeqNum );
+ PrintUShort( scf_SentAllocNum );
+ PrintUShort( scf_RecvSeqNum );
+ PrintUShort( scf_RecdAckNum );
+ PrintUShort( scf_RecdAllocNum );
+ PrintUShort( scf_RetrySeqNum );
+
+ PrintUShort( scf_RenegAckAckNum );
+
+ PrintNChar( scf_RemAddr, sizeof( _obj.scf_RemAddr ));
+ PrintNChar( scf_RemAckAddr, sizeof( _obj.scf_RemAckAddr ));
+
+ PrintUShort( scf_RemConnId );
+ PrintUShort( scf_RenegMaxPktSize );
+
+ PrintIpxLocalTarget( scf_AckLocalTarget );
+
+ PrintUShort( scf_MaxPktSize );
+ PrintUChar( scf_DataType );
+
+ PrintIpxLocalTarget( scf_LocalTarget );
+ PrintLock( scf_Lock );
+
+ PrintJoin();
+ PrintPtr( scf_AddrFile );
+ dprintf( "(" );
+ DumpSpxAddressFile( ( ULONG )_obj.scf_AddrFile, VERBOSITY_ONE_LINER );
+ dprintf( ")\n" );
+
+ PrintPtr( scf_ConnCtx );
+
+ PrintPtr( scf_FileObject );
+
+ PrintLL( scf_DiscLinkage );
+ PrintLL( scf_ReqLinkage );
+ PrintLL( scf_ReqDoneLinkage );
+ PrintLL( scf_RecvDoneLinkage );
+ PrintLL( scf_RecvLinkage );
+ PrintPtr( scf_CurRecvReq );
+ PrintULong( scf_CurRecvOffset );
+ PrintULong( scf_CurRecvSize );
+ PrintPtr( scf_ReqPkt );
+ PrintULong( scf_ReqPktOffset );
+ PrintULong( scf_ReqPktSize );
+ PrintULong( scf_ReqPktFlags );
+ PrintEnum( scf_ReqPktType, EnumSpxSendReqType );
+ PrintPtr( scf_SendSeqListHead );
+ PrintPtr( scf_SendSeqListTail );
+ PrintPtr( scf_SendListHead );
+ PrintPtr( scf_SendListTail );
+ PrintPtr( scf_RecvListHead );
+ PrintPtr( scf_RecvListTail );
+ PrintPtr( scf_ConnectReq );
+ PrintPtr( scf_CleanupReq );
+ PrintPtr( scf_CloseReq );
+
+#if DBG
+ PrintUShort( scf_PktSeqNum );
+ PrintXULong( scf_PktFlags );
+ PrintXULong( scf_PktFlags2 );
+
+ PrintULong( scf_IndBytes );
+ PrintULong( scf_IndLine );
+#endif
+
+#if DBG_WDW_CLOSE
+ PrintULong( scf_WdwCloseAve );
+ PrintAddr( scf_WdwCloseTime );
+#endif
+
+ PrintPtr( scf_Device );
+
+ PrintEndStruct();
+}
+
diff --git a/private/ntos/tdi/isn/isnext/spxext.h b/private/ntos/tdi/isn/isnext/spxext.h
new file mode 100644
index 000000000..ec94d99c3
--- /dev/null
+++ b/private/ntos/tdi/isn/isnext/spxext.h
@@ -0,0 +1,16 @@
+#if !defined( INCLUDED_SPXEXT_H )
+#define INCLUDED_SPXEXT_H
+
+extern MEMBER_TABLE SpxConnFileMembers[];
+
+VOID
+DumpSpxConnFile
+(
+ ULONG DeviceToDump,
+ VERBOSITY Verbosity
+);
+
+#define SPX_MAJOR_STRUCTURES \
+{ "SpxConnFile", SpxConnFileMembers, DumpSpxConnFile }
+
+#endif
diff --git a/private/ntos/tdi/isn/isnext/traverse.c b/private/ntos/tdi/isn/isnext/traverse.c
new file mode 100644
index 000000000..98715779c
--- /dev/null
+++ b/private/ntos/tdi/isn/isnext/traverse.c
@@ -0,0 +1,419 @@
+#include "precomp.h"
+#pragma hdrstop
+
+MEMBER_VARIABLE_INFO _MemberInfo;
+
+
+#define STATE_FILENAME "isnext.state"
+
+STRUCTURE_TABLE StructureTable[] =
+{
+ IPX_MAJOR_STRUCTURES,
+ SPX_MAJOR_STRUCTURES,
+ { NULL }
+};
+
+BOOL NextListEntry( ULONG Current, PULONG Next );
+BOOL PrevListEntry( ULONG Current, PULONG Prev );
+
+VOID NextElement( PMEMBER_VARIABLE_INFO pMemberInfo );
+VOID PrevElement( PMEMBER_VARIABLE_INFO pMemberInfo );
+VOID DumpListItem( PMEMBER_VARIABLE_INFO pMemberInfo );
+
+
+BOOL
+LocateMemberVariable
+(
+ PCHAR pchStructName,
+ PCHAR pchMemberName,
+ PVOID pvStructure,
+ PMEMBER_VARIABLE_INFO pMemberInfo
+)
+{
+ BOOL bMatch;
+ int index;
+ PMEMBER_TABLE pMemberTable;
+ CHAR pchCurrent[ MAX_LIST_VARIABLE_NAME_LENGTH + 1 ];
+ CHAR _pchStructName[ MAX_LIST_VARIABLE_NAME_LENGTH + 1 ];
+ CHAR _pchMemberName[ MAX_LIST_VARIABLE_NAME_LENGTH + 1 ];
+
+ dprintf( "LocateMemberVariable( \"%s\", \"%s\", 0x%08X )\n", pchStructName, pchMemberName, pMemberInfo );
+
+ strcpy( _pchStructName, pchStructName );
+ strcpy( _pchMemberName, pchMemberName );
+
+ _strupr( _pchStructName );
+ _strupr( _pchMemberName );
+
+ pMemberInfo->StructureIndex = 0;
+ pMemberInfo->MemberIndex = 0;
+
+ bMatch = FALSE;
+
+ for ( index = 0; StructureTable[ index ].pchStructName != NULL; index ++ )
+ {
+ strcpy( pchCurrent, StructureTable[ index ].pchStructName );
+ _strupr( pchCurrent );
+
+ if ( strstr( pchCurrent, _pchStructName ))
+ {
+ if ( bMatch )
+ {
+ dprintf( "The specified structure name is ambiguous.\n" );
+ return( FALSE );
+ }
+
+ pMemberInfo->StructureIndex = index;
+
+ bMatch = TRUE;
+ }
+ }
+
+ if ( !bMatch )
+ {
+ dprintf( "No matching structure name was found.\n" );
+ return( FALSE );
+ }
+
+ pMemberTable = StructureTable[ pMemberInfo->StructureIndex ].pMemberTable;
+
+ bMatch = FALSE;
+
+ for ( index = 0; pMemberTable[ index ].pchMemberName != NULL; index ++ )
+ {
+ strcpy( pchCurrent, pMemberTable[ index ].pchMemberName );
+ _strupr( pchCurrent );
+
+ if ( strstr( pchCurrent, _pchMemberName ))
+ {
+ if ( bMatch )
+ {
+ dprintf( "The variable specified is ambiguous.\n" );
+ return( FALSE );
+ }
+
+ pMemberInfo->MemberIndex = index;
+
+ bMatch = TRUE;
+ }
+ }
+
+ if ( !bMatch )
+ {
+ dprintf( "No matching member name was found in the %s structure.\n", pchStructName );
+ return( FALSE );
+ }
+
+ pMemberInfo->prHeadContainingObject = ( ULONG )pvStructure;
+ pMemberInfo->prHeadLinkage = (( ULONG )pvStructure ) + pMemberTable[ pMemberInfo->MemberIndex ].cbOffsetToHead;
+ pMemberInfo->prCurrentLinkage = pMemberInfo->prHeadLinkage;
+ pMemberInfo->cCurrentElement = 0;
+
+ return( TRUE );
+}
+
+BOOL WriteMemberInfo( PMEMBER_VARIABLE_INFO pMemberInfo )
+{
+ HANDLE hStateFile;
+ DWORD dwWritten;
+
+ hStateFile = CreateFile( STATE_FILENAME,
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+
+ if ( hStateFile == NULL )
+ {
+ dprintf( "Can't create state file\n" );
+ return( FALSE );
+ }
+
+ if ( !WriteFile( hStateFile,
+ pMemberInfo,
+ sizeof( MEMBER_VARIABLE_INFO ),
+ &dwWritten,
+ NULL ) || ( dwWritten != sizeof( MEMBER_VARIABLE_INFO )))
+ {
+ dprintf( "Can't write to state file\n" );
+ CloseHandle( hStateFile );
+ return( FALSE );
+ }
+
+ CloseHandle( hStateFile );
+
+ return( TRUE );
+}
+
+BOOL ReadMemberInfo( PMEMBER_VARIABLE_INFO pMemberInfo )
+{
+ HANDLE hStateFile;
+ DWORD dwRead;
+
+ hStateFile = CreateFile( STATE_FILENAME,
+ GENERIC_READ,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+ if ( hStateFile == NULL )
+ {
+ dprintf( "Can't open state file\n" );
+ return( FALSE );
+ }
+
+ if ( !ReadFile( hStateFile,
+ pMemberInfo,
+ sizeof( MEMBER_VARIABLE_INFO ),
+ &dwRead,
+ NULL ) || ( dwRead != sizeof( MEMBER_VARIABLE_INFO )))
+ {
+ dprintf( "Can't read from state file\n" );
+ CloseHandle( hStateFile );
+ return( FALSE );
+ }
+
+ CloseHandle( hStateFile );
+ return( TRUE );
+}
+
+
+DECLARE_API( next )
+{
+ MEMBER_VARIABLE_INFO MemberInfo;
+
+ if ( !ReadMemberInfo( &MemberInfo ) )
+ {
+ return;
+ }
+
+ NextElement( &MemberInfo );
+ DumpListItem( &MemberInfo );
+ WriteMemberInfo( &MemberInfo );
+}
+
+DECLARE_API( prev )
+{
+ MEMBER_VARIABLE_INFO MemberInfo;
+
+ if ( !ReadMemberInfo( &MemberInfo ) )
+ {
+ return;
+ }
+
+ PrevElement( &MemberInfo );
+ DumpListItem( &MemberInfo );
+ WriteMemberInfo( &MemberInfo );
+}
+
+
+VOID DumpListItem( PMEMBER_VARIABLE_INFO pMemberInfo )
+{
+ PBYTE pbObject;
+ PMEMBER_TABLE pMemberTable;
+
+ dprintf( "Focus is on: %s.%s, element # %d\n",
+ StructureTable[ pMemberInfo->StructureIndex ].pchStructName,
+ StructureTable[ pMemberInfo->StructureIndex ].pMemberTable[ pMemberInfo->MemberIndex ].pchMemberName,
+ pMemberInfo->cCurrentElement );
+
+ pMemberTable = &StructureTable[ pMemberInfo->StructureIndex ].pMemberTable[ pMemberInfo->MemberIndex ];
+
+ if ( pMemberInfo->prCurrentLinkage == pMemberInfo->prHeadLinkage )
+ {
+ //
+ // Rather than dumping the head list item, dump all the items on the list,
+ // in summary form.
+ //
+
+ do
+ {
+ NextElement( pMemberInfo );
+
+ if ( pMemberInfo->prCurrentLinkage != pMemberInfo->prHeadLinkage )
+ {
+ pbObject = (( PBYTE )pMemberInfo->prCurrentLinkage )
+ - pMemberTable->cbOffsetToLink;
+
+ pMemberTable->DumpStructure( ( ULONG )pbObject, VERBOSITY_ONE_LINER );
+ dprintf( "\n" );
+ }
+ } while ( pMemberInfo->prCurrentLinkage != pMemberInfo->prHeadLinkage );
+ }
+ else
+ {
+ pbObject = (( PBYTE )pMemberInfo->prCurrentLinkage )
+ - pMemberTable->cbOffsetToLink;
+
+ pMemberTable->DumpStructure( ( ULONG )pbObject, VERBOSITY_NORMAL );
+ }
+}
+
+
+VOID NextElement( PMEMBER_VARIABLE_INFO pMemberInfo )
+{
+ ULONG NextLinkage;
+ PMEMBER_TABLE pMember;
+
+ pMember = &StructureTable[ pMemberInfo->StructureIndex ].pMemberTable[ pMemberInfo->MemberIndex ];
+
+ if ( !pMember->Next( pMemberInfo->prCurrentLinkage, &NextLinkage ))
+ {
+ dprintf( "Command failed.\n" );
+ return;
+ }
+
+ pMemberInfo->prCurrentLinkage = NextLinkage;
+ pMemberInfo->cCurrentElement++;
+
+ if ( pMemberInfo->prCurrentLinkage == pMemberInfo->prHeadLinkage )
+ {
+ pMemberInfo->cCurrentElement = 0;
+ }
+}
+
+BOOL NextListEntry( ULONG Current, PULONG Next )
+{
+ ULONG result;
+ ULONG prNextEntry;
+ LIST_ENTRY Entry;
+ LIST_ENTRY NextEntry;
+
+ if ( !ReadMemory( Current,
+ &Entry,
+ sizeof( Entry ),
+ &result ))
+ {
+ dprintf( "Couldn't read current list entry at 0x%08X.\n", Current );
+ return( FALSE );
+ }
+
+ prNextEntry = ( ULONG )Entry.Flink;
+
+ if ( !ReadMemory( prNextEntry,
+ &NextEntry,
+ sizeof( NextEntry ),
+ &result ))
+ {
+ dprintf( "Couldn't read next list entry at 0x%08X.\n", prNextEntry );
+ return( FALSE );
+ }
+
+ if ( ( ULONG )NextEntry.Blink != Current )
+ {
+ dprintf( "Next entry's Blink doesn't match current entry's address.\n" );
+ dprintf( "The list might be corrupt, or you may be using traversal state saved before the list changed.\n" );
+ return( FALSE );
+ }
+
+ *Next = prNextEntry;
+ return( TRUE );
+}
+
+VOID PrevElement( PMEMBER_VARIABLE_INFO pMemberInfo )
+{
+ ULONG PrevLinkage;
+ PMEMBER_TABLE pMember;
+
+ pMember = &StructureTable[ pMemberInfo->StructureIndex ].pMemberTable[ pMemberInfo->MemberIndex ];
+
+ if ( !pMember->Prev( pMemberInfo->prCurrentLinkage, &PrevLinkage ))
+ {
+ dprintf( "Command failed.\n" );
+ return;
+ }
+
+ pMemberInfo->prCurrentLinkage = PrevLinkage;
+ pMemberInfo->cCurrentElement++;
+
+ if ( pMemberInfo->prCurrentLinkage == pMemberInfo->prHeadLinkage )
+ {
+ pMemberInfo->cCurrentElement = 0;
+ }
+}
+
+BOOL PrevListEntry( ULONG Current, PULONG Prev )
+{
+ ULONG result;
+ ULONG prPrevEntry;
+ LIST_ENTRY Entry;
+ LIST_ENTRY PrevEntry;
+
+ if ( !ReadMemory( Current,
+ &Entry,
+ sizeof( Entry ),
+ &result ))
+ {
+ dprintf( "Couldn't read current list entry at 0x%08X.\n", Current );
+ return( FALSE );
+ }
+
+ prPrevEntry = ( ULONG )Entry.Blink;
+
+ if ( !ReadMemory( prPrevEntry,
+ &PrevEntry,
+ sizeof( PrevEntry ),
+ &result ))
+ {
+ dprintf( "Couldn't read previous list entry at 0x%08X.\n", prPrevEntry );
+ return( FALSE );
+ }
+
+ if ( ( ULONG )PrevEntry.Blink != Current )
+ {
+ dprintf( "Previous entry's Blink doesn't match current entry's address.\n" );
+ dprintf( "The list might be corrupt, or you may be using traversal state saved before the list changed.\n" );
+ return( FALSE );
+ }
+
+ *Prev = prPrevEntry;
+ return( TRUE );
+}
+
+BOOL ReadArgsForTraverse( const char *args, char *VarName )
+{
+ PCHAR pchListVar;
+ int index;
+ BOOL bRetval = FALSE;
+
+ pchListVar = strstr( args, "-l" );
+
+ if ( pchListVar )
+ {
+ pchListVar += 2;
+
+ while ( *pchListVar == ' ' )
+ {
+ pchListVar ++;
+ }
+
+ if ( *pchListVar == '\0' )
+ {
+ dprintf( "NOT IMPLEMENTED: usage on -l\n" );
+// ipxdev_usage();
+ return( bRetval );
+ }
+
+ for ( index = 0; index < MAX_LIST_VARIABLE_NAME_LENGTH; index ++ )
+ {
+ VarName[ index ] = *pchListVar;
+
+ if ( *pchListVar == ' ' || *pchListVar == '\0' )
+ {
+ VarName[ index ] = '\0';
+ break;
+ }
+
+ VarName[ index + 1 ] = '\0';
+
+ pchListVar ++;
+ }
+
+ bRetval = TRUE;
+ }
+
+ return( bRetval );
+}
diff --git a/private/ntos/tdi/isn/isnext/traverse.h b/private/ntos/tdi/isn/isnext/traverse.h
new file mode 100644
index 000000000..287b57a13
--- /dev/null
+++ b/private/ntos/tdi/isn/isnext/traverse.h
@@ -0,0 +1,55 @@
+#if !defined( INCLUDED_TRAVERSE_H )
+#define INCLUDED_TRAVERSE_H
+
+#define MAX_LIST_VARIABLE_NAME_LENGTH 200
+
+typedef struct
+{
+ int StructureIndex;
+ int MemberIndex;
+
+ ULONG prHeadContainingObject;
+ ULONG prHeadLinkage;
+ ULONG prCurrentLinkage;
+ int cCurrentElement;
+} MEMBER_VARIABLE_INFO, *PMEMBER_VARIABLE_INFO;
+
+typedef VOID (*pfDumpStructure)( ULONG , VERBOSITY );
+typedef BOOL (*pfNextStructure)( ULONG Current, PULONG Next );
+typedef BOOL (*pfPrevStructure)( ULONG Current, PULONG Prev );
+
+typedef struct
+{
+ PCHAR pchMemberName;
+
+ LONG cbOffsetToHead;
+
+ pfDumpStructure DumpStructure;
+ pfNextStructure Next;
+ pfPrevStructure Prev;
+ LONG cbOffsetToLink;
+
+} MEMBER_TABLE, *PMEMBER_TABLE;
+
+typedef struct
+{
+ PCHAR pchStructName;
+ PMEMBER_TABLE pMemberTable;
+
+ pfDumpStructure DumpStructure;
+} STRUCTURE_TABLE, *PSTRUCTURE_TABLE;
+
+BOOL ReadArgsForTraverse( const char *args, char *VarName );
+BOOL ReadMemberInfo( PMEMBER_VARIABLE_INFO pMemberInfo );
+BOOL WriteMemberInfo( PMEMBER_VARIABLE_INFO pMemberInfo );
+BOOL LocateMemberVariable( PCHAR pchStructName, PCHAR pchMemberName, PVOID pvStructure, PMEMBER_VARIABLE_INFO pMemberInfo );
+
+
+DECLARE_API( next );
+DECLARE_API( prev );
+
+extern BOOL NextListEntry( ULONG Current, PULONG Next );
+extern BOOL PrevListEntry( ULONG Current, PULONG Prev );
+
+
+#endif
diff --git a/private/ntos/tdi/isn/nb/action.c b/private/ntos/tdi/isn/nb/action.c
new file mode 100644
index 000000000..9ff843a76
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/action.c
@@ -0,0 +1,221 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ action.c
+
+Abstract:
+
+ This module contains code which implements the TDI action
+ dispatch routines.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+typedef struct _NB_ACTION_GET_COUNTS {
+ USHORT MaximumNicId; // returns maximum NIC ID
+ USHORT NicIdCounts[32]; // session counts for first 32 NIC IDs
+} NB_ACTION_GET_COUNTS, *PNB_ACTION_GET_COUNTS;
+
+
+NTSTATUS
+NbiTdiAction(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles action requests.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the action.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ PADDRESS_FILE AddressFile;
+ PCONNECTION Connection;
+ UINT BufferLength;
+ UINT DataLength;
+ PNDIS_BUFFER NdisBuffer;
+ CTELockHandle LockHandle;
+ union {
+ PNB_ACTION_GET_COUNTS GetCounts;
+ } u; // BUGBUG: Make these unaligned??
+ PNWLINK_ACTION NwlinkAction;
+ UINT i;
+ static UCHAR BogusId[4] = { 0x01, 0x00, 0x00, 0x00 }; // old nwrdr uses this
+
+
+ //
+ // To maintain some compatibility with the NWLINK streams-
+ // based transport, we use the streams header format for
+ // our actions. The old transport expected the action header
+ // to be in InputBuffer and the output to go in OutputBuffer.
+ // We follow the TDI spec, which states that OutputBuffer
+ // is used for both input and output. Since IOCTL_TDI_ACTION
+ // is method out direct, this means that the output buffer
+ // is mapped by the MDL chain; for action the chain will
+ // only have one piece so we use it for input and output.
+ //
+
+ NdisBuffer = REQUEST_NDIS_BUFFER(Request);
+ if (NdisBuffer == NULL) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ NdisQueryBuffer (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength);
+
+ if ((!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MISN", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MIPX", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "XPIM", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), BogusId, 4))) {
+
+ return STATUS_NOT_SUPPORTED;
+ }
+
+
+ //
+ // Make sure we have enough room for just the header not
+ // including the data.
+ //
+
+ if (BufferLength < (UINT)(FIELD_OFFSET(NWLINK_ACTION, Data[0]))) {
+ NB_DEBUG (QUERY, ("Nwlink action failed, buffer too small\n"));
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ DataLength = BufferLength - FIELD_OFFSET(NWLINK_ACTION, Data[0]);
+
+
+ //
+ // Make sure that the correct file object is being used.
+ //
+
+ if (NwlinkAction->OptionType == NWLINK_OPTION_ADDRESS) {
+
+ if (REQUEST_OPEN_TYPE(Request) != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
+ NB_DEBUG (QUERY, ("Nwlink action failed, not address file\n"));
+ return STATUS_INVALID_HANDLE;
+ }
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ if ((AddressFile->Size != sizeof (ADDRESS_FILE)) ||
+ (AddressFile->Type != NB_ADDRESSFILE_SIGNATURE)) {
+
+ NB_DEBUG (QUERY, ("Nwlink action failed, bad address file\n"));
+ return STATUS_INVALID_HANDLE;
+ }
+
+ } else if (NwlinkAction->OptionType != NWLINK_OPTION_CONTROL) {
+
+ NB_DEBUG (QUERY, ("Nwlink action failed, option type %d\n", NwlinkAction->OptionType));
+ return STATUS_NOT_SUPPORTED;
+ }
+
+
+ //
+ // Handle the requests based on the action code. For these
+ // requests ActionHeader->ActionCode is 0, we use the
+ // Option field in the streams header instead.
+ //
+
+
+ Status = STATUS_SUCCESS;
+
+ switch (NwlinkAction->Option) {
+
+ case (I_MIPX | 351):
+
+ //
+ // A request for details on every binding.
+ //
+
+ if (DataLength < sizeof(NB_ACTION_GET_COUNTS)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.GetCounts = (PNB_ACTION_GET_COUNTS)(NwlinkAction->Data);
+
+ u.GetCounts->MaximumNicId = NbiDevice->MaximumNicId;
+
+ for (i = 0; i < 32 ; i++) {
+ u.GetCounts->NicIdCounts[i] = 0;
+ }
+
+ for (i = 0; i < CONNECTION_HASH_COUNT; i++) {
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Connection = Device->ConnectionHash[i].Connections;
+
+ while (Connection != NULL) {
+#if defined(_PNP_POWER)
+ if ((Connection->State == CONNECTION_STATE_ACTIVE) &&
+ (Connection->LocalTarget.NicHandle.NicId < 32)) {
+
+ ++u.GetCounts->NicIdCounts[Connection->LocalTarget.NicHandle.NicId];
+ }
+#else
+ if ((Connection->State == CONNECTION_STATE_ACTIVE) &&
+ (Connection->LocalTarget.NicId < 32)) {
+
+ ++u.GetCounts->NicIdCounts[Connection->LocalTarget.NicId];
+ }
+#endif _PNP_POWER
+ Connection = Connection->NextConnection;
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ break;
+
+ //
+ // The Option was not supported, so fail.
+ //
+
+ default:
+
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+
+
+ } // end of the long switch on NwlinkAction->Option
+
+
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ NB_DEBUG (QUERY, ("Nwlink action %lx failed, status %lx\n", NwlinkAction->Option, Status));
+ }
+#endif
+
+ return Status;
+
+} /* NbiTdiAction */
+
diff --git a/private/ntos/tdi/isn/nb/address.c b/private/ntos/tdi/isn/nb/address.c
new file mode 100644
index 000000000..2eb882b80
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/address.c
@@ -0,0 +1,2406 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ address.c
+
+Abstract:
+
+ This module contains code which implements the ADDRESS object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport address objects.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Map all generic accesses to the same one.
+//
+
+static GENERIC_MAPPING AddressGenericMapping =
+ { READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL };
+
+
+
+TDI_ADDRESS_NETBIOS UNALIGNED *
+NbiParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN BOOLEAN BroadcastAddressOk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, looking for an address
+ of type TDI_ADDRESS_TYPE_NETBIOS.
+
+Arguments:
+
+ Transport - The generic TDI address.
+
+ BroadcastAddressOk - TRUE if we should return the broadcast
+ address if found. If so, a value of (PVOID)-1 indicates
+ the broadcast address.
+
+Return Value:
+
+ A pointer to the Netbios address, or NULL if none is found,
+ or (PVOID)-1 if the broadcast address is found.
+
+--*/
+
+{
+ TA_ADDRESS UNALIGNED * addressName;
+ INT i;
+
+ addressName = &TransportAddress->Address[0];
+
+ //
+ // The name can be passed with multiple entries; we'll take and use only
+ // the Netbios one.
+ //
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++) {
+ if (addressName->AddressType == TDI_ADDRESS_TYPE_NETBIOS) {
+ if ((addressName->AddressLength == 0) &&
+ BroadcastAddressOk) {
+ return (PVOID)-1;
+ } else if (addressName->AddressLength == sizeof(TDI_ADDRESS_NETBIOS)) {
+ return ((TDI_ADDRESS_NETBIOS UNALIGNED *)(addressName->Address));
+ }
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+ return NULL;
+
+} /* NbiParseTdiAddress */
+
+
+BOOLEAN
+NbiValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, verifying that the
+ components of the address do not extend past the specified
+ length.
+
+Arguments:
+
+ TransportAddress - The generic TDI address.
+
+ TransportAddressLength - The specific length of TransportAddress.
+
+Return Value:
+
+ TRUE if the address is valid, FALSE otherwise.
+
+--*/
+
+{
+ PUCHAR AddressEnd = ((PUCHAR)TransportAddress) + TransportAddressLength;
+ TA_ADDRESS UNALIGNED * addressName;
+ INT i;
+
+ if (TransportAddressLength < sizeof(TransportAddress->TAAddressCount)) {
+ NbiPrint0 ("NbfValidateTdiAddress: runt address\n");
+ return FALSE;
+ }
+
+ addressName = &TransportAddress->Address[0];
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++) {
+ if (addressName->Address > AddressEnd) {
+ NbiPrint0 ("NbiValidateTdiAddress: address too short\n");
+ return FALSE;
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+
+ if ((PUCHAR)addressName > AddressEnd) {
+ NbiPrint0 ("NbiValidateTdiAddress: address too short\n");
+ return FALSE;
+ }
+ return TRUE;
+
+} /* NbiValidateTdiAddress */
+
+
+NTSTATUS
+NbiOpenAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens a file that points to an existing address object, or, if
+ the object doesn't exist, creates it (note that creation of the address
+ object includes registering the address, and may take many seconds to
+ complete, depending upon system configuration).
+
+ If the address already exists, and it has an ACL associated with it, the
+ ACL is checked for access rights before allowing creation of the address.
+
+Arguments:
+
+ Device - pointer to the device describing the Netbios transport.
+
+ Request - a pointer to the request used for the creation of the address.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ PFILE_FULL_EA_INFORMATION ea;
+ TRANSPORT_ADDRESS UNALIGNED *name;
+ TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress;
+ ULONG DesiredShareAccess;
+ CTELockHandle LockHandle;
+ PACCESS_STATE AccessState;
+ ACCESS_MASK GrantedAccess;
+ BOOLEAN AccessAllowed;
+ BOOLEAN found = FALSE;
+#ifdef ISN_NT
+ PIRP Irp = (PIRP)Request;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+#endif
+#if 0
+ TA_NETBIOS_ADDRESS FakeAddress;
+#endif
+
+
+ //
+ // The network name is in the EA, passed in the request.
+ //
+
+ ea = OPEN_REQUEST_EA_INFORMATION(Request);
+ if (ea == NULL) {
+ NbiPrint1("OpenAddress: REQUEST %lx has no EA\n", Request);
+ return STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+ //
+ // this may be a valid name; parse the name from the EA and use it if OK.
+ //
+
+ name = (PTRANSPORT_ADDRESS)&ea->EaName[ea->EaNameLength+1];
+#if 0
+ TdiBuildNetbiosAddress(
+ "ADAMBA67 ",
+ FALSE,
+ &FakeAddress);
+ name = (PTRANSPORT_ADDRESS)&FakeAddress;
+#endif
+
+ //
+ // The name can be passed with multiple entries; we'll take and use only
+ // the first one of type Netbios. This call returns (PVOID)-1 if the
+ // address is the broadcast address.
+ //
+
+ NetbiosAddress = NbiParseTdiAddress (name, TRUE);
+
+ if (NetbiosAddress == NULL) {
+ NbiPrint1("OpenAddress: REQUEST %lx has no Netbios Address\n", Request);
+ return STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+ //
+ // get an address file structure to represent this address.
+ //
+
+ AddressFile = NbiCreateAddressFile (Device);
+
+ if (AddressFile == (PADDRESS_FILE)NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // See if this address is already established. This call automatically
+ // increments the reference count on the address so that it won't disappear
+ // from underneath us after this call but before we have a chance to use it.
+ //
+ // To ensure that we don't create two address objects for the
+ // same address, we hold the device context addressResource until
+ // we have found the address or created a new one.
+ //
+
+ ExAcquireResourceExclusive (&Device->AddressResource, TRUE);
+
+#if defined(_PNP_POWER)
+
+ Address = NbiFindAddress (
+ Device,
+ ( NetbiosAddress == (PVOID)-1 ) ? (PVOID)-1 : NetbiosAddress->NetbiosName
+ );
+
+ if (Address == NULL) {
+
+#else
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Address = NbiLookupAddress (Device, NetbiosAddress);
+
+ if (Address == NULL) {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+#endif _PNP_POWER
+
+ //
+ // This address doesn't exist. Create it.
+ // This initializes the address with a ref
+ // of type ADDRESS_FILE, so if we fail here
+ // we need to remove that.
+ //
+
+ Address = NbiCreateAddress (
+ Device,
+ NetbiosAddress);
+
+ if (Address != (PADDRESS)NULL) {
+
+ //
+ // Set this now in case we have to deref.
+ //
+
+ AddressFile->AddressLock = &Address->Lock;
+
+#ifdef ISN_NT
+
+ //
+ // Initialize the shared access now. We use read access
+ // to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ IoSetShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &Address->u.ShareAccess);
+
+
+ //
+ // Assign the security descriptor (need to do this with
+ // the spinlock released because the descriptor is not
+ // mapped).
+ //
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ status = SeAssignSecurity(
+ NULL, // parent descriptor
+ AccessState->SecurityDescriptor,
+ &Address->SecurityDescriptor,
+ FALSE, // is directory
+ &AccessState->SubjectSecurityContext,
+ &AddressGenericMapping,
+ NonPagedPool);
+
+ if (!NT_SUCCESS(status)) {
+
+ //
+ // Error, return status.
+ //
+
+ IoRemoveShareAccess (IrpSp->FileObject, &Address->u.ShareAccess);
+ ExReleaseResource (&Device->AddressResource);
+ NbiDereferenceAddress (Address, AREF_ADDRESS_FILE);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ return status;
+
+ }
+
+#endif
+
+ ExReleaseResource (&Device->AddressResource);
+
+ //
+ // if the adapter isn't ready, we can't do any of this; get out
+ //
+#if defined(_PNP_POWER)
+ if (Device->State != DEVICE_STATE_OPEN) {
+#else
+ if (Device->State == DEVICE_STATE_STOPPING) {
+#endif _PNP_POWER
+ NbiDereferenceAddress (Address, AREF_ADDRESS_FILE);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ status = STATUS_DEVICE_NOT_READY;
+
+ } else {
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+#ifdef ISN_NT
+ AddressFile->FileObject = IrpSp->FileObject;
+#endif
+ AddressFile->Address = Address;
+
+ NB_INSERT_TAIL_LIST(
+ &Address->AddressFileDatabase,
+ &AddressFile->Linkage,
+ &Address->Lock);
+
+ if (NetbiosAddress == (PVOID)-1) {
+
+ AddressFile->OpenRequest = NULL;
+ AddressFile->State = ADDRESSFILE_STATE_OPEN;
+ status = STATUS_SUCCESS;
+
+ } else {
+
+ AddressFile->OpenRequest = Request;
+ AddressFile->State = ADDRESSFILE_STATE_OPENING;
+ status = STATUS_PENDING;
+
+ NbiStartRegistration (Address);
+ }
+
+ }
+
+ } else {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ //
+ // If the address could not be created, and is not in the
+ // process of being created, then we can't open up an address.
+ // Since we can't use the AddressLock to deref, we just destroy
+ // the address file.
+ //
+
+ NbiDestroyAddressFile (AddressFile);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ } else {
+
+#if !defined(_PNP_POWER)
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+#endif !_PNP_POWER
+ NB_DEBUG2 (ADDRESS, ("Add to address %lx\n", Address));
+
+ //
+ // Set this now in case we have to deref.
+ //
+
+ AddressFile->AddressLock = &Address->Lock;
+
+ //
+ // Make sure the types do not conflict.
+ //
+
+ if ((NetbiosAddress != (PVOID)-1) &&
+ (NetbiosAddress->NetbiosNameType != Address->NetbiosAddress.NetbiosNameType)) {
+
+ NB_DEBUG (ADDRESS, ("Address types conflict %lx\n", Address));
+ ExReleaseResource (&Device->AddressResource);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ status = STATUS_DUPLICATE_NAME;
+
+ } else {
+
+ //
+ // The address already exists. Check the ACL and see if we
+ // can access it. If so, simply use this address as our address.
+ //
+
+#ifdef ISN_NT
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ AccessAllowed = SeAccessCheck(
+ Address->SecurityDescriptor,
+ &AccessState->SubjectSecurityContext,
+ FALSE, // tokens locked
+ IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
+ (ACCESS_MASK)0, // previously granted
+ NULL, // privileges
+ &AddressGenericMapping,
+ Irp->RequestorMode,
+ &GrantedAccess,
+ &status);
+
+#else // ISN_NT
+
+ AccessAllowed = TRUE;
+
+#endif // ISN_NT
+
+ if (!AccessAllowed) {
+
+ NB_DEBUG (ADDRESS, ("Address access not allowed %lx\n", Address));
+ ExReleaseResource (&Device->AddressResource);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ } else {
+
+#ifdef ISN_NT
+
+ //
+ // Now check that we can obtain the desired share
+ // access. We use read access to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ status = IoCheckShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &Address->u.ShareAccess,
+ TRUE);
+
+#else // ISN_NT
+
+ status = STATUS_SUCCESS;
+
+#endif // ISN_NT
+
+ if (!NT_SUCCESS (status)) {
+
+ NB_DEBUG (ADDRESS, ("Address share access wrong %lx\n", Address));
+ ExReleaseResource (&Device->AddressResource);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ } else {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ //
+ // Insert the address file on the address
+ // list; we will pend this open if the address
+ // is still registering. If the address has
+ // already failed as duplicate, then we
+ // fail the open.
+ //
+
+ if (Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) {
+
+ NB_DEBUG (ADDRESS, ("Address duplicated %lx\n", Address));
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ status = STATUS_DUPLICATE_NAME;
+
+ } else {
+
+ InsertTailList (
+ &Address->AddressFileDatabase,
+ &AddressFile->Linkage);
+
+ //
+ // Start registration unless it is registered or
+ // it is the broadcast address.
+ //
+
+ if ((Address->State == ADDRESS_STATE_REGISTERING) &&
+ (NetbiosAddress != (PVOID)-1)) {
+
+ AddressFile->OpenRequest = Request;
+ AddressFile->State = ADDRESSFILE_STATE_OPENING;
+ status = STATUS_PENDING;
+
+ } else {
+
+ AddressFile->OpenRequest = NULL;
+ AddressFile->State = ADDRESSFILE_STATE_OPEN;
+ status = STATUS_SUCCESS;
+ }
+
+ AddressFile->Address = Address;
+#ifdef ISN_NT
+ AddressFile->FileObject = IrpSp->FileObject;
+#endif
+
+ NbiReferenceAddress (Address, AREF_ADDRESS_FILE);
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ }
+
+ }
+ }
+ }
+
+ //
+ // Remove the reference from NbiLookupAddress.
+ //
+
+ NbiDereferenceAddress (Address, AREF_LOOKUP);
+ }
+
+ return status;
+
+} /* NbiOpenAddress */
+
+
+VOID
+NbiStartRegistration(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the registration process for a netbios name
+ by sending out the first add name packet and starting the timer
+ so that NbiRegistrationTimeout is called after the correct timeout.
+
+Arguments:
+
+ Address - The address which is to be registered.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ NB_DEBUG2 (ADDRESS, ("StartRegistration of %lx\n", Address));
+
+ //
+ // First send out an add name packet.
+ //
+
+ NbiSendNameFrame(
+ Address,
+ (UCHAR)(Address->NameTypeFlag | NB_NAME_USED),
+ NB_CMD_ADD_NAME,
+ NULL,
+ NULL);
+
+ Address->RegistrationCount = 0;
+
+ //
+ // Now start the timer.
+ //
+
+ NbiReferenceAddress (Address, AREF_TIMER);
+
+ CTEInitTimer (&Address->RegistrationTimer);
+ CTEStartTimer(
+ &Address->RegistrationTimer,
+ Address->Device->BroadcastTimeout,
+ NbiRegistrationTimeout,
+ (PVOID)Address);
+
+} /* NbiStartRegistration */
+
+
+VOID
+NbiRegistrationTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the address registration
+ timer expires. It sends another add name if needed, or
+ checks the result if the correct number have been sent.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the address pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADDRESS Address = (PADDRESS)Context;
+ CTELockHandle LockHandle;
+ PADDRESS_FILE AddressFile, ReferencedAddressFile;
+ PLIST_ENTRY p;
+
+ ++Address->RegistrationCount;
+
+ if ((Address->RegistrationCount < Address->Device->BroadcastCount) &&
+ ((Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) == 0)) {
+
+ NB_DEBUG2 (ADDRESS, ("Send add name %d for %lx\n", Address->RegistrationCount+1, Address));
+
+ NbiSendNameFrame(
+ Address,
+ (UCHAR)(Address->NameTypeFlag | NB_NAME_USED),
+ NB_CMD_ADD_NAME,
+ NULL,
+ NULL);
+
+ CTEStartTimer(
+ &Address->RegistrationTimer,
+ Address->Device->BroadcastTimeout,
+ NbiRegistrationTimeout,
+ (PVOID)Address);
+
+ } else {
+
+ //
+ // The correct number of frames have been sent, see what
+ // happened.
+ //
+
+ NB_DEBUG2 (ADDRESS, ("Done with add names for %lx\n", Address));
+
+ ReferencedAddressFile = NULL;
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if ((Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) == 0) {
+ Address->State = ADDRESS_STATE_OPEN;
+ } else {
+ Address->State = ADDRESS_STATE_STOPPING;
+ }
+
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+
+ AddressFile = CONTAINING_RECORD (p, ADDRESS_FILE, Linkage);
+ CTEAssert (AddressFile->State == ADDRESSFILE_STATE_OPENING);
+ CTEAssert (AddressFile->OpenRequest != NULL);
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_TIMEOUT);
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_TIMEOUT);
+ }
+
+ //
+ // Now see what to do with this address file.
+ //
+
+ REQUEST_INFORMATION(AddressFile->OpenRequest) = 0;
+
+ if (Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) {
+
+ NB_DEBUG (ADDRESS, ("Open of address file %lx failed, duplicate\n", AddressFile));
+ REQUEST_STATUS(AddressFile->OpenRequest) = STATUS_DUPLICATE_NAME;
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ } else {
+
+ NB_DEBUG2 (ADDRESS, ("Complete open of address file %lx\n", AddressFile));
+ REQUEST_STATUS(AddressFile->OpenRequest) = STATUS_SUCCESS;
+ AddressFile->State = ADDRESSFILE_STATE_OPEN;
+
+ }
+
+ NbiCompleteRequest (AddressFile->OpenRequest);
+ NbiFreeRequest (Address->Device, AddressFile->OpenRequest);
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ ReferencedAddressFile = AddressFile;
+
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_TIMEOUT);
+ }
+
+ NbiDereferenceAddress (Address, AREF_TIMER);
+
+ }
+
+} /* NbiRegistrationTimeout */
+
+
+VOID
+NbiProcessFindName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_FIND_NAME frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADDRESS Address;
+ NB_CONNECTIONLESS UNALIGNED * NbConnectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
+ PDEVICE Device = NbiDevice;
+
+ if (PacketSize != sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME)) {
+ return;
+ }
+
+ //
+ // Quick check for any names starting with this character.
+ //
+
+ if (Device->AddressCounts[NbConnectionless->NameFrame.Name[0]] == 0) {
+ return;
+ }
+
+ //
+ // Always respond to broadcast requests.
+ //
+#if defined(_PNP_POWER)
+ if (RtlEqualMemory (NetbiosBroadcastName, NbConnectionless->NameFrame.Name, 16)) {
+
+ NbiSendNameFrame(
+ NULL,
+ NB_NAME_DUPLICATED, // this is what Novell machines use
+ NB_CMD_NAME_RECOGNIZED,
+ RemoteAddress,
+ NbConnectionless);
+
+ } else if (Address = NbiFindAddress(Device, (PUCHAR)NbConnectionless->NameFrame.Name)) {
+
+ NbiSendNameFrame(
+ Address,
+ (UCHAR)(Address->NameTypeFlag | NB_NAME_USED | NB_NAME_REGISTERED),
+ NB_CMD_NAME_RECOGNIZED,
+ RemoteAddress,
+ NbConnectionless);
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ } else if ( NbiFindAdapterAddress( NbConnectionless->NameFrame.Name, LOCK_NOT_ACQUIRED ) ) {
+
+ NbiSendNameFrame(
+ NULL,
+ (UCHAR)(NB_NAME_UNIQUE | NB_NAME_USED | NB_NAME_REGISTERED),
+ NB_CMD_NAME_RECOGNIZED,
+ RemoteAddress,
+ NbConnectionless);
+ }
+#else
+ if (RtlEqualMemory (NetbiosBroadcastName, NbConnectionless->NameFrame.Name, 16)) {
+
+ NbiSendNameFrame(
+ NULL,
+ NB_NAME_DUPLICATED, // this is what Novell machines use
+ NB_CMD_NAME_RECOGNIZED,
+ RemoteAddress,
+ (PTDI_ADDRESS_IPX)(NbConnectionless->IpxHeader.SourceNetwork));
+
+ } else if (Address = NbiFindAddress(Device, (PUCHAR)NbConnectionless->NameFrame.Name)) {
+
+ NbiSendNameFrame(
+ Address,
+ (UCHAR)(Address->NameTypeFlag | NB_NAME_USED | NB_NAME_REGISTERED),
+ NB_CMD_NAME_RECOGNIZED,
+ RemoteAddress,
+ (PTDI_ADDRESS_IPX)(NbConnectionless->IpxHeader.SourceNetwork));
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ }
+#endif _PNP_POWER
+} /* NbiProcessFindName */
+
+
+VOID
+NbiProcessAddName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_ADD_NAME frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADDRESS Address;
+ NB_CONNECTIONLESS UNALIGNED * NbConnectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
+ PDEVICE Device = NbiDevice;
+ CTELockHandle LockHandle;
+ BOOLEAN LocalFrame;
+
+
+ if (PacketSize != sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME)) {
+ return;
+ }
+
+ //
+ // Ignore any frame that came from us, except for the purpose
+ // of updating the cache.
+ //
+
+ if ((Device->Bind.QueryHandler)(
+ IPX_QUERY_IS_ADDRESS_LOCAL,
+#if defined(_PNP_POWER)
+ &RemoteAddress->NicHandle,
+#else
+ RemoteAddress->NicId,
+#endif _PNP_POWER
+ NbConnectionless->IpxHeader.SourceNetwork,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL) == STATUS_SUCCESS) {
+
+ LocalFrame = TRUE;
+
+ } else {
+
+ LocalFrame = FALSE;
+
+ }
+
+ if (!LocalFrame) {
+
+ if ((Device->AddressCounts[NbConnectionless->NameFrame.Name[0]] != 0) &&
+ (Address = NbiFindAddress(Device, (PUCHAR)NbConnectionless->NameFrame.Name))) {
+
+ if (NB_NODE_BROADCAST(NbConnectionless->IpxHeader.DestinationNode)) {
+
+ //
+ // If this frame is an add name (identified because it is a
+ // broadcast frame) then respond if we have it registered
+ // unique, or we have it group and someone is trying to add
+ // it unique.
+ //
+
+ if ((Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_UNIQUE) ||
+ ((Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_GROUP) &&
+ ((NbConnectionless->NameFrame.NameTypeFlag & NB_NAME_GROUP) == 0))) {
+
+ //
+ // According to GeorgeJ's doc, on a name in use we just
+ // echo back the name type flags from the request.
+ //
+
+ NbiSendNameFrame(
+ Address,
+ NbConnectionless->NameFrame.NameTypeFlag,
+ NB_CMD_NAME_IN_USE,
+ RemoteAddress,
+#if defined(_PNP_POWER)
+ NbConnectionless);
+#else
+ (PTDI_ADDRESS_IPX)(NbConnectionless->IpxHeader.SourceNetwork));
+#endif _PNP_POWER
+ }
+
+ } else if ((*(UNALIGNED ULONG *)NbConnectionless->IpxHeader.DestinationNetwork ==
+ *(UNALIGNED ULONG *)Device->Bind.Network) &&
+ NB_NODE_EQUAL(NbConnectionless->IpxHeader.DestinationNode, Device->Bind.Node)) {
+
+ //
+ // If this is an add name response (which will be sent
+ // directly to us) then we need to mark the address
+ // as such.
+ //
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+ Address->Flags |= ADDRESS_FLAGS_DUPLICATE_NAME;
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ }
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ }
+
+ }
+
+
+ //
+ // Pass this frame over to the netbios cache management
+ // routines to check if they need to update their cache.
+ //
+
+ CacheUpdateFromAddName (RemoteAddress, NbConnectionless, LocalFrame);
+
+} /* NbiProcessAddName */
+
+
+PADDRESS
+NbiCreateAddress(
+ IN PDEVICE Device,
+ IN TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a transport address and associates it with
+ the specified transport device context. The reference count in the
+ address is automatically set to 1, and the reference count of the
+ device context is incremented.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ NetbiosAddress - The name to assign to this address, or -1 if it
+ is the broadcast address.
+
+Return Value:
+
+ The newly created address, or NULL if none can be allocated.
+
+--*/
+
+{
+ PADDRESS Address;
+
+ Address = (PADDRESS)NbiAllocateMemory (sizeof(ADDRESS), MEMORY_ADDRESS, "Address");
+ if (Address == NULL) {
+ NB_DEBUG (ADDRESS, ("Create address %.16s failed\n",
+ (NetbiosAddress == (PVOID)-1) ? "<broadcast>" : NetbiosAddress->NetbiosName));
+ return NULL;
+ }
+
+ NB_DEBUG2 (ADDRESS, ("Create address %lx (%.16s)\n", Address,
+ (NetbiosAddress == (PVOID)-1) ? "<broadcast>" : NetbiosAddress->NetbiosName));
+ RtlZeroMemory (Address, sizeof(ADDRESS));
+
+ Address->Type = NB_ADDRESS_SIGNATURE;
+ Address->Size = sizeof (ADDRESS);
+ Address->State = ADDRESS_STATE_REGISTERING;
+ Address->Flags = 0;
+
+ Address->Device = Device;
+ Address->DeviceLock = &Device->Lock;
+ CTEInitLock (&Address->Lock.Lock);
+
+ InitializeListHead (&Address->AddressFileDatabase);
+
+ Address->ReferenceCount = 1;
+#if DBG
+ Address->RefTypes[AREF_ADDRESS_FILE] = 1;
+#endif
+
+ if (NetbiosAddress == (PVOID)-1) {
+ Address->NetbiosAddress.Broadcast = TRUE;
+ } else {
+ Address->NetbiosAddress.Broadcast = FALSE;
+ Address->NetbiosAddress.NetbiosNameType = NetbiosAddress->NetbiosNameType;
+ RtlCopyMemory (Address->NetbiosAddress.NetbiosName, NetbiosAddress->NetbiosName, 16);
+ ++Device->AddressCounts[NetbiosAddress->NetbiosName[0]];
+ }
+
+ if (Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_UNIQUE) {
+ Address->NameTypeFlag = NB_NAME_UNIQUE;
+ } else {
+ Address->NameTypeFlag = NB_NAME_GROUP;
+ }
+
+ //
+ // Now link this address into the specified device context's
+ // address database. To do this, we need to acquire the spin lock
+ // on the device context.
+ //
+
+ InsertTailList (&Device->AddressDatabase, &Address->Linkage);
+ ++Device->AddressCount;
+
+ NbiReferenceDevice (Device, DREF_ADDRESS);
+
+ return Address;
+
+} /* NbiCreateAddress */
+
+
+NTSTATUS
+NbiVerifyAddressFile (
+#if defined(_PNP_POWER)
+ IN PADDRESS_FILE AddressFile,
+ IN BOOLEAN ConflictIsOk
+#else
+ IN PADDRESS_FILE AddressFile
+#endif _PNP_POWER
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to verify that the pointer given us in a file
+ object is in fact a valid address file object. We also verify that the
+ address object pointed to by it is a valid address object, and reference
+ it to keep it from disappearing while we use it.
+
+Arguments:
+
+ AddressFile - potential pointer to a ADDRESS_FILE object
+
+ ConflictIsOk - TRUE if we should succeed the verify even if the
+ corresponding address is in CONFLICT. ( For Close and
+ cleanup we return STATUS_SUCCESS even if we are in conflict
+ so that the addressfile can be destroyed)
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_ADDRESS otherwise
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ NTSTATUS status = STATUS_SUCCESS;
+ PADDRESS Address;
+ BOOLEAN LockHeld = FALSE;
+
+ //
+ // try to verify the address file signature. If the signature is valid,
+ // verify the address pointed to by it and get the address spinlock.
+ // check the address's state, and increment the reference count if it's
+ // ok to use it. Note that the only time we return an error for state is
+ // if the address is closing.
+ //
+
+ try {
+
+ if ((AddressFile->Size == sizeof (ADDRESS_FILE)) &&
+ (AddressFile->Type == NB_ADDRESSFILE_SIGNATURE) ) {
+// (AddressFile->State != ADDRESSFILE_STATE_CLOSING) ) {
+
+ Address = AddressFile->Address;
+
+ if ((Address->Size == sizeof (ADDRESS)) &&
+ (Address->Type == NB_ADDRESS_SIGNATURE) ) {
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ LockHeld = TRUE;
+
+#if defined(_PNP_POWER)
+ if (Address->State != ADDRESS_STATE_STOPPING &&
+ ( ConflictIsOk || ( !(Address->Flags & ADDRESS_FLAGS_CONFLICT) )) ) {
+#else
+ if (Address->State != ADDRESS_STATE_STOPPING) {
+#endif _PNP_POWER
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_VERIFY);
+
+ } else {
+
+ NbiPrint1("NbiVerifyAddressFile: A %lx closing\n", Address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ } else {
+
+ NbiPrint1("NbiVerifyAddressFile: A %lx bad signature\n", Address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } else {
+
+ NbiPrint1("NbiVerifyAddressFile: AF %lx bad signature\n", AddressFile);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ NbiPrint1("NbiVerifyAddressFile: AF %lx exception\n", Address);
+ if (LockHeld) {
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ }
+ return GetExceptionCode();
+ }
+
+ return status;
+
+} /* NbiVerifyAddressFile */
+
+
+VOID
+NbiDestroyAddress(
+ IN PVOID Parameter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a transport address and removes all references
+ made by it to other objects in the transport. The address structure
+ is returned to nonpaged system pool. It is assumed
+ that the caller has already removed all addressfile structures associated
+ with this address.
+
+ It is called from a worker thread queue by NbiDerefAddress when
+ the reference count goes to 0.
+
+ This thread is only queued by NbiDerefAddress. The reason for
+ this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ Address - Pointer to a transport address structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PADDRESS Address = (PADDRESS)Parameter;
+ PDEVICE Device = Address->Device;
+ CTELockHandle LockHandle;
+
+ NB_DEBUG2 (ADDRESS, ("Destroy address %lx <%.16s>\n", Address,
+ Address->NetbiosAddress.Broadcast ? "<broadcast>" : Address->NetbiosAddress.NetbiosName));
+
+ SeDeassignSecurity (&Address->SecurityDescriptor);
+
+ //
+ // Delink this address from its associated device context's address
+ // database. To do this we must spin lock on the device context object,
+ // not on the address.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (!Address->NetbiosAddress.Broadcast) {
+ --Device->AddressCounts[Address->NetbiosAddress.NetbiosName[0]];
+ }
+ --Device->AddressCount;
+ RemoveEntryList (&Address->Linkage);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ NbiFreeMemory (Address, sizeof(ADDRESS), MEMORY_ADDRESS, "Address");
+
+ NbiDereferenceDevice (Device, DREF_ADDRESS);
+
+} /* NbiDestroyAddress */
+
+
+#if DBG
+VOID
+NbiRefAddress(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (Address->ReferenceCount > 0); // not perfect, but...
+
+ InterlockedIncrement( &Address->ReferenceCount );
+} /* NbiRefAddress */
+
+
+VOID
+NbiRefAddressLock(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address
+ when the device lock is already held.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (Address->ReferenceCount > 0); // not perfect, but...
+
+ InterlockedIncrement( &Address->ReferenceCount );
+
+} /* NbiRefAddressLock */
+#endif
+
+
+VOID
+NbiDerefAddress(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport address by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ NbiDestroyAddress to remove it from the system.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG newvalue;
+
+ newvalue = InterlockedDecrement( &Address->ReferenceCount );
+ //
+ // If we have deleted all references to this address, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ CTEAssert (newvalue >= 0);
+
+ if (newvalue == 0) {
+
+#if ISN_NT
+ ExInitializeWorkItem(
+ &Address->u.DestroyAddressQueueItem,
+ NbiDestroyAddress,
+ (PVOID)Address);
+ ExQueueWorkItem(&Address->u.DestroyAddressQueueItem, DelayedWorkQueue);
+#else
+ NbiDestroyAddress(Address);
+#endif
+
+ }
+
+} /* NbiDerefAddress */
+
+
+PADDRESS_FILE
+NbiCreateAddressFile(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates an address file from the pool of ther
+ specified device context. The reference count in the
+ address is automatically set to 1.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+Return Value:
+
+ The allocate address file or NULL.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PADDRESS_FILE AddressFile;
+ UINT i;
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ AddressFile = (PADDRESS_FILE)NbiAllocateMemory (sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile");
+ if (AddressFile == NULL) {
+ NB_DEBUG (ADDRESS, ("Create address file failed\n"));
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return NULL;
+ }
+
+ NB_DEBUG2 (ADDRESS, ("Create address file %lx\n", AddressFile));
+
+ RtlZeroMemory (AddressFile, sizeof(ADDRESS_FILE));
+
+ AddressFile->Type = NB_ADDRESSFILE_SIGNATURE;
+ AddressFile->Size = sizeof (ADDRESS_FILE);
+
+ InitializeListHead (&AddressFile->ReceiveDatagramQueue);
+ InitializeListHead (&AddressFile->ConnectionDatabase);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ AddressFile->Address = NULL;
+#ifdef ISN_NT
+ AddressFile->FileObject = NULL;
+#endif
+ AddressFile->Device = Device;
+ AddressFile->State = ADDRESSFILE_STATE_OPENING;
+ AddressFile->ReferenceCount = 1;
+#if DBG
+ AddressFile->RefTypes[AFREF_CREATE] = 1;
+#endif
+ AddressFile->CloseRequest = (PREQUEST)NULL;
+
+ //
+ // Initialize the request handlers.
+ //
+
+ for (i = 0; i < 6; i++) {
+ AddressFile->RegisteredHandler[i] = FALSE;
+ AddressFile->HandlerContexts[i] = NULL;
+ AddressFile->Handlers[i] = TdiDefaultHandlers[i];
+ }
+
+ CTEAssert (AddressFile->ConnectionHandler == TdiDefaultConnectHandler);
+ CTEAssert (AddressFile->DisconnectHandler == TdiDefaultDisconnectHandler);
+ CTEAssert (AddressFile->ErrorHandler == TdiDefaultErrorHandler);
+ CTEAssert (AddressFile->ReceiveHandler == TdiDefaultReceiveHandler);
+ CTEAssert (AddressFile->ReceiveDatagramHandler == TdiDefaultRcvDatagramHandler);
+ CTEAssert (AddressFile->ExpeditedDataHandler == TdiDefaultRcvExpeditedHandler);
+
+ return AddressFile;
+
+} /* NbiCreateAddressFile */
+
+
+NTSTATUS
+NbiDestroyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys an address file and removes all references
+ made by it to other objects in the transport.
+
+ This routine is only called by NbiDereferenceAddressFile. The reason
+ for this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address file object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ AddressFile Pointer to a transport address file structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ CTELockHandle LockHandle, LockHandle1;
+ PADDRESS Address;
+ PDEVICE Device;
+ PREQUEST CloseRequest;
+ BOOLEAN StopAddress;
+
+ NB_DEBUG2 (ADDRESS, ("Destroy address file %lx\n", AddressFile));
+
+ Address = AddressFile->Address;
+ Device = AddressFile->Device;
+
+ if (Address) {
+
+ //
+ // This addressfile was associated with an address.
+ //
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ //
+ // remove this addressfile from the address list and disassociate it from
+ // the file handle.
+ //
+
+ RemoveEntryList (&AddressFile->Linkage);
+ InitializeListHead (&AddressFile->Linkage);
+
+ if (Address->AddressFileDatabase.Flink == &Address->AddressFileDatabase) {
+
+ //
+ // This is the last open of this address, it will close
+ // due to normal dereferencing but we have to set the
+ // CLOSING flag too to stop further references.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle1);
+ Address->State = ADDRESS_STATE_STOPPING;
+ NB_FREE_LOCK (&Device->Lock, LockHandle1);
+
+ StopAddress = TRUE;
+
+ } else {
+
+ StopAddress = FALSE;
+ }
+
+ AddressFile->Address = NULL;
+
+#ifdef ISN_NT
+ AddressFile->FileObject->FsContext = NULL;
+ AddressFile->FileObject->FsContext2 = NULL;
+#endif
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ //
+ // We will already have been removed from the ShareAccess
+ // of the owning address.
+ //
+
+ if (StopAddress && (!Address->NetbiosAddress.Broadcast)) {
+
+ NbiSendNameFrame(
+ Address,
+ (UCHAR)(Address->NameTypeFlag |
+ NB_NAME_USED | NB_NAME_REGISTERED | NB_NAME_DEREGISTERED),
+ NB_CMD_DELETE_NAME,
+ NULL,
+ NULL);
+ }
+
+ //
+ // Now dereference the owning address.
+ //
+
+ NbiDereferenceAddress (Address, AREF_ADDRESS_FILE);
+
+ }
+
+ //
+ // Save this for later completion.
+ //
+
+ CloseRequest = AddressFile->CloseRequest;
+
+ //
+ // return the addressFile to the pool of address files
+ //
+
+ NbiFreeMemory (AddressFile, sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile");
+
+ if (CloseRequest != (PREQUEST)NULL) {
+ REQUEST_INFORMATION(CloseRequest) = 0;
+ REQUEST_STATUS(CloseRequest) = STATUS_SUCCESS;
+ NbiCompleteRequest (CloseRequest);
+ NbiFreeRequest (Device, CloseRequest);
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbiDestroyAddressFile */
+
+
+#if DBG
+VOID
+NbiRefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+
+ InterlockedIncrement( &AddressFile->ReferenceCount );
+} /* NbiRefAddressFile */
+
+
+VOID
+NbiRefAddressFileLock(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+ IT IS CALLED WITH THE ADDRESS LOCK HELD.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+
+ InterlockedIncrement( &AddressFile->ReferenceCount );
+
+} /* NbiRefAddressFileLock */
+
+#endif
+
+
+VOID
+NbiDerefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences an address file by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ NbiDestroyAddressFile to remove it from the system.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG newvalue;
+
+ newvalue = InterlockedDecrement( &AddressFile->ReferenceCount );
+
+ //
+ // If we have deleted all references to this address file, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ CTEAssert (newvalue >= 0);
+
+ if (newvalue == 0) {
+ NbiDestroyAddressFile (AddressFile);
+ }
+
+} /* NbiDerefAddressFile */
+
+#if !defined(_PNP_POWER)
+
+PADDRESS
+NbiLookupAddress(
+ IN PDEVICE Device,
+ IN TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the transport addresses defined for the given
+ device context and compares them with the specified NETWORK
+ NAME values. If an exact match is found, then a pointer to the
+ ADDRESS object is returned, and as a side effect, the reference
+ count to the address object is incremented. If the address is not
+ found, then NULL is returned.
+
+ NOTE: This routine must be called with the Device
+ spinlock held.
+
+Arguments:
+
+ Device - Pointer to the device object and its extension.
+
+ NetbiosAddress - The name to look up, or -1 if the broadcast
+ address is being searched for.
+
+Return Value:
+
+ Pointer to the ADDRESS object found, or NULL if not found.
+
+--*/
+
+{
+ PADDRESS Address;
+ PLIST_ENTRY p;
+
+ p = Device->AddressDatabase.Flink;
+
+ for (p = Device->AddressDatabase.Flink;
+ p != &Device->AddressDatabase;
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ if (Address->State == ADDRESS_STATE_STOPPING) {
+ continue;
+ }
+
+ if (Address->NetbiosAddress.Broadcast) {
+
+ //
+ // This address is the broadcast one, so no match
+ // unless we are looking for that.
+ //
+
+ if (NetbiosAddress != (PVOID)-1) {
+ continue;
+ }
+
+ } else {
+
+ //
+ // This address is not the broadcast, so if we are
+ // looking for that then no match, else compare the
+ // two names.
+ //
+
+ if (NetbiosAddress == (PVOID)-1) {
+ continue;
+ }
+
+ if (!RtlEqualMemory(
+ Address->NetbiosAddress.NetbiosName,
+ NetbiosAddress->NetbiosName,
+ 16)) {
+ continue;
+ }
+ }
+
+ //
+ // We found the match. Bump the reference count on the address, and
+ // return a pointer to the address object for the caller to use.
+ //
+
+ NbiReferenceAddressLock (Address, AREF_LOOKUP);
+ return Address;
+
+ } /* for */
+
+ //
+ // The specified address was not found.
+ //
+
+ return NULL;
+
+} /* NbiLookupAddress */
+#endif !_PNP_POWER
+
+
+PADDRESS
+NbiFindAddress(
+ IN PDEVICE Device,
+ IN PUCHAR NetbiosName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the transport addresses defined for the given
+ device context and compares them with the specified NetbiosName
+ values. If a match is found, the address is referenced and the
+ pointer is returned.
+
+ We ignore any addresses which are either STOPPING or are under
+ CONFLICT state.
+
+ A name in CONFLICT is dead for all practical purposes
+ except Close. This routine is called by various name service,
+ datagram and session sevice routines. We hide any names in CONFLICT
+ from these routines.
+
+ This routine is also called by NbiTdiOpenAddress().
+ A name could have been marked in CONFLICT ages ago(but is not closed
+ yet). We must allow another open of the same name as that might
+ succeed now.
+
+Arguments:
+
+ Device - Pointer to the device object and its extension.
+
+ NetbiosName - The name to look up, or -1 for the broadcast name.
+
+Return Value:
+
+ Pointer to the ADDRESS object found, or NULL if not found.
+
+--*/
+
+{
+ PADDRESS Address;
+ PLIST_ENTRY p;
+ CTELockHandle LockHandle;
+
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ p = Device->AddressDatabase.Flink;
+
+ for (p = Device->AddressDatabase.Flink;
+ p != &Device->AddressDatabase;
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+#if defined(_PNP_POWER)
+ if ( ( Address->State == ADDRESS_STATE_STOPPING ) ||
+ ( Address->Flags & ADDRESS_FLAGS_CONFLICT ) ) {
+#else
+ if (Address->State == ADDRESS_STATE_STOPPING) {
+#endif _PNP_POWER
+ continue;
+ }
+
+ if (Address->NetbiosAddress.Broadcast) {
+
+ //
+ // This address is the broadcast one, so no match
+ // unless we are looking for that.
+ //
+
+ if (NetbiosName != (PVOID)-1) {
+ continue;
+ }
+
+ } else {
+
+ //
+ // This address is not the broadcast, so if we are
+ // looking for that then no match, else compare the
+ // two names.
+ //
+
+ if ((NetbiosName == (PVOID)-1) ||
+ (!RtlEqualMemory(
+ Address->NetbiosAddress.NetbiosName,
+ NetbiosName,
+ 16))) {
+ continue;
+ }
+ }
+
+
+ //
+ // We found the match. Bump the reference count on the address, and
+ // return a pointer to the address object for the caller to use.
+ //
+
+ NbiReferenceAddressLock (Address, AREF_FIND);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return Address;
+
+ } /* for */
+
+ //
+ // The specified address was not found.
+ //
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return NULL;
+
+} /* NbiFindAddress */
+
+
+NTSTATUS
+NbiStopAddressFile(
+ IN PADDRESS_FILE AddressFile,
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to terminate all activity on an AddressFile and
+ destroy the object. We remove every connection and datagram associated
+ with this addressfile from the address database and terminate their
+ activity. Then, if there are no other outstanding addressfiles open on
+ this address, the address will go away.
+
+Arguments:
+
+ AddressFile - pointer to the addressFile to be stopped
+
+ Address - the owning address for this addressFile (we do not depend upon
+ the pointer in the addressFile because we want this routine to be safe)
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the request
+ is not for a real address.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PCONNECTION Connection;
+ PREQUEST Request;
+ PDEVICE Device = Address->Device;
+ CTELockHandle LockHandle1, LockHandle2;
+ LIST_ENTRY SendDatagramList;
+ PNB_SEND_RESERVED Reserved;
+ PREQUEST DatagramRequest;
+ NB_DEFINE_LOCK_HANDLE (LockHandle3)
+ CTELockHandle CancelLH;
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+ LIST_ENTRY DatagramQ;
+
+
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle1);
+
+ if (AddressFile->State == ADDRESSFILE_STATE_CLOSING) {
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+ return STATUS_SUCCESS;
+ }
+
+
+ //
+ // This prevents anybody else from being put on the
+ // ConnectionDatabase.
+ //
+
+ AddressFile->State = ADDRESSFILE_STATE_CLOSING;
+
+ while (!IsListEmpty (&AddressFile->ConnectionDatabase)) {
+
+ p = RemoveHeadList (&AddressFile->ConnectionDatabase);
+ Connection = CONTAINING_RECORD (p, CONNECTION, AddressFileLinkage);
+
+ CTEAssert (Connection->AddressFile == AddressFile);
+ Connection->AddressFileLinked = FALSE;
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if (Connection->ReferenceCount == 0) {
+
+ //
+ // The refcount is already 0, so we can just
+ // NULL out this field to complete the disassociate.
+ //
+
+ Connection->AddressFile = NULL;
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
+
+ } else {
+
+ //
+ // Mark this so we know to disassociate when the
+ // count goes to 0, but that there is no specific
+ // request pending on it. We also stop the connection
+ // to shut it down.
+ //
+
+ Connection->DisassociatePending = (PVOID)-1;
+ NbiReferenceConnectionLock (Connection, CREF_DISASSOC);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+
+ NB_BEGIN_SYNC (&SyncContext);
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle3);
+
+ //
+ // This call frees the connection lock.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_INVALID_ADDRESS
+ NB_LOCK_HANDLE_ARG (LockHandle3));
+
+ NB_END_SYNC (&SyncContext);
+
+ NbiDereferenceConnection (Connection, CREF_DISASSOC);
+
+ }
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle1);
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+
+
+ //
+ // Abort all pending send datagrams.
+ //
+ // BUGBUG: Also make them cancellable.
+ //
+
+ InitializeListHead (&SendDatagramList);
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ p = Device->WaitingDatagrams.Flink;
+
+ while (p != &Device->WaitingDatagrams) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ p = p->Flink;
+
+ if (Reserved->u.SR_DG.AddressFile == AddressFile) {
+
+ RemoveEntryList (&Reserved->WaitLinkage);
+ InsertTailList (&SendDatagramList, &Reserved->WaitLinkage);
+
+ }
+
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ for (p = SendDatagramList.Flink; p != &SendDatagramList; ) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+ p = p->Flink;
+
+ DatagramRequest = Reserved->u.SR_DG.DatagramRequest;
+
+ NB_DEBUG2 (DATAGRAM, ("Aborting datagram %lx on %lx\n", DatagramRequest, AddressFile));
+
+ REQUEST_STATUS(DatagramRequest) = STATUS_SUCCESS;
+
+ NbiCompleteRequest(DatagramRequest);
+ NbiFreeRequest (Device, DatagramRequest);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_SEND_DGRAM);
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ }
+
+
+ //
+ // Abort all pending receive datagrams.
+ //
+
+ InitializeListHead( &DatagramQ );
+
+ NB_GET_CANCEL_LOCK(&CancelLH);
+ NB_GET_LOCK (&Address->Lock, &LockHandle1);
+
+ while (!IsListEmpty(&AddressFile->ReceiveDatagramQueue)) {
+
+ p = RemoveHeadList (&AddressFile->ReceiveDatagramQueue);
+ Request = LIST_ENTRY_TO_REQUEST (p);
+
+ // Insert it on a private Q, so it can be completed later.
+ InsertTailList( &DatagramQ, p);
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_NETWORK_NAME_DELETED;
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+
+
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
+
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK(CancelLH);
+
+ for( p = DatagramQ.Flink; p != &DatagramQ; ) {
+ Request = LIST_ENTRY_TO_REQUEST ( p );
+
+ p = p->Flink;
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+
+ }
+
+
+ return STATUS_SUCCESS;
+
+} /* NbiStopAddressFile */
+
+
+NTSTATUS
+NbiCloseAddressFile(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to close the addressfile pointed to by a file
+ object. If there is any activity to be run down, we will run it down
+ before we terminate the addressfile. We remove every connection and
+ datagram associated with this addressfile from the address database
+ and terminate their activity. Then, if there are no other outstanding
+ addressfiles open on this address, the address will go away.
+
+Arguments:
+
+ Request - the close request.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the
+ request does not point to a real address.
+
+--*/
+
+{
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+ AddressFile->CloseRequest = Request;
+
+ //
+ // We assume that addressFile has already been verified
+ // at this point.
+ //
+
+ Address = AddressFile->Address;
+ CTEAssert (Address);
+
+ //
+ // Remove us from the access info for this address.
+ //
+
+ ExAcquireResourceExclusive (&Device->AddressResource, TRUE);
+#ifdef ISN_NT
+ IoRemoveShareAccess (AddressFile->FileObject, &Address->u.ShareAccess);
+#endif
+ ExReleaseResource (&Device->AddressResource);
+
+ NbiStopAddressFile (AddressFile, Address);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ return STATUS_PENDING;
+
+} /* NbiCloseAddressFile */
+
+#if defined(_PNP_POWER)
+
+
+PADAPTER_ADDRESS
+NbiCreateAdapterAddress(
+ IN PCHAR AdapterMacAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates an adapter address sttuctures which stores
+ the netbios name of an adapter. the netbios name has 12 0's
+ followed by the mac address of the adapter.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ AdapterMacAddress - pointer to the adapter mac address given to us
+ by IPX.
+
+Return Value:
+
+ The newly created address, or NULL if none can be allocated.
+ THIS ROUTINE MUST BE CALLED WITH THE DEVICE LOCK HELD.
+
+--*/
+
+{
+ PADAPTER_ADDRESS AdapterAddress;
+ CTELockHandle LockHandle;
+ PDEVICE Device = NbiDevice;
+
+ AdapterAddress = (PADAPTER_ADDRESS)NbiAllocateMemory (sizeof(ADAPTER_ADDRESS), MEMORY_ADAPTER_ADDRESS, "Adapter Address");
+ if (AdapterAddress == NULL) {
+ NB_DEBUG (ADDRESS, ("Create Adapter Address %<2.2x><2.2x><2.2x><2.2x><2.2x><2.2x> failed\n",
+ AdapterMacAddress[0],
+ AdapterMacAddress[1],
+ AdapterMacAddress[2],
+ AdapterMacAddress[3],
+ AdapterMacAddress[4],
+ AdapterMacAddress[5]
+ ));
+ return NULL;
+ }
+
+ AdapterAddress->Type = NB_ADAPTER_ADDRESS_SIGNATURE;
+ AdapterAddress->Size = sizeof (ADDRESS);
+
+ RtlZeroMemory(AdapterAddress->NetbiosName, 10);
+ RtlCopyMemory(&AdapterAddress->NetbiosName[10], AdapterMacAddress, 6);
+
+
+ InsertTailList (&Device->AdapterAddressDatabase, &AdapterAddress->Linkage);
+ ++Device->AddressCounts[AdapterAddress->NetbiosName[0]];
+
+ return AdapterAddress;
+
+} /* NbiCreateAdapterAddress */
+
+
+NTSTATUS
+NbiDestroyAdapterAddress(
+ IN PADAPTER_ADDRESS AdapterAddress OPTIONAL,
+ IN PCHAR AdapterMacAddress OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys the adapter address structure and removes it
+ from the list.
+
+Arguments:
+
+ AdapterAddress - Pointer to an adapter address structure to be destroyed
+ NULL if AdapterMacAddress is given.
+
+ AdapterMacAddress - Mac Address of the adapter which just got deleted. so find
+ the corresponding adapter address structure and remove it.
+ NULL if AdapterAddress is supplied.
+
+Return Value:
+
+ STATUS_SUCCESS or STATUS_UNSUCCESSFUL if address not found.
+
+ THIS ROUTINE ASSUMES THE THE DEVICE IS LOCK IS HELD BY THE CALLER
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ CTELockHandle LockHandle;
+ UCHAR NetbiosName[NB_NETBIOS_NAME_SIZE];
+
+
+ //
+
+ CTEAssert( AdapterAddress || AdapterMacAddress );
+ if ( !AdapterAddress ) {
+ RtlZeroMemory( NetbiosName, 10);
+ RtlCopyMemory( &NetbiosName[10], AdapterMacAddress, 6 );
+
+ AdapterAddress = NbiFindAdapterAddress( NetbiosName, LOCK_ACQUIRED );
+
+ if ( !AdapterAddress ) {
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ NB_DEBUG2 (ADDRESS, ("Destroy Adapter address %lx <%.16s>\n", AdapterAddress,AdapterAddress->NetbiosName));
+ RemoveEntryList (&AdapterAddress->Linkage);
+ ++Device->AddressCounts[AdapterAddress->NetbiosName[0]];
+
+ NbiFreeMemory (AdapterAddress, sizeof(ADAPTER_ADDRESS), MEMORY_ADAPTER_ADDRESS, "AdapterAddress");
+
+ return STATUS_SUCCESS;
+} /* NbiDestroyAdapterAddress */
+
+
+PADAPTER_ADDRESS
+NbiFindAdapterAddress(
+ IN PCHAR NetbiosName,
+ IN BOOLEAN LockHeld
+ )
+
+/*++
+
+Routine Description:
+
+ This routine finds an adapter address ( netbios name ) for the given
+ AdapterMacAddress and returns a pointer to it. Note that no reference
+ is done on this address, so if this routine is called without the device
+ lock, the caller must not use this pointer directly.
+
+Arguments:
+
+ NetbiosName - NetbiosName to be found.
+
+ LockHeld - is device lock already held or not.
+
+Return Value:
+
+ Pointer to the adapter address if found, NULL otherwise.
+
+--*/
+
+{
+
+ PLIST_ENTRY p;
+ CTELockHandle LockHandle;
+ PADAPTER_ADDRESS AdapterAddress;
+ PDEVICE Device = NbiDevice;
+
+
+ if ( !LockHeld ) {
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+ }
+ for ( p = Device->AdapterAddressDatabase.Flink;
+ p != &Device->AdapterAddressDatabase;
+ p = p->Flink ) {
+
+ AdapterAddress = CONTAINING_RECORD( p, ADAPTER_ADDRESS, Linkage );
+ if ( RtlEqualMemory(
+ NetbiosName,
+ AdapterAddress->NetbiosName,
+ NB_NETBIOS_NAME_SIZE ) ) {
+ break;
+ }
+ }
+
+
+ if ( !LockHeld ) {
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+ }
+
+ if ( p == &Device->AdapterAddressDatabase ) {
+ return NULL;
+ } else {
+ return AdapterAddress;
+ }
+
+} /* NbiFindAdapterAddress */
+
+#endif _PNP_POWER
diff --git a/private/ntos/tdi/isn/nb/autodial.c b/private/ntos/tdi/isn/nb/autodial.c
new file mode 100644
index 000000000..ec56e2351
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/autodial.c
@@ -0,0 +1,526 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ autodial.c
+
+Abstract:
+
+ NT specific routines for interfacing with the
+ RAS AutoDial driver (rasacd.sys).
+
+Author:
+
+ Anthony Discolo (adiscolo) Aug 30, 1995
+
+Revision History:
+
+ Who When What
+ -------- -------- ----------------------------------------------
+ adiscolo 08-30-95 created
+
+Notes:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef RASAUTODIAL
+
+#include <acd.h>
+#include <acdapi.h>
+
+//
+// Global variables
+//
+BOOLEAN fAcdLoadedG;
+ACD_DRIVER AcdDriverG;
+ULONG ulDriverIdG = 'Nbi ';
+
+
+
+VOID
+NbiRetryTdiConnect(
+ IN BOOLEAN fSuccess,
+ IN PVOID *pArgs
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called indirectly by the automatic
+ connection driver to continue the connection process
+ after an automatic connection has been made.
+
+Arguments:
+
+ fSuccess - TRUE if the connection attempt was successful.
+
+ pArgs - a pointer to the argument vector
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NTSTATUS status;
+ PDEVICE pDevice = pArgs[0];
+ PCONNECTION pConnection = pArgs[1];
+ PREQUEST pRequest = pArgs[2];
+ CTELockHandle ConnectionLH, DeviceLH;
+ CTELockHandle CancelLH;
+ BOOLEAN bLockFreed = FALSE;
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+#if notdef // DBG
+ DbgPrint("NbiRetryTdiConnect: fSuccess=%d, pConnection=0x%x\n", fSuccess, pConnection);
+#endif
+
+ status = NbiVerifyConnection(pConnection);
+ if (!NT_SUCCESS(status)) {
+ DbgPrint(
+ "NbiRetryTdiConnect: NbiVerifyConnection failed on connection 0x%x (status=0x%x)\n",
+ pConnection,
+ status);
+ return;
+ }
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_GET_LOCK (&pConnection->Lock, &ConnectionLH);
+ NB_GET_LOCK (&pDevice->Lock, &DeviceLH);
+
+#if notdef // DBG
+ DbgPrint(
+ "NbiRetryTdiConnect: AddressFile=0x%x, DisassociatePending=0x%x, ClosePending=0x%x\n",
+ pConnection->AddressFile,
+ pConnection->DisassociatePending,
+ pConnection->ClosePending);
+#endif
+
+ if ((pConnection->AddressFile != NULL) &&
+ (pConnection->AddressFile != (PVOID)-1) &&
+ (pConnection->DisassociatePending == NULL) &&
+ (pConnection->ClosePending == NULL))
+ {
+ NbiReferenceConnectionLock(pConnection, CREF_CONNECT);
+ //
+ // Clear the AUTOCONNECTING flag since we
+ // done with the automatic connection attempt.
+ // Set the AUTOCONNECTED flag to prevent us
+ // from attempting an automatic connection
+ // for this connection again.
+ //
+ pConnection->Flags &= ~CONNECTION_FLAGS_AUTOCONNECTING;
+ pConnection->Flags |= CONNECTION_FLAGS_AUTOCONNECTED;
+
+ pConnection->State = CONNECTION_STATE_CONNECTING;
+ pConnection->Retries = pDevice->ConnectionCount;
+ status = NbiTdiConnectFindName(
+ pDevice,
+ pRequest,
+ pConnection,
+ CancelLH,
+ ConnectionLH,
+ DeviceLH,
+ &bLockFreed);
+ }
+ else {
+ DbgPrint("NbiRetryTdiConnect: Connect on invalid connection 0x%x\n", pConnection);
+
+ pConnection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+ NB_FREE_LOCK (&pDevice->Lock, DeviceLH);
+ status = STATUS_INVALID_CONNECTION;
+ }
+ if (!bLockFreed) {
+ NB_FREE_LOCK (&pConnection->Lock, ConnectionLH);
+ NB_FREE_CANCEL_LOCK(CancelLH);
+ }
+ //
+ // Complete the irp if necessary.
+ //
+ if (status != STATUS_PENDING) {
+ REQUEST_INFORMATION(pRequest) = 0;
+ REQUEST_STATUS(pRequest) = status;
+
+ NbiCompleteRequest(pRequest);
+ NbiFreeRequest(pDevice, pRequest);
+ }
+ NbiDereferenceConnection(pConnection, CREF_VERIFY);
+} /* NbiRetryTdiConnect */
+
+
+
+BOOLEAN
+NbiCancelAutoDialRequest(
+ IN PVOID pArg,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN USHORT nArgs,
+ IN PVOID *pArgs
+ )
+{
+#if notdef // DBG
+ DbgPrint("NbiCancelAutodialRequest: pArg=0x%x\n", pArg);
+#endif
+ if (nArgs != 2)
+ return FALSE;
+
+ return (pArgs[1] == pArg);
+} // NbiCancelAutoDialRequest
+
+
+
+BOOLEAN
+NbiCancelTdiConnect(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest,
+ IN PCONNECTION pConnection
+ )
+
+/*++
+
+DESCRIPTION
+ This routine is called by the I/O system to cancel a connection
+ when we are attempting to restore an automatic connection.
+
+ARGUMENTS
+ pDevice: a pointer to the device object for this driver
+
+ pRequest: a pointer to the irp to be cancelled
+
+ pConnection: a pointer to the connnection to be cancelled
+
+RETURN VALUE
+ TRUE if the request was canceled; FALSE otherwise.
+
+--*/
+
+{
+ ACD_ADDR addr;
+
+ //
+ // Get the address of the connection.
+ //
+ addr.fType = ACD_ADDR_NB;
+ RtlCopyMemory(&addr.cNetbios, pConnection->RemoteName, 16);
+#ifdef notdef // DBG
+ DbgPrint(
+ "NbiCancelTdiConnect: pIrp=0x%x, RemoteName=%-15.15s, pConnection=0x%x\n",
+ pRequest,
+ addr.cNetbios,
+ pConnection);
+#endif
+ //
+ // Cancel the autodial request.
+ //
+ return (*AcdDriverG.lpfnCancelConnection)(
+ ulDriverIdG,
+ &addr,
+ NbiCancelAutoDialRequest,
+ pConnection);
+} // NbiCancelTdiConnect
+
+
+
+BOOLEAN
+NbiAttemptAutoDial(
+ IN PDEVICE pDevice,
+ IN PCONNECTION pConnection,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN PREQUEST pRequest
+ )
+
+/*++
+
+Routine Description:
+
+ Call the automatic connection driver to attempt an
+ automatic connection.
+
+Arguments:
+
+ pDevice - a pointer to the DEVICE structure for this connection
+
+ pConnection - a pointer to the CONNECTION block for this connection
+
+ ulFlags - connection flags to pass to the automatic
+ connection driver
+
+ pProc - a callback procedure when the automatic connection completes
+
+ pRequest - a pointer to the request irp
+
+Return Value:
+
+ TRUE if the automatic connection was started successfully,
+ FALSE otherwise.
+
+--*/
+
+{
+ ACD_ADDR addr;
+ PVOID pArgs[3];
+ BOOLEAN bSuccess;
+
+ //
+ // If we've already attempted an automatic connection
+ // on this connection, don't try it again.
+ //
+ if (pConnection->Flags & CONNECTION_FLAGS_AUTOCONNECTED)
+ return FALSE;
+ //
+ // Get the address of the connection.
+ //
+ addr.fType = ACD_ADDR_NB;
+ RtlCopyMemory(&addr.cNetbios, pConnection->RemoteName, 16);
+#ifdef notdef // DBG
+ DbgPrint("NbiAttemptAutoDial: szAddr=%15.15s\n", addr.cNetbios);
+#endif
+ //
+ // Attempt to start the connection.
+ // NbiRetryTdiConnect() will be called
+ // when the connection process has completed.
+ //
+ pArgs[0] = pDevice;
+ pArgs[1] = pConnection;
+ pArgs[2] = pRequest;
+ bSuccess = (*AcdDriverG.lpfnStartConnection)(
+ ulDriverIdG,
+ &addr,
+ ulFlags,
+ pProc,
+ 3,
+ pArgs);
+ if (bSuccess) {
+ //
+ // Set the AUTOCONNECTING flag so we know
+ // to also cancel the connection in the
+ // automatic connection driver if this
+ // request gets canceled.
+ //
+ pConnection->Flags |= CONNECTION_FLAGS_AUTOCONNECTING;
+ }
+} // NbiAttemptAutoDial
+
+
+
+VOID
+NbiNoteNewConnection(
+ IN PCONNECTION pConnection
+ )
+{
+ NTSTATUS status;
+ ACD_ADDR addr;
+ ACD_ADAPTER adapter;
+ ULONG i;
+ TDI_ADDRESS_IPX tdiIpxAddress;
+
+ addr.fType = ACD_ADDR_NB;
+ RtlCopyMemory(&addr.cNetbios, pConnection->RemoteName, 16);
+ //
+ // Determine the mac address of the adapter
+ // over which the connection has been made.
+ //
+ status = (pConnection->Device->Bind.QueryHandler)(
+ IPX_QUERY_IPX_ADDRESS,
+#if defined(_PNP_POWER)
+ &pConnection->LocalTarget.NicHandle,
+#else
+ pConnection->LocalTarget.NicId,
+#endif _PNP_POWER
+ &tdiIpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL);
+ if (status != STATUS_SUCCESS) {
+#if notdef // DBG
+ DbgPrint("NbiNoteNewConnection: QueryHandler(IPX_QUERY_IPX_ADDRESS) failed (status=0x%x)\n", status);
+ return;
+#endif
+ }
+ //
+ // Copy the source mac address to identify
+ // the adapter.
+ //
+ adapter.fType = ACD_ADAPTER_MAC;
+ for (i = 0; i < 6; i++)
+ adapter.cMac[i] = tdiIpxAddress.NodeAddress[i];
+#if notdef // DBG
+ DbgPrint(
+ "NbiNoteNewConnection: address=%-15.15s, remote mac=%02x:%02x:%02x:%02x:%02x:%02x\n",
+ addr.cNetbios,
+ adapter.cMac[0],
+ adapter.cMac[1],
+ adapter.cMac[2],
+ adapter.cMac[3],
+ adapter.cMac[4],
+ adapter.cMac[5]);
+#endif
+ //
+ // Simply notify the automatic connection driver
+ // that a successful connection has been made.
+ //
+ (*AcdDriverG.lpfnNewConnection)(
+ &addr,
+ &adapter);
+} // NbiNoteNewConnection
+
+
+
+VOID
+NbiAcdBind()
+{
+ NTSTATUS status;
+ UNICODE_STRING nameString;
+ IO_STATUS_BLOCK ioStatusBlock;
+ PIRP pIrp;
+ PFILE_OBJECT pAcdFileObject;
+ PDEVICE_OBJECT pAcdDeviceObject;
+ PACD_DRIVER pDriver = &AcdDriverG;
+
+ //
+ // Initialize the name of the automatic
+ // connection device.
+ //
+ RtlInitUnicodeString(&nameString, ACD_DEVICE_NAME);
+ //
+ // Get the file and device objects for the
+ // device.
+ //
+ status = IoGetDeviceObjectPointer(
+ &nameString,
+ SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
+ &pAcdFileObject,
+ &pAcdDeviceObject);
+ if (status != STATUS_SUCCESS)
+ return;
+ //
+ // Reference the device object.
+ //
+ ObReferenceObject(pAcdDeviceObject);
+ //
+ // Remove the reference IoGetDeviceObjectPointer()
+ // put on the file object.
+ //
+ ObDereferenceObject(pAcdFileObject);
+ //
+ // Initialize our part of the ACD_DRIVER
+ // structure.
+ //
+ KeInitializeSpinLock(&AcdDriverG.SpinLock);
+ AcdDriverG.ulDriverId = ulDriverIdG;
+ AcdDriverG.fEnabled = FALSE;
+ //
+ // Build a request to get the automatic
+ // connection driver entry points.
+ //
+ pIrp = IoBuildDeviceIoControlRequest(
+ IOCTL_INTERNAL_ACD_BIND,
+ pAcdDeviceObject,
+ (PVOID)&pDriver,
+ sizeof (pDriver),
+ NULL,
+ 0,
+ TRUE,
+ NULL,
+ &ioStatusBlock);
+ if (pIrp == NULL) {
+ ObDereferenceObject(pAcdDeviceObject);
+ return;
+ }
+ //
+ // Submit the request to the
+ // automatic connection driver.
+ //
+ status = IoCallDriver(pAcdDeviceObject, pIrp);
+ fAcdLoadedG = (status == STATUS_SUCCESS);
+ //
+ // Close the device.
+ //
+ ObDereferenceObject(pAcdDeviceObject);
+} // NbiAcdBind
+
+
+
+VOID
+NbiAcdUnbind()
+{
+ NTSTATUS status;
+ UNICODE_STRING nameString;
+ IO_STATUS_BLOCK ioStatusBlock;
+ PIRP pIrp;
+ PFILE_OBJECT pAcdFileObject;
+ PDEVICE_OBJECT pAcdDeviceObject;
+ PACD_DRIVER pDriver = &AcdDriverG;
+
+ //
+ // Don't bother to unbind if we
+ // didn't successfully bind in the
+ // first place.
+ //
+ if (!fAcdLoadedG)
+ return;
+ //
+ // Initialize the name of the automatic
+ // connection device.
+ //
+ RtlInitUnicodeString(&nameString, ACD_DEVICE_NAME);
+ //
+ // Get the file and device objects for the
+ // device.
+ //
+ status = IoGetDeviceObjectPointer(
+ &nameString,
+ SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
+ &pAcdFileObject,
+ &pAcdDeviceObject);
+ if (status != STATUS_SUCCESS)
+ return;
+ //
+ // Reference the device object.
+ //
+ ObReferenceObject(pAcdDeviceObject);
+ //
+ // Remove the reference IoGetDeviceObjectPointer()
+ // put on the file object.
+ //
+ ObDereferenceObject(pAcdFileObject);
+ //
+ // Build a request to unbind from
+ // the automatic connection driver.
+ //
+ pIrp = IoBuildDeviceIoControlRequest(
+ IOCTL_INTERNAL_ACD_UNBIND,
+ pAcdDeviceObject,
+ (PVOID)&pDriver,
+ sizeof (pDriver),
+ NULL,
+ 0,
+ TRUE,
+ NULL,
+ &ioStatusBlock);
+ if (pIrp == NULL) {
+ ObDereferenceObject(pAcdDeviceObject);
+ return;
+ }
+ //
+ // Submit the request to the
+ // automatic connection driver.
+ //
+ status = IoCallDriver(pAcdDeviceObject, pIrp);
+ //
+ // Close the device.
+ //
+ ObDereferenceObject(pAcdDeviceObject);
+} // NbiAcdUnbind
+
+#endif // RASAUTODIAL
diff --git a/private/ntos/tdi/isn/nb/bind.c b/private/ntos/tdi/isn/nb/bind.c
new file mode 100644
index 000000000..58509f692
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/bind.c
@@ -0,0 +1,594 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ driver.c
+
+Abstract:
+
+ This module contains the DriverEntry and other initialization
+ code for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 16-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,NbiBind)
+#endif
+
+#if defined(_PNP_POWER)
+//
+// local functions.
+//
+VOID
+NbiPnPNotification(
+ IN IPX_PNP_OPCODE OpCode,
+ IN PVOID PnPData
+ );
+#endif _PNP_POWER
+
+
+NTSTATUS
+NbiBind(
+ IN PDEVICE Device,
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine binds the Netbios module of ISN to the IPX
+ module, which provides the NDIS binding services.
+
+Arguments:
+
+ Device - Pointer to the Netbios device.
+
+ Config - Pointer to the configuration information.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatusBlock;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+/* union {
+ IPX_INTERNAL_BIND_INPUT Input;
+ IPX_INTERNAL_BIND_OUTPUT Output;
+ } Bind;
+*/
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &Config->BindName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = ZwCreateFile(
+ &Device->BindHandle,
+ SYNCHRONIZE | GENERIC_READ,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0L);
+
+ if (!NT_SUCCESS(Status)) {
+
+ NB_DEBUG (BIND, ("Could not open IPX (%ws) %lx\n",
+ Config->BindName.Buffer, Status));
+ NbiWriteGeneralErrorLog(
+ Device,
+ EVENT_TRANSPORT_ADAPTER_NOT_FOUND,
+ 1,
+ Status,
+ Config->BindName.Buffer,
+ 0,
+ NULL);
+ return Status;
+ }
+
+ //
+ // Fill in our bind data.
+ //
+
+#if defined(_PNP_POWER)
+ Device->BindInput.Version = ISN_VERSION;
+#else
+ Device->BindInput.Version = 1;
+#endif _PNP_POWER
+ Device->BindInput.Identifier = IDENTIFIER_NB;
+ Device->BindInput.BroadcastEnable = TRUE;
+ Device->BindInput.LookaheadRequired = 192;
+ Device->BindInput.ProtocolOptions = 0;
+ Device->BindInput.ReceiveHandler = NbiReceive;
+ Device->BindInput.ReceiveCompleteHandler = NbiReceiveComplete;
+ Device->BindInput.StatusHandler = NbiStatus;
+ Device->BindInput.SendCompleteHandler = NbiSendComplete;
+ Device->BindInput.TransferDataCompleteHandler = NbiTransferDataComplete;
+ Device->BindInput.FindRouteCompleteHandler = NbiFindRouteComplete;
+ Device->BindInput.LineUpHandler = NbiLineUp;
+ Device->BindInput.LineDownHandler = NbiLineDown;
+ Device->BindInput.ScheduleRouteHandler = NULL;
+#if defined(_PNP_POWER)
+ Device->BindInput.PnPHandler = NbiPnPNotification;
+#endif _PNP_POWER
+
+
+ Status = ZwDeviceIoControlFile(
+ Device->BindHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPX_INTERNAL_BIND, // IoControlCode
+ &Device->BindInput, // Input Buffer
+ sizeof(Device->BindInput), // Input Buffer Length
+ &Device->Bind, // OutputBuffer
+ sizeof(Device->Bind)); // OutputBufferLength
+
+ //
+ // We open synchronous, so this shouldn't happen.
+ //
+
+ CTEAssert (Status != STATUS_PENDING);
+
+ //
+ // Save the bind data.
+ //
+
+ if (Status == STATUS_SUCCESS) {
+
+ NB_DEBUG2 (BIND, ("Successfully bound to IPX (%ws)\n",
+ Config->BindName.Buffer));
+// RtlCopyMemory (&Device->Bind, &Bind.Output, sizeof(IPX_INTERNAL_BIND_OUTPUT));
+
+#if !defined(_PNP_POWER)
+ RtlZeroMemory (Device->ReservedNetbiosName, 16);
+ RtlCopyMemory (&Device->ReservedNetbiosName[10], Device->Bind.Node, 6);
+
+ Status = (*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_MAXIMUM_NIC_ID,
+ (USHORT)0,
+ &Device->MaximumNicId,
+ sizeof(Device->MaximumNicId),
+ NULL);
+ CTEAssert (Status == STATUS_SUCCESS);
+#endif !_PNP_POWER
+
+ } else {
+
+ NB_DEBUG (BIND, ("Could not bind to IPX (%ws) %lx\n",
+ Config->BindName.Buffer, Status));
+ NbiWriteGeneralErrorLog(
+ Device,
+ EVENT_TRANSPORT_BINDING_FAILED,
+ 1,
+ Status,
+ Config->BindName.Buffer,
+ 0,
+ NULL);
+ ZwClose(Device->BindHandle);
+ }
+
+ return Status;
+
+} /* NbiBind */
+
+
+VOID
+NbiUnbind(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This function closes the binding between the Netbios over
+ IPX module and the IPX module previously established by
+ NbiBind.
+
+Arguments:
+
+ Device - The netbios device object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ZwClose (Device->BindHandle);
+
+} /* NbiUnbind */
+
+
+VOID
+NbiStatus(
+ IN USHORT NicId,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This function receives a status indication from IPX,
+ corresponding to a status indication from an underlying
+ NDIS driver.
+
+Arguments:
+
+ NicId - The NIC ID of the underlying adapter.
+
+ GeneralStatus - The general status code.
+
+ StatusBuffer - The status buffer.
+
+ StatusBufferLength - The length of the status buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+} /* NbiStatus */
+
+
+VOID
+NbiLineUp(
+ IN USHORT NicId,
+ IN PIPX_LINE_INFO LineInfo,
+ IN NDIS_MEDIUM DeviceType,
+ IN PVOID ConfigurationData
+ )
+
+
+/*++
+
+Routine Description:
+
+ This function receives line up indications from IPX,
+ indicating that the specified adapter is now up with
+ the characteristics shown.
+
+Arguments:
+
+ NicId - The NIC ID of the underlying adapter.
+
+ LineInfo - Information about the adapter's medium.
+
+ DeviceType - The type of the adapter.
+
+ ConfigurationData - IPX-specific configuration data.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPXCP_CONFIGURATION Configuration = (PIPXCP_CONFIGURATION)ConfigurationData;
+
+ //
+ // Update queries have NULL as the ConfigurationData. These
+ // only indicate changes in LineInfo. BUGBUG Ignore these
+ // for the moment.
+ //
+
+ if (Configuration == NULL) {
+ return;
+ }
+
+#if !defined(_PNP_POWER)
+ //
+ // Since Netbios outgoing queries only go out on network 1,
+ // we ignore this (BUGBUG for the moment) unless that is
+ // the NIC it is on.
+ //
+
+ if (NicId == 1) {
+
+ RtlCopyMemory(NbiDevice->ConnectionlessHeader.SourceNetwork, Configuration->Network, 4);
+ RtlCopyMemory(NbiDevice->ConnectionlessHeader.SourceNode, Configuration->LocalNode, 6);
+
+ }
+#endif !_PNP_POWER
+} /* NbiLineUp */
+
+
+VOID
+NbiLineDown(
+ IN USHORT NicId,
+ IN ULONG FwdAdapterContext
+ )
+
+
+/*++
+
+Routine Description:
+
+ This function receives line down indications from IPX,
+ indicating that the specified adapter is no longer
+ up.
+
+Arguments:
+
+ NicId - The NIC ID of the underlying adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+} /* NbiLineDown */
+
+#if defined(_PNP_POWER)
+
+VOID
+NbiPnPNotification(
+ IN IPX_PNP_OPCODE OpCode,
+ IN PVOID PnPData
+ )
+
+/*++
+
+Routine Description:
+
+ This function receives the notification about PnP events from IPX.
+
+Arguments:
+
+ OpCode - Type of the PnP event
+
+ PnPData - Data associated with this event.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PDEVICE Device = NbiDevice;
+ USHORT MaximumNicId = 0;
+ CTELockHandle LockHandle;
+ UCHAR PrevReservedName[NB_NETBIOS_NAME_SIZE];
+ UNICODE_STRING UnicodeDeviceName;
+
+
+ NB_DEBUG2( DEVICE, ("Received a pnp notification, opcode %d\n",OpCode ));
+
+ switch( OpCode ) {
+ case IPX_PNP_ADD_DEVICE : {
+ IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
+ BOOLEAN ReallocReceiveBuffers = FALSE;
+
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+
+ if ( PnPInfo->NewReservedAddress ) {
+
+ *(UNALIGNED ULONG *)Device->Bind.Network = PnPInfo->NetworkAddress;
+ RtlCopyMemory( Device->Bind.Node, PnPInfo->NodeAddress, 6);
+
+// RtlZeroMemory(Device->ReservedNetbiosName, NB_NETBIOS_NAME_SIZE);
+// RtlCopyMemory(&Device->ReservedNetbiosName[10], Device->Bind.Node, 6);
+
+ *(UNALIGNED ULONG *)Device->ConnectionlessHeader.SourceNetwork = *(UNALIGNED ULONG *)Device->Bind.Network;
+ RtlCopyMemory(Device->ConnectionlessHeader.SourceNode, Device->Bind.Node, 6);
+ }
+
+ if ( PnPInfo->FirstORLastDevice ) {
+ CTEAssert( PnPInfo->NewReservedAddress );
+ CTEAssert( Device->State != DEVICE_STATE_OPEN );
+
+
+ //
+ // we must do this while we still have the device lock.
+ //
+ if ( !Device->LongTimerRunning ) {
+ Device->LongTimerRunning = TRUE;
+ NbiReferenceDevice (Device, DREF_LONG_TIMER);
+
+ CTEStartTimer(
+ &Device->LongTimer,
+ LONG_TIMER_DELTA,
+ NbiLongTimeout,
+ (PVOID)Device);
+
+ }
+
+ Device->State = DEVICE_STATE_OPEN;
+
+ CTEAssert( !Device->MaximumNicId );
+
+ Device->Bind.LineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
+ Device->Bind.LineInfo.MaximumPacketSize = PnPInfo->LineInfo.MaximumSendSize;
+ ReallocReceiveBuffers = TRUE;
+ } else {
+ if ( PnPInfo->LineInfo.MaximumPacketSize > Device->CurMaxReceiveBufferSize ) {
+ ReallocReceiveBuffers = TRUE;
+ }
+ //
+ // MaxSendSize could become smaller.
+ //
+ Device->Bind.LineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
+ }
+
+ Device->MaximumNicId++;
+
+
+ //
+ //
+ NbiCreateAdapterAddress( PnPInfo->NodeAddress );
+
+ //
+ // And finally remove all the failed cache entries since we might
+ // find those routes using this new adapter
+ //
+ FlushFailedNetbiosCacheEntries(Device->NameCache);
+
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+
+
+ if ( ReallocReceiveBuffers ) {
+ PWORK_QUEUE_ITEM WorkItem;
+
+ WorkItem = NbiAllocateMemory( sizeof(WORK_QUEUE_ITEM), MEMORY_WORK_ITEM, "Alloc Rcv Buffer work item");
+
+ if ( WorkItem ) {
+ ExInitializeWorkItem( WorkItem, NbiReAllocateReceiveBufferPool, (PVOID) WorkItem );
+ ExQueueWorkItem( WorkItem, DelayedWorkQueue );
+ } else {
+ NB_DEBUG( DEVICE, ("Cannt schdule work item to realloc receive buffer pool\n"));
+ }
+ }
+ //
+ // Notify the TDI clients about the device creation
+ //
+ if ( PnPInfo->FirstORLastDevice ) {
+ UnicodeDeviceName.Buffer = Device->DeviceName;
+ UnicodeDeviceName.MaximumLength = Device->DeviceNameLength;
+ UnicodeDeviceName.Length = Device->DeviceNameLength - sizeof(WCHAR);
+
+ if ( !NT_SUCCESS( TdiRegisterDeviceObject(
+ &UnicodeDeviceName,
+ &Device->TdiRegistrationHandle ) )) {
+ NB_DEBUG( DEVICE, ("Failed to register nwlnknb with TDI\n"));
+ }
+ }
+
+ break;
+ }
+ case IPX_PNP_DELETE_DEVICE : {
+
+ IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
+
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE CacheName;
+ USHORT i,j,NetworksRemoved;
+
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+
+ CTEAssert( Device->MaximumNicId );
+ Device->MaximumNicId--;
+
+ if ( PnPInfo->FirstORLastDevice ) {
+ Device->State = DEVICE_STATE_LOADED;
+ Device->MaximumNicId = 0;
+
+ }
+
+
+ //
+ // MaximumSendSize could change if the card with the smallest send size just
+ // got removed. MaximumPacketSize could only become smaller and we ignore that
+ // since we dont need to(want to) realloc ReceiveBuffers.
+ //
+
+ Device->Bind.LineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
+
+ //
+ // Flush all the cache entries that are using this NicId in the local
+ // target.
+ //
+ RemoveInvalidRoutesFromNetbiosCacheTable( Device->NameCache, &PnPInfo->NicHandle );
+
+ NbiDestroyAdapterAddress( NULL, PnPInfo->NodeAddress );
+
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+
+/* //
+ // Now mark the previous reserved name in conflict if it has
+ // been registered by any of our client
+ //
+ if ( Address = NbiFindAddress( Device, PrevReservedName ) ) {
+ NB_GET_LOCK( &Address->Lock, &LockHandle );
+ Address->Flags |= ADDRESS_FLAGS_CONFLICT;
+ NB_FREE_LOCK( &Address->Lock, LockHandle );
+
+ NB_DEBUG( ADDRESS, ("Reserved Address %lx<%.16s> is marked CONFLICT\n",Address,Address->NetbiosAddress.NetbiosName));
+ //
+ // nbifindaddress added a reference, so deref
+ //
+ NbiDereferenceAddress( Address, AREF_FIND );
+ }
+*/
+
+ //
+ // inform tdi clients about the device deletion
+ //
+ if ( PnPInfo->FirstORLastDevice ) {
+ if ( !NT_SUCCESS( TdiDeregisterDeviceObject(
+ Device->TdiRegistrationHandle ) )) {
+ NB_DEBUG( DEVICE, ("Failed to Deregister nwlnknb with TDI\n"));
+ }
+ }
+
+ break;
+ }
+ case IPX_PNP_ADDRESS_CHANGE: {
+ IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
+ PADDRESS Address;
+ BOOLEAN ReservedNameClosing = FALSE;
+
+ CTEAssert( PnPInfo->NewReservedAddress );
+
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+ *(UNALIGNED ULONG *)Device->Bind.Network = PnPInfo->NetworkAddress;
+ RtlCopyMemory( Device->Bind.Node, PnPInfo->NodeAddress, 6);
+
+ *(UNALIGNED ULONG *)Device->ConnectionlessHeader.SourceNetwork = *(UNALIGNED ULONG *)Device->Bind.Network;
+ RtlCopyMemory(Device->ConnectionlessHeader.SourceNode, Device->Bind.Node, 6);
+
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+
+
+ break;
+ }
+ case IPX_PNP_TRANSLATE_DEVICE:
+ break;
+ case IPX_PNP_TRANSLATE_ADDRESS:
+ break;
+ default:
+ CTEAssert( FALSE );
+ }
+} /* NbiPnPNotification */
+
+#endif _PNP_POWER
diff --git a/private/ntos/tdi/isn/nb/cache.c b/private/ntos/tdi/isn/nb/cache.c
new file mode 100644
index 000000000..cbd27ad67
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/cache.c
@@ -0,0 +1,2746 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ cache.c
+
+Abstract:
+
+ This module contains the name cache routines for the Netbios
+ module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 20-December-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef RASAUTODIAL
+#include <acd.h>
+#include <acdapi.h>
+
+extern BOOLEAN fAcdLoadedG;
+extern ACD_DRIVER AcdDriverG;
+
+BOOLEAN
+NbiAttemptAutoDial(
+ IN PDEVICE pDevice,
+ IN PCONNECTION pConnection,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN PREQUEST pRequest
+ );
+
+VOID
+NbiRetryTdiConnect(
+ IN BOOLEAN fSuccess,
+ IN PVOID *pArgs
+ );
+#endif // RASAUTODIAL
+
+//
+// BUGBUG: We should change to monitor add name packets better,
+// so if we get an add for a different place we attempt to determine
+// if it is real or bogus and update if possible.
+//
+
+
+NTSTATUS
+CacheFindName(
+ IN PDEVICE Device,
+ IN FIND_NAME_TYPE Type,
+ IN PUCHAR RemoteName OPTIONAL,
+ OUT PNETBIOS_CACHE * CacheName
+)
+
+/*++
+
+Routine Description:
+
+ This routine looks up a particular remote name in the
+ Netbios name cache. If it cannot find it, a find name
+ request is queued up.
+
+ THIS REQUEST IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Type - Defines the type. The effect this has is:
+ FindNameConnect - On connects we will ignore an existing
+ cache entry if it got no response before.
+ FindNameNetbiosFindName - For these we ignore an existing
+ cache entry if it is for a group name -- this is
+ because the find name wants the address of every
+ machine, not just the network list.
+ FindNameOther - Normal handling is done.
+
+ RemoteName - The name to be discovered -- will be NULL if it
+ is the broadcast address.
+
+ CacheName - Returns the cache entry that was discovered.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY s;
+ PNETBIOS_CACHE FoundCacheName;
+ PNB_SEND_RESERVED Reserved;
+ PUCHAR RealRemoteName; // RemoteName or NetbiosBroadcastName
+
+ //
+ // First scan the netbios name cache to see if we know
+ // about this remote.
+ //
+
+ if (RemoteName) {
+ RealRemoteName = RemoteName;
+ } else {
+ RealRemoteName = NetbiosBroadcastName;
+ }
+
+ if ( FindInNetbiosCacheTable ( Device->NameCache,
+ RealRemoteName,
+ &FoundCacheName ) == STATUS_SUCCESS ) {
+
+ //
+ // If this is a netbios find name, we only can use unique
+ // names in the cache; for the group ones we need to requery
+ // because the cache only lists networks, not individual machines.
+ // For connect requests, if we find an empty cache entry we
+ // remove it and requery.
+ //
+
+ if ( FoundCacheName->Unique || (Type != FindNameNetbiosFindName) ) {
+
+ if (FoundCacheName->NetworksUsed > 0) {
+
+ *CacheName = FoundCacheName;
+ NB_DEBUG2 (CACHE, ("Found cache name <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
+ return STATUS_SUCCESS;
+
+ } else {
+
+ if (Type != FindNameConnect) {
+
+ if (FoundCacheName->FailedOnDownWan) {
+ NB_DEBUG2 (CACHE, ("Found cache name, but down wan <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ } else {
+ NB_DEBUG2 (CACHE, ("Found cache name, but no nets <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+ } else {
+
+ //
+ // This is a connect and the current cache entry
+ // has zero names; delete it.
+ //
+
+ RemoveFromNetbiosCacheTable ( Device->NameCache, FoundCacheName );
+ CTEAssert (FoundCacheName->ReferenceCount == 1);
+ if (--FoundCacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free unneeded empty cache entry %lx\n", FoundCacheName));
+ NbiFreeMemory(
+ FoundCacheName,
+ sizeof(NETBIOS_CACHE) + ((FoundCacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free due to replacement");
+ }
+
+ }
+ }
+ }
+ }
+
+
+ //
+ // There was no suitable cache entry for this network, first see
+ // if there is one pending.
+ //
+
+ for (p = Device->WaitingFindNames.Flink;
+ p != &Device->WaitingFindNames;
+ p = p->Flink) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ //
+ // For this purpose we ignore a packet if a route
+ // has been found and it was for a unique name. This
+ // is because the cache information has already been
+ // inserted for this name. Otherwise if the name has
+ // since been deleted from the cache, the request
+ // that is looking for this name will starve because
+ // FindNameTimeout will just destroy the packet.
+ //
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+ continue;
+ }
+
+ if (RtlEqualMemory(
+ Reserved->u.SR_FN.NetbiosName,
+ RealRemoteName, 16)) {
+
+ NB_DEBUG2 (CACHE, ("Cache name already pending <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
+
+ //
+ // There is already one pending. If it is for a group
+ // name and this is a netbios find name, we make sure
+ // the retry count is such that at least one more
+ // query will be sent, so the netbios find name
+ // buffer can be filled with the responses from this.
+ //
+
+ if ((Type == FindNameNetbiosFindName) &&
+ (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseGroup) &&
+ (Reserved->u.SR_FN.RetryCount == Device->BroadcastCount)) {
+
+ --Reserved->u.SR_FN.RetryCount;
+ }
+
+ return STATUS_PENDING;
+ }
+ }
+
+ s = NbiPopSendPacket(Device, TRUE);
+
+ if (s == NULL) {
+ NB_DEBUG (CACHE, ("Couldn't get packet to find <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+
+ //
+ // We have the packet, fill it in for this request.
+ //
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = FALSE;
+ Reserved->Type = SEND_TYPE_FIND_NAME;
+ RtlCopyMemory (Reserved->u.SR_FN.NetbiosName, RealRemoteName, 16);
+ Reserved->u.SR_FN.StatusAndSentOnUpLine = FNStatusNoResponse; // SentOnUpLine is FALSE
+ Reserved->u.SR_FN.RetryCount = 0;
+ Reserved->u.SR_FN.NewCache = NULL;
+ Reserved->u.SR_FN.SendTime = Device->FindNameTime;
+#if !defined(_PNP_POWER)
+ Reserved->u.SR_FN.CurrentNicId = 1;
+
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_MAX_TYPE_20_NIC_ID,
+ (USHORT)0,
+ &Reserved->u.SR_FN.MaximumNicId,
+ sizeof(USHORT),
+ NULL);
+
+ if (Reserved->u.SR_FN.MaximumNicId == 0) {
+ Reserved->u.SR_FN.MaximumNicId = 1; // code assumes at least one
+ }
+#endif !_PNP_POWER
+ NB_DEBUG2 (CACHE, ("Queued FIND_NAME %lx for <%.16s>\n",
+ Reserved, RemoteName ? RemoteName : "<broadcast>"));
+
+
+ InsertHeadList(
+ &Device->WaitingFindNames,
+ &Reserved->WaitLinkage);
+
+ ++Device->FindNamePacketCount;
+
+ if (!Device->FindNameTimerActive) {
+
+ Device->FindNameTimerActive = TRUE;
+ NbiReferenceDevice (Device, DREF_FN_TIMER);
+
+ CTEStartTimer(
+ &Device->FindNameTimer,
+ 1, // 1 ms, i.e. expire immediately
+ FindNameTimeout,
+ (PVOID)Device);
+ }
+
+ NbiReferenceDevice (Device, DREF_FIND_NAME);
+
+ return STATUS_PENDING;
+
+} /* CacheFindName */
+
+
+VOID
+FindNameTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the find name timer expires.
+ It is called every FIND_NAME_GRANULARITY milliseconds unless there
+ is nothing to do.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the device pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)Context;
+ PLIST_ENTRY p, q;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ PNETBIOS_CACHE FoundCacheName;
+ NDIS_STATUS NdisStatus;
+#if !defined(_PNP_POWER)
+ static IPX_LOCAL_TARGET BroadcastTarget = { 0, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
+#endif !_PNP_POWER
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ ++Device->FindNameTime;
+
+ if (Device->FindNamePacketCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("FindNameTimeout exiting\n"));
+
+ Device->FindNameTimerActive = FALSE;
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ NbiDereferenceDevice (Device, DREF_FN_TIMER);
+
+ return;
+ }
+
+ //
+ // Check what is on the queue; this is set up as a
+ // loop but in fact it rarely does (under no
+ // circumstances can we send more than one packet
+ // each time this function executes).
+ //
+#if defined(_PNP_POWER)
+ while (TRUE) {
+
+ p = Device->WaitingFindNames.Flink;
+ if (p == &Device->WaitingFindNames) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ if (Reserved->SendInProgress) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+
+ //
+ // This was a find name for a unique name which got a
+ // response but was not freed at the time (because
+ // SendInProgress was still TRUE) so we free it now.
+ //
+
+ (VOID)RemoveHeadList (&Device->WaitingFindNames);
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+ --Device->FindNamePacketCount;
+
+ //
+ // It is OK to do this with the lock held because
+ // it won't be the last one (we have the RIP_TIMER ref).
+ //
+
+ NbiDereferenceDevice (Device, DREF_FIND_NAME);
+ continue;
+ }
+
+ if (((SHORT)(Device->FindNameTime - Reserved->u.SR_FN.SendTime)) < 0) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ (VOID)RemoveHeadList (&Device->WaitingFindNames);
+
+
+ //
+ // Increment the counter and see if we have sent
+ // all the frames we need to (we will age out
+ // here if we got no response for a unique query,
+ // or if we are doing a global name or broadcast
+ // search). We also kill the query right now if
+ // we have not found anything but down wan lines
+ // to send it on.
+ //
+
+ if ((++Reserved->u.SR_FN.RetryCount > Device->BroadcastCount) ||
+ ((Reserved->u.SR_FN.RetryCount > 1) && (!NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved)))) {
+
+#if DBG
+ if (Reserved->u.SR_FN.RetryCount > Device->BroadcastCount) {
+ NB_DEBUG2 (CACHE, ("FindNameTimeout aging out %lx\n", Reserved));
+ } else {
+ NB_DEBUG2 (CACHE, ("FindNameTimeout no active nets %lx\n", Reserved));
+ }
+#endif
+
+ //
+ // This packet is stale, clean it up and continue.
+ //
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseGroup) {
+
+ CTEAssert (Reserved->u.SR_FN.NewCache != NULL);
+
+ //
+ // If this was a group name and we have a new
+ // cache entry that we have been building for it,
+ // then insert that in the queue and use it
+ // to succeed any pending connects. Because
+ // netbios find name requests can cause cache
+ // requests for group names to be queued even
+ // if we already have on in the database, we
+ // first scan for old ones and remove them.
+ //
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ Reserved->u.SR_FN.NetbiosName,
+ &FoundCacheName ) == STATUS_SUCCESS ) {
+
+ NB_DEBUG2 (CACHE, ("Found old group cache name <%.16s>\n", FoundCacheName->NetbiosName));
+
+ RemoveFromNetbiosCacheTable ( Device->NameCache, FoundCacheName );
+
+ if (--FoundCacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free replaced cache entry %lx\n", FoundCacheName));
+ NbiFreeMemory(
+ FoundCacheName,
+ sizeof(NETBIOS_CACHE) + ((FoundCacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free due to replacement");
+
+ }
+
+ }
+
+ Reserved->u.SR_FN.NewCache->TimeStamp = Device->CacheTimeStamp;
+
+ InsertInNetbiosCacheTable(
+ Device->NameCache,
+ Reserved->u.SR_FN.NewCache);
+
+ //
+ // Reference it for the moment since CacheHandlePending
+ // uses it after releasing the lock. CacheHandlePending
+ // will dereference it.
+ //
+
+ ++Reserved->u.SR_FN.NewCache->ReferenceCount;
+
+ //
+ // This call releases the locks
+ //
+
+ CacheHandlePending(
+ Device,
+ Reserved->u.SR_FN.NetbiosName,
+ NetbiosNameFound,
+ Reserved->u.SR_FN.NewCache
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ CTEAssert (Reserved->u.SR_FN.NewCache == NULL);
+
+ //
+ // Allocate an empty cache entry to record the
+ // fact that we could not find this name, unless
+ // there is already an entry for this name.
+ //
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ Reserved->u.SR_FN.NetbiosName,
+ &FoundCacheName ) == STATUS_SUCCESS ) {
+
+
+ NB_DEBUG2 (CACHE, ("Don't replace old group cache name with empty <%.16s>\n", FoundCacheName->NetbiosName));
+ } else {
+
+ PNETBIOS_CACHE EmptyCache;
+
+ //
+ // Nothing found.
+ //
+
+ EmptyCache = NbiAllocateMemory (sizeof(NETBIOS_CACHE), MEMORY_CACHE, "Cache Entry");
+ if (EmptyCache != NULL) {
+
+ RtlZeroMemory (EmptyCache, sizeof(NETBIOS_CACHE));
+
+ NB_DEBUG2 (CACHE, ("Allocate new empty cache %lx for <%.16s>\n",
+ EmptyCache, Reserved->u.SR_FN.NetbiosName));
+
+ RtlCopyMemory (EmptyCache->NetbiosName, Reserved->u.SR_FN.NetbiosName, 16);
+ EmptyCache->Unique = TRUE; // so we'll delete it if we see an add name
+ EmptyCache->ReferenceCount = 1;
+ EmptyCache->NetworksAllocated = 1;
+ EmptyCache->TimeStamp = Device->CacheTimeStamp;
+ EmptyCache->NetworksUsed = 0;
+ EmptyCache->FailedOnDownWan = (BOOLEAN)
+ !NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved);
+
+ InsertInNetbiosCacheTable (
+ Device->NameCache,
+ EmptyCache);
+ }
+ }
+
+ //
+ // Fail all datagrams, etc. that were waiting for
+ // this route. This call releases the lock.
+ //
+
+ CacheHandlePending(
+ Device,
+ Reserved->u.SR_FN.NetbiosName,
+ NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved) ?
+ NetbiosNameNotFoundNormal :
+ NetbiosNameNotFoundWanDown,
+ NULL
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ --Device->FindNamePacketCount;
+ NbiDereferenceDevice (Device, DREF_FIND_NAME);
+ continue;
+ }
+
+
+
+
+ //
+ // Send the packet out again. We first set the time so
+ // it won't be sent again until the appropriate timeout.
+ //
+
+ Reserved->u.SR_FN.SendTime = (USHORT)(Device->FindNameTime + Device->FindNameTimeout);
+
+ InsertTailList (&Device->WaitingFindNames, &Reserved->WaitLinkage);
+
+ CTEAssert (Reserved->Identifier == IDENTIFIER_NB);
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // If this is the first retry, we need to initialize the packet
+ //
+ if ( Reserved->u.SR_FN.RetryCount == 1 ) {
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address, which is
+ // what we want.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)(&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
+
+ Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
+ Header->NameFrame.ConnectionControlFlag = 0x00;
+ Header->NameFrame.DataStreamType = NB_CMD_FIND_NAME;
+ Header->NameFrame.DataStreamType2 = NB_CMD_FIND_NAME;
+ Header->NameFrame.NameTypeFlag = 0x00;
+
+ RtlCopyMemory(
+ Header->NameFrame.Name,
+ Reserved->u.SR_FN.NetbiosName,
+ 16);
+
+
+ }
+ //
+ // Now submit the packet to IPX.
+ //
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ NB_DEBUG2 (CACHE, ("FindNameTimeout sending %lx\n", Reserved));
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) +
+ sizeof(NB_NAME_FRAME));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &BroadcastTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+
+ break;
+
+ }
+#else
+ while (TRUE) {
+
+ p = Device->WaitingFindNames.Flink;
+ if (p == &Device->WaitingFindNames) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ if (Reserved->SendInProgress) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+
+ //
+ // This was a find name for a unique name which got a
+ // response but was not freed at the time (because
+ // SendInProgress was still TRUE) so we free it now.
+ //
+
+ (VOID)RemoveHeadList (&Device->WaitingFindNames);
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+ --Device->FindNamePacketCount;
+
+ //
+ // It is OK to do this with the lock held because
+ // it won't be the last one (we have the RIP_TIMER ref).
+ //
+
+ NbiDereferenceDevice (Device, DREF_FIND_NAME);
+ continue;
+ }
+
+ if (((SHORT)(Device->FindNameTime - Reserved->u.SR_FN.SendTime)) < 0) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ (VOID)RemoveHeadList (&Device->WaitingFindNames);
+
+ //
+ // Save this now, then change it if needed.
+ //
+
+ BroadcastTarget.NicId = Reserved->u.SR_FN.CurrentNicId;
+
+ if (Reserved->u.SR_FN.CurrentNicId == 1) {
+
+ //
+ // Increment the counter and see if we have sent
+ // all the frames we need to (we will age out
+ // here if we got no response for a unique query,
+ // or if we are doing a global name or broadcast
+ // search). We also kill the query right now if
+ // we have not found anything but down wan lines
+ // to send it on.
+ //
+
+ if ((++Reserved->u.SR_FN.RetryCount > Device->BroadcastCount) ||
+ ((Reserved->u.SR_FN.RetryCount > 1) && (!NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved)))) {
+
+#if DBG
+ if (Reserved->u.SR_FN.RetryCount > Device->BroadcastCount) {
+ NB_DEBUG2 (CACHE, ("FindNameTimeout aging out %lx\n", Reserved));
+ } else {
+ NB_DEBUG2 (CACHE, ("FindNameTimeout no active nets %lx\n", Reserved));
+ }
+#endif
+
+ //
+ // This packet is stale, clean it up and continue.
+ //
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseGroup) {
+
+ CTEAssert (Reserved->u.SR_FN.NewCache != NULL);
+
+ //
+ // If this was a group name and we have a new
+ // cache entry that we have been building for it,
+ // then insert that in the queue and use it
+ // to succeed any pending connects. Because
+ // netbios find name requests can cause cache
+ // requests for group names to be queued even
+ // if we already have on in the database, we
+ // first scan for old ones and remove them.
+ //
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ Reserved->u.SR_FN.NetbiosName,
+ &FoundCacheName ) == STATUS_SUCCESS ) {
+
+ NB_DEBUG2 (CACHE, ("Found old group cache name <%.16s>\n", FoundCacheName->NetbiosName));
+
+ RemoveFromNetbiosCacheTable ( Device->NameCache, FoundCacheName );
+
+ if (--FoundCacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free replaced cache entry %lx\n", FoundCacheName));
+ NbiFreeMemory(
+ FoundCacheName,
+ sizeof(NETBIOS_CACHE) + ((FoundCacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free due to replacement");
+
+ }
+ }
+
+ Reserved->u.SR_FN.NewCache->TimeStamp = Device->CacheTimeStamp;
+
+ InsertInNetbiosCacheTable(
+ Device->NameCache,
+ Reserved->u.SR_FN.NewCache);
+
+ //
+ // Reference it for the moment since CacheHandlePending
+ // uses it after releasing the lock. CacheHandlePending
+ // will dereference it.
+ //
+
+ ++Reserved->u.SR_FN.NewCache->ReferenceCount;
+
+ //
+ // This call releases the locks
+ //
+
+ CacheHandlePending(
+ Device,
+ Reserved->u.SR_FN.NetbiosName,
+ NetbiosNameFound,
+ Reserved->u.SR_FN.NewCache
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ CTEAssert (Reserved->u.SR_FN.NewCache == NULL);
+
+ //
+ // Allocate an empty cache entry to record the
+ // fact that we could not find this name, unless
+ // there is already an entry for this name.
+ //
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ Reserved->u.SR_FN.NetbiosName,
+ &FoundCacheName ) == STATUS_SUCCESS ) {
+
+
+ NB_DEBUG2 (CACHE, ("Don't replace old group cache name with empty <%.16s>\n", FoundCacheName->NetbiosName));
+
+ } else {
+
+ PNETBIOS_CACHE EmptyCache;
+
+ //
+ // Nothing found.
+ //
+
+ EmptyCache = NbiAllocateMemory (sizeof(NETBIOS_CACHE), MEMORY_CACHE, "Cache Entry");
+ if (EmptyCache != NULL) {
+
+ RtlZeroMemory (EmptyCache, sizeof(NETBIOS_CACHE));
+
+ NB_DEBUG2 (CACHE, ("Allocate new empty cache %lx for <%.16s>\n",
+ EmptyCache, Reserved->u.SR_FN.NetbiosName));
+
+ RtlCopyMemory (EmptyCache->NetbiosName, Reserved->u.SR_FN.NetbiosName, 16);
+ EmptyCache->Unique = TRUE; // so we'll delete it if we see an add name
+ EmptyCache->ReferenceCount = 1;
+ EmptyCache->NetworksAllocated = 1;
+ EmptyCache->TimeStamp = Device->CacheTimeStamp;
+ EmptyCache->NetworksUsed = 0;
+ EmptyCache->FailedOnDownWan = (BOOLEAN)
+ !NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved);
+
+ InsertInNetbiosCacheTable (
+ Device->NameCache,
+ EmptyCache);
+ }
+ }
+
+ //
+ // Fail all datagrams, etc. that were waiting for
+ // this route. This call releases the lock.
+ //
+
+ CacheHandlePending(
+ Device,
+ Reserved->u.SR_FN.NetbiosName,
+ NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved) ?
+ NetbiosNameNotFoundNormal :
+ NetbiosNameNotFoundWanDown,
+ NULL
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+ --Device->FindNamePacketCount;
+ NbiDereferenceDevice (Device, DREF_FIND_NAME);
+ continue;
+ }
+
+ }
+
+
+ //
+ // Increment the current NIC ID for next time.
+ //
+
+ if (Reserved->u.SR_FN.CurrentNicId >= Reserved->u.SR_FN.MaximumNicId) {
+ Reserved->u.SR_FN.CurrentNicId = 1;
+ } else {
+ ++Reserved->u.SR_FN.CurrentNicId;
+ }
+
+
+ //
+ // Send the packet out again. We first set the time so
+ // it won't be sent again until the appropriate timeout.
+ // If we are going to wrap around the maximum NIC ID
+ // after sending this packet we wait the full configured
+ // amount, otherwise we wait almost the minimum (but still
+ // insert ourselves at the back of the queue to be fair).
+ //
+
+ if (Reserved->u.SR_FN.CurrentNicId == 1) {
+ Reserved->u.SR_FN.SendTime = (USHORT)(Device->FindNameTime + Device->FindNameTimeout);
+ } else {
+ Reserved->u.SR_FN.SendTime = (USHORT)(Device->FindNameTime + 2);
+ }
+ InsertTailList (&Device->WaitingFindNames, &Reserved->WaitLinkage);
+
+ CTEAssert (Reserved->Identifier == IDENTIFIER_NB);
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address, which is
+ // what we want.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)(&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
+
+ Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
+ Header->NameFrame.ConnectionControlFlag = 0x00;
+ Header->NameFrame.DataStreamType = NB_CMD_FIND_NAME;
+ Header->NameFrame.DataStreamType2 = NB_CMD_FIND_NAME;
+ Header->NameFrame.NameTypeFlag = 0x00;
+
+ RtlCopyMemory(
+ Header->NameFrame.Name,
+ Reserved->u.SR_FN.NetbiosName,
+ 16);
+
+ //
+ // Now submit the packet to IPX.
+ //
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ NB_DEBUG2 (CACHE, ("FindNameTimeout sending %lx to %d\n", Reserved, BroadcastTarget.NicId));
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) +
+ sizeof(NB_NAME_FRAME));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &BroadcastTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+ if (NdisStatus == STATUS_DEVICE_DOES_NOT_EXIST) {
+
+ //
+ // This send was done on a down wan line. To avoid
+ // extensive delays sending find names on systems
+ // with a lot of wan lines, we loop around immediately
+ // and do the next send. We put this packet back on
+ // the head of the list and change its SendTime so
+ // it will be resent immediately.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ NB_DEBUG2 (CACHE, ("FindNameTimeout resending %lx, wan send failed\n", Reserved));
+
+ RemoveEntryList (&Reserved->WaitLinkage);
+ InsertHeadList (&Device->WaitingFindNames, &Reserved->WaitLinkage);
+ Reserved->u.SR_FN.SendTime = Device->FindNameTime;
+
+ continue;
+
+ } else {
+
+ //
+ // We keep track of when it finds a net that isn't
+ // a down wan line so that we can tell when datagram
+ // sends should fail (otherwise we succeed them, so
+ // the browser won't think this is a down wan line).
+ //
+
+ NB_SET_SR_FN_SENT_ON_UP_LINE (Reserved, TRUE);
+ }
+
+
+ break;
+
+ }
+#endif _PNP_POWER
+
+ //
+ // Since we did something this time, we restart the timer.
+ //
+
+ CTEStartTimer(
+ &Device->FindNameTimer,
+ FIND_NAME_GRANULARITY,
+ FindNameTimeout,
+ (PVOID)Device);
+
+} /* FindNameTimeout */
+
+
+VOID
+CacheHandlePending(
+ IN PDEVICE Device,
+ IN PUCHAR RemoteName,
+ IN NETBIOS_NAME_RESULT Result,
+ IN PNETBIOS_CACHE CacheName OPTIONAL
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine cleans up pending datagrams and connects
+ that were waiting for a route to be discovered to a
+ given Netbios NAME. THIS ROUTINE IS CALLED WITH
+ DEVICE->LOCK ACQUIRED AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Device - The device.
+
+ RemoteName - The netbios name that was being searched for.
+
+ Result - Indicates if the name was found, or not found due
+ to no response or wan lines being down.
+
+ CacheName - If Result is NetbiosNameFound, the cache entry for this name.
+ This entry has been referenced and this routine will deref it.
+
+ LockHandle - The handle used to acquire the lock.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ LIST_ENTRY DatagramList;
+ LIST_ENTRY ConnectList;
+ LIST_ENTRY AdapterStatusList;
+ LIST_ENTRY NetbiosFindNameList;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ PLIST_ENTRY p;
+ PREQUEST ConnectRequest, DatagramRequest, AdapterStatusRequest, NetbiosFindNameRequest;
+ PCONNECTION Connection;
+ PADDRESS_FILE AddressFile;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteAddress;
+ CTELockHandle CancelLH;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+
+
+ InitializeListHead (&DatagramList);
+ InitializeListHead (&ConnectList);
+ InitializeListHead (&AdapterStatusList);
+ InitializeListHead (&NetbiosFindNameList);
+
+ //
+ // Put all connect requests on ConnectList. They will
+ // be continued or failed later.
+ //
+
+ p = Device->WaitingConnects.Flink;
+
+ while (p != &Device->WaitingConnects) {
+
+ ConnectRequest = LIST_ENTRY_TO_REQUEST(p);
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(ConnectRequest);
+ p = p->Flink;
+
+ if (RtlEqualMemory (Connection->RemoteName, RemoteName, 16)) {
+
+ RemoveEntryList (REQUEST_LINKAGE(ConnectRequest));
+ InsertTailList (&ConnectList, REQUEST_LINKAGE(ConnectRequest));
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_W_ACK;
+ }
+
+ }
+
+
+ //
+ // Put all the datagrams on Datagram list. They will be
+ // sent or failed later.
+ //
+
+ p = Device->WaitingDatagrams.Flink;
+
+ while (p != &Device->WaitingDatagrams) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ p = p->Flink;
+
+ //
+ // Check differently based on whether we were looking for
+ // the broadcast address or not.
+ //
+
+ if (Reserved->u.SR_DG.RemoteName == (PVOID)-1) {
+ if (!RtlEqualMemory (RemoteName, NetbiosBroadcastName, 16)) {
+ continue;
+ }
+ } else {
+
+ if (!RtlEqualMemory (RemoteName, Reserved->u.SR_DG.RemoteName->NetbiosName, 16)) {
+ continue;
+ }
+ }
+
+ RemoveEntryList (&Reserved->WaitLinkage);
+ InsertTailList (&DatagramList, &Reserved->WaitLinkage);
+
+ //
+ // Reference this here with the lock held.
+ //
+
+ if (Result == NetbiosNameFound) {
+ ++CacheName->ReferenceCount;
+ }
+
+ }
+
+
+ //
+ // Put all the adapter status requests on AdapterStatus
+ // list. They will be sent or failed later.
+ //
+
+ p = Device->WaitingAdapterStatus.Flink;
+
+ while (p != &Device->WaitingAdapterStatus) {
+
+ AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ p = p->Flink;
+
+ RemoteAddress = (TDI_ADDRESS_NETBIOS UNALIGNED *)REQUEST_INFORMATION(AdapterStatusRequest);
+
+ if (!RtlEqualMemory(
+ RemoteName,
+ RemoteAddress->NetbiosName,
+ 16)) {
+ continue;
+ }
+
+ RemoveEntryList (REQUEST_LINKAGE(AdapterStatusRequest));
+ InsertTailList (&AdapterStatusList, REQUEST_LINKAGE(AdapterStatusRequest));
+
+ //
+ // Reference this here with the lock held.
+ //
+
+ if (Result == NetbiosNameFound) {
+ ++CacheName->ReferenceCount;
+ }
+
+ }
+
+
+ //
+ // Put all the netbios find name requests on NetbiosFindName
+ // list. They will be completed later.
+ //
+
+ p = Device->WaitingNetbiosFindName.Flink;
+
+ while (p != &Device->WaitingNetbiosFindName) {
+
+ NetbiosFindNameRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ p = p->Flink;
+
+ RemoteAddress = (TDI_ADDRESS_NETBIOS UNALIGNED *)REQUEST_INFORMATION(NetbiosFindNameRequest);
+
+ if (!RtlEqualMemory(
+ RemoteName,
+ RemoteAddress->NetbiosName,
+ 16)) {
+ continue;
+ }
+
+ RemoveEntryList (REQUEST_LINKAGE(NetbiosFindNameRequest));
+ InsertTailList (&NetbiosFindNameList, REQUEST_LINKAGE(NetbiosFindNameRequest));
+
+ }
+
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+
+ //
+ // Now that the lock is free, process all the packets on
+ // the various lists.
+ //
+
+ for (p = ConnectList.Flink; p != &ConnectList; ) {
+
+ ConnectRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(ConnectRequest);
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN)) {
+
+ if (Result == NetbiosNameFound) {
+
+ NB_DEBUG2 (CONNECTION, ("Found queued connect %lx on %lx\n", ConnectRequest, Connection));
+
+ //
+ // Continue with the connection sequence.
+ //
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_W_ROUTE;
+
+
+ if (!ConnectRequest->Cancel) {
+
+ IoSetCancelRoutine (ConnectRequest, NbiCancelConnectWaitResponse);
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle1 );
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ Connection->LocalTarget = CacheName->Networks[0].LocalTarget;
+ RtlCopyMemory(&Connection->RemoteHeader.DestinationNetwork, &CacheName->FirstResponse, 12);
+ NbiReferenceConnectionSync (Connection, CREF_FIND_ROUTE);
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network = CacheName->FirstResponse.NetworkAddress;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,CacheName->FirstResponse.NodeAddress,6);
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_RIP_IF_NEEDED;
+
+ //
+ // When this completes, we will send the session init.
+ // We don't call it if the client is for network 0,
+ // instead just fake as if no route could be found
+ // and we will use the local target we got here.
+ //
+
+ if (CacheName->FirstResponse.NetworkAddress != 0) {
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ } else {
+
+ NbiFindRouteComplete(
+ &Connection->FindRouteRequest,
+ FALSE);
+
+ }
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelling connect %lx on %lx\n", ConnectRequest, Connection));
+
+ goto AbortConnect;
+
+ //
+ // Jumps down into the else below.
+ //
+
+ }
+
+ } else {
+ BOOLEAN bAutodialAttempt = FALSE;
+
+ NB_DEBUG2 (CONNECTION, ("Timing out connect %lx on %lx\n", ConnectRequest, Connection));
+AbortConnect:
+
+ ASSERT (Connection->ConnectRequest == ConnectRequest);
+
+#ifdef RASAUTODIAL
+ if (fAcdLoadedG) {
+ CTELockHandle adirql;
+ BOOLEAN fEnabled;
+
+ //
+ // See if the automatic connection driver knows
+ // about this address before we search the
+ // network. If it does, we return STATUS_PENDING,
+ // and we will come back here via NbfRetryTdiConnect().
+ //
+ CTEGetLock(&AcdDriverG.SpinLock, &adirql);
+ fEnabled = AcdDriverG.fEnabled;
+ CTEFreeLock(&AcdDriverG.SpinLock, adirql);
+ if (fEnabled && NbiAttemptAutoDial(
+ Device,
+ Connection,
+ 0,
+ NbiRetryTdiConnect,
+ ConnectRequest))
+ {
+ NB_SYNC_FREE_LOCK(&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK(CancelLH);
+
+ bAutodialAttempt = TRUE;
+ }
+ }
+#endif // RASAUTODIAL
+
+ if (!bAutodialAttempt) {
+ Connection->ConnectRequest = NULL;
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ IoSetCancelRoutine( ConnectRequest, (PDRIVER_CANCEL)NULL );
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ REQUEST_STATUS(ConnectRequest) = STATUS_BAD_NETWORK_PATH;
+
+ NbiCompleteRequest(ConnectRequest);
+ NbiFreeRequest (Device, ConnectRequest);
+ }
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ }
+
+ } else {
+
+ // BUGBUG What happens to the IRP? Who completes it?
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_WAIT_CACHE);
+
+ }
+
+
+ for (p = DatagramList.Flink; p != &DatagramList; ) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+ p = p->Flink;
+
+ if (Result == NetbiosNameFound) {
+
+ NB_DEBUG2 (DATAGRAM, ("Found queued datagram %lx on %lx\n", Reserved->u.SR_DG.DatagramRequest, Reserved->u.SR_DG.AddressFile));
+
+ Reserved->u.SR_DG.Cache = CacheName;
+ Reserved->u.SR_DG.CurrentNetwork = 0;
+
+ //
+ // CacheName was referenced above.
+ //
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+ if ( REQUEST_NDIS_BUFFER( Reserved->u.SR_DG.DatagramRequest )) {
+ NdisChainBufferAtBack (Packet, REQUEST_NDIS_BUFFER(Reserved->u.SR_DG.DatagramRequest));
+ }
+
+ NbiTransmitDatagram (Reserved);
+
+ } else {
+
+ //
+ // BETABUGBUG: Should we send it once as a broadcast
+ // on net 0, just in case??
+ //
+
+ AddressFile = Reserved->u.SR_DG.AddressFile;
+ DatagramRequest = Reserved->u.SR_DG.DatagramRequest;
+
+ NB_DEBUG2 (DATAGRAM, ("Timing out datagram %lx on %lx\n", DatagramRequest, AddressFile));
+
+ //
+ // If the failure was due to a down wan line indicate
+ // that, otherwise return success (so the browser won't
+ // confuse this with a down wan line).
+ //
+
+ if (Result == NetbiosNameNotFoundWanDown) {
+ REQUEST_STATUS(DatagramRequest) = STATUS_DEVICE_DOES_NOT_EXIST;
+ REQUEST_INFORMATION(DatagramRequest) = 0;
+ } else {
+ REQUEST_STATUS(DatagramRequest) = STATUS_SUCCESS;
+ }
+
+ NbiCompleteRequest(DatagramRequest);
+ NbiFreeRequest (Device, DatagramRequest);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_SEND_DGRAM);
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+ }
+
+ }
+
+
+ for (p = AdapterStatusList.Flink; p != &AdapterStatusList; ) {
+
+ AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ if (Result == NetbiosNameFound) {
+
+ NB_DEBUG2 (QUERY, ("Found queued AdapterStatus %lx\n", AdapterStatusRequest));
+
+ //
+ // Continue with the AdapterStatus sequence. We put
+ // it in ActiveAdapterStatus, it will either get
+ // completed when a response is received or timed
+ // out by the long timeout.
+ //
+
+ REQUEST_STATUS(AdapterStatusRequest) = (NTSTATUS)CacheName;
+
+ //
+ // CacheName was referenced above.
+ //
+
+ REQUEST_INFORMATION (AdapterStatusRequest) = 0;
+
+ NB_INSERT_TAIL_LIST(
+ &Device->ActiveAdapterStatus,
+ REQUEST_LINKAGE (AdapterStatusRequest),
+ &Device->Lock);
+
+ NbiSendStatusQuery (AdapterStatusRequest);
+
+ } else {
+
+ NB_DEBUG2 (QUERY, ("Timing out AdapterStatus %lx\n", AdapterStatusRequest));
+
+ REQUEST_STATUS(AdapterStatusRequest) = STATUS_IO_TIMEOUT;
+
+ NbiCompleteRequest(AdapterStatusRequest);
+ NbiFreeRequest (Device, AdapterStatusRequest);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_QUERY);
+
+ }
+
+ }
+
+
+ for (p = NetbiosFindNameList.Flink; p != &NetbiosFindNameList; ) {
+
+ NetbiosFindNameRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ //
+ // In fact there is not much difference between success or
+ // failure, since in the successful case the information
+ // will already have been written to the buffer. Just
+ // complete the request with the appropriate status,
+ // which will already be stored in the request.
+ //
+
+ if (Result == NetbiosNameFound) {
+
+ if (CacheName->Unique) {
+
+ NB_DEBUG2 (QUERY, ("Found queued unique NetbiosFindName %lx\n", NetbiosFindNameRequest));
+
+ } else {
+
+ NB_DEBUG2 (QUERY, ("Found queued group NetbiosFindName %lx\n", NetbiosFindNameRequest));
+
+ }
+
+ } else {
+
+ CTEAssert (REQUEST_STATUS(NetbiosFindNameRequest) == STATUS_IO_TIMEOUT);
+ NB_DEBUG2 (QUERY, ("Timed out NetbiosFindName %lx\n", NetbiosFindNameRequest));
+
+ }
+
+ //
+ // This sets REQUEST_INFORMATION(Request) to the correct value.
+ //
+
+ NbiSetNetbiosFindNameInformation (NetbiosFindNameRequest);
+
+ NbiCompleteRequest(NetbiosFindNameRequest);
+ NbiFreeRequest (Device, NetbiosFindNameRequest);
+
+ NbiDereferenceDevice (Device, DREF_NB_FIND_NAME);
+
+ }
+
+
+ //
+ // We referenced this temporarily so we could use it in here,
+ // deref and check if we need to delete it.
+ //
+
+ if (Result == NetbiosNameFound) {
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle1);
+
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free newly allocated cache entry %lx\n", CacheName));
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free in CacheHandlePending");
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle1);
+
+ }
+
+} /* CacheHandlePending */
+
+
+VOID
+NbiProcessNameRecognized(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_NAME_RECOGNIZED frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PDEVICE Device = NbiDevice;
+ PNETBIOS_CACHE NameCache;
+ PREQUEST NetbiosFindNameRequest;
+ PNB_SEND_RESERVED Reserved;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteNetbiosAddress;
+ NB_CONNECTIONLESS UNALIGNED * Connectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
+ NB_DEFINE_LOCK_HANDLE(LockHandle)
+
+
+#if 0
+ //
+ // BETABUGBUG: We should handle responses from network 0
+ // differently -- if they are for a group name, we should
+ // keep them around but only until we get a non-zero
+ // response from the same card.
+ //
+
+ if (*(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork) == 0) {
+ return;
+ }
+#endif
+
+
+ //
+ // We need to scan our queue of pending find name packets
+ // to see if someone is waiting for this name.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (p = Device->WaitingFindNames.Flink;
+ p != &Device->WaitingFindNames;
+ p = p->Flink) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ //
+ // Find names which have already found unique names are
+ // "dead", waiting for FindNameTimeout to remove them,
+ // and should be ignored when scanning the list.
+ //
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+
+ continue;
+ }
+
+ if (RtlEqualMemory (Reserved->u.SR_FN.NetbiosName, Connectionless->NameFrame.Name, 16)) {
+ break;
+ }
+ }
+
+ if (p == &Device->WaitingFindNames) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+
+ //
+ // Scan for any netbios find name requests on the queue, and
+ // inform them about this remote. We need to do this on every
+ // response because group names need every computer recorded,
+ // but the normal cache only includes one entry per network.
+ //
+
+ for (p = Device->WaitingNetbiosFindName.Flink;
+ p != &Device->WaitingNetbiosFindName;
+ p = p->Flink) {
+
+ NetbiosFindNameRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ RemoteNetbiosAddress = (TDI_ADDRESS_NETBIOS UNALIGNED *)REQUEST_INFORMATION(NetbiosFindNameRequest);
+
+ if (!RtlEqualMemory(
+ Connectionless->NameFrame.Name,
+ RemoteNetbiosAddress->NetbiosName,
+ 16)) {
+ continue;
+ }
+
+ //
+ // This will update the request status if needed.
+ //
+
+ NbiUpdateNetbiosFindName(
+ NetbiosFindNameRequest,
+#if defined(_PNP_POWER)
+ &RemoteAddress->NicHandle,
+#else
+ RemoteAddress->NicId,
+#endif _PNP_POWER
+ (TDI_ADDRESS_IPX UNALIGNED *)Connectionless->IpxHeader.SourceNetwork,
+ (BOOLEAN)((Connectionless->NameFrame.NameTypeFlag & NB_NAME_GROUP) == 0));
+
+ }
+
+
+ //
+ // See what is up with this pending find name packet.
+ //
+
+ if (Reserved->u.SR_FN.NewCache == NULL) {
+
+ //
+ // This is the first response we have received, so we
+ // allocate the initial entry with room for a single
+ // entry.
+ //
+
+ NameCache = NbiAllocateMemory (sizeof(NETBIOS_CACHE), MEMORY_CACHE, "Cache Entry");
+ if (NameCache == NULL) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ NB_DEBUG2 (CACHE, ("Alloc new cache %lx for <%.16s>, net %lx\n",
+ NameCache, Reserved->u.SR_FN.NetbiosName,
+ *(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork)));
+
+ RtlCopyMemory (NameCache->NetbiosName, Connectionless->NameFrame.Name, 16);
+ NameCache->Unique = (BOOLEAN)((Connectionless->NameFrame.NameTypeFlag & NB_NAME_GROUP) == 0);
+ NameCache->ReferenceCount = 1;
+ RtlCopyMemory (&NameCache->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12);
+ NameCache->NetworksAllocated = 1;
+ NameCache->NetworksUsed = 1;
+ NameCache->Networks[0].Network = *(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork);
+
+ if (RtlEqualMemory (Connectionless->NameFrame.Name, NetbiosBroadcastName, 16)) {
+
+ NB_SET_SR_FN_STATUS (Reserved, FNStatusResponseGroup);
+ NameCache->Unique = FALSE;
+
+ } else {
+
+ NB_SET_SR_FN_STATUS(
+ Reserved,
+ NameCache->Unique ? FNStatusResponseUnique : FNStatusResponseGroup);
+
+ }
+
+ Reserved->u.SR_FN.NewCache = NameCache;
+
+ //
+ // If this packet was not routed to us and is for a group name,
+ // rather than use whatever local target it happened to come
+ // from we set it up so that it is broadcast on that net.
+ //
+
+ if ((RtlEqualMemory (RemoteAddress->MacAddress, Connectionless->IpxHeader.SourceNode, 6)) &&
+ (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseGroup)) {
+#if defined(_PNP_POWER)
+ NameCache->Networks[0].LocalTarget.NicHandle = RemoteAddress->NicHandle;
+#else
+ NameCache->Networks[0].LocalTarget.NicId = RemoteAddress->NicId;
+#endif _PNP_POWER
+ RtlCopyMemory (NameCache->Networks[0].LocalTarget.MacAddress, BroadcastAddress, 6);
+ RtlCopyMemory (NameCache->FirstResponse.NodeAddress, BroadcastAddress, 6);
+ } else {
+ NameCache->Networks[0].LocalTarget = *RemoteAddress;
+ }
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+
+ //
+ // Complete pending requests now, since it is a unique
+ // name we have all the information we will get.
+ //
+
+ NameCache->TimeStamp = Device->CacheTimeStamp;
+
+ InsertInNetbiosCacheTable(
+ Device->NameCache,
+ NameCache);
+
+ //
+ // Reference it since CacheHandlePending uses it
+ // with the lock released. CacheHandlePending
+ // will dereference it.
+ //
+
+ ++NameCache->ReferenceCount;
+
+ //
+ // This call releases the lock.
+ //
+
+ CacheHandlePending(
+ Device,
+ Reserved->u.SR_FN.NetbiosName,
+ NetbiosNameFound,
+ NameCache
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ //
+ // We already have a response to this frame.
+ //
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+
+ //
+ // BUGBUG: Should we check that the response is also
+ // unique? Not much to do since I don't know of an
+ // equivalent to the netbeui NAME_IN_CONFLICT.
+ //
+
+ } else {
+
+ //
+ // This is a group name.
+ //
+
+ if (Connectionless->NameFrame.NameTypeFlag & NB_NAME_GROUP) {
+
+ //
+ // Update our information about this network if needed.
+ // This may free the existing cache and allocate a new one.
+ //
+
+ Reserved->u.SR_FN.NewCache =
+ CacheUpdateNameCache(
+ Reserved->u.SR_FN.NewCache,
+ RemoteAddress,
+ (TDI_ADDRESS_IPX UNALIGNED *)
+ Connectionless->IpxHeader.SourceNetwork,
+ FALSE);
+
+ } else {
+
+ //
+ // BUGBUG: This respondent thinks it is a unique name
+ // but we think it is group, should we do something?
+ //
+
+ }
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+} /* NbiProcessNameRecognized */
+
+
+PNETBIOS_CACHE
+CacheUpdateNameCache(
+ IN PNETBIOS_CACHE NameCache,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN TDI_ADDRESS_IPX UNALIGNED * SourceAddress,
+ IN BOOLEAN ModifyQueue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to update a netbios cache entry
+ with a new network, if it is does not already contain
+ information about the network. It is called when a frame
+ is received advertising the appropriate cache entry, which
+ is either a group name or the broadcast name.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH IT HELD.
+
+Arguments:
+
+ NameCache - The name cache entry to update.
+
+ RemoteAddress - The remote address on which a frame was received.
+
+ IpxAddress - The source IPX address of the frame.
+
+ ModifyQueue - TRUE if we should update the queue which this
+ cache entry is in, if we reallocate it.
+
+Return Value:
+
+ The netbios cache entry, either the original or a reallocated one.
+
+--*/
+
+{
+
+ PDEVICE Device = NbiDevice;
+ USHORT NewNetworks;
+ PNETBIOS_CACHE NewNameCache;
+ PLIST_ENTRY OldPrevious;
+ UINT i;
+
+ //
+ // See if we already know about this network.
+ //
+
+ for (i = 0; i < NameCache->NetworksUsed; i++) {
+ if (NameCache->Networks[i].Network == SourceAddress->NetworkAddress) {
+ return NameCache;
+ }
+ }
+
+ //
+ // We need to add information about this network
+ // to the name cache entry. If we have to allocate
+ // a new one we do that.
+ //
+
+ NB_DEBUG2 (CACHE, ("Got new net %lx for <%.16s>\n",
+ SourceAddress->NetworkAddress,
+ NameCache->NetbiosName));
+
+ if (NameCache->NetworksUsed == NameCache->NetworksAllocated) {
+
+ //
+ // We double the number of entries allocated until
+ // we hit 16, then add 8 at a time.
+ //
+
+ if (NameCache->NetworksAllocated < 16) {
+ NewNetworks = NameCache->NetworksAllocated * 2;
+ } else {
+ NewNetworks = NameCache->NetworksAllocated + 8;
+ }
+
+
+ NewNameCache = NbiAllocateMemory(
+ sizeof(NETBIOS_CACHE) + ((NewNetworks-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Enlarge cache entry");
+
+ if (NewNameCache == NULL) {
+ return NameCache;
+ }
+
+ NB_DEBUG2 (CACHE, ("Expand cache %lx to %lx for <%.16s>\n",
+ NameCache, NewNameCache, NameCache->NetbiosName));
+
+ //
+ // Copy the new current data to the new one.
+ //
+
+ RtlCopyMemory(
+ NewNameCache,
+ NameCache,
+ sizeof(NETBIOS_CACHE) + ((NameCache->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)));
+
+ NewNameCache->NetworksAllocated = NewNetworks;
+ NewNameCache->ReferenceCount = 1;
+
+ if (ModifyQueue) {
+
+ //
+ // Insert at the same place as the old one. The time
+ // stamp is the same as the old one.
+ //
+
+
+ ReinsertInNetbiosCacheTable( Device->NameCache, NameCache, NewNameCache );
+
+ }
+
+ if (--NameCache->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free replaced cache entry %lx\n", NameCache));
+ NbiFreeMemory(
+ NameCache,
+ sizeof(NETBIOS_CACHE) + ((NameCache->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Enlarge existing");
+
+ }
+
+ NameCache = NewNameCache;
+
+ }
+
+ NameCache->Networks[NameCache->NetworksUsed].Network =
+ SourceAddress->NetworkAddress;
+
+ //
+ // If this packet was not routed to us, then store the local
+ // target for a correct broadcast.
+ //
+
+ if (RtlEqualMemory (RemoteAddress->MacAddress, SourceAddress->NodeAddress, 6)) {
+#if defined(_PNP_POWER)
+ NameCache->Networks[NameCache->NetworksUsed].LocalTarget.NicHandle = RemoteAddress->NicHandle;
+#else
+ NameCache->Networks[NameCache->NetworksUsed].LocalTarget.NicId = RemoteAddress->NicId;
+#endif _PNP_POWER
+ RtlCopyMemory (NameCache->Networks[NameCache->NetworksUsed].LocalTarget.MacAddress, BroadcastAddress, 6);
+ } else {
+ NameCache->Networks[NameCache->NetworksUsed].LocalTarget = *RemoteAddress;
+ }
+
+ ++NameCache->NetworksUsed;
+
+ return NameCache;
+
+} /* CacheUpdateNameCache */
+
+
+VOID
+CacheUpdateFromAddName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN NB_CONNECTIONLESS UNALIGNED * Connectionless,
+ IN BOOLEAN LocalFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when an add name frame is received.
+ If it is for a group name it checks if our cache entry for
+ that group name needs to be updated to include a new network;
+ for all frames it checks if our broadcast cache entry needs
+ to be updated to include a new network.
+
+Arguments:
+
+ RemoteAddress - The address the frame was received from.
+
+ Connectionless - The header of the received add name.
+
+ LocalFrame - TRUE if the frame was sent locally.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PUCHAR NetbiosName;
+ PNETBIOS_CACHE NameCache;
+ PLIST_ENTRY p;
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ NetbiosName = (PUCHAR)Connectionless->NameFrame.Name;
+
+ //
+ // First look up the broadcast name.
+ //
+ // BUGBUG: We should cache a pointer to the cache name
+ // for the broadcast entry, if there is one.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (!LocalFrame) {
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ NetbiosBroadcastName,
+ &NameCache ) == STATUS_SUCCESS ) {
+ //
+ // This will reallocate a cache entry and update the
+ // queue if necessary.
+ //
+
+ (VOID)CacheUpdateNameCache(
+ NameCache,
+ RemoteAddress,
+ (TDI_ADDRESS_IPX UNALIGNED *)(Connectionless->IpxHeader.SourceNetwork),
+ TRUE);
+ }
+
+ }
+
+
+ //
+ // Now see if our database needs to be updated based on this.
+ //
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ Connectionless->NameFrame.Name,
+ &NameCache ) == STATUS_SUCCESS ) {
+
+
+ if (!NameCache->Unique) {
+
+ if (!LocalFrame) {
+
+ //
+ // This will reallocate a cache entry and update the
+ // queue if necessary.
+ //
+
+ (VOID)CacheUpdateNameCache(
+ NameCache,
+ RemoteAddress,
+ (TDI_ADDRESS_IPX UNALIGNED *)(Connectionless->IpxHeader.SourceNetwork),
+ TRUE);
+
+ }
+
+ } else {
+
+ //
+ // To be safe, delete any unique names we get add
+ // names for (we will requery next time we need it).
+ // BUGBUG: Update the database instead -- but then
+ // we may not get the best route??
+ //
+
+ RemoveFromNetbiosCacheTable ( Device->NameCache, NameCache );
+
+ if (--NameCache->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free add named cache entry %lx\n", NameCache));
+ NbiFreeMemory(
+ NameCache,
+ sizeof(NETBIOS_CACHE) + ((NameCache->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Enlarge existing");
+
+ }
+
+ }
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+} /* CacheUpdateFromAddName */
+
+
+VOID
+NbiProcessDeleteName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_DELETE_NAME frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NB_CONNECTIONLESS UNALIGNED * Connectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
+ PUCHAR NetbiosName;
+ PNETBIOS_CACHE CacheName;
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ if (PacketSize != sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME)) {
+ return;
+ }
+
+ //
+ // We want to update our netbios cache to reflect the
+ // fact that this name is no longer valid.
+ //
+
+ NetbiosName = (PUCHAR)Connectionless->NameFrame.Name;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ NetbiosName,
+ &CacheName ) == STATUS_SUCCESS ) {
+
+ //
+ // We don't track group names since we don't know if
+ // this is the last person that owns it. We also drop
+ // the frame if does not come from the person we think
+ // owns this name.
+ //
+
+ if ((!CacheName->Unique) ||
+ (CacheName->NetworksUsed == 0) ||
+ (!RtlEqualMemory (&CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12))) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ NB_DEBUG2 (CACHE, ("Found cache name to delete <%.16s>\n", NetbiosName));
+
+ }else {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+
+ //
+ // We have a cache entry, take it out of the list. If no
+ // one else is using it, delete it; if not, they will delete
+ // it when they are done.
+ //
+
+
+ RemoveFromNetbiosCacheTable ( Device->NameCache, CacheName);
+
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ NB_DEBUG2 (CACHE, ("Free delete name cache entry %lx\n", CacheName));
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Name deleted");
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+} /* NbiProcessDeleteName */
+
+VOID
+InsertInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE CacheEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine inserts a new cache entry in the hash table
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ CacheEntry - Entry to be inserted.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ USHORT HashIndex;
+
+ //
+ // Keep a threshold of how many entries do we keep in the table.
+ // If it crosses the threshold, just remove the oldest entry
+ //
+ if ( CacheTable->CurrentEntries >= CacheTable->MaxHashIndex * NB_MAX_AVG_CACHE_ENTRIES_PER_BUCKET ) {
+ PNETBIOS_CACHE OldestCacheEntry = NULL;
+ PNETBIOS_CACHE NextEntry;
+ PLIST_ENTRY p;
+
+ for ( HashIndex = 0; HashIndex < CacheTable->MaxHashIndex; HashIndex++) {
+ if ( (p = CacheTable->Bucket[ HashIndex ].Blink ) != &CacheTable->Bucket[ HashIndex ] ) {
+ NextEntry = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+
+ if ( OldestCacheEntry ) {
+ if ( NextEntry->TimeStamp < OldestCacheEntry->TimeStamp ) {
+ OldestCacheEntry = NextEntry;
+ }
+ } else {
+ OldestCacheEntry = NextEntry;
+ }
+ }
+ }
+
+ CTEAssert( OldestCacheEntry );
+
+ NB_DEBUG2 (CACHE, ("Threshold exceeded, removing oldest cache entry %lx\n", OldestCacheEntry));
+ RemoveEntryList (&OldestCacheEntry->Linkage);
+ CacheTable->CurrentEntries--;
+
+ if (--OldestCacheEntry->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Freed cache entry %lx\n", OldestCacheEntry));
+
+ NbiFreeMemory(
+ OldestCacheEntry,
+ sizeof(NETBIOS_CACHE) + ((OldestCacheEntry->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Aged out");
+
+ }
+
+ }
+ HashIndex = ( ( CacheEntry->NetbiosName[0] & 0x0f ) << 4 ) + ( CacheEntry->NetbiosName[1] & 0x0f );
+ HashIndex = HashIndex % CacheTable->MaxHashIndex;
+
+ InsertHeadList( &CacheTable->Bucket[HashIndex], &CacheEntry->Linkage );
+ CacheTable->CurrentEntries++;
+} /* InsertInNetbiosCacheTable */
+
+
+__inline
+VOID
+ReinsertInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE OldEntry,
+ IN PNETBIOS_CACHE NewEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine inserts a new cache entry at the same place where
+ the old entry was.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ CacheEntry - Entry to be inserted.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PLIST_ENTRY OldPrevious;
+
+ OldPrevious = OldEntry->Linkage.Blink;
+ RemoveEntryList (&OldEntry->Linkage);
+ InsertHeadList (OldPrevious, &NewEntry->Linkage);
+} /* ReinsertInNetbiosCacheTable */
+
+__inline
+VOID
+RemoveFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE CacheEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes an entry from the cache table.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ CacheEntry - Entry to be removed.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Return Value:
+
+ None.
+--*/
+
+{
+ RemoveEntryList( &CacheEntry->Linkage );
+ CacheTable->CurrentEntries--;
+} /* RemoveFromNetbiosCacheTable */
+
+
+
+VOID
+FlushOldFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN USHORT AgeLimit
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes all the old entries from the hash table.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ AgeLimit - All the entries older than AgeLimit will be removed.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Return Value:
+
+ None.
+--*/
+
+{
+ USHORT HashIndex;
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE CacheName;
+
+ //
+ // run the hash table looking for old entries. Since new entries
+ // are stored at the head and all entries are time stamped when
+ // they are inserted, we scan backwards and stop once we find
+ // an entry which does not need to be aged.
+ // we repeat this for each bucket.
+
+ for ( HashIndex = 0; HashIndex < CacheTable->MaxHashIndex; HashIndex++) {
+ for (p = CacheTable->Bucket[ HashIndex ].Blink;
+ p != &CacheTable->Bucket[ HashIndex ];
+ ) {
+
+ CacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+ p = p->Blink;
+
+ //
+ // see if any entries have been around for more than agelimit
+ //
+
+ if ((USHORT)(NbiDevice->CacheTimeStamp - CacheName->TimeStamp) >= AgeLimit ) {
+
+ RemoveEntryList (&CacheName->Linkage);
+ CacheTable->CurrentEntries--;
+
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Aging out name cache entry %lx\n", CacheName));
+
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Aged out");
+
+ }
+
+ } else {
+
+ break;
+
+ }
+ } // for loop
+ } // for loop
+} /* FlushOldFromNetbiosCacheTable */
+
+VOID
+FlushFailedNetbiosCacheEntries(
+ IN PNETBIOS_CACHE_TABLE CacheTable
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes all the failed entries from the hash table.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Return Value:
+
+ None.
+--*/
+
+{
+ USHORT HashIndex;
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE CacheName;
+
+ //
+ // run the hash table looking for old entries. Since new entries
+ // are stored at the head and all entries are time stamped when
+ // they are inserted, we scan backwards and stop once we find
+ // an entry which does not need to be aged.
+ // we repeat this for each bucket.
+
+ for ( HashIndex = 0; HashIndex < CacheTable->MaxHashIndex; HashIndex++) {
+ for (p = CacheTable->Bucket[ HashIndex ].Blink;
+ p != &CacheTable->Bucket[ HashIndex ];
+ ) {
+
+ CacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+ p = p->Blink;
+
+ //
+ // flush all the failed cache entries.
+ // We do this when a new adapter appears, and there's a possiblity that
+ // the failed entries might succeed now on the new adapter.
+ //
+
+ if (CacheName->NetworksUsed == 0) {
+ RemoveEntryList (&CacheName->Linkage);
+ CacheTable->CurrentEntries--;
+ CTEAssert( CacheName->ReferenceCount == 1 );
+ CTEAssert( CacheName->NetworksAllocated == 1 );
+
+ NB_DEBUG2 (CACHE, ("Flushing out failed name cache entry %lx\n", CacheName));
+
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE),
+ MEMORY_CACHE,
+ "Aged out");
+
+ }
+ } // for loop
+ } // for loop
+} /* FlushFailedNetbiosCacheEntries */
+
+VOID
+RemoveInvalidRoutesFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN NIC_HANDLE UNALIGNED *InvalidNicHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes all invalid route entries from the hash table.
+ Routes become invalid when the binding is deleted in Ipx due to PnP
+ event.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ InvalidRouteNicId - NicId of the invalid routes.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Return Value:
+
+ None.
+--*/
+
+{
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE CacheName;
+ USHORT i,j,NetworksRemoved;
+ USHORT HashIndex;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Flush all the cache entries that are using this NicId in the local
+ // target.
+ //
+
+ for ( HashIndex = 0; HashIndex < Device->NameCache->MaxHashIndex; HashIndex++) {
+ for (p = Device->NameCache->Bucket[ HashIndex ].Flink;
+ p != &Device->NameCache->Bucket[ HashIndex ];
+ ) {
+
+ CacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+ p = p->Flink;
+
+
+ //
+ // Remove each of those routes which is using this NicId.
+ // if no routes left, then flush the cache entry also.
+ // ( unique names have only one route anyways )
+ //
+ for ( i = 0, NetworksRemoved = 0; i < CacheName->NetworksUsed; i++ ) {
+ if ( CacheName->Networks[i].LocalTarget.NicHandle.NicId == InvalidNicHandle->NicId ) {
+ CTEAssert( RtlEqualMemory( &CacheName->Networks[i].LocalTarget.NicHandle, InvalidNicHandle, sizeof(NIC_HANDLE)));
+ for ( j = i+1; j < CacheName->NetworksUsed; j++ ) {
+ CacheName->Networks[j-1] = CacheName->Networks[j];
+ }
+ NetworksRemoved++;
+ } else if ( CacheName->Networks[i].LocalTarget.NicHandle.NicId > InvalidNicHandle->NicId ) {
+ CacheName->Networks[i].LocalTarget.NicHandle.NicId--;
+ }
+ }
+ CTEAssert( NetworksRemoved <= CacheName->NetworksUsed );
+ if ( ! ( CacheName->NetworksUsed -= NetworksRemoved ) ) {
+ RemoveEntryList (&CacheName->Linkage);
+ CacheTable->CurrentEntries--;
+
+ NB_DEBUG2 (CACHE, ("Removed cache entry %lx bcoz route(NicId %d) deleted\n", CacheName, InvalidNicHandle->NicId ));
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Freed name cache entry %lx\n", CacheName));
+
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Aged out");
+
+ }
+ }
+ } // for loop
+ } // for loop
+} /* RemoveInvalidRoutesFromNetbiosCacheTable */
+
+
+NTSTATUS
+FindInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PUCHAR NameToBeFound,
+ OUT PNETBIOS_CACHE *CacheEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine finds a netbios name in the Hash Table and returns
+ the corresponding cache entry.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ CacheEntry - Pointer to the netbios cache entry if found.
+
+Return Value:
+
+ STATUS_SUCCESS - if successful.
+
+ STATUS_UNSUCCESSFUL - otherwise.
+
+--*/
+
+{
+ USHORT HashIndex;
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE FoundCacheName;
+
+
+ HashIndex = ( ( NameToBeFound[0] & 0x0f ) << 4 ) + ( NameToBeFound[1] & 0x0f );
+ HashIndex = HashIndex % CacheTable->MaxHashIndex;
+
+ for (p = ( CacheTable->Bucket[ HashIndex ] ).Flink;
+ p != &CacheTable->Bucket[ HashIndex ];
+ p = p->Flink) {
+
+ FoundCacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+
+ //
+ // See if this entry is for the same name we are looking for.
+
+ if ( RtlEqualMemory (FoundCacheName->NetbiosName, NameToBeFound, 16) ) {
+ *CacheEntry = FoundCacheName;
+ return STATUS_SUCCESS;
+ }
+ }
+
+ return STATUS_UNSUCCESSFUL;
+} /* FindInNetbiosCacheTable */
+
+NTSTATUS
+CreateNetbiosCacheTable(
+ IN OUT PNETBIOS_CACHE_TABLE *NewTable,
+ IN USHORT MaxHashIndex
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a new hash table for netbios cache
+ and initializes it.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Arguments:
+
+ NewTable - The pointer of the table to be created.
+
+ MaxHashIndex - Number of buckets in the hash table.
+
+Return Value:
+
+ STATUS_SUCCESS - if successful.
+
+ STATUS_INSUFFICIENT_RESOURCES - If cannot allocate memory.
+
+--*/
+
+{
+ USHORT i;
+
+ *NewTable = NbiAllocateMemory (sizeof(NETBIOS_CACHE_TABLE) + sizeof(LIST_ENTRY) * ( MaxHashIndex - 1) ,
+ MEMORY_CACHE, "Cache Table");
+
+ if ( *NewTable ) {
+ for ( i = 0; i < MaxHashIndex; i++ ) {
+ InitializeListHead(& (*NewTable)->Bucket[i] );
+ }
+
+ (*NewTable)->MaxHashIndex = MaxHashIndex;
+ (*NewTable)->CurrentEntries = 0;
+ return STATUS_SUCCESS;
+ }
+ else {
+ NB_DEBUG( CACHE, ("Cannot create Netbios Cache Table\n") );
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+} /* CreateNetbiosCacheTable */
+
+
+VOID
+DestroyNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes all entries from the hash table.
+ and free up the hash table.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+Return Value:
+
+ None.
+--*/
+
+{
+ USHORT HashIndex;
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE CacheName;
+
+
+ for ( HashIndex = 0; HashIndex < CacheTable->MaxHashIndex; HashIndex++) {
+ while (!IsListEmpty ( &( CacheTable->Bucket[ HashIndex ] ) ) ) {
+
+ p = RemoveHeadList ( &( CacheTable->Bucket[ HashIndex ] ));
+ CacheTable->CurrentEntries--;
+ CacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+
+ NB_DEBUG2 (CACHE, ("Free cache entry %lx\n", CacheName));
+
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free entries");
+
+ }
+ } // for loop
+
+ CTEAssert( CacheTable->CurrentEntries == 0 );
+
+ NbiFreeMemory (CacheTable, sizeof(NETBIOS_CACHE_TABLE) + sizeof(LIST_ENTRY) * ( CacheTable->MaxHashIndex - 1) ,
+ MEMORY_CACHE, "Free Cache Table");
+
+} /* DestroyNetbiosCacheTable */
+
+
diff --git a/private/ntos/tdi/isn/nb/config.c b/private/ntos/tdi/isn/nb/config.c
new file mode 100644
index 000000000..8689c5d20
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/config.c
@@ -0,0 +1,661 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ config.c
+
+Abstract:
+
+ This contains all routines necessary for the support of the dynamic
+ configuration of the ISN Netbios module.
+
+Author:
+
+ Adam Barr (adamba) 16-November-1993
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Local functions used to access the registry.
+//
+
+NTSTATUS
+NbiGetConfigValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+NbiAddBind(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+NbiAddExport(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+NbiReadLinkageInformation(
+ IN PCONFIG Config
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,NbiGetConfiguration)
+#pragma alloc_text(INIT,NbiFreeConfiguration)
+#pragma alloc_text(INIT,NbiGetConfigValue)
+#pragma alloc_text(INIT,NbiAddBind)
+#pragma alloc_text(INIT,NbiAddExport)
+#pragma alloc_text(INIT,NbiReadLinkageInformation)
+#endif
+
+
+
+NTSTATUS
+NbiGetConfiguration (
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath,
+ OUT PCONFIG * ConfigPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by Netbios to get information from the configuration
+ management routines. We read the registry, starting at RegistryPath,
+ to get the parameters. If they don't exist, we use the defaults
+ set in ipxcnfg.h file. A list of adapters to bind to is chained
+ on to the config information.
+
+Arguments:
+
+ DriverObject - Used for logging errors.
+
+ RegistryPath - The name of Netbios' node in the registry.
+
+ ConfigPtr - Returns the configuration information.
+
+Return Value:
+
+ Status - STATUS_SUCCESS if everything OK, STATUS_INSUFFICIENT_RESOURCES
+ otherwise.
+
+--*/
+{
+ PWSTR RegistryPathBuffer;
+ PCONFIG Config;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[CONFIG_PARAMETERS+2];
+ NTSTATUS Status;
+ ULONG One = 1;
+ ULONG Two = 2;
+ ULONG Three = 3;
+ ULONG Four = 4;
+ ULONG Five = 5;
+ ULONG Eight = 8;
+ ULONG FortyEight = 48;
+ ULONG Sixty = 60;
+ ULONG TwoFifty = 250;
+ ULONG FiveHundred = 500;
+ ULONG MaxMTU = 0xffffffff;
+
+ PWSTR Parameters = L"Parameters";
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[CONFIG_PARAMETERS] = {
+ { L"AckDelayTime", &TwoFifty } , // milliseconds
+ { L"AckWindow", &Two } ,
+ { L"AckWindowThreshold", &FiveHundred } , // milliseconds
+ { L"EnablePiggyBackAck", &One } ,
+ { L"Extensions", &One } ,
+ { L"RcvWindowMax", &Four } ,
+ { L"BroadcastCount", &Three } ,
+ { L"BroadcastTimeout", &One } , // half-seconds
+ { L"ConnectionCount", &Five } ,
+ { L"ConnectionTimeout", &Two } , // half-seconds
+ { L"InitPackets", &Eight } ,
+ { L"MaxPackets", &FortyEight } ,
+ { L"InitialRetransmissionTime", &FiveHundred } , // milliseconds
+ { L"Internet", &One } ,
+ { L"KeepAliveCount", &Eight } ,
+ { L"KeepAliveTimeout", &Sixty } , // half-seconds
+ { L"RetransmitMax", &Eight } ,
+ { L"RouterMTU", &MaxMTU } };
+ UINT i;
+
+
+ //
+ // Allocate memory for the main config structure.
+ //
+
+ Config = NbiAllocateMemory (sizeof(CONFIG), MEMORY_CONFIG, "Config");
+ if (Config == NULL) {
+ NbiWriteResourceErrorLog ((PVOID)DriverObject, sizeof(CONFIG), MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Config->DeviceName.Buffer = NULL;
+ Config->BindName.Buffer = NULL;
+ Config->DriverObject = DriverObject; // save this to log errors
+
+ //
+ // Read in the NDIS binding information (if none is present
+ // the array will be filled with all known drivers).
+ //
+ // NbiReadLinkageInformation expects a null-terminated path,
+ // so we have to create one from the UNICODE_STRING.
+ //
+
+ RegistryPathBuffer = (PWSTR)NbiAllocateMemory(RegistryPath->Length + sizeof(WCHAR),
+ MEMORY_CONFIG, "RegistryPathBuffer");
+ if (RegistryPathBuffer == NULL) {
+ NbiWriteResourceErrorLog ((PVOID)DriverObject, RegistryPath->Length + sizeof(WCHAR), MEMORY_CONFIG);
+ NbiFreeConfiguration(Config);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ RtlCopyMemory (RegistryPathBuffer, RegistryPath->Buffer, RegistryPath->Length);
+ *(PWCHAR)(((PUCHAR)RegistryPathBuffer)+RegistryPath->Length) = (WCHAR)'\0';
+
+ Config->RegistryPathBuffer = RegistryPathBuffer;
+
+
+ //
+ // Determine what name to export and who to bind to.
+ //
+
+ Status = NbiReadLinkageInformation (Config);
+
+ if (Status != STATUS_SUCCESS) {
+
+ //
+ // If it failed it logged an error.
+ //
+
+ NbiFreeConfiguration(Config);
+ return Status;
+ }
+
+
+ //
+ // Read the per-transport (as opposed to per-binding)
+ // parameters.
+ //
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Parameters key below Netbios
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Parameters;
+
+ //
+ // 2-18) Call NbiSetBindingValue for each of the keys we
+ // care about.
+ //
+
+ for (i = 0; i < CONFIG_PARAMETERS; i++) {
+
+ QueryTable[i+1].QueryRoutine = NbiGetConfigValue;
+ QueryTable[i+1].Flags = 0;
+ QueryTable[i+1].Name = ParameterValues[i].KeyName;
+ QueryTable[i+1].EntryContext = (PVOID)i;
+ QueryTable[i+1].DefaultType = REG_DWORD;
+ QueryTable[i+1].DefaultData = (PVOID)(ParameterValues[i].DefaultValue);
+ QueryTable[i+1].DefaultLength = sizeof(ULONG);
+
+ }
+
+ //
+ // 19) Stop
+ //
+
+ QueryTable[CONFIG_PARAMETERS+1].QueryRoutine = NULL;
+ QueryTable[CONFIG_PARAMETERS+1].Flags = 0;
+ QueryTable[CONFIG_PARAMETERS+1].Name = NULL;
+
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+
+ NbiFreeConfiguration(Config);
+ NbiWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 701,
+ Status,
+ Parameters,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ NbiFreeMemory (RegistryPathBuffer, RegistryPath->Length + sizeof(WCHAR), MEMORY_CONFIG, "RegistryPathBuffer");
+ *ConfigPtr = Config;
+
+ return STATUS_SUCCESS;
+
+} /* NbiGetConfiguration */
+
+
+VOID
+NbiFreeConfiguration (
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by Netbios to get free any storage that was allocated
+ by NbiGetConfiguration in producing the specified CONFIG structure.
+
+Arguments:
+
+ Config - A pointer to the configuration information structure.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if (Config->BindName.Buffer) {
+ NbiFreeMemory (Config->BindName.Buffer, Config->BindName.MaximumLength, MEMORY_CONFIG, "BindName");
+ }
+
+ if (Config->DeviceName.Buffer) {
+ NbiFreeMemory (Config->DeviceName.Buffer, Config->DeviceName.MaximumLength, MEMORY_CONFIG, "DeviceName");
+ }
+
+ NbiFreeMemory (Config, sizeof(CONFIG), MEMORY_CONFIG, "Config");
+
+} /* NbiFreeConfig */
+
+
+NTSTATUS
+NbiGetConfigValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each entry in the Parameters
+ node to set the config values. The table is set up
+ so that this function will be called with correct default
+ values for keys that are not present.
+
+Arguments:
+
+ ValueName - The name of the value (ignored).
+
+ ValueType - The type of the value (REG_DWORD -- ignored).
+
+ ValueData - The data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to the CONFIG structure.
+
+ EntryContext - The index in Config->Parameters to save the value.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+ ULONG Data = *(UNALIGNED ULONG *)ValueData;
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+
+ if ((ValueType != REG_DWORD) || (ValueLength != sizeof(ULONG))) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+
+ switch ( (ULONG) EntryContext ) {
+ case CONFIG_ROUTER_MTU:
+ if ( ( Data - sizeof(NB_CONNECTION) - sizeof(IPX_HEADER) ) <= 0 ) {
+ Config->Parameters[CONFIG_ROUTER_MTU] = 0xffffffff;
+ NbiWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 704,
+ STATUS_INVALID_PARAMETER,
+ ValueName,
+ 0,
+ NULL);
+ return STATUS_SUCCESS;
+ }
+ break;
+ default:
+ break;
+ }
+
+ NB_DEBUG2 (CONFIG, ("Config parameter %d, value %lx\n",
+ (ULONG)EntryContext, Data));
+ Config->Parameters[(ULONG)EntryContext] = Data;
+
+ return STATUS_SUCCESS;
+
+} /* NbiGetConfigValue */
+
+
+NTSTATUS
+NbiAddBind(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Bind" multi-string and
+ saves the information in a Config structure.
+
+Arguments:
+
+ ValueName - The name of the value ("Bind" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - A pointer to the Config structure.
+
+ EntryContext - A pointer to a count of binds that is incremented.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+ PULONG ValueReadOk = ((PULONG)EntryContext);
+ PWCHAR NameBuffer;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+
+ if (*ValueReadOk == 0) {
+
+ NB_DEBUG2 (CONFIG, ("Read bind value %ws\n", ValueData));
+
+ NameBuffer = (PWCHAR)NbiAllocateMemory (ValueLength, MEMORY_CONFIG, "BindName");
+ if (NameBuffer == NULL) {
+ NbiWriteResourceErrorLog ((PVOID)Config->DriverObject, ValueLength, MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (NameBuffer, ValueData, ValueLength);
+ Config->BindName.Buffer = NameBuffer;
+ Config->BindName.Length = (USHORT)(ValueLength - sizeof(WCHAR));
+ Config->BindName.MaximumLength = (USHORT)ValueLength;
+
+ //
+ // Set this to ignore any other callbacks and let the
+ // caller know we read something.
+ //
+
+ *ValueReadOk = 1;
+
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbiAddBind */
+
+
+NTSTATUS
+NbiAddExport(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Export" multi-string. It
+ saves the first callback string in the Config structure.
+
+Arguments:
+
+ ValueName - The name of the value ("Export" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - A pointer to the Config structure.
+
+ EntryContext - A pointer to a ULONG that goes to 1 after the
+ first call to this routine (so we know to ignore other ones).
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+ PULONG ValueReadOk = ((PULONG)EntryContext);
+ PWCHAR NameBuffer;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+
+ if (*ValueReadOk == 0) {
+
+ NB_DEBUG2 (CONFIG, ("Read export value %ws\n", ValueData));
+
+ NameBuffer = (PWCHAR)NbiAllocateMemory (ValueLength, MEMORY_CONFIG, "DeviceName");
+ if (NameBuffer == NULL) {
+ NbiWriteResourceErrorLog ((PVOID)Config->DriverObject, ValueLength, MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (NameBuffer, ValueData, ValueLength);
+ Config->DeviceName.Buffer = NameBuffer;
+ Config->DeviceName.Length = (USHORT)(ValueLength - sizeof(WCHAR));
+ Config->DeviceName.MaximumLength = (USHORT)ValueLength;
+
+ //
+ // Set this to ignore any other callbacks and let the
+ // caller know we read something.
+ //
+
+ *ValueReadOk = 1;
+
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbiAddExport */
+
+
+NTSTATUS
+NbiReadLinkageInformation(
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by Netbios to read its linkage information
+ from the registry.
+
+Arguments:
+
+ Config - The config structure which will have per-binding information
+ linked on to it.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[3];
+ PWSTR Subkey = L"Linkage";
+ PWSTR Bind = L"Bind";
+ PWSTR Export = L"Export";
+ ULONG ValueReadOk; // set to TRUE when a value is read correctly
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Linkage key below Netbios
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Subkey;
+
+ //
+ // 1) Call NbiAddExport for each string in "Export"
+ //
+
+ QueryTable[1].QueryRoutine = NbiAddExport;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[1].Name = Export;
+ QueryTable[1].EntryContext = (PVOID)&ValueReadOk;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 2) Stop
+ //
+
+ QueryTable[2].QueryRoutine = NULL;
+ QueryTable[2].Flags = 0;
+ QueryTable[2].Name = NULL;
+
+
+ ValueReadOk = 0;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if ((Status != STATUS_SUCCESS) || (ValueReadOk == 0)) {
+
+ NbiWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 702,
+ Status,
+ Export,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+
+ //
+ // 1) Change to call NbiAddBind for each string in "Bind"
+ //
+
+ QueryTable[1].QueryRoutine = NbiAddBind;
+ QueryTable[1].Flags = 0; // not required
+ QueryTable[1].Name = Bind;
+ QueryTable[1].EntryContext = (PVOID)&ValueReadOk;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ ValueReadOk = 0;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if ((Status != STATUS_SUCCESS) || (ValueReadOk == 0)) {
+
+ NbiWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 703,
+ Status,
+ Bind,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbiReadLinkageInformation */
+
diff --git a/private/ntos/tdi/isn/nb/config.h b/private/ntos/tdi/isn/nb/config.h
new file mode 100644
index 000000000..99b6c6357
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/config.h
@@ -0,0 +1,70 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ config.h
+
+Abstract:
+
+ Private include file for the ISN Netbios module.
+ file defines all constants and structures necessary for support of
+ the dynamic configuration of ST.
+
+Revision History:
+
+--*/
+
+
+//
+// These are used to index into the Parameters array in CONFIG.
+//
+
+#define CONFIG_ACK_DELAY_TIME 0
+#define CONFIG_ACK_WINDOW 1
+#define CONFIG_ACK_WINDOW_THRESHOLD 2
+#define CONFIG_ENABLE_PIGGYBACK_ACK 3
+#define CONFIG_EXTENSIONS 4
+#define CONFIG_RCV_WINDOW_MAX 5
+#define CONFIG_BROADCAST_COUNT 6
+#define CONFIG_BROADCAST_TIMEOUT 7
+#define CONFIG_CONNECTION_COUNT 8
+#define CONFIG_CONNECTION_TIMEOUT 9
+#define CONFIG_INIT_PACKETS 10
+#define CONFIG_MAX_PACKETS 11
+#define CONFIG_INIT_RETRANSMIT_TIME 12
+#define CONFIG_INTERNET 13
+#define CONFIG_KEEP_ALIVE_COUNT 14
+#define CONFIG_KEEP_ALIVE_TIMEOUT 15
+#define CONFIG_RETRANSMIT_MAX 16
+#define CONFIG_ROUTER_MTU 17
+#define CONFIG_PARAMETERS 18
+
+//
+// Main configuration structure.
+//
+
+typedef struct _CONFIG {
+
+ ULONG Parameters[CONFIG_PARAMETERS]; // index defined above
+ NDIS_STRING DeviceName; // device name exported
+ NDIS_STRING BindName; // device to bind to
+ PWSTR RegistryPathBuffer; // path to config info
+ PDRIVER_OBJECT DriverObject; // used for logging errors
+
+} CONFIG, * PCONFIG;
+
+
+NTSTATUS
+NbiGetConfiguration (
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath,
+ OUT PCONFIG * ConfigPtr
+ );
+
+VOID
+NbiFreeConfiguration (
+ IN PCONFIG Config
+ );
+
diff --git a/private/ntos/tdi/isn/nb/connect.c b/private/ntos/tdi/isn/nb/connect.c
new file mode 100644
index 000000000..7ee7204b5
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/connect.c
@@ -0,0 +1,3628 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ connect.c
+
+Abstract:
+
+ This routine contains the code to handle connect requests
+ for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 22-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+#ifdef RASAUTODIAL
+#include <acd.h>
+#include <acdapi.h>
+
+BOOLEAN
+NbiCancelTdiConnect(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest,
+ IN PCONNECTION pConnection
+ );
+#endif // RASAUTODIAL
+
+
+
+VOID
+NbiFindRouteComplete(
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a find route request
+ previously issued to IPX completes.
+
+Arguments:
+
+ FindRouteRequest - The find route request that was issued.
+
+ FoundRoute - TRUE if the route was found.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PDEVICE Device = NbiDevice;
+ UINT i;
+ BOOLEAN LocalRoute;
+ USHORT TickCount;
+ PREQUEST RequestToComplete;
+ PUSHORT Counts;
+ CTELockHandle LockHandle1, LockHandle2;
+ CTELockHandle CancelLH;
+
+ Connection = CONTAINING_RECORD (FindRouteRequest, CONNECTION, FindRouteRequest);
+
+ NB_GET_CANCEL_LOCK(&CancelLH);
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ Connection->FindRouteInProgress = FALSE;
+
+ if (FoundRoute) {
+
+ //
+ // See if the route is local or not (for local routes
+ // we use the real MAC address in the local target, but
+ // the NIC ID may not be what we expect.
+ //
+
+ LocalRoute = TRUE;
+
+ for (i = 0; i < 6; i++) {
+ if (FindRouteRequest->LocalTarget.MacAddress[i] != 0x00) {
+ LocalRoute = FALSE;
+ }
+ }
+
+ if (LocalRoute) {
+
+#if defined(_PNP_POWER)
+ Connection->LocalTarget.NicHandle = FindRouteRequest->LocalTarget.NicHandle;
+#else
+ Connection->LocalTarget.NicId = FindRouteRequest->LocalTarget.NicId;
+#endif _PNP_POWER
+
+ } else {
+
+ Connection->LocalTarget = FindRouteRequest->LocalTarget;
+
+ }
+
+ Counts = (PUSHORT)(&FindRouteRequest->Reserved2);
+ TickCount = Counts[0];
+
+ if (TickCount > 1) {
+
+ //
+ // Each tick is 55 ms, and for our timeout we use 10 ticks
+ // worth (this makes tick count of 1 be about 500 ms, the
+ // default).
+ //
+ // We get 55 milliseconds from
+ //
+ // 1 second * 1000 milliseconds 55 ms
+ // -------- ----------------- = -----
+ // 18.21 ticks 1 second tick
+ //
+
+ Connection->TickCount = TickCount;
+ Connection->BaseRetransmitTimeout = (TickCount * 550) / SHORT_TIMER_DELTA;
+ if (Connection->State != CONNECTION_STATE_ACTIVE) {
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+ }
+ }
+
+ Connection->HopCount = Counts[1];
+
+ }
+
+ //
+ // If the call failed we just use whatever route we had before
+ // (on a connect it will be from the name query response, on
+ // a listen from whatever the incoming connect frame had).
+ //
+
+ if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_C_W_ROUTE)) {
+
+ // we dont need to hold CancelSpinLock so release it,
+ // since we are releasing the locks out of order, we must
+ // swap the irql to get the priorities right.
+
+ NB_SWAP_IRQL( CancelLH, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ //
+ // Continue on with the session init frame.
+ //
+
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_LINE_INFO,
+
+#if defined(_PNP_POWER)
+ &Connection->LocalTarget.NicHandle,
+#else
+ Connection->LocalTarget.NicId,
+#endif _PNP_POWER
+ &Connection->LineInfo,
+ sizeof(IPX_LINE_INFO),
+ NULL);
+
+ // Maximum packet size is the lower of RouterMtu and MaximumSendSize.
+ Connection->MaximumPacketSize = NB_MIN( Device->RouterMtu - sizeof(IPX_HEADER) , Connection->LineInfo.MaximumSendSize ) - sizeof(NB_CONNECTION) ;
+
+ Connection->ReceiveWindowSize = 6;
+ Connection->SendWindowSize = 2;
+ Connection->MaxSendWindowSize = 6; // BUGBUG: Base on what he sent
+
+ //
+ // Don't set RcvSequenceMax yet because we don't know
+ // if the connection is old or new netbios.
+ //
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_W_ACK;
+
+ //
+ // We found a route, we need to start the connect
+ // process by sending out the session initialize
+ // frame. We start the timer to handle retries.
+ //
+ // CTEStartTimer doesn't deal with changing the
+ // expiration time of a running timer, so we have
+ // to stop it first. If we succeed in stopping the
+ // timer, then the CREF_TIMER reference from the
+ // previous starting of the timer remains, so we
+ // don't need to reference the connection again.
+ //
+
+ if (!CTEStopTimer (&Connection->Timer)) {
+ NbiReferenceConnectionLock (Connection, CREF_TIMER);
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ CTEStartTimer(
+ &Connection->Timer,
+ Device->ConnectionTimeout,
+ NbiConnectionTimeout,
+ (PVOID)Connection);
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ NbiSendSessionInitialize (Connection);
+
+ } else if ((Connection->State == CONNECTION_STATE_LISTENING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_L_W_ROUTE)) {
+
+ if (Connection->ListenRequest != NULL) {
+
+ NbiTransferReferenceConnection (Connection, CREF_LISTEN, CREF_ACTIVE);
+ RequestToComplete = Connection->ListenRequest;
+ Connection->ListenRequest = NULL;
+ IoSetCancelRoutine (RequestToComplete, (PDRIVER_CANCEL)NULL);
+
+ } else if (Connection->AcceptRequest != NULL) {
+
+ NbiTransferReferenceConnection (Connection, CREF_ACCEPT, CREF_ACTIVE);
+ RequestToComplete = Connection->AcceptRequest;
+ Connection->AcceptRequest = NULL;
+
+ } else {
+
+ CTEAssert (FALSE);
+ RequestToComplete = NULL;
+
+ }
+
+ // we dont need to hold CancelSpinLock so release it,
+ // since we are releasing the locks out of order, we must
+ // swap the irql to get the priorities right.
+
+ NB_SWAP_IRQL( CancelLH, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_LINE_INFO,
+#if defined(_PNP_POWER)
+ &Connection->LocalTarget.NicHandle,
+#else
+ Connection->LocalTarget.NicId,
+#endif _PNP_POWER
+ &Connection->LineInfo,
+ sizeof(IPX_LINE_INFO),
+ NULL);
+
+
+ // Take the lowest of MaximumPacketSize ( set from the sessionInit
+ // frame ), MaximumSendSize and RouterMtu.
+
+ if (Connection->MaximumPacketSize > Connection->LineInfo.MaximumSendSize - sizeof(NB_CONNECTION)) {
+
+ Connection->MaximumPacketSize = NB_MIN( Device->RouterMtu - sizeof(IPX_HEADER), Connection->LineInfo.MaximumSendSize ) - sizeof(NB_CONNECTION);
+
+ } else {
+
+ // Connection->MaximumPacketSize is what was set by the sender so already
+ // accounts for the header.
+ Connection->MaximumPacketSize = NB_MIN( Device->RouterMtu - sizeof(NB_CONNECTION) - sizeof(IPX_HEADER), Connection->MaximumPacketSize ) ;
+
+ }
+
+ Connection->ReceiveWindowSize = 6;
+ Connection->SendWindowSize = 2;
+ Connection->MaxSendWindowSize = 6; // BUGBUG: Base on what he sent
+
+ if (Connection->NewNetbios) {
+ CTEAssert (Connection->LocalRcvSequenceMax == 4); // should have been set
+ Connection->LocalRcvSequenceMax = Connection->ReceiveWindowSize;
+ }
+
+ Connection->State = CONNECTION_STATE_ACTIVE;
+ Connection->SubState = CONNECTION_SUBSTATE_A_IDLE;
+ Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
+
+ ++Device->Statistics.OpenConnections;
+
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ //
+ // StartWatchdog acquires TimerLock, so we have to
+ // free Lock first.
+ //
+
+
+ NbiStartWatchdog (Connection);
+
+ //
+ // This releases the connection lock, so that SessionInitAckData
+ // can't be freed before it is copied.
+ //
+
+ NbiSendSessionInitAck(
+ Connection,
+ Connection->SessionInitAckData,
+ Connection->SessionInitAckDataLength,
+ &LockHandle1);
+
+ if (RequestToComplete != NULL) {
+
+ REQUEST_STATUS(RequestToComplete) = STATUS_SUCCESS;
+
+ NbiCompleteRequest (RequestToComplete);
+ NbiFreeRequest (Device, RequestToComplete);
+
+ }
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_FIND_ROUTE);
+
+} /* NbiFindRouteComplete */
+
+
+NTSTATUS
+NbiOpenConnection(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to open a connection. Note that the connection that
+ is open is of little use until associated with an address; until then,
+ the only thing that can be done with it is close it.
+
+Arguments:
+
+ Device - Pointer to the device for this driver.
+
+ Request - Pointer to the request representing the open.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PFILE_FULL_EA_INFORMATION ea;
+#ifdef ISN_NT
+ PIRP Irp = (PIRP)Request;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+#endif
+
+ //
+ // First, try to make a connection object to represent this pending
+ // connection. Then fill in the relevant fields.
+ // In addition to the creation, if successful NbfCreateConnection
+ // will create a second reference which is removed once the request
+ // references the connection, or if the function exits before that.
+
+ if (!(Connection = NbiCreateConnection (Device))) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // set the connection context so we can connect the user to this data
+ // structure
+ //
+
+ ea = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+ RtlCopyMemory (
+ &Connection->Context,
+ &ea->EaName[ea->EaNameLength+1],
+ sizeof (PVOID));
+
+ //
+ // let file object point at connection and connection at file object
+ //
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)Connection;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_CONNECTION_FILE;
+#ifdef ISN_NT
+ Connection->FileObject = IrpSp->FileObject;
+#endif
+
+ return STATUS_SUCCESS;
+
+} /* NbiOpenConnection */
+
+
+VOID
+NbiStopConnection(
+ IN PCONNECTION Connection,
+ IN NTSTATUS DisconnectStatus
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to stop an active connection.
+
+ THIS ROUTINE IS CALLED WITH THE CONNECTION LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection to be stopped.
+
+ DisconnectStatus - The reason for the disconnect. One of:
+ STATUS_LINK_FAILED: We timed out trying to probe the remote.
+ STATUS_REMOTE_DISCONNECT: The remote sent a session end.
+ STATUS_LOCAL_DISCONNECT: The local side disconnected.
+ STATUS_CANCELLED: A send or receive on this connection was cancelled.
+ STATUS_INVALID_CONNECTION: The local side closed the connection.
+ STATUS_INVALID_ADDRESS: The local side closed the address.
+
+ LockHandle - The handle which the connection lock was acquired with.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST ListenRequest, AcceptRequest, SendRequest, ReceiveRequest,
+ DisconnectWaitRequest, ConnectRequest;
+ PREQUEST Request, TmpRequest;
+ BOOLEAN DerefForPacketize;
+ BOOLEAN DerefForWaitPacket;
+ BOOLEAN DerefForActive;
+ BOOLEAN DerefForWaitCache;
+ BOOLEAN SendSessionEnd;
+ BOOLEAN ActiveReceive;
+ BOOLEAN IndicateToClient;
+ BOOLEAN ConnectionWasActive;
+ PDEVICE Device = NbiDevice;
+ PADDRESS_FILE AddressFile;
+ NB_DEFINE_LOCK_HANDLE (LockHandle2)
+ NB_DEFINE_LOCK_HANDLE (LockHandle3)
+ CTELockHandle CancelLH;
+
+
+ NB_DEBUG2 (CONNECTION, ("Stop connection %lx (%lx)\n", Connection, DisconnectStatus));
+
+ //
+ // These flags control our actions after we set the state to
+ // DISCONNECT.
+ //
+
+ DerefForPacketize = FALSE;
+ DerefForWaitPacket = FALSE;
+ DerefForActive = FALSE;
+ DerefForWaitCache = FALSE;
+ SendSessionEnd = FALSE;
+ ActiveReceive = FALSE;
+ IndicateToClient = FALSE;
+ ConnectionWasActive = FALSE;
+
+ //
+ // These contain requests or queues of request to complete.
+ //
+
+ ListenRequest = NULL;
+ AcceptRequest = NULL;
+ SendRequest = NULL;
+ ReceiveRequest = NULL;
+ DisconnectWaitRequest = NULL;
+ ConnectRequest = NULL;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ --Device->Statistics.OpenConnections;
+
+ ConnectionWasActive = TRUE;
+
+ Connection->Status = DisconnectStatus;
+
+ if ((DisconnectStatus == STATUS_LINK_FAILED) ||
+ (DisconnectStatus == STATUS_LOCAL_DISCONNECT)) {
+
+ //
+ // Send out session end frames, but fewer if
+ // we timed out.
+ //
+ // BUGBUG: What about STATUS_CANCELLED?
+ //
+
+ Connection->Retries = (DisconnectStatus == STATUS_LOCAL_DISCONNECT) ?
+ Device->ConnectionCount :
+ (Device->ConnectionCount / 2);
+
+ SendSessionEnd = TRUE;
+ Connection->SubState = CONNECTION_SUBSTATE_D_W_ACK;
+
+ //
+ // CTEStartTimer doesn't deal with changing the
+ // expiration time of a running timer, so we have
+ // to stop it first. If we succeed in stopping the
+ // timer, then the CREF_TIMER reference from the
+ // previous starting of the timer remains, so we
+ // don't need to reference the connection again.
+ //
+
+ if (!CTEStopTimer (&Connection->Timer)) {
+ NbiReferenceConnectionLock (Connection, CREF_TIMER);
+ }
+
+ CTEStartTimer(
+ &Connection->Timer,
+ Device->ConnectionTimeout,
+ NbiConnectionTimeout,
+ (PVOID)Connection);
+
+ }
+
+ if (Connection->ReceiveState == CONNECTION_RECEIVE_TRANSFER) {
+ ActiveReceive = TRUE;
+ }
+
+ Connection->State = CONNECTION_STATE_DISCONNECT;
+ DerefForActive = TRUE;
+
+ if (Connection->DisconnectWaitRequest != NULL) {
+ DisconnectWaitRequest = Connection->DisconnectWaitRequest;
+ Connection->DisconnectWaitRequest = NULL;
+ }
+
+ if ((DisconnectStatus == STATUS_LINK_FAILED) ||
+ (DisconnectStatus == STATUS_REMOTE_DISCONNECT) ||
+ (DisconnectStatus == STATUS_CANCELLED)) {
+
+ IndicateToClient = TRUE;
+
+ }
+
+ //
+ // If we are inside NbiAssignSequenceAndSend, add
+ // a reference so the connection won't go away during it.
+ //
+
+ if (Connection->NdisSendsInProgress > 0) {
+ *(Connection->NdisSendReference) = TRUE;
+ NB_DEBUG2 (SEND, ("Adding CREF_NDIS_SEND to %lx\n", Connection));
+ NbiReferenceConnectionLock (Connection, CREF_NDIS_SEND);
+ }
+
+ //
+ // Clean up some other stuff.
+ //
+
+ Connection->ReceiveUnaccepted = 0;
+ Connection->CurrentIndicateOffset = 0;
+
+ //
+ // Update our counters. BUGBUG: Some of these we
+ // never use.
+ //
+
+ switch (DisconnectStatus) {
+
+ case STATUS_LOCAL_DISCONNECT:
+ ++Device->Statistics.LocalDisconnects;
+ break;
+ case STATUS_REMOTE_DISCONNECT:
+ ++Device->Statistics.RemoteDisconnects;
+ break;
+ case STATUS_LINK_FAILED:
+ ++Device->Statistics.LinkFailures;
+ break;
+ case STATUS_IO_TIMEOUT:
+ ++Device->Statistics.SessionTimeouts;
+ break;
+ case STATUS_CANCELLED:
+ ++Device->Statistics.CancelledConnections;
+ break;
+ case STATUS_REMOTE_RESOURCES:
+ ++Device->Statistics.RemoteResourceFailures;
+ break;
+ case STATUS_INVALID_CONNECTION:
+ case STATUS_INVALID_ADDRESS:
+ case STATUS_INSUFFICIENT_RESOURCES:
+ ++Device->Statistics.LocalResourceFailures;
+ break;
+ case STATUS_BAD_NETWORK_PATH:
+ case STATUS_REMOTE_NOT_LISTENING:
+ ++Device->Statistics.NotFoundFailures;
+ break;
+ default:
+ CTEAssert(FALSE);
+ break;
+ }
+
+ } else if (Connection->State == CONNECTION_STATE_CONNECTING) {
+
+ //
+ // There is a connect in progress. We have to find ourselves
+ // in the pending connect queue if we are there.
+ //
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_C_FIND_NAME) {
+ RemoveEntryList (REQUEST_LINKAGE(Connection->ConnectRequest));
+ DerefForWaitCache = TRUE;
+ }
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN) {
+
+ ConnectRequest = Connection->ConnectRequest;
+ Connection->ConnectRequest = NULL;
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ }
+
+ }
+
+
+ //
+ // If we allocated this memory, free it.
+ //
+
+ if (Connection->SessionInitAckDataLength > 0) {
+
+ NbiFreeMemory(
+ Connection->SessionInitAckData,
+ Connection->SessionInitAckDataLength,
+ MEMORY_CONNECTION,
+ "SessionInitAckData");
+ Connection->SessionInitAckData = NULL;
+ Connection->SessionInitAckDataLength = 0;
+
+ }
+
+
+ if (Connection->ListenRequest != NULL) {
+
+ ListenRequest = Connection->ListenRequest;
+ Connection->ListenRequest = NULL;
+ RemoveEntryList (REQUEST_LINKAGE(ListenRequest)); // take out of Device->ListenQueue
+
+ }
+
+ if (Connection->AcceptRequest != NULL) {
+
+ AcceptRequest = Connection->AcceptRequest;
+ Connection->AcceptRequest = NULL;
+
+ }
+
+
+ //
+ // BUGBUG: Do we need to stop the connection timer?
+ // I don't think so.
+ //
+
+
+
+ //
+ // A lot of this we only have to tear down if we were
+ // active before this, because once we are stopping nothing
+ // new will get started. BUGBUG: Some of the other stuff
+ // can be put inside this if also.
+ //
+
+ if (ConnectionWasActive) {
+
+ //
+ // Stop any receives. If there is one that is actively
+ // transferring we leave it and just run down the rest
+ // of the queue. If not, we queue the rest of the
+ // queue on the back of the current one and run
+ // down them all.
+ //
+
+ if (ActiveReceive) {
+
+ ReceiveRequest = Connection->ReceiveQueue.Head;
+
+ //
+ // Connection->ReceiveRequest will get set to NULL
+ // when the transfer completes.
+ //
+
+ } else {
+
+ ReceiveRequest = Connection->ReceiveRequest;
+ if (ReceiveRequest) {
+ REQUEST_SINGLE_LINKAGE (ReceiveRequest) = Connection->ReceiveQueue.Head;
+ } else {
+ ReceiveRequest = Connection->ReceiveQueue.Head;
+ }
+ Connection->ReceiveRequest = NULL;
+
+ }
+
+ Connection->ReceiveQueue.Head = NULL;
+
+
+ if ((Request = Connection->FirstMessageRequest) != NULL) {
+
+ //
+ // If the current request has some sends outstanding, then
+ // we dequeue it from the queue to let it complete when
+ // the sends complete. In that case we set SendRequest
+ // to be the rest of the queue, which will be aborted.
+ // If the current request has no sends, then we put
+ // queue everything to SendRequest to be aborted below.
+ //
+
+#if DBG
+ if (REQUEST_REFCOUNT(Request) > 100) {
+ DbgPrint ("Request %lx (%lx) has high refcount\n",
+ Connection, Request);
+ DbgBreakPoint();
+ }
+#endif
+ if (--REQUEST_REFCOUNT(Request) == 0) {
+
+ //
+ // NOTE: If this is a multi-request message, then
+ // the linkage of Request will already point to the
+ // send queue head, but we don't bother checking.
+ //
+
+ SendRequest = Request;
+ REQUEST_SINGLE_LINKAGE (Request) = Connection->SendQueue.Head;
+
+ } else {
+
+ if (Connection->FirstMessageRequest == Connection->LastMessageRequest) {
+
+ REQUEST_SINGLE_LINKAGE (Request) = NULL;
+
+ } else {
+
+ Connection->SendQueue.Head = REQUEST_SINGLE_LINKAGE (Connection->LastMessageRequest);
+ REQUEST_SINGLE_LINKAGE (Connection->LastMessageRequest) = NULL;
+
+ }
+
+ SendRequest = Connection->SendQueue.Head;
+
+ }
+
+ Connection->FirstMessageRequest = NULL;
+
+ } else {
+
+ //
+ // This may happen if we were sending a probe when a
+ // send was submitted, and the probe timed out.
+ //
+
+ SendRequest = Connection->SendQueue.Head;
+
+ }
+
+ Connection->SendQueue.Head = NULL;
+
+ }
+
+
+ if (Connection->OnWaitPacketQueue) {
+ Connection->OnWaitPacketQueue = FALSE;
+ RemoveEntryList (&Connection->WaitPacketLinkage);
+ DerefForWaitPacket = TRUE;
+ }
+
+ if (Connection->OnPacketizeQueue) {
+ Connection->OnPacketizeQueue = FALSE;
+ RemoveEntryList (&Connection->PacketizeLinkage);
+ DerefForPacketize = TRUE;
+ }
+
+ //
+ // BUGBUG: Should we check if DataAckPending is TRUE and
+ // send an ack??
+ //
+
+ Connection->DataAckPending = FALSE;
+ Connection->PiggybackAckTimeout = FALSE;
+ Connection->ReceivesWithoutAck = 0;
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ //
+ // We can't acquire TimerLock with Lock held, since
+ // we sometimes call ReferenceConnection (which does an
+ // interlocked add using Lock) with TimerLock held.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle3);
+
+ if (Connection->OnShortList) {
+ Connection->OnShortList = FALSE;
+ RemoveEntryList (&Connection->ShortList);
+ }
+
+ if (Connection->OnLongList) {
+ Connection->OnLongList = FALSE;
+ RemoveEntryList (&Connection->LongList);
+ }
+
+ if (Connection->OnDataAckQueue) {
+ Connection->OnDataAckQueue = FALSE;
+ RemoveEntryList (&Connection->DataAckLinkage);
+ Device->DataAckQueueChanged = TRUE;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle3);
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+
+ if (IndicateToClient) {
+
+ AddressFile = Connection->AddressFile;
+
+ if (AddressFile->RegisteredHandler[TDI_EVENT_DISCONNECT]) {
+
+ NB_DEBUG2 (CONNECTION, ("Session end indicated on connection %lx\n", Connection));
+
+ (*AddressFile->DisconnectHandler)(
+ AddressFile->HandlerContexts[TDI_EVENT_DISCONNECT],
+ Connection->Context,
+ 0, // DisconnectData
+ NULL,
+ 0, // DisconnectInformation
+ NULL,
+ TDI_DISCONNECT_RELEASE); // DisconnectReason. BUGBUG: Clean it up?
+
+ }
+
+ }
+
+
+ if (DisconnectWaitRequest != NULL) {
+
+ //
+ // Make the TDI tester happy by returning CONNECTION_RESET
+ // here.
+ //
+
+ if (DisconnectStatus == STATUS_REMOTE_DISCONNECT) {
+ REQUEST_STATUS(DisconnectWaitRequest) = STATUS_CONNECTION_RESET;
+ } else {
+ REQUEST_STATUS(DisconnectWaitRequest) = DisconnectStatus;
+ }
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (DisconnectWaitRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiCompleteRequest (DisconnectWaitRequest);
+ NbiFreeRequest (Device, DisconnectWaitRequest);
+
+ }
+
+ if (ConnectRequest != NULL) {
+
+ REQUEST_STATUS (ConnectRequest) = STATUS_LOCAL_DISCONNECT;
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (ConnectRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiCompleteRequest(ConnectRequest);
+ NbiFreeRequest (Device, ConnectRequest);
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ }
+
+ if (ListenRequest != NULL) {
+
+ REQUEST_INFORMATION(ListenRequest) = 0;
+ REQUEST_STATUS(ListenRequest) = STATUS_LOCAL_DISCONNECT;
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (ListenRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiCompleteRequest (ListenRequest);
+ NbiFreeRequest(Device, ListenRequest);
+
+ NbiDereferenceConnection (Connection, CREF_LISTEN);
+
+ }
+
+ if (AcceptRequest != NULL) {
+
+ REQUEST_INFORMATION(AcceptRequest) = 0;
+ REQUEST_STATUS(AcceptRequest) = STATUS_LOCAL_DISCONNECT;
+
+ NbiCompleteRequest (AcceptRequest);
+ NbiFreeRequest(Device, AcceptRequest);
+
+ NbiDereferenceConnection (Connection, CREF_ACCEPT);
+
+ }
+
+ while (ReceiveRequest != NULL) {
+
+ TmpRequest = REQUEST_SINGLE_LINKAGE (ReceiveRequest);
+
+ REQUEST_STATUS (ReceiveRequest) = DisconnectStatus;
+ REQUEST_INFORMATION (ReceiveRequest) = 0;
+
+ NB_DEBUG2 (RECEIVE, ("StopConnection aborting receive %lx\n", ReceiveRequest));
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (ReceiveRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiCompleteRequest (ReceiveRequest);
+ NbiFreeRequest (Device, ReceiveRequest);
+
+ ++Connection->ConnectionInfo.ReceiveErrors;
+
+ ReceiveRequest = TmpRequest;
+
+ NbiDereferenceConnection (Connection, CREF_RECEIVE);
+
+ }
+
+ while (SendRequest != NULL) {
+
+ TmpRequest = REQUEST_SINGLE_LINKAGE (SendRequest);
+
+ REQUEST_STATUS (SendRequest) = DisconnectStatus;
+ REQUEST_INFORMATION (SendRequest) = 0;
+
+ NB_DEBUG2 (SEND, ("StopConnection aborting send %lx\n", SendRequest));
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (SendRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiCompleteRequest (SendRequest);
+ NbiFreeRequest (Device, SendRequest);
+
+ ++Connection->ConnectionInfo.TransmissionErrors;
+
+ SendRequest = TmpRequest;
+
+ NbiDereferenceConnection (Connection, CREF_SEND);
+
+ }
+
+ if (SendSessionEnd) {
+ NbiSendSessionEnd (Connection);
+ }
+
+ if (DerefForWaitCache) {
+ NbiDereferenceConnection (Connection, CREF_WAIT_CACHE);
+ }
+
+ if (DerefForPacketize) {
+ NbiDereferenceConnection (Connection, CREF_PACKETIZE);
+ }
+
+ if (DerefForWaitPacket) {
+ NbiDereferenceConnection (Connection, CREF_W_PACKET);
+ }
+
+ if (DerefForActive) {
+ NbiDereferenceConnection (Connection, CREF_ACTIVE);
+ }
+
+} /* NbiStopConnection */
+
+
+NTSTATUS
+NbiCloseConnection(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to close a connection.
+
+Arguments:
+
+ Device - Pointer to the device for this driver.
+
+ Request - Pointer to the request representing the open.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ CTELockHandle LockHandle;
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_DEBUG2 (CONNECTION, ("Close connection %lx\n", Connection));
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (Connection->ReferenceCount == 0) {
+
+ //
+ // If we are associated with an address, we need
+ // to simulate a disassociate at this point.
+ //
+
+ if ((Connection->AddressFile != NULL) &&
+ (Connection->AddressFile != (PVOID)-1)) {
+
+ AddressFile = Connection->AddressFile;
+ Connection->AddressFile = (PVOID)-1;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Take this connection out of the address file's list.
+ //
+
+ Address = AddressFile->Address;
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (Connection->AddressFileLinked) {
+ Connection->AddressFileLinked = FALSE;
+ RemoveEntryList (&Connection->AddressFileLinkage);
+ }
+
+ //
+ // We are done.
+ //
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ Connection->AddressFile = NULL;
+
+ //
+ // Clean up the reference counts and complete any
+ // disassociate requests that pended.
+ //
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ }
+
+ //
+ // Even if the ref count is zero and some thread has already done cleanup,
+ // we can not destroy the connection bcoz some other thread might still be
+ // in HandleConnectionZero routine. This could happen when 2 threads call into
+ // HandleConnectionZero, one thread runs thru completion, close comes along
+ // and the other thread is still in HandleConnectionZero routine.
+ //
+
+ if ( Connection->CanBeDestroyed && ( Connection->ThreadsInHandleConnectionZero == 0 ) ) {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ NbiDestroyConnection(Connection);
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ Connection->ClosePending = Request;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ Status = STATUS_PENDING;
+
+ }
+
+ } else {
+
+ Connection->ClosePending = Request;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ Status = STATUS_PENDING;
+
+ }
+
+ return Status;
+
+} /* NbiCloseConnection */
+
+
+NTSTATUS
+NbiTdiAssociateAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the association of the connection and
+ the address for the user.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the associate.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+#ifdef ISN_NT
+ PFILE_OBJECT FileObject;
+#endif
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PTDI_REQUEST_KERNEL_ASSOCIATE Parameters;
+ CTELockHandle LockHandle;
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+
+ //
+ // The request request parameters hold
+ // get a pointer to the address FileObject, which points us to the
+ // transport's address object, which is where we want to put the
+ // connection.
+ //
+
+ Parameters = (PTDI_REQUEST_KERNEL_ASSOCIATE)REQUEST_PARAMETERS(Request);
+
+#ifdef ISN_NT
+
+ Status = ObReferenceObjectByHandle (
+ Parameters->AddressHandle,
+ 0L,
+ 0,
+ KernelMode,
+ (PVOID *)&FileObject,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+ return Status;
+ }
+
+ AddressFile = (PADDRESS_FILE)(FileObject->FsContext);
+
+#else
+
+ //
+ // I don't know how this works in a VxD.
+ //
+
+ AddressFile = (PADDRESS_FILE)(Parameters->AddressHandle);
+
+#endif
+
+ //
+ // Make sure the address file is valid, and reference it.
+ //
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_NOT_OK);
+#else
+ Status = NbiVerifyAddressFile (AddressFile);
+#endif _PNP_POWER
+
+ if (!NT_SUCCESS(Status)) {
+
+#ifdef ISN_NT
+ ObDereferenceObject (FileObject);
+#endif
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+ return Status;
+ }
+
+ NB_DEBUG2 (CONNECTION, ("Associate connection %lx with address file %lx\n",
+ Connection, AddressFile));
+
+
+ //
+ // Now insert the connection into the database of the address.
+ //
+
+ Address = AddressFile->Address;
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (Connection->AddressFile != NULL) {
+
+ //
+ // The connection is already associated with
+ // an address file.
+ //
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ Status = STATUS_INVALID_CONNECTION;
+
+ } else {
+
+ if (AddressFile->State == ADDRESSFILE_STATE_OPEN) {
+
+ Connection->AddressFile = AddressFile;
+ Connection->AddressFileLinked = TRUE;
+ InsertHeadList (&AddressFile->ConnectionDatabase, &Connection->AddressFileLinkage);
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ NbiTransferReferenceAddressFile (AddressFile, AFREF_VERIFY, AFREF_CONNECTION);
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ Status = STATUS_INVALID_ADDRESS;
+ }
+
+ }
+
+#ifdef ISN_NT
+
+ //
+ // We don't need the reference to the file object, we just
+ // used it to get from the handle to the object.
+ //
+
+ ObDereferenceObject (FileObject);
+
+#endif
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiAssociateAddress */
+
+
+NTSTATUS
+NbiTdiDisassociateAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the disassociation of the connection
+ and the address for the user.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the associate.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ NTSTATUS Status;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ CTELockHandle LockHandle;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ NB_DEBUG2 (CONNECTION, ("Disassociate connection %lx\n", Connection));
+
+
+ //
+ // First check if the connection is still active.
+ //
+
+ NB_BEGIN_SYNC (&SyncContext);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ if (Connection->State != CONNECTION_STATE_INACTIVE) {
+
+ //
+ // This releases the lock.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_INVALID_ADDRESS
+ NB_LOCK_HANDLE_ARG (LockHandle1));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ }
+
+ //
+ // BUGBUG: Keep the sync through the function??
+ //
+
+ NB_END_SYNC (&SyncContext);
+
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ //
+ // Make sure the connection is associated and is not in the
+ // middle of disassociating.
+ //
+
+ if ((Connection->AddressFile != NULL) &&
+ (Connection->AddressFile != (PVOID)-1) &&
+ (Connection->DisassociatePending == NULL)) {
+
+ if (Connection->ReferenceCount == 0) {
+
+ //
+ // Because the connection still has a reference to
+ // the address file, we know it is still valid. We
+ // set the connection address file to the temporary
+ // value of -1, which prevents somebody else from
+ // disassociating it and also prevents a new association.
+ //
+
+ AddressFile = Connection->AddressFile;
+ Connection->AddressFile = (PVOID)-1;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ Address = AddressFile->Address;
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (Connection->AddressFileLinked) {
+ Connection->AddressFileLinked = FALSE;
+ RemoveEntryList (&Connection->AddressFileLinkage);
+ }
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ Connection->AddressFile = NULL;
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ //
+ // Set this so when the count goes to 0 it will
+ // be disassociated and the request completed.
+ //
+
+ Connection->DisassociatePending = Request;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ Status = STATUS_PENDING;
+
+ }
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiDisassociateAddress */
+
+
+NTSTATUS
+NbiTdiListen(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine posts a listen on a connection.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the listen.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1, LockHandle2;
+ CTELockHandle CancelLH;
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ //
+ // The connection must be inactive, but associated and
+ // with no disassociate or close pending.
+ //
+
+ if ((Connection->State == CONNECTION_STATE_INACTIVE) &&
+ (Connection->AddressFile != NULL) &&
+ (Connection->AddressFile != (PVOID)-1) &&
+ (Connection->DisassociatePending == NULL) &&
+ (Connection->ClosePending == NULL)) {
+
+ Connection->State = CONNECTION_STATE_LISTENING;
+ Connection->SubState = CONNECTION_SUBSTATE_L_WAITING;
+
+ (VOID)NbiAssignConnectionId (Device, Connection); // BUGBUG: Check return code.
+
+
+ if (!Request->Cancel) {
+
+ NB_DEBUG2 (CONNECTION, ("Queued listen %lx on %lx\n", Request, Connection));
+ InsertTailList (&Device->ListenQueue, REQUEST_LINKAGE(Request));
+ IoSetCancelRoutine (Request, NbiCancelListen);
+ Connection->ListenRequest = Request;
+ NbiReferenceConnectionLock (Connection, CREF_LISTEN);
+ Status = STATUS_PENDING;
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled listen %lx on %lx\n", Request, Connection));
+ Connection->State = CONNECTION_STATE_INACTIVE;
+ Status = STATUS_CANCELLED;
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiListen */
+
+
+NTSTATUS
+NbiTdiAccept(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine accepts a connection to a remote machine. The
+ connection must previously have completed a listen with
+ the TDI_QUERY_ACCEPT flag on.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the accept.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1, LockHandle2;
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if ((Connection->State == CONNECTION_STATE_LISTENING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_L_W_ACCEPT)) {
+
+ Connection->SubState = CONNECTION_SUBSTATE_L_W_ROUTE;
+
+ NbiTransferReferenceConnection (Connection, CREF_W_ACCEPT, CREF_ACCEPT);
+ Connection->AcceptRequest = Request;
+
+ NbiReferenceConnectionLock (Connection, CREF_FIND_ROUTE);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network =
+ *(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,Connection->RemoteHeader.DestinationNode,6);
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_NO_RIP;
+
+ //
+ // When this completes, we will send the session init
+ // ack. We don't call it if the client is for network 0,
+ // instead just fake as if no route could be found
+ // and we will use the local target we got here.
+ // The accept is completed when this completes.
+ //
+
+ if (*(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork != 0) {
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ } else {
+
+ NbiFindRouteComplete(
+ &Connection->FindRouteRequest,
+ FALSE);
+
+ }
+
+ NB_DEBUG2 (CONNECTION, ("Accept received on %lx\n", Connection));
+
+ Status = STATUS_PENDING;
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Accept received on invalid connection %lx\n", Connection));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiAccept */
+
+
+NTSTATUS
+NbiTdiConnect(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine connects to a remote machine.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the connect.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteName;
+ PTDI_REQUEST_KERNEL_CONNECT Parameters;
+#if 0
+ PLARGE_INTEGER RequestedTimeout;
+ LARGE_INTEGER RealTimeout;
+#endif
+ PNETBIOS_CACHE CacheName;
+ CTELockHandle LockHandle1, LockHandle2;
+ CTELockHandle CancelLH;
+ BOOLEAN bLockFreed = FALSE;
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ //
+ // The connection must be inactive, but associated and
+ // with no disassociate or close pending.
+ //
+
+ if ((Connection->State == CONNECTION_STATE_INACTIVE) &&
+ (Connection->AddressFile != NULL) &&
+ (Connection->AddressFile != (PVOID)-1) &&
+ (Connection->DisassociatePending == NULL) &&
+ (Connection->ClosePending == NULL)) {
+
+ Parameters = (PTDI_REQUEST_KERNEL_CONNECT)REQUEST_PARAMETERS(Request);
+ RemoteName = NbiParseTdiAddress((PTRANSPORT_ADDRESS)(Parameters->RequestConnectionInformation->RemoteAddress), FALSE);
+
+ if (RemoteName == NULL) {
+
+ //
+ // There is no netbios remote address specified.
+ //
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ Status = STATUS_BAD_NETWORK_PATH;
+
+ } else {
+
+ NbiReferenceConnectionLock (Connection, CREF_CONNECT);
+ Connection->State = CONNECTION_STATE_CONNECTING;
+ RtlCopyMemory (Connection->RemoteName, RemoteName->NetbiosName, 16);
+
+ Connection->Retries = Device->ConnectionCount;
+
+ (VOID)NbiAssignConnectionId (Device, Connection); // BUGBUG: Check return code.
+
+ Status = NbiTdiConnectFindName(
+ Device,
+ Request,
+ Connection,
+ CancelLH,
+ LockHandle1,
+ LockHandle2,
+ &bLockFreed);
+
+ }
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Connect on invalid connection %lx\n", Connection));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ if (!bLockFreed) {
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ }
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiConnect */
+
+
+NTSTATUS
+NbiTdiConnectFindName(
+ IN PDEVICE Device,
+ IN PREQUEST Request,
+ IN PCONNECTION Connection,
+ IN CTELockHandle CancelLH,
+ IN CTELockHandle ConnectionLH,
+ IN CTELockHandle DeviceLH,
+ IN PBOOLEAN pbLockFreed
+ )
+{
+ NTSTATUS Status;
+ PNETBIOS_CACHE CacheName;
+
+ //
+ // See what is up with this Netbios name.
+ //
+
+ Status = CacheFindName(
+ Device,
+ FindNameConnect,
+ Connection->RemoteName,
+ &CacheName);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A request for routes to this name has been
+ // sent out on the net, we queue up this connect
+ // request and processing will be resumed when
+ // we get a response.
+ //
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_FIND_NAME;
+
+
+ if (!Request->Cancel) {
+
+ InsertTailList( &Device->WaitingConnects, REQUEST_LINKAGE(Request));
+ IoSetCancelRoutine (Request, NbiCancelConnectFindName);
+ Connection->ConnectRequest = Request;
+ NbiReferenceConnectionLock (Connection, CREF_WAIT_CACHE);
+ NB_DEBUG2 (CONNECTION, ("Queueing up connect %lx on %lx\n",
+ Request, Connection));
+
+ NB_FREE_LOCK (&Device->Lock, DeviceLH);
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled connect %lx on %lx\n", Request, Connection));
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ NB_FREE_LOCK (&Device->Lock, DeviceLH);
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ Status = STATUS_CANCELLED;
+ }
+
+ } else if (Status == STATUS_SUCCESS) {
+
+ //
+ // We don't need to worry about referencing CacheName
+ // because we stop using it before we release the lock.
+ //
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_W_ROUTE;
+
+
+ if (!Request->Cancel) {
+
+ IoSetCancelRoutine (Request, NbiCancelConnectWaitResponse);
+
+ // we dont need to hold CancelSpinLock so release it,
+ // since we are releasing the locks out of order, we must
+ // swap the irql to get the priorities right.
+
+ NB_SWAP_IRQL( CancelLH, ConnectionLH);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ Connection->LocalTarget = CacheName->Networks[0].LocalTarget;
+ RtlCopyMemory(&Connection->RemoteHeader.DestinationNetwork, &CacheName->FirstResponse, 12);
+
+ Connection->ConnectRequest = Request;
+ NbiReferenceConnectionLock (Connection, CREF_FIND_ROUTE);
+
+ NB_DEBUG2 (CONNECTION, ("Found connect cached %lx on %lx\n",
+ Request, Connection));
+
+ NB_FREE_LOCK (&Device->Lock, DeviceLH);
+ NB_FREE_LOCK (&Connection->Lock, ConnectionLH);
+
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network = CacheName->FirstResponse.NetworkAddress;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,CacheName->FirstResponse.NodeAddress,6);
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_RIP_IF_NEEDED;
+
+ //
+ // When this completes, we will send the session init.
+ // We don't call it if the client is for network 0,
+ // instead just fake as if no route could be found
+ // and we will use the local target we got here.
+ //
+
+ if (CacheName->FirstResponse.NetworkAddress != 0) {
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ } else {
+
+ NbiFindRouteComplete(
+ &Connection->FindRouteRequest,
+ FALSE);
+
+ }
+
+ Status = STATUS_PENDING;
+
+ //
+ // This jump is like falling out of the if, except
+ // it skips over freeing the connection lock since
+ // we just did that.
+ //
+
+ *pbLockFreed = TRUE;
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled connect %lx on %lx\n", Request, Connection));
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+ NB_FREE_LOCK (&Device->Lock, DeviceLH);
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ Status = STATUS_CANCELLED;
+ }
+
+ } else {
+
+ //
+ // We could not find or queue a request for
+ // this remote, fail it. When the refcount
+ // drops the state will go to INACTIVE and
+ // the connection ID will be deassigned.
+ //
+
+ if (Status == STATUS_DEVICE_DOES_NOT_EXIST) {
+ Status = STATUS_BAD_NETWORK_PATH;
+ }
+
+ NB_FREE_LOCK (&Device->Lock, DeviceLH);
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+ }
+
+ return Status;
+} /* NbiTdiConnectFindName */
+
+
+NTSTATUS
+NbiTdiDisconnect(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine connects to a remote machine.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the connect.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+ BOOLEAN DisconnectWait;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+ NB_DEFINE_LOCK_HANDLE (LockHandle2)
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+ CTELockHandle CancelLH;
+
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ DisconnectWait = (BOOLEAN)
+ ((((PTDI_REQUEST_KERNEL_DISCONNECT)(REQUEST_PARAMETERS(Request)))->RequestFlags &
+ TDI_DISCONNECT_WAIT) != 0);
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+
+ //
+ // We need to be inside a sync because NbiStopConnection
+ // expects that.
+ //
+
+ NB_BEGIN_SYNC (&SyncContext);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if (DisconnectWait) {
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ //
+ // This disconnect wait will get completed by
+ // NbiStopConnection.
+ //
+
+ if (Connection->DisconnectWaitRequest == NULL) {
+
+
+ if (!Request->Cancel) {
+
+ IoSetCancelRoutine (Request, NbiCancelDisconnectWait);
+ NB_DEBUG2 (CONNECTION, ("Disconnect wait queued on connection %lx\n", Connection));
+ Connection->DisconnectWaitRequest = Request;
+ Status = STATUS_PENDING;
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled disconnect wait on connection %lx\n", Connection));
+ Status = STATUS_CANCELLED;
+ }
+
+ } else {
+
+ //
+ // We got a second disconnect request and we already
+ // have one pending.
+ //
+
+ NB_DEBUG (CONNECTION, ("Disconnect wait failed, already queued on connection %lx\n", Connection));
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ } else if (Connection->State == CONNECTION_STATE_DISCONNECT) {
+
+ NB_DEBUG (CONNECTION, ("Disconnect wait submitted on disconnected connection %lx\n", Connection));
+ Status = Connection->Status;
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Disconnect wait failed, bad state on connection %lx\n", Connection));
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ } else {
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ // we dont need to hold CancelSpinLock so release it,
+ // since we are releasing the locks out of order, we must
+ // swap the irql to get the priorities right.
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ Connection->DisconnectRequest = Request;
+ Status = STATUS_PENDING;
+
+ NB_DEBUG2 (CONNECTION, ("Disconnect of active connection %lx\n", Connection));
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+
+ //
+ // This call releases the connection lock, sets
+ // the state to DISCONNECTING, and sends out
+ // the first session end.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_LOCAL_DISCONNECT
+ NB_LOCK_HANDLE_ARG (LockHandle1));
+
+ } else if (Connection->State == CONNECTION_STATE_DISCONNECT) {
+
+ //
+ // There is already a disconnect pending. Queue
+ // this one up so it completes when the refcount
+ // goes to zero.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Disconnect of disconnecting connection %lx\n", Connection));
+
+ if (Connection->DisconnectRequest == NULL) {
+ Connection->DisconnectRequest = Request;
+ Status = STATUS_PENDING;
+ } else {
+ Status = STATUS_SUCCESS;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ } else if ((Connection->State == CONNECTION_STATE_LISTENING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_L_W_ACCEPT)) {
+
+ //
+ // We were waiting for an accept, but instead we got
+ // a disconnect. Remove the reference and the teardown
+ // will proceed. The disconnect will complete when the
+ // refcount goes to zero.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Disconnect of accept pending connection %lx\n", Connection));
+
+ if (Connection->DisconnectRequest == NULL) {
+ Connection->DisconnectRequest = Request;
+ Status = STATUS_PENDING;
+ } else {
+ Status = STATUS_SUCCESS;
+ }
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiDereferenceConnection (Connection, CREF_W_ACCEPT);
+
+ } else if (Connection->State == CONNECTION_STATE_CONNECTING) {
+
+ // we dont need to hold CancelSpinLock so release it,
+ // since we are releasing the locks out of order, we must
+ // swap the irql to get the priorities right.
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ //
+ // We are connecting, and got a disconnect. We call
+ // NbiStopConnection which will handle this case
+ // and abort the connect.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Disconnect of connecting connection %lx\n", Connection));
+
+ if (Connection->DisconnectRequest == NULL) {
+ Connection->DisconnectRequest = Request;
+ Status = STATUS_PENDING;
+ } else {
+ Status = STATUS_SUCCESS;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ //
+ // This call releases the connection lock and
+ // aborts the connect request.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_LOCAL_DISCONNECT
+ NB_LOCK_HANDLE_ARG (LockHandle1));
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Disconnect of invalid connection (%d) %lx\n",
+ Connection->State, Connection));
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ }
+
+ NB_END_SYNC (&SyncContext);
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiDisconnect */
+
+
+BOOLEAN
+NbiAssignConnectionId(
+ IN PDEVICE Device,
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to assign a connection ID. It picks
+ one whose hash table has the fewest entries.
+
+ THIS ROUTINE IS CALLED WITH THE LOCK HELD AND RETURNS WITH
+ IT HELD. THE CONNECTION IS INSERTED INTO THE CORRECT HASH
+ ENTRY BY THIS CALL.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Connection - The connection that needs an ID assigned.
+
+Return Value:
+
+ TRUE if it could be successfully assigned.
+
+--*/
+
+{
+ UINT Hash;
+ UINT i;
+ USHORT ConnectionId, HashId;
+ PCONNECTION CurConnection;
+
+
+ CTEAssert (Connection->LocalConnectionId == 0xffff);
+
+ //
+ // Find the hash bucket with the fewest entries.
+ //
+
+ Hash = 0;
+ for (i = 1; i < CONNECTION_HASH_COUNT; i++) {
+ if (Device->ConnectionHash[i].ConnectionCount < Device->ConnectionHash[Hash].ConnectionCount) {
+ Hash = i;
+ }
+ }
+
+
+ //
+ // Now find a valid connection ID within that bucket.
+ //
+
+ ConnectionId = Device->ConnectionHash[Hash].NextConnectionId;
+
+ while (TRUE) {
+
+ //
+ // Scan through the list to see if this ID is in use.
+ //
+
+ HashId = (USHORT)(ConnectionId | (Hash << CONNECTION_HASH_SHIFT));
+
+ CurConnection = Device->ConnectionHash[Hash].Connections;
+
+ while (CurConnection != NULL) {
+ if (CurConnection->LocalConnectionId != HashId) {
+ CurConnection = CurConnection->NextConnection;
+ } else {
+ break;
+ }
+ }
+
+ if (CurConnection == NULL) {
+ break;
+ }
+
+ if (ConnectionId >= CONNECTION_MAXIMUM_ID) {
+ ConnectionId = 1;
+ } else {
+ ++ConnectionId;
+ }
+
+ //
+ // BUGBUG: What if we have 64K-1 sessions and loop forever?
+ //
+ }
+
+ if (Device->ConnectionHash[Hash].NextConnectionId >= CONNECTION_MAXIMUM_ID) {
+ Device->ConnectionHash[Hash].NextConnectionId = 1;
+ } else {
+ ++Device->ConnectionHash[Hash].NextConnectionId;
+ }
+
+ Connection->LocalConnectionId = HashId;
+ Connection->RemoteConnectionId = 0xffff;
+ NB_DEBUG2 (CONNECTION, ("Assigned ID %lx to %x\n", Connection->LocalConnectionId, Connection));
+
+ Connection->NextConnection = Device->ConnectionHash[Hash].Connections;
+ Device->ConnectionHash[Hash].Connections = Connection;
+ ++Device->ConnectionHash[Hash].ConnectionCount;
+
+ return TRUE;
+
+} /* NbiAssignConnectionId */
+
+
+VOID
+NbiDeassignConnectionId(
+ IN PDEVICE Device,
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to deassign a connection ID. It removes
+ the connection from the hash bucket for its ID.
+
+ THIS ROUTINE IS CALLED WITH THE LOCK HELD AND RETURNS WITH
+ IT HELD.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Connection - The connection that needs an ID assigned.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT Hash;
+ PCONNECTION CurConnection;
+ PCONNECTION * PrevConnection;
+
+ //
+ // Make sure the connection has a valid ID.
+ //
+
+ CTEAssert (Connection->LocalConnectionId != 0xffff);
+
+ Hash = (Connection->LocalConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
+
+ CurConnection = Device->ConnectionHash[Hash].Connections;
+ PrevConnection = &Device->ConnectionHash[Hash].Connections;
+
+ while (TRUE) {
+
+ CTEAssert (CurConnection != NULL);
+
+ //
+ // We can loop until we find it because it should be
+ // on here.
+ //
+
+ if (CurConnection == Connection) {
+ *PrevConnection = Connection->NextConnection;
+ --Device->ConnectionHash[Hash].ConnectionCount;
+ break;
+ }
+
+ PrevConnection = &CurConnection->NextConnection;
+ CurConnection = CurConnection->NextConnection;
+
+ }
+
+ Connection->LocalConnectionId = 0xffff;
+
+} /* NbiDeassignConnectionId */
+
+
+VOID
+NbiConnectionTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the connection timer expires.
+ This is either because we need to send the next session
+ initialize, or because our listen has timed out.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCONNECTION Connection = (PCONNECTION)Context;
+ PDEVICE Device = NbiDevice;
+ PREQUEST Request;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_LOCK_HANDLE (CancelLH)
+
+ //
+ // Take the lock and see what we need to do.
+ //
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN)) {
+
+ if (--Connection->Retries == 0) {
+
+ NB_DEBUG2 (CONNECTION, ("Timing out session initializes on %lx\n", Connection));
+
+ //
+ // We have just timed out this connect, we fail the
+ // request. When the reference count goes to 0 we
+ // will set the state to INACTIVE and deassign
+ // the connection ID.
+ //
+
+ Request = Connection->ConnectRequest;
+ Connection->ConnectRequest = NULL;
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ REQUEST_STATUS (Request) = STATUS_BAD_NETWORK_PATH;
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+
+ } else {
+
+ //
+ // Send the next session initialize.
+ //
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NbiSendSessionInitialize (Connection);
+
+ CTEStartTimer(
+ &Connection->Timer,
+ Device->ConnectionTimeout,
+ NbiConnectionTimeout,
+ (PVOID)Connection);
+
+ }
+
+ } else if (Connection->State == CONNECTION_STATE_DISCONNECT) {
+
+ if ((Connection->SubState != CONNECTION_SUBSTATE_D_W_ACK) ||
+ (--Connection->Retries == 0)) {
+
+ NB_DEBUG2 (CONNECTION, ("Timing out disconnect of %lx\n", Connection));
+
+ //
+ // Just dereference the connection, that will cause the
+ // disconnect to be completed, the state to be set
+ // to INACTIVE, and our connection ID deassigned.
+ //
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+
+ } else {
+
+ //
+ // Send the next session end.
+ //
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NbiSendSessionEnd(Connection);
+
+ CTEStartTimer(
+ &Connection->Timer,
+ Device->ConnectionTimeout,
+ NbiConnectionTimeout,
+ (PVOID)Connection);
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+
+ }
+
+} /* NbiConnectionTimeout */
+
+
+VOID
+NbiCancelListen(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a posted
+ listen.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1, LockHandle2;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PREQUEST Request = (PREQUEST)Irp;
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_LISTEN));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ if ((Connection->State == CONNECTION_STATE_LISTENING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_L_WAITING) &&
+ (Connection->ListenRequest == Request)) {
+
+ //
+ // When the reference count goes to 0, we will set the
+ // state to INACTIVE and deassign the connection ID.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled listen on %lx\n", Connection));
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+ Connection->ListenRequest = NULL;
+ RemoveEntryList (REQUEST_LINKAGE(Request));
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest(Device, Request);
+
+ NbiDereferenceConnection (Connection, CREF_LISTEN);
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Cancel listen on invalid connection %lx\n", Connection));
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ }
+
+} /* NbiCancelListen */
+
+
+VOID
+NbiCancelConnectFindName(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a connect
+ request which is waiting for the name to be found.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1, LockHandle2;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PREQUEST Request = (PREQUEST)Irp;
+ PLIST_ENTRY p;
+ BOOLEAN fCanceled = TRUE;
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_CONNECT));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_C_FIND_NAME) &&
+ (Connection->ConnectRequest == Request)) {
+
+ //
+ // Make sure the request is still on the queue
+ // before cancelling it.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ for (p = Device->WaitingConnects.Flink;
+ p != &Device->WaitingConnects;
+ p = p->Flink) {
+
+ if (LIST_ENTRY_TO_REQUEST(p) == Request) {
+ break;
+ }
+ }
+
+ if (p != &Device->WaitingConnects) {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled find name connect on %lx\n", Connection));
+
+ //
+ // When the reference count goes to 0, we will set the
+ // state to INACTIVE and deassign the connection ID.
+ //
+
+ Connection->ConnectRequest = NULL;
+ RemoveEntryList (REQUEST_LINKAGE(Request));
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+#ifdef RASAUTODIAL
+ if (Connection->Flags & CONNECTION_FLAGS_AUTOCONNECTING)
+ fCanceled = NbiCancelTdiConnect(Device, Request, Connection);
+#endif // RASAUTODIAL
+
+ if (fCanceled) {
+ NbiCompleteRequest (Request);
+ NbiFreeRequest(Device, Request);
+ }
+
+ NbiDereferenceConnection (Connection, CREF_WAIT_CACHE);
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Cancel connect not found on queue %lx\n", Connection));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ }
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Cancel connect on invalid connection %lx\n", Connection));
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ }
+
+} /* NbiCancelConnectFindName */
+
+
+VOID
+NbiCancelConnectWaitResponse(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a connect
+ request which is waiting for a rip or session init response
+ from the remote.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PREQUEST Request = (PREQUEST)Irp;
+ BOOLEAN TimerWasStopped = FALSE;
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_CONNECT));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN) &&
+ (Connection->ConnectRequest == Request)) {
+
+ //
+ // When the reference count goes to 0, we will set the
+ // state to INACTIVE and deassign the connection ID.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled wait response connect on %lx\n", Connection));
+
+ Connection->ConnectRequest = NULL;
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ if (CTEStopTimer (&Connection->Timer)) {
+ TimerWasStopped = TRUE;
+ }
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest(Device, Request);
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ if (TimerWasStopped) {
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+ }
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Cancel connect on invalid connection %lx\n", Connection));
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ }
+
+} /* NbiCancelConnectWaitResponse */
+
+
+VOID
+NbiCancelDisconnectWait(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a posted
+ disconnect wait.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1, LockHandle2;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PREQUEST Request = (PREQUEST)Irp;
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_DISCONNECT));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if (Connection->DisconnectWaitRequest == Request) {
+
+ Connection->DisconnectWaitRequest = NULL;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest(Device, Request);
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ }
+
+} /* NbiCancelDisconnectWait */
+
+
+PCONNECTION
+NbiLookupConnectionByContext(
+ IN PADDRESS_FILE AddressFile,
+ IN CONNECTION_CONTEXT ConnectionContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine looks up a connection based on the context.
+ The connection is assumed to be associated with the
+ specified address file.
+
+Arguments:
+
+ AddressFile - Pointer to an address file.
+
+ ConnectionContext - Connection context to find.
+
+Return Value:
+
+ A pointer to the connection we found
+
+--*/
+
+{
+ CTELockHandle LockHandle1, LockHandle2;
+ PLIST_ENTRY p;
+ PADDRESS Address = AddressFile->Address;
+ PCONNECTION Connection;
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle1);
+
+ for (p=AddressFile->ConnectionDatabase.Flink;
+ p != &AddressFile->ConnectionDatabase;
+ p=p->Flink) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, AddressFileLinkage);
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle2);
+
+ //
+ // BUGBUG: Does this spinlock ordering hurt us
+ // somewhere else?
+ //
+
+ if (Connection->Context == ConnectionContext) {
+
+ NbiReferenceConnection (Connection, CREF_BY_CONTEXT);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle2);
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+
+ return Connection;
+ }
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle2);
+
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+
+ return NULL;
+
+} /* NbiLookupConnectionByContext */
+
+
+PCONNECTION
+NbiCreateConnection(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a transport connection and associates it with
+ the specified transport device context. The reference count in the
+ connection is automatically set to 1, and the reference count of the
+ device context is incremented.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ connection.
+
+Return Value:
+
+ The newly created connection, or NULL if none can be allocated.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PNB_SEND_RESERVED SendReserved;
+ ULONG ConnectionSize;
+ ULONG HeaderLength;
+ NTSTATUS Status;
+ CTELockHandle LockHandle;
+
+ HeaderLength = Device->Bind.MacHeaderNeeded + sizeof(NB_CONNECTION);
+ ConnectionSize = FIELD_OFFSET (CONNECTION, SendPacketHeader[0]) + HeaderLength;
+
+ Connection = (PCONNECTION)NbiAllocateMemory (ConnectionSize, MEMORY_CONNECTION, "Connection");
+ if (Connection == NULL) {
+ NB_DEBUG (CONNECTION, ("Create connection failed\n"));
+ return NULL;
+ }
+
+ NB_DEBUG2 (CONNECTION, ("Create connection %lx\n", Connection));
+ RtlZeroMemory (Connection, ConnectionSize);
+
+
+#if defined(NB_OWN_PACKETS)
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (NbiInitializeSendPacket(
+ Device,
+ Connection->SendPacketPoolHandle,
+ &Connection->SendPacket,
+ Connection->SendPacketHeader,
+ HeaderLength) != STATUS_SUCCESS) {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ NB_DEBUG (CONNECTION, ("Could not initialize connection packet %lx\n", &Connection->SendPacket));
+ Connection->SendPacketInUse = TRUE;
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ SendReserved = SEND_RESERVED(&Connection->SendPacket);
+ SendReserved->u.SR_CO.Connection = Connection;
+ SendReserved->OwnedByConnection = TRUE;
+#ifdef NB_TRACK_POOL
+ SendReserved->Pool = NULL;
+#endif
+ }
+
+#else // !NB_OWN_PACKETS
+
+ //
+ // if we are using ndis packets, first create packet pool for 1 packet descriptor
+ //
+ NdisAllocatePacketPool( &Status, &Connection->SendPacketPoolHandle, 1, sizeof(NB_SEND_RESERVED));
+ if (!NT_SUCCESS(Status)){
+ NB_DEBUG (CONNECTION, ("Could not allocatee connection packet %lx\n", Status));
+ Connection->SendPacketInUse = TRUE;
+ } else {
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (NbiInitializeSendPacket(
+ Device,
+ Connection->SendPacketPoolHandle,
+ &Connection->SendPacket,
+ Connection->SendPacketHeader,
+ HeaderLength) != STATUS_SUCCESS) {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ NB_DEBUG (CONNECTION, ("Could not initialize connection packet %lx\n", &Connection->SendPacket));
+ Connection->SendPacketInUse = TRUE;
+
+ //
+ // Also free up the pool which we allocated above.
+ //
+ NdisFreePacketPool(Connection->SendPacketPoolHandle);
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ SendReserved = SEND_RESERVED(&Connection->SendPacket);
+ SendReserved->u.SR_CO.Connection = Connection;
+ SendReserved->OwnedByConnection = TRUE;
+#ifdef NB_TRACK_POOL
+ SendReserved->Pool = NULL;
+#endif
+ }
+ }
+
+#endif NB_OWN_PACKETS
+
+ Connection->Type = NB_CONNECTION_SIGNATURE;
+ Connection->Size = (USHORT)ConnectionSize;
+
+#if 0
+ Connection->AddressFileLinked = FALSE;
+ Connection->AddressFile = NULL;
+#endif
+
+ Connection->State = CONNECTION_STATE_INACTIVE;
+#if 0
+ Connection->SubState = 0;
+ Connection->ReferenceCount = 0;
+#endif
+
+ Connection->CanBeDestroyed = TRUE;
+
+ Connection->TickCount = 1;
+ Connection->HopCount = 1;
+
+ //
+ // Device->InitialRetransmissionTime is in milliseconds, as is
+ // SHORT_TIMER_DELTA.
+ //
+
+ Connection->BaseRetransmitTimeout = Device->InitialRetransmissionTime / SHORT_TIMER_DELTA;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+
+ //
+ // Device->KeepAliveTimeout is in half-seconds, while LONG_TIMER_DELTA
+ // is in milliseconds.
+ //
+
+ Connection->WatchdogTimeout = (Device->KeepAliveTimeout * 500) / LONG_TIMER_DELTA;
+
+
+ Connection->LocalConnectionId = 0xffff;
+
+ //
+ // When the connection becomes active we will replace the
+ // destination address of this header with the correct
+ // information.
+ //
+
+ RtlCopyMemory(&Connection->RemoteHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+
+ Connection->Device = Device;
+ Connection->DeviceLock = &Device->Lock;
+ CTEInitLock (&Connection->Lock.Lock);
+
+ CTEInitTimer (&Connection->Timer);
+
+ InitializeListHead (&Connection->NdisSendQueue);
+#if 0
+ Connection->NdisSendsInProgress = 0;
+ Connection->DisassociatePending = NULL;
+ Connection->ClosePending = NULL;
+ Connection->SessionInitAckData = NULL;
+ Connection->SessionInitAckDataLength = 0;
+ Connection->PiggybackAckTimeout = FALSE;
+ Connection->ReceivesWithoutAck = 0;
+#endif
+ Connection->Flags = 0;
+
+ NbiReferenceDevice (Device, DREF_CONNECTION);
+
+ return Connection;
+
+} /* NbiCreateConnection */
+
+
+NTSTATUS
+NbiVerifyConnection (
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to verify that the pointer given us in a file
+ object is in fact a valid connection object. We reference
+ it to keep it from disappearing while we use it.
+
+Arguments:
+
+ Connection - potential pointer to a CONNECTION object
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_CONNECTION otherwise
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ NTSTATUS status = STATUS_SUCCESS;
+ PDEVICE Device = NbiDevice;
+ BOOLEAN LockHeld = FALSE;
+
+ try {
+
+ if ((Connection->Size == FIELD_OFFSET (CONNECTION, SendPacketHeader[0]) +
+ NbiDevice->Bind.MacHeaderNeeded + sizeof(NB_CONNECTION)) &&
+ (Connection->Type == NB_CONNECTION_SIGNATURE)) {
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ LockHeld = TRUE;
+
+ if (Connection->State != CONNECTION_STATE_CLOSING) {
+
+ NbiReferenceConnectionLock (Connection, CREF_VERIFY);
+
+ } else {
+
+ NbiPrint1("NbiVerifyConnection: C %lx closing\n", Connection);
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ } else {
+
+ NbiPrint1("NbiVerifyConnection: C %lx bad signature\n", Connection);
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ NbiPrint1("NbiVerifyConnection: C %lx exception\n", Connection);
+ if (LockHeld) {
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+ return GetExceptionCode();
+ }
+
+ return status;
+
+} /* NbiVerifyConnection */
+
+
+VOID
+NbiDestroyConnection(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a transport connection and removes all references
+ made by it to other objects in the transport. The connection structure
+ is returned to nonpaged system pool.
+
+Arguments:
+
+ Connection - Pointer to a transport connection structure to be destroyed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = Connection->Device;
+#if 0
+ CTELockHandle LockHandle;
+#endif
+
+ NB_DEBUG2 (CONNECTION, ("Destroy connection %lx\n", Connection));
+
+ if (!Connection->SendPacketInUse) {
+ NbiDeinitializeSendPacket (Device, &Connection->SendPacket, Device->Bind.MacHeaderNeeded + sizeof(NB_CONNECTION));
+#if !defined(NB_OWN_PACKETS)
+ NdisFreePacketPool(Connection->SendPacketPoolHandle);
+#endif
+ }
+
+ NbiFreeMemory (Connection, (ULONG)Connection->Size, MEMORY_CONNECTION, "Connection");
+
+ NbiDereferenceDevice (Device, DREF_CONNECTION);
+
+} /* NbiDestroyConnection */
+
+
+#if DBG
+VOID
+NbiRefConnection(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ (VOID)ExInterlockedAddUlong (
+ &Connection->ReferenceCount,
+ 1,
+ &Connection->DeviceLock->Lock);
+
+ Connection->CanBeDestroyed = FALSE;
+
+ CTEAssert (Connection->ReferenceCount > 0);
+
+} /* NbiRefConnection */
+
+
+VOID
+NbiRefConnectionLock(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport connection
+ when the device lock is already held.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ ++Connection->ReferenceCount;
+ Connection->CanBeDestroyed = FALSE;
+
+ CTEAssert (Connection->ReferenceCount > 0);
+
+} /* NbiRefConnectionLock */
+
+
+VOID
+NbiRefConnectionSync(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport connection
+ when we are in a sync routine.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ (VOID)NB_ADD_ULONG (
+ &Connection->ReferenceCount,
+ 1,
+ Connection->DeviceLock);
+
+ Connection->CanBeDestroyed = FALSE;
+
+ CTEAssert (Connection->ReferenceCount > 0);
+
+} /* NbiRefConnectionSync */
+
+
+VOID
+NbiDerefConnection(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport connection by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ NbiHandleConnectionZero to complete any disconnect, disassociate,
+ or close requests that have pended on the connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+ CTELockHandle LockHandle;
+
+ NB_GET_LOCK( Connection->DeviceLock, &LockHandle );
+ CTEAssert( Connection->ReferenceCount );
+ if ( !(--Connection->ReferenceCount) ) {
+
+ Connection->ThreadsInHandleConnectionZero++;
+
+ NB_FREE_LOCK( Connection->DeviceLock, LockHandle );
+
+ //
+ // If the refcount has dropped to 0, then the connection can
+ // become inactive. We reacquire the spinlock and if it has not
+ // jumped back up then we handle any disassociates and closes
+ // that have pended.
+ //
+
+ NbiHandleConnectionZero (Connection);
+ } else {
+
+ NB_FREE_LOCK( Connection->DeviceLock, LockHandle );
+ }
+
+
+} /* NbiDerefConnection */
+
+
+#endif
+
+
+VOID
+NbiHandleConnectionZero(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles a connection's refcount going to 0.
+
+ BUGBUG: If two threads are in this at the same time and
+ the close has already come through, one of them might
+ destroy the connection while the other one is looking
+ at it. We minimize the chance of this by not derefing
+ the connection after calling CloseConnection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PDEVICE Device;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PREQUEST DisconnectPending;
+ PREQUEST DisassociatePending;
+ PREQUEST ClosePending;
+
+
+ Device = Connection->Device;
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+#if DBG
+ //
+ // Make sure if our reference count is zero, all the
+ // sub-reference counts are also zero.
+ //
+
+ if (Connection->ReferenceCount == 0) {
+
+ UINT i;
+ for (i = 0; i < CREF_TOTAL; i++) {
+ if (Connection->RefTypes[i] != 0) {
+ DbgPrint ("NBI: Connection reftype mismatch on %lx\n", Connection);
+ DbgBreakPoint();
+ }
+ }
+ }
+#endif
+
+ //
+ // If the connection was assigned an ID, then remove it
+ // (it is assigned one when it leaves INACTIVE).
+ //
+
+ if (Connection->LocalConnectionId != 0xffff) {
+ NbiDeassignConnectionId (Device, Connection);
+ }
+
+ //
+ // Complete any pending disconnects.
+ //
+
+ if (Connection->DisconnectRequest != NULL) {
+
+ DisconnectPending = Connection->DisconnectRequest;
+ Connection->DisconnectRequest = NULL;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ REQUEST_STATUS(DisconnectPending) = STATUS_SUCCESS;
+ NbiCompleteRequest (DisconnectPending);
+ NbiFreeRequest (Device, DisconnectPending);
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ }
+
+ //
+ // This should have been completed by NbiStopConnection,
+ // or else not allowed to be queued.
+ //
+
+ CTEAssert (Connection->DisconnectWaitRequest == NULL);
+
+
+ Connection->State = CONNECTION_STATE_INACTIVE;
+
+ //
+ // BUGBUG: Make NbiInitializeConnection() to take care of all this.
+ //
+
+ RtlZeroMemory (&Connection->ConnectionInfo, sizeof(TDI_CONNECTION_INFO));
+ Connection->TickCount = 1;
+ Connection->HopCount = 1;
+ Connection->BaseRetransmitTimeout = Device->InitialRetransmissionTime / SHORT_TIMER_DELTA;
+
+ Connection->ConnectionInfo.TransmittedTsdus = 0;
+ Connection->ConnectionInfo.TransmissionErrors = 0;
+ Connection->ConnectionInfo.ReceivedTsdus = 0;
+ Connection->ConnectionInfo.ReceiveErrors = 0;
+
+ //
+ // See if we need to do a disassociate now.
+ //
+
+ if ((Connection->ReferenceCount == 0) &&
+ (Connection->DisassociatePending != NULL)) {
+
+ //
+ // A disassociate pended, now we complete it.
+ //
+
+ DisassociatePending = Connection->DisassociatePending;
+ Connection->DisassociatePending = NULL;
+
+ //
+ // Set this so nobody else tries to disassociate.
+ //
+
+ AddressFile = Connection->AddressFile;
+ Connection->AddressFile = (PVOID)-1;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Take this connection out of the address file's list.
+ //
+
+ Address = AddressFile->Address;
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (Connection->AddressFileLinked) {
+ Connection->AddressFileLinked = FALSE;
+ RemoveEntryList (&Connection->AddressFileLinkage);
+ }
+
+ //
+ // We are done.
+ //
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ Connection->AddressFile = NULL;
+
+ //
+ // Clean up the reference counts and complete any
+ // disassociate requests that pended.
+ //
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
+
+ if (DisassociatePending != (PVOID)-1) {
+ REQUEST_STATUS(DisassociatePending) = STATUS_SUCCESS;
+ NbiCompleteRequest (DisassociatePending);
+ NbiFreeRequest (Device, DisassociatePending);
+ }
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+
+ //
+ // If a close was pending, complete that.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if ((Connection->ReferenceCount == 0) &&
+ (Connection->ClosePending)) {
+
+ ClosePending = Connection->ClosePending;
+ Connection->ClosePending = NULL;
+
+ //
+ // If we are associated with an address, we need
+ // to simulate a disassociate at this point.
+ //
+
+ if ((Connection->AddressFile != NULL) &&
+ (Connection->AddressFile != (PVOID)-1)) {
+
+ AddressFile = Connection->AddressFile;
+ Connection->AddressFile = (PVOID)-1;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Take this connection out of the address file's list.
+ //
+
+ Address = AddressFile->Address;
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (Connection->AddressFileLinked) {
+ Connection->AddressFileLinked = FALSE;
+ RemoveEntryList (&Connection->AddressFileLinkage);
+ }
+
+ //
+ // We are done.
+ //
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ Connection->AddressFile = NULL;
+
+ //
+ // Clean up the reference counts and complete any
+ // disassociate requests that pended.
+ //
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ //
+ // Even if the ref count is zero and we just cleaned up everything,
+ // we can not destroy the connection bcoz some other thread might still be
+ // in HandleConnectionZero routine. This could happen when 2 threads call into
+ // HandleConnectionZero, one thread runs thru completion, close comes along
+ // and the other thread is still in HandleConnectionZero routine.
+ //
+
+ CTEAssert( Connection->ThreadsInHandleConnectionZero );
+ if (ExInterlockedAddUlong ( &Connection->ThreadsInHandleConnectionZero, (ULONG)-1, &Device->Lock.Lock) == 1) {
+ NbiDestroyConnection(Connection);
+ }
+
+ REQUEST_STATUS(ClosePending) = STATUS_SUCCESS;
+ NbiCompleteRequest (ClosePending);
+ NbiFreeRequest (Device, ClosePending);
+
+ } else {
+
+ if ( Connection->ReferenceCount == 0 ) {
+ Connection->CanBeDestroyed = TRUE;
+ }
+
+ CTEAssert( Connection->ThreadsInHandleConnectionZero );
+ Connection->ThreadsInHandleConnectionZero--;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+} /* NbiHandleConnectionZero */
+
diff --git a/private/ntos/tdi/isn/nb/datagram.c b/private/ntos/tdi/isn/nb/datagram.c
new file mode 100644
index 000000000..5c599206e
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/datagram.c
@@ -0,0 +1,1089 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ datagram.c
+
+Abstract:
+
+ This module contains the code to handle datagram reception
+ for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 28-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+
+VOID
+NbiProcessDatagram(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize,
+ IN BOOLEAN Broadcast
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles datagram indications.
+
+Arguments:
+
+ MacBindingHandle - A handle to use when calling NdisTransferData.
+
+ MacReceiveContext - A context to use when calling NdisTransferData.
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The lookahead buffer, starting at the IPX
+ header.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+ Broadcast - TRUE if the frame was a broadcast datagram.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PADDRESS Address;
+ NDIS_STATUS NdisStatus;
+ PUCHAR NetbiosName;
+ NB_CONNECTIONLESS UNALIGNED * Connectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)LookaheadBuffer;
+ PDEVICE Device = NbiDevice;
+ PSINGLE_LIST_ENTRY s;
+ PNB_RECEIVE_RESERVED ReceiveReserved;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ ULONG DataOffset;
+ UINT BytesTransferred;
+ PNDIS_PACKET Packet;
+ CTELockHandle LockHandle;
+
+
+ //
+ // See if there is an address that might want this.
+ //
+
+ if (Broadcast) {
+ NetbiosName = (PVOID)-1;
+ } else {
+ NetbiosName = (PUCHAR)Connectionless->Datagram.DestinationName;
+ if (Device->AddressCounts[NetbiosName[0]] == 0) {
+ return;
+ }
+ }
+
+ DataOffset = sizeof(IPX_HEADER) + sizeof(NB_DATAGRAM);
+
+#if defined(_PNP_POWER)
+ if ((PacketSize < DataOffset) ||
+ (PacketSize > DataOffset + Device->CurMaxReceiveBufferSize)) {
+#else
+ if ((PacketSize < DataOffset) ||
+ (PacketSize > DataOffset + Device->Bind.LineInfo.MaximumPacketSize)) {
+#endif _PNP_POWER
+
+ NB_DEBUG (DATAGRAM, ("Datagram length %d discarded\n", PacketSize));
+ return;
+ }
+
+ Address = NbiFindAddress (Device, NetbiosName);
+
+ if (Address == NULL) {
+ return;
+ }
+
+ //
+ // We need to cache the remote name if the packet came across the router.
+ // This allows this machine to get back to the RAS client which might
+ // have sent this datagram. We currently dont allow broadcasts to go out
+ // on the dial-in line.
+ // Dont cache some of the widely used group names, that would be too much
+ // to store in cache.
+ //
+
+#if 0
+ if ( Connectionless->IpxHeader.TransportControl &&
+ !( (Address->NetbiosAddress.NetbiosName[15] == 0x0 ) &&
+ (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) &&
+ !( (Address->NetbiosAddress.NetbiosName[15] == 0x01 ) &&
+ (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) &&
+ !( (Address->NetbiosAddress.NetbiosName[15] == 0x1E ) &&
+ (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) ) {
+#endif
+ if ( Connectionless->IpxHeader.TransportControl &&
+ ( (Address->NetbiosAddress.NetbiosName[15] == 0x1c ) &&
+ (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) ) {
+
+ PNETBIOS_CACHE CacheName;
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+ if ( FindInNetbiosCacheTable ( Device->NameCache,
+ Connectionless->Datagram.SourceName,
+ &CacheName ) != STATUS_SUCCESS ) {
+
+ CacheName = NbiAllocateMemory (sizeof(NETBIOS_CACHE), MEMORY_CACHE, "Cache Entry");
+ if (CacheName ) {
+ RtlCopyMemory (CacheName->NetbiosName, Connectionless->Datagram.SourceName, 16);
+ CacheName->Unique = TRUE;
+ CacheName->ReferenceCount = 1;
+ RtlCopyMemory (&CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12);
+ CacheName->NetworksAllocated = 1;
+ CacheName->NetworksUsed = 1;
+ CacheName->Networks[0].Network = *(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork);
+ CacheName->Networks[0].LocalTarget = *RemoteAddress;
+ NB_DEBUG2 (CACHE, ("Alloc new cache from Datagram %lx for <%.16s>\n",
+ CacheName, CacheName->NetbiosName));
+
+ CacheName->TimeStamp = Device->CacheTimeStamp;
+
+ InsertInNetbiosCacheTable(
+ Device->NameCache,
+ CacheName);
+
+ }
+ } else if ( CacheName->Unique ) {
+ //
+ // We already have an entry for this remote. We should update
+ // the address. This is so that if the ras client dials-out
+ // then dials-in again and gets a new address, we dont end up
+ // caching the old address.
+ //
+ if ( !RtlEqualMemory( &CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12) ) {
+
+ RtlCopyMemory (&CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12);
+ CacheName->Networks[0].Network = *(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork);
+ CacheName->Networks[0].LocalTarget = *RemoteAddress;
+
+ }
+ }
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+
+ //
+ // We need to allocate a packet and buffer for the transfer.
+ //
+
+ s = NbiPopReceivePacket (Device);
+ if (s == NULL) {
+ NbiDereferenceAddress (Address, AREF_FIND);
+ return;
+ }
+
+ ReceiveReserved = CONTAINING_RECORD (s, NB_RECEIVE_RESERVED, PoolLinkage);
+
+
+ s = NbiPopReceiveBuffer (Device);
+ if (s == NULL) {
+ ExInterlockedPushEntrySList(
+ &Device->ReceivePacketList,
+ &ReceiveReserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+ NbiDereferenceAddress (Address, AREF_FIND);
+ return;
+ }
+
+ ReceiveBuffer = CONTAINING_RECORD (s, NB_RECEIVE_BUFFER, PoolLinkage);
+
+ Packet = CONTAINING_RECORD (ReceiveReserved, NDIS_PACKET, ProtocolReserved[0]);
+ ReceiveReserved->u.RR_DG.ReceiveBuffer = ReceiveBuffer;
+
+
+ //
+ // Now that we have a packet and a buffer, set up the transfer.
+ // The indication to the TDI clients will happen at receive
+ // complete time.
+ //
+
+ NdisChainBufferAtFront (Packet, ReceiveBuffer->NdisBuffer);
+ ReceiveBuffer->Address = Address;
+
+ ReceiveReserved->Type = RECEIVE_TYPE_DATAGRAM;
+ CTEAssert (!ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = TRUE;
+
+ TdiCopyLookaheadData(
+ &ReceiveBuffer->RemoteName,
+ Connectionless->Datagram.SourceName,
+ 16,
+ (MacOptions & NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA) ? TDI_RECEIVE_COPY_LOOKAHEAD : 0);
+
+ (*Device->Bind.TransferDataHandler) (
+ &NdisStatus,
+ MacBindingHandle,
+ MacReceiveContext,
+ LookaheadBufferOffset + DataOffset,
+ PacketSize - DataOffset,
+ Packet,
+ &BytesTransferred);
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+#if DBG
+ if (NdisStatus == STATUS_SUCCESS) {
+ CTEAssert (BytesTransferred == PacketSize - DataOffset);
+ }
+#endif
+
+ NbiTransferDataComplete(
+ Packet,
+ NdisStatus,
+ BytesTransferred);
+
+ }
+
+} /* NbiProcessDatagram */
+
+
+VOID
+NbiIndicateDatagram(
+ IN PADDRESS Address,
+ IN PUCHAR RemoteName,
+ IN PUCHAR Data,
+ IN ULONG DataLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine indicates a datagram to clients on the specified
+ address. It is called from NbiReceiveComplete.
+
+Arguments:
+
+ Address - The address the datagram was sent to.
+
+ RemoteName - The source netbios address of the datagram.
+
+ Data - The data.
+
+ DataLength - The length of the data.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p, q;
+ PIRP Irp;
+ ULONG IndicateBytesCopied;
+ PREQUEST Request;
+ TA_NETBIOS_ADDRESS SourceName;
+ PTDI_CONNECTION_INFORMATION RemoteInformation;
+ PADDRESS_FILE AddressFile, ReferencedAddressFile;
+ PTDI_CONNECTION_INFORMATION DatagramInformation;
+ TDI_ADDRESS_NETBIOS UNALIGNED * DatagramAddress;
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ CTELockHandle CancelLH;
+
+ //
+ // Update our statistics.
+ //
+
+ ++Device->Statistics.DatagramsReceived;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DatagramBytesReceived,
+ DataLength);
+
+ //
+ // Call the client's ReceiveDatagram indication handler. He may
+ // want to accept the datagram that way.
+ //
+
+ TdiBuildNetbiosAddress (RemoteName, FALSE, &SourceName);
+ ReferencedAddressFile = NULL;
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+
+ //
+ // Find the next open address file in the list.
+ //
+
+ AddressFile = CONTAINING_RECORD (p, ADDRESS_FILE, Linkage);
+ if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
+ continue;
+ }
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_INDICATION);
+
+ //
+ // do we have a datagram receive request outstanding? If so, we will
+ // satisfy it first. We run through the receive datagram queue
+ // until we find a datagram with no remote address or with
+ // this sender's address as its remote address.
+ //
+
+ for (q = AddressFile->ReceiveDatagramQueue.Flink;
+ q != &AddressFile->ReceiveDatagramQueue;
+ q = q->Flink) {
+
+ Request = LIST_ENTRY_TO_REQUEST (q);
+ DatagramInformation = ((PTDI_REQUEST_KERNEL_RECEIVEDG)
+ REQUEST_PARAMETERS(Request))->ReceiveDatagramInformation;
+
+ if (DatagramInformation &&
+ (DatagramInformation->RemoteAddress) &&
+ (DatagramAddress = NbiParseTdiAddress(DatagramInformation->RemoteAddress, FALSE)) &&
+ (!RtlEqualMemory(
+ RemoteName,
+ DatagramAddress->NetbiosName,
+ 16))) {
+ continue;
+ }
+ break;
+ }
+
+ if (q != &AddressFile->ReceiveDatagramQueue) {
+
+ RemoveEntryList (q);
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile != NULL) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION);
+ }
+ ReferencedAddressFile = AddressFile;
+
+ //
+ // Do this deref now, we hold another one so it
+ // will stick around.
+ //
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
+
+ IndicateBytesCopied = 0;
+
+ //
+ // Fall past the else to copy the data.
+ //
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile != NULL) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION);
+ }
+ ReferencedAddressFile = AddressFile;
+
+ //
+ // No receive datagram requests; is there a kernel client?
+ //
+
+ if (AddressFile->RegisteredHandler[TDI_EVENT_RECEIVE_DATAGRAM]) {
+
+ IndicateBytesCopied = 0;
+
+ if ((*AddressFile->ReceiveDatagramHandler)(
+ AddressFile->HandlerContexts[TDI_EVENT_RECEIVE_DATAGRAM],
+ sizeof (TA_NETBIOS_ADDRESS),
+ &SourceName,
+ 0,
+ NULL,
+ TDI_RECEIVE_COPY_LOOKAHEAD,
+ DataLength, // indicated
+ DataLength, // available
+ &IndicateBytesCopied,
+ Data,
+ &Irp) != STATUS_MORE_PROCESSING_REQUIRED) {
+
+ //
+ // The client did not return a request, go to the
+ // next address file.
+ //
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+
+ }
+
+ Request = NbiAllocateRequest (Device, Irp);
+
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+ }
+
+ } else {
+
+ //
+ // The client has nothing posted and no handler,
+ // go on to the next address file.
+ //
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+
+ }
+
+ }
+
+ //
+ // We have a request; copy the actual user data.
+ //
+ if ( REQUEST_NDIS_BUFFER (Request) ) {
+
+ REQUEST_STATUS(Request) =
+ TdiCopyBufferToMdl (
+ Data,
+ IndicateBytesCopied,
+ DataLength - IndicateBytesCopied,
+ REQUEST_NDIS_BUFFER (Request),
+ 0,
+ &REQUEST_INFORMATION (Request));
+
+ } else {
+ //
+ // No buffer specified in the request
+ //
+ REQUEST_INFORMATION (Request) = 0;
+ //
+ // If there was any data to be copied, return error o/w success
+ //
+ REQUEST_STATUS(Request) = ( (DataLength - IndicateBytesCopied) ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS );
+ }
+
+ //
+ // Copy the addressing information.
+ //
+
+ RemoteInformation = ((PTDI_REQUEST_KERNEL_RECEIVEDG)
+ REQUEST_PARAMETERS(Request))->ReturnDatagramInformation;
+
+ if (RemoteInformation != NULL) {
+
+ RtlCopyMemory(
+ (PTA_NETBIOS_ADDRESS)RemoteInformation->RemoteAddress,
+ &SourceName,
+ (RemoteInformation->RemoteAddressLength < sizeof(TA_NETBIOS_ADDRESS)) ?
+ RemoteInformation->RemoteAddressLength : sizeof(TA_NETBIOS_ADDRESS));
+ }
+
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+
+ } // end of for loop through the address files
+
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle);
+
+
+ if (ReferencedAddressFile != NULL) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION);
+ }
+
+} /* NbiIndicateDatagram */
+
+
+NTSTATUS
+NbiTdiSendDatagram(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a datagram on an address.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the datagram send.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PADDRESS_FILE AddressFile;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteName;
+ PTDI_REQUEST_KERNEL_SENDDG Parameters;
+ PSINGLE_LIST_ENTRY s;
+ PNETBIOS_CACHE CacheName;
+ CTELockHandle LockHandle;
+ NTSTATUS Status;
+
+ //
+ // Make sure that the address is valid.
+ //
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_NOT_OK);
+#else
+ Status = NbiVerifyAddressFile (AddressFile);
+#endif _PNP_POWER
+
+ if (Status == STATUS_SUCCESS) {
+
+ Parameters = (PTDI_REQUEST_KERNEL_SENDDG)REQUEST_PARAMETERS(Request);
+ RemoteName = NbiParseTdiAddress((PTRANSPORT_ADDRESS)(Parameters->SendDatagramInformation->RemoteAddress), TRUE);
+
+
+ //
+ // Check that datagram size is less than the maximum allowable
+ // by the adapters. In the worst case this would be
+ // 576 - 64 = 512.
+ //
+
+#if defined(_PNP_POWER)
+ if ( ( Parameters->SendLength + sizeof(NB_DATAGRAM) ) > Device->Bind.LineInfo.MaximumSendSize ) {
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ NB_DEBUG(DATAGRAM, ("Datagram too large %d, Max allowed %d\n", Parameters->SendLength + sizeof(NB_DATAGRAM), Device->Bind.LineInfo.MaximumSendSize ));
+ return STATUS_INVALID_PARAMETER;
+ }
+#else
+ if ( ( Parameters->SendLength + sizeof(NB_DATAGRAM) ) > Device->Bind.LineInfo.MaximumPacketSize ) {
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ NB_DEBUG(DATAGRAM, ("Datagram too large %d, Max allowed %d\n", Parameters->SendLength + sizeof(NB_DATAGRAM), Device->Bind.LineInfo.MaximumPacketSize ));
+ return STATUS_INVALID_PARAMETER;
+ }
+#endif _PNP_POWER
+
+ if (RemoteName != NULL) {
+
+ //
+ // Get a packet to use in this send.
+ //
+
+ s = NbiPopSendPacket (Device, FALSE);
+
+ if (s != NULL) {
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ //
+ // Check on the cache status of this name.
+ //
+
+ Reserved->u.SR_DG.DatagramRequest = Request;
+ Reserved->u.SR_DG.AddressFile = AddressFile;
+ Reserved->u.SR_DG.RemoteName = RemoteName;
+
+ REQUEST_INFORMATION (Request) = Parameters->SendLength;
+
+ ++Device->Statistics.DatagramsSent;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DatagramBytesSent,
+ Parameters->SendLength);
+
+ if (Device->Internet) {
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Status = CacheFindName(
+ Device,
+ FindNameOther,
+ (RemoteName == (PVOID)-1) ? NULL : (PUCHAR)RemoteName->NetbiosName,
+ &CacheName);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A request for routes to this name has been
+ // sent out on the net, we queue up this datagram
+ // request and processing will be resumed when
+ // we get a response.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Queueing up datagram %lx on %lx\n",
+ Request, AddressFile));
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_SEND_DGRAM);
+
+ InsertTailList(
+ &Device->WaitingDatagrams,
+ &Reserved->WaitLinkage);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ } else if (Status == STATUS_SUCCESS) {
+
+ NB_DEBUG2 (CONNECTION, ("Found datagram cached %lx on %lx\n",
+ Request, AddressFile));
+
+ //
+ // We reference the cache name entry so it won't
+ // go away while we are using it.
+ //
+
+ Reserved->u.SR_DG.Cache = CacheName;
+ Reserved->u.SR_DG.CurrentNetwork = 0;
+ ++CacheName->ReferenceCount;
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_SEND_DGRAM);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+ if ( REQUEST_NDIS_BUFFER(Request) ) {
+ NdisChainBufferAtBack (Packet, REQUEST_NDIS_BUFFER(Request));
+ }
+
+ NbiTransmitDatagram(
+ Reserved);
+
+ Status = STATUS_PENDING;
+
+ } else {
+
+ //
+ // Only this failure gets passed back up to
+ // the caller, to avoid confusing the browser.
+ //
+
+ if (Status != STATUS_DEVICE_DOES_NOT_EXIST) {
+
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ REQUEST_INFORMATION (Request) = 0;
+ }
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+
+
+
+ }
+
+ } else {
+
+ //
+ // We are not in internet mode, so we do not
+ // need to do the name discovery.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Sending datagram direct %lx on %lx\n",
+ Request, AddressFile));
+
+ Reserved->u.SR_DG.Cache = NULL;
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_SEND_DGRAM);
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ if ( REQUEST_NDIS_BUFFER(Request) ) {
+ NdisChainBufferAtBack (Packet, REQUEST_NDIS_BUFFER(Request));
+ }
+ NbiTransmitDatagram(
+ Reserved);
+
+ Status = STATUS_PENDING;
+
+ }
+
+ } else {
+
+ //
+ // Could not allocate a packet for the datagram.
+ //
+
+ NB_DEBUG (DATAGRAM, ("Couldn't get packet to send DG %lx\n", Request));
+
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+ } else {
+
+ //
+ // There is no netbios remote address specified.
+ //
+
+ NB_DEBUG (DATAGRAM, ("No netbios address in DG %lx\n", Request));
+ Status = STATUS_BAD_NETWORK_PATH;
+
+ }
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ } else {
+
+ NB_DEBUG (DATAGRAM, ("Invalid address file for DG %lx\n", Request));
+
+ }
+
+ return Status;
+
+} /* NbiTdiSendDatagram */
+
+
+VOID
+NbiTransmitDatagram(
+ IN PNB_SEND_RESERVED Reserved
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a datagram to the next net in the
+ cache entry for the remote name.
+
+Arguments:
+
+ Reserved - The reserved section of the packet that has
+ been allocated for this send. Reserved->u.SR_DG.Cache
+ will be NULL if Internet mode is off, otherwise it
+ will contain the cache entry to use when sending
+ this datagram.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_PACKET Packet;
+ PNETBIOS_CACHE CacheName;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ ULONG HeaderLength;
+ ULONG PacketLength;
+ NDIS_STATUS NdisStatus;
+ IPX_LOCAL_TARGET TempLocalTarget;
+ PIPX_LOCAL_TARGET LocalTarget;
+ PDEVICE Device = NbiDevice;
+
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_DATAGRAM;
+
+ CacheName = Reserved->u.SR_DG.Cache;
+
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address, so we modify
+ // that for the current netbios cache entry if needed.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+
+ if (CacheName == NULL) {
+
+#if defined(_PNP_POWER)
+ //
+ // IPX will send this on all the Nics.
+ //
+ TempLocalTarget.NicHandle.NicId = (USHORT)ITERATIVE_NIC_ID;
+#else
+ TempLocalTarget.NicId = 1;
+#endif _PNP_POWER
+ RtlCopyMemory (TempLocalTarget.MacAddress, BroadcastAddress, 6);
+ LocalTarget = &TempLocalTarget;
+
+ } else {
+
+ if (CacheName->Unique) {
+ RtlCopyMemory (Header->IpxHeader.DestinationNetwork, &CacheName->FirstResponse, 12);
+ } else {
+ *(UNALIGNED ULONG *)Header->IpxHeader.DestinationNetwork = CacheName->Networks[Reserved->u.SR_DG.CurrentNetwork].Network;
+ RtlCopyMemory (&Header->IpxHeader.DestinationNode, BroadcastAddress, 6);
+ }
+
+ LocalTarget = &CacheName->Networks[Reserved->u.SR_DG.CurrentNetwork].LocalTarget;
+
+ }
+
+ HeaderLength = sizeof(IPX_HEADER) + sizeof(NB_DATAGRAM);
+
+ PacketLength = HeaderLength + REQUEST_INFORMATION(Reserved->u.SR_DG.DatagramRequest);
+
+ Header->IpxHeader.PacketLength[0] = (UCHAR)(PacketLength / 256);
+ Header->IpxHeader.PacketLength[1] = (UCHAR)(PacketLength % 256);
+ Header->IpxHeader.PacketType = 0x04;
+
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ Header->Datagram.ConnectionControlFlag = 0x00;
+ RtlCopyMemory(
+ Header->Datagram.SourceName,
+ Reserved->u.SR_DG.AddressFile->Address->NetbiosAddress.NetbiosName,
+ 16);
+
+ if (Reserved->u.SR_DG.RemoteName != (PVOID)-1) {
+
+ //
+ // This is a directed, as opposed to broadcast, datagram.
+ //
+
+ Header->Datagram.DataStreamType = NB_CMD_DATAGRAM;
+ RtlCopyMemory(
+ Header->Datagram.DestinationName,
+ Reserved->u.SR_DG.RemoteName->NetbiosName,
+ 16);
+
+ } else {
+
+ Header->Datagram.DataStreamType = NB_CMD_BROADCAST_DATAGRAM;
+ RtlZeroMemory(
+ Header->Datagram.DestinationName,
+ 16);
+
+ }
+
+
+ //
+ // Now send the frame (IPX will adjust the length of the
+ // first buffer and the whole frame correctly).
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), HeaderLength);
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ PacketLength,
+ HeaderLength)) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiTransmitDatagram */
+
+
+NTSTATUS
+NbiTdiReceiveDatagram(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiReceiveDatagram request for the transport
+ provider. Receive datagrams just get queued up to an address, and are
+ completed when a DATAGRAM or DATAGRAM_BROADCAST frame is received at
+ the address.
+
+Arguments:
+
+ Request - Describes this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ CTELockHandle LockHandle;
+ CTELockHandle CancelLH;
+
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_NOT_OK);
+#else
+ Status = NbiVerifyAddressFile (AddressFile);
+#endif _PNP_POWER
+
+ if (Status != STATUS_SUCCESS) {
+ return Status;
+ }
+
+ Address = AddressFile->Address;
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ return STATUS_INVALID_HANDLE;
+ }
+
+
+ if (Request->Cancel) {
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ return STATUS_CANCELLED;
+ }
+
+ InsertTailList (&AddressFile->ReceiveDatagramQueue, REQUEST_LINKAGE(Request));
+
+ IoSetCancelRoutine (Request, NbiCancelReceiveDatagram);
+
+ NB_DEBUG2 (DATAGRAM, ("RDG posted on %lx\n", AddressFile));
+
+ NbiTransferReferenceAddressFile (AddressFile, AFREF_VERIFY, AFREF_RCV_DGRAM);
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ return STATUS_PENDING;
+
+} /* NbiTdiReceiveDatagram */
+
+
+VOID
+NbiCancelReceiveDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a receive
+ datagram. The datagram is found on the address file's receive
+ datagram queue.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PLIST_ENTRY p;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PREQUEST Request = (PREQUEST)Irp;
+ BOOLEAN Found;
+ NB_DEFINE_LOCK_HANDLE(LockHandle)
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_RECEIVE_DATAGRAM));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_TRANSPORT_ADDRESS_FILE);
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+ Address = AddressFile->Address;
+
+ Found = FALSE;
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+
+ for (p = AddressFile->ReceiveDatagramQueue.Flink;
+ p != &AddressFile->ReceiveDatagramQueue;
+ p = p->Flink) {
+
+ if (LIST_ENTRY_TO_REQUEST(p) == Request) {
+
+ RemoveEntryList (p);
+ Found = TRUE;
+ break;
+ }
+ }
+
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ if (Found) {
+
+ NB_DEBUG (DATAGRAM, ("Cancelled datagram on %lx\n", AddressFile));
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest((PDEVICE)DeviceObject, Request);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
+
+ }
+
+} /* NbiCancelReceiveDatagram */
+
diff --git a/private/ntos/tdi/isn/nb/device.c b/private/ntos/tdi/isn/nb/device.c
new file mode 100644
index 000000000..d1a9af781
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/device.c
@@ -0,0 +1,461 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ device.c
+
+Abstract:
+
+ This module contains code which implements the DEVICE object.
+ Routines are provided to reference, and dereference transport device
+ context objects.
+
+ The transport device context object is a structure which contains a
+ system-defined DEVICE_OBJECT followed by information which is maintained
+ by the transport provider, called the context.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,NbiCreateDevice)
+#endif
+
+
+VOID
+NbiRefDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a device context.
+
+Arguments:
+
+ Device - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ CTEAssert (Device->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement (&Device->ReferenceCount);
+
+} /* NbiRefDevice */
+
+
+VOID
+NbiDerefDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a device context by decrementing the
+ reference count contained in the structure. Currently, we don't
+ do anything special when the reference count drops to zero, but
+ we could dynamically unload stuff then.
+
+Arguments:
+
+ Device - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&Device->ReferenceCount);
+
+ CTEAssert (result >= 0);
+
+ if (result == 0) {
+ NbiDestroyDevice (Device);
+ }
+
+} /* NbiDerefDevice */
+
+
+NTSTATUS
+NbiCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN OUT PDEVICE *DevicePtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates and initializes a device context structure.
+
+Arguments:
+
+
+ DriverObject - pointer to the IO subsystem supplied driver object.
+
+ Device - Pointer to a pointer to a transport device context object.
+
+ DeviceName - pointer to the name of the device this device object points to.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
+
+--*/
+
+{
+ NTSTATUS status;
+ PDEVICE_OBJECT deviceObject;
+ PDEVICE Device;
+ ULONG DeviceSize;
+ UINT i;
+
+
+ //
+ // Create the device object for the sample transport, allowing
+ // room at the end for the device name to be stored (for use
+ // in logging errors) and the RIP fields.
+ //
+
+ DeviceSize = sizeof(DEVICE) - sizeof(DEVICE_OBJECT) +
+ DeviceName->Length + sizeof(UNICODE_NULL);
+
+ status = IoCreateDevice(
+ DriverObject,
+ DeviceSize,
+ DeviceName,
+ FILE_DEVICE_TRANSPORT,
+ 0,
+ FALSE,
+ &deviceObject);
+
+ if (!NT_SUCCESS(status)) {
+ NB_DEBUG(DEVICE, ("Create device %ws failed %lx\n", DeviceName->Buffer, status));
+ return status;
+ }
+
+ deviceObject->Flags |= DO_DIRECT_IO;
+
+ Device = (PDEVICE)deviceObject;
+
+ NB_DEBUG2 (DEVICE, ("Create device %ws succeeded %lx\n", DeviceName->Buffer, Device));
+
+ //
+ // Initialize our part of the device context.
+ //
+
+ RtlZeroMemory(
+ ((PUCHAR)Device) + sizeof(DEVICE_OBJECT),
+ sizeof(DEVICE) - sizeof(DEVICE_OBJECT));
+
+ //
+ // Copy over the device name.
+ //
+
+ Device->DeviceNameLength = DeviceName->Length + sizeof(WCHAR);
+ Device->DeviceName = (PWCHAR)(Device+1);
+ RtlCopyMemory(
+ Device->DeviceName,
+ DeviceName->Buffer,
+ DeviceName->Length);
+ Device->DeviceName[DeviceName->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ //
+ // Initialize the reference count.
+ //
+
+ Device->ReferenceCount = 1;
+#if DBG
+ Device->RefTypes[DREF_CREATE] = 1;
+#endif
+
+#if DBG
+ RtlCopyMemory(Device->Signature1, "NDC1", 4);
+ RtlCopyMemory(Device->Signature2, "NDC2", 4);
+#endif
+
+ //
+ // BETABUGBUG: Clean this up a bit.
+ //
+
+ Device->Information.Version = 0x0100;
+ Device->Information.MaxSendSize = 65535;
+ Device->Information.MaxConnectionUserData = 0;
+ Device->Information.MaxDatagramSize = 500;
+ Device->Information.ServiceFlags =
+ TDI_SERVICE_CONNECTION_MODE | TDI_SERVICE_ERROR_FREE_DELIVERY |
+ TDI_SERVICE_MULTICAST_SUPPORTED | TDI_SERVICE_BROADCAST_SUPPORTED |
+ TDI_SERVICE_DELAYED_ACCEPTANCE | TDI_SERVICE_CONNECTIONLESS_MODE |
+ TDI_SERVICE_MESSAGE_MODE;
+ Device->Information.MinimumLookaheadData = 128;
+ Device->Information.MaximumLookaheadData = 1500;
+ Device->Information.NumberOfResources = 0;
+ KeQuerySystemTime (&Device->Information.StartTime);
+
+ Device->Statistics.Version = 0x0100;
+ Device->Statistics.MaximumSendWindow = 4;
+ Device->Statistics.AverageSendWindow = 4;
+
+ //
+ // Set this so we won't ignore the broadcast name.
+ //
+
+ Device->AddressCounts['*'] = 1;
+
+ //
+ // Initialize the resource that guards address ACLs.
+ //
+
+ ExInitializeResource (&Device->AddressResource);
+
+ //
+ // initialize the various fields in the device context
+ //
+
+ CTEInitLock (&Device->Interlock.Lock);
+ CTEInitLock (&Device->Lock.Lock);
+
+ CTEInitTimer (&Device->FindNameTimer);
+
+ Device->ControlChannelIdentifier = 1;
+
+ InitializeListHead (&Device->GlobalSendPacketList);
+ InitializeListHead (&Device->GlobalReceivePacketList);
+ InitializeListHead (&Device->GlobalReceiveBufferList);
+
+ InitializeListHead (&Device->AddressDatabase);
+#if defined(_PNP_POWER)
+ InitializeListHead (&Device->AdapterAddressDatabase);
+#endif _PNP_POWER
+
+ InitializeListHead (&Device->WaitingFindNames);
+
+ InitializeListHead (&Device->WaitingConnects);
+ InitializeListHead (&Device->WaitingDatagrams);
+
+ InitializeListHead (&Device->WaitingAdapterStatus);
+ InitializeListHead (&Device->ActiveAdapterStatus);
+
+ InitializeListHead (&Device->WaitingNetbiosFindName);
+
+ InitializeListHead (&Device->ReceiveDatagrams);
+ InitializeListHead (&Device->ConnectIndicationInProgress);
+
+ InitializeListHead (&Device->ListenQueue);
+
+ InitializeListHead (&Device->ReceiveCompletionQueue);
+
+ InitializeListHead (&Device->WaitPacketConnections);
+ InitializeListHead (&Device->PacketizeConnections);
+ InitializeListHead (&Device->DataAckConnections);
+
+ Device->MemoryUsage = 0;
+
+ InitializeListHead (&Device->SendPoolList);
+ InitializeListHead (&Device->ReceivePoolList);
+ InitializeListHead (&Device->ReceiveBufferPoolList);
+
+ ExInitializeSListHead( &Device->SendPacketList );
+ ExInitializeSListHead( &Device->ReceivePacketList );
+ Device->ReceiveBufferList.Next = NULL;
+
+ for (i = 0; i < CONNECTION_HASH_COUNT; i++) {
+ Device->ConnectionHash[i].Connections = NULL;
+ Device->ConnectionHash[i].ConnectionCount = 0;
+ Device->ConnectionHash[i].NextConnectionId = 1;
+ }
+
+ KeQuerySystemTime (&Device->NbiStartTime);
+
+ Device->State = DEVICE_STATE_CLOSED;
+
+ Device->Type = NB_DEVICE_SIGNATURE;
+ Device->Size - sizeof (DEVICE);
+
+
+ *DevicePtr = Device;
+ return STATUS_SUCCESS;
+
+} /* NbiCreateDevice */
+
+
+VOID
+NbiDestroyDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a device context structure.
+
+Arguments:
+
+ Device - Pointer to a pointer to a transport device context object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PNB_SEND_POOL SendPool;
+ PNB_SEND_PACKET SendPacket;
+ UINT SendPoolSize;
+ PNB_RECEIVE_POOL ReceivePool;
+ PNB_RECEIVE_PACKET ReceivePacket;
+ UINT ReceivePoolSize;
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ UINT ReceiveBufferPoolSize;
+ ULONG HeaderLength;
+ UINT i;
+
+ NB_DEBUG2 (DEVICE, ("Destroy device %lx\n", Device));
+
+ //
+ // Take all the connectionless packets out of its pools.
+ //
+
+ HeaderLength = Device->Bind.MacHeaderNeeded + sizeof(NB_CONNECTIONLESS);
+
+ SendPoolSize = FIELD_OFFSET (NB_SEND_POOL, Packets[0]) +
+ (sizeof(NB_SEND_PACKET) * Device->InitPackets) +
+ (HeaderLength * Device->InitPackets);
+
+ while (!IsListEmpty (&Device->SendPoolList)) {
+
+ p = RemoveHeadList (&Device->SendPoolList);
+ SendPool = CONTAINING_RECORD (p, NB_SEND_POOL, Linkage);
+
+ for (i = 0; i < SendPool->PacketCount; i++) {
+
+ SendPacket = &SendPool->Packets[i];
+ NbiDeinitializeSendPacket (Device, SendPacket, HeaderLength);
+
+ }
+
+ NB_DEBUG2 (PACKET, ("Free packet pool %lx\n", SendPool));
+
+#if !defined(NB_OWN_PACKETS)
+ NdisFreePacketPool(SendPool->PoolHandle);
+#endif
+
+ NbiFreeMemory (SendPool, SendPoolSize, MEMORY_PACKET, "SendPool");
+ }
+
+
+ ReceivePoolSize = FIELD_OFFSET (NB_RECEIVE_POOL, Packets[0]) +
+ (sizeof(NB_RECEIVE_PACKET) * Device->InitPackets);
+
+ while (!IsListEmpty (&Device->ReceivePoolList)) {
+
+ p = RemoveHeadList (&Device->ReceivePoolList);
+ ReceivePool = CONTAINING_RECORD (p, NB_RECEIVE_POOL, Linkage);
+
+ for (i = 0; i < ReceivePool->PacketCount; i++) {
+
+ ReceivePacket = &ReceivePool->Packets[i];
+ NbiDeinitializeReceivePacket (Device, ReceivePacket);
+
+ }
+
+ NB_DEBUG2 (PACKET, ("Free packet pool %lx\n", ReceivePool));
+#if !defined(NB_OWN_PACKETS)
+ NdisFreePacketPool(ReceivePool->PoolHandle);
+#endif
+ NbiFreeMemory (ReceivePool, ReceivePoolSize, MEMORY_PACKET, "ReceivePool");
+ }
+
+#if defined(_PNP_POWER)
+ NbiDestroyReceiveBufferPools( Device );
+
+ //
+ // Destroy adapter address list.
+ //
+ while(!IsListEmpty( &Device->AdapterAddressDatabase ) ){
+ PADAPTER_ADDRESS AdapterAddress;
+ AdapterAddress = CONTAINING_RECORD( Device->AdapterAddressDatabase.Flink, ADAPTER_ADDRESS, Linkage );
+ NbiDestroyAdapterAddress( AdapterAddress, NULL );
+ }
+#else
+ ReceiveBufferPoolSize = FIELD_OFFSET (NB_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(NB_RECEIVE_BUFFER) * Device->InitPackets) +
+ (Device->Bind.LineInfo.MaximumPacketSize * Device->InitPackets);
+
+ while (!IsListEmpty (&Device->ReceiveBufferPoolList)) {
+
+ p = RemoveHeadList (&Device->ReceiveBufferPoolList);
+ ReceiveBufferPool = CONTAINING_RECORD (p, NB_RECEIVE_BUFFER_POOL, Linkage);
+
+ for (i = 0; i < ReceiveBufferPool->BufferCount; i++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[i];
+ NbiDeinitializeReceiveBuffer (Device, ReceiveBuffer);
+
+ }
+
+ NB_DEBUG2 (PACKET, ("Free buffer pool %lx\n", ReceiveBufferPool));
+ NbiFreeMemory (ReceiveBufferPool, ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+ }
+#endif _PNP_POWER
+
+ NB_DEBUG (DEVICE, ("Final memory use is %d\n", Device->MemoryUsage));
+
+#if DBG
+ for (i = 0; i < MEMORY_MAX; i++) {
+ if (NbiMemoryTag[i].BytesAllocated != 0) {
+ NB_DEBUG (DEVICE, ("Tag %d: %d bytes left\n", i, NbiMemoryTag[i].BytesAllocated));
+ }
+ }
+#endif
+
+ //
+ // If we are being unloaded then someone is waiting for this
+ // event to finish the cleanup, since we may be at DISPATCH_LEVEL;
+ // otherwise it is during load and we can just kill ourselves here.
+ //
+
+ if (Device->UnloadWaiting) {
+
+ KeSetEvent(
+ &Device->UnloadEvent,
+ 0L,
+ FALSE);
+
+ } else {
+
+ CTEAssert (KeGetCurrentIrql() < DISPATCH_LEVEL);
+ ExDeleteResource (&Device->AddressResource);
+ IoDeleteDevice ((PDEVICE_OBJECT)Device);
+ }
+
+} /* NbiDestroyDevice */
+
diff --git a/private/ntos/tdi/isn/nb/dirs b/private/ntos/tdi/isn/nb/dirs
new file mode 100644
index 000000000..0dab2f056
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/dirs
@@ -0,0 +1,22 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=up mp
diff --git a/private/ntos/tdi/isn/nb/driver.c b/private/ntos/tdi/isn/nb/driver.c
new file mode 100644
index 000000000..a22e48a53
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/driver.c
@@ -0,0 +1,1794 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ driver.c
+
+Abstract:
+
+ This module contains the DriverEntry and other initialization
+ code for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 16-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+PDEVICE NbiDevice = NULL;
+DEFINE_LOCK_STRUCTURE(NbiGlobalPoolInterlock);
+
+#ifdef RSRC_TIMEOUT_DBG
+
+ULONG NbiGlobalDebugResTimeout = 1;
+LARGE_INTEGER NbiGlobalMaxResTimeout;
+ // the packet is allocated from ndis pool.
+NB_SEND_PACKET NbiGlobalDeathPacket; // try to use this first for sends
+UCHAR NbiGlobalDeathPacketHeader[100];
+
+VOID
+NbiInitDeathPacket()
+{
+
+ NDIS_HANDLE PoolHandle; // poolhandle for sendpacket below when
+ NTSTATUS Status;
+
+ //
+ // if we are using ndis packets, first create packet pool for 1 packet descriptor
+ //
+ NdisAllocatePacketPool( &Status, &PoolHandle, 1, sizeof(NB_SEND_RESERVED));
+ if (!NT_SUCCESS(Status)){
+ DbgPrint("Could not allocatee death packet %lx\n", Status);
+ NbiGlobalDebugResTimeout = 0;
+ } else {
+
+ if (NbiInitializeSendPacket(
+ NbiDevice,
+ PoolHandle,
+ &NbiGlobalDeathPacket,
+ NbiGlobalDeathPacketHeader,
+ NbiDevice->Bind.MacHeaderNeeded + sizeof(NB_CONNECTION)) != STATUS_SUCCESS) {
+
+ DbgPrint("Could not allocatee death packet %lx\n", Status);
+ NbiGlobalDebugResTimeout = 0;
+
+ //
+ // Also free up the pool which we allocated above.
+ //
+ NdisFreePacketPool(PoolHandle);
+ }
+ }
+
+}
+#endif //RSRC_TIMEOUT_DBG
+
+#if DBG
+
+ULONG NbiDebug = 0xffffffff;
+ULONG NbiDebug2 = 0x00000000;
+ULONG NbiMemoryDebug = 0x0002482c;
+
+UCHAR NbiTempDebugBuffer[150];
+UCHAR NbiDebugMemory[NB_MEMORY_LOG_SIZE][64];
+PUCHAR NbiDebugMemoryLoc = NbiDebugMemory[0];
+PUCHAR NbiDebugMemoryEnd = NbiDebugMemory[NB_MEMORY_LOG_SIZE];
+VOID
+NbiDebugMemoryLog(
+ IN PUCHAR FormatString,
+ ...
+)
+
+{
+ INT ArgLen;
+ va_list ArgumentPointer;
+
+ va_start(ArgumentPointer, FormatString);
+
+ //
+ // To avoid any overflows, copy this in a temp buffer first.
+ RtlZeroMemory (NbiTempDebugBuffer, 150);
+ ArgLen = vsprintf(NbiTempDebugBuffer,FormatString, ArgumentPointer);
+ va_end(ArgumentPointer);
+
+ if ( ArgLen > 64 ) {
+ CTEAssert( FALSE );
+ } else {
+ RtlZeroMemory (NbiDebugMemoryLoc, 64);
+ RtlCopyMemory( NbiDebugMemoryLoc, NbiTempDebugBuffer, ArgLen );
+
+ NbiDebugMemoryLoc += 64;
+ if (NbiDebugMemoryLoc >= NbiDebugMemoryEnd) {
+ NbiDebugMemoryLoc = NbiDebugMemory[0];
+ }
+ }
+
+} /* NbiDebugMemoryLog */
+
+
+DEFINE_LOCK_STRUCTURE(NbiMemoryInterlock);
+MEMORY_TAG NbiMemoryTag[MEMORY_MAX];
+
+#endif
+//
+// This is used only for CHK build. For
+// tracking the refcount problem on connection, this
+// is moved here for now.
+//
+DEFINE_LOCK_STRUCTURE(NbiGlobalInterlock);
+
+
+#ifdef RASAUTODIAL
+VOID
+NbiAcdBind();
+
+VOID
+NbiAcdUnbind();
+#endif
+
+#ifdef NB_PACKET_LOG
+
+ULONG NbiPacketLogDebug = NB_PACKET_LOG_RCV_OTHER | NB_PACKET_LOG_SEND_OTHER;
+USHORT NbiPacketLogSocket = 0;
+DEFINE_LOCK_STRUCTURE(NbiPacketLogLock);
+NB_PACKET_LOG_ENTRY NbiPacketLog[NB_PACKET_LOG_LENGTH];
+PNB_PACKET_LOG_ENTRY NbiPacketLogLoc = NbiPacketLog;
+PNB_PACKET_LOG_ENTRY NbiPacketLogEnd = &NbiPacketLog[NB_PACKET_LOG_LENGTH];
+
+VOID
+NbiLogPacket(
+ IN BOOLEAN Send,
+ IN PUCHAR DestMac,
+ IN PUCHAR SrcMac,
+ IN USHORT Length,
+ IN PVOID NbiHeader,
+ IN PVOID Data
+ )
+
+{
+
+ CTELockHandle LockHandle;
+ PNB_PACKET_LOG_ENTRY PacketLog;
+ LARGE_INTEGER TickCount;
+ ULONG DataLength;
+
+ CTEGetLock (&NbiPacketLogLock, &LockHandle);
+
+ PacketLog = NbiPacketLogLoc;
+
+ ++NbiPacketLogLoc;
+ if (NbiPacketLogLoc >= NbiPacketLogEnd) {
+ NbiPacketLogLoc = NbiPacketLog;
+ }
+ *(UNALIGNED ULONG *)NbiPacketLogLoc->TimeStamp = 0x3e3d3d3d; // "===>"
+
+ CTEFreeLock (&NbiPacketLogLock, LockHandle);
+
+ RtlZeroMemory (PacketLog, sizeof(NB_PACKET_LOG_ENTRY));
+
+ PacketLog->SendReceive = Send ? '>' : '<';
+
+ KeQueryTickCount(&TickCount);
+ _itoa (TickCount.LowPart % 100000, PacketLog->TimeStamp, 10);
+
+ RtlCopyMemory(PacketLog->DestMac, DestMac, 6);
+ RtlCopyMemory(PacketLog->SrcMac, SrcMac, 6);
+ PacketLog->Length[0] = Length / 256;
+ PacketLog->Length[1] = Length % 256;
+
+ if (Length < sizeof(IPX_HEADER)) {
+ RtlCopyMemory(&PacketLog->NbiHeader, NbiHeader, Length);
+ } else {
+ RtlCopyMemory(&PacketLog->NbiHeader, NbiHeader, sizeof(IPX_HEADER));
+ }
+
+ DataLength = Length - sizeof(IPX_HEADER);
+ if (DataLength < 14) {
+ RtlCopyMemory(PacketLog->Data, Data, DataLength);
+ } else {
+ RtlCopyMemory(PacketLog->Data, Data, 14);
+ }
+
+} /* NbiLogPacket */
+
+#endif // NB_PACKET_LOG
+
+
+//
+// Forward declaration of various routines used in this module.
+//
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+VOID
+NbiUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+NTSTATUS
+NbiDispatchDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbiDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbiDispatchInternal (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+NbiFreeResources (
+ IN PVOID Adapter
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,DriverEntry)
+#endif
+
+//
+// This prevents us from having a bss section.
+//
+
+ULONG _setjmpexused = 0;
+
+
+//
+// These two are used in various places in the driver.
+//
+
+#if defined(_PNP_POWER)
+IPX_LOCAL_TARGET BroadcastTarget = { {ITERATIVE_NIC_ID}, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
+#endif _PNP_POWER
+
+UCHAR BroadcastAddress[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+UCHAR NetbiosBroadcastName[16] = { '*', 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ULONG NbiFailLoad = FALSE;
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs initialization of the Netbios ISN module.
+ It creates the device objects for the transport
+ provider and performs other driver initialization.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+ RegistryPath - The name of Netbios's node in the registry.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ static const NDIS_STRING ProtocolName = NDIS_STRING_CONST("Netbios/IPX Transport");
+ PDEVICE Device;
+ PIPX_HEADER IpxHeader;
+ CTELockHandle LockHandle;
+
+ PCONFIG Config = NULL;
+
+#if 0
+ DbgPrint ("NBI: FailLoad at %lx\n", &NbiFailLoad);
+ DbgBreakPoint();
+
+ if (NbiFailLoad) {
+ return STATUS_UNSUCCESSFUL;
+ }
+#endif
+
+ //
+ // Initialize the Common Transport Environment.
+ //
+
+ if (CTEInitialize() == 0) {
+ NB_DEBUG (DEVICE, ("CTEInitialize() failed\n"));
+ NbiWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_REGISTER_FAILED,
+ 101,
+ STATUS_UNSUCCESSFUL,
+ NULL,
+ 0,
+ NULL);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+#if DBG
+ CTEInitLock (&NbiGlobalInterlock);
+ CTEInitLock (&NbiMemoryInterlock);
+ {
+ UINT i;
+ for (i = 0; i < MEMORY_MAX; i++) {
+ NbiMemoryTag[i].Tag = i;
+ NbiMemoryTag[i].BytesAllocated = 0;
+ }
+ }
+#endif
+#ifdef NB_PACKET_LOG
+ CTEInitLock (&NbiPacketLogLock);
+#endif
+
+#if defined(NB_OWN_PACKETS)
+ CTEAssert (NDIS_PACKET_SIZE == FIELD_OFFSET(NDIS_PACKET, ProtocolReserved[0]));
+#endif
+
+ NB_DEBUG2 (DEVICE, ("ISN Netbios loaded\n"));
+
+ //
+ // This allocates the CONFIG structure and returns
+ // it in Config.
+ //
+
+ status = NbiGetConfiguration(DriverObject, RegistryPath, &Config);
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // If it failed it logged an error.
+ //
+
+ PANIC (" Failed to initialize transport, ISN Netbios initialization failed.\n");
+ return status;
+ }
+
+
+ //
+ // Initialize the driver object with this driver's entry points.
+ //
+
+ DriverObject->MajorFunction [IRP_MJ_CREATE] = NbiDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLOSE] = NbiDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLEANUP] = NbiDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL] = NbiDispatchInternal;
+ DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = NbiDispatchDeviceControl;
+
+ DriverObject->DriverUnload = NbiUnload;
+
+
+ //
+ // Create the device object which exports our name.
+ //
+
+ status = NbiCreateDevice (DriverObject, &Config->DeviceName, &Device);
+
+ if (!NT_SUCCESS (status)) {
+
+ NbiWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_CREATE_DEVICE,
+ 801,
+ status,
+ NULL,
+ 0,
+ NULL);
+
+ NbiFreeConfiguration(Config);
+ return status;
+ }
+
+ NbiDevice = Device;
+
+ //
+ // Initialize the global pool interlock
+ //
+ CTEInitLock (&NbiGlobalPoolInterlock);
+
+
+ //
+ // Save the relevant configuration parameters.
+ //
+
+ Device->AckDelayTime = (Config->Parameters[CONFIG_ACK_DELAY_TIME] / SHORT_TIMER_DELTA) + 1;
+ Device->AckWindow = Config->Parameters[CONFIG_ACK_WINDOW];
+ Device->AckWindowThreshold = Config->Parameters[CONFIG_ACK_WINDOW_THRESHOLD];
+ Device->EnablePiggyBackAck = Config->Parameters[CONFIG_ENABLE_PIGGYBACK_ACK];
+ Device->Extensions = Config->Parameters[CONFIG_EXTENSIONS];
+ Device->RcvWindowMax = Config->Parameters[CONFIG_RCV_WINDOW_MAX];
+ Device->BroadcastCount = Config->Parameters[CONFIG_BROADCAST_COUNT];
+ Device->BroadcastTimeout = Config->Parameters[CONFIG_BROADCAST_TIMEOUT] * 500;
+ Device->ConnectionCount = Config->Parameters[CONFIG_CONNECTION_COUNT];
+ Device->ConnectionTimeout = Config->Parameters[CONFIG_CONNECTION_TIMEOUT] * 500;
+ Device->InitPackets = Config->Parameters[CONFIG_INIT_PACKETS];
+ Device->MaxPackets = Config->Parameters[CONFIG_MAX_PACKETS];
+ Device->InitialRetransmissionTime = Config->Parameters[CONFIG_INIT_RETRANSMIT_TIME];
+ Device->Internet = Config->Parameters[CONFIG_INTERNET];
+ Device->KeepAliveCount = Config->Parameters[CONFIG_KEEP_ALIVE_COUNT];
+ Device->KeepAliveTimeout = Config->Parameters[CONFIG_KEEP_ALIVE_TIMEOUT];
+ Device->RetransmitMax = Config->Parameters[CONFIG_RETRANSMIT_MAX];
+ Device->RouterMtu = Config->Parameters[CONFIG_ROUTER_MTU];
+
+ Device->FindNameTimeout =
+ ((Config->Parameters[CONFIG_BROADCAST_TIMEOUT] * 500) + (FIND_NAME_GRANULARITY/2)) /
+ FIND_NAME_GRANULARITY;
+
+ Device->MaxReceiveBuffers = 20; // BUGBUG: Make it configurable?
+
+#if defined(_PNP_POWER)
+ //
+ // Make Tdi ready for pnp notifications before binding
+ // to IPX
+ //
+ TdiInitialize();
+
+ // Initialize the timer system. This should be done before
+ // binding to ipx because we should have timers intialized
+ // before ipx calls our pnp indications.
+
+ NbiInitializeTimers (Device);
+#endif _PNP_POWER
+
+ //
+ // Now bind to IPX via the internal interface.
+ //
+
+ status = NbiBind (Device, Config);
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // If it failed it logged an error.
+ //
+
+ NbiFreeConfiguration(Config);
+ NbiDereferenceDevice (Device, DREF_LOADED);
+ return status;
+ }
+
+#ifdef RSRC_TIMEOUT_DBG
+ NbiInitDeathPacket();
+ // NbiGlobalMaxResTimeout.QuadPart = 50; // 1*1000*10000;
+ NbiGlobalMaxResTimeout.QuadPart = 20*60*1000;
+ NbiGlobalMaxResTimeout.QuadPart *= 10000;
+#endif // RSRC_TIMEOUT_DBG
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ //
+ // Create Hash Table to store netbios cache entries
+ // For server create a big table, for workstation a small one
+ //
+
+ if ( MmIsThisAnNtAsSystem() ) {
+ status = CreateNetbiosCacheTable( &Device->NameCache, NB_NETBIOS_CACHE_TABLE_LARGE );
+ } else {
+ status = CreateNetbiosCacheTable( &Device->NameCache, NB_NETBIOS_CACHE_TABLE_SMALL );
+ }
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // If it failed it logged an error.
+ //
+
+ NB_FREE_LOCK(&Device->Lock, LockHandle);
+ NbiFreeConfiguration(Config);
+ NbiDereferenceDevice (Device, DREF_LOADED);
+ return status;
+ }
+
+ //
+ // Allocate our initial connectionless packet pool.
+ //
+
+ NbiAllocateSendPool (Device);
+
+ //
+ // Allocate our initial receive packet pool.
+ //
+
+ NbiAllocateReceivePool (Device);
+
+ //
+ // Allocate our initial receive buffer pool.
+ //
+ //
+#if !defined(_PNP_POWER)
+ NbiAllocateReceiveBufferPool (Device);
+#endif !_PNP_POWER
+
+#if defined(_PNP_POWER)
+ if ( DEVICE_STATE_CLOSED == Device->State ) {
+ Device->State = DEVICE_STATE_LOADED;
+ }
+#endif _PNP_POWER
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+#if !defined(_PNP_POWER)
+ //
+ // Start the timer system.
+ //
+
+ NbiInitializeTimers (Device);
+#endif !_PNP_POWER
+
+
+ //
+ // Fill in the default connnectionless header.
+ //
+
+ IpxHeader = &Device->ConnectionlessHeader;
+ IpxHeader->CheckSum = 0xffff;
+ IpxHeader->PacketLength[0] = 0;
+ IpxHeader->PacketLength[1] = 0;
+ IpxHeader->TransportControl = 0;
+ IpxHeader->PacketType = 0;
+ *(UNALIGNED ULONG *)(IpxHeader->DestinationNetwork) = 0;
+ RtlCopyMemory(IpxHeader->DestinationNode, BroadcastAddress, 6);
+ IpxHeader->DestinationSocket = NB_SOCKET;
+ IpxHeader->SourceSocket = NB_SOCKET;
+#if !defined(_PNP_POWER)
+ RtlCopyMemory(IpxHeader->SourceNetwork, Device->Bind.Network, 4);
+ RtlCopyMemory(IpxHeader->SourceNode, Device->Bind.Node, 6);
+
+ Device->State = DEVICE_STATE_OPEN;
+#endif !_PNP_POWER
+
+
+ NbiFreeConfiguration(Config);
+
+#ifdef RASAUTODIAL
+ //
+ // Get the automatic connection
+ // driver entry points.
+ //
+ NbiAcdBind();
+#endif
+
+ return STATUS_SUCCESS;
+
+} /* DriverEntry */
+
+VOID
+NbiUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unloads the sample transport driver.
+ It unbinds from any NDIS drivers that are open and frees all resources
+ associated with the transport. The I/O system will not call us until
+ nobody above has Netbios open.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ None. When the function returns, the driver is unloaded.
+
+--*/
+
+{
+ PNETBIOS_CACHE CacheName;
+ PDEVICE Device = NbiDevice;
+ PLIST_ENTRY p;
+
+ UNREFERENCED_PARAMETER (DriverObject);
+
+
+#ifdef RASAUTODIAL
+ //
+ // Unbind from the
+ // automatic connection driver.
+ //
+ NbiAcdUnbind();
+#endif
+
+ Device->State = DEVICE_STATE_STOPPING;
+
+ //
+ // Free the cache of netbios names.
+ //
+
+ DestroyNetbiosCacheTable( Device->NameCache );
+
+ //
+ // Cancel the long timer.
+ //
+
+ if (CTEStopTimer (&Device->LongTimer)) {
+ NbiDereferenceDevice (Device, DREF_LONG_TIMER);
+ }
+
+ //
+ // Unbind from the IPX driver.
+ //
+
+ NbiUnbind (Device);
+
+ //
+ // This event will get set when the reference count
+ // drops to 0.
+ //
+
+ KeInitializeEvent(
+ &Device->UnloadEvent,
+ NotificationEvent,
+ FALSE);
+ Device->UnloadWaiting = TRUE;
+
+ //
+ // Remove the reference for us being loaded.
+ //
+
+ NbiDereferenceDevice (Device, DREF_LOADED);
+
+ //
+ // Wait for our count to drop to zero.
+ //
+
+ KeWaitForSingleObject(
+ &Device->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ //
+ // Do the cleanup that has to happen at IRQL 0.
+ //
+
+ ExDeleteResource (&Device->AddressResource);
+ IoDeleteDevice ((PDEVICE_OBJECT)Device);
+
+} /* NbiUnload */
+
+
+VOID
+NbiFreeResources (
+ IN PVOID Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by Netbios to clean up the data structures associated
+ with a given Device. When this routine exits, the Device
+ should be deleted as it no longer has any assocaited resources.
+
+Arguments:
+
+ Device - Pointer to the Device we wish to clean up.
+
+Return Value:
+
+ None.
+
+--*/
+{
+#if 0
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY s;
+ PTP_PACKET packet;
+ PNDIS_PACKET ndisPacket;
+ PBUFFER_TAG BufferTag;
+#endif
+
+
+#if 0
+ //
+ // Clean up packet pool.
+ //
+
+ while ( Device->PacketPool.Next != NULL ) {
+ s = PopEntryList( &Device->PacketPool );
+ packet = CONTAINING_RECORD( s, TP_PACKET, Linkage );
+
+ NbiDeallocateSendPacket (Device, packet);
+ }
+
+ //
+ // Clean up receive packet pool
+ //
+
+ while ( Device->ReceivePacketPool.Next != NULL) {
+ s = PopEntryList (&Device->ReceivePacketPool);
+
+ //
+ // HACK: This works because Linkage is the first field in
+ // ProtocolReserved for a receive packet.
+ //
+
+ ndisPacket = CONTAINING_RECORD (s, NDIS_PACKET, ProtocolReserved[0]);
+
+ NbiDeallocateReceivePacket (Device, ndisPacket);
+ }
+
+
+ //
+ // Clean up receive buffer pool.
+ //
+
+ while ( Device->ReceiveBufferPool.Next != NULL ) {
+ s = PopEntryList( &Device->ReceiveBufferPool );
+ BufferTag = CONTAINING_RECORD (s, BUFFER_TAG, Linkage );
+
+ NbiDeallocateReceiveBuffer (Device, BufferTag);
+ }
+
+#endif
+
+} /* NbiFreeResources */
+
+
+NTSTATUS
+NbiDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the IPXNB device driver.
+ It accepts an I/O Request Packet, performs the request, and then
+ returns with the appropriate status.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ NTSTATUS Status;
+ PFILE_FULL_EA_INFORMATION openType;
+ BOOLEAN found;
+ PADDRESS_FILE AddressFile;
+ PCONNECTION Connection;
+ PREQUEST Request;
+ UINT i;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+
+#if !defined(_PNP_POWER)
+ if (Device->State != DEVICE_STATE_OPEN) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+#endif !_PNP_POWER
+
+ //
+ // Allocate a request to track this IRP.
+ //
+
+ Request = NbiAllocateRequest (Device, Irp);
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ MARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = STATUS_PENDING;
+ REQUEST_INFORMATION(Request) = 0;
+
+ //
+ // Case on the function that is being performed by the requestor. If the
+ // operation is a valid one for this device, then make it look like it was
+ // successfully completed, where possible.
+ //
+
+
+ switch (REQUEST_MAJOR_FUNCTION(Request)) {
+
+ //
+ // The Create function opens a transport object (either address or
+ // connection). Access checking is performed on the specified
+ // address to ensure security of transport-layer addresses.
+ //
+
+ case IRP_MJ_CREATE:
+
+#if defined(_PNP_POWER)
+ if (Device->State != DEVICE_STATE_OPEN) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ break;
+ }
+#endif _PNP_POWER
+
+ openType = OPEN_REQUEST_EA_INFORMATION(Request);
+
+ if (openType != NULL) {
+
+ found = TRUE;
+
+ for (i=0;i<openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiTransportAddress[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = NbiOpenAddress (Device, Request);
+ break;
+ }
+
+ //
+ // Connection?
+ //
+
+ found = TRUE;
+
+ for (i=0;i<openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiConnectionContext[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = NbiOpenConnection (Device, Request);
+ break;
+ }
+
+ } else {
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)(Device->ControlChannelIdentifier);
+ ++Device->ControlChannelIdentifier;
+ if (Device->ControlChannelIdentifier == 0) {
+ Device->ControlChannelIdentifier = 1;
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_CONTROL_CHANNEL_FILE;
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case IRP_MJ_CLOSE:
+
+#if defined(_PNP_POWER)
+ if ( (Device->State != DEVICE_STATE_OPEN) && (Device->State != DEVICE_STATE_LOADED) ) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ break;
+ }
+#endif _PNP_POWER
+
+ //
+ // The Close function closes a transport endpoint, terminates
+ // all outstanding transport activity on the endpoint, and unbinds
+ // the endpoint from its transport address, if any. If this
+ // is the last transport endpoint bound to the address, then
+ // the address is removed from the provider.
+ //
+
+ switch ((ULONG)REQUEST_OPEN_TYPE(Request)) {
+
+ case TDI_TRANSPORT_ADDRESS_FILE:
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ //
+ // This creates a reference to AddressFile.
+ //
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile(AddressFile, CONFLICT_IS_OK);
+#else
+ Status = NbiVerifyAddressFile(AddressFile);
+#endif _PNP_POWER
+
+ if (!NT_SUCCESS (Status)) {
+ Status = STATUS_INVALID_HANDLE;
+ } else {
+ Status = NbiCloseAddressFile (Device, Request);
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ }
+
+ break;
+
+ case TDI_CONNECTION_FILE:
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ //
+ // We don't call VerifyConnection because the I/O
+ // system should only give us one close and the file
+ // object should be valid. This helps avoid a window
+ // where two threads call HandleConnectionZero at the
+ // same time.
+ //
+
+ Status = NbiCloseConnection (Device, Request);
+
+ break;
+
+ case TDI_CONTROL_CHANNEL_FILE:
+
+ //
+ // See if it is one of the upper driver's control channels.
+ //
+
+ Status = STATUS_SUCCESS;
+
+ break;
+
+ default:
+
+ Status = STATUS_INVALID_HANDLE;
+
+ }
+
+ break;
+
+ case IRP_MJ_CLEANUP:
+
+#if defined(_PNP_POWER)
+ if ( (Device->State != DEVICE_STATE_OPEN) && (Device->State != DEVICE_STATE_LOADED) ) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ break;
+ }
+#endif _PNP_POWER
+
+ //
+ // Handle the two stage IRP for a file close operation. When the first
+ // stage hits, run down all activity on the object of interest. This
+ // do everything to it but remove the creation hold. Then, when the
+ // CLOSE irp hits, actually close the object.
+ //
+
+ switch ((ULONG)REQUEST_OPEN_TYPE(Request)) {
+
+ case TDI_TRANSPORT_ADDRESS_FILE:
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile(AddressFile, CONFLICT_IS_OK);
+#else
+ Status = NbiVerifyAddressFile(AddressFile);
+#endif _PNP_POWER
+
+ if (!NT_SUCCESS (Status)) {
+
+ Status = STATUS_INVALID_HANDLE;
+
+ } else {
+
+ NbiStopAddressFile (AddressFile, AddressFile->Address);
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case TDI_CONNECTION_FILE:
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection(Connection);
+
+ if (!NT_SUCCESS (Status)) {
+
+ Status = STATUS_INVALID_HANDLE;
+
+ } else {
+
+ NB_BEGIN_SYNC (&SyncContext);
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ //
+ // This call releases the lock.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_INVALID_CONNECTION
+ NB_LOCK_HANDLE_ARG (LockHandle1));
+
+ NB_END_SYNC (&SyncContext);
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case TDI_CONTROL_CHANNEL_FILE:
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+
+ Status = STATUS_INVALID_HANDLE;
+
+ }
+
+ break;
+
+ default:
+
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ } /* major function switch */
+
+ if (Status != STATUS_PENDING) {
+ UNMARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = Status;
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ return Status;
+
+} /* NbiDispatchOpenClose */
+
+
+NTSTATUS
+NbiDispatchDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ //
+ // Branch to the appropriate request handler. Preliminary checking of
+ // the size of the request block is performed here so that it is known
+ // in the handlers that the minimum input parameters are readable. It
+ // is *not* determined here whether variable length input fields are
+ // passed correctly; this is a check which must be made within each routine.
+ //
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+
+ default:
+
+ //
+ // Convert the user call to the proper internal device call.
+ //
+
+ Status = TdiMapUserRequest (DeviceObject, Irp, IrpSp);
+
+ if (Status == STATUS_SUCCESS) {
+
+ //
+ // If TdiMapUserRequest returns SUCCESS then the IRP
+ // has been converted into an IRP_MJ_INTERNAL_DEVICE_CONTROL
+ // IRP, so we dispatch it as usual. The IRP will
+ // be completed by this call.
+ //
+
+ Status = NbiDispatchInternal (DeviceObject, Irp);
+
+ } else {
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ }
+
+ break;
+ }
+
+ return Status;
+
+} /* NbiDeviceControl */
+
+
+NB_TDI_DISPATCH_ROUTINE NbiDispatchInternalTable[] = {
+ NbiTdiAssociateAddress,
+ NbiTdiDisassociateAddress,
+ NbiTdiConnect,
+ NbiTdiListen,
+ NbiTdiAccept,
+ NbiTdiDisconnect,
+ NbiTdiSend,
+ NbiTdiReceive,
+ NbiTdiSendDatagram,
+ NbiTdiReceiveDatagram,
+ NbiTdiSetEventHandler,
+ NbiTdiQueryInformation,
+ NbiTdiSetInformation,
+ NbiTdiAction
+ };
+
+
+NTSTATUS
+NbiDispatchInternal(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PREQUEST Request;
+ UCHAR MinorFunction;
+
+ if (Device->State != DEVICE_STATE_OPEN) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+
+ //
+ // Allocate a request to track this IRP.
+ //
+
+ Request = NbiAllocateRequest (Device, Irp);
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ MARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = STATUS_PENDING;
+ REQUEST_INFORMATION(Request) = 0;
+
+
+ //
+ // Branch to the appropriate request handler.
+ //
+
+ MinorFunction = REQUEST_MINOR_FUNCTION(Request) - 1;
+
+ if (MinorFunction <= (TDI_ACTION-1)) {
+
+ Status = (*NbiDispatchInternalTable[MinorFunction]) (
+ Device,
+ Request);
+
+ } else {
+
+ NB_DEBUG (DRIVER, ("Unsupported minor code %d\n", MinorFunction+1));
+ if ((MinorFunction+1) == TDI_DISCONNECT) {
+ Status = STATUS_SUCCESS;
+ } else {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ }
+
+ if (Status != STATUS_PENDING) {
+ UNMARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = Status;
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ return Status;
+
+} /* NbiDispatchInternal */
+
+
+PVOID
+NbipAllocateMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN BOOLEAN ChargeDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory, making sure it is within
+ the limit allowed by the device.
+
+Arguments:
+
+ BytesNeeded - The number of bytes to allocated.
+
+ ChargeDevice - TRUE if the device should be charged.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PVOID Memory;
+ PDEVICE Device = NbiDevice;
+
+ if (ChargeDevice) {
+ if ((Device->MemoryLimit != 0) &&
+ (((LONG)(Device->MemoryUsage + BytesNeeded) >
+ Device->MemoryLimit))) {
+
+ NbiPrint1 ("Nbi: Could not allocate %d: limit\n", BytesNeeded);
+ NbiWriteResourceErrorLog (Device, BytesNeeded, Tag);
+ return NULL;
+ }
+ }
+
+#if ISN_NT
+ Memory = ExAllocatePoolWithTag (NonPagedPool, BytesNeeded, ' IBN');
+#else
+ Memory = CTEAllocMem (BytesNeeded);
+#endif
+
+ if (Memory == NULL) {
+
+ NbiPrint1("Nbi: Could not allocate %d: no pool\n", BytesNeeded);
+
+ if (ChargeDevice) {
+ NbiWriteResourceErrorLog (Device, BytesNeeded, Tag);
+ }
+
+ return NULL;
+ }
+
+ if (ChargeDevice) {
+ Device->MemoryUsage += BytesNeeded;
+ }
+
+ return Memory;
+
+} /* NbipAllocateMemory */
+
+
+VOID
+NbipFreeMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN BOOLEAN ChargeDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees memory allocated with NbipAllocateMemory.
+
+Arguments:
+
+ Memory - The memory allocated.
+
+ BytesAllocated - The number of bytes to freed.
+
+ ChargeDevice - TRUE if the device should be charged.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+
+#if ISN_NT
+ ExFreePool (Memory);
+#else
+ CTEFreeMem (Memory);
+#endif
+
+ if (ChargeDevice) {
+ Device->MemoryUsage -= BytesAllocated;
+ }
+
+} /* NbipFreeMemory */
+
+#if DBG
+
+
+PVOID
+NbipAllocateTaggedMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory, charging it to the device.
+ If it cannot allocate memory it uses the Tag and Descriptor
+ to log an error.
+
+Arguments:
+
+ BytesNeeded - The number of bytes to allocated.
+
+ Tag - A unique ID used in the error log.
+
+ Description - A text description of the allocation.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PVOID Memory;
+
+ UNREFERENCED_PARAMETER(Description);
+
+ Memory = NbipAllocateMemory(BytesNeeded, Tag, (BOOLEAN)(Tag != MEMORY_CONFIG));
+
+ if (Memory) {
+ ExInterlockedAddUlong(
+ &NbiMemoryTag[Tag].BytesAllocated,
+ BytesNeeded,
+ &NbiMemoryInterlock);
+ }
+
+ return Memory;
+
+} /* NbipAllocateTaggedMemory */
+
+
+VOID
+NbipFreeTaggedMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees memory allocated with NbipAllocateTaggedMemory.
+
+Arguments:
+
+ Memory - The memory allocated.
+
+ BytesAllocated - The number of bytes to freed.
+
+ Tag - A unique ID used in the error log.
+
+ Description - A text description of the allocation.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UNREFERENCED_PARAMETER(Description);
+
+ ExInterlockedAddUlong(
+ &NbiMemoryTag[Tag].BytesAllocated,
+ (ULONG)(-(LONG)BytesAllocated),
+ &NbiMemoryInterlock);
+
+ NbipFreeMemory (Memory, BytesAllocated, (BOOLEAN)(Tag != MEMORY_CONFIG));
+
+} /* NbipFreeTaggedMemory */
+
+#endif
+
+
+VOID
+NbiWriteResourceErrorLog(
+ IN PDEVICE Device,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ an out of resources condition.
+
+Arguments:
+
+ Device - Pointer to the device context.
+
+ BytesNeeded - If applicable, the number of bytes that could not
+ be allocated.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ PUCHAR StringLoc;
+ ULONG TempUniqueError;
+ static WCHAR UniqueErrorBuffer[4] = L"000";
+ INT i;
+
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ Device->DeviceNameLength +
+ sizeof(UniqueErrorBuffer);
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)Device,
+ EntrySize
+ );
+
+ //
+ // Convert the error value into a buffer.
+ //
+
+ TempUniqueError = UniqueErrorValue;
+ for (i=1; i>=0; i--) {
+ UniqueErrorBuffer[i] = (WCHAR)((TempUniqueError % 10) + L'0');
+ TempUniqueError /= 10;
+ }
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = sizeof(ULONG);
+ errorLogEntry->NumberOfStrings = 2;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = EVENT_TRANSPORT_RESOURCE_POOL;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+ errorLogEntry->DumpData[0] = BytesNeeded;
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
+
+ StringLoc += Device->DeviceNameLength;
+ RtlCopyMemory (StringLoc, UniqueErrorBuffer, sizeof(UniqueErrorBuffer));
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* NbiWriteResourceErrorLog */
+
+
+VOID
+NbiWriteGeneralErrorLog(
+ IN PDEVICE Device,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN ULONG DumpDataCount,
+ IN ULONG DumpData[]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ a general problem as indicated by the parameters. It handles
+ event codes REGISTER_FAILED, BINDING_FAILED, ADAPTER_NOT_FOUND,
+ TRANSFER_DATA, TOO_MANY_LINKS, and BAD_PROTOCOL. All these
+ events have messages with one or two strings in them.
+
+Arguments:
+
+ Device - Pointer to the device context, or this may be
+ a driver object instead.
+
+ ErrorCode - The transport event code.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet.
+
+ FinalStatus - Used as the FinalStatus in the error log packet.
+
+ SecondString - If not NULL, the string to use as the %3
+ value in the error log packet.
+
+ DumpDataCount - The number of ULONGs of dump data.
+
+ DumpData - Dump data for the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG SecondStringSize;
+ PUCHAR StringLoc;
+ static WCHAR DriverName[8] = L"NwlnkNb";
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ (DumpDataCount * sizeof(ULONG));
+
+ if (Device->Type == IO_TYPE_DEVICE) {
+ EntrySize += (UCHAR)Device->DeviceNameLength;
+ } else {
+ EntrySize += sizeof(DriverName);
+ }
+
+ if (SecondString) {
+ SecondStringSize = (wcslen(SecondString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize += (UCHAR)SecondStringSize;
+ }
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)Device,
+ EntrySize
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = (USHORT)(DumpDataCount * sizeof(ULONG));
+ errorLogEntry->NumberOfStrings = (SecondString == NULL) ? 1 : 2;
+ errorLogEntry->StringOffset =
+ sizeof(IO_ERROR_LOG_PACKET) + ((DumpDataCount-1) * sizeof(ULONG));
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ if (DumpDataCount) {
+ RtlCopyMemory(errorLogEntry->DumpData, DumpData, DumpDataCount * sizeof(ULONG));
+ }
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ if (Device->Type == IO_TYPE_DEVICE) {
+ RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
+ StringLoc += Device->DeviceNameLength;
+ } else {
+ RtlCopyMemory (StringLoc, DriverName, sizeof(DriverName));
+ StringLoc += sizeof(DriverName);
+ }
+ if (SecondString) {
+ RtlCopyMemory (StringLoc, SecondString, SecondStringSize);
+ }
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* NbiWriteGeneralErrorLog */
+
+
+VOID
+NbiWriteOidErrorLog(
+ IN PDEVICE Device,
+ IN NTSTATUS ErrorCode,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR AdapterString,
+ IN ULONG OidValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ a problem querying or setting an OID on an adapter. It handles
+ event codes SET_OID_FAILED and QUERY_OID_FAILED.
+
+Arguments:
+
+ Device - Pointer to the device context.
+
+ ErrorCode - Used as the ErrorCode in the error log packet.
+
+ FinalStatus - Used as the FinalStatus in the error log packet.
+
+ AdapterString - The name of the adapter we were bound to.
+
+ OidValue - The OID which could not be set or queried.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG AdapterStringSize;
+ PUCHAR StringLoc;
+ static WCHAR OidBuffer[9] = L"00000000";
+ INT i;
+ UINT CurrentDigit;
+
+ AdapterStringSize = (wcslen(AdapterString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) -
+ sizeof(ULONG) +
+ Device->DeviceNameLength +
+ AdapterStringSize +
+ sizeof(OidBuffer);
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)Device,
+ EntrySize
+ );
+
+ //
+ // Convert the OID into a buffer.
+ //
+
+ for (i=7; i>=0; i--) {
+ CurrentDigit = OidValue & 0xf;
+ OidValue >>= 4;
+ if (CurrentDigit >= 0xa) {
+ OidBuffer[i] = (WCHAR)(CurrentDigit - 0xa + L'A');
+ } else {
+ OidBuffer[i] = (WCHAR)(CurrentDigit + L'0');
+ }
+ }
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = 0;
+ errorLogEntry->NumberOfStrings = 3;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) - sizeof(ULONG);
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
+ StringLoc += Device->DeviceNameLength;
+
+ RtlCopyMemory (StringLoc, OidBuffer, sizeof(OidBuffer));
+ StringLoc += sizeof(OidBuffer);
+
+ RtlCopyMemory (StringLoc, AdapterString, AdapterStringSize);
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* NbiWriteOidErrorLog */
+
diff --git a/private/ntos/tdi/isn/nb/event.c b/private/ntos/tdi/isn/nb/event.c
new file mode 100644
index 000000000..f6cff7105
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/event.c
@@ -0,0 +1,117 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ event.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiSetEventHandler
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+PVOID TdiDefaultHandlers[6] = {
+ TdiDefaultConnectHandler,
+ TdiDefaultDisconnectHandler,
+ TdiDefaultErrorHandler,
+ TdiDefaultReceiveHandler,
+ TdiDefaultRcvDatagramHandler,
+ TdiDefaultRcvExpeditedHandler
+ };
+
+
+NTSTATUS
+NbiTdiSetEventHandler(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetEventHandler request for the
+ transport provider. The caller (request dispatcher) verifies
+ that this routine will not be executed on behalf of a user-mode
+ client, as this request enables direct callouts at DISPATCH_LEVEL.
+
+Arguments:
+
+ Device - The netbios device object.
+
+ Request - Pointer to the request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ CTELockHandle LockHandle;
+ PTDI_REQUEST_KERNEL_SET_EVENT Parameters;
+ PADDRESS_FILE AddressFile;
+ UINT EventType;
+
+ UNREFERENCED_PARAMETER (Device);
+
+ //
+ // Get the Address this is associated with; if there is none, get out.
+ //
+
+ AddressFile = REQUEST_OPEN_CONTEXT(Request);
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_OK);
+#else
+ Status = NbiVerifyAddressFile (AddressFile);
+#endif _PNP_POWER
+
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ NB_GET_LOCK (&AddressFile->Address->Lock, &LockHandle);
+
+ Parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)REQUEST_PARAMETERS(Request);
+ EventType = (UINT)(Parameters->EventType);
+
+ if (Parameters->EventType > TDI_EVENT_RECEIVE_EXPEDITED) {
+
+ Status = STATUS_INVALID_PARAMETER;
+
+ } else {
+
+ if (Parameters->EventHandler == NULL) {
+ AddressFile->RegisteredHandler[EventType] = FALSE;
+ AddressFile->Handlers[EventType] = TdiDefaultHandlers[EventType];
+ AddressFile->HandlerContexts[EventType] = NULL;
+ } else {
+ AddressFile->Handlers[EventType] = Parameters->EventHandler;
+ AddressFile->HandlerContexts[EventType] = Parameters->EventContext;
+ AddressFile->RegisteredHandler[EventType] = TRUE;
+ }
+
+ }
+
+ NB_FREE_LOCK (&AddressFile->Address->Lock, LockHandle);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiSetEventHandler */
+
diff --git a/private/ntos/tdi/isn/nb/frame.c b/private/ntos/tdi/isn/nb/frame.c
new file mode 100644
index 000000000..49846a177
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/frame.c
@@ -0,0 +1,1096 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ frame.c
+
+Abstract:
+
+ This module contains code which creates and sends various
+ types of frames.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#if defined(_PNP_POWER)
+
+VOID
+NbiSendNameFrame(
+ IN PADDRESS Address OPTIONAL,
+ IN UCHAR NameTypeFlag,
+ IN UCHAR DataStreamType,
+ IN PIPX_LOCAL_TARGET LocalTarget OPTIONAL,
+ IN NB_CONNECTIONLESS UNALIGNED * ReqFrame OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a name frame on the
+ specified address. It handles add name, name in use, and
+ delete name frames.
+
+Arguments:
+
+ Address - The address on which the frame is sent. This will
+ be NULL if we are responding to a request to the
+ broadcast address.
+
+ NameTypeFlag - The name type flag to use.
+
+ DataStreamType - The type of the command.
+
+ LocalTarget - If specified, the local target to use for the
+ send (if not, it will be broadcast).
+
+ ReqFrame - If specified, the request frame for which this
+ response is being sent. The reqframe contains the
+ destination ipx address and the netbios name.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ IPX_LOCAL_TARGET TempLocalTarget;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->u.SR_NF.Address = Address; // may be NULL
+ Reserved->Type = SEND_TYPE_NAME_FRAME;
+
+ //
+ // Frame that are not sent to a specific address are
+ // sent to all valid NIC IDs.
+ //
+
+ if (!ARGUMENT_PRESENT(LocalTarget)) {
+ Reserved->u.SR_NF.NameTypeFlag = NameTypeFlag;
+ Reserved->u.SR_NF.DataStreamType = DataStreamType;
+ }
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ if (ARGUMENT_PRESENT(ReqFrame)) {
+ RtlCopyMemory((PVOID)&Header->IpxHeader.DestinationNetwork, (PVOID)ReqFrame->IpxHeader.SourceNetwork, 12);
+ }
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
+
+ if (ARGUMENT_PRESENT(LocalTarget)) {
+ Header->IpxHeader.PacketType = 0x04;
+ } else {
+ Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
+ }
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
+ Header->NameFrame.ConnectionControlFlag = 0x00;
+ Header->NameFrame.DataStreamType = DataStreamType;
+ Header->NameFrame.NameTypeFlag = NameTypeFlag;
+
+ //
+ // DataStreamType2 is the same as DataStreamType except for
+ // name in use frames where it is set to the add name type.
+ //
+
+ Header->NameFrame.DataStreamType2 = (UCHAR)
+ ((DataStreamType != NB_CMD_NAME_IN_USE) ? DataStreamType : NB_CMD_ADD_NAME);
+
+ RtlCopyMemory(
+ Header->NameFrame.Name,
+ Address ? Address->NetbiosAddress.NetbiosName : ReqFrame->NameFrame.Name,
+ 16);
+
+ if (Address) {
+ NbiReferenceAddress (Address, AREF_NAME_FRAME);
+ } else {
+ NbiReferenceDevice (Device, DREF_NAME_FRAME);
+ }
+
+ //
+ // Now send the frame (because it is all in the first segment,
+ // IPX will adjust the length of the buffer correctly).
+ //
+
+ if (!ARGUMENT_PRESENT(LocalTarget)) {
+ LocalTarget = &BroadcastTarget;
+ }
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) +
+ sizeof(NB_NAME_FRAME));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendNameFrame */
+#else
+
+VOID
+NbiSendNameFrame(
+ IN PADDRESS Address OPTIONAL,
+ IN UCHAR NameTypeFlag,
+ IN UCHAR DataStreamType,
+ IN PIPX_LOCAL_TARGET LocalTarget OPTIONAL,
+ IN TDI_ADDRESS_IPX UNALIGNED * DestAddress OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a name frame on the
+ specified address. It handles add name, name in use, and
+ delete name frames.
+
+Arguments:
+
+ Address - The address on which the frame is sent. This will
+ be NULL if we are responding to a request to the
+ broadcast address.
+
+ NameTypeFlag - The name type flag to use.
+
+ DataStreamType - The type of the command.
+
+ LocalTarget - If specified, the local target to use for the
+ send (if not, it will be broadcast).
+
+ DestAddress - If specified, the destination IPX address to
+ use for the send (if not, it will be broadcast on net 0).
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ IPX_LOCAL_TARGET TempLocalTarget;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->u.SR_NF.Address = Address; // may be NULL
+ Reserved->Type = SEND_TYPE_NAME_FRAME;
+
+ //
+ // Frame that are not sent to a specific address are
+ // sent to all valid NIC IDs.
+ //
+
+ if (!ARGUMENT_PRESENT(LocalTarget)) {
+ Reserved->u.SR_NF.CurrentNicId = 1;
+ Reserved->u.SR_NF.NameTypeFlag = NameTypeFlag;
+ Reserved->u.SR_NF.DataStreamType = DataStreamType;
+ } else {
+ Reserved->u.SR_NF.CurrentNicId = 0;
+ }
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ if (ARGUMENT_PRESENT(DestAddress)) {
+ RtlCopyMemory((PVOID)&Header->IpxHeader.DestinationNetwork, (PVOID)DestAddress, 12);
+ }
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
+
+ if (ARGUMENT_PRESENT(LocalTarget)) {
+ Header->IpxHeader.PacketType = 0x04;
+ } else {
+ Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
+ }
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
+ Header->NameFrame.ConnectionControlFlag = 0x00;
+ Header->NameFrame.DataStreamType = DataStreamType;
+ Header->NameFrame.NameTypeFlag = NameTypeFlag;
+
+ //
+ // DataStreamType2 is the same as DataStreamType except for
+ // name in use frames where it is set to the add name type.
+ //
+
+ Header->NameFrame.DataStreamType2 = (UCHAR)
+ ((DataStreamType != NB_CMD_NAME_IN_USE) ? DataStreamType : NB_CMD_ADD_NAME);
+
+ RtlCopyMemory(
+ Header->NameFrame.Name,
+ Address ? Address->NetbiosAddress.NetbiosName : NetbiosBroadcastName,
+ 16);
+
+ if (Address) {
+ NbiReferenceAddress (Address, AREF_NAME_FRAME);
+ } else {
+ NbiReferenceDevice (Device, DREF_NAME_FRAME);
+ }
+
+ //
+ // Now send the frame (because it is all in the first segment,
+ // IPX will adjust the length of the buffer correctly).
+ //
+
+ if (!ARGUMENT_PRESENT(LocalTarget)) {
+ TempLocalTarget.NicId = 1; // BUGBUG: What if 1 isn't valid?
+ RtlCopyMemory (TempLocalTarget.MacAddress, BroadcastAddress, 6);
+ LocalTarget = &TempLocalTarget;
+ }
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) +
+ sizeof(NB_NAME_FRAME));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendNameFrame */
+#endif _PNP_POWER
+
+
+VOID
+NbiSendSessionInitialize(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a session initialize
+ frame for the specified connection.
+
+Arguments:
+
+ Connection - The connection on which the frame is sent.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTION UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ PNB_SESSION_INIT SessionInitMemory;
+ PNDIS_BUFFER SessionInitBuffer;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ return;
+ }
+
+
+ //
+ // Allocate a buffer for the extra portion of the
+ // session initialize.
+ //
+
+ SessionInitMemory = (PNB_SESSION_INIT)NbiAllocateMemory(sizeof(NB_SESSION_INIT), MEMORY_CONNECTION, "Session Initialize");
+ if (!SessionInitMemory) {
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ return;
+ }
+
+ //
+ // Allocate an NDIS buffer to map the extra buffer.
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &SessionInitBuffer,
+ Device->NdisBufferPoolHandle,
+ SessionInitMemory,
+ sizeof(NB_SESSION_INIT));
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbiFreeMemory (SessionInitMemory, sizeof(NB_SESSION_INIT), MEMORY_CONNECTION, "Session Initialize");
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_INIT;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(NB_CONNECTION)+sizeof(NB_SESSION_INIT)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(NB_CONNECTION)+sizeof(NB_SESSION_INIT)) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ if (Device->Extensions) {
+ Header->Session.ConnectionControlFlag = NB_CONTROL_SEND_ACK | NB_CONTROL_NEW_NB;
+ } else {
+ Header->Session.ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+ }
+ Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = 0xffff;
+ Header->Session.SendSequence = 0;
+ Header->Session.TotalDataLength = sizeof(NB_SESSION_INIT);
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = sizeof(NB_SESSION_INIT);
+ Header->Session.ReceiveSequence = 0;
+ if (Device->Extensions) {
+ Header->Session.ReceiveSequenceMax = 1; // low estimate for the moment
+ } else {
+ Header->Session.BytesReceived = 0;
+ }
+
+ RtlCopyMemory (SessionInitMemory->SourceName, Connection->AddressFile->Address->NetbiosAddress.NetbiosName, 16);
+ RtlCopyMemory (SessionInitMemory->DestinationName, Connection->RemoteName, 16);
+
+ //
+ // BUGBUG: What exactly should I put here?
+ //
+
+ SessionInitMemory->MaximumDataSize = (USHORT)Connection->MaximumPacketSize;
+ SessionInitMemory->StartTripTime = (USHORT)
+ ((Device->InitialRetransmissionTime * (Device->KeepAliveCount+1)) / 500);
+ SessionInitMemory->MaximumPacketTime = SessionInitMemory->StartTripTime + 12;
+
+ //
+ // BUGBUG: Should we ref the connection? It doesn't
+ // really matter which we do.
+ //
+
+ NbiReferenceDevice (Device, DREF_SESSION_INIT);
+
+ NdisChainBufferAtBack (Packet, SessionInitBuffer);
+
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &Connection->LocalTarget,
+ Packet,
+ sizeof(NB_CONNECTION) + sizeof(NB_SESSION_INIT),
+ sizeof(NB_CONNECTION))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendSessionInitialize */
+
+
+VOID
+NbiSendSessionInitAck(
+ IN PCONNECTION Connection,
+ IN PUCHAR ExtraData,
+ IN ULONG ExtraDataLength,
+ IN CTELockHandle * LockHandle OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a session initialize ack
+ frame for the specified connection. If extra data was
+ specified in the session initialize frame it is echoed
+ back to the remote.
+
+Arguments:
+
+ Connection - The connection on which the frame is sent.
+
+ ExtraData - Any extra data (after the SESSION_INIT buffer)
+ in the frame.
+
+ ExtraDataLength - THe length of the extra data.
+
+ LockHandle - If specified, indicates the connection lock
+ is held and should be released. This is for cases
+ where the ExtraData is in memory which may be freed
+ once the connection lock is released.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTION UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ ULONG SessionInitBufferLength;
+ PNB_SESSION_INIT SessionInitMemory;
+ PNDIS_BUFFER SessionInitBuffer;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ if (ARGUMENT_PRESENT(LockHandle)) {
+ NB_FREE_LOCK (&Connection->Lock, *LockHandle);
+ }
+ return;
+ }
+
+
+ //
+ // Allocate a buffer for the extra portion of the
+ // session initialize.
+ //
+
+ SessionInitBufferLength = sizeof(NB_SESSION_INIT) + ExtraDataLength;
+ SessionInitMemory = (PNB_SESSION_INIT)NbiAllocateMemory(SessionInitBufferLength, MEMORY_CONNECTION, "Session Initialize");
+ if (!SessionInitMemory) {
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ if (ARGUMENT_PRESENT(LockHandle)) {
+ NB_FREE_LOCK (&Connection->Lock, *LockHandle);
+ }
+ return;
+ }
+
+ //
+ // Save the extra data, now we can free the lock.
+ //
+
+ if (ExtraDataLength != 0) {
+ RtlCopyMemory (SessionInitMemory+1, ExtraData, ExtraDataLength);
+ }
+ if (ARGUMENT_PRESENT(LockHandle)) {
+ NB_FREE_LOCK (&Connection->Lock, *LockHandle);
+ }
+
+ //
+ // Allocate an NDIS buffer to map the extra buffer.
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &SessionInitBuffer,
+ Device->NdisBufferPoolHandle,
+ SessionInitMemory,
+ SessionInitBufferLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbiFreeMemory (SessionInitMemory, SessionInitBufferLength, MEMORY_CONNECTION, "Session Initialize");
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_INIT;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(NB_CONNECTION)+SessionInitBufferLength) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(NB_CONNECTION)+SessionInitBufferLength) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ if (Connection->NewNetbios) {
+ Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM | NB_CONTROL_NEW_NB;
+ } else {
+ Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM;
+ }
+ CTEAssert (Connection->CurrentSend.SendSequence == 0);
+ CTEAssert (Connection->ReceiveSequence == 1);
+ Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = Connection->RemoteConnectionId;
+ Header->Session.SendSequence = 0;
+ Header->Session.TotalDataLength = (USHORT)SessionInitBufferLength;
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = (USHORT)SessionInitBufferLength;
+ Header->Session.ReceiveSequence = 1;
+ if (Connection->NewNetbios) {
+ Header->Session.ReceiveSequenceMax = Connection->LocalRcvSequenceMax;
+ } else {
+ Header->Session.BytesReceived = 0;
+ }
+
+ RtlCopyMemory (SessionInitMemory->SourceName, Connection->AddressFile->Address->NetbiosAddress.NetbiosName, 16);
+ RtlCopyMemory (SessionInitMemory->DestinationName, Connection->RemoteName, 16);
+
+ //
+ // BUGBUG: What exactly should I put here?
+ //
+
+ SessionInitMemory->MaximumDataSize = (USHORT)Connection->MaximumPacketSize;
+ SessionInitMemory->StartTripTime = (USHORT)
+ ((Device->InitialRetransmissionTime * (Device->KeepAliveCount+1)) / 500);
+ SessionInitMemory->MaximumPacketTime = SessionInitMemory->StartTripTime + 12;
+
+ //
+ // BUGBUG: Should we ref the connection? It doesn't
+ // really matter which we do.
+ //
+
+ NbiReferenceDevice (Device, DREF_SESSION_INIT);
+
+ NdisChainBufferAtBack (Packet, SessionInitBuffer);
+
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &Connection->LocalTarget,
+ Packet,
+ sizeof(NB_CONNECTION) + SessionInitBufferLength,
+ sizeof(NB_CONNECTION))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendSessionInitAck */
+
+
+VOID
+NbiSendDataAck(
+ IN PCONNECTION Connection,
+ IN NB_ACK_TYPE AckType
+ IN NB_LOCK_HANDLE_PARAM (LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a data ack frame.
+
+ THIS ROUTINE IS CALLED WITH THE LOCK HANDLE HELD AND
+ RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection on which the frame is sent.
+
+ AckType - Indicates if this is a query to the remote,
+ a response to a received probe, or a request to resend.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTION UNALIGNED * Header;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, try for the connection
+ // packet. If that's not available, that's OK since data
+ // acks are connectionless anyway.
+ //
+
+ if (s == NULL) {
+
+ if (!Connection->SendPacketInUse) {
+
+ Connection->SendPacketInUse = TRUE;
+ Packet = PACKET(&Connection->SendPacket);
+ Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+ }
+
+ } else {
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ }
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_NO_DATA;
+ Reserved->u.SR_CO.Connection = Connection;
+ Reserved->u.SR_CO.PacketLength = sizeof(NB_CONNECTION);
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = sizeof(NB_CONNECTION) / 256;
+ Header->IpxHeader.PacketLength[1] = sizeof(NB_CONNECTION) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ switch (AckType) {
+ case NbiAckQuery: Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM | NB_CONTROL_SEND_ACK; break;
+ case NbiAckResponse: Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM; break;
+ case NbiAckResend: Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM | NB_CONTROL_RESEND; break;
+ }
+ Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = Connection->RemoteConnectionId;
+ Header->Session.SendSequence = Connection->CurrentSend.SendSequence;
+ Header->Session.TotalDataLength = (USHORT)Connection->CurrentSend.MessageOffset;
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = 0;
+
+#if 0
+ //
+ // These are set by NbiAssignSequenceAndSend.
+ //
+
+ Header->Session.ReceiveSequence = Connection->ReceiveSequence;
+ Header->Session.BytesReceived = (USHORT)Connection->CurrentReceive.MessageOffset;
+#endif
+
+ NbiReferenceConnectionSync(Connection, CREF_FRAME);
+
+ //
+ // Set this so we will accept a probe from a remote without
+ // the send ack bit on. However if we receive such a request
+ // we turn this flag off until we get something else from the
+ // remote.
+ //
+
+ Connection->IgnoreNextDosProbe = FALSE;
+
+ Connection->ReceivesWithoutAck = 0;
+
+ //
+ // This frees the lock. IPX will adjust the length of
+ // the first buffer correctly.
+ //
+
+ NbiAssignSequenceAndSend(
+ Connection,
+ Packet
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+} /* NbiSendDataAck */
+
+
+VOID
+NbiSendSessionEnd(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a session end
+ frame for the specified connection.
+
+Arguments:
+
+ Connection - The connection on which the frame is sent.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTION UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_NO_DATA;
+ Reserved->u.SR_CO.Connection = Connection;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = sizeof(NB_CONNECTION) / 256;
+ Header->IpxHeader.PacketLength[1] = sizeof(NB_CONNECTION) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header. We don't advance the
+ // send pointer, since it is the last frame of the session
+ // and we want it to stay the same in the case of resends.
+ //
+
+ Header->Session.ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+ Header->Session.DataStreamType = NB_CMD_SESSION_END;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = Connection->RemoteConnectionId;
+ Header->Session.SendSequence = Connection->CurrentSend.SendSequence;
+ Header->Session.TotalDataLength = 0;
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = 0;
+ Header->Session.ReceiveSequence = Connection->ReceiveSequence;
+ if (Connection->NewNetbios) {
+ Header->Session.ReceiveSequenceMax = Connection->LocalRcvSequenceMax;
+ } else {
+ Header->Session.BytesReceived = 0;
+ }
+
+ NbiReferenceConnection (Connection, CREF_FRAME);
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &Connection->LocalTarget,
+ Packet,
+ sizeof(NB_CONNECTION),
+ sizeof(NB_CONNECTION))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendSessionEnd */
+
+
+VOID
+NbiSendSessionEndAck(
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN NB_SESSION UNALIGNED * SessionEnd
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a session end
+ frame. Generally it is sent on a connection but we
+ are not tied to that, to allow us to respond to
+ session ends from unknown remotes.
+
+Arguments:
+
+ RemoteAddress - The remote IPX address.
+
+ LocalTarget - The local target of the remote.
+
+ SessionEnd - The received session end frame.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTION UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_NO_DATA;
+ Reserved->u.SR_CO.Connection = NULL;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ RtlCopyMemory(&Header->IpxHeader.DestinationNetwork, (PVOID)RemoteAddress, 12);
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(NB_CONNECTION)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(NB_CONNECTION)) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ Header->Session.ConnectionControlFlag = 0x00;
+ Header->Session.DataStreamType = NB_CMD_SESSION_END_ACK;
+ Header->Session.SourceConnectionId = SessionEnd->DestConnectionId;
+ Header->Session.DestConnectionId = SessionEnd->SourceConnectionId;
+ Header->Session.SendSequence = SessionEnd->ReceiveSequence;
+ Header->Session.TotalDataLength = 0;
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = 0;
+ if (SessionEnd->BytesReceived != 0) { // BUGBUG: Will this detect new netbios?
+ Header->Session.ReceiveSequence = SessionEnd->SendSequence + 1;
+ Header->Session.ReceiveSequenceMax = SessionEnd->SendSequence + 3;
+ } else {
+ Header->Session.ReceiveSequence = SessionEnd->SendSequence;
+ Header->Session.BytesReceived = 0;
+ }
+
+ NbiReferenceDevice (Device, DREF_FRAME);
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ sizeof(NB_CONNECTION),
+ sizeof(NB_CONNECTION))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendSessionEndAck */
+
diff --git a/private/ntos/tdi/isn/nb/isnnb.h b/private/ntos/tdi/isn/nb/isnnb.h
new file mode 100644
index 000000000..2d142e346
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/isnnb.h
@@ -0,0 +1,787 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ isnnb.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+#define NB_MAXIMUM_MAC 40
+
+#define NB_SOCKET 0x5504
+
+#if defined(_PNP_POWER)
+#define NB_NETBIOS_NAME_SIZE 16
+
+#define LOCK_ACQUIRED TRUE
+#define LOCK_NOT_ACQUIRED FALSE
+#endif _PNP_POWER
+
+//
+// Defined granularity of find name timeouts in milliseconds --
+// we make this the same as the spec'ed RIP gap to avoid
+// flooding routers.
+//
+
+#define FIND_NAME_GRANULARITY 55
+
+
+//
+// Defines the number of milliseconds between expirations of the
+// short and long timers.
+//
+
+#define MILLISECONDS 10000 // number of NT time units in one
+
+#define SHORT_TIMER_DELTA 100
+#define LONG_TIMER_DELTA 2000
+
+
+//
+// Convert a ushort netware order <-> machine order
+//
+
+#define REORDER_USHORT(_Ushort) ((((_Ushort) & 0xff00) >> 8) | (((_Ushort) & 0x00ff) << 8))
+
+//
+// Convert a ulong netware order <-> machine order
+//
+
+#define REORDER_ULONG(_Ulong) \
+ ((((_Ulong) & 0xff000000) >> 24) | \
+ (((_Ulong) & 0x00ff0000) >> 8) | \
+ (((_Ulong) & 0x0000ff00) << 8) | \
+ (((_Ulong) & 0x000000ff) << 24))
+
+
+
+#include <packon.h>
+
+//
+// Definition of the IPX header.
+//
+
+typedef struct _IPX_HEADER {
+ USHORT CheckSum;
+ UCHAR PacketLength[2];
+ UCHAR TransportControl;
+ UCHAR PacketType;
+ UCHAR DestinationNetwork[4];
+ UCHAR DestinationNode[6];
+ USHORT DestinationSocket;
+ UCHAR SourceNetwork[4];
+ UCHAR SourceNode[6];
+ USHORT SourceSocket;
+} IPX_HEADER, *PIPX_HEADER;
+
+
+//
+// Definition of the Netbios header for name frames.
+//
+
+typedef struct _NB_NAME_FRAME {
+ union {
+ struct {
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ };
+ UCHAR RoutingInfo[32];
+ };
+ UCHAR NameTypeFlag;
+ UCHAR DataStreamType2;
+ UCHAR Name[16];
+} NB_NAME_FRAME, *PNB_NAME_FRAME;
+
+//
+// Definition of the Netbios header for directed datagrams.
+//
+
+typedef struct _NB_DATAGRAM {
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ UCHAR SourceName[16];
+ UCHAR DestinationName[16];
+} NB_DATAGRAM, *PNB_DATAGRAM;
+
+//
+// Definition of the Netbios header for a status query.
+//
+
+typedef struct _NB_STATUS_QUERY {
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ UCHAR Padding[14];
+} NB_STATUS_QUERY, *PNB_STATUS_QUERY;
+
+//
+// Definition of the Netbios header for a status response
+// (this does not include the status buffer itself).
+//
+
+typedef struct _NB_STATUS_RESPONSE {
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+} NB_STATUS_RESPONSE, *PNB_STATUS_RESPONSE;
+
+
+//
+// Definition of the general Netbios connectionless header.
+//
+
+typedef struct _NB_CONNECTIONLESS {
+ IPX_HEADER IpxHeader;
+ union {
+ NB_NAME_FRAME NameFrame;
+ NB_DATAGRAM Datagram;
+ NB_STATUS_QUERY StatusQuery;
+ NB_STATUS_RESPONSE StatusResponse;
+ };
+} NB_CONNECTIONLESS, *PNB_CONNECTIONLESS;
+
+
+//
+// Definition of the Netbios session frame.
+//
+
+typedef struct _NB_SESSION {
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ USHORT SourceConnectionId;
+ USHORT DestConnectionId;
+ USHORT SendSequence;
+ USHORT TotalDataLength;
+ USHORT Offset;
+ USHORT DataLength;
+ USHORT ReceiveSequence;
+ union {
+ USHORT BytesReceived;
+ USHORT ReceiveSequenceMax;
+ };
+} NB_SESSION, *PNB_SESSION;
+
+
+//
+// Definition of the extra fields in a Netbios
+// session frame for session init and session init
+// ack.
+//
+
+typedef struct _NB_SESSION_INIT {
+ UCHAR SourceName[16];
+ UCHAR DestinationName[16];
+ USHORT MaximumDataSize;
+ USHORT MaximumPacketTime;
+ USHORT StartTripTime;
+} NB_SESSION_INIT, *PNB_SESSION_INIT;
+
+
+//
+// Definition of the general Netbios connection-oriented header.
+//
+
+typedef struct _NB_CONNECTION {
+ IPX_HEADER IpxHeader;
+ NB_SESSION Session;
+} NB_CONNECTION, *PNB_CONNECTION;
+
+
+//
+// Definition of a Netbios packet.
+//
+
+typedef union _NB_FRAME {
+ NB_CONNECTIONLESS Connectionless;
+ NB_CONNECTION Connection;
+} NB_FRAME, *PNB_FRAME;
+
+#include <packoff.h>
+
+
+//
+// Definitions for the DataStreamType field, with the
+// format used shown in the comment afterward.
+//
+
+#define NB_CMD_FIND_NAME 0x01 // NAME_FRAME
+#define NB_CMD_NAME_RECOGNIZED 0x02 // NAME_FRAME
+#define NB_CMD_ADD_NAME 0x03 // NAME_FRAME
+#define NB_CMD_NAME_IN_USE 0x04 // NAME_FRAME
+#define NB_CMD_DELETE_NAME 0x05 // NAME_FRAME
+#define NB_CMD_SESSION_DATA 0x06 // SESSION
+#define NB_CMD_SESSION_END 0x07 // SESSION
+#define NB_CMD_SESSION_END_ACK 0x08 // SESSION
+#define NB_CMD_STATUS_QUERY 0x09 // STATUS_QUERY
+#define NB_CMD_STATUS_RESPONSE 0x0a // STATUS_RESPONSE
+#define NB_CMD_DATAGRAM 0x0b // DATAGRAM
+#define NB_CMD_BROADCAST_DATAGRAM 0x0c // BROADCAST_DATAGRAM
+
+#ifdef RSRC_TIMEOUT_DBG
+#define NB_CMD_DEATH_PACKET 0x99 //
+#endif // RSRC_TIMEOUT_DBG
+
+//
+// Bit values in the NameTypeFlag of NB_NAME_FRAME frames.
+//
+
+#define NB_NAME_UNIQUE 0x00
+#define NB_NAME_GROUP 0x80
+#define NB_NAME_USED 0x40
+#define NB_NAME_REGISTERED 0x04
+#define NB_NAME_DUPLICATED 0x02
+#define NB_NAME_DEREGISTERED 0x01
+
+//
+// Bit values in the ConnectionControlFlag.
+//
+
+#define NB_CONTROL_SYSTEM 0x80
+#define NB_CONTROL_SEND_ACK 0x40
+#define NB_CONTROL_ATTENTION 0x20
+#define NB_CONTROL_EOM 0x10
+#define NB_CONTROL_RESEND 0x08
+#define NB_CONTROL_NEW_NB 0x01
+
+
+
+#define NB_DEVICE_SIGNATURE 0x1401
+#if defined(_PNP_POWER)
+#define NB_ADAPTER_ADDRESS_SIGNATURE 0x1403
+#endif _PNP_POWER
+#define NB_ADDRESS_SIGNATURE 0x1404
+#define NB_ADDRESSFILE_SIGNATURE 0x1405
+#define NB_CONNECTION_SIGNATURE 0x1406
+
+
+//
+// Useful in various places.
+//
+#if defined(_PNP_POWER)
+extern IPX_LOCAL_TARGET BroadcastTarget;
+#endif _PNP_POWER
+extern UCHAR BroadcastAddress[6];
+extern UCHAR NetbiosBroadcastName[16];
+
+
+//
+// Contains the default handler for each of the TDI event types
+// that are supported.
+//
+
+extern PVOID TdiDefaultHandlers[6];
+
+
+//
+// Define a structure that can track lock acquire/release.
+//
+
+typedef struct _NB_LOCK {
+ CTELock Lock;
+#if DBG
+ ULONG LockAcquired;
+ UCHAR LastAcquireFile[8];
+ ULONG LastAcquireLine;
+ UCHAR LastReleaseFile[8];
+ ULONG LastReleaseLine;
+#endif
+} NB_LOCK, *PNB_LOCK;
+
+
+
+#if DBG
+
+extern ULONG NbiDebug;
+extern ULONG NbiDebug2;
+extern ULONG NbiMemoryDebug;
+
+#define NB_MEMORY_LOG_SIZE 128
+extern UCHAR NbiDebugMemory[NB_MEMORY_LOG_SIZE][64];
+extern PUCHAR NbiDebugMemoryLoc;
+extern PUCHAR NbiDebugMemoryEnd;
+
+VOID
+NbiDebugMemoryLog(
+ IN PUCHAR FormatString,
+ ...
+);
+
+#define NB_DEBUG(_Flag, _Print) { \
+ if (NbiDebug & (NB_DEBUG_ ## _Flag)) { \
+ DbgPrint ("NBI: "); \
+ DbgPrint _Print; \
+ } \
+ if (NbiMemoryDebug & (NB_DEBUG_ ## _Flag)) { \
+ NbiDebugMemoryLog _Print; \
+ } \
+}
+
+#define NB_DEBUG2(_Flag, _Print) { \
+ if (NbiDebug2 & (NB_DEBUG_ ## _Flag)) { \
+ DbgPrint ("NBI: "); \
+ DbgPrint _Print; \
+ } \
+ if (NbiMemoryDebug & (NB_DEBUG_ ## _Flag)) { \
+ NbiDebugMemoryLog _Print; \
+ } \
+}
+
+#else
+
+#define NB_DEBUG(_Flag, _Print)
+#define NB_DEBUG2(_Flag, _Print)
+
+#endif
+
+
+//
+// These definitions are for abstracting IRPs from the
+// transport for portability.
+//
+
+#if ISN_NT
+
+typedef IRP REQUEST, *PREQUEST;
+typedef struct _REQUEST_LIST_HEAD {
+ PREQUEST Head; // list is empty if this is NULL
+ PREQUEST Tail; // undefined if the list is empty.
+} REQUEST_LIST_HEAD, *PREQUEST_LIST_HEAD;
+
+
+//
+// PREQUEST
+// NbiAllocateRequest(
+// IN PDEVICE Device,
+// IN PIRP Irp
+// );
+//
+// Allocates a request for the system-specific request structure.
+//
+
+#define NbiAllocateRequest(_Device,_Irp) \
+ (_Irp)
+
+
+//
+// BOOLEAN
+// IF_NOT_ALLOCATED(
+// IN PREQUEST Request
+// );
+//
+// Checks if a request was not successfully allocated.
+//
+
+#define IF_NOT_ALLOCATED(_Request) \
+ if (0)
+
+
+//
+// VOID
+// NbiFreeRequest(
+// IN PDEVICE Device,
+// IN PREQUEST Request
+// );
+//
+// Frees a previously allocated request.
+//
+
+#define NbiFreeRequest(_Device,_Request) \
+ ;
+
+
+//
+// VOID
+// MARK_REQUEST_PENDING(
+// IN PREQUEST Request
+// );
+//
+// Marks that a request will pend.
+//
+
+#define MARK_REQUEST_PENDING(_Request) \
+ IoMarkIrpPending(_Request)
+
+
+//
+// VOID
+// UNMARK_REQUEST_PENDING(
+// IN PREQUEST Request
+// );
+//
+// Marks that a request will not pend.
+//
+
+#define UNMARK_REQUEST_PENDING(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->Control) &= ~SL_PENDING_RETURNED)
+
+
+//
+// UCHAR
+// REQUEST_MAJOR_FUNCTION
+// IN PREQUEST Request
+// );
+//
+// Returns the major function code of a request.
+//
+
+#define REQUEST_MAJOR_FUNCTION(_Request) \
+ ((IoGetCurrentIrpStackLocation(_Request))->MajorFunction)
+
+
+//
+// UCHAR
+// REQUEST_MINOR_FUNCTION
+// IN PREQUEST Request
+// );
+//
+// Returns the minor function code of a request.
+//
+
+#define REQUEST_MINOR_FUNCTION(_Request) \
+ ((IoGetCurrentIrpStackLocation(_Request))->MinorFunction)
+
+
+//
+// PNDIS_BUFFER
+// REQUEST_NDIS_BUFFER
+// IN PREQUEST Request
+// );
+//
+// Returns the NDIS buffer chain associated with a request.
+//
+
+#define REQUEST_NDIS_BUFFER(_Request) \
+ ((PNDIS_BUFFER)((_Request)->MdlAddress))
+
+
+//
+// PVOID
+// REQUEST_OPEN_CONTEXT(
+// IN PREQUEST Request
+// );
+//
+// Gets the context associated with an opened address/connection/control channel.
+//
+
+#define REQUEST_OPEN_CONTEXT(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->FileObject)->FsContext)
+
+
+//
+// PVOID
+// REQUEST_OPEN_TYPE(
+// IN PREQUEST Request
+// );
+//
+// Gets the type associated with an opened address/connection/control channel.
+//
+
+#define REQUEST_OPEN_TYPE(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->FileObject)->FsContext2)
+
+
+//
+// PFILE_FULL_EA_INFORMATION
+// OPEN_REQUEST_EA_INFORMATION(
+// IN PREQUEST Request
+// );
+//
+// Returns the EA information associated with an open/close request.
+//
+
+#define OPEN_REQUEST_EA_INFORMATION(_Request) \
+ ((PFILE_FULL_EA_INFORMATION)((_Request)->AssociatedIrp.SystemBuffer))
+
+
+//
+// PTDI_REQUEST_KERNEL
+// REQUEST_PARAMETERS(
+// IN PREQUEST Request
+// );
+//
+// Obtains a pointer to the parameters of a request.
+//
+
+#define REQUEST_PARAMETERS(_Request) \
+ (&((IoGetCurrentIrpStackLocation(_Request))->Parameters))
+
+
+//
+// PLIST_ENTRY
+// REQUEST_LINKAGE(
+// IN PREQUEST Request
+// );
+//
+// Returns a pointer to a linkage field in the request.
+//
+
+#define REQUEST_LINKAGE(_Request) \
+ (&((_Request)->Tail.Overlay.ListEntry))
+
+
+//
+// PREQUEST
+// REQUEST_SINGLE_LINKAGE(
+// IN PREQUEST Request
+// );
+//
+// Used to access a single list linkage field in the request.
+//
+
+#define REQUEST_SINGLE_LINKAGE(_Request) \
+ (*((PREQUEST *)&((_Request)->Tail.Overlay.ListEntry.Flink)))
+
+
+//
+// ULONG
+// REQUEST_REFCOUNT(
+// IN PREQUEST Request
+// );
+//
+// Used to access a field in the request which can be used for
+// the reference count, as long as it is on a REQUEST_LIST.
+//
+
+#define REQUEST_REFCOUNT(_Request) \
+ (*((PULONG)&((_Request)->Tail.Overlay.ListEntry.Blink)))
+
+
+//
+// VOID
+// REQUEST_LIST_INSERT_TAIL(
+// IN PREQUEST_LIST_HEAD Head,
+// IN PREQUEST Entry
+// );
+//
+// Inserts a request into a single list linkage queue.
+//
+
+#define REQUEST_LIST_INSERT_TAIL(_Head,_Entry) { \
+ if ((_Head)->Head == NULL) { \
+ (_Head)->Head = (_Entry); \
+ (_Head)->Tail = (_Entry); \
+ } else { \
+ REQUEST_SINGLE_LINKAGE((_Head)->Tail) = (_Entry); \
+ (_Head)->Tail = (_Entry); \
+ } \
+}
+
+
+//
+// PREQUEST
+// LIST_ENTRY_TO_REQUEST(
+// IN PLIST_ENTRY ListEntry
+// );
+//
+// Returns a request given a linkage field in it.
+//
+
+#define LIST_ENTRY_TO_REQUEST(_ListEntry) \
+ ((PREQUEST)(CONTAINING_RECORD(_ListEntry, REQUEST, Tail.Overlay.ListEntry)))
+
+
+//
+// NTSTATUS
+// REQUEST_STATUS(
+// IN PREQUEST Request
+// );
+//
+// Used to access the status field of a request.
+//
+
+#define REQUEST_STATUS(_Request) \
+ (_Request)->IoStatus.Status
+
+
+//
+// ULONG
+// REQUEST_INFORMATION(
+// IN PREQUEST Request)
+// );
+//
+// Used to access the information field of a request.
+//
+
+#define REQUEST_INFORMATION(_Request) \
+ (_Request)->IoStatus.Information
+
+
+//
+// VOID
+// NbiCompleteRequest(
+// IN PREQUEST Request
+// );
+//
+// Completes a request whose status and information fields have
+// been filled in.
+//
+
+#define NbiCompleteRequest(_Request) \
+ IoCompleteRequest (_Request, IO_NETWORK_INCREMENT)
+
+#else
+
+//
+// These routines must be defined for portability to a VxD.
+//
+
+#endif
+
+//
+// some utility macros.
+
+// Minimum of two
+//
+#define NB_MIN( _a , _b ) ( ( (_a) < (_b) ) ? (_a) : (_b) )
+
+//
+// Swap the _s1 and _s2 of Type _T
+//
+
+#define NB_SWAP(_s1, _s2, _T) { \
+ _T _temp; \
+ _temp = (_s1); \
+ (_s1) = (_s2); \
+ (_s2) = _temp; \
+}
+
+#define NB_SWAP_IRQL( _s1, _s2 ) NB_SWAP( _s1, _s2, CTELockHandle )
+
+//
+// Define our own spinlock routines.
+//
+
+#if DBG
+
+#define NB_GET_LOCK(_Lock, _LockHandle) { \
+ CTEGetLock(&(_Lock)->Lock, _LockHandle); \
+ (_Lock)->LockAcquired = TRUE; \
+ strncpy((_Lock)->LastAcquireFile, strrchr(__FILE__,'\\')+1, 7); \
+ (_Lock)->LastAcquireLine = __LINE__; \
+}
+
+#define NB_FREE_LOCK(_Lock, _LockHandle) { \
+ (_Lock)->LockAcquired = FALSE; \
+ strncpy((_Lock)->LastReleaseFile, strrchr(__FILE__,'\\')+1, 7); \
+ (_Lock)->LastReleaseLine = __LINE__; \
+ CTEFreeLock(&(_Lock)->Lock, _LockHandle); \
+}
+
+#define NB_GET_LOCK_DPC(_Lock) { \
+ ExAcquireSpinLockAtDpcLevel(&(_Lock)->Lock); \
+ (_Lock)->LockAcquired = TRUE; \
+ strncpy((_Lock)->LastAcquireFile, strrchr(__FILE__,'\\')+1, 7); \
+ (_Lock)->LastAcquireLine = __LINE__; \
+}
+
+#define NB_FREE_LOCK_DPC(_Lock) { \
+ (_Lock)->LockAcquired = FALSE; \
+ strncpy((_Lock)->LastReleaseFile, strrchr(__FILE__,'\\')+1, 7); \
+ (_Lock)->LastReleaseLine = __LINE__; \
+ ExReleaseSpinLockFromDpcLevel(&(_Lock)->Lock); \
+}
+
+#else
+
+#define NB_GET_LOCK(_Lock, _LockHandle) CTEGetLock(&(_Lock)->Lock, _LockHandle)
+#define NB_FREE_LOCK(_Lock, _LockHandle) CTEFreeLock(&(_Lock)->Lock, _LockHandle)
+#define NB_GET_LOCK_DPC(_Lock) ExAcquireSpinLockAtDpcLevel(&(_Lock)->Lock)
+#define NB_FREE_LOCK_DPC(_Lock) ExReleaseSpinLockFromDpcLevel(&(_Lock)->Lock)
+
+#endif
+
+
+#define NB_GET_CANCEL_LOCK( _LockHandle ) IoAcquireCancelSpinLock( _LockHandle )
+
+#define NB_FREE_CANCEL_LOCK( _LockHandle ) IoReleaseCancelSpinLock( _LockHandle )
+
+
+//
+// Routines to optimize for a uni-processor environment.
+//
+
+
+#define NB_INCREMENT(_Long, _Lock) InterlockedIncrement(_Long)
+#define NB_DECREMENT(_Long, _Lock) InterlockedDecrement(_Long)
+
+#define NB_ADD_ULONG(_Pulong, _Ulong, _Lock) ExInterlockedAddUlong(_Pulong, _Ulong, &(_Lock)->Lock)
+
+#define NB_DEFINE_SYNC_CONTEXT(_SyncContext)
+#define NB_BEGIN_SYNC(_SyncContext)
+#define NB_END_SYNC(_SyncContext)
+
+#define NB_DEFINE_LOCK_HANDLE(_LockHandle) CTELockHandle _LockHandle;
+
+//
+// BUGBUG: Make these be NB_XXX_LOCK_DPC calls -- then the definitions
+// of the NB_SYNC_XXX_LOCK calls can be changed to not need _LockHandle
+// and many of the functions won't need that as a parameter.
+//
+
+#define NB_SYNC_GET_LOCK(_Lock, _LockHandle) NB_GET_LOCK(_Lock, _LockHandle)
+#define NB_SYNC_FREE_LOCK(_Lock, _LockHandle) NB_FREE_LOCK(_Lock, _LockHandle)
+
+#define NB_REMOVE_HEAD_LIST(_Queue, _Lock) ExInterlockedRemoveHeadList(_Queue, &(_Lock)->Lock)
+#define NB_LIST_WAS_EMPTY(_Queue, _OldHead) ((_OldHead) == NULL)
+#define NB_INSERT_HEAD_LIST(_Queue, _Entry, _Lock) ExInterlockedInsertHeadList(_Queue, _Entry, &(_Lock)->Lock)
+#define NB_INSERT_TAIL_LIST(_Queue, _Entry, _Lock) ExInterlockedInsertTailList(_Queue, _Entry, &(_Lock)->Lock)
+
+#define NB_POP_ENTRY_LIST(_Queue, _Lock) ExInterlockedPopEntryList(_Queue, &(_Lock)->Lock)
+#define NB_PUSH_ENTRY_LIST(_Queue, _Entry, _Lock) ExInterlockedPushEntryList(_Queue, _Entry, &(_Lock)->Lock)
+
+#define NB_LOCK_HANDLE_PARAM(_LockHandle) , IN CTELockHandle _LockHandle
+#define NB_LOCK_HANDLE_ARG(_LockHandle) , (_LockHandle)
+
+#define NB_SYNC_SWAP_IRQL( _s1, _s2 ) NB_SWAP( _s1, _s2, CTELockHandle )
+
+
+//
+// This macro adds a ULONG to a LARGE_INTEGER (should be
+// called with a spinlock held).
+//
+
+#define ADD_TO_LARGE_INTEGER(_LargeInteger,_Ulong) \
+ ExInterlockedAddLargeStatistic((_LargeInteger),(ULONG)(_Ulong))
+
+#define NB_DEBUG_DEVICE 0x00000001
+#define NB_DEBUG_ADDRESS 0x00000004
+#define NB_DEBUG_SEND 0x00000008
+#define NB_DEBUG_RECEIVE 0x00000020
+#define NB_DEBUG_CONFIG 0x00000040
+#define NB_DEBUG_PACKET 0x00000080
+#define NB_DEBUG_BIND 0x00000200
+#define NB_DEBUG_ADDRESS_FRAME 0x00000400
+#define NB_DEBUG_CONNECTION 0x00000800
+#define NB_DEBUG_QUERY 0x00001000
+#define NB_DEBUG_DRIVER 0x00002000
+#define NB_DEBUG_CACHE 0x00004000
+#define NB_DEBUG_DATAGRAM 0x00008000
+#define NB_DEBUG_TIMER 0x00010000
+#define NB_DEBUG_SEND_WINDOW 0x00020000
+
+
+
+//
+// NB_GET_NBHDR_BUFF - gets the nb header in the packet. It is always the
+// second buffer.
+//
+#define NB_GET_NBHDR_BUFF(Packet) (NDIS_BUFFER_LINKAGE((Packet)->Private.Head))
+
+
diff --git a/private/ntos/tdi/isn/nb/mp/makefile b/private/ntos/tdi/isn/nb/mp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/mp/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isn/nb/mp/sources b/private/ntos/tdi/isn/nb/mp/sources
new file mode 100644
index 000000000..dc48d81bb
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/mp/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+NT_UP=0
+
+TARGETPATH=\nt\public\sdk\lib
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/isn/nb/nbcount/makefile b/private/ntos/tdi/isn/nb/nbcount/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/nbcount/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isn/nb/nbcount/nbcount.c b/private/ntos/tdi/isn/nb/nbcount/nbcount.c
new file mode 100644
index 000000000..74a656f16
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/nbcount/nbcount.c
@@ -0,0 +1,177 @@
+/****************************************************************************
+* (c) Copyright 1990, 1993 Micro Computer Systems, Inc. All rights reserved.
+*****************************************************************************
+*
+* Title: IPX/SPX Compatible Source Routing Daemon for Windows NT
+*
+* Module: ipx/route/ipxroute.c
+*
+* Version: 1.00.00
+*
+* Date: 04-08-93
+*
+* Author: Brian Walker
+*
+*****************************************************************************
+*
+* Change Log:
+*
+* Date DevSFC Comment
+* -------- ------ -------------------------------------------------------
+*****************************************************************************
+*
+* Functional Description:
+*
+*
+****************************************************************************/
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <process.h>
+#include <ntstapi.h>
+#include <sys/stropts.h>
+#include <windows.h>
+#include "errno.h"
+#include "tdi.h"
+#include "isnkrnl.h"
+
+
+typedef struct _NB_ACTION_GET_COUNTS {
+ USHORT MaximumNicId; // returns maximum NIC ID
+ USHORT NicIdCounts[32]; // session counts for first 32 NIC IDs
+} NB_ACTION_GET_COUNTS, *PNB_ACTION_GET_COUNTS;
+
+HANDLE isnnbfd;
+wchar_t isnnbname[] = L"\\Device\\NwlnkNb";
+char pgmname[] = "NBCOUNT";
+
+/** **/
+
+#define INVALID_HANDLE (HANDLE)(-1)
+
+int do_isnnbioctl(HANDLE fd, int cmd, char *datap, int dlen);
+
+/*page*************************************************************
+ m a i n
+
+ This is the main routine that gets executed when a NET START
+ happens.
+
+ Arguments - None
+
+ Returns - Nothing
+********************************************************************/
+void _CRTAPI1 main(int argc, char **argv)
+{
+ UNICODE_STRING FileString;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatusBlock;
+ NTSTATUS Status;
+ NB_ACTION_GET_COUNTS GetCounts;
+ int rc;
+ int i;
+
+ /** Open the nwlnknb driver **/
+
+ RtlInitUnicodeString (&FileString, isnnbname);
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &FileString,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenFile(
+ &isnnbfd,
+ SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT);
+
+ if (!NT_SUCCESS(Status)) {
+ isnnbfd = INVALID_HANDLE;
+ printf("Could not open transport\n");
+ }
+
+ if (isnnbfd == INVALID_HANDLE) {
+ exit(1);
+ }
+
+ rc = do_isnnbioctl(isnnbfd, (I_MIPX | 351), (char *)&GetCounts, sizeof(NB_ACTION_GET_COUNTS));
+ if (rc == 0) {
+
+ printf("NB NIC count: %d\n", GetCounts.MaximumNicId);
+ for (i = 1; i <= GetCounts.MaximumNicId; i++) {
+ printf("NIC %d: %d sessions\n", i, GetCounts.NicIdCounts[i]);
+ }
+ }
+}
+
+
+/*page***************************************************************
+ d o _ i s n i p x i o c t l
+
+ Do the equivalent of a stream ioctl to isnnb
+
+ Arguments - fd = Handle to put on
+ cmd = Command to send
+ datap = Ptr to ctrl buffer
+ dlen = Ptr to len of data buffer
+
+ Returns - 0 = OK
+ else = Error
+********************************************************************/
+int do_isnnbioctl(HANDLE fd, int cmd, char *datap, int dlen)
+{
+ NTSTATUS Status;
+ UCHAR buffer[300];
+ PNWLINK_ACTION action;
+ IO_STATUS_BLOCK IoStatusBlock;
+ int rc;
+
+ /** Fill out the structure **/
+
+ action = (PNWLINK_ACTION)buffer;
+
+ action->Header.TransportId = ISN_ACTION_TRANSPORT_ID;
+ action->OptionType = NWLINK_OPTION_CONTROL;
+ action->BufferLength = sizeof(ULONG) + dlen;
+ action->Option = cmd;
+ RtlMoveMemory(action->Data, datap, dlen);
+
+ /** Issue the ioctl **/
+
+ Status = NtDeviceIoControlFile(
+ fd,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ IOCTL_TDI_ACTION,
+ NULL,
+ 0,
+ action,
+ FIELD_OFFSET(NWLINK_ACTION,Data) + dlen);
+
+ if (Status != STATUS_SUCCESS) {
+ if (Status == STATUS_INVALID_PARAMETER) {
+ rc = ERANGE;
+ } else {
+ rc = EINVAL;
+ }
+ } else {
+ if (dlen > 0) {
+ RtlMoveMemory (datap, action->Data, dlen);
+ }
+ rc = 0;
+ }
+
+ return rc;
+
+}
+
diff --git a/private/ntos/tdi/isn/nb/nbcount/nbcount.rc b/private/ntos/tdi/isn/nb/nbcount/nbcount.rc
new file mode 100644
index 000000000..ada219b24
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/nbcount/nbcount.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "NWLink Netbios Session Count Application"
+#define VER_INTERNALNAME_STR "nbcount.exe"
+#define VER_ORIGINALFILENAME_STR "nbcount.exe"
+
+#include "common.ver"
diff --git a/private/ntos/tdi/isn/nb/nbcount/sources b/private/ntos/tdi/isn/nb/nbcount/sources
new file mode 100644
index 000000000..f9dfe3561
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/nbcount/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1993 Micro Computer Systems, Inc.
+
+!ENDIF
+
+MAJORCOMP=nwlink
+MINORCOMP=nbcount
+
+TARGETNAME=nbcount
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=UMAPPL_NOLIB
+
+USE_CRTDLL=1
+
+C_DEFINES=$(C_DEFINES)
+
+!IF 0
+INCLUDES=..\h;..\..\..\..\..\inc;..\..\..\..\inc;..\..\..\inc
+!ELSE
+INCLUDES=..\h;$(BASEDIR)\private\inc;$(BASEDIR)\private\ntos\inc;$(BASEDIR)\private\ntos\streams\inc
+!ENDIF
+
+SOURCES= nbcount.c nbcount.rc
+
+UMTYPE=console
+UMAPPL=$(TARGETNAME)
+UMLIBS=$(BASEDIR)\public\sdk\lib\*\ntdll.lib \
+
diff --git a/private/ntos/tdi/isn/nb/nbiprocs.h b/private/ntos/tdi/isn/nb/nbiprocs.h
new file mode 100644
index 000000000..64fd8f3a6
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/nbiprocs.h
@@ -0,0 +1,1533 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ nbiprocs.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 16-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+//
+// MACROS.
+//
+//
+// Debugging aids
+//
+
+//
+// VOID
+// PANIC(
+// IN PSZ Message
+// );
+//
+
+#if DBG
+#define PANIC(Msg) \
+ CTEPrint ((Msg))
+#else
+#define PANIC(Msg)
+#endif
+
+
+//
+// These are define to allow CTEPrints that disappear when
+// DBG is 0.
+//
+
+#if DBG
+#define NbiPrint0(fmt) DbgPrint(fmt)
+#define NbiPrint1(fmt,v0) DbgPrint(fmt,v0)
+#define NbiPrint2(fmt,v0,v1) DbgPrint(fmt,v0,v1)
+#define NbiPrint3(fmt,v0,v1,v2) DbgPrint(fmt,v0,v1,v2)
+#define NbiPrint4(fmt,v0,v1,v2,v3) DbgPrint(fmt,v0,v1,v2,v3)
+#define NbiPrint5(fmt,v0,v1,v2,v3,v4) DbgPrint(fmt,v0,v1,v2,v3,v4)
+#define NbiPrint6(fmt,v0,v1,v2,v3,v4,v5) DbgPrint(fmt,v0,v1,v2,v3,v4,v5)
+#else
+#define NbiPrint0(fmt)
+#define NbiPrint1(fmt,v0)
+#define NbiPrint2(fmt,v0,v1)
+#define NbiPrint3(fmt,v0,v1,v2)
+#define NbiPrint4(fmt,v0,v1,v2,v3)
+#define NbiPrint5(fmt,v0,v1,v2,v3,v4)
+#define NbiPrint6(fmt,v0,v1,v2,v3,v4,v5)
+#endif
+
+
+//
+// Routines to log packets to a buffer.
+//
+
+#if DBG
+#define NB_PACKET_LOG 1
+#endif
+
+#ifdef NB_PACKET_LOG
+
+//
+// The size of this is 64 bytes for easy display.
+//
+
+typedef struct _NB_PACKET_LOG_ENTRY {
+ UCHAR SendReceive;
+ UCHAR TimeStamp[5]; // low 5 digits of tick count.
+ UCHAR DestMac[6];
+ UCHAR SrcMac[6];
+ UCHAR Length[2];
+ IPX_HEADER NbiHeader;
+ UCHAR Data[14];
+} NB_PACKET_LOG_ENTRY, *PNB_PACKET_LOG_ENTRY;
+
+#define NB_PACKET_LOG_LENGTH 128
+extern ULONG NbiPacketLogDebug;
+extern USHORT NbiPacketLogSocket;
+EXTERNAL_LOCK(NbiPacketLogLock);
+extern NB_PACKET_LOG_ENTRY NbiPacketLog[NB_PACKET_LOG_LENGTH];
+extern PNB_PACKET_LOG_ENTRY NbiPacketLogLoc;
+extern PNB_PACKET_LOG_ENTRY NbiPacketLogEnd;
+
+//
+// Bit fields in NbiPacketLogDebug
+//
+
+#define NB_PACKET_LOG_RCV_RIP 0x0001 // All RIP packets
+#define NB_PACKET_LOG_RCV_SPX 0x0002 // All SPX packets
+#define NB_PACKET_LOG_RCV_NB 0x0004 // All Netbios packets
+#define NB_PACKET_LOG_RCV_OTHER 0x0008 // All TDI client packets
+#define NB_PACKET_LOG_RCV_SOCKET 0x0010 // All packets to NbiPacketLogSocket
+#define NB_PACKET_LOG_RCV_ALL 0x0020 // All packets (even non-NB)
+
+#define NB_PACKET_LOG_SEND_RIP 0x0001 // All RIP packets
+#define NB_PACKET_LOG_SEND_SPX 0x0002 // All SPX packets
+#define NB_PACKET_LOG_SEND_NB 0x0004 // All Netbios packets
+#define NB_PACKET_LOG_SEND_OTHER 0x0008 // All TDI client packets
+#define NB_PACKET_LOG_SEND_SOCKET 0x0010 // All packets from NbiPacketLogSocket
+
+VOID
+NbiLogPacket(
+ IN BOOLEAN Send,
+ IN PUCHAR DestMac,
+ IN PUCHAR SrcMac,
+ IN USHORT Length,
+ IN PVOID NbiHeader,
+ IN PVOID Data
+ );
+
+#define PACKET_LOG(_Bit) (NbiPacketLogDebug & (_Bit))
+
+#else // NB_PACKET_LOG
+
+#define NbiLogPacket(_MacHeader,_Length,_NbiHeader,_Data)
+#define PACKET_LOG(_Bit) 0
+
+#endif // NB_PACKET_LOG
+
+
+#if DBG
+
+#define NbiReferenceDevice(_Device, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Device)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefDevice (_Device)
+
+#define NbiDereferenceDevice(_Device, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Device)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock); \
+ NbiDerefDevice (_Device)
+
+
+#define NbiReferenceAddress(_Address, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Address)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefAddress (_Address)
+
+#define NbiReferenceAddressLock(_Address, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Address)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefAddressLock (_Address)
+
+#define NbiDereferenceAddress(_Address, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Address)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock); \
+ NbiDerefAddress (_Address)
+
+
+#define NbiReferenceAddressFile(_AddressFile, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefAddressFile (_AddressFile)
+
+#define NbiReferenceAddressFileLock(_AddressFile, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefAddressFileLock (_AddressFile)
+
+#define NbiDereferenceAddressFile(_AddressFile, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock); \
+ NbiDerefAddressFile (_AddressFile)
+
+#define NbiTransferReferenceAddressFile(_AddressFile, _OldType, _NewType) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_AddressFile)->RefTypes[_NewType], \
+ 1, \
+ &NbiGlobalInterlock); \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_AddressFile)->RefTypes[_OldType], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock);
+
+
+#define NbiReferenceConnection(_Connection, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefConnection (_Connection)
+
+#define NbiReferenceConnectionLock(_Connection, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefConnectionLock (_Connection)
+
+#define NbiReferenceConnectionSync(_Connection, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefConnectionSync (_Connection)
+
+#define NbiDereferenceConnection(_Connection, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock); \
+ NbiDerefConnection (_Connection)
+
+#define NbiTransferReferenceConnection(_Connection, _OldType, _NewType) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_NewType], \
+ 1, \
+ &NbiGlobalInterlock); \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_OldType], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock);
+
+#else // DBG
+
+#define NbiReferenceDevice(_Device, _Type) \
+ InterlockedIncrement(&(_Device)->ReferenceCount)
+
+#define NbiDereferenceDevice(_Device, _Type) \
+ NbiDerefDevice (_Device)
+
+
+
+#define NbiReferenceAddress(_Address, _Type) \
+ InterlockedIncrement( &(_Address)->ReferenceCount )
+
+#define NbiReferenceAddressLock(_Address, _Type) \
+ InterlockedIncrement( &(_Address)->ReferenceCount )
+
+#define NbiDereferenceAddress(_Address, _Type) \
+ NbiDerefAddress (_Address)
+
+
+#define NbiReferenceAddressFile(_AddressFile, _Type) \
+ InterlockedIncrement( &(_AddressFile)->ReferenceCount )
+
+#define NbiReferenceAddressFileLock(_AddressFile, _Type) \
+ InterlockedIncrement( &(_AddressFile)->ReferenceCount )
+
+#define NbiDereferenceAddressFile(_AddressFile, _Type) \
+ if ( !InterlockedDecrement(&(_AddressFile)->ReferenceCount )) { \
+ NbiDestroyAddressFile (_AddressFile); \
+ }
+
+#define NbiTransferReferenceAddressFile(_AddressFile, _OldType, _NewType)
+
+
+#define NbiReferenceConnection(_Connection, _Type) { \
+ (VOID)ExInterlockedAddUlong( \
+ &(_Connection)->ReferenceCount, \
+ 1, \
+ &(_Connection)->DeviceLock->Lock); \
+ (_Connection)->CanBeDestroyed = FALSE; \
+}
+
+#define NbiReferenceConnectionLock(_Connection, _Type) { \
+ ++(_Connection)->ReferenceCount; \
+ (_Connection)->CanBeDestroyed = FALSE; \
+}
+
+#define NbiReferenceConnectionSync(_Connection, _Type) { \
+ (VOID)NB_ADD_ULONG( \
+ &(_Connection)->ReferenceCount, \
+ 1, \
+ (_Connection)->DeviceLock); \
+ (_Connection)->CanBeDestroyed = FALSE; \
+}
+
+#define NbiDereferenceConnection(_Connection, _Type) { \
+ CTELockHandle _LockHandle; \
+ NB_GET_LOCK( (_Connection)->DeviceLock, &_LockHandle ); \
+ if ( !(--(_Connection)->ReferenceCount) ) { \
+ (_Connection)->ThreadsInHandleConnectionZero++; \
+ NB_FREE_LOCK( (_Connection)->DeviceLock, _LockHandle ); \
+ NbiHandleConnectionZero (_Connection); \
+ } else { \
+ NB_FREE_LOCK( (_Connection)->DeviceLock, _LockHandle ); \
+ } \
+}
+
+
+#define NbiTransferReferenceConnection(_Connection, _OldType, _NewType)
+
+#endif // DBG
+
+
+
+#if DBG
+
+#define NbiAllocateMemory(_BytesNeeded,_Tag,_Description) \
+ NbipAllocateTaggedMemory(_BytesNeeded,_Tag,_Description)
+
+#define NbiFreeMemory(_Memory,_BytesAllocated,_Tag,_Description) \
+ NbipFreeTaggedMemory(_Memory,_BytesAllocated,_Tag,_Description)
+
+#else // DBG
+
+#define NbiAllocateMemory(_BytesNeeded,_Tag,_Description) \
+ NbipAllocateMemory(_BytesNeeded,_Tag,(BOOLEAN)((_Tag) != MEMORY_CONFIG))
+
+#define NbiFreeMemory(_Memory,_BytesAllocated,_Tag,_Description) \
+ NbipFreeMemory(_Memory,_BytesAllocated,(BOOLEAN)((_Tag) != MEMORY_CONFIG))
+
+
+#endif // DBG
+
+
+//
+// Definition of the callback routine where an NdisTransferData
+// call is not needed.
+//
+
+typedef VOID
+(*NB_CALLBACK_NO_TRANSFER) (
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+
+
+//
+// This routine compares two node addresses.
+//
+
+#define NB_NODE_EQUAL(_A,_B) \
+ ((*(UNALIGNED ULONG *)((PUCHAR)(_A)) == *(UNALIGNED ULONG *)((PUCHAR)(_B))) && \
+ (*(UNALIGNED USHORT *)(((PUCHAR)(_A))+4) == *(UNALIGNED USHORT *)(((PUCHAR)(_B))+4)))
+
+//
+// This routine checks if an address is the broadcast address.
+//
+
+#define NB_NODE_BROADCAST(_A) \
+ ((*(UNALIGNED ULONG *)((PUCHAR)(_A)) == 0xffffffff) && \
+ (*(UNALIGNED USHORT *)(((PUCHAR)(_A))+4) == 0xffff))
+
+
+//
+// Definition of the routine to handler a particular minor
+// code for an IOCTL_MJ_INTERNAL_DEVICE_CONTROL IRP.
+//
+
+typedef NTSTATUS
+(*NB_TDI_DISPATCH_ROUTINE) (
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+
+//
+// Routines in action.c
+//
+
+NTSTATUS
+NbiTdiAction(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+//
+// Routines in address.c
+//
+
+TDI_ADDRESS_NETBIOS UNALIGNED *
+NbiParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN BOOLEAN BroadcastAddressOk
+ );
+
+BOOLEAN
+NbiValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength
+ );
+
+NTSTATUS
+NbiOpenAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiStartRegistration(
+ IN PADDRESS Address
+ );
+
+VOID
+NbiRegistrationTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ );
+
+VOID
+NbiProcessFindName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+VOID
+NbiProcessAddName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+NTSTATUS
+NbiOpenConnection(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+PADDRESS
+NbiCreateAddress(
+ IN PDEVICE Device,
+ IN TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress
+ );
+
+NTSTATUS
+NbiVerifyAddressFile (
+#if defined(_PNP_POWER)
+ IN PADDRESS_FILE AddressFile,
+ IN BOOLEAN ConflictIsOk
+#else
+ IN PADDRESS_FILE AddressFile
+#endif _PNP_POWER
+ );
+
+VOID
+NbiDestroyAddress(
+ IN PVOID Parameter
+ );
+
+#if DBG
+
+VOID
+NbiRefAddress(
+ IN PADDRESS Address
+ );
+
+VOID
+NbiRefAddressLock(
+ IN PADDRESS Address
+ );
+
+#endif
+
+VOID
+NbiDerefAddress(
+ IN PADDRESS Address
+ );
+
+PADDRESS_FILE
+NbiCreateAddressFile(
+ IN PDEVICE Device
+ );
+
+NTSTATUS
+NbiDestroyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+#if DBG
+
+VOID
+NbiRefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+NbiRefAddressFileLock(
+ IN PADDRESS_FILE AddressFile
+ );
+
+#endif
+
+VOID
+NbiDerefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+#if !defined(_PNP_POWER)
+PADDRESS
+NbiLookupAddress(
+ IN PDEVICE Device,
+ IN TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress
+ );
+#endif !_PNP_POWER
+
+PADDRESS
+NbiFindAddress(
+ IN PDEVICE Device,
+ IN PUCHAR NetbiosName
+ );
+
+NTSTATUS
+NbiStopAddressFile(
+ IN PADDRESS_FILE AddressFile,
+ IN PADDRESS Address
+ );
+
+NTSTATUS
+NbiCloseAddressFile(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+#if defined(_PNP_POWER)
+PADAPTER_ADDRESS
+NbiCreateAdapterAddress(
+ IN PCHAR AdapterMacAddress
+ );
+
+NTSTATUS
+NbiDestroyAdapterAddress(
+ IN PADAPTER_ADDRESS AdapterAddress OPTIONAL,
+ IN PCHAR AdapterMacAddress OPTIONAL
+ );
+
+PADAPTER_ADDRESS
+NbiFindAdapterAddress(
+ IN PCHAR NetbiosName,
+ IN BOOLEAN LockHeld
+ );
+#endif _PNP_POWER
+
+
+//
+// Routines in bind.c
+//
+
+NTSTATUS
+NbiBind(
+ IN PDEVICE Device,
+ IN PCONFIG Config
+ );
+
+VOID
+NbiUnbind(
+ IN PDEVICE Device
+ );
+
+VOID
+NbiStatus(
+ IN USHORT NicId,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength
+ );
+
+VOID
+NbiLineUp(
+ IN USHORT NicId,
+ IN PIPX_LINE_INFO LineInfo,
+ IN NDIS_MEDIUM DeviceType,
+ IN PVOID ConfigurationData
+ );
+
+VOID
+NbiLineDown(
+ IN USHORT NicId,
+ IN ULONG FwdAdapterCtx
+ );
+
+
+//
+// Routines in cache.c
+//
+
+NTSTATUS
+CacheFindName(
+ IN PDEVICE Device,
+ IN FIND_NAME_TYPE Type,
+ IN PUCHAR RemoteName OPTIONAL,
+ OUT PNETBIOS_CACHE * CacheName
+);
+
+VOID
+FindNameTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ );
+
+VOID
+CacheHandlePending(
+ IN PDEVICE Device,
+ IN PUCHAR RemoteName,
+ IN NETBIOS_NAME_RESULT Result,
+ IN PNETBIOS_CACHE CacheName OPTIONAL
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiProcessNameRecognized(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+PNETBIOS_CACHE
+CacheUpdateNameCache(
+ IN PNETBIOS_CACHE NameCache,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN TDI_ADDRESS_IPX UNALIGNED * SourceAddress,
+ IN BOOLEAN ModifyQueue
+ );
+
+VOID
+CacheUpdateFromAddName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN NB_CONNECTIONLESS UNALIGNED * Connectionless,
+ IN BOOLEAN LocalFrame
+ );
+
+VOID
+NbiProcessDeleteName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+VOID
+InsertInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE CacheEntry
+ );
+
+VOID
+ReinsertInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE OldEntry,
+ IN PNETBIOS_CACHE NewEntry
+ );
+
+VOID
+RemoveFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE CacheEntry
+ );
+
+VOID
+FlushOldFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN USHORT AgeLimit
+ );
+
+VOID
+FlushFailedNetbiosCacheEntries(
+ IN PNETBIOS_CACHE_TABLE CacheTable
+ );
+
+VOID
+RemoveInvalidRoutesFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN NIC_HANDLE UNALIGNED *InvalidNicHandle
+ );
+
+NTSTATUS
+FindInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PUCHAR NameToBeFound,
+ OUT PNETBIOS_CACHE *CacheEntry
+ );
+
+NTSTATUS
+CreateNetbiosCacheTable(
+ IN OUT PNETBIOS_CACHE_TABLE *NewTable,
+ IN USHORT MaxHashIndex
+ );
+
+VOID
+DestroyNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable
+ );
+
+//
+// Routines in connect.c
+//
+
+VOID
+NbiFindRouteComplete(
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute
+ );
+
+NTSTATUS
+NbiOpenConnection(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiStopConnection(
+ IN PCONNECTION Connection,
+ IN NTSTATUS DisconnectStatus
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+NTSTATUS
+NbiCloseConnection(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiAssociateAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiDisassociateAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiListen(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiAccept(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiConnect(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiConnectFindName(
+ IN PDEVICE Device,
+ IN PREQUEST Request,
+ IN PCONNECTION Connection,
+ IN CTELockHandle CancelLH,
+ IN CTELockHandle ConnectionLH,
+ IN CTELockHandle DeviceLH,
+ IN PBOOLEAN pbLockFreed
+ );
+
+NTSTATUS
+NbiTdiDisconnect(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+BOOLEAN
+NbiAssignConnectionId(
+ IN PDEVICE Device,
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiDeassignConnectionId(
+ IN PDEVICE Device,
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiConnectionTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ );
+
+VOID
+NbiCancelListen(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+NbiCancelConnectFindName(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+NbiCancelConnectWaitResponse(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+NbiCancelDisconnectWait(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+PCONNECTION
+NbiLookupConnectionByContext(
+ IN PADDRESS_FILE AddressFile,
+ IN CONNECTION_CONTEXT ConnectionContext
+ );
+
+PCONNECTION
+NbiCreateConnection(
+ IN PDEVICE Device
+ );
+
+NTSTATUS
+NbiVerifyConnection (
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiDestroyConnection(
+ IN PCONNECTION Connection
+ );
+
+#if DBG
+VOID
+NbiRefConnection(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiRefConnectionLock(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiRefConnectionSync(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiDerefConnection(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiDerefConnectionSync(
+ IN PCONNECTION Connection
+ );
+#endif
+
+VOID
+NbiHandleConnectionZero(
+ IN PCONNECTION Connection
+ );
+
+
+//
+// Routines in datagram.c
+//
+
+VOID
+NbiProcessDatagram(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize,
+ IN BOOLEAN Broadcast
+ );
+
+VOID
+NbiIndicateDatagram(
+ IN PADDRESS Address,
+ IN PUCHAR RemoteName,
+ IN PUCHAR Data,
+ IN ULONG DataLength
+ );
+
+NTSTATUS
+NbiTdiSendDatagram(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiTransmitDatagram(
+ IN PNB_SEND_RESERVED Reserved
+ );
+
+NTSTATUS
+NbiTdiReceiveDatagram(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiCancelReceiveDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+
+//
+// Routines in device.c
+//
+
+VOID
+NbiRefDevice(
+ IN PDEVICE Device
+ );
+
+VOID
+NbiDerefDevice(
+ IN PDEVICE Device
+ );
+
+NTSTATUS
+NbiCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN OUT PDEVICE *DevicePtr
+ );
+
+VOID
+NbiDestroyDevice(
+ IN PDEVICE Device
+ );
+
+
+//
+// Routines in driver.c
+//
+
+PVOID
+NbipAllocateMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN BOOLEAN ChargeDevice
+ );
+
+VOID
+NbipFreeMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN BOOLEAN ChargeDevice
+ );
+
+#if DBG
+
+PVOID
+NbipAllocateTaggedMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ );
+
+VOID
+NbipFreeTaggedMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ );
+
+#endif
+
+VOID
+NbiWriteResourceErrorLog(
+ IN PDEVICE Device,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue
+ );
+
+VOID
+NbiWriteGeneralErrorLog(
+ IN PDEVICE Device,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN ULONG DumpDataCount,
+ IN ULONG DumpData[]
+ );
+
+VOID
+NbiWriteOidErrorLog(
+ IN PDEVICE Device,
+ IN NTSTATUS ErrorCode,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR AdapterString,
+ IN ULONG OidValue
+ );
+
+
+//
+// Routines in event.c
+//
+
+NTSTATUS
+NbiTdiSetEventHandler(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+//
+// Routines in frame.c
+//
+
+VOID
+NbiSendNameFrame(
+ IN PADDRESS Address,
+ IN UCHAR NameTypeFlag,
+ IN UCHAR DataStreamType,
+ IN PIPX_LOCAL_TARGET LocalTarget OPTIONAL,
+#if defined(_PNP_POWER)
+ IN NB_CONNECTIONLESS UNALIGNED * ReqFrame OPTIONAL
+#else
+ IN TDI_ADDRESS_IPX UNALIGNED * DestAddress OPTIONAL
+#endif _PNP_POWER
+ );
+
+VOID
+NbiSendSessionInitialize(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiSendSessionInitAck(
+ IN PCONNECTION Connection,
+ IN PUCHAR ExtraData,
+ IN ULONG ExtraDataLength,
+ IN CTELockHandle * LockHandle OPTIONAL
+ );
+
+VOID
+NbiSendDataAck(
+ IN PCONNECTION Connection,
+ IN NB_ACK_TYPE AckType
+ IN NB_LOCK_HANDLE_PARAM (LockHandle)
+ );
+
+VOID
+NbiSendSessionEnd(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiSendSessionEndAck(
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN NB_SESSION UNALIGNED * SessionEnd
+ );
+
+
+//
+// Routines in packet.c
+//
+
+NTSTATUS
+NbiInitializeSendPacket(
+ IN PDEVICE Device,
+ IN NDIS_HANDLE PoolHandle OPTIONAL,
+ IN PNB_SEND_PACKET Packet,
+ IN PUCHAR Header,
+ IN ULONG HeaderLength
+ );
+
+NTSTATUS
+NbiInitializeReceivePacket(
+ IN PDEVICE Device,
+ IN NDIS_HANDLE PoolHandle OPTIONAL,
+ IN PNB_RECEIVE_PACKET Packet
+ );
+
+NTSTATUS
+NbiInitializeReceiveBuffer(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer,
+ IN PUCHAR DataBuffer,
+ IN ULONG DataBufferLength
+ );
+
+VOID
+NbiDeinitializeSendPacket(
+ IN PDEVICE Device,
+ IN PNB_SEND_PACKET Packet,
+ IN ULONG HeaderLength
+ );
+
+VOID
+NbiDeinitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_PACKET Packet
+ );
+
+VOID
+NbiDeinitializeReceiveBuffer(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer
+ );
+
+VOID
+NbiAllocateSendPool(
+ IN PDEVICE Device
+ );
+
+VOID
+NbiAllocateReceivePool(
+ IN PDEVICE Device
+ );
+
+#if defined(_PNP_POWER)
+VOID
+NbiAllocateReceiveBufferPool(
+ IN PDEVICE Device,
+ IN UINT DataLength
+ );
+
+VOID
+NbiReAllocateReceiveBufferPool(
+ IN PWORK_QUEUE_ITEM WorkItem
+ );
+
+VOID
+NbiDestroyReceiveBufferPools(
+ IN PDEVICE Device
+ );
+
+VOID
+NbiPushReceiveBuffer (
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer
+ );
+#else
+VOID
+NbiAllocateReceiveBufferPool(
+ IN PDEVICE Device
+ );
+#endif _PNP_POWER
+
+PSINGLE_LIST_ENTRY
+NbiPopSendPacket(
+ IN PDEVICE Device,
+ IN BOOLEAN LockAcquired
+ );
+
+VOID
+NbiPushSendPacket(
+ IN PNB_SEND_RESERVED Reserved
+ );
+
+VOID
+NbiCheckForWaitPacket(
+ IN PCONNECTION Connection
+ );
+
+PSINGLE_LIST_ENTRY
+NbiPopReceivePacket(
+ IN PDEVICE Device
+ );
+
+PSINGLE_LIST_ENTRY
+NbiPopReceiveBuffer(
+ IN PDEVICE Device
+ );
+
+
+//
+// Routines in query.c
+//
+
+NTSTATUS
+NbiTdiQueryInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiStoreAdapterStatus(
+ IN ULONG MaximumLength,
+ IN USHORT NicId,
+ OUT PVOID * StatusBuffer,
+ OUT ULONG * StatusBufferLength,
+ OUT ULONG * ValidBufferLength
+ );
+
+VOID
+NbiUpdateNetbiosFindName(
+ IN PREQUEST Request,
+#if defined(_PNP_POWER)
+ IN PNIC_HANDLE NicHandle,
+#else
+ IN USHORT NicId,
+#endif _PNP_POWER
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteIpxAddress,
+ IN BOOLEAN Unique
+ );
+
+VOID
+NbiSetNetbiosFindNameInformation(
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiSetInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiProcessStatusQuery(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+VOID
+NbiSendStatusQuery(
+ IN PREQUEST Request
+ );
+
+VOID
+NbiProcessStatusResponse(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ );
+
+
+//
+// Routines in receive.c
+//
+
+
+BOOLEAN
+NbiReceive(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN ULONG FwdAdapterCtx,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize,
+ IN PMDL pMdl
+ );
+
+VOID
+NbiReceiveComplete(
+ IN USHORT NicId
+ );
+
+VOID
+NbiTransferDataComplete(
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ );
+
+VOID
+NbiAcknowledgeReceive(
+ IN PCONNECTION Connection
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiCompleteReceive(
+ IN PCONNECTION Connection,
+ IN BOOLEAN EndOfMessage,
+ IN CTELockHandle CancelLH
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+NTSTATUS
+NbiTdiReceive(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiCancelReceive(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+
+//
+// Routines in send.c
+//
+
+
+VOID
+NbiSendComplete(
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+NbiAssignSequenceAndSend(
+ IN PCONNECTION Connection,
+ IN PNDIS_PACKET Packet
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+NTSTATUS
+NbiTdiSend(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiPacketizeSend(
+ IN PCONNECTION Connection
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiReframeConnection(
+ IN PCONNECTION Connection,
+ IN USHORT ReceiveSequence,
+ IN USHORT BytesReceived,
+ IN BOOLEAN Resend
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiRestartConnection(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiAdvanceUnAckedByBytes(
+ IN PCONNECTION Connection,
+ IN ULONG BytesAcked
+ );
+
+VOID
+NbiAdvanceUnAckedBySequence(
+ IN PCONNECTION Connection,
+ IN USHORT ReceiveSequence
+ );
+
+VOID
+NbiCancelSend(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbiBuildBufferChainFromBufferChain (
+ IN NDIS_HANDLE BufferPoolHandle,
+ IN PNDIS_BUFFER CurrentSourceBuffer,
+ IN ULONG CurrentByteOffset,
+ IN ULONG DesiredLength,
+ OUT PNDIS_BUFFER *DestinationBuffer,
+ OUT PNDIS_BUFFER *NewSourceBuffer,
+ OUT ULONG *NewByteOffset,
+ OUT ULONG *ActualLength
+ );
+
+
+//
+// Routines in session.c
+//
+
+VOID
+NbiProcessSessionData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ );
+
+VOID
+NbiProcessDataAck(
+ IN PCONNECTION Connection,
+ IN NB_SESSION UNALIGNED * Sess,
+ IN PIPX_LOCAL_TARGET RemoteAddress
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiProcessSessionInitialize(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+VOID
+NbiProcessSessionInitAck(
+ IN PCONNECTION Connection,
+ IN NB_SESSION UNALIGNED * Sess
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiProcessSessionEnd(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+VOID
+NbiProcessSessionEndAck(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+
+//
+// Routines in timer.c
+//
+
+VOID
+NbiStartRetransmit(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiStartWatchdog(
+ IN PCONNECTION Connection
+ );
+
+#if DBG
+
+VOID
+NbiStopRetransmit(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiStopWatchdog(
+ IN PCONNECTION Connection
+ );
+
+#else
+
+#define NbiStopRetransmit(_Connection) \
+ (_Connection)->Retransmit = 0;
+
+#define NbiStopWatchdog(_Connection) \
+ (_Connection)->Watchdog = 0;
+
+#endif
+
+VOID
+NbiExpireRetransmit(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiExpireWatchdog(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiShortTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ );
+
+VOID
+NbiLongTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ );
+
+VOID
+NbiStartShortTimer(
+ IN PDEVICE Device
+ );
+
+VOID
+NbiInitializeTimers(
+ IN PDEVICE Device
+ );
+
diff --git a/private/ntos/tdi/isn/nb/nbitypes.h b/private/ntos/tdi/isn/nb/nbitypes.h
new file mode 100644
index 000000000..604df5fb5
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/nbitypes.h
@@ -0,0 +1,1511 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ nbitypes.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 16-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+//
+// For find name requests, defines the current status (SR_FN.Status).
+//
+
+typedef enum {
+ FNStatusNoResponse, // no response has been received
+ FNStatusResponseUnique, // response received, is a unique name
+ FNStatusResponseGroup // response received, is a group name
+};
+
+//
+// Defines the results we can get from sending a series of find
+// names to locate a netbios name.
+//
+
+typedef enum _NETBIOS_NAME_RESULT {
+ NetbiosNameFound, // name was located
+ NetbiosNameNotFoundNormal, // name not found, no response received
+ NetbiosNameNotFoundWanDown // name not found, all lines were down
+} NETBIOS_NAME_RESULT, *PNETBIOS_NAME_RESULT;
+
+
+//
+// Definition of the protocol reserved field of a send packet.
+//
+
+typedef struct _NB_SEND_RESERVED {
+ UCHAR Identifier; // 0 for NB packets
+ BOOLEAN SendInProgress; // used in an NdisSend
+ UCHAR Type; // what to do on completion
+ BOOLEAN OwnedByConnection; // if this is a connection's one packet
+#if defined(_PNP_POWER)
+ PVOID Reserved[SEND_RESERVED_COMMON_SIZE]; // used by ipx for even-padding and local target etc.
+#else
+ PVOID Reserved[2]; // used by ipx for even-padding
+#endif _PNP_POWER
+ LIST_ENTRY GlobalLinkage; // all packets are on this
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free queue
+ LIST_ENTRY WaitLinkage; // when waiting on other queues
+#ifdef NB_TRACK_POOL
+ PVOID Pool; // send pool it was allocated from
+#endif
+ union {
+ struct {
+ UCHAR NetbiosName[16]; // name being searched for
+ UCHAR StatusAndSentOnUpLine; // low nibble: look at FNStatusXXX enum
+ // high nibble: TRUE if while sending, found lan or up wan line
+ UCHAR RetryCount; // number of times sent
+ USHORT SendTime; // based on Device->FindNameTime
+#if !defined(_PNP_POWER)
+ USHORT CurrentNicId; // current nic id it is being sent on
+ USHORT MaximumNicId; // highest one it will be sent on
+#endif !_PNP_POWER
+ struct _NETBIOS_CACHE * NewCache; // new cache entry for group names
+ } SR_FN;
+ struct {
+ struct _ADDRESS * Address; // that owns this packet, if one does
+ PREQUEST Request; // send datagram request
+ struct _ADDRESS_FILE * AddressFile; // that this send is on
+#if !defined(_PNP_POWER)
+ USHORT CurrentNicId; // non-zero for frames that go to all
+#endif !_PNP_POWER
+ UCHAR NameTypeFlag; // save these two values for frames
+ UCHAR DataStreamType; // that need to be sent to all nic id's
+ } SR_NF;
+ struct {
+ PREQUEST DatagramRequest; // holds the passed-in request
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteName; // will be -1 for broadcast
+ struct _ADDRESS_FILE * AddressFile; // that the datagram was sent on
+ struct _NETBIOS_CACHE * Cache; // how to route to the netbios address
+ ULONG CurrentNetwork; // within the cache entry
+ } SR_DG;
+ struct {
+ struct _CONNECTION * Connection; // that this frame was sent on.
+ PREQUEST Request; // that this frame was sent for.
+ ULONG PacketLength; // total packet length.
+ BOOLEAN NoNdisBuffer; // none allocate for send
+ } SR_CO;
+ struct {
+ ULONG ActualBufferLength; // real length of allocated buffer.
+ } SR_AS;
+ } u;
+ PUCHAR Header; // points to the MAC/IPX/NB header
+ PNDIS_BUFFER HeaderBuffer; // the NDIS_BUFFER describing Header
+} NB_SEND_RESERVED, *PNB_SEND_RESERVED;
+
+//
+// Values for Type.
+//
+
+#define SEND_TYPE_NAME_FRAME 1
+#define SEND_TYPE_SESSION_INIT 2
+#define SEND_TYPE_FIND_NAME 3
+#define SEND_TYPE_DATAGRAM 4
+#define SEND_TYPE_SESSION_NO_DATA 5
+#define SEND_TYPE_SESSION_DATA 6
+#define SEND_TYPE_STATUS_QUERY 7
+#define SEND_TYPE_STATUS_RESPONSE 8
+
+#ifdef RSRC_TIMEOUT_DBG
+#define SEND_TYPE_DEATH_PACKET 9
+#endif //RSRC_TIMEOUT_DBG
+
+//
+// Macros to access StatusAndSentOnUpLine.
+//
+
+#define NB_GET_SR_FN_STATUS(_Reserved) \
+ ((_Reserved)->u.SR_FN.StatusAndSentOnUpLine & 0x0f)
+
+#define NB_SET_SR_FN_STATUS(_Reserved,_Value) \
+ (_Reserved)->u.SR_FN.StatusAndSentOnUpLine = \
+ (((_Reserved)->u.SR_FN.StatusAndSentOnUpLine & 0xf0) | (_Value));
+
+#define NB_GET_SR_FN_SENT_ON_UP_LINE(_Reserved) \
+ (((_Reserved)->u.SR_FN.StatusAndSentOnUpLine & 0xf0) != 0)
+
+#define NB_SET_SR_FN_SENT_ON_UP_LINE(_Reserved,_Value) \
+ (_Reserved)->u.SR_FN.StatusAndSentOnUpLine = \
+ (((_Reserved)->u.SR_FN.StatusAndSentOnUpLine & 0x0f) | ((_Value) << 4));
+
+
+//
+// Definition of the protocol reserved field of a receive packet.
+//
+
+typedef struct _NB_RECEIVE_RESERVED {
+ UCHAR Identifier; // 0 for NB packets
+ BOOLEAN TransferInProgress; // used in an NdisTransferData
+ UCHAR Type; // what to do on completion
+#if defined(_PNP_POWER)
+ PVOID Pool; // send pool it was allocated from
+#else
+
+#ifdef IPX_TRACK_POOL
+ PVOID Pool; // send pool it was allocated from
+#endif
+
+#endif _PNP_POWER
+ union {
+ struct {
+ struct _CONNECTION * Connection; // that the transfer is for
+ BOOLEAN EndOfMessage; // this was the last part of a message
+ BOOLEAN CompleteReceive; // receive should be completed
+ BOOLEAN NoNdisBuffer; // user's mdl chain was used
+ BOOLEAN PartialReceive; // (new nb) don't ack this packet
+ } RR_CO;
+ struct {
+ struct _NB_RECEIVE_BUFFER * ReceiveBuffer; // datagram receive buffer
+ } RR_DG;
+ struct {
+ PREQUEST Request; // for this request
+ } RR_AS;
+ } u;
+ LIST_ENTRY GlobalLinkage; // all packets are on this
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free queue
+} NB_RECEIVE_RESERVED, *PNB_RECEIVE_RESERVED;
+
+//
+// Values for Type.
+//
+
+#define RECEIVE_TYPE_DATAGRAM 1
+#define RECEIVE_TYPE_DATA 2
+#define RECEIVE_TYPE_ADAPTER_STATUS 3
+
+
+
+typedef struct _NB_RECEIVE_BUFFER {
+ LIST_ENTRY GlobalLinkage; // all buffers are on this
+#if defined(_PNP_POWER)
+ PVOID Pool; // receive buffer pool was allocated from
+#else
+#ifdef NB_TRACK_POOL
+ PVOID Pool; // receive buffer pool was allocated from
+#endif
+#endif _PNP_POWER
+ struct _ADDRESS * Address; // that the datagram is for
+ SINGLE_LIST_ENTRY PoolLinkage; // when in free pool
+ LIST_ENTRY WaitLinkage; // when in ReceiveDatagrams queue
+ PNDIS_BUFFER NdisBuffer; // describes the data
+ UCHAR RemoteName[16]; // datagram was received from
+ ULONG DataLength; // length for current one, not allocated
+ PUCHAR Data; // points to data to hold packet
+} NB_RECEIVE_BUFFER, *PNB_RECEIVE_BUFFER;
+
+
+//
+// Types to abstract NDIS packets. This is to allow us to
+// switch from using our own memory for packets to using
+// authentically allocated NDIS packets.
+//
+
+//#define NB_OWN_PACKETS 1
+
+#ifdef NB_OWN_PACKETS
+
+#define NDIS_PACKET_SIZE 48
+// #define NDIS_PACKET_SIZE FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])
+
+typedef struct _NB_SEND_PACKET {
+ UCHAR Data[NDIS_PACKET_SIZE+sizeof(NB_SEND_RESERVED)];
+} NB_SEND_PACKET, *PNB_SEND_PACKET;
+
+typedef struct _NB_RECEIVE_PACKET {
+ UCHAR Data[NDIS_PACKET_SIZE+sizeof(NB_RECEIVE_RESERVED)];
+} NB_RECEIVE_PACKET, *PNB_RECEIVE_PACKET;
+
+typedef struct _NB_SEND_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ NB_SEND_PACKET Packets[1];
+ // after the packets the header buffers are allocated also.
+} NB_SEND_POOL, *PNB_SEND_POOL;
+
+typedef struct _NB_RECEIVE_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ NB_RECEIVE_PACKET Packets[1];
+} NB_RECEIVE_POOL, *PNB_RECEIVE_POOL;
+
+#define PACKET(_Packet) ((PNDIS_PACKET)((_Packet)->Data))
+
+#define NbiAllocateSendPacket(_Device,_PoolHandle, _SendPacket,_Status) { \
+ NdisReinitializePacket((PNDIS_PACKET)((_SendPacket)->Data)); \
+ *(_Status) = STATUS_SUCCESS; \
+}
+
+#define NbiAllocateReceivePacket(_Device,_PoolHandle, _ReceivePacket,_Status) { \
+ NdisReinitializePacket((PNDIS_PACKET)((_ReceivePacket)->Data)); \
+ *(_Status) = STATUS_SUCCESS; \
+}
+
+#define NbiFreeSendPacket(_Device,_Packet)
+
+#define NbiFreeReceivePacket(_Device,_Packet)
+
+
+#else // NB_OWN_PACKETS
+
+typedef struct _NB_SEND_PACKET {
+ PNDIS_PACKET Packet;
+} NB_SEND_PACKET, *PNB_SEND_PACKET;
+
+typedef struct _NB_RECEIVE_PACKET {
+ PNDIS_PACKET Packet;
+} NB_RECEIVE_PACKET, *PNB_RECEIVE_PACKET;
+
+typedef struct _NB_PACKET_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ NDIS_HANDLE PoolHandle;
+ NB_SEND_PACKET Packets[1];
+ // after the packets the header buffers are allocated also.
+} NB_SEND_POOL, *PNB_SEND_POOL;
+
+typedef struct _NB_RECEIVE_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ NDIS_HANDLE PoolHandle;
+ NB_RECEIVE_PACKET Packets[1];
+} NB_RECEIVE_POOL, *PNB_RECEIVE_POOL;
+
+#define PACKET(_Packet) ((_Packet)->Packet)
+
+#define NbiAllocateSendPacket(_Device,_PoolHandle, _SendPacket,_Status) { \
+ NdisAllocatePacket(_Status, &(_SendPacket)->Packet, _PoolHandle); \
+}
+
+#define NbiAllocateReceivePacket(_Device, _PoolHandle, _ReceivePacket,_Status) { \
+ NdisAllocatePacket(_Status, &(_ReceivePacket)->Packet, _PoolHandle); \
+}
+
+#define NbiFreeSendPacket(_Device,_Packet) { \
+ NdisFreePacket(PACKET(_Packet)); \
+}
+
+#define NbiFreeReceivePacket(_Device,_Packet) { \
+ NdisFreePacket(PACKET(_Packet)); \
+}
+
+#endif // NB_OWN_PACKETS
+
+#define SEND_RESERVED(_Packet) ((PNB_SEND_RESERVED)((PACKET(_Packet))->ProtocolReserved))
+#define RECEIVE_RESERVED(_Packet) ((PNB_RECEIVE_RESERVED)((PACKET(_Packet))->ProtocolReserved))
+
+
+
+typedef struct _NB_RECEIVE_BUFFER_POOL {
+ LIST_ENTRY Linkage;
+ UINT BufferCount;
+ UINT BufferFree;
+#if defined(_PNP_POWER)
+ UINT BufferDataSize; // allocation size of each buffer data
+#endif _PNP_POWER
+ NB_RECEIVE_BUFFER Buffers[1];
+ // after the packets the data buffers are allocated also.
+} NB_RECEIVE_BUFFER_POOL, *PNB_RECEIVE_BUFFER_POOL;
+
+
+//
+// Tags for memory allocation.
+//
+
+#define MEMORY_CONFIG 0
+#define MEMORY_ADAPTER 1
+#define MEMORY_ADDRESS 2
+#define MEMORY_PACKET 3
+#define MEMORY_CACHE 4
+#define MEMORY_CONNECTION 5
+#define MEMORY_STATUS 6
+#define MEMORY_QUERY 7
+#if defined(_PNP_POWER)
+#define MEMORY_WORK_ITEM 8
+#define MEMORY_ADAPTER_ADDRESS 9
+#endif _PNP_POWER
+
+#if defined(_PNP_POWER)
+#define MEMORY_MAX 10
+#else
+#define MEMORY_MAX 8
+#endif _PNP_POWER
+
+#if DBG
+
+//
+// Holds the allocations for a specific memory type.
+//
+
+typedef struct _MEMORY_TAG {
+ ULONG Tag;
+ ULONG BytesAllocated;
+} MEMORY_TAG, *PMEMORY_TAG;
+
+EXTERNAL_LOCK(NbiMemoryInterlock);
+extern MEMORY_TAG NbiMemoryTag[MEMORY_MAX];
+
+#endif
+
+
+
+//
+// This structure holds a single remote network which a
+// Netbios name exists on.
+//
+
+typedef struct _NETBIOS_NETWORK {
+ ULONG Network;
+ IPX_LOCAL_TARGET LocalTarget;
+} NETBIOS_NETWORK, *PNETBIOS_NETWORK;
+
+//
+// This defines a netbios cache entry for a given name.
+//
+
+typedef struct _NETBIOS_CACHE {
+ UCHAR NetbiosName[16];
+ BOOLEAN Unique;
+ BOOLEAN FailedOnDownWan; // if NetworksUsed == 0, was it due to down wan lines?
+ USHORT TimeStamp; // in seconds - CacheTimeStamp when inserted
+ ULONG ReferenceCount;
+ LIST_ENTRY Linkage;
+ TDI_ADDRESS_IPX FirstResponse;
+ USHORT NetworksAllocated;
+ USHORT NetworksUsed;
+ NETBIOS_NETWORK Networks[1]; // may be more than one of these
+} NETBIOS_CACHE, *PNETBIOS_CACHE;
+
+typedef struct _NETBIOS_CACHE_TABLE {
+ USHORT MaxHashIndex;
+ USHORT CurrentEntries;
+ LIST_ENTRY Bucket[1];
+} NETBIOS_CACHE_TABLE, *PNETBIOS_CACHE_TABLE;
+
+#define NB_NETBIOS_CACHE_TABLE_LARGE 26 // for server
+#define NB_NETBIOS_CACHE_TABLE_SMALL 8 // for workstation
+#define NB_MAX_AVG_CACHE_ENTRIES_PER_BUCKET 8
+
+//
+// This defines the different kind of requests that can be made
+// to CacheFindName().
+//
+
+typedef enum _FIND_NAME_TYPE {
+ FindNameConnect,
+ FindNameNetbiosFindName,
+ FindNameOther
+} FIND_NAME_TYPE, *PFIND_NAME_TYPE;
+
+
+//
+// The number of hash entries in the non-inactive connection
+// database.
+//
+
+#define CONNECTION_HASH_COUNT 8
+
+//
+// Mask and shift to retrieve the hash number from a connection
+// ID.
+//
+
+#define CONNECTION_HASH_MASK 0xe000
+#define CONNECTION_HASH_SHIFT 13
+
+//
+// The maximum connection ID we can assign, not counting the
+// shifted-over hash id (which occupies the top 3 bits of the
+// real id we use on the wire). We can use all the bits except
+// the top one, to prevent an ID of 0xffff being used.
+//
+
+#define CONNECTION_MAXIMUM_ID (USHORT)(~CONNECTION_HASH_MASK & ~1)
+
+//
+// A single connection hash bucket.
+//
+
+typedef struct _CONNECTION_HASH {
+ struct _CONNECTION * Connections;
+ USHORT ConnectionCount;
+ USHORT NextConnectionId;
+} CONNECTION_HASH, *PCONNECTION_HASH;
+
+
+//
+// These are queued in the ConnectIndicationInProgress
+// queue to track indications to TDI clients.
+//
+
+typedef struct _CONNECT_INDICATION {
+ LIST_ENTRY Linkage;
+ UCHAR NetbiosName[16];
+ TDI_ADDRESS_IPX RemoteAddress;
+ USHORT ConnectionId;
+} CONNECT_INDICATION, *PCONNECT_INDICATION;
+
+//
+// This structure defines the per-device structure for NB
+// (one of these is allocated globally).
+//
+
+#define DREF_CREATE 0
+#define DREF_LOADED 1
+#define DREF_ADAPTER 2
+#define DREF_ADDRESS 3
+#define DREF_CONNECTION 4
+#define DREF_FN_TIMER 5
+#define DREF_FIND_NAME 6
+#define DREF_SESSION_INIT 7
+#define DREF_NAME_FRAME 8
+#define DREF_FRAME 9
+#define DREF_SHORT_TIMER 10
+#define DREF_LONG_TIMER 11
+#define DREF_STATUS_QUERY 12
+#define DREF_STATUS_RESPONSE 13
+#define DREF_STATUS_FRAME 14
+#define DREF_NB_FIND_NAME 15
+
+#define DREF_TOTAL 16
+
+typedef struct _DEVICE {
+
+ DEVICE_OBJECT DeviceObject; // the I/O system's device object.
+
+#if DBG
+ ULONG RefTypes[DREF_TOTAL];
+#endif
+
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+#if DBG
+ UCHAR Signature1[4]; // contains "IDC1"
+#endif
+
+ NB_LOCK Interlock; // GLOBAL lock for reference count.
+ // (used in ExInterlockedXxx calls)
+ NB_LOCK Lock;
+ LONG ReferenceCount; // activity count/this provider.
+
+ //
+ // These are kept around for error logging, and stored right
+ // after this structure.
+ //
+
+ PWCHAR DeviceName;
+#if defined(_PNP_POWER)
+ USHORT DeviceNameLength;
+#else
+ ULONG DeviceNameLength;
+#endif _PNP_POWER
+
+ LIST_ENTRY GlobalSendPacketList;
+ LIST_ENTRY GlobalReceivePacketList;
+ LIST_ENTRY GlobalReceiveBufferList;
+
+ //
+ // All send packet pools are chained on this list.
+ //
+
+ LIST_ENTRY SendPoolList;
+ LIST_ENTRY ReceivePoolList;
+ LIST_ENTRY ReceiveBufferPoolList;
+
+ SLIST_HEADER SendPacketList;
+ SLIST_HEADER ReceivePacketList;
+ SINGLE_LIST_ENTRY ReceiveBufferList;
+
+ //
+ // Receive requests waiting to be completed.
+ //
+
+ LIST_ENTRY ReceiveCompletionQueue;
+
+ //
+ // Connections waiting for send packets.
+ //
+
+ LIST_ENTRY WaitPacketConnections;
+
+ //
+ // Connections waiting to packetize.
+ //
+
+ LIST_ENTRY PacketizeConnections;
+
+ //
+ // Connections waiting to send a data ack.
+ //
+
+ LIST_ENTRY DataAckConnections;
+
+ //
+ // The list changed while we were processing it.
+ //
+
+ BOOLEAN DataAckQueueChanged;
+
+ //
+ // Information to manage the Netbios name cache.
+ //
+
+ LIST_ENTRY WaitingConnects; // connect requests waiting for a name
+ LIST_ENTRY WaitingDatagrams; // datagram requests waiting for a name
+ LIST_ENTRY WaitingAdapterStatus; // adapter status requests waiting for a name
+ LIST_ENTRY WaitingNetbiosFindName; // netbios find name requests waiting for a name
+
+ //
+ // Holds adapter status request which have a name and
+ // are waiting for a response. The long timeout aborts
+ // these after a couple of expirations (BUGBUG: currently we
+ // do not do resends).
+ //
+
+ LIST_ENTRY ActiveAdapterStatus;
+
+ //
+ // Receive datagrams waiting to be indicated.
+ //
+
+ LIST_ENTRY ReceiveDatagrams;
+
+ //
+ // In-progress connect indications (used to make
+ // sure we don't indicate the same packet twice).
+ //
+
+ LIST_ENTRY ConnectIndicationInProgress;
+
+ //
+ // Listens that have been posted to connections.
+ //
+
+ LIST_ENTRY ListenQueue;
+
+ UCHAR State;
+
+ //
+ // The following fields control the timer system.
+ // The short timer is used for retransmission and
+ // delayed acks, and the long timer is used for
+ // watchdog timeouts.
+ //
+ BOOLEAN ShortListActive; // ShortList is not empty.
+ BOOLEAN DataAckActive; // DataAckConnections is not empty.
+ BOOLEAN TimersInitialized; // has the timer system been initialized.
+ BOOLEAN ProcessingShortTimer; // TRUE if we are in ScanShortTimer.
+#if defined(_PNP_POWER)
+ BOOLEAN LongTimerRunning; // True if the long timer is running.
+#endif _PNP_POWER
+ LARGE_INTEGER ShortTimerStart; // tick count when the short timer was set.
+ CTETimer ShortTimer; // controls the short timer.
+ ULONG ShortAbsoluteTime; // up-count timer ticks, short timer.
+ CTETimer LongTimer; // kernel DPC object, long timer.
+ ULONG LongAbsoluteTime; // up-count timer ticks, long timer.
+ NB_LOCK TimerLock; // lock for following timer queues
+ LIST_ENTRY ShortList; // list of waiting connections
+ LIST_ENTRY LongList; // list of waiting connections
+
+
+ //
+ // Hash table of non-inactive connections.
+ //
+
+ CONNECTION_HASH ConnectionHash[CONNECTION_HASH_COUNT];
+
+ //
+ // Control the queue of waiting find names.
+ //
+
+ USHORT FindNameTime; // incremented each time the timer runs
+ BOOLEAN FindNameTimerActive; // TRUE if the timer is queued
+ CTETimer FindNameTimer; // runs every FIND_NAME_GRANULARITY
+ ULONG FindNameTimeout; // the retry count in timer ticks
+
+ ULONG FindNamePacketCount; // Count of packets on the queue
+ LIST_ENTRY WaitingFindNames; // FIND_NAME frames waiting to go out
+
+ //
+ // The cache of NETBIOS_CACHE entries.
+ //
+
+ PNETBIOS_CACHE_TABLE NameCache;
+
+ //
+ // The current time stamp, incremented every second.
+ //
+
+ USHORT CacheTimeStamp;
+
+ //
+ // Maximum valid NIC ID we can use.
+ //
+
+ USHORT MaximumNicId;
+
+
+ //
+ // Handle for our binding to the IPX driver.
+ //
+
+ HANDLE BindHandle;
+
+ //
+ // Holds the output from binding to IPX.
+ //
+ union {
+ IPX_INTERNAL_BIND_OUTPUT Bind;
+ IPX_INTERNAL_BIND_INPUT BindInput;
+ };
+
+ //
+ // Holds our reserved netbios name, which is 10 bytes
+ // of zeros followed by our node address.
+ //
+#if !defined(_PNP_POWER)
+ UCHAR ReservedNetbiosName[16];
+#endif !_PNP_POWER
+
+ //
+ // This holds the total memory allocated for the above structures.
+ //
+
+ LONG MemoryUsage;
+ LONG MemoryLimit;
+
+ //
+ // How many packets have been allocated.
+ //
+
+ ULONG AllocatedSendPackets;
+ ULONG AllocatedReceivePackets;
+ ULONG AllocatedReceiveBuffers;
+
+#if defined(_PNP_POWER)
+ //
+ // This is the size of each buffer in the receive buffer pool.
+ // We reallocate buffer pool when the LineInfo.MaxPacketSize changes(increases)
+ // from IPX because of a new adapter. The LineInfo.MaxPacketSize could
+ // also change(decrease) when a adapter disappears but our buffer pool size
+ // will stay at this value.
+ //
+ ULONG CurMaxReceiveBufferSize;
+#endif _PNP_POWER
+
+ //
+ // Other configuration parameters.
+ //
+
+ ULONG AckDelayTime; // converted to short timeouts, rounded up
+ ULONG AckWindow;
+ ULONG AckWindowThreshold;
+ ULONG EnablePiggyBackAck;
+ ULONG Extensions;
+ ULONG RcvWindowMax;
+ ULONG BroadcastCount;
+ ULONG BroadcastTimeout;
+ ULONG ConnectionCount;
+ ULONG ConnectionTimeout;
+ ULONG InitPackets;
+ ULONG MaxPackets;
+ ULONG InitialRetransmissionTime;
+ ULONG Internet;
+ ULONG KeepAliveCount;
+ ULONG KeepAliveTimeout;
+ ULONG RetransmitMax;
+ ULONG RouterMtu;
+
+ ULONG MaxReceiveBuffers;
+
+
+ //
+ // Where we tell upper drivers to put their headers.
+ //
+
+ ULONG IncludedHeaderOffset;
+
+ //
+ // The following field is a head of a list of ADDRESS objects that
+ // are defined for this transport provider. To edit the list, you must
+ // hold the spinlock of the device context object.
+ //
+
+ LIST_ENTRY AddressDatabase; // list of defined transport addresses.
+#if defined(_PNP_POWER)
+ LIST_ENTRY AdapterAddressDatabase; // list of netbios names made from adapter addresses.
+#endif _PNP_POWER
+
+ ULONG AddressCount; // number of addresses in the database.
+
+ NDIS_HANDLE NdisBufferPoolHandle;
+
+#if DBG
+ UCHAR Signature2[4]; // contains "IDC2"
+#endif
+
+ //
+ // This structure holds a pre-built IPX header which is used
+ // to quickly fill in common fields of outgoing connectionless
+ // frames.
+ //
+
+ IPX_HEADER ConnectionlessHeader;
+
+ //
+ // This event is used when unloading to signal that
+ // the reference count is now 0.
+ //
+
+ KEVENT UnloadEvent;
+ BOOLEAN UnloadWaiting;
+
+#if defined(_PNP_POWER)
+ HANDLE TdiRegistrationHandle;
+#endif _PNP_POWER
+
+ //
+ // Counters for most of the statistics that NB maintains;
+ // some of these are kept elsewhere. Including the structure
+ // itself wastes a little space but ensures that the alignment
+ // inside the structure is correct.
+ //
+
+ TDI_PROVIDER_STATISTICS Statistics;
+
+ //
+ // These are "temporary" versions of the other counters.
+ // During normal operations we update these, then during
+ // the short timer expiration we update the real ones.
+ //
+
+ ULONG TempFrameBytesSent;
+ ULONG TempFramesSent;
+ ULONG TempFrameBytesReceived;
+ ULONG TempFramesReceived;
+
+
+ //
+ // This contains the next unique indentified to use as
+ // the FsContext in the file object associated with an
+ // open of the control channel.
+ //
+
+ USHORT ControlChannelIdentifier;
+
+ //
+ // Counters for "active" time.
+ //
+
+ LARGE_INTEGER NbiStartTime;
+
+ //
+ // This array is used to quickly dismiss connectionless frames
+ // that are not destined for us. The count is the number
+ // of addresses with that first letter that are registered
+ // on this device.
+ //
+
+ UCHAR AddressCounts[256];
+
+ //
+ // This resource guards access to the ShareAccess
+ // and SecurityDescriptor fields in addresses.
+ //
+
+ ERESOURCE AddressResource;
+
+ //
+ // The following structure contains statistics counters for use
+ // by TdiQueryInformation and TdiSetInformation. They should not
+ // be used for maintenance of internal data structures.
+ //
+
+ TDI_PROVIDER_INFO Information; // information about this provider.
+
+} DEVICE, * PDEVICE;
+
+
+extern PDEVICE NbiDevice;
+EXTERNAL_LOCK(NbiGlobalPoolInterlock);
+
+//
+// This is used only for CHK build. For
+// tracking the refcount problem on connection, this
+// is moved here for now.
+//
+
+EXTERNAL_LOCK(NbiGlobalInterlock);
+
+
+//
+// device state definitions
+//
+#if defined(_PNP_POWER)
+#define DEVICE_STATE_CLOSED 0x00 // Initial state
+#define DEVICE_STATE_LOADED 0x01 // Loaded and bound to IPX but no adapters
+#define DEVICE_STATE_OPEN 0x02 // Fully operational
+#define DEVICE_STATE_STOPPING 0x03 // Unload has been initiated, The I/O system
+ // will not call us until nobody above has Netbios open.
+#else
+#define DEVICE_STATE_CLOSED 0x00
+#define DEVICE_STATE_OPEN 0x01
+#define DEVICE_STATE_STOPPING 0x02
+#endif _PNP_POWER
+
+
+#define NB_TDI_RESOURCES 9
+
+
+//
+// This structure is pointed to by the FsContext field in the FILE_OBJECT
+// for this Address. This structure is the base for all activities on
+// the open file object within the transport provider. All active connections
+// on the address point to this structure, although no queues exist here to do
+// work from. This structure also maintains a reference to an ADDRESS
+// structure, which describes the address that it is bound to.
+//
+
+#define AFREF_CREATE 0
+#define AFREF_RCV_DGRAM 1
+#define AFREF_SEND_DGRAM 2
+#define AFREF_VERIFY 3
+#define AFREF_INDICATION 4
+#define AFREF_TIMEOUT 5
+#define AFREF_CONNECTION 6
+
+#define AFREF_TOTAL 8
+
+typedef struct _ADDRESS_FILE {
+
+#if DBG
+ ULONG RefTypes[AFREF_TOTAL];
+#endif
+
+ CSHORT Type;
+ CSHORT Size;
+
+ LIST_ENTRY Linkage; // next address file on this address.
+ // also used for linkage in the
+ // look-aside list
+
+ ULONG ReferenceCount; // number of references to this object.
+
+ //
+ // the current state of the address file structure; this is either open or
+ // closing
+ //
+
+ UCHAR State;
+
+ PNB_LOCK AddressLock;
+
+ //
+ // The following fields are kept for housekeeping purposes.
+ //
+
+ PREQUEST OpenRequest; // the request used for open
+ struct _ADDRESS *Address; // address to which we are bound.
+#ifdef ISN_NT
+ PFILE_OBJECT FileObject; // easy backlink to file object.
+#endif
+ struct _DEVICE *Device; // device to which we are attached.
+
+ LIST_ENTRY ConnectionDatabase; // associated with this address.
+
+ LIST_ENTRY ReceiveDatagramQueue; // posted by the client.
+
+ //
+ // This holds the request used to close this address file,
+ // for pended completion.
+ //
+
+ PREQUEST CloseRequest;
+
+ //
+ // Handler for kernel event actions. First we have a set of booleans that
+ // indicate whether or not this address has an event handler of the given
+ // type registered.
+ //
+
+ BOOLEAN RegisteredHandler[6];
+
+ //
+ // This is a list of handlers for a given event. They can be
+ // accessed using the explicit names for type-checking, or the
+ // array (indexed by the event type) for speed.
+ //
+
+ union {
+ struct {
+ PTDI_IND_CONNECT ConnectionHandler;
+ PTDI_IND_DISCONNECT DisconnectHandler;
+ PTDI_IND_ERROR ErrorHandler;
+ PTDI_IND_RECEIVE ReceiveHandler;
+ PTDI_IND_RECEIVE_DATAGRAM ReceiveDatagramHandler;
+ PTDI_IND_RECEIVE_EXPEDITED ExpeditedDataHandler;
+ };
+ PVOID Handlers[6];
+ };
+
+ PVOID HandlerContexts[6];
+
+} ADDRESS_FILE, *PADDRESS_FILE;
+
+#define ADDRESSFILE_STATE_OPENING 0x00 // not yet open for business
+#define ADDRESSFILE_STATE_OPEN 0x01 // open for business
+#define ADDRESSFILE_STATE_CLOSING 0x02 // closing
+
+
+//
+// This structure defines a NETBIOS name as a character array for use when
+// passing preformatted NETBIOS names between internal routines. It is
+// not a part of the external interface to the transport provider.
+//
+
+typedef struct _NBI_NETBIOS_ADDRESS {
+ UCHAR NetbiosName[16];
+ USHORT NetbiosNameType;
+ BOOLEAN Broadcast;
+} NBI_NETBIOS_ADDRESS, *PNBI_NETBIOS_ADDRESS;
+
+//
+// This structure defines an ADDRESS, or active transport address,
+// maintained by the transport provider. It contains all the visible
+// components of the address (such as the TSAP and network name components),
+// and it also contains other maintenance parts, such as a reference count,
+// ACL, and so on. All outstanding connection-oriented and connectionless
+// data transfer requests are queued here.
+//
+
+#define AREF_ADDRESS_FILE 0
+#define AREF_LOOKUP 1
+#define AREF_RECEIVE 2
+#define AREF_NAME_FRAME 3
+#define AREF_TIMER 4
+#define AREF_FIND 5
+
+#define AREF_TOTAL 8
+
+
+typedef struct _ADDRESS {
+
+#if DBG
+ ULONG RefTypes[AREF_TOTAL];
+#endif
+
+ USHORT Size;
+ CSHORT Type;
+
+ LIST_ENTRY Linkage; // next address/this device object.
+ ULONG ReferenceCount; // number of references to this object.
+
+ NB_LOCK Lock;
+
+ //
+ // The following fields comprise the actual address itself.
+ //
+
+ PREQUEST Request; // pointer to address creation request.
+
+ UCHAR NameTypeFlag; // NB_NAME_UNIQUE or NB_NAME_GROUP
+
+ NBI_NETBIOS_ADDRESS NetbiosAddress; // our netbios name.
+
+ //
+ // The following fields are used to maintain state about this address.
+ //
+
+ ULONG Flags; // attributes of the address.
+ ULONG State; // current state of the address.
+ struct _DEVICE *Device; // device context to which we are attached.
+ PNB_LOCK DeviceLock;
+
+ //
+ // The following queues is used to hold send datagrams for this
+ // address. Receive datagrams are queued to the address file. Requests are
+ // processed in a first-in, first-out manner, so that the very next request
+ // to be serviced is always at the head of its respective queue. These
+ // queues are managed by the EXECUTIVE interlocked list management routines.
+ // The actual objects which get queued to this structure are request control
+ // blocks (RCBs).
+ //
+
+ LIST_ENTRY AddressFileDatabase; // list of defined address file objects
+
+ UCHAR SendPacketHeader[NB_MAXIMUM_MAC + sizeof(IPX_HEADER)];
+
+ //
+ // This timer is used for registering the name.
+ //
+
+ CTETimer RegistrationTimer;
+
+ //
+ // Number of times an add name frame has been sent.
+ //
+
+ ULONG RegistrationCount;
+
+#ifdef ISN_NT
+
+ //
+ // These two can be a union because they are not used
+ // concurrently.
+ //
+
+ union {
+
+ //
+ // This structure is used for checking share access.
+ //
+
+ SHARE_ACCESS ShareAccess;
+
+ //
+ // Used for delaying NbiDestroyAddress to a thread so
+ // we can access the security descriptor.
+ //
+
+ WORK_QUEUE_ITEM DestroyAddressQueueItem;
+
+ } u;
+
+ //
+ // This structure is used to hold ACLs on the address.
+
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+
+#endif
+
+} ADDRESS, *PADDRESS;
+
+//
+// Values for Flags
+//
+
+#define ADDRESS_FLAGS_DUPLICATE_NAME 0x00000002
+#if defined(_PNP_POWER)
+#define ADDRESS_FLAGS_CONFLICT 0x00000010
+#endif _PNP_POWER
+
+#if defined(_PNP_POWER)
+//
+// this booleans are passed to nbiverifyaddressfile calls.
+//
+#define CONFLICT_IS_OK TRUE
+#define CONFLICT_IS_NOT_OK FALSE
+#endif _PNP_POWER
+
+//
+// Values for State
+//
+
+#define ADDRESS_STATE_REGISTERING 1
+#define ADDRESS_STATE_OPEN 2
+#define ADDRESS_STATE_STOPPING 3
+
+#if defined(_PNP_POWER)
+//
+// This holds the adapters names i.e netbios names which are
+// created from adater node address to support adapter status
+// queries using adapter node addresses.
+//
+typedef struct _ADAPTER_ADDRESS {
+
+ USHORT Size;
+ CSHORT Type;
+
+ LIST_ENTRY Linkage; // next address/this device object.
+ NIC_HANDLE NicHandle; // NicHandle corresponding to this address.
+ UCHAR NetbiosName[16];
+} ADAPTER_ADDRESS, *PADAPTER_ADDRESS;
+#endif _PNP_POWER
+
+//
+// This defines the types of probe packets we can send.
+//
+
+typedef enum _NB_ACK_TYPE {
+ NbiAckQuery,
+ NbiAckResponse,
+ NbiAckResend
+} NB_ACK_TYPE, *PNB_ACK_TYPE;
+
+
+//
+// This defines the a packetizing location in a
+// send.
+//
+
+typedef struct _SEND_POINTER {
+ ULONG MessageOffset; // up count, bytes sent this message.
+ PREQUEST Request; // current send request in chain.
+ PNDIS_BUFFER Buffer; // current buffer in send chain.
+ ULONG BufferOffset; // current byte offset in current buffer.
+ USHORT SendSequence;
+} SEND_POINTER, *PSEND_POINTER;
+
+//
+// This defines the current location in a receive.
+//
+
+typedef struct _RECEIVE_POINTER {
+ ULONG MessageOffset; // up count, bytes received this message.
+ ULONG Offset; // up count, bytes received this request.
+ PNDIS_BUFFER Buffer; // current buffer in receive request.
+ ULONG BufferOffset; // current byte offset in current buffer.
+} RECEIVE_POINTER, *PRECEIVE_POINTER;
+
+
+//
+// This structure defines a connection, which controls a
+// session with a remote.
+//
+
+#define CREF_VERIFY 0
+#define CREF_LISTEN 1
+#define CREF_CONNECT 2
+#define CREF_WAIT_CACHE 3
+#define CREF_TIMER 4
+#define CREF_INDICATE 5
+#define CREF_ACTIVE 6
+#define CREF_FRAME 7
+#define CREF_BY_CONTEXT 8
+#define CREF_W_ACCEPT 9
+#define CREF_SEND 10
+#define CREF_RECEIVE 11
+#define CREF_PACKETIZE 12
+#define CREF_DISASSOC 13
+#define CREF_W_PACKET 14
+#define CREF_CANCEL 15
+#define CREF_NDIS_SEND 16
+#define CREF_SHORT_D_ACK 17
+#define CREF_LONG_D_ACK 18
+#define CREF_FIND_ROUTE 19
+#define CREF_ACCEPT 20
+
+#define CREF_TOTAL 24
+
+typedef struct _CONNECTION {
+
+#if DBG
+ ULONG RefTypes[CREF_TOTAL];
+#endif
+
+ CSHORT Type;
+ USHORT Size;
+
+ NB_LOCK Lock;
+ PNB_LOCK DeviceLock;
+
+ ULONG ReferenceCount; // number of references to this object.
+
+ CONNECTION_CONTEXT Context; // client-specified value.
+
+ ULONG State;
+ ULONG SubState;
+ ULONG ReceiveState; // SubState tracks sends when active.
+ ULONG NewNetbios; // 1 if we negotiated this.
+
+ REQUEST_LIST_HEAD SendQueue;
+ REQUEST_LIST_HEAD ReceiveQueue;
+
+ USHORT ReceiveSequence;
+
+ USHORT LocalRcvSequenceMax; // we advertise to him (will be near SendSequence)
+ USHORT RemoteRcvSequenceMax; // he advertises to us (will be near ReceiveSequence)
+ USHORT SendWindowSequenceLimit; // when this send window ends (may send past it however)
+
+ //
+ // RemoteRcvSequenceMax is the largest frame number that he expects to
+ // receive, while SendWindowSequenceLimit is one more than the max
+ // we can send. I.e. if he is advertising a window of 4 and we think
+ // the window should be 2, and the current send sequence is 7,
+ // RemoteRcvSequenceMax is 10 and SendWindowSequenceLimit is 9.
+ //
+
+ USHORT ReceiveWindowSize; // when it is open, how big to make it
+ USHORT SendWindowSize; // what we'll send, may be less than what he advertises
+ USHORT MaxSendWindowSize; // maximum we allow it to grow to
+
+ USHORT IncreaseWindowFailures; // how many windows after increase have had retransmits
+ BOOLEAN RetransmitThisWindow; // we had to retransmit in this send window
+ BOOLEAN SendWindowIncrease; // send window was just increased.
+ BOOLEAN ResponseTimeout; // we hit timeout in SEND_W or REMOTE_W
+
+ BOOLEAN SendBufferInUse; // current send's already queued on packet
+
+ ULONG Retries;
+
+ //
+ // Tracks the current send.
+ //
+
+ SEND_POINTER CurrentSend;
+
+ //
+ // Tracks the unacked point in the send.
+ //
+
+ SEND_POINTER UnAckedSend;
+
+ PREQUEST FirstMessageRequest; // first one in the message.
+ PREQUEST LastMessageRequest; // last one in the message.
+
+ ULONG CurrentMessageLength; // total length of current message.
+
+ //
+ // Tracks the current receive.
+ //
+
+ RECEIVE_POINTER CurrentReceive; // where to receive next data
+ RECEIVE_POINTER PreviousReceive; // stores it while transfer in progress
+
+ PREQUEST ReceiveRequest; // current one; not in ReceiveQueue
+ ULONG ReceiveLength; // length of ReceiveRequest
+
+ ULONG ReceiveUnaccepted; // by client...only indicate when == 0
+
+ ULONG CurrentIndicateOffset; // if previous frame was partially accepted.
+
+ IPX_LINE_INFO LineInfo; // for the adapter this connect is on.
+ ULONG MaximumPacketSize; // as negotiated during session init/ack
+
+ //
+ // Links us in the non-inactive connection hash bucket.
+ //
+
+ struct _CONNECTION * NextConnection;
+
+ //
+ // These are used to determine when to piggyback and when not to.
+ //
+
+ BOOLEAN NoPiggybackHeuristic; // we have reason to assume it would be bad.
+ BOOLEAN PiggybackAckTimeout; // we got a timeout last time we tried.
+ ULONG ReceivesWithoutAck; // used to do an auto ack.
+
+ //
+ // The following field is used as linkage in the device's
+ // PacketizeConnections queue.
+ //
+
+ LIST_ENTRY PacketizeLinkage;
+
+ //
+ // The following field is used as linkage in the device's
+ // WaitPacketConnections queue.
+ //
+
+ LIST_ENTRY WaitPacketLinkage;
+
+ //
+ // The following field is used as linkage in the device's
+ // DataAckConnections queue.
+ //
+
+ LIST_ENTRY DataAckLinkage;
+
+ //
+ // TRUE if we are on these queues.
+ //
+
+ BOOLEAN OnPacketizeQueue;
+ BOOLEAN OnWaitPacketQueue;
+ BOOLEAN OnDataAckQueue;
+
+ //
+ // TRUE if we have a piggyback ack pending.
+ //
+
+ BOOLEAN DataAckPending;
+
+ //
+ // TRUE if the current receive does not allow piggyback acks.
+ //
+
+ BOOLEAN CurrentReceiveNoPiggyback;
+
+ //
+ // Number of short timer expirations with the data ack queued.
+ //
+
+ ULONG DataAckTimeouts;
+
+ //
+ // Used to queue sends so that no two are outstanding at once.
+ //
+
+ ULONG NdisSendsInProgress;
+ LIST_ENTRY NdisSendQueue;
+
+ //
+ // This pointer is valid when NdisSendsInProgress is non-zero;
+ // it holds a pointer to a location on the stack of the thread
+ // which is inside NbiAssignSequenceAndSend. If this location
+ // is set to TRUE, it means the connection was stopped by another
+ // thread and a reference was added to keep the connection around.
+ //
+
+ PBOOLEAN NdisSendReference;
+
+ //
+ // These are used for timeouts.
+ //
+
+ ULONG BaseRetransmitTimeout; // config # of short timeouts we wait.
+ ULONG CurrentRetransmitTimeout; // possibly backed-off number
+ ULONG WatchdogTimeout; // how many long timeouts we wait.
+ ULONG Retransmit; // timer; based on Device->ShortAbsoluteTime
+ ULONG Watchdog; // timer; based on Device->LongAbsoluteTime
+ USHORT TickCount; // 18.21/second, # for 576-byte packet.
+ USHORT HopCount; // As returned by ipx on find route.
+ BOOLEAN OnShortList; // are we inserted in the list
+ BOOLEAN OnLongList; // are we inserted in the list
+ LIST_ENTRY ShortList; // queues us on Device->ShortList
+ LIST_ENTRY LongList; // queues us on Device->LongList
+
+ //
+ // These are valid when we have a connection established;
+ //
+
+ USHORT LocalConnectionId;
+ USHORT RemoteConnectionId;
+
+ PREQUEST DisassociatePending; // guarded by device lock.
+ PREQUEST ClosePending;
+
+ PREQUEST ConnectRequest;
+ PREQUEST ListenRequest;
+ PREQUEST AcceptRequest;
+ PREQUEST DisconnectRequest;
+ PREQUEST DisconnectWaitRequest;
+
+ ULONG CanBeDestroyed; // FALSE if reference is non-zero
+ ULONG ThreadsInHandleConnectionZero; // # of threads in HandleConnectionZero
+
+ //
+ // These are used to hold extra data that was sent on a session
+ // init, for use in sending the ack. Generally will be NULL and 0.
+ //
+
+ PUCHAR SessionInitAckData;
+ ULONG SessionInitAckDataLength;
+
+ IPX_LOCAL_TARGET LocalTarget; // for the remote when active.
+ IPX_HEADER RemoteHeader;
+
+ CTETimer Timer;
+
+ PADDRESS_FILE AddressFile; // guarded by device lock if associated.
+ LIST_ENTRY AddressFileLinkage; // guarded by device lock
+ ULONG AddressFileLinked; // TRUE if queued using AddressFileLinkage
+
+ PDEVICE Device;
+#ifdef ISN_NT
+ PFILE_OBJECT FileObject; // easy backlink to file object.
+#endif
+
+ CHAR RemoteName[16]; // for an active connection.
+
+ IPX_FIND_ROUTE_REQUEST FindRouteRequest; // use this to verify route.
+
+ TDI_CONNECTION_INFO ConnectionInfo; // can be queried from above.
+
+ BOOLEAN FindRouteInProgress; // we have a request pending.
+
+ BOOLEAN SendPacketInUse; // put this here to align packet/header.
+ BOOLEAN IgnoreNextDosProbe;
+
+ NTSTATUS Status; // status code for connection rundown.
+
+#ifdef RSRC_TIMEOUT_DBG
+ LARGE_INTEGER FirstMessageRequestTime;
+#endif //RSRC_TIMEOUT_DBG
+
+ NDIS_HANDLE SendPacketPoolHandle; // poolhandle for sendpacket below when
+ // the packet is allocated from ndis pool.
+
+ NB_SEND_PACKET SendPacket; // try to use this first for sends
+
+ ULONG Flags; // miscellaneous connection flags
+
+ UCHAR SendPacketHeader[1]; // connection is extended to include this
+
+ //
+ // NOTE: This is variable length structure!
+ // Do not add fields below this comment.
+ //
+} CONNECTION, *PCONNECTION;
+
+
+#define CONNECTION_STATE_INACTIVE 1
+#define CONNECTION_STATE_CONNECTING 2
+#define CONNECTION_STATE_LISTENING 3
+#define CONNECTION_STATE_ACTIVE 4
+#define CONNECTION_STATE_DISCONNECT 5
+#define CONNECTION_STATE_CLOSING 6
+
+
+#define CONNECTION_SUBSTATE_L_WAITING 1 // queued by a listen
+#define CONNECTION_SUBSTATE_L_W_ACCEPT 2 // waiting for user to accept
+#define CONNECTION_SUBSTATE_L_W_ROUTE 3 // waiting for rip response
+
+#define CONNECTION_SUBSTATE_C_FIND_NAME 1 // waiting for cache response
+#define CONNECTION_SUBSTATE_C_W_ACK 2 // waiting for session init ack
+#define CONNECTION_SUBSTATE_C_W_ROUTE 3 // waiting for rip response
+#define CONNECTION_SUBSTATE_C_DISCONN 4 // disconnect was issued
+
+#define CONNECTION_SUBSTATE_A_IDLE 1 // no sends in progress
+#define CONNECTION_SUBSTATE_A_PACKETIZE 2 // packetizing a send
+#define CONNECTION_SUBSTATE_A_W_ACK 3 // waiting for an ack
+#define CONNECTION_SUBSTATE_A_W_PACKET 4 // waiting for a packet
+#define CONNECTION_SUBSTATE_A_W_EOR 5 // waiting for eor to start packetizing
+#define CONNECTION_SUBSTATE_A_W_PROBE 6 // waiting for a keep-alive response
+#define CONNECTION_SUBSTATE_A_REMOTE_W 7 // remote shut down our window
+
+#define CONNECTION_RECEIVE_IDLE 1 // no receives queued
+#define CONNECTION_RECEIVE_ACTIVE 2 // receive is queued
+#define CONNECTION_RECEIVE_W_RCV 3 // waiting for receive to be posted
+#define CONNECTION_RECEIVE_INDICATE 4 // indication in progress
+#define CONNECTION_RECEIVE_TRANSFER 5 // transfer is in progress
+#define CONNECTION_RECEIVE_PENDING 6 // last request is queued for completion
+
+#define CONNECTION_SUBSTATE_D_W_ACK 1
+#define CONNECTION_SUBSTATE_D_GOT_ACK 2
+
+//
+// Bit values for Flags field in
+// the CONNECTION structure.
+//
+#define CONNECTION_FLAGS_AUTOCONNECTING 0x00000001 // RAS autodial in progress
+#define CONNECTION_FLAGS_AUTOCONNECTED 0x00000002 // RAS autodial connected
+
+#ifdef RSRC_TIMEOUT_DBG
+extern ULONG NbiGlobalDebugResTimeout;
+extern LARGE_INTEGER NbiGlobalMaxResTimeout;
+extern NB_SEND_PACKET NbiGlobalDeathPacket; // try to use this first for sends
+#endif //RSRC_TIMEOUT_DBG
diff --git a/private/ntos/tdi/isn/nb/nwlnknb.ini b/private/ntos/tdi/isn/nb/nwlnknb.ini
new file mode 100644
index 000000000..e2df88f54
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/nwlnknb.ini
@@ -0,0 +1,43 @@
+\Registry\Machine\System\CurrentControlSet\Services\NwlnkNb
+ Type = REG_DWORD 0x00000001
+ Start = REG_DWORD 0x00000003
+ ErrorControl = REG_DWORD 0x00000001
+ ImagePath = REG_EXPAND_SZ \SystemRoot\System32\drivers\nwlnknb.sys
+ DisplayName = NWLINK2 IPX Netbios Protocol
+ Group = TDI
+ DependOnService = REG_MULTI_SZ "NwlnkIpx"
+ DependOnGroup = REG_MULTI_SZ "NDIS"
+ Linkage
+ Bind = REG_MULTI_SZ "\Device\NwlnkIpx"
+ Export = REG_MULTI_SZ "\Device\NwlnkNb"
+ Route = REG_MULTI_SZ ""NwlnkIpx""
+ Disabled
+ Bind = REG_MULTI_SZ
+ Export = REG_MULTI_SZ
+ Route = REG_MULTI_SZ
+ Parameters
+ AckDelayTime = REG_DWORD 0x000000fa
+ AckWindow = REG_DWORD 0x00000002
+ AckWindowThreshold = REG_DWORD 0x000001f4
+ EnablePiggyBackAck = REG_DWORD 0x00000001
+ Extensions = REG_DWORD 0x00000001
+ RcvWindowMax = REG_DWORD 0x00000004
+ BroadcastCount = REG_DWORD 0x00000003
+ BroadcastTimeout = REG_DWORD 0x00000001
+ ConnectionCount = REG_DWORD 0x00000005
+ ConnectionTimeout = REG_DWORD 0x00000002
+ InitPackets= REG_DWORD 0x00000005
+ MaxPackets = REG_DWORD 0x0000001e
+ InitialRetransmissionTime = REG_DWORD 0x000001f4
+ Internet = REG_DWORD 0x00000001
+ KeepAliveCount = REG_DWORD 0x00000008
+ KeepAliveTimeout = REG_DWORD 0x0000003c
+ RetransmitMax = REG_DWORD 0x00000008
+ Performance
+ Library = Perfctrs.dll
+ Open = OpenNbfPerformanceData
+ Collect = CollectNbfPerformanceData
+ Close = CloseNbfPerformanceData
+\Registry\Machine\System\CurrentControlSet\Services\EventLog\System\NwlnkNb
+ EventMessageFile = REG_EXPAND_SZ %SystemRoot%\System32\netevent.dll
+ TypesSupported = REG_DWORD 0x00000007
diff --git a/private/ntos/tdi/isn/nb/nwlnknb.rc b/private/ntos/tdi/isn/nb/nwlnknb.rc
new file mode 100644
index 000000000..1b0163cf3
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/nwlnknb.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "NWLINK2 IPX Netbios Protocol Driver"
+#define VER_INTERNALNAME_STR "nwlnknb.sys"
+#define VER_ORIGINALFILENAME_STR "nwlnknb.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/tdi/isn/nb/packet.c b/private/ntos/tdi/isn/nb/packet.c
new file mode 100644
index 000000000..7e22534a8
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/packet.c
@@ -0,0 +1,1482 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ packet.c
+
+Abstract:
+
+ This module contains code that implements the SEND_PACKET and
+ RECEIVE_PACKET objects, which describe NDIS packets used
+ by the transport.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Local Function Protos
+//
+#if defined(_PNP_POWER)
+#if !defined(DBG)
+__inline
+#endif
+VOID
+NbiFreeReceiveBufferPool (
+ IN PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool
+ );
+#endif _PNP_POWER
+
+
+NTSTATUS
+NbiInitializeSendPacket(
+ IN PDEVICE Device,
+ IN NDIS_HANDLE PoolHandle OPTIONAL,
+ IN PNB_SEND_PACKET Packet,
+ IN PUCHAR Header,
+ IN ULONG HeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a send packet by chaining the
+ buffer for the header on it.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD,
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+ PoolHandle - Ndis packet pool handle if !NB_OWN_PACKETS
+
+ Packet - The packet to initialize.
+
+ Header - Points to storage for the header.
+
+ HeaderLength - The length of the header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ NTSTATUS Status;
+ PNDIS_BUFFER NdisBuffer;
+ PNDIS_BUFFER NdisNbBuffer;
+ PNB_SEND_RESERVED Reserved;
+ ULONG MacHeaderNeeded = NbiDevice->Bind.MacHeaderNeeded;
+
+ NbiAllocateSendPacket (Device, PoolHandle, Packet, &Status);
+
+ if (Status != STATUS_SUCCESS) {
+ // ERROR LOG
+ return Status;
+ }
+// DbgPrint("NbiInitializeSendPacket: PACKET is (%x)\n", PACKET(Packet));
+
+ //
+ // allocate the mac header.
+ //
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Device->NdisBufferPoolHandle,
+ Header,
+ MacHeaderNeeded);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbiFreeSendPacket (Device, Packet);
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NdisChainBufferAtFront (PACKET(Packet), NdisBuffer);
+
+// DbgPrint("NbiInitializeSendPacket: MAC header address is (%x)\n", NdisBuffer);
+ //
+ // Allocate the nb header
+ //
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisNbBuffer,
+ Device->NdisBufferPoolHandle,
+ Header + MacHeaderNeeded,
+ HeaderLength - MacHeaderNeeded);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NdisUnchainBufferAtFront (PACKET(Packet), &NdisBuffer);
+ CTEAssert (NdisBuffer);
+
+ NdisAdjustBufferLength (NdisBuffer, MacHeaderNeeded);
+ NdisFreeBuffer (NdisBuffer);
+ NbiFreeSendPacket (Device, Packet);
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // DbgPrint("NbiInitializeSendPacket: IPX header address is (%x)\n", NdisNbBuffer);
+ NdisChainBufferAtBack (PACKET(Packet), NdisNbBuffer);
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->Identifier = IDENTIFIER_NB;
+ Reserved->SendInProgress = FALSE;
+ Reserved->OwnedByConnection = FALSE;
+ Reserved->Header = Header;
+ Reserved->HeaderBuffer = NdisBuffer;
+
+ Reserved->Reserved[0] = NULL;
+ Reserved->Reserved[1] = NULL;
+
+ InsertHeadList(
+ &Device->GlobalSendPacketList,
+ &Reserved->GlobalLinkage);
+
+ return STATUS_SUCCESS;
+
+} /* NbiInitializeSendPacket */
+
+
+NTSTATUS
+NbiInitializeReceivePacket(
+ IN PDEVICE Device,
+ IN NDIS_HANDLE PoolHandle OPTIONAL,
+ IN PNB_RECEIVE_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive packet.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD,
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+ PoolHandle - Ndis packet pool handle if !NB_OWN_PACKETS
+
+ Packet - The packet to initialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ PNB_RECEIVE_RESERVED Reserved;
+
+ NbiAllocateReceivePacket (Device, PoolHandle, Packet, &Status);
+
+ if (Status != STATUS_SUCCESS) {
+ // ERROR LOG
+ return Status;
+ }
+
+ Reserved = RECEIVE_RESERVED(Packet);
+ Reserved->Identifier = IDENTIFIER_NB;
+ Reserved->TransferInProgress = FALSE;
+
+ InsertHeadList(
+ &Device->GlobalReceivePacketList,
+ &Reserved->GlobalLinkage);
+
+ return STATUS_SUCCESS;
+
+} /* NbiInitializeReceivePacket */
+
+
+NTSTATUS
+NbiInitializeReceiveBuffer(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer,
+ IN PUCHAR DataBuffer,
+ IN ULONG DataBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive buffer by allocating
+ an NDIS_BUFFER to describe the data buffer.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD,
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+ ReceiveBuffer - The receive buffer to initialize.
+
+ DataBuffer - The data buffer.
+
+ DataBufferLength - The length of the data buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ PNDIS_BUFFER NdisBuffer;
+
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Device->NdisBufferPoolHandle,
+ DataBuffer,
+ DataBufferLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ ReceiveBuffer->NdisBuffer = NdisBuffer;
+ ReceiveBuffer->Data = DataBuffer;
+ ReceiveBuffer->DataLength = 0;
+
+ InsertHeadList(
+ &Device->GlobalReceiveBufferList,
+ &ReceiveBuffer->GlobalLinkage);
+
+ return STATUS_SUCCESS;
+
+} /* NbiInitializeReceiveBuffer */
+
+
+
+VOID
+NbiDeinitializeSendPacket(
+ IN PDEVICE Device,
+ IN PNB_SEND_PACKET Packet,
+ IN ULONG HeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a send packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to deinitialize.
+
+ HeaderLength - The length of the first buffer on the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_BUFFER NdisBuffer;
+ PNB_SEND_RESERVED Reserved;
+ CTELockHandle LockHandle;
+ ULONG MacHeaderNeeded = NbiDevice->Bind.MacHeaderNeeded;
+
+ CTEAssert(HeaderLength > MacHeaderNeeded);
+ Reserved = SEND_RESERVED(Packet);
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Reserved->GlobalLinkage);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Free the mac header
+ //
+ // DbgPrint("NbiDeinitializeSendPacket: PACKET is (%x)\n", PACKET(Packet));
+ NdisUnchainBufferAtFront (PACKET(Packet), &NdisBuffer);
+ CTEAssert (NdisBuffer);
+ // DbgPrint("NbiDeinitializeSendPacket: MAC header address is (%x)\n", NdisBuffer);
+
+ NdisAdjustBufferLength (NdisBuffer, MacHeaderNeeded);
+ NdisFreeBuffer (NdisBuffer);
+
+ //
+ // Free the nb header
+ //
+ NdisUnchainBufferAtFront (PACKET(Packet), &NdisBuffer);
+ // DbgPrint("NbiDeinitializeSendPacket: IPX header address is (%x)\n", NdisBuffer);
+ CTEAssert (NdisBuffer);
+
+ NdisAdjustBufferLength (NdisBuffer, HeaderLength - MacHeaderNeeded);
+ NdisFreeBuffer (NdisBuffer);
+
+ //
+ // free the packet
+ //
+ NbiFreeSendPacket (Device, Packet);
+
+} /* NbiDeinitializeSendPacket */
+
+
+VOID
+NbiDeinitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to initialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNB_RECEIVE_RESERVED Reserved;
+ CTELockHandle LockHandle;
+
+ Reserved = RECEIVE_RESERVED(Packet);
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Reserved->GlobalLinkage);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ NbiFreeReceivePacket (Device, Packet);
+
+} /* NbiDeinitializeReceivePacket */
+
+
+
+VOID
+NbiDeinitializeReceiveBuffer(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a receive buffer.
+
+Arguments:
+
+ Device - The device.
+
+ ReceiveBuffer - The receive buffer.
+
+Return Value:
+
+ None.
+
+ THIS ROUTINE SHOULD BE CALLED WITH THE DEVICE LOCK HELD. If this
+ routine also called from the DestroyDevice routine, it is not
+ necessary to call this with the lock.
+
+--*/
+
+{
+#if defined(_PNP_POWER)
+ RemoveEntryList (&ReceiveBuffer->GlobalLinkage);
+#else
+ CTELockHandle LockHandle;
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+ RemoveEntryList (&ReceiveBuffer->GlobalLinkage);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+#endif _PNP_POWER
+
+ NdisFreeBuffer (ReceiveBuffer->NdisBuffer);
+
+} /* NbiDeinitializeReceiveBuffer */
+
+
+
+VOID
+NbiAllocateSendPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 packets to the pool for this device.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNB_SEND_POOL SendPool;
+ UINT SendPoolSize;
+ UINT PacketNum;
+ PNB_SEND_PACKET Packet;
+ PNB_SEND_RESERVED Reserved;
+ PUCHAR Header;
+ ULONG HeaderLength;
+ NTSTATUS Status;
+
+ HeaderLength = Device->Bind.MacHeaderNeeded + sizeof(NB_CONNECTIONLESS);
+ SendPoolSize = FIELD_OFFSET (NB_SEND_POOL, Packets[0]) +
+ (sizeof(NB_SEND_PACKET) * Device->InitPackets) +
+ (HeaderLength * Device->InitPackets);
+
+ SendPool = (PNB_SEND_POOL)NbiAllocateMemory (SendPoolSize, MEMORY_PACKET, "SendPool");
+ if (SendPool == NULL) {
+ NB_DEBUG (PACKET, ("Could not allocate send pool memory\n"));
+ return;
+ }
+
+ RtlZeroMemory (SendPool, SendPoolSize);
+
+
+#if !defined(NB_OWN_PACKETS)
+ //
+ // Now allocate the ndis packet pool
+ //
+ NdisAllocatePacketPool( &Status, &SendPool->PoolHandle, Device->InitPackets, sizeof(NB_SEND_RESERVED));
+ if (!NT_SUCCESS(Status)){
+ NB_DEBUG (PACKET, ("Could not allocate Ndis Packet Pool memory\n"));
+ NbiFreeMemory( SendPool, SendPoolSize, MEMORY_PACKET, "Send Pool Freed");
+ return;
+ }
+#endif
+
+ NB_DEBUG2 (PACKET, ("Initializing send pool %lx, %d packets, header %d\n",
+ SendPool, Device->InitPackets, HeaderLength));
+
+ Header = (PUCHAR)(&SendPool->Packets[Device->InitPackets]);
+
+ for (PacketNum = 0; PacketNum < Device->InitPackets; PacketNum++) {
+
+ Packet = &SendPool->Packets[PacketNum];
+
+ if (NbiInitializeSendPacket (
+ Device,
+#ifdef NB_OWN_PACKETS
+ NULL,
+#else
+ SendPool->PoolHandle,
+#endif
+ Packet,
+ Header,
+ HeaderLength) != STATUS_SUCCESS) {
+ NB_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->u.SR_NF.Address = NULL;
+#ifdef NB_TRACK_POOL
+ Reserved->Pool = SendPool;
+#endif
+
+ Header += HeaderLength;
+
+ }
+
+ SendPool->PacketCount = PacketNum;
+ SendPool->PacketFree = PacketNum;
+
+ for (PacketNum = 0; PacketNum < SendPool->PacketCount; PacketNum++) {
+
+ Packet = &SendPool->Packets[PacketNum];
+ Reserved = SEND_RESERVED(Packet);
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ }
+
+ InsertTailList (&Device->SendPoolList, &SendPool->Linkage);
+
+ Device->AllocatedSendPackets += SendPool->PacketCount;
+
+} /* NbiAllocateSendPool */
+
+
+VOID
+NbiAllocateReceivePool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 5 receive packets to the pool for this device.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNB_RECEIVE_POOL ReceivePool;
+ UINT ReceivePoolSize;
+ UINT PacketNum;
+ PNB_RECEIVE_PACKET Packet;
+ PNB_RECEIVE_RESERVED Reserved;
+ NTSTATUS Status;
+
+ ReceivePoolSize = FIELD_OFFSET (NB_RECEIVE_POOL, Packets[0]) +
+ (sizeof(NB_RECEIVE_PACKET) * Device->InitPackets);
+
+ ReceivePool = (PNB_RECEIVE_POOL)NbiAllocateMemory (ReceivePoolSize, MEMORY_PACKET, "ReceivePool");
+ if (ReceivePool == NULL) {
+ NB_DEBUG (PACKET, ("Could not allocate receive pool memory\n"));
+ return;
+ }
+
+ RtlZeroMemory (ReceivePool, ReceivePoolSize);
+
+#if !defined(NB_OWN_PACKETS)
+ //
+ // Now allocate the ndis packet pool
+ //
+ NdisAllocatePacketPool( &Status, &ReceivePool->PoolHandle, Device->InitPackets, sizeof(NB_RECEIVE_RESERVED));
+ if (!NT_SUCCESS(Status)){
+ NB_DEBUG (PACKET, ("Could not allocate Ndis Packet Pool memory\n"));
+ NbiFreeMemory( ReceivePool, ReceivePoolSize, MEMORY_PACKET, "Receive Pool Freed");
+ return;
+ }
+#endif NB_OWN_PACKETS
+
+ NB_DEBUG2 (PACKET, ("Initializing receive pool %lx, %d packets\n",
+ ReceivePool, Device->InitPackets));
+
+ for (PacketNum = 0; PacketNum < Device->InitPackets; PacketNum++) {
+
+ Packet = &ReceivePool->Packets[PacketNum];
+
+ if (NbiInitializeReceivePacket (
+ Device,
+#ifdef NB_OWN_PACKETS
+ NULL,
+#else
+ ReceivePool->PoolHandle,
+#endif
+ Packet) != STATUS_SUCCESS) {
+ NB_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = RECEIVE_RESERVED(Packet);
+#ifdef NB_TRACK_POOL
+ Reserved->Pool = ReceivePool;
+#endif
+
+ }
+
+ ReceivePool->PacketCount = PacketNum;
+ ReceivePool->PacketFree = PacketNum;
+
+ for (PacketNum = 0; PacketNum < ReceivePool->PacketCount; PacketNum++) {
+
+ Packet = &ReceivePool->Packets[PacketNum];
+ Reserved = RECEIVE_RESERVED(Packet);
+ ExInterlockedPushEntrySList(
+ &Device->ReceivePacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+// PushEntryList (&Device->ReceivePacketList, &Reserved->PoolLinkage);
+
+ }
+
+ InsertTailList (&Device->ReceivePoolList, &ReceivePool->Linkage);
+
+ Device->AllocatedReceivePackets += ReceivePool->PacketCount;
+
+} /* NbiAllocateReceivePool */
+
+
+#if defined(_PNP_POWER)
+
+VOID
+NbiAllocateReceiveBufferPool(
+ IN PDEVICE Device,
+ IN UINT DataLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds receive buffers to the pool for this device.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+ DataLength - Max length of the data in each buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ UINT ReceiveBufferPoolSize;
+ UINT BufferNum;
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ PUCHAR Data;
+
+
+ ReceiveBufferPoolSize = FIELD_OFFSET (NB_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(NB_RECEIVE_BUFFER) * Device->InitPackets) +
+ (DataLength * Device->InitPackets);
+
+ ReceiveBufferPool = (PNB_RECEIVE_BUFFER_POOL)NbiAllocateMemory (ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+ if (ReceiveBufferPool == NULL) {
+ NB_DEBUG (PACKET, ("Could not allocate receive buffer pool memory\n"));
+ return;
+ }
+
+ RtlZeroMemory (ReceiveBufferPool, ReceiveBufferPoolSize);
+
+ NB_DEBUG2 (PACKET, ("Initializing receive buffer pool %lx, %d buffers, data %d\n",
+ ReceiveBufferPool, Device->InitPackets, DataLength));
+
+ Data = (PUCHAR)(&ReceiveBufferPool->Buffers[Device->InitPackets]);
+
+ for (BufferNum = 0; BufferNum < Device->InitPackets; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+
+ if (NbiInitializeReceiveBuffer (Device, ReceiveBuffer, Data, DataLength) != STATUS_SUCCESS) {
+ NB_DEBUG (PACKET, ("Could not initialize buffer %lx\n", ReceiveBuffer));
+ break;
+ }
+
+ ReceiveBuffer->Pool = ReceiveBufferPool;
+
+ Data += DataLength;
+
+ }
+
+ ReceiveBufferPool->BufferCount = BufferNum;
+ ReceiveBufferPool->BufferFree = BufferNum;
+ ReceiveBufferPool->BufferDataSize = DataLength;
+
+ for (BufferNum = 0; BufferNum < ReceiveBufferPool->BufferCount; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+ PushEntryList (&Device->ReceiveBufferList, &ReceiveBuffer->PoolLinkage);
+
+ }
+
+ InsertTailList (&Device->ReceiveBufferPoolList, &ReceiveBufferPool->Linkage);
+
+ Device->AllocatedReceiveBuffers += ReceiveBufferPool->BufferCount;
+ Device->CurMaxReceiveBufferSize = DataLength;
+
+} /* NbiAllocateReceiveBufferPool */
+#else
+
+VOID
+NbiAllocateReceiveBufferPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds receive buffers to the pool for this device.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ UINT ReceiveBufferPoolSize;
+ UINT BufferNum;
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ UINT DataLength;
+ PUCHAR Data;
+
+ DataLength = Device->Bind.LineInfo.MaximumPacketSize;
+
+ ReceiveBufferPoolSize = FIELD_OFFSET (NB_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(NB_RECEIVE_BUFFER) * Device->InitPackets) +
+ (DataLength * Device->InitPackets);
+
+ ReceiveBufferPool = (PNB_RECEIVE_BUFFER_POOL)NbiAllocateMemory (ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+ if (ReceiveBufferPool == NULL) {
+ NB_DEBUG (PACKET, ("Could not allocate receive buffer pool memory\n"));
+ return;
+ }
+
+ RtlZeroMemory (ReceiveBufferPool, ReceiveBufferPoolSize);
+
+ NB_DEBUG2 (PACKET, ("Initializing receive buffer pool %lx, %d buffers, data %d\n",
+ ReceiveBufferPool, Device->InitPackets, DataLength));
+
+ Data = (PUCHAR)(&ReceiveBufferPool->Buffers[Device->InitPackets]);
+
+ for (BufferNum = 0; BufferNum < Device->InitPackets; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+
+ if (NbiInitializeReceiveBuffer (Device, ReceiveBuffer, Data, DataLength) != STATUS_SUCCESS) {
+ NB_DEBUG (PACKET, ("Could not initialize buffer %lx\n", ReceiveBuffer));
+ break;
+ }
+
+#ifdef NB_TRACK_POOL
+ ReceiveBuffer->Pool = ReceiveBufferPool;
+#endif
+
+ Data += DataLength;
+
+ }
+
+ ReceiveBufferPool->BufferCount = BufferNum;
+ ReceiveBufferPool->BufferFree = BufferNum;
+
+ for (BufferNum = 0; BufferNum < ReceiveBufferPool->BufferCount; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+ PushEntryList (&Device->ReceiveBufferList, &ReceiveBuffer->PoolLinkage);
+
+ }
+
+ InsertTailList (&Device->ReceiveBufferPoolList, &ReceiveBufferPool->Linkage);
+
+ Device->AllocatedReceiveBuffers += ReceiveBufferPool->BufferCount;
+
+} /* NbiAllocateReceiveBufferPool */
+#endif _PNP_POWER
+
+#if defined(_PNP_POWER)
+
+VOID
+NbiReAllocateReceiveBufferPool(
+ IN PWORK_QUEUE_ITEM WorkItem
+ )
+
+/*++
+
+Routine Description:
+
+ This routines destroys all the existing Buffer Pools and creates
+ new one using the larger packet size given to us by IPX because
+ a new card was inserted with a larger packet size.
+
+Arguments:
+
+ WorkItem - The work item that was allocated for this.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PDEVICE Device = NbiDevice;
+ CTELockHandle LockHandle;
+
+ NB_GET_LOCK ( &Device->Lock, &LockHandle );
+
+ if ( Device->Bind.LineInfo.MaximumPacketSize > Device->CurMaxReceiveBufferSize ) {
+
+#if DBG
+ DbgPrint("Reallocating new pools due to new maxpacketsize\n");
+#endif
+ NbiDestroyReceiveBufferPools( Device );
+ NbiAllocateReceiveBufferPool( Device, Device->Bind.LineInfo.MaximumPacketSize );
+
+ }
+
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+
+ NbiFreeMemory( WorkItem, sizeof(WORK_QUEUE_ITEM), MEMORY_WORK_ITEM, "Alloc Rcv Buff Work Item freed");
+}
+
+#if !defined(DBG)
+__inline
+#endif
+VOID
+NbiFreeReceiveBufferPool (
+ IN PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees the
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+{
+ PDEVICE Device = NbiDevice;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ UINT ReceiveBufferPoolSize,i;
+
+ CTEAssert( ReceiveBufferPool->BufferDataSize );
+
+ ReceiveBufferPoolSize = FIELD_OFFSET (NB_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(NB_RECEIVE_BUFFER) * Device->InitPackets) +
+ (ReceiveBufferPool->BufferDataSize * Device->InitPackets);
+
+ //
+ // Check if we can free this pool
+ //
+ CTEAssert(ReceiveBufferPool->BufferCount == ReceiveBufferPool->BufferFree );
+
+ for (i = 0; i < ReceiveBufferPool->BufferCount; i++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[i];
+ NbiDeinitializeReceiveBuffer (Device, ReceiveBuffer);
+
+ }
+
+ RemoveEntryList( &ReceiveBufferPool->Linkage );
+
+ NB_DEBUG2 (PACKET, ("Free buffer pool %lx\n", ReceiveBufferPool));
+
+ NbiFreeMemory (ReceiveBufferPool, ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+
+}
+
+
+VOID
+NbiDestroyReceiveBufferPools(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routines walks the ReceiveBufferPoolList and destroys the
+ pool which does not have any buffer in use.
+
+Arguments:
+
+Return Value:
+
+ None.
+
+ THIS ROUTINE COULD BE CALLED WITH THE DEVICE LOCK HELD. If this
+ routine is also called from the DestroyDevice routine, it is not
+ necessary to call this with the lock.
+
+--*/
+{
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY Unused;
+
+
+ //
+ // Clean up this list before we call NbiFreeReceiveBufferPool bcoz that will
+ // simply destroy all the buffer which might be queue here on this list.
+ // At the end of this routine we must start with a fresh ReceiveBufferList.
+ //
+ do {
+ Unused = PopEntryList( &Device->ReceiveBufferList );
+ } while( Unused );
+
+ //
+ // Now destroy each individual ReceiveBufferPool.
+ //
+ for ( p = Device->ReceiveBufferPoolList.Flink;
+ p != &Device->ReceiveBufferPoolList;
+ ) {
+
+
+ ReceiveBufferPool = CONTAINING_RECORD (p, NB_RECEIVE_BUFFER_POOL, Linkage);
+ p = p->Flink;
+
+ //
+ // This will destroy and unlink this Pool if none of its buffer is
+ // in use currently.
+ //
+
+ if ( ReceiveBufferPool->BufferCount == ReceiveBufferPool->BufferFree ) {
+ NbiFreeReceiveBufferPool( ReceiveBufferPool );
+ } else {
+ //
+ // When the device is stopping we must succeed in freeing the pool.
+ CTEAssert( Device->State != DEVICE_STATE_STOPPING );
+ }
+
+ }
+
+}
+
+
+VOID
+NbiPushReceiveBuffer (
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the receive buffer back to the free list.
+ It checks the size of this buffer. If it is smaller than the
+ the CurMaxReceiveBufferSize, then it does not return this back
+ to the free list, instead it destroys it and possibly also
+ destroys the pool associated with it. O/w it simply returns this
+ to the free list.
+
+Arguments:
+
+ ReceiveBuffer - Pointer to the buffer to be returned to the free list.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool = (PNB_RECEIVE_BUFFER_POOL)ReceiveBuffer->Pool;
+ PDEVICE Device = NbiDevice;
+ CTELockHandle LockHandle;
+#if defined(DBG)
+ ULONG BufLen = 0;
+#endif
+
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+
+#if defined(DBG)
+ NdisQueryBuffer( ReceiveBuffer->NdisBuffer, NULL, &BufLen );
+ CTEAssert( BufLen == ReceiveBufferPool->BufferDataSize );
+#endif
+
+ //
+ // This is an old buffer which was in use when we changed
+ // the CurMaxReceiveBufferSize due to new adapter. We must not
+ // return this buffer back to free list. Infact, if the pool
+ // associated with this buffer does not have any other buffers
+ // in use, we should free the pool also.
+ CTEAssert( ReceiveBufferPool->BufferFree < ReceiveBufferPool->BufferCount );
+ ReceiveBufferPool->BufferFree++;
+
+ if ( ReceiveBufferPool->BufferDataSize < Device->CurMaxReceiveBufferSize ) {
+
+#if DBG
+ DbgPrint("ReceiveBuffer %lx, not returned to pool %lx( Free %d)\n", ReceiveBuffer, ReceiveBufferPool, ReceiveBufferPool->BufferFree);
+#endif
+
+
+ if ( ReceiveBufferPool->BufferFree == ReceiveBufferPool->BufferCount ) {
+ NbiFreeReceiveBufferPool( ReceiveBufferPool );
+ }
+ } else {
+
+ PushEntryList( &Device->ReceiveBufferList, &ReceiveBuffer->PoolLinkage );
+
+
+ }
+
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+}
+#endif _PNP_POWER
+
+
+PSINGLE_LIST_ENTRY
+NbiPopSendPacket(
+ IN PDEVICE Device,
+ IN BOOLEAN LockAcquired
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool.
+ If there are no packets in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+ LockAcquired - TRUE if Device->Lock is acquired.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ CTELockHandle LockHandle;
+
+ s = ExInterlockedPopEntrySList(
+ &Device->SendPacketList,
+ &NbiGlobalPoolInterlock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (!LockAcquired) {
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+ }
+
+ if (Device->AllocatedSendPackets < Device->MaxPackets) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+
+ NbiAllocateSendPool (Device);
+
+
+ if (!LockAcquired) {
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+
+ s = ExInterlockedPopEntrySList(
+ &Device->SendPacketList,
+ &NbiGlobalPoolInterlock);
+
+ return s;
+ } else {
+
+ if (!LockAcquired) {
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+ return NULL;
+ }
+
+} /* NbiPopSendPacket */
+
+
+VOID
+NbiPushSendPacket(
+ IN PNB_SEND_RESERVED Reserved
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees a packet back to the device context's pool.
+ If there are connections waiting for packets, it removes
+ one from the list and inserts it on the packetize queue.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ PLIST_ENTRY p;
+ PCONNECTION Connection;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ //
+ // BUGBUG: Make this a function. Optimize for
+ // UP by not doing two checks?
+ //
+
+ if (!IsListEmpty (&Device->WaitPacketConnections)) {
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ p = RemoveHeadList (&Device->WaitPacketConnections);
+
+ //
+ // Take a connection off the WaitPacketQueue and put it
+ // on the PacketizeQueue. We don't worry about if the
+ // connection has stopped, that will get checked when
+ // the PacketizeQueue is run down.
+ //
+ // Since this is in send completion, we may not get
+ // a receive complete. We guard against this by calling
+ // NbiReceiveComplete from the long timer timeout.
+ //
+
+ if (p != &Device->WaitPacketConnections) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, WaitPacketLinkage);
+
+ CTEAssert (Connection->OnWaitPacketQueue);
+ Connection->OnWaitPacketQueue = FALSE;
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_W_PACKET) {
+
+ CTEAssert (!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ NbiTransferReferenceConnection (Connection, CREF_W_PACKET, CREF_PACKETIZE);
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ } else {
+
+ NbiDereferenceConnection (Connection, CREF_W_PACKET);
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ }
+
+} /* NbiPushSendPacket */
+
+
+VOID
+NbiCheckForWaitPacket(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks if a connection is on the wait packet
+ queue and if so takes it off and queues it to be packetized.
+ It is meant to be called when the connection's packet has
+ been freed.
+
+Arguments:
+
+ Connection - The connection to check.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle1);
+
+ if (Connection->OnWaitPacketQueue) {
+
+ Connection->OnWaitPacketQueue = FALSE;
+ RemoveEntryList (&Connection->WaitPacketLinkage);
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_W_PACKET) {
+
+ CTEAssert (!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ NbiTransferReferenceConnection (Connection, CREF_W_PACKET, CREF_PACKETIZE);
+
+ InsertTailList(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage);
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle1);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NbiDereferenceConnection (Connection, CREF_W_PACKET);
+
+ return;
+ }
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle1);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+} /* NbiCheckForWaitPacket */
+
+
+PSINGLE_LIST_ENTRY
+NbiPopReceivePacket(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool.
+ If there are no packets in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ CTELockHandle LockHandle;
+
+ s = ExInterlockedPopEntrySList(
+ &Device->ReceivePacketList,
+ &NbiGlobalPoolInterlock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedReceivePackets < Device->MaxPackets) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ NbiAllocateReceivePool (Device);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ s = ExInterlockedPopEntrySList(
+ &Device->ReceivePacketList,
+ &NbiGlobalPoolInterlock);
+
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* NbiPopReceivePacket */
+
+
+PSINGLE_LIST_ENTRY
+NbiPopReceiveBuffer(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a receive buffer from the device context's pool.
+ If there are no buffers in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the buffer to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated receive buffer.
+
+--*/
+
+{
+#if defined(_PNP_POWER)
+ PSINGLE_LIST_ENTRY s;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ CTELockHandle LockHandle;
+
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+
+ s = PopEntryList( &Device->ReceiveBufferList );
+
+
+ if ( !s ) {
+
+ //
+ // No buffer in the pool, see if we can allocate more.
+ //
+ if (Device->AllocatedReceiveBuffers < Device->MaxReceiveBuffers) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+
+ NbiAllocateReceiveBufferPool (Device, Device->CurMaxReceiveBufferSize );
+ s = PopEntryList(&Device->ReceiveBufferList);
+ }
+ }
+
+ if ( s ) {
+
+
+ //
+ // Decrement the BufferFree count on the corresponding ReceiveBufferPool.
+ // so that we know that
+ ReceiveBuffer = CONTAINING_RECORD( s, NB_RECEIVE_BUFFER, PoolLinkage );
+
+
+ ReceiveBufferPool = (PNB_RECEIVE_BUFFER_POOL)ReceiveBuffer->Pool;
+
+ CTEAssert( ReceiveBufferPool->BufferFree && ( ReceiveBufferPool->BufferFree <= ReceiveBufferPool->BufferCount ) );
+ CTEAssert( ReceiveBufferPool->BufferDataSize == Device->CurMaxReceiveBufferSize );
+
+ ReceiveBufferPool->BufferFree--;
+
+ }
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ return s;
+#else
+ PSINGLE_LIST_ENTRY s;
+ CTELockHandle LockHandle;
+
+ s = ExInterlockedPopEntryList(
+ &Device->ReceiveBufferList,
+ &Device->Lock.Lock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No buffer in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedReceiveBuffers < Device->MaxReceiveBuffers) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ NbiAllocateReceiveBufferPool (Device);
+ s = PopEntryList(&Device->ReceiveBufferList);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+#endif _PNP_POWER
+} /* NbiPopReceiveBuffer */
+
diff --git a/private/ntos/tdi/isn/nb/precomp.h b/private/ntos/tdi/isn/nb/precomp.h
new file mode 100644
index 000000000..a024f2d3d
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/precomp.h
@@ -0,0 +1,42 @@
+/*++
+
+Copyright (c) 1993-1995 Microsoft Corporation
+
+Module Name:
+
+ precomp.h
+
+Abstract:
+
+ Precompilation header file.
+
+Author:
+
+ Adam Barr (adamba) 08-Sep-1993
+
+Revision History:
+
+--*/
+
+#define ISN_NT 1
+
+//
+// These are needed for CTE
+//
+
+#if DBG
+#define DEBUG 1
+#endif
+
+#define NT 1
+
+#include <ntos.h>
+#include <tdikrnl.h>
+#include <ndis.h>
+#include <cxport.h>
+#include <bind.h>
+#include "isnnb.h"
+#include "config.h"
+#include "nbitypes.h"
+#include "nbiprocs.h"
+#include "zwapi.h"
diff --git a/private/ntos/tdi/isn/nb/query.c b/private/ntos/tdi/isn/nb/query.c
new file mode 100644
index 000000000..6ee33adf3
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/query.c
@@ -0,0 +1,1817 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ query.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiQueryInformation
+ o TdiSetInformation
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Remove the warning -- this is defined in windef also.
+//
+
+#ifdef FAR
+#undef FAR
+#endif
+
+#include <windef.h>
+#include <nb30.h>
+
+
+//
+// Useful macro to obtain the total length of a buffer chain.
+// BUGBUG: Make this use NDIS macros.
+//
+
+#define NbiGetBufferChainLength(Buffer, Length) { \
+ PNDIS_BUFFER _Buffer = (Buffer); \
+ *(Length) = 0; \
+ while (_Buffer) { \
+ *(Length) += MmGetMdlByteCount(_Buffer); \
+ _Buffer = _Buffer->Next; \
+ } \
+}
+
+
+NTSTATUS
+NbiTdiQueryInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiQueryInformation request for the transport
+ provider.
+
+Arguments:
+
+ Request - the request for the operation.
+
+Return Value:
+
+ The status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTDI_REQUEST_KERNEL_QUERY_INFORMATION Query;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PCONNECTION Connection;
+ union {
+ struct {
+ ULONG ActivityCount;
+ TA_NETBIOS_ADDRESS NbiAddress;
+ } AddressInfo;
+ TA_NETBIOS_ADDRESS BroadcastAddress;
+ TDI_ADDRESS_IPX IpxAddress;
+ TDI_DATAGRAM_INFO DatagramInfo;
+ struct {
+ FIND_NAME_HEADER Header;
+ FIND_NAME_BUFFER Buffer;
+ } FindNameInfo;
+ } TempBuffer;
+ IPX_SOURCE_ROUTING_INFO SourceRoutingInfo;
+ PADAPTER_STATUS AdapterStatus;
+ BOOLEAN RemoteAdapterStatus;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteAddress;
+ ULONG TargetBufferLength;
+ ULONG AdapterStatusLength;
+ ULONG ValidStatusLength;
+ ULONG ElementSize, TransportAddressSize;
+ PTRANSPORT_ADDRESS TransportAddress;
+ TA_ADDRESS UNALIGNED * CurAddress;
+ PNETBIOS_CACHE CacheName;
+ FIND_NAME_HEADER UNALIGNED * FindNameHeader;
+ UINT FindNameBufferLength;
+ NTSTATUS QueryStatus;
+ CTELockHandle LockHandle;
+ PLIST_ENTRY p;
+ BOOLEAN UsedConnection;
+ UINT i;
+
+
+ //
+ // what type of status do we want?
+ //
+
+ Query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)REQUEST_PARAMETERS(Request);
+
+ switch (Query->QueryType) {
+
+ case TDI_QUERY_ADDRESS_INFO:
+
+ //
+ // The caller wants the exact address value.
+ //
+
+ if (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_NOT_OK);
+#else
+ Status = NbiVerifyAddressFile (AddressFile);
+#endif _PNP_POWER
+
+ if (!NT_SUCCESS(Status)) {
+ break;
+ }
+
+ UsedConnection = FALSE;
+
+ } else if (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE) {
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+
+ if (!NT_SUCCESS(Status)) {
+ break;
+ }
+
+ UsedConnection = TRUE;
+
+ AddressFile = Connection->AddressFile;
+
+ } else {
+
+ Status = STATUS_INVALID_ADDRESS;
+ break;
+
+ }
+
+ Address = AddressFile->Address;
+
+ NB_DEBUG2 (QUERY, ("Query address info on %lx\n", AddressFile));
+
+ TempBuffer.AddressInfo.ActivityCount = 0;
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+
+ if (CONTAINING_RECORD (p, ADDRESS_FILE, Linkage)->State == ADDRESSFILE_STATE_OPEN) {
+ ++TempBuffer.AddressInfo.ActivityCount;
+ }
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ TdiBuildNetbiosAddress(
+ AddressFile->Address->NetbiosAddress.NetbiosName,
+ (BOOLEAN)(AddressFile->Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_GROUP),
+ &TempBuffer.AddressInfo.NbiAddress);
+
+ Status = TdiCopyBufferToMdl(
+ &TempBuffer.AddressInfo,
+ 0,
+ sizeof(ULONG) + sizeof(TA_NETBIOS_ADDRESS),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ if (UsedConnection) {
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ } else {
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ }
+
+ break;
+
+ case TDI_QUERY_CONNECTION_INFO:
+
+ //
+ // Connection info is queried on a connection,
+ // verify this.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ if (Connection->State != CONNECTION_STATE_ACTIVE) {
+
+ Status = STATUS_INVALID_CONNECTION;
+
+ } else {
+
+ //
+ // Assume 50 ms of delay for every hop after the
+ // first. The delay is returned as a negative number.
+ //
+
+ if (Connection->HopCount > 1) {
+ Connection->ConnectionInfo.Delay.HighPart = (ULONG)-1;
+ Connection->ConnectionInfo.Delay.LowPart =
+ -((Connection->HopCount-1) * 50 * MILLISECONDS);
+ } else {
+ Connection->ConnectionInfo.Delay.HighPart = 0;
+ Connection->ConnectionInfo.Delay.LowPart = 0;
+ }
+
+ //
+ // We have tick count; to convert to bytes/second we do:
+ //
+ // packet 576 bytes 18.21 ticks
+ // ---------------- * --------- * -----------
+ // tick_count ticks packet seconds
+ //
+ // to get 10489/tick_count = bytes/second. We
+ // double this because routers tend to
+ // overestimate it.
+ //
+ // Since tick_count has such a low granularity,
+ // a tick count of 1 gives us a throughput of
+ // only 84 kbps, which is much too low. In
+ // that case we return twice the link speed
+ // which is in 100 bps units; that corresponds
+ // to about 1/6 of our bandwidth in bytes/sec.
+ //
+
+ if (Connection->TickCount <= Connection->HopCount) {
+
+ Connection->ConnectionInfo.Throughput.QuadPart =
+ UInt32x32To64 (Connection->LineInfo.LinkSpeed, 2);
+
+ } else {
+
+ Connection->ConnectionInfo.Throughput.HighPart = 0;
+ Connection->ConnectionInfo.Throughput.LowPart =
+ 20978 / (Connection->TickCount - Connection->HopCount);
+
+ }
+
+ Connection->ConnectionInfo.Unreliable = FALSE;
+
+ Status = TdiCopyBufferToMdl (
+ &Connection->ConnectionInfo,
+ 0,
+ sizeof(TDI_CONNECTION_INFO),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ break;
+
+ case TDI_QUERY_PROVIDER_INFO:
+
+ NB_DEBUG2 (QUERY, ("Query provider info\n"));
+
+ Status = TdiCopyBufferToMdl (
+ &Device->Information,
+ 0,
+ sizeof (TDI_PROVIDER_INFO),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_BROADCAST_ADDRESS:
+
+ //
+ // for this provider, the broadcast address is a zero byte name,
+ // contained in a Transport address structure.
+ //
+
+ NB_DEBUG2 (QUERY, ("Query broadcast address\n"));
+
+ TempBuffer.BroadcastAddress.TAAddressCount = 1;
+ TempBuffer.BroadcastAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ TempBuffer.BroadcastAddress.Address[0].AddressLength = 0;
+
+ Status = TdiCopyBufferToMdl (
+ (PVOID)&TempBuffer.BroadcastAddress,
+ 0L,
+ sizeof (TempBuffer.BroadcastAddress.TAAddressCount) +
+ sizeof (TempBuffer.BroadcastAddress.Address[0].AddressType) +
+ sizeof (TempBuffer.BroadcastAddress.Address[0].AddressLength),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ break;
+
+ case TDI_QUERY_ADAPTER_STATUS:
+
+ //
+ // Determine if this is a local or remote query.
+ //
+
+ RemoteAdapterStatus = FALSE;
+
+ if (Query->RequestConnectionInformation != NULL) {
+
+ RemoteAddress = NbiParseTdiAddress(Query->RequestConnectionInformation->RemoteAddress, FALSE);
+
+ if (RemoteAddress == NULL) {
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+#if defined(_PNP_POWER)
+ if ( !NbiFindAdapterAddress(
+ RemoteAddress->NetbiosName,
+ LOCK_NOT_ACQUIRED ) ) {
+
+ RemoteAdapterStatus = TRUE;
+ }
+#else
+ if (!RtlEqualMemory(
+ RemoteAddress->NetbiosName,
+ Device->ReservedNetbiosName,
+ 16)) {
+
+ RemoteAdapterStatus = TRUE;
+
+ }
+#endif _PNP_POWER
+
+ }
+
+ if (RemoteAdapterStatus) {
+
+ //
+ // See if we have this name cached.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Status = CacheFindName(
+ Device,
+ FindNameOther,
+ RemoteAddress->NetbiosName,
+ &CacheName);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A request for routes to this name has been
+ // sent out on the net, we queue up this status
+ // request and processing will be resumed when
+ // we get a response.
+ //
+ // The status field in the request will hold
+ // the cache entry for the remote. The information
+ // field will hold the remote netbios name while
+ // it is in the WaitingAdapterStatus queue, and
+ // will hold a timeout value while we it is in
+ // the ActiveAdapterStatus queue.
+ //
+
+ NB_DEBUG2 (QUERY, ("Queueing up adapter status %lx\n", Request));
+
+ NbiReferenceDevice (Device, DREF_STATUS_QUERY);
+
+ REQUEST_INFORMATION (Request) = (ULONG)RemoteAddress;
+
+ InsertTailList(
+ &Device->WaitingAdapterStatus,
+ REQUEST_LINKAGE (Request));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ } else if (Status == STATUS_SUCCESS) {
+
+ NB_DEBUG2 (QUERY, ("Found adapter status cached %lx\n", Request));
+
+ //
+ // We reference the cache name entry so it won't
+ // go away while we are using it.
+ //
+
+ REQUEST_STATUS(Request) = (NTSTATUS)CacheName;
+ ++CacheName->ReferenceCount;
+
+ NbiReferenceDevice (Device, DREF_STATUS_QUERY);
+
+ REQUEST_INFORMATION (Request) = 0;
+
+ InsertTailList(
+ &Device->ActiveAdapterStatus,
+ REQUEST_LINKAGE (Request));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ NbiSendStatusQuery (Request);
+
+ Status = STATUS_PENDING;
+
+ } else {
+
+ if (Status != STATUS_INSUFFICIENT_RESOURCES) {
+ Status = STATUS_IO_TIMEOUT;
+ }
+
+ REQUEST_INFORMATION (Request) = 0;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ //
+ // Local adapter status.
+ //
+
+ NbiGetBufferChainLength (REQUEST_NDIS_BUFFER(Request), &TargetBufferLength);
+
+ Status = NbiStoreAdapterStatus(
+ TargetBufferLength,
+ 1, // NIC ID, was 0, changed to 1 for Bug #18026
+ // because for NicId = 0, Ipx returns virtual
+ // address. Netbios uses that to register the
+ // name (00...01) and fails.
+ &AdapterStatus,
+ &AdapterStatusLength,
+ &ValidStatusLength);
+
+ if (Status != STATUS_INSUFFICIENT_RESOURCES) {
+
+ //
+ // This should succeed since we know the length
+ // will fit.
+ //
+
+ (VOID)TdiCopyBufferToMdl(
+ AdapterStatus,
+ 0,
+ ValidStatusLength,
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ NbiFreeMemory (AdapterStatus, AdapterStatusLength, MEMORY_STATUS, "Adapter Status");
+
+ }
+
+ }
+
+ break;
+
+ case TDI_QUERY_FIND_NAME:
+
+ //
+ // Check that there is a valid Netbios remote address.
+ //
+
+ if ((Query->RequestConnectionInformation == NULL) ||
+ ((RemoteAddress = NbiParseTdiAddress(Query->RequestConnectionInformation->RemoteAddress, FALSE)) == NULL)) {
+
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+ //
+ // We assume the entire request buffer is in the first
+ // piece of the MDL chain (BUGBUG: Can we do this?).
+ // Make sure there is room for at least the header.
+ //
+
+ NdisQueryBuffer(REQUEST_NDIS_BUFFER(Request), (PVOID *)&FindNameHeader, &FindNameBufferLength);
+ if (FindNameBufferLength < sizeof(FIND_NAME_HEADER)) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // See if we have this name cached. We specify that this is
+ // a netbios name query, so this will only succeed if this is a
+ // unique name -- for a group name it will queue up a find
+ // name query and when we get the response we will fill in
+ // the request's buffer based on it.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Status = CacheFindName(
+ Device,
+ FindNameNetbiosFindName,
+ RemoteAddress->NetbiosName,
+ &CacheName);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A request for routes to this name has been
+ // sent out on the net, we queue up this find
+ // name request and processing will be resumed when
+ // we get a response.
+ //
+ // The information field will hold the remote
+ // netbios name while it is in the WaitingNetbiosFindName
+ // queue. The status will hold the current status --
+ // initially failure, then success, then overflow
+ // if the buffer is too small.
+ //
+
+ NB_DEBUG2 (QUERY, ("Queueing up find name %lx\n", Request));
+
+ NbiReferenceDevice (Device, DREF_NB_FIND_NAME);
+
+ FindNameHeader->node_count = 0;
+ FindNameHeader->reserved = 0;
+ FindNameHeader->unique_group = 0;
+
+ REQUEST_INFORMATION (Request) = (ULONG)RemoteAddress;
+
+ //
+ // Assume it fails, we update the status to
+ // SUCCESS or BUFFER_OVERFLOW if needed.
+ //
+
+ REQUEST_STATUS (Request) = STATUS_IO_TIMEOUT;
+
+ InsertTailList(
+ &Device->WaitingNetbiosFindName,
+ REQUEST_LINKAGE (Request));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ } else if (Status == STATUS_SUCCESS) {
+
+ NB_DEBUG2 (QUERY, ("Found find name cached %lx\n", Request));
+
+ //
+ // We don't need to reference the cache entry since
+ // we only use it here with the lock still held.
+ //
+
+ //
+ // Query the local address, which we will return as
+ // the destination address of this query. Since we
+ // use TempBuffer.IpxAddress for this query, we have
+ // to immediately copy it to its correct place in
+ // TempBuffer.FindNameInfo.Buffer.
+ //
+#if defined(_PNP_POWER)
+ if( (*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ &CacheName->Networks[0].LocalTarget.NicHandle,
+ &TempBuffer.IpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL) != STATUS_SUCCESS ) {
+ NB_DEBUG( QUERY, ("Ipx Query %d failed for Nic %x\n",IPX_QUERY_IPX_ADDRESS,
+ CacheName->Networks[0].LocalTarget.NicHandle.NicId ));
+
+ goto QueryFindNameFailed;
+ }
+#else
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ CacheName->Networks[0].LocalTarget.NicId,
+ &TempBuffer.IpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL);
+#endif _PNP_POWER
+
+ RtlMoveMemory (TempBuffer.FindNameInfo.Buffer.destination_addr, TempBuffer.IpxAddress.NodeAddress, 6);
+ TempBuffer.FindNameInfo.Buffer.access_control = 0x10; // standard token-ring values
+ TempBuffer.FindNameInfo.Buffer.frame_control = 0x40;
+ RtlCopyMemory (TempBuffer.FindNameInfo.Buffer.source_addr, CacheName->FirstResponse.NodeAddress, 6);
+
+ //
+ // Query source routing information about this remote, if any.
+ //
+
+ SourceRoutingInfo.Identifier = IDENTIFIER_NB;
+ RtlCopyMemory (SourceRoutingInfo.RemoteAddress, CacheName->FirstResponse.NodeAddress, 6);
+
+ QueryStatus = (*Device->Bind.QueryHandler)(
+ IPX_QUERY_SOURCE_ROUTING,
+#if defined(_PNP_POWER)
+ &CacheName->Networks[0].LocalTarget.NicHandle,
+#else
+ CacheName->Networks[0].LocalTarget.NicId,
+#endif _PNP_POWER
+ &SourceRoutingInfo,
+ sizeof(IPX_SOURCE_ROUTING_INFO),
+ NULL);
+
+ RtlZeroMemory(TempBuffer.FindNameInfo.Buffer.routing_info, 18);
+ if (QueryStatus != STATUS_SUCCESS) {
+ SourceRoutingInfo.SourceRoutingLength = 0;
+ } else if (SourceRoutingInfo.SourceRoutingLength > 0) {
+ RtlMoveMemory(
+ TempBuffer.FindNameInfo.Buffer.routing_info,
+ SourceRoutingInfo.SourceRouting,
+ SourceRoutingInfo.SourceRoutingLength);
+ }
+
+ TempBuffer.FindNameInfo.Buffer.length = (UCHAR)(14 + SourceRoutingInfo.SourceRoutingLength);
+
+ TempBuffer.FindNameInfo.Header.node_count = 1;
+ TempBuffer.FindNameInfo.Header.reserved = 0;
+ TempBuffer.FindNameInfo.Header.unique_group = 0; // unique
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // 33 is sizeof(FIND_NAME_BUFFER) without the padding.
+ //
+
+ Status = TdiCopyBufferToMdl (
+ (PVOID)&TempBuffer.FindNameInfo,
+ 0,
+ sizeof(FIND_NAME_HEADER) + 33,
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ } else {
+
+#if defined(_PNP_POWER)
+QueryFindNameFailed:
+#endif _PNP_POWER
+
+ if (Status != STATUS_INSUFFICIENT_RESOURCES) {
+ Status = STATUS_IO_TIMEOUT;
+ }
+
+ REQUEST_INFORMATION (Request) = 0;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ break;
+
+ case TDI_QUERY_PROVIDER_STATISTICS:
+
+ //
+ // BETABUGBUG: Keep track of more of these.
+ //
+
+ NB_DEBUG2 (QUERY, ("Query provider statistics\n"));
+
+ Status = TdiCopyBufferToMdl (
+ &Device->Statistics,
+ 0,
+ FIELD_OFFSET (TDI_PROVIDER_STATISTICS, ResourceStats[0]),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_DATAGRAM_INFO:
+
+ NB_DEBUG2 (QUERY, ("Query datagram info\n"));
+
+ TempBuffer.DatagramInfo.MaximumDatagramBytes = 0;
+ TempBuffer.DatagramInfo.MaximumDatagramCount = 0;
+
+ Status = TdiCopyBufferToMdl (
+ &TempBuffer.DatagramInfo,
+ 0,
+ sizeof(TempBuffer.DatagramInfo),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_DATA_LINK_ADDRESS:
+ case TDI_QUERY_NETWORK_ADDRESS:{
+#if defined(_PNP_POWER)
+ Status = (*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ (Query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS
+ ? IPX_QUERY_DATA_LINK_ADDRESS
+ : IPX_QUERY_NETWORK_ADDRESS ),
+ NULL,
+ Request,
+ 0,
+ NULL);
+#else
+ ULONG TransportAddressAllocSize;
+
+ if (Query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
+ ElementSize = (2 * sizeof(USHORT)) + 6;
+ } else {
+ ElementSize = (2 * sizeof(USHORT)) + sizeof(TDI_ADDRESS_IPX);
+ }
+
+// TransportAddress = CTEAllocMem(sizeof(int) + (ElementSize * Device->MaximumNicId));
+ TransportAddressAllocSize = sizeof(int) + ( ElementSize * Device->MaximumNicId);
+ TransportAddress = NbiAllocateMemory( TransportAddressAllocSize, MEMORY_QUERY, "Temp Query Allocation");
+
+ if (TransportAddress == NULL) {
+
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ TransportAddress->TAAddressCount = 0;
+ TransportAddressSize = sizeof(int);
+ CurAddress = (TA_ADDRESS UNALIGNED *)TransportAddress->Address;
+
+ for (i = 1; i <= Device->MaximumNicId; i++) {
+
+ Status = (*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ (USHORT)i,
+ &TempBuffer.IpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+ continue;
+ }
+
+ if (Query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
+ CurAddress->AddressLength = 6;
+ CurAddress->AddressType = TDI_ADDRESS_TYPE_UNSPEC;
+ RtlCopyMemory (CurAddress->Address, TempBuffer.IpxAddress.NodeAddress, 6);
+ } else {
+ CurAddress->AddressLength = sizeof(TDI_ADDRESS_IPX);
+ CurAddress->AddressType = TDI_ADDRESS_TYPE_IPX;
+ RtlCopyMemory (CurAddress->Address, &TempBuffer.IpxAddress, sizeof(TDI_ADDRESS_IPX));
+ }
+ ++TransportAddress->TAAddressCount;
+ TransportAddressSize += ElementSize;
+ CurAddress = (TA_ADDRESS UNALIGNED *)(((PUCHAR)CurAddress) + ElementSize);
+
+ }
+
+ Status = TdiCopyBufferToMdl (
+ TransportAddress,
+ 0,
+ TransportAddressSize,
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+// CTEFreeMem (TransportAddress);
+ NbiFreeMemory( TransportAddress, TransportAddressAllocSize, MEMORY_QUERY, "Temp Query Allocation");
+
+ }
+#endif _PNP_POWER
+ break;
+ }
+ default:
+
+ NB_DEBUG (QUERY, ("Invalid query type %d\n", Query->QueryType));
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ return Status;
+
+} /* NbiTdiQueryInformation */
+
+
+NTSTATUS
+NbiStoreAdapterStatus(
+ IN ULONG MaximumLength,
+ IN USHORT NicId,
+ OUT PVOID * StatusBuffer,
+ OUT ULONG * StatusBufferLength,
+ OUT ULONG * ValidBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates an ADAPTER_STATUS buffer and
+ fills it in. The buffer will be allocated at most
+ MaximumLength size. The caller is responsible for
+ freeing the buffer.
+
+Arguments:
+
+ MaximumLength - The maximum length to allocate.
+
+ NicId - The NIC ID the query was received on, or 0 for
+ a local query.
+
+ StatusBuffer - Returns the allocated buffer.
+
+ StatusBufferLength - Returns the length of the buffer.
+
+ ValidBufferLength - Returns the length of the buffer which
+ contains valid adapter status data.
+
+Return Value:
+
+ STATUS_SUCCESS - The buffer was written successfully.
+ STATUS_BUFFER_OVERFLOW - The buffer was written but not all
+ data could fit in MaximumLength bytes.
+ STATUS_INSUFFICIENT_RESOURCES - The buffer could not be allocated.
+
+--*/
+
+{
+
+ PADAPTER_STATUS AdapterStatus;
+ PNAME_BUFFER NameBuffer;
+ ADAPTER_STATUS TempAdapterStatus;
+#if !defined(_PNP_POWER)
+ TDI_ADDRESS_IPX IpxAddress;
+#endif !_PNP_POWER
+ PDEVICE Device = NbiDevice;
+ PADDRESS Address;
+ UCHAR NameCount;
+ ULONG LengthNeeded;
+ ULONG BytesWritten;
+ NTSTATUS Status;
+ PLIST_ENTRY p;
+ CTELockHandle LockHandle;
+
+
+ //
+ // First fill in the basic adapter status structure, to make
+ // it easier to copy over if the target buffer is really short.
+ //
+
+ RtlZeroMemory ((PVOID)&TempAdapterStatus, sizeof(ADAPTER_STATUS));
+
+#if defined(_PNP_POWER)
+ RtlCopyMemory (TempAdapterStatus.adapter_address, Device->Bind.Node, 6);
+#else
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ NicId,
+ &IpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL);
+
+ RtlCopyMemory (TempAdapterStatus.adapter_address, IpxAddress.NodeAddress, 6);
+#endif _PNP_POWER
+
+
+ //
+ // Some of the fields mean different things for Novell Netbios,
+ // as described in the comments.
+ //
+
+ TempAdapterStatus.rev_major = 0; // Jumpers
+ TempAdapterStatus.reserved0 = 0; // SelfTest
+ TempAdapterStatus.adapter_type = 0; // MajorVersion
+ TempAdapterStatus.rev_minor = 0; // MinorVersion
+
+ TempAdapterStatus.duration = 0; // ReportingPeriod
+ TempAdapterStatus.frmr_recv = 0; // ReceiveCRCErrors
+ TempAdapterStatus.frmr_xmit = 0; // ReceiveAlignErrors
+
+ TempAdapterStatus.iframe_recv_err = 0; // XmitCollisions
+ TempAdapterStatus.xmit_aborts = 0; // XmitAbort
+
+ TempAdapterStatus.xmit_success = Device->Statistics.DataFramesSent; // SuccessfulXmits
+ TempAdapterStatus.recv_success = Device->Statistics.DataFramesReceived; // SuccessfulReceive
+
+ TempAdapterStatus.iframe_xmit_err = (WORD)Device->Statistics.DataFramesResent; // XmitRetries
+ TempAdapterStatus.recv_buff_unavail = (WORD)Device->Statistics.DataFramesRejected; // ExhaustedResource
+
+ // t1_timeouts, ti_timeouts, and reserved1 are unused.
+
+ TempAdapterStatus.free_ncbs = 0xffff; // FreeBlocks
+ TempAdapterStatus.max_cfg_ncbs = 0xffff; // ConfiguredNCB
+ TempAdapterStatus.max_ncbs = 0xffff; // MaxNCB
+
+ // xmit_bug_unavail and max_dgram_size are unused.
+
+ TempAdapterStatus.pending_sess = (WORD)Device->Statistics.OpenConnections; // CurrentSessions
+ TempAdapterStatus.max_cfg_sess = 0xffff; // MaxSessionConfigured
+ TempAdapterStatus.max_sess = 0xffff; // MaxSessionPossible
+ TempAdapterStatus.max_sess_pkt_size =
+ Device->Bind.LineInfo.MaximumSendSize - sizeof(NB_CONNECTION); // MaxSessionPacketSize
+
+ TempAdapterStatus.name_count = 0;
+
+
+ //
+ // Do a quick estimate of how many names we need room for.
+ // This includes stopping addresses and the broadcast
+ // address, for the moment. BUGBUG: Fix this?
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ LengthNeeded = sizeof(ADAPTER_STATUS) + (Device->AddressCount * sizeof(NAME_BUFFER));
+
+ if (LengthNeeded > MaximumLength) {
+ LengthNeeded = MaximumLength;
+ }
+
+ AdapterStatus = NbiAllocateMemory(LengthNeeded, MEMORY_STATUS, "Adapter Status");
+ if (AdapterStatus == NULL) {
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ *StatusBuffer = AdapterStatus;
+ *StatusBufferLength = LengthNeeded;
+
+ if (LengthNeeded < sizeof(ADAPTER_STATUS)) {
+ RtlCopyMemory (AdapterStatus, &TempAdapterStatus, LengthNeeded);
+ *ValidBufferLength = LengthNeeded;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return STATUS_BUFFER_OVERFLOW;
+ }
+
+ RtlCopyMemory (AdapterStatus, &TempAdapterStatus, sizeof(ADAPTER_STATUS));
+
+ BytesWritten = sizeof(ADAPTER_STATUS);
+ NameBuffer = (PNAME_BUFFER)(AdapterStatus+1);
+ NameCount = 0;
+
+ //
+ // Scan through the device's address database, filling in
+ // the NAME_BUFFERs.
+ //
+
+ Status = STATUS_SUCCESS;
+
+ for (p = Device->AddressDatabase.Flink;
+ p != &Device->AddressDatabase;
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ //
+ // Ignore addresses that are shutting down.
+ //
+
+#if defined(_PNP_POWER)
+ if ((Address->State != ADDRESS_STATE_OPEN) ||
+ (Address->Flags & ADDRESS_FLAGS_CONFLICT)) {
+ continue;
+ }
+#else
+ if ((Address->State != ADDRESS_STATE_OPEN) != 0) {
+ continue;
+ }
+#endif _PNP_POWER
+
+ //
+ // Ignore the broadcast address.
+ //
+
+ if (Address->NetbiosAddress.Broadcast) {
+ continue;
+ }
+
+ //
+ // Ignore our reserved address.
+ //
+#if defined(_PNP_POWER)
+ if ( NbiFindAdapterAddress(
+ Address->NetbiosAddress.NetbiosName,
+ LOCK_ACQUIRED
+ )) {
+ continue;
+ }
+#else
+ if (RtlEqualMemory(
+ Address->NetbiosAddress.NetbiosName,
+ Device->ReservedNetbiosName,
+ 16)) {
+ continue;
+ }
+
+#endif _PNP_POWER
+ //
+ // Make sure we still have room.
+ //
+
+ if (BytesWritten + sizeof(NAME_BUFFER) > LengthNeeded) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ break;
+ }
+
+ RtlCopyMemory(
+ NameBuffer->name,
+ Address->NetbiosAddress.NetbiosName,
+ 16);
+
+ ++NameCount;
+ NameBuffer->name_num = NameCount;
+
+ NameBuffer->name_flags = REGISTERED;
+ if (Address->NameTypeFlag == NB_NAME_GROUP) {
+ NameBuffer->name_flags |= GROUP_NAME;
+ }
+
+ //
+ // BUGBUG: name_flags should be done more accurately.
+ //
+
+ BytesWritten += sizeof(NAME_BUFFER);
+ ++NameBuffer;
+
+ }
+
+ AdapterStatus->name_count = (WORD)NameCount;
+ *ValidBufferLength = BytesWritten;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return Status;
+
+} /* NbiStoreAdapterStatus */
+
+
+VOID
+NbiUpdateNetbiosFindName(
+ IN PREQUEST Request,
+#if defined(_PNP_POWER)
+ IN PNIC_HANDLE NicHandle,
+#else
+ IN USHORT NicId,
+#endif _PNP_POWER
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteIpxAddress,
+ IN BOOLEAN Unique
+ )
+
+/*++
+
+Routine Description:
+
+ This routine updates the find name request with the
+ new information received. It updates the status in
+ the request if needed.
+
+Arguments:
+
+ Request - The netbios find name request.
+
+ NicId - The NIC ID the response was received on.
+
+ RemoteIpxAddress - The IPX address of the remote.
+
+ Unique - TRUE if the name is unique.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ FIND_NAME_HEADER UNALIGNED * FindNameHeader;
+ FIND_NAME_BUFFER UNALIGNED * FindNameBuffer;
+ UINT FindNameBufferLength;
+ TDI_ADDRESS_IPX LocalIpxAddress;
+ IPX_SOURCE_ROUTING_INFO SourceRoutingInfo;
+ NTSTATUS QueryStatus;
+ UINT i;
+
+
+ NdisQueryBuffer(REQUEST_NDIS_BUFFER(Request), (PVOID *)&FindNameHeader, &FindNameBufferLength);
+
+ //
+ // Scan through the names saved so far and see if this one
+ // is there.
+ //
+
+ FindNameBuffer = (FIND_NAME_BUFFER UNALIGNED *)(FindNameHeader+1);
+
+ for (i = 0; i < FindNameHeader->node_count; i++) {
+
+ if (RtlEqualMemory(
+ FindNameBuffer->source_addr,
+ RemoteIpxAddress->NodeAddress,
+ 6)) {
+
+ //
+ // This remote already responded, ignore it.
+ //
+
+ return;
+
+ }
+
+ FindNameBuffer = (FIND_NAME_BUFFER UNALIGNED *)
+ (((PUCHAR)FindNameBuffer) + 33);
+
+ }
+
+ //
+ // Make sure there is room for this new node. 33 is
+ // sizeof(FIND_NAME_BUFFER) without padding.
+ //
+
+ if (FindNameBufferLength < sizeof(FIND_NAME_HEADER) + ((FindNameHeader->node_count+1) * 33)) {
+ REQUEST_STATUS(Request) = STATUS_BUFFER_OVERFLOW;
+ return;
+ }
+
+ //
+ // Query the local address, which we will return as
+ // the destination address of this query.
+ //
+
+#if defined(_PNP_POWER)
+ if( (*NbiDevice->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ NicHandle,
+ &LocalIpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL) != STATUS_SUCCESS ) {
+ //
+ // Ignore this response if the query fails. maybe the NicHandle
+ // is bad or it just got removed.
+ //
+ NB_DEBUG( QUERY, ("Ipx Query %d failed for Nic %x\n",IPX_QUERY_IPX_ADDRESS,
+ NicHandle->NicId ));
+ return;
+ }
+#else
+ (VOID)(*NbiDevice->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ NicId,
+ &LocalIpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL);
+#endif _PNP_POWER
+
+ FindNameBuffer->access_control = 0x10; // standard token-ring values
+ FindNameBuffer->frame_control = 0x40;
+ RtlMoveMemory (FindNameBuffer->destination_addr, LocalIpxAddress.NodeAddress, 6);
+ RtlCopyMemory (FindNameBuffer->source_addr, RemoteIpxAddress->NodeAddress, 6);
+
+ //
+ // Query source routing information about this remote, if any.
+ //
+
+ SourceRoutingInfo.Identifier = IDENTIFIER_NB;
+ RtlCopyMemory (SourceRoutingInfo.RemoteAddress, RemoteIpxAddress->NodeAddress, 6);
+
+ QueryStatus = (*NbiDevice->Bind.QueryHandler)(
+ IPX_QUERY_SOURCE_ROUTING,
+#if defined(_PNP_POWER)
+ NicHandle,
+#else
+ NicId,
+#endif _PNP_POWER
+ &SourceRoutingInfo,
+ sizeof(IPX_SOURCE_ROUTING_INFO),
+ NULL);
+
+ RtlZeroMemory(FindNameBuffer->routing_info, 18);
+ if (QueryStatus != STATUS_SUCCESS) {
+ SourceRoutingInfo.SourceRoutingLength = 0;
+ } else if (SourceRoutingInfo.SourceRoutingLength > 0) {
+ RtlMoveMemory(
+ FindNameBuffer->routing_info,
+ SourceRoutingInfo.SourceRouting,
+ SourceRoutingInfo.SourceRoutingLength);
+ }
+
+ FindNameBuffer->length = (UCHAR)(14 + SourceRoutingInfo.SourceRoutingLength);
+
+ ++FindNameHeader->node_count;
+ if (!Unique) {
+ FindNameHeader->unique_group = 1; // group
+ }
+
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+
+} /* NbiUpdateNetbiosFindName */
+
+
+VOID
+NbiSetNetbiosFindNameInformation(
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the REQUEST_INFORMATION field to the right
+ value based on the number of responses recorded in the netbios
+ find name request's buffer.
+
+Arguments:
+
+ Request - The netbios find name request.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ FIND_NAME_HEADER UNALIGNED * FindNameHeader;
+ UINT FindNameBufferLength;
+
+
+ NdisQueryBuffer(REQUEST_NDIS_BUFFER(Request), (PVOID *)&FindNameHeader, &FindNameBufferLength);
+
+ //
+ // 33 is sizeof(FIND_NAME_BUFFER) without the padding.
+ //
+
+ REQUEST_INFORMATION(Request) = sizeof(FIND_NAME_HEADER) + (FindNameHeader->node_count * 33);
+
+} /* NbiSetNetbiosFindNameInformation */
+
+
+NTSTATUS
+NbiTdiSetInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetInformation request for the transport
+ provider.
+
+Arguments:
+
+ Device - the device.
+
+ Request - the request for the operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (Device);
+ UNREFERENCED_PARAMETER (Request);
+
+ return STATUS_NOT_IMPLEMENTED;
+
+} /* NbiTdiSetInformation */
+
+
+VOID
+NbiProcessStatusQuery(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_STATUS_QUERY frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ IPX_LINE_INFO LineInfo;
+ ULONG ResponseSize;
+ NTSTATUS Status;
+ PNDIS_BUFFER AdapterStatusBuffer;
+ PADAPTER_STATUS AdapterStatus;
+ ULONG AdapterStatusLength;
+ ULONG ValidStatusLength;
+ PDEVICE Device = NbiDevice;
+ NB_CONNECTIONLESS UNALIGNED * Connectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
+
+
+ //
+ // The old stack does not include the 14 bytes of padding in
+ // the 802.3 or IPX length of the packet.
+ //
+
+ if (PacketSize < (sizeof(IPX_HEADER) + 2)) {
+ return;
+ }
+
+ //
+ // Get the maximum size we can send.
+ //
+#if defined(_PNP_POWER)
+ if( (*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_LINE_INFO,
+ &RemoteAddress->NicHandle,
+ &LineInfo,
+ sizeof(IPX_LINE_INFO),
+ NULL) != STATUS_SUCCESS ) {
+ //
+ // Bad NicHandle or it just got removed.
+ //
+ NB_DEBUG( QUERY, ("Ipx Query %d failed for Nic %x\n",IPX_QUERY_LINE_INFO,
+ RemoteAddress->NicHandle.NicId ));
+
+ return;
+ }
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+ if (s == NULL) {
+ return;
+ }
+#else
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+ if (s == NULL) {
+ return;
+ }
+
+ //
+ // Get the maximum size we can send.
+ //
+
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_LINE_INFO,
+ RemoteAddress->NicId,
+ &LineInfo,
+ sizeof(IPX_LINE_INFO),
+ NULL);
+#endif _PNP_POWER
+
+ ResponseSize = LineInfo.MaximumSendSize - sizeof(IPX_HEADER) - sizeof(NB_STATUS_RESPONSE);
+
+ //
+ // Get the local adapter status (this allocates a buffer).
+ //
+
+ Status = NbiStoreAdapterStatus(
+ ResponseSize,
+#if defined(_PNP_POWER)
+ RemoteAddress->NicHandle.NicId,
+#else
+ RemoteAddress->NicId,
+#endif _PNP_POWER
+ &AdapterStatus,
+ &AdapterStatusLength,
+ &ValidStatusLength);
+
+ if (Status == STATUS_INSUFFICIENT_RESOURCES) {
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ return;
+ }
+
+ //
+ // Allocate an NDIS buffer to map the extra buffer.
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &AdapterStatusBuffer,
+ Device->NdisBufferPoolHandle,
+ AdapterStatus,
+ ValidStatusLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbiFreeMemory (AdapterStatus, AdapterStatusLength, MEMORY_STATUS, "Adapter Status");
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ return;
+ }
+
+ NB_DEBUG2 (QUERY, ("Reply to AdapterStatus from %lx %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ *(UNALIGNED ULONG *)Connectionless->IpxHeader.SourceNetwork,
+ Connectionless->IpxHeader.SourceNode[0],
+ Connectionless->IpxHeader.SourceNode[1],
+ Connectionless->IpxHeader.SourceNode[2],
+ Connectionless->IpxHeader.SourceNode[3],
+ Connectionless->IpxHeader.SourceNode[4],
+ Connectionless->IpxHeader.SourceNode[5]));
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_STATUS_RESPONSE;
+ Reserved->u.SR_AS.ActualBufferLength = AdapterStatusLength;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ RtlCopyMemory(&Header->IpxHeader.DestinationNetwork, Connectionless->IpxHeader.SourceNetwork, 12);
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_STATUS_RESPONSE)+ValidStatusLength) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_STATUS_RESPONSE)+ValidStatusLength) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ Header->StatusResponse.ConnectionControlFlag = 0x00;
+ Header->StatusResponse.DataStreamType = NB_CMD_STATUS_RESPONSE;
+
+ NbiReferenceDevice (Device, DREF_STATUS_RESPONSE);
+
+ NdisChainBufferAtBack (Packet, AdapterStatusBuffer);
+
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ RemoteAddress,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE) + ValidStatusLength,
+ sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiProcessStatusQuery */
+
+
+VOID
+NbiSendStatusQuery(
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends NB_CMD_STATUS_QUERY frames.
+
+Arguments:
+
+ Request - Holds the request describing the remote adapter
+ status query. REQUEST_STATUS(Request) points
+ to the netbios cache entry for the remote name.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ PNETBIOS_CACHE CacheName;
+ PIPX_LOCAL_TARGET LocalTarget;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+ if (s == NULL) {
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_STATUS_QUERY;
+
+ CacheName = (PNETBIOS_CACHE)REQUEST_STATUS(Request);
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ RtlCopyMemory (Header->IpxHeader.DestinationNetwork, &CacheName->FirstResponse, 12);
+
+ LocalTarget = &CacheName->Networks[0].LocalTarget;
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_STATUS_QUERY)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_STATUS_QUERY)) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ Header->StatusResponse.ConnectionControlFlag = 0x00;
+ Header->StatusResponse.DataStreamType = NB_CMD_STATUS_QUERY;
+
+ NbiReferenceDevice (Device, DREF_STATUS_FRAME);
+
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) + sizeof(NB_STATUS_QUERY));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_STATUS_QUERY),
+ sizeof(IPX_HEADER) + sizeof(NB_STATUS_QUERY))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiProcessStatusQuery */
+
+
+VOID
+NbiProcessStatusResponse(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_STATUS_RESPONSE frames.
+
+Arguments:
+
+ MacBindingHandle - A handle to use when calling NdisTransferData.
+
+ MacReceiveContext - A context to use when calling NdisTransferData.
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The lookahead buffer, starting at the IPX
+ header.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ CTELockHandle LockHandle;
+ PREQUEST AdapterStatusRequest;
+ PNETBIOS_CACHE CacheName;
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY s;
+ PNDIS_BUFFER TargetBuffer;
+ ULONG TargetBufferLength, BytesToTransfer;
+ ULONG BytesTransferred;
+ NDIS_STATUS NdisStatus;
+ PNB_RECEIVE_RESERVED ReceiveReserved;
+ PNDIS_PACKET Packet;
+ BOOLEAN Found;
+ PNAME_BUFFER NameBuffer;
+ UINT i,NameCount = 0;
+ NB_CONNECTIONLESS UNALIGNED * Connectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)LookaheadBuffer;
+
+
+ if (PacketSize < (sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE))) {
+ return;
+ }
+
+ //
+ // Find out how many names are there.
+ //
+ NameBuffer = (PNAME_BUFFER)(LookaheadBuffer + sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE) + sizeof(ADAPTER_STATUS));
+ if ( LookaheadBufferSize > sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE) + sizeof(ADAPTER_STATUS) ) {
+ NameCount = (LookaheadBufferSize - (sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE) + sizeof(ADAPTER_STATUS)) ) /
+ sizeof(NAME_BUFFER);
+ }
+ //
+ // Find a request queued to this remote. If there are
+ // multiple requests outstanding for the same name we
+ // should get multiple responses, so we only need to
+ // find one.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Found = FALSE;
+ p = Device->ActiveAdapterStatus.Flink;
+
+ while (p != &Device->ActiveAdapterStatus) {
+
+ AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ CacheName = (PNETBIOS_CACHE)REQUEST_STATUS(AdapterStatusRequest);
+ if ( CacheName->Unique ) {
+ if (RtlEqualMemory(
+ &CacheName->FirstResponse,
+ Connectionless->IpxHeader.SourceNetwork,
+ 12)) {
+ Found = TRUE;
+ break;
+ }
+ } else if ( RtlEqualMemory( CacheName->NetbiosName,NetbiosBroadcastName,16)){
+ //
+ // It's a broadcast name. Any response is fine.
+ //
+ Found = TRUE;
+ break;
+ } else {
+ //
+ // It's group name. Make sure that this remote
+ // has this group name registered with him.
+ //
+ for (i =0;i<NameCount;i++) {
+ if ( (RtlEqualMemory(
+ CacheName->NetbiosName,
+ NameBuffer[i].name,
+ 16)) &&
+
+ (NameBuffer[i].name_flags & GROUP_NAME) ) {
+
+ Found = TRUE;
+ break;
+ }
+ }
+ }
+
+ }
+
+ if (!Found) {
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ NB_DEBUG2 (QUERY, ("Got response to AdapterStatus %lx\n", AdapterStatusRequest));
+
+ RemoveEntryList (REQUEST_LINKAGE(AdapterStatusRequest));
+
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free delete name cache entry %lx\n", CacheName));
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Name deleted");
+
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ s = NbiPopReceivePacket (Device);
+ if (s == NULL) {
+
+ REQUEST_INFORMATION (AdapterStatusRequest) = 0;
+ REQUEST_STATUS (AdapterStatusRequest) = STATUS_INSUFFICIENT_RESOURCES;
+
+ NbiCompleteRequest (AdapterStatusRequest);
+ NbiFreeRequest (Device, AdapterStatusRequest);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_QUERY);
+
+ return;
+ }
+
+ ReceiveReserved = CONTAINING_RECORD (s, NB_RECEIVE_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (ReceiveReserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ //
+ // Initialize the receive packet.
+ //
+
+ ReceiveReserved->Type = RECEIVE_TYPE_ADAPTER_STATUS;
+ ReceiveReserved->u.RR_AS.Request = AdapterStatusRequest;
+ REQUEST_STATUS(AdapterStatusRequest) = STATUS_SUCCESS;
+ CTEAssert (!ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = TRUE;
+
+ //
+ // Now that we have a packet and a buffer, set up the transfer.
+ // We will complete the request when the transfer completes.
+ //
+
+ TargetBuffer = REQUEST_NDIS_BUFFER (AdapterStatusRequest);
+
+ NdisChainBufferAtFront (Packet, TargetBuffer);
+
+ NbiGetBufferChainLength (TargetBuffer, &TargetBufferLength);
+ BytesToTransfer = PacketSize - (sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE));
+ if (TargetBufferLength < BytesToTransfer) {
+ BytesToTransfer = TargetBufferLength;
+ REQUEST_STATUS(AdapterStatusRequest) = STATUS_BUFFER_OVERFLOW;
+ }
+
+ (*Device->Bind.TransferDataHandler) (
+ &NdisStatus,
+ MacBindingHandle,
+ MacReceiveContext,
+ LookaheadBufferOffset + (sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE)),
+ BytesToTransfer,
+ Packet,
+ &BytesTransferred);
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+#if DBG
+ if (NdisStatus == STATUS_SUCCESS) {
+ CTEAssert (BytesTransferred == BytesToTransfer);
+ }
+#endif
+
+ NbiTransferDataComplete(
+ Packet,
+ NdisStatus,
+ BytesTransferred);
+
+ }
+
+} /* NbiProcessStatusResponse */
+
diff --git a/private/ntos/tdi/isn/nb/receive.c b/private/ntos/tdi/isn/nb/receive.c
new file mode 100644
index 000000000..721209d68
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/receive.c
@@ -0,0 +1,1307 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ receive.c
+
+Abstract:
+
+ This module contains the code to handle receive indication
+ and posted receives for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 22-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// This routine is a no-op to put in the NbiCallbacks table so
+// we can avoid checking for runt session frames (this is because
+// of how the if is structure below).
+//
+
+VOID
+NbiProcessSessionRunt(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+{
+ return;
+}
+
+NB_CALLBACK_NO_TRANSFER NbiCallbacksNoTransfer[] = {
+ NbiProcessFindName,
+ NbiProcessNameRecognized,
+ NbiProcessAddName,
+ NbiProcessAddName, // processes name in use frames also
+ NbiProcessDeleteName,
+ NbiProcessSessionRunt, // in case get a short session packet
+ NbiProcessSessionEnd,
+ NbiProcessSessionEndAck,
+ NbiProcessStatusQuery
+ };
+
+#ifdef RSRC_TIMEOUT_DBG
+VOID
+NbiProcessDeathPacket(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_SESSION_DATA frames.
+
+Arguments:
+
+ MacBindingHandle - A handle to use when calling NdisTransferData.
+
+ MacReceiveContext - A context to use when calling NdisTransferData.
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The lookahead buffer, starting at the IPX
+ header.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)LookaheadBuffer;
+ NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
+ PCONNECTION Connection;
+ PDEVICE Device = NbiDevice;
+ ULONG Hash;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ DbgPrint("******Received death packet - connid %x\n",Sess->DestConnectionId);
+
+ if ( !NbiGlobalDebugResTimeout ) {
+ return;
+ }
+
+ if (Sess->DestConnectionId != 0xffff) {
+
+ //
+ // This is an active connection, find it using
+ // our session id.
+ //
+
+ Hash = (Sess->DestConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Connection = Device->ConnectionHash[Hash].Connections;
+
+ while (Connection != NULL) {
+
+ if (Connection->LocalConnectionId == Sess->DestConnectionId) {
+ break;
+ }
+ Connection = Connection->NextConnection;
+ }
+
+ if (Connection == NULL) {
+ DbgPrint("********No Connection found with %x id\n",Sess->DestConnectionId);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ DbgPrint("******Received death packet on conn %lx from <%.16s>\n",Connection,Connection->RemoteName);
+ DbgBreakPoint();
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+}
+#endif //RSRC_TIMEOUT_DBG
+
+
+BOOLEAN
+NbiReceive(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN ULONG FwdAdapterCtx,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize,
+ IN PMDL pMdl
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles receive indications from IPX.
+
+Arguments:
+
+ MacBindingHandle - A handle to use when calling NdisTransferData.
+
+ MacReceiveContext - A context to use when calling NdisTransferData.
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The lookahead buffer, starting at the IPX
+ header.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ TRUE - receivepacket taken, will return later with NdisReturnPacket.
+ Currently, we always return FALSE.
+
+--*/
+
+{
+ PNB_FRAME NbFrame = (PNB_FRAME)LookaheadBuffer;
+ UCHAR DataStreamType;
+
+ //
+ // We know that this is a frame with a valid IPX header
+ // because IPX would not give it to use otherwise. However,
+ // it does not check the source socket.
+ //
+
+ if (NbFrame->Connectionless.IpxHeader.SourceSocket != NB_SOCKET) {
+ return FALSE;
+ }
+
+ ++NbiDevice->Statistics.PacketsReceived;
+
+ // First assume that the DataStreamType is at the normal place i.e 2nd byte
+ //
+
+ // Now see if this is a name frame.
+ //
+ if ( PacketSize == sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME) ) {
+ // In the internet mode, the DataStreamType2 becomes DataStreamType
+ if (NbFrame->Connectionless.IpxHeader.PacketType == 0x14 ) {
+ DataStreamType = NbFrame->Connectionless.NameFrame.DataStreamType2;
+ } else {
+ DataStreamType = NbFrame->Connectionless.NameFrame.DataStreamType;
+ }
+
+ // Is this a name frame?
+ // NB_CMD_FIND_NAME = 1 .... NB_CMD_DELETE_NAME = 5
+ //
+ if ((DataStreamType >= NB_CMD_FIND_NAME) && (DataStreamType <= NB_CMD_DELETE_NAME)) {
+ if (LookaheadBufferSize == PacketSize) {
+ (*NbiCallbacksNoTransfer[DataStreamType-1])(
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize);
+ }
+ return FALSE;
+ }
+
+ }
+
+#ifdef RSRC_TIMEOUT_DBG
+ if ((PacketSize >= sizeof(NB_CONNECTION)) &&
+ (NbFrame->Connection.Session.DataStreamType == NB_CMD_DEATH_PACKET)) {
+
+ NbiProcessDeathPacket(
+ MacBindingHandle,
+ MacReceiveContext,
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ LookaheadBufferOffset,
+ PacketSize);
+ }
+#endif //RSRC_TIMEOUT_DBG
+
+ if ((PacketSize >= sizeof(NB_CONNECTION)) &&
+ (NbFrame->Connection.Session.DataStreamType == NB_CMD_SESSION_DATA)) {
+
+ NbiProcessSessionData(
+ MacBindingHandle,
+ MacReceiveContext,
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ LookaheadBufferOffset,
+ PacketSize);
+
+ } else {
+
+ DataStreamType = NbFrame->Connectionless.NameFrame.DataStreamType;
+ // Handle NB_CMD_SESSION_END = 7 ... NB_CMD_STATUS_QUERY = 9
+ //
+ if ((DataStreamType >= NB_CMD_SESSION_END ) && (DataStreamType <= NB_CMD_STATUS_QUERY)) {
+ if (LookaheadBufferSize == PacketSize) {
+ (*NbiCallbacksNoTransfer[DataStreamType-1])(
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize);
+ }
+
+ } else if (DataStreamType == NB_CMD_STATUS_RESPONSE) {
+
+ NbiProcessStatusResponse(
+ MacBindingHandle,
+ MacReceiveContext,
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ LookaheadBufferOffset,
+ PacketSize);
+
+ } else if ((DataStreamType == NB_CMD_DATAGRAM) ||
+ (DataStreamType == NB_CMD_BROADCAST_DATAGRAM)) {
+
+ NbiProcessDatagram(
+ MacBindingHandle,
+ MacReceiveContext,
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ LookaheadBufferOffset,
+ PacketSize,
+ (BOOLEAN)(DataStreamType == NB_CMD_BROADCAST_DATAGRAM));
+
+ }
+
+ }
+
+ return FALSE;
+} /* NbiReceive */
+
+
+VOID
+NbiReceiveComplete(
+ IN USHORT NicId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles receive complete indications from IPX.
+
+Arguments:
+
+ NicId - The NIC ID on which a receive was previously indicated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PLIST_ENTRY p;
+ PADDRESS Address;
+ PREQUEST Request;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ PDEVICE Device = NbiDevice;
+ LIST_ENTRY LocalList;
+ PCONNECTION Connection;
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+
+ //
+ // Complete any pending receive requests.
+ //
+
+
+ if (!IsListEmpty (&Device->ReceiveCompletionQueue)) {
+
+ p = NB_REMOVE_HEAD_LIST(
+ &Device->ReceiveCompletionQueue,
+ &Device->Lock);
+
+ while (!NB_LIST_WAS_EMPTY(&Device->ReceiveCompletionQueue, p)) {
+
+ Request = LIST_ENTRY_TO_REQUEST (p);
+
+ //
+ // BUGBUG: Cache the connection somewhere easier
+ // to retrieve?
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_DEBUG2 (RECEIVE, ("Completing receive %lx (%d), status %lx\n",
+ Request, REQUEST_INFORMATION(Request), REQUEST_STATUS(Request)));
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (NbiDevice, Request);
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
+
+ NbiDereferenceConnection (Connection, CREF_RECEIVE);
+
+ p = NB_REMOVE_HEAD_LIST(
+ &Device->ReceiveCompletionQueue,
+ &Device->Lock);
+
+ }
+
+ }
+
+
+ //
+ // Indicate any datagrams to clients.
+ //
+
+ if (!IsListEmpty (&Device->ReceiveDatagrams)) {
+
+ p = NB_REMOVE_HEAD_LIST(
+ &Device->ReceiveDatagrams,
+ &Device->Lock);
+
+ while (!NB_LIST_WAS_EMPTY(&Device->ReceiveDatagrams, p)) {
+
+ ReceiveBuffer = CONTAINING_RECORD (p, NB_RECEIVE_BUFFER, WaitLinkage);
+ Address = ReceiveBuffer->Address;
+
+ NbiIndicateDatagram(
+ Address,
+ ReceiveBuffer->RemoteName,
+ ReceiveBuffer->Data,
+ ReceiveBuffer->DataLength);
+
+#if defined(_PNP_POWER)
+ NbiPushReceiveBuffer ( ReceiveBuffer );
+#else
+ NB_PUSH_ENTRY_LIST(
+ &Device->ReceiveBufferList,
+ &ReceiveBuffer->PoolLinkage,
+ &Device->Lock);
+#endif _PNP_POWER
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ p = NB_REMOVE_HEAD_LIST(
+ &Device->ReceiveDatagrams,
+ &Device->Lock);
+
+ }
+ }
+
+
+ //
+ // Start packetizing connections.
+ //
+
+ if (!IsListEmpty (&Device->PacketizeConnections)) {
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ //
+ // Check again because it may just have become
+ // empty, and the code below depends on it being
+ // non-empty.
+ //
+
+ if (!IsListEmpty (&Device->PacketizeConnections)) {
+
+ //
+ // We copy the list locally, in case someone gets
+ // put back on it. We have to hack the end so
+ // it points to LocalList instead of PacketizeConnections.
+ //
+
+ LocalList = Device->PacketizeConnections;
+ LocalList.Flink->Blink = &LocalList;
+ LocalList.Blink->Flink = &LocalList;
+
+ InitializeListHead (&Device->PacketizeConnections);
+
+ //
+ // Set all these connections to not be on the list, so
+ // NbiStopConnection won't try to take them off.
+ //
+
+ for (p = LocalList.Flink; p != &LocalList; p = p->Flink) {
+ Connection = CONTAINING_RECORD (p, CONNECTION, PacketizeLinkage);
+ CTEAssert (Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = FALSE;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ while (TRUE) {
+
+ p = RemoveHeadList (&LocalList);
+ if (p == &LocalList) {
+ break;
+ }
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, PacketizeLinkage);
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if ((Connection->State == CONNECTION_STATE_ACTIVE) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_A_PACKETIZE)) {
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG (LockHandle)
+ );
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_PACKETIZE);
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+ }
+
+} /* NbiReceiveComplete */
+
+
+VOID
+NbiTransferDataComplete(
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles a transfer data complete indication from
+ IPX, indicating that a previously issued NdisTransferData
+ call has completed.
+
+Arguments:
+
+ Packet - The packet associated with the transfer.
+
+ Status - The status of the transfer.
+
+ BytesTransferred - The number of bytes transferred.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNB_RECEIVE_RESERVED ReceiveReserved;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ PADDRESS Address;
+ PCONNECTION Connection;
+ PNDIS_BUFFER CurBuffer, TmpBuffer;
+ PREQUEST AdapterStatusRequest;
+ PDEVICE Device = NbiDevice;
+ CTELockHandle CancelLH;
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+
+ ReceiveReserved = (PNB_RECEIVE_RESERVED)(Packet->ProtocolReserved);
+
+ switch (ReceiveReserved->Type) {
+
+ case RECEIVE_TYPE_DATA:
+
+ CTEAssert (ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = FALSE;
+
+ Connection = ReceiveReserved->u.RR_CO.Connection;
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ Connection->CurrentReceive = Connection->PreviousReceive;
+ Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ //
+ // BUGBUG: Send a resend ack?
+ //
+
+ } else {
+
+ //
+ // This aborts the current receive and
+ // releases the connection lock.
+ //
+
+ NbiCompleteReceive(
+ Connection,
+ ReceiveReserved->u.RR_CO.EndOfMessage,
+ CancelLH
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ } else {
+
+
+ Connection->CurrentReceive.Offset += BytesTransferred;
+ Connection->CurrentReceive.MessageOffset += BytesTransferred;
+
+ if (ReceiveReserved->u.RR_CO.CompleteReceive ||
+ (Connection->State != CONNECTION_STATE_ACTIVE)) {
+
+ if (ReceiveReserved->u.RR_CO.EndOfMessage) {
+
+ CTEAssert (!ReceiveReserved->u.RR_CO.PartialReceive);
+
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax; // harmless if NewNetbios is FALSE
+ Connection->CurrentReceive.MessageOffset = 0;
+ Connection->CurrentIndicateOffset = 0;
+
+ } else if (Connection->NewNetbios) {
+
+ if (ReceiveReserved->u.RR_CO.PartialReceive) {
+ Connection->CurrentIndicateOffset += BytesTransferred;
+ } else {
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax;
+ Connection->CurrentIndicateOffset = 0;
+ }
+ }
+
+ //
+ // This sends an ack and releases the connection lock.
+ //
+
+ NbiCompleteReceive(
+ Connection,
+ ReceiveReserved->u.RR_CO.EndOfMessage,
+ CancelLH
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle );
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
+
+ if (Connection->NewNetbios) {
+
+ //
+ // A partial receive should only happen if we are
+ // completing the receive.
+ //
+
+ CTEAssert (!ReceiveReserved->u.RR_CO.PartialReceive);
+
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax;
+ Connection->CurrentIndicateOffset = 0;
+
+ if ((Connection->CurrentReceiveNoPiggyback) ||
+ ((Device->AckWindow != 0) &&
+ (++Connection->ReceivesWithoutAck >= Device->AckWindow))) {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ }
+
+ }
+
+ //
+ // Free the NDIS buffer chain if we allocated one.
+ //
+
+ if (!ReceiveReserved->u.RR_CO.NoNdisBuffer) {
+
+ NdisQueryPacket (Packet, NULL, NULL, &CurBuffer, NULL);
+
+ while (CurBuffer) {
+ TmpBuffer = NDIS_BUFFER_LINKAGE (CurBuffer);
+ NdisFreeBuffer (CurBuffer);
+ CurBuffer = TmpBuffer;
+ }
+
+ }
+
+ NdisReinitializePacket (Packet);
+ ExInterlockedPushEntrySList(
+ &Device->ReceivePacketList,
+ &ReceiveReserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+
+ break;
+
+ case RECEIVE_TYPE_DATAGRAM:
+
+ CTEAssert (ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = FALSE;
+
+ ReceiveBuffer = ReceiveReserved->u.RR_DG.ReceiveBuffer;
+
+ //
+ // Free the packet used for the transfer.
+ //
+
+ ReceiveReserved->u.RR_DG.ReceiveBuffer = NULL;
+ NdisReinitializePacket (Packet);
+ ExInterlockedPushEntrySList(
+ &Device->ReceivePacketList,
+ &ReceiveReserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ //
+ // If it succeeded then queue it for indication,
+ // otherwise free the receive buffer also.
+ //
+
+ if (Status == STATUS_SUCCESS) {
+
+ ReceiveBuffer->DataLength = BytesTransferred;
+ NB_INSERT_HEAD_LIST(
+ &Device->ReceiveDatagrams,
+ &ReceiveBuffer->WaitLinkage,
+ &Device->Lock);
+
+ } else {
+
+ Address = ReceiveBuffer->Address;
+
+#if defined(_PNP_POWER)
+ NbiPushReceiveBuffer ( ReceiveBuffer );
+#else
+ NB_PUSH_ENTRY_LIST(
+ &Device->ReceiveBufferList,
+ &ReceiveBuffer->PoolLinkage,
+ &Device->Lock);
+#endif _PNP_POWER
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ }
+
+ break;
+
+ case RECEIVE_TYPE_ADAPTER_STATUS:
+
+ CTEAssert (ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = FALSE;
+
+ AdapterStatusRequest = ReceiveReserved->u.RR_AS.Request;
+
+ //
+ // Free the packet used for the transfer.
+ //
+
+ NdisReinitializePacket (Packet);
+ ExInterlockedPushEntrySList(
+ &Device->ReceivePacketList,
+ &ReceiveReserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ //
+ // Complete the request.
+ //
+
+ if (Status == STATUS_SUCCESS) {
+
+ //
+ // REQUEST_STATUS() is already to set to SUCCESS or
+ // BUFFER_OVERFLOW based on whether the buffer was
+ // big enough.
+ //
+
+ REQUEST_INFORMATION(AdapterStatusRequest) = BytesTransferred;
+
+ } else {
+
+ REQUEST_INFORMATION(AdapterStatusRequest) = 0;
+ REQUEST_STATUS(AdapterStatusRequest) = STATUS_UNEXPECTED_NETWORK_ERROR;
+
+ }
+
+ NbiCompleteRequest (AdapterStatusRequest);
+ NbiFreeRequest (Device, AdapterStatusRequest);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_QUERY);
+
+ break;
+
+ }
+
+} /* NbiTransferDataComplete */
+
+
+VOID
+NbiAcknowledgeReceive(
+ IN PCONNECTION Connection
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a receive needs to be acked to
+ the remote. It either sends a data ack or queues up a piggyback
+ ack request.
+
+ NOTE: THIS FUNCTION IS CALLED WITH THE CONNECTION LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - Pointer to the connection.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+
+ if (Connection->NewNetbios) {
+
+ //
+ // CurrentReceiveNoPiggyback is based on the bits he
+ // set in his frame, NoPiggybackHeuristic is based on
+ // guesses about the traffic pattern, it is set to
+ // TRUE if we think we should not piggyback.
+ //
+
+ if ((!Device->EnablePiggyBackAck) ||
+ (Connection->CurrentReceiveNoPiggyback) ||
+ (Connection->PiggybackAckTimeout) ||
+ (Connection->NoPiggybackHeuristic)) {
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ if (!Connection->DataAckPending) {
+
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+
+ //
+ // Some stacks can have multiple messages
+ // outstanding, so we may already have an
+ // ack queued.
+ //
+
+ Connection->DataAckTimeouts = 0;
+ Connection->DataAckPending = TRUE;
+
+ ++Device->Statistics.PiggybackAckQueued;
+
+ if (!Connection->OnDataAckQueue) {
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle1);
+
+ if (!Connection->OnDataAckQueue) {
+ Connection->OnDataAckQueue = TRUE;
+ InsertTailList (&Device->DataAckConnections, &Connection->DataAckLinkage);
+ }
+
+ if (!Device->DataAckActive) {
+ NbiStartShortTimer (Device);
+ Device->DataAckActive = TRUE;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle1);
+ }
+
+ //
+ // Clear this, since a message ack resets the count.
+ //
+
+ Connection->ReceivesWithoutAck = 0;
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ } else {
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+}
+
+
+VOID
+NbiCompleteReceive(
+ IN PCONNECTION Connection,
+ IN BOOLEAN EndOfMessage,
+ IN CTELockHandle CancelLH
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when we have filled up a receive request
+ and need to complete it.
+
+ NOTE: THIS FUNCTION IS CALLED WITH THE CONNECTION LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+ THIS ROUTINE ALSO HOLDS CANCEL SPIN LOCK WHEN IT IS CALLED
+ AND RELEASES IT WHEN IT RETURNS.
+Arguments:
+
+ Connection - Pointer to the connection.
+
+ EndOfMessage - BOOLEAN set to true if the message end was received.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST Request;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Complete the current receive request. If the connection
+ // has shut down then we complete it right here, otherwise
+ // we queue it for completion in the receive complete
+ // handler.
+ //
+
+ Request = Connection->ReceiveRequest;
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle );
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ if (Connection->State != CONNECTION_STATE_ACTIVE) {
+
+ Connection->ReceiveRequest = NULL; // StopConnection won't do this
+
+ REQUEST_STATUS(Request) = Connection->Status;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NB_DEBUG2 (RECEIVE, ("Completing receive %lx (%d), status %lx\n",
+ Request, REQUEST_INFORMATION(Request), REQUEST_STATUS(Request)));
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (NbiDevice, Request);
+
+ ++Connection->ConnectionInfo.ReceiveErrors;
+
+ NbiDereferenceConnection (Connection, CREF_RECEIVE);
+
+ } else {
+
+ REQUEST_INFORMATION (Request) = Connection->CurrentReceive.Offset;
+
+ if (EndOfMessage) {
+
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+
+ } else {
+
+ REQUEST_STATUS(Request) = STATUS_BUFFER_OVERFLOW;
+
+ }
+
+ //
+ // If we indicated to the client, adjust this down by the
+ // amount of data taken, when it hits zero we can reindicate.
+ //
+
+ if (Connection->ReceiveUnaccepted) {
+ NB_DEBUG2 (RECEIVE, ("Moving Unaccepted %d down by %d\n",
+ Connection->ReceiveUnaccepted, Connection->CurrentReceive.Offset));
+ if (Connection->CurrentReceive.Offset >= Connection->ReceiveUnaccepted) {
+ Connection->ReceiveUnaccepted = 0;
+ } else {
+ Connection->ReceiveUnaccepted -= Connection->CurrentReceive.Offset;
+ }
+ }
+
+ //
+ // BUGBUG: Check whether to activate another receive?
+ //
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_PENDING;
+ Connection->ReceiveRequest = NULL;
+
+ //
+ // This releases the lock.
+ //
+
+ if (Connection->NewNetbios) {
+
+ if (EndOfMessage) {
+
+ NbiAcknowledgeReceive(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ if (Connection->CurrentIndicateOffset != 0) {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResend
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else if ((Connection->CurrentReceiveNoPiggyback) ||
+ ((Device->AckWindow != 0) &&
+ (++Connection->ReceivesWithoutAck >= Device->AckWindow))) {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+ }
+
+ } else {
+
+ NbiSendDataAck(
+ Connection,
+ EndOfMessage ? NbiAckResponse : NbiAckResend
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ ++Connection->ConnectionInfo.ReceivedTsdus;
+
+ //
+ // This will complete the request inside ReceiveComplete,
+ // dereference the connection, and set the state to IDLE.
+ //
+
+ NB_INSERT_TAIL_LIST(
+ &Device->ReceiveCompletionQueue,
+ REQUEST_LINKAGE (Request),
+ &Device->Lock);
+
+ }
+
+} /* NbiCompleteReceive */
+
+
+NTSTATUS
+NbiTdiReceive(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does a receive on an active connection.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the receive.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ PCONNECTION Connection;
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ CTELockHandle CancelLH;
+
+ //
+ // First make sure the connection is valid.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ if (Connection->Type == NB_CONNECTION_SIGNATURE) {
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_BEGIN_SYNC (&SyncContext);
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ //
+ // Make sure the connection is in a good state.
+ //
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ //
+ // If the connection is idle then send it now, otherwise
+ // queue it.
+ //
+
+
+ if (!Request->Cancel) {
+
+ IoSetCancelRoutine (Request, NbiCancelReceive);
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle );
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ NbiReferenceConnectionSync (Connection, CREF_RECEIVE);
+
+ //
+ // Insert this in our queue, then see if we need
+ // to wake up the remote.
+ //
+
+ REQUEST_SINGLE_LINKAGE(Request) = NULL;
+ REQUEST_LIST_INSERT_TAIL(&Connection->ReceiveQueue, Request);
+
+ if (Connection->ReceiveState != CONNECTION_RECEIVE_W_RCV) {
+
+ NB_DEBUG2 (RECEIVE, ("Receive %lx, connection %lx idle\n", Request, Connection));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ } else {
+
+ NB_DEBUG2 (RECEIVE, ("Receive %lx, connection %lx awakened\n", Request, Connection));
+ Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
+
+ //
+ // This releases the lock.
+ //
+
+ if (Connection->NewNetbios) {
+
+ Connection->LocalRcvSequenceMax = (USHORT)
+ (Connection->ReceiveSequence + Connection->ReceiveWindowSize - 1);
+
+ }
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResend
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ NB_END_SYNC (&SyncContext);
+ return STATUS_PENDING;
+
+ } else {
+
+ NB_DEBUG2 (RECEIVE, ("Receive %lx, connection %lx cancelled\n", Request, Connection));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_END_SYNC (&SyncContext);
+
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ return STATUS_CANCELLED;
+
+ }
+
+ } else {
+
+ NB_DEBUG2 (RECEIVE, ("Receive connection %lx state is %d\n", Connection, Connection->State));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_END_SYNC (&SyncContext);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ return STATUS_INVALID_CONNECTION;
+
+ }
+
+ } else {
+
+ NB_DEBUG (RECEIVE, ("Receive connection %lx has bad signature\n", Connection));
+ return STATUS_INVALID_CONNECTION;
+
+ }
+
+} /* NbiTdiReceive */
+
+
+VOID
+NbiCancelReceive(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a receive.
+ The request is found on the connection's receive queue.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PREQUEST Request = (PREQUEST)Irp;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_RECEIVE));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+
+ //
+ // Just stop the connection, that will tear down any
+ // receives.
+ //
+ // BUGBUG: Do we care about cancelling non-active
+ // receives without stopping the connection??
+ //
+ // BUGBUG: This routine is the same as NbiCancelSend,
+ // so if we don't make it more specific, merge the two.
+ //
+
+ NbiReferenceConnectionSync (Connection, CREF_CANCEL);
+
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+
+ NB_BEGIN_SYNC (&SyncContext);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ //
+ // This frees the lock, cancels any sends, etc.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_CANCELLED
+ NB_LOCK_HANDLE_ARG (LockHandle));
+
+ NbiDereferenceConnection (Connection, CREF_CANCEL);
+
+ NB_END_SYNC (&SyncContext);
+
+} /* NbiCancelReceive */
+
diff --git a/private/ntos/tdi/isn/nb/send.c b/private/ntos/tdi/isn/nb/send.c
new file mode 100644
index 000000000..a4443c73c
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/send.c
@@ -0,0 +1,2886 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ This module contains the send routines for the Netbios
+ module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 22-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+
+VOID
+NbiSendComplete(
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+)
+
+/*++
+
+Routine Description:
+
+ This routine handles a send completion call from IPX.
+
+Arguments:
+
+ Packet - The packet which has been completed.
+
+ Status - The status of the send.
+
+Return Value:
+
+ None.
+
+--*/
+
+
+
+{
+ PDEVICE Device = NbiDevice;
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ PCONNECTION Connection;
+ PREQUEST DatagramRequest;
+ PREQUEST SendRequest, TmpRequest;
+ PNDIS_BUFFER CurBuffer, TmpBuffer;
+ PNETBIOS_CACHE CacheName;
+ PNDIS_BUFFER SecondBuffer;
+ PVOID SecondBufferMemory;
+ UINT SecondBufferLength;
+ ULONG oldvalue;
+ PNB_SEND_RESERVED Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
+ CTELockHandle CancelLH;
+#if defined(_PNP_POWER)
+ CTELockHandle LockHandle;
+#endif _PNP_POWER
+
+ //
+ // We jump back here if we re-call send from inside this
+ // function and it doesn't pend (to avoid stack overflow).
+ //
+
+FunctionStart:;
+
+ ++Device->Statistics.PacketsSent;
+
+ switch (Reserved->Type) {
+
+ case SEND_TYPE_SESSION_DATA:
+
+ //
+ // This was a send on a session. This references the
+ // IRP.
+ //
+
+ NB_DEBUG2 (SEND, ("Complete NDIS packet %lx\n", Reserved));
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ Connection = Reserved->u.SR_CO.Connection;
+ SendRequest = Reserved->u.SR_CO.Request;
+
+ if (!Reserved->u.SR_CO.NoNdisBuffer) {
+
+ CurBuffer = NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer));
+ while (CurBuffer) {
+ TmpBuffer = NDIS_BUFFER_LINKAGE (CurBuffer);
+ NdisFreeBuffer (CurBuffer);
+ CurBuffer = TmpBuffer;
+ }
+
+ }
+
+ //
+ // If NoNdisBuffer is TRUE, then we could set
+ // Connection->SendBufferInUse to FALSE here. The
+ // problem is that a new send might be in progress
+ // by the time this completes and it may have
+ // used the user buffer, then if we need to
+ // retransmit that packet we would use the buffer
+ // twice. We instead rely on the fact that whenever
+ // we make a new send active we set SendBufferInUse
+ // to FALSE. The net effect is that the user's buffer
+ // can be used the first time a send is packetize
+ // but not on resends.
+ //
+
+ NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = NULL;
+ NdisRecalculatePacketCounts (Packet);
+
+#if DBG
+ if (REQUEST_REFCOUNT(SendRequest) > 100) {
+ DbgPrint ("Request %lx (%lx) has high refcount\n",
+ Connection, SendRequest);
+ DbgBreakPoint();
+ }
+#endif
+
+#if defined(__PNP)
+ NB_GET_LOCK( &Connection->Lock, &LockHandle );
+ oldvalue = REQUEST_REFCOUNT(SendRequest)--;
+ if ( DEVICE_NETWORK_PATH_NOT_FOUND == Status ) {
+ Connection->LocalTarget = Reserved->LocalTarget;
+ }
+ NB_FREE_LOCK( &Connection->Lock, LockHandle );
+#else
+ oldvalue = NB_ADD_ULONG(
+ &REQUEST_REFCOUNT (SendRequest),
+ (ULONG)-1,
+ &Connection->Lock);
+#endif __PNP
+
+ if (oldvalue == 1) {
+
+ //
+ // If the refcount on this request is now zero then
+ // we already got the ack for it, which means
+ // that the ack-processing code has unlinked the
+ // request from Connection->SendQueue. So we
+ // can just run the queue of connections here
+ // and complete them.
+ //
+ // We dereference the connection for all but one
+ // of the requests, we hang on to that until a bit
+ // later so everything stays around.
+ //
+
+ while (TRUE) {
+
+ TmpRequest = REQUEST_SINGLE_LINKAGE (SendRequest);
+ NB_DEBUG2 (SEND, ("Completing request %lx from send complete\n", SendRequest));
+ REQUEST_STATUS (SendRequest) = STATUS_SUCCESS;
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (SendRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ NbiCompleteRequest (SendRequest);
+ NbiFreeRequest (Device, SendRequest);
+ ++Connection->ConnectionInfo.TransmittedTsdus;
+ SendRequest = TmpRequest;
+
+ if (SendRequest == NULL) {
+ break;
+ }
+ NbiDereferenceConnection (Connection, CREF_SEND);
+
+ }
+
+ }
+
+ if (Reserved->OwnedByConnection) {
+
+ Connection->SendPacketInUse = FALSE;
+
+ if (Connection->OnWaitPacketQueue) {
+
+ //
+ // This will put the connection on the packetize
+ // queue if appropriate.
+ //
+
+ NbiCheckForWaitPacket (Connection);
+
+ }
+
+ } else {
+
+ NbiPushSendPacket(Reserved);
+
+ }
+
+ if (oldvalue == 1) {
+ NbiDereferenceConnection (Connection, CREF_SEND);
+ }
+
+ break;
+
+ case SEND_TYPE_NAME_FRAME:
+
+ //
+ // The frame is an add name/delete name; put it back in
+ // the pool and deref the address.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+
+ Address = Reserved->u.SR_NF.Address;
+
+#if !defined(_PNP_POWER)
+ if ((Reserved->u.SR_NF.CurrentNicId) &&
+ (Reserved->u.SR_NF.CurrentNicId < Device->MaximumNicId)) {
+
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ IPX_LOCAL_TARGET TempLocalTarget;
+
+ //
+ // This is a name frame being sent to every address, so
+ // resent it to the next NIC ID. We hold the address
+ // reference through this send.
+ //
+
+ CTEAssert (Address != NULL);
+
+ ++Reserved->u.SR_NF.CurrentNicId;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
+
+ Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
+ Header->NameFrame.ConnectionControlFlag = 0x00;
+ Header->NameFrame.DataStreamType = Reserved->u.SR_NF.DataStreamType;
+ Header->NameFrame.NameTypeFlag = Reserved->u.SR_NF.NameTypeFlag;
+
+ //
+ // This is not a name in use frame so DataStreamType2
+ // is the same as DataStreamType.
+ //
+
+ Header->NameFrame.DataStreamType2 = Reserved->u.SR_NF.DataStreamType;
+
+ RtlCopyMemory(
+ Header->NameFrame.Name,
+ Address->NetbiosAddress.NetbiosName,
+ 16);
+
+ //
+ // Now send the frame (because it is all in the first segment,
+ // IPX will adjust the length of the buffer correctly).
+ //
+
+ TempLocalTarget.NicId = Reserved->u.SR_NF.CurrentNicId;
+ RtlCopyMemory (TempLocalTarget.MacAddress, BroadcastAddress, 6);
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME));
+ if ((Status =
+ (*Device->Bind.SendHandler)(
+ &TempLocalTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
+
+ goto FunctionStart;
+
+ }
+
+ return;
+
+ }
+#endif !_PNP_POWER
+
+ Reserved->SendInProgress = FALSE;
+
+ NbiPushSendPacket (Reserved);
+
+ if (Address) {
+ NbiDereferenceAddress (Address, AREF_NAME_FRAME);
+ } else {
+ NbiDereferenceDevice (Device, DREF_NAME_FRAME);
+ }
+
+ break;
+
+ case SEND_TYPE_SESSION_INIT:
+
+ //
+ // This is a session initialize or session init ack; free
+ // the second buffer, put the packet back in the pool and
+ // deref the device.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ NdisUnchainBufferAtBack (Packet, &SecondBuffer);
+ NdisQueryBuffer (SecondBuffer, &SecondBufferMemory, &SecondBufferLength);
+ CTEAssert (SecondBufferLength == sizeof(NB_SESSION_INIT));
+
+ NdisFreeBuffer(SecondBuffer);
+ NbiFreeMemory (SecondBufferMemory, sizeof(NB_SESSION_INIT), MEMORY_CONNECTION, "Session Initialize");
+
+ NbiPushSendPacket (Reserved);
+
+ NbiDereferenceDevice (Device, DREF_SESSION_INIT);
+
+ break;
+
+ case SEND_TYPE_SESSION_NO_DATA:
+
+ //
+ // This is a frame which was sent on a connection but
+ // has no data (ack, session end, session end ack).
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ Connection = Reserved->u.SR_CO.Connection;
+
+ if (Reserved->OwnedByConnection) {
+
+ CTEAssert (Connection != NULL);
+ Connection->SendPacketInUse = FALSE;
+
+ if (Connection->OnWaitPacketQueue) {
+
+ //
+ // This will put the connection on the packetize
+ // queue if appropriate.
+ //
+
+ NbiCheckForWaitPacket (Connection);
+
+ }
+
+ } else {
+
+ NbiPushSendPacket(Reserved);
+
+ }
+
+ if (Connection != NULL) {
+ NbiDereferenceConnection (Connection, CREF_FRAME);
+ } else {
+ NbiDereferenceDevice (Device, DREF_FRAME);
+ }
+
+ break;
+
+ case SEND_TYPE_FIND_NAME:
+
+ //
+ // The frame is a find name; just set SendInProgress to
+ // FALSE and FindNameTimeout will clean it up.
+ //
+#if defined(_PNP_POWER)
+ NB_GET_LOCK( &Device->Lock, &LockHandle);
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+ //
+ // We keep track of when it finds a net that isn't
+ // a down wan line so that we can tell when datagram
+ // sends should fail (otherwise we succeed them, so
+ // the browser won't think this is a down wan line).
+ //
+ if ( STATUS_SUCCESS == Status ) {
+ NB_SET_SR_FN_SENT_ON_UP_LINE (Reserved, TRUE);
+ } else {
+ NB_DEBUG( CACHE, ("Send complete of find name with failure %lx\n",Status ));
+ }
+ NB_FREE_LOCK(&Device->Lock, LockHandle);
+#else
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+#endif _PNP_POWER
+ break;
+
+ case SEND_TYPE_DATAGRAM:
+
+ //
+ // If there are any more networks to send this on then
+ // do so, otherwise put it back in the pool and complete
+ // the request.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ if ((Reserved->u.SR_DG.Cache == NULL) ||
+ (++Reserved->u.SR_DG.CurrentNetwork >=
+ Reserved->u.SR_DG.Cache->NetworksUsed)) {
+
+ AddressFile = Reserved->u.SR_DG.AddressFile;
+ DatagramRequest = Reserved->u.SR_DG.DatagramRequest;
+
+ NB_DEBUG2 (DATAGRAM, ("Completing datagram %lx on %lx\n", DatagramRequest, AddressFile));
+
+ //
+ // Remove any user buffers chained on this packet.
+ //
+
+ NdisReinitializePacket (Packet);
+ NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = NULL;
+ NdisChainBufferAtFront (Packet, Reserved->HeaderBuffer);
+
+ //
+ // Complete the request.
+ //
+
+ REQUEST_STATUS(DatagramRequest) = Status;
+
+ NbiCompleteRequest(DatagramRequest);
+ NbiFreeRequest (Device, DatagramRequest);
+
+ CacheName = Reserved->u.SR_DG.Cache;
+
+ NbiPushSendPacket (Reserved);
+
+ //
+ // Since we are no longer referencing the cache
+ // name, see if we should delete it (this will
+ // happen if the cache entry was aged out while
+ // the datagram was being processed).
+ //
+
+ if (CacheName != NULL) {
+
+ oldvalue = NB_ADD_ULONG(
+ &CacheName->ReferenceCount,
+ (ULONG)-1,
+ &Device->Lock);
+
+ if (oldvalue == 1) {
+
+ NB_DEBUG2 (CACHE, ("Free aged cache entry %lx\n", CacheName));
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free old cache");
+
+ }
+ }
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_SEND_DGRAM);
+
+ } else {
+
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ PIPX_LOCAL_TARGET LocalTarget;
+ ULONG HeaderLength;
+ ULONG PacketLength;
+
+ // send the datagram on the next net.
+ CTEAssert (!Reserved->u.SR_DG.Cache->Unique);
+ Reserved->SendInProgress = TRUE;
+
+ CacheName = Reserved->u.SR_DG.Cache;
+
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address, so we modify
+ // that for the current netbios cache entry if needed.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+
+
+ *(UNALIGNED ULONG *)Header->IpxHeader.DestinationNetwork = CacheName->Networks[Reserved->u.SR_DG.CurrentNetwork].Network;
+ RtlCopyMemory (&Header->IpxHeader.DestinationNode, BroadcastAddress, 6);
+
+ LocalTarget = &CacheName->Networks[Reserved->u.SR_DG.CurrentNetwork].LocalTarget;
+
+
+ HeaderLength = sizeof(IPX_HEADER) + sizeof(NB_DATAGRAM);
+
+ PacketLength = HeaderLength + REQUEST_INFORMATION(Reserved->u.SR_DG.DatagramRequest);
+
+ Header->IpxHeader.PacketLength[0] = (UCHAR)(PacketLength / 256);
+ Header->IpxHeader.PacketLength[1] = (UCHAR)(PacketLength % 256);
+ Header->IpxHeader.PacketType = 0x04;
+
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ Header->Datagram.ConnectionControlFlag = 0x00;
+ RtlCopyMemory(
+ Header->Datagram.SourceName,
+ Reserved->u.SR_DG.AddressFile->Address->NetbiosAddress.NetbiosName,
+ 16);
+
+ if (Reserved->u.SR_DG.RemoteName != (PVOID)-1) {
+
+ //
+ // This is a directed, as opposed to broadcast, datagram.
+ //
+
+ Header->Datagram.DataStreamType = NB_CMD_DATAGRAM;
+ RtlCopyMemory(
+ Header->Datagram.DestinationName,
+ Reserved->u.SR_DG.RemoteName->NetbiosName,
+ 16);
+
+ } else {
+
+ Header->Datagram.DataStreamType = NB_CMD_BROADCAST_DATAGRAM;
+ RtlZeroMemory(
+ Header->Datagram.DestinationName,
+ 16);
+
+ }
+
+
+ //
+ // Now send the frame (IPX will adjust the length of the
+ // first buffer and the whole frame correctly).
+ //
+
+ if ((Status =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ PacketLength,
+ HeaderLength)) != STATUS_PENDING) {
+
+ goto FunctionStart;
+ }
+
+ }
+
+ break;
+
+ case SEND_TYPE_STATUS_QUERY:
+
+ //
+ // This is an adapter status query, which is a simple
+ // packet.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ NbiPushSendPacket (Reserved);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_FRAME);
+
+ break;
+
+ case SEND_TYPE_STATUS_RESPONSE:
+
+ //
+ // This is an adapter status response, we have to free the
+ // second buffer.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ NdisUnchainBufferAtBack (Packet, &SecondBuffer);
+ NdisQueryBuffer (SecondBuffer, &SecondBufferMemory, &SecondBufferLength);
+
+ NdisFreeBuffer(SecondBuffer);
+ NbiFreeMemory (SecondBufferMemory, Reserved->u.SR_AS.ActualBufferLength, MEMORY_STATUS, "Adapter Status");
+
+ NbiPushSendPacket (Reserved);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_RESPONSE);
+
+ break;
+
+#ifdef RSRC_TIMEOUT_DBG
+ case SEND_TYPE_DEATH_PACKET:
+
+ //
+ // This is a session initialize or session init ack; free
+ // the second buffer, put the packet back in the pool and
+ // deref the device.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+ DbgPrint("********Death packet send completed status %lx\n",Status);
+ DbgBreakPoint();
+ break;
+#endif //RSRC_TIMEOUT_DBG
+
+ default:
+
+ CTEAssert (FALSE);
+ break;
+
+ }
+
+} /* NbiSendComplete */
+
+#if 0
+ULONG NbiLoudSendQueue = 1;
+#endif
+
+VOID
+NbiAssignSequenceAndSend(
+ IN PCONNECTION Connection,
+ IN PNDIS_PACKET Packet
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to ensure that receive sequence numbers on
+ packets are numbered correctly. It is called in place of the lower-level
+ send handler; after assigning the receive sequence number it locks out
+ other sends until the NdisSend call has returned (not necessarily completed),
+ insuring that the packets with increasing receive sequence numbers
+ are queue in the right order by the MAC.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE CONNECTION LOCK HELD, AND
+ RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection the send is on.
+
+ Packet - The packet to send.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS NdisStatus;
+ PNB_SEND_RESERVED Reserved;
+ PLIST_ENTRY p;
+ NB_CONNECTION UNALIGNED * Header;
+ PDEVICE Device = NbiDevice;
+ BOOLEAN NdisSendReference;
+ ULONG result;
+
+
+ Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
+
+ CTEAssert (Connection->State == CONNECTION_STATE_ACTIVE);
+
+ //
+ // If there is a send in progress, then queue this packet
+ // and return.
+ //
+
+ if (Connection->NdisSendsInProgress > 0) {
+
+ NB_DEBUG2 (SEND, ("Queueing send packet %lx on %lx\n", Reserved, Connection));
+ InsertTailList (&Connection->NdisSendQueue, &Reserved->WaitLinkage);
+ ++Connection->NdisSendsInProgress;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+ }
+
+ //
+ // No send in progress. Set the flag to true, and fill in the
+ // receive sequence fields in the packet.
+ //
+
+ Connection->NdisSendsInProgress = 1;
+ NdisSendReference = FALSE;
+ Connection->NdisSendReference = &NdisSendReference;
+
+ while (TRUE) {
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ Header->Session.ReceiveSequence = Connection->ReceiveSequence;
+ if (Connection->NewNetbios) {
+ Header->Session.ReceiveSequenceMax = Connection->LocalRcvSequenceMax;
+ } else {
+ Header->Session.BytesReceived = (USHORT)Connection->CurrentReceive.MessageOffset;
+ }
+
+ //
+ // Since we are acking as much as we know, we can clear
+ // this flag. The connection will eventually get removed
+ // from the queue by the long timeout.
+ //
+
+ Connection->DataAckPending = FALSE;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+ NdisStatus = (*Device->Bind.SendHandler)(
+ &Connection->LocalTarget,
+ Packet,
+ Reserved->u.SR_CO.PacketLength,
+ sizeof(NB_CONNECTION));
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+ //
+ // Take the ref count down, which may allow others
+ // to come through.
+ //
+
+ result = NB_ADD_ULONG(
+ &Connection->NdisSendsInProgress,
+ (ULONG)-1,
+ &Connection->Lock);
+
+ //
+ // We have now sent a packet, see if any queued up while we
+ // were doing it. If the count was zero after removing ours,
+ // then anything else queued is being processed, so we can
+ // exit. If the connection was stopped while we were sending,
+ // a special reference was added which we remove (NbiStopConnection
+ // sets NdisSendReference to TRUE, using the pointer saved
+ // in Connection->NdisSendReference).
+ //
+
+ if (result == 1) {
+ if (NdisSendReference) {
+ NB_DEBUG2 (SEND, ("Remove CREF_NDIS_SEND from %lx\n", Connection));
+ NbiDereferenceConnection (Connection, CREF_NDIS_SEND);
+ }
+ return;
+ }
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ p = RemoveHeadList(&Connection->NdisSendQueue);
+
+ //
+ // If the refcount was not zero, then nobody else should
+ // have taken packets off since they would have been
+ // blocked by us. So, the queue should not be empty.
+ //
+
+ ASSERT (p != &Connection->NdisSendQueue);
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ } // while loop
+
+ //
+ // We should never reach here.
+ //
+
+ CTEAssert (FALSE);
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+} /* NbiAssignSequenceAndSend */
+
+
+NTSTATUS
+NbiTdiSend(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does a send on an active connection.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the send.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PTDI_REQUEST_KERNEL_SEND Parameters;
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ CTELockHandle CancelLH;
+
+ //
+ // First make sure the connection is valid.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ if (Connection->Type == NB_CONNECTION_SIGNATURE) {
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_BEGIN_SYNC (&SyncContext);
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ //
+ // Make sure the connection is in a good state.
+ //
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ //
+ // If the connection is idle then send it now, otherwise
+ // queue it.
+ //
+
+
+ if (!Request->Cancel) {
+
+
+ Parameters = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request);
+
+ //
+ // For old netbios, don't allow sends greater than 64K-1.
+ //
+
+ if ((Connection->NewNetbios) ||
+ (Parameters->SendLength <= 0xffff)) {
+
+ IoSetCancelRoutine (Request, NbiCancelSend);
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle );
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ REQUEST_INFORMATION (Request) = Parameters->SendLength; // assume it succeeds.
+
+ REQUEST_REFCOUNT (Request) = 1; // refcount starts at 1.
+ NbiReferenceConnectionSync (Connection, CREF_SEND);
+
+ //
+ // NOTE: The connection send queue is managed such
+ // that the current send being packetized is not on
+ // the queue. For multiple-request messages, the
+ // first one is not on the queue, but its linkage
+ // field points to the next request in the message
+ // (which will be on the head of the queue).
+ //
+
+ if ((Parameters->SendFlags & TDI_SEND_PARTIAL) == 0) {
+
+ //
+ // This is a final send.
+ //
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_IDLE) {
+
+ NB_DEBUG2 (SEND, ("Send %lx, connection %lx idle\n", Request, Connection));
+
+ Connection->CurrentSend.Request = Request;
+ Connection->CurrentSend.MessageOffset = 0;
+ Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentSend.BufferOffset = 0;
+ Connection->SendBufferInUse = FALSE;
+
+ Connection->UnAckedSend = Connection->CurrentSend;
+
+ Connection->FirstMessageRequest = Request;
+#ifdef RSRC_TIMEOUT_DBG
+ KeQuerySystemTime(&Connection->FirstMessageRequestTime);
+
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Connection->FirstMessageRequestTime.QuadPart;
+#endif //RSRC_TIMEOUT_DBG
+
+ Connection->LastMessageRequest = Request;
+ Connection->CurrentMessageLength = Parameters->SendLength;
+
+ //
+ // This frees the connection lock.
+ //
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle)
+ );
+
+ } else if (Connection->SubState == CONNECTION_SUBSTATE_A_W_EOR) {
+
+ //
+ // We have been collecting partial sends waiting
+ // for a final one, which we have now received,
+ // so start packetizing.
+ //
+ // We chain it on the back of the send queue,
+ // in addition if this is the second request in the
+ // message, we have to link the first request (which
+ // is not on the queue) to this one.
+ //
+ //
+
+ NB_DEBUG2 (SEND, ("Send %lx, connection %lx got eor\n", Request, Connection));
+
+ Connection->LastMessageRequest = Request;
+ Connection->CurrentMessageLength += Parameters->SendLength;
+
+ if (Connection->SendQueue.Head == NULL) {
+ REQUEST_SINGLE_LINKAGE(Connection->FirstMessageRequest) = Request;
+ }
+ REQUEST_SINGLE_LINKAGE(Request) = NULL;
+ REQUEST_LIST_INSERT_TAIL(&Connection->SendQueue, Request);
+
+ Connection->UnAckedSend = Connection->CurrentSend;
+#ifdef RSRC_TIMEOUT_DBG
+ {
+ LARGE_INTEGER Time;
+
+ KeQuerySystemTime(&Time);
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Time.QuadPart;
+ }
+#endif //RSRC_TIMEOUT_DBG
+ //
+ // This frees the connection lock.
+ //
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle)
+ );
+
+ } else {
+
+ //
+ // The state is PACKETIZE, W_ACK, or W_PACKET.
+ //
+
+ NB_DEBUG2 (SEND, ("Send %lx, connection %lx busy\n", Request, Connection));
+
+ REQUEST_SINGLE_LINKAGE(Request) = NULL;
+ REQUEST_LIST_INSERT_TAIL(&Connection->SendQueue, Request);
+
+#ifdef RSRC_TIMEOUT_DBG
+ {
+ LARGE_INTEGER Time;
+ KeQuerySystemTime(&Time);
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Time.QuadPart;
+ }
+#endif //RSRC_TIMEOUT_DBG
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ //
+ // This is a partial send. We queue them up without
+ // packetizing until we get a final (this is because
+ // we have to put a correct Connection->CurrentMessageLength
+ // in the frames.
+ //
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_IDLE) {
+
+ //
+ // Start collecting partial sends. NOTE: Partial sends
+ // are always inserted in the send queue
+ //
+
+ Connection->CurrentSend.Request = Request;
+ Connection->CurrentSend.MessageOffset = 0;
+ Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentSend.BufferOffset = 0;
+ Connection->SendBufferInUse = FALSE;
+
+ Connection->FirstMessageRequest = Request;
+#ifdef RSRC_TIMEOUT_DBG
+ KeQuerySystemTime(&Connection->FirstMessageRequestTime);
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Connection->FirstMessageRequestTime.QuadPart;
+#endif //RSRC_TIMEOUT_DBG
+
+ Connection->CurrentMessageLength = Parameters->SendLength;
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_EOR;
+
+ } else if (Connection->SubState == CONNECTION_SUBSTATE_A_W_EOR) {
+
+ //
+ // We have got another partial send to add to our
+ // list. We chain it on the back of the send queue,
+ // in addition if this is the second request in the
+ // message, we have to link the first request (which
+ // is not on the queue) to this one.
+ //
+
+ Connection->LastMessageRequest = Request;
+ Connection->CurrentMessageLength += Parameters->SendLength;
+
+ if (Connection->SendQueue.Head == NULL) {
+ REQUEST_SINGLE_LINKAGE(Connection->FirstMessageRequest) = Request;
+ }
+ REQUEST_SINGLE_LINKAGE(Request) = NULL;
+ REQUEST_LIST_INSERT_TAIL(&Connection->SendQueue, Request);
+#ifdef RSRC_TIMEOUT_DBG
+ {
+ LARGE_INTEGER Time;
+ KeQuerySystemTime(&Time);
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Time.QuadPart;
+ }
+#endif //RSRC_TIMEOUT_DBG
+ } else {
+
+ REQUEST_SINGLE_LINKAGE(Request) = NULL;
+ REQUEST_LIST_INSERT_TAIL(&Connection->SendQueue, Request);
+
+#ifdef RSRC_TIMEOUT_DBG
+ {
+ LARGE_INTEGER Time;
+ KeQuerySystemTime(&Time);
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Time.QuadPart;
+ }
+#endif //RSRC_TIMEOUT_DBG
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ NB_END_SYNC (&SyncContext);
+ return STATUS_PENDING;
+
+ } else {
+
+ NB_DEBUG2 (SEND, ("Send %lx, too long for connection %lx (%d)\n", Request, Connection, Parameters->SendLength));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_END_SYNC (&SyncContext);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ return STATUS_INVALID_PARAMETER;
+
+ }
+
+ } else {
+
+ NB_DEBUG2 (SEND, ("Send %lx, connection %lx cancelled\n", Request, Connection));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_END_SYNC (&SyncContext);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ return STATUS_CANCELLED;
+
+ }
+
+ } else {
+
+ NB_DEBUG (SEND, ("Send connection %lx state is %d\n", Connection, Connection->State));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_END_SYNC (&SyncContext);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ return STATUS_INVALID_CONNECTION;
+
+ }
+
+ } else {
+
+ NB_DEBUG (SEND, ("Send connection %lx has bad signature\n", Connection));
+ return STATUS_INVALID_CONNECTION;
+
+ }
+
+} /* NbiTdiSend */
+
+
+VOID
+NbiPacketizeSend(
+ IN PCONNECTION Connection
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does a send on an active connection.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection.
+
+ LockHandle - The handle used to acquire the lock.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST Request;
+ PNDIS_PACKET Packet;
+ PNDIS_BUFFER BufferChain;
+ PNB_SEND_RESERVED Reserved;
+ PDEVICE Device = NbiDevice;
+ NB_CONNECTION UNALIGNED * Header;
+ ULONG PacketLength;
+ ULONG PacketSize;
+ ULONG DesiredLength;
+ ULONG ActualLength;
+ NTSTATUS Status;
+ PSINGLE_LIST_ENTRY s;
+ USHORT ThisSendSequence;
+ USHORT ThisOffset;
+ BOOLEAN ExitAfterSend;
+ UCHAR ConnectionControlFlag;
+ CTELockHandle DeviceLockHandle;
+
+ //
+ // We jump back here if we are talking new Netbios and it
+ // is OK to packetize another send.
+ //
+
+SendAnotherPacket:
+
+ //
+ // If we decide to packetize another send after this, we
+ // change ExitAfterSend to FALSE and SubState to PACKETIZE.
+ // Right now we don't change SubState in case it is W_PACKET.
+ //
+
+ ExitAfterSend = TRUE;
+
+ CTEAssert (Connection->CurrentSend.Request != NULL);
+
+ if (Connection->NewNetbios) {
+
+ //
+ // Check that we have send window, both that advertised
+ // by the remote and our own locally-decided window which
+ // may be smaller.
+ //
+
+ if (((USHORT)(Connection->CurrentSend.SendSequence-1) == Connection->RemoteRcvSequenceMax) ||
+ (((USHORT)(Connection->CurrentSend.SendSequence - Connection->UnAckedSend.SendSequence)) >= Connection->SendWindowSize)) {
+
+ //
+ // Keep track of whether we are waiting because of his window
+ // or because of our local window. If it is because of our local
+ // window then we may want to adjust it after this window
+ // is acked.
+ //
+
+ if ((USHORT)(Connection->CurrentSend.SendSequence-1) != Connection->RemoteRcvSequenceMax) {
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_ACK;
+ NB_DEBUG2 (SEND, ("Connection %lx local shut down at %lx, %lx\n", Connection, Connection->CurrentSend.SendSequence, Connection->UnAckedSend.SendSequence));
+ } else {
+ Connection->SubState = CONNECTION_SUBSTATE_A_REMOTE_W;
+ NB_DEBUG2 (SEND, ("Connection %lx remote shut down at %lx\n", Connection, Connection->CurrentSend.SendSequence));
+ }
+
+ //
+ // Start the timer so we will keep bugging him about
+ // this. BUGBUG: What if he doesn't get a receive down
+ // quickly -- but this is better than losing his ack
+ // and then dying. We won't really back off our timer
+ // because we will keep getting acks, and resetting it.
+ //
+
+ NbiStartRetransmit (Connection);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+
+ }
+
+ }
+
+ Request = Connection->CurrentSend.Request;
+
+ //
+ // If we are in this routine then we know that
+ // we are coming out of IDLE, W_ACK, or W_PACKET
+ // and we still have the lock held. We also know
+ // that there is a send request in progress. If
+ // an ack for none or part of the last packet was
+ // received, then our send pointers have been
+ // adjusted to reflect that.
+ //
+
+ //
+ // First get a packet for the current send.
+ //
+
+ if (!Connection->SendPacketInUse) {
+
+ Connection->SendPacketInUse = TRUE;
+ Packet = PACKET(&Connection->SendPacket);
+ Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
+
+ } else {
+
+ s = ExInterlockedPopEntrySList(
+ &Device->SendPacketList,
+ &NbiGlobalPoolInterlock);
+
+ if (s == NULL) {
+
+ //
+ // This function tries to allocate another packet pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ if (s == NULL) {
+
+ //
+ // It is possible to come in here and already be in
+ // W_PACKET state -- this is because we may packetize
+ // when in that state, and rather than always be
+ // checking that we weren't in W_PACKET, we go
+ // ahead and check again here.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_W_PACKET) {
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_PACKET;
+
+ NB_GET_LOCK (&Device->Lock, &DeviceLockHandle);
+ if (!Connection->OnWaitPacketQueue) {
+
+ NbiReferenceConnectionLock (Connection, CREF_W_PACKET);
+
+ Connection->OnWaitPacketQueue = TRUE;
+
+ InsertTailList(
+ &Device->WaitPacketConnections,
+ &Connection->WaitPacketLinkage
+ );
+
+// NB_INSERT_TAIL_LIST(
+// &Device->WaitPacketConnections,
+// &Connection->WaitPacketLinkage,
+// &Device->Lock);
+
+ }
+ NB_FREE_LOCK (&Device->Lock, DeviceLockHandle);
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+ }
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ }
+
+ //
+ // Set this now, we will change it later if needed.
+ //
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_ACK;
+
+
+ //
+ // Save these since they go in this next packet.
+ //
+
+ ThisSendSequence = Connection->CurrentSend.SendSequence;
+ ThisOffset = (USHORT)Connection->CurrentSend.MessageOffset;
+
+
+ //
+ // Now see if we need to copy the buffer chain.
+ //
+
+ PacketSize = Connection->MaximumPacketSize;
+
+ if (Connection->CurrentSend.MessageOffset + PacketSize >= Connection->CurrentMessageLength) {
+
+ PacketSize = Connection->CurrentMessageLength - Connection->CurrentSend.MessageOffset;
+
+ if ((Connection->CurrentSend.MessageOffset == 0) &&
+ (!Connection->SendBufferInUse)) {
+
+ //
+ // If the entire send remaining fits in one packet,
+ // and this is also the first packet in the send,
+ // then the entire send fits in one packet and
+ // we don't need to build a duplicate buffer chain.
+ //
+
+ BufferChain = Connection->CurrentSend.Buffer;
+ Reserved->u.SR_CO.NoNdisBuffer = TRUE;
+ Connection->CurrentSend.Buffer = NULL;
+ Connection->CurrentSend.BufferOffset = 0;
+ Connection->CurrentSend.MessageOffset = Connection->CurrentMessageLength;
+ Connection->CurrentSend.Request = NULL;
+ ++Connection->CurrentSend.SendSequence;
+ Connection->SendBufferInUse = TRUE;
+ if (Connection->NewNetbios) {
+ if ((ThisSendSequence == Connection->RemoteRcvSequenceMax) ||
+ ((((PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request))->SendFlags) &
+ TDI_SEND_NO_RESPONSE_EXPECTED)) { // BUGBUG: optimize this check
+ ConnectionControlFlag = NB_CONTROL_EOM | NB_CONTROL_SEND_ACK;
+ } else {
+ ConnectionControlFlag = NB_CONTROL_EOM;
+ }
+ Connection->PiggybackAckTimeout = FALSE;
+ } else {
+ ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+ }
+
+ if (BufferChain != NULL) {
+ NB_DEBUG2 (SEND, ("Send packet %lx on %lx (%d/%d), user buffer\n",
+ Reserved, Connection,
+ Connection->CurrentSend.SendSequence,
+ Connection->CurrentSend.MessageOffset));
+ NdisChainBufferAtBack (Packet, BufferChain);
+ } else {
+ NB_DEBUG2 (SEND, ("Send packet %lx on %lx (%d/%d), no buffer\n",
+ Reserved, Connection,
+ Connection->CurrentSend.SendSequence,
+ Connection->CurrentSend.MessageOffset));
+ }
+
+ goto GotBufferChain;
+
+ }
+
+ }
+
+ //
+ // We need to build a partial buffer chain. In the case
+ // where the current request is a partial one, we may
+ // build this from the ndis buffer chains of several
+ // requests.
+ //
+
+ if (PacketSize > 0) {
+
+ DesiredLength = PacketSize;
+
+ NB_DEBUG2 (SEND, ("Send packet %lx on %lx (%d/%d), allocate buffer\n",
+ Reserved, Connection,
+ Connection->CurrentSend.SendSequence,
+ Connection->CurrentSend.MessageOffset));
+
+ while (TRUE) {
+
+ Status = NbiBuildBufferChainFromBufferChain (
+ Device->NdisBufferPoolHandle,
+ Connection->CurrentSend.Buffer,
+ Connection->CurrentSend.BufferOffset,
+ DesiredLength,
+ &BufferChain,
+ &Connection->CurrentSend.Buffer,
+ &Connection->CurrentSend.BufferOffset,
+ &ActualLength);
+
+ if (Status != STATUS_SUCCESS) {
+
+ PNDIS_BUFFER CurBuffer, TmpBuffer;
+
+ NB_DEBUG2 (SEND, ("Allocate buffer chain failed for packet %lx\n", Reserved));
+
+ //
+ // We could not allocate resources for this send.
+ // We'll put the connection on the packetize
+ // queue and hope we get more resources later.
+ //
+
+ NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
+
+ CTEAssert (!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ //
+ // Connection->CurrentSend can stay where it is.
+ //
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ //
+ // Free any buffers we have allocated on previous calls
+ // to BuildBufferChain inside this same while(TRUE) loop,
+ // then free the packet.
+ //
+
+ CurBuffer = NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer));
+ while (CurBuffer) {
+ TmpBuffer = NDIS_BUFFER_LINKAGE (CurBuffer);
+ NdisFreeBuffer (CurBuffer);
+ CurBuffer = TmpBuffer;
+ }
+
+ NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = NULL;
+ NdisRecalculatePacketCounts (Packet);
+
+ if (Reserved->OwnedByConnection) {
+ Connection->SendPacketInUse = FALSE;
+ } else {
+ NbiPushSendPacket(Reserved);
+ }
+
+ return;
+
+ }
+
+ NdisChainBufferAtBack (Packet, BufferChain);
+ Connection->CurrentSend.MessageOffset += ActualLength;
+
+ DesiredLength -= ActualLength;
+
+ if (DesiredLength == 0) {
+
+ //
+ // We have gotten enough data for our packet.
+ //
+
+ if (Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength) {
+ Connection->CurrentSend.Request = NULL;
+ }
+ break;
+ }
+
+ //
+ // We ran out of buffer chain on this send, which means
+ // that we must have another one behind it (since we
+ // don't start packetizing partial sends until all of
+ // them are queued).
+ //
+
+ Request = REQUEST_SINGLE_LINKAGE(Request);
+ if (Request == NULL) {
+ KeBugCheck (NDIS_INTERNAL_ERROR);
+ }
+
+ Connection->CurrentSend.Request = Request;
+ Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentSend.BufferOffset = 0;
+
+ }
+
+ } else {
+
+ //
+ // This is a zero-length send (in general we will go
+ // through the code before the if that uses the user's
+ // buffer, but not on a resend).
+ //
+
+ Connection->CurrentSend.Buffer = NULL;
+ Connection->CurrentSend.BufferOffset = 0;
+ CTEAssert (Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength);
+ Connection->CurrentSend.Request = NULL;
+
+ NB_DEBUG2 (SEND, ("Send packet %lx on %lx (%d/%d), no alloc buf\n",
+ Reserved, Connection,
+ Connection->CurrentSend.SendSequence,
+ Connection->CurrentSend.MessageOffset));
+
+ }
+
+ Reserved->u.SR_CO.NoNdisBuffer = FALSE;
+
+ if (Connection->NewNetbios) {
+
+ ++Connection->CurrentSend.SendSequence;
+ if (Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength) {
+
+ if (((USHORT)(Connection->CurrentSend.SendSequence - Connection->UnAckedSend.SendSequence)) >= Connection->SendWindowSize) {
+
+ ConnectionControlFlag = NB_CONTROL_EOM | NB_CONTROL_SEND_ACK;
+
+ } else if ((ThisSendSequence == Connection->RemoteRcvSequenceMax) ||
+ ((((PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request))->SendFlags) &
+ TDI_SEND_NO_RESPONSE_EXPECTED)) { // BUGBUG: optimize this check
+
+ ConnectionControlFlag = NB_CONTROL_EOM | NB_CONTROL_SEND_ACK;
+
+ } else {
+
+ ConnectionControlFlag = NB_CONTROL_EOM;
+ }
+ Connection->PiggybackAckTimeout = FALSE;
+
+ } else if (((USHORT)(Connection->CurrentSend.SendSequence - Connection->UnAckedSend.SendSequence)) >= Connection->SendWindowSize) {
+
+ ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+
+ } else if (ThisSendSequence == Connection->RemoteRcvSequenceMax) {
+
+ ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+
+ } else {
+
+ ConnectionControlFlag = 0;
+ ExitAfterSend = FALSE;
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ }
+
+ } else {
+
+ ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+ if (Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength) {
+ ++Connection->CurrentSend.SendSequence;
+ }
+ }
+
+GotBufferChain:
+
+ //
+ // We have a packet and a buffer chain, there are
+ // no other resources required for a send so we can
+ // fill in the header and go.
+ //
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_DATA;
+ Reserved->u.SR_CO.Connection = Connection;
+ Reserved->u.SR_CO.Request = Connection->FirstMessageRequest;
+
+ PacketLength = PacketSize + sizeof(NB_CONNECTION);
+ Reserved->u.SR_CO.PacketLength = PacketLength;
+
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = (UCHAR)(PacketLength / 256);
+ Header->IpxHeader.PacketLength[1] = (UCHAR)(PacketLength % 256);
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header. BUGBUG: Put this in
+ // a contiguous buffer in the connection.
+ //
+
+ Header->Session.ConnectionControlFlag = ConnectionControlFlag;
+ Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = Connection->RemoteConnectionId;
+ Header->Session.SendSequence = ThisSendSequence;
+ Header->Session.TotalDataLength = (USHORT)Connection->CurrentMessageLength;
+ Header->Session.Offset = ThisOffset;
+ Header->Session.DataLength = (USHORT)PacketSize;
+
+#if 0
+ //
+ // These are set by NbiAssignSequenceAndSend.
+ //
+
+ Header->Session.ReceiveSequence = Connection->ReceiveSequence;
+ Header->Session.BytesReceived = (USHORT)Connection->CurrentReceive.MessageOffset;
+#endif
+
+ //
+ // Reference the request to account for this send.
+ //
+
+#if DBG
+ if (REQUEST_REFCOUNT(Request) > 100) {
+ DbgPrint ("Request %lx (%lx) has high refcount\n",
+ Connection, Request);
+ DbgBreakPoint();
+ }
+#endif
+ ++REQUEST_REFCOUNT (Request);
+
+ ++Device->TempFramesSent;
+ Device->TempFrameBytesSent += PacketSize;
+
+ //
+ // Start the timer.
+ //
+
+ NbiStartRetransmit (Connection);
+
+ //
+ // This frees the lock. IPX will adjust the length of
+ // the first buffer correctly.
+ //
+
+ NbiAssignSequenceAndSend(
+ Connection,
+ Packet
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ if (!ExitAfterSend) {
+
+ //
+ // BUGBUG: Did we need to reference the connection until we
+ // get the lock back??
+ //
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+ if ((Connection->State == CONNECTION_STATE_ACTIVE) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_A_PACKETIZE)) {
+
+ //
+ // Jump back to the beginning of the function to
+ // repacketize.
+
+ goto SendAnotherPacket;
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ }
+
+} /* NbiPacketizeSend */
+
+
+VOID
+NbiAdjustSendWindow(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adjusts a connection's send window if needed. It is
+ assumed that we just got an ack for a full send window.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Connection - The connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ if (Connection->RetransmitThisWindow) {
+
+ //
+ // Move it down. Check if this keeps happening.
+ //
+
+ if (Connection->SendWindowSize > 2) {
+ --Connection->SendWindowSize;
+ NB_DEBUG2 (SEND_WINDOW, ("Lower window to %d on %lx (%lx)\n", Connection->SendWindowSize, Connection, Connection->CurrentSend.SendSequence));
+ }
+
+ if (Connection->SendWindowIncrease) {
+
+ //
+ // We just increased the window.
+ //
+
+ ++Connection->IncreaseWindowFailures;
+ NB_DEBUG2 (SEND_WINDOW, ("%d consecutive increase failues on %lx (%lx)\n", Connection->IncreaseWindowFailures, Connection, Connection->CurrentSend.SendSequence));
+
+ if (Connection->IncreaseWindowFailures >= 2) {
+
+ if (Connection->MaxSendWindowSize > 2) {
+
+ //
+ // Lock ourselves at a smaller window.
+ //
+
+ Connection->MaxSendWindowSize = Connection->SendWindowSize;
+ NB_DEBUG2 (SEND_WINDOW, ("Lock send window at %d on %lx (%lx)\n", Connection->MaxSendWindowSize, Connection, Connection->CurrentSend.SendSequence));
+ }
+
+ Connection->IncreaseWindowFailures = 0;
+ }
+
+ Connection->SendWindowIncrease = FALSE;
+ }
+
+ } else {
+
+ //
+ // Increase it if allowed, and make a note
+ // in case this increase causes problems in
+ // the next window.
+ //
+
+ if (Connection->SendWindowSize < Connection->MaxSendWindowSize) {
+
+ ++Connection->SendWindowSize;
+ NB_DEBUG2 (SEND_WINDOW, ("Raise window to %d on %lx (%lx)\n", Connection->SendWindowSize, Connection, Connection->CurrentSend.SendSequence));
+ Connection->SendWindowIncrease = TRUE;
+
+ } else {
+
+ if (Connection->SendWindowIncrease) {
+
+ //
+ // We just increased it and nothing failed,
+ // which is good.
+ //
+
+ Connection->SendWindowIncrease = FALSE;
+ Connection->IncreaseWindowFailures = 0;
+ NB_DEBUG2 (SEND_WINDOW, ("Raised window OK on %lx (%lx)\n", Connection, Connection->CurrentSend.SendSequence));
+ }
+ }
+ }
+
+
+ //
+ // This controls when we'll check this again.
+ //
+
+ Connection->SendWindowSequenceLimit += Connection->SendWindowSize;
+
+} /* NbiAdjustSendWindow */
+
+
+VOID
+NbiReframeConnection(
+ IN PCONNECTION Connection,
+ IN USHORT ReceiveSequence,
+ IN USHORT BytesReceived,
+ IN BOOLEAN Resend
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when we have gotten an ack
+ for some data. It completes any sends that have
+ been acked, and if needed modifies the current send
+ pointer and queues the connection for repacketizing.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection.
+
+ ReceiveSequence - The receive sequence from the remote.
+
+ BytesReceived - The number of bytes received in this message.
+
+ Resend - If it is OK to resend based on this packet.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST Request, TmpRequest;
+ PREQUEST RequestToComplete;
+ PDEVICE Device = NbiDevice;
+ CTELockHandle CancelLH;
+
+
+ //
+ // BUGBUG: We should change to stop the timer
+ // only if we go idle, since otherwise we still
+ // want it running, or will restart it when we
+ // packetize.
+ //
+
+ //
+ // See how much is acked here.
+ //
+
+ if ((Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength) &&
+ (ReceiveSequence == (USHORT)(Connection->CurrentSend.SendSequence)) &&
+ (Connection->FirstMessageRequest != NULL)) {
+
+ // Special check for 0 length send which was not accepted by the remote.
+ // In this case it will pass the above 3 conditions yet, nothing
+ // is acked. BUG#10395
+ if (!Connection->CurrentSend.MessageOffset && Connection->CurrentSend.SendSequence == Connection->UnAckedSend.SendSequence ) {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+ }
+
+ //
+ // This acks the entire message.
+ //
+
+ NB_DEBUG2 (SEND, ("Got ack for entire message on %lx (%d)\n", Connection, Connection->CurrentSend.SendSequence));
+
+ NbiStopRetransmit (Connection);
+
+ Connection->CurrentSend.MessageOffset = 0; // BUGBUG: Needed?
+ Connection->UnAckedSend.MessageOffset = 0;
+
+ //
+ // We don't adjust the send window since we likely stopped
+ // packetizing before we hit it.
+ //
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+
+
+ if (Connection->NewNetbios) {
+
+ Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
+
+ //
+ // See if we need to adjust our send window.
+ //
+
+ if (((SHORT)(Connection->CurrentSend.SendSequence - Connection->SendWindowSequenceLimit)) >= 0) {
+
+ NbiAdjustSendWindow (Connection);
+
+ } else {
+
+ //
+ // Advance this, we won't get meaningful results until we
+ // send a full window in one message.
+ //
+
+ Connection->SendWindowSequenceLimit = Connection->CurrentSend.SendSequence + Connection->SendWindowSize;
+ }
+
+
+ }
+
+ Connection->RetransmitThisWindow = FALSE;
+
+ Request = Connection->FirstMessageRequest;
+
+ //
+ // We dequeue these requests from the connection's
+ // send queue.
+ //
+
+ if (Connection->FirstMessageRequest == Connection->LastMessageRequest) {
+
+ REQUEST_SINGLE_LINKAGE (Request) = NULL;
+
+ } else {
+
+ Connection->SendQueue.Head = REQUEST_SINGLE_LINKAGE (Connection->LastMessageRequest);
+ REQUEST_SINGLE_LINKAGE (Connection->LastMessageRequest) = NULL;
+
+ }
+
+#if DBG
+ if (REQUEST_REFCOUNT(Request) > 100) {
+ DbgPrint ("Request %lx (%lx) has high refcount\n",
+ Connection, Request);
+ DbgBreakPoint();
+ }
+#endif
+ if (--REQUEST_REFCOUNT(Request) == 0) {
+
+ RequestToComplete = Request;
+
+ } else {
+
+ //
+ // There are still sends pending, this will get
+ // completed when the last send completes. Since
+ // we have already unlinked the request from the
+ // connection's send queue we can do this without
+ // any locks.
+ //
+
+ RequestToComplete = NULL;
+
+ }
+
+ //
+ // Now see if there is a send to activate.
+ //
+
+ NbiRestartConnection (Connection);
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ //
+ // Now complete any requests we need to.
+ //
+
+ while (RequestToComplete != NULL) {
+
+ TmpRequest = REQUEST_SINGLE_LINKAGE (RequestToComplete);
+ REQUEST_STATUS (RequestToComplete) = STATUS_SUCCESS;
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (RequestToComplete, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ NbiCompleteRequest (RequestToComplete);
+ NbiFreeRequest (Device, RequestToComplete);
+ ++Connection->ConnectionInfo.TransmittedTsdus;
+ RequestToComplete = TmpRequest;
+
+ NbiDereferenceConnection (Connection, CREF_SEND);
+
+ }
+
+ } else if ((ReceiveSequence == Connection->CurrentSend.SendSequence) &&
+ (Connection->NewNetbios || (BytesReceived == Connection->CurrentSend.MessageOffset)) &&
+ (Connection->CurrentSend.Request != NULL)) {
+
+ //
+ // This acks whatever we sent last time, and we are
+ // not done packetizing this send, so we can repacketize.
+ // BUGBUG: With SendSequence changing as it does now,
+ // don't need the CurrentSend.Request check???
+ //
+
+ NB_DEBUG2 (SEND, ("Got full ack on %lx (%d)\n", Connection, Connection->CurrentSend.SendSequence));
+
+ NbiStopRetransmit (Connection);
+
+ if (Connection->NewNetbios) {
+
+ //
+ // If we are waiting for a window, and this does not open it
+ // anymore, then we don't reset our timers/retries.
+ //
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_REMOTE_W) {
+
+ if (Connection->RemoteRcvSequenceMax != BytesReceived) {
+ Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+
+ }
+
+ //
+ // Advance this, we won't get meaningful results until we
+ // send a full window in one message.
+ //
+
+ Connection->SendWindowSequenceLimit = Connection->CurrentSend.SendSequence + Connection->SendWindowSize;
+
+ } else {
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+ Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
+
+ if (((SHORT)(Connection->CurrentSend.SendSequence - Connection->SendWindowSequenceLimit)) >= 0) {
+
+ NbiAdjustSendWindow (Connection);
+
+ } else {
+
+ //
+ // Advance this, we won't get meaningful results until we
+ // send a full window in one message.
+ //
+
+ Connection->SendWindowSequenceLimit = Connection->CurrentSend.SendSequence + Connection->SendWindowSize;
+ }
+
+ }
+
+ } else {
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+ }
+
+ Connection->RetransmitThisWindow = FALSE;
+
+ Connection->UnAckedSend = Connection->CurrentSend;
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_PACKETIZE) {
+
+ //
+ // We may be on if this ack is duplicated.
+ //
+
+ NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
+
+ CTEAssert(!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ } else if( Connection->FirstMessageRequest ) {
+
+ //
+ // This acked part of the current send. If the
+ // remote is requesting a resend then we advance
+ // the current send location by the amount
+ // acked and resend from there. If he does
+ // not want a resend, just ignore this.
+ //
+ // We repacketize immediately because we have
+ // backed up the pointer, and this would
+ // cause us to ignore an ack for the amount
+ // sent. Since we don't release the lock
+ // until we have packetized, the current
+ // pointer will be advanced past there.
+ //
+ // BUGBUG: If he is acking more than we sent, we
+ // ignore this -- the remote is confused and there
+ // is nothing much we can do.
+ //
+
+ if (Resend) {
+
+ if (Connection->NewNetbios &&
+ (((Connection->UnAckedSend.SendSequence < Connection->CurrentSend.SendSequence) &&
+ (ReceiveSequence >= Connection->UnAckedSend.SendSequence) &&
+ (ReceiveSequence < Connection->CurrentSend.SendSequence)) ||
+ ((Connection->UnAckedSend.SendSequence > Connection->CurrentSend.SendSequence) &&
+ ((ReceiveSequence >= Connection->UnAckedSend.SendSequence) ||
+ (ReceiveSequence < Connection->CurrentSend.SendSequence))))) {
+
+ BOOLEAN SomethingAcked = (BOOLEAN)
+ (ReceiveSequence != Connection->UnAckedSend.SendSequence);
+
+ //
+ // New netbios and the receive sequence is valid.
+ //
+
+ NbiStopRetransmit (Connection);
+
+ //
+ // Advance our unacked pointer by the amount
+ // acked in this response.
+ //
+
+ NbiAdvanceUnAckedBySequence(
+ Connection,
+ ReceiveSequence);
+
+ Connection->RetransmitThisWindow = TRUE;
+
+ ++Connection->ConnectionInfo.TransmissionErrors;
+ ++Device->Statistics.DataFramesResent;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesResent,
+ Connection->CurrentSend.MessageOffset - Connection->UnAckedSend.MessageOffset);
+
+ //
+ // Packetize from that point on.
+ //
+
+ Connection->CurrentSend = Connection->UnAckedSend;
+
+ //
+ // If anything was acked, then reset the retry count.
+ //
+
+ if (SomethingAcked) {
+
+ //
+ // See if we need to adjust our send window.
+ //
+
+ if (((SHORT)(Connection->UnAckedSend.SendSequence - Connection->SendWindowSequenceLimit)) >= 0) {
+
+ NbiAdjustSendWindow (Connection);
+
+ }
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+
+ }
+
+ Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
+
+ //
+ // Now packetize. This will set the state to
+ // something meaningful and release the lock.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_PACKETIZE) {
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle)
+ );
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else if (!Connection->NewNetbios &&
+ ((ReceiveSequence == Connection->UnAckedSend.SendSequence) &&
+ (BytesReceived <= Connection->CurrentSend.MessageOffset))) {
+
+ ULONG BytesAcked =
+ BytesReceived - Connection->UnAckedSend.MessageOffset;
+
+ //
+ // Old netbios.
+ //
+
+ NbiStopRetransmit (Connection);
+
+ //
+ // Advance our unacked pointer by the amount
+ // acked in this response.
+ //
+
+ NbiAdvanceUnAckedByBytes(
+ Connection,
+ BytesAcked);
+
+ ++Connection->ConnectionInfo.TransmissionErrors;
+ ++Device->Statistics.DataFramesResent;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesResent,
+ Connection->CurrentSend.MessageOffset - Connection->UnAckedSend.MessageOffset);
+
+ //
+ // Packetize from that point on.
+ //
+
+ Connection->CurrentSend = Connection->UnAckedSend;
+
+ //
+ // If anything was acked, reset the retry count
+ //
+ if ( BytesAcked ) {
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+ }
+
+ //
+ // Now packetize. This will set the state to
+ // something meaningful and release the lock.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_PACKETIZE) {
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle)
+ );
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ if (Connection->NewNetbios &&
+ (((Connection->UnAckedSend.SendSequence < Connection->CurrentSend.SendSequence) &&
+ (ReceiveSequence >= Connection->UnAckedSend.SendSequence) &&
+ (ReceiveSequence < Connection->CurrentSend.SendSequence)) ||
+ ((Connection->UnAckedSend.SendSequence > Connection->CurrentSend.SendSequence) &&
+ ((ReceiveSequence >= Connection->UnAckedSend.SendSequence) ||
+ (ReceiveSequence < Connection->CurrentSend.SendSequence))))) {
+
+ BOOLEAN SomethingAcked = (BOOLEAN)
+ (ReceiveSequence != Connection->UnAckedSend.SendSequence);
+
+ //
+ // New netbios and the receive sequence is valid. We advance
+ // the back of our send window, but we don't repacketize.
+ //
+
+ //
+ // Advance our unacked pointer by the amount
+ // acked in this response.
+ //
+
+ NbiAdvanceUnAckedBySequence(
+ Connection,
+ ReceiveSequence);
+
+ Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
+
+ //
+ // If anything was acked, then reset the retry count.
+ //
+
+ if (SomethingAcked) {
+
+ //
+ // See if we need to adjust our send window.
+ //
+
+ if (((SHORT)(Connection->UnAckedSend.SendSequence - Connection->SendWindowSequenceLimit)) >= 0) {
+
+ NbiAdjustSendWindow (Connection);
+
+ }
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+
+
+ //
+ // Now packetize. This will set the state to
+ // something meaningful and release the lock.
+ //
+
+ if ((Connection->CurrentSend.Request != NULL) &&
+ (Connection->SubState != CONNECTION_SUBSTATE_A_PACKETIZE)) {
+
+ NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
+
+ CTEAssert(!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ }
+ }
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+} /* NbiReframeConnection */
+
+
+VOID
+NbiRestartConnection(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when have gotten an ack for
+ a full message, or received a response to a watchdog
+ probe, and need to check if the connection should
+ start packetizing.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Connection - The connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST Request, TmpRequest;
+ ULONG TempCount;
+ PTDI_REQUEST_KERNEL_SEND Parameters;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // See if there is a send to activate.
+ //
+
+ if (Connection->SendQueue.Head != NULL) {
+
+ //
+ // Take the first send off the queue and make
+ // it current.
+ //
+
+ Request = Connection->SendQueue.Head;
+ Connection->SendQueue.Head = REQUEST_SINGLE_LINKAGE (Request);
+
+ //
+ // BUGBUG: Cache the information about being EOM
+ // in a more easily accessible location?
+ //
+
+ Parameters = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request);
+ if ((Parameters->SendFlags & TDI_SEND_PARTIAL) == 0) {
+
+ //
+ // This is a one-request message.
+ //
+
+ Connection->CurrentSend.Request = Request;
+ Connection->CurrentSend.MessageOffset = 0;
+ Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentSend.BufferOffset = 0;
+ Connection->SendBufferInUse = FALSE;
+
+ Connection->UnAckedSend = Connection->CurrentSend;
+
+ Connection->FirstMessageRequest = Request;
+#ifdef RSRC_TIMEOUT_DBG
+ KeQuerySystemTime(&Connection->FirstMessageRequestTime);
+#endif //RSRC_TIMEOUT_DBG
+
+ Connection->LastMessageRequest = Request;
+ Connection->CurrentMessageLength = Parameters->SendLength;
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
+
+ CTEAssert (!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ } else {
+
+ //
+ // This is a multiple-request message. We scan
+ // to see if we have the end of message received
+ // yet.
+ //
+
+ TempCount = Parameters->SendLength;
+ TmpRequest = Request;
+ Request = REQUEST_SINGLE_LINKAGE(Request);
+
+ while (Request != NULL) {
+
+ TempCount += Parameters->SendLength;
+
+ Parameters = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request);
+ if ((Parameters->SendFlags & TDI_SEND_PARTIAL) == 0) {
+
+ Connection->CurrentSend.Request = TmpRequest;
+ Connection->CurrentSend.MessageOffset = 0;
+ Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (TmpRequest);
+ Connection->CurrentSend.BufferOffset = 0;
+ Connection->SendBufferInUse = FALSE;
+
+ Connection->UnAckedSend = Connection->CurrentSend;
+
+ Connection->FirstMessageRequest = TmpRequest;
+ Connection->LastMessageRequest = Request;
+#ifdef RSRC_TIMEOUT_DBG
+ KeQuerySystemTime(&Connection->FirstMessageRequestTime);
+#endif //RSRC_TIMEOUT_DBG
+
+ Connection->CurrentMessageLength = TempCount;
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
+
+ CTEAssert (!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ break;
+
+ }
+
+ Request = REQUEST_SINGLE_LINKAGE(Request);
+
+ }
+
+ if (Request == NULL) {
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_EOR;
+
+ }
+
+ }
+
+ } else {
+
+ Connection->FirstMessageRequest = NULL;
+ Connection->SubState = CONNECTION_SUBSTATE_A_IDLE;
+
+ NbiStartWatchdog (Connection);
+
+ }
+
+} /* NbiRestartConnection */
+
+
+VOID
+NbiAdvanceUnAckedByBytes(
+ IN PCONNECTION Connection,
+ IN ULONG BytesAcked
+ )
+
+/*++
+
+Routine Description:
+
+ This routine advances the Connection->UnAckedSend
+ send pointer by the specified number of bytes. It
+ assumes that there are enough send requests to
+ handle the number specified.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Connection - The connection.
+
+ BytesAcked - The number of bytes acked.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ ULONG CurSendBufferLength;
+ ULONG BytesLeft = BytesAcked;
+ ULONG TempBytes;
+
+ while (BytesLeft > 0) {
+
+ NdisQueryBuffer (Connection->UnAckedSend.Buffer, NULL, &CurSendBufferLength);
+
+ //
+ // See if bytes acked ends within the current buffer.
+ //
+
+ if (Connection->UnAckedSend.BufferOffset + BytesLeft <
+ CurSendBufferLength) {
+
+ Connection->UnAckedSend.BufferOffset += BytesLeft;
+ Connection->UnAckedSend.MessageOffset += BytesLeft;
+ break;
+
+ } else {
+
+ TempBytes = CurSendBufferLength - Connection->UnAckedSend.BufferOffset;
+ BytesLeft -= TempBytes;
+ Connection->UnAckedSend.MessageOffset += TempBytes;
+
+ //
+ // No, so advance the buffer.
+ //
+
+ Connection->UnAckedSend.BufferOffset = 0;
+ Connection->UnAckedSend.Buffer =
+ NDIS_BUFFER_LINKAGE (Connection->UnAckedSend.Buffer);
+
+ //
+ // Is there a next buffer in this request?
+ //
+
+ if (Connection->UnAckedSend.Buffer == NULL) {
+
+ //
+ // No, so advance the request unless we are done.
+ //
+
+ if (BytesLeft == 0) {
+ return;
+ }
+
+ Connection->UnAckedSend.Request =
+ REQUEST_SINGLE_LINKAGE(Connection->UnAckedSend.Request);
+
+ if (Connection->UnAckedSend.Request == NULL) {
+ KeBugCheck (NDIS_INTERNAL_ERROR);
+ }
+
+ Connection->UnAckedSend.Buffer =
+ REQUEST_NDIS_BUFFER (Connection->UnAckedSend.Request);
+
+ }
+ }
+ }
+
+} /* NbiAdvanceUnAckedByBytes */
+
+
+VOID
+NbiAdvanceUnAckedBySequence(
+ IN PCONNECTION Connection,
+ IN USHORT ReceiveSequence
+ )
+
+/*++
+
+Routine Description:
+
+ This routine advances the Connection->UnAckedSend
+ send pointer so that the next packet to send will be
+ the correct one for ReceiveSequence. UnAckedSend
+ must point to a known valid combination. It
+ assumes that there are enough send requests to
+ handle the sequence specified.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Connection - The connection.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ USHORT PacketsAcked;
+
+ //
+ // BUGBUG: Fix this to account for partial sends, where
+ // we might not have used the max. for all packets.
+ //
+
+ PacketsAcked = ReceiveSequence - Connection->UnAckedSend.SendSequence;
+
+ NbiAdvanceUnAckedByBytes(
+ Connection,
+ PacketsAcked * Connection->MaximumPacketSize);
+
+ Connection->UnAckedSend.SendSequence += PacketsAcked;
+
+} /* NbiAdvanceUnAckedBySequence */
+
+
+VOID
+NbiCancelSend(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a send
+ The request is found on the connection's send queue.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PREQUEST Request = (PREQUEST)Irp;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_SEND));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ //
+ // Just stop the connection, that will tear down any
+ // sends.
+ //
+ // BUGBUG: Do we care about cancelling non-active
+ // sends without stopping the connection??
+ //
+
+ NbiReferenceConnectionSync (Connection, CREF_CANCEL);
+
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+
+ NB_BEGIN_SYNC (&SyncContext);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ //
+ // This frees the lock, cancels any sends, etc.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_CANCELLED
+ NB_LOCK_HANDLE_ARG (LockHandle));
+
+ NbiDereferenceConnection (Connection, CREF_CANCEL);
+
+ NB_END_SYNC (&SyncContext);
+
+} /* NbiCancelSend */
+
+
+NTSTATUS
+NbiBuildBufferChainFromBufferChain (
+ IN NDIS_HANDLE BufferPoolHandle,
+ IN PNDIS_BUFFER CurrentSourceBuffer,
+ IN ULONG CurrentByteOffset,
+ IN ULONG DesiredLength,
+ OUT PNDIS_BUFFER *DestinationBuffer,
+ OUT PNDIS_BUFFER *NewSourceBuffer,
+ OUT ULONG *NewByteOffset,
+ OUT ULONG *ActualLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to build an NDIS_BUFFER chain from a source
+ NDIS_BUFFER chain and offset into it. We assume we don't know the
+ length of the source Mdl chain, and we must allocate the NDIS_BUFFERs
+ for the destination chain, which we do from the NDIS buffer pool.
+
+ If the system runs out of memory while we are building the destination
+ NDIS_BUFFER chain, we completely clean up the built chain and return with
+ NewCurrentMdl and NewByteOffset set to the current values of CurrentMdl
+ and ByteOffset.
+
+Environment:
+
+Arguments:
+
+ BufferPoolHandle - The buffer pool to allocate buffers from.
+
+ CurrentSourceBuffer - Points to the start of the NDIS_BUFFER chain
+ from which to draw the packet.
+
+ CurrentByteOffset - Offset within this NDIS_BUFFER to start the packet at.
+
+ DesiredLength - The number of bytes to insert into the packet.
+
+ DestinationBuffer - returned pointer to the NDIS_BUFFER chain describing
+ the packet.
+
+ NewSourceBuffer - returned pointer to the NDIS_BUFFER that would
+ be used for the next byte of packet. NULL if the source NDIS_BUFFER
+ chain was exhausted.
+
+ NewByteOffset - returned offset into the NewSourceBuffer for the next byte
+ of packet. NULL if the source NDIS_BUFFER chain was exhausted.
+
+ ActualLength - The actual length of the data copied.
+
+Return Value:
+
+ STATUS_SUCCESS if the build of the returned NDIS_BUFFER chain succeeded
+ and was the correct length.
+
+ STATUS_INSUFFICIENT_RESOURCES if we ran out of NDIS_BUFFERs while
+ building the destination chain.
+
+--*/
+{
+ ULONG AvailableBytes;
+ ULONG CurrentByteCount;
+ ULONG BytesCopied;
+ PNDIS_BUFFER OldNdisBuffer;
+ PNDIS_BUFFER NewNdisBuffer;
+ NDIS_STATUS NdisStatus;
+
+
+ OldNdisBuffer = CurrentSourceBuffer;
+ NdisQueryBuffer (OldNdisBuffer, NULL, &CurrentByteCount);
+
+ AvailableBytes = CurrentByteCount - CurrentByteOffset;
+ if (AvailableBytes > DesiredLength) {
+ AvailableBytes = DesiredLength;
+ }
+
+ //
+ // Build the first NDIS_BUFFER, which could conceivably be the only one...
+ //
+
+ NdisCopyBuffer(
+ &NdisStatus,
+ &NewNdisBuffer,
+ BufferPoolHandle,
+ OldNdisBuffer,
+ CurrentByteOffset,
+ AvailableBytes);
+
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ *NewSourceBuffer = CurrentSourceBuffer;
+ *NewByteOffset = CurrentByteOffset;
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ *DestinationBuffer = NewNdisBuffer;
+ BytesCopied = AvailableBytes;
+
+ //
+ // Was the first NDIS_BUFFER enough data.
+ //
+
+ if (BytesCopied == DesiredLength) {
+ if (CurrentByteOffset + AvailableBytes == CurrentByteCount) {
+ *NewSourceBuffer = CurrentSourceBuffer->Next;
+ *NewByteOffset = 0;
+ } else {
+ *NewSourceBuffer = CurrentSourceBuffer;
+ *NewByteOffset = CurrentByteOffset + AvailableBytes;
+ }
+ *ActualLength = BytesCopied;
+ return STATUS_SUCCESS;
+ }
+
+ if (CurrentSourceBuffer->Next == NULL) {
+
+ *NewSourceBuffer = NULL;
+ *NewByteOffset = 0;
+ *ActualLength = BytesCopied;
+ return STATUS_SUCCESS;
+
+ }
+
+ //
+ // Need more data, so follow the in Mdl chain to create a packet.
+ //
+
+ OldNdisBuffer = OldNdisBuffer->Next;
+ NdisQueryBuffer (OldNdisBuffer, NULL, &CurrentByteCount);
+
+ while (OldNdisBuffer != NULL) {
+
+ AvailableBytes = DesiredLength - BytesCopied;
+ if (AvailableBytes > CurrentByteCount) {
+ AvailableBytes = CurrentByteCount;
+ }
+
+ NdisCopyBuffer(
+ &NdisStatus,
+ &(NDIS_BUFFER_LINKAGE(NewNdisBuffer)),
+ BufferPoolHandle,
+ OldNdisBuffer,
+ 0,
+ AvailableBytes);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // ran out of resources. put back what we've used in this call and
+ // return the error.
+ //
+
+ while (*DestinationBuffer != NULL) {
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE(*DestinationBuffer);
+ NdisFreeBuffer (*DestinationBuffer);
+ *DestinationBuffer = NewNdisBuffer;
+ }
+
+ *NewByteOffset = CurrentByteOffset;
+ *NewSourceBuffer = CurrentSourceBuffer;
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE(NewNdisBuffer);
+
+ BytesCopied += AvailableBytes;
+
+ if (BytesCopied == DesiredLength) {
+ if (AvailableBytes == CurrentByteCount) {
+ *NewSourceBuffer = OldNdisBuffer->Next;
+ *NewByteOffset = 0;
+ } else {
+ *NewSourceBuffer = OldNdisBuffer;
+ *NewByteOffset = AvailableBytes;
+ }
+ *ActualLength = BytesCopied;
+ return STATUS_SUCCESS;
+ }
+
+ OldNdisBuffer = OldNdisBuffer->Next;
+ NdisQueryBuffer (OldNdisBuffer, NULL, &CurrentByteCount);
+
+ }
+
+ //
+ // We ran out of source buffer chain.
+ //
+
+ *NewSourceBuffer = NULL;
+ *NewByteOffset = 0;
+ *ActualLength = BytesCopied;
+ return STATUS_SUCCESS;
+
+} /* NbiBuildBufferChainFromBufferChain */
+
diff --git a/private/ntos/tdi/isn/nb/session.c b/private/ntos/tdi/isn/nb/session.c
new file mode 100644
index 000000000..fe998feb2
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/session.c
@@ -0,0 +1,2450 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ session.c
+
+Abstract:
+
+ This module contains the code to handle session frames
+ for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 28-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#ifdef RASAUTODIAL
+#include <acd.h>
+#include <acdapi.h>
+#endif // RASAUTODIAL
+#pragma hdrstop
+
+#ifdef RASAUTODIAL
+extern BOOLEAN fAcdLoadedG;
+extern ACD_DRIVER AcdDriverG;
+
+VOID
+NbiNoteNewConnection(
+ PCONNECTION pConnection
+ );
+#endif
+
+#ifdef RSRC_TIMEOUT_DBG
+VOID
+NbiSendDeathPacket(
+ IN PCONNECTION Connection,
+ IN CTELockHandle LockHandle
+ )
+{
+ PNDIS_PACKET Packet = PACKET(&NbiGlobalDeathPacket);
+ PNB_SEND_RESERVED Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
+ NB_CONNECTION UNALIGNED * Header;
+ PDEVICE Device = NbiDevice;
+ NDIS_STATUS NdisStatus;
+
+ if ( Reserved->SendInProgress ) {
+ DbgPrint("***Could not send death packet - in use\n");
+ NB_FREE_LOCK(&Connection->Lock, LockHandle);
+ return;
+ }
+
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_DEATH_PACKET;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(NB_CONNECTION)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(NB_CONNECTION)) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+ Header->Session.ConnectionControlFlag = 0;
+ Header->Session.DataStreamType = NB_CMD_DEATH_PACKET;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = Connection->RemoteConnectionId;
+ Header->Session.SendSequence = 0;
+ Header->Session.TotalDataLength = 0;
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = 0;
+
+
+ NB_FREE_LOCK(&Connection->Lock, LockHandle);
+
+ DbgPrint("*****Death packet is being sent for connection %lx, to <%.16s>\n",Connection, Connection->RemoteName);
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &Connection->LocalTarget,
+ Packet,
+ sizeof(NB_CONNECTION),
+ sizeof(NB_CONNECTION))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+}
+#endif //RSRC_TIMEOUT_DBG
+
+
+VOID
+NbiProcessSessionData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_SESSION_DATA frames.
+
+Arguments:
+
+ MacBindingHandle - A handle to use when calling NdisTransferData.
+
+ MacReceiveContext - A context to use when calling NdisTransferData.
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The lookahead buffer, starting at the IPX
+ header.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)LookaheadBuffer;
+ NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
+ PCONNECTION Connection;
+ PREQUEST Request;
+ PDEVICE Device = NbiDevice;
+ ULONG Hash;
+ ULONG ReceiveFlags;
+ ULONG IndicateBytesTransferred;
+ ULONG DataAvailable, DataIndicated;
+ ULONG DestBytes, BytesToTransfer;
+ PUCHAR DataHeader;
+ BOOLEAN Last, CompleteReceive, EndOfMessage, PartialReceive, CopyLookahead;
+ NTSTATUS Status;
+ NDIS_STATUS NdisStatus;
+ ULONG NdisBytesTransferred;
+ PIRP ReceiveIrp;
+ PSINGLE_LIST_ENTRY s;
+ PNB_RECEIVE_RESERVED ReceiveReserved;
+ PNDIS_PACKET Packet;
+ PNDIS_BUFFER BufferChain;
+ ULONG BufferChainLength;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ CTELockHandle CancelLH;
+
+ if (Sess->DestConnectionId != 0xffff) {
+
+ //
+ // This is an active connection, find it using
+ // our session id.
+ //
+
+ Hash = (Sess->DestConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Connection = Device->ConnectionHash[Hash].Connections;
+
+ while (Connection != NULL) {
+
+ if (Connection->LocalConnectionId == Sess->DestConnectionId) {
+ break;
+ }
+ Connection = Connection->NextConnection;
+ }
+
+ if (Connection == NULL) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ NbiReferenceConnectionLock (Connection, CREF_INDICATE);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // See what is happening with this connection.
+ //
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+#ifdef RSRC_TIMEOUT_DBG
+ if ( Connection->FirstMessageRequest && NbiGlobalDebugResTimeout ) {
+ LARGE_INTEGER CurrentTime, ElapsedTime;
+ KeQuerySystemTime(&CurrentTime);
+ ElapsedTime.QuadPart = CurrentTime.QuadPart - Connection->FirstMessageRequestTime.QuadPart;
+// DbgPrint("*****Elapsed %lx.%lx time\n",ElapsedTime.HighPart,ElapsedTime.LowPart);
+ if ( ElapsedTime.QuadPart > NbiGlobalMaxResTimeout.QuadPart ) {
+
+ DbgPrint("*****Connection %lx is not copleting irp %lx for %lx.%lx time\n",Connection, Connection->FirstMessageRequest,
+ ElapsedTime.HighPart,ElapsedTime.LowPart);
+ DbgPrint("************irp arrived at %lx.%lx current time %lx.%lx\n",
+ Connection->FirstMessageRequestTime.HighPart,Connection->FirstMessageRequestTime.LowPart,
+ CurrentTime.HighPart, CurrentTime.LowPart);
+
+ NbiSendDeathPacket( Connection, LockHandle );
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+ }
+ }
+#endif //RSRC_TIMEOUT_DBG
+
+ //
+ // The connection is up, see if this is data should
+ // be received.
+ //
+
+ if (Sess->ConnectionControlFlag & NB_CONTROL_SYSTEM) {
+
+ //
+ // This is an ack. This call releases
+ // the lock. BUGBUG: Does this need to
+ // be a function?
+ //
+
+ NbiProcessDataAck(
+ Connection,
+ Sess,
+ RemoteAddress
+ NB_LOCK_HANDLE_ARG (LockHandle)
+ );
+
+ } else {
+
+ //
+ // See if there is any piggyback ack here.
+ //
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK) {
+
+ //
+ // We are waiting for an ack, so see if this acks
+ // anything. Even the old netbios sometimes piggyback
+ // acks (and doesn't send the explicit ack).
+ //
+ // This releases the lock. BUGBUG: Fix this.
+ //
+
+ NbiReframeConnection(
+ Connection,
+ Sess->ReceiveSequence,
+ Sess->BytesReceived,
+ FALSE
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State != CONNECTION_STATE_ACTIVE) {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+ }
+
+ } else if ((Connection->NewNetbios) &&
+ (Connection->CurrentSend.SendSequence != Connection->UnAckedSend.SendSequence)) {
+
+ //
+ // For the new netbios, even if we are not waiting
+ // for an ack he may have acked something with this
+ // send and we should check, since it may allow
+ // us to open our send window.
+ //
+ // This releases the lock. BUGBUG: Fix this.
+ //
+
+ NbiReframeConnection(
+ Connection,
+ Sess->ReceiveSequence,
+ Sess->BytesReceived,
+ FALSE
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State != CONNECTION_STATE_ACTIVE) {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+ }
+
+ }
+
+ //
+ // This is data on the connection. First make sure
+ // it is the data we expect next.
+ //
+
+ if (Connection->NewNetbios) {
+
+ if (Sess->SendSequence != Connection->ReceiveSequence) {
+
+ ++Connection->ConnectionInfo.ReceiveErrors;
+ ++Device->Statistics.DataFramesRejected;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesRejected,
+ PacketSize - sizeof(NB_CONNECTION));
+
+ if ((Connection->ReceiveState == CONNECTION_RECEIVE_IDLE) ||
+ (Connection->ReceiveState == CONNECTION_RECEIVE_ACTIVE)) {
+
+ NB_ACK_TYPE AckType;
+
+ NB_DEBUG2 (RECEIVE, ("Got unexp data on %lx, %x(%d) expect %x(%d)\n",
+ Connection, Sess->SendSequence, Sess->Offset,
+ Connection->ReceiveSequence, Connection->CurrentReceive.MessageOffset));
+
+ //
+ // If we are receiving a packet we have already seen, just
+ // send a normal ack, otherwise force a resend. This test
+ // we do is equivalent to
+ // Sess->SendSequence < Connection->ReceiveSequence
+ // but rearranged so it works when the numbers wrap.
+ //
+
+ if ((SHORT)(Sess->SendSequence - Connection->ReceiveSequence) < 0) {
+
+ //
+ // Since this is a resend, check if the local
+ // target has changed.
+ //
+#if defined(_PNP_POWER)
+
+ if (!RtlEqualMemory (&Connection->LocalTarget, RemoteAddress, sizeof(IPX_LOCAL_TARGET))) {
+#if DBG
+ DbgPrint ("NBI: Switch local target for %lx, (%d,%d)\n", Connection,
+ Connection->LocalTarget.NicHandle.NicId, RemoteAddress->NicHandle.NicId);
+#endif
+ Connection->LocalTarget = *RemoteAddress;
+ }
+
+#else
+
+ if (!RtlEqualMemory (&Connection->LocalTarget, RemoteAddress, 8)) {
+#if DBG
+ DbgPrint ("NBI: Switch local target for %lx\n", Connection);
+#endif
+ Connection->LocalTarget = *RemoteAddress;
+ }
+
+#endif _PNP_POWER
+ AckType = NbiAckResponse;
+
+ } else {
+
+ AckType = NbiAckResend;
+ }
+
+ //
+ // This frees the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ AckType
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_DEBUG (RECEIVE, ("Got unexp on %lx RcvState %d, %x(%d) exp %x(%d)\n",
+ Connection, Connection->ReceiveState,
+ Sess->SendSequence, Sess->Offset,
+ Connection->ReceiveSequence, Connection->CurrentReceive.MessageOffset));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ } else {
+
+ //
+ // Old netbios.
+ //
+
+ if ((Sess->SendSequence != Connection->ReceiveSequence) ||
+ (Sess->Offset != Connection->CurrentReceive.MessageOffset)) {
+
+ ++Connection->ConnectionInfo.ReceiveErrors;
+ ++Device->Statistics.DataFramesRejected;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesRejected,
+ PacketSize - sizeof(NB_CONNECTION));
+
+ if ((Connection->ReceiveState == CONNECTION_RECEIVE_IDLE) ||
+ (Connection->ReceiveState == CONNECTION_RECEIVE_ACTIVE)) {
+
+ NB_ACK_TYPE AckType;
+
+ NB_DEBUG2 (RECEIVE, ("Got unexp on %lx, %x(%d) expect %x(%d)\n",
+ Connection, Sess->SendSequence, Sess->Offset,
+ Connection->ReceiveSequence, Connection->CurrentReceive.MessageOffset));
+
+ //
+ // If we are receiving the last packet again, just
+ // send a normal ack, otherwise force a resend.
+ //
+
+ if (((Sess->SendSequence == Connection->ReceiveSequence) &&
+ ((ULONG)(Sess->Offset + Sess->DataLength) == Connection->CurrentReceive.MessageOffset)) ||
+ (Sess->SendSequence == (USHORT)(Connection->ReceiveSequence-1))) {
+ AckType = NbiAckResponse;
+ } else {
+ AckType = NbiAckResend;
+ }
+
+ //
+ // This frees the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ AckType
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_DEBUG (RECEIVE, ("Got unexp on %lx RcvState %d, %x(%d) exp %x(%d)\n",
+ Connection, Connection->ReceiveState,
+ Sess->SendSequence, Sess->Offset,
+ Connection->ReceiveSequence, Connection->CurrentReceive.MessageOffset));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ }
+
+
+ IndicateBytesTransferred = 0;
+ DataAvailable = PacketSize - sizeof(NB_CONNECTION);
+ DataIndicated = LookaheadBufferSize - sizeof(NB_CONNECTION);
+ DataHeader = LookaheadBuffer + sizeof(NB_CONNECTION);
+
+ ++Device->TempFramesReceived;
+ Device->TempFrameBytesReceived += DataAvailable;
+
+ if (Connection->CurrentIndicateOffset) {
+ CTEAssert (DataAvailable >= Connection->CurrentIndicateOffset);
+ DataAvailable -= Connection->CurrentIndicateOffset;
+ if (DataIndicated >= Connection->CurrentIndicateOffset) {
+ DataIndicated -= Connection->CurrentIndicateOffset;
+ } else {
+ DataIndicated = 0;
+ }
+ DataHeader += Connection->CurrentIndicateOffset;
+ }
+
+ CopyLookahead = (BOOLEAN)(MacOptions & NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA);
+
+ if (Connection->NewNetbios) {
+ Last = (BOOLEAN)((Sess->ConnectionControlFlag & NB_CONTROL_EOM) != 0);
+ } else {
+ Last = (BOOLEAN)(Sess->Offset + Sess->DataLength == Sess->TotalDataLength);
+ }
+
+ Connection->CurrentReceiveNoPiggyback =
+ (BOOLEAN)((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) != 0);
+
+ if (Connection->ReceiveState == CONNECTION_RECEIVE_IDLE) {
+
+ //
+ // We don't have a receive posted, so see if we can
+ // get one from the queue or our client.
+ //
+
+ if (Connection->ReceiveQueue.Head != NULL) {
+
+ PTDI_REQUEST_KERNEL_RECEIVE ReceiveParameters;
+
+ Request = Connection->ReceiveQueue.Head;
+ Connection->ReceiveQueue.Head = REQUEST_SINGLE_LINKAGE(Request);
+ Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
+
+ Connection->ReceiveRequest = Request;
+ ReceiveParameters = (PTDI_REQUEST_KERNEL_RECEIVE)
+ (REQUEST_PARAMETERS(Request));
+ Connection->ReceiveLength = ReceiveParameters->ReceiveLength;
+
+ //
+ // If there is a send in progress, then we assume
+ // we are not in straight request-response mode
+ // and disable piggybacking of this ack.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_IDLE) {
+ Connection->NoPiggybackHeuristic = TRUE;
+ } else {
+ Connection->NoPiggybackHeuristic = (BOOLEAN)
+ ((ReceiveParameters->ReceiveFlags & TDI_RECEIVE_NO_RESPONSE_EXP) != 0);
+ }
+
+ Connection->CurrentReceive.Offset = 0;
+ Connection->CurrentReceive.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentReceive.BufferOffset = 0;
+
+ NB_DEBUG2 (RECEIVE, ("Activated receive %lx on %lx (%d)\n", Request, Connection, Connection->ReceiveSequence));
+
+ //
+ // Fall through the if and process the data.
+ //
+
+ } else {
+
+ if ((Connection->ReceiveUnaccepted == 0) &&
+ (Connection->AddressFile->RegisteredHandler[TDI_EVENT_RECEIVE])) {
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_INDICATE;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ ReceiveFlags = TDI_RECEIVE_AT_DISPATCH_LEVEL;
+ if (Last) {
+ ReceiveFlags |= TDI_RECEIVE_ENTIRE_MESSAGE;
+ }
+ if (CopyLookahead) {
+ ReceiveFlags |= TDI_RECEIVE_COPY_LOOKAHEAD;
+ }
+
+ Status = (*Connection->AddressFile->ReceiveHandler)(
+ Connection->AddressFile->HandlerContexts[TDI_EVENT_RECEIVE],
+ Connection->Context,
+ ReceiveFlags,
+ DataIndicated,
+ DataAvailable,
+ &IndicateBytesTransferred,
+ DataHeader,
+ &ReceiveIrp);
+
+ if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
+
+ //
+ // We got an IRP, activate it.
+ //
+
+ Request = NbiAllocateRequest (Device, ReceiveIrp);
+
+ IF_NOT_ALLOCATED(Request) {
+
+ ReceiveIrp->IoStatus.Information = 0;
+ ReceiveIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (ReceiveIrp, IO_NETWORK_INCREMENT);
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_W_RCV;
+
+ if (Connection->NewNetbios) {
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ Connection->LocalRcvSequenceMax =
+ (USHORT)(Connection->ReceiveSequence - 1);
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ CTEAssert (REQUEST_OPEN_CONTEXT(Request) == Connection);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ PTDI_REQUEST_KERNEL_RECEIVE ReceiveParameters;
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
+ Connection->ReceiveUnaccepted = DataAvailable - IndicateBytesTransferred;
+
+ Connection->ReceiveRequest = Request;
+ ReceiveParameters = (PTDI_REQUEST_KERNEL_RECEIVE)
+ (REQUEST_PARAMETERS(Request));
+ Connection->ReceiveLength = ReceiveParameters->ReceiveLength;
+
+ //
+ // If there is a send in progress, then we assume
+ // we are not in straight request-response mode
+ // and disable piggybacking of this ack.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_IDLE) {
+ Connection->NoPiggybackHeuristic = TRUE;
+ } else {
+ Connection->NoPiggybackHeuristic = (BOOLEAN)
+ ((ReceiveParameters->ReceiveFlags & TDI_RECEIVE_NO_RESPONSE_EXP) != 0);
+ }
+
+ Connection->CurrentReceive.Offset = 0;
+ Connection->CurrentReceive.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentReceive.BufferOffset = 0;
+
+ NbiReferenceConnectionSync (Connection, CREF_RECEIVE);
+
+ NB_DEBUG2 (RECEIVE, ("Indicate got receive %lx on %lx (%d)\n", Request, Connection, Connection->ReceiveSequence));
+
+ //
+ // Fall through the if and process the data.
+ //
+
+ } else {
+
+ //
+ // The connection has been stopped.
+ //
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+ }
+
+ } else if (Status == STATUS_SUCCESS) {
+
+ //
+ // He accepted some or all of the data.
+ //
+
+ NB_DEBUG2 (RECEIVE, ("Indicate took receive data %lx (%d)\n", Connection, Connection->ReceiveSequence));
+
+ if ( (IndicateBytesTransferred >= DataAvailable)) {
+
+ CTEAssert (IndicateBytesTransferred == DataAvailable);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax; // harmless if NewNetbios is FALSE
+ Connection->CurrentIndicateOffset = 0;
+ if ( Last ) {
+ Connection->CurrentReceive.MessageOffset = 0;
+ } else {
+ Connection->CurrentReceive.MessageOffset+= IndicateBytesTransferred;
+ }
+
+
+ ++Connection->ConnectionInfo.ReceivedTsdus;
+
+ //
+ // If there is a send in progress, then we assume
+ // we are not in straight request-response mode
+ // and disable piggybacking of this ack.
+ //
+
+ Connection->NoPiggybackHeuristic = (BOOLEAN)
+ (Connection->SubState != CONNECTION_SUBSTATE_A_IDLE);
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
+ Connection->ReceiveRequest = NULL;
+
+ //
+ // This releases the lock.
+ //
+
+ NbiAcknowledgeReceive(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ //
+ // We will do the easiest thing here, which
+ // is to send an ack for the amount he
+ // took, and force a retransmit on the
+ // remote. For net netbios we make a note
+ // of how many bytes were taken and ask
+ // for a resend.
+ //
+ // BUGBUG: Handle this better??
+ //
+
+#if DBG
+ DbgPrint ("NBI: Client took partial indicate data\n");
+#endif
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ Connection->CurrentReceive.MessageOffset +=
+ IndicateBytesTransferred;
+ Connection->ReceiveUnaccepted =
+ DataAvailable - IndicateBytesTransferred;
+ Connection->ReceiveState = CONNECTION_RECEIVE_W_RCV;
+
+ if (Connection->NewNetbios) {
+ Connection->CurrentIndicateOffset = IndicateBytesTransferred;
+ //
+ // NOTE: We don't advance ReceiveSequence
+ //
+ }
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ Connection->NewNetbios ?
+ NbiAckResend : NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ } else {
+
+ //
+ // No IRP returned.
+ //
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ Connection->ReceiveUnaccepted = DataAvailable;
+ Connection->ReceiveState = CONNECTION_RECEIVE_W_RCV;
+ NB_DEBUG (RECEIVE, ("Indicate got no receive on %lx (%lx)\n", Connection, Status));
+
+ if (Connection->NewNetbios) {
+
+ Connection->LocalRcvSequenceMax =
+ (USHORT)(Connection->ReceiveSequence - 1);
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ } else {
+
+ //
+ // No receive handler.
+ //
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_W_RCV;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ if (Connection->ReceiveUnaccepted == 0) {
+ NB_DEBUG (RECEIVE, ("No receive, no handler on %lx\n", Connection));
+ } else {
+ NB_DEBUG (RECEIVE, ("No receive, ReceiveUnaccepted %d on %lx\n",
+ Connection->ReceiveUnaccepted, Connection));
+ }
+
+ if (Connection->NewNetbios) {
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ Connection->LocalRcvSequenceMax =
+ (USHORT)(Connection->ReceiveSequence - 1);
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ }
+
+ } else if (Connection->ReceiveState != CONNECTION_RECEIVE_ACTIVE) {
+
+ //
+ // If we have a transfer in progress, or are waiting for
+ // a receive to be posted, then ignore this frame.
+ //
+
+ NB_DEBUG2 (RECEIVE, ("Got data on %lx, state %d (%d)\n", Connection, Connection->ReceiveState, Connection->ReceiveSequence));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ //
+ // At this point we have a receive and it is set to
+ // the correct current location.
+ //
+
+ DestBytes = Connection->ReceiveLength - Connection->CurrentReceive.Offset;
+ BytesToTransfer = DataAvailable - IndicateBytesTransferred;
+
+ if (DestBytes < BytesToTransfer) {
+
+ //
+ // If the data overflows the current receive, then make a
+ // note that we should complete the receive at the end of
+ // transfer data, but with EOR false.
+ //
+
+ EndOfMessage = FALSE;
+ CompleteReceive = TRUE;
+ PartialReceive = TRUE;
+ BytesToTransfer = DestBytes;
+
+ } else if (DestBytes == BytesToTransfer) {
+
+ //
+ // If the data just fills the current receive, then complete
+ // the receive; EOR depends on whether this is a DOL or not.
+ //
+
+ EndOfMessage = Last;
+ CompleteReceive = TRUE;
+ PartialReceive = FALSE;
+
+ } else {
+
+ //
+ // Complete the receive if this is a DOL.
+ //
+
+ EndOfMessage = Last;
+ CompleteReceive = Last;
+ PartialReceive = FALSE;
+
+ }
+
+ //
+ // If we can copy the data directly, then update our
+ // pointers, send an ack, and do the copy.
+ //
+
+ if ((BytesToTransfer > 0) &&
+ (IndicateBytesTransferred + BytesToTransfer <= DataIndicated)) {
+
+ ULONG BytesNow, BytesLeft;
+ PUCHAR CurTarget, CurSource;
+ ULONG CurTargetLen;
+ PNDIS_BUFFER CurBuffer;
+ ULONG CurByteOffset;
+
+ NB_DEBUG2 (RECEIVE, ("Direct copy of %d bytes %lx (%d)\n", BytesToTransfer, Connection, Connection->ReceiveSequence));
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_TRANSFER;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ CurBuffer = Connection->CurrentReceive.Buffer;
+ CurByteOffset = Connection->CurrentReceive.BufferOffset;
+
+ NdisQueryBuffer (CurBuffer, &CurTarget, &CurTargetLen);
+ CurTarget += CurByteOffset;
+ CurTargetLen -= CurByteOffset;
+
+ CurSource = DataHeader + IndicateBytesTransferred;
+ BytesLeft = BytesToTransfer;
+
+ while (TRUE) {
+
+ if (CurTargetLen < BytesLeft) {
+ BytesNow = CurTargetLen;
+ } else {
+ BytesNow = BytesLeft;
+ }
+ TdiCopyLookaheadData(
+ CurTarget,
+ CurSource,
+ BytesNow,
+ CopyLookahead ? TDI_RECEIVE_COPY_LOOKAHEAD : 0);
+
+ if (BytesNow == CurTargetLen) {
+ BytesLeft -= BytesNow;
+ CurBuffer = CurBuffer->Next;
+ CurByteOffset = 0;
+ if (BytesLeft > 0) {
+ NdisQueryBuffer (CurBuffer, &CurTarget, &CurTargetLen);
+ CurSource += BytesNow;
+ } else {
+ break;
+ }
+ } else {
+ CurByteOffset += BytesNow;
+ CTEAssert (BytesLeft == BytesNow);
+ break;
+ }
+
+ }
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ Connection->CurrentReceive.Buffer = CurBuffer;
+ Connection->CurrentReceive.BufferOffset = CurByteOffset;
+
+ Connection->CurrentReceive.Offset += BytesToTransfer;
+ Connection->CurrentReceive.MessageOffset += BytesToTransfer;
+
+ if (CompleteReceive ||
+ (Connection->State != CONNECTION_STATE_ACTIVE)) {
+
+ if (EndOfMessage) {
+
+ CTEAssert (!PartialReceive);
+
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax; // harmless if NewNetbios is FALSE
+ Connection->CurrentReceive.MessageOffset = 0;
+ Connection->CurrentIndicateOffset = 0;
+
+ } else if (Connection->NewNetbios) {
+
+ if (PartialReceive) {
+ Connection->CurrentIndicateOffset += BytesToTransfer;
+ } else {
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax;
+ Connection->CurrentIndicateOffset = 0;
+ }
+ }
+
+ //
+ // This sends an ack and releases the connection lock.
+ // and CANCEL Lock.
+ //
+
+ NbiCompleteReceive(
+ Connection,
+ EndOfMessage,
+ CancelLH
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ //
+ // CompleteReceive is FALSE, so EndOfMessage is FALSE.
+ //
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
+
+ //
+ // This releases the lock.
+ //
+
+ if (Connection->NewNetbios) {
+
+ //
+ // A partial receive should only happen if we are
+ // completing the receive.
+ //
+
+ CTEAssert (!PartialReceive);
+
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax;
+ Connection->CurrentIndicateOffset = 0;
+
+ if ((Connection->CurrentReceiveNoPiggyback) ||
+ ((Device->AckWindow != 0) &&
+ (++Connection->ReceivesWithoutAck >= Device->AckWindow))) {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+
+ //
+ // We have to set up a call to transfer data and send
+ // the ack after it completes (if it succeeds).
+ //
+
+ s = NbiPopReceivePacket (Device);
+ if (s == NULL) {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ ++Connection->ConnectionInfo.ReceiveErrors;
+ ++Device->Statistics.DataFramesRejected;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesRejected,
+ DataAvailable);
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+ }
+
+ ReceiveReserved = CONTAINING_RECORD (s, NB_RECEIVE_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (ReceiveReserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ //
+ // Initialize the receive packet.
+ //
+
+ ReceiveReserved->u.RR_CO.Connection = Connection;
+ ReceiveReserved->u.RR_CO.EndOfMessage = EndOfMessage;
+ ReceiveReserved->u.RR_CO.CompleteReceive = CompleteReceive;
+ ReceiveReserved->u.RR_CO.PartialReceive = PartialReceive;
+
+ ReceiveReserved->Type = RECEIVE_TYPE_DATA;
+ CTEAssert (!ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = TRUE;
+
+ //
+ // if we've got zero bytes left, avoid the TransferData below and
+ // just deliver.
+ //
+
+ if (BytesToTransfer <= 0) {
+
+ ReceiveReserved->u.RR_CO.NoNdisBuffer = TRUE;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_DEBUG2 (RECEIVE, ("TransferData of 0 bytes %lx (%d)\n", Connection, Connection->ReceiveSequence));
+ NbiTransferDataComplete(
+ Packet,
+ NDIS_STATUS_SUCCESS,
+ 0);
+
+ return;
+ }
+
+ //
+ // If needed, build a buffer chain to describe this
+ // to NDIS.
+ //
+
+ Connection->PreviousReceive = Connection->CurrentReceive;
+
+ if ((Connection->CurrentReceive.Offset == 0) &&
+ CompleteReceive) {
+
+ BufferChain = Connection->CurrentReceive.Buffer;
+ BufferChainLength = BytesToTransfer;
+ Connection->CurrentReceive.Buffer = NULL;
+ ReceiveReserved->u.RR_CO.NoNdisBuffer = TRUE;
+
+ } else {
+
+ if (NbiBuildBufferChainFromBufferChain (
+ Device->NdisBufferPoolHandle,
+ Connection->CurrentReceive.Buffer,
+ Connection->CurrentReceive.BufferOffset,
+ BytesToTransfer,
+ &BufferChain,
+ &Connection->CurrentReceive.Buffer,
+ &Connection->CurrentReceive.BufferOffset,
+ &BufferChainLength) != NDIS_STATUS_SUCCESS) {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_DEBUG2 (RECEIVE, ("Could not build receive buffer chain %lx (%d)\n", Connection, Connection->ReceiveSequence));
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ ReceiveReserved->u.RR_CO.NoNdisBuffer = FALSE;
+
+ }
+
+
+ NdisChainBufferAtFront (Packet, BufferChain);
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_TRANSFER;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NB_DEBUG2 (RECEIVE, ("TransferData of %d bytes %lx (%d)\n", BytesToTransfer, Connection, Connection->ReceiveSequence));
+
+ (*Device->Bind.TransferDataHandler) (
+ &NdisStatus,
+ MacBindingHandle,
+ MacReceiveContext,
+ LookaheadBufferOffset + sizeof(NB_CONNECTION) +
+ Connection->CurrentIndicateOffset + IndicateBytesTransferred,
+ BytesToTransfer,
+ Packet,
+ (PUINT)&NdisBytesTransferred);
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+#if DBG
+ if (NdisStatus == STATUS_SUCCESS) {
+ CTEAssert (NdisBytesTransferred == BytesToTransfer);
+ }
+#endif
+
+ NbiTransferDataComplete (
+ Packet,
+ NdisStatus,
+ NdisBytesTransferred);
+
+ }
+
+ return;
+
+ }
+
+ } else if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN)) {
+
+ //
+ // If this is the ack for the session initialize, then
+ // complete the pending connects. This routine releases
+ // the connection lock.
+ //
+
+ NbiProcessSessionInitAck(
+ Connection,
+ Sess
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+
+ } else {
+
+ //
+ // This is a session initialize frame.
+ //
+ // BUGBUG: If there is more data than in the lookahead
+ // buffer, we won't be able to echo it back in the
+ // response.
+ //
+
+ NbiProcessSessionInitialize(
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize);
+
+ }
+
+} /* NbiProcessSessionData */
+
+
+VOID
+NbiProcessDataAck(
+ IN PCONNECTION Connection,
+ IN NB_SESSION UNALIGNED * Sess,
+ IN PIPX_LOCAL_TARGET RemoteAddress
+ NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an ack on an active connection.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection.
+
+ Sess - The session frame.
+
+ RemoteAddress - The local target this packet was received from.
+
+ LockHandle - The handle used to acquire the lock.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ BOOLEAN Resend;
+
+ //
+ // Make sure we expect an ack right now.
+ //
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ if (((Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK) ||
+ (Connection->SubState == CONNECTION_SUBSTATE_A_REMOTE_W)) &&
+ ((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) == 0)) {
+
+ //
+ // We are waiting for an ack (because we completed
+ // packetizing a send, or ran out of receive window).
+ //
+ // This will complete any sends that are acked by
+ // this receive, and if necessary readjust the
+ // send pointer and requeue the connection for
+ // packetizing. It release the connection lock.
+ //
+
+ if (Connection->ResponseTimeout) {
+ Resend = TRUE;
+ Connection->ResponseTimeout = FALSE;
+ } else {
+ Resend = (BOOLEAN)
+ ((Sess->ConnectionControlFlag & NB_CONTROL_RESEND) != 0);
+ }
+
+ NbiReframeConnection(
+ Connection,
+ Sess->ReceiveSequence,
+ Sess->BytesReceived,
+ Resend
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else if ((Connection->SubState == CONNECTION_SUBSTATE_A_W_PROBE) &&
+ ((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) == 0)) {
+
+ //
+ // We had a probe outstanding and got a response. Restart
+ // the connection if needed (a send may have just been
+ // posted while the probe was outstanding).
+ //
+ // BUGBUG: We should check that the response is really
+ // correct.
+ //
+
+ if (Connection->NewNetbios) {
+ Connection->RemoteRcvSequenceMax = Sess->ReceiveSequenceMax;
+ }
+
+ NbiRestartConnection (Connection);
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ } else if ((Connection->SubState == CONNECTION_SUBSTATE_A_PACKETIZE) &&
+ ((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) == 0)) {
+
+ if (Connection->NewNetbios) {
+
+ //
+ // We are packetizing, reframe. In the unlikely
+ // event that this acks everything we may packetize
+ // in this call, but that is OK (the other thread
+ // will exit if we finish up). More normally we
+ // will just advance UnAcked send a bit.
+ //
+
+ NbiReframeConnection(
+ Connection,
+ Sess->ReceiveSequence,
+ Sess->BytesReceived,
+ (BOOLEAN)((Sess->ConnectionControlFlag & NB_CONTROL_RESEND) != 0)
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+#if 0
+
+ //
+ // BUGBUG: Should handle this case (i.e. may be in W_PACKET).
+ //
+
+ } else if ((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) == 0) {
+
+ DbgPrint ("NWLNKNB: Ignoring ack, state is %d\n", Connection->SubState);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+#endif
+
+ } else {
+
+ //
+ // We got a probe from the remote. Some old DOS clients
+ // send probes that do not have the send ack bit on,
+ // so we respond to any probe if none of the conditions
+ // above are true. This call releases the lock.
+ //
+ // We use the IgnoreNextDosProbe flag to ignore every
+ // second probe of this nature, to avoid a data ack
+ // war between two machines who each think they are
+ // responding to the other. This flag is set to FALSE
+ // whenever we send an ack or a probe.
+ //
+
+ if (!Connection->IgnoreNextDosProbe) {
+
+ //
+ // Since this is a probe, check if the local
+ // target has changed.
+ //
+
+ if (!RtlEqualMemory (&Connection->LocalTarget, RemoteAddress, 8)) {
+#if DBG
+ DbgPrint ("NBI: Switch local target for %lx\n", Connection);
+#endif
+ Connection->LocalTarget = *RemoteAddress;
+ }
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+ Connection->IgnoreNextDosProbe = TRUE;
+
+ } else {
+
+ Connection->IgnoreNextDosProbe = FALSE;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+
+ }
+
+} /* NbiProcessDataAck */
+
+
+VOID
+NbiProcessSessionInitialize(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_SESSION frames which have
+ a remote connection ID of 0xffff -- these are session
+ initialize frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ PacketBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)PacketBuffer;
+ NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
+ NB_SESSION_INIT UNALIGNED * SessInit = (NB_SESSION_INIT UNALIGNED *)(Sess+1);
+ CONNECT_INDICATION TempConnInd;
+ PCONNECT_INDICATION ConnInd;
+ PCONNECTION Connection;
+ PADDRESS Address;
+ PREQUEST Request, ListenRequest, AcceptRequest;
+ PDEVICE Device = NbiDevice;
+ PLIST_ENTRY p;
+ ULONG Hash;
+ TA_NETBIOS_ADDRESS SourceName;
+ PIRP AcceptIrp;
+ CONNECTION_CONTEXT ConnectionContext;
+ NTSTATUS AcceptStatus;
+ PADDRESS_FILE AddressFile, ReferencedAddressFile;
+ PTDI_REQUEST_KERNEL_LISTEN ListenParameters;
+ PTDI_CONNECTION_INFORMATION ListenInformation;
+ PTDI_CONNECTION_INFORMATION RemoteInformation;
+ TDI_ADDRESS_NETBIOS UNALIGNED * ListenAddress;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+ NB_DEFINE_LOCK_HANDLE (LockHandle2)
+ NB_DEFINE_LOCK_HANDLE (LockHandle3)
+ CTELockHandle CancelLH;
+
+ //
+ // Verify that the whole packet is there.
+ //
+
+ if (PacketSize < (sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT))) {
+#if DBG
+ DbgPrint ("NBI: Got short session initialize, %d/%d\n", PacketSize,
+ sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT));
+#endif
+ return;
+ }
+
+ //
+ // Verify that MaximumDataSize that remote can support is > 0
+ // Bug # 19405
+ //
+ if ( SessInit->MaximumDataSize == 0 ) {
+ NB_DEBUG(CONNECTION, ("Connect request with MaximumDataSize == 0\n"
+));
+ return;
+ }
+
+ //
+ // Make sure this is for an address we care about.
+ //
+
+ if (Device->AddressCounts[SessInit->DestinationName[0]] == 0) {
+ return;
+ }
+
+ Address = NbiFindAddress (Device, (PUCHAR)SessInit->DestinationName);
+
+ if (Address == NULL) {
+ return;
+ }
+
+ //
+ // First see if we have a session to this remote. We check
+ // this in case our ack of the session initialize was dropped,
+ // we don't want to reindicate our client.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle3);
+
+ for (Hash = 0; Hash < CONNECTION_HASH_COUNT; Hash++) {
+
+ Connection = Device->ConnectionHash[Hash].Connections;
+
+ while (Connection != NULL) {
+
+ if ((RtlEqualMemory (&Connection->RemoteHeader.DestinationNetwork, Conn->IpxHeader.SourceNetwork, 12)) &&
+ (Connection->RemoteConnectionId == Sess->SourceConnectionId) &&
+ (Connection->State != CONNECTION_STATE_DISCONNECT)) {
+
+ //
+ // Yes, we are talking to this remote, if it is active then
+ // respond, otherwise we are in the process of connecting
+ // and we will respond eventually.
+ //
+
+#if DBG
+ DbgPrint ("NBI: Got connect request on active connection %lx\n", Connection);
+#endif
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ NbiReferenceConnectionLock (Connection, CREF_INDICATE);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+ NbiSendSessionInitAck(
+ Connection,
+ (PUCHAR)(SessInit+1),
+ PacketSize - (sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT)),
+ NULL); // lock is not held
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+ }
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+ return;
+ }
+
+ Connection = Connection->NextConnection;
+ }
+ }
+
+
+ TdiBuildNetbiosAddress ((PUCHAR)SessInit->SourceName, FALSE, &SourceName);
+
+ //
+ // Scan the queue of listens to see if there is one that
+ // satisfies this request.
+ //
+ // NOTE: The device lock is held here.
+ //
+
+ for (p = Device->ListenQueue.Flink;
+ p != &Device->ListenQueue;
+ p = p->Flink) {
+
+ Request = LIST_ENTRY_TO_REQUEST (p);
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ if (Connection->AddressFile->Address != Address) {
+ continue;
+ }
+
+ //
+ // Check that this listen is not specific to a different
+ // netbios name.
+ //
+
+ ListenParameters = (PTDI_REQUEST_KERNEL_LISTEN)REQUEST_PARAMETERS(Request);
+ ListenInformation = ListenParameters->RequestConnectionInformation;
+
+ if (ListenInformation &&
+ (ListenInformation->RemoteAddress) &&
+ (ListenAddress = NbiParseTdiAddress(ListenInformation->RemoteAddress, FALSE)) &&
+ (!RtlEqualMemory(
+ SessInit->SourceName,
+ ListenAddress->NetbiosName,
+ 16))) {
+ continue;
+ }
+
+ //
+ // This connection is valid, so we use it.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Activating queued listen %lx\n", Connection));
+
+ RemoveEntryList (REQUEST_LINKAGE(Request));
+
+ RtlCopyMemory(&Connection->RemoteHeader.DestinationNetwork, Conn->IpxHeader.SourceNetwork, 12);
+ RtlCopyMemory (Connection->RemoteName, SessInit->SourceName, 16);
+ Connection->LocalTarget = *RemoteAddress;
+ Connection->RemoteConnectionId = Sess->SourceConnectionId;
+
+ Connection->SessionInitAckDataLength =
+ PacketSize - (sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT));
+ if (Connection->SessionInitAckDataLength > 0) {
+ Connection->SessionInitAckData = NbiAllocateMemory(
+ Connection->SessionInitAckDataLength, MEMORY_CONNECTION, "SessionInitAckData");
+ RtlCopyMemory(
+ Connection->SessionInitAckData,
+ (PUCHAR)(SessInit+1),
+ Connection->SessionInitAckDataLength);
+ }
+
+
+ Connection->MaximumPacketSize = SessInit->MaximumDataSize;
+
+ Connection->CurrentSend.SendSequence = 0;
+ Connection->UnAckedSend.SendSequence = 0;
+ Connection->RetransmitThisWindow = FALSE;
+ Connection->ReceiveSequence = 1;
+ Connection->CurrentReceive.MessageOffset = 0;
+ Connection->Retries = Device->KeepAliveCount;
+ if (Device->Extensions && ((Sess->ConnectionControlFlag & NB_CONTROL_NEW_NB) != 0)) {
+ Connection->NewNetbios = TRUE;
+ Connection->LocalRcvSequenceMax = 4; // may get modified after ripping based on card
+ Connection->RemoteRcvSequenceMax = Sess->ReceiveSequenceMax;
+ Connection->SendWindowSequenceLimit = 2;
+ if (Connection->RemoteRcvSequenceMax == 0) {
+ Connection->RemoteRcvSequenceMax = 1;
+ }
+ } else {
+ Connection->NewNetbios = FALSE;
+ }
+
+ //
+ // Save this information now for whenever we complete the listen.
+ //
+
+ RemoteInformation = ListenParameters->ReturnConnectionInformation;
+
+ if (RemoteInformation != NULL) {
+
+ RtlCopyMemory(
+ (PTA_NETBIOS_ADDRESS)RemoteInformation->RemoteAddress,
+ &SourceName,
+ (RemoteInformation->RemoteAddressLength < sizeof(TA_NETBIOS_ADDRESS)) ?
+ RemoteInformation->RemoteAddressLength : sizeof(TA_NETBIOS_ADDRESS));
+ }
+
+
+ if (ListenParameters->RequestFlags & TDI_QUERY_ACCEPT) {
+
+ //
+ // We have to wait for an accept before sending the
+ // session init ack, so we complete the listen and wait.
+ //
+
+ ListenRequest = Request;
+ Connection->ListenRequest = NULL;
+
+ NB_DEBUG2 (CONNECTION, ("Queued listen on %lx awaiting accept\n", Connection));
+
+ Connection->SubState = CONNECTION_SUBSTATE_L_W_ACCEPT;
+
+ NbiTransferReferenceConnection (Connection, CREF_LISTEN, CREF_W_ACCEPT);
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+ } else {
+
+ //
+ // We are ready to go, so we send out the find route request
+ // for the remote. We keep the listen alive and the CREF_LISTEN
+ // reference on until this completes.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Activating queued listen on %lx\n", Connection));
+
+ ListenRequest = NULL;
+
+ Connection->SubState = CONNECTION_SUBSTATE_L_W_ROUTE;
+
+ NbiReferenceConnectionLock (Connection, CREF_FIND_ROUTE);
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network =
+ *(UNALIGNED ULONG *)Conn->IpxHeader.SourceNetwork;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,Conn->IpxHeader.SourceNode,6);
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_NO_RIP;
+
+ //
+ // When this completes, we will send the session init
+ // ack. We don't call it if the client is for network 0,
+ // instead just fake as if no route could be found
+ // and we will use the local target we got here.
+ //
+
+ if (*(UNALIGNED ULONG *)Conn->IpxHeader.SourceNetwork != 0) {
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ } else {
+
+ NbiFindRouteComplete(
+ &Connection->FindRouteRequest,
+ FALSE);
+
+ }
+
+ }
+
+ //
+ // Complete the listen if needed.
+ //
+
+ if (ListenRequest != NULL) {
+
+ REQUEST_INFORMATION (ListenRequest) = 0;
+ REQUEST_STATUS (ListenRequest) = STATUS_SUCCESS;
+
+ NB_GET_CANCEL_LOCK ( &CancelLH );
+ IoSetCancelRoutine (ListenRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ NbiCompleteRequest (ListenRequest);
+ NbiFreeRequest (Device, ListenRequest);
+
+ }
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ return;
+
+ }
+
+ //
+ // We could not find a listen, so we indicate to every
+ // client. Make sure there is no session initialize for this
+ // remote being indicated. If there is not, we insert
+ // ourselves in the queue to block others.
+ //
+ // NOTE: The device lock is held here.
+ //
+
+ for (p = Device->ConnectIndicationInProgress.Flink;
+ p != &Device->ConnectIndicationInProgress;
+ p = p->Flink) {
+
+ ConnInd = CONTAINING_RECORD (p, CONNECT_INDICATION, Linkage);
+
+ if ((RtlEqualMemory(ConnInd->NetbiosName, SessInit->DestinationName, 16)) &&
+ (RtlEqualMemory(&ConnInd->RemoteAddress, Conn->IpxHeader.SourceNetwork, 12)) &&
+ (ConnInd->ConnectionId == Sess->SourceConnectionId)) {
+
+ //
+ // We are processing a request from this remote for
+ // the same ID, to avoid confusion we just exit.
+ //
+
+#if DBG
+ DbgPrint ("NBI: Already processing connect to <%.16s>\n", SessInit->DestinationName);
+#endif
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+ NbiDereferenceAddress (Address, AREF_FIND);
+ return;
+ }
+
+ }
+
+ RtlCopyMemory (&TempConnInd.RemoteAddress, SessInit->DestinationName, 16);
+ RtlCopyMemory (&TempConnInd.RemoteAddress, Conn->IpxHeader.SourceNetwork, 12);
+ TempConnInd.ConnectionId = Sess->SourceConnectionId;
+
+ InsertTailList (&Device->ConnectIndicationInProgress, &TempConnInd.Linkage);
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+
+ //
+ // Now scan through the address to find someone who has
+ // an indication routine registed and wants this connection.
+ //
+
+
+ ReferencedAddressFile = NULL;
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle1);
+
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+
+ //
+ // Find the next open address file in the list.
+ //
+
+ AddressFile = CONTAINING_RECORD (p, ADDRESS_FILE, Linkage);
+ if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
+ continue;
+ }
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_INDICATION);
+
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle1);
+
+ if (ReferencedAddressFile != NULL) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION);
+ }
+ ReferencedAddressFile = AddressFile;
+
+ //
+ // No posted listen requests; is there a kernel client?
+ //
+
+ if (AddressFile->RegisteredHandler[TDI_EVENT_CONNECT]) {
+
+ if ((*AddressFile->ConnectionHandler)(
+ AddressFile->HandlerContexts[TDI_EVENT_CONNECT],
+ sizeof (TA_NETBIOS_ADDRESS),
+ &SourceName,
+ 0, // user data
+ NULL,
+ 0, // options
+ NULL,
+ &ConnectionContext,
+ &AcceptIrp) != STATUS_MORE_PROCESSING_REQUIRED) {
+
+ //
+ // The client did not return a request, go to the
+ // next address file.
+ //
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle1);
+ continue;
+
+ }
+
+ AcceptRequest = NbiAllocateRequest (Device, AcceptIrp);
+
+ IF_NOT_ALLOCATED(AcceptRequest) {
+
+ AcceptStatus = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+ //
+ // The client accepted the connect, so activate
+ // the connection and complete the accept.
+ // listen. This lookup references the connection
+ // so we know it will remain valid.
+ //
+
+ Connection = NbiLookupConnectionByContext (
+ AddressFile,
+ ConnectionContext);
+
+ if (Connection != NULL) {
+
+ ASSERT (Connection->AddressFile == AddressFile);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle2);
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle3);
+
+ if ((Connection->State == CONNECTION_STATE_INACTIVE) &&
+ (Connection->DisassociatePending == NULL) &&
+ (Connection->ClosePending == NULL)) {
+
+ NB_DEBUG2 (CONNECTION, ("Indication on %lx returned connection %lx\n", AddressFile, Connection));
+
+ Connection->State = CONNECTION_STATE_LISTENING;
+ Connection->SubState = CONNECTION_SUBSTATE_L_W_ROUTE;
+
+ Connection->Retries = Device->KeepAliveCount;
+
+ RtlCopyMemory(&Connection->RemoteHeader.DestinationNetwork, Conn->IpxHeader.SourceNetwork, 12);
+ RtlCopyMemory (Connection->RemoteName, SessInit->SourceName, 16);
+ Connection->LocalTarget = *RemoteAddress;
+
+ Connection->SessionInitAckDataLength =
+ PacketSize - (sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT));
+ if (Connection->SessionInitAckDataLength > 0) {
+ Connection->SessionInitAckData = NbiAllocateMemory(
+ Connection->SessionInitAckDataLength, MEMORY_CONNECTION, "SessionInitAckData");
+ RtlCopyMemory(
+ Connection->SessionInitAckData,
+ (PUCHAR)(SessInit+1),
+ Connection->SessionInitAckDataLength);
+ }
+
+ Connection->MaximumPacketSize = SessInit->MaximumDataSize;
+
+ (VOID)NbiAssignConnectionId (Device, Connection); // BUGBUG: Check return code.
+ Connection->RemoteConnectionId = Sess->SourceConnectionId;
+
+ Connection->CurrentSend.SendSequence = 0;
+ Connection->UnAckedSend.SendSequence = 0;
+ Connection->RetransmitThisWindow = FALSE;
+ Connection->ReceiveSequence = 1;
+ Connection->CurrentReceive.MessageOffset = 0;
+ Connection->Retries = Device->KeepAliveCount;
+ if (Device->Extensions && ((Sess->ConnectionControlFlag & NB_CONTROL_NEW_NB) != 0)) {
+ Connection->NewNetbios = TRUE;
+ Connection->LocalRcvSequenceMax = 4; // may get modified after ripping based on card
+ Connection->RemoteRcvSequenceMax = Sess->ReceiveSequenceMax;
+ Connection->SendWindowSequenceLimit = 2;
+ if (Connection->RemoteRcvSequenceMax == 0) {
+ Connection->RemoteRcvSequenceMax = 1;
+ }
+ } else {
+ Connection->NewNetbios = FALSE;
+ }
+
+ NbiReferenceConnectionLock (Connection, CREF_ACCEPT);
+ NbiReferenceConnectionLock (Connection, CREF_FIND_ROUTE);
+
+ Connection->AcceptRequest = AcceptRequest;
+ AcceptStatus = STATUS_PENDING;
+
+ //
+ // Take us out of this list now, we will jump to
+ // FoundConnection which is past the removal below.
+ //
+
+ RemoveEntryList (&TempConnInd.Linkage);
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle2);
+
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network =
+ *(UNALIGNED ULONG *)Conn->IpxHeader.SourceNetwork;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,Conn->IpxHeader.SourceNode,6);
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_NO_RIP;
+
+ //
+ // When this completes, we will send the session init
+ // ack. We don't call it if the client is for network 0,
+ // instead just fake as if no route could be found
+ // and we will use the local target we got here.
+ // The accept is completed when this completes.
+ //
+
+ if (*(UNALIGNED ULONG *)Conn->IpxHeader.SourceNetwork != 0) {
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ } else {
+
+ NbiFindRouteComplete(
+ &Connection->FindRouteRequest,
+ FALSE);
+
+ }
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Indication on %lx returned invalid connection %lx\n", AddressFile, Connection));
+ AcceptStatus = STATUS_INVALID_CONNECTION;
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle2);
+
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_BY_CONTEXT);
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Indication on %lx returned unknown connection %lx\n", AddressFile, Connection));
+ AcceptStatus = STATUS_INVALID_CONNECTION;
+
+ }
+ }
+
+ //
+ // Complete the accept request in the failure case.
+ //
+
+ if (AcceptStatus != STATUS_PENDING) {
+
+ REQUEST_STATUS (AcceptRequest) = AcceptStatus;
+
+ NbiCompleteRequest (AcceptRequest);
+ NbiFreeRequest (Device, AcceptRequest);
+
+ } else {
+
+ //
+ // We found a connection, so we break; this is
+ // a jump since the while exit assumes the
+ // address lock is held.
+ //
+
+ goto FoundConnection;
+
+ }
+
+ }
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle1);
+
+ } // end of for loop through the address files
+
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle1);
+
+
+ //
+ // Take us out of the list that blocks other indications
+ // from this remote to this address.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle3);
+ RemoveEntryList (&TempConnInd.Linkage);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+FoundConnection:
+
+ if (ReferencedAddressFile != NULL) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION);
+ }
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+} /* NbiProcessSessionInitialize */
+
+
+VOID
+NbiProcessSessionInitAck(
+ IN PCONNECTION Connection,
+ IN NB_SESSION UNALIGNED * Sess
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles session init ack frames.
+
+ THIS ROUTINE IS CALLED WITH THE CONNECTION LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection.
+
+ Sess - The netbios header for the received frame.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST Request;
+ NB_SESSION_INIT UNALIGNED * SessInit = (NB_SESSION_INIT UNALIGNED *)(Sess+1);
+ BOOLEAN TimerWasStopped = FALSE;
+ CTELockHandle CancelLH;
+
+ if ((Sess->ConnectionControlFlag & NB_CONTROL_SYSTEM) &&
+ (Sess->SendSequence == 0x0000) &&
+ (Sess->ReceiveSequence == 0x0001)) {
+
+ NB_DEBUG2 (CONNECTION, ("Completing connect on %lx\n", Connection));
+
+ if (CTEStopTimer (&Connection->Timer)) {
+ TimerWasStopped = TRUE;
+ }
+
+ Connection->State = CONNECTION_STATE_ACTIVE;
+ Connection->SubState = CONNECTION_SUBSTATE_A_IDLE;
+ Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
+
+ if (Connection->Retries == NbiDevice->ConnectionCount) {
+ ++NbiDevice->Statistics.ConnectionsAfterNoRetry;
+ } else {
+ ++NbiDevice->Statistics.ConnectionsAfterRetry;
+ }
+ ++NbiDevice->Statistics.OpenConnections;
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ NbiStartWatchdog (Connection);
+
+ Connection->RemoteConnectionId = Sess->SourceConnectionId;
+
+ Connection->CurrentSend.SendSequence = 1;
+ Connection->UnAckedSend.SendSequence = 1;
+ Connection->RetransmitThisWindow = FALSE;
+ Connection->ReceiveSequence = 0;
+ Connection->CurrentReceive.MessageOffset = 0;
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ if (NbiDevice->Extensions && ((Sess->ConnectionControlFlag & NB_CONTROL_NEW_NB) != 0)) {
+ Connection->NewNetbios = TRUE;
+ Connection->LocalRcvSequenceMax =
+ (USHORT)(Connection->ReceiveWindowSize - 1);
+ Connection->RemoteRcvSequenceMax = Sess->ReceiveSequenceMax;
+ Connection->SendWindowSequenceLimit = 3;
+ } else {
+ Connection->NewNetbios = FALSE;
+ }
+
+ if (Connection->MaximumPacketSize > SessInit->MaximumDataSize) {
+ Connection->MaximumPacketSize = SessInit->MaximumDataSize;
+ }
+
+ Request = Connection->ConnectRequest;
+
+#ifdef RASAUTODIAL
+ //
+ // Check to see if we have to notify
+ // the automatic connection driver about
+ // this connection.
+ //
+ if (fAcdLoadedG) {
+ BOOLEAN fEnabled;
+ CTELockHandle AcdHandle;
+
+ CTEGetLock(&AcdDriverG.SpinLock, &AcdHandle);
+ fEnabled = AcdDriverG.fEnabled;
+ CTEFreeLock(&AcdDriverG.SpinLock, AcdHandle);
+ if (fEnabled)
+ NbiNoteNewConnection(Connection);
+ }
+#endif // RASAUTODIAL
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ REQUEST_STATUS (Request) = STATUS_SUCCESS;
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+
+ NbiTransferReferenceConnection (Connection, CREF_CONNECT, CREF_ACTIVE);
+
+ if (TimerWasStopped) {
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+} /* NbiProcessSessionInitAck */
+
+
+VOID
+NbiProcessSessionEnd(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_SESSION_END frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)PacketBuffer;
+ NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
+ PCONNECTION Connection;
+ PDEVICE Device = NbiDevice;
+ ULONG Hash;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+ NB_DEFINE_LOCK_HANDLE (LockHandle2)
+
+ //
+ // This is an active connection, find it using
+ // our session id (BUGBUG: Make this a function).
+ //
+
+ Hash = (Sess->DestConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ Connection = Device->ConnectionHash[Hash].Connections;
+
+ while (Connection != NULL) {
+
+ if (Connection->LocalConnectionId == Sess->DestConnectionId) {
+ break;
+ }
+ Connection = Connection->NextConnection;
+ }
+
+
+ //
+ // We reply to any session end, even if we don't know the
+ // connection, to speed up the disconnect on the remote.
+ //
+
+ if (Connection == NULL) {
+
+ NB_DEBUG (CONNECTION, ("Session end received on unknown id %lx\n", Sess->DestConnectionId));
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ NbiSendSessionEndAck(
+ (TDI_ADDRESS_IPX UNALIGNED *)(Conn->IpxHeader.SourceNetwork),
+ RemoteAddress,
+ Sess);
+ return;
+ }
+
+ NbiReferenceConnectionLock (Connection, CREF_INDICATE);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK) {
+
+ //
+ // We are waiting for an ack, so see if this acks
+ // anything. We do this in case a full send has been
+ // received by the remote but he did not send an
+ // ack before the session went down -- this will
+ // prevent us from failing a send which actually
+ // succeeded. If we are not in W_ACK this may ack
+ // part of a send, but in that case we don't care
+ // since StopConnection will abort it anyway and
+ // the amount successfully received by the remote
+ // doesn't matter.
+ //
+ // This releases the lock. BUGBUG: Fix this.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Session end at W_ACK, reframing %lx (%d)\n", Connection, Sess->ReceiveSequence));
+
+ NbiReframeConnection(
+ Connection,
+ Sess->ReceiveSequence,
+ Sess->BytesReceived,
+ FALSE
+ NB_LOCK_HANDLE_ARG(LockHandle1));
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Session end received on connection %lx\n", Connection));
+
+ }
+
+ //
+ // This call sets the state to DISCONNECT and
+ // releases the connection lock. It will also
+ // complete a disconnect wait request if one
+ // is pending, and indicate to our client
+ // if needed.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_REMOTE_DISCONNECT
+ NB_LOCK_HANDLE_ARG (LockHandle1));
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Session end received on inactive connection %lx\n", Connection));
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ }
+
+ NbiSendSessionEndAck(
+ (TDI_ADDRESS_IPX UNALIGNED *)(Conn->IpxHeader.SourceNetwork),
+ RemoteAddress,
+ Sess);
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+
+} /* NbiProcessSessionEnd */
+
+
+VOID
+NbiProcessSessionEndAck(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_SESSION_END_ACK frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)PacketBuffer;
+ NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
+ PCONNECTION Connection;
+ PDEVICE Device = NbiDevice;
+ ULONG Hash;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // This is an active connection, find it using
+ // our session id (BUGBUG: Make this a function).
+ //
+
+ Hash = (Sess->DestConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Connection = Device->ConnectionHash[Hash].Connections;
+
+ while (Connection != NULL) {
+
+ if (Connection->LocalConnectionId == Sess->DestConnectionId) {
+ break;
+ }
+ Connection = Connection->NextConnection;
+ }
+
+ if (Connection == NULL) {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ NbiReferenceConnectionLock (Connection, CREF_INDICATE);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // See what is happening with this connection.
+ //
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_DISCONNECT) {
+
+ //
+ // Stop the timer, when the reference goes away it
+ // will shut down. We set the substate so if the
+ // timer is running it will not restart (BUGBUG:
+ // there is a small window here, but it is not
+ // harmful, we will just have to timeout one
+ // more time).
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Got session end ack on %lx\n", Connection));
+
+ Connection->SubState = CONNECTION_SUBSTATE_D_GOT_ACK;
+ if (CTEStopTimer (&Connection->Timer)) {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+ } else {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+
+} /* NbiProcessSessionEndAck */
+
diff --git a/private/ntos/tdi/isn/nb/sources.inc b/private/ntos/tdi/isn/nb/sources.inc
new file mode 100644
index 000000000..f54b4918b
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/sources.inc
@@ -0,0 +1,69 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=nwlnknb
+
+TARGETNAME=nwlnknb
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\tdi.lib \
+ $(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..;..\inc;..\..\inc;..\..\..\..\inc;..\..\..\..\..\inc
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+C_DEFINES=$(C_DEFINES) -D_NTDRIVER_ -D_PNP_POWER=1 -DRASAUTODIAL
+#-DRSRC_TIMEOUT_DBG
+
+!IFDEF BUILD_FOR_3_51
+C_DEFINES= $(C_DEFINES) -D_NTIFS_
+!ENDIF
+
+SOURCES= \
+ ..\action.c \
+ ..\address.c \
+ ..\autodial.c \
+ ..\bind.c \
+ ..\cache.c \
+ ..\config.c \
+ ..\connect.c \
+ ..\datagram.c \
+ ..\device.c \
+ ..\driver.c \
+ ..\event.c \
+ ..\frame.c \
+ ..\nwlnknb.rc \
+ ..\packet.c \
+ ..\query.c \
+ ..\receive.c \
+ ..\send.c \
+ ..\session.c \
+ ..\timer.c
+
+PRECOMPILED_INCLUDE=..\precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
+ \ No newline at end of file
diff --git a/private/ntos/tdi/isn/nb/timer.c b/private/ntos/tdi/isn/nb/timer.c
new file mode 100644
index 000000000..381b120e5
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/timer.c
@@ -0,0 +1,1233 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ timer.c
+
+Abstract:
+
+ This module contains code which implements the timers for
+ netbios.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+ULONG NbiTickIncrement = 0;
+ULONG NbiShortTimerDeltaTicks = 0;
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,NbiInitializeTimers)
+#endif
+
+
+VOID
+NbiStartRetransmit(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the retransmit timer for the given connection.
+ The connection is inserted on the short list if it isn't on already.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - pointer to the connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // Insert us in the queue if we aren't in it.
+ //
+
+ Connection->Retransmit =
+ Device->ShortAbsoluteTime + Connection->CurrentRetransmitTimeout;
+
+ if (!Connection->OnShortList) {
+
+ CTEAssert (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ if (!Connection->OnShortList) {
+ Connection->OnShortList = TRUE;
+ InsertTailList (&Device->ShortList, &Connection->ShortList);
+ }
+
+ if (!Device->ShortListActive) {
+ NbiStartShortTimer (Device);
+ Device->ShortListActive = TRUE;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+ }
+
+} /* NbiStartRetransmit */
+
+
+VOID
+NbiStartWatchdog(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the watchdog timer for a connection.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - pointer to the connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+
+ Connection->Watchdog = Device->LongAbsoluteTime + Connection->WatchdogTimeout;
+
+ if (!Connection->OnLongList) {
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ if (!Connection->OnLongList) {
+ Connection->OnLongList = TRUE;
+ InsertTailList (&Device->LongList, &Connection->LongList);
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+ }
+
+} /* NbiStartWatchdog */
+
+#if DBG
+
+VOID
+NbiStopRetransmit(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stops the retransmit timer for a connection.
+
+Arguments:
+
+ Connection - pointer to the connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ Connection->Retransmit = 0;
+
+} /* NbiStopRetransmit */
+
+
+VOID
+NbiStopWatchdog(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stops the watchdog timer for a connection.
+
+Arguments:
+
+ Connection - pointer to the connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ Connection->Watchdog = 0;
+
+} /* NbiStopWatchdog */
+#endif
+
+
+VOID
+NbiExpireRetransmit(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the connection's retransmit timer
+ expires. It is called from NbiShortTimeout.
+
+Arguments:
+
+ Connection - Pointer to the connection whose timer has expired.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ BOOLEAN SendFindRoute;
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ SendFindRoute = FALSE;
+
+ ++Device->Statistics.ResponseTimerExpirations;
+
+ if (!(Connection->NewNetbios) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK)) {
+
+ if (--Connection->Retries == 0) {
+
+ //
+ // Shut down the connection. This will send
+ // out half the usual number of session end
+ // frames.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Wait for ack timeout of active connection %lx\n", Connection));
+
+ //
+ // This free the connection lock.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_LINK_FAILED
+ NB_LOCK_HANDLE_ARG (LockHandle)
+ );
+
+ } else {
+
+ //
+ // Set our current packetize location back to the
+ // spot of the last ack, and start up again.
+ //
+ // BUGBUG: Should we send a probe here?
+ //
+
+ Connection->CurrentSend = Connection->UnAckedSend;
+ Connection->RetransmitThisWindow = TRUE;
+ if (Connection->CurrentRetransmitTimeout < (Connection->BaseRetransmitTimeout*8)) {
+ Connection->CurrentRetransmitTimeout =
+ (Connection->CurrentRetransmitTimeout * 3) / 2;
+ }
+
+ NB_DEBUG2 (SEND, ("Connection %lx retransmit timeout\n", Connection));
+
+ //
+ // After half the retries, send a find route unless we
+ // are already doing one, or the connection is to network
+ // 0. When this completes we update the local target,
+ // for whatever good that does.
+ //
+
+ if ((!Connection->FindRouteInProgress) &&
+ (Connection->Retries == (Device->KeepAliveCount/2)) &&
+ (*(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork != 0)) {
+
+ SendFindRoute = TRUE;
+ Connection->FindRouteInProgress = TRUE;
+ NbiReferenceConnectionSync (Connection, CREF_FIND_ROUTE);
+
+ }
+
+ //
+ // This releases the lock.
+ //
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle)
+ );
+
+ }
+
+ } else if ((Connection->SubState == CONNECTION_SUBSTATE_A_W_PROBE) ||
+ (Connection->SubState == CONNECTION_SUBSTATE_A_REMOTE_W) ||
+ (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK)) {
+
+ if (--Connection->Retries == 0) {
+
+ //
+ // Shut down the connection. This will send
+ // out half the usual number of session end
+ // frames.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Probe timeout of active connection %lx\n", Connection));
+
+ //
+ // This free the connection lock.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_LINK_FAILED
+ NB_LOCK_HANDLE_ARG (LockHandle)
+ );
+
+ } else {
+
+ Connection->RetransmitThisWindow = TRUE;
+ if (Connection->CurrentRetransmitTimeout < (Connection->BaseRetransmitTimeout*8)) {
+ Connection->CurrentRetransmitTimeout =
+ (Connection->CurrentRetransmitTimeout * 3) / 2;
+ }
+
+ NbiStartRetransmit (Connection);
+
+ //
+ // After half the retries, send a find route unless we
+ // are already doing one, or the connection is to network
+ // 0. When this completes we update the local target,
+ // for whatever good that does.
+ //
+
+ if ((!Connection->FindRouteInProgress) &&
+ (Connection->Retries == (Device->KeepAliveCount/2)) &&
+ (*(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork != 0)) {
+
+ SendFindRoute = TRUE;
+ Connection->FindRouteInProgress = TRUE;
+ NbiReferenceConnectionSync (Connection, CREF_FIND_ROUTE);
+
+ }
+
+ //
+ // Set this so we know to retransmit when the ack
+ // is received.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_W_PROBE) {
+ Connection->ResponseTimeout = TRUE;
+ }
+
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckQuery
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ if (SendFindRoute) {
+
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network =
+ *(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,Connection->RemoteHeader.DestinationNode,6);
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_FORCE_RIP;
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+} /* NbiExpireRetansmit */
+
+
+VOID
+NbiExpireWatchdog(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the connection's watchdog timer
+ expires. It is called from NbiLongTimeout.
+
+Arguments:
+
+ Connection - Pointer to the connection whose timer has expired.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ //
+ // If we are not idle, then something else is happening
+ // so the watchdog is unnecessary.
+ //
+
+ if ((Connection->State == CONNECTION_STATE_ACTIVE) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_A_IDLE)) {
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_PROBE;
+ NbiStartRetransmit (Connection);
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckQuery
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+} /* NbiExpireWatchdog */
+
+
+VOID
+NbiShortTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called at regular intervals to see if any of
+ the short connection timers have expired, and if so to execute their
+ expiration routines.
+
+Arguments:
+
+ Event - The event controlling the timer.
+
+ Context - Points to our device.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PLIST_ENTRY p, nextp;
+ PDEVICE Device = (PDEVICE)Context;
+ PCONNECTION Connection;
+ BOOLEAN RestartTimer = FALSE;
+ LARGE_INTEGER CurrentTick;
+ LARGE_INTEGER TickDifference;
+ ULONG TickDelta;
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ //
+ // This prevents anybody from starting the timer while we
+ // are in this routine (the main reason for this is that it
+ // makes it easier to determine whether we should restart
+ // it at the end of this routine).
+ //
+
+ Device->ProcessingShortTimer = TRUE;
+
+ //
+ // Advance the up-counter used to mark time in SHORT_TIMER_DELTA units. If we
+ // advance it all the way to 0xf0000000, then reset it to 0x10000000.
+ // We also run all the lists, decreasing all counters by 0xe0000000.
+ //
+
+
+ KeQueryTickCount (&CurrentTick);
+
+ TickDifference.QuadPart = CurrentTick.QuadPart -
+ Device->ShortTimerStart.QuadPart;
+
+ TickDelta = TickDifference.LowPart / NbiShortTimerDeltaTicks;
+ if (TickDelta == 0) {
+ TickDelta = 1;
+ }
+
+ Device->ShortAbsoluteTime += TickDelta;
+
+ if (Device->ShortAbsoluteTime >= 0xf0000000) {
+
+ ULONG Timeout;
+
+ Device->ShortAbsoluteTime -= 0xe0000000;
+
+ p = Device->ShortList.Flink;
+ while (p != &Device->ShortList) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, ShortList);
+
+ Timeout = Connection->Retransmit;
+ if (Timeout) {
+ Connection->Retransmit = Timeout - 0xe0000000;
+ }
+
+ p = p->Flink;
+ }
+
+ }
+
+ p = Device->ShortList.Flink;
+ while (p != &Device->ShortList) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, ShortList);
+
+ ASSERT (Connection->OnShortList);
+
+ //
+ // To avoid problems with the refcount being 0, don't
+ // do this if we are in ADM.
+ //
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ if (Connection->Retransmit &&
+ (Device->ShortAbsoluteTime > Connection->Retransmit)) {
+
+ Connection->Retransmit = 0;
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+ NbiExpireRetransmit (Connection); // no locks held
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ }
+
+ }
+
+ if (!Connection->OnShortList) {
+
+ //
+ // The link has been taken out of the list while
+ // we were processing it. In this (rare) case we
+ // stop processing the whole list, we'll get it
+ // next time.
+ //
+
+ break;
+
+ }
+
+ nextp = p->Flink;
+
+ if (Connection->Retransmit == 0) {
+
+ Connection->OnShortList = FALSE;
+ RemoveEntryList(p);
+
+ //
+ // Do another check; that way if someone slipped in between
+ // the check of Connection->Tx and the OnShortList = FALSE and
+ // therefore exited without inserting, we'll catch that here.
+ //
+
+ if (Connection->Retransmit != 0) {
+ InsertTailList(&Device->ShortList, &Connection->ShortList);
+ Connection->OnShortList = TRUE;
+ }
+
+ }
+
+ p = nextp;
+
+ }
+
+ //
+ // If the list is empty note that, otherwise ShortListActive
+ // remains TRUE.
+ //
+
+ if (IsListEmpty (&Device->ShortList)) {
+ Device->ShortListActive = FALSE;
+ }
+
+
+ //
+ // Connection Data Ack timers. This queue is used to indicate
+ // that a piggyback ack is pending for this connection. We walk
+ // the queue, for each element we check if the connection has
+ // been on the queue for enough times through here,
+ // If so, we take it off and send an ack. Note that
+ // we have to be very careful how we walk the queue, since
+ // it may be changing while this is running.
+ //
+
+ for (p = Device->DataAckConnections.Flink;
+ p != &Device->DataAckConnections;
+ p = p->Flink) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, DataAckLinkage);
+
+ //
+ // Skip this connection if it is not queued or it is
+ // too recent to matter. We may skip incorrectly if
+ // the connection is just being queued, but that is
+ // OK, we will get it next time.
+ //
+
+ if (!Connection->DataAckPending) {
+ continue;
+ }
+
+ ++Connection->DataAckTimeouts;
+
+ if (Connection->DataAckTimeouts < Device->AckDelayTime) {
+ continue;
+ }
+
+ NbiReferenceConnectionSync (Connection, CREF_SHORT_D_ACK);
+
+ Device->DataAckQueueChanged = FALSE;
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+ //
+ // Check the correct connection flag, to ensure that a
+ // send has not just taken him off the queue.
+ //
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->DataAckPending) {
+
+ //
+ // Yes, we were waiting to piggyback an ack, but no send
+ // has come along. Turn off the flags and send an ack.
+ // We set PiggybackAckTimeout to TRUE so that we won't try
+ // to piggyback a response until we get back traffic.
+ //
+
+ Connection->DataAckPending = FALSE;
+ Connection->PiggybackAckTimeout = TRUE;
+ ++Device->Statistics.AckTimerExpirations;
+ ++Device->Statistics.PiggybackAckTimeouts;
+
+ //
+ // This call releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_SHORT_D_ACK);
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ //
+ // If the list has changed, then we need to stop processing
+ // since p->Flink is not valid.
+ //
+
+ if (Device->DataAckQueueChanged) {
+ break;
+ }
+
+ }
+
+ if (IsListEmpty (&Device->DataAckConnections)) {
+ Device->DataAckActive = FALSE;
+ }
+
+
+ //
+ // Update the real counters from the temp ones. We have
+ // TimerLock here, which is good enough.
+ //
+
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesSent,
+ Device->TempFrameBytesSent);
+ Device->Statistics.DataFramesSent += Device->TempFramesSent;
+
+ Device->TempFrameBytesSent = 0;
+ Device->TempFramesSent = 0;
+
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesReceived,
+ Device->TempFrameBytesReceived);
+ Device->Statistics.DataFramesReceived += Device->TempFramesReceived;
+
+ Device->TempFrameBytesReceived = 0;
+ Device->TempFramesReceived = 0;
+
+
+ //
+ // Determine if we have to restart the timer.
+ //
+
+ Device->ProcessingShortTimer = FALSE;
+
+ if ((Device->ShortListActive || Device->DataAckActive) &&
+ (Device->State != DEVICE_STATE_STOPPING)) {
+
+ RestartTimer = TRUE;
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+ if (RestartTimer) {
+
+ //
+ // Start up the timer again. Note that because we start the timer
+ // after doing work (above), the timer values will slip somewhat,
+ // depending on the load on the protocol. This is entirely acceptable
+ // and will prevent us from using the timer DPC in two different
+ // threads of execution.
+ //
+
+ KeQueryTickCount(&Device->ShortTimerStart);
+
+ CTEStartTimer(
+ &Device->ShortTimer,
+ SHORT_TIMER_DELTA,
+ NbiShortTimeout,
+ (PVOID)Device);
+
+ } else {
+
+ NbiDereferenceDevice (Device, DREF_SHORT_TIMER);
+
+ }
+
+} /* NbiShortTimeout */
+
+
+VOID
+NbiLongTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called at regular intervals to see if any of
+ the long connection timers have expired, and if so to execute their
+ expiration routines.
+
+Arguments:
+
+ Event - The event controlling the timer.
+
+ Context - Points to our device.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)Context;
+ PLIST_ENTRY p, nextp;
+ LIST_ENTRY AdapterStatusList;
+ PREQUEST AdapterStatusRequest;
+ PCONNECTION Connection;
+ PNETBIOS_CACHE CacheName;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+
+
+ //
+ // Advance the up-counter used to mark time in LONG_TIMER_DELTA units. If we
+ // advance it all the way to 0xf0000000, then reset it to 0x10000000.
+ // We also run all the lists, decreasing all counters by 0xe0000000.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ if (++Device->LongAbsoluteTime == 0xf0000000) {
+
+ ULONG Timeout;
+
+ Device->LongAbsoluteTime = 0x10000000;
+
+ p = Device->LongList.Flink;
+ while (p != &Device->LongList) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, LongList);
+
+ Timeout = Connection->Watchdog;
+ if (Timeout) {
+ Connection->Watchdog = Timeout - 0xe0000000;
+ }
+
+ p = p->Flink;
+ }
+
+ }
+
+
+ if ((Device->LongAbsoluteTime % 4) == 0) {
+
+ p = Device->LongList.Flink;
+ while (p != &Device->LongList) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, LongList);
+
+ ASSERT (Connection->OnLongList);
+
+ //
+ // To avoid problems with the refcount being 0, don't
+ // do this if we are in ADM.
+ //
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ if (Connection->Watchdog && (Device->LongAbsoluteTime > Connection->Watchdog)) {
+
+ Connection->Watchdog = 0;
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+ NbiExpireWatchdog (Connection); // no spinlocks held
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ }
+
+ }
+
+ if (!Connection->OnLongList) {
+
+ //
+ // The link has been taken out of the list while
+ // we were processing it. In this (rare) case we
+ // stop processing the whole list, we'll get it
+ // next time.
+ //
+
+#if DBG
+ DbgPrint ("NBI: Stop processing LongList, %lx removed\n", Connection);
+#endif
+ break;
+
+ }
+
+ nextp = p->Flink;
+
+ if (Connection->Watchdog == 0) {
+
+ Connection->OnLongList = FALSE;
+ RemoveEntryList(p);
+
+ if (Connection->Watchdog != 0) {
+ InsertTailList(&Device->LongList, &Connection->LongList);
+ Connection->OnLongList = TRUE;
+ }
+
+ }
+
+ p = nextp;
+
+ }
+
+ }
+
+
+ //
+ // Now scan the data ack queue, looking for connections with
+ // no acks queued that we can get rid of.
+ //
+ // Note: The timer spinlock is held here.
+ //
+
+ for (p = Device->DataAckConnections.Flink;
+ p != &Device->DataAckConnections;
+ p = p->Flink) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, DataAckLinkage);
+
+ if (Connection->DataAckPending) {
+ continue;
+ }
+
+ NbiReferenceConnectionSync (Connection, CREF_LONG_D_ACK);
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ //
+ // Have to check again, because the connection might
+ // just have been stopped, and it also might just have
+ // had a data ack queued.
+ //
+
+ if (Connection->OnDataAckQueue) {
+
+ Connection->OnDataAckQueue = FALSE;
+
+ RemoveEntryList (&Connection->DataAckLinkage);
+
+ if (Connection->DataAckPending) {
+ InsertTailList (&Device->DataAckConnections, &Connection->DataAckLinkage);
+ Connection->OnDataAckQueue = TRUE;
+ }
+
+ Device->DataAckQueueChanged = TRUE;
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ NbiDereferenceConnection (Connection, CREF_LONG_D_ACK);
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ //
+ // Since we have changed the list, we can't tell if p->Flink
+ // is valid, so break. The effect is that we gradually peel
+ // connections off the queue.
+ //
+
+ break;
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+
+ //
+ // Scan for any uncompleted receive IRPs, this may happen if
+ // the cable is pulled and we don't get any more ReceiveComplete
+ // indications.
+
+ NbiReceiveComplete((USHORT)0);
+
+
+ //
+ // Check if any adapter status queries are getting old.
+ //
+
+ InitializeListHead (&AdapterStatusList);
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ p = Device->ActiveAdapterStatus.Flink;
+
+ while (p != &Device->ActiveAdapterStatus) {
+
+ AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ p = p->Flink;
+
+ if (REQUEST_INFORMATION(AdapterStatusRequest) == 1) {
+
+ //
+ // BUGBUG: We should resend a certain number of times.
+ //
+
+ RemoveEntryList (REQUEST_LINKAGE(AdapterStatusRequest));
+ InsertTailList (&AdapterStatusList, REQUEST_LINKAGE(AdapterStatusRequest));
+
+ //
+ // We are going to abort this request, so dereference
+ // the cache entry it used.
+ //
+
+ CacheName = (PNETBIOS_CACHE)REQUEST_STATUS(AdapterStatusRequest);
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free delete name cache entry %lx\n", CacheName));
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Name deleted");
+
+ }
+
+ } else {
+
+ ++REQUEST_INFORMATION(AdapterStatusRequest);
+
+ }
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+
+ for (p = AdapterStatusList.Flink; p != &AdapterStatusList; ) {
+
+ AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ NB_DEBUG2 (QUERY, ("AdapterStatus %lx got name but no response\n", AdapterStatusRequest));
+
+ REQUEST_INFORMATION(AdapterStatusRequest) = 0;
+ REQUEST_STATUS(AdapterStatusRequest) = STATUS_IO_TIMEOUT;
+
+ NbiCompleteRequest(AdapterStatusRequest);
+ NbiFreeRequest (Device, AdapterStatusRequest);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_QUERY);
+
+ }
+
+ //
+ // See if a minute has passed and we need to check for empty
+ // cache entries to age out. We check for 64 seconds to make
+ // the mod operation faster.
+ //
+
+#if defined(_PNP_POWER)
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+#endif _PNP_POWER
+
+ ++Device->CacheTimeStamp;
+
+ if ((Device->CacheTimeStamp % 64) == 0) {
+
+
+ //
+ // flush all the entries which have been around for ten minutes
+ // (LONG_TIMER_DELTA is in milliseconds).
+ //
+
+ FlushOldFromNetbiosCacheTable( Device->NameCache, (600000 / LONG_TIMER_DELTA) );
+
+ }
+
+
+ //
+ // Start up the timer again. Note that because we start the timer
+ // after doing work (above), the timer values will slip somewhat,
+ // depending on the load on the protocol. This is entirely acceptable
+ // and will prevent us from using the timer DPC in two different
+ // threads of execution.
+ //
+
+ if (Device->State != DEVICE_STATE_STOPPING) {
+
+ CTEStartTimer(
+ &Device->LongTimer,
+ LONG_TIMER_DELTA,
+ NbiLongTimeout,
+ (PVOID)Device);
+
+ } else {
+#if defined(_PNP_POWER)
+ Device->LongTimerRunning = FALSE;
+#endif _PNP_POWER
+ NbiDereferenceDevice (Device, DREF_LONG_TIMER);
+ }
+
+#if defined(_PNP_POWER)
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+#endif _PNP_POWER
+} /* NbiLongTimeout */
+
+
+VOID
+NbiStartShortTimer(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the short timer, if it is not already running.
+
+Arguments:
+
+ Device - Pointer to our device context.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ //
+ // Start the timer unless it the DPC is already running (in
+ // which case it will restart the timer itself if needed),
+ // or some list is active (meaning the timer is already
+ // queued up).
+ //
+
+ if ((!Device->ProcessingShortTimer) &&
+ (!(Device->ShortListActive)) &&
+ (!(Device->DataAckActive))) {
+
+ NbiReferenceDevice (Device, DREF_SHORT_TIMER);
+
+ KeQueryTickCount(&Device->ShortTimerStart);
+
+ CTEStartTimer(
+ &Device->ShortTimer,
+ SHORT_TIMER_DELTA,
+ NbiShortTimeout,
+ (PVOID)Device);
+
+ }
+
+} /* NbiStartShortTimer */
+
+
+VOID
+NbiInitializeTimers(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the lightweight timer system for the transport
+ provider.
+
+Arguments:
+
+ Device - Pointer to our device.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ //
+ // NbiTickIncrement is the number of NT time increments
+ // which pass between each tick. NbiShortTimerDeltaTicks
+ // is the number of ticks which should happen in
+ // SHORT_TIMER_DELTA milliseconds (i.e. between each
+ // expiration of the short timer).
+ //
+
+ NbiTickIncrement = KeQueryTimeIncrement();
+
+ if (NbiTickIncrement > (SHORT_TIMER_DELTA * MILLISECONDS)) {
+ NbiShortTimerDeltaTicks = 1;
+ } else {
+ NbiShortTimerDeltaTicks = (SHORT_TIMER_DELTA * MILLISECONDS) / NbiTickIncrement;
+ }
+
+ //
+ // The AbsoluteTime cycles between 0x10000000 and 0xf0000000.
+ //
+
+ Device->ShortAbsoluteTime = 0x10000000;
+ Device->LongAbsoluteTime = 0x10000000;
+
+ CTEInitTimer (&Device->ShortTimer);
+ CTEInitTimer (&Device->LongTimer);
+
+#if !defined(_PNP_POWER)
+ //
+ // One reference for the long timer.
+ //
+
+ NbiReferenceDevice (Device, DREF_LONG_TIMER);
+
+ CTEStartTimer(
+ &Device->LongTimer,
+ LONG_TIMER_DELTA,
+ NbiLongTimeout,
+ (PVOID)Device);
+
+#endif !_PNP_POWER
+
+ Device->TimersInitialized = TRUE;
+ Device->ShortListActive = FALSE;
+ Device->ProcessingShortTimer = FALSE;
+
+ InitializeListHead (&Device->ShortList);
+ InitializeListHead (&Device->LongList);
+
+ CTEInitLock (&Device->TimerLock.Lock);
+
+} /* NbiInitializeTimers */
+
diff --git a/private/ntos/tdi/isn/nb/up/makefile b/private/ntos/tdi/isn/nb/up/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/up/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isn/nb/up/sources b/private/ntos/tdi/isn/nb/up/sources
new file mode 100644
index 000000000..85cdb3764
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/up/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+UP_DRIVER=yes
+
+TARGETPATH=obj
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/isn/rip/debug.h b/private/ntos/tdi/isn/rip/debug.h
new file mode 100644
index 000000000..2086b91d5
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/debug.h
@@ -0,0 +1,62 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: debug.h
+//
+// Description: Debug macros definitions
+//
+// Author: Stefan Solomon (stefans) October 4, 1993.
+//
+// Revision History:
+//
+//***
+
+#ifndef _DEBUG_
+#define _DEBUG_
+
+#if DBG
+#define DBG_INIT ((ULONG)0x00000001)
+#define DBG_IOCTL ((ULONG)0x00000002)
+#define DBG_UNLOAD ((ULONG)0x00000004)
+#define DBG_RCVPKT ((ULONG)0x00000008)
+#define DBG_RECV ((ULONG)0x00000010)
+#define DBG_ROUTE ((ULONG)0x00000020)
+#define DBG_SEND ((ULONG)0x00000040)
+#define DBG_RIP ((ULONG)0x00000080)
+#define DBG_SNDREQ ((ULONG)0x00000100)
+#define DBG_RIPTIMER ((ULONG)0x00000200)
+#define DBG_NIC ((ULONG)0x00000400)
+#define DBG_RIPAUX ((ULONG)0x00000800)
+#define DBG_NOTIFY ((ULONG)0x00001000)
+#define DBG_LINE ((ULONG)0x00002000)
+#define DBG_NETBIOS ((ULONG)0x00004000)
+#define DBG_INNACTIVITY ((ULONG)0x00008000)
+
+
+#define DEF_DBG_LEVEL DBG_INIT | \
+ DBG_IOCTL | \
+ DBG_UNLOAD | \
+ DBG_NIC | \
+ DBG_LINE | \
+ DBG_NOTIFY
+
+extern ULONG RouterDebugLevel;
+
+#define RtPrint(LEVEL,STRING) \
+ do { \
+ ULONG _level = (LEVEL); \
+ if (RouterDebugLevel & _level) { \
+ DbgPrint STRING; \
+ } \
+ } while (0)
+
+#define WAN_EMULATION
+
+#else
+#define RtPrint(LEVEL,STRING) do {NOTHING;} while (0)
+#endif
+
+#endif // _DEBUG_
diff --git a/private/ntos/tdi/isn/rip/dirs b/private/ntos/tdi/isn/rip/dirs
new file mode 100644
index 000000000..0dab2f056
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/dirs
@@ -0,0 +1,22 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=up mp
diff --git a/private/ntos/tdi/isn/rip/driver.c b/private/ntos/tdi/isn/rip/driver.c
new file mode 100644
index 000000000..ece07e568
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/driver.c
@@ -0,0 +1,1023 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: driver.c
+//
+// Description: router driver entry point
+//
+// Author: Stefan Solomon (stefans) October 13, 1993.
+//
+// Revision History:
+//
+//***
+
+#include <stdarg.h>
+#include "rtdefs.h"
+#include "driver.h"
+
+#if DBG
+ULONG RouterDebugLevel = DEF_DBG_LEVEL;
+#else
+ULONG RouterDebugLevel;
+#endif
+
+NTSTATUS
+GetRouterParameters(PUNICODE_STRING);
+
+NTSTATUS
+RouterDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+RouterUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+NTSTATUS
+RouterIoctl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN OUT PVOID ioBuffer,
+ IN ULONG inputBufferLength,
+ IN ULONG outputBufferLength
+ );
+
+USHORT dbgpktnr;
+
+NTSTATUS
+IoctlSnapRoutes(VOID);
+
+NTSTATUS
+IoctlGetNextRoute(PVOID iobufferp,
+ ULONG inbufflen,
+ ULONG outbufflen,
+ PULONG sizep);
+
+NTSTATUS
+IoctlCheckNetNumber(PVOID iobufferp,
+ ULONG inbufflen,
+ ULONG outbufflen,
+ PULONG bytestransfp);
+
+NTSTATUS
+IoctlShowNicInfo(PVOID iobufferp,
+ ULONG inbufflen,
+ ULONG outbufflen,
+ PULONG bytestransfp);
+
+NTSTATUS
+IoctlZeroNicStatistics(PVOID iobufferp,
+ ULONG inbufflen,
+ ULONG outbufflen,
+ PULONG bytestransfp);
+
+NTSTATUS
+IoctlShowMemStatistics(PVOID iobufferp,
+ ULONG inbufflen,
+ ULONG outbufflen,
+ PULONG bytestransfp);
+
+NTSTATUS
+IoctlGetWanInactivity(PVOID iobufferp,
+ ULONG inbufflen,
+ ULONG outbufflen,
+ PULONG bytestransfp);
+
+NTSTATUS
+IoctlSetWanGlobalNet(PVOID iobufferp,
+ ULONG inbufflen,
+ ULONG outbufflen,
+ PULONG bytestransfp);
+
+NTSTATUS
+IoctlDeleteWanGlobalAddress(PVOID iobufferp,
+ ULONG inbufflen,
+ ULONG outbufflen,
+ PULONG bytestransfp);
+
+VOID
+DeleteGlobalWanNet(VOID);
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point.
+ This entry point is called directly by the I/O system.
+
+Arguments:
+
+ DriverObject - pointer to the driver object
+
+ RegistryPath - pointer to a unicode string representing the path
+ to driver-specific key in the registry
+
+Return Value:
+
+ STATUS_SUCCESS if successful,
+ STATUS_UNSUCCESSFUL otherwise
+
+--*/
+{
+
+ PDEVICE_OBJECT deviceObject = NULL;
+ NTSTATUS ntStatus;
+ WCHAR deviceNameBuffer[] = L"\\Device\\Ipxroute";
+ UNICODE_STRING deviceNameUnicodeString;
+ PIPX_INTERNAL_BIND_RIP_OUTPUT IpxBindBuffp = NULL;
+
+ RtPrint(DBG_INIT, ("IPXROUTER: Entering DriverEntry\n"));
+
+ //
+ // Create a non - EXCLUSIVE device object (more than 1 thread at a time
+ // can make requests to this device)
+ //
+
+ RtlInitUnicodeString (&deviceNameUnicodeString,
+ deviceNameBuffer);
+
+ ntStatus = IoCreateDevice (DriverObject,
+ 0,
+ &deviceNameUnicodeString,
+ FILE_DEVICE_IPXROUTER,
+ 0,
+ FALSE,
+ &deviceObject
+ );
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ //
+ // Create dispatch points for device control, create, close.
+ //
+
+ DriverObject->MajorFunction[IRP_MJ_CREATE] =
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] =
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = RouterDispatch;
+ DriverObject->DriverUnload = RouterUnload;
+
+ }
+ else
+ {
+ RtPrint (DBG_INIT, ("IPXROUTER: IoCreateDevice failed\n"));
+ goto failure_exit;
+ }
+
+ // get registry configuration
+ ntStatus = GetRouterParameters(RegistryPath);
+
+ if(!NT_SUCCESS(ntStatus)) {
+
+ RtPrint (DBG_INIT, ("IPXROUTER: Error reading registry parameters\n"));
+ goto failure_exit;
+ }
+
+ // Bind to the ipx driver.
+ // If succesful, it will point the argument to a paged pool buffered with
+ // the Ipx driver output data. This buffer has to be freed after usage.
+ // The buffer is freed in the RouterInit routine.
+ ntStatus = BindToIpxDriver(&IpxBindBuffp);
+
+ if(!NT_SUCCESS(ntStatus)) {
+
+ RtPrint (DBG_INIT, ("IPXROUTER: Bind to Ipx driver failed\n"));
+ goto failure_exit;
+ }
+
+ // initialize the router
+ ntStatus = RouterInit(IpxBindBuffp);
+
+ if(!NT_SUCCESS(ntStatus)) {
+
+ RtPrint (DBG_INIT, ("IPXROUTER: Error initializing the router\n"));
+ goto failure_exit;
+ }
+
+ // Start the global timer
+ StartRtTimer();
+
+ // all initialization done
+ RouterInitialized = TRUE;
+
+ // Start the routing functionality
+ ntStatus = RouterStart();
+
+ if(!NT_SUCCESS(ntStatus)) {
+
+ RtPrint (DBG_INIT, ("IPXROUTER: Error starting the router\n"));
+ goto failure_exit;
+ }
+
+ // started OK
+ return STATUS_SUCCESS;
+
+failure_exit:
+
+ IoDeleteDevice (DriverObject->DeviceObject);
+ return ntStatus;
+}
+
+
+
+NTSTATUS
+RouterDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+/*++
+
+Routine Description:
+
+ Process the IRPs sent to this device.
+
+Arguments:
+
+ DeviceObject - pointer to a device object
+
+ Irp - pointer to an I/O Request Packet
+
+Return Value:
+
+
+--*/
+{
+ PIO_STACK_LOCATION irpStack;
+ PVOID ioBuffer;
+ ULONG inputBufferLength;
+ ULONG outputBufferLength;
+ ULONG ioControlCode;
+ NTSTATUS ntStatus;
+
+
+ //
+ // Init to default settings- we only expect 1 type of
+ // IOCTL to roll through here, all others an error.
+ //
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+
+ //
+ // Get a pointer to the current location in the Irp. This is where
+ // the function codes and parameters are located.
+ //
+
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+
+
+ //
+ // Get the pointer to the input/output buffer and it's length
+ //
+
+ ioBuffer = Irp->AssociatedIrp.SystemBuffer;
+ inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
+ outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+
+ switch (irpStack->MajorFunction)
+ {
+ case IRP_MJ_CREATE:
+
+ RtPrint(DBG_IOCTL, ("IPXROUTER: IRP_MJ_CREATE\n"));
+ dbgpktnr = 0x5000;
+
+ break;
+
+ case IRP_MJ_CLOSE:
+
+ RtPrint(DBG_IOCTL, ("IPXROUTER: IRP_MJ_CLOSE\n"));
+
+ break;
+
+ case IRP_MJ_DEVICE_CONTROL:
+
+ ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
+
+ switch (ioControlCode)
+ {
+
+ case IOCTL_IPXROUTER_SNAPROUTES:
+
+ Irp->IoStatus.Status = IoctlSnapRoutes();
+ break;
+
+ case IOCTL_IPXROUTER_GETNEXTROUTE:
+
+ Irp->IoStatus.Status = IoctlGetNextRoute (
+ ioBuffer,
+ inputBufferLength,
+ outputBufferLength,
+ &Irp->IoStatus.Information
+ );
+ break;
+
+ case IOCTL_IPXROUTER_CHECKNETNUMBER:
+
+ Irp->IoStatus.Status = IoctlCheckNetNumber (
+ ioBuffer,
+ inputBufferLength,
+ outputBufferLength,
+ &Irp->IoStatus.Information
+ );
+ break;
+
+ case IOCTL_IPXROUTER_SHOWNICINFO:
+
+ Irp->IoStatus.Status = IoctlShowNicInfo (
+ ioBuffer,
+ inputBufferLength,
+ outputBufferLength,
+ &Irp->IoStatus.Information
+ );
+ break;
+
+ case IOCTL_IPXROUTER_ZERONICSTATISTICS:
+
+ Irp->IoStatus.Status = IoctlZeroNicStatistics (
+ ioBuffer,
+ inputBufferLength,
+ outputBufferLength,
+ &Irp->IoStatus.Information
+ );
+ break;
+
+ case IOCTL_IPXROUTER_SHOWMEMSTATISTICS:
+
+ Irp->IoStatus.Status = IoctlShowMemStatistics (
+ ioBuffer,
+ inputBufferLength,
+ outputBufferLength,
+ &Irp->IoStatus.Information
+ );
+ break;
+
+ case IOCTL_IPXROUTER_GETWANINNACTIVITY:
+
+ Irp->IoStatus.Status = IoctlGetWanInactivity (
+ ioBuffer,
+ inputBufferLength,
+ outputBufferLength,
+ &Irp->IoStatus.Information
+ );
+ break;
+
+ case IOCTL_IPXROUTER_SETWANGLOBALADDRESS:
+
+ Irp->IoStatus.Status = IoctlSetWanGlobalNet(
+ ioBuffer,
+ inputBufferLength,
+ outputBufferLength,
+ &Irp->IoStatus.Information
+ );
+ break;
+
+ case IOCTL_IPXROUTER_DELETEWANGLOBALADDRESS:
+
+ Irp->IoStatus.Status = IoctlDeleteWanGlobalAddress(
+ ioBuffer,
+ inputBufferLength,
+ outputBufferLength,
+ &Irp->IoStatus.Information
+ );
+ break;
+
+ default:
+
+ RtPrint (DBG_INIT, ("IPXROUTER: unknown IRP_MJ_DEVICE_CONTROL\n"));
+
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+
+ break;
+
+ }
+
+ break;
+ }
+
+
+ //
+ // DON'T get cute and try to use the status field of
+ // the irp in the return status. That IRP IS GONE as
+ // soon as you call IoCompleteRequest.
+ //
+
+ ntStatus = Irp->IoStatus.Status;
+
+ IoCompleteRequest(Irp,
+ IO_NO_INCREMENT);
+
+
+ //
+ // We never have pending operation so always return the status code.
+ //
+
+ return ntStatus;
+}
+
+
+
+VOID
+RouterUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ DriverObject - pointer to a driver object
+
+Return Value:
+
+
+--*/
+{
+ PNICCB niccbp;
+ USHORT i;
+
+ RouterUnloading = TRUE;
+
+ // stop the global timer
+ StopRtTimer();
+
+ // stop the rip timer. If the rip timer work item has already been scheduled
+ // wait until it completes
+ StopRipTimer();
+
+ // stop the routing functionality
+ RouterStop();
+
+ // close all nics
+ for(i=0; i<MaximumNicCount; i++) {
+
+ niccbp = NicCbPtrTab[i];
+
+ if(NicClose(niccbp,
+ SIGNAL_CLOSE_COMPLETION_EVENT) == NIC_CLOSE_PENDING) {
+
+ // wait for the close timer to detect complete closing
+ KeWaitForSingleObject(
+ &niccbp->NicClosedEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ (PLARGE_INTEGER)NULL
+ );
+ }
+ }
+
+ // free resources allocated by all nics
+ for(i=0; i<MaximumNicCount; i++) {
+
+ niccbp = NicCbPtrTab[i];
+
+ if(NicFreeResources(niccbp) == NIC_RESOURCES_PENDING) {
+
+ // wait for the close timer to detect resources freed
+ KeWaitForSingleObject(
+ &niccbp->NicClosedEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ (PLARGE_INTEGER)NULL
+ );
+ }
+ }
+
+ // at this point, all rcv pkts are returned to the pool and no new packets
+ // can be allocated.
+ // all send packets have been freed and no new send requests are permitted.
+
+ // unbind from the IPX driver
+ UnbindFromIpxDriver();
+
+ // free the allocated memory
+ DestroyNicCbs();
+ DestroyRcvPktPool();
+
+ //
+ // Delete the device object
+ //
+
+ RtPrint(DBG_UNLOAD, ("IPXROUTER: unloading\n"));
+
+ IoDeleteDevice (DriverObject->DeviceObject);
+}
+
+LIST_ENTRY displayroutes;
+
+NTSTATUS
+IoctlGetNextRoute(PVOID iobufferp,
+ ULONG inbufflen,
+ ULONG outbufflen,
+ PULONG bytestransfp)
+{
+ PIPX_ROUTE_ENTRY rtep, drtep;
+ PLIST_ENTRY lep;
+
+ ASSERT(outbufflen >= sizeof(IPX_ROUTE_ENTRY));
+
+ if(IsListEmpty(&displayroutes)) {
+
+ return STATUS_NO_MORE_ENTRIES;
+ }
+
+ lep = RemoveHeadList(&displayroutes);
+
+ rtep = CONTAINING_RECORD(lep, IPX_ROUTE_ENTRY, PRIVATE.Linkage);
+ drtep = (PIPX_ROUTE_ENTRY)iobufferp;
+
+ *drtep = *rtep;
+ *bytestransfp = sizeof(IPX_ROUTE_ENTRY);
+
+ ExFreePool(rtep);
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+IoctlSnapRoutes(VOID)
+{
+ PIPX_ROUTE_ENTRY rtep, drtep;
+ UINT i;
+ KIRQL oldirql;
+
+ InitializeListHead(&displayroutes);
+
+ for(i=0; i<SegmentCount; i++) {
+
+ // LOCK THE ROUTING TABLE
+ ExAcquireSpinLock(&SegmentLocksTable[i], &oldirql);
+
+ if((rtep = IpxGetFirstRoute(i)) == NULL) {
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[i], oldirql);
+
+ continue;
+ }
+
+ drtep = ExAllocatePool(NonPagedPool, sizeof(IPX_ROUTE_ENTRY));
+
+ *drtep = *rtep;
+
+ InsertTailList(&displayroutes, &drtep->PRIVATE.Linkage);
+
+ while((rtep = IpxGetNextRoute(i)) != NULL) {
+
+ drtep = ExAllocatePool(NonPagedPool, sizeof(IPX_ROUTE_ENTRY));
+ *drtep = *rtep;
+ InsertTailList(&displayroutes, &drtep->PRIVATE.Linkage);
+ }
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[i], oldirql);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+IoctlCheckNetNumber(PVOID iobufferp,
+ ULONG inbufflen,
+ ULONG outbufflen,
+ PULONG bytestransfp)
+{
+ UINT seg;
+ UCHAR CheckNetwork[4];
+ KIRQL oldirql;
+
+ ASSERT(outbufflen >= sizeof(ULONG));
+
+ memcpy(CheckNetwork, iobufferp, 4);
+
+ // set the output to no-conflict
+ *(PULONG)iobufferp = 1;
+
+ seg = IpxGetSegment(CheckNetwork);
+
+ // LOCK THE ROUTING TABLE
+ ExAcquireSpinLock(&SegmentLocksTable[seg], &oldirql);
+
+ if(IpxGetRoute(seg, CheckNetwork)) {
+
+ *(PULONG)iobufferp = 0;
+ }
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[seg], oldirql);
+
+ *bytestransfp = sizeof(ULONG);
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+IoctlShowNicInfo(PVOID iobufferp,
+ ULONG inbufflen,
+ ULONG outbufflen,
+ PULONG bytestransfp)
+{
+ PNICCB niccbp;
+ USHORT index;
+ USHORT i;
+ PSHOW_NIC_INFO nisp;
+
+ ASSERT(outbufflen >= sizeof(SHOW_NIC_INFO));
+
+ index = *(PUSHORT)iobufferp;
+
+ for(i=0; i<MaximumNicCount; i++) {
+
+ niccbp=NicCbPtrTab[i];
+
+ if(niccbp->DeviceType == IPX_ROUTER_INVALID_DEVICE_TYPE) {
+
+ // skip the non configured nic
+ continue;
+ }
+
+ // configured nic
+ if(index--) {
+
+ // skip this
+ continue;
+ }
+
+ // configured nic and index == 0
+ nisp = (PSHOW_NIC_INFO)iobufferp;
+
+ nisp->NicId = niccbp->NicId;
+
+ if(niccbp->DeviceType == NdisMediumWan) {
+
+ nisp->DeviceType = SHOW_NIC_WAN;
+ }
+ else
+ {
+ nisp->DeviceType = SHOW_NIC_LAN;
+ }
+
+ nisp->NicState = niccbp->NicState;
+ memcpy(nisp->Network, niccbp->Network, 4);
+ memcpy(nisp->Node, niccbp->Node, 6);
+ nisp->TickCount = niccbp->TickCount;
+ nisp->StatBadReceived = niccbp->StatBadReceived;
+ nisp->StatRipReceived = niccbp->StatRipReceived;
+ nisp->StatRipSent = niccbp->StatRipSent;
+ nisp->StatRoutedReceived = niccbp->StatRoutedReceived;
+ nisp->StatRoutedSent = niccbp->StatRoutedSent;
+ nisp->StatType20Received = niccbp->StatType20Received;
+ nisp->StatType20Sent = niccbp->StatType20Sent;
+
+ *bytestransfp = sizeof(SHOW_NIC_INFO);
+ return STATUS_SUCCESS;
+ }
+
+ return STATUS_NO_MORE_ENTRIES;
+}
+
+NTSTATUS
+IoctlZeroNicStatistics(PVOID iobufferp,
+ ULONG inbufflen,
+ ULONG outbufflen,
+ PULONG bytestransfp)
+{
+ PNICCB niccbp;
+ USHORT i;
+
+ for(i=0; i<MaximumNicCount; i++) {
+
+ niccbp=NicCbPtrTab[i];
+
+ if(niccbp->DeviceType == IPX_ROUTER_INVALID_DEVICE_TYPE) {
+
+ // skip the non configured nic
+ continue;
+ }
+
+ // configured nic
+ ZeroNicStatistics(niccbp);
+ }
+
+ StatMemPeakCount = 0;
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+IoctlShowMemStatistics(PVOID iobufferp,
+ ULONG inbufflen,
+ ULONG outbufflen,
+ PULONG bytestransfp)
+{
+ PSHOW_MEM_STAT smsp;
+
+ smsp = (PSHOW_MEM_STAT)iobufferp;
+
+ smsp->PeakPktAllocCount = StatMemPeakCount;
+ smsp->CurrentPktAllocCount = StatMemAllocCount;
+ smsp->CurrentPktPoolCount = RcvPktCount;
+ smsp->PacketSize = UlongMaxFrameSize * sizeof(ULONG);
+
+ *bytestransfp = sizeof(SHOW_MEM_STAT);
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+IoctlGetWanInactivity(PVOID iobufferp,
+ ULONG inbufflen,
+ ULONG outbufflen,
+ PULONG bytestransfp)
+{
+ PGET_WAN_INNACTIVITY pgwi;
+ PNICCB niccbp;
+ USHORT i;
+
+ pgwi = (PGET_WAN_INNACTIVITY)iobufferp;
+
+ // check that we have a valid NicId
+ if(pgwi->NicId == 0xFFFF) {
+
+ // get the valid NicId for this remote node
+ for(i=0; i<MaximumNicCount; i++) {
+
+ niccbp = NicCbPtrTab[i];
+ if((niccbp->DeviceType == NdisMediumWan) &&
+ (niccbp->NicState == NIC_ACTIVE)) {
+
+ // check if this is the one we look for
+ if(!memcmp(pgwi->RemoteNode, niccbp->RemoteNode, 6)) {
+
+ // this is the one
+ pgwi->NicId = niccbp->NicId;
+ break;
+ }
+ }
+ }
+
+ // check that we have found the nic
+ if(pgwi->NicId == 0xFFFF) {
+
+ // ERROR: no nic coresponding to this remote node
+ goto WanInactivityExit;
+ }
+ }
+ else
+ {
+ // check that we have a valid handle indeed
+ if(pgwi->NicId < MaximumNicCount) {
+
+ // Nic id looks valid
+ niccbp = NicCbPtrTab[pgwi->NicId];
+
+ if(memcmp(pgwi->RemoteNode, niccbp->RemoteNode, 6)) {
+
+ // ERROR: this nic id has a wrong remote node
+ // reset the nic id to indicate the error
+ pgwi->NicId = 0xFFFF;
+
+ goto WanInactivityExit;
+ }
+ }
+ else
+ {
+ // ERROR: wrong nic id -> too big
+ // reset the nicid to indicate the error
+ pgwi->NicId = 0xFFFF;
+
+ goto WanInactivityExit;
+ }
+ }
+
+ // we got the correct nic id
+ pgwi->WanInnactivityCount = IpxGetWanInactivity(niccbp->NicId);
+
+WanInactivityExit:
+
+ *bytestransfp = sizeof(GET_WAN_INNACTIVITY);
+
+ return STATUS_SUCCESS;
+}
+
+//***
+//
+// Function: IoctlSetWanGlobalNet
+//
+// Descr: Called by ipxcp when the dll gets loaded, if configured with
+// global wan net option.
+// It generates a net number using the last four bytes of the address of
+// the first lan net, checks that the net number is unique and then adds it
+// to the routing table and marks the route as wan global.
+// Returns the wan global net number to the caller.
+//
+//***
+
+NTSTATUS
+IoctlSetWanGlobalNet(PVOID iobufferp,
+ ULONG inbufflen,
+ ULONG outbufflen,
+ PULONG bytestransfp)
+{
+ UCHAR wnet[4]; // wan global net number
+ USHORT i;
+ PNICCB niccbp;
+ UINT seg;
+ KIRQL oldirql;
+ PIPX_ROUTE_ENTRY rtep;
+ PSET_WAN_GLOBAL_ADDRESS wgap;
+ BOOLEAN statconfig; // TRUE -> static net config
+ // FALSE -> dynamic net config
+ ULONG wnetnumber;
+ LARGE_INTEGER tickcount;
+
+ // check if we have already been called to configure the router for a WanGlobalNet.
+ // If this has hapened, clean up before seting the new wan global network number
+ DeleteGlobalWanNet();
+
+ // get the wnet desired value from the ioctl request
+ wgap = (PSET_WAN_GLOBAL_ADDRESS)iobufferp;
+ memcpy(wnet, wgap->WanGlobalNetwork, 4);
+
+ // assume success and set the final error code
+ wgap->ErrorCode = 0;
+ *bytestransfp = sizeof(SET_WAN_GLOBAL_ADDRESS);
+
+ // check if this is a static value or dynamic config is wanted
+ if(!memcmp(wnet, nulladdress, 4)) {
+
+ // wnet is null -> we are requested to make the address
+ // get the node address of the first LAN card and make the net address with its last
+ // four bytes
+
+ // Put the tick count value in case we don't find a LAN card !
+ KeQueryTickCount(&tickcount);
+ PUTULONG2LONG(wnet, tickcount.LowPart);
+
+ statconfig = FALSE;
+
+ for(i=0; i<MaximumNicCount; i++) {
+
+ niccbp = NicCbPtrTab[i];
+
+ if((niccbp->DeviceType != IPX_ROUTER_INVALID_DEVICE_TYPE) && // configured nic
+ (niccbp->DeviceType != NdisMediumWan)) { // LAN nic
+
+ memcpy(wnet, &niccbp->Node[2], 4);
+ break;
+ }
+ }
+
+ }
+ else
+ {
+ // wnet is the number the user requests
+ statconfig = TRUE;
+ }
+
+ // Check that the static/dynamic wan global net nr is a unique net number
+ seg = IpxGetSegment(wnet);
+
+ // LOCK THE ROUTING TABLE
+ ExAcquireSpinLock(&SegmentLocksTable[seg], &oldirql);
+
+ while(IpxGetRoute(seg, wnet)) {
+
+ // the network number exists -> we are allowed to resolve the conflict only in
+ // the case we are configuring dynamically
+ if(!statconfig) {
+
+ // increment the number and try again
+ GETLONG2ULONG(&wnetnumber, wnet);
+ wnetnumber++;
+ PUTULONG2LONG(wnet, wnetnumber);
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[seg], oldirql);
+
+ seg = IpxGetSegment(wnet);
+ // RELOCK THE ROUTING TABLE
+ ExAcquireSpinLock(&SegmentLocksTable[seg], &oldirql);
+ }
+ else
+ {
+ // return and report the error
+ wgap->ErrorCode = ERROR_IPXCP_NETWORK_NUMBER_IN_USE;
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[seg], oldirql);
+
+ return STATUS_SUCCESS;
+ }
+ }
+
+ // there is no such net, add it
+ if((rtep = ExAllocatePool(NonPagedPool, sizeof(IPX_ROUTE_ENTRY))) == NULL) {
+
+ // can't allocate the route entry -> return
+ wgap->ErrorCode = ERROR_IPXCP_MEMORY_ALLOCATION_FAILURE;
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[seg], oldirql);
+
+ return STATUS_SUCCESS;
+ }
+
+ // set up the new route entry
+ memcpy(rtep->Network, wnet, IPX_NET_LEN);
+
+ rtep->NicId = 0xFFFE; // that's what we use for the global wan net
+
+ memcpy(rtep->NextRouter, nulladdress, IPX_NODE_LEN);
+ rtep->Flags = IPX_ROUTER_LOCAL_NET | IPX_ROUTER_PERMANENT_ENTRY | IPX_ROUTER_GLOBAL_WAN_NET;
+ rtep->Timer = 0; // TTL of this route entry is 3 min
+ rtep->Segment = seg;
+ rtep->TickCount = DEFAULT_WAN_GLOBAL_NET_TICKCOUNT;
+ rtep->HopCount = 1;
+
+ InitializeListHead(&rtep->AlternateRoute);
+
+ RtPrint(DBG_INIT, ("IpxRouter: IoctlSetWanGlobalNet: Adding route entry for global WAN net %x-%x-%x-%x \n",
+ wnet[0],
+ wnet[1],
+ wnet[2],
+ wnet[3]));
+
+ IpxAddRoute(seg, rtep);
+
+ // set our global variable to indicate we have a global wan net
+ WanGlobalNetworkEnabled = TRUE;
+ memcpy(WanGlobalNetwork, rtep->Network, 4);
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[seg], oldirql);
+
+ // Broadcast the new route entry on all the LAN segments
+ BroadcastWanNetUpdate(rtep, NULL, NULL);
+
+ // copy the net and return
+ memcpy(wgap->WanGlobalNetwork, wnet, IPX_NET_LEN);
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+DeleteGlobalWanNet(VOID)
+{
+ UINT seg;
+ KIRQL oldirql;
+ PIPX_ROUTE_ENTRY rtep;
+
+ // if configured with a wan global network, delete and free the route entry now
+ if(WanGlobalNetworkEnabled) {
+
+ WanGlobalNetworkEnabled = FALSE;
+
+ seg = IpxGetSegment(WanGlobalNetwork);
+
+ // LOCK THE ROUTING TABLE
+ ExAcquireSpinLock(&SegmentLocksTable[seg], &oldirql);
+
+ if(rtep = IpxGetRoute(seg, WanGlobalNetwork)) {
+
+ IpxDeleteRoute(seg, rtep);
+
+ RtPrint(DBG_INIT, ("IpxRouter: DeleteGlobalWanNet: Deleted wan global net route entry\n"));
+ }
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[seg], oldirql);
+
+ if(rtep) {
+
+ ExFreePool(rtep);
+ }
+ }
+}
+
+NTSTATUS
+IoctlDeleteWanGlobalAddress(PVOID iobufferp,
+ ULONG inbufflen,
+ ULONG outbufflen,
+ PULONG bytestransfp)
+{
+ // If we are called with this IOCtl, it means IPXCP has been reconfigured to
+ // to use static/dynamic wan nets allocation and NOT the global wan net.
+ // If the router had been configured previously for the global wan net, delete the
+ // net and reconfigure now.
+ DeleteGlobalWanNet();
+
+ return STATUS_SUCCESS;
+}
diff --git a/private/ntos/tdi/isn/rip/driver.h b/private/ntos/tdi/isn/rip/driver.h
new file mode 100644
index 000000000..a75b65ba4
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/driver.h
@@ -0,0 +1,150 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ driver.h
+
+Abstract:
+
+
+Environment:
+
+ kernel & User mode
+
+Notes:
+
+
+Revision History:
+
+--*/
+
+
+//
+// Define the various device type values. Note that values used by Microsoft
+// Corporation are in the range 0-32767, and 32768-65535 are reserved for use
+// by customers.
+//
+
+#define FILE_DEVICE_IPXROUTER 0x00008000
+
+
+
+//
+// Macro definition for defining IOCTL and FSCTL function control codes. Note
+// that function codes 0-2047 are reserved for Microsoft Corporation, and
+// 2048-4095 are reserved for customers.
+//
+
+#define IPXROUTER_IOCTL_INDEX (ULONG)0x00000800
+
+
+//
+// Define our own private IOCTLs
+//
+
+#define IOCTL_IPXROUTER_SNAPROUTES CTL_CODE(FILE_DEVICE_IPXROUTER, \
+ IPXROUTER_IOCTL_INDEX+1,\
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_IPXROUTER_GETNEXTROUTE CTL_CODE(FILE_DEVICE_IPXROUTER, \
+ IPXROUTER_IOCTL_INDEX+2,\
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_IPXROUTER_CHECKNETNUMBER CTL_CODE(FILE_DEVICE_IPXROUTER, \
+ IPXROUTER_IOCTL_INDEX+3,\
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_IPXROUTER_SHOWNICINFO CTL_CODE(FILE_DEVICE_IPXROUTER, \
+ IPXROUTER_IOCTL_INDEX+4,\
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_IPXROUTER_ZERONICSTATISTICS CTL_CODE(FILE_DEVICE_IPXROUTER, \
+ IPXROUTER_IOCTL_INDEX+5,\
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_IPXROUTER_SHOWMEMSTATISTICS CTL_CODE(FILE_DEVICE_IPXROUTER, \
+ IPXROUTER_IOCTL_INDEX+6,\
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_IPXROUTER_GETWANINNACTIVITY CTL_CODE(FILE_DEVICE_IPXROUTER, \
+ IPXROUTER_IOCTL_INDEX+7,\
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_IPXROUTER_SETWANGLOBALADDRESS CTL_CODE(FILE_DEVICE_IPXROUTER, \
+ IPXROUTER_IOCTL_INDEX+8,\
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_IPXROUTER_DELETEWANGLOBALADDRESS CTL_CODE(FILE_DEVICE_IPXROUTER, \
+ IPXROUTER_IOCTL_INDEX+9,\
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+
+//*** Nic Info Ioctl Data ***
+
+#define SHOW_NIC_LAN 0
+#define SHOW_NIC_WAN 1
+
+#define SHOW_NIC_CLOSED 0
+#define SHOW_NIC_CLOSING 1
+#define SHOW_NIC_ACTIVE 2
+#define SHOW_NIC_PENDING_OPEN 3
+
+typedef struct _SHOW_NIC_INFO {
+
+ USHORT NicId;
+ USHORT DeviceType;
+ USHORT NicState;
+ UCHAR Network[4];
+ UCHAR Node[6];
+ USHORT TickCount;
+ ULONG StatBadReceived;
+ ULONG StatRipReceived;
+ ULONG StatRipSent;
+ ULONG StatRoutedReceived;
+ ULONG StatRoutedSent;
+ ULONG StatType20Received;
+ ULONG StatType20Sent;
+ } SHOW_NIC_INFO, *PSHOW_NIC_INFO;
+
+//*** Memory Statistics Data ***
+
+typedef struct _SHOW_MEM_STAT {
+
+ ULONG PeakPktAllocCount;
+ ULONG CurrentPktAllocCount;
+ ULONG CurrentPktPoolCount;
+ ULONG PacketSize;
+ } SHOW_MEM_STAT, *PSHOW_MEM_STAT;
+
+//*** Wan Innactivity Data ***
+// For the first call the NicId is set to 0xffff. The router will associate
+// the remote node with a valid nic id, which will be used in subsequent calls.
+
+typedef struct _GET_WAN_INNACTIVITY {
+
+ USHORT NicId;
+ UCHAR RemoteNode[6];
+ ULONG WanInnactivityCount;
+ } GET_WAN_INNACTIVITY, *PGET_WAN_INNACTIVITY;
+
+//*** Wan Global Address Data ***
+
+#define ERROR_IPXCP_NETWORK_NUMBER_IN_USE 1
+#define ERROR_IPXCP_MEMORY_ALLOCATION_FAILURE 2
+
+typedef struct _SET_WAN_GLOBAL_ADDRESS {
+
+ UCHAR WanGlobalNetwork[4];
+ ULONG ErrorCode;
+ } SET_WAN_GLOBAL_ADDRESS, *PSET_WAN_GLOBAL_ADDRESS;
diff --git a/private/ntos/tdi/isn/rip/globals.c b/private/ntos/tdi/isn/rip/globals.c
new file mode 100644
index 000000000..8480f1073
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/globals.c
@@ -0,0 +1,86 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: globals.c
+//
+// Description: global configuration parameters and data structures
+//
+// Author: Stefan Solomon (stefans) October 4, 1993.
+//
+// Revision History:
+//
+//***
+
+#include "rtdefs.h"
+
+//*** Router Driver State ***
+
+// 1. Initialization Flag - no receives are accepted as long as the driver is
+// not initialized
+// FALSE - not initialized, TRUE - initialized
+
+BOOLEAN RouterInitialized = FALSE;
+
+// 2. Unloading Flag - indicates that driver unloading is taking place
+// FALSE - not unloading, TRUE - unloading
+
+BOOLEAN RouterUnloading = FALSE;
+
+//*** Router Type - LAN-WAN-LAN or Client/Server ***
+
+BOOLEAN LanWanLan = FALSE;
+
+//*** Enable LAN to LAN routing on the same machine ***
+// by default, this is disabled in the first RAS only version ***
+ULONG EnableLanRouting = 0;
+
+//*** some auxiliary data
+
+UCHAR nulladdress[] = {0, 0, 0, 0, 0, 0};
+UCHAR bcastaddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+//
+//*** Routing Table auxiliary structures ***
+//
+
+UINT SegmentCount; // nr of segments (hash buckets) of the RT
+PKSPIN_LOCK SegmentLocksTable; // points to the array of segment locks for RT
+
+// frame size
+ULONG MaxFrameSize = DEF_MAX_FRAME_SIZE;
+
+// MAC header needed
+ULONG MacHeaderNeeded = 40;
+
+// RIP requests/responses queue
+
+NDIS_SPIN_LOCK RipPktsListLock;
+LIST_ENTRY RipPktsList;
+
+// Propagated & net up bcast control structures
+
+NDIS_SPIN_LOCK PropagatedPktsListLock;
+LIST_ENTRY PropagatedPktsList;
+
+// this dpc initialized with the SendNext function
+KDPC PropagatedPktsDpc;
+BOOLEAN PropagatedPktsDpcQueued = FALSE;
+
+//*** Entry Points into the IPX stack ***
+
+IPX_INTERNAL_SEND IpxSendPacket;
+IPX_INTERNAL_GET_SEGMENT IpxGetSegment;
+IPX_INTERNAL_GET_ROUTE IpxGetRoute;
+IPX_INTERNAL_ADD_ROUTE IpxAddRoute;
+IPX_INTERNAL_DELETE_ROUTE IpxDeleteRoute;
+IPX_INTERNAL_GET_FIRST_ROUTE IpxGetFirstRoute;
+IPX_INTERNAL_GET_NEXT_ROUTE IpxGetNextRoute;
+//
+// [BUGBUGZZ] remove since NdisWan does it.
+//
+IPX_INTERNAL_INCREMENT_WAN_INACTIVITY IpxIncrementWanInactivity;
+IPX_INTERNAL_QUERY_WAN_INACTIVITY IpxGetWanInactivity;
+IPX_INTERNAL_TRANSFER_DATA IpxTransferData;
diff --git a/private/ntos/tdi/isn/rip/globals.h b/private/ntos/tdi/isn/rip/globals.h
new file mode 100644
index 000000000..8fc037708
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/globals.h
@@ -0,0 +1,369 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: globals.h
+//
+// Description: global routines and data structures
+//
+// Author: Stefan Solomon (stefans) October 18, 1993.
+//
+// Revision History:
+//
+//***
+
+//*** Router Driver State ***
+
+// 1. Initialization Flag
+// FALSE - not initialized, TRUE - initialized
+
+extern BOOLEAN RouterInitialized;
+
+// 2. Unloading Flag - indicates that driver unloading is taking place
+// FALSE - not unloading, TRUE - unloading
+
+extern BOOLEAN RouterUnloading;
+
+// Router Role - Total or partial connectivity
+
+extern BOOLEAN LanWanLan;
+
+// LAN routing on the same machine - disabled for RAS
+
+extern ULONG EnableLanRouting;
+
+// Netbios Routing enable/disable
+
+extern ULONG NetbiosRouting;
+
+// max nic count
+extern USHORT MaximumNicCount;
+
+//*** some auxiliary data
+
+extern UCHAR nulladdress[];
+extern UCHAR bcastaddress[];
+
+//
+//*** Routing Table auxiliary structures ***
+//
+
+extern UINT SegmentCount; // nr of segments (hash buckets) of the RT
+extern PKSPIN_LOCK SegmentLocksTable; // points to the array of segment locks for RT
+
+// frame size
+extern ULONG MaxFrameSize;
+
+// MAC header needed
+extern ULONG MacHeaderNeeded;
+
+
+// RIP requests/responses queue
+
+NDIS_SPIN_LOCK RipPktsListLock;
+LIST_ENTRY RipPktsList;
+
+// Propagated & net up bcast control structures
+
+extern NDIS_SPIN_LOCK PropagatedPktsListLock;
+extern LIST_ENTRY PropagatedPktsList;
+
+// this dpc initialized with the SendNext function
+extern KDPC PropagatedPktsDpc;
+extern BOOLEAN PropagatedPktsDpcQueued;
+
+// rcv pkt pool size as one of: small(1), medium(2), large(3). (config parameter)
+extern UINT RcvPktPoolSize;
+
+// the number of receive packets per pool segment (config parameter)
+extern UINT RcvPktsPerSegment;
+
+// memory statistics: peak allocation counter
+extern ULONG StatMemPeakCount;
+extern ULONG StatMemAllocCount;
+
+extern UINT RcvPktCount; // total pkts allocated for the
+
+// Max frame size as a multiple of ULONGs
+extern UINT UlongMaxFrameSize;
+
+//*** max send pkts queued limit: over this limit the send pkts get discarded
+extern ULONG MaxSendPktsQueued;
+
+//*** Entry Points into the IPX stack ***
+
+IPX_INTERNAL_SEND IpxSendPacket;
+IPX_INTERNAL_GET_SEGMENT IpxGetSegment;
+IPX_INTERNAL_GET_ROUTE IpxGetRoute;
+IPX_INTERNAL_ADD_ROUTE IpxAddRoute;
+IPX_INTERNAL_DELETE_ROUTE IpxDeleteRoute;
+IPX_INTERNAL_GET_FIRST_ROUTE IpxGetFirstRoute;
+IPX_INTERNAL_GET_NEXT_ROUTE IpxGetNextRoute;
+//
+// [BUGBUGZZ] remove since NdisWan does it.
+//
+IPX_INTERNAL_INCREMENT_WAN_INACTIVITY IpxIncrementWanInactivity;
+IPX_INTERNAL_QUERY_WAN_INACTIVITY IpxGetWanInactivity;
+IPX_INTERNAL_TRANSFER_DATA IpxTransferData;
+
+extern PNICCB *NicCbPtrTab;
+
+extern USHORT VirtualNicId;
+extern UCHAR VirtualNetwork[4];
+
+//*** Global Functions ***
+
+NTSTATUS
+BindToIpxDriver(PIPX_INTERNAL_BIND_RIP_OUTPUT *IpxBindBuffpp);
+
+VOID
+UnbindFromIpxDriver(VOID);
+
+NTSTATUS
+RouterInit(PIPX_INTERNAL_BIND_RIP_OUTPUT IpxBindBuffp);
+
+VOID
+InitRtTimer(VOID);
+
+VOID
+StartRtTimer(VOID);
+
+VOID
+StopRtTimer(VOID);
+
+UINT
+CreateRcvPktPool(VOID);
+
+VOID
+DestroyRcvPktPool(VOID);
+
+VOID
+RcvPktPoolScavenger(VOID);
+
+
+UINT
+CreateNicCbs(PIPX_INTERNAL_BIND_RIP_OUTPUT IpxBindBuffp);
+
+VOID
+DestroyNicCbs(VOID);
+
+PPACKET_TAG
+AllocateRcvPkt(PNICCB niccbp);
+
+VOID
+FreeRcvPkt(PPACKET_TAG pktp);
+
+NTSTATUS
+RouterStart(VOID);
+
+BOOLEAN
+RtReceive (
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN ULONG FwdAdapterCtx,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize,
+ IN PMDL pMdl
+);
+
+VOID
+RtReceiveComplete (
+ IN USHORT NicId
+);
+
+VOID
+RtStatus (
+ IN USHORT NicId,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength
+);
+
+VOID
+RtSendComplete (
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+);
+
+VOID
+RtTransferDataComplete (
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+);
+
+VOID
+RtFindRouteComplete (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute
+);
+
+VOID
+RtLineUp (
+ IN USHORT NicId,
+ IN PIPX_LINE_INFO LineInfo,
+ IN NDIS_MEDIUM DeviceType,
+ IN PVOID ConfigurationData
+);
+
+VOID
+RtLineDown (
+ IN USHORT NicId,
+ IN ULONG FwdAdapterCtx
+);
+
+VOID
+RtScheduleRoute (
+ IN PIPX_ROUTE_ENTRY RouteEntry
+);
+
+VOID
+ProcessNbPacket(PPACKET_TAG pktp);
+
+VOID
+ProcessRipPacket(PPACKET_TAG pktp);
+
+VOID
+RoutePacket(PPACKET_TAG pktp);
+
+VOID
+SendPacket(PPACKET_TAG pktp);
+
+VOID
+InitRipSndDispatcher(VOID);
+
+VOID
+InitRipSndAtNic(PNICCB niccbp);
+
+VOID
+RipDispatchSndReq(PRIP_SNDREQ sndreqp);
+
+BOOLEAN
+RipQueueSndReqAtNic(PNICCB niccbp,
+ PRIP_SNDREQ sndreqp);
+
+VOID
+SendRipPktCompleted(PPACKET_TAG pktp);
+
+PIPX_ROUTE_ENTRY
+GetRoute(UINT segment,
+ BOOLEAN FirstRoute);
+
+VOID
+SetNetworkEntry(PUCHAR nep,
+ PIPX_ROUTE_ENTRY rtep);
+
+VOID
+InitRipTimer(VOID);
+
+VOID
+RipTimer(VOID);
+
+VOID
+EnableRcvPktAllocation(PNICCB niccbp,
+ BOOLEAN enab_mode);
+
+BOOLEAN
+IsRipSndResourceFree(PNICCB niccbp);
+
+BOOLEAN
+IsRcvPktResourceFree(PNICCB niccbp);
+
+VOID
+RipSendAtNicCompleted(PRIP_SNDREQ sndreqp);
+
+NIC_OPEN_STATUS
+NicOpen(PNICCB niccbp);
+
+NIC_CLOSE_STATUS
+NicClose(PNICCB niccbp,
+ USHORT CloseCompletionOption);
+
+UINT
+AddRouteToBcastSndReq(PLIST_ENTRY nodelistp,
+ PIPX_ROUTE_ENTRY rtep);
+
+PRIP_SNDREQ
+GetBcastSndReq(PLIST_ENTRY nodelistp,
+ PUSHORT NicIdp);
+
+VOID
+RouterStop(VOID);
+
+VOID
+StopRipTimer();
+
+NIC_RESOURCES_STATUS
+NicFreeResources(PNICCB niccbp);
+
+VOID
+BroadcastRipUpdate(PRIP_SNDREQ sndreqp, // send request
+ PNICCB niccbp, // do not send on this nic
+ PKEVENT eventp); // wait if this event is not NULL
+VOID
+BroadcastRipGeneralResponse(PRIP_SNDREQ sndreqp);
+
+VOID
+NicCloseComplete(PNICCB niccbp);
+
+USHORT
+tickcount(UINT linkspeed);
+
+VOID
+WanGenRequestTimeout(PKDPC Dpc,
+ PVOID DefferedContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2);
+
+
+BOOLEAN
+IsNetInNbPacket(PPACKET_TAG pktp,
+ PNICCB niccbp);
+VOID
+SendPropagatedPacket(PPACKET_TAG pktp);
+
+VOID
+SendNextPropagatedPkt(PKDPC Dpc,
+ PVOID DefferedContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2);
+
+VOID
+ZeroNicStatistics(PNICCB niccbp);
+
+VOID
+InitWanNodeHT(VOID);
+
+PNICCB
+GetWanNodeNiccbp(PUCHAR nodep);
+
+VOID
+AddWanNodeToHT(PNICCB niccbp);
+
+VOID
+RemoveWanNodeFromHT(PNICCB niccbp);
+
+extern BOOLEAN WanGlobalNetworkEnabled;
+extern UCHAR WanGlobalNetwork[];
+
+VOID
+InitNetbiosRoutingFilter(VOID);
+
+BOOLEAN
+IsNetbiosRoutingAllowed(PNICCB srcniccbp,
+ PNICCB dstniccbp);
+
+
+VOID
+BroadcastWanNetUpdate(PIPX_ROUTE_ENTRY rtep, // route entry to bcast
+ PNICCB niccbp, // do not send on this nic
+ PKEVENT eventp); // synch event
+
+VOID
+SendGenRequestOnWanClient(VOID);
diff --git a/private/ntos/tdi/isn/rip/init.c b/private/ntos/tdi/isn/rip/init.c
new file mode 100644
index 000000000..a5a4cb5b8
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/init.c
@@ -0,0 +1,174 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: init.c
+//
+// Description: initialize global data structures
+//
+// Author: Stefan Solomon (stefans) October 5, 1993.
+//
+// Revision History:
+//
+//***
+
+#include "rtdefs.h"
+
+
+//***
+//
+// Function: RouterInit
+//
+// Descr: Initializes global data structures
+//
+// Parameters: IpxBindBuffp - pointer to the ipx module bind output buffer
+//
+// Returns: STATUS_SUCCESS
+// STATUS_INSUFFICIENT_RESOURCES
+//
+//***
+
+NTSTATUS
+RouterInit(PIPX_INTERNAL_BIND_RIP_OUTPUT IpxBindBuffp)
+{
+ int i;
+ PIPX_NIC_DATA NicDatap;
+ UINT MaxLanFrameSize;
+ BOOLEAN NicCbManInitialized = FALSE;
+ BOOLEAN RcvPktManInitialized = FALSE;
+ BOOLEAN RipResponseManInitialized = FALSE;
+
+
+ //*** Initialize NicCBs ***
+
+ if(CreateNicCbs(IpxBindBuffp)) {
+
+ goto cleanup;
+ }
+
+ NicCbManInitialized = TRUE;
+
+ // Initialize the table of handlers into the IPX driver
+
+ IpxSendPacket = IpxBindBuffp->SendHandler;
+ IpxGetSegment = IpxBindBuffp->GetSegmentHandler;
+ IpxGetRoute = IpxBindBuffp->GetRouteHandler;
+ IpxAddRoute = IpxBindBuffp->AddRouteHandler;
+ IpxDeleteRoute = IpxBindBuffp->DeleteRouteHandler;
+ IpxGetFirstRoute = IpxBindBuffp->GetFirstRouteHandler;
+ IpxGetNextRoute = IpxBindBuffp->GetNextRouteHandler;
+
+ //
+ // [BUGBUGZZ] remove since NdisWan does it.
+ //
+ IpxIncrementWanInactivity = IpxBindBuffp->IncrementWanInactivityHandler;
+ IpxGetWanInactivity = IpxBindBuffp->QueryWanInactivityHandler;
+ IpxTransferData = IpxBindBuffp->TransferDataHandler;
+
+ // Initialize the Routing Table Auxiliary Structures
+
+ SegmentCount = IpxBindBuffp->SegmentCount;
+ SegmentLocksTable = IpxBindBuffp->SegmentLocks;
+
+ // get the MAC header needed by the IPX module
+ MacHeaderNeeded = IpxBindBuffp->MacHeaderNeeded;
+
+ // try to determine the MaxLanFrameSize
+ MaxLanFrameSize = 0;
+
+ for(i=0, NicDatap = IpxBindBuffp->NicInfoBuffer.NicData;
+ i<IpxBindBuffp->NicInfoBuffer.NicCount;
+ i++, NicDatap++) {
+
+ if((NicDatap->DeviceType != NdisMediumWan) &&
+ (NicDatap->LineInfo.MaximumPacketSize > MaxLanFrameSize)) {
+
+ MaxLanFrameSize = NicDatap->LineInfo.MaximumPacketSize;
+ }
+ }
+
+ if(MaxLanFrameSize) {
+
+ MaxFrameSize = MaxLanFrameSize;
+ }
+ else
+ {
+ RtPrint(DBG_INIT, ("IpxRouter: RouterInit: There are no LAN devices configured !\n"));
+ }
+
+ //*** Initialize the Rcv Pkt Manager ***
+
+ if(CreateRcvPktPool()) {
+
+ goto cleanup;
+ }
+
+ RcvPktManInitialized = TRUE;
+
+ //*** Initialize the Netbios Bcast Control Structures ***
+
+ INITIALIZE_SPIN_LOCK(&PropagatedPktsListLock);
+ InitializeListHead(&PropagatedPktsList);
+ KeInitializeDpc(&PropagatedPktsDpc, SendNextPropagatedPkt, NULL);
+ InitNetbiosRoutingFilter();
+
+ //*** Initialize the RIP requests/responses queue ***
+
+ INITIALIZE_SPIN_LOCK(&RipPktsListLock);
+ InitializeListHead(&RipPktsList);
+
+ //*** Initialize the RIP Response Manager ***
+
+ InitRipSndDispatcher();
+
+ //*** Initialize the Wan Nodes Hash Table ***
+
+ InitWanNodeHT();
+
+ // all done, free the bind output buffer
+ ExFreePool((PVOID)IpxBindBuffp);
+
+ // initialize the global timer
+ InitRtTimer();
+
+ // open all the configured nics
+ for(i=0; i<MaximumNicCount; i++) {
+
+ if(NicCbPtrTab[i]->NicState == NIC_PENDING_OPEN) {
+
+ NicOpen(NicCbPtrTab[i]);
+ }
+ }
+
+ return STATUS_SUCCESS;
+
+cleanup:
+
+ // free all the nonpaged pool memory allocated up to this point
+
+ if(NicCbManInitialized) {
+
+ DestroyNicCbs();
+ }
+
+ if(RcvPktManInitialized) {
+
+ DestroyRcvPktPool();
+ }
+
+ if(RipResponseManInitialized) {
+
+/*** !!! taken out temporarily
+
+ DestroyRipResponseMan();
+
+***/
+ }
+
+ // all cleaned up, free the bind output buffer
+ ExFreePool(IpxBindBuffp);
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+}
diff --git a/private/ntos/tdi/isn/rip/ipxbind.c b/private/ntos/tdi/isn/rip/ipxbind.c
new file mode 100644
index 000000000..e4da3867e
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/ipxbind.c
@@ -0,0 +1,191 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: ipxbind.c
+//
+// Description: binding to the IPX driver
+//
+// Author: Stefan Solomon (stefans) October 18, 1993.
+//
+// Revision History:
+//
+//***
+
+#include <ntos.h>
+#include "rtdefs.h"
+
+NTSTATUS
+ReadIpxDeviceName(VOID);
+
+ULONG
+IsWanGlobalNetRequested(VOID);
+
+// global handle of the IPX driver
+HANDLE FileHandle;
+
+UNICODE_STRING UnicodeFileName;
+PWSTR FileNamep;
+
+NTSTATUS
+BindToIpxDriver(PIPX_INTERNAL_BIND_RIP_OUTPUT *IpxBindBuffpp)
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatusBlock;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PUCHAR bufferp;
+ UINT outbuflen, inbuflen;
+ PIPX_INTERNAL_BIND_INPUT bip;
+
+ // Read Ipx exported device name from the registry
+ ReadIpxDeviceName();
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &UnicodeFileName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+ Status = NtCreateFile(
+ &FileHandle,
+ SYNCHRONIZE | GENERIC_READ,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0L
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ RtPrint(DBG_INIT, ("IpxRouter: Open of the IPX driver failed with %lx\n", Status));
+ return Status;
+ }
+
+ RtPrint(DBG_INIT, ("IpxRouter: Open of the IPX driver was successful!\n"));
+
+ // First, send a IOCTL to find out how much data we need to allocate
+ inbuflen = sizeof(IPX_INTERNAL_BIND_INPUT);
+ if((bip = ExAllocatePool(PagedPool, inbuflen)) == NULL) {
+
+ NtClose(FileHandle);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // fill in our bind data
+ bip->Version = 1;
+ bip->Identifier = IDENTIFIER_RIP;
+ bip->BroadcastEnable = TRUE;
+ bip->LookaheadRequired = IPXH_HDRSIZE;
+ bip->ProtocolOptions = 0;
+ bip->ReceiveHandler = RtReceive;
+ bip->ReceiveCompleteHandler = RtReceiveComplete;
+ bip->StatusHandler = RtStatus;
+ bip->SendCompleteHandler = RtSendComplete;
+ bip->TransferDataCompleteHandler = RtTransferDataComplete;
+ bip->FindRouteCompleteHandler = RtFindRouteComplete;
+ bip->LineUpHandler = RtLineUp;
+ bip->LineDownHandler = RtLineDown;
+ bip->ScheduleRouteHandler = RtScheduleRoute;
+
+ if(IsWanGlobalNetRequested()) {
+
+ bip->RipParameters = IPX_RIP_PARAM_GLOBAL_NETWORK;
+ }
+ else
+ {
+ bip->RipParameters = 0;
+ }
+
+ Status = NtDeviceIoControlFile(
+ FileHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPX_INTERNAL_BIND, // IoControlCode
+ bip, // Input Buffer
+ inbuflen, // Input Buffer Length
+ NULL, // Output Buffer
+ 0); // Output Buffer Length
+
+
+ if (Status == STATUS_PENDING) {
+ Status=NtWaitForSingleObject(
+ FileHandle,
+ (BOOLEAN)FALSE,
+ NULL);
+ }
+
+ if (Status != STATUS_BUFFER_TOO_SMALL) {
+
+ RtPrint(DBG_INIT, ("IpxRouter: Ioctl to the IPX driver failed with %lx\n", Status));
+
+ ExFreePool(bip);
+ NtClose(FileHandle);
+ return STATUS_INVALID_PARAMETER;
+ }
+ outbuflen = IoStatusBlock.Information;
+
+ if((bufferp = ExAllocatePool(PagedPool, outbuflen)) == NULL) {
+
+ ExFreePool(bip);
+ NtClose(FileHandle);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ Status = NtDeviceIoControlFile(
+ FileHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPX_INTERNAL_BIND, // IoControlCode
+ bip, // Input Buffer
+ inbuflen, // Input Buffer Length
+ bufferp, // Output Buffer
+ outbuflen); // Output Buffer Length
+
+
+ if (Status == STATUS_PENDING) {
+ Status=NtWaitForSingleObject(
+ FileHandle,
+ (BOOLEAN)FALSE,
+ NULL);
+ }
+
+ if (Status != STATUS_SUCCESS) {
+
+ RtPrint(DBG_INIT, ("IpxRouter: Ioctl to the IPX driver failed with %lx\n", IoStatusBlock.Status));
+
+ ExFreePool(bip);
+ ExFreePool(bufferp);
+ NtClose(FileHandle);
+ return Status;
+ }
+
+ RtPrint(DBG_INIT, ("IpxRouter: Succesfuly bound to the IPX driver\n"));
+
+ ExFreePool(bip);
+
+ *IpxBindBuffpp = (PIPX_INTERNAL_BIND_RIP_OUTPUT)bufferp;
+
+ return Status;
+}
+
+
+VOID
+UnbindFromIpxDriver(VOID)
+{
+ NtClose(FileHandle);
+ ExFreePool(FileNamep);
+}
diff --git a/private/ntos/tdi/isn/rip/lineind.c b/private/ntos/tdi/isn/rip/lineind.c
new file mode 100644
index 000000000..079a98463
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/lineind.c
@@ -0,0 +1,430 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: lineind.c
+//
+// Description: WAN connection/disconection routines
+//
+// Author: Stefan Solomon (stefans) November 20, 1993.
+//
+// Revision History:
+//
+//***
+
+#include "rtdefs.h"
+
+BOOLEAN WanGlobalNetworkEnabled = FALSE;// this is set to TRUE if the router has been
+ // configured to assign the same global address
+ // to all wan clients
+UCHAR WanGlobalNetwork[4];
+
+
+VOID
+SendWanGenRequest(PNICCB niccbp);
+
+VOID
+StartWanGenRequestTimer(PNICCB niccbp);
+
+//***
+//
+// Function: RtLineUp
+//
+// Descr: Called when a new WAN connection has been established
+//
+//***
+
+VOID
+RtLineUp (
+ IN USHORT NicId,
+ IN PIPX_LINE_INFO LineInfo,
+ IN NDIS_MEDIUM DeviceType,
+ IN PVOID ConfigurationData)
+{
+ PNICCB niccbp;
+ PIPX_ROUTE_ENTRY rtep, oldrtep;
+ PIPXCP_CONFIGURATION configp;
+ UINT segment;
+ KIRQL oldirql;
+
+ RtPrint(DBG_LINE, ("IpxRouter: RtLineUp: Entered on NicId %d\n", NicId));
+
+ configp = (PIPXCP_CONFIGURATION)ConfigurationData;
+ niccbp = NicCbPtrTab[NicId];
+
+ //*** If the NIC is active, this is just an update. Ignore it for the
+ // moment
+
+ if(niccbp->NicState != NIC_CLOSED) {
+
+ return;
+ }
+
+ //
+ //*** set up the NIC Control Block with the configuration information ***
+ //
+
+ memcpy(niccbp->Network, configp->Network, 4);
+ memcpy(niccbp->Node, configp->LocalNode, 6);
+ memcpy(niccbp->RemoteNode, configp->RemoteNode, 6);
+
+ // set the role of this node in this wan connection
+ if(configp->ConnectionClient) {
+
+ niccbp->WanConnectionClient = TRUE;
+ }
+ else
+ {
+ niccbp->WanConnectionClient = FALSE;
+ }
+
+ niccbp->LinkSpeed = LineInfo->LinkSpeed;
+ niccbp->TickCount = tickcount(niccbp->LinkSpeed);
+ niccbp->MaximumPacketSize = LineInfo->MaximumPacketSize;
+ niccbp->MacOptions = LineInfo->MacOptions;
+ niccbp->DeviceType = DeviceType;
+
+ // reset statistics counters
+ ZeroNicStatistics(niccbp);
+
+ // try 3 times to get the other end's routes
+ niccbp->WanGenRequestCount = 3;
+
+ // now, try to open the nic
+ if(NicOpen(niccbp) != NIC_OPEN_SUCCESS) {
+
+ // !!!
+ return;
+ }
+
+ //
+ //*** check if we have a global wan route ***
+ //
+ if((WanGlobalNetworkEnabled) &&
+ (!niccbp->WanConnectionClient)) {
+
+ //
+ //*** There is a global WAN route AND this is a "server" node ***
+ //*** Add the remote "client" node to the WAN Nodes Hash Table ***
+ //
+
+ AddWanNodeToHT(niccbp);
+ }
+ else
+ {
+ //
+ //*** There is no global WAN route OR this is a "client" node ***
+ //*** Add a new entry in the routing table for the local WAN net ***
+ //
+
+ if((rtep = ExAllocatePool(NonPagedPool, sizeof(IPX_ROUTE_ENTRY))) == NULL) {
+
+ // can't allocate the route entry -> close the nic and return
+ NicClose(niccbp, 0);
+ return;
+ }
+
+ segment = IpxGetSegment(niccbp->Network);
+
+ // LOCK THE ROUTING TABLE
+ ExAcquireSpinLock(&SegmentLocksTable[segment], &oldirql);
+
+ // Clean-up any old propagated route with the same net address
+ // At this point, we do not worry about alternate routes, cause we do
+ // not add alternate routes in the routing table yet.
+ if((oldrtep = IpxGetRoute(segment, niccbp->Network)) != NULL) {
+
+ RtPrint(DBG_LINE, ("IpxRouter: RtLineUp: Deleting old route for net %x-%x-%x-%x on NicId %d\n",
+ niccbp->Network[0],
+ niccbp->Network[1],
+ niccbp->Network[2],
+ niccbp->Network[3],
+ oldrtep->NicId));
+
+ IpxDeleteRoute(segment, oldrtep);
+ ExFreePool(oldrtep);
+ }
+
+ // set up the new route entry
+ memcpy(rtep->Network, niccbp->Network, IPX_NET_LEN);
+ rtep->NicId = niccbp->NicId;
+ memcpy(rtep->NextRouter, niccbp->Node, IPX_NODE_LEN);
+ rtep->Flags = IPX_ROUTER_LOCAL_NET;
+ rtep->Timer = 0; // TTL of this route entry is 3 min
+ rtep->Segment = segment;
+ rtep->TickCount = niccbp->TickCount;
+ rtep->HopCount = 1;
+
+ InitializeListHead(&rtep->AlternateRoute);
+
+ RtPrint(DBG_LINE, ("IpxRouter: RtLineUp: Adding new route for net %x-%x-%x-%x on NicId %d\n",
+ niccbp->Network[0],
+ niccbp->Network[1],
+ niccbp->Network[2],
+ niccbp->Network[3],
+ niccbp->NicId));
+
+ IpxAddRoute(segment, rtep);
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
+
+ // Broadcast the new route entry on all the LAN segments
+ BroadcastWanNetUpdate(rtep, niccbp, NULL);
+ }
+
+ //
+ //*** Get the WAN peer's routing table info. ***
+ //
+
+ // Send a general request on this net and then send more general requests
+ // with a timer.
+
+ ACQUIRE_SPIN_LOCK(&niccbp->NicLock);
+
+ if(niccbp->NicState != NIC_ACTIVE) {
+
+ // nic has been closed while we were opening; reset the counter
+ // to show to the closing timer that the wan request timer will not
+ // get scheduled.
+ niccbp->WanGenRequestCount = 0;
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+ return;
+ }
+
+ --niccbp->WanGenRequestCount;
+
+ if(niccbp->WanGenRequestCount) {
+
+ // we have at least one more request to send beside the one we are
+ // sending now -> start the timer
+ StartWanGenRequestTimer(niccbp);
+ }
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+
+ SendWanGenRequest(niccbp);
+}
+
+//***
+//
+// Function: RtLineDown
+//
+// Descr: Called when a WAN line has been disconnected
+//
+//***
+
+VOID
+RtLineDown (IN USHORT NicId, IN ULONG FwdAdapterCtx)
+{
+ LIST_ENTRY DownRoutesList;
+ UINT seg;
+ BOOLEAN FirstRoute;
+ KIRQL oldirql;
+ PIPX_ROUTE_ENTRY rtep;
+ PRIP_SNDREQ sndreqp;
+ PNICCB niccbp;
+ USHORT DownNicId;
+
+ RtPrint(DBG_LINE, ("IpxRouter: RtLineDown: Entered for NicId %d\n", NicId));
+
+
+ // get the nic ptr for this snd req
+ niccbp = NicCbPtrTab[NicId];
+
+ if (niccbp->NicState!=NIC_ACTIVE) {
+ RtPrint (DBG_LINE, ("IpxRouter: NicId %d is already inactive\n", NicId));
+ return;
+ }
+ // scan the routing table and delete all the routing table entries
+ // visible through this nic.
+ InitializeListHead(&DownRoutesList);
+
+ for(seg=0; seg<SegmentCount; seg++) {
+
+ FirstRoute = TRUE;
+
+ // LOCK THE ROUTING TABLE
+ ExAcquireSpinLock(&SegmentLocksTable[seg], &oldirql);
+
+ while((rtep = GetRoute(seg, FirstRoute)) != NULL) {
+
+ FirstRoute = FALSE;
+
+ // if this is the global wan route, skip it
+ if(rtep->Flags & IPX_ROUTER_GLOBAL_WAN_NET) {
+
+ // skip it!
+ continue;
+ }
+
+ // check if this route entry is based on the nic going down
+ if(rtep->NicId == NicId) {
+
+ IpxDeleteRoute(seg, rtep);
+
+ // mark it as down
+ rtep->HopCount = 16;
+
+ // add the route to the packets we prepare for bcast
+ AddRouteToBcastSndReq(&DownRoutesList, rtep);
+
+ // finally, free the route entry
+ ExFreePool(rtep);
+ }
+ }
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[seg], oldirql);
+
+ } // for all segments
+
+ // broadcast all the deleted routes
+ if((sndreqp = GetBcastSndReq(&DownRoutesList, &DownNicId)) != NULL) {
+
+ // set up the request to send a bcast response with the changes
+ // to all the nics except this one
+ BroadcastRipUpdate(sndreqp, niccbp, NULL);
+ }
+
+ //
+ //*** If this is a "server" node and global WAN net if it has a global Wan net
+ //*** for remote clients, remove the client node form the wan nodes hash table
+ //
+ if((WanGlobalNetworkEnabled) &&
+ (!niccbp->WanConnectionClient)) {
+
+ //
+ //*** There is a global WAN route AND this is a "server" node ***
+ //*** Add the remote "client" node to the WAN Nodes Hash Table ***
+ //
+
+ RemoveWanNodeFromHT(niccbp);
+ }
+
+ // finally, close the nic
+ NicClose(niccbp, 0);
+
+ return;
+}
+
+
+VOID
+SendWanGenRequest(PNICCB niccbp)
+{
+ PRIP_SNDREQ sndrqp;
+
+ if((sndrqp = ExAllocatePool(NonPagedPool, sizeof(RIP_SNDREQ))) == NULL) {
+
+ return;
+ }
+
+ sndrqp->SndReqId = RIP_GEN_REQUEST;
+ sndrqp->SendOnAllNics = FALSE; // send to this nic only
+ memcpy(sndrqp->DestNode, bcastaddress, IPX_NODE_LEN);
+ sndrqp->DestSock = IPX_RIP_SOCKET;
+ sndrqp->DoNotSendNicCbp = NULL; // do no except any nic
+ sndrqp->SenderNicCbp = niccbp;
+ sndrqp->SndCompleteEventp = NULL;
+
+ RipQueueSndReqAtNic(niccbp, sndrqp);
+}
+
+
+VOID
+WanGenRequestTimeout(PKDPC Dpc,
+ PVOID DefferedContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2)
+{
+ PNICCB niccbp;
+
+ niccbp = (PNICCB)DefferedContext;
+
+
+ ACQUIRE_SPIN_LOCK(&niccbp->NicLock);
+
+ if(niccbp->NicState != NIC_ACTIVE) {
+
+ // reset the request counter to show that we won't reschedule
+ // the timer
+ niccbp->WanGenRequestCount = 0;
+
+ RtPrint(DBG_LINE, ("IpxRouter: WanGenRequestTimeout: closing done on NicId %d\n", niccbp->NicId));
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+ return;
+ }
+
+ --niccbp->WanGenRequestCount;
+
+ RtPrint(DBG_LINE, ("IpxRouter: WanGenRequestTimeout: sending gen req on NicId %d remaining %d\n", niccbp->NicId, niccbp->WanGenRequestCount));
+
+ if(niccbp->WanGenRequestCount) {
+
+ StartWanGenRequestTimer(niccbp);
+ }
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+
+ SendWanGenRequest(niccbp);
+}
+
+//***
+//
+// Function: StartWanGenRequestTimer
+//
+// Descr: Starts the timer for 2 sec at this Nic Cb
+//
+// Params: pointer to Nic Cb
+//
+// Returns: none
+//
+//***
+
+VOID
+StartWanGenRequestTimer(PNICCB niccbp)
+{
+ LARGE_INTEGER timeout;
+
+ timeout.LowPart = (ULONG)(-4000 * 10000L); // 4 sec
+ timeout.HighPart = -1;
+
+ KeSetTimer(&niccbp->WanGenRequestTimer, timeout, &niccbp->WanGenRequestDpc);
+}
+
+//***
+//
+// Function: SendGenRequestOnWanClient
+//
+// Descr: Sends periodical gen requests on the WAN client to get the
+// remote router's updates
+//
+//***
+
+VOID
+SendGenRequestOnWanClient(VOID)
+{
+ PNICCB niccbp;
+ USHORT i;
+
+ // scan all nics to find the wan client nic active (if any)
+ for(i=0; i<MaximumNicCount; i++) {
+
+ niccbp = NicCbPtrTab[i];
+
+ if((niccbp->NicState == NIC_ACTIVE) &&
+ (niccbp->DeviceType == NdisMediumWan) &&
+ (niccbp->WanConnectionClient)) {
+
+ // send a RIP General Request on this NIC
+ // There is only one client NIC (or none) per router
+ SendWanGenRequest(niccbp);
+
+ return;
+ }
+ }
+}
diff --git a/private/ntos/tdi/isn/rip/mp/makefile b/private/ntos/tdi/isn/rip/mp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/mp/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isn/rip/mp/sources b/private/ntos/tdi/isn/rip/mp/sources
new file mode 100644
index 000000000..dc48d81bb
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/mp/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+NT_UP=0
+
+TARGETPATH=\nt\public\sdk\lib
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/isn/rip/nbproc.c b/private/ntos/tdi/isn/rip/nbproc.c
new file mode 100644
index 000000000..50b6e1d58
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/nbproc.c
@@ -0,0 +1,38 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: nbproc.c
+//
+// Description: process netbios propagated packets
+//
+// Author: Stefan Solomon (stefans) October 11, 1993.
+//
+// Revision History:
+//
+//***
+
+#include "rtdefs.h"
+
+//***
+//
+// Function: ProcessNbPacket
+//
+// Descr:
+//
+// Params: Packet
+//
+// Returns: none
+//
+//***
+
+VOID
+ProcessNbPacket(PPACKET_TAG rcvpktp)
+{
+ // STUB !!!
+ FreeRcvPkt(rcvpktp);
+
+ return;
+}
diff --git a/private/ntos/tdi/isn/rip/netbios.c b/private/ntos/tdi/isn/rip/netbios.c
new file mode 100644
index 000000000..0664164e8
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/netbios.c
@@ -0,0 +1,155 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: netbios.c
+//
+// Description: process netbios broadcast packets
+//
+// Author: Stefan Solomon (stefans) December 16, 1993.
+//
+// Revision History:
+//
+//***
+
+#include "rtdefs.h"
+
+ULONG NetbiosRouting = 0; //enable netbios routing
+
+VOID
+ProcessNbPacket(PPACKET_TAG pktp)
+{
+ UCHAR rtcount;
+ PUCHAR hdrp;
+ PNICCB niccbp;
+
+ if(!NetbiosRouting) {
+
+ // discard
+ FreeRcvPkt(pktp);
+ return;
+ }
+
+ // get a pointer to the IPX header
+ hdrp = pktp->DataBufferp;
+
+ // get a pointer to the packet owner NicCb
+ niccbp = pktp->PacketOwnerNicCbp;
+
+ RtPrint(DBG_NETBIOS, ("IpxRouter: ProcessNbPacket: recvd pkt 0x%x on Nic %d\n", pktp, niccbp->NicId));
+
+ // get the number of routers this packet has crossed
+ rtcount = *(hdrp + IPXH_XPORTCTL);
+
+ // check that this is a netbios bcast packet and didnt exceed the limit of
+ // routers to traverse
+ if(memcmp(hdrp + IPXH_DESTNODE, bcastaddress, 6) ||
+ (rtcount >= 8)) {
+
+ // discard
+ FreeRcvPkt(pktp);
+ return;
+ }
+
+ // check if the packet has been sent more then once on this net
+ if(IsNetInNbPacket(pktp, niccbp)) {
+
+ // discard
+ FreeRcvPkt(pktp);
+ return;
+ }
+
+ // the packet will be broadcasted on all the nets that are LAN and are NOT
+ // included in the Network Number fields.
+
+ memcpy(hdrp + IPXH_HDRSIZE + 4 * rtcount,
+ niccbp->Network,
+ IPX_NET_LEN);
+
+ (*(hdrp + IPXH_XPORTCTL))++;
+
+ // set the destination network in the packet to 0
+ memcpy(hdrp + IPXH_DESTNET, nulladdress, 4);
+
+ SendPropagatedPacket(pktp);
+}
+
+
+BOOLEAN
+IsNetInNbPacket(PPACKET_TAG pktp,
+ PNICCB niccbp)
+{
+ UCHAR rtcount, i;
+ PUCHAR hdrp;
+
+ // get a pointer to the IPX header
+ hdrp = pktp->DataBufferp;
+
+ // get the number of routers this packet has crossed
+ rtcount = *(hdrp + IPXH_XPORTCTL);
+
+ for(i=0; i<rtcount; i++) {
+
+ if(!(memcmp(hdrp + IPXH_HDRSIZE + 4 * i,
+ niccbp->Network,
+ IPX_NET_LEN))) {
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+// Filter array for netbios routing. The first index is the source, the
+// second is the destination. The convention is 0 is LAN and 1 is WAN.
+BOOLEAN NetbiosRoutingFilter[2][2] = { FALSE, FALSE, FALSE, FALSE };
+
+VOID
+InitNetbiosRoutingFilter(VOID)
+{
+ if(NetbiosRouting & NETBIOS_ROUTING_LAN_TO_LAN) {
+
+ NetbiosRoutingFilter[0][0] = TRUE;
+ }
+
+ if(NetbiosRouting & NETBIOS_ROUTING_WAN_TO_LAN) {
+
+ NetbiosRoutingFilter[1][0] = TRUE;
+ }
+
+ if(NetbiosRouting & NETBIOS_ROUTING_LAN_TO_WAN) {
+
+ NetbiosRoutingFilter[0][1] = TRUE;
+ }
+}
+
+//***
+//
+// Function: IsNetbiosRoutingAllowed
+//
+// Descr: Returns the value in the NetbiosRoutingFilter array corresponding
+// to the src and dest device types
+//***
+
+BOOLEAN
+IsNetbiosRoutingAllowed(PNICCB srcniccbp,
+ PNICCB dstniccbp)
+{
+ USHORT dst = 0, src = 0;
+
+ if(srcniccbp->DeviceType == NdisMediumWan) {
+
+ src = 1;
+ }
+
+ if(dstniccbp->DeviceType == NdisMediumWan) {
+
+ dst = 1;
+ }
+
+ return NetbiosRoutingFilter[src][dst];
+}
diff --git a/private/ntos/tdi/isn/rip/nicman.c b/private/ntos/tdi/isn/rip/nicman.c
new file mode 100644
index 000000000..424351f2a
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/nicman.c
@@ -0,0 +1,640 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: nicman.c
+//
+// Description: NicCb management routines
+//
+// Author: Stefan Solomon (stefans) October 7, 1993.
+//
+// Revision History:
+//
+//***
+
+#include "rtdefs.h"
+
+// counters
+
+USHORT MaximumNicCount; // total number of Nics possble
+
+// array of pointers to NicCb indexed by the NicId
+PNICCB *NicCbPtrTab;
+
+PNICCB NicCbArray;
+
+VOID
+ConfigureNicCb(PNICCB niccbp,
+ PIPX_NIC_DATA nicdatp);
+
+USHORT VirtualNicId;
+UCHAR VirtualNetwork[4];
+
+VOID
+StartNicCloseTimer(PNICCB niccbp);
+
+VOID
+NicCloseTimeout(PKDPC Dpc,
+ PVOID DefferedContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2);
+
+
+
+//***
+//
+// Function: CreateNicCbs
+//
+// Descr: creates the NicCbs structures and queues them in their respective
+// lists
+//
+// Params: none
+//
+// Returns: 0 - success, 1 - failure
+//
+//***
+
+UINT
+CreateNicCbs(PIPX_INTERNAL_BIND_RIP_OUTPUT IpxBindBuffp)
+{
+ ULONG tablen, arraylen;
+ PNICCB niccbp;
+ PIPX_NIC_DATA nicdatp;
+ UINT LanNicsCount = 0;
+ UINT WanNicsCount = 0;
+ USHORT ConfiguredNicCount;
+ USHORT i;
+
+ RtPrint(DBG_INIT, ("IpxRouter: CreateNicCbs: Entered\n"));
+
+ MaximumNicCount = IpxBindBuffp->MaximumNicCount;
+ ConfiguredNicCount = IpxBindBuffp->NicInfoBuffer.NicCount;
+
+ RtPrint(DBG_INIT, ("IpxRouter: Max Nics Count = %d, Configured Nics Count = %d\n",
+ MaximumNicCount, ConfiguredNicCount));
+
+ ASSERT(ConfiguredNicCount <= MaximumNicCount);
+
+ // allocate the NicCbs Ptrs and NicCbs structures tables
+ tablen = sizeof(PNICCB) * MaximumNicCount;
+
+ if((NicCbPtrTab = (PNICCB *)CTEAllocMem(tablen)) == NULL) {
+
+ // memory allocation failure, abort all
+ return 1;
+ }
+
+ // zero the tables
+ RtlZeroMemory(NicCbPtrTab, tablen);
+
+ arraylen = sizeof(NICCB) * MaximumNicCount;
+
+ if((NicCbArray = (PNICCB)CTEAllocMem(arraylen)) == NULL) {
+
+ // memory allocation failure, abort all
+ CTEFreeMem(NicCbPtrTab);
+ return 1;
+ }
+
+ // zero the tables
+ RtlZeroMemory(NicCbArray, arraylen);
+
+ // initialize the NicCb pointers table and
+ // initialize ALL NicCbs to the NIC_CLOSED status
+ niccbp = NicCbArray; // NicCb table start
+
+ for(i=0; i<MaximumNicCount; i++, niccbp++) {
+
+ // pointers table
+ NicCbPtrTab[i] = niccbp;
+
+ // NicCb
+ niccbp->NicId = i;
+ InitializeListHead(&niccbp->SendQueue);
+ InitializeListHead(&niccbp->ReceiveQueue);
+
+ KeInitializeDpc(&niccbp->NicCloseDpc, NicCloseTimeout, niccbp);
+ KeInitializeTimer(&niccbp->NicCloseTimer);
+ KeInitializeEvent(&niccbp->NicClosedEvent, NotificationEvent, FALSE);
+
+ // initialize the WanGenRequests sender
+ KeInitializeDpc(&niccbp->WanGenRequestDpc, WanGenRequestTimeout, niccbp);
+ KeInitializeTimer(&niccbp->WanGenRequestTimer);
+ niccbp->WanGenRequestCount = 0;
+
+ INITIALIZE_SPIN_LOCK(&niccbp->NicLock);
+
+ InitRipSndAtNic(niccbp);
+
+ // default -> always enabled
+ niccbp->WanRoutingDisabled = FALSE;
+
+ niccbp->NicState = NIC_CLOSED;
+
+ // set device type to an invalid type
+ niccbp->DeviceType = IPX_ROUTER_INVALID_DEVICE_TYPE;
+
+ }
+
+ // configure the NicCbs that we got in the config data buffer
+ nicdatp = IpxBindBuffp->NicInfoBuffer.NicData; // config data start
+
+ for(i=0; i<ConfiguredNicCount; i++, nicdatp++) {
+
+ ASSERT(nicdatp->NicId < MaximumNicCount);
+
+ niccbp = NicCbPtrTab[nicdatp->NicId];
+ ConfigureNicCb(niccbp, nicdatp);
+
+ // If this is not a Wan device, open it
+ if(niccbp->DeviceType != NdisMediumWan) {
+
+ niccbp->NicState = NIC_PENDING_OPEN;
+ }
+
+#if DBG
+ if(niccbp->DeviceType == NdisMediumWan) {
+ WanNicsCount++;
+ }
+ else
+ {
+ LanNicsCount++;
+ }
+#endif
+
+ }
+
+ RtPrint(DBG_INIT, ("IpxRouter: CreateNicCbs created %d Lan Nics\n", LanNicsCount));
+ RtPrint(DBG_INIT, ("IpxRouter: CreateNicCbs created %d Wan Nics\n", WanNicsCount));
+
+ // get the virtual numbers, if any
+ VirtualNicId = IpxBindBuffp->NicInfoBuffer.VirtualNicId;
+ memcpy(VirtualNetwork, IpxBindBuffp->NicInfoBuffer.VirtualNetwork, IPX_NET_LEN);
+
+ // All Done
+ return 0;
+}
+
+//***
+//
+// Function: DestroyNicCbs
+//
+// Descr: frees the memory allocated for NicCbs
+//
+// Params: none
+//
+// Returns: none
+//
+//***
+
+VOID
+DestroyNicCbs(VOID)
+{
+ UINT i;
+
+ for(i=0; i<MaximumNicCount; i++) {
+
+ DEINITIALIZE_SPIN_LOCK(&NicCbPtrTab[i]->NicLock);
+ }
+
+ CTEFreeMem(NicCbPtrTab);
+ CTEFreeMem(NicCbArray);
+}
+
+//***
+//
+// Function: ConfigureNicCb
+//
+// Descr: Initializes the NicCb data struct
+//
+// Params: NicCb ptr, Nic data buffer ptr
+//
+// Returns: none
+//
+//***
+
+VOID
+ConfigureNicCb(PNICCB niccbp,
+ PIPX_NIC_DATA nicdatp)
+{
+#if DBG
+ char *devtypestr;
+#endif
+
+ niccbp->NicId = nicdatp->NicId;
+ memcpy(niccbp->Network, nicdatp->Network, 4);
+ memcpy(niccbp->Node, nicdatp->Node, 6);
+ niccbp->LinkSpeed = nicdatp->LineInfo.LinkSpeed;
+ niccbp->TickCount = tickcount(niccbp->LinkSpeed);
+ niccbp->MaximumPacketSize = nicdatp->LineInfo.MaximumPacketSize;
+ niccbp->MacOptions = nicdatp->LineInfo.MacOptions;
+ niccbp->DeviceType = nicdatp->DeviceType;
+
+ niccbp->SendPktsQueuedCount = 0;
+
+ ZeroNicStatistics(niccbp);
+
+#if DBG
+ if(niccbp->DeviceType == NdisMediumWan) {
+
+ devtypestr = "WAN";
+ }
+ else
+ {
+ devtypestr = "LAN";
+ }
+#endif
+
+ // update the WanRoutingDisabled flag from the IPX_NIC_DATA
+ if(nicdatp->EnableWanRouter) {
+
+ RtPrint(DBG_INIT, ("IpxRouter: Wan Router Enabled for NicId %d\n", niccbp->NicId));
+
+ niccbp->WanRoutingDisabled = FALSE;
+ }
+ else
+ {
+ RtPrint(DBG_INIT, ("IpxRouter: Wan Router Disabled for NicId %d\n", niccbp->NicId));
+
+ niccbp->WanRoutingDisabled = TRUE;
+ }
+
+ RtPrint(DBG_INIT, ("IpxRouter: Configured Nic %d with DeviceType %s\n", niccbp->NicId, devtypestr));
+}
+
+USHORT
+tickcount(UINT linkspeed)
+{
+ USHORT tc;
+
+ ASSERT(linkspeed != 0);
+
+ if(linkspeed >= 10000) {
+
+ // link speed >= 1M bps
+ return 1;
+ }
+ else
+ {
+ // compute the necessary time to send a 576 bytes packet over this
+ // line and express it as nr of ticks.
+ // One tick = 55ms
+
+ tc = 57600 / linkspeed;
+ tc = tc / 55 + 1;
+ return tc;
+ }
+}
+
+//***
+//
+// Function: NicClose
+//
+// Descr: Starts the nic closing operation, as follows:
+// 1. Sets the nic state to NIC_CLOSING, which disables further
+// receives/sends on this nic. Doing this will complete immediately
+// any receives, receive complete and sends.
+// 2. Dequeues and completes all snd requests waiting in this nic
+// rip snd req queue.
+// 3. Checks if all closing conditions are met.
+// 4. If the resources are freed, nic is closed. Else the nic closing
+// timer is started which will do a periodic check of closing
+// conditions.
+//
+//***
+
+NIC_CLOSE_STATUS
+NicClose(PNICCB niccbp,
+ USHORT CloseCompletionOption)
+{
+ PLIST_ENTRY lep;
+ PRIP_SNDREQ sndreqp;
+ LIST_ENTRY RemovedRipSndReqList;
+ NIC_CLOSE_STATUS rc;
+
+ ACQUIRE_SPIN_LOCK(&niccbp->NicLock);
+
+ switch(niccbp->NicState) {
+
+ case NIC_CLOSED:
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+ return NIC_CLOSE_SUCCESS;
+
+ case NIC_CLOSING:
+
+ niccbp->CloseCompletionOptions |= CloseCompletionOption;
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+ return NIC_CLOSE_PENDING;
+
+ case NIC_ACTIVE:
+
+ niccbp->CloseCompletionOptions |= CloseCompletionOption;
+
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+ }
+
+ // cancel the Wan Gen Requests timer
+ if(niccbp->DeviceType == NdisMediumWan) {
+
+ // check if the timer has been scheduled to fire
+ // (this is equivalent with checking if there are wan gen req to send)
+ if(niccbp->WanGenRequestCount) {
+
+ // the wan requests timer is in the system's timer queue because
+ // there still are requests to send. Try to cancel it now
+ if(KeCancelTimer(&niccbp->WanGenRequestTimer)) {
+
+ RtPrint(DBG_NIC, ("IpxRouter: NicClose: Cancel WanReqTimer for NicId %d was successful\n", niccbp->NicId));
+ // cancel was successful, reset the request count
+ niccbp->WanGenRequestCount = 0;
+ }
+ else
+ {
+ RtPrint(DBG_NIC, ("IpxRouter: NicClose: Could not cancel WanReqTimer for NicId %d\n", niccbp->NicId));
+ }
+ }
+ }
+
+ InitializeListHead(&RemovedRipSndReqList);
+
+ // remove all pending rip snd requests
+ while(!IsListEmpty(&niccbp->RipSendQueue)) {
+
+ lep = RemoveHeadList(&niccbp->RipSendQueue);
+ sndreqp = CONTAINING_RECORD(lep, RIP_SNDREQ, NicLinkage);
+
+ InsertTailList(&RemovedRipSndReqList, &sndreqp->NicLinkage);
+ }
+
+ // check if all resources for this nic have been de-allocated
+ if(IsListEmpty(&niccbp->SendQueue) &&
+ IsListEmpty(&niccbp->ReceiveQueue) &&
+ (niccbp->RipSndReqp == NULL) &&
+ (niccbp->WanGenRequestCount == 0)) {
+
+ niccbp->NicState = NIC_CLOSED;
+ niccbp->CloseCompletionOptions = 0;
+
+ rc = NIC_CLOSE_SUCCESS;
+ }
+ else
+ {
+ niccbp->NicState = NIC_CLOSING;
+ KeResetEvent(&niccbp->NicClosedEvent);
+ StartNicCloseTimer(niccbp);
+ rc = NIC_CLOSE_PENDING;
+ }
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+
+ // invoke completion routine for all the removed snd requests
+ while(!IsListEmpty(&RemovedRipSndReqList)) {
+
+ lep = RemoveHeadList(&RemovedRipSndReqList);
+ sndreqp = CONTAINING_RECORD(lep, RIP_SNDREQ, NicLinkage);
+
+ RipSendAtNicCompleted(sndreqp);
+ }
+
+#if DBG
+
+ if(rc == NIC_CLOSE_SUCCESS) {
+
+ RtPrint(DBG_NIC, ("IpxRouter: NicClose: Closed OK for NicId: %d\n", niccbp->NicId));
+ }
+ else
+ {
+ RtPrint(DBG_NIC, ("IpxRouter: NicClose: Close pending for NicId: %d\n", niccbp->NicId));
+ }
+
+#endif
+
+ return rc;
+}
+
+VOID
+NicCloseTimeout(PKDPC Dpc,
+ PVOID DefferedContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2)
+{
+ PNICCB niccbp;
+ BOOLEAN SignalCompletionEvent = FALSE;
+ BOOLEAN CallCompletionRoutine = FALSE;
+
+ niccbp = (PNICCB)DefferedContext;
+
+ ACQUIRE_SPIN_LOCK(&niccbp->NicLock);
+
+ switch(niccbp->NicState) {
+
+ case NIC_CLOSING:
+
+ // check closing conditions
+ if((IsListEmpty(&niccbp->SendQueue)) &&
+ (IsListEmpty(&niccbp->ReceiveQueue)) &&
+ (niccbp->RipSndReqp == NULL) &&
+ (niccbp->WanGenRequestCount == 0)) {
+
+ niccbp->NicState = NIC_CLOSED;
+
+ if(niccbp->CloseCompletionOptions & SIGNAL_CLOSE_COMPLETION_EVENT) {
+
+ SignalCompletionEvent = TRUE;
+ }
+
+ if(niccbp->CloseCompletionOptions & CALL_CLOSE_COMPLETION_ROUTINE) {
+
+ CallCompletionRoutine = TRUE;
+ }
+
+ niccbp->CloseCompletionOptions = 0;
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+
+ if(CallCompletionRoutine) {
+
+ NicCloseComplete(niccbp);
+ }
+
+ if(SignalCompletionEvent) {
+
+ // signal the router driver that this nic is closed
+ KeSetEvent(&niccbp->NicClosedEvent, 0L, FALSE);
+ }
+
+ RtPrint(DBG_NIC, ("IpxRouter: NicCloseTimeout: Closed OK for NicId: %d\n", niccbp->NicId));
+ }
+ else
+ {
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+
+ // restart the timer and check next time
+ StartNicCloseTimer(niccbp);
+
+ RtPrint(DBG_NIC, ("IpxRouter: NicCloseTimeout: Close pending for NicId: %d\n", niccbp->NicId));
+ }
+
+ break;
+
+ case NIC_CLOSED:
+
+ // we can be called with nic closed only to check that nic
+ // rcv pkts have all been released
+ if(IsRcvPktResourceFree) {
+
+ // signal the router driver that this nic is closed
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+
+ KeSetEvent(&niccbp->NicClosedEvent, 0L, FALSE);
+
+ RtPrint(DBG_NIC, ("IpxRouter: NicCloseTimeout: Free Resources OK for NicId: %d\n", niccbp->NicId));
+ }
+ else
+ {
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+
+ // restart the timer and check next time
+ StartNicCloseTimer(niccbp);
+
+ RtPrint(DBG_NIC, ("IpxRouter: NicCloseTimeout: Free Resources pending for NicId: %d\n", niccbp->NicId));
+ }
+
+ break;
+
+ default:
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+
+ ASSERT(FALSE);
+ break;
+ }
+}
+
+NIC_RESOURCES_STATUS
+NicFreeResources(PNICCB niccbp)
+{
+ NIC_RESOURCES_STATUS rc;
+
+ ASSERT(niccbp->NicState == NIC_CLOSED);
+
+ if(IsRcvPktResourceFree(niccbp)) {
+
+ rc = NIC_RESOURCES_FREED;
+ }
+ else
+ {
+ // we reuse the closing timer for freeing the resources
+ KeResetEvent(&niccbp->NicClosedEvent);
+ StartNicCloseTimer(niccbp);
+ rc = NIC_RESOURCES_PENDING;
+ }
+
+#if DBG
+
+ if(rc == NIC_RESOURCES_FREED) {
+
+ RtPrint(DBG_NIC, ("IpxRouter: NicFreeResources: Resources freed OK for NicId: %d\n", niccbp->NicId));
+ }
+ else
+ {
+ RtPrint(DBG_NIC, ("IpxRouter: NicFreeResources: Free resources pending for NicId: %d\n", niccbp->NicId));
+ }
+
+#endif
+
+ return rc;
+}
+
+//***
+//
+// Function: NicOpen
+//
+// Descr: Sets the nic state to active so that further receives/snd can
+// execute.
+//
+//***
+
+NIC_OPEN_STATUS
+NicOpen(PNICCB niccbp)
+{
+
+ RtPrint(DBG_NIC, ("IpxRouter: NicOpen: Entered for NicId: %d\n", niccbp->NicId));
+ ACQUIRE_SPIN_LOCK(&niccbp->NicLock);
+
+ if(RouterUnloading) {
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+ return NIC_OPEN_FAILURE;
+ }
+
+ // check that we are CLOSED
+ switch(niccbp->NicState) {
+
+ case NIC_CLOSED:
+ case NIC_PENDING_OPEN:
+
+ // reset the close completion options
+ niccbp->CloseCompletionOptions = 0;
+
+ break;
+
+ default:
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+ return NIC_OPEN_FAILURE;
+ }
+
+ niccbp->NicState = NIC_ACTIVE;
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+ return NIC_OPEN_SUCCESS;
+}
+
+
+//***
+//
+// Function: StartNicCloseTimer
+//
+// Descr: Starts the timer for 200 ms at this Nic Cb
+//
+// Params: pointer to Nic Cb
+//
+// Returns: none
+//
+//***
+
+VOID
+StartNicCloseTimer(PNICCB niccbp)
+{
+ LARGE_INTEGER timeout;
+
+ timeout.LowPart = (ULONG)(-200 * 10000L); // 200 ms
+ timeout.HighPart = -1;
+
+ KeSetTimer(&niccbp->NicCloseTimer, timeout, &niccbp->NicCloseDpc);
+}
+
+VOID
+ZeroNicStatistics(PNICCB niccbp)
+{
+ niccbp->StatBadReceived = 0;
+ niccbp->StatRipReceived = 0;
+ niccbp->StatRipSent = 0;
+ niccbp->StatRoutedReceived = 0;
+ niccbp->StatRoutedSent = 0;
+ niccbp->StatType20Received = 0;
+ niccbp->StatType20Sent = 0;
+}
diff --git a/private/ntos/tdi/isn/rip/nwlnkrip.rc b/private/ntos/tdi/isn/rip/nwlnkrip.rc
new file mode 100644
index 000000000..06f8b26da
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/nwlnkrip.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "NWLINK2 RIP Protocol Driver"
+#define VER_INTERNALNAME_STR "nwlnkrip.sys"
+#define VER_ORIGINALFILENAME_STR "nwlnkrip.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/tdi/isn/rip/packet.h b/private/ntos/tdi/isn/rip/packet.h
new file mode 100644
index 000000000..6d5d3b91b
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/packet.h
@@ -0,0 +1,81 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: packet.h
+//
+// Description: Contains general definitions for the ipx and rip packets
+//
+// Author: Stefan Solomon (stefans) October 4, 1993.
+//
+// Revision History:
+//
+//***
+
+#ifndef _PACKET_
+#define _PACKET_
+
+//*** Socket Numbers
+
+#define IPX_RIP_SOCKET (USHORT)0x453
+#define IPX_NETBIOS_SOCKET (USHORT)0x455
+
+//*** Packet Types
+
+#define IPX_RIP_TYPE 1 // RIP request/reply packet
+#define IPX_NETBIOS_TYPE 20 // Netbios propagated packet
+
+//*** RIP Operations
+
+#define RIP_REQUEST (USHORT)1
+#define RIP_RESPONSE (USHORT)2
+
+//*** Offsets into the IPX header
+
+#define IPXH_HDRSIZE 30 // Size of the IPX header
+#define IPXH_CHECKSUM 0 // Checksum
+#define IPXH_LENGTH 2 // Length
+#define IPXH_XPORTCTL 4 // Transport Control
+#define IPXH_PKTTYPE 5 // Packet Type
+#define IPXH_DESTADDR 6 // Dest. Address (Total)
+#define IPXH_DESTNET 6 // Dest. Network Address
+#define IPXH_DESTNODE 10 // Dest. Node Address
+#define IPXH_DESTSOCK 16 // Dest. Socket Number
+#define IPXH_SRCADDR 18 // Source Address (Total)
+#define IPXH_SRCNET 18 // Source Network Address
+#define IPXH_SRCNODE 22 // Source Node Address
+#define IPXH_SRCSOCK 28 // Source Socket Number
+
+#define IPX_NET_LEN 4
+#define IPX_NODE_LEN 6
+
+//*** RIP OPERATION FIELD
+
+#define RIP_OPCODE 30 // rip operation code offset
+
+//*** Network entry structure in the RIP request/response
+
+#define RIP_INFO 32 // first network entry in the rip packet
+
+#define NE_ENTRYSIZE 8 // 4 network + 2 hops + 2 ticks
+#define NE_NETNUMBER 0 // network number offset
+#define NE_NROFHOPS 4 // number of hops offset
+#define NE_NROFTICKS 6 // nymber of ticks offset
+
+//*** maximum nr of hops for a normal packet ***
+
+#define IPX_MAX_HOPS 16
+
+//*** define rip response packet size
+
+#define RIP_RESPONSE_PACKET_LEN 432
+
+//*** offsets into the netbios session data packet ***
+
+#define NB_CONNECTION_CONTROL_FLAG 30
+#define NB_DATA_STREAM_TYPE 31
+#define NB_TOTAL_DATA_LENGTH 38
+
+#endif
diff --git a/private/ntos/tdi/isn/rip/rcvind.c b/private/ntos/tdi/isn/rip/rcvind.c
new file mode 100644
index 000000000..392f31e74
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/rcvind.c
@@ -0,0 +1,448 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: rcvind.c
+//
+// Description: receive indication handler
+//
+// Author: Stefan Solomon (stefans) October 8 1993.
+//
+// Revision History:
+//
+//***
+
+#include "rtdefs.h"
+
+VOID
+ReceivePacketComplete(PPACKET_TAG rcvpktp,
+ UINT BytesTransferred);
+
+VOID
+DbgFilterReceivedPacket(PUCHAR hdrp);
+
+//***
+//
+// Function: RtReceive
+//
+// Descr: This routine receives control from the IPX driver as an
+// indication that a frame has been received on one of our NICs.
+// This routine is time critical.
+//
+// Params:
+//
+// Returns:
+//
+//***
+
+BOOLEAN
+RtReceive(NDIS_HANDLE MacBindingHandle,
+ NDIS_HANDLE MacReceiveContext,
+ ULONG FwdAdapterCtx,
+ PIPX_LOCAL_TARGET RemoteAddress,
+ ULONG MacOptions,
+ PUCHAR LookaheadBuffer,
+ UINT LookaheadBufferSize,
+ UINT LookaheadBufferOffset,
+ UINT PacketSize,
+ PMDL pMdl)
+{
+ PNICCB niccbp;
+ PPACKET_TAG rcvpktp;
+ NDIS_STATUS NdisStatus;
+ UINT BytesTransferred;
+ PNDIS_PACKET pktdescrp;
+
+ //
+ //*** Some Basic Validations ***
+ //
+
+ RtPrint(DBG_RECV, ("IpxRouter: RtReceive: Entered\n"));
+
+#if DBG
+ DbgFilterReceivedPacket(LookaheadBuffer);
+#endif
+
+ // check that our configuration process has terminated OK
+ if(!RouterInitialized) {
+
+ return FALSE;
+ }
+ // check that the packet fits our buffers
+ if(PacketSize > MaxFrameSize) {
+
+ return FALSE;
+ }
+ // check if we got the whole IPX header in the lookahead buffer
+ if(LookaheadBufferSize < IPXH_HDRSIZE) {
+
+ return FALSE;
+ }
+ // check if we are active on this NIC
+ niccbp = NicCbPtrTab[RemoteAddress->NicId];
+
+ if(niccbp->DeviceType != NdisMediumWan) {
+
+ // ckeck if this is not our own loopedback broadcast packet
+ if(!memcmp(RemoteAddress->MacAddress, niccbp->Node, 6)) {
+
+ return FALSE;
+ }
+
+ // This is a LAN NIC, the source node is unique
+ if(!memcmp(LookaheadBuffer + IPXH_SRCNODE, niccbp->Node, 6)) {
+
+ return FALSE;
+ }
+ }
+ else
+ {
+ // This is a WAN NIC, the source node is 1 and may conflict.
+ // Make an extra check with the network number
+ if(!memcmp(LookaheadBuffer + IPXH_SRCNET, niccbp->Network, 4) &&
+ !memcmp(LookaheadBuffer + IPXH_SRCNODE, niccbp->Node, 6)) {
+
+ // same net && same node -> loopback -> discard
+ return FALSE;
+ }
+ }
+
+ // check if the packet didn't exceed the allowed number of hops
+ if(*(LookaheadBuffer + IPXH_XPORTCTL) >= 16) {
+
+ return FALSE;
+ }
+ //
+ //*** Accept the packet ***
+ //
+
+ ACQUIRE_SPIN_LOCK(&niccbp->NicLock);
+
+ // check that we are enabled to receive on this nic
+ if(niccbp->NicState != NIC_ACTIVE) {
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+ return FALSE;
+ }
+
+ // try to get a packet from the rcv pkt pool
+ if((rcvpktp = AllocateRcvPkt(niccbp)) == NULL) {
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+ RtPrint(DBG_RECV, ("IpxRouter: RtReceive: Can't allocate a rcv pkt\n"));
+ return FALSE;
+ }
+
+ // set up the new packet
+ pktdescrp = CONTAINING_RECORD(rcvpktp, NDIS_PACKET, ProtocolReserved);
+
+ // enqueue the packet in the NIC's recv list and wait for the
+ // transfer to complete
+ rcvpktp->QueueOwnerNicCbp = niccbp;
+
+ InsertTailList(&niccbp->ReceiveQueue, &rcvpktp->PacketLinkage);
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+
+ // try to get the packet data
+ IpxTransferData(&NdisStatus,
+ MacBindingHandle,
+ MacReceiveContext,
+ LookaheadBufferOffset, // start of IPX header
+ PacketSize, // packet size starting at IPX header
+ pktdescrp,
+ &BytesTransferred);
+
+ if(NdisStatus != NDIS_STATUS_PENDING) {
+
+ // complete the frame processing
+ RtTransferDataComplete(pktdescrp, NdisStatus, BytesTransferred);
+ }
+ return FALSE;
+}
+
+
+//***
+//
+// Function: RtTransferDataComplete
+//
+// Descr:
+//
+//***
+
+VOID
+RtTransferDataComplete(PNDIS_PACKET packetp,
+ NDIS_STATUS NdisStatus,
+ UINT BytesTransferred)
+{
+ PPACKET_TAG rcvpktp;
+ PNICCB niccbp;
+
+ rcvpktp = (PPACKET_TAG)(packetp->ProtocolReserved);
+ niccbp = rcvpktp->QueueOwnerNicCbp;
+
+ // remove the packet from the receive queue
+ ACQUIRE_SPIN_LOCK(&niccbp->NicLock);
+
+ RemoveEntryList(&rcvpktp->PacketLinkage);
+
+ // check the success of the transfer and our Nic state
+ if((NdisStatus != NDIS_STATUS_SUCCESS) ||
+ (niccbp->NicState != NIC_ACTIVE)) {
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+
+ RtPrint(DBG_NOTIFY, ("IpxRouter: RtTransferDataComplete: failed %x\n", NdisStatus));
+ FreeRcvPkt(rcvpktp);
+ return;
+ }
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+
+ ReceivePacketComplete(rcvpktp, BytesTransferred);
+ return;
+}
+
+//***
+//
+// Function: ReceivePacketComplete
+//
+// Descr: actual packet processing
+//
+//***
+
+VOID
+ReceivePacketComplete(PPACKET_TAG rcvpktp,
+ UINT BytesTransferred)
+{
+ USHORT pktlen;
+ PUCHAR hdrp;
+ PNICCB niccbp;
+ USHORT destsock;
+
+ // get a pointer to the IPX header
+ hdrp = rcvpktp->DataBufferp;
+
+ // get a pointer to the packet owner NicCb
+ niccbp = rcvpktp->PacketOwnerNicCbp;
+
+ // check that we have the whole packet
+ GETSHORT2USHORT(&pktlen, hdrp + IPXH_LENGTH);
+
+ if(BytesTransferred < pktlen) {
+
+ // we miss a part of the IPX frame
+ niccbp->StatBadReceived++;
+
+ // free the packet and get out
+ RtPrint(DBG_RECV, ("IpxRouter: ReceivePacketComplete: incomplete transfer\n"));
+ FreeRcvPkt(rcvpktp);
+ return;
+ }
+
+ //*** if dest net is 0, replace it with our net
+ if(!memcmp(hdrp + IPXH_DESTNET, nulladdress, IPX_NET_LEN)) {
+
+ memcpy(hdrp + IPXH_DESTNET, niccbp->Network, IPX_NET_LEN);
+ }
+
+ //*** if src net is 0, replace it with our net
+ if(!memcmp(hdrp + IPXH_SRCNET, nulladdress, IPX_NET_LEN)) {
+
+ memcpy(hdrp + IPXH_SRCNET, niccbp->Network, IPX_NET_LEN);
+ }
+
+ // check if the packet is destined for our own internal processes
+ if(!memcmp(hdrp + IPXH_DESTNET, niccbp->Network, IPX_NET_LEN)) {
+
+ //
+ //*** Packet directed to us (Netbios bcast or RIP) ***
+ //
+
+ // check if this is a Netbios Broadcast packet
+ if(*(hdrp + IPXH_PKTTYPE) == IPX_NETBIOS_TYPE) {
+
+ niccbp->StatType20Received++;
+
+ // this is a propagated Netbios packet
+ ProcessNbPacket(rcvpktp);
+
+ return;
+ }
+
+ // check if this is a RIP packet
+ GETSHORT2USHORT(&destsock, hdrp + IPXH_DESTSOCK);
+ if(destsock == IPX_RIP_SOCKET) {
+
+ niccbp->StatRipReceived++;
+
+ // this is a RIP packet.
+ // Queue it for postprocessing by the receive complete
+ ACQUIRE_SPIN_LOCK(&RipPktsListLock);
+
+ InsertTailList(&RipPktsList, &rcvpktp->PacketLinkage);
+
+ RELEASE_SPIN_LOCK(&RipPktsListLock);
+
+ return;
+ }
+
+ // This packet is not for us !!!
+ niccbp->StatBadReceived++;
+
+ RtPrint(DBG_RECV, ("IpxRouter: ReceivePacketComplete: packet is not for the router!!!\n"));
+ FreeRcvPkt(rcvpktp);
+ return;
+ }
+
+ else
+ {
+ // check if this packet is destined to the RIP socket
+ // this may happen if a badly configured router thinks it is on a
+ // different net segment
+ GETSHORT2USHORT(&destsock, hdrp + IPXH_DESTSOCK);
+ if(destsock == IPX_RIP_SOCKET) {
+
+ niccbp->StatBadReceived++;
+
+ // discard the packet
+ FreeRcvPkt(rcvpktp);
+ return;
+ }
+
+ //
+ //*** Packet to be routed
+ //
+
+ niccbp->StatRoutedReceived++;
+
+ RoutePacket(rcvpktp);
+ }
+}
+
+//***
+//
+// Function: RtReceiveComplete
+//
+// Descr: This routine receives control from the IPX driver after one or
+// more receive operations have completed and no receive is in progress.
+// It is called under less severe time constraints than RtReceive.
+// We use it to perform post processing of RIP requests/replies
+// queued in the RIP queue.
+//
+// Params:
+//
+// Returns:
+//
+//***
+
+VOID
+RtReceiveComplete(USHORT NicId)
+{
+ LIST_ENTRY TempRipProcessList;
+ PLIST_ENTRY lep;
+ PPACKET_TAG pktp;
+
+ RtPrint(DBG_RECV, ("IpxRouter: RtReceiveComplete: Entered\n"));
+
+ // check that our configuration process has terminated OK
+ if(!RouterInitialized) {
+
+ return;
+ }
+
+ InitializeListHead(&TempRipProcessList);
+
+ ACQUIRE_SPIN_LOCK(&RipPktsListLock);
+
+ while(!IsListEmpty(&RipPktsList)) {
+
+ lep = RemoveHeadList(&RipPktsList);
+ InsertTailList(&TempRipProcessList, lep);
+ }
+
+ RELEASE_SPIN_LOCK(&RipPktsListLock);
+
+ while(!IsListEmpty(&TempRipProcessList)) {
+
+ lep = RemoveHeadList(&TempRipProcessList);
+ pktp = CONTAINING_RECORD(lep, PACKET_TAG, PacketLinkage);
+
+ ProcessRipPacket(pktp);
+ }
+}
+
+#if DBG
+
+ULONG DbgFilterTrap = 0; // 1 - on dst and src (net + node),
+ // 2 - on dst (net + node),
+ // 3 - on src (net + node),
+ // 4 - on dst (net + node + socket)
+
+UCHAR DbgFilterDstNet[4];
+UCHAR DbgFilterDstNode[6];
+UCHAR DbgFilterDstSocket[2];
+UCHAR DbgFilterSrcNet[4];
+UCHAR DbgFilterSrcNode[6];
+UCHAR DbgFilterSrcSocket[2];
+PUCHAR DbgFilterFrame;
+
+VOID
+DbgFilterReceivedPacket(PUCHAR hdrp)
+{
+ switch(DbgFilterTrap) {
+
+ case 1:
+
+ if(!memcmp(hdrp + IPXH_DESTNET, DbgFilterDstNet, 4) &&
+ !memcmp(hdrp + IPXH_DESTNODE, DbgFilterDstNode, 6) &&
+ !memcmp(hdrp + IPXH_SRCNET, DbgFilterSrcNet, 4) &&
+ !memcmp(hdrp + IPXH_SRCNODE, DbgFilterSrcNode, 6)) {
+
+ DbgBreakPoint();
+ }
+
+ break;
+
+ case 2:
+
+ if(!memcmp(hdrp + IPXH_DESTNET, DbgFilterDstNet, 4) &&
+ !memcmp(hdrp + IPXH_DESTNODE, DbgFilterDstNode, 6)) {
+
+ DbgBreakPoint();
+ }
+
+ break;
+
+ case 3:
+
+ if(!memcmp(hdrp + IPXH_SRCNET, DbgFilterSrcNet, 4) &&
+ !memcmp(hdrp + IPXH_SRCNODE, DbgFilterSrcNode, 6)) {
+
+ DbgBreakPoint();
+ }
+
+ break;
+
+ case 4:
+
+ if(!memcmp(hdrp + IPXH_DESTNET, DbgFilterDstNet, 4) &&
+ !memcmp(hdrp + IPXH_DESTNODE, DbgFilterDstNode, 6) &&
+ !memcmp(hdrp + IPXH_DESTSOCK, DbgFilterDstSocket, 2)) {
+
+ DbgBreakPoint();
+ }
+
+ break;
+
+ default:
+
+ break;
+ }
+
+ DbgFilterFrame = hdrp;
+}
+
+#endif
diff --git a/private/ntos/tdi/isn/rip/rcvpkt.c b/private/ntos/tdi/isn/rip/rcvpkt.c
new file mode 100644
index 000000000..250e97dbc
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/rcvpkt.c
@@ -0,0 +1,833 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: rcvpkt.c
+//
+// Description: rcv pkt pool manager
+//
+// Author: Stefan Solomon (stefans) October 5, 1993.
+//
+// Revision History:
+//
+//***
+
+#include "rtdefs.h"
+
+PRCVPKT_SEGMENT
+CreateRcvPktSegment(VOID);
+
+VOID
+DestroyRcvPktSegment(PRCVPKT_SEGMENT segp);
+
+PPACKET_TAG
+CreateRcvPkt(PULONG buffp,
+ PRCVPKT_SEGMENT segp);
+
+VOID
+DestroyRcvPkt(PPACKET_TAG pktp);
+
+// the pool size parameter
+UINT RcvPktPoolSize = RCVPKT_MEDIUM_POOL_SIZE;
+
+// the number of receive packets per pool segment (config parameter)
+UINT RcvPktsPerSegment = DEF_RCV_PKTS_PER_SEGMENT;
+UINT LowRcvPktsCount = 0;
+
+
+// Max frame size as a multiple of ULONGs
+UINT UlongMaxFrameSize;
+
+//
+//*** Control Structures For the Rcv Pkt Segment List ***
+//
+
+NDIS_SPIN_LOCK RcvPktSegListLock;
+
+UINT RcvPktSegCount = 0; // total segments allocated
+ // for this pool
+UINT MaxRcvPktCount = 0; // max nr of pkts the pool can have
+UINT RcvPktCount = 0; // total pkts allocated for the
+ // pool: free + owned by nics
+PUINT RcvPktPerNicCount; // table of pkts allocated for
+ // each nic, indexed by NicId
+LIST_ENTRY RcvPktSegList; // list of pool segments
+
+//*** Statistics: Peak rcv pkts allocation ***
+
+ULONG StatMemAllocCount = 0;
+ULONG StatMemPeakCount = 0;
+
+//*** Control Structure for the Allocate Ahead Function ***
+
+typedef enum _ALLOC_AHEAD_STATE {
+
+ ALLOC_AHEAD_IDLE,
+ ALLOC_AHEAD_ACTIVE
+ } ALLOC_AHEAD_STATE;
+
+ALLOC_AHEAD_STATE AllocAheadState;
+
+WORK_QUEUE_ITEM AllocAheadWorkItem;
+
+VOID
+AllocAhead(PVOID parameter);
+
+VOID
+CheckAllocationAhead(VOID);
+
+//***
+//
+// Function: CreateRcvPktPool
+//
+// Descr: Allocates the rcv pkt descr and buff descr pools.
+// Creates the rcv pkt segment list and allocates one segment
+//
+// Params: none
+//
+// Returns: 0 - success, 1 - failure
+//
+//***
+
+UINT
+CreateRcvPktPool(VOID)
+{
+ UINT MaxRcvPktsPerNic;
+ PRCVPKT_SEGMENT segp;
+
+ RtPrint(DBG_INIT, ("IpxRouter: CreateRcvPktPool: Entered\n"));
+
+ // calculate the maxrcvpktspernic function of the pool size
+ switch(RcvPktPoolSize) {
+
+ case RCVPKT_SMALL_POOL_SIZE:
+
+ MaxRcvPktsPerNic = 100;
+ break;
+
+ case RCVPKT_MEDIUM_POOL_SIZE:
+
+ MaxRcvPktsPerNic = 250;
+ break;
+
+ case RCVPKT_LARGE_POOL_SIZE:
+ default:
+
+ MaxRcvPktsPerNic = 0; // unlimited
+ break;
+ }
+
+ INITIALIZE_SPIN_LOCK(&RcvPktSegListLock);
+
+ InitializeListHead(&RcvPktSegList);
+
+ // initialize the pool max limit.
+ if(MaxRcvPktsPerNic) {
+
+ MaxRcvPktCount = MaximumNicCount * MaxRcvPktsPerNic;
+ }
+ else
+ {
+ MaxRcvPktCount = 0xFFFFFFFF;
+ }
+
+ UlongMaxFrameSize = MaxFrameSize / sizeof(ULONG) + 1;
+
+ // allocate the array of rcv pkts allocated /nic
+ if((RcvPktPerNicCount = (PUINT)CTEAllocMem(
+ MaximumNicCount * sizeof(UINT))) == NULL) {
+
+ goto cleanup;
+ }
+ RtlZeroMemory(RcvPktPerNicCount, MaximumNicCount * sizeof(UINT));
+
+ //
+ //*** Create the first segment and insert it in the pool
+ //
+
+ if((segp = CreateRcvPktSegment()) == NULL) {
+
+ goto cleanup;
+ }
+
+ // chain the segment in the rcv pkt seg list
+ ACQUIRE_SPIN_LOCK(&RcvPktSegListLock);
+
+ RcvPktSegCount++;
+ RcvPktCount += segp->MaxPktCount;
+
+ InsertTailList(&RcvPktSegList, &segp->SegmentLinkage);
+
+ // initialize the allocate ahead structures
+ AllocAheadState = ALLOC_AHEAD_IDLE;
+ LowRcvPktsCount = RcvPktsPerSegment / 2;
+ ExInitializeWorkItem(&AllocAheadWorkItem, AllocAhead, NULL);
+
+ RELEASE_SPIN_LOCK(&RcvPktSegListLock);
+
+ // All Done
+
+ return 0;
+
+cleanup:
+
+ DestroyRcvPktPool();
+
+ return 1;
+}
+
+//***
+//
+// Function: DestroyRcvPktPool
+//
+// Descr: Destroys all the pool segments.
+// Frees the rcv pkt segment memory array.
+//
+// Params: none
+//
+// Returns: none
+//
+//***
+
+VOID
+DestroyRcvPktPool(VOID)
+{
+ PLIST_ENTRY slp;
+ PRCVPKT_SEGMENT sp;
+
+ RtPrint(DBG_INIT, ("IpxRouter: DestroyRcvPktPool: Entered\n"));
+
+ // ckeck if segment list has been created and destroy it if it exists
+ ACQUIRE_SPIN_LOCK(&RcvPktSegListLock);
+
+ while(!IsListEmpty(&RcvPktSegList)) {
+
+ slp = RemoveTailList(&RcvPktSegList);
+ sp = CONTAINING_RECORD(slp, RCVPKT_SEGMENT, SegmentLinkage);
+
+ DestroyRcvPktSegment(sp);
+ }
+
+ RELEASE_SPIN_LOCK(&RcvPktSegListLock);
+
+ if(RcvPktPerNicCount) {
+
+ CTEFreeMem(RcvPktPerNicCount);
+ }
+
+ DEINITIALIZE_SPIN_LOCK(&RcvPktSegListLock);
+}
+
+//***
+//
+// Function: CreateRcvPktSegment
+//
+// Descr: Allocates a memory buffer of size:
+// rcv pkt segment + n * maxframesize.
+// Allocates n rcv pkt descr and 2n buff descr and creates the
+// rcv packets.
+// Chains all rcv pkts in the rcv pkt segment.
+// Note:
+// Only one buff descr is chained in each packet descr.
+// A ptr is kept in the packet tag to the second buff descr which
+// is associated with the MAC header in the packet tag.
+//
+// Params: none
+//
+// Returns: Segment ptr or NULL if failure.
+//
+//***
+
+PRCVPKT_SEGMENT
+CreateRcvPktSegment(VOID)
+{
+ PRCVPKT_SEGMENT segp;
+ ULONG seglen;
+ UINT i;
+ PPACKET_TAG pktp;
+ PULONG buffp;
+ NDIS_STATUS NdisStatus;
+ UINT PktReservedLen;
+
+ RtPrint(DBG_RCVPKT, ("IpxRouter: CreateRcvPktSegment: Entered\n"));
+
+ seglen = sizeof(RCVPKT_SEGMENT) +
+ RcvPktsPerSegment * UlongMaxFrameSize * sizeof(ULONG);
+
+ if((segp = CTEAllocMem(seglen)) == NULL) {
+
+ return NULL;
+ }
+
+ RtlZeroMemory(segp, sizeof(RCVPKT_SEGMENT));
+ InitializeListHead(&segp->PacketList);
+
+ // Allocate receive packet descriptors and buffer descriptors pools
+ // for this segment
+
+ PktReservedLen = sizeof(PACKET_TAG);
+ segp->RcvPktDescrPoolSize = RcvPktsPerSegment;
+
+ NdisAllocatePacketPool(
+ &NdisStatus,
+ &segp->RcvPktDescrPoolHandle,
+ segp->RcvPktDescrPoolSize,
+ PktReservedLen);
+
+ if(NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ CTEFreeMem(segp);
+ return NULL;
+ }
+
+ // each packet has 2 buffer descriptors
+ segp->RcvPktBuffDescrPoolSize = 2 * RcvPktsPerSegment;
+
+ NdisAllocateBufferPool (
+ &NdisStatus,
+ &segp->RcvPktBuffDescrPoolHandle,
+ segp->RcvPktBuffDescrPoolSize);
+
+ if(NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ NdisFreePacketPool(segp->RcvPktDescrPoolHandle);
+ CTEFreeMem(segp);
+ return NULL;
+ }
+
+ // Make the list of packets
+ for(i=0, buffp=segp->DataBuffer; i<RcvPktsPerSegment; i++) {
+
+ if(pktp = CreateRcvPkt(buffp, segp)) {
+
+ // enqueue this packet in the segment control block
+ InsertTailList(&segp->PacketList, &pktp->PacketLinkage);
+ segp->AvailablePktCount++;
+
+ buffp += UlongMaxFrameSize;
+ }
+ else
+ {
+ DbgBreakPoint();
+ DestroyRcvPktSegment(segp);
+ return NULL;
+ }
+ }
+
+ // set up the total packet allocation count for this segment
+ segp->MaxPktCount = segp->AvailablePktCount;
+
+ RtPrint(DBG_RCVPKT, ("IpxRouter: CreateRcvPktSegment: success\n"));
+
+ return segp;
+}
+
+
+//***
+//
+// Function: DestroyRcvPktSegment
+//
+// Descr: Dequeues the pkt descr and
+// buff descriptors to their respective pools.
+// Frees the memory buffer.
+//
+// Params: Segment ptr
+//
+// Returns: none
+//
+//***
+
+VOID
+DestroyRcvPktSegment(PRCVPKT_SEGMENT segp)
+{
+ PLIST_ENTRY lep;
+ PPACKET_TAG pktp;
+
+ RtPrint(DBG_RCVPKT, ("IpxRouter: DestroyRcvPktSegment: Entered\n"));
+
+ while(!IsListEmpty(&segp->PacketList)) {
+
+ lep = RemoveHeadList(&segp->PacketList);
+ pktp = CONTAINING_RECORD(lep, PACKET_TAG, PacketLinkage);
+ DestroyRcvPkt(pktp);
+ }
+
+ // deallocate the buff descr pool and packet descr pool
+ NdisFreeBufferPool(segp->RcvPktBuffDescrPoolHandle);
+ NdisFreePacketPool(segp->RcvPktDescrPoolHandle);
+
+ CTEFreeMem(segp);
+}
+
+//***
+//
+// Function: CreateRcvPkt
+//
+// Descr: allocates a pkt descr and 2 buff descr
+// makes the necessary chains
+//
+// Params: data buffer ptr
+//
+// Returns: prt to packet or null is failure
+//
+//***
+
+PPACKET_TAG
+CreateRcvPkt(PULONG buffp,
+ PRCVPKT_SEGMENT segp)
+{
+ NDIS_STATUS NdisStatus;
+ PNDIS_PACKET NdisPacket;
+ PNDIS_BUFFER NdisDataBuffer;
+ PNDIS_BUFFER NdisMacBuffer;
+ UINT bufflen;
+ PPACKET_TAG pktp;
+
+ RtPrint(DBG_RCVPKT, ("IpxRouter: CreateRcvPkt: Entered\n"));
+
+ bufflen = UlongMaxFrameSize * sizeof(ULONG);
+
+ NdisAllocatePacket(&NdisStatus,
+ &NdisPacket,
+ segp->RcvPktDescrPoolHandle);
+
+ if(NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ return NULL;
+ }
+
+ pktp = (PPACKET_TAG)&NdisPacket->ProtocolReserved;
+ RtlZeroMemory(pktp, sizeof(PACKET_TAG));
+
+ NdisAllocateBuffer(&NdisStatus,
+ &NdisDataBuffer,
+ segp->RcvPktBuffDescrPoolHandle,
+ buffp,
+ bufflen);
+
+ if(NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ NdisFreePacket(NdisPacket);
+
+ return NULL;
+ }
+
+ NdisAllocateBuffer(&NdisStatus,
+ &NdisMacBuffer,
+ segp->RcvPktBuffDescrPoolHandle,
+ pktp->MacHeader,
+ MacHeaderNeeded);
+
+ if(NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ NdisFreePacket(NdisPacket);
+ NdisFreeBuffer(NdisDataBuffer);
+
+ return NULL;
+ }
+
+ NdisChainBufferAtFront(NdisPacket, NdisDataBuffer);
+ pktp->Identifier = IDENTIFIER_RIP;
+ pktp->ReservedPvoid[0] = NULL;
+ pktp->ReservedPvoid[1] = NULL;
+ pktp->PacketType = RCV_PACKET;
+ pktp->RcvPktSegmentp = segp;
+ pktp->DataBufferp = (PUCHAR)buffp;
+ pktp->DataBufferLength = bufflen;
+ pktp->HeaderBuffDescrp = NdisMacBuffer;
+
+ return pktp;
+}
+
+//***
+//
+// Function: DestroyRcvPkt
+//
+// Descr: deallocates a pkt descr and 2 buff descr
+// unmakes the necessary chains
+//
+// Params: Packet
+//
+// Returns: none
+//
+//***
+
+VOID
+DestroyRcvPkt(PPACKET_TAG pktp)
+{
+ PNDIS_PACKET NdisPacket;
+ PNDIS_BUFFER NdisBuffer;
+
+ RtPrint(DBG_RCVPKT, ("IpxRouter: DestroyRcvPkt: Entered\n"));
+
+ NdisPacket = CONTAINING_RECORD(pktp, NDIS_PACKET, ProtocolReserved);
+
+ // free the data buffer descr
+ NdisUnchainBufferAtBack (NdisPacket, &NdisBuffer);
+ if (NdisBuffer != NULL) {
+ NdisFreeBuffer (NdisBuffer);
+ }
+ else
+ {
+ // !!! break
+ DbgBreakPoint();
+ }
+
+ // free the mac hdr buff descr
+ NdisFreeBuffer(pktp->HeaderBuffDescrp);
+
+ NdisFreePacket(NdisPacket);
+}
+
+//***
+//
+// Function: AllocateRcvPkt
+//
+// Descr: Tries to do the allocation starting with the FIRST available
+// segment.
+// If no available segments, tries to allocate one.
+// Decrements available pkts counter and resets scavenger's tick
+// count. Sets the packet tag rcv pool array ptr to this segment.
+// HOLDS THE LOCK until done.
+//
+// Params: NicCbp to charge
+//
+// Returns: Packet or NULL if the rcv pkt pool array is empty.
+//
+//***
+
+PPACKET_TAG
+AllocateRcvPkt(PNICCB niccbp)
+{
+ PLIST_ENTRY nextp;
+ PRCVPKT_SEGMENT segp;
+ PPACKET_TAG pktp;
+ USHORT NicId;
+ PLIST_ENTRY lep;
+ UINT FreeRcvPktCount = 0; // how many pkts are available in the
+ // pool
+
+ NicId = niccbp->NicId;
+
+ ACQUIRE_SPIN_LOCK(&RcvPktSegListLock);
+
+ // walk the segments list until we find a segment with available pkts
+ nextp = RcvPktSegList.Flink;
+
+ while(nextp != &RcvPktSegList) {
+
+ segp = CONTAINING_RECORD(nextp, RCVPKT_SEGMENT, SegmentLinkage);
+ if(segp->AvailablePktCount) {
+
+ goto allocation_ok;
+ }
+ nextp = segp->SegmentLinkage.Flink;
+ }
+
+ // pool is empty, check if we can create a new segment
+ if(RcvPktCount >= MaxRcvPktCount) {
+
+ // we can't allocate anything
+ goto allocation_failure;
+ }
+
+ // we can allocate a new segment
+ if((segp = CreateRcvPktSegment()) == NULL) {
+
+ // we are beyond salvation !!! break
+ goto allocation_failure;
+ }
+
+ // increment the segment count
+ RcvPktSegCount++;
+
+ // add the new segment to the pool
+ InsertTailList(&RcvPktSegList, &segp->SegmentLinkage);
+
+ // and increment the global allocation counter
+ RcvPktCount += segp->AvailablePktCount;
+
+allocation_ok:
+
+ RtPrint(DBG_RCVPKT, ("IpxRouter: AllocateRcvPkt: OK\n"));
+
+ lep = RemoveHeadList(&segp->PacketList);
+ pktp = CONTAINING_RECORD(lep, PACKET_TAG, PacketLinkage);
+
+ ASSERT(pktp != NULL);
+
+ segp->AvailablePktCount--;
+
+ // reset the segment aging timer
+ segp->AgingTimer = 0;
+
+ // charge the nic for this allocation
+ RcvPktPerNicCount[NicId]++;
+
+ // set the nic owner in the packet
+ pktp->PacketOwnerNicCbp = niccbp;
+
+ // set the packet type
+ pktp->PacketType = RCV_PACKET;
+
+ // before we return the packet, we check if we have hit the low packet
+ // count and, if true, queue a work item to allocate a new segment
+ CheckAllocationAhead();
+
+ // return the packet
+
+ // update statistics
+ StatMemAllocCount++;
+
+ if(StatMemPeakCount < StatMemAllocCount) {
+
+ StatMemPeakCount = StatMemAllocCount;
+ }
+
+ RELEASE_SPIN_LOCK(&RcvPktSegListLock);
+
+ return pktp;
+
+allocation_failure:
+
+ RtPrint(DBG_RCVPKT, ("IpxRouter: AllocateRcvPkt: Failure\n"));
+
+ RELEASE_SPIN_LOCK(&RcvPktSegListLock);
+
+ return NULL;
+}
+
+//***
+//
+// Function: FreeRcvPkt
+//
+// Descr: Inserts the rcv pkt in the respective list and increments the
+// available pkts counter for this pool segment.
+// HOLDS the lock until done.
+//
+// Params: Packet
+//
+// Returns: none
+//
+//***
+
+VOID
+FreeRcvPkt(PPACKET_TAG pktp)
+{
+ PRCVPKT_SEGMENT segp;
+
+#if DBG
+ PRCVPKT_SEGMENT walksegp;
+ PLIST_ENTRY nextp;
+#endif // DBG
+
+ USHORT NicId;
+
+ RtPrint(DBG_RCVPKT, ("IpxRouter: FreeRcvPkt: Entered\n"));
+
+ ACQUIRE_SPIN_LOCK(&RcvPktSegListLock);
+
+ // update statistics
+ StatMemAllocCount--;
+
+ // discharge the Nic
+ NicId = pktp->PacketOwnerNicCbp->NicId;
+ RcvPktPerNicCount[NicId]--;
+
+ // get the packet segment
+ segp = pktp->RcvPktSegmentp;
+
+#if DBG
+
+ {
+ // check that this segment is indeed in our list by walking the list
+ BOOLEAN ValidSegment = FALSE;
+
+ nextp = RcvPktSegList.Flink;
+
+ while(nextp != &RcvPktSegList) {
+
+ walksegp = CONTAINING_RECORD(nextp, RCVPKT_SEGMENT, SegmentLinkage);
+ if(nextp == &segp->SegmentLinkage) {
+
+ ValidSegment = TRUE;
+ break;
+ }
+ nextp = walksegp->SegmentLinkage.Flink;
+ }
+
+ ASSERT(ValidSegment == TRUE);
+ }
+#endif
+
+ // put packet back into the segment list
+ InsertTailList(&segp->PacketList, &pktp->PacketLinkage);
+
+ // increment the available pkts count for this segment
+ segp->AvailablePktCount++;
+
+ ASSERT(segp->AvailablePktCount <= segp->MaxPktCount);
+
+ RELEASE_SPIN_LOCK(&RcvPktSegListLock);
+
+ return;
+}
+
+//***
+//
+// Function: RcvPktPoolScavenger
+//
+// Descr: Entered every 2 sec as a timer DPC.
+// Increments the scavenger tick count for the segment at the
+// tail. If the tick count reaches 3 (6 secs not used) destroys
+// the segment.
+// The scavenger does not act on the FIRST segment.
+// HOLDS THE LOCK until done
+//
+//
+// Params: none
+//
+// Returns: none
+//
+//***
+
+VOID
+RcvPktPoolScavenger(VOID)
+{
+ PRCVPKT_SEGMENT segp;
+ PLIST_ENTRY lastep;
+
+// RtPrint(DBG_RCVPKT, ("IpxRouter: Pool scavenger: pool has %d segmentst\n", RcvPktSegCount));
+
+ ACQUIRE_SPIN_LOCK(&RcvPktSegListLock);
+
+ ASSERT(RcvPktSegCount);
+
+ if(RcvPktSegCount == 1) {
+
+ RELEASE_SPIN_LOCK(&RcvPktSegListLock);
+
+ return;
+ }
+
+ // get to the last segment in the list
+ lastep = RcvPktSegList.Blink;
+ segp = CONTAINING_RECORD(lastep, RCVPKT_SEGMENT, SegmentLinkage);
+
+ // check if all packets are returned to the segment
+ if(segp->AvailablePktCount == segp->MaxPktCount) {
+
+ // we can age this segment
+ if(segp->AgingTimer++ >= 3) {
+
+ // this segment too old and may be deleted
+ RtPrint(DBG_RCVPKT, ("IpxRouter: Pool scavenger: pool has %d segments, will destroy the last\n",
+ RcvPktSegCount));
+
+ RemoveEntryList(&segp->SegmentLinkage);
+ RcvPktSegCount--;
+ RcvPktCount -= segp->MaxPktCount;
+
+ DestroyRcvPktSegment(segp);
+ }
+ }
+
+ RELEASE_SPIN_LOCK(&RcvPktSegListLock);
+
+ return;
+}
+
+//***
+//
+// Function: AllocAhead
+//
+// Descr:
+//
+//***
+
+VOID
+AllocAhead(PVOID Parameter)
+{
+ PRCVPKT_SEGMENT segp;
+
+ RtPrint(DBG_RCVPKT, ("IpxRouter: AllocAhead: Entered\n"));
+
+ ACQUIRE_SPIN_LOCK(&RcvPktSegListLock);
+
+ // check if we can create a new segment
+ if(RcvPktCount >= MaxRcvPktCount) {
+
+ // we can't allocate anything
+ goto aa_exit;
+ }
+
+ // we can allocate a new segment
+ if((segp = CreateRcvPktSegment()) == NULL) {
+
+ // we are beyond salvation !!! break
+ goto aa_exit;
+ }
+
+ // increment the segment count
+ RcvPktSegCount++;
+
+ // add the new segment to the pool
+ InsertTailList(&RcvPktSegList, &segp->SegmentLinkage);
+
+ // and increment the global allocation counter
+ RcvPktCount += segp->AvailablePktCount;
+
+aa_exit:
+
+ AllocAheadState = ALLOC_AHEAD_IDLE;
+
+ RELEASE_SPIN_LOCK(&RcvPktSegListLock);
+}
+
+VOID
+CheckAllocationAhead(VOID)
+{
+ UINT FreeRcvPktsCount = 0;
+ PLIST_ENTRY nextp;
+ PRCVPKT_SEGMENT segp;
+
+ // get the total number of free packets in the pool and check if we
+ // are at our low count
+ nextp = RcvPktSegList.Flink;
+
+ while(nextp != &RcvPktSegList) {
+
+ segp = CONTAINING_RECORD(nextp, RCVPKT_SEGMENT, SegmentLinkage);
+ FreeRcvPktsCount += segp->AvailablePktCount;
+ nextp = segp->SegmentLinkage.Flink;
+ }
+
+ if((FreeRcvPktsCount <= LowRcvPktsCount) &&
+ (AllocAheadState == ALLOC_AHEAD_IDLE)) {
+
+ ExQueueWorkItem(&AllocAheadWorkItem, CriticalWorkQueue);
+ AllocAheadState = ALLOC_AHEAD_ACTIVE;
+ }
+}
+
+BOOLEAN
+IsRcvPktResourceFree(PNICCB niccbp)
+{
+ USHORT NicId;
+ BOOLEAN res_free = FALSE;
+
+ NicId = niccbp->NicId;
+
+ ACQUIRE_SPIN_LOCK(&RcvPktSegListLock);
+
+ if(!RcvPktPerNicCount[NicId]) {
+
+ res_free = TRUE;
+ }
+
+ RELEASE_SPIN_LOCK(&RcvPktSegListLock);
+
+ return res_free;
+}
diff --git a/private/ntos/tdi/isn/rip/registry.c b/private/ntos/tdi/isn/rip/registry.c
new file mode 100644
index 000000000..b7b85b5d0
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/registry.c
@@ -0,0 +1,258 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: registry.c
+//
+// Description: routines for reading the registry configuration
+//
+// Author: Stefan Solomon (stefans) November 9, 1993.
+//
+// Revision History:
+//
+//***
+
+#include "rtdefs.h"
+
+NTSTATUS
+SetIpxDeviceName(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+extern UNICODE_STRING UnicodeFileName;
+extern PWSTR FileNamep;
+
+//***
+//
+// Function: ReadIpxDeviceName
+//
+// Descr: Reads the device name exported by ipx so we can bind to it
+//
+//***
+
+NTSTATUS
+ReadIpxDeviceName(VOID)
+{
+
+ NTSTATUS Status;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+ PWSTR Export = L"Export";
+ PWSTR IpxRegistryPath = L"NwLnkIpx\\Linkage";
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Call SetIpxDeviceName for the string in "Export"
+ //
+
+ QueryTable[0].QueryRoutine = SetIpxDeviceName;
+ QueryTable[0].Flags = 0;
+ QueryTable[0].Name = Export;
+ QueryTable[0].EntryContext = NULL;
+ QueryTable[0].DefaultType = REG_NONE;
+
+ //
+ // 2) Stop
+ //
+
+ QueryTable[1].QueryRoutine = NULL;
+ QueryTable[1].Flags = 0;
+ QueryTable[1].Name = NULL;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ IpxRegistryPath,
+ QueryTable,
+ NULL,
+ NULL);
+
+ return Status;
+}
+
+NTSTATUS
+SetIpxDeviceName(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Export" multi-string and
+ saves the information in a ConfigurationInfo structure.
+
+Arguments:
+
+ ValueName - The name of the value ("Export" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - NULL.
+
+ EntryContext - NULL.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ FileNamep = (PWSTR)ExAllocatePool(NonPagedPool, ValueLength);
+ if (FileNamep != NULL) {
+
+ RtlCopyMemory(FileNamep, ValueData, ValueLength);
+ RtlInitUnicodeString (&UnicodeFileName, FileNamep);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+//***
+//
+// Function: GetRouterParameters
+//
+// Descr: Reads the parameters from the registry and sets them
+//
+//***
+
+NTSTATUS
+GetRouterParameters(IN PUNICODE_STRING RegistryPath)
+{
+
+ NTSTATUS Status;
+ PWSTR RegistryPathBuffer;
+ PWSTR Parameters = L"Parameters";
+ RTL_QUERY_REGISTRY_TABLE paramTable[7]; // table size = nr of params + 1
+
+ RegistryPathBuffer = (PWSTR)ExAllocatePool(NonPagedPool, RegistryPath->Length + sizeof(WCHAR));
+
+ if (RegistryPathBuffer == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (RegistryPathBuffer, RegistryPath->Buffer, RegistryPath->Length);
+ *(PWCHAR)(((PUCHAR)RegistryPathBuffer)+RegistryPath->Length) = (WCHAR)'\0';
+
+ RtlZeroMemory(&paramTable[0], sizeof(paramTable));
+
+ paramTable[0].QueryRoutine = NULL;
+ paramTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ paramTable[0].Name = Parameters;
+
+ paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ paramTable[1].Name = L"RcvPktPoolSize";
+ paramTable[1].EntryContext = &RcvPktPoolSize;
+ paramTable[1].DefaultType = REG_DWORD;
+ paramTable[1].DefaultData = &RcvPktPoolSize;
+ paramTable[1].DefaultLength = sizeof(ULONG);
+
+ paramTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ paramTable[2].Name = L"RcvPktsPerSegment";
+ paramTable[2].EntryContext = &RcvPktsPerSegment;
+ paramTable[2].DefaultType = REG_DWORD;
+ paramTable[2].DefaultData = &RcvPktsPerSegment;
+ paramTable[2].DefaultLength = sizeof(ULONG);
+
+ paramTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ paramTable[3].Name = L"NetbiosRouting";
+ paramTable[3].EntryContext = &NetbiosRouting;
+ paramTable[3].DefaultType = REG_DWORD;
+ paramTable[3].DefaultData = &NetbiosRouting;
+ paramTable[3].DefaultLength = sizeof(ULONG);
+
+ paramTable[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ paramTable[4].Name = L"MaxSendPktsQueued";
+ paramTable[4].EntryContext = &MaxSendPktsQueued;
+ paramTable[4].DefaultType = REG_DWORD;
+ paramTable[4].DefaultData = &MaxSendPktsQueued;
+ paramTable[4].DefaultLength = sizeof(ULONG);
+
+ paramTable[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ paramTable[5].Name = L"EnableLanRouting";
+ paramTable[5].EntryContext = &EnableLanRouting;
+ paramTable[5].DefaultType = REG_DWORD;
+ paramTable[5].DefaultData = &EnableLanRouting;
+ paramTable[5].DefaultLength = sizeof(ULONG);
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ RegistryPathBuffer,
+ paramTable,
+ NULL,
+ NULL);
+
+ if(!NT_SUCCESS(Status)) {
+
+ RtPrint (DBG_INIT, ("IpxRouter: Missing Parameters key in the registry\n"));
+ }
+
+ ExFreePool(RegistryPathBuffer);
+
+ // check if the parameters received are within limits:
+ if((RcvPktPoolSize > RCVPKT_LARGE_POOL_SIZE) ||
+ (RcvPktPoolSize < RCVPKT_SMALL_POOL_SIZE)) {
+
+ RcvPktPoolSize = RCVPKT_MEDIUM_POOL_SIZE;
+ }
+
+ if((RcvPktsPerSegment > MAX_RCV_PKTS_PER_SEGMENT) ||
+ (RcvPktsPerSegment < MIN_RCV_PKTS_PER_SEGMENT)) {
+
+ RcvPktsPerSegment = DEF_RCV_PKTS_PER_SEGMENT;
+ }
+
+ // even if the RtlQueryRegistryValues has failed, we return success and will
+ // use the defaults.
+ return STATUS_SUCCESS;
+}
+
+ULONG
+IsWanGlobalNetRequested(VOID)
+{
+
+ NTSTATUS Status;
+ PWSTR IpxCpParametersPath = L"RemoteAccess\\Parameters\\Ipx";
+ RTL_QUERY_REGISTRY_TABLE paramTable[2]; // table size = nr of params + 1
+
+ ULONG WanGlobalNetRequested = 0;
+
+ RtlZeroMemory(&paramTable[0], sizeof(paramTable));
+
+ paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ paramTable[0].Name = L"GlobalWanNet";
+ paramTable[0].EntryContext = &WanGlobalNetRequested;
+ paramTable[0].DefaultType = REG_DWORD;
+ paramTable[0].DefaultData = &WanGlobalNetRequested;
+ paramTable[0].DefaultLength = sizeof(ULONG);
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ IpxCpParametersPath,
+ paramTable,
+ NULL,
+ NULL);
+
+ RtPrint(DBG_INIT, ("IpxRouter: GlobalWanNet request = %d\n", WanGlobalNetRequested));
+
+ return WanGlobalNetRequested;
+}
diff --git a/private/ntos/tdi/isn/rip/ripaux.c b/private/ntos/tdi/isn/rip/ripaux.c
new file mode 100644
index 000000000..f61bbb573
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/ripaux.c
@@ -0,0 +1,455 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: ripaux.c
+//
+// Description: Misc aux routines for doing RIP
+//
+// Author: Stefan Solomon (stefans) November 5, 1993.
+//
+// Revision History:
+//
+//***
+
+#include "rtdefs.h"
+
+typedef struct _NIC_NODE {
+
+ LIST_ENTRY NodeLinkage;
+ LIST_ENTRY BcastPktsList;
+ USHORT NicId;
+ } NIC_NODE, *PNIC_NODE;
+
+//***
+//
+// Function: AddRouteToBcastSndReq
+//
+// Descr: Builds a list of nodes where each node represents a
+// Nic. Each node has an attached list of broadcast packets
+// which contain the list of routes to be advertised.
+// At each invokation, the coresponding nic node is located
+// (or created) and the route information is set in the
+// broadcast packet attached to the node.
+//
+//***
+
+UINT
+AddRouteToBcastSndReq(PLIST_ENTRY nodelistp,
+ PIPX_ROUTE_ENTRY rtep)
+{
+ PLIST_ENTRY nextp;
+ PNIC_NODE nodep;
+ BOOLEAN found;
+ PRIP_UPDATE_SNDREQ respcbp = NULL; // ptr to changes response to bcast
+ PUCHAR hdrp; // Ipx pkt header
+ USHORT pktlen;
+ PLIST_ENTRY lep;
+
+ // traverse the nodes list looking for our nic id.
+ nextp = nodelistp->Flink;
+ found = FALSE;
+
+ while(nextp != nodelistp) {
+
+ nodep = CONTAINING_RECORD(nextp, NIC_NODE, NodeLinkage);
+ if(nodep->NicId == rtep->NicId) {
+
+ found = TRUE;
+ break;
+ }
+
+ nextp = nextp->Flink;
+ }
+
+ if(!found) {
+
+ // create the node we need
+ if((nodep = ExAllocatePool(NonPagedPool, sizeof(NIC_NODE))) == NULL) {
+
+ // can't create the node
+ return 1;
+ }
+
+ InitializeListHead(&nodep->BcastPktsList);
+ nodep->NicId = rtep->NicId;
+
+ // create a send bcast request structure and add it to the node
+ if((respcbp = ExAllocatePool(NonPagedPool,
+ sizeof(RIP_UPDATE_SNDREQ) + RIP_SNDPKT_MAXLEN)) == NULL) {
+
+ // free the node
+ ExFreePool(nodep);
+ return 1;
+ }
+
+ InsertTailList(&nodep->BcastPktsList, &respcbp->RipSndReq.NicLinkage);
+
+ // get the Ipx packet length and Ipx packet header
+ hdrp = (PUCHAR)respcbp->RipSndPktBuff.IpxPacket;
+ pktlen = RIP_INFO;
+
+ // now add the node to the nodes list
+ InsertTailList(nodelistp, &nodep->NodeLinkage);
+
+ }
+ else
+ {
+ // we found the node
+ // now go to the last packet in the node and check if there is room for
+ // a network entry
+ ASSERT(!IsListEmpty(&nodep->BcastPktsList));
+ lep = nodep->BcastPktsList.Blink;
+ respcbp = CONTAINING_RECORD(lep, RIP_UPDATE_SNDREQ, RipSndReq.NicLinkage);
+
+ // get IPX packet length
+ hdrp = (PUCHAR)respcbp->RipSndPktBuff.IpxPacket;
+ GETSHORT2USHORT(&pktlen, hdrp + IPXH_LENGTH);
+
+ if(pktlen >= RIP_RESPONSE_PACKET_LEN) {
+
+ // this packet is full
+ // create a new send bcast request structure and add it to the node
+ if((respcbp = ExAllocatePool(NonPagedPool,
+ sizeof(RIP_UPDATE_SNDREQ) + RIP_SNDPKT_MAXLEN)) == NULL) {
+
+ return 1;
+ }
+
+ InsertTailList(&nodep->BcastPktsList, &respcbp->RipSndReq.NicLinkage);
+
+ // get the Ipx packet length and Ipx packet header
+ hdrp = (PUCHAR)respcbp->RipSndPktBuff.IpxPacket;
+ pktlen = RIP_INFO;
+ }
+ }
+
+ // add the new route entry to the bcast pkt
+ SetNetworkEntry(hdrp + pktlen, rtep);
+
+ // increment the packet length and put it in the packet
+ pktlen += NE_ENTRYSIZE;
+ PUTUSHORT2SHORT(hdrp + IPXH_LENGTH, pktlen);
+
+ RtPrint(DBG_RIPAUX, ("IpxRouter: AddRouteToBcastSndReq: net entry added for NicId %d\n", nodep->NicId));
+
+ return 0;
+}
+
+//***
+//
+// Function: GetBcastSndReq
+//
+// Descr: For each call it tries to remove one broadcast packet
+// from the list. If the nic node list of packets is empty
+// after the removeal, the nic node is freed.
+//
+//***
+
+PRIP_SNDREQ
+GetBcastSndReq(PLIST_ENTRY nodelistp,
+ PUSHORT NicIdp)
+{
+ PNIC_NODE nodep;
+ PRIP_SNDREQ sndreqp;
+ PLIST_ENTRY lep;
+
+ if(IsListEmpty(nodelistp)) {
+
+ return NULL;
+ }
+
+ lep = nodelistp->Flink;
+ nodep = CONTAINING_RECORD(lep, NIC_NODE, NodeLinkage);
+
+ ASSERT(!IsListEmpty(&nodep->BcastPktsList));
+
+ lep = RemoveHeadList(&nodep->BcastPktsList);
+ sndreqp = CONTAINING_RECORD(lep, RIP_SNDREQ, NicLinkage);
+ *NicIdp = nodep->NicId;
+
+ if(IsListEmpty(&nodep->BcastPktsList)) {
+
+ RemoveEntryList(&nodep->NodeLinkage);
+ ExFreePool(nodep);
+ }
+
+ RtPrint(DBG_RIPAUX, ("IpxRouter: GetBcastSndReq: got snd req pkt for NicId %d\n", *NicIdp));
+
+ return sndreqp;
+}
+
+//***
+//
+// Function: BroadcastRipUpdate
+//
+// Descr: Set up the snd req for this bcast and dispatch it.
+// If wait on event is requested, wait until send completes.
+//
+//***
+
+VOID
+BroadcastRipUpdate(PRIP_SNDREQ sndreqp, // send request
+ PNICCB niccbp, // do not send on this nic
+ PKEVENT eventp) // wait if this event is not NULL
+{
+ sndreqp->SndReqId = RIP_UPDATE;
+ sndreqp->SendOnAllNics = TRUE;
+ memcpy(sndreqp->DestNode, bcastaddress, IPX_NODE_LEN);
+ sndreqp->DestSock = IPX_RIP_SOCKET;
+ sndreqp->DoNotSendNicCbp = niccbp; // do not send update on this nic
+ sndreqp->SenderNicCbp = NULL;
+
+ sndreqp->SndCompleteEventp = eventp;
+
+ if(eventp != NULL) {
+
+ // WAIT on event after the bcast req is dispatched.
+ KeResetEvent(eventp);
+
+ // dispatch the bcast request
+ RipDispatchSndReq(sndreqp);
+
+ // wait for this request to complete.
+ KeWaitForSingleObject(
+ eventp,
+ Executive,
+ KernelMode,
+ FALSE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ KeResetEvent(eventp);
+
+ }
+ else
+ {
+ // NO WAIT -> dispatch the bcast request and return
+ RipDispatchSndReq(sndreqp);
+ }
+}
+
+//***
+//
+// Function: BroadcastRipGeneralResponse
+//
+// Descr: Set up the snd req for this bcast and dispatch it.
+//
+//***
+
+VOID
+BroadcastRipGeneralResponse(PRIP_SNDREQ sndreqp)
+{
+ sndreqp->SndReqId = RIP_GEN_RESPONSE;
+ sndreqp->SendOnAllNics = TRUE; // send on all
+ memcpy(sndreqp->DestNode, bcastaddress, IPX_NODE_LEN);
+ sndreqp->DestSock = IPX_RIP_SOCKET;
+ sndreqp->DoNotSendNicCbp = NULL; // send without exception
+ sndreqp->SenderNicCbp = NULL;
+ sndreqp->SndCompleteEventp = NULL;
+
+ RipDispatchSndReq(sndreqp);
+}
+
+
+//***
+//
+// Function: BroadcastWanNetUpdate
+//
+// Descr: Broadcasts RIP update for one WAN network entry
+//
+//***
+
+VOID
+BroadcastWanNetUpdate(PIPX_ROUTE_ENTRY rtep, // route entry to bcast
+ PNICCB niccbp, // do not send on this nic
+ PKEVENT eventp) // synch event
+{
+ PRIP_UPDATE_SNDREQ respcbp = NULL; // ptr to changes response to bcast
+ PUCHAR sndhdrp;
+ USHORT sndpktlen;
+ PRIP_SNDREQ sndreqp;
+
+ // allocate a send request struct to bcast changes in the routing table
+ if((respcbp = ExAllocatePool(NonPagedPool,
+ sizeof(RIP_UPDATE_SNDREQ) + RIP_SNDPKT_MINLEN)) == NULL) {
+ //!!!
+ return;
+ }
+
+ // get the ipx hdr ptr for the send packet
+ sndhdrp = (PUCHAR)respcbp->RipSndPktBuff.IpxPacket;
+
+ // set the initial length
+ sndpktlen = RIP_INFO;
+
+ // fill in the network entry structure in the packet with the
+ // info from the route entry
+ SetNetworkEntry(sndhdrp + sndpktlen, rtep);
+
+ // increment the send packet length to the next network entry
+ sndpktlen += NE_ENTRYSIZE;
+
+ // set the new packet length
+ PUTUSHORT2SHORT(sndhdrp + IPXH_LENGTH, sndpktlen);
+
+ // set up the request to send a bcast response with the changes
+ sndreqp = &respcbp->RipSndReq;
+
+ BroadcastRipUpdate(sndreqp, niccbp, eventp);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//*** Routines for handling the hash table of node numbers -> nic ptrs mapping.
+
+// The WAN nodes hash table
+
+NDIS_SPIN_LOCK WanNodeHTLock;
+
+LIST_ENTRY WanNodeHT[NODE_HTSIZE];
+
+//***
+//
+// Function: InitWanNodeHT
+//
+// Descr:
+//
+//***
+
+VOID
+InitWanNodeHT(VOID)
+{
+ int i;
+ PLIST_ENTRY WanNodeHTBucketp;
+
+ INITIALIZE_SPIN_LOCK(&WanNodeHTLock);
+
+ WanNodeHTBucketp = WanNodeHT;
+
+ for(i=0; i<NODE_HTSIZE; i++, WanNodeHTBucketp++) {
+
+ InitializeListHead(WanNodeHTBucketp);
+ }
+}
+
+
+//***
+//
+// Function: ndhash
+//
+// Descr: compute the hash index for this node
+//
+//***
+
+int
+ndhash(PUCHAR nodep)
+{
+ USHORT ndindex = 6;
+ int hv = 0; // hash value
+
+ while(ndindex--) {
+
+ hv += nodep[ndindex] & 0xff;
+ }
+
+ return hv % NODE_HTSIZE;
+}
+
+//***
+//
+// Function: GetWanNodeNiccb
+//
+// Descr: get the nic CB for a given WAN node
+//
+//***
+
+PNICCB
+GetWanNodeNiccbp(PUCHAR nodep)
+{
+ int hv;
+ PLIST_ENTRY nextp;
+ PNICCB niccbp;
+
+ hv = ndhash(nodep);
+
+ ACQUIRE_SPIN_LOCK(&WanNodeHTLock);
+
+ // walk the niccbs list until we get to the node
+ nextp = WanNodeHT[hv].Flink;
+
+ while(nextp != &WanNodeHT[hv]) {
+
+ niccbp = CONTAINING_RECORD(nextp, NICCB, WanHtLinkage);
+
+ if(!memcmp(niccbp->RemoteNode, nodep, 6)) {
+
+ RELEASE_SPIN_LOCK(&WanNodeHTLock);
+ return niccbp;
+ }
+
+ nextp = niccbp->WanHtLinkage.Flink;
+ }
+
+ RELEASE_SPIN_LOCK(&WanNodeHTLock);
+
+ return NULL;
+}
+
+
+//***
+//
+// Function: AddWanNodeToHT
+//
+// Descr: Inserts a new node in the WAN nodes Hash Table
+//
+//***
+
+VOID
+AddWanNodeToHT(PNICCB niccbp)
+{
+ int hv;
+
+ hv = ndhash(niccbp->RemoteNode);
+
+ ACQUIRE_SPIN_LOCK(&WanNodeHTLock);
+
+ InsertTailList(&WanNodeHT[hv], &niccbp->WanHtLinkage);
+
+ RELEASE_SPIN_LOCK(&WanNodeHTLock);
+}
+
+//***
+//
+// Function: RemoveWanNodeFromHT
+//
+// Descr: Removes a WAN node from the WAN nodes Hash Table
+//
+//***
+
+VOID
+RemoveWanNodeFromHT(PNICCB niccbp)
+{
+ int hv;
+
+ hv = ndhash(niccbp->RemoteNode);
+
+ ACQUIRE_SPIN_LOCK(&WanNodeHTLock);
+
+ RemoveEntryList(&niccbp->WanHtLinkage);
+
+ RELEASE_SPIN_LOCK(&WanNodeHTLock);
+}
diff --git a/private/ntos/tdi/isn/rip/ripproc.c b/private/ntos/tdi/isn/rip/ripproc.c
new file mode 100644
index 000000000..dc98e307d
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/ripproc.c
@@ -0,0 +1,745 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: ripproc.c
+//
+// Description: process rip packets
+//
+// Author: Stefan Solomon (stefans) October 11, 1993.
+//
+// Revision History:
+//
+//***
+
+#include "rtdefs.h"
+
+VOID
+RipRequest(PPACKET_TAG pktp);
+
+VOID
+RipResponse(PPACKET_TAG pktp);
+
+VOID
+SetNetworkEntry(PUCHAR nep,
+ PIPX_ROUTE_ENTRY rtep);
+
+//***
+//
+// Function: ProcessRipPacket
+//
+// Descr:
+//
+// Params: Packet
+//
+// Returns: none
+//
+//***
+
+VOID
+ProcessRipPacket(PPACKET_TAG pktp)
+{
+ USHORT opcode;
+ PUCHAR hdrp; // ptr to the packet header
+
+ // get a ptr to the packet header
+ hdrp = pktp->DataBufferp;
+
+ // check the RIP operation type
+ GETSHORT2USHORT(&opcode, hdrp + RIP_OPCODE);
+
+ switch(opcode) {
+
+ case RIP_REQUEST:
+
+ RipRequest(pktp);
+ break;
+
+ case RIP_RESPONSE:
+
+ RipResponse(pktp);
+ break;
+
+ default:
+
+ // this is an invalid frame
+
+ RtPrint(DBG_NOTIFY, ("IpxRouter: ProcessRipPacket: Reject invalid frame\n"));
+ FreeRcvPkt(pktp);
+ break;
+ }
+}
+
+//***
+//
+// Function: RipRequest
+//
+// Descr: process the RIP request
+//
+//***
+
+VOID
+RipRequest(PPACKET_TAG pktp)
+{
+ USHORT reqlen; // offset to get next request
+ USHORT resplen; // offset to put next response
+ USHORT pktlen; // packet length
+ PUCHAR hdrp; // ptr to the packet header
+ PNICCB niccbp; // ptr to nic ctrl blk that received this packet
+ PNICCB rtniccbp;
+ PIPX_ROUTE_ENTRY rtep;
+ KIRQL oldirql;
+ PRIP_SNDREQ respcbp;
+ UINT segment;
+ BOOLEAN PingRouter = FALSE;
+
+ RtPrint(DBG_RIP, ("IpxRouter: RipRequest: Entered\n"));
+
+ // get a ptr to the packet owner Nic
+ niccbp = pktp->PacketOwnerNicCbp;
+
+ // if there is no network number for this NIC we don't reply to this RIP
+ // request
+ if(!memcmp(niccbp->Network, nulladdress, IPX_NET_LEN)) {
+
+ RtPrint(DBG_NOTIFY, ("IpxRouter: Cannot reply to RIP request on unnumbered net for NIC %d\n",
+ niccbp->NicId));
+
+ // free the packet buffer and return
+ FreeRcvPkt(pktp);
+
+ return;
+ }
+
+ // get a ptr to the packet header
+ hdrp = pktp->DataBufferp;
+
+ // get IPX packet length
+ GETSHORT2USHORT(&pktlen, hdrp + IPXH_LENGTH);
+
+ // We may have one or more network entry requests in the packet.
+ // If one network entry is 0xFFFFFFFF, then a general RIP response is
+ // requested.
+
+ // for each network entry, try to get the answer from our routing table
+ for(reqlen = resplen = RIP_INFO;
+ reqlen < pktlen;
+ reqlen += NE_ENTRYSIZE) {
+
+ // check if a general response is requested
+ if(!memcmp(hdrp + reqlen + NE_NETNUMBER, bcastaddress, IPX_NET_LEN)) {
+
+ // queue a req for rip gen response for this net and free the packet.
+ // the req will be dequeued and processed by the rip response
+ // thread.
+ if((respcbp = ExAllocatePool(NonPagedPool,
+ sizeof(RIP_SNDREQ))) != NULL) {
+
+ // set up the send request
+ respcbp->SndReqId = RIP_GEN_RESPONSE;
+ respcbp->SendOnAllNics = FALSE; // send only to requesting node
+ // fill in the sending node address, to be used in the response
+ memcpy(respcbp->DestNode, hdrp + IPXH_SRCNODE, 6);
+
+ // fill in the sending socket to be used in the response
+ GETSHORT2USHORT(&respcbp->DestSock, hdrp + IPXH_SRCSOCK);
+
+ respcbp->DoNotSendNicCbp = NULL;
+ respcbp->SenderNicCbp = niccbp;
+ respcbp->SndCompleteEventp = NULL;
+
+ if(!RipQueueSndReqAtNic(niccbp, respcbp)) {
+
+ // can't queue this request
+ ExFreePool(respcbp);
+ respcbp = NULL;
+ }
+ }
+
+ FreeRcvPkt(pktp);
+ return;
+ }
+
+ //*** a specific response is requested. ***
+ // if the requested network number is 0, we replace it with
+ // the network segment the packet was received on:
+ if(!memcmp(hdrp + reqlen + NE_NETNUMBER, nulladdress, IPX_NET_LEN)) {
+
+ RtPrint(DBG_RIP, ("IpxRouter: RipRequest: request info on directly attached net\n"));
+ memcpy(hdrp + reqlen + NE_NETNUMBER, niccbp->Network, IPX_NET_LEN);
+ PingRouter = TRUE;
+ }
+
+ segment = IpxGetSegment(hdrp + reqlen + NE_NETNUMBER);
+
+ // LOCK THE ROUTING TABLE
+ ExAcquireSpinLock(&SegmentLocksTable[segment], &oldirql);
+
+ if(rtep = IpxGetRoute(segment, hdrp + reqlen + NE_NETNUMBER)) {
+
+ // check if we can route the packet
+ // the route should be on a different nic id than the received
+ // packet. For the global WAN net, rtep->NicId = 0xFFFE !
+ if(rtep->NicId != niccbp->NicId) {
+
+ // if the response will be sent on a WAN link then there
+ // is some filtering to do
+ if(niccbp->DeviceType == NdisMediumWan) {
+
+ // check if the target net is the global WAN net
+ if(!(rtep->Flags & IPX_ROUTER_GLOBAL_WAN_NET)) {
+
+ // This is a request received on WAN and the target is not
+ // the global WAN net
+ rtniccbp = NicCbPtrTab[rtep->NicId];
+
+ // check if the target net is visible via a WAN-Disabled LAN
+ if((rtniccbp->DeviceType != NdisMediumWan) &&
+ (rtniccbp->WanRoutingDisabled)) {
+
+ // the target is a LAN disabled for WAN traffic
+ // skip it!
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
+
+ continue;
+ }
+
+ // check if the nic to send on is a WAN client.
+ if(niccbp->WanConnectionClient) {
+
+ // Check if LAN-WAN-LAN connectivity is enabled
+ if(!LanWanLan) {
+
+ // this node can only inform about its virtual net
+ if(rtniccbp->NicId != VirtualNicId) {
+
+ // skip it!
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
+
+ continue;
+ }
+ }
+ }
+ }
+ else
+ {
+ // this is a request received on WAN and the target is the
+ // global WAN net.
+
+ // check if the nic to send on doesn't have the same WAN address
+ if(!memcmp(rtep->Network, niccbp->Network, 4)) {
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
+
+ continue;
+ }
+
+ // check if the nic to send on is a WAN client.
+ if(niccbp->WanConnectionClient) {
+
+ // Check if LAN-WAN-LAN connectivity is enabled
+ if(!LanWanLan) {
+
+ // this node can only inform about its virtual net
+ // and the global net is not the virtual net
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
+
+ continue;
+ }
+ }
+ }
+ }
+ else
+ {
+ // The response will be sent on a LAN.
+
+ // if LAN to LAN routing is disabled and if the target
+ // route is from a LAN Nic, we do not repond to it
+ if(!EnableLanRouting) {
+
+ // LAN routing is disabled -> the only routes we can
+ // respond with are the virtual net or any WAN net
+ if(!(rtep->Flags & IPX_ROUTER_GLOBAL_WAN_NET)) {
+
+ // the target net is not the global wan net
+ // check if it is not the virtual net
+ if(rtep->NicId != VirtualNicId) {
+
+ // the target net is not the virtual net
+ // check the it is not a LAN net
+ if(NicCbPtrTab[rtep->NicId]->DeviceType != NdisMediumWan) {
+
+ // The target net is NOT:
+ // 1. the global wan net
+ // 2. the vitual net
+ // 3. a WAN net
+ // I.e. -> target is a LAN net -> do not answer
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
+
+ continue;
+ }
+ }
+ }
+ }
+
+ // if the destination nic is WAN and has a client role and
+ // LAN-WAN-LAN traffic is disabled, do not respond to it
+ if(!LanWanLan) {
+
+ if(!(rtep->Flags & IPX_ROUTER_GLOBAL_WAN_NET)) {
+
+ if( (NicCbPtrTab[rtep->NicId]->DeviceType == NdisMediumWan) &&
+ (NicCbPtrTab[rtep->NicId]->WanConnectionClient)) {
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
+
+ continue;
+ }
+ }
+ }
+
+ }
+
+ // we can route it -> answer to it
+ // fill in the network entry structure in the packet with the
+ // info from the route entry
+ SetNetworkEntry(hdrp + resplen, rtep);
+
+ // increment the response length to the next response entry
+ resplen += NE_ENTRYSIZE;
+ }
+
+ if(PingRouter) {
+
+ // answer to the ping request
+ SetNetworkEntry(hdrp + resplen, rtep);
+
+ // increment the response length to the next response entry
+ resplen += NE_ENTRYSIZE;
+ }
+ }
+
+ PingRouter = FALSE;
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
+ }
+
+ // We are done answering this request.
+ // Check if any response has been generated
+ if(resplen == RIP_INFO) {
+
+ // no response generated for this packet
+ RtPrint(DBG_RIP, ("IpxRouter: RipRequest: no response send for this request\n"));
+ FreeRcvPkt(pktp);
+ return;
+ }
+
+ // Turn the packet around and send it. This is done by changing the
+ // packet's src and dest nodes and sockets. (src and dst net are the same)
+ memcpy(hdrp + IPXH_DESTNODE, hdrp + IPXH_SRCNODE, 6);
+ memcpy(hdrp + IPXH_SRCNODE, niccbp->Node, 6);
+
+ memcpy(hdrp + IPXH_DESTSOCK, hdrp + IPXH_SRCSOCK, 2);
+ PUTUSHORT2SHORT(hdrp + IPXH_SRCSOCK, IPX_RIP_SOCKET);
+
+ // change the packet type to RIP response
+ PUTUSHORT2SHORT(hdrp + RIP_OPCODE, RIP_RESPONSE);
+
+ // set the new packet length
+ PUTUSHORT2SHORT(hdrp + IPXH_LENGTH, resplen);
+
+ // prepare remote address structure in the packet tag to send the packet
+ pktp->RemoteAddress.NicId = niccbp->NicId;
+ memcpy(pktp->RemoteAddress.MacAddress, hdrp + IPXH_DESTNODE, 6);
+
+ // Send the packet. The packet will be freed when send completes.
+ RtPrint(DBG_RIP, ("IpxRouter: RipRequest: send response send for this request\n"));
+
+ SendPacket(pktp);
+}
+
+//***
+//
+// Function: RipResponse
+//
+// Descr: Updates the routing table with the response info
+//
+// Params: Packet
+//
+// Returns: none
+//
+//***
+
+VOID
+RipResponse(PPACKET_TAG pktp)
+{
+ USHORT resplen; // offset of the next response network entry
+ USHORT pktlen; // IPX packet length
+ PUCHAR hdrp; // ptr to the packet header
+ PNICCB niccbp; // ptr to the nic ctrl blk the packet that
+ // received the packet
+ PIPX_ROUTE_ENTRY oldrtep, newrtep; // new and old routing tab entries
+ KIRQL oldirql;
+ USHORT nrofhops;
+ BOOLEAN RouteDown;
+ PRIP_UPDATE_SNDREQ respcbp = NULL; // ptr to changes response to bcast
+ PRIP_SNDREQ sndreqp;
+ PUCHAR sndhdrp;
+ USHORT sndpktlen;
+ UINT segment;
+ USHORT tickcount;
+
+#if DBG
+ UCHAR b[6];
+#endif
+
+ RtPrint(DBG_RIP, ("IpxRouter: RipResponse: Entered\n"));
+
+ // get a ptr to this Nic
+ niccbp = pktp->PacketOwnerNicCbp;
+
+ // get a ptr to the received response packet header
+ hdrp = pktp->DataBufferp;
+
+ // get received response packet length
+ GETSHORT2USHORT(&pktlen, hdrp + IPXH_LENGTH);
+
+ // For each network entry, check if we have it in our routing table.
+ // If we do not have this entry or if
+ // it is a better entry than what we have, we add it to the routing table
+ // !!! for this primary version, we don't care about better entries !!!
+
+ for(resplen = RIP_INFO;
+ resplen < pktlen;
+ resplen += NE_ENTRYSIZE) {
+
+ newrtep = NULL;
+ // check if the network route is up or down
+ GETSHORT2USHORT(&nrofhops, hdrp + resplen + NE_NROFHOPS);
+
+ if(nrofhops < 16) {
+
+ RouteDown = FALSE;
+ }
+ else
+ {
+ RouteDown = TRUE;
+ }
+
+ segment = IpxGetSegment(hdrp + resplen + NE_NETNUMBER);
+
+ // LOCK THE ROUTING TABLE
+ ExAcquireSpinLock(&SegmentLocksTable[segment], &oldirql);
+
+ // check if the entry exists.
+ if((oldrtep = IpxGetRoute(segment, hdrp + resplen + NE_NETNUMBER)) == NULL) {
+
+ //*** This route does not exist ***
+
+ // if this is a route down bcast and we didn't have this route
+ // we skip this information
+ if(RouteDown) {
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
+
+ continue;
+ }
+
+ // if this is a route with 15 hops, we choose for now to ignore
+ // it.
+ if(nrofhops == 15) {
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
+
+ continue;
+ }
+
+ // This is a new route. We add this route to the routing table
+ if(newrtep = ExAllocatePool(NonPagedPool, sizeof(IPX_ROUTE_ENTRY))) {
+
+ // set it up
+ memcpy(newrtep->Network, hdrp + resplen + NE_NETNUMBER, IPX_NET_LEN);
+ newrtep->NicId = niccbp->NicId;
+ memcpy(newrtep->NextRouter, hdrp + IPXH_SRCNODE, IPX_NODE_LEN);
+ newrtep->Flags = 0;
+ newrtep->Timer = 0; // TTL of this route entry is 3 min
+ newrtep->Segment = segment;
+ GETSHORT2USHORT(&newrtep->TickCount, hdrp + resplen + NE_NROFTICKS);
+ GETSHORT2USHORT(&newrtep->HopCount, hdrp + resplen + NE_NROFHOPS);
+
+ // increment the hop count to reflect our new router in the path
+ // the tick count received from the other router includes the
+ // nr of ticks on the network segment it was sent, so no adjust
+ // is necessary
+ newrtep->HopCount++;
+
+ InitializeListHead(&newrtep->AlternateRoute);
+
+ // add it to the table
+ IpxAddRoute(segment, newrtep);
+ }
+ }
+ else
+ {
+ //
+ //*** This route exists in our routing table ***
+ //
+
+ // first check if the response is coming from
+ // the same router as the one which we got the route from
+ if(memcmp(oldrtep->NextRouter, hdrp + IPXH_SRCNODE, IPX_NODE_LEN)) {
+
+ //
+ //** This is a response from another router for the same network
+ //
+
+ // check if the response is : route unreachable
+ if(RouteDown) {
+
+ // useless response -> discard it!
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
+#if DBG
+ memcpy(b, hdrp + resplen + NE_NETNUMBER, 4);
+#endif
+ continue;
+ }
+
+ // if the route is not down but this is a better route, add it
+ // instead.
+
+ // Check if this is a better route
+ GETSHORT2USHORT(&tickcount, hdrp + resplen + NE_NROFTICKS);
+ if(tickcount >= oldrtep->TickCount) {
+
+ // same or worse route, ignore it!
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
+#if DBG
+ memcpy(b, hdrp + resplen + NE_NETNUMBER, 4);
+#endif
+
+ continue;
+ }
+
+ // Ignore this response if it refers to a permanent/local
+ // net
+ if((oldrtep->Flags & IPX_ROUTER_PERMANENT_ENTRY) ||
+ (oldrtep->Flags & IPX_ROUTER_LOCAL_NET)) {
+
+ // skip this route!
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
+ continue;
+ }
+
+ // We have a better route
+ // Just copy the new route over the old route entry
+ // we do not modify the network and segment fields
+
+ oldrtep->NicId = niccbp->NicId;
+ memcpy(oldrtep->NextRouter, hdrp + IPXH_SRCNODE, IPX_NODE_LEN);
+ oldrtep->Flags = 0;
+ oldrtep->Timer = 0; // TTL of this route entry is 3 min
+ GETSHORT2USHORT(&oldrtep->TickCount, hdrp + resplen + NE_NROFTICKS);
+ GETSHORT2USHORT(&oldrtep->HopCount, hdrp + resplen + NE_NROFHOPS);
+
+ // increment the hop count to reflect our new router in the path
+ // the tick count received from the other router includes the
+ // nr of ticks on the network segment it was sent, so no adjust
+ // is necessary
+ oldrtep->HopCount++;
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
+#if DBG
+ memcpy(b, hdrp + resplen + NE_NETNUMBER, 4);
+#endif
+
+ continue;
+ }
+
+ //
+ //*** This response comes from the same router as the one which gave
+ //*** us this route entry initially
+ //
+
+ // First -> reset the aging timer
+ oldrtep->Timer = 0;
+
+ // if the info tells us that the route is down, we should delete
+ // the route from the routing table and inform all other routers
+ // of the change
+ if(RouteDown) {
+
+ // this may be a bogus packet from the wire
+ if((oldrtep->Flags & IPX_ROUTER_PERMANENT_ENTRY) ||
+ (oldrtep->Flags & IPX_ROUTER_LOCAL_NET)) {
+
+#if DBG
+ memcpy(b, hdrp + IPXH_SRCNODE, 6);
+#endif
+ RtPrint(DBG_NOTIFY, ("IpxRouter: RipResponse: Bogus resp permanent route down from %x-%x-%x-%x-%x-%x !!\n",
+ b[0],b[1],b[2],b[3],b[4],b[5]));
+
+ RouteDown = FALSE;
+ }
+ else
+ {
+ IpxDeleteRoute(segment, oldrtep);
+
+ // set the nr of hops to 16 in the route entry; used later to
+ // bcast the change
+ oldrtep->HopCount = 16;
+ }
+ }
+ else
+ {
+ // update hop and tick counts
+ GETSHORT2USHORT(&oldrtep->TickCount, hdrp + resplen + NE_NROFTICKS);
+ GETSHORT2USHORT(&oldrtep->HopCount, hdrp + resplen + NE_NROFHOPS);
+
+ // increment the hop count to reflect our new router in the path
+ // the tick count received from the other router includes the
+ // nr of ticks on the network segment it was sent, so no adjust
+ // is necessary
+ oldrtep->HopCount++;
+ }
+ }
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
+
+ // if the rip response packet is bigger than the standard length we will
+ // fragment the bcast update and broadcast it with the rip timer
+ if(pktlen > RIP_RESPONSE_PACKET_LEN) {
+
+ if(oldrtep && RouteDown) {
+
+ ExFreePool(oldrtep);
+ }
+
+ continue;
+ }
+
+ // if the RIP response packet comes from a LAN and if the LAN to LAN
+ // routing is disabled, we won't broadcast any update. This is so because:
+ // 1. We don't broadcast updates on WAN
+ // 2. We broadcast only WAN updates on LAN if LAN routing disabled
+ if((!EnableLanRouting) &&
+ (niccbp->DeviceType != NdisMediumWan)) {
+
+ if(oldrtep && RouteDown) {
+
+ ExFreePool(oldrtep);
+ }
+
+ continue;
+ }
+
+ // check if we will broadcast any change now and if a bcast packet
+ // request + buffer have been allocated
+ if (newrtep || (oldrtep && RouteDown)) {
+
+ // check if a send bcast req struct has already been allocated
+ if(respcbp == NULL) {
+
+ // allocate a send request struct to bcast changes in the routing table
+ respcbp = ExAllocatePool(NonPagedPool,
+ sizeof(RIP_UPDATE_SNDREQ) + RIP_SNDPKT_MAXLEN);
+
+ if(respcbp != NULL) {
+
+ // get the ipx hdr ptr for the send packet
+ sndhdrp = (PUCHAR)respcbp->RipSndPktBuff.IpxPacket;
+
+ // set the initial length
+ sndpktlen = RIP_INFO;
+ }
+ }
+ }
+
+ // check if we have added a new route or deleted an old one
+ if(newrtep) {
+
+ // write the network entry for this new route in the packet to be
+ // sent
+ if(respcbp) {
+
+ // fill in the network entry structure in the packet with the
+ // info from the route entry
+ SetNetworkEntry(sndhdrp + sndpktlen, newrtep);
+
+ // increment the send packet length to the next network entry
+ sndpktlen += NE_ENTRYSIZE;
+ }
+ }
+ else
+ {
+ // check if an old route has been deleted
+ if(oldrtep && RouteDown) {
+
+ // write the network entry for this old route in the packet to be
+ // sent
+ if(respcbp) {
+
+ // fill in the network entry structure in the packet with the
+ // info from the route entry
+ SetNetworkEntry(sndhdrp + sndpktlen, oldrtep);
+
+ // increment the send packet length to the next network entry
+ sndpktlen += NE_ENTRYSIZE;
+
+ ExFreePool(oldrtep);
+ }
+ }
+ }
+ }
+
+ // if we have added or deleted some routes, we make a request to the rip bcast
+ // thread to have them bcasted over to the other nics
+
+ if(respcbp) {
+
+ // Send a bcast update with the changes to all the nics except this one
+ sndreqp = &respcbp->RipSndReq;
+ // set the new packet length
+ PUTUSHORT2SHORT(sndhdrp + IPXH_LENGTH, sndpktlen);
+
+ BroadcastRipUpdate(sndreqp, niccbp, NULL);
+ }
+
+ // free the packet
+ FreeRcvPkt(pktp);
+}
+
+
+//***
+//
+// Function: SetNetworkEntry
+//
+// Descr:
+//
+//***
+
+VOID
+SetNetworkEntry(PUCHAR nep, // points to the network entry in the
+ // RIP packet
+ PIPX_ROUTE_ENTRY rtep)
+{
+ memcpy(nep + NE_NETNUMBER, rtep->Network, IPX_NET_LEN);
+ PUTUSHORT2SHORT(nep + NE_NROFHOPS, rtep->HopCount);
+ PUTUSHORT2SHORT(nep + NE_NROFTICKS, rtep->TickCount);
+}
diff --git a/private/ntos/tdi/isn/rip/ripsend.c b/private/ntos/tdi/isn/rip/ripsend.c
new file mode 100644
index 000000000..229388e6c
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/ripsend.c
@@ -0,0 +1,1176 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: ripsend.c
+//
+// Description: processes rip send requests queued at the different
+// queues: send all nets and send one net
+//
+// Author: Stefan Solomon (stefans) October 11, 1993.
+//
+// Revision History:
+//
+//***
+
+#include <memory.h>
+#include <string.h>
+#include "rtdefs.h"
+
+NDIS_SPIN_LOCK RipGlobalSndListLock;
+LIST_ENTRY RipGlobalSndList;
+
+// this global specifies the type of RIP updates on WAN.
+// For this first version it is set to 0 -> No Rip updates on WAN.
+ULONG RipWanUpdate;
+
+VOID
+StartRipSndAtNic(PVOID Parameter);
+
+VOID
+InterPktGapTimeout(PKDPC Dpc,
+ PVOID DefferedContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2);
+
+PNICCB
+GetFirstAvailabelNic(USHORT BaseNicId,
+ PNICCB DoNotSendNicCbp);
+
+UINT
+MakeRipSendPkts(PNICCB niccbp);
+
+UINT
+MakeRipGenResponsePkts(PNICCB niccbp);
+
+PPACKET_TAG
+AllocRipGenResponsePkt(PNICCB niccbp);
+
+UINT
+MakeRipUpdatePkt(PNICCB niccbp);
+
+UINT
+MakeRipGenRequestPkt(PNICCB niccbp);
+
+PPACKET_TAG
+CreateRipNdisPkt(PRIP_SNDPKT_BUFF rbp,
+ PNICCB niccbp);
+
+PRIP_SNDPKT_BUFF
+DestroyRipNdisPkt(PPACKET_TAG pktp);
+
+PNICCB
+GetFirstAvailableNic(USHORT BaseNicId,
+ PNICCB DoNotSendNicCbp);
+
+
+VOID
+StartInterPktGapTimer(PNICCB niccbp);
+
+VOID
+SetRipIpxHeader(PUCHAR hdrp, // pointer to the packet header
+ PNICCB niccbp, // pointer to the rip send request
+ USHORT RipOpcode);
+
+VOID
+SetRipRemoteAddress(PPACKET_TAG pktp,
+ PNICCB niccbp);
+
+//***
+//
+// Function: InitRipSndDispatcher
+//
+// Descr: initializes the global Rip send dispatcher
+//
+// Params: none
+//
+// Returns: none
+//
+//***
+
+VOID
+InitRipSndDispatcher(VOID)
+{
+ INITIALIZE_SPIN_LOCK(&RipGlobalSndListLock);
+ InitializeListHead(&RipGlobalSndList);
+}
+
+//***
+//
+// Function: InitRipSndAtNic
+//
+// Descr: Called at nic init time.
+// Initializes the nic based Rip send machine
+//
+// Params: none
+//
+// Returns: none
+//
+//***
+
+
+VOID
+InitRipSndAtNic(PNICCB niccbp)
+{
+ InitializeListHead(&niccbp->RipSendQueue);
+
+ // set the rip send machine to IDLE state
+ niccbp->RipSndReqp = NULL;
+
+ InitializeListHead(&niccbp->RipSndPktsList);
+
+ ExInitializeWorkItem(&niccbp->RipSndReqWorkItem, StartRipSndAtNic, niccbp);
+
+ KeInitializeDpc(&niccbp->InterPktGapDpc, InterPktGapTimeout, niccbp);
+ KeInitializeTimer(&niccbp->InterPktGapTimer);
+}
+
+//***
+//
+// Function: RipDispatchSndReq
+//
+// Descr:
+//
+//***
+
+VOID
+RipDispatchSndReq(PRIP_SNDREQ sndreqp)
+{
+ PNICCB niccbp;
+
+ RtPrint(DBG_SNDREQ, ("IpxRouter: RipDispatchSndReq: Entered\n"));
+
+ // get the first available nic to get the send request
+ // a non-null value in the DoNotSendNicCbp indicates we should not use
+ // this nic as a sender
+ niccbp = GetFirstAvailableNic(0, sndreqp->DoNotSendNicCbp);
+ if(niccbp == NULL) {
+
+ // if this was an update AND we are unloading AND event has to be
+ // signaled, do it
+ if((sndreqp->SndReqId == RIP_UPDATE) &&
+ (sndreqp->SndCompleteEventp != NULL) &&
+ RouterUnloading) {
+
+ KeSetEvent(sndreqp->SndCompleteEventp, 0L, FALSE);
+ }
+
+ ExFreePool(sndreqp);
+ return;
+ }
+ ACQUIRE_SPIN_LOCK(&RipGlobalSndListLock);
+
+ InsertTailList(&RipGlobalSndList, &sndreqp->GlobalLinkage);
+
+ RELEASE_SPIN_LOCK(&RipGlobalSndListLock);
+
+ sndreqp->SenderNicCbp = niccbp;
+ if(!RipQueueSndReqAtNic(niccbp, sndreqp)) {
+
+ // can't dispatch to this nic, call completion
+ RipSendAtNicCompleted(sndreqp);
+ }
+}
+
+
+VOID
+RipSendAtNicCompleted(PRIP_SNDREQ sndreqp)
+{
+ BOOLEAN Done = FALSE; // we are done with this snd req
+ BOOLEAN QueuedAtNic = FALSE; // request queued at a nic
+ PNICCB niccbp;
+
+ RtPrint(DBG_SNDREQ, ("IpxRouter: RipSendAtNicCompleted: Entered for NicId %d\n", sndreqp->SenderNicCbp->NicId));
+
+ if(!sndreqp->SendOnAllNics) {
+
+ // this request had to be sent on one nic only and is now terminated
+ Done = TRUE;
+ }
+ else
+ {
+ // this request has to be sent on all nics
+ // loop until the request is queued at a nic OR there are no more
+ // nics available
+ while(!Done && !QueuedAtNic) {
+
+ // get the next available nic to get the send request
+ niccbp = GetFirstAvailableNic(sndreqp->SenderNicCbp->NicId,
+ sndreqp->DoNotSendNicCbp);
+ if(niccbp == NULL) {
+
+ // No nic available
+ ACQUIRE_SPIN_LOCK(&RipGlobalSndListLock);
+
+ RemoveEntryList(&sndreqp->GlobalLinkage);
+
+ RELEASE_SPIN_LOCK(&RipGlobalSndListLock);
+ Done = TRUE;
+ }
+ else
+ {
+ sndreqp->SenderNicCbp = niccbp;
+ QueuedAtNic = RipQueueSndReqAtNic(niccbp, sndreqp);
+ }
+ }
+ }
+
+ if(Done) {
+
+ // if this was an update and we are unloading and event has to be
+ // signaled, do it
+ if((sndreqp->SndReqId == RIP_UPDATE) &&
+ (sndreqp->SndCompleteEventp != NULL) &&
+ RouterUnloading) {
+
+ KeSetEvent(sndreqp->SndCompleteEventp, 0L, FALSE);
+ }
+
+ ExFreePool(sndreqp);
+ }
+}
+
+//***
+//
+// Function: RipQueueSndReqAtNic
+//
+// Descr: Queues the Rip send req at this nic for delivery
+// The Nic has been verified that is active prior to queueing
+//
+// Returns: TRUE - queued OK, FALSE - could not queue
+//
+//***
+
+BOOLEAN
+RipQueueSndReqAtNic(PNICCB niccbp,
+ PRIP_SNDREQ sndreqp)
+{
+ // check if we should start work right away or should queue it
+ // for deffered processing
+
+ ACQUIRE_SPIN_LOCK(&niccbp->NicLock);
+
+ // check if rip sending is enabled on this nic
+ if(niccbp->NicState != NIC_ACTIVE) {
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+
+ RtPrint(DBG_SNDREQ, ("IpxRouter: RipQueueSndReqAtNic: NicId %d is closed or closing, cannot queue the snd req\n", niccbp->NicId));
+
+ return FALSE;
+ }
+
+ // check if the rip send machine is ACTIVE
+ if(niccbp->RipSndReqp != NULL) {
+
+ // the machine is ACTIVE processing another snd req; queue for later
+ InsertTailList(&niccbp->RipSendQueue, &sndreqp->NicLinkage);
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+
+ RtPrint(DBG_SNDREQ, ("IpxRouter: RipQueueSndReqAtNic: Queued for NicId %d\n", niccbp->NicId));
+
+ return TRUE;
+ }
+
+ // The RIP send machine for this Nic is IDLE. Activate it.
+ niccbp->RipSndReqp = sndreqp;
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+
+ RtPrint(DBG_SNDREQ, ("IpxRouter: RipQueueSndReqAtNic: Started for NicId %d\n", niccbp->NicId));
+
+ // if this is a directed response queue it in the critical, else noncritical
+ if((sndreqp->SndReqId == RIP_GEN_RESPONSE) &&
+ (memcmp(sndreqp->DestNode, bcastaddress, IPX_NODE_LEN))) {
+
+ ExQueueWorkItem(&niccbp->RipSndReqWorkItem, CriticalWorkQueue);
+ }
+ else
+ {
+ ExQueueWorkItem(&niccbp->RipSndReqWorkItem, DelayedWorkQueue);
+ }
+
+ return TRUE;
+}
+
+//***
+//
+// Function: StartRipSndAtNic
+//
+// Descr: This routine is the work item queued by
+// RipQueueSndReqAtNic when it starts the Rip Send Machine for
+// this Nic.
+//
+// Params: Ptr to the Nic
+//
+//***
+
+VOID
+StartRipSndAtNic(PVOID Parameter)
+{
+ PNICCB niccbp;
+ PLIST_ENTRY lep;
+ PPACKET_TAG pktp;
+
+ niccbp = (PNICCB)Parameter;
+
+ // check that the rip send machine has been activated
+ ASSERT(niccbp->RipSndReqp != NULL);
+
+ // allocate and prepare the packets for this send and queue them
+ // at the nic
+ while(MakeRipSendPkts(niccbp)) {
+
+ // No packets have been prepared. Notify the dispatcher that we are
+ // done with this request.
+ RipSendAtNicCompleted(niccbp->RipSndReqp);
+
+ // try to get the next send request queued at this nic
+ ACQUIRE_SPIN_LOCK(&niccbp->NicLock);
+
+ if(IsListEmpty(&niccbp->RipSendQueue)) {
+
+ // no more work for this Nic -> set it to IDLE state
+ niccbp->RipSndReqp = NULL;
+
+ // !!! announce the closing machine that the current Rip send processing has terminated !!!
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+ return;
+ }
+
+ // there are snd requests queued
+ lep = RemoveHeadList(&niccbp->RipSendQueue);
+
+ // set rip send machine to ACTIVE state
+ niccbp->RipSndReqp = CONTAINING_RECORD(lep, RIP_SNDREQ, NicLinkage);
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+ }
+
+ //*** send the first prepared packet ***
+
+ lep = RemoveHeadList(&niccbp->RipSndPktsList);
+ pktp = CONTAINING_RECORD(lep, PACKET_TAG, PacketLinkage);
+ SendPacket(pktp);
+}
+
+//***
+//
+// Function: SendRipPktCompleted
+//
+// Descr: This function is called by the send completion routine when
+// a Rip send packet has been completed.
+//
+//***
+
+VOID
+SendRipPktCompleted(PPACKET_TAG pktp)
+{
+ PNICCB niccbp;
+ PRIP_SNDPKT_BUFF rbp;
+
+ niccbp = pktp->PacketOwnerNicCbp;
+
+ // Destroy the ndis parts of the packet and get back the original snd pkt
+ // structure
+ rbp = DestroyRipNdisPkt(pktp);
+
+ // If this was not an update broadcast, release the send pkt buffer struct
+ if(niccbp->RipSndReqp->SndReqId != RIP_UPDATE) {
+
+ // free the snd pkt buffer
+ ExFreePool(rbp);
+ }
+
+ // set the machine to wait for a interpacket gap
+ StartInterPktGapTimer(niccbp);
+}
+
+//***
+//
+// Function: InterPktGapTimeout
+//
+// Descr: Called by the timer Nic interpacket gap timer DPC when the
+// interpacket gap timeout expired. Sends the next packet in the list
+//
+//***
+
+VOID
+InterPktGapTimeout(PKDPC Dpc,
+ PVOID DefferedContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2)
+{
+ PNICCB niccbp;
+ PLIST_ENTRY lep;
+ PPACKET_TAG pktp;
+
+ niccbp = (PNICCB)DefferedContext;
+
+ // check if we have more packets to send from this request
+ if(!IsListEmpty(&niccbp->RipSndPktsList)) {
+
+ // dequeue the first packet from the list and send it
+ lep = RemoveHeadList(&niccbp->RipSndPktsList);
+ pktp = CONTAINING_RECORD(lep, PACKET_TAG, PacketLinkage);
+
+ SendPacket(pktp);
+ return;
+ }
+
+ //*** This Rip send has been completed ***
+
+ // Notify the UPPER machine
+ RipSendAtNicCompleted(niccbp->RipSndReqp);
+
+ // check if there are more send requests queued
+ ACQUIRE_SPIN_LOCK(&niccbp->NicLock);
+
+ if(IsListEmpty(&niccbp->RipSendQueue)) {
+
+ // set the rip send machine to IDLE state
+ niccbp->RipSndReqp = NULL;
+
+ // !!! announce the closing machine that the current Rip send processing has terminated !!!
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+ return;
+ }
+ else
+ {
+ // there are snd requests queued
+ lep = RemoveHeadList(&niccbp->RipSendQueue);
+
+ // set the rip send machine to ACTIVE state
+ niccbp->RipSndReqp = CONTAINING_RECORD(lep, RIP_SNDREQ, NicLinkage);
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+ }
+
+ // start a new work item to take care of this send
+ // if this is a directed response queue it in the critical, else noncritical
+ if((niccbp->RipSndReqp->SndReqId == RIP_GEN_RESPONSE) &&
+ (memcmp(niccbp->RipSndReqp->DestNode, bcastaddress, IPX_NODE_LEN))) {
+
+ ExQueueWorkItem(&niccbp->RipSndReqWorkItem, CriticalWorkQueue);
+ }
+ else
+ {
+ ExQueueWorkItem(&niccbp->RipSndReqWorkItem, DelayedWorkQueue);
+ }
+}
+
+//***
+//
+// Function: GetFirstAvailableNic
+//
+// Descr: returns the nic cbp ptr of the first nic starting with the
+// specified base, which is not the src nic and which is active
+//
+//***
+
+PNICCB
+GetFirstAvailableNic(USHORT BaseNicId,
+ PNICCB DoNotSendNicCbp)
+{
+ USHORT i;
+ USHORT StartNicId;
+ PNICCB niccbp;
+
+ if(BaseNicId == 0) {
+
+ // we start from the beginning of the table
+ StartNicId = 0;
+ }
+ else
+ {
+ // check if this was the last nic
+ if(BaseNicId >= MaximumNicCount - 1) {
+
+ return NULL;
+ }
+
+ StartNicId = BaseNicId + 1;
+ }
+
+ for(i=StartNicId; i<MaximumNicCount; i++) {
+
+ niccbp = NicCbPtrTab[i];
+ if(niccbp->NicState == NIC_ACTIVE) {
+
+ // check if we should avoid this nic
+ if(DoNotSendNicCbp != NULL) {
+
+ if(niccbp->NicId == DoNotSendNicCbp->NicId) {
+
+ continue; // skip this nic
+ }
+ }
+
+ // if this nic doesn't have a net number, we don't
+ // send anything on it. (In other words, we are a ROUTER, we can't
+ // send rip packets with source net == 0)
+ if(!memcmp(niccbp->Network, nulladdress, IPX_NET_LEN)) {
+
+ continue; // skip this nic
+ }
+
+ // for LAN-WAN-LAN we should look at the RipWanUpdate parameter
+ // on how and what to send on WAN. For this version we just
+ // don't send anything on WAN, unless we received a request for it
+ if(niccbp->DeviceType == NdisMediumWan) {
+
+ continue; // skip this nic
+ }
+
+ // we found it
+ return niccbp;
+ }
+ }
+
+ return NULL;
+}
+
+//***
+//
+// Function: MakeRipSendPkts
+//
+// Descr: Invokes the make pkts routine according to the snd req type
+//
+//***
+
+UINT
+MakeRipSendPkts(PNICCB niccbp)
+{
+ PRIP_SNDREQ sndreqp;
+ UINT rc = 0; // assume success
+
+ sndreqp = niccbp->RipSndReqp;
+
+ switch(sndreqp->SndReqId) {
+
+ case RIP_GEN_RESPONSE:
+
+ rc = MakeRipGenResponsePkts(niccbp);
+ break;
+
+ case RIP_UPDATE:
+
+ rc = MakeRipUpdatePkt(niccbp);
+ break;
+
+ case RIP_GEN_REQUEST:
+
+ rc = MakeRipGenRequestPkt(niccbp);
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+ }
+
+ return rc;
+}
+
+//***
+//
+// Function: MakeRipGenResponsePkts
+//
+// Descr: allocates and prepares all packets for the RIP gen response
+// The routing table is walked and all network entries which
+// were not received from this nic are copied into RIP response
+// packets. As packets are built, they are queued into the rip
+// send pkts queue at the nic.
+//
+// Params: nic
+//
+// Returns: 0 - success, 1 - did not prepare any packets
+//
+//***
+
+UINT
+MakeRipGenResponsePkts(PNICCB niccbp)
+{
+ PPACKET_TAG pktp;
+ UINT seg;
+ PUCHAR hdrp;
+ USHORT pktlen;
+ BOOLEAN FirstRoute;
+ PRIP_SNDPKT_BUFF rbp;
+ KIRQL oldirql;
+ PIPX_ROUTE_ENTRY rtep;
+ PNICCB rtniccbp;
+
+ // allocate first packet and set net entry ptr in the packet
+ if((pktp = AllocRipGenResponsePkt(niccbp)) == NULL) {
+
+ return 1;
+ }
+
+ // find out what type of Nic is this Nic
+
+
+ hdrp = pktp->DataBufferp;
+ pktlen = RIP_INFO;
+
+ for(seg=0; seg<SegmentCount; seg++) {
+
+ FirstRoute = TRUE;
+
+ // LOCK THE ROUTING TABLE
+ ExAcquireSpinLock(&SegmentLocksTable[seg], &oldirql);
+
+ while((rtep = GetRoute(seg, FirstRoute)) != NULL) {
+
+ FirstRoute = FALSE;
+
+ // SPLIT HORIZON !
+ // check if this network entry originates from this nic
+ // For the global WAN network, rtep->NicId = 0xFFFE !
+ if(rtep->NicId != niccbp->NicId) {
+
+ // check if the target net is a global wan net
+ if(!(rtep->Flags & IPX_ROUTER_GLOBAL_WAN_NET)) {
+
+ // the target is not the global wan net
+ rtniccbp = NicCbPtrTab[rtep->NicId];
+
+ // if the response will be sent on a WAN link then there
+ // is some filtering to do
+ if(niccbp->DeviceType == NdisMediumWan) {
+
+ // check if the target net is visible via a WAN-Disabled LAN
+ if((rtniccbp->DeviceType != NdisMediumWan) &&
+ (rtniccbp->WanRoutingDisabled)) {
+
+ // skip it!
+ continue;
+ }
+
+ // check if the nic to send on is a WAN client.
+ if(niccbp->WanConnectionClient) {
+
+ // Check if LAN-WAN-LAN connectivity is enabled
+ if(!LanWanLan) {
+
+ // this node can only inform about its virtual net
+ if(rtniccbp->NicId != VirtualNicId) {
+
+ // skip it!
+ continue;
+ }
+ }
+ }
+ }
+ else
+ {
+ // The response will be sent on a LAN net
+ // check if LAN to LAN routing is enabled
+ if(!EnableLanRouting) {
+
+ // LAN to LAN routing is disabled
+ // We will send a response only if the target net
+ // is WAN or virtual nic id
+ if(rtniccbp->NicId != VirtualNicId) {
+
+ // The target is not the virtual net, check if
+ // it is a WAN net
+ if(rtniccbp->DeviceType != NdisMediumWan) {
+
+ // The target net is a LAN -> don't answer
+ continue;
+ }
+ }
+ }
+ }
+
+ // if the route originates from a wan client nic and
+ // LAN-WAN-LAN connectivity is not enabled, we do not propagate
+ // this route
+ if(!LanWanLan) {
+
+ if((rtniccbp->DeviceType == NdisMediumWan) &&
+ (rtniccbp->WanConnectionClient)) {
+
+ // skip it!
+ continue;
+ }
+ }
+ }
+ else
+ {
+ // the target net is the global wan net
+ // check if the nic to send on is WAN
+ if(niccbp->DeviceType == NdisMediumWan) {
+
+ // check if the WAN nic to send on doesn't have the same address
+ if(!memcmp(rtep->Network, niccbp->Network, 4)) {
+
+ // skip it!
+ continue;
+ }
+
+ // check if the WAN nic to send on is a connection client.
+ // We can send this info on a connection client only if LanWanLan
+ // is enabled
+
+ if(niccbp->WanConnectionClient) {
+
+ if(!LanWanLan) {
+
+ // skip it!
+ continue;
+ }
+ }
+ }
+ }
+
+ SetNetworkEntry(hdrp + pktlen, rtep);
+ pktlen += NE_ENTRYSIZE;
+ }
+
+ if(pktlen >= RIP_RESPONSE_PACKET_LEN) {
+
+ // we are done with this packet
+ PUTUSHORT2SHORT(hdrp + IPXH_LENGTH, pktlen);
+ InsertTailList(&niccbp->RipSndPktsList, &pktp->PacketLinkage);
+
+ if((pktp = AllocRipGenResponsePkt(niccbp)) == NULL) {
+
+ // we can't go any further, we are partially done and we
+ // send what we have got so far
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[seg], oldirql);
+
+ return 0;
+ }
+
+ // we have got a new packet
+ hdrp = pktp->DataBufferp;
+ pktlen = RIP_INFO;
+ }
+
+ } // while
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[seg], oldirql);
+ }
+
+ // we are done with this last packet.
+ // check if it has any entries
+ if(pktlen > RIP_INFO) {
+
+ PUTUSHORT2SHORT(hdrp + IPXH_LENGTH, pktlen);
+ InsertTailList(&niccbp->RipSndPktsList, &pktp->PacketLinkage);
+ }
+ else
+ {
+ // this packet does not have any rip info => free it
+ rbp = DestroyRipNdisPkt(pktp);
+ ExFreePool(rbp);
+ }
+
+ // check if we have produced any packets
+ if(IsListEmpty(&niccbp->RipSndPktsList)) {
+
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+//***
+//
+// Function: GetRoute
+//
+// Descr: invokes getfisrt route the first time, then get next route.
+//
+//***
+
+PIPX_ROUTE_ENTRY
+GetRoute(UINT segment,
+ BOOLEAN FirstRoute)
+{
+ if(FirstRoute) {
+
+ return(IpxGetFirstRoute(segment));
+ }
+ else
+ {
+ return(IpxGetNextRoute(segment));
+ }
+}
+
+//***
+//
+// Function: AllocRipGenResponsePkt
+//
+// Descr: allocates the data buffer and the ndis descriptors and makes a
+// gen response packet header in the data buffer.
+//
+//***
+
+PPACKET_TAG
+AllocRipGenResponsePkt(PNICCB niccbp)
+{
+ PPACKET_TAG pktp;
+ PRIP_SNDPKT_BUFF rbp;
+
+ // allocate the send packet buffer for this packet. Do a max len allocation
+ if((rbp = ExAllocatePool(NonPagedPool,
+ sizeof(RIP_SNDPKT_BUFF) + RIP_SNDPKT_MAXLEN)) == NULL) {
+
+ return NULL;
+ }
+
+ // create the ndis packet structures
+ // an ndis packet gets created and associated with the snd pkt buffer
+ if((pktp = CreateRipNdisPkt(rbp, niccbp)) == NULL) {
+
+ ExFreePool(rbp);
+
+ return NULL;
+ }
+
+ // set the ipx header in the packet
+ SetRipIpxHeader(pktp->DataBufferp, niccbp, RIP_RESPONSE);
+
+ // set the remote (destination) address
+ SetRipRemoteAddress(pktp, niccbp);
+
+ return pktp;
+}
+
+//***
+//
+// Function: MakeRipUpdatePkt
+//
+// Descr: allocates only the ndis pkt and buff descriptors. The data buff
+// has been already allocated in the snd req pkt.
+// Then makes the ndis packet, formats the ipx header and queues
+// the packet int the nic's rip send pkts queue
+//***
+
+UINT
+MakeRipUpdatePkt(PNICCB niccbp)
+{
+ PPACKET_TAG pktp;
+ PRIP_SNDPKT_BUFF rbp;
+ PRIP_UPDATE_SNDREQ rup;
+
+ // get the ptr to the send pkt buffer
+ rup = (PRIP_UPDATE_SNDREQ)(niccbp->RipSndReqp);
+ rbp = &rup->RipSndPktBuff;
+
+ // create the ndis packet for this update send
+ if((pktp = CreateRipNdisPkt(rbp, niccbp)) == NULL) {
+
+ return 1;
+ }
+
+ // set up the ipx header in the packet
+ SetRipIpxHeader(pktp->DataBufferp, niccbp, RIP_RESPONSE);
+
+ // set up the remote address
+ SetRipRemoteAddress(pktp, niccbp);
+
+ // insert the packet in the list of packets at the nic
+ InsertTailList(&niccbp->RipSndPktsList, &pktp->PacketLinkage);
+
+ return 0;
+}
+
+//***
+//
+// Function: MakeRipGenRequestPkt
+//
+// Descr: allocates the data buffer and the buffer descr and makes
+// the ndis packet. Formats the request header and data and queues
+// the packet in the RipSndPktsList
+//
+//***
+
+UINT
+MakeRipGenRequestPkt(PNICCB niccbp)
+{
+ PPACKET_TAG pktp;
+ PRIP_SNDPKT_BUFF rbp;
+ PUCHAR hdrp;
+
+ // allocate the minimum send packet buffer for this packet
+ if((rbp = ExAllocatePool(NonPagedPool,
+ sizeof(RIP_SNDPKT_BUFF) + RIP_SNDPKT_MINLEN)) == NULL) {
+
+ return 1;
+ }
+
+ // create the ndis packet structures
+ // an ndis packet gets created and associated with the snd pkt buffer
+ if((pktp = CreateRipNdisPkt(rbp, niccbp)) == NULL) {
+
+ ExFreePool(rbp);
+
+ return 1;
+ }
+ // create the Ipx packet header in the data buffer part of the snd pkt buff
+ hdrp = pktp->DataBufferp;
+
+ PUTUSHORT2SHORT(hdrp + IPXH_LENGTH, RIP_INFO + NE_ENTRYSIZE);
+
+ // set the rest of the ipx header
+ SetRipIpxHeader(hdrp, niccbp, RIP_REQUEST);
+
+ // set up the remote address in the packet to send
+ SetRipRemoteAddress(pktp, niccbp);
+
+ // set up the gen request net entry in the packet
+ memcpy(hdrp + RIP_INFO + NE_NETNUMBER, bcastaddress, IPX_NET_LEN);
+ PUTUSHORT2SHORT(hdrp + RIP_INFO + NE_NROFHOPS, 0xFFFF);
+ PUTUSHORT2SHORT(hdrp + RIP_INFO + NE_NROFTICKS, 0xFFFF);
+
+ // insert the packet in the list of packets at the nic
+ InsertTailList(&niccbp->RipSndPktsList, &pktp->PacketLinkage);
+
+ return 0;
+}
+
+//***
+//
+// Function: CreateRipNdisPkt
+//
+// Descr: allocates the ndis pkt descr pool of 1 and buff descr pool of
+// 2, allocates the pkt descr and buff descrs and chains them to
+// form the necessary ndis pkt structure using the received snd
+// buffer
+//***
+
+PPACKET_TAG
+CreateRipNdisPkt(PRIP_SNDPKT_BUFF rbp,
+ PNICCB niccbp)
+{
+ NDIS_STATUS NdisStatus;
+ PNDIS_PACKET NdisPacket;
+ PNDIS_BUFFER NdisDataBuffer;
+ PNDIS_BUFFER NdisMacBuffer;
+ UINT PktReservedLen;
+ PPACKET_TAG pktp;
+
+ // Allocate the packet descriptor and buffer descriptor pools
+ // for this packet
+ PktReservedLen = sizeof(PACKET_TAG);
+ rbp->PktDescrPoolSize = 1;
+
+ NdisAllocatePacketPool(
+ &NdisStatus,
+ &rbp->PktDescrPoolHandle,
+ rbp->PktDescrPoolSize,
+ PktReservedLen);
+
+ if(NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ return NULL;
+ }
+
+ // each packet has 2 buffer descriptors
+ rbp->BuffDescrPoolSize = 2;
+
+ NdisAllocateBufferPool (
+ &NdisStatus,
+ &rbp->BuffDescrPoolHandle,
+ rbp->BuffDescrPoolSize);
+
+ if(NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ NdisFreePacketPool(rbp->PktDescrPoolHandle);
+ return NULL;
+ }
+
+ // allocate the pkt descr, buff descriptors and chain them
+ NdisAllocatePacket(&NdisStatus,
+ &NdisPacket,
+ rbp->PktDescrPoolHandle);
+
+ if(NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ NdisFreePacketPool(rbp->PktDescrPoolHandle);
+ NdisFreeBufferPool(rbp->BuffDescrPoolHandle);
+ return NULL;
+ }
+
+ pktp = (PPACKET_TAG)&NdisPacket->ProtocolReserved;
+ RtlZeroMemory(pktp, sizeof(PACKET_TAG));
+
+ NdisAllocateBuffer(&NdisStatus,
+ &NdisDataBuffer,
+ rbp->BuffDescrPoolHandle,
+ rbp->IpxPacket,
+ 432);
+
+ if(NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ NdisFreePacket(NdisPacket);
+ NdisFreePacketPool(rbp->PktDescrPoolHandle);
+ NdisFreeBufferPool(rbp->BuffDescrPoolHandle);
+
+ return NULL;
+ }
+
+ NdisAllocateBuffer(&NdisStatus,
+ &NdisMacBuffer,
+ rbp->BuffDescrPoolHandle,
+ pktp->MacHeader,
+ MacHeaderNeeded);
+
+ if(NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ NdisFreePacket(NdisPacket);
+ NdisFreeBuffer(NdisDataBuffer);
+ NdisFreePacketPool(rbp->PktDescrPoolHandle);
+ NdisFreeBufferPool(rbp->BuffDescrPoolHandle);
+
+ return NULL;
+ }
+
+ NdisChainBufferAtFront(NdisPacket, NdisDataBuffer);
+ pktp->Identifier = IDENTIFIER_RIP;
+ pktp->ReservedPvoid[0] = NULL;
+ pktp->ReservedPvoid[1] = NULL;
+ pktp->PacketType = RIP_SEND_PACKET;
+ pktp->RcvPktSegmentp = NULL;
+ pktp->DataBufferp = (PUCHAR)(rbp->IpxPacket);
+ pktp->DataBufferLength = 432;
+ pktp->PacketOwnerNicCbp = niccbp;
+ pktp->HeaderBuffDescrp = NdisMacBuffer;
+
+ RtPrint(DBG_SNDREQ, ("IpxRouter: CreateRipNdisPkt pktp=0x%x\n", pktp));
+
+ return pktp;
+}
+
+//***
+//
+// Function: DestroyRipNdisPkt
+//
+// Descr: Frees the allocated ndis structures used in sending this packet
+//
+// Returns: ptr to the snd buffer used in this packets
+//
+//***
+
+PRIP_SNDPKT_BUFF
+DestroyRipNdisPkt(PPACKET_TAG pktp)
+{
+ PRIP_SNDPKT_BUFF rbp;
+ PNDIS_PACKET NdisPacket;
+ PNDIS_BUFFER NdisBuffer;
+ PNICCB niccbp;
+
+ RtPrint(DBG_SNDREQ, ("IpxRouter: DestroyRipNdisPkt pktp=0x%x\n", pktp));
+
+ niccbp = pktp->PacketOwnerNicCbp;
+
+ // get a ptr to the send buff structure
+ rbp = CONTAINING_RECORD(pktp->DataBufferp, RIP_SNDPKT_BUFF, IpxPacket);
+
+ NdisPacket = CONTAINING_RECORD(pktp, NDIS_PACKET, ProtocolReserved);
+
+ // free the data buffer descr
+ NdisUnchainBufferAtBack (NdisPacket, &NdisBuffer);
+ if (NdisBuffer != NULL) {
+ NdisFreeBuffer (NdisBuffer);
+ }
+ else
+ {
+ // !!! break
+ DbgBreakPoint();
+ }
+
+ // free the mac hdr buff descr
+ NdisFreeBuffer(pktp->HeaderBuffDescrp);
+
+ NdisFreePacket(NdisPacket);
+
+ NdisFreePacketPool(rbp->PktDescrPoolHandle);
+ NdisFreeBufferPool(rbp->BuffDescrPoolHandle);
+
+ return rbp;
+}
+
+
+//***
+//
+// Function: StartInterPktGapTimer
+//
+// Descr: Starts the timer for 55 ms at this Nic Cb
+//
+// Params: pointer to Nic Cb
+//
+// Returns: none
+//
+//***
+
+VOID
+StartInterPktGapTimer(PNICCB niccbp)
+{
+ LARGE_INTEGER timeout;
+
+ timeout.LowPart = (ULONG)(-55 * 10000L); // 55 ms
+ timeout.HighPart = -1;
+
+ KeSetTimer(&niccbp->InterPktGapTimer, timeout, &niccbp->InterPktGapDpc);
+}
+
+
+
+VOID
+SetRipIpxHeader(PUCHAR hdrp, // pointer to the packet header
+ PNICCB niccbp, // pointer to the rip send request
+ USHORT RipOpcode)
+{
+ PUTUSHORT2SHORT(hdrp + IPXH_CHECKSUM, 0xFFFF);
+ *(hdrp + IPXH_XPORTCTL) = 0;
+ *(hdrp + IPXH_PKTTYPE) = 1; // RIP packet
+ memcpy(hdrp + IPXH_DESTNET, niccbp->Network, IPX_NET_LEN);
+ memcpy(hdrp + IPXH_DESTNODE, niccbp->RipSndReqp->DestNode, IPX_NODE_LEN);
+ PUTUSHORT2SHORT(hdrp + IPXH_DESTSOCK, niccbp->RipSndReqp->DestSock);
+ memcpy(hdrp + IPXH_SRCNET, niccbp->Network, IPX_NET_LEN);
+ memcpy(hdrp + IPXH_SRCNODE, niccbp->Node, IPX_NODE_LEN);
+ PUTUSHORT2SHORT(hdrp + IPXH_SRCSOCK, IPX_RIP_SOCKET);
+
+ // set the opcode
+ PUTUSHORT2SHORT(hdrp + RIP_OPCODE, RipOpcode);
+}
+
+VOID
+SetRipRemoteAddress(PPACKET_TAG pktp,
+ PNICCB niccbp)
+{
+ // set up the remote address in the packet to send
+ pktp->RemoteAddress.NicId = niccbp->NicId;
+ if(niccbp->DeviceType != NdisMediumWan) {
+
+ // we send on a LAN
+ memcpy(pktp->RemoteAddress.MacAddress, niccbp->RipSndReqp->DestNode, IPX_NODE_LEN);
+ }
+ else
+ {
+ // we send on a WAN line. If the destination socket is broadcast, replace
+ // it with the address of the remote node
+ if(!memcmp(niccbp->RipSndReqp->DestNode, bcastaddress, IPX_NODE_LEN)) {
+
+ memcpy(pktp->RemoteAddress.MacAddress, niccbp->RemoteNode, IPX_NODE_LEN);
+ }
+ else
+ {
+ memcpy(pktp->RemoteAddress.MacAddress, niccbp->RipSndReqp->DestNode, IPX_NODE_LEN);
+ }
+ }
+}
diff --git a/private/ntos/tdi/isn/rip/riptimer.c b/private/ntos/tdi/isn/rip/riptimer.c
new file mode 100644
index 000000000..dd9e0d39c
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/riptimer.c
@@ -0,0 +1,221 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: riptimer.c
+//
+// Description: rip timer manager. Does periodic bcast and aging
+//
+// Author: Stefan Solomon (stefans) October 18, 1993.
+//
+// Revision History:
+//
+//***
+
+#include "rtdefs.h"
+
+WORK_QUEUE_ITEM RipTimerWorkItem;
+
+UINT RipTimerCount;
+
+NDIS_SPIN_LOCK StopRipTimerLock;
+BOOLEAN RipTimerStopRequested;
+BOOLEAN RipTimerWorkItemPending;
+KEVENT RipTimerWorkItemCompletedEvent;
+
+VOID
+AgeAndBcastRoutes(PVOID Parameter);
+
+VOID
+InitRipTimer(VOID)
+{
+ RipTimerCount = RIP_TIMEOUT; // 60 sec aging time
+ ExInitializeWorkItem(&RipTimerWorkItem, AgeAndBcastRoutes, NULL);
+ KeInitializeEvent(&RipTimerWorkItemCompletedEvent, NotificationEvent, FALSE);
+ INITIALIZE_SPIN_LOCK(&StopRipTimerLock);
+ RipTimerStopRequested = FALSE;
+ RipTimerWorkItemPending = FALSE;
+}
+
+VOID
+RipTimer(VOID)
+{
+ if(--RipTimerCount) {
+
+ return;
+ }
+
+ RipTimerCount = RIP_TIMEOUT;
+
+ // timer has expired
+ // check if stop timer has been requested at this point
+ ACQUIRE_SPIN_LOCK(&StopRipTimerLock);
+
+ if(RipTimerStopRequested) {
+
+ // return with no further action
+ RELEASE_SPIN_LOCK(&StopRipTimerLock);
+ return;
+ }
+
+ // Check if the work item is pending. We don't want to queue it twice
+ if(RipTimerWorkItemPending) {
+
+ // return with no further action
+ RELEASE_SPIN_LOCK(&StopRipTimerLock);
+ return;
+ }
+
+ // mark that we have queued the work item
+ RipTimerWorkItemPending = TRUE;
+
+ RELEASE_SPIN_LOCK(&StopRipTimerLock);
+
+ ExQueueWorkItem(&RipTimerWorkItem, DelayedWorkQueue);
+}
+
+VOID
+AgeAndBcastRoutes(PVOID Parameter)
+{
+ LIST_ENTRY DownRoutesList;
+ KIRQL oldirql;
+ PIPX_ROUTE_ENTRY rtep;
+ PNICCB niccbp;
+ UINT seg;
+ BOOLEAN FirstRoute;
+ PRIP_SNDREQ sndreqp;
+ USHORT NicId;
+
+ RtPrint(DBG_RIPTIMER, ("IpxRouter: AgeAndBcastRoutes: Entered\n"));
+
+ InitializeListHead(&DownRoutesList);
+
+ // Scan the routing table and decrement the timer for each route entry.
+ // If the timer == 0, remove the route entry.
+ // All removed route entries are recorded into an update rip packet.
+ // At the end, broadcast the update
+
+ for(seg=0; seg<SegmentCount; seg++) {
+
+ FirstRoute = TRUE;
+
+ // LOCK THE ROUTING TABLE
+ ExAcquireSpinLock(&SegmentLocksTable[seg], &oldirql);
+
+ while((rtep = GetRoute(seg, FirstRoute)) != NULL) {
+
+ FirstRoute = FALSE;
+
+ // check if this is a locally attached route
+ if((rtep->Flags & IPX_ROUTER_PERMANENT_ENTRY) ||
+ (rtep->Flags & IPX_ROUTER_LOCAL_NET)) {
+
+ // local route, skip it
+ continue;
+ }
+
+ // check if this is a route accesible via a WAN nic.
+ // These are static routes and are never aged.
+ // They are deleted only when the line goes down.
+ niccbp = NicCbPtrTab[rtep->NicId];
+ if(niccbp->DeviceType == NdisMediumWan) {
+
+ // static WAN route, skip it
+ continue;
+ }
+
+ // non local route and non static WAN route, age it
+ if(++rtep->Timer >= 3) {
+
+ // this route is too old, delete it
+ IpxDeleteRoute(seg, rtep);
+
+ // mark it as down
+ rtep->HopCount = 16;
+
+ // add the route to the packets we prepare for bcast
+ AddRouteToBcastSndReq(&DownRoutesList, rtep);
+
+ // finally, free the route entry
+ ExFreePool(rtep);
+ }
+ }
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[seg], oldirql);
+
+ } // for all segments
+
+ // broadcast all the deleted routes
+ while((sndreqp = GetBcastSndReq(&DownRoutesList, &NicId)) != NULL) {
+
+ // get the nic ptr for this snd req
+ niccbp = NicCbPtrTab[NicId];
+
+ BroadcastRipUpdate(sndreqp, niccbp, NULL);
+ }
+
+ // Finally, dispatch a periodic bcast request to all nics
+ if((sndreqp = ExAllocatePool(NonPagedPool, sizeof(RIP_SNDREQ))) != NULL) {
+
+ BroadcastRipGeneralResponse(sndreqp);
+ }
+
+ // If the router has a client WAN nic, request update on WAN from the
+ // remote server router
+ SendGenRequestOnWanClient();
+
+ // check if stop was requested and our completion is waited
+ ACQUIRE_SPIN_LOCK(&StopRipTimerLock);
+
+ // mark that we have terminated
+ RipTimerWorkItemPending = FALSE;
+
+ if(!RipTimerStopRequested) {
+
+ RELEASE_SPIN_LOCK(&StopRipTimerLock);
+ return;
+ }
+
+ RELEASE_SPIN_LOCK(&StopRipTimerLock);
+
+ RtPrint(DBG_UNLOAD, ("IpxRouter: AgeAndBcastRoutes: signal completion to pending stop timer\n"));
+
+ // signal that we are done
+ KeSetEvent(&RipTimerWorkItemCompletedEvent, 0L, FALSE);
+}
+
+
+VOID
+StopRipTimer()
+{
+ KeResetEvent(&RipTimerWorkItemCompletedEvent);
+
+ // check if the work item has been queued
+ ACQUIRE_SPIN_LOCK(&StopRipTimerLock);
+
+ // mark that we request stopping
+ RipTimerStopRequested = TRUE;
+
+ if(!RipTimerWorkItemPending) {
+
+ RELEASE_SPIN_LOCK(&StopRipTimerLock);
+
+ RtPrint(DBG_UNLOAD, ("IpxRouter: StopRipTimer: Completed immediately\n"));
+ return;
+ }
+
+ RELEASE_SPIN_LOCK(&StopRipTimerLock);
+
+ RtPrint(DBG_UNLOAD, ("IpxRouter: StopRipTimer: Waiting for the work item to complete\n"));
+
+ KeWaitForSingleObject(
+ &RipTimerWorkItemCompletedEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ (PLARGE_INTEGER)NULL
+ );
+}
diff --git a/private/ntos/tdi/isn/rip/route.c b/private/ntos/tdi/isn/rip/route.c
new file mode 100644
index 000000000..82e44016e
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/route.c
@@ -0,0 +1,179 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: route.c
+//
+// Description: route packet routine
+//
+// Author: Stefan Solomon (stefans) October 11, 1993.
+//
+// Revision History:
+//
+//***
+
+#include "rtdefs.h"
+
+//***
+//
+// Function: RoutePacket
+//
+// Descr: Routes this packet
+//
+// Params: Packet
+//
+// Returns: none
+//
+//***
+
+VOID
+RoutePacket(PPACKET_TAG pktp)
+{
+ PUCHAR hdrp; // points to the IPX packet header
+ PUCHAR destnet; // points to destination network
+ UINT segment; // routing table segment
+ KIRQL oldirql;
+ PIPX_ROUTE_ENTRY tabrtep;
+ PNICCB dstniccbp, srcniccbp; // dest and src nic cb pointers
+
+ // check if we know about the destination network
+ hdrp = pktp->DataBufferp;
+ destnet = hdrp + IPXH_DESTNET;
+
+ segment = IpxGetSegment(destnet);
+
+ ExAcquireSpinLock(&SegmentLocksTable[segment], &oldirql);
+
+ if((tabrtep = IpxGetRoute(segment, destnet)) == NULL) {
+
+ // no such route
+ ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
+ RtPrint(DBG_ROUTE, ("IpxRouter: RoutePacket: route not found!\n"));
+ FreeRcvPkt(pktp);
+ return;
+ }
+
+ // check if the destination route is the Global Wan Route. If it is, then get the
+ // nic id of the destination nic
+ if(tabrtep->Flags & IPX_ROUTER_GLOBAL_WAN_NET) {
+
+ // sanity check
+ ASSERT(tabrtep->NicId == 0xFFFE);
+ ASSERT(WanGlobalNetworkEnabled);
+
+ // get the destination nic id from the wan nodes hash table
+ dstniccbp = GetWanNodeNiccbp(hdrp + IPXH_DESTNODE);
+
+ // check if the nic hasn't been removed from the table (by RtLineDown)
+ if(dstniccbp == NULL) {
+
+ ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
+ FreeRcvPkt(pktp);
+ return;
+ }
+ else
+ {
+ // extra sanity checks
+ ASSERT(dstniccbp->DeviceType == NdisMediumWan);
+ ASSERT(!dstniccbp->WanConnectionClient);
+ }
+ }
+ else
+ {
+ dstniccbp = NicCbPtrTab[tabrtep->NicId];
+ }
+
+ // check if the destination route is reachable through another nic than
+ // the nic we received the packet from.
+ if(pktp->PacketOwnerNicCbp->NicId == dstniccbp->NicId) {
+
+ // we can't send the packet back where it came from => discard it
+ ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
+ FreeRcvPkt(pktp);
+ return;
+ }
+
+ // if either the src or the dst of the packet is a WAN nic, there are
+ // a series of checks to perform
+
+ // get the source nic for this packet
+ srcniccbp = NicCbPtrTab[pktp->PacketOwnerNicCbp->NicId];
+
+ // 1. check if one of the two nics is WAN and the other is a LAN nic disabled
+ // for WAN traffic
+ if( ((dstniccbp->DeviceType == NdisMediumWan) &&
+ (srcniccbp->DeviceType != NdisMediumWan) &&
+ (srcniccbp->WanRoutingDisabled)) ||
+
+ ((dstniccbp->DeviceType != NdisMediumWan) &&
+ (srcniccbp->DeviceType == NdisMediumWan) &&
+ (dstniccbp->WanRoutingDisabled)) ) {
+
+ RtPrint(DBG_ROUTE, ("IpxRouter: RoutePacket: discard pkt because WAN traffic disabled for this LAN\n"));
+ ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
+ FreeRcvPkt(pktp);
+ return;
+ }
+
+ // 2. check if one of the two nics is WAN and has a client role and
+ // LAN-WAN-LAN traffic is disabled
+ if(!LanWanLan) {
+
+ if( ((dstniccbp->DeviceType == NdisMediumWan) &&
+ (dstniccbp->WanConnectionClient)) ||
+
+ ((srcniccbp->DeviceType == NdisMediumWan) &&
+ (srcniccbp->WanConnectionClient)) ) {
+
+ RtPrint(DBG_ROUTE, ("IpxRouter: RoutePacket: discard pkt because WAN has client role\n"));
+ ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
+ FreeRcvPkt(pktp);
+ return;
+ }
+ }
+
+ // 3. If both source and destination NICs are LAN, check if LAN routing is
+ // enabled.
+ if((dstniccbp->DeviceType != NdisMediumWan) &&
+ (srcniccbp->DeviceType != NdisMediumWan) &&
+ (!EnableLanRouting)) {
+
+ RtPrint(DBG_ROUTE, ("IpxRouter: RoutePacket: discard pkt because LAN routing disabled\n"));
+ ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
+ FreeRcvPkt(pktp);
+ return;
+ }
+
+ // general send preparation
+ pktp->RemoteAddress.NicId = dstniccbp->NicId;
+
+ //*** check if the network is directly connected ***
+
+ if(tabrtep->Flags & IPX_ROUTER_LOCAL_NET) {
+
+ // prepare the packet for a direct send to the destination node
+ memcpy(&pktp->RemoteAddress.MacAddress,
+ hdrp + IPXH_DESTNODE,
+ IPX_NODE_LEN);
+ }
+ else
+ {
+ // prepare the packet to be sent to the next router in the path to
+ // the destination node
+ memcpy(&pktp->RemoteAddress.MacAddress,
+ tabrtep->NextRouter,
+ IPX_NODE_LEN);
+ }
+
+ ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql);
+
+ // increment the nr of hops in the packet
+ *(hdrp + IPXH_XPORTCTL) += 1;
+
+ // queue the packet at the sending nic and send it
+ SendPacket(pktp);
+
+ return;
+}
diff --git a/private/ntos/tdi/isn/rip/rtdefs.h b/private/ntos/tdi/isn/rip/rtdefs.h
new file mode 100644
index 000000000..a19457954
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/rtdefs.h
@@ -0,0 +1,327 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: rtdefs.h
+//
+// Description: Defines private structures and types for the ipx router
+//
+// Author: Stefan Solomon (stefans) October 4, 1993.
+//
+// Revision History:
+//
+//***
+
+
+
+#define ISN_NT 1
+
+//
+// These are needed for CTE
+//
+
+#if DBG
+#define DEBUG 1
+#endif
+
+#define NT 1
+
+#include <ntos.h>
+#include <tdikrnl.h>
+#include <ndis.h>
+#include <cxport.h>
+#include <bind.h>
+
+#include "debug.h"
+#include "packet.h"
+#include "utils.h"
+
+#ifndef _RTDEFS_
+#define _RTDEFS_
+
+//
+//*** NIC Control Block ***
+//
+
+typedef enum _NIC_STATE {
+
+ NIC_CLOSED, // line disconnected for this Nic and clean up done
+ NIC_CLOSING, // line down received and in the process of cleaning up
+ NIC_ACTIVE, // Nic active
+ NIC_PENDING_OPEN
+ } NIC_STATE;
+
+typedef enum _NIC_CLOSE_STATUS { // returned by NicClose
+
+ NIC_CLOSE_SUCCESS,
+ NIC_CLOSE_FAILURE,
+ NIC_CLOSE_PENDING
+ } NIC_CLOSE_STATUS;
+
+typedef enum _NIC_RESOURCES_STATUS { // returned by NicFreeResources
+
+ NIC_RESOURCES_FREED,
+ NIC_RESOURCES_PENDING
+ } NIC_RESOURCES_STATUS;
+
+typedef enum _NIC_OPEN_STATUS { // returned by NicOpen
+
+ NIC_OPEN_SUCCESS,
+ NIC_OPEN_FAILURE,
+ } NIC_OPEN_STATUS;
+
+struct _RIP_SNDREQ;
+
+// close completion options
+#define SIGNAL_CLOSE_COMPLETION_EVENT 0x00001
+#define CALL_CLOSE_COMPLETION_ROUTINE 0x00002
+
+typedef struct _NICCB {
+
+ LIST_ENTRY SendQueue; // queue of packets being sent
+ LIST_ENTRY ReceiveQueue; // queue of packets being received
+ LIST_ENTRY RipSendQueue; // RIP responses to send on this nic
+ struct _RIP_SNDREQ *RipSndReqp; // RIP request presently being sent
+ LIST_ENTRY RipSndPktsList;
+ NDIS_SPIN_LOCK NicLock;
+ NIC_STATE NicState; // NIC_ACTIVE, NIC_CLOSING, NIC_CLOSED
+ USHORT NicId;
+ USHORT CloseCompletionOptions;
+ UCHAR Network[4];
+ UCHAR Node[6]; // local node address
+ UCHAR RemoteNode[6]; // address of remote node, for WAN links
+ BOOLEAN WanRoutingDisabled;
+ BOOLEAN WanConnectionClient;
+ USHORT TickCount; // this is derived from link speed
+ UINT LinkSpeed;
+ UINT MaximumPacketSize;
+ UINT MacOptions;
+ NDIS_MEDIUM DeviceType;
+ WORK_QUEUE_ITEM RipSndReqWorkItem;
+ KTIMER InterPktGapTimer;
+ KDPC InterPktGapDpc;
+ KTIMER NicCloseTimer;
+ KDPC NicCloseDpc;
+ KEVENT NicClosedEvent;
+ KTIMER WanGenRequestTimer;
+ KDPC WanGenRequestDpc;
+ UINT WanGenRequestCount;
+ LIST_ENTRY WanHtLinkage; // linkage in the WAN nodes hash table
+
+ //*** count of send packets queued for send on this nic ***
+
+ ULONG SendPktsQueuedCount;
+
+ //*** statistics kept here ***
+
+ ULONG StatBadReceived;
+ ULONG StatRipReceived;
+ ULONG StatRipSent;
+ ULONG StatRoutedReceived;
+ ULONG StatRoutedSent;
+ ULONG StatType20Received;
+ ULONG StatType20Sent;
+
+ } NICCB, *PNICCB;
+
+//
+//*** Rcv Packet Pool Segment Entry ***
+//
+
+typedef struct _RCVPKT_SEGMENT {
+
+ LIST_ENTRY SegmentLinkage; // linkage in the segment list
+ LIST_ENTRY PacketList; // list of packets
+ UINT MaxPktCount; // total nr of pkts in this segment
+ UINT AvailablePktCount; // available pkts in this segment
+ UINT AgingTimer; // incremented by the scavenger
+ // segment removed when 3 ticks
+
+ NDIS_HANDLE RcvPktDescrPoolHandle; // Rcv packets descr pool
+ ULONG RcvPktDescrPoolSize;
+
+ NDIS_HANDLE RcvPktBuffDescrPoolHandle;// Rcv buffer descriptors pool
+ ULONG RcvPktBuffDescrPoolSize;
+
+ ULONG DataBuffer[1];
+ } RCVPKT_SEGMENT, *PRCVPKT_SEGMENT;
+
+
+//
+//*** Packet Tag Structure ***
+//
+
+typedef enum _PACKET_TYPE {
+
+ RCV_PACKET, // Used for RIP requests/ specific replies and routing.
+ // These packets are allocated from the rcv pools and
+ // charged to the Nic which received them
+
+ RIP_SEND_PACKET, // packets used for the send rip response/request
+
+ PROPAGATED_BCAST_PACKET // used for Netbios bcasts. These packets are taken
+ // from the rcv pkt pool
+ } PACKET_TYPE;
+
+typedef struct _PACKET_TAG {
+
+ UCHAR Identifier; // this should be IDENTIFIER_RIP
+
+ UCHAR ReservedUchar[3]; // ensure alignment of ReservedPvoid
+ PVOID ReservedPvoid[2]; // needed by ipx for padding on ethernet
+
+ LIST_ENTRY PacketLinkage; // links this packet in send/receive queues
+ // and the rcv pkt pool queue
+ PACKET_TYPE PacketType; // see above
+
+ PRCVPKT_SEGMENT RcvPktSegmentp; // for RCV_PACKET types, the rcv pkt
+ // pool segment where it belongs
+
+ PUCHAR DataBufferp; // data buffer
+ UINT DataBufferLength; // original length of the data buffer
+
+ PNICCB QueueOwnerNicCbp; // points to the NicCb where it is queued
+ PNICCB PacketOwnerNicCbp; // ptr to NicCb charged for this packet
+
+ IPX_LOCAL_TARGET RemoteAddress; // remote address to send this packet
+ // on (used by send routines)
+
+ PNDIS_BUFFER HeaderBuffDescrp; // ptr to buff descr for the MAC header
+ // NULL if the buff descr is chained in
+ // the pkt descr (after send completes)
+ UCHAR MacHeader[40]; // 40 bytes of Mac Header for sends
+ } PACKET_TAG, *PPACKET_TAG;
+
+//
+//*** RIP Send Requests ***
+//
+
+// for each rip send packet, there is a structure used to keep the pkt descr
+// pool, buff descr pool and data buffer.
+
+typedef struct _RIP_SNDPKT_BUFF {
+
+ NDIS_HANDLE PktDescrPoolHandle; // Rcv packets descr pool
+ ULONG PktDescrPoolSize;
+
+ NDIS_HANDLE BuffDescrPoolHandle;// Rcv buffer descriptors pool
+ ULONG BuffDescrPoolSize;
+
+ ULONG IpxPacket[8]; // 32 -> ipx rip header
+ } RIP_SNDPKT_BUFF, *PRIP_SNDPKT_BUFF;
+
+#define RIP_SNDPKT_MAXLEN 400 // max length to be added to ipx rip header
+#define RIP_SNDPKT_MINLEN 8 // one network entry size
+
+// each rip send request is made of a control block set up by the module
+// requesting the send (rip response, timer, etc.)
+
+typedef enum _RIP_SNDREQ_ID {
+
+ RIP_GEN_RESPONSE, // Send the whole routing table as viewed from this nic
+
+ RIP_UPDATE, // Bcast the associated list of changes
+
+ RIP_GEN_REQUEST // bcast this request on all LANs. This is sent when the
+ // router starts and requests info about all the other
+ // routers.
+
+ } RIP_SNDREQ_ID;
+
+
+
+typedef struct _RIP_SNDREQ {
+
+ LIST_ENTRY GlobalLinkage; // linkage in the Rip global dispatch queue.
+ // the request stays in this queue until sent on
+ // all nics
+ LIST_ENTRY NicLinkage; // linkage in the Rip send request queue at
+ // the Nic Cb
+ RIP_SNDREQ_ID SndReqId; // rip send request type
+ BOOLEAN SendOnAllNics; // how to dispatch this request:
+ // TRUE - send on all nics, FALSE - send only
+ // on the sender nic cb
+ UCHAR DestNode[6]; // destination node:
+ // if different of bcast address represents
+ // the address to send this request to
+ USHORT DestSock; // destination socket to receive the resp
+ PNICCB DoNotSendNicCbp; // do not send on this nic
+ PNICCB SenderNicCbp; // ptr to the nic on which this is sent
+ PKEVENT SndCompleteEventp; // ptr to send complete event
+ } RIP_SNDREQ, *PRIP_SNDREQ;
+
+typedef struct _RIP_UPDATE_SNDREQ {
+
+ RIP_SNDREQ RipSndReq;
+ RIP_SNDPKT_BUFF RipSndPktBuff;
+} RIP_UPDATE_SNDREQ, *PRIP_UPDATE_SNDREQ;
+
+
+//
+//*** Miscellaneous Global Defs & Constants ***
+//
+
+#include "globals.h"
+
+// default configuration values
+
+// default maximum frame size
+#define DEF_MAX_FRAME_SIZE 1518
+
+// default RIP bcast frame size (IPX header + 50 network entries)
+#define DEF_BCAST_FRAME_SIZE 432
+
+// define rcv pkt pool sizes
+
+// small pool -> 100 pkts / per nic
+#define RCVPKT_SMALL_POOL_SIZE 1
+
+// medium pool -> 250 pkts per nic
+#define RCVPKT_MEDIUM_POOL_SIZE 2
+
+// large pool -> unlimited nr of pkts per nic
+#define RCVPKT_LARGE_POOL_SIZE 3
+
+// the number of rcv packets per segment (config parameter)
+#define MIN_RCV_PKTS_PER_SEGMENT 2
+#define DEF_RCV_PKTS_PER_SEGMENT 16
+#define MAX_RCV_PKTS_PER_SEGMENT 32
+
+// the default timeout interval for rip bcasts and aging
+#define RIP_TIMEOUT 60
+
+// the default limit on the number of send pkts queued on one nic
+#define MAX_SEND_PKTS_QUEUED 100
+
+//
+//*** Definitions for the WAN nodes hash table used in routing packets LAN -> WAN for the
+//*** case when the router is configured with a unique WAN network number
+//
+
+#define NODE_HTSIZE 37
+
+//*** tick count associated with the wan global net. Because that's a global value,
+//*** it was picked to reflect an average on an async net
+#define DEFAULT_WAN_GLOBAL_NET_TICKCOUNT 20
+
+//*** invalid device type -> to distinguish between LAN, WAN and non configured devices
+
+#define IPX_ROUTER_INVALID_DEVICE_TYPE 0xFFFF
+
+//
+//*** Definitions for the netbios routing flags in the NetbiosRouting parameter ***
+//
+
+#define NETBIOS_ROUTING_LAN_TO_LAN 0x00000001
+#define NETBIOS_ROUTING_WAN_TO_LAN 0x00000002
+#define NETBIOS_ROUTING_LAN_TO_WAN 0x00000004
+
+//
+// Allocate Pool With Tag
+//
+
+#define ExAllocatePool(type, size) ExAllocatePoolWithTag((type), (size), 'XPIR')
+
+#endif // _RTDEFS_
diff --git a/private/ntos/tdi/isn/rip/rttest/makefile b/private/ntos/tdi/isn/rip/rttest/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/rttest/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isn/rip/rttest/nwsap.h b/private/ntos/tdi/isn/rip/rttest/nwsap.h
new file mode 100644
index 000000000..c99a84063
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/rttest/nwsap.h
@@ -0,0 +1,75 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+Copyright (c) 1993 Micro Computer Systems, Inc.
+
+Module Name:
+
+ net\inc\nwsap.h
+
+Abstract:
+
+ This is the public include file for the Nw Sap Agent API.
+
+Author:
+
+ Brian Walker (MCS) 06-30-1993
+
+Revision History:
+
+--*/
+
+#ifndef _NWSAP_
+#define _NWSAP_
+
+/** Return codes for Advertise API and BindLib API **/
+
+#define SAPRETURN_SUCCESS 0
+#define SAPRETURN_NOMEMORY 1
+#define SAPRETURN_EXISTS 2
+#define SAPRETURN_NOTEXIST 3
+#define SAPRETURN_NOTINIT 4
+#define SAPRETURN_INVALIDNAME 5
+
+/** Function Prototypes **/
+
+INT
+SapAddAdvertise(
+ IN PUCHAR ServerName,
+ IN USHORT ServerType,
+ IN PUCHAR ServerAddr);
+
+INT
+SapRemoveAdvertise(
+ IN PUCHAR ServerName,
+ IN USHORT ServerType);
+
+DWORD
+SapLibInit(
+ VOID);
+
+DWORD
+SapLibShutdown(
+ VOID);
+
+INT
+SapGetObjectID(
+ IN PUCHAR ObjectName,
+ IN USHORT ObjectType,
+ IN PULONG ObjectID);
+
+INT
+SapGetObjectName(
+ IN ULONG ObjectID,
+ IN PUCHAR ObjectName,
+ IN PUSHORT ObjectType,
+ IN PUCHAR ObjectAddr);
+
+INT
+SapScanObject(
+ IN PULONG ObjectID,
+ IN PUCHAR ObjectName,
+ IN PUSHORT ObjectType,
+ IN USHORT ScanType);
+
+#endif
diff --git a/private/ntos/tdi/isn/rip/rttest/rttest.c b/private/ntos/tdi/isn/rip/rttest/rttest.c
new file mode 100644
index 000000000..941e93511
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/rttest/rttest.c
@@ -0,0 +1,426 @@
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <ntddser.h>
+
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <malloc.h>
+
+#include "..\driver.h"
+#include "utils.h"
+#include "nwsap.h"
+
+typedef struct _IPX_ROUTE_ENTRY {
+ UCHAR Network[4];
+ USHORT NicId;
+ UCHAR NextRouter[6];
+ PVOID NdisBindingContext;
+ USHORT Flags;
+ USHORT Timer;
+ UINT Segment;
+ USHORT TickCount;
+ USHORT HopCount;
+ PVOID AlternateRoute[2];
+ PVOID NicLinkage[2];
+ struct {
+ PVOID Linkage[2];
+ ULONG Reserved[1];
+ } PRIVATE;
+} IPX_ROUTE_ENTRY, * PIPX_ROUTE_ENTRY;
+
+
+
+INT
+IsDigit(UCHAR *string) {
+ if (*string < '0' || *string >'9') {
+ return(0);
+ }
+ return(1);
+}
+
+
+IPX_ROUTE_ENTRY rte;
+
+VOID
+RouterDisplayTable(
+ PHANDLE FileHandle,
+ PIO_STATUS_BLOCK IoStatusBlock) {
+
+ ULONG netnr;
+ NTSTATUS Status;
+
+ printf("<------------ ROUTING TABLE START ------------->\n\n");
+
+ Status = NtDeviceIoControlFile(
+ *FileHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPXROUTER_SNAPROUTES, // IoControlCode
+ NULL, // Input Buffer
+ 0, // Input Buffer Length
+ NULL, // Output Buffer
+ 0); // Output Buffer Length
+
+ if (IoStatusBlock->Status != STATUS_SUCCESS) {
+
+ printf("Ioctl snap routes failed\n");
+ return;
+ }
+
+ while(TRUE) {
+
+ Status = NtDeviceIoControlFile(
+ *FileHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPXROUTER_GETNEXTROUTE, // IoControlCode
+ NULL, // Input Buffer
+ 0, // Input Buffer Length
+ &rte, // Output Buffer
+ sizeof(IPX_ROUTE_ENTRY)); // Output Buffer Length
+
+
+ if(IoStatusBlock->Status == STATUS_NO_MORE_ENTRIES) {
+
+ printf("\n\n<------------ ROUTING TABLE END ------------->\n\n");
+ return;
+ }
+
+
+ if(Status != STATUS_SUCCESS) {
+
+ printf("Ioctl failure\n");
+ return;
+ }
+
+ // get net nr in "on the wire" order
+
+ GETLONG2ULONG(&netnr, rte.Network);
+
+ printf("<-- net=%.8x, nic=%d, hops=%d, ticks=%d, flags=0x%x -->\n",
+ netnr, rte.NicId, rte.HopCount, rte.TickCount, rte.Flags);
+ }
+}
+
+PUCHAR DeviceType[2] = { "LAN", "WAN" };
+PUCHAR NicState[4] = { "CLOSED", "CLOSING", "ACTIVE", "PENDING_OPEN" };
+
+
+VOID
+RouterShowNicInfo(
+ PHANDLE FileHandle,
+ PIO_STATUS_BLOCK IoStatusBlock) {
+
+ SHOW_NIC_INFO nis;
+ USHORT index, i;
+
+ NTSTATUS Status;
+
+ printf("\n");
+ index = 0;
+
+ while(TRUE) {
+
+ Status = NtDeviceIoControlFile(
+ *FileHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPXROUTER_SHOWNICINFO, // IoControlCode
+ &index, // Input Buffer
+ sizeof(USHORT), // Input Buffer Length
+ &nis, // Output Buffer
+ sizeof(nis)); // Output Buffer Length
+
+ index++;
+ printf("\n");
+
+ if(IoStatusBlock->Status == STATUS_NO_MORE_ENTRIES) {
+
+ return;
+ }
+
+
+ if(Status != STATUS_SUCCESS) {
+
+ printf("Ioctl failure\n");
+ return;
+ }
+
+ printf("NicId = %d\n", nis.NicId);
+ printf("DeviceType = %s\n", DeviceType[nis.DeviceType]);
+ printf("NicState = %s\n", NicState[nis.NicState]);
+ printf("Network = ");
+ for(i=0; i<4; i++) {
+
+ printf("%.2x", nis.Network[i]);
+ }
+ printf("\nNode = ");
+ for(i=0; i<6; i++) {
+
+ printf("%.2x", nis.Node[i]);
+ }
+ printf("\nTickCount = %d\n", nis.TickCount);
+
+ printf("RIP Packets Traffic: Received = %d, Sent = %d\n",
+ nis.StatRipReceived, nis.StatRipSent);
+
+ printf("Routed Packets Traffic: Received = %d, Sent = %d\n",
+ nis.StatRoutedReceived, nis.StatRoutedSent);
+
+ printf("Type 20 Packets Traffic: Received = %d, Sent = %d\n",
+ nis.StatType20Received, nis.StatType20Sent);
+
+ printf("Bad Packets Received = %d\n", nis.StatBadReceived);
+
+ }
+}
+
+VOID
+RouterShowMemStat(
+ PHANDLE FileHandle,
+ PIO_STATUS_BLOCK IoStatusBlock) {
+
+ SHOW_MEM_STAT sms;
+
+ NTSTATUS Status;
+
+ Status = NtDeviceIoControlFile(
+ *FileHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPXROUTER_SHOWMEMSTATISTICS, // IoControlCode
+ NULL, // Input Buffer
+ 0, // Input Buffer Length
+ &sms, // Output Buffer
+ sizeof(sms)); // Output Buffer Length
+
+ if(Status != STATUS_SUCCESS) {
+
+ printf("Ioctl failure\n");
+ return;
+ }
+
+ printf("\n\nPeak receive packets allocation: %d pkts\n", sms.PeakPktAllocCount);
+ printf("Current receive packets allocation: %d pkts\n", sms.CurrentPktAllocCount);
+ printf("Current packet pool size (alloc'ed + free) %d pkts , %dk\n",
+ sms.CurrentPktPoolCount, (sms.CurrentPktPoolCount * sms.PacketSize)/1024 + 1);
+ printf("Packet Size %d\n", sms.PacketSize);
+}
+
+
+VOID
+RouterClearStatistics(
+ PHANDLE FileHandle,
+ PIO_STATUS_BLOCK IoStatusBlock) {
+
+ NTSTATUS Status;
+
+ Status = NtDeviceIoControlFile(
+ *FileHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPXROUTER_ZERONICSTATISTICS, // IoControlCode
+ NULL, // Input Buffer
+ 0, // Input Buffer Length
+ NULL, // Output Buffer
+ 0); // Output Buffer Length
+
+ if(Status != STATUS_SUCCESS) {
+
+ printf("Ioctl failure\n");
+ return;
+ }
+}
+
+VOID
+SapShowAllServers()
+{
+ INT rc;
+ ULONG ObjectID = 0xFFFFFFFF;
+ UCHAR ObjectName[100];
+ USHORT ObjectType;
+ USHORT ScanType = 0xFFFF;
+
+ memset(&ObjectName, 0, 100);
+
+ while((rc = SapScanObject(&ObjectID,
+ ObjectName,
+ &ObjectType,
+ ScanType)) == SAPRETURN_SUCCESS) {
+
+ printf("%-48s ServerType=%d\n", &ObjectName, ObjectType);
+ }
+}
+
+VOID
+SapShowFileServers()
+{
+ INT rc;
+ ULONG ObjectID = 0xFFFFFFFF;
+ UCHAR ObjectName[100];
+ USHORT ObjectType;
+ USHORT ScanType = 0x4;
+ UCHAR IpxAddress[12];
+ USHORT i;
+
+ memset(&ObjectName, 0, 100);
+
+ printf("\nServer Name IPX Address\n");
+ printf("-------------------------------------------\n");
+
+ printf("\n");
+ while((rc = SapScanObject(&ObjectID,
+ ObjectName,
+ &ObjectType,
+ ScanType)) == SAPRETURN_SUCCESS) {
+
+ // get object address
+ SapGetObjectName(ObjectID,
+ ObjectName,
+ &ObjectType,
+ IpxAddress);
+
+
+ printf("%-30s", &ObjectName);
+ for(i=0; i<4; i++) {
+
+ printf("%.2x", IpxAddress[i]);
+ }
+ printf(".");
+ for(i=4; i<10; i++) {
+
+ printf("%.2x", IpxAddress[i]);
+ }
+ printf("\n");
+ }
+}
+
+VOID _cdecl
+main(
+ IN WORD argc,
+ IN LPSTR argv[]
+ )
+
+{
+ HANDLE RouterFileHandle;
+ OBJECT_ATTRIBUTES RouterObjectAttributes;
+ IO_STATUS_BLOCK RouterIoStatusBlock;
+ UNICODE_STRING RouterFileString;
+ WCHAR RouterFileName[] = L"\\Device\\Ipxroute";
+ NTSTATUS Status;
+
+ PVOID Memory;
+ int choice;
+
+ RtlInitUnicodeString (&RouterFileString, RouterFileName);
+
+ InitializeObjectAttributes(
+ &RouterObjectAttributes,
+ &RouterFileString,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenFile(
+ &RouterFileHandle, // HANDLE of file
+ SYNCHRONIZE | GENERIC_READ,
+ &RouterObjectAttributes,
+ &RouterIoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, // Share Access
+ FILE_SYNCHRONOUS_IO_NONALERT); // Open Options
+
+ if (!NT_SUCCESS(Status)) {
+ printf("Open of IPX Router returned %lx\n", Status);
+ return;
+ }
+ else
+ {
+ printf("Open of %Z was successful!\n",&RouterFileString);
+ }
+
+ //
+ // Allocate storage to hold all this.
+ //
+
+ Memory = malloc (200 * sizeof(ULONG));
+ if (Memory == NULL) {
+ printf("Malloc failed.\n");
+ return;
+ }
+
+ SapLibInit();
+
+
+ do {
+ printf("\n");
+ printf("----------- IPX ROUTER TEST MENU -------------\n");
+ printf("\n");
+ printf(" 1. Show Routing Table\n");
+ printf(" 2. Show Network Interfaces Statistics\n");
+ printf(" 3. Show Packet Pool Statistics\n");
+ printf(" 4. Clear Router Statistics\n");
+ printf(" 5. Show All Servers (of all types) in SAP Table\n");
+ printf(" 6. Show NetWare File Servers in SAP Table\n");
+ printf(" 99.Exit\n");
+ printf("\n");
+ printf("Enter your choice -->");
+
+ scanf("%d", &choice);
+
+ switch (choice) {
+ case 1:
+ RouterDisplayTable(&RouterFileHandle, &RouterIoStatusBlock);
+ break;
+ case 2:
+ RouterShowNicInfo(&RouterFileHandle, &RouterIoStatusBlock);
+ break;
+ case 3:
+ RouterShowMemStat(&RouterFileHandle, &RouterIoStatusBlock);
+ break;
+ case 4:
+ RouterClearStatistics(&RouterFileHandle, &RouterIoStatusBlock);
+ break;
+ case 5:
+ SapShowAllServers();
+ break;
+ case 6:
+ SapShowFileServers();
+ break;
+
+
+ case 99:
+ break;
+ default:
+ printf("Bad choice !!\n");
+ }
+
+ } while (choice != 99);
+
+
+ Status = NtClose(RouterFileHandle);
+
+ if (!NT_SUCCESS(Status)) {
+ printf("Router Close returned %lx\n", Status);
+ } else {
+ printf("Router Close successful\n");
+ }
+
+ free (Memory);
+
+}
+
+
diff --git a/private/ntos/tdi/isn/rip/rttest/sources b/private/ntos/tdi/isn/rip/rttest/sources
new file mode 100644
index 000000000..fc42df2d6
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/rttest/sources
@@ -0,0 +1,42 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+UMLIBS=obj\*\hubtest.lib \nt\public\sdk\lib\*\setargv.obj
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ndis
+MINORCOMP=rttest
+
+TARGETNAME=rttest
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\nwsaplib.lib
+
+INCLUDES=
+
+SOURCES=rttest.c
+
+
+UMTYPE=console
+UMLIBS=
+
diff --git a/private/ntos/tdi/isn/rip/rttest/utils.h b/private/ntos/tdi/isn/rip/rttest/utils.h
new file mode 100644
index 000000000..afacd2a35
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/rttest/utils.h
@@ -0,0 +1,55 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: utils.h
+//
+// Description: Contains miscellaneous utilities
+//
+// Author: Stefan Solomon (stefans) October 4, 1993.
+//
+// Revision History:
+//
+//***
+
+#ifndef _UTILS_
+#define _UTILS_
+
+/*
+ * The following macros deal with on-the-wire short and long values
+ *
+ * On the wire format is big-endian i.e. a long value of 0x01020304 is
+ * represented as 01 02 03 04.
+ * Similarly a short value of 0x0102 is represented as 01 02.
+ *
+ * The host format is not assumed since it will vary from processor to
+ * processor.
+ */
+
+// Get a short from on-the-wire format to a USHORT in the host format
+#define GETSHORT2USHORT(DstPtr, SrcPtr) \
+ *(PUSHORT)(DstPtr) = ((*((PUCHAR)(SrcPtr)+0) << 8) + \
+ (*((PUCHAR)(SrcPtr)+1) ))
+
+// Get a long from on-the-wire format to a ULONG in the host format
+#define GETLONG2ULONG(DstPtr, SrcPtr) \
+ *(PULONG)(DstPtr) = ((*((PUCHAR)(SrcPtr)+0) << 24) + \
+ (*((PUCHAR)(SrcPtr)+1) << 16) + \
+ (*((PUCHAR)(SrcPtr)+2) << 8) + \
+ (*((PUCHAR)(SrcPtr)+3) ))
+
+// Put a USHORT from the host format to a short to on-the-wire format
+#define PUTUSHORT2SHORT(DstPtr, Src) \
+ *((PUCHAR)(DstPtr)+0) = (UCHAR) ((USHORT)(Src) >> 8), \
+ *((PUCHAR)(DstPtr)+1) = (UCHAR)(Src)
+
+// Put a ULONG from the host format to an array of 4 UCHARs on-the-wire format
+#define PUTULONG2LONG(DstPtr, Src) \
+ *((PUCHAR)(DstPtr)+0) = (UCHAR) ((ULONG)(Src) >> 24), \
+ *((PUCHAR)(DstPtr)+1) = (UCHAR) ((ULONG)(Src) >> 16), \
+ *((PUCHAR)(DstPtr)+2) = (UCHAR) ((ULONG)(Src) >> 8), \
+ *((PUCHAR)(DstPtr)+3) = (UCHAR) (Src)
+
+#endif // _UTILS_
diff --git a/private/ntos/tdi/isn/rip/send.c b/private/ntos/tdi/isn/rip/send.c
new file mode 100644
index 000000000..22810fe6c
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/send.c
@@ -0,0 +1,524 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: send.c
+//
+// Description: send packet routines
+//
+// Author: Stefan Solomon (stefans) October 11, 1993.
+//
+// Revision History:
+//
+//***
+
+#include "rtdefs.h"
+
+VOID
+SendPacketComplete(PPACKET_TAG pktp);
+
+UINT
+SendPropagatedPacketComplete(PPACKET_TAG pktp);
+
+VOID
+UpdateSendStatistics(PNICCB niccb,
+ PPACKET_TAG pktp);
+
+VOID
+SetType20PktDestNet(PPACKET_TAG pktp);
+
+VOID
+UpdateRipResponseTickCount(PUCHAR hdrp,
+ PNICCB niccbp);
+
+
+//*** max send pkts queued limit: over this limit the send pkts get discarded
+
+ULONG MaxSendPktsQueued = MAX_SEND_PKTS_QUEUED;
+
+//***
+//
+// Function: SendPacket
+//
+// Descr: enqueues the packet in the requested Nic queue and initiates
+// the send
+//
+// Params: Packet
+//
+// Returns: none
+//
+//***
+
+VOID
+SendPacket(PPACKET_TAG pktp)
+{
+ PNDIS_PACKET pktdescrp;
+ NDIS_STATUS NdisStatus;
+ UINT BufferCount;
+ PNDIS_BUFFER FirstBufferp;
+ USHORT pktlen;
+ PNICCB niccbp;
+ PUCHAR hdrp;
+
+ RtPrint(DBG_SEND, ("IpxRouter: SendPacket: pktp=0x%x\n", pktp));
+
+ // get the packet length
+ hdrp = pktp->DataBufferp;
+ GETSHORT2USHORT(&pktlen, hdrp + IPXH_LENGTH);
+
+ // get the pkt descr ptr
+ pktdescrp = CONTAINING_RECORD(pktp, NDIS_PACKET, ProtocolReserved);
+
+ // adjust the length of the packet to send
+ NdisQueryPacket(pktdescrp,
+ NULL,
+ &BufferCount,
+ &FirstBufferp,
+ NULL);
+
+ NdisAdjustBufferLength(FirstBufferp, pktlen);
+
+ // chain the mac hdr buff descr at the front (the mac hdr buff descr
+ // already points at the Mac header in the packet tag)
+ NdisChainBufferAtFront(pktdescrp, pktp->HeaderBuffDescrp);
+
+ // get the Nic Cb ptr where we should send this packet
+ niccbp = NicCbPtrTab[pktp->RemoteAddress.NicId];
+
+ // Do not send if it doesn't fit the max frame size
+ // for this adapter
+ if(pktlen > niccbp->MaximumPacketSize) {
+
+ SendPacketComplete(pktp);
+ return;
+ }
+
+ // if the packet is a RIP Response, update the tick count in the
+ // network entry fields
+ UpdateRipResponseTickCount(hdrp, niccbp);
+
+ ACQUIRE_SPIN_LOCK(&niccbp->NicLock);
+
+ // check Nic Status. Do not send on a closed Nic
+ if(niccbp->NicState != NIC_ACTIVE) {
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+
+ SendPacketComplete(pktp);
+ return;
+ }
+
+ // check if we are allowed to queue this packet (we aren't over limit)
+ if(niccbp->SendPktsQueuedCount >= MaxSendPktsQueued) {
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+
+ SendPacketComplete(pktp);
+ return;
+ }
+
+
+ // Nic is active, we can send
+ UpdateSendStatistics(niccbp, pktp);
+
+ // set the QUEUE owner of the packet
+ pktp->QueueOwnerNicCbp = niccbp;
+
+ // enqueue the packet in the NIC's send list and wait for the
+ // transfer to complete
+ InsertTailList(&niccbp->SendQueue, &pktp->PacketLinkage);
+
+ // increment the queued pkts counter
+ niccbp->SendPktsQueuedCount++;
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+
+ // send the packet
+ NdisStatus = IpxSendPacket(&pktp->RemoteAddress,
+ pktdescrp,
+ pktlen,
+ 0);
+
+
+ if(NdisStatus != NDIS_STATUS_PENDING) {
+
+ RtSendComplete(pktdescrp, NdisStatus);
+ }
+}
+
+//***
+//
+// Function: RtSendComplete
+//
+// Descr: called by the IPX driver when send completed
+//
+// Params:
+//
+// Returns:
+//
+//***
+
+VOID
+RtSendComplete(PNDIS_PACKET pktdescrp,
+ NDIS_STATUS NdisStatus)
+{
+ PNICCB niccbp;
+ PPACKET_TAG pktp;
+
+ pktp = (PPACKET_TAG)pktdescrp->ProtocolReserved;
+
+ RtPrint(DBG_SEND, ("IpxRouter: RtSendComplete: pktp=0x%x\n", pktp));
+
+ niccbp = pktp->QueueOwnerNicCbp;
+
+#if DBG
+ // this is for debugging purposes
+ if(NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ RtPrint(DBG_NOTIFY, ("IpxRouter: SendPacket: FAILED with %xl\n", NdisStatus));
+ }
+#endif
+
+ // dequeue the packet from the send queue and complete processing
+ ACQUIRE_SPIN_LOCK(&niccbp->NicLock);
+
+ RemoveEntryList(&pktp->PacketLinkage);
+
+ // decrement queued send pkts counter
+ niccbp->SendPktsQueuedCount--;
+
+ RELEASE_SPIN_LOCK(&niccbp->NicLock);
+
+ // complete the send packet processing
+ SendPacketComplete(pktp);
+}
+
+//***
+//
+// Function: SendPacketComplete
+//
+// Descr: post send processing
+//
+// Params: Packet
+//
+// Returns: None
+//
+//***
+
+VOID
+SendPacketComplete(PPACKET_TAG pktp)
+{
+ PNDIS_PACKET NdisPacket;
+ PNDIS_BUFFER NdisBuffer = NULL;
+ UINT BufferCount;
+
+ RtPrint(DBG_SEND, ("IpxRouter: SendPacketComplete: Entered\n"));
+
+ // unchain the first buffer descriptor (MacHeader)
+ NdisPacket = CONTAINING_RECORD(pktp, NDIS_PACKET, ProtocolReserved);
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ ASSERT(NdisBuffer == pktp->HeaderBuffDescrp);
+
+ // readjust the original buffer descriptor length
+ // get the pkt descr ptr
+ NdisQueryPacket(NdisPacket,
+ NULL,
+ &BufferCount,
+ &NdisBuffer,
+ NULL);
+
+ NdisAdjustBufferLength(NdisBuffer, pktp->DataBufferLength);
+ NdisRecalculatePacketCounts(NdisPacket);
+
+ // what to do next is controlled by the packet type
+ switch(pktp->PacketType) {
+
+ case RCV_PACKET:
+
+ // this has been a routed packet or a directed rip reply
+ // free it to the rcv pkt pool and discharge the nic
+
+ FreeRcvPkt(pktp);
+
+ break;
+
+ case RIP_SEND_PACKET:
+
+ // call the completion routines for these guys
+ SendRipPktCompleted(pktp);
+
+ break;
+
+ case PROPAGATED_BCAST_PACKET:
+
+ // send the packet on the next available net (if any left) or return it
+ // to the pool
+ if(SendPropagatedPacketComplete(pktp)) {
+
+ RtPrint(DBG_NETBIOS, ("IpxRouter: SendPacketComplete: free propagated pkt 0x%x\n", pktp));
+
+ // can't propagate further, return to rcv pkt pool
+ FreeRcvPkt(pktp);
+ }
+
+ break;
+
+ default:
+
+ // !!! break
+ ASSERT(FALSE);
+ break;
+ }
+}
+
+//***
+//
+// Function: SendPropagatedPacket
+//
+// Descr: marks the packet as a propagated packet type and sends it
+// starting at the beginning of the LanNics list
+//
+// Params: Packet
+//
+// Returns: none
+//
+//***
+
+VOID
+SendPropagatedPacket(PPACKET_TAG pktp)
+{
+ USHORT i;
+ PNICCB niccbp;
+
+ // check if there is an active Nic to send on next and if this Nic is
+ // active and is not the packet owner nic
+ for(i=0; i<MaximumNicCount; i++) {
+
+ niccbp = NicCbPtrTab[i];
+
+ if((niccbp->NicState == NIC_ACTIVE) &&
+ (IsNetbiosRoutingAllowed(pktp->PacketOwnerNicCbp, niccbp)) &&
+ (!IsNetInNbPacket(pktp, niccbp))) {
+
+ // send the packet on this nic
+ pktp->PacketType = PROPAGATED_BCAST_PACKET;
+ pktp->RemoteAddress.NicId = niccbp->NicId;
+ memcpy(pktp->RemoteAddress.MacAddress, bcastaddress, 6);
+
+ RtPrint(DBG_NETBIOS, ("IpxRouter: SendPropagatedPacket: send pkt 0x%x on Nic %d\n", pktp, niccbp->NicId));
+ SetType20PktDestNet(pktp);
+ SendPacket(pktp);
+
+ return;
+ }
+ }
+
+ // can't propagate this packet, free it
+ FreeRcvPkt(pktp);
+}
+
+//***
+//
+// Function: SendPropagatedPacketComplete
+//
+// Descr: If there is a next active NicCb to send the packet on, queues
+// the packet in the propagation list and queues a Dpc to send the
+// packet on this Nic.
+//
+// Params: Packet
+//
+// Returns: 0 - packet queued for propagation, 1 - can't propagate further
+//
+//***
+
+UINT
+SendPropagatedPacketComplete(PPACKET_TAG pktp)
+{
+ PNICCB niccbp; // nic that has sent the packet
+ USHORT i;
+
+ // check if there is another active Nic to send on next and if this Nic is
+ // active and is not the packet owner nic
+ for(i=pktp->RemoteAddress.NicId+1; // next Nic Id
+ i<MaximumNicCount;
+ i++) {
+
+ niccbp = NicCbPtrTab[i];
+
+ if((niccbp->NicState == NIC_ACTIVE) &&
+ (IsNetbiosRoutingAllowed(pktp->PacketOwnerNicCbp, niccbp)) &&
+ (!IsNetInNbPacket(pktp, niccbp))) {
+
+ // We have found the next nic.
+ pktp->RemoteAddress.NicId = i;
+
+ // queue the packet for a propagated send.
+ ACQUIRE_SPIN_LOCK(&PropagatedPktsListLock);
+
+ InsertTailList(&PropagatedPktsList, &pktp->PacketLinkage);
+
+ if(!PropagatedPktsDpcQueued) {
+
+ // queue a Dpc to send the packet
+ KeInsertQueueDpc(&PropagatedPktsDpc, NULL, NULL);
+ PropagatedPktsDpcQueued = TRUE;
+ }
+
+ RELEASE_SPIN_LOCK(&PropagatedPktsListLock);
+
+ return 0;
+ }
+ }
+
+ // we are done with this packet
+ return 1;
+}
+
+//***
+//
+// Function: SendNextPropagatedPacket
+//
+// Descr: DPC called routine which dequeues the next packet from the
+// propagated packets list and sends it
+//
+// Params: none
+//
+// Returns: none
+//
+//***
+
+
+VOID
+SendNextPropagatedPkt(PKDPC Dpc,
+ PVOID DefferedContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2)
+{
+ PLIST_ENTRY lep;
+ PPACKET_TAG pktp;
+ LIST_ENTRY sendlist;
+
+ InitializeListHead(&sendlist);
+
+ // get next item from the propagated bcast queue and send it
+
+ ACQUIRE_SPIN_LOCK(&PropagatedPktsListLock);
+
+ PropagatedPktsDpcQueued = FALSE;
+
+ while(!IsListEmpty(&PropagatedPktsList)) {
+
+ lep = RemoveHeadList(&PropagatedPktsList);
+ InsertTailList(&sendlist, lep);
+ }
+
+ RELEASE_SPIN_LOCK(&PropagatedPktsListLock);
+
+ while(!IsListEmpty(&sendlist)) {
+
+ lep = RemoveHeadList(&sendlist);
+ pktp = CONTAINING_RECORD(lep, PACKET_TAG, PacketLinkage);
+ SetType20PktDestNet(pktp);
+ SendPacket(pktp);
+ }
+}
+
+VOID
+UpdateSendStatistics(PNICCB niccbp,
+ PPACKET_TAG pktp)
+{
+ PUCHAR hdrp;
+ USHORT srcsock;
+
+ switch(pktp->PacketType) {
+
+ case RCV_PACKET:
+
+ hdrp = pktp->DataBufferp;
+ GETSHORT2USHORT(&srcsock, hdrp + IPXH_DESTSOCK);
+
+ if(srcsock == IPX_RIP_SOCKET) {
+
+ niccbp->StatRipSent++;
+ }
+ else
+ {
+ niccbp->StatRoutedSent++;
+ }
+
+ break;
+
+ case RIP_SEND_PACKET:
+
+ niccbp->StatRipSent++;
+ break;
+
+ case PROPAGATED_BCAST_PACKET:
+
+ niccbp->StatType20Sent++;
+ break;
+
+ default:
+
+ break;
+
+ }
+}
+
+VOID
+SetType20PktDestNet(PPACKET_TAG pktp)
+{
+ PNICCB niccbp;
+ PUCHAR hdrp;
+
+ // get the Nic Cb ptr where we should send this packet
+ niccbp = NicCbPtrTab[pktp->RemoteAddress.NicId];
+
+ // set the destination net in the packet
+ hdrp = pktp->DataBufferp;
+
+ memcpy(hdrp + IPXH_DESTNET, niccbp->Network, 4);
+}
+
+
+VOID
+UpdateRipResponseTickCount(PUCHAR hdrp,
+ PNICCB niccbp)
+{
+ USHORT resplen;
+ USHORT pktlen;
+ USHORT srcsock;
+ USHORT opcode;
+ USHORT nrofticks;
+
+ // check if this is a RIP Response packet
+ GETSHORT2USHORT(&srcsock, hdrp + IPXH_SRCSOCK);
+ if(srcsock != IPX_RIP_SOCKET) {
+
+ return;
+ }
+
+ GETSHORT2USHORT(&opcode, hdrp + RIP_OPCODE);
+ if(opcode != RIP_RESPONSE) {
+
+ return;
+ }
+
+ //*** RIP Response Packet ***
+
+ // get the response packet length
+ GETSHORT2USHORT(&pktlen, hdrp + IPXH_LENGTH);
+
+ // for each network entry, increment the number of ticks so that
+ // we add the nr of ticks for the nic to send the packet on
+ for(resplen = RIP_INFO;
+ resplen < pktlen;
+ resplen += NE_ENTRYSIZE) {
+
+ GETSHORT2USHORT(&nrofticks, hdrp + resplen + NE_NROFTICKS);
+ nrofticks += niccbp->TickCount;
+ PUTUSHORT2SHORT(hdrp + resplen + NE_NROFTICKS, nrofticks);
+ }
+}
diff --git a/private/ntos/tdi/isn/rip/sources.inc b/private/ntos/tdi/isn/rip/sources.inc
new file mode 100644
index 000000000..d49c538bd
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/sources.inc
@@ -0,0 +1,60 @@
+!IF 0
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=nwlnkrip
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..\..\inc;..\..\..\inc;..\..\..\..\inc;..\..\..\..\..\inc
+
+C_DEFINES=$(C_DEFINES) -D_NTDRIVER_
+
+!IFDEF BUILD_FOR_3_51
+C_DEFINES= $(C_DEFINES) -D_NTIFS_
+!ENDIF
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=..\driver.c \
+ ..\globals.c \
+ ..\ipxbind.c \
+ ..\init.c \
+ ..\start.c \
+ ..\nicman.c \
+ ..\rcvpkt.c \
+ ..\timer.c \
+ ..\rcvind.c \
+ ..\route.c \
+ ..\send.c \
+ ..\ripproc.c \
+ ..\ripsend.c \
+ ..\riptimer.c \
+ ..\ripaux.c \
+ ..\stubs.c \
+ ..\registry.c \
+ ..\lineind.c \
+ ..\netbios.c \
+ ..\nwlnkrip.rc
+
+RELATIVE_DEPTH=..\..
diff --git a/private/ntos/tdi/isn/rip/start.c b/private/ntos/tdi/isn/rip/start.c
new file mode 100644
index 000000000..d9409f1a6
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/start.c
@@ -0,0 +1,193 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: start.c
+//
+// Description: starts the router
+//
+// Author: Stefan Solomon (stefans) October 5, 1993.
+//
+// Revision History:
+//
+//***
+
+#include "rtdefs.h"
+
+KEVENT BcastSndReqEvent;
+
+//***
+//
+// Function: RouterStart
+//
+// Descr: Starts the router
+//
+// Parameters:
+//
+// Returns: STATUS_SUCCESS
+// STATUS_INSUFFICIENT_RESOURCES
+//
+//***
+
+NTSTATUS
+RouterStart(VOID)
+{
+ PRIP_SNDREQ sndrqp;
+
+ //*** Send a general RIP bcast to all active nets ***
+ //*** announcing our routes ***
+
+ if((sndrqp = ExAllocatePool(NonPagedPool, sizeof(RIP_SNDREQ))) == NULL) {
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ BroadcastRipGeneralResponse(sndrqp);
+
+ //*** Send a general RIP request to all active nets ***
+ //*** requesting their routing tables ***
+
+ if((sndrqp = ExAllocatePool(NonPagedPool, sizeof(RIP_SNDREQ))) == NULL) {
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ sndrqp->SndReqId = RIP_GEN_REQUEST;
+ sndrqp->SendOnAllNics = TRUE; // send to everybody
+ memcpy(sndrqp->DestNode, bcastaddress, IPX_NODE_LEN);
+ sndrqp->DestSock = IPX_RIP_SOCKET;
+ sndrqp->DoNotSendNicCbp = NULL; // do no except any nic
+ sndrqp->SenderNicCbp = NULL;
+ sndrqp->SndCompleteEventp = NULL;
+
+ RipDispatchSndReq(sndrqp);
+
+ return STATUS_SUCCESS;
+}
+
+
+VOID
+RouterStop(VOID)
+{
+ LIST_ENTRY DownRoutesList;
+ KIRQL oldirql;
+ PIPX_ROUTE_ENTRY rtep;
+ UINT seg;
+ BOOLEAN FirstRoute;
+ PRIP_SNDREQ sndreqp;
+ USHORT NicId;
+ PNICCB niccbp;
+ USHORT tmp;
+ PRIP_UPDATE_SNDREQ respcbp = NULL; // ptr to changes response to bcast
+
+ RtPrint(DBG_INIT, ("IpxRouter: RouterStop: Entered\n"));
+
+ KeInitializeEvent(&BcastSndReqEvent, NotificationEvent, FALSE);
+
+ // if configured with a wan global net, send bcast update that it will
+ // go down now.
+ if(WanGlobalNetworkEnabled) {
+
+ WanGlobalNetworkEnabled = FALSE;
+
+ seg = IpxGetSegment(WanGlobalNetwork);
+
+ // LOCK THE ROUTING TABLE
+ ExAcquireSpinLock(&SegmentLocksTable[seg], &oldirql);
+
+ if(rtep = IpxGetRoute(seg, WanGlobalNetwork)) {
+
+ IpxDeleteRoute(seg, rtep);
+
+ // set hop count to "unreachable"
+ rtep->HopCount = 16;
+ RtPrint(DBG_INIT, ("IpxRouter: DeleteGlobalWanNet: Deleted wan global net route entry\n"));
+ }
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[seg], oldirql);
+
+ if(rtep == NULL) {
+
+ goto wan_global_done;
+ }
+
+ // Broadcast the route entry down on all the LAN segments
+ BroadcastWanNetUpdate(rtep, NULL, &BcastSndReqEvent);
+
+ ExFreePool(rtep);
+ }
+
+wan_global_done:
+
+
+ // scan the routing table and remove all route entries (except the
+ // permanent ones).
+ // For all route entries (permanent or not) make the snd req pkts for
+ // bcast.
+
+ InitializeListHead(&DownRoutesList);
+
+ for(seg=0; seg<SegmentCount; seg++) {
+
+ FirstRoute = TRUE;
+
+ // LOCK THE ROUTING TABLE
+ ExAcquireSpinLock(&SegmentLocksTable[seg], &oldirql);
+
+ while((rtep = GetRoute(seg, FirstRoute)) != NULL) {
+
+ FirstRoute = FALSE;
+
+ // check if this is a locally attached route
+ if(rtep->Flags & IPX_ROUTER_PERMANENT_ENTRY) {
+
+ // local route - do not delete it
+
+ // mark it as down - temporarily
+ tmp = rtep->HopCount;
+ rtep->HopCount = 16;
+
+ // add the route to the packets we prepare for bcast
+ AddRouteToBcastSndReq(&DownRoutesList, rtep);
+
+ // restore the hop count
+ rtep->HopCount = tmp;
+ }
+ else
+ {
+ // non local route - delete it
+
+ IpxDeleteRoute(seg, rtep);
+
+ // mark it as down
+ rtep->HopCount = 16;
+
+ // add the route to the packets we prepare for bcast
+ AddRouteToBcastSndReq(&DownRoutesList, rtep);
+
+ // finally, free the route entry
+ ExFreePool(rtep);
+ }
+ }
+
+ // UNLOCK THE ROUTING TABLE
+ ExReleaseSpinLock(&SegmentLocksTable[seg], oldirql);
+
+ } // for all segments
+
+ // broadcast all the deleted routes
+ while((sndreqp = GetBcastSndReq(&DownRoutesList, &NicId)) != NULL) {
+
+ // get the nic ptr for this snd req
+ niccbp = NicCbPtrTab[NicId];
+
+ // set up the request to send a bcast response with the changes
+ // to all the nics except this one
+ // The send is made with WAIT ON EVENT option so that we don't download
+ // until all sends are completed.
+ BroadcastRipUpdate(sndreqp, niccbp, &BcastSndReqEvent);
+ }
+}
diff --git a/private/ntos/tdi/isn/rip/stubs.c b/private/ntos/tdi/isn/rip/stubs.c
new file mode 100644
index 000000000..00eb42f8f
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/stubs.c
@@ -0,0 +1,38 @@
+
+#include "rtdefs.h"
+
+// define stubs for functions not implemented
+
+VOID
+RtStatus (
+ IN USHORT NicId,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength
+)
+{
+ return;
+}
+
+VOID
+RtFindRouteComplete (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute
+)
+{
+ return;
+}
+
+VOID
+NicCloseComplete(PNICCB niccbp)
+{
+ return;
+}
+
+VOID
+RtScheduleRoute (
+ IN PIPX_ROUTE_ENTRY RouteEntry
+)
+{
+ return;
+}
diff --git a/private/ntos/tdi/isn/rip/timer.c b/private/ntos/tdi/isn/rip/timer.c
new file mode 100644
index 000000000..de65d6131
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/timer.c
@@ -0,0 +1,140 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: timer.c
+//
+// Description: global timer manager
+//
+// Author: Stefan Solomon (stefans) October 18, 1993.
+//
+// Revision History:
+//
+//***
+
+#include "rtdefs.h"
+
+//*** Definitions of time intervals ***
+
+// global timer tick
+#define TIME_1SEC 1L
+
+// time to scavenge the rcv pkt pool in seconds
+#define RCVPKT_POOL_TIMEOUT 2
+
+// time to increment the wan Inactivity timer (1 minute)
+#define WAN_INACTIVITY_TIMEOUT 60
+
+VOID
+WanInactivityTimer(VOID);
+
+
+
+KTIMER GlobalTimer;
+KDPC GlobalTimerDpc;
+
+UINT RcvPktPoolTimerCount;
+UINT WanInactivityTimerCount;
+
+VOID
+RtTimer(PKDPC Dpc,
+ PVOID DefferedContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2);
+
+
+VOID
+InitRtTimer(VOID)
+{
+ // initialize the 5 secs global timer
+ KeInitializeDpc(&GlobalTimerDpc, RtTimer, NULL);
+ KeInitializeTimer(&GlobalTimer);
+
+ // init the timeout for the rcv pkt pool scavenger
+ RcvPktPoolTimerCount = RCVPKT_POOL_TIMEOUT;
+
+ // init rip aging and bcast timer
+ InitRipTimer();
+
+ // init the timeout for the Wan Inactivity timer
+ WanInactivityTimerCount = WAN_INACTIVITY_TIMEOUT;
+}
+
+VOID
+StartRtTimer(VOID)
+{
+ LARGE_INTEGER timeout;
+
+ timeout.LowPart = (ULONG)(-TIME_1SEC * 10000000L);
+ timeout.HighPart = -1;
+
+ KeSetTimer(&GlobalTimer, timeout, &GlobalTimerDpc);
+}
+
+VOID
+StopRtTimer(VOID)
+{
+ BOOLEAN rc = FALSE;
+
+ while(rc == FALSE) {
+
+ rc = KeCancelTimer(&GlobalTimer);
+ }
+}
+
+VOID
+RtTimer(PKDPC Dpc,
+ PVOID DefferedContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2)
+{
+ // call the rcv pkt pool scavenger every 2 secs
+ if(--RcvPktPoolTimerCount == 0) {
+
+ RcvPktPoolTimerCount = RCVPKT_POOL_TIMEOUT;
+ RcvPktPoolScavenger();
+ }
+
+ // call the rip aging and bcast timer
+ RipTimer();
+
+ // call the wan Inactivity timer every 60 seconds
+ if(--WanInactivityTimerCount == 0) {
+
+ WanInactivityTimerCount = WAN_INACTIVITY_TIMEOUT;
+ WanInactivityTimer();
+ }
+
+ // re-start the timer
+ StartRtTimer();
+}
+
+//***
+//
+// Function: WanInactivityTimer
+//
+// Descr: Scans the niccbs and increments the inactivity counter for
+// all WAN nics.
+//
+//***
+
+VOID
+WanInactivityTimer(VOID)
+{
+ PNICCB niccbp;
+ USHORT i;
+
+ // increment the Inactivity counter for all WAN nics which are active
+ for(i=0; i<MaximumNicCount; i++) {
+
+ niccbp = NicCbPtrTab[i];
+
+ if((niccbp->NicState == NIC_ACTIVE) &&
+ (niccbp->DeviceType == NdisMediumWan)) {
+
+ IpxIncrementWanInactivity(niccbp->NicId);
+ }
+ }
+}
diff --git a/private/ntos/tdi/isn/rip/up/makefile b/private/ntos/tdi/isn/rip/up/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/up/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isn/rip/up/sources b/private/ntos/tdi/isn/rip/up/sources
new file mode 100644
index 000000000..85cdb3764
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/up/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+UP_DRIVER=yes
+
+TARGETPATH=obj
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/isn/rip/utils.h b/private/ntos/tdi/isn/rip/utils.h
new file mode 100644
index 000000000..90a1f9762
--- /dev/null
+++ b/private/ntos/tdi/isn/rip/utils.h
@@ -0,0 +1,77 @@
+/*******************************************************************/
+/* Copyright(c) 1993 Microsoft Corporation */
+/*******************************************************************/
+
+//***
+//
+// Filename: utils.h
+//
+// Description: Contains miscellaneous utilities
+//
+// Author: Stefan Solomon (stefans) October 4, 1993.
+//
+// Revision History:
+//
+//***
+
+#ifndef _UTILS_
+#define _UTILS_
+
+//*** General Spin Lock Utilities ***
+
+#define INITIALIZE_SPIN_LOCK(lockp) \
+ NdisAllocateSpinLock(lockp)
+
+#define DEINITIALIZE_SPIN_LOCK(lock) \
+ NdisFreeSpinLock(lock)
+
+#define ACQUIRE_SPIN_LOCK(lockp) \
+ NdisAcquireSpinLock(lockp)
+
+#define RELEASE_SPIN_LOCK(lockp) \
+ NdisReleaseSpinLock(lockp)
+
+//*** Routing Table Spin Locks ***
+
+#define ACQUIRE_RTSEGMENT_SPIN_LOCK(segment, oldirqlp) \
+ ExAcquireSpinLock(SegmentLocksTable + segment, oldirqlp)
+
+#define RELEASE_RTSEGEMENT_SPIN_LOCK(segment, oldirqlp) \
+ ExReleaseSpinLock(SegmentLocksTable + segment, oldirqlp)
+
+/*
+ * The following macros deal with on-the-wire short and long values
+ *
+ * On the wire format is big-endian i.e. a long value of 0x01020304 is
+ * represented as 01 02 03 04.
+ * Similarly a short value of 0x0102 is represented as 01 02.
+ *
+ * The host format is not assumed since it will vary from processor to
+ * processor.
+ */
+
+// Get a short from on-the-wire format to a USHORT in the host format
+#define GETSHORT2USHORT(DstPtr, SrcPtr) \
+ *(PUSHORT)(DstPtr) = ((*((PUCHAR)(SrcPtr)+0) << 8) + \
+ (*((PUCHAR)(SrcPtr)+1) ))
+
+// Get a long from on-the-wire format to a ULONG in the host format
+#define GETLONG2ULONG(DstPtr, SrcPtr) \
+ *(PULONG)(DstPtr) = ((*((PUCHAR)(SrcPtr)+0) << 24) + \
+ (*((PUCHAR)(SrcPtr)+1) << 16) + \
+ (*((PUCHAR)(SrcPtr)+2) << 8) + \
+ (*((PUCHAR)(SrcPtr)+3) ))
+
+// Put a USHORT from the host format to a short to on-the-wire format
+#define PUTUSHORT2SHORT(DstPtr, Src) \
+ *((PUCHAR)(DstPtr)+0) = (UCHAR) ((USHORT)(Src) >> 8), \
+ *((PUCHAR)(DstPtr)+1) = (UCHAR)(Src)
+
+// Put a ULONG from the host format to an array of 4 UCHARs on-the-wire format
+#define PUTULONG2LONG(DstPtr, Src) \
+ *((PUCHAR)(DstPtr)+0) = (UCHAR) ((ULONG)(Src) >> 24), \
+ *((PUCHAR)(DstPtr)+1) = (UCHAR) ((ULONG)(Src) >> 16), \
+ *((PUCHAR)(DstPtr)+2) = (UCHAR) ((ULONG)(Src) >> 8), \
+ *((PUCHAR)(DstPtr)+3) = (UCHAR) (Src)
+
+#endif // _UTILS_
diff --git a/private/ntos/tdi/isn/sockhelp/makefile b/private/ntos/tdi/isn/sockhelp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isn/sockhelp/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isn/sockhelp/sources b/private/ntos/tdi/isn/sockhelp/sources
new file mode 100644
index 000000000..cfa9e8e30
--- /dev/null
+++ b/private/ntos/tdi/isn/sockhelp/sources
@@ -0,0 +1,32 @@
+!IF 0
+
+Copyright (c) 1993 Micro Computer Systems, Inc
+
+!ENDIF
+
+MAJORCOMP=nwlink
+MINORCOMP=wshisn
+DLLBASE=0x75a00000
+
+TARGETNAME=wshisn
+TARGETPATH=obj
+TARGETPATHLIB=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=DYNLINK
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\wsock32.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib
+
+USE_NTDLL=1
+
+!IF 1
+INCLUDES=..\inc;..\..\..\..\inc
+!ELSE
+INCLUDES=..\inc;$(BASEDIR)\private\inc
+!ENDIF
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=wshisn.c \
+ wshelper.c \
+ wshutil.c \
+ wshisn.rc
+
diff --git a/private/ntos/tdi/isn/sockhelp/wshelper.c b/private/ntos/tdi/isn/sockhelp/wshelper.c
new file mode 100644
index 000000000..5895c4791
--- /dev/null
+++ b/private/ntos/tdi/isn/sockhelp/wshelper.c
@@ -0,0 +1,1778 @@
+/****************************************************************************
+* (c) Copyright 1993 Micro Computer Systems, Inc. All rights reserved.
+*****************************************************************************
+*
+* Title: IPX WinSock Helper DLL for Windows NT
+*
+* Module: ipx/sockhelp/wshelper.c
+*
+* Version: 1.00.00
+*
+* Date: 04-08-93
+*
+* Author: Brian Walker
+*
+*****************************************************************************
+*
+* Change Log:
+*
+* Date DevSFC Comment
+* -------- ------ -------------------------------------------------------
+*
+*****************************************************************************
+*
+* Functional Description:
+*
+****************************************************************************/
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#include <windef.h>
+#include <winbase.h>
+#include <tdi.h>
+
+#include <winsock.h>
+#include <wsahelp.h>
+#include <basetyps.h>
+#include <nspapi.h>
+#include <nspapip.h>
+#include <wsipx.h>
+#include <wsnwlink.h>
+
+#include <isnkrnl.h>
+
+#if defined(UNICODE)
+#define NWLNKSPX_SERVICE_NAME L"nwlnkspx"
+#else
+#define NWLNKSPX_SERVICE_NAME "nwlnkspx"
+#endif
+
+
+typedef struct _IPX_OLD_ADDRESS_DATA {
+ UINT adapternum;
+ UCHAR netnum[4];
+ UCHAR nodenum[6];
+} IPX_OLD_ADDRESS_DATA, *PIPX_OLD_ADDRESS_DATA;
+
+
+/** Device names for IPX sockets **/
+
+#define ISNDGRAM_DEVNAME L"\\Device\\NwlnkIpx"
+
+/** Device names for SPX/SPXII sockets **/
+
+#define ISNSTREAM_DEVNAME L"\\Device\\NwlnkSpx\\SpxStream"
+#define ISNSEQPKT_DEVNAME L"\\Device\\NwlnkSpx\\Spx"
+
+#define ISNSTREAMII_DEVNAME L"\\Device\\NwlnkSpx\\Stream"
+#define ISNSEQPKTII_DEVNAME L"\\Device\\NwlnkSpx"
+
+/** Friendly names for IPX and SPX. **/
+
+#define SPX_NAME L"SPX"
+#define SPX2_NAME L"SPX II"
+#define IPX_NAME L"IPX"
+
+/** Start for IPX protocol families **/
+
+#define MCSBASE_DGRAM NSPROTO_IPX
+
+/** **/
+
+UCHAR wsh_bcast[6] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+// SPX Loaded flag, set for each process
+BOOLEAN SpxLoaded = FALSE;
+
+//
+// IPX/SPX provider GUIDs.
+//
+
+GUID IpxProviderGuid =
+ { /* 11058240-be47-11cf-95c8-00805f48a192 */
+ 0x11058240,
+ 0xbe47,
+ 0x11cf,
+ { 0x95, 0xc8, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}
+ };
+
+GUID SpxProviderGuid =
+ { /* 11058241-be47-11cf-95c8-00805f48a192 */
+ 0x11058241,
+ 0xbe47,
+ 0x11cf,
+ { 0x95, 0xc8, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}
+ };
+
+/** Forward Decls/External Prototypes **/
+DWORD
+WshLoadSpx(
+ VOID);
+
+extern
+INT
+do_tdi_action(
+ HANDLE,
+ ULONG,
+ PUCHAR,
+ INT,
+ BOOLEAN,
+ PHANDLE OPTIONAL);
+
+/*page****************************************************************
+ These are the triples we support.
+*********************************************************************/
+typedef struct _MAPPING_TRIPLE {
+ INT triple_addrfam;
+ INT triple_socktype;
+ INT triple_protocol;
+} MAPPING_TRIPLE, *PMAPPING_TRIPLE;
+#define MAPPING_NUM_COLUMNS 3
+
+extern MAPPING_TRIPLE stream_triples[];
+extern int stream_num_triples;
+extern int stream_table_size;
+
+extern MAPPING_TRIPLE dgram_triples[];
+extern int dgram_num_triples;
+extern int dgram_table_size;
+
+/** Forward declarations on internal routines **/
+
+BOOLEAN is_triple_in_list(PMAPPING_TRIPLE, ULONG, INT, INT, INT);
+
+/**
+ There is one of these structures allocated for every
+ socket that is created for us.
+**/
+
+typedef struct _WSHIPX_SOCKET_CONTEXT {
+ INT con_addrfam;
+ INT con_socktype;
+ INT con_pcol;
+ INT con_flags;
+ UCHAR con_sendptype; /* Current send packet type */
+ UCHAR con_recvptype; /* Recv ptype we are filtering on */
+ UCHAR con_dstype; /* Datastream type */
+} WSHIPX_SOCKET_CONTEXT, *PWSHIPX_SOCKET_CONTEXT;
+
+/** Values for con_flags **/
+
+#define WSHCON_FILTER 0x0001 /* We are filtering on recv pkt type */
+#define WSHCON_EXTADDR 0x0002 /* Extended addressing is on */
+#define WSHCON_SENDHDR 0x0004 /* Send header flag */
+#define WSHCON_RCVBCAST 0x0008 /* It does receive broadcasts */
+#define WSHCON_IMM_SPXACK 0x0020 /* Immediate spx acks no piggyback */
+
+/*page***************************************************************
+ W S H O p e n S o c k e t
+
+ This is called for the socket call. We make sure that
+ we support the address family/socket type/protocol triple
+ given and then we will allocate some memory to keep track
+ of the socket.
+
+ Arguments - addrfam = Entry: Address family from socket call
+ Exit: Filled in address family
+ socktype = Entry: Socket type from socket call
+ Exit: Filled in socket type
+ pcol = Entry: Protocol from socket call
+ Exit: Filled in protocol
+ devname = Ptr to where to store device name
+ pcontext = Where to store context value
+ events = Bitmask for events we want to know about
+
+ Returns - NO_ERROR = OK
+ Else = WinSock Error Code
+*********************************************************************/
+INT WSHOpenSocket(PINT addrfam, PINT socktype, PINT pcol,
+ PUNICODE_STRING devname, PVOID *pcontext, PDWORD events)
+{
+ PWSHIPX_SOCKET_CONTEXT context;
+
+ /** Determine whether this is DGRAM or STREAM or SEQPACKET **/
+
+ if (is_triple_in_list(stream_triples, stream_num_triples,
+ *addrfam, *socktype, *pcol)) {
+
+ if (*socktype == SOCK_SEQPACKET) {
+ if (*pcol == NSPROTO_SPX)
+ RtlInitUnicodeString(devname, ISNSEQPKT_DEVNAME);
+ else
+ RtlInitUnicodeString(devname, ISNSEQPKTII_DEVNAME);
+ }
+ else {
+ if (*pcol == NSPROTO_SPX)
+ RtlInitUnicodeString(devname, ISNSTREAM_DEVNAME);
+ else
+ RtlInitUnicodeString(devname, ISNSTREAMII_DEVNAME);
+ }
+
+ if (!SpxLoaded) {
+
+ WshLoadSpx();
+
+ }
+ }
+
+ /** Check for DGRAM **/
+
+ else if (is_triple_in_list(dgram_triples, dgram_num_triples,
+ *addrfam, *socktype, *pcol)) {
+
+ RtlInitUnicodeString(devname, ISNDGRAM_DEVNAME);
+ }
+
+ /**
+ All others are errors. This should never happen unless
+ the registry information is wrong.
+ **/
+
+ else
+ return WSAEINVAL;
+
+ /** Allocate context for the socket **/
+
+ context = RtlAllocateHeap(RtlProcessHeap(), 0L, sizeof(*context));
+ if (context == NULL)
+ return WSAENOBUFS;
+
+ /** Init the context **/
+
+ context->con_addrfam = *addrfam;
+ context->con_socktype = *socktype;
+ context->con_pcol = *pcol;
+ context->con_flags = WSHCON_RCVBCAST;
+ context->con_sendptype = (UCHAR)(*pcol - MCSBASE_DGRAM);
+ context->con_recvptype = 0;
+ context->con_dstype = 0;
+
+ /**
+ Tell the Windows Sockets DLL which state transitions we
+ are interested in.
+ **/
+
+ *events = WSH_NOTIFY_CLOSE | WSH_NOTIFY_BIND | WSH_NOTIFY_CONNECT;
+
+ /** Give WinSock DLL our context pointer **/
+
+ *pcontext = context;
+
+ /** Everything OK - return OK **/
+
+ return NO_ERROR;
+}
+
+/*page**************************************************************
+ W S H G e t S o c k A d d r T y p e
+
+ This routine parses a sockaddr to determine the type
+ of machine address and endpoint address portions of the
+ sockaddr. This is called by the WinSock DLL whenever it
+ needs to interpret a sockaddr.
+
+ Arguments - sockaddr = Ptr to sockaddr struct to evaluate
+ sockaddrlen = Length of data in the sockaddr
+ sockaddrinfo = Ptr to structure to recv info
+ about the sockaddr
+
+ Returns - NO_ERROR = Evaluation OK
+ Else = WinSock error code
+********************************************************************/
+INT WSHGetSockaddrType(PSOCKADDR sockaddr, DWORD sockaddrlen,
+ PSOCKADDR_INFO sockaddrinfo)
+{
+ PSOCKADDR_IPX sa = (PSOCKADDR_IPX)sockaddr;
+
+
+ /** Make sure the address family is correct **/
+
+ if (sa->sa_family != AF_NS)
+ return WSAEAFNOSUPPORT;
+
+ /** Make sure the length is OK **/
+
+ if (sockaddrlen < sizeof(SOCKADDR_IPX))
+ return WSAEFAULT;
+
+ /** Looks like a good addr - determine the type **/
+
+ if (!memcmp(sa->sa_nodenum, wsh_bcast, 6))
+ sockaddrinfo->AddressInfo = SockaddrAddressInfoBroadcast;
+ else
+ sockaddrinfo->AddressInfo = SockaddrAddressInfoNormal;
+
+ /** Determine the endpoint **/
+
+ if (sa->sa_socket == 0)
+ sockaddrinfo->EndpointInfo = SockaddrEndpointInfoWildcard;
+ else if (ntohs(sa->sa_socket) < 2000)
+ sockaddrinfo->EndpointInfo = SockaddrEndpointInfoReserved;
+ else
+ sockaddrinfo->EndpointInfo = SockaddrEndpointInfoNormal;
+
+ /** **/
+
+ return NO_ERROR;
+}
+
+/*page**************************************************************
+ W S H G e t W i n s o c k M a p p i n g
+
+ Returns the list of address family/socket type/protocol
+ triples supported by this helper DLL.
+
+ Arguments - mapping = Contect ptr from WSAOpenSocket
+ maplen =
+
+ Returns - The length in bytes of a eeded OK
+ Else = WinSock error code
+********************************************************************/
+DWORD WSHGetWinsockMapping(PWINSOCK_MAPPING mapping, DWORD maplen)
+{
+ DWORD len;
+
+ /**
+ Figure how much data we are going to copy into
+ the user buffer.
+ **/
+
+ len = sizeof(WINSOCK_MAPPING) - sizeof(MAPPING_TRIPLE) +
+ dgram_table_size + stream_table_size;
+
+ /**
+ If the buffer passed is too small, then return the size
+ that is needed. The caller should then call us again
+ with a buffer of the correct size.
+ **/
+
+ if (len > maplen)
+ return len;
+
+ /** Fill in the output buffer **/
+
+ mapping->Rows = stream_num_triples + dgram_num_triples;
+ mapping->Columns = MAPPING_NUM_COLUMNS;
+ RtlMoveMemory(mapping->Mapping,
+ stream_triples,
+ stream_table_size);
+
+ RtlMoveMemory((PCHAR)mapping->Mapping + stream_table_size,
+ dgram_triples,
+ dgram_table_size);
+
+ /** Return the number of bytes we filled in **/
+
+ return len;
+}
+
+/*page***************************************************************
+ W S H N o t i f y
+
+ This routine is called for events that we registered at
+ open socket time.
+
+ Arguments - context = Context ptr from WSAOpenSocket
+ handle = Socket handle
+ addrhandle = Datagram Handle
+ connhandle = Connection Handle
+ event = What event happened
+
+ Returns - NO_ERROR = Operation succeeded OK
+ Else = WinSock error code
+*********************************************************************/
+INT WSHNotify(PVOID context, SOCKET handle,
+ HANDLE addrhandle, HANDLE connhandle,
+ DWORD event)
+{
+ INT rc;
+ INT t1;
+ PWSHIPX_SOCKET_CONTEXT ct;
+
+ /** Get context pointer **/
+
+ ct = (PWSHIPX_SOCKET_CONTEXT)context;
+
+ /** On close - just free the context structure **/
+
+ if (event == WSH_NOTIFY_CLOSE) {
+ RtlFreeHeap(RtlProcessHeap(), 0L, context);
+ return NO_ERROR;
+ }
+
+ /** On bind set the send packet type **/
+
+ if (event == WSH_NOTIFY_BIND)
+ {
+ if (ct->con_socktype == SOCK_DGRAM)
+ {
+ /** Set the send packet ptype **/
+ t1 = (UINT)ct->con_sendptype;
+ rc = WSHSetSocketInformation(
+ context, handle, addrhandle,
+ connhandle, NSPROTO_IPX,
+ IPX_PTYPE, (PCHAR)&t1, sizeof(INT));
+
+ if (rc)
+ return rc;
+
+ if (ct->con_flags & WSHCON_EXTADDR)
+ {
+ t1 = 1;
+ rc = WSHSetSocketInformation(
+ context, handle, addrhandle,
+ connhandle, NSPROTO_IPX,
+ IPX_EXTENDED_ADDRESS, (PCHAR)&t1, sizeof(INT));
+
+ if (rc)
+ return rc;
+ }
+
+ /** Set the recv filter packet type **/
+
+ if (ct->con_flags & WSHCON_FILTER)
+ {
+ t1 = (UINT)ct->con_recvptype;
+ rc = WSHSetSocketInformation(
+ context, handle, addrhandle,
+ connhandle, NSPROTO_IPX,
+ IPX_FILTERPTYPE, (PCHAR)&t1, sizeof(INT));
+
+ if (rc)
+ return rc;
+ }
+
+ /** Set up broadcast reception **/
+
+ if (ct->con_flags & WSHCON_RCVBCAST)
+ {
+
+ t1 = 1;
+ rc = WSHSetSocketInformation(
+ context, handle, addrhandle,
+ connhandle, NSPROTO_IPX,
+ IPX_RECEIVE_BROADCAST, (PCHAR)&t1, sizeof(INT));
+
+ if (rc)
+ return rc;
+ }
+
+ /** Enable send header if we need to **/
+ if (ct->con_flags & WSHCON_SENDHDR)
+ {
+ t1 = 1;
+ rc = WSHSetSocketInformation(
+ context, handle, addrhandle,
+ connhandle, NSPROTO_IPX,
+ IPX_RECVHDR, (PCHAR)&t1, sizeof(INT));
+
+ if (rc)
+ return rc;
+ }
+ }
+ else if ((ct->con_socktype == SOCK_STREAM) ||
+ (ct->con_socktype == SOCK_SEQPACKET))
+ {
+ if (ct->con_flags & WSHCON_SENDHDR)
+ {
+ t1 = 1;
+ rc = WSHSetSocketInformation(
+ context, handle, addrhandle,
+ connhandle, NSPROTO_IPX,
+ IPX_RECVHDR, (PCHAR)&t1, sizeof(INT));
+
+ if (rc)
+ return rc;
+ }
+
+ if (ct->con_flags & WSHCON_IMM_SPXACK)
+ {
+ t1 = 1;
+ rc = WSHSetSocketInformation(
+ context, handle, addrhandle,
+ connhandle, NSPROTO_IPX,
+ IPX_IMMEDIATESPXACK, (PCHAR)&t1, sizeof(INT));
+
+ if (rc)
+ return rc;
+ }
+ }
+
+ /** It is OK - return OK **/
+ return NO_ERROR;
+ }
+
+ /** On connect set things not set already **/
+ if (event == WSH_NOTIFY_CONNECT)
+ {
+
+ /** If on DGRAM - just return OK **/
+ if (ct->con_socktype == SOCK_DGRAM)
+ return NO_ERROR;
+
+ /**
+ If the datastream type has been set - set it
+ **/
+
+ if (ct->con_dstype)
+ {
+ rc = do_tdi_action(connhandle, MSPX_SETDATASTREAM, &ct->con_dstype, 1, FALSE, NULL);
+ if (rc)
+ return rc;
+ }
+
+ /** It is OK - return OK **/
+ return NO_ERROR;
+ }
+
+ /** All others are bad **/
+ return WSAEINVAL;
+}
+
+
+/*page**************************************************************
+ W S H G e t S o c k I n f o r m a t i o n
+
+ This routine retrieves information about a socket for those
+ socket options supported in this DLL. The options
+ supported here are SO_KEEPALIVE and SO_DONTROUTE. This
+ routine is called by the WinSock DLL when a level/option name
+ combination is passed to getsockopt that the WinSock DLL
+ does not understand.
+
+ Arguments - context = Context ptr from WSAOpenSocket
+ handle = Socket handle
+ addrhandle = Datagram Handle
+ connhandle = Connection Handle
+ level = Level from getsockopt call
+ optname = Option name from getsockopt call
+ optvalue = Option value ptr from getsockopt call
+ optlength = Option length field from getsockopt call
+
+ Returns - NO_ERROR = Operation succeeded OK
+ Else = WinSock error code
+********************************************************************/
+INT WSHGetSocketInformation(PVOID context, SOCKET handle,
+ HANDLE addrhandle, HANDLE connhandle,
+ INT level, INT optname, PCHAR optvalue,
+ PINT optlength)
+{
+ PWSHIPX_SOCKET_CONTEXT ct;
+ INT rc;
+ INT ibuf[2];
+ PIPX_ADDRESS_DATA p;
+
+ /** Get ptr to context **/
+
+ ct = (PWSHIPX_SOCKET_CONTEXT)context;
+
+ //
+ // Check if this is an internal request for context information.
+ //
+
+ if ( level == SOL_INTERNAL && optname == SO_CONTEXT ) {
+
+ //
+ // The Windows Sockets DLL is requesting context information
+ // from us. If an output buffer was not supplied, the Windows
+ // Sockets DLL is just requesting the size of our context
+ // information.
+ //
+
+ if ( optvalue != NULL ) {
+
+ //
+ // Make sure that the buffer is sufficient to hold all the
+ // context information.
+ //
+
+ if ( *optlength < sizeof(*ct) ) {
+ return WSAEFAULT;
+ }
+
+ //
+ // Copy in the context information.
+ //
+
+ RtlCopyMemory( optvalue, ct, sizeof(*ct) );
+ }
+
+ *optlength = sizeof(*ct);
+
+ return NO_ERROR;
+ }
+
+ /** The only level we support is NSPROTO_IPX **/
+
+ if (level != NSPROTO_IPX)
+ return WSAEINVAL;
+
+ /** Fill in the result based on the options name **/
+
+ switch (optname) {
+
+ /** Get the current send packet type **/
+
+ case IPX_PTYPE:
+
+ /** Make sure the length is OK **/
+
+ if (*optlength < sizeof(INT))
+ return WSAEFAULT;
+
+ /** Make sure this is for a DGRAM socket **/
+
+ if (ct->con_socktype != SOCK_DGRAM)
+ return WSAEINVAL;
+
+ /** Set the type **/
+
+ *(UINT *)optvalue = (UINT)ct->con_sendptype;
+ *optlength = sizeof(UINT);
+ break;
+
+ /** Get the current recv packet type filter **/
+
+ case IPX_FILTERPTYPE:
+
+ /** Make sure length is OK **/
+
+ if (*optlength < sizeof(INT))
+ return WSAEFAULT;
+
+ /** Make sure this is for a DGRAM socket **/
+
+ if (ct->con_socktype != SOCK_DGRAM)
+ return WSAEINVAL;
+
+ /** If option not on - return error **/
+
+ if (!(ct->con_flags & WSHCON_FILTER))
+ return WSAEINVAL;
+
+ /** Save the new value **/
+
+ *(UINT *)optvalue = (UINT)ct->con_recvptype;
+ *optlength = sizeof(UINT);
+ break;
+
+ /** Get the max DGRAM size that can be sent **/
+
+ case IPX_MAXSIZE:
+
+ /** Make sure length is OK **/
+
+ if (*optlength < sizeof(INT))
+ return WSAEFAULT;
+
+ /** Make sure this is for a DGRAM socket **/
+
+ if (ct->con_socktype != SOCK_DGRAM)
+ return WSAEINVAL;
+
+ /** Get the value from the driver **/
+
+ rc = do_tdi_action(addrhandle, MIPX_GETPKTSIZE, (PUCHAR)ibuf, sizeof(INT)*2, TRUE, NULL);
+
+ *(INT *)optvalue = ibuf[1];
+ *optlength = sizeof(int);
+
+ /** Return the result **/
+
+ return rc;
+
+ /** Get the max adapternum that is valid **/
+
+ case IPX_MAX_ADAPTER_NUM:
+
+ /** Make sure length is OK **/
+
+ if (*optlength < sizeof(INT))
+ return WSAEFAULT;
+
+ /** Make sure this is for a DGRAM socket **/
+
+ if (ct->con_socktype != SOCK_DGRAM)
+ return WSAEINVAL;
+
+ /** Get the value from the driver **/
+
+ rc = do_tdi_action(addrhandle, MIPX_ADAPTERNUM, optvalue, sizeof(INT), TRUE, NULL);
+
+ *optlength = sizeof(int);
+
+ /** Return the result **/
+
+ return rc;
+
+ /** Get SPX statistics **/
+
+ case IPX_SPXGETCONNECTIONSTATUS:
+
+ /** Make sure data length OK **/
+
+ if (*optlength < sizeof(IPX_SPXCONNSTATUS_DATA))
+ return WSAEFAULT;
+
+ /** Make sure this is for a STREAM socket **/
+
+ if ((ct->con_socktype != SOCK_STREAM) &&
+ (ct->con_socktype != SOCK_SEQPACKET)) {
+
+ return WSAEINVAL;
+ }
+
+ /** Send it to the driver **/
+
+ rc = do_tdi_action(
+ connhandle,
+ MSPX_GETSTATS,
+ optvalue,
+ *optlength,
+ FALSE,
+ NULL);
+
+ if (rc)
+ return rc;
+
+ *optlength = sizeof(IPX_SPXCONNSTATUS_DATA);
+
+ /** Return OK **/
+
+ return NO_ERROR;
+
+ /** Get the current datastream type to send pkts with **/
+
+ case IPX_DSTYPE:
+
+ /** Make sure length is OK **/
+
+ if (*optlength < sizeof(INT))
+ return WSAEFAULT;
+
+ /** Make sure this is for a STREAM socket **/
+
+ if ((ct->con_socktype != SOCK_STREAM) &&
+ (ct->con_socktype != SOCK_SEQPACKET)) {
+
+ return WSAEINVAL;
+ }
+
+ /** Save the new value **/
+
+ *(UINT *)optvalue = (UINT)ct->con_dstype;
+ *optlength = sizeof(UINT);
+ break;
+
+ /** Get net information **/
+
+ case IPX_GETNETINFO:
+
+ /** Make sure data length OK **/
+
+ if (*optlength < sizeof(IPX_NETNUM_DATA))
+ return WSAEFAULT;
+
+ /** Make sure this is for a DGRAM socket **/
+
+ if (ct->con_socktype != SOCK_DGRAM)
+ return WSAEINVAL;
+
+ /** Send it to the driver **/
+
+ rc = do_tdi_action(
+ addrhandle,
+ MIPX_GETNETINFO,
+ optvalue,
+ *optlength,
+ TRUE,
+ NULL);
+
+ if (rc) {
+ return rc;
+ }
+
+ *optlength = sizeof(IPX_NETNUM_DATA);
+
+ /** Return OK **/
+
+ return NO_ERROR;
+
+ /** Get net information without RIPping **/
+
+ case IPX_GETNETINFO_NORIP:
+
+ /** Make sure data length OK **/
+
+ if (*optlength < sizeof(IPX_NETNUM_DATA))
+ return WSAEFAULT;
+
+ /** Make sure this is for a DGRAM socket **/
+
+ if (ct->con_socktype != SOCK_DGRAM)
+ return WSAEINVAL;
+
+ /** Send it to the driver **/
+
+ rc = do_tdi_action(
+ addrhandle,
+ MIPX_GETNETINFO_NR,
+ optvalue,
+ *optlength,
+ TRUE,
+ NULL);
+
+ if (rc) {
+ return rc;
+ }
+
+ *optlength = sizeof(IPX_NETNUM_DATA);
+
+ /** Return OK **/
+
+ return NO_ERROR;
+
+ /** Like GETNETINFO, but force a re-rip **/
+
+ case IPX_RERIPNETNUMBER:
+
+ /** Make sure data length OK **/
+
+ if (*optlength < sizeof(IPX_NETNUM_DATA))
+ return WSAEFAULT;
+
+ /** Make sure this is for a DGRAM socket **/
+
+ if (ct->con_socktype != SOCK_DGRAM)
+ return WSAEINVAL;
+
+ /** Send it to the driver **/
+
+ rc = do_tdi_action(
+ addrhandle,
+ MIPX_RERIPNETNUM,
+ optvalue,
+ *optlength,
+ TRUE,
+ NULL);
+
+ if (rc) {
+ return rc;
+ }
+
+ *optlength = sizeof(IPX_NETNUM_DATA);
+
+ /** Return OK **/
+
+ return NO_ERROR;
+
+ /** Get card information **/
+
+ case IPX_ADDRESS_NOTIFY:
+
+ /** We need the action header, the data, and the event handle **/
+
+ if (*optlength < (INT)(FIELD_OFFSET(NWLINK_ACTION, Data[0]) + sizeof(IPX_ADDRESS_DATA) + sizeof(HANDLE)))
+ return WSAEFAULT;
+
+ /** Otherwise just fall through **/
+
+ case IPX_ADDRESS:
+
+ /** Make sure data length OK **/
+
+ if (*optlength < sizeof(IPX_OLD_ADDRESS_DATA))
+ return WSAEFAULT;
+
+ /** Make sure this is for a DGRAM socket **/
+
+ if (ct->con_socktype != SOCK_DGRAM)
+ return WSAEINVAL;
+
+ /** Send it to the driver **/
+
+ if (optname == IPX_ADDRESS) {
+
+ rc = do_tdi_action(
+ addrhandle,
+ MIPX_GETCARDINFO,
+ optvalue,
+ *optlength,
+ TRUE,
+ NULL);
+
+ } else {
+
+ rc = do_tdi_action(
+ addrhandle,
+ MIPX_NOTIFYCARDINFO,
+ optvalue,
+ *optlength - sizeof(HANDLE),
+ TRUE,
+ (PHANDLE)(optvalue + FIELD_OFFSET(NWLINK_ACTION, Data[0]) + sizeof(IPX_ADDRESS_DATA)));
+ }
+
+ if (rc) {
+ p = (PIPX_ADDRESS_DATA)optvalue;
+ memset(p->netnum, 0xFF, 4);
+ memset(p->nodenum, 0xFF, 6);
+ return rc;
+ }
+
+ /** Return OK **/
+
+ if (*optlength < sizeof(IPX_ADDRESS_DATA)) {
+ *optlength = sizeof(IPX_OLD_ADDRESS_DATA);
+ } else if (*optlength < sizeof(IPX_ADDRESS_DATA)) {
+ *optlength = sizeof(IPX_ADDRESS_DATA);
+ }
+
+ return NO_ERROR;
+
+ /** All others are error **/
+
+ default:
+ return WSAENOPROTOOPT;
+ }
+
+ /** All is OK **/
+
+ return NO_ERROR;
+}
+
+/*page***************************************************************
+ W S H S e t S o c k e t I n f o r m a t i o n
+
+ This routine sets information about a socket for those
+ options supported in this helper DLL. This routine
+ is called when a setsockopt call is made and the option/level
+ passed is unknown to the WinSock DLL.
+
+ Arguments - context = Context ptr from WSAOpenSocket
+ handle = Socket handle
+ addrhandle = Datagram Handle
+ connhandle = Connection Handle
+ level = Level from getsockopt call
+ optname = Option name from getsockopt call
+ optvalue = Option value ptr from getsockopt call
+ optlength = Option length field from getsockopt call
+
+ Returns - NO_ERROR = Operation succeeded OK
+ Else = WinSock error code
+*********************************************************************/
+INT WSHSetSocketInformation(PVOID context, SOCKET handle,
+ HANDLE addrhandle, HANDLE connhandle,
+ INT level, INT optname, PCHAR optvalue,
+ INT optlength)
+{
+ PWSHIPX_SOCKET_CONTEXT ct;
+ INT rc;
+
+ /** Get ptr to context **/
+
+ ct = (PWSHIPX_SOCKET_CONTEXT)context;
+
+ //
+ // Check if this is an internal request for context information.
+ //
+
+ if ( level == SOL_INTERNAL && optname == SO_CONTEXT ) {
+
+ //
+ // The Windows Sockets DLL is requesting that we set context
+ // information for a new socket. If the new socket was
+ // accept()'ed, then we have already been notified of the socket
+ // and HelperDllSocketContext will be valid. If the new socket
+ // was inherited or duped into this process, then this is our
+ // first notification of the socket and HelperDllSocketContext
+ // will be equal to NULL.
+ //
+ // Insure that the context information being passed to us is
+ // sufficiently large.
+ //
+
+ if ( optlength < sizeof(*ct) ) {
+ return WSAEINVAL;
+ }
+
+ if ( ct == NULL ) {
+
+ //
+ // This is our notification that a socket handle was
+ // inherited or duped into this process. Allocate a context
+ // structure for the new socket.
+ //
+
+ ct = RtlAllocateHeap( RtlProcessHeap( ), 0, sizeof(*ct) );
+ if ( ct == NULL ) {
+ return WSAENOBUFS;
+ }
+
+ //
+ // Copy over information into the context block.
+ //
+
+ RtlCopyMemory( ct, optvalue, sizeof(*ct) );
+
+ //
+ // Tell the Windows Sockets DLL where our context information is
+ // stored so that it can return the context pointer in future
+ // calls.
+ //
+
+ *(PWSHIPX_SOCKET_CONTEXT *)optvalue = ct;
+
+ return NO_ERROR;
+
+ } else {
+
+ PWSHIPX_SOCKET_CONTEXT parentContext;
+ INT one = 1;
+
+ //
+ // The socket was accept()'ed and it needs to have the same
+ // properties as it's parent. The OptionValue buffer
+ // contains the context information of this socket's parent.
+ //
+
+ parentContext = (PWSHIPX_SOCKET_CONTEXT)optvalue;
+
+ ASSERT( ct->con_addrfam == parentContext->con_addrfam );
+ ASSERT( ct->con_socktype == parentContext->con_socktype );
+ ASSERT( ct->con_pcol == parentContext->con_pcol );
+
+ return NO_ERROR;
+ }
+ }
+
+ /** We only support level NSPROTO_IPX **/
+
+ if (level != NSPROTO_IPX)
+ return WSAEINVAL;
+
+ /** Handle the options **/
+
+ switch (optname) {
+
+ /** Set the send packet type **/
+
+ case IPX_PTYPE:
+
+ /** Make sure length is OK **/
+
+ if (optlength < sizeof(INT))
+ return WSAEFAULT;
+
+ /** Make sure this is for a DGRAM socket **/
+
+ if (ct->con_socktype != SOCK_DGRAM)
+ return WSAEINVAL;
+
+ /** Get the value and check it **/
+
+ rc = *(INT *)optvalue;
+ if ((rc < 0) || (rc > 255))
+ return WSAEINVAL;
+
+ /** Save the new value **/
+
+ ct->con_sendptype = (UCHAR)rc;
+
+ /** Send the new value down to the driver **/
+
+ if (addrhandle)
+ rc = do_tdi_action(addrhandle, MIPX_SETSENDPTYPE, &ct->con_sendptype, 1, TRUE, NULL);
+ else
+ rc = NO_ERROR;
+
+ return rc;
+
+ /** Set the recv filter for packet type **/
+
+ case IPX_FILTERPTYPE:
+
+ /** Make sure length is OK **/
+
+ if (optlength < sizeof(INT))
+ return WSAEFAULT;
+
+ /** Make sure this is for a DGRAM socket **/
+
+ if (ct->con_socktype != SOCK_DGRAM)
+ return WSAEINVAL;
+
+ /** Get the value and check it **/
+
+ rc = *(INT *)optvalue;
+ if ((rc < 0) || (rc > 255))
+ return WSAEINVAL;
+
+ /** Save the new value **/
+
+ ct->con_recvptype = (UCHAR)rc;
+ ct->con_flags |= WSHCON_FILTER;
+
+ /** Send the new value down to the driver **/
+
+ if (addrhandle)
+ rc = do_tdi_action(addrhandle, MIPX_FILTERPTYPE, &ct->con_recvptype, 1, TRUE, NULL);
+ else
+ rc = NO_ERROR;
+
+ /** **/
+
+ return rc;
+
+ /** Stop filtering recv on pkt type **/
+
+ case IPX_STOPFILTERPTYPE:
+
+ /** Make sure this is for a DGRAM socket **/
+
+ if (ct->con_socktype != SOCK_DGRAM)
+ return WSAEINVAL;
+
+ /** Turn off the flag **/
+
+ ct->con_flags &= ~WSHCON_FILTER;
+
+ /** Tell the driver **/
+
+ if (addrhandle)
+ rc = do_tdi_action(addrhandle, MIPX_NOFILTERPTYPE, NULL, 0, TRUE, NULL);
+ else
+ rc = NO_ERROR;
+ break;
+
+ /** Set piggyback wait for backtraffic flag **/
+ case IPX_IMMEDIATESPXACK:
+
+ /** Get the optvalue as an INT **/
+
+ rc = *(INT *)optvalue;
+
+ /** **/
+
+ if (rc)
+ {
+ /** Turn it ON **/
+ rc = WSAEINVAL;
+ if ((ct->con_socktype == SOCK_STREAM) ||
+ (ct->con_socktype == SOCK_SEQPACKET))
+ {
+ rc = NO_ERROR;
+
+ ct->con_flags |= WSHCON_IMM_SPXACK;
+
+ if (addrhandle)
+ rc = do_tdi_action(addrhandle, MSPX_NOACKWAIT, NULL, 0, TRUE, NULL);
+ }
+ }
+ else
+ {
+ /** Turn it OFF **/
+ rc = WSAEINVAL;
+ if ((ct->con_socktype == SOCK_STREAM) ||
+ (ct->con_socktype == SOCK_SEQPACKET))
+ {
+ rc = NO_ERROR;
+
+ ct->con_flags &= ~WSHCON_IMM_SPXACK;
+
+ if (addrhandle)
+ rc = do_tdi_action(addrhandle, MSPX_ACKWAIT, NULL, 0, TRUE, NULL);
+ }
+ }
+
+ /** Return the result **/
+ return rc;
+
+ /** Set to recv pcol hdrs with data **/
+
+ case IPX_RECVHDR:
+
+ /** Get the optvalue as an INT **/
+ rc = *(INT *)optvalue;
+
+ if (rc)
+ {
+ /** Turn it ON **/
+ ct->con_flags |= WSHCON_SENDHDR;
+
+ /** Send it to the driver **/
+ rc = WSAEINVAL;
+ if (ct->con_socktype == SOCK_DGRAM)
+ {
+ rc = NO_ERROR;
+ if (addrhandle)
+ rc = do_tdi_action(addrhandle, MIPX_SENDHEADER, NULL, 0, TRUE, NULL);
+ }
+ else if ((ct->con_socktype == SOCK_STREAM) ||
+ (ct->con_socktype == SOCK_SEQPACKET))
+ {
+ /** Do this on address handle **/
+ rc = NO_ERROR;
+ if (addrhandle)
+ rc = do_tdi_action(addrhandle, MSPX_SENDHEADER, NULL, 0, TRUE, NULL);
+ }
+ }
+ else
+ {
+
+ /** Turn it OFF **/
+ ct->con_flags &= ~WSHCON_SENDHDR;
+
+ /** Send it to the driver **/
+ rc = WSAEINVAL;
+ if (ct->con_socktype == SOCK_DGRAM)
+ {
+ rc = NO_ERROR;
+ if (addrhandle)
+ rc = do_tdi_action(addrhandle, MIPX_NOSENDHEADER, NULL, 0, TRUE, NULL);
+ }
+ else if ((ct->con_socktype == SOCK_STREAM) ||
+ (ct->con_socktype == SOCK_SEQPACKET))
+ {
+ rc = NO_ERROR;
+ if (addrhandle)
+ rc = do_tdi_action(addrhandle, MSPX_NOSENDHEADER, NULL, 0, TRUE, NULL);
+ }
+ }
+
+ /** Return the result **/
+ return rc;
+
+ /** Set the Datastream type to send pkts with **/
+
+ case IPX_DSTYPE:
+
+ /** Make sure length is OK **/
+
+ if (optlength < sizeof(INT))
+ return WSAEFAULT;
+
+ /** Make sure this is for a STREAM socket **/
+
+ if ((ct->con_socktype != SOCK_STREAM) &&
+ (ct->con_socktype != SOCK_SEQPACKET)) {
+
+ return WSAEINVAL;
+ }
+
+ /** Get the value and check it **/
+
+ rc = *(INT *)optvalue;
+ if ((rc < 0) || (rc > 255))
+ return WSAEINVAL;
+
+ /** Save the new value **/
+
+ ct->con_dstype = (UCHAR)rc;
+
+ /** Send the new value down to the driver **/
+
+ if (connhandle)
+ rc = do_tdi_action(connhandle, MSPX_SETDATASTREAM, &ct->con_dstype, 1, FALSE, NULL);
+ else
+ rc = 0;
+
+ /** **/
+
+ return rc;
+
+ /** Set the extended address option **/
+
+ case IPX_EXTENDED_ADDRESS:
+
+ /** Make sure length is OK **/
+
+ if (optlength < sizeof(INT))
+ return WSAEFAULT;
+
+ /** Make sure this is for a DGRAM socket **/
+
+ if (ct->con_socktype != SOCK_DGRAM)
+ return WSAEINVAL;
+
+ /** Get the optvalue as an INT **/
+
+ rc = *(INT *)optvalue;
+
+ /** **/
+
+ if (rc) {
+
+ /** Send the option down to the driver **/
+
+ ct->con_flags |= WSHCON_EXTADDR;
+ if (addrhandle)
+ rc = do_tdi_action(addrhandle, MIPX_SENDADDROPT, NULL, 0, TRUE, NULL);
+ else
+ rc = NO_ERROR;
+ }
+ else {
+
+ /** Send the option down to the driver **/
+
+ ct->con_flags &= ~WSHCON_EXTADDR;
+ if (addrhandle)
+ rc = do_tdi_action(addrhandle, MIPX_NOSENDADDROPT, NULL, 0, TRUE, NULL);
+ else
+ rc = NO_ERROR;
+ }
+ return rc;
+
+
+ /** Set the broadcast reception **/
+
+ case IPX_RECEIVE_BROADCAST:
+
+ /** Make sure length is OK **/
+
+ if (optlength < sizeof(INT))
+ return WSAEFAULT;
+
+ /** Make sure this is for a DGRAM socket **/
+
+ if (ct->con_socktype != SOCK_DGRAM)
+ return WSAEINVAL;
+
+ /** Get the optvalue as an INT **/
+
+ rc = *(INT *)optvalue;
+
+ /** **/
+
+ if (rc) {
+
+ /** Send the option down to the driver **/
+
+ ct->con_flags |= WSHCON_RCVBCAST;
+ if (addrhandle)
+ rc = do_tdi_action(addrhandle, MIPX_RCVBCAST, NULL, 0, TRUE, NULL);
+ else
+ rc = NO_ERROR;
+ }
+ else {
+
+ /** Send the option down to the driver **/
+
+ ct->con_flags &= ~WSHCON_RCVBCAST;
+ if (addrhandle)
+ rc = do_tdi_action(addrhandle, MIPX_NORCVBCAST, NULL, 0, TRUE, NULL);
+ else
+ rc = NO_ERROR;
+ }
+ return rc;
+
+ /** All others return error **/
+
+ default:
+ return WSAENOPROTOOPT;
+ }
+
+ /** All Done OK **/
+
+ return NO_ERROR;
+}
+
+/*page***************************************************************
+ W S H G e t W i l d c a r d S o c k a d d r
+
+ This routing returns a wilcard socket address for the
+ sockets DLL to use.
+
+ Arguments - context = Context ptr from WSAOpenSocket
+ addrp = Ptr to where to store the address
+ addrlen = Ptr to where to store length of address
+
+ Returns - NO_ERROR = Operation succeeded OK
+ Else = WinSock error code
+*********************************************************************/
+INT WSHGetWildcardSockaddr(PVOID context, PSOCKADDR addrp, PINT addrlen)
+{
+
+ /**
+ Setup the address as the address family +
+ all 0's for the rest.
+ **/
+
+ memset(addrp, 0, sizeof(SOCKADDR));
+ addrp->sa_family = AF_NS;
+
+ /** Set the address length **/
+
+ *addrlen = sizeof(SOCKADDR);
+
+ /** Return OK **/
+
+ return NO_ERROR;
+}
+
+/*page***************************************************************
+ i s _ t r i p l e _ i n _ l i s t
+
+ Check to see if the given triple is in the given
+ triple list.
+
+ Arguments - tlist = Ptr to the triple list
+ tlen = Num entries in the triple list
+ addrfam = Address family to look for
+ socktype = Socket Type to look for
+ pcol = Protocol to look for
+
+ Returns - TRUE = Yes
+ FALSE = No
+*********************************************************************/
+BOOLEAN is_triple_in_list(PMAPPING_TRIPLE tlist, ULONG tlen,
+ INT addrfam, INT socktype, INT pcol)
+{
+ ULONG i;
+
+ /**
+ Go thru the list and search to see if we can
+ find the given triple in the list.
+ **/
+
+ for (i = 0 ; i < tlen ; i++,tlist++) {
+
+ /** If it matches - return OK **/
+
+ if ((addrfam == tlist->triple_addrfam) &&
+ (socktype == tlist->triple_socktype) &&
+ (pcol == tlist->triple_protocol))
+
+ return TRUE;
+ }
+
+ /** Not Found **/
+
+ return FALSE;
+}
+
+/*page***************************************************************
+ W S H E n u m P r o t o c o l s
+
+ Enumerates IPX/SPX protocols.
+
+ Returns - NO_ERROR or an error code.
+*********************************************************************/
+INT
+WSHEnumProtocols (
+ IN LPINT lpiProtocols,
+ IN LPTSTR lpTransportKeyName,
+ IN OUT LPVOID lpProtocolBuffer,
+ IN OUT LPDWORD lpdwBufferLength
+ )
+{
+ DWORD bytesRequired;
+ PPROTOCOL_INFOW protocolInfo;
+ BOOL useSpx = FALSE;
+ BOOL useSpx2 = FALSE;
+ BOOL useIpx = FALSE;
+ BOOL spxString;
+ DWORD i;
+ PWCHAR namePtr;
+ INT entriesReturned = 0;
+
+ //
+ // Determine whether we should return information for IPX or SPX.
+ //
+
+ if ( _wcsicmp( L"NwlnkIpx", (LPWSTR)lpTransportKeyName ) == 0 ) {
+ spxString = FALSE;
+ } else {
+ spxString = TRUE;
+ }
+
+ //
+ // Make sure that the caller cares about SPX, SPX2, and/or IPX.
+ //
+
+ if ( ARGUMENT_PRESENT( lpiProtocols ) ) {
+
+ for ( i = 0; lpiProtocols[i] != 0; i++ ) {
+ if ( lpiProtocols[i] == NSPROTO_SPX && spxString ) {
+ useSpx = TRUE;
+ }
+ if ( lpiProtocols[i] == NSPROTO_SPXII && spxString ) {
+ useSpx2 = TRUE;
+ }
+ if ( lpiProtocols[i] == NSPROTO_IPX && !spxString ) {
+ useIpx = TRUE;
+ }
+ }
+
+ } else {
+
+ useSpx = FALSE;
+ useSpx2 = spxString;
+ useIpx = !spxString;
+ }
+
+ if ( !useSpx && !useSpx2 && !useIpx ) {
+ *lpdwBufferLength = 0;
+ return 0;
+ }
+
+ //
+ // Make sure that the caller has specified a sufficiently large
+ // buffer.
+ //
+
+ bytesRequired = (sizeof(PROTOCOL_INFO) * 3) +
+ ( (wcslen( SPX_NAME ) + 1) * sizeof(WCHAR)) +
+ ( (wcslen( SPX2_NAME ) + 1) * sizeof(WCHAR)) +
+ ( (wcslen( IPX_NAME ) + 1) * sizeof(WCHAR));
+
+ if ( bytesRequired > *lpdwBufferLength ) {
+ *lpdwBufferLength = bytesRequired;
+ return -1;
+ }
+
+ //
+ // Initialize local variables.
+ //
+
+ protocolInfo = lpProtocolBuffer;
+ namePtr = (PWCHAR)( (PCHAR)lpProtocolBuffer + *lpdwBufferLength );
+
+ //
+ // Fill in SPX info, if requested.
+ //
+
+ if ( useSpx ) {
+
+ entriesReturned += 1;
+
+ protocolInfo->dwServiceFlags = XP_GUARANTEED_DELIVERY |
+ XP_MESSAGE_ORIENTED |
+ XP_PSEUDO_STREAM |
+ XP_GUARANTEED_ORDER |
+ XP_FRAGMENTATION;
+ protocolInfo->iAddressFamily = AF_IPX;
+ protocolInfo->iMaxSockAddr = 0x10;
+ protocolInfo->iMinSockAddr = 0xE;
+ protocolInfo->iSocketType = SOCK_SEQPACKET;
+ protocolInfo->iProtocol = NSPROTO_SPX;
+ protocolInfo->dwMessageSize = 0xFFFFFFFF;
+
+ namePtr = namePtr - (wcslen( SPX_NAME) + 1);
+ protocolInfo->lpProtocol = namePtr;
+ wcscpy( protocolInfo->lpProtocol, SPX_NAME );
+
+ protocolInfo += 1;
+ }
+
+ //
+ // Fill in SPX II info, if requested.
+ //
+
+ if ( useSpx2 ) {
+
+ entriesReturned += 1;
+
+ protocolInfo->dwServiceFlags = XP_GUARANTEED_DELIVERY |
+ XP_MESSAGE_ORIENTED |
+ XP_PSEUDO_STREAM |
+ XP_GRACEFUL_CLOSE |
+ XP_GUARANTEED_ORDER |
+ XP_FRAGMENTATION;
+ protocolInfo->iAddressFamily = AF_IPX;
+ protocolInfo->iMaxSockAddr = 0x10;
+ protocolInfo->iMinSockAddr = 0xE;
+ protocolInfo->iSocketType = SOCK_SEQPACKET;
+ protocolInfo->iProtocol = NSPROTO_SPXII;
+ protocolInfo->dwMessageSize = 0xFFFFFFFF;
+
+ namePtr = namePtr - (wcslen( SPX2_NAME) + 1);
+ protocolInfo->lpProtocol = namePtr;
+ wcscpy( protocolInfo->lpProtocol, SPX2_NAME );
+
+ protocolInfo += 1;
+ }
+
+ //
+ // Fill in IPX info, if requested.
+ //
+
+ if ( useIpx ) {
+
+ entriesReturned += 1;
+
+ protocolInfo->dwServiceFlags = XP_CONNECTIONLESS |
+ XP_MESSAGE_ORIENTED |
+ XP_SUPPORTS_BROADCAST |
+ XP_SUPPORTS_MULTICAST |
+ XP_FRAGMENTATION;
+ protocolInfo->iAddressFamily = AF_IPX;
+ protocolInfo->iMaxSockAddr = 0x10;
+ protocolInfo->iMinSockAddr = 0xE;
+ protocolInfo->iSocketType = SOCK_DGRAM;
+ protocolInfo->iProtocol = NSPROTO_IPX;
+ protocolInfo->dwMessageSize = 576;
+
+ namePtr = namePtr - (wcslen( IPX_NAME) + 1);
+ protocolInfo->lpProtocol = namePtr;
+ wcscpy( protocolInfo->lpProtocol, IPX_NAME );
+ }
+
+ *lpdwBufferLength = bytesRequired;
+
+ return entriesReturned;
+
+} // WSHEnumProtocols
+
+
+#define _IPX_CONTROL_CODE(request,method) \
+ CTL_CODE(FILE_DEVICE_TRANSPORT, request, method, FILE_ANY_ACCESS)
+#define IOCTL_IPX_LOAD_SPX _IPX_CONTROL_CODE( 0x5678, METHOD_BUFFERED )
+
+DWORD
+WshLoadSpx(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Starts the nwlnkspx.sys driver by submitting a special ioctl
+ to ipx, which calls ZwLoadDriver() for us.
+
+Arguments:
+
+ none
+
+Returns:
+
+ Error return from the load operation.
+
+++*/
+{
+ DWORD err = NO_ERROR;
+ HANDLE FileHandle;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatusBlock;
+ UNICODE_STRING FileString;
+ WCHAR FileName[] = L"\\Device\\NwlnkIpx";
+ NTSTATUS Status;
+
+ RtlInitUnicodeString (&FileString, FileName);
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &FileString,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenFile(
+ &FileHandle,
+ SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT);
+
+ if (!NT_SUCCESS(Status)) {
+
+ err = ERROR_FILE_NOT_FOUND;
+
+ } else {
+
+ Status = NtDeviceIoControlFile(
+ FileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ IOCTL_IPX_LOAD_SPX,
+ NULL,
+ 0,
+ NULL,
+ 0);
+
+ if (Status == STATUS_IMAGE_ALREADY_LOADED) {
+
+ err = ERROR_SERVICE_ALREADY_RUNNING;
+
+ //
+ // #36451
+ // If the service controller loads SPX ("net start nwlnkspx", or due to dependency of RPC on SPX)
+ // then we get this error the first time too. Keep a note of that.
+ //
+ // BUGBUG: we still leak a handle per process since the handle to the driver is actually created
+ // in the system process' context. The ideal way to fix this should be to have IPX associate the
+ // handle with the current process (so handle is destroyed when the process dies) or to have the
+ // dll tell IPX to close the handle it opened earlier.
+ //
+ SpxLoaded = TRUE;
+
+ } else if (!NT_SUCCESS(Status)) {
+
+ err = ERROR_IO_DEVICE;
+
+ } else {
+ SpxLoaded = TRUE;
+ }
+
+ NtClose (FileHandle);
+
+ }
+
+ return(err);
+}
+
+/*page***************************************************************
+ W S H G e t P r o v i d e r G u i d
+
+ Queries the GUID identifier for this protocol.
+
+ Returns - NO_ERROR or an error code.
+*********************************************************************/
+INT
+WINAPI
+WSHGetProviderGuid (
+ IN LPWSTR ProviderName,
+ OUT LPGUID ProviderGuid
+ )
+{
+
+ if( ProviderName == NULL ||
+ ProviderGuid == NULL ) {
+
+ return WSAEFAULT;
+
+ }
+
+ if( _wcsicmp( ProviderName, L"NwlnkIpx" ) == 0 ) {
+
+ RtlCopyMemory(
+ ProviderGuid,
+ &IpxProviderGuid,
+ sizeof(GUID)
+ );
+
+ return NO_ERROR;
+
+ }
+
+ if( _wcsicmp( ProviderName, L"NwlnkSpx" ) == 0 ) {
+
+ RtlCopyMemory(
+ ProviderGuid,
+ &SpxProviderGuid,
+ sizeof(GUID)
+ );
+
+ return NO_ERROR;
+
+ }
+
+ return WSAEINVAL;
+
+} // WSHGetProviderGuid
+
diff --git a/private/ntos/tdi/isn/sockhelp/wshisn.c b/private/ntos/tdi/isn/sockhelp/wshisn.c
new file mode 100644
index 000000000..75cb70f40
--- /dev/null
+++ b/private/ntos/tdi/isn/sockhelp/wshisn.c
@@ -0,0 +1,323 @@
+/****************************************************************************
+* (c) Copyright 1993 Micro Computer Systems, Inc. All rights reserved.
+*****************************************************************************
+*
+* Title: IPX/SPX WinSock Helper DLL for Windows NT
+*
+* Module: ipx/sockhelp/wshnwlnk.c
+*
+* Version: 1.00.00
+*
+* Date: 04-08-93
+*
+* Author: Brian Walker
+*
+*****************************************************************************
+*
+* Change Log:
+*
+* Date DevSFC Comment
+* -------- ------ -------------------------------------------------------
+*
+*****************************************************************************
+*
+* Functional Description:
+*
+****************************************************************************/
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#include <windef.h>
+#include <winbase.h>
+#include <tdi.h>
+
+#include <winsock.h>
+#include <wsahelp.h>
+#include <wsipx.h>
+#include <wsnwlink.h>
+
+/*page****************************************************************
+ These are the triples we support.
+*********************************************************************/
+typedef struct _MAPPING_TRIPLE {
+ INT triple_addrfam;
+ INT triple_socktype;
+ INT triple_protocol;
+} MAPPING_TRIPLE, *PMAPPING_TRIPLE;
+
+MAPPING_TRIPLE stream_triples[] = {
+ { AF_NS, SOCK_STREAM, NSPROTO_SPX },
+ { AF_NS, SOCK_SEQPACKET, NSPROTO_SPX },
+ { AF_NS, SOCK_STREAM, NSPROTO_SPXII },
+ { AF_NS, SOCK_SEQPACKET, NSPROTO_SPXII },
+};
+int stream_num_triples = 4; /* When SPXII - set to 4 */
+int stream_table_size = sizeof(stream_triples);
+
+/**
+ For IPX we assign the default packet type according to the
+ protocol type used. The user can also we setsockopt
+ to set the packet type.
+**/
+
+MAPPING_TRIPLE dgram_triples[] = {
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+1 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+2 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+3 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+4 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+5 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+6 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+7 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+8 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+9 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+10 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+11 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+12 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+13 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+14 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+15 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+16 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+17 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+18 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+19 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+20 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+21 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+22 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+23 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+24 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+25 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+26 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+27 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+28 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+29 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+30 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+31 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+32 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+33 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+34 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+35 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+36 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+37 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+38 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+39 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+40 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+41 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+42 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+43 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+44 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+45 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+46 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+47 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+48 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+49 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+50 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+51 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+52 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+53 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+54 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+55 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+56 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+57 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+58 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+59 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+60 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+61 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+62 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+63 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+64 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+65 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+66 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+67 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+68 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+69 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+70 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+71 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+72 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+73 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+74 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+75 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+76 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+77 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+78 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+79 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+80 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+81 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+82 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+83 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+84 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+85 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+86 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+87 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+88 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+89 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+90 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+91 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+92 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+93 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+94 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+95 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+96 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+97 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+98 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+99 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+100 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+101 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+102 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+103 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+104 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+105 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+106 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+107 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+108 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+109 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+110 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+111 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+112 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+113 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+114 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+115 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+116 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+117 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+118 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+119 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+120 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+121 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+122 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+123 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+124 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+125 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+126 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+127 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+128 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+129 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+130 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+131 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+132 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+133 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+134 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+135 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+136 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+137 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+138 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+139 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+140 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+141 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+142 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+143 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+144 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+145 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+146 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+147 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+148 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+149 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+150 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+151 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+152 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+153 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+154 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+155 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+156 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+157 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+158 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+159 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+160 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+161 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+162 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+163 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+164 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+165 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+166 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+167 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+168 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+169 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+170 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+171 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+172 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+173 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+174 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+175 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+176 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+177 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+178 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+179 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+180 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+181 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+182 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+183 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+184 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+185 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+186 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+187 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+188 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+189 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+190 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+191 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+192 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+193 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+194 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+195 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+196 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+197 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+198 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+199 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+200 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+201 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+202 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+203 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+204 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+205 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+206 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+207 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+208 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+209 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+210 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+211 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+212 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+213 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+214 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+215 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+216 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+217 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+218 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+219 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+220 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+221 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+222 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+223 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+224 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+225 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+226 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+227 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+228 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+229 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+230 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+231 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+232 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+233 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+234 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+235 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+236 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+237 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+238 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+239 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+240 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+241 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+242 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+243 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+244 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+245 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+246 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+247 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+248 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+249 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+250 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+251 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+252 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+253 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+254 },
+ { AF_NS, SOCK_DGRAM, NSPROTO_IPX+255 }
+};
+int dgram_num_triples = 256;
+int dgram_table_size = sizeof(dgram_triples);
diff --git a/private/ntos/tdi/isn/sockhelp/wshisn.def b/private/ntos/tdi/isn/sockhelp/wshisn.def
new file mode 100644
index 000000000..c9eecc2a4
--- /dev/null
+++ b/private/ntos/tdi/isn/sockhelp/wshisn.def
@@ -0,0 +1,21 @@
+LIBRARY WSHISN
+
+DESCRIPTION 'ISN Windows NT Sockets Helper DLL'
+
+CODE PRELOAD FIXED
+DATA PRELOAD FIXED SINGLE
+
+HEAPSIZE 1024
+STACKSIZE 16384
+
+EXPORTS
+ WSHGetSockaddrType
+ WSHGetSocketInformation
+ WSHGetWinsockMapping
+ WSHNotify
+ WSHOpenSocket
+ WSHSetSocketInformation
+ WSHGetWildcardSockaddr
+ WSHEnumProtocols
+ WSHGetProviderGuid
+
diff --git a/private/ntos/tdi/isn/sockhelp/wshisn.rc b/private/ntos/tdi/isn/sockhelp/wshisn.rc
new file mode 100644
index 000000000..e58fcaaf7
--- /dev/null
+++ b/private/ntos/tdi/isn/sockhelp/wshisn.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "NWLINK2 Socket Helper DLL"
+#define VER_INTERNALNAME_STR "wshisn.DLL"
+
+#include "common.ver"
+
diff --git a/private/ntos/tdi/isn/sockhelp/wshutil.c b/private/ntos/tdi/isn/sockhelp/wshutil.c
new file mode 100644
index 000000000..4559bd6d0
--- /dev/null
+++ b/private/ntos/tdi/isn/sockhelp/wshutil.c
@@ -0,0 +1,189 @@
+/****************************************************************************
+* (c) Copyright 1993 Micro Computer Systems, Inc. All rights reserved.
+*****************************************************************************
+*
+* Title: IPX/SPX WinSock Helper DLL for Windows NT
+*
+* Module: ipx/sockhelp/wshutil.c
+*
+* Version: 1.00.00
+*
+* Date: 04-08-93
+*
+* Author: Brian Walker
+*
+*****************************************************************************
+*
+* Change Log:
+*
+* Date DevSFC Comment
+* -------- ------ -------------------------------------------------------
+*
+*****************************************************************************
+*
+* Functional Description:
+*
+****************************************************************************/
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#include <windef.h>
+#include <winbase.h>
+#include <tdi.h>
+
+#include <winsock.h>
+#include <wsahelp.h>
+
+#include <isnkrnl.h>
+
+/*page*******************************************************
+ d o _ t d i _ a c t i o n
+
+ Generate a TDI_ACTION down to the streams
+ driver.
+
+ Arguments - fd = Handle to send on
+ cmd = Command to send down
+ optbuf = Ptr to options buffer
+ optlen = Ptr to options length
+ addrflag = TRUE = This is for DG/STREAM socket on addr handle
+ FALSE = This is for conn handle
+
+ Returns - A WinSock error code (NO_ERROR = OK)
+************************************************************/
+INT do_tdi_action(HANDLE fd, ULONG cmd, PUCHAR optbuf, INT optlen, BOOLEAN addrflag, PHANDLE eventhandle OPTIONAL)
+{
+ NTSTATUS status;
+ PSTREAMS_TDI_ACTION tdibuf;
+ ULONG tdilen;
+ IO_STATUS_BLOCK iostat;
+ HANDLE event;
+
+
+ /** If the eventhandle is passed, it also means that the **/
+ /** NWLINK_ACTION header is pre-allocated in the buffer, **/
+ /** although we still have to fill the header in here. **/
+
+ if (eventhandle == NULL) {
+
+ /** Get the length of the buffer we need to allocate **/
+
+ tdilen = FIELD_OFFSET(STREAMS_TDI_ACTION,Buffer) + sizeof(ULONG) + optlen;
+
+ /** Allocate a buffer to use for the action **/
+
+ tdibuf = RtlAllocateHeap(RtlProcessHeap(), 0, tdilen);
+ if (tdibuf == NULL) {
+ return WSAENOBUFS;
+ }
+
+ } else {
+
+ tdilen = optlen;
+ tdibuf = (PSTREAMS_TDI_ACTION)optbuf;
+
+ }
+
+ /** Set the datagram option **/
+
+ RtlMoveMemory(&tdibuf->Header.TransportId, "MISN", 4);
+ tdibuf->DatagramOption = addrflag;
+
+ /**
+ Fill out the buffer, the buffer looks like this:
+
+ ULONG cmd
+ data passed.
+ **/
+
+ memcpy(tdibuf->Buffer, &cmd, sizeof(ULONG));
+
+ if (eventhandle == NULL) {
+
+ tdibuf->BufferLength = sizeof(ULONG) + optlen;
+
+ RtlMoveMemory(tdibuf->Buffer + sizeof(ULONG), optbuf, optlen);
+
+ /** Create an event to wait on **/
+
+ status = NtCreateEvent(
+ &event,
+ EVENT_ALL_ACCESS,
+ NULL,
+ SynchronizationEvent,
+ FALSE);
+
+ /** If no event - then return error **/
+
+ if (!NT_SUCCESS(status)) {
+ RtlFreeHeap(RtlProcessHeap(), 0, tdibuf);
+ return WSAENOBUFS;
+ }
+
+ } else {
+
+ tdibuf->BufferLength = sizeof(ULONG) + optlen - FIELD_OFFSET (NWLINK_ACTION, Data[0]);
+
+ /** Use the event handle passed in **/
+
+ event = *eventhandle;
+
+ }
+
+ /** **/
+
+ status = NtDeviceIoControlFile(
+ fd,
+ event,
+ NULL,
+ NULL,
+ &iostat,
+ IOCTL_TDI_ACTION,
+ NULL,
+ 0,
+ tdibuf,
+ tdilen);
+
+
+ if (eventhandle == NULL) {
+
+ /** If pending - wait for it to finish **/
+
+ if (status == STATUS_PENDING) {
+ status = NtWaitForSingleObject(event, FALSE, NULL);
+ ASSERT(status == 0);
+ status = iostat.Status;
+ }
+
+ /** Close the event **/
+
+ NtClose(event);
+
+ }
+
+ /** If we get an error - return it **/
+
+ if (!NT_SUCCESS(status)) {
+ if (eventhandle == NULL) {
+ RtlFreeHeap(RtlProcessHeap(), 0, tdibuf);
+ }
+ return WSAEINVAL;
+ }
+
+ if (eventhandle == NULL) {
+
+ /** Copy the returned back to optbuf if needed */
+
+ if (optlen) {
+ RtlMoveMemory (optbuf, tdibuf->Buffer + sizeof(ULONG), optlen);
+ }
+
+ RtlFreeHeap(RtlProcessHeap(), 0, tdibuf);
+
+ }
+
+ /** Return OK **/
+
+ return NO_ERROR;
+}
diff --git a/private/ntos/tdi/isn/spx/dirs b/private/ntos/tdi/isn/spx/dirs
new file mode 100644
index 000000000..0dab2f056
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/dirs
@@ -0,0 +1,22 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=up mp
diff --git a/private/ntos/tdi/isn/spx/globals.c b/private/ntos/tdi/isn/spx/globals.c
new file mode 100644
index 000000000..51fc80803
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/globals.c
@@ -0,0 +1,87 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ globals.c
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Global values
+PDEVICE SpxDevice = NULL;
+UNICODE_STRING IpxDeviceName = {0};
+HANDLE IpxHandle = NULL;
+
+LARGE_INTEGER Magic100000 = {
+ 0x1b478424,
+ 0xa7c5ac47
+ };
+// Line info
+IPX_LINE_INFO IpxLineInfo = {0};
+USHORT IpxMacHdrNeeded = 0;
+USHORT IpxInclHdrOffset= 0;
+
+// Entry Points into the IPX stack
+IPX_INTERNAL_SEND IpxSendPacket = NULL;
+IPX_INTERNAL_FIND_ROUTE IpxFindRoute = NULL;
+IPX_INTERNAL_QUERY IpxQuery = NULL;
+IPX_INTERNAL_TRANSFER_DATA IpxTransferData = NULL;
+
+#if DBG
+ULONG SpxDebugDump = 0;
+LONG SpxDumpInterval = DBG_DUMP_DEF_INTERVAL;
+ULONG SpxDebugLevel = DBG_LEVEL_ERR;
+ULONG SpxDebugSystems = DBG_COMP_MOST;
+#endif
+
+// Unload event triggered when ref count on device goes to zero.
+KEVENT SpxUnloadEvent = {0};
+
+// Maximum packet size quanta used during packet size negotiation
+ULONG SpxMaxPktSize[] = {
+ 576 - MIN_IPXSPX2_HDRSIZE,
+ 1024 - MIN_IPXSPX2_HDRSIZE,
+ 1474 - MIN_IPXSPX2_HDRSIZE,
+ 1492 - MIN_IPXSPX2_HDRSIZE,
+ 1500 - MIN_IPXSPX2_HDRSIZE,
+ 1954 - MIN_IPXSPX2_HDRSIZE,
+ 4002 - MIN_IPXSPX2_HDRSIZE,
+ 8192 - MIN_IPXSPX2_HDRSIZE,
+ 17314 - MIN_IPXSPX2_HDRSIZE,
+ 65535 - MIN_IPXSPX2_HDRSIZE
+ };
+
+ULONG SpxMaxPktSizeIndex = sizeof(SpxMaxPktSize)/sizeof(ULONG);
+
+
+// Global interlock
+CTELock SpxGlobalInterlock = {0};
+
+// Another one, used only for global queues for addr/conn
+CTELock SpxGlobalQInterlock = {0};
+PSPX_CONN_FILE SpxGlobalConnList = NULL;
+PSPX_ADDR_FILE SpxGlobalAddrList = NULL;
+
+SPX_CONNFILE_LIST SpxPktConnList = {NULL, NULL};
+SPX_CONNFILE_LIST SpxRecvConnList = {NULL, NULL};
+
+// Timer globals
+LONG SpxTimerCurrentTime = 0;
diff --git a/private/ntos/tdi/isn/spx/h/fwddecls.h b/private/ntos/tdi/isn/spx/h/fwddecls.h
new file mode 100644
index 000000000..feda4e76b
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/fwddecls.h
@@ -0,0 +1,28 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ fwddecls.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+struct _SPX_ADDR ;
+struct _SPX_ADDR_FILE ;
+struct _SPX_CONN_FILE ;
+struct _SPX_SEND_RESD ;
diff --git a/private/ntos/tdi/isn/spx/h/globals.h b/private/ntos/tdi/isn/spx/h/globals.h
new file mode 100644
index 000000000..e4fcf39a8
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/globals.h
@@ -0,0 +1,67 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ globals.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+extern PDEVICE SpxDevice;
+extern UNICODE_STRING IpxDeviceName;
+extern HANDLE IpxHandle;
+
+extern LARGE_INTEGER Magic100000;
+
+#if 1 // DBG
+extern ULONG SpxDebugDump;
+extern LONG SpxDumpInterval;
+extern ULONG SpxDebugLevel;
+extern ULONG SpxDebugSystems;
+
+#endif
+
+// More IPX info.
+extern IPX_LINE_INFO IpxLineInfo;
+extern USHORT IpxMacHdrNeeded;
+extern USHORT IpxInclHdrOffset;
+
+// Entry Points into the IPX stack
+extern IPX_INTERNAL_SEND IpxSendPacket;
+extern IPX_INTERNAL_FIND_ROUTE IpxFindRoute;
+extern IPX_INTERNAL_QUERY IpxQuery;
+extern IPX_INTERNAL_TRANSFER_DATA IpxTransferData;
+
+// Unload event
+extern KEVENT SpxUnloadEvent;
+
+extern ULONG SpxMaxPktSize[];
+extern ULONG SpxMaxPktSizeIndex;
+
+extern CTELock SpxGlobalInterlock;
+
+
+extern CTELock SpxGlobalQInterlock;
+extern PSPX_CONN_FILE SpxGlobalConnList;
+extern PSPX_ADDR_FILE SpxGlobalAddrList;
+
+extern SPX_CONNFILE_LIST SpxPktConnList;
+extern SPX_CONNFILE_LIST SpxRecvConnList;
+
+extern LONG SpxTimerCurrentTime;
diff --git a/private/ntos/tdi/isn/spx/h/isnspx.h b/private/ntos/tdi/isn/spx/h/isnspx.h
new file mode 100644
index 000000000..6080b0423
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/isnspx.h
@@ -0,0 +1,363 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ isnspx.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ SPX module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#define ISN_NT 1
+
+//
+// These are needed for CTE
+//
+
+#if DBG
+#define DEBUG 1
+#endif
+
+#define NT 1
+
+
+#include <ntddk.h>
+#include <tdikrnl.h>
+#include <ndis.h>
+#ifndef CTE_TYPEDEFS_DEFINED
+#include <cxport.h>
+#endif
+#include <bind.h>
+
+#include "wsnwlink.h"
+
+#define SPX_DEVICE_SIGNATURE (USHORT)(*(PUSHORT)"SD")
+#define SPX_ADDRESS_SIGNATURE (USHORT)(*(PUSHORT)"AD")
+#define SPX_ADDRESSFILE_SIGNATURE (USHORT)(*(PUSHORT)"AF")
+#define SPX_CONNFILE_SIGNATURE (USHORT)(*(PUSHORT)"CF")
+
+#define SPX_FILE_TYPE_CONTROL (ULONG)0x4701 // file is type control
+
+#define SPX_ADD_ULONG(_Pulong, _Ulong, _Lock) InterlockedExchangeAdd(_Pulong, _Ulong)
+
+typedef UCHAR BYTE, *PBYTE;
+typedef ULONG DWORD, *PDWORD;
+
+//
+// These definitions are for abstracting IRPs from the
+// transport for portability.
+//
+
+#if ISN_NT
+
+typedef IRP REQUEST, *PREQUEST;
+
+//
+// PREQUEST
+// SpxAllocateRequest(
+// IN PDEVICE Device,
+// IN PIRP Irp
+// );
+//
+// Allocates a request for the system-specific request structure.
+//
+
+#define SpxAllocateRequest(_Device,_Irp) \
+ (_Irp)
+
+//
+// BOOLEAN
+// IF_NOT_ALLOCATED(
+// IN PREQUEST Request
+// );
+//
+// Checks if a request was not successfully allocated.
+//
+
+#define IF_NOT_ALLOCATED(_Request) \
+ if (0)
+
+
+//
+// VOID
+// SpxFreeRequest(
+// IN PDEVICE Device,
+// IN PREQUEST Request
+// );
+//
+// Frees a previously allocated request.
+//
+
+#define SpxFreeRequest(_Device,_Request) \
+ ;
+
+
+//
+// VOID
+// MARK_REQUEST_PENDING(
+// IN PREQUEST Request
+// );
+//
+// Marks that a request will pend.
+//
+
+#define MARK_REQUEST_PENDING(_Request) \
+ IoMarkIrpPending(_Request)
+
+
+//
+// VOID
+// UNMARK_REQUEST_PENDING(
+// IN PREQUEST Request
+// );
+//
+// Marks that a request will not pend.
+//
+
+#define UNMARK_REQUEST_PENDING(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->Control) &= ~SL_PENDING_RETURNED)
+
+
+//
+// UCHAR
+// REQUEST_MAJOR_FUNCTION
+// IN PREQUEST Request
+// );
+//
+// Returns the major function code of a request.
+//
+
+#define REQUEST_MAJOR_FUNCTION(_Request) \
+ ((IoGetCurrentIrpStackLocation(_Request))->MajorFunction)
+
+
+//
+// UCHAR
+// REQUEST_MINOR_FUNCTION
+// IN PREQUEST Request
+// );
+//
+// Returns the minor function code of a request.
+//
+
+#define REQUEST_MINOR_FUNCTION(_Request) \
+ ((IoGetCurrentIrpStackLocation(_Request))->MinorFunction)
+
+
+//
+// PNDIS_BUFFER
+// REQUEST_NDIS_BUFFER
+// IN PREQUEST Request
+// );
+//
+// Returns the NDIS buffer chain associated with a request.
+//
+
+#define REQUEST_NDIS_BUFFER(_Request) \
+ ((PNDIS_BUFFER)((_Request)->MdlAddress))
+
+
+//
+// PVOID
+// REQUEST_TDI_BUFFER
+// IN PREQUEST Request
+// );
+//
+// Returns the TDI buffer chain associated with a request.
+//
+
+#define REQUEST_TDI_BUFFER(_Request) \
+ ((PVOID)((_Request)->MdlAddress))
+
+
+//
+// PVOID
+// REQUEST_OPEN_CONTEXT(
+// IN PREQUEST Request
+// );
+//
+// Gets the context associated with an opened address/connection/control channel.
+//
+
+#define REQUEST_OPEN_CONTEXT(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->FileObject)->FsContext)
+
+
+//
+// PVOID
+// REQUEST_OPEN_TYPE(
+// IN PREQUEST Request
+// );
+//
+// Gets the type associated with an opened address/connection/control channel.
+//
+
+#define REQUEST_OPEN_TYPE(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->FileObject)->FsContext2)
+
+
+//
+// PFILE_FULL_EA_INFORMATION
+// OPEN_REQUEST_EA_INFORMATION(
+// IN PREQUEST Request
+// );
+//
+// Returns the EA information associated with an open/close request.
+//
+
+#define OPEN_REQUEST_EA_INFORMATION(_Request) \
+ ((PFILE_FULL_EA_INFORMATION)((_Request)->AssociatedIrp.SystemBuffer))
+
+
+//
+// PTDI_REQUEST_KERNEL
+// REQUEST_PARAMETERS(
+// IN PREQUEST Request
+// );
+//
+// Obtains a pointer to the parameters of a request.
+//
+
+#define REQUEST_PARAMETERS(_Request) \
+ (&((IoGetCurrentIrpStackLocation(_Request))->Parameters))
+
+
+//
+// PLIST_ENTRY
+// REQUEST_LINKAGE(
+// IN PREQUEST Request
+// );
+//
+// Returns a pointer to a linkage field in the request.
+//
+
+#define REQUEST_LINKAGE(_Request) \
+ (&((_Request)->Tail.Overlay.ListEntry))
+
+
+//
+// PREQUEST
+// LIST_ENTRY_TO_REQUEST(
+// IN PLIST_ENTRY ListEntry
+// );
+//
+// Returns a request given a linkage field in it.
+//
+
+#define LIST_ENTRY_TO_REQUEST(_ListEntry) \
+ ((PREQUEST)(CONTAINING_RECORD(_ListEntry, REQUEST, Tail.Overlay.ListEntry)))
+
+
+//
+// PUNICODE_STRING
+// REQUEST_OPEN_NAME(
+// IN PREQUEST Request
+// );
+//
+// Used to access the RemainingName field of a request.
+//
+
+#define REQUEST_OPEN_NAME(_Request) \
+ (&((IoGetCurrentIrpStackLocation(_Request))->FileObject->FileName))
+
+//
+// NTSTATUS
+// REQUEST_STATUS(
+// IN PREQUEST Request
+// );
+//
+// Used to access the status field of a request.
+//
+
+#define REQUEST_STATUS(_Request) \
+ (_Request)->IoStatus.Status
+
+
+//
+// ULONG
+// REQUEST_INFORMATION(
+// IN PREQUEST Request)
+// );
+//
+// Used to access the information field of a request.
+//
+
+#define REQUEST_INFORMATION(_Request) \
+ (_Request)->IoStatus.Information
+
+
+//
+// VOID
+// SpxCompleteRequest(
+// IN PREQUEST Request
+// );
+//
+// Completes a request whose status and information fields have
+// been filled in.
+//
+
+#define SpxCompleteRequest(_Request) \
+ { \
+ CTELockHandle _CancelIrql; \
+ DBGPRINT(TDI, INFO, \
+ ("SpxCompleteRequest: Completing %lx with %lx\n", \
+ (_Request), REQUEST_STATUS(_Request))); \
+ \
+ IoAcquireCancelSpinLock( &_CancelIrql ); \
+ (_Request)->CancelRoutine = NULL; \
+ IoReleaseCancelSpinLock( _CancelIrql ); \
+ IoCompleteRequest (_Request, IO_NETWORK_INCREMENT); \
+ }
+
+#else
+
+//
+// These routines must be defined for portability to a VxD.
+//
+
+#endif
+
+#include "fwddecls.h"
+
+// BUGBUG: This should go in ntddk.h?
+#ifndef _NTIOAPI_
+#include "spxntdef.h"
+#endif
+
+#include "spxreg.h"
+#include "spxdev.h"
+#include "spxbind.h"
+#include "spxtimer.h"
+#include "spxpkt.h"
+#include "spxerror.h"
+#include "spxaddr.h"
+#include "spxconn.h"
+#include "spxrecv.h"
+#include "spxsend.h"
+#include "spxquery.h"
+#include "spxmem.h"
+#include "spxutils.h"
+
+
+// Globals
+#include "globals.h"
+
+
+
+
diff --git a/private/ntos/tdi/isn/spx/h/spxaddr.h b/private/ntos/tdi/isn/spx/h/spxaddr.h
new file mode 100644
index 000000000..b49a4791e
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxaddr.h
@@ -0,0 +1,426 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxaddr.h
+
+Abstract:
+
+
+Author:
+
+ Adam Barr (adamba ) Original Version
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#define DYNSKT_RANGE_START 0x4000
+#define DYNSKT_RANGE_END 0x7FFF
+#define SOCKET_UNIQUENESS 1
+
+// This structure is pointed to by the FsContext field in the FILE_OBJECT
+// for this Address. This structure is the base for all activities on
+// the open file object within the transport provider. All active connections
+// on the address point to this structure, although no queues exist here to do
+// work from. This structure also maintains a reference to an ADDRESS
+// structure, which describes the address that it is bound to.
+
+#define AFREF_CREATE 0
+#define AFREF_VERIFY 1
+#define AFREF_INDICATION 2
+#define AFREF_CONN_ASSOC 3
+
+#define AFREF_TOTAL 4
+
+typedef struct _SPX_ADDR_FILE {
+
+#if DBG
+ ULONG saf_RefTypes[AFREF_TOTAL];
+#endif
+
+ CSHORT saf_Type;
+ CSHORT saf_Size;
+
+ // number of references to this object.
+ ULONG saf_RefCount;
+
+ // Linkage in address list.
+ struct _SPX_ADDR_FILE * saf_Next;
+ struct _SPX_ADDR_FILE * saf_GlobalNext;
+
+ // List of associated connection/active or otherwise
+ struct _SPX_CONN_FILE * saf_AssocConnList;
+
+ // the current state of the address file structure; this is either open or
+ // closing
+ USHORT saf_Flags;
+
+ // address to which we are bound, pointer to its lock.
+ struct _SPX_ADDR * saf_Addr;
+ CTELock * saf_AddrLock;
+
+#ifdef ISN_NT
+ // easy backlink to file object.
+ PFILE_OBJECT saf_FileObject;
+#endif
+
+ // device to which we are attached.
+ struct _DEVICE * saf_Device;
+
+ // This holds the request used to close this address file,
+ // for pended completion.
+ PREQUEST saf_CloseReq;
+
+ // This function pointer points to a connection indication handler for this
+ // Address. Any time a connect request is received on the address, this
+ // routine is invoked.
+ PTDI_IND_CONNECT saf_ConnHandler;
+ PVOID saf_ConnHandlerCtx;
+
+ // The following function pointer always points to a TDI_IND_DISCONNECT
+ // handler for the address.
+ PTDI_IND_DISCONNECT saf_DiscHandler;
+ PVOID saf_DiscHandlerCtx;
+
+ // The following function pointer always points to a TDI_IND_RECEIVE
+ // event handler for connections on this address.
+ PTDI_IND_RECEIVE saf_RecvHandler;
+ PVOID saf_RecvHandlerCtx;
+
+ // Send possible handler
+ PTDI_IND_SEND_POSSIBLE saf_SendPossibleHandler;
+ PVOID saf_SendPossibleHandlerCtx;
+
+ // !!!We do not do datagrams or expedited data!!!
+
+ // The following function pointer always points to a TDI_IND_ERROR
+ // handler for the address.
+ PTDI_IND_ERROR saf_ErrHandler;
+ PVOID saf_ErrHandlerCtx;
+ PVOID saf_ErrHandlerOwner;
+
+
+} SPX_ADDR_FILE, *PSPX_ADDR_FILE;
+
+#define SPX_ADDRFILE_OPENING 0x0000 // not yet open for business
+#define SPX_ADDRFILE_OPEN 0x0001 // open for business
+#define SPX_ADDRFILE_CLOSING 0x0002 // closing
+#define SPX_ADDRFILE_STREAM 0x0004 // Opened for stream mode operation
+#define SPX_ADDRFILE_CONNIND 0x0008 // Connect ind in progress
+#define SPX_ADDRFILE_SPX2 0x0010 // Attempt SPX2 address file
+#define SPX_ADDRFILE_NOACKWAIT 0x0020 // Dont delay acks on assoc connections
+#define SPX_ADDRFILE_IPXHDR 0x0040 // Pass ipx hdr on all assoc connections
+// ***STOP*** ***STOP*** ***STOP*** ***STOP*** ***STOP*** ***STOP*** ***STOP***
+// If you are adding any more states to this beyond 0x0080, MAKE SURE to go
+// in code and change statements like (Flags & SPX_***) to
+// ((Flags & SPX_**) != 0)!!! I dont want to make that change that at this stage.
+// ***STOP*** ***STOP*** ***STOP*** ***STOP*** ***STOP*** ***STOP*** ***STOP***
+
+// This structure defines an ADDRESS, or active transport address,
+// maintained by the transport provider. It contains all the visible
+// components of the address (such as the TSAP and network name components),
+// and it also contains other maintenance parts, such as a reference count,
+// ACL, and so on.
+
+#define AREF_ADDR_FILE 0
+#define AREF_LOOKUP 1
+#define AREF_RECEIVE 2
+
+#define AREF_TOTAL 4
+
+typedef struct _SPX_ADDR {
+
+#if DBG
+ ULONG sa_RefTypes[AREF_TOTAL];
+#endif
+
+ USHORT sa_Size;
+ CSHORT sa_Type;
+
+ // number of references to this object.
+ ULONG sa_RefCount;
+
+ // next address/this device object.
+ struct _SPX_ADDR * sa_Next;
+
+ // The following fields are used to maintain state about this address.
+ // attributes of the address.
+ ULONG sa_Flags;
+
+ // Next addressfile for this address
+ struct _SPX_ADDR_FILE * sa_AddrFileList;
+
+ // List of inactive connections and active connections on this address file.
+ struct _SPX_CONN_FILE * sa_InactiveConnList;
+ struct _SPX_CONN_FILE * sa_ActiveConnList;
+
+ // This is the list of connections which have a POST_LISTEN on them. They
+ // do not have a local connection id at this point. But will, when they move
+ // from here to the ActiveConnList, when the listen is satisfied (no matter
+ // if the accept has not been posted yet, in the case of non-autoaccept listens)
+ struct _SPX_CONN_FILE * sa_ListenConnList;
+
+ CTELock sa_Lock;
+
+ // the socket this address corresponds to.
+ USHORT sa_Socket;
+
+ // device context to which we are attached.
+ struct _DEVICE * sa_Device;
+ CTELock * sa_DeviceLock;
+
+#ifdef ISN_NT
+
+ // These two can be a union because they are not used
+ // concurrently.
+ union {
+
+ // This structure is used for checking share access.
+ SHARE_ACCESS sa_ShareAccess;
+
+ // Used for delaying NbfDestroyAddress to a thread so
+ // we can access the security descriptor.
+ WORK_QUEUE_ITEM sa_DestroyAddrQueueItem;
+
+ } u;
+
+ // This structure is used to hold ACLs on the address.
+ PSECURITY_DESCRIPTOR sa_SecurityDescriptor;
+
+#endif
+
+} SPX_ADDR, *PSPX_ADDR;
+
+#define SPX_ADDR_CLOSING 0x00000001
+
+
+// ROUTINE PROTOTYPES
+
+VOID
+SpxAddrRef(
+ IN PSPX_ADDR Address);
+
+VOID
+SpxAddrLockRef(
+ IN PSPX_ADDR Address);
+
+VOID
+SpxAddrDeref(
+ IN PSPX_ADDR Address);
+
+VOID
+SpxAddrFileRef(
+ IN PSPX_ADDR_FILE pAddrFile);
+
+VOID
+SpxAddrFileLockRef(
+ IN PSPX_ADDR_FILE pAddrFile);
+
+VOID
+SpxAddrFileDeref(
+ IN PSPX_ADDR_FILE pAddrFile);
+
+PSPX_ADDR
+SpxAddrCreate(
+ IN PDEVICE Device,
+ IN USHORT Socket);
+
+NTSTATUS
+SpxAddrFileCreate(
+ IN PDEVICE Device,
+ IN PREQUEST Request,
+ OUT PSPX_ADDR_FILE * ppAddrFile);
+
+NTSTATUS
+SpxAddrOpen(
+ IN PDEVICE Device,
+ IN PREQUEST Request);
+
+NTSTATUS
+SpxAddrSetEventHandler(
+ IN PDEVICE Device,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxAddrFileVerify(
+ IN PSPX_ADDR_FILE pAddrFile);
+
+NTSTATUS
+SpxAddrFileStop(
+ IN PSPX_ADDR_FILE pAddrFile,
+ IN PSPX_ADDR Address);
+
+NTSTATUS
+SpxAddrFileCleanup(
+ IN PDEVICE Device,
+ IN PREQUEST Request);
+
+NTSTATUS
+SpxAddrFileClose(
+ IN PDEVICE Device,
+ IN PREQUEST Request);
+
+PSPX_ADDR
+SpxAddrLookup(
+ IN PDEVICE Device,
+ IN USHORT Socket);
+
+NTSTATUS
+SpxAddrConnByRemoteIdAddrLock(
+ IN PSPX_ADDR pSpxAddr,
+ IN USHORT SrcConnId,
+ IN PBYTE SrcIpxAddr,
+ OUT struct _SPX_CONN_FILE **ppSpxConnFile);
+
+NTSTATUS
+SpxAddrFileDestroy(
+ IN PSPX_ADDR_FILE pAddrFile);
+
+VOID
+SpxAddrDestroy(
+ IN PVOID Parameter);
+
+USHORT
+SpxAddrAssignSocket(
+ IN PDEVICE Device);
+
+BOOLEAN
+SpxAddrExists(
+ IN PDEVICE Device,
+ IN USHORT Socket);
+
+NTSTATUS
+spxAddrRemoveFromGlobalList(
+ IN PSPX_ADDR_FILE pSpxAddrFile);
+
+VOID
+spxAddrInsertIntoGlobalList(
+ IN PSPX_ADDR_FILE pSpxAddrFile);
+
+#if DBG
+#define SpxAddrReference(_Address, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_Address)->sa_RefTypes[_Type],\
+ 1, \
+ &SpxGlobalInterlock); \
+ SpxAddrRef (_Address); \
+ }
+
+#define SpxAddrLockReference(_Address, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_Address)->sa_RefTypes[_Type], \
+ 1, \
+ &SpxGlobalInterlock); \
+ SpxAddrLockRef (_Address); \
+ }
+
+#define SpxAddrDereference(_Address, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_Address)->sa_RefTypes[_Type], \
+ (ULONG)-1, \
+ &SpxGlobalInterlock); \
+ if (SPX_ADD_ULONG( \
+ &(_Address)->sa_RefCount, \
+ (ULONG)-1, \
+ &(_Address)->sa_Lock) == 1) { \
+ SpxAddrDestroy (_Address); \
+ }\
+ }
+
+
+#define SpxAddrFileReference(_AddressFile, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_AddressFile)->saf_RefTypes[_Type], \
+ 1, \
+ &SpxGlobalInterlock); \
+ SpxAddrFileRef (_AddressFile); \
+ }
+
+#define SpxAddrFileLockReference(_AddressFile, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_AddressFile)->saf_RefTypes[_Type], \
+ 1, \
+ &SpxGlobalInterlock); \
+ SpxAddrFileLockRef (_AddressFile); \
+ }
+
+#define SpxAddrFileDereference(_AddressFile, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_AddressFile)->saf_RefTypes[_Type], \
+ (ULONG)-1, \
+ &SpxGlobalInterlock); \
+ SpxAddrFileDeref (_AddressFile); \
+ }
+
+#define SpxAddrFileTransferReference(_AddressFile, _OldType, _NewType) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_AddressFile)->saf_RefTypes[_NewType], \
+ 1, \
+ &SpxGlobalInterlock); \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_AddressFile)->saf_RefTypes[_OldType], \
+ (ULONG)-1, \
+ &SpxGlobalInterlock); \
+ }
+
+#else // DBG
+
+#define SpxAddrReference(_Address, _Type) \
+ SPX_ADD_ULONG( \
+ &(_Address)->sa_RefCount, \
+ 1, \
+ (_Address)->sa_DeviceLock)
+
+#define SpxAddrLockReference(_Address, _Type) \
+ SPX_ADD_ULONG( \
+ &(_Address)->sa_RefCount, \
+ 1, \
+ (_Address)->sa_DeviceLock);
+
+#define SpxAddrDereference(_Address, _Type) \
+ if (SPX_ADD_ULONG( \
+ &(_Address)->sa_RefCount, \
+ (ULONG)-1, \
+ &(_Address)->sa_Lock) == 1) { \
+ SpxAddrDestroy (_Address); \
+ }
+
+#define SpxAddrFileReference(_AddressFile, _Type) \
+ SPX_ADD_ULONG( \
+ &(_AddressFile)->saf_RefCount, \
+ 1, \
+ (_AddressFile)->saf_AddrLock)
+
+#define SpxAddrFileLockReference(_AddressFile, _Type) \
+ SPX_ADD_ULONG( \
+ &(_AddressFile)->saf_RefCount, \
+ 1, \
+ (_AddressFile)->saf_AddrLock);
+
+#define SpxAddrFileDereference(_AddressFile, _Type) \
+ if (SPX_ADD_ULONG( \
+ &(_AddressFile)->saf_RefCount, \
+ (ULONG)-1, \
+ (_AddressFile)->saf_AddrLock) == 1) { \
+ SpxAddrFileDestroy (_AddressFile); \
+ }
+
+#define SpxAddrFileTransferReference(_AddressFile, _OldType, _NewType)
+
+#endif // DBG
diff --git a/private/ntos/tdi/isn/spx/h/spxbind.h b/private/ntos/tdi/isn/spx/h/spxbind.h
new file mode 100644
index 000000000..81ad6ac58
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxbind.h
@@ -0,0 +1,32 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxbind.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+NTSTATUS
+SpxInitBindToIpx(
+ VOID);
+
+VOID
+SpxUnbindFromIpx(
+ VOID);
+
diff --git a/private/ntos/tdi/isn/spx/h/spxconn.h b/private/ntos/tdi/isn/spx/h/spxconn.h
new file mode 100644
index 000000000..bb1173432
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxconn.h
@@ -0,0 +1,1666 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxconn.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 5-July-1995
+ Bug fixes - tagged [SA]
+
+--*/
+
+// Minimum value for RTT in ms.
+// BUGBUG: Have these be a derivate of registry values.
+#define SPX_T1_MIN 200
+#define MAX_RETRY_DELAY 5000 // 5 seconds
+#define SPX_DEF_RENEG_RETRYCOUNT 1 // All reneg pkts except min sent once
+
+// Some types
+typedef enum
+{
+ SPX_CALL_RECVLEVEL,
+ SPX_CALL_TDILEVEL
+} SPX_CALL_LEVEL;
+
+typedef enum
+{
+ SPX_REQ_DATA,
+ SPX_REQ_ORDREL,
+ SPX_REQ_DISC
+
+} SPX_SENDREQ_TYPE;
+
+// This structure is pointed to by the FsContext field in the FILE_OBJECT
+// for this Connection.
+
+#define CFREF_CREATE 0
+#define CFREF_VERIFY 1
+#define CFREF_INDICATION 2
+#define CFREF_BYCTX 3
+#define CFREF_BYID 4
+#define CFREF_ADDR 5
+#define CFREF_REQ 6
+#define CFREF_TIMER 7
+#define CFREF_PKTIZE 8
+#define CFREF_RECV 9
+#define CFREF_ABORTPKT 10
+#define CFREF_ERRORSTATE 11
+#define CFREF_FINDROUTE 12
+
+//
+// New state added to reflect an SPXI connection which is waiting for
+// a local disconnect after having indicated a RELEASE to AFD.
+//
+#define CFREF_DISCWAITSPX 13
+
+#define CFREF_TOTAL 14
+
+#define CFMAX_STATES 20
+
+typedef struct _SPX_CONN_FILE
+{
+
+#if DBG
+ ULONG scf_RefTypes[CFREF_TOTAL];
+
+#if 0
+//
+// Disabled for now - to enable logging of states, move this array *after* the Type/Size;
+// a change in their offset can cause problems since we assume the offset to be less than
+// the size of an AddressFile structure. (see SpxTdiQueryInformation)
+//
+ ULONG scf_StateBuffer[CFMAX_STATES];
+ ULONG scf_NextStatePtr;
+#endif
+
+#endif
+
+ CSHORT scf_Type;
+ CSHORT scf_Size;
+
+ // number of references to this object.
+ ULONG scf_RefCount;
+
+ // Linkage in device address file list. The connection can be on the device
+ // connection list, address inactive/listen/active list.
+ struct _SPX_CONN_FILE * scf_Next;
+ struct _SPX_CONN_FILE * scf_AssocNext;
+ struct _SPX_CONN_FILE * scf_GlobalActiveNext;
+
+ // Queued in a global list, stays here from creation to destroy.
+ struct _SPX_CONN_FILE * scf_GlobalNext;
+ struct _SPX_CONN_FILE * scf_PktNext;
+ struct _SPX_CONN_FILE * scf_ProcessRecvNext;
+
+ // the current state of the connection. One main state and multiple substates.
+ ULONG scf_Flags;
+
+ // More information
+ ULONG scf_Flags2;
+
+#if DBG
+ // Save the state of flags/flags2 before reinit. Overwritten every reinit.
+ ULONG scf_GhostFlags;
+ ULONG scf_GhostFlags2;
+ ULONG scf_GhostRefCount;
+ PREQUEST scf_GhostDiscReq;
+#endif
+
+ // Connection retry counts, or watchdog timer count when the connection goes
+ // active
+ union
+ {
+ LONG scf_CRetryCount;
+ LONG scf_WRetryCount;
+ };
+ LONG scf_RRetryCount;
+ USHORT scf_RRetrySeqNum;
+
+ union
+ {
+ ULONG scf_CTimerId;
+ ULONG scf_RTimerId; // Only after we turn active
+ };
+
+ ULONG scf_WTimerId; // Watchdog timer
+ ULONG scf_TTimerId; // TDI Connect/Disconnect timer
+ ULONG scf_ATimerId; // Ack timer id
+
+ // Variables used to manage the Retry timer tick value
+ // Note our timer subsytem fires at 100ms granularity.
+ int scf_BaseT1;
+ int scf_AveT1;
+ int scf_DevT1;
+
+ // Stored in HOST-ORDER
+ // LOCAL variables
+ USHORT scf_LocalConnId;
+ USHORT scf_SendSeqNum; // Debug dw +9a
+ USHORT scf_SentAllocNum; // dw +9c
+
+ // REMOTE variables
+ USHORT scf_RecvSeqNum; // dw +9e
+ USHORT scf_RecdAckNum; // dw +a0
+ USHORT scf_RecdAllocNum; // dw +a2
+
+ // RETRY sequence number
+ USHORT scf_RetrySeqNum;
+
+ // Saved ack number to be used in building the reneg ack packet.
+ // Note that our RecvSeqNum which we normally use is overwritten
+ // when we receive a renegotiate request.
+ USHORT scf_RenegAckAckNum;
+
+ // Stored in NETWORK-ORDER. scf_RemAckAddr contains the remote address
+ // for a data packet that had the ack bit set, buildAck will use this
+ // address.
+ BYTE scf_RemAddr[12];
+ BYTE scf_RemAckAddr[12];
+ USHORT scf_RemConnId; // Debug dw +be
+
+ // Maximum packet size (or size of first) reneg packet.
+ USHORT scf_RenegMaxPktSize;
+
+ // Local target to use in when sending acks. This is set to received
+ // data's indicated local target.
+ IPX_LOCAL_TARGET scf_AckLocalTarget;
+
+ // Maximum packet size to use for this connection
+ USHORT scf_MaxPktSize;
+ UCHAR scf_DataType;
+
+ // Local target to use in sends, initialized upon connect indication
+ // or when find_route completes
+ IPX_LOCAL_TARGET scf_LocalTarget;
+
+ // Connection lock
+ CTELock scf_Lock;
+
+ // address to which we are bound
+ struct _SPX_ADDR_FILE * scf_AddrFile;
+
+ // Connection context
+ CONNECTION_CONTEXT scf_ConnCtx;
+
+#ifdef ISN_NT
+ // easy backlink to file object.
+ PFILE_OBJECT scf_FileObject;
+#endif
+
+ // LIST_ENTRY of disconnect irps waiting for completion. There could be
+ // multiple disconnect inform irps.
+ LIST_ENTRY scf_DiscLinkage;
+
+ // LIST_ENTRY of send requests (intially contains connect/listen/accept also)
+ // on this connection.
+ LIST_ENTRY scf_ReqLinkage;
+
+ // Queue for completed requests awaiting completion
+ LIST_ENTRY scf_ReqDoneLinkage;
+ LIST_ENTRY scf_RecvDoneLinkage;
+
+ // Queue for pending receives
+ LIST_ENTRY scf_RecvLinkage;
+ PREQUEST scf_CurRecvReq;
+ ULONG scf_CurRecvOffset;
+ ULONG scf_CurRecvSize;
+
+ // Current request packetize info
+ PREQUEST scf_ReqPkt;
+ ULONG scf_ReqPktOffset;
+ ULONG scf_ReqPktSize;
+ ULONG scf_ReqPktFlags;
+ SPX_SENDREQ_TYPE scf_ReqPktType;
+
+ // Single linked list of sequenced send/disc packets
+ PSPX_SEND_RESD scf_SendSeqListHead;
+ PSPX_SEND_RESD scf_SendSeqListTail;
+
+ // Single linked list of send (unsequenced) packets
+ PSPX_SEND_RESD scf_SendListHead;
+ PSPX_SEND_RESD scf_SendListTail;
+
+ // Single linked list of buffered recv packets.
+ PSPX_RECV_RESD scf_RecvListHead;
+ PSPX_RECV_RESD scf_RecvListTail;
+
+ // Connect request
+ PREQUEST scf_ConnectReq;
+
+ // This holds the request used to close this address file,
+ // for pended completion. We also pend cleanup requests for connections.
+ PREQUEST scf_CleanupReq;
+ PREQUEST scf_CloseReq;
+
+#if DBG
+
+ // Packet being indicated, seq num, flags/flags2
+ USHORT scf_PktSeqNum;
+ ULONG scf_PktFlags;
+ ULONG scf_PktFlags2;
+
+ ULONG scf_IndBytes;
+ ULONG scf_IndLine;
+#endif
+
+#if DBG_WDW_CLOSE
+
+ // Keep track of how long the window was closed on this connection.
+ ULONG scf_WdwCloseAve;
+ LARGE_INTEGER scf_WdwCloseTime; // Time when wdw was closed
+#endif
+
+ // device to which we are attached.
+ struct _DEVICE * scf_Device;
+
+} SPX_CONN_FILE, *PSPX_CONN_FILE;
+
+
+// Basic states
+// Least significant byte of flags is used.
+// Mutually exclusive states are coded as numbers, others are bit flags.
+// Only main states are currently in form of numbers. Also, send and receive.
+//
+// Once we go active, we need SEND/RECEIVE/DISC substates to be mutually
+// exclusive with each other. As all three could be active at the same time.
+
+// Connection MAIN states. These are all mutually exclusive.
+#define SPX_CONNFILE_MAINMASK 0x00000007
+#define SPX_CONNFILE_ACTIVE 0x00000001
+#define SPX_CONNFILE_CONNECTING 0x00000002
+#define SPX_CONNFILE_LISTENING 0x00000003
+#define SPX_CONNFILE_DISCONN 0x00000004
+
+// Connecting states (VALID when CONNFILE_CONNECTING)
+#define SPX_CONNECT_MASK 0x000000F0
+#define SPX_CONNECT_SENTREQ 0x00000010
+#define SPX_CONNECT_NEG 0x00000020
+#define SPX_CONNECT_W_SETUP 0x00000030
+
+// Listening states (VALID when CONNFILE_LISTENING)
+#define SPX_LISTEN_MASK 0x000000F0
+#define SPX_LISTEN_RECDREQ 0x00000010
+#define SPX_LISTEN_SENTACK 0x00000020
+#define SPX_LISTEN_NEGACK 0x00000030
+#define SPX_LISTEN_SETUP 0x00000040
+
+// Connection SUB states
+// Send machine states (VALID when CONNFILE_ACTIVE)
+#define SPX_SEND_MASK 0x000000F0
+#define SPX_SEND_IDLE 0x00000000
+#define SPX_SEND_PACKETIZE 0x00000010
+#define SPX_SEND_RETRY 0x00000020
+#define SPX_SEND_RETRYWD 0x00000030
+#define SPX_SEND_RENEG 0x00000040
+#define SPX_SEND_RETRY2 0x00000050
+#define SPX_SEND_RETRY3 0x00000060
+#define SPX_SEND_WD 0x00000070 // We dont reneg pkt size on wdog
+ // Also we change to this state only
+ // 2nd time wdog fires w/out ack.
+#define SPX_SEND_NAK_RECD 0x00000080
+
+// Receive machine states (VALID when CONNFILE_ACTIVE)
+#define SPX_RECV_MASK 0x00000F00
+#define SPX_RECV_IDLE 0x00000000
+#define SPX_RECV_POSTED 0x00000100
+#define SPX_RECV_PROCESS_PKTS 0x00000200
+
+// Disconnect states (VALID when CONNFILE_DISCONN/CONNFILE_ACTIVE)
+// These are valid when either ACTIVE/DISCONN is set. We use these when
+// active for a orderly release, i.e. we receive pkt from remote, but we
+// stay active (setting SPX_DISC_RECV_ORDREL) until our client posts a
+// disconnect, which is when we move to disconnecting.
+#define SPX_DISC_MASK 0x0000F000
+#define SPX_DISC_IDLE 0x00000000
+#define SPX_DISC_ABORT 0x00001000
+#define SPX_DISC_SENT_IDISC 0x00002000
+#define SPX_DISC_POST_ORDREL 0x00003000
+#define SPX_DISC_SENT_ORDREL 0x00004000
+#define SPX_DISC_ORDREL_ACKED 0x00005000
+#define SPX_DISC_POST_IDISC 0x00006000
+
+// [SA] bug #14655 added flag to indicate that SpxConnInactivate already called for
+// this disconnecting connection
+//
+#define SPX_DISC_INACTIVATED 0x00007000
+
+// The following are not mutually exclusive.
+#define SPX_CONNFILE_RECVQ 0x00010000 // Process completed receives/pkts
+#define SPX_CONNFILE_RENEG_SIZE 0x00020000 // Size changed in renegotiate pkt
+#define SPX_CONNFILE_ACKQ 0x00040000 // Waiting to piggyback ack queue
+#define SPX_CONNFILE_PKTQ 0x00080000 // Waiting to packetize queue
+
+#define SPX_CONNFILE_ASSOC 0x00100000 // associated
+#define SPX_CONNFILE_NEG 0x00200000 // CR had neg set (for delayed accept)
+#define SPX_CONNFILE_SPX2 0x00400000
+#define SPX_CONNFILE_STREAM 0x00800000
+#define SPX_CONNFILE_R_TIMER 0x01000000 // Retry timer (only after ACTIVE)
+#define SPX_CONNFILE_C_TIMER 0x01000000 // Connect timer
+#define SPX_CONNFILE_W_TIMER 0x02000000 // Watchdog timer
+#define SPX_CONNFILE_T_TIMER 0x04000000 // tdi connect/disc timer specified
+#define SPX_CONNFILE_RENEG_PKT 0x08000000 // Renegotiate changed size, repacketize
+#define SPX_CONNFILE_IND_IDISC 0x10000000 // Indicated abortive disc to afd
+#define SPX_CONNFILE_IND_ODISC 0x20000000 // Indicated orderly release to afd
+
+#define SPX_CONNFILE_STOPPING 0x40000000
+#define SPX_CONNFILE_CLOSING 0x80000000 // closing
+
+#define SPX_CONNFILE2_PKT_NOIND 0x00000001
+#define SPX_CONNFILE2_RENEGRECD 0x00000002 // A renegotiate was received.
+ // scf_RenegAckAckNum set.
+#define SPX_CONNFILE2_PKT 0x00000004
+#define SPX_CONNFILE2_FINDROUTE 0x00000010 // A find route in progress on conn.
+#define SPX_CONNFILE2_NOACKWAIT 0x00000020 // Dont delay acks on connection, option
+#define SPX_CONNFILE2_IMMED_ACK 0x00000040 // Send an immediate ack,no back traffic
+#define SPX_CONNFILE2_IPXHDR 0x00000080 // Pass ipxhdr in receives
+
+//
+// [SA] Saves the IDisc flag passed to AbortiveDisc; this is TRUE only if there was
+// a remote disconnect on an SPX connection (in which case, we indicate TDI_DISCONNECT_RELEASE
+// else we indicate TDI_DISCONNECT_ABORT)
+//
+#define SPX_CONNFILE2_IDISC 0x00000100
+
+//
+// Indicates an SPXI connfile waiting for a local disconnect in response
+// to a TDI_DISCONNECT_RELEASE to AFD.
+//
+#define SPX_CONNFILE2_DISC_WAIT 0x00000200
+
+// FindRoute request structure
+typedef struct _SPX_FIND_ROUTE_REQUEST
+{
+ // !!!!This must be the first element in the structure
+ IPX_FIND_ROUTE_REQUEST fr_FindRouteReq;
+ PVOID fr_Ctx;
+
+} SPX_FIND_ROUTE_REQUEST, *PSPX_FIND_ROUTE_REQUEST;
+
+typedef struct _SPX_CONNFILE_LIST
+{
+ PSPX_CONN_FILE pcl_Head;
+ PSPX_CONN_FILE pcl_Tail;
+
+} SPX_CONNFILE_LIST, *PSPX_CONNFILE_LIST;
+
+// Exported routines
+
+NTSTATUS
+SpxConnOpen(
+ IN PDEVICE pDevice,
+ IN CONNECTION_CONTEXT pConnCtx,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnCleanup(
+ IN PDEVICE Device,
+ IN PREQUEST Request);
+
+NTSTATUS
+SpxConnClose(
+ IN PDEVICE Device,
+ IN PREQUEST Request);
+
+NTSTATUS
+SpxConnDisAssociate(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+spxConnDisAssoc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+SpxConnStop(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+NTSTATUS
+SpxConnAssociate(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnConnect(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnListen(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnAccept(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnAction(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnDisconnect(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnSend(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnRecv(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+VOID
+SpxConnFileRefByCtxLock(
+ IN PSPX_ADDR_FILE pSpxAddrFile,
+ IN CONNECTION_CONTEXT Ctx,
+ OUT PSPX_CONN_FILE * ppSpxConnFile,
+ OUT NTSTATUS * pStatus);
+
+NTSTATUS
+SpxConnFileVerify (
+ IN PSPX_CONN_FILE pConnFile);
+
+VOID
+SpxConnFileDeref(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+SpxConnConnectFindRouteComplete(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_FIND_ROUTE_REQUEST pFrReq,
+ IN BOOLEAN FoundRoute,
+ IN CTELockHandle LockHandle);
+
+VOID
+SpxConnActiveFindRouteComplete(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_FIND_ROUTE_REQUEST pFrReq,
+ IN BOOLEAN FoundRoute,
+ IN CTELockHandle LockHandle);
+
+BOOLEAN
+SpxConnPacketize(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN BOOLEAN fNormalState,
+ IN CTELockHandle LockHandleConn);
+
+#if DBG
+VOID
+SpxConnFileRef(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+SpxConnFileLockRef(
+ IN PSPX_CONN_FILE pSpxConnFile);
+#endif
+
+VOID
+SpxConnFileRefByIdLock (
+ IN USHORT ConnId,
+ OUT PSPX_CONN_FILE * ppSpxConnFile,
+ OUT PNTSTATUS pStatus);
+
+BOOLEAN
+SpxConnDequeuePktLock(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PNDIS_PACKET pPkt);
+
+VOID
+SpxConnSendAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+SpxConnSendNack(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN USHORT NumToSend,
+ IN CTELockHandle LockHandleConn);
+
+BOOLEAN
+SpxConnProcessAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PIPXSPX_HDR pAckHdr,
+ IN CTELockHandle lockHandle);
+
+VOID
+SpxConnProcessRenegReq(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN CTELockHandle lockHandle);
+
+VOID
+SpxConnProcessIDisc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle lockHandle);
+
+VOID
+SpxConnProcessOrdRel(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle lockHandle);
+
+BOOLEAN
+SpxConnDequeueRecvPktLock(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PNDIS_PACKET pPkt);
+
+BOOLEAN
+SpxConnDequeueSendPktLock(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PNDIS_PACKET pPkt);
+
+// LOCAL functions
+VOID
+spxConnHandleConnReq(
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr);
+
+VOID
+spxConnHandleSessPktFromClient(
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnHandleSessPktFromSrv(
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+ULONG
+spxConnConnectTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown);
+
+ULONG
+spxConnWatchdogTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown);
+
+ULONG
+spxConnRetryTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown);
+
+ULONG
+spxConnAckTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown);
+
+VOID
+spxConnCompletePended(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+SpxConnQWaitAck(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+USHORT
+spxConnGetId(
+ VOID);
+
+VOID
+spxConnInsertIntoActiveList(
+ IN PSPX_ADDR pSpxAddr,
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnInsertIntoInactiveList(
+ IN PSPX_ADDR pSpxAddr,
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+NTSTATUS
+spxConnRemoveFromGlobalList(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnInsertIntoGlobalList(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+NTSTATUS
+spxConnRemoveFromGlobalActiveList(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnPushIntoPktList(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnPopFromPktList(
+ IN PSPX_CONN_FILE * ppSpxConnFile);
+
+VOID
+spxConnPushIntoRecvList(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnPopFromRecvList(
+ IN PSPX_CONN_FILE * ppSpxConnFile);
+
+VOID
+spxConnInsertIntoGlobalActiveList(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnInsertIntoListenList(
+ IN PSPX_ADDR pSpxAddr,
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+NTSTATUS
+spxConnRemoveFromList(
+ IN PSPX_CONN_FILE * ppConnListHead,
+ IN PSPX_CONN_FILE pConnRemove);
+
+NTSTATUS
+spxConnRemoveFromAssocList(
+ IN PSPX_CONN_FILE * ppConnListHead,
+ IN PSPX_CONN_FILE pConnRemove);
+
+VOID
+spxConnInactivate(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+BOOLEAN
+spxConnGetPktByType(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN ULONG PktType,
+ IN BOOLEAN fSeqList,
+ IN PNDIS_PACKET * ppPkt);
+
+BOOLEAN
+spxConnGetPktBySeqNum(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN USHORT SeqNum,
+ IN PNDIS_PACKET * ppPkt);
+
+VOID
+spxConnResendPkts(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn);
+
+BOOLEAN
+spxConnCheckNegSize(
+ IN PUSHORT pNegSize);
+
+VOID
+spxConnSetNegSize(
+ IN OUT PNDIS_PACKET pPkt,
+ IN ULONG Size);
+
+BOOLEAN
+spxConnAcceptCr(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_ADDR pSpxAddr,
+ IN CTELockHandle LockHandleDev,
+ IN CTELockHandle LockHandleAddr,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+spxConnAbortConnect(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN CTELockHandle LockHandleDev,
+ IN CTELockHandle LockHandleAddr,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+spxConnCompleteConnect(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleDev,
+ IN CTELockHandle LockHandleAddr,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+SpxConnQueueRecv(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+spxConnProcessRecv(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PREQUEST pRequest,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+spxConnProcessIndData(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn);
+
+NTSTATUS
+spxConnOrderlyDisc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN PREQUEST pRequest,
+ IN CTELockHandle LockHandleConn);
+
+NTSTATUS
+spxConnInformedDisc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN PREQUEST pRequest,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+spxConnAbortiveDisc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn,
+ IN BOOLEAN Flag); // [SA] Bug #15249
+
+VOID
+spxConnAbortRecvs(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+spxConnAbortSends(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+spxConnResetSendQueue(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnAbortSendPkt(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_SEND_RESD pSendResd,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn);
+
+//
+// MACROS
+//
+#define SHIFT100000 16
+
+#define SPX_CONVERT100NSTOCENTISEC(Li) \
+ RtlExtendedMagicDivide((Li), Magic100000, SHIFT100000)
+
+#define UNSIGNED_BETWEEN_WITH_WRAP(Low, High, Target) \
+ ((Low <= High) ? ((Target >= Low) && (Target <= High)) : \
+ ((Target >= Low) || (Target <= High)))
+
+// This is with the assumption that the window size will never be greater
+// than the difference of 0x8000 and 0x1000. If High is < 1000 and Low
+// is > 8000 then we can assume a wrap happened. Otherwise, we assume no
+// wrap and do a straight compare.
+#define MAX_WINDOW_SIZE 0x6000
+#define DEFAULT_WINDOW_SIZE 8
+
+#define UNSIGNED_GREATER_WITH_WRAP(High, Low) \
+ (((High < 0x1000) && (Low > 0x8000)) ? TRUE : (High > Low))
+
+#define SPX_SET_ACKNUM(pSpxConnFile, RecdAckNum, RecdAllocNum) \
+ { \
+ DBGPRINT(SEND, DBG, \
+ ("SPX_SET_ACKNUM: %lx.%lx = %lx.%lx (%s.%d)\n", \
+ (RecdAckNum), (RecdAllocNum), \
+ ((pSpxConnFile)->scf_RecdAckNum), \
+ ((pSpxConnFile)->scf_RecdAllocNum), \
+ __FILE__, __LINE__)); \
+ \
+ if (UNSIGNED_GREATER_WITH_WRAP((RecdAckNum), \
+ ((pSpxConnFile)->scf_RecdAckNum))) \
+ { \
+ (pSpxConnFile)->scf_RecdAckNum = (RecdAckNum); \
+ } \
+ \
+ if (UNSIGNED_GREATER_WITH_WRAP((RecdAllocNum), \
+ ((pSpxConnFile)->scf_RecdAllocNum)))\
+ { \
+ (pSpxConnFile)->scf_RecdAllocNum = (RecdAllocNum); \
+ } \
+ }
+
+#define BEGIN_PROCESS_PACKET(pSpxConnFile, seqNum) \
+ { \
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_PKT); \
+ }
+
+#define END_PROCESS_PACKET(pSpxConnFile, fBuffered, fSuccess) \
+ { \
+ SPX_CONN_RESETFLAG2(pSpxConnFile, \
+ (SPX_CONNFILE2_PKT |SPX_CONNFILE2_RENEGRECD)); \
+ if (fSuccess) \
+ { \
+ SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_PKT_NOIND); \
+ SPX_SET_RECVNUM(pSpxConnFile, fBuffered); \
+ } \
+ }
+
+#define INCREMENT_WINDOW(pSpxConnFile) \
+ ((pSpxConnFile)->scf_SentAllocNum++)
+
+#define ADD_TO_WINDOW(pSpxConnFile, numPkts) \
+ ((pSpxConnFile)->scf_SentAllocNum += (numPkts))
+
+#if DBG_WDW_CLOSE
+#define SPX_SET_RECVNUM(pSpxConnFile, fBuffered) \
+ { \
+ (pSpxConnFile)->scf_RecvSeqNum++; \
+ if (!fBuffered) \
+ (pSpxConnFile)->scf_SentAllocNum++; \
+ \
+ if (fBuffered && \
+ (UNSIGNED_GREATER_WITH_WRAP( \
+ (pSpxConnFile)->scf_RecvSeqNum, \
+ (pSpxConnFile)->scf_SentAllocNum))) \
+ { \
+ KeQuerySystemTime( \
+ (PLARGE_INTEGER)&pSpxConnFile->scf_WdwCloseTime); \
+ } \
+ }
+#else
+#define SPX_SET_RECVNUM(pSpxConnFile, fBuffered) \
+ { \
+ (pSpxConnFile)->scf_RecvSeqNum++; \
+ if (!fBuffered) \
+ (pSpxConnFile)->scf_SentAllocNum++; \
+ }
+#endif
+
+
+#define SPX_CONN_SETNEXT_CUR_RECV(pSpxConnFile, pRequest) \
+ { \
+ RemoveEntryList(REQUEST_LINKAGE((pRequest))); \
+ pSpxConnFile->scf_CurRecvReq = NULL; \
+ pSpxConnFile->scf_CurRecvOffset = 0; \
+ pSpxConnFile->scf_CurRecvSize = 0; \
+ if (!IsListEmpty(&(pSpxConnFile)->scf_RecvLinkage)) \
+ { \
+ PTDI_REQUEST_KERNEL_RECEIVE _p; \
+ DBGPRINT(RECEIVE, DBG, \
+ ("spxConnProcessRecv: CURRECV %lx\n", pRequest)); \
+ \
+ (pSpxConnFile)->scf_CurRecvReq = \
+ LIST_ENTRY_TO_REQUEST( \
+ (pSpxConnFile)->scf_RecvLinkage.Flink); \
+ \
+ _p = (PTDI_REQUEST_KERNEL_RECEIVE) \
+ REQUEST_PARAMETERS((pSpxConnFile)->scf_CurRecvReq); \
+ \
+ (pSpxConnFile)->scf_CurRecvOffset = 0; \
+ (pSpxConnFile)->scf_CurRecvSize = (_p)->ReceiveLength; \
+ } \
+ if ((SPX_RECV_STATE(pSpxConnFile) == SPX_RECV_IDLE) || \
+ (SPX_RECV_STATE(pSpxConnFile) == SPX_RECV_POSTED)) \
+ { \
+ SPX_RECV_SETSTATE( \
+ pSpxConnFile, \
+ (pSpxConnFile->scf_CurRecvReq == NULL) ? \
+ SPX_RECV_IDLE : SPX_RECV_POSTED); \
+ } \
+ }
+
+#define SPX_INSERT_ADDR_ACTIVE(pSpxAddr, pSpxConnFile) \
+ { \
+ (pSpxConnFile)->scf_Next = (pSpxAddr)->sa_ActiveConnList; \
+ (pSpxAddr)->sa_ActiveConnList = pSpxConnFile; \
+ }
+
+#define SPX_INSERT_ADDR_INACTIVE(pSpxAddr, pSpxConnFile) \
+ { \
+ (pSpxConnFile)->scf_Next = (pSpxAddr)->sa_InactiveConnList; \
+ (pSpxAddr)->sa_InactiveConnList = pSpxConnFile; \
+ }
+
+#define SPX_INSERT_ADDR_LISTEN(pSpxAddr, pSpxConnFile) \
+ { \
+ (pSpxConnFile)->scf_Next = (pSpxAddr)->sa_ListenConnList; \
+ (pSpxAddr)->sa_ListenConnList = pSpxConnFile; \
+ }
+
+
+//
+// STATE MANIPULATION
+//
+
+#if 0
+//
+// Disabled for now
+//
+#define SPX_STORE_LAST_STATE(pSpxConnFile) \
+ (pSpxConnFile)->scf_StateBuffer[(pSpxConnFile)->scf_NextStatePtr++] = \
+ (pSpxConnFile)->scf_Flags; \
+ (pSpxConnFile)->scf_NextStatePtr %= CFMAX_STATES;
+#else
+
+#define SPX_STORE_LAST_STATE(pSpxConnFile)
+
+#endif
+
+#define SPX_MAIN_STATE(pSpxConnFile) \
+ ((pSpxConnFile)->scf_Flags & SPX_CONNFILE_MAINMASK)
+
+// #define SPX_CONN_IDLE(pSpxConnFile) \
+// ((BOOLEAN)(SPX_MAIN_STATE(pSpxConnFile) == 0))
+
+#define SPX_CONN_IDLE(pSpxConnFile) \
+ ((BOOLEAN)((SPX_MAIN_STATE(pSpxConnFile) == 0) || \
+ ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) && \
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED))))
+
+#define SPX_CONN_ACTIVE(pSpxConnFile) \
+ ((BOOLEAN)(SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_ACTIVE))
+
+#define SPX_CONN_CONNECTING(pSpxConnFile) \
+ ((BOOLEAN)(SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_CONNECTING))
+
+#define SPX_CONN_LISTENING(pSpxConnFile) \
+ ((BOOLEAN)(SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_LISTENING))
+
+#define SPX_CONN_DISC(pSpxConnFile) \
+ ((BOOLEAN)(SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN))
+
+#if DBG
+
+#define SPX_MAIN_SETSTATE(pSpxConnFile, newState) \
+ { \
+ SPX_STORE_LAST_STATE(pSpxConnFile) \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_CONNFILE_MAINMASK) | (newState));\
+ }
+
+#else
+
+#define SPX_MAIN_SETSTATE(pSpxConnFile, newState) \
+ { \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_CONNFILE_MAINMASK) | (newState));\
+ }
+
+#endif
+
+#define SPX_CONN_FLAG(pSpxConnFile, Flag) \
+ ((BOOLEAN)(((pSpxConnFile)->scf_Flags & (Flag)) != 0))
+
+#define SPX_CONN_FLAG2(pSpxConnFile, Flag) \
+ ((BOOLEAN)(((pSpxConnFile)->scf_Flags2 & (Flag)) != 0))
+
+#if DBG
+
+#define SPX_CONN_SETFLAG(pSpxConnFile, Flag) \
+ SPX_STORE_LAST_STATE(pSpxConnFile) \
+ ((pSpxConnFile)->scf_Flags |= (Flag))
+#else
+
+#define SPX_CONN_SETFLAG(pSpxConnFile, Flag) \
+ ((pSpxConnFile)->scf_Flags |= (Flag))
+
+#endif
+
+#define SPX_CONN_SETFLAG2(pSpxConnFile, Flag) \
+ ((pSpxConnFile)->scf_Flags2 |= (Flag))
+
+#define SPX_CONN_RESETFLAG(pSpxConnFile, Flag) \
+ ((pSpxConnFile)->scf_Flags &= ~(Flag))
+
+#define SPX_CONN_RESETFLAG2(pSpxConnFile, Flag) \
+ ((pSpxConnFile)->scf_Flags2 &= ~(Flag))
+
+#define SPX2_CONN(pSpxConnFile) \
+ (SPX_CONN_FLAG((pSpxConnFile), SPX_CONNFILE_SPX2))
+
+#define SPX_CONN_STREAM(pSpxConnFile) \
+ (SPX_CONN_FLAG((pSpxConnFile), SPX_CONNFILE_STREAM))
+
+#define SPX_CONN_MSG(pSpxConnFile) \
+ (!SPX_CONN_FLAG((pSpxConnFile), SPX_CONNFILE_STREAM))
+
+#define SPX_LISTEN_STATE(pSpxConnFile) \
+ ((pSpxConnFile)->scf_Flags & SPX_LISTEN_MASK)
+
+#define SPX_CONNECT_STATE(pSpxConnFile) \
+ ((pSpxConnFile)->scf_Flags & SPX_CONNECT_MASK)
+
+#define SPX_SEND_STATE(pSpxConnFile) \
+ ((pSpxConnFile)->scf_Flags & SPX_SEND_MASK)
+
+#define SPX_RECV_STATE(pSpxConnFile) \
+ ((pSpxConnFile)->scf_Flags & SPX_RECV_MASK)
+
+#define SPX_DISC_STATE(pSpxConnFile) \
+ ((pSpxConnFile)->scf_Flags & SPX_DISC_MASK)
+
+#if DBG
+
+#define SPX_LISTEN_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("LISTEN: %x -> %x\n", \
+ SPX_LISTEN_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ SPX_STORE_LAST_STATE(pSpxConnFile) \
+ pSpxConnFile->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_LISTEN_MASK) | (newState)); \
+ }
+
+#define SPX_CONNECT_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("CONNECT: %x -> %x\n", \
+ SPX_CONNECT_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ SPX_STORE_LAST_STATE(pSpxConnFile) \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_CONNECT_MASK) | (newState)); \
+ }
+
+#define SPX_SEND_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("SEND: %x -> %x\n", \
+ SPX_SEND_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ SPX_STORE_LAST_STATE(pSpxConnFile) \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_SEND_MASK) | (newState)); \
+ }
+
+#define SPX_RECV_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("RECV: %x -> %x\n", \
+ SPX_RECV_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ SPX_STORE_LAST_STATE(pSpxConnFile) \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_RECV_MASK) | (newState)); \
+ }
+
+#define SPX_DISC_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("DISC: %x -> %x\n", \
+ SPX_DISC_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ SPX_STORE_LAST_STATE(pSpxConnFile) \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_DISC_MASK) | (newState)); \
+ }
+
+#else
+
+#define SPX_LISTEN_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("LISTEN: %x -> %x\n", \
+ SPX_LISTEN_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ pSpxConnFile->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_LISTEN_MASK) | (newState)); \
+ }
+
+#define SPX_CONNECT_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("CONNECT: %x -> %x\n", \
+ SPX_CONNECT_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_CONNECT_MASK) | (newState)); \
+ }
+
+#define SPX_SEND_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("SEND: %x -> %x\n", \
+ SPX_SEND_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_SEND_MASK) | (newState)); \
+ }
+
+#define SPX_RECV_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("RECV: %x -> %x\n", \
+ SPX_RECV_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_RECV_MASK) | (newState)); \
+ }
+
+#define SPX_DISC_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("DISC: %x -> %x\n", \
+ SPX_DISC_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_DISC_MASK) | (newState)); \
+ }
+#endif //DBG
+#define SpxConnQueueSendPktTail(pSpxConnFile, pPkt) \
+ { \
+ PSPX_SEND_RESD _pSendResd; \
+ _pSendResd = (PSPX_SEND_RESD)((pPkt)->ProtocolReserved); \
+ _pSendResd->sr_Next = NULL; \
+ if ((pSpxConnFile)->scf_SendListTail != NULL) \
+ { \
+ (pSpxConnFile)->scf_SendListTail->sr_Next = _pSendResd; \
+ (pSpxConnFile)->scf_SendListTail = _pSendResd;\
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_SendListTail = \
+ (pSpxConnFile)->scf_SendListHead = _pSendResd; \
+ } \
+ }
+
+#define SpxConnQueueSendPktHead(pSpxConnFile, pPkt) \
+ { \
+ PSPX_SEND_RESD _pSendResd; \
+ _pSendResd = (PSPX_SEND_RESD)((pPkt)->ProtocolReserved); \
+ _pSendResd->sr_Next = NULL; \
+ if ((pSpxConnFile)->scf_SendListTail != NULL) \
+ { \
+ _pSendResd->sr_Next = (pSpxConnFile)->scf_SendListHead; \
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_SendListTail = _pSendResd; \
+ } \
+ (pSpxConnFile)->scf_SendListHead = _pSendResd; \
+ }
+
+#define SpxConnQueueSendSeqPktTail(pSpxConnFile, pPkt) \
+ { \
+ PSPX_SEND_RESD _pSendResd; \
+ _pSendResd = (PSPX_SEND_RESD)((pPkt)->ProtocolReserved); \
+ _pSendResd->sr_Next = NULL; \
+ if ((pSpxConnFile)->scf_SendSeqListTail != NULL) \
+ { \
+ (pSpxConnFile)->scf_SendSeqListTail->sr_Next = _pSendResd;\
+ (pSpxConnFile)->scf_SendSeqListTail = _pSendResd;\
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_SendSeqListTail = \
+ (pSpxConnFile)->scf_SendSeqListHead = _pSendResd; \
+ } \
+ }
+
+#define SpxConnQueueSendSeqPktHead(pSpxConnFile, pPkt) \
+ { \
+ PSPX_SEND_RESD _pSendResd; \
+ _pSendResd = (PSPX_SEND_RESD)((pPkt)->ProtocolReserved); \
+ _pSendResd->sr_Next = NULL; \
+ if ((pSpxConnFile)->scf_SendSeqListTail != NULL) \
+ { \
+ _pSendResd->sr_Next = (pSpxConnFile)->scf_SendSeqListHead;\
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_SendSeqListTail = _pSendResd; \
+ } \
+ (pSpxConnFile)->scf_SendSeqListHead = _pSendResd; \
+ }
+
+#define SpxConnQueueRecvPktTail(pSpxConnFile, pPkt) \
+ { \
+ PSPX_RECV_RESD _pRecvResd; \
+ _pRecvResd = (PSPX_RECV_RESD)((pPkt)->ProtocolReserved); \
+ _pRecvResd->rr_Next = NULL; \
+ if ((pSpxConnFile)->scf_RecvListTail != NULL) \
+ { \
+ (pSpxConnFile)->scf_RecvListTail->rr_Next = _pRecvResd; \
+ (pSpxConnFile)->scf_RecvListTail = _pRecvResd;\
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_RecvListTail = \
+ (pSpxConnFile)->scf_RecvListHead = _pRecvResd; \
+ } \
+ }
+
+#define SpxConnQueueRecvPktHead(pSpxConnFile, pPkt) \
+ { \
+ PSPX_RECV_RESD _pRecvResd; \
+ _pRecvResd = (PSPX_RECV_RESD)((pPkt)->ProtocolReserved); \
+ _pRecvResd->rr_Next = NULL; \
+ if ((pSpxConnFile)->scf_RecvListTail != NULL) \
+ { \
+ _pRecvResd->rr_Next = (pSpxConnFile)->scf_RecvListHead; \
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_RecvListTail = _pRecvResd; \
+ } \
+ (pSpxConnFile)->scf_RecvListHead = _pRecvResd; \
+ }
+
+#if DBG
+#define SpxConnFileReference(_ConnFile, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_ConnFile)->scf_RefTypes[_Type], \
+ 1, \
+ &SpxGlobalInterlock); \
+ SpxConnFileRef (_ConnFile); \
+ }
+
+#define SpxConnFileLockReference(_ConnFile, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_ConnFile)->scf_RefTypes[_Type], \
+ 1, \
+ &SpxGlobalInterlock); \
+ SpxConnFileLockRef (_ConnFile); \
+ }
+
+#define SpxConnFileDereference(_ConnFile, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_ConnFile)->scf_RefTypes[_Type], \
+ (ULONG)-1, \
+ &SpxGlobalInterlock); \
+ SpxConnFileDeref (_ConnFile); \
+ }
+
+#define SpxConnFileReferenceByCtx(_pAddrFile, _Ctx, _ppConnFile, _pStatus) \
+ { \
+ CTELockHandle _lockHandle; \
+ CTEGetLock((_pAddrFile)->saf_AddrLock, &(_lockHandle)); \
+ SpxConnFileRefByCtxLock((_pAddrFile), (_Ctx), (_ppConnFile),(_pStatus));\
+ CTEFreeLock((_pAddrFile)->saf_AddrLock, (_lockHandle)); \
+ }
+
+#define SpxConnFileReferenceByCtxLock(_pAddrFile, _Ctx, _ppConnFile, _pStatus) \
+ SpxConnFileRefByCtxLock((_pAddrFile), (_Ctx), (_ppConnFile),(_pStatus));
+
+#define SpxConnFileReferenceById(_ConnId, _ppConnFile, _pStatus) \
+ { \
+ CTELockHandle _l; \
+ CTEGetLock(&SpxDevice->dev_Lock, &(_l)); \
+ SpxConnFileRefByIdLock(_ConnId, _ppConnFile, _pStatus); \
+ CTEFreeLock(&SpxDevice->dev_Lock, _l); \
+ }
+
+#define SpxConnFileTransferReference(_ConnFile, _OldType, _NewType) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_ConnFile)->scf_RefTypes[_NewType], \
+ 1, \
+ &SpxGlobalInterlock); \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_ConnFile)->scf_RefTypes[_OldType], \
+ (ULONG)-1, \
+ &SpxGlobalInterlock); \
+ }
+
+#else // DBG
+
+#define SpxConnFileReference(_ConnFile, _Type) \
+ SPX_ADD_ULONG( \
+ &(_ConnFile)->scf_RefCount, \
+ 1, \
+ &(_ConnFile)->scf_Lock)
+
+#define SpxConnFileLockReference(_ConnFile, _Type) \
+ SPX_ADD_ULONG( \
+ &(_ConnFile)->scf_RefCount, \
+ 1, \
+ &(_ConnFile)->scf_Lock);
+
+#define SpxConnFileDereference(_ConnFile, _Type) \
+ { \
+ SpxConnFileDeref(_ConnFile); \
+ }
+
+#define SpxConnFileReferenceByCtx(_pAddrFile, _Ctx, _ppConnFile, _pStatus) \
+ { \
+ CTELockHandle _lockHandle; \
+ CTEGetLock((_pAddrFile)->saf_AddrLock, &(_lockHandle)); \
+ SpxConnFileRefByCtxLock((_pAddrFile), (_Ctx), (_ppConnFile),(_pStatus));\
+ CTEFreeLock((_pAddrFile)->saf_AddrLock, (_lockHandle)); \
+ }
+
+#define SpxConnFileReferenceByCtxLock(_pAddrFile, _Ctx, _ppConnFile, _pStatus) \
+ SpxConnFileRefByCtxLock((_pAddrFile), (_Ctx), (_ppConnFile),(_pStatus));
+
+#define SpxConnFileReferenceById(_ConnId, _ppConnFile, _pStatus) \
+ { \
+ CTELockHandle _lockHandle; \
+ CTEGetLock(&SpxDevice->dev_Lock, &(_lockHandle)); \
+ SpxConnFileRefByIdLock(_ConnId, _ppConnFile, _pStatus); \
+ CTEFreeLock(&SpxDevice->dev_Lock, (_lockHandle)); \
+ }
+
+#define SpxConnFileTransferReference(_ConnFile, _OldType, _NewType)
+
+#endif // DBG
+
+
+// Set the packet size. If we are spx1 or spx2 and !neg, check if we are different
+// nets, set to min then, else use the size indicated by IPX. If we are spx2, just
+// set it to our local max.
+//
+// Also always even out packet size and round down. This solves an issue with
+// data size needing to be even for some novell 802.2 clients.
+//
+// Fix after beta2 for tokring using receive size. Only if spx2 and neg.
+#if defined(_PNP_POWER)
+#define SPX_MAX_PKT_SIZE(pSpxConnFile, fSpx2Neg, fSpx2, pRemNet) \
+ { \
+ if (!fSpx2 && PARAM(CONFIG_BACKCOMP_SPX)) { \
+ (pSpxConnFile)->scf_MaxPktSize = SPX_MAX_PACKET; \
+ } \
+ else { \
+ IPX_LINE_INFO _i; \
+ \
+ (VOID)(*IpxQuery)( \
+ IPX_QUERY_LINE_INFO, \
+ &(pSpxConnFile)->scf_LocalTarget.NicHandle, \
+ &(_i), \
+ sizeof(IPX_LINE_INFO), \
+ NULL); \
+ \
+ (pSpxConnFile)->scf_MaxPktSize = (_i).MaximumPacketSize; \
+ if (!fSpx2Neg) \
+ { \
+ (pSpxConnFile)->scf_MaxPktSize = (_i).MaximumSendSize; \
+ } \
+ \
+ if ((pSpxConnFile)->scf_MaxPktSize < SPX_MAX_PACKET) \
+ { \
+ (pSpxConnFile)->scf_MaxPktSize = SPX_MAX_PACKET; \
+ } \
+ \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: Nets %lx.%lx Max Pkt %d\n", \
+ (*(UNALIGNED ULONG *)(pRemNet)), \
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network, \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ DBGPRINT(CONNECT, DBG, \
+ ("%s : %d.%d\n", __FILE__, __LINE__, fSpx2Neg)); \
+ \
+ if ((!fSpx2Neg) && \
+ ((*(UNALIGNED ULONG *)(pRemNet)) != 0) && \
+ ((*(UNALIGNED ULONG *)SpxDevice->dev_Network) != 0) && \
+ ((*(UNALIGNED ULONG *)(pRemNet)) != \
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network)) \
+ { \
+ if (PARAM(CONFIG_ROUTER_MTU) != 0) \
+ { \
+ DBGPRINT(CONNECT, ERR, \
+ ("SPX_MAX_PKT_SIZE: PARAM %lx Max Pkt %lx\n", \
+ PARAM(CONFIG_ROUTER_MTU), \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ \
+ (pSpxConnFile)->scf_MaxPktSize = \
+ (USHORT)(MIN(PARAM(CONFIG_ROUTER_MTU), \
+ (ULONG)((pSpxConnFile)->scf_MaxPktSize)));\
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_MaxPktSize = SPX_MAX_PACKET; \
+ } \
+ \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: Nets %lx.%lx Max Pkt %d\n", \
+ (*(UNALIGNED ULONG *)(pRemNet)), \
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network, \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: LineInfo Pkt %d\n", \
+ (_i).MaximumSendSize)); \
+ } \
+ } \
+ (pSpxConnFile)->scf_MaxPktSize &= ~((USHORT)1); \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: %lx.%d\n", \
+ (pSpxConnFile)->scf_MaxPktSize, \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ }
+#else
+#define SPX_MAX_PKT_SIZE(pSpxConnFile, fSpx2Neg, fSpx2, pRemNet) \
+ { \
+ if (!fSpx2 && PARAM(CONFIG_BACKCOMP_SPX)) { \
+ (pSpxConnFile)->scf_MaxPktSize = SPX_MAX_PACKET; \
+ } \
+ else { \
+ IPX_LINE_INFO _i; \
+ \
+ (VOID)(*IpxQuery)( \
+ IPX_QUERY_LINE_INFO, \
+ (pSpxConnFile)->scf_LocalTarget.NicId, \
+ &(_i), \
+ sizeof(IPX_LINE_INFO), \
+ NULL); \
+ \
+ (pSpxConnFile)->scf_MaxPktSize = (_i).MaximumPacketSize; \
+ if (!fSpx2Neg) \
+ { \
+ (pSpxConnFile)->scf_MaxPktSize = (_i).MaximumSendSize; \
+ } \
+ \
+ if ((pSpxConnFile)->scf_MaxPktSize < SPX_MAX_PACKET) \
+ { \
+ (pSpxConnFile)->scf_MaxPktSize = SPX_MAX_PACKET; \
+ } \
+ \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: Nets %lx.%lx Max Pkt %d\n", \
+ (*(UNALIGNED ULONG *)(pRemNet)), \
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network, \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ DBGPRINT(CONNECT, DBG, \
+ ("%s : %d.%d\n", __FILE__, __LINE__, fSpx2Neg)); \
+ \
+ if ((!fSpx2Neg) && \
+ ((*(UNALIGNED ULONG *)(pRemNet)) != 0) && \
+ ((*(UNALIGNED ULONG *)SpxDevice->dev_Network) != 0) && \
+ ((*(UNALIGNED ULONG *)(pRemNet)) != \
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network)) \
+ { \
+ if (PARAM(CONFIG_ROUTER_MTU) != 0) \
+ { \
+ DBGPRINT(CONNECT, ERR, \
+ ("SPX_MAX_PKT_SIZE: PARAM %lx Max Pkt %lx\n", \
+ PARAM(CONFIG_ROUTER_MTU), \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ \
+ (pSpxConnFile)->scf_MaxPktSize = \
+ (USHORT)(MIN(PARAM(CONFIG_ROUTER_MTU), \
+ (ULONG)((pSpxConnFile)->scf_MaxPktSize)));\
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_MaxPktSize = SPX_MAX_PACKET; \
+ } \
+ \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: Nets %lx.%lx Max Pkt %d\n", \
+ (*(UNALIGNED ULONG *)(pRemNet)), \
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network, \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: LineInfo Pkt %d\n", \
+ (_i).MaximumSendSize)); \
+ } \
+ } \
+ (pSpxConnFile)->scf_MaxPktSize &= ~((USHORT)1); \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: %lx.%d\n", \
+ (pSpxConnFile)->scf_MaxPktSize, \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ }
+#endif _PNP_POWER
+
+#if DBG
+#define SPX_SENDPACKET(pSpxConnFile, pNdisPkt, pSendResd) \
+ { \
+ NDIS_STATUS _n; \
+ \
+ ++SpxDevice->dev_Stat.PacketsSent; \
+ \
+ _n = (*IpxSendPacket)( \
+ &(pSpxConnFile)->scf_LocalTarget, \
+ (pNdisPkt), \
+ (pSendResd)->sr_Len, \
+ (pSendResd)->sr_HdrLen); \
+ \
+ if (_n != NDIS_STATUS_PENDING) \
+ { \
+ if (_n != NDIS_STATUS_SUCCESS) \
+ { \
+ DBGPRINT(SEND, ERR, \
+ ("SPX_SENDPACKET: Failed with %lx in %s.%lx\n", \
+ _n, __FILE__, __LINE__)); \
+ } \
+ \
+ SpxSendComplete( \
+ (pNdisPkt), \
+ _n); \
+ } \
+ }
+
+#define SPX_SENDACK(pSpxConnFile, pNdisPkt, pSendResd) \
+ { \
+ NDIS_STATUS _n; \
+ \
+ ++SpxDevice->dev_Stat.PacketsSent; \
+ \
+ _n = (*IpxSendPacket)( \
+ &(pSpxConnFile)->scf_AckLocalTarget, \
+ (pNdisPkt), \
+ (pSendResd)->sr_Len, \
+ (pSendResd)->sr_HdrLen); \
+ \
+ if (_n != NDIS_STATUS_PENDING) \
+ { \
+ if (_n != NDIS_STATUS_SUCCESS) \
+ { \
+ DBGPRINT(SEND, ERR, \
+ ("SPX_SENDPACKET: Failed with %lx in %s.%lx\n", \
+ _n, __FILE__, __LINE__)); \
+ } \
+ \
+ SpxSendComplete( \
+ (pNdisPkt), \
+ _n); \
+ } \
+ }
+
+#else // DBG
+#define SPX_SENDPACKET(pSpxConnFile, pNdisPkt, pSendResd) \
+ { \
+ NDIS_STATUS _n; \
+ \
+ ++SpxDevice->dev_Stat.PacketsSent; \
+ \
+ _n = (*IpxSendPacket)( \
+ &(pSpxConnFile)->scf_LocalTarget, \
+ (pNdisPkt), \
+ (pSendResd)->sr_Len, \
+ (pSendResd)->sr_HdrLen); \
+ \
+ if (_n != NDIS_STATUS_PENDING) \
+ { \
+ SpxSendComplete( \
+ (pNdisPkt), \
+ _n); \
+ } \
+ }
+#define SPX_SENDACK(pSpxConnFile, pNdisPkt, pSendResd) \
+ { \
+ NDIS_STATUS _n; \
+ \
+ ++SpxDevice->dev_Stat.PacketsSent; \
+ \
+ _n = (*IpxSendPacket)( \
+ &(pSpxConnFile)->scf_AckLocalTarget, \
+ (pNdisPkt), \
+ (pSendResd)->sr_Len, \
+ (pSendResd)->sr_HdrLen); \
+ \
+ if (_n != NDIS_STATUS_PENDING) \
+ { \
+ SpxSendComplete( \
+ (pNdisPkt), \
+ _n); \
+ } \
+ }
+
+#endif // DBG
+
+#define SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile) \
+ { \
+ if (!SPX_CONN_FLAG( \
+ (pSpxConnFile), \
+ SPX_CONNFILE_RECVQ)) \
+ { \
+ SPX_CONN_SETFLAG((pSpxConnFile), SPX_CONNFILE_RECVQ); \
+ SpxConnFileLockReference(pSpxConnFile, CFREF_RECV); \
+ SPX_QUEUE_TAIL_RECVLIST(pSpxConnFile); \
+ } \
+ }
+
+#define SPX_QUEUE_TAIL_PKTLIST(pSpxConnFile) \
+ { \
+ if (SpxPktConnList.pcl_Tail) \
+ { \
+ SpxPktConnList.pcl_Tail->scf_PktNext = pSpxConnFile; \
+ SpxPktConnList.pcl_Tail = pSpxConnFile; \
+ } \
+ else \
+ { \
+ SpxPktConnList.pcl_Tail = \
+ SpxPktConnList.pcl_Head = pSpxConnFile; \
+ } \
+ }
+
+#define SPX_QUEUE_TAIL_RECVLIST(pSpxConnFile) \
+ { \
+ if (SpxRecvConnList.pcl_Tail) \
+ { \
+ SpxRecvConnList.pcl_Tail->scf_ProcessRecvNext = pSpxConnFile; \
+ SpxRecvConnList.pcl_Tail = pSpxConnFile; \
+ } \
+ else \
+ { \
+ SpxRecvConnList.pcl_Tail = \
+ SpxRecvConnList.pcl_Head = pSpxConnFile; \
+ } \
+ }
+
+
diff --git a/private/ntos/tdi/isn/spx/h/spxdev.h b/private/ntos/tdi/isn/spx/h/spxdev.h
new file mode 100644
index 000000000..30c0adae5
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxdev.h
@@ -0,0 +1,204 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxdev.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ SPX module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba ) Original Version
+ Nikhil Kamkolkar (nikhilk) 17-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+
+// Hash buckets for SPX_ADDR done using socket number
+#define NUM_SPXADDR_HASH_BUCKETS 8
+#define NUM_SPXADDR_HASH_MASK 7
+#define NUM_SPXCONN_HASH_BUCKETS 8
+#define NUM_SPXCONN_HASH_MASK 7
+
+// This structure defines the per-device structure for SPX
+// (one of these is allocated globally).
+#define DREF_CREATE 0
+#define DREF_LOADED 1
+#define DREF_ADAPTER 2
+#define DREF_ADDRESS 3
+#define DREF_ORPHAN 4
+
+#define DREF_TOTAL 5
+
+typedef struct _DEVICE {
+
+ DEVICE_OBJECT dev_DevObj; // the I/O system's device object.
+
+#if DBG
+ ULONG dev_RefTypes[DREF_TOTAL];
+#endif
+
+ CSHORT dev_Type; // type of this structure
+ USHORT dev_Size; // size of this structure
+
+#if DBG
+ UCHAR dev_Signature1[4]; // contains "SPX1"
+#endif
+
+ // activity count/this provider.
+ LONG dev_RefCount;
+ UCHAR dev_State;
+
+ // number of adapters IPX is bound to.
+ USHORT dev_Adapters;
+
+ // GLOBAL lock for reference count (used in ExInterlockedXxx calls).
+ CTELock dev_Interlock;
+ CTELock dev_Lock;
+
+ // Hash table of lists of addresses opened on this device
+ struct _SPX_ADDR * dev_AddrHashTable[NUM_SPXADDR_HASH_BUCKETS];
+
+ // List of all active connections, later this be a tree.
+ struct _SPX_CONN_FILE * dev_GlobalActiveConnList[NUM_SPXCONN_HASH_BUCKETS];
+ USHORT dev_NextConnId;
+
+ // Other configuration parameters.
+ // Where the current socket allocation is.
+ USHORT dev_CurrentSocket;
+
+ // Our node and network.
+ UCHAR dev_Network[4];
+ UCHAR dev_Node[6];
+
+ // Pointer to the config information from registry
+ PCONFIG dev_ConfigInfo;
+
+ // Control channel identifier
+ ULONG dev_CcId;
+
+ // These are kept around for error logging, and stored right
+ // after this structure.
+ PWCHAR dev_DeviceName;
+#if defined(_PNP_POWER)
+ USHORT dev_DeviceNameLen;
+#else
+ ULONG dev_DeviceNameLen;
+#endif _PNP_POWER
+
+#if DBG
+ UCHAR dev_Signature2[4]; // contains "SPX2"
+#endif
+
+ // Handle to ndis buffer pool for spx stack.
+ NDIS_HANDLE dev_NdisBufferPoolHandle;
+
+ // registration handle with tdi clients.
+#if defined(_PNP_POWER)
+ HANDLE dev_TdiRegistrationHandle;
+#endif _PNP_POWER
+
+ // This interlock is used to guard access to the statistics
+ // define below.
+ KSPIN_LOCK dev_StatInterlock; // for ULONG quantities
+ KSPIN_LOCK dev_StatSpinLock; // for LARGE_INTEGER quantities
+
+ // Counters for most of the statistics that SPX maintains;
+ // some of these are kept elsewhere. Including the structure
+ // itself wastes a little space but ensures that the alignment
+ // inside the structure is correct.
+ TDI_PROVIDER_STATISTICS dev_Stat;
+
+ // This resource guards access to the ShareAccess
+ // and SecurityDescriptor fields in addresses.
+ ERESOURCE dev_AddrResource;
+
+ // The following structure contains statistics counters for use
+ // by TdiQueryInformation and TdiSetInformation. They should not
+ // be used for maintenance of internal data structures.
+ TDI_PROVIDER_INFO dev_ProviderInfo; // information about this provider.
+
+} DEVICE, * PDEVICE;
+
+// device state definitions
+#if defined(_PNP_POWER)
+#define DEVICE_STATE_CLOSED 0x00 // Initial state
+#define DEVICE_STATE_LOADED 0x01 // Loaded and bound to IPX but no adapters
+#define DEVICE_STATE_OPEN 0x02 // Fully operational
+#define DEVICE_STATE_STOPPING 0x03 // Unload has been initiated, The I/O system
+ // will not call us until nobody above has Netbios open.
+#else
+#define DEVICE_STATE_CLOSED 0x00
+#define DEVICE_STATE_OPEN 0x01
+#define DEVICE_STATE_STOPPING 0x02
+#endif _PNP_POWER
+
+
+// SPX device name
+#define SPX_DEVICE_NAME L"\\Device\\NwlnkSpx"
+
+#define SPX_TDI_RESOURCES 9
+
+
+// MACROS
+#if DBG
+
+#define SpxReferenceDevice(_Device, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_Device)->dev_RefTypes[_Type], \
+ 1, \
+ &SpxGlobalInterlock); \
+ \
+ (VOID)InterlockedIncrement ( \
+ &(_Device)->dev_RefCount); \
+ }
+
+#define SpxDereferenceDevice(_Device, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_Device)->dev_RefTypes[_Type], \
+ (ULONG)-1, \
+ &SpxGlobalInterlock); \
+ SpxDerefDevice (_Device); \
+ }
+
+#else
+
+#define SpxReferenceDevice(_Device, _Type) \
+ { \
+ (VOID)InterlockedIncrement ( \
+ &(_Device)->dev_RefCount); \
+ }
+
+#define SpxDereferenceDevice(_Device, _Type) \
+ SpxDerefDevice (_Device)
+
+#endif
+
+// EXPORTED ROUTINES
+
+VOID
+SpxDestroyDevice(
+ IN PDEVICE Device);
+
+VOID
+SpxDerefDevice(
+ IN PDEVICE Device);
+
+NTSTATUS
+SpxInitCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN OUT PDEVICE *DevicePtr);
diff --git a/private/ntos/tdi/isn/spx/h/spxerror.h b/private/ntos/tdi/isn/spx/h/spxerror.h
new file mode 100644
index 000000000..761342512
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxerror.h
@@ -0,0 +1,246 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ spxerror.h
+
+Abstract:
+
+ This module contains some error definitions for spx.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+
+Notes: Tab stop: 4
+--*/
+
+// Define the modules names for SPX - use the high bits.
+#define SPXDRVR 0x00010000
+#define SPXREG 0x00020000
+#define SPXDEV 0x00030000
+#define SPXBIND 0x00040000
+#define SPXRECV 0x00050000
+#define SPXSEND 0x00060000
+#define SPXTIMER 0x00070000
+#define SPXERROR 0x00080000
+#define SPXPKT 0x00090000
+#define SPXUTILS 0x000a0000
+#define SPXCPKT 0x000b0000
+#define SPXCONN 0x000c0000
+#define SPXADDR 0x000d0000
+#define SPXCUTIL 0x000e0000
+#define SPXINIT 0x000f0000
+#define SPXMEM 0x00100000
+#define SPXQUERY 0x00200000
+
+
+// DEBUGGING SUPPORT:
+// Debugging messages are provided per-subsystem defined here, and within
+// the subsystems, there are 4 levels of messages.
+//
+// The four levels of debug messages are:
+//
+// INFO: Informational messages, eg., entry exit in routines
+// DBG: Used when debugging some msgs are turned from info to dbg
+// WARN: Something went wrong, but its not an error, eg., packet was not ours
+// ERR: Error situations, but we can still run if a retry happens
+// FATAL: In this situation, the driver is not operational
+
+#define DBG_LEVEL_INFO 0x4000
+#define DBG_LEVEL_DBG 0x5000
+#define DBG_LEVEL_DBG1 0x5001
+#define DBG_LEVEL_DBG2 0x5002
+#define DBG_LEVEL_DBG3 0x5003
+#define DBG_LEVEL_WARN 0x6000
+#define DBG_LEVEL_ERR 0x7000
+#define DBG_LEVEL_FATAL 0x8000
+
+// SUBSYSTEMS
+#define DBG_COMP_DEVICE 0x00000001
+#define DBG_COMP_CREATE 0x00000002
+#define DBG_COMP_ADDRESS 0x00000004
+#define DBG_COMP_SEND 0x00000008
+#define DBG_COMP_NDIS 0x00000010
+#define DBG_COMP_RECEIVE 0x00000020
+#define DBG_COMP_CONFIG 0x00000040
+#define DBG_COMP_PACKET 0x00000080
+#define DBG_COMP_RESOURCES 0x00000100
+#define DBG_COMP_BIND 0x00000200
+#define DBG_COMP_UNLOAD 0x00000400
+#define DBG_COMP_DUMP 0x00000800
+#define DBG_COMP_REFCOUNTS 0x00001000
+#define DBG_COMP_SYSTEM 0x00002000
+#define DBG_COMP_CRITSEC 0x00004000
+#define DBG_COMP_UTILS 0x00008000
+#define DBG_COMP_TDI 0x00010000
+#define DBG_COMP_CONNECT 0x00020000
+#define DBG_COMP_DISC 0x00040000
+#define DBG_COMP_ACTION 0x00080000
+#define DBG_COMP_STATE 0x00100000
+
+#define DBG_COMP_MOST (DBG_COMP_DEVICE | \
+ DBG_COMP_CREATE | \
+ DBG_COMP_ADDRESS | \
+ DBG_COMP_SEND | \
+ DBG_COMP_NDIS | \
+ DBG_COMP_RECEIVE | \
+ DBG_COMP_CONFIG | \
+ DBG_COMP_PACKET | \
+ DBG_COMP_RESOURCES | \
+ DBG_COMP_BIND | \
+ DBG_COMP_UNLOAD | \
+ DBG_COMP_DUMP | \
+ DBG_COMP_REFCOUNTS | \
+ DBG_COMP_SYSTEM | \
+ DBG_COMP_CRITSEC | \
+ DBG_COMP_UTILS | \
+ DBG_COMP_TDI | \
+ DBG_COMP_CONNECT | \
+ DBG_COMP_DISC | \
+ DBG_COMP_ACTION | \
+ DBG_COMP_STATE)
+
+
+// More debugging support. These values define the dumping components.
+// There are a max of 32 such components that can be defined. Each of
+// these are associated with a dump routine. It one is specified and
+// enabled, periodically it is called. It is upto that component to
+// decide what it wants to do
+
+#define DBG_DUMP_DEF_INTERVAL 30 // In Seconds
+
+// This defines the number of times an error has to happen consecutively before
+// it gets logged again.
+#define ERROR_CONSEQ_FREQ 200
+#define ERROR_CONSEQ_TIME (60*30) // 30 minutes
+
+#ifdef DBG
+typedef VOID (*DUMP_ROUTINE)(VOID);
+
+extern
+BOOLEAN
+SpxDumpComponents(
+ IN PVOID Context);
+
+#endif
+
+//
+// PROTOTYPES
+//
+
+BOOLEAN
+SpxFilterErrorLogEntry(
+ IN NTSTATUS UniqueErrorCode,
+ IN NTSTATUS NtStatusCode,
+ IN PVOID RawDataBuf OPTIONAL,
+ IN LONG RawDataLen);
+VOID
+SpxWriteResourceErrorLog(
+ IN PDEVICE Device,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue);
+
+VOID
+SpxWriteGeneralErrorLog(
+ IN PDEVICE Device,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN PVOID RawDataBuf OPTIONAL,
+ IN LONG RawDataLen);
+
+
+//
+// MACROS
+//
+
+#if DBG
+#define LOG_ERROR(Error, NtStatus, SecondString, RawData, RawDataLen) \
+ { \
+ SpxWriteGeneralErrorLog( \
+ SpxDevice, \
+ Error, \
+ FILENUM | __LINE__, \
+ NtStatus, \
+ SecondString, \
+ RawData, \
+ RawDataLen); \
+ }
+
+#define RES_LOG_ERROR(BytesNeeded) \
+ { \
+ SpxWriteResourceErrorLog( \
+ SpxDevice, \
+ BytesNeeded, \
+ FILENUM | __LINE__); \
+ }
+
+#else
+
+#define LOG_ERROR(Error, NtStatus, SecondString, RawData, RawDataLen) \
+ { \
+ SpxWriteGeneralErrorLog( \
+ SpxDevice, \
+ Error, \
+ FILENUM | __LINE__, \
+ NtStatus, \
+ SecondString, \
+ RawData, \
+ RawDataLen); \
+ }
+
+#define RES_LOG_ERROR(BytesNeeded) \
+ { \
+ SpxWriteResourceErrorLog( \
+ SpxDevice, \
+ BytesNeeded, \
+ FILENUM | __LINE__); \
+ }
+
+#endif
+
+
+#if DBG
+
+#define DBGPRINT(Component, Level, Fmt) \
+ { \
+ if (((DBG_LEVEL_ ## Level) >= SpxDebugLevel) && \
+ (SpxDebugSystems & (DBG_COMP_ ## Component))) \
+ { \
+ DbgPrint("SPX: "); \
+ DbgPrint Fmt; \
+ } \
+ }
+
+#define DBGBRK(Level) \
+ { \
+ if ((DBG_LEVEL_ ## Level) >= SpxDebugLevel) \
+ DbgBreakPoint(); \
+ }
+
+#define TMPLOGERR() \
+ { \
+ DBGPRINT(MOST, ERR, \
+ ("TempErrLog: %s, Line %ld\n", __FILE__, __LINE__)); \
+ }
+
+#else
+#define DBGPRINT(Component, Level, Fmt)
+#define DBGBRK(Level)
+#define TMPLOGERR()
+#endif
+
+extern
+VOID
+SpxWriteErrorLogEntry(
+ IN NTSTATUS UniqueErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS NtStatusCode,
+ IN PVOID RawDataBuf OPTIONAL,
+ IN LONG RawDataLen);
diff --git a/private/ntos/tdi/isn/spx/h/spxmem.h b/private/ntos/tdi/isn/spx/h/spxmem.h
new file mode 100644
index 000000000..717c69a6b
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxmem.h
@@ -0,0 +1,142 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxmem.h
+
+Abstract:
+
+ This module contains memory management routines.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 17-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+
+#define QWORDSIZEBLOCK(Size) (((Size)+sizeof(LARGE_INTEGER)-1) & ~(sizeof(LARGE_INTEGER)-1))
+#define SPX_MEMORY_SIGNATURE *(PULONG)"SPXM"
+#define ZEROED_MEMORY_TAG 0xF0000000
+#define SPX_TAG *((PULONG)"SPX ")
+
+//
+// Definitions for the block management package
+//
+typedef UCHAR BLKID;
+
+// Add a BLKID_xxx and an entry to atalkBlkSize for every block client
+#define BLKID_TIMERLIST (BLKID)0
+#define BLKID_NDISSEND (BLKID)1
+#define BLKID_NDISRECV (BLKID)2
+#define NUM_BLKIDS (BLKID)3
+
+typedef struct _BLK_CHUNK
+{
+ struct _BLK_CHUNK * bc_Next; // Pointer to next in the link
+ SHORT bc_NumFrees; // Number of free blocks in the chunk
+ UCHAR bc_Age; // Number of invocations since the chunk free
+ BLKID bc_BlkId; // Id of the block
+ struct _BLK_HDR * bc_FreeHead; // Head of the list of free blocks
+
+#ifndef SPX_OWN_PACKETS
+ PVOID bc_ChunkCtx; // Used to store pool header if not own
+ // packets
+#else
+ PVOID bc_Padding; // Keep the header 16 bytes
+#endif
+
+ // This is followed by an array of N blks of size M such that the block header
+ // is exactly spxChunkSize[i]
+
+} BLK_CHUNK, *PBLK_CHUNK;
+
+typedef struct _BLK_HDR
+{
+ union
+ {
+ struct _BLK_HDR * bh_Next; // Valid when it is free
+ struct _BLK_CHUNK * bh_pChunk; // The parent chunk to which this blocks belong
+ // valid when it is allocated
+ };
+ PVOID bh_Padding; // Make the header 8 bytes
+} BLK_HDR, *PBLK_HDR;
+
+#define BC_OVERHEAD (8+8) // LARGE_INTEGER for SpxAllocMemory() header and
+ // POOL_HEADER for ExAllocatePool() header
+
+#define BLOCK_POOL_TIMER 1000 // Check interval (1 sec)
+#define MAX_BLOCK_POOL_AGE 3 // # of timer invocations before free
+
+ULONG
+spxBPAgePool(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown);
+
+
+#ifdef TRACK_MEMORY_USAGE
+
+#define SpxAllocateMemory(Size) SpxAllocMem((Size), FILENUM | __LINE__)
+
+extern
+PVOID
+SpxAllocMem(
+ IN ULONG Size,
+ IN ULONG FileLine
+);
+
+extern
+VOID
+SpxTrackMemoryUsage(
+ IN PVOID pMem,
+ IN BOOLEAN Alloc,
+ IN ULONG FileLine
+);
+
+#else
+
+#define SpxAllocateMemory(Size) SpxAllocMem(Size)
+#define SpxTrackMemoryUsage(pMem, Alloc, FileLine)
+
+extern
+PVOID
+SpxAllocMem(
+ IN ULONG Size
+);
+
+#endif // TRACK_MEMORY_USAGE
+
+VOID
+SpxFreeMemory(
+ IN PVOID pBuf);
+
+#define SpxAllocateZeroedMemory(Size) SpxAllocateMemory((Size) | ZEROED_MEMORY_TAG)
+
+
+extern
+NTSTATUS
+SpxInitMemorySystem(
+ IN PDEVICE pSpxDevice);
+
+extern
+VOID
+SpxDeInitMemorySystem(
+ IN PDEVICE pSpxDevice);
+
+PVOID
+SpxBPAllocBlock(
+ IN BLKID BlockId);
+
+VOID
+SpxBPFreeBlock(
+ IN PVOID pBlock,
+ IN BLKID BlockId);
+
diff --git a/private/ntos/tdi/isn/spx/h/spxntdef.h b/private/ntos/tdi/isn/spx/h/spxntdef.h
new file mode 100644
index 000000000..60f9c9e54
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxntdef.h
@@ -0,0 +1,72 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxntdef.h
+
+Abstract:
+
+ Missing nt definitions in ntddk.h
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+NTSTATUS
+NTAPI
+NtCreateFile(
+ OUT PHANDLE FileHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN PLARGE_INTEGER AllocationSize OPTIONAL,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN PVOID EaBuffer OPTIONAL,
+ IN ULONG EaLength
+ );
+
+NTSTATUS
+NTAPI
+NtClose(
+ IN HANDLE Handle
+ );
+
+NTSTATUS
+NTAPI
+NtDeviceIoControlFile(
+ IN HANDLE FileHandle,
+ IN HANDLE Event OPTIONAL,
+ IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+ IN PVOID ApcContext OPTIONAL,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN ULONG IoControlCode,
+ IN PVOID InputBuffer OPTIONAL,
+ IN ULONG InputBufferLength,
+ OUT PVOID OutputBuffer OPTIONAL,
+ IN ULONG OutputBufferLength
+ );
+
+NTSTATUS
+NTAPI
+NtWaitForSingleObject(
+ IN HANDLE Handle,
+ IN BOOLEAN Alertable,
+ IN PLARGE_INTEGER Timeout OPTIONAL
+ );
+
+
diff --git a/private/ntos/tdi/isn/spx/h/spxpkt.h b/private/ntos/tdi/isn/spx/h/spxpkt.h
new file mode 100644
index 000000000..b643ed95b
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxpkt.h
@@ -0,0 +1,466 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxpkt.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+// Use our own NDIS packets
+#define SPX_OWN_PACKETS 1
+
+// Offsets into the IPX header
+#define IPX_HDRSIZE 30 // Size of the IPX header
+#define IPX_CHECKSUM 0 // Checksum
+#define IPX_LENGTH 2 // Length
+#define IPX_XPORTCTL 4 // Transport Control
+#define IPX_PKTTYPE 5 // Packet Type
+#define IPX_DESTADDR 6 // Dest. Address (Total)
+#define IPX_DESTNET 6 // Dest. Network Address
+#define IPX_DESTNODE 10 // Dest. Node Address
+#define IPX_DESTSOCK 16 // Dest. Socket Number
+#define IPX_SRCADDR 18 // Source Address (Total)
+#define IPX_SRCNET 18 // Source Network Address
+#define IPX_SRCNODE 22 // Source Node Address
+#define IPX_SRCSOCK 28 // Source Socket Number
+
+#define IPX_NET_LEN 4
+#define IPX_NODE_LEN 6
+
+
+#include <packon.h>
+
+// Definition of the IPX/SPX header.
+typedef struct _IPXSPX_HEADER
+{
+ USHORT hdr_CheckSum;
+ USHORT hdr_PktLen;
+ UCHAR hdr_XportCtrl;
+ UCHAR hdr_PktType;
+ UCHAR hdr_DestNet[4];
+ UCHAR hdr_DestNode[6];
+ USHORT hdr_DestSkt;
+ UCHAR hdr_SrcNet[4];
+ UCHAR hdr_SrcNode[6];
+ USHORT hdr_SrcSkt;
+
+ // SPX Header Elements
+ UCHAR hdr_ConnCtrl;
+ UCHAR hdr_DataType;
+ USHORT hdr_SrcConnId;
+ USHORT hdr_DestConnId;
+ USHORT hdr_SeqNum;
+ USHORT hdr_AckNum;
+ USHORT hdr_AllocNum;
+
+ // For non-CR SPXII packets only
+ USHORT hdr_NegSize;
+
+} IPXSPX_HDR, *PIPXSPX_HDR;
+
+#include <packoff.h>
+
+// NDIS Packet size
+#define NDIS_PACKET_SIZE 48
+
+// Minimum header size (doesnt include neg size)
+#define MIN_IPXSPX_HDRSIZE (sizeof(IPXSPX_HDR) - sizeof(USHORT))
+#define MIN_IPXSPX2_HDRSIZE sizeof(IPXSPX_HDR)
+#define SPX_CR_PKTLEN 42
+
+// SPX packet type
+#define SPX_PKT_TYPE 0x5
+
+// Connection control fields
+#define SPX_CC_XHD 0x01
+#define SPX_CC_RES1 0x02
+#define SPX_CC_NEG 0x04
+#define SPX_CC_SPX2 0x08
+#define SPX_CC_EOM 0x10
+#define SPX_CC_ATN 0x20
+#define SPX_CC_ACK 0x40
+#define SPX_CC_SYS 0x80
+
+#define SPX_CC_CR (SPX_CC_ACK | SPX_CC_SYS)
+
+// Data stream types
+#define SPX2_DT_ORDREL 0xFD
+#define SPX2_DT_IDISC 0xFE
+#define SPX2_DT_IDISC_ACK 0xFF
+
+// Negotiation size
+#define SPX_MAX_PACKET 576
+#define SPX_NEG_MIN SPX_MAX_PACKET
+#define SPX_NEG_MAX 65535
+
+// No packet references connection. But if the sends are being aborted, and
+// the packet happens to be owned by ipx at the time, the pkt is dequeued from
+// conn, the ABORT flag is set and conn is referenced for packet.
+//
+// Send packet states
+// ABORT : Used for aborted packet. Calls AbortSendPkt().
+// IPXOWNS : Currently owned by ipx
+// FREEDATA: Frees the data associated with second ndis buffer desc
+// ACKREQ : Only for sequenced packets. Set by retry timer in packets it wants
+// resent (1 for spx1, all pending for spx2) with ack bit set.
+// DESTROY : Only for non-sequenced packets, dequeue packet from list and free.
+// REQ : For both seq/non-seq. A request is associated with the packet
+// SEQ : Packet is a sequenced packet.
+// LASTPKT : Packet is last packet comprising the request, if acked req is done.
+// EOM : Send EOM with the last packet for this request
+// ACKEDPKT: Send completion must only deref req with pkt and complete if zero.
+//
+
+#define SPX_SENDPKT_IDLE 0
+#define SPX_SENDPKT_ABORT 0x0002
+#define SPX_SENDPKT_IPXOWNS 0x0004
+#define SPX_SENDPKT_FREEDATA 0x0008
+#define SPX_SENDPKT_ACKREQ 0x0010
+#define SPX_SENDPKT_DESTROY 0x0020
+#define SPX_SENDPKT_REQ 0x0040
+#define SPX_SENDPKT_SEQ 0x0080
+#define SPX_SENDPKT_LASTPKT 0x0100
+#define SPX_SENDPKT_ACKEDPKT 0x0200
+#define SPX_SENDPKT_EOM 0x0400
+#define SPX_SENDPKT_REXMIT 0x0800
+
+// Packet types
+#define SPX_TYPE_CR 0x01
+#define SPX_TYPE_CRACK 0x02
+#define SPX_TYPE_SN 0x03
+#define SPX_TYPE_SNACK 0x04
+#define SPX_TYPE_SS 0x05
+#define SPX_TYPE_SSACK 0x06
+#define SPX_TYPE_RR 0x07
+#define SPX_TYPE_RRACK 0x08
+#define SPX_TYPE_IDISC 0x09
+#define SPX_TYPE_IDISCACK 0x0a
+#define SPX_TYPE_ORDREL 0x0b
+#define SPX_TYPE_ORDRELACK 0x0c
+#define SPX_TYPE_DATA 0x0d
+#define SPX_TYPE_DATAACK 0x0e
+#define SPX_TYPE_DATANACK 0x0f
+#define SPX_TYPE_PROBE 0x10
+
+// Definition of the protocol reserved field of a send packet.
+// BUGBUG: Make Len/HdrLen USHORTS, move to the end before the
+// sr_SentTime so we dont use padding space.
+typedef struct _SPX_SEND_RESD
+{
+ UCHAR sr_Id; // Set to SPX
+ UCHAR sr_Type; // What kind of packet
+ USHORT sr_State; // State of send packet
+ PVOID sr_Reserved1; // Needed by IPX
+ PVOID sr_Reserved2; // Needed by IPX
+#if defined(_PNP_POWER)
+ PVOID sr_Reserved[SEND_RESERVED_COMMON_SIZE-2]; // needed by IPX for local target
+#endif _PNP_POWER
+ ULONG sr_Len; // Length of packet
+ ULONG sr_HdrLen; // Included header length
+
+ struct _SPX_SEND_RESD * sr_Next; // Points to next packet
+ // in send queue in conn.
+ PREQUEST sr_Request; // request associated
+ ULONG sr_Offset; // Offset in mdl for sends
+
+#ifndef SPX_OWN_PACKETS
+ PVOID sr_FreePtr; // Ptr to use in free chunk
+#endif
+
+ struct _SPX_CONN_FILE * sr_ConnFile; // that this send is on
+ USHORT sr_SeqNum; // Seq num for seq pkts
+
+ // Quad word aligned.
+ LARGE_INTEGER sr_SentTime; // Time packet was sent
+ // Only valid for data pkt
+ // with ACKREQ set.
+
+} SPX_SEND_RESD, *PSPX_SEND_RESD;
+
+
+
+// Recv packet states
+#define SPX_RECVPKT_IDLE 0
+#define SPX_RECVPKT_BUFFERING 0x0001
+#define SPX_RECVPKT_IDISC 0x0002
+#define SPX_RECVPKT_ORD_DISC 0x0004
+#define SPX_RECVPKT_INDICATED 0x0008
+#define SPX_RECVPKT_SENDACK 0x0010
+#define SPX_RECVPKT_EOM 0x0020
+#define SPX_RECVPKT_IMMEDACK 0x0040
+
+#define SPX_RECVPKT_DISCMASK (SPX_RECVPKT_ORD_DISC | SPX_RECVPKT_IDISC)
+
+// Definition of the protocol reserved field of a receive packet.
+typedef struct _SPX_RECV_RESD
+{
+ UCHAR rr_Id; // Set to SPX
+ USHORT rr_State; // State of receive packet
+ struct _SPX_RECV_RESD * rr_Next; // Points to next packet
+ ULONG rr_DataOffset; // To indicate/copy from
+
+#ifndef SPX_OWN_PACKETS
+ PVOID rr_FreePtr; // Ptr to use in free chunk
+#endif
+
+#if DBG
+ USHORT rr_SeqNum; // Seq num of packet
+#endif
+
+ PREQUEST rr_Request; // request waiting on xfer
+ struct _SPX_CONN_FILE * rr_ConnFile; // that this recv is on
+
+} SPX_RECV_RESD, *PSPX_RECV_RESD;
+
+
+// Destination built as an assign of 3 ulongs.
+#define SpxBuildIpxHdr(pIpxSpxHdr, PktLen, pRemAddr, SrcSkt) \
+ { \
+ PBYTE pDestIpxAddr = (PBYTE)pIpxSpxHdr->hdr_DestNet; \
+ (pIpxSpxHdr)->hdr_CheckSum = 0xFFFF; \
+ PUTSHORT2SHORT((PUSHORT)(&(pIpxSpxHdr)->hdr_PktLen), (PktLen)); \
+ (pIpxSpxHdr)->hdr_XportCtrl = 0; \
+ (pIpxSpxHdr)->hdr_PktType = SPX_PKT_TYPE; \
+ *((UNALIGNED ULONG *)pDestIpxAddr) = \
+ *((UNALIGNED ULONG *)pRemAddr); \
+ *((UNALIGNED ULONG *)(pDestIpxAddr+4)) = \
+ *((UNALIGNED ULONG *)(pRemAddr+4)); \
+ *((UNALIGNED ULONG *)(pDestIpxAddr+8)) = \
+ *((UNALIGNED ULONG *)(pRemAddr+8)); \
+ *((UNALIGNED ULONG *)((pIpxSpxHdr)->hdr_SrcNet))= \
+ *((UNALIGNED ULONG *)(SpxDevice->dev_Network)); \
+ *((UNALIGNED ULONG *)((pIpxSpxHdr)->hdr_SrcNode)) = \
+ *((UNALIGNED ULONG *)SpxDevice->dev_Node); \
+ *((UNALIGNED USHORT *)((pIpxSpxHdr)->hdr_SrcNode+4)) = \
+ *((UNALIGNED USHORT *)(SpxDevice->dev_Node+4)); \
+ *((UNALIGNED USHORT *)&((pIpxSpxHdr)->hdr_SrcSkt)) = \
+ SrcSkt; \
+ }
+
+#define SpxCopyIpxAddr(pIpxSpxHdr, pDestIpxAddr) \
+ { \
+ PBYTE pRemAddr = (PBYTE)pIpxSpxHdr->hdr_SrcNet; \
+ *((UNALIGNED ULONG *)pDestIpxAddr) = \
+ *((UNALIGNED ULONG *)pRemAddr); \
+ *((UNALIGNED ULONG *)(pDestIpxAddr+4)) = \
+ *((UNALIGNED ULONG *)(pRemAddr+4)); \
+ *((UNALIGNED ULONG *)(pDestIpxAddr+8)) = \
+ *((UNALIGNED ULONG *)(pRemAddr+8)); \
+ }
+
+#ifndef SPX_OWN_PACKETS
+#define SpxAllocSendPacket(_Device,_SendPacket,_Status) \
+ { \
+ NDIS_HANDLE _Handle; \
+ NdisAllocatePacketPool(_Status, &(_Handle),1,sizeof(SPX_SEND_RESD));\
+ if (*(_Status) == NDIS_STATUS_SUCCESS) { \
+ NdisAllocatePacket(_Status, &(_SendPacket), (_Handle)); \
+ SEND_RESD(_SendPacket)->sr_PoolHandle = (_Handle); \
+ } \
+ }
+
+#define SpxAllocRecvPacket(_Device,_RecvPacket,_Status) \
+ { \
+ NDIS_HANDLE _Handle; \
+ NdisAllocatePacketPool(_Status, &(_Handle),1,sizeof(SPX_RECV_RESD));\
+ if (*(_Status) == NDIS_STATUS_SUCCESS) { \
+ NdisAllocatePacket(_Status, &(_RecvPacket), (_Handle)); \
+ RECV_RESD(_RecvPacket)->sr_PoolHandle = (_Handle); \
+ } \
+ }
+
+#define SpxFreeSendPacket(_Device,_Packet) \
+ { \
+ NDIS_HANDLE _Handle = SEND_RESD(_Packet)->sr_PoolHandle; \
+ NdisFreePacket(_Packet); \
+ NdisFreePacketPool(_Handle); \
+ }
+
+#define SpxFreeRecvPacket(_Device,_Packet) \
+ { \
+ NDIS_HANDLE _Handle = RECV_RESD(_Packet)->rr_PoolHandle; \
+ NdisFreePacket(_Packet); \
+ NdisFreePacketPool(_Handle); \
+ }
+
+#define SpxReInitSendPacket(_Packet)
+ {
+ NDIS_HANDLE _Handle = SEND_RESD(_Packet)->sr_PoolHandle;
+ NdisReInitializePacket(_Packet);
+ SEND_RESD(_Packet)->sr_PoolHandle = (_Handle);
+ }
+
+#define SpxReInitRecvPacket(_Packet)
+ {
+ NDIS_HANDLE _Handle = RECV_RESD(_Packet)->rr_PoolHandle;
+ NdisReInitializePacket(_Packet);
+ RECV_RESD(_Packet)->rr_PoolHandle = (_Handle);
+ }
+
+#define SEND_RESD(_Packet) ((PSPX_SEND_RESD)((_Packet)->ProtocolReserved))
+#define RECV_RESD(_Packet) ((PSPX_RECV_RESD)((_Packet)->ProtocolReserved))
+
+#else
+
+#define SpxAllocSendPacket(_Device, _SendPacket, _Status) \
+ { \
+ if (*(_SendPacket) = SpxBPAllocBlock(BLKID_NDISSEND)) \
+ *(_Status) = NDIS_STATUS_SUCCESS; \
+ else \
+ *(_Status) = NDIS_STATUS_RESOURCES; \
+ }
+
+#define SpxAllocRecvPacket(_Device,_RecvPacket,_Status) \
+ { \
+ if (*(_RecvPacket) = SpxBPAllocBlock(BLKID_NDISRECV)) \
+ *(_Status) = NDIS_STATUS_SUCCESS; \
+ else \
+ *(_Status) = NDIS_STATUS_RESOURCES; \
+ }
+
+#define SpxFreeSendPacket(_Device,_Packet) \
+ { \
+ SpxBPFreeBlock(_Packet, BLKID_NDISSEND); \
+ }
+
+#define SpxFreeRecvPacket(_Device,_Packet) \
+ { \
+ SpxBPFreeBlock(_Packet, BLKID_NDISRECV); \
+ }
+
+#define SpxReInitSendPacket(_Packet) \
+ { \
+ }
+
+#define SpxReInitRecvPacket(_Packet) \
+ { \
+ }
+
+#define SEND_RESD(_Packet) ((PSPX_SEND_RESD)((_Packet)->ProtocolReserved))
+#define RECV_RESD(_Packet) ((PSPX_RECV_RESD)((_Packet)->ProtocolReserved))
+
+#endif
+
+
+//
+// Routine Prototypes
+//
+
+VOID
+SpxPktBuildCr(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ IN struct _SPX_ADDR * pSpxAddr,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fSpx2);
+
+VOID
+SpxPktBuildCrAck(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ IN struct _SPX_ADDR * pSpxAddr,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fNeg,
+ IN BOOLEAN fSpx2);
+
+VOID
+SpxPktBuildSn(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State);
+
+VOID
+SpxPktBuildSs(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State);
+
+VOID
+SpxPktBuildSsAck(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State);
+
+VOID
+SpxPktBuildSnAck(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State);
+
+VOID
+SpxPktBuildRr(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT SeqNum,
+ IN USHORT State);
+
+VOID
+SpxPktBuildRrAck(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN USHORT MaxPktSize);
+
+VOID
+SpxPktBuildProbe(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fSpx2);
+
+VOID
+SpxPktBuildData(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN USHORT Length);
+
+VOID
+SpxCopyBufferChain(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_BUFFER * TargetChain,
+ IN NDIS_HANDLE PoolHandle,
+ IN PNDIS_BUFFER SourceChain,
+ IN UINT Offset,
+ IN UINT Length
+ );
+
+VOID
+SpxPktBuildAck(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fBuildNack,
+ IN USHORT NumToResend);
+
+VOID
+SpxPktBuildDisc(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ IN PREQUEST pRequest,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN UCHAR DataType);
+
+VOID
+SpxPktRecvRelease(
+ IN PNDIS_PACKET pPkt);
+
+VOID
+SpxPktSendRelease(
+ IN PNDIS_PACKET pPkt);
diff --git a/private/ntos/tdi/isn/spx/h/spxquery.h b/private/ntos/tdi/isn/spx/h/spxquery.h
new file mode 100644
index 000000000..68e0a1ca8
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxquery.h
@@ -0,0 +1,54 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxquery.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#define SPX_TDI_PROVIDERINFO_VERSION 0x0001
+#define SPX_PINFOSENDSIZE 0xFFFFFFFF
+#define SPX_PINFOMINMAXLOOKAHEAD 128
+
+//
+// Bug #14498: Indicate to AFD that we are capable of orderly disc so AFD can follow
+// these semantics.
+// In order to have SPXI connections work correctly, we OR this bit in at query time.
+// (see SpxTdiQueryInformation)
+//
+#define SPX_PINFOSERVICEFLAGS ( TDI_SERVICE_CONNECTION_MODE | \
+ TDI_SERVICE_DELAYED_ACCEPTANCE | \
+ TDI_SERVICE_MESSAGE_MODE | \
+ TDI_SERVICE_ERROR_FREE_DELIVERY) // | \
+ // TDI_SERVICE_ORDERLY_RELEASE )
+
+VOID
+SpxQueryInitProviderInfo(
+ PTDI_PROVIDER_INFO ProviderInfo);
+
+NTSTATUS
+SpxTdiQueryInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request);
+
+NTSTATUS
+SpxTdiSetInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request);
+
diff --git a/private/ntos/tdi/isn/spx/h/spxrecv.h b/private/ntos/tdi/isn/spx/h/spxrecv.h
new file mode 100644
index 000000000..ca1572c64
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxrecv.h
@@ -0,0 +1,91 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxrecv.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+BOOLEAN
+SpxReceive(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN ULONG FwdAdapterCtx,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize,
+ IN PMDL pMdl);
+
+VOID
+SpxTransferDataComplete(
+ IN PNDIS_PACKET pNdisPkt,
+ IN NDIS_STATUS NdisStatus,
+ IN UINT BytesTransferred);
+
+VOID
+SpxReceiveComplete(
+ IN USHORT NicId);
+
+VOID
+SpxRecvDataPacket(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize);
+
+VOID
+SpxRecvDiscPacket(
+ IN PUCHAR LookaheadBuffer,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN UINT LookaheadSize);
+
+VOID
+SpxRecvSysPacket(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize);
+
+VOID
+SpxRecvFlushBytes(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN ULONG BytesToFlush,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+SpxRecvProcessPkts(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn);
+
+BOOLEAN
+SpxRecvIndicatePendingData(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn);
+
diff --git a/private/ntos/tdi/isn/spx/h/spxreg.h b/private/ntos/tdi/isn/spx/h/spxreg.h
new file mode 100644
index 000000000..4e0cb469b
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxreg.h
@@ -0,0 +1,65 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxreg.h
+
+Abstract:
+
+ Private include file for the ISN SPX module.
+ file defines all constants and structures necessary for support of
+ the dynamic configuration of ST.
+
+Revision History:
+
+--*/
+
+#define HALFSEC_TO_MS_FACTOR 500
+#define IPX_REG_PATH L"NwlnkIpx\\Linkage"
+
+// These are used to index into the Parameters array in CONFIG.
+#define CONFIG_CONNECTION_COUNT 0
+#define CONFIG_CONNECTION_TIMEOUT 1
+#define CONFIG_INIT_PACKETS 2
+#define CONFIG_MAX_PACKETS 3
+#define CONFIG_INITIAL_RETRANSMIT_TIMEOUT 4
+#define CONFIG_KEEPALIVE_COUNT 5
+#define CONFIG_KEEPALIVE_TIMEOUT 6
+#define CONFIG_WINDOW_SIZE 7
+#define CONFIG_SOCKET_RANGE_START 8
+#define CONFIG_SOCKET_RANGE_END 9
+#define CONFIG_SOCKET_UNIQUENESS 10
+#define CONFIG_MAX_PACKET_SIZE 11
+#define CONFIG_REXMIT_COUNT 12
+
+// Hidden parameters
+#define CONFIG_DISABLE_SPX2 13
+#define CONFIG_ROUTER_MTU 14
+#define CONFIG_BACKCOMP_SPX 15
+
+#define CONFIG_PARAMETERS 16
+
+// Main configuration structure.
+typedef struct _CONFIG {
+
+ ULONG cf_Parameters[CONFIG_PARAMETERS]; // index defined above
+ NDIS_STRING cf_DeviceName; // device name exported
+ PWSTR cf_RegistryPathBuffer; // path to config info
+
+} CONFIG, * PCONFIG;
+
+
+#define PARAM(x) (SpxDevice->dev_ConfigInfo->cf_Parameters[(x)])
+
+
+NTSTATUS
+SpxInitGetConfiguration (
+ IN PUNICODE_STRING RegistryPath,
+ OUT PCONFIG * ConfigPtr);
+
+VOID
+SpxInitFreeConfiguration (
+ IN PCONFIG Config);
+
diff --git a/private/ntos/tdi/isn/spx/h/spxsend.h b/private/ntos/tdi/isn/spx/h/spxsend.h
new file mode 100644
index 000000000..40ef810ea
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxsend.h
@@ -0,0 +1,34 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxsend.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+VOID
+SpxSendComplete(
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus);
+
+VOID
+SpxSendPktRelease(
+ IN PNDIS_PACKET pPkt,
+ IN UINT BufCount);
diff --git a/private/ntos/tdi/isn/spx/h/spxtimer.h b/private/ntos/tdi/isn/spx/h/spxtimer.h
new file mode 100644
index 000000000..225037bd2
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxtimer.h
@@ -0,0 +1,101 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ spxtimer.h
+
+Abstract:
+
+ This module contains routines to schedule timer events.
+
+Author:
+
+ Jameel Hyder (jameelh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version
+
+Notes: Tab stop: 4
+--*/
+
+#define TIMER_DONT_REQUEUE 0
+#define TIMER_REQUEUE_CUR_VALUE 1
+
+typedef ULONG (*TIMER_ROUTINE)(IN PVOID Context, IN BOOLEAN TimerShuttingDown);
+
+extern
+NTSTATUS
+SpxTimerInit(
+ VOID);
+
+extern
+ULONG
+SpxTimerScheduleEvent(
+ IN TIMER_ROUTINE Worker, // Routine to invoke when time expires
+ IN ULONG DeltaTime, // Schedule after this much time
+ IN PVOID pContext); // Context to pass to the routine
+
+extern
+VOID
+SpxTimerFlushAndStop(
+ VOID);
+
+extern
+BOOLEAN
+SpxTimerCancelEvent(
+ IN ULONG TimerId,
+ IN BOOLEAN ReEnqueue);
+
+#define TMR_SIGNATURE *(PULONG)"ATMR"
+#if DBG
+#define VALID_TMR(pTmr) (((pTmr) != NULL) && \
+ ((pTmr)->tmr_Signature == TMR_SIGNATURE))
+#else
+#define VALID_TMR(pTmr) ((pTmr) != NULL)
+#endif
+typedef struct _TimerList
+{
+#if DBG
+ ULONG tmr_Signature;
+#endif
+ struct _TimerList * tmr_Next; // Link to next
+ struct _TimerList ** tmr_Prev; // Link to prev
+ struct _TimerList * tmr_Overflow; // Link to overflow entry in hash table
+ ULONG tmr_AbsTime; // Absolute time, for re-enqueue
+ ULONG tmr_RelDelta; // Relative to the previous entry
+ ULONG tmr_Id; // Unique Id for this event
+ BOOLEAN tmr_Cancelled; // Was the timer cancelled?
+ TIMER_ROUTINE tmr_Worker; // Real Worker
+ PVOID tmr_Context; // Real context
+} TIMERLIST, *PTIMERLIST;
+
+
+#define SpxGetCurrentTime() (SpxTimerCurrentTime/SPX_TIMER_FACTOR)
+#define SpxGetCurrentTick() SpxTimerCurrentTime
+
+// Keep this at a ONE second level.
+#define SPX_TIMER_FACTOR 10 // i.e. 10 ticks per second
+#define SPX_MS_TO_TICKS 100 // Divide ms by this to get ticks
+#define SPX_TIMER_TICK -1000000L // 100ms in 100ns units
+#define SPX_TIMER_WAIT 50 // Time to wait in FlushAndStop in ms
+#define TIMER_HASH_TABLE 32
+
+VOID
+spxTimerDpcRoutine(
+ IN PKDPC pKDpc,
+ IN PVOID pContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2);
+
+VOID
+spxTimerWorker(
+ IN PTIMERLIST pList);
+
+VOID
+spxTimerEnqueue(
+ PTIMERLIST pListNew);
+
+
diff --git a/private/ntos/tdi/isn/spx/h/spxutils.h b/private/ntos/tdi/isn/spx/h/spxutils.h
new file mode 100644
index 000000000..074a1649b
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxutils.h
@@ -0,0 +1,178 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxutils.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+// For PROTO_SPX, i'd return a device name from the dll of the form
+// \Device\NwlnkSpx\SpxStream (for SOCK_STREAM) or
+// \Device\NwlnkSpx\Spx (for SOCK_SEQPKT)
+//
+// and for PROTO_SPXII (the more common case we hope, even if
+// internally we degrade to SPX1 cause of the remote client's
+// limitations)
+// \Device\NwlnkSpx\Stream (for SOCK_STREAM) or
+// \Device\NwlnkSpx (for SOCK_SEQPKT)
+
+#define SOCKET1STREAM_SUFFIX L"\\SpxStream"
+#define SOCKET1_SUFFIX L"\\Spx"
+#define SOCKET2STREAM_SUFFIX L"\\Stream"
+#define SOCKET1_TYPE_SEQPKT 0
+#define SOCKET2_TYPE_SEQPKT 1
+#define SOCKET1_TYPE_STREAM 2
+#define SOCKET2_TYPE_STREAM 3
+
+#define IN_RANGE(_S, _RangeStart, _RangeEnd) \
+ ((_S >= _RangeStart) && (_S <= _RangeEnd))
+
+
+//
+// The following macros deal with on-the-wire integer and long values
+//
+// On the wire format is big-endian i.e. a long value of 0x01020304 is
+// represented as 01 02 03 04. Similarly an int value of 0x0102 is
+// represented as 01 02.
+//
+// The host format is not assumed since it will vary from processor to
+// processor.
+//
+
+// Get a byte from on-the-wire format to a short in the host format
+#define GETBYTE2SHORT(DstPtr, SrcPtr) \
+ *(PUSHORT)(DstPtr) = (USHORT) (*(PBYTE)(SrcPtr))
+
+// Get a byte from on-the-wire format to a short in the host format
+#define GETBYTE2ULONG(DstPtr, SrcPtr) \
+ *(PULONG)(DstPtr) = (ULONG) (*(PBYTE)(SrcPtr))
+
+// Get a short from on-the-wire format to a dword in the host format
+#define GETSHORT2ULONG(DstPtr, SrcPtr) \
+ *(PULONG)(DstPtr) = ((*((PBYTE)(SrcPtr)+0) << 8) + \
+ (*((PBYTE)(SrcPtr)+1) ))
+
+// Get a short from on-the-wire format to a dword in the host format
+#define GETSHORT2SHORT(DstPtr, SrcPtr) \
+ *(PUSHORT)(DstPtr) = ((*((PBYTE)(SrcPtr)+0) << 8) + \
+ (*((PBYTE)(SrcPtr)+1) ))
+
+// Get a dword from on-the-wire format to a dword in the host format
+#define GETULONG2ULONG(DstPtr, SrcPtr) \
+ *(PULONG)(DstPtr) = ((*((PBYTE)(SrcPtr)+0) << 24) + \
+ (*((PBYTE)(SrcPtr)+1) << 16) + \
+ (*((PBYTE)(SrcPtr)+2) << 8) + \
+ (*((PBYTE)(SrcPtr)+3) ))
+
+// Get a dword from on-the-wire format to a dword in the same format but
+// also watch out for alignment
+#define GETULONG2ULONG_NOCONV(DstPtr, SrcPtr) \
+ *((PBYTE)(DstPtr)+0) = *((PBYTE)(SrcPtr)+0); \
+ *((PBYTE)(DstPtr)+1) = *((PBYTE)(SrcPtr)+1); \
+ *((PBYTE)(DstPtr)+2) = *((PBYTE)(SrcPtr)+2); \
+ *((PBYTE)(DstPtr)+3) = *((PBYTE)(SrcPtr)+3);
+
+// Put a dword from the host format to a short to on-the-wire format
+#define PUTBYTE2BYTE(DstPtr, Src) \
+ *((PBYTE)(DstPtr)) = (BYTE)(Src)
+
+// Put a dword from the host format to a short to on-the-wire format
+#define PUTSHORT2BYTE(DstPtr, Src) \
+ *((PBYTE)(DstPtr)) = ((USHORT)(Src) % 256)
+
+// Put a dword from the host format to a short to on-the-wire format
+#define PUTSHORT2SHORT(DstPtr, Src) \
+ *((PBYTE)(DstPtr)+0) = (BYTE) ((USHORT)(Src) >> 8), \
+ *((PBYTE)(DstPtr)+1) = (BYTE)(Src)
+
+// Put a dword from the host format to a byte to on-the-wire format
+#define PUTULONG2BYTE(DstPtr, Src) \
+ *(PBYTE)(DstPtr) = (BYTE)(Src)
+
+// Put a dword from the host format to a short to on-the-wire format
+#define PUTULONG2SHORT(DstPtr, Src) \
+ *((PBYTE)(DstPtr)+0) = (BYTE) ((ULONG)(Src) >> 8), \
+ *((PBYTE)(DstPtr)+1) = (BYTE) (Src)
+
+// Put a dword from the host format to a dword to on-the-wire format
+#define PUTULONG2ULONG(DstPtr, Src) \
+ *((PBYTE)(DstPtr)+0) = (BYTE) ((ULONG)(Src) >> 24), \
+ *((PBYTE)(DstPtr)+1) = (BYTE) ((ULONG)(Src) >> 16), \
+ *((PBYTE)(DstPtr)+2) = (BYTE) ((ULONG)(Src) >> 8), \
+ *((PBYTE)(DstPtr)+3) = (BYTE) (Src)
+
+// Put a BYTE[4] array into another BYTE4 array.
+#define PUTBYTE42BYTE4(DstPtr, SrcPtr) \
+ *((PBYTE)(DstPtr)+0) = *((PBYTE)(SrcPtr)+0), \
+ *((PBYTE)(DstPtr)+1) = *((PBYTE)(SrcPtr)+1), \
+ *((PBYTE)(DstPtr)+2) = *((PBYTE)(SrcPtr)+2), \
+ *((PBYTE)(DstPtr)+3) = *((PBYTE)(SrcPtr)+3)
+
+// MIN/MAX macros
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+
+
+
+// Exported prototypes
+
+UINT
+SpxUtilWstrLength(
+ IN PWSTR Wstr);
+
+LONG
+SpxRandomNumber(
+ VOID);
+
+NTSTATUS
+SpxUtilGetSocketType(
+ PUNICODE_STRING RemainingFileName,
+ PBYTE SocketType);
+
+VOID
+SpxSleep(
+ IN ULONG TimeInMs);
+
+ULONG
+SpxBuildTdiAddress(
+ IN PVOID AddressBuffer,
+ IN ULONG AddressBufferLength,
+ IN UCHAR Network[4],
+ IN UCHAR Node[6],
+ IN USHORT Socket);
+
+VOID
+SpxBuildTdiAddressFromIpxAddr(
+ IN PVOID AddressBuffer,
+ IN PBYTE pIpxAddr);
+
+TDI_ADDRESS_IPX UNALIGNED *
+SpxParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress);
+
+BOOLEAN
+SpxValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength);
+
+VOID
+SpxCalculateNewT1(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ IN int NewT1);
diff --git a/private/ntos/tdi/isn/spx/mp/makefile b/private/ntos/tdi/isn/spx/mp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/mp/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isn/spx/mp/sources b/private/ntos/tdi/isn/spx/mp/sources
new file mode 100644
index 000000000..dc48d81bb
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/mp/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+NT_UP=0
+
+TARGETPATH=\nt\public\sdk\lib
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/isn/spx/nwlnkspx.rc b/private/ntos/tdi/isn/spx/nwlnkspx.rc
new file mode 100644
index 000000000..02175f21d
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/nwlnkspx.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "NWLINK2 SPX Protocol Driver"
+#define VER_INTERNALNAME_STR "nwlnkspx.sys"
+#define VER_ORIGINALFILENAME_STR "nwlnkspx.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/tdi/isn/spx/precomp.h b/private/ntos/tdi/isn/spx/precomp.h
new file mode 100644
index 000000000..d227d02f9
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/precomp.h
@@ -0,0 +1 @@
+#include "isnspx.h"
diff --git a/private/ntos/tdi/isn/spx/sources.inc b/private/ntos/tdi/isn/spx/sources.inc
new file mode 100644
index 000000000..419f580f1
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/sources.inc
@@ -0,0 +1,65 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=nwlnkspx
+
+TARGETNAME=nwlnkspx
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\tdi.lib \
+ $(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..;..\h;..\..\inc;..\..\..\..\inc;..\..\..\..\..\inc
+
+C_DEFINES=$(C_DEFINES) -D_NTDRIVER_ -D_PNP_POWER=1
+
+!IFDEF BUILD_FOR_3_51
+C_DEFINES=$(C_DEFINES) -D_NTIFS_
+!ENDIF
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=..\spxdrvr.c \
+ ..\spxreg.c \
+ ..\spxdev.c \
+ ..\spxbind.c \
+ ..\spxaddr.c \
+ ..\spxconn.c \
+ ..\spxcutil.c \
+ ..\spxcpkt.c \
+ ..\spxrecv.c \
+ ..\spxsend.c \
+ ..\spxquery.c \
+ ..\spxutils.c \
+ ..\spxmem.c \
+ ..\spxtimer.c \
+ ..\spxpkt.c \
+ ..\globals.c \
+ ..\spxerror.c \
+ ..\nwlnkspx.rc
+
+PRECOMPILED_INCLUDE=..\precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
diff --git a/private/ntos/tdi/isn/spx/spxaddr.c b/private/ntos/tdi/isn/spx/spxaddr.c
new file mode 100644
index 000000000..e9e85dc5c
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxaddr.c
@@ -0,0 +1,1729 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxaddr.c
+
+Abstract:
+
+ This module contains code which implements the ADDRESS object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport address objects.
+
+Author:
+
+ Adam Barr (adamba ) Original Version
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text( PAGE, SpxAddrFileCreate)
+#pragma alloc_text( PAGE, SpxAddrFileClose)
+#endif
+
+// Define module number for event logging entries
+#define FILENUM SPXADDR
+
+// Map all generic accesses to the same one.
+static GENERIC_MAPPING AddressGenericMapping =
+ { READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL };
+
+#define REORDER(_Socket) ((((_Socket) & 0xff00) >> 8) | (((_Socket) & 0x00ff) << 8))
+
+
+
+
+NTSTATUS
+SpxAddrOpen(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens a file that points to an existing address object, or, if
+ the object doesn't exist, creates it (note that creation of the address
+ object includes registering the address, and may take many seconds to
+ complete, depending upon system configuration).
+
+ If the address already exists, and it has an ACL associated with it, the
+ ACL is checked for access rights before allowing creation of the address.
+
+Arguments:
+
+ DeviceObject - pointer to the device object describing the ST transport.
+
+ Request - a pointer to the request used for the creation of the address.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PSPX_ADDR pAddr;
+ PSPX_ADDR_FILE pAddrFile;
+ PFILE_FULL_EA_INFORMATION ea;
+ TRANSPORT_ADDRESS UNALIGNED *name;
+ TA_ADDRESS UNALIGNED * AddressName;
+ USHORT Socket, hostSocket;
+ ULONG DesiredShareAccess;
+ CTELockHandle LockHandle, LockHandleAddr;
+ PACCESS_STATE AccessState;
+ ACCESS_MASK GrantedAccess;
+ BOOLEAN AccessAllowed;
+ int i;
+ BOOLEAN found = FALSE;
+
+#ifdef ISN_NT
+ PIRP Irp = (PIRP)Request;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+#endif
+
+
+ // The network name is in the EA, passed in the request.
+ ea = OPEN_REQUEST_EA_INFORMATION(Request);
+ if (ea == NULL)
+ {
+ DBGPRINT(TDI, ERR,
+ ("OpenAddress: REQUEST %lx has no EA\n", Request));
+
+ return STATUS_NONEXISTENT_EA_ENTRY;
+ }
+
+ // this may be a valid name; parse the name from the EA and use it if OK.
+ name = (PTRANSPORT_ADDRESS)&ea->EaName[ea->EaNameLength+1];
+ AddressName = (PTA_ADDRESS)&name->Address[0];
+
+ // The name can be passed with multiple entries; we'll take and use only
+ // the first one of type IPX.
+ for (i=0;i<name->TAAddressCount;i++)
+ {
+ if (AddressName->AddressType == TDI_ADDRESS_TYPE_IPX)
+ {
+ if (AddressName->AddressLength >= sizeof(TDI_ADDRESS_IPX))
+ {
+ Socket =
+ ((TDI_ADDRESS_IPX UNALIGNED *)&AddressName->Address[0])->Socket;
+
+ GETSHORT2SHORT(&hostSocket, &Socket);
+
+ DBGPRINT(CREATE, DBG,
+ ("SpxAddrOpen: Creating socket %lx.h%lx\n",
+ Socket, hostSocket ));
+
+ found = TRUE;
+ }
+ break;
+
+ }
+ else
+ {
+
+ AddressName = (PTA_ADDRESS)(AddressName->Address +
+ AddressName->AddressLength);
+ }
+ }
+
+ if (!found)
+ {
+ DBGPRINT(TDI, ERR,
+ ("OpenAddress: REQUEST %lx has no IPX Address\n", Request));
+
+ return STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+#ifdef SOCKET_RANGE_OPEN_LIMITATION_REMOVED
+ // Is the socket in our range if its in the range 0x4000-0x7FFF
+ if (IN_RANGE(hostSocket, DYNSKT_RANGE_START, DYNSKT_RANGE_END))
+ {
+ if (!IN_RANGE(
+ hostSocket,
+ PARAM(CONFIG_SOCKET_RANGE_START),
+ PARAM(CONFIG_SOCKET_RANGE_END)))
+ {
+ return(STATUS_INVALID_ADDRESS);
+ }
+ }
+#endif
+
+ // get an address file structure to represent this address.
+ status = SpxAddrFileCreate(Device, Request, &pAddrFile);
+ if (!NT_SUCCESS(status))
+ return status;
+
+ // See if this address is already established. This call automatically
+ // increments the reference count on the address so that it won't disappear
+ // from underneath us after this call but before we have a chance to use it.
+ //
+ // To ensure that we don't create two address objects for the
+ // same address, we hold the device context addressResource until
+ // we have found the address or created a new one.
+ ExAcquireResourceExclusive (&Device->dev_AddrResource, TRUE);
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+
+ // We checkfor/create sockets within the critical section.
+ if (Socket == 0)
+ {
+ Socket = SpxAddrAssignSocket(Device);
+
+ if (Socket == 0)
+ {
+ DBGPRINT(ADDRESS, ERR,
+ ("OpenAddress, no unique socket found\n"));
+
+ CTEFreeLock (&Device->dev_Lock, LockHandle);
+ ExReleaseResource (&Device->dev_AddrResource);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ DBGPRINT(ADDRESS, INFO,
+ ("OpenAddress, assigned socket %lx\n", Socket));
+ }
+
+ pAddr = SpxAddrLookup(Device, Socket);
+
+ if (pAddr == NULL)
+ {
+ CTEFreeLock (&Device->dev_Lock, LockHandle);
+
+ // This address doesn't exist. Create it.
+ // registering it. It also puts a ref of type ADDR_FILE on address.
+ pAddr = SpxAddrCreate(
+ Device,
+ Socket);
+
+ if (pAddr != (PSPX_ADDR)NULL)
+ {
+#ifdef ISN_NT
+
+ // Initialize the shared access now. We use read access
+ // to control all access.
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ IoSetShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &pAddr->u.sa_ShareAccess);
+
+
+ // Assign the security descriptor (need to do this with
+ // the spinlock released because the descriptor is not
+ // mapped).
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ status = SeAssignSecurity(
+ NULL, // parent descriptor
+ AccessState->SecurityDescriptor,
+ &pAddr->sa_SecurityDescriptor,
+ FALSE, // is directory
+ &AccessState->SubjectSecurityContext,
+ &AddressGenericMapping,
+ NonPagedPool);
+
+ if (!NT_SUCCESS(status))
+ {
+ // Error, return status.
+ IoRemoveShareAccess (IrpSp->FileObject, &pAddr->u.sa_ShareAccess);
+ ExReleaseResource (&Device->dev_AddrResource);
+ SpxAddrDereference (pAddr, AREF_ADDR_FILE);
+
+ SpxAddrFileDestroy(pAddrFile);
+ return status;
+ }
+
+#endif
+
+ ExReleaseResource (&Device->dev_AddrResource);
+
+ // if the adapter isn't ready, we can't do any of this; get out
+#if defined(_PNP_POWER)
+ if (Device->dev_State != DEVICE_STATE_OPEN)
+#else
+ if (Device->dev_State == DEVICE_STATE_STOPPING)
+#endif _PNP_POWER
+ {
+ SpxAddrDereference (pAddr, AREF_ADDR_FILE);
+
+ SpxAddrFileDestroy(pAddrFile);
+ status = STATUS_DEVICE_NOT_READY;
+ }
+ else
+ {
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)pAddrFile;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+#ifdef ISN_NT
+ pAddrFile->saf_FileObject = IrpSp->FileObject;
+#endif
+ CTEGetLock (&pAddr->sa_Lock, &LockHandleAddr);
+ pAddrFile->saf_Addr = pAddr;
+ pAddrFile->saf_AddrLock = &pAddr->sa_Lock;
+
+ // Set flags appropriately, note spx/stream flags are set at this
+ // point.
+ pAddrFile->saf_Flags &= ~SPX_ADDRFILE_OPENING;
+ pAddrFile->saf_Flags |= SPX_ADDRFILE_OPEN;
+
+ // Queue in the address list, removed in destroy.
+ pAddrFile->saf_Next = pAddr->sa_AddrFileList;
+ pAddr->sa_AddrFileList = pAddrFile;
+
+ CTEFreeLock (&pAddr->sa_Lock, LockHandleAddr);
+ status = STATUS_SUCCESS;
+ }
+ }
+ else
+ {
+ ExReleaseResource (&Device->dev_AddrResource);
+
+ // If the address could not be created, and is not in the process of
+ // being created, then we can't open up an address.
+
+ SpxAddrFileDestroy(pAddrFile);
+ }
+ }
+ else
+ {
+ CTEFreeLock (&Device->dev_Lock, LockHandle);
+
+ DBGPRINT(ADDRESS, ERR,
+ ("Add to address %lx\n", pAddr));
+
+ // The address already exists. Check the ACL and see if we
+ // can access it. If so, simply use this address as our address.
+
+#ifdef ISN_NT
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ AccessAllowed = SeAccessCheck(
+ pAddr->sa_SecurityDescriptor,
+ &AccessState->SubjectSecurityContext,
+ FALSE, // tokens locked
+ IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
+ (ACCESS_MASK)0, // previously granted
+ NULL, // privileges
+ &AddressGenericMapping,
+ Irp->RequestorMode,
+ &GrantedAccess,
+ &status);
+
+#else // ISN_NT
+
+ AccessAllowed = TRUE;
+
+#endif // ISN_NT
+
+ if (!AccessAllowed)
+ {
+ ExReleaseResource (&Device->dev_AddrResource);
+ SpxAddrFileDestroy(pAddrFile);
+ }
+ else
+ {
+#ifdef ISN_NT
+
+ // Now check that we can obtain the desired share
+ // access. We use read access to control all access.
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ status = IoCheckShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &pAddr->u.sa_ShareAccess,
+ TRUE);
+
+#else // ISN_NT
+
+ status = STATUS_SUCCESS;
+
+#endif // ISN_NT
+
+ if (!NT_SUCCESS (status))
+ {
+ ExReleaseResource (&Device->dev_AddrResource);
+ SpxAddrFileDestroy(pAddrFile);
+ }
+ else
+ {
+ ExReleaseResource (&Device->dev_AddrResource);
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+ CTEGetLock (&pAddr->sa_Lock, &LockHandleAddr);
+
+ pAddrFile->saf_Addr = pAddr;
+ pAddrFile->saf_AddrLock = &pAddr->sa_Lock;
+#ifdef ISN_NT
+ pAddrFile->saf_FileObject = IrpSp->FileObject;
+#endif
+ // Set flags appropriately, note spx/stream flags are set at this
+ // point.
+ pAddrFile->saf_Flags &= ~SPX_ADDRFILE_OPENING;
+ pAddrFile->saf_Flags |= SPX_ADDRFILE_OPEN;
+
+ SpxAddrLockReference (pAddr, AREF_ADDR_FILE);
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)pAddrFile;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ // Queue in the address list, removed in destroy.
+ pAddrFile->saf_Next = pAddr->sa_AddrFileList;
+ pAddr->sa_AddrFileList = pAddrFile;
+
+ CTEFreeLock (&pAddr->sa_Lock, LockHandleAddr);
+ CTEFreeLock (&Device->dev_Lock, LockHandle);
+
+ status = STATUS_SUCCESS;
+ }
+ }
+
+ // Remove the reference from SpxLookupAddress.
+ SpxAddrDereference (pAddr, AREF_LOOKUP);
+ }
+
+ return status;
+
+} // SpxAddrOpen
+
+
+
+
+NTSTATUS
+SpxAddrSetEventHandler(
+ IN PDEVICE Device,
+ IN PREQUEST pRequest
+ )
+{
+ CTELockHandle lockHandle;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ PSPX_ADDR_FILE
+ pSpxAddrFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+ PTDI_REQUEST_KERNEL_SET_EVENT
+ pParam = (PTDI_REQUEST_KERNEL_SET_EVENT)REQUEST_PARAMETERS(pRequest);
+
+ if ((status = SpxAddrFileVerify(pSpxAddrFile)) != STATUS_SUCCESS)
+ return(status);
+
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle);
+ switch (pParam->EventType)
+ {
+
+ case TDI_EVENT_ERROR:
+
+ break;
+
+ case TDI_EVENT_CONNECT:
+
+ pSpxAddrFile->saf_ConnHandler =
+ (PTDI_IND_CONNECT)(pParam->EventHandler);
+ pSpxAddrFile->saf_ConnHandlerCtx =
+ pParam->EventContext;
+
+ break;
+
+ case TDI_EVENT_RECEIVE:
+
+ pSpxAddrFile->saf_RecvHandler =
+ (PTDI_IND_RECEIVE)(pParam->EventHandler);
+ pSpxAddrFile->saf_RecvHandlerCtx =
+ pParam->EventContext;
+
+ break;
+
+ case TDI_EVENT_DISCONNECT:
+
+ pSpxAddrFile->saf_DiscHandler =
+ (PTDI_IND_DISCONNECT)(pParam->EventHandler);
+ pSpxAddrFile->saf_DiscHandlerCtx =
+ pParam->EventContext;
+
+ break;
+
+
+ case TDI_EVENT_SEND_POSSIBLE :
+
+ pSpxAddrFile->saf_SendPossibleHandler =
+ (PTDI_IND_SEND_POSSIBLE)(pParam->EventHandler);
+ pSpxAddrFile->saf_SendPossibleHandlerCtx =
+ pParam->EventContext;
+
+ break;
+
+ case TDI_EVENT_RECEIVE_DATAGRAM:
+ case TDI_EVENT_RECEIVE_EXPEDITED:
+ default:
+
+ status = STATUS_INVALID_PARAMETER;
+ }
+
+ CTEFreeLock(pSpxAddrFile->saf_AddrLock, lockHandle);
+
+ SpxAddrFileDereference(pSpxAddrFile, AFREF_VERIFY);
+ return(status);
+}
+
+
+
+PSPX_ADDR
+SpxAddrCreate(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a transport address and associates it with
+ the specified transport device context. The reference count in the
+ address is automatically set to 1, and the reference count of the
+ device context is incremented.
+
+ NOTE: This routine must be called with the Device
+ spinlock held.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ Socket - The socket to assign to this address.
+
+Return Value:
+
+ The newly created address, or NULL if none can be allocated.
+
+--*/
+
+{
+ PSPX_ADDR pAddr;
+ int index;
+ CTELockHandle lockHandle;
+
+ pAddr = (PSPX_ADDR)SpxAllocateZeroedMemory (sizeof(SPX_ADDR));
+ if (pAddr == NULL)
+ {
+ DBGPRINT(ADDRESS, INFO,
+ ("Create address %lx failed\n", (ULONG)Socket));
+
+ return NULL;
+ }
+
+ DBGPRINT(ADDRESS, INFO,
+ ("Create address %lx (%lx)\n", pAddr, (ULONG)Socket));
+
+ pAddr->sa_Type = SPX_ADDRESS_SIGNATURE;
+ pAddr->sa_Size = sizeof (SPX_ADDR);
+ pAddr->sa_Flags = 0;
+
+ pAddr->sa_Device = Device;
+ pAddr->sa_DeviceLock = &Device->dev_Lock;
+ CTEInitLock (&pAddr->sa_Lock);
+
+ // This reference is for the address file that will associated with this addr.
+ pAddr->sa_RefCount = 1;
+
+#if DBG
+ pAddr->sa_RefTypes[AREF_ADDR_FILE] = 1;
+#endif
+
+ pAddr->sa_Socket = Socket;
+
+ // Insert address into the device hash table.
+ index = (int)(Socket & NUM_SPXADDR_HASH_MASK);
+
+ CTEGetLock (&Device->dev_Lock, &lockHandle);
+ pAddr->sa_Next = Device->dev_AddrHashTable[index];
+ Device->dev_AddrHashTable[index] = pAddr;
+ CTEFreeLock (&Device->dev_Lock, lockHandle);
+
+ SpxReferenceDevice (Device, DREF_ADDRESS);
+
+ return pAddr;
+
+} // SpxAddrCreate
+
+
+
+
+NTSTATUS
+SpxAddrFileVerify(
+ IN PSPX_ADDR_FILE pAddrFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to verify that the pointer given us in a file
+ object is in fact a valid address file object. We also verify that the
+ address object pointed to by it is a valid address object, and reference
+ it to keep it from disappearing while we use it.
+
+Arguments:
+
+ AddressFile - potential pointer to a SPX_ADDR_FILE object
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_ADDRESS otherwise
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ NTSTATUS status = STATUS_SUCCESS;
+ PSPX_ADDR Address;
+
+ // try to verify the address file signature. If the signature is valid,
+ // verify the address pointed to by it and get the address spinlock.
+ // check the address's state, and increment the reference count if it's
+ // ok to use it. Note that the only time we return an error for state is
+ // if the address is closing.
+
+ try
+ {
+ if ((pAddrFile->saf_Size == sizeof (SPX_ADDR_FILE)) &&
+ (pAddrFile->saf_Type == SPX_ADDRESSFILE_SIGNATURE) )
+ {
+ Address = pAddrFile->saf_Addr;
+
+ if ((Address->sa_Size == sizeof (SPX_ADDR)) &&
+ (Address->sa_Type == SPX_ADDRESS_SIGNATURE) )
+ {
+ CTEGetLock (&Address->sa_Lock, &LockHandle);
+
+ if ((Address->sa_Flags & SPX_ADDR_CLOSING) == 0)
+ {
+ SpxAddrFileLockReference(pAddrFile, AFREF_VERIFY);
+ }
+ else
+ {
+ DBGPRINT(TDI, ERR,
+ ("StVerifyAddressFile: A %lx closing\n", Address));
+
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ CTEFreeLock (&Address->sa_Lock, LockHandle);
+ }
+ else
+ {
+ DBGPRINT(TDI, ERR,
+ ("StVerifyAddressFile: A %lx bad signature\n", Address));
+
+ status = STATUS_INVALID_ADDRESS;
+ }
+ }
+ else
+ {
+ DBGPRINT(TDI, ERR,
+ ("StVerifyAddressFile: AF %lx bad signature\n", pAddrFile));
+
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DBGPRINT(TDI, ERR,
+ ("SpxAddrFileVerify: AF %lx exception\n", Address));
+
+ return GetExceptionCode();
+ }
+
+ return status;
+
+} // SpxAddrFileVerify
+
+
+
+
+VOID
+SpxAddrDestroy(
+ IN PVOID Parameter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a transport address and removes all references
+ made by it to other objects in the transport. The address structure
+ is returned to nonpaged system pool. It is assumed
+ that the caller has already removed all addressfile structures associated
+ with this address.
+
+ It is called from a worker thread queue by SpxDerefAddress when
+ the reference count goes to 0.
+
+ This thread is only queued by SpxDerefAddress. The reason for
+ this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ Address - Pointer to a transport address structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PSPX_ADDR pAddr, *ppAddr;
+ CTELockHandle LockHandle;
+
+ PSPX_ADDR Address = (PSPX_ADDR)Parameter;
+ PDEVICE Device = Address->sa_Device;
+ int index = (int)(Address->sa_Socket & NUM_SPXADDR_HASH_MASK);
+
+ DBGPRINT(ADDRESS, INFO,
+ ("Destroy address %lx\n", Address));
+
+ SeDeassignSecurity (&Address->sa_SecurityDescriptor);
+
+ // Delink this address from its associated device context's address
+ // database. To do this we must spin lock on the device context object,
+ // not on the address.
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+ for (ppAddr = &Device->dev_AddrHashTable[index]; (pAddr = *ppAddr) != NULL;)
+ {
+ if (pAddr == Address)
+ {
+ *ppAddr = pAddr->sa_Next;
+ break;
+ }
+
+ ppAddr = &pAddr->sa_Next;
+ }
+ CTEFreeLock (&Device->dev_Lock, LockHandle);
+
+ SpxFreeMemory (Address);
+ SpxDereferenceDevice (Device, DREF_ADDRESS);
+
+}
+
+
+
+
+#if DBG
+
+VOID
+SpxAddrRef(
+ IN PSPX_ADDR Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (Address->sa_RefCount > 0); // not perfect, but...
+
+ (VOID)SPX_ADD_ULONG (
+ &Address->sa_RefCount,
+ 1,
+ Address->sa_DeviceLock);
+}
+
+
+
+
+VOID
+SpxAddrLockRef(
+ IN PSPX_ADDR Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address
+ when the device lock is already held.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (Address->sa_RefCount > 0); // not perfect, but...
+ (VOID)SPX_ADD_ULONG (
+ &Address->sa_RefCount,
+ 1,
+ Address->sa_DeviceLock);
+}
+#endif
+
+
+
+
+VOID
+SpxAddrDeref(
+ IN PSPX_ADDR Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport address by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ SpxDestroyAddress to remove it from the system.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+
+ oldvalue = SPX_ADD_ULONG (
+ &Address->sa_RefCount,
+ (ULONG)-1,
+ Address->sa_DeviceLock);
+
+ //
+ // If we have deleted all references to this address, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ CTEAssert (oldvalue != 0);
+
+ if (oldvalue == 1)
+ {
+#if ISN_NT
+ ExInitializeWorkItem(
+ &Address->u.sa_DestroyAddrQueueItem,
+ SpxAddrDestroy,
+ (PVOID)Address);
+ ExQueueWorkItem(&Address->u.sa_DestroyAddrQueueItem, DelayedWorkQueue);
+#else
+ SpxAddrDestroy(Address);
+#endif
+
+ }
+
+}
+
+
+
+
+NTSTATUS
+SpxAddrFileCreate(
+ IN PDEVICE Device,
+ IN PREQUEST Request,
+ OUT PSPX_ADDR_FILE * ppAddrFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates an address file from the pool of ther
+ specified device context. The reference count in the
+ address is automatically set to 1.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+Return Value:
+
+ The allocate address file or NULL.
+
+--*/
+
+{
+ NTSTATUS status;
+ BYTE socketType;
+ CTELockHandle LockHandle;
+ PSPX_ADDR_FILE pAddrFile;
+
+ // What is the address file type?
+ if (!NT_SUCCESS(status = SpxUtilGetSocketType(
+ REQUEST_OPEN_NAME(Request),
+ &socketType)))
+ {
+ return(status);
+ }
+
+ pAddrFile = (PSPX_ADDR_FILE)SpxAllocateZeroedMemory (sizeof(SPX_ADDR_FILE));
+ if (pAddrFile == NULL)
+ {
+ DBGPRINT(ADDRESS, ERR,
+ ("Create address file failed\n"));
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ DBGPRINT(ADDRESS, INFO,
+ ("Create address file %lx\n", pAddrFile));
+
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+
+ pAddrFile->saf_Type = SPX_ADDRESSFILE_SIGNATURE;
+ pAddrFile->saf_Size = sizeof (SPX_ADDR_FILE);
+
+ pAddrFile->saf_Addr = NULL;
+
+#ifdef ISN_NT
+ pAddrFile->saf_FileObject = NULL;
+#endif
+
+ pAddrFile->saf_Device = Device;
+ pAddrFile->saf_Flags = SPX_ADDRFILE_OPENING;
+ if ((socketType == SOCKET1_TYPE_SEQPKT) ||
+ (socketType == SOCKET1_TYPE_STREAM))
+ {
+ if (socketType == SOCKET1_TYPE_STREAM)
+ {
+ pAddrFile->saf_Flags |= SPX_ADDRFILE_STREAM;
+ }
+ }
+
+ if ((socketType == SOCKET2_TYPE_SEQPKT) ||
+ (socketType == SOCKET2_TYPE_STREAM))
+ {
+ pAddrFile->saf_Flags |= SPX_ADDRFILE_SPX2;
+ if (socketType == SOCKET2_TYPE_STREAM)
+ {
+ pAddrFile->saf_Flags |= SPX_ADDRFILE_STREAM;
+ }
+ }
+
+ pAddrFile->saf_RefCount = 1;
+
+#if DBG
+ pAddrFile->saf_RefTypes[AFREF_CREATE] = 1;
+#endif
+
+ pAddrFile->saf_CloseReq = (PREQUEST)NULL;
+
+ // Initialize the request handlers.
+ pAddrFile->saf_ConnHandler =
+ pAddrFile->saf_ConnHandlerCtx = NULL;
+ pAddrFile->saf_DiscHandler =
+ pAddrFile->saf_DiscHandlerCtx = NULL;
+ pAddrFile->saf_RecvHandler =
+ pAddrFile->saf_RecvHandlerCtx = NULL;
+ pAddrFile->saf_ErrHandler =
+ pAddrFile->saf_ErrHandlerCtx = NULL;
+
+ // Release lock
+ CTEFreeLock (&Device->dev_Lock, LockHandle);
+
+ // Put in the global list for our reference
+ spxAddrInsertIntoGlobalList(pAddrFile);
+
+ *ppAddrFile = pAddrFile;
+ return STATUS_SUCCESS;
+
+}
+
+
+
+
+NTSTATUS
+SpxAddrFileDestroy(
+ IN PSPX_ADDR_FILE pAddrFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys an address file and removes all references
+ made by it to other objects in the transport.
+
+ This routine is only called by SpxAddrFileDereference. The reason
+ for this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address file object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ pAddrFile Pointer to a transport address file structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ CTELockHandle LockHandle, LockHandle1;
+ PSPX_ADDR Address;
+ PDEVICE Device;
+ PREQUEST CloseRequest;
+ PSPX_ADDR_FILE pRemAddr, *ppRemAddr;
+
+ DBGPRINT(ADDRESS, INFO,
+ ("Destroy address file %lx\n", pAddrFile));
+
+ Address = pAddrFile->saf_Addr;
+ Device = pAddrFile->saf_Device;
+
+ if (Address)
+ {
+ CTEGetLock (&Device->dev_Lock, &LockHandle1);
+
+ // This addressfile was associated with an address.
+ CTEGetLock (&Address->sa_Lock, &LockHandle);
+
+ // If the last reference on the address is being removed, set the
+ // closing flag to prevent further references.
+
+ //if (Address->sa_RefCount == 1)
+
+ //
+ // ** The lock passed here is a dummy - it is pre-compiled out.
+ //
+ if (SPX_ADD_ULONG(&Address->sa_RefCount, 0, &Address->sa_Lock) == 1) {
+ Address->sa_Flags |= SPX_ADDR_CLOSING;
+ }
+
+ // Dequeue the address file from the address list.
+ for (ppRemAddr = &Address->sa_AddrFileList; (pRemAddr = *ppRemAddr) != NULL;)
+ {
+ if (pRemAddr == pAddrFile)
+ {
+ *ppRemAddr = pRemAddr->saf_Next;
+ break;
+ }
+
+ ppRemAddr = &pRemAddr->saf_Next;
+ }
+
+ pAddrFile->saf_Addr = NULL;
+
+#ifdef ISN_NT
+ pAddrFile->saf_FileObject->FsContext = NULL;
+ pAddrFile->saf_FileObject->FsContext2 = NULL;
+#endif
+
+ CTEFreeLock (&Address->sa_Lock, LockHandle);
+ CTEFreeLock (&Device->dev_Lock, LockHandle1);
+
+ // We will already have been removed from the ShareAccess
+ // of the owning address.
+ //
+ // Now dereference the owning address.
+ SpxAddrDereference(Address, AREF_ADDR_FILE);
+ }
+
+ // Save this for later completion.
+ CloseRequest = pAddrFile->saf_CloseReq;
+
+ // Remove from the global list
+ spxAddrRemoveFromGlobalList(pAddrFile);
+
+ // return the addressFile to the pool of address files
+ SpxFreeMemory (pAddrFile);
+
+ if (CloseRequest != (PREQUEST)NULL)
+ {
+ REQUEST_INFORMATION(CloseRequest) = 0;
+ REQUEST_STATUS(CloseRequest) = STATUS_SUCCESS;
+ SpxCompleteRequest (CloseRequest);
+ SpxFreeRequest (Device, CloseRequest);
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+
+
+
+#if DBG
+
+VOID
+SpxAddrFileRef(
+ IN PSPX_ADDR_FILE pAddrFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+
+Arguments:
+
+ pAddrFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (pAddrFile->saf_RefCount > 0); // not perfect, but...
+
+ (VOID)SPX_ADD_ULONG (
+ &pAddrFile->saf_RefCount,
+ 1,
+ pAddrFile->saf_AddrLock);
+
+} // SpxRefAddressFile
+
+
+
+
+VOID
+SpxAddrFileLockRef(
+ IN PSPX_ADDR_FILE pAddrFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+ IT IS CALLED WITH THE ADDRESS LOCK HELD.
+
+Arguments:
+
+ pAddrFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (pAddrFile->saf_RefCount > 0); // not perfect, but...
+ (VOID)SPX_ADD_ULONG (
+ &pAddrFile->saf_RefCount,
+ 1,
+ pAddrFile->saf_AddrLock);
+
+}
+#endif
+
+
+
+
+VOID
+SpxAddrFileDeref(
+ IN PSPX_ADDR_FILE pAddrFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences an address file by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ SpxDestroyAddressFile to remove it from the system.
+
+Arguments:
+
+ pAddrFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+
+ oldvalue = SPX_ADD_ULONG (
+ &pAddrFile->saf_RefCount,
+ (ULONG)-1,
+ pAddrFile->saf_AddrLock);
+
+ // If we have deleted all references to this address file, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ CTEAssert (oldvalue > 0);
+
+ if (oldvalue == 1)
+ {
+ SpxAddrFileDestroy(pAddrFile);
+ }
+
+}
+
+
+
+
+PSPX_ADDR
+SpxAddrLookup(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the transport addresses defined for the given
+ device context and compares them with the specified NETWORK
+ NAME values. If an exact match is found, then a pointer to the
+ ADDRESS object is returned, and as a side effect, the reference
+ count to the address object is incremented. If the address is not
+ found, then NULL is returned.
+
+ NOTE: This routine must be called with the Device
+ spinlock held.
+
+Arguments:
+
+ Device - Pointer to the device object and its extension.
+
+ Socket - The socket to look up.
+
+Return Value:
+
+ Pointer to the ADDRESS object found, or NULL if not found.
+
+--*/
+
+{
+ PSPX_ADDR Address;
+ int index = (int)(Socket & NUM_SPXADDR_HASH_MASK);
+
+ for (Address = Device->dev_AddrHashTable[index];
+ Address != NULL;
+ Address = Address->sa_Next)
+ {
+ if ((Address->sa_Flags & SPX_ADDR_CLOSING) != 0)
+ {
+ continue;
+ }
+
+ if (Address->sa_Socket == Socket)
+ {
+ // We found the match. Bump the reference count on the address, and
+ // return a pointer to the address object for the caller to use.
+ SpxAddrLockReference(Address, AREF_LOOKUP);
+ return Address;
+
+ }
+ }
+
+ // The specified address was not found.
+ return NULL;
+
+}
+
+
+
+
+BOOLEAN
+SpxAddrExists(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ )
+
+/*++
+
+Routine Description:
+
+ NOTE: This routine must be called with the Device
+ spinlock held.
+
+Arguments:
+
+ Device - Pointer to the device object and its extension.
+
+ Socket - The socket to look up.
+
+Return Value:
+
+ TRUE if so, else FALSE
+
+--*/
+
+{
+ PSPX_ADDR Address;
+ int index = (int)(Socket & NUM_SPXADDR_HASH_MASK);
+
+ for (Address = Device->dev_AddrHashTable[index];
+ Address != NULL;
+ Address = Address->sa_Next)
+ {
+ if ((Address->sa_Flags & SPX_ADDR_CLOSING) != 0)
+ {
+ continue;
+ }
+
+ if (Address->sa_Socket == Socket)
+ {
+ // We found the match
+ return TRUE;
+ }
+ }
+
+ // The specified address was not found.
+ return FALSE;
+
+} // SpxAddrExists
+
+
+
+
+NTSTATUS
+SpxAddrConnByRemoteIdAddrLock(
+ IN PSPX_ADDR pSpxAddr,
+ IN USHORT SrcConnId,
+ IN PBYTE SrcIpxAddr,
+ OUT PSPX_CONN_FILE *ppSpxConnFile
+ )
+{
+ PSPX_CONN_FILE pSpxConnFile;
+ NTSTATUS status = STATUS_INVALID_CONNECTION;
+
+ for (pSpxConnFile = pSpxAddr->sa_ActiveConnList;
+ pSpxConnFile != NULL;
+ pSpxConnFile = pSpxConnFile->scf_Next)
+ {
+ if ((pSpxConnFile->scf_RemConnId == SrcConnId) &&
+ (*((UNALIGNED ULONG *)SrcIpxAddr) ==
+ *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr)) &&
+ (*(UNALIGNED ULONG *)(SrcIpxAddr+4) ==
+ *(UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr+4)) &&
+ (*(UNALIGNED ULONG *)(SrcIpxAddr+8) ==
+ *(UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr+8)))
+ {
+ SpxConnFileReference(pSpxConnFile, CFREF_ADDR);
+ *ppSpxConnFile = pSpxConnFile;
+ status = STATUS_SUCCESS;
+ break;
+ }
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxAddrFileStop(
+ IN PSPX_ADDR_FILE pAddrFile,
+ IN PSPX_ADDR Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to terminate all activity on an pAddrFile and
+ destroy the object. We remove every connection and datagram associated
+ with this addressfile from the address database and terminate their
+ activity. Then, if there are no other outstanding addressfiles open on
+ this address, the address will go away.
+
+Arguments:
+
+ pAddrFile - pointer to the addressFile to be stopped
+
+ Address - the owning address for this addressFile (we do not depend upon
+ the pointer in the addressFile because we want this routine to be safe)
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the request
+ is not for a real address.
+
+--*/
+
+{
+ PSPX_CONN_FILE pSpxConnFile, pSpxConnFileNext;
+ CTELockHandle LockHandle;
+
+
+ DBGPRINT(ADDRESS, DBG,
+ ("SpxAddrFileStop: %lx\n", pAddrFile));
+
+ CTEGetLock (&Address->sa_Lock, &LockHandle);
+
+ if (pAddrFile->saf_Flags & SPX_ADDRFILE_CLOSING)
+ {
+ CTEFreeLock (&Address->sa_Lock, LockHandle);
+ return STATUS_SUCCESS;
+ }
+
+ pAddrFile->saf_Flags |= SPX_ADDRFILE_CLOSING;
+
+ pSpxConnFileNext = NULL;
+ if (pSpxConnFile = pAddrFile->saf_AssocConnList)
+ {
+ pSpxConnFileNext = pSpxConnFile;
+ SpxConnFileReference(pSpxConnFile, CFREF_ADDR);
+ }
+
+ while (pSpxConnFile)
+ {
+ if (pSpxConnFileNext = pSpxConnFile->scf_AssocNext)
+ {
+ SpxConnFileReference(pSpxConnFileNext, CFREF_ADDR);
+ }
+ CTEFreeLock (&Address->sa_Lock, LockHandle);
+
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxAddrFileClose: Assoc conn stop %lx when %lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RefCount));
+
+ SpxConnStop(pSpxConnFile);
+ SpxConnFileDereference(pSpxConnFile, CFREF_ADDR);
+
+ CTEGetLock (&Address->sa_Lock, &LockHandle);
+ pSpxConnFile = pSpxConnFileNext;
+ }
+
+ CTEFreeLock (&Address->sa_Lock, LockHandle);
+ return STATUS_SUCCESS;
+
+}
+
+
+
+
+NTSTATUS
+SpxAddrFileCleanup(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ Request - the close request.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the
+ request does not point to a real address.
+
+--*/
+
+{
+ PSPX_ADDR Address;
+ PSPX_ADDR_FILE pSpxAddrFile;
+ NTSTATUS status;
+
+ pSpxAddrFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ DBGPRINT(ADDRESS, INFO,
+ ("SpxAddrFileCleanup: %lx\n", pSpxAddrFile));
+
+ status = SpxAddrFileVerify(pSpxAddrFile);
+ if (!NT_SUCCESS (status))
+ {
+ return(status);
+ }
+
+ // We assume that addressFile has already been verified
+ // at this point.
+ Address = pSpxAddrFile->saf_Addr;
+ CTEAssert (Address);
+
+ SpxAddrFileStop(pSpxAddrFile, Address);
+ SpxAddrFileDereference(pSpxAddrFile, AFREF_VERIFY);
+ return STATUS_SUCCESS;
+}
+
+
+
+
+NTSTATUS
+SpxAddrFileClose(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to close the addressfile pointed to by a file
+ object. If there is any activity to be run down, we will run it down
+ before we terminate the addressfile. We remove every connection and
+ datagram associated with this addressfile from the address database
+ and terminate their activity. Then, if there are no other outstanding
+ addressfiles open on this address, the address will go away.
+
+Arguments:
+
+ Request - the close request.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the
+ request does not point to a real address.
+
+--*/
+
+{
+ PSPX_ADDR Address;
+ PSPX_ADDR_FILE pSpxAddrFile;
+ NTSTATUS status;
+
+ pSpxAddrFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ DBGPRINT(ADDRESS, DBG,
+ ("SpxAddrFileClose: %lx\n", pSpxAddrFile));
+
+ status = SpxAddrFileVerify(pSpxAddrFile);
+
+ if (!NT_SUCCESS (status))
+ {
+ return(status);
+ }
+
+ pSpxAddrFile->saf_CloseReq = Request;
+
+ // We assume that addressFile has already been verified
+ // at this point.
+ Address = pSpxAddrFile->saf_Addr;
+ CTEAssert (Address);
+
+ // Remove us from the access info for this address.
+ ExAcquireResourceExclusive (&Device->dev_AddrResource, TRUE);
+
+#ifdef ISN_NT
+ IoRemoveShareAccess (pSpxAddrFile->saf_FileObject, &Address->u.sa_ShareAccess);
+#endif
+
+ ExReleaseResource (&Device->dev_AddrResource);
+
+
+ SpxAddrFileDereference (pSpxAddrFile, AFREF_CREATE);
+ SpxAddrFileDereference(pSpxAddrFile, AFREF_VERIFY);
+ return STATUS_PENDING;
+
+} // SpxCloseAddressFile
+
+
+
+
+USHORT
+SpxAddrAssignSocket(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine assigns a socket that is unique within a range
+ of SocketUniqueness.
+
+Arguments:
+
+ Device - Pointer to the device context.
+
+Return Value:
+
+ The assigned socket number, or 0 if a unique one cannot
+ be found.
+
+--*/
+
+{
+ BOOLEAN wrapped = FALSE;
+ USHORT temp, Socket;
+
+ // We have to auto-assign a socket.
+ temp = Device->dev_CurrentSocket;
+ PUTSHORT2SHORT(
+ &Socket,
+ Device->dev_CurrentSocket);
+
+ while (TRUE)
+ {
+ Device->dev_CurrentSocket += (USHORT)PARAM(CONFIG_SOCKET_UNIQUENESS);
+ if (Device->dev_CurrentSocket > PARAM(CONFIG_SOCKET_RANGE_END))
+ {
+ Device->dev_CurrentSocket = (USHORT)PARAM(CONFIG_SOCKET_RANGE_START);
+ wrapped = TRUE;
+ }
+
+ if (!SpxAddrExists (Device, Socket))
+ {
+ break;
+ }
+
+ PUTSHORT2SHORT(
+ &Socket,
+ Device->dev_CurrentSocket);
+
+ if (wrapped && (Device->dev_CurrentSocket >= temp))
+ {
+ // If we have checked all possible values given SOCKET_UNIQUENESS...
+ // This may actually return ERROR even if there are
+ // available socket numbers although they may be
+ // implicitly in use due to SOCKET_UNIQUENESS being
+ // > 1. That is the way it is to work.
+
+ Socket = 0;
+ break;
+ }
+ }
+
+ DBGPRINT(ADDRESS, INFO,
+ ("OpenAddress, assigned socket %lx\n", Socket));
+
+ return(Socket);
+}
+
+
+
+
+VOID
+spxAddrInsertIntoGlobalList(
+ IN PSPX_ADDR_FILE pSpxAddrFile
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ pSpxAddrFile->saf_GlobalNext = SpxGlobalAddrList;
+ SpxGlobalAddrList = pSpxAddrFile;
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+
+ return;
+}
+
+
+
+
+NTSTATUS
+spxAddrRemoveFromGlobalList(
+ IN PSPX_ADDR_FILE pSpxAddrFile
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+ PSPX_ADDR_FILE pC, *ppC;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ for (ppC = &SpxGlobalAddrList;
+ (pC = *ppC) != NULL;)
+ {
+ if (pC == pSpxAddrFile)
+ {
+ DBGPRINT(SEND, INFO,
+ ("SpxAddrRemoveFromGlobal: %lx\n", pSpxAddrFile));
+
+ // Remove from list
+ *ppC = pC->saf_GlobalNext;
+ break;
+ }
+
+ ppC = &pC->saf_GlobalNext;
+ }
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+
+ if (pC == NULL)
+ status = STATUS_INVALID_ADDRESS;
+
+ return(status);
+}
+
+
+
+
diff --git a/private/ntos/tdi/isn/spx/spxbind.c b/private/ntos/tdi/isn/spx/spxbind.c
new file mode 100644
index 000000000..ba46eb7a9
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxbind.c
@@ -0,0 +1,602 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxbind.c
+
+Abstract:
+
+ This module contains the code to bind to the IPX transport, as well as the
+ indication routines for the IPX transport not including the send/recv ones.
+
+Author:
+
+ Stefan Solomon (stefans) Original Version
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXBIND
+
+VOID
+SpxStatus (
+ IN USHORT NicId,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength);
+
+VOID
+SpxFindRouteComplete (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute);
+
+VOID
+SpxScheduleRoute (
+ IN PIPX_ROUTE_ENTRY RouteEntry);
+
+VOID
+SpxLineDown (
+ IN USHORT NicId,
+ IN ULONG FwdAdapterContext);
+
+VOID
+SpxLineUp (
+ IN USHORT NicId,
+ IN PIPX_LINE_INFO LineInfo,
+ IN NDIS_MEDIUM DeviceType,
+ IN PVOID ConfigurationData);
+
+VOID
+SpxFindRouteComplete (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute);
+
+#if defined(_PNP_POWER)
+VOID
+SpxPnPNotification(
+ IN IPX_PNP_OPCODE OpCode,
+ IN PVOID PnPData
+ );
+#endif _PNP_POWER
+
+#if defined(_PNP_POWER)
+//
+// globals and externs
+//
+extern CTELock spxTimerLock;
+extern LARGE_INTEGER spxTimerTick;
+extern KTIMER spxTimer;
+extern KDPC spxTimerDpc;
+extern BOOLEAN spxTimerStopped;
+#endif _PNP_POWER
+
+NTSTATUS
+SpxInitBindToIpx(
+ VOID
+ )
+
+{
+ NTSTATUS status;
+ IO_STATUS_BLOCK ioStatusBlock;
+ OBJECT_ATTRIBUTES objectAttr;
+ PIPX_INTERNAL_BIND_INPUT pBindInput;
+ PIPX_INTERNAL_BIND_OUTPUT pBindOutput;
+
+ InitializeObjectAttributes(
+ &objectAttr,
+ &IpxDeviceName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ status = NtCreateFile(
+ &IpxHandle,
+ SYNCHRONIZE | GENERIC_READ,
+ &objectAttr,
+ &ioStatusBlock,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0L);
+
+ if (!NT_SUCCESS(status)) {
+ return status;
+ }
+
+ if ((pBindInput = CTEAllocMem(sizeof(IPX_INTERNAL_BIND_INPUT))) == NULL) {
+ NtClose(IpxHandle);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ // Fill in our bind data
+#if defined(_PNP_POWER)
+ pBindInput->Version = ISN_VERSION;
+#else
+ pBindInput->Version = 1;
+#endif _PNP_POWER
+ pBindInput->Identifier = IDENTIFIER_SPX;
+ pBindInput->BroadcastEnable = FALSE;
+ pBindInput->LookaheadRequired = IPX_HDRSIZE;
+ pBindInput->ProtocolOptions = 0;
+ pBindInput->ReceiveHandler = SpxReceive;
+ pBindInput->ReceiveCompleteHandler = SpxReceiveComplete;
+ pBindInput->StatusHandler = SpxStatus;
+ pBindInput->SendCompleteHandler = SpxSendComplete;
+ pBindInput->TransferDataCompleteHandler = SpxTransferDataComplete;
+ pBindInput->FindRouteCompleteHandler = SpxFindRouteComplete;
+ pBindInput->LineUpHandler = SpxLineUp;
+ pBindInput->LineDownHandler = SpxLineDown;
+ pBindInput->ScheduleRouteHandler = SpxScheduleRoute;
+#if defined(_PNP_POWER)
+ pBindInput->PnPHandler = SpxPnPNotification;
+#endif _PNP_POWER
+
+
+ // First get the length for the output buffer.
+ status = NtDeviceIoControlFile(
+ IpxHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &ioStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPX_INTERNAL_BIND, // IoControlCode
+ pBindInput, // Input Buffer
+ sizeof(IPX_INTERNAL_BIND_INPUT), // Input Buffer Length
+ NULL, // Output Buffer
+ 0);
+
+ if (status == STATUS_PENDING) {
+ status = NtWaitForSingleObject(
+ IpxHandle,
+ (BOOLEAN)FALSE,
+ NULL);
+ }
+
+ if (status != STATUS_BUFFER_TOO_SMALL) {
+ CTEFreeMem(pBindInput);
+ NtClose(IpxHandle);
+ return(STATUS_INVALID_PARAMETER);
+ }
+
+ if ((pBindOutput = CTEAllocMem(ioStatusBlock.Information)) == NULL) {
+ CTEFreeMem(pBindInput);
+ NtClose(IpxHandle);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ status = NtDeviceIoControlFile(
+ IpxHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &ioStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPX_INTERNAL_BIND, // IoControlCode
+ pBindInput, // Input Buffer
+ sizeof(IPX_INTERNAL_BIND_INPUT), // Input Buffer Length
+ pBindOutput, // Output Buffer
+ ioStatusBlock.Information);
+
+ if (status == STATUS_PENDING) {
+ status = NtWaitForSingleObject(
+ IpxHandle,
+ (BOOLEAN)FALSE,
+ NULL);
+ }
+
+ if (status == STATUS_SUCCESS) {
+
+ // Get all the info from the bind output buffer and save in
+ // appropriate places.
+ IpxLineInfo = pBindOutput->LineInfo;
+ IpxMacHdrNeeded = pBindOutput->MacHeaderNeeded;
+ IpxInclHdrOffset = pBindOutput->IncludedHeaderOffset;
+
+ IpxSendPacket = pBindOutput->SendHandler;
+ IpxFindRoute = pBindOutput->FindRouteHandler;
+ IpxQuery = pBindOutput->QueryHandler;
+ IpxTransferData = pBindOutput->TransferDataHandler;
+
+#if !defined(_PNP_POWER)
+ // Copy over the network node info.
+ RtlCopyMemory(
+ SpxDevice->dev_Network,
+ pBindOutput->Network,
+ IPX_NET_LEN);
+
+ RtlCopyMemory(
+ SpxDevice->dev_Node,
+ pBindOutput->Node,
+ IPX_NODE_LEN);
+
+
+ DBGPRINT(TDI, INFO,
+ ("SpxInitBindToIpx: Ipx Net %lx\n",
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network));
+
+ //
+ // Find out how many adapters IPX has, if this fails
+ // just assume one.
+ //
+
+ if ((*IpxQuery)(
+ IPX_QUERY_MAXIMUM_NIC_ID,
+ 0,
+ &SpxDevice->dev_Adapters,
+ sizeof(USHORT),
+ NULL) != STATUS_SUCCESS) {
+
+ SpxDevice->dev_Adapters = 1;
+
+ }
+#endif !_PNP_POWER
+ } else {
+
+ NtClose(IpxHandle);
+ status = STATUS_INVALID_PARAMETER;
+ }
+ CTEFreeMem(pBindInput);
+ CTEFreeMem(pBindOutput);
+
+ return status;
+}
+
+
+
+
+VOID
+SpxUnbindFromIpx(
+ VOID
+ )
+
+{
+ NtClose(IpxHandle);
+ return;
+}
+
+
+
+
+VOID
+SpxStatus(
+ IN USHORT NicId,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength
+ )
+
+{
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxStatus: CALLED WITH %lx\n",
+ GeneralStatus));
+
+ return;
+}
+
+
+
+VOID
+SpxFindRouteComplete (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute
+ )
+
+{
+ CTELockHandle lockHandle;
+ PSPX_FIND_ROUTE_REQUEST pSpxFrReq = (PSPX_FIND_ROUTE_REQUEST)FindRouteRequest;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)pSpxFrReq->fr_Ctx;
+
+ // This will be on a connection. Grab the lock, check the state and go from
+ // there.
+ if (pSpxConnFile == NULL)
+ {
+ // Should this ever happen?
+ KeBugCheck(0);
+ return;
+ }
+
+ // Check the state. The called routines release the lock, remove the reference.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ if (SPX_CONN_CONNECTING(pSpxConnFile))
+ {
+ // We are doing an active connect!
+ SpxConnConnectFindRouteComplete(
+ pSpxConnFile,
+ pSpxFrReq,
+ FoundRoute,
+ lockHandle);
+ }
+ else // For all others call active
+ {
+ SpxConnActiveFindRouteComplete(
+ pSpxConnFile,
+ pSpxFrReq,
+ FoundRoute,
+ lockHandle);
+ }
+
+ // Free the find route request.
+ SpxFreeMemory(pSpxFrReq);
+
+ return;
+}
+
+
+
+
+VOID
+SpxLineUp (
+ IN USHORT NicId,
+ IN PIPX_LINE_INFO LineInfo,
+ IN NDIS_MEDIUM DeviceType,
+ IN PVOID ConfigurationData
+ )
+
+{
+ // With PnP, our local address is changed when we get PnP
+ // notification.
+#if !defined(_PNP_POWER)
+
+ //
+ // If we get a line up for NicId 0, it means our local
+ // network number has changed, re-query from IPX.
+ //
+
+ if (NicId == 0) {
+
+ TDI_ADDRESS_IPX IpxAddress;
+
+ if ((*IpxQuery)(
+ IPX_QUERY_IPX_ADDRESS,
+ 0,
+ &IpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL) == STATUS_SUCCESS) {
+
+ RtlCopyMemory(
+ SpxDevice->dev_Network,
+ &IpxAddress.NetworkAddress,
+ IPX_NET_LEN);
+
+ DBGPRINT(TDI, INFO,
+ ("SpxLineUp: Ipx Net %lx\n",
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network));
+
+ //
+ // The node shouldn't change!
+ //
+
+ if (!RtlEqualMemory(
+ SpxDevice->dev_Node,
+ IpxAddress.NodeAddress,
+ IPX_NODE_LEN)) {
+
+ DBGPRINT(TDI, ERR,
+ ("SpxLineUp: Node address has changed\n"));
+ }
+ }
+
+ } else {
+
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxLineUp: CALLED WITH %lx\n",
+ NicId));
+ }
+
+ return;
+#endif !_PNP_POWER
+
+}
+
+
+
+
+VOID
+SpxLineDown (
+ IN USHORT NicId,
+ IN ULONG FwdAdapterContext
+ )
+
+{
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxLineDown: CALLED WITH %lx\n",
+ NicId));
+
+ return;
+}
+
+
+
+
+VOID
+SpxScheduleRoute (
+ IN PIPX_ROUTE_ENTRY RouteEntry
+ )
+
+{
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxScheduleRoute: CALLED WITH %lx\n",
+ RouteEntry));
+
+ return;
+}
+
+#if defined(_PNP_POWER)
+VOID
+SpxPnPNotification(
+ IN IPX_PNP_OPCODE OpCode,
+ IN PVOID PnPData
+ )
+
+/*++
+
+Routine Description:
+
+ This function receives the notification about PnP events from IPX
+
+Arguments:
+
+ OpCode - Type of the PnP event
+
+ PnPData - Data associated with this event.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ USHORT MaximumNicId = 0;
+ CTELockHandle LockHandle;
+ NTSTATUS Status;
+ PDEVICE Device = SpxDevice;
+ UNICODE_STRING UnicodeDeviceName;
+
+ DBGPRINT(DEVICE, DBG,("Received a pnp notification, opcode %d\n",OpCode));
+
+ switch( OpCode ) {
+ case IPX_PNP_ADD_DEVICE : {
+ CTELockHandle TimerLockHandle;
+ IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
+
+
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+
+ if ( PnPInfo->FirstORLastDevice ) {
+ CTEAssert( PnPInfo->NewReservedAddress );
+ CTEAssert( Device->dev_State != DEVICE_STATE_OPEN );
+
+ *(UNALIGNED ULONG *)Device->dev_Network = PnPInfo->NetworkAddress;
+ RtlCopyMemory( Device->dev_Node, PnPInfo->NodeAddress, 6);
+
+ //
+ // Start the timer. It is possible that the timer
+ // was still running or we are still in the timer dpc
+ // from the previous ADD_DEVICE - DELETE_DEVICE execution
+ // cycle. But it is ok simply restart this, because
+ // KeSetTimer implicitly cancels the previous Dpc.
+ //
+
+ CTEGetLock(&spxTimerLock, &TimerLockHandle);
+ spxTimerStopped = FALSE;
+ CTEFreeLock(&spxTimerLock, TimerLockHandle);
+ KeSetTimer(&spxTimer,
+ spxTimerTick,
+ &spxTimerDpc);
+
+
+ Device->dev_State = DEVICE_STATE_OPEN;
+
+
+ CTEAssert( !Device->dev_Adapters );
+
+ IpxLineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
+ IpxLineInfo.MaximumPacketSize = PnPInfo->LineInfo.MaximumPacketSize;
+ // set the provider info
+ SpxDevice->dev_ProviderInfo.MaximumLookaheadData = IpxLineInfo.MaximumPacketSize;
+ // Set the window size in statistics
+ SpxDevice->dev_Stat.MaximumSendWindow =
+ SpxDevice->dev_Stat.AverageSendWindow = PARAM(CONFIG_WINDOW_SIZE) *
+ IpxLineInfo.MaximumSendSize;
+
+ }else {
+ IpxLineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
+ // Set the window size in statistics
+ SpxDevice->dev_Stat.MaximumSendWindow =
+ SpxDevice->dev_Stat.AverageSendWindow = PARAM(CONFIG_WINDOW_SIZE) *
+ IpxLineInfo.MaximumSendSize;
+
+ }
+
+ Device->dev_Adapters++;
+ CTEFreeLock ( &Device->dev_Lock, LockHandle );
+
+ //
+ // Notify the TDI clients about the device creation
+ //
+ if ( PnPInfo->FirstORLastDevice ) {
+ UnicodeDeviceName.Buffer = Device->dev_DeviceName;
+ UnicodeDeviceName.MaximumLength = Device->dev_DeviceNameLen;
+ UnicodeDeviceName.Length = Device->dev_DeviceNameLen - sizeof(WCHAR);
+
+ if ( !NT_SUCCESS( TdiRegisterDeviceObject(
+ &UnicodeDeviceName,
+ &Device->dev_TdiRegistrationHandle ) )) {
+ DBGPRINT(TDI,ERR, ("Failed to register Spx Device with TDI\n"));
+ }
+ }
+
+ break;
+ }
+ case IPX_PNP_DELETE_DEVICE : {
+
+ IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
+
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+
+ CTEAssert( Device->dev_Adapters );
+ Device->dev_Adapters--;
+
+ if ( PnPInfo->FirstORLastDevice ) {
+ Device->dev_State = DEVICE_STATE_LOADED;
+ Device->dev_Adapters = 0;
+ }
+
+ IpxLineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
+ CTEFreeLock ( &Device->dev_Lock, LockHandle );
+
+ if ( PnPInfo->FirstORLastDevice ) {
+ SpxTimerFlushAndStop();
+ //
+ // inform tdi clients about the device deletion
+ //
+ if ( !NT_SUCCESS( TdiDeregisterDeviceObject(
+ Device->dev_TdiRegistrationHandle ) )) {
+ DBGPRINT(TDI,ERR, ("Failed to Deregister Spx Device with TDI\n"));
+ }
+ }
+ //
+ // TBD: call ExNotifyCallback
+ //
+
+ break;
+ }
+ case IPX_PNP_ADDRESS_CHANGE: {
+ IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
+
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+ CTEAssert( PnPInfo->NewReservedAddress );
+
+ *(UNALIGNED ULONG *)Device->dev_Network = PnPInfo->NetworkAddress;
+ RtlCopyMemory( Device->dev_Node, PnPInfo->NodeAddress, 6);
+
+ CTEFreeLock ( &Device->dev_Lock, LockHandle );
+ break;
+ }
+ case IPX_PNP_TRANSLATE_DEVICE:
+ break;
+ case IPX_PNP_TRANSLATE_ADDRESS:
+ break;
+ default:
+ CTEAssert( FALSE );
+ }
+} /* NbiPnPNotification */
+
+#endif _PNP_POWER
diff --git a/private/ntos/tdi/isn/spx/spxconn.c b/private/ntos/tdi/isn/spx/spxconn.c
new file mode 100644
index 000000000..0c139fbc7
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxconn.c
@@ -0,0 +1,3851 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxconn.c
+
+Abstract:
+
+ This module contains code which implements the CONNECTION object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport connection objects.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 5-July-1995
+ Bug fixes - tagged [SA]
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, SpxConnOpen)
+#pragma alloc_text(PAGE, SpxConnCleanup)
+#pragma alloc_text(PAGE, SpxConnClose)
+#endif
+
+// Define module number for event logging entries
+#define FILENUM SPXCONN
+
+VOID
+SpxFindRouteComplete (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute);
+
+
+NTSTATUS
+SpxConnOpen(
+ IN PDEVICE pDevice,
+ IN CONNECTION_CONTEXT ConnCtx,
+ IN PREQUEST pRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to create a connection object and associate the
+ passed ConnectionContext with it.
+
+Arguments:
+
+ pConnCtx - The TDI ConnectionContext to be associated with object
+
+Return Value:
+
+ STATUS_SUCCESS if connection was successfully opened
+ Error otherwise.
+
+--*/
+
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PSPX_CONN_FILE pSpxConnFile;
+
+#ifdef ISN_NT
+ PIRP Irp = (PIRP)pRequest;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+#endif
+
+
+ // Allocate memory for a connection object
+ if ((pSpxConnFile = SpxAllocateZeroedMemory(sizeof(SPX_CONN_FILE))) == NULL)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ // Initialize values
+ pSpxConnFile->scf_Flags = 0;
+ pSpxConnFile->scf_Type = SPX_CONNFILE_SIGNATURE;
+ pSpxConnFile->scf_Size = sizeof (SPX_CONN_FILE);
+
+ CTEInitLock (&pSpxConnFile->scf_Lock);
+
+ pSpxConnFile->scf_ConnCtx = ConnCtx;
+ pSpxConnFile->scf_Device = pDevice;
+
+ // Initialize list for requests.
+ InitializeListHead(&pSpxConnFile->scf_ReqLinkage);
+ InitializeListHead(&pSpxConnFile->scf_RecvLinkage);
+ InitializeListHead(&pSpxConnFile->scf_RecvDoneLinkage);
+ InitializeListHead(&pSpxConnFile->scf_ReqDoneLinkage);
+ InitializeListHead(&pSpxConnFile->scf_DiscLinkage);
+
+#ifdef ISN_NT
+ // easy backlink to file object.
+ pSpxConnFile->scf_FileObject = IrpSp->FileObject;
+#endif
+
+ // For connections we go from 0->0 with flags indicating if a close
+ // happened.
+ pSpxConnFile->scf_RefCount = 0;
+
+ // Insert into a global connection list.
+ spxConnInsertIntoGlobalList(pSpxConnFile);
+
+#if DBG
+
+ // Initialize this to 0xFFFF so we dont hit assert on first packet.
+ pSpxConnFile->scf_PktSeqNum = 0xFFFF;
+
+#endif
+
+ // Set values in the request.
+ REQUEST_OPEN_CONTEXT(pRequest) = (PVOID)pSpxConnFile;
+ REQUEST_OPEN_TYPE(pRequest) = (PVOID)TDI_CONNECTION_FILE;
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxConnOpen: Opened %lx\n", pSpxConnFile));
+
+ ASSERT(status == STATUS_SUCCESS);
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnCleanup(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ Request - the close request.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the
+ request does not point to a real connection
+
+--*/
+
+{
+ NTSTATUS status;
+ CTELockHandle lockHandle;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ // Verify connection file
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ DBGBRK(FATAL);
+ return (status);
+ }
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxConnFileCleanup: %lx.%lx when %lx\n",
+ pSpxConnFile, Request, pSpxConnFile->scf_RefCount));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ pSpxConnFile->scf_CleanupReq = Request;
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ // We have a reference, so it wont go to zero until stop returns. Therefore
+ // deref can expect flag to be set.
+ SpxConnStop(pSpxConnFile);
+ SpxConnFileDereference (pSpxConnFile, CFREF_VERIFY);
+
+ //
+ // If this is a connection which is waiting for a local disconnect,
+ // deref it since we dont expect a disconnect after a cleanup.
+ //
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ if (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_DISC_WAIT)) {
+
+ CTEAssert( (SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED) &&
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC));
+
+ CTEAssert(pSpxConnFile->scf_RefTypes[CFREF_DISCWAITSPX]);
+
+ SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_DISC_WAIT);
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ KdPrint(("Deref for DISCWAIT on connfile: %lx\n", pSpxConnFile));
+
+ SpxConnFileDereference (pSpxConnFile, CFREF_DISCWAITSPX);
+ } else {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+
+ return STATUS_PENDING;
+}
+
+
+
+
+NTSTATUS
+SpxConnClose(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ Request - the close request.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the
+ request does not point to a real connection
+
+--*/
+
+{
+ NTSTATUS status;
+ CTELockHandle lockHandle;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ // Verify connection file
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ DBGBRK(FATAL);
+ return (status);
+ }
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxConnFileClose: %lx when %lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RefCount));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ pSpxConnFile->scf_CloseReq = Request;
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_CLOSING);
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ SpxConnFileDereference (pSpxConnFile, CFREF_VERIFY);
+ return STATUS_PENDING;
+}
+
+
+
+
+VOID
+SpxConnStop(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+ !!!Connection must have a reference when this is called!!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ CTELockHandle lockHandle;
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxConnFileStop: %lx when %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RefCount,
+ pSpxConnFile->scf_Flags));
+
+ // Call disconnect and disassociate
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_STOPPING))
+ {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_STOPPING);
+ if (!SPX_CONN_IDLE(pSpxConnFile))
+ {
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_LOCAL_DISCONNECT,
+ SPX_CALL_TDILEVEL,
+ lockHandle,
+ FALSE); // [SA] Bug #15249
+
+ }
+ else
+ {
+ // Disassociate if we are associated.
+ spxConnDisAssoc(pSpxConnFile, lockHandle);
+ }
+
+ // Lock released at this point.
+ }
+ else
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+ return;
+}
+
+
+
+
+NTSTATUS
+SpxConnAssociate(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine moves the connection from the device list to the inactive
+ connection list in the address of the address file specified. The address
+ file is pointed to by the connection and is referenced for the associate.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ PSPX_ADDR_FILE pSpxAddrFile;
+ CTELockHandle lockHandle1, lockHandle2;
+
+ BOOLEAN derefAddr = FALSE, derefConn = FALSE;
+ PFILE_OBJECT pFileObj = NULL;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+ HANDLE AddrObjHandle =
+ ((PTDI_REQUEST_KERNEL_ASSOCIATE)(REQUEST_PARAMETERS(pRequest)))->AddressHandle;
+
+ do
+ {
+ // Get the handle to the address object from the irp and map it to
+ // the corres. file object.
+ status = ObReferenceObjectByHandle(
+ AddrObjHandle,
+ 0,
+ 0,
+ KernelMode,
+ (PVOID *)&pFileObj,
+ NULL);
+
+ if (!NT_SUCCESS(status))
+ break;
+
+ pSpxAddrFile = pFileObj->FsContext;
+ ASSERT(pFileObj->FsContext2 == (PVOID)TDI_TRANSPORT_ADDRESS_FILE);
+
+ // Verify address file/connection file
+ if ((status = SpxAddrFileVerify(pSpxAddrFile)) != STATUS_SUCCESS)
+ break;
+
+ derefAddr = TRUE;
+
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ break;
+
+ derefConn = TRUE;
+
+ // Grab the addres file lock, then the connection lock for associate.
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle1);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle2);
+ if (!SPX_CONN_FLAG(pSpxConnFile, (SPX_CONNFILE_CLOSING |
+ SPX_CONNFILE_STOPPING |
+ SPX_CONNFILE_ASSOC))
+ &&
+ !(pSpxAddrFile->saf_Flags & SPX_ADDRFILE_CLOSING))
+ {
+ derefAddr = FALSE;
+ SpxAddrFileTransferReference(
+ pSpxAddrFile, AFREF_VERIFY, AFREF_CONN_ASSOC);
+
+ // Queue in the inactive list in the address
+ pSpxConnFile->scf_Next = pSpxAddrFile->saf_Addr->sa_InactiveConnList;
+ pSpxAddrFile->saf_Addr->sa_InactiveConnList = pSpxConnFile;
+
+ // Queue in the assoc list in the address file
+ pSpxConnFile->scf_AssocNext = pSpxAddrFile->saf_AssocConnList;
+ pSpxAddrFile->saf_AssocConnList = pSpxConnFile;
+
+ // Remember the addrfile in the connection
+ pSpxConnFile->scf_AddrFile = pSpxAddrFile;
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_ASSOC);
+
+ status = STATUS_SUCCESS;
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxConnAssociate: %lx with address file %lx\n",
+ pSpxConnFile, pSpxAddrFile));
+ }
+ else
+ {
+ status = STATUS_INVALID_PARAMETER;
+ }
+ CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandle2);
+ CTEFreeLock (pSpxAddrFile->saf_AddrLock, lockHandle1);
+
+ // Dereference the file object corres. to the address object
+ ObDereferenceObject(pFileObj);
+
+ } while (FALSE);
+
+ if (derefAddr)
+ {
+ SpxAddrFileDereference(pSpxAddrFile, AFREF_VERIFY);
+ }
+
+ if (derefConn)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnDisAssociate(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ CTELockHandle lockHandle;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ // Verify connection file
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ return (status);
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ if (!SPX_CONN_IDLE(pSpxConnFile)
+ ||
+ (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC)))
+ {
+ status = STATUS_INVALID_CONNECTION;
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ // Unlink it if ok.
+ if (NT_SUCCESS(status))
+ {
+ SpxConnStop(pSpxConnFile);
+ }
+
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ return(status);
+}
+
+
+
+
+NTSTATUS
+spxConnDisAssoc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ CTELockHandle lockHandleAddr;
+ PSPX_ADDR_FILE pSpxAddrFile;
+
+ if (SPX_CONN_IDLE(pSpxConnFile)
+ &&
+ (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC)))
+ {
+ pSpxAddrFile = pSpxConnFile->scf_AddrFile;
+ }
+ else
+ {
+ status = STATUS_INVALID_CONNECTION;
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ // Unlink it if ok.
+ if (NT_SUCCESS(status))
+ {
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+
+ // Check again as we had released the lock
+ if (SPX_CONN_IDLE(pSpxConnFile)
+ &&
+ (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC)))
+ {
+ pSpxConnFile->scf_AddrFile = NULL;
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_ASSOC);
+
+ // Dequeue the connection from the address file
+ spxConnRemoveFromAssocList(
+ &pSpxAddrFile->saf_AssocConnList,
+ pSpxConnFile);
+
+ // Dequeue the connection file from the address list. It must be
+ // in the inactive list.
+ spxConnRemoveFromList(
+ &pSpxAddrFile->saf_Addr->sa_InactiveConnList,
+ pSpxConnFile);
+ }
+ else
+ {
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ CTEFreeLock (&pSpxConnFile->scf_Lock, LockHandleConn);
+ CTEFreeLock (pSpxAddrFile->saf_AddrLock, lockHandleAddr);
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxConnDisAssociate: %lx from address file %lx\n",
+ pSpxConnFile, pSpxAddrFile));
+
+ if (NT_SUCCESS(status))
+ {
+ // Remove reference on address for this association.
+ SpxAddrFileDereference(pSpxAddrFile, AFREF_CONN_ASSOC);
+ }
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnConnect(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ BUGBUG:
+ We need to have another timer that will be started on the connection
+ if the tdi client indicated a timeout value. 0 -> we do not start such
+ a timer, -1 implies, we let our connection timeout values do their thing.
+ Any other value will forcibly shutdown the connect process, when the timer
+ fires.
+
+Return Value:
+
+
+--*/
+
+{
+ PTDI_REQUEST_KERNEL_CONNECT pParam;
+ TDI_ADDRESS_IPX UNALIGNED * pTdiAddr;
+ PNDIS_PACKET pCrPkt;
+ NTSTATUS status;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PSPX_FIND_ROUTE_REQUEST pFindRouteReq;
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+ PSPX_ADDR pSpxAddr;
+ BOOLEAN locksHeld = TRUE;
+
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ // Unpack the connect parameters
+ pParam = (PTDI_REQUEST_KERNEL_CONNECT)REQUEST_PARAMETERS(pRequest);
+ pTdiAddr= SpxParseTdiAddress(
+ pParam->RequestConnectionInformation->RemoteAddress);
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnConnect: Remote SOCKET %lx on %lx.%lx\n",
+ pTdiAddr->Socket,
+ pSpxConnFile,
+ pRequest));
+
+ // Check if the connection is in a valid state
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ return(status);
+ }
+
+ do
+ {
+ if ((pFindRouteReq =
+ (PSPX_FIND_ROUTE_REQUEST)SpxAllocateMemory(
+ sizeof(SPX_FIND_ROUTE_REQUEST))) == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ // Check if connection is associated, if so, the association cannot
+ // go away until the reference above is removed. So we are safe in
+ // releasing the lock.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ status = STATUS_INVALID_ADDRESS;
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC))
+ {
+ status = STATUS_SUCCESS;
+ pSpxAddr = pSpxConnFile->scf_AddrFile->saf_Addr;
+
+ // See if this connection is to be a spx2 connection.
+ SPX_CONN_RESETFLAG(pSpxConnFile,
+ (SPX_CONNFILE_SPX2 |
+ SPX_CONNFILE_NEG |
+ SPX_CONNFILE_STREAM));
+
+ if ((PARAM(CONFIG_DISABLE_SPX2) == 0) &&
+ (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_SPX2))
+ {
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnConnect: SPX2 requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG(
+ pSpxConnFile, (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
+ }
+
+ if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_STREAM)
+ {
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnConnect: SOCK_STREAM requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_STREAM);
+ }
+
+ if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_NOACKWAIT)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnConnect: NOACKWAIT requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_NOACKWAIT);
+ }
+
+ if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_IPXHDR)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleConnReq: IPXHDR requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR);
+ }
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+
+ } while (FALSE);
+
+ if (!NT_SUCCESS(status))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnConnect: Failed %lx\n", status));
+
+ if (pFindRouteReq)
+ {
+ SpxFreeMemory(pFindRouteReq);
+ }
+
+ return(status);
+ }
+
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(&pSpxAddr->sa_Lock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ locksHeld = TRUE;
+
+ status = STATUS_INVALID_CONNECTION;
+ if (SPX_CONN_IDLE(pSpxConnFile) &&
+ ((pSpxConnFile->scf_LocalConnId = spxConnGetId()) != 0))
+ {
+ //
+ // If this was a post-inactivated file, clear the disconnect flags
+ //
+ if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED)) {
+
+ SPX_DISC_SETSTATE(pSpxConnFile, 0);
+ }
+
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_CONNECTING);
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
+
+ if (((USHORT)PARAM(CONFIG_WINDOW_SIZE) == 0) ||
+ ((USHORT)PARAM(CONFIG_WINDOW_SIZE) > MAX_WINDOW_SIZE))
+ {
+ PARAM(CONFIG_WINDOW_SIZE) = DEFAULT_WINDOW_SIZE;
+ }
+
+ pSpxConnFile->scf_SentAllocNum = (USHORT)(PARAM(CONFIG_WINDOW_SIZE) - 1);
+
+ // Move connection from inactive list to non-inactive list.
+ if (!NT_SUCCESS(spxConnRemoveFromList(
+ &pSpxAddr->sa_InactiveConnList,
+ pSpxConnFile)))
+ {
+ // This should never happen!
+ KeBugCheck(0);
+ }
+
+ // Put connection in the non-inactive list. Connection id must be set.
+ SPX_INSERT_ADDR_ACTIVE(
+ pSpxAddr,
+ pSpxConnFile);
+
+ // Insert in the global connection tree on device
+ spxConnInsertIntoGlobalActiveList(
+ pSpxConnFile);
+
+ // Store the remote address in the connection.
+ // !!NOTE!! We get both the network/socket in network form.
+ *((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) =
+ *((UNALIGNED ULONG *)(&pTdiAddr->NetworkAddress));
+
+ RtlCopyMemory(
+ pSpxConnFile->scf_RemAddr+4,
+ pTdiAddr->NodeAddress,
+ 6);
+
+ *((UNALIGNED USHORT *)(pSpxConnFile->scf_RemAddr+10)) =
+ *((UNALIGNED USHORT *)(&pTdiAddr->Socket));
+
+ // Ok, we are all set, build connect packet, queue it into connection
+ // with the connect request. Ndis buffer already describes this memory
+ // Build IPX header.
+
+ pCrPkt = NULL; // so it knows to allocate one.
+
+ SpxPktBuildCr(
+ pSpxConnFile,
+ pSpxAddr,
+ &pCrPkt,
+ SPX_SENDPKT_IDLE,
+ SPX2_CONN(pSpxConnFile));
+
+ if (pCrPkt != NULL)
+ {
+ // Remember the request in the connection
+ //
+ // Dont queue for the failure case since we complete it in SpxInternalDispatch.
+ //
+ InsertTailList(
+ &pSpxConnFile->scf_ReqLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ SpxConnQueueSendPktTail(pSpxConnFile, pCrPkt);
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pCrPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ // Initialize the find route request
+ *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Network)=
+ *((UNALIGNED ULONG *)pIpxSpxHdr->hdr_DestNet);
+
+ //
+ // [SA] Bug #15094
+ // We need to also pass in the node number to IPX so that IPX can
+ // compare the node addresses to determine the proper WAN NICid
+ //
+
+ // RtlCopyMemory (pFindRouteReq->fr_FindRouteReq.Node, pIpxSpxHdr->hdr_DestNode, 6) ;
+
+ *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Node)=
+ *((UNALIGNED ULONG *)pIpxSpxHdr->hdr_DestNode);
+
+ *((UNALIGNED USHORT *)(pFindRouteReq->fr_FindRouteReq.Node+4))=
+ *((UNALIGNED USHORT *)(pIpxSpxHdr->hdr_DestNode+4));
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnConnect: NETWORK %lx\n",
+ *((UNALIGNED ULONG *)pIpxSpxHdr->hdr_DestNet)));
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnConnect: NODE %02x-%02x-%02x-%02x-%02x-%02x\n",
+ pFindRouteReq->fr_FindRouteReq.Node[0], pFindRouteReq->fr_FindRouteReq.Node[1],
+ pFindRouteReq->fr_FindRouteReq.Node[2], pFindRouteReq->fr_FindRouteReq.Node[3],
+ pFindRouteReq->fr_FindRouteReq.Node[4], pFindRouteReq->fr_FindRouteReq.Node[5]));
+
+ pFindRouteReq->fr_FindRouteReq.Identifier = IDENTIFIER_SPX;
+ pFindRouteReq->fr_Ctx = pSpxConnFile;
+
+ // We wont force a rip for every connection. Only if its not
+ // in the IPX database.
+ pFindRouteReq->fr_FindRouteReq.Type = IPX_FIND_ROUTE_RIP_IF_NEEDED;
+
+ // Reference for the find route. So that abort connect wont
+ // free up the connection until we return from here.
+ SpxConnFileLockReference(pSpxConnFile, CFREF_FINDROUTE);
+ status = STATUS_PENDING;
+ }
+ else
+ {
+ // Abort connect attempt.
+ spxConnAbortConnect(
+ pSpxConnFile,
+ status,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ CTEAssert(pSpxConnFile->scf_ConnectReq == NULL);
+
+ locksHeld = FALSE;
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ if (locksHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(&pSpxAddr->sa_Lock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ // Start off the find route request, We send the packet in completion.
+ // The verify reference is kept until the connect request completes.
+ // If connecting to network 0 we don't do this, proceed to find
+ // route completion which will send the request on very card.
+
+ if (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0) {
+
+ SpxFindRouteComplete(
+ &pFindRouteReq->fr_FindRouteReq,
+ TRUE);
+
+ } else {
+
+ (*IpxFindRoute)(
+ &pFindRouteReq->fr_FindRouteReq);
+ }
+ }
+ else
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnConnect: Failed %lx\n", status));
+
+ SpxFreeMemory(pFindRouteReq);
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnListen(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ We assume the connection passed in is already associated with an address.
+ If it is not, we will die! Is that ok?
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ CTELockHandle lockHandle1, lockHandle2;
+ PSPX_ADDR pSpxAddr;
+
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ // Check if the connection is in a valid state
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ return(status);
+ }
+
+ // Check if connection is associated, if so, the association cannot
+ // go away until the reference above is removed. So we are safe in
+ // releasing the lock.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle2);
+ status = STATUS_INVALID_ADDRESS;
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC))
+ {
+ status = STATUS_SUCCESS;
+ pSpxAddr = pSpxConnFile->scf_AddrFile->saf_Addr;
+
+ // See if this connection is to be a spx2 connection.
+ SPX_CONN_RESETFLAG(pSpxConnFile,
+ (SPX_CONNFILE_SPX2 |
+ SPX_CONNFILE_NEG |
+ SPX_CONNFILE_STREAM));
+
+ if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_SPX2)
+ {
+ SPX_CONN_SETFLAG(
+ pSpxConnFile, (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
+ }
+
+ if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_STREAM)
+ {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_STREAM);
+ }
+
+ if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_NOACKWAIT)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnConnect: NOACKWAIT requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_NOACKWAIT);
+ }
+
+ if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_IPXHDR)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleConnReq: IPXHDR requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR);
+ }
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle2);
+
+ if (NT_SUCCESS(status))
+ {
+ CTEGetLock(&pSpxAddr->sa_Lock, &lockHandle1);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle2);
+ status = STATUS_INVALID_CONNECTION;
+ if (SPX_CONN_IDLE(pSpxConnFile))
+ {
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_LISTENING);
+
+ // Move connection from inactive list to listening list.
+ if (NT_SUCCESS(spxConnRemoveFromList(
+ &pSpxAddr->sa_InactiveConnList,
+ pSpxConnFile)))
+ {
+ // Put connection in the listening list.
+ SPX_INSERT_ADDR_LISTEN(pSpxAddr, pSpxConnFile);
+
+ InsertTailList(
+ &pSpxConnFile->scf_ReqLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ status = STATUS_PENDING;
+ }
+ else
+ {
+ // This should never happen!
+ KeBugCheck(0);
+ }
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle2);
+ CTEFreeLock(&pSpxAddr->sa_Lock, lockHandle1);
+ }
+
+
+ if (!NT_SUCCESS(status))
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnAccept(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_ADDR pSpxAddr;
+ NTSTATUS status;
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnAccept: %lx\n", pSpxConnFile));
+
+ // Check if the connection is in a valid state
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ return (status);
+ }
+
+ // Check if we are in the correct state and associated.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ status = STATUS_INVALID_CONNECTION;
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC))
+ {
+ status = STATUS_SUCCESS;
+ pSpxAddr = pSpxConnFile->scf_AddrFile->saf_Addr;
+ }
+ CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandleConn);
+
+ if (NT_SUCCESS(status))
+ {
+ // Grab all three locks
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ status = STATUS_INVALID_CONNECTION;
+ if ((SPX_CONN_LISTENING(pSpxConnFile)) &&
+ (SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_RECDREQ))
+ {
+ InsertTailList(
+ &pSpxConnFile->scf_ReqLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // Call acceptcr now.
+ spxConnAcceptCr(
+ pSpxConnFile,
+ pSpxAddr,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnAccept: Accepted\n"));
+
+ status = STATUS_PENDING;
+ }
+ else
+ {
+ // Free all locks.
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ }
+ }
+
+ // Remove reference. Note: Listen reference will exist if ok. And that will
+ // be transferred to the fact that the connection is active when accepted.
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnDisconnect(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+/*++
+
+Routine Description:
+
+ If active, we do the following.
+ If informative disconnect, just remember the request in the connection.
+ We do not ref for request. Assume it will always be checked for when
+ changing from disconnect to idle.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PTDI_REQUEST_KERNEL_DISCONNECT pParam;
+ NTSTATUS status;
+ CTELockHandle lockHandleConn;
+ BOOLEAN lockHeld;
+ SPX_SENDREQ_TYPE reqType;
+ int numDerefs = 0;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ pParam = (PTDI_REQUEST_KERNEL_DISCONNECT)REQUEST_PARAMETERS(pRequest);
+
+ // Check if the connection is in a valid state
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ return(status);
+ }
+
+ // Deref unless the disc request gets queued in as a send request.
+ numDerefs++;
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnDisconnect: %lx On %lx when %lx.%lx %lx Params %lx\n",
+ pRequest, pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile),
+ SPX_DISC_STATE(pSpxConnFile),
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC),
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC),
+ pParam->RequestFlags));
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnDisconnect: %lx\n", pSpxConnFile));
+
+ // Check if we are in the correct state and associated.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ lockHeld = TRUE;
+ switch (pParam->RequestFlags)
+ {
+ case TDI_DISCONNECT_WAIT:
+
+ // If informative disconnect, just remember in the connection.
+ status = STATUS_INVALID_CONNECTION;
+ if (!SPX_CONN_IDLE(pSpxConnFile))
+ {
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ status = STATUS_PENDING;
+ }
+
+ break;
+
+ case TDI_DISCONNECT_ABORT:
+ case TDI_DISCONNECT_RELEASE:
+
+ // NOTE! We don't honor the async disconnect symantics of tdi
+ // but map them to an abortive disconnect.
+ // NOTE! If our send list is not empty but our client tries to
+ // do a orderly release, we just queue the ord rel as a send
+ // data request. In process ack, we check for the next packet
+ // to not be a ord rel before giving up on window closure.
+ // NOTE! For spx1 connection, map TDI_DISCONNECT_RELEASE to
+ // TDI_DISCONNECT_ABORT (Informed disconnect)
+
+ if (!SPX2_CONN(pSpxConnFile))
+ {
+ pParam->RequestFlags = TDI_DISCONNECT_ABORT;
+ }
+
+ switch (SPX_MAIN_STATE(pSpxConnFile))
+ {
+ case SPX_CONNFILE_ACTIVE:
+
+ // Since we are not a timer disconnect, then we need to keep
+ // retrying the disconnect packet. Change state to DISCONN if this
+ // is not an orderly release or we previously received an orderly
+ // release and are now confirming it.
+ // Retry timer will now keep sending out the disconnect packet.
+
+ reqType = SPX_REQ_DISC;
+ if (pParam->RequestFlags == TDI_DISCONNECT_RELEASE)
+ {
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_POST_ORDREL);
+ reqType = SPX_REQ_ORDREL;
+ }
+ else
+ {
+ // Abortive disconnect
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_DISCONN);
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_POST_IDISC);
+ numDerefs++;
+
+ spxConnAbortSends(
+ pSpxConnFile,
+ STATUS_LOCAL_DISCONNECT,
+ SPX_CALL_TDILEVEL,
+ lockHandleConn);
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ // Abort all receives if we are informed disconnect.
+ spxConnAbortRecvs(
+ pSpxConnFile,
+ STATUS_LOCAL_DISCONNECT,
+ SPX_CALL_TDILEVEL,
+ lockHandleConn);
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ // Since we released the lock, a remote IDISC could have come
+ // in in which case we really don't want to queue in the disc
+ // request. Instead, we set it as the disc request in the
+ // connection if one is not already there.
+ if (SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_POST_IDISC)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnDisconnect: DISC not POST! %lx.%lx\n",
+ pSpxConnFile, SPX_DISC_STATE(pSpxConnFile)));
+
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ status = STATUS_PENDING;
+ break;
+ }
+ }
+
+ // !NOTE
+ // AbortSends might leave send requests around as packets might
+ // have been with ipx at the time. That is why SendComplete should
+ // never call AbortSends but must call AbortPkt else it may complete
+ // the following disconnect request prematurely.
+
+ // Creation reference for request.
+ REQUEST_INFORMATION(pRequest) = 1;
+
+ // If we have no current requests, queue it in and
+ // set it to be the current request, else just queue it in.
+ // There may be other pending requests in queue.
+ if (pSpxConnFile->scf_ReqPkt == NULL)
+ {
+ pSpxConnFile->scf_ReqPkt = pRequest;
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pSpxConnFile->scf_ReqPktSize = 0;
+ pSpxConnFile->scf_ReqPktType = reqType;
+ }
+
+ InsertTailList(
+ &pSpxConnFile->scf_ReqLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // Do not deref the connection, it is taken by the pending request
+ numDerefs--;
+
+ // We packetize only upto the window we have.
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE)
+ {
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_PACKETIZE);
+ SpxConnPacketize(
+ pSpxConnFile,
+ TRUE,
+ lockHandleConn);
+
+ lockHeld = FALSE;
+ }
+
+ status = STATUS_PENDING;
+ break;
+
+ case SPX_CONNFILE_CONNECTING:
+ case SPX_CONNFILE_LISTENING:
+
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_INSUFFICIENT_RESOURCES,
+ SPX_CALL_TDILEVEL,
+ lockHandleConn,
+ FALSE); // [SA] Bug #15249
+
+ lockHeld = FALSE;
+ status = STATUS_SUCCESS;
+ break;
+
+ case SPX_CONNFILE_DISCONN:
+
+ // When we queue in a disconnect as a send request, we expect
+ // to be able to set it into the scf_DiscReq when it is done.
+ // So we don't use scf_DiscReq here. This will be a problem if
+ // the client has a InformDiscReq pending, and a remote disconnect
+ // comes in, *and* the client then does a disc. We will be completing
+ // the request with STATUS_INVALID_CONNECTION.
+ status = STATUS_INVALID_CONNECTION;
+ if (pParam->RequestFlags != TDI_DISCONNECT_RELEASE)
+ {
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ status = STATUS_PENDING;
+
+ //
+ // If this is a disconnect for a connection which was already
+ // disconnected (but AFD's disconnect handler was not called
+ // because the connfile could not be placed in the inactive list),
+ // set this flag so that the disconnect is not called from
+ // ConnInactivate now that the disconnect has occured here.
+ //
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC)) {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
+ }
+
+ //
+ // If this was an SPXI connection where we indicated TDI_DISCONNECT_RELEASE
+ // to AFD, the ref count was bumped up to indicate a wait for local disconnect
+ // from AFD. Now that we have this disconnect, deref the connection file. Now
+ // we are ready to truly inactivate this connection file.
+ //
+ if (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_DISC_WAIT)) {
+
+ CTEAssert( (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED) &&
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC));
+
+ CTEAssert(pSpxConnFile->scf_RefTypes[CFREF_DISCWAITSPX]);
+
+ SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_DISC_WAIT);
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ lockHeld = FALSE;
+
+ SpxConnFileDereference(pSpxConnFile, CFREF_DISCWAITSPX);
+ }
+ }
+
+ break;
+
+ default:
+
+ // Should never happen!
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ break;
+
+ default:
+
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ }
+
+ DBGPRINT(CONNECT, INFO,
+ ("SpxConnDisconnect: returning for %lx.%lx\n", pSpxConnFile, status));
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnSend(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PTDI_REQUEST_KERNEL_SEND pParam;
+ NTSTATUS status;
+ CTELockHandle lockHandleConn;
+ BOOLEAN lockHeld;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ pParam = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(pRequest);
+
+ // Check if the connection is in a valid state
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ return(status);
+ }
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnSend: %lx.%lx.%lx.%lx\n",
+ pSpxConnFile, pRequest, pParam->SendLength, pParam->SendFlags));
+
+
+ // Check if we are in the correct state and associated.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ lockHeld = TRUE;
+
+ DBGPRINT(SEND, INFO,
+ ("Send: %lx.%lx.%lx\n",
+ pParam->SendLength, pParam->SendFlags, pRequest));
+
+ status = STATUS_PENDING;
+ do
+ {
+ if (SPX_CONN_ACTIVE(pSpxConnFile) &&
+ ((SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_POST_ORDREL) &&
+ (SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_SENT_ORDREL) &&
+ (SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_ORDREL_ACKED)))
+ {
+ // Creation reference for request.
+ REQUEST_INFORMATION(pRequest) = 1;
+
+ // If we have no current requests, queue it in and
+ // set it to be the current request, else just queue it in.
+ // There may be other pending requests in queue.
+ if (pSpxConnFile->scf_ReqPkt == NULL)
+ {
+ DBGPRINT(SEND, INFO,
+ ("%lx\n",
+ pRequest));
+
+ pSpxConnFile->scf_ReqPkt = pRequest;
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pSpxConnFile->scf_ReqPktSize = pParam->SendLength;
+ pSpxConnFile->scf_ReqPktFlags = pParam->SendFlags;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DATA;
+ }
+
+ InsertTailList(
+ &pSpxConnFile->scf_ReqLinkage,
+ REQUEST_LINKAGE(pRequest));
+ }
+ else
+ {
+ //
+ // [SA] Bug #14655
+ // Return the correct error message in case a send fails due to remote disconnect
+ //
+
+ if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ ((SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT) ||
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED)))
+ {
+ status = STATUS_REMOTE_DISCONNECT ;
+ }
+ else
+ {
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ break;
+ }
+
+ // We packetize only upto the window we have.
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE)
+ {
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_PACKETIZE);
+ SpxConnPacketize(pSpxConnFile, TRUE, lockHandleConn);
+ lockHeld = FALSE;
+ }
+
+ } while (FALSE);
+
+
+ if (lockHeld)
+ {
+ CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandleConn);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnRecv(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS status;
+ CTELockHandle lockHandle;
+ BOOLEAN fLockHeld;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ // Check if the connection is in a valid state
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ return(status);
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnReceive: %lx.%lx\n", pSpxConnFile, pRequest));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ fLockHeld = TRUE;
+ status = STATUS_INVALID_CONNECTION;
+ if (SPX_CONN_ACTIVE(pSpxConnFile) &&
+ !(SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC)))
+ {
+ status = STATUS_PENDING;
+
+ // This routine adds its own reference.
+ SpxConnQueueRecv(pSpxConnFile, pRequest);
+
+ // If recv pkt queue is non-empty then we have buffered data. Call
+ // process pkts/receives.
+ if ((SPX_RECV_STATE(pSpxConnFile) == SPX_RECV_IDLE) ||
+ (SPX_RECV_STATE(pSpxConnFile) == SPX_RECV_POSTED))
+ {
+ SpxRecvProcessPkts(pSpxConnFile, lockHandle);
+ fLockHeld = FALSE;
+ }
+ }
+
+ if (fLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnAction(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS Status;
+ UINT BufferLength;
+ UINT DataLength;
+ PNDIS_BUFFER NdisBuffer;
+ PNWLINK_ACTION NwlinkAction;
+ CTELockHandle lockHandle;
+ PIPX_SPXCONNSTATUS_DATA pGetStats;
+ PSPX_CONN_FILE pSpxConnFile = NULL;
+ PSPX_ADDR_FILE pSpxAddrFile = NULL;
+ static UCHAR BogusId[4] = { 0x01, 0x00, 0x00, 0x00 }; // old nwrdr uses this
+
+ //
+ // To maintain some compatibility with the NWLINK streams-
+ // based transport, we use the streams header format for
+ // our actions. The old transport expected the action header
+ // to be in InputBuffer and the output to go in OutputBuffer.
+ // We follow the TDI spec, which states that OutputBuffer
+ // is used for both input and output. Since IOCTL_TDI_ACTION
+ // is method out direct, this means that the output buffer
+ // is mapped by the MDL chain; for action the chain will
+ // only have one piece so we use it for input and output.
+ //
+
+ NdisBuffer = REQUEST_NDIS_BUFFER(pRequest);
+ if (NdisBuffer == NULL)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ NdisQueryBuffer(
+ REQUEST_NDIS_BUFFER(pRequest), (PVOID *)&NwlinkAction, &BufferLength);
+
+ if ((!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MISN", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MIPX", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "XPIM", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), BogusId, 4))) {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ // Make sure we have enough room for just the header not
+ // including the data.
+ if (BufferLength < (UINT)(FIELD_OFFSET(NWLINK_ACTION, Data[0])))
+ {
+ DBGPRINT(ACTION, ERR,
+ ("Nwlink action failed, buffer too small\n"));
+
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ DataLength = BufferLength - FIELD_OFFSET(NWLINK_ACTION, Data[0]);
+
+ // Make sure that the correct file object is being used.
+ switch (NwlinkAction->OptionType)
+ {
+ case NWLINK_OPTION_CONNECTION:
+
+ if (REQUEST_OPEN_TYPE(pRequest) != (PVOID)TDI_CONNECTION_FILE)
+ {
+ DBGPRINT(ACTION, ERR,
+ ("Nwlink action failed, not connection file\n"));
+
+ return STATUS_INVALID_HANDLE;
+ }
+
+ pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ if ((Status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ return(Status);
+
+ break;
+
+ case NWLINK_OPTION_ADDRESS:
+
+ if (REQUEST_OPEN_TYPE(pRequest) != (PVOID)TDI_TRANSPORT_ADDRESS_FILE)
+ {
+ DBGPRINT(ACTION, ERR,
+ ("Nwlink action failed, not address file\n"));
+
+ return STATUS_INVALID_HANDLE;
+ }
+
+ pSpxAddrFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ if ((Status = SpxAddrFileVerify(pSpxAddrFile)) != STATUS_SUCCESS)
+ return(Status);
+
+ break;
+
+ default:
+
+ DBGPRINT(ACTION, ERR,
+ ("Nwlink action failed, option type %d\n",
+ NwlinkAction->OptionType));
+
+ return STATUS_INVALID_HANDLE;
+ }
+
+ // Handle the requests based on the action code. For these
+ // requests ActionHeader->ActionCode is 0, we use the
+ // Option field in the streams header instead.
+
+ Status = STATUS_SUCCESS;
+
+ DBGPRINT(ACTION, INFO,
+ ("SpxConnAction: Option %x\n", NwlinkAction->Option));
+
+ switch (NwlinkAction->Option)
+ {
+
+ //
+ // This first group support the winsock helper dll.
+ // In most cases the corresponding sockopt is shown in
+ // the comment, as well as the contents of the Data
+ // part of the action buffer.
+ //
+
+ case MSPX_SETDATASTREAM:
+
+ if (pSpxConnFile == NULL)
+ {
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ if (DataLength >= 1)
+ {
+ DBGPRINT(ACTION, INFO,
+ ("%lx: MIPX_SETSENDPTYPE %x\n",
+ pSpxConnFile, NwlinkAction->Data[0]));
+
+ pSpxConnFile->scf_DataType = NwlinkAction->Data[0];
+ }
+ else
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+
+ case MSPX_SENDHEADER:
+
+ DBGPRINT(ACTION, INFO,
+ ("%lx: MSPX_SENDHEADER\n", pSpxAddrFile));
+
+ if (pSpxAddrFile == NULL)
+ {
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle);
+ pSpxAddrFile->saf_Flags |= SPX_ADDRFILE_IPXHDR;
+ CTEFreeLock(pSpxAddrFile->saf_AddrLock, lockHandle);
+ break ;
+
+ case MSPX_NOSENDHEADER:
+
+ DBGPRINT(ACTION, INFO,
+ ("%lx: MSPX_NOSENDHEADER\n", pSpxAddrFile));
+
+ if (pSpxAddrFile == NULL)
+ {
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle);
+ pSpxAddrFile->saf_Flags &= ~SPX_ADDRFILE_IPXHDR;
+ CTEFreeLock(pSpxAddrFile->saf_AddrLock, lockHandle);
+ break;
+
+ case MSPX_GETSTATS:
+
+ DBGPRINT(ACTION, INFO,
+ ("%lx: MSPX_GETSTATS\n", pSpxConnFile));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ if (!SPX_CONN_IDLE(pSpxConnFile))
+ {
+ USHORT TempRetryCount;
+
+ //
+ // Status fields are returned in network order.
+ //
+
+ pGetStats = (PIPX_SPXCONNSTATUS_DATA)&NwlinkAction->Data[0];
+
+ switch (SPX_MAIN_STATE(pSpxConnFile)) {
+ case SPX_CONNFILE_LISTENING: pGetStats->ConnectionState = 1; break;
+ case SPX_CONNFILE_CONNECTING: pGetStats->ConnectionState = 2; break;
+ case SPX_CONNFILE_ACTIVE: pGetStats->ConnectionState = 3; break;
+ case SPX_CONNFILE_DISCONN: pGetStats->ConnectionState = 4; break;
+ default: pGetStats->ConnectionState = 0;
+ }
+ pGetStats->WatchDogActive = 1; // Always 1
+ GETSHORT2SHORT( // scf_LocalConnId is in host order
+ &pGetStats->LocalConnectionId,
+ &pSpxConnFile->scf_LocalConnId);
+ pGetStats->RemoteConnectionId = pSpxConnFile->scf_RemConnId;
+
+ GETSHORT2SHORT(&pGetStats->LocalSequenceNumber, &pSpxConnFile->scf_SendSeqNum);
+ GETSHORT2SHORT(&pGetStats->LocalAckNumber, &pSpxConnFile->scf_RecvSeqNum);
+ GETSHORT2SHORT(&pGetStats->LocalAllocNumber, &pSpxConnFile->scf_SentAllocNum);
+ GETSHORT2SHORT(&pGetStats->RemoteAckNumber, &pSpxConnFile->scf_RecdAckNum);
+ GETSHORT2SHORT(&pGetStats->RemoteAllocNumber, &pSpxConnFile->scf_RecdAllocNum);
+
+ pGetStats->LocalSocket = pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket;
+
+ RtlZeroMemory(pGetStats->ImmediateAddress, 6);
+
+ // Remote network returned in net order.
+ *((ULONG UNALIGNED *)pGetStats->RemoteNetwork) =
+ *((ULONG UNALIGNED *)pSpxConnFile->scf_RemAddr);
+
+ RtlCopyMemory(
+ pGetStats->RemoteNode,
+ &pSpxConnFile->scf_RemAddr[4],
+ 6);
+
+ pGetStats->RemoteSocket = *((UNALIGNED USHORT *)(pSpxConnFile->scf_RemAddr+10));
+
+ TempRetryCount = (USHORT)pSpxConnFile->scf_WRetryCount;
+ GETSHORT2SHORT(&pGetStats->RetransmissionCount, &TempRetryCount);
+ GETSHORT2SHORT(&pGetStats->EstimatedRoundTripDelay, &pSpxConnFile->scf_BaseT1);
+ pGetStats->RetransmittedPackets = 0;
+ pGetStats->SuppressedPacket = 0;
+
+ DBGPRINT(ACTION, INFO,
+ ("SSeq %lx RSeq %lx RecdAck %lx RemAllocNum %lx\n",
+ pGetStats->LocalSequenceNumber,
+ pGetStats->LocalAckNumber,
+ pGetStats->RemoteAckNumber,
+ pGetStats->RemoteAllocNumber));
+
+ DBGPRINT(ACTION, INFO,
+ ("LocalSkt %lx RemSkt %lx LocConnId %lx RemConnId %lx\n",
+ pGetStats->LocalSocket,
+ pGetStats->RemoteSocket,
+ pGetStats->LocalConnectionId,
+ pGetStats->RemoteConnectionId));
+ }
+ else
+ {
+ Status = STATUS_INVALID_CONNECTION;
+ }
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ break;
+
+ case MSPX_NOACKWAIT:
+
+ DBGPRINT(ACTION, ERR,
+ ("%lx: MSPX_NOACKWAIT\n", pSpxAddrFile));
+
+ if (pSpxAddrFile == NULL)
+ {
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle);
+ pSpxAddrFile->saf_Flags |= SPX_ADDRFILE_NOACKWAIT;
+ CTEFreeLock(pSpxAddrFile->saf_AddrLock, lockHandle);
+ break;
+
+ case MSPX_ACKWAIT:
+
+ DBGPRINT(ACTION, ERR,
+ ("%lx: MSPX_ACKWAIT\n", pSpxAddrFile));
+
+ if (pSpxAddrFile == NULL)
+ {
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle);
+ pSpxAddrFile->saf_Flags &= ~SPX_ADDRFILE_NOACKWAIT;
+ CTEFreeLock(pSpxAddrFile->saf_AddrLock, lockHandle);
+ break;
+
+
+ //
+ // These are new for ISN (not supported in NWLINK).
+ //
+
+ // The Option was not supported, so fail.
+ default:
+
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+
+
+ } // end of the long switch on NwlinkAction->Option
+
+
+#if DBG
+ if (Status != STATUS_SUCCESS) {
+ DBGPRINT(ACTION, ERR,
+ ("Nwlink action %lx failed, status %lx\n",
+ NwlinkAction->Option, Status));
+ }
+
+#endif
+
+ if (pSpxConnFile)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ if (pSpxAddrFile)
+ {
+ SpxAddrFileDereference(pSpxAddrFile, AFREF_VERIFY);
+ }
+
+ return Status;
+}
+
+
+
+
+VOID
+SpxConnConnectFindRouteComplete(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_FIND_ROUTE_REQUEST pFrReq,
+ IN BOOLEAN FoundRoute,
+ IN CTELockHandle LockHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine is called with the connection lock held and the conn refd.
+ It should deal with both.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pCrPkt;
+ PSPX_SEND_RESD pSendResd;
+ ULONG Timeout;
+ NTSTATUS status = STATUS_BAD_NETWORK_PATH;
+
+ pSendResd = pSpxConnFile->scf_SendListHead;
+ pCrPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ DBGPRINT(CONNECT, INFO,
+ ("SpxConnConnectFindRouteComplete: %lx.%d\n",
+ pSpxConnFile, FoundRoute));
+
+#if defined(_PNP_POWER)
+
+ Timeout = PARAM(CONFIG_CONNECTION_TIMEOUT) * HALFSEC_TO_MS_FACTOR;
+#else
+ if (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0) {
+
+ // Here we are going to send on every NIC ID. We adjust the
+ // timeout down so that a full run through all the NIC IDs will
+ // take one normal timeout. We don't adjust the timer below
+ // 100 ms however.
+
+ Timeout = (PARAM(CONFIG_CONNECTION_TIMEOUT) * HALFSEC_TO_MS_FACTOR) / SpxDevice->dev_Adapters;
+ if (Timeout < (HALFSEC_TO_MS_FACTOR/5)) {
+ Timeout = HALFSEC_TO_MS_FACTOR / 5;
+ }
+
+ } else {
+
+ Timeout = PARAM(CONFIG_CONNECTION_TIMEOUT) * HALFSEC_TO_MS_FACTOR;
+ }
+#endif
+
+
+ // Timeout value is in half-seconds
+ if ((FoundRoute) &&
+ ((pSpxConnFile->scf_CTimerId =
+ SpxTimerScheduleEvent(
+ spxConnConnectTimer,
+ Timeout,
+ pSpxConnFile)) != 0))
+ {
+ // Add a reference for the connect timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+
+#if 0
+ {
+ int i;
+ char *address = pFrReq->fr_FindRouteReq.LocalTarget.MacAddress;
+
+ DbgPrint("FIND ROUTE LOCALTARGET.MAC:\n");
+ for (i= 0; i < 6; i++)
+ {
+ UCHAR ch1, ch2;
+
+ ch1 = ((address[i] >> 4) & 0x0F);
+ if (ch1 > 0x9)
+ {
+ ch1 -= 0xa;
+ ch1 += 'a';
+ }
+ else
+ {
+ ch1 += '0';
+ }
+
+ ch2 = (address[i] & 0x0F);
+ if (ch2 > 0x9)
+ {
+ ch2 -= 0xa;
+ ch2 += 'a';
+ }
+ else
+ {
+ ch2 += '0';
+ }
+
+ DbgPrint("%c%c", ch1, ch2);
+ }
+ DbgPrint("\n");
+
+ address = pSpxConnFile->scf_RemAddr+4;
+ DbgPrint("SPX DESTINATION ADDRESS:\n");
+ for (i= 0; i < 6; i++)
+ {
+ UCHAR ch1, ch2;
+
+ ch1 = ((address[i] >> 4) & 0x0F);
+ if (ch1 > 0x9)
+ {
+ ch1 -= 0xa;
+ ch1 += 'a';
+ }
+ else
+ {
+ ch1 += '0';
+ }
+
+ ch2 = (address[i] & 0x0F);
+ if (ch2 > 0x9)
+ {
+ ch2 -= 0xa;
+ ch2 += 'a';
+ }
+ else
+ {
+ ch2 += '0';
+ }
+
+ DbgPrint("%c%c", ch1, ch2);
+ }
+ DbgPrint("\n");
+ }
+
+ DbgPrint("NIC Id %lx\n", pFrReq->fr_FindRouteReq.LocalTarget.NicId);
+#endif
+
+ // If the mac address in local target is all zeros, fill it with our
+ // destination address. Also if this is a connect to network 0 fill
+ // it in with the destination address, and further down we will loop
+ // through all possible NIC IDs.
+ if (((*((UNALIGNED ULONG *)
+ (pFrReq->fr_FindRouteReq.LocalTarget.MacAddress+2)) == (ULONG)0)
+ &&
+ (*((UNALIGNED USHORT *)
+ (pFrReq->fr_FindRouteReq.LocalTarget.MacAddress+4)) == (USHORT)0))
+ ||
+ (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0))
+ {
+ DBGPRINT(CONNECT, INFO,
+ ("SpxConnConnectFindRouteComplete: LOCAL NET\n"));
+
+ RtlCopyMemory(
+ pFrReq->fr_FindRouteReq.LocalTarget.MacAddress,
+ pSpxConnFile->scf_RemAddr+4,
+ 6);
+ }
+
+ // We are all set to go ahead with the connect.
+ // Timer is started on connection
+ status = STATUS_SUCCESS;
+
+#if defined(_PNP_POWER)
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
+#else
+ if (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0) {
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT) * SpxDevice->dev_Adapters;
+ } else {
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
+ }
+#endif _PNP_POWER
+
+ SPX_CONN_SETFLAG(pSpxConnFile,
+ (SPX_CONNFILE_C_TIMER | SPX_CONNECT_SENTREQ));
+
+ pSpxConnFile->scf_LocalTarget = pFrReq->fr_FindRouteReq.LocalTarget;
+ pSpxConnFile->scf_AckLocalTarget= pFrReq->fr_FindRouteReq.LocalTarget;
+ if (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0) {
+#if defined(_PNP_POWER)
+ pSpxConnFile->scf_LocalTarget.NicHandle.NicId = (USHORT)ITERATIVE_NIC_ID;
+ pSpxConnFile->scf_AckLocalTarget.NicHandle.NicId = (USHORT)ITERATIVE_NIC_ID;
+#else
+ pSpxConnFile->scf_LocalTarget.NicId = 1;
+ pSpxConnFile->scf_AckLocalTarget.NicId = 1;
+#endif _PNP_POWER
+ }
+
+ // We will be giving the packet to ipx.
+ pSendResd->sr_State |= SPX_SENDPKT_IPXOWNS;
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandle);
+
+ // Send the packet
+ SPX_SENDPACKET(pSpxConnFile, pCrPkt, pSendResd);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandle);
+
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnConnectFindRouteComplete: FAILED on %lx.%d\n",
+ pSpxConnFile, FoundRoute));
+
+ spxConnAbortConnect(
+ pSpxConnFile,
+ status,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+ }
+
+ // Remove the reference for the call.
+ SpxConnFileDereference(pSpxConnFile, CFREF_FINDROUTE);
+ return;
+}
+
+
+
+
+VOID
+SpxConnActiveFindRouteComplete(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_FIND_ROUTE_REQUEST pFrReq,
+ IN BOOLEAN FoundRoute,
+ IN CTELockHandle LockHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine is called with the connection lock held and the conn refd.
+ It should deal with both.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ BOOLEAN fDisconnect = TRUE;
+
+ SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_FINDROUTE);
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnActiveFindRouteComplete: %lx.%lx\n",
+ pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ // If we are disconnecting, just remove the reference and exit.
+ if (SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_ACTIVE)
+ {
+ fDisconnect = FALSE;
+
+ // We are here if either the wdog or the retry timer did a find
+ // route. We need to save the info from the find route if it was
+ // successful and just restart the timers.
+ if (FoundRoute)
+ {
+ // If the mac address in local target is all zeros, fill it with our
+ // destination address.
+ if ((*((UNALIGNED ULONG *)
+ (pFrReq->fr_FindRouteReq.LocalTarget.MacAddress+2)) == (ULONG)0)
+ &&
+ (*((UNALIGNED USHORT *)
+ (pFrReq->fr_FindRouteReq.LocalTarget.MacAddress+4)) == (USHORT)0))
+ {
+ DBGPRINT(CONNECT, INFO,
+ ("SpxConnActiveFindRouteComplete: LOCAL NET\n"));
+
+ RtlCopyMemory(
+ pFrReq->fr_FindRouteReq.LocalTarget.MacAddress,
+ pSpxConnFile->scf_RemAddr+4,
+ 6);
+ }
+
+ pSpxConnFile->scf_LocalTarget = pFrReq->fr_FindRouteReq.LocalTarget;
+ }
+
+ // Depending on state restart the wdog or retry timer. Add reference
+ // for it.
+ switch (SPX_SEND_STATE(pSpxConnFile))
+ {
+ case SPX_SEND_RETRY:
+
+ // Set state to SPX_SEND_RETRYWD
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRYWD);
+
+ // Start retry timer.
+ if ((pSpxConnFile->scf_RTimerId =
+ SpxTimerScheduleEvent(
+ spxConnRetryTimer,
+ pSpxConnFile->scf_BaseT1,
+ pSpxConnFile)) != 0)
+ {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
+
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ }
+ else
+ {
+ fDisconnect = TRUE;
+ }
+
+ break;
+
+ case SPX_SEND_WD:
+
+ // Start watchdog timer.
+ if ((pSpxConnFile->scf_WTimerId =
+ SpxTimerScheduleEvent(
+ spxConnWatchdogTimer,
+ PARAM(CONFIG_KEEPALIVE_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) != 0)
+ {
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ }
+ else
+ {
+ fDisconnect = TRUE;
+ }
+
+ break;
+
+ case SPX_SEND_IDLE:
+ case SPX_SEND_PACKETIZE:
+
+ // Do nothing, remove reference and leave.
+ break;
+
+ default:
+
+ KeBugCheck(0);
+ }
+ }
+
+ if (fDisconnect)
+ {
+ DBGPRINT(CONNECT, DBG1,
+ ("SpxConnActiveFindRouteComplete: DISCONNECT %lx.%lx\n",
+ pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ // Abortive disc will reset the funky state if necessary.
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_INSUFFICIENT_RESOURCES,
+ SPX_CALL_TDILEVEL,
+ LockHandle,
+ FALSE); // [SA] Bug #15249
+ }
+ else
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandle);
+ }
+
+ SpxConnFileDereference(pSpxConnFile, CFREF_FINDROUTE);
+ return;
+}
+
+
+
+
+ULONG
+spxConnConnectTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown
+ )
+/*++
+
+Routine Description:
+
+ We enter this routine during the connection attempt. We could be at any
+ stage of sending either the CR or the SN packet. If we have reached the end of
+ the retry count, we need to know the substate at that point. For a CR, we give
+ up trying to connect, and for a SN we try the next lower packet size or if we
+ have reached the minimum packet size, we give up the connect.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)Context;
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+ BOOLEAN fAbort = FALSE, locksHeld = FALSE, sendPkt = FALSE;
+ PREQUEST pRequest = NULL;
+
+ // Get all locks
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ locksHeld = TRUE;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnConnectTimer: Entered\n"));
+
+ do
+ {
+ if ((!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER)) ||
+ (!SPX_CONN_CONNECTING(pSpxConnFile) &&
+ !SPX_CONN_LISTENING(pSpxConnFile)))
+ {
+ TimerShuttingDown = TRUE;
+ }
+
+ if (TimerShuttingDown)
+ {
+ break;
+ }
+
+ if (SPX_CONN_CONNECTING(pSpxConnFile))
+ {
+ switch (SPX_CONNECT_STATE(pSpxConnFile))
+ {
+ case SPX_CONNECT_SENTREQ:
+
+ // There should be only one packet in list, the cr.
+ CTEAssert(pSpxConnFile->scf_SendListHead ==
+ pSpxConnFile->scf_SendListTail);
+
+ pSendResd = pSpxConnFile->scf_SendListHead;
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd,
+ NDIS_PACKET,
+ ProtocolReserved);
+
+ if (pSpxConnFile->scf_CRetryCount-- == 0)
+ {
+ // No luck, we need to complete connect request with failure
+ ++SpxDevice->dev_Stat.NotFoundFailures;
+ fAbort = TRUE;
+ break;
+ }
+
+ // We need to resend the packet
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0)
+ {
+ // Try next time.
+ break;
+ }
+
+ pSendResd->sr_State |= SPX_SENDPKT_IPXOWNS;
+ sendPkt = TRUE;
+ break;
+
+ case SPX_CONNECT_NEG:
+
+ if (!spxConnGetPktByType(
+ pSpxConnFile,
+ SPX_TYPE_SN,
+ FALSE,
+ &pPkt))
+ {
+ KeBugCheck(0);
+ }
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0)
+ {
+ // Try when we come in next.
+ break;
+ }
+
+
+ // If we have exhausted current retries, try next smaller size.
+ // If this was the smallest size, we abort.
+ if (pSpxConnFile->scf_CRetryCount-- == 0)
+ {
+ // Have we tried the smallest size?
+ CTEAssert(pSpxConnFile->scf_MaxPktSize > 0);
+ if (!spxConnCheckNegSize(&pSpxConnFile->scf_MaxPktSize))
+ {
+ // Give up! Remove negotiate packet etc.
+ ++SpxDevice->dev_Stat.SessionTimeouts;
+ fAbort = TRUE;
+ break;
+ }
+
+ // Set neg pkt size to new lower size
+ spxConnSetNegSize(
+ pPkt,
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE);
+
+ pSpxConnFile->scf_CRetryCount =
+ PARAM(CONFIG_CONNECTION_COUNT);
+ }
+
+ // We need to resend the packet
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0);
+ pSendResd->sr_State |= SPX_SENDPKT_IPXOWNS;
+ sendPkt = TRUE;
+ break;
+
+ case SPX_CONNECT_W_SETUP:
+ default:
+
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnConnectTimer: state is W_Setup %lx\n",
+ pSpxConnFile));
+
+ KeBugCheck(0);
+ }
+ }
+ else
+ {
+ switch (SPX_LISTEN_STATE(pSpxConnFile))
+ {
+ case SPX_LISTEN_SETUP:
+
+ if (!spxConnGetPktByType(
+ pSpxConnFile,
+ SPX_TYPE_SS,
+ FALSE,
+ &pPkt))
+ {
+ KeBugCheck(0);
+ }
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0)
+ {
+ // Try when we come in next.
+ break;
+ }
+
+ // If we have exhausted current retries, try next smaller size.
+ // If this was the smallest size, we abort.
+ if (pSpxConnFile->scf_CRetryCount-- == 0)
+ {
+ // Have we tried the smallest size?
+ if (!spxConnCheckNegSize(&pSpxConnFile->scf_MaxPktSize))
+ {
+ // Give up! Remove negotiate packet etc. Have an abort
+ // kind of routine.
+ ++SpxDevice->dev_Stat.SessionTimeouts;
+ fAbort = TRUE;
+ break;
+ }
+
+ // Set neg pkt size to new lower size
+ spxConnSetNegSize(
+ pPkt,
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE);
+
+ pSpxConnFile->scf_CRetryCount =
+ PARAM(CONFIG_CONNECTION_COUNT);
+ }
+
+ // We need to resend the packet
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0);
+
+ pSendResd->sr_State |= SPX_SENDPKT_IPXOWNS;
+ sendPkt = TRUE;
+ break;
+
+ default:
+
+ KeBugCheck(0);
+
+ }
+ }
+
+ } while (FALSE);
+
+ if (fAbort)
+ {
+ CTEAssert(!sendPkt);
+
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnConnectTimer: Expired for %lx\n", pSpxConnFile));
+
+ spxConnAbortConnect(
+ pSpxConnFile,
+ STATUS_BAD_NETWORK_PATH,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ }
+
+ if (locksHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ }
+
+ if (sendPkt)
+ {
+ CTEAssert(!fAbort);
+
+#if !defined(_PNP_POWER)
+ if ((SPX_CONNECT_STATE(pSpxConnFile) == SPX_CONNECT_SENTREQ) &&
+ (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0)) {
+
+ // we are sending to all NICs because this is the initial
+ // connect frame and the remote network is 0.
+
+ pSpxConnFile->scf_LocalTarget.NicId = (USHORT)
+ ((pSpxConnFile->scf_LocalTarget.NicId % SpxDevice->dev_Adapters) + 1);
+
+ // we pass this a valid packet in pPkt, so it knows to
+ // just refresh the header and not update the protocol
+ // reserved variables.
+
+ SpxPktBuildCr(
+ pSpxConnFile,
+ pSpxConnFile->scf_AddrFile->saf_Addr,
+ &pPkt,
+ 0, // state will not be updated
+ SPX2_CONN(pSpxConnFile));
+
+ }
+#endif !_PNP_POWER
+
+ // Send the packet
+ SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ if (TimerShuttingDown || fAbort)
+ {
+ // Dereference connection for verify done in connect, for timer. This
+ // should complete any pending disconnects if they had come in in the
+ // meantime.
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ return(TIMER_DONT_REQUEUE);
+ }
+
+ return(TIMER_REQUEUE_CUR_VALUE);
+}
+
+
+
+
+ULONG
+spxConnWatchdogTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown
+ )
+/*++
+
+Routine Description:
+
+ This is started on a connection right after the CR or the CR ack is received.
+ During the connection establishment phase, it does nothing other than decrement
+ the retry count and upon reaching 0, it aborts the connection. When it goes off
+ and finds the connection is active, it sends a probe.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)Context;
+ CTELockHandle lockHandle;
+ PSPX_SEND_RESD pSendResd;
+ PSPX_FIND_ROUTE_REQUEST pFindRouteReq;
+ PNDIS_PACKET pProbe = NULL;
+ BOOLEAN lockHeld, fSpx2 = SPX2_CONN(pSpxConnFile),
+ fDisconnect = FALSE, fFindRoute = FALSE, fSendProbe = FALSE;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnWatchdogTimer: Entered\n"));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ lockHeld = TRUE;
+ do
+ {
+ if (TimerShuttingDown ||
+ (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER)) ||
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT))
+ {
+#if DBG
+ if ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_IDLE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_WD))
+ {
+ CTEAssert(FALSE);
+ }
+#endif
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ TimerShuttingDown = TRUE;
+ break;
+ }
+
+ // If the retry timer is active on this connection, and the watchdog
+ // timer happens to fire, just requeue ourselves for spx2. For spx1,
+ // we go ahead with sending a probe. Retry timer does the same things
+ // watchdog does for spx2.
+ switch (SPX_MAIN_STATE(pSpxConnFile))
+ {
+ case SPX_CONNFILE_ACTIVE:
+ case SPX_CONNFILE_DISCONN:
+
+ // Squash the race condition where a disconnect request is never
+ // packetized, because the send state was not IDLE.
+ if (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_POST_IDISC)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnWatchdogTimer: POST IDISC %lx\n",
+ pSpxConnFile));
+
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnWatchdogTimer: PKT POST IDISC %lx\n",
+ pSpxConnFile));
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_PACKETIZE);
+ SpxConnPacketize(
+ pSpxConnFile,
+ TRUE,
+ lockHandle);
+
+ lockHeld = FALSE;
+ break;
+ }
+ }
+
+ if (!fSpx2)
+ {
+ if (pSpxConnFile->scf_WRetryCount-- > 0)
+ {
+ fSendProbe = TRUE;
+ }
+ else
+ {
+ fDisconnect = TRUE;
+ }
+
+ break;
+ }
+
+ // SPX2 connection. Watchdog algorithm needs to do lots of goody
+ // stuff. If retry is active, just requeue ourselves.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER))
+ break;
+
+ // There is a race between watchdog and retry if its started. Who
+ // ever changes the state first gets to go do its thing.
+ switch (SPX_SEND_STATE(pSpxConnFile))
+ {
+ case SPX_SEND_IDLE:
+
+ // Enter WD state only if we fired for the second time witout
+ // an ack. This prevents PACKETIZE from blocking due to being
+ // in a non-idle state.
+ CTEAssert(pSpxConnFile->scf_WRetryCount != 0);
+ if ((pSpxConnFile->scf_WRetryCount)-- !=
+ (LONG)PARAM(CONFIG_KEEPALIVE_COUNT))
+ {
+ // We enter the WD state. Build and send a probe.
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_WD);
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ERRORSTATE);
+ }
+
+ fSendProbe = TRUE;
+ break;
+
+ case SPX_SEND_PACKETIZE:
+
+ // Do nothing.
+ break;
+
+ case SPX_SEND_RETRY:
+ case SPX_SEND_RETRYWD:
+ case SPX_SEND_RENEG:
+ case SPX_SEND_RETRY2:
+ case SPX_SEND_RETRY3:
+
+ // Do nothing. Send timer got in first.
+ DBGPRINT(CONNECT, DBG1,
+ ("SpxConnWDogTimer: When retry fired %lx\n",
+ pSpxConnFile));
+
+ break;
+
+ case SPX_SEND_WD:
+
+ // Decrement count. If not zero, send a probe. If half the
+ // count is reached, stop timer and call find route.
+ if (pSpxConnFile->scf_WRetryCount-- > 0)
+ {
+ if (pSpxConnFile->scf_WRetryCount !=
+ (LONG)PARAM(CONFIG_KEEPALIVE_COUNT)/2)
+ {
+ fSendProbe = TRUE;
+ break;
+ }
+
+ if ((pFindRouteReq =
+ (PSPX_FIND_ROUTE_REQUEST)SpxAllocateMemory(
+ sizeof(SPX_FIND_ROUTE_REQUEST))) == NULL)
+ {
+ fDisconnect = TRUE;
+ break;
+ }
+
+ // Remove timer reference/ Add find route request ref
+ fFindRoute = TRUE;
+ TimerShuttingDown = TRUE;
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_FINDROUTE);
+ SpxConnFileLockReference(pSpxConnFile, CFREF_FINDROUTE);
+
+ // Initialize the find route request
+ *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Network) =
+ *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr);
+
+ //
+ // [SA] Bug #15094
+ // We need to also pass in the node number to IPX so that IPX can
+ // compare the node addresses to determine the proper WAN NICid
+ //
+
+ // RtlCopyMemory (pFindRouteReq->fr_FindRouteReq.Node, pSpxConnFile->scf_RemAddr+4, 6);
+
+ *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Node)=
+ *((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr+4));
+
+ *((UNALIGNED USHORT *)(pFindRouteReq->fr_FindRouteReq.Node+4))=
+ *((UNALIGNED USHORT *)(pSpxConnFile->scf_RemAddr+8));
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnWDogTimer: NETWORK %lx\n",
+ *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr)));
+
+ pFindRouteReq->fr_FindRouteReq.Identifier= IDENTIFIER_SPX;
+ pFindRouteReq->fr_Ctx = pSpxConnFile;
+
+ // Make sure we have IPX re-rip.
+ pFindRouteReq->fr_FindRouteReq.Type = IPX_FIND_ROUTE_FORCE_RIP;
+ }
+ else
+ {
+ fDisconnect = TRUE;
+ }
+
+ break;
+
+ default:
+
+ KeBugCheck(0);
+ }
+
+ break;
+
+ case SPX_CONNFILE_CONNECTING:
+
+ if ((SPX_CONNECT_STATE(pSpxConnFile) == SPX_CONNECT_SENTREQ) ||
+ (SPX_CONNECT_STATE(pSpxConnFile) == SPX_CONNECT_NEG))
+ {
+ // Do nothing. Connect timer is active.
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnWDogTimer: CR Timer active %lx\n",
+ pSpxConnFile));
+
+ break;
+ }
+
+ if (!(pSpxConnFile->scf_WRetryCount--))
+ {
+ // Disconnect!
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnWatchdogTimer: Connection %lx.%lx expired\n",
+ pSpxConnFile->scf_LocalConnId, pSpxConnFile));
+
+ fDisconnect = TRUE;
+ }
+
+ break;
+
+ case SPX_CONNFILE_LISTENING:
+
+ if (SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_SETUP)
+ {
+ // Do nothing. Connect timer is active.
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnWDogTimer: CR Timer active %lx\n",
+ pSpxConnFile));
+
+ break;
+ }
+
+ if (!(pSpxConnFile->scf_WRetryCount--))
+ {
+ // Disconnect!
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnWatchdogTimer: Connection %lx.%lx expired\n",
+ pSpxConnFile->scf_LocalConnId, pSpxConnFile));
+
+ fDisconnect = TRUE;
+ }
+
+ break;
+
+ default:
+
+ // Should never happen!
+ KeBugCheck(0);
+ }
+
+ } while (FALSE);
+
+ if (fSendProbe)
+ {
+ CTEAssert(lockHeld);
+ CTEAssert(!fDisconnect);
+
+ DBGPRINT(CONNECT, DBG1,
+ ("spxConnWatchdogTimer: Send Probe from %lx.%lx\n",
+ pSpxConnFile->scf_LocalConnId, pSpxConnFile));
+
+ // Build a probe and send it out to the remote end.
+ SpxPktBuildProbe(
+ pSpxConnFile,
+ &pProbe,
+ (SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY),
+ fSpx2);
+
+ if (pProbe != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pProbe);
+ pSendResd = (PSPX_SEND_RESD)(pProbe->ProtocolReserved);
+ }
+ }
+
+ if (fDisconnect)
+ {
+ CTEAssert(lockHeld);
+ CTEAssert(!fSendProbe);
+
+ // Disconnect!
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnWatchdogTimer: Connection %lx.%lx expired\n",
+ pSpxConnFile->scf_LocalConnId, pSpxConnFile));
+
+ TimerShuttingDown = TRUE;
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+
+ // If spx2, check if we need to do anything special.
+ // AbortiveDisc will reset funky state if needed.
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_LINK_TIMEOUT,
+ SPX_CALL_TDILEVEL,
+ lockHandle,
+ FALSE); // [SA] Bug #15249
+
+ lockHeld = FALSE;
+ }
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ if (fFindRoute)
+ {
+ CTEAssert(!fSendProbe);
+ CTEAssert(!fDisconnect);
+ CTEAssert(TimerShuttingDown);
+
+ // Start off the find route request
+ (*IpxFindRoute)(
+ &pFindRouteReq->fr_FindRouteReq);
+ }
+
+ if (pProbe != NULL)
+ {
+ // Send the packet
+ SPX_SENDPACKET(pSpxConnFile, pProbe, pSendResd);
+ }
+
+ if (TimerShuttingDown)
+ {
+ // Dereference connection for verify done in connect, for timer. This
+ // should complete any pending disconnects if they had come in in the
+ // meantime.
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return((TimerShuttingDown ? TIMER_DONT_REQUEUE : TIMER_REQUEUE_CUR_VALUE));
+}
+
+
+
+ULONG
+spxConnRetryTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)Context;
+ PSPX_SEND_RESD pSendResd;
+ CTELockHandle lockHandleConn;
+ PIPXSPX_HDR pSendHdr;
+ PNDIS_PACKET pPkt;
+ PNDIS_PACKET pProbe = NULL;
+ PSPX_FIND_ROUTE_REQUEST pFindRouteReq;
+ USHORT reenqueueTime = TIMER_REQUEUE_CUR_VALUE;
+ BOOLEAN lockHeld, fResendPkt = FALSE, fDisconnect = FALSE,
+ fFindRoute = FALSE, fBackoffTimer = FALSE;
+ PREQUEST pRequest = NULL;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnRetryTimer: Entered\n"));
+
+ // Get lock
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ lockHeld = TRUE;
+
+ do
+ {
+ // If timer is not up, no send pkts, just return.
+ if (TimerShuttingDown ||
+ (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER)) ||
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT) ||
+ ((pSendResd = pSpxConnFile->scf_SendSeqListHead) == NULL))
+ {
+#if DBG
+ if ((pSendResd = pSpxConnFile->scf_SendSeqListHead) == NULL)
+ {
+ if ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_IDLE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_PACKETIZE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_WD))
+ {
+ CTEAssert(FALSE);
+ }
+ }
+#endif
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
+ TimerShuttingDown = TRUE;
+ break;
+ }
+
+ // In all other cases, reenqueue with potentially modified reenqueue
+ // time.
+ reenqueueTime = pSpxConnFile->scf_BaseT1;
+ DBGPRINT(SEND, INFO,
+ ("spxConnRetryTimer: BaseT1 %lx on %lx\n",
+ pSpxConnFile->scf_BaseT1, pSpxConnFile));
+
+ // If an ack for a packet was processed while we were out, reset
+ // retry count and return. Or if we are packetizing, return.
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_PACKETIZE)
+ {
+ break;
+ }
+ else if ((SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE) &&
+ (pSpxConnFile->scf_RetrySeqNum != pSendResd->sr_SeqNum))
+ {
+ pSpxConnFile->scf_RetrySeqNum = pSendResd->sr_SeqNum;
+ break;
+ }
+
+ // If packet is still with IPX, requeue for next time.
+ if (pSendResd->sr_State & SPX_SENDPKT_IPXOWNS)
+ {
+ break;
+ }
+
+ CTEAssert(pSendResd != NULL);
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ pSendHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ switch (SPX_SEND_STATE(pSpxConnFile))
+ {
+ case SPX_SEND_IDLE:
+
+ // Set ack bit in packet. pSendResd initialized at beginning.
+ pSendHdr->hdr_ConnCtrl |= SPX_CC_ACK;
+
+ // Do we backoff the timer?
+ fBackoffTimer =
+ (BOOLEAN)((pSendResd->sr_State & SPX_SENDPKT_REXMIT) != 0);
+
+ // We are going to resend this packet
+ pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
+ SPX_SENDPKT_ACKREQ |
+ SPX_SENDPKT_REXMIT);
+
+ ++SpxDevice->dev_Stat.ResponseTimerExpirations;
+
+ CTEAssert((ULONG)pSpxConnFile->scf_RRetryCount <=
+ PARAM(CONFIG_REXMIT_COUNT));
+
+ DBGPRINT(SEND, DBG1,
+ ("spxConnRetryTimer: Retry Count %lx on %lx\n",
+ pSpxConnFile->scf_RRetryCount, pSpxConnFile));
+
+ fResendPkt = TRUE;
+ if (pSpxConnFile->scf_RRetryCount-- != 0)
+ {
+ // We dont treat the IDISC packet as a data packet, so none
+ // of the fancy spx2 retry stuff if we are retrying the idisc.
+ if (SPX2_CONN(pSpxConnFile) &&
+ (SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_SENT_IDISC))
+ {
+ // We enter the RETRY state. Reference conn for this
+ // "funky" state.
+ CTEAssert(SPX2_CONN(pSpxConnFile));
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY);
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ERRORSTATE);
+ }
+ }
+ else
+ {
+ DBGPRINT(SEND, ERR,
+ ("spxConnRetryTimer: Retry Count over on %lx\n",
+ pSpxConnFile));
+
+ fDisconnect = TRUE;
+ fResendPkt = FALSE;
+ pSendResd->sr_State &= ~SPX_SENDPKT_IPXOWNS;
+ }
+
+ break;
+
+ case SPX_SEND_RETRY:
+
+ // When we have reached retry_count/2 limit, start locate route. Do
+ // not queue ourselves. Handle restarting timer in find route
+ // completion. If timer starts successfully in find route comp, then
+ // it will change our state to RETRYWD.
+
+ // Decrement count. If half the count is reached, stop timer and call
+ // find route.
+ if (pSpxConnFile->scf_RRetryCount-- !=
+ (LONG)PARAM(CONFIG_REXMIT_COUNT)/2)
+ {
+ // We are going to resend this packet
+ pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
+ SPX_SENDPKT_ACKREQ |
+ SPX_SENDPKT_REXMIT);
+
+ fResendPkt = TRUE;
+ fBackoffTimer = TRUE;
+ break;
+ }
+
+ if ((pFindRouteReq =
+ (PSPX_FIND_ROUTE_REQUEST)SpxAllocateMemory(
+ sizeof(SPX_FIND_ROUTE_REQUEST))) == NULL)
+ {
+ DBGPRINT(SEND, ERR,
+ ("spxConnRetryTimer: Alloc Mem %lx\n",
+ pSpxConnFile));
+
+ fDisconnect = TRUE;
+ break;
+ }
+
+ // Remove timer reference/ Add find route request ref
+ fFindRoute = TRUE;
+ TimerShuttingDown = TRUE;
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_FINDROUTE);
+ SpxConnFileLockReference(pSpxConnFile, CFREF_FINDROUTE);
+
+ // Initialize the find route request
+ *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Network)=
+ *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr);
+
+ //
+ // [SA] Bug #15094
+ // We need to also pass in the node number to IPX so that IPX can
+ // compare the node addresses to determine the proper WAN NICid
+ //
+
+ // RtlCopyMemory (pFindRouteReq->fr_FindRouteReq.Node, pSpxConnFile->scf_RemAddr+4, 6) ;
+
+ *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Node)=
+ *((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr+4));
+
+ *((UNALIGNED USHORT *)(pFindRouteReq->fr_FindRouteReq.Node+4)) =
+ *((UNALIGNED USHORT *)(pSpxConnFile->scf_RemAddr+8));
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnRetryTimer: NETWORK %lx\n",
+ *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr)));
+
+ pFindRouteReq->fr_FindRouteReq.Identifier= IDENTIFIER_SPX;
+ pFindRouteReq->fr_Ctx = pSpxConnFile;
+
+ // Make sure we have IPX re-rip.
+ pFindRouteReq->fr_FindRouteReq.Type = IPX_FIND_ROUTE_FORCE_RIP;
+ break;
+
+ case SPX_SEND_RETRYWD:
+
+ // Retry a watchdog packet WCount times (initialize to RETRY_COUNT).
+ // If process ack receives an ack (i.e. actual ack packet) while in
+ // this state, it will transition the state to RENEG.
+ //
+ // If the pending data gets acked while in this state, we go back
+ // to idle.
+ DBGPRINT(CONNECT, DBG1,
+ ("spxConnRetryTimer: Send Probe from %lx.%lx\n",
+ pSpxConnFile->scf_LocalConnId, pSpxConnFile));
+
+ // Use watchdog count here.
+ if (pSpxConnFile->scf_WRetryCount-- > 0)
+ {
+ // Build a probe and send it out to the remote end.
+ SpxPktBuildProbe(
+ pSpxConnFile,
+ &pProbe,
+ (SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY),
+ TRUE);
+
+ if (pProbe != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pProbe);
+ pSendResd = (PSPX_SEND_RESD)(pProbe->ProtocolReserved);
+ break;
+ }
+ }
+
+ // Just set state to retry data packet retry_count/2 times.
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY2);
+ break;
+
+ case SPX_SEND_RENEG:
+
+ // Renegotiate size. If we give up, goto RETRY3.
+ // For this both sides must have negotiated size to begin with.
+ // If they did not, we go on to retrying the data packet.
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG))
+ {
+ DBGPRINT(SEND, ERR,
+ ("spxConnRetryTimer: NO NEG FLAG SET: %lx - %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_Flags));
+
+ // Reset count to be
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY3);
+ break;
+ }
+
+ // Send reneg packet, if we get the rr ack, then we resend data
+ // on queue. Note that each time we goto a new negotiate size,
+ // we rebuild the data packets.
+ if (pSpxConnFile->scf_RRetryCount-- == 0)
+ {
+ // Reset count.
+ pSpxConnFile->scf_RRetryCount = SPX_DEF_RENEG_RETRYCOUNT;
+ if ((ULONG)pSpxConnFile->scf_MaxPktSize <=
+ (SpxMaxPktSize[0] + MIN_IPXSPX2_HDRSIZE))
+ {
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnRetryTimer: %lx MIN RENEG SIZE\n",
+ pSpxConnFile));
+ }
+
+ // Are we at the lowest possible reneg pkt size? If not, try
+ // next lower. When we do this, we free all pending send
+ // packets and reset the packetize queue to the first packet.
+ // Process ack will just do packetize and will not do anything
+ // more other than resetting state to proper value.
+ DBGPRINT(SEND, DBG3,
+ ("spxConnRetryTimer: RENEG: %lx - CURRENT %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_MaxPktSize));
+
+ if (!spxConnCheckNegSize(&pSpxConnFile->scf_MaxPktSize))
+ {
+ // We tried lowest size and failed to receive ack. Just
+ // retry data packet, and disc if no ack.
+ DBGPRINT(SEND, DBG3,
+ ("spxConnRetryTimer: RENEG(min), RETRY3: %lx - %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_MaxPktSize));
+
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY3);
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT);
+ break;
+ }
+
+ DBGPRINT(SEND, DBG3,
+ ("spxConnRetryTimer: RENEG(!min): %lx - ATTEMPT %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_MaxPktSize));
+ }
+
+ DBGPRINT(SEND, DBG3,
+ ("spxConnRetryTimer: %lx.%lx.%lx RENEG SEQNUM %lx ACKNUM %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_RRetryCount,
+ pSpxConnFile->scf_MaxPktSize,
+ (USHORT)(pSpxConnFile->scf_SendSeqListTail->sr_SeqNum + 1),
+ pSpxConnFile->scf_SentAllocNum));
+
+ // Use first unused data packet sequence number.
+ SpxPktBuildRr(
+ pSpxConnFile,
+ &pPkt,
+ (USHORT)(pSpxConnFile->scf_SendSeqListTail->sr_SeqNum + 1),
+ (SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY));
+
+ if (pPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ fResendPkt = TRUE;
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT);
+ }
+
+ break;
+
+ case SPX_SEND_RETRY2:
+
+ // Retry the data packet for remaining amount of RRetryCount. If not
+ // acked goto cleanup. If ack received while in this state, goto idle.
+
+ if (pSpxConnFile->scf_RRetryCount-- > 0)
+ {
+ // We are going to resend this packet
+ pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
+ SPX_SENDPKT_ACKREQ |
+ SPX_SENDPKT_REXMIT);
+
+ DBGPRINT(SEND, DBG3,
+ ("spxConnRetryTimer: 2nd try Resend on %lx\n",
+ pSpxConnFile));
+
+ fResendPkt = TRUE;
+ fBackoffTimer = TRUE;
+ }
+ else
+ {
+ DBGPRINT(SEND, ERR,
+ ("spxConnRetryTimer: Retry Count over on %lx\n",
+ pSpxConnFile));
+
+ fDisconnect = TRUE;
+ }
+
+ break;
+
+ case SPX_SEND_RETRY3:
+
+ // Send data packet for RETRY_COUNT times initialized in RRetryCount
+ // before state changed to this state. If ok, process ack moves us
+ // back to PKT/IDLE. If not, we disconnect.
+ // We are going to resend this packet
+
+ if (pSpxConnFile->scf_RRetryCount-- > 0)
+ {
+ DBGPRINT(SEND, DBG3,
+ ("spxConnRetryTimer: 3rd try Resend on %lx\n",
+ pSpxConnFile));
+
+ // We are going to resend this packet
+ pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
+ SPX_SENDPKT_ACKREQ |
+ SPX_SENDPKT_REXMIT);
+
+ fResendPkt = TRUE;
+ fBackoffTimer = TRUE;
+ }
+ else
+ {
+ DBGPRINT(SEND, ERR,
+ ("spxConnRetryTimer: Retry Count over on %lx\n",
+ pSpxConnFile));
+
+ fDisconnect = TRUE;
+ }
+
+ break;
+
+ case SPX_SEND_WD:
+
+ // Do nothing. Watchdog timer has fired, just requeue.
+ break;
+
+ default:
+
+ KeBugCheck(0);
+ }
+
+ if (fBackoffTimer)
+ {
+ // Increase retransmit timeout by 50% upto maximum indicated by
+ // initial retransmission value.
+
+ reenqueueTime += reenqueueTime/2;
+ if (reenqueueTime > MAX_RETRY_DELAY)
+ reenqueueTime = MAX_RETRY_DELAY;
+
+ pSpxConnFile->scf_BaseT1 =
+ pSpxConnFile->scf_AveT1 = reenqueueTime;
+ pSpxConnFile->scf_DevT1 = 0;
+
+ DBGPRINT(SEND, DBG,
+ ("spxConnRetryTimer: Backed retry on %lx.%lx %lx\n",
+ pSpxConnFile, pSendResd->sr_SeqNum, reenqueueTime));
+ }
+
+ if (fDisconnect)
+ {
+ CTEAssert(lockHeld);
+
+ // Do not requeue this timer.
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
+ TimerShuttingDown = TRUE;
+
+ // Disconnect the connection.
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_LINK_TIMEOUT,
+ SPX_CALL_TDILEVEL,
+ lockHandleConn,
+ FALSE); // [SA] Bug #15249
+
+ lockHeld = FALSE;
+ }
+
+ } while (FALSE);
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ }
+
+ if (fResendPkt)
+ {
+ DBGPRINT(SEND, DBG,
+ ("spxConnRetryTimer: Resend pkt on %lx.%lx\n",
+ pSpxConnFile, pSendResd->sr_SeqNum));
+
+ ++SpxDevice->dev_Stat.DataFramesResent;
+ ExInterlockedAddLargeStatistic(
+ &SpxDevice->dev_Stat.DataFrameBytesResent,
+ pSendResd->sr_Len - (SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE));
+ SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
+ }
+ else if (fFindRoute)
+ {
+ CTEAssert(!fResendPkt);
+ CTEAssert(!fDisconnect);
+ CTEAssert(TimerShuttingDown);
+
+ DBGPRINT(SEND, DBG3,
+ ("spxConnRetryTimer: Find route on %lx\n",
+ pSpxConnFile));
+
+ // Start off the find route request
+ (*IpxFindRoute)(
+ &pFindRouteReq->fr_FindRouteReq);
+ }
+ else if (pProbe != NULL)
+ {
+ // Send the packet
+ SPX_SENDPACKET(pSpxConnFile, pProbe, pSendResd);
+ }
+
+ if (TimerShuttingDown)
+ {
+ // Dereference connection for verify done in connect, for timer. This
+ // should complete any pending disconnects if they had come in in the
+ // meantime.
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ reenqueueTime = TIMER_DONT_REQUEUE;
+ }
+
+ DBGPRINT(SEND, INFO,
+ ("spxConnRetryTimer: Reenqueue time : %lx on %lx\n",
+ reenqueueTime, pSpxConnFile));
+
+ return(reenqueueTime);
+}
+
+
+
+
+ULONG
+spxConnAckTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)Context;
+ CTELockHandle lockHandleConn;
+
+ DBGPRINT(SEND, INFO,
+ ("spxConnAckTimer: Entered\n"));
+
+ // Get lock
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ if (!TimerShuttingDown &&
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ACKQ))
+ {
+ // We didnt have any back traffic, until we do a send from this
+ // end, send acks immediately. Dont try to piggyback.
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_ACKQ);
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_IMMED_ACK);
+
+ ++SpxDevice->dev_Stat.PiggybackAckTimeouts;
+
+ DBGPRINT(SEND, DBG,
+ ("spxConnAckTimer: Send ack on %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RecvSeqNum));
+
+ SpxConnSendAck(pSpxConnFile, lockHandleConn);
+ }
+ else
+ {
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_ACKQ);
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ }
+
+ // Dereference connection for verify done in connect, for timer. This
+ // should complete any pending disconnects if they had come in in the
+ // meantime.
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ return(TIMER_DONT_REQUEUE);
+}
+
+
+
+//
+// DISCONNECT ROUTINES
+//
+
+
+VOID
+spxConnAbortiveDisc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn,
+ IN BOOLEAN IDiscFlag // [SA] Bug #15249
+ )
+/*++
+
+Routine Description:
+
+ This is called when:
+ We time out or have insufficient resources -
+ STATUS_LINK_TIMEOUT/STATUS_INSUFFICIENT_RESOURCES
+ - We abort everything. Could be from watchdog or retry. Stop both.
+
+ We receive a informed disconnect packet -
+ STATUS_REMOTE_DISCONNECT
+ - We abort everything. Ack must be sent by caller as an orphan pkt.
+
+ We receive a informed disconnect ack pkt
+ STATUS_SUCCESS
+ - We abort everything
+ - Abort is done with status success (this completes our disc req in
+ the send queue)
+
+ NOTE: CALLED UNDER THE CONNECTION LOCK.
+
+Arguments:
+[SA] Bug #15249: Added IDiscFlag to indicate if this is an Informed Disconnect. If so, indicate
+ TDI_DISCONNECT_RELEASE to AFD so it allows a receive of buffered pkts. This flag is TRUE
+ only if this routine is called from SpxConnProcessIDisc for SPX connections.
+
+Return Value:
+
+
+--*/
+{
+ int numDerefs = 0;
+ PVOID pDiscHandlerCtx=NULL;
+ PTDI_IND_DISCONNECT pDiscHandler = NULL;
+ BOOLEAN lockHeld = TRUE;
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnAbortiveDisc: %lx - On %lx when %lx\n",
+ Status, pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ switch (Status) {
+ case STATUS_LINK_TIMEOUT: ++SpxDevice->dev_Stat.LinkFailures; break;
+ case STATUS_INSUFFICIENT_RESOURCES: ++SpxDevice->dev_Stat.LocalResourceFailures; break;
+ case STATUS_REMOTE_DISCONNECT: ++SpxDevice->dev_Stat.RemoteDisconnects; break;
+ case STATUS_SUCCESS:
+ case STATUS_LOCAL_DISCONNECT: ++SpxDevice->dev_Stat.LocalDisconnects; break;
+ }
+
+ switch (SPX_MAIN_STATE(pSpxConnFile))
+ {
+ case SPX_CONNFILE_ACTIVE:
+
+ // For transition from active to disconn.
+ numDerefs++;
+
+ case SPX_CONNFILE_DISCONN:
+
+ // If we are in any state other than idle/packetize,
+ // remove the reference for the funky state, and reset the send state to be
+ // idle.
+ if ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_IDLE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_PACKETIZE))
+ {
+#if DBG
+ if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnAbortiveDisc: When DISC STATE %lx.%lx\n",
+ pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
+ }
+#endif
+
+ DBGPRINT(CONNECT, DBG1,
+ ("spxConnAbortiveDisc: When SEND ERROR STATE %lx.%lx\n",
+ pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ numDerefs++;
+ }
+
+ // This can be called when a idisc is received, or if a timer
+ // disconnect is happening, or if we sent a idisc/ordrel, but the retries
+ // timed out and we are aborting the connection.
+ // So if we are already aborting, never mind.
+
+ //
+ // [SA] Bug #15249
+ // SPX_DISC_INACTIVATED indicates a DISC_ABORT'ing connection that has been
+ // inactivated (connfile removed from active conn. list)
+ //
+
+ if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ ((SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT) ||
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED)))
+ {
+ break;
+ }
+
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_DISCONN);
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_ABORT);
+
+ // Stop all timers.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_TTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER);
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_RTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_WTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ }
+#if 0
+ //
+ // [SA] We need to call AFD after aborting sends since this connection
+ // becomes a candidate for re-use as soon as the disconnect handler is
+ // called.
+ // We call the disconnect handler when the refcount falls to 0 and the
+ // connection transitions to the inactive list.
+ //
+
+ // NOTE! We indicate disconnect to afd *before* aborting sends to avoid
+ // afd from calling us again with a disconnect.
+ // Get disconnect handler if we have one. And we have not indicated
+ // abortive disconnect on this connection to afd.
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC))
+ {
+ // Yeah, we set the flag regardless of whether a handler is
+ // present.
+ pDiscHandler = pSpxConnFile->scf_AddrFile->saf_DiscHandler;
+ pDiscHandlerCtx = pSpxConnFile->scf_AddrFile->saf_DiscHandlerCtx;
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
+ }
+#endif
+ //
+ // [SA] Save the IDiscFlag in the Connection.
+ //
+ (IDiscFlag) ?
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_IDISC) :
+ SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_IDISC);
+
+ // Indicate disconnect to afd.
+ if (pDiscHandler != NULL)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnAbortiveDisc: Indicating to afd On %lx when %lx\n",
+ pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ // First complete all requests waiting for receive completion on
+ // this conn before indicating disconnect.
+ spxConnCompletePended(pSpxConnFile);
+
+
+ //
+ // [SA] bug #15249
+ // If not Informed disconnect, indicate DISCONNECT_ABORT to AFD
+ //
+
+ if (!IDiscFlag)
+ {
+ (*pDiscHandler)(
+ pDiscHandlerCtx,
+ pSpxConnFile->scf_ConnCtx,
+ 0, // Disc data
+ NULL,
+ 0, // Disc info
+ NULL,
+ TDI_DISCONNECT_ABORT);
+ }
+ else
+ {
+ //
+ // [SA] bug #15249
+ // Indicate DISCONNECT_RELEASE to AFD so it allows receive of packets
+ // it has buffered before the remote disconnect took place.
+ //
+
+ (*pDiscHandler)(
+ pDiscHandlerCtx,
+ pSpxConnFile->scf_ConnCtx,
+ 0, // Disc data
+ NULL,
+ 0, // Disc info
+ NULL,
+ TDI_DISCONNECT_RELEASE);
+ }
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ }
+
+ // Go through and kill all pending requests.
+ spxConnAbortRecvs(
+ pSpxConnFile,
+ Status,
+ CallLevel,
+ LockHandleConn);
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+
+ spxConnAbortSends(
+ pSpxConnFile,
+ Status,
+ CallLevel,
+ LockHandleConn);
+
+ lockHeld = FALSE;
+ break;
+
+ case SPX_CONNFILE_CONNECTING:
+ case SPX_CONNFILE_LISTENING:
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnAbortiveDisc: CONN/LIST Disc On %lx when %lx\n",
+ pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ lockHeld = FALSE;
+
+ {
+ CTELockHandle lockHandleAddr, lockHandleDev;
+
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+
+ // Ensure we are still in connecting/listening, else call abortive
+ // again.
+ switch (SPX_MAIN_STATE(pSpxConnFile))
+ {
+ case SPX_CONNFILE_CONNECTING:
+ case SPX_CONNFILE_LISTENING:
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnAbortiveDisc: CONN/LIST Disc2 On %lx when %lx\n",
+ pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ spxConnAbortConnect(
+ pSpxConnFile,
+ Status,
+ lockHandleDev,
+ lockHandleAddr,
+ LockHandleConn);
+
+ break;
+
+ case SPX_CONNFILE_ACTIVE:
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ CTEFreeLock(
+ pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(
+ &SpxDevice->dev_Lock, lockHandleDev);
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnAbortiveDisc: CHG ACT Disc2 On %lx when %lx\n",
+ pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ Status,
+ CallLevel,
+ LockHandleConn,
+ FALSE); // [SA] Bug #15249
+
+ break;
+
+ default:
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ CTEFreeLock(
+ pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(
+ &SpxDevice->dev_Lock, lockHandleDev);
+
+ break;
+ }
+ }
+
+ default:
+
+ // Already disconnected.
+ break;
+ }
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
diff --git a/private/ntos/tdi/isn/spx/spxcpkt.c b/private/ntos/tdi/isn/spx/spxcpkt.c
new file mode 100644
index 000000000..0c606ab0a
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxcpkt.c
@@ -0,0 +1,4131 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxcpkt.c
+
+Abstract:
+
+ This module contains code which implements the CONNECTION object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport connection objects.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 14-July-1995
+ Bug fixes - tagged [SA]
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXCPKT
+
+VOID
+spxConnHandleConnReq(
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ BOOLEAN fNeg, fSpx2;
+ TA_IPX_ADDRESS srcIpxAddr;
+ PTDI_IND_CONNECT connHandler;
+ USHORT srcConnId, destConnId, destSkt,
+ pktLen, seqNum, ackNum, allocNum;
+ PVOID connHandlerCtx;
+ PREQUEST pListenReq;
+ PSPX_SEND_RESD pSendResd;
+ NTSTATUS status;
+ CTELockHandle lockHandle, lockHandleDev, lockHandleConn;
+ CONNECTION_CONTEXT connCtx;
+ PIRP acceptIrp;
+ PSPX_ADDR pSpxAddr;
+ PSPX_ADDR_FILE pSpxAddrFile, pSpxRefFile;
+ PSPX_CONN_FILE pSpxConnFile;
+ PNDIS_PACKET pCrAckPkt;
+ BOOLEAN connectAccepted = FALSE, delayAccept = FALSE,
+ addrLock = FALSE, tdiListen = FALSE;
+
+ // Convert hdr to host format as needed.
+ GETSHORT2SHORT(&pktLen, &pIpxSpxHdr->hdr_PktLen);
+ GETSHORT2SHORT(&destConnId, &pIpxSpxHdr->hdr_DestConnId);
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+ GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
+
+ // We keep and use the remote id in the net format. This maintains the
+ // 0x0 and 0xFFFF to be as in the host format.
+ srcConnId = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_SrcConnId;
+
+ // Verify Connect Request
+ if (((pIpxSpxHdr->hdr_ConnCtrl & (SPX_CC_ACK | SPX_CC_SYS)) !=
+ (SPX_CC_ACK | SPX_CC_SYS)) ||
+ (pIpxSpxHdr->hdr_DataType != 0) ||
+ (seqNum != 0) ||
+ (ackNum != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (destConnId != 0xFFFF))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnSysPacket: VerifyCR Failed %lx.%lx\n",
+ srcConnId, destConnId));
+ return;
+ }
+
+ // Get the destination socket from the header
+ destSkt = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_DestSkt;
+
+ SpxBuildTdiAddress(
+ &srcIpxAddr,
+ sizeof(srcIpxAddr),
+ (PBYTE)pIpxSpxHdr->hdr_SrcNet,
+ pIpxSpxHdr->hdr_SrcNode,
+ pIpxSpxHdr->hdr_SrcSkt);
+
+ // Ok, get the address object this is destined for.
+ CTEGetLock (&SpxDevice->dev_Lock, &lockHandleDev);
+ pSpxAddr = SpxAddrLookup(SpxDevice, destSkt);
+ CTEFreeLock (&SpxDevice->dev_Lock, lockHandleDev);
+ if (pSpxAddr == NULL)
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxReceive: No addr for %lx\n", destSkt));
+
+ return;
+ }
+
+ fSpx2 = ((PARAM(CONFIG_DISABLE_SPX2) == 0) &&
+ (BOOLEAN)(pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2));
+ fNeg = (BOOLEAN)(fSpx2 && (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_NEG));
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleConnReq: Received connect req! %d.%d\n",
+ fSpx2, fNeg));
+
+ CTEGetLock (&pSpxAddr->sa_Lock, &lockHandle);
+ addrLock = TRUE;
+
+ // We use a bit setting in the flag to prevent reentering
+ // per address file.
+ //
+ // We first search the list of non-inactive connections on the address
+ // this packet came in on to see if it is a duplicate. If it is, we just
+ // resend ack. Note we dont need to scan the global connection list.
+ status = SpxAddrConnByRemoteIdAddrLock(
+ pSpxAddr, srcConnId, pIpxSpxHdr->hdr_SrcNet, &pSpxConnFile);
+
+ if (NT_SUCCESS(status))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleConnReq: Received duplicate connect req! %lx\n",
+ pSpxConnFile));
+
+ if (SPX_CONN_ACTIVE(pSpxConnFile) ||
+ (SPX_CONN_LISTENING(pSpxConnFile) &&
+ ((SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_SENTACK) ||
+ (SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_SETUP))))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleConnReq: Sending Duplicate CR - ACK! %lx\n",
+ pSpxConnFile));
+
+ // Build and send an ack
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ SpxPktBuildCrAck(
+ pSpxConnFile,
+ pSpxAddr,
+ &pCrAckPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG),
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2));
+
+ if (pCrAckPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pCrAckPkt);
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock (&pSpxAddr->sa_Lock, lockHandle);
+ addrLock = FALSE;
+
+ // Send the CR Ack packet!
+ if (pCrAckPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pCrAckPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pCrAckPkt, pSendResd);
+ }
+ }
+
+ if (addrLock)
+ {
+ CTEFreeLock (&pSpxAddr->sa_Lock, lockHandle);
+ // We should return in this if, else addrLock should be set to
+ // FALSE.
+ }
+
+ // Deref the connection
+ SpxConnFileDereference(pSpxConnFile, CFREF_ADDR);
+
+ // Deref the address
+ SpxAddrDereference (pSpxAddr, AREF_LOOKUP);
+ return;
+ }
+
+ do
+ {
+ // New connection request:
+ // Assume we will be able to accept it and allocate a packet for the ack.
+ // Walk list of listening connections if any.
+
+ pSpxRefFile = NULL;
+ if ((pSpxConnFile = pSpxAddr->sa_ListenConnList) != NULL)
+ {
+ PTDI_REQUEST_KERNEL_LISTEN pParam;
+
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnIndicate: Listen available!\n"));
+
+ // dequeue connection
+ pSpxAddr->sa_ListenConnList = pSpxConnFile->scf_Next;
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ CTEAssert(!IsListEmpty(&pSpxConnFile->scf_ReqLinkage));
+ pListenReq = LIST_ENTRY_TO_REQUEST(pSpxConnFile->scf_ReqLinkage.Flink);
+ pParam = (PTDI_REQUEST_KERNEL_LISTEN)REQUEST_PARAMETERS(pListenReq);
+
+ // if autoaccept, acceptIrp = listenIrp, get connection id and
+ // process as we do for an indication. As the connection has a
+ // listen posted on it, it must have a reference for it.
+ //
+ // if !autoaccept, we need to complete the listen irp.
+ delayAccept = (BOOLEAN)((pParam->RequestFlags & TDI_QUERY_ACCEPT) != 0);
+ if (delayAccept)
+ {
+ // Remove the listen irp and prepare for completion.
+ // NOTE!! Here we do not remove the listen reference. This will
+ // be removed if disconnect happens, or if accept
+ // happens, it is transferred to being ref for connection
+ // being active.
+ RemoveEntryList(REQUEST_LINKAGE(pListenReq));
+ REQUEST_STATUS(pListenReq) = STATUS_SUCCESS;
+ REQUEST_INFORMATION(pListenReq) = 0;
+ }
+
+ // Are we ok with spx2?
+ if (!(SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2)) ||
+ !fSpx2)
+ {
+ // We better use spx only.
+ SPX_CONN_RESETFLAG(pSpxConnFile,
+ (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
+ fSpx2 = fNeg = FALSE;
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+
+ connectAccepted = TRUE;
+ tdiListen = TRUE;
+ }
+ else
+ {
+ // No listens available. Check for connect handlers.
+ // Walk list of address files indicating to each until accepted.
+ for (pSpxAddrFile = pSpxAddr->sa_AddrFileList;
+ pSpxAddrFile != NULL;
+ pSpxAddrFile = pSpxAddrFile->saf_Next)
+ {
+ if ((pSpxAddrFile->saf_Flags & (SPX_ADDRFILE_CLOSING |
+ SPX_ADDRFILE_CONNIND)) ||
+ ((connHandler = pSpxAddrFile->saf_ConnHandler) == NULL))
+ {
+ continue;
+ }
+
+ // Connect indication in progress, drop all subsequent.
+ pSpxAddrFile->saf_Flags |= SPX_ADDRFILE_CONNIND;
+
+ connHandlerCtx = pSpxAddrFile->saf_ConnHandlerCtx;
+ SpxAddrFileLockReference(pSpxAddrFile, AFREF_INDICATION);
+ CTEFreeLock(&pSpxAddr->sa_Lock, lockHandle);
+ addrLock = FALSE;
+
+ if (pSpxRefFile)
+ {
+ SpxAddrFileDereference(pSpxRefFile, AFREF_INDICATION);
+ pSpxRefFile = NULL;
+ }
+
+ // Make the indication. We are always returned an accept irp on
+ // indication. Else we fail to accept the connection.
+ status = (*connHandler)(
+ connHandlerCtx,
+ sizeof(srcIpxAddr),
+ (PVOID)&srcIpxAddr,
+ 0, // User data length
+ NULL, // User data
+ 0, // Option length
+ NULL, // Options
+ &connCtx,
+ &acceptIrp);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConn: indicate status %lx.%lx\n",
+ status, acceptIrp));
+
+ CTEGetLock (&pSpxAddr->sa_Lock, &lockHandle);
+ addrLock = TRUE;
+ pSpxAddrFile->saf_Flags &= ~SPX_ADDRFILE_CONNIND;
+
+ if (status == STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ CTEAssert(acceptIrp != NULL);
+
+ // Find the connection and accept the connection using that
+ // connection object.
+ SpxConnFileReferenceByCtxLock(
+ pSpxAddrFile,
+ connCtx,
+ &pSpxConnFile,
+ &status);
+
+ if (!NT_SUCCESS(status))
+ {
+ // The connection object is closing, or is not found
+ // in our list. The accept irp must have had the same
+ // connection object. AFD isnt behaving well.
+ KeBugCheck(0);
+ }
+
+ // Only for debugging.
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_BYCTX,
+ CFREF_VERIFY);
+
+ pListenReq = SpxAllocateRequest(
+ SpxDevice,
+ acceptIrp);
+
+ IF_NOT_ALLOCATED(pListenReq)
+ {
+ acceptIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT);
+
+ // Setup for dereference
+ pSpxRefFile = pSpxAddrFile;
+ break;
+ }
+
+ InsertTailList(
+ &pSpxConnFile->scf_ReqLinkage,
+ REQUEST_LINKAGE(pListenReq));
+
+ // Setup for dereference
+ pSpxRefFile = pSpxAddrFile;
+ connectAccepted = TRUE;
+
+ // See if this connection is to be a spx2 connection.
+ SPX_CONN_RESETFLAG(pSpxConnFile,
+ (SPX_CONNFILE_SPX2 |
+ SPX_CONNFILE_NEG |
+ SPX_CONNFILE_STREAM));
+
+ if ((pSpxAddrFile->saf_Flags & SPX_ADDRFILE_SPX2) && fSpx2)
+ {
+ SPX_CONN_SETFLAG(
+ pSpxConnFile, (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
+ }
+ else
+ {
+ fSpx2 = fNeg = FALSE;
+ }
+
+ if (pSpxAddrFile->saf_Flags & SPX_ADDRFILE_STREAM)
+ {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_STREAM);
+ }
+
+ if (pSpxAddrFile->saf_Flags & SPX_ADDRFILE_NOACKWAIT)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleConnReq: NOACKWAIT requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_NOACKWAIT);
+ }
+
+ if (pSpxAddrFile->saf_Flags & SPX_ADDRFILE_IPXHDR)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleConnReq: IPXHDR requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR);
+ }
+
+ break;
+ }
+ else
+ {
+ // We are not going to accept the connection on this address.
+ // Try next one.
+ pSpxRefFile = pSpxAddrFile;
+ continue;
+ }
+ }
+ }
+
+ } while (FALSE);
+
+ if (addrLock)
+ {
+ CTEFreeLock (&pSpxAddr->sa_Lock, lockHandle);
+ // No need for flag from this point on.
+ // addrLock = FALSE;
+ }
+
+ if (pSpxRefFile)
+ {
+ SpxAddrFileDereference(pSpxRefFile, AFREF_INDICATION);
+ pSpxRefFile = NULL;
+ }
+
+ if (connectAccepted)
+ {
+ CTEGetLock (&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock (&pSpxAddr->sa_Lock, &lockHandle);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ if (((USHORT)PARAM(CONFIG_WINDOW_SIZE) == 0) ||
+ ((USHORT)PARAM(CONFIG_WINDOW_SIZE) > MAX_WINDOW_SIZE))
+ {
+ PARAM(CONFIG_WINDOW_SIZE) = DEFAULT_WINDOW_SIZE;
+ }
+
+ pSpxConnFile->scf_LocalConnId = spxConnGetId();
+ pSpxConnFile->scf_RemConnId = srcConnId;
+ pSpxConnFile->scf_SendSeqNum = 0;
+ pSpxConnFile->scf_RecvSeqNum = 0;
+ pSpxConnFile->scf_RecdAckNum = 0;
+ pSpxConnFile->scf_RetrySeqNum = 0;
+ pSpxConnFile->scf_SentAllocNum = (USHORT)(PARAM(CONFIG_WINDOW_SIZE) - 1);
+ pSpxConnFile->scf_RecdAllocNum = allocNum;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnHandleConnReq: %lx CONN L.R %lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_LocalConnId,
+ pSpxConnFile->scf_RemConnId));
+
+ pSpxConnFile->scf_LocalTarget = *pRemoteAddr;
+ pSpxConnFile->scf_AckLocalTarget= *pRemoteAddr;
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAddr);
+
+ // Set max packet size in connection
+ SPX_MAX_PKT_SIZE(pSpxConnFile, (fSpx2 && fNeg), fSpx2, pIpxSpxHdr->hdr_SrcNet);
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleConnReq: Accept connect req on %lx.%lx..%lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_LocalConnId,
+ pSpxConnFile->scf_RecdAllocNum, pSpxConnFile->scf_MaxPktSize));
+
+ // Aborts must now deal with the lists. Need this as Accept has to
+ // deal with it.
+ // Put in non-inactive list. All processing now is equivalent to
+ // that when a listen is completed on a connection.
+ if ((!tdiListen) && (!NT_SUCCESS(spxConnRemoveFromList(
+ &pSpxAddr->sa_InactiveConnList,
+ pSpxConnFile))))
+ {
+ // Should never happen!
+ KeBugCheck(0);
+ }
+
+ SPX_INSERT_ADDR_ACTIVE(pSpxAddr, pSpxConnFile);
+
+ // Insert in the global connection tree on device.
+ spxConnInsertIntoGlobalActiveList(
+ pSpxConnFile);
+
+ SPX_CONN_SETFLAG(pSpxConnFile,
+ ((fNeg ? SPX_CONNFILE_NEG : 0) |
+ (fSpx2 ? SPX_CONNFILE_SPX2: 0)));
+
+ //
+ // If this was a post-inactivated file, clear the disconnect flags
+ //
+ if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED)) {
+
+ SPX_DISC_SETSTATE(pSpxConnFile, 0);
+ }
+#if 0
+ //
+ // Make sure that this connection got a local disconnect if it was an SPXI
+ // connection earlier, in response to a TDI_DISCONNECT_RELEASE.
+ //
+
+ CTEAssert(pSpxConnFile->scf_RefTypes[CFREF_DISCWAITSPX] == 0);
+#endif
+
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_LISTENING);
+ SPX_LISTEN_SETSTATE(pSpxConnFile, (delayAccept ? SPX_LISTEN_RECDREQ : 0));
+
+ if (!delayAccept)
+ {
+ spxConnAcceptCr(
+ pSpxConnFile,
+ pSpxAddr,
+ lockHandleDev,
+ lockHandle,
+ lockHandleConn);
+ }
+ else
+ {
+ // Release the locks.
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock (&pSpxAddr->sa_Lock, lockHandle);
+ CTEFreeLock (&SpxDevice->dev_Lock, lockHandleDev);
+
+ // Complete the listen irp. Note reference is not removed. Done when
+ // accept is posted.
+ SpxCompleteRequest(pListenReq);
+ }
+ } else {
+ ++SpxDevice->dev_Stat.NoListenFailures;
+ }
+
+ // Deref the address
+ SpxAddrDereference (pSpxAddr, AREF_LOOKUP);
+ return;
+}
+
+
+
+
+VOID
+spxConnHandleSessPktFromClient(
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+ Packet received from the client side of the connection.
+ Handles:
+ Session Negotiate
+ Sends Session Setup, when recd, handles SS Ack
+
+ STATE MACHINE:
+
+ RR
+ / \
+ / \ ReceivedAck(SPX1Connection)
+ / \
+ / \--------> ACTIVE
+ / ^
+ Send / |
+ ACK / |
+ / |
+ / RecvNeg/NoNeg |
+ / SendSS |
+ SA--------->SS---------------+
+ ^ | SSAckRecv
+ | |
+ +-----+
+ RecvNeg
+
+ RR - Received Connect Request
+ SA - Sent CR Ack
+ SS - Sent Session Setup
+
+ We move from SA to SS when connection is not negotiatiable and we
+ immediately send the SS, or when we receive negotiate packet and send the neg
+ ack and the session setup.
+
+ Note we could receive a negotiate packet when in SS, as our ack to the
+ negotiate could have been dropped. We deal with this.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PNDIS_PACKET pSnAckPkt, pSsPkt = NULL;
+ PSPX_SEND_RESD pSendResd, pSsSendResd;
+ USHORT srcConnId, destConnId,
+ pktLen, seqNum, negSize, ackNum, allocNum;
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+ BOOLEAN locksHeld = FALSE;
+
+ GETSHORT2SHORT(&pktLen, &pIpxSpxHdr->hdr_PktLen);
+ GETSHORT2SHORT(&destConnId, &pIpxSpxHdr->hdr_DestConnId);
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+ GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
+
+ // We keep and use the remote id in the net format. This maintains the
+ // 0x0 and 0xFFFF to be as in the host format.
+ srcConnId = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_SrcConnId;
+
+ // If spx2 we convert neg size field too
+ if (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2)
+ {
+ GETSHORT2SHORT(&negSize, &pIpxSpxHdr->hdr_NegSize);
+ CTEAssert(negSize > 0);
+ }
+
+ // Grab all three locks
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ locksHeld = TRUE;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnHandleSessPktFromClient: %lx\n", pSpxConnFile));
+
+ // Check substate
+ switch (SPX_LISTEN_STATE(pSpxConnFile))
+ {
+ case SPX_LISTEN_RECDREQ:
+
+ // Do nothing.
+ break;
+
+ case SPX_LISTEN_SETUP:
+
+ // Is this a setup ack? If so, yippee. Our ack to a negotiate packet
+ // could have been dropped, and so we could also get a negotiate packet
+ // in that case. If that happens, fall through.
+ // Verify Ss Ack
+ if (!SPX2_CONN(pSpxConnFile) ||
+ (pktLen != MIN_IPXSPX2_HDRSIZE) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_SYS | SPX_CC_SPX2)) !=
+ (SPX_CC_SYS | SPX_CC_SPX2)) ||
+ (pIpxSpxHdr->hdr_DataType != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId) ||
+ (seqNum != 0))
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnSysPacket: VerifySSACK Failed Checking SN %lx.%lx\n",
+ srcConnId, destConnId));
+
+ // Fall through to see if this is a neg packet
+ if (!(SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG)))
+ {
+ break;
+ }
+ }
+ else
+ {
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromClient: Recd SSACK %lx\n",
+ pSpxConnFile));
+
+ spxConnCompleteConnect(
+ pSpxConnFile,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ break;
+ }
+
+ case SPX_LISTEN_SENTACK:
+
+ // We expect a negotiate packet.
+ // We should have asked for SPX2/NEG to begin with.
+ // Verify Sn
+ if (((pSpxConnFile->scf_Flags & (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG)) !=
+ (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG)) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) !=
+ (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) ||
+ (pIpxSpxHdr->hdr_DataType != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId) ||
+ (seqNum != 0) ||
+ ((negSize < SPX_NEG_MIN) ||
+ (negSize > SPX_NEG_MAX)))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnSysPacket: VerifySN Failed %lx.%lx\n",
+ srcConnId, destConnId));
+
+ break;
+ }
+
+ // Remember max packet size in connection.
+ pSpxConnFile->scf_MaxPktSize = negSize;
+ CTEAssert(negSize > 0);
+
+ // Build sn ack, abort if we fail
+ SpxPktBuildSnAck(
+ pSpxConnFile,
+ &pSnAckPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY);
+
+ if (pSnAckPkt == NULL)
+ {
+ spxConnAbortConnect(
+ pSpxConnFile,
+ STATUS_INSUFFICIENT_RESOURCES,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ break;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromClient: Sending SNACK %lx\n",
+ pSpxConnFile));
+
+ // Queue in the packet.
+ SpxConnQueueSendPktTail(pSpxConnFile, pSnAckPkt);
+
+ // The session packet should already be on queue.
+ if (!spxConnGetPktByType(
+ pSpxConnFile,
+ SPX_TYPE_SS,
+ FALSE,
+ &pSsPkt))
+ {
+ KeBugCheck(0);
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromClient: Sending SS %lx\n",
+ pSpxConnFile));
+
+ pSsSendResd = (PSPX_SEND_RESD)(pSsPkt->ProtocolReserved);
+
+ // We need to resend the packet
+ if ((pSsSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0)
+ {
+ // Try next time.
+ pSsPkt = NULL;
+ }
+ else
+ {
+ // Set the size to the neg size indicated in connection.
+ // This could be lower than the size the packet was build
+ // with originally. But will never be higher.
+ pSsSendResd->sr_State |= SPX_SENDPKT_IPXOWNS;
+ spxConnSetNegSize(
+ pSsPkt,
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE);
+ }
+
+ // If we are actually LISTEN_SETUP, then send the ss packet also.
+ // We need to start the connect timer to resend the ss pkt.
+ if (SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_SENTACK)
+ {
+ if ((pSpxConnFile->scf_CTimerId =
+ SpxTimerScheduleEvent(
+ spxConnConnectTimer,
+ PARAM(CONFIG_CONNECTION_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) == 0)
+ {
+ spxConnAbortConnect(
+ pSpxConnFile,
+ STATUS_INSUFFICIENT_RESOURCES,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ break;
+ }
+
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+
+ SPX_LISTEN_SETSTATE(pSpxConnFile, SPX_LISTEN_SETUP);
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ locksHeld = FALSE;
+
+ // Send ack packet
+ pSendResd = (PSPX_SEND_RESD)(pSnAckPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pSnAckPkt, pSendResd);
+
+ // If we have to send the session setup packet, send that too.
+ if (pSsPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pSsPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pSsPkt, pSendResd);
+ }
+
+ break;
+
+ default:
+
+ // Ignore
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnSysPacket: UNKNOWN %lx.%lx\n",
+ srcConnId, destConnId));
+
+ break;
+ }
+
+ if (locksHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnHandleSessPktFromSrv(
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+ Packet received from the server side of the connection. This will both
+ release the lock and dereference the connection as it sees fit.
+
+ STATE MACHINE:
+
+ SR--CTimerExpires-->IDLE
+ /| \
+ / | \ ReceivedAck(SPX1Connection)
+ / | \
+ / | \--------> ACTIVE
+ (Neg) / | ^
+ Send / |RecvAck |
+ SN / |NoNeg |
+ / | |
+ / | |
+ / v |
+ SN--------->WS---------------+
+ RecvSNAck RecvSS
+
+ SR - Sent Connect request
+ SN - Sent Session Negotiate
+ WS - Waiting for session setup packet
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ BOOLEAN fNeg, fSpx2;
+ USHORT srcConnId, destConnId,
+ pktLen, seqNum, negSize, ackNum, allocNum;
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+ BOOLEAN cTimerCancelled = FALSE, fAbort = FALSE, locksHeld = FALSE;
+ PNDIS_PACKET pSsAckPkt, pSnPkt, pPkt = NULL;
+
+ // We should get a CR Ack, or if our substate is sent session neg
+ // we should get a session neg ack, or if we are waiting for session
+ // setup, we should get one of those.
+
+ fSpx2 = (BOOLEAN)(pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2);
+ fNeg = (BOOLEAN)(fSpx2 && (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_NEG));
+
+ GETSHORT2SHORT(&pktLen, &pIpxSpxHdr->hdr_PktLen);
+ GETSHORT2SHORT(&destConnId, &pIpxSpxHdr->hdr_DestConnId);
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+ GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
+
+ // We keep and use the remote id in the net format. This maintains the
+ // 0x0 and 0xFFFF to be as in the host format.
+ srcConnId = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_SrcConnId;
+
+ // If spx2 we convert neg size field too
+ if (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2)
+ {
+ GETSHORT2SHORT(&negSize, &pIpxSpxHdr->hdr_NegSize);
+ CTEAssert(negSize > 0);
+ }
+
+ // Grab all three locks
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ locksHeld = TRUE;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnHandleSessPktFromSrv: %lx\n", pSpxConnFile));
+
+ // Check substate
+ switch (SPX_CONNECT_STATE(pSpxConnFile))
+ {
+ case SPX_CONNECT_SENTREQ:
+
+ // Check if this qualifies as the ack.
+ // Verify CR Ack
+ if ((pIpxSpxHdr->hdr_DataType != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (seqNum != 0) ||
+ (ackNum != 0) ||
+ ((pktLen != MIN_IPXSPX_HDRSIZE) &&
+ ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
+ (pktLen != MIN_IPXSPX2_HDRSIZE))) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
+ ((negSize < SPX_NEG_MIN) ||
+ (negSize > SPX_NEG_MAX))))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleSessPktFromSrv: CRAck Invalid %lx %lx.%lx.%lx\n",
+ pSpxConnFile,
+ pktLen, negSize, pIpxSpxHdr->hdr_ConnCtrl));
+
+ break;
+ }
+
+ // !!!BUGBUG!!!
+ // From current spx code base:
+ // Do we need to send an ack to this ack? In case of SPX only?
+ // What if this ack is dropped? We need to send an ack, if in future
+ // we get CONNECT REQ Acks, until we reach active?
+ // * If they want an ack schedule it. The normal case is for this not
+ // * to happen, but some Novell mainframe front ends insist on having
+ // * this. And technically, it is OK for them to do this.
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnHandleSessPktFromSrv: Recd CRACK %lx\n", pSpxConnFile));
+
+ // Grab the remote alloc num/conn id (in net format)
+ pSpxConnFile->scf_SendSeqNum = 0;
+ pSpxConnFile->scf_RecvSeqNum = 0;
+ pSpxConnFile->scf_RecdAckNum = 0;
+ pSpxConnFile->scf_RemConnId = srcConnId;
+ pSpxConnFile->scf_RecdAllocNum = allocNum;
+
+ // If we have been looking for network 0, which means the
+ // packets were sent on all NIC IDs, update our local
+ // target now that we have received a response.
+
+#if defined(_PNP_POWER)
+ if (pSpxConnFile->scf_LocalTarget.NicHandle.NicId == (USHORT)ITERATIVE_NIC_ID) {
+#else
+ if (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0) {
+#endif _PNP_POWER
+ pSpxConnFile->scf_LocalTarget = *pRemoteAddr;
+ pSpxConnFile->scf_AckLocalTarget= *pRemoteAddr;
+ }
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnHandleSessPktFromSrv: %lx CONN L.R %lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_LocalConnId,
+ pSpxConnFile->scf_RemConnId));
+
+ if (!fSpx2 || !fNeg)
+ {
+ cTimerCancelled = SpxTimerCancelEvent(
+ pSpxConnFile->scf_CTimerId, FALSE);
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+
+ if ((pSpxConnFile->scf_WTimerId =
+ SpxTimerScheduleEvent(
+ spxConnWatchdogTimer,
+ PARAM(CONFIG_KEEPALIVE_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) == 0)
+ {
+ fAbort = TRUE;
+ break;
+ }
+
+ // Reference transferred to watchdog timer.
+ if (cTimerCancelled)
+ {
+ cTimerCancelled = FALSE;
+ }
+ else
+ {
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+ }
+
+ // Set max packet size, assume not spx2 or !neg, so pass in FALSE
+ SPX_MAX_PKT_SIZE(pSpxConnFile, FALSE, FALSE, pIpxSpxHdr->hdr_SrcNet);
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPSrv: Accept connect req on %lx.%lx.%lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_LocalConnId,
+ pSpxConnFile->scf_RecdAllocNum, pSpxConnFile->scf_MaxPktSize));
+
+ if (!fSpx2)
+ {
+ // Reset spx2 flags.
+ SPX_CONN_RESETFLAG(pSpxConnFile, (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
+
+ // Complete connect request, this free the lock.
+ // Cancels tdi timer too. Sets all necessary flags.
+ spxConnCompleteConnect(
+ pSpxConnFile,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ break;
+ }
+
+ if (!fNeg)
+ {
+ // Goto W_SETUP
+ // Reset all connect related flags, also spx2/neg flags.
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_NEG);
+ SPX_CONNECT_SETSTATE(pSpxConnFile, SPX_CONNECT_W_SETUP);
+ break;
+ }
+
+ // Reset max packet size. SPX2 and NEG.
+ SPX_MAX_PKT_SIZE(pSpxConnFile, TRUE, TRUE, pIpxSpxHdr->hdr_SrcNet);
+
+ CTEAssert(negSize > 0);
+ CTEAssert(pSpxConnFile->scf_MaxPktSize > 0);
+ pSpxConnFile->scf_MaxPktSize =
+ MIN(negSize, pSpxConnFile->scf_MaxPktSize);
+
+ pSpxConnFile->scf_MaxPktSize = (USHORT)
+ MIN(pSpxConnFile->scf_MaxPktSize, PARAM(CONFIG_MAX_PACKET_SIZE));
+
+ // For SPX2 with negotiation, we set up sneg packet and move to
+ // SPX_CONNECT_NEG.
+ SpxPktBuildSn(
+ pSpxConnFile,
+ &pSnPkt,
+ SPX_SENDPKT_IPXOWNS);
+
+ if (pSnPkt == NULL)
+ {
+ fAbort = TRUE;
+ break;
+ }
+
+ // Queue in packet
+ SpxConnQueueSendPktTail(pSpxConnFile, pSnPkt);
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromSrv: Sending SN %lx\n",
+ pSpxConnFile));
+
+ // Reset retry count for connect timer
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
+
+ // Change state.
+ SPX_CONNECT_SETSTATE(pSpxConnFile, SPX_CONNECT_NEG);
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ locksHeld = FALSE;
+
+ // Send the packet
+ pSendResd = (PSPX_SEND_RESD)(pSnPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pSnPkt, pSendResd);
+ break;
+
+ case SPX_CONNECT_NEG:
+
+ // We expect a session neg ack.
+ // We should have asked for SPX2/NEG to begin with.
+ // Verify SN Ack
+ if (((pSpxConnFile->scf_Flags & (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG)) !=
+ (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG)) ||
+ (pktLen != MIN_IPXSPX2_HDRSIZE) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) !=
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) ||
+ (pIpxSpxHdr->hdr_DataType != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId) ||
+ (seqNum != 0))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnSysPacket: VerifySNACK Failed %lx.%lx\n",
+ srcConnId, destConnId));
+
+ break;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromSrv: Recd SNACK %lx %lx.%lx\n",
+ pSpxConnFile, negSize, pSpxConnFile->scf_MaxPktSize));
+
+ if (negSize > pSpxConnFile->scf_MaxPktSize)
+ negSize = pSpxConnFile->scf_MaxPktSize;
+
+ // Get the size to use
+ if (negSize <= pSpxConnFile->scf_MaxPktSize)
+ {
+ pSpxConnFile->scf_MaxPktSize = negSize;
+ if (!spxConnGetPktByType(
+ pSpxConnFile,
+ SPX_TYPE_SN,
+ FALSE,
+ &pPkt))
+ {
+ KeBugCheck(0);
+ }
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0)
+ {
+ // Set abort flag and reference conn for the pkt.
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+ else
+ {
+ // Free the negotiate packet
+ SpxPktSendRelease(pPkt);
+ }
+
+ CTEAssert(pSpxConnFile->scf_Flags & SPX_CONNFILE_C_TIMER);
+ cTimerCancelled = SpxTimerCancelEvent(
+ pSpxConnFile->scf_CTimerId, FALSE);
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+
+ // Start the watchdog timer, if fail, we abort.
+ if ((pSpxConnFile->scf_WTimerId =
+ SpxTimerScheduleEvent(
+ spxConnWatchdogTimer,
+ PARAM(CONFIG_KEEPALIVE_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) == 0)
+ {
+ // Complete cr with error.
+ fAbort = TRUE;
+ break;
+ }
+
+ // Reference goes to watchdog timer.
+ if (cTimerCancelled)
+ {
+ cTimerCancelled = FALSE;
+ }
+ else
+ {
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ // We move to the W_SETUP state.
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+
+ SPX_CONNECT_SETSTATE(pSpxConnFile, SPX_CONNECT_W_SETUP);
+ }
+
+ break;
+
+ case SPX_CONNECT_W_SETUP:
+
+ // Does this qualify as a session setup packet?
+ // Verify SS
+ if (!SPX2_CONN(pSpxConnFile) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_SPX2)) !=
+ (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_SPX2)) ||
+ (pIpxSpxHdr->hdr_DataType != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId) ||
+ (seqNum != 0) ||
+ ((negSize < SPX_NEG_MIN) ||
+ (negSize > SPX_NEG_MAX)))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnSysPacket: VerifySS Failed %lx.%lx, %lx %lx.%lx\n",
+ srcConnId, destConnId, negSize,
+ pIpxSpxHdr->hdr_ConnCtrl,
+ (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_SPX2)));
+
+ break;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromSrv: Recd SS %lx\n", pSpxConnFile));
+
+ // Copy remote address over into connection (socket could change)
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAddr);
+
+ // Remember max packet size in connection.
+ pSpxConnFile->scf_MaxPktSize = negSize;
+
+ // Build ss ack, abort if we fail
+ SpxPktBuildSsAck(
+ pSpxConnFile,
+ &pSsAckPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY | SPX_SENDPKT_ABORT);
+
+ if (pSsAckPkt == NULL)
+ {
+ fAbort = TRUE;
+ break;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromSrv: Sending SSACK %lx\n",
+ pSpxConnFile));
+
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+
+ // We dont queue in the pkt as its already marked as abort.
+ // Queue in the packet.
+ // SpxConnQueueSendPktTail(pSpxConnFile, pSsAckPkt);
+
+ // Complete connect, this releases lock.
+ spxConnCompleteConnect(
+ pSpxConnFile,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+
+ // Send ack packet
+ pSendResd = (PSPX_SEND_RESD)(pSsAckPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pSsAckPkt, pSendResd);
+ break;
+
+ default:
+
+ // Ignore
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnSysPacket: UNKNOWN %lx.%lx\n",
+ srcConnId, destConnId));
+
+ break;
+ }
+
+ if (fAbort)
+ {
+ spxConnAbortConnect(
+ pSpxConnFile,
+ STATUS_INSUFFICIENT_RESOURCES,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ }
+
+ if (locksHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ }
+
+ if (cTimerCancelled)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnAbortConnect(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN CTELockHandle LockHandleDev,
+ IN CTELockHandle LockHandleAddr,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+ This routine abort a connection (both client and server side) in the middle
+ of a connection establishment.
+
+ !!! Called with connection lock held, releases lock before return !!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt;
+ PREQUEST pRequest = NULL;
+ int numDerefs = 0;
+
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnAbortConnect: %lx\n", pSpxConnFile));
+
+#if DBG
+ if (!SPX_CONN_CONNECTING(pSpxConnFile) && !SPX_CONN_LISTENING(pSpxConnFile))
+ {
+ KeBugCheck(0);
+ }
+#endif
+
+ if (Status == STATUS_INSUFFICIENT_RESOURCES) { // others should be counted elsewhere
+ ++SpxDevice->dev_Stat.LocalResourceFailures;
+ }
+
+ // Free up all the packets
+ while ((pSendResd = pSpxConnFile->scf_SendListHead) != NULL)
+ {
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // Set abort flag and reference conn for the pkt.
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+ }
+
+
+ // Cancel all timers
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_TTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER);
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_CTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_WTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ }
+
+ // We could be called from disconnect for an accept in which case there
+ // will be no queued request. But we need to remove the reference if there
+ // is no request (an accept/listen irp) and listen state is on.
+ CTEAssert(IsListEmpty(&pSpxConnFile->scf_DiscLinkage));
+ if (!IsListEmpty(&pSpxConnFile->scf_ReqLinkage))
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(pSpxConnFile->scf_ReqLinkage.Flink);
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+ REQUEST_STATUS(pRequest) = Status;
+ REQUEST_INFORMATION(pRequest) = 0;
+
+ // Save req in conn for deref to complete.
+ pSpxConnFile->scf_ConnectReq = pRequest;
+
+ numDerefs++;
+ }
+ else if (SPX_CONN_LISTENING(pSpxConnFile))
+ {
+ numDerefs++;
+ }
+
+ // Bug #20999
+ // Race condition was an abort came in from timer, but the connect state
+ // was left unchanged. Due to an extra ref on the connection from the
+ // aborted cr, the state remained so, and then the cr ack came in, and
+ // a session neg was built and queued on the connection. Although it should
+ // not have been. And we hit the assert in deref where the connection is
+ // being reinitialized. Since this can be called for both listening and
+ // connecting connections, do the below.
+ SPX_LISTEN_SETSTATE(pSpxConnFile, 0);
+ if (SPX_CONN_CONNECTING(pSpxConnFile))
+ {
+ SPX_CONNECT_SETSTATE(pSpxConnFile, 0);
+ }
+
+ CTEFreeLock (&pSpxConnFile->scf_Lock, LockHandleConn);
+ CTEFreeLock (pSpxConnFile->scf_AddrFile->saf_AddrLock, LockHandleAddr);
+ CTEFreeLock (&SpxDevice->dev_Lock, LockHandleDev);
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+VOID
+spxConnCompleteConnect(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleDev,
+ IN CTELockHandle LockHandleAddr,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+ This routine completes a connection (both client and server side)
+ !!! Called with connection lock held, releases lock before return !!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PREQUEST pRequest;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt;
+ int numDerefs = 0;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnCompleteConnect: %lx\n", pSpxConnFile));
+
+#if DBG
+ if (!SPX_CONN_CONNECTING(pSpxConnFile) && !SPX_CONN_LISTENING(pSpxConnFile))
+ {
+ DBGBRK(FATAL);
+ }
+#endif
+
+ // Free up all the packets
+ while ((pSendResd = pSpxConnFile->scf_SendListHead) != NULL)
+ {
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // Set abort flag and reference conn for the pkt.
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+ }
+
+
+ // Cancel tdi connect timer if we are connecting.
+ switch (SPX_MAIN_STATE(pSpxConnFile))
+ {
+ case SPX_CONNFILE_CONNECTING:
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_TTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER);
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_CTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+ }
+
+ if (pSpxConnFile->scf_CRetryCount == (LONG)(PARAM(CONFIG_CONNECTION_COUNT))) {
+ ++SpxDevice->dev_Stat.ConnectionsAfterNoRetry;
+ } else {
+ ++SpxDevice->dev_Stat.ConnectionsAfterRetry;
+ }
+
+ // Reset all connect related flags
+ SPX_MAIN_SETSTATE(pSpxConnFile, 0);
+ SPX_CONNECT_SETSTATE(pSpxConnFile, 0);
+ break;
+
+ case SPX_CONNFILE_LISTENING:
+
+ if (pSpxConnFile->scf_Flags & SPX_CONNFILE_C_TIMER)
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_CTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+ }
+
+ SPX_MAIN_SETSTATE(pSpxConnFile, 0);
+ SPX_LISTEN_SETSTATE(pSpxConnFile, 0);
+ break;
+
+ default:
+
+ KeBugCheck(0);
+
+ }
+
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_ACTIVE);
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ SPX_RECV_SETSTATE(pSpxConnFile, SPX_RECV_IDLE);
+
+ ++SpxDevice->dev_Stat.OpenConnections;
+
+ // Initialize timer values
+ pSpxConnFile->scf_BaseT1 =
+ pSpxConnFile->scf_AveT1 = PARAM(CONFIG_INITIAL_RETRANSMIT_TIMEOUT);
+ pSpxConnFile->scf_DevT1 = 0;
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+
+ pRequest = LIST_ENTRY_TO_REQUEST(pSpxConnFile->scf_ReqLinkage.Flink);
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+ REQUEST_STATUS(pRequest) = STATUS_SUCCESS;
+ REQUEST_INFORMATION(pRequest) = 0;
+
+ // When we complete the request, we essentially transfer the reference
+ // to the fact that the connection is active. This will be taken away
+ // when a Disconnect happens on the connection and we transition from
+ // ACTIVE to DISCONN.
+ // numDerefs++;
+
+ CTEFreeLock (&pSpxConnFile->scf_Lock, LockHandleConn);
+ CTEFreeLock (pSpxConnFile->scf_AddrFile->saf_AddrLock, LockHandleAddr);
+ CTEFreeLock (&SpxDevice->dev_Lock, LockHandleDev);
+
+ // Complete request
+ SpxCompleteRequest(pRequest);
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+BOOLEAN
+spxConnAcceptCr(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_ADDR pSpxAddr,
+ IN CTELockHandle LockHandleDev,
+ IN CTELockHandle LockHandleAddr,
+ IN CTELockHandle LockHandleConn
+ )
+{
+ PNDIS_PACKET pSsPkt, pCrAckPkt;
+ PSPX_SEND_RESD pSendResd;
+
+ BOOLEAN fNeg = SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG);
+ BOOLEAN fSpx2 = SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2);
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnAcceptCr: %lx.%d.%d\n",
+ pSpxConnFile, fSpx2, fNeg));
+
+ // Build and queue in packet.
+ SpxPktBuildCrAck(
+ pSpxConnFile,
+ pSpxAddr,
+ &pCrAckPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
+ fNeg,
+ fSpx2);
+
+ if ((pCrAckPkt != NULL) &&
+ (pSpxConnFile->scf_LocalConnId != 0))
+ {
+ // Queue in the packet.
+ SpxConnQueueSendPktTail(pSpxConnFile, pCrAckPkt);
+ }
+ else
+ {
+ goto AbortConnect;
+ }
+
+
+ // Start the timer
+ if ((pSpxConnFile->scf_WTimerId =
+ SpxTimerScheduleEvent(
+ spxConnWatchdogTimer,
+ PARAM(CONFIG_KEEPALIVE_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) != 0)
+ {
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+ }
+ else
+ {
+ goto AbortConnect;
+ }
+
+
+ // We start the connect timer for retrying ss which we send out now
+ // if we are not negotiating.
+ if (fSpx2)
+ {
+ // Build the session setup packet also for spx2.
+ SpxPktBuildSs(
+ pSpxConnFile,
+ &pSsPkt,
+ (USHORT)(fNeg ? 0 : SPX_SENDPKT_IPXOWNS));
+
+ if (pSsPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pSsPkt);
+ }
+ else
+ {
+ goto AbortConnect;
+ }
+
+ if (!fNeg)
+ {
+ if ((pSpxConnFile->scf_CTimerId =
+ SpxTimerScheduleEvent(
+ spxConnConnectTimer,
+ PARAM(CONFIG_CONNECTION_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) != 0)
+ {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
+
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ }
+ else
+ {
+ goto AbortConnect;
+ }
+ }
+ }
+
+ CTEAssert((fNeg && fSpx2) || (!fSpx2 && !fNeg));
+
+ // For a SPX connection, we immediately become active. This happens
+ // in the completeConnect routine. !!Dont change it here!!
+ if (!fSpx2)
+ {
+ spxConnCompleteConnect(
+ pSpxConnFile,
+ LockHandleDev,
+ LockHandleAddr,
+ LockHandleConn);
+ }
+ else
+ {
+ SPX_LISTEN_SETSTATE(
+ pSpxConnFile, (fNeg ? SPX_LISTEN_SENTACK : SPX_LISTEN_SETUP));
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ CTEFreeLock (&pSpxAddr->sa_Lock, LockHandleAddr);
+ CTEFreeLock (&SpxDevice->dev_Lock, LockHandleDev);
+ }
+
+ // Send the CR Ack packet!
+ pSendResd = (PSPX_SEND_RESD)(pCrAckPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pCrAckPkt, pSendResd);
+
+ if (fSpx2 && !fNeg)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pSsPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pSsPkt, pSendResd);
+ }
+
+ return(TRUE);
+
+
+AbortConnect:
+
+ spxConnAbortConnect(
+ pSpxConnFile,
+ STATUS_INSUFFICIENT_RESOURCES,
+ LockHandleDev,
+ LockHandleAddr,
+ LockHandleConn);
+
+ return (FALSE);
+}
+
+
+
+BOOLEAN
+SpxConnPacketize(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN BOOLEAN fNormalState,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+ The caller needs to set the state to packetize before calling this
+ routine. This can be called when SEND state is RENEG also.
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+ fNormalState - If true, it will assume it can release lock to send,
+ else, it just builds pkts without releasing lock and
+ releases lock at end. Used after reneg changes size.
+
+Return Value:
+
+
+--*/
+{
+ PLIST_ENTRY p;
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ USHORT windowSize;
+ ULONG dataLen;
+ USHORT sendFlags;
+ int numDerefs = 0;
+ BOOLEAN fFirstPass = TRUE, fSuccess = TRUE;
+ PREQUEST pRequest;
+
+#if DBG
+ if ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_PACKETIZE) &&
+ fNormalState)
+ {
+ DBGBRK(FATAL);
+ KeBugCheck(0);
+ }
+#endif
+
+ // Build all of the packets. The firsttime flag is used so
+ // that if we get a 0 byte send, we will send it. The firsttime
+ // flag will be set and we will build the packet and send it.
+ //
+ // FOR SPX1, we cannot trust the remote window size. So we only send
+ // stuff if window size is greater than 0 *AND* we do not have any pending
+ // sends. Dont get in here if we are ABORT. Dont want to be handling any
+ // more requests.
+ while((SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_ABORT) &&
+ ((pRequest = pSpxConnFile->scf_ReqPkt) != NULL) &&
+ ((pSpxConnFile->scf_ReqPktSize > 0) || fFirstPass))
+ {
+ fFirstPass = FALSE;
+ windowSize = pSpxConnFile->scf_RecdAllocNum -
+ pSpxConnFile->scf_SendSeqNum + 1;
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnPacketize: WINDOW %lx for %lx\n",
+ windowSize, pSpxConnFile));
+
+
+ DBGPRINT(SEND, DBG,
+ ("REMALLOC %lx SENDSEQ %lx\n",
+ pSpxConnFile->scf_RecdAllocNum,
+ pSpxConnFile->scf_SendSeqNum));
+
+
+ CTEAssert(windowSize >= 0);
+
+ // Disconnect/Orderly release is not subject to window closure.
+ if ((pSpxConnFile->scf_ReqPktType == SPX_REQ_DATA) &&
+ (((windowSize == 0) && SPX2_CONN(pSpxConnFile)) ||
+ (!SPX2_CONN(pSpxConnFile) &&
+ (pSpxConnFile->scf_SendSeqListHead != NULL))))
+ {
+ break;
+ }
+
+ if (pSpxConnFile->scf_ReqPktType == SPX_REQ_DATA)
+ {
+ CTEAssert(pRequest == pSpxConnFile->scf_ReqPkt);
+
+ // Get data length
+ dataLen = (ULONG)MIN(pSpxConnFile->scf_ReqPktSize,
+ (pSpxConnFile->scf_MaxPktSize -
+ ((SPX2_CONN(pSpxConnFile) ?
+ MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE))));
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnPacketize: %lx Sending %lx Size %lx Req %lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_SendSeqNum,
+ dataLen,
+ pSpxConnFile->scf_ReqPkt,
+ pSpxConnFile->scf_ReqPktSize));
+
+ // Build data packet. Handles 0-length for data. Puts in seq num in
+ // send resd section of packet also.
+ sendFlags =
+ (USHORT)((fNormalState ? SPX_SENDPKT_IPXOWNS : 0) |
+ SPX_SENDPKT_REQ |
+ SPX_SENDPKT_SEQ |
+ ((!SPX2_CONN(pSpxConnFile) || (windowSize == 1)) ?
+ SPX_SENDPKT_ACKREQ : 0));
+
+ if (dataLen == pSpxConnFile->scf_ReqPktSize)
+ {
+ // Last packet of send, ask for a ack.
+ sendFlags |= (SPX_SENDPKT_LASTPKT | SPX_SENDPKT_ACKREQ);
+ if ((pSpxConnFile->scf_ReqPktFlags & TDI_SEND_PARTIAL) == 0)
+ sendFlags |= SPX_SENDPKT_EOM;
+ }
+
+ SpxPktBuildData(
+ pSpxConnFile,
+ &pPkt,
+ sendFlags,
+ (USHORT)dataLen);
+ }
+ else
+ {
+ dataLen = 0;
+
+ DBGPRINT(SEND, DBG,
+ ("Building DISC packet on %lx ReqPktSize %lx\n",
+ pSpxConnFile, pSpxConnFile->scf_ReqPktSize));
+
+ // Build informed disc/orderly rel packet, associate with request
+ SpxPktBuildDisc(
+ pSpxConnFile,
+ pRequest,
+ &pPkt,
+ (USHORT)((fNormalState ? SPX_SENDPKT_IPXOWNS : 0) | SPX_SENDPKT_REQ |
+ SPX_SENDPKT_SEQ | SPX_SENDPKT_LASTPKT),
+ (UCHAR)((pSpxConnFile->scf_ReqPktType == SPX_REQ_ORDREL) ?
+ SPX2_DT_ORDREL : SPX2_DT_IDISC));
+ }
+
+ if (pPkt != NULL)
+ {
+ // If we were waiting to send an ack, we don't have to as we are
+ // piggybacking it now. Cancel ack timer, get out.
+ if (fNormalState && SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ACKQ))
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxConnPacketize: Piggyback happening for %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RecvSeqNum));
+
+ // We are sending data, allow piggybacks to happen.
+ SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_IMMED_ACK);
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_ACKQ);
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_ATimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ }
+
+ if (pSpxConnFile->scf_ReqPktType != SPX_REQ_DATA)
+ {
+ // For a disconnect set the state
+ if (pSpxConnFile->scf_ReqPktType == SPX_REQ_ORDREL)
+ {
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC))
+ {
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_DISCONN);
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_SENT_ORDREL);
+ numDerefs++;
+ }
+ else if (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_POST_ORDREL)
+ {
+ CTEAssert((SPX_MAIN_STATE(pSpxConnFile) ==
+ SPX_CONNFILE_ACTIVE) ||
+ (SPX_MAIN_STATE(pSpxConnFile) ==
+ SPX_CONNFILE_DISCONN));
+
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_SENT_ORDREL);
+ }
+ else
+ {
+ CTEAssert(
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_SENT_ORDREL));
+ }
+ }
+ else
+ {
+ CTEAssert(SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN);
+ CTEAssert(SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_POST_IDISC);
+
+ // Note we have send the idisc here.
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_SENT_IDISC);
+ }
+ }
+ }
+ else
+ {
+ fSuccess = FALSE;
+ break;
+ }
+
+
+ // Queue in packet, reference request for the packet
+ SpxConnQueueSendSeqPktTail(pSpxConnFile, pPkt);
+ REQUEST_INFORMATION(pRequest)++;
+
+ pSpxConnFile->scf_ReqPktSize -= dataLen;
+ pSpxConnFile->scf_ReqPktOffset += dataLen;
+
+ DBGPRINT(SEND, INFO,
+ ("SpxConnPacketize: Req %lx Size after pkt %lx.%lx\n",
+ pSpxConnFile->scf_ReqPkt, pSpxConnFile->scf_ReqPktSize,
+ dataLen));
+
+ // Even if window size if zero, setup next request is current one
+ // is done. We are here only after we have packetized this send req.
+ if (pSpxConnFile->scf_ReqPktSize == 0)
+ {
+ // This request has been fully packetized. Either go on to
+ // next request or we are done packetizing.
+ p = REQUEST_LINKAGE(pRequest);
+ if (p->Flink == &pSpxConnFile->scf_ReqLinkage)
+ {
+ DBGPRINT(SEND, INFO,
+ ("SpxConnPacketize: Req %lx done, no more\n",
+ pRequest));
+
+ pSpxConnFile->scf_ReqPkt = NULL;
+ pSpxConnFile->scf_ReqPktSize = 0;
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pRequest = NULL;
+ }
+ else
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(p->Flink);
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ PTDI_REQUEST_KERNEL_SEND pParam;
+
+ pParam = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(pRequest);
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnPacketize: Req done, setting next %lx.%lx\n",
+ pRequest, pParam->SendLength));
+
+ DBGPRINT(SEND, INFO,
+ ("-%lx-\n",
+ pRequest));
+
+ // Set parameters in connection for another go.
+ pSpxConnFile->scf_ReqPkt = pRequest;
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pSpxConnFile->scf_ReqPktFlags = pParam->SendFlags;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DATA;
+
+ if ((pSpxConnFile->scf_ReqPktSize = pParam->SendLength) == 0)
+ {
+ // Another zero length send.
+ fFirstPass = TRUE;
+ }
+ }
+ else
+ {
+ PTDI_REQUEST_KERNEL_DISCONNECT pParam;
+
+ pParam =
+ (PTDI_REQUEST_KERNEL_DISCONNECT)REQUEST_PARAMETERS(pRequest);
+
+ pSpxConnFile->scf_ReqPkt = pRequest;
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pSpxConnFile->scf_ReqPktSize = 0;
+ fFirstPass = TRUE;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DISC;
+ if (pParam->RequestFlags == TDI_DISCONNECT_RELEASE)
+ {
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_ORDREL;
+ }
+ }
+ }
+ }
+
+ if (fNormalState)
+ {
+ // Send the packet if we are not at the reneg state
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ ++SpxDevice->dev_Stat.DataFramesSent;
+ ExInterlockedAddLargeStatistic(
+ &SpxDevice->dev_Stat.DataFrameBytesSent,
+ dataLen);
+ SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ }
+
+ // Check if retry timer needs to be started.
+ if (!(SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER)))
+ {
+ if ((pSpxConnFile->scf_RTimerId =
+ SpxTimerScheduleEvent(
+ spxConnRetryTimer,
+ pSpxConnFile->scf_BaseT1,
+ pSpxConnFile)) != 0)
+ {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ }
+ else
+ {
+ DBGPRINT(SEND, ERR,
+ ("SpxConnPacketize: Failed to start retry timer\n"));
+
+ fSuccess = FALSE;
+ break;
+ }
+ }
+ }
+
+ // Dont overwrite an error state.
+ if (((fNormalState) &&
+ (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_PACKETIZE)) ||
+ ((SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_RETRY3) &&
+ (pSpxConnFile->scf_SendSeqListHead == NULL)))
+ {
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_RETRY3)
+ {
+ DBGPRINT(SEND, ERR,
+ ("COULD NOT PACKETIZE AFTER RENEG %lx\n", pSpxConnFile));
+
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ numDerefs++;
+ }
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ }
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(fSuccess);
+}
+
+
+
+
+VOID
+SpxConnQueueRecv(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PREQUEST pRequest
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PTDI_REQUEST_KERNEL_RECEIVE pParam;
+ NTSTATUS status = STATUS_PENDING;
+
+ if (IsListEmpty(&pSpxConnFile->scf_RecvLinkage))
+ {
+ pParam = (PTDI_REQUEST_KERNEL_RECEIVE)REQUEST_PARAMETERS(pRequest);
+ pSpxConnFile->scf_CurRecvReq = pRequest;
+ pSpxConnFile->scf_CurRecvOffset = 0;
+ pSpxConnFile->scf_CurRecvSize = pParam->ReceiveLength;
+ }
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnQueueRecv: %lx.%lx\n", pRequest, pParam->ReceiveLength));
+
+ // Reference connection for this recv.
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+
+ InsertTailList(
+ &pSpxConnFile->scf_RecvLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // RECV irps have no creation references.
+ REQUEST_INFORMATION(pRequest) = 0;
+ REQUEST_STATUS(pRequest) = STATUS_SUCCESS;
+
+ // State to receive_posted if we are idle.
+ if (SPX_RECV_STATE(pSpxConnFile) == SPX_RECV_IDLE)
+ {
+ SPX_RECV_SETSTATE(pSpxConnFile, SPX_RECV_POSTED);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnCompletePended(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+{
+ CTELockHandle lockHandleInter;
+ LIST_ENTRY ReqList, *p;
+ PREQUEST pRequest;
+
+ InitializeListHead(&ReqList);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnCompletePended: PENDING RECV REQUESTS IN DONE LIST! %lx\n",
+ pSpxConnFile));
+
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ p = pSpxConnFile->scf_RecvDoneLinkage.Flink;
+ while (p != &pSpxConnFile->scf_RecvDoneLinkage)
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+ InsertTailList(
+ &ReqList,
+ REQUEST_LINKAGE(pRequest));
+ }
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+
+ while (!IsListEmpty(&ReqList))
+ {
+ p = RemoveHeadList(&ReqList);
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ DBGPRINT(TDI, DBG,
+ ("SpxConnDiscPkt: PENDING REQ COMP %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+
+#if DBG
+ if (REQUEST_MINOR_FUNCTION(pRequest) == TDI_RECEIVE)
+ {
+ if ((REQUEST_STATUS(pRequest) == STATUS_SUCCESS) &&
+ (REQUEST_INFORMATION(pRequest) == 0))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxReceiveComplete: Completing %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+ }
+ }
+#endif
+
+ SpxCompleteRequest(pRequest);
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+VOID
+SpxConnQWaitAck(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ // If we are not already in ack queue, queue ourselves in starting
+ // ack timer.
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ACKQ))
+ {
+ // First start ack timer.
+ if ((pSpxConnFile->scf_ATimerId =
+ SpxTimerScheduleEvent(
+ spxConnAckTimer,
+ 100,
+ pSpxConnFile)) != 0)
+ {
+ // Reference connection for timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_ACKQ);
+ ++SpxDevice->dev_Stat.PiggybackAckQueued;
+ }
+ }
+
+ return;
+}
+
+
+
+
+
+VOID
+SpxConnSendAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt = NULL;
+
+ DBGPRINT(SEND, DBG,
+ ("spxConnSendAck: ACKING on %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RecvSeqNum));
+
+ // Build an ack packet, queue it in non-sequenced queue. Only if we are
+ // active.
+ if (SPX_CONN_ACTIVE(pSpxConnFile))
+ {
+ SpxPktBuildAck(
+ pSpxConnFile,
+ &pPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
+ FALSE,
+ 0);
+
+ if (pPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+ }
+ else
+ {
+ // Log error
+ DBGPRINT(SEND, ERR,
+ ("SpxConnSendAck: Could not allocate!\n"));
+ }
+ }
+#if DBG
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxConnSendAck: WHEN NOT ACTIVE STATE@!@\n"));
+ }
+#endif
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ // Send it.
+ if (pPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+
+ // Send the packet
+ SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxConnSendNack(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN USHORT NumToSend,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt = NULL;
+
+ DBGPRINT(SEND, DBG,
+ ("spxConnSendNack: NACKING on %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RecvSeqNum));
+
+ // Build an nack packet, queue it in non-sequenced queue. Only if we are
+ // active.
+ if (SPX_CONN_ACTIVE(pSpxConnFile))
+ {
+ SpxPktBuildAck(
+ pSpxConnFile,
+ &pPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
+ TRUE,
+ NumToSend);
+
+ if (pPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+ }
+ else
+ {
+ // Log error
+ DBGPRINT(SEND, ERR,
+ ("SpxConnSendAck: Could not allocate!\n"));
+ }
+ }
+#if DBG
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxConnSendAck: WHEN NOT ACTIVE STATE@!@\n"));
+ }
+#endif
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ // Send it.
+ if (pPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+
+ // Send the packet
+ SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ return;
+}
+
+
+
+
+
+BOOLEAN
+SpxConnProcessAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN CTELockHandle lockHandle
+ )
+/*++
+
+Routine Description:
+
+ !!!MUST BE CALLED WITH THE CONNECTION LOCK HELD!!!
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ PREQUEST pRequest;
+ PSPX_SEND_RESD pSendResd;
+ CTELockHandle interLockHandle;
+ USHORT seqNum = 0, ackNum;
+ int numDerefs = 0;
+ BOOLEAN fLastPkt, lockHeld = TRUE, fAbort = FALSE,
+ fResetRetryTimer, fResendPkt = FALSE, fResetSendQueue = FALSE;
+
+ if (pIpxSpxHdr != NULL)
+ {
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+
+ // Ack numbers should already be set in connection!
+ if (SPX2_CONN(pSpxConnFile))
+ {
+ switch (SPX_SEND_STATE(pSpxConnFile))
+ {
+ case SPX_SEND_RETRYWD:
+
+ // Did we receive an ack for pending data? If so, we goto
+ // idle and process the ack.
+ if (((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL) &&
+ (UNSIGNED_GREATER_WITH_WRAP(
+ pSpxConnFile->scf_RecdAckNum,
+ pSendResd->sr_SeqNum)))
+ {
+ DBGPRINT(SEND, ERR,
+ ("SpxConnProcessAck: Data acked RETRYWD %lx.%lx!\n",
+ pSpxConnFile, pSendResd->sr_SeqNum));
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ numDerefs++;
+ }
+ else
+ {
+ // Ok, we received an ack for our probe retry, goto
+ // renegotiate packet size.
+ // For this both sides must have negotiated size to begin with.
+ // If they did not, we go on to retrying the data packet.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG))
+ {
+ pSpxConnFile->scf_RRetryCount = SPX_DEF_RENEG_RETRYCOUNT;
+ if ((ULONG)pSpxConnFile->scf_MaxPktSize <=
+ (SpxMaxPktSize[0] + MIN_IPXSPX2_HDRSIZE))
+ {
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: %lx MIN RENEG SIZE\n",
+ pSpxConnFile));
+ }
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RENEG);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: %lx CONNECTION ENTERING RENEG\n",
+ pSpxConnFile));
+ }
+ else
+ {
+ DBGPRINT(SEND, ERR,
+ ("spxConnRetryTimer: NO NEG FLAG SET: %lx - %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_Flags));
+
+ // Reset count to be
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY3);
+ }
+ }
+
+ break;
+
+ case SPX_SEND_RENEG:
+
+ // We better have a data packet in the list.
+ CTEAssert(pSpxConnFile->scf_SendSeqListHead);
+
+#if DBG
+ if ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) ==
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2))
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: %lx.%lx.%lx RENEGACK SEQNUM %lx ACKNUM %lx EXPSEQ %lx\n",
+ pSpxConnFile,
+ pIpxSpxHdr->hdr_ConnCtrl,
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT),
+ seqNum,
+ ackNum,
+ (pSpxConnFile->scf_SendSeqListHead->sr_SeqNum + 1)));
+ }
+#endif
+
+ // Verify we received an RR ack. If so, we set state to
+ // SEND_RETRY3. First repacketize if we need to.
+ if ((SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT)) &&
+ ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) ==
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)))
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: RENEG! NEW %lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_MaxPktSize));
+
+ // Dont allow anymore reneg packet acks to be looked at.
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT);
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+
+ // Also set the new send sequence number.
+ pSpxConnFile->scf_SendSeqNum =
+ (USHORT)(pSpxConnFile->scf_SendSeqListTail->sr_SeqNum + 1);
+
+ // Get the max packet size we will really use. Retry timer
+ // could have sent other sizes by now, so we can't depend
+ // on whats set.
+ // Remember max packet size in connection.
+ GETSHORT2SHORT(
+ &pSpxConnFile->scf_MaxPktSize, &pIpxSpxHdr->hdr_NegSize);
+
+ // Basic sanity checking on the max packet size.
+ if (pSpxConnFile->scf_MaxPktSize < SPX_NEG_MIN)
+ pSpxConnFile->scf_MaxPktSize = SPX_NEG_MIN;
+
+ // Get ready to reset the send queue.
+ fResetSendQueue = TRUE;
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: RENEG DONE : RETRY3 %lx.%lx MP %lx!\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_SendSeqNum,
+ pSpxConnFile->scf_MaxPktSize));
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY3);
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: DUPLICATE RENEG ACK %lx!\n",
+ pSpxConnFile));
+ }
+
+ break;
+
+ case SPX_SEND_RETRY:
+ case SPX_SEND_RETRY2:
+ case SPX_SEND_RETRY3:
+
+ if (((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL) &&
+ (UNSIGNED_GREATER_WITH_WRAP(
+ pSpxConnFile->scf_RecdAckNum,
+ pSendResd->sr_SeqNum)))
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxConnProcessAck: Data acked %lx.%lx!\n",
+ pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
+
+#if DBG
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_RETRY3)
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: CONN RESTORED %lx.%lx!\n",
+ pSpxConnFile, pSendResd->sr_SeqNum));
+ }
+#endif
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ numDerefs++;
+ }
+
+ break;
+
+ case SPX_SEND_WD:
+
+ // Ok, we received an ack for our watchdog. Done.
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ numDerefs++;
+
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ break;
+
+ default:
+
+ break;
+ }
+
+#if DBG
+ if (seqNum != 0)
+ {
+ // We have a nack, which contains an implicit ack.
+ // Instead of nack processing, what we do is we resend a
+ // packet left unacked after ack processing. ONLY if we
+ // either enter the loop below (fResetRetryTimer is FALSE)
+ // or if seqNum is non-zero (SPX2 only NACK)
+ }
+#endif
+ }
+ }
+
+ // Once our numbers are updated, we check to see if any of our packets
+ // have been acked.
+ fResetRetryTimer = TRUE;
+ while (((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL) &&
+ ((SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE) ||
+ (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_PACKETIZE) ||
+ fResetSendQueue) &&
+ (UNSIGNED_GREATER_WITH_WRAP(
+ pSpxConnFile->scf_RecdAckNum,
+ pSendResd->sr_SeqNum)))
+ {
+ // Reset retry timer
+ if (fResetRetryTimer)
+ {
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER))
+ {
+ // This will either successfully restart or not affect the timer
+ // if it is currently running.
+ SpxTimerCancelEvent(
+ pSpxConnFile->scf_RTimerId,
+ TRUE);
+
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+ }
+
+ fResetRetryTimer = FALSE;
+ }
+
+ // Update the retry seq num.
+ pSpxConnFile->scf_RetrySeqNum = pSendResd->sr_SeqNum;
+
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ pRequest = pSendResd->sr_Request;
+
+#if DBG
+ if (fResetSendQueue)
+ {
+ DBGPRINT(SEND, ERR,
+ ("SpxConnProcessAck: Data acked RENEG %lx.%lx!\n",
+ pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
+ }
+#endif
+
+ DBGPRINT(SEND, DBG,
+ ("%lx Acked\n", pSendResd->sr_SeqNum));
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnProcessAck: %lx Seq %lx Acked Sr %lx Req %lx %lx.%lx\n",
+ pSpxConnFile,
+ pSendResd->sr_SeqNum,
+ pSendResd,
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // If this packet is the last one comprising this request, remove request
+ // from queue. Calculate retry time.
+ fLastPkt = (BOOLEAN)((pSendResd->sr_State & SPX_SENDPKT_LASTPKT) != 0);
+ if ((pSendResd->sr_State & SPX_SENDPKT_ACKREQ) &&
+ ((pSendResd->sr_State & SPX_SENDPKT_REXMIT) == 0) &&
+ ((pSendResd->sr_SeqNum + 1) == pSpxConnFile->scf_RecdAckNum))
+ {
+ LARGE_INTEGER li, ntTime;
+ int value;
+
+ // This is the packet which is being acked. Adjust round trip
+ // timer.
+ li = pSendResd->sr_SentTime;
+ if (li.LowPart && li.HighPart)
+ {
+ KeQuerySystemTime(&ntTime);
+
+ // Get the difference
+ ntTime.QuadPart = ntTime.QuadPart - li.QuadPart;
+
+ // Convert to milliseconds. If the highpart is 0, we
+ // take a shortcut.
+ if (ntTime.HighPart == 0)
+ {
+ value = ntTime.LowPart/10000;
+ }
+ else
+ {
+ ntTime = SPX_CONVERT100NSTOCENTISEC(ntTime);
+ value = ntTime.LowPart << 4;
+ }
+
+ // Set new time
+ SpxCalculateNewT1(pSpxConnFile, value);
+ }
+ }
+
+ if (fLastPkt)
+ {
+ // Set status
+ REQUEST_STATUS(pRequest) = STATUS_SUCCESS;
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+
+ // Remove creation reference
+ --(REQUEST_INFORMATION(pRequest));
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnProcessAck: LASTSEQ # %lx for Req %lx with %lx.%lx\n",
+ pSendResd->sr_SeqNum,
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ CTEAssert(REQUEST_INFORMATION(pRequest) != 0);
+ }
+
+ // Dequeue the packet
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_SEQ) != 0);
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ // Dereference request for the dequeing of the packet
+ --(REQUEST_INFORMATION(pRequest));
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnProcessAck: Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // Packet owned by IPX. What do we do now? Set acked pkt so request
+ // gets dereferenced in send completion. Note that the packet is already
+ // off the queue and is floating at this point.
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnProcessAck: IPXOWNS Pkt %lx with %lx.%lx\n",
+ pPkt, pRequest, REQUEST_STATUS(pRequest)));
+
+ pSendResd->sr_State |= SPX_SENDPKT_ACKEDPKT;
+ }
+
+ if (SPX2_CONN(pSpxConnFile) &&
+ (REQUEST_MINOR_FUNCTION(pRequest) == TDI_DISCONNECT) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_SENT_ORDREL))
+ {
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_ORDREL_ACKED);
+
+ // If we had received an ordrel in the meantime, we need
+ // to disconnect.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC))
+ {
+ fAbort = TRUE;
+ }
+ }
+
+ // All packets comprising a request have been acked!
+ if (REQUEST_INFORMATION(pRequest) == 0)
+ {
+ CTELockHandle lockHandleInter;
+
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ PTDI_REQUEST_KERNEL_SEND pParam;
+
+ pParam = (PTDI_REQUEST_KERNEL_SEND)
+ REQUEST_PARAMETERS(pRequest);
+
+ REQUEST_INFORMATION(pRequest) = pParam->SendLength;
+
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: QForComp Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_ReqDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // If connection is not already in recv queue, put it in
+ // there.
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Set the request in the connection, and deref for it.
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ numDerefs++;
+
+ }
+ }
+#if DBG
+ else if (fLastPkt)
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessAck: ReqFloating %lx.%lx\n",
+ pSpxConnFile, pRequest));
+ }
+#endif
+ }
+
+ // See if we reset the send queue and repacketize.
+ if (fResetSendQueue)
+ {
+ // Reset send queue and repacketize only if pkts left unacked.
+ if (pSpxConnFile->scf_SendSeqListHead)
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: Resetting send queue %lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_MaxPktSize));
+
+ spxConnResetSendQueue(pSpxConnFile);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: Repacketizing %lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_MaxPktSize));
+
+ SpxConnPacketize(pSpxConnFile, FALSE, lockHandle);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ }
+ else
+ {
+ // We just go back to idle state now.
+ DBGPRINT(SEND, ERR,
+ ("SpxConnProcessAck: All packets acked reneg ack! %lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_MaxPktSize));
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ numDerefs++;
+
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+ }
+ }
+
+ // See if we resend a packet.
+ if ((seqNum != 0) &&
+ !fAbort &&
+ ((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL) &&
+ (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE) &&
+ ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0))
+ {
+ PIPXSPX_HDR pSendHdr;
+
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ pSendHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ // Set ack bit in packet. pSendResd initialized at beginning.
+ pSendHdr->hdr_ConnCtrl |= SPX_CC_ACK;
+
+ // We are going to resend this packet
+ pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
+ SPX_SENDPKT_ACKREQ |
+ SPX_SENDPKT_REXMIT);
+
+ fResendPkt = TRUE;
+ }
+
+ // Push into packetize only if we received an ack. And if there arent any
+ // packets already waiting. Probably retransmit happening.
+ if (!fAbort &&
+ SPX_CONN_ACTIVE(pSpxConnFile) &&
+ (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE) &&
+ (pSpxConnFile->scf_ReqPkt != NULL) &&
+ (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_PKTQ)) &&
+ ((pSpxConnFile->scf_SendSeqListHead) == NULL) &&
+ (!SPX2_CONN(pSpxConnFile) ||
+ ((SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_ORDREL_ACKED) &&
+ (SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_SENT_ORDREL))))
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessAck: Recd ack pktizng\n", pSpxConnFile));
+
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_PKTQ);
+ SpxConnFileLockReference(pSpxConnFile, CFREF_PKTIZE);
+
+ CTEGetLock(&SpxGlobalQInterlock, &interLockHandle);
+ SPX_QUEUE_TAIL_PKTLIST(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, interLockHandle);
+ }
+ else if (fAbort)
+ {
+ // Set IDISC flag so Abortive doesnt reindicate.
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_SUCCESS,
+ SPX_CALL_RECVLEVEL,
+ lockHandle,
+ FALSE); // [SA] bug #15249
+
+ lockHeld = FALSE;
+ }
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ if (fResendPkt)
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: Resend pkt on %lx.%lx\n",
+ pSpxConnFile, pSendResd->sr_SeqNum));
+
+ ++SpxDevice->dev_Stat.DataFramesResent;
+ ExInterlockedAddLargeStatistic(
+ &SpxDevice->dev_Stat.DataFrameBytesResent,
+ pSendResd->sr_Len - (SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE));
+ SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(TRUE);
+}
+
+
+
+
+VOID
+SpxConnProcessRenegReq(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN CTELockHandle lockHandle
+ )
+/*++
+
+Routine Description:
+
+ !!!MUST BE CALLED WITH THE CONNECTION LOCK HELD!!!
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ USHORT seqNum, ackNum, allocNum, maxPktSize;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt = NULL;
+
+ // The remote sent us a renegotiate request. We need to send an ack back
+ // ONLY if we have not acked a data packet with that same sequence number.
+ // This is guaranteed by the fact that we will not accept the reneg request
+ // if we have already acked a data packet with the same seq num, as our
+ // receive seq number would be incremented already.
+ //
+ // Note that if we have pending send packets we may end up doing a reneg
+ // also.
+
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+ GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
+ GETSHORT2SHORT(&maxPktSize, &pIpxSpxHdr->hdr_PktLen);
+
+ // If the received seq num is less than the expected receive sequence number
+ // we ignore this request.
+ if (!UNSIGNED_GREATER_WITH_WRAP(
+ seqNum,
+ pSpxConnFile->scf_RecvSeqNum) &&
+ (seqNum != pSpxConnFile->scf_RecvSeqNum))
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessRenegReq: %lx ERROR RENSEQ %lx RECVSEQ %lx %lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ return;
+ }
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessRenegReq: %lx RENSEQ %lx RECVSEQ %lx MAXPKT %lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum, maxPktSize));
+
+ // Set ack numbers for connection.
+ SPX_SET_ACKNUM(
+ pSpxConnFile, ackNum, allocNum);
+
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *pRemoteAddr;
+
+ // Set RenegAckAckNum before calling buildrrack. If a previous reneg
+ // request was received with a greater maxpktsize, send an ack with
+ // that maxpktsize.
+ if (!SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_RENEGRECD))
+ {
+ pSpxConnFile->scf_RenegAckAckNum = pSpxConnFile->scf_RecvSeqNum;
+ pSpxConnFile->scf_RenegMaxPktSize= maxPktSize;
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_RENEGRECD);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessRenegReq: %lx SENT ALLOC NUM CURRENT %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_SentAllocNum));
+
+ // Adjust sentallocnum now that recvseqnum might have moved up.
+ pSpxConnFile->scf_SentAllocNum +=
+ (seqNum - pSpxConnFile->scf_RenegAckAckNum);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessRenegReq: %lx SENT ALLOC NUM ADJUSTED %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_SentAllocNum));
+ }
+
+ // The recvseqnum for the reneg is always >= the renegackacknum.
+ pSpxConnFile->scf_RecvSeqNum = seqNum;
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessRenegReq: %lx RESET RECVSEQ %lx SavedACKACK %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_RecvSeqNum,
+ pSpxConnFile->scf_RenegAckAckNum));
+
+ // Build and send an ack.
+ SpxPktBuildRrAck(
+ pSpxConnFile,
+ &pPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
+ pSpxConnFile->scf_RenegMaxPktSize);
+
+ if (pPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+ }
+#if DBG
+ else
+ {
+ // Log error
+ DBGPRINT(SEND, ERR,
+ ("SpxConnSendRenegReqAck: Could not allocate!\n"));
+ }
+#endif
+
+
+ // Check if we are an ack/nack packet in which case call process
+ // ack. Note that the spx2 orderly release ack is a normal spx2 ack.
+ SpxConnProcessAck(pSpxConnFile, NULL, lockHandle);
+
+ if (pPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+
+ // Send the packet
+ SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxConnProcessOrdRel(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle lockHandle
+ )
+/*++
+
+Routine Description:
+
+ !!!MUST BE CALLED WITH THE CONNECTION LOCK HELD!!!
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PVOID pDiscHandlerCtx;
+ PTDI_IND_DISCONNECT pDiscHandler = NULL;
+ int numDerefs = 0;
+ PNDIS_PACKET pPkt = NULL;
+ BOOLEAN lockHeld = TRUE, fAbort = FALSE;
+
+ if (SPX_CONN_ACTIVE(pSpxConnFile))
+ {
+ if (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ORDREL_ACKED)
+ {
+ fAbort = TRUE;
+ }
+
+ // Send an ack if one was asked for. And we are done with this pkt
+ // Update seq numbers and stuff.
+ SPX_SET_RECVNUM(pSpxConnFile, FALSE);
+
+ // Build and send an ack for this. Ordinary spx2 ack.
+ SpxPktBuildAck(
+ pSpxConnFile,
+ &pPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY | SPX_SENDPKT_ABORT,
+ FALSE,
+ 0);
+
+ if (pPkt != NULL)
+ {
+ // We don't queue this pkt in as we have the ABORT flag set in
+ // the packet, which implies the pkt is already dequeued.
+ // SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+
+ // Reference conn for the pkt.
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+
+ // Get disconnect handler if we have one. And have not indicated
+ // abortive disconnect on this connection to afd.
+
+ //
+ // Bug #14354 - odisc and idisc cross each other, leading to double disc to AFD
+ //
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC) &&
+ !SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC))
+ {
+ // Yeah, we set the flag regardless of whether a handler is
+ // present.
+ pDiscHandler =pSpxConnFile->scf_AddrFile->saf_DiscHandler;
+ pDiscHandlerCtx=pSpxConnFile->scf_AddrFile->saf_DiscHandlerCtx;
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC);
+ }
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ // Indicate disconnect to afd.
+ if (pDiscHandler != NULL)
+ {
+ (*pDiscHandler)(
+ pDiscHandlerCtx,
+ pSpxConnFile->scf_ConnCtx,
+ 0, // Disc data
+ NULL,
+ 0, // Disc info
+ NULL,
+ TDI_DISCONNECT_RELEASE);
+ }
+
+ // We abort any receives here if !fAbort else we abort conn.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+
+ if (fAbort)
+ {
+ // Set IDISC flag so Abortive doesnt reindicate.
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_SUCCESS,
+ SPX_CALL_RECVLEVEL,
+ lockHandle,
+ FALSE); // [SA] bug #15249
+
+ lockHeld = FALSE;
+ }
+ else
+ {
+ // Go through and kill all pending requests.
+ spxConnAbortRecvs(
+ pSpxConnFile,
+ STATUS_REMOTE_DISCONNECT,
+ SPX_CALL_RECVLEVEL,
+ lockHandle);
+
+ lockHeld = FALSE;
+ }
+ }
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ if (pPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+
+ // Send the packet
+ SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxConnProcessIDisc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle lockHandle
+ )
+/*++
+
+Routine Description:
+
+ !!!MUST BE CALLED WITH THE CONNECTION LOCK HELD!!!
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt = NULL;
+
+ SPX_SET_RECVNUM(pSpxConnFile, FALSE);
+
+ // Build and send an ack for the idisc. Need to modify data type
+ // and reset sys bit on ack.
+ // BUG #12344 - Fixing this led to the problem where we queue in
+ // the pkt below, but AbortSends could already have been called
+ // => this packet stays on queue without a ref, conn gets freed
+ // underneath, and in the sendcomplete we crash when this send
+ // completes.
+ //
+ // Fix is to setup this pkt as a aborted pkt to start with.
+
+ SpxPktBuildAck(
+ pSpxConnFile,
+ &pPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY | SPX_SENDPKT_ABORT,
+ FALSE,
+ 0);
+
+ if (pPkt != NULL)
+ {
+ PIPXSPX_HDR pSendHdr;
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ pSendHdr->hdr_ConnCtrl &= ~SPX_CC_SYS;
+ pSendHdr->hdr_DataType = SPX2_DT_IDISC_ACK;
+
+ // We don't queue this pkt in as we have the ABORT flag set in
+ // the packet, which implies the pkt is already dequeued.
+ // SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+
+ // Reference conn for the pkt.
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+
+ // We better not have any received pkts, we ignore disconnect
+ // pkts when that happens.
+ CTEAssert(pSpxConnFile->scf_RecvListTail == NULL);
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+
+#if DBG
+ if (pSpxConnFile->scf_SendSeqListHead != NULL)
+ {
+ DBGPRINT(CONNECT, DBG1,
+ ("SpxConnDiscPacket: DATA/DISC %lx.%lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_SendListHead,
+ pSpxConnFile->scf_SendSeqListHead));
+ }
+#endif
+
+ // Call abortive disconnect on connection.
+
+ //
+ // [SA] bug #15249
+ // This is an informed disconnect, hence pass DISCONNECT_RELEASE to AFD (TRUE in last param)
+ //
+ //
+ // We pass true only in the case of an SPX connection. SPX2 connections follow the
+ // exact semantics of Informed Disconnect.
+ //
+ if (!SPX2_CONN(pSpxConnFile)) {
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_REMOTE_DISCONNECT,
+ SPX_CALL_RECVLEVEL,
+ lockHandle,
+ TRUE);
+ } else {
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_REMOTE_DISCONNECT,
+ SPX_CALL_RECVLEVEL,
+ lockHandle,
+ FALSE);
+ }
+
+ if (pPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+
+ // Send the packet
+ SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnResetSendQueue(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PREQUEST pRequest;
+ PNDIS_PACKET pPkt;
+
+ pSendResd = pSpxConnFile->scf_SendSeqListHead;
+ CTEAssert(pSendResd != NULL);
+
+ pRequest = pSendResd->sr_Request;
+
+ // Reset the current send request values
+ pSpxConnFile->scf_ReqPkt = pSendResd->sr_Request;
+ pSpxConnFile->scf_ReqPktOffset = pSendResd->sr_Offset;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DATA;
+
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ PTDI_REQUEST_KERNEL_SEND pParam;
+
+ pParam = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(pRequest);
+
+ DBGPRINT(SEND, DBG3,
+ ("spxConnResetSendQueue: %lx.%lx.%lx Reset SEND Req to %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_Flags, pSpxConnFile->scf_Flags2,
+ pRequest, pParam->SendLength));
+
+ // Set parameters in connection for another go. Size parameter is
+ // original size - offset at this point.
+ pSpxConnFile->scf_ReqPktFlags = pParam->SendFlags;
+ pSpxConnFile->scf_ReqPktSize = pParam->SendLength -
+ pSpxConnFile->scf_ReqPktOffset;
+ }
+ else
+ {
+ PTDI_REQUEST_KERNEL_DISCONNECT pParam;
+
+ DBGPRINT(SEND, ERR,
+ ("spxConnResetSendQueue: %lx.%lx.%lx Reset DISC Req to %lx\n",
+ pSpxConnFile, pSpxConnFile->scf_Flags, pSpxConnFile->scf_Flags2,
+ pRequest));
+
+ DBGPRINT(SEND, ERR,
+ ("spxConnResetSendQueue: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ pParam =
+ (PTDI_REQUEST_KERNEL_DISCONNECT)REQUEST_PARAMETERS(pRequest);
+
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pSpxConnFile->scf_ReqPktSize = 0;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DISC;
+ if (pParam->RequestFlags == TDI_DISCONNECT_RELEASE)
+ {
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_ORDREL;
+ }
+ }
+
+ DBGPRINT(SEND, DBG3,
+ ("spxConnResetSendQueue: Seq Num for %lx is now %lx\n",
+ pSpxConnFile, pSpxConnFile->scf_SendSeqNum));
+
+ // When we are trying to abort a pkt and it is in use by ipx, we simply let
+ // it float.
+ do
+ {
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_REQ) != 0);
+ pRequest = pSendResd->sr_Request;
+
+ CTEAssert(REQUEST_INFORMATION(pRequest) != 0);
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ if (--(REQUEST_INFORMATION(pRequest)) == 0)
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ KeBugCheck(0);
+ }
+
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // We let send completion know that this packet is to be aborted.
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+
+ } while ((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL);
+
+ return;
+}
+
+
+
+
+VOID
+spxConnAbortSendPkt(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_SEND_RESD pSendResd,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+ Called to abort either a sequenced or a non-sequenced packet ONLY from
+ send completion.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LIST_ENTRY ReqList, *p;
+ PREQUEST pRequest;
+ PNDIS_PACKET pPkt;
+ int numDerefs = 0;
+
+ InitializeListHead(&ReqList);
+
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ if ((pSendResd->sr_State & SPX_SENDPKT_REQ) != 0)
+ {
+ pRequest = pSendResd->sr_Request;
+
+ CTEAssert(REQUEST_INFORMATION(pRequest) != 0);
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0);
+ if (--(REQUEST_INFORMATION(pRequest)) == 0)
+ {
+ // Remove request from list its on
+ // BUG #11626 - request is already removed from list.
+ // RemoveEntryList(REQUEST_LINKAGE(pRequest));
+
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendAbort: QForComp Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (CallLevel == SPX_CALL_RECVLEVEL)
+ {
+ CTELockHandle lockHandleInter;
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_ReqDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // If connection is not already in recv queue, put it in
+ // there.
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ else
+ {
+ InsertTailList(
+ &ReqList,
+ REQUEST_LINKAGE(pRequest));
+ }
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Set the request in the connection, and deref for it.
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ numDerefs++;
+ }
+ }
+ }
+
+ // Release
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ SpxConnFileDereference(pSpxConnFile, CFREF_ABORTPKT);
+
+ if (!IsListEmpty(&ReqList))
+ {
+ p = RemoveHeadList(&ReqList);
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ SpxCompleteRequest(pRequest);
+ numDerefs++;
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnAbortSends(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LIST_ENTRY ReqList, *p;
+ PSPX_SEND_RESD pSendResd;
+ PREQUEST pRequest;
+ PNDIS_PACKET pPkt;
+ int numDerefs = 0;
+
+ InitializeListHead(&ReqList);
+
+ // We better be in disconnect state, abortive/informed/orderly initiate.
+ CTEAssert(SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN);
+
+ // Reset the current send request values
+ pSpxConnFile->scf_ReqPkt = NULL;
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pSpxConnFile->scf_ReqPktSize = 0;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DATA;
+
+ // First go through the non-seq pkt queue.Just set abort flag if owned by ipx
+ while ((pSendResd = pSpxConnFile->scf_SendListHead) != NULL)
+ {
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_REQ) == 0);
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // Set abort flag and reference conn for the pkt if its not already.
+ // We only do this check for the non-sequenced packets.
+ // BUG #12344 (see SpxRecvDiscPacket())
+ if ((pSendResd->sr_State & SPX_SENDPKT_ABORT) == 0)
+ {
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+ }
+ }
+
+ // When we are trying to abort a pkt and it is in use by ipx, we simply let
+ // it float.
+ while ((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL)
+ {
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_REQ) != 0);
+ pRequest = pSendResd->sr_Request;
+
+ CTEAssert(REQUEST_INFORMATION(pRequest) != 0);
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ if (--(REQUEST_INFORMATION(pRequest)) == 0)
+ {
+ // Remove request from list its on
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+
+ // Set status
+ REQUEST_STATUS(pRequest) = Status;
+ REQUEST_INFORMATION(pRequest) = 0;
+
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendAbort: QForComp Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (CallLevel == SPX_CALL_RECVLEVEL)
+ {
+ CTELockHandle lockHandleInter;
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_ReqDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // If connection is not already in recv queue, put it in
+ // there.
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ else
+ {
+ InsertTailList(
+ &ReqList,
+ REQUEST_LINKAGE(pRequest));
+ }
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Set the request in the connection, and deref for it.
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ numDerefs++;
+ }
+ }
+
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // We let send completion know that this packet is to be aborted.
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+ }
+
+ // If retry timer state is on, then we need to reset and deref.
+ if ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_IDLE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_PACKETIZE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_WD))
+ {
+ DBGPRINT(SEND, DBG1,
+ ("spxConnAbortSends: When SEND ERROR STATE %lx.%lx\n",
+ pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ numDerefs++;
+ }
+
+ // Remove creation references on all sends.
+ if (!IsListEmpty(&pSpxConnFile->scf_ReqLinkage))
+ {
+ p = pSpxConnFile->scf_ReqLinkage.Flink;
+ while (p != &pSpxConnFile->scf_ReqLinkage)
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ // Remove request from list its on. Its complete or abort list for it.
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+
+ // Set status
+ REQUEST_STATUS(pRequest) = Status;
+
+ DBGPRINT(SEND, DBG1,
+ ("SpxSendAbort: %lx Aborting Send Request %lx with %lx.%lx\n",
+ pSpxConnFile, pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (--(REQUEST_INFORMATION(pRequest)) == 0)
+ {
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendAbort: QForComp Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (CallLevel == SPX_CALL_RECVLEVEL)
+ {
+ CTELockHandle lockHandleInter;
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_ReqDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // If connection is not already in recv queue, put it in
+ // there.
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ else
+ {
+ InsertTailList(
+ &ReqList,
+ REQUEST_LINKAGE(pRequest));
+ }
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG1,
+ ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Set the request in the connection, and deref for it.
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ numDerefs++;
+ }
+ }
+#if DBG
+ else
+ {
+ // Let it float,
+ DBGPRINT(SEND, DBG1,
+ ("SpxSendAbort: %lx Floating Send %lx with %lx.%lx\n",
+ pSpxConnFile, pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+ }
+#endif
+ }
+ }
+
+ // Release
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ while (!IsListEmpty(&ReqList))
+ {
+ p = RemoveHeadList(&ReqList);
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ SpxCompleteRequest(pRequest);
+ numDerefs++;
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnAbortRecvs(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LIST_ENTRY ReqList, *p;
+ PREQUEST pRequest;
+ PSPX_RECV_RESD pRecvResd;
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+ PBYTE pData;
+ ULONG dataLen;
+ int numDerefs = 0;
+
+ InitializeListHead(&ReqList);
+
+ // We better be in disconnect state, abortive/informed/orderly initiate.
+ // Reset the current receive request values
+ pSpxConnFile->scf_CurRecvReq = NULL;
+ pSpxConnFile->scf_CurRecvOffset = 0;
+ pSpxConnFile->scf_CurRecvSize = 0;
+
+ // If we have any buffered data, abort it.
+ // Buffered data that is 0 bytes long (only eom) may not have a ndis
+ // buffer associated with it.
+ while ((pRecvResd = pSpxConnFile->scf_RecvListHead) != NULL)
+ {
+ if ((pSpxConnFile->scf_RecvListHead = pRecvResd->rr_Next) == NULL)
+ {
+ pSpxConnFile->scf_RecvListTail = NULL;
+ }
+
+ pNdisPkt = (PNDIS_PACKET)
+ CONTAINING_RECORD(pRecvResd, NDIS_PACKET, ProtocolReserved);
+
+ DBGPRINT(RECEIVE, DBG1,
+ ("spxConnAbortRecvs: %lx in bufferlist on %lx\n",
+ pSpxConnFile, pNdisPkt));
+
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ if (pNdisBuffer != NULL)
+ {
+ NdisQueryBuffer(pNdisBuffer, &pData, &dataLen);
+ CTEAssert(pData != NULL);
+ CTEAssert(dataLen >= 0);
+
+ SpxFreeMemory(pData);
+ NdisFreeBuffer(pNdisBuffer);
+ }
+
+ // Packet consumed. Free it up.
+ numDerefs++;
+
+ // Free the ndis packet
+ SpxPktRecvRelease(pNdisPkt);
+ }
+
+ // If packets are on this queue, they are waiting for transfer data to
+ // complete. Can't do much about that, just go and remove creation refs
+ // on the receives.
+ if (!IsListEmpty(&pSpxConnFile->scf_RecvLinkage))
+ {
+ p = pSpxConnFile->scf_RecvLinkage.Flink;
+ while (p != &pSpxConnFile->scf_RecvLinkage)
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ // Remove request from list its on
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+
+ // Set status
+ REQUEST_STATUS(pRequest) = Status;
+
+ DBGPRINT(RECEIVE, DBG1,
+ ("SpxRecvAbort: Aborting Recv Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (REQUEST_INFORMATION(pRequest) == 0)
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxRecvAbort: QForComp Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (CallLevel == SPX_CALL_RECVLEVEL)
+ {
+ CTELockHandle lockHandleInter;
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_RecvDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // If connection is not already in recv queue, put it in
+ // there.
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ else
+ {
+ InsertTailList(
+ &ReqList,
+ REQUEST_LINKAGE(pRequest));
+ }
+ }
+#if DBG
+ else
+ {
+ // Let it float,
+ DBGPRINT(SEND, DBG1,
+ ("SpxSendAbort: %lx Floating Send %lx with %lx.%lx\n",
+ pSpxConnFile, pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+ }
+#endif
+ }
+ }
+
+ // Release
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ while (!IsListEmpty(&ReqList))
+ {
+ p = RemoveHeadList(&ReqList);
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ numDerefs++;
+
+ SpxCompleteRequest(pRequest);
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+#if 0
+
+VOID
+spxConnResendPkts(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ USHORT startSeqNum;
+ BOOLEAN fLockHeld = TRUE, fDone = FALSE;
+
+ pSendResd = pSpxConnFile->scf_SendSeqListHead;
+ if (pSendResd)
+ {
+ startSeqNum = pSendResd->sr_SeqNum;
+ DBGPRINT(SEND, DBG,
+ ("spxConnResendPkts: StartSeqNum %lx for resend on %lx\n",
+ startSeqNum, pSpxConnFile));
+
+ while (spxConnGetPktBySeqNum(pSpxConnFile, startSeqNum++, &pPkt))
+ {
+ CTEAssert(pPkt != NULL);
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ if (!(pSendResd->sr_State & SPX_SENDPKT_IPXOWNS))
+ {
+ DBGPRINT(SEND, DBG,
+ ("spxConnResendPkts: Pkt %lx.%lx resent on %lx\n",
+ pPkt, (startSeqNum - 1), pSpxConnFile));
+
+ // We are going to send this packet
+ pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
+ SPX_SENDPKT_REXMIT);
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("spxConnResendPkts: Pkt %lx.%lx owned by ipx on %lx\n",
+ pPkt, (startSeqNum - 1), pSpxConnFile));
+ break;
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ fLockHeld = FALSE;
+
+ // If pkt has the ack bit set, we break.
+ fDone = ((pSendResd->sr_State & SPX_SENDPKT_ACKREQ) != 0);
+
+ // Send the packet
+ SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
+ if (fDone)
+ {
+ break;
+ }
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ fLockHeld = TRUE;
+ }
+ }
+
+ if (fLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ }
+
+ return;
+}
+#endif
diff --git a/private/ntos/tdi/isn/spx/spxcutil.c b/private/ntos/tdi/isn/spx/spxcutil.c
new file mode 100644
index 000000000..fa2105e42
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxcutil.c
@@ -0,0 +1,1736 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxcutil.c
+
+Abstract:
+
+ This module contains code which implements the CONNECTION object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport connection objects.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 5-July-1995
+ Bug fixes - tagged [SA]
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+// Define module number for event logging entries
+#define FILENUM SPXCUTIL
+
+//
+// Minor utility routines
+//
+
+
+BOOLEAN
+spxConnCheckNegSize(
+ IN PUSHORT pNegSize
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ int i;
+
+ // We go thru table and see if this is the minimum size or if it
+ // can go down further. Return true if it is not the minimum size.
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnCheckNegSize: Current %lx Check Val %lx\n",
+ (ULONG)(*pNegSize - MIN_IPXSPX2_HDRSIZE),
+ SpxMaxPktSize[0]));
+
+ if ((ULONG)(*pNegSize - MIN_IPXSPX2_HDRSIZE) <= SpxMaxPktSize[0])
+ return(FALSE);
+
+ for (i = SpxMaxPktSizeIndex-1; i > 0; i--)
+ {
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnCheckNegSize: Current %lx Check Val %lx\n",
+ (ULONG)(*pNegSize - MIN_IPXSPX2_HDRSIZE),
+ SpxMaxPktSize[i]));
+
+ if (SpxMaxPktSize[i] < (ULONG)(*pNegSize - MIN_IPXSPX2_HDRSIZE))
+ break;
+ }
+
+ *pNegSize = (USHORT)(SpxMaxPktSize[i] + MIN_IPXSPX2_HDRSIZE);
+
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnCheckNegSize: Trying Size %lx Min size possible %lx\n",
+ *pNegSize, SpxMaxPktSize[0] + MIN_IPXSPX2_HDRSIZE));
+
+ return(TRUE);
+}
+
+
+
+
+VOID
+spxConnSetNegSize(
+ IN OUT PNDIS_PACKET pPkt,
+ IN ULONG Size
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_BUFFER pNdisBuffer;
+ UINT bufCount;
+ PSPX_SEND_RESD pSendResd;
+ PIPXSPX_HDR pIpxSpxHdr;
+
+ CTEAssert(Size > 0);
+ NdisQueryPacket(pPkt, NULL, &bufCount, &pNdisBuffer, NULL);
+ CTEAssert (bufCount == 3);
+
+ NdisGetNextBuffer(pNdisBuffer, &pNdisBuffer);
+ NdisGetNextBuffer(pNdisBuffer, &pNdisBuffer);
+ NdisAdjustBufferLength(pNdisBuffer, Size);
+
+ // Change it in send reserved
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Len = (Size + MIN_IPXSPX2_HDRSIZE);
+
+ // Change in ipx header
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ PUTSHORT2SHORT((PUSHORT)&pIpxSpxHdr->hdr_PktLen, (Size + MIN_IPXSPX2_HDRSIZE));
+
+ // Change in the neg packet field of the header.
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ (Size + MIN_IPXSPX2_HDRSIZE));
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnSetNegSize: Setting size to %lx Hdr %lx\n",
+ Size, (Size + MIN_IPXSPX2_HDRSIZE)));
+
+ return;
+}
+
+
+
+
+BOOLEAN
+SpxConnDequeueSendPktLock(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PNDIS_PACKET pPkt
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSr, pListHead, pListTail;
+ PSPX_SEND_RESD pSendResd;
+ BOOLEAN removed = TRUE;
+
+ // If we are sequenced or not decides which list we choose.
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ if ((pSendResd->sr_State & SPX_SENDPKT_SEQ) != 0)
+ {
+ pListHead = pSpxConnFile->scf_SendSeqListHead;
+ pListTail = pSpxConnFile->scf_SendSeqListTail;
+ }
+ else
+ {
+ pListHead = pSpxConnFile->scf_SendListHead;
+ pListTail = pSpxConnFile->scf_SendListTail;
+ }
+
+ // Most often, we will be at the head of the list.
+ if (pListHead == pSendResd)
+ {
+ if ((pListHead = pSendResd->sr_Next) == NULL)
+ {
+ DBGPRINT(SEND, INFO,
+ ("SpxConnDequeuePktLock: %lx first in list\n", pSendResd));
+
+ pListTail = NULL;
+ }
+ }
+ else
+ {
+ DBGPRINT(SEND, INFO,
+ ("SpxConnDequeuePktLock: %lx !first in list\n", pSendResd));
+
+ pSr = pListHead;
+ while (pSr != NULL)
+ {
+ if (pSr->sr_Next == pSendResd)
+ {
+ if ((pSr->sr_Next = pSendResd->sr_Next) == NULL)
+ {
+ pListTail = pSr;
+ }
+
+ break;
+ }
+
+ pSr = pSr->sr_Next;
+ }
+
+ if (pSr == NULL)
+ removed = FALSE;
+ }
+
+ if (removed)
+ {
+ if ((pSendResd->sr_State & SPX_SENDPKT_SEQ) != 0)
+ {
+ pSpxConnFile->scf_SendSeqListHead = pListHead;
+ pSpxConnFile->scf_SendSeqListTail = pListTail;
+ }
+ else
+ {
+ pSpxConnFile->scf_SendListHead = pListHead;
+ pSpxConnFile->scf_SendListTail = pListTail;
+ }
+ }
+
+ return(removed);
+}
+
+
+
+
+BOOLEAN
+SpxConnDequeueRecvPktLock(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PNDIS_PACKET pPkt
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_RECV_RESD pSr, pListHead, pListTail;
+ PSPX_RECV_RESD pRecvResd;
+ BOOLEAN removed = TRUE;
+
+ pRecvResd = (PSPX_RECV_RESD)(pPkt->ProtocolReserved);
+ pListHead = pSpxConnFile->scf_RecvListHead;
+ pListTail = pSpxConnFile->scf_RecvListTail;
+
+ // Most often, we will be at the head of the list.
+ if (pListHead == pRecvResd)
+ {
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnDequeuePktLock: %lx first in list\n", pRecvResd));
+
+ if ((pListHead = pRecvResd->rr_Next) == NULL)
+ {
+ pListTail = NULL;
+ }
+ }
+ else
+ {
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnDequeuePktLock: %lx !first in list\n", pRecvResd));
+
+ pSr = pListHead;
+ while (pSr != NULL)
+ {
+ if (pSr->rr_Next == pRecvResd)
+ {
+ if ((pSr->rr_Next = pRecvResd->rr_Next) == NULL)
+ {
+ pListTail = pSr;
+ }
+
+ break;
+ }
+
+ pSr = pSr->rr_Next;
+ }
+
+ if (pSr == NULL)
+ removed = FALSE;
+ }
+
+ if (removed)
+ {
+ pSpxConnFile->scf_RecvListHead = pListHead;
+ pSpxConnFile->scf_RecvListTail = pListTail;
+ }
+
+ return(removed);
+}
+
+
+
+
+BOOLEAN
+spxConnGetPktByType(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN ULONG PktType,
+ IN BOOLEAN fSeqList,
+ IN PNDIS_PACKET * ppPkt
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSr, *ppSr;
+
+ // Most often, we will be at the head of the list.
+ ppSr = (fSeqList ?
+ &pSpxConnFile->scf_SendSeqListHead :
+ &pSpxConnFile->scf_SendListHead);
+
+ for (; (pSr = *ppSr) != NULL; )
+ {
+ if (pSr->sr_Type == PktType)
+ {
+ *ppPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSr, NDIS_PACKET, ProtocolReserved);
+
+ DBGPRINT(SEND, INFO,
+ ("SpxConnFindByType: %lx.%lx.%d\n", pSr,*ppPkt, fSeqList));
+
+ break;
+ }
+
+ ppSr = &pSr->sr_Next;
+ }
+
+ return(pSr != NULL);
+}
+
+
+
+
+BOOLEAN
+spxConnGetPktBySeqNum(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN USHORT SeqNum,
+ IN PNDIS_PACKET * ppPkt
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSr, *ppSr;
+
+ // Most often, we will be at the head of the list.
+ ppSr = &pSpxConnFile->scf_SendSeqListHead;
+ for (; (pSr = *ppSr) != NULL; )
+ {
+ if (pSr->sr_SeqNum == SeqNum)
+ {
+ *ppPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSr, NDIS_PACKET, ProtocolReserved);
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnFindBySeq: %lx.%lx.%d\n", pSr,*ppPkt, SeqNum));
+
+ break;
+ }
+
+ ppSr = &pSr->sr_Next;
+ }
+
+ return(pSr != NULL);
+}
+
+
+
+
+USHORT
+spxConnGetId(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This must be called with the device lock held.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pSpxConnFile;
+ BOOLEAN wrapped = FALSE;
+ USHORT startConnId, retConnId;
+
+ startConnId = SpxDevice->dev_NextConnId;
+
+ // Search the global active list.
+ do
+ {
+ if ((SpxDevice->dev_NextConnId >= startConnId) && wrapped)
+ {
+ retConnId = 0;
+ break;
+ }
+
+ if (SpxDevice->dev_NextConnId == 0xFFFF)
+ {
+ wrapped = TRUE;
+ SpxDevice->dev_NextConnId = 1;
+ continue;
+ }
+
+ // BUGBUG: Later this be a tree.
+ for (pSpxConnFile = SpxDevice->dev_GlobalActiveConnList[
+ SpxDevice->dev_NextConnId & NUM_SPXCONN_HASH_MASK];
+ pSpxConnFile != NULL;
+ pSpxConnFile = pSpxConnFile->scf_GlobalActiveNext)
+ {
+ if (pSpxConnFile->scf_LocalConnId == SpxDevice->dev_NextConnId)
+ {
+ break;
+ }
+ }
+
+ // Increment for next time.
+ retConnId = SpxDevice->dev_NextConnId++;
+
+ // Ensure we are still legal. We could return if connfile is null.
+ if (SpxDevice->dev_NextConnId == 0xFFFF)
+ {
+ wrapped = TRUE;
+ SpxDevice->dev_NextConnId = 1;
+ }
+
+ if (pSpxConnFile != NULL)
+ {
+ continue;
+ }
+
+ break;
+
+ } while (TRUE);
+
+ return(retConnId);
+}
+
+
+
+
+NTSTATUS
+spxConnRemoveFromList(
+ IN PSPX_CONN_FILE * ppConnListHead,
+ IN PSPX_CONN_FILE pConnRemove
+ )
+
+/*++
+
+Routine Description:
+
+ This routine must be called with the address lock (and the lock of the remove
+ connection will usually also be, but is not needed) held.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pRemConn, *ppRemConn;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ // Dequeue the connection file from the address list. It must be
+ // in the inactive list.
+ for (ppRemConn = ppConnListHead;
+ (pRemConn = *ppRemConn) != NULL;)
+ {
+ if (pRemConn == pConnRemove)
+ {
+ *ppRemConn = pRemConn->scf_Next;
+ break;
+ }
+
+ ppRemConn = &pRemConn->scf_Next;
+ }
+
+ if (pRemConn == NULL)
+ {
+ DBGBRK(FATAL);
+ CTEAssert(0);
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+spxConnRemoveFromAssocList(
+ IN PSPX_CONN_FILE * ppConnListHead,
+ IN PSPX_CONN_FILE pConnRemove
+ )
+
+/*++
+
+Routine Description:
+
+ This routine must be called with the address lock (and the lock of the remove
+ connection will usually also be, but is not needed) held.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pRemConn, *ppRemConn;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ // Dequeue the connection file from the address list. It must be
+ // in the inactive list.
+ for (ppRemConn = ppConnListHead;
+ (pRemConn = *ppRemConn) != NULL;)
+ {
+ if (pRemConn == pConnRemove)
+ {
+ *ppRemConn = pRemConn->scf_AssocNext;
+ break;
+ }
+
+ ppRemConn = &pRemConn->scf_AssocNext;
+ }
+
+ if (pRemConn == NULL)
+ {
+ CTEAssert(0);
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ return(status);
+}
+
+
+
+
+VOID
+spxConnInsertIntoGlobalActiveList(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine must be called with the device lock held.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ int index = (int)(pSpxConnFile->scf_LocalConnId &
+ NUM_SPXCONN_HASH_MASK);
+
+ // For now, its just a linear list.
+ pSpxConnFile->scf_GlobalActiveNext =
+ SpxDevice->dev_GlobalActiveConnList[index];
+
+ SpxDevice->dev_GlobalActiveConnList[index] =
+ pSpxConnFile;
+
+ return;
+}
+
+
+
+
+NTSTATUS
+spxConnRemoveFromGlobalActiveList(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine must be called with the device lock held.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PSPX_CONN_FILE pC, *ppC;
+ int index = (int)(pSpxConnFile->scf_LocalConnId &
+ NUM_SPXCONN_HASH_MASK);
+ NTSTATUS status = STATUS_SUCCESS;
+
+ // For now, its just a linear list.
+ for (ppC = &SpxDevice->dev_GlobalActiveConnList[index];
+ (pC = *ppC) != NULL;)
+ {
+ if (pC == pSpxConnFile)
+ {
+ DBGPRINT(SEND, INFO,
+ ("SpxConnRemoveFromGlobal: %lx\n", pSpxConnFile));
+
+ // Remove from list
+ *ppC = pC->scf_GlobalActiveNext;
+ break;
+ }
+
+ ppC = &pC->scf_GlobalActiveNext;
+ }
+
+ if (pC == NULL)
+ status = STATUS_INVALID_CONNECTION;
+
+ return(status);
+}
+
+
+
+
+VOID
+spxConnInsertIntoGlobalList(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ pSpxConnFile->scf_GlobalNext = SpxGlobalConnList;
+ SpxGlobalConnList = pSpxConnFile;
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+
+ return;
+}
+
+
+
+
+NTSTATUS
+spxConnRemoveFromGlobalList(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+ PSPX_CONN_FILE pC, *ppC;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ for (ppC = &SpxGlobalConnList;
+ (pC = *ppC) != NULL;)
+ {
+ if (pC == pSpxConnFile)
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxConnRemoveFromGlobal: %lx\n", pSpxConnFile));
+
+ // Remove from list
+ *ppC = pC->scf_GlobalNext;
+ break;
+ }
+
+ ppC = &pC->scf_GlobalNext;
+ }
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+
+ if (pC == NULL)
+ status = STATUS_INVALID_CONNECTION;
+
+ return(status);
+}
+
+
+
+
+
+
+#if 0
+
+VOID
+spxConnPushIntoPktList(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ !!!MACROIZE!!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ pSpxConnFile->scf_PktNext = SpxPktConnList;
+ SpxPktConnList = pSpxConnFile;
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+
+ return;
+}
+
+
+
+
+VOID
+spxConnPopFromPktList(
+ IN PSPX_CONN_FILE * ppSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ !!!MACROIZE!!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ if ((*ppSpxConnFile = SpxPktConnList) != NULL)
+ {
+ SpxPktConnList = SpxPktConnList->scf_PktNext;
+ DBGPRINT(SEND, DBG,
+ ("SpxConnRemoveFromPkt: %lx\n", *ppSpxConnFile));
+ }
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+ return;
+}
+
+
+
+
+VOID
+spxConnPushIntoRecvList(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ !!!MACROIZE!!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ pSpxConnFile->scf_ProcessRecvNext = SpxRecvConnList;
+ SpxRecvConnList = pSpxConnFile;
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+
+ return;
+}
+
+
+
+
+VOID
+spxConnPopFromRecvList(
+ IN PSPX_CONN_FILE * ppSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ !!!MACROIZE!!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ if ((*ppSpxConnFile = SpxRecvConnList) != NULL)
+ {
+ SpxRecvConnList = SpxRecvConnList->scf_ProcessRecvNext;
+ DBGPRINT(SEND, INFO,
+ ("SpxConnRemoveFromRecv: %lx\n", *ppSpxConnFile));
+ }
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+ return;
+}
+
+#endif
+
+
+//
+// Reference/Dereference routines
+//
+
+
+#if DBG
+
+VOID
+SpxConnFileRef(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (pSpxConnFile->scf_RefCount >= 0); // not perfect, but...
+
+ (VOID)SPX_ADD_ULONG (
+ &pSpxConnFile->scf_RefCount,
+ 1,
+ &pSpxConnFile->scf_Lock);
+
+} // SpxRefConnectionFile
+
+
+
+
+VOID
+SpxConnFileLockRef(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+ IT IS CALLED WITH THE CONNECTION LOCK HELD.
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (pSpxConnFile->scf_RefCount >= 0); // not perfect, but...
+
+ (VOID)SPX_ADD_ULONG (
+ &pSpxConnFile->scf_RefCount,
+ 1,
+ &pSpxConnFile->scf_Lock);
+
+} // SpxRefConnectionFileLock
+
+#endif
+
+
+
+
+VOID
+SpxConnFileRefByIdLock (
+ IN USHORT ConnId,
+ OUT PSPX_CONN_FILE * ppSpxConnFile,
+ OUT PNTSTATUS pStatus
+ )
+
+/*++
+
+Routine Description:
+
+ !!!MUST BE CALLED WITH THE DEVICE LOCK HELD!!!
+
+ All active connections should be on the device active list. Later,
+ this data structure will be a tree, caching the last accessed
+ connection.
+
+Arguments:
+
+
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_CONNECTION otherwise
+
+--*/
+{
+ PSPX_CONN_FILE pSpxChkConn;
+
+ *pStatus = STATUS_SUCCESS;
+
+ for (pSpxChkConn =
+ SpxDevice->dev_GlobalActiveConnList[ConnId & NUM_SPXCONN_HASH_MASK];
+ pSpxChkConn != NULL;
+ pSpxChkConn = pSpxChkConn->scf_GlobalActiveNext)
+ {
+ if (pSpxChkConn->scf_LocalConnId == ConnId)
+ {
+ SpxConnFileReference(pSpxChkConn, CFREF_BYID);
+ *ppSpxConnFile = pSpxChkConn;
+ break;
+ }
+ }
+
+ if (pSpxChkConn == NULL)
+ {
+ *pStatus = STATUS_INVALID_CONNECTION;
+ }
+
+ return;
+
+}
+
+
+
+
+VOID
+SpxConnFileRefByCtxLock(
+ IN PSPX_ADDR_FILE pSpxAddrFile,
+ IN CONNECTION_CONTEXT Ctx,
+ OUT PSPX_CONN_FILE * ppSpxConnFile,
+ OUT PNTSTATUS pStatus
+ )
+/*++
+
+Routine Description:
+
+ !!!MUST BE CALLED WITH THE ADDRESS LOCK HELD!!!
+
+ Returns a referenced connection file with the associated context and
+ address file desired.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pSpxChkConn;
+
+ *pStatus = STATUS_SUCCESS;
+
+ for (pSpxChkConn = pSpxAddrFile->saf_Addr->sa_InactiveConnList;
+ pSpxChkConn != NULL;
+ pSpxChkConn = pSpxChkConn->scf_Next)
+ {
+ if ((pSpxChkConn->scf_ConnCtx == Ctx) &&
+ (pSpxChkConn->scf_AddrFile == pSpxAddrFile))
+ {
+ SpxConnFileReference(pSpxChkConn, CFREF_BYCTX);
+ *ppSpxConnFile = pSpxChkConn;
+ break;
+ }
+ }
+
+ if (pSpxChkConn == NULL)
+ {
+ *pStatus = STATUS_INVALID_CONNECTION;
+ }
+
+ return;
+}
+
+
+
+
+NTSTATUS
+SpxConnFileVerify (
+ IN PSPX_CONN_FILE pConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to verify that the pointer given us in a file
+ object is in fact a valid address file object. We also verify that the
+ address object pointed to by it is a valid address object, and reference
+ it to keep it from disappearing while we use it.
+
+Arguments:
+
+
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_CONNECTION otherwise
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ try
+ {
+ if ((pConnFile->scf_Size == sizeof (SPX_CONN_FILE)) &&
+ (pConnFile->scf_Type == SPX_CONNFILE_SIGNATURE))
+ {
+ CTEGetLock (&pConnFile->scf_Lock, &LockHandle);
+ if (!SPX_CONN_FLAG(pConnFile, SPX_CONNFILE_CLOSING))
+ {
+ SpxConnFileLockReference(pConnFile, CFREF_VERIFY);
+ }
+ else
+ {
+ DBGPRINT(TDI, ERR,
+ ("StVerifyConnFile: A %lx closing\n", pConnFile));
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+ CTEFreeLock (&pConnFile->scf_Lock, LockHandle);
+ }
+ else
+ {
+ DBGPRINT(TDI, ERR,
+ ("StVerifyAddressFile: AF %lx bad signature\n", pConnFile));
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DBGPRINT(TDI, ERR,
+ ("SpxVerifyConnFile: AF %lx exception\n", pConnFile));
+
+ return GetExceptionCode();
+ }
+
+ return status;
+
+} // SpxVerifyConnFile
+
+
+
+
+VOID
+SpxConnFileDeref(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences an address file by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ SpxDestroyConnectionFile to remove it from the system.
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+ BOOLEAN fDiscNotIndicated = FALSE;
+ BOOLEAN fIDiscFlag = FALSE;
+ BOOLEAN fSpx2;
+
+ CTEAssert(pSpxConnFile->scf_RefCount > 0);
+ oldvalue = SPX_ADD_ULONG (
+ &pSpxConnFile->scf_RefCount,
+ (ULONG)-1,
+ &pSpxConnFile->scf_Lock);
+
+ CTEAssert (oldvalue > 0);
+ if (oldvalue == 1)
+ {
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+ LIST_ENTRY discReqList, *p;
+ PREQUEST pDiscReq;
+ PSPX_ADDR_FILE pSpxAddrFile = NULL;
+ PREQUEST pCloseReq = NULL,
+ pCleanupReq = NULL,
+ pConnectReq = NULL;
+ BOOLEAN fDisassoc = FALSE;
+
+ InitializeListHead(&discReqList);
+
+ // We may not be associated at this point. Note: When we are active we
+ // always have a reference. So its not like we execute this code very often.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC))
+ {
+ pSpxAddrFile = pSpxConnFile->scf_AddrFile;
+ }
+ else
+ {
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_STOPPING))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Conn cleanup %lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_CleanupReq));
+
+ // Save this for later completion.
+ pCleanupReq = pSpxConnFile->scf_CleanupReq;
+ pSpxConnFile->scf_CleanupReq = NULL;
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_CLOSING))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Conn closing %lx\n",
+ pSpxConnFile));
+
+ // Save this for later completion.
+ pCloseReq = pSpxConnFile->scf_CloseReq;
+
+ //
+ // Null this out so on a re-entrant case, we dont try to complete this again.
+ //
+ pSpxConnFile->scf_CloseReq = NULL;
+ CTEAssert(pCloseReq != NULL);
+ }
+ }
+ CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandleConn);
+
+ if (pSpxAddrFile)
+ {
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ //if (pSpxConnFile->scf_RefCount == 0)
+
+ //
+ // ** The lock passed here is a dummy - it is pre-compiled out.
+ //
+ if (SPX_ADD_ULONG(&pSpxConnFile->scf_RefCount, 0, &pSpxConnFile->scf_Lock) == 0)
+ {
+ DBGPRINT(TDI, INFO,
+ ("SpxDerefConnectionFile: Conn is 0 %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_Flags));
+
+ // All pending requests on this connection are done. See if we
+ // need to complete the disconnect phase etc.
+ switch (SPX_MAIN_STATE(pSpxConnFile))
+ {
+ case SPX_CONNFILE_DISCONN:
+
+ // Disconnect is done. Move connection out of all the lists
+ // it is on, reset states etc.
+ DBGPRINT(TDI, INFO,
+ ("SpxDerefConnectionFile: Conn being inactivated %lx\n",
+ pSpxConnFile));
+
+ // Time to complete disc requests if present.
+ // There could be multiple of them.
+ p = pSpxConnFile->scf_DiscLinkage.Flink;
+ while (p != &pSpxConnFile->scf_DiscLinkage)
+ {
+ pDiscReq = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Disc on %lx.%lx\n",
+ pSpxConnFile, pDiscReq));
+
+ RemoveEntryList(REQUEST_LINKAGE(pDiscReq));
+
+ if (REQUEST_STATUS(pDiscReq) == STATUS_PENDING)
+ {
+ REQUEST_STATUS(pDiscReq) = STATUS_SUCCESS;
+ }
+
+ InsertTailList(
+ &discReqList,
+ REQUEST_LINKAGE(pDiscReq));
+ }
+
+ //
+ // Note the state here, and check after the conn has been inactivated.
+ //
+
+ //
+ // Bug #14354 - odisc and idisc cross each other, leading to double disc to AFD
+ //
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC) &&
+ !SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC)) {
+ fDiscNotIndicated = TRUE;
+ }
+
+ if (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IDISC)) {
+ fIDiscFlag = TRUE;
+ }
+
+ fSpx2 = (SPX2_CONN(pSpxConnFile)) ? TRUE : FALSE;
+
+ //
+ // [SA] Bug #14655
+ // Do not try to inactivate an already inactivated connection
+ //
+
+ if (!(SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED)) {
+ spxConnInactivate(pSpxConnFile);
+ } else {
+ //
+ // This is an SPXI connection which has got the local disconnect.
+ // Reset the flags now.
+ //
+ CTEAssert(!fDiscNotIndicated);
+
+ SPX_MAIN_SETSTATE(pSpxConnFile, 0);
+ SPX_DISC_SETSTATE(pSpxConnFile, 0);
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
+ }
+
+ //
+ // [SA] If we were waiting for sends to be aborted and did not indicate this
+ // disconnect to AFD; and AFD did not call a disconnect on this connection,
+ // then call the disonnect handler now.
+ //
+ if (fDiscNotIndicated) {
+ PVOID pDiscHandlerCtx;
+ PTDI_IND_DISCONNECT pDiscHandler = NULL;
+ ULONG discCode = 0;
+
+ pDiscHandler = pSpxConnFile->scf_AddrFile->saf_DiscHandler;
+ pDiscHandlerCtx = pSpxConnFile->scf_AddrFile->saf_DiscHandlerCtx;
+
+ // Indicate disconnect to afd.
+ if (pDiscHandler != NULL) {
+
+ //
+ // If this was an SPXI connection, the disconnect state is still
+ // DISCONN, so if this routine is re-entered, we need to prevent
+ // a re-indicate to AFD.
+ // Also, we need to wait for a local disconnect from AFD since
+ // we indicated a TDI_DISCONNECT_RELEASE. We bump up the ref count
+ // in this case.
+ //
+ if (!fSpx2) {
+ CTEAssert( (SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED) );
+
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
+
+ if (fIDiscFlag) {
+ SpxConnFileLockReference(pSpxConnFile, CFREF_DISCWAITSPX);
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_DISC_WAIT);
+ }
+ }
+
+ CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock (pSpxAddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock (&SpxDevice->dev_Lock, lockHandleDev);
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxDerefConnectionFile: Indicating to afd On %lx when %lx\n",
+ pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ // First complete all requests waiting for receive completion on
+ // this conn before indicating disconnect.
+ spxConnCompletePended(pSpxConnFile);
+
+ if (fIDiscFlag) {
+ //
+ // Indicate DISCONNECT_RELEASE to AFD so it allows receive of packets
+ // it has buffered before the remote disconnect took place.
+ //
+ discCode = TDI_DISCONNECT_RELEASE;
+ } else {
+ //
+ // [SA] bug #15249
+ // If not Informed disconnect, indicate DISCONNECT_ABORT to AFD
+ //
+ discCode = TDI_DISCONNECT_ABORT;
+ }
+
+ (*pDiscHandler)(
+ pDiscHandlerCtx,
+ pSpxConnFile->scf_ConnCtx,
+ 0, // Disc data
+ NULL,
+ 0, // Disc info
+ NULL,
+ discCode);
+
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ }
+ }
+
+ --SpxDevice->dev_Stat.OpenConnections;
+
+ break;
+
+ case SPX_CONNFILE_CONNECTING:
+ case SPX_CONNFILE_LISTENING:
+
+ // Get connect/accept request if present.
+ pConnectReq = pSpxConnFile->scf_ConnectReq;
+ pSpxConnFile->scf_ConnectReq = NULL;
+
+ spxConnInactivate(pSpxConnFile);
+ break;
+
+ case SPX_CONNFILE_ACTIVE:
+
+ KeBugCheck(0);
+
+ default:
+
+ CTEAssert(SPX_MAIN_STATE(pSpxConnFile) == 0);
+ break;
+ }
+
+ // If stopping, disassociate from the address file. Complete
+ // cleanup request.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_STOPPING))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Conn cleanup %lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_CleanupReq));
+
+ // Save this for later completion.
+ pCleanupReq = pSpxConnFile->scf_CleanupReq;
+ pSpxConnFile->scf_CleanupReq = NULL;
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_STOPPING);
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC))
+ {
+ DBGPRINT(TDI, INFO,
+ ("SpxDerefConnectionFile: Conn stopping %lx\n",
+ pSpxConnFile));
+
+ pSpxAddrFile = pSpxConnFile->scf_AddrFile;
+ SPX_CONN_RESETFLAG(pSpxConnFile,SPX_CONNFILE_ASSOC);
+
+ // Dequeue the connection from the address file
+ spxConnRemoveFromAssocList(
+ &pSpxAddrFile->saf_AssocConnList,
+ pSpxConnFile);
+
+ // Dequeue the connection file from the address list. It must
+ // be in the inactive list.
+ spxConnRemoveFromList(
+ &pSpxAddrFile->saf_Addr->sa_InactiveConnList,
+ pSpxConnFile);
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxConnDerefDisAssociate: %lx from addr file %lx\n",
+ pSpxConnFile, pSpxAddrFile));
+
+ fDisassoc = TRUE;
+ }
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_CLOSING))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Conn closing %lx\n",
+ pSpxConnFile));
+
+ // Save this for later completion.
+ pCloseReq = pSpxConnFile->scf_CloseReq;
+
+ //
+ // Null this out so on a re-entrant case, we dont try to complete this again.
+ //
+ pSpxConnFile->scf_CloseReq = NULL;
+ CTEAssert(pCloseReq != NULL);
+ }
+
+ CTEAssert(IsListEmpty(&pSpxConnFile->scf_ReqLinkage));
+ CTEAssert(IsListEmpty(&pSpxConnFile->scf_RecvLinkage));
+ CTEAssert(IsListEmpty(&pSpxConnFile->scf_DiscLinkage));
+ }
+ CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock (pSpxAddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock (&SpxDevice->dev_Lock, lockHandleDev);
+ }
+
+ if (fDisassoc)
+ {
+ // Remove reference on address for this association.
+ SpxAddrFileDereference(pSpxAddrFile, AFREF_CONN_ASSOC);
+ }
+
+ if (pConnectReq != (PREQUEST)NULL)
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Connect on %lx req %lx\n",
+ pSpxConnFile, pConnectReq));
+
+ // Status will already be set in here. We should be here only if
+ // connect is being aborted.
+ SpxCompleteRequest(pConnectReq);
+ }
+
+ while (!IsListEmpty(&discReqList))
+ {
+ p = RemoveHeadList(&discReqList);
+ pDiscReq = LIST_ENTRY_TO_REQUEST(p);
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnFileDeref: DISC REQ %lx.%lx Completing\n",
+ pSpxConnFile, pDiscReq));
+
+ SpxCompleteRequest(pDiscReq);
+ }
+
+ if (pCleanupReq != (PREQUEST)NULL)
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Cleanup complete %lx req %lx\n",
+ pSpxConnFile, pCleanupReq));
+
+ REQUEST_INFORMATION(pCleanupReq) = 0;
+ REQUEST_STATUS(pCleanupReq) = STATUS_SUCCESS;
+ SpxCompleteRequest (pCleanupReq);
+ }
+
+ if (pCloseReq != (PREQUEST)NULL)
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Freed %lx close req %lx\n",
+ pSpxConnFile, pCloseReq));
+
+ CTEAssert(pSpxConnFile->scf_RefCount == 0);
+
+ // Remove from the global list
+ if (!NT_SUCCESS(spxConnRemoveFromGlobalList(pSpxConnFile)))
+ {
+ KeBugCheck(0);
+ }
+
+ // Free it up.
+ SpxFreeMemory (pSpxConnFile);
+
+ REQUEST_INFORMATION(pCloseReq) = 0;
+ REQUEST_STATUS(pCloseReq) = STATUS_SUCCESS;
+ SpxCompleteRequest (pCloseReq);
+ }
+ }
+
+ return;
+
+} // SpxDerefConnectionFile
+
+
+
+
+VOID
+spxConnReInit(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ // Reinit all variables.
+ pSpxConnFile->scf_Flags2 = 0;
+
+ pSpxConnFile->scf_GlobalActiveNext = NULL;
+ pSpxConnFile->scf_PktNext = NULL;
+ pSpxConnFile->scf_CRetryCount = 0;
+ pSpxConnFile->scf_WRetryCount = 0;
+ pSpxConnFile->scf_RRetryCount = 0;
+ pSpxConnFile->scf_RRetrySeqNum = 0;
+
+ pSpxConnFile->scf_CTimerId =
+ pSpxConnFile->scf_RTimerId =
+ pSpxConnFile->scf_WTimerId =
+ pSpxConnFile->scf_TTimerId =
+ pSpxConnFile->scf_ATimerId = 0;
+
+ pSpxConnFile->scf_LocalConnId =
+ pSpxConnFile->scf_SendSeqNum =
+ pSpxConnFile->scf_SentAllocNum =
+ pSpxConnFile->scf_RecvSeqNum =
+ pSpxConnFile->scf_RetrySeqNum =
+ pSpxConnFile->scf_RecdAckNum =
+ pSpxConnFile->scf_RemConnId =
+ pSpxConnFile->scf_RecdAllocNum = 0;
+
+#if DBG
+ // Initialize so we dont hit breakpoint on seq 0
+ pSpxConnFile->scf_PktSeqNum = 0xFFFF;
+#endif
+
+ pSpxConnFile->scf_DataType = 0;
+
+ CTEAssert(IsListEmpty(&pSpxConnFile->scf_ReqLinkage));
+ CTEAssert(IsListEmpty(&pSpxConnFile->scf_DiscLinkage));
+ CTEAssert(IsListEmpty(&pSpxConnFile->scf_RecvLinkage));
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+ CTEAssert(pSpxConnFile->scf_RecvListTail == NULL);
+ CTEAssert(pSpxConnFile->scf_SendListHead == NULL);
+ CTEAssert(pSpxConnFile->scf_SendListTail == NULL);
+ CTEAssert(pSpxConnFile->scf_SendSeqListHead == NULL);
+ CTEAssert(pSpxConnFile->scf_SendSeqListTail == NULL);
+ pSpxConnFile->scf_CurRecvReq = NULL;
+ pSpxConnFile->scf_CurRecvOffset = 0;
+ pSpxConnFile->scf_CurRecvSize = 0;
+
+ pSpxConnFile->scf_ReqPkt = NULL;
+
+ return;
+}
+
+
+
+
+VOID
+spxConnInactivate(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+ !!! Called with dev/addr/connection lock held !!!
+
+Arguments:
+
+ This gets us back to associate SAVING the state of the STOPPING and
+ CLOSING flags so that dereference can go ahead and finish those.
+
+Return Value:
+
+
+--*/
+{
+ BOOLEAN fStopping, fClosing, fAborting;
+
+ fStopping = SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_STOPPING);
+ fClosing = SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_CLOSING);
+
+ //
+ // [SA] Bug #14655
+ // Save the disconnect states so that a proper error can be given in the case of
+ // a send after a remote disconnection.
+ //
+
+ //
+ // Bug #17729
+ // Dont retain these flags if a local disconnect has already occured.
+ //
+
+ fAborting = (!SPX2_CONN(pSpxConnFile) &&
+ !SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC) &&
+ (SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT));
+
+#if DBG
+ pSpxConnFile->scf_GhostFlags = pSpxConnFile->scf_Flags;
+ pSpxConnFile->scf_GhostFlags2 = pSpxConnFile->scf_Flags2;
+ pSpxConnFile->scf_GhostRefCount = pSpxConnFile->scf_RefCount;
+#endif
+
+ // Clear all flags, go back to the assoc state. Restore stop/close
+ pSpxConnFile->scf_Flags = SPX_CONNFILE_ASSOC;
+ SPX_CONN_SETFLAG(pSpxConnFile,
+ ((fStopping ? SPX_CONNFILE_STOPPING : 0) |
+ (fClosing ? SPX_CONNFILE_CLOSING : 0)));
+
+ //
+ // [SA] bug #14655
+ // In order to avoid a re-entry, mark connection as SPX_DISC_INACTIVATED
+ //
+ if (fAborting)
+ {
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_DISCONN);
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_INACTIVATED);
+ }
+
+ // Remove connection from global list on device
+ if (!NT_SUCCESS(spxConnRemoveFromGlobalActiveList(
+ pSpxConnFile)))
+ {
+ KeBugCheck(0);
+ }
+
+ // Remove connection from active list on address
+ if (!NT_SUCCESS(spxConnRemoveFromList(
+ &pSpxConnFile->scf_AddrFile->saf_Addr->sa_ActiveConnList,
+ pSpxConnFile)))
+ {
+ KeBugCheck(0);
+ }
+
+ // Put connection in inactive list on address
+ SPX_INSERT_ADDR_INACTIVE(
+ pSpxConnFile->scf_AddrFile->saf_Addr,
+ pSpxConnFile);
+
+ spxConnReInit(pSpxConnFile);
+ return;
+}
diff --git a/private/ntos/tdi/isn/spx/spxdev.c b/private/ntos/tdi/isn/spx/spxdev.c
new file mode 100644
index 000000000..431498686
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxdev.c
@@ -0,0 +1,242 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxdev.c
+
+Abstract:
+
+ This module contains code which implements the DEVICE_CONTEXT object.
+ Routines are provided to reference, and dereference transport device
+ context objects.
+
+ The transport device context object is a structure which contains a
+ system-defined DEVICE_OBJECT followed by information which is maintained
+ by the transport provider, called the context.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXDEV
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT, SpxInitCreateDevice)
+#pragma alloc_text(PAGE, SpxDestroyDevice)
+#endif
+
+
+
+
+VOID
+SpxDerefDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a device context by decrementing the
+ reference count contained in the structure. Currently, we don't
+ do anything special when the reference count drops to zero, but
+ we could dynamically unload stuff then.
+
+Arguments:
+
+ Device - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&Device->dev_RefCount);
+
+ CTEAssert (result >= 0);
+
+ if (result == 0)
+ {
+ // Close binding to IPX
+ SpxUnbindFromIpx();
+
+ // Set unload event.
+ KeSetEvent(&SpxUnloadEvent, IO_NETWORK_INCREMENT, FALSE);
+ }
+
+} // SpxDerefDevice
+
+
+
+
+NTSTATUS
+SpxInitCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN OUT PDEVICE * DevicePtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates and initializes a device context structure.
+
+Arguments:
+
+
+ DriverObject - pointer to the IO subsystem supplied driver object.
+
+ Device - Pointer to a pointer to a transport device context object.
+
+ DeviceName - pointer to the name of the device this device object points to.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
+
+--*/
+
+{
+ NTSTATUS status;
+ PDEVICE_OBJECT deviceObject;
+ PDEVICE Device;
+ ULONG DeviceSize;
+ ULONG DeviceNameOffset;
+
+
+ DBGPRINT(DEVICE, INFO,
+ ("SpxInitCreateDevice - Create device %ws\n", DeviceName->Buffer));
+
+ // Create the device object for the sample transport, allowing
+ // room at the end for the device name to be stored (for use
+ // in logging errors).
+ DeviceSize = sizeof(DEVICE) - sizeof(DEVICE_OBJECT) +
+ DeviceName->Length + sizeof(UNICODE_NULL);
+
+ status = IoCreateDevice(
+ DriverObject,
+ DeviceSize,
+ DeviceName,
+ FILE_DEVICE_TRANSPORT,
+ 0,
+ FALSE,
+ &deviceObject);
+
+ if (!NT_SUCCESS(status)) {
+ DBGPRINT(DEVICE, ERR, ("IoCreateDevice failed\n"));
+ return status;
+ }
+
+ deviceObject->Flags |= DO_DIRECT_IO;
+ Device = (PDEVICE)deviceObject;
+
+ DBGPRINT(DEVICE, INFO, ("IoCreateDevice succeeded %lx\n", Device));
+
+ // Initialize our part of the device context.
+ RtlZeroMemory(
+ ((PUCHAR)Device) + sizeof(DEVICE_OBJECT),
+ sizeof(DEVICE) - sizeof(DEVICE_OBJECT));
+
+ DeviceNameOffset = sizeof(DEVICE);
+
+ // Copy over the device name.
+ Device->dev_DeviceNameLen = DeviceName->Length + sizeof(WCHAR);
+ Device->dev_DeviceName = (PWCHAR)(((PUCHAR)Device) + DeviceNameOffset);
+
+ RtlCopyMemory(
+ Device->dev_DeviceName,
+ DeviceName->Buffer,
+ DeviceName->Length);
+
+ Device->dev_DeviceName[DeviceName->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ // Initialize the reference count.
+ Device->dev_RefCount = 1;
+
+#if DBG
+ Device->dev_RefTypes[DREF_CREATE] = 1;
+#endif
+
+#if DBG
+ RtlCopyMemory(Device->dev_Signature1, "IDC1", 4);
+ RtlCopyMemory(Device->dev_Signature2, "IDC2", 4);
+#endif
+
+ // Set next conn id to be used.
+ Device->dev_NextConnId = (USHORT)SpxRandomNumber();
+ if (Device->dev_NextConnId == 0xFFFF)
+ {
+ Device->dev_NextConnId = 1;
+ }
+
+ DBGPRINT(DEVICE, ERR,
+ ("SpxInitCreateDevice: Start Conn Id %lx\n", Device->dev_NextConnId));
+
+ // Initialize the resource that guards address ACLs.
+ ExInitializeResource (&Device->dev_AddrResource);
+
+ // initialize the various fields in the device context
+ CTEInitLock (&Device->dev_Interlock);
+ CTEInitLock (&Device->dev_Lock);
+ KeInitializeSpinLock (&Device->dev_StatInterlock);
+ KeInitializeSpinLock (&Device->dev_StatSpinLock);
+
+ Device->dev_State = DEVICE_STATE_CLOSED;
+ Device->dev_Type = SPX_DEVICE_SIGNATURE;
+ Device->dev_Size = sizeof (DEVICE);
+
+ Device->dev_Stat.Version = 0x100;
+
+ *DevicePtr = Device;
+ return STATUS_SUCCESS;
+
+} // SpxCreateDevice
+
+
+
+
+VOID
+SpxDestroyDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a device context structure.
+
+Arguments:
+
+ Device - Pointer to a pointer to a transport device context object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ExDeleteResource (&Device->dev_AddrResource);
+ IoDeleteDevice ((PDEVICE_OBJECT)Device);
+
+} // SpxDestroyDevice
diff --git a/private/ntos/tdi/isn/spx/spxdrvr.c b/private/ntos/tdi/isn/spx/spxdrvr.c
new file mode 100644
index 000000000..0e9935d1a
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxdrvr.c
@@ -0,0 +1,1008 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxdrvr.c
+
+Abstract:
+
+ This module contains the DriverEntry and other initialization
+ code for the SPX/SPXII module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) Original Version
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 14-July-1995
+ Bug fixes - tagged [SA]
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXDRVR
+
+// Forward declaration of various routines used in this module.
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath);
+
+NTSTATUS
+SpxDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+NTSTATUS
+SpxDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+NTSTATUS
+SpxDispatchInternal (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+NTSTATUS
+SpxDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+VOID
+SpxUnload(
+ IN PDRIVER_OBJECT DriverObject);
+
+VOID
+SpxTdiCancel(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT, DriverEntry)
+#pragma alloc_text(PAGE, SpxUnload)
+#pragma alloc_text(PAGE, SpxDispatchOpenClose)
+#pragma alloc_text(PAGE, SpxDispatch)
+#pragma alloc_text(PAGE, SpxDeviceControl)
+#pragma alloc_text(PAGE, SpxUnload)
+#endif
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs initialization of the SPX ISN module.
+ It creates the device objects for the transport
+ provider and performs other driver initialization.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+ RegistryPath - The name of ST's node in the registry.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ UNICODE_STRING deviceName;
+ NTSTATUS status = STATUS_SUCCESS;
+ BOOLEAN BoundToIpx = FALSE;
+
+ // DBGBRK(FATAL);
+
+ // Initialize the Common Transport Environment.
+ if (CTEInitialize() == 0) {
+ return (STATUS_UNSUCCESSFUL);
+ }
+
+ // We have this #define'd. Ugh, but CONTAINING_RECORD has problem owise.
+ CTEAssert(NDIS_PACKET_SIZE == FIELD_OFFSET(NDIS_PACKET, ProtocolReserved[0]));
+
+ // Create the device object. (IoCreateDevice zeroes the memory
+ // occupied by the object.)
+ RtlInitUnicodeString(&deviceName, SPX_DEVICE_NAME);
+ status = SpxInitCreateDevice(
+ DriverObject,
+ &deviceName,
+ &SpxDevice);
+
+ if (!NT_SUCCESS(status))
+ {
+ return(status);
+ }
+
+ do
+ {
+ CTEInitLock (&SpxGlobalInterlock);
+ CTEInitLock (&SpxGlobalQInterlock);
+
+ // Initialize the unload event
+ KeInitializeEvent(
+ &SpxUnloadEvent,
+ NotificationEvent,
+ FALSE);
+
+ // !!!The device is created at this point!!!
+ // Get information from the registry.
+ status = SpxInitGetConfiguration(
+ RegistryPath,
+ &SpxDevice->dev_ConfigInfo);
+
+ if (!NT_SUCCESS(status))
+ {
+ break;
+ }
+
+#if defined(_PNP_POWER)
+ //
+ // Make Tdi ready for pnp notifications before binding
+ // to IPX
+ //
+ TdiInitialize();
+
+ // Initialize the timer system. This should be done before
+ // binding to ipx because we should have timers intialized
+ // before ipx calls our pnp indications.
+ if (!NT_SUCCESS(status = SpxTimerInit()))
+ {
+ break;
+ }
+#endif _PNP_POWER
+
+ // Bind to the IPX transport.
+ if (!NT_SUCCESS(status = SpxInitBindToIpx()))
+ {
+ // BUGBUG: Have ipx name here as second string
+ LOG_ERROR(
+ EVENT_TRANSPORT_BINDING_FAILED,
+ status,
+ NULL,
+ NULL,
+ 0);
+
+ break;
+ }
+
+ BoundToIpx = TRUE;
+
+#if !defined(_PNP_POWER)
+ // Initialize the timer system
+ if (!NT_SUCCESS(status = SpxTimerInit()))
+ {
+ break;
+ }
+#endif !_PNP_POWER
+
+ // Initialize the block manager
+ if (!NT_SUCCESS(status = SpxInitMemorySystem(SpxDevice)))
+ {
+
+ // Stop the timer subsystem
+ SpxTimerFlushAndStop();
+ break;
+ }
+
+ // Initialize the driver object with this driver's entry points.
+ DriverObject->MajorFunction [IRP_MJ_CREATE] = SpxDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLOSE] = SpxDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLEANUP] = SpxDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL]
+ = SpxDispatch;
+ DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL]
+ = SpxDispatchInternal;
+ DriverObject->DriverUnload = SpxUnload;
+
+ // Initialize the provider info
+ SpxQueryInitProviderInfo(&SpxDevice->dev_ProviderInfo);
+ SpxDevice->dev_CurrentSocket = (USHORT)PARAM(CONFIG_SOCKET_RANGE_START);
+
+#if !defined(_PNP_POWER)
+ // We are open now.
+ SpxDevice->dev_State = DEVICE_STATE_OPEN;
+#endif !_PNP_POWER
+
+ // Set the window size in statistics
+ SpxDevice->dev_Stat.MaximumSendWindow =
+ SpxDevice->dev_Stat.AverageSendWindow = PARAM(CONFIG_WINDOW_SIZE) *
+ IpxLineInfo.MaximumSendSize;
+
+#if defined(_PNP_POWER)
+ if ( DEVICE_STATE_CLOSED == SpxDevice->dev_State ) {
+ SpxDevice->dev_State = DEVICE_STATE_LOADED;
+ }
+#endif _PNP_POWER
+
+ } while (FALSE);
+
+ if (!NT_SUCCESS(status) )
+ {
+ // Delete the device and any associated resources created.
+ if( BoundToIpx ) {
+ SpxDerefDevice(SpxDevice);
+ }
+ SpxDestroyDevice(SpxDevice);
+ }
+
+ return (status);
+}
+
+
+
+
+VOID
+SpxUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unloads the sample transport driver. The I/O system will not
+ call us until nobody above has ST open.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ None. When the function returns, the driver is unloaded.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (DriverObject);
+
+ // Stop the timer subsystem
+ SpxTimerFlushAndStop();
+
+ // Remove creation reference count on the IPX device object.
+ SpxDerefDevice(SpxDevice);
+
+ // Wait on the unload event.
+ KeWaitForSingleObject(
+ &SpxUnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL);
+
+ // Release the block memory stuff
+ SpxDeInitMemorySystem(SpxDevice);
+ SpxDestroyDevice(SpxDevice);
+ return;
+}
+
+
+
+NTSTATUS
+SpxDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the ST device driver.
+ It accepts an I/O Request Packet, performs the request, and then
+ returns with the appropriate status.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+
+ if (Device->dev_State != DEVICE_STATE_OPEN) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ // Make sure status information is consistent every time.
+ IoMarkIrpPending (Irp);
+ Irp->IoStatus.Status = STATUS_PENDING;
+ Irp->IoStatus.Information = 0;
+
+ // Case on the function that is being performed by the requestor. If the
+ // operation is a valid one for this device, then make it look like it was
+ // successfully completed, where possible.
+ switch (IrpSp->MajorFunction) {
+
+ case IRP_MJ_DEVICE_CONTROL:
+
+ Status = SpxDeviceControl (DeviceObject, Irp);
+ break;
+
+ default:
+
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ //
+ // Complete the Irp here instead of below.
+ //
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ } // major function switch
+
+ /* Commented out and re-located to the default case above.
+
+ if (Status != STATUS_PENDING) {
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ }
+ */
+
+ // Return the immediate status code to the caller.
+ return Status;
+
+} // SpxDispatch
+
+VOID
+SpxAssignControlChannelId(
+ IN PDEVICE Device,
+ IN PIRP Request
+ )
+/*++
+
+Routine Description:
+
+ This routine is required to ensure that the Device lock (to protect the ControlChannelId in the Device)
+ is not taken in a pageable routine (SpxDispatchOpenClose).
+
+ NOTE: SPX returns the ControlChannelId in the Request, but never uses it later when it comes down in a
+ close/cleanup. The CCID is a ULONG; in future, if we start using this field (as in IPX which uses these Ids
+ to determine lineup Irps to complete), then we may run out of numbers (since we monotonically increase the CCID);
+ though there is a low chance of that since we will probably run out of memory before that! Anyhow, if that
+ happens, one solution (used in IPX) is to make the CCID into a Large Integer and pack the values into the
+ REQUEST_OPEN_TYPE(Irp) too.
+
+
+Arguments:
+
+ Device - Pointer to the device object for this driver.
+
+ Request - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ CTELockHandle LockHandle;
+
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)(Device->dev_CcId);
+ ++Device->dev_CcId;
+ if (Device->dev_CcId == 0) {
+ Device->dev_CcId = 1;
+ }
+
+ CTEFreeLock (&Device->dev_Lock, LockHandle);
+}
+
+NTSTATUS
+SpxDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the ST device driver.
+ It accepts an I/O Request Packet, performs the request, and then
+ returns with the appropriate status.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ NTSTATUS Status;
+ BOOLEAN found;
+ PREQUEST Request;
+ UINT i;
+ PFILE_FULL_EA_INFORMATION openType;
+ CONNECTION_CONTEXT connCtx;
+
+
+#if !defined(_PNP_POWER)
+ if (Device->dev_State != DEVICE_STATE_OPEN) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+#endif !_PNP_POWER
+
+ // Allocate a request to track this IRP.
+ Request = SpxAllocateRequest (Device, Irp);
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+
+ // Make sure status information is consistent every time.
+ MARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = STATUS_PENDING;
+ REQUEST_INFORMATION(Request) = 0;
+
+ // Case on the function that is being performed by the requestor. If the
+ // operation is a valid one for this device, then make it look like it was
+ // successfully completed, where possible.
+ switch (REQUEST_MAJOR_FUNCTION(Request)) {
+
+ // The Create function opens a transport object (either address or
+ // connection). Access checking is performed on the specified
+ // address to ensure security of transport-layer addresses.
+ case IRP_MJ_CREATE:
+
+#if defined(_PNP_POWER)
+ if (Device->dev_State != DEVICE_STATE_OPEN) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ break;
+ }
+#endif _PNP_POWER
+
+ openType = OPEN_REQUEST_EA_INFORMATION(Request);
+
+ if (openType != NULL) {
+
+ found = TRUE;
+
+ for (i=0;i<openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiTransportAddress[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = SpxAddrOpen (Device, Request);
+ break;
+ }
+
+ // Connection?
+ found = TRUE;
+
+ for (i=0;i<openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiConnectionContext[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ if (openType->EaValueLength < sizeof(CONNECTION_CONTEXT))
+ {
+
+ DBGPRINT(CREATE, ERR,
+ ("Create: Context size %d\n", openType->EaValueLength));
+
+ Status = STATUS_EA_LIST_INCONSISTENT;
+ break;
+ }
+
+ connCtx =
+ *((CONNECTION_CONTEXT UNALIGNED *)
+ &openType->EaName[openType->EaNameLength+1]);
+
+ Status = SpxConnOpen(
+ Device,
+ connCtx,
+ Request);
+
+ break;
+ }
+
+ } else {
+
+ //
+ // Takes a lock in a Pageable routine - call another (non-paged) function to do that.
+ //
+ SpxAssignControlChannelId(Device, Request);
+
+ REQUEST_OPEN_TYPE(Request) = (PVOID)SPX_FILE_TYPE_CONTROL;
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case IRP_MJ_CLOSE:
+
+#if defined(_PNP_POWER)
+ if ((Device->dev_State != DEVICE_STATE_OPEN) && ( Device->dev_State != DEVICE_STATE_LOADED )) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ break;
+ }
+#endif _PNP_POWER
+
+ // The Close function closes a transport endpoint, terminates
+ // all outstanding transport activity on the endpoint, and unbinds
+ // the endpoint from its transport address, if any. If this
+ // is the last transport endpoint bound to the address, then
+ // the address is removed from the provider.
+ switch ((ULONG)REQUEST_OPEN_TYPE(Request)) {
+ case TDI_TRANSPORT_ADDRESS_FILE:
+
+ Status = SpxAddrFileClose(Device, Request);
+ break;
+
+ case TDI_CONNECTION_FILE:
+ Status = SpxConnClose(Device, Request);
+ break;
+
+ case SPX_FILE_TYPE_CONTROL:
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ break;
+
+ case IRP_MJ_CLEANUP:
+
+#if defined(_PNP_POWER)
+ if ((Device->dev_State != DEVICE_STATE_OPEN) && ( Device->dev_State != DEVICE_STATE_LOADED )) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ break;
+ }
+#endif _PNP_POWER
+
+ // Handle the two stage IRP for a file close operation. When the first
+ // stage hits, run down all activity on the object of interest. This
+ // do everything to it but remove the creation hold. Then, when the
+ // CLOSE irp hits, actually close the object.
+ switch ((ULONG)REQUEST_OPEN_TYPE(Request)) {
+ case TDI_TRANSPORT_ADDRESS_FILE:
+
+ Status = SpxAddrFileCleanup(Device, Request);
+ break;
+
+ case TDI_CONNECTION_FILE:
+
+ Status = SpxConnCleanup(Device, Request);
+ break;
+
+ case SPX_FILE_TYPE_CONTROL:
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ break;
+
+ default:
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ } // major function switch
+
+ if (Status != STATUS_PENDING) {
+ UNMARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = Status;
+ SpxCompleteRequest (Request);
+ SpxFreeRequest (Device, Request);
+ }
+
+ // Return the immediate status code to the caller.
+ return Status;
+
+} // SpxDispatchOpenClose
+
+
+
+
+NTSTATUS
+SpxDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ // Convert the user call to the proper internal device call.
+ Status = TdiMapUserRequest (DeviceObject, Irp, IrpSp);
+ if (Status == STATUS_SUCCESS) {
+
+ // If TdiMapUserRequest returns SUCCESS then the IRP
+ // has been converted into an IRP_MJ_INTERNAL_DEVICE_CONTROL
+ // IRP, so we dispatch it as usual. The IRP will
+ // be completed by this call.
+ Status = SpxDispatchInternal (DeviceObject, Irp);
+
+ //
+ // Return the proper error code here. If SpxDispatchInternal returns an error,
+ // then we used to map it to pending below; this is wrong since the client above
+ // us could wait for ever since the IO subsystem does not set the event if an
+ // error is returned and the Irp is not marked pending.
+ //
+
+ // Status = STATUS_PENDING;
+ } else {
+
+ DBGPRINT(TDI, DBG,
+ ("Unknown Tdi code in Irp: %lx\n", Irp));
+
+ //
+ // Complete the Irp....
+ //
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ }
+
+ return Status;
+
+} // SpxDeviceControl
+
+
+
+
+NTSTATUS
+SpxDispatchInternal (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ PREQUEST Request;
+ KIRQL oldIrql;
+ NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+
+
+ if (Device->dev_State != DEVICE_STATE_OPEN)
+ {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+
+ // Allocate a request to track this IRP.
+ Request = SpxAllocateRequest (Device, Irp);
+ IF_NOT_ALLOCATED(Request)
+ {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+
+ // Make sure status information is consistent every time.
+ MARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = STATUS_PENDING;
+ REQUEST_INFORMATION(Request) = 0;
+
+ // Cancel irp
+ IoAcquireCancelSpinLock(&oldIrql);
+ if (!Irp->Cancel)
+ {
+ IoSetCancelRoutine(Irp, (PDRIVER_CANCEL)SpxTdiCancel);
+ }
+ IoReleaseCancelSpinLock(oldIrql);
+
+ if (Irp->Cancel)
+ return STATUS_CANCELLED;
+
+ // Branch to the appropriate request handler. Preliminary checking of
+ // the size of the request block is performed here so that it is known
+ // in the handlers that the minimum input parameters are readable. It
+ // is *not* determined here whether variable length input fields are
+ // passed correctly; this is a check which must be made within each routine.
+ switch (REQUEST_MINOR_FUNCTION(Request))
+ {
+ case TDI_ACCEPT:
+
+ Status = SpxConnAccept(
+ Device,
+ Request);
+
+ break;
+
+ case TDI_SET_EVENT_HANDLER:
+
+ Status = SpxAddrSetEventHandler(
+ Device,
+ Request);
+
+ break;
+
+ case TDI_RECEIVE:
+
+ Status = SpxConnRecv(
+ Device,
+ Request);
+ break;
+
+
+ case TDI_SEND:
+
+ Status = SpxConnSend(
+ Device,
+ Request);
+ break;
+
+ case TDI_ACTION:
+
+ Status = SpxConnAction(
+ Device,
+ Request);
+ break;
+
+ case TDI_ASSOCIATE_ADDRESS:
+
+ Status = SpxConnAssociate(
+ Device,
+ Request);
+
+ break;
+
+ case TDI_DISASSOCIATE_ADDRESS:
+
+ Status = SpxConnDisAssociate(
+ Device,
+ Request);
+
+ break;
+
+ case TDI_CONNECT:
+
+ Status = SpxConnConnect(
+ Device,
+ Request);
+
+ break;
+
+ case TDI_DISCONNECT:
+
+ Status = SpxConnDisconnect(
+ Device,
+ Request);
+ break;
+
+ case TDI_LISTEN:
+
+ Status = SpxConnListen(
+ Device,
+ Request);
+ break;
+
+ case TDI_QUERY_INFORMATION:
+
+ Status = SpxTdiQueryInformation(
+ Device,
+ Request);
+
+ break;
+
+ case TDI_SET_INFORMATION:
+
+ Status = SpxTdiSetInformation(
+ Device,
+ Request);
+
+ break;
+
+ // Something we don't know about was submitted.
+ default:
+
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ if (Status != STATUS_PENDING)
+ {
+ UNMARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = Status;
+ IoAcquireCancelSpinLock(&oldIrql);
+ IoSetCancelRoutine(Irp, (PDRIVER_CANCEL)NULL);
+ IoReleaseCancelSpinLock(oldIrql);
+ SpxCompleteRequest (Request);
+ SpxFreeRequest (Device, Request);
+ }
+
+ // Return the immediate status code to the caller.
+ return Status;
+
+} // SpxDispatchInternal
+
+
+
+
+VOID
+SpxTdiCancel(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+/*++
+
+Routine Description:
+
+ This routine handles cancellation of IO requests
+
+Arguments:
+
+
+Return Value:
+--*/
+{
+ PREQUEST Request;
+ PSPX_ADDR_FILE pSpxAddrFile;
+ PSPX_ADDR pSpxAddr;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ CTELockHandle connectIrql;
+ CTELockHandle TempIrql;
+ PSPX_CONN_FILE pSpxConnFile;
+
+ Request = SpxAllocateRequest (Device, Irp);
+ IF_NOT_ALLOCATED(Request)
+ {
+ return;
+ }
+
+ DBGPRINT(TDI, ERR,
+ ("SpxTdiCancel: Cancel irp called %lx.%lx\n",
+ Irp, REQUEST_OPEN_CONTEXT(Request)));
+
+ switch ((ULONG)REQUEST_OPEN_TYPE(Request))
+ {
+ case TDI_CONNECTION_FILE:
+ pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(Request);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &connectIrql);
+
+ //
+ // Swap the irql
+ //
+ TempIrql = connectIrql;
+ connectIrql = Irp->CancelIrql;
+ Irp->CancelIrql = TempIrql;
+
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_STOPPING))
+ {
+ if (!SPX_CONN_IDLE(pSpxConnFile))
+ {
+ //
+ // This releases the lock
+ //
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_LOCAL_DISCONNECT,
+ SPX_CALL_TDILEVEL,
+ connectIrql,
+ FALSE); // [SA] bug #15249
+ }
+ }
+
+// SpxConnStop((PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(Request));
+ break;
+
+ case TDI_TRANSPORT_ADDRESS_FILE:
+
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+ pSpxAddrFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(Request);
+ pSpxAddr = pSpxAddrFile->saf_Addr;
+ SpxAddrFileStop(pSpxAddrFile, pSpxAddr);
+ break;
+
+ default:
+
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+ break;
+
+ }
+
+}
diff --git a/private/ntos/tdi/isn/spx/spxerror.c b/private/ntos/tdi/isn/spx/spxerror.c
new file mode 100644
index 000000000..7d2cc7444
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxerror.c
@@ -0,0 +1,316 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxerror.c
+
+Abstract:
+
+ This module contains code which provides error logging support.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXERROR
+
+LONG SpxLastRawDataLen = 0;
+NTSTATUS SpxLastUniqueErrorCode = STATUS_SUCCESS;
+NTSTATUS SpxLastNtStatusCode = STATUS_SUCCESS;
+ULONG SpxLastErrorCount = 0;
+LONG SpxLastErrorTime = 0;
+BYTE SpxLastRawData[PORT_MAXIMUM_MESSAGE_LENGTH - \
+ sizeof(IO_ERROR_LOG_PACKET)] = {0};
+
+BOOLEAN
+SpxFilterErrorLogEntry(
+ IN NTSTATUS UniqueErrorCode,
+ IN NTSTATUS NtStatusCode,
+ IN PVOID RawDataBuf OPTIONAL,
+ IN LONG RawDataLen
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+
+ int insertionStringLength = 0;
+
+ // Filter out events such that the same event recurring close together does not
+ // cause errorlog clogging. The scheme is - if the event is same as the last event
+ // and the elapsed time is > THRESHOLD and ERROR_CONSEQ_FREQ simulataneous errors
+ // have happened, then log it else skip
+ if ((UniqueErrorCode == SpxLastUniqueErrorCode) &&
+ (NtStatusCode == SpxLastNtStatusCode))
+ {
+ SpxLastErrorCount++;
+ if ((SpxLastRawDataLen == RawDataLen) &&
+ (RtlEqualMemory(SpxLastRawData, RawDataBuf, RawDataLen)) &&
+ ((SpxLastErrorCount % ERROR_CONSEQ_FREQ) != 0) &&
+ ((SpxGetCurrentTime() - SpxLastErrorTime) < ERROR_CONSEQ_TIME))
+ {
+ return(FALSE);
+ }
+ }
+
+ SpxLastUniqueErrorCode = UniqueErrorCode;
+ SpxLastNtStatusCode = NtStatusCode;
+ SpxLastErrorCount = 0;
+ SpxLastErrorTime = SpxGetCurrentTime();
+ if (RawDataLen != 0)
+ {
+ SpxLastRawDataLen = RawDataLen;
+ RtlCopyMemory(
+ SpxLastRawData,
+ RawDataBuf,
+ RawDataLen);
+ }
+
+ return(TRUE);
+}
+
+
+
+
+VOID
+SpxWriteResourceErrorLog(
+ IN PDEVICE Device,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ an out of resources condition.
+
+Arguments:
+
+ Device - Pointer to the device context.
+
+ BytesNeeded - If applicable, the number of bytes that could not
+ be allocated.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ PUCHAR StringLoc;
+ ULONG TempUniqueError;
+ static WCHAR UniqueErrorBuffer[4] = L"000";
+ UINT i;
+
+ if (!SpxFilterErrorLogEntry(
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ STATUS_INSUFFICIENT_RESOURCES,
+ (PVOID)&BytesNeeded,
+ sizeof(BytesNeeded)))
+ {
+ return;
+ }
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ Device->dev_DeviceNameLen +
+ sizeof(UniqueErrorBuffer);
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)Device,
+ EntrySize);
+
+ // Convert the error value into a buffer.
+ TempUniqueError = UniqueErrorValue;
+ for (i=1; i>=0; i--)
+ {
+ UniqueErrorBuffer[i] = (WCHAR)((TempUniqueError % 10) + L'0');
+ TempUniqueError /= 10;
+ }
+
+ if (errorLogEntry != NULL)
+ {
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = sizeof(ULONG);
+ errorLogEntry->NumberOfStrings = 2;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = EVENT_TRANSPORT_RESOURCE_POOL;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+ errorLogEntry->DumpData[0] = BytesNeeded;
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ RtlCopyMemory(
+ StringLoc, Device->dev_DeviceName, Device->dev_DeviceNameLen);
+
+ StringLoc += Device->dev_DeviceNameLen;
+ RtlCopyMemory(
+ StringLoc, UniqueErrorBuffer, sizeof(UniqueErrorBuffer));
+
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+}
+
+
+
+
+VOID
+SpxWriteGeneralErrorLog(
+ IN PDEVICE Device,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN PVOID RawDataBuf OPTIONAL,
+ IN LONG RawDataLen
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ a general problem as indicated by the parameters. It handles
+ event codes REGISTER_FAILED, BINDING_FAILED, ADAPTER_NOT_FOUND,
+ TRANSFER_DATA, TOO_MANY_LINKS, and BAD_PROTOCOL. All these
+ events have messages with one or two strings in them.
+
+Arguments:
+
+ Device - Pointer to the device context, or this may be
+ a driver object instead.
+
+ ErrorCode - The transport event code.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet.
+
+ FinalStatus - Used as the FinalStatus in the error log packet.
+
+ SecondString - If not NULL, the string to use as the %3
+ value in the error log packet.
+
+ RawDataBuf - The number of ULONGs of dump data.
+
+ RawDataLen - Dump data for the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG SecondStringSize;
+ PUCHAR StringLoc;
+ static WCHAR DriverName[4] = L"Spx";
+
+ if (!SpxFilterErrorLogEntry(
+ ErrorCode,
+ FinalStatus,
+ RawDataBuf,
+ RawDataLen))
+ {
+ return;
+ }
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) + RawDataLen;
+ if (Device->dev_Type == SPX_DEVICE_SIGNATURE)
+ {
+ EntrySize += (UCHAR)Device->dev_DeviceNameLen;
+ }
+ else
+ {
+ EntrySize += sizeof(DriverName);
+ }
+
+ if (SecondString)
+ {
+ SecondStringSize = (wcslen(SecondString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize += (UCHAR)SecondStringSize;
+ }
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)Device,
+ EntrySize);
+
+ if (errorLogEntry != NULL)
+ {
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = (USHORT)RawDataLen;
+ errorLogEntry->NumberOfStrings = (SecondString == NULL) ? 1 : 2;
+ errorLogEntry->StringOffset =
+ sizeof(IO_ERROR_LOG_PACKET) + RawDataLen;
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ if (RawDataLen != 0)
+ {
+ RtlCopyMemory(errorLogEntry->DumpData, RawDataBuf, RawDataLen);
+ }
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ if (Device->dev_Type == SPX_DEVICE_SIGNATURE)
+ {
+ RtlCopyMemory(
+ StringLoc, Device->dev_DeviceName, Device->dev_DeviceNameLen);
+
+ StringLoc += Device->dev_DeviceNameLen;
+ }
+ else
+ {
+ RtlCopyMemory (StringLoc, DriverName, sizeof(DriverName));
+ StringLoc += sizeof(DriverName);
+ }
+
+ if (SecondString)
+ {
+ RtlCopyMemory (StringLoc, SecondString, SecondStringSize);
+ }
+
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+ return;
+}
diff --git a/private/ntos/tdi/isn/spx/spxmem.c b/private/ntos/tdi/isn/spx/spxmem.c
new file mode 100644
index 000000000..9cd400e5b
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxmem.c
@@ -0,0 +1,897 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxmem.c
+
+Abstract:
+
+ This module contains code which implements the memory allocation wrappers.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+ Jameel Hyder (jameelh) Initial Version
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text( INIT, SpxInitMemorySystem)
+#pragma alloc_text( PAGE, SpxDeInitMemorySystem)
+#endif
+
+// Define module number for event logging entries
+#define FILENUM SPXMEM
+
+// Globals for this module
+// Some block sizes (like NDISSEND/NDISRECV are filled in after binding with IPX)
+USHORT spxBlkSize[NUM_BLKIDS] = // Size of each block
+ {
+ sizeof(BLK_HDR)+sizeof(TIMERLIST), // BLKID_TIMERLIST
+ 0, // BLKID_NDISSEND
+ 0 // BLKID_NDISRECV
+ };
+
+USHORT spxChunkSize[NUM_BLKIDS] = // Size of each Chunk
+ {
+ 512-BC_OVERHEAD, // BLKID_TIMERLIST
+ 512-BC_OVERHEAD, // BLKID_NDISSEND
+ 512-BC_OVERHEAD // BLKID_NDISRECV
+ };
+
+
+// Filled in after binding with IPX
+// Reference for below.
+// ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/
+// (sizeof(BLK_HDR)+sizeof(TIMERLIST)), // BLKID_TIMERLIST
+USHORT spxNumBlks[NUM_BLKIDS] = // Number of blocks per chunk
+ {
+ ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/
+ (sizeof(BLK_HDR)+sizeof(TIMERLIST)), // BLKID_TIMERLIST
+ 0, // BLKID_NDISSEND
+ 0 // BLKID_NDISRECV
+ };
+
+CTELock spxBPLock[NUM_BLKIDS] = { 0 };
+PBLK_CHUNK spxBPHead[NUM_BLKIDS] = { 0 };
+
+
+
+
+NTSTATUS
+SpxInitMemorySystem(
+ IN PDEVICE pSpxDevice
+ )
+/*++
+
+Routine Description:
+
+ !!! MUST BE CALLED AFTER BINDING TO IPX!!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LONG i;
+ NDIS_STATUS ndisStatus;
+
+ // Try to allocate the ndis buffer pool.
+ NdisAllocateBufferPool(
+ &ndisStatus,
+ &pSpxDevice->dev_NdisBufferPoolHandle,
+ 20);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ return(STATUS_INSUFFICIENT_RESOURCES);
+
+ for (i = 0; i < NUM_BLKIDS; i++)
+ CTEInitLock (&spxBPLock[i]);
+
+ // Set the sizes in the block id info arrays.
+ for (i = 0; i < NUM_BLKIDS; i++)
+ {
+ // BUGBUG: Do it.
+ switch (i)
+ {
+ case BLKID_NDISSEND:
+
+#ifdef SPX_OWN_PACKETS
+ spxBlkSize[i] = sizeof(BLK_HDR) +
+ sizeof(SPX_SEND_RESD) +
+ NDIS_PACKET_SIZE +
+ IpxMacHdrNeeded +
+ MIN_IPXSPX2_HDRSIZE;
+#else
+ spxBlkSize[i] = sizeof(PNDIS_PACKET);
+#endif
+
+ //
+ // Round the block size up to the next 8-byte boundary.
+ //
+ spxBlkSize[i] = QWORDSIZEBLOCK(spxBlkSize[i]);
+
+ // Set number blocks
+ spxNumBlks[i] = ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/spxBlkSize[i];
+ break;
+
+ case BLKID_NDISRECV:
+
+#ifdef SPX_OWN_PACKETS
+ spxBlkSize[i] = sizeof(BLK_HDR) +
+ sizeof(SPX_RECV_RESD) +
+ NDIS_PACKET_SIZE;
+#else
+ spxBlkSize[i] = sizeof(PNDIS_PACKET);
+#endif
+
+ //
+ // Round the block size up to the next 8-byte boundary.
+ //
+ spxBlkSize[i] = QWORDSIZEBLOCK(spxBlkSize[i]);
+
+ // Set number blocks
+ spxNumBlks[i] = ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/spxBlkSize[i];
+ break;
+
+ default:
+
+ break;
+ }
+
+ }
+
+ SpxTimerScheduleEvent((TIMER_ROUTINE)spxBPAgePool,
+ BLOCK_POOL_TIMER,
+ NULL);
+}
+
+
+
+
+VOID
+SpxDeInitMemorySystem(
+ IN PDEVICE pSpxDevice
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LONG i, j, NumBlksPerChunk;
+ PBLK_CHUNK pChunk, pFree;
+
+ for (i = 0; i < NUM_BLKIDS; i++)
+ {
+ NumBlksPerChunk = spxNumBlks[i];
+ for (pChunk = spxBPHead[i];
+ pChunk != NULL; )
+ {
+ DBGPRINT(RESOURCES, ERR,
+ ("SpxInitMemorySystem: Freeing %lx\n", pChunk));
+
+ CTEAssert (pChunk->bc_NumFrees == NumBlksPerChunk);
+
+ if ((pChunk->bc_BlkId == BLKID_NDISSEND) ||
+ (pChunk->bc_BlkId == BLKID_NDISRECV))
+ {
+ PBLK_HDR pBlkHdr;
+
+ // We need to free the Ndis stuff for these guys
+ for (j = 0, pBlkHdr = pChunk->bc_FreeHead;
+ j < NumBlksPerChunk;
+ j++, pBlkHdr = pBlkHdr->bh_Next)
+ {
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+
+#ifdef SPX_OWN_PACKETS
+ // Only need to free the ndis buffer.
+ pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
+
+ if (pChunk->bc_BlkId == BLKID_NDISSEND)
+ {
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ if (pNdisBuffer == NULL)
+ {
+ // Something is terribly awry.
+ KeBugCheck(0);
+ }
+
+ NdisFreeBuffer(pNdisBuffer);
+
+ //
+ // Free the second MDL also
+ //
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ if (pNdisBuffer == NULL)
+ {
+ // Something is terribly awry.
+ KeBugCheck(0);
+ }
+
+ NdisFreeBuffer(pNdisBuffer);
+ }
+#else
+ // Need to free both the packet and the buffer.
+ ppNdisPkt = (PNDIS_PACKET *)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
+
+ if (pChunk->bc_BlkId == BLKID_NDISSEND)
+ {
+
+ NdisUnchainBufferAtFront(*ppNdisPkt, &pNdisBuffer);
+ if (pNdisBuffer == NULL)
+ {
+ // Something is terribly awry.
+ KeBugCheck(0);
+ }
+
+ NdisFreeBuffer(pNdisBuffer);
+ }
+ NdisFreePacket(*ppNdisPkt);
+#endif
+ }
+ }
+ pFree = pChunk;
+ pChunk = pChunk->bc_Next;
+
+#ifndef SPX_OWN_PACKETS
+ // Free the ndis packet pool in chunk
+ NdisFreePacketPool((NDIS_HANDLE)pFree->bc_ChunkCtx);
+#endif
+ SpxFreeMemory(pFree);
+ }
+ }
+
+ // Free up the ndis buffer pool
+ NdisFreeBufferPool(
+ pSpxDevice->dev_NdisBufferPoolHandle);
+
+ return;
+}
+
+
+
+
+PVOID
+SpxAllocMem(
+#ifdef TRACK_MEMORY_USAGE
+ IN ULONG Size,
+ IN ULONG FileLine
+#else
+ IN ULONG Size
+#endif // TRACK_MEMORY_USAGE
+ )
+/*++
+
+Routine Description:
+
+ Allocate a block of non-paged memory. This is just a wrapper over ExAllocPool.
+ Allocation failures are error-logged. We always allocate a ULONG more than
+ the specified size to accomodate the size. This is used by SpxFreeMemory
+ to update the statistics.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PBYTE pBuf;
+ BOOLEAN zeroed;
+
+ // round up the size so that we can put a signature at the end
+ // that is on a LARGE_INTEGER boundary
+ zeroed = ((Size & ZEROED_MEMORY_TAG) == ZEROED_MEMORY_TAG);
+
+ Size = QWORDSIZEBLOCK(Size & ~ZEROED_MEMORY_TAG);
+
+ // Do the actual memory allocation. Allocate eight extra bytes so
+ // that we can store the size of the allocation for the free routine
+ // and still keep the buffer quadword aligned.
+
+ if ((pBuf = ExAllocatePoolWithTag(NonPagedPool, Size + sizeof(LARGE_INTEGER)
+#if DBG
+ + sizeof(ULONG)
+#endif
+ ,SPX_TAG)) == NULL)
+ {
+ DBGPRINT(RESOURCES, FATAL,
+ ("SpxAllocMemory: failed - size %lx\n", Size));
+
+ TMPLOGERR();
+ return NULL;
+ }
+
+ // Save the size of this block in the four extra bytes we allocated.
+ *((PULONG)pBuf) = (Size + sizeof(LARGE_INTEGER));
+
+ // Return a pointer to the memory after the size longword.
+ pBuf += sizeof(LARGE_INTEGER);
+
+#if DBG
+ *((PULONG)(pBuf+Size)) = SPX_MEMORY_SIGNATURE;
+ DBGPRINT(RESOURCES, INFO,
+ ("SpxAllocMemory: %lx Allocated %lx bytes @%lx\n",
+ *(PULONG)((PBYTE)(&Size) - sizeof(Size)), Size, pBuf));
+#endif
+
+ SpxTrackMemoryUsage((PVOID)(pBuf - sizeof(LARGE_INTEGER)), TRUE, FileLine);
+
+ if (zeroed)
+ RtlZeroMemory(pBuf, Size);
+
+ return (pBuf);
+}
+
+
+
+
+VOID
+SpxFreeMemory(
+ IN PVOID pBuf
+ )
+/*++
+
+Routine Description:
+
+ Free the block of memory allocated via SpxAllocMemory. This is
+ a wrapper around ExFreePool.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PULONG pRealBuffer;
+
+ // Get a pointer to the block allocated by ExAllocatePool --
+ // we allocate a LARGE_INTEGER at the front.
+ pRealBuffer = ((PULONG)pBuf - 2);
+
+ SpxTrackMemoryUsage(pRealBuffer, FALSE, 0);
+
+#if DBG
+ // Check the signature at the end
+ if (*(PULONG)((PCHAR)pRealBuffer + *(PULONG)pRealBuffer)
+ != SPX_MEMORY_SIGNATURE)
+ {
+ DBGPRINT(RESOURCES, FATAL,
+ ("SpxFreeMemory: Memory overrun on block %lx\n", pRealBuffer));
+
+ DBGBRK(FATAL);
+ }
+
+ *(PULONG)((PCHAR)pRealBuffer + *(PULONG)pRealBuffer) = 0;
+#endif
+
+#if DBG
+ *pRealBuffer = 0;
+#endif
+
+ // Free the pool and return.
+ ExFreePool(pRealBuffer);
+}
+
+
+
+
+#ifdef TRACK_MEMORY_USAGE
+
+#define MAX_PTR_COUNT 4*1024
+#define MAX_MEM_USERS 512
+CTELock spxMemTrackLock = {0};
+CTELockHandle lockHandle = {0};
+struct
+{
+ PVOID mem_Ptr;
+ ULONG mem_FileLine;
+} spxMemPtrs[MAX_PTR_COUNT] = {0};
+
+struct
+{
+ ULONG mem_FL;
+ ULONG mem_Count;
+} spxMemUsage[MAX_MEM_USERS] = {0};
+
+VOID
+SpxTrackMemoryUsage(
+ IN PVOID pMem,
+ IN BOOLEAN Alloc,
+ IN ULONG FileLine
+ )
+/*++
+
+Routine Description:
+
+ Keep track of memory usage by storing and clearing away pointers as and
+ when they are allocated or freed. This helps in keeping track of memory
+ leaks.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ static int i = 0;
+ int j, k;
+
+ CTEGetLock (&spxMemTrackLock, &lockHandle);
+
+ if (Alloc)
+ {
+ for (j = 0; j < MAX_PTR_COUNT; i++, j++)
+ {
+ i = i & (MAX_PTR_COUNT-1);
+ if (spxMemPtrs[i].mem_Ptr == NULL)
+ {
+ spxMemPtrs[i].mem_Ptr = pMem;
+ spxMemPtrs[i++].mem_FileLine = FileLine;
+ break;
+ }
+ }
+
+ for (k = 0; k < MAX_MEM_USERS; k++)
+ {
+ if (spxMemUsage[k].mem_FL == FileLine)
+ {
+ spxMemUsage[k].mem_Count ++;
+ break;
+ }
+ }
+ if (k == MAX_MEM_USERS)
+ {
+ for (k = 0; k < MAX_MEM_USERS; k++)
+ {
+ if (spxMemUsage[k].mem_FL == 0)
+ {
+ spxMemUsage[k].mem_FL = FileLine;
+ spxMemUsage[k].mem_Count = 1;
+ break;
+ }
+ }
+ }
+ if (k == MAX_MEM_USERS)
+ {
+ DBGPRINT(RESOURCES, ERR,
+ ("SpxTrackMemoryUsage: Out of space on spxMemUsage !!!\n"));
+
+ DBGBRK(FATAL);
+ }
+ }
+ else
+ {
+ for (j = 0, k = i; j < MAX_PTR_COUNT; j++, k--)
+ {
+ k = k & (MAX_PTR_COUNT-1);
+ if (spxMemPtrs[k].mem_Ptr == pMem)
+ {
+ spxMemPtrs[k].mem_Ptr = 0;
+ spxMemPtrs[k].mem_FileLine = 0;
+ break;
+ }
+ }
+ }
+
+ CTEFreeLock (&spxMemTrackLock, lockHandle);
+
+ if (j == MAX_PTR_COUNT)
+ {
+ DBGPRINT(RESOURCES, ERR,
+ ("SpxTrackMemoryUsage: %s\n", Alloc ? "Table Full" : "Can't find"));
+
+ DBGBRK(FATAL);
+ }
+}
+
+#endif // TRACK_MEMORY_USAGE
+
+
+
+
+PVOID
+SpxBPAllocBlock(
+ IN BLKID BlockId
+ )
+/*++
+
+Routine Description:
+
+ Alloc a block of memory from the block pool package. This is written to speed up
+ operations where a lot of small fixed size allocations/frees happen. Going to
+ ExAllocPool() in these cases is expensive.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PBLK_HDR pBlk = NULL;
+ PBLK_CHUNK pChunk, *ppChunkHead;
+ USHORT BlkSize;
+ CTELockHandle lockHandle;
+ PSPX_SEND_RESD pSendResd;
+ PSPX_RECV_RESD pRecvResd;
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+ PNDIS_BUFFER pNdisIpxSpxBuffer;
+
+
+ CTEAssert (BlockId < NUM_BLKIDS);
+
+ if (BlockId < NUM_BLKIDS)
+ {
+ BlkSize = spxBlkSize[BlockId];
+ ppChunkHead = &spxBPHead[BlockId];
+
+ CTEGetLock(&spxBPLock[BlockId], &lockHandle);
+
+ for (pChunk = *ppChunkHead;
+ pChunk != NULL;
+ pChunk = pChunk->bc_Next)
+ {
+ CTEAssert(pChunk->bc_BlkId == BlockId);
+ if (pChunk->bc_NumFrees > 0)
+ {
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxBPAllocBlock: Found space in Chunk %lx\n", pChunk));
+#ifdef PROFILING
+ InterlockedIncrement( &SpxStatistics.stat_NumBPHits);
+#endif
+ break;
+ }
+ }
+
+ if (pChunk == NULL)
+ {
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxBPAllocBlock: Allocating a new chunk for Id %d\n", BlockId));
+
+#ifdef PROFILING
+ InterlockedIncrement( &SpxStatistics.stat_NumBPMisses);
+#endif
+ pChunk = SpxAllocateMemory(spxChunkSize[BlockId]);
+ if (pChunk != NULL)
+ {
+ LONG i, j;
+ PBLK_HDR pBlkHdr;
+ USHORT NumBlksPerChunk;
+
+ NumBlksPerChunk = spxNumBlks[BlockId];
+ pChunk->bc_NumFrees = NumBlksPerChunk;
+ pChunk->bc_BlkId = BlockId;
+ pChunk->bc_FreeHead = (PBLK_HDR)((PBYTE)pChunk + sizeof(BLK_CHUNK));
+
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxBPAllocBlock: Initializing chunk %lx\n", pChunk));
+
+ // Initialize the blocks in the chunk
+ for (i = 0, pBlkHdr = pChunk->bc_FreeHead;
+ i < NumBlksPerChunk;
+ i++, pBlkHdr = pBlkHdr->bh_Next)
+ {
+ NDIS_STATUS ndisStatus;
+
+ pBlkHdr->bh_Next = (PBLK_HDR)((PBYTE)pBlkHdr + BlkSize);
+ if (BlockId == BLKID_NDISSEND)
+ {
+ PBYTE pHdrMem;
+
+#ifdef SPX_OWN_PACKETS
+ // Point to the ndis packet,initialize it.
+ pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
+ NdisReinitializePacket(pNdisPkt);
+
+ // Allocate a ndis buffer descriptor describing hdr memory
+ // and queue it in.
+ pHdrMem = (PBYTE)pNdisPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD);
+
+ NdisAllocateBuffer(
+ &ndisStatus,
+ &pNdisBuffer,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ pHdrMem,
+ IpxMacHdrNeeded);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ // Link the buffer descriptor into the packet descriptor
+ NdisChainBufferAtBack(
+ pNdisPkt,
+ pNdisBuffer);
+
+
+ NdisAllocateBuffer(
+ &ndisStatus,
+ &pNdisIpxSpxBuffer,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ pHdrMem + IpxMacHdrNeeded,
+ MIN_IPXSPX2_HDRSIZE);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ // Link the buffer descriptor into the packet descriptor
+ NdisChainBufferAtBack(
+ pNdisPkt,
+ pNdisIpxSpxBuffer);
+
+
+
+ pSendResd = (PSPX_SEND_RESD)pNdisPkt->ProtocolReserved;
+
+#else
+ // Allocate a ndis packet pool for this chunk
+ NdisAllocatePacketPool();
+ etc.
+#endif
+
+
+ // Initialize elements of the protocol reserved structure.
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = SPX_SENDPKT_IDLE;
+ }
+ else if (BlockId == BLKID_NDISRECV)
+ {
+#ifdef SPX_OWN_PACKETS
+ // Point to the ndis packet,initialize it.
+ pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
+ NdisReinitializePacket(pNdisPkt);
+
+ pRecvResd = (PSPX_RECV_RESD)pNdisPkt->ProtocolReserved;
+
+#else
+ // Allocate a ndis packet pool for this chunk
+ NdisAllocatePacketPool();
+ etc.
+#endif
+
+ // Initialize elements of the protocol reserved structure.
+ pRecvResd->rr_Id = IDENTIFIER_SPX;
+ pRecvResd->rr_State = SPX_RECVPKT_IDLE;
+ }
+ }
+
+ if (i != NumBlksPerChunk)
+ {
+ // This has to be a failure from Ndis for send blocks!!!
+ // Undo a bunch of stuff
+ CTEAssert (BlockId == BLKID_NDISSEND);
+ pBlkHdr = pChunk->bc_FreeHead;
+ for (j = 0, pBlkHdr = pChunk->bc_FreeHead;
+ j < i; j++, pBlkHdr = pBlkHdr->bh_Next)
+ {
+ NdisUnchainBufferAtFront(
+ (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR)),
+ &pNdisBuffer);
+
+ CTEAssert(pNdisBuffer != NULL);
+ NdisFreeBuffer(pNdisBuffer);
+
+ NdisUnchainBufferAtFront(
+ (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR)),
+ &pNdisIpxSpxBuffer);
+
+ if (pNdisIpxSpxBuffer)
+ {
+ NdisFreeBuffer(pNdisIpxSpxBuffer);
+ }
+ }
+
+ SpxFreeMemory(pChunk);
+ pChunk = NULL;
+ }
+ else
+ {
+ // Successfully initialized the chunk, link it in
+ pChunk->bc_Next = *ppChunkHead;
+ *ppChunkHead = pChunk;
+ }
+ }
+ }
+
+ if (pChunk != NULL)
+ {
+ CTEAssert(pChunk->bc_BlkId == BlockId);
+ DBGPRINT(RESOURCES, INFO,
+ ("SpxBPAllocBlock: Allocating a block out of chunk %lx(%d) for Id %d\n",
+ pChunk, pChunk->bc_NumFrees, BlockId));
+
+ pChunk->bc_NumFrees --;
+ pChunk->bc_Age = 0; // Reset age
+ pBlk = pChunk->bc_FreeHead;
+ pChunk->bc_FreeHead = pBlk->bh_Next;
+ pBlk->bh_pChunk = pChunk;
+
+ // Skip the block header!
+ pBlk++;
+ }
+
+ CTEFreeLock(&spxBPLock[BlockId], lockHandle);
+ }
+
+ return pBlk;
+}
+
+
+
+VOID
+SpxBPFreeBlock(
+ IN PVOID pBlock,
+ IN BLKID BlockId
+ )
+/*++
+
+Routine Description:
+
+ Return a block to its owning chunk.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PBLK_CHUNK pChunk;
+ PBLK_HDR pBlkHdr = (PBLK_HDR)((PCHAR)pBlock - sizeof(BLK_HDR));
+ CTELockHandle lockHandle;
+
+ CTEGetLock(&spxBPLock[BlockId], &lockHandle);
+
+ for (pChunk = spxBPHead[BlockId];
+ pChunk != NULL;
+ pChunk = pChunk->bc_Next)
+ {
+ CTEAssert(pChunk->bc_BlkId == BlockId);
+ if (pBlkHdr->bh_pChunk == pChunk)
+ {
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxBPFreeBlock: Returning Block %lx to chunk %lx for Id %d\n",
+ pBlkHdr, pChunk, BlockId));
+
+ CTEAssert (pChunk->bc_NumFrees < spxNumBlks[BlockId]);
+ pChunk->bc_NumFrees ++;
+ pBlkHdr->bh_Next = pChunk->bc_FreeHead;
+ pChunk->bc_FreeHead = pBlkHdr;
+ break;
+ }
+ }
+ CTEAssert ((pChunk != NULL) && (pChunk->bc_FreeHead == pBlkHdr));
+
+ CTEFreeLock(&spxBPLock[BlockId], lockHandle);
+ return;
+}
+
+
+
+
+ULONG
+spxBPAgePool(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown
+ )
+/*++
+
+Routine Description:
+
+ Age out the block pool of unused blocks
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PBLK_CHUNK pChunk, *ppChunk, pFree = NULL;
+ LONG i, j, NumBlksPerChunk;
+ CTELockHandle lockHandle;
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+
+ if (TimerShuttingDown)
+ {
+ return TIMER_DONT_REQUEUE;
+ }
+
+ for (i = 0; i < NUM_BLKIDS; i++)
+ {
+ NumBlksPerChunk = spxNumBlks[i];
+ CTEGetLock(&spxBPLock[i], &lockHandle);
+
+ for (ppChunk = &spxBPHead[i];
+ (pChunk = *ppChunk) != NULL; )
+ {
+ if ((pChunk->bc_NumFrees == NumBlksPerChunk) &&
+ (++(pChunk->bc_Age) >= MAX_BLOCK_POOL_AGE))
+ {
+ DBGPRINT(SYSTEM, INFO,
+ ("spxBPAgePool: freeing Chunk %lx, Id %d\n",
+ pChunk, pChunk->bc_BlkId));
+
+ *ppChunk = pChunk->bc_Next;
+#ifdef PROFILING
+ InterlockedIncrement( &SpxStatistics.stat_NumBPAge);
+#endif
+ if (pChunk->bc_BlkId == BLKID_NDISSEND)
+ {
+ PBLK_HDR pBlkHdr;
+
+ // We need to free Ndis stuff for these guys
+ pBlkHdr = pChunk->bc_FreeHead;
+ for (j = 0, pBlkHdr = pChunk->bc_FreeHead;
+ j < NumBlksPerChunk;
+ j++, pBlkHdr = pBlkHdr->bh_Next)
+ {
+ pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
+ NdisUnchainBufferAtFront(
+ pNdisPkt,
+ &pNdisBuffer);
+
+ NdisFreeBuffer(pNdisBuffer);
+
+ NdisUnchainBufferAtFront(
+ pNdisPkt,
+ &pNdisBuffer);
+
+ NdisFreeBuffer(pNdisBuffer);
+ }
+ }
+
+ SpxFreeMemory(pChunk);
+ }
+ else
+ {
+ ppChunk = &pChunk->bc_Next;
+ }
+ }
+ CTEFreeLock(&spxBPLock[i], lockHandle);
+ }
+
+ return TIMER_REQUEUE_CUR_VALUE;
+}
diff --git a/private/ntos/tdi/isn/spx/spxpkt.c b/private/ntos/tdi/isn/spx/spxpkt.c
new file mode 100644
index 000000000..46b234020
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxpkt.c
@@ -0,0 +1,1594 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxpkt.c
+
+Abstract:
+
+ This module contains code that builds various spx packets.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+// Define module number for event logging entries
+#define FILENUM SPXPKT
+
+VOID
+SpxPktBuildCr(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_ADDR pSpxAddr,
+ IN OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fSpx2
+ )
+/*++
+
+Routine Description:
+
+ NOTE: If *ppPkt is NULL, we allocate a packet. If not, we just
+ recreate the data and don't update the packet's state.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pCrPkt;
+ PSPX_SEND_RESD pSendResd;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr;
+
+ if (*ppPkt == NULL) {
+
+ SpxAllocSendPacket(SpxDevice, &pCrPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnHandleConnReq: Could not allocate ndis packet\n"));
+ return;
+ }
+
+ } else {
+
+ pCrPkt = *ppPkt;
+ }
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pCrPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ NdisQueryPacket(pCrPkt, NULL, NULL, &pNdisMacHdr, NULL);
+ pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr);
+ if (!fSpx2)
+ {
+ NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE);
+ }
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ MIN_IPXSPX_HDRSIZE,
+ pSpxConnFile->scf_RemAddr,
+ pSpxAddr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | SPX_CC_ACK |
+ (fSpx2 ? (SPX_CC_SPX2 | SPX_CC_NEG) : 0));
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId = 0xFFFF;
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ pIpxSpxHdr->hdr_AckNum = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+
+ // Initialize
+
+ if (*ppPkt == NULL) {
+
+ pSendResd = (PSPX_SEND_RESD)(pCrPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_CR;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = State;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Len = pSendResd->sr_HdrLen = MIN_IPXSPX_HDRSIZE;
+
+ *ppPkt = pCrPkt;
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildCrAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_ADDR pSpxAddr,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fNeg,
+ IN BOOLEAN fSpx2
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pCrAckPkt;
+ PSPX_SEND_RESD pSendResd;
+ PIPXSPX_HDR pIpxSpxHdr;
+ NDIS_STATUS ndisStatus;
+ USHORT hdrLen;
+ PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr;
+
+ *ppPkt = NULL;
+
+ SpxAllocSendPacket(SpxDevice, &pCrAckPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnHandleConnReq: Could not allocate ndis packet\n"));
+ return;
+ }
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pCrAckPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ hdrLen = (SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE);
+
+ NdisQueryPacket(pCrAckPkt, NULL, NULL, &pNdisMacHdr, NULL);
+ pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr);
+ if (!SPX2_CONN(pSpxConnFile))
+ {
+ NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE);
+ }
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ hdrLen,
+ pSpxConnFile->scf_RemAddr,
+ pSpxAddr->sa_Socket);
+
+ pIpxSpxHdr->hdr_ConnCtrl =
+ (SPX_CC_SYS |
+ (fSpx2 ? SPX_CC_SPX2 : 0) |
+ (fNeg ? SPX_CC_NEG : 0));
+
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ pIpxSpxHdr->hdr_AckNum = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+
+ if (SPX2_CONN(pSpxConnFile))
+ {
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnBuildCrAck: Spx2 packet size %d.%lx\n",
+ pSpxConnFile->scf_MaxPktSize));
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+ }
+
+
+ pSendResd = (PSPX_SEND_RESD)(pCrAckPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_CRACK;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = State;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Len = pSendResd->sr_HdrLen = hdrLen;
+
+ *ppPkt = pCrAckPkt;
+ return;
+}
+
+
+
+VOID
+SpxPktBuildSn(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_BUFFER pBuf;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PBYTE pData;
+
+ do
+ {
+ *ppPkt = NULL;
+
+ // Allocate a ndis packet for the cr.
+ SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ CTEAssert(pSpxConnFile->scf_MaxPktSize != 0);
+ DBGPRINT(SEND, DBG,
+ ("SpxPktBuildSn: Data size %lx\n", pSpxConnFile->scf_MaxPktSize));
+
+ if ((pData =
+ SpxAllocateMemory(
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE)) == NULL)
+ {
+ SpxPktSendRelease(pPkt);
+ break;
+ }
+
+ // Build ndis buffer desc
+ NdisAllocateBuffer(
+ &ndisStatus,
+ &pBuf,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ pData,
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ SpxPktSendRelease(pPkt);
+ SpxFreeMemory(pData);
+ break;
+ }
+
+ // Chain at back.
+ NdisChainBufferAtBack(
+ pPkt,
+ pBuf);
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ pSpxConnFile->scf_MaxPktSize,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl = ( SPX_CC_SYS | SPX_CC_ACK |
+ SPX_CC_NEG | SPX_CC_SPX2);
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ pIpxSpxHdr->hdr_AckNum = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+
+ // Init the data part to indicate no neg values
+ *(UNALIGNED ULONG *)pData = 0;
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_SN;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = (State | SPX_SENDPKT_FREEDATA);
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE;
+ pSendResd->sr_Len = pSpxConnFile->scf_MaxPktSize;
+
+ *ppPkt = pPkt;
+
+ } while (FALSE);
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildSnAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PSPX_SEND_RESD pSendResd;
+
+ do
+ {
+ *ppPkt = NULL;
+
+ // Allocate a ndis packet for the cr.
+ SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ MIN_IPXSPX2_HDRSIZE,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2);
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ pIpxSpxHdr->hdr_AckNum = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_SNACK;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = State;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Len = pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE;
+
+ *ppPkt = pPkt;
+
+ } while (FALSE);
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildSs(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_BUFFER pBuf;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PBYTE pData;
+
+ do
+ {
+ *ppPkt = NULL;
+
+ // Allocate a ndis packet for the cr.
+ SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+
+ CTEAssert(pSpxConnFile->scf_MaxPktSize != 0);
+ DBGPRINT(SEND, DBG,
+ ("SpxPktBuildSs: Data size %lx\n", pSpxConnFile->scf_MaxPktSize));
+
+ if ((pData =
+ SpxAllocateMemory(
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE)) == NULL)
+ {
+ SpxPktSendRelease(pPkt);
+ break;
+ }
+
+ // Build ndis buffer desc
+ NdisAllocateBuffer(
+ &ndisStatus,
+ &pBuf,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ pData,
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ SpxPktSendRelease(pPkt);
+ SpxFreeMemory(pData);
+ break;
+ }
+
+ // Chain at back.
+ NdisChainBufferAtBack(
+ pPkt,
+ pBuf);
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ pSpxConnFile->scf_MaxPktSize,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl =
+ (SPX_CC_SYS | SPX_CC_ACK | SPX_CC_SPX2 |
+ ((pSpxConnFile->scf_Flags & SPX_CONNFILE_NEG) ? SPX_CC_NEG : 0));
+
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ pIpxSpxHdr->hdr_AckNum = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+
+ // Init the data part to indicate no neg values
+ *(UNALIGNED ULONG *)pData = 0;
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_SS;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = (State | SPX_SENDPKT_FREEDATA);
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE;
+ pSendResd->sr_Len = pSpxConnFile->scf_MaxPktSize;
+
+ *ppPkt = pPkt;
+ } while (FALSE);
+
+ return;
+}
+
+
+
+VOID
+SpxPktBuildSsAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PSPX_SEND_RESD pSendResd;
+
+ do
+ {
+ *ppPkt = NULL;
+
+ // Allocate a ndis packet for the cr.
+ SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ MIN_IPXSPX2_HDRSIZE,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl =
+ (SPX_CC_SYS | SPX_CC_SPX2 |
+ ((pSpxConnFile->scf_Flags & SPX_CONNFILE_NEG) ? SPX_CC_NEG : 0));
+
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ pIpxSpxHdr->hdr_AckNum = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_SSACK;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = State;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Len = pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE;
+
+ *ppPkt = pPkt;
+
+ } while (FALSE);
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildRr(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT SeqNum,
+ IN USHORT State
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_BUFFER pBuf;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PBYTE pData;
+
+ do
+ {
+ *ppPkt = NULL;
+
+ // Allocate a ndis packet for the cr.
+ SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ if ((pData =
+ SpxAllocateMemory(
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE)) == NULL)
+ {
+ SpxPktSendRelease(pPkt);
+ break;
+ }
+
+ // Build ndis buffer desc
+ NdisAllocateBuffer(
+ &ndisStatus,
+ &pBuf,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ pData,
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ SpxPktSendRelease(pPkt);
+ SpxFreeMemory(pData);
+ break;
+ }
+
+ // Chain at back.
+ NdisChainBufferAtBack(
+ pPkt,
+ pBuf);
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ pSpxConnFile->scf_MaxPktSize,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl = ( SPX_CC_SYS | SPX_CC_ACK |
+ SPX_CC_NEG | SPX_CC_SPX2);
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+
+ // For a renegotiate request, we use the sequence number of
+ // the first waiting data packet. Passed in.
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SeqNum,
+ SeqNum);
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AckNum,
+ pSpxConnFile->scf_RecvSeqNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+
+ // Init the data part to indicate no neg values
+ *(UNALIGNED ULONG *)pData = 0;
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_RR;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = (State | SPX_SENDPKT_FREEDATA);
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_SeqNum = SeqNum;
+ pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE;
+ pSendResd->sr_Len = pSpxConnFile->scf_MaxPktSize;
+
+ *ppPkt = pPkt;
+
+ } while (FALSE);
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildRrAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN USHORT MaxPktSize
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PSPX_SEND_RESD pSendResd;
+
+ do
+ {
+ *ppPkt = NULL;
+
+ // Allocate a ndis packet for the cr.
+ SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ MIN_IPXSPX2_HDRSIZE,
+ pSpxConnFile->scf_RemAckAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2);
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SeqNum,
+ pSpxConnFile->scf_SendSeqNum);
+
+ // For the RrAck, ack number will be the appropriate number
+ // for the last data packet received.
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AckNum,
+ pSpxConnFile->scf_RenegAckAckNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ MaxPktSize);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxPktBuildRrAck: SEQ %lx ACKNUM %lx ALLOCNUM %lx MAXPKT %lx\n",
+ pSpxConnFile->scf_SendSeqNum,
+ pSpxConnFile->scf_RenegAckAckNum,
+ pSpxConnFile->scf_SentAllocNum,
+ MaxPktSize));
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_RRACK;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = State;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Len = pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE;
+
+ *ppPkt = pPkt;
+
+ } while (FALSE);
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildDisc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PREQUEST pRequest,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN UCHAR DataType
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pDiscPkt;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ USHORT hdrLen;
+ PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr;
+
+
+ *ppPkt = NULL;
+
+ SpxAllocSendPacket(SpxDevice, &pDiscPkt, &ndisStatus);
+ if (ndisStatus == NDIS_STATUS_SUCCESS)
+ {
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pDiscPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ hdrLen = SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE;
+ NdisQueryPacket(pDiscPkt, NULL, NULL, &pNdisMacHdr, NULL);
+ pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr);
+ if (!SPX2_CONN(pSpxConnFile))
+ {
+ NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE);
+ }
+
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ hdrLen,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl =
+ (SPX_CC_ACK |
+ (SPX2_CONN(pSpxConnFile) ? SPX_CC_SPX2 : 0) |
+ ((DataType == SPX2_DT_IDISC) ? 0 : SPX_CC_EOM));
+
+ pIpxSpxHdr->hdr_DataType = DataType;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId =
+ *((UNALIGNED USHORT *)&pSpxConnFile->scf_RemConnId);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SeqNum,
+ pSpxConnFile->scf_SendSeqNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AckNum,
+ pSpxConnFile->scf_RecvSeqNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+
+ if (SPX2_CONN(pSpxConnFile))
+ {
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+ }
+
+ pSendResd = (PSPX_SEND_RESD)(pDiscPkt->ProtocolReserved);
+
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_State = State;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_Type =
+ ((DataType == SPX2_DT_IDISC) ? SPX_TYPE_IDISC : SPX_TYPE_ORDREL);
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Request = pRequest;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Offset = 0;
+ pSendResd->sr_SeqNum = pSpxConnFile->scf_SendSeqNum;
+ pSendResd->sr_Len =
+ pSendResd->sr_HdrLen = hdrLen;
+
+ *ppPkt = pDiscPkt;
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildProbe(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fSpx2
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pProbe;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ USHORT hdrLen;
+ PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr;
+
+
+ *ppPkt = NULL;
+
+ SpxAllocSendPacket(SpxDevice, &pProbe, &ndisStatus);
+ if (ndisStatus == NDIS_STATUS_SUCCESS)
+ {
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pProbe +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ hdrLen = (fSpx2 ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE);
+
+ NdisQueryPacket(pProbe, NULL, NULL, &pNdisMacHdr, NULL);
+ pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr);
+ if (!fSpx2)
+ {
+ NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE);
+ }
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ hdrLen,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | SPX_CC_ACK |
+ (fSpx2 ? SPX_CC_SPX2 : 0));
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId =
+ *((UNALIGNED USHORT *)&pSpxConnFile->scf_RemConnId);
+
+ if (fSpx2)
+ {
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+ }
+ else
+ {
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SeqNum,
+ pSpxConnFile->scf_SendSeqNum);
+ }
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AckNum,
+ pSpxConnFile->scf_RecvSeqNum);
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+
+ pSendResd = (PSPX_SEND_RESD)(pProbe->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_PROBE;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = State;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Len =
+ pSendResd->sr_HdrLen = (fSpx2 ? MIN_IPXSPX2_HDRSIZE
+ : MIN_IPXSPX_HDRSIZE);
+
+ *ppPkt = pProbe;
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildData(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN USHORT Length
+ )
+/*++
+
+Routine Description:
+
+ Handles zero length sends.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_BUFFER pNdisBuffer;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pDataPkt;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ USHORT hdrLen;
+ PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr;
+
+ *ppPkt = NULL;
+
+ SpxAllocSendPacket(SpxDevice, &pDataPkt, &ndisStatus);
+ if (ndisStatus == NDIS_STATUS_SUCCESS)
+ {
+ // Make a ndis buffer descriptor for the data if present.
+ if (Length > 0)
+ {
+ SpxCopyBufferChain(
+ &ndisStatus,
+ &pNdisBuffer,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ REQUEST_TDI_BUFFER(pSpxConnFile->scf_ReqPkt),
+ pSpxConnFile->scf_ReqPktOffset,
+ Length);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ // Free the send packet
+ SpxPktSendRelease(pDataPkt);
+ return;
+ }
+
+ // Chain this in the packet
+ NdisChainBufferAtBack(pDataPkt, pNdisBuffer);
+ }
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pDataPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ hdrLen = SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE;
+ Length += hdrLen;
+
+ NdisQueryPacket(pDataPkt, NULL, NULL, &pNdisMacHdr, NULL);
+ pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr);
+ if (!SPX2_CONN(pSpxConnFile))
+ {
+ NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE);
+ }
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ Length,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl =
+ (((State & SPX_SENDPKT_ACKREQ) ? SPX_CC_ACK : 0) |
+ ((State & SPX_SENDPKT_EOM) ? SPX_CC_EOM : 0) |
+ (SPX2_CONN(pSpxConnFile) ? SPX_CC_SPX2 : 0));
+
+ pIpxSpxHdr->hdr_DataType = pSpxConnFile->scf_DataType;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId =
+ *((UNALIGNED USHORT *)&pSpxConnFile->scf_RemConnId);
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SeqNum,
+ pSpxConnFile->scf_SendSeqNum);
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AckNum,
+ pSpxConnFile->scf_RecvSeqNum);
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+
+ if (SPX2_CONN(pSpxConnFile))
+ {
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+ }
+
+ pSendResd = (PSPX_SEND_RESD)(pDataPkt->ProtocolReserved);
+
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_State = State;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_Type = SPX_TYPE_DATA;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Request = pSpxConnFile->scf_ReqPkt;
+ pSendResd->sr_Offset = pSpxConnFile->scf_ReqPktOffset;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_SeqNum = pSpxConnFile->scf_SendSeqNum;
+ pSendResd->sr_Len = Length;
+ pSendResd->sr_HdrLen = hdrLen;
+
+ if (State & SPX_SENDPKT_ACKREQ)
+ {
+ KeQuerySystemTime((PLARGE_INTEGER)&pSendResd->sr_SentTime);
+ }
+
+ CTEAssert(pSendResd->sr_Len <= pSpxConnFile->scf_MaxPktSize);
+ *ppPkt = pDataPkt;
+
+ // Ok, allocation succeeded. Increment send seq.
+ pSpxConnFile->scf_SendSeqNum++;
+ }
+
+ return;
+}
+
+
+VOID
+SpxCopyBufferChain(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_BUFFER * TargetChain,
+ IN NDIS_HANDLE PoolHandle,
+ IN PNDIS_BUFFER SourceChain,
+ IN UINT Offset,
+ IN UINT Length
+ )
+/*++
+
+Routine Description:
+
+ Creates a TargetBufferChain from the SourceBufferChain. The copy begins at
+ the 'Offset' location in the source chain. It copies 'Length' bytes. It also
+ handles Length = 0. If we run out of source chain before copying length amount
+ of bytes or run out of memory to create any more buffers for the target chain,
+ we clean up the partial chain created so far.
+
+Arguments:
+
+ Status - Status of the request.
+ TargetChain - Pointer to the allocated buffer descriptor.
+ PoolHandle - Handle that is used to specify the pool.
+ SourceChain - Pointer to the descriptor of the source memory.
+ Offset - The Offset in the sources memory from which the copy is to
+ begin
+ Length - Number of Bytes to copy.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UINT BytesBeforeCurBuffer = 0;
+ PNDIS_BUFFER CurBuffer = SourceChain;
+ UINT BytesLeft;
+ UINT AvailableBytes;
+ PNDIS_BUFFER NewNdisBuffer, StartTargetChain;
+
+ CTEAssert( SourceChain );
+
+ // First of all find the source buffer that contains data that starts at
+ // Offset.
+ NdisQueryBuffer( CurBuffer, NULL, &AvailableBytes );
+ while ( BytesBeforeCurBuffer + AvailableBytes <= Offset ) {
+ BytesBeforeCurBuffer += AvailableBytes;
+ CurBuffer = CurBuffer->Next;
+ if ( CurBuffer ) {
+ NdisQueryBuffer( CurBuffer, NULL, &AvailableBytes );
+ } else {
+ break;
+ }
+ }
+
+ if ( ! CurBuffer ) {
+ *Status = STATUS_UNSUCCESSFUL;
+ return;
+ }
+
+ //
+ // Copy the first buffer. This takes care of Length = 0.
+ //
+ BytesLeft = Length;
+
+ //
+ // ( Offset - BytesBeforeCurBuffer ) gives us the offset within this buffer.
+ //
+
+ AvailableBytes -= ( Offset - BytesBeforeCurBuffer );
+
+ if ( AvailableBytes > BytesLeft ) {
+ AvailableBytes = BytesLeft;
+ }
+
+ NdisCopyBuffer(
+ Status,
+ &NewNdisBuffer,
+ PoolHandle,
+ CurBuffer,
+ Offset - BytesBeforeCurBuffer,
+ AvailableBytes);
+
+ if ( *Status != NDIS_STATUS_SUCCESS ) {
+ return;
+ }
+
+ StartTargetChain = NewNdisBuffer;
+ BytesLeft -= AvailableBytes;
+
+ //
+ // Did the first buffer have enough data. If so, we r done.
+ //
+ if ( ! BytesLeft ) {
+ *TargetChain = StartTargetChain;
+ return;
+ }
+
+ //
+ // Now follow the Mdl chain and copy more buffers.
+ //
+ CurBuffer = CurBuffer->Next;
+ NdisQueryBuffer( CurBuffer, NULL, &AvailableBytes );
+ while ( CurBuffer ) {
+
+ if ( AvailableBytes > BytesLeft ) {
+ AvailableBytes = BytesLeft;
+ }
+
+ NdisCopyBuffer(
+ Status,
+ &(NDIS_BUFFER_LINKAGE(NewNdisBuffer)),
+ PoolHandle,
+ CurBuffer,
+ 0,
+ AvailableBytes);
+
+ if ( *Status != NDIS_STATUS_SUCCESS ) {
+
+ //
+ // ran out of resources. put back what we've used in this call and
+ // return the error.
+ //
+
+ while ( StartTargetChain != NULL) {
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE( StartTargetChain );
+ NdisFreeBuffer ( StartTargetChain );
+ StartTargetChain = NewNdisBuffer;
+ }
+
+ return;
+ }
+
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE(NewNdisBuffer);
+ BytesLeft -= AvailableBytes;
+
+ if ( ! BytesLeft ) {
+ *TargetChain = StartTargetChain;
+ return;
+ }
+
+ CurBuffer = CurBuffer->Next;
+ NdisQueryBuffer( CurBuffer, NULL, &AvailableBytes );
+ }
+
+ //
+ // Ran out of source chain. This should not happen.
+ //
+
+ CTEAssert( FALSE );
+
+ // For Retail build we clean up anyways.
+
+ while ( StartTargetChain != NULL) {
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE( StartTargetChain );
+ NdisFreeBuffer ( StartTargetChain );
+ StartTargetChain = NewNdisBuffer;
+ }
+
+ *Status = STATUS_UNSUCCESSFUL;
+ return;
+}
+
+
+VOID
+SpxPktBuildAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fBuildNack,
+ IN USHORT NumToResend
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ PIPXSPX_HDR pIpxSpxHdr;
+ NDIS_STATUS ndisStatus;
+ USHORT hdrLen;
+ PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr;
+
+ BOOLEAN fSpx2 = SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2);
+
+ *ppPkt = NULL;
+
+ SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ DBGPRINT(SEND, ERR,
+ ("SpxPktBuildAck: Could not allocate ndis packet\n"));
+ return;
+ }
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ hdrLen = SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE;
+ NdisQueryPacket(pPkt, NULL, NULL, &pNdisMacHdr, NULL);
+ pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr);
+ if (!fSpx2)
+ {
+ NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE);
+ }
+
+ // Send where data came from
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ hdrLen,
+ pSpxConnFile->scf_RemAckAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | (fSpx2 ? SPX_CC_SPX2 : 0));
+
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AckNum,
+ pSpxConnFile->scf_RecvSeqNum);
+
+ if (fSpx2)
+ {
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ if (fBuildNack)
+ {
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SeqNum,
+ NumToResend);
+ }
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+ }
+ else
+ {
+ // Put current send seq number in packet for spx1
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SeqNum,
+ pSpxConnFile->scf_SendSeqNum);
+ }
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = (fBuildNack ? SPX_TYPE_DATANACK : SPX_TYPE_DATAACK);
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = State;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Len = pSendResd->sr_HdrLen = hdrLen;
+
+ *ppPkt = pPkt;
+ return;
+}
+
+
+
+VOID
+SpxPktRecvRelease(
+ IN PNDIS_PACKET pPkt
+ )
+{
+ ((PSPX_RECV_RESD)(pPkt->ProtocolReserved))->rr_State = SPX_RECVPKT_IDLE;
+ SpxFreeRecvPacket(SpxDevice, pPkt);
+ return;
+}
+
+
+
+
+VOID
+SpxPktSendRelease(
+ IN PNDIS_PACKET pPkt
+ )
+{
+ PNDIS_BUFFER pBuf, pIpxSpxBuf, pFreeBuf;
+ UINT bufCount;
+
+ CTEAssert((((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_State &
+ SPX_SENDPKT_IPXOWNS) == 0);
+
+ NdisQueryPacket(pPkt, NULL, &bufCount, &pBuf, NULL);
+
+ // BufCount == 1 for only the header. That's ok, we just reset the length
+ // and free the packet to the buffer pools. Else we need to free user buffers
+ // before that.
+
+ NdisUnchainBufferAtFront(
+ pPkt,
+ &pBuf);
+
+ NdisUnchainBufferAtFront(
+ pPkt,
+ &pIpxSpxBuf);
+
+ //
+ // Set the header length to the max. that can be needed.
+ //
+ NdisAdjustBufferLength(pIpxSpxBuf, MIN_IPXSPX2_HDRSIZE);
+
+ while (bufCount-- > 2)
+ {
+ PBYTE pData;
+ ULONG dataLen;
+
+ NdisUnchainBufferAtBack(
+ pPkt,
+ &pFreeBuf);
+
+ // See if we free data associated with the buffer
+ if ((((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_State &
+ SPX_SENDPKT_FREEDATA) != 0)
+ {
+ NdisQueryBuffer(pFreeBuf, &pData, &dataLen);
+ CTEAssert(pData != NULL);
+ SpxFreeMemory(pData);
+ }
+
+ CTEAssert(pFreeBuf != NULL);
+ NdisFreeBuffer(pFreeBuf);
+ }
+
+ NdisReinitializePacket(pPkt);
+
+ // Initialize elements of the protocol reserved structure.
+ ((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_Id = IDENTIFIER_SPX;
+ ((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_State = SPX_SENDPKT_IDLE;
+ ((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_Reserved1= NULL;
+ ((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_Reserved2= NULL;
+
+ NdisChainBufferAtFront(
+ pPkt,
+ pBuf);
+
+ NdisChainBufferAtBack(
+ pPkt,
+ pIpxSpxBuf);
+
+ SpxFreeSendPacket(SpxDevice, pPkt);
+ return;
+}
diff --git a/private/ntos/tdi/isn/spx/spxquery.c b/private/ntos/tdi/isn/spx/spxquery.c
new file mode 100644
index 000000000..047ecabe8
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxquery.c
@@ -0,0 +1,259 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxquery.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiQueryInformation
+
+Author:
+
+ Adam Barr (adamba) Initial Version
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Discardable code after Init time
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT, SpxQueryInitProviderInfo)
+#endif
+
+// Define module number for event logging entries
+#define FILENUM SPXQUERY
+
+// Useful macro to obtain the total length of an MDL chain.
+#define SpxGetMdlChainLength(Mdl, Length) { \
+ PMDL _Mdl = (Mdl); \
+ *(Length) = 0; \
+ while (_Mdl) { \
+ *(Length) += MmGetMdlByteCount(_Mdl); \
+ _Mdl = _Mdl->Next; \
+ } \
+}
+
+
+
+VOID
+SpxQueryInitProviderInfo(
+ PTDI_PROVIDER_INFO ProviderInfo
+ )
+{
+ // Initialize to defaults first
+ RtlZeroMemory((PVOID)ProviderInfo, sizeof(TDI_PROVIDER_INFO));
+
+ ProviderInfo->Version = SPX_TDI_PROVIDERINFO_VERSION;
+ KeQuerySystemTime (&ProviderInfo->StartTime);
+ ProviderInfo->MinimumLookaheadData = SPX_PINFOMINMAXLOOKAHEAD;
+ ProviderInfo->MaximumLookaheadData = IpxLineInfo.MaximumPacketSize;
+ ProviderInfo->MaxSendSize = SPX_PINFOSENDSIZE;
+ ProviderInfo->ServiceFlags = SPX_PINFOSERVICEFLAGS;
+ return;
+}
+
+
+
+
+NTSTATUS
+SpxTdiQueryInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiQueryInformation request for the transport
+ provider.
+
+Arguments:
+
+ Request - the request for the operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PSPX_ADDR_FILE AddressFile;
+ PSPX_CONN_FILE ConnectionFile;
+ PTDI_REQUEST_KERNEL_QUERY_INFORMATION query;
+ struct {
+ ULONG ActivityCount;
+ TA_IPX_ADDRESS SpxAddress;
+ } AddressInfo;
+
+
+
+ // what type of status do we want?
+ query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)REQUEST_PARAMETERS(Request);
+
+ switch (query->QueryType)
+ {
+ case TDI_QUERY_CONNECTION_INFO:
+
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ case TDI_QUERY_ADDRESS_INFO:
+
+ // The caller wants the exact address value.
+
+ ConnectionFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(Request);
+ status = SpxConnFileVerify(ConnectionFile);
+
+ if (status == STATUS_SUCCESS) {
+ AddressFile = ConnectionFile->scf_AddrFile;
+ SpxConnFileDereference(ConnectionFile, CFREF_VERIFY);
+ } else {
+ AddressFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(Request);
+ }
+
+ status = SpxAddrFileVerify(AddressFile);
+
+ if (status == STATUS_SUCCESS)
+ {
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxTdiQuery: Net.Socket %lx.%lx\n",
+ *(PULONG)Device->dev_Network,
+ AddressFile->saf_Addr->sa_Socket));
+
+ AddressInfo.ActivityCount = 0;
+ (VOID)SpxBuildTdiAddress(
+ &AddressInfo.SpxAddress,
+ sizeof(TA_IPX_ADDRESS),
+ Device->dev_Network,
+ Device->dev_Node,
+ AddressFile->saf_Addr->sa_Socket);
+
+ status = TdiCopyBufferToMdl(
+ &AddressInfo,
+ 0,
+ sizeof(AddressInfo),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ SpxAddrFileDereference(AddressFile, AFREF_VERIFY);
+
+ }
+
+ break;
+
+ case TDI_QUERY_PROVIDER_INFO: {
+ BYTE socketType;
+ TDI_PROVIDER_INFO providerInfo = Device->dev_ProviderInfo;
+
+ //
+ // The device name extension comes down in the Irp
+ //
+ if (!NT_SUCCESS(status = SpxUtilGetSocketType(
+ REQUEST_OPEN_NAME(Request),
+ &socketType))) {
+ DBGPRINT(RECEIVE, ERR, ("TDI_QUERY_PROVIDER_INFO: SpxUtilGetSocketType failed: %lx\n", status));
+ return(status);
+ }
+
+ //
+ // The Catapult folks had a problem where AFD was discarding buffered sends on the NT box when it got a
+ // local disconnect on SPX1. This was because the Orderly release flag was always set in the provider
+ // info. AFD queries this once per device type. We detect the device above and OR in the orderly release
+ // flag if this query came down on an SPX2 endpoint.
+ // This is to make sure that AFD follows the correct disconnect semantics for SPX1 and SPX2 (SPX1 does
+ // only abortive; SPX2 does both abortive and orderly).
+ //
+ // BUGBUG: this will still not solve the problem completely since a connection that starts off as an SPX2
+ // one can still be negotiated to SPX1 if the remote supports only SPX1.
+ //
+ if ((socketType == SOCKET2_TYPE_SEQPKT) ||
+ (socketType == SOCKET2_TYPE_STREAM)) {
+
+ DBGPRINT(RECEIVE, INFO, ("TDI_QUERY_PROVIDER_INFO: SPX2 socket\n"));
+ providerInfo.ServiceFlags |= TDI_SERVICE_ORDERLY_RELEASE;
+ } else {
+ DBGPRINT(RECEIVE, INFO, ("TDI_QUERY_PROVIDER_INFO: SPX1 socket\n"));
+ }
+
+ status = TdiCopyBufferToMdl (
+ &providerInfo,
+ 0,
+ sizeof (TDI_PROVIDER_INFO),
+ REQUEST_TDI_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+ }
+
+ case TDI_QUERY_PROVIDER_STATISTICS:
+
+ status = TdiCopyBufferToMdl (
+ &Device->dev_Stat,
+ 0,
+ FIELD_OFFSET (TDI_PROVIDER_STATISTICS, ResourceStats[0]),
+ REQUEST_TDI_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ default:
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ return status;
+
+} // SpxTdiQueryInformation
+
+
+
+NTSTATUS
+SpxTdiSetInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetInformation request for the transport
+ provider.
+
+Arguments:
+
+ Device - the device.
+
+ Request - the request for the operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (Device);
+ UNREFERENCED_PARAMETER (Request);
+
+ return STATUS_NOT_IMPLEMENTED;
+
+} // SpxTdiSetInformation
+
diff --git a/private/ntos/tdi/isn/spx/spxrecv.c b/private/ntos/tdi/isn/spx/spxrecv.c
new file mode 100644
index 000000000..9dc8b6fe3
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxrecv.c
@@ -0,0 +1,2839 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxrecv.c
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 5-July-1995
+ Bug fixes - tagged [SA]
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXRECV
+
+BOOLEAN
+SpxReceive(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN ULONG FwdAdapterCtx,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize,
+ IN PMDL pMdl
+ )
+
+{
+ PIPXSPX_HDR pHdr;
+
+ // We have a separate routine to process SYS packets. DATA packets are
+ // processed within this routine.
+ if (LookaheadBufferSize < MIN_IPXSPX_HDRSIZE)
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxReceive: Invalid length %lx\n", LookaheadBufferSize));
+
+ return FALSE;
+ }
+
+ ++SpxDevice->dev_Stat.PacketsReceived;
+
+ pHdr = (PIPXSPX_HDR)LookaheadBuffer;
+ if ((pHdr->hdr_ConnCtrl & SPX_CC_SYS) == 0)
+ {
+ // Check for data packets
+ if ((pHdr->hdr_DataType != SPX2_DT_ORDREL) &&
+ (pHdr->hdr_DataType != SPX2_DT_IDISC) &&
+ (pHdr->hdr_DataType != SPX2_DT_IDISC_ACK))
+ {
+ // HANDLE DATA PACKET
+ SpxRecvDataPacket(
+ MacBindingHandle,
+ MacReceiveContext,
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ LookaheadBufferOffset,
+ PacketSize);
+ }
+ else
+ {
+ // The whole packet better be in the lookahead, else we ignore.
+ if (LookaheadBufferSize == PacketSize)
+ {
+ SpxRecvDiscPacket(
+ LookaheadBuffer,
+ RemoteAddress,
+ LookaheadBufferSize);
+ }
+ }
+ }
+ else
+ {
+ SpxRecvSysPacket(
+ MacBindingHandle,
+ MacReceiveContext,
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ LookaheadBufferOffset,
+ PacketSize);
+ }
+
+ return FALSE;
+}
+
+
+
+
+VOID
+SpxTransferDataComplete(
+ IN PNDIS_PACKET pNdisPkt,
+ IN NDIS_STATUS NdisStatus,
+ IN UINT BytesTransferred
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pSpxConnFile;
+ PREQUEST pRequest;
+ PSPX_RECV_RESD pRecvResd;
+ CTELockHandle lockHandle;
+ NTSTATUS status;
+ BOOLEAN fAck, fEom, fBuffered, fImmedAck, fLockHeld;
+ PNDIS_BUFFER pNdisBuffer;
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxTransferData: For %lx with status %lx\n", pNdisPkt, NdisStatus));
+
+ pRecvResd = RECV_RESD(pNdisPkt);
+ pSpxConnFile = pRecvResd->rr_ConnFile;
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ fLockHeld = TRUE;
+
+ fEom = ((pRecvResd->rr_State & SPX_RECVPKT_EOM) != 0);
+ fImmedAck = ((pRecvResd->rr_State & SPX_RECVPKT_IMMEDACK) != 0);
+ fBuffered = ((pRecvResd->rr_State & SPX_RECVPKT_BUFFERING) != 0);
+ fAck = ((pRecvResd->rr_State & SPX_RECVPKT_SENDACK) != 0);
+
+ // Check if receive is done. If we remove the reference for this
+ // packet and it goes to zero, that means the receive was aborted.
+ // Move to the completion queue.
+ // If receive is filled up, then remove the creation reference
+ // i.e. just complete the receive at this point.
+ // There can be only one packet per receive, we dont support
+ // out of order reception.
+
+ if (!fBuffered)
+ {
+ // Get pointer to the buffer descriptor and its memory.
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ CTEAssert((pNdisBuffer != NULL) || (BytesTransferred == 0));
+
+ // BUG #11772
+ // On MP-machines scf_CurRecvReq could be set to NULL. Get the req
+ // from the recv packet.
+ // pRequest = pSpxConnFile->scf_CurRecvReq;
+ // CTEAssert(pRequest == pRecvResd->rr_Request);
+ pRequest = pRecvResd->rr_Request;
+
+ // Remove reference for this packet.
+ --(REQUEST_INFORMATION(pRequest));
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS)
+ {
+ pSpxConnFile->scf_CurRecvOffset += BytesTransferred;
+ pSpxConnFile->scf_CurRecvSize -= BytesTransferred;
+
+#if DBG
+ if ((pRecvResd->rr_State & SPX_RECVPKT_INDICATED) != 0)
+ {
+ if (BytesTransferred != 0)
+ {
+ CTEAssert (pSpxConnFile->scf_IndBytes != 0);
+ pSpxConnFile->scf_IndBytes -= BytesTransferred;
+ }
+ }
+#endif
+
+ if (REQUEST_INFORMATION(pRequest) == 0)
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxTransferDataComplete: Request %lx ref %lx Cur %lx.%lx\n",
+ pRequest, REQUEST_INFORMATION(pRequest),
+ REQUEST_STATUS(pRequest),
+ pSpxConnFile->scf_CurRecvSize));
+
+ if (SPX_CONN_STREAM(pSpxConnFile) ||
+ (pSpxConnFile->scf_CurRecvSize == 0) ||
+ fEom ||
+ ((REQUEST_STATUS(pRequest) != STATUS_SUCCESS) &&
+ (REQUEST_STATUS(pRequest) != STATUS_RECEIVE_PARTIAL)))
+ {
+ CTELockHandle lockHandleInter;
+
+ // We are done with this receive.
+ REQUEST_INFORMATION(pRequest) = pSpxConnFile->scf_CurRecvOffset;
+
+ status = STATUS_SUCCESS;
+ if (!SPX_CONN_STREAM(pSpxConnFile) &&
+ (pSpxConnFile->scf_CurRecvSize == 0) &&
+ !fEom)
+ {
+ status = STATUS_RECEIVE_PARTIAL;
+ }
+
+ if ((REQUEST_STATUS(pRequest) != STATUS_SUCCESS) &&
+ (REQUEST_STATUS(pRequest) != STATUS_RECEIVE_PARTIAL))
+ {
+ status = REQUEST_STATUS(pRequest);
+ }
+
+ REQUEST_STATUS(pRequest) = status;
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxTransferDataComplete: Request %lx ref %lx Cur %lx.%lx\n",
+ pRequest, REQUEST_INFORMATION(pRequest),
+ REQUEST_STATUS(pRequest),
+ pSpxConnFile->scf_CurRecvSize));
+
+ // Dequeue this request, Set next recv if one exists.
+ SPX_CONN_SETNEXT_CUR_RECV(pSpxConnFile, pRequest);
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_RecvDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ }
+ }
+
+ if (pNdisBuffer != NULL)
+ {
+ NdisFreeBuffer(pNdisBuffer);
+ }
+ }
+ else
+ {
+ // Buffered receive, queue it in if successful.
+ // BUG #18363
+ // IF WE DISCONNECTED in the meantime, we need to just dump this
+ // packet.
+ if (SPX_CONN_ACTIVE(pSpxConnFile) &&
+ (NdisStatus == NDIS_STATUS_SUCCESS))
+ {
+ // Queue packet in connection. Reference connection for this.
+ SpxConnQueueRecvPktTail(pSpxConnFile, pNdisPkt);
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxTransferData: Buffering: %lx Pkt %lx Size %lx F %lx\n",
+ pSpxConnFile, pNdisPkt, BytesTransferred, pRecvResd->rr_State));
+
+ // There could either be queued receives. (This could happen in
+ // a partial receive case. Or if a receive got queued in while we
+ // were processing this packet (Possible on MP)), or a packet was
+ // buffered while we were completing some receives
+
+ CTEAssert(pSpxConnFile->scf_RecvListHead);
+
+ if ((pSpxConnFile->scf_CurRecvReq != NULL) ||
+ ((pSpxConnFile->scf_RecvListHead->rr_State &
+ SPX_RECVPKT_INDICATED) == 0))
+ {
+ CTELockHandle interLockHandle;
+
+ // Push this connection into a ProcessRecv queue which will be
+ // dealt with in receive completion.
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxRecvTransferData: Queueing for recvp %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_Flags));
+
+ // Get the global q lock, push into recv list.
+ CTEGetLock(&SpxGlobalQInterlock, &interLockHandle);
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, interLockHandle);
+ }
+ }
+ else
+ {
+ PBYTE pData;
+ ULONG dataLen;
+
+ // Get pointer to the buffer descriptor and its memory.
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ if (pNdisBuffer != NULL)
+ {
+ NdisQueryBuffer(pNdisBuffer, &pData, &dataLen);
+ CTEAssert(pData != NULL);
+ CTEAssert(dataLen >= 0);
+
+ // Free the data, ndis buffer.
+ if (pNdisBuffer != NULL)
+ {
+ NdisFreeBuffer(pNdisBuffer);
+ }
+ SpxFreeMemory(pData);
+ }
+
+ // Dont send ack, set status to be failure so we free packet/buffer.
+ fAck = FALSE;
+ NdisStatus = NDIS_STATUS_FAILURE;
+ }
+ }
+
+ END_PROCESS_PACKET(
+ pSpxConnFile, fBuffered, (NdisStatus == NDIS_STATUS_SUCCESS));
+
+ if (fAck)
+ {
+ // Rem ack addr should have been copied in receive.
+
+ // #17564
+ if (fImmedAck ||
+ SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_NOACKWAIT) ||
+ SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IMMED_ACK))
+ {
+ SpxConnSendAck(pSpxConnFile, lockHandle);
+ fLockHeld = FALSE;
+ }
+ else
+ {
+ SpxConnQWaitAck(pSpxConnFile);
+ }
+ }
+
+ if (fLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ if (!fBuffered || (NdisStatus != STATUS_SUCCESS))
+ {
+ // Free the ndis packet/buffer
+ SpxPktRecvRelease(pNdisPkt);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxReceiveComplete(
+ IN USHORT NicId
+ )
+
+{
+ CTELockHandle lockHandleInter, lockHandle;
+ PREQUEST pRequest;
+ BOOLEAN fConnLockHeld, fInterlockHeld;
+ PSPX_CONN_FILE pSpxConnFile;
+ int numDerefs = 0;
+
+ // See if any connections need recv processing. This will also take
+ // care of any acks opening up window so our sends go to the max.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ fInterlockHeld = TRUE;
+
+ while ((pSpxConnFile = SpxRecvConnList.pcl_Head) != NULL)
+ {
+ // Reset for each connection
+ numDerefs = 0;
+
+ if ((SpxRecvConnList.pcl_Head = pSpxConnFile->scf_ProcessRecvNext) == NULL)
+ SpxRecvConnList.pcl_Tail = NULL;
+
+ // Reset next field to NULL
+ pSpxConnFile->scf_ProcessRecvNext = NULL;
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnRemoveFromRecv: %lx\n", pSpxConnFile));
+
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+
+ do
+ {
+ // Complete pending requests.
+ while (!IsListEmpty(&pSpxConnFile->scf_ReqDoneLinkage))
+ {
+ pRequest =
+ LIST_ENTRY_TO_REQUEST(pSpxConnFile->scf_ReqDoneLinkage.Flink);
+
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ DBGPRINT(TDI, DBG,
+ ("SpxReceiveComplete: Completing %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ CTEAssert (REQUEST_MINOR_FUNCTION(pRequest) != TDI_RECEIVE);
+ SpxCompleteRequest(pRequest);
+ numDerefs++;
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ }
+
+ // Call process pkts if we have any packets or if any receives to
+ // complete. Note this will call even when there are no receives
+ // queued and the first packet has already been indicated.
+ if ((SPX_RECV_STATE(pSpxConnFile) != SPX_RECV_PROCESS_PKTS) &&
+ (!IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage) ||
+ (pSpxConnFile->scf_RecvListHead != NULL)))
+ {
+ // We have the flag reference on the connection.
+ SpxRecvProcessPkts(pSpxConnFile, lockHandle);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ }
+
+#if DBG
+ if (!IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxReceiveComplete: RecvDone left %lx\n",
+ pSpxConnFile));
+ }
+#endif
+
+ // Hmm. This check is rather expensive, and essentially we are doing
+ // it twice. Should look to see if this can be modified safely.
+ } while ((!IsListEmpty(&pSpxConnFile->scf_ReqDoneLinkage)) ||
+ ((SPX_RECV_STATE(pSpxConnFile) != SPX_RECV_PROCESS_PKTS) &&
+ ((!IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage)) ||
+ ((pSpxConnFile->scf_RecvListHead != NULL) &&
+ ((pSpxConnFile->scf_RecvListHead->rr_State &
+ (SPX_RECVPKT_BUFFERING | SPX_RECVPKT_INDICATED)) ==
+ SPX_RECVPKT_BUFFERING)))));
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_RECVQ);
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_RECV,
+ CFREF_VERIFY);
+
+ numDerefs++;
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ }
+
+
+ // First see if we need to packetize.
+ while ((pSpxConnFile = SpxPktConnList.pcl_Head) != NULL)
+ {
+ if ((SpxPktConnList.pcl_Head = pSpxConnFile->scf_PktNext) == NULL)
+ SpxPktConnList.pcl_Tail = NULL;
+
+ // Reset next field to NULL
+ pSpxConnFile->scf_PktNext = NULL;
+
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnRemoveFromPkt: %lx\n", pSpxConnFile));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ fConnLockHeld = TRUE;
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxReceiveComplete: Packetizing %lx\n", pSpxConnFile));
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_PKTQ);
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE)
+ {
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_PACKETIZE);
+ if (SpxConnPacketize(
+ pSpxConnFile,
+ TRUE,
+ lockHandle))
+ {
+ // Done.
+ fConnLockHeld = FALSE;
+ }
+ }
+
+ if (fConnLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ SpxConnFileDereference(pSpxConnFile, CFREF_PKTIZE);
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ }
+
+ if (fInterlockHeld)
+ {
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+
+ return;
+}
+
+
+
+
+//
+// PACKET HANDLING ROUTINES
+//
+
+
+VOID
+SpxRecvSysPacket(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ )
+/*++
+
+Routine Description:
+
+ This is called to indicate an incoming system packet.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ PIPXSPX_HDR pHdr;
+ USHORT srcConnId, destConnId,
+ pktLen, ackNum, allocNum;
+ PSPX_CONN_FILE pSpxConnFile;
+ CTELockHandle lockHandle;
+ BOOLEAN lockHeld = FALSE;
+
+ pHdr = (PIPXSPX_HDR)LookaheadBuffer;
+
+ // check minimum length
+ if (PacketSize < MIN_IPXSPX_HDRSIZE)
+ {
+ return;
+ }
+
+ // Convert hdr to host format as needed.
+ GETSHORT2SHORT(&pktLen, &pHdr->hdr_PktLen);
+ GETSHORT2SHORT(&destConnId, &pHdr->hdr_DestConnId);
+
+ if ((pktLen < MIN_IPXSPX_HDRSIZE) ||
+ (pktLen > PacketSize) ||
+ (pHdr->hdr_PktType != SPX_PKT_TYPE))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxRecvSysPacket: Packet Size %lx.%lx\n",
+ pktLen, PacketSize));
+
+ return;
+ }
+
+ if ((pktLen == SPX_CR_PKTLEN) &&
+ (destConnId == 0xFFFF) &&
+ (pHdr->hdr_ConnCtrl & SPX_CC_CR))
+ {
+ spxConnHandleConnReq(
+ pHdr,
+ pRemoteAddr);
+
+ return;
+ }
+
+ //
+ // [SA] Bug #14917
+ // Some SPX SYS packets (no extended ack field) may come in with the SPX2 bit set.
+ // Make sure we don't discard these packets.
+ //
+
+ // if ((pHdr->hdr_ConnCtrl & SPX_CC_SPX2) && (pktLen < MIN_IPXSPX2_HDRSIZE))
+ // {
+ // return;
+ // }
+
+ GETSHORT2SHORT(&ackNum, &pHdr->hdr_AckNum);
+ GETSHORT2SHORT(&allocNum, &pHdr->hdr_AllocNum);
+
+ // We keep and use the remote id in the net format. This maintains the
+ // 0x0 and 0xFFFF to be as in the host format.
+ srcConnId = *(USHORT UNALIGNED *)&pHdr->hdr_SrcConnId;
+
+ if ((srcConnId == 0) || (srcConnId == 0xFFFF) || (destConnId == 0))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnSysPacket: Incorrect conn id %lx.%lx\n",
+ srcConnId, destConnId));
+
+ return;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnSysPacket: packet received dest %lx src %lx\n",
+ pHdr->hdr_DestSkt, pHdr->hdr_SrcSkt));
+
+ // Find the connection this is destined for and reference it.
+ SpxConnFileReferenceById(destConnId, &pSpxConnFile, &status);
+ if (!NT_SUCCESS(status))
+ {
+ DBGPRINT(RECEIVE, WARN,
+ ("SpxConnSysPacket: Id %lx NOT FOUND\n", destConnId));
+ return;
+ }
+
+ do
+ {
+
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnSysPacket: Id %lx Conn %lx\n",
+ destConnId, pSpxConnFile));
+
+ // This could be one of many packets. Connection ack/Session negotiate/
+ // Session setup, Data Ack, Probe/Ack, Renegotiate/Ack. We shunt
+ // off all the packets to different routines but process the data
+ // ack packets here.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ //
+ // We have the connection. We should update the dest. sock # in
+ // it in case it changed. Unix machines do do that sometimes.
+ // SCO bug 7676
+ //
+ SpxCopyIpxAddr(pHdr, pSpxConnFile->scf_RemAddr);
+
+ lockHeld = TRUE;
+
+ // Restart watchdog timer if started.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER))
+ {
+ // This will either successfully restart or not affect the timer
+ // if it is currently running.
+ SpxTimerCancelEvent(
+ pSpxConnFile->scf_WTimerId,
+ TRUE);
+
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+ }
+
+ switch (SPX_MAIN_STATE(pSpxConnFile))
+ {
+ case SPX_CONNFILE_CONNECTING:
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ lockHeld = FALSE;
+
+ spxConnHandleSessPktFromSrv(
+ pHdr,
+ pRemoteAddr,
+ pSpxConnFile);
+
+ break;
+
+ case SPX_CONNFILE_LISTENING:
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ lockHeld = FALSE;
+
+ spxConnHandleSessPktFromClient(
+ pHdr,
+ pRemoteAddr,
+ pSpxConnFile);
+
+ break;
+
+ case SPX_CONNFILE_ACTIVE:
+ case SPX_CONNFILE_DISCONN:
+
+ // NOTE: Our ack to a session setup might get dropped.
+ // But the SS Ack is similar to a normal SPX2 ack.
+ // We dont have to do anything special.
+
+ // Received ack/nack/reneg/reneg ack/disc associated packet.
+ // Disc packets except ordrel ack have non-zero datastream type.
+ if ((pHdr->hdr_ConnCtrl &
+ (SPX_CC_SYS | SPX_CC_ACK | SPX_CC_NEG | SPX_CC_SPX2)) ==
+ (SPX_CC_SYS | SPX_CC_ACK | SPX_CC_NEG | SPX_CC_SPX2))
+ {
+ // We received a renegotiate packet. Ignore all ack values
+ // in a reneg req.
+ SpxConnProcessRenegReq(pSpxConnFile, pHdr, pRemoteAddr, lockHandle);
+ lockHeld = FALSE;
+ break;
+ }
+
+ // Set ack numbers for connection.
+ SPX_SET_ACKNUM(
+ pSpxConnFile, ackNum, allocNum);
+
+ // Check if we are an ack/nack packet in which case call process
+ // ack. Note that the spx2 orderly release ack is a normal spx2 ack.
+ if (((pHdr->hdr_ConnCtrl & SPX_CC_ACK) == 0) &&
+ (pHdr->hdr_DataType == 0))
+ {
+ SpxConnProcessAck(pSpxConnFile, pHdr, lockHandle);
+ lockHeld = FALSE;
+ }
+ else
+ {
+ // Just process the numbers we got.
+ SpxConnProcessAck(pSpxConnFile, NULL, lockHandle);
+ lockHeld = FALSE;
+ }
+
+ // If the remote wants us to send an ack, do it.
+ if (pHdr->hdr_ConnCtrl & SPX_CC_ACK)
+ {
+ // First copy the remote address in connection.
+ SpxCopyIpxAddr(pHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *pRemoteAddr;
+
+ if (!lockHeld)
+ {
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ lockHeld = TRUE;
+ }
+
+ SpxConnSendAck(pSpxConnFile, lockHandle);
+ lockHeld = FALSE;
+ break;
+ }
+
+ break;
+
+ default:
+
+ // Ignore this packet.
+ DBGPRINT(RECEIVE, WARN,
+ ("SpxConnSysPacket: Ignoring packet, state is not active\n"));
+ break;
+ }
+
+ } while (FALSE);
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ // Remove reference added on connection
+ SpxConnFileDereference(pSpxConnFile, CFREF_BYID);
+ return;
+}
+
+
+
+
+VOID
+SpxRecvDiscPacket(
+ IN PUCHAR LookaheadBuffer,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN UINT LookaheadSize
+ )
+/*++
+
+Routine Description:
+
+ This is called to indicate an incoming connection.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS status;
+ PIPXSPX_HDR pHdr;
+ USHORT srcConnId, destConnId,
+ pktLen, seqNum, ackNum, allocNum;
+ PSPX_CONN_FILE pSpxConnFile;
+ CTELockHandle lockHandle;
+ BOOLEAN lockHeld;
+
+ pHdr = (PIPXSPX_HDR)LookaheadBuffer;
+
+ // check minimum length
+ if (LookaheadSize < MIN_IPXSPX_HDRSIZE)
+ {
+ return;
+ }
+
+ // Convert hdr to host format as needed.
+ GETSHORT2SHORT(&pktLen, &pHdr->hdr_PktLen);
+ GETSHORT2SHORT(&destConnId, &pHdr->hdr_DestConnId);
+ GETSHORT2SHORT(&seqNum, &pHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pHdr->hdr_AckNum);
+ GETSHORT2SHORT(&allocNum, &pHdr->hdr_AllocNum);
+
+ if ((pktLen < MIN_IPXSPX_HDRSIZE) ||
+ (pHdr->hdr_PktType != SPX_PKT_TYPE))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxRecvDiscPacket: Packet Size %lx\n",
+ pktLen));
+
+ return;
+ }
+
+ // We keep and use the remote id in the net format. This maintains the
+ // 0x0 and 0xFFFF to be as in the host format.
+ srcConnId = *(USHORT UNALIGNED *)&pHdr->hdr_SrcConnId;
+ if ((srcConnId == 0) || (srcConnId == 0xFFFF) || (destConnId == 0))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnDiscPacket: Incorrect conn id %lx.%lx\n",
+ srcConnId, destConnId));
+
+ return;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnDiscPacket: packet received dest %lx src %lx\n",
+ pHdr->hdr_DestSkt, pHdr->hdr_SrcSkt));
+
+ // Find the connection this is destined for and reference it.
+ SpxConnFileReferenceById(destConnId, &pSpxConnFile, &status);
+ if (!NT_SUCCESS(status))
+ {
+ DBGPRINT(RECEIVE, WARN,
+ ("SpxConnDiscPacket: Id %lx NOT FOUND", destConnId));
+
+ return;
+ }
+
+ do
+ {
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnDiscPacket: Id %lx Conn %lx DiscType %lx\n",
+ destConnId, pSpxConnFile, pHdr->hdr_DataType));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ lockHeld = TRUE;
+
+ // Unless we are in the active/disconnecting, but send state = idle
+ // and recv state = idle/recv posted, we ignore all disconnect packets.
+ if (((SPX_MAIN_STATE(pSpxConnFile) != SPX_CONNFILE_ACTIVE) &&
+ (SPX_MAIN_STATE(pSpxConnFile) != SPX_CONNFILE_DISCONN)) ||
+ ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_IDLE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_PACKETIZE)) ||
+ ((SPX_RECV_STATE(pSpxConnFile) != SPX_RECV_IDLE) &&
+ (SPX_RECV_STATE(pSpxConnFile) != SPX_RECV_POSTED)) ||
+ !(IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage)) ||
+ (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_PKT)))
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDiscPacket: %lx, %lx, %lx.%lx, %d.%d\n",
+ pSpxConnFile,
+ SPX_MAIN_STATE(pSpxConnFile),
+ SPX_SEND_STATE(pSpxConnFile), SPX_RECV_STATE(pSpxConnFile),
+ (IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage)),
+ (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_PKT))));
+
+ break;
+ }
+
+ // If we have received a disconnect, process received ack to complete any
+ // pending sends before we allow the disconnect. This ack number will be
+ // the last word on this session.
+ SPX_SET_ACKNUM(
+ pSpxConnFile, ackNum, allocNum);
+
+ SpxConnProcessAck(pSpxConnFile, NULL, lockHandle);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+
+ switch (pHdr->hdr_DataType)
+ {
+ case SPX2_DT_ORDREL:
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDiscPacket: Recd ORDREl!\n"));
+
+ // BUGBUG: Need to deal with all sthe states.
+ // Restart watchdog timer if started.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER))
+ {
+ // This will either successfully restart or not affect the timer
+ // if it is currently running.
+ SpxTimerCancelEvent(
+ pSpxConnFile->scf_WTimerId,
+ TRUE);
+
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+ }
+
+ // On receive, we do check the seq num for the orderly release, just
+ // like for a data packet.
+ // If this was not already indicated, indicate it now. That is all
+ // we do for an orderly release. When our client does a orderly rel
+ // and we receive the ack for that, call abortive with success.
+
+ // Verify ord rel packet, this checks if seq nums match also.
+ if ((pktLen != MIN_IPXSPX2_HDRSIZE) ||
+ ((pHdr->hdr_ConnCtrl &
+ (SPX_CC_ACK | SPX_CC_EOM | SPX_CC_SPX2)) !=
+ (SPX_CC_ACK | SPX_CC_EOM | SPX_CC_SPX2)) ||
+ (pHdr->hdr_DataType != SPX2_DT_ORDREL) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId))
+ {
+ DBGPRINT(CONNECT, DBG1,
+ ("SpxConnDiscPacket: OR Failed/Ignored %lx, %lx.%lx.%lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum,
+ pSpxConnFile->scf_RecvListTail));
+
+ break;
+ }
+
+ // If it passed above test, but seq number is incorrect, schedule
+ // to send an ack.
+ if (seqNum != pSpxConnFile->scf_RecvSeqNum)
+ {
+ USHORT NumToResend;
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnDiscPacket: Unexpected seq on %lx, %lx.%lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
+
+ // Calculate number to be resent. If we expect sequence 1 and receive
+ // 2 for eg., we need to send a nack, else we send an ack.
+ if (SPX2_CONN(pSpxConnFile) &&
+ UNSIGNED_GREATER_WITH_WRAP(
+ seqNum,
+ pSpxConnFile->scf_RecvSeqNum) &&
+ !UNSIGNED_GREATER_WITH_WRAP(
+ seqNum,
+ pSpxConnFile->scf_SentAllocNum))
+ {
+ NumToResend = (USHORT)(seqNum - pSpxConnFile->scf_RecvSeqNum + 1);
+ SpxConnSendNack(pSpxConnFile, NumToResend, lockHandle);
+ lockHeld = FALSE;
+ }
+
+ break;
+ }
+
+ // Copy address for when ack is to be sent.
+ SpxCopyIpxAddr(pHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *pRemoteAddr;
+
+ if (pSpxConnFile->scf_RecvListHead == NULL)
+ {
+ // No received data, go ahead and process now.
+ DBGPRINT(CONNECT, INFO,
+ ("SpxConnDiscPacket: NO DATA ORDREL %lx.%lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_RecvListHead,
+ pSpxConnFile->scf_SendSeqListHead));
+
+ SpxConnProcessOrdRel(pSpxConnFile, lockHandle);
+ lockHeld = FALSE;
+ }
+ else
+ {
+ // No received data, go ahead and process now.
+ DBGPRINT(CONNECT, DBG1,
+ ("SpxConnDiscPacket: DATA ORDREL %lx.%lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_RecvListHead,
+ pSpxConnFile->scf_SendSeqListHead));
+
+ // Set flag in last recd buffer
+ pSpxConnFile->scf_RecvListTail->rr_State |= SPX_RECVPKT_ORD_DISC;
+ }
+
+ break;
+
+ case SPX2_DT_IDISC:
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDiscPacket: %lx Recd IDISC %lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_RefCount));
+
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnDiscPacket: SEND %d. RECV %d.%lx!\n",
+ IsListEmpty(&pSpxConnFile->scf_ReqLinkage),
+ IsListEmpty(&pSpxConnFile->scf_RecvLinkage),
+ pSpxConnFile->scf_RecvDoneLinkage));
+
+ if (!((pktLen == MIN_IPXSPX_HDRSIZE) ||
+ ((pHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
+ (pktLen == MIN_IPXSPX2_HDRSIZE))) ||
+ !(pHdr->hdr_ConnCtrl & SPX_CC_ACK) ||
+ (pHdr->hdr_DataType != SPX2_DT_IDISC) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnDiscPacket:IDISC Ignored %lx.%lx.%lx.%lx\n",
+ pSpxConnFile, seqNum,
+ pSpxConnFile->scf_RecvSeqNum,
+ pSpxConnFile->scf_RecvListTail));
+ break;
+ }
+
+ // Copy address for when ack is to be sent.
+ SpxCopyIpxAddr(pHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *pRemoteAddr;
+
+ if (pSpxConnFile->scf_RecvListHead == NULL)
+ {
+ // No received data, go ahead and process now.
+ DBGPRINT(CONNECT, INFO,
+ ("SpxConnDiscPacket: NO RECV DATA IDISC %lx.%lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_RecvListHead,
+ pSpxConnFile->scf_SendSeqListHead));
+
+ SpxConnProcessIDisc(pSpxConnFile, lockHandle);
+
+ lockHeld = FALSE;
+ }
+ else
+ {
+ // Set flag in last recd buffer
+
+ pSpxConnFile->scf_RecvListTail->rr_State |= SPX_RECVPKT_IDISC;
+ }
+
+ break;
+
+ case SPX2_DT_IDISC_ACK:
+
+ // Done with informed disconnect. Call abort connection with
+ // status success. That completes the pending disconnect request
+ // with status_success.
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDiscPacket: %lx Recd IDISC ack!\n", pSpxConnFile));
+
+ if (!((pktLen == MIN_IPXSPX_HDRSIZE) ||
+ ((pHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
+ (pktLen == MIN_IPXSPX2_HDRSIZE))) ||
+ (pHdr->hdr_DataType != SPX2_DT_IDISC_ACK) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnDiscPacket:Ver idisc ack Failed %lx, %lx.%lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
+ break;
+ }
+
+ // We should be in the right state to accept this.
+ if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_SENT_IDISC))
+ {
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_SUCCESS,
+ SPX_CALL_RECVLEVEL,
+ lockHandle,
+ FALSE); // [SA] bug #15249
+
+ lockHeld = FALSE;
+ }
+
+ break;
+
+ default:
+
+ KeBugCheck(0);
+ }
+
+
+ } while (FALSE);
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ // Remove reference added on connection
+ SpxConnFileDereference(pSpxConnFile, CFREF_BYID);
+ return;
+}
+
+
+
+
+VOID
+SpxRecvBufferPkt(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT LookaheadOffset,
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN UINT PacketSize,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+ This is called to indicate an incoming connection.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pNdisPkt;
+ PSPX_RECV_RESD pRecvResd;
+ ULONG bytesCopied;
+ BOOLEAN fEom;
+ NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
+ PBYTE pData = NULL;
+ PNDIS_BUFFER pNdisBuffer = NULL;
+
+ if (PacketSize > 0)
+ {
+ // Allocate memory for this data.
+ if (pData = (PBYTE)SpxAllocateMemory(PacketSize))
+ {
+ // Describe memory with a ndis buffer descriptor.
+ NdisAllocateBuffer(
+ &ndisStatus,
+ &pNdisBuffer,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ pData,
+ PacketSize);
+ }
+ else
+ {
+ ndisStatus = NDIS_STATUS_RESOURCES;
+ }
+ }
+
+ if (ndisStatus == NDIS_STATUS_SUCCESS)
+ {
+ // Allocate a ndis receive packet.
+ SpxAllocRecvPacket(SpxDevice, &pNdisPkt, &ndisStatus);
+ if (ndisStatus == NDIS_STATUS_SUCCESS)
+ {
+ // Queue the buffer into the packet if there is one.
+ if (pNdisBuffer)
+ {
+ NdisChainBufferAtBack(
+ pNdisPkt,
+ pNdisBuffer);
+ }
+
+ fEom = ((SPX_CONN_MSG(pSpxConnFile) &&
+ (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_EOM)) ||
+ SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR));
+
+ pRecvResd = RECV_RESD(pNdisPkt);
+ pRecvResd->rr_DataOffset= 0;
+
+#if DBG
+ // Store seq number
+ GETSHORT2SHORT(&pRecvResd->rr_SeqNum , &pIpxSpxHdr->hdr_SeqNum);
+#endif
+
+ pRecvResd->rr_State =
+ (SPX_RECVPKT_BUFFERING |
+ (SPX_CONN_FLAG2(
+ pSpxConnFile, SPX_CONNFILE2_PKT_NOIND) ? SPX_RECVPKT_INDICATED : 0) |
+ (fEom ? SPX_RECVPKT_EOM : 0) |
+ ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_ACK) ? SPX_RECVPKT_SENDACK : 0));
+
+ if (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_ACK)
+ {
+ // copy the remote address in connection.
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *pRemoteAddr;
+ }
+
+ pRecvResd->rr_Request = NULL;
+ pRecvResd->rr_ConnFile = pSpxConnFile;
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxRecvBufferPkt: %lx Len %lx DataPts %lx F %lx\n",
+ pSpxConnFile, PacketSize, pData, pRecvResd->rr_State));
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ // Call ndis transfer data. Copy ENTIRE packet. copySize has
+ // been modified so use original values.
+ ndisStatus = NDIS_STATUS_SUCCESS;
+ bytesCopied = 0;
+ if (PacketSize > 0)
+ {
+ (*IpxTransferData)(
+ &ndisStatus,
+ MacBindingHandle,
+ MacReceiveContext,
+ LookaheadOffset,
+ PacketSize,
+ pNdisPkt,
+ &bytesCopied);
+ }
+
+ if (ndisStatus != STATUS_PENDING)
+ {
+ SpxTransferDataComplete(
+ pNdisPkt,
+ ndisStatus,
+ bytesCopied);
+ }
+
+ // BUG: FDDI returns pending which screws us up here. Stupid bug
+ ndisStatus = NDIS_STATUS_SUCCESS;
+ }
+ }
+
+ // ASSERT: Lock will be freed in the success case.
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxRecvBufferPkt: FAILED!\n"));
+
+ END_PROCESS_PACKET(pSpxConnFile, FALSE, FALSE);
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ if (pData != NULL)
+ {
+ SpxFreeMemory(pData);
+ }
+
+ if (pNdisBuffer != NULL)
+ {
+ NdisFreeBuffer(pNdisBuffer);
+ }
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxRecvDataPacket(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadSize,
+ IN UINT LookaheadOffset,
+ IN UINT PacketSize
+ )
+/*++
+
+Routine Description:
+
+ This is called to indicate an incoming connection.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ PIPXSPX_HDR pIpxSpxHdr;
+ USHORT srcConnId, destConnId,
+ pktLen, seqNum, ackNum, allocNum;
+ ULONG receiveFlags;
+ PSPX_CONN_FILE pSpxConnFile;
+ PTDI_IND_RECEIVE pRecvHandler;
+ PVOID pRecvCtx;
+ PIRP pRecvIrp;
+ ULONG bytesTaken, iOffset, copySize, bytesCopied;
+ CTELockHandle lockHandle;
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+ PSPX_RECV_RESD pRecvResd;
+ NDIS_STATUS ndisStatus;
+ PREQUEST pRequest = NULL;
+ BOOLEAN fEom,
+ fImmedAck = FALSE, fLockHeld = FALSE, fPktDone = FALSE;
+
+ pIpxSpxHdr = (PIPXSPX_HDR)LookaheadBuffer;
+
+ // check minimum length
+ if (PacketSize < MIN_IPXSPX_HDRSIZE)
+ {
+ return;
+ }
+
+ // Convert hdr to host format as needed.
+ GETSHORT2SHORT(&pktLen, &pIpxSpxHdr->hdr_PktLen);
+ GETSHORT2SHORT(&destConnId, &pIpxSpxHdr->hdr_DestConnId);
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+
+ if ((pktLen < MIN_IPXSPX_HDRSIZE) ||
+ (pktLen > PacketSize) ||
+ (pIpxSpxHdr->hdr_PktType != SPX_PKT_TYPE))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnDataPacket: Packet Size %lx.%lx\n",
+ pktLen, PacketSize));
+
+ return;
+ }
+
+ // We keep and use the remote id in the net format.
+ srcConnId = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_SrcConnId;
+
+ if ((srcConnId == 0) || (srcConnId == 0xFFFF) || (destConnId == 0))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnDataPacket: Incorrect conn id %lx.%lx\n",
+ srcConnId, destConnId));
+
+ return;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnDataPacket: packet received dest %lx src %lx seq %lx\n",
+ pIpxSpxHdr->hdr_DestSkt, pIpxSpxHdr->hdr_SrcSkt, seqNum));
+
+ if ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
+ (pktLen < MIN_IPXSPX2_HDRSIZE))
+ {
+ return;
+ }
+
+ // Find the connection this is destined for and reference it.
+ SpxConnFileReferenceById(destConnId, &pSpxConnFile, &status);
+ if (!NT_SUCCESS(status))
+ {
+ DBGPRINT(RECEIVE, WARN,
+ ("SpxConnDataPacket: Id %lx NOT FOUND", destConnId));
+ return;
+ }
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+
+#if 0
+ //
+ // We have the connection. We should update the dest. sock # in
+ // it in case it changed. Unix machines do do that sometimes.
+ // SCO bug 7676
+ //
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAddr);
+#endif
+
+ fLockHeld = TRUE;
+ do
+ {
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnDataPacket: Id %lx Conn %lx\n",
+ destConnId, pSpxConnFile));
+
+ // Restart watchdog timer if started.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER))
+ {
+ // This will either successfully restart or not affect the timer
+ // if it is currently running.
+ SpxTimerCancelEvent(
+ pSpxConnFile->scf_WTimerId,
+ TRUE);
+
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+ }
+
+ if (SPX_CONN_ACTIVE(pSpxConnFile))
+ {
+ // Verify data packet, this checks if seq nums match also.
+ if ((pIpxSpxHdr->hdr_SrcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId) ||
+ !((pktLen >= MIN_IPXSPX_HDRSIZE) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
+ (pktLen >= MIN_IPXSPX2_HDRSIZE))))
+ {
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnDataPacket: Failed %lx, %lx.%lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
+
+ break;
+ }
+
+ // If it passed above test, but seq number is incorrect, schedule
+ // to send an ack.
+ if (seqNum != pSpxConnFile->scf_RecvSeqNum)
+ {
+ USHORT NumToResend;
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnDataPacket: Unexpected seq on %lx, %lx.%lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
+
+ ++SpxDevice->dev_Stat.DataFramesRejected;
+ ExInterlockedAddLargeStatistic(
+ &SpxDevice->dev_Stat.DataFrameBytesRejected,
+ pktLen - (SPX2_CONN(pSpxConnFile) ?
+ MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE));
+
+ //
+ // Bug #16975: Set the remote ack addr for use in SpxConnSendAck()
+ //
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *RemoteAddress;
+
+ // Calculate number to be resent. If we expect sequence 1 and receive
+ // 2 for eg., we need to send a nack, else we send an ack.
+ if (SPX2_CONN(pSpxConnFile) &&
+ UNSIGNED_GREATER_WITH_WRAP(
+ seqNum,
+ pSpxConnFile->scf_RecvSeqNum) &&
+ !UNSIGNED_GREATER_WITH_WRAP(
+ seqNum,
+ pSpxConnFile->scf_SentAllocNum))
+ {
+ NumToResend = (USHORT)(seqNum - pSpxConnFile->scf_RecvSeqNum + 1);
+ SpxConnSendNack(pSpxConnFile, NumToResend, lockHandle);
+ fLockHeld = FALSE;
+ }
+ else
+ {
+ SpxConnSendAck(pSpxConnFile, lockHandle);
+ fLockHeld = FALSE;
+ }
+
+ break;
+ }
+
+ // If we have received an orderly release, we accept no more data
+ // packets.
+ if (SPX_CONN_FLAG(
+ pSpxConnFile,
+ (SPX_CONNFILE_IND_IDISC |
+ SPX_CONNFILE_IND_ODISC))
+
+ ||
+
+ ((pSpxConnFile->scf_RecvListTail != NULL) &&
+ ((pSpxConnFile->scf_RecvListTail->rr_State &
+ SPX_RECVPKT_DISCMASK) != 0)))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnDataPacket: After ord rel %lx, %lx.%lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
+
+ break;
+ }
+
+ // We are processing a packet OR a receive is about to complete.
+ if (!SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_PKT))
+ {
+ BEGIN_PROCESS_PACKET(pSpxConnFile, seqNum);
+ }
+ else
+ {
+ // Already processing a packet. Or a receive is waiting to
+ // complete. Get out.
+ break;
+ }
+
+ // Set ack numbers for connection.
+ SPX_SET_ACKNUM(
+ pSpxConnFile, ackNum, allocNum);
+
+ SpxConnProcessAck(pSpxConnFile, NULL, lockHandle);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+
+ iOffset = MIN_IPXSPX2_HDRSIZE;
+ if (!SPX2_CONN(pSpxConnFile))
+ {
+ iOffset = 0;
+ if (!SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR))
+ {
+ iOffset = MIN_IPXSPX_HDRSIZE;
+ }
+ }
+
+ copySize = pktLen - iOffset;
+ fEom = ((SPX_CONN_MSG(pSpxConnFile) &&
+ (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_EOM)) ||
+ SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR));
+
+ // Do we attempt to piggyback? If not, fImmedAck is true.
+ // For SPX1 we dont piggyback.
+ // Bug #18253
+ fImmedAck = (!SPX2_CONN(pSpxConnFile) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_EOM) == 0));
+
+ // If we do not have EOM to indicate AND we are a zero-sized packet
+ // then just consume this packet.
+ if (!fEom && (copySize == 0))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnDataPacket: ZERO LENGTH PACKET NO EOM %lx.%lx\n",
+ pSpxConnFile, seqNum));
+
+ fPktDone = TRUE;
+ break;
+ }
+
+ receiveFlags = TDI_RECEIVE_NORMAL;
+ receiveFlags |= ((fEom ? TDI_RECEIVE_ENTIRE_MESSAGE : 0) |
+ (((MacOptions &
+ NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA) != 0) ?
+ TDI_RECEIVE_COPY_LOOKAHEAD : 0));
+
+ ++SpxDevice->dev_Stat.DataFramesReceived;
+ ExInterlockedAddLargeStatistic(
+ &SpxDevice->dev_Stat.DataFrameBytesReceived,
+ copySize);
+
+ // Ok, we accept this packet. Depending on our state.
+ switch (SPX_RECV_STATE(pSpxConnFile))
+ {
+ case SPX_RECV_PROCESS_PKTS:
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDataPacket: recv completions on %lx\n",
+ pSpxConnFile));
+
+ goto BufferPacket;
+
+ case SPX_RECV_IDLE:
+
+ // If recv q is non-empty we are buffering data.
+ // Also, if no receive handler goto buffer data. Also, if receives
+ // are being completed, buffer this packet.
+ if ((pSpxConnFile->scf_RecvListHead != NULL) ||
+ !(IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage)) ||
+ !(pRecvHandler = pSpxConnFile->scf_AddrFile->saf_RecvHandler))
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDataPacket: RecvListHead non-null %lx\n",
+ pSpxConnFile));
+
+ goto BufferPacket;
+ }
+
+ if (!SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_PKT_NOIND))
+ {
+ pRecvCtx = pSpxConnFile->scf_AddrFile->saf_RecvHandlerCtx;
+
+ // Don't indicate this packet again.
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_PKT_NOIND);
+
+#if DBG
+ CTEAssert(pSpxConnFile->scf_CurRecvReq == NULL);
+
+ // Debug code to ensure we dont reindicate data/indicate
+ // when previously indicated data waiting with afd.
+
+ //
+ // Comment this out for Buf # 10394. we'r hitting this assert
+ // even when there was no data loss.
+ //
+ // CTEAssert(pSpxConnFile->scf_IndBytes == 0);
+ CTEAssert(pSpxConnFile->scf_PktSeqNum != seqNum);
+
+ pSpxConnFile->scf_PktSeqNum = seqNum;
+ pSpxConnFile->scf_PktFlags = pSpxConnFile->scf_Flags;
+ pSpxConnFile->scf_PktFlags2 = pSpxConnFile->scf_Flags2;
+
+ pSpxConnFile->scf_IndBytes = copySize;
+ pSpxConnFile->scf_IndLine = __LINE__;
+
+
+#endif
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ bytesTaken = 0;
+ status = (*pRecvHandler)(
+ pRecvCtx,
+ pSpxConnFile->scf_ConnCtx,
+ receiveFlags,
+ LookaheadSize - iOffset,
+ copySize,
+ &bytesTaken,
+ LookaheadBuffer + iOffset,
+ &pRecvIrp);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDataPacket: IND Flags %lx.%lx ConnID %lx,\
+ %lx Ctx %lx SEQ %lx Size %lx . %lx .%lx IND Status %lx\n",
+ pIpxSpxHdr->hdr_ConnCtrl,
+ receiveFlags,
+ destConnId,
+ pSpxConnFile,
+ pSpxConnFile->scf_ConnCtx,
+ seqNum,
+ LookaheadSize - iOffset,
+ copySize,
+ bytesTaken,
+ status));
+
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnDataPacket: %x %x %x %x %x %x %x %x %x %x %x %x\n",
+ *(LookaheadBuffer+iOffset),
+ *(LookaheadBuffer+iOffset+1),
+ *(LookaheadBuffer+iOffset+2),
+ *(LookaheadBuffer+iOffset+3),
+ *(LookaheadBuffer+iOffset+4),
+ *(LookaheadBuffer+iOffset+5),
+ *(LookaheadBuffer+iOffset+6),
+ *(LookaheadBuffer+iOffset+7),
+ *(LookaheadBuffer+iOffset+8),
+ *(LookaheadBuffer+iOffset+9),
+ *(LookaheadBuffer+iOffset+10),
+ *(LookaheadBuffer+iOffset+11)));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+
+ if (status == STATUS_SUCCESS)
+ {
+ // Assume all data accepted.
+ CTEAssert((bytesTaken != 0) || fEom);
+ fPktDone = TRUE;
+
+#if DBG
+ // Set this to 0, since we just indicated, there could
+ // not have been other data.
+ pSpxConnFile->scf_IndBytes = 0;
+#endif
+
+ break;
+ }
+
+ if (status == STATUS_MORE_PROCESSING_REQUIRED)
+ {
+
+ // Queue irp into connection, change state to receive
+ // posted and fall thru.
+ pRequest = SpxAllocateRequest(
+ SpxDevice,
+ pRecvIrp);
+
+ IF_NOT_ALLOCATED(pRequest)
+ {
+ pRecvIrp->IoStatus.Status =
+ STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (pRecvIrp, IO_NETWORK_INCREMENT);
+ break;
+ }
+
+ // If there was indicated but not received data waiting
+ // (which in this path there will never be, the request
+ // could be completed given the data filled it up, and
+ // the lock released.
+ SpxConnQueueRecv(
+ pSpxConnFile,
+ pRequest);
+
+ CTEAssert(pRequest == pSpxConnFile->scf_CurRecvReq);
+ }
+ else if (IsListEmpty(&pSpxConnFile->scf_RecvLinkage))
+ {
+ // Data was not accepted. Need to buffer data and
+ // reduce window.
+ goto BufferPacket;
+ }
+
+ // Fall through to recv_posted.
+ }
+ else
+ {
+ DBGPRINT(RECEIVE, WARN,
+ ("SpxConnDataPacket: !!!Ignoring %lx Seq %lx\n",
+ pSpxConnFile,
+ seqNum));
+
+ break;
+ }
+
+ case SPX_RECV_POSTED:
+
+ if (pSpxConnFile->scf_RecvListHead != NULL)
+ {
+ // This can happen also. Buffer packet if it does.
+ goto BufferPacket;
+ }
+
+ // If a receive irp is posted, then process the receive irp. If
+ // we fell thru we MAY already will have an irp.
+ if (pRequest == NULL)
+ {
+ CTEAssert(!IsListEmpty(&pSpxConnFile->scf_RecvLinkage));
+ CTEAssert(pSpxConnFile->scf_CurRecvReq != NULL);
+ pRequest = pSpxConnFile->scf_CurRecvReq;
+ }
+
+ // Process receive. Here we do not need to worry about
+ // indicated yet not received data. We just deal with
+ // servicing the current packet.
+ CTEAssert(pRequest == pSpxConnFile->scf_CurRecvReq);
+ if ((LookaheadSize == PacketSize) &&
+ (pSpxConnFile->scf_CurRecvSize >= copySize))
+ {
+ bytesCopied = 0;
+ status = STATUS_SUCCESS;
+ if (copySize > 0)
+ {
+ status = TdiCopyBufferToMdl(
+ LookaheadBuffer,
+ iOffset,
+ copySize,
+ REQUEST_TDI_BUFFER(pRequest),
+ pSpxConnFile->scf_CurRecvOffset,
+ &bytesCopied);
+
+ CTEAssert(NT_SUCCESS(status));
+ if (!NT_SUCCESS(status))
+ {
+ // Abort request with this status. Reset request
+ // queue to next request if one is available.
+ }
+
+ DBGPRINT(RECEIVE, DBG,
+ ("BytesCopied %lx CopySize %lx, Recv Size %lx.%lx\n",
+ bytesCopied, copySize,
+ pSpxConnFile->scf_CurRecvSize,
+ pSpxConnFile->scf_CurRecvOffset));
+ }
+
+ // Update current request values and see if this request
+ // is to be completed. Either zero or fEom.
+ pSpxConnFile->scf_CurRecvOffset += bytesCopied;
+ pSpxConnFile->scf_CurRecvSize -= bytesCopied;
+
+#if DBG
+ // Decrement indicated data count
+ if (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_PKT_NOIND))
+ {
+ if (bytesCopied != 0)
+ {
+ CTEAssert (pSpxConnFile->scf_IndBytes != 0);
+ pSpxConnFile->scf_IndBytes -= bytesCopied;
+ }
+ }
+#endif
+
+ if (SPX_CONN_STREAM(pSpxConnFile) ||
+ (pSpxConnFile->scf_CurRecvSize == 0) ||
+ fEom)
+ {
+ CTELockHandle lockHandleInter;
+
+ // Set status
+ REQUEST_STATUS(pRequest) = STATUS_SUCCESS;
+ REQUEST_INFORMATION(pRequest)=
+ pSpxConnFile->scf_CurRecvOffset;
+
+ if (!SPX_CONN_STREAM(pSpxConnFile) &&
+ (pSpxConnFile->scf_CurRecvSize == 0) &&
+ !fEom)
+ {
+ REQUEST_STATUS(pRequest) = STATUS_RECEIVE_PARTIAL;
+ }
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnData: Completing recv %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Dequeue this request, Set next recv if one exists.
+ SPX_CONN_SETNEXT_CUR_RECV(pSpxConnFile, pRequest);
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_RecvDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+
+ fPktDone = TRUE;
+ }
+ else
+ {
+ // Need to allocate a ndis receive packet for transfer
+ // data.
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDataPacket: %lx.%lx Tranfer data needed!\n",
+ copySize, pSpxConnFile->scf_CurRecvSize));
+
+ if (copySize > pSpxConnFile->scf_CurRecvSize)
+ {
+ // Partial receive. Buffer and then deal with it.
+ goto BufferPacket;
+ }
+
+ // Allocate a ndis receive packet.
+ SpxAllocRecvPacket(SpxDevice, &pNdisPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ // Describe the receive irp's data with a ndis buffer
+ // descriptor.
+ if (copySize > 0)
+ {
+ SpxCopyBufferChain(
+ &ndisStatus,
+ &pNdisBuffer,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ REQUEST_TDI_BUFFER(pRequest),
+ pSpxConnFile->scf_CurRecvOffset,
+ copySize);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ // Free the recv packet
+ SpxPktRecvRelease(pNdisPkt);
+ break;
+ }
+
+ // Queue the buffer into the packet
+ // Link the buffer descriptor into the packet descriptor
+ NdisChainBufferAtBack(
+ pNdisPkt,
+ pNdisBuffer);
+ }
+
+ // Don't care about whether this is indicated or not here
+ // as it is not a buffering packet.
+ pRecvResd = RECV_RESD(pNdisPkt);
+ pRecvResd->rr_Id = IDENTIFIER_SPX;
+ pRecvResd->rr_State =
+ ((fEom ? SPX_RECVPKT_EOM : 0) |
+ (SPX_CONN_FLAG2(
+ pSpxConnFile, SPX_CONNFILE2_PKT_NOIND) ? SPX_RECVPKT_INDICATED : 0) |
+ (fImmedAck ? SPX_RECVPKT_IMMEDACK : 0) |
+ ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_ACK) ?
+ SPX_RECVPKT_SENDACK : 0));
+
+ if (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_ACK)
+ {
+ // copy the remote address in connection.
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *RemoteAddress;
+ }
+
+ pRecvResd->rr_Request = pRequest;
+ pRecvResd->rr_ConnFile = pSpxConnFile;
+
+ // reference receive request
+ REQUEST_INFORMATION(pRequest)++;
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ fLockHeld = FALSE;
+
+ // Call ndis transfer data.
+ ndisStatus = NDIS_STATUS_SUCCESS;
+ bytesCopied = 0;
+ if (copySize > 0)
+ {
+ (*IpxTransferData)(
+ &ndisStatus,
+ MacBindingHandle,
+ MacReceiveContext,
+ iOffset + LookaheadOffset,
+ copySize,
+ pNdisPkt,
+ &bytesCopied);
+ }
+
+ if (ndisStatus != STATUS_PENDING)
+ {
+ SpxTransferDataComplete(
+ pNdisPkt,
+ ndisStatus,
+ bytesCopied);
+ }
+ }
+
+ break;
+
+ default:
+
+ KeBugCheck(0);
+ break;
+ }
+
+ break;
+
+BufferPacket:
+
+ SpxRecvBufferPkt(
+ pSpxConnFile,
+ MacBindingHandle,
+ MacReceiveContext,
+ iOffset + LookaheadOffset,
+ pIpxSpxHdr,
+ copySize,
+ RemoteAddress,
+ lockHandle);
+
+ fLockHeld = FALSE;
+ }
+
+ } while (FALSE);
+
+ // Here we process a received ack.
+ if (!fLockHeld)
+ {
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ fLockHeld = TRUE;
+ }
+
+ // Send an ack if one was asked for. And we are done with this packet.
+ if (fPktDone)
+ {
+ END_PROCESS_PACKET(pSpxConnFile, FALSE, TRUE);
+ }
+
+ if ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_ACK) && fPktDone)
+ {
+ if (!fLockHeld)
+ {
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ fLockHeld = TRUE;
+ }
+
+ // First copy the remote address in connection.
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *RemoteAddress;
+
+ // #17564
+ if (fImmedAck ||
+ SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_NOACKWAIT) ||
+ SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IMMED_ACK))
+ {
+ SpxConnSendAck(pSpxConnFile, lockHandle);
+ fLockHeld = FALSE;
+ }
+ else
+ {
+ SpxConnQWaitAck(pSpxConnFile);
+ }
+ }
+
+ if (fLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ // Deref the connection
+ SpxConnFileDereference(pSpxConnFile, CFREF_BYID);
+ return;
+}
+
+
+
+
+VOID
+SpxRecvFlushBytes(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN ULONG BytesToFlush,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+ PSPX_RECV_RESD pRecvResd;
+ PBYTE pData;
+ ULONG dataLen, copyLen;
+ BOOLEAN fLockHeld = TRUE, fWdwOpen = FALSE;
+ USHORT discState = 0;
+ int numPkts = 0, numDerefs = 0;
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxRecvFlushBytes: %lx Flush %lx\n",
+ pSpxConnFile, BytesToFlush));
+
+ while (((pRecvResd = pSpxConnFile->scf_RecvListHead) != NULL) &&
+ ((BytesToFlush > 0) ||
+ ((pRecvResd->rr_State & SPX_RECVPKT_INDICATED) != 0)))
+ {
+ // A buffering recv packet will have ATMOST one ndis buffer descriptor
+ // queued in, which will describe a segment of memory we have
+ // allocated. An offset will also be present indicating the data
+ // to start reading from (or to indicate from to AFD).
+ CTEAssert((pRecvResd->rr_State & SPX_RECVPKT_BUFFERING) != 0);
+ pNdisPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pRecvResd, NDIS_PACKET, ProtocolReserved);
+
+ NdisQueryPacket(pNdisPkt, NULL, NULL, &pNdisBuffer, NULL);
+
+ // Initialize pData
+ pData = NULL;
+ dataLen = 0;
+
+ if (pNdisBuffer != NULL)
+ {
+ NdisQueryBuffer(pNdisBuffer, &pData, &dataLen);
+ CTEAssert(pData != NULL);
+ CTEAssert(dataLen >= 0);
+ }
+
+ if ((BytesToFlush == 0) && (dataLen != 0))
+ {
+ // Don't flush this packet.
+ break;
+ }
+
+ // Allow for zero data, eom only packets.
+ copyLen = MIN((dataLen - pRecvResd->rr_DataOffset), BytesToFlush);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxRecvFlushBytes: %lx Pkt %lx DataLen %lx Copy %lx Flush %lx\n",
+ pSpxConnFile, pNdisPkt, dataLen, copyLen, BytesToFlush));
+
+ // Adjust various values to see whats done whats not
+ pRecvResd->rr_DataOffset += (USHORT)copyLen;
+ BytesToFlush -= (ULONG)copyLen;
+
+#if DBG
+ if (copyLen != 0)
+ {
+ CTEAssert (pSpxConnFile->scf_IndBytes != 0);
+ pSpxConnFile->scf_IndBytes -= copyLen;
+ }
+#endif
+
+ if (pRecvResd->rr_DataOffset == dataLen)
+ {
+ // Packet consumed. Free it up. Check if disc happened.
+ discState = (pRecvResd->rr_State & SPX_RECVPKT_DISCMASK);
+ CTEAssert((discState == 0) ||
+ (pRecvResd == pSpxConnFile->scf_RecvListTail));
+
+ numDerefs++;
+ SpxConnDequeueRecvPktLock(pSpxConnFile, pNdisPkt);
+ if (pNdisBuffer != NULL)
+ {
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ CTEAssert(pNdisBuffer != NULL);
+ NdisFreeBuffer(pNdisBuffer);
+ SpxFreeMemory(pData);
+ }
+
+ SpxPktRecvRelease(pNdisPkt);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxRecvFlushBytes: !!!ALL INDICATED on %lx.%lx.%lx.%lx\n",
+ pSpxConnFile, pNdisPkt, pNdisBuffer, pData));
+
+ INCREMENT_WINDOW(pSpxConnFile);
+ fWdwOpen = TRUE;
+ }
+ else
+ {
+ // Took only part of this packet. Get out.
+ break;
+ }
+ }
+
+ if (fWdwOpen && (pSpxConnFile->scf_RecvListHead == NULL))
+ {
+ // Send an ack as our windows probably opened up. Dont wait to
+ // piggyback here...
+ DBGPRINT(RECEIVE, DBG,
+ ("spxRecvFlushBytes: Send ACK %lx\n",
+ pSpxConnFile));
+
+#if DBG_WDW_CLOSE
+ // If packets been indicated we have started buffering. Also
+ // check if window is now zero.
+ {
+ LARGE_INTEGER li, ntTime;
+ int value;
+
+ li = pSpxConnFile->scf_WdwCloseTime;
+ if (li.LowPart && li.HighPart)
+ {
+ KeQuerySystemTime(&ntTime);
+
+ // Get the difference
+ ntTime.QuadPart = ntTime.QuadPart - li.QuadPart;
+
+ // Convert to milliseconds. If the highpart is 0, we
+ // take a shortcut.
+ if (ntTime.HighPart == 0)
+ {
+ value = ntTime.LowPart/10000;
+ }
+ else
+ {
+ ntTime = SPX_CONVERT100NSTOCENTISEC(ntTime);
+ value = ntTime.LowPart << 4;
+ }
+
+ // Set new average close time
+ pSpxConnFile->scf_WdwCloseAve += value;
+ pSpxConnFile->scf_WdwCloseAve /= 2;
+ DBGPRINT(RECEIVE, DBG,
+ ("V %ld AVE %ld\n",
+ value, pSpxConnFile->scf_WdwCloseAve));
+ }
+ }
+#endif
+
+ SpxConnSendAck(pSpxConnFile, LockHandleConn);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ }
+
+ // Check if disconnect happened
+ switch (discState)
+ {
+ case SPX_RECVPKT_IDISC:
+
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+
+ DBGPRINT(RECEIVE, ERR,
+ ("spxRecvFlushBytes: Buffered IDISC %lx\n",
+ pSpxConnFile));
+
+ SpxConnProcessIDisc(pSpxConnFile, LockHandleConn);
+ fLockHeld = FALSE;
+ break;
+
+ case SPX_RECVPKT_ORD_DISC:
+
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+
+ DBGPRINT(RECEIVE, ERR,
+ ("spxRecvFlushBytes: Buffered ORDREL %lx\n",
+ pSpxConnFile));
+
+ SpxConnProcessOrdRel(pSpxConnFile, LockHandleConn);
+ fLockHeld = FALSE;
+ break;
+
+ case (SPX_RECVPKT_IDISC | SPX_RECVPKT_ORD_DISC):
+
+ // IDISC has more priority.
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+
+ DBGPRINT(RECEIVE, ERR,
+ ("spxRecvFlushBytes: Buffered IDISC *AND* ORDREL %lx\n",
+ pSpxConnFile));
+
+ SpxConnProcessIDisc(pSpxConnFile, LockHandleConn);
+ fLockHeld = FALSE;
+ break;
+
+ default:
+
+ break;
+ }
+
+ if (fLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+BOOLEAN
+SpxRecvIndicatePendingData(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+ BOOLEAN - Receive was queued => TRUE
+
+--*/
+{
+ ULONG indicateFlags;
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+ PREQUEST pRequest;
+ PIRP pRecvIrp;
+ ULONG bytesTaken, totalSize, bufSize;
+ PTDI_IND_RECEIVE pRecvHandler;
+ PVOID pRecvCtx;
+ PSPX_RECV_RESD pRecvResd;
+ NTSTATUS status;
+ PBYTE lookaheadData;
+ ULONG lookaheadSize;
+ BOOLEAN fLockHeld = TRUE, fRecvQueued = FALSE;
+
+
+ while ((pRecvHandler = pSpxConnFile->scf_AddrFile->saf_RecvHandler) &&
+ ((pRecvResd = pSpxConnFile->scf_RecvListHead) != NULL) &&
+ (IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage)) &&
+ ((pRecvResd->rr_State & SPX_RECVPKT_BUFFERING) != 0) &&
+ ((pRecvResd->rr_State & SPX_RECVPKT_INDICATED) == 0))
+ {
+ // Once a receive is queued we better get out.
+ CTEAssert(!fRecvQueued);
+
+ // Initialize lookahead values
+ lookaheadData = NULL;
+ lookaheadSize = 0;
+
+ // We have no indicated but pending data, and there is some data to
+ // indicate. Figure out how much. Indicate upto end of message or as
+ // much as we have.
+
+ // A buffering recv packet will have ATMOST one ndis buffer descriptor
+ // queued in, which will describe a segment of memory we have
+ // allocated. An offset will also be present indicating the data
+ // to start reading from (or to indicate from to AFD).
+ CTEAssert((pRecvResd->rr_State & SPX_RECVPKT_BUFFERING) != 0);
+ pNdisPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pRecvResd, NDIS_PACKET, ProtocolReserved);
+
+ NdisQueryPacket(pNdisPkt, NULL, NULL, &pNdisBuffer, NULL);
+ if (pNdisBuffer != NULL)
+ {
+ NdisQueryBuffer(pNdisBuffer, &lookaheadData, &lookaheadSize);
+ CTEAssert(lookaheadData != NULL);
+ CTEAssert(lookaheadSize >= 0);
+ }
+
+ // Allow for zero data, eom only packets.
+ lookaheadSize -= pRecvResd->rr_DataOffset;
+ totalSize = lookaheadSize;
+ lookaheadData += pRecvResd->rr_DataOffset;
+
+ // If this packet contained data then eom must also have been
+ // indicated at the time all the data was consumed.
+ CTEAssert((lookaheadSize > 0) ||
+ ((pRecvResd->rr_DataOffset == 0) &&
+ ((pRecvResd->rr_State & SPX_RECVPKT_EOM) != 0)));
+
+#if DBG
+ CTEAssert (pSpxConnFile->scf_CurRecvReq == NULL);
+
+ // Debug code to ensure we dont reindicate data/indicate
+ // when previously indicated data waiting with afd.
+ CTEAssert(pSpxConnFile->scf_IndBytes == 0);
+ CTEAssert(pSpxConnFile->scf_PktSeqNum != pRecvResd->rr_SeqNum);
+
+ pSpxConnFile->scf_PktSeqNum = pRecvResd->rr_SeqNum;
+ pSpxConnFile->scf_PktFlags = pSpxConnFile->scf_Flags;
+ pSpxConnFile->scf_PktFlags2 = pSpxConnFile->scf_Flags2;
+#endif
+
+ pRecvResd->rr_State |= SPX_RECVPKT_INDICATED;
+
+ // Go ahead and walk the list of waiting packets. Get total size.
+ while ((pRecvResd->rr_Next != NULL) &&
+ ((pRecvResd->rr_State & SPX_RECVPKT_EOM) == 0))
+ {
+ // Check next packet.
+ pRecvResd = pRecvResd->rr_Next;
+
+#if DBG
+ CTEAssert(pSpxConnFile->scf_PktSeqNum != pRecvResd->rr_SeqNum);
+
+ pSpxConnFile->scf_PktSeqNum = pRecvResd->rr_SeqNum;
+ pSpxConnFile->scf_PktFlags = pSpxConnFile->scf_Flags;
+ pSpxConnFile->scf_PktFlags2 = pSpxConnFile->scf_Flags2;
+#endif
+
+ pRecvResd->rr_State |= SPX_RECVPKT_INDICATED;
+
+ pNdisPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pRecvResd, NDIS_PACKET, ProtocolReserved);
+
+ NdisQueryPacket(pNdisPkt, NULL, NULL, NULL, &bufSize);
+ CTEAssert(bufSize >= 0);
+
+ // Allow for zero data, eom only packets.
+ totalSize += bufSize;
+ }
+
+#if DBG
+ pSpxConnFile->scf_IndBytes = totalSize;
+ pSpxConnFile->scf_IndLine = __LINE__;
+
+ // There better not be any pending receives. If so, we have data
+ // corruption about to happen.
+ if (!IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage))
+ {
+ DBGBRK(FATAL);
+ KeBugCheck(0);
+ }
+#endif
+
+ indicateFlags = TDI_RECEIVE_NORMAL | TDI_RECEIVE_COPY_LOOKAHEAD;
+ if ((pRecvResd->rr_State & SPX_RECVPKT_EOM) != 0)
+ {
+ indicateFlags |= TDI_RECEIVE_ENTIRE_MESSAGE;
+ }
+
+ pRecvCtx = pSpxConnFile->scf_AddrFile->saf_RecvHandlerCtx;
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ bytesTaken = 0;
+ status = (*pRecvHandler)(
+ pRecvCtx,
+ pSpxConnFile->scf_ConnCtx,
+ indicateFlags,
+ lookaheadSize,
+ totalSize,
+ &bytesTaken,
+ lookaheadData,
+ &pRecvIrp);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnIndicatePendingData: IND Flags %lx Size %lx .%lx IND Status %lx\n",
+ indicateFlags,
+ totalSize,
+ bytesTaken,
+ status));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ if (status == STATUS_SUCCESS)
+ {
+ // Assume all data accepted. Free bytesTaken worth of data packets.
+ // Sometimes AFD returns STATUS_SUCCESS to just flush the data, so
+ // we can't assume it took only one packet (since lookahead only
+ // had that information).
+ CTEAssert(bytesTaken == totalSize);
+ SpxRecvFlushBytes(pSpxConnFile, totalSize, LockHandleConn);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ continue;
+ }
+ else if (status == STATUS_MORE_PROCESSING_REQUIRED)
+ {
+
+ // Queue irp into connection, change state to receive
+ // posted and fall thru.
+ pRequest = SpxAllocateRequest(
+ SpxDevice,
+ pRecvIrp);
+
+ IF_NOT_ALLOCATED(pRequest)
+ {
+ pRecvIrp->IoStatus.Status =
+ STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (pRecvIrp, IO_NETWORK_INCREMENT);
+ return (FALSE);
+ }
+
+ SpxConnQueueRecv(
+ pSpxConnFile,
+ pRequest);
+
+ fRecvQueued = TRUE;
+ }
+
+ break;
+ }
+
+ if (fLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ }
+
+ return fRecvQueued;
+}
+
+
+
+
+VOID
+SpxRecvProcessPkts(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+ Handle buffered data, complete irp if necessary. Set state to idle
+ if list becomes empty.
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+ BOOLEAN: More data left to indicate => TRUE
+
+--*/
+{
+ ULONG remainingDataLen, copyLen, bytesCopied;
+ PREQUEST pRequest;
+ NTSTATUS status;
+ BOOLEAN fEom;
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+ PSPX_RECV_RESD pRecvResd;
+ ULONG dataLen;
+ PBYTE pData;
+ LIST_ENTRY *p;
+ BOOLEAN fLockHeld = TRUE, fMoreData = TRUE, fWdwOpen = FALSE;
+ USHORT discState = 0;
+ int numDerefs = 0;
+
+ if (SPX_RECV_STATE(pSpxConnFile) != SPX_RECV_PROCESS_PKTS)
+ {
+ SPX_RECV_SETSTATE(pSpxConnFile, SPX_RECV_PROCESS_PKTS);
+
+ProcessReceives:
+
+ while ((pSpxConnFile->scf_CurRecvReq != NULL) &&
+ ((pRecvResd = pSpxConnFile->scf_RecvListHead) != NULL))
+ {
+ // A buffering recv packet will have one ndis buffer descriptor
+ // queued in, which will describe a segment of memory we have
+ // allocated. An offset will also be present indicating the data
+ // to start reading from (or to indicate from to AFD).
+ CTEAssert((pRecvResd->rr_State & SPX_RECVPKT_BUFFERING) != 0);
+
+ pNdisPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pRecvResd, NDIS_PACKET, ProtocolReserved);
+
+ NdisQueryPacket(pNdisPkt, NULL, NULL, &pNdisBuffer, NULL);
+
+ // Initialize pData
+ pData = NULL;
+ dataLen = 0;
+
+ if (pNdisBuffer != NULL)
+ {
+ NdisQueryBuffer(pNdisBuffer, &pData, &dataLen);
+ CTEAssert(pData != NULL);
+ CTEAssert(dataLen >= 0);
+ }
+
+ // Allow for zero data, eom only packets.
+ remainingDataLen = dataLen - pRecvResd->rr_DataOffset;
+
+ // If this packet contained data then eom must also have been
+ // indicated at the time all the data was consumed.
+ CTEAssert((remainingDataLen > 0) ||
+ ((pRecvResd->rr_DataOffset == 0) &&
+ ((pRecvResd->rr_State & SPX_RECVPKT_EOM) != 0)));
+
+ status = STATUS_SUCCESS;
+ copyLen = 0;
+ if (remainingDataLen > 0)
+ {
+ copyLen = MIN(remainingDataLen, pSpxConnFile->scf_CurRecvSize);
+ status = TdiCopyBufferToMdl(
+ pData,
+ pRecvResd->rr_DataOffset,
+ copyLen,
+ REQUEST_TDI_BUFFER(pSpxConnFile->scf_CurRecvReq),
+ pSpxConnFile->scf_CurRecvOffset,
+ &bytesCopied);
+
+ CTEAssert(NT_SUCCESS(status));
+ if (!NT_SUCCESS(status))
+ {
+ // Abort request with this status. Reset request
+ // queue to next request if one is available.
+ copyLen = pSpxConnFile->scf_CurRecvSize;
+ }
+ }
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessRecdPkts: %lx Pkt %lx Data %lx Size %lx F %lx\n",
+ pSpxConnFile, pNdisPkt, pData, copyLen, pRecvResd->rr_State));
+
+ // Adjust various values to see whats done whats not
+ pRecvResd->rr_DataOffset += (USHORT)copyLen;
+ pSpxConnFile->scf_CurRecvSize -= (USHORT)copyLen;
+ pSpxConnFile->scf_CurRecvOffset += (USHORT)copyLen;
+
+#if DBG
+ // If this packet was part of indicated data count, decrement.
+ if ((pRecvResd->rr_State & SPX_RECVPKT_INDICATED) != 0)
+ {
+ if (copyLen != 0)
+ {
+ CTEAssert (pSpxConnFile->scf_IndBytes != 0);
+ pSpxConnFile->scf_IndBytes -= copyLen;
+ }
+ }
+#endif
+
+ // Set fEom/discState (init to 0) only if all of packet was consumed.
+ fEom = FALSE;
+ if (pRecvResd->rr_DataOffset == dataLen)
+ {
+ fEom = (BOOLEAN)((pRecvResd->rr_State & SPX_RECVPKT_EOM) != 0);
+
+ // Remember if disconnect needed to happen. If set, this better be
+ // last packet received. Again, only if entire pkt was consumed.
+ discState = (pRecvResd->rr_State & SPX_RECVPKT_DISCMASK);
+ CTEAssert((discState == 0) ||
+ (pRecvResd == pSpxConnFile->scf_RecvListTail));
+
+ // Packet consumed. Free it up.
+ numDerefs++;
+
+ SpxConnDequeueRecvPktLock(pSpxConnFile, pNdisPkt);
+ INCREMENT_WINDOW(pSpxConnFile);
+
+ fWdwOpen = TRUE;
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessRecdPkts: %lx Pkt %lx Data %lx DEQUEUED\n",
+ pSpxConnFile, pNdisPkt, pData));
+
+ if (pNdisBuffer != NULL)
+ {
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ NdisFreeBuffer(pNdisBuffer);
+ SpxFreeMemory(pData);
+ }
+
+ SpxPktRecvRelease(pNdisPkt);
+ }
+ else
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessRecdPkts: %lx Pkt %lx PARTIAL USE %lx.%lx\n",
+ pSpxConnFile, pNdisPkt, pRecvResd->rr_DataOffset, dataLen));
+ }
+
+ // Don't complete until we are out of all packets and stream mode or...
+ if (((pSpxConnFile->scf_RecvListHead == NULL) &&
+ SPX_CONN_STREAM(pSpxConnFile)) ||
+ (pSpxConnFile->scf_CurRecvSize == 0) ||
+ fEom)
+ {
+ // Done with receive, move to completion or complete depending on
+ // call level.
+ pRequest = pSpxConnFile->scf_CurRecvReq;
+
+ // Set status. Complete with error from TdiCopy if so.
+ REQUEST_INFORMATION(pRequest) = pSpxConnFile->scf_CurRecvOffset;
+ REQUEST_STATUS(pRequest) = status;
+
+ // Ensure we dont overwrite an error status.
+ if (!SPX_CONN_STREAM(pSpxConnFile) &&
+ (pSpxConnFile->scf_CurRecvSize == 0) &&
+ !fEom &&
+ NT_SUCCESS(status))
+ {
+ REQUEST_STATUS(pRequest) = STATUS_RECEIVE_PARTIAL;
+ }
+
+ // Dequeue this request, set next recv if one exists.
+ SPX_CONN_SETNEXT_CUR_RECV(pSpxConnFile, pRequest);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessRecdPkts: %lx Recv %lx with %lx.%lx\n",
+ pSpxConnFile, pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+#if DBG
+ if ((REQUEST_STATUS(pRequest) == STATUS_SUCCESS) &&
+ (REQUEST_INFORMATION(pRequest) == 0))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxReceiveComplete: Completing %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+ }
+#endif
+
+ // Request is done. Move to receive completion list. There
+ // could already be previously queued requests in here.
+ InsertTailList(
+ &pSpxConnFile->scf_RecvDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+ }
+
+ CTEAssert((discState == 0) ||
+ (pSpxConnFile->scf_RecvListHead == NULL));
+ }
+
+ // Complete any completed receives
+ while ((p = pSpxConnFile->scf_RecvDoneLinkage.Flink) !=
+ &pSpxConnFile->scf_RecvDoneLinkage)
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ DBGPRINT(TDI, DBG,
+ ("SpxConnDiscPkt: PENDING REQ COMP %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+#if DBG
+ if ((REQUEST_STATUS(pRequest) == STATUS_SUCCESS) &&
+ (REQUEST_INFORMATION(pRequest) == 0))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxReceiveComplete: Completing %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+ }
+#endif
+
+ SpxCompleteRequest(pRequest);
+ numDerefs++;
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ }
+
+ fMoreData = ((pSpxConnFile->scf_RecvListHead != NULL) &&
+ ((pSpxConnFile->scf_RecvListHead ->rr_State &
+ SPX_RECVPKT_BUFFERING) != 0) &&
+ ((pSpxConnFile->scf_RecvListHead->rr_State &
+ SPX_RECVPKT_INDICATED) == 0));
+
+ while (fMoreData)
+ {
+ // Bug #21036
+ // If there is a receive waiting to be processed, we better not
+ // indicate data before we finish it.
+ if (pSpxConnFile->scf_CurRecvReq != NULL)
+ goto ProcessReceives;
+
+ // If a receive was queued the goto beginning again.
+ if (SpxRecvIndicatePendingData(pSpxConnFile, LockHandleConn))
+ {
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ goto ProcessReceives;
+ }
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ fMoreData = ((pSpxConnFile->scf_RecvListHead != NULL) &&
+ ((pSpxConnFile->scf_RecvListHead ->rr_State &
+ SPX_RECVPKT_BUFFERING) != 0) &&
+ ((pSpxConnFile->scf_RecvListHead->rr_State &
+ SPX_RECVPKT_INDICATED) == 0));
+ }
+
+ // Set state
+ SPX_RECV_SETSTATE(
+ pSpxConnFile,
+ (pSpxConnFile->scf_CurRecvReq == NULL) ?
+ SPX_RECV_IDLE : SPX_RECV_POSTED);
+ }
+#if DBG
+ else
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("spxConnProcessRecdPkts: Already processing pkts %lx\n",
+ pSpxConnFile));
+ }
+#endif
+
+ if (fWdwOpen && (pSpxConnFile->scf_RecvListHead == NULL))
+ {
+ // Send an ack as our windows probably opened up. Dont wait to
+ // piggyback here...
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessRecdPkts: Send ACK %lx\n",
+ pSpxConnFile));
+
+#if DBG_WDW_CLOSE
+ // If packets been indicated we have started buffering. Also
+ // check if window is now zero.
+ {
+ LARGE_INTEGER li, ntTime;
+ int value;
+
+ li = pSpxConnFile->scf_WdwCloseTime;
+ if (li.LowPart && li.HighPart)
+ {
+ KeQuerySystemTime(&ntTime);
+
+ // Get the difference
+ ntTime.QuadPart = ntTime.QuadPart - li.QuadPart;
+
+ // Convert to milliseconds. If the highpart is 0, we
+ // take a shortcut.
+ if (ntTime.HighPart == 0)
+ {
+ value = ntTime.LowPart/10000;
+ }
+ else
+ {
+ ntTime = SPX_CONVERT100NSTOCENTISEC(ntTime);
+ value = ntTime.LowPart << 4;
+ }
+
+ // Set new average close time
+ pSpxConnFile->scf_WdwCloseAve += value;
+ pSpxConnFile->scf_WdwCloseAve /= 2;
+ DBGPRINT(RECEIVE, DBG,
+ ("V %ld AVE %ld\n",
+ value, pSpxConnFile->scf_WdwCloseAve));
+ }
+ }
+#endif
+
+ SpxConnSendAck(pSpxConnFile, LockHandleConn);
+ fLockHeld = FALSE;
+ }
+
+ // Check if disconnect happened
+ switch (discState)
+ {
+ case SPX_RECVPKT_IDISC:
+
+ CTEAssert(!fMoreData);
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+
+ if (!fLockHeld)
+ {
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ }
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessRecdPkts: Buffered IDISC %lx\n",
+ pSpxConnFile, fMoreData));
+
+ SpxConnProcessIDisc(pSpxConnFile, LockHandleConn);
+ fLockHeld = FALSE;
+ break;
+
+ case SPX_RECVPKT_ORD_DISC:
+
+ CTEAssert(!fMoreData);
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+
+ if (!fLockHeld)
+ {
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ }
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessRecdPkts: Buffered ORDREL %lx\n",
+ pSpxConnFile, fMoreData));
+
+ SpxConnProcessOrdRel(pSpxConnFile, LockHandleConn);
+ fLockHeld = FALSE;
+ break;
+
+ case (SPX_RECVPKT_IDISC | SPX_RECVPKT_ORD_DISC):
+
+ // IDISC has more priority.
+ CTEAssert(!fMoreData);
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+
+ if (!fLockHeld)
+ {
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ }
+
+ DBGPRINT(RECEIVE, ERR,
+ ("spxConnProcessRecdPkts: Buffered IDISC *AND* ORDREL %lx\n",
+ pSpxConnFile, fMoreData));
+
+ SpxConnProcessIDisc(pSpxConnFile, LockHandleConn);
+ fLockHeld = FALSE;
+ break;
+
+ default:
+
+ break;
+ }
+
+ if (fLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
diff --git a/private/ntos/tdi/isn/spx/spxreg.c b/private/ntos/tdi/isn/spx/spxreg.c
new file mode 100644
index 000000000..4389dca5f
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxreg.c
@@ -0,0 +1,400 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxreg.c
+
+Abstract:
+
+ This contains all routines necessary for the support of the dynamic
+ configuration of the ISN SPX module.
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXREG
+
+// Local functions used to access the registry.
+NTSTATUS
+SpxInitReadIpxDeviceName(
+ VOID);
+
+NTSTATUS
+SpxInitSetIpxDeviceName(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext);
+
+NTSTATUS
+SpxInitGetConfigValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext);
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT, SpxInitGetConfiguration)
+#pragma alloc_text(INIT, SpxInitFreeConfiguration)
+#pragma alloc_text(INIT, SpxInitGetConfigValue)
+#pragma alloc_text(INIT, SpxInitReadIpxDeviceName)
+#pragma alloc_text(INIT, SpxInitSetIpxDeviceName)
+#endif
+
+
+NTSTATUS
+SpxInitGetConfiguration (
+ IN PUNICODE_STRING RegistryPath,
+ OUT PCONFIG * ConfigPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by SPX to get information from the configuration
+ management routines. We read the registry, starting at RegistryPath,
+ to get the parameters. If they don't exist, we use the defaults
+ set in ipxcnfg.h file. A list of adapters to bind to is chained
+ on to the config information.
+
+Arguments:
+
+ RegistryPath - The name of ST's node in the registry.
+
+ ConfigPtr - Returns the configuration information.
+
+Return Value:
+
+ Status - STATUS_SUCCESS if everything OK, STATUS_INSUFFICIENT_RESOURCES
+ otherwise.
+
+--*/
+{
+ NTSTATUS Status;
+ UINT i;
+ PWSTR RegistryPathBuffer;
+ PCONFIG Config;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[CONFIG_PARAMETERS+2];
+
+ ULONG Zero = 0;
+ ULONG Two = 2;
+ ULONG Four = 4;
+ ULONG Five = 5;
+ ULONG Eight = 8;
+ ULONG Twelve = 12;
+ ULONG Fifteen = 15;
+ ULONG Thirty = 30;
+ ULONG FiveHundred = 500;
+ ULONG Hex4000 = 0x4000;
+ ULONG Hex7FFF = 0x7FFF;
+ ULONG FourK = 4096;
+
+ PWSTR Parameters = L"Parameters";
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[CONFIG_PARAMETERS] = {
+ { L"ConnectionCount", &Five },
+ { L"ConnectionTimeout", &Two },
+ { L"InitPackets", &Five },
+ { L"MaxPackets", &Thirty},
+ { L"InitialRetransmissionTime", &FiveHundred},
+ { L"KeepAliveCount", &Eight},
+ { L"KeepAliveTimeout", &Twelve},
+ { L"WindowSize", &Four},
+ { L"SpxSocketRangeStart", &Hex4000},
+ { L"SpxSocketRangeEnd", &Hex7FFF},
+ { L"SpxSocketUniqueness", &Eight},
+ { L"MaxPacketSize", &FourK},
+ { L"RetransmissionCount", &Eight},
+ { L"DisableSpx2", &Zero},
+ { L"RouterMtu", &Zero},
+ { L"BackCompSpx", &Zero}
+ };
+
+ if (!NT_SUCCESS(SpxInitReadIpxDeviceName()))
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Allocate memory for the main config structure.
+ Config = CTEAllocMem (sizeof(CONFIG));
+ if (Config == NULL) {
+ TMPLOGERR();
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Config->cf_DeviceName.Buffer = NULL;
+
+ // SpxReadLinkageInformation expects a null-terminated path,
+ // so we have to create one from the UNICODE_STRING.
+ RegistryPathBuffer = (PWSTR)CTEAllocMem(RegistryPath->Length + sizeof(WCHAR));
+
+ if (RegistryPathBuffer == NULL) {
+
+ SpxInitFreeConfiguration(Config);
+
+ TMPLOGERR();
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (
+ RegistryPathBuffer,
+ RegistryPath->Buffer,
+ RegistryPath->Length);
+
+ *(PWCHAR)(((PUCHAR)RegistryPathBuffer)+RegistryPath->Length) = (WCHAR)'\0';
+
+ Config->cf_RegistryPathBuffer = RegistryPathBuffer;
+
+ // Read the per-transport (as opposed to per-binding)
+ // parameters.
+ //
+ // Set up QueryTable to do the following:
+ // 1) Switch to the Parameters key below SPX
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Parameters;
+
+ // 2-14) Call SpxSetBindingValue for each of the keys we
+ // care about.
+ for (i = 0; i < CONFIG_PARAMETERS; i++) {
+
+ QueryTable[i+1].QueryRoutine = SpxInitGetConfigValue;
+ QueryTable[i+1].Flags = 0;
+ QueryTable[i+1].Name = ParameterValues[i].KeyName;
+ QueryTable[i+1].EntryContext = (PVOID)i;
+ QueryTable[i+1].DefaultType = REG_DWORD;
+ QueryTable[i+1].DefaultData = (PVOID)(ParameterValues[i].DefaultValue);
+ QueryTable[i+1].DefaultLength = sizeof(ULONG);
+ }
+
+ // 15) Stop
+ QueryTable[CONFIG_PARAMETERS+1].QueryRoutine = NULL;
+ QueryTable[CONFIG_PARAMETERS+1].Flags = 0;
+ QueryTable[CONFIG_PARAMETERS+1].Name = NULL;
+
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->cf_RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+ SpxInitFreeConfiguration(Config);
+
+ TMPLOGERR();
+ return Status;
+ }
+
+ CTEFreeMem (RegistryPathBuffer);
+ *ConfigPtr = Config;
+
+ return STATUS_SUCCESS;
+
+} // SpxInitGetConfiguration
+
+
+
+
+VOID
+SpxInitFreeConfiguration (
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by SPX to get free any storage that was allocated
+ by SpxGetConfiguration in producing the specified CONFIG structure.
+
+Arguments:
+
+ Config - A pointer to the configuration information structure.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ CTEFreeMem (Config);
+
+} // SpxInitFreeConfig
+
+
+
+
+NTSTATUS
+SpxInitGetConfigValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each entry in the Parameters
+ node to set the config values. The table is set up
+ so that this function will be called with correct default
+ values for keys that are not present.
+
+Arguments:
+
+ ValueName - The name of the value (ignored).
+
+ ValueType - The type of the value (REG_DWORD -- ignored).
+
+ ValueData - The data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to the CONFIG structure.
+
+ EntryContext - The index in Config->Parameters to save the value.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+
+ if ((ValueType != REG_DWORD) || (ValueLength != sizeof(ULONG))) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ DBGPRINT(CONFIG, INFO,
+ ("Config parameter %d, value %lx\n",
+ (ULONG)EntryContext, *(UNALIGNED ULONG *)ValueData));
+
+ Config->cf_Parameters[(ULONG)EntryContext] = *(UNALIGNED ULONG *)ValueData;
+ return STATUS_SUCCESS;
+
+} // SpxInitGetConfigValue
+
+
+
+
+NTSTATUS
+SpxInitReadIpxDeviceName(
+ VOID
+ )
+
+{
+ NTSTATUS Status;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+ PWSTR Export = L"Export";
+ PWSTR IpxRegistryPath = IPX_REG_PATH;
+
+ // Set up QueryTable to do the following:
+ //
+ // 1) Call SetIpxDeviceName for the string in "Export"
+ QueryTable[0].QueryRoutine = SpxInitSetIpxDeviceName;
+ QueryTable[0].Flags = 0;
+ QueryTable[0].Name = Export;
+ QueryTable[0].EntryContext = NULL;
+ QueryTable[0].DefaultType = REG_NONE;
+
+ // 2) Stop
+ QueryTable[1].QueryRoutine = NULL;
+ QueryTable[1].Flags = 0;
+ QueryTable[1].Name = NULL;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ IpxRegistryPath,
+ QueryTable,
+ NULL,
+ NULL);
+
+ return Status;
+}
+
+
+
+
+NTSTATUS
+SpxInitSetIpxDeviceName(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Export" multi-string and
+ saves the information in a ConfigurationInfo structure.
+
+Arguments:
+
+ ValueName - The name of the value ("Export" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - NULL.
+
+ EntryContext - NULL.
+
+Return Value:
+
+ status
+
+--*/
+
+{
+ PWSTR fileName;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ fileName = (PWSTR)CTEAllocMem(ValueLength);
+ if (fileName != NULL) {
+ RtlCopyMemory(fileName, ValueData, ValueLength);
+ RtlInitUnicodeString (&IpxDeviceName, fileName);
+ }
+ else
+ {
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ return(status);
+}
+
diff --git a/private/ntos/tdi/isn/spx/spxsend.c b/private/ntos/tdi/isn/spx/spxsend.c
new file mode 100644
index 000000000..6b856953d
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxsend.c
@@ -0,0 +1,262 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxsend.c
+
+Abstract:
+
+ This module contains code that implements the send engine for the
+ SPX transport provider.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+// Define module number for event logging entries
+#define FILENUM SPXSEND
+
+VOID
+SpxSendComplete(
+ IN PNDIS_PACKET pNdisPkt,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to indicate that a connection-
+ oriented packet has been shipped and is no longer needed by the Physical
+ Provider.
+
+Arguments:
+
+ ProtocolBindingContext - The ADAPTER structure for this binding.
+
+ NdisPacket/RequestHandle - A pointer to the NDIS_PACKET that we sent.
+
+ NdisStatus - the completion status of the send.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PSPX_CONN_FILE pSpxConnFile;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_BUFFER pNdisBuffer;
+ CTELockHandle lockHandle;
+ UINT bufCount;
+ PREQUEST pRequest = NULL;
+ BOOLEAN completeReq = FALSE, freePkt = FALSE,
+ orphaned = FALSE, lockHeld = FALSE;
+
+ pSendResd = (PSPX_SEND_RESD)(pNdisPkt->ProtocolReserved);
+
+#if DBG
+ if (NdisStatus != NDIS_STATUS_SUCCESS)
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: For %lx with status **%lx**\n",
+ pNdisPkt, NdisStatus));
+ }
+#endif
+
+ // IPX changes the length set for the first ndis buffer descriptor.
+ // Change it back to its original value here.
+ NdisQueryPacket(pNdisPkt, NULL, &bufCount, &pNdisBuffer, NULL);
+ NdisAdjustBufferLength(pNdisBuffer, IpxMacHdrNeeded + MIN_IPXSPX2_HDRSIZE);
+
+ do
+ {
+ pSpxConnFile = pSendResd->sr_ConnFile;
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ lockHeld = TRUE;
+#if defined(__PNP)
+ //
+ // if IPX gave us a new LocalTarget, use for our next send.
+ //
+ // But if we are sending connect requests by iterating over NicIds,
+ // dont update the local target bcoz that will screw up our iteration
+ // logic.
+ //
+ if ( DEVICE_NETWORK_PATH_NOT_FOUND == NdisStatus
+ &&
+ !(
+ SPX_CONN_CONNECTING(pSpxConnFile) &&
+ (SPX_CONNECT_STATE(pSpxConnFile) == SPX_CONNECT_SENTREQ) &&
+ (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0)
+ ) ) {
+
+ pSpxConnFile->scf_LocalTarget = pSendResd->LocalTarget;
+
+ //
+ // Renegotiate the max packet size if we have an active SPX2
+ // session going on and we negotiated the max size originally.
+ //
+ if ( SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_ACTIVE &&
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2) &&
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG) ) {
+
+ //
+ // this call will get the local max size on this new local target
+ // from IPX.
+ //
+ SPX_MAX_PKT_SIZE(pSpxConnFile, TRUE, TRUE, *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr );
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RENEG);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: %lx CONNECTION ENTERING RENEG\n",
+ pSpxConnFile));
+ }
+
+ }
+#endif __PNP
+
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0);
+
+ // IPX dont own this packet nomore.
+ pSendResd->sr_State &= ~SPX_SENDPKT_IPXOWNS;
+
+ // If a send packet has been aborted, then we need to call
+ // abort send to go ahead and free up this packet, and deref associated
+ // request, if there is one, potentially completing it.
+ if ((pSendResd->sr_State & SPX_SENDPKT_ABORT) != 0)
+ {
+ spxConnAbortSendPkt(
+ pSpxConnFile,
+ pSendResd,
+ SPX_CALL_TDILEVEL,
+ lockHandle);
+
+ lockHeld = FALSE;
+ break;
+ }
+
+ // If there is an associated request, remove reference on it. BUT for a
+ // sequenced packet only if it has been acked and is waiting for the request
+ // to be dereferenced. It is already dequeued from queue, just free it up.
+ if ((((pSendResd->sr_State & SPX_SENDPKT_REQ) != 0) &&
+ ((pSendResd->sr_State & SPX_SENDPKT_SEQ) == 0)) ||
+ ((pSendResd->sr_State & SPX_SENDPKT_ACKEDPKT) != 0))
+ {
+ freePkt = (BOOLEAN)((pSendResd->sr_State & SPX_SENDPKT_ACKEDPKT) != 0);
+
+ pRequest = pSendResd->sr_Request;
+ CTEAssert(pRequest != NULL);
+
+ DBGPRINT(SEND, DBG,
+ ("IpxSendComplete: ReqRef before dec %lx.%lx\n",
+ pRequest, REQUEST_INFORMATION(pRequest)));
+
+ // Deref the request and see if we complete it now. We always have our
+ // own reference on the request.
+ // !!! Status should already have been set in request...!!!
+ if (--(REQUEST_INFORMATION(pRequest)) == 0)
+ {
+ CTEAssert(REQUEST_STATUS(pRequest) != STATUS_PENDING);
+
+ completeReq = TRUE;
+
+ // If this is acked already, request is not on list.
+ // BUG #11626
+ if ((pSendResd->sr_State & SPX_SENDPKT_ACKEDPKT) == 0)
+ {
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+ }
+ }
+ }
+
+ // Do we destroy this packet?
+ if ((pSendResd->sr_State & SPX_SENDPKT_DESTROY) != 0)
+ {
+ // Remove this packet from the send list in the connection.
+ DBGPRINT(SEND, INFO,
+ ("IpxSendComplete: destroy packet...\n"));
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pNdisPkt);
+ freePkt = TRUE;
+ }
+
+ } while (FALSE);
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ if (freePkt)
+ {
+ DBGPRINT(SEND, INFO,
+ ("IpxSendComplete: free packet...\n"));
+
+ SpxPktSendRelease(pNdisPkt);
+ }
+
+ if (completeReq)
+ {
+ // If this is a send request, set info to data sent, else it will be
+ // zero.
+ if (REQUEST_MINOR_FUNCTION(pRequest) == TDI_SEND)
+ {
+ PTDI_REQUEST_KERNEL_SEND pParam;
+
+ pParam = (PTDI_REQUEST_KERNEL_SEND)
+ REQUEST_PARAMETERS(pRequest);
+
+ REQUEST_INFORMATION(pRequest) = pParam->SendLength;
+ DBGPRINT(SEND, DBG,
+ ("IpxSendComplete: complete req %lx.%lx...\n",
+ REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ CTEAssert(pRequest != NULL);
+ CTEAssert(REQUEST_STATUS(pRequest) != STATUS_PENDING);
+ SpxCompleteRequest(pRequest);
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: %lx DISC Request %lx with %lx.%lx\n",
+ pSpxConnFile, pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: %lx.%lx.%lx\n",
+ pSpxConnFile->scf_RefCount,
+ pSpxConnFile->scf_Flags,
+ pSpxConnFile->scf_Flags2));
+
+ // Set the request in the connection, and deref for it.
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+ }
+
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+
+} // SpxSendComplete
+
+
+
diff --git a/private/ntos/tdi/isn/spx/spxtimer.c b/private/ntos/tdi/isn/spx/spxtimer.c
new file mode 100644
index 000000000..bdb4e1d7f
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxtimer.c
@@ -0,0 +1,637 @@
+/*
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ spxtimer.c
+
+Abstract:
+
+ This file implements the timer routines used by the stack.
+
+Author:
+
+ Jameel Hyder (jameelh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+
+Revision History:
+ 23 Feb 1993 Initial Version
+
+Notes: Tab stop: 4
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXTIMER
+
+// Discardable code after Init time
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT, SpxTimerInit)
+#endif
+
+// Globals for this module
+PTIMERLIST spxTimerList = NULL;
+PTIMERLIST spxTimerTable[TIMER_HASH_TABLE] = {0};
+PTIMERLIST spxTimerActive = NULL;
+CTELock spxTimerLock = {0};
+LARGE_INTEGER spxTimerTick = {0};
+KTIMER spxTimer = {0};
+KDPC spxTimerDpc = {0};
+ULONG spxTimerId = 1;
+LONG spxTimerCount = 0;
+USHORT spxTimerDispatchCount = 0;
+BOOLEAN spxTimerStopped = FALSE;
+
+
+NTSTATUS
+SpxTimerInit(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Initialize the timer component for the appletalk stack.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+#if !defined(_PNP_POWER)
+ BOOLEAN TimerStarted;
+#endif !_PNP_POWER
+
+ // Initialize the timer and its associated Dpc. timer will be kicked
+ // off when we get the first card arrival notification from ipx
+ KeInitializeTimer(&spxTimer);
+ CTEInitLock(&spxTimerLock);
+ KeInitializeDpc(&spxTimerDpc, spxTimerDpcRoutine, NULL);
+ spxTimerTick = RtlConvertLongToLargeInteger(SPX_TIMER_TICK);
+#if !defined(_PNP_POWER)
+ TimerStarted = KeSetTimer(&spxTimer,
+ spxTimerTick,
+ &spxTimerDpc);
+ CTEAssert(!TimerStarted);
+#endif !_PNP_POWER
+ return STATUS_SUCCESS;
+}
+
+
+
+
+ULONG
+SpxTimerScheduleEvent(
+ IN TIMER_ROUTINE Worker, // Routine to invoke when time expires
+ IN ULONG MsTime, // Schedule after this much time
+ IN PVOID pContext // Context(s) to pass to the routine
+ )
+/*++
+
+Routine Description:
+
+ Insert an event in the timer event list. If the list is empty, then
+ fire off a timer. The time is specified in ms. We convert to ticks.
+ Each tick is currently 100ms. It may not be zero or negative. The internal
+ timer fires at 100ms granularity.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PTIMERLIST pList;
+ CTELockHandle lockHandle;
+ ULONG DeltaTime;
+ ULONG Id = 0;
+
+ // Convert to ticks.
+ DeltaTime = MsTime/SPX_MS_TO_TICKS;
+ if (DeltaTime == 0)
+ {
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxTimerScheduleEvent: Converting %ld to ticks %ld\n",
+ MsTime, DeltaTime));
+
+ DeltaTime = 1;
+ }
+
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxTimerScheduleEvent: Converting %ld to ticks %ld\n",
+ MsTime, DeltaTime));
+
+ // Negative or Zero DeltaTime is invalid.
+ CTEAssert (DeltaTime > 0);
+
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxTimerScheduleEvent: Routine %lx, Time %d, Context %lx\n",
+ Worker, DeltaTime, pContext));
+
+ CTEGetLock(&spxTimerLock, &lockHandle);
+
+ if (spxTimerStopped)
+ {
+ DBGPRINT(SYSTEM, FATAL,
+ ("SpxTimerScheduleEvent: Called after Flush !!\n"));
+ }
+
+ else do
+ {
+ pList = SpxBPAllocBlock(BLKID_TIMERLIST);
+
+ if (pList == NULL)
+ {
+ break;
+ }
+
+#if DBG
+ pList->tmr_Signature = TMR_SIGNATURE;
+#endif
+ pList->tmr_Cancelled = FALSE;
+ pList->tmr_Worker = Worker;
+ pList->tmr_AbsTime = DeltaTime;
+ pList->tmr_Context = pContext;
+
+ Id = pList->tmr_Id = spxTimerId++;
+
+ // Take care of wrap around
+ if (spxTimerId == 0)
+ spxTimerId = 1;
+
+ // Enqueue this handler
+ spxTimerEnqueue(pList);
+ } while (FALSE);
+
+ CTEFreeLock(&spxTimerLock, lockHandle);
+
+ return Id;
+}
+
+
+
+VOID
+spxTimerDpcRoutine(
+ IN PKDPC pKDpc,
+ IN PVOID pContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+/*++
+
+Routine Description:
+
+ This is called in at DISPATCH_LEVEL when the timer expires. The entry at
+ the head of the list is decremented and if ZERO unlinked and dispatched.
+ If the list is non-empty, the timer is fired again.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PTIMERLIST pList, *ppList;
+ BOOLEAN TimerStarted;
+ ULONG ReEnqueueTime;
+ CTELockHandle lockHandle;
+
+ pKDpc; pContext; SystemArgument1; SystemArgument2;
+
+#if defined(_PNP_POWER)
+ CTEGetLock(&spxTimerLock, &lockHandle);
+ if (spxTimerStopped)
+ {
+ DBGPRINT(SYSTEM, ERR,
+ ("spxTimerDpc: Enetered after Flush !!!\n"));
+
+ CTEFreeLock(&spxTimerLock, lockHandle);
+ return;
+ }
+#else
+ if (spxTimerStopped)
+ {
+ DBGPRINT(SYSTEM, ERR,
+ ("spxTimerDpc: Enetered after Flush !!!\n"));
+ return;
+ }
+
+ CTEGetLock(&spxTimerLock, &lockHandle);
+#endif _PNP_POWER
+
+ SpxTimerCurrentTime ++; // Update our relative time
+
+#ifdef PROFILING
+ // This is the only place where this is changed. And it always increases.
+ SpxStatistics.stat_ElapsedTime = SpxTimerCurrentTime;
+#endif
+
+ // We should never be here if we have no work to do
+ if ((spxTimerList != NULL))
+ {
+ // Careful here. If two guys wanna go off together - let them !!
+ if (spxTimerList->tmr_RelDelta != 0)
+ (spxTimerList->tmr_RelDelta)--;
+
+ // Dispatch the entry if it is ready to go
+ if (spxTimerList->tmr_RelDelta == 0)
+ {
+ pList = spxTimerList;
+ CTEAssert(VALID_TMR(pList));
+
+ // Unlink from the list
+ spxTimerList = pList->tmr_Next;
+ if (spxTimerList != NULL)
+ spxTimerList->tmr_Prev = &spxTimerList;
+
+ // Unlink from the hash table now
+ for (ppList = &spxTimerTable[pList->tmr_Id % TIMER_HASH_TABLE];
+ *ppList != NULL;
+ ppList = &((*ppList)->tmr_Overflow))
+ {
+ CTEAssert(VALID_TMR(*ppList));
+ if (*ppList == pList)
+ {
+ *ppList = pList->tmr_Overflow;
+ break;
+ }
+ }
+
+ CTEAssert (*ppList == pList->tmr_Overflow);
+
+ DBGPRINT(SYSTEM, INFO,
+ ("spxTimerDpcRoutine: Dispatching %lx\n",
+ pList->tmr_Worker));
+
+ spxTimerDispatchCount ++;
+ spxTimerCount --;
+ spxTimerActive = pList;
+ CTEFreeLock(&spxTimerLock, lockHandle);
+
+ // If reenqueue time is 0, do not requeue. If 1, then requeue with
+ // current value, else use value specified.
+ ReEnqueueTime = (*pList->tmr_Worker)(pList->tmr_Context, FALSE);
+ DBGPRINT(SYSTEM, INFO,
+ ("spxTimerDpcRoutine: Reenequeu time %lx.%lx\n",
+ ReEnqueueTime, pList->tmr_AbsTime));
+
+ CTEGetLock(&spxTimerLock, &lockHandle);
+
+ spxTimerActive = NULL;
+ spxTimerDispatchCount --;
+
+ if (ReEnqueueTime != TIMER_DONT_REQUEUE)
+ {
+ // If this chappie was cancelled while it was running
+ // and it wants to be re-queued, do it right away.
+ if (pList->tmr_Cancelled)
+ {
+ (*pList->tmr_Worker)(pList->tmr_Context, FALSE);
+ SpxBPFreeBlock(pList, BLKID_TIMERLIST);
+ }
+ else
+ {
+ if (ReEnqueueTime != TIMER_REQUEUE_CUR_VALUE)
+ {
+ pList->tmr_AbsTime = ReEnqueueTime/SPX_MS_TO_TICKS;
+ if (pList->tmr_AbsTime == 0)
+ {
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxTimerDispatch: Requeue at %ld\n",
+ pList->tmr_AbsTime));
+ }
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxTimerDispatch: Requeue at %ld.%ld\n",
+ ReEnqueueTime, pList->tmr_AbsTime));
+ }
+
+ spxTimerEnqueue(pList);
+ }
+ }
+ else
+ {
+ SpxBPFreeBlock(pList, BLKID_TIMERLIST);
+ }
+ }
+ }
+
+#if defined(_PNP_POWER)
+ if (!spxTimerStopped)
+ {
+ TimerStarted = KeSetTimer(&spxTimer,
+ spxTimerTick,
+ &spxTimerDpc);
+
+ // it is possible that while we were here in Dpc, PNP_ADD_DEVICE
+ // restarted the timer, so this assert is commented out for PnP
+// CTEAssert(!TimerStarted);
+ }
+
+ CTEFreeLock(&spxTimerLock, lockHandle);
+#else
+ CTEFreeLock(&spxTimerLock, lockHandle);
+
+ if (!spxTimerStopped)
+ {
+ TimerStarted = KeSetTimer(&spxTimer,
+ spxTimerTick,
+ &spxTimerDpc);
+ CTEAssert(!TimerStarted);
+ }
+#endif _PNP_POWER
+}
+
+
+VOID
+spxTimerEnqueue(
+ IN PTIMERLIST pListNew
+ )
+/*++
+
+Routine Description:
+
+ Here is a thesis on the code that follows.
+
+ The timer events are maintained as a list which the timer dpc routine
+ looks at every timer tick. The list is maintained in such a way that only
+ the head of the list needs to be updated every tick i.e. the entire list
+ is never scanned. The way this is achieved is by keeping delta times
+ relative to the previous entry.
+
+ Every timer tick, the relative time at the head of the list is decremented.
+ When that goes to ZERO, the head of the list is unlinked and dispatched.
+
+ To give an example, we have the following events queued at time slots
+ X Schedule A after 10 ticks.
+ X+3 Schedule B after 5 ticks.
+ X+5 Schedule C after 4 ticks.
+ X+8 Schedule D after 6 ticks.
+
+ So A will schedule at X+10, B at X+8 (X+3+5), C at X+9 (X+5+4) and
+ D at X+14 (X+8+6).
+
+ The above example covers all the situations.
+
+ - NULL List.
+ - Inserting at head of list.
+ - Inserting in the middle of the list.
+ - Appending to the list tail.
+
+ The list will look as follows.
+
+ BEFORE AFTER
+ ------ -----
+
+ X Head -->| Head -> A(10) ->|
+ A(10)
+
+ X+3 Head -> A(7) ->| Head -> B(5) -> A(2) ->|
+ B(5)
+
+ X+5 Head -> B(3) -> A(2) ->| Head -> B(3) -> C(1) -> A(1) ->|
+ C(4)
+
+ X+8 Head -> C(1) -> A(1) ->| Head -> C(1) -> A(1) -> D(4) ->|
+ D(6)
+
+ The granularity is one tick. THIS MUST BE CALLED WITH THE TIMER LOCK HELD.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PTIMERLIST pList, *ppList;
+ ULONG DeltaTime = pListNew->tmr_AbsTime;
+
+ // The DeltaTime is adjusted in every pass of the loop to reflect the
+ // time after the previous entry that the new entry will schedule.
+ for (ppList = &spxTimerList;
+ (pList = *ppList) != NULL;
+ ppList = &pList->tmr_Next)
+ {
+ CTEAssert(VALID_TMR(pList));
+ if (DeltaTime <= pList->tmr_RelDelta)
+ {
+ pList->tmr_RelDelta -= DeltaTime;
+ break;
+ }
+ DeltaTime -= pList->tmr_RelDelta;
+ }
+
+
+ // Link this in the chain
+ pListNew->tmr_RelDelta = DeltaTime;
+ pListNew->tmr_Next = pList;
+ pListNew->tmr_Prev = ppList;
+ *ppList = pListNew;
+ if (pList != NULL)
+ {
+ pList->tmr_Prev = &pListNew->tmr_Next;
+ }
+
+ // Now link it in the hash table
+ pListNew->tmr_Overflow = spxTimerTable[pListNew->tmr_Id % TIMER_HASH_TABLE];
+ spxTimerTable[pListNew->tmr_Id % TIMER_HASH_TABLE] = pListNew;
+ spxTimerCount ++;
+}
+
+
+
+
+VOID
+SpxTimerFlushAndStop(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Force all entries in the timer queue to be dispatched immediately. No
+ more queue'ing of timer routines is permitted after this. The timer
+ essentially shuts down.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PTIMERLIST pList;
+ CTELockHandle lockHandle;
+
+ CTEAssert (KeGetCurrentIrql() == LOW_LEVEL);
+
+ DBGPRINT(SYSTEM, ERR,
+ ("SpxTimerFlushAndStop: Entered\n"));
+
+ CTEGetLock(&spxTimerLock, &lockHandle);
+
+ spxTimerStopped = TRUE;
+
+ KeCancelTimer(&spxTimer);
+
+ if (spxTimerList != NULL)
+ {
+ // Dispatch all entries right away
+ while (spxTimerList != NULL)
+ {
+ pList = spxTimerList;
+ CTEAssert(VALID_TMR(pList));
+ spxTimerList = pList->tmr_Next;
+
+ DBGPRINT(SYSTEM, INFO,
+ ("spxTimerFlushAndStop: Dispatching %lx\n",
+ pList->tmr_Worker));
+
+ // The timer routines assume they are being called at DISPATCH
+ // level. This is OK since we are calling with SpinLock held.
+
+ (*pList->tmr_Worker)(pList->tmr_Context, TRUE);
+
+ spxTimerCount --;
+ SpxBPFreeBlock(pList, BLKID_TIMERLIST);
+ }
+ RtlZeroMemory(spxTimerTable, sizeof(spxTimerTable));
+ }
+
+ CTEFreeLock(&spxTimerLock, lockHandle);
+
+ // Wait for all timer routines to complete
+ while (spxTimerDispatchCount != 0)
+ {
+ SpxSleep(SPX_TIMER_WAIT);
+ }
+}
+
+
+
+
+BOOLEAN
+SpxTimerCancelEvent(
+ IN ULONG TimerId,
+ IN BOOLEAN ReEnqueue
+ )
+/*++
+
+Routine Description:
+
+ Cancel a previously scheduled timer event, if it hasn't fired already.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PTIMERLIST pList, *ppList;
+ CTELockHandle lockHandle;
+
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxTimerCancelEvent: Entered for TimerId %ld\n", TimerId));
+
+ CTEAssert(TimerId != 0);
+
+ CTEGetLock(&spxTimerLock, &lockHandle);
+
+ for (ppList = &spxTimerTable[TimerId % TIMER_HASH_TABLE];
+ (pList = *ppList) != NULL;
+ ppList = &pList->tmr_Overflow)
+ {
+ CTEAssert(VALID_TMR(pList));
+ // If we find it, cancel it
+ if (pList->tmr_Id == TimerId)
+ {
+ // Unlink this from the hash table
+ *ppList = pList->tmr_Overflow;
+
+ // ... and from the list
+ if (pList->tmr_Next != NULL)
+ {
+ pList->tmr_Next->tmr_RelDelta += pList->tmr_RelDelta;
+ pList->tmr_Next->tmr_Prev = pList->tmr_Prev;
+ }
+ *(pList->tmr_Prev) = pList->tmr_Next;
+
+ spxTimerCount --;
+ if (ReEnqueue)
+ spxTimerEnqueue(pList);
+ else SpxBPFreeBlock(pList, BLKID_TIMERLIST);
+ break;
+ }
+ }
+
+ // If we could not find it in the list, see if it currently running.
+ // If so mark him to not reschedule itself, only if reenqueue was false.
+ if (pList == NULL)
+ {
+ if ((spxTimerActive != NULL) &&
+ (spxTimerActive->tmr_Id == TimerId) &&
+ !ReEnqueue)
+ {
+ spxTimerActive->tmr_Cancelled = TRUE;
+ }
+ }
+
+ CTEFreeLock(&spxTimerLock, lockHandle);
+
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxTimerCancelEvent: %s for Id %ld\n",
+ (pList != NULL) ? "Success" : "Failure", TimerId));
+
+ return (pList != NULL);
+}
+
+
+
+
+#if DBG
+
+VOID
+SpxTimerDumpList(
+ VOID
+ )
+{
+ PTIMERLIST pList;
+ ULONG CumTime = 0;
+ CTELockHandle lockHandle;
+
+ DBGPRINT(DUMP, FATAL,
+ ("TIMER LIST: (Times are in %dms units\n", 1000));
+ DBGPRINT(DUMP, FATAL,
+ ("\tTimerId Time(Abs) Time(Rel) Routine Address\n"));
+
+ CTEGetLock(&spxTimerLock, &lockHandle);
+
+ for (pList = spxTimerList;
+ pList != NULL;
+ pList = pList->tmr_Next)
+ {
+ CumTime += pList->tmr_RelDelta;
+ DBGPRINT(DUMP, FATAL,
+ ("\t% 6lx %5d %5ld %lx\n",
+ pList->tmr_Id, pList->tmr_AbsTime, CumTime, pList->tmr_Worker));
+ }
+
+ CTEFreeLock(&spxTimerLock, lockHandle);
+}
+
+#endif
diff --git a/private/ntos/tdi/isn/spx/spxutils.c b/private/ntos/tdi/isn/spx/spxutils.c
new file mode 100644
index 000000000..024a36988
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxutils.c
@@ -0,0 +1,484 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxutils.c
+
+Abstract:
+
+ This contains all utility routines for the ISN SPX module.
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXUTILS
+
+UINT
+SpxUtilWstrLength(
+ IN PWSTR Wstr
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ UINT length = 0;
+
+ while (*Wstr++)
+ {
+ length += sizeof(WCHAR);
+ }
+
+ return length;
+}
+
+
+
+
+LONG
+SpxRandomNumber(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LARGE_INTEGER Li;
+ static LONG seed = 0;
+
+ // Return a positive pseudo-random number; simple linear congruential
+ // algorithm. ANSI C "rand()" function.
+
+ if (seed == 0)
+ {
+ KeQuerySystemTime(&Li);
+ seed = Li.LowPart;
+ }
+
+ seed *= (0x41C64E6D + 0x3039);
+
+ return (seed & 0x7FFFFFFF);
+}
+
+
+
+
+NTSTATUS
+SpxUtilGetSocketType(
+ PUNICODE_STRING RemainingFileName,
+ PBYTE SocketType
+ )
+/*++
+
+Routine Description:
+
+ For PROTO_SPX, i'd return a device name from the dll of the form
+ \Device\IsnSpx\SpxStream (for SOCK_STREAM) or
+ \Device\IsnSpx\Spx (for SOCK_SEQPKT)
+
+ and for PROTO_SPXII (the more common case we hope, even if
+ internally we degrade to SPX1 cause of the remote client's
+ limitations)
+ \Device\IsnSpx\Stream (for SOCK_STREAM) or
+ \Device\IsnSpx (for SOCK_SEQPKT)
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ UNICODE_STRING typeString;
+
+ *SocketType = SOCKET2_TYPE_SEQPKT;
+
+ // Check for the socket type
+ do
+ {
+ if (RemainingFileName->Length == 0)
+ {
+ break;
+ }
+
+ if ((UINT)RemainingFileName->Length ==
+ SpxUtilWstrLength(SOCKET1STREAM_SUFFIX))
+ {
+ RtlInitUnicodeString(&typeString, SOCKET1STREAM_SUFFIX);
+
+ // Case insensitive compare
+ if (RtlEqualUnicodeString(&typeString, RemainingFileName, TRUE))
+ {
+ *SocketType = SOCKET1_TYPE_STREAM;
+ break;
+ }
+ }
+
+ if ((UINT)RemainingFileName->Length ==
+ SpxUtilWstrLength(SOCKET1_SUFFIX))
+ {
+ RtlInitUnicodeString(&typeString, SOCKET1_SUFFIX);
+
+ // Case insensitive compare
+ if (RtlEqualUnicodeString(&typeString, RemainingFileName, TRUE))
+ {
+ *SocketType = SOCKET1_TYPE_SEQPKT;
+ break;
+ }
+ }
+
+ if ((UINT)RemainingFileName->Length ==
+ SpxUtilWstrLength(SOCKET2STREAM_SUFFIX))
+ {
+ RtlInitUnicodeString(&typeString, SOCKET2STREAM_SUFFIX);
+
+ // Case insensitive compare
+ if (RtlEqualUnicodeString(&typeString, RemainingFileName, TRUE))
+ {
+ *SocketType = SOCKET2_TYPE_STREAM;
+ break;
+ }
+ }
+
+ status = STATUS_NO_SUCH_DEVICE;
+
+ } while (FALSE);
+
+ return(status);
+}
+
+
+
+
+#define ONE_MS_IN_100ns -10000L // 1ms in 100ns units
+
+VOID
+SpxSleep(
+ IN ULONG TimeInMs
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ KTIMER SleepTimer;
+
+ ASSERT (KeGetCurrentIrql() == LOW_LEVEL);
+
+ KeInitializeTimer(&SleepTimer);
+
+ KeSetTimer(&SleepTimer,
+ RtlConvertLongToLargeInteger(TimeInMs * ONE_MS_IN_100ns),
+ NULL);
+
+ KeWaitForSingleObject(&SleepTimer, UserRequest, KernelMode, FALSE, NULL);
+ return;
+}
+
+
+
+
+TDI_ADDRESS_IPX UNALIGNED *
+SpxParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, looking for an address
+ of type TDI_ADDRESS_TYPE_IPX.
+
+Arguments:
+
+ Transport - The generic TDI address.
+
+Return Value:
+
+ A pointer to the IPX address, or NULL if none is found.
+
+--*/
+
+{
+ TA_ADDRESS UNALIGNED * addressName;
+ INT i;
+
+ addressName = &TransportAddress->Address[0];
+
+ // The name can be passed with multiple entries; we'll take and use only
+ // the IPX one.
+ for (i=0;i<TransportAddress->TAAddressCount;i++)
+ {
+ if (addressName->AddressType == TDI_ADDRESS_TYPE_IPX)
+ {
+ if (addressName->AddressLength >= sizeof(TDI_ADDRESS_IPX))
+ {
+ return ((TDI_ADDRESS_IPX UNALIGNED *)(addressName->Address));
+ }
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+ return NULL;
+
+} // SpxParseTdiAddress
+
+
+
+BOOLEAN
+SpxValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, verifying that the
+ components of the address do not extend past the specified
+ length.
+
+Arguments:
+
+ TransportAddress - The generic TDI address.
+
+ TransportAddressLength - The specific length of TransportAddress.
+
+Return Value:
+
+ TRUE if the address is valid, FALSE otherwise.
+
+--*/
+
+{
+ PUCHAR AddressEnd = ((PUCHAR)TransportAddress) + TransportAddressLength;
+ TA_ADDRESS UNALIGNED * addressName;
+ INT i;
+
+ if (TransportAddressLength < sizeof(TransportAddress->TAAddressCount))
+ {
+ DBGPRINT(TDI, ERR,
+ ("SpxValidateTdiAddress: runt address\n"));
+
+ return FALSE;
+ }
+
+ addressName = &TransportAddress->Address[0];
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++)
+ {
+ if (addressName->Address > AddressEnd)
+ {
+ DBGPRINT(TDI, ERR,
+ ("SpxValidateTdiAddress: address too short\n"));
+
+ return FALSE;
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+
+ if ((PUCHAR)addressName > AddressEnd)
+ {
+ DBGPRINT(TDI, ERR,
+ ("SpxValidateTdiAddress: address too short\n"));
+
+ return FALSE;
+ }
+ return TRUE;
+
+} // SpxValidateTdiAddress
+
+
+
+
+ULONG
+SpxBuildTdiAddress(
+ IN PVOID AddressBuffer,
+ IN ULONG AddressBufferLength,
+ IN UCHAR Network[4],
+ IN UCHAR Node[6],
+ IN USHORT Socket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine fills in a TRANSPORT_ADDRESS in the specified
+ buffer, given the socket, network and node. It will write
+ less than the full address if the buffer is too short.
+
+Arguments:
+
+ AddressBuffer - The buffer that will hold the address.
+
+ AddressBufferLength - The length of the buffer.
+
+ Network - The network number.
+
+ Node - The node address.
+
+ Socket - The socket.
+
+Return Value:
+
+ The number of bytes written into AddressBuffer.
+
+--*/
+
+{
+ TA_IPX_ADDRESS UNALIGNED * SpxAddress;
+ TA_IPX_ADDRESS TempAddress;
+
+ if (AddressBufferLength >= sizeof(TA_IPX_ADDRESS))
+ {
+ SpxAddress = (TA_IPX_ADDRESS UNALIGNED *)AddressBuffer;
+ }
+ else
+ {
+ SpxAddress = (TA_IPX_ADDRESS UNALIGNED *)&TempAddress;
+ }
+
+ SpxAddress->TAAddressCount = 1;
+ SpxAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX);
+ SpxAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
+ SpxAddress->Address[0].Address[0].NetworkAddress = *(UNALIGNED LONG *)Network;
+ SpxAddress->Address[0].Address[0].Socket = Socket;
+ RtlCopyMemory(SpxAddress->Address[0].Address[0].NodeAddress, Node, 6);
+
+ if (AddressBufferLength >= sizeof(TA_IPX_ADDRESS))
+ {
+ return sizeof(TA_IPX_ADDRESS);
+ }
+ else
+ {
+ RtlCopyMemory(AddressBuffer, &TempAddress, AddressBufferLength);
+ return AddressBufferLength;
+ }
+
+} // SpxBuildTdiAddress
+
+
+
+VOID
+SpxBuildTdiAddressFromIpxAddr(
+ IN PVOID AddressBuffer,
+ IN PBYTE pIpxAddr
+ )
+{
+ TA_IPX_ADDRESS UNALIGNED * SpxAddress;
+
+ SpxAddress = (TA_IPX_ADDRESS UNALIGNED *)AddressBuffer;
+ SpxAddress->TAAddressCount = 1;
+ SpxAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX);
+ SpxAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
+ SpxAddress->Address[0].Address[0].NetworkAddress = *(UNALIGNED LONG *)pIpxAddr;
+ RtlCopyMemory(
+ SpxAddress->Address[0].Address[0].NodeAddress,
+ pIpxAddr+4,
+ 6);
+
+ GETSHORT2SHORT(
+ &SpxAddress->Address[0].Address[0].Socket,
+ pIpxAddr + 10);
+
+ return;
+}
+
+
+
+VOID
+SpxCalculateNewT1(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ IN int NewT1
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ NewT1 - New value for the RTT in ms.
+
+Return Value:
+
+
+--*/
+{
+ int baseT1, error;
+
+ //
+ // VAN JACOBSEN Algorithm. From Internetworking with Tcp/ip
+ // (Comer) book.
+ //
+
+ error = NewT1 - (pSpxConnFile->scf_AveT1 >> 3);
+ pSpxConnFile->scf_AveT1 += error;
+ if (pSpxConnFile->scf_AveT1 <= 0) // Make sure not too small
+ {
+ pSpxConnFile->scf_AveT1 = SPX_T1_MIN;
+ }
+
+ if (error < 0)
+ error = -error;
+
+ error -= (pSpxConnFile->scf_DevT1 >> 2);
+ pSpxConnFile->scf_DevT1 += error;
+ if (pSpxConnFile->scf_DevT1 <= 0)
+ pSpxConnFile->scf_DevT1 = 1;
+
+ baseT1 = (((pSpxConnFile->scf_AveT1 >> 2) + pSpxConnFile->scf_DevT1) >> 1);
+
+ // If less then min - set it
+ if (baseT1 < SPX_T1_MIN)
+ baseT1 = SPX_T1_MIN;
+
+ // Set the new value
+ DBGPRINT(TDI, DBG,
+ ("SpxCalculateNewT1: Old value %lx New %lx\n",
+ pSpxConnFile->scf_BaseT1, baseT1));
+
+ pSpxConnFile->scf_BaseT1 = baseT1;
+
+ // At the time of restarting the timer,we convert this to a tick value.
+ return;
+}
+
diff --git a/private/ntos/tdi/isn/spx/up/makefile b/private/ntos/tdi/isn/spx/up/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/up/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isn/spx/up/sources b/private/ntos/tdi/isn/spx/up/sources
new file mode 100644
index 000000000..85cdb3764
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/up/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+UP_DRIVER=yes
+
+TARGETPATH=obj
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/isnp/dirs b/private/ntos/tdi/isnp/dirs
new file mode 100644
index 000000000..a93e8e700
--- /dev/null
+++ b/private/ntos/tdi/isnp/dirs
@@ -0,0 +1,28 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS= \
+ ipx \
+ nb \
+ spx
+
+OPTIONAL_DIRS=
diff --git a/private/ntos/tdi/isnp/inc/bind.h b/private/ntos/tdi/isnp/inc/bind.h
new file mode 100644
index 000000000..60294349d
--- /dev/null
+++ b/private/ntos/tdi/isnp/inc/bind.h
@@ -0,0 +1,563 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ bind.h
+
+Abstract:
+
+ Private include file for the ISN transport. It defines the
+ structures used for binding between IPX and the upper drivers.
+
+Author:
+
+ Adam Barr (adamba) 04-Oct-1993
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 5-July-1995
+ Bug fixes - tagged [SA]
+
+--*/
+
+#ifndef _ISN_BIND_
+#define _ISN_BIND_
+
+//
+// Retrieve the common definitions.
+//
+
+#include <isnkrnl.h>
+
+
+//
+// Define the IOCTL used for binding between the upper
+// drivers and IPX.
+//
+
+#define _IPX_CONTROL_CODE(request,method) \
+ CTL_CODE(FILE_DEVICE_TRANSPORT, request, method, FILE_ANY_ACCESS)
+
+#define IOCTL_IPX_INTERNAL_BIND _IPX_CONTROL_CODE( 0x1234, METHOD_BUFFERED )
+
+
+//
+// Identifier for the drivers in ISN.
+//
+
+#define IDENTIFIER_NB 0
+#define IDENTIFIER_SPX 1
+#define IDENTIFIER_RIP 2
+#define IDENTIFIER_IPX 3
+
+#ifdef _PNP_POWER
+//
+// This the number of PVOIDs in the beginning of the SEND_RESERVED
+// section of a packet header, to be set aside by the ISN clients (NB/SPX)
+// for IPX's private use.
+//
+#define SEND_RESERVED_COMMON_SIZE 8
+#endif
+
+//
+// Definition of a RIP router table entry.
+//
+
+typedef struct _IPX_ROUTE_ENTRY {
+ UCHAR Network[4];
+ USHORT NicId;
+ UCHAR NextRouter[6];
+ NDIS_HANDLE NdisBindingContext;
+ USHORT Flags;
+ USHORT Timer;
+ UINT Segment;
+ USHORT TickCount;
+ USHORT HopCount;
+ LIST_ENTRY AlternateRoute;
+ LIST_ENTRY NicLinkage;
+ struct {
+ LIST_ENTRY Linkage;
+ ULONG Reserved[1];
+ } PRIVATE;
+} IPX_ROUTE_ENTRY, * PIPX_ROUTE_ENTRY;
+
+//
+// Definition of the Flags values.
+//
+
+#define IPX_ROUTER_PERMANENT_ENTRY 0x0001 // entry should never be deleted
+#define IPX_ROUTER_LOCAL_NET 0x0002 // locally attached network
+#define IPX_ROUTER_SCHEDULE_ROUTE 0x0004 // call ScheduleRouteHandler after using
+#define IPX_ROUTER_GLOBAL_WAN_NET 0x0008 // this is for rip's global network number
+
+
+//
+// Definition of the structure provided on a find
+// route/find route completion call.
+//
+
+//
+// [SA] Bug #15094 added node number to the structure.
+//
+
+typedef struct _IPX_FIND_ROUTE_REQUEST {
+ UCHAR Network[4];
+ UCHAR Node[6] ;
+ IPX_LOCAL_TARGET LocalTarget;
+ UCHAR Identifier;
+ UCHAR Type;
+ UCHAR Reserved1[2];
+ PVOID Reserved2;
+ LIST_ENTRY Linkage;
+} IPX_FIND_ROUTE_REQUEST, *PIPX_FIND_ROUTE_REQUEST;
+
+//
+// Definitions for the Type value.
+//
+
+#define IPX_FIND_ROUTE_NO_RIP 1 // fail if net is not in database
+#define IPX_FIND_ROUTE_RIP_IF_NEEDED 2 // return net if in database, otherwise RIP out
+#define IPX_FIND_ROUTE_FORCE_RIP 3 // re-RIP even if net is in database
+
+
+//
+// Structure used when querying the line information
+// for a specific NID ID.
+//
+
+typedef struct _IPX_LINE_INFO {
+ UINT LinkSpeed;
+ UINT MaximumPacketSize;
+ UINT MaximumSendSize;
+ UINT MacOptions;
+} IPX_LINE_INFO, *PIPX_LINE_INFO;
+
+
+
+//
+// Functions provided by the upper driver.
+//
+
+typedef VOID
+(*IPX_INTERNAL_RECEIVE) (
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+);
+
+typedef VOID
+(*IPX_INTERNAL_RECEIVE_COMPLETE) (
+ IN USHORT NicId
+);
+
+typedef VOID
+(*IPX_INTERNAL_STATUS) (
+ IN USHORT NicId,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength
+);
+
+typedef VOID
+(*IPX_INTERNAL_SEND_COMPLETE) (
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+);
+
+typedef VOID
+(*IPX_INTERNAL_TRANSFER_DATA_COMPLETE) (
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+);
+
+typedef VOID
+(*IPX_INTERNAL_FIND_ROUTE_COMPLETE) (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute
+);
+
+typedef VOID
+(*IPX_INTERNAL_LINE_UP) (
+ IN USHORT NicId,
+ IN PIPX_LINE_INFO LineInfo,
+ IN NDIS_MEDIUM DeviceType,
+ IN PVOID ConfigurationData
+);
+
+typedef VOID
+(*IPX_INTERNAL_LINE_DOWN) (
+ IN USHORT NicId
+);
+
+typedef VOID
+(*IPX_INTERNAL_SCHEDULE_ROUTE) (
+ IN PIPX_ROUTE_ENTRY RouteEntry
+);
+
+#if defined(_PNP_POWER)
+
+//
+// following opcodes are used when calling the
+// above handler.
+//
+typedef enum _IPX_PNP_OPCODE {
+ IPX_PNP_ADD_DEVICE, // 0 - addition of the first adapter
+ IPX_PNP_DELETE_DEVICE, // 1 - deletion of the last adapter
+ IPX_PNP_TRANSLATE_DEVICE, // 2 - translate device resource
+ IPX_PNP_TRANSLATE_ADDRESS, // 3 - translate address resource
+ IPX_PNP_ADDRESS_CHANGE, // 4 - Adapter address or Reserved address changed
+ IPX_PNP_MAX_OPCODES, // 5
+} IPX_PNP_OPCODE, *PIPX_PNP_OPCODE;
+
+//
+// PnP event notification handler.
+//
+typedef VOID
+(*IPX_INTERNAL_PNP_NOTIFICATION) (
+ IN IPX_PNP_OPCODE PnPOpcode,
+ IN OUT PVOID PnpData
+);
+
+//
+// Pointer to this structure is passed in PnPData portion of
+// the above handler when the opcode is ADD_DEVICE or DELETE_DEVICE.
+//
+typedef struct _IPX_PNP_INFO {
+ ULONG NetworkAddress;
+ UCHAR NodeAddress[6];
+ BOOLEAN NewReservedAddress; // where the above is a new reserved
+ // address for the Ipx clients.
+ BOOLEAN FirstORLastDevice; // is this a first card arrival or last card deletion.
+ IPX_LINE_INFO LineInfo; // New LineInfo.
+ NIC_HANDLE NicHandle;
+} IPX_PNP_INFO, *PIPX_PNP_INFO;
+
+#endif _PNP_POWER
+
+//
+// Input to the bind IOCTL
+//
+
+typedef struct _IPX_INTERNAL_BIND_INPUT {
+ USHORT Version;
+ UCHAR Identifier;
+ BOOLEAN BroadcastEnable;
+ UINT LookaheadRequired;
+ UINT ProtocolOptions;
+ IPX_INTERNAL_RECEIVE ReceiveHandler;
+ IPX_INTERNAL_RECEIVE_COMPLETE ReceiveCompleteHandler;
+ IPX_INTERNAL_STATUS StatusHandler;
+ IPX_INTERNAL_SEND_COMPLETE SendCompleteHandler;
+ IPX_INTERNAL_TRANSFER_DATA_COMPLETE TransferDataCompleteHandler;
+ IPX_INTERNAL_FIND_ROUTE_COMPLETE FindRouteCompleteHandler;
+ IPX_INTERNAL_LINE_UP LineUpHandler;
+ IPX_INTERNAL_LINE_DOWN LineDownHandler;
+ IPX_INTERNAL_SCHEDULE_ROUTE ScheduleRouteHandler;
+#if defined(_PNP_POWER)
+ IPX_INTERNAL_PNP_NOTIFICATION PnPHandler;
+#endif _PNP_POWER
+ ULONG RipParameters;
+} IPX_INTERNAL_BIND_INPUT, * PIPX_INTERNAL_BIND_INPUT;
+
+#if defined(_PNP_POWER)
+#define ISN_VERSION 2
+#endif _PNP_POWER
+//
+// Bit mask values for RipParameters.
+//
+
+#define IPX_RIP_PARAM_GLOBAL_NETWORK 0x00000001 // single network for all WANS
+
+
+
+//
+// Functions provided by the lower driver.
+//
+
+typedef NDIS_STATUS
+(*IPX_INTERNAL_SEND) (
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+);
+
+typedef VOID
+(*IPX_INTERNAL_FIND_ROUTE) (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest
+);
+
+typedef NTSTATUS
+(*IPX_INTERNAL_QUERY) (
+ IN ULONG InternalQueryType,
+#if defined(_PNP_POWER)
+ IN PNIC_HANDLE NicHandle OPTIONAL,
+#else
+ IN USHORT NicId OPTIONAL,
+#endif _PNP_POWER
+ IN OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG BufferLengthNeeded OPTIONAL
+);
+
+typedef VOID
+(*IPX_INTERNAL_TRANSFER_DATA)(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+//
+// Definitions of the internal query types. In all cases
+// STATUS_SUCCESS is returned if the request succeeds, and
+// STATUS_BUFFER_TOO_SMALL is returned, and BufferLengthNeeded
+// set if specified, if the buffer is too short. Other
+// return codes are defined below. The routine never pends.
+//
+
+//
+// This is used to query the line info. NicId specifies which one
+// to query. Buffer contains an IPX_LINE_INFO structure which is
+// used to return the information. Other return values:
+//
+// STATUS_INVALID_PARAMETER - NicId is invalid.
+//
+
+#define IPX_QUERY_LINE_INFO 1
+
+//
+// This is used to query the maximum NicId. NicId is unused. The
+// Buffer contains a USHORT which is used to return the information.
+//
+
+#define IPX_QUERY_MAXIMUM_NIC_ID 2
+
+//
+// This is used to determine if the IPX address specified was sent
+// by our local machine. If the address is the source address of a
+// received frame, NicId should be the ID that was indicated; otherwise
+// it should be set to 0. Buffer holds a TDI_ADDRESS_IPX. This
+// call returns STATUS_SUCCESS if the address is local, and
+// STATUS_NO_SUCH_DEVICE if not.
+//
+
+#define IPX_QUERY_IS_ADDRESS_LOCAL 3
+
+//
+// This is used to query the receive buffer space of a given NicId.
+// Buffer contains a ULONG which is used to return the information.
+// It returns STATUS_INVALID_PARAMETER if NicId is invalid.
+//
+
+#define IPX_QUERY_RECEIVE_BUFFER_SPACE 4
+
+//
+// This is used to query the local IPX address of a given NicId.
+// Buffer contains a TDI_ADDRESS_IPX structure (the Socket is
+// returned as 0). If it is queried on net 0 it returns the
+// virtual network if there is one, otherwise STATUS_INVALID_PARAMETER.
+// It returns STATUS_INVALID_PARAMETER if NicId is invalid.
+//
+
+#define IPX_QUERY_IPX_ADDRESS 5
+
+//
+// This is used to return the source routing information for
+// a give remote address. NicId will be the NIC the packet was
+// received from. The IPX_SOURCE_ROUTING_QUERY is contained
+// in Buffer. Always returns STATUS_SUCCESS, although the
+// SourceRoutingLength may be 0 for unknown remotes.
+//
+// The source routing is return in the direction it was received
+// from the remote, not the direction used in replying. The
+// MaximumSendSize includes the IPX header (as it does in
+// IPX_LINE_INFO).
+//
+
+#define IPX_QUERY_SOURCE_ROUTING 6
+
+typedef struct _IPX_SOURCE_ROUTING_INFO {
+ USHORT Identifier; // input: the caller's IDENTIFIER_SPX, _NB, etc.
+ UCHAR RemoteAddress[6]; // input: the remote address
+ UCHAR SourceRouting[18]; // output: room for the maximum source route
+ USHORT SourceRoutingLength; // output: the valid length of source route
+ ULONG MaximumSendSize; // output: based on nic and source routing
+} IPX_SOURCE_ROUTING_INFO, * PIPX_SOURCE_ROUTING_INFO;
+
+//
+// This is used to query the maximum NicId over which outgoing type
+// 20 packets should be sent. It will be less than or equal to
+// the IPX_QUERY_MAXIMUM_NIC_ID value. What's excluded are down wan
+// lines and dialin wan lines if DisableDialinNetbios bit 1 is set.
+//
+
+#define IPX_QUERY_MAX_TYPE_20_NIC_ID 7
+
+#if defined(_PNP_POWER)
+
+//
+// This are used by NB to pass down these TDI queries which cannot
+// be completed in NB.
+//
+
+#define IPX_QUERY_DATA_LINK_ADDRESS 8
+#define IPX_QUERY_NETWORK_ADDRESS 9
+
+#endif _PNP_POWER
+
+//
+// Output of a non-RIP bind.
+//
+
+typedef struct _IPX_INTERNAL_BIND_OUTPUT {
+ USHORT Version;
+ UCHAR Node[6];
+ UCHAR Network[4];
+ USHORT MacHeaderNeeded;
+ USHORT IncludedHeaderOffset;
+ IPX_LINE_INFO LineInfo;
+ IPX_INTERNAL_SEND SendHandler;
+ IPX_INTERNAL_FIND_ROUTE FindRouteHandler;
+ IPX_INTERNAL_QUERY QueryHandler;
+ IPX_INTERNAL_TRANSFER_DATA TransferDataHandler;
+} IPX_INTERNAL_BIND_OUTPUT, * PIPX_INTERNAL_BIND_OUTPUT;
+
+
+
+//
+// Lower driver functions provided only for RIP.
+//
+
+typedef UINT
+(*IPX_INTERNAL_GET_SEGMENT) (
+ IN UCHAR Network[4]
+);
+
+typedef PIPX_ROUTE_ENTRY
+(*IPX_INTERNAL_GET_ROUTE) (
+ IN UINT Segment,
+ IN UCHAR Network[4]
+);
+
+typedef BOOLEAN
+(*IPX_INTERNAL_ADD_ROUTE) (
+ IN UINT Segment,
+ IN PIPX_ROUTE_ENTRY RouteEntry
+);
+
+typedef BOOLEAN
+(*IPX_INTERNAL_DELETE_ROUTE) (
+ IN UINT Segment,
+ IN PIPX_ROUTE_ENTRY RouteEntry
+);
+
+typedef PIPX_ROUTE_ENTRY
+(*IPX_INTERNAL_GET_FIRST_ROUTE) (
+ IN UINT Segment
+);
+
+typedef PIPX_ROUTE_ENTRY
+(*IPX_INTERNAL_GET_NEXT_ROUTE) (
+ IN UINT Segment
+);
+
+typedef VOID
+(*IPX_INTERNAL_INCREMENT_WAN_INACTIVITY) (
+#ifdef _PNP_LATER
+ IN NIC_HANDLE NicHandle
+#else
+ IN USHORT NicId
+#endif
+);
+
+typedef ULONG
+(*IPX_INTERNAL_QUERY_WAN_INACTIVITY) (
+#ifdef _PNP_LATER
+ IN NIC_HANDLE NicHandle
+#else
+ IN USHORT NicId
+#endif
+
+);
+
+//
+// Describes a single network.
+//
+
+typedef struct _IPX_NIC_DATA {
+ USHORT NicId;
+ UCHAR Node[6];
+ UCHAR Network[4];
+ IPX_LINE_INFO LineInfo;
+ NDIS_MEDIUM DeviceType;
+ ULONG EnableWanRouter;
+} IPX_NIC_DATA, * PIPX_NIC_DATA;
+
+
+//
+// Describes all networks.
+//
+
+typedef struct _IPX_NIC_INFO_BUFFER {
+ USHORT NicCount;
+ USHORT VirtualNicId;
+ UCHAR VirtualNetwork[4];
+ IPX_NIC_DATA NicData[1];
+} IPX_NIC_INFO_BUFFER, * PIPX_NIC_INFO_BUFFER;
+
+
+//
+// Output from a RIP bind (the actual structure size is
+// based on the number of IPX_NIC_DATA elements in the
+// final IPX_NIC_INFO_BUFFER structure).
+//
+
+typedef struct _IPX_INTERNAL_BIND_RIP_OUTPUT {
+ USHORT Version;
+ USHORT MaximumNicCount;
+ USHORT MacHeaderNeeded;
+ USHORT IncludedHeaderOffset;
+ IPX_INTERNAL_SEND SendHandler;
+ UINT SegmentCount;
+ KSPIN_LOCK * SegmentLocks;
+ IPX_INTERNAL_GET_SEGMENT GetSegmentHandler;
+ IPX_INTERNAL_GET_ROUTE GetRouteHandler;
+ IPX_INTERNAL_ADD_ROUTE AddRouteHandler;
+ IPX_INTERNAL_DELETE_ROUTE DeleteRouteHandler;
+ IPX_INTERNAL_GET_FIRST_ROUTE GetFirstRouteHandler;
+ IPX_INTERNAL_GET_NEXT_ROUTE GetNextRouteHandler;
+ IPX_INTERNAL_INCREMENT_WAN_INACTIVITY IncrementWanInactivityHandler;
+ IPX_INTERNAL_QUERY_WAN_INACTIVITY QueryWanInactivityHandler;
+ IPX_INTERNAL_TRANSFER_DATA TransferDataHandler;
+ IPX_NIC_INFO_BUFFER NicInfoBuffer;
+} IPX_INTERNAL_BIND_RIP_OUTPUT, * PIPX_INTERNAL_BIND_RIP_OUTPUT;
+
+#endif // _ISN_BIND_
+
+
+#ifndef _IPXCP_CONFIG_
+#define _IPXCP_CONFIG_
+
+typedef struct _IPXCP_CONFIGURATION {
+ USHORT Version;
+ USHORT Length;
+ UCHAR Network[4];
+ UCHAR LocalNode[6];
+ UCHAR RemoteNode[6];
+ ULONG ConnectionClient; // 0 - Server, 1 - Client
+} IPXCP_CONFIGURATION, *PIPXCP_CONFIGURATION;
+
+#endif // _IPXCP_CONFIG_
+
diff --git a/private/ntos/tdi/isnp/inc/ioctls.h b/private/ntos/tdi/isnp/inc/ioctls.h
new file mode 100644
index 000000000..e7dd7b81a
--- /dev/null
+++ b/private/ntos/tdi/isnp/inc/ioctls.h
@@ -0,0 +1,155 @@
+#define VER_IOCH "@(#)MCS ipx/h/ioctls.h 1.00.00 - 08 APR 1993";
+
+/****************************************************************************
+* (c) Copyright 1990, 1993 Micro Computer Systems, Inc. All rights reserved.
+*****************************************************************************
+*
+* Title: IPX/SPX Driver for Windows NT
+*
+* Module: ipx/h/ioctls.h
+*
+* Version: 1.00.00
+*
+* Date: 04-08-93
+*
+* Author: Brian Walker
+*
+*****************************************************************************
+*
+* Change Log:
+*
+* Date DevSFC Comment
+* -------- ------ -------------------------------------------------------
+*****************************************************************************
+*
+* Functional Description:
+*
+* IOCTL defines
+*
+****************************************************************************/
+
+/** Ioctls for IPX - (X) = User callable **/
+
+/**
+ ioctls will values 100 - 150 were added for the NT port.
+**/
+
+#define I_MIPX (('I' << 24) | ('D' << 16) | ('P' << 8))
+#define MIPX_SETNODEADDR I_MIPX | 0 /* Set the node address */
+#define MIPX_SETNETNUM I_MIPX | 1 /* Set the network number */
+#define MIPX_SETPTYPE I_MIPX | 2 /* (X) Set the packet type */
+#define MIPX_SENTTYPE I_MIPX | 3 /* (X) Set the xport type */
+#define MIPX_SETPKTSIZE I_MIPX | 4 /* Set the packet size */
+#define MIPX_SETSAP I_MIPX | 5 /* Set the sap/type field */
+#define MIPX_SENDOPTS I_MIPX | 6 /* (X) Send options on recv */
+#define MIPX_NOSENDOPTS I_MIPX | 7 /* (X) Don't send options on recv */
+#define MIPX_SENDSRC I_MIPX | 8 /* (X) Send source address up */
+#define MIPX_NOSENDSRC I_MIPX | 9 /* (X) Don't Send source address up */
+#define MIPX_CONVBCAST I_MIPX | 10 /* Convert TKR bcast to func addr */
+#define MIPX_NOCONVBCAST I_MIPX | 11 /* Don't cnvrt TKR bcast to funcaddr */
+#define MIPX_SETCARDTYPE I_MIPX | 12 /* Set 802.3 or ETH type */
+#define MIPX_STARGROUP I_MIPX | 13 /* This is stargroup */
+#define MIPX_SWAPLENGTH I_MIPX | 14 /* Set flag for swapping 802.3 length */
+#define MIPX_SENDDEST I_MIPX | 15 /* (X) Send dest. address up */
+#define MIPX_NOSENDDEST I_MIPX | 16 /* (X) Don't send dest. address up */
+#define MIPX_SENDFDEST I_MIPX | 17 /* (X) Send final dest. address up */
+#define MIPX_NOSENDFDEST I_MIPX | 18 /* (X) Don't send final dest. up */
+
+/** Added for NT port **/
+
+#define MIPX_SETVERSION I_MIPX | 100 /* Set card version */
+#define MIPX_GETSTATUS I_MIPX | 101
+#define MIPX_SENDADDROPT I_MIPX | 102 /* (X) Send ptype w/addr on recv */
+#define MIPX_NOSENDADDROPT I_MIPX | 103 /* (X) Stop sending ptype on recv */
+#define MIPX_CHECKSUM I_MIPX | 104 /* Enable/Disable checksum */
+#define MIPX_GETPKTSIZE I_MIPX | 105 /* Get max packet size */
+#define MIPX_SENDHEADER I_MIPX | 106 /* Send header with data */
+#define MIPX_NOSENDHEADER I_MIPX | 107 /* Don't send header with data */
+#define MIPX_SETCURCARD I_MIPX | 108 /* Set current card for IOCTLs */
+#define MIPX_SETMACTYPE I_MIPX | 109 /* Set the Cards MAC type */
+#define MIPX_DOSROUTE I_MIPX | 110 /* Do source routing on this card*/
+#define MIPX_NOSROUTE I_MIPX | 111 /* Don't source routine the card*/
+#define MIPX_SETRIPRETRY I_MIPX | 112 /* Set RIP retry count */
+#define MIPX_SETRIPTO I_MIPX | 113 /* Set RIP timeout */
+#define MIPX_SETTKRSAP I_MIPX | 114 /* Set the token ring SAP */
+#define MIPX_SETUSELLC I_MIPX | 115 /* Put LLC hdr on packets */
+#define MIPX_SETUSESNAP I_MIPX | 116 /* Put SNAP hdr on packets */
+#define MIPX_8023LEN I_MIPX | 117 /* 1=make even, 0=dont make even*/
+#define MIPX_SENDPTYPE I_MIPX | 118 /* Send ptype in options on recv*/
+#define MIPX_NOSENDPTYPE I_MIPX | 119 /* Don't send ptype in options */
+#define MIPX_FILTERPTYPE I_MIPX | 120 /* Filter on recv ptype */
+#define MIPX_NOFILTERPTYPE I_MIPX | 121 /* Don't Filter on recv ptype */
+#define MIPX_SETSENDPTYPE I_MIPX | 122 /* Set pkt type to send with */
+#define MIPX_GETCARDINFO I_MIPX | 123 /* Get info on a card */
+#define MIPX_SENDCARDNUM I_MIPX | 124 /* Send card num up in options */
+#define MIPX_NOSENDCARDNUM I_MIPX | 125 /* Dont send card num in options*/
+#define MIPX_SETROUTER I_MIPX | 126 /* Set router enabled flag */
+#define MIPX_SETRIPAGE I_MIPX | 127 /* Set RIP age timeout */
+#define MIPX_SETRIPUSAGE I_MIPX | 128 /* Set RIP usage timeout */
+#define MIPX_SETSROUTEUSAGE I_MIPX| 129 /* Set the SROUTE usage timeout */
+#define MIPX_SETINTNET I_MIPX | 130 /* Set internal network number */
+#define MIPX_NOVIRTADDR I_MIPX | 131 /* Turn off virtual net num */
+#define MIPX_VIRTADDR I_MIPX | 132 /* Turn on virtual net num */
+#define MIPX_SETBCASTFLAG I_MIPX | 133 /* Turn on bcast flag in addr */
+#define MIPX_NOBCASTFLAG I_MIPX | 134 /* Turn off bcast flag in addr */
+#define MIPX_GETNETINFO I_MIPX | 135 /* Get info on a network num */
+#define MIPX_SETDELAYTIME I_MIPX | 136 /* Set cards delay time */
+#define MIPX_SETROUTEADV I_MIPX | 137 /* Route advertise timeout */
+#define MIPX_SETSOCKETS I_MIPX | 138 /* Set default sockets */
+#define MIPX_SETLINKSPEED I_MIPX | 139 /* Set the link speed for a card*/
+#define MIPX_SETWANFLAG I_MIPX | 140
+#define MIPX_GETCARDCHANGES I_MIPX | 141 /* Wait for card changes */
+#define MIPX_GETMAXADAPTERS I_MIPX | 142
+#define MIPX_REUSEADDRESS I_MIPX | 143
+#define MIPX_RERIPNETNUM I_MIPX | 144 /* ReRip a network */
+
+/** For Source Routing Support **/
+
+#define MIPX_SRCLEAR I_MIPX | 200 /* Clear the source routing table*/
+#define MIPX_SRDEF I_MIPX | 201 /* 0=Single Rte, 1=All Routes */
+#define MIPX_SRBCAST I_MIPX | 202 /* 0=Single Rte, 1=All Routes */
+#define MIPX_SRMULTI I_MIPX | 203 /* 0=Single Rte, 1=All Routes */
+#define MIPX_SRREMOVE I_MIPX | 204 /* Remove a node from the table */
+#define MIPX_SRLIST I_MIPX | 205 /* Get the source routing table */
+#define MIPX_SRGETPARMS I_MIPX | 206 /* Get source routing parms */
+
+#define MIPX_SETSHOULDPUT I_MIPX | 210 /* Turn on should put call */
+#define MIPX_DELSHOULDPUT I_MIPX | 211 /* Turn off should put call */
+#define MIPX_GETSHOULDPUT I_MIPX | 212 /* Get ptr to mipx_shouldput */
+
+/** Added for ISN **/
+
+#define MIPX_RCVBCAST I_MIPX | 300 /* (X) Enable broadcast reception */
+#define MIPX_NORCVBCAST I_MIPX | 301 /* (X) Disable broadcast reception */
+#define MIPX_ADAPTERNUM I_MIPX | 302 /* Get maximum adapter number */
+#define MIPX_NOTIFYCARDINFO I_MIPX | 303 /* Pend until card info changes */
+#define MIPX_LOCALTARGET I_MIPX | 304 /* Get local target for address */
+#define MIPX_NETWORKINFO I_MIPX | 305 /* Return info about remote net */
+#define MIPX_ZEROSOCKET I_MIPX | 306 /* Use 0 as source socket on sends */
+
+/** Ioctls for SPX **/
+
+#define I_MSPX (('S' << 24) | ('P' << 16) | ('P' << 8))
+#define MSPX_SETADDR I_MSPX | 0 /* Set the network address */
+#define MSPX_SETPKTSIZE I_MSPX | 1 /* Set the packet size per card */
+#define MSPX_SETDATASTREAM I_MSPX | 2 /* Set datastream type */
+
+/** Added for NT port **/
+
+#define MSPX_SETASLISTEN I_MSPX | 100 /* Set as a listen socket */
+#define MSPX_GETSTATUS I_MSPX | 101 /* Get running status */
+#define MSPX_GETQUEUEPTR I_MSPX | 102 /* Get ptr to the streams queue */
+#define MSPX_SETDATAACK I_MSPX | 103 /* Set DATA ACK option */
+#define MSPX_NODATAACK I_MSPX | 104 /* Turn off DATA ACK option */
+#define MSPX_SETMAXPKTSOCK I_MSPX | 105 /* Set the packet size per socket */
+#define MSPX_SETWINDOWCARD I_MSPX | 106 /* Set window size for card */
+#define MSPX_SETWINDOWSOCK I_MSPX | 107 /* Set window size for 1 socket */
+#define MSPX_SENDHEADER I_MSPX | 108 /* Send header with data */
+#define MSPX_NOSENDHEADER I_MSPX | 109 /* Don't send header with data */
+#define MSPX_GETPKTSIZE I_MSPX | 110 /* Get the packet size per card */
+#define MSPX_SETCONNCNT I_MSPX | 111 /* Set the conn req count */
+#define MSPX_SETCONNTO I_MSPX | 112 /* Set the conn req timeout */
+#define MSPX_SETALIVECNT I_MSPX | 113 /* Set the keepalive count */
+#define MSPX_SETALIVETO I_MSPX | 114 /* Set the keepalive timeout */
+#define MSPX_SETALWAYSEOM I_MSPX | 115 /* Turn on always EOM flag */
+#define MSPX_NOALWAYSEOM I_MSPX | 116 /* Turn off always EOM flag */
diff --git a/private/ntos/tdi/isnp/inc/isn.h b/private/ntos/tdi/isnp/inc/isn.h
new file mode 100644
index 000000000..7b7e23601
--- /dev/null
+++ b/private/ntos/tdi/isnp/inc/isn.h
@@ -0,0 +1,41 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ isn.h
+
+Abstract:
+
+ Private include file for the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 08-Sep-1993
+
+Revision History:
+
+--*/
+
+
+#define ISN_NT 1
+
+
+//
+// These are needed for CTE
+//
+
+#if DBG
+#define DEBUG 1
+#endif
+
+#define NT 1
+
+
+#include <ntddk.h>
+#include <tdikrnl.h>
+#include <ndis.h>
+#include <cxport.h>
+#include <bind.h>
+
diff --git a/private/ntos/tdi/isnp/ipx/action.c b/private/ntos/tdi/isnp/ipx/action.c
new file mode 100644
index 000000000..807391cae
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/action.c
@@ -0,0 +1,1802 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ action.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiAction
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+#include <packon.h>
+
+typedef struct _GET_PKT_SIZE {
+ ULONG Unknown;
+ ULONG MaxDatagramSize;
+} GET_PKT_SIZE, *PGET_PKT_SIZE;
+
+
+//
+// These structures are used to set and query information
+// about our source routing table.
+//
+
+typedef struct _SR_GET_PARAMETERS {
+ ULONG BoardNumber; // 0-based
+ ULONG SrDefault; // 0 = single route, 1 = all routes
+ ULONG SrBroadcast;
+ ULONG SrMulticast;
+} SR_GET_PARAMETERS, *PSR_GET_PARAMETERS;
+
+typedef struct _SR_SET_PARAMETER {
+ ULONG BoardNumber; // 0-based
+ ULONG Parameter; // 0 = single route, 1 = all routes
+} SR_SET_PARAMETER, *PSR_SET_PARAMETER;
+
+typedef struct _SR_SET_REMOVE {
+ ULONG BoardNumber; // 0-based
+ UCHAR MacAddress[6]; // remote to drop routing for
+} SR_SET_REMOVE, *PSR_SET_REMOVE;
+
+typedef struct _SR_SET_CLEAR {
+ ULONG BoardNumber; // 0-based
+} SR_SET_CLEAR, *PSR_SET_CLEAR;
+
+#include <packoff.h>
+
+typedef struct _ISN_ACTION_GET_DETAILS {
+ USHORT NicId; // passed by caller, returns count if it is 0
+ BOOLEAN BindingSet; // returns TRUE if in a set
+ UCHAR Type; // 1 = lan, 2 = up wan, 3 = down wan
+ ULONG FrameType; // returns 0 through 3
+ ULONG NetworkNumber; // returns virtual net if NicId is 0
+ UCHAR Node[6]; // adapter MAC address
+ WCHAR AdapterName[64]; // terminated with Unicode NULL
+} ISN_ACTION_GET_DETAILS, *PISN_ACTION_GET_DETAILS;
+
+
+
+NTSTATUS
+IpxTdiAction(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiAction request for the transport
+ provider.
+
+Arguments:
+
+ Device - The device for the operation.
+
+ Request - Describes the action request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PADDRESS_FILE AddressFile;
+ UINT BufferLength;
+ UINT DataLength;
+ PNDIS_BUFFER NdisBuffer;
+ CTELockHandle LockHandle;
+ PBINDING Binding, MasterBinding;
+ PADAPTER Adapter;
+ union {
+ PISN_ACTION_GET_LOCAL_TARGET GetLocalTarget;
+ PISN_ACTION_GET_NETWORK_INFO GetNetworkInfo;
+ PISN_ACTION_GET_DETAILS GetDetails;
+ PSR_GET_PARAMETERS GetSrParameters;
+ PSR_SET_PARAMETER SetSrParameter;
+ PSR_SET_REMOVE SetSrRemove;
+ PSR_SET_CLEAR SetSrClear;
+ PIPX_ADDRESS_DATA IpxAddressData;
+ PGET_PKT_SIZE GetPktSize;
+ PIPX_NETNUM_DATA IpxNetnumData;
+ } u; // BUGBUG: Make these unaligned??
+ PIPX_ROUTE_ENTRY RouteEntry;
+ PNWLINK_ACTION NwlinkAction;
+ ULONG Segment;
+ ULONG AdapterNum;
+ static UCHAR BogusId[4] = { 0x01, 0x00, 0x00, 0x00 }; // old nwrdr uses this
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ //
+ // To maintain some compatibility with the NWLINK streams-
+ // based transport, we use the streams header format for
+ // our actions. The old transport expected the action header
+ // to be in InputBuffer and the output to go in OutputBuffer.
+ // We follow the TDI spec, which states that OutputBuffer
+ // is used for both input and output. Since IOCTL_TDI_ACTION
+ // is method out direct, this means that the output buffer
+ // is mapped by the MDL chain; for action the chain will
+ // only have one piece so we use it for input and output.
+ //
+
+ NdisBuffer = REQUEST_NDIS_BUFFER(Request);
+ if (NdisBuffer == NULL) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ NdisQueryBuffer (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength);
+
+ if ((!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MISN", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MIPX", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "XPIM", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), BogusId, 4))) {
+
+ return STATUS_NOT_SUPPORTED;
+ }
+
+
+ //
+ // Make sure we have enough room for just the header not
+ // including the data.
+ //
+
+ if (BufferLength < (UINT)(FIELD_OFFSET(NWLINK_ACTION, Data[0]))) {
+ IPX_DEBUG (ACTION, ("Nwlink action failed, buffer too small\n"));
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ DataLength = BufferLength - FIELD_OFFSET(NWLINK_ACTION, Data[0]);
+
+
+ //
+ // Make sure that the correct file object is being used.
+ //
+
+ if (NwlinkAction->OptionType == NWLINK_OPTION_ADDRESS) {
+
+ if (REQUEST_OPEN_TYPE(Request) != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
+ IPX_DEBUG (ACTION, ("Nwlink action failed, not address file\n"));
+ return STATUS_INVALID_HANDLE;
+ }
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ if ((AddressFile->Size != sizeof (ADDRESS_FILE)) ||
+ (AddressFile->Type != IPX_ADDRESSFILE_SIGNATURE)) {
+
+ IPX_DEBUG (ACTION, ("Nwlink action failed, bad address file\n"));
+ return STATUS_INVALID_HANDLE;
+ }
+
+ } else if (NwlinkAction->OptionType != NWLINK_OPTION_CONTROL) {
+
+ IPX_DEBUG (ACTION, ("Nwlink action failed, option type %d\n", NwlinkAction->OptionType));
+ return STATUS_NOT_SUPPORTED;
+ }
+
+
+ //
+ // Handle the requests based on the action code. For these
+ // requests ActionHeader->ActionCode is 0, we use the
+ // Option field in the streams header instead.
+ //
+
+
+ Status = STATUS_SUCCESS;
+
+ switch (NwlinkAction->Option) {
+
+ //DbgPrint("NwlinkAction->Option is (%x)\n", NwlinkAction->Option);
+ //
+ // This first group support the winsock helper dll.
+ // In most cases the corresponding sockopt is shown in
+ // the comment, as well as the contents of the Data
+ // part of the action buffer.
+ //
+
+ case MIPX_SETSENDPTYPE:
+
+ //
+ // IPX_PTYPE: Data is a single byte packet type.
+ //
+
+ if (DataLength >= 1) {
+ IPX_DEBUG (ACTION, ("%lx: MIPX_SETSENDPTYPE %x\n", AddressFile, NwlinkAction->Data[0]));
+ AddressFile->DefaultPacketType = NwlinkAction->Data[0];
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case MIPX_FILTERPTYPE:
+
+ //
+ // IPX_FILTERPTYPE: Data is a single byte to filter on.
+ //
+
+ if (DataLength >= 1) {
+ IPX_DEBUG (ACTION, ("%lx: MIPX_FILTERPTYPE %x\n", AddressFile, NwlinkAction->Data[0]));
+ AddressFile->FilteredType = NwlinkAction->Data[0];
+ AddressFile->FilterOnPacketType = TRUE;
+ AddressFile->SpecialReceiveProcessing = TRUE;
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case MIPX_NOFILTERPTYPE:
+
+ //
+ // IPX_STOPFILTERPTYPE.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NOFILTERPTYPE\n", AddressFile));
+ AddressFile->FilterOnPacketType = FALSE;
+ AddressFile->SpecialReceiveProcessing = (BOOLEAN)
+ (AddressFile->ExtendedAddressing || AddressFile->ReceiveFlagsAddressing ||
+ AddressFile->ReceiveIpxHeader || AddressFile->IsSapSocket);
+ break;
+
+ case MIPX_SENDADDROPT:
+
+ //
+ // IPX_EXTENDED_ADDRESS (TRUE).
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_SENDADDROPT\n", AddressFile));
+ AddressFile->ExtendedAddressing = TRUE;
+ AddressFile->SpecialReceiveProcessing = TRUE;
+ break;
+
+ case MIPX_NOSENDADDROPT:
+
+ //
+ // IPX_EXTENDED_ADDRESS (FALSE).
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NOSENDADDROPT\n", AddressFile));
+ AddressFile->ExtendedAddressing = FALSE;
+ AddressFile->SpecialReceiveProcessing = (BOOLEAN)
+ (AddressFile->ReceiveFlagsAddressing || AddressFile->ReceiveIpxHeader ||
+ AddressFile->FilterOnPacketType || AddressFile->IsSapSocket);
+ break;
+
+ case MIPX_SETRCVFLAGS:
+
+ //
+ // No sockopt yet.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_SETRCVFLAGS\n", AddressFile));
+ AddressFile->ReceiveFlagsAddressing = TRUE;
+ AddressFile->SpecialReceiveProcessing = TRUE;
+ break;
+
+ case MIPX_NORCVFLAGS:
+
+ //
+ // No sockopt yet.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NORCVFLAGS\n", AddressFile));
+ AddressFile->ReceiveFlagsAddressing = FALSE;
+ AddressFile->SpecialReceiveProcessing = (BOOLEAN)
+ (AddressFile->ExtendedAddressing || AddressFile->ReceiveIpxHeader ||
+ AddressFile->FilterOnPacketType || AddressFile->IsSapSocket);
+ break;
+
+ case MIPX_SENDHEADER:
+
+ //
+ // IPX_RECVHDR (TRUE);
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_SENDHEADER\n", AddressFile));
+ AddressFile->ReceiveIpxHeader = TRUE;
+ AddressFile->SpecialReceiveProcessing = TRUE;
+ break;
+
+ case MIPX_NOSENDHEADER:
+
+ //
+ // IPX_RECVHDR (FALSE);
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NOSENDHEADER\n", AddressFile));
+ AddressFile->ReceiveIpxHeader = FALSE;
+ AddressFile->SpecialReceiveProcessing = (BOOLEAN)
+ (AddressFile->ExtendedAddressing || AddressFile->ReceiveFlagsAddressing ||
+ AddressFile->FilterOnPacketType || AddressFile->IsSapSocket);
+ break;
+
+ case MIPX_RCVBCAST:
+
+ //
+ // Broadcast reception enabled.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_RCVBCAST\n", AddressFile));
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ if (!AddressFile->EnableBroadcast) {
+
+ AddressFile->EnableBroadcast = TRUE;
+ IpxAddBroadcast (Device);
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ break;
+
+ case MIPX_NORCVBCAST:
+
+ //
+ // Broadcast reception disabled.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NORCVBCAST\n", AddressFile));
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ if (AddressFile->EnableBroadcast) {
+
+ AddressFile->EnableBroadcast = FALSE;
+ IpxRemoveBroadcast (Device);
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ break;
+
+ case MIPX_GETPKTSIZE:
+
+ //
+ // IPX_MAXSIZE.
+ //
+ // BUGBUG: Figure out what the first length is for.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_GETPKTSIZE\n", AddressFile));
+ if (DataLength >= sizeof(GET_PKT_SIZE)) {
+ u.GetPktSize = (PGET_PKT_SIZE)(NwlinkAction->Data);
+ u.GetPktSize->Unknown = 0;
+ u.GetPktSize->MaxDatagramSize = Device->Information.MaxDatagramSize;
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case MIPX_ADAPTERNUM:
+
+ //
+ // IPX_MAX_ADAPTER_NUM.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_ADAPTERNUM\n", AddressFile));
+ if (DataLength >= sizeof(ULONG)) {
+ *(UNALIGNED ULONG *)(NwlinkAction->Data) = Device->SapNicCount;
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case MIPX_ADAPTERNUM2:
+
+ //
+ // IPX_MAX_ADAPTER_NUM.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_ADAPTERNUM2\n", AddressFile));
+ if (DataLength >= sizeof(ULONG)) {
+ *(UNALIGNED ULONG *)(NwlinkAction->Data) = MIN (Device->MaxBindings, Device->ValidBindings);
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case MIPX_GETCARDINFO:
+ case MIPX_GETCARDINFO2:
+
+ //
+ // GETCARDINFO is IPX_ADDRESS.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_GETCARDINFO (%d)\n",
+ AddressFile, *(UNALIGNED UINT *)NwlinkAction->Data));
+ if (DataLength >= sizeof(IPX_ADDRESS_DATA)) {
+ u.IpxAddressData = (PIPX_ADDRESS_DATA)(NwlinkAction->Data);
+ AdapterNum = u.IpxAddressData->adapternum+1;
+
+ if (((AdapterNum >= 1) && (AdapterNum <= Device->SapNicCount)) ||
+ ((NwlinkAction->Option == MIPX_GETCARDINFO2) && (AdapterNum <= (ULONG) MIN (Device->MaxBindings, Device->ValidBindings)))) {
+
+#ifdef _PNP_POWER
+// Get lock
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_ID_TO_BINDING(Device, AdapterNum);
+#else
+ Binding = Device->Bindings[AdapterNum];
+#endif
+ if (Binding == NULL) {
+
+ //
+ // This should be a binding in the WAN range
+ // of an adapter which is currently not
+ // allocated. We scan back to the previous
+ // non-NULL binding, which should be on the
+ // same adapter, and return a down line with
+ // the same characteristics as that binding.
+ //
+
+ UINT i = AdapterNum;
+
+ do {
+ --i;
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ } while (Binding == NULL);
+
+ CTEAssert (Binding->Adapter->MacInfo.MediumAsync);
+ CTEAssert (i >= Binding->Adapter->FirstWanNicId);
+ CTEAssert (AdapterNum <= Binding->Adapter->LastWanNicId);
+
+ u.IpxAddressData->status = FALSE;
+ *(UNALIGNED ULONG *)u.IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+
+ } else {
+
+ if ((Binding->Adapter->MacInfo.MediumAsync) &&
+ (Device->WanGlobalNetworkNumber)) {
+
+ //
+ // In this case we make it look like one big wan
+ // net, so the line is "up" or "down" depending
+ // on whether we have given him the first indication
+ // or not.
+ //
+
+ u.IpxAddressData->status = Device->GlobalNetworkIndicated;
+ *(UNALIGNED ULONG *)u.IpxAddressData->netnum = Device->GlobalWanNetwork;
+
+ } else {
+
+ u.IpxAddressData->status = Binding->LineUp;
+ *(UNALIGNED ULONG *)u.IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+ }
+
+ }
+
+ RtlCopyMemory(u.IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
+
+ Adapter = Binding->Adapter;
+ u.IpxAddressData->wan = Adapter->MacInfo.MediumAsync;
+ u.IpxAddressData->maxpkt =
+ (NwlinkAction->Option == MIPX_GETCARDINFO) ?
+ Binding->AnnouncedMaxDatagramSize :
+ Binding->RealMaxDatagramSize;
+ u.IpxAddressData->linkspeed = Binding->MediumSpeed;
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ } else {
+
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ } else {
+#if 1
+ //
+ // Support the old format query for now.
+ //
+
+ typedef struct _IPX_OLD_ADDRESS_DATA {
+ UINT adapternum;
+ UCHAR netnum[4];
+ UCHAR nodenum[6];
+ } IPX_OLD_ADDRESS_DATA, *PIPX_OLD_ADDRESS_DATA;
+
+ if (DataLength >= sizeof(IPX_OLD_ADDRESS_DATA)) {
+ u.IpxAddressData = (PIPX_ADDRESS_DATA)(NwlinkAction->Data);
+ AdapterNum = u.IpxAddressData->adapternum+1;
+
+ if ((AdapterNum >= 1) && (AdapterNum <= Device->SapNicCount)) {
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ if (Binding = NIC_ID_TO_BINDING(Device, AdapterNum)) {
+ *(UNALIGNED ULONG *)u.IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(u.IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (Binding = Device->Bindings[AdapterNum]) {
+ *(UNALIGNED ULONG *)u.IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(u.IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+#endif
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+#else
+ Status = STATUS_BUFFER_TOO_SMALL;
+#endif
+ }
+ break;
+
+ case MIPX_NOTIFYCARDINFO:
+
+ //
+ // IPX_ADDRESS_NOTIFY.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NOTIFYCARDINFO (%lx)\n", AddressFile, Request));
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ //
+ // If the device is open and there is room in the
+ // buffer for the data, insert it in our queue.
+ // It will be completed when a change happens or
+ // the driver is unloaded.
+ //
+
+ if (Device->State == DEVICE_STATE_OPEN) {
+ if (DataLength >= sizeof(IPX_ADDRESS_DATA)) {
+ InsertTailList(
+ &Device->AddressNotifyQueue,
+ REQUEST_LINKAGE(Request)
+ );
+ IoSetCancelRoutine (Request, IpxCancelAction);
+ if (Request->Cancel) {
+ (VOID)RemoveTailList (&Device->AddressNotifyQueue);
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ Status = STATUS_CANCELLED;
+ } else {
+ IpxReferenceDevice (Device, DREF_ADDRESS_NOTIFY);
+ Status = STATUS_PENDING;
+ }
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ } else {
+ Status = STATUS_DEVICE_NOT_READY;
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ break;
+
+ case MIPX_LINECHANGE:
+
+ //
+ // IPX_ADDRESS_NOTIFY.
+ //
+
+ IPX_DEBUG (ACTION, ("MIPX_LINECHANGE (%lx)\n", Request));
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ //
+ // If the device is open and there is room in the
+ // buffer for the data, insert it in our queue.
+ // It will be completed when a change happens or
+ // the driver is unloaded.
+ //
+
+ if (Device->State == DEVICE_STATE_OPEN) {
+
+ InsertTailList(
+ &Device->LineChangeQueue,
+ REQUEST_LINKAGE(Request)
+ );
+
+ IoSetCancelRoutine (Request, IpxCancelAction);
+ if (Request->Cancel) {
+ (VOID)RemoveTailList (&Device->LineChangeQueue);
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ Status = STATUS_CANCELLED;
+ } else {
+ IpxReferenceDevice (Device, DREF_LINE_CHANGE);
+ Status = STATUS_PENDING;
+ }
+ } else {
+ Status = STATUS_DEVICE_NOT_READY;
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ break;
+
+ case MIPX_GETNETINFO_NR:
+
+ //
+ // A request for network information about the immediate
+ // route to a network (this is called by sockets apps).
+ //
+
+ if (DataLength < sizeof(IPX_NETNUM_DATA)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.IpxNetnumData = (PIPX_NETNUM_DATA)(NwlinkAction->Data);
+
+ //
+ // A query on network 0 means that the caller wants
+ // information about our directly attached net.
+ //
+
+ if (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum == 0) {
+
+ //
+ // The tick count is the number of 1/18.21 second ticks
+ // it takes to deliver a 576-byte packet. Our link speed
+ // is in 100 bit-per-second units. We calculate it as
+ // follows (LS is the LinkSpeed):
+ //
+ // 576 bytes 8 bits 1 second 1821 ticks
+ // * ------ * ------------- * ----------
+ // 1 byte LS * 100 bits 100 seconds
+ //
+ // which becomes 839 / LinkSpeed -- we add LinkSpeed
+ // to the top to round up.
+ //
+
+ if (Device->LinkSpeed == 0) {
+ u.IpxNetnumData->netdelay = 16;
+ } else {
+ u.IpxNetnumData->netdelay = (USHORT)((839 + Device->LinkSpeed) /
+ (Device->LinkSpeed));
+ }
+ u.IpxNetnumData->hopcount = 0;
+ u.IpxNetnumData->cardnum = 0;
+ RtlMoveMemory (u.IpxNetnumData->router, Device->SourceAddress.NodeAddress, 6);
+
+ } else {
+
+
+#ifdef _PNP_POWER
+ Segment = RipGetSegment(u.IpxNetnumData->netnum);
+
+ //
+ // To maintain the lock order: BindAccessLock > RIP table
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+ if ((RouteEntry != NULL) &&
+ (Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId))) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(MIN (Device->MaxBindings, Binding->MasterBinding->NicId) - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // Fail the call, we don't have a route yet.
+ //
+
+ IPX_DEBUG (ACTION, ("MIPX_GETNETINFO_NR failed net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+ Status = STATUS_BAD_NETWORK_PATH;
+
+ }
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+#else
+ Segment = RipGetSegment(u.IpxNetnumData->netnum);
+
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+ if ((RouteEntry != NULL) &&
+ (Binding = Device->Bindings[RouteEntry->NicId])) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(Binding->MasterBinding->NicId - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // Fail the call, we don't have a route yet.
+ //
+
+ IPX_DEBUG (ACTION, ("MIPX_GETNETINFO_NR failed net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+ Status = STATUS_BAD_NETWORK_PATH;
+
+ }
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+#endif
+
+ }
+
+ break;
+
+ case MIPX_RERIPNETNUM:
+
+ //
+ // A request for network information about the immediate
+ // route to a network (this is called by sockets apps).
+ //
+
+ if (DataLength < sizeof(IPX_NETNUM_DATA)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.IpxNetnumData = (PIPX_NETNUM_DATA)(NwlinkAction->Data);
+
+ //
+ // BUGBUG: Allow net 0 queries??
+ //
+
+ if (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum == 0) {
+
+ if (Device->LinkSpeed == 0) {
+ u.IpxNetnumData->netdelay = 16;
+ } else {
+ u.IpxNetnumData->netdelay = (USHORT)((839 + Device->LinkSpeed) /
+ (Device->LinkSpeed));
+ }
+ u.IpxNetnumData->hopcount = 0;
+ u.IpxNetnumData->cardnum = 0;
+ RtlMoveMemory (u.IpxNetnumData->router, Device->SourceAddress.NodeAddress, 6);
+
+ } else {
+
+ Segment = RipGetSegment(u.IpxNetnumData->netnum);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+
+ if ((RouteEntry != NULL) &&
+ (Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId)) &&
+ (RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY)) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(MIN (Device->MaxBindings, Binding->MasterBinding->NicId) - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // This call will return STATUS_PENDING if we successfully
+ // queue a RIP request for the packet.
+ //
+
+ Status = RipQueueRequest (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum, RIP_REQUEST);
+ CTEAssert (Status != STATUS_SUCCESS);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this request for completion when the RIP response
+ // arrives. We save the network in the information
+ // field for easier retrieval later.
+ //
+
+ REQUEST_INFORMATION(Request) = (ULONG)u.IpxNetnumData;
+ InsertTailList(
+ &Device->Segments[Segment].WaitingReripNetnum,
+ REQUEST_LINKAGE(Request));
+
+ IPX_DEBUG (ACTION, ("MIPX_RERIPNETNUM queued net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+
+ }
+
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+
+ if ((RouteEntry != NULL) &&
+ (Binding = Device->Bindings[RouteEntry->NicId]) &&
+ (RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY)) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(Binding->MasterBinding->NicId - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // This call will return STATUS_PENDING if we successfully
+ // queue a RIP request for the packet.
+ //
+
+ Status = RipQueueRequest (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum, RIP_REQUEST);
+ CTEAssert (Status != STATUS_SUCCESS);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this request for completion when the RIP response
+ // arrives. We save the network in the information
+ // field for easier retrieval later.
+ //
+
+ REQUEST_INFORMATION(Request) = (ULONG)u.IpxNetnumData;
+ InsertTailList(
+ &Device->Segments[Segment].WaitingReripNetnum,
+ REQUEST_LINKAGE(Request));
+
+ IPX_DEBUG (ACTION, ("MIPX_RERIPNETNUM queued net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+
+ }
+
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+#endif
+ }
+
+ break;
+
+ case MIPX_GETNETINFO:
+
+ //
+ // A request for network information about the immediate
+ // route to a network (this is called by sockets apps).
+ //
+
+ if (DataLength < sizeof(IPX_NETNUM_DATA)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.IpxNetnumData = (PIPX_NETNUM_DATA)(NwlinkAction->Data);
+
+ //
+ // BUGBUG: Allow net 0 queries??
+ //
+
+ if (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum == 0) {
+
+ if (Device->LinkSpeed == 0) {
+ u.IpxNetnumData->netdelay = 16;
+ } else {
+ u.IpxNetnumData->netdelay = (USHORT)((839 + Device->LinkSpeed) /
+ (Device->LinkSpeed));
+ }
+ u.IpxNetnumData->hopcount = 0;
+ u.IpxNetnumData->cardnum = 0;
+ RtlMoveMemory (u.IpxNetnumData->router, Device->SourceAddress.NodeAddress, 6);
+
+ } else {
+
+ Segment = RipGetSegment(u.IpxNetnumData->netnum);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+
+ if ((RouteEntry != NULL) &&
+ (Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId))) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(MIN (Device->MaxBindings, Binding->MasterBinding->NicId) - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // This call will return STATUS_PENDING if we successfully
+ // queue a RIP request for the packet.
+ //
+
+ Status = RipQueueRequest (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum, RIP_REQUEST);
+ CTEAssert (Status != STATUS_SUCCESS);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this request for completion when the RIP response
+ // arrives. We save the network in the information
+ // field for easier retrieval later.
+ //
+
+ REQUEST_INFORMATION(Request) = (ULONG)u.IpxNetnumData;
+ InsertTailList(
+ &Device->Segments[Segment].WaitingReripNetnum,
+ REQUEST_LINKAGE(Request));
+
+ IPX_DEBUG (ACTION, ("MIPX_GETNETINFO queued net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+
+ }
+
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+
+ if ((RouteEntry != NULL) &&
+ (Binding = Device->Bindings[RouteEntry->NicId])) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(Binding->MasterBinding->NicId - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // This call will return STATUS_PENDING if we successfully
+ // queue a RIP request for the packet.
+ //
+
+ Status = RipQueueRequest (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum, RIP_REQUEST);
+ CTEAssert (Status != STATUS_SUCCESS);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this request for completion when the RIP response
+ // arrives. We save the network in the information
+ // field for easier retrieval later.
+ //
+
+ REQUEST_INFORMATION(Request) = (ULONG)u.IpxNetnumData;
+ InsertTailList(
+ &Device->Segments[Segment].WaitingReripNetnum,
+ REQUEST_LINKAGE(Request));
+
+ IPX_DEBUG (ACTION, ("MIPX_GETNETINFO queued net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+
+ }
+
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+#endif
+ }
+
+ break;
+
+ case MIPX_SENDPTYPE:
+ case MIPX_NOSENDPTYPE:
+
+ //
+ // For the moment just use OptionsLength >= 1 to indicate
+ // that the send options include the packet type.
+ //
+ // BUGBUG: Do we need to worry about card num being there?
+ //
+
+#if 0
+ IPX_DEBUG (ACTION, ("%lx: MIPS_%sSENDPTYPE\n", AddressFile,
+ NwlinkAction->Option == MIPX_SENDPTYPE ? "" : "NO"));
+#endif
+ break;
+
+ case MIPX_ZEROSOCKET:
+
+ //
+ // Sends from this address should be from socket 0;
+ // This is done the simple way by just putting the
+ // information in the address itself, instead of
+ // making it per address file (this is OK since
+ // this call is not exposed through winsock).
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_ZEROSOCKET\n", AddressFile));
+ AddressFile->Address->SendSourceSocket = 0;
+ AddressFile->Address->LocalAddress.Socket = 0;
+ break;
+
+
+ //
+ // This next batch are the source routing options. They
+ // are submitted by the IPXROUTE program.
+ //
+ // BUGBUG: Do we expose all binding set members to this?
+
+ case MIPX_SRGETPARMS:
+
+ if (DataLength >= sizeof(SR_GET_PARAMETERS)) {
+ u.GetSrParameters = (PSR_GET_PARAMETERS)(NwlinkAction->Data);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ if (Binding = NIC_ID_TO_BINDING(Device, u.GetSrParameters->BoardNumber+1)) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRGETPARMS (%d)\n", u.GetSrParameters->BoardNumber+1));
+ u.GetSrParameters->SrDefault = (Binding->AllRouteDirected) ? 1 : 0;
+ u.GetSrParameters->SrBroadcast = (Binding->AllRouteBroadcast) ? 1 : 0;
+ u.GetSrParameters->SrMulticast = (Binding->AllRouteMulticast) ? 1 : 0;
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (Binding = Device->Bindings[u.GetSrParameters->BoardNumber+1]) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRGETPARMS (%d)\n", u.GetSrParameters->BoardNumber+1));
+ u.GetSrParameters->SrDefault = (Binding->AllRouteDirected) ? 1 : 0;
+ u.GetSrParameters->SrBroadcast = (Binding->AllRouteBroadcast) ? 1 : 0;
+ u.GetSrParameters->SrMulticast = (Binding->AllRouteMulticast) ? 1 : 0;
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+#endif
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+
+ case MIPX_SRDEF:
+ case MIPX_SRBCAST:
+ case MIPX_SRMULTI:
+
+ if (DataLength >= sizeof(SR_SET_PARAMETER)) {
+ u.SetSrParameter = (PSR_SET_PARAMETER)(NwlinkAction->Data);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ if (Binding = NIC_ID_TO_BINDING(Device, u.SetSrParameter->BoardNumber+1)) {
+ if (NwlinkAction->Option == MIPX_SRDEF) {
+
+ //
+ // BUGBUG: The compiler generates strange
+ // code which always makes this path be
+ // taken????
+ //
+
+ IPX_DEBUG (ACTION, ("MIPX_SRDEF %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteDirected = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ } else if (NwlinkAction->Option == MIPX_SRBCAST) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRBCAST %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteBroadcast = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ } else {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRMCAST %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteMulticast = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ }
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (Binding = Device->Bindings[u.SetSrParameter->BoardNumber+1]) {
+ if (NwlinkAction->Option == MIPX_SRDEF) {
+
+ //
+ // BUGBUG: The compiler generates strange
+ // code which always makes this path be
+ // taken????
+ //
+
+ IPX_DEBUG (ACTION, ("MIPX_SRDEF %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteDirected = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ } else if (NwlinkAction->Option == MIPX_SRBCAST) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRBCAST %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteBroadcast = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ } else {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRMCAST %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteMulticast = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ }
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+#endif
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+
+ case MIPX_SRREMOVE:
+
+ if (DataLength >= sizeof(SR_SET_REMOVE)) {
+ u.SetSrRemove = (PSR_SET_REMOVE)(NwlinkAction->Data);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ if (Binding = NIC_ID_TO_BINDING(Device, u.SetSrRemove->BoardNumber+1)) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRREMOVE %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x (%d)\n",
+ u.SetSrRemove->MacAddress[0],
+ u.SetSrRemove->MacAddress[1],
+ u.SetSrRemove->MacAddress[2],
+ u.SetSrRemove->MacAddress[3],
+ u.SetSrRemove->MacAddress[4],
+ u.SetSrRemove->MacAddress[5],
+ u.SetSrRemove->BoardNumber+1));
+ MacSourceRoutingRemove (Binding, u.SetSrRemove->MacAddress);
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (Binding = Device->Bindings[u.SetSrRemove->BoardNumber+1]) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRREMOVE %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x (%d)\n",
+ u.SetSrRemove->MacAddress[0],
+ u.SetSrRemove->MacAddress[1],
+ u.SetSrRemove->MacAddress[2],
+ u.SetSrRemove->MacAddress[3],
+ u.SetSrRemove->MacAddress[4],
+ u.SetSrRemove->MacAddress[5],
+ u.SetSrRemove->BoardNumber+1));
+ MacSourceRoutingRemove (Binding, u.SetSrRemove->MacAddress);
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+#endif
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+
+ case MIPX_SRCLEAR:
+
+ if (DataLength >= sizeof(SR_SET_CLEAR)) {
+ u.SetSrClear = (PSR_SET_CLEAR)(NwlinkAction->Data);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ if (Binding = NIC_ID_TO_BINDING(Device, u.SetSrClear->BoardNumber+1)) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRCLEAR (%d)\n", u.SetSrClear->BoardNumber+1));
+ MacSourceRoutingClear (Binding);
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (Binding = Device->Bindings[u.SetSrClear->BoardNumber+1]) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRCLEAR (%d)\n", u.SetSrClear->BoardNumber+1));
+ MacSourceRoutingClear (Binding);
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+#endif
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+
+
+ //
+ // These are new for ISN (not supported in NWLINK).
+ //
+
+ case MIPX_LOCALTARGET:
+
+ //
+ // A request for the local target for an IPX address.
+ //
+
+ if (DataLength < sizeof(ISN_ACTION_GET_LOCAL_TARGET)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.GetLocalTarget = (PISN_ACTION_GET_LOCAL_TARGET)(NwlinkAction->Data);
+ Segment = RipGetSegment((PUCHAR)&u.GetLocalTarget->IpxAddress.NetworkAddress);
+
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See if this route is local.
+ //
+
+ RouteEntry = RipGetRoute (Segment, (PUCHAR)&u.GetLocalTarget->IpxAddress.NetworkAddress);
+
+ if ((RouteEntry != NULL) &&
+ (RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY)) {
+
+ //
+ // This is a local net, to send to it you just use
+ // the appropriate NIC ID and the real MAC address.
+ //
+
+ if ((RouteEntry->Flags & IPX_ROUTER_LOCAL_NET) == 0) {
+
+ //
+ // It's the virtual net, send via the first card.
+ //
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&u.GetLocalTarget->LocalTarget, 1);
+#else
+ u.GetLocalTarget->LocalTarget.NicId = 1;
+#endif
+
+ } else {
+
+#ifdef _PNP_POWER
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId);
+
+ if (Binding->BindingSetMember) {
+
+ //
+ // It's a binding set member, we round-robin the
+ // responses across all the cards to distribute
+ // the traffic.
+ //
+
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+
+ FILL_LOCAL_TARGET(&u.GetLocalTarget->LocalTarget, MIN( Device->MaxBindings, Binding->NicId));
+
+ } else {
+
+ FILL_LOCAL_TARGET(&u.GetLocalTarget->LocalTarget, RouteEntry->NicId);
+
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ Binding = Device->Bindings[RouteEntry->NicId];
+ if (Binding->BindingSetMember) {
+
+ //
+ // It's a binding set member, we round-robin the
+ // responses across all the cards to distribute
+ // the traffic.
+ //
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+
+ u.GetLocalTarget->LocalTarget.NicId = Binding->NicId;
+ } else {
+
+ u.GetLocalTarget->LocalTarget.NicId = RouteEntry->NicId;
+
+ }
+#endif
+
+ }
+
+ RtlCopyMemory(
+ u.GetLocalTarget->LocalTarget.MacAddress,
+ u.GetLocalTarget->IpxAddress.NodeAddress,
+ 6);
+
+ } else {
+
+ //
+ // This call will return STATUS_PENDING if we successfully
+ // queue a RIP request for the packet.
+ //
+
+ Status = RipQueueRequest (u.GetLocalTarget->IpxAddress.NetworkAddress, RIP_REQUEST);
+ CTEAssert (Status != STATUS_SUCCESS);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this request for completion when the RIP response
+ // arrives. We save the network in the information
+ // field for easier retrieval later.
+ //
+
+ REQUEST_INFORMATION(Request) = (ULONG)u.GetLocalTarget;
+ InsertTailList(
+ &Device->Segments[Segment].WaitingLocalTarget,
+ REQUEST_LINKAGE(Request));
+
+ }
+
+#ifdef _PNP_POWER
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+#endif
+ }
+#ifndef _PNP_POWER
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+#endif
+
+
+ break;
+
+ case MIPX_NETWORKINFO:
+
+ //
+ // A request for network information about the immediate
+ // route to a network.
+ //
+
+ if (DataLength < sizeof(ISN_ACTION_GET_NETWORK_INFO)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.GetNetworkInfo = (PISN_ACTION_GET_NETWORK_INFO)(NwlinkAction->Data);
+
+ if (u.GetNetworkInfo->Network == 0) {
+
+ //
+ // This is information about the local card.
+ //
+
+ u.GetNetworkInfo->LinkSpeed = Device->LinkSpeed * 12;
+ u.GetNetworkInfo->MaximumPacketSize = Device->Information.MaxDatagramSize;
+
+ } else {
+
+ Segment = RipGetSegment((PUCHAR)&u.GetNetworkInfo->Network);
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, (PUCHAR)&u.GetNetworkInfo->Network);
+
+ if ((RouteEntry != NULL) &&
+#ifdef _PNP_POWER
+ (Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId))) {
+#else
+ (Binding = Device->Bindings[RouteEntry->NicId])) {
+#endif
+
+ //
+ // Our medium speed is stored in 100 bps, we
+ // convert to bytes/sec by multiplying by 12
+ // (should really be 100/8 = 12.5).
+ //
+
+ u.GetNetworkInfo->LinkSpeed = Binding->MediumSpeed * 12;
+ u.GetNetworkInfo->MaximumPacketSize = Binding->AnnouncedMaxDatagramSize;
+
+ } else {
+
+ //
+ // Fail the call, we don't have a route yet.
+ // BUGBUG: This requires that a packet has been
+ // sent to this net already; nwrdr says this is
+ // OK, they will send their connect request
+ // before they query. On the server it should
+ // have RIP running so all nets should be in
+ // the database.
+ //
+
+ Status = STATUS_BAD_NETWORK_PATH;
+
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ }
+
+ break;
+
+ case MIPX_CONFIG:
+
+ //
+ // A request for details on every binding.
+ //
+
+ if (DataLength < sizeof(ISN_ACTION_GET_DETAILS)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.GetDetails = (PISN_ACTION_GET_DETAILS)(NwlinkAction->Data);
+
+ if (u.GetDetails->NicId == 0) {
+
+ //
+ // This is information about the local card. We also
+ // tell him the total number of bindings in NicId.
+ //
+
+ u.GetDetails->NetworkNumber = Device->VirtualNetworkNumber;
+ u.GetDetails->NicId = (USHORT)MIN (Device->MaxBindings, Device->ValidBindings);
+
+ } else {
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ Binding = NIC_ID_TO_BINDING(Device, u.GetDetails->NicId);
+#else
+ Binding = Device->Bindings[u.GetDetails->NicId];
+#endif
+
+ if ((Binding != NULL) &&
+ (u.GetDetails->NicId <= MIN (Device->MaxBindings, Device->ValidBindings))) {
+
+ ULONG StringLoc;
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ u.GetDetails->NetworkNumber = Binding->LocalAddress.NetworkAddress;
+ if (Binding->Adapter->MacInfo.MediumType == NdisMediumArcnet878_2) {
+ u.GetDetails->FrameType = ISN_FRAME_TYPE_ARCNET;
+ } else {
+ u.GetDetails->FrameType = Binding->FrameType;
+ }
+ u.GetDetails->BindingSet = Binding->BindingSetMember;
+ if (Binding->Adapter->MacInfo.MediumAsync) {
+ if (Binding->LineUp) {
+ u.GetDetails->Type = 2;
+ } else {
+ u.GetDetails->Type = 3;
+ }
+ } else {
+ u.GetDetails->Type = 1;
+ }
+
+ RtlCopyMemory (u.GetDetails->Node, Binding->LocalMacAddress.Address, 6);
+
+ //
+ // Copy the adapter name, including the final NULL.
+ //
+
+ StringLoc = (Binding->Adapter->AdapterNameLength / sizeof(WCHAR)) - 2;
+ while (Binding->Adapter->AdapterName[StringLoc] != L'\\') {
+ --StringLoc;
+ }
+ RtlCopyMemory(
+ u.GetDetails->AdapterName,
+ &Binding->Adapter->AdapterName[StringLoc+1],
+ Binding->Adapter->AdapterNameLength - ((StringLoc+1) * sizeof(WCHAR)));
+
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ } else {
+
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ Status = STATUS_INVALID_PARAMETER;
+
+ }
+ }
+
+ break;
+
+
+ //
+ // The Option was not supported, so fail.
+ //
+
+ default:
+
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+
+
+ } // end of the long switch on NwlinkAction->Option
+
+
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ IPX_DEBUG (ACTION, ("Nwlink action %lx failed, status %lx\n", NwlinkAction->Option, Status));
+ }
+#endif
+
+ return Status;
+
+} /* IpxTdiAction */
+
+
+VOID
+IpxCancelAction(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel an Action.
+ What is done to cancel it is specific to each action.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ PREQUEST Request = (PREQUEST)Irp;
+ CTELockHandle LockHandle;
+ PLIST_ENTRY p;
+ BOOLEAN Found;
+ UINT IOCTLType;
+
+ ASSERT( DeviceObject->DeviceExtension == IpxDevice );
+
+ //
+ // Find the request on the address notify queue.
+ //
+
+ Found = FALSE;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (p = Device->AddressNotifyQueue.Flink;
+ p != &Device->AddressNotifyQueue;
+ p = p->Flink) {
+
+ if (LIST_ENTRY_TO_REQUEST(p) == Request) {
+
+ RemoveEntryList (p);
+ Found = TRUE;
+ IOCTLType = MIPX_NOTIFYCARDINFO;
+ break;
+ }
+ }
+
+ if (!Found) {
+ for (p = Device->LineChangeQueue.Flink;
+ p != &Device->LineChangeQueue;
+ p = p->Flink) {
+
+ if (LIST_ENTRY_TO_REQUEST(p) == Request) {
+
+ RemoveEntryList (p);
+ Found = TRUE;
+ IOCTLType = MIPX_LINECHANGE;
+ break;
+ }
+ }
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ if (Found) {
+
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ IpxCompleteRequest (Request);
+ IpxFreeRequest(Device, Request);
+ if (IOCTLType == MIPX_NOTIFYCARDINFO) {
+ IPX_DEBUG(ACTION, ("Cancelled action NOTIFYCARDINFO %lx\n", Request));
+ IpxDereferenceDevice (Device, DREF_ADDRESS_NOTIFY);
+ } else {
+ IPX_DEBUG(ACTION, ("Cancelled action LINECHANGE %lx\n", Request));
+ IpxDereferenceDevice (Device, DREF_LINE_CHANGE);
+ }
+
+ }
+#if DBG
+ else {
+ IPX_DEBUG(ACTION, ("Cancelled action orphan %lx\n", Request));
+ }
+#endif
+
+} /* IpxCancelAction */
+
+
+VOID
+IpxAbortLineChanges(
+ IN PVOID ControlChannelContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine aborts any line change IRPs posted by the
+ control channel with the specified open context. It is
+ called when a control channel is being shut down.
+
+Arguments:
+
+ ControlChannelContext - The context assigned to the control
+ channel when it was opened.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ CTELockHandle LockHandle;
+ LIST_ENTRY AbortList;
+ PLIST_ENTRY p;
+ PREQUEST Request;
+ KIRQL irql;
+
+
+ InitializeListHead (&AbortList);
+
+ IoAcquireCancelSpinLock( &irql );
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ p = Device->LineChangeQueue.Flink;
+
+ while (p != &Device->LineChangeQueue) {
+ LARGE_INTEGER ControlChId;
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ CCID_FROM_REQUEST(ControlChId, Request);
+
+ p = p->Flink;
+
+ if (ControlChId.QuadPart == ((PLARGE_INTEGER)ControlChannelContext)->QuadPart) {
+ RemoveEntryList (REQUEST_LINKAGE(Request));
+ InsertTailList (&AbortList, REQUEST_LINKAGE(Request));
+ }
+ }
+
+ while (!IsListEmpty (&AbortList)) {
+
+ p = RemoveHeadList (&AbortList);
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ IPX_DEBUG(ACTION, ("Aborting line change %lx\n", Request));
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ CTEFreeLock(&Device->Lock, LockHandle);
+ IoReleaseCancelSpinLock( irql );
+
+ IpxCompleteRequest (Request);
+ IpxFreeRequest(Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_LINE_CHANGE);
+
+ IoAcquireCancelSpinLock( &irql );
+ CTEGetLock(&Device->Lock, &LockHandle);
+ }
+
+ CTEFreeLock(&Device->Lock, LockHandle);
+ IoReleaseCancelSpinLock( irql );
+} /* IpxAbortLineChanges */
+
diff --git a/private/ntos/tdi/isnp/ipx/adapter.c b/private/ntos/tdi/isnp/ipx/adapter.c
new file mode 100644
index 000000000..479570e48
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/adapter.c
@@ -0,0 +1,636 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ adapter.c
+
+Abstract:
+
+ This module contains code which implements the ADAPTER object.
+ Routines are provided to reference, and dereference transport
+ adapter objects.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// These are init only until binding is really dynamic.
+//
+#ifndef _PNP_POWER
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,IpxCreateAdapter)
+#endif
+#endif _PNP_POWER
+
+
+
+VOID
+IpxRefBinding(
+ IN PBINDING Binding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a device context.
+
+Arguments:
+
+ Binding - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ CTEAssert (Binding->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement (&Binding->ReferenceCount);
+
+} /* IpxRefBinding */
+
+
+VOID
+IpxDerefBinding(
+ IN PBINDING Binding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a device context by decrementing the
+ reference count contained in the structure. Currently, we don't
+ do anything special when the reference count drops to zero, but
+ we could dynamically unload stuff then.
+
+Arguments:
+
+ Binding - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&Binding->ReferenceCount);
+
+ CTEAssert (result >= 0);
+
+ if (result == 0) {
+ IpxDestroyBinding (Binding);
+ }
+
+} /* IpxDerefBinding */
+
+
+NTSTATUS
+IpxCreateAdapter(
+ IN PDEVICE Device,
+ IN PUNICODE_STRING AdapterName,
+ IN OUT PADAPTER *AdapterPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates and initializes a device context structure.
+
+Arguments:
+
+
+ DriverObject - pointer to the IO subsystem supplied driver object.
+
+ Adapter - Pointer to a pointer to a transport device context object.
+
+ AdapterName - pointer to the name of the device this device object points to.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
+
+--*/
+
+{
+ PADAPTER Adapter;
+#if 0
+ UINT i, j;
+#endif
+
+ Adapter = (PADAPTER)IpxAllocateMemory (sizeof(ADAPTER) + AdapterName->Length + sizeof(WCHAR), MEMORY_ADAPTER, "Adapter");
+
+#ifdef _PNP_POWER
+ if (Adapter == NULL) {
+ if (KeGetCurrentIrql() == 0) {
+ IPX_DEBUG (ADAPTER, ("Create adapter %ws failed\n", AdapterName));
+ } else {
+ IPX_DEBUG (ADAPTER, ("Create adapter %lx failed\n", AdapterName));
+ }
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ IPX_DEBUG (ADAPTER, ("Create adapter %lx %lx succeeded\n", Adapter, AdapterName));
+#else
+ if (Adapter == NULL) {
+ IPX_DEBUG (ADAPTER, ("Create adapter %ws failed\n", AdapterName->Buffer));
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ IPX_DEBUG (ADAPTER, ("Create adapter %ws succeeded\n", AdapterName->Buffer));
+#endif
+
+ RtlZeroMemory(Adapter, sizeof(ADAPTER));
+
+ //
+ // Copy over the adapter name.
+ //
+
+ Adapter->AdapterNameLength = AdapterName->Length + sizeof(WCHAR);
+ Adapter->AdapterName = (PWCHAR)(Adapter+1);
+ RtlCopyMemory(
+ Adapter->AdapterName,
+ AdapterName->Buffer,
+ AdapterName->Length);
+ Adapter->AdapterName[AdapterName->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+
+#if DBG
+ RtlCopyMemory(Adapter->Signature1, "IAD1", 4);
+#endif
+
+ Adapter->Type = IPX_ADAPTER_SIGNATURE;
+ Adapter->Size = sizeof(ADAPTER);
+
+ CTEInitLock (&Adapter->Lock);
+
+ InitializeListHead (&Adapter->RequestCompletionQueue);
+
+ InitializeListHead (&Adapter->ReceiveBufferPoolList);
+
+ ExInitializeSListHead (&Adapter->ReceiveBufferList);
+
+ Adapter->Device = Device;
+ Adapter->DeviceLock = &Device->Lock;
+ IpxReferenceDevice (Device, DREF_ADAPTER);
+
+#if 0
+ Adapter->ReceiveBufferPool.Next = NULL;
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+ Adapter->Bindings[i] = NULL;
+ }
+ Adapter->BindingCount = 0;
+
+ for (i = 0; i < IDENTIFIER_TOTAL; i++) {
+ for (j = 0; j < SOURCE_ROUTE_HASH_SIZE; j++) {
+ Adapter->SourceRoutingHeads[i][j] = (PSOURCE_ROUTE)NULL;
+ }
+ }
+#endif
+
+ //
+ // BUGBUG: For the moment, we have to do the source
+ // routing operation on any type where broadcast
+ // may not be used for discovery -- improve this
+ // hopefully.
+ //
+
+ Adapter->SourceRoutingEmpty[IDENTIFIER_RIP] = FALSE;
+ Adapter->SourceRoutingEmpty[IDENTIFIER_IPX] = FALSE;
+ Adapter->SourceRoutingEmpty[IDENTIFIER_SPX] = FALSE;
+ Adapter->SourceRoutingEmpty[IDENTIFIER_NB] = TRUE;
+
+#ifdef _PNP_POWER
+ //
+ // Lock here? [BUGBUGZZ]
+ //
+ Adapter->ReferenceCount = 1;
+#endif
+
+ *AdapterPtr = Adapter;
+
+ return STATUS_SUCCESS;
+
+} /* IpxCreateAdapter */
+
+
+VOID
+IpxDestroyAdapter(
+ IN PADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a device context structure.
+
+Arguments:
+
+ Adapter - Pointer to a pointer to a transport device context object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Database, Hash;
+ PSOURCE_ROUTE Current;
+ ULONG ReceiveBufferPoolSize;
+ PIPX_RECEIVE_BUFFER ReceiveBuffer;
+ PIPX_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ PDEVICE Device = Adapter->Device;
+ PLIST_ENTRY p;
+ UINT i;
+
+ IPX_DEBUG (ADAPTER, ("Destroy adapter %lx\n", Adapter));
+
+ //
+ // Free any receive buffer pools this adapter has.
+ //
+
+ ReceiveBufferPoolSize = FIELD_OFFSET (IPX_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(IPX_RECEIVE_BUFFER) * Device->InitReceiveBuffers) +
+ (Adapter->MaxReceivePacketSize * Device->InitReceiveBuffers);
+
+ while (!IsListEmpty (&Adapter->ReceiveBufferPoolList)) {
+
+ p = RemoveHeadList (&Adapter->ReceiveBufferPoolList);
+ ReceiveBufferPool = CONTAINING_RECORD (p, IPX_RECEIVE_BUFFER_POOL, Linkage);
+
+ for (i = 0; i < ReceiveBufferPool->BufferCount; i++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[i];
+ IpxDeinitializeReceiveBuffer (Adapter, ReceiveBuffer, Adapter->MaxReceivePacketSize);
+
+ }
+
+ IPX_DEBUG (PACKET, ("Free buffer pool %lx\n", ReceiveBufferPool));
+ IpxFreeMemory (ReceiveBufferPool, ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+ }
+
+ //
+ // Free all the source routing information for this adapter.
+ //
+
+ for (Database = 0; Database < IDENTIFIER_TOTAL; Database++) {
+
+ for (Hash = 0; Hash < SOURCE_ROUTE_HASH_SIZE; Hash++) {
+
+ while (Adapter->SourceRoutingHeads[Database][Hash]) {
+
+ Current = Adapter->SourceRoutingHeads[Database][Hash];
+ Adapter->SourceRoutingHeads[Database][Hash] = Current->Next;
+
+ IpxFreeMemory (Current, SOURCE_ROUTE_SIZE (Current->SourceRoutingLength), MEMORY_SOURCE_ROUTE, "SourceRouting");
+ }
+ }
+ }
+
+ IpxDereferenceDevice (Adapter->Device, DREF_ADAPTER);
+ IpxFreeMemory (Adapter, sizeof(ADAPTER) + Adapter->AdapterNameLength, MEMORY_ADAPTER, "Adapter");
+
+} /* IpxDestroyAdapter */
+
+
+NTSTATUS
+IpxCreateBinding(
+ IN PDEVICE Device,
+ IN PBINDING_CONFIG ConfigBinding OPTIONAL,
+ IN ULONG NetworkNumberIndex,
+ IN PWCHAR AdapterName,
+ IN OUT PBINDING *BindingPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates and initializes a binding structure.
+
+Arguments:
+
+ Device - The device.
+
+ ConfigBinding - Information about this binding. If this is
+ NULL then this is a WAN binding and all the relevant
+ information will be filled in by the caller.
+
+ NetworkNumberIndex - The index in the frame type array for
+ ConfigBinding indicating which frame type this binding is for.
+ Not used if ConfigBinding is not provided.
+
+ AdapterName - Used for error logging.
+
+ BindingPtr - Returns the allocated binding structure.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
+
+--*/
+
+{
+ PBINDING Binding;
+#ifdef _PNP_POWER
+ PSINGLE_LIST_ENTRY s;
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BindingList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ goto GotBinding;
+ }
+
+ //
+ // This function tries to allocate another packet pool.
+ //
+
+ s = IpxPopBinding(Device);
+
+ //
+ // Possibly we should queue the packet up to wait
+ // for one to become free.
+ //
+
+ if (s == NULL) {
+
+#if DBG
+ if (KeGetCurrentIrql() == 0) {
+ IPX_DEBUG (ADAPTER, ("Create binding %ws failed\n", AdapterName));
+ } else {
+ IPX_DEBUG (ADAPTER, ("Create binding WAN failed\n"));
+ }
+#endif
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+GotBinding:
+
+ Binding = CONTAINING_RECORD (s, BINDING, PoolLinkage);
+
+#else
+ Binding = (PBINDING)IpxAllocateMemory (sizeof(BINDING), MEMORY_ADAPTER, "Binding");
+
+ //
+ // We can't vsprintf a %ws at DPC level, so we check for
+ // that. Only WAN bindings will be created then.
+ //
+
+ if (Binding == NULL) {
+#if DBG
+ if (KeGetCurrentIrql() == 0) {
+ IPX_DEBUG (ADAPTER, ("Create binding %ws failed\n", AdapterName));
+ } else {
+ IPX_DEBUG (ADAPTER, ("Create binding WAN failed\n"));
+ }
+#endif
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+#endif
+
+#if DBG
+ if (KeGetCurrentIrql() == 0) {
+ IPX_DEBUG (ADAPTER, ("Create binding %ws succeeded, %lx\n", AdapterName, Binding));
+ } else {
+ IPX_DEBUG (ADAPTER, ("Create binding WAN succeeded\n"));
+ }
+#endif
+
+ RtlZeroMemory(Binding, sizeof(BINDING));
+
+ //
+ // Initialize the reference count.
+ //
+
+ Binding->ReferenceCount = 1;
+#if DBG
+ Binding->RefTypes[BREF_BOUND] = 1;
+#endif
+
+#if DBG
+ RtlCopyMemory(Binding->Signature1, "IBI1", 4);
+#endif
+
+ Binding->Type = IPX_BINDING_SIGNATURE;
+ Binding->Size = sizeof(BINDING);
+
+ Binding->Device = Device;
+ Binding->DeviceLock = &Device->Lock;
+
+ if (ConfigBinding != NULL) {
+
+ ULONG Temp = ConfigBinding->NetworkNumber[NetworkNumberIndex];
+ Binding->ConfiguredNetworkNumber = REORDER_ULONG (Temp);
+
+ Binding->AutoDetect = ConfigBinding->AutoDetect[NetworkNumberIndex];
+ Binding->DefaultAutoDetect = ConfigBinding->DefaultAutoDetect[NetworkNumberIndex];
+
+ Binding->AllRouteDirected = (BOOLEAN)ConfigBinding->Parameters[BINDING_ALL_ROUTE_DEF];
+ Binding->AllRouteBroadcast = (BOOLEAN)ConfigBinding->Parameters[BINDING_ALL_ROUTE_BC];
+ Binding->AllRouteMulticast = (BOOLEAN)ConfigBinding->Parameters[BINDING_ALL_ROUTE_MC];
+
+ }
+
+ Binding->ReceiveBroadcast = TRUE;
+#if 0
+ Binding->BindingSetMember = FALSE;
+ Binding->NextBinding = (PBINDING)NULL;
+ Binding->DialOutAsync = FALSE;
+#endif
+
+ //
+ // We set Binding->FrameType later, after we can map it based on the
+ // media type of the adapter we bind to.
+ //
+
+ *BindingPtr = Binding;
+
+ return STATUS_SUCCESS;
+
+} /* IpxCreateBinding */
+
+
+VOID
+IpxDestroyBinding(
+ IN PBINDING Binding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a binding structure.
+
+Arguments:
+
+ Binding - Pointer to a transport binding structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IPX_DEBUG (ADAPTER, ("Destroy binding %lx\n", Binding));
+
+#ifdef _PNP_POWER
+
+ IPX_PUSH_ENTRY_LIST(
+ &IpxDevice->BindingList,
+ &Binding->PoolLinkage,
+ &IpxDevice->SListsLock);
+#else
+ IpxFreeMemory (Binding, sizeof(BINDING), MEMORY_ADAPTER, "Binding");
+#endif
+
+} /* IpxDestroyBinding */
+
+
+#ifdef _PNP_POWER
+VOID
+IpxAllocateBindingPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 bindings to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_BINDING_POOL BindingPool;
+ UINT BindingPoolSize;
+ UINT BindingNum;
+ PBINDING Binding;
+ CTELockHandle LockHandle;
+
+ BindingPoolSize = FIELD_OFFSET (IPX_BINDING_POOL, Bindings[0]) +
+ (sizeof(BINDING) * Device->InitBindings);
+
+ BindingPool = (PIPX_BINDING_POOL)IpxAllocateMemory (BindingPoolSize, MEMORY_PACKET, "BindingPool");
+
+ if (BindingPool == NULL) {
+ IPX_DEBUG (PNP, ("Could not allocate binding pool memory\n"));
+ return;
+ }
+
+
+ IPX_DEBUG (PNP, ("Initializing Binding pool %lx, %d bindings\n",
+ BindingPool, Device->InitBindings));
+
+ BindingPool->BindingCount = Device->InitBindings;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (BindingNum = 0; BindingNum < BindingPool->BindingCount; BindingNum++) {
+
+ Binding = &BindingPool->Bindings[BindingNum];
+ IPX_PUSH_ENTRY_LIST (&Device->BindingList, &Binding->PoolLinkage, &Device->SListsLock);
+
+#ifdef IPX_TRACK_POOL
+ Binding->Pool = BindingPool;
+#endif
+ }
+
+ InsertTailList (&Device->BindingPoolList, &BindingPool->Linkage);
+
+ Device->AllocatedBindings += BindingPool->BindingCount;
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+} /* IpxAllocateBindingPool */
+
+
+PSINGLE_LIST_ENTRY
+IpxPopBinding(
+ PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a binding from the device context's pool.
+ If there are no bindings in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated binding.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BindingList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedBindings < Device->MaxPoolBindings) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ IpxAllocateBindingPool (Device);
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BindingList,
+ &Device->SListsLock);
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* IpxPopBinding */
+#endif
diff --git a/private/ntos/tdi/isnp/ipx/address.c b/private/ntos/tdi/isnp/ipx/address.c
new file mode 100644
index 000000000..1049bc8de
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/address.c
@@ -0,0 +1,1843 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ address.c
+
+Abstract:
+
+ This module contains code which implements the ADDRESS object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport address objects.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports - tagged [CH]
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Map all generic accesses to the same one.
+//
+
+static GENERIC_MAPPING AddressGenericMapping =
+ { READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL };
+
+
+
+TDI_ADDRESS_IPX UNALIGNED *
+IpxParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, looking for an address
+ of type TDI_ADDRESS_TYPE_IPX.
+
+Arguments:
+
+ Transport - The generic TDI address.
+
+Return Value:
+
+ A pointer to the IPX address, or NULL if none is found.
+
+--*/
+
+{
+ TA_ADDRESS UNALIGNED * addressName;
+ INT i;
+
+ addressName = &TransportAddress->Address[0];
+
+ //
+ // The name can be passed with multiple entries; we'll take and use only
+ // the IPX one.
+ //
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++) {
+ if (addressName->AddressType == TDI_ADDRESS_TYPE_IPX) {
+ if (addressName->AddressLength >= sizeof(TDI_ADDRESS_IPX)) {
+ return ((TDI_ADDRESS_IPX UNALIGNED *)(addressName->Address));
+ }
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+ return NULL;
+
+} /* IpxParseTdiAddress */
+
+
+BOOLEAN
+IpxValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, verifying that the
+ components of the address do not extend past the specified
+ length.
+
+Arguments:
+
+ TransportAddress - The generic TDI address.
+
+ TransportAddressLength - The specific length of TransportAddress.
+
+Return Value:
+
+ TRUE if the address is valid, FALSE otherwise.
+
+--*/
+
+{
+ PUCHAR AddressEnd = ((PUCHAR)TransportAddress) + TransportAddressLength;
+ TA_ADDRESS UNALIGNED * addressName;
+ INT i;
+
+ if (TransportAddressLength < sizeof(TransportAddress->TAAddressCount)) {
+ IpxPrint0 ("IpxValidateTdiAddress: runt address\n");
+ return FALSE;
+ }
+
+ addressName = &TransportAddress->Address[0];
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++) {
+ if (addressName->Address > AddressEnd) {
+ IpxPrint0 ("IpxValidateTdiAddress: address too short\n");
+ return FALSE;
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+
+ if ((PUCHAR)addressName > AddressEnd) {
+ IpxPrint0 ("IpxValidateTdiAddress: address too short\n");
+ return FALSE;
+ }
+ return TRUE;
+
+} /* IpxValidateTdiAddress */
+
+#if DBG
+
+VOID
+IpxBuildTdiAddress(
+ IN PVOID AddressBuffer,
+ IN ULONG Network,
+ IN UCHAR Node[6],
+ IN USHORT Socket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine fills in a TRANSPORT_ADDRESS in the specified
+ buffer, given the socket, network and node.
+
+Arguments:
+
+ AddressBuffer - The buffer that will hold the address.
+
+ Network - The network number.
+
+ Node - The node address.
+
+ Socket - The socket.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ TA_IPX_ADDRESS UNALIGNED * IpxAddress;
+
+ IpxAddress = (TA_IPX_ADDRESS UNALIGNED *)AddressBuffer;
+
+ IpxAddress->TAAddressCount = 1;
+ IpxAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX);
+ IpxAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
+ IpxAddress->Address[0].Address[0].NetworkAddress = Network;
+ IpxAddress->Address[0].Address[0].Socket = Socket;
+ RtlCopyMemory(IpxAddress->Address[0].Address[0].NodeAddress, Node, 6);
+
+} /* IpxBuildTdiAddress */
+#endif
+
+
+NTSTATUS
+IpxOpenAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens a file that points to an existing address object, or, if
+ the object doesn't exist, creates it (note that creation of the address
+ object includes registering the address, and may take many seconds to
+ complete, depending upon system configuration).
+
+ If the address already exists, and it has an ACL associated with it, the
+ ACL is checked for access rights before allowing creation of the address.
+
+Arguments:
+
+ Device - pointer to the device describing the IPX transport.
+
+ Request - a pointer to the request used for the creation of the address.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ PFILE_FULL_EA_INFORMATION ea;
+ TRANSPORT_ADDRESS UNALIGNED *name;
+ TA_ADDRESS UNALIGNED *AddressName;
+ USHORT Socket;
+ ULONG DesiredShareAccess;
+ CTELockHandle LockHandle;
+ PACCESS_STATE AccessState;
+ ACCESS_MASK GrantedAccess;
+ BOOLEAN AccessAllowed;
+ int i;
+ BOOLEAN found = FALSE;
+#ifdef ISN_NT
+ PIRP Irp = (PIRP)Request;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+#endif
+
+
+ //
+ // If we are a dedicated router, we cannot let addresses
+ // be opened.
+ //
+
+ if (Device->DedicatedRouter) {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ //
+ // The network name is in the EA, passed in the request.
+ //
+
+ ea = OPEN_REQUEST_EA_INFORMATION(Request);
+ if (ea == NULL) {
+ IpxPrint1("OpenAddress: REQUEST %lx has no EA\n", Request);
+ return STATUS_NONEXISTENT_EA_ENTRY;
+ }
+
+ //
+ // this may be a valid name; parse the name from the EA and use it if OK.
+ //
+
+ name = (PTRANSPORT_ADDRESS)&ea->EaName[ea->EaNameLength+1];
+ AddressName = (PTA_ADDRESS)&name->Address[0];
+
+ //
+ // The name can be passed with multiple entries; we'll take and use only
+ // the first one of type IPX.
+ //
+
+ for (i=0;i<name->TAAddressCount;i++) {
+ if (AddressName->AddressType == TDI_ADDRESS_TYPE_IPX) {
+ if (AddressName->AddressLength >= sizeof(TDI_ADDRESS_IPX)) {
+ Socket = ((TDI_ADDRESS_IPX UNALIGNED *)&AddressName->Address[0])->Socket;
+ found = TRUE;
+ }
+ break;
+
+ } else {
+
+ AddressName = (PTA_ADDRESS)(AddressName->Address +
+ AddressName->AddressLength);
+
+ }
+
+ }
+
+ if (!found) {
+ IPX_DEBUG (ADDRESS, ("OpenAddress, request %lx has no IPX Address\n", Request));
+ return STATUS_NONEXISTENT_EA_ENTRY;
+ }
+
+ if (Socket == 0) {
+
+ Socket = IpxAssignSocket (Device);
+
+ if (Socket == 0) {
+ IPX_DEBUG (ADDRESS, ("OpenAddress, no unique socket found\n"));
+ return STATUS_INSUFFICIENT_RESOURCES;
+ } else {
+ IPX_DEBUG (ADDRESS, ("OpenAddress, assigned socket %lx\n", REORDER_USHORT(Socket)));
+ }
+
+ } else {
+
+ IPX_DEBUG (ADDRESS, ("OpenAddress, socket %lx\n", REORDER_USHORT(Socket)));
+
+ }
+
+ //
+ // get an address file structure to represent this address.
+ //
+
+ AddressFile = IpxCreateAddressFile (Device);
+
+ if (AddressFile == (PADDRESS_FILE)NULL) {
+ return status;
+ }
+
+ //
+ // We mark this socket specially.
+ //
+
+ if (Socket == SAP_SOCKET) {
+ AddressFile->IsSapSocket = TRUE;
+ AddressFile->SpecialReceiveProcessing = TRUE;
+ }
+
+ //
+ // See if this address is already established. This call automatically
+ // increments the reference count on the address so that it won't disappear
+ // from underneath us after this call but before we have a chance to use it.
+ //
+ // To ensure that we don't create two address objects for the
+ // same address, we hold the device context addressResource until
+ // we have found the address or created a new one.
+ //
+
+ ExAcquireResourceExclusive (&Device->AddressResource, TRUE);
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ Address = IpxLookupAddress (Device, Socket);
+
+ if (Address == NULL) {
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ //
+ // This address doesn't exist. Create it.
+ // registering it.
+ //
+
+ Address = IpxCreateAddress (
+ Device,
+ Socket);
+
+ if (Address != (PADDRESS)NULL) {
+
+ //
+ // Set this now in case we have to deref.
+ //
+
+ AddressFile->AddressLock = &Address->Lock;
+
+#ifdef ISN_NT
+
+ //
+ // Initialize the shared access now. We use read access
+ // to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ IoSetShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &Address->u.ShareAccess);
+
+
+ //
+ // Assign the security descriptor (need to do this with
+ // the spinlock released because the descriptor is not
+ // mapped).
+ //
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ status = SeAssignSecurity(
+ NULL, // parent descriptor
+ AccessState->SecurityDescriptor,
+ &Address->SecurityDescriptor,
+ FALSE, // is directory
+ &AccessState->SubjectSecurityContext,
+ &AddressGenericMapping,
+ NonPagedPool);
+
+ if (!NT_SUCCESS(status)) {
+
+ //
+ // Error, return status.
+ //
+
+ IoRemoveShareAccess (IrpSp->FileObject, &Address->u.ShareAccess);
+ ExReleaseResource (&Device->AddressResource);
+ IpxDereferenceAddress (Address, AREF_ADDRESS_FILE);
+ IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ return status;
+
+ }
+
+#endif
+
+ ExReleaseResource (&Device->AddressResource);
+
+ //
+ // if the adapter isn't ready, we can't do any of this; get out
+ //
+
+ if (Device->State == DEVICE_STATE_STOPPING) {
+ IpxDereferenceAddress (Address, AREF_ADDRESS_FILE);
+ IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ status = STATUS_DEVICE_NOT_READY;
+
+ } else {
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+#ifdef ISN_NT
+ AddressFile->FileObject = IrpSp->FileObject;
+#endif
+ AddressFile->Request = Request;
+ AddressFile->Address = Address;
+
+ CTEGetLock (&Address->Lock, &LockHandle);
+ InsertTailList (&Address->AddressFileDatabase, &AddressFile->Linkage);
+ CTEFreeLock (&Address->Lock, LockHandle);
+
+ AddressFile->Request = NULL;
+ AddressFile->State = ADDRESSFILE_STATE_OPEN;
+ status = STATUS_SUCCESS;
+
+ }
+
+ } else {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ //
+ // If the address could not be created, and is not in the
+ // process of being created, then we can't open up an address.
+ // Since we can't use the AddressLock to deref, we just destroy
+ // the address file.
+ //
+
+ IpxDestroyAddressFile (AddressFile);
+
+ }
+
+ } else {
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ IPX_DEBUG (ADDRESS, ("Add to address %lx\n", Address));
+
+ //
+ // Set this now in case we have to deref.
+ //
+
+ AddressFile->AddressLock = &Address->Lock;
+
+ //
+ // The address already exists. Check the ACL and see if we
+ // can access it. If so, simply use this address as our address.
+ //
+
+#ifdef ISN_NT
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ AccessAllowed = SeAccessCheck(
+ Address->SecurityDescriptor,
+ &AccessState->SubjectSecurityContext,
+ FALSE, // tokens locked
+ IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
+ (ACCESS_MASK)0, // previously granted
+ NULL, // privileges
+ &AddressGenericMapping,
+ Irp->RequestorMode,
+ &GrantedAccess,
+ &status);
+
+#else // ISN_NT
+
+ AccessAllowed = TRUE;
+
+#endif // ISN_NT
+
+ if (!AccessAllowed) {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ } else {
+
+#ifdef ISN_NT
+
+ //
+ // Now check that we can obtain the desired share
+ // access. We use read access to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ status = IoCheckShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &Address->u.ShareAccess,
+ TRUE);
+
+#else // ISN_NT
+
+ status = STATUS_SUCCESS;
+
+#endif // ISN_NT
+
+ if (!NT_SUCCESS (status)) {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ } else {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ CTEGetLock (&Address->Lock, &LockHandle);
+
+ InsertTailList (
+ &Address->AddressFileDatabase,
+ &AddressFile->Linkage);
+
+ AddressFile->Request = NULL;
+ AddressFile->Address = Address;
+#ifdef ISN_NT
+ AddressFile->FileObject = IrpSp->FileObject;
+#endif
+ AddressFile->State = ADDRESSFILE_STATE_OPEN;
+
+ IpxReferenceAddress (Address, AREF_ADDRESS_FILE);
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ CTEFreeLock (&Address->Lock, LockHandle);
+
+ status = STATUS_SUCCESS;
+
+ }
+ }
+
+ //
+ // Remove the reference from IpxLookupAddress.
+ //
+
+ IpxDereferenceAddress (Address, AREF_LOOKUP);
+ }
+
+ return status;
+
+} /* IpxOpenAddress */
+
+
+USHORT
+IpxAssignSocket(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine assigns a socket that is unique within a range
+ of SocketUniqueness.
+
+Arguments:
+
+ Device - Pointer to the device context.
+
+Return Value:
+
+ The assigned socket number, or 0 if a unique one cannot
+ be found.
+
+--*/
+
+{
+ USHORT InitialSocket, CurrentSocket, AddressSocket;
+ ULONG CurrentHash;
+ BOOLEAN Conflict;
+ PLIST_ENTRY p;
+ PADDRESS Address;
+ CTELockHandle LockHandle;
+
+ //
+ // Loop through all possible sockets, starting at
+ // Device->CurrentSocket, looking for a suitable one.
+ // Device->CurrentSocket rotates through the possible
+ // sockets to improve the chances of finding one
+ // quickly.
+ //
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ InitialSocket = Device->CurrentSocket;
+ Device->CurrentSocket = (USHORT)(Device->CurrentSocket + Device->SocketUniqueness);
+ if ((USHORT)(Device->CurrentSocket+Device->SocketUniqueness) > Device->SocketEnd) {
+ Device->CurrentSocket = Device->SocketStart;
+ }
+
+ CurrentSocket = InitialSocket;
+
+ do {
+
+ //
+ // Scan all addresses; if we find one with a socket
+ // that conflicts with this one, we can't use it.
+ //
+ // NOTE: Device->Lock is acquired here.
+ //
+
+ Conflict = FALSE;
+
+ for (CurrentHash = 0; CurrentHash < IPX_ADDRESS_HASH_COUNT; CurrentHash++) {
+
+ for (p = Device->AddressDatabases[CurrentHash].Flink;
+ p != &Device->AddressDatabases[CurrentHash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+ AddressSocket = REORDER_USHORT(Address->Socket);
+
+ if ((AddressSocket + Device->SocketUniqueness > CurrentSocket) &&
+ (AddressSocket < CurrentSocket + Device->SocketUniqueness)) {
+ Conflict = TRUE;
+ break;
+ }
+ }
+
+ //
+ // If we've found a conflict, no need to check the other
+ // queues.
+ //
+
+ if (Conflict) {
+ break;
+ }
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ //
+ // We intentionally free the lock here so that we
+ // never spend too much time with it held.
+ //
+
+ if (!Conflict) {
+
+ //
+ // We went through the address list without
+ // finding a conflict; use this socket.
+ //
+
+ return REORDER_USHORT(CurrentSocket);
+ }
+
+ CurrentSocket = (USHORT)(CurrentSocket + Device->SocketUniqueness);
+ if ((USHORT)(CurrentSocket+Device->SocketUniqueness) > Device->SocketEnd) {
+ CurrentSocket = Device->SocketStart;
+ }
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ } while (CurrentSocket != InitialSocket);
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ //
+ // Could not find one to assign.
+ //
+
+ return (USHORT)0;
+
+} /* IpxAssignSocket */
+
+
+PADDRESS
+IpxCreateAddress(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a transport address and associates it with
+ the specified transport device context. The reference count in the
+ address is automatically set to 1, and the reference count of the
+ device context is incremented.
+
+ NOTE: This routine must be called with the Device
+ spinlock held.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ Socket - The socket to assign to this address.
+
+Return Value:
+
+ The newly created address, or NULL if none can be allocated.
+
+--*/
+
+{
+ PADDRESS Address;
+ PIPX_SEND_RESERVED SendReserved;
+ PIPX_RECEIVE_RESERVED ReceiveReserved;
+ NDIS_STATUS Status;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ Address = (PADDRESS)IpxAllocateMemory (sizeof(ADDRESS), MEMORY_ADDRESS, "Address");
+ if (Address == NULL) {
+ IPX_DEBUG (ADDRESS, ("Create address %lx failed\n", REORDER_USHORT(Socket)));
+ return NULL;
+ }
+
+ IPX_DEBUG (ADDRESS, ("Create address %lx (%lx)\n", Address, REORDER_USHORT(Socket)));
+ RtlZeroMemory (Address, sizeof(ADDRESS));
+
+#ifndef IPX_OWN_PACKETS
+ IpxAllocateSingleSendPacket(Device, &Address->SendPacket, &Status);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ goto Fail1;
+ }
+#endif
+
+ if (IpxInitializeSendPacket (Device, &Address->SendPacket, Address->SendPacketHeader) != STATUS_SUCCESS) {
+#ifndef IPX_OWN_PACKETS
+Fail1:
+#endif
+ Address->SendPacketInUse = TRUE;
+ } else {
+ SendReserved = SEND_RESERVED(&Address->SendPacket);
+ SendReserved->Address = Address;
+ SendReserved->OwnedByAddress = TRUE;
+ Address->SendPacketInUse = FALSE;
+#ifdef IPX_TRACK_POOL
+ SendReserved->Pool = NULL;
+#endif
+ }
+
+
+#if BACK_FILL
+ {
+ PIPX_SEND_RESERVED BackFillReserved;
+
+#ifndef IPX_OWN_PACKETS
+ IpxAllocateSingleSendPacket(Device, &Address->BackFillPacket, &Status);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ goto Fail2;
+ }
+#endif
+ if (IpxInitializeBackFillPacket (Device, &Address->BackFillPacket, NULL) != STATUS_SUCCESS) {
+#ifndef IPX_OWN_PACKETS
+Fail2:
+#endif
+ Address->BackFillPacketInUse = TRUE;
+ } else {
+ BackFillReserved = SEND_RESERVED(&Address->BackFillPacket);
+ BackFillReserved->Address = Address;
+ Address->BackFillPacketInUse = FALSE;
+ BackFillReserved->OwnedByAddress = TRUE;
+#ifdef IPX_TRACK_POOL
+ BackFillReserved->Pool = NULL;
+#endif
+ }
+ }
+#endif
+
+#ifndef IPX_OWN_PACKETS
+ IpxAllocateSingleReceivePacket(Device, &Address->ReceivePacket, &Status);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ goto Fail3;
+ }
+#endif
+ if (IpxInitializeReceivePacket (Device, &Address->ReceivePacket) != STATUS_SUCCESS) {
+#ifndef IPX_OWN_PACKETS
+Fail3:
+#endif
+ Address->ReceivePacketInUse = TRUE;
+ } else {
+ ReceiveReserved = RECEIVE_RESERVED(&Address->ReceivePacket);
+ ReceiveReserved->Address = Address;
+ ReceiveReserved->OwnedByAddress = TRUE;
+ Address->ReceivePacketInUse = FALSE;
+#ifdef IPX_TRACK_POOL
+ ReceiveReserved->Pool = NULL;
+#endif
+ }
+
+ Address->Type = IPX_ADDRESS_SIGNATURE;
+ Address->Size = sizeof (ADDRESS);
+
+ Address->Device = Device;
+ Address->DeviceLock = &Device->Lock;
+ CTEInitLock (&Address->Lock);
+
+ InitializeListHead (&Address->AddressFileDatabase);
+
+ Address->ReferenceCount = 1;
+#if DBG
+ Address->RefTypes[AREF_ADDRESS_FILE] = 1;
+#endif
+ Address->Socket = Socket;
+ Address->SendSourceSocket = Socket;
+
+ //
+ // Save our local address for building datagrams quickly.
+ //
+
+ RtlCopyMemory (&Address->LocalAddress, &Device->SourceAddress, FIELD_OFFSET(TDI_ADDRESS_IPX,Socket));
+ Address->LocalAddress.Socket = Socket;
+
+ //
+ // Now link this address into the specified device context's
+ // address database. To do this, we need to acquire the spin lock
+ // on the device context.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+ InsertTailList (&Device->AddressDatabases[IPX_HASH_SOCKET(Socket)], &Address->Linkage);
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ IpxReferenceDevice (Device, DREF_ADDRESS);
+
+ return Address;
+
+} /* IpxCreateAddress */
+
+
+NTSTATUS
+IpxVerifyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to verify that the pointer given us in a file
+ object is in fact a valid address file object. We also verify that the
+ address object pointed to by it is a valid address object, and reference
+ it to keep it from disappearing while we use it.
+
+Arguments:
+
+ AddressFile - potential pointer to a ADDRESS_FILE object
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_ADDRESS otherwise
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ NTSTATUS status = STATUS_SUCCESS;
+ PADDRESS Address;
+
+ //
+ // try to verify the address file signature. If the signature is valid,
+ // verify the address pointed to by it and get the address spinlock.
+ // check the address's state, and increment the reference count if it's
+ // ok to use it. Note that the only time we return an error for state is
+ // if the address is closing.
+ //
+
+ try {
+
+ if ((AddressFile->Size == sizeof (ADDRESS_FILE)) &&
+ (AddressFile->Type == IPX_ADDRESSFILE_SIGNATURE) ) {
+// (AddressFile->State != ADDRESSFILE_STATE_CLOSING) ) {
+
+ Address = AddressFile->Address;
+
+ if ((Address->Size == sizeof (ADDRESS)) &&
+ (Address->Type == IPX_ADDRESS_SIGNATURE) ) {
+
+ CTEGetLock (&Address->Lock, &LockHandle);
+
+ if (!Address->Stopping) {
+
+ IpxReferenceAddressFileLock (AddressFile, AFREF_VERIFY);
+
+ } else {
+
+ IpxPrint1("IpxVerifyAddressFile: A %lx closing\n", Address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ CTEFreeLock (&Address->Lock, LockHandle);
+
+ } else {
+
+ IpxPrint1("IpxVerifyAddressFile: A %lx bad signature\n", Address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } else {
+
+ IpxPrint1("IpxVerifyAddressFile: AF %lx bad signature\n", AddressFile);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ IpxPrint1("IpxVerifyAddressFile: AF %lx exception\n", Address);
+ return GetExceptionCode();
+ }
+
+ return status;
+
+} /* IpxVerifyAddressFile */
+
+
+VOID
+IpxDestroyAddress(
+ IN PVOID Parameter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a transport address and removes all references
+ made by it to other objects in the transport. The address structure
+ is returned to nonpaged system pool. It is assumed
+ that the caller has already removed all addressfile structures associated
+ with this address.
+
+ It is called from a worker thread queue by IpxDerefAddress when
+ the reference count goes to 0.
+
+ This thread is only queued by IpxDerefAddress. The reason for
+ this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ Address - Pointer to a transport address structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PADDRESS Address = (PADDRESS)Parameter;
+ PDEVICE Device = Address->Device;
+ CTELockHandle LockHandle;
+
+ IPX_DEBUG (ADDRESS, ("Destroy address %lx (%lx)\n", Address, REORDER_USHORT(Address->Socket)));
+
+ SeDeassignSecurity (&Address->SecurityDescriptor);
+
+ //
+ // Delink this address from its associated device context's address
+ // database. To do this we must spin lock on the device context object,
+ // not on the address.
+ //
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Address->Linkage);
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ if (!Address->SendPacketInUse) {
+ IpxDeinitializeSendPacket (Device, &Address->SendPacket);
+#ifndef IPX_OWN_PACKETS
+ IpxFreeSingleSendPacket (Device, Address->SendPacket);
+#endif
+ }
+
+ if (!Address->ReceivePacketInUse) {
+ IpxDeinitializeReceivePacket (Device, &Address->ReceivePacket);
+#ifndef IPX_OWN_PACKETS
+ IpxFreeSingleReceivePacket (Device, Address->ReceivePacket);
+#endif
+ }
+
+#if BACK_FILL
+ if (!Address->BackFillPacketInUse) {
+ IpxDeinitializeBackFillPacket (Device, &Address->BackFillPacket);
+#ifndef IPX_OWN_PACKETS
+ IpxFreeSingleSendPacket (Device, Address->BackFillPacket);
+#endif
+ }
+#endif
+ IpxFreeMemory (Address, sizeof(ADDRESS), MEMORY_ADDRESS, "Address");
+
+ IpxDereferenceDevice (Device, DREF_ADDRESS);
+
+} /* IpxDestroyAddress */
+
+
+#if DBG
+VOID
+IpxRefAddress(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (Address->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement(&Address->ReferenceCount);
+
+} /* IpxRefAddress */
+
+
+VOID
+IpxRefAddressLock(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address
+ when the device lock is already held.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (Address->ReferenceCount > 0); // not perfect, but...
+
+ // ++Address->ReferenceCount;
+ (VOID)InterlockedIncrement(&Address->ReferenceCount);
+
+} /* IpxRefAddressLock */
+#endif
+
+
+VOID
+IpxDerefAddress(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport address by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IpxDestroyAddress to remove it from the system.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+
+ oldvalue = IPX_ADD_ULONG (
+ &Address->ReferenceCount,
+ (ULONG)-1,
+ Address->DeviceLock);
+
+ //
+ // If we have deleted all references to this address, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ CTEAssert (oldvalue != 0);
+
+ if (oldvalue == 1) {
+
+#if ISN_NT
+ ExInitializeWorkItem(
+ &Address->u.DestroyAddressQueueItem,
+ IpxDestroyAddress,
+ (PVOID)Address);
+ ExQueueWorkItem(&Address->u.DestroyAddressQueueItem, DelayedWorkQueue);
+#else
+ IpxDestroyAddress(Address);
+#endif
+
+ }
+
+} /* IpxDerefAddress */
+
+
+VOID
+IpxDerefAddressSync(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport address by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IpxDestroyAddress to remove it from the system. This routine can
+ only be called when we are synchronized (inside an IPX_SYNC_START/
+ IPX_SYNC_END pair, with a lock held, or in an indication).
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+
+ oldvalue = IPX_ADD_ULONG (
+ &Address->ReferenceCount,
+ (ULONG)-1,
+ Address->DeviceLock);
+
+ //
+ // If we have deleted all references to this address, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ CTEAssert (oldvalue != 0);
+
+ if (oldvalue == 1) {
+
+#if ISN_NT
+ ExInitializeWorkItem(
+ &Address->u.DestroyAddressQueueItem,
+ IpxDestroyAddress,
+ (PVOID)Address);
+ ExQueueWorkItem(&Address->u.DestroyAddressQueueItem, DelayedWorkQueue);
+#else
+ IpxDestroyAddress(Address);
+#endif
+
+ }
+
+} /* IpxDerefAddressSync */
+
+
+PADDRESS_FILE
+IpxCreateAddressFile(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates an address file from the pool of ther
+ specified device context. The reference count in the
+ address is automatically set to 1.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+Return Value:
+
+ The allocate address file or NULL.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PADDRESS_FILE AddressFile;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ AddressFile = (PADDRESS_FILE)IpxAllocateMemory (sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile");
+ if (AddressFile == NULL) {
+ IPX_DEBUG (ADDRESS, ("Create address file failed\n"));
+ CTEFreeLock (&Device->Lock, LockHandle);
+ return NULL;
+ }
+
+ IPX_DEBUG (ADDRESS, ("Create address file %lx\n", AddressFile));
+
+ RtlZeroMemory (AddressFile, sizeof(ADDRESS_FILE));
+
+ AddressFile->Type = IPX_ADDRESSFILE_SIGNATURE;
+ AddressFile->Size = sizeof (ADDRESS_FILE);
+
+ InitializeListHead (&AddressFile->ReceiveDatagramQueue);
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+#if 0
+ AddressFile->SpecialReceiveProcessing = FALSE;
+ AddressFile->ExtendedAddressing = FALSE;
+ AddressFile->ReceiveIpxHeader = FALSE;
+ AddressFile->FilterOnPacketType = FALSE;
+ AddressFile->DefaultPacketType = 0;
+ AddressFile->Address = NULL;
+#ifdef ISN_NT
+ AddressFile->FileObject = NULL;
+#endif
+#endif
+
+ AddressFile->Device = Device;
+ AddressFile->State = ADDRESSFILE_STATE_OPENING;
+ AddressFile->ReferenceCount = 1;
+#if DBG
+ AddressFile->RefTypes[AFREF_CREATE] = 1;
+#endif
+ AddressFile->CloseRequest = (PREQUEST)NULL;
+
+ //
+ // Initialize the request handlers.
+ //
+
+ AddressFile->RegisteredReceiveDatagramHandler = FALSE;
+ AddressFile->ReceiveDatagramHandler = TdiDefaultRcvDatagramHandler;
+ AddressFile->ReceiveDatagramHandlerContext = NULL;
+
+ //
+ // [CH] Added these handlers for chained buffer receives
+ //
+ AddressFile->RegisteredChainedReceiveDatagramHandler = FALSE;
+ AddressFile->ChainedReceiveDatagramHandler = TdiDefaultChainedRcvDatagramHandler;
+ AddressFile->ChainedReceiveDatagramHandlerContext = NULL;
+
+ AddressFile->RegisteredErrorHandler = FALSE;
+ AddressFile->ErrorHandler = TdiDefaultErrorHandler;
+ AddressFile->ErrorHandlerContext = NULL;
+
+ return AddressFile;
+
+} /* IpxCreateAddressFile */
+
+
+NTSTATUS
+IpxDestroyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys an address file and removes all references
+ made by it to other objects in the transport.
+
+ This routine is only called by IpxDereferenceAddressFile. The reason
+ for this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address file object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ AddressFile Pointer to a transport address file structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ CTELockHandle LockHandle, LockHandle1;
+ PADDRESS Address;
+ PDEVICE Device;
+ PREQUEST CloseRequest;
+
+ IPX_DEBUG (ADDRESS, ("Destroy address file %lx\n", AddressFile));
+
+ Address = AddressFile->Address;
+ Device = AddressFile->Device;
+
+ if (Address) {
+
+ //
+ // This addressfile was associated with an address.
+ //
+
+ CTEGetLock (&Address->Lock, &LockHandle);
+
+ //
+ // remove this addressfile from the address list and disassociate it from
+ // the file handle.
+ //
+
+ RemoveEntryList (&AddressFile->Linkage);
+ InitializeListHead (&AddressFile->Linkage);
+
+ if (Address->AddressFileDatabase.Flink == &Address->AddressFileDatabase) {
+
+ //
+ // This is the last open of this address, it will close
+ // due to normal dereferencing but we have to set the
+ // CLOSING flag too to stop further references.
+ //
+
+ CTEGetLock (&Device->Lock, &LockHandle1);
+ Address->Stopping = TRUE;
+ if (Device->LastAddress == Address) {
+ Device->LastAddress = NULL;
+ }
+ CTEFreeLock (&Device->Lock, LockHandle1);
+
+ }
+
+ AddressFile->Address = NULL;
+
+#ifdef ISN_NT
+ AddressFile->FileObject->FsContext = NULL;
+ AddressFile->FileObject->FsContext2 = NULL;
+#endif
+
+ CTEFreeLock (&Address->Lock, LockHandle);
+
+ //
+ // We will already have been removed from the ShareAccess
+ // of the owning address.
+ //
+
+ //
+ // Now dereference the owning address.
+ //
+
+ IpxDereferenceAddress (Address, AREF_ADDRESS_FILE);
+
+ }
+
+ //
+ // Save this for later completion.
+ //
+
+ CloseRequest = AddressFile->CloseRequest;
+
+ //
+ // return the addressFile to the pool of address files
+ //
+
+ IpxFreeMemory (AddressFile, sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile");
+
+ if (CloseRequest != (PREQUEST)NULL) {
+ REQUEST_INFORMATION(CloseRequest) = 0;
+ REQUEST_STATUS(CloseRequest) = STATUS_SUCCESS;
+ IpxCompleteRequest (CloseRequest);
+ IpxFreeRequest (Device, CloseRequest);
+ }
+
+ return STATUS_SUCCESS;
+
+} /* IpxDestroyAddressFile */
+
+
+#if DBG
+VOID
+IpxRefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)IPX_ADD_ULONG (
+ &AddressFile->ReferenceCount,
+ 1,
+ AddressFile->AddressLock);
+
+} /* IpxRefAddressFile */
+
+
+VOID
+IpxRefAddressFileLock(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+ IT IS CALLED WITH THE ADDRESS LOCK HELD.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+ //++AddressFile->ReferenceCount;
+ (VOID)InterlockedIncrement(&AddressFile->ReferenceCount);
+
+} /* IpxRefAddressFileLock */
+
+
+VOID
+IpxRefAddressFileSync(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)IPX_ADD_ULONG (
+ &AddressFile->ReferenceCount,
+ 1,
+ AddressFile->AddressLock);
+
+} /* IpxRefAddressFileSync */
+
+
+VOID
+IpxDerefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences an address file by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IpxDestroyAddressFile to remove it from the system.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+
+ oldvalue = IPX_ADD_ULONG (
+ &AddressFile->ReferenceCount,
+ (ULONG)-1,
+ AddressFile->AddressLock);
+
+ //
+ // If we have deleted all references to this address file, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ CTEAssert (oldvalue > 0);
+
+ if (oldvalue == 1) {
+ IpxDestroyAddressFile (AddressFile);
+ }
+
+} /* IpxDerefAddressFile */
+
+
+VOID
+IpxDerefAddressFileSync(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences an address file by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IpxDestroyAddressFile to remove it from the system. This routine
+ can only be called when we are synchronized (inside an IPX_SYNC_START/
+ IPX_SYNC_END pair, with a lock held, or in an indication).
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+
+ oldvalue = IPX_ADD_ULONG (
+ &AddressFile->ReferenceCount,
+ (ULONG)-1,
+ AddressFile->AddressLock);
+
+ //
+ // If we have deleted all references to this address file, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ CTEAssert (oldvalue > 0);
+
+ if (oldvalue == 1) {
+ IpxDestroyAddressFile (AddressFile);
+ }
+
+} /* IpxDerefAddressFileSync */
+#endif
+
+
+PADDRESS
+IpxLookupAddress(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the transport addresses defined for the given
+ device context and compares them with the specified NETWORK
+ NAME values. If an exact match is found, then a pointer to the
+ ADDRESS object is returned, and as a side effect, the reference
+ count to the address object is incremented. If the address is not
+ found, then NULL is returned.
+
+ NOTE: This routine must be called with the Device
+ spinlock held.
+
+Arguments:
+
+ Device - Pointer to the device object and its extension.
+
+ Socket - The socket to look up.
+
+Return Value:
+
+ Pointer to the ADDRESS object found, or NULL if not found.
+
+--*/
+
+{
+ PADDRESS Address;
+ PLIST_ENTRY p;
+ ULONG Hash = IPX_HASH_SOCKET (Socket);
+
+ p = Device->AddressDatabases[Hash].Flink;
+
+ for (p = Device->AddressDatabases[Hash].Flink;
+ p != &Device->AddressDatabases[Hash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ if (Address->Stopping) {
+ continue;
+ }
+
+ if (Address->Socket == Socket) {
+
+ //
+ // We found the match. Bump the reference count on the address, and
+ // return a pointer to the address object for the caller to use.
+ //
+
+ IpxReferenceAddressLock (Address, AREF_LOOKUP);
+ return Address;
+
+ }
+
+ }
+
+ //
+ // The specified address was not found.
+ //
+
+ return NULL;
+
+} /* IpxLookupAddress */
+
+
+NTSTATUS
+IpxStopAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to terminate all activity on an AddressFile and
+ destroy the object. We remove every connection and datagram associated
+ with this addressfile from the address database and terminate their
+ activity. Then, if there are no other outstanding addressfiles open on
+ this address, the address will go away.
+
+Arguments:
+
+ AddressFile - pointer to the addressFile to be stopped
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the request
+ is not for a real address.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PREQUEST Request;
+ PADDRESS Address = AddressFile->Address;
+ PLIST_ENTRY p;
+ KIRQL irql;
+
+
+ IoAcquireCancelSpinLock( &irql );
+ CTEGetLock (&Address->Lock, &LockHandle);
+
+ if (AddressFile->State == ADDRESSFILE_STATE_CLOSING) {
+ CTEFreeLock (&Address->Lock, LockHandle);
+ IoReleaseCancelSpinLock( irql );
+ return STATUS_SUCCESS;
+ }
+
+
+ AddressFile->State = ADDRESSFILE_STATE_CLOSING;
+
+ while (!(IsListEmpty(&AddressFile->ReceiveDatagramQueue))) {
+
+ p = RemoveHeadList (&AddressFile->ReceiveDatagramQueue);
+ Request = LIST_ENTRY_TO_REQUEST (p);
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_NETWORK_NAME_DELETED;
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+
+ CTEFreeLock(&Address->Lock, LockHandle);
+ IoReleaseCancelSpinLock( irql );
+
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
+
+ IoAcquireCancelSpinLock( &irql );
+ CTEGetLock(&Address->Lock, &LockHandle);
+
+ }
+
+ CTEFreeLock(&Address->Lock, LockHandle);
+ IoReleaseCancelSpinLock( irql );
+
+} /* IpxStopAddressFile */
+
+
+NTSTATUS
+IpxCloseAddressFile(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to close the addressfile pointed to by a file
+ object. If there is any activity to be run down, we will run it down
+ before we terminate the addressfile. We remove every connection and
+ datagram associated with this addressfile from the address database
+ and terminate their activity. Then, if there are no other outstanding
+ addressfiles open on this address, the address will go away.
+
+Arguments:
+
+ Request - the close request.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the
+ request does not point to a real address.
+
+--*/
+
+{
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ CTELockHandle LockHandle;
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+ AddressFile->CloseRequest = Request;
+
+ //
+ // We assume that addressFile has already been verified
+ // at this point.
+ //
+
+ Address = AddressFile->Address;
+ CTEAssert (Address);
+
+ //
+ // Remove us from the access info for this address.
+ //
+
+ ExAcquireResourceExclusive (&Device->AddressResource, TRUE);
+#ifdef ISN_NT
+ IoRemoveShareAccess (AddressFile->FileObject, &Address->u.ShareAccess);
+#endif
+ ExReleaseResource (&Device->AddressResource);
+
+ //
+ // If this address file had broadcasts enabled, turn it off.
+ //
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ if (AddressFile->EnableBroadcast) {
+ AddressFile->EnableBroadcast = FALSE;
+ IpxRemoveBroadcast (Device);
+ }
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ IpxStopAddressFile (AddressFile);
+ IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ return STATUS_PENDING;
+
+} /* IpxCloseAddressFile */
+
+
diff --git a/private/ntos/tdi/isnp/ipx/config.c b/private/ntos/tdi/isnp/ipx/config.c
new file mode 100644
index 000000000..f5d8aefbf
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/config.c
@@ -0,0 +1,1715 @@
+/*++
+
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ config.c
+
+Abstract:
+
+ This contains all routines necessary for the support of the dynamic
+ configuration of the ISN IPX module.
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 19-Sept-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Local functions used to access the registry.
+//
+
+NTSTATUS
+IpxGetConfigValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+IpxGetBindingValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+IpxGetFrameType(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+IpxAddBind(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+IpxAddExport(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+IpxReadLinkageInformation(
+ IN PCONFIG Config
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,IpxGetConfiguration)
+#pragma alloc_text(INIT,IpxFreeConfiguration)
+
+#ifndef _PNP_POWER
+#pragma alloc_text(INIT,IpxGetConfigValue)
+#pragma alloc_text(INIT,IpxGetBindingValue)
+#pragma alloc_text(INIT,IpxGetFrameType)
+#pragma alloc_text(INIT,IpxWriteDefaultAutoDetectType)
+#endif
+
+#pragma alloc_text(INIT,IpxAddBind)
+#pragma alloc_text(INIT,IpxAddExport)
+#pragma alloc_text(INIT,IpxReadLinkageInformation)
+#endif
+
+
+
+NTSTATUS
+IpxGetConfiguration (
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath,
+ OUT PCONFIG * ConfigPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by IPX to get information from the configuration
+ management routines. We read the registry, starting at RegistryPath,
+ to get the parameters. If they don't exist, we use the defaults
+ set in ipxcnfg.h file. A list of adapters to bind to is chained
+ on to the config information.
+
+Arguments:
+
+ DriverObject - Used for logging errors.
+
+ RegistryPath - The name of IPX's node in the registry.
+
+ ConfigPtr - Returns the configuration information.
+
+Return Value:
+
+ Status - STATUS_SUCCESS if everything OK, STATUS_INSUFFICIENT_RESOURCES
+ otherwise.
+
+--*/
+
+{
+ PWSTR RegistryPathBuffer;
+ PCONFIG Config;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[CONFIG_PARAMETERS+2];
+ NTSTATUS Status;
+ ULONG Zero = 0;
+ ULONG One = 1;
+ ULONG Five = 5;
+ ULONG Eight = 8;
+ ULONG Ten = 10;
+ ULONG Fifteen = 15;
+ ULONG Fifty = 50;
+ ULONG DefaultSocketStart = 0x4000;
+ ULONG DefaultSocketEnd = 0x8000;
+ ULONG RipSegments = RIP_SEGMENTS;
+ PWSTR Parameters = L"Parameters";
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[CONFIG_PARAMETERS] = {
+ { L"DedicatedRouter", &Zero } ,
+ { L"InitDatagrams", &Ten } ,
+ { L"MaxDatagrams", &Fifty } ,
+ { L"RipAgeTime", &Five } , // minutes
+ { L"RipCount", &Five } ,
+ { L"RipTimeout", &One } , // half-second
+ { L"RipUsageTime", &Fifteen } , // minutes
+ { L"SourceRouteUsageTime", &Ten } , // minutes
+ { L"SocketUniqueness", &Eight } ,
+ { L"SocketStart", &DefaultSocketStart } ,
+ { L"SocketEnd", &DefaultSocketEnd } ,
+ { L"VirtualNetworkNumber", &Zero } ,
+ { L"MaxMemoryUsage", &Zero } ,
+ { L"RipTableSize", &RipSegments } ,
+ { L"VirtualNetworkOptional", &One } ,
+ { L"EthernetPadToEven", &One } ,
+ { L"EthernetExtraPadding", &Zero } ,
+ { L"SingleNetworkActive", &Zero } ,
+ { L"DisableDialoutSap", &Zero } ,
+ { L"DisableDialinNetbios", &One } ,
+ { L"VerifySourceAddress", &One } };
+ UINT i;
+
+
+ //
+ // Allocate memory for the main config structure.
+ //
+
+ Config = IpxAllocateMemory (sizeof(CONFIG), MEMORY_CONFIG, "Config");
+ if (Config == NULL) {
+ IpxWriteResourceErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ sizeof(CONFIG),
+ MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Config->DeviceName.Buffer = NULL;
+ InitializeListHead (&Config->BindingList);
+ Config->DriverObject = DriverObject;
+
+ //
+ // Read in the NDIS binding information.
+ //
+ // IpxReadLinkageInformation expects a null-terminated path,
+ // so we have to create one from the UNICODE_STRING.
+ //
+
+ RegistryPathBuffer = (PWSTR)IpxAllocateMemory(RegistryPath->Length + sizeof(WCHAR),
+ MEMORY_CONFIG, "RegistryPathBuffer");
+ if (RegistryPathBuffer == NULL) {
+ IpxFreeConfiguration(Config);
+ IpxWriteResourceErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ RegistryPath->Length + sizeof(WCHAR),
+ MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ RtlCopyMemory (RegistryPathBuffer, RegistryPath->Buffer, RegistryPath->Length);
+ *(PWCHAR)(((PUCHAR)RegistryPathBuffer)+RegistryPath->Length) = (WCHAR)'\0';
+
+ Config->RegistryPathBuffer = RegistryPathBuffer;
+
+ //
+ // Determine what name to export and who to bind to.
+ //
+
+ Status = IpxReadLinkageInformation (Config);
+ if (Status != STATUS_SUCCESS) {
+
+ //
+ // It logged an error if it failed.
+ //
+
+ IpxFreeConfiguration(Config);
+ return Status;
+ }
+
+ //
+ // Read the per-transport (as opposed to per-binding)
+ // parameters.
+ //
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Parameters key below IPX
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Parameters;
+
+ //
+ // 2-14) Call IpxGetConfigValue for each of the keys we
+ // care about.
+ //
+
+ for (i = 0; i < CONFIG_PARAMETERS; i++) {
+
+ QueryTable[i+1].QueryRoutine = IpxGetConfigValue;
+ QueryTable[i+1].Flags = 0;
+ QueryTable[i+1].Name = ParameterValues[i].KeyName;
+ QueryTable[i+1].EntryContext = (PVOID)i;
+ QueryTable[i+1].DefaultType = REG_DWORD;
+ QueryTable[i+1].DefaultData = (PVOID)(ParameterValues[i].DefaultValue);
+ QueryTable[i+1].DefaultLength = sizeof(ULONG);
+
+ }
+
+ //
+ // 15) Stop
+ //
+
+ QueryTable[CONFIG_PARAMETERS+1].QueryRoutine = NULL;
+ QueryTable[CONFIG_PARAMETERS+1].Flags = 0;
+ QueryTable[CONFIG_PARAMETERS+1].Name = NULL;
+
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+
+ IpxFreeConfiguration(Config);
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 905,
+ Status,
+ Parameters,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ //
+ // For PnP, we need to keep this path around
+ //
+#ifndef _PNP_POWER
+ IpxFreeMemory (RegistryPathBuffer, RegistryPath->Length + sizeof(WCHAR), MEMORY_CONFIG, "RegistryPathBuffer");
+#endif _PNP_POWER
+
+ *ConfigPtr = Config;
+
+ return STATUS_SUCCESS;
+
+} /* IpxGetConfiguration */
+
+
+VOID
+IpxFreeConfiguration (
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by IPX to get free any storage that was allocated
+ by IpxGetConfiguration in producing the specified CONFIG structure.
+
+Arguments:
+
+ Config - A pointer to the configuration information structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PBINDING_CONFIG Binding;
+
+ while (!IsListEmpty (&Config->BindingList)) {
+ p = RemoveHeadList (&Config->BindingList);
+ Binding = CONTAINING_RECORD (p, BINDING_CONFIG, Linkage);
+ IpxFreeMemory (Binding->AdapterName.Buffer, Binding->AdapterName.MaximumLength, MEMORY_CONFIG, "NameBuffer");
+ IpxFreeMemory (Binding, sizeof(BINDING_CONFIG), MEMORY_CONFIG, "Binding");
+ }
+
+ if (Config->DeviceName.Buffer) {
+ IpxFreeMemory (Config->DeviceName.Buffer, Config->DeviceName.MaximumLength, MEMORY_CONFIG, "DeviceName");
+ }
+
+ IpxFreeMemory (Config, sizeof(CONFIG), MEMORY_CONFIG, "Config");
+
+} /* IpxFreeConfiguration */
+
+
+NTSTATUS
+IpxGetConfigValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each entry in the Parameters
+ node to set the config values. The table is set up
+ so that this function will be called with correct default
+ values for keys that are not present.
+
+Arguments:
+
+ ValueName - The name of the value (ignored).
+
+ ValueType - The type of the value (REG_DWORD -- ignored).
+
+ ValueData - The data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to the CONFIG structure.
+
+ EntryContext - The index in Config->Parameters to save the value.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+
+ if ((ValueType != REG_DWORD) || (ValueLength != sizeof(ULONG))) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 904,
+ STATUS_INVALID_PARAMETER,
+ ValueName,
+ 0,
+ NULL);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IPX_DEBUG (CONFIG, ("Config parameter %d, value %lx\n",
+ (ULONG)EntryContext, *(UNALIGNED ULONG *)ValueData));
+ Config->Parameters[(ULONG)EntryContext] = *(UNALIGNED ULONG *)ValueData;
+
+ return STATUS_SUCCESS;
+
+} /* IpxGetConfigValue */
+
+
+NTSTATUS
+IpxGetBindingValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each entry in the NetConfig\DriverNN
+ node to set the per-binding values. The table is set up
+ so that this function will be called with correct default
+ values for keys that are not present.
+
+Arguments:
+
+ ValueName - The name of the value (ignored).
+
+ ValueType - The type of the value (REG_DWORD -- ignored).
+
+ ValueData - The data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to the BINDING_CONFIG structure.
+
+ EntryContext - The index in Binding->Parameters to save the value.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PBINDING_CONFIG Binding = (PBINDING_CONFIG)Context;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+
+ if ((ValueType != REG_DWORD) || (ValueLength != sizeof(ULONG))) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Binding->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 903,
+ STATUS_INVALID_PARAMETER,
+ ValueName,
+ 0,
+ NULL);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IPX_DEBUG (CONFIG, ("Binding parameter %d, value %lx\n",
+ (ULONG)EntryContext, *(UNALIGNED ULONG *)ValueData));
+ Binding->Parameters[(ULONG)EntryContext] = *(UNALIGNED ULONG *)ValueData;
+
+ return STATUS_SUCCESS;
+
+} /* IpxGetBindingValue */
+
+
+NTSTATUS
+IpxGetFrameType(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues.
+ It is called for each of the entry in the "PktType" and
+ "NetworkNumber" multi-strings for a given binding.
+
+Arguments:
+
+ ValueName - The name of the value ("PktType" or "NetworkNumber" -- ignored).
+
+ ValueType - The type of the value (REG_MULTI_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - A pointer to the BINDING_CONFIG structure.
+
+ EntryContext - A pointer to a count of multi-string entries.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PBINDING_CONFIG Binding = (PBINDING_CONFIG)Context;
+ ULONG IntegerValue;
+ PWCHAR Cur;
+ PULONG Count = (PULONG)EntryContext;
+
+ if ((ValueType != REG_SZ) ||
+ (*Count >= 4)) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Binding->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 903,
+ STATUS_INVALID_PARAMETER,
+ ValueName,
+ 0,
+ NULL);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IntegerValue = 0;
+ for (Cur = (PWCHAR)(ValueData); ; Cur++) {
+ if (*Cur >= L'0' && *Cur <= L'9') {
+ IntegerValue = (IntegerValue * 16) + (*Cur - L'0');
+ } else if (*Cur >= L'A' && *Cur <= L'F') {
+ IntegerValue = (IntegerValue * 16) + (*Cur - L'A' + 10);
+ } else if (*Cur >= L'a' && *Cur <= L'f') {
+ IntegerValue = (IntegerValue * 16) + (*Cur - L'a' + 10);
+ } else {
+ break;
+ }
+ }
+
+ if (((PWCHAR)ValueName)[0] == L'P') {
+
+ //
+ // PktType. We map arcnet to 802_3 so the code around
+ // here can assume there are only four packets type --
+ // the frame type is ignored later for arcnet.
+ //
+
+ if ((IntegerValue > ISN_FRAME_TYPE_ARCNET) &&
+ (IntegerValue != ISN_FRAME_TYPE_AUTO)) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Binding->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 903,
+ STATUS_INVALID_PARAMETER,
+ ValueName,
+ 0,
+ NULL);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IPX_DEBUG (CONFIG, ("PktType(%d) is %lx\n", *Count, IntegerValue));
+ if (IntegerValue == ISN_FRAME_TYPE_ARCNET) {
+ Binding->FrameType[*Count] = ISN_FRAME_TYPE_802_3;
+ } else {
+ Binding->FrameType[*Count] = IntegerValue;
+ }
+
+ } else {
+
+ //
+ // NetworkNumber
+ //
+
+ IPX_DEBUG (CONFIG, ("NetworkNumber(%d) is %d\n", *Count, IntegerValue));
+ Binding->NetworkNumber[*Count] = IntegerValue;
+
+ }
+
+ ++(*Count);
+
+ return STATUS_SUCCESS;
+
+} /* IpxGetFrameType */
+
+
+NTSTATUS
+IpxAddBind(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Bind" multi-string and
+ saves the information in a Config structure. It
+ also queries the per-binding information and stores it.
+
+Arguments:
+
+ ValueName - The name of the value ("Bind" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - A pointer to the Config structure.
+
+ EntryContext - A pointer to a count of binds that is incremented.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+ PBINDING_CONFIG Binding;
+ PULONG CurBindNum = ((PULONG)EntryContext);
+ RTL_QUERY_REGISTRY_TABLE QueryTable[BINDING_PARAMETERS+4];
+ ULONG FrameTypeCount, NetworkNumberCount;
+ ULONG StringLoc;
+ BOOLEAN AutoDetect;
+ ULONG AutoDetectLoc;
+ ULONG SlideCount;
+ PWCHAR NameBuffer;
+ NTSTATUS Status;
+ BOOLEAN FrameTypeUsed[ISN_FRAME_TYPE_MAX];
+ ULONG Zero = 0;
+ ULONG One = 1;
+ ULONG DefaultBindSap = 0x8137;
+ ULONG DefaultAutoDetectType = ISN_FRAME_TYPE_802_2;
+ PWSTR Subkey = L"NetConfig\\12345678901234567890"; // BUGBUG: hack
+ PWSTR ValueDataWstr = (PWSTR)ValueData;
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[BINDING_PARAMETERS] = {
+ { L"MaxPktSize", &Zero } ,
+ { L"BindSap", &DefaultBindSap } ,
+ { L"DefaultAutoDetectType", &DefaultAutoDetectType } ,
+ { L"SourceRouting", &One } ,
+ { L"SourceRouteDef", &Zero } ,
+ { L"SourceRouteBcast", &Zero } ,
+ { L"SourceRouteMcast", &Zero } ,
+ { L"EnableFuncaddr", &One } ,
+ { L"EnableWanRouter", &One } };
+ ULONG BindingPreference[ISN_FRAME_TYPE_MAX] = {
+ ISN_FRAME_TYPE_802_2,
+ ISN_FRAME_TYPE_802_3,
+ ISN_FRAME_TYPE_ETHERNET_II,
+ ISN_FRAME_TYPE_SNAP };
+
+ UINT i, j, k;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+
+
+ Binding = (PBINDING_CONFIG)IpxAllocateMemory (sizeof(BINDING_CONFIG), MEMORY_CONFIG, "Binding");
+ if (Binding == NULL) {
+ IpxWriteResourceErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ sizeof(BINDING_CONFIG),
+ MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NameBuffer = (PWCHAR)IpxAllocateMemory (ValueLength, MEMORY_CONFIG, "NameBuffer");
+ if (NameBuffer == NULL) {
+ IpxFreeMemory (Binding, sizeof(BINDING_CONFIG), MEMORY_CONFIG, "Binding");
+ IpxWriteResourceErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ ValueLength,
+ MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (NameBuffer, ValueData, ValueLength);
+ Binding->AdapterName.Buffer = NameBuffer;
+ Binding->AdapterName.Length = (USHORT)(ValueLength - sizeof(WCHAR));
+ Binding->AdapterName.MaximumLength = (USHORT)ValueLength;
+
+ Binding->DriverObject = Config->DriverObject;
+
+ FrameTypeCount = 0;
+ NetworkNumberCount = 0;
+
+ //
+ // The structure is allocated OK, insert it into the list.
+ //
+
+ InsertTailList (&Config->BindingList, &Binding->Linkage);
+ ++(*CurBindNum);
+
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the NetConfig\XXXX key below IPX
+ // (we construct the right name in Subkey,
+ // first scan back to find the \, then copy
+ // the rest over, including the final '\0').
+ //
+
+ StringLoc = (ValueLength / sizeof(WCHAR)) - 2;
+ while (ValueDataWstr[StringLoc] != L'\\') {
+ --StringLoc;
+ }
+ RtlCopyMemory(&Subkey[10], &ValueDataWstr[StringLoc+1], ValueLength - ((StringLoc+1) * sizeof(WCHAR)));
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Subkey;
+
+ //
+ // 2) Call IpxGetFrameType for each part of the
+ // "PktType" multi-string.
+ //
+
+ QueryTable[1].QueryRoutine = IpxGetFrameType;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[1].Name = L"PktType";
+ QueryTable[1].EntryContext = &FrameTypeCount;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Call IpxGetFrameType for each part of the
+ // "NetworkNumber" multi-string.
+ //
+
+ QueryTable[2].QueryRoutine = IpxGetFrameType;
+ QueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[2].Name = L"NetworkNumber";
+ QueryTable[2].EntryContext = &NetworkNumberCount;
+ QueryTable[2].DefaultType = REG_NONE;
+
+ //
+ // 4-11) Call IpxGetBindingValue for each of the keys we
+ // care about.
+ //
+
+ for (i = 0; i < BINDING_PARAMETERS; i++) {
+
+ QueryTable[i+3].QueryRoutine = IpxGetBindingValue;
+ QueryTable[i+3].Flags = 0;
+ QueryTable[i+3].Name = ParameterValues[i].KeyName;
+ QueryTable[i+3].EntryContext = (PVOID)i;
+ QueryTable[i+3].DefaultType = REG_DWORD;
+ QueryTable[i+3].DefaultData = (PVOID)(ParameterValues[i].DefaultValue);
+ QueryTable[i+3].DefaultLength = sizeof(ULONG);
+
+ }
+
+ //
+ // 12) Stop
+ //
+
+ QueryTable[BINDING_PARAMETERS+3].QueryRoutine = NULL;
+ QueryTable[BINDING_PARAMETERS+3].Flags = 0;
+ QueryTable[BINDING_PARAMETERS+3].Name = NULL;
+
+
+ IPX_DEBUG (CONFIG, ("Read bind key for %ws (%ws)\n", ValueData, Subkey));
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Binding,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+
+ //
+ // The binding will get freed during cleanup.
+ //
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 906,
+ Status,
+ Subkey,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ if (FrameTypeCount == 0) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_NO_FRAME_TYPES,
+ 907,
+ Status,
+ Subkey + 10,
+ 0,
+ NULL);
+ }
+
+ if (FrameTypeCount > NetworkNumberCount) {
+ for (i = NetworkNumberCount; i <FrameTypeCount; i++) {
+ Binding->NetworkNumber[i] = 0;
+ }
+ }
+ Binding->FrameTypeCount = FrameTypeCount;
+
+ //
+ // Go through and eliminate duplicates from the frame
+ // type array.
+ //
+
+ for (i = 0; i < Binding->FrameTypeCount; i++) {
+
+ for (j = i+1; j < Binding->FrameTypeCount; j++) {
+
+ if (Binding->FrameType[j] == Binding->FrameType[i]) {
+
+ IPX_DEBUG (CONFIG, ("Frame types %d and %d identical\n", i, j));
+
+ //
+ // A duplicate, slide everything else down.
+ //
+
+ for (k = j+1; k < Binding->FrameTypeCount; k++) {
+ Binding->FrameType[k-1] = Binding->FrameType[k];
+ Binding->NetworkNumber[k-1] = Binding->NetworkNumber[k];
+ }
+ --Binding->FrameTypeCount;
+
+ --j; // so we check whoever just moved into this spot.
+ }
+ }
+ }
+
+
+ //
+ // Mark all the explicitly configured frame types, and
+ // see if we have to auto-detect.
+ //
+
+ for (i = 0; i < 4; i++) {
+ FrameTypeUsed[i] = FALSE;
+ }
+
+ AutoDetect = FALSE;
+ for (i = 0; i < Binding->FrameTypeCount; i++) {
+ if (Binding->FrameType[i] == ISN_FRAME_TYPE_AUTO) {
+ AutoDetectLoc = i;
+ AutoDetect = TRUE;
+ } else {
+ Binding->AutoDetect[i] = FALSE;
+ Binding->DefaultAutoDetect[i] = FALSE;
+ FrameTypeUsed[Binding->FrameType[i]] = TRUE;
+ }
+ }
+
+ if (!AutoDetect) {
+ IPX_DEBUG (AUTO_DETECT, ("No bindings auto-detected\n"));
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Slide everything that is past the auto-detect point up
+ // to the end.
+ //
+
+ SlideCount = Binding->FrameTypeCount - AutoDetectLoc - 1;
+ for (j = 3; j > 3 - SlideCount; j--) {
+ Binding->FrameType[j] = Binding->FrameType[j-(3-Binding->FrameTypeCount)];
+ Binding->NetworkNumber[j] = Binding->NetworkNumber[j-(3-Binding->FrameTypeCount)];
+ Binding->AutoDetect[j] = Binding->AutoDetect[j-(3-Binding->FrameTypeCount)];
+ Binding->DefaultAutoDetect[j] = Binding->DefaultAutoDetect[j-(3-Binding->FrameTypeCount)];
+ }
+
+ //
+ // Now fill in any frame types that are not hard-coded,
+ // this will start at AutoDetectLoc and exactly fill up
+ // the gap created when we slid things up above. We
+ // first put the default auto-detect at the first spot.
+ //
+
+ if (!FrameTypeUsed[Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT]]) {
+ Binding->FrameType[AutoDetectLoc] = Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT];
+ Binding->NetworkNumber[AutoDetectLoc] = 0;
+ Binding->AutoDetect[AutoDetectLoc] = TRUE;
+ Binding->DefaultAutoDetect[AutoDetectLoc] = TRUE;
+ ++AutoDetectLoc;
+ FrameTypeUsed[Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT]] = TRUE;
+ }
+
+ //
+ // Now fill in the array, using the preference order in
+ // the BindingPreference array (this comes into effect
+ // because the first frame type in our list that we
+ // find is used).
+ //
+
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+
+ if (!FrameTypeUsed[BindingPreference[i]]) {
+ Binding->FrameType[AutoDetectLoc] = BindingPreference[i];
+ Binding->NetworkNumber[AutoDetectLoc] = 0;
+ Binding->AutoDetect[AutoDetectLoc] = TRUE;
+ Binding->DefaultAutoDetect[AutoDetectLoc] = FALSE;
+ ++AutoDetectLoc;
+ }
+ }
+
+ Binding->FrameTypeCount = ISN_FRAME_TYPE_MAX;
+
+#if DBG
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+ IPX_DEBUG (AUTO_DETECT, ("%d: type %d, net %d, auto %d\n",
+ i, Binding->FrameType[i], Binding->NetworkNumber[i], Binding->AutoDetect[i]));
+ }
+#endif
+
+ return STATUS_SUCCESS;
+
+} /* IpxAddBind */
+
+
+NTSTATUS
+IpxAddExport(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Export" multi-string. It
+ saves the first callback string in the Config structure.
+
+Arguments:
+
+ ValueName - The name of the value ("Export" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - A pointer to the Config structure.
+
+ EntryContext - A pointer to a ULONG that goes to 1 after the
+ first call to this routine (so we know to ignore other ones).
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+ PULONG ValueReadOk = ((PULONG)EntryContext);
+ PWCHAR NameBuffer;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+
+ if (*ValueReadOk == 0) {
+
+ IPX_DEBUG (CONFIG, ("Read export value %ws\n", ValueData));
+
+ NameBuffer = (PWCHAR)IpxAllocateMemory (ValueLength, MEMORY_CONFIG, "DeviceName");
+ if (NameBuffer == NULL) {
+ IpxWriteResourceErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ ValueLength,
+ MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (NameBuffer, ValueData, ValueLength);
+ Config->DeviceName.Buffer = NameBuffer;
+ Config->DeviceName.Length = (USHORT)(ValueLength - sizeof(WCHAR));
+ Config->DeviceName.MaximumLength = (USHORT)ValueLength;
+
+ //
+ // Set this to ignore any other callbacks and let the
+ // caller know we read something.
+ //
+
+ *ValueReadOk = 1;
+
+ }
+
+ return STATUS_SUCCESS;
+
+} /* IpxAddExport */
+
+
+NTSTATUS
+IpxReadLinkageInformation(
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by IPX to read its linkage information
+ from the registry.
+
+Arguments:
+
+ Config - The config structure which will have per-binding information
+ linked on to it.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[3];
+ PWSTR Subkey = L"Linkage";
+ PWSTR Bind = L"Bind";
+ PWSTR Export = L"Export";
+ ULONG ValueReadOk;
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Linkage key below IPX
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Subkey;
+
+ //
+ // 1) Call IpxAddExport for each string in "Export"
+ //
+
+ QueryTable[1].QueryRoutine = IpxAddExport;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[1].Name = Export;
+ QueryTable[1].EntryContext = (PVOID)&ValueReadOk;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 2) Stop
+ //
+
+ QueryTable[2].QueryRoutine = NULL;
+ QueryTable[2].Flags = 0;
+ QueryTable[2].Name = NULL;
+
+
+ ValueReadOk = 0;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if ((Status != STATUS_SUCCESS) || (ValueReadOk == 0)) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 901,
+ Status,
+ Export,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+#ifndef _PNP_POWER
+//
+// This will be done as and when adapters appear.
+//
+ //
+ // 1) Change to call IpxAddBind for each string in "Bind"
+ //
+
+ QueryTable[1].QueryRoutine = IpxAddBind;
+ QueryTable[1].Flags = 0; // not required
+ QueryTable[1].Name = Bind;
+ QueryTable[1].EntryContext = (PVOID)&Config->BindCount;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ Config->BindCount = 0;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ //
+ // For the moment fail if we find no bindings -- eventually when
+ // we support dynamic binding we should stick around in this case.
+ //
+
+ if ((Status != STATUS_SUCCESS) || (Config->BindCount == 0)) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 902,
+ Status,
+ Bind,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+#endif
+ return STATUS_SUCCESS;
+
+} /* IpxReadLinkageInformation */
+
+
+VOID
+IpxWriteDefaultAutoDetectType(
+ IN PUNICODE_STRING RegistryPath,
+ IN struct _ADAPTER * Adapter,
+ IN ULONG FrameType
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when we were unable to detect the default
+ auto-detect type and instead found a different one. We update
+ the "DefaultAutoDetectType" in the registry.
+
+Arguments:
+
+ RegistryPath - The name of IPX's node in the registry.
+
+ Adapter - The adapter which we auto-detected on.
+
+ FrameType - The new auto-detected value.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PWSTR FullRegistryPath;
+ PUCHAR CurRegistryPath;
+ ULONG FullRegistryPathLength;
+ ULONG AdapterNameLength;
+ WCHAR NetConfigName[] = L"\\NetConfig";
+ static PWCHAR FrameTypeNames[4] = { L"Ethernet II", L"802.3", L"802.2", L"SNAP" };
+ PWCHAR CurAdapterName;
+ NTSTATUS Status;
+
+
+ //
+ // We need to allocate a buffer which contains the registry path,
+ // followed by "NetConfig", followed by the adapter name, and
+ // then NULL-terminated.
+ //
+
+ CurAdapterName = &Adapter->AdapterName[(Adapter->AdapterNameLength/sizeof(WCHAR))-2];
+ while (*CurAdapterName != L'\\') {
+ --CurAdapterName;
+ }
+ CurAdapterName;
+ AdapterNameLength = Adapter->AdapterNameLength - ((CurAdapterName - Adapter->AdapterName) * sizeof(WCHAR)) - sizeof(WCHAR);
+
+ FullRegistryPathLength = RegistryPath->Length + sizeof(NetConfigName) + AdapterNameLength;
+
+ FullRegistryPath = (PWSTR)IpxAllocateMemory (FullRegistryPathLength, MEMORY_CONFIG, "FullRegistryPath");
+ if (FullRegistryPath == NULL) {
+ IpxWriteResourceErrorLog(
+ IpxDevice->DeviceObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ FullRegistryPathLength,
+ MEMORY_CONFIG);
+ return;
+ }
+
+ CurRegistryPath = (PUCHAR)FullRegistryPath;
+ RtlCopyMemory (CurRegistryPath, RegistryPath->Buffer, RegistryPath->Length);
+ CurRegistryPath += RegistryPath->Length;
+ RtlCopyMemory (CurRegistryPath, NetConfigName, sizeof(NetConfigName) - sizeof(WCHAR));
+ CurRegistryPath += (sizeof(NetConfigName) - sizeof(WCHAR));
+ RtlCopyMemory (CurRegistryPath, CurAdapterName, AdapterNameLength);
+ CurRegistryPath += AdapterNameLength;
+ *(PWCHAR)CurRegistryPath = L'\0';
+
+ Status = RtlWriteRegistryValue(
+ RTL_REGISTRY_ABSOLUTE,
+ FullRegistryPath,
+ L"DefaultAutoDetectType",
+ REG_DWORD,
+ &FrameType,
+ sizeof(ULONG));
+
+ IpxFreeMemory (FullRegistryPath, FullRegistryPathLength, MEMORY_CONFIG, "FullRegistryPath");
+
+ IpxWriteGeneralErrorLog(
+ IpxDevice->DeviceObject,
+ EVENT_IPX_NEW_DEFAULT_TYPE,
+ 888,
+ STATUS_SUCCESS,
+ FrameTypeNames[FrameType],
+ 0,
+ NULL);
+
+} /* IpxWriteDefaultAutoDetectType */
+
+
+#ifdef _PNP_POWER
+//
+// Vnet# and VnetOptional
+//
+#define VIRTUAL_NETWORK_PARAMETERS 2
+
+NTSTATUS
+IpxPnPGetVirtualNetworkNumber (
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by IPX to read the virtual network number
+ from the registry. This is called on appearance/disappearance of an
+ adapter from the system. We read the registry, starting at RegistryPath,
+ to get the value of the VirtualNetworkNumber parameter. If it doesn't
+ exist, we use the default set in ipxcnfg.h file.
+ Adapted from IpxGetConfiguration().
+
+Arguments:
+
+ Config - Contians the configuration information.
+
+Return Value:
+
+ Status - STATUS_SUCCESS if everything OK, STATUS_DEVICE_CONFIGURATION_ERROR
+ otherwise.
+
+--*/
+
+{
+ RTL_QUERY_REGISTRY_TABLE QueryTable[VIRTUAL_NETWORK_PARAMETERS+2];
+ NTSTATUS Status;
+ ULONG Zero = 0;
+ ULONG One = 1;
+ PWSTR Parameters = L"Parameters";
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[VIRTUAL_NETWORK_PARAMETERS] = {
+ { L"VirtualNetworkNumber", &Zero } ,
+ { L"VirtualNetworkOptional", &One } };
+ UINT i;
+
+ //
+ // Read the virtual net number from the parameters.
+ //
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Parameters key below IPX
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Parameters;
+
+ //
+ // 2) Call IpxGetConfigValue for the virtual net number key
+ //
+
+ QueryTable[1].QueryRoutine = IpxGetConfigValue;
+ QueryTable[1].Flags = 0;
+ QueryTable[1].Name = ParameterValues[0].KeyName;
+ QueryTable[1].EntryContext = (PVOID)CONFIG_VIRTUAL_NETWORK;
+ QueryTable[1].DefaultType = REG_DWORD;
+ QueryTable[1].DefaultData = (PVOID)(ParameterValues[0].DefaultValue);
+ QueryTable[1].DefaultLength = sizeof(ULONG);
+
+ //
+ // 2) Call IpxGetConfigValue for the virtual net optional key
+ //
+
+ QueryTable[2].QueryRoutine = IpxGetConfigValue;
+ QueryTable[2].Flags = 0;
+ QueryTable[2].Name = ParameterValues[1].KeyName;
+ QueryTable[2].EntryContext = (PVOID)CONFIG_VIRTUAL_OPTIONAL;
+ QueryTable[2].DefaultType = REG_DWORD;
+ QueryTable[2].DefaultData = (PVOID)(ParameterValues[1].DefaultValue);
+ QueryTable[2].DefaultLength = sizeof(ULONG);
+
+ //
+ // 15) Stop
+ //
+
+ QueryTable[3].QueryRoutine = NULL;
+ QueryTable[3].Flags = 0;
+ QueryTable[3].Name = NULL;
+
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 905,
+ Status,
+ Parameters,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ return STATUS_SUCCESS;
+
+} /* IpxPnPGetNetworkNumber */
+
+
+NTSTATUS
+IpxPnPGetAdapterParameters(
+ IN PCONFIG Config,
+ IN PNDIS_STRING DeviceName,
+ IN OUT PBINDING_CONFIG Binding
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by IPX to read the adapter-specific parameters
+ from the registry on PnP appearance of an adapter in the system.
+ We read the registry, starting at RegistryPath\NetConfig\DeviceName.
+
+ Adapted from IpxAddBind().
+
+Arguments:
+
+ Config - Config structure - supplies the DeviceObject and RegistryPathBuffer.
+
+ DeviceName - name of the adapter that was added.
+
+ Binding - Returns the configuration information per adapter.
+
+Return Value:
+
+ Status - STATUS_SUCCESS if everything OK, STATUS_DEVICE_CONFIGURATION_ERROR
+ otherwise.
+
+--*/
+{
+ RTL_QUERY_REGISTRY_TABLE QueryTable[BINDING_PARAMETERS+4];
+ ULONG FrameTypeCount, NetworkNumberCount;
+ ULONG StringLoc;
+ BOOLEAN AutoDetect;
+ ULONG AutoDetectLoc;
+ ULONG SlideCount;
+ PWCHAR NameBuffer;
+ NTSTATUS Status;
+ BOOLEAN FrameTypeUsed[ISN_FRAME_TYPE_MAX];
+ ULONG Zero = 0;
+ ULONG One = 1;
+ ULONG DefaultBindSap = 0x8137;
+ ULONG DefaultAutoDetectType = ISN_FRAME_TYPE_802_2;
+ PWSTR Subkey = L"NetConfig\\12345678901234567890"; // BUGBUG: hack
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[BINDING_PARAMETERS] = {
+ { L"MaxPktSize", &Zero } ,
+ { L"BindSap", &DefaultBindSap } ,
+ { L"DefaultAutoDetectType", &DefaultAutoDetectType } ,
+ { L"SourceRouting", &One } ,
+ { L"SourceRouteDef", &Zero } ,
+ { L"SourceRouteBcast", &Zero } ,
+ { L"SourceRouteMcast", &Zero } ,
+ { L"EnableFuncaddr", &One } ,
+ { L"EnableWanRouter", &One } };
+ ULONG BindingPreference[ISN_FRAME_TYPE_MAX] = {
+ ISN_FRAME_TYPE_802_2,
+ ISN_FRAME_TYPE_802_3,
+ ISN_FRAME_TYPE_ETHERNET_II,
+ ISN_FRAME_TYPE_SNAP };
+
+ UINT i, j, k;
+
+ FrameTypeCount = 0;
+ NetworkNumberCount = 0;
+
+ //
+ // The structure is allocated OK, insert it into the list.
+ //
+
+// InsertTailList (&Config->BindingList, &Binding->Linkage);
+// ++(*CurBindNum);
+
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the NetConfig\XXXX key below IPX
+ // (we construct the right name in Subkey,
+ // first scan back to find the \, then copy
+ // the rest over, including the final '\0').
+ //
+ StringLoc = (DeviceName->MaximumLength / sizeof(WCHAR)) - 2;
+ while (DeviceName->Buffer[StringLoc] != L'\\') {
+ --StringLoc;
+ }
+ RtlCopyMemory(&Subkey[10], &DeviceName->Buffer[StringLoc+1], DeviceName->MaximumLength - ((StringLoc+1) * sizeof(WCHAR)));
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Subkey;
+
+ //
+ // 2) Call IpxGetFrameType for each part of the
+ // "PktType" multi-string.
+ //
+
+ QueryTable[1].QueryRoutine = IpxGetFrameType;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[1].Name = L"PktType";
+ QueryTable[1].EntryContext = &FrameTypeCount;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Call IpxGetFrameType for each part of the
+ // "NetworkNumber" multi-string.
+ //
+
+ QueryTable[2].QueryRoutine = IpxGetFrameType;
+ QueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[2].Name = L"NetworkNumber";
+ QueryTable[2].EntryContext = &NetworkNumberCount;
+ QueryTable[2].DefaultType = REG_NONE;
+
+ //
+ // 4-11) Call IpxGetBindingValue for each of the keys we
+ // care about.
+ //
+
+ for (i = 0; i < BINDING_PARAMETERS; i++) {
+
+ QueryTable[i+3].QueryRoutine = IpxGetBindingValue;
+ QueryTable[i+3].Flags = 0;
+ QueryTable[i+3].Name = ParameterValues[i].KeyName;
+ QueryTable[i+3].EntryContext = (PVOID)i;
+ QueryTable[i+3].DefaultType = REG_DWORD;
+ QueryTable[i+3].DefaultData = (PVOID)(ParameterValues[i].DefaultValue);
+ QueryTable[i+3].DefaultLength = sizeof(ULONG);
+
+ }
+
+ //
+ // 12) Stop
+ //
+
+ QueryTable[BINDING_PARAMETERS+3].QueryRoutine = NULL;
+ QueryTable[BINDING_PARAMETERS+3].Flags = 0;
+ QueryTable[BINDING_PARAMETERS+3].Name = NULL;
+
+
+ IPX_DEBUG (CONFIG, ("Read bind key for %ws (%ws)\n", DeviceName->Buffer, Subkey));
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Binding,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+
+ //
+ // The binding will get freed during cleanup.
+ //
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 906,
+ Status,
+ Subkey,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ if (FrameTypeCount == 0) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_NO_FRAME_TYPES,
+ 907,
+ Status,
+ Subkey + 10,
+ 0,
+ NULL);
+ }
+
+ if (FrameTypeCount > NetworkNumberCount) {
+ for (i = NetworkNumberCount; i <FrameTypeCount; i++) {
+ Binding->NetworkNumber[i] = 0;
+ }
+ }
+ Binding->FrameTypeCount = FrameTypeCount;
+
+ //
+ // Go through and eliminate duplicates from the frame
+ // type array.
+ //
+
+ for (i = 0; i < Binding->FrameTypeCount; i++) {
+
+ for (j = i+1; j < Binding->FrameTypeCount; j++) {
+
+ if (Binding->FrameType[j] == Binding->FrameType[i]) {
+
+ IPX_DEBUG (CONFIG, ("Frame types %d and %d identical\n", i, j));
+
+ //
+ // A duplicate, slide everything else down.
+ //
+
+ for (k = j+1; k < Binding->FrameTypeCount; k++) {
+ Binding->FrameType[k-1] = Binding->FrameType[k];
+ Binding->NetworkNumber[k-1] = Binding->NetworkNumber[k];
+ }
+ --Binding->FrameTypeCount;
+
+ --j; // so we check whoever just moved into this spot.
+ }
+ }
+ }
+
+
+ //
+ // Mark all the explicitly configured frame types, and
+ // see if we have to auto-detect.
+ //
+
+ for (i = 0; i < 4; i++) {
+ FrameTypeUsed[i] = FALSE;
+ }
+
+ AutoDetect = FALSE;
+ for (i = 0; i < Binding->FrameTypeCount; i++) {
+ if ((Binding->FrameType[i] == ISN_FRAME_TYPE_AUTO)) {
+ AutoDetectLoc = i;
+ AutoDetect = TRUE;
+ } else {
+ Binding->AutoDetect[i] = FALSE;
+ Binding->DefaultAutoDetect[i] = FALSE;
+ FrameTypeUsed[Binding->FrameType[i]] = TRUE;
+ }
+ }
+
+ if (!AutoDetect) {
+ IPX_DEBUG (AUTO_DETECT, ("No bindings auto-detected\n"));
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Slide everything that is past the auto-detect point up
+ // to the end.
+ //
+
+ //
+ // Fixed this loop which can spill over if the FrameTypeCount is 4 and the SlideCount > 0.
+ // Here, the FrameTypeCount is 1-based, whereas the indices are 0-based, we need to make
+ // the index 1-based for this to work. So, instead of (3-Binding->FrameTypeCount), we use
+ // (4-Binding->FrameTypeCount). This loop copies all the non-auto-detect frametypes down to
+ // the bottom of the array to make space after the last auto-detect frame-type for filling
+ // in the frametypes in the preference order.
+ //
+#if 0
+ SlideCount = Binding->FrameTypeCount - AutoDetectLoc - 1;
+ for (j = 3; j > 3 - SlideCount; j--) {
+ Binding->FrameType[j] = Binding->FrameType[j-(3-Binding->FrameTypeCount)];
+ Binding->NetworkNumber[j] = Binding->NetworkNumber[j-(3-Binding->FrameTypeCount)];
+ Binding->AutoDetect[j] = Binding->AutoDetect[j-(3-Binding->FrameTypeCount)];
+ Binding->DefaultAutoDetect[j] = Binding->DefaultAutoDetect[j-(3-Binding->FrameTypeCount)];
+ }
+#else
+ SlideCount = Binding->FrameTypeCount - AutoDetectLoc - 1;
+ for (j = 3; j > 3 - SlideCount; j--) {
+ Binding->FrameType[j] = Binding->FrameType[j-(4-Binding->FrameTypeCount)];
+ Binding->NetworkNumber[j] = Binding->NetworkNumber[j-(4-Binding->FrameTypeCount)];
+ Binding->AutoDetect[j] = Binding->AutoDetect[j-(4-Binding->FrameTypeCount)];
+ Binding->DefaultAutoDetect[j] = Binding->DefaultAutoDetect[j-(4-Binding->FrameTypeCount)];
+ }
+#endif
+
+ //
+ // Now fill in any frame types that are not hard-coded,
+ // this will start at AutoDetectLoc and exactly fill up
+ // the gap created when we slid things up above. We
+ // first put the default auto-detect at the first spot.
+ //
+
+ if (!FrameTypeUsed[Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT]]) {
+ Binding->FrameType[AutoDetectLoc] = Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT];
+ Binding->NetworkNumber[AutoDetectLoc] = 0;
+ Binding->AutoDetect[AutoDetectLoc] = TRUE;
+ Binding->DefaultAutoDetect[AutoDetectLoc] = TRUE;
+ ++AutoDetectLoc;
+ FrameTypeUsed[Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT]] = TRUE;
+ }
+
+ //
+ // Now fill in the array, using the preference order in
+ // the BindingPreference array (this comes into effect
+ // because the first frame type in our list that we
+ // find is used).
+ //
+
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+
+ if (!FrameTypeUsed[BindingPreference[i]]) {
+ Binding->FrameType[AutoDetectLoc] = BindingPreference[i];
+ Binding->NetworkNumber[AutoDetectLoc] = 0;
+ Binding->AutoDetect[AutoDetectLoc] = TRUE;
+ Binding->DefaultAutoDetect[AutoDetectLoc] = FALSE;
+ ++AutoDetectLoc;
+ }
+ }
+
+ Binding->FrameTypeCount = ISN_FRAME_TYPE_MAX;
+
+#if DBG
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+ IPX_DEBUG (AUTO_DETECT, ("%d: type %d, net %d, auto %d\n",
+ i, Binding->FrameType[i], Binding->NetworkNumber[i], Binding->AutoDetect[i]));
+ }
+#endif
+
+ return STATUS_SUCCESS;
+} /* IpxPnPGetAdapterParameters */
+
+#endif _PNP_POWER
+
diff --git a/private/ntos/tdi/isnp/ipx/config.h b/private/ntos/tdi/isnp/ipx/config.h
new file mode 100644
index 000000000..ba6e76d83
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/config.h
@@ -0,0 +1,132 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ config.h
+
+Abstract:
+
+ Private include file for the ISN IPX module.
+ file defines all constants and structures necessary for support of
+ the dynamic configuration of ST.
+
+Revision History:
+
+--*/
+
+
+//
+// These are used to index into the Parameters array in CONFIG.
+//
+
+#define CONFIG_DEDICATED_ROUTER 0
+#define CONFIG_INIT_DATAGRAMS 1
+#define CONFIG_MAX_DATAGRAMS 2
+#define CONFIG_RIP_AGE_TIME 3
+#define CONFIG_RIP_COUNT 4
+#define CONFIG_RIP_TIMEOUT 5
+#define CONFIG_RIP_USAGE_TIME 6
+#define CONFIG_ROUTE_USAGE_TIME 7
+#define CONFIG_SOCKET_UNIQUENESS 8
+#define CONFIG_SOCKET_START 9
+#define CONFIG_SOCKET_END 10
+#define CONFIG_VIRTUAL_NETWORK 11
+#define CONFIG_MAX_MEMORY_USAGE 12
+#define CONFIG_RIP_TABLE_SIZE 13
+#define CONFIG_VIRTUAL_OPTIONAL 14
+#define CONFIG_ETHERNET_PAD 15
+#define CONFIG_ETHERNET_LENGTH 16
+#define CONFIG_SINGLE_NETWORK 17
+#define CONFIG_DISABLE_DIALOUT_SAP 18
+#define CONFIG_DISABLE_DIALIN_NB 19
+#define CONFIG_VERIFY_SOURCE_ADDRESS 20
+
+#define CONFIG_PARAMETERS 21
+
+//
+// Main configuration structure.
+//
+
+typedef struct _CONFIG {
+
+ ULONG Parameters[CONFIG_PARAMETERS]; // index defined above
+ NDIS_STRING DeviceName; // device name exported
+ PWSTR RegistryPathBuffer; // path to config info
+ ULONG BindCount; // entries in BindingList
+ LIST_ENTRY BindingList; // one per binding
+ PDRIVER_OBJECT DriverObject; // used for logging errors
+
+} CONFIG, * PCONFIG;
+
+
+//
+// These are used to index into the Parameters array in BINDING_CONFIG.
+//
+
+#define BINDING_MAX_PKT_SIZE 0
+#define BINDING_BIND_SAP 1
+#define BINDING_DEFAULT_AUTO_DETECT 2
+#define BINDING_SOURCE_ROUTE 3
+#define BINDING_ALL_ROUTE_DEF 4
+#define BINDING_ALL_ROUTE_BC 5
+#define BINDING_ALL_ROUTE_MC 6
+#define BINDING_ENABLE_FUNC_ADDR 7
+#define BINDING_ENABLE_WAN 8
+
+#define BINDING_PARAMETERS 9
+
+
+//
+// One of these is allocated per adapter we are to bind to.
+//
+
+typedef struct _BINDING_CONFIG {
+
+ LIST_ENTRY Linkage; // for chaining on BindingList
+ NDIS_STRING AdapterName; // NDIS adapter to bind to
+ ULONG FrameTypeCount; // number of frame types defined (max. 4)
+ // == number of valid entries in arrays:
+ ULONG FrameType[ISN_FRAME_TYPE_MAX]; // ISN_FRAME_TYPE_XXX
+ ULONG NetworkNumber[ISN_FRAME_TYPE_MAX]; // may be 0
+ BOOLEAN AutoDetect[ISN_FRAME_TYPE_MAX]; // remove if net number can't be found
+ BOOLEAN DefaultAutoDetect[ISN_FRAME_TYPE_MAX]; // use this if multiple or none found
+ ULONG Parameters[BINDING_PARAMETERS]; // index defined above
+ PDRIVER_OBJECT DriverObject; // used for logging errors
+
+} BINDING_CONFIG, * PBINDING_CONFIG;
+
+
+NTSTATUS
+IpxGetConfiguration (
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath,
+ OUT PCONFIG * ConfigPtr
+ );
+
+VOID
+IpxFreeConfiguration (
+ IN PCONFIG Config
+ );
+
+VOID
+IpxWriteDefaultAutoDetectType(
+ IN PUNICODE_STRING RegistryPath,
+ IN struct _ADAPTER * Adapter,
+ IN ULONG FrameType
+ );
+
+#ifdef _PNP_POWER
+NTSTATUS
+IpxPnPGetVirtualNetworkNumber (
+ IN PCONFIG Config
+ );
+
+NTSTATUS
+IpxPnPGetAdapterParameters(
+ IN PCONFIG Config,
+ IN PNDIS_STRING DeviceName,
+ IN OUT PBINDING_CONFIG Binding
+ );
+#endif _PNP_POWER
diff --git a/private/ntos/tdi/isnp/ipx/device.c b/private/ntos/tdi/isnp/ipx/device.c
new file mode 100644
index 000000000..f2d9d19f4
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/device.c
@@ -0,0 +1,599 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ device.c
+
+Abstract:
+
+ This module contains code which implements the DEVICE_CONTEXT object.
+ Routines are provided to reference, and dereference transport device
+ context objects.
+
+ The transport device context object is a structure which contains a
+ system-defined DEVICE_OBJECT followed by information which is maintained
+ by the transport provider, called the context.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,IpxCreateDevice)
+#endif
+
+
+
+VOID
+IpxRefDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a device context.
+
+Arguments:
+
+ Device - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ CTEAssert (Device->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement(&Device->ReferenceCount);
+
+} /* IpxRefDevice */
+
+
+VOID
+IpxDerefDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a device context by decrementing the
+ reference count contained in the structure. Currently, we don't
+ do anything special when the reference count drops to zero, but
+ we could dynamically unload stuff then.
+
+Arguments:
+
+ Device - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&Device->ReferenceCount);
+
+ CTEAssert (result >= 0);
+
+ if (result == 0) {
+ IpxDestroyDevice (Device);
+ }
+
+} /* IpxDerefDevice */
+
+
+NTSTATUS
+IpxCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN ULONG SegmentCount,
+ IN OUT PDEVICE *DevicePtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates and initializes a device context structure.
+
+Arguments:
+
+
+ DriverObject - pointer to the IO subsystem supplied driver object.
+
+ Device - Pointer to a pointer to a transport device context object.
+
+ SegmentCount - The number of segments in the RIP router table.
+
+ DeviceName - pointer to the name of the device this device object points to.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
+
+--*/
+
+{
+ NTSTATUS status;
+ PDEVICE_OBJECT deviceObject;
+ PDEVICE Device;
+ ULONG DeviceSize;
+ ULONG LocksOffset;
+ ULONG SegmentsOffset;
+ ULONG DeviceNameOffset;
+ UINT i;
+
+
+ //
+ // Create the device object for the sample transport, allowing
+ // room at the end for the device name to be stored (for use
+ // in logging errors) and the RIP fields.
+ //
+
+ DeviceSize = sizeof(DEVICE) +
+ (sizeof(CTELock) * SegmentCount) +
+ (sizeof(ROUTER_SEGMENT) * SegmentCount) +
+ DeviceName->Length + sizeof(UNICODE_NULL);
+
+ status = IoCreateDevice(
+ DriverObject,
+ DeviceSize,
+ DeviceName,
+ FILE_DEVICE_TRANSPORT,
+ 0,
+ FALSE,
+ &deviceObject);
+
+ if (!NT_SUCCESS(status)) {
+ IPX_DEBUG(DEVICE, ("Create device %ws failed %lx\n", DeviceName->Buffer, status));
+ return status;
+ }
+
+ deviceObject->Flags |= DO_DIRECT_IO;
+
+ Device = (PDEVICE)deviceObject->DeviceExtension;
+
+ IPX_DEBUG(DEVICE, ("Create device %ws succeeded %lx\n", DeviceName->Buffer));
+
+ //
+ // Initialize our part of the device context.
+ //
+
+ RtlZeroMemory(
+ ((PUCHAR)Device) + sizeof(DEVICE_OBJECT),
+ sizeof(DEVICE) - sizeof(DEVICE_OBJECT));
+
+ Device->DeviceObject = deviceObject;
+
+ LocksOffset = sizeof(DEVICE);
+ SegmentsOffset = LocksOffset + (sizeof(CTELock) * SegmentCount);
+ DeviceNameOffset = SegmentsOffset + (sizeof(ROUTER_SEGMENT) * SegmentCount);
+
+ //
+ // Set some internal pointers.
+ //
+
+ Device->SegmentLocks = (CTELock *)(((PUCHAR)Device) + LocksOffset);
+ Device->Segments = (PROUTER_SEGMENT)(((PUCHAR)Device) + SegmentsOffset);
+ Device->SegmentCount = SegmentCount;
+
+ for (i = 0; i < SegmentCount; i++) {
+
+ CTEInitLock (&Device->SegmentLocks[i]);
+ InitializeListHead (&Device->Segments[i].WaitingForRoute);
+ InitializeListHead (&Device->Segments[i].FindWaitingForRoute);
+ InitializeListHead (&Device->Segments[i].WaitingLocalTarget);
+ InitializeListHead (&Device->Segments[i].WaitingReripNetnum);
+ InitializeListHead (&Device->Segments[i].Entries);
+ Device->Segments[i].EnumerateLocation = &Device->Segments[i].Entries;
+
+ }
+
+ //
+ // Copy over the device name.
+ //
+
+ Device->DeviceNameLength = DeviceName->Length + sizeof(WCHAR);
+ Device->DeviceName = (PWCHAR)(((PUCHAR)Device) + DeviceNameOffset);
+ RtlCopyMemory(
+ Device->DeviceName,
+ DeviceName->Buffer,
+ DeviceName->Length);
+ Device->DeviceName[DeviceName->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ //
+ // Initialize the reference count.
+ //
+
+ Device->ReferenceCount = 1;
+#if DBG
+ Device->RefTypes[DREF_CREATE] = 1;
+#endif
+
+#if DBG
+ RtlCopyMemory(Device->Signature1, "IDC1", 4);
+ RtlCopyMemory(Device->Signature2, "IDC2", 4);
+#endif
+
+ Device->Information.Version = 0x0100;
+ Device->Information.MaxSendSize = 0; // no sends allowed
+ Device->Information.MaxConnectionUserData = 0;
+ Device->Information.ServiceFlags =
+ TDI_SERVICE_CONNECTIONLESS_MODE | TDI_SERVICE_BROADCAST_SUPPORTED |
+ TDI_SERVICE_ROUTE_DIRECTED;
+ Device->Information.MinimumLookaheadData = 128;
+ Device->Information.NumberOfResources = IPX_TDI_RESOURCES;
+ KeQuerySystemTime (&Device->Information.StartTime);
+
+ Device->Statistics.Version = 0x0100;
+
+#if 0
+ //
+ // These will be filled in after all the binding is done.
+ //
+
+ Device->Information.MaxDatagramSize = 0;
+ Device->Information.MaximumLookaheadData = 0;
+
+
+ Device->SourceRoutingUsed = FALSE;
+ Device->SourceRoutingTime = 0;
+ Device->RipPacketCount = 0;
+
+ Device->RipShortTimerActive = FALSE;
+ Device->RipSendTime = 0;
+#endif
+
+
+ //
+ // Initialize the resource that guards address ACLs.
+ //
+
+ ExInitializeResource (&Device->AddressResource);
+
+#ifdef _PNP_POWER
+ //
+ // Init the resource that guards the binding array/indices
+ //
+ CTEInitLock (&Device->BindAccessLock);
+#endif _PNP_POWER
+
+ InitializeListHead (&Device->WaitingRipPackets);
+ CTEInitTimer (&Device->RipShortTimer);
+ CTEInitTimer (&Device->RipLongTimer);
+
+ CTEInitTimer (&Device->SourceRoutingTimer);
+
+ //
+ // initialize the various fields in the device context
+ //
+
+ CTEInitLock (&Device->Interlock);
+ CTEInitLock (&Device->Lock);
+ CTEInitLock (&Device->SListsLock);
+
+ Device->ControlChannelIdentifier.QuadPart = 1;
+
+ InitializeListHead (&Device->GlobalSendPacketList);
+ InitializeListHead (&Device->GlobalReceivePacketList);
+ InitializeListHead (&Device->GlobalReceiveBufferList);
+#if BACK_FILL
+ InitializeListHead (&Device->GlobalBackFillPacketList);
+#endif
+
+ InitializeListHead (&Device->AddressNotifyQueue);
+ InitializeListHead (&Device->LineChangeQueue);
+
+ for (i = 0; i < IPX_ADDRESS_HASH_COUNT; i++) {
+ InitializeListHead (&Device->AddressDatabases[i]);
+ }
+
+#if BACK_FILL
+ InitializeListHead (&Device->BackFillPoolList);
+#endif
+ InitializeListHead (&Device->SendPoolList);
+ InitializeListHead (&Device->ReceivePoolList);
+
+#ifdef _PNP_POWER
+ InitializeListHead (&Device->BindingPoolList);
+#endif
+
+ ExInitializeSListHead (&Device->SendPacketList);
+ ExInitializeSListHead (&Device->ReceivePacketList);
+#if BACK_FILL
+ ExInitializeSListHead (&Device->BackFillPacketList);
+#endif
+
+#ifdef _PNP_POWER
+ ExInitializeSListHead (&Device->BindingList);
+#endif
+
+#if 0
+ Device->MemoryUsage = 0;
+ Device->SendPacketList.Next = NULL;
+ Device->ReceivePacketList.Next = NULL;
+ Device->Bindings = NULL;
+ Device->BindingCount = 0;
+#endif
+
+ KeQuerySystemTime (&Device->IpxStartTime);
+
+ Device->State = DEVICE_STATE_CLOSED;
+ Device->AutoDetectState = AUTO_DETECT_STATE_INIT;
+
+ Device->Type = IPX_DEVICE_SIGNATURE;
+ Device->Size = sizeof (DEVICE);
+
+
+ *DevicePtr = Device;
+ return STATUS_SUCCESS;
+
+} /* IpxCreateDevice */
+
+
+VOID
+IpxDestroyDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a device context structure.
+
+Arguments:
+
+ Device - Pointer to a pointer to a transport device context object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY s;
+ PIPX_SEND_POOL SendPool;
+ PIPX_SEND_PACKET SendPacket;
+ PIPX_RECEIVE_POOL ReceivePool;
+ PIPX_RECEIVE_PACKET ReceivePacket;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ UINT SendPoolSize;
+ UINT ReceivePoolSize;
+ UINT i;
+#if BACK_FILL
+ PIPX_SEND_POOL BackFillPool;
+ UINT BackFillPoolSize;
+ PIPX_SEND_PACKET BackFillPacket;
+#endif
+
+#ifdef _PNP_POWER
+ PIPX_BINDING_POOL BindingPool;
+ UINT BindingPoolSize;
+ PBINDING Binding;
+#endif
+
+ IPX_DEBUG (DEVICE, ("Destroy device %lx\n", Device));
+
+ //
+ // Take all the packets out of its pools.
+ //
+
+#if _PNP_POWER
+ BindingPoolSize = FIELD_OFFSET (IPX_BINDING_POOL, Bindings[0]) +
+ (sizeof(BINDING) * Device->InitBindings);
+
+ while (!IsListEmpty (&Device->BindingPoolList)) {
+
+ p = RemoveHeadList (&Device->BindingPoolList);
+ BindingPool = CONTAINING_RECORD (p, IPX_BINDING_POOL, Linkage);
+ IPX_DEBUG (PACKET, ("Free binding pool %lx\n", BindingPool));
+ IpxFreeMemory (BindingPool, BindingPoolSize, MEMORY_PACKET, "BindingPool");
+
+ }
+#endif
+
+#ifdef IPX_OWN_PACKETS
+
+#if BACK_FILL
+ BackFillPoolSize = FIELD_OFFSET (IPX_SEND_POOL, Packets[0]) +
+ (sizeof(IPX_SEND_PACKET) * Device->InitDatagrams);
+ while (!IsListEmpty (&Device->BackFillPoolList)) {
+
+ p = RemoveHeadList (&Device->BackFillPoolList);
+ BackFillPool = CONTAINING_RECORD (p, IPX_SEND_POOL, Linkage);
+
+ for (i = 0; i < BackFillPool->PacketCount; i++) {
+ BackFillPacket = &BackFillPool->Packets[i];
+ IpxDeinitializeBackFillPacket (Device, BackFillPacket);
+ }
+
+ IPX_DEBUG (PACKET, ("Free packet pool %lx\n", BackFillPool));
+ IpxFreeMemory (BackFillPool, BackFillPoolSize, MEMORY_PACKET, "BackPool");
+ }
+#endif
+
+ SendPoolSize = FIELD_OFFSET (IPX_SEND_POOL, Packets[0]) +
+ (sizeof(IPX_SEND_PACKET) * Device->InitDatagrams) +
+ (((IPX_MAXIMUM_MAC + sizeof(IPX_HEADER) + 3) & ~3) * Device->InitDatagrams);
+
+ while (!IsListEmpty (&Device->SendPoolList)) {
+
+ p = RemoveHeadList (&Device->SendPoolList);
+ SendPool = CONTAINING_RECORD (p, IPX_SEND_POOL, Linkage);
+
+ for (i = 0; i < SendPool->PacketCount; i++) {
+
+ SendPacket = &SendPool->Packets[i];
+ IpxDeinitializeSendPacket (Device, SendPacket);
+
+ }
+
+ IPX_DEBUG (PACKET, ("Free packet pool %lx\n", SendPool));
+ IpxFreeMemory (SendPool, SendPoolSize, MEMORY_PACKET, "SendPool");
+ }
+
+ ReceivePoolSize = FIELD_OFFSET (IPX_RECEIVE_POOL, Packets[0]) +
+ (sizeof(IPX_RECEIVE_PACKET) * Device->InitReceivePackets);
+
+ while (!IsListEmpty (&Device->ReceivePoolList)) {
+
+ p = RemoveHeadList (&Device->ReceivePoolList);
+ ReceivePool = CONTAINING_RECORD (p, IPX_RECEIVE_POOL, Linkage);
+
+ for (i = 0; i < ReceivePool->PacketCount; i++) {
+
+ ReceivePacket = &ReceivePool->Packets[i];
+ IpxDeinitializeReceivePacket (Device, ReceivePacket);
+
+ }
+
+ IPX_DEBUG (PACKET, ("Free receive packet pool %lx\n", ReceivePool));
+ IpxFreeMemory (ReceivePool, ReceivePoolSize, MEMORY_PACKET, "ReceivePool");
+ }
+#else
+
+#if BACK_FILL
+
+ while (s = IPX_POP_ENTRY_LIST(&Device->BackFillPacketList, &Device->Lock)) {
+ PIPX_SEND_RESERVED Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+ IPX_SEND_PACKET BackFillPacket;
+
+ BackFillPacket.Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ IpxDeinitializeBackFillPacket (Device, &BackFillPacket);
+ Device->MemoryUsage -= (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_SEND_RESERVED));
+ }
+
+ while (!IsListEmpty (&Device->BackFillPoolList)) {
+
+ p = RemoveHeadList (&Device->BackFillPoolList);
+ BackFillPool = CONTAINING_RECORD (p, IPX_SEND_POOL, Linkage);
+
+ IPX_DEBUG (PACKET, ("Free packet pool %lx\n", BackFillPool));
+ NdisFreePacketPool (BackFillPool->PoolHandle);
+ Device->MemoryUsage -= FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]);
+
+ IpxFreeMemory (BackFillPool, sizeof(IPX_SEND_POOL), MEMORY_PACKET, "BafiPool");
+ }
+#endif
+
+ while (s = IPX_POP_ENTRY_LIST(&Device->SendPacketList, &Device->Lock)){
+ PIPX_SEND_RESERVED Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+ IPX_SEND_PACKET SendPacket;
+ PUCHAR Header = Reserved->Header;
+
+ SendPacket.Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ IpxDeinitializeSendPacket (Device, &SendPacket);
+ Device->MemoryUsage -= (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_SEND_RESERVED));
+ }
+
+ while (!IsListEmpty (&Device->SendPoolList)) {
+
+ p = RemoveHeadList (&Device->SendPoolList);
+ SendPool = CONTAINING_RECORD (p, IPX_SEND_POOL, Linkage);
+
+ IPX_DEBUG (PACKET, ("Free packet pool %lx\n", SendPool));
+ NdisFreePacketPool (SendPool->PoolHandle);
+ Device->MemoryUsage -= FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]);
+
+ IpxFreeMemory (SendPool->Header, PACKET_HEADER_SIZE * Device->InitDatagrams, MEMORY_PACKET, "SendPool");
+
+ IpxFreeMemory (SendPool, sizeof(IPX_SEND_POOL), MEMORY_PACKET, "SendPool");
+ }
+
+ while (s = IPX_POP_ENTRY_LIST(&Device->ReceivePacketList, &Device->Lock)){
+ PIPX_RECEIVE_RESERVED Reserved = CONTAINING_RECORD (s, IPX_RECEIVE_RESERVED, PoolLinkage);
+ IPX_RECEIVE_PACKET ReceivePacket;
+
+ ReceivePacket.Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ IpxDeinitializeReceivePacket (Device, &ReceivePacket);
+ Device->MemoryUsage -= (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_RECEIVE_RESERVED));
+ }
+
+ while (!IsListEmpty (&Device->ReceivePoolList)) {
+
+ p = RemoveHeadList (&Device->ReceivePoolList);
+ ReceivePool = CONTAINING_RECORD (p, IPX_RECEIVE_POOL, Linkage);
+
+ IPX_DEBUG (PACKET, ("Free packet pool %lx\n", ReceivePool));
+ NdisFreePacketPool (ReceivePool->PoolHandle);
+ Device->MemoryUsage -= FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]);
+
+ IpxFreeMemory (ReceivePool, sizeof(IPX_RECEIVE_POOL), MEMORY_PACKET, "ReceivePool");
+ }
+
+#endif IPX_OWN_PACKETS
+ //
+ // Destroy all rip table entries.
+ //
+
+ for (i = 0; i < Device->SegmentCount; i++) {
+
+ RouteEntry = RipGetFirstRoute(i);
+ while (RouteEntry != NULL) {
+
+ (VOID)RipDeleteRoute(i, RouteEntry);
+ IpxFreeMemory(RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ RouteEntry = RipGetNextRoute(i);
+
+ }
+
+ }
+
+ IPX_DEBUG (DEVICE, ("Final memory use is %d\n", Device->MemoryUsage));
+#if DBG
+ for (i = 0; i < MEMORY_MAX; i++) {
+ if (IpxMemoryTag[i].BytesAllocated != 0) {
+ IPX_DEBUG (DEVICE, ("Tag %d: %d bytes left\n", i, IpxMemoryTag[i].BytesAllocated));
+ }
+ }
+#endif
+
+ //
+ // If we are being unloaded then someone is waiting for this
+ // event to finish the cleanup, since we may be at DISPATCH_LEVEL;
+ // otherwise it is during load and we can just kill ourselves here.
+ //
+
+ if (Device->UnloadWaiting) {
+
+ KeSetEvent(
+ &Device->UnloadEvent,
+ 0L,
+ FALSE);
+
+ } else {
+
+ CTEAssert (KeGetCurrentIrql() < DISPATCH_LEVEL);
+ ExDeleteResource (&Device->AddressResource);
+ IoDeleteDevice (Device->DeviceObject);
+ }
+
+} /* IpxDestroyDevice */
+
diff --git a/private/ntos/tdi/isnp/ipx/dirs b/private/ntos/tdi/isnp/ipx/dirs
new file mode 100644
index 000000000..0dab2f056
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/dirs
@@ -0,0 +1,22 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=up mp
diff --git a/private/ntos/tdi/isnp/ipx/driver.c b/private/ntos/tdi/isnp/ipx/driver.c
new file mode 100644
index 000000000..7c32cd0e3
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/driver.c
@@ -0,0 +1,4219 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ driver.c
+
+Abstract:
+
+ This module contains the DriverEntry and other initialization
+ code for the IPX module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+ Sanjay Anand (SanjayAn) 18-Sept-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+PDEVICE IpxDevice = NULL;
+PIPX_PADDING_BUFFER IpxPaddingBuffer = NULL;
+
+#if DBG
+
+UCHAR IpxTempDebugBuffer[150];
+ULONG IpxDebug = 0x0;
+ULONG IpxMemoryDebug = 0xffffffd3;
+UCHAR IpxDebugMemory[IPX_MEMORY_LOG_SIZE][64];
+PUCHAR IpxDebugMemoryLoc = IpxDebugMemory[0];
+PUCHAR IpxDebugMemoryEnd = IpxDebugMemory[IPX_MEMORY_LOG_SIZE];
+
+VOID
+IpxDebugMemoryLog(
+ IN PUCHAR FormatString,
+ ...
+)
+
+{
+ INT ArgLen;
+ va_list ArgumentPointer;
+
+ va_start(ArgumentPointer, FormatString);
+
+ //
+ // To avoid any overflows, copy this in a temp buffer first.
+ RtlZeroMemory (IpxTempDebugBuffer, 150);
+ ArgLen = vsprintf(IpxTempDebugBuffer, FormatString, ArgumentPointer);
+ va_end(ArgumentPointer);
+
+ if ( ArgLen > 64 ) {
+ CTEAssert( FALSE );
+ } else {
+ RtlZeroMemory (IpxDebugMemoryLoc, 64);
+ RtlCopyMemory( IpxDebugMemoryLoc, IpxTempDebugBuffer, ArgLen );
+
+ IpxDebugMemoryLoc += 64;
+ if (IpxDebugMemoryLoc >= IpxDebugMemoryEnd) {
+ IpxDebugMemoryLoc = IpxDebugMemory[0];
+ }
+ }
+}
+
+
+DEFINE_LOCK_STRUCTURE(IpxMemoryInterlock);
+MEMORY_TAG IpxMemoryTag[MEMORY_MAX];
+
+DEFINE_LOCK_STRUCTURE(IpxGlobalInterlock);
+
+#endif
+
+#if DBG
+
+//
+// Use for debug printouts
+//
+
+PUCHAR FrameTypeNames[5] = { "Ethernet II", "802.3", "802.2", "SNAP", "Arcnet" };
+#define OutputFrameType(_Binding) \
+ (((_Binding)->Adapter->MacInfo.MediumType == NdisMediumArcnet878_2) ? \
+ FrameTypeNames[4] : \
+ FrameTypeNames[(_Binding)->FrameType])
+#endif
+
+
+#ifdef IPX_PACKET_LOG
+
+ULONG IpxPacketLogDebug = IPX_PACKET_LOG_RCV_OTHER | IPX_PACKET_LOG_SEND_OTHER;
+USHORT IpxPacketLogSocket = 0;
+DEFINE_LOCK_STRUCTURE(IpxPacketLogLock);
+IPX_PACKET_LOG_ENTRY IpxPacketLog[IPX_PACKET_LOG_LENGTH];
+PIPX_PACKET_LOG_ENTRY IpxPacketLogLoc = IpxPacketLog;
+PIPX_PACKET_LOG_ENTRY IpxPacketLogEnd = &IpxPacketLog[IPX_PACKET_LOG_LENGTH];
+
+VOID
+IpxLogPacket(
+ IN BOOLEAN Send,
+ IN PUCHAR DestMac,
+ IN PUCHAR SrcMac,
+ IN USHORT Length,
+ IN PVOID IpxHeader,
+ IN PVOID Data
+ )
+
+{
+
+ CTELockHandle LockHandle;
+ PIPX_PACKET_LOG_ENTRY PacketLog;
+ LARGE_INTEGER TickCount;
+ ULONG DataLength;
+
+ CTEGetLock (&IpxPacketLogLock, &LockHandle);
+
+ PacketLog = IpxPacketLogLoc;
+
+ ++IpxPacketLogLoc;
+ if (IpxPacketLogLoc >= IpxPacketLogEnd) {
+ IpxPacketLogLoc = IpxPacketLog;
+ }
+ *(UNALIGNED ULONG *)IpxPacketLogLoc->TimeStamp = 0x3e3d3d3d; // "===>"
+
+ CTEFreeLock (&IpxPacketLogLock, LockHandle);
+
+ RtlZeroMemory (PacketLog, sizeof(IPX_PACKET_LOG_ENTRY));
+
+ PacketLog->SendReceive = Send ? '>' : '<';
+
+ KeQueryTickCount(&TickCount);
+ _itoa (TickCount.LowPart % 100000, PacketLog->TimeStamp, 10);
+
+ RtlCopyMemory(PacketLog->DestMac, DestMac, 6);
+ RtlCopyMemory(PacketLog->SrcMac, SrcMac, 6);
+ PacketLog->Length[0] = Length / 256;
+ PacketLog->Length[1] = Length % 256;
+
+ if (Length < sizeof(IPX_HEADER)) {
+ RtlCopyMemory(&PacketLog->IpxHeader, IpxHeader, Length);
+ } else {
+ RtlCopyMemory(&PacketLog->IpxHeader, IpxHeader, sizeof(IPX_HEADER));
+ }
+
+ DataLength = Length - sizeof(IPX_HEADER);
+ if (DataLength < 14) {
+ RtlCopyMemory(PacketLog->Data, Data, DataLength);
+ } else {
+ RtlCopyMemory(PacketLog->Data, Data, 14);
+ }
+
+} /* IpxLogPacket */
+
+#endif // IPX_PACKET_LOG
+
+
+//
+// Forward declaration of various routines used in this module.
+//
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+//
+// This is now shared with other modules
+//
+#ifndef _PNP_POWER
+ULONG
+IpxResolveAutoDetect(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+VOID
+IpxResolveBindingSets(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings
+ );
+
+NTSTATUS
+IpxBindToAdapter(
+ IN PDEVICE Device,
+ IN PBINDING_CONFIG ConfigAdapter,
+ IN ULONG FrameTypeIndex
+ );
+
+NTSTATUS
+IpxUnBindFromAdapter(
+ IN PBINDING Binding
+ );
+#endif _PNP_POWER
+
+VOID
+IpxUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+NTSTATUS
+IpxDispatchDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+IpxDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+IpxDispatchInternal (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,DriverEntry)
+
+//
+// These routines can be called at any time in case of PnP.
+//
+#ifndef _PNP_POWER
+#pragma alloc_text(INIT,IpxResolveAutoDetect)
+#pragma alloc_text(INIT,IpxResolveBindingSets)
+#pragma alloc_text(INIT,IpxBindToAdapter)
+#endif
+
+#endif
+
+UCHAR VirtualNode[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
+
+//
+// This prevents us from having a bss section.
+//
+
+ULONG _setjmpexused = 0;
+
+ULONG IpxFailLoad = FALSE;
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs initialization of the IPX ISN module.
+ It creates the device objects for the transport
+ provider and performs other driver initialization.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+ RegistryPath - The name of IPX's node in the registry.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ UINT SuccessfulOpens, ValidBindings;
+#ifdef _PNP_POWER
+ static const NDIS_STRING ProtocolName = NDIS_STRING_CONST("NWLNKIPX");
+#else
+ static const NDIS_STRING ProtocolName = NDIS_STRING_CONST("IPX Transport");
+#endif
+ PDEVICE Device;
+ PBINDING Binding;
+ PADAPTER Adapter;
+ ULONG BindingCount, BindingIndex;
+ PBINDING * BindingArray;
+ PLIST_ENTRY p;
+ ULONG AnnouncedMaxDatagram, RealMaxDatagram, MaxLookahead;
+ ULONG LinkSpeed, MacOptions;
+ ULONG Temp;
+ UINT i;
+ BOOLEAN CountedWan;
+
+ PCONFIG Config = NULL;
+ PBINDING_CONFIG ConfigBinding;
+
+#if 0
+ DbgPrint ("IPX: FailLoad at %lx\n", &IpxFailLoad);
+ DbgBreakPoint();
+
+ if (IpxFailLoad) {
+ return STATUS_UNSUCCESSFUL;
+ }
+#endif
+
+
+ //
+ // This ordering matters because we use it to quickly
+ // determine if packets are internally generated or not.
+ //
+
+ CTEAssert (IDENTIFIER_NB < IDENTIFIER_IPX);
+ CTEAssert (IDENTIFIER_SPX < IDENTIFIER_IPX);
+ CTEAssert (IDENTIFIER_RIP < IDENTIFIER_IPX);
+ CTEAssert (IDENTIFIER_RIP_INTERNAL > IDENTIFIER_IPX);
+
+ //
+ // We assume that this structure is not packet in between
+ // the fields.
+ //
+
+ CTEAssert (FIELD_OFFSET (TDI_ADDRESS_IPX, Socket) + sizeof(USHORT) == 12);
+
+
+ //
+ // Initialize the Common Transport Environment.
+ //
+
+ if (CTEInitialize() == 0) {
+
+ IPX_DEBUG (DEVICE, ("CTEInitialize() failed\n"));
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_REGISTER_FAILED,
+ 101,
+ STATUS_UNSUCCESSFUL,
+ NULL,
+ 0,
+ NULL);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+#if DBG
+ CTEInitLock (&IpxGlobalInterlock);
+ CTEInitLock (&IpxMemoryInterlock);
+ for (i = 0; i < MEMORY_MAX; i++) {
+ IpxMemoryTag[i].Tag = i;
+ IpxMemoryTag[i].BytesAllocated = 0;
+ }
+#endif
+#ifdef IPX_PACKET_LOG
+ CTEInitLock (&IpxPacketLogLock);
+#endif
+
+#ifdef IPX_OWN_PACKETS
+ CTEAssert (NDIS_PACKET_SIZE == FIELD_OFFSET(NDIS_PACKET, ProtocolReserved[0]));
+#endif
+
+ IPX_DEBUG (DEVICE, ("IPX loaded\n"));
+
+ //
+ // This allocates the CONFIG structure and returns
+ // it in Config.
+ //
+
+ status = IpxGetConfiguration(DriverObject, RegistryPath, &Config);
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // If it failed, it logged an error.
+ //
+
+ PANIC (" Failed to initialize transport, IPX initialization failed.\n");
+ return status;
+
+ }
+
+#ifdef _PNP_POWER
+ //
+ // Initialize the TDI layer.
+ //
+ TdiInitialize();
+#endif
+
+ //
+ // make ourselves known to the NDIS wrapper.
+ //
+
+ status = IpxRegisterProtocol ((PNDIS_STRING)&ProtocolName);
+
+ if (!NT_SUCCESS (status)) {
+
+ IpxFreeConfiguration(Config);
+ PANIC ("IpxInitialize: RegisterProtocol failed!\n");
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_REGISTER_FAILED,
+ 607,
+ status,
+ NULL,
+ 0,
+ NULL);
+
+ return status;
+
+ }
+
+
+ //
+ // Initialize the driver object with this driver's entry points.
+ //
+
+ DriverObject->MajorFunction [IRP_MJ_CREATE] = IpxDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLOSE] = IpxDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLEANUP] = IpxDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL] = IpxDispatchInternal;
+ DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = IpxDispatchDeviceControl;
+
+ DriverObject->DriverUnload = IpxUnload;
+
+ SuccessfulOpens = 0;
+
+ status = IpxCreateDevice(
+ DriverObject,
+ &Config->DeviceName,
+ Config->Parameters[CONFIG_RIP_TABLE_SIZE],
+ &Device);
+
+ if (!NT_SUCCESS (status)) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_CREATE_DEVICE,
+ 801,
+ status,
+ NULL,
+ 0,
+ NULL);
+
+ IpxFreeConfiguration(Config);
+ IpxDeregisterProtocol();
+ return status;
+ }
+
+ IpxDevice = Device;
+
+
+ //
+ // Save the relevant configuration parameters.
+ //
+
+ Device->DedicatedRouter = (BOOLEAN)(Config->Parameters[CONFIG_DEDICATED_ROUTER] != 0);
+ Device->InitDatagrams = Config->Parameters[CONFIG_INIT_DATAGRAMS];
+ Device->MaxDatagrams = Config->Parameters[CONFIG_MAX_DATAGRAMS];
+ Device->RipAgeTime = Config->Parameters[CONFIG_RIP_AGE_TIME];
+ Device->RipCount = Config->Parameters[CONFIG_RIP_COUNT];
+ Device->RipTimeout =
+ ((Config->Parameters[CONFIG_RIP_TIMEOUT] * 500) + (RIP_GRANULARITY/2)) /
+ RIP_GRANULARITY;
+ Device->RipUsageTime = Config->Parameters[CONFIG_RIP_USAGE_TIME];
+ Device->SourceRouteUsageTime = Config->Parameters[CONFIG_ROUTE_USAGE_TIME];
+ Device->SocketUniqueness = Config->Parameters[CONFIG_SOCKET_UNIQUENESS];
+ Device->SocketStart = (USHORT)Config->Parameters[CONFIG_SOCKET_START];
+ Device->SocketEnd = (USHORT)Config->Parameters[CONFIG_SOCKET_END];
+ Device->MemoryLimit = Config->Parameters[CONFIG_MAX_MEMORY_USAGE];
+ Device->VerifySourceAddress = (BOOLEAN)(Config->Parameters[CONFIG_VERIFY_SOURCE_ADDRESS] != 0);
+
+ Device->InitReceivePackets = (Device->InitDatagrams + 1) / 2;
+ Device->InitReceiveBuffers = (Device->InitDatagrams + 1) / 2;
+
+ Device->MaxReceivePackets = 10; // BUGBUG: config this?
+ Device->MaxReceiveBuffers = 10;
+
+#ifdef _PNP_POWER
+ Device->InitBindings = 5; // BUGBUG: config this?
+
+ //
+ // RAS max is 240 (?) + 10 max LAN
+ //
+ Device->MaxPoolBindings = 250; // BUGBUG: config this?
+#endif
+
+ //
+ // Have to reverse this.
+ //
+#ifndef _PNP_POWER
+//
+// Look at this only when the first adapter appears.
+//
+ Temp = Config->Parameters[CONFIG_VIRTUAL_NETWORK];
+ Device->VirtualNetworkNumber = REORDER_ULONG (Temp);
+#endif
+
+ Device->VirtualNetworkOptional = (BOOLEAN)(Config->Parameters[CONFIG_VIRTUAL_OPTIONAL] != 0);
+
+ Device->CurrentSocket = Device->SocketStart;
+
+ Device->EthernetPadToEven = (BOOLEAN)(Config->Parameters[CONFIG_ETHERNET_PAD] != 0);
+ Device->EthernetExtraPadding = (Config->Parameters[CONFIG_ETHERNET_LENGTH] & 0xfffffffe) + 1;
+
+ Device->SingleNetworkActive = (BOOLEAN)(Config->Parameters[CONFIG_SINGLE_NETWORK] != 0);
+ Device->DisableDialoutSap = (BOOLEAN)(Config->Parameters[CONFIG_DISABLE_DIALOUT_SAP] != 0);
+ Device->DisableDialinNetbios = (UCHAR)(Config->Parameters[CONFIG_DISABLE_DIALIN_NB]);
+
+#ifdef _PNP_POWER
+//
+// Used later to access the registry.
+//
+ Device->RegistryPathBuffer = Config->RegistryPathBuffer;
+ Device->RegistryPath.Length = RegistryPath->Length;
+ Device->RegistryPath.MaximumLength = RegistryPath->MaximumLength;
+ Device->RegistryPath.Buffer = Device->RegistryPathBuffer;
+#endif _PNP_POWER
+
+ //
+ // ActiveNetworkWan will start as FALSE, which is correct.
+ //
+
+ //
+ // Allocate our initial packet pool. We do not allocate
+ // receive and receive buffer pools until we need them,
+ // because in many cases we never do.
+ //
+
+#if BACK_FILL
+ IpxAllocateBackFillPool (Device);
+#endif
+
+ IpxAllocateSendPool (Device);
+
+#ifdef _PNP_POWER
+ IpxAllocateBindingPool (Device);
+#endif
+
+ //
+ // Allocate one 1-byte buffer for odd length packets.
+ //
+
+ IpxPaddingBuffer = IpxAllocatePaddingBuffer(Device);
+
+ if ( IpxPaddingBuffer == (PIPX_PADDING_BUFFER)NULL ) {
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 801,
+ STATUS_INSUFFICIENT_RESOURCES,
+ NULL,
+ 0,
+ NULL);
+
+ IpxFreeConfiguration(Config);
+ IpxDeregisterProtocol();
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Initialize the loopback structures
+ //
+ IpxInitLoopback();
+
+//
+// All this will be done on appearance of adapters.
+//
+
+#ifndef _PNP_POWER
+
+ //
+ // Bind to all the configured adapters.
+ //
+
+ InitializeListHead (&Device->InitialBindingList);
+
+ p = Config->BindingList.Flink;
+
+ while (p != &Config->BindingList) {
+
+ ConfigBinding = CONTAINING_RECORD (p, BINDING_CONFIG, Linkage);
+ p = p->Flink;
+
+ for (i = 0; i < ConfigBinding->FrameTypeCount; i++) {
+
+ //
+ // If successful, this queues them on Device->InitialBindingList.
+ //
+
+ status = IpxBindToAdapter (Device, ConfigBinding, i);
+
+ //
+ // If this failed because the adapter could not be bound
+ // to, then don't try any more frame types on this adapter.
+ // For other failures we do try the other frame types.
+ //
+
+ if (status == STATUS_DEVICE_DOES_NOT_EXIST) {
+ break;
+ }
+
+ if (status != STATUS_SUCCESS) {
+ continue;
+ }
+
+ if (ConfigBinding->AutoDetect[i]) {
+ Device->AutoDetect = TRUE;
+ }
+
+ ++SuccessfulOpens;
+
+ }
+
+ }
+
+
+ IpxFreeConfiguration(Config);
+
+ if (SuccessfulOpens == 0) {
+
+ IpxDereferenceDevice (Device, DREF_CREATE);
+
+ } else {
+
+ IPX_DEFINE_SYNC_CONTEXT (SyncContext);
+
+ //
+ // Allocate the device binding array and transfer those
+ // on the list to it. First count up the bindings.
+ //
+
+ BindingCount = 0;
+
+ for (p = Device->InitialBindingList.Flink;
+ p != &Device->InitialBindingList;
+ p = p->Flink) {
+
+ Binding = CONTAINING_RECORD (p, BINDING, InitialLinkage);
+ Adapter = Binding->Adapter;
+
+ if (Adapter->MacInfo.MediumAsync) {
+ Adapter->FirstWanNicId = (USHORT)(BindingCount+1);
+ Adapter->LastWanNicId = (USHORT)(BindingCount + Adapter->WanNicIdCount);
+ BindingCount += Adapter->WanNicIdCount;
+ } else {
+ ++BindingCount;
+ }
+ }
+
+ BindingArray = (PBINDING *)IpxAllocateMemory ((BindingCount+1) * sizeof(BINDING), MEMORY_BINDING, "Binding array");
+
+ if (BindingArray == NULL) {
+
+ while (!IsListEmpty (&Device->InitialBindingList)) {
+ p = RemoveHeadList (&Device->InitialBindingList);
+ Binding = CONTAINING_RECORD (p, BINDING, InitialLinkage);
+ IpxDestroyBinding (Binding);
+ }
+
+ IpxDereferenceDevice (Device, DREF_CREATE);
+ SuccessfulOpens = 0;
+ goto InitFailed;
+ }
+
+ RtlZeroMemory (BindingArray, (BindingCount+1) * sizeof(BINDING));
+
+ //
+ // Now walk the list transferring bindings to the array.
+ //
+
+ BindingIndex = 1;
+
+ for (p = Device->InitialBindingList.Flink;
+ p != &Device->InitialBindingList;
+ ) {
+
+ Binding = CONTAINING_RECORD (p, BINDING, InitialLinkage);
+
+ p = p->Flink; // we overwrite the linkage in here, so save it.
+
+ BindingArray[BindingIndex] = Binding;
+ Binding->NicId = (USHORT)BindingIndex;
+
+ if (Binding->ConfiguredNetworkNumber != 0) {
+
+ //
+ // If the configured network number is non-zero, then
+ // use it, unless we are unable to insert a rip table
+ // entry for it (duplicates are OK because they will
+ // become binding set members -- BUGBUG: What if the
+ // duplicate is a different media or frame type, then
+ // it won't get noted as a binding set).
+ //
+
+ status = RipInsertLocalNetwork(
+ Binding->ConfiguredNetworkNumber,
+ Binding->NicId,
+ Binding->Adapter->NdisBindingHandle,
+ (USHORT)((839 + Binding->Adapter->MediumSpeed) / Binding->Adapter->MediumSpeed));
+
+ if ((status == STATUS_SUCCESS) ||
+ (status == STATUS_DUPLICATE_NAME)) {
+
+ Binding->LocalAddress.NetworkAddress = Binding->ConfiguredNetworkNumber;
+ }
+ }
+
+ //
+ // These are a union with the InitialLinkage fields.
+ //
+
+ Binding->NextBinding = NULL;
+ Binding->CurrentSendBinding = NULL;
+
+ Adapter = Binding->Adapter;
+
+ if (Adapter->MacInfo.MediumAsync) {
+ CTEAssert (Adapter->FirstWanNicId == BindingIndex);
+ BindingIndex += Adapter->WanNicIdCount;
+ } else {
+ ++BindingIndex;
+ }
+ }
+
+ CTEAssert (BindingIndex == BindingCount+1);
+
+ Device->Bindings = BindingArray;
+ Device->BindingCount = BindingCount;
+
+
+ //
+ // Queue a request to discover our locally attached
+ // adapter addresses. This must succeed because we
+ // just allocated our send packet pool. We need
+ // to wait for this, either because we are
+ // auto-detecting or because we need to determine
+ // if there are multiple cards on the same network.
+ //
+
+ KeInitializeEvent(
+ &Device->AutoDetectEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ Device->AutoDetectState = AUTO_DETECT_STATE_RUNNING;
+
+ //
+ // Make this 0; after we are done waiting, which means
+ // the packet has been completed, we set it to the
+ // correct value.
+ //
+
+ Device->IncludedHeaderOffset = 0;
+
+ IPX_BEGIN_SYNC (&SyncContext);
+ status = RipQueueRequest (0xffffffff, RIP_REQUEST);
+ IPX_END_SYNC (&SyncContext);
+
+ CTEAssert (status == STATUS_PENDING);
+
+ //
+ // This is set when this rip send completes.
+ //
+
+ IPX_DEBUG (AUTO_DETECT, ("Waiting for AutoDetectEvent\n"));
+
+ KeWaitForSingleObject(
+ &Device->AutoDetectEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ Device->AutoDetectState = AUTO_DETECT_STATE_PROCESSING;
+
+ //
+ // Now that we are done receiving responses, insert the
+ // current network number for every auto-detect binding
+ // to the rip database.
+ //
+
+ for (i = 1; i <= Device->BindingCount; i++) {
+
+ Binding = Device->Bindings[i];
+
+ //
+ // Skip empty WAN slots or bindings that were configured
+ // for a certain network number, we inserted those above.
+ // If no network number was detected, also skip it.
+ //
+
+ if ((!Binding) ||
+ (Binding->ConfiguredNetworkNumber != 0) ||
+ (Binding->TentativeNetworkAddress == 0)) {
+
+ continue;
+ }
+
+ IPX_DEBUG (AUTO_DETECT, ("Final score for %lx on %lx is %d - %d\n",
+ REORDER_ULONG(Binding->TentativeNetworkAddress),
+ Binding,
+ Binding->MatchingResponses,
+ Binding->NonMatchingResponses));
+
+ //
+ // We don't care about the status.
+ //
+
+ status = RipInsertLocalNetwork(
+ Binding->TentativeNetworkAddress,
+ Binding->NicId,
+ Binding->Adapter->NdisBindingHandle,
+ (USHORT)((839 + Binding->MediumSpeed) / Binding->MediumSpeed));
+
+ if ((status != STATUS_SUCCESS) &&
+ (status != STATUS_DUPLICATE_NAME)) {
+
+ //
+ // We failed to insert, keep it at zero, hopefully
+ // we will be able to update later.
+ //
+
+#if DBG
+ DbgPrint ("IPX: Could not insert net %lx for binding %lx\n",
+ REORDER_ULONG(Binding->LocalAddress.NetworkAddress),
+ Binding);
+#endif
+ CTEAssert (Binding->LocalAddress.NetworkAddress == 0);
+
+ } else {
+
+ Binding->LocalAddress.NetworkAddress = Binding->TentativeNetworkAddress;
+ }
+
+ }
+
+ ValidBindings = Device->BindingCount;
+
+ if (Device->AutoDetect) {
+
+ ValidBindings = IpxResolveAutoDetect (Device, ValidBindings, RegistryPath);
+
+ }
+
+ Device->ValidBindings = ValidBindings;
+
+ //
+ // Now see if any bindings are actually on the same
+ // network. This sets Device->HighestExternalNicId
+ // and Device->HighestType20NicId.
+ //
+
+ IpxResolveBindingSets (Device, ValidBindings);
+
+
+ //
+ // For multiple adapters, use the offset of the first...why not.
+ //
+
+#if 0
+ Device->IncludedHeaderOffset = Device->Bindings[1]->DefHeaderSize;
+#endif
+
+ Device->IncludedHeaderOffset = MAC_HEADER_SIZE;
+
+ //
+ // Success; see if there is a virtual network configured.
+ //
+
+ if (Device->VirtualNetworkNumber != 0) {
+
+ status = RipInsertLocalNetwork(
+ Device->VirtualNetworkNumber,
+ 0, // NIC ID
+ Device->Bindings[1]->Adapter->NdisBindingHandle,
+ 1);
+
+ if (status != STATUS_SUCCESS) {
+
+ //
+ // Log the appropriate error, then ignore the
+ // virtual network. If the error was
+ // INSUFFICIENT_RESOURCES, the RIP module
+ // will have already logged an error.
+ //
+
+ if (status == STATUS_DUPLICATE_NAME) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Ignoring virtual network %lx, conflict\n", REORDER_ULONG (Device->VirtualNetworkNumber)));
+
+ IpxWriteResourceErrorLog(
+ Device->DeviceObject,
+ EVENT_IPX_INTERNAL_NET_INVALID,
+ 0,
+ REORDER_ULONG (Device->VirtualNetworkNumber));
+ }
+
+ Device->VirtualNetworkNumber = 0;
+ goto NoVirtualNetwork;
+
+ }
+
+ Device->VirtualNetwork = TRUE;
+ Device->MultiCardZeroVirtual = FALSE;
+ RtlCopyMemory(Device->SourceAddress.NodeAddress, VirtualNode, 6);
+ Device->SourceAddress.NetworkAddress = Device->VirtualNetworkNumber;
+
+ //
+ // This will get set to FALSE if RIP binds.
+ //
+
+ Device->RipResponder = TRUE;
+
+ } else {
+
+NoVirtualNetwork:
+
+ Device->VirtualNetwork = FALSE;
+
+ //
+ // See if we need to be set up for the fake
+ // virtual network.
+ //
+
+ if (ValidBindings > 1) {
+
+ CTEAssert (Device->VirtualNetworkOptional);
+
+ //
+ // In this case we return as our local node the
+ // address of the first card. We will also only
+ // direct SAP sends to that card.
+ //
+
+ Device->MultiCardZeroVirtual = TRUE;
+
+ } else {
+
+ Device->MultiCardZeroVirtual = FALSE;
+ }
+
+ RtlCopyMemory(&Device->SourceAddress, &Device->Bindings[1]->LocalAddress, FIELD_OFFSET(TDI_ADDRESS_IPX,Socket));
+
+ }
+
+
+ //
+ // Now get SapNicCount -- regular adapters are counted
+ // as one, but all the WAN lines together only count for one.
+ // We also calculate FirstLanNicId and FirstWanNicId here.
+ //
+
+ CountedWan = FALSE;
+ Device->SapNicCount = 0;
+
+ Device->FirstLanNicId = (USHORT)-1;
+ Device->FirstWanNicId = (USHORT)-1;
+
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+
+ if (Device->Bindings[i]) {
+
+ if (Device->Bindings[i]->Adapter->MacInfo.MediumAsync) {
+
+ if (Device->FirstWanNicId == (USHORT)-1) {
+ Device->FirstWanNicId = i;
+ }
+
+ if (CountedWan) {
+ continue;
+ } else {
+ CountedWan = TRUE;
+ }
+
+ } else {
+
+ if (Device->FirstLanNicId == (USHORT)-1) {
+ Device->FirstLanNicId = i;
+ }
+
+ }
+
+ } else {
+
+ //
+ // NULL bindings are WANs and are not the first one,
+ // so don't count them.
+ //
+
+ CTEAssert (Device->FirstWanNicId != -1);
+ CTEAssert (CountedWan);
+ continue;
+ }
+
+ ++Device->SapNicCount;
+
+ }
+ }
+
+ if (Device->FirstLanNicId == (USHORT)-1) {
+ Device->FirstLanNicId = 1;
+ }
+ if (Device->FirstWanNicId == (USHORT)-1) {
+ Device->FirstWanNicId = 1;
+ }
+
+
+ //
+ // Calculate some values based on all the bindings.
+ //
+
+ MaxLookahead = Device->Bindings[1]->MaxLookaheadData; // largest binding value
+ AnnouncedMaxDatagram = Device->Bindings[1]->AnnouncedMaxDatagramSize; // smallest binding value
+ RealMaxDatagram = Device->Bindings[1]->RealMaxDatagramSize; // smallest binding value
+
+ if (Device->Bindings[1]->LineUp) {
+ LinkSpeed = Device->Bindings[1]->MediumSpeed; // smallest binding value
+ } else {
+ LinkSpeed = 0xffffffff;
+ }
+ MacOptions = Device->Bindings[1]->Adapter->MacInfo.MacOptions; // AND of binding values
+
+ for (i = 2; i <= ValidBindings; i++) {
+
+ Binding = Device->Bindings[i];
+
+ if (!Binding) {
+ continue;
+ }
+
+ if (Binding->MaxLookaheadData > MaxLookahead) {
+ MaxLookahead = Binding->MaxLookaheadData;
+ }
+ if (Binding->AnnouncedMaxDatagramSize < AnnouncedMaxDatagram) {
+ AnnouncedMaxDatagram = Binding->AnnouncedMaxDatagramSize;
+ }
+ if (Binding->RealMaxDatagramSize < RealMaxDatagram) {
+ RealMaxDatagram = Binding->RealMaxDatagramSize;
+ }
+
+ if (Binding->LineUp && (Binding->MediumSpeed < LinkSpeed)) {
+ LinkSpeed = Binding->MediumSpeed;
+ }
+ MacOptions &= Binding->Adapter->MacInfo.MacOptions;
+
+ }
+
+ Device->Information.MaxDatagramSize = AnnouncedMaxDatagram;
+ Device->RealMaxDatagramSize = RealMaxDatagram;
+ Device->Information.MaximumLookaheadData = MaxLookahead;
+
+ //
+ // If we couldn't find anything better, use the speed from
+ // the first binding.
+ //
+
+ if (LinkSpeed == 0xffffffff) {
+ Device->LinkSpeed = Device->Bindings[1]->MediumSpeed;
+ } else {
+ Device->LinkSpeed = LinkSpeed;
+ }
+ Device->MacOptions = MacOptions;
+
+ Device->State = DEVICE_STATE_OPEN;
+ Device->AutoDetectState = AUTO_DETECT_STATE_DONE;
+
+ IPX_DEBUG (DEVICE, ("Node is %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x, ",
+ Device->SourceAddress.NodeAddress[0], Device->SourceAddress.NodeAddress[1],
+ Device->SourceAddress.NodeAddress[2], Device->SourceAddress.NodeAddress[3],
+ Device->SourceAddress.NodeAddress[4], Device->SourceAddress.NodeAddress[5]));
+ IPX_DEBUG (DEVICE, ("Network is %lx\n",
+ REORDER_ULONG (Device->SourceAddress.NetworkAddress)));
+
+
+ //
+ // Start the timer which updates the RIP database
+ // periodically. For the first one we do a ten
+ // second timeout (hopefully this is enough time
+ // for RIP to start if it is going to).
+ //
+
+ IpxReferenceDevice (Device, DREF_LONG_TIMER);
+
+ CTEStartTimer(
+ &Device->RipLongTimer,
+ 10000,
+ RipLongTimeout,
+ (PVOID)Device);
+
+ //
+ // We use this event when unloading to signal that we
+ // can proceed...initialize it here so we know it is
+ // ready to go when unload is called.
+ //
+
+ KeInitializeEvent(
+ &IpxDevice->UnloadEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ }
+
+InitFailed:
+
+ if (SuccessfulOpens == 0) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_NO_ADAPTERS,
+ 802,
+ STATUS_DEVICE_DOES_NOT_EXIST,
+ NULL,
+ 0,
+ NULL);
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+
+ } else {
+
+ return STATUS_SUCCESS;
+ }
+
+#else // _PNP_POWER
+{
+ PBIND_ARRAY_ELEM BindingArray;
+ PTA_ADDRESS TdiRegistrationAddress;
+
+ //
+ // Pre-allocate the binding array
+ // Later, we will allocate the LAN/WAN and SLAVE bindings separately
+ // [BUGBUGZZ] Read the array size from registry?
+ //
+ BindingArray = (PBIND_ARRAY_ELEM)IpxAllocateMemory (
+ MAX_BINDINGS * sizeof(BIND_ARRAY_ELEM),
+ MEMORY_BINDING,
+ "Binding array");
+
+ if (BindingArray == NULL) {
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_NO_ADAPTERS,
+ 802,
+ STATUS_DEVICE_DOES_NOT_EXIST,
+ NULL,
+ 0,
+ NULL);
+ IpxDereferenceDevice (Device, DREF_CREATE);
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ }
+
+ Device->MaxBindings = MAX_BINDINGS;
+
+ //
+ // Allocate the TA_ADDRESS structure - this will be used in all TdiRegisterNetAddress
+ // notifications.
+ //
+ TdiRegistrationAddress = (PTA_ADDRESS)IpxAllocateMemory (
+ (2 * sizeof(USHORT) + sizeof(TDI_ADDRESS_IPX)),
+ MEMORY_ADDRESS,
+ "Tdi Address");
+
+ if (TdiRegistrationAddress == NULL) {
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_NO_ADAPTERS,
+ 802,
+ STATUS_DEVICE_DOES_NOT_EXIST,
+ NULL,
+ 0,
+ NULL);
+ IpxFreeMemory(BindingArray, sizeof(BindingArray), MEMORY_BINDING, "Binding Array");
+ IpxDereferenceDevice (Device, DREF_CREATE);
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ }
+
+ RtlZeroMemory (BindingArray, MAX_BINDINGS * sizeof(BIND_ARRAY_ELEM));
+ RtlZeroMemory (TdiRegistrationAddress, 2 * sizeof(USHORT) + sizeof(TDI_ADDRESS_IPX));
+
+ Device->Bindings = BindingArray;
+
+ TdiRegistrationAddress->AddressLength = sizeof(TDI_ADDRESS_IPX);
+ TdiRegistrationAddress->AddressType = TDI_ADDRESS_TYPE_IPX;
+
+ //
+ // Store the pointer in the Device.
+ //
+ Device->TdiRegistrationAddress = TdiRegistrationAddress;
+
+ //
+ // Device state is loaded, but not opened. It is opened when at least
+ // one adapter has appeared.
+ //
+ Device->State = DEVICE_STATE_LOADED;
+
+ Device->FirstLanNicId = Device->FirstWanNicId = (USHORT)1; // will be changed later
+
+ IpxFreeConfiguration(Config);
+
+ //
+ // We use this event when unloading to signal that we
+ // can proceed...initialize it here so we know it is
+ // ready to go when unload is called.
+ //
+
+ KeInitializeEvent(
+ &IpxDevice->UnloadEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ return STATUS_SUCCESS;
+}
+#endif // _PNP_POWER
+} /* DriverEntry */
+
+
+ULONG
+IpxResolveAutoDetect(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings,
+#ifdef _PNP_POWER
+ IN CTELockHandle *LockHandle1,
+#endif
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called for auto-detect bindings to
+ remove any bindings that were not successfully found.
+ It also updates "DefaultAutoDetectType" in the registry
+ if needed.
+
+Arguments:
+
+ Device - The IPX device object.
+
+ ValidBindings - The total number of bindings present.
+
+ RegistryPath - The path to the ipx registry, used if we have
+ to write a value back.
+
+Return Value:
+
+ The updated number of bindings.
+
+--*/
+
+{
+ PBINDING Binding, TmpBinding;
+ UINT i, j;
+
+ //
+ // Get rid of any auto-detect devices which we
+ // could not find nets for. We also remove any
+ // devices which are not the first ones
+ // auto-detected on a particular adapter.
+ //
+
+ for (i = 1; i <= ValidBindings; i++) {
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+
+ if (!Binding) {
+ continue;
+ }
+
+ //
+ // If this was auto-detected and was not the default,
+ // or it was the default, but nothing was detected for
+ // it *and* something else *was* detected (which means
+ // we will use that frame type when we get to it),
+ // we may need to remove this binding.
+ //
+
+ if (Binding->AutoDetect &&
+ (!Binding->DefaultAutoDetect ||
+ (Binding->DefaultAutoDetect &&
+ (Binding->LocalAddress.NetworkAddress == 0) &&
+ Binding->Adapter->AutoDetectResponse))) {
+
+ if ((Binding->LocalAddress.NetworkAddress == 0) ||
+ (Binding->Adapter->AutoDetectFound)) {
+
+ //
+ // Remove this binding.
+ //
+
+ if (Binding->LocalAddress.NetworkAddress == 0) {
+ IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) no net found\n",
+ i, Binding->FrameType));
+ } else {
+ IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) adapter already auto-detected\n",
+ i, Binding->FrameType));
+ }
+
+ CTEAssert (Binding->NicId == i);
+ CTEAssert (!Binding->Adapter->MacInfo.MediumAsync);
+
+ //
+ // Remove any routes through this NIC, and
+ // adjust any NIC ID's above this one in the
+ // database down by one.
+ //
+
+ RipAdjustForBindingChange (Binding->NicId, 0, IpxBindingDeleted);
+
+ Binding->Adapter->Bindings[Binding->FrameType] = NULL;
+ for (j = i+1; j <= ValidBindings; j++) {
+#ifndef _PNP_POWER
+ TmpBinding = Device->Bindings[j];
+ Device->Bindings[j-1] = TmpBinding;
+#else
+ TmpBinding = NIC_ID_TO_BINDING(Device, j);
+ INSERT_BINDING(Device, j-1, TmpBinding);
+#endif _PNP_POWER
+ if (TmpBinding) {
+ if ((TmpBinding->Adapter->MacInfo.MediumAsync) &&
+ (TmpBinding->Adapter->FirstWanNicId == TmpBinding->NicId)) {
+ --TmpBinding->Adapter->FirstWanNicId;
+ --TmpBinding->Adapter->LastWanNicId;
+ }
+ --TmpBinding->NicId;
+ }
+ }
+#ifdef _PNP_POWER
+ INSERT_BINDING(Device, ValidBindings, NULL);
+#else
+ Device->Bindings[ValidBindings] = NULL;
+#endif
+ --Binding->Adapter->BindingCount;
+ --ValidBindings;
+
+ --i; // so we check the binding that was just moved.
+
+ //
+ // Wait 100 ms before freeing the binding,
+ // in case an indication is using it.
+ //
+
+ KeStallExecutionProcessor(100000);
+
+ IpxDestroyBinding (Binding);
+
+ } else {
+
+ IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) auto-detected OK\n",
+ i, Binding->FrameType));
+
+#if DBG
+ DbgPrint ("IPX: Auto-detected non-default frame type %s, net %lx\n",
+ OutputFrameType(Binding),
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+#endif
+
+ //
+ // Save it in the registry for the next boot.
+ //
+#ifdef _PNP_POWER
+//
+// This cannot be done at DPC, so, drop the IRQL
+//
+ IPX_FREE_LOCK1(&Device->BindAccessLock, *LockHandle1);
+ IpxWriteDefaultAutoDetectType(
+ RegistryPath,
+ Binding->Adapter,
+ Binding->FrameType);
+ IPX_GET_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ IpxWriteDefaultAutoDetectType(
+ RegistryPath,
+ Binding->Adapter,
+ Binding->FrameType);
+#endif
+
+ Binding->Adapter->AutoDetectFound = TRUE;
+ }
+
+ } else {
+
+ if (Binding->AutoDetect) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) auto-detect default\n",
+ i, Binding->FrameType));
+
+#if DBG
+ if (Binding->LocalAddress.NetworkAddress != 0) {
+ DbgPrint ("IPX: Auto-detected default frame type %s, net %lx\n",
+ OutputFrameType(Binding),
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+ } else {
+ DbgPrint ("IPX: Using default auto-detect frame type %s\n",
+ OutputFrameType(Binding));
+ }
+#endif
+
+ Binding->Adapter->AutoDetectFound = TRUE;
+
+ } else {
+
+ IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) not auto-detected\n",
+ i, Binding->FrameType));
+ }
+
+ }
+
+ }
+
+
+ for (i = 1; i <= ValidBindings; i++) {
+#ifdef _PNP_POWER
+ if (Binding = NIC_ID_TO_BINDING(Device, i)) {
+#else
+ if (Binding = Device->Bindings[i]) {
+#endif
+ CTEAssert (Binding->NicId == i);
+ IPX_DEBUG (AUTO_DETECT, ("Binding %lx, type %d, auto %d\n",
+ Binding, Binding->FrameType, Binding->AutoDetect));
+ }
+
+ }
+
+ return ValidBindings;
+
+} /* IpxResolveAutoDetect */
+
+
+VOID
+IpxResolveBindingSets(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to determine if we have any
+ binding sets and rearrange the bindings the way we
+ like. The order is as follows:
+
+ - First comes the first binding to each LAN network
+ - Following that are all WAN bindings
+ - Following that are any duplicate bindings to LAN networks
+ (the others in the "binding set").
+
+ If "global wan net" is true we will advertise up to
+ and including the first wan binding as the highest nic
+ id; otherwise we advertise up to and including the last
+ wan binding. In all cases the duplicate bindings are
+ hidden.
+
+Arguments:
+
+ Device - The IPX device object.
+
+ ValidBindings - The total number of bindings present.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PBINDING Binding, MasterBinding, TmpBinding;
+ UINT i, j;
+ ULONG WanCount, DuplicateCount;
+
+ //
+ // First loop through and push all the wan bindings
+ // to the end.
+ //
+#ifdef _PNP_POWER
+
+ WanCount = Device->HighestExternalNicId - Device->HighestLanNicId;
+
+#else
+
+ WanCount = 0;
+
+ //
+ // For PnP, we dont do this as the bindings are in order
+ // at the time of insertion
+ //
+ for (i = 1; i <= (ValidBindings-WanCount); ) {
+
+ Binding = Device->Bindings[i];
+
+ if ((Binding == NULL) || Binding->Adapter->MacInfo.MediumAsync) {
+
+ //
+ // Put this binding at the end, and slide all the
+ // others down. If it is a NULL WAN binding then we
+ // don't have to do some of this.
+ //
+
+#if DBG
+ //
+ // Any non-NULL bindings should be correct in this
+ // respect at any point.
+ //
+
+ if (Binding != NULL) {
+ CTEAssert (Binding->NicId == i);
+ }
+#endif
+
+ //
+ // If the Binding is NULL we won't have anything in the
+ // database at this binding, but we still need to adjust
+ // any NIC ID's in the database which are above this.
+ //
+
+ RipAdjustForBindingChange ((USHORT)i, (USHORT)ValidBindings, IpxBindingMoved);
+
+ //
+ // Slide the bindings above this down.
+ //
+
+ for (j = i+1; j <= ValidBindings; j++) {
+ TmpBinding = Device->Bindings[j];
+ Device->Bindings[j-1] = TmpBinding;
+ if (TmpBinding) {
+ if ((TmpBinding->Adapter->MacInfo.MediumAsync) &&
+ (TmpBinding->Adapter->FirstWanNicId == TmpBinding->NicId)) {
+ --TmpBinding->Adapter->FirstWanNicId;
+ --TmpBinding->Adapter->LastWanNicId;
+ }
+ --TmpBinding->NicId;
+ }
+ }
+
+ //
+ // Put this binding at the end.
+ //
+
+ Device->Bindings[ValidBindings] = Binding;
+ if (Binding != NULL) {
+ if ((Binding->Adapter->MacInfo.MediumAsync) &&
+ (Binding->Adapter->FirstWanNicId == Binding->NicId)) {
+ Binding->Adapter->FirstWanNicId = (USHORT)ValidBindings;
+ Binding->Adapter->LastWanNicId += (USHORT)(ValidBindings - Binding->NicId);
+ }
+ Binding->NicId = (USHORT)ValidBindings;
+ }
+ ++WanCount;
+
+ //
+ // Keep i the same, to check the new binding at
+ // this position.
+ //
+
+ } else {
+
+ i++;
+
+ }
+
+ }
+#endif _PNP_POWER
+ //
+ // Now go through and find the LAN duplicates and
+ // create binding sets from them.
+ //
+
+ DuplicateCount = 0;
+
+ for (i = 1; i <= (ValidBindings-(WanCount+DuplicateCount)); ) {
+
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ CTEAssert (Binding != NULL); // because we are only looking at LAN bindings
+
+ CTEAssert (!Binding->Adapter->MacInfo.MediumAsync);
+
+ if (Binding->LocalAddress.NetworkAddress == 0) {
+ i++;
+ continue;
+ }
+
+ //
+ // See if any previous bindings match the
+ // frame type, medium type, and number of
+ // this network (for the moment we match on
+ // frame type and medium type too so that we
+ // don't have to worry about different frame
+ // formats and header offsets within a set).
+ //
+
+ for (j = 1; j < i; j++) {
+#ifdef _PNP_POWER
+ MasterBinding = NIC_ID_TO_BINDING(Device, j);
+#else
+ MasterBinding = Device->Bindings[j];
+#endif
+ if ((MasterBinding->LocalAddress.NetworkAddress == Binding->LocalAddress.NetworkAddress) &&
+ (MasterBinding->FrameType == Binding->FrameType) &&
+ (MasterBinding->Adapter->MacInfo.MediumType == Binding->Adapter->MacInfo.MediumType)) {
+ break;
+ }
+
+ }
+
+ if (j == i) {
+ i++;
+ continue;
+ }
+
+ //
+ // We have a duplicate. First slide it down to the
+ // end. Note that we change any router entries that
+ // use our real NicId to use the real NicId of the
+ // master (there should be no entries in the rip
+ // database that have the NicId of a binding slave).
+ //
+
+ RipAdjustForBindingChange (Binding->NicId, MasterBinding->NicId, IpxBindingMoved);
+
+ for (j = i+1; j <= ValidBindings; j++) {
+#ifdef _PNP_POWER
+ TmpBinding = NIC_ID_TO_BINDING(Device, j);
+ INSERT_BINDING(Device, j-1, TmpBinding);
+#else
+ TmpBinding = Device->Bindings[j];
+ Device->Bindings[j-1] = TmpBinding;
+#endif
+ if (TmpBinding) {
+ if ((TmpBinding->Adapter->MacInfo.MediumAsync) &&
+ (TmpBinding->Adapter->FirstWanNicId == TmpBinding->NicId)) {
+ --TmpBinding->Adapter->FirstWanNicId;
+ --TmpBinding->Adapter->LastWanNicId;
+ }
+ --TmpBinding->NicId;
+ }
+ }
+#ifdef _PNP_POWER
+ INSERT_BINDING(Device, ValidBindings, Binding);
+#else
+ Device->Bindings[ValidBindings] = Binding;
+#endif
+
+ Binding->NicId = (USHORT)ValidBindings;
+ ++DuplicateCount;
+
+ //
+ // Now make MasterBinding the head of a binding set.
+ //
+
+ if (MasterBinding->BindingSetMember) {
+
+ //
+ // Just insert ourselves in the chain.
+ //
+
+#if DBG
+ DbgPrint ("IPX: %lx is also on network %lx\n",
+ Binding->Adapter->AdapterName,
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+#endif
+ IPX_DEBUG (AUTO_DETECT, ("Add %lx to binding set of %lx\n", Binding, MasterBinding));
+
+ CTEAssert (MasterBinding->CurrentSendBinding);
+ Binding->NextBinding = MasterBinding->NextBinding;
+
+ } else {
+
+ //
+ // Start the chain with the two bindings in it.
+ //
+
+#if DBG
+ DbgPrint ("IPX: %lx and %lx are on the same network %lx, will load balance\n",
+ MasterBinding->Adapter->AdapterName, Binding->Adapter->AdapterName,
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+#endif
+ IPX_DEBUG (AUTO_DETECT, ("Create new %lx in binding set of %lx\n", Binding, MasterBinding));
+
+ MasterBinding->BindingSetMember = TRUE;
+ MasterBinding->CurrentSendBinding = MasterBinding;
+ MasterBinding->MasterBinding = MasterBinding;
+ Binding->NextBinding = MasterBinding;
+
+ }
+
+ MasterBinding->NextBinding = Binding;
+ Binding->BindingSetMember = TRUE;
+ Binding->ReceiveBroadcast = FALSE;
+ Binding->CurrentSendBinding = NULL;
+ Binding->MasterBinding = MasterBinding;
+
+ //
+ // Since the master binding looks like all members of
+ // the binding set to people querying from above, we have
+ // to make it the worst-case of all the elements. Generally
+ // these will be equal since the frame type and media is
+ // the same.
+ //
+
+ if (Binding->MaxLookaheadData > MasterBinding->MaxLookaheadData) {
+ MasterBinding->MaxLookaheadData = Binding->MaxLookaheadData;
+ }
+ if (Binding->AnnouncedMaxDatagramSize < MasterBinding->AnnouncedMaxDatagramSize) {
+ MasterBinding->AnnouncedMaxDatagramSize = Binding->AnnouncedMaxDatagramSize;
+ }
+ if (Binding->RealMaxDatagramSize < MasterBinding->RealMaxDatagramSize) {
+ MasterBinding->RealMaxDatagramSize = Binding->RealMaxDatagramSize;
+ }
+ if (Binding->MediumSpeed < MasterBinding->MediumSpeed) {
+ MasterBinding->MediumSpeed = Binding->MediumSpeed;
+ }
+
+ //
+ // Keep i the same, to check the new binding at
+ // this position.
+ //
+
+ }
+#ifndef _PNP_POWER
+ Device->HighestExternalNicId = (USHORT)(ValidBindings - DuplicateCount);
+ Device->HighestType20NicId = (USHORT)(ValidBindings-(WanCount+DuplicateCount));
+#else
+ Device->HighestLanNicId -= (USHORT)DuplicateCount;
+
+ if (Device->HighestLanNicId == 0) {
+ CTEAssert(FALSE);
+ }
+
+ Device->HighestExternalNicId -= (USHORT)DuplicateCount;
+ Device->HighestType20NicId -= (USHORT)DuplicateCount;
+ Device->SapNicCount -= (USHORT)DuplicateCount;
+#endif _PNP_POWER
+} /* IpxResolveBindingSets */
+
+
+NTSTATUS
+IpxBindToAdapter(
+ IN PDEVICE Device,
+ IN PBINDING_CONFIG ConfigBinding,
+#ifdef _PNP_POWER
+ IN PADAPTER *AdapterPtr,
+#endif
+ IN ULONG FrameTypeIndex
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles binding the transport to a new
+ adapter. It can be called at any point during the life
+ of the transport.
+
+Arguments:
+
+ Device - The IPX device object.
+
+ ConfigBinding - The configuration info for this binding.
+
+ AdapterPtr - pointer to the adapter to bind to in case of PnP.
+
+ FrameTypeIndex - The index into ConfigBinding's array of frame
+ types for this adapter. The routine is called once for
+ every valid frame type.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ NTSTATUS status;
+
+#ifndef _PNP_POWER
+ //
+ // Adapter came in as a parameter
+ //
+ PADAPTER Adapter = NULL;
+#else
+ PADAPTER Adapter = *AdapterPtr;
+#endif
+
+ PBINDING Binding, OldBinding;
+ ULONG FrameType, MappedFrameType;
+ PLIST_ENTRY p;
+
+ //
+ // We can't bind more than one adapter unless we have a
+ // virtual network configured or we are allowed to run
+ // with a virtual network of 0.
+ //
+
+ if (Device->BindingCount == 1) {
+ if ((Device->VirtualNetworkNumber == 0) &&
+ (!Device->VirtualNetworkOptional)) {
+
+ IPX_DEBUG (ADAPTER, ("Cannot bind to more than one adapter\n"));
+ DbgPrint ("IPX: Disallowing multiple bind ==> VirtualNetwork is 0\n");
+ IpxWriteGeneralErrorLog(
+ Device->DeviceObject,
+ EVENT_TRANSPORT_BINDING_FAILED,
+ 666,
+ STATUS_NOT_SUPPORTED,
+ ConfigBinding->AdapterName.Buffer,
+ 0,
+ NULL);
+
+ return STATUS_NOT_SUPPORTED;
+ }
+ }
+
+
+ //
+ // First allocate the memory for the binding.
+ //
+
+ status = IpxCreateBinding(
+ Device,
+ ConfigBinding,
+ FrameTypeIndex,
+ ConfigBinding->AdapterName.Buffer,
+ &Binding);
+
+ if (status != STATUS_SUCCESS) {
+ return status;
+ }
+
+ FrameType = ConfigBinding->FrameType[FrameTypeIndex];
+
+//
+// In PnP case, we dont need to check for existing adapters since
+// we supply a NULL adapter in the parameters if it needs to be created
+//
+#ifndef _PNP_POWER
+
+ //
+ // Check if there is already an NDIS binding to this adapter,
+ // and if so, that there is not already a binding with this
+ // frame type.
+ //
+
+
+ for (p = Device->InitialBindingList.Flink;
+ p != &Device->InitialBindingList;
+ p = p->Flink) {
+
+ OldBinding = CONTAINING_RECORD (p, BINDING, InitialLinkage);
+
+ if (RtlEqualMemory(
+ OldBinding->Adapter->AdapterName,
+ ConfigBinding->AdapterName.Buffer,
+ OldBinding->Adapter->AdapterNameLength)) {
+
+ Adapter = OldBinding->Adapter;
+
+ MacMapFrameType(
+ Adapter->MacInfo.RealMediumType,
+ FrameType,
+ &MappedFrameType);
+
+ if (Adapter->Bindings[MappedFrameType] != NULL) {
+
+ IPX_DEBUG (ADAPTER, ("Bind to adapter %ws, type %d exists\n",
+ Adapter->AdapterName,
+ MappedFrameType));
+
+ //
+ // If this was the auto-detect default for this
+ // adapter and it failed, we need to make the
+ // previous one the default, so that at least
+ // one binding will stick around.
+ //
+
+ if (ConfigBinding->DefaultAutoDetect[FrameTypeIndex]) {
+ IPX_DEBUG (ADAPTER, ("Default auto-detect changed from %d to %d\n",
+ FrameType, MappedFrameType));
+ Adapter->Bindings[MappedFrameType]->DefaultAutoDetect = TRUE;
+ }
+
+ IpxDestroyBinding (Binding);
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ IPX_DEBUG (ADAPTER, ("Using existing bind to adapter %ws, type %d\n",
+ Adapter->AdapterName,
+ MappedFrameType));
+ break;
+
+ }
+ }
+#endif _PNP_POWER
+
+ if (Adapter == NULL) {
+
+ //
+ // No binding to this adapter exists, so create a
+ // new one.
+ //
+
+ status = IpxCreateAdapter(
+ Device,
+ &ConfigBinding->AdapterName,
+ &Adapter);
+
+ if (status != STATUS_SUCCESS) {
+ IpxDestroyBinding(Binding);
+ return status;
+ }
+
+ //
+ // Save these now (they will be the same for all bindings
+ // on this adapter).
+ //
+
+ Adapter->ConfigMaxPacketSize = ConfigBinding->Parameters[BINDING_MAX_PKT_SIZE];
+ Adapter->SourceRouting = (BOOLEAN)ConfigBinding->Parameters[BINDING_SOURCE_ROUTE];
+ Adapter->EnableFunctionalAddress = (BOOLEAN)ConfigBinding->Parameters[BINDING_ENABLE_FUNC_ADDR];
+ Adapter->EnableWanRouter = (BOOLEAN)ConfigBinding->Parameters[BINDING_ENABLE_WAN];
+
+ Adapter->BindSap = (USHORT)ConfigBinding->Parameters[BINDING_BIND_SAP];
+ Adapter->BindSapNetworkOrder = REORDER_USHORT(Adapter->BindSap);
+ CTEAssert (Adapter->BindSap == 0x8137);
+ CTEAssert (Adapter->BindSapNetworkOrder == 0x3781);
+
+ //
+ // Now fire up NDIS so this adapter talks
+ //
+
+ status = IpxInitializeNdis(
+ Adapter,
+ ConfigBinding);
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // Log an error.
+ //
+
+ IpxWriteGeneralErrorLog(
+ Device->DeviceObject,
+ EVENT_TRANSPORT_BINDING_FAILED,
+ 601,
+ status,
+ ConfigBinding->AdapterName.Buffer,
+ 0,
+ NULL);
+
+ IpxDestroyAdapter (Adapter);
+ IpxDestroyBinding (Binding);
+
+ //
+ // Returning this status informs the caller to not
+ // try any more frame types on this adapter.
+ //
+
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+
+ }
+
+ //
+ // For 802.5 bindings we need to start the source routing
+ // timer to time out old entries.
+ //
+
+ if ((Adapter->MacInfo.MediumType == NdisMedium802_5) &&
+ (Adapter->SourceRouting)) {
+
+ if (!Device->SourceRoutingUsed) {
+
+ Device->SourceRoutingUsed = TRUE;
+ IpxReferenceDevice (Device, DREF_SR_TIMER);
+
+ CTEStartTimer(
+ &Device->SourceRoutingTimer,
+ 60000, // one minute timeout
+ MacSourceRoutingTimeout,
+ (PVOID)Device);
+ }
+ }
+
+ MacMapFrameType(
+ Adapter->MacInfo.RealMediumType,
+ FrameType,
+ &MappedFrameType);
+
+ IPX_DEBUG (ADAPTER, ("Create new bind to adapter %ws, type %d\n",
+ ConfigBinding->AdapterName.Buffer,
+ MappedFrameType));
+
+ IpxAllocateReceiveBufferPool (Adapter);
+
+#ifdef _PNP_POWER
+ *AdapterPtr = Adapter;
+#endif
+ }
+#ifdef _PNP_POWER
+ else {
+ //
+ // get the mapped frame type
+ //
+ MacMapFrameType(
+ Adapter->MacInfo.RealMediumType,
+ FrameType,
+ &MappedFrameType);
+
+ if (Adapter->Bindings[MappedFrameType] != NULL) {
+
+ IPX_DEBUG (ADAPTER, ("Bind to adapter %ws, type %d exists\n",
+ Adapter->AdapterName,
+ MappedFrameType));
+
+ //
+ // If this was the auto-detect default for this
+ // adapter and it failed, we need to make the
+ // previous one the default, so that at least
+ // one binding will stick around.
+ //
+
+ if (ConfigBinding->DefaultAutoDetect[FrameTypeIndex]) {
+ IPX_DEBUG (ADAPTER, ("Default auto-detect changed from %d to %d\n",
+ FrameType, MappedFrameType));
+ Adapter->Bindings[MappedFrameType]->DefaultAutoDetect = TRUE;
+ }
+
+ IpxDestroyBinding (Binding);
+
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ IPX_DEBUG (ADAPTER, ("Using existing bind to adapter %ws, type %d\n",
+ Adapter->AdapterName,
+ MappedFrameType));
+ }
+#endif _PNP_POWER
+
+ //
+ // The local node address starts out the same as the
+ // MAC address of the adapter (on WAN this will change).
+ // The local MAC address can also change for WAN.
+ //
+
+ RtlCopyMemory (Binding->LocalAddress.NodeAddress, Adapter->LocalMacAddress.Address, 6);
+ RtlCopyMemory (Binding->LocalMacAddress.Address, Adapter->LocalMacAddress.Address, 6);
+
+
+ //
+ // Save the send handler.
+ //
+
+ Binding->SendFrameHandler = NULL;
+ Binding->FrameType = MappedFrameType;
+
+ //
+ // BUGBUG: Put this in InitializeBindingInfo.
+ //
+
+ switch (Adapter->MacInfo.RealMediumType) {
+ case NdisMedium802_3:
+ switch (MappedFrameType) {
+ case ISN_FRAME_TYPE_802_3: Binding->SendFrameHandler = IpxSendFrame802_3802_3; break;
+ case ISN_FRAME_TYPE_802_2: Binding->SendFrameHandler = IpxSendFrame802_3802_2; break;
+ case ISN_FRAME_TYPE_ETHERNET_II: Binding->SendFrameHandler = IpxSendFrame802_3EthernetII; break;
+ case ISN_FRAME_TYPE_SNAP: Binding->SendFrameHandler = IpxSendFrame802_3Snap; break;
+ }
+ break;
+ case NdisMedium802_5:
+ switch (MappedFrameType) {
+ case ISN_FRAME_TYPE_802_2: Binding->SendFrameHandler = IpxSendFrame802_5802_2; break;
+ case ISN_FRAME_TYPE_SNAP: Binding->SendFrameHandler = IpxSendFrame802_5Snap; break;
+ }
+ break;
+ case NdisMediumFddi:
+ switch (MappedFrameType) {
+ case ISN_FRAME_TYPE_802_3: Binding->SendFrameHandler = IpxSendFrameFddi802_3; break;
+ case ISN_FRAME_TYPE_802_2: Binding->SendFrameHandler = IpxSendFrameFddi802_2; break;
+ case ISN_FRAME_TYPE_SNAP: Binding->SendFrameHandler = IpxSendFrameFddiSnap; break;
+ }
+ break;
+ case NdisMediumArcnet878_2:
+ switch (MappedFrameType) {
+ case ISN_FRAME_TYPE_802_3: Binding->SendFrameHandler = IpxSendFrameArcnet878_2; break;
+ }
+ break;
+ case NdisMediumWan:
+ switch (MappedFrameType) {
+ case ISN_FRAME_TYPE_ETHERNET_II: Binding->SendFrameHandler = IpxSendFrameWanEthernetII; break;
+ }
+ break;
+ }
+
+ if (Binding->SendFrameHandler == NULL) {
+ DbgPrint ("BUGBUG!: SendFrameHandler is NULL\n");
+ }
+
+ Adapter->Bindings[MappedFrameType] = Binding;
+ ++Adapter->BindingCount;
+
+ Binding->Adapter = Adapter;
+
+#ifndef _PNP_POWER
+ InsertTailList (&Device->InitialBindingList, &Binding->InitialLinkage);
+#endif _PNP_POWER
+
+ //
+ // NicId and ExternalNicId will be filled in later when the binding
+ // is assigned a spot in the Device->Bindings array.
+ //
+
+ //
+ // Initialize the per-binding MAC information
+ //
+
+ if ((Adapter->ConfigMaxPacketSize == 0) ||
+ (Adapter->MaxSendPacketSize < Adapter->ConfigMaxPacketSize)) {
+ Binding->MaxSendPacketSize = Adapter->MaxSendPacketSize;
+ } else {
+ Binding->MaxSendPacketSize = Adapter->ConfigMaxPacketSize;
+ }
+ Binding->MediumSpeed = Adapter->MediumSpeed;
+ if (Adapter->MacInfo.MediumAsync) {
+ Binding->LineUp = FALSE;
+ } else {
+ Binding->LineUp = TRUE;
+ }
+
+ MacInitializeBindingInfo(
+ Binding,
+ Adapter);
+
+ return STATUS_SUCCESS;
+
+} /* IpxBindToAdapter */
+
+
+BOOLEAN
+IpxIsAddressLocal(
+ IN TDI_ADDRESS_IPX UNALIGNED * SourceAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns TRUE if the specified SourceAddress indicates
+ the packet was sent by us, and FALSE otherwise.
+
+Arguments:
+
+ SourceAddress - The source IPX address.
+
+Return Value:
+
+ TRUE if the address is local.
+
+--*/
+
+{
+ PBINDING Binding;
+ UINT i;
+
+ //
+ // First see if it is a virtual network address or not.
+ //
+
+ if (RtlEqualMemory (VirtualNode, SourceAddress->NodeAddress, 6)) {
+
+ //
+ // This is us if we have a virtual network configured.
+ // If we don't have a virtual node, we fall through to the
+ // other check -- an arcnet card configured as node 1 will
+ // have what we think of as the "virtual node" as its
+ // real node address.
+ //
+
+ if ((IpxDevice->VirtualNetwork) &&
+ (IpxDevice->VirtualNetworkNumber == SourceAddress->NetworkAddress)) {
+ return TRUE;
+ }
+
+ }
+
+ //
+ // Check through our list of adapters to see if one of
+ // them is the source node.
+ //
+ {
+ ULONG Index = MIN (IpxDevice->MaxBindings, IpxDevice->ValidBindings);
+
+ for (i = 1; i <= Index; i++) {
+#ifdef _PNP_POWER
+ if (((Binding = NIC_ID_TO_BINDING(IpxDevice, i)) != NULL) &&
+#else
+ if (((Binding = IpxDevice->Bindings[i]) != NULL) &&
+#endif _PNP_POWER
+ (RtlEqualMemory (Binding->LocalAddress.NodeAddress, SourceAddress->NodeAddress, 6))) {
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+
+} /* IpxIsAddressLocal */
+
+
+NTSTATUS
+IpxUnBindFromAdapter(
+ IN PBINDING Binding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles unbinding the transport from an
+ adapter. It can be called at any point during the life
+ of the transport.
+
+Arguments:
+
+ Binding - The adapter to unbind.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ PADAPTER Adapter = Binding->Adapter;
+
+ Adapter->Bindings[Binding->FrameType] = NULL;
+ --Adapter->BindingCount;
+
+ IpxDereferenceBinding (Binding, BREF_BOUND);
+
+ if (Adapter->BindingCount == 0) {
+
+ //
+ // DereferenceAdapter is a NULL macro for load-only.
+ //
+ // BUGBUG: Revisit Post 4.0
+ //
+#ifdef _PNP_LATER
+ //
+ // Take away the creation reference. When the in-use ref is taken off,
+ // we destroy this adapter.
+ //
+ IpxDereferenceAdapter(Adapter);
+#else
+ //
+ // Free the packet pools, etc. and close the
+ // adapter.
+ //
+
+ IpxCloseNdis (Adapter);
+
+ IpxDestroyAdapter (Adapter);
+#endif
+ }
+
+ return STATUS_SUCCESS;
+
+} /* IpxUnBindFromAdapter */
+
+
+VOID
+IpxUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unloads the sample transport driver.
+ It unbinds from any NDIS drivers that are open and frees all resources
+ associated with the transport. The I/O system will not call us until
+ nobody above has IPX open.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ None. When the function returns, the driver is unloaded.
+
+--*/
+
+{
+
+ PBINDING Binding;
+ PREQUEST Request;
+ PLIST_ENTRY p;
+ UINT i;
+
+
+ UNREFERENCED_PARAMETER (DriverObject);
+
+ IpxDevice->State = DEVICE_STATE_STOPPING;
+
+
+ //
+ // Complete any pending address notify requests.
+ //
+
+ while ((p = ExInterlockedRemoveHeadList(
+ &IpxDevice->AddressNotifyQueue,
+ &IpxDevice->Lock)) != NULL) {
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+ REQUEST_STATUS(Request) = STATUS_DEVICE_NOT_READY;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (IpxDevice, Request);
+
+ IpxDereferenceDevice (IpxDevice, DREF_ADDRESS_NOTIFY);
+ }
+
+
+ //
+ // Cancel the source routing timer if used.
+ //
+
+ if (IpxDevice->SourceRoutingUsed) {
+
+ IpxDevice->SourceRoutingUsed = FALSE;
+ if (CTEStopTimer (&IpxDevice->SourceRoutingTimer)) {
+ IpxDereferenceDevice (IpxDevice, DREF_SR_TIMER);
+ }
+ }
+
+
+ //
+ // Cancel the RIP long timer, and if we do that then
+ // send a RIP DOWN message if needed.
+ //
+
+ if (CTEStopTimer (&IpxDevice->RipLongTimer)) {
+
+ if (IpxDevice->RipResponder) {
+
+ if (RipQueueRequest (IpxDevice->VirtualNetworkNumber, RIP_DOWN) == STATUS_PENDING) {
+
+ //
+ // If we queue a request, it will stop the timer.
+ //
+
+ KeWaitForSingleObject(
+ &IpxDevice->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+ }
+ }
+
+ IpxDereferenceDevice (IpxDevice, DREF_LONG_TIMER);
+
+ } else {
+
+ //
+ // We couldn't stop the timer, which means it is running,
+ // so we need to wait for the event that is kicked when
+ // the RIP DOWN messages are done.
+ //
+
+ if (IpxDevice->RipResponder) {
+
+ KeWaitForSingleObject(
+ &IpxDevice->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+ }
+ }
+
+
+ //
+ // Walk the list of device contexts.
+ //
+
+ for (i = 1; i <= IpxDevice->BindingCount; i++) {
+#ifdef _PNP_POWER
+ if ((Binding = NIC_ID_TO_BINDING(IpxDevice, i)) != NULL) {
+ INSERT_BINDING(IpxDevice, i, NULL);
+#else
+ if (IpxDevice->Bindings[i] != NULL) {
+ Binding = IpxDevice->Bindings[i];
+ IpxDevice->Bindings[i] = NULL;
+#endif _PNP_POWER
+
+ IpxUnBindFromAdapter (Binding);
+
+ }
+
+ }
+
+#ifdef _PNP_POWER
+
+ IpxFreeMemory ( IpxDevice->Bindings,
+ IpxDevice->MaxBindings * sizeof(BIND_ARRAY_ELEM),
+ MEMORY_BINDING,
+ "Binding array");
+
+ //
+ // Deallocate the TdiRegistrationAddress and RegistryPathBuffer.
+ //
+ IpxFreeMemory ( IpxDevice->TdiRegistrationAddress,
+ (2 * sizeof(USHORT) + sizeof(TDI_ADDRESS_IPX)),
+ MEMORY_ADDRESS,
+ "Tdi Address");
+
+ IpxFreeMemory ( IpxDevice->RegistryPathBuffer,
+ IpxDevice->RegistryPath.Length + sizeof(WCHAR),
+ MEMORY_CONFIG,
+ "RegistryPathBuffer");
+
+#endif
+
+ KeResetEvent(
+ &IpxDevice->UnloadEvent
+ );
+ IpxDevice->UnloadWaiting = TRUE;
+
+ //
+ // Remove the reference for us being loaded.
+ //
+
+ IpxDereferenceDevice (IpxDevice, DREF_CREATE);
+
+ //
+ // Wait for our count to drop to zero.
+ //
+
+ KeWaitForSingleObject(
+ &IpxDevice->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ //
+ // Now free the padding buffer.
+ //
+
+ IpxFreePaddingBuffer (IpxDevice);
+
+ //
+ // Now do the cleanup that has to happen at IRQL 0.
+ //
+
+ ExDeleteResource (&IpxDevice->AddressResource);
+ IoDeleteDevice (IpxDevice->DeviceObject);
+
+ //
+ // Finally, remove ourselves as an NDIS protocol.
+ //
+
+ IpxDeregisterProtocol();
+
+} /* IpxUnload */
+
+
+NTSTATUS
+IpxDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the IPX device driver.
+ It accepts an I/O Request Packet, performs the request, and then
+ returns with the appropriate status.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PDEVICE Device = IpxDevice;
+ NTSTATUS Status;
+ PFILE_FULL_EA_INFORMATION openType;
+ BOOLEAN found;
+ PADDRESS_FILE AddressFile;
+ PREQUEST Request;
+ UINT i;
+
+ ASSERT( DeviceObject->DeviceExtension == IpxDevice );
+
+#ifdef _PNP_POWER
+ if ((Device->State == DEVICE_STATE_CLOSED) ||
+ (Device->State == DEVICE_STATE_STOPPING)) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+#else
+ if (Device->State != DEVICE_STATE_OPEN) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+#endif
+ //
+ // Allocate a request to track this IRP.
+ //
+
+ Request = IpxAllocateRequest (Device, Irp);
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ MARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = STATUS_PENDING;
+ REQUEST_INFORMATION(Request) = 0;
+
+ //
+ // Case on the function that is being performed by the requestor. If the
+ // operation is a valid one for this device, then make it look like it was
+ // successfully completed, where possible.
+ //
+
+
+ switch (REQUEST_MAJOR_FUNCTION(Request)) {
+
+ //
+ // The Create function opens a transport object (either address or
+ // connection). Access checking is performed on the specified
+ // address to ensure security of transport-layer addresses.
+ //
+
+ case IRP_MJ_CREATE:
+
+ openType = OPEN_REQUEST_EA_INFORMATION(Request);
+
+ if (openType != NULL) {
+
+ found = TRUE;
+
+ for (i=0;i<openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiTransportAddress[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = IpxOpenAddress (Device, Request);
+ break;
+ }
+
+ //
+ // Connection?
+ //
+
+ found = TRUE;
+
+ for (i=0;i<openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiConnectionContext[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ } else {
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ //
+ // LowPart is in the OPEN_CONTEXT directly.
+ // HighPart goes into the upper 2 bytes of the OPEN_TYPE.
+ //
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)(Device->ControlChannelIdentifier.LowPart);
+
+ (ULONG)(REQUEST_OPEN_TYPE(Request)) = (Device->ControlChannelIdentifier.HighPart << 16);
+ (ULONG)(REQUEST_OPEN_TYPE(Request)) |= IPX_FILE_TYPE_CONTROL;
+
+ ++(Device->ControlChannelIdentifier.QuadPart);
+
+ if (Device->ControlChannelIdentifier.QuadPart > MAX_CCID) {
+ Device->ControlChannelIdentifier.QuadPart = 1;
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case IRP_MJ_CLOSE:
+
+ //
+ // The Close function closes a transport endpoint, terminates
+ // all outstanding transport activity on the endpoint, and unbinds
+ // the endpoint from its transport address, if any. If this
+ // is the last transport endpoint bound to the address, then
+ // the address is removed from the provider.
+ //
+
+ switch ((ULONG)(REQUEST_OPEN_TYPE(Request)) & IPX_CC_MASK) {
+ case TDI_TRANSPORT_ADDRESS_FILE:
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ //
+ // This creates a reference to AddressFile->Address
+ // which is removed by IpxCloseAddressFile.
+ //
+
+ Status = IpxVerifyAddressFile(AddressFile);
+
+ if (!NT_SUCCESS (Status)) {
+ Status = STATUS_INVALID_HANDLE;
+ } else {
+ Status = IpxCloseAddressFile (Device, Request);
+ IpxDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ }
+
+ break;
+
+ case IPX_FILE_TYPE_CONTROL:
+ {
+ LARGE_INTEGER ControlChannelId;
+
+ CCID_FROM_REQUEST(ControlChannelId, Request);
+
+ //
+ // See if it is one of the upper driver's control channels.
+ //
+
+ Status = STATUS_SUCCESS;
+
+ IPX_DEBUG (DEVICE, ("CCID: (%d, %d)\n", ControlChannelId.HighPart, ControlChannelId.LowPart));
+
+ for (i = 0; i < UPPER_DRIVER_COUNT; i++) {
+ if (Device->UpperDriverControlChannel[i].QuadPart ==
+ ControlChannelId.QuadPart) {
+ Status = IpxInternalUnbind (Device, i);
+ break;
+ }
+ }
+
+ break;
+ }
+ default:
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ break;
+
+ case IRP_MJ_CLEANUP:
+
+ //
+ // Handle the two stage IRP for a file close operation. When the first
+ // stage hits, run down all activity on the object of interest. This
+ // do everything to it but remove the creation hold. Then, when the
+ // CLOSE irp hits, actually close the object.
+ //
+
+ switch ((ULONG)(REQUEST_OPEN_TYPE(Request)) & IPX_CC_MASK) {
+ case TDI_TRANSPORT_ADDRESS_FILE:
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+ Status = IpxVerifyAddressFile(AddressFile);
+ if (!NT_SUCCESS (Status)) {
+
+ Status = STATUS_INVALID_HANDLE;
+
+ } else {
+
+ IpxStopAddressFile (AddressFile);
+ IpxDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case IPX_FILE_TYPE_CONTROL:
+ {
+ LARGE_INTEGER ControlChannelId;
+
+ CCID_FROM_REQUEST(ControlChannelId, Request);
+
+ //
+ // Check for any line change IRPs submitted by this
+ // address.
+ //
+
+ IpxAbortLineChanges ((PVOID)&ControlChannelId);
+
+ Status = STATUS_SUCCESS;
+ break;
+ }
+ default:
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ break;
+
+ default:
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ } /* major function switch */
+
+ if (Status != STATUS_PENDING) {
+ UNMARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = Status;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ return Status;
+
+} /* IpxDispatchOpenClose */
+
+#define IOCTL_IPX_LOAD_SPX _IPX_CONTROL_CODE( 0x5678, METHOD_BUFFERED )
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+ZwLoadDriver(
+ IN PUNICODE_STRING DriverServiceName
+ );
+
+
+NTSTATUS
+IpxDispatchDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE Device = IpxDevice;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (Irp);
+ static NDIS_STRING SpxServiceName = NDIS_STRING_CONST ("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\NwlnkSpx");
+
+ ASSERT( DeviceObject->DeviceExtension == IpxDevice );
+
+ //
+ // Branch to the appropriate request handler. Preliminary checking of
+ // the size of the request block is performed here so that it is known
+ // in the handlers that the minimum input parameters are readable. It
+ // is *not* determined here whether variable length input fields are
+ // passed correctly; this is a check which must be made within each routine.
+ //
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+
+ case IOCTL_TDI_QUERY_DIRECT_SENDDG_HANDLER: {
+
+ PULONG EntryPoint;
+
+ //
+ // This is the LanmanServer trying to get the send
+ // entry point.
+ //
+
+ IPX_DEBUG (BIND, ("Direct send entry point being returned\n"));
+
+ EntryPoint = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+ *EntryPoint = (ULONG)IpxTdiSendDatagram;
+
+ Status = STATUS_SUCCESS;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ break;
+ }
+
+ case IOCTL_IPX_INTERNAL_BIND:
+
+ //
+ // This is a client trying to bind.
+ //
+
+ CTEAssert ((IOCTL_IPX_INTERNAL_BIND & 0x3) == METHOD_BUFFERED);
+ CTEAssert (IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL);
+
+#ifdef _PNP_POWER
+
+ if ((Device->State == DEVICE_STATE_CLOSED) ||
+ (Device->State == DEVICE_STATE_STOPPING)) {
+#else
+ if (Device->State != DEVICE_STATE_OPEN) {
+#endif
+ Status = STATUS_INVALID_DEVICE_STATE;
+
+ } else {
+
+ Status = IpxInternalBind (Device, Irp);
+
+ }
+
+ CTEAssert (Status != STATUS_PENDING);
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ break;
+
+ case IOCTL_IPX_LOAD_SPX:
+
+ //
+ // The SPX helper dll is asking us to load SPX.
+ //
+
+ Status = ZwLoadDriver (&SpxServiceName);
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ break;
+
+ default:
+
+ //
+ // Convert the user call to the proper internal device call.
+ //
+
+ Status = TdiMapUserRequest (DeviceObject, Irp, IrpSp);
+
+ if (Status == STATUS_SUCCESS) {
+
+ //
+ // If TdiMapUserRequest returns SUCCESS then the IRP
+ // has been converted into an IRP_MJ_INTERNAL_DEVICE_CONTROL
+ // IRP, so we dispatch it as usual. The IRP will
+ // be completed by this call.
+ //
+
+ Status = IpxDispatchInternal (DeviceObject, Irp);
+
+ } else {
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ }
+
+ break;
+ }
+ return Status;
+
+} /* IpxDispatchDeviceControl */
+
+
+NTSTATUS
+IpxDispatchInternal (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE Device = IpxDevice;
+ PREQUEST Request;
+
+ ASSERT( DeviceObject->DeviceExtension == IpxDevice );
+
+ if (Device->State == DEVICE_STATE_OPEN) {
+
+ //
+ // Allocate a request to track this IRP.
+ //
+
+ Request = IpxAllocateRequest (Device, Irp);
+
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ MARK_REQUEST_PENDING(Request);
+#if DBG
+ REQUEST_STATUS(Request) = STATUS_PENDING;
+ REQUEST_INFORMATION(Request) = 0;
+#endif
+
+ //
+ // Branch to the appropriate request handler. Preliminary checking of
+ // the size of the request block is performed here so that it is known
+ // in the handlers that the minimum input parameters are readable. It
+ // is *not* determined here whether variable length input fields are
+ // passed correctly; this is a check which must be made within each routine.
+ //
+
+ switch (REQUEST_MINOR_FUNCTION(Request)) {
+
+ case TDI_SEND_DATAGRAM:
+ Status = IpxTdiSendDatagram (DeviceObject, Request);
+ break;
+
+ case TDI_ACTION:
+ Status = IpxTdiAction (Device, Request);
+ break;
+
+ case TDI_QUERY_INFORMATION:
+ Status = IpxTdiQueryInformation (Device, Request);
+ break;
+
+ case TDI_RECEIVE_DATAGRAM:
+ Status = IpxTdiReceiveDatagram (Request);
+ break;
+
+ case TDI_SET_EVENT_HANDLER:
+ Status = IpxTdiSetEventHandler (Request);
+ break;
+
+ case TDI_SET_INFORMATION:
+ Status = IpxTdiSetInformation (Device, Request);
+ break;
+
+
+ //
+ // Something we don't know about was submitted.
+ //
+
+ default:
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ if (Status == STATUS_PENDING) {
+
+ return STATUS_PENDING;
+
+ } else {
+
+ UNMARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = Status;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+ return Status;
+ }
+
+ } else {
+
+ //
+ // The device was not open.
+ //
+
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+} /* IpxDispatchInternal */
+
+
+PVOID
+IpxpAllocateMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN BOOLEAN ChargeDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory, making sure it is within
+ the limit allowed by the device.
+
+Arguments:
+
+ BytesNeeded - The number of bytes to allocated.
+
+ ChargeDevice - TRUE if the device should be charged.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PVOID Memory;
+ PDEVICE Device = IpxDevice;
+
+ if (ChargeDevice) {
+ if ((Device->MemoryLimit != 0) &&
+ (((LONG)(Device->MemoryUsage + BytesNeeded) >
+ Device->MemoryLimit))) {
+
+ IpxPrint1 ("IPX: Could not allocate %d: limit\n", BytesNeeded);
+ IpxWriteResourceErrorLog(
+ Device->DeviceObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ BytesNeeded,
+ Tag);
+
+ return NULL;
+ }
+ }
+
+#if ISN_NT
+ Memory = ExAllocatePoolWithTag (NonPagedPool, BytesNeeded, ' XPI');
+#else
+ Memory = CTEAllocMem (BytesNeeded);
+#endif
+
+ if (Memory == NULL) {
+
+ IpxPrint1("IPX: Could not allocate %d: no pool\n", BytesNeeded);
+ if (ChargeDevice) {
+ IpxWriteResourceErrorLog(
+ Device->DeviceObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ BytesNeeded,
+ Tag);
+ }
+
+ return NULL;
+ }
+
+ if (ChargeDevice) {
+ Device->MemoryUsage += BytesNeeded;
+ }
+
+ return Memory;
+} /* IpxpAllocateMemory */
+
+
+VOID
+IpxpFreeMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN BOOLEAN ChargeDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees memory allocated with IpxpAllocateMemory.
+
+Arguments:
+
+ Memory - The memory allocated.
+
+ BytesAllocated - The number of bytes to freed.
+
+ ChargeDevice - TRUE if the device should be charged.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+
+#if ISN_NT
+ ExFreePool (Memory);
+#else
+ CTEFreeMem (Memory);
+#endif
+ if (ChargeDevice) {
+ Device->MemoryUsage -= BytesAllocated;
+ }
+
+} /* IpxpFreeMemory */
+
+#if DBG
+
+
+PVOID
+IpxpAllocateTaggedMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory, charging it to the device.
+ If it cannot allocate memory it uses the Tag and Descriptor
+ to log an error.
+
+Arguments:
+
+ BytesNeeded - The number of bytes to allocated.
+
+ Tag - A unique ID used in the error log.
+
+ Description - A text description of the allocation.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PVOID Memory;
+
+ UNREFERENCED_PARAMETER(Description);
+
+ Memory = IpxpAllocateMemory(BytesNeeded, Tag, (BOOLEAN)(Tag != MEMORY_CONFIG));
+
+ if (Memory) {
+ (VOID)IPX_ADD_ULONG(
+ &IpxMemoryTag[Tag].BytesAllocated,
+ BytesNeeded,
+ &IpxMemoryInterlock);
+ }
+
+ return Memory;
+
+} /* IpxpAllocateTaggedMemory */
+
+
+VOID
+IpxpFreeTaggedMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees memory allocated with IpxpAllocateTaggedMemory.
+
+Arguments:
+
+ Memory - The memory allocated.
+
+ BytesAllocated - The number of bytes to freed.
+
+ Tag - A unique ID used in the error log.
+
+ Description - A text description of the allocation.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UNREFERENCED_PARAMETER(Description);
+
+ (VOID)IPX_ADD_ULONG(
+ &IpxMemoryTag[Tag].BytesAllocated,
+ (ULONG)(-(LONG)BytesAllocated),
+ &IpxMemoryInterlock);
+
+ IpxpFreeMemory (Memory, BytesAllocated, (BOOLEAN)(Tag != MEMORY_CONFIG));
+
+} /* IpxpFreeTaggedMemory */
+
+#endif
+
+
+VOID
+IpxWriteResourceErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry which has
+ a %3 value that needs to be converted to a string. It is currently
+ used for EVENT_TRANSPORT_RESOURCE_POOL and EVENT_IPX_INTERNAL_NET_
+ INVALID.
+
+Arguments:
+
+ DeviceObject - Pointer to the system device object.
+
+ ErrorCode - The transport event code.
+
+ BytesNeeded - If applicable, the number of bytes that could not
+ be allocated -- will be put in the dump data.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet and converted for use as the %3 string.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ PUCHAR StringLoc;
+ ULONG TempUniqueError;
+ PDEVICE Device = IpxDevice;
+ static WCHAR UniqueErrorBuffer[9] = L"00000000";
+ UINT CurrentDigit;
+ INT i;
+
+
+ //
+ // Convert the error value into a buffer.
+ //
+
+ TempUniqueError = UniqueErrorValue;
+ i = 8;
+ do {
+ CurrentDigit = TempUniqueError & 0xf;
+ TempUniqueError >>= 4;
+ i--;
+ if (CurrentDigit >= 0xa) {
+ UniqueErrorBuffer[i] = (WCHAR)(CurrentDigit - 0xa + L'A');
+ } else {
+ UniqueErrorBuffer[i] = (WCHAR)(CurrentDigit + L'0');
+ }
+ } while (TempUniqueError);
+
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ Device->DeviceNameLength +
+ sizeof(UniqueErrorBuffer) - (i * sizeof(WCHAR));
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ DeviceObject,
+ EntrySize
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = sizeof(ULONG);
+ errorLogEntry->NumberOfStrings = 2;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+ errorLogEntry->DumpData[0] = BytesNeeded;
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
+
+ StringLoc += Device->DeviceNameLength;
+ RtlCopyMemory (StringLoc, UniqueErrorBuffer + i, sizeof(UniqueErrorBuffer) - (i * sizeof(WCHAR)));
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* IpxWriteResourceErrorLog */
+
+
+VOID
+IpxWriteGeneralErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN ULONG DumpDataCount,
+ IN ULONG DumpData[]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ a general problem as indicated by the parameters. It handles
+ event codes REGISTER_FAILED, BINDING_FAILED, ADAPTER_NOT_FOUND,
+ TRANSFER_DATA, TOO_MANY_LINKS, and BAD_PROTOCOL. All these
+ events have messages with one or two strings in them.
+
+Arguments:
+
+ DeviceObject - Pointer to the system device object, or this may be
+ a driver object instead.
+
+ ErrorCode - The transport event code.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet.
+
+ FinalStatus - Used as the FinalStatus in the error log packet.
+
+ SecondString - If not NULL, the string to use as the %3
+ value in the error log packet.
+
+ DumpDataCount - The number of ULONGs of dump data.
+
+ DumpData - Dump data for the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG SecondStringSize;
+ PUCHAR StringLoc;
+ PDEVICE Device = IpxDevice;
+ static WCHAR DriverName[9] = L"NwlnkIpx";
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ (DumpDataCount * sizeof(ULONG));
+
+ if (DeviceObject->Type == IO_TYPE_DEVICE) {
+ EntrySize += (UCHAR)Device->DeviceNameLength;
+ } else {
+ EntrySize += sizeof(DriverName);
+ }
+
+ if (SecondString) {
+ SecondStringSize = (wcslen(SecondString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize += (UCHAR)SecondStringSize;
+ }
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ DeviceObject,
+ EntrySize
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = (USHORT)(DumpDataCount * sizeof(ULONG));
+ errorLogEntry->NumberOfStrings = (SecondString == NULL) ? 1 : 2;
+ errorLogEntry->StringOffset =
+ sizeof(IO_ERROR_LOG_PACKET) + ((DumpDataCount-1) * sizeof(ULONG));
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ if (DumpDataCount) {
+ RtlCopyMemory(errorLogEntry->DumpData, DumpData, DumpDataCount * sizeof(ULONG));
+ }
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ if (DeviceObject->Type == IO_TYPE_DEVICE) {
+ RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
+ StringLoc += Device->DeviceNameLength;
+ } else {
+ RtlCopyMemory (StringLoc, DriverName, sizeof(DriverName));
+ StringLoc += sizeof(DriverName);
+ }
+ if (SecondString) {
+ RtlCopyMemory (StringLoc, SecondString, SecondStringSize);
+ }
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* IpxWriteGeneralErrorLog */
+
+
+VOID
+IpxWriteOidErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR AdapterString,
+ IN ULONG OidValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ a problem querying or setting an OID on an adapter. It handles
+ event codes SET_OID_FAILED and QUERY_OID_FAILED.
+
+Arguments:
+
+ DeviceObject - Pointer to the system device object.
+
+ ErrorCode - Used as the ErrorCode in the error log packet.
+
+ FinalStatus - Used as the FinalStatus in the error log packet.
+
+ AdapterString - The name of the adapter we were bound to.
+
+ OidValue - The OID which could not be set or queried.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG AdapterStringSize;
+ PUCHAR StringLoc;
+ PDEVICE Device = IpxDevice;
+ static WCHAR OidBuffer[9] = L"00000000";
+ INT i;
+ UINT CurrentDigit;
+
+ AdapterStringSize = (wcslen(AdapterString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) -
+ sizeof(ULONG) +
+ Device->DeviceNameLength +
+ AdapterStringSize +
+ sizeof(OidBuffer);
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ DeviceObject,
+ EntrySize
+ );
+
+ //
+ // Convert the OID into a buffer.
+ //
+
+ for (i=7; i>=0; i--) {
+ CurrentDigit = OidValue & 0xf;
+ OidValue >>= 4;
+ if (CurrentDigit >= 0xa) {
+ OidBuffer[i] = (WCHAR)(CurrentDigit - 0xa + L'A');
+ } else {
+ OidBuffer[i] = (WCHAR)(CurrentDigit + L'0');
+ }
+ }
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = 0;
+ errorLogEntry->NumberOfStrings = 3;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) - sizeof(ULONG);
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
+ StringLoc += Device->DeviceNameLength;
+
+ RtlCopyMemory (StringLoc, OidBuffer, sizeof(OidBuffer));
+ StringLoc += sizeof(OidBuffer);
+
+ RtlCopyMemory (StringLoc, AdapterString, AdapterStringSize);
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* IpxWriteOidErrorLog */
+
+
+#ifdef _PNP_POWER
+VOID
+IpxPnPUpdateDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ Updates datagram sizes, lookahead sizes, etc. in the Device as a result
+ of a new binding coming in.
+
+Arguments:
+
+ Device - The IPX device object.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG AnnouncedMaxDatagram, RealMaxDatagram, MaxLookahead;
+ ULONG LinkSpeed, MacOptions;
+ ULONG i;
+ PBINDING Binding;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ IPX_GET_LOCK(&Device->BindAccessLock, &LockHandle);
+
+ //
+ // Calculate some values based on all the bindings.
+ //
+
+ MaxLookahead = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->MaxLookaheadData; // largest binding value
+ AnnouncedMaxDatagram = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->AnnouncedMaxDatagramSize; // smallest binding value
+ RealMaxDatagram = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->RealMaxDatagramSize; // smallest binding value
+
+ if (NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->LineUp) {
+ LinkSpeed = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->MediumSpeed; // smallest binding value
+ } else {
+ LinkSpeed = 0xffffffff;
+ }
+ MacOptions = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->Adapter->MacInfo.MacOptions; // AND of binding values
+
+ for (i = 2; i <= Device->ValidBindings; i++) {
+
+ Binding = NIC_ID_TO_BINDING_NO_ILOCK(Device, i);
+
+ if (!Binding) {
+ continue;
+ }
+
+ if (Binding->MaxLookaheadData > MaxLookahead) {
+ MaxLookahead = Binding->MaxLookaheadData;
+ }
+ if (Binding->AnnouncedMaxDatagramSize < AnnouncedMaxDatagram) {
+ AnnouncedMaxDatagram = Binding->AnnouncedMaxDatagramSize;
+ }
+ if (Binding->RealMaxDatagramSize < RealMaxDatagram) {
+ RealMaxDatagram = Binding->RealMaxDatagramSize;
+ }
+
+ if (Binding->LineUp && (Binding->MediumSpeed < LinkSpeed)) {
+ LinkSpeed = Binding->MediumSpeed;
+ }
+ MacOptions &= Binding->Adapter->MacInfo.MacOptions;
+
+ }
+
+ Device->Information.MaxDatagramSize = AnnouncedMaxDatagram;
+ Device->RealMaxDatagramSize = RealMaxDatagram;
+ Device->Information.MaximumLookaheadData = MaxLookahead;
+
+ //
+ // If we couldn't find anything better, use the speed from
+ // the first binding.
+ //
+
+ if (LinkSpeed == 0xffffffff) {
+ Device->LinkSpeed = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->MediumSpeed;
+ } else {
+ Device->LinkSpeed = LinkSpeed;
+ }
+ Device->MacOptions = MacOptions;
+
+ IPX_FREE_LOCK(&Device->BindAccessLock, LockHandle);
+}
+
+VOID
+IpxPnPUpdateBindingArray(
+ IN PDEVICE Device,
+ IN PADAPTER Adapter,
+ IN PBINDING_CONFIG ConfigBinding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to update the binding array to
+ add the new bindings that appeared in this PnP event.
+ The order of bindings in the array is as follows:
+
+ - First comes the first binding to each LAN network
+ - Following that are all WAN bindings
+ - Following that are any duplicate bindings to LAN networks
+ (the others in the "binding set").
+
+ This routine inserts the bindings while maintaining this
+ order by resolving binding sets.
+
+ The bindings are also inserted into the RIP database.
+
+ If "global wan net" is true we will advertise up to
+ and including the first wan binding as the highest nic
+ id; otherwise we advertise up to and including the last
+ wan binding. In all cases the duplicate bindings are
+ hidden.
+
+ Updates the SapNicCount, Device->FirstLanNicId and Device->FirstWanNicId
+
+Arguments:
+
+ Device - The IPX device object.
+
+ Adapter - The adapter added in this PnP event
+
+ ValidBindings - the number of bindings valid for this adapter (if LAN)
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG i, j;
+ PBINDING Binding, MasterBinding;
+ NTSTATUS status;
+
+ //
+ // Insert in proper place; if WAN, after all the WAN bindings
+ // If LAN, check for binding sets and insert in proper place
+ // Also, insert into the Rip Tables.
+ //
+
+ //
+ // Go thru' the bindings for this adapter, inserting into the
+ // binding array in place
+ //
+ for (i = 0; i < ConfigBinding->FrameTypeCount; i++) {
+ ULONG MappedFrameType;
+
+ //
+ // Store in the preference order.
+ // Map the frame types since we could have a case where the user selects a FrameType (say, EthernetII on FDDI)
+ // which maps to a different FrameType (802.2). Then we would fail to find the binding in the adapter array;
+ // we could potentialy add a binding twice (if two frame types map to the same Frame, then we would go to the
+ // mapped one twice). This is taken care of by purging dups from the ConfigBinding->FrameType array when we
+ // create the bindings off of the Adapter (see call to IpxBindToAdapter).
+ //
+
+ MacMapFrameType(
+ Adapter->MacInfo.RealMediumType,
+ ConfigBinding->FrameType[i],
+ &MappedFrameType);
+
+ Binding = Adapter->Bindings[MappedFrameType];
+
+ if (!Binding){
+ continue;
+ }
+
+ CTEAssert(Binding->FrameType == MappedFrameType);
+
+ if (Adapter->MacInfo.MediumAsync) {
+ //
+ // WAN: Place after the HighestExternalNicId, with space for WanLine # of bindings.
+ // Update the First/LastWanNicId.
+ //
+ Adapter->FirstWanNicId = (USHORT)Device->HighestExternalNicId+1;
+ Adapter->LastWanNicId = (USHORT)(Device->HighestExternalNicId + Adapter->WanNicIdCount);
+
+ //
+ // Make sure we dont overflow the array
+ // Re-alloc the array to fit the new bindings
+ //
+ if (Device->ValidBindings+Adapter->WanNicIdCount >= Device->MaxBindings) {
+ status = IpxPnPReallocateBindingArray(Device, Adapter->WanNicIdCount);
+ CTEAssert(status == STATUS_SUCCESS);
+ }
+
+ //
+ // Move Slaves down by WanNicIdCount# of entries
+ //
+ for (j = Device->ValidBindings; j > Device->HighestExternalNicId; j--) {
+ INSERT_BINDING(Device, j+Adapter->WanNicIdCount, NIC_ID_TO_BINDING_NO_ILOCK(Device, j));
+ if (NIC_ID_TO_BINDING_NO_ILOCK(Device, j+Adapter->WanNicIdCount)) {
+ NIC_ID_TO_BINDING_NO_ILOCK(Device, j+Adapter->WanNicIdCount)->NicId += (USHORT)Adapter->WanNicIdCount;
+ }
+ }
+
+ //
+ // Insert the WAN binding in the place just allocated
+ //
+ INSERT_BINDING(Device, Device->HighestExternalNicId+1, Binding);
+ SET_VERSION(Device, Device->HighestExternalNicId+1);
+
+ Binding->NicId = (USHORT)Device->HighestExternalNicId+1;
+
+ //
+ // Update the indices
+ //
+ Device->HighestExternalNicId += (USHORT)Adapter->WanNicIdCount;
+ Device->ValidBindings += (USHORT)Adapter->WanNicIdCount;
+ Device->BindingCount += (USHORT)Adapter->WanNicIdCount;
+ Device->SapNicCount++;
+
+ //
+ // Since we initialize FirstWanNicId to 1, we need to compare against that.
+ // In case of no LAN bindings, we are fine since we have only one WAN binding initally
+ // (all the other WAN lines have place holders).
+ //
+ if (Device->FirstWanNicId == (USHORT)1) {
+ Device->FirstWanNicId = Binding->NicId;
+ }
+
+ //
+ // BUGBUGZZ Make this inline later
+ //
+ // This should be done after all the auto-detect bindings have been thrown away.
+ //
+ // IpxPnPUpdateDevice(Device, Binding);
+
+ //
+ // Since WAN can have only one frame type, break
+ //
+ break;
+
+ } else {
+
+ Device->BindingCount++;
+
+ //
+ // Make sure we dont overflow the array
+ // Re-alloc the array to fit the new bindings
+ //
+ if (Device->ValidBindings+1 >= Device->MaxBindings) {
+ status = IpxPnPReallocateBindingArray(Device, 1);
+ CTEAssert(status == STATUS_SUCCESS);
+ }
+
+ //
+ // LAN: Figure out if it is a slave binding only for non-auto-detect bindings.
+ //
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (j = 1; j < Index; j++) {
+ MasterBinding = NIC_ID_TO_BINDING_NO_ILOCK(Device, j);
+ if ((MasterBinding->ConfiguredNetworkNumber) &&
+ (MasterBinding->ConfiguredNetworkNumber == Binding->ConfiguredNetworkNumber) &&
+ (MasterBinding->FrameType == Binding->FrameType) &&
+ (MasterBinding->Adapter->MacInfo.MediumType == Binding->Adapter->MacInfo.MediumType)) {
+
+ CTEAssert(Binding->ConfiguredNetworkNumber);
+ break;
+ }
+ }
+ }
+
+ if (j < Device->HighestExternalNicId) {
+ //
+ // Slave binding
+ //
+
+ //
+ // Now make MasterBinding the head of a binding set.
+ //
+
+ if (MasterBinding->BindingSetMember) {
+
+ //
+ // Just insert ourselves in the chain.
+ //
+
+#if DBG
+ DbgPrint ("IPX: %ws is also on network %lx\n",
+ Binding->Adapter->AdapterName,
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+#endif
+ IPX_DEBUG (AUTO_DETECT, ("Add %lx to binding set of %lx\n", Binding, MasterBinding));
+
+ CTEAssert (MasterBinding->CurrentSendBinding);
+ Binding->NextBinding = MasterBinding->NextBinding;
+
+ } else {
+
+ //
+ // Start the chain with the two bindings in it.
+ //
+
+#if DBG
+ DbgPrint ("IPX: %lx and %lx are on the same network %lx, will load balance\n",
+ MasterBinding->Adapter->AdapterName, Binding->Adapter->AdapterName,
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+#endif
+ IPX_DEBUG (AUTO_DETECT, ("Create new %lx in binding set of %lx\n", Binding, MasterBinding));
+
+ MasterBinding->BindingSetMember = TRUE;
+ MasterBinding->CurrentSendBinding = MasterBinding;
+ MasterBinding->MasterBinding = MasterBinding;
+ Binding->NextBinding = MasterBinding;
+
+ }
+
+ MasterBinding->NextBinding = Binding;
+ Binding->BindingSetMember = TRUE;
+ Binding->ReceiveBroadcast = FALSE;
+ Binding->CurrentSendBinding = NULL;
+ Binding->MasterBinding = MasterBinding;
+
+ //
+ // Since the master binding looks like all members of
+ // the binding set to people querying from above, we have
+ // to make it the worst-case of all the elements. Generally
+ // these will be equal since the frame type and media is
+ // the same.
+ //
+
+ if (Binding->MaxLookaheadData > MasterBinding->MaxLookaheadData) {
+ MasterBinding->MaxLookaheadData = Binding->MaxLookaheadData;
+ }
+ if (Binding->AnnouncedMaxDatagramSize < MasterBinding->AnnouncedMaxDatagramSize) {
+ MasterBinding->AnnouncedMaxDatagramSize = Binding->AnnouncedMaxDatagramSize;
+ }
+ if (Binding->RealMaxDatagramSize < MasterBinding->RealMaxDatagramSize) {
+ MasterBinding->RealMaxDatagramSize = Binding->RealMaxDatagramSize;
+ }
+ if (Binding->MediumSpeed < MasterBinding->MediumSpeed) {
+ MasterBinding->MediumSpeed = Binding->MediumSpeed;
+ }
+
+ //
+ // Place the binding after the last slave binding
+ //
+ INSERT_BINDING(Device, Device->ValidBindings+1, Binding);
+ SET_VERSION(Device, Device->ValidBindings+1);
+
+ Binding->NicId = (USHORT)Device->ValidBindings+1;
+
+ //
+ // Update the indices
+ //
+ Device->ValidBindings++;
+
+ } else {
+
+ //
+ // Not a binding set slave binding - just add it after the last LAN binding
+ //
+
+ //
+ // Move WAN and Slaves down by 1 entry
+ //
+ for (j = Device->ValidBindings; j > Device->HighestLanNicId; j--) {
+ INSERT_BINDING(Device, j+1, NIC_ID_TO_BINDING_NO_ILOCK(Device, j));
+ if (NIC_ID_TO_BINDING_NO_ILOCK(Device, j+1)) {
+ NIC_ID_TO_BINDING_NO_ILOCK(Device, j+1)->NicId++;
+ }
+ }
+
+ //
+ // Insert the LAN binding in the place just allocated
+ //
+ INSERT_BINDING(Device, Device->HighestLanNicId+1, Binding);
+ SET_VERSION(Device, Device->HighestLanNicId+1);
+ Binding->NicId = (USHORT)Device->HighestLanNicId+1;
+
+ //
+ // Update the indices
+ //
+ Device->HighestLanNicId++;
+ Device->HighestExternalNicId++;
+ Device->ValidBindings++;
+ Device->HighestType20NicId++;
+ Device->SapNicCount++;
+
+ if (Device->FirstLanNicId == (USHORT)-1) {
+ Device->FirstLanNicId = Binding->NicId;
+ }
+
+ }
+
+ }
+
+ //
+ // Insert this binding in the RIP Tables
+ //
+ if (Binding->ConfiguredNetworkNumber != 0) {
+ status = RipInsertLocalNetwork(
+ Binding->ConfiguredNetworkNumber,
+ Binding->NicId,
+ Binding->Adapter->NdisBindingHandle,
+ (USHORT)((839 + Binding->Adapter->MediumSpeed) / Binding->Adapter->MediumSpeed));
+
+ if ((status == STATUS_SUCCESS) ||
+ (status == STATUS_DUPLICATE_NAME)) {
+
+ Binding->LocalAddress.NetworkAddress = Binding->ConfiguredNetworkNumber;
+ }
+ }
+
+ //
+ // BUGBUGZZ Make this inline later
+ //
+ // This should be done after all the auto-detect bindings have been thrown away.
+ //
+ // IpxPnPUpdateDevice(Device, Binding);
+ }
+} /* IpxPnPUpdateBindingArray */
+
+
+VOID
+IpxPnPToLoad()
+/*++
+
+Routine Description:
+
+ This routine takes the driver to LOADED state (from OPEN) when all
+ PnP adapters have been removed from the machine.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None. When the function returns, the driver is in LOADED state.
+
+--*/
+
+{
+ PBINDING Binding;
+ PREQUEST Request;
+ PLIST_ENTRY p;
+ UINT i;
+ NTSTATUS ntStatus;
+
+ IPX_DEBUG(PNP, ("Going back to loaded state\n"));
+
+ //
+ // Inform TDI clients about the open of our device object.
+ //
+ if ((ntStatus = TdiDeregisterDeviceObject(IpxDevice->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("TdiDeRegisterDeviceObject failed: %lx", ntStatus));
+ }
+
+ //
+ // Complete any pending address notify requests.
+ //
+
+ while ((p = ExInterlockedRemoveHeadList(
+ &IpxDevice->AddressNotifyQueue,
+ &IpxDevice->Lock)) != NULL) {
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+ REQUEST_STATUS(Request) = STATUS_DEVICE_NOT_READY;
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (IpxDevice, Request);
+
+ IpxDereferenceDevice (IpxDevice, DREF_ADDRESS_NOTIFY);
+ }
+
+ //
+ // Cancel the source routing timer if used.
+ //
+
+ if (IpxDevice->SourceRoutingUsed) {
+
+ IpxDevice->SourceRoutingUsed = FALSE;
+ if (CTEStopTimer (&IpxDevice->SourceRoutingTimer)) {
+ IpxDereferenceDevice (IpxDevice, DREF_SR_TIMER);
+ }
+ }
+
+
+ //
+ // Cancel the RIP long timer, and if we do that then
+ // send a RIP DOWN message if needed.
+ //
+
+ if (CTEStopTimer (&IpxDevice->RipLongTimer)) {
+
+ if (IpxDevice->RipResponder) {
+
+ if (RipQueueRequest (IpxDevice->VirtualNetworkNumber, RIP_DOWN) == STATUS_PENDING) {
+
+ //
+ // If we queue a request, it will stop the timer.
+ //
+
+ KeWaitForSingleObject(
+ &IpxDevice->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+ }
+ }
+
+ IpxDereferenceDevice (IpxDevice, DREF_LONG_TIMER);
+
+ } else {
+
+ //
+ // We couldn't stop the timer, which means it is running,
+ // so we need to wait for the event that is kicked when
+ // the RIP DOWN messages are done.
+ //
+
+ if (IpxDevice->RipResponder) {
+
+ KeWaitForSingleObject(
+ &IpxDevice->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+ }
+ }
+} /* IpxPnPToLoad */
+
+
+NTSTATUS
+IpxPnPReallocateBindingArray(
+ IN PDEVICE Device,
+ IN ULONG Size
+ )
+/*++
+
+Routine Description:
+
+ This routine reallocates the binding array when the number of bindings go above
+ Device->MaxBindings.
+
+Arguments:
+
+ Device - pointer to the device.
+ Size - the number of new entries required.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PBIND_ARRAY_ELEM BindingArray;
+ ULONG Pad=2; // extra bindings we keep around
+ ULONG NewSize = Size + Pad + Device->MaxBindings;
+
+ //
+ // The absolute max WAN bindings.
+ //
+ CTEAssert(Size < 2048);
+
+ //
+ // Re-allocate the new array
+ //
+ BindingArray = (PBIND_ARRAY_ELEM)IpxAllocateMemory (
+ NewSize * sizeof(BIND_ARRAY_ELEM),
+ MEMORY_BINDING,
+ "Binding array");
+
+ if (BindingArray == NULL) {
+ IpxWriteGeneralErrorLog(
+ (PVOID)Device->DeviceObject,
+ EVENT_IPX_NO_ADAPTERS,
+ 802,
+ STATUS_DEVICE_DOES_NOT_EXIST,
+ NULL,
+ 0,
+ NULL);
+ IpxDereferenceDevice (Device, DREF_CREATE);
+
+ DbgPrint ("Failed to allocate memory in binding array expansion\n");
+
+ //
+ // Unload the driver here? In case of WAN, we can tolerate this failure. What about LAN? [BUGBUGZZ]
+ //
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory (BindingArray, NewSize * sizeof(BIND_ARRAY_ELEM));
+
+ //
+ // Copy the old array into the new one.
+ //
+ RtlCopyMemory (BindingArray, Device->Bindings, (Device->ValidBindings+1) * sizeof(BIND_ARRAY_ELEM));
+
+ //
+ // Free the old one.
+ //
+ IpxFreeMemory ( Device->Bindings,
+ Device->MaxBindings * sizeof(BIND_ARRAY_ELEM),
+ MEMORY_BINDING,
+ "Binding array");
+
+ IPX_DEBUG(PNP, ("Expand bindarr old: %lx, new: %lx, oldsize: %lx\n",
+ Device->Bindings, BindingArray, Device->MaxBindings));
+
+ //
+ // Use interlocked exchange to assign this since we dont take the BindAccessLock anymore.
+ //
+ // Device->Bindings = BindingArray;
+ SET_VALUE(Device->Bindings, BindingArray);
+
+ Device->MaxBindings = (USHORT)NewSize;
+
+ return STATUS_SUCCESS;
+}
+#endif _PNP_POWER
+
diff --git a/private/ntos/tdi/isnp/ipx/event.c b/private/ntos/tdi/isnp/ipx/event.c
new file mode 100644
index 000000000..a64f85d34
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/event.c
@@ -0,0 +1,143 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ event.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiSetEventHandler
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports
+
+ 1. Added a new event type - TDI_EVENT_CHAINED_RECEIVE_DATAGRAM
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+NTSTATUS
+IpxTdiSetEventHandler(
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetEventHandler request for the
+ transport provider. The caller (request dispatcher) verifies
+ that this routine will not be executed on behalf of a user-mode
+ client, as this request enables direct callouts at DISPATCH_LEVEL.
+
+Arguments:
+
+ Request - Pointer to the request
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ CTELockHandle LockHandle;
+ PTDI_REQUEST_KERNEL_SET_EVENT Parameters;
+ PADDRESS_FILE AddressFile;
+
+ //
+ // Get the Address this is associated with; if there is none, get out.
+ //
+
+ AddressFile = REQUEST_OPEN_CONTEXT(Request);
+ Status = IpxVerifyAddressFile (AddressFile);
+
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ CTEGetLock (&AddressFile->Address->Lock, &LockHandle);
+
+ Parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)REQUEST_PARAMETERS(Request);
+
+ switch (Parameters->EventType) {
+
+ case TDI_EVENT_RECEIVE_DATAGRAM:
+
+ if (Parameters->EventHandler == NULL) {
+ AddressFile->ReceiveDatagramHandler =
+ (PTDI_IND_RECEIVE_DATAGRAM)TdiDefaultRcvDatagramHandler;
+ AddressFile->ReceiveDatagramHandlerContext = NULL;
+ AddressFile->RegisteredReceiveDatagramHandler = FALSE;
+ } else {
+ AddressFile->ReceiveDatagramHandler =
+ (PTDI_IND_RECEIVE_DATAGRAM)Parameters->EventHandler;
+ AddressFile->ReceiveDatagramHandlerContext = Parameters->EventContext;
+ AddressFile->RegisteredReceiveDatagramHandler = TRUE;
+ }
+
+ break;
+ //
+ // [SA] New event handler to receive chained buffers
+ //
+ case TDI_EVENT_CHAINED_RECEIVE_DATAGRAM:
+
+ if (Parameters->EventHandler == NULL) {
+ AddressFile->ChainedReceiveDatagramHandler =
+ (PTDI_IND_CHAINED_RECEIVE_DATAGRAM)TdiDefaultChainedRcvDatagramHandler;
+ AddressFile->ChainedReceiveDatagramHandlerContext = NULL;
+ AddressFile->RegisteredChainedReceiveDatagramHandler = FALSE;
+ } else {
+ AddressFile->ChainedReceiveDatagramHandler =
+ (PTDI_IND_CHAINED_RECEIVE_DATAGRAM)Parameters->EventHandler;
+ AddressFile->ChainedReceiveDatagramHandlerContext = Parameters->EventContext;
+ AddressFile->RegisteredChainedReceiveDatagramHandler = TRUE;
+ }
+
+ break;
+
+ case TDI_EVENT_ERROR:
+
+ if (Parameters->EventHandler == NULL) {
+ AddressFile->ErrorHandler =
+ (PTDI_IND_ERROR)TdiDefaultErrorHandler;
+ AddressFile->ErrorHandlerContext = NULL;
+ AddressFile->RegisteredErrorHandler = FALSE;
+ } else {
+ AddressFile->ErrorHandler =
+ (PTDI_IND_ERROR)Parameters->EventHandler;
+ AddressFile->ErrorHandlerContext = Parameters->EventContext;
+ AddressFile->RegisteredErrorHandler = TRUE;
+ }
+
+ break;
+
+ default:
+
+ Status = STATUS_INVALID_PARAMETER;
+
+ } /* switch */
+
+ CTEFreeLock (&AddressFile->Address->Lock, LockHandle);
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ REQUEST_INFORMATION(Request) = 0;
+
+ return Status;
+
+} /* IpxTdiSetEventHandler */
+
diff --git a/private/ntos/tdi/isnp/ipx/ind.c b/private/ntos/tdi/isnp/ipx/ind.c
new file mode 100644
index 000000000..f43a524bc
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/ind.c
@@ -0,0 +1,4047 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ ind.c
+
+Abstract:
+
+ This module contains code which implements the indication handler
+ for the IPX transport provider.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports
+
+ 1. Added IpxReceivePacket which receives buffers that can be owned
+ 2. Changed IpxReceiveIndication to call a new function IpxReceiveIndicationNew
+ which takes an extra parameter to indicate whether this is a chained receive or
+ not.
+ 3. Changed IpxProcessDatagram to take the MDL ptr to indicate chained receive,
+ a client count and the headerbuffersize as params.
+
+ Sanjay Anand (SanjayAn) 27-Oct-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// This is declared here so it will be in the same function
+// as IpxReceiveIndication and we can inline it.
+//
+
+
+#if defined(_M_IX86)
+_inline
+#endif
+VOID
+IpxProcessDatagram(
+ IN PDEVICE Device,
+ IN PADAPTER Adapter,
+ IN PBINDING Binding,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_DATAGRAM_OPTIONS DatagramOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize,
+ IN BOOLEAN Broadcast,
+ IN PINT pTdiClientCount,
+ IN UINT HeaderBufferSize,
+ IN PMDL pMdl,
+ IN NDIS_HANDLE BindingContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routing handles incoming IPX datagrams.
+
+Arguments:
+
+ Device - The IPX device.
+
+ Adapter - The adapter the frame was received on.
+
+ Binding - The binding of the adapter it was received on.
+
+ MacReceiveContext - The context to use when calling
+ NdisTransferData.
+
+ DatagramOptions - Contains the datagram options, which
+ consists of room for the packet type, padding, and
+ the local target of the remote the frame was received from.
+
+ LookaheadBuffer - The lookahead data.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The length of the packet, starting at the IPX
+ header.
+
+ Broadcast - TRUE if the packet was broadcast.
+
+ pTdiClientCount - to return count of the number of TDI clients above us
+ so NDIS can obtain that many ref counts on the buffer.
+
+ HeaderBufferSize - the size of the MAC header buffer - used to determine
+ the offsets into the TSDU.
+
+ pMdl - Mdl chain pointer - non-NULL if chained receive
+
+ BindingContext - In case of loopback, this contains IPX_LOOPBACK_COOKIE
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ PIPX_HEADER IpxHeader = (PIPX_HEADER)LookaheadBuffer;
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ PADDRESS_FILE ReferencedAddressFile;
+ PREQUEST Request;
+ PIPX_RECEIVE_BUFFER ReceiveBuffer;
+ PTDI_CONNECTION_INFORMATION DatagramInformation;
+ TDI_ADDRESS_IPX UNALIGNED * DatagramAddress;
+ ULONG IndicateBytesCopied;
+ IPX_ADDRESS_EXTENDED_FLAGS SourceAddress;
+ ULONG SourceAddressLength;
+ ULONG RequestCount;
+ PNDIS_BUFFER NdisBuffer;
+ NDIS_STATUS NdisStatus;
+ NTSTATUS Status;
+ PIRP Irp;
+ UINT ByteOffset, BytesToTransfer;
+ ULONG BytesTransferred;
+ BOOLEAN LastAddressFile;
+ ULONG IndicateOffset;
+ PNDIS_PACKET ReceivePacket;
+ PIPX_RECEIVE_RESERVED Reserved;
+ PLIST_ENTRY p, q;
+ PSINGLE_LIST_ENTRY s;
+ USHORT DestinationSocket;
+ USHORT SourceSocket;
+ ULONG Hash;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // First scan the device's address database, looking for
+ // the destination socket of this frame.
+ //
+
+ DestinationSocket = *(USHORT UNALIGNED *)&IpxHeader->DestinationSocket;
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if ((Address = Device->LastAddress) &&
+ (Address->Socket == DestinationSocket)) {
+
+ //
+ // Device->LastAddress cannot be stopping, so
+ // we use it.
+ //
+
+ IpxReferenceAddressLock (Address, AREF_RECEIVE);
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ goto FoundAddress;
+ }
+
+ Hash = IPX_DEST_SOCKET_HASH (IpxHeader);
+
+ for (p = Device->AddressDatabases[Hash].Flink;
+ p != &Device->AddressDatabases[Hash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ if ((Address->Socket == DestinationSocket) &&
+ (!Address->Stopping)) {
+ IpxReferenceAddressLock (Address, AREF_RECEIVE);
+ Device->LastAddress = Address;
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ goto FoundAddress;
+ }
+ }
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // If we had found an address we would have jumped
+ // past here.
+ //
+
+ return;
+
+FoundAddress:
+
+ SourceSocket = *(USHORT UNALIGNED *)&IpxHeader->SourceSocket;
+ IpxBuildTdiAddress(
+ &SourceAddress.IpxAddress,
+ (*(ULONG UNALIGNED *)(IpxHeader->SourceNetwork) == 0) ?
+ Binding->LocalAddress.NetworkAddress :
+ *(UNALIGNED ULONG *)(IpxHeader->SourceNetwork),
+ IpxHeader->SourceNode,
+ SourceSocket);
+
+ DatagramOptions->PacketType = IpxHeader->PacketType;
+
+
+ //
+ // Now that we have found the address, scan its list of
+ // address files for clients that want this datagram.
+ //
+ // If we have to release the address lock to indicate to
+ // a client, we reference the current address file. If
+ // we get an IRP we transfer the reference to that;
+ // otherwise we store the address file in ReferencedAddressFile
+ // and deref it the next time we release the lock.
+ //
+
+ ReferencedAddressFile = NULL;
+ RequestCount = 0;
+
+ ++Device->TempDatagramsReceived;
+ Device->TempDatagramBytesReceived += (PacketSize - sizeof(IPX_HEADER));
+
+ //
+ // If LastAddressFile is TRUE, it means we did an indication
+ // to the client on the last address file in the address'
+ // list, and we did not reacquire the lock when we were
+ // done.
+ //
+
+ LastAddressFile = FALSE;
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+
+ AddressFile = CONTAINING_RECORD (p, ADDRESS_FILE, Linkage);
+
+ if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
+ continue; // next address file
+ }
+
+ //
+ // Set these to the common values, then change them.
+ //
+
+ SourceAddressLength = sizeof(TA_IPX_ADDRESS);
+ IndicateOffset = sizeof(IPX_HEADER);
+
+ if (AddressFile->SpecialReceiveProcessing) {
+
+ //
+ // On dial out lines, we don't indicate packets to
+ // the SAP socket if DisableDialoutSap is set.
+ //
+
+ if ((AddressFile->IsSapSocket) &&
+ (Binding->DialOutAsync) &&
+ (Device->DisableDialoutSap || Device->SingleNetworkActive)) {
+
+ //
+ // Go to the next address file (although it will
+ // likely fail this test too).
+ //
+
+ continue;
+
+ }
+
+ //
+ // Set this, since generally we want it.
+ //
+
+ SourceAddress.PacketType = IpxHeader->PacketType;
+
+ //
+ // See if we fail a packet type filter.
+ //
+
+ if (AddressFile->FilterOnPacketType) {
+ if (AddressFile->FilteredType != IpxHeader->PacketType) {
+ continue;
+ }
+ }
+
+ //
+ // Calculate how long the addresses expected are.
+ //
+
+ if (AddressFile->ReceiveFlagsAddressing ||
+ AddressFile->ExtendedAddressing) {
+
+ SourceAddress.Flags = 0;
+ if (Broadcast) {
+ SourceAddress.Flags = IPX_EXTENDED_FLAG_BROADCAST;
+ }
+ if (IpxIsAddressLocal((TDI_ADDRESS_IPX UNALIGNED *)
+ &SourceAddress.IpxAddress.Address[0].Address[0])) {
+ SourceAddress.Flags |= IPX_EXTENDED_FLAG_LOCAL;
+ }
+ SourceAddressLength = sizeof(IPX_ADDRESS_EXTENDED_FLAGS);
+ SourceAddress.IpxAddress.Address[0].AddressLength +=
+ (sizeof(IPX_ADDRESS_EXTENDED_FLAGS) - sizeof(TA_IPX_ADDRESS));
+
+ }
+
+ //
+ // Determine how much of the packet the client wants.
+ //
+
+ if (AddressFile->ReceiveIpxHeader) {
+ IndicateOffset = 0;
+ }
+ }
+
+ //
+ // First scan the address' receive datagram queue
+ // for datagrams that match. We do a quick check
+ // to see if the list is empty.
+ //
+
+ q = AddressFile->ReceiveDatagramQueue.Flink;
+ if (q != &AddressFile->ReceiveDatagramQueue) {
+
+ do {
+
+ Request = LIST_ENTRY_TO_REQUEST(q);
+
+ DatagramInformation =
+ ((PTDI_REQUEST_KERNEL_RECEIVEDG)(REQUEST_PARAMETERS(Request)))->
+ ReceiveDatagramInformation;
+
+ if ((DatagramInformation != NULL) &&
+ (DatagramInformation->RemoteAddress != NULL) &&
+ (DatagramAddress = IpxParseTdiAddress(DatagramInformation->RemoteAddress)) &&
+ (DatagramAddress->Socket != SourceSocket)) {
+
+ //
+ // The address that this datagram is looking for is
+ // not satisfied by this frame.
+ //
+ // BUGBUG: Speed this up; worry about node and network?
+ //
+
+ q = q->Flink;
+ continue; // next receive datagram on this address file
+
+ } else {
+
+ //
+ // We found a datagram on the queue.
+ //
+
+ IPX_DEBUG (RECEIVE, ("Found RDG on %lx\n", AddressFile));
+ RemoveEntryList (q);
+ REQUEST_INFORMATION(Request) = 0;
+
+ goto HandleDatagram;
+
+ }
+
+ } while (q != &AddressFile->ReceiveDatagramQueue);
+
+ }
+
+ //
+ // If we found a datagram we would have jumped past here,
+ // so looking for a datagram failed; see if the
+ // client has a receive datagram handler registered.
+ //
+
+ //
+ // Look for the chained receive handler if the MDL is not NULL
+ //
+ if (pMdl && AddressFile->RegisteredChainedReceiveDatagramHandler) {
+
+ //
+ // Chained receive both above and below => we indicate the entire MDL up.
+ // Offset the LookaheadBuffer by the size of the MAC header.
+ //
+ LookaheadBufferOffset += HeaderBufferSize;
+
+ IpxReferenceAddressFileLock (AddressFile, AFREF_INDICATION);
+
+ //
+ // Set this so we can exit without reacquiring
+ // the lock.
+ //
+
+ if (p == &Address->AddressFileDatabase) {
+ LastAddressFile = TRUE;
+ }
+
+ IndicateBytesCopied = 0;
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile) {
+ IpxDereferenceAddressFileSync (ReferencedAddressFile, AFREF_INDICATION);
+ ReferencedAddressFile = NULL;
+ }
+
+ IPX_DEBUG(RECEIVE, ("ChainedIndicate RecvLen: %d, StartOffset: %d, Tsdu: %lx\n",
+ PacketSize - IndicateOffset, IndicateOffset, pMdl));
+
+ //
+ // Will return SUCCESS if the client did not take ownership of the Tsdu
+ // PENDING if the client took ownership and will free it later (using TdiFreeReceiveChain).
+ // DATA_NOT_ACCEPTED if the client did not take ownership and did not copy the data.
+ //
+
+ //
+ // Since NDIS needs an array of PNDIS_PACKETs when the TDI client returns this packet,
+ // we pass the Packet as the ReceiveContext here. The TDI client will pass in the address
+ // of this context on a ReturnPacket.
+ // Also, NDIS needs the PacketArray (not to be confused with the array of packetptrs. mentioned
+ // above) on an NdisTransferData call. These clients dont do this, but other clients like
+ // NB, SPX, RIP or TDI clients that do not have this new interface, can call NdisTransferData
+ // so we pass in the PacketArray as a parameter to them.
+ //
+ Status = (*AddressFile->ChainedReceiveDatagramHandler)(
+ AddressFile->ChainedReceiveDatagramHandlerContext,
+ SourceAddressLength,
+ &SourceAddress,
+ sizeof(IPX_DATAGRAM_OPTIONS),
+ DatagramOptions,
+ Adapter->MacInfo.CopyLookahead, // TdiRcvFlags|Adapter->MacInfo.CopyLookahead, Receive datagram flags
+ PacketSize - IndicateOffset, // ReceiveLength
+ IndicateOffset+LookaheadBufferOffset, // StartingOffset
+ pMdl, // Tsdu - MDL chain
+ (PNDIS_PACKET)MacReceiveContext); // TransportContext - pointer to the packet
+
+ if (Status != STATUS_DATA_NOT_ACCEPTED) {
+
+ if (Status == STATUS_PENDING) {
+ //
+ // We assume here that the client referenced the packet which will
+ // be removed when the packet is freed.
+ // Increment the Tdi client count
+ //
+ (*pTdiClientCount)++;
+ }
+
+ //
+ // The handler accepted the data or did not
+ // return an IRP; in either case there is
+ // nothing else to do, so go to the next
+ // address file.
+ //
+
+ ReferencedAddressFile = AddressFile;
+ if (!LastAddressFile) {
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+
+ } else {
+
+ //
+ // In this case we have no cleanup, so just leave
+ // if there are no datagrams pending.
+ //
+ // RequestCount should always be 0 here.
+ //
+
+
+ //if (RequestCount == 0) {
+ // return;
+ //}
+ goto BreakWithoutLock;
+ }
+
+ } else {
+ //
+ // Since no IRP can be returned here, we continue to the next addressfile
+ //
+
+ ReferencedAddressFile = AddressFile;
+ if (!LastAddressFile) {
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+
+ } else {
+
+ //
+ // In this case we have no cleanup, so just leave
+ // if there are no datagrams pending.
+ //
+
+ //if (RequestCount == 0) {
+ // return;
+ //}
+ goto BreakWithoutLock;
+ }
+ }
+
+ } else if (AddressFile->RegisteredReceiveDatagramHandler) {
+
+ IpxReferenceAddressFileLock (AddressFile, AFREF_INDICATION);
+
+ //
+ // Set this so we can exit without reacquiring
+ // the lock.
+ //
+
+ if (p == &Address->AddressFileDatabase) {
+ LastAddressFile = TRUE;
+ }
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile) {
+ IpxDereferenceAddressFileSync (ReferencedAddressFile, AFREF_INDICATION);
+ ReferencedAddressFile = NULL;
+ }
+
+ IndicateBytesCopied = 0;
+
+ if (PacketSize > LookaheadBufferSize) {
+ IPX_DEBUG(RECEIVE, ("Indicate %d/%d to %lx on %lx\n",
+ LookaheadBufferSize, PacketSize,
+ AddressFile->ReceiveDatagramHandler, AddressFile));
+ }
+
+ Status = (*AddressFile->ReceiveDatagramHandler)(
+ AddressFile->ReceiveDatagramHandlerContext,
+ SourceAddressLength,
+ &SourceAddress,
+ sizeof(IPX_DATAGRAM_OPTIONS),
+ DatagramOptions,
+ Adapter->MacInfo.CopyLookahead,
+ LookaheadBufferSize - IndicateOffset, // indicated
+ PacketSize - IndicateOffset, // available
+ &IndicateBytesCopied, // taken
+ LookaheadBuffer + IndicateOffset, // data
+ &Irp);
+
+
+ if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
+
+ //
+ // The handler accepted the data or did not
+ // return an IRP; in either case there is
+ // nothing else to do, so go to the next
+ // address file.
+ //
+
+ ReferencedAddressFile = AddressFile;
+ if (!LastAddressFile) {
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+
+ } else {
+
+ //
+ // In this case we have no cleanup, so just leave
+ // if there are no datagrams pending.
+ //
+
+ if (RequestCount == 0) {
+ return;
+ }
+ goto BreakWithoutLock;
+ }
+
+ } else {
+
+ //
+ // The client returned an IRP.
+ //
+
+ IPX_DEBUG (RECEIVE, ("Indicate IRP %lx, taken %d\n", Irp, IndicateBytesCopied));
+
+ Request = IpxAllocateRequest (Device, Irp);
+
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ ReferencedAddressFile = AddressFile;
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+ }
+
+ if (!LastAddressFile) {
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+ }
+
+#if DBG
+ //
+ // Make sure the IRP file object is right.
+ //
+
+ if (IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext != AddressFile) {
+ DbgPrint ("IRP %lx does not match AF %lx, H %lx C %lx\n",
+ Irp, AddressFile,
+ AddressFile->ReceiveDatagramHandler,
+ AddressFile->ReceiveDatagramHandlerContext);
+ DbgBreakPoint();
+ }
+#endif
+ //
+ // Set up the information field so we know
+ // how much to skip in it.
+ //
+
+ IpxTransferReferenceAddressFile (AddressFile, AFREF_INDICATION, AFREF_RCV_DGRAM);
+ REQUEST_INFORMATION(Request) = IndicateBytesCopied;
+
+ //
+ // Fall out of the if and continue via
+ // HandleDatagram...
+ //
+
+ }
+
+ } else {
+
+ //
+ // No posted datagram, no handler; go to the next
+ // address file.
+ //
+
+ continue; // next address file
+
+ }
+
+HandleDatagram:
+
+ //
+ // At this point, Request is set to the request
+ // that will hold for this address file, and
+ // REQUEST_INFORMATION() is the offset to start
+ // the transfer at.
+ //
+
+ //
+ // First copy over the source address while it is handy.
+ //
+
+ DatagramInformation =
+ ((PTDI_REQUEST_KERNEL_RECEIVEDG)(REQUEST_PARAMETERS(Request)))->
+ ReturnDatagramInformation;
+
+ if (DatagramInformation != NULL) {
+
+ RtlCopyMemory(
+ DatagramInformation->RemoteAddress,
+ &SourceAddress,
+ (ULONG)DatagramInformation->RemoteAddressLength < SourceAddressLength ?
+ DatagramInformation->RemoteAddressLength : SourceAddressLength);
+ RtlCopyMemory(
+ DatagramInformation->Options,
+ &DatagramOptions,
+ (ULONG)DatagramInformation->OptionsLength < sizeof(IPX_DATAGRAM_OPTIONS) ?
+ DatagramInformation->OptionsLength : sizeof(IPX_DATAGRAM_OPTIONS));
+
+ }
+
+ //
+ // Now check if this is the first request that will
+ // take the data, otherwise queue it up.
+ //
+
+ if (RequestCount == 0) {
+
+ //
+ // First one; we need to allocate a packet for the transfer.
+ //
+
+ //if (Address->ReceivePacketInUse) {
+ if (InterlockedExchangeAdd(&Address->ReceivePacketInUse, 0) != 0) {
+ //
+ // Need a packet, check the pool.
+ //
+
+ s = IpxPopReceivePacket (Device);
+
+ if (s == NULL) {
+
+ //
+ // None in pool, fail the request.
+ //
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_INSUFFICIENT_RESOURCES;
+ IPX_INSERT_TAIL_LIST(
+ &Adapter->RequestCompletionQueue,
+ REQUEST_LINKAGE(Request),
+ Adapter->DeviceLock);
+
+ if (!LastAddressFile) {
+ continue;
+ } else {
+ goto BreakWithoutLock;
+ }
+
+ }
+
+ Reserved = CONTAINING_RECORD (s, IPX_RECEIVE_RESERVED, PoolLinkage);
+ ReceivePacket = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ } else {
+
+ // Address->ReceivePacketInUse = TRUE;
+ InterlockedIncrement(&Address->ReceivePacketInUse);
+
+ ReceivePacket = PACKET(&Address->ReceivePacket);
+ Reserved = RECEIVE_RESERVED(&Address->ReceivePacket);
+
+ }
+
+ CTEAssert (IsListEmpty(&Reserved->Requests));
+
+ Reserved->SingleRequest = Request;
+ NdisBuffer = REQUEST_NDIS_BUFFER(Request);
+
+ ByteOffset = REQUEST_INFORMATION(Request) + LookaheadBufferOffset + IndicateOffset;
+ BytesToTransfer =
+ ((PTDI_REQUEST_KERNEL_RECEIVEDG)(REQUEST_PARAMETERS(Request)))->ReceiveLength;
+
+ if (BytesToTransfer > (PacketSize - IndicateOffset)) {
+ BytesToTransfer = PacketSize - IndicateOffset;
+ }
+
+ } else {
+
+ if (RequestCount == 1) {
+
+ //
+ // There is already one request. We need to
+ // allocate a buffer.
+ //
+
+ s = IpxPopReceiveBuffer (Adapter);
+
+ if (s == NULL) {
+
+ //
+ // No buffers, fail the request.
+ //
+ // BUGBUG: Should we fail the transfer for the
+ // first request too?
+ //
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_INSUFFICIENT_RESOURCES;
+ IPX_INSERT_TAIL_LIST(
+ &Adapter->RequestCompletionQueue,
+ REQUEST_LINKAGE(Request),
+ Adapter->DeviceLock);
+
+ if (!LastAddressFile) {
+ continue;
+ } else {
+ goto BreakWithoutLock;
+ }
+ }
+
+ ReceiveBuffer = CONTAINING_RECORD(s, IPX_RECEIVE_BUFFER, PoolLinkage);
+ NdisBuffer = ReceiveBuffer->NdisBuffer;
+
+ //
+ // Convert this to a queued multiple piece request.
+ //
+
+ InsertTailList(&Reserved->Requests, REQUEST_LINKAGE(Reserved->SingleRequest));
+ Reserved->SingleRequest = NULL;
+ Reserved->ReceiveBuffer = ReceiveBuffer;
+
+ ByteOffset = LookaheadBufferOffset;
+ BytesToTransfer = PacketSize;
+
+ }
+
+ InsertTailList(&Reserved->Requests, REQUEST_LINKAGE(Request));
+
+ }
+
+ //
+ // We are done setting up this address file's transfer,
+ // proceed to the next one.
+ //
+
+ ++RequestCount;
+
+ if (LastAddressFile) {
+ goto BreakWithoutLock;
+ }
+
+ }
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+
+BreakWithoutLock:
+
+ if (ReferencedAddressFile) {
+ IpxDereferenceAddressFileSync (ReferencedAddressFile, AFREF_INDICATION);
+ ReferencedAddressFile = NULL;
+ }
+
+
+ //
+ // We can be transferring directly into a request's buffer,
+ // transferring into an intermediate buffer, or not
+ // receiving the packet at all.
+ //
+
+ if (RequestCount > 0) {
+
+ //
+ // If this is true, then ReceivePacket, Reserved,
+ // and NdisBuffer are all set up correctly.
+ //
+
+ CTEAssert (ReceivePacket);
+ CTEAssert (Reserved == (PIPX_RECEIVE_RESERVED)(ReceivePacket->ProtocolReserved));
+
+
+ NdisChainBufferAtFront(ReceivePacket, NdisBuffer);
+
+ IPX_DEBUG (RECEIVE, ("Transfer into %lx, offset %d bytes %d\n",
+ NdisBuffer, ByteOffset, BytesToTransfer));
+
+ if (BindingContext == (PVOID)IPX_LOOPBACK_COOKIE) {
+
+ IPX_DEBUG (LOOPB, ("Loopback Copy from packet: %lx to packet: %lx\n", ReceivePacket, MacReceiveContext));
+
+ NdisCopyFromPacketToPacket(
+ ReceivePacket, // Destination
+ 0, // DestinationOffset
+ BytesToTransfer, // BytesToCopy
+ (PNDIS_PACKET)MacReceiveContext, // Source
+ ByteOffset, // SourceOffset - loopback packet
+ &BytesTransferred); // BytesCopied
+
+ NdisStatus = NDIS_STATUS_SUCCESS;
+
+ } else {
+ NdisTransferData(
+ &NdisStatus,
+ Adapter->NdisBindingHandle,
+ MacReceiveContext,
+ ByteOffset,
+ BytesToTransfer,
+ ReceivePacket,
+ &BytesTransferred);
+ }
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+
+ IpxTransferDataComplete(
+ (NDIS_HANDLE)Adapter,
+ ReceivePacket,
+ NdisStatus,
+ BytesTransferred);
+ }
+ }
+
+
+ IpxDereferenceAddressSync (Address, AREF_RECEIVE);
+
+} /* IpxProcessDatagram */
+
+
+
+NDIS_STATUS
+IpxReceiveIndication(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a frame has been received on the physical link.
+ This routine is time critical, so we only allocate a
+ buffer and copy the packet into it. We also perform minimal
+ validation on this packet. It gets queued to the device context
+ to allow for processing later.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+ ReceiveContext - A magic cookie for the MAC.
+
+ HeaderBuffer - pointer to a buffer containing the packet header.
+
+ HeaderBufferSize - the size of the header.
+
+ LookaheadBuffer - pointer to a buffer containing the negotiated minimum
+ amount of buffer I get to look at (not including header).
+
+ LookaheadBufferSize - the size of the above. May be less than asked
+ for, if that's all there is.
+
+ PacketSize - Overall size of the packet (not including header).
+
+Return Value:
+
+ NDIS_STATUS - status of operation, one of:
+
+ NDIS_STATUS_SUCCESS if packet accepted,
+ NDIS_STATUS_NOT_RECOGNIZED if not recognized by protocol,
+ NDIS_any_other_thing if I understand, but can't handle.
+
+--*/
+{
+ //
+ // Call the actual receive indication handler and indicate that this is not a
+ // chained receive
+ //
+
+ return IpxReceiveIndicationNew (
+ BindingContext,
+ ReceiveContext, // ReceiveContext
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize, // PacketSize
+ NULL, // pMdl - non-NULL => chained receive.
+ NULL // pTdiClientCount - used in chained recv case to keep count of TDI clients
+ );
+
+}
+
+
+NDIS_STATUS
+IpxReceiveIndicationNew(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize,
+ IN PMDL pMdl,
+ IN PINT pTdiClientCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a frame has been received on the physical link.
+ This routine is time critical, so we only allocate a
+ buffer and copy the packet into it. We also perform minimal
+ validation on this packet. It gets queued to the device context
+ to allow for processing later.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+ ReceiveContext - A magic cookie for the MAC.
+
+ HeaderBuffer - pointer to a buffer containing the packet header.
+
+ HeaderBufferSize - the size of the header.
+
+ LookaheadBuffer - pointer to a buffer containing the negotiated minimum
+ amount of buffer I get to look at (not including header).
+
+ LookaheadBufferSize - the size of the above. May be less than asked
+ for, if that's all there is.
+
+ PacketSize - Overall size of the packet (not including header).
+
+ pMdl - pointer to MDL chain if chained, NULL if this came from indication.
+
+Return Value:
+
+ NDIS_STATUS - status of operation, one of:
+
+ NDIS_STATUS_SUCCESS if packet accepted,
+ NDIS_STATUS_NOT_RECOGNIZED if not recognized by protocol,
+ NDIS_any_other_thing if I understand, but can't handle.
+
+--*/
+{
+
+ IPX_DATAGRAM_OPTIONS DatagramOptions;
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+ PBINDING Binding;
+ PDEVICE Device = IpxDevice;
+ PUCHAR Header = (PUCHAR)HeaderBuffer;
+ PUCHAR Lookahead = (PUCHAR)LookaheadBuffer;
+ ULONG PacketLength;
+ UINT IpxPacketSize;
+ ULONG Length802_3;
+ USHORT Saps;
+ ULONG DestinationNetwork;
+ ULONG SourceNetwork;
+ PUCHAR DestinationNode;
+ USHORT DestinationSocket;
+ ULONG IpxHeaderOffset;
+ PIPX_HEADER IpxHeader;
+ UINT i;
+ BOOLEAN IsBroadcast;
+ BOOLEAN IsLoopback = FALSE;
+#if DBG
+ PUCHAR DestMacAddress;
+ ULONG ReceiveFlag;
+#endif
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif _PNP_POWER
+
+ //
+ // Reject packets that are too short to hold even the
+ // basic IPX header (this ignores any extra 802.2 etc.
+ // headers but is good enough because a runt will fail
+ // the IPX header packet length check).
+ //
+
+ if (PacketSize < sizeof(IPX_HEADER)) {
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // If this is a loopback packet, no need to do figure out the
+ // MAC header.
+ //
+ if (BindingContext == (PVOID)IPX_LOOPBACK_COOKIE) {
+
+#ifdef _PNP_POWER
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_ID_TO_BINDING(IpxDevice, 1);
+
+ if (!Binding) {
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ goto NotValidLoopback;
+ }
+
+ Adapter = Binding->Adapter;
+
+ //
+ // Bump up the ref count so the adapter doesn't disappear from under
+ // us.
+ //
+ IpxReferenceAdapter(Adapter);
+
+ IpxReferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ FILL_LOCAL_TARGET(&DatagramOptions.LocalTarget, 0);
+#else
+ if ((Binding = IpxDevice->Bindings[1]) == NULL) {
+ goto NotValidLoopback;
+ }
+
+ Adapter = Binding->Adapter;
+
+ DatagramOptions.LocalTarget.NicId = 0;
+#endif
+
+ //
+ // Do this copy later, from the IpxHeader.
+ //
+ // RtlCopyMemory (DatagramOptions.LocalTarget.MacAddress, Binding->LocalAddress.NodeAddress, 6);
+
+ if (Binding->Adapter->MacInfo.MediumType == NdisMedium802_5) {
+ DatagramOptions.LocalTarget.MacAddress[0] &= 0x7f;
+ }
+
+ //
+ // Ipx header starts at the top of the LookAheadBuffer
+ //
+ IpxHeaderOffset = 0;
+
+ IPX_DEBUG (LOOPB, ("Loopback packet received: %lx\n", ReceiveContext));
+
+#if DBG
+ DestMacAddress = DatagramOptions.LocalTarget.MacAddress;
+#endif
+
+ IsLoopback = TRUE;
+ goto Loopback;
+ }
+
+#ifdef _PNP_POWER
+ //
+ // Bump up the ref count so the adapter doesn't disappear from under
+ // us.
+ //
+ IpxReferenceAdapter(Adapter);
+#endif
+
+ //
+ // The first step is to construct the 8-byte local
+ // target from the packet. We store it in the 9-byte
+ // datagram options, leaving one byte at the front
+ // for use by IpxProcessDatagram when indicating to
+ // its TDI clients.
+ //
+
+#if DBG
+ Binding = NULL;
+#endif
+
+ if (Adapter->MacInfo.MediumType == NdisMedium802_3) {
+
+ //
+ // Try to figure out what the packet type is.
+ //
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+
+ if (Header[12] < 0x06) {
+
+ //
+ // An 802.3 header; check the next bytes. They may
+ // be E0/E0 (802.2), FFFF (raw 802.3) or A0/A0 (SNAP).
+ //
+
+ Saps = *(UNALIGNED USHORT *)(Lookahead);
+
+ if (Saps == 0xffff) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_3]) == NULL) {
+ goto NotValid802_3;
+ }
+ IpxHeaderOffset = 0;
+ Length802_3 = ((Header[12] << 8) | Header[13]);
+ goto Valid802_3;
+
+ } else if (Saps == 0xe0e0) {
+ if (Lookahead[2] == 0x03) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_2]) == NULL) {
+ goto NotValid802_3;
+ }
+ IpxHeaderOffset = 3;
+ Length802_3 = ((Header[12] << 8) | Header[13]);
+ goto Valid802_3;
+ }
+
+ } else if (Saps == 0xaaaa) {
+
+ if ((Lookahead[2] == 0x03) &&
+ (*(UNALIGNED USHORT *)(Lookahead+6) == Adapter->BindSapNetworkOrder)) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_SNAP]) == NULL) {
+ goto NotValid802_3;
+ }
+ IpxHeaderOffset = 8;
+ Length802_3 = ((Header[12] << 8) | Header[13]);
+ goto Valid802_3;
+ }
+ }
+
+ goto NotValid802_3;
+
+ } else {
+
+ //
+ // It has an ethertype, see if it is ours.
+ //
+
+ if (*(UNALIGNED USHORT *)(Header+12) == Adapter->BindSapNetworkOrder) {
+
+ if (Adapter->MacInfo.MediumAsync) {
+
+ *((ULONG UNALIGNED *)(&Binding)) = *((ULONG UNALIGNED *)(&Header[2]));
+
+ CTEAssert(Binding != NULL);
+
+ if ((Binding != NULL) &&
+ (Binding->LineUp)) {
+
+ IpxHeaderOffset = 0;
+ Length802_3 = PacketSize; // set this so the check succeeds
+
+ //
+ // Check if this is a type 20 packet and
+ // we are disabling them on dialin lines -- we do
+ // this check here to avoid impacting the main
+ // indication path for LANs.
+ //
+ // The 0x02 bit of DisableDialinNetbios controls
+ // WAN->LAN packets, which we handle here.
+ //
+
+ if ((!Binding->DialOutAsync) &&
+ ((Device->DisableDialinNetbios & 0x02) != 0)) {
+
+ IpxHeader = (PIPX_HEADER)Lookahead; // IpxHeaderOffset is 0
+ if (IpxHeader->PacketType == 0x14) {
+#ifdef _PNP_POWER
+ IpxDereferenceAdapter(Adapter);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ return STATUS_SUCCESS;
+ }
+ }
+
+ goto Valid802_3;
+ }
+ goto NotValid802_3;
+
+ } else if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_ETHERNET_II]) == NULL) {
+ goto NotValid802_3;
+ }
+
+ IpxHeaderOffset = 0;
+ Length802_3 = PacketSize; // set this so the check succeeds
+ goto Valid802_3;
+
+ }
+ }
+
+ goto NotValid802_3;
+
+Valid802_3:
+
+ if (Length802_3 > PacketSize) {
+ goto NotValid802_3;
+ } else if (Length802_3 < PacketSize) {
+ PacketSize = Length802_3;
+ if (LookaheadBufferSize > Length802_3) {
+ LookaheadBufferSize = Length802_3;
+ }
+ }
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ RtlCopyMemory (DatagramOptions.LocalTarget.MacAddress, Header+6, 6);
+#if DBG
+ DestMacAddress = Header;
+#endif
+
+ } else if (Adapter->MacInfo.MediumType == NdisMedium802_5) {
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ Saps = *(USHORT UNALIGNED *)(Lookahead);
+
+ if (Saps == 0xe0e0) {
+
+ if (Lookahead[2] == 0x03) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_2]) == NULL) {
+ goto NotValid802_5;
+ }
+
+ IpxHeaderOffset = 3;
+ goto Valid802_5;
+ }
+
+ } else if (Saps == 0xaaaa) {
+
+ if ((Lookahead[2] == 0x03) &&
+ (*(UNALIGNED USHORT *)(Lookahead+6) == Adapter->BindSapNetworkOrder)) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_SNAP]) == NULL) {
+ goto NotValid802_5;
+ }
+ IpxHeaderOffset = 8;
+ goto Valid802_5;
+ }
+ }
+
+ goto NotValid802_5;
+
+Valid802_5:
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ RtlCopyMemory (DatagramOptions.LocalTarget.MacAddress, Header+8, 6);
+ DatagramOptions.LocalTarget.MacAddress[0] &= 0x7f;
+
+#if DBG
+ DestMacAddress = Header+2;
+#endif
+
+ } else if (Adapter->MacInfo.MediumType == NdisMediumFddi) {
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ Saps = *(USHORT UNALIGNED *)(Lookahead);
+
+ if (Saps == 0xe0e0) {
+
+ if (Lookahead[2] == 0x03) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_2]) == NULL) {
+ goto NotValidFddi;
+ }
+ IpxHeaderOffset = 3;
+ goto ValidFddi;
+ }
+
+ } else if (Saps == 0xffff) {
+
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_3]) == NULL) {
+ goto NotValidFddi;
+ }
+ IpxHeaderOffset = 0;
+ goto ValidFddi;
+
+ } else if (Saps == 0xaaaa) {
+
+ if ((Lookahead[2] == 0x03) &&
+ (*(UNALIGNED USHORT *)(Lookahead+6) == Adapter->BindSapNetworkOrder)) {
+
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_SNAP]) == NULL) {
+ goto NotValidFddi;
+ }
+ IpxHeaderOffset = 8;
+ goto ValidFddi;
+ }
+ }
+
+ goto NotValidFddi;
+
+ValidFddi:
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ RtlCopyMemory (DatagramOptions.LocalTarget.MacAddress, Header+7, 6);
+
+#if DBG
+ DestMacAddress = Header+1;
+#endif
+
+
+ } else {
+
+ //
+ // NdisMediumArcnet878_2
+ //
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ if ((Header[2] == ARCNET_PROTOCOL_ID) &&
+ ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_3]) != NULL)) {
+
+ IpxHeaderOffset = 0;
+ RtlZeroMemory (DatagramOptions.LocalTarget.MacAddress, 5);
+ DatagramOptions.LocalTarget.MacAddress[5] = Header[0];
+
+ } else {
+
+#ifdef _PNP_POWER
+ IpxDereferenceAdapter(Adapter);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(IPX_PACKET_LOG_RCV_ALL)) {
+ IpxLogPacket(FALSE, Header+2, Header+1, (USHORT)PacketSize, LookaheadBuffer, (PUCHAR)LookaheadBuffer + sizeof(IPX_HEADER));
+ }
+#endif
+ return NDIS_STATUS_SUCCESS;
+ }
+
+#if DBG
+ DestMacAddress = Header+2; // BUGBUG Need to log less than six bytes
+#endif
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ }
+
+ //
+ // Make sure this didn't slip through.
+ //
+
+ CTEAssert (Binding != NULL);
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&DatagramOptions.LocalTarget, MIN( Device->MaxBindings, Binding->NicId));
+#else
+ DatagramOptions.LocalTarget.NicId = Binding->NicId;
+#endif
+
+Loopback:
+
+ //
+ // Now that we have validated the header and constructed
+ // the local target, indicate the packet to the correct
+ // client.
+ //
+
+ IpxHeader = (PIPX_HEADER)(Lookahead + IpxHeaderOffset);
+
+ PacketLength = (IpxHeader->PacketLength[0] << 8) | IpxHeader->PacketLength[1];
+
+ IpxPacketSize = PacketSize - IpxHeaderOffset;
+
+ if (PacketLength > IpxPacketSize) {
+
+#ifdef _PNP_POWER
+ IpxDereferenceAdapter(Adapter);
+ IpxDereferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+#endif
+
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(IPX_PACKET_LOG_RCV_ALL)) {
+ IpxLogPacket(FALSE, DestMacAddress, DatagramOptions.LocalTarget.MacAddress, (USHORT)PacketSize, IpxHeader, IpxHeader+1);
+ }
+#endif
+ IPX_DEBUG (BAD_PACKET, ("Packet len %d, IPX len %d\n",
+ PacketLength, IpxPacketSize));
+
+ return NDIS_STATUS_SUCCESS;
+
+ } else if (PacketLength < IpxPacketSize) {
+
+ IpxPacketSize = PacketLength;
+ if (LookaheadBufferSize > (PacketLength + IpxHeaderOffset)) {
+ LookaheadBufferSize = PacketLength + IpxHeaderOffset;
+ }
+
+ }
+
+ //
+ // Bug #33595 - (hotfixed in 3.51, checked into 4.0 beta2)
+ // Customer problem where NT allowed RIP/SAP to reply to an 802.5 functional address in the IPX source node. The source
+ // MAC address was proper in this case. We need to check for the case where if the packet's source network is the same
+ // as that of the binding it came on (=> did not come thru a router), then the SourceNodeAddress in the IPX header
+ // should be equal to the SourceAddress in the MAC header.
+ //
+ // This check is controlled through a registry value - VerifySourceAddress.
+ // In case of Arcnet, this check will not succeed.
+ // Also, for WAN, the node addresses will not match, so avoid check for those.
+
+ //
+ // If the source network is 0, we drop it. Auto-detect frames should have matching node (MAC) addresses.
+ // Loopback packets dont have a valid header, so skip this test for them.
+ //
+ // BUGBUG: For loopback pkts, do all the processing above, so we can avoid all these checks for IsLoopback here.
+ // Also, to prevent the RtlCopyMemory into the localtarget above, try to use the MAC header to indicate the
+ // correct binding to us so we dont use the first one always.
+ //
+ // CAVEAT:: when using the MAC header as a binding pointer, ensure that we use the adapter corresp, to that binding
+ // to enque all the receive requests. currently we enqueue them onto the first bindings adapter.
+ //
+ if (((*(UNALIGNED ULONG *)IpxHeader->SourceNetwork == Binding->LocalAddress.NetworkAddress) ||
+ (*(UNALIGNED ULONG *)IpxHeader->SourceNetwork == 0)) &&
+ (!IPX_NODE_EQUAL (IpxHeader->SourceNode, DatagramOptions.LocalTarget.MacAddress)) &&
+ Device->VerifySourceAddress &&
+ !IsLoopback &&
+ !Adapter->MacInfo.MediumAsync &&
+ (Adapter->MacInfo.MediumType != NdisMediumArcnet878_2)) {
+
+ IPX_DEBUG(BAD_PACKET, ("Local packet: Src MAC %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x ",
+ DatagramOptions.LocalTarget.MacAddress[0],
+ DatagramOptions.LocalTarget.MacAddress[1],
+ DatagramOptions.LocalTarget.MacAddress[2],
+ DatagramOptions.LocalTarget.MacAddress[3],
+ DatagramOptions.LocalTarget.MacAddress[4],
+ DatagramOptions.LocalTarget.MacAddress[5]));
+
+ IPX_DEBUG(BAD_PACKET, ("IPX Src Node %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ IpxHeader->SourceNode[0],
+ IpxHeader->SourceNode[1],
+ IpxHeader->SourceNode[2],
+ IpxHeader->SourceNode[3],
+ IpxHeader->SourceNode[4],
+ IpxHeader->SourceNode[5]));
+
+#ifdef IPX_PACKET_LOG
+ ReceiveFlag = IPX_PACKET_LOG_RCV_ALL;
+ if (PACKET_LOG(ReceiveFlag)) {
+ IpxLogPacket(
+ FALSE,
+ DestMacAddress,
+ DatagramOptions.LocalTarget.MacAddress,
+ (USHORT)IpxPacketSize,
+ IpxHeader,
+ IpxHeader+1);
+ }
+#endif
+
+#ifdef _PNP_POWER
+ IpxDereferenceAdapter(Adapter);
+ IpxDereferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+#endif
+
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ DestinationSocket = *(USHORT UNALIGNED *)&IpxHeader->DestinationSocket;
+
+ //
+ // In order to have consistent local targets, copy over the target from the IpxHeader.
+ //
+ if (IsLoopback) {
+ IPX_DEBUG (LOOPB, ("Loopback packet copied the localtarget: %lx\n", IpxHeader->DestinationNode));
+ // RtlCopyMemory (DatagramOptions.LocalTarget.MacAddress, IpxHeader->DestinationNode, 6);
+
+ *((UNALIGNED ULONG *)DatagramOptions.LocalTarget.MacAddress) =
+ *((UNALIGNED ULONG *)IpxHeader->DestinationNode);
+
+ *((UNALIGNED USHORT *)(DatagramOptions.LocalTarget.MacAddress+4)) =
+ *((UNALIGNED USHORT *)(IpxHeader->DestinationNode+4));
+ }
+
+ ++Device->Statistics.PacketsReceived;
+
+ if (DestinationSocket != RIP_SOCKET) {
+
+ DestinationNetwork = *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork;
+ DestinationNode = IpxHeader->DestinationNode;
+
+RecheckPacket:
+
+ if (Device->MultiCardZeroVirtual) {
+
+ if ((DestinationNetwork == Binding->LocalAddress.NetworkAddress) ||
+ (DestinationNetwork == 0)) {
+
+ if (IPX_NODE_EQUAL (DestinationNode, Binding->LocalAddress.NodeAddress)) {
+ IsBroadcast = FALSE;
+ goto DestinationOk;
+ } else {
+ if ((IsBroadcast = IPX_NODE_BROADCAST(DestinationNode)) &&
+ (Binding->ReceiveBroadcast)) {
+ goto DestinationOk;
+ }
+ }
+
+ //
+ // If this is a binding set slave, check for the master's
+ // address.
+ //
+
+ if ((Binding->BindingSetMember) &&
+ (IPX_NODE_EQUAL (DestinationNode, Binding->MasterBinding->LocalAddress.NodeAddress))) {
+ goto DestinationOk;
+ }
+
+ } else {
+ IsBroadcast = IPX_NODE_BROADCAST(DestinationNode);
+ }
+
+ } else {
+
+ if ((DestinationNetwork == Device->SourceAddress.NetworkAddress) ||
+ (DestinationNetwork == 0)) {
+
+ if (IPX_NODE_EQUAL (DestinationNode, Device->SourceAddress.NodeAddress)) {
+ IsBroadcast = FALSE;
+ goto DestinationOk;
+ } else {
+ if ((IsBroadcast = IPX_NODE_BROADCAST(DestinationNode)) &&
+ (Binding->ReceiveBroadcast)) {
+ goto DestinationOk;
+ }
+ }
+ } else {
+ IsBroadcast = IPX_NODE_BROADCAST(DestinationNode);
+ }
+
+ //
+ // We need to check for frames that are sent to the
+ // binding node and net, because if we have a virtual
+ // net we won't catch them in the check above. This
+ // will include any Netbios frames, since they don't
+ // use the virtual net. Doing the check like this will slow
+ // down netbios indications just a bit on a machine with
+ // a virtual network, but it saves a jump for other traffic
+ // vs. adding the check up there (the assumption is if we
+ // have a virtual net most traffic is NCP).
+ //
+ // Note that IsBroadcast is already set, so we don't have
+ // to do that.
+ //
+
+ if ((Device->VirtualNetwork) &&
+ ((DestinationNetwork == Binding->LocalAddress.NetworkAddress) ||
+ (DestinationNetwork == 0))) {
+
+ if (IPX_NODE_EQUAL (DestinationNode, Binding->LocalAddress.NodeAddress)) {
+ goto DestinationOk;
+ } else {
+ if (IsBroadcast && (Binding->ReceiveBroadcast)) {
+ goto DestinationOk;
+ }
+
+ }
+
+ //
+ // If this is a binding set slave, check for the master's
+ // address.
+ //
+
+ if ((Binding->BindingSetMember) &&
+ (IPX_NODE_EQUAL (DestinationNode, Binding->MasterBinding->LocalAddress.NodeAddress))) {
+ goto DestinationOk;
+ }
+ }
+ }
+
+ //
+ // If this was a loopback packet that was sent on the second binding (but showed back up on the first one),
+ // then the networknumbers will not match. Allow the receive on the first binding itself.
+ //
+ if (IsLoopback) {
+ IPX_DEBUG (LOOPB, ("Loopback packet forced on first binding: %lx\n", ReceiveContext));
+ goto DestinationOk;
+ }
+
+ //
+ // If we did not receive this packet, it might be because
+ // our network is still 0 and this packet was actually
+ // sent to the real network number. If so we try to
+ // update our local address, and if successful we
+ // re-check the packet. We don't insert if we are
+ // not done with auto detection, to avoid colliding
+ // with that.
+ //
+ // To avoid problems if we are a router, we only update
+ // on packets that are broadcast or sent to us.
+ //
+
+ if ((Binding->LocalAddress.NetworkAddress == 0) &&
+ (Device->AutoDetectState == AUTO_DETECT_STATE_DONE) &&
+ (DestinationNetwork != 0) &&
+ (IsBroadcast ||
+ IPX_NODE_EQUAL (DestinationNode, Binding->LocalAddress.NodeAddress))) {
+
+ CTEAssert (Binding->NicId != 0);
+
+ if (IpxUpdateBindingNetwork(
+ Device,
+ Binding,
+ DestinationNetwork) == STATUS_SUCCESS) {
+
+ IPX_DEBUG (RIP, ("Binding %d reconfigured to network %lx\n",
+ Binding->NicId,
+ REORDER_ULONG(Binding->LocalAddress.NetworkAddress)));
+
+ //
+ // Jump back and re-process the packet; we know
+ // we won't loop through here again because the
+ // binding's network is now non-zero.
+ //
+
+ goto RecheckPacket;
+
+ }
+ }
+
+
+ //
+ // The only frames that will not already have jumped to
+ // DestinationOk are those to or from the SAP socket,
+ // so we check for those.
+ //
+
+ if ((*(USHORT UNALIGNED *)&IpxHeader->SourceSocket == SAP_SOCKET) ||
+ (DestinationSocket == SAP_SOCKET)) {
+
+DestinationOk:
+
+ //
+ // An IPX packet sent to us, or a SAP packet (which
+ // are not sent to the virtual address but still need
+ // to be indicated and not forwarded to RIP).
+ //
+
+ if (DestinationSocket == NB_SOCKET) {
+#if DBG
+ ReceiveFlag = IPX_PACKET_LOG_RCV_NB | IPX_PACKET_LOG_RCV_ALL;
+#endif
+ if (((!IsBroadcast) || (Device->UpperDrivers[IDENTIFIER_NB].BroadcastEnable)) &&
+ (Device->UpperDriverBound[IDENTIFIER_NB])) {
+
+ if (!IsLoopback && Adapter->MacInfo.MediumType == NdisMedium802_5) {
+ MacUpdateSourceRouting (IDENTIFIER_NB, Adapter, Header, HeaderBufferSize);
+ }
+
+ //
+ // We add HeaderBufferSize to the IpxHeaderOffset field since we do an NdisCopyFromPacketToPacket
+ // in IpxTransferData, which needs offset from the beginning of the packet.
+ // NdisTransferData adds the offset passed in to the beginning of the IPX packet.
+ //
+ (*Device->UpperDrivers[IDENTIFIER_NB].ReceiveHandler)(
+ (IsLoopback) ? BindingContext : Adapter->NdisBindingHandle,
+ ReceiveContext,
+ &DatagramOptions.LocalTarget,
+ Adapter->MacInfo.MacOptions,
+ (PUCHAR)IpxHeader,
+ LookaheadBufferSize - IpxHeaderOffset,
+ (IsLoopback) ? IpxHeaderOffset+HeaderBufferSize : IpxHeaderOffset,
+ IpxPacketSize);
+
+ Device->ReceiveCompletePending[IDENTIFIER_NB] = TRUE;
+ }
+
+ //
+ // The router needs to see Netbios type 20 broadcasts.
+ //
+
+ if (IsBroadcast &&
+ (IpxHeader->PacketType == 0x14) &&
+ (Binding->ReceiveBroadcast)) {
+ goto RipIndication;
+ }
+
+ } else if (IpxHeader->PacketType == SPX_PACKET_TYPE) {
+
+#if DBG
+ ReceiveFlag = IPX_PACKET_LOG_RCV_SPX | IPX_PACKET_LOG_RCV_ALL;
+#endif
+
+ if (((!IsBroadcast) || (Device->UpperDrivers[IDENTIFIER_SPX].BroadcastEnable)) &&
+ (Device->UpperDriverBound[IDENTIFIER_SPX])) {
+
+ if (!IsLoopback && Adapter->MacInfo.MediumType == NdisMedium802_5) {
+ MacUpdateSourceRouting (IDENTIFIER_SPX, Adapter, Header, HeaderBufferSize);
+ }
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].ReceiveHandler)(
+ (IsLoopback) ? BindingContext : Adapter->NdisBindingHandle,
+ ReceiveContext,
+ &DatagramOptions.LocalTarget,
+ Adapter->MacInfo.MacOptions,
+ (PUCHAR)IpxHeader,
+ LookaheadBufferSize - IpxHeaderOffset,
+ (IsLoopback) ? IpxHeaderOffset+HeaderBufferSize : IpxHeaderOffset,
+ IpxPacketSize);
+
+ Device->ReceiveCompletePending[IDENTIFIER_SPX] = TRUE;
+ }
+
+ } else {
+
+ IPX_DEBUG (RECEIVE, ("Received packet type %d, length %d\n",
+ Binding->FrameType,
+ IpxPacketSize));
+ IPX_DEBUG (RECEIVE, ("Source %lx %2.2x-%2.2x-%2.2x-%2.2x %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ *(USHORT UNALIGNED *)&IpxHeader->SourceSocket,
+ IpxHeader->SourceNetwork[0],
+ IpxHeader->SourceNetwork[1],
+ IpxHeader->SourceNetwork[2],
+ IpxHeader->SourceNetwork[3],
+ IpxHeader->SourceNode[0],
+ IpxHeader->SourceNode[1],
+ IpxHeader->SourceNode[2],
+ IpxHeader->SourceNode[3],
+ IpxHeader->SourceNode[4],
+ IpxHeader->SourceNode[5]));
+ IPX_DEBUG (RECEIVE, ("Destination %d %2.2x-%2.2x-%2.2x-%2.2x %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ DestinationSocket,
+ IpxHeader->DestinationNetwork[0],
+ IpxHeader->DestinationNetwork[1],
+ IpxHeader->DestinationNetwork[2],
+ IpxHeader->DestinationNetwork[3],
+ IpxHeader->DestinationNode[0],
+ IpxHeader->DestinationNode[1],
+ IpxHeader->DestinationNode[2],
+ IpxHeader->DestinationNode[3],
+ IpxHeader->DestinationNode[4],
+ IpxHeader->DestinationNode[5]));
+
+#if DBG
+ if (IpxHeader->DestinationSocket == IpxPacketLogSocket) {
+ ReceiveFlag = IPX_PACKET_LOG_RCV_SOCKET | IPX_PACKET_LOG_RCV_OTHER | IPX_PACKET_LOG_RCV_ALL;
+ } else {
+ ReceiveFlag = IPX_PACKET_LOG_RCV_OTHER | IPX_PACKET_LOG_RCV_ALL;
+ }
+#endif
+
+ //
+ // Fiddle with this if so in the general case
+ // the jump is not made (BUGBUG the compiler
+ // still rearranges it).
+ //
+
+ if (Adapter->MacInfo.MediumType != NdisMedium802_5) {
+
+CallProcessDatagram:
+ //
+ // [SA] Returns a status now which needs to be returned to NDIS
+ // Also, MDL is passed in.
+ // We need to pass in the HeaderBufferSize too....
+ //
+ IpxProcessDatagram(
+ Device,
+ Adapter,
+ Binding,
+ ReceiveContext,
+ &DatagramOptions,
+ (PUCHAR)IpxHeader,
+ LookaheadBufferSize - IpxHeaderOffset,
+ (IsLoopback) ? IpxHeaderOffset+HeaderBufferSize : IpxHeaderOffset, // lookaheadbufferoffset
+ IpxPacketSize,
+ IsBroadcast,
+ pTdiClientCount,
+ HeaderBufferSize,
+ pMdl,
+ BindingContext);
+
+ } else {
+ if (!IsLoopback) {
+ MacUpdateSourceRouting (IDENTIFIER_IPX, Adapter, Header, HeaderBufferSize);
+ }
+ goto CallProcessDatagram;
+ }
+
+ //
+ // The router needs to see type 20 broadcasts.
+ //
+
+ if (IsBroadcast &&
+ (IpxHeader->PacketType == 0x14) &&
+ (Binding->ReceiveBroadcast)) {
+ goto RipIndication;
+ }
+ }
+
+ } else {
+
+#if DBG
+ ReceiveFlag = IPX_PACKET_LOG_RCV_ALL;
+#endif
+
+ //
+ // We need to let non-type 20 broadcast frames go to RIP to allow for lan-specific
+ // broadcasts. For logon over IPX, this allows the logon request to get thru the WAN
+ // line.
+ //
+ // if ( !IsBroadcast ) {
+
+RipIndication:;
+
+ if (Device->UpperDriverBound[IDENTIFIER_RIP]) {
+
+ if (!IsLoopback && Adapter->MacInfo.MediumType == NdisMedium802_5) {
+ MacUpdateSourceRouting (IDENTIFIER_RIP, Adapter, Header, HeaderBufferSize);
+ }
+
+ //
+ // We hide binding sets from the router, to avoid
+ // misordering packets which it routes.
+ //
+
+ if (!IsLoopback && Binding->BindingSetMember) {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&DatagramOptions.LocalTarget, MIN (Device->MaxBindings, Binding->MasterBinding->NicId));
+#else
+ DatagramOptions.LocalTarget.NicId = Binding->MasterBinding->NicId;
+#endif
+ }
+
+ (*Device->UpperDrivers[IDENTIFIER_RIP].ReceiveHandler)(
+ (IsLoopback) ? BindingContext : Adapter->NdisBindingHandle,
+ ReceiveContext,
+ &DatagramOptions.LocalTarget,
+ Adapter->MacInfo.MacOptions,
+ (PUCHAR)IpxHeader,
+ LookaheadBufferSize - IpxHeaderOffset,
+ (IsLoopback) ? IpxHeaderOffset+HeaderBufferSize : IpxHeaderOffset,
+ IpxPacketSize);
+
+ Device->ReceiveCompletePending[IDENTIFIER_RIP] = TRUE;
+ }
+ // }
+ }
+
+ } else {
+
+ if ((Binding->ReceiveBroadcast) ||
+ (!IPX_NODE_BROADCAST(IpxHeader->DestinationNode))) {
+
+ SourceNetwork = *(UNALIGNED LONG *)IpxHeader->SourceNetwork;
+
+ //
+ // Sent to the RIP socket; check if this binding needs a
+ // network number.
+ //
+
+ if ((Binding->LocalAddress.NetworkAddress == 0) &&
+ ((SourceNetwork = *(UNALIGNED LONG *)IpxHeader->SourceNetwork) != 0)) {
+
+ switch (Device->AutoDetectState) {
+
+ case AUTO_DETECT_STATE_DONE:
+
+ //
+ // We are done with auto-detect and running.
+ // Make sure this packet is useful. If the source
+ // MAC address and source IPX node are the same then
+ // it was not routed, and we also check that it is not
+ // an IPX broadcast (otherwise a misconfigured client
+ // might confuse us).
+ //
+
+ if ((RtlEqualMemory(
+ IpxHeader->SourceNode,
+ DatagramOptions.LocalTarget.MacAddress,
+ 6)) &&
+ (*(UNALIGNED ULONG *)(IpxHeader->DestinationNode) != 0xffffffff) &&
+ (*(UNALIGNED USHORT *)(IpxHeader->DestinationNode+4) != 0xffff)) {
+
+ CTEAssert (Binding->NicId != 0);
+
+ if (IpxUpdateBindingNetwork(
+ Device,
+ Binding,
+ *(UNALIGNED LONG *)IpxHeader->SourceNetwork) == STATUS_SUCCESS) {
+
+ IPX_DEBUG (RIP, ("Binding %d is network %lx\n",
+ Binding->NicId,
+ REORDER_ULONG(Binding->LocalAddress.NetworkAddress)));
+
+ }
+ }
+
+ break;
+
+ case AUTO_DETECT_STATE_RUNNING:
+
+ //
+ // We are waiting for rip responses to figure out our
+ // network number. We count the responses that match
+ // and do not match our current value; when the non-
+ // matching number exceeds it we switch (to whatever
+ // this frame happens to have). Note that on the first
+ // non-zero response this will be the case and we will
+ // switch to that network.
+ //
+ // After auto-detect is done we call RipInsertLocalNetwork
+ // for whatever the current network is on each binding.
+ //
+
+ if (SourceNetwork == Binding->TentativeNetworkAddress) {
+
+ ++Binding->MatchingResponses;
+
+ } else {
+
+ ++Binding->NonMatchingResponses;
+
+ if (Binding->NonMatchingResponses > Binding->MatchingResponses) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Switching to net %lx on %lx (%d - %d)\n",
+ REORDER_ULONG(SourceNetwork),
+ Binding,
+ Binding->NonMatchingResponses,
+ Binding->MatchingResponses));
+
+ Binding->TentativeNetworkAddress = SourceNetwork;
+ Binding->MatchingResponses = 1;
+ Binding->NonMatchingResponses = 0;
+ }
+
+ }
+
+ //
+ // If we are auto-detecting and we have just found
+ // a default, set this so that RIP stops trying
+ // to auto-detect on other nets. BUGBUG: Unless we
+ // are on a server doing multiple detects.
+ //
+
+ if (Binding->DefaultAutoDetect) {
+ Adapter->DefaultAutoDetected = TRUE;
+ }
+ Adapter->AutoDetectResponse = TRUE;
+
+ break;
+
+ default:
+
+ //
+ // We are still initializing, or are processing auto-detect
+ // responses, not the right time to start updating stuff.
+ //
+
+ break;
+
+ }
+
+ }
+
+
+ //
+ // See if any packets are waiting for a RIP response.
+ //
+
+ if (Device->RipPacketCount > 0) {
+
+ RIP_PACKET UNALIGNED * RipPacket = (RIP_PACKET UNALIGNED *)(IpxHeader+1);
+
+ if ((IpxPacketSize >= sizeof(IPX_HEADER) + sizeof(RIP_PACKET)) &&
+ (RipPacket->Operation == RIP_RESPONSE) &&
+ (RipPacket->NetworkEntry.NetworkNumber != 0xffffffff)) {
+
+ RipProcessResponse(
+ Device,
+ &DatagramOptions.LocalTarget,
+ RipPacket);
+ }
+ }
+
+
+ //
+ // See if this is a RIP response for our virtual network
+ // and we are the only person who could respond to it.
+ // We also respond to general queries on WAN lines since
+ // we are the only machine on it.
+ //
+
+ if (Device->RipResponder) {
+
+ PRIP_PACKET RipPacket =
+ (PRIP_PACKET)(IpxHeader+1);
+
+ if ((IpxPacketSize >= sizeof(IPX_HEADER) + sizeof(RIP_PACKET)) &&
+ (RipPacket->Operation == RIP_REQUEST) &&
+ ((RipPacket->NetworkEntry.NetworkNumber == Device->VirtualNetworkNumber) ||
+ (Adapter->MacInfo.MediumAsync && (RipPacket->NetworkEntry.NetworkNumber == 0xffffffff)))) {
+
+ //
+ // Update this so our response goes out correctly.
+ //
+
+ if (!IsLoopback && Adapter->MacInfo.MediumType == NdisMedium802_5) {
+ MacUpdateSourceRouting (IDENTIFIER_IPX, Adapter, Header, HeaderBufferSize);
+ }
+
+ RipSendResponse(
+ Binding,
+ (TDI_ADDRESS_IPX UNALIGNED *)(IpxHeader->SourceNetwork),
+ &DatagramOptions.LocalTarget);
+ }
+ }
+
+#if DBG
+ ReceiveFlag = IPX_PACKET_LOG_RCV_RIP | IPX_PACKET_LOG_RCV_ALL;
+#endif
+
+ //
+ // See if the RIP upper driver wants it too.
+ //
+
+ goto RipIndication;
+ }
+
+ }
+
+
+#ifdef _PNP_POWER
+ IpxDereferenceAdapter(Adapter);
+ IpxDereferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+#endif
+
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(ReceiveFlag)) {
+ IpxLogPacket(
+ FALSE,
+ DestMacAddress,
+ DatagramOptions.LocalTarget.MacAddress,
+ (USHORT)IpxPacketSize,
+ IpxHeader,
+ IpxHeader+1);
+ }
+#endif
+ return NDIS_STATUS_SUCCESS;
+
+ //
+ // These are the failure routines for the various media types.
+ // They only differ in the debug logging.
+ //
+
+NotValid802_3:
+
+#ifdef _PNP_POWER
+
+ IpxDereferenceAdapter(Adapter);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(IPX_PACKET_LOG_RCV_ALL)) {
+ IpxLogPacket(FALSE, Header, Header+6, (USHORT)PacketSize, LookaheadBuffer, (PUCHAR)LookaheadBuffer + sizeof(IPX_HEADER));
+ }
+#endif
+ return NDIS_STATUS_SUCCESS;
+
+NotValid802_5:
+
+#ifdef _PNP_POWER
+
+ IpxDereferenceAdapter(Adapter);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(IPX_PACKET_LOG_RCV_ALL)) {
+ IpxLogPacket(FALSE, Header+2, Header+8, (USHORT)PacketSize, LookaheadBuffer, (PUCHAR)LookaheadBuffer + sizeof(IPX_HEADER));
+ }
+#endif
+ return NDIS_STATUS_SUCCESS;
+
+NotValidFddi:
+
+#ifdef _PNP_POWER
+
+ IpxDereferenceAdapter(Adapter);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+NotValidLoopback:
+
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(IPX_PACKET_LOG_RCV_ALL)) {
+ IpxLogPacket(FALSE, Header+1, Header+7, (USHORT)PacketSize, LookaheadBuffer, (PUCHAR)LookaheadBuffer + sizeof(IPX_HEADER));
+ }
+#endif
+
+ return NDIS_STATUS_SUCCESS;
+
+} /* IpxReceiveIndication */
+
+
+VOID
+IpxReceiveComplete(
+ IN NDIS_HANDLE BindingContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a connection(less) frame has been received on the
+ physical link. We dispatch to the correct packet handler here.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+ PREQUEST Request;
+ PADDRESS_FILE AddressFile;
+ PLIST_ENTRY linkage;
+
+
+ //
+ // Complete all pending receives. Do a quick check
+ // without the lock.
+ //
+
+ while (!IsListEmpty (&Adapter->RequestCompletionQueue)) {
+
+ linkage = IPX_REMOVE_HEAD_LIST(
+ &Adapter->RequestCompletionQueue,
+ Adapter->DeviceLock);
+
+ if (!IPX_LIST_WAS_EMPTY (&Adapter->RequestCompletionQueue, linkage)) {
+
+ Request = LIST_ENTRY_TO_REQUEST(linkage);
+ AddressFile = REQUEST_OPEN_CONTEXT(Request);
+
+ IPX_DEBUG (RECEIVE, ("Completing RDG on %lx\n", AddressFile));
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ IpxCompleteRequest(Request);
+ IpxFreeRequest(Adapter->Device, Request);
+
+ IpxDereferenceAddressFileSync (AddressFile, AFREF_RCV_DGRAM);
+
+ } else {
+
+ //
+ // IPX_REMOVE_HEAD_LIST returned nothing, so don't
+ // bother looping back.
+ //
+
+ break;
+
+ }
+
+ }
+
+ //
+ // Unwind this loop for speed.
+ //
+
+ if (IpxDevice->AnyUpperDriverBound) {
+
+ PDEVICE Device = IpxDevice;
+
+ if ((Device->UpperDriverBound[0]) &&
+ (Device->ReceiveCompletePending[0])) {
+
+ (*Device->UpperDrivers[0].ReceiveCompleteHandler)(
+ (USHORT)1); // BUGBUG: Fix NIC ID or remove.
+ Device->ReceiveCompletePending[0] = FALSE;
+
+ }
+
+ if ((Device->UpperDriverBound[1]) &&
+ (Device->ReceiveCompletePending[1])) {
+
+ (*Device->UpperDrivers[1].ReceiveCompleteHandler)(
+ (USHORT)1); // BUGBUG: Fix NIC ID or remove.
+ Device->ReceiveCompletePending[1] = FALSE;
+
+ }
+
+ if ((Device->UpperDriverBound[2]) &&
+ (Device->ReceiveCompletePending[2])) {
+
+ (*Device->UpperDrivers[2].ReceiveCompleteHandler)(
+ (USHORT)1); // BUGBUG: Fix NIC ID or remove.
+ Device->ReceiveCompletePending[2] = FALSE;
+
+ }
+
+ }
+
+} /* IpxReceiveComplete */
+
+
+NTSTATUS
+IpxUpdateBindingNetwork(
+ IN PDEVICE Device,
+ IN PBINDING Binding,
+ IN ULONG Network
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when we have decided that we now know
+ the network number for a binding which we previously thought
+ was zero.
+
+Arguments:
+
+ Device - The IPX device.
+
+ Binding - The binding being updated.
+
+ Network - The new network number.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PADDRESS Address;
+ ULONG CurrentHash;
+ PLIST_ENTRY p;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // Only binding set members should have these different,
+ // and they will not have a network of 0.
+ //
+
+ Status = RipInsertLocalNetwork(
+ Network,
+ Binding->NicId,
+ Binding->Adapter->NdisBindingHandle,
+ (USHORT)((839 + Binding->MediumSpeed) / Binding->MediumSpeed));
+
+ if (Status == STATUS_SUCCESS) {
+
+ Binding->LocalAddress.NetworkAddress = Network;
+
+ //
+ // Update the device address if we have no virtual net
+ // and there is one binding (!Device->MultiCardZeroVirtual)
+ // or this is the first binding, which is the one we
+ // appear to be if a) we have no virtual net defined and
+ // b) we are bound to multiple cards.
+ //
+#ifdef _PNP_POWER
+
+ if ((!Device->MultiCardZeroVirtual) || (Binding->NicId == 1)) {
+
+ if (!Device->VirtualNetwork) {
+
+ Device->SourceAddress.NetworkAddress = Network;
+
+ //
+ // Scan through all the addresses that exist and modify
+ // their pre-constructed local IPX address to reflect
+ // the new local net and node.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (CurrentHash = 0; CurrentHash < IPX_ADDRESS_HASH_COUNT; CurrentHash++) {
+
+ for (p = Device->AddressDatabases[CurrentHash].Flink;
+ p != &Device->AddressDatabases[CurrentHash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ Address->LocalAddress.NetworkAddress = Network;
+ }
+ }
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Let SPX know because it fills in its own headers.
+ //
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_PNP_INFO IpxPnPInfo;
+
+ IpxPnPInfo.NewReservedAddress = TRUE;
+ IpxPnPInfo.NetworkAddress = Network;
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_ADDRESS_CHANGE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_ADDRESS_CHANGED to SPX: net addr: %lx\n", Network));
+ }
+
+ }
+ }
+#else
+ if ((!Device->VirtualNetwork) &&
+ ((!Device->MultiCardZeroVirtual) || (Binding->NicId == 1))) {
+
+ Device->SourceAddress.NetworkAddress = Network;
+
+ //
+ // Scan through all the addresses that exist and modify
+ // their pre-constructed local IPX address to reflect
+ // the new local net and node.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (CurrentHash = 0; CurrentHash < IPX_ADDRESS_HASH_COUNT; CurrentHash++) {
+
+ for (p = Device->AddressDatabases[CurrentHash].Flink;
+ p != &Device->AddressDatabases[CurrentHash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ Address->LocalAddress.NetworkAddress = Network;
+ }
+ }
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Let SPX know because it fills in its own
+ // headers. When we indicate a line up on NIC ID
+ // 0 it knows to requery the local address.
+ //
+ // BUGBUG: Line up indication to RIP/NB??
+ //
+
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+
+ IPX_LINE_INFO LineInfo;
+ LineInfo.LinkSpeed = Device->LinkSpeed;
+ LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ LineInfo.MacOptions = Device->MacOptions;
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].LineUpHandler)(
+ 0,
+ &LineInfo,
+ Binding->Adapter->MacInfo.RealMediumType,
+ NULL);
+
+ }
+ }
+#endif
+ } else if (Status == STATUS_DUPLICATE_NAME) {
+
+ //
+ // If it was a duplicate we still set the binding's local
+ // address to the value so we can detect binding sets.
+ //
+
+ Binding->LocalAddress.NetworkAddress = Network;
+
+ }
+
+ return Status;
+
+} /* IpxUpdateBindingNetwork */
+
+
+INT
+IpxReceivePacket (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a frame has been received on the physical link.
+ The packet passed up from NDIS can be held on to by the TDI clients
+ that request TDI_EVENT_RECEIVE_EX_DATAGRAM events with us.
+
+Arguments:
+
+ ProtocolBindingContext - The Adapter Binding specified at initialization time.
+
+ Packet - contains the packet received as well as some mediaspecific info.
+
+Return Value:
+
+ return of IpxReceiveIndicationNew(),
+
+--*/
+{
+ UINT HeaderBufferSize = NDIS_GET_PACKET_HEADER_SIZE(Packet);
+ UINT firstbufferLength, bufferLength;
+ PNDIS_BUFFER pFirstBuffer;
+ PUCHAR headerBuffer;
+ NTSTATUS ntStatus;
+ INT tdiClientCount = 0;
+
+ //
+ // Query the number of buffers, the first MDL's descriptor and the packet length
+ //
+ NdisGetFirstBufferFromPacket(Packet, // packet
+ &pFirstBuffer, // first buffer descriptor
+ &headerBuffer, // ptr to the start of packet
+ &firstbufferLength,// length of the header+lookahead
+ &bufferLength); // length of the bytes in the buffers
+
+ //
+ // ReceiveContext is the packet itself
+ //
+
+ ntStatus = IpxReceiveIndicationNew (
+ ProtocolBindingContext,
+ Packet, // ReceiveContext
+ headerBuffer,
+ HeaderBufferSize,
+ headerBuffer + HeaderBufferSize, // LookaheadBuffer
+ bufferLength - HeaderBufferSize, // LookaheadBufferSize
+ bufferLength - HeaderBufferSize, // PacketSize - since the whole packet is indicated
+ pFirstBuffer, // pMdl
+ &tdiClientCount // tdi client count
+ );
+
+ IPX_DEBUG(RECEIVE, ("IpxReceivePacket: Tdi Client Count is: %lx\n", tdiClientCount));
+
+ return tdiClientCount;
+} /* IpxReceivePacket */
+
+
+#ifdef _PNP_POWER
+
+#if defined(_M_IX86)
+_inline
+#endif
+BOOLEAN
+IpxNewVirtualNetwork(
+ IN PDEVICE Device,
+ IN BOOLEAN NewVirtualNetwork
+ )
+/*++
+
+Routine Description:
+
+ If the virtualnetwork number changed, this function records this fact
+ in the device.
+
+ Called with the BINDACCESSLOCK held.
+Arguments:
+
+ Device - Pointer to the Device.
+
+ NewVirtualNetwork - boolean to indicate if the virtual net# changed.
+
+Return Value:
+
+ BOOLEAN - to indicate whether SPX's reserved address was changed.
+
+--*/
+{
+ NTSTATUS ntStatus;
+ UCHAR VirtualNode[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
+ BOOLEAN ReservedAddrChanged = FALSE;
+
+ if (Device->VirtualNetworkNumber) {
+
+ if (NewVirtualNetwork) {
+ //
+ // If a new one appeared.
+ //
+
+ ntStatus = RipInsertLocalNetwork(
+ Device->VirtualNetworkNumber,
+ 0, // NIC ID
+ NIC_ID_TO_BINDING(Device, 1)->Adapter->NdisBindingHandle,
+ 1);
+
+ if (ntStatus != STATUS_SUCCESS) {
+
+ //
+ // Log the appropriate error, then ignore the
+ // virtual network. If the error was
+ // INSUFFICIENT_RESOURCES, the RIP module
+ // will have already logged an error.
+ //
+
+ if (ntStatus == STATUS_DUPLICATE_NAME) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Ignoring virtual network %lx, conflict\n", REORDER_ULONG (Device->VirtualNetworkNumber)));
+
+ IpxWriteResourceErrorLog(
+ Device->DeviceObject,
+ EVENT_IPX_INTERNAL_NET_INVALID,
+ 0,
+ REORDER_ULONG (Device->VirtualNetworkNumber));
+ }
+
+ Device->VirtualNetworkNumber = 0;
+ goto NoVirtualNetwork;
+
+ }
+
+ //
+ // If the number is non-zero now, a new one appeared
+ //
+ Device->VirtualNetwork = TRUE;
+ Device->MultiCardZeroVirtual = FALSE;
+ RtlCopyMemory(Device->SourceAddress.NodeAddress, VirtualNode, 6);
+ Device->SourceAddress.NetworkAddress = Device->VirtualNetworkNumber;
+ ReservedAddrChanged = TRUE;
+
+ //
+ // If RIP is not bound, then this node is a RipResponder
+ //
+ if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ Device->RipResponder = TRUE;
+ }
+ }
+
+ } else {
+NoVirtualNetwork:
+ Device->VirtualNetwork = FALSE;
+
+ //
+ // See if we need to be set up for the fake
+ // virtual network.
+ //
+
+ if (Device->ValidBindings > 1) {
+
+ CTEAssert (Device->VirtualNetworkOptional);
+
+ //
+ // In this case we return as our local node the
+ // address of the first card. We will also only
+ // direct SAP sends to that card.
+ //
+
+ Device->MultiCardZeroVirtual = TRUE;
+
+ } else {
+
+ Device->MultiCardZeroVirtual = FALSE;
+ }
+
+ if (NewVirtualNetwork) {
+ //
+ // The virtual network number disappeared this time
+ //
+
+ //
+ // Remove the prev. net # from the RIP tables here
+ //
+ RipAdjustForBindingChange (0, 0, IpxBindingDeleted);
+
+ //
+ // If we were a RipResponder, we are not anymore
+ //
+ if (Device->RipResponder) {
+ Device->RipResponder = FALSE;
+ }
+ }
+
+ //
+ // Since there is not virtual network number, SPX's reserved address is
+ // the address of the first binding. This could have changed because of
+ // several reasons: if there was a WAN binding only earlier and this time
+ // a LAN binding appeared, or if the first LAN binding disappeared. Instead
+ // of checking for all these conditions, check if the Device's sourceaddress
+ // and that of the first mis-match.
+ // NB uses the address of the first device always and hence does not need
+ // this mechanism to determine if this is a reserved address change.
+ //
+ if (!RtlEqualMemory( &Device->SourceAddress,
+ &NIC_ID_TO_BINDING(Device, 1)->LocalAddress,
+ FIELD_OFFSET(TDI_ADDRESS_IPX,Socket))) {
+
+ RtlCopyMemory( &Device->SourceAddress,
+ &NIC_ID_TO_BINDING(Device, 1)->LocalAddress,
+ FIELD_OFFSET(TDI_ADDRESS_IPX,Socket));
+
+ ReservedAddrChanged = TRUE;
+ }
+ }
+
+ return ReservedAddrChanged;
+}
+
+
+VOID
+IpxBindAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE BindContext,
+ IN PNDIS_STRING DeviceName,
+ IN PVOID SystemSpecific1,
+ IN PVOID SystemSpecific2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives a Plug and Play notification about a new
+ adapter in the machine. We are called here only if this adapter
+ is to be bound to us, so we don't make any checks for this.
+
+Arguments:
+
+ Status - NDIS_STATUS_SUCCESS, NDIS_STATUS_PENDING
+
+ BindContext - context to represent this bind indication
+
+ DeviceName - Name of the adapter that appeared (e.g. \Device\Lance1)
+
+ SystemSpecific1/2 - Not used here
+
+Return Value:
+
+ Status - NDIS_STATUS_SUCCESS
+
+--*/
+{
+ NTSTATUS ntStatus;
+ PDEVICE Device = IpxDevice;
+ PADAPTER Adapter = NULL;
+ CONFIG Config;
+ UINT i;
+ ULONG Temp, SuccessfulOpens=0;
+ PBINDING Binding;
+ BINDING_CONFIG ConfigBinding;
+ ULONG ValidBindings;
+ USHORT AutoDetectReject;
+ BOOLEAN NewVirtualNetwork = FALSE;
+ BOOLEAN FirstDevice = FALSE;
+ BOOLEAN ReservedAddrChanged = FALSE;
+ IPX_PNP_INFO IpxPnPInfo;
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_DEFINE_LOCK_HANDLE(LockHandle)
+
+ //
+ // Used for error logging
+ //
+ Config.DriverObject = (PDRIVER_OBJECT)Device->DeviceObject;
+
+ Config.RegistryPathBuffer = Device->RegistryPathBuffer;
+ ConfigBinding.AdapterName = *DeviceName;
+
+ //
+ // Read the registry to see if a virtual network number appeared/disappeared
+ //
+ ntStatus = IpxPnPGetVirtualNetworkNumber(&Config);
+
+ if (ntStatus != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("Could not read the vnet#: registrypathbuffer: %lx\n", Device->RegistryPathBuffer));
+ *Status = NDIS_STATUS_SUCCESS;
+ return;
+ }
+
+ Temp = REORDER_ULONG (Config.Parameters[CONFIG_VIRTUAL_NETWORK]);
+
+ //
+ // If the virtual network number changed, record this fact.
+ //
+ if (Device->VirtualNetworkNumber != Temp) {
+ NewVirtualNetwork = TRUE;
+ Device->VirtualNetworkNumber = Temp;
+ }
+
+ Device->VirtualNetworkOptional = (BOOLEAN)(Config.Parameters[CONFIG_VIRTUAL_OPTIONAL] != 0);
+
+ IPX_DEBUG(PNP, ("Virtual net # is: %lx\n", Temp));
+
+ //
+ // For each FrameType and Network Number configured, initialize the
+ // FrameType array in the CONFIG_BINDING
+ //
+ ntStatus = IpxPnPGetAdapterParameters(
+ &Config,
+ DeviceName,
+ &ConfigBinding);
+
+ if (ntStatus != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("Could not read the adapter params: DeviceName: %lx\n", DeviceName->Buffer));
+ *Status = NDIS_STATUS_SUCCESS;
+ return;
+ }
+
+ IPX_DEBUG(PNP, ("ConfigBinding.FrameTypeCount: %lx\n", ConfigBinding.FrameTypeCount));
+
+ //
+ // Reset the auto-detect state to init so that if a receive occurs on this binding
+ // before we can place this binding in the device's binding array, we know of it.
+ //
+ Device->AutoDetectState = AUTO_DETECT_STATE_INIT;
+
+ //
+ // Register adapter with NDIS; query the various parameters; get the WAN line count
+ // if this is a WAN adapter.
+ // Allocate the bindings corresponding to this adapter
+ //
+ for (i = 0; i < ConfigBinding.FrameTypeCount; i++) {
+
+ //
+ // If successful, this queues them on Device->InitialBindingList. [BUGBUGZZ] not right now
+ // Adapter is NULL first time and is allocated then. In subsequent calls,
+ // it is not NULL and the bindings are hooked to this adapter.
+
+ ntStatus = IpxBindToAdapter (Device, &ConfigBinding, &Adapter, i);
+
+ //
+ // If this failed because the adapter could not be bound
+ // to, then don't try any more frame types on this adapter.
+ // For other failures we do try the other frame types.
+ //
+
+ if (ntStatus == STATUS_DEVICE_DOES_NOT_EXIST) {
+ break;
+ }
+
+ //
+ // If the status is STATUS_NOT_SUPPORTED, then this frametype mapped to a previously
+ // initialized one. In this case, remove this index fron the FrameType array so that
+ // when we try to update the binding array, we dont have duplicates.
+ //
+ if (ntStatus == STATUS_NOT_SUPPORTED) {
+ ULONG j;
+
+ //
+ // Remove this frametype from the FrameType array.
+ //
+ for (j = i+1; j < ConfigBinding.FrameTypeCount; j++) {
+ ConfigBinding.FrameType[j-1] = ConfigBinding.FrameType[j];
+ }
+
+ --ConfigBinding.FrameTypeCount;
+
+ //
+ // Decrement so we see the one just moved up.
+ //
+ --i;
+
+#if DBG
+ for (j = 0; j < ISN_FRAME_TYPE_MAX; j++) {
+ IPX_DEBUG (AUTO_DETECT, ("%d: type %d, net %d, auto %d\n",
+ j, ConfigBinding.FrameType[j], ConfigBinding.NetworkNumber[j], ConfigBinding.AutoDetect[j]));
+ }
+#endif
+ continue;
+ }
+
+ if (ntStatus != STATUS_SUCCESS) {
+ continue;
+ }
+
+ if (ConfigBinding.AutoDetect[i]) {
+ Device->AutoDetect = TRUE;
+ }
+
+ CTEAssert(Adapter);
+
+ ++SuccessfulOpens;
+
+ //
+ // Even for WAN adapters, the FrameTypeCount is set to 4. We only need to
+ // allocate one binding for WAN; the others come later.
+ //
+ if (Adapter->MacInfo.MediumAsync) {
+ break;
+ }
+ }
+
+ if (SuccessfulOpens == 0) {
+ goto InitFailed;
+ }
+
+ //
+ // Place all the bindings corresponding to this adapter in the binding array
+ // Also resolve binding sets for non-autodetect bindings.
+ //
+
+ //
+ // Obtain lock to the Binding related stuff.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ IpxPnPUpdateBindingArray (Device, Adapter, &ConfigBinding);
+
+ //
+ // Release access to the Binding related stuff.
+ //
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // If at least one card appeared here, set our state
+ // to open
+ //
+ // [BUGBUGZZ]: what if all these bindings are eliminated - then
+ // the state is not open...
+ //
+ if (Device->ValidBindings > 0) {
+ if (Device->State == DEVICE_STATE_LOADED) {
+ FirstDevice = TRUE;
+ Device->State = DEVICE_STATE_OPEN;
+ }
+ }
+
+ //
+ // We don't do auto-detect/bindingsets for WAN lines: skip over.
+ //
+ if (Adapter->MacInfo.MediumAsync) {
+ goto jump_wan;
+ }
+
+ //
+ // Auto-detect the network number. Update the results for only the
+ // bindings corresponding to this adapter
+ //
+
+ //
+ // Queue a request to discover our locally attached
+ // adapter addresses. This must succeed because we
+ // just allocated our send packet pool. We need
+ // to wait for this, either because we are
+ // auto-detecting or because we need to determine
+ // if there are multiple cards on the same network.
+ //
+
+ KeInitializeEvent(
+ &Device->AutoDetectEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ Device->AutoDetectState = AUTO_DETECT_STATE_RUNNING;
+
+ //
+ // Make this 0; after we are done waiting, which means
+ // the packet has been completed, we set it to the
+ // correct value.
+ //
+
+ // Device->IncludedHeaderOffset = 0;
+
+ IPX_BEGIN_SYNC (&SyncContext);
+ ntStatus = RipQueueRequest (0xffffffff, RIP_REQUEST);
+ IPX_END_SYNC (&SyncContext);
+
+ CTEAssert (ntStatus == STATUS_PENDING);
+
+ //
+ // This is set when this rip send completes.
+ //
+
+ IPX_DEBUG (AUTO_DETECT, ("Waiting for AutoDetectEvent\n"));
+
+ KeWaitForSingleObject(
+ &Device->AutoDetectEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ Device->AutoDetectState = AUTO_DETECT_STATE_PROCESSING;
+
+ //
+ // Now that we are done receiving responses, insert the
+ // current network number for every auto-detect binding
+ // to the rip database.
+ //
+
+ //
+ // Obtain exclusive access to the Binding related stuff.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ //
+ // Note, here we go thru' only the bindings corresponding to this adapter
+ //
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+
+ Binding = Adapter->Bindings[i];
+
+ //
+ // Skip empty binding slots or bindings that were configured
+ // for a certain network number, we inserted those above.
+ // If no network number was detected, also skip it.
+ //
+
+ if ((!Binding) ||
+ (Binding->ConfiguredNetworkNumber != 0) ||
+ (Binding->TentativeNetworkAddress == 0)) {
+
+ continue;
+ }
+
+ IPX_DEBUG (AUTO_DETECT, ("Final score for %lx on %lx is %d - %d\n",
+ REORDER_ULONG(Binding->TentativeNetworkAddress),
+ Binding,
+ Binding->MatchingResponses,
+ Binding->NonMatchingResponses));
+
+ //
+ // We don't care about the status.
+ //
+
+ ntStatus = RipInsertLocalNetwork(
+ Binding->TentativeNetworkAddress,
+ Binding->NicId,
+ Binding->Adapter->NdisBindingHandle,
+ (USHORT)((839 + Binding->MediumSpeed) / Binding->MediumSpeed));
+
+ if ((ntStatus != STATUS_SUCCESS) &&
+ (ntStatus != STATUS_DUPLICATE_NAME)) {
+
+ //
+ // We failed to insert, keep it at zero, hopefully
+ // we will be able to update later.
+ //
+
+#if DBG
+ DbgPrint ("IPX: Could not insert net %lx for binding %lx\n",
+ REORDER_ULONG(Binding->LocalAddress.NetworkAddress),
+ Binding);
+#endif
+ CTEAssert (Binding->LocalAddress.NetworkAddress == 0);
+
+ } else {
+
+ Binding->LocalAddress.NetworkAddress = Binding->TentativeNetworkAddress;
+ }
+
+ Binding->LocalAddress.NetworkAddress = Binding->TentativeNetworkAddress;
+ }
+
+ // ValidBindings = Device->BindingCount;
+
+ ValidBindings = Device->ValidBindings;
+
+ // [BUGBUGZZ] if (Device->AutoDetect) {
+
+ ValidBindings = IpxResolveAutoDetect (Device, ValidBindings, &LockHandle1, &Device->RegistryPath);
+
+ //}
+
+ //
+ // Adjust all the indices by the number of AutoDetect bindings thrown away
+ //
+ // AutoDetectReject = (USHORT)(Device->BindingCount - ValidBindings);
+
+ AutoDetectReject = (USHORT)(Device->ValidBindings - ValidBindings);
+
+ Device->HighestLanNicId -= AutoDetectReject;
+ Device->HighestExternalNicId -= AutoDetectReject;
+ Device->HighestType20NicId -= AutoDetectReject;
+ Device->SapNicCount -= AutoDetectReject;
+
+ Device->ValidBindings = (USHORT)ValidBindings;
+
+ //
+ // Now see if any bindings are actually on the same
+ // network. This updates the Device->HighestExternalNicId
+ // and Device->HighestType20NicId, SapNicCount, HighestLanNicId
+ //
+
+ //
+ // Do this only for the auto-detect bindings
+ // [BUGBUGZZ] check this
+ //
+
+ //if (Device->AutoDetect) {
+ IpxResolveBindingSets (Device, Device->HighestExternalNicId);
+ //}
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+jump_wan:
+
+ IPX_DEBUG(PNP, ("BindingCount: %lu\n", Device->BindingCount));
+ IPX_DEBUG(PNP, ("ValidBindings: %lu\n", Device->ValidBindings));
+ IPX_DEBUG(PNP, ("HighestLanNicId: %lu\n", Device->HighestLanNicId));
+ IPX_DEBUG(PNP, ("HighestExternalNicId: %lu\n", Device->HighestExternalNicId));
+ IPX_DEBUG(PNP, ("HighestType20NicId: %lu\n", Device->HighestType20NicId));
+ IPX_DEBUG(PNP, ("SapNicCount: %lu\n", Device->SapNicCount));
+ IPX_DEBUG(PNP, ("BindingArray: %lx\n", Device->Bindings));
+
+ //
+ // Enable this regardless of whether any of our clients enabled b'cast.
+ // NB always enables it, so we are fine.
+ //
+ // Since we dont increment the Broadcast count in the device, we will disable b'casts
+ // correctly if the count drops to 0.
+ //
+ // If the ISN clients appear before the adapters, they increment the BCount, but
+ // since the ValidBindings is 0, all works. Then, when the adapters appear, we enable
+ // the broadcasts here.
+ //
+ // If the adapters appear before the ISN clients, then the broadcast is enabled on
+ // the adapters here and the adapter's flag is set to indicate this, which will prevent
+ // any further calls to NDIS when the ISN clients force an IpxAddBroadcast.
+ //
+ Device->EnableBroadcastPending = TRUE;
+ IpxBroadcastOperation((PVOID)TRUE);
+
+ //
+ // For multiple adapters, use the offset of the first...why not.
+ //
+
+#if 0
+ Device->IncludedHeaderOffset = Device->Bindings[1]->DefHeaderSize;
+#endif
+
+ Device->IncludedHeaderOffset = MAC_HEADER_SIZE;
+
+ //
+ // This function updates flags like RipResponder, MultiCardZeroVirtual, etc.
+ // If the VirtualNetwork number changed (NewVirtualNetwork is TRUE), it updates
+ // the Device structure and the RIP tables accordingly.
+ // It returns a boolean to indicate if SPX's reserved address changed.
+ //
+ ReservedAddrChanged = IpxNewVirtualNetwork(Device, NewVirtualNetwork);
+
+ //
+ // Update the values once the auto-detect bindings have been thrown away...
+ //
+ IpxPnPUpdateDevice(Device);
+
+ Device->AutoDetectState = AUTO_DETECT_STATE_DONE;
+
+ IPX_DEBUG (DEVICE, ("Node is %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x, ",
+ Device->SourceAddress.NodeAddress[0], Device->SourceAddress.NodeAddress[1],
+ Device->SourceAddress.NodeAddress[2], Device->SourceAddress.NodeAddress[3],
+ Device->SourceAddress.NodeAddress[4], Device->SourceAddress.NodeAddress[5]));
+ IPX_DEBUG (DEVICE, ("Network is %lx\n",
+ REORDER_ULONG (Device->SourceAddress.NetworkAddress)));
+
+ //
+ // Start the timer which updates the RIP database
+ // periodically. For the first one we do a ten
+ // second timeout (hopefully this is enough time
+ // for RIP to start if it is going to).
+ //
+ if (FirstDevice) {
+ UNICODE_STRING devicename;
+
+ //
+ // Inform TDI clients about the open of our device object.
+ //
+ devicename.MaximumLength = (USHORT)Device->DeviceNameLength;
+ devicename.Length = (USHORT)Device->DeviceNameLength - sizeof(WCHAR);
+ devicename.Buffer = Device->DeviceName;
+
+ if ((ntStatus = TdiRegisterDeviceObject(
+ &devicename,
+ &Device->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+
+ IPX_DEBUG(PNP, ("TdiRegisterDeviceObject failed: %lx", ntStatus));
+ }
+
+ IpxReferenceDevice (Device, DREF_LONG_TIMER);
+
+ CTEStartTimer(
+ &Device->RipLongTimer,
+ 10000,
+ RipLongTimeout,
+ (PVOID)Device);
+
+ }
+
+ //
+ // Set up the LineInfo struct.
+ //
+ IpxPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ IpxPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ //
+ // Inform NB and TDI of all the bindings corresponding to this adapter
+ //
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+ Binding = Adapter->Bindings[i];
+
+ //
+ // If a NULL binding or a binding set slave, dont inform NB about it.
+ //
+ if (!Binding || (Binding->NicId > Device->HighestExternalNicId)) {
+#if DBG
+ if (Binding) {
+ IPX_DEBUG(PNP, ("Binding: %lx, Binding set slave\n", Binding));
+ }
+#endif
+ continue;
+ }
+
+ //
+ // Register this address with the TDI clients.
+ //
+ RtlCopyMemory (Device->TdiRegistrationAddress->Address, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
+
+ if ((ntStatus = TdiRegisterNetAddress(
+ Device->TdiRegistrationAddress,
+ &Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+
+ IPX_DEBUG(PNP, ("TdiRegisterNetAddress failed: %lx", ntStatus));
+ }
+
+ //
+ // Lock taken to check the UpperDriverBound flag.
+ // We already have the BindAccessLock at this point.
+ //
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ //
+ // We could have informed the upper driver from IpxPnPIsnIndicate
+ // Ensure that we dont do it twice.
+ //
+ if (!Binding->IsnInformed[IDENTIFIER_NB]) {
+
+ //
+ // Also, to ensure that the indications are done in the right order,
+ // check if the first card has been indicated yet.
+ //
+ if ((Binding->NicId != 1) &&
+ !NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->IsnInformed[IDENTIFIER_NB]) {
+
+ break;
+ }
+
+ Binding->IsnInformed[IDENTIFIER_NB] = TRUE;
+
+ if (Binding->NicId == 1) {
+ IpxPnPInfo.NewReservedAddress = TRUE;
+
+ if (FirstDevice) {
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+ } else {
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+ }
+ } else {
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+ IpxPnPInfo.NewReservedAddress = FALSE;
+ }
+
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(PNP, ("PnP to NB add: %lx\n", Binding));
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+ }
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ //
+ // Always true for SPX
+ //
+ IpxPnPInfo.NewReservedAddress = TRUE;
+
+ if (FirstDevice) {
+
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+
+ //
+ // We could have informed the upper driver from IpxPnPIsnIndicate
+ //
+ if (!NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->IsnInformed[IDENTIFIER_SPX]) {
+
+ NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->IsnInformed[IDENTIFIER_SPX] = TRUE;
+ //
+ // Inform SPX - the network/node address is the Virtual one if it exists
+ // else the address of the first binding
+ //
+ IpxPnPInfo.NetworkAddress = Device->SourceAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Device->SourceAddress.NodeAddress, 6);
+
+ if (Device->VirtualNetwork) {
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 0);
+ } else {
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 1);
+ }
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(PNP, ("PnP to SPX add: %lx\n", Binding));
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ } else {
+
+ //
+ // Not the first device - inform if the reserved address changed.
+ //
+ if (ReservedAddrChanged) {
+ if (!NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->IsnInformed[IDENTIFIER_SPX]) {
+ NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->IsnInformed[IDENTIFIER_SPX] = TRUE;
+ IPX_DEBUG(PNP, ("Reserved addr changed; SPX not told of first one yet\n"));
+ }
+
+ IpxPnPInfo.NetworkAddress = Device->SourceAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Device->SourceAddress.NodeAddress, 6);
+
+ if (Device->VirtualNetwork) {
+ //
+ // new one appeared
+ //
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 0);
+ } else {
+ //
+ // Old one disappeared
+ //
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 1);
+ }
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("PnP to SPX add (res. addr change): %lx\n", Binding));
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+
+ //
+ // Release access to the Binding related stuff.
+ //
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+InitFailed:
+ *Status = NDIS_STATUS_SUCCESS;
+ return;
+
+} /* IpxBindAdapter */
+
+
+VOID
+IpxUnbindAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE UnbindContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives a Plug and Play notification about the removal
+ of an existing adapter from the machine. We are called here only if
+ this adapter is to be bound to us, so we don't make any checks for this.
+
+Arguments:
+
+ Status - NDIS_STATUS_SUCCESS, NDIS_STATUS_PENDING.
+
+ ProtocolBindingContext - the adapter that got removed.
+
+ UnbindContext - context to represent this bind indication.
+
+Return Value:
+
+ Void - return thru' Status above.
+
+--*/
+{
+ NTSTATUS ntStatus;
+ PADAPTER Adapter=(PADAPTER)ProtocolBindingContext;
+ CONFIG Config;
+ PBINDING Binding;
+ PDEVICE Device=IpxDevice;
+ ULONG i, Temp;
+ BOOLEAN NewVirtualNetwork = FALSE;
+ BOOLEAN NBReservedAddrChanged = FALSE;
+ BOOLEAN SPXInformed = FALSE;
+ IPX_PNP_INFO IpxPnPInfo;
+ PBINDING newMasterBinding;
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_DEFINE_LOCK_HANDLE(LockHandle)
+
+ //
+ // Used for error logging
+ //
+ Config.DriverObject = (PDRIVER_OBJECT)Device->DeviceObject;
+
+ Config.RegistryPathBuffer = Device->RegistryPathBuffer;
+
+ //
+ // Read the registry to see if a virtual network number appeared/disappeared
+ //
+ ntStatus = IpxPnPGetVirtualNetworkNumber(&Config);
+
+ if (ntStatus != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("Could not read the vnet#: registrypathbuffer: %lx\n", Device->RegistryPathBuffer));
+ *Status = NDIS_STATUS_SUCCESS;
+ return;
+ }
+
+ Temp = REORDER_ULONG (Config.Parameters[CONFIG_VIRTUAL_NETWORK]);
+
+ //
+ // If the VirtualNetwork number changed, record it.
+ //
+ if (Device->VirtualNetworkNumber != Temp) {
+ NewVirtualNetwork = TRUE;
+ }
+
+ Device->VirtualNetworkOptional = (BOOLEAN)(Config.Parameters[CONFIG_VIRTUAL_OPTIONAL] != 0);
+
+ IPX_DEBUG(PNP, ("Virtual net # is: %lx\n", Temp));
+
+ //
+ // If the WAN adapter disappeared, we can simply remove all the WAN bindings since
+ // all of them correspond to this single WAN adapter. Since we tell NB only about
+ // the first one of these, we need to indicate removal of only one binding to NB.
+ //
+ if (Adapter->MacInfo.MediumAsync) {
+ USHORT wanLineCount = (USHORT)Adapter->WanNicIdCount;
+
+ CTEAssert(wanLineCount == (Device->HighestExternalNicId - Device->HighestLanNicId));
+
+ //
+ // If no more bindings remain, tell upper driver of the same.
+ // We go back to the loaded state.
+ //
+
+ if ((Device->ValidBindings - wanLineCount) == 0) {
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+ Device->State = DEVICE_STATE_LOADED;
+
+ //
+ // Shut down RIP timers, complete address notify requests, etc.
+ //
+ IpxPnPToLoad();
+ } else {
+ CTEAssert(Device->State == DEVICE_STATE_OPEN);
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+ }
+
+ //
+ // Set up the LineInfo struct.
+ //
+ IpxPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ IpxPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ //
+ // Get to the first WAN binding - this is always the one after the last LAN binding.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_ID_TO_BINDING_NO_ILOCK(Device, Device->HighestLanNicId+1);
+
+ //
+ // DeRegister this address with the TDI clients.
+ //
+
+ CTEAssert(Binding->TdiRegistrationHandle);
+
+ if ((ntStatus = TdiDeregisterNetAddress(Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("TdiDeRegisterNetAddress failed: %lx", ntStatus));
+ }
+
+ //
+ // Give the PnP indication to indicate the deletion only if it was
+ // added before.
+ //
+ if (Binding->IsnInformed[IDENTIFIER_NB]) {
+
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform NB: delete WAN device\n"));
+
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_DELETE_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(PNP, ("PnP to NB delete: %lx\n", Binding));
+ }
+#if DBG
+ else {
+ DbgPrint("WAN adapter id: %lx not indicated to NB\n", Binding->NicId);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+#endif
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+
+ //
+ // Inform SPX only if this is the last device.
+ //
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ if (IpxPnPInfo.FirstORLastDevice && Binding->IsnInformed[IDENTIFIER_SPX]) {
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ CTEAssert(Device->HighestLanNicId == 0);
+
+ //
+ // Get to the first WAN binding - this is always the one after the last LAN binding.
+ //
+ Binding = NIC_ID_TO_BINDING_NO_ILOCK(Device, Device->HighestLanNicId+1);
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform SPX: delete WAN device\n"));
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_DELETE_DEVICE,
+ &IpxPnPInfo);
+ }
+
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+
+ //
+ // Now remove these WAN bindings from the array. Move all the Slave bindings
+ // up to where the WAN bindings were.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ for (i = Device->HighestLanNicId+1; i <= Device->HighestExternalNicId; i++) {
+ //
+ // Unbind from the adapter - if it is not referenced by any other thread, it will
+ // be deleted at this point.
+ //
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ IpxUnBindFromAdapter(NIC_ID_TO_BINDING_NO_ILOCK(Device, i));
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ //
+ // Move the slave binding here.
+ //
+ INSERT_BINDING(Device, i, NIC_ID_TO_BINDING_NO_ILOCK(Device, i+wanLineCount));
+ }
+
+ /*
+ RtlCopyMemory( Device->Bindings[Device->HighestLanNicId+1],
+ Device->Bindings[Device->HighestExternalNicId+1],
+ (Device->ValidBindings - Device->HighestExternalNicId) * sizeof(PBIND_ARRAY_ELEM));
+ */
+
+ //
+ // Update the indices
+ //
+ Device->HighestExternalNicId -= wanLineCount;
+ Device->ValidBindings -= wanLineCount;
+ Device->BindingCount -= wanLineCount;
+ Device->SapNicCount = Device->HighestType20NicId = Device->HighestLanNicId;
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ CTEAssert(Device->HighestLanNicId == Device->HighestExternalNicId);
+
+ } else {
+ //
+ // LAN adapter disappeared.
+ //
+
+ //
+ // Set up the LineInfo struct.
+ //
+ IpxPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ IpxPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ //
+ // For each binding corresponding to this adapter, inform NB only
+ // if the binding addition was indicated.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+ Binding = Adapter->Bindings[i];
+
+ if (!Binding) {
+ continue;
+ }
+
+ //
+ // We cannot receive on this binding anymore
+ //
+ Adapter->Bindings[i] = NULL;
+
+ //
+ // If this was a slave binding, dont inform of the deletion.
+ // Just remove the binding from the binding array and the bindingset list.
+ //
+
+ if (Binding->NicId > Device->HighestExternalNicId) {
+ PBINDING MasterBinding, tempBinding;
+
+ CTEAssert(Binding->BindingSetMember);
+ CTEAssert(Binding->CurrentSendBinding == NULL);
+
+ //
+ // Traverse the bindingset list and remove this binding from there.
+ //
+ tempBinding = MasterBinding = Binding->MasterBinding;
+
+ while (tempBinding->NextBinding != MasterBinding) {
+ if (tempBinding->NextBinding == Binding) {
+ tempBinding->NextBinding = tempBinding->NextBinding->NextBinding;
+ break;
+ }
+ tempBinding = tempBinding->NextBinding;
+ }
+
+ //
+ // If no more slaves, this is no longer a bindingset.
+ //
+ if (MasterBinding->NextBinding == MasterBinding) {
+ MasterBinding->BindingSetMember = FALSE;
+ MasterBinding->CurrentSendBinding = NULL;
+ MasterBinding->ReceiveBroadcast = TRUE;
+
+ IPX_DEBUG(PNP, ("Slave binding: %lx removed, no master: %lx\n", Binding, MasterBinding));
+ }
+
+ //
+ // Change the slave binding entries to have the master's NicId
+ //
+ RipAdjustForBindingChange (Binding->NicId, MasterBinding->NicId, IpxBindingMoved);
+ IPX_DEBUG(PNP, ("RipAdjustForBindingChange (%d, %d, IpxBindingMoved)\n", Binding->NicId, MasterBinding->NicId));
+
+ //
+ // Null out the Slave binding.
+ //
+ INSERT_BINDING(Device, Binding->NicId, NULL);
+
+ --Device->ValidBindings;
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ IpxUnBindFromAdapter(Binding);
+
+ continue;
+ }
+
+ //
+ // If this was the last binding, go back to loaded state and shut down the RIP timers.
+ //
+ if (Device->ValidBindings == 1) {
+ CTEAssert(Device->HighestExternalNicId == 1);
+ CTEAssert(Device->HighestLanNicId == 1);
+ CTEAssert(Device->SapNicCount == 1);
+ CTEAssert(Device->HighestType20NicId == 1);
+
+ Device->State = DEVICE_STATE_LOADED;
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+
+ //
+ // Shut down RIP timers, complete address notify requests, etc.
+ //
+ IpxPnPToLoad();
+
+ } else {
+ CTEAssert(Device->State == DEVICE_STATE_OPEN);
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+ }
+
+ //
+ // If this was a master binding, promote a slave binding to master.
+ //
+ if (Binding->BindingSetMember) {
+
+ CTEAssert(Binding->CurrentSendBinding);
+ CTEAssert(Binding->MasterBinding == Binding);
+
+ //
+ // Promote the next slave to Master.
+ //
+ newMasterBinding = Binding->NextBinding;
+ INSERT_BINDING(Device, Binding->NicId, newMasterBinding);
+ newMasterBinding->CurrentSendBinding = newMasterBinding;
+ newMasterBinding->MasterBinding = newMasterBinding;
+
+ //
+ // If this is the only binding remaining out of its set,
+ // it is no longer part of a set.
+ //
+ if (newMasterBinding->NextBinding == Binding) {
+ newMasterBinding->NextBinding = newMasterBinding->CurrentSendBinding = NULL;
+ newMasterBinding->BindingSetMember = FALSE;
+ newMasterBinding->ReceiveBroadcast = TRUE;
+
+ IPX_DEBUG(PNP, ("Master binding: %lx removed, no master: %lx\n", Binding, newMasterBinding));
+ }
+
+ //
+ // Change the slave binding entries to have the master's NicId
+ //
+ RipAdjustForBindingChange (newMasterBinding->NicId, Binding->NicId, IpxBindingMoved);
+ IPX_DEBUG(PNP, ("RipAdjustForBindingChange (%d, %d, IpxBindingMoved)\n", newMasterBinding->NicId, Binding->NicId));
+
+ //
+ // Register slave's address with the TDI clients.
+ //
+ CTEAssert(!newMasterBinding->TdiRegistrationHandle);
+
+ RtlCopyMemory ( Device->TdiRegistrationAddress->Address,
+ &newMasterBinding->LocalAddress,
+ sizeof(TDI_ADDRESS_IPX));
+
+ if ((ntStatus = TdiRegisterNetAddress(
+ Device->TdiRegistrationAddress,
+ &newMasterBinding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+
+ IPX_DEBUG(PNP, ("TdiRegisterNetAddress failed: %lx", ntStatus));
+ }
+
+ //
+ // Null out the slave binding
+ //
+ INSERT_BINDING(Device, newMasterBinding->NicId, NULL);
+
+ newMasterBinding->NicId = Binding->NicId;
+
+ IPX_DEBUG(PNP, ("Promoted a master binding: %lx, old master: %lx\n", newMasterBinding, Binding));
+ } else {
+
+ ULONG j;
+
+ //
+ // Remove the binding from the array
+ //
+ RipAdjustForBindingChange (Binding->NicId, 0, IpxBindingDeleted);
+
+ for (j = Binding->NicId+1; j <= Device->HighestExternalNicId; j++) {
+ INSERT_BINDING(Device, j-1, NIC_ID_TO_BINDING_NO_ILOCK(Device, j));
+ --NIC_ID_TO_BINDING_NO_ILOCK(Device, j)->NicId;
+ }
+
+ INSERT_BINDING(Device, Device->HighestExternalNicId, NULL);
+
+ --Device->HighestExternalNicId;
+ --Device->HighestLanNicId;
+ --Device->HighestType20NicId;
+ --Device->SapNicCount;
+ }
+
+ --Device->ValidBindings;
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+
+ //
+ // If this is the first binding, NB's reserved will change.
+ // When we inform SPX of an address change later, we dont have
+ // this binding to know if this binding was indicated to SPX earlier.
+ // So, set SPXInformed, which is used later to determine if an address
+ // change is to be indicated to SPX later.
+ //
+ // Since NB is informed of all adapters, we inform of the reserved address
+ // change to NB if the new Binding (now at NicId 1) was indicated earlier.
+ //
+ if (Binding->NicId == 1) {
+ NBReservedAddrChanged = TRUE;
+ if (Binding->IsnInformed[IDENTIFIER_SPX]) {
+ SPXInformed = TRUE;
+ }
+ }
+
+ CTEAssert(Binding->TdiRegistrationHandle);
+
+ //
+ // DeRegister this address with the TDI clients.
+ //
+ if ((ntStatus = TdiDeregisterNetAddress(Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("TdiDeRegisterNetAddress failed: %lx", ntStatus));
+ }
+
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ //
+ // If this binding's addition was indicated earlier, indicate its deletion to NB.
+ //
+ if (Binding->IsnInformed[IDENTIFIER_NB]) {
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform NB: delete LAN device: %lx\n", Binding));
+
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_DELETE_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ //
+ // If this was a Master, indicate the addition of the (promoted) slave
+ //
+ if (Binding->BindingSetMember) {
+ IpxPnPInfo.NetworkAddress = newMasterBinding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, newMasterBinding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, newMasterBinding->NicId);
+
+ //
+ // In this case, we set the ReservedAddrChanged bit here itself so dont need
+ // to indicate a separate address changed.
+ //
+ IpxPnPInfo.NewReservedAddress = (NBReservedAddrChanged) ? TRUE : FALSE;
+ NBReservedAddrChanged = FALSE;
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform NB: add slave device: NicId: %lx\n", Binding->NicId));
+
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ newMasterBinding->IsnInformed[IDENTIFIER_NB] = TRUE;
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ }
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+
+ //
+ // Last device - inform SPX if it is bound and this device was added earlier.
+ //
+ if (IpxPnPInfo.FirstORLastDevice) {
+ IPX_DEBUG(PNP, ("Last device - inform SPX\n"));
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ if (Binding->IsnInformed[IDENTIFIER_SPX]) {
+
+ IpxPnPInfo.NetworkAddress = Device->SourceAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Device->SourceAddress.NodeAddress, 6);
+
+ if (Device->VirtualNetwork) {
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 0);
+ } else {
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 1);
+ }
+
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform SPX: last LAN device\n"));
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_DELETE_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+ }
+
+ //
+ // Unbind from the adapter so it can be deleted
+ //
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ IpxUnBindFromAdapter(Binding);
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+
+ //
+ // Update the Device and RIP tables if this is not the last device.
+ // If the reserved address changed, inform NB and SPX of this change.
+ //
+ if (!IpxPnPInfo.FirstORLastDevice) {
+
+ Binding = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1);
+
+ if (IpxNewVirtualNetwork(Device, NewVirtualNetwork)) {
+
+ IPX_DEBUG(PNP, ("SPX's reserved address changed\n"));
+
+ //
+ // SPX's reserved address changed
+ //
+ IpxPnPInfo.NewReservedAddress = TRUE;
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ //
+ // If this binding's addition was indicated earlier, indicate change of address.
+ //
+ if (SPXInformed) {
+ Binding->IsnInformed[IDENTIFIER_SPX] = TRUE;
+
+ IPX_DEBUG(PNP, ("Inform SPX: reserved address changed\n"));
+ IpxPnPInfo.NetworkAddress = Device->SourceAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Device->SourceAddress.NodeAddress, 6);
+
+ if (Device->VirtualNetwork) {
+ //
+ // new one appeared
+ //
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 0);
+ } else {
+ //
+ // Old one disappeared
+ //
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 1);
+ }
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+ } else {
+
+ //
+ // Set the first binding's flag so that when this binding goes away, we remember
+ // to inform SPX of this device's removal.
+ //
+
+ IPX_DEBUG(PNP, ("Transfer SPX informed flag to NicId: %lx\n", Binding->NicId));
+ Binding->IsnInformed[IDENTIFIER_SPX] = TRUE;
+ }
+
+ if (NBReservedAddrChanged) {
+ //
+ // NB's reserved address changed.
+ //
+ IpxPnPInfo.NewReservedAddress = TRUE;
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ //
+ // If this binding's addition was indicated earlier, indicate the change of reserved address.
+ //
+ if (Binding->IsnInformed[IDENTIFIER_NB]) {
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform NB: reserved address changed\n"));
+
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_ADDRESS_CHANGE,
+ &IpxPnPInfo);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+ }
+ }
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+
+ //
+ // Re-calculate the values of datagram sizes in the Device.
+ //
+ IpxPnPUpdateDevice(Device);
+
+ IPX_DEBUG(PNP, ("BindingCount: %lu\n", Device->BindingCount));
+ IPX_DEBUG(PNP, ("ValidBindings: %lu\n", Device->ValidBindings));
+ IPX_DEBUG(PNP, ("HighestLanNicId: %lu\n", Device->HighestLanNicId));
+ IPX_DEBUG(PNP, ("HighestExternalNicId: %lu\n", Device->HighestExternalNicId));
+ IPX_DEBUG(PNP, ("HighestType20NicId: %lu\n", Device->HighestType20NicId));
+ IPX_DEBUG(PNP, ("SapNicCount: %lu\n", Device->SapNicCount));
+ IPX_DEBUG(PNP, ("BindingArray: %lx\n", Device->Bindings));
+} /* IpxUnbindAdapter */
+
+
+VOID
+IpxTranslate(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ OUT PNET_PNP_ID IdList,
+ IN ULONG IdListLength,
+ OUT PULONG BytesReturned
+ )
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a frame has been received on the physical link.
+ The packet passed up from NDIS can be held on to by the TDI clients
+ that request TDI_EVENT_RECEIVE_EX_DATAGRAM events with us.
+
+Arguments:
+
+ ProtocolBindingContext - The Adapter Binding specified at initialization time.
+
+ ReceivedPacket - The packet received
+
+ MediaSpecificInformation - Used for media such as Irda, wireless, etc. Not used here.
+
+ HeaderBufferSize - Size of the MAC header
+
+Return Value:
+
+ return of IpxReceiveIndicationNew(),
+
+--*/
+{
+} /* IpxTranslate */
+
+#endif _PNP_POWER
+
+
diff --git a/private/ntos/tdi/isnp/ipx/internal.c b/private/ntos/tdi/isnp/ipx/internal.c
new file mode 100644
index 000000000..f11790158
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/internal.c
@@ -0,0 +1,1233 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ internal.c
+
+Abstract:
+
+ This module contains the code to handle the internal
+ binding of the upper drivers to IPX.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 25-August-1995
+ Bug Fixes - tagged [SA]
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+
+NTSTATUS
+IpxInternalBind(
+ IN PDEVICE Device,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used when one of the upper drivers submits
+ a request to bind to IPX.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (Irp);
+ PIPX_INTERNAL_BIND_INPUT BindInput;
+ PIPX_INTERNAL_BIND_OUTPUT BindOutput;
+ PIPX_INTERNAL_BIND_RIP_OUTPUT BindRipOutput;
+ CTELockHandle LockHandle;
+ PIPX_NIC_DATA NicData;
+ PBINDING Binding, LastRealBinding;
+ PADAPTER Adapter;
+ ULONG Identifier;
+ ULONG BindOutputSize;
+ BOOLEAN BroadcastEnable;
+ UINT i;
+#if DBG
+ PUCHAR IdStrings[] = { "NB", "SPX", "RIP" };
+#endif
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
+ (sizeof(IPX_INTERNAL_BIND_INPUT) - sizeof(ULONG))) {
+
+ IPX_DEBUG (BIND, ("Bind received, bad input length %d/%d\n",
+ IrpSp->Parameters.DeviceIoControl.InputBufferLength,
+ sizeof (IPX_INTERNAL_BIND_INPUT)));
+ return STATUS_INVALID_PARAMETER;
+
+ }
+
+ BindInput = (PIPX_INTERNAL_BIND_INPUT)(Irp->AssociatedIrp.SystemBuffer);
+
+ if (BindInput->Identifier >= UPPER_DRIVER_COUNT) {
+ IPX_DEBUG (BIND, ("Bind received, bad id %d\n", BindInput->Identifier));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IPX_DEBUG (BIND, ("Bind received from id %d (%s)\n",
+ BindInput->Identifier,
+ IdStrings[BindInput->Identifier]));
+
+#ifdef _PNP_POWER
+// RIP gives us version == 1 whereas the others give us 2 (ISN_VERSION).
+// [BUGBUGZZ] - have RIP change?
+//
+ if (BindInput->Identifier == IDENTIFIER_RIP) {
+ if (BindInput->Version != 1) {
+ IPX_DEBUG (BIND, ("Bind: bad version %d/%d\n",
+ BindInput->Version, 1));
+ return STATUS_INVALID_PARAMETER;
+ }
+ } else {
+ if (BindInput->Version != ISN_VERSION) {
+ IPX_DEBUG (BIND, ("Bind: bad version %d/%d\n",
+ BindInput->Version, 1));
+ return STATUS_INVALID_PARAMETER;
+ }
+ }
+
+#else
+ if (BindInput->Version != 1) {
+ IPX_DEBUG (BIND, ("Bind: bad version %d/%d\n",
+ BindInput->Version, 1));
+ return STATUS_INVALID_PARAMETER;
+ }
+#endif
+
+ if (BindInput->Identifier != IDENTIFIER_RIP) {
+ BindOutputSize = sizeof(IPX_INTERNAL_BIND_OUTPUT);
+ } else {
+ BindOutputSize = FIELD_OFFSET (IPX_INTERNAL_BIND_RIP_OUTPUT, NicInfoBuffer.NicData[0]) +
+ (MIN (Device->MaxBindings, Device->HighestExternalNicId) * sizeof(IPX_NIC_DATA));
+ }
+
+ Irp->IoStatus.Information = BindOutputSize;
+
+ if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
+ BindOutputSize) {
+
+ IPX_DEBUG (BIND, ("Bind: bad output length %d/%d\n",
+ IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
+ BindOutputSize));
+
+ //
+ // Fail this request with BUFFER_TOO_SMALL. Since the
+ // I/O system may not copy the status block back to
+ // the user's status block, do that here so that
+ // he gets IoStatus.Information.
+ //
+
+ try {
+ *Irp->UserIosb = Irp->IoStatus;
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+ NOTHING;
+ }
+
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // We have verified the length, make sure we are not
+ // already bound.
+ //
+
+ Identifier = BindInput->Identifier;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ if (Device->UpperDriverBound[Identifier]) {
+ IPX_DEBUG (BIND, ("Bind: already bound\n"));
+ CTEFreeLock (&Device->Lock, LockHandle);
+ return STATUS_REQUEST_NOT_ACCEPTED;
+ }
+
+ {
+ LARGE_INTEGER ControlChId;
+
+ CCID_FROM_REQUEST(ControlChId, Irp);
+
+ IPX_DEBUG (BIND, ("Control ChId: (%d, %d) for Id: %d\n", ControlChId.HighPart, ControlChId.LowPart, Identifier));
+ Device->UpperDriverControlChannel[Identifier].QuadPart = ControlChId.QuadPart;
+ }
+
+ RtlCopyMemory(
+ &Device->UpperDrivers[Identifier],
+ BindInput,
+ sizeof (IPX_INTERNAL_BIND_INPUT)
+ );
+
+ BroadcastEnable = BindInput->BroadcastEnable;
+
+ //
+ // Now construct the output buffer.
+ //
+
+ if (Identifier != IDENTIFIER_RIP) {
+
+ BindOutput = (PIPX_INTERNAL_BIND_OUTPUT)Irp->AssociatedIrp.SystemBuffer;
+
+ BindOutput->Version = 1;
+
+ //
+ // Tell netbios our first binding's net/node instead of the
+ // virtual one.
+ //
+#ifdef _PNP_POWER
+//
+// Fill the fields in only if the adapters have already appeared
+// Else, set NodeNumber to 0 so NB/SPX know of it.
+//
+ if ((*(UNALIGNED USHORT *)(Device->SourceAddress.NodeAddress+4) != 0) ||
+ (*(UNALIGNED ULONG *)Device->SourceAddress.NodeAddress != 0)) {
+
+ IPX_DEBUG(BIND, ("Device already opened\n"));
+ CTEAssert(Device->ValidBindings);
+
+ if (Identifier == IDENTIFIER_SPX) {
+
+ //
+ // For SPX, inform directly.
+ //
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ if (!NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier]) {
+ NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier] = TRUE;
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IpxPnPIsnIndicate((PVOID)Identifier);
+
+ } else {
+ CTEAssert(FALSE);
+
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+ } else {
+ //
+ // For NB, queue a work item which will go thru' the adapters list and
+ // inform the upper drivers about each of them.
+ //
+ ExInitializeWorkItem(
+ &Device->PnPIndicationsQueueItem,
+ IpxPnPIsnIndicate,
+ (PVOID)Identifier);
+ ExQueueWorkItem(&Device->PnPIndicationsQueueItem, DelayedWorkQueue);
+ }
+
+ } else {
+ IPX_DEBUG(BIND, ("Device not open\n"));
+ *((UNALIGNED ULONG *)BindOutput->Node) = 0;
+ *((UNALIGNED USHORT *)(BindOutput->Node+4)) = 0;
+ RtlZeroMemory(&BindOutput->LineInfo, sizeof(BindOutput->LineInfo));
+ }
+
+ BindOutput->MacHeaderNeeded = MAC_HEADER_SIZE; //40;
+ BindOutput->IncludedHeaderOffset = MAC_HEADER_SIZE; // (USHORT)Device->IncludedHeaderOffset;
+
+ BindOutput->SendHandler = IpxSendFramePreFwd;
+ BindOutput->FindRouteHandler = IpxInternalFindRoute;
+ BindOutput->QueryHandler = IpxInternalQuery;
+
+#else
+ if ((Identifier == IDENTIFIER_NB) &&
+ (Device->VirtualNetwork)) {
+ RtlCopyMemory(BindOutput->Node, Device->Bindings[1]->LocalAddress.NodeAddress, 6);
+ *(UNALIGNED ULONG *)(BindOutput->Network) = Device->Bindings[1]->LocalAddress.NetworkAddress;
+ } else {
+
+ RtlCopyMemory(BindOutput->Node, Device->SourceAddress.NodeAddress, 6);
+ *(UNALIGNED ULONG *)(BindOutput->Network) = Device->SourceAddress.NetworkAddress;
+ }
+
+ BindOutput->MacHeaderNeeded = MAC_HEADER_SIZE; //40;
+
+ BindOutput->IncludedHeaderOffset = (USHORT)Device->IncludedHeaderOffset;
+
+ BindOutput->LineInfo.LinkSpeed = Device->LinkSpeed;
+ BindOutput->LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ BindOutput->LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ BindOutput->LineInfo.MacOptions = Device->MacOptions;
+
+ BindOutput->SendHandler = IpxSendFrame;
+ BindOutput->FindRouteHandler = IpxInternalFindRoute;
+ BindOutput->QueryHandler = IpxInternalQuery;
+#endif
+ BindOutput->TransferDataHandler = IpxTransferData;
+ } else {
+ //
+ // Set this so we stop RIPping for our virtual network (if
+ // we have one).
+ //
+
+ Device->RipResponder = FALSE;
+
+ //
+ // See if he wants a single wan network number.
+ //
+
+ if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength <
+ sizeof(IPX_INTERNAL_BIND_INPUT)) ||
+ ((BindInput->RipParameters & IPX_RIP_PARAM_GLOBAL_NETWORK) == 0)) {
+
+ Device->WanGlobalNetworkNumber = FALSE;
+ Device->SapNicCount = Device->HighestExternalNicId;
+
+ } else {
+
+ Device->WanGlobalNetworkNumber = TRUE;
+
+ }
+
+ BindRipOutput = (PIPX_INTERNAL_BIND_RIP_OUTPUT)Irp->AssociatedIrp.SystemBuffer;
+
+ BindRipOutput->Version = 1;
+ BindRipOutput->MaximumNicCount = MIN (Device->MaxBindings, Device->HighestExternalNicId) + 1;
+
+ BindRipOutput->MacHeaderNeeded = MAC_HEADER_SIZE; //40;
+ BindRipOutput->IncludedHeaderOffset = (USHORT)Device->IncludedHeaderOffset;
+
+ BindRipOutput->SendHandler = IpxSendFrame;
+
+ BindRipOutput->SegmentCount = Device->SegmentCount;
+ BindRipOutput->SegmentLocks = Device->SegmentLocks;
+
+ BindRipOutput->GetSegmentHandler = RipGetSegment;
+ BindRipOutput->GetRouteHandler = RipGetRoute;
+ BindRipOutput->AddRouteHandler = RipAddRoute;
+ BindRipOutput->DeleteRouteHandler = RipDeleteRoute;
+ BindRipOutput->GetFirstRouteHandler = RipGetFirstRoute;
+ BindRipOutput->GetNextRouteHandler = RipGetNextRoute;
+
+ BindRipOutput->IncrementWanInactivityHandler = IpxInternalIncrementWanInactivity;
+ BindRipOutput->QueryWanInactivityHandler = IpxInternalQueryWanInactivity;
+
+ BindRipOutput->TransferDataHandler = IpxTransferData;
+
+ BindRipOutput->NicInfoBuffer.NicCount = (USHORT)MIN (Device->MaxBindings, Device->HighestExternalNicId);
+ BindRipOutput->NicInfoBuffer.VirtualNicId = 0;
+ if (Device->VirtualNetwork || Device->MultiCardZeroVirtual) {
+ *(UNALIGNED ULONG *)(BindRipOutput->NicInfoBuffer.VirtualNetwork) = Device->SourceAddress.NetworkAddress;
+ } else if (Device->DedicatedRouter) {
+ *(UNALIGNED ULONG *)(BindRipOutput->NicInfoBuffer.VirtualNetwork) = 0x0;
+ }
+
+ NicData = &BindRipOutput->NicInfoBuffer.NicData[0];
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+
+ //
+ // NULL bindings are WAN bindings, so we return the
+ // information from the last non-NULL binding found,
+ // which will be the first one on this adapter.
+ // Otherwise we save this as the last non-NULL one.
+ //
+
+ if (Binding == NULL) {
+ Binding = LastRealBinding;
+ } else {
+ LastRealBinding = Binding;
+ }
+
+ Adapter = Binding->Adapter;
+ NicData->NicId = i;
+ RtlCopyMemory (NicData->Node, Binding->LocalAddress.NodeAddress, 6);
+ *(UNALIGNED ULONG *)NicData->Network = Binding->LocalAddress.NetworkAddress;
+ NicData->LineInfo.LinkSpeed = Binding->MediumSpeed;
+ NicData->LineInfo.MaximumPacketSize =
+ Binding->MaxLookaheadData + sizeof(IPX_HEADER);
+ NicData->LineInfo.MaximumSendSize =
+ Binding->AnnouncedMaxDatagramSize + sizeof(IPX_HEADER);
+ NicData->LineInfo.MacOptions = Adapter->MacInfo.MacOptions;
+ NicData->DeviceType = Adapter->MacInfo.RealMediumType;
+ NicData->EnableWanRouter = Adapter->EnableWanRouter;
+
+ ++NicData;
+ }
+ }
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ }
+ if (BroadcastEnable) {
+ IpxAddBroadcast (Device);
+ }
+
+ Device->UpperDriverBound[Identifier] = TRUE;
+ Device->AnyUpperDriverBound = TRUE;
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ return STATUS_SUCCESS;
+
+} /* IpxInternalBind */
+
+
+NTSTATUS
+IpxInternalUnbind(
+ IN PDEVICE Device,
+ IN UINT Identifier
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used when one of the upper drivers submits
+ a request to unbind from IPX. It does this by closing the
+ control channel on which the bind ioctl was submitted.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+#if DBG
+ PUCHAR IdStrings[] = { "NB", "SPX", "RIP" };
+#endif
+
+ IPX_DEBUG (BIND, ("Unbind received from id %d (%s)\n",
+ Identifier,
+ IdStrings[Identifier]));
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ if (!Device->UpperDriverBound[Identifier]) {
+ CTEFreeLock (&Device->Lock, LockHandle);
+ IPX_DEBUG (BIND, ("No existing binding\n"));
+ return STATUS_SUCCESS;
+ }
+
+ Device->UpperDriverBound[Identifier] = FALSE;
+ Device->AnyUpperDriverBound = (BOOLEAN)
+ (Device->UpperDriverBound[IDENTIFIER_RIP] ||
+ Device->UpperDriverBound[IDENTIFIER_SPX] ||
+ Device->UpperDriverBound[IDENTIFIER_NB]);
+
+ if (Device->UpperDrivers[Identifier].BroadcastEnable) {
+ IpxRemoveBroadcast (Device);
+ }
+
+#ifdef _PNP_POWER
+ if (Device->ValidBindings > 0) {
+ //
+ // If SPX went away, reset the IsnIndicate flag in the first binding
+ //
+ if (Identifier == IDENTIFIER_SPX) {
+ CTEAssert(NIC_ID_TO_BINDING(Device, 1));
+
+ if (NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier]) {
+ NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier] = FALSE;
+ IPX_DEBUG(PNP, ("SPX unbound: IsnInformed turned off\n"));
+ }
+ }
+
+ //
+ // If NB went away, reset all the Binding's flags
+ //
+ if (Identifier == IDENTIFIER_SPX) {
+ PBINDING Binding;
+ UINT i;
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i < Index; i++) {
+ Binding = NIC_ID_TO_BINDING(Device, i);
+ if (Binding && Binding->IsnInformed[Identifier]) {
+ Binding->IsnInformed[Identifier] = FALSE;
+ IPX_DEBUG(PNP, ("NB unbound: IsnInformed off for NicId: %lx\n", i));
+ }
+ }
+ }
+ }
+#endif
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ //
+ // BUGBUG: Ensure that no calls are made to bogus
+ // handlers.
+ //
+
+ return STATUS_SUCCESS;
+
+} /* IpxInternalUnbind */
+
+
+VOID
+IpxInternalFindRoute (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the entry point for upper drivers to submit
+ requests to find a remote network, which is contained in
+ FindRouteRequest->Network. FindRouteRequest->Identifier must
+ contain the identifier of the upper driver.
+
+ This request is always asynchronous and is completed by
+ a call to the FindRouteComplete handler of the upper driver.
+
+ NOTE: As a currently unspecified extension to this call,
+ we returns the tick and hop counts as two USHORTs in the
+ PVOID Reserved2 structure of the request.
+
+Arguments:
+
+ FindRouteRequest - Describes the request and contains
+ storage for IPX to use while processing it.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ ULONG Segment;
+ TDI_ADDRESS_IPX TempAddress;
+ PBINDING Binding, MasterBinding;
+ NTSTATUS Status;
+ IPX_DEFINE_SYNC_CONTEXT (SyncContext)
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ //
+ // First see if we have a route to this network in our
+ // table.
+ //
+
+ TempAddress.NetworkAddress = *(UNALIGNED ULONG *)(FindRouteRequest->Network);
+ //
+ // [SA] Bug #15094 Copy over the Node address so it can be used in WAN cases
+ //
+
+ // RtlZeroMemory (TempAddress.NodeAddress, 6);
+
+ *((UNALIGNED ULONG *)TempAddress.NodeAddress) = *((UNALIGNED ULONG *)FindRouteRequest->Node);
+ *((UNALIGNED USHORT *)(TempAddress.NodeAddress+4)) = *((UNALIGNED USHORT *)(FindRouteRequest->Node+4));
+
+ Segment = RipGetSegment(FindRouteRequest->Network);
+#ifdef _PNP_POWER
+ //
+ // Since we maintain the order of locks as Bind > Device > RIP table
+ // Get the lock up-front.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ IPX_BEGIN_SYNC (&SyncContext);
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // This call will return STATUS_PENDING if we need to
+ // RIP for the packet.
+ //
+
+ CTEAssert ((sizeof(USHORT)*2) <= sizeof(PVOID));
+
+ Status = RipGetLocalTarget(
+ Segment,
+ &TempAddress,
+ FindRouteRequest->Type,
+ &FindRouteRequest->LocalTarget,
+ (PUSHORT)&FindRouteRequest->Reserved2);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this find route request for completion when the
+ // RIP response arrives.
+ //
+
+ CTEAssert (FindRouteRequest->Type != IPX_FIND_ROUTE_NO_RIP); // should never pend
+
+ InsertTailList(
+ &Device->Segments[Segment].FindWaitingForRoute,
+ &FindRouteRequest->Linkage);
+
+ }
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_END_SYNC (&SyncContext);
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ if (Status != STATUS_PENDING) {
+
+ if (Status == STATUS_SUCCESS && FindRouteRequest->LocalTarget.NicId) {
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_HANDLE_TO_BINDING(Device, &FindRouteRequest->LocalTarget.NicHandle);
+
+ if (Binding->BindingSetMember) {
+
+ //
+ // It's a binding set member, we round-robin the
+ // responses across all the cards to distribute
+ // the traffic.
+ //
+
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+
+ FILL_LOCAL_TARGET(&FindRouteRequest->LocalTarget, Binding->NicId);
+
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ Binding = Device->Bindings[FindRouteRequest->LocalTarget.NicId];
+
+ if (Binding->BindingSetMember) {
+
+ //
+ // It's a binding set member, we round-robin the
+ // responses across all the cards to distribute
+ // the traffic.
+ //
+
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+
+ FindRouteRequest->LocalTarget.NicId = Binding->NicId;
+
+ }
+#endif
+ }
+
+ (*Device->UpperDrivers[FindRouteRequest->Identifier].FindRouteCompleteHandler)(
+ FindRouteRequest,
+ (BOOLEAN)((Status == STATUS_SUCCESS) ? TRUE : FALSE));
+
+ }
+
+} /* IpxInternalFindRoute */
+
+
+NTSTATUS
+IpxInternalQuery(
+ IN ULONG InternalQueryType,
+#ifdef _PNP_POWER
+ IN PNIC_HANDLE NicHandle OPTIONAL,
+#else
+ IN USHORT NicId OPTIONAL,
+#endif
+ IN OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG BufferLengthNeeded OPTIONAL
+)
+
+/*++
+
+Routine Description:
+
+ This routine is the entry point for upper drivers to query
+ information from us.
+
+Arguments:
+
+ InternalQueryType - Identifies the type of the query.
+
+ NicId - The ID to query, if needed
+
+ Buffer - Input or output buffer for the query.
+
+ BufferLength - The length of the buffer.
+
+ BufferLengthNeeded - If the buffer is too short, this returns
+ the length needed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PBINDING Binding;
+ BOOLEAN BindingNeeded;
+ ULONG LengthNeeded;
+ PIPX_LINE_INFO LineInfo;
+ PUSHORT MaximumNicId;
+ PULONG ReceiveBufferSpace;
+ TDI_ADDRESS_IPX UNALIGNED * IpxAddress;
+ IPX_SOURCE_ROUTING_INFO UNALIGNED * SourceRoutingInfo;
+ ULONG SourceRoutingLength;
+ UINT MaxUserData;
+ PDEVICE Device = IpxDevice;
+#ifdef _PNP_POWER
+ USHORT NicId = NicHandle->NicId;
+
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ //
+ // First verify the parameters.
+ //
+
+ switch (InternalQueryType) {
+
+ case IPX_QUERY_LINE_INFO:
+
+ BindingNeeded = TRUE;
+ LengthNeeded = sizeof(IPX_LINE_INFO);
+ break;
+
+ case IPX_QUERY_MAXIMUM_NIC_ID:
+ case IPX_QUERY_MAX_TYPE_20_NIC_ID:
+
+ BindingNeeded = FALSE;
+ LengthNeeded = sizeof(USHORT);
+ break;
+
+ case IPX_QUERY_IS_ADDRESS_LOCAL:
+
+ BindingNeeded = FALSE; // for now we don't need it
+ LengthNeeded = sizeof(TDI_ADDRESS_IPX);
+ break;
+
+ case IPX_QUERY_RECEIVE_BUFFER_SPACE:
+
+ BindingNeeded = TRUE;
+ LengthNeeded = sizeof(ULONG);
+ break;
+
+ case IPX_QUERY_IPX_ADDRESS:
+
+ if ((NicId == 0) &&
+ (BufferLength >= sizeof(TDI_ADDRESS_IPX))) {
+
+ RtlCopyMemory (Buffer, &Device->SourceAddress, sizeof(TDI_ADDRESS_IPX));
+ return STATUS_SUCCESS;
+
+ }
+
+ BindingNeeded = TRUE;
+ LengthNeeded = sizeof(TDI_ADDRESS_IPX);
+ break;
+
+ case IPX_QUERY_SOURCE_ROUTING:
+
+ BindingNeeded = TRUE;
+ LengthNeeded = sizeof(IPX_SOURCE_ROUTING_INFO);
+ break;
+
+#ifdef _PNP_POWER
+ //
+ // These are moved down from NB/SPX to IPX. LengthNeeded is set to 0
+ // so we dont return BUFFER_TOO_SMALL here; we assume here that
+ // Bufferlength is also 0.
+ // Buffer is actually the IRP here.
+ //
+ case IPX_QUERY_DATA_LINK_ADDRESS:
+ case IPX_QUERY_NETWORK_ADDRESS:
+
+ BindingNeeded = FALSE;
+ LengthNeeded = 0;
+ break;
+#endif
+ default:
+
+ return STATUS_NOT_SUPPORTED;
+
+ }
+
+
+ if (LengthNeeded > BufferLength) {
+ if (BufferLengthNeeded != NULL) {
+ *BufferLengthNeeded = LengthNeeded;
+ }
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ if (BindingNeeded) {
+
+ if (NicId == 0) {
+ NicId = 1;
+ }
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_ID_TO_BINDING(IpxDevice, NicId);
+ if ((Binding == NULL) ||
+ (!Binding->LineUp)) {
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ Binding = IpxDevice->Bindings[NicId];
+ if ((Binding == NULL) ||
+ (!Binding->LineUp)) {
+ return STATUS_INVALID_PARAMETER;
+ }
+#endif
+ }
+
+
+ //
+ // Now return the data.
+ //
+
+ switch (InternalQueryType) {
+
+ case IPX_QUERY_LINE_INFO:
+
+ LineInfo = (PIPX_LINE_INFO)Buffer;
+ LineInfo->LinkSpeed = Binding->MediumSpeed;
+ LineInfo->MaximumPacketSize = Binding->MaxLookaheadData + sizeof(IPX_HEADER);
+ LineInfo->MaximumSendSize = Binding->AnnouncedMaxDatagramSize + sizeof(IPX_HEADER);
+ LineInfo->MacOptions = Binding->Adapter->MacInfo.MacOptions;
+ break;
+
+ case IPX_QUERY_MAXIMUM_NIC_ID:
+
+ MaximumNicId = (PUSHORT)Buffer;
+ *MaximumNicId = MIN (Device->MaxBindings, IpxDevice->HighestExternalNicId);
+ break;
+
+ case IPX_QUERY_IS_ADDRESS_LOCAL:
+
+ IpxAddress = (TDI_ADDRESS_IPX UNALIGNED *)Buffer;
+ if (!IpxIsAddressLocal(IpxAddress)) {
+ return STATUS_NO_SUCH_DEVICE;
+ }
+ break;
+
+ case IPX_QUERY_RECEIVE_BUFFER_SPACE:
+
+ ReceiveBufferSpace = (PULONG)Buffer;
+ *ReceiveBufferSpace = Binding->Adapter->ReceiveBufferSpace;
+ break;
+
+ case IPX_QUERY_IPX_ADDRESS:
+
+ RtlCopyMemory (Buffer, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
+ break;
+
+ case IPX_QUERY_SOURCE_ROUTING:
+
+ SourceRoutingInfo = (IPX_SOURCE_ROUTING_INFO UNALIGNED *)Buffer;
+
+ MacLookupSourceRouting(
+ SourceRoutingInfo->Identifier,
+ Binding,
+ SourceRoutingInfo->RemoteAddress,
+ SourceRoutingInfo->SourceRouting,
+ &SourceRoutingLength);
+
+ //
+ // Reverse the direction of the source routing since it
+ // is returned in the outgoing order.
+ //
+
+ if (SourceRoutingLength > 0) {
+ SourceRoutingInfo->SourceRouting[0] &= 0x7f;
+ }
+ SourceRoutingInfo->SourceRoutingLength = (USHORT)SourceRoutingLength;
+
+ MacReturnMaxDataSize(
+ &Binding->Adapter->MacInfo,
+ SourceRoutingInfo->SourceRouting,
+ SourceRoutingLength,
+ Binding->MaxSendPacketSize,
+ &MaxUserData);
+
+ //
+ // MaxUserData does not include the MAC header but does include
+ // any extra 802.2 etc. headers, so we adjust for that to get the
+ // size starting at the IPX header.
+ //
+
+ SourceRoutingInfo->MaximumSendSize =
+ MaxUserData -
+ (Binding->DefHeaderSize - Binding->Adapter->MacInfo.MinHeaderLength);
+
+ break;
+
+ case IPX_QUERY_MAX_TYPE_20_NIC_ID:
+
+ MaximumNicId = (PUSHORT)Buffer;
+ *MaximumNicId = MIN (Device->MaxBindings, IpxDevice->HighestType20NicId);
+ break;
+
+#ifdef _PNP_POWER
+ case IPX_QUERY_DATA_LINK_ADDRESS:
+ case IPX_QUERY_NETWORK_ADDRESS:
+ //
+ // Call the TDI query equivalent here.
+ //
+ return IpxTdiQueryInformation(Device, (PREQUEST)Buffer);
+
+#endif
+ }
+
+#ifdef _PNP_POWER
+ //
+ // If Binding was needed earlier, it was referenced, deref it now.
+ //
+ if (BindingNeeded) {
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ }
+#endif
+
+ //
+ // If we haven't returned failure by now, succeed.
+ //
+
+ return STATUS_SUCCESS;
+
+} /* IpxInternalQuery */
+
+
+VOID
+IpxInternalIncrementWanInactivity(
+#ifdef _PNP_LATER
+// RIP not converted yet...
+//
+ IN NIC_HANDLE NicHandle
+#else
+ IN USHORT NicId
+#endif
+)
+
+/*++
+
+Routine Description:
+
+ This routine is the entry point where rip calls us to increment
+ the inactivity counter on a wan binding. This is done every
+ minute.
+
+Arguments:
+
+ NicId - The NIC ID of the wan binding.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+#ifdef _PNP_POWER
+ PBINDING Binding;
+
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ IPX_GET_LOCK1(&IpxDevice->BindAccessLock, &LockHandle1);
+ //
+ // [BUGBUGZZ] Change to NIC_HANDLE_TO_BINDING later. Not done yet since RIP not changed to
+ // use NICHANDLE instead of NicId
+ //
+ Binding = NIC_ID_TO_BINDING(IpxDevice, NicId);
+
+ if ((Binding != NULL) &&
+ (Binding->Adapter->MacInfo.MediumAsync)) {
+
+ ++Binding->WanInactivityCounter;
+
+ } else {
+
+ CTEAssert (FALSE);
+
+ }
+ IPX_FREE_LOCK1(&IpxDevice->BindAccessLock, LockHandle1);
+#else
+ PBINDING Binding = IpxDevice->Bindings[NicId];
+
+ if ((Binding != NULL) &&
+ (Binding->Adapter->MacInfo.MediumAsync)) {
+
+ ++Binding->WanInactivityCounter;
+
+ } else {
+
+ CTEAssert (FALSE);
+
+ }
+#endif
+
+} /* IpxInternalIncrementWanInactivity */
+
+
+ULONG
+IpxInternalQueryWanInactivity(
+#ifdef _PNP_LATER
+ IN NIC_HANDLE NicHandle
+#else
+ IN USHORT NicId
+#endif
+)
+
+/*++
+
+Routine Description:
+
+ This routine is the entry point where rip calls us to query
+ the inactivity counter on a wan binding.
+
+Arguments:
+
+ NicId - The NIC ID of the wan binding.
+
+Return Value:
+
+ The inactivity counter for this binding.
+
+--*/
+
+{
+#ifdef _PNP_POWER
+ PBINDING Binding;
+
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ IPX_GET_LOCK1(&IpxDevice->BindAccessLock, &LockHandle1);
+ // Binding = NIC_HANDLE_TO_BINDING(IpxDevice, &NicHandle);
+
+ Binding = NIC_ID_TO_BINDING(IpxDevice, NicId);
+ if ((Binding != NULL) &&
+ (Binding->Adapter->MacInfo.MediumAsync)) {
+ IPX_FREE_LOCK1(&IpxDevice->BindAccessLock, LockHandle1);
+ return Binding->WanInactivityCounter;
+
+ } else {
+ IPX_FREE_LOCK1(&IpxDevice->BindAccessLock, LockHandle1);
+ CTEAssert (FALSE);
+ return 0;
+
+ }
+
+#else
+ PBINDING Binding = IpxDevice->Bindings[NicId];
+
+ if ((Binding != NULL) &&
+ (Binding->Adapter->MacInfo.MediumAsync)) {
+
+ return Binding->WanInactivityCounter;
+
+ } else {
+
+ CTEAssert (FALSE);
+ return 0;
+
+ }
+#endif
+
+} /* IpxInternalQueryWanInactivity */
+
+#ifdef _PNP_POWER
+
+VOID
+IpxPnPIsnIndicate(
+ IN PVOID Param
+)
+
+/*++
+
+Routine Description:
+
+ This routine goes through the list of adapters and informs (thru' PnP indications)
+ the ISN drivers bound to IPX about any new adapters that have appeared before the
+ bind took place.
+
+ This is queued as a work item in the InternalBind routine.
+
+Arguments:
+
+ Param - the upper driver identifier.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Identifier = (ULONG)Param;
+ PDEVICE Device=IpxDevice;
+ ULONG i;
+ PBINDING Binding;
+ IPX_PNP_INFO IpxPnPInfo;
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ //
+ // Set up the LineInfo struct.
+ //
+
+ //
+ // BUGBUG: Do we give Binding-specific information here?
+ //
+ IpxPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ IpxPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ switch(Identifier) {
+ case IDENTIFIER_NB:
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ //
+ // Inform about all the adapters
+ //
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+ Binding = NIC_ID_TO_BINDING(Device, i);
+
+ if (!Binding) {
+ continue;
+ }
+
+ //
+ // We could have informed the upper driver from IpxBindAdapter
+ //
+ if (!Binding->IsnInformed[Identifier]) {
+ Binding->IsnInformed[Identifier] = TRUE;
+
+ //
+ // Inform NB - the reserved network/node address is always that of the first
+ // binding
+ //
+ if (i==1) {
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+ IpxPnPInfo.NewReservedAddress = TRUE;
+ } else {
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+ IpxPnPInfo.NewReservedAddress = FALSE;
+ }
+
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, (USHORT)i);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[Identifier].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(PNP, ("IpxPnPIsnIndicate: PnP to NB add: %lx\n", Binding));
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ }
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ break;
+
+ case IDENTIFIER_SPX:
+ //
+ // For SPX this is called directly, with the IsnInformed flag appropriately set.
+ // This is done so that the IsnInformed flag cannot be changed under
+ // us by the BindAdapter routine.
+ //
+#if 0
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ if (!NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier]) {
+ NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier] = TRUE;
+#endif
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+ //
+ // Inform of the reserved address only
+ //
+ if (Device->VirtualNetwork) {
+ IpxPnPInfo.NetworkAddress = Device->SourceAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Device->SourceAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 0);
+ } else {
+ IpxPnPInfo.NetworkAddress = NIC_ID_TO_BINDING(Device, 1)->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, NIC_ID_TO_BINDING(Device, 1)->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 1);
+ }
+
+ IpxPnPInfo.NewReservedAddress = TRUE;
+
+ // IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ (*Device->UpperDrivers[Identifier].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(PNP, ("IpxPnPIsnIndicate: PnP to SPX add: %lx\n", NIC_ID_TO_BINDING(Device, 1)));
+#if 0
+ } else {
+ CTEAssert(FALSE);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+#endif
+
+ }
+}
+#endif
diff --git a/private/ntos/tdi/isnp/ipx/ipxprocs.h b/private/ntos/tdi/isnp/ipx/ipxprocs.h
new file mode 100644
index 000000000..abfcf6ec3
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/ipxprocs.h
@@ -0,0 +1,1525 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ ipxprocs.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ IPX module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports - tagged [CH]
+ 1. Added new functions - IpxReceivePacket, IpxReceiveIndicationNew
+
+ Sanjay Anand (SanjayAn) 27-Oct-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+--*/
+
+
+//
+// MACROS.
+//
+//
+// Debugging aids
+//
+
+//
+// VOID
+// PANIC(
+// IN PSZ Message
+// );
+//
+
+#if DBG
+#define PANIC(Msg) \
+ CTEPrint ((Msg))
+#else
+#define PANIC(Msg)
+#endif
+
+
+//
+// These are define to allow CTEPrints that disappear when
+// DBG is 0.
+//
+
+#if DBG
+#define IpxPrint0(fmt) DbgPrint(fmt)
+#define IpxPrint1(fmt,v0) DbgPrint(fmt,v0)
+#define IpxPrint2(fmt,v0,v1) DbgPrint(fmt,v0,v1)
+#define IpxPrint3(fmt,v0,v1,v2) DbgPrint(fmt,v0,v1,v2)
+#define IpxPrint4(fmt,v0,v1,v2,v3) DbgPrint(fmt,v0,v1,v2,v3)
+#define IpxPrint5(fmt,v0,v1,v2,v3,v4) DbgPrint(fmt,v0,v1,v2,v3,v4)
+#define IpxPrint6(fmt,v0,v1,v2,v3,v4,v5) DbgPrint(fmt,v0,v1,v2,v3,v4,v5)
+#else
+#define IpxPrint0(fmt)
+#define IpxPrint1(fmt,v0)
+#define IpxPrint2(fmt,v0,v1)
+#define IpxPrint3(fmt,v0,v1,v2)
+#define IpxPrint4(fmt,v0,v1,v2,v3)
+#define IpxPrint5(fmt,v0,v1,v2,v3,v4)
+#define IpxPrint6(fmt,v0,v1,v2,v3,v4,v5)
+#endif
+
+
+//
+// Routines to log packets to a buffer.
+//
+
+#if DBG
+#define IPX_PACKET_LOG 1
+#endif
+
+#ifdef IPX_PACKET_LOG
+
+//
+// The size of this is 64 bytes for easy display.
+//
+
+typedef struct _IPX_PACKET_LOG_ENTRY {
+ UCHAR SendReceive;
+ UCHAR TimeStamp[5]; // low 5 digits of tick count.
+ UCHAR DestMac[6];
+ UCHAR SrcMac[6];
+ UCHAR Length[2];
+ IPX_HEADER IpxHeader;
+ UCHAR Data[14];
+} IPX_PACKET_LOG_ENTRY, *PIPX_PACKET_LOG_ENTRY;
+
+#define IPX_PACKET_LOG_LENGTH 128
+extern ULONG IpxPacketLogDebug;
+extern USHORT IpxPacketLogSocket;
+EXTERNAL_LOCK(IpxPacketLogLock);
+extern IPX_PACKET_LOG_ENTRY IpxPacketLog[IPX_PACKET_LOG_LENGTH];
+extern PIPX_PACKET_LOG_ENTRY IpxPacketLogLoc;
+extern PIPX_PACKET_LOG_ENTRY IpxPacketLogEnd;
+
+//
+// Bit fields in IpxPacketLogDebug
+//
+
+#define IPX_PACKET_LOG_RCV_RIP 0x0001 // All RIP packets
+#define IPX_PACKET_LOG_RCV_SPX 0x0002 // All SPX packets
+#define IPX_PACKET_LOG_RCV_NB 0x0004 // All Netbios packets
+#define IPX_PACKET_LOG_RCV_OTHER 0x0008 // All TDI client packets
+#define IPX_PACKET_LOG_RCV_SOCKET 0x0010 // All packets to IpxPacketLogSocket
+#define IPX_PACKET_LOG_RCV_ALL 0x0020 // All packets (even non-IPX)
+
+#define IPX_PACKET_LOG_SEND_RIP 0x0001 // All RIP packets
+#define IPX_PACKET_LOG_SEND_SPX 0x0002 // All SPX packets
+#define IPX_PACKET_LOG_SEND_NB 0x0004 // All Netbios packets
+#define IPX_PACKET_LOG_SEND_OTHER 0x0008 // All TDI client packets
+#define IPX_PACKET_LOG_SEND_SOCKET 0x0010 // All packets from IpxPacketLogSocket
+
+VOID
+IpxLogPacket(
+ IN BOOLEAN Send,
+ IN PUCHAR DestMac,
+ IN PUCHAR SrcMac,
+ IN USHORT Length,
+ IN PVOID IpxHeader,
+ IN PVOID Data
+ );
+
+#define PACKET_LOG(_Bit) (IpxPacketLogDebug & (_Bit))
+
+#else // IPX_PACKET_LOG
+
+#define IpxLogPacket(_MacHeader,_Length,_IpxHeader,_Data)
+#define PACKET_LOG(_Bit) 0
+
+#endif // IPX_PACKET_LOG
+
+#ifdef _PNP_POWER
+//
+// In load-only PnP, references are not needed on adapters. This should be changed
+// to actually take the reference post 4.0.
+//
+// BUGBUG: Revisit Post 4.0 - Keep the actual instructions around for ease of activation later.
+//
+#define IpxReferenceAdapter(_adapter)
+ // InterlockedIncrement(&(_adapter)->ReferenceCount)
+
+#define IpxDereferenceAdapter(_adapter)
+/*
+ if (InterlockedDecrement(&(_adapter)->ReferenceCount) == 0) {\
+ IpxCloseNdis(_adapter); \
+ IpxDestroyAdapter(_adapter);\
+ }\
+*/
+#endif
+
+//
+// In load-only PnP case, we dont need the references on bindings. All such references
+// have been changed to this macro.
+//
+#define IpxReferenceBinding1(_Binding, _Type)
+
+#define IpxDereferenceBinding1(_Binding, _Type)
+
+#if DBG
+
+#define IpxReferenceBinding(_Binding, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Binding)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefBinding (_Binding)
+
+#define IpxDereferenceBinding(_Binding, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Binding)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefBinding (_Binding)
+
+#define IpxReferenceDevice(_Device, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Device)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefDevice (_Device)
+
+#define IpxDereferenceDevice(_Device, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Device)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefDevice (_Device)
+
+
+#define IpxReferenceAddress(_Address, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Address)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefAddress (_Address)
+
+#define IpxReferenceAddressLock(_Address, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Address)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefAddressLock (_Address)
+
+#define IpxDereferenceAddress(_Address, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Address)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefAddress (_Address)
+
+#define IpxDereferenceAddressSync(_Address, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Address)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefAddressSync (_Address)
+
+
+#define IpxReferenceAddressFile(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefAddressFile (_AddressFile)
+
+#define IpxReferenceAddressFileLock(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefAddressFileLock (_AddressFile)
+
+#define IpxReferenceAddressFileSync(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefAddressFileSync (_AddressFile)
+
+#define IpxDereferenceAddressFile(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefAddressFile (_AddressFile)
+
+#define IpxDereferenceAddressFileSync(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefAddressFileSync (_AddressFile)
+
+#define IpxTransferReferenceAddressFile(_AddressFile, _OldType, _NewType) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_NewType], \
+ 1, \
+ &IpxGlobalInterlock); \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_OldType], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock);
+
+#else // DBG
+
+#define IpxReferenceBinding(_Binding, _Type) \
+ InterlockedIncrement(&(_Binding)->ReferenceCount)
+
+#define IpxDereferenceBinding(_Binding, _Type) \
+ IpxDerefBinding (_Binding)
+
+#define IpxReferenceDevice(_Device, _Type) \
+ InterlockedIncrement(&(_Device)->ReferenceCount)
+
+#define IpxDereferenceDevice(_Device, _Type) \
+ IpxDerefDevice (_Device)
+
+#define IpxReferenceAddress(_Address, _Type) \
+ InterlockedIncrement(&(_Address)->ReferenceCount)
+
+#define IpxReferenceAddressLock(_Address, _Type) \
+ InterlockedIncrement(&(_Address)->ReferenceCount)
+
+#define IpxDereferenceAddress(_Address, _Type) \
+ IpxDerefAddress (_Address)
+
+#define IpxDereferenceAddressSync(_Address, _Type) \
+ IpxDerefAddressSync (_Address)
+
+#define IpxReferenceAddressFile(_AddressFile, _Type) \
+ InterlockedIncrement(&(_AddressFile)->ReferenceCount)
+
+#define IpxReferenceAddressFileLock(_AddressFile, _Type) \
+ InterlockedIncrement(&(_AddressFile)->ReferenceCount)
+
+#define IpxReferenceAddressFileSync(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG( \
+ &(_AddressFile)->ReferenceCount, \
+ 1, \
+ (_AddressFile)->AddressLock)
+
+#define IpxDereferenceAddressFile(_AddressFile, _Type) \
+ if (InterlockedDecrement(&(_AddressFile)->ReferenceCount) == 0) { \
+ IpxDestroyAddressFile (_AddressFile); \
+ }
+
+#define IpxDereferenceAddressFileSync(_AddressFile, _Type) \
+ if (InterlockedDecrement(&(_AddressFile)->ReferenceCount) == 0) { \
+ IpxDestroyAddressFile (_AddressFile); \
+ }
+
+#define IpxTransferReferenceAddressFile(_AddressFile, _OldType, _NewType)
+
+#endif // DBG
+
+
+
+#if DBG
+
+#define IpxAllocateMemory(_BytesNeeded,_Tag,_Description) \
+ IpxpAllocateTaggedMemory(_BytesNeeded,_Tag,_Description)
+
+#define IpxFreeMemory(_Memory,_BytesAllocated,_Tag,_Description) \
+ IpxpFreeTaggedMemory(_Memory,_BytesAllocated,_Tag,_Description)
+
+#else // DBG
+
+#define IpxAllocateMemory(_BytesNeeded,_Tag,_Description) \
+ IpxpAllocateMemory(_BytesNeeded,_Tag,(BOOLEAN)((_Tag) != MEMORY_CONFIG))
+
+#define IpxFreeMemory(_Memory,_BytesAllocated,_Tag,_Description) \
+ IpxpFreeMemory(_Memory,_BytesAllocated,(BOOLEAN)((_Tag) != MEMORY_CONFIG))
+
+
+#endif // DBG
+
+
+//
+// This routine compares two node addresses.
+//
+
+#define IPX_NODE_EQUAL(_A,_B) \
+ ((*(UNALIGNED ULONG *)((PUCHAR)(_A)) == *(UNALIGNED ULONG *)((PUCHAR)(_B))) && \
+ (*(UNALIGNED USHORT *)(((PUCHAR)(_A))+4) == *(UNALIGNED USHORT *)(((PUCHAR)(_B))+4)))
+
+//
+// This routine checks if an address is the broadcast address.
+//
+
+#define IPX_NODE_BROADCAST(_A) \
+ ((*(UNALIGNED ULONG *)((PUCHAR)(_A)) == 0xffffffff) && \
+ (*(UNALIGNED USHORT *)(((PUCHAR)(_A))+4) == 0xffff))
+
+//
+// This routine does an ordered compare of two node addresses. It
+// can handle the first address having the source-routing bit on.
+//
+
+#define IPX_NODE_COMPARE(_A,_B,_R) \
+ if ((*(_R) = (*(UNALIGNED SHORT *)(((PUCHAR)(_A))+4) - *(UNALIGNED SHORT *)(((PUCHAR)(_B))+4))) == 0) { \
+ *(_R) = ((*(UNALIGNED LONG *)((PUCHAR)(_A)) & 0xffffff7f) - *(UNALIGNED LONG *)((PUCHAR)(_B))); \
+ }
+
+
+
+//
+// Routines in action.c
+//
+
+NTSTATUS
+IpxTdiAction(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+IpxCancelAction(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+IpxAbortLineChanges(
+ IN PVOID ControlChannelContext
+ );
+
+
+//
+// Routines in adapter.c
+//
+
+VOID
+IpxRefBinding(
+ IN PBINDING Binding
+ );
+
+VOID
+IpxDerefBinding(
+ IN PBINDING Binding
+ );
+
+NTSTATUS
+IpxCreateAdapter(
+ IN PDEVICE Device,
+ IN PUNICODE_STRING AdapterName,
+ IN OUT PADAPTER *AdapterPtr
+ );
+
+VOID
+IpxDestroyAdapter(
+ IN PADAPTER Adapter
+ );
+
+NTSTATUS
+IpxCreateBinding(
+ IN PDEVICE Device,
+ IN PBINDING_CONFIG ConfigBinding OPTIONAL,
+ IN ULONG NetworkNumberIndex,
+ IN PWCHAR AdapterName,
+ IN OUT PBINDING *BindingPtr
+ );
+
+VOID
+IpxDestroyBinding(
+ IN PBINDING Binding
+ );
+
+#ifdef _PNP_POWER
+VOID
+IpxAllocateBindingPool(
+ IN PDEVICE Device
+ );
+
+PSINGLE_LIST_ENTRY
+IpxPopBinding(
+ PDEVICE Device
+ );
+#endif
+
+//
+// Routines in address.c
+//
+
+TDI_ADDRESS_IPX UNALIGNED *
+IpxParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress
+ );
+
+BOOLEAN
+IpxValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength
+ );
+
+#if DBG
+
+VOID
+IpxBuildTdiAddress(
+ IN PVOID AddressBuffer,
+ IN ULONG Network,
+ IN UCHAR Node[6],
+ IN USHORT Socket
+ );
+
+#else
+
+#define IpxBuildTdiAddress(_AddressBuffer,_Network,_Node,_Socket) { \
+ TA_IPX_ADDRESS UNALIGNED * _IpxAddress = (TA_IPX_ADDRESS UNALIGNED *)(_AddressBuffer); \
+ _IpxAddress->TAAddressCount = 1; \
+ _IpxAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX); \
+ _IpxAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX; \
+ _IpxAddress->Address[0].Address[0].NetworkAddress = (_Network); \
+ _IpxAddress->Address[0].Address[0].Socket = (_Socket); \
+ RtlCopyMemory(_IpxAddress->Address[0].Address[0].NodeAddress, (_Node), 6); \
+}
+
+#endif
+
+NTSTATUS
+IpxOpenAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+USHORT
+IpxAssignSocket(
+ IN PDEVICE Device
+ );
+
+PADDRESS
+IpxCreateAddress(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ );
+
+NTSTATUS
+IpxVerifyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+IpxDestroyAddress(
+ IN PVOID Parameter
+ );
+
+#if DBG
+
+VOID
+IpxRefAddress(
+ IN PADDRESS Address
+ );
+
+VOID
+IpxRefAddressLock(
+ IN PADDRESS Address
+ );
+
+#endif
+
+VOID
+IpxDerefAddress(
+ IN PADDRESS Address
+ );
+
+VOID
+IpxDerefAddressSync(
+ IN PADDRESS Address
+ );
+
+PADDRESS_FILE
+IpxCreateAddressFile(
+ IN PDEVICE Device
+ );
+
+NTSTATUS
+IpxDestroyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+#if DBG
+
+VOID
+IpxRefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+IpxRefAddressFileLock(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+IpxRefAddressFileSync(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+IpxDerefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+IpxDerefAddressFileSync(
+ IN PADDRESS_FILE AddressFile
+ );
+
+#endif
+
+PADDRESS
+IpxLookupAddress(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ );
+
+NTSTATUS
+IpxStopAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+NTSTATUS
+IpxCloseAddressFile(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+//
+// Routines in device.c
+//
+
+VOID
+IpxRefDevice(
+ IN PDEVICE Device
+ );
+
+VOID
+IpxDerefDevice(
+ IN PDEVICE Device
+ );
+
+NTSTATUS
+IpxCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN ULONG SegmentCount,
+ IN OUT PDEVICE *DevicePtr
+ );
+
+VOID
+IpxDestroyDevice(
+ IN PDEVICE Device
+ );
+
+
+//
+// Routines in driver.c
+//
+#ifdef _PNP_POWER
+VOID
+IpxPnPUpdateDevice(
+ IN PDEVICE Device
+ );
+#endif
+
+BOOLEAN
+IpxIsAddressLocal(
+ IN TDI_ADDRESS_IPX UNALIGNED * SourceAddress
+ );
+
+PVOID
+IpxpAllocateMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN BOOLEAN ChargeDevice
+ );
+
+VOID
+IpxpFreeMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN BOOLEAN ChargeDevice
+ );
+
+#if DBG
+
+PVOID
+IpxpAllocateTaggedMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ );
+
+VOID
+IpxpFreeTaggedMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ );
+
+#endif
+
+VOID
+IpxWriteResourceErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue
+ );
+
+VOID
+IpxWriteGeneralErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN ULONG DumpDataCount,
+ IN ULONG DumpData[]
+ );
+
+VOID
+IpxWriteOidErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR AdapterString,
+ IN ULONG OidValue
+ );
+
+#ifdef _PNP_POWER
+ULONG
+IpxResolveAutoDetect(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings,
+ IN CTELockHandle *LockHandle1,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+VOID
+IpxResolveBindingSets(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings
+ );
+
+NTSTATUS
+IpxBindToAdapter(
+ IN PDEVICE Device,
+ IN PBINDING_CONFIG ConfigAdapter,
+ IN PADAPTER *AdapterPtr,
+ IN ULONG FrameTypeIndex
+ );
+
+NTSTATUS
+IpxUnBindFromAdapter(
+ IN PBINDING Binding
+ );
+
+VOID
+IpxPnPUpdateBindingArray(
+ IN PDEVICE Device,
+ IN PADAPTER Adapter,
+ IN PBINDING_CONFIG ConfigBinding
+ );
+
+VOID
+IpxPnPToLoad();
+
+NTSTATUS
+IpxPnPReallocateBindingArray(
+ IN PDEVICE Device,
+ IN ULONG Size
+ );
+
+#endif _PNP_POWER
+
+//
+// Routines in event.c
+//
+
+NTSTATUS
+IpxTdiSetEventHandler(
+ IN PREQUEST Request
+ );
+
+
+//
+// Routines in ind.c
+//
+
+//
+// [CH] Added these two functions
+//
+INT
+IpxReceivePacket (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet
+ );
+
+NDIS_STATUS
+IpxReceiveIndicationNew(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize,
+ IN PMDL pMdl,
+ IN PINT pTdiClientCount
+ );
+
+NDIS_STATUS
+IpxReceiveIndication(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+VOID
+IpxReceiveComplete(
+ IN NDIS_HANDLE BindingContext
+ );
+
+NTSTATUS
+IpxUpdateBindingNetwork(
+ IN PDEVICE Device,
+ IN PBINDING Binding,
+ IN ULONG Network
+ );
+
+
+//
+// Routines in internal.c
+//
+
+NTSTATUS
+IpxInternalBind(
+ IN PDEVICE Device,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+IpxInternalUnbind(
+ IN PDEVICE Device,
+ IN UINT Identifier
+ );
+
+VOID
+IpxInternalFindRoute(
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest
+ );
+
+NTSTATUS
+IpxInternalQuery(
+ IN ULONG InternalQueryType,
+#ifdef _PNP_POWER
+ IN PNIC_HANDLE NicHandle OPTIONAL,
+#else
+ IN USHORT NicId OPTIONAL,
+#endif
+ IN OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG BufferLengthNeeded OPTIONAL
+);
+
+VOID
+IpxInternalIncrementWanInactivity(
+#ifdef _PNP_LATER
+ IN NIC_HANDLE NicHandle
+#else
+ IN USHORT NicId
+#endif
+);
+
+ULONG
+IpxInternalQueryWanInactivity(
+#ifdef _PNP_LATER
+ IN NIC_HANDLE NicHandle
+#else
+ IN USHORT NicId
+#endif
+);
+
+#ifdef _PNP_POWER
+VOID
+IpxPnPIsnIndicate(
+ IN PVOID Param
+);
+#endif
+
+//
+// Routines in ndis.c
+//
+
+NTSTATUS
+IpxRegisterProtocol(
+ IN PNDIS_STRING NameString
+ );
+
+VOID
+IpxDeregisterProtocol(
+ VOID
+ );
+
+NTSTATUS
+IpxInitializeNdis(
+ IN PADAPTER Adapter,
+ IN PBINDING_CONFIG ConfigBinding
+ );
+
+VOID
+IpxAddBroadcast(
+ IN PDEVICE Device
+ );
+
+VOID
+IpxRemoveBroadcast(
+ IN PDEVICE Device
+ );
+
+VOID
+IpxBroadcastOperation(
+ IN PVOID Parameter
+ );
+
+BOOLEAN
+IpxIsAddressLocal(
+ IN TDI_ADDRESS_IPX UNALIGNED * SourceAddress
+ );
+
+VOID
+IpxCloseNdis(
+ IN PADAPTER Adapter
+ );
+
+VOID
+IpxOpenAdapterComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN NDIS_STATUS OpenErrorStatus
+ );
+
+VOID
+IpxCloseAdapterComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus
+ );
+
+VOID
+IpxResetComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus
+ );
+
+VOID
+IpxRequestComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS NdisStatus
+ );
+
+VOID
+IpxStatus(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ );
+
+VOID
+IpxStatusComplete(
+ IN NDIS_HANDLE NdisBindingContext
+ );
+
+
+#ifdef _PNP_POWER
+VOID
+IpxBindAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE BindContext,
+ IN PNDIS_STRING DeviceName,
+ IN PVOID SystemSpecific1,
+ IN PVOID SystemSpecific2
+ );
+
+VOID
+IpxUnbindAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE UnbindContext
+ );
+
+VOID
+IpxTranslate(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ OUT PNET_PNP_ID IdList,
+ IN ULONG IdListLength,
+ OUT PULONG BytesReturned
+ );
+#endif // _PNP_POWER
+
+//
+// Routines in mac.c
+//
+
+VOID
+MacInitializeBindingInfo(
+ IN struct _BINDING * Binding,
+ IN struct _ADAPTER * Adapter
+ );
+
+VOID
+MacInitializeMacInfo(
+ IN NDIS_MEDIUM MacType,
+ OUT PNDIS_INFORMATION MacInfo
+ );
+
+VOID
+MacMapFrameType(
+ IN NDIS_MEDIUM MacType,
+ IN ULONG FrameType,
+ OUT ULONG * MappedFrameType
+ );
+
+VOID
+MacReturnMaxDataSize(
+ IN PNDIS_INFORMATION MacInfo,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN UINT DeviceMaxFrameSize,
+ OUT PUINT MaxFrameSize
+ );
+
+#ifdef _PNP_POWER
+NDIS_STATUS
+IpxSendFramePreFwd(
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+#endif
+
+NDIS_STATUS
+IpxSendFrame(
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_3802_3(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_3802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_3EthernetII(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_3Snap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_5802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_5Snap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrameFddi802_3(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrameFddi802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrameFddiSnap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrameArcnet878_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrameWanEthernetII(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+VOID
+MacUpdateSourceRouting(
+ IN ULONG Database,
+ IN PADAPTER Adapter,
+ IN PUCHAR MacHeader,
+ IN ULONG MacHeaderLength
+ );
+
+VOID
+MacLookupSourceRouting(
+ IN ULONG Database,
+ IN PBINDING Binding,
+ IN UCHAR NextRouter[6],
+ IN OUT UCHAR SourceRouting[18],
+ OUT PULONG SourceRoutingLength
+ );
+
+VOID
+MacSourceRoutingTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ );
+
+VOID
+MacSourceRoutingRemove(
+ IN PBINDING Binding,
+ IN UCHAR MacAddress[6]
+ );
+
+VOID
+MacSourceRoutingClear(
+ IN PBINDING Binding
+ );
+
+
+//
+// Routines in packet.c
+//
+
+NTSTATUS
+IpxInitializeSendPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet,
+ IN PUCHAR Header
+ );
+
+#if BACK_FILL
+NTSTATUS
+IpxInitializeBackFillPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet,
+ IN PUCHAR Header
+ );
+#endif
+
+NTSTATUS
+IpxInitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PIPX_RECEIVE_PACKET Packet
+ );
+
+NTSTATUS
+NbiInitializeReceiveBuffer(
+ IN PADAPTER Adapter,
+ IN PIPX_RECEIVE_BUFFER ReceiveBuffer,
+ IN PUCHAR DataBuffer,
+ IN ULONG DataBufferLength
+ );
+
+NTSTATUS
+IpxInitializePaddingBuffer(
+ IN PDEVICE Device,
+ IN PIPX_PADDING_BUFFER PaddingBuffer,
+ IN ULONG DataBufferLength
+ );
+
+VOID
+IpxDeinitializeSendPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet
+ );
+
+#if BACK_FILL
+VOID
+IpxDeinitializeBackFillPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet
+ );
+#endif
+
+VOID
+IpxDeinitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PIPX_RECEIVE_PACKET Packet
+ );
+
+VOID
+IpxDeinitializeReceiveBuffer(
+ IN PADAPTER Adapter,
+ IN PIPX_RECEIVE_BUFFER ReceiveBuffer,
+ IN ULONG DataBufferLength
+ );
+
+VOID
+IpxDeinitializePaddingBuffer(
+ IN PDEVICE Device,
+ IN PIPX_PADDING_BUFFER PaddingBuffer,
+ IN ULONG DataBufferLength
+ );
+
+VOID
+IpxAllocateSendPool(
+ IN PDEVICE Device
+ );
+
+#if BACK_FILL
+VOID
+IpxAllocateBackFillPool(
+ IN PDEVICE Device
+ );
+#endif
+
+VOID
+IpxAllocateReceivePool(
+ IN PDEVICE Device
+ );
+
+VOID
+IpxAllocateReceiveBufferPool(
+ IN PADAPTER Adapter
+ );
+
+PSINGLE_LIST_ENTRY
+IpxPopSendPacket(
+ IN PDEVICE Device
+ );
+
+#if BACK_FILL
+PSINGLE_LIST_ENTRY
+IpxPopBackFillPacket(
+ IN PDEVICE Device
+ );
+#endif
+
+PSINGLE_LIST_ENTRY
+IpxPopReceivePacket(
+ IN PDEVICE Device
+ );
+
+PSINGLE_LIST_ENTRY
+IpxPopReceiveBuffer(
+ IN PADAPTER Adapter
+ );
+
+PIPX_PADDING_BUFFER
+IpxAllocatePaddingBuffer(
+ IN PDEVICE Device
+ );
+
+VOID
+IpxFreePaddingBuffer(
+ IN PDEVICE Device
+ );
+
+
+
+//
+// Routines in query.c
+//
+
+NTSTATUS
+IpxTdiQueryInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+IpxTdiSetInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+//
+// Routines in receive.c
+//
+
+VOID
+IpxTransferDataComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus,
+ IN UINT BytesTransferred
+ );
+
+
+VOID
+IpxTransferData(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+NTSTATUS
+IpxTdiReceiveDatagram(
+ IN PREQUEST Request
+ );
+
+VOID
+IpxCancelReceiveDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+
+//
+// Routines in rip.c
+//
+
+NTSTATUS
+RipGetLocalTarget(
+ IN ULONG Segment,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN UCHAR Type,
+ OUT PIPX_LOCAL_TARGET LocalTarget,
+ OUT USHORT Counts[2] OPTIONAL
+ );
+
+NTSTATUS
+RipQueueRequest(
+ IN ULONG Network,
+ IN USHORT Operation
+ );
+
+VOID
+RipSendResponse(
+ IN PBINDING Binding,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PIPX_LOCAL_TARGET LocalTarget
+ );
+
+VOID
+RipShortTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ );
+
+VOID
+RipLongTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ );
+
+VOID
+RipCleanupPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_RESERVED RipReserved
+ );
+
+VOID
+RipProcessResponse(
+ IN PDEVICE Device,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN RIP_PACKET UNALIGNED * RipPacket
+ );
+
+VOID
+RipHandleRoutePending(
+ IN PDEVICE Device,
+ IN UCHAR Network[4],
+ IN CTELockHandle LockHandle,
+ IN BOOLEAN Success,
+ IN OPTIONAL PIPX_LOCAL_TARGET LocalTarget,
+ IN OPTIONAL USHORT HopCount,
+ IN OPTIONAL USHORT TickCount
+ );
+
+NTSTATUS
+RipInsertLocalNetwork(
+ IN ULONG Network,
+ IN USHORT NicId,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN USHORT Count
+ );
+
+VOID
+RipAdjustForBindingChange(
+ IN USHORT NicId,
+ IN USHORT NewNicId,
+ IN IPX_BINDING_CHANGE_TYPE ChangeType
+ );
+
+UINT
+RipGetSegment(
+ IN UCHAR Network[4]
+ );
+
+PIPX_ROUTE_ENTRY
+RipGetRoute(
+ IN UINT Segment,
+ IN UCHAR Network[4]
+ );
+
+BOOLEAN
+RipAddRoute(
+ IN UINT Segment,
+ IN PIPX_ROUTE_ENTRY RouteEntry
+ );
+
+BOOLEAN
+RipDeleteRoute(
+ IN UINT Segment,
+ IN PIPX_ROUTE_ENTRY RouteEntry
+ );
+
+PIPX_ROUTE_ENTRY
+RipGetFirstRoute(
+ IN UINT Segment
+ );
+
+PIPX_ROUTE_ENTRY
+RipGetNextRoute(
+ IN UINT Segment
+ );
+
+VOID
+RipDropRemoteEntries(
+ VOID
+ );
+
+
+//
+// Routines in send.c
+//
+
+VOID
+IpxSendComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ );
+
+NTSTATUS
+IpxTdiSendDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PREQUEST Request
+ );
+
+#if DBG
+VOID
+IpxConstructHeader(
+ IN PUCHAR Header,
+ IN USHORT PacketLength,
+ IN UCHAR PacketType,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PTDI_ADDRESS_IPX LocalAddress
+ );
+#else
+#define IpxConstructHeader(_Header,_PacketLength,_PacketType,_RemoteAddress,_LocalAddress) { \
+ PIPX_HEADER _IpxHeader = (PIPX_HEADER)(_Header); \
+ _IpxHeader->CheckSum = 0xffff; \
+ _IpxHeader->PacketLength[0] = (UCHAR)((_PacketLength) / 256); \
+ _IpxHeader->PacketLength[1] = (UCHAR)((_PacketLength) % 256); \
+ _IpxHeader->TransportControl = 0; \
+ _IpxHeader->PacketType = (_PacketType); \
+ RtlCopyMemory(_IpxHeader->DestinationNetwork, (PVOID)(_RemoteAddress), 12); \
+ RtlCopyMemory(_IpxHeader->SourceNetwork, (_LocalAddress), 12); \
+}
+#endif
+
+//
+// Routines in loopback.c
+//
+
+VOID
+IpxDoLoopback(
+ IN CTEEvent *Event,
+ IN PVOID Context
+ );
+
+VOID
+IpxInitLoopback();
+
+VOID
+IpxLoopbackEnque(
+ IN PNDIS_PACKET Packet,
+ IN PVOID Context
+ );
+
diff --git a/private/ntos/tdi/isnp/ipx/ipxtypes.h b/private/ntos/tdi/isnp/ipx/ipxtypes.h
new file mode 100644
index 000000000..0cc788a8f
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/ipxtypes.h
@@ -0,0 +1,1999 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ ipxtypes.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ IPX module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports - tagged [CH]
+
+ Sanjay Anand (SanjayAn) 27-Oct-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+--*/
+
+
+//
+// Definition of the protocol reserved field of a send packet.
+//
+
+typedef struct _IPX_SEND_RESERVED {
+ UCHAR Identifier; // 0 for IPX packets
+ BOOLEAN SendInProgress; // used in an NdisSend
+ BOOLEAN OwnedByAddress; // packet is owned by an address
+ UCHAR DestinationType; // one of DEF, BCAST, MCAST
+ struct _IPX_PADDING_BUFFER * PaddingBuffer; // if one was allocated
+ PNDIS_BUFFER PreviousTail; // if padding buffer was appended
+#ifdef _PNP_POWER
+ IPX_LOCAL_TARGET LocalTarget;
+ USHORT CurrentNicId; // current binding being tried for net 0 sends
+ ULONG PacketLength; // length that comes into IpxSendFrame initially
+ BOOLEAN Net0SendSucceeded; // at least one NdisSend succeeded for net 0 sends
+#endif
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free queue
+ LIST_ENTRY GlobalLinkage; // all packets are on this
+ LIST_ENTRY WaitLinkage; // when on WaitingForRoute/WaitingRipPackets
+#ifdef IPX_TRACK_POOL
+ PVOID Pool; // send pool it was allocated from
+#endif
+ struct _ADDRESS * Address; // that owns this packet, if ones does
+
+ //
+ // The next fields are used differently depending on whether
+ // the packet is being used for a datagram send or a rip request.
+ //
+
+ union {
+ struct {
+ PREQUEST Request; // send datagram request
+ struct _ADDRESS_FILE * AddressFile; // that this send is on
+ USHORT CurrentNicId; // current binding being tried for net 0 sends
+ BOOLEAN Net0SendSucceeded; // at least one NdisSend succeeded for net 0 sends
+ BOOLEAN OutgoingSap; // packet is sent from the SAP socket
+ } SR_DG;
+ struct {
+ ULONG Network; // net we are looking for
+ USHORT CurrentNicId; // current binding being tried
+ UCHAR RetryCount; // number of times sent; 0xfe = response, 0xff = down
+ BOOLEAN RouteFound; // network has been found
+ USHORT SendTime; // timer expirations when sent.
+ BOOLEAN NoIdAdvance; // don't advance CurrentNicId this time.
+ } SR_RIP;
+ } u;
+
+ PUCHAR Header; // points to the MAC/IPX header
+ PNDIS_BUFFER HeaderBuffer; // the NDIS_BUFFER describing Header;
+#if BACK_FILL
+ BOOLEAN BackFill; // 1 if we are using SMB's extended header
+ PNDIS_BUFFER IpxHeader; // Place holder for our IpxHeader
+ PNDIS_BUFFER MacHeader; // Place holder for our mac header
+ PVOID MappedSystemVa;
+ PVOID ByteOffset;
+ LONG UserLength;
+#endif
+} IPX_SEND_RESERVED, *PIPX_SEND_RESERVED;
+
+//
+// Values for the DestinationType field.
+//
+
+#define DESTINATION_DEF 1
+#define DESTINATION_BCAST 2
+#define DESTINATION_MCAST 3
+
+//
+// Used to indicate to IpxReceiveIndication that this is a loopback packet
+// Assumption: Ndis cannot return this as the NdisBindingHandle value since
+// that is a pointer (our pointers shd in kernel space, if not in Nonpaged pool).
+//
+#define IPX_LOOPBACK_COOKIE 0x00460007
+
+//
+// MIN/MAX macros
+//
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+#ifdef _PNP_POWER
+
+//
+// In order to avoid a lock to read a value, this is used.
+// As long as the final value has made it to _b by the time
+// the check is made, this works fine.
+//
+
+#define ASSIGN_LOOP(_a, _b) \
+ do { \
+ _a = _b; \
+ } while ( _a != _b );
+
+//
+// Gets the value of a Ulong (possibly a pointer) by adding 0 in an interlocked manner.
+// This relies on the fact that the return of the ExchangeAdd will be the value prior to
+// addition. Since the value added is 0, the final value stays the same.
+//
+#define GET_VALUE(x) \
+ InterlockedExchangeAdd((PULONG)&(x), 0)
+
+#define SET_VALUE(x,y) \
+ InterlockedExchange((PLONG)&(x), (LONG)(y))
+
+/*
+PBINDING
+NIC_ID_TO_BINDING (
+ IN PDEVICE _device,
+ IN USHORT _nicid
+ );
+*/
+//
+// We need to ensure that the binding array pointer is valid hence use the interlocked operation.
+// Also, the binding pointer read out of the array should be valid. Since the bindings are never
+// freed (IPX maintains a pool of bindings), the pointer thus retrieved will always point to
+// memory that belongs to us, which in the worst case could point to a re-claimed binding block.
+//
+// BUGBUGZZ: we can eliminate the second interlock if we always ensure that the bindings in an array
+// dont change i.e. when we move around bindings, do them in a copy and make that the master (thru'
+// a single ulong exchange).
+//
+// A problem that still remains here is that even if we get a valid (IPX owned non-paged) ptr out of
+// the array, we still cannot atomically get a ref on the binding
+// We might need those locks after all.... (revisit post SUR when the delete is enabled).
+//
+#define NIC_ID_TO_BINDING(_device, _nicid) \
+ ((PBINDING)GET_VALUE( ((PBIND_ARRAY_ELEM) GET_VALUE( (_device)->Bindings) )[_nicid].Binding ))
+
+/*
+PBINDING
+NIC_ID_TO_BINDING_NO_ILOCK (
+ IN PDEVICE _device,
+ IN USHORT _nicid
+ );
+*/
+//
+// No interlocked operations are used here to get to the binding. This is used in the PnP add/delete
+// adapter paths on the assumption that NDIS will serialize the addition/deletion of cards. [JammelH: 5/15/96]
+//
+#define NIC_ID_TO_BINDING_NO_ILOCK(_device, _nicid) \
+ ((_device)->Bindings[_nicid].Binding)
+
+/*
+VOID
+INSERT_BINDING(
+ IN PDEVICE _device,
+ IN USHORT _nicid,
+ IN PBINDING _binding
+ )
+*/
+//
+// We dont do a get_value for the first arg of the macro since we are the writer and
+// this value cannot change from under us here (NDIS will not give us two PnP Add adapter
+// indications simultaneously).
+//
+#define INSERT_BINDING(_device, _nicid, _binding) \
+ SET_VALUE((_device)->Bindings[_nicid].Binding, (_binding));
+
+/*
+VOID
+SET_VERSION(
+ IN PDEVICE _device,
+ IN USHORT _nicid
+ )
+*/
+#define SET_VERSION(_device, _nicid) \
+ SET_VALUE((_device)->Bindings[_nicid].Version, ++(_device)->BindingVersionNumber);
+
+/*
+PBINDING
+NIC_HANDLE_TO_BINDING (
+ IN PDEVICE _device,
+ IN PNIC_HANDLE _nichandle,
+ );
+*/
+#ifdef _PNP_LATER
+#define NIC_HANDLE_TO_BINDING(_device, _nichandle) \
+ (((_nichandle)->Signature == IPX_BINDING_SIGNATURE) && \
+ ((_nichandle)->Version == (_device)->Bindings[(_nichandle)->NicId].Version)) ? \
+ (_device)->Bindings[(_nichandle)->NicId].Binding : NULL;
+#else
+
+#define NIC_HANDLE_TO_BINDING(_device, _nichandle) \
+ NIC_ID_TO_BINDING(_device, (_nichandle)->NicId);
+#endif
+
+/*
+VOID
+FILL_LOCAL_TARGET(
+ IN PLOCAL_TARGET _localtarget,
+ IN USHORT _nicid
+ )
+*/
+
+#define FILL_LOCAL_TARGET(_localtarget, _nicid) \
+ NIC_HANDLE_FROM_NIC((_localtarget)->NicHandle, _nicid)
+
+#ifdef _PNP_LATER
+#define NIC_HANDLE_FROM_NIC(_nichandle, _nic) \
+ _nichandle.NicId = _nic; \
+ _nichandle.Signature = IPX_BINDING_SIGNATURE; \
+ if (_nic == 0) { \
+ _nichandle.Version = 0; \
+ } else { \
+ _nichandle.Version = IpxDevice->Bindings[_nic].Version; \
+ }
+
+#else
+
+#define NIC_HANDLE_FROM_NIC(_nichandle, _nic) \
+ _nichandle.NicId = _nic;
+
+#endif
+
+#define NIC_FROM_LOCAL_TARGET(_localtarget) \
+ (_localtarget)->NicHandle.NicId
+
+#endif _PNP_POWER
+
+//
+// Definition of the protocol reserved field of a receive packet.
+//
+
+typedef struct _IPX_RECEIVE_RESERVED {
+ UCHAR Identifier; // 0 for IPX packets
+ BOOLEAN TransferInProgress; // used in an NdisTransferData
+ BOOLEAN OwnedByAddress; // packet is owned by an address
+#ifdef IPX_TRACK_POOL
+ PVOID Pool; // send pool it was allocated from
+#endif
+ struct _ADDRESS * Address; // that owns this packet, if ones does
+ PREQUEST SingleRequest; // if transfer is for one only
+ struct _IPX_RECEIVE_BUFFER * ReceiveBuffer; // if transfer is for multiple requests
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free queue
+ LIST_ENTRY GlobalLinkage; // all packets are on this
+ LIST_ENTRY Requests; // waiting on this transfer
+} IPX_RECEIVE_RESERVED, *PIPX_RECEIVE_RESERVED;
+
+//
+// The amount of data we need in our standard header, rounded up
+// to the next longword bounday.
+//
+// [BUGBUGZZ] Make this declaration in one place
+//
+#define PACKET_HEADER_SIZE (MAC_HEADER_SIZE + IPX_HEADER_SIZE + RIP_PACKET_SIZE)
+
+//
+// Types to abstract NDIS packets. This is to allow us to
+// switch from using our own memory for packets to using
+// authentically allocated NDIS packets.
+//
+
+// #define IPX_OWN_PACKETS 1
+
+#define IpxAllocateSendPacket(_Device,_SendPacket,_Status) { \
+ NdisReinitializePacket((PNDIS_PACKET)(PACKET(_SendPacket))); \
+ *(_Status) = STATUS_SUCCESS; \
+}
+
+#define IpxAllocateReceivePacket(_Device,_ReceivePacket,_Status) { \
+ NdisReinitializePacket((PNDIS_PACKET)(PACKET(_ReceivePacket))); \
+ *(_Status) = STATUS_SUCCESS; \
+}
+
+#ifdef IPX_OWN_PACKETS
+
+#define NDIS_PACKET_SIZE 48
+// #define NDIS_PACKET_SIZE FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])
+
+typedef struct _IPX_SEND_PACKET {
+ UCHAR Data[NDIS_PACKET_SIZE+sizeof(IPX_SEND_RESERVED)];
+} IPX_SEND_PACKET, *PIPX_SEND_PACKET;
+
+typedef struct _IPX_RECEIVE_PACKET {
+ UCHAR Data[NDIS_PACKET_SIZE+sizeof(IPX_RECEIVE_RESERVED)];
+} IPX_RECEIVE_PACKET, *PIPX_RECEIVE_PACKET;
+
+#define PACKET(_Packet) ((PNDIS_PACKET)((_Packet)->Data))
+
+#define IpxFreeSendPacket(_Device,_Packet)
+
+#define IpxFreeReceivePacket(_Device,_Packet)
+
+#else // IPX_OWN_PACKETS
+
+typedef struct _IPX_SEND_PACKET {
+ PNDIS_PACKET Packet;
+ NDIS_HANDLE PoolHandle;
+} IPX_SEND_PACKET, *PIPX_SEND_PACKET;
+
+typedef struct _IPX_RECEIVE_PACKET {
+ PNDIS_PACKET Packet;
+ NDIS_HANDLE PoolHandle;
+} IPX_RECEIVE_PACKET, *PIPX_RECEIVE_PACKET;
+
+#define PACKET(_Packet) ((_Packet)->Packet)
+
+#define IpxAllocateSingleSendPacket(_Device,_SendPacket,_Status) { \
+ NdisAllocatePacketPool(_Status, &(_SendPacket)->PoolHandle,1,sizeof(IPX_SEND_RESERVED)); \
+ if (*(_Status) == NDIS_STATUS_SUCCESS) { \
+ NdisAllocatePacket(_Status, &(_SendPacket)->Packet, (_SendPacket)->PoolHandle); \
+ if (*(_Status) == NDIS_STATUS_SUCCESS) { \
+ (_Device)->MemoryUsage += \
+ (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0])+ \
+ FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])+ \
+ sizeof(IPX_SEND_RESERVED)); \
+ } else {\
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis packet memory\n"));\
+ }\
+ } else {\
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis pool memory\n"));\
+ }\
+}
+
+#define IpxAllocateSingleReceivePacket(_Device,_ReceivePacket,_Status) { \
+ NdisAllocatePacketPool(_Status, &(_ReceivePacket)->PoolHandle,1,sizeof(IPX_RECEIVE_RESERVED)); \
+ if (*(_Status) == NDIS_STATUS_SUCCESS) { \
+ NdisAllocatePacket(_Status, &(_ReceivePacket)->Packet, (_ReceivePacket)->PoolHandle); \
+ if (*(_Status) == NDIS_STATUS_SUCCESS) { \
+ (_Device)->MemoryUsage += \
+ (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0])+ \
+ FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])+ \
+ sizeof(IPX_RECEIVE_RESERVED)); \
+ } else {\
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis packet memory\n"));\
+ }\
+ } else {\
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis pool memory\n"));\
+ }\
+}
+
+#define IpxFreeSingleSendPacket(_Device,_Packet) { \
+ NdisFreePacket((_Packet).Packet); \
+ NdisFreePacketPool((_Packet).PoolHandle); \
+ (_Device)->MemoryUsage -= \
+ (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0])+ \
+ FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])+ \
+ sizeof(IPX_SEND_RESERVED)); \
+}
+#define IpxFreeSingleReceivePacket(_Device,_Packet) { \
+ NdisFreePacket((_Packet).Packet); \
+ NdisFreePacketPool((_Packet).PoolHandle); \
+ (_Device)->MemoryUsage -= \
+ (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0])+ \
+ FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])+ \
+ sizeof(IPX_RECEIVE_RESERVED)); \
+}
+
+#define IpxFreeSendPacket(_Device,_Packet) NdisFreePacket(PACKET(_Packet))
+
+#define IpxFreeReceivePacket(_Device,_Packet) NdisFreePacket(PACKET(_Packet))
+
+#endif // IPX_OWN_PACKETS
+
+#define SEND_RESERVED(_Packet) ((PIPX_SEND_RESERVED)((PACKET(_Packet))->ProtocolReserved))
+#define RECEIVE_RESERVED(_Packet) ((PIPX_RECEIVE_RESERVED)((PACKET(_Packet))->ProtocolReserved))
+
+
+//
+// This is the structure that contains a receive buffer for
+// datagrams that are going to multiple recipients.
+//
+
+typedef struct _IPX_RECEIVE_BUFFER {
+ LIST_ENTRY GlobalLinkage; // all buffers are on this
+#ifdef IPX_TRACK_POOL
+ PVOID Pool; // receive buffer pool was allocated from
+#endif
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free list
+ PNDIS_BUFFER NdisBuffer; // length of the NDIS buffer
+ ULONG DataLength; // length of the data
+ PUCHAR Data; // the actual data
+} IPX_RECEIVE_BUFFER, *PIPX_RECEIVE_BUFFER;
+
+
+//
+// This is the structure that contains a padding buffer for
+// padding ethernet frames out to an even number of bytes.
+//
+
+typedef struct _IPX_PADDING_BUFFER {
+ LIST_ENTRY GlobalLinkage; // all buffers are on this
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free list
+ PNDIS_BUFFER NdisBuffer; // length of the NDIS buffer
+ ULONG DataLength; // length of the data
+ UCHAR Data[1]; // the actual pad data
+} IPX_PADDING_BUFFER, *PIPX_PADDING_BUFFER;
+
+#ifdef IPX_OWN_PACKETS
+
+typedef struct _IPX_SEND_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ IPX_SEND_PACKET Packets[1];
+} IPX_SEND_POOL, *PIPX_SEND_POOL;
+
+typedef struct _IPX_RECEIVE_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ IPX_RECEIVE_PACKET Packets[1];
+} IPX_RECEIVE_POOL, *PIPX_RECEIVE_POOL;
+#else
+
+typedef struct _IPX_PACKET_POOL {
+ LIST_ENTRY Linkage;
+ PUCHAR Header;
+ NDIS_HANDLE PoolHandle;
+} IPX_PACKET_POOL, *PIPX_PACKET_POOL;
+
+typedef IPX_PACKET_POOL IPX_RECEIVE_POOL, *PIPX_RECEIVE_POOL;
+typedef IPX_PACKET_POOL IPX_SEND_POOL, *PIPX_SEND_POOL;
+
+#endif // IPX_OWN_PACKETS
+
+typedef struct _IPX_RECEIVE_BUFFER_POOL {
+ LIST_ENTRY Linkage;
+ UINT BufferCount;
+ UINT BufferFree;
+ IPX_RECEIVE_BUFFER Buffers[1];
+ // after the packets the data buffers are allocated also.
+} IPX_RECEIVE_BUFFER_POOL, *PIPX_RECEIVE_BUFFER_POOL;
+
+//
+// Number of upper drivers we support.
+//
+
+#define UPPER_DRIVER_COUNT 3
+
+
+
+//
+// Tags for memory allocation.
+//
+
+#define MEMORY_CONFIG 0
+#define MEMORY_ADAPTER 1
+#define MEMORY_ADDRESS 2
+#define MEMORY_PACKET 3
+#define MEMORY_RIP 4
+#define MEMORY_SOURCE_ROUTE 5
+#define MEMORY_BINDING 6
+#define MEMORY_QUERY 7
+
+#define MEMORY_MAX 8
+
+#if DBG
+
+//
+// Holds the allocations for a specific memory type.
+//
+
+typedef struct _MEMORY_TAG {
+ ULONG Tag;
+ ULONG BytesAllocated;
+} MEMORY_TAG, *PMEMORY_TAG;
+
+EXTERNAL_LOCK(IpxMemoryInterlock);
+extern MEMORY_TAG IpxMemoryTag[MEMORY_MAX];
+
+#endif
+
+
+//
+// This defines the reasons we delete rip entries for a binding.
+//
+
+typedef enum _IPX_BINDING_CHANGE_TYPE {
+ IpxBindingDeleted,
+ IpxBindingMoved,
+ IpxBindingDown
+} IPX_BINDING_CHANGE_TYPE, *PIPX_BINDING_CHANGE_TYPE;
+
+
+//
+// This structure contains information about a single
+// source routing entry.
+//
+
+typedef struct _SOURCE_ROUTE {
+
+ struct _SOURCE_ROUTE * Next; // next in hash list
+
+ UCHAR MacAddress[6]; // remote MAC address
+ UCHAR TimeSinceUsed; // timer expirations since last used
+ UCHAR SourceRoutingLength; // length of the data
+
+ UCHAR SourceRouting[1]; // source routing data, stored as received in
+
+} SOURCE_ROUTE, *PSOURCE_ROUTE;
+
+#define SOURCE_ROUTE_SIZE(_SourceRoutingLength) \
+ (FIELD_OFFSET(SOURCE_ROUTE, SourceRouting[0]) + (_SourceRoutingLength))
+
+#define SOURCE_ROUTE_HASH_SIZE 16
+
+//
+// ULONG
+// MacSourceRoutingHash(
+// IN PUCHAR MacAddress
+// )
+//
+// /*++
+//
+// Routine Description:
+//
+// This routine returns a hash value based on the MAC address
+// that is pointed to. It will be between 0 and SOURCE_ROUTE_HASH_SIZE.
+//
+// Arguments:
+//
+// MacAddress - The MAC address. NOTE: The source-routing bit may
+// or may not be on in the first byte, this routine will handle
+// that.
+//
+// Return Value:
+//
+// The hash value.
+//
+// --*/
+//
+
+#define MacSourceRoutingHash(_MacAddress) \
+ ((ULONG)((_MacAddress)[5] % SOURCE_ROUTE_HASH_SIZE))
+
+
+
+//
+// this structure describes a single NDIS adapter that IPX is
+// bound to.
+//
+
+struct _DEVICE;
+
+typedef struct _ADAPTER {
+
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+#if DBG
+ UCHAR Signature1[4]; // contains "IAD1"
+#endif
+
+#ifdef _PNP_POWER
+ ULONG ReferenceCount;
+#endif
+
+ ULONG BindingCount; // number bound to this adapter
+
+ //
+ // Handle returned by the NDIS wrapper after we bind to it.
+ //
+
+ NDIS_HANDLE NdisBindingHandle;
+
+ //
+ // The queue of (currently receive only) requests waiting to complete.
+ //
+
+ LIST_ENTRY RequestCompletionQueue;
+
+ //
+ // IPX header normal offsets for directed and
+ // broadcast/multicast frames.
+ //
+
+ ULONG DefHeaderSizes[ISN_FRAME_TYPE_MAX];
+ ULONG BcMcHeaderSizes[ISN_FRAME_TYPE_MAX];
+
+ //
+ // List of buffers to be used for transfers.
+ //
+
+ ULONG AllocatedReceiveBuffers;
+ LIST_ENTRY ReceiveBufferPoolList;
+ SLIST_HEADER ReceiveBufferList;
+
+ //
+ // List of ethernet padding buffers.
+ //
+
+ ULONG AllocatedPaddingBuffers;
+ SINGLE_LIST_ENTRY PaddingBufferList;
+
+ struct _BINDING * Bindings[ISN_FRAME_TYPE_MAX]; // the binding for each frame type.
+
+ //
+ // TRUE if broadcast reception is enabled on this adapter.
+ //
+
+ BOOLEAN BroadcastEnabled;
+
+ //
+ // TRUE if we have enabled an auto-detected frame type
+ // on this adapter -- used to prevent multiple ones.
+ //
+
+ BOOLEAN AutoDetectFound;
+
+ //
+ // TRUE if we got a response to at least one of our
+ // auto-detect frames.
+ //
+
+ BOOLEAN AutoDetectResponse;
+
+ //
+ // This is TRUE if we are auto-detecting and we have
+ // found the default auto-detect type on the net.
+ //
+
+ BOOLEAN DefaultAutoDetected;
+
+ //
+ // For WAN adapters, we support multiple bindings per
+ // adapter, all with the same frame type. For them we
+ // demultiplex using the local mac address. This stores
+ // the range of device NIC IDs associated with this
+ // particular address.
+ //
+
+ USHORT FirstWanNicId;
+ USHORT LastWanNicId;
+ ULONG WanNicIdCount;
+
+ //
+ // This is based on the configuration.
+ //
+
+ USHORT BindSap; // usually 0x8137
+ USHORT BindSapNetworkOrder; // usually 0x3781
+ BOOLEAN SourceRouting;
+ BOOLEAN EnableFunctionalAddress;
+ BOOLEAN EnableWanRouter;
+ ULONG ConfigMaxPacketSize;
+
+ //
+ // TRUE if the tree is empty, so we can check quickly.
+ //
+
+ BOOLEAN SourceRoutingEmpty[IDENTIFIER_TOTAL];
+
+ //
+ // These are kept around for error logging, and stored right
+ // after this structure.
+ //
+
+ PWCHAR AdapterName;
+ ULONG AdapterNameLength;
+
+ struct _DEVICE * Device;
+
+ CTELock Lock;
+ CTELock * DeviceLock;
+
+ //
+ // some MAC addresses we use in the transport
+ //
+
+ HARDWARE_ADDRESS LocalMacAddress; // our local hardware address.
+
+ //
+ // The value of Device->SourceRoutingTime the last time
+ // we checked the list for timeouts (this is so we can
+ // tell in the timeout code when two bindings point to the
+ // same adapter).
+ //
+
+ CHAR LastSourceRoutingTime;
+
+ //
+ // These are used while initializing the MAC driver.
+ //
+
+ KEVENT NdisRequestEvent; // used for pended requests.
+ NDIS_STATUS NdisRequestStatus; // records request status.
+ NDIS_STATUS OpenErrorStatus; // if Status is NDIS_STATUS_OPEN_FAILED.
+
+ //
+ // This is the Mac type we must build the packet header for and know the
+ // offsets for.
+ //
+
+ NDIS_INFORMATION MacInfo;
+
+ ULONG MaxReceivePacketSize; // does not include the MAC header
+ ULONG MaxSendPacketSize; // includes the MAC header
+ ULONG ReceiveBufferSpace; // as queried from the card
+
+ //
+ // This information is used to keep track of the speed of
+ // the underlying medium.
+ //
+
+ ULONG MediumSpeed; // in units of 100 bytes/sec
+
+ //
+ // The source routing tree for each of the identifiers
+ //
+
+ PSOURCE_ROUTE SourceRoutingHeads[IDENTIFIER_TOTAL][SOURCE_ROUTE_HASH_SIZE];
+
+} ADAPTER, * PADAPTER;
+
+#define ASSERT_ADAPTER(_Adapter) \
+ CTEAssert (((_Adapter)->Type == IPX_ADAPTER_SIGNATURE) && ((_Adapter)->Size == sizeof(ADAPTER)))
+
+
+//
+// These are the media and frame type specific MAC header
+// constructors that we call in the main TDI send path.
+//
+
+typedef NDIS_STATUS
+(*IPX_SEND_FRAME_HANDLER) (
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+
+#define BREF_BOUND 1
+#ifdef _PNP_POWER
+#define BREF_DEVICE_ACCESS 2
+#define BREF_ADAPTER_ACCESS 3
+#endif
+#define BREF_TOTAL 4
+
+typedef struct _BINDING {
+
+#if DBG
+ ULONG RefTypes[BREF_TOTAL];
+#endif
+
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+#if DBG
+ UCHAR Signature1[4]; // contains "IBI1"
+#endif
+
+ ULONG ReferenceCount;
+
+#ifdef _PNP_POWER
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free queue
+#endif
+
+ //
+ // Adapter this binding is on.
+ //
+
+ PADAPTER Adapter;
+
+ //
+ // ID identifying us to the system (will be the index
+ // in Device->Bindings[]).
+ //
+
+ USHORT NicId;
+
+ //
+ // For LANs these will be the same as the adapter's, for WANs
+ // they change on line up indications.
+ //
+
+ ULONG MaxSendPacketSize;
+ ULONG MediumSpeed; // in units of 100 bytes/sec
+ HARDWARE_ADDRESS LocalMacAddress; // our local hardware address.
+
+ //
+ // This is used for WAN lines, all sends go to this address
+ // which is given on line up.
+ //
+
+ HARDWARE_ADDRESS RemoteMacAddress;
+
+ //
+ // For WAN lines, holds the remote address indicated to us
+ // in the IPXCP_CONFIGURATION structure -- this is used to
+ // select a binding to send to when WanGlobalNetworkNumber
+ // is TRUE.
+ //
+
+ UCHAR WanRemoteNode[6];
+
+ //
+ // TRUE if this binding was set up to allow auto-detection,
+ // instead of being configured explicitly in the registry.
+ //
+
+ BOOLEAN AutoDetect;
+
+ //
+ // TRUE if this binding was set up for auto-detection AND
+ // was the default in the registry.
+ //
+
+ BOOLEAN DefaultAutoDetect;
+
+ //
+ // During auto-detect when we are processing responses from
+ // various networks, these keep track of how many responses
+ // we have received that match the current guess at the
+ // network number, and how many don't (the current guess
+ // is stored in TentativeNetworkAddress).
+ //
+
+ USHORT MatchingResponses;
+ USHORT NonMatchingResponses;
+
+ //
+ // During auto-detect, stores the current guess at the
+ // network number.
+ //
+
+ ULONG TentativeNetworkAddress;
+
+ //
+ // TRUE if this binding is part of a binding set.
+ //
+
+ BOOLEAN BindingSetMember;
+
+ //
+ // TRUE if this binding should receive broadcasts (this
+ // rotates through the members of a binding set).
+ //
+
+ BOOLEAN ReceiveBroadcast;
+
+ //
+ // TRUE for WAN lines if we are up.
+ //
+
+ BOOLEAN LineUp;
+
+ //
+ // TRUE if this is a WAN line and is dialout.
+ //
+
+ BOOLEAN DialOutAsync;
+
+ union {
+
+ //
+ // Used when a binding is active, if it is a member
+ // of a binding set.
+ //
+
+ struct {
+
+ //
+ // Used to link members of a binding set in a circular list.
+ // NULL for non-set members.
+ //
+
+ struct _BINDING * NextBinding;
+
+ //
+ // If this binding is a master of a binding set, this points
+ // to the binding to use for the next send. For other members
+ // of a binding set it is NULL. We use this to determine
+ // if a binding is a master or not.
+ //
+
+ struct _BINDING * CurrentSendBinding;
+
+ //
+ // For binding set members, points to the master binding
+ // (if this is the master it points to itself).
+ //
+
+ struct _BINDING * MasterBinding;
+
+ };
+
+ //
+ // This is used when we are first binding to adapters,
+ // and the device's Bindings array is not yet allocated.
+ //
+
+ LIST_ENTRY InitialLinkage;
+
+ };
+
+ //
+ // Used by rip to keep track of unused wan lines.
+ //
+
+ ULONG WanInactivityCounter;
+
+ //
+ // Our local address, we don't use the socket but we keep
+ // it here so we can do quick copies. It contains the
+ // real network that we are bound to and our node
+ // address on that net (typically the adapter's MAC
+ // address but it will change for WANs).
+ //
+
+ TDI_ADDRESS_IPX LocalAddress;
+
+ IPX_SEND_FRAME_HANDLER SendFrameHandler;
+
+ struct _DEVICE * Device;
+
+ CTELock * DeviceLock;
+
+ ULONG DefHeaderSize; // IPX header offset for directed frames
+ ULONG BcMcHeaderSize; // IPX header offset for broadcast/multicast
+
+ ULONG AnnouncedMaxDatagramSize; // what we advertise -- assumes worst-case SR
+ ULONG RealMaxDatagramSize; // what will really break the card
+ ULONG MaxLookaheadData;
+
+ //
+ // Configuration parameters. We overlay all of them except
+ // FrameType over the worker thread item we use to delay
+ // deletion -- all the others are not needed once the
+ // binding is up. Some of the config parameters are stored
+ // in the adapter, these are the ones that are modified
+ // per-binding.
+ //
+
+ ULONG FrameType;
+ union {
+ struct {
+ ULONG ConfiguredNetworkNumber;
+ BOOLEAN AllRouteDirected;
+ BOOLEAN AllRouteBroadcast;
+ BOOLEAN AllRouteMulticast;
+ };
+ WORK_QUEUE_ITEM WanDelayedQueueItem;
+ };
+
+#ifdef _PNP_POWER
+ //
+ // Indicates whether this binding was indicated to the ISN driver
+ //
+ BOOLEAN IsnInformed[UPPER_DRIVER_COUNT];
+
+ //
+ // Keeps the NetAddressRegistrationHandle.
+ //
+ HANDLE TdiRegistrationHandle;
+#endif
+} BINDING, * PBINDING;
+
+
+#ifdef _PNP_POWER
+typedef struct _IPX_BINDING_POOL {
+ LIST_ENTRY Linkage;
+ UINT BindingCount;
+ BINDING Bindings[1];
+} IPX_BINDING_POOL, *PIPX_BINDING_POOL;
+#endif
+
+//
+// This structure defines the control structure for a single
+// router table segment.
+//
+
+typedef struct _ROUTER_SEGMENT {
+ LIST_ENTRY WaitingForRoute; // packets waiting for a route in this segment
+ LIST_ENTRY FindWaitingForRoute; // find route requests waiting for a route in this segment
+ LIST_ENTRY WaitingLocalTarget; // QUERY_IPX_LOCAL_TARGETs waiting for a route in this segment
+ LIST_ENTRY WaitingReripNetnum; // MIPX_RERIPNETNUMs waiting for a route in this segment
+ LIST_ENTRY Entries;
+ PLIST_ENTRY EnumerateLocation;
+} ROUTER_SEGMENT, *PROUTER_SEGMENT;
+
+
+//
+// Number of buckets in the address hash table. This is
+// a multiple of 2 so hashing is quick.
+//
+
+#define IPX_ADDRESS_HASH_COUNT 16
+
+//
+// Routine to convert a socket to a hash index. We use the
+// high bits because it is stored reversed.
+//
+
+#define IPX_HASH_SOCKET(_S) ((((_S) & 0xff00) >> 8) % IPX_ADDRESS_HASH_COUNT)
+
+//
+// This macro gets the socket hash right out of the IPX header.
+//
+
+#define IPX_DEST_SOCKET_HASH(_IpxHeader) (((PUCHAR)&(_IpxHeader)->DestinationSocket)[1] % IPX_ADDRESS_HASH_COUNT)
+
+
+//
+// This structure defines the per-device structure for IPX
+// (one of these is allocated globally).
+//
+
+#define DREF_CREATE 0
+#define DREF_LOADED 1
+#define DREF_ADAPTER 2
+#define DREF_ADDRESS 3
+#define DREF_SR_TIMER 4
+#define DREF_RIP_TIMER 5
+#define DREF_LONG_TIMER 6
+#define DREF_RIP_PACKET 7
+#define DREF_ADDRESS_NOTIFY 8
+#define DREF_LINE_CHANGE 9
+
+#define DREF_TOTAL 12
+
+#ifdef _PNP_POWER
+//
+// Pre-allocated binding array size
+//
+#define MAX_BINDINGS 50
+#endif _PNP_POWER
+
+#ifdef _PNP_POWER
+//
+// Our new binding array is composed of the following binding
+// array element
+//
+typedef struct _BIND_ARRAY_ELEM {
+ PBINDING Binding;
+ ULONG Version;
+} BIND_ARRAY_ELEM, *PBIND_ARRAY_ELEM;
+
+#endif _PNP_POWER
+
+typedef struct _DEVICE {
+
+#if DBG
+ ULONG RefTypes[DREF_TOTAL];
+#endif
+
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+#if DBG
+ UCHAR Signature1[4]; // contains "IDC1"
+#endif
+
+ CTELock Interlock; // GLOBAL lock for reference count.
+ // (used in ExInterlockedXxx calls)
+
+ //
+ // These are temporary versions of these counters, during
+ // timer expiration we update the real ones.
+ //
+
+ ULONG TempDatagramBytesSent;
+ ULONG TempDatagramsSent;
+ ULONG TempDatagramBytesReceived;
+ ULONG TempDatagramsReceived;
+
+ //
+ // Configuration parameters.
+ //
+
+ BOOLEAN EthernetPadToEven;
+ BOOLEAN SingleNetworkActive;
+ BOOLEAN DisableDialoutSap;
+
+ //
+ // TRUE if we have multiple cards but a virtual network of 0.
+ //
+
+ BOOLEAN MultiCardZeroVirtual;
+
+ CTELock Lock;
+
+ //
+ // Lock to access the sequenced lists in the device.
+ //
+ CTELock SListsLock;
+
+ LONG ReferenceCount; // activity count/this provider.
+
+#ifdef _PNP_POWER
+
+ //
+ // Lock used to control the access to a binding (either from the
+ // binding array in the device or from the binding array in the
+ // adapter.
+ //
+ CTELock BindAccessLock;
+
+ //
+ // Registry Path for use when PnP adapters appear.
+ //
+ PWSTR RegistryPathBuffer;
+
+ UNICODE_STRING RegistryPath;
+
+ //
+ // Binding array has the Version number too
+ //
+ PBIND_ARRAY_ELEM Bindings; // allocated when number is determined.
+ ULONG BindingCount; // total allocated in Bindings.
+
+ //
+ // Monotonically increasing version number kept in bindings.
+ // Hopefully this will not wrap around...
+ //
+ ULONG BindingVersionNumber;
+#else
+ //
+ // During init we hold all bindings in a queue, but after we
+ // know the approximate number we allocate an array.
+ //
+
+ union {
+ LIST_ENTRY InitialBindingList; // only used during init.
+ struct {
+ PBINDING * Bindings; // allocated when number is determined.
+ ULONG BindingCount; // total allocated in Bindings.
+ };
+ };
+#endif _PNP_POWER
+
+
+ //
+ // ValidBindings is the number of bindings in the array which may
+ // be valid (they are lan bindings or down wan binding placeholders).
+ // It will be less than BindingCount by the number of auto-detect
+ // bindings that are thrown away. HighestExternalNicId is ValidBindings
+ // minus any binding set slaves which are moved to the end of the
+ // array. SapNicCount is like HighestExternalNicId except that
+ // if WanGlobalNetworkNumber is TRUE it will count all WAN bindings
+ // as one. HighestExternalType20NicId is like HighestExternalNicId
+ // except it stops when all the remaining bindings are down wan
+ // lines, or dialin wan lines if DisableDialinNetbios bit 1 is on.
+ //
+
+ USHORT ValidBindings;
+ USHORT HighestExternalNicId;
+ USHORT SapNicCount;
+ USHORT HighestType20NicId;
+#ifdef _PNP_POWER
+ //
+ // Keeps track of the last LAN binding's position in the binding array
+ //
+ USHORT HighestLanNicId;
+
+ //
+ // This keeps track of the current size of the binding array
+ //
+ USHORT MaxBindings;
+#endif _PNP_POWER
+
+ LIST_ENTRY GlobalSendPacketList;
+ LIST_ENTRY GlobalReceivePacketList;
+ LIST_ENTRY GlobalReceiveBufferList;
+
+#if BACK_FILL
+ LIST_ENTRY GlobalBackFillPacketList;
+#endif
+
+ //
+ // Action requests from SAP waiting for an adapter status to change.
+ //
+
+ LIST_ENTRY AddressNotifyQueue;
+
+ //
+ // Action requests from nwrdr waiting for the WAN line
+ // to go up/down.
+ //
+
+ LIST_ENTRY LineChangeQueue;
+
+ //
+ // All packet pools are chained on these lists.
+ //
+
+ LIST_ENTRY SendPoolList;
+ LIST_ENTRY ReceivePoolList;
+
+
+#if BACK_FILL
+ LIST_ENTRY BackFillPoolList;
+ SLIST_HEADER BackFillPacketList;
+#endif
+
+#ifdef _PNP_POWER
+ LIST_ENTRY BindingPoolList;
+ SLIST_HEADER BindingList;
+#endif
+
+ SLIST_HEADER SendPacketList;
+ SLIST_HEADER ReceivePacketList;
+ PIPX_PADDING_BUFFER PaddingBuffer;
+
+ UCHAR State;
+
+ UCHAR FrameTypeDefault;
+
+ //
+ // This holds state if SingleNetworkActive is TRUE. If
+ // it is TRUE then WAN nets are active; if it is FALSE
+ // then LAN nets are active.
+ //
+
+ BOOLEAN ActiveNetworkWan;
+
+ //
+ // TRUE if we have a virtual network.
+ //
+
+ BOOLEAN VirtualNetwork;
+
+ //
+ // If we are set up for SingleNetworkActive, we may have
+ // to start our broadcast of net 0 frames somewhere other
+ // than NIC ID 1, so that we don't send to the wrong type.
+ //
+
+ USHORT FirstLanNicId;
+ USHORT FirstWanNicId;
+
+ //
+ // This holds the total memory allocated for the above structures.
+ //
+
+ LONG MemoryUsage;
+ LONG MemoryLimit;
+
+ //
+ // How many of various resources have been allocated.
+ //
+
+ ULONG AllocatedDatagrams;
+ ULONG AllocatedReceivePackets;
+ ULONG AllocatedPaddingBuffers;
+
+ //
+ // Other configuration parameters.
+ //
+
+ ULONG InitDatagrams;
+ ULONG MaxDatagrams;
+ ULONG RipAgeTime;
+ ULONG RipCount;
+ ULONG RipTimeout;
+ ULONG RipUsageTime;
+ ULONG SourceRouteUsageTime;
+ USHORT SocketStart;
+ USHORT SocketEnd;
+ ULONG SocketUniqueness;
+ ULONG VirtualNetworkNumber;
+ ULONG EthernetExtraPadding;
+ BOOLEAN DedicatedRouter;
+ BOOLEAN VirtualNetworkOptional;
+ UCHAR DisableDialinNetbios;
+
+ //
+ // These are currently not read from the registry.
+ //
+
+ ULONG InitReceivePackets;
+ ULONG InitReceiveBuffers;
+ ULONG MaxReceivePackets;
+ ULONG MaxReceiveBuffers;
+
+#ifdef _PNP_POWER
+ ULONG MaxPoolBindings;
+ ULONG AllocatedBindings;
+ ULONG InitBindings;
+#endif
+
+ //
+ // This contains the next unique indentified to use as
+ // the FsContext in the file object associated with an
+ // open of the control channel.
+ //
+
+ LARGE_INTEGER ControlChannelIdentifier;
+
+ //
+ // This registry parameter controls whether IPX checks (and discards)
+ // packets with mismatched Source addresses in the receive path.
+ //
+ BOOLEAN VerifySourceAddress;
+
+ //
+ // Where the current socket allocation is.
+ //
+ USHORT CurrentSocket;
+
+ //
+ // Number of segments in the RIP database.
+ //
+
+ ULONG SegmentCount;
+
+ //
+ // Points to an array of locks for the RIP database (these
+ // are stored outside of the ROUTER_SEGMENT so the array
+ // can be exposed to the RIP upper driver as one piece).
+ //
+
+ CTELock *SegmentLocks;
+
+ //
+ // Points to an array of ROUTER_SEGMENT fields for
+ // various RIP control fields.
+ //
+
+ ROUTER_SEGMENT *Segments;
+
+ //
+ // Queue of RIP packets waiting to be sent.
+ //
+
+ LIST_ENTRY WaitingRipPackets;
+ ULONG RipPacketCount;
+
+ //
+ // Timer that keeps RIP requests RIP_GRANULARITY ms apart.
+ //
+
+ BOOLEAN RipShortTimerActive;
+ USHORT RipSendTime;
+ CTETimer RipShortTimer;
+
+ //
+ // Timer that runs to age out unused rip entries (if the
+ // router is not bound) and re-rip every so often for
+ // active entries.
+ //
+
+ CTETimer RipLongTimer;
+
+ //
+ // This controls the source routing timeout code.
+ //
+
+ BOOLEAN SourceRoutingUsed; // TRUE if any 802.5 bindings exist.
+ CHAR SourceRoutingTime; // incremented each time timer fires.
+ CTETimer SourceRoutingTimer; // runs every minute.
+
+ //
+ // These are the merging of the binding values.
+ //
+
+ ULONG LinkSpeed;
+ ULONG MacOptions;
+
+ //
+ // Where we tell upper drivers to put their headers.
+ //
+
+ ULONG IncludedHeaderOffset;
+
+ //
+ // A pre-allocated header containing our node and network,
+ // plus an unused socket (so the structure is a known size
+ // for easy copying).
+ //
+
+ TDI_ADDRESS_IPX SourceAddress;
+
+ //
+ // The following field is an array of list heads of ADDRESS objects that
+ // are defined for this transport provider. To edit the list, you must
+ // hold the spinlock of the device context object.
+ //
+
+ LIST_ENTRY AddressDatabases[IPX_ADDRESS_HASH_COUNT]; // list of defined transport addresses.
+
+ //
+ // Holds the last address we looked up.
+ //
+
+ PVOID LastAddress;
+
+ NDIS_HANDLE NdisBufferPoolHandle;
+
+ //
+ // The following structure contains statistics counters for use
+ // by TdiQueryInformation and TdiSetInformation. They should not
+ // be used for maintenance of internal data structures.
+ //
+
+ TDI_PROVIDER_INFO Information; // information about this provider.
+
+ //
+ // Information.MaxDatagramSize is the minimum size we can
+ // send to all bindings assuming worst-case source routing;
+ // this is the value that won't break any network drivers.
+ //
+
+ ULONG RealMaxDatagramSize;
+
+#if DBG
+ UCHAR Signature2[4]; // contains "IDC2"
+#endif
+
+ //
+ // Indicates whether each upper driver is bound
+ // (Netbios = 0, SPX = 1, RIP = 2).
+ //
+
+ BOOLEAN UpperDriverBound[UPPER_DRIVER_COUNT];
+
+ //
+ // TRUE if any driver is bound.
+ //
+
+ BOOLEAN AnyUpperDriverBound;
+
+ //
+ // Whether a receive complete should be indicated to
+ // this upper driver.
+ //
+
+ BOOLEAN ReceiveCompletePending[UPPER_DRIVER_COUNT];
+
+ //
+ // Control channel identifier for each of the upper
+ // drivers' bindings.
+ //
+
+ LARGE_INTEGER UpperDriverControlChannel[UPPER_DRIVER_COUNT];
+
+ //
+ // Entry points and other information for each of the
+ // upper drivers.
+ //
+
+ IPX_INTERNAL_BIND_INPUT UpperDrivers[UPPER_DRIVER_COUNT];
+
+ //
+ // How many upper drivers want broadcast enabled.
+ //
+
+ ULONG EnableBroadcastCount;
+
+ //
+ // Indicates if an enable broadcast operation is in
+ // progress.
+ //
+
+ BOOLEAN EnableBroadcastPending;
+
+ //
+ // Indicates if a disable broadcast operation is in
+ // progress.
+ //
+
+ BOOLEAN DisableBroadcastPending;
+
+ //
+ // Indicates if the current operation should be
+ // reversed when it is finished.
+ //
+
+ BOOLEAN ReverseBroadcastOperation;
+
+ //
+ // TRUE if RIP wants a single network number for all WANs
+ //
+
+ BOOLEAN WanGlobalNetworkNumber;
+
+ //
+ // If WanGlobalNetworkNumber is TRUE, then this holds the
+ // actual value of the network number, once we know it.
+ //
+
+ ULONG GlobalWanNetwork;
+
+ //
+ // Set to TRUE if WanGlobalNetworkNumber is TRUE and we
+ // have already completed a queued notify from SAP. In
+ // this case GlobalWanNetwork will be set correctly.
+ //
+
+ BOOLEAN GlobalNetworkIndicated;
+
+ //
+ // TRUE if we need to act as a RIP announcer/responder
+ // for our virtual net.
+ //
+
+ BOOLEAN RipResponder;
+
+ //
+ // TRUE if we have already logged an error because someone
+ // sent a SAP response but we have multiple cards with no
+ // virtual network.
+ //
+
+ BOOLEAN SapWarningLogged;
+
+ //
+ // Used to queue up a worker thread to perform
+ // broadcast operations.
+ //
+
+ WORK_QUEUE_ITEM BroadcastOperationQueueItem;
+
+#ifdef _PNP_POWER
+ //
+ // Used to queue up a worker thread to perform
+ // PnP indications to upper drivers.
+ //
+
+ WORK_QUEUE_ITEM PnPIndicationsQueueItem;
+#endif
+
+ //
+ // This event is used when unloading to signal that
+ // the reference count is now 0.
+ //
+
+ KEVENT UnloadEvent;
+ BOOLEAN UnloadWaiting;
+
+ //
+ // Counters for most of the statistics that IPX maintains;
+ // some of these are kept elsewhere. Including the structure
+ // itself wastes a little space but ensures that the alignment
+ // inside the structure is correct.
+ //
+
+ TDI_PROVIDER_STATISTICS Statistics;
+
+
+ //
+ // This is TRUE if we have any adapters where we are
+ // auto-detecting the frame type.
+ //
+
+ BOOLEAN AutoDetect;
+
+ //
+ // This is TRUE if we are auto-detecting and we have
+ // found the default auto-detect type on the net.
+ //
+
+ BOOLEAN DefaultAutoDetected;
+
+ //
+ // Our state during auto-detect. After we are done this
+ // will stay at AutoDetectDone;
+ //
+
+ UCHAR AutoDetectState;
+
+ //
+ // If we are auto-detecting, this event is used to stall
+ // our initialization code while we do auto-detection --
+ // this is so we have a constant view of the world once
+ // we return from DriverEntry.
+ //
+
+ KEVENT AutoDetectEvent;
+
+ //
+ // Counters for "active" time.
+ //
+
+ LARGE_INTEGER IpxStartTime;
+
+ //
+ // This resource guards access to the ShareAccess
+ // and SecurityDescriptor fields in addresses.
+ //
+
+ ERESOURCE AddressResource;
+
+ //
+ // Points back to the system device object.
+ //
+
+ PDEVICE_OBJECT DeviceObject;
+
+#ifdef _PNP_POWER
+ //
+ // Used to store the Tdi registration handle for deviceobject notifications.
+ //
+ HANDLE TdiRegistrationHandle;
+
+ //
+ // Used to store the TA_ADDRESS which is indicated up to Tdi clients as adapters appear.
+ //
+ PTA_ADDRESS TdiRegistrationAddress;
+#endif
+
+ //
+ // These are kept around for error logging, and stored right
+ // after this structure.
+ //
+
+ PWCHAR DeviceName;
+ ULONG DeviceNameLength;
+
+} DEVICE, * PDEVICE;
+
+
+extern PDEVICE IpxDevice;
+extern PIPX_PADDING_BUFFER IpxPaddingBuffer;
+#if DBG
+EXTERNAL_LOCK(IpxGlobalInterlock);
+#endif
+
+
+//
+// device state definitions
+//
+
+#define DEVICE_STATE_CLOSED 0x00
+#define DEVICE_STATE_OPEN 0x01
+#define DEVICE_STATE_STOPPING 0x02
+
+#ifdef _PNP_POWER
+
+//
+// New state which comes between CLOSED and OPEN. At this state,
+// there are no adapters in the system and so no network activity
+// is possible.
+//
+#define DEVICE_STATE_LOADED 0x03
+#endif _PNP_POWER
+
+//
+// This is the state of our auto-detect if we do it.
+//
+
+#define AUTO_DETECT_STATE_INIT 0x00 // still initializing the device
+#define AUTO_DETECT_STATE_RUNNING 0x01 // sent ffffffff query, waiting for responses
+#define AUTO_DETECT_STATE_PROCESSING 0x02 // processing the responses
+#define AUTO_DETECT_STATE_DONE 0x03 // detection is done, IPX is active
+
+
+
+#define IPX_TDI_RESOURCES 9
+
+
+//
+// This structure is pointed to by the FsContext field in the FILE_OBJECT
+// for this Address. This structure is the base for all activities on
+// the open file object within the transport provider. All active connections
+// on the address point to this structure, although no queues exist here to do
+// work from. This structure also maintains a reference to an ADDRESS
+// structure, which describes the address that it is bound to.
+//
+
+#define AFREF_CREATE 0
+#define AFREF_RCV_DGRAM 1
+#define AFREF_SEND_DGRAM 2
+#define AFREF_VERIFY 3
+#define AFREF_INDICATION 4
+
+#define AFREF_TOTAL 8
+
+typedef struct _ADDRESS_FILE {
+
+#if DBG
+ ULONG RefTypes[AFREF_TOTAL];
+#endif
+
+ CSHORT Type;
+ CSHORT Size;
+
+ LIST_ENTRY Linkage; // next address file on this address.
+ // also used for linkage in the
+ // look-aside list
+
+ ULONG ReferenceCount; // number of references to this object.
+
+ //
+ // the current state of the address file structure; this is either open or
+ // closing
+ //
+
+ UCHAR State;
+
+ CTELock * AddressLock;
+
+ //
+ // The following fields are kept for housekeeping purposes.
+ //
+
+ PREQUEST Request; // the request used for open or close
+ struct _ADDRESS *Address; // address to which we are bound.
+#ifdef ISN_NT
+ PFILE_OBJECT FileObject; // easy backlink to file object.
+#endif
+ struct _DEVICE *Device; // device to which we are attached.
+
+ //
+ //
+ // TRUE if ExtendedAddressing, ReceiveIpxHeader,
+ // FilterOnPacketType, or ReceiveFlagAddressing is TRUE.
+ //
+
+ BOOLEAN SpecialReceiveProcessing;
+
+ //
+ // The remote address of a send datagram includes the
+ // packet type. and on a receive datagram includes
+ // the packet type AND a flags byte indicating information
+ // about the frame (was it broadcast, was it sent from
+ // this machine).
+ //
+
+ BOOLEAN ExtendedAddressing;
+
+ //
+ // TRUE if the address on a receive datagram includes
+ // the packet type and a flags byte (like ExtendedAddressing),
+ // but on send the address is normal (no packet type).
+ //
+
+ BOOLEAN ReceiveFlagsAddressing;
+
+ //
+ // Is the IPX header received with the data.
+ //
+
+ BOOLEAN ReceiveIpxHeader;
+
+ //
+ // The packet type to use if it is unspecified in the send.
+ //
+
+ UCHAR DefaultPacketType;
+
+ //
+ // TRUE if packet type filtering is enabled.
+ //
+
+ BOOLEAN FilterOnPacketType;
+
+ //
+ // The packet type to filter on.
+ //
+
+ UCHAR FilteredType;
+
+ //
+ // Does this address file want broadcast packets.
+ //
+
+ BOOLEAN EnableBroadcast;
+
+ //
+ // This is set to TRUE if this is the SAP socket -- we
+ // put this under SpecialReceiveProcessing to avoid
+ // hitting the main path.
+ //
+
+ BOOLEAN IsSapSocket;
+
+ //
+ // The following queue is used to queue receive datagram requests
+ // on this address file. Send datagram requests are queued on the
+ // address itself. These queues are managed by the EXECUTIVE interlocked
+ // list management routines. The actual objects which get queued to this
+ // structure are request control blocks (RCBs).
+ //
+
+ LIST_ENTRY ReceiveDatagramQueue; // FIFO of outstanding TdiReceiveDatagrams.
+
+ //
+ // This holds the request used to close this address file,
+ // for pended completion.
+ //
+
+ PREQUEST CloseRequest;
+
+ //
+ // handler for kernel event actions. First we have a set of booleans that
+ // indicate whether or not this address has an event handler of the given
+ // type registered.
+ //
+
+ //
+ // [CH] Added the chained receive handlers.
+ //
+
+ BOOLEAN RegisteredReceiveDatagramHandler;
+ BOOLEAN RegisteredChainedReceiveDatagramHandler;
+ BOOLEAN RegisteredErrorHandler;
+
+ //
+ // The following function pointer always points to a TDI_IND_RECEIVE_DATAGRAM
+ // event handler for the address. If the NULL handler is specified in a
+ // TdiSetEventHandler, this this points to an internal routine which does
+ // not accept the incoming data.
+ //
+
+ PTDI_IND_RECEIVE_DATAGRAM ReceiveDatagramHandler;
+ PVOID ReceiveDatagramHandlerContext;
+ PTDI_IND_CHAINED_RECEIVE_DATAGRAM ChainedReceiveDatagramHandler;
+ PVOID ChainedReceiveDatagramHandlerContext;
+
+ //
+ // The following function pointer always points to a TDI_IND_ERROR
+ // handler for the address. If the NULL handler is specified in a
+ // TdiSetEventHandler, this this points to an internal routine which
+ // simply returns successfully.
+ //
+
+ PTDI_IND_ERROR ErrorHandler;
+ PVOID ErrorHandlerContext;
+
+} ADDRESS_FILE, *PADDRESS_FILE;
+
+#define ADDRESSFILE_STATE_OPENING 0x00 // not yet open for business
+#define ADDRESSFILE_STATE_OPEN 0x01 // open for business
+#define ADDRESSFILE_STATE_CLOSING 0x02 // closing
+
+
+//
+// This structure defines an ADDRESS, or active transport address,
+// maintained by the transport provider. It contains all the visible
+// components of the address (such as the TSAP and network name components),
+// and it also contains other maintenance parts, such as a reference count,
+// ACL, and so on. All outstanding connection-oriented and connectionless
+// data transfer requests are queued here.
+//
+
+#define AREF_ADDRESS_FILE 0
+#define AREF_LOOKUP 1
+#define AREF_RECEIVE 2
+
+#define AREF_TOTAL 4
+
+typedef struct _ADDRESS {
+
+#if DBG
+ ULONG RefTypes[AREF_TOTAL];
+#endif
+
+ USHORT Size;
+ CSHORT Type;
+
+/* ULONGs to allow for Interlocked operations.
+
+ BOOLEAN SendPacketInUse; // put these after so header is aligned.
+
+ BOOLEAN ReceivePacketInUse;
+#if BACK_FILL
+ BOOLEAN BackFillPacketInUse;
+#endif
+*/
+
+ ULONG SendPacketInUse; // put these after so header is aligned.
+
+ ULONG ReceivePacketInUse;
+#if BACK_FILL
+ ULONG BackFillPacketInUse;
+#endif
+
+ LIST_ENTRY Linkage; // next address/this device object.
+ ULONG ReferenceCount; // number of references to this object.
+
+ CTELock Lock;
+
+ //
+ // The following fields comprise the actual address itself.
+ //
+
+ PREQUEST Request; // pointer to address creation request.
+
+ USHORT Socket; // the socket this address corresponds to.
+ USHORT SendSourceSocket; // used for sends; may be == Socket or 0
+
+ //
+ // The following fields are used to maintain state about this address.
+ //
+
+ BOOLEAN Stopping;
+ ULONG Flags; // attributes of the address.
+ struct _DEVICE *Device; // device context to which we are attached.
+ CTELock * DeviceLock;
+
+ //
+ // The following queues is used to hold send datagrams for this
+ // address. Receive datagrams are queued to the address file. Requests are
+ // processed in a first-in, first-out manner, so that the very next request
+ // to be serviced is always at the head of its respective queue. These
+ // queues are managed by the EXECUTIVE interlocked list management routines.
+ // The actual objects which get queued to this structure are request control
+ // blocks (RCBs).
+ //
+
+ LIST_ENTRY AddressFileDatabase; // list of defined address file objects
+
+ //
+ // Holds our source address, used for construcing datagrams
+ // quickly.
+ //
+
+ TDI_ADDRESS_IPX LocalAddress;
+
+ IPX_SEND_PACKET SendPacket;
+ IPX_RECEIVE_PACKET ReceivePacket;
+
+#if BACK_FILL
+ IPX_SEND_PACKET BackFillPacket;
+#endif
+
+
+ UCHAR SendPacketHeader[IPX_MAXIMUM_MAC + sizeof(IPX_HEADER)];
+
+#ifdef ISN_NT
+
+ //
+ // These two can be a union because they are not used
+ // concurrently.
+ //
+
+ union {
+
+ //
+ // This structure is used for checking share access.
+ //
+
+ SHARE_ACCESS ShareAccess;
+
+ //
+ // Used for delaying IpxDestroyAddress to a thread so
+ // we can access the security descriptor.
+ //
+
+ WORK_QUEUE_ITEM DestroyAddressQueueItem;
+
+ } u;
+
+ //
+ // This structure is used to hold ACLs on the address.
+
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+
+#endif
+
+} ADDRESS, *PADDRESS;
+
+#define ADDRESS_FLAGS_STOPPING 0x00000001
+
+//
+// In order to increase the range of ControlChannelIds, we have a large integer to represent
+// monotonically increasing ControlChannelIdentifiers. This large integer is packed into the
+// 6 Bytes as follows:
+//
+// REQUEST_OPEN_CONTEXT(_Request) - 4 bytes
+// Upper 2 bytes of REQUEST_OPEN_TYPE(_Request) - 2 bytes
+//
+// IPX_CC_MASK is used to mask out the upper 2 bytes of the OPEN_TYPE.
+// MAX_CCID is 2^48.
+//
+#define IPX_CC_MASK 0x0000ffff
+
+#define MAX_CCID 0xffffffffffff
+
+#define CCID_FROM_REQUEST(_ccid, _Request) \
+ (_ccid).LowPart = (ULONG)(REQUEST_OPEN_CONTEXT(_Request)); \
+ (_ccid).HighPart = ((ULONG)(REQUEST_OPEN_TYPE(_Request)) >> 16);
+
diff --git a/private/ntos/tdi/isnp/ipx/isnipx.h b/private/ntos/tdi/isnp/ipx/isnipx.h
new file mode 100644
index 000000000..df947d439
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/isnipx.h
@@ -0,0 +1,531 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ isnipx.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ IPX module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#ifndef _ISNIPX_
+#define _ISNIPX_
+
+#define MAC_HEADER_SIZE ((IPX_MAXIMUM_MAC + 3) & ~3)
+#define RIP_PACKET_SIZE ((sizeof(RIP_PACKET) + 3) & ~3)
+#define IPX_HEADER_SIZE ((sizeof(IPX_HEADER) + 3) & ~3)
+
+//
+// Frame type definitions
+//
+
+#define ISN_FRAME_TYPE_ETHERNET_II 0
+#define ISN_FRAME_TYPE_802_3 1
+#define ISN_FRAME_TYPE_802_2 2
+#define ISN_FRAME_TYPE_SNAP 3
+#define ISN_FRAME_TYPE_ARCNET 4 // we ignore this
+#define ISN_FRAME_TYPE_MAX 4 // of the four standard ones
+
+#define ISN_FRAME_TYPE_AUTO 0xff
+
+
+//
+// This defines the size of the maximum MAC header required
+// (token-ring: MAC 14 bytes, RI 18 bytes, LLC 3 bytes, SNAP 5 bytes).
+//
+
+#define IPX_MAXIMUM_MAC 40
+
+//
+// This is an internal identifier used for RIP query packets.
+//
+
+#define IDENTIFIER_RIP_INTERNAL 4
+
+//
+// This is an internal identifier used for RIP response packets.
+//
+
+#define IDENTIFIER_RIP_RESPONSE 5
+
+
+//
+// This is the total number of "real" identifiers.
+//
+
+#define IDENTIFIER_TOTAL 4
+
+
+//
+// Some definitions (in the correct on-the-wire order).
+//
+
+#define RIP_PACKET_TYPE 0x01
+#define RIP_SOCKET 0x5304
+#define RIP_REQUEST 0x0100
+#define RIP_RESPONSE 0x0200
+#define RIP_DOWN 0x8200 // use high bit to indicate it
+
+#define SAP_PACKET_TYPE 0x04
+#define SAP_SOCKET 0x5204
+
+#define SPX_PACKET_TYPE 0x05
+
+#define NB_SOCKET 0x5504
+
+
+#include <packon.h>
+
+//
+// Definition of the IPX header.
+//
+
+typedef struct _IPX_HEADER {
+ USHORT CheckSum;
+ UCHAR PacketLength[2];
+ UCHAR TransportControl;
+ UCHAR PacketType;
+ UCHAR DestinationNetwork[4];
+ UCHAR DestinationNode[6];
+ USHORT DestinationSocket;
+ UCHAR SourceNetwork[4];
+ UCHAR SourceNode[6];
+ USHORT SourceSocket;
+} IPX_HEADER, *PIPX_HEADER;
+
+
+//
+// Definition of a RIP network entry.
+//
+
+typedef struct _RIP_NETWORK_ENTRY {
+ ULONG NetworkNumber;
+ USHORT HopCount;
+ USHORT TickCount;
+} RIP_NETWORK_ENTRY, *PRIP_NETWORK_ENTRY;
+
+//
+// Definition of a single entry rip packet.
+//
+
+typedef struct _RIP_PACKET {
+ USHORT Operation;
+ RIP_NETWORK_ENTRY NetworkEntry;
+} RIP_PACKET, *PRIP_PACKET;
+
+#include <packoff.h>
+
+
+#define IPX_DEVICE_SIGNATURE 0x1401
+#define IPX_ADAPTER_SIGNATURE 0x1402
+#define IPX_BINDING_SIGNATURE 0x1403
+#define IPX_ADDRESS_SIGNATURE 0x1404
+#define IPX_ADDRESSFILE_SIGNATURE 0x1405
+
+#define IPX_FILE_TYPE_CONTROL (ULONG)0x4701 // file is type control
+
+
+//
+// Defined granularity of RIP timeouts in milliseconds
+//
+
+#define RIP_GRANULARITY 55
+
+
+//
+// The default number of segments in the RIP table.
+//
+
+#define RIP_SEGMENTS 7
+
+
+
+//
+// Convert a ushort netware order <-> machine order
+//
+
+#define REORDER_USHORT(_Ushort) ((((_Ushort) & 0xff00) >> 8) | (((_Ushort) & 0x00ff) << 8))
+
+//
+// Convert a ulong netware order <-> machine order
+//
+
+#define REORDER_ULONG(_Ulong) \
+ ((((_Ulong) & 0xff000000) >> 24) | \
+ (((_Ulong) & 0x00ff0000) >> 8) | \
+ (((_Ulong) & 0x0000ff00) << 8) | \
+ (((_Ulong) & 0x000000ff) << 24))
+
+
+
+#if DBG
+
+extern ULONG IpxDebug;
+extern ULONG IpxMemoryDebug;
+
+#define IPX_MEMORY_LOG_SIZE 128
+extern UCHAR IpxDebugMemory[IPX_MEMORY_LOG_SIZE][64];
+extern PUCHAR IpxDebugMemoryLoc;
+extern PUCHAR IpxDebugMemoryEnd;
+
+VOID
+IpxDebugMemoryLog(
+ IN PUCHAR FormatString,
+ ...
+);
+
+#define IPX_DEBUG(_Flag, _Print) { \
+ if (IpxDebug & (IPX_DEBUG_ ## _Flag)) { \
+ DbgPrint ("IPX: "); \
+ DbgPrint _Print; \
+ } \
+ if (IpxMemoryDebug & (IPX_DEBUG_ ## _Flag)) { \
+ IpxDebugMemoryLog _Print; \
+ } \
+}
+
+#else
+
+#define IPX_DEBUG(_Flag, _Print)
+
+#endif
+
+
+//
+// These definitions are for abstracting IRPs from the
+// transport for portability.
+//
+
+#if ISN_NT
+
+typedef IRP REQUEST, *PREQUEST;
+
+
+//
+// PREQUEST
+// IpxAllocateRequest(
+// IN PDEVICE Device,
+// IN PIRP Irp
+// );
+//
+// Allocates a request for the system-specific request structure.
+//
+
+#define IpxAllocateRequest(_Device,_Irp) \
+ (_Irp)
+
+
+//
+// BOOLEAN
+// IF_NOT_ALLOCATED(
+// IN PREQUEST Request
+// );
+//
+// Checks if a request was not successfully allocated.
+//
+
+#define IF_NOT_ALLOCATED(_Request) \
+ if (0)
+
+
+//
+// VOID
+// IpxFreeRequest(
+// IN PDEVICE Device,
+// IN PREQUEST Request
+// );
+//
+// Frees a previously allocated request.
+//
+
+#define IpxFreeRequest(_Device,_Request) \
+ ;
+
+
+//
+// VOID
+// MARK_REQUEST_PENDING(
+// IN PREQUEST Request
+// );
+//
+// Marks that a request will pend.
+//
+
+#define MARK_REQUEST_PENDING(_Request) \
+ IoMarkIrpPending(_Request)
+
+
+//
+// VOID
+// UNMARK_REQUEST_PENDING(
+// IN PREQUEST Request
+// );
+//
+// Marks that a request will not pend.
+//
+
+#define UNMARK_REQUEST_PENDING(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->Control) &= ~SL_PENDING_RETURNED)
+
+
+//
+// UCHAR
+// REQUEST_MAJOR_FUNCTION
+// IN PREQUEST Request
+// );
+//
+// Returns the major function code of a request.
+//
+
+#define REQUEST_MAJOR_FUNCTION(_Request) \
+ ((IoGetCurrentIrpStackLocation(_Request))->MajorFunction)
+
+
+//
+// UCHAR
+// REQUEST_MINOR_FUNCTION
+// IN PREQUEST Request
+// );
+//
+// Returns the minor function code of a request.
+//
+
+#define REQUEST_MINOR_FUNCTION(_Request) \
+ ((IoGetCurrentIrpStackLocation(_Request))->MinorFunction)
+
+
+//
+// PNDIS_BUFFER
+// REQUEST_NDIS_BUFFER
+// IN PREQUEST Request
+// );
+//
+// Returns the NDIS buffer chain associated with a request.
+//
+
+#define REQUEST_NDIS_BUFFER(_Request) \
+ ((PNDIS_BUFFER)((_Request)->MdlAddress))
+
+
+//
+// PVOID
+// REQUEST_OPEN_CONTEXT(
+// IN PREQUEST Request
+// );
+//
+// Gets the context associated with an opened address/connection/control channel.
+//
+
+#define REQUEST_OPEN_CONTEXT(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->FileObject)->FsContext)
+
+
+//
+// PVOID
+// REQUEST_OPEN_TYPE(
+// IN PREQUEST Request
+// );
+//
+// Gets the type associated with an opened address/connection/control channel.
+//
+
+#define REQUEST_OPEN_TYPE(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->FileObject)->FsContext2)
+
+
+//
+// PFILE_FULL_EA_INFORMATION
+// OPEN_REQUEST_EA_INFORMATION(
+// IN PREQUEST Request
+// );
+//
+// Returns the EA information associated with an open/close request.
+//
+
+#define OPEN_REQUEST_EA_INFORMATION(_Request) \
+ ((PFILE_FULL_EA_INFORMATION)((_Request)->AssociatedIrp.SystemBuffer))
+
+
+//
+// PTDI_REQUEST_KERNEL
+// REQUEST_PARAMETERS(
+// IN PREQUEST Request
+// );
+//
+// Obtains a pointer to the parameters of a request.
+//
+
+#define REQUEST_PARAMETERS(_Request) \
+ (&((IoGetCurrentIrpStackLocation(_Request))->Parameters))
+
+
+//
+// VOID
+// REQUEST_OPEN_CONTEXT_AND_PARAMS(
+// IN PREQUEST Request
+// OUT PVOID * OpenContext,
+// OUT PTDI_REQUEST_KERNEL * Parameters
+// );
+//
+// Simultaneously returns the open context and the parameters
+// for a request (this is an optimization since the send
+// datagram code needs them both).
+//
+
+#define REQUEST_OPEN_CONTEXT_AND_PARAMS(_Request,_OpenContext,_Parameters) { \
+ PIO_STACK_LOCATION _IrpSp = IoGetCurrentIrpStackLocation(_Request); \
+ *(_OpenContext) = _IrpSp->FileObject->FsContext; \
+ *(_Parameters) = (PTDI_REQUEST_KERNEL)(&_IrpSp->Parameters); \
+}
+
+
+//
+// PLIST_ENTRY
+// REQUEST_LINKAGE(
+// IN PREQUEST Request
+// );
+//
+// Returns a pointer to a linkage field in the request.
+//
+
+#define REQUEST_LINKAGE(_Request) \
+ (&((_Request)->Tail.Overlay.ListEntry))
+
+
+//
+// PREQUEST
+// LIST_ENTRY_TO_REQUEST(
+// IN PLIST_ENTRY ListEntry
+// );
+//
+// Returns a request given a linkage field in it.
+//
+
+#define LIST_ENTRY_TO_REQUEST(_ListEntry) \
+ ((PREQUEST)(CONTAINING_RECORD(_ListEntry, REQUEST, Tail.Overlay.ListEntry)))
+
+
+//
+// NTSTATUS
+// REQUEST_STATUS(
+// IN PREQUEST Request
+// );
+//
+// Used to access the status field of a request.
+//
+
+#define REQUEST_STATUS(_Request) \
+ (_Request)->IoStatus.Status
+
+
+//
+// ULONG
+// REQUEST_INFORMATION(
+// IN PREQUEST Request)
+// );
+//
+// Used to access the information field of a request.
+//
+
+#define REQUEST_INFORMATION(_Request) \
+ (_Request)->IoStatus.Information
+
+
+//
+// VOID
+// IpxCompleteRequest(
+// IN PREQUEST Request
+// );
+//
+// Completes a request whose status and information fields have
+// been filled in.
+//
+
+#define IpxCompleteRequest(_Request) \
+ IoCompleteRequest (_Request, IO_NETWORK_INCREMENT)
+
+#else
+
+//
+// These routines must be defined for portability to a VxD.
+//
+
+#endif
+
+
+#define IPX_INCREMENT(_Long, _Lock) InterlockedIncrement(_Long)
+#define IPX_DECREMENT(_Long, _Lock) InterlockedDecrement(_Long)
+
+#define IPX_ADD_ULONG(_Pulong, _Ulong, _Lock) InterlockedExchangeAdd(_Pulong, _Ulong)
+
+#define IPX_DEFINE_SYNC_CONTEXT(_SyncContext)
+#define IPX_BEGIN_SYNC(_SyncContext)
+#define IPX_END_SYNC(_SyncContext)
+
+#define IPX_DEFINE_LOCK_HANDLE(_LockHandle) CTELockHandle _LockHandle;
+#define IPX_DEFINE_LOCK_HANDLE_PARAM(_LockHandle) CTELockHandle _LockHandle;
+
+#define IPX_GET_LOCK(_Lock, _LockHandle) \
+ CTEGetLock(_Lock, _LockHandle)
+
+#define IPX_FREE_LOCK(_Lock, _LockHandle) \
+ CTEFreeLock(_Lock, _LockHandle)
+
+#define IPX_GET_LOCK1(_Lock, _LockHandle)
+
+#define IPX_FREE_LOCK1(_Lock, _LockHandle)
+
+#define IPX_REMOVE_HEAD_LIST(_Queue, _Lock) ExInterlockedRemoveHeadList(_Queue, _Lock)
+#define IPX_LIST_WAS_EMPTY(_Queue, _OldHead) ((_OldHead) == NULL)
+#define IPX_INSERT_HEAD_LIST(_Queue, _Entry, _Lock) ExInterlockedInsertHeadList(_Queue, _Entry, _Lock)
+#define IPX_INSERT_TAIL_LIST(_Queue, _Entry, _Lock) ExInterlockedInsertTailList(_Queue, _Entry, _Lock)
+
+#define IPX_POP_ENTRY_LIST(_Queue, _Lock) ExInterlockedPopEntrySList(_Queue, _Lock)
+#define IPX_PUSH_ENTRY_LIST(_Queue, _Entry, _Lock) ExInterlockedPushEntrySList(_Queue, _Entry, _Lock)
+
+//
+// This macro adds a ULONG to a LARGE_INTEGER.
+//
+
+#define ADD_TO_LARGE_INTEGER(_LargeInteger,_Ulong) \
+ ExInterlockedAddLargeStatistic((_LargeInteger),(ULONG)(_Ulong))
+
+#define IPX_DEBUG_DEVICE 0x00000001
+#define IPX_DEBUG_ADAPTER 0x00000002
+#define IPX_DEBUG_ADDRESS 0x00000004
+#define IPX_DEBUG_SEND 0x00000008
+#define IPX_DEBUG_NDIS 0x00000010
+#define IPX_DEBUG_RECEIVE 0x00000020
+#define IPX_DEBUG_CONFIG 0x00000040
+#define IPX_DEBUG_PACKET 0x00000080
+#define IPX_DEBUG_RIP 0x00000100
+#define IPX_DEBUG_BIND 0x00000200
+#define IPX_DEBUG_ACTION 0x00000400
+#define IPX_DEBUG_BAD_PACKET 0x00000800
+#define IPX_DEBUG_SOURCE_ROUTE 0x00001000
+#define IPX_DEBUG_WAN 0x00002000
+#define IPX_DEBUG_AUTO_DETECT 0x00004000
+
+#ifdef _PNP_POWER
+#define IPX_DEBUG_PNP 0x00008000
+#endif
+
+#define IPX_DEBUG_LOOPB 0x00010000
+
+#endif
diff --git a/private/ntos/tdi/isnp/ipx/loopback.c b/private/ntos/tdi/isnp/ipx/loopback.c
new file mode 100644
index 000000000..be44bae5b
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/loopback.c
@@ -0,0 +1,280 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ loopback.c
+
+Abstract:
+
+ This module contains the routines to implement loopback
+
+Author:
+
+ Sanjay Anand (SanjayAn) 2/6/96
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Global lock to control access to the Loopback queue
+//
+DEFINE_LOCK_STRUCTURE(LoopLock)
+
+//
+// Head and tail of the Loopback queue
+//
+PNDIS_PACKET LoopXmitHead = (PNDIS_PACKET)NULL;
+PNDIS_PACKET LoopXmitTail = (PNDIS_PACKET)NULL;
+
+CTEEvent LoopXmitEvent;
+BOOLEAN LoopXmitRtnRunning = 0;
+
+//
+// MaximumPacket sized buffer to hold the lookahead data.
+//
+// ZZBUGBUG: In PnP this value can change
+//
+// PUCHAR LookaheadBuffer=NULL;
+#define LOOP_LOOKAHEAD_SIZE 128 + sizeof(IPX_HEADER) + 8 + 34
+
+
+VOID
+IpxDoLoopback(
+ IN CTEEvent *Event,
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ Does the actual loopback.
+
+Arguments:
+
+ Event - Pointer to event structure.
+
+ Context - Pointer to ZZ
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_PACKET Packet; // Pointer to packet being transmitted
+ PNDIS_BUFFER Buffer; // Current NDIS buffer being processed.
+ ULONG TotalLength; // Total length of send.
+ ULONG LookaheadLength; // Bytes in lookahead.
+ ULONG Copied; // Bytes copied so far.
+ PUCHAR CopyPtr; // Pointer to buffer being copied into.
+ PUCHAR SrcPtr; // Pointer to buffer being copied from.
+ ULONG SrcLength; // Length of src buffer.
+ BOOLEAN Rcvd = FALSE;
+ PIPX_SEND_RESERVED Reserved;
+ ULONG MacSize;
+ PNDIS_PACKET *PacketPtr;
+ UCHAR LookaheadBuffer[LOOP_LOOKAHEAD_SIZE];
+
+ IPX_DEFINE_LOCK_HANDLE(Handle)
+
+ KIRQL OldIrql;
+
+ CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ //
+ // Raise IRQL so we can acquire locks at DPC level in the receive code.
+ // Also to be able to ReceiveIndicate at DPC
+ //
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ IPX_GET_LOCK(&LoopLock, &Handle);
+
+ if (LoopXmitRtnRunning) {
+ IPX_FREE_LOCK(&LoopLock, Handle);
+ KeLowerIrql(OldIrql);
+ return;
+ }
+
+ LoopXmitRtnRunning = 1;
+
+ for (;;) {
+
+ //
+ // Get the next packet from the list.
+ //
+ Packet = LoopXmitHead;
+
+ if (Packet != (PNDIS_PACKET)NULL) {
+ Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ LoopXmitHead = (PNDIS_PACKET)(Reserved->PaddingBuffer);
+ IPX_FREE_LOCK(&LoopLock, Handle);
+ } else { // Nothing left to do.
+ LoopXmitRtnRunning = 0;
+ IPX_FREE_LOCK(&LoopLock, Handle);
+ break;
+ }
+
+ //
+ // We use the PaddingBuffer section as the next ptr.
+ //
+ Reserved->PaddingBuffer = NULL;
+
+ IPX_DEBUG(LOOPB, ("Packet: %lx\n", Packet));
+
+ NdisQueryPacket(Packet, NULL, NULL, &Buffer, &TotalLength);
+
+ NdisQueryBuffer(Buffer, NULL, &MacSize);
+
+ IPX_DEBUG(LOOPB, ("Buffer: %lx Totalpktlen: %lx MacSize: %lx\n", Buffer, TotalLength, MacSize));
+
+ LookaheadLength = MIN(LOOP_LOOKAHEAD_SIZE, TotalLength);
+ Copied = 0;
+ CopyPtr = LookaheadBuffer;
+ while (Copied < LookaheadLength) {
+ ULONG ThisCopy; // Bytes to copy this time.
+
+#ifdef DBG
+ if (!Buffer) {
+ DbgBreakPoint();
+ IPX_GET_LOCK(&LoopLock, &Handle);
+ LoopXmitRtnRunning = 0;
+ IPX_FREE_LOCK(&LoopLock, Handle);
+ KeLowerIrql(OldIrql);
+ return;
+ }
+#endif
+
+ NdisQueryBuffer(Buffer, &SrcPtr, &SrcLength);
+ ThisCopy = MIN(SrcLength, LookaheadLength - Copied);
+ CTEMemCopy(CopyPtr, SrcPtr, ThisCopy);
+ Copied += ThisCopy;
+ CopyPtr += ThisCopy;
+ NdisGetNextBuffer(Buffer, &Buffer);
+ }
+
+ Rcvd = TRUE;
+
+#ifdef BACK_FILL
+ //
+ // For Backfill packets, the MAC header is not yet set up; for others, it is the size
+ // of the first MDL (17).
+ //
+ if ((Reserved->Identifier == IDENTIFIER_IPX) &&
+ (Reserved->BackFill)) {
+ MacSize = 0;
+ }
+#endif
+ IpxReceiveIndication( (NDIS_HANDLE)IPX_LOOPBACK_COOKIE, // BindingContext
+ Packet, // ReceiveContext
+ (MacSize) ? LookaheadBuffer : NULL, // HeaderBuffer
+ MacSize, // HeaderBufferSize
+ LookaheadBuffer+MacSize, // LookAheadBuffer
+ LookaheadLength-MacSize, // LookAheadBufferSize
+ TotalLength-MacSize); // PacketSize
+
+ IpxSendComplete(Context, Packet, NDIS_STATUS_SUCCESS);
+
+ //
+ // Give other threads a chance to run.
+ //
+ KeLowerIrql(OldIrql);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ IPX_GET_LOCK(&LoopLock, &Handle);
+ }
+
+ if (Rcvd) {
+ IpxReceiveComplete(Context);
+ }
+
+ KeLowerIrql(OldIrql);
+}
+
+
+VOID
+IpxInitLoopback()
+/*++
+
+Routine Description:
+
+ Initializes various loopback structures.
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+{
+ CTEInitLock(&LoopLock);
+ CTEInitEvent(&LoopXmitEvent, IpxDoLoopback);
+ return;
+}
+
+
+VOID
+IpxLoopbackEnque(
+ IN PNDIS_PACKET Packet,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ Enqueues a packet to the loopbackQ
+
+Arguments:
+
+ Packet - The packet to be enqueued.
+
+ Context - Pointer to the adapter corresp to the first binding.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ IPX_DEFINE_LOCK_HANDLE(LockHandle)
+
+ //
+ // We use the PaddingBuffer as the next ptr.
+ //
+ Reserved->PaddingBuffer = NULL;
+
+ IPX_GET_LOCK(&LoopLock, &LockHandle);
+
+ //
+ // LoopbackQ is empty
+ //
+ if (LoopXmitHead == (PNDIS_PACKET)NULL) {
+ LoopXmitHead = Packet;
+ } else {
+ Reserved = (PIPX_SEND_RESERVED)(LoopXmitTail->ProtocolReserved);
+ (PNDIS_PACKET)(Reserved->PaddingBuffer) = Packet;
+ }
+ LoopXmitTail = Packet;
+
+ IPX_DEBUG(LOOPB, ("Enqued packet: %lx, Reserved: %lx\n", Packet, Reserved));
+
+ //
+ // If this routine is not already running, schedule it as a work item.
+ //
+ if (!LoopXmitRtnRunning) {
+ CTEScheduleEvent(&LoopXmitEvent, Context);
+ }
+
+ IPX_FREE_LOCK(&LoopLock, LockHandle);
+}
diff --git a/private/ntos/tdi/isnp/ipx/mac.c b/private/ntos/tdi/isnp/ipx/mac.c
new file mode 100644
index 000000000..93f9e8a89
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/mac.c
@@ -0,0 +1,3793 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ mac.c
+
+Abstract:
+
+ This module contains code which implements Mac type dependent code for
+ the IPX transport.
+
+Environment:
+
+ Kernel mode (Actually, unimportant)
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#define TR_LENGTH_MASK 0x1F // low 5 bits in byte
+#define TR_DIRECTION_MASK 0x80 // returns direction bit
+#define TR_DEFAULT_LENGTH 0x70 // default for outgoing
+#define TR_MAX_SIZE_MASK 0x70
+
+#define TR_PREAMBLE_AC 0x10
+#define TR_PREAMBLE_FC 0x40
+
+#define FDDI_HEADER_BYTE 0x57
+
+
+static UCHAR AllRouteSourceRouting[2] = { 0x82, TR_DEFAULT_LENGTH };
+static UCHAR SingleRouteSourceRouting[2] = { 0xc2, TR_DEFAULT_LENGTH };
+
+#define ROUTE_EQUAL(_A,_B) { \
+ (*(UNALIGNED USHORT *)(_A) == *(UNALIGNED USHORT *)(_B)) \
+}
+
+//
+// For back-fillable packets, chains the back-fill space as a MAC header
+// to the packet and sets the header pointer.
+//
+
+//
+// BUGBUG: We dont need to test for IDENTIFIER_IPX since it will always be
+// true for the mediumframe specific send handlers.
+//
+#define BACK_FILL_HEADER(_header, _reserved, _headerlength, _packet) \
+ if ((_reserved)->Identifier == IDENTIFIER_IPX) { \
+ if((_reserved)->BackFill) { \
+ CTEAssert ((_reserved)->HeaderBuffer); \
+ CTEAssert ((_reserved)->HeaderBuffer->MdlFlags & MDL_NETWORK_HEADER); \
+ _header = (PCHAR)(_reserved)->HeaderBuffer->MappedSystemVa - _headerlength; \
+ (_reserved)->HeaderBuffer->MappedSystemVa = (PCHAR)(_reserved)->HeaderBuffer->MappedSystemVa - _headerlength; \
+ (_reserved)->HeaderBuffer->ByteOffset -= _headerlength; \
+ NdisChainBufferAtFront(_packet,(PNDIS_BUFFER)(_reserved)->HeaderBuffer); \
+ } \
+ }
+
+//
+// In case of back-fillable packets, the adjusted length should include
+// the prev. bytecount of the headerbuffer.
+//
+#define BACK_FILL_ADJUST_BUFFER_LENGTH(_reserved, _headerlength) \
+ if((_reserved)->BackFill){ \
+ NdisAdjustBufferLength ((_reserved)->HeaderBuffer, _headerlength+(_reserved)->HeaderBuffer->ByteCount); \
+ IPX_DEBUG(SEND,("mac user mdl %x\n", (_reserved)->HeaderBuffer)); \
+ } else { \
+ NdisAdjustBufferLength ((_reserved)->HeaderBuffer, _headerlength); \
+ }
+
+//
+// This is the interpretation of the length bits in
+// the 802.5 source-routing information.
+//
+
+ULONG SR802_5Lengths[8] = { 516, 1500, 2052, 4472,
+ 8144, 11407, 17800, 17800 };
+
+#ifndef _PNP_POWER
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,MacInitializeMacInfo)
+#endif
+
+#endif
+
+
+VOID
+MacInitializeBindingInfo(
+ IN struct _BINDING * Binding,
+ IN struct _ADAPTER * Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Fills in the binding info based on the adapter's MacInfo
+ and the frame type of the binding.
+
+Arguments:
+
+ Binding - The newly created binding.
+
+ Adapter - The adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG MaxUserData;
+
+ Binding->DefHeaderSize = Adapter->DefHeaderSizes[Binding->FrameType];
+ Binding->BcMcHeaderSize = Adapter->BcMcHeaderSizes[Binding->FrameType];
+
+ MacReturnMaxDataSize(
+ &Adapter->MacInfo,
+ NULL,
+ 0,
+ Binding->MaxSendPacketSize,
+ &MaxUserData);
+
+ Binding->MaxLookaheadData =
+ Adapter->MaxReceivePacketSize -
+ sizeof(IPX_HEADER) -
+ (Binding->DefHeaderSize - Adapter->MacInfo.MinHeaderLength);
+
+ Binding->AnnouncedMaxDatagramSize =
+ MaxUserData -
+ sizeof(IPX_HEADER) -
+ (Binding->DefHeaderSize - Adapter->MacInfo.MinHeaderLength);
+
+ Binding->RealMaxDatagramSize =
+ Binding->MaxSendPacketSize -
+ Adapter->MacInfo.MaxHeaderLength -
+ sizeof(IPX_HEADER) -
+ (Binding->DefHeaderSize - Adapter->MacInfo.MinHeaderLength);
+
+} /* MacInitializeBindingInfo */
+
+
+VOID
+MacInitializeMacInfo(
+ IN NDIS_MEDIUM MacType,
+ OUT PNDIS_INFORMATION MacInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Fills in the MacInfo table based on MacType.
+
+Arguments:
+
+ MacType - The MAC type we wish to decode.
+
+ MacInfo - The MacInfo structure to fill in.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ switch (MacType) {
+ case NdisMedium802_3:
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->MediumAsync = FALSE;
+ MacInfo->BroadcastMask = 0x01;
+ MacInfo->MaxHeaderLength = 14;
+ MacInfo->MinHeaderLength = 14;
+ MacInfo->MediumType = NdisMedium802_3;
+ break;
+ case NdisMedium802_5:
+ MacInfo->SourceRouting = TRUE;
+ MacInfo->MediumAsync = FALSE;
+ MacInfo->BroadcastMask = 0x80;
+ MacInfo->MaxHeaderLength = 32;
+ MacInfo->MinHeaderLength = 14;
+ MacInfo->MediumType = NdisMedium802_5;
+ break;
+ case NdisMediumFddi:
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->MediumAsync = FALSE;
+ MacInfo->BroadcastMask = 0x01;
+ MacInfo->MaxHeaderLength = 13;
+ MacInfo->MinHeaderLength = 13;
+ MacInfo->MediumType = NdisMediumFddi;
+ break;
+ case NdisMediumArcnet878_2:
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->MediumAsync = FALSE;
+ MacInfo->BroadcastMask = 0x00;
+ MacInfo->MaxHeaderLength = 3;
+ MacInfo->MinHeaderLength = 3;
+ MacInfo->MediumType = NdisMediumArcnet878_2;
+ break;
+ case NdisMediumWan:
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->MediumAsync = TRUE;
+ MacInfo->BroadcastMask = 0x01;
+ MacInfo->MaxHeaderLength = 14;
+ MacInfo->MinHeaderLength = 14;
+ MacInfo->MediumType = NdisMedium802_3;
+ break;
+ default:
+ CTEAssert(FALSE);
+ }
+ MacInfo->RealMediumType = MacType;
+
+} /* MacInitializeMacInfo */
+
+
+VOID
+MacMapFrameType(
+ IN NDIS_MEDIUM MacType,
+ IN ULONG FrameType,
+ OUT ULONG * MappedFrameType
+ )
+
+/*++
+
+Routine Description:
+
+ Maps the specified frame type to a value which is
+ valid for the medium.
+
+Arguments:
+
+ MacType - The MAC type we wish to map for.
+
+ FrameType - The frame type in question.
+
+ MappedFrameType - Returns the mapped frame type.
+
+Return Value:
+
+--*/
+
+{
+ switch (MacType) {
+
+ //
+ // Ethernet accepts all values, the default is 802.2.
+ //
+
+ case NdisMedium802_3:
+ if (FrameType >= ISN_FRAME_TYPE_MAX) {
+ *MappedFrameType = ISN_FRAME_TYPE_802_2;
+ } else {
+ *MappedFrameType = FrameType;
+ }
+ break;
+
+ //
+ // Token-ring supports SNAP and 802.2 only.
+ //
+
+ case NdisMedium802_5:
+ if (FrameType == ISN_FRAME_TYPE_SNAP) {
+ *MappedFrameType = ISN_FRAME_TYPE_SNAP;
+ } else {
+ *MappedFrameType = ISN_FRAME_TYPE_802_2;
+ }
+ break;
+
+ //
+ // FDDI supports SNAP, 802.2, and 802.3 only.
+ //
+
+ case NdisMediumFddi:
+ if ((FrameType == ISN_FRAME_TYPE_SNAP) || (FrameType == ISN_FRAME_TYPE_802_3)) {
+ *MappedFrameType = FrameType;
+ } else {
+ *MappedFrameType = ISN_FRAME_TYPE_802_2;
+ }
+ break;
+
+ //
+ // On arcnet there is only one frame type, use 802.3
+ // (it doesn't matter what we use).
+ //
+
+ case NdisMediumArcnet878_2:
+ *MappedFrameType = ISN_FRAME_TYPE_802_3;
+ break;
+
+ //
+ // WAN uses ethernet II because it includes the ethertype.
+ //
+
+ case NdisMediumWan:
+ *MappedFrameType = ISN_FRAME_TYPE_ETHERNET_II;
+ break;
+
+ default:
+ CTEAssert(FALSE);
+ }
+
+} /* MacMapFrameType */
+
+//
+// BUGBUG -- use symbols instead of hardcoded values for mac header lengths
+// --pradeepb
+//
+
+VOID
+MacReturnMaxDataSize(
+ IN PNDIS_INFORMATION MacInfo,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN UINT DeviceMaxFrameSize,
+ OUT PUINT MaxFrameSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the space available for user data in a MAC packet.
+ This will be the available space after the MAC header; all headers
+ headers will be included in this space.
+
+Arguments:
+
+ MacInfo - Describes the MAC we wish to decode.
+
+ SourceRouting - If we are concerned about a reply to a specific
+ frame, then this information is used.
+
+ SourceRouting - The length of SourceRouting.
+
+ MaxFrameSize - The maximum frame size as returned by the adapter.
+
+ MaxDataSize - The maximum data size computed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ switch (MacInfo->MediumType) {
+
+ case NdisMedium802_3:
+
+ //
+ // For 802.3, we always have a 14-byte MAC header.
+ //
+
+ *MaxFrameSize = DeviceMaxFrameSize - 14;
+ break;
+
+ case NdisMedium802_5:
+
+ //
+ // For 802.5, if we have source routing information then
+ // use that, otherwise assume the worst.
+ //
+
+ if (SourceRouting && SourceRoutingLength >= 2) {
+
+ UINT SRLength;
+
+ SRLength = SR802_5Lengths[(SourceRouting[1] & TR_MAX_SIZE_MASK) >> 4];
+ DeviceMaxFrameSize -= (SourceRoutingLength + 14);
+
+ if (DeviceMaxFrameSize < SRLength) {
+ *MaxFrameSize = DeviceMaxFrameSize;
+ } else {
+ *MaxFrameSize = SRLength;
+ }
+
+ } else {
+
+#if 0
+ if (DeviceMaxFrameSize < 608) {
+ *MaxFrameSize = DeviceMaxFrameSize - 32;
+ } else {
+ *MaxFrameSize = 576;
+ }
+#endif
+ //
+ // bug # 6192. There is no point in assuming the worst. It only
+ // leads to lower throughput. Packets can get dropped by an
+ // an intermediate router for both cases (this one and the one
+ // above where 576 is chosen). In the above case, they will
+ // get dropped if two ethernet machines are communicating via
+ // a token ring. In this case, they will if two token ring
+ // machines with a frame size > max ethernet frame size are
+ // going over an ethernet. To fix the packet drop case, one
+ // should adjust the MaxPktSize Parameter of the card.
+ //
+ *MaxFrameSize = DeviceMaxFrameSize - 32;
+ }
+
+ break;
+
+ case NdisMediumFddi:
+
+ //
+ // For FDDI, we always have a 13-byte MAC header.
+ //
+
+ *MaxFrameSize = DeviceMaxFrameSize - 13;
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ //
+ // For Arcnet, we always have a 3-byte MAC header.
+ //
+
+ *MaxFrameSize = DeviceMaxFrameSize - 3;
+ break;
+
+ }
+
+} /* MacReturnMaxDataSize */
+
+#if 0
+
+VOID
+IpxUpdateWanInactivityCounter(
+ IN PBINDING Binding,
+ IN IPX_HEADER UNALIGNED * IpxHeader,
+ IN ULONG IncludedHeaderLength,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a frame is being sent on a WAN
+ line. It updates the inactivity counter for this binding
+ unless:
+
+ - The frame is from the RIP socket
+ - The frame is from the SAP socket
+ - The frame is a netbios keep alive
+ - The frame is an NCP keep alive
+
+ BUGBUG: Take the identifier as a parameter to optimize.
+
+Arguments:
+
+ Binding - The binding the frame is sent on.
+
+ IpxHeader - May contain the first bytes of the packet.
+
+ IncludedHeaderLength - The number of packet bytes at IpxHeader.
+
+ Packet - The full NDIS packet.
+
+ PacketLength - The length of the packet.
+
+Return Value:
+
+ None, but in some cases we return without resetting the
+ inactivity counter.
+
+Comments: THIS FUNCTION IS REAL HACKY AND NEEDS TO BE WORKED AT. WE CAN
+ Improve the instruction count here - pradeepb
+
+--*/
+
+{
+ PNDIS_BUFFER SecondBuffer = NULL;
+ PUCHAR SecondBufferData;
+ UINT SecondBufferLength;
+ USHORT SourceSocket;
+ PNDIS_BUFFER ThirdBuffer = NULL;
+ PUCHAR ThirdBufferData;
+ UINT ThirdBufferLength;
+
+ UNREFERENCED_PARAMETER (PacketLength);
+
+ //
+ // First get the source socket.
+ //
+
+#if 0
+ //
+ // Only time IncludedHeaderLength is less than the offset of
+ // SourceSocket in IPX header is when it 0 (from rip)
+ //
+ if (IncludedHeaderLength <= FIELD_OFFSET (IPX_HEADER, SourceSocket)) {
+#endif
+
+ //
+ // Get the second buffer in the packet (the ipx header is always in
+ // the second buffer - pradeepb.
+ //
+ // In this case
+ // there must be a second buffer or the packet is too
+ // short, so we don't check for NULL.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, &SecondBuffer, NULL);
+ SecondBuffer = NDIS_BUFFER_LINKAGE(SecondBuffer);
+ NdisQueryBuffer (SecondBuffer, (PVOID *)&SecondBufferData, &SecondBufferLength);
+
+ SourceSocket = *(UNALIGNED USHORT *)
+ (&SecondBufferData[FIELD_OFFSET(IPX_HEADER, SourceSocket) - IncludedHeaderLength]);
+
+#if 0
+ }
+else {
+
+ SourceSocket = IpxHeader->SourceSocket;
+ }
+#endif
+ if ((SourceSocket == RIP_SOCKET) ||
+ (SourceSocket == SAP_SOCKET)) {
+
+ return;
+
+ }
+
+ if (SourceSocket == NB_SOCKET) {
+
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ USHORT TotalDataLength;
+
+#if 0
+ //
+ // We assume the connection control flag and data stream type
+ // are in the same buffer.
+ //
+
+ if (IncludedHeaderLength < sizeof(IPX_HEADER) + 2) {
+
+ if (SecondBuffer == NULL) {
+
+ //
+ // Get the second buffer in the packet.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, &SecondBuffer, NULL);
+ SecondBuffer = NDIS_BUFFER_LINKAGE(SecondBuffer);
+ NdisQueryBuffer (ThirdBuffer, (PVOID *)&SecondBufferData, &SecondBufferLength);
+
+ }
+#endif
+
+ ConnectionControlFlag = *(SecondBufferData + (sizeof(IPX_HEADER) - IncludedHeaderLength));
+ DataStreamType = *(SecondBufferData + (sizeof(IPX_HEADER) + 1 - IncludedHeaderLength));
+
+
+#if 0
+ } else {
+
+ ConnectionControlFlag = ((PUCHAR)(IpxHeader+1))[0];
+ DataStreamType = ((PUCHAR)(IpxHeader+1))[1];
+ }
+
+#endif
+
+ //
+ // If this is a SYS packet with or without a request for ACK and
+ // has session data in it.
+ //
+ if (((ConnectionControlFlag == 0x80) || (ConnectionControlFlag == 0xc0)) &&
+ (DataStreamType == 0x06)) {
+
+ //
+ // This would be from the rip driver, if IncludedHeaderLength is
+ // 0. -- pradeepb
+ //
+ // At this point, we assume that total data length is in
+ // the same buffer as the others.
+ //
+ //
+ // real hacky way of doing things. One should be using
+ // FIELD_OFFSET(NB_SESSION, TotalDataLength) instead of 8.
+ // -- pradeepb
+ //
+
+ if (IncludedHeaderLength < sizeof(IPX_HEADER) + 2) {
+ TotalDataLength = *(USHORT UNALIGNED *)(SecondBufferData + (sizeof(IPX_HEADER) + 8 - IncludedHeaderLength));
+ } else {
+ TotalDataLength = ((USHORT UNALIGNED *)(IpxHeader+1))[4];
+ }
+
+ if (TotalDataLength == 0) {
+ return;
+ }
+ }
+
+ } else {
+
+ UCHAR KeepAliveSignature;
+
+
+ //
+ // Now see if it is an NCP keep alive.
+ //
+
+ if (PacketLength == sizeof(IPX_HEADER) + 2) {
+
+ //
+ // if from rip
+ //
+ if (IncludedHeaderLength <= sizeof(IPX_HEADER) + 1) {
+
+
+ //
+ // Get the second buffer
+ //
+#if 0
+ if (SecondBuffer == NULL) {
+
+ //
+ // Get the second buffer in the packet.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, &SecondBuffer, NULL);
+ ThirdBuffer = NDIS_BUFFER_LINKAGE(SecondBuffer);
+ NdisQueryBuffer (ThirdBuffer, (PVOID *)&ThirdBufferData, &ThirdBufferLength);
+
+ }
+#endif
+ KeepAliveSignature = SecondBufferData[sizeof(IPX_HEADER) + 1 - IncludedHeaderLength];
+
+ } else {
+
+ //
+ // will we ever come here - pradeepb?
+ //
+ KeepAliveSignature = SecondBufferData[sizeof(IPX_HEADER) + 1 - IncludedHeaderLength];
+#if 0
+ KeepAliveSignature = ((PUCHAR)(IpxHeader+1))[1];
+#endif
+
+ }
+
+ if ((KeepAliveSignature == '?') ||
+ (KeepAliveSignature == 'Y')) {
+ return;
+ }
+
+ }
+
+ }
+
+ //
+ // This was a normal packet, so reset this.
+ //
+
+ Binding->WanInactivityCounter = 0;
+
+} /* IpxUpdateWanInactivityCounter */
+#endif
+
+
+VOID
+IpxUpdateWanInactivityCounter(
+ IN PBINDING Binding,
+ IN IPX_HEADER UNALIGNED * IpxHeader,
+ IN ULONG IncludedHeaderLength,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a frame is being sent on a WAN
+ line. It updates the inactivity counter for this binding
+ unless:
+
+ - The frame is from the RIP socket
+ - The frame is from the SAP socket
+ - The frame is a netbios keep alive
+ - The frame is an NCP keep alive
+
+ BUGBUG: Take the identifier as a parameter to optimize.
+
+Arguments:
+
+ Binding - The binding the frame is sent on.
+
+ IpxHeader - May contain the first bytes of the packet.
+
+ IncludedHeaderLength - The number of packet bytes at IpxHeader.
+
+ Packet - The full NDIS packet.
+
+ PacketLength - The length of the packet.
+
+Return Value:
+
+ None, but in some cases we return without resetting the
+ inactivity counter.
+
+Comments: Improve the instruction count here - pradeepb
+
+--*/
+
+{
+ USHORT SourceSocket;
+ PNDIS_BUFFER DataBuffer = NULL;
+ PUCHAR DataBufferData;
+ UINT DataBufferLength;
+
+
+ //
+ // First get the source socket.
+ //
+ SourceSocket = IpxHeader->SourceSocket;
+ if ((SourceSocket == RIP_SOCKET) ||
+ (SourceSocket == SAP_SOCKET)) {
+
+ return;
+
+ }
+
+ if (SourceSocket == NB_SOCKET) {
+
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ USHORT TotalDataLength;
+
+ //
+ // ConnectionControlFlag and DataStreamType will always follow
+ // IpxHeader
+ //
+ ConnectionControlFlag = ((PUCHAR)(IpxHeader+1))[0];
+ DataStreamType = ((PUCHAR)(IpxHeader+1))[1];
+
+ //
+ // If this is a SYS packet with or without a request for ACK and
+ // has session data in it.
+ //
+ if (((ConnectionControlFlag == 0x80) || (ConnectionControlFlag == 0xc0)) &&
+ (DataStreamType == 0x06)) {
+
+ //
+ // TotalDataLength is in the same buffer.
+ //
+ TotalDataLength = ((USHORT UNALIGNED *)(IpxHeader+1))[4];
+
+ //
+ // No need to update the WAN activity counter
+ //
+ if (TotalDataLength == 0) {
+ return;
+ }
+ }
+
+ } else {
+
+ UCHAR KeepAliveSignature;
+
+
+ //
+ // Now see if it is an NCP keep alive. It can be from rip or from
+ // NCP on this machine
+ //
+ // NOTE: We cannot come here for an SMB packet - [IsaacHe - 12/15].
+ //
+ if (PacketLength == sizeof(IPX_HEADER) + 2) {
+
+ //
+ // Get the client data buffer
+ //
+ NdisQueryPacket(Packet, NULL, NULL, &DataBuffer, NULL);
+
+ //
+ // If the included header length is 0, it is from rip
+ //
+ if (IncludedHeaderLength == 0) {
+
+ //
+ // Get the second buffer in the packet. The second buffer
+ // contains the IPX header + other stuff
+ //
+ DataBuffer = NDIS_BUFFER_LINKAGE(DataBuffer);
+ } else {
+ //
+ // Get the third buffer in the packet.
+ //
+ DataBuffer = NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE(DataBuffer));
+ }
+
+ NdisQueryBuffer (DataBuffer, (PVOID *)&DataBufferData, &DataBufferLength);
+ CTEAssert(DataBufferData);
+
+ if (IncludedHeaderLength == 0) {
+ KeepAliveSignature = DataBufferData[sizeof(IPX_HEADER) + 1];
+ } else {
+ KeepAliveSignature = DataBufferData[1];
+ }
+
+ if ((KeepAliveSignature == '?') ||
+ (KeepAliveSignature == 'Y')) {
+ return;
+ }
+ }
+ }
+
+
+ //
+ // This was a normal packet, so reset this.
+ //
+
+ Binding->WanInactivityCounter = 0;
+
+} /* IpxUpdateWanInactivityCounter */
+
+#if DBG
+ULONG IpxPadCount = 0;
+#endif
+
+#ifdef _PNP_POWER
+
+NDIS_STATUS
+IpxSendFramePreFwd(
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NB/SPX to send a frame.
+
+Arguments:
+
+ LocalTarget - The local target of the send - NB will have the LocalTarget in the Send_Reserved part
+ of the packet; SPX will not now, but will later.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ Return of IpxSendFrame
+
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ PNDIS_BUFFER HeaderBuffer;
+ UINT TempHeaderBufferLength;
+ PDEVICE Device = IpxDevice;
+ PIPX_HEADER TempHeader;
+
+ NdisQueryPacket (Packet, NULL, NULL, &HeaderBuffer, NULL);
+ NdisQueryBuffer(HeaderBuffer, &Header, &TempHeaderBufferLength);
+
+ //
+ // Set this now, will change later
+ //
+ Reserved->CurrentNicId = 0;
+
+ //
+ // Copy the LocalTarget into the send reserved area of the packet.
+ //
+ Reserved->LocalTarget = *LocalTarget;
+
+ //
+ // If the NicId in the handle is 0, then this could be a send
+ // over all NICs in the case of NB/SPX.
+ //
+ if (NIC_FROM_LOCAL_TARGET(LocalTarget) == 0) {
+ CTEAssert(Reserved->Identifier == IDENTIFIER_NB ||
+ Reserved->Identifier == IDENTIFIER_SPX);
+
+ //
+ // Check the destination network in the IPX header. If this is 0,
+ // then we need to iterate the send over all NICs.
+ //
+ TempHeader = (PIPX_HEADER)(&Header[Device->IncludedHeaderOffset]);
+
+ if ((*(UNALIGNED ULONG *)(TempHeader->DestinationNetwork) == 0) &&
+ ((IPX_NODE_BROADCAST(TempHeader->DestinationNode)) ||
+ (Reserved->Identifier == IDENTIFIER_SPX))) {
+
+ //
+ // Start with the first NIC
+ // BUGBUG: Search for the first NIC
+ //
+
+ IPX_DEBUG(SEND, ("Iteration over NICs started, reserved: %lx\n", Reserved));
+ Reserved->CurrentNicId = 1;
+ Reserved->Net0SendSucceeded = FALSE;
+
+ FILL_LOCAL_TARGET(&Reserved->LocalTarget, 1);
+ Reserved->PacketLength = PacketLength;
+ } else {
+ //
+ // If this is on the loopback adapter (Nic 0), queue it on the LoopbackQueue;
+ // if the LoopbackRtn is not started, start it now.
+ //
+
+ //
+ // Enque this packet to the LoopbackQueue on the binding.
+ // If the LoopbackRtn is not already scheduled, schedule it.
+ //
+
+ IPX_DEBUG(LOOPB, ("Mac.c: Packet: %x\n", Packet));
+
+ //
+ // Recalculate packet counts here.
+ //
+
+ //
+ // Assume an 802_3802_2 header and use that length.
+ //
+
+ //
+ // Adjust the MAC header's length to the right value
+ //
+ NdisAdjustBufferLength (HeaderBuffer, 17);
+ NdisRecalculatePacketCounts (Packet);
+ IpxLoopbackEnque(Packet, NIC_ID_TO_BINDING(Device, 1)->Adapter);
+
+ //
+ // The upper driver waits for the SendComplete.
+ //
+ return STATUS_PENDING;
+ }
+
+ return IpxSendFrame (
+ &Reserved->LocalTarget,
+ Packet,
+ PacketLength,
+ IncludedHeaderLength);
+
+ } else {
+ return IpxSendFrame (
+ LocalTarget,
+ Packet,
+ PacketLength,
+ IncludedHeaderLength);
+ }
+}
+#endif
+
+
+NDIS_STATUS
+IpxSendFrame(
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ BUGBUG: Check that Binding is not NULL.
+
+Arguments:
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PDEVICE Device = IpxDevice;
+ PUCHAR Header;
+ PBINDING Binding, MasterBinding;
+ PADAPTER Adapter;
+ ULONG TwoBytes;
+ PNDIS_BUFFER HeaderBuffer;
+ UINT TempHeaderBufferLength;
+ ULONG HeaderLength=0;
+ UCHAR SourceRoutingBuffer[18];
+ PUCHAR SourceRouting;
+ ULONG SourceRoutingLength;
+ NDIS_STATUS Status;
+ ULONG BufferLength;
+ UCHAR DestinationType;
+ UCHAR SourceRoutingIdentifier;
+ ULONG HeaderSizeRequired;
+ PIPX_HEADER TempHeader;
+ USHORT PktLength;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ //
+ // Get the lock on the binding array
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_HANDLE_TO_BINDING(Device, &LocalTarget->NicHandle);
+
+ if (Binding == NULL) {
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ IPX_DEBUG(PNP, ("Invalid NIC handle: %lx\n", LocalTarget->NicHandle));
+ //
+ // [BUGBUGZZ] Return a unique error that NB/SPX see and re-query the NicId.
+ //
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ }
+
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+
+ Adapter = Binding->Adapter;
+
+ IpxReferenceAdapter(Adapter);
+
+ //
+ // Release the lock
+ //
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+
+ //
+ // If this is on the loopback adapter (Nic 0), queue it on the LoopbackQueue;
+ // if the LoopbackRtn is not started, start it now.
+ //
+ if (LocalTarget->NicId == 0) {
+
+ //
+ // Enque this packet to the LoopbackQueue on the binding.
+ // If the LoopbackRtn is not already scheduled, schedule it.
+ //
+
+ IPX_DEBUG(LOOPB, ("Mac.c: Packet: %x\n", Packet));
+
+ //
+ // Assume an 802_3802_2 header and use that length.
+ //
+
+ //
+ // Adjust the MAC header's length to the right value
+ //
+ // NdisAdjustBufferLength (HeaderBuffer, 17);
+
+ NdisRecalculatePacketCounts (Packet);
+
+ IpxLoopbackEnque(Packet, Device->Bindings[1]->Adapter);
+
+ //
+ // The upper driver waits for the SendComplete.
+ //
+ return STATUS_PENDING;
+ }
+
+ Binding = Device->Bindings[LocalTarget->NicId];
+
+ if (Binding == NULL) {
+ return STATUS_DEVICE_DOES_NOT_EXIST; // BUGBUG: Make this a separate switch that generally falls through?
+ }
+ Adapter = Binding->Adapter;
+#endif _PNP_POWER
+
+ //
+ // For IPX and other protocols that are guaranteed to have allocated
+ // the header from non-paged pool, use the buffer directly. For others,
+ // query the packet for the pointer to the MDL.
+ //
+ if (Reserved->Identifier >= IDENTIFIER_IPX) {
+ HeaderBuffer = Reserved->HeaderBuffer;
+ Header = Reserved->Header;
+
+ } else {
+ NdisQueryPacket (Packet, NULL, NULL, &HeaderBuffer, NULL);
+ NdisQueryBuffer(HeaderBuffer, &Header, &TempHeaderBufferLength);
+ }
+
+ CTEAssert (Reserved->PaddingBuffer == NULL);
+
+ //
+ // First move the packet around if needed.
+ //
+
+ if (Reserved->Identifier < IDENTIFIER_IPX) {
+
+ //
+ // Only RIP will have IncludedHeaderLength as 0. I don't know
+ // why we have the comment about RIP inside this if statement.
+ //
+ if (IncludedHeaderLength > 0) {
+
+ //
+ // Spx can handle a virtual net as long as it is
+ // not 0. Netbios always needs to use the real address.
+ // We need to hack the ipx source address for packets
+ // which are sent by spx if we have a fake virtual
+ // net, and packets sent by netbios unless we are
+ // bound to only one card.
+ //
+
+ //
+ // We handle binding sets as follows, based on who
+ // sent the frame to us:
+ //
+ // RIP: Since we only tell RIP about the masters at
+ // bind time, and hide slaves on indications, it should
+ // never be sending on a slave binding. Since RIP knows
+ // the real net and node of every binding we don't
+ // need to modify the packet at all.
+ //
+ // NB: For broadcasts we want to put the first card's
+ // address in the IPX source but round-robin the
+ // actual sends over all cards (broadcasts shouldn't
+ // be passed in with a slave's NIC ID). For directed
+ // packets, which may come in on a slave, we should
+ // put the slave's address in the IPX source.
+ //
+ // SPX: SPX does not send broadcasts. For directed
+ // frames we want to use the slave's net and node
+ // in the IPX source.
+ //
+
+ if (Reserved->Identifier == IDENTIFIER_NB) {
+
+ CTEAssert (IncludedHeaderLength >= sizeof(IPX_HEADER));
+
+ //
+ // Get the packet length from the ipx header. Compare with
+ // the max. allowed datagram size.
+ //
+ TempHeader = (PIPX_HEADER)(&Header[Device->IncludedHeaderOffset]);
+ PktLength = ((TempHeader->PacketLength[0] << 8) |
+ (TempHeader->PacketLength[1]));
+
+//
+// BUGBUG - Not the most efficient way to do this. NWLNKNB should do this.
+// Doing it in ipx means doing it for all packets (even those sent on
+// connections). Will remove this later when nwlnknb change has been
+// tested.
+//
+
+
+ if (PktLength > (Binding->AnnouncedMaxDatagramSize + sizeof(IPX_HEADER))) {
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ PktLength,
+ Binding->AnnouncedMaxDatagramSize + sizeof(IPX_HEADER)));
+
+#ifdef _PNP_POWER
+ //
+ // Dereference the binding and adapter
+ //
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxDereferenceAdapter(Adapter);
+#endif _PNP_POWER
+ return STATUS_INVALID_BUFFER_SIZE;
+ }
+
+ if (Device->ValidBindings > 1) {
+
+
+ //
+ // Store this now, since even if we round-robin the
+ // actual send we want the binding set master's net
+ // and node in the IPX source address.
+ //
+
+ *(UNALIGNED ULONG *)TempHeader->SourceNetwork = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory (TempHeader->SourceNode, Binding->LocalAddress.NodeAddress, 6);
+
+ if (Binding->BindingSetMember) {
+
+ if (IPX_NODE_BROADCAST(LocalTarget->MacAddress)) {
+
+ //
+ // This is a broadcast, so we round-robin the
+ // sends through the binding set.
+ //
+#ifdef _PNP_POWER
+ //
+ // [BUGBUGZZ]: We dont have a lock here - the masterbinding could be bogus
+ //
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxDereferenceAdapter(Adapter);
+#endif
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+ Adapter = Binding->Adapter;
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxReferenceAdapter(Adapter);
+#endif
+ }
+
+ }
+ }
+
+ } else if (Reserved->Identifier == IDENTIFIER_SPX) {
+
+ //
+ // Need to update this if we have multiple cards but
+ // a zero virtual net.
+ //
+
+ if (Device->MultiCardZeroVirtual) {
+
+ CTEAssert (IncludedHeaderLength >= sizeof(IPX_HEADER));
+
+ TempHeader = (PIPX_HEADER)(&Header[Device->IncludedHeaderOffset]);
+
+ *(UNALIGNED ULONG *)TempHeader->SourceNetwork = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory (TempHeader->SourceNode, Binding->LocalAddress.NodeAddress, 6);
+
+ }
+
+ } else {
+
+ //
+ // For a rip packet it should not be in a binding set,
+ // or if it is it should be the master.
+ //
+#if DBG
+ CTEAssert ((!Binding->BindingSetMember) ||
+ (Binding->CurrentSendBinding));
+#endif
+ }
+
+
+#if 0
+ //
+ // There is a header included, we need to adjust it.
+ // The header will be at Device->IncludedHeaderOffset.
+ //
+
+ if (LocalTarget->MacAddress[0] & Adapter->MacInfo.BroadcastMask) {
+ HeaderSizeRequired = Adapter->BcMcHeaderSizes[Binding->FrameType];
+ } else {
+ HeaderSizeRequired = Adapter->DefHeaderSizes[Binding->FrameType];
+ }
+
+ if (HeaderSizeRequired != Device->IncludedHeaderOffset) {
+
+ RtlMoveMemory(
+ &Header[HeaderSizeRequired],
+ &Header[Device->IncludedHeaderOffset],
+ IncludedHeaderLength);
+ }
+#endif
+ }
+ }
+
+
+
+ switch (Adapter->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+
+ if (!Binding->LineUp) {
+ //
+ // Bug #17273 return proper error message
+ //
+ // return STATUS_DEVICE_DOES_NOT_EXIST; // BUGBUG: Make this a separate switch that generally falls through?
+#ifdef _PNP_POWER
+ //
+ // Derefernce the binding and adapter
+ //
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxDereferenceAdapter(Adapter);
+#endif _PNP_POWER
+ return STATUS_NETWORK_UNREACHABLE;
+ }
+
+ if (Adapter->MacInfo.MediumAsync) {
+
+ IPX_HEADER UNALIGNED * IpxHeader;
+ PNDIS_BUFFER IpxNdisBuff;
+ UINT IpxHeaderLen;
+
+#if 0
+ //
+ // The header should have been moved here.
+ //
+
+ CTEAssert(Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] ==
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II]);
+
+
+ IpxHeader = (IPX_HEADER UNALIGNED *)
+ (&Header[Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II]]);
+#endif
+ //
+ // The Ipx header is always the second ndis buffer in the mdl
+ // chain. Get it and then query the va of the same.
+ //
+ IpxNdisBuff = NDIS_BUFFER_LINKAGE(HeaderBuffer);
+ NdisQueryBuffer (IpxNdisBuff, (PVOID *)&IpxHeader, &IpxHeaderLen);
+// IpxHeader = (IPX_HEADER UNALIGNED *) (&Header[MAC_HEADER_SIZE]);
+
+ //
+ // If this is a type 20 name frame from Netbios and we are
+ // on a dialin WAN line, drop it if configured to.
+ //
+ // The 0x01 bit of DisableDialinNetbios controls
+ // internal->WAN packets, which we handle here.
+ //
+ //
+
+ //
+ // SS# 33592: In case of iterative sends, the IncludedHeaderLength is not set properly
+ // since we dont keep track of the length that came in the first time (we track the PacketLength
+ // however). The included length field is used here for checking for NB_NAME_FRAMES, but elsewhere
+ // used only to distinguish between whether RIP or NB/SPX sent the packet (IncludedHeaderLen ==0 for RIP)
+ // The ideal solution here is to do way with this field altogether, but for the beta we will just use the
+ // PacketLength field for comparison here since we are assured that this will be equal to the InclHeaderLen
+ // for any type 0x14 packet that comes down from NB.
+ //
+ // BUGBUGZZ: Remove the IncludedHeaderLength field.
+ //
+ if ((!Binding->DialOutAsync) &&
+ (Reserved->Identifier == IDENTIFIER_NB) &&
+ // (IncludedHeaderLength == sizeof(IPX_HEADER) + 50) && // 50 == sizeof(NB_NAME_FRAME)
+ (PacketLength == sizeof(IPX_HEADER) + 50) && // 50 == sizeof(NB_NAME_FRAME)
+ ((Device->DisableDialinNetbios & 0x01) != 0) &&
+ (IpxHeader->PacketType == 0x14)) {
+#ifdef _PNP_POWER
+ //
+ // Derefernce the binding and adapter
+ //
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxDereferenceAdapter(Adapter);
+#endif _PNP_POWER
+ return STATUS_SUCCESS;
+ }
+
+
+ //
+ // We do checks to see if we should reset the inactivity
+ // counter. We normally need to check for netbios
+ // session alives, packets from rip, packets from
+ // sap, and ncp keep alives. In fact sap and ncp
+ // packets don't come through here.
+ //
+
+ IpxUpdateWanInactivityCounter(
+ Binding,
+ IpxHeader,
+ IncludedHeaderLength,
+ Packet,
+ PacketLength);
+
+ RtlCopyMemory (Header, Binding->RemoteMacAddress.Address, 6);
+
+ } else {
+
+ RtlCopyMemory (Header, LocalTarget->MacAddress, 6);
+ }
+
+ RtlCopyMemory (Header+6, Binding->LocalMacAddress.Address, 6);
+
+ switch (Binding->FrameType) {
+
+ case ISN_FRAME_TYPE_802_2:
+ TwoBytes = PacketLength + 3;
+ Header[14] = 0xe0;
+ Header[15] = 0xe0;
+ Header[16] = 0x03;
+ HeaderLength = 17;
+ break;
+ case ISN_FRAME_TYPE_802_3:
+ TwoBytes = PacketLength;
+ HeaderLength = 14;
+ break;
+ case ISN_FRAME_TYPE_ETHERNET_II:
+ TwoBytes = Adapter->BindSap;
+ HeaderLength = 14;
+ break;
+ case ISN_FRAME_TYPE_SNAP:
+ TwoBytes = PacketLength + 8;
+ Header[14] = 0xaa;
+ Header[15] = 0xaa;
+ Header[16] = 0x03;
+ Header[17] = 0x00;
+ Header[18] = 0x00;
+ Header[19] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[20]) = Adapter->BindSapNetworkOrder;
+ HeaderLength = 22;
+ break;
+ }
+
+ Header[12] = (UCHAR)(TwoBytes / 256);
+ Header[13] = (UCHAR)(TwoBytes % 256);
+
+ //BufferLength = IncludedHeaderLength + HeaderLength;
+ BufferLength = HeaderLength;
+
+ //
+ // Pad odd-length packets if needed.
+ //
+
+ if ((((PacketLength + HeaderLength) & 1) != 0) &&
+ (Device->EthernetPadToEven) &&
+ (!Adapter->MacInfo.MediumAsync)) {
+
+ PNDIS_BUFFER CurBuffer;
+ PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer;
+ UINT Offset;
+ UINT LastBufferLength;
+
+ //
+ // Find the tail of the current packet.
+ //
+
+ CurBuffer = HeaderBuffer;
+ while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) {
+ CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer);
+ }
+
+ //
+ // If the last byte of the last NDIS_BUFFER is not at the end of
+ // the page, then we can simply increase the NDIS_BUFFER ByteCount
+ // by one.
+ // Otherwise, we must use the global padding buffer.
+ //
+
+ NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength );
+
+ if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0) {
+ if ( CurBuffer == HeaderBuffer ) {
+ BufferLength++; // Just bump this length
+ } else {
+ NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) );
+
+ Reserved->PreviousTail = NULL;
+ Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer;
+ }
+
+ } else {
+
+ CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL);
+
+ Reserved->PreviousTail = CurBuffer;
+ NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer;
+ Reserved->PaddingBuffer = PaddingBuffer;
+
+ }
+
+ if (TwoBytes != Adapter->BindSap) {
+ CTEAssert(TwoBytes & 1);
+ TwoBytes += 1;
+ Header[12] = (UCHAR)(TwoBytes / 256);
+ Header[13] = (UCHAR)(TwoBytes % 256);
+ }
+
+#if DBG
+ ++IpxPadCount;
+#endif
+ }
+
+ break;
+
+ case NdisMedium802_5:
+
+ if (Reserved->Identifier >= IDENTIFIER_IPX) {
+
+ DestinationType = Reserved->DestinationType;
+ SourceRoutingIdentifier = IDENTIFIER_IPX;
+
+ } else {
+
+ if (LocalTarget->MacAddress[0] & 0x80) {
+ if (*(UNALIGNED ULONG *)(&LocalTarget->MacAddress[2]) != 0xffffffff) {
+ DestinationType = DESTINATION_MCAST;
+ } else {
+ DestinationType = DESTINATION_BCAST;
+ }
+ } else {
+ DestinationType = DESTINATION_DEF;
+ }
+ SourceRoutingIdentifier = Reserved->Identifier;
+
+ }
+
+ if (DestinationType == DESTINATION_DEF) {
+
+ MacLookupSourceRouting(
+ SourceRoutingIdentifier,
+ Binding,
+ LocalTarget->MacAddress,
+ SourceRoutingBuffer,
+ &SourceRoutingLength);
+
+ if (SourceRoutingLength != 0) {
+
+// PUCHAR IpxHeader = Header + Binding->DefHeaderSize;
+ PUCHAR IpxHeader = Header + MAC_HEADER_SIZE;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ SourceRouting = SourceRoutingBuffer;
+// RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+
+ } else {
+
+ //
+ // For these packets we assume that the header is in the
+ // right place.
+ //
+
+ if (!Adapter->SourceRouting) {
+
+ SourceRoutingLength = 0;
+
+ } else {
+
+ if (DestinationType == DESTINATION_BCAST) {
+
+ if (Binding->AllRouteBroadcast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ } else {
+
+ CTEAssert (DestinationType == DESTINATION_MCAST);
+
+ if (Binding->AllRouteMulticast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ }
+ }
+
+#if 0
+ if (SourceRoutingLength != 0) {
+
+ // PUCHAR IpxHeader = Header + Binding->BcMcHeaderSize;
+ PUCHAR IpxHeader = Header + MAC_HEADER_SIZE;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+#endif
+
+ }
+
+ Header[0] = TR_PREAMBLE_AC;
+ Header[1] = TR_PREAMBLE_FC;
+ RtlCopyMemory (Header+2, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+8, Binding->LocalMacAddress.Address, 6);
+
+ if (SourceRoutingLength != 0) {
+ Header[8] |= TR_SOURCE_ROUTE_FLAG;
+ RtlCopyMemory (Header+14, SourceRouting, SourceRoutingLength);
+ }
+
+ Header += (14 + SourceRoutingLength);
+
+ switch (Binding->FrameType) {
+ case ISN_FRAME_TYPE_802_2:
+ case ISN_FRAME_TYPE_802_3:
+ case ISN_FRAME_TYPE_ETHERNET_II:
+ Header[0] = 0xe0;
+ Header[1] = 0xe0;
+ Header[2] = 0x03;
+ HeaderLength = 17;
+ break;
+ case ISN_FRAME_TYPE_SNAP:
+ Header[0] = 0xaa;
+ Header[1] = 0xaa;
+ Header[2] = 0x03;
+ Header[3] = 0x00;
+ Header[4] = 0x00;
+ Header[5] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[6]) = Adapter->BindSapNetworkOrder;
+ HeaderLength = 22;
+ break;
+ }
+
+// BufferLength = IncludedHeaderLength + HeaderLength + SourceRoutingLength;
+ BufferLength = HeaderLength + SourceRoutingLength;
+
+ break;
+
+ case NdisMediumFddi:
+
+ Header[0] = FDDI_HEADER_BYTE;
+ RtlCopyMemory (Header+1, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+7, Binding->LocalMacAddress.Address, 6);
+
+ switch (Binding->FrameType) {
+ case ISN_FRAME_TYPE_802_3:
+ HeaderLength = 13;
+ break;
+ case ISN_FRAME_TYPE_802_2:
+ case ISN_FRAME_TYPE_ETHERNET_II:
+ Header[13] = 0xe0;
+ Header[14] = 0xe0;
+ Header[15] = 0x03;
+ HeaderLength = 16;
+ break;
+ case ISN_FRAME_TYPE_SNAP:
+ Header[13] = 0xaa;
+ Header[14] = 0xaa;
+ Header[15] = 0x03;
+ Header[16] = 0x00;
+ Header[17] = 0x00;
+ Header[18] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[19]) = Adapter->BindSapNetworkOrder;
+ HeaderLength = 21;
+ break;
+ }
+
+// BufferLength = IncludedHeaderLength + HeaderLength;
+ BufferLength = HeaderLength;
+
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ //
+ // Convert broadcast address to 0 (the arcnet broadcast).
+ //
+
+ Header[0] = Binding->LocalMacAddress.Address[5];
+ if (LocalTarget->MacAddress[5] == 0xff) {
+ Header[1] = 0x00;
+ } else {
+ Header[1] = LocalTarget->MacAddress[5];
+ }
+ Header[2] = ARCNET_PROTOCOL_ID;
+
+ //
+ // Binding->FrameType is not used.
+ //
+
+ HeaderLength = 3;
+// BufferLength = IncludedHeaderLength + HeaderLength;
+ BufferLength = HeaderLength;
+
+ break;
+
+ }
+
+ //
+ // Adjust the MAC header's length to the right value
+ //
+ NdisAdjustBufferLength (HeaderBuffer, BufferLength);
+ NdisRecalculatePacketCounts (Packet);
+
+#if 0
+ {
+ PMDL mdl;
+ mdl = (PMDL)NDIS_BUFFER_LINKAGE(HeaderBuffer);
+ if (mdl) {
+
+ KdPrint(("**Bytecount %x %x\n",mdl->ByteCount, mdl));
+ if ((LONG)mdl->ByteCount < 0) {
+ DbgBreakPoint();
+ }
+ }
+ }
+#endif
+
+#if DBG
+ {
+ ULONG SendFlag;
+ ULONG Temp;
+ PNDIS_BUFFER FirstPacketBuffer;
+ PNDIS_BUFFER SecondPacketBuffer;
+ IPX_HEADER DumpHeader;
+ UCHAR DumpData[14];
+
+ NdisQueryPacket (Packet, NULL, NULL, &FirstPacketBuffer, NULL);
+ SecondPacketBuffer = NDIS_BUFFER_LINKAGE(FirstPacketBuffer);
+ TdiCopyMdlToBuffer(SecondPacketBuffer, 0, &DumpHeader, 0, sizeof(IPX_HEADER), &Temp);
+ if (Reserved->Identifier == IDENTIFIER_NB) {
+ SendFlag = IPX_PACKET_LOG_SEND_NB;
+ } else if (Reserved->Identifier == IDENTIFIER_SPX) {
+ SendFlag = IPX_PACKET_LOG_SEND_SPX;
+ } else if (Reserved->Identifier == IDENTIFIER_RIP) {
+ SendFlag = IPX_PACKET_LOG_SEND_RIP;
+ } else {
+ if (DumpHeader.SourceSocket == IpxPacketLogSocket) {
+ SendFlag = IPX_PACKET_LOG_SEND_SOCKET | IPX_PACKET_LOG_SEND_OTHER;
+ } else {
+ SendFlag = IPX_PACKET_LOG_SEND_OTHER;
+ }
+ }
+
+#if 0
+ if (PACKET_LOG(SendFlag)) {
+
+ TdiCopyMdlToBuffer(SecondPacketBuffer, sizeof(IPX_HEADER), &DumpData, 0, 14, &Temp);
+
+ IpxLogPacket(
+ TRUE,
+ LocalTarget->MacAddress,
+ Binding->LocalMacAddress.Address,
+ (USHORT)PacketLength,
+ &DumpHeader,
+ DumpData);
+
+ }
+#endif
+ }
+#endif
+
+ ++Device->Statistics.PacketsSent;
+
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+#ifdef _PNP_POWER
+ if (Status != STATUS_PENDING) {
+
+ if (Reserved->PaddingBuffer) {
+
+ //
+ // Remove padding if it was done.
+ //
+
+ if ( Reserved->PreviousTail ) {
+ NDIS_BUFFER_LINKAGE (Reserved->PreviousTail) = (PNDIS_BUFFER)NULL;
+ } else {
+ PNDIS_BUFFER LastBuffer = (PNDIS_BUFFER)Reserved->PaddingBuffer;
+ UINT LastBufferLength;
+
+ NdisQueryBuffer( LastBuffer, NULL, &LastBufferLength );
+ NdisAdjustBufferLength( LastBuffer, (LastBufferLength - 1) );
+ }
+
+ Reserved->PaddingBuffer = NULL;
+
+ if (Reserved->Identifier < IDENTIFIER_IPX) {
+ NdisRecalculatePacketCounts (Packet);
+ }
+ }
+
+ //
+ // If this was an NB/SPX packet, and there was an
+ // iterative send going on, then call the SendComplete
+ // handler.
+ //
+ if ((Reserved->Identifier == IDENTIFIER_NB ||
+ Reserved->Identifier == IDENTIFIER_SPX) &&
+ (Reserved->CurrentNicId)) {
+
+ IpxSendComplete(
+ (NDIS_HANDLE)Binding->Adapter,
+ Packet,
+ Status);
+
+ Status = STATUS_PENDING;
+ }
+ }
+#else
+ if ((Status != STATUS_PENDING) &&
+ (Reserved->PaddingBuffer)) {
+
+ //
+ // Remove padding if it was done.
+ //
+
+ if ( Reserved->PreviousTail ) {
+ NDIS_BUFFER_LINKAGE (Reserved->PreviousTail) = (PNDIS_BUFFER)NULL;
+ } else {
+ PNDIS_BUFFER LastBuffer = (PNDIS_BUFFER)Reserved->PaddingBuffer;
+ UINT LastBufferLength;
+
+ NdisQueryBuffer( LastBuffer, NULL, &LastBufferLength );
+ NdisAdjustBufferLength( LastBuffer, (LastBufferLength - 1) );
+ }
+
+ Reserved->PaddingBuffer = NULL;
+
+ if (Reserved->Identifier < IDENTIFIER_IPX) {
+ NdisRecalculatePacketCounts (Packet);
+ }
+ }
+#endif
+
+#ifdef _PNP_POWER
+ //
+ // Derefernce the binding and adapter
+ //
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxDereferenceAdapter(Adapter);
+#endif _PNP_POWER
+
+ return Status;
+
+} /* IpxSendFrame */
+
+
+NDIS_STATUS
+IpxSendFrame802_3802_3(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_3 FRAMES IN
+ THE ISN_FRAME_TYPE_802_3 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+ //
+ // BUGBUG: Remove the IncludedHeaderLength parameter from here
+ //
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+ LONG HeaderLength;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 14, Packet);
+ IPX_DEBUG(SEND,("Backfill request 802_3802_3!! %x %x %x\n", Packet, Reserved, Reserved->HeaderBuffer));
+#endif
+
+ RtlCopyMemory (Header, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+6, Adapter->LocalMacAddress.Address, 6);
+
+ //
+ // Pad odd-length packets if needed.
+ //
+
+ if (((PacketLength & 1) != 0) &&
+ (IpxDevice->EthernetPadToEven)) {
+
+ PNDIS_BUFFER CurBuffer;
+ PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer;
+ UINT Offset;
+ UINT LastBufferLength;
+
+ //
+ // Find the tail of the current packet.
+ //
+
+ CurBuffer = Reserved->HeaderBuffer;
+ while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) {
+ CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer);
+ }
+
+ //
+ // If the last byte of the last NDIS_BUFFER is not at the end of
+ // the page, then we can simply increase the NDIS_BUFFER ByteCount
+ // by one.
+ // Otherwise, we must use the global padding buffer.
+ //
+
+ NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength );
+
+ if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0) {
+#if BACK_FILL
+ if (0) {
+
+#else
+ if ( CurBuffer == Reserved->HeaderBuffer ) {
+ IncludedHeaderLength++; // Just bump this length
+#endif
+ } else {
+ NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) );
+
+ Reserved->PreviousTail = NULL;
+ Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer;
+ }
+
+ } else {
+
+ CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL);
+
+ Reserved->PreviousTail = CurBuffer;
+ NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer;
+ Reserved->PaddingBuffer = PaddingBuffer;
+
+ }
+
+ ++PacketLength;
+#if DBG
+ ++IpxPadCount;
+#endif
+
+ }
+
+ Header[12] = (UCHAR)(PacketLength / 256);
+ Header[13] = (UCHAR)(PacketLength % 256);
+
+ //NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 14);
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 14);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 14);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_3802_3 */
+
+
+NDIS_STATUS
+IpxSendFrame802_3802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_3 FRAMES IN
+ THE ISN_FRAME_TYPE_802_2 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ ULONG TwoBytes;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 17, Packet);
+ IPX_DEBUG(SEND, ("Backfill request 802_3802_3!! %x %x %x\n", Packet, Reserved, Reserved->HeaderBuffer));
+ IPX_DEBUG(SEND, ("packet=%x, usermdl %x\n",Packet,Reserved->HeaderBuffer));
+#endif
+
+ RtlCopyMemory (Header, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+6, Adapter->LocalMacAddress.Address, 6);
+
+ TwoBytes = PacketLength + 3;
+ Header[14] = 0xe0;
+ Header[15] = 0xe0;
+ Header[16] = 0x03;
+
+ //
+ // Pad odd-length packets if needed.
+ //
+
+ if (((PacketLength & 1) == 0) &&
+ (IpxDevice->EthernetPadToEven)) {
+
+ PNDIS_BUFFER CurBuffer;
+ PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer;
+ UINT Offset;
+ UINT LastBufferLength;
+
+ //
+ // Find the tail of the current packet.
+ //
+
+ CurBuffer = Reserved->HeaderBuffer;
+ while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) {
+ CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer);
+ }
+
+ //
+ // If the last byte of the last NDIS_BUFFER is not at the end of
+ // the page, then we can simply increase the NDIS_BUFFER ByteCount
+ // by one.
+ // Otherwise, we must use the global padding buffer.
+ //
+
+ NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength );
+
+ if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0 ) {
+#if BACK_FILL
+ if (0) {
+#else
+ if ( CurBuffer == Reserved->HeaderBuffer ) {
+
+ IncludedHeaderLength++; // Just bump this length
+#endif
+ } else {
+ NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) );
+
+ Reserved->PreviousTail = NULL;
+ Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer;
+ }
+
+ } else {
+
+ CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL);
+
+ Reserved->PreviousTail = CurBuffer;
+ NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer;
+ Reserved->PaddingBuffer = PaddingBuffer;
+
+ }
+
+ ++TwoBytes;
+#if DBG
+ ++IpxPadCount;
+#endif
+
+ }
+
+ Header[12] = (UCHAR)(TwoBytes / 256);
+ Header[13] = (UCHAR)(TwoBytes % 256);
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 17);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 17);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 17);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_3802_2 */
+
+
+NDIS_STATUS
+IpxSendFrame802_3EthernetII(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_3 FRAMES IN
+ THE ISN_FRAME_TYPE_ETHERNET_II FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 14, Packet);
+#endif BACK_FILL
+
+ RtlCopyMemory (Header, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+6, Adapter->LocalMacAddress.Address, 6);
+
+ *(UNALIGNED USHORT *)(&Header[12]) = Adapter->BindSapNetworkOrder;
+
+ //
+ // Pad odd-length packets if needed.
+ //
+
+ if (((PacketLength & 1) != 0) &&
+ (IpxDevice->EthernetPadToEven)) {
+
+ PNDIS_BUFFER CurBuffer;
+ PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer;
+ UINT Offset;
+ UINT LastBufferLength;
+
+ //
+ // Find the tail of the current packet.
+ //
+
+ CurBuffer = Reserved->HeaderBuffer;
+ while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) {
+ CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer);
+ }
+
+ //
+ // If the last byte of the last NDIS_BUFFER is not at the end of
+ // the page, then we can simply increase the NDIS_BUFFER ByteCount
+ // by one.
+ // Otherwise, we must use the global padding buffer.
+ //
+
+ NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength );
+
+ if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0) {
+
+#if BACK_FILL
+ if (0) {
+
+#else
+ if ( CurBuffer == Reserved->HeaderBuffer ) {
+ IncludedHeaderLength++; // Just bump this length
+#endif
+ } else {
+ NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) );
+
+ Reserved->PreviousTail = NULL;
+ Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer;
+ }
+
+ } else {
+
+ CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL);
+
+ Reserved->PreviousTail = CurBuffer;
+ NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer;
+ Reserved->PaddingBuffer = PaddingBuffer;
+
+ }
+
+#if DBG
+ ++IpxPadCount;
+#endif
+
+ }
+
+ // NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 14);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 14);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 14);
+#endif
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_3EthernetII */
+
+
+NDIS_STATUS
+IpxSendFrame802_3Snap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_3 FRAMES IN
+ THE ISN_FRAME_TYPE_SNAP FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ ULONG TwoBytes;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 22, Packet);
+#endif BACK_FILL
+
+ RtlCopyMemory (Header, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+6, Adapter->LocalMacAddress.Address, 6);
+
+ TwoBytes = PacketLength + 8;
+ Header[14] = 0xaa;
+ Header[15] = 0xaa;
+ Header[16] = 0x03;
+ Header[17] = 0x00;
+ Header[18] = 0x00;
+ Header[19] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[20]) = Adapter->BindSapNetworkOrder;
+
+ //
+ // Pad odd-length packets if needed.
+ //
+
+ if (((PacketLength & 1) == 0) &&
+ (IpxDevice->EthernetPadToEven)) {
+
+ PNDIS_BUFFER CurBuffer;
+ PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer;
+ UINT Offset;
+ UINT LastBufferLength;
+
+ //
+ // Find the tail of the current packet.
+ //
+
+ CurBuffer = Reserved->HeaderBuffer;
+ while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) {
+ CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer);
+ }
+
+ //
+ // If the last byte of the last NDIS_BUFFER is not at the end of
+ // the page, then we can simply increase the NDIS_BUFFER ByteCount
+ // by one.
+ // Otherwise, we must use the global padding buffer.
+ //
+
+ NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength );
+
+ if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0) {
+
+#if BACK_FILL
+ if (0) {
+
+#else
+ if ( CurBuffer == Reserved->HeaderBuffer ) {
+ IncludedHeaderLength++; // Just bump this length
+#endif
+ } else {
+ NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) );
+
+ Reserved->PreviousTail = NULL;
+ Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer;
+ }
+
+ } else {
+
+ CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL);
+
+ Reserved->PreviousTail = CurBuffer;
+ NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer;
+ Reserved->PaddingBuffer = PaddingBuffer;
+
+ }
+
+ ++TwoBytes;
+#if DBG
+ ++IpxPadCount;
+#endif
+
+ }
+
+ Header[12] = (UCHAR)(TwoBytes / 256);
+ Header[13] = (UCHAR)(TwoBytes % 256);
+
+ // NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 22);
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 22);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 22);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_3Snap */
+
+
+NDIS_STATUS
+IpxSendFrame802_5802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_5 FRAMES IN
+ THE ISN_FRAME_TYPE_802_2 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PBINDING Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_2];
+ PUCHAR Header;
+ ULONG HeaderLength;
+ UCHAR SourceRoutingBuffer[18];
+ PUCHAR SourceRouting;
+ ULONG SourceRoutingLength;
+ NDIS_STATUS Status;
+ ULONG BufferLength;
+ UCHAR DestinationType;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 17, Packet);
+#endif BACK_FILL
+
+ DestinationType = Reserved->DestinationType;
+
+ if (DestinationType == DESTINATION_DEF) {
+
+ MacLookupSourceRouting(
+ Reserved->Identifier,
+ Binding,
+ LocalTarget->MacAddress,
+ SourceRoutingBuffer,
+ &SourceRoutingLength);
+
+ if (SourceRoutingLength != 0) {
+
+ //PUCHAR IpxHeader = Header + Binding->DefHeaderSize;
+ PUCHAR IpxHeader = Header + MAC_HEADER_SIZE;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ SourceRouting = SourceRoutingBuffer;
+// RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+
+ } else {
+
+ //
+ // For these packets we assume that the header is in the
+ // right place.
+ //
+
+ if (!Adapter->SourceRouting) {
+
+ SourceRoutingLength = 0;
+
+ } else {
+
+ if (DestinationType == DESTINATION_BCAST) {
+
+ if (Binding->AllRouteBroadcast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ } else {
+
+ CTEAssert (DestinationType == DESTINATION_MCAST);
+
+ if (Binding->AllRouteMulticast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ }
+ }
+
+#if 0
+ if (SourceRoutingLength != 0) {
+
+ PUCHAR IpxHeader = Header + Binding->BcMcHeaderSize;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+#endif
+ }
+
+ Header[0] = TR_PREAMBLE_AC;
+ Header[1] = TR_PREAMBLE_FC;
+ RtlCopyMemory (Header+2, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+8, Adapter->LocalMacAddress.Address, 6);
+
+ if (SourceRoutingLength != 0) {
+ Header[8] |= TR_SOURCE_ROUTE_FLAG;
+ RtlCopyMemory (Header+14, SourceRouting, SourceRoutingLength);
+ }
+
+ Header += (14 + SourceRoutingLength);
+
+ Header[0] = 0xe0;
+ Header[1] = 0xe0;
+ Header[2] = 0x03;
+ HeaderLength = 17;
+
+ //BufferLength = IncludedHeaderLength + HeaderLength + SourceRoutingLength;
+ BufferLength = HeaderLength + SourceRoutingLength;
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, BufferLength);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, BufferLength);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_5802_2 */
+
+
+NDIS_STATUS
+IpxSendFrame802_5Snap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_5 FRAMES IN
+ THE ISN_FRAME_TYPE_SNAP FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PBINDING Binding = Adapter->Bindings[ISN_FRAME_TYPE_SNAP];
+ PUCHAR Header;
+ ULONG HeaderLength;
+ UCHAR SourceRoutingBuffer[18];
+ PUCHAR SourceRouting;
+ ULONG SourceRoutingLength;
+ NDIS_STATUS Status;
+ ULONG BufferLength;
+ UCHAR DestinationType;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 22, Packet);
+#endif BACK_FILL
+
+ DestinationType = Reserved->DestinationType;
+
+ if (DestinationType == DESTINATION_DEF) {
+
+ MacLookupSourceRouting(
+ Reserved->Identifier,
+ Binding,
+ LocalTarget->MacAddress,
+ SourceRoutingBuffer,
+ &SourceRoutingLength);
+
+ if (SourceRoutingLength != 0) {
+
+// PUCHAR IpxHeader = Header + Binding->DefHeaderSize;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ SourceRouting = SourceRoutingBuffer;
+ // RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+
+ } else {
+
+ //
+ // For these packets we assume that the header is in the
+ // right place.
+ //
+
+ if (!Adapter->SourceRouting) {
+
+ SourceRoutingLength = 0;
+
+ } else {
+
+ if (DestinationType == DESTINATION_BCAST) {
+
+ if (Binding->AllRouteBroadcast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ } else {
+
+ CTEAssert (DestinationType == DESTINATION_MCAST);
+
+ if (Binding->AllRouteMulticast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ }
+
+ if (SourceRoutingLength != 0) {
+
+ // PUCHAR IpxHeader = Header + Binding->BcMcHeaderSize;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ // RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+ }
+ }
+
+ Header[0] = TR_PREAMBLE_AC;
+ Header[1] = TR_PREAMBLE_FC;
+ RtlCopyMemory (Header+2, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+8, Adapter->LocalMacAddress.Address, 6);
+
+ if (SourceRoutingLength != 0) {
+ Header[8] |= TR_SOURCE_ROUTE_FLAG;
+ RtlCopyMemory (Header+14, SourceRouting, SourceRoutingLength);
+ }
+
+ Header += (14 + SourceRoutingLength);
+
+ Header[0] = 0xaa;
+ Header[1] = 0xaa;
+ Header[2] = 0x03;
+ Header[3] = 0x00;
+ Header[4] = 0x00;
+ Header[5] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[6]) = Adapter->BindSapNetworkOrder;
+ HeaderLength = 22;
+
+ //BufferLength = IncludedHeaderLength + HeaderLength + SourceRoutingLength;
+ BufferLength = HeaderLength + SourceRoutingLength;
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, BufferLength);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, BufferLength);
+#endif
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_5Snap */
+
+
+NDIS_STATUS
+IpxSendFrameFddi802_3(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMFDDI FRAMES IN
+ THE ISN_FRAME_TYPE_802_3 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 13, Packet);
+#endif BACK_FILL
+
+ Header[0] = FDDI_HEADER_BYTE;
+ RtlCopyMemory (Header+1, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+7, Adapter->LocalMacAddress.Address, 6);
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 13);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 13);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 13);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrameFddi802_3 */
+
+
+NDIS_STATUS
+IpxSendFrameFddi802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMFDDI FRAMES IN
+ THE ISN_FRAME_TYPE_802_2 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 16, Packet);
+#endif BACK_FILL
+
+ Header[0] = FDDI_HEADER_BYTE;
+ RtlCopyMemory (Header+1, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+7, Adapter->LocalMacAddress.Address, 6);
+
+ Header[13] = 0xe0;
+ Header[14] = 0xe0;
+ Header[15] = 0x03;
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 16);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 16);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 16);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrameFddi802_2 */
+
+
+NDIS_STATUS
+IpxSendFrameFddiSnap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMFDDI FRAMES IN
+ THE ISN_FRAME_TYPE_SNAP FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 21, Packet);
+#endif BACK_FILL
+
+ Header[0] = FDDI_HEADER_BYTE;
+ RtlCopyMemory (Header+1, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+7, Adapter->LocalMacAddress.Address, 6);
+
+ Header[13] = 0xaa;
+ Header[14] = 0xaa;
+ Header[15] = 0x03;
+ Header[16] = 0x00;
+ Header[17] = 0x00;
+ Header[18] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[19]) = Adapter->BindSapNetworkOrder;
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 21);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 21);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 21);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrameFddiSnap */
+
+
+NDIS_STATUS
+IpxSendFrameArcnet878_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMARCNET878_2 FRAMES IN
+ THE ISN_FRAME_TYPE_802_2 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 3, Packet);
+#endif BACK_FILL
+ //
+ // Convert broadcast address to 0 (the arcnet broadcast).
+ //
+
+ Header[0] = Adapter->LocalMacAddress.Address[5];
+ if (LocalTarget->MacAddress[5] == 0xff) {
+ Header[1] = 0x00;
+ } else {
+ Header[1] = LocalTarget->MacAddress[5];
+ }
+ Header[2] = ARCNET_PROTOCOL_ID;
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 3);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 3);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 3);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrameFddiArcnet878_2 */
+
+
+NDIS_STATUS
+IpxSendFrameWanEthernetII(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMWAN FRAMES IN
+ THE ISN_FRAME_TYPE_ETHERNET_II FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+#ifdef _PNP_POWER
+ PBINDING Binding;
+
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_GET_LOCK1(&IpxDevice->BindAccessLock, &LockHandle1);
+ Binding = NIC_ID_TO_BINDING(IpxDevice, NIC_FROM_LOCAL_TARGET(LocalTarget));
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+
+ IPX_FREE_LOCK1(&IpxDevice->BindAccessLock, LockHandle1);
+
+#else
+ PBINDING Binding = IpxDevice->Bindings[LocalTarget->NicId];
+#endif _PNP_POWER
+
+ if (Binding->LineUp) {
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 14, Packet);
+
+ //
+ // Call UpdateWanInactivity only if this is not a backfill packet, since
+ // SMB server does not do KeepAlives. In case, of backfilled packets, reset
+ // the counter regardless.
+ //
+ if (!Reserved->BackFill) {
+ IpxUpdateWanInactivityCounter(
+ Binding,
+ (IPX_HEADER UNALIGNED *)(Header + IpxDevice->IncludedHeaderOffset),
+ IncludedHeaderLength,
+ Packet,
+ PacketLength);
+ } else {
+ Binding->WanInactivityCounter = 0;
+ }
+
+#else
+ //
+ // We do checks to see if we should reset the inactivity
+ // counter. We normally need to check for netbios
+ // session alives, packets from rip, packets from
+ // sap, and ncp keep alives. In fact netbios packets
+ // and rip packets don't come through here.
+ //
+
+ IpxUpdateWanInactivityCounter(
+ Binding,
+ (IPX_HEADER UNALIGNED *)(Header + IpxDevice->IncludedHeaderOffset),
+ IncludedHeaderLength,
+ Packet,
+ PacketLength);
+#endif BACK_FILL
+
+ RtlCopyMemory (Header, Binding->RemoteMacAddress.Address, 6);
+ RtlCopyMemory (Header+6, Binding->LocalMacAddress.Address, 6);
+
+ *(UNALIGNED USHORT *)(&Header[12]) = Adapter->BindSapNetworkOrder;
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 14);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 14);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 14);
+#endif
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ return Status;
+
+ } else {
+
+ //
+ // Bug #17273 return proper error message
+ //
+
+ // return STATUS_DEVICE_DOES_NOT_EXIST;
+
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ return STATUS_NETWORK_UNREACHABLE;
+ }
+
+} /* IpxSendFrameWanEthernetII */
+
+
+VOID
+MacUpdateSourceRouting(
+ IN ULONG Database,
+ IN PADAPTER Adapter,
+ IN PUCHAR MacHeader,
+ IN ULONG MacHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a valid IPX frame is received from
+ a remote. It gives the source routing database a change to
+ update itself to include information about this remote.
+
+Arguments:
+
+ Database - The "database" to use (IPX, SPX, NB, RIP).
+
+ Adapter - The adapter the frame was received on.
+
+ MacHeader - The MAC header of the received frame.
+
+ MacHeaderLength - The length of the MAC header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSOURCE_ROUTE Current;
+ ULONG Hash;
+ LONG Result;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ CTEAssert ((Database >= 0) && (Database <= 3));
+
+ //
+ // If this adapter is configured for no source routing, don't
+ // need to do anything.
+ //
+
+ if (!Adapter->SourceRouting) {
+ return;
+ }
+
+ //
+ // See if this source routing is relevant. We don't
+ // care about two-byte source routing since that
+ // indicates it did not cross a router. If there
+ // is nothing in the database, then don't add
+ // this if it is minimal (if it is not, we need
+ // to add it so we will find it on sending).
+ //
+
+ if ((Adapter->SourceRoutingEmpty[Database]) &&
+ (MacHeaderLength <= 16)) {
+ return;
+ }
+
+ IPX_GET_LOCK (&Adapter->Lock, &LockHandle);
+
+ //
+ // Try to find this address in the database.
+ //
+
+ Hash = MacSourceRoutingHash (MacHeader+8);
+ Current = Adapter->SourceRoutingHeads[Database][Hash];
+
+ while (Current != (PSOURCE_ROUTE)NULL) {
+
+ IPX_NODE_COMPARE (MacHeader+8, Current->MacAddress, &Result);
+
+ if (Result == 0) {
+
+ //
+ // We found routing for this node. If the data is the
+ // same as what we have, update the time since used to
+ // prevent aging.
+ //
+
+ if ((Current->SourceRoutingLength == MacHeaderLength-14) &&
+ (RtlEqualMemory (Current->SourceRouting, MacHeader+14, MacHeaderLength-14))) {
+
+ Current->TimeSinceUsed = 0;
+ }
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+ return;
+
+ } else {
+
+ Current = Current->Next;
+ }
+
+ }
+
+ //
+ // Not found, insert a new node at the front of the list.
+ //
+
+ Current = (PSOURCE_ROUTE)IpxAllocateMemory (SOURCE_ROUTE_SIZE(MacHeaderLength-14), MEMORY_SOURCE_ROUTE, "SourceRouting");
+
+ if (Current == (PSOURCE_ROUTE)NULL) {
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+ return;
+ }
+
+ Current->Next = Adapter->SourceRoutingHeads[Database][Hash];
+ Adapter->SourceRoutingHeads[Database][Hash] = Current;
+
+ Adapter->SourceRoutingEmpty[Database] = FALSE;
+
+ RtlCopyMemory (Current->MacAddress, MacHeader+8, 6);
+ Current->MacAddress[0] &= 0x7f;
+ Current->SourceRoutingLength = (UCHAR)(MacHeaderLength - 14);
+ RtlCopyMemory (Current->SourceRouting, MacHeader+14, MacHeaderLength - 14);
+
+ Current->TimeSinceUsed = 0;
+
+ IPX_DEBUG (SOURCE_ROUTE, ("Adding source route %lx for %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ Current, Current->MacAddress[0], Current->MacAddress[1],
+ Current->MacAddress[2], Current->MacAddress[3],
+ Current->MacAddress[4], Current->MacAddress[5]));
+
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+
+} /* MacUpdateSourceRouting */
+
+
+VOID
+MacLookupSourceRouting(
+ IN ULONG Database,
+ IN PBINDING Binding,
+ IN UCHAR MacAddress[6],
+ IN OUT UCHAR SourceRouting[18],
+ OUT PULONG SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine looks up a target address in the adapter's
+ source routing database to see if source routing information
+ needs to be added to the frame.
+
+Arguments:
+
+ Database - The "database" to use (IPX, SPX, NB, RIP).
+
+ Binding - The binding the frame is being sent on.
+
+ MacAddress - The destination address.
+
+ SourceRouting - Buffer to hold the returned source routing info.
+
+ SourceRoutingLength - The returned source routing length.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSOURCE_ROUTE Current;
+ PADAPTER Adapter = Binding->Adapter;
+ ULONG Hash;
+ LONG Result;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ //
+ // If this adapter is configured for no source routing, don't
+ // insert any.
+ //
+
+ if (!Adapter->SourceRouting) {
+ *SourceRoutingLength = 0;
+ return;
+ }
+
+ //
+ // See if source routing has not been important so far.
+ //
+ // BUGBUG: This is wrong because we may be sending a directed
+ // packet to somebody on the other side of a router, without
+ // ever having received a routed packet. We fix this for the
+ // moment by only setting SourceRoutingEmpty for netbios
+ // which uses broadcasts for discovery.
+ //
+
+ if (Adapter->SourceRoutingEmpty[Database]) {
+ *SourceRoutingLength = 0;
+ return;
+ }
+
+ Hash = MacSourceRoutingHash (MacAddress);
+
+ IPX_GET_LOCK (&Adapter->Lock, &LockHandle);
+ Current = Adapter->SourceRoutingHeads[Database][Hash];
+
+ while (Current != (PSOURCE_ROUTE)NULL) {
+
+ IPX_NODE_COMPARE (MacAddress, Current->MacAddress, &Result);
+
+ if (Result == 0) {
+
+ //
+ // We found routing for this node.
+ //
+
+ if (Current->SourceRoutingLength <= 2) {
+ *SourceRoutingLength = 0;
+ } else {
+ RtlCopyMemory (SourceRouting, Current->SourceRouting, Current->SourceRoutingLength);
+ SourceRouting[0] = (SourceRouting[0] & TR_LENGTH_MASK);
+ SourceRouting[1] = (SourceRouting[1] ^ TR_DIRECTION_MASK);
+ *SourceRoutingLength = Current->SourceRoutingLength;
+ }
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+ return;
+
+ } else {
+
+ Current = Current->Next;
+
+ }
+
+ }
+
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+
+ //
+ // We did not find this node, use the default.
+ //
+
+ if (Binding->AllRouteDirected) {
+ RtlCopyMemory (SourceRouting, AllRouteSourceRouting, 2);
+ } else {
+ RtlCopyMemory (SourceRouting, SingleRouteSourceRouting, 2);
+ }
+ *SourceRoutingLength = 2;
+
+} /* MacLookupSourceRouting */
+
+
+VOID
+MacSourceRoutingTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the source routing timer expires.
+ It is called every minute.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the device pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)Context;
+ PADAPTER Adapter;
+ PBINDING Binding;
+ PSOURCE_ROUTE Current, OldCurrent, Previous;
+ UINT i, j, k;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+#ifdef _PNP_POWER
+
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ //
+ // Get a lock on the access path.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ ++Device->SourceRoutingTime;
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->ValidBindings);
+
+ for (i = 1; i <= Index; i++) {
+
+ if (Binding = NIC_ID_TO_BINDING(Device, i)) {
+#else
+ ++Device->SourceRoutingTime;
+
+ for (i = 1; i <= Device->ValidBindings; i++) {
+
+ if (Binding = Device->Bindings[i]) {
+#endif _PNP_POWER
+
+ Adapter = Binding->Adapter;
+
+ if (Adapter->LastSourceRoutingTime != Device->SourceRoutingTime) {
+
+ //
+ // We need to scan this adapter's source routing
+ // tree for stale routes. To simplify the scan we
+ // only delete entries that have at least one
+ // child that is NULL.
+ //
+
+ Adapter->LastSourceRoutingTime = Device->SourceRoutingTime;
+
+ for (j = 0; j < IDENTIFIER_TOTAL; j++) {
+
+ for (k = 0; k < SOURCE_ROUTE_HASH_SIZE; k++) {
+
+ if (Adapter->SourceRoutingHeads[j][k] == (PSOURCE_ROUTE)NULL) {
+ continue;
+ }
+
+ IPX_GET_LOCK (&Adapter->Lock, &LockHandle);
+
+ Current = Adapter->SourceRoutingHeads[j][k];
+ Previous = (PSOURCE_ROUTE)NULL;
+
+ while (Current != (PSOURCE_ROUTE)NULL) {
+
+ ++Current->TimeSinceUsed;
+
+ if (Current->TimeSinceUsed >= Device->SourceRouteUsageTime) {
+
+ //
+ // A stale entry needs to be aged.
+ //
+
+ if (Previous) {
+ Previous->Next = Current->Next;
+ } else {
+ Adapter->SourceRoutingHeads[j][k] = Current->Next;
+ }
+
+ OldCurrent = Current;
+ Current = Current->Next;
+
+ IPX_DEBUG (SOURCE_ROUTE, ("Aging out source-route entry %lx\n", OldCurrent));
+ IpxFreeMemory (OldCurrent, SOURCE_ROUTE_SIZE (OldCurrent->SourceRoutingLength), MEMORY_SOURCE_ROUTE, "SourceRouting");
+
+ } else {
+
+ Previous = Current;
+ Current = Current->Next;
+ }
+
+ }
+
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+
+ } // for loop through the database's hash list
+
+ } // for loop through the adapter's four databases
+
+ } // if adapter's database needs to be checked
+
+ } // if binding exists
+
+ } // for loop through every binding
+ }
+
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif _PNP_POWER
+
+ //
+ // Now restart the timer unless we should not (which means
+ // we are being unloaded).
+ //
+
+ if (Device->SourceRoutingUsed) {
+
+ CTEStartTimer(
+ &Device->SourceRoutingTimer,
+ 60000, // one minute timeout
+ MacSourceRoutingTimeout,
+ (PVOID)Device);
+
+ } else {
+
+ IpxDereferenceDevice (Device, DREF_SR_TIMER);
+ }
+
+} /* MacSourceRoutingTimeout */
+
+
+VOID
+MacSourceRoutingRemove(
+ IN PBINDING Binding,
+ IN UCHAR MacAddress[6]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the IPX action handler when an
+ IPXROUTE use has specified that source routing for a given
+ MAC address should be removed.
+
+Arguments:
+
+ Binding - The binding to modify.
+
+ MacAddress - The MAC address to remove.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PSOURCE_ROUTE Current, Previous;
+ PADAPTER Adapter = Binding->Adapter;
+ ULONG Hash;
+ ULONG Database;
+ LONG Result;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // Scan through to find the matching entry in each database.
+ //
+
+ Hash = MacSourceRoutingHash (MacAddress);
+
+ IPX_GET_LOCK (&Adapter->Lock, &LockHandle);
+
+ for (Database = 0; Database < IDENTIFIER_TOTAL; Database++) {
+
+ Current = Adapter->SourceRoutingHeads[Database][Hash];
+ Previous = NULL;
+
+ while (Current != (PSOURCE_ROUTE)NULL) {
+
+ IPX_NODE_COMPARE (MacAddress, Current->MacAddress, &Result);
+
+ if (Result == 0) {
+
+ if (Previous) {
+ Previous->Next = Current->Next;
+ } else {
+ Adapter->SourceRoutingHeads[Database][Hash] = Current->Next;
+ }
+
+ IPX_DEBUG (SOURCE_ROUTE, ("IPXROUTE freeing source-route entry %lx\n", Current));
+ IpxFreeMemory (Current, SOURCE_ROUTE_SIZE (Current->SourceRoutingLength), MEMORY_SOURCE_ROUTE, "SourceRouting");
+
+ break;
+
+ } else {
+
+ Previous = Current;
+ Current = Current->Next;
+
+ }
+
+ }
+
+ }
+
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+
+} /* MacSourceRoutingRemove */
+
+
+VOID
+MacSourceRoutingClear(
+ IN PBINDING Binding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the IPX action handler when an
+ IPXROUTE use has specified that source routing for a given
+ binding should be cleared entirely.
+
+Arguments:
+
+ Binding - The binding to be cleared.
+
+ MacAddress - The MAC address to remove.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSOURCE_ROUTE Current;
+ PADAPTER Adapter = Binding->Adapter;
+ ULONG Database, Hash;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // Scan through and remove every entry in the database.
+ //
+
+ IPX_GET_LOCK (&Adapter->Lock, &LockHandle);
+
+ for (Database = 0; Database < IDENTIFIER_TOTAL; Database++) {
+
+ for (Hash = 0; Hash < SOURCE_ROUTE_HASH_SIZE; Hash++) {
+
+ while (Adapter->SourceRoutingHeads[Database][Hash]) {
+
+ Current = Adapter->SourceRoutingHeads[Database][Hash];
+ Adapter->SourceRoutingHeads[Database][Hash] = Current->Next;
+
+ IpxFreeMemory (Current, SOURCE_ROUTE_SIZE (Current->SourceRoutingLength), MEMORY_SOURCE_ROUTE, "SourceRouting");
+
+ }
+ }
+ }
+
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+
+} /* MacSourceRoutingClear */
+
+
+
diff --git a/private/ntos/tdi/isnp/ipx/mac.h b/private/ntos/tdi/isnp/ipx/mac.h
new file mode 100644
index 000000000..a88e77ecd
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/mac.h
@@ -0,0 +1,44 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ mac.h
+
+Abstract:
+
+ This header file defines manifest constants and necessary macros for use
+ by transports dealing with multiple MAC cards through the NDIS interface.
+
+Revision History:
+
+--*/
+
+
+//
+// We need this to define information about the MAC. Note that
+// it is a strange structure in that the first four elements
+// are for use internally by the mac.c routines, while the
+// DeviceContext knows about and uses the last two.
+//
+
+typedef struct _NDIS_INFORMATION {
+
+ NDIS_MEDIUM MediumType;
+ NDIS_MEDIUM RealMediumType;
+ BOOLEAN SourceRouting;
+ BOOLEAN MediumAsync;
+ UCHAR BroadcastMask;
+ ULONG CopyLookahead;
+ ULONG MacOptions;
+ ULONG MinHeaderLength;
+ ULONG MaxHeaderLength;
+
+} NDIS_INFORMATION, * PNDIS_INFORMATION;
+
+
+#define TR_SOURCE_ROUTE_FLAG 0x80
+
+#define ARCNET_PROTOCOL_ID 0xFA
+
diff --git a/private/ntos/tdi/isnp/ipx/mp/makefile b/private/ntos/tdi/isnp/ipx/mp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/mp/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isnp/ipx/mp/nwlnkipx.prf b/private/ntos/tdi/isnp/ipx/mp/nwlnkipx.prf
new file mode 100644
index 000000000..0c4359235
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/mp/nwlnkipx.prf
@@ -0,0 +1,89 @@
+IpxTdiSendDatagram@8
+IpxReceiveIndicationNew@36
+IpxSendFrame@16
+IpxReceiveComplete@4
+IpxSendFrame802_3802_2@20
+IpxReceivePacket@8
+IpxDerefAddressSync@4
+IpxSendComplete@12
+IpxSendFramePreFwd@16
+IpxReceiveIndication@28
+IpxInitializeBackFillPacket@12
+IpxpAllocateMemory@12
+IpxPopBackFillPacket@4
+IpxAllocateBackFillPool@4
+RipLongTimeout@8
+CTEStartTimer@16
+TdiCopyBufferToMdl@24
+IpxTdiQueryInformation@8
+IpxVerifyAddressFile@4
+IpxDispatchInternal@8
+IpxTransferData@28
+IpxInitLoopback@0
+RipGetFirstRoute@4
+IpxCreateAddress@8
+MacReturnMaxDataSize@20
+IpxLookupAddress@8
+IpxAbortLineChanges@4
+MacMapFrameType@12
+IpxInitializeReceiveBuffer@16
+IpxDispatchOpenClose@8
+IpxTdiSetEventHandler@4
+IpxCreateAddressFile@4
+IpxInternalBind@8
+IpxInitializeReceivePacket@8
+IpxIsAddressLocal@4
+IpxOpenAddress@8
+IpxAllocateReceiveBufferPool@4
+IpxSubmitNdisRequest@12
+IpxAddBroadcast@4
+IpxDestroyBinding@4
+RipAdjustForBindingChange@12
+IpxDispatchDeviceControl@8
+IpxAllocatePaddingBuffer@4
+TdiMapUserRequest@12
+CTEInitialize@0
+IpxInitializeSendPacket@12
+IpxpFreeMemory@12
+IpxInitializePaddingBuffer@12
+IpxAllocateSendPool@4
+RipCleanupPacket@8
+TdiRegisterDeviceObject@8
+TdiRegisterNetAddress@8
+IpxTdiAction@8
+IpxCreateBinding@20
+IpxDerefDevice@4
+MacInitializeBindingInfo@8
+IpxRegisterProtocol@4
+IpxInitializeNdis@8
+IpxGetConfigValue@24
+IpxCreateAdapter@12
+IpxResolveBindingSets@8
+IpxGetFrameType@24
+MacInitializeMacInfo@8
+IpxGetBindingValue@24
+RipQueueRequest@8
+RipShortTimeout@8
+IpxPopSendPacket@4
+IpxAllocateBindingPool@4
+IpxInternalQuery@20
+CTEInitTimer@4
+IpxRequestComplete@12
+IpxBroadcastOperation@4
+CTEInitEvent@8
+IpxPnPGetVirtualNetworkNumber@4
+IpxPnPGetAdapterParameters@12
+IpxOpenAdapterComplete@12
+IpxResolveAutoDetect@16
+IpxBindToAdapter@16
+TdiInitialize@0
+IpxPnPIsnIndicate@4
+IpxPnPUpdateBindingArray@12
+IpxBindAdapter@20
+IpxPnPUpdateDevice@4
+IpxGetConfiguration@12
+IpxAddExport@24
+IpxCreateDevice@16
+DriverEntry@8
+IpxReadLinkageInformation@4
+IpxFreeConfiguration@4
diff --git a/private/ntos/tdi/isnp/ipx/mp/sources b/private/ntos/tdi/isnp/ipx/mp/sources
new file mode 100644
index 000000000..dc48d81bb
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/mp/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+NT_UP=0
+
+TARGETPATH=\nt\public\sdk\lib
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/isnp/ipx/ndis.c b/private/ntos/tdi/isnp/ipx/ndis.c
new file mode 100644
index 000000000..14066a786
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/ndis.c
@@ -0,0 +1,2204 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ ndis.c
+
+Abstract:
+
+ This module contains code which implements the routines used to
+ initialize the IPX <-> NDIS interface, as well as most of the
+ interface routines.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports
+ 1. Added the ReceivePacketHandler to the ProtChars.
+
+ Sanjay Anand (SanjayAn) 27-Oct-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+ Tony Bell (TonyBe) 10-Dec-1995
+ Changes to support new NdisWan Lineup.
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// This is a one-per-driver variable used in binding
+// to the NDIS interface.
+//
+
+NDIS_HANDLE IpxNdisProtocolHandle = (NDIS_HANDLE)NULL;
+
+NDIS_STATUS
+IpxSubmitNdisRequest(
+ IN PADAPTER Adapter,
+ IN PNDIS_REQUEST NdisRequest,
+ IN PNDIS_STRING AdapterString
+ );
+
+#ifndef _PNP_POWER
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,IpxRegisterProtocol)
+#pragma alloc_text(INIT,IpxInitializeNdis)
+#endif
+#endif
+
+
+NTSTATUS
+IpxRegisterProtocol(
+ IN PNDIS_STRING NameString
+ )
+
+/*++
+
+Routine Description:
+
+ This routine introduces this transport to the NDIS interface.
+
+Arguments:
+
+ NameString - The name of the transport.
+
+Return Value:
+
+ The function value is the status of the operation.
+ STATUS_SUCCESS if all goes well,
+ Failure status if we tried to register and couldn't,
+ STATUS_INSUFFICIENT_RESOURCES if we couldn't even try to register.
+
+--*/
+
+{
+ NDIS_STATUS ndisStatus;
+
+ NDIS_PROTOCOL_CHARACTERISTICS ProtChars; // Used temporarily to register
+
+
+ //
+ // Set up the characteristics of this protocol
+ //
+#if NDIS40
+ ProtChars.MajorNdisVersion = 4;
+
+ ProtChars.ReceivePacketHandler = IpxReceivePacket;
+#else
+ ProtChars.MajorNdisVersion = 3;
+#endif
+ ProtChars.MinorNdisVersion = 0;
+
+ ProtChars.Name = *NameString;
+
+ ProtChars.OpenAdapterCompleteHandler = IpxOpenAdapterComplete;
+ ProtChars.CloseAdapterCompleteHandler = IpxCloseAdapterComplete;
+ ProtChars.ResetCompleteHandler = IpxResetComplete;
+ ProtChars.RequestCompleteHandler = IpxRequestComplete;
+
+ ProtChars.SendCompleteHandler = IpxSendComplete;
+ ProtChars.TransferDataCompleteHandler = IpxTransferDataComplete;
+
+ ProtChars.ReceiveHandler = IpxReceiveIndication;
+ ProtChars.ReceiveCompleteHandler = IpxReceiveComplete;
+ ProtChars.StatusHandler = IpxStatus;
+ ProtChars.StatusCompleteHandler = IpxStatusComplete;
+
+#ifdef _PNP_POWER
+ ProtChars.BindAdapterHandler = IpxBindAdapter;
+ ProtChars.UnbindAdapterHandler = IpxUnbindAdapter;
+ ProtChars.TranslateHandler = IpxTranslate;
+#endif // _PNP_POWER
+
+ NdisRegisterProtocol (
+ &ndisStatus,
+ &IpxNdisProtocolHandle,
+ &ProtChars,
+ (UINT)sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + NameString->Length);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS) {
+ return (NTSTATUS)ndisStatus;
+ }
+
+ return STATUS_SUCCESS;
+
+} /* IpxRegisterProtocol */
+
+
+VOID
+IpxDeregisterProtocol (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes this transport to the NDIS interface.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS ndisStatus;
+
+ if (IpxNdisProtocolHandle != (NDIS_HANDLE)NULL) {
+ NdisDeregisterProtocol (
+ &ndisStatus,
+ IpxNdisProtocolHandle);
+ IpxNdisProtocolHandle = (NDIS_HANDLE)NULL;
+ }
+
+} /* IpxDeregisterProtocol */
+
+
+NDIS_STATUS
+IpxSubmitNdisRequest(
+ IN PADAPTER Adapter,
+ IN PNDIS_REQUEST NdisRequest,
+ IN PNDIS_STRING AdapterString
+ )
+
+/*++
+
+Routine Description:
+
+ This routine passed an NDIS_REQUEST to the MAC and waits
+ until it has completed before returning the final status.
+
+Arguments:
+
+ Adapter - Pointer to the device context for this driver.
+
+ NdisRequest - Pointer to the NDIS_REQUEST to submit.
+
+ AdapterString - The name of the adapter, in case an error needs
+ to be logged.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NDIS_STATUS NdisStatus;
+
+ NdisRequest(
+ &NdisStatus,
+ Adapter->NdisBindingHandle,
+ NdisRequest);
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &Adapter->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = Adapter->NdisRequestStatus;
+
+ KeResetEvent(
+ &Adapter->NdisRequestEvent
+ );
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ IPX_DEBUG (NDIS, ("%s on OID %8.8lx failed %lx\n",
+ NdisRequest->RequestType == NdisRequestSetInformation ? "Set" : "Query",
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ NdisStatus));
+
+ IpxWriteOidErrorLog(
+ Adapter->Device->DeviceObject,
+ NdisRequest->RequestType == NdisRequestSetInformation ?
+ EVENT_TRANSPORT_SET_OID_FAILED : EVENT_TRANSPORT_QUERY_OID_FAILED,
+ NdisStatus,
+ AdapterString->Buffer,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid);
+
+ } else {
+
+ IPX_DEBUG (NDIS, ("%s on OID %8.8lx succeeded\n",
+ NdisRequest->RequestType == NdisRequestSetInformation ? "Set" : "Query",
+ NdisRequest->DATA.QUERY_INFORMATION.Oid));
+ }
+
+ return NdisStatus;
+
+} /* IpxSubmitNdisRequest */
+
+
+NTSTATUS
+IpxInitializeNdis(
+ IN PADAPTER Adapter,
+ IN PBINDING_CONFIG ConfigBinding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine introduces this transport to the NDIS interface and sets up
+ any necessary NDIS data structures (Buffer pools and such). It will be
+ called for each adapter opened by this transport.
+
+Arguments:
+
+ Adapter - Structure describing this binding.
+
+ ConfigAdapter - Configuration information for this binding.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NDIS_STATUS NdisStatus;
+ NDIS_STATUS OpenErrorStatus;
+ NDIS_MEDIUM IpxSupportedMedia[] = { NdisMedium802_3, NdisMedium802_5, NdisMediumFddi, NdisMediumArcnet878_2, NdisMediumWan };
+ UINT SelectedMedium;
+ NDIS_REQUEST IpxRequest;
+ ULONG MinimumLookahead;
+ UCHAR WanProtocolId[6] = { 0x80, 0x00, 0x00, 0x00, 0x81, 0x37 };
+ UCHAR FunctionalAddress[4] = { 0x00, 0x80, 0x00, 0x00 };
+ ULONG WanHeaderFormat = NdisWanHeaderEthernet;
+ NDIS_OID IpxOid;
+ ULONG MacOptions;
+ ULONG PacketFilter;
+ PNDIS_STRING AdapterString = &ConfigBinding->AdapterName;
+
+ //
+ // Initialize this adapter for IPX use through NDIS
+ //
+
+ //
+ // This event is used in case any of the NDIS requests
+ // pend; we wait until it is set by the completion
+ // routine, which also sets NdisRequestStatus.
+ //
+
+ KeInitializeEvent(
+ &Adapter->NdisRequestEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ Adapter->NdisBindingHandle = NULL;
+
+ OpenErrorStatus = 0;
+
+ NdisOpenAdapter (
+ &NdisStatus,
+ &OpenErrorStatus,
+ &Adapter->NdisBindingHandle,
+ &SelectedMedium,
+ IpxSupportedMedia,
+ sizeof (IpxSupportedMedia) / sizeof(NDIS_MEDIUM),
+ IpxNdisProtocolHandle,
+ (NDIS_HANDLE)Adapter,
+ &ConfigBinding->AdapterName,
+ 0,
+ NULL);
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &Adapter->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = Adapter->NdisRequestStatus;
+ OpenErrorStatus = Adapter->OpenErrorStatus;
+
+ KeResetEvent(
+ &Adapter->NdisRequestEvent
+ );
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ IPX_DEBUG (NDIS, ("Open %ws failed %lx\n", ConfigBinding->AdapterName.Buffer, NdisStatus));
+
+ IpxWriteGeneralErrorLog(
+ Adapter->Device->DeviceObject,
+ EVENT_TRANSPORT_ADAPTER_NOT_FOUND,
+ 807,
+ NdisStatus,
+ AdapterString->Buffer,
+ 1,
+ &OpenErrorStatus);
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ IPX_DEBUG (NDIS, ("Open %ws succeeded\n", ConfigBinding->AdapterName.Buffer));
+ }
+
+
+ //
+ // Get the information we need about the adapter, based on
+ // the media type.
+ //
+
+ MacInitializeMacInfo(
+ IpxSupportedMedia[SelectedMedium],
+ &Adapter->MacInfo);
+
+
+ switch (Adapter->MacInfo.RealMediumType) {
+
+ case NdisMedium802_3:
+
+ IpxOid = OID_802_3_CURRENT_ADDRESS;
+ break;
+
+ case NdisMedium802_5:
+
+ IpxOid = OID_802_5_CURRENT_ADDRESS;
+ break;
+
+ case NdisMediumFddi:
+
+ IpxOid = OID_FDDI_LONG_CURRENT_ADDR;
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ IpxOid = OID_ARCNET_CURRENT_ADDRESS;
+ break;
+
+ case NdisMediumWan:
+
+ IpxOid = OID_WAN_CURRENT_ADDRESS;
+ break;
+
+ default:
+
+ NdisStatus = NDIS_STATUS_FAILURE;
+ break;
+
+ }
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = IpxOid;
+
+ if (IpxOid != OID_ARCNET_CURRENT_ADDRESS) {
+
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = Adapter->LocalMacAddress.Address;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 6;
+
+ } else {
+
+ //
+ // We take the arcnet single-byte address and right-justify
+ // it in a field of zeros.
+ //
+
+ RtlZeroMemory (Adapter->LocalMacAddress.Address, 5);
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &Adapter->LocalMacAddress.Address[5];
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 1;
+
+ }
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now query the maximum packet sizes.
+ //
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_FRAME_SIZE;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(Adapter->MaxReceivePacketSize);
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(Adapter->MaxSendPacketSize);
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Query the receive buffer space.
+ //
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_RECEIVE_BUFFER_SPACE;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(Adapter->ReceiveBufferSpace);
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now set the minimum lookahead size. The value we choose
+ // here is the 128 needed for TDI indications, plus the size
+ // of the IPX header, plus the largest extra header possible
+ // (a SNAP header, 8 bytes), plus the largest higher-level
+ // header (I think it is a Netbios datagram, 34 bytes).
+ //
+ // BETABUGBUG: Adapt this based on higher-level bindings and
+ // configured frame types.
+ //
+
+ MinimumLookahead = 128 + sizeof(IPX_HEADER) + 8 + 34;
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_CURRENT_LOOKAHEAD;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &MinimumLookahead;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now query the link speed
+ //
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_LINK_SPEED;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(Adapter->MediumSpeed);
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // For wan, specify our protocol ID and header format.
+ // We don't query the medium subtype because we don't
+ // case (since we require ethernet emulation).
+ //
+
+ if (Adapter->MacInfo.MediumAsync) {
+
+ if (Adapter->BindSap != 0x8137) {
+ *(UNALIGNED USHORT *)(&WanProtocolId[4]) = Adapter->BindSapNetworkOrder;
+ }
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_PROTOCOL_TYPE;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = WanProtocolId;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 6;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_HEADER_FORMAT;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &WanHeaderFormat;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Now query the line count.
+ //
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_LINE_COUNT;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &Adapter->WanNicIdCount;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ Adapter->WanNicIdCount = 1;
+ }
+
+ if (Adapter->WanNicIdCount == 0) {
+
+ IPX_DEBUG (NDIS, ("OID_WAN_LINE_COUNT returned 0 lines\n"));
+
+ IpxWriteOidErrorLog(
+ Adapter->Device->DeviceObject,
+ EVENT_TRANSPORT_QUERY_OID_FAILED,
+ NDIS_STATUS_INVALID_DATA,
+ AdapterString->Buffer,
+ OID_WAN_LINE_COUNT);
+
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+ }
+
+
+ //
+ // For 802.5 adapter's configured that way, we enable the
+ // functional address (C0-00-00-80-00-00).
+ //
+
+ if ((Adapter->MacInfo.MediumType == NdisMedium802_5) &&
+ (Adapter->EnableFunctionalAddress)) {
+
+ //
+ // For token-ring, we pass the last four bytes of the
+ // Netbios functional address.
+ //
+
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_802_5_CURRENT_FUNCTIONAL;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = FunctionalAddress;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+
+ //
+ // Now query the MAC's optional characteristics.
+ //
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAC_OPTIONS;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &MacOptions;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Adapter->MacInfo.CopyLookahead =
+ ((MacOptions & NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA) != 0) ?
+ TDI_RECEIVE_COPY_LOOKAHEAD : 0;
+ Adapter->MacInfo.MacOptions = MacOptions;
+
+
+ switch (Adapter->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_2] = 17;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_3] = 14;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 14;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_SNAP] = 22;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_2] = 17;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_3] = 14;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 14;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_SNAP] = 22;
+ break;
+
+ case NdisMedium802_5:
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_2] = 17;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_3] = 17;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 17;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_SNAP] = 22;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_2] = 17;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_3] = 17;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 17;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_SNAP] = 22;
+ break;
+
+ case NdisMediumFddi:
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_2] = 16;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_3] = 13;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 16;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_SNAP] = 21;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_2] = 16;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_3] = 13;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 16;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_SNAP] = 21;
+ break;
+
+ case NdisMediumArcnet878_2:
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_2] = 3;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_3] = 3;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 3;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_SNAP] = 3;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_2] = 3;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_3] = 3;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 3;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_SNAP] = 3;
+ break;
+
+ }
+
+ //
+ // BUGBUG: If functional filtering is set, set the address
+ // for the appropriate binding.
+ //
+
+ //
+ // Now that everything is set up, we enable the filter
+ // for packet reception.
+ //
+
+ switch (Adapter->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+ case NdisMediumFddi:
+ case NdisMedium802_5:
+ case NdisMediumArcnet878_2:
+
+ //
+ // If we have a virtual network number we need to receive
+ // broadcasts (either the router will be bound in which
+ // case we want them, or we need to respond to rip requests
+ // ourselves).
+ //
+
+ PacketFilter = NDIS_PACKET_TYPE_DIRECTED;
+
+ if (Adapter->Device->VirtualNetworkNumber != 0) {
+
+ Adapter->BroadcastEnabled = TRUE;
+ Adapter->Device->EnableBroadcastCount = 1;
+ PacketFilter |= NDIS_PACKET_TYPE_BROADCAST;
+
+ if ((Adapter->MacInfo.MediumType == NdisMedium802_5) && (Adapter->EnableFunctionalAddress)) {
+ PacketFilter |= NDIS_PACKET_TYPE_FUNCTIONAL;
+ }
+
+ } else {
+
+ Adapter->BroadcastEnabled = FALSE;
+ Adapter->Device->EnableBroadcastCount = 0;
+
+ }
+
+ break;
+
+ default:
+
+ CTEAssert (FALSE);
+ break;
+
+ }
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ IpxRequest.DATA.SET_INFORMATION.InformationBuffer = &PacketFilter;
+ IpxRequest.DATA.SET_INFORMATION.InformationBufferLength = sizeof(ULONG);
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ return STATUS_SUCCESS;
+
+} /* IpxInitializeNdis */
+
+
+VOID
+IpxAddBroadcast(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when another reason for enabling
+ broadcast reception is added. If it is the first, then
+ reception on the card is enabled by queueing a call to
+ IpxBroadcastOperation.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD.
+
+Arguments:
+
+ Device - The IPX device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ++Device->EnableBroadcastCount;
+
+ if (Device->EnableBroadcastCount == 1) {
+
+ //
+ // Broadcasts should be enabled.
+ //
+
+ if (!Device->EnableBroadcastPending) {
+
+ if (Device->DisableBroadcastPending) {
+ Device->ReverseBroadcastOperation = TRUE;
+ } else {
+ Device->EnableBroadcastPending = TRUE;
+ ExInitializeWorkItem(
+ &Device->BroadcastOperationQueueItem,
+ IpxBroadcastOperation,
+ (PVOID)TRUE);
+ ExQueueWorkItem(&Device->BroadcastOperationQueueItem, DelayedWorkQueue);
+ }
+ }
+ }
+
+} /* IpxAddBroadcast */
+
+
+VOID
+IpxRemoveBroadcast(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a reason for enabling
+ broadcast reception is removed. If it is the last, then
+ reception on the card is disabled by queueing a call to
+ IpxBroadcastOperation.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD.
+
+Arguments:
+
+ Device - The IPX device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ --Device->EnableBroadcastCount;
+
+ if (Device->EnableBroadcastCount == 0) {
+
+ //
+ // Broadcasts should be disabled.
+ //
+
+ if (!Device->DisableBroadcastPending) {
+
+ if (Device->EnableBroadcastPending) {
+ Device->ReverseBroadcastOperation = TRUE;
+ } else {
+ Device->DisableBroadcastPending = TRUE;
+ ExInitializeWorkItem(
+ &Device->BroadcastOperationQueueItem,
+ IpxBroadcastOperation,
+ (PVOID)FALSE);
+ ExQueueWorkItem(&Device->BroadcastOperationQueueItem, DelayedWorkQueue);
+ }
+ }
+ }
+
+} /* IpxRemoveBroadcast */
+
+
+VOID
+IpxBroadcastOperation(
+ IN PVOID Parameter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to change whether broadcast reception
+ is enabled or disabled. It performs the requested operation
+ on every adapter bound to by IPX.
+
+ This routine is called by a worker thread queued when a
+ bind/unbind operation changes the broadcast state.
+
+Arguments:
+
+ Parameter - TRUE if broadcasts should be enabled, FALSE
+ if they should be disabled.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ BOOLEAN Enable = (BOOLEAN)Parameter;
+ UINT i;
+ PBINDING Binding;
+ PADAPTER Adapter;
+ ULONG PacketFilter;
+ NDIS_REQUEST IpxRequest;
+ NDIS_STRING AdapterName;
+ CTELockHandle LockHandle;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ IPX_DEBUG (NDIS, ("%s operation started\n", Enable ? "Enable" : "Disable"));
+
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->ValidBindings);
+
+ for (i = 1; i <= Index; i++) {
+
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ IPX_DEBUG (NDIS, ("%s operation started\n", Enable ? "Enable" : "Disable"));
+
+ for (i = 1; i <= Device->ValidBindings; i++) {
+
+ Binding = Device->Bindings[i];
+#endif
+ if (Binding == NULL) {
+ continue;
+ }
+
+ Adapter = Binding->Adapter;
+ if (Adapter->BroadcastEnabled == Enable) {
+ continue;
+ }
+
+ if (Enable) {
+ if ((Adapter->MacInfo.MediumType == NdisMedium802_5) && (Adapter->EnableFunctionalAddress)) {
+ PacketFilter = (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_FUNCTIONAL);
+ } else {
+ PacketFilter = (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST);
+ }
+ } else {
+ PacketFilter = NDIS_PACKET_TYPE_DIRECTED;
+ }
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ IpxRequest.DATA.SET_INFORMATION.InformationBuffer = &PacketFilter;
+ IpxRequest.DATA.SET_INFORMATION.InformationBufferLength = sizeof(ULONG);
+
+ AdapterName.Buffer = Adapter->AdapterName;
+ AdapterName.Length = (USHORT)Adapter->AdapterNameLength;
+ AdapterName.MaximumLength = (USHORT)(Adapter->AdapterNameLength + sizeof(WCHAR));
+
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ (VOID)IpxSubmitNdisRequest (Adapter, &IpxRequest, &AdapterName);
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+
+ Adapter->BroadcastEnabled = Enable;
+
+ }
+ }
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ if (Enable) {
+
+ CTEAssert (Device->EnableBroadcastPending);
+ Device->EnableBroadcastPending = FALSE;
+
+ if (Device->ReverseBroadcastOperation) {
+ Device->ReverseBroadcastOperation = FALSE;
+ Device->DisableBroadcastPending = TRUE;
+ ExInitializeWorkItem(
+ &Device->BroadcastOperationQueueItem,
+ IpxBroadcastOperation,
+ (PVOID)FALSE);
+ ExQueueWorkItem(&Device->BroadcastOperationQueueItem, DelayedWorkQueue);
+ }
+
+ } else {
+
+ CTEAssert (Device->DisableBroadcastPending);
+ Device->DisableBroadcastPending = FALSE;
+
+ if (Device->ReverseBroadcastOperation) {
+ Device->ReverseBroadcastOperation = FALSE;
+ Device->EnableBroadcastPending = TRUE;
+ ExInitializeWorkItem(
+ &Device->BroadcastOperationQueueItem,
+ IpxBroadcastOperation,
+ (PVOID)TRUE);
+ ExQueueWorkItem(&Device->BroadcastOperationQueueItem, DelayedWorkQueue);
+ }
+
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+}/* IpxBroadcastOperation */
+
+
+VOID
+IpxCloseNdis(
+ IN PADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unbinds the transport from the NDIS interface and does
+ any other work required to undo what was done in IpxInitializeNdis.
+ It is written so that it can be called from within IpxInitializeNdis
+ if it fails partway through.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NDIS_STATUS ndisStatus;
+
+ //
+ // Close the NDIS binding.
+ //
+
+ if (Adapter->NdisBindingHandle != (NDIS_HANDLE)NULL) {
+
+ //
+ // This event is used in case any of the NDIS requests
+ // pend; we wait until it is set by the completion
+ // routine, which also sets NdisRequestStatus.
+ //
+
+ KeInitializeEvent(
+ &Adapter->NdisRequestEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ NdisCloseAdapter(
+ &ndisStatus,
+ Adapter->NdisBindingHandle);
+
+ if (ndisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &Adapter->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ ndisStatus = Adapter->NdisRequestStatus;
+
+ KeResetEvent(
+ &Adapter->NdisRequestEvent
+ );
+
+ }
+
+ //
+ // We ignore ndisStatus.
+ //
+
+ }
+
+#if 0
+ if (Adapter->SendPacketPoolHandle != NULL) {
+ NdisFreePacketPool (Adapter->SendPacketPoolHandle);
+ }
+
+ if (Adapter->ReceivePacketPoolHandle != NULL) {
+ NdisFreePacketPool (Adapter->ReceivePacketPoolHandle);
+ }
+
+ if (Adapter->NdisBufferPoolHandle != NULL) {
+ NdisFreeBufferPool (Adapter->NdisBufferPoolHandle);
+ }
+#endif
+
+} /* IpxCloseNdis */
+
+
+VOID
+IpxOpenAdapterComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN NDIS_STATUS OpenErrorStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that an open adapter
+ is complete. Since we only ever have one outstanding, and then only
+ during initialization, all we do is record the status and set
+ the event to signalled to unblock the initialization thread.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+ OpenErrorStatus - More status information.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+
+ Adapter->NdisRequestStatus = NdisStatus;
+ Adapter->OpenErrorStatus = OpenErrorStatus;
+
+ KeSetEvent(
+ &Adapter->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+} /* IpxOpenAdapterComplete */
+
+VOID
+IpxCloseAdapterComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a close adapter
+ is complete. Currently we don't close adapters, so this is not
+ a problem.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+
+ Adapter->NdisRequestStatus = NdisStatus;
+
+ KeSetEvent(
+ &Adapter->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+} /* IpxCloseAdapterComplete */
+
+
+VOID
+IpxResetComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a reset adapter
+ is complete. Currently we don't reset adapters, so this is not
+ a problem.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(BindingContext);
+ UNREFERENCED_PARAMETER(NdisStatus);
+
+} /* IpxResetComplete */
+
+
+VOID
+IpxRequestComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a request is complete.
+ Since we only ever have one request outstanding, and then only
+ during initialization, all we do is record the status and set
+ the event to signalled to unblock the initialization thread.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisRequest - The object describing the request.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+
+ Adapter->NdisRequestStatus = NdisStatus;
+
+ KeSetEvent(
+ &Adapter->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+} /* IpxRequestComplete */
+
+
+VOID
+IpxStatus(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ )
+
+{
+ PADAPTER Adapter, TmpAdapter;
+
+ PNDIS_WAN_LINE_UP LineUp;
+ PNDIS_WAN_LINE_DOWN LineDown;
+ PIPXCP_CONFIGURATION Configuration; // contains ipx net and node
+
+ BOOLEAN UpdateLineUp;
+ PBINDING Binding, TmpBinding;
+ PDEVICE Device;
+ PADDRESS Address;
+ ULONG CurrentHash;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ PNDIS_BUFFER NdisBuffer;
+ PNWLINK_ACTION NwlinkAction;
+ PIPX_ADDRESS_DATA IpxAddressData;
+ PREQUEST Request;
+ UINT BufferLength;
+ IPX_LINE_INFO LineInfo;
+ ULONG Segment;
+ ULONG LinkSpeed;
+ PLIST_ENTRY p;
+ NTSTATUS Status;
+ UINT i, j;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+ NTSTATUS ntStatus;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ Adapter = (PADAPTER)NdisBindingContext;
+
+ IpxReferenceAdapter(Adapter);
+#else
+ Adapter = (PADAPTER)NdisBindingContext;
+#endif
+
+ Device = Adapter->Device;
+
+ switch (NdisStatus) {
+
+ case NDIS_STATUS_WAN_LINE_UP:
+
+
+ //
+ // If the line is already up, then we are just getting
+ // a change in line conditions, and the IPXCP_CONFIGURATION
+ // information is not included. If it turns out we need
+ // all the info, we check the size again later.
+ //
+
+ if (StatusBufferSize < sizeof(NDIS_WAN_LINE_UP)) {
+ IPX_DEBUG (WAN, ("Line up, status buffer size wrong %d/%d\n", StatusBufferSize, sizeof(NDIS_WAN_LINE_UP)));
+#ifdef _PNP_POWER
+ goto error_no_lock;
+#else
+ return;
+#endif
+ }
+
+ LineUp = (PNDIS_WAN_LINE_UP)StatusBuffer;
+
+ //
+ // We scan through the adapter's NIC ID range looking
+ // for an active binding with the same remote address.
+ //
+
+ UpdateLineUp = FALSE;
+
+ //
+ // See if this is a new lineup or not
+ //
+ *((ULONG UNALIGNED *)(&Binding)) =
+ *((ULONG UNALIGNED *)(&LineUp->LocalAddress[2]));
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+
+ if (Binding != NULL) {
+ UpdateLineUp = TRUE;
+ }
+
+ if (LineUp->ProtocolType != Adapter->BindSap) {
+ IPX_DEBUG (WAN, ("Line up, wrong protocol type %lx\n", LineUp->ProtocolType));
+
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ goto error_no_lock;
+#else
+ return;
+#endif
+ }
+
+ Configuration = (PIPXCP_CONFIGURATION)LineUp->ProtocolBuffer;
+
+ //
+ // PNP_POWER - We hold the exclusive lock to the binding array (thru both the device and adapter)
+ // and the reference to the adapter at this point.
+ //
+
+ //
+ // If this line was previously down, create a new binding
+ // if needed.
+ //
+
+ if (!UpdateLineUp) {
+
+ //
+ // We look for a binding that is allocated but down, if
+ // we can't find that then we look for any empty spot in
+ // the adapter's NIC ID range and allocate a binding in it.
+ // Since we always allocate this way, the allocated
+ // bindings are all clumped at the beginning and once
+ // we find a NULL spot we know there are no more
+ // allocated ones.
+ //
+ // We keep track of the first binding on this adapter
+ // in TmpBinding in case we need config info from it.
+ //
+
+ TmpBinding = NULL;
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (i = Adapter->FirstWanNicId;
+ i <= Adapter->LastWanNicId;
+ i++) {
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ if (TmpBinding == NULL) {
+ TmpBinding = Binding;
+ }
+
+ if ((Binding == NULL) ||
+ (!Binding->LineUp)) {
+ break;
+ }
+ }
+
+ if (i > Adapter->LastWanNicId) {
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IPX_DEBUG (WAN, ("Line up, no WAN binding available\n"));
+ return;
+ }
+
+ if (Binding == NULL) {
+
+ //
+ // We need to allocate one.
+ //
+
+ CTEAssert (TmpBinding != NULL);
+
+#ifdef _PNP_POWER
+ //
+ // CreateBinding does an InterLockedPop with the DeviceLock.
+ // So, release the lock here.
+ //
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+#endif
+ Status = IpxCreateBinding(
+ Device,
+ NULL,
+ 0,
+ Adapter->AdapterName,
+ &Binding);
+
+ if (Status != STATUS_SUCCESS) {
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ IPX_DEBUG (WAN, ("Line up, could not create WAN binding\n"));
+ goto error_no_lock;
+#else
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IPX_DEBUG (WAN, ("Line up, could not create WAN binding\n"));
+ return;
+#endif
+ }
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+#endif
+ //
+ // Binding->AllRouteXXX doesn't matter for WAN.
+ //
+
+ Binding->FrameType = ISN_FRAME_TYPE_ETHERNET_II;
+ Binding->SendFrameHandler = IpxSendFrameWanEthernetII;
+ ++Adapter->BindingCount;
+ Binding->Adapter = Adapter;
+
+ Binding->NicId = i;
+#ifdef _PNP_POWER
+ INSERT_BINDING(Device, i, Binding);
+#else
+ Device->Bindings[i] = Binding;
+#endif
+
+ //
+ // Other fields are filled in below.
+ //
+
+ }
+
+ //
+ // This is not an update, so note that the line is active.
+ //
+
+ Binding->LineUp = TRUE;
+
+ if (Configuration->ConnectionClient == 1) {
+ Binding->DialOutAsync = TRUE;
+ } else {
+ Binding->DialOutAsync = FALSE;
+ }
+
+ //
+ // Keep track of the highest NIC ID that we should
+ // send type 20s out on.
+ //
+
+ if (i > (UINT)MIN (Device->MaxBindings, Device->HighestType20NicId)) {
+
+ if ((Binding->DialOutAsync) ||
+ ((Device->DisableDialinNetbios & 0x01) == 0)) {
+
+ Device->HighestType20NicId = i;
+ }
+ }
+
+ //
+ // We could error out below, trying to insert this network number. In RipShortTimeout
+ // we dont check for LineUp when calculating the tick counts; set this before the insert
+ // attempt.
+ //
+ Binding->MediumSpeed = LineUp->LinkSpeed;
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+
+ //
+ // Add a router entry for this net if there is no router.
+ // We want the number of ticks for a 576-byte frame,
+ // given the link speed in 100 bps units, so we calculate
+ // as:
+ //
+ // seconds 18.21 ticks 4608 bits
+ // --------------------- * ----------- * ---------
+ // link_speed * 100 bits second frame
+ //
+ // to get the formula
+ //
+ // ticks/frame = 839 / link_speed.
+ //
+ // We add link_speed to the numerator also to ensure
+ // that the value is at least 1.
+ //
+
+ if ((!Device->UpperDriverBound[IDENTIFIER_RIP]) &&
+ (*(UNALIGNED ULONG *)Configuration->Network != 0)) {
+ if (RipInsertLocalNetwork(
+ *(UNALIGNED ULONG *)Configuration->Network,
+ Binding->NicId,
+ Adapter->NdisBindingHandle,
+ (USHORT)((839 + LineUp->LinkSpeed) / LineUp->LinkSpeed)) != STATUS_SUCCESS) {
+ //
+ // This means we couldn't allocate memory, or
+ // the entry already existed. If it already
+ // exists we can ignore it for the moment.
+ //
+ // BUGBUG: Now it will succeed if the network
+ // exists.
+ //
+
+ IPX_DEBUG (WAN, ("Line up, could not insert local network\n"));
+ Binding->LineUp = FALSE;
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ goto error_no_lock;
+#else
+ return;
+#endif
+ }
+ }
+
+
+ //
+ // Update our addresses.
+ //
+ Binding->LocalAddress.NetworkAddress = *(UNALIGNED ULONG *)Configuration->Network;
+ RtlCopyMemory (Binding->LocalAddress.NodeAddress, Configuration->LocalNode, 6);
+ RtlCopyMemory (Binding->WanRemoteNode, Configuration->RemoteNode, 6);
+
+ //
+ // Return the binding context for this puppy!
+ //
+ *((ULONG UNALIGNED *)(&LineUp->LocalAddress[2])) =
+ *((ULONG UNALIGNED *)(&Binding));
+
+ RtlCopyMemory (Binding->LocalMacAddress.Address, LineUp->LocalAddress, 6);
+ RtlCopyMemory (Binding->RemoteMacAddress.Address, LineUp->RemoteAddress, 6);
+
+ //
+ // Update the device node and all the address
+ // nodes if we have only one bound, or this is
+ // binding one.
+ //
+
+ if (!Device->VirtualNetwork) {
+
+ if ((!Device->MultiCardZeroVirtual) || (Binding->NicId == 1)) {
+ Device->SourceAddress.NetworkAddress = *(UNALIGNED ULONG *)(Configuration->Network);
+ RtlCopyMemory (Device->SourceAddress.NodeAddress, Configuration->LocalNode, 6);
+ }
+
+ //
+ // Scan through all the addresses that exist and modify
+ // their pre-constructed local IPX address to reflect
+ // the new local net and node.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (CurrentHash = 0; CurrentHash < IPX_ADDRESS_HASH_COUNT; CurrentHash++) {
+
+ for (p = Device->AddressDatabases[CurrentHash].Flink;
+ p != &Device->AddressDatabases[CurrentHash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ Address->LocalAddress.NetworkAddress = *(UNALIGNED ULONG *)Configuration->Network;
+ RtlCopyMemory (Address->LocalAddress.NodeAddress, Configuration->LocalNode, 6);
+ }
+ }
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ //
+ // Reset this since the line just came up.
+ //
+
+ Binding->WanInactivityCounter = 0;
+
+ }
+
+ LinkSpeed = LineUp->LinkSpeed;
+
+ //
+ // Scan through bindings to update Device->LinkSpeed.
+ // If SingleNetworkActive is set, we only count WAN
+ // bindings when doing this (although it is unlikely
+ // a LAN binding would be the winner).
+ //
+ // BUGBUG: Update other device information?
+ //
+
+ for (i = 1; i <= Device->ValidBindings; i++) {
+#ifdef _PNP_POWER
+ if (TmpBinding = NIC_ID_TO_BINDING(Device, i)) {
+#else
+ if (TmpBinding = Device->Bindings[i]) {
+#endif
+ TmpAdapter = TmpBinding->Adapter;
+ if (TmpBinding->LineUp &&
+ (!Device->SingleNetworkActive || TmpAdapter->MacInfo.MediumAsync) &&
+ (TmpBinding->MediumSpeed < LinkSpeed)) {
+ LinkSpeed = TmpBinding->MediumSpeed;
+ }
+ }
+ }
+
+#ifdef _PNP_POWER
+ //
+ // Release the lock after incrementing the reference count
+ //
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ Device->LinkSpeed = LinkSpeed;
+
+ if ((Adapter->ConfigMaxPacketSize == 0) ||
+ (LineUp->MaximumTotalSize < Adapter->ConfigMaxPacketSize)) {
+ Binding->MaxSendPacketSize = LineUp->MaximumTotalSize;
+ } else {
+ Binding->MaxSendPacketSize = Adapter->ConfigMaxPacketSize;
+ }
+ MacInitializeBindingInfo (Binding, Adapter);
+
+#ifdef _PNP_POWER
+
+ //
+ // We dont give lineups; instead indicate only if the PnP reserved address
+ // changed to SPX. NB gets all PnP indications with the reserved address case
+ // marked out.
+ //
+ {
+ IPX_PNP_INFO NBPnPInfo;
+
+ if ((!Device->MultiCardZeroVirtual) || (Binding->NicId == 1)) {
+
+ //
+ // NB's reserved address changed.
+ //
+ NBPnPInfo.NewReservedAddress = TRUE;
+
+ if (!Device->VirtualNetwork) {
+ //
+ // Let SPX know because it fills in its own headers.
+ //
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_PNP_INFO IpxPnPInfo;
+
+ IpxPnPInfo.NewReservedAddress = TRUE;
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_ADDRESS_CHANGE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_ADDRESS_CHANGED to SPX: net addr: %lx\n", Binding->LocalAddress.NetworkAddress));
+ }
+ }
+ } else {
+ NBPnPInfo.NewReservedAddress = FALSE;
+ }
+
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ NBPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ NBPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ NBPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ NBPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ NBPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ NBPnPInfo.FirstORLastDevice = FALSE;
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ RtlCopyMemory(NBPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(NBPnPInfo.NicHandle, Binding->NicId);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &NBPnPInfo);
+
+ IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_ADD_DEVICE (lineup) to NB: net addr: %lx\n", Binding->LocalAddress.NetworkAddress));
+ }
+
+ //
+ // Register this address with the TDI clients.
+ //
+ RtlCopyMemory (Device->TdiRegistrationAddress->Address, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
+
+ if ((ntStatus = TdiRegisterNetAddress(
+ Device->TdiRegistrationAddress,
+ &Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+
+ IPX_DEBUG(PNP, ("TdiRegisterNetAddress failed: %lx", ntStatus));
+ }
+ }
+
+ //
+ // Indicate to the upper drivers.
+ //
+ LineInfo.LinkSpeed = LineUp->LinkSpeed;
+ LineInfo.MaximumPacketSize = LineUp->MaximumTotalSize - 14;
+ LineInfo.MaximumSendSize = LineUp->MaximumTotalSize - 14;
+ LineInfo.MacOptions = Adapter->MacInfo.MacOptions;
+
+ //
+ // Give line up to RIP as it is not PnP aware.
+ //
+ if (Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ (*Device->UpperDrivers[IDENTIFIER_RIP].LineUpHandler)(
+ Binding->NicId,
+ &LineInfo,
+ NdisMediumWan,
+ UpdateLineUp ? NULL : Configuration);
+ }
+#else
+ //
+ // Indicate to the upper drivers.
+ //
+ LineInfo.LinkSpeed = LineUp->LinkSpeed;
+ LineInfo.MaximumPacketSize = LineUp->MaximumTotalSize - 14;
+ LineInfo.MaximumSendSize = LineUp->MaximumTotalSize - 14;
+ LineInfo.MacOptions = Adapter->MacInfo.MacOptions;
+ for (i = 0; i < UPPER_DRIVER_COUNT; i++) {
+
+ if (Device->UpperDriverBound[i]) {
+ (*Device->UpperDrivers[i].LineUpHandler)(
+ Binding->NicId,
+ &LineInfo,
+ NdisMediumWan,
+ UpdateLineUp ? NULL : Configuration);
+ }
+ }
+#endif
+ if (!UpdateLineUp) {
+
+ if ((Device->SingleNetworkActive) &&
+ (Configuration->ConnectionClient == 1)) {
+ //
+ // Drop all entries in the database if rip is not bound.
+ //
+
+ if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ RipDropRemoteEntries();
+ }
+
+ Device->ActiveNetworkWan = TRUE;
+
+ //
+ // Find a queued line change and complete it.
+ //
+
+ if ((p = ExInterlockedRemoveHeadList(
+ &Device->LineChangeQueue,
+ &Device->Lock)) != NULL) {
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_LINE_CHANGE);
+
+ }
+
+ //
+ // If we have a virtual net, do a broadcast now so
+ // the router on the other end will know about us.
+ //
+ // BUGBUG: Use RipSendResponse, and do it even
+ // if SingleNetworkActive is FALSE??
+ //
+
+ if (Device->RipResponder) {
+ (VOID)RipQueueRequest (Device->VirtualNetworkNumber, RIP_RESPONSE);
+ }
+
+ }
+
+ //
+ // Find a queued address notify and complete it.
+ // If WanGlobalNetworkNumber is TRUE, we only do
+ // this when the first dialin line comes up.
+ //
+
+ if ((!Device->WanGlobalNetworkNumber ||
+ (!Device->GlobalNetworkIndicated && !Binding->DialOutAsync))
+ &&
+ ((p = ExInterlockedRemoveHeadList(
+ &Device->AddressNotifyQueue,
+ &Device->Lock)) != NULL)) {
+
+ if (Device->WanGlobalNetworkNumber) {
+ Device->GlobalWanNetwork = Binding->LocalAddress.NetworkAddress;
+ Device->GlobalNetworkIndicated = TRUE;
+ }
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+ NdisBuffer = REQUEST_NDIS_BUFFER(Request);
+ NdisQueryBuffer (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength);
+
+ IpxAddressData = (PIPX_ADDRESS_DATA)(NwlinkAction->Data);
+
+ if (Device->WanGlobalNetworkNumber) {
+ IpxAddressData->adapternum = Device->SapNicCount - 1;
+ } else {
+ IpxAddressData->adapternum = Binding->NicId - 1;
+ }
+ *(UNALIGNED ULONG *)IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
+ IpxAddressData->wan = TRUE;
+ IpxAddressData->status = TRUE;
+ IpxAddressData->maxpkt = Binding->AnnouncedMaxDatagramSize; // BUGBUG: Use real?
+ IpxAddressData->linkspeed = Binding->MediumSpeed;
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_ADDRESS_NOTIFY);
+ }
+ }
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ break;
+
+ case NDIS_STATUS_WAN_LINE_DOWN:
+
+ if (StatusBufferSize < sizeof(NDIS_WAN_LINE_DOWN)) {
+ IPX_DEBUG (WAN, ("Line down, status buffer size wrong %d/%d\n", StatusBufferSize, sizeof(NDIS_WAN_LINE_DOWN)));
+ return;
+ }
+
+ LineDown = (PNDIS_WAN_LINE_DOWN)StatusBuffer;
+
+ *((ULONG UNALIGNED*)(&Binding)) = *((ULONG UNALIGNED*)(&LineDown->LocalAddress[2]));
+
+ CTEAssert(Binding != NULL);
+
+ //
+ // Note that the WAN line is down.
+ //
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+
+ Binding->LineUp = FALSE;
+
+ //
+ // PNP_POWER - we hold the exclusive lock to the binding
+ // and reference to the adapter at this point.
+ //
+
+ //
+ // Keep track of the highest NIC ID that we should
+ // send type 20s out on.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (Binding->NicId == MIN (Device->MaxBindings, Device->HighestType20NicId)) {
+
+ //
+ // This was the old limit, so we have to scan
+ // backwards to update it -- we stop when we hit
+ // a non-WAN binding, or a wan binding that is up and
+ // dialout, or any wan binding if bit 1 in
+ // DisableDialinNetbios is off.
+ //
+
+ for (i = Binding->NicId-1; i >= 1; i--) {
+#ifdef _PNP_POWER
+ TmpBinding = NIC_ID_TO_BINDING(Device, i);
+#else
+ TmpBinding = Device->Bindings[i];
+#endif
+
+ if ((TmpBinding != NULL) &&
+ ((!TmpBinding->Adapter->MacInfo.MediumAsync) ||
+ (TmpBinding->LineUp &&
+ ((Binding->DialOutAsync) ||
+ ((Device->DisableDialinNetbios & 0x01) == 0))))) {
+
+ break;
+ }
+ }
+
+ Device->HighestType20NicId = i;
+
+ }
+
+
+ //
+ // Scan through bindings to update Device->LinkSpeed.
+ // If SingleNetworkActive is set, we only count LAN
+ // bindings when doing this.
+ //
+ // BUGBUG: Update other device information?
+ //
+
+ LinkSpeed = 0xffffffff;
+ for (i = 1; i <= Device->ValidBindings; i++) {
+#ifdef _PNP_POWER
+ if (TmpBinding = NIC_ID_TO_BINDING(Device, i)) {
+#else
+ if (TmpBinding = Device->Bindings[i]) {
+#endif
+ TmpAdapter = TmpBinding->Adapter;
+ if (TmpBinding->LineUp &&
+ (!Device->SingleNetworkActive || !TmpAdapter->MacInfo.MediumAsync) &&
+ (TmpBinding->MediumSpeed < LinkSpeed)) {
+ LinkSpeed = TmpBinding->MediumSpeed;
+ }
+ }
+ }
+
+ if (LinkSpeed != 0xffffffff) {
+ Device->LinkSpeed = LinkSpeed;
+ }
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ //
+ // Remove our router entry for this net.
+ //
+
+ if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
+
+ Segment = RipGetSegment ((PUCHAR)&Binding->LocalAddress.NetworkAddress);
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ RouteEntry = RipGetRoute (Segment, (PUCHAR)&Binding->LocalAddress.NetworkAddress);
+
+ if (RouteEntry != (PIPX_ROUTE_ENTRY)NULL) {
+
+ RipDeleteRoute (Segment, RouteEntry);
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ IpxFreeMemory (RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+
+ } else {
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ }
+
+ RipAdjustForBindingChange (Binding->NicId, 0, IpxBindingDown);
+
+ }
+
+ //
+ // Indicate to the upper drivers.
+ //
+#ifdef _PNP_POWER
+
+ //
+ // DeRegister this address with the TDI clients.
+ //
+ {
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ CTEAssert(Binding->TdiRegistrationHandle);
+
+ if ((ntStatus = TdiDeregisterNetAddress(Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("TdiDeRegisterNetAddress failed: %lx", ntStatus));
+ }
+
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_PNP_INFO NBPnPInfo;
+
+ CTEAssert(Binding->IsnInformed[IDENTIFIER_NB]);
+
+ NBPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ NBPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ NBPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ NBPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ NBPnPInfo.NewReservedAddress = FALSE;
+ NBPnPInfo.FirstORLastDevice = FALSE;
+
+ NBPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+
+ RtlCopyMemory(NBPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(NBPnPInfo.NicHandle, Binding->NicId);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_DELETE_DEVICE,
+ &NBPnPInfo);
+
+ IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_DELETE_DEVICE (linedown) to NB: addr: %lx\n", Binding->LocalAddress.NetworkAddress));
+ } else {
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+ }
+
+ if (Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ (*Device->UpperDrivers[IDENTIFIER_RIP].LineDownHandler)(
+ Binding->NicId);
+ }
+#else
+ for (i = 0; i < UPPER_DRIVER_COUNT; i++) {
+
+ if (Device->UpperDriverBound[i]) {
+ (*Device->UpperDrivers[i].LineDownHandler)(
+ Binding->NicId);
+ }
+ }
+#endif
+
+ if ((Device->SingleNetworkActive) &&
+ (Binding->DialOutAsync)) {
+
+ //
+ // Drop all entries in the database if rip is not bound.
+ //
+
+ if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ RipDropRemoteEntries();
+ }
+
+ Device->ActiveNetworkWan = FALSE;
+
+ //
+ // Find a queued line change and complete it.
+ //
+
+ if ((p = ExInterlockedRemoveHeadList(
+ &Device->LineChangeQueue,
+ &Device->Lock)) != NULL) {
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_LINE_CHANGE);
+
+ }
+
+ }
+
+ //
+ // Find a queued address notify and complete it.
+ //
+
+ if ((!Device->WanGlobalNetworkNumber) &&
+ ((p = ExInterlockedRemoveHeadList(
+ &Device->AddressNotifyQueue,
+ &Device->Lock)) != NULL)) {
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+ NdisBuffer = REQUEST_NDIS_BUFFER(Request);
+ NdisQueryBuffer (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength);
+
+ IpxAddressData = (PIPX_ADDRESS_DATA)(NwlinkAction->Data);
+
+ IpxAddressData->adapternum = Binding->NicId - 1;
+ *(UNALIGNED ULONG *)IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
+ IpxAddressData->wan = TRUE;
+ IpxAddressData->status = FALSE;
+ IpxAddressData->maxpkt = Binding->AnnouncedMaxDatagramSize; // BUGBUG: Use real?
+ IpxAddressData->linkspeed = Binding->MediumSpeed;
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_ADDRESS_NOTIFY);
+ }
+
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ break;
+
+ case NDIS_STATUS_WAN_FRAGMENT:
+
+ //
+ // No response needed, IPX is a datagram service.
+ //
+ // BUGBUG: What about telling Netbios/SPX?
+ //
+
+ break;
+
+ default:
+
+ break;
+
+ }
+
+#ifdef _PNP_POWER
+error_no_lock:
+ IpxDereferenceAdapter(Adapter);
+#endif
+
+} /* IpxStatus */
+
+
+VOID
+IpxStatusComplete(
+ IN NDIS_HANDLE NdisBindingContext
+ )
+{
+ UNREFERENCED_PARAMETER (NdisBindingContext);
+
+} /* IpxStatusComplete */
+
+
+
diff --git a/private/ntos/tdi/isnp/ipx/nwlnkipx.ini b/private/ntos/tdi/isnp/ipx/nwlnkipx.ini
new file mode 100644
index 000000000..416f0c6b7
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/nwlnkipx.ini
@@ -0,0 +1,191 @@
+\Registry\Machine\System\CurrentControlSet\Services\NwlnkIpx
+ Type = REG_DWORD 0x00000001
+ Start = REG_DWORD 0x00000003
+ ErrorControl = REG_DWORD 0x00000001
+ ImagePath = REG_EXPAND_SZ \SystemRoot\System32\drivers\nwlnkipx.sys
+ DisplayName = NWLINK2 IPX Protocol
+ Group = TDI
+ DependOnService = REG_MULTI_SZ
+ DependOnGroup = REG_MULTI_SZ "NDIS"
+ Linkage
+ Bind = REG_MULTI_SZ "\Device\Elnkii1"
+ Export = REG_MULTI_SZ "\Device\NwlnkIpx"
+ Route = REG_MULTI_SZ ""Elnkii" "Elnkii1""
+ Disabled
+ Bind = REG_MULTI_SZ
+ Export = REG_MULTI_SZ
+ Route = REG_MULTI_SZ
+ NetConfig
+ Elnkii1
+ NetworkNumber = REG_MULTI_SZ "0"
+ PktType = REG_MULTI_SZ "1"
+ BindSap = REG_DWORD 0x00008137
+ SourceRouting = REG_DWORD 0x00000001
+ SourceRouteDef = REG_DWORD 0x00000000
+ SourceRouteBcast = REG_DWORD 0x00000000
+ SourceRouteMcast = REG_DWORD 0x00000000
+ EnableFuncaddr = REG_DWORD 0x00000001
+ MaxPktSize = REG_DWORD 0x00000000
+ Netcard2
+ NetworkNumber = REG_MULTI_SZ "0"
+ PktType = REG_MULTI_SZ "1"
+ BindSap = REG_DWORD 0x00008137
+ SourceRouting = REG_DWORD 0x00000001
+ SourceRouteDef = REG_DWORD 0x00000000
+ SourceRouteBcast = REG_DWORD 0x00000000
+ SourceRouteMcast = REG_DWORD 0x00000000
+ EnableFuncaddr = REG_DWORD 0x00000001
+ MaxPktSize = REG_DWORD 0x00000000
+ Netcard3
+ NetworkNumber = REG_MULTI_SZ "0"
+ PktType = REG_MULTI_SZ "1"
+ BindSap = REG_DWORD 0x00008137
+ SourceRouting = REG_DWORD 0x00000001
+ SourceRouteDef = REG_DWORD 0x00000000
+ SourceRouteBcast = REG_DWORD 0x00000000
+ SourceRouteMcast = REG_DWORD 0x00000000
+ EnableFuncaddr = REG_DWORD 0x00000001
+ MaxPktSize = REG_DWORD 0x00000000
+ Netcard4
+ NetworkNumber = REG_MULTI_SZ "0"
+ PktType = REG_MULTI_SZ "1"
+ BindSap = REG_DWORD 0x00008137
+ SourceRouting = REG_DWORD 0x00000001
+ SourceRouteDef = REG_DWORD 0x00000000
+ SourceRouteBcast = REG_DWORD 0x00000000
+ SourceRouteMcast = REG_DWORD 0x00000000
+ EnableFuncaddr = REG_DWORD 0x00000001
+ MaxPktSize = REG_DWORD 0x00000000
+ Netcard5
+ NetworkNumber = REG_MULTI_SZ "0"
+ PktType = REG_MULTI_SZ "1"
+ BindSap = REG_DWORD 0x00008137
+ SourceRouting = REG_DWORD 0x00000001
+ SourceRouteDef = REG_DWORD 0x00000000
+ SourceRouteBcast = REG_DWORD 0x00000000
+ SourceRouteMcast = REG_DWORD 0x00000000
+ EnableFuncaddr = REG_DWORD 0x00000001
+ MaxPktSize = REG_DWORD 0x00000000
+ Parameters
+ DedicatedRouter = REG_DWORD 0x00000000
+ InitDatagrams = REG_DWORD 0x0000000a
+ MaxDatagrams = REG_DWORD 0x00000032
+ RipAgeTime = REG_DWORD 0x00000005
+ RipCount = REG_DWORD 0x00000005
+ RipTimeout = REG_DWORD 0x00000001
+ RipUsageTime = REG_DWORD 0x0000000f
+ SourceRouteUsageTime = REG_DWORD 0x0000000a
+ SocketUniqueness = REG_DWORD 0x00000008
+ VirtualNetworkNumber = REG_DWORD 0x00000000
+ VirtualNetworkOptional = REG_DWORD 0x00000001
+ Winsock
+ Mapping = REG_BINARY 0x00000c08
+ 0x00000100 0x00000003 0x00000006 0x00000002 0x000003e8 0x00000006 0x00000002 0x000003e9
+ 0x00000006 0x00000002 0x000003ea 0x00000006 0x00000002 0x000003eb 0x00000006 0x00000002
+ 0x000003ec 0x00000006 0x00000002 0x000003ed 0x00000006 0x00000002 0x000003ee 0x00000006
+ 0x00000002 0x000003ef 0x00000006 0x00000002 0x000003f0 0x00000006 0x00000002 0x000003f1
+ 0x00000006 0x00000002 0x000003f2 0x00000006 0x00000002 0x000003f3 0x00000006 0x00000002
+ 0x000003f4 0x00000006 0x00000002 0x000003f5 0x00000006 0x00000002 0x000003f6 0x00000006
+ 0x00000002 0x000003f7 0x00000006 0x00000002 0x000003f8 0x00000006 0x00000002 0x000003f9
+ 0x00000006 0x00000002 0x000003fa 0x00000006 0x00000002 0x000003fb 0x00000006 0x00000002
+ 0x000003fc 0x00000006 0x00000002 0x000003fd 0x00000006 0x00000002 0x000003fe 0x00000006
+ 0x00000002 0x000003ff 0x00000006 0x00000002 0x00000400 0x00000006 0x00000002 0x00000401
+ 0x00000006 0x00000002 0x00000402 0x00000006 0x00000002 0x00000403 0x00000006 0x00000002
+ 0x00000404 0x00000006 0x00000002 0x00000405 0x00000006 0x00000002 0x00000406 0x00000006
+ 0x00000002 0x00000407 0x00000006 0x00000002 0x00000408 0x00000006 0x00000002 0x00000409
+ 0x00000006 0x00000002 0x0000040a 0x00000006 0x00000002 0x0000040b 0x00000006 0x00000002
+ 0x0000040c 0x00000006 0x00000002 0x0000040d 0x00000006 0x00000002 0x0000040e 0x00000006
+ 0x00000002 0x0000040f 0x00000006 0x00000002 0x00000410 0x00000006 0x00000002 0x00000411
+ 0x00000006 0x00000002 0x00000412 0x00000006 0x00000002 0x00000413 0x00000006 0x00000002
+ 0x00000414 0x00000006 0x00000002 0x00000415 0x00000006 0x00000002 0x00000416 0x00000006
+ 0x00000002 0x00000417 0x00000006 0x00000002 0x00000418 0x00000006 0x00000002 0x00000419
+ 0x00000006 0x00000002 0x0000041a 0x00000006 0x00000002 0x0000041b 0x00000006 0x00000002
+ 0x0000041c 0x00000006 0x00000002 0x0000041d 0x00000006 0x00000002 0x0000041e 0x00000006
+ 0x00000002 0x0000041f 0x00000006 0x00000002 0x00000420 0x00000006 0x00000002 0x00000421
+ 0x00000006 0x00000002 0x00000422 0x00000006 0x00000002 0x00000423 0x00000006 0x00000002
+ 0x00000424 0x00000006 0x00000002 0x00000425 0x00000006 0x00000002 0x00000426 0x00000006
+ 0x00000002 0x00000427 0x00000006 0x00000002 0x00000428 0x00000006 0x00000002 0x00000429
+ 0x00000006 0x00000002 0x0000042a 0x00000006 0x00000002 0x0000042b 0x00000006 0x00000002
+ 0x0000042c 0x00000006 0x00000002 0x0000042d 0x00000006 0x00000002 0x0000042e 0x00000006
+ 0x00000002 0x0000042f 0x00000006 0x00000002 0x00000430 0x00000006 0x00000002 0x00000431
+ 0x00000006 0x00000002 0x00000432 0x00000006 0x00000002 0x00000433 0x00000006 0x00000002
+ 0x00000434 0x00000006 0x00000002 0x00000435 0x00000006 0x00000002 0x00000436 0x00000006
+ 0x00000002 0x00000437 0x00000006 0x00000002 0x00000438 0x00000006 0x00000002 0x00000439
+ 0x00000006 0x00000002 0x0000043a 0x00000006 0x00000002 0x0000043b 0x00000006 0x00000002
+ 0x0000043c 0x00000006 0x00000002 0x0000043d 0x00000006 0x00000002 0x0000043e 0x00000006
+ 0x00000002 0x0000043f 0x00000006 0x00000002 0x00000440 0x00000006 0x00000002 0x00000441
+ 0x00000006 0x00000002 0x00000442 0x00000006 0x00000002 0x00000443 0x00000006 0x00000002
+ 0x00000444 0x00000006 0x00000002 0x00000445 0x00000006 0x00000002 0x00000446 0x00000006
+ 0x00000002 0x00000447 0x00000006 0x00000002 0x00000448 0x00000006 0x00000002 0x00000449
+ 0x00000006 0x00000002 0x0000044a 0x00000006 0x00000002 0x0000044b 0x00000006 0x00000002
+ 0x0000044c 0x00000006 0x00000002 0x0000044d 0x00000006 0x00000002 0x0000044e 0x00000006
+ 0x00000002 0x0000044f 0x00000006 0x00000002 0x00000450 0x00000006 0x00000002 0x00000451
+ 0x00000006 0x00000002 0x00000452 0x00000006 0x00000002 0x00000453 0x00000006 0x00000002
+ 0x00000454 0x00000006 0x00000002 0x00000455 0x00000006 0x00000002 0x00000456 0x00000006
+ 0x00000002 0x00000457 0x00000006 0x00000002 0x00000458 0x00000006 0x00000002 0x00000459
+ 0x00000006 0x00000002 0x0000045a 0x00000006 0x00000002 0x0000045b 0x00000006 0x00000002
+ 0x0000045c 0x00000006 0x00000002 0x0000045d 0x00000006 0x00000002 0x0000045e 0x00000006
+ 0x00000002 0x0000045f 0x00000006 0x00000002 0x00000460 0x00000006 0x00000002 0x00000461
+ 0x00000006 0x00000002 0x00000462 0x00000006 0x00000002 0x00000463 0x00000006 0x00000002
+ 0x00000464 0x00000006 0x00000002 0x00000465 0x00000006 0x00000002 0x00000466 0x00000006
+ 0x00000002 0x00000467 0x00000006 0x00000002 0x00000468 0x00000006 0x00000002 0x00000469
+ 0x00000006 0x00000002 0x0000046a 0x00000006 0x00000002 0x0000046b 0x00000006 0x00000002
+ 0x0000046c 0x00000006 0x00000002 0x0000046d 0x00000006 0x00000002 0x0000046e 0x00000006
+ 0x00000002 0x0000046f 0x00000006 0x00000002 0x00000470 0x00000006 0x00000002 0x00000471
+ 0x00000006 0x00000002 0x00000472 0x00000006 0x00000002 0x00000473 0x00000006 0x00000002
+ 0x00000474 0x00000006 0x00000002 0x00000475 0x00000006 0x00000002 0x00000476 0x00000006
+ 0x00000002 0x00000477 0x00000006 0x00000002 0x00000478 0x00000006 0x00000002 0x00000479
+ 0x00000006 0x00000002 0x0000047a 0x00000006 0x00000002 0x0000047b 0x00000006 0x00000002
+ 0x0000047c 0x00000006 0x00000002 0x0000047d 0x00000006 0x00000002 0x0000047e 0x00000006
+ 0x00000002 0x0000047f 0x00000006 0x00000002 0x00000480 0x00000006 0x00000002 0x00000481
+ 0x00000006 0x00000002 0x00000482 0x00000006 0x00000002 0x00000483 0x00000006 0x00000002
+ 0x00000484 0x00000006 0x00000002 0x00000485 0x00000006 0x00000002 0x00000486 0x00000006
+ 0x00000002 0x00000487 0x00000006 0x00000002 0x00000488 0x00000006 0x00000002 0x00000489
+ 0x00000006 0x00000002 0x0000048a 0x00000006 0x00000002 0x0000048b 0x00000006 0x00000002
+ 0x0000048c 0x00000006 0x00000002 0x0000048d 0x00000006 0x00000002 0x0000048e 0x00000006
+ 0x00000002 0x0000048f 0x00000006 0x00000002 0x00000490 0x00000006 0x00000002 0x00000491
+ 0x00000006 0x00000002 0x00000492 0x00000006 0x00000002 0x00000493 0x00000006 0x00000002
+ 0x00000494 0x00000006 0x00000002 0x00000495 0x00000006 0x00000002 0x00000496 0x00000006
+ 0x00000002 0x00000497 0x00000006 0x00000002 0x00000498 0x00000006 0x00000002 0x00000499
+ 0x00000006 0x00000002 0x0000049a 0x00000006 0x00000002 0x0000049b 0x00000006 0x00000002
+ 0x0000049c 0x00000006 0x00000002 0x0000049d 0x00000006 0x00000002 0x0000049e 0x00000006
+ 0x00000002 0x0000049f 0x00000006 0x00000002 0x000004a0 0x00000006 0x00000002 0x000004a1
+ 0x00000006 0x00000002 0x000004a2 0x00000006 0x00000002 0x000004a3 0x00000006 0x00000002
+ 0x000004a4 0x00000006 0x00000002 0x000004a5 0x00000006 0x00000002 0x000004a6 0x00000006
+ 0x00000002 0x000004a7 0x00000006 0x00000002 0x000004a8 0x00000006 0x00000002 0x000004a9
+ 0x00000006 0x00000002 0x000004aa 0x00000006 0x00000002 0x000004ab 0x00000006 0x00000002
+ 0x000004ac 0x00000006 0x00000002 0x000004ad 0x00000006 0x00000002 0x000004ae 0x00000006
+ 0x00000002 0x000004af 0x00000006 0x00000002 0x000004b0 0x00000006 0x00000002 0x000004b1
+ 0x00000006 0x00000002 0x000004b2 0x00000006 0x00000002 0x000004b3 0x00000006 0x00000002
+ 0x000004b4 0x00000006 0x00000002 0x000004b5 0x00000006 0x00000002 0x000004b6 0x00000006
+ 0x00000002 0x000004b7 0x00000006 0x00000002 0x000004b8 0x00000006 0x00000002 0x000004b9
+ 0x00000006 0x00000002 0x000004ba 0x00000006 0x00000002 0x000004bb 0x00000006 0x00000002
+ 0x000004bc 0x00000006 0x00000002 0x000004bd 0x00000006 0x00000002 0x000004be 0x00000006
+ 0x00000002 0x000004bf 0x00000006 0x00000002 0x000004c0 0x00000006 0x00000002 0x000004c1
+ 0x00000006 0x00000002 0x000004c2 0x00000006 0x00000002 0x000004c3 0x00000006 0x00000002
+ 0x000004c4 0x00000006 0x00000002 0x000004c5 0x00000006 0x00000002 0x000004c6 0x00000006
+ 0x00000002 0x000004c7 0x00000006 0x00000002 0x000004c8 0x00000006 0x00000002 0x000004c9
+ 0x00000006 0x00000002 0x000004ca 0x00000006 0x00000002 0x000004cb 0x00000006 0x00000002
+ 0x000004cc 0x00000006 0x00000002 0x000004cd 0x00000006 0x00000002 0x000004ce 0x00000006
+ 0x00000002 0x000004cf 0x00000006 0x00000002 0x000004d0 0x00000006 0x00000002 0x000004d1
+ 0x00000006 0x00000002 0x000004d2 0x00000006 0x00000002 0x000004d3 0x00000006 0x00000002
+ 0x000004d4 0x00000006 0x00000002 0x000004d5 0x00000006 0x00000002 0x000004d6 0x00000006
+ 0x00000002 0x000004d7 0x00000006 0x00000002 0x000004d8 0x00000006 0x00000002 0x000004d9
+ 0x00000006 0x00000002 0x000004da 0x00000006 0x00000002 0x000004db 0x00000006 0x00000002
+ 0x000004dc 0x00000006 0x00000002 0x000004dd 0x00000006 0x00000002 0x000004de 0x00000006
+ 0x00000002 0x000004df 0x00000006 0x00000002 0x000004e0 0x00000006 0x00000002 0x000004e1
+ 0x00000006 0x00000002 0x000004e2 0x00000006 0x00000002 0x000004e3 0x00000006 0x00000002
+ 0x000004e4 0x00000006 0x00000002 0x000004e5 0x00000006 0x00000002 0x000004e6 0x00000006
+ 0x00000002 0x000004e7
+
+ HelperDllName = REG_EXPAND_SZ %SystemRoot%\system32\wshisn.dll
+ MinSockaddrLength = REG_DWORD 0x0000000e
+ MaxSockaddrLength = REG_DWORD 0x00000010
+ Performance
+ Library = Perfctrs.dll
+ Open = OpenNbfPerformanceData
+ Collect = CollectNbfPerformanceData
+ Close = CloseNbfPerformanceData
+\Registry\Machine\System\CurrentControlSet\Services\EventLog\System\NwlnkIpx
+ EventMessageFile = REG_EXPAND_SZ %SystemRoot%\System32\netevent.dll
+ TypesSupported = REG_DWORD 0x00000007
diff --git a/private/ntos/tdi/isnp/ipx/nwlnkipx.rc b/private/ntos/tdi/isnp/ipx/nwlnkipx.rc
new file mode 100644
index 000000000..0f437a15d
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/nwlnkipx.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "NWLINK2 IPX Protocol Driver"
+#define VER_INTERNALNAME_STR "nwlnkipx.sys"
+#define VER_ORIGINALFILENAME_STR "nwlnkipx.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/tdi/isnp/ipx/packet.c b/private/ntos/tdi/isnp/ipx/packet.c
new file mode 100644
index 000000000..f70154b03
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/packet.c
@@ -0,0 +1,1560 @@
+/*++
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ packet.c
+
+Abstract:
+
+ This module contains code that implements the SEND_PACKET and
+ RECEIVE_PACKET objects, which describe NDIS packets used
+ by the transport.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+NTSTATUS
+IpxInitializeSendPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet,
+ IN PUCHAR Header
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a send packet by chaining the
+ buffer for the header on it.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to initialize.
+
+ Header - Points to storage for the header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ NTSTATUS Status;
+ PNDIS_BUFFER NdisMacBuffer;
+ PNDIS_BUFFER NdisIpxBuffer;
+ PIPX_SEND_RESERVED Reserved;
+
+ IpxAllocateSendPacket (Device, Packet, &Status);
+
+ if (Status != STATUS_SUCCESS) {
+ // ERROR LOG
+ return Status;
+ }
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisMacBuffer,
+ Device->NdisBufferPoolHandle,
+ Header,
+ MAC_HEADER_SIZE);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxFreeSendPacket (Device, Packet);
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisIpxBuffer,
+ Device->NdisBufferPoolHandle,
+ Header + MAC_HEADER_SIZE,
+ IPX_HEADER_SIZE + RIP_PACKET_SIZE);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxFreeSendPacket (Device, Packet);
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NdisChainBufferAtFront (PACKET(Packet), NdisMacBuffer);
+ NdisChainBufferAtBack (PACKET(Packet), NdisIpxBuffer);
+
+ //
+ // This flag optimizes the virtual to physical address X-ln
+ // in the MAC drivers on x86
+ //
+ NdisMacBuffer->MdlFlags|=MDL_NETWORK_HEADER;
+ NdisIpxBuffer->MdlFlags|=MDL_NETWORK_HEADER;
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->Identifier = IDENTIFIER_IPX;
+ Reserved->SendInProgress = FALSE;
+ Reserved->Header = Header;
+ Reserved->HeaderBuffer = NdisMacBuffer;
+ Reserved->PaddingBuffer = NULL;
+#if BACK_FILL
+ Reserved->BackFill = FALSE;
+#endif
+
+ ExInterlockedInsertHeadList(
+ &Device->GlobalSendPacketList,
+ &Reserved->GlobalLinkage,
+ &Device->Lock);
+
+ return STATUS_SUCCESS;
+
+} /* IpxInitializeSendPacket */
+
+#if BACK_FILL
+NTSTATUS
+IpxInitializeBackFillPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet,
+ IN PUCHAR Header
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a send packet by chaining the
+ buffer for the header on it.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to initialize.
+
+ Header - Points to storage for the header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ NTSTATUS Status;
+ PNDIS_BUFFER NdisMacBuffer;
+ PNDIS_BUFFER NdisIpxBuffer;
+ PIPX_SEND_RESERVED Reserved;
+
+
+ IPX_DEBUG (PACKET, ("Initializing backfill packet\n"));
+ IpxAllocateSendPacket (Device, Packet, &Status);
+
+ if (Status != STATUS_SUCCESS) {
+ // ERROR LOG
+ return Status;
+ }
+
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->Identifier = IDENTIFIER_IPX;
+ Reserved->SendInProgress = FALSE;
+ Reserved->Header = NULL;
+ Reserved->HeaderBuffer = NULL;
+ Reserved->PaddingBuffer = NULL;
+ Reserved->BackFill = TRUE;
+
+ ExInterlockedInsertHeadList(
+ &Device->GlobalBackFillPacketList,
+ &Reserved->GlobalLinkage,
+ &Device->Lock);
+
+ IPX_DEBUG (PACKET, ("Initializing backfill packet Done\n"));
+ return STATUS_SUCCESS;
+
+} /* IpxInitializeBackFillPacket */
+#endif
+
+
+NTSTATUS
+IpxInitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PIPX_RECEIVE_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to initialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ PIPX_RECEIVE_RESERVED Reserved;
+
+ IpxAllocateReceivePacket (Device, Packet, &Status);
+
+ if (Status != STATUS_SUCCESS) {
+ // ERROR LOG
+ return Status;
+ }
+
+ Reserved = RECEIVE_RESERVED(Packet);
+ Reserved->Identifier = IDENTIFIER_IPX;
+ Reserved->TransferInProgress = FALSE;
+ Reserved->SingleRequest = NULL;
+ Reserved->ReceiveBuffer = NULL;
+ InitializeListHead (&Reserved->Requests);
+
+ ExInterlockedInsertHeadList(
+ &Device->GlobalReceivePacketList,
+ &Reserved->GlobalLinkage,
+ &Device->Lock);
+
+ return STATUS_SUCCESS;
+
+} /* IpxInitializeReceivePacket */
+
+
+NTSTATUS
+IpxInitializeReceiveBuffer(
+ IN PADAPTER Adapter,
+ IN PIPX_RECEIVE_BUFFER ReceiveBuffer,
+ IN PUCHAR DataBuffer,
+ IN ULONG DataBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive buffer by allocating
+ an NDIS_BUFFER to describe the data buffer.
+
+Arguments:
+
+ Adapter - The adapter.
+
+ ReceiveBuffer - The receive buffer to initialize.
+
+ DataBuffer - The data buffer.
+
+ DataBufferLength - The length of the data buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ PNDIS_BUFFER NdisBuffer;
+ PDEVICE Device = Adapter->Device;
+
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Device->NdisBufferPoolHandle,
+ DataBuffer,
+ DataBufferLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ ReceiveBuffer->NdisBuffer = NdisBuffer;
+ ReceiveBuffer->Data = DataBuffer;
+ ReceiveBuffer->DataLength = 0;
+
+ ExInterlockedInsertHeadList(
+ &Device->GlobalReceiveBufferList,
+ &ReceiveBuffer->GlobalLinkage,
+ &Device->Lock);
+
+ return STATUS_SUCCESS;
+
+} /* IpxInitializeReceiveBuffer */
+
+
+NTSTATUS
+IpxInitializePaddingBuffer(
+ IN PDEVICE Device,
+ IN PIPX_PADDING_BUFFER PaddingBuffer,
+ IN ULONG DataBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a padding buffer by allocating
+ an NDIS_BUFFER to describe the data buffer.
+
+Arguments:
+
+ Adapter - The adapter.
+
+ PaddingBuffer - The receive buffer to initialize.
+
+ DataBufferLength - The length of the data buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ PNDIS_BUFFER NdisBuffer;
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Device->NdisBufferPoolHandle,
+ PaddingBuffer->Data,
+ DataBufferLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NDIS_BUFFER_LINKAGE(NdisBuffer) = (PNDIS_BUFFER)NULL;
+ PaddingBuffer->NdisBuffer = NdisBuffer;
+ PaddingBuffer->DataLength = DataBufferLength;
+ RtlZeroMemory (PaddingBuffer->Data, DataBufferLength);
+
+ return STATUS_SUCCESS;
+
+} /* IpxInitializePaddingBuffer */
+
+
+VOID
+IpxDeinitializeSendPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a send packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to deinitialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_BUFFER NdisBuffer;
+ PNDIS_BUFFER NdisIpxBuffer;
+ PIPX_SEND_RESERVED Reserved;
+ CTELockHandle LockHandle;
+
+
+ Reserved = SEND_RESERVED(Packet);
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Reserved->GlobalLinkage);
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ //
+ // Free the packet in a slightly unconventional way; this
+ // allows us to not have to NULL out HeaderBuffer's linkage
+ // field during normal operations when we put it back in
+ // the free pool.
+ //
+
+ NdisBuffer = Reserved->HeaderBuffer;
+ NdisIpxBuffer = NDIS_BUFFER_LINKAGE(NdisBuffer);
+ NDIS_BUFFER_LINKAGE (NdisBuffer) = NULL;
+ NDIS_BUFFER_LINKAGE (NdisIpxBuffer) = NULL;
+
+#if 0
+ NdisAdjustBufferLength (NdisBuffer, PACKET_HEADER_SIZE);
+#endif
+ NdisAdjustBufferLength (NdisBuffer, MAC_HEADER_SIZE);
+ NdisAdjustBufferLength (NdisIpxBuffer, IPX_HEADER_SIZE + RIP_PACKET_SIZE);
+
+ NdisFreeBuffer (NdisBuffer);
+ NdisFreeBuffer (NdisIpxBuffer);
+
+ NdisReinitializePacket (PACKET(Packet));
+ IpxFreeSendPacket (Device, Packet);
+
+} /* IpxDeinitializeSendPacket */
+
+#if BACK_FILL
+VOID
+IpxDeinitializeBackFillPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a back fill packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to deinitialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_BUFFER NdisBuffer;
+ PNDIS_BUFFER NdisIpxBuffer;
+ PIPX_SEND_RESERVED Reserved;
+ CTELockHandle LockHandle;
+
+ IPX_DEBUG (PACKET, ("DeInitializing backfill packet\n"));
+
+ Reserved = SEND_RESERVED(Packet);
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Reserved->GlobalLinkage);
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+
+
+ NdisReinitializePacket (PACKET(Packet));
+ IpxFreeSendPacket (Device, Packet);
+ IPX_DEBUG (PACKET, ("DeInitializing backfill packet Done\n"));
+
+
+} /* IpxDeinitializeBackFillPacket */
+#endif
+
+
+VOID
+IpxDeinitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PIPX_RECEIVE_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to initialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PIPX_RECEIVE_RESERVED Reserved;
+ CTELockHandle LockHandle;
+
+ Reserved = RECEIVE_RESERVED(Packet);
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Reserved->GlobalLinkage);
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ IpxFreeReceivePacket (Device, Packet);
+
+} /* IpxDeinitializeReceivePacket */
+
+
+VOID
+IpxDeinitializeReceiveBuffer(
+ IN PADAPTER Adapter,
+ IN PIPX_RECEIVE_BUFFER ReceiveBuffer,
+ IN ULONG DataBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a receive buffer.
+
+Arguments:
+
+ Device - The device.
+
+ ReceiveBuffer - The receive buffer.
+
+ DataBufferLength - The allocated length of the receive buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PDEVICE Device = Adapter->Device;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ RemoveEntryList (&ReceiveBuffer->GlobalLinkage);
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ NdisAdjustBufferLength (ReceiveBuffer->NdisBuffer, DataBufferLength);
+ NdisFreeBuffer (ReceiveBuffer->NdisBuffer);
+
+} /* IpxDeinitializeReceiveBuffer */
+
+
+VOID
+IpxDeinitializePaddingBuffer(
+ IN PDEVICE Device,
+ IN PIPX_PADDING_BUFFER PaddingBuffer,
+ IN ULONG DataBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a padding buffer.
+
+Arguments:
+
+ Device - The device.
+
+ PaddingBuffer - The padding buffer.
+
+ DataBufferLength - The allocated length of the padding buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NdisAdjustBufferLength (PaddingBuffer->NdisBuffer, DataBufferLength);
+ NdisFreeBuffer (PaddingBuffer->NdisBuffer);
+
+} /* IpxDeinitializePaddingBuffer */
+
+
+
+#ifdef IPX_OWN_PACKETS
+VOID
+IpxAllocateSendPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_POOL SendPool;
+ UINT SendPoolSize;
+ UINT PacketNum;
+ PIPX_SEND_PACKET Packet;
+ PIPX_SEND_RESERVED Reserved;
+ PUCHAR Header;
+ CTELockHandle LockHandle;
+
+
+ SendPoolSize = FIELD_OFFSET (IPX_SEND_POOL, Packets[0]) +
+ (sizeof(IPX_SEND_PACKET) * Device->InitDatagrams) +
+ (PACKET_HEADER_SIZE * Device->InitDatagrams);
+
+
+ SendPool = (PIPX_SEND_POOL)IpxAllocateMemory (SendPoolSize, MEMORY_PACKET, "SendPool");
+ if (SendPool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate send pool memory\n"));
+ return;
+ }
+
+
+ IPX_DEBUG (PACKET, ("Initializing send pool %lx, %d packets\n",
+ SendPool, Device->InitDatagrams));
+
+ Header = (PUCHAR)(&SendPool->Packets[Device->InitDatagrams]);
+
+ for (PacketNum = 0; PacketNum < Device->InitDatagrams; PacketNum++) {
+
+ Packet = &SendPool->Packets[PacketNum];
+
+ if (IpxInitializeSendPacket (Device, Packet, Header) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = SendPool;
+#endif
+
+ Header += PACKET_HEADER_SIZE;
+
+ }
+
+ SendPool->PacketCount = PacketNum;
+ SendPool->PacketFree = PacketNum;
+
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (PacketNum = 0; PacketNum < SendPool->PacketCount; PacketNum++) {
+
+ Packet = &SendPool->Packets[PacketNum];
+ Reserved = SEND_RESERVED(Packet);
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+
+ }
+
+ InsertTailList (&Device->SendPoolList, &SendPool->Linkage);
+
+ Device->AllocatedDatagrams += SendPool->PacketCount;
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+} /* IpxAllocateSendPool */
+
+#if BACK_FILL
+
+VOID
+IpxAllocateBackFillPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_POOL SendPool;
+ UINT SendPoolSize;
+ UINT PacketNum;
+ PIPX_SEND_PACKET Packet;
+ PIPX_SEND_RESERVED Reserved;
+ PUCHAR Header;
+ CTELockHandle LockHandle;
+
+ PIPX_SEND_POOL BackFillPool;
+ UINT BackFillPoolSize;
+
+ IPX_DEBUG (PACKET, ("Allocating backfill pool\n"));
+
+
+ BackFillPoolSize = FIELD_OFFSET (IPX_SEND_POOL, Packets[0]) +
+ (sizeof(IPX_SEND_PACKET) * Device->InitDatagrams);
+
+
+ // Allocate pool for back fillable packets
+
+ BackFillPool = (PIPX_SEND_POOL)IpxAllocateMemory (BackFillPoolSize, MEMORY_PACKET, "BafiPool");
+
+ if (BackFillPool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate BackFill pool memory\n"));
+ return;
+ }
+
+
+
+
+
+ for (PacketNum = 0; PacketNum < Device->InitDatagrams; PacketNum++) {
+
+ Packet = &BackFillPool->Packets[PacketNum];
+
+ if (IpxInitializeBackFillPacket (Device, Packet, NULL) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = BackFillPool;
+#endif
+
+
+ }
+
+ BackFillPool->PacketCount = PacketNum;
+ BackFillPool->PacketFree = PacketNum;
+
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (PacketNum = 0; PacketNum < BackFillPool->PacketCount; PacketNum++) {
+
+ Packet = &BackFillPool->Packets[PacketNum];
+ Reserved = SEND_RESERVED(Packet);
+ IPX_PUSH_ENTRY_LIST (&Device->BackFillPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+
+ }
+
+ InsertTailList (&Device->BackFillPoolList, &BackFillPool->Linkage);
+
+
+ IPX_DEBUG (PACKET, ("Allocation of backfill pool done\n"));
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+} /* IpxAllocateBackFillPool */
+
+#endif
+
+
+VOID
+IpxAllocateReceivePool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds receive packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_RECEIVE_POOL ReceivePool;
+ UINT ReceivePoolSize;
+ UINT PacketNum;
+ PIPX_RECEIVE_PACKET Packet;
+ PIPX_RECEIVE_RESERVED Reserved;
+ CTELockHandle LockHandle;
+
+ ReceivePoolSize = FIELD_OFFSET (IPX_RECEIVE_POOL, Packets[0]) +
+ (sizeof(IPX_RECEIVE_PACKET) * Device->InitReceivePackets);
+
+ ReceivePool = (PIPX_RECEIVE_POOL)IpxAllocateMemory (ReceivePoolSize, MEMORY_PACKET, "ReceivePool");
+ if (ReceivePool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate receive pool memory\n"));
+ return;
+ }
+
+ IPX_DEBUG (PACKET, ("Initializing receive pool %lx, %d packets\n",
+ ReceivePool, Device->InitReceivePackets));
+
+ for (PacketNum = 0; PacketNum < Device->InitReceivePackets; PacketNum++) {
+
+ Packet = &ReceivePool->Packets[PacketNum];
+
+ if (IpxInitializeReceivePacket (Device, Packet) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = RECEIVE_RESERVED(Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = ReceivePool;
+#endif
+
+ }
+
+ ReceivePool->PacketCount = PacketNum;
+ ReceivePool->PacketFree = PacketNum;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (PacketNum = 0; PacketNum < ReceivePool->PacketCount; PacketNum++) {
+
+ Packet = &ReceivePool->Packets[PacketNum];
+ Reserved = RECEIVE_RESERVED(Packet);
+ IPX_PUSH_ENTRY_LIST (&Device->ReceivePacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+
+ }
+
+ InsertTailList (&Device->ReceivePoolList, &ReceivePool->Linkage);
+
+ Device->AllocatedReceivePackets += ReceivePool->PacketCount;
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+} /* IpxAllocateReceivePool */
+
+
+#else // IPX_OWN_PACKETS
+VOID
+IpxAllocateSendPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_POOL SendPool;
+ UINT HeaderSize;
+ UINT PacketNum;
+ IPX_SEND_PACKET Packet;
+ PIPX_SEND_RESERVED Reserved;
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ CTELockHandle LockHandle;
+
+ SendPool = (PIPX_SEND_POOL)IpxAllocateMemory (sizeof(IPX_SEND_POOL), MEMORY_PACKET, "SendPool");
+
+ if (SendPool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate send pool memory\n"));
+ return;
+ }
+
+ HeaderSize = PACKET_HEADER_SIZE * Device->InitDatagrams;
+
+ Header = (PUCHAR)IpxAllocateMemory (HeaderSize, MEMORY_PACKET, "SendPool");
+
+ if (Header == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate header memory\n"));
+ return;
+ }
+
+ NdisAllocatePacketPool(&Status, &SendPool->PoolHandle, Device->InitDatagrams, sizeof(IPX_SEND_RESERVED));
+
+ if (Status == NDIS_STATUS_RESOURCES) {
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis pool memory\n"));
+ return;
+ }
+
+ Device->MemoryUsage += (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]) +
+ Device->InitDatagrams * (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_SEND_RESERVED)));
+
+ IPX_DEBUG (PACKET, ("Initializing send pool %lx, %d packets\n",
+ SendPool, Device->InitDatagrams));
+
+ SendPool->Header = Header;
+
+ for (PacketNum = 0; PacketNum < Device->InitDatagrams; PacketNum++) {
+
+ NdisAllocatePacket(&Status, &PACKET(&Packet), SendPool->PoolHandle);
+
+ if (IpxInitializeSendPacket (Device, &Packet, Header) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = SEND_RESERVED(&Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = SendPool;
+#endif
+
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+
+ Header += PACKET_HEADER_SIZE;
+
+ }
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ Device->AllocatedDatagrams += PacketNum;
+ InsertTailList (&Device->SendPoolList, &SendPool->Linkage);
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+} /* IpxAllocateSendPool */
+
+
+#if BACK_FILL
+
+VOID
+IpxAllocateBackFillPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT PacketNum;
+ IPX_SEND_PACKET Packet;
+ PIPX_SEND_RESERVED Reserved;
+ CTELockHandle LockHandle;
+ PIPX_SEND_POOL BackFillPool;
+ NDIS_STATUS Status;
+
+ IPX_DEBUG (PACKET, ("Allocating backfill pool\n"));
+
+ // Allocate pool for back fillable packets
+
+ BackFillPool = (PIPX_SEND_POOL)IpxAllocateMemory (sizeof(IPX_SEND_POOL), MEMORY_PACKET, "BafiPool");
+
+ if (BackFillPool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate backfill pool memory\n"));
+ return;
+ }
+
+ NdisAllocatePacketPool(&Status, &BackFillPool->PoolHandle, Device->InitDatagrams, sizeof(IPX_SEND_RESERVED));
+
+ if (Status == NDIS_STATUS_RESOURCES) {
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis pool memory\n"));
+ return;
+ }
+
+ Device->MemoryUsage += (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]) +
+ Device->InitDatagrams * (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_SEND_RESERVED)));
+
+ for (PacketNum = 0; PacketNum < Device->InitDatagrams; PacketNum++) {
+
+ NdisAllocatePacket(&Status, &PACKET(&Packet), BackFillPool->PoolHandle);
+
+ if (IpxInitializeBackFillPacket (Device, &Packet, NULL) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = SEND_RESERVED(&Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = BackFillPool;
+#endif
+
+ IPX_PUSH_ENTRY_LIST (&Device->BackFillPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+ }
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ InsertTailList (&Device->BackFillPoolList, &BackFillPool->Linkage);
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+} /* IpxAllocateBackFillPool */
+
+#endif
+
+
+VOID
+IpxAllocateReceivePool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds receive packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_RECEIVE_POOL ReceivePool;
+ UINT PacketNum;
+ IPX_RECEIVE_PACKET Packet;
+ PIPX_RECEIVE_RESERVED Reserved;
+ CTELockHandle LockHandle;
+ NDIS_STATUS Status;
+
+ ReceivePool = (PIPX_SEND_POOL)IpxAllocateMemory (sizeof(IPX_RECEIVE_POOL), MEMORY_PACKET, "ReceivePool");
+
+ if (ReceivePool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate receive pool memory\n"));
+ return;
+ }
+
+ NdisAllocatePacketPool(&Status, &ReceivePool->PoolHandle, Device->InitDatagrams, sizeof(IPX_SEND_RESERVED));
+
+ if (Status == NDIS_STATUS_RESOURCES) {
+ IPX_DEBUG (PACKET, ("Could not allocate receive pool memory\n"));
+ return;
+ }
+
+ IPX_DEBUG (PACKET, ("Initializing receive pool %lx, %d packets\n",
+ ReceivePool, Device->InitReceivePackets));
+
+ Device->MemoryUsage += (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]) +
+ Device->InitReceivePackets * (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_RECEIVE_RESERVED)));
+
+ for (PacketNum = 0; PacketNum < Device->InitReceivePackets; PacketNum++) {
+
+ NdisAllocatePacket(&Status, &PACKET(&Packet), ReceivePool->PoolHandle);
+
+ if (IpxInitializeReceivePacket (Device, &Packet) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = RECEIVE_RESERVED(&Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = ReceivePool;
+#endif
+
+ IPX_PUSH_ENTRY_LIST (&Device->ReceivePacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+
+ }
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ Device->AllocatedReceivePackets += PacketNum;
+
+ InsertTailList (&Device->ReceivePoolList, &ReceivePool->Linkage);
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+} /* IpxAllocateReceivePool */
+#endif // IPX_OWN_PACKETS
+
+VOID
+IpxAllocateReceiveBufferPool(
+ IN PADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds receive buffers to the pool for this adapter.
+
+Arguments:
+
+ Adapter - The adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_RECEIVE_BUFFER ReceiveBuffer;
+ UINT ReceiveBufferPoolSize;
+ UINT BufferNum;
+ PIPX_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ PDEVICE Device = Adapter->Device;
+ UINT DataLength;
+ PUCHAR Data;
+ CTELockHandle LockHandle;
+
+ DataLength = Adapter->MaxReceivePacketSize;
+
+ ReceiveBufferPoolSize = FIELD_OFFSET (IPX_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(IPX_RECEIVE_BUFFER) * Device->InitReceiveBuffers) +
+ (DataLength * Device->InitReceiveBuffers);
+
+ ReceiveBufferPool = (PIPX_RECEIVE_BUFFER_POOL)IpxAllocateMemory (ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+ if (ReceiveBufferPool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate receive buffer pool memory\n"));
+ return;
+ }
+
+ IPX_DEBUG (PACKET, ("Init recv buffer pool %lx, %d buffers, data %d\n",
+ ReceiveBufferPool, Device->InitReceiveBuffers, DataLength));
+
+ Data = (PUCHAR)(&ReceiveBufferPool->Buffers[Device->InitReceiveBuffers]);
+
+
+ for (BufferNum = 0; BufferNum < Device->InitReceiveBuffers; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+
+ if (IpxInitializeReceiveBuffer (Adapter, ReceiveBuffer, Data, DataLength) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize buffer %lx\n", ReceiveBuffer));
+ break;
+ }
+
+#ifdef IPX_TRACK_POOL
+ ReceiveBuffer->Pool = ReceiveBufferPool;
+#endif
+
+ Data += DataLength;
+
+ }
+
+ ReceiveBufferPool->BufferCount = BufferNum;
+ ReceiveBufferPool->BufferFree = BufferNum;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (BufferNum = 0; BufferNum < ReceiveBufferPool->BufferCount; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+ IPX_PUSH_ENTRY_LIST (&Adapter->ReceiveBufferList, &ReceiveBuffer->PoolLinkage, &Device->SListsLock);
+
+ }
+
+ InsertTailList (&Adapter->ReceiveBufferPoolList, &ReceiveBufferPool->Linkage);
+
+ Adapter->AllocatedReceiveBuffers += ReceiveBufferPool->BufferCount;
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+} /* IpxAllocateReceiveBufferPool */
+
+
+PSINGLE_LIST_ENTRY
+IpxPopSendPacket(
+ PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool.
+ If there are no packets in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedDatagrams < Device->MaxDatagrams) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ IpxAllocateSendPool (Device);
+ s = IPX_POP_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Device->SListsLock);
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* IpxPopSendPacket */
+
+#if BACK_FILL
+
+PSINGLE_LIST_ENTRY
+IpxPopBackFillPacket(
+ PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool.
+ If there are no packets in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+
+ IPX_DEBUG (PACKET, ("Popping backfill packet\n"));
+
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BackFillPacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedDatagrams < Device->MaxDatagrams) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ IpxAllocateBackFillPool (Device);
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BackFillPacketList,
+ &Device->SListsLock);
+
+
+ IPX_DEBUG (PACKET, ("Popping backfill packet done\n"));
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* IpxPopBackFillPacket */
+#endif //BackFill
+
+
+PSINGLE_LIST_ENTRY
+IpxPopReceivePacket(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool.
+ If there are no packets in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->ReceivePacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedReceivePackets < Device->MaxReceivePackets) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ IpxAllocateReceivePool (Device);
+ s = IPX_POP_ENTRY_LIST(
+ &Device->ReceivePacketList,
+ &Device->SListsLock);
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* IpxPopReceivePacket */
+
+
+PSINGLE_LIST_ENTRY
+IpxPopReceiveBuffer(
+ IN PADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a receive buffer from the adapter's pool.
+ If there are no buffers in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Adapter - Pointer to our adapter to charge the buffer to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated receive buffer.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PDEVICE Device = Adapter->Device;
+
+ s = IPX_POP_ENTRY_LIST(
+ &Adapter->ReceiveBufferList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No buffer in the pool, see if we can allocate more.
+ //
+
+ if (Adapter->AllocatedReceiveBuffers < Device->MaxReceiveBuffers) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ IpxAllocateReceiveBufferPool (Adapter);
+ s = IPX_POP_ENTRY_LIST(
+ &Adapter->ReceiveBufferList,
+ &Device->SListsLock);
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* IpxPopReceiveBuffer */
+
+
+PIPX_PADDING_BUFFER
+IpxAllocatePaddingBuffer(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a padding buffer for use by all devices.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the allocated padding buffer.
+
+--*/
+
+{
+ PIPX_PADDING_BUFFER PaddingBuffer;
+ ULONG PaddingBufferSize;
+
+ //
+ // We are assuming that we can use 1 global padding buffer for ALL
+ // transmits! We must therefore test to make sure that EthernetExtraPadding
+ // is not greater than 1. Otherwise, we must assume that the extra padding
+ // is being used for something and we therefore cannot share across all
+ // transmit requests.
+ //
+
+ //
+ // We cannot support more than 1 byte padding space, since we allocate only
+ // one buffer for all transmit requests.
+ //
+
+ if ( Device->EthernetExtraPadding > 1 ) {
+ IPX_DEBUG (PACKET, ("Padding buffer cannot be more than 1 byte\n"));
+ DbgBreakPoint();
+ }
+
+ //
+ // Allocate a padding buffer if possible.
+ //
+
+ PaddingBufferSize = FIELD_OFFSET (IPX_PADDING_BUFFER, Data[0]) + Device->EthernetExtraPadding;
+
+ PaddingBuffer = IpxAllocateMemory (PaddingBufferSize, MEMORY_PACKET, "PaddingBuffer");
+
+ if (PaddingBuffer != NULL) {
+
+ if (IpxInitializePaddingBuffer (Device, PaddingBuffer, Device->EthernetExtraPadding) !=
+ STATUS_SUCCESS) {
+ IpxFreeMemory (PaddingBuffer, PaddingBufferSize, MEMORY_PACKET, "Padding Buffer");
+ } else {
+ IPX_DEBUG (PACKET, ("Allocate padding buffer %lx\n", PaddingBuffer));
+ return PaddingBuffer;
+ }
+ }
+
+ return NULL;
+
+} /* IpxAllocatePaddingBuffer */
+
+
+VOID
+IpxFreePaddingBuffer(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deallocates the padding buffer.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG PaddingBufferSize;
+
+ if ( IpxPaddingBuffer == (PIPX_PADDING_BUFFER)NULL ) {
+ return;
+ }
+
+ PaddingBufferSize = FIELD_OFFSET (IPX_PADDING_BUFFER, Data[0]) + Device->EthernetExtraPadding;
+ IpxFreeMemory( IpxPaddingBuffer, PaddingBufferSize, MEMORY_PACKET, "Padding Buffer" );
+ IpxPaddingBuffer = (PIPX_PADDING_BUFFER)NULL;
+
+} /* IpxFreePaddingBuffer */
+
diff --git a/private/ntos/tdi/isnp/ipx/precomp.h b/private/ntos/tdi/isnp/ipx/precomp.h
new file mode 100644
index 000000000..818629e5e
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/precomp.h
@@ -0,0 +1,44 @@
+/*++
+
+Copyright (c) 1993-1995 Microsoft Corporation
+
+Module Name:
+
+ precomp.h
+
+Abstract:
+
+ Precompilation header file.
+
+Author:
+
+ Adam Barr (adamba) 08-Sep-1993
+
+Revision History:
+
+--*/
+
+
+#define ISN_NT 1
+
+//
+// These are needed for CTE
+//
+
+#if DBG
+#define DEBUG 1
+#endif
+
+#define NT 1
+
+#include <ntos.h>
+#include <tdikrnl.h>
+#include <ndis.h>
+#include <cxport.h>
+#include <bind.h>
+#include "isnipx.h"
+#include "config.h"
+#include "mac.h"
+#include "ipxtypes.h"
+#include "ipxprocs.h"
+#include <wsnwlink.h>
diff --git a/private/ntos/tdi/isnp/ipx/query.c b/private/ntos/tdi/isnp/ipx/query.c
new file mode 100644
index 000000000..28b38df5c
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/query.c
@@ -0,0 +1,297 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ query.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiQueryInformation
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Useful macro to obtain the total length of an MDL chain.
+//
+
+#define IpxGetMdlChainLength(Mdl, Length) { \
+ PMDL _Mdl = (Mdl); \
+ *(Length) = 0; \
+ while (_Mdl) { \
+ *(Length) += MmGetMdlByteCount(_Mdl); \
+ _Mdl = _Mdl->Next; \
+ } \
+}
+
+
+
+NTSTATUS
+IpxTdiQueryInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiQueryInformation request for the transport
+ provider.
+
+Arguments:
+
+ Request - the request for the operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTDI_REQUEST_KERNEL_QUERY_INFORMATION query;
+ PADDRESS_FILE AddressFile;
+ ULONG ElementSize, TransportAddressSize;
+ PTRANSPORT_ADDRESS TransportAddress;
+ TA_ADDRESS UNALIGNED * CurAddress;
+ PBINDING Binding;
+ union {
+ struct {
+ ULONG ActivityCount;
+ TA_IPX_ADDRESS IpxAddress;
+ } AddressInfo;
+ TDI_DATAGRAM_INFO DatagramInfo;
+ TDI_ADDRESS_IPX IpxAddress;
+ } TempBuffer;
+ UINT i;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ //
+ // what type of status do we want?
+ //
+
+ query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)REQUEST_PARAMETERS(Request);
+
+ switch (query->QueryType) {
+
+ case TDI_QUERY_ADDRESS_INFO:
+
+ //
+ // The caller wants the exact address value.
+ //
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ status = IpxVerifyAddressFile (AddressFile);
+
+ if (status == STATUS_SUCCESS) {
+
+ TempBuffer.AddressInfo.ActivityCount = 0;
+
+ IpxBuildTdiAddress(
+ &TempBuffer.AddressInfo.IpxAddress,
+ Device->SourceAddress.NetworkAddress,
+ Device->SourceAddress.NodeAddress,
+ AddressFile->Address->Socket);
+
+ status = TdiCopyBufferToMdl(
+ &TempBuffer.AddressInfo,
+ 0,
+ sizeof(TempBuffer.AddressInfo),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ }
+
+ break;
+
+ case TDI_QUERY_PROVIDER_INFO:
+
+ status = TdiCopyBufferToMdl (
+ &(Device->Information),
+ 0,
+ sizeof (TDI_PROVIDER_INFO),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_PROVIDER_STATISTICS:
+
+ status = TdiCopyBufferToMdl (
+ &Device->Statistics,
+ 0,
+ FIELD_OFFSET (TDI_PROVIDER_STATISTICS, ResourceStats[0]),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_DATAGRAM_INFO:
+
+ TempBuffer.DatagramInfo.MaximumDatagramBytes = 0;
+ TempBuffer.DatagramInfo.MaximumDatagramCount = 0;
+
+ status = TdiCopyBufferToMdl (
+ &TempBuffer.DatagramInfo,
+ 0,
+ sizeof(TempBuffer.DatagramInfo),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_DATA_LINK_ADDRESS:
+ case TDI_QUERY_NETWORK_ADDRESS:
+
+ if (query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
+ ElementSize = (2 * sizeof(USHORT)) + 6;
+ } else {
+ ElementSize = (2 * sizeof(USHORT)) + sizeof(TDI_ADDRESS_IPX);
+ }
+
+ TransportAddress = IpxAllocateMemory(sizeof(int) + (ElementSize * MIN (Device->MaxBindings, Device->ValidBindings)), MEMORY_QUERY, "NetworkAddress");
+
+ if (TransportAddress == NULL) {
+
+ status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ TransportAddress->TAAddressCount = 0;
+ TransportAddressSize = sizeof(int);
+ CurAddress = (TA_ADDRESS UNALIGNED *)TransportAddress->Address;
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->ValidBindings);
+
+ for (i = 1; i <= Index; i++) {
+
+ Binding = NIC_ID_TO_BINDING(Device, i);
+ if ((Binding == NULL) ||
+ (!Binding->LineUp)) {
+ continue;
+ }
+
+ if (query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
+ CurAddress->AddressLength = 6;
+ CurAddress->AddressType = Binding->Adapter->MacInfo.RealMediumType;
+ RtlCopyMemory (CurAddress->Address, Binding->LocalAddress.NodeAddress, 6);
+ } else {
+ CurAddress->AddressLength = sizeof(TDI_ADDRESS_IPX);
+ CurAddress->AddressType = TDI_ADDRESS_TYPE_IPX;
+ RtlCopyMemory (CurAddress->Address, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
+ }
+ ++TransportAddress->TAAddressCount;
+ TransportAddressSize += ElementSize;
+ CurAddress = (TA_ADDRESS UNALIGNED *)(((PUCHAR)CurAddress) + ElementSize);
+
+ }
+ }
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ for (i = 1; i <= Device->ValidBindings; i++) {
+
+ Binding = Device->Bindings[i];
+ if ((Binding == NULL) ||
+ (!Binding->LineUp)) {
+ continue;
+ }
+
+ if (query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
+ CurAddress->AddressLength = 6;
+ CurAddress->AddressType = Binding->Adapter->MacInfo.RealMediumType;
+ RtlCopyMemory (CurAddress->Address, Binding->LocalAddress.NodeAddress, 6);
+ } else {
+ CurAddress->AddressLength = sizeof(TDI_ADDRESS_IPX);
+ CurAddress->AddressType = TDI_ADDRESS_TYPE_IPX;
+ RtlCopyMemory (CurAddress->Address, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
+ }
+ ++TransportAddress->TAAddressCount;
+ TransportAddressSize += ElementSize;
+ CurAddress = (TA_ADDRESS UNALIGNED *)(((PUCHAR)CurAddress) + ElementSize);
+
+ }
+#endif
+ status = TdiCopyBufferToMdl (
+ TransportAddress,
+ 0,
+ TransportAddressSize,
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ CTEFreeMem (TransportAddress);
+
+ }
+
+ break;
+
+ default:
+
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ return status;
+
+} /* IpxTdiQueryInformation */
+
+
+NTSTATUS
+IpxTdiSetInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetInformation request for the transport
+ provider.
+
+Arguments:
+
+ Device - the device.
+
+ Request - the request for the operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (Device);
+ UNREFERENCED_PARAMETER (Request);
+
+ return STATUS_NOT_IMPLEMENTED;
+
+} /* IpxTdiSetInformation */
+
+
diff --git a/private/ntos/tdi/isnp/ipx/receive.c b/private/ntos/tdi/isnp/ipx/receive.c
new file mode 100644
index 000000000..ff9c68fbd
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/receive.c
@@ -0,0 +1,466 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ receive.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiReceiveDatagram
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+
+VOID
+IpxTransferDataComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus,
+ IN UINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that an NdisTransferData has completed. We use this indication
+ to complete any pended requests to our clients.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+ NdisPacket/RequestHandle - An identifier for the request that completed.
+
+ NdisStatus - The completion status for the request.
+
+ BytesTransferred - Number of bytes actually transferred.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+ PIPX_RECEIVE_RESERVED Reserved = (PIPX_RECEIVE_RESERVED)(NdisPacket->ProtocolReserved);
+ PREQUEST Request, LastRequest;
+ PADDRESS_FILE AddressFile;
+ ULONG ByteOffset;
+ PLIST_ENTRY p;
+ PDEVICE Device;
+
+
+ switch (Reserved->Identifier) {
+
+ case IDENTIFIER_IPX:
+
+ if (Reserved->SingleRequest) {
+
+ //
+ // The transfer was directly into the client buffer,
+ // so simply complete the request.
+ //
+
+ Request = Reserved->SingleRequest;
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ IPX_DEBUG (RECEIVE, ("Transferred %d bytes\n", BytesTransferred));
+ REQUEST_INFORMATION(Request) = BytesTransferred;
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+
+ } else {
+
+ IPX_DEBUG (RECEIVE, ("Transfer failed\n"));
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_ADAPTER_HARDWARE_ERROR;
+
+ }
+
+ LastRequest = Request;
+ Reserved->SingleRequest = NULL;
+
+ } else {
+
+ //
+ // Multiple clients requested this datagram. Save
+ // the last one to delay queueing it for completion.
+ //
+
+ LastRequest = LIST_ENTRY_TO_REQUEST (Reserved->Requests.Blink);
+
+ while (TRUE) {
+
+ p = RemoveHeadList (&Reserved->Requests);
+ if (p == &Reserved->Requests) {
+ break;
+ }
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+ AddressFile = REQUEST_OPEN_CONTEXT(Request);
+
+ if (AddressFile->ReceiveIpxHeader) {
+ ByteOffset = 0;
+ } else {
+ ByteOffset = sizeof(IPX_HEADER);
+ }
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ REQUEST_STATUS(Request) =
+ TdiCopyBufferToMdl(
+ Reserved->ReceiveBuffer->Data,
+ ByteOffset + REQUEST_INFORMATION(Request),
+ ((PTDI_REQUEST_KERNEL_RECEIVEDG)(REQUEST_PARAMETERS(Request)))->ReceiveLength,
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ } else {
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_ADAPTER_HARDWARE_ERROR;
+
+ }
+
+ if (Request != LastRequest) {
+
+ IPX_INSERT_TAIL_LIST(
+ &Adapter->RequestCompletionQueue,
+ REQUEST_LINKAGE(Request),
+ Adapter->DeviceLock);
+
+ }
+
+ }
+
+ //
+ // Now free the receive buffer back.
+ //
+
+ IPX_PUSH_ENTRY_LIST(
+ &Adapter->ReceiveBufferList,
+ &Reserved->ReceiveBuffer->PoolLinkage,
+ &Adapter->Device->SListsLock);
+
+ Reserved->ReceiveBuffer = NULL;
+
+ }
+
+
+ //
+ // Now free the packet.
+ //
+
+ NdisReinitializePacket (NdisPacket);
+
+ if (Reserved->OwnedByAddress) {
+
+ // Reserved->Address->ReceivePacketInUse = FALSE;
+ InterlockedDecrement(&Reserved->Address->ReceivePacketInUse);
+
+ } else {
+
+ Device = Adapter->Device;
+
+ IPX_PUSH_ENTRY_LIST(
+ &Device->ReceivePacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+
+ }
+
+
+ //
+ // We Delay inserting the last request (or the only one)
+ // until after we have put the packet back, to keep the
+ // address around if needed (the address won't go away
+ // until the last address file does, and the address file
+ // won't go away until the datagram is completed).
+ //
+
+ IPX_INSERT_TAIL_LIST(
+ &Adapter->RequestCompletionQueue,
+ REQUEST_LINKAGE(LastRequest),
+ Adapter->DeviceLock);
+
+ IpxReceiveComplete ((NDIS_HANDLE)Adapter);
+
+ break;
+
+ default:
+
+ Device = Adapter->Device;
+
+ (*Device->UpperDrivers[Reserved->Identifier].TransferDataCompleteHandler)(
+ NdisPacket,
+ NdisStatus,
+ BytesTransferred);
+
+ break;
+
+ }
+
+} /* IpxTransferDataComplete */
+
+
+VOID
+IpxTransferData(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by all tightly bound clients instead of NdisTransferData.
+ If this is a loopback packet, the transfer is done directly here, else NdisTransferData
+ is called.
+
+Arguments:
+
+ Status - status of operation
+ NdisBindingHandle - Loopback cookie or Ndis context
+ MacReceiveContext - Loopback packet or Mac context
+ ByteOffset - Source offset
+ BytesToTransfer - length of the transfer desired
+ Packet - dest packet
+ BytesTransferred - length of successful transfer
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ //
+ // If this is a loopback packet, copy the data directly
+ //
+ if (NdisBindingHandle == (PVOID)IPX_LOOPBACK_COOKIE) {
+
+ IPX_DEBUG (LOOPB, ("LoopbXfer: src: %lx, dest: %lx, bytestoxfer: %lx\n",
+ MacReceiveContext, Packet, BytesToTransfer));
+
+ NdisCopyFromPacketToPacket(
+ Packet, // Destination
+ 0, // DestinationOffset
+ BytesToTransfer, // BytesToCopy
+ (PNDIS_PACKET)MacReceiveContext, // Source
+ ByteOffset, // SourceOffset
+ BytesTransferred); // BytesCopied
+
+ *Status = NDIS_STATUS_SUCCESS;
+ } else {
+ NdisTransferData(
+ Status,
+ NdisBindingHandle,
+ MacReceiveContext,
+ ByteOffset,
+ BytesToTransfer,
+ Packet,
+ BytesTransferred);
+ }
+}
+
+
+
+NTSTATUS
+IpxTdiReceiveDatagram(
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiReceiveDatagram request for the transport
+ provider. Receive datagrams just get queued up to an address, and are
+ completed when a DATAGRAM or DATAGRAM_BROADCAST frame is received at
+ the address.
+
+Arguments:
+
+ Irp - I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ IPX_DEFINE_SYNC_CONTEXT (SyncContext)
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ //
+ // Do a quick check of the validity of the address.
+ //
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ if ((AddressFile->Size != sizeof (ADDRESS_FILE)) ||
+ (AddressFile->Type != IPX_ADDRESSFILE_SIGNATURE)) {
+
+ return STATUS_INVALID_HANDLE;
+ }
+
+ Address = AddressFile->Address;
+
+ if ((Address == NULL) ||
+ (Address->Size != sizeof (ADDRESS)) ||
+ (Address->Type != IPX_ADDRESS_SIGNATURE)) {
+
+ return STATUS_INVALID_HANDLE;
+ }
+
+ IPX_BEGIN_SYNC (&SyncContext);
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ IPX_END_SYNC (&SyncContext);
+ return STATUS_INVALID_HANDLE;
+ }
+
+
+ InsertTailList (&AddressFile->ReceiveDatagramQueue, REQUEST_LINKAGE(Request));
+
+ IoSetCancelRoutine (Request, IpxCancelReceiveDatagram);
+
+ if (Request->Cancel) {
+
+ (VOID)RemoveTailList (&AddressFile->ReceiveDatagramQueue);
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ IPX_END_SYNC (&SyncContext);
+ return STATUS_CANCELLED;
+ }
+
+ IPX_DEBUG (RECEIVE, ("RDG posted on %lx\n", AddressFile));
+
+ IpxReferenceAddressFileLock (AddressFile, AFREF_RCV_DGRAM);
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+
+ IPX_END_SYNC (&SyncContext);
+
+ return STATUS_PENDING;
+
+} /* IpxTdiReceiveDatagram */
+
+
+VOID
+IpxCancelReceiveDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a receive
+ datagram. The datagram is found on the address file's receive
+ datagram queue.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PLIST_ENTRY p;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PREQUEST Request = (PREQUEST)Irp;
+ BOOLEAN Found;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_RECEIVE_DATAGRAM));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_TRANSPORT_ADDRESS_FILE);
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+ Address = AddressFile->Address;
+
+ Found = FALSE;
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+
+ for (p = AddressFile->ReceiveDatagramQueue.Flink;
+ p != &AddressFile->ReceiveDatagramQueue;
+ p = p->Flink) {
+
+ if (LIST_ENTRY_TO_REQUEST(p) == Request) {
+
+ RemoveEntryList (p);
+ Found = TRUE;
+ break;
+ }
+ }
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ if (Found) {
+
+ IPX_DEBUG(RECEIVE, ("Cancelled datagram on %lx\n", AddressFile));
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ IpxCompleteRequest (Request);
+ ASSERT( DeviceObject->DeviceExtension == IpxDevice );
+ IpxFreeRequest(IpxDevice, Request);
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
+
+ }
+
+} /* IpxCancelReceiveDatagram */
+
+
diff --git a/private/ntos/tdi/isnp/ipx/rip.c b/private/ntos/tdi/isnp/ipx/rip.c
new file mode 100644
index 000000000..d30770223
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/rip.c
@@ -0,0 +1,2655 @@
+/*++
+
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ rip.c
+
+Abstract:
+
+ This module contains code that implements the client-side
+ RIP support and simple router table support.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+UCHAR BroadcastAddress[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+
+NTSTATUS
+RipGetLocalTarget(
+ IN ULONG Segment,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN UCHAR Type,
+ OUT PIPX_LOCAL_TARGET LocalTarget,
+ OUT USHORT Counts[2] OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine looks up the proper route for the specified remote
+ address. If a RIP request needs to be generated it does so.
+
+ NOTE: THIS REQUEST IS CALLED WITH THE SEGMENT LOCK HELD.
+ NOTE: IN THE CASE OF PnP, THIS COMES WITH THE BIND LOCK SHARED.
+
+Arguments:
+
+ Segment - The segment associate with the remote address.
+
+ RemoteAddress - The IPX address of the remote.
+
+ Type - One of IPX_FIND_ROUTE_NO_RIP, IPX_FIND_ROUTE_RIP_IF_NEEDED,
+ or IPX_FIND_ROUTE_FORCE_RIP.
+
+ LocalTarget - Returns the next router information.
+
+ Counts - If specified, used to return the tick and hop count.
+
+Return Value:
+
+ STATUS_SUCCESS if a route is found, STATUS_PENDING if a
+ RIP request needs to be generated, failure status if a
+ RIP request packet cannot be allocated.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ PBINDING Binding;
+ UINT i;
+
+
+ //
+ // Packets sent to network 0 go on the first adapter also.
+ //
+
+ if (RemoteAddress->NetworkAddress == 0) {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, 1);
+
+ RtlCopyMemory (LocalTarget->MacAddress, RemoteAddress->NodeAddress, 6);
+ if (ARGUMENT_PRESENT(Counts)) {
+ Counts[0] = (USHORT)((839 + NIC_ID_TO_BINDING(Device, 1)->MediumSpeed) /
+ NIC_ID_TO_BINDING(Device, 1)->MediumSpeed); // tick count
+ Counts[1] = 1; // hop count
+ }
+#else
+ LocalTarget->NicId = 1;
+
+ RtlCopyMemory (LocalTarget->MacAddress, RemoteAddress->NodeAddress, 6);
+ if (ARGUMENT_PRESENT(Counts)) {
+ Counts[0] = (USHORT)((839 + Device->Bindings[1]->MediumSpeed) /
+ Device->Bindings[1]->MediumSpeed); // tick count
+ Counts[1] = 1; // hop count
+ }
+#endif
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // See if this is a packet sent to our virtual network.
+ //
+
+ if (Device->VirtualNetwork &&
+ (RemoteAddress->NetworkAddress == Device->SourceAddress.NetworkAddress)) {
+
+ //
+ // Send it through adapter 1.
+ // BUGBUG: Do real loopback.
+ //
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, 0);
+ RtlCopyMemory (LocalTarget->MacAddress, NIC_ID_TO_BINDING(Device, 1)->LocalMacAddress.Address, 6);
+#else
+ //
+ // Loopback this packet
+ //
+ LocalTarget->NicId = 0;
+ RtlCopyMemory (LocalTarget->MacAddress, Device->Bindings[1]->LocalMacAddress.Address, 6);
+#endif
+
+ IPX_DEBUG (LOOPB, ("Loopback Nic returned for net: %lx\n", RemoteAddress->NetworkAddress));
+ if (ARGUMENT_PRESENT(Counts)) {
+ Counts[0] = 1; // tick count
+ Counts[1] = 1; // hop count
+ }
+ return STATUS_SUCCESS;
+
+ }
+
+ //
+ // Look up the route in the table. If the net is one
+ // of the ones we are directly attached to, this will
+ // return an entry with the correct flag set.
+ //
+
+ RouteEntry = RipGetRoute(Segment, (PUCHAR)&(RemoteAddress->NetworkAddress));
+
+ if (RouteEntry != NULL) {
+
+ RouteEntry->Timer = 0;
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, RouteEntry->NicId);
+#else
+ LocalTarget->NicId = RouteEntry->NicId;
+#endif
+ if (RouteEntry->Flags & IPX_ROUTER_LOCAL_NET) {
+
+ //
+ // The machine is on the same net, so send it directly.
+ //
+
+ RtlCopyMemory (LocalTarget->MacAddress, RemoteAddress->NodeAddress, 6);
+
+ if (RouteEntry->Flags & IPX_ROUTER_GLOBAL_WAN_NET) {
+
+ //
+ // The NicId here is bogus, we have to scan through
+ // our bindings until we find one whose indicated
+ // IPX remote node matches the destination node of
+ // this frame. We don't scan into the duplicate
+ // binding set members since they won't be WANs.
+ //
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ if ((Binding != (PBINDING)NULL) &&
+ (Binding->Adapter->MacInfo.MediumAsync) &&
+ (RtlEqualMemory(
+ Binding->WanRemoteNode,
+ RemoteAddress->NodeAddress,
+ 6))) {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, MIN( Device->MaxBindings, Binding->NicId));
+#else
+ LocalTarget->NicId = Binding->NicId;
+#endif
+ break;
+
+ }
+ }
+ }
+
+ if (i > (UINT)MIN (Device->MaxBindings, Device->HighestExternalNicId)) {
+ //
+ // Bug #17273 return proper error message
+ //
+
+ // return STATUS_DEVICE_DOES_NOT_EXIST;
+ return STATUS_NETWORK_UNREACHABLE;
+ }
+
+ } else {
+ //
+ // Find out if this is a loopback packet. If so, return NicId 0
+ //
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ //
+ // Self-directed - loopback
+ //
+ if ((Binding != (PBINDING)NULL) &&
+ (RtlEqualMemory(
+ Binding->LocalAddress.NodeAddress,
+ RemoteAddress->NodeAddress,
+ 6))) {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, 0);
+#else
+ LocalTarget->NicId = 0;
+#endif
+
+ IPX_DEBUG (LOOPB, ("2.Loopback Nic returned for net: %lx\n", RemoteAddress->NetworkAddress));
+ break;
+
+ }
+ }
+ }
+ }
+
+ } else {
+
+ CTEAssert ((RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY) == 0);
+
+ //
+ // This is not a locally attached net, so if the caller
+ // is forcing a re-RIP then do that.
+ //
+
+ if (Type == IPX_FIND_ROUTE_FORCE_RIP) {
+ goto QueueUpRequest;
+ }
+
+ //
+ // Fill in the address of the next router in the route.
+ //
+
+ RtlCopyMemory (LocalTarget->MacAddress, RouteEntry->NextRouter, 6);
+
+ }
+
+ if (ARGUMENT_PRESENT(Counts)) {
+ Counts[0] = RouteEntry->TickCount;
+ Counts[1] = RouteEntry->HopCount;
+ }
+
+ return STATUS_SUCCESS;
+
+ }
+
+QueueUpRequest:
+
+ if (Type == IPX_FIND_ROUTE_NO_RIP) {
+
+ //
+ // Bug #17273 return proper error message
+ //
+
+ // return STATUS_DEVICE_DOES_NOT_EXIST;
+ return STATUS_NETWORK_UNREACHABLE;
+
+ } else {
+
+ return RipQueueRequest (RemoteAddress->NetworkAddress, RIP_REQUEST);
+
+ }
+
+} /* RipGetLocalTarget */
+
+
+NTSTATUS
+RipQueueRequest(
+ IN ULONG Network,
+ IN USHORT Operation
+ )
+
+/*++
+
+Routine Description:
+
+ This routine queues up a request for a RIP route. It can be
+ used to find a specific route or to discover the locally
+ attached network (if Network is 0). It can also be used
+ to do a periodic announcement of the virtual net, which
+ we do once a minute if the router is not bound.
+
+ NOTE: THIS REQUEST IS CALLED WITH THE SEGMENT LOCK HELD
+ IF IT IS A REQUEST AND THE NETWORK IS NOT 0xffffffff.
+
+Arguments:
+
+ Network - The network to discover.
+
+ Operation - One of RIP_REQUEST, RIP_RESPONSE, or RIP_DOWN.
+
+Return Value:
+
+ STATUS_PENDING if the request is queued, failure status
+ if it could not be.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ PIPX_SEND_RESERVED Reserved;
+ PSINGLE_LIST_ENTRY s;
+ PLIST_ENTRY p;
+ PRIP_PACKET RipPacket;
+ TDI_ADDRESS_IPX RemoteAddress;
+ TDI_ADDRESS_IPX LocalAddress;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+ PNDIS_BUFFER pNdisIpxBuff;
+
+
+ //
+ // Make sure we only queue a request for net 0xffffffff if we
+ // are auto-detecting, because we assume that in other places.
+ //
+
+ if ((Network == 0xffffffff) &&
+ (Device->AutoDetectState != AUTO_DETECT_STATE_RUNNING)) {
+
+ return STATUS_BAD_NETWORK_PATH;
+
+ }
+
+ //
+ // Try to get a packet to use for the RIP request. We
+ // allocate this now, but check if it succeeded later,
+ // to make the locking work better (we need to keep
+ // the lock between when we check for an existing
+ // request on this network and when we queue this
+ // request).
+ //
+
+ s = IpxPopSendPacket (Device);
+
+ //
+ // There was no router table entry for this network, first see
+ // if there is already a pending request for this route.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (Operation == RIP_REQUEST) {
+
+ for (p = Device->WaitingRipPackets.Flink;
+ p != &Device->WaitingRipPackets;
+ p = p->Flink) {
+
+ Reserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
+
+ //
+ // Skip responses.
+ //
+
+ if (Reserved->u.SR_RIP.RetryCount >= 0xfe) {
+ continue;
+ }
+
+ if (Reserved->u.SR_RIP.Network == Network &&
+ !Reserved->u.SR_RIP.RouteFound) {
+
+ //
+ // There is already one pending, put back the packet if
+ // we got one (we hold the lock already).
+ //
+
+ if (s != NULL) {
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, s, &Device->SListsLock);
+ }
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ return STATUS_PENDING;
+ }
+ }
+
+ }
+
+
+ if (s == NULL) {
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+
+ //
+ // We have the packet, fill it in for this request.
+ //
+
+ Reserved->Identifier = IDENTIFIER_RIP_INTERNAL;
+ Reserved->SendInProgress = FALSE;
+ Reserved->DestinationType = DESTINATION_BCAST;
+ Reserved->u.SR_RIP.CurrentNicId = 0;
+ Reserved->u.SR_RIP.NoIdAdvance = FALSE;
+ switch (Operation) {
+ case RIP_REQUEST: Reserved->u.SR_RIP.RetryCount = 0; break;
+ case RIP_RESPONSE: Reserved->u.SR_RIP.RetryCount = 0xfe; break;
+ case RIP_DOWN: Reserved->u.SR_RIP.RetryCount = 0xff; break;
+ }
+ Reserved->u.SR_RIP.RouteFound = FALSE;
+ Reserved->u.SR_RIP.Network = Network;
+ Reserved->u.SR_RIP.SendTime = Device->RipSendTime;
+
+ //
+ // We aren't guaranteed that this is the case for packets
+ // on the free list.
+ //
+
+ pNdisIpxBuff = NDIS_BUFFER_LINKAGE (Reserved->HeaderBuffer);
+ NDIS_BUFFER_LINKAGE (pNdisIpxBuff) = NULL;
+
+ //
+ // Fill in the IPX header at the standard offset (for sending
+ // to actual bindings it will be moved around if needed). We
+ // have to construct the local and remote addresses so they
+ // are in the format that IpxConstructHeader expects.
+ //
+
+ RemoteAddress.NetworkAddress = Network;
+ RtlCopyMemory (RemoteAddress.NodeAddress, BroadcastAddress, 6);
+ RemoteAddress.Socket = RIP_SOCKET;
+
+ RtlCopyMemory (&LocalAddress, &Device->SourceAddress, FIELD_OFFSET(TDI_ADDRESS_IPX,Socket));
+ LocalAddress.Socket = RIP_SOCKET;
+
+ IpxConstructHeader(
+// &Reserved->Header[Device->IncludedHeaderOffset],
+ &Reserved->Header[MAC_HEADER_SIZE],
+ sizeof(IPX_HEADER) + sizeof (RIP_PACKET),
+ RIP_PACKET_TYPE,
+ &RemoteAddress,
+ &LocalAddress);
+
+ //
+ // Fill in the RIP request also.
+ //
+
+#if 0
+ RipPacket = (PRIP_PACKET)(&Reserved->Header[Device->IncludedHeaderOffset + sizeof(IPX_HEADER)]);
+#endif
+ RipPacket = (PRIP_PACKET)(&Reserved->Header[MAC_HEADER_SIZE + sizeof(IPX_HEADER)]);
+ RipPacket->Operation = Operation & 0x7fff;
+ RipPacket->NetworkEntry.NetworkNumber = Network;
+
+ if (Operation == RIP_REQUEST) {
+ RipPacket->NetworkEntry.HopCount = REORDER_USHORT(0xffff);
+ RipPacket->NetworkEntry.TickCount = REORDER_USHORT(0xffff);
+ } else if (Operation == RIP_RESPONSE) {
+ RipPacket->NetworkEntry.HopCount = REORDER_USHORT(1);
+ RipPacket->NetworkEntry.TickCount = REORDER_USHORT(2); // will be modified when sent
+ } else {
+ RipPacket->NetworkEntry.HopCount = REORDER_USHORT(16);
+ RipPacket->NetworkEntry.TickCount = REORDER_USHORT(16);
+ }
+
+ NdisAdjustBufferLength(pNdisIpxBuff, sizeof(IPX_HEADER) + sizeof(RIP_PACKET));
+ //
+ // Now insert this packet in the queue of pending RIP
+ // requests and start the timer if needed (this is done
+ // to ensure the RIP_GRANULARITY milliseconds inter-RIP-packet
+ // delay).
+ //
+
+ IPX_DEBUG (RIP, ("RIP %s for network %lx\n",
+ (Operation == RIP_REQUEST) ? "request" : ((Operation == RIP_RESPONSE) ? "announce" : "down"),
+ REORDER_ULONG(Network)));
+
+ InsertHeadList(
+ &Device->WaitingRipPackets,
+ &Reserved->WaitLinkage);
+
+ ++Device->RipPacketCount;
+
+ if (!Device->RipShortTimerActive) {
+
+ Device->RipShortTimerActive = TRUE;
+ IpxReferenceDevice (Device, DREF_RIP_TIMER);
+
+ CTEStartTimer(
+ &Device->RipShortTimer,
+ 1, // 1 ms, i.e. expire immediately
+ RipShortTimeout,
+ (PVOID)Device);
+ }
+
+ IpxReferenceDevice (Device, DREF_RIP_PACKET);
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ return STATUS_PENDING;
+
+} /* RipQueueRequest */
+
+
+VOID
+RipSendResponse(
+ IN PBINDING Binding,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PIPX_LOCAL_TARGET LocalTarget
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a respond to a RIP request from a client --
+ this is only used if we have a virtual network and the router
+ is not bound, and somebody queries on the virtual network.
+
+Arguments:
+
+ Binding - The binding on which the request was received.
+
+ RemoteAddress - The IPX source address of the request.
+
+ LocalTarget - The local target of the received packet.
+
+Return Value:
+
+ STATUS_PENDING if the request is queued, failure status
+ if it could not be.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PIPX_SEND_RESERVED Reserved;
+ TDI_ADDRESS_IPX LocalAddress;
+ PNDIS_PACKET Packet;
+ PIPX_HEADER IpxHeader;
+ PRIP_PACKET RipPacket;
+ PDEVICE Device = IpxDevice;
+ PBINDING MasterBinding;
+ NDIS_STATUS NdisStatus;
+ USHORT TickCount;
+ PNDIS_BUFFER pNdisIpxBuff;
+
+ //
+ // Get a packet to use for the RIP response.
+ //
+
+ s = IpxPopSendPacket (Device);
+
+ if (s == NULL) {
+ return;
+ }
+
+ IpxReferenceDevice (Device, DREF_RIP_PACKET);
+
+ Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+
+ //
+ // We have the packet, fill it in for this request.
+ //
+
+ Reserved->Identifier = IDENTIFIER_RIP_RESPONSE;
+ Reserved->DestinationType = DESTINATION_DEF;
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ //
+ // We aren't guaranteed that this is the case for packets
+ // on the free list.
+ //
+
+ pNdisIpxBuff = NDIS_BUFFER_LINKAGE (Reserved->HeaderBuffer);
+ NDIS_BUFFER_LINKAGE (pNdisIpxBuff) = NULL;
+
+ //
+ // If this binding is a binding set member, round-robin through
+ // the various bindings when responding. We will get some natural
+ // round-robinning because broadcast requests are received on
+ // binding set members in turn, but they are only rotated once
+ // a second.
+ //
+
+ if (Binding->BindingSetMember) {
+
+ //
+ // It's a binding set member, we round-robin the
+ // responses across all the cards to distribute
+ // the traffic.
+ //
+
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ }
+
+ //
+ // Fill in the IPX header at the correct offset.
+ //
+
+ LocalAddress.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory (LocalAddress.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ LocalAddress.Socket = RIP_SOCKET;
+#if 0
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[Binding->DefHeaderSize]);
+#endif
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[MAC_HEADER_SIZE]);
+
+ IpxConstructHeader(
+ (PUCHAR)IpxHeader,
+ sizeof(IPX_HEADER) + sizeof (RIP_PACKET),
+ RIP_PACKET_TYPE,
+ RemoteAddress,
+ &LocalAddress);
+
+ //
+ // In case the request comes from net 0, fill that in too.
+ //
+
+ *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork = Binding->LocalAddress.NetworkAddress;
+
+
+ //
+ // Fill in the RIP request.
+ //
+
+ RipPacket = (PRIP_PACKET)(IpxHeader+1);
+
+ RipPacket->Operation = RIP_RESPONSE;
+ RipPacket->NetworkEntry.NetworkNumber = Device->VirtualNetworkNumber;
+
+ RipPacket->NetworkEntry.HopCount = REORDER_USHORT(1);
+ TickCount = (USHORT)(((839 + Binding->MediumSpeed) / Binding->MediumSpeed) + 1);
+ RipPacket->NetworkEntry.TickCount = REORDER_USHORT(TickCount);
+
+ IPX_DEBUG (RIP, ("RIP response for virtual network %lx\n",
+ REORDER_ULONG(Device->VirtualNetworkNumber)));
+
+ NdisAdjustBufferLength(pNdisIpxBuff, sizeof(IPX_HEADER) + sizeof(RIP_PACKET));
+ //
+ // Now submit the packet to NDIS.
+ //
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ if ((NdisStatus = IpxSendFrame(
+ LocalTarget,
+ Packet,
+ sizeof(RIP_PACKET) + sizeof(IPX_HEADER),
+ sizeof(RIP_PACKET) + sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ IpxSendComplete(
+ (NDIS_HANDLE)Binding->Adapter,
+ Packet,
+ NdisStatus);
+ }
+
+#ifdef _PNP_POWER
+ if (Binding->BindingSetMember) {
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ }
+#endif
+ return;
+
+} /* RipSendResponse */
+
+
+VOID
+RipShortTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the RIP short timer expires.
+ It is called every RIP_GRANULARITY milliseconds unless there
+ is nothing to do.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the device pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)Context;
+ PLIST_ENTRY p;
+ PIPX_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ USHORT OldNicId, NewNicId;
+ ULONG OldOffset, NewOffset;
+ PIPX_HEADER IpxHeader;
+ PBINDING Binding, MasterBinding;
+ NDIS_STATUS NdisStatus;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+#ifdef _PNP_LATER
+ static IPX_LOCAL_TARGET BroadcastTarget = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, {0, 0, 0} };
+#else
+ static IPX_LOCAL_TARGET BroadcastTarget = { 0, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
+#endif
+
+ static ULONG ZeroNetwork = 0;
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ ++Device->RipSendTime;
+
+ if (Device->RipPacketCount == 0) {
+
+ Device->RipShortTimerActive = FALSE;
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IpxDereferenceDevice (Device, DREF_RIP_TIMER);
+
+ return;
+ }
+
+ //
+ // Check what is on the queue; this is set up as a
+ // loop but in fact it rarely does (under no
+ // circumstances can we send more than one packet
+ // each time this function executes).
+ //
+
+ while (TRUE) {
+
+ p = Device->WaitingRipPackets.Flink;
+ if (p == &Device->WaitingRipPackets) {
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ Reserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
+
+ if ((Reserved->u.SR_RIP.RouteFound) && (!Reserved->SendInProgress)) {
+
+ (VOID)RemoveHeadList (&Device->WaitingRipPackets);
+ Reserved->Identifier = IDENTIFIER_IPX;
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+ --Device->RipPacketCount;
+
+ //
+ // It is OK to do this with the lock held because
+ // it won't be the last one (we have the RIP_TIMER ref).
+ //
+
+ IpxDereferenceDevice (Device, DREF_RIP_PACKET);
+ continue;
+ }
+
+ if ((((SHORT)(Device->RipSendTime - Reserved->u.SR_RIP.SendTime)) < 0) ||
+ Reserved->SendInProgress) {
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ (VOID)RemoveHeadList (&Device->WaitingRipPackets);
+
+ //
+ // Find the right binding to send to. If NoIdAdvance
+ // is set, then the binding doesn't need to be changed
+ // this time (this means we wrapped last time).
+ //
+
+ OldNicId = Reserved->u.SR_RIP.CurrentNicId;
+
+ if (!Reserved->u.SR_RIP.NoIdAdvance) {
+
+ BOOLEAN FoundNext = FALSE;
+
+#ifdef _PNP_POWER
+//
+// To maintain the lock order, release Device lock here and re-acquire later
+//
+ USHORT StartId;
+
+ if (Device->ValidBindings == 0) {
+ IPX_DEBUG(PNP, ("ValidBindings 0 in RipShortTimeOut\n"));
+
+ Device->RipShortTimerActive = FALSE;
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IpxDereferenceDevice (Device, DREF_RIP_TIMER);
+ return;
+ }
+
+ StartId = (USHORT)((OldNicId % MIN (Device->MaxBindings, Device->ValidBindings)) + 1);
+
+ NewNicId = StartId;
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#else
+
+ USHORT StartId = (USHORT)((OldNicId % Device->BindingCount) + 1);
+
+ NewNicId = StartId;
+#endif
+ do {
+
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, NewNicId);
+#else
+ Binding = Device->Bindings[NewNicId];
+#endif
+ if (Reserved->u.SR_RIP.Network != 0xffffffff) {
+
+ //
+ // We are looking for a real net; check that
+ // the next binding is valid. If it is a WAN
+ // binding, we don't send queries if the router
+ // is bound. If it is a LAN binding, we don't
+ // send queries if we are configured for
+ // SingleNetworkActive and the WAN is up.
+ // We also don't send queries on binding set
+ // members which aren't masters.
+ //
+
+ if ((Binding != NULL)
+ &&
+ ((!Binding->Adapter->MacInfo.MediumAsync) ||
+ (!Device->UpperDriverBound[IDENTIFIER_RIP]))
+ &&
+ ((Binding->Adapter->MacInfo.MediumAsync) ||
+ (!Device->SingleNetworkActive) ||
+ (!Device->ActiveNetworkWan))
+ &&
+ ((!Binding->BindingSetMember) ||
+ (Binding->CurrentSendBinding))) {
+
+ FoundNext = TRUE;
+ break;
+ }
+
+ } else {
+
+ //
+ // We are sending out the initial request to net
+ // 0xffffffff, to generate traffic so we can figure
+ // out our real network number. We don't do this
+ // to nets that already have a number and we don't
+ // do it on WAN links. We also don't do it on
+ // auto-detect nets if we have found the default.
+ //
+
+
+ if ((Binding != NULL) &&
+ (Binding->TentativeNetworkAddress == 0) &&
+ (!Binding->Adapter->MacInfo.MediumAsync) &&
+ (!Binding->AutoDetect || !Binding->Adapter->DefaultAutoDetected)) {
+ FoundNext = TRUE;
+ break;
+ }
+ }
+#ifdef _PNP_POWER
+ //
+ // [BUGBUGZZ] Why cycle thru the entire list?
+ //
+ NewNicId = (USHORT)((NewNicId % MIN (Device->MaxBindings, Device->ValidBindings)) + 1);
+#else
+ NewNicId = (USHORT)((NewNicId % Device->BindingCount) + 1);
+#endif
+ } while (NewNicId != StartId);
+
+ if (!FoundNext) {
+
+ //
+ // Nothing more needs to be done with this packet,
+ // leave it off the queue and since we didn't send
+ // a packet we can check for more.
+ //
+#ifndef _PNP_POWER
+ //
+ // This was released above (before the BindAccessLock was taken
+ //
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+#endif
+ RipCleanupPacket(Device, Reserved);
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+ --Device->RipPacketCount;
+ IpxDereferenceDevice (Device, DREF_RIP_PACKET);
+ continue;
+
+ }
+
+#ifdef _PNP_POWER
+
+ IPX_DEBUG(RIP, ("RIP: FoundNext: %lx, StartId: %lx, OldNicId: %lx, NewNicId: %lx\n", FoundNext, StartId, OldNicId, NewNicId));
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // Re-acquire the Device lock
+ //
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+#endif
+
+ Reserved->u.SR_RIP.CurrentNicId = NewNicId;
+
+ //
+ // Move the data around if needed.
+ //
+
+#if 0
+ if (OldNicId != NewNicId) {
+
+ if (OldNicId == 0) {
+ OldOffset = Device->IncludedHeaderOffset;
+ } else {
+ OldOffset = Device->Bindings[OldNicId]->BcMcHeaderSize;
+ }
+
+ NewOffset = Binding->BcMcHeaderSize;
+
+ if (OldOffset != NewOffset) {
+
+ RtlMoveMemory(
+ &Reserved->Header[NewOffset],
+ &Reserved->Header[OldOffset],
+ sizeof(IPX_HEADER) + sizeof(RIP_PACKET));
+
+ }
+
+ }
+#endif
+
+ if (NewNicId <= OldNicId) {
+
+ //
+ // We found a new binding but we wrapped, so increment
+ // the counter. If we have done all the resends, or
+ // this is a response (indicated by retry count of 0xff;
+ // they are only sent once) then clean up.
+ //
+
+ if ((Reserved->u.SR_RIP.RetryCount >= 0xfe) ||
+ ((++Reserved->u.SR_RIP.RetryCount) == Device->RipCount)) {
+
+ //
+ // This packet is stale, clean it up and continue.
+ //
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ RipCleanupPacket(Device, Reserved);
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+ --Device->RipPacketCount;
+ IpxDereferenceDevice (Device, DREF_RIP_PACKET);
+
+ } else {
+
+ //
+ // We wrapped, so put ourselves back in the queue
+ // at the end.
+ //
+
+ Reserved->u.SR_RIP.SendTime = (USHORT)(Device->RipSendTime + Device->RipTimeout - 1);
+ Reserved->u.SR_RIP.NoIdAdvance = TRUE;
+ InsertTailList (&Device->WaitingRipPackets, &Reserved->WaitLinkage);
+
+#ifdef _PNP_POWER
+ //
+ // Free the Device lock before deref'ing the Binding so we maintain
+ // the lock order: BindingAccess > GlobalInterLock > Device
+ //
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+#endif
+ }
+
+ continue;
+
+ }
+#ifdef _PNP_POWER
+//
+// To prevent the re-acquire of the device lock, this is moved up...
+//
+ //
+ // Send it again as soon as possible (it we just wrapped, then
+ // we will have put ourselves at the tail and won't get here).
+ //
+
+ InsertHeadList (&Device->WaitingRipPackets, &Reserved->WaitLinkage);
+
+ CTEAssert (Reserved->Identifier == IDENTIFIER_RIP_INTERNAL);
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+#endif
+ } else {
+
+ //
+ // Next time we need to advance the binding.
+ //
+
+ Reserved->u.SR_RIP.NoIdAdvance = FALSE;
+ NewNicId = OldNicId;
+#ifdef _PNP_POWER
+ //
+ // Send it again as soon as possible (it we just wrapped, then
+ // we will have put ourselves at the tail and won't get here).
+ //
+
+ InsertHeadList (&Device->WaitingRipPackets, &Reserved->WaitLinkage);
+
+ CTEAssert (Reserved->Identifier == IDENTIFIER_RIP_INTERNAL);
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ Binding = NIC_ID_TO_BINDING(Device, NewNicId);
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ Binding = Device->Bindings[NewNicId];
+#endif
+
+ }
+#ifndef _PNP_POWER
+ //
+ // Send it again as soon as possible (it we just wrapped, then
+ // we will have put ourselves at the tail and won't get here).
+ //
+
+ InsertHeadList (&Device->WaitingRipPackets, &Reserved->WaitLinkage);
+
+ CTEAssert (Reserved->Identifier == IDENTIFIER_RIP_INTERNAL);
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+#endif
+ //
+ // This packet should be sent on binding NewNicId; first
+ // move the data to the right location for the current
+ // binding.
+ //
+#ifdef _PNP_POWER
+ CTEAssert (Binding == NIC_ID_TO_BINDING(Device, NewNicId)); // temp, just to make sure
+#else
+ CTEAssert (Binding == Device->Bindings[NewNicId]); // temp, just to make sure
+#endif
+// NewOffset = Binding->BcMcHeaderSize;
+
+ //
+ // Now submit the packet to NDIS.
+ //
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&BroadcastTarget, NewNicId);
+#else
+ BroadcastTarget.NicId = NewNicId;
+#endif
+
+ //
+ // Modify the header so the packet comes from this
+ // specific adapter, not the virtual network.
+ //
+
+ // IpxHeader = (PIPX_HEADER)(&Reserved->Header[NewOffset]);
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[MAC_HEADER_SIZE]);
+
+ if (Reserved->u.SR_RIP.Network == 0xffffffff) {
+ *(UNALIGNED ULONG *)IpxHeader->SourceNetwork = 0;
+ } else {
+ *(UNALIGNED ULONG *)IpxHeader->SourceNetwork = Binding->LocalAddress.NetworkAddress;
+ }
+
+ if (Reserved->u.SR_RIP.RetryCount < 0xfe) {
+
+ //
+ // This is an outgoing query. We round-robin these through
+ // binding sets.
+ //
+
+ if (Binding->BindingSetMember) {
+
+ //
+ // Shouldn't have any binding sets during initial
+ // discovery.
+ //
+
+ CTEAssert (Reserved->u.SR_RIP.Network != 0xffffffff);
+
+ //
+ // If we are in a binding set, then use the current binding
+ // in the set for this send, and advance the current binding.
+ // The places we have used Binding before here will be fine
+ // since the binding set members all have the same media
+ // and frame type.
+ //
+
+ CTEAssert (Binding->CurrentSendBinding); // should be a master.
+ MasterBinding = Binding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+#ifdef _PNP_POWER
+ //
+ // [BUGBUGZZ]: We dont have a lock here - the masterbinding could be bogus
+ //
+ IpxDereferenceBinding1(MasterBinding, BREF_DEVICE_ACCESS);
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ }
+ }
+
+
+ RtlCopyMemory (IpxHeader->SourceNode, Binding->LocalAddress.NodeAddress, 6);
+
+ //
+ // Bug# 6485
+ // Rip request, general or specific, is putting the network of the
+ // node to which the route has to be found in the ipx header remote
+ // network field. Some novell routers don't like that. This network
+ // field should be 0.
+ //
+ {
+ PRIP_PACKET RipPacket = (PRIP_PACKET)(&Reserved->Header[MAC_HEADER_SIZE + sizeof(IPX_HEADER)]);
+
+ if (RipPacket->Operation != RIP_REQUEST) {
+ *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork = Binding->LocalAddress.NetworkAddress;
+ } else {
+ *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork = 0;
+ }
+ }
+
+ //
+ // If this is a RIP_RESPONSE, set the tick count for this
+ // binding.
+ //
+
+ if (Reserved->u.SR_RIP.RetryCount == 0xfe) {
+
+ PRIP_PACKET RipPacket = (PRIP_PACKET)(IpxHeader+1);
+ USHORT TickCount = (USHORT)
+ (((839 + Binding->MediumSpeed) / Binding->MediumSpeed) + 1);
+
+ RipPacket->NetworkEntry.TickCount = REORDER_USHORT(TickCount);
+
+ }
+
+ if ((NdisStatus = IpxSendFrame(
+ &BroadcastTarget,
+ Packet,
+ sizeof(RIP_PACKET) + sizeof(IPX_HEADER),
+ sizeof(RIP_PACKET) + sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ IpxSendComplete(
+ (NDIS_HANDLE)Binding->Adapter,
+ Packet,
+ NdisStatus);
+ }
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+
+ break;
+
+ }
+
+ CTEStartTimer(
+ &Device->RipShortTimer,
+ RIP_GRANULARITY,
+ RipShortTimeout,
+ (PVOID)Device);
+
+} /* RipShortTimeout */
+
+
+VOID
+RipLongTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the RIP long timer expires.
+ It is called every minute and handles periodic re-RIPping
+ to ensure that entries are accurate, as well as aging out
+ of entries if the rip router is not bound.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the device pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)Context;
+ PROUTER_SEGMENT RouterSegment;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ UINT Segment;
+ UINT i;
+ PBINDING Binding;
+ IPX_DEFINE_LOCK_HANDLE(LockHandle)
+
+
+ //
+ // Rotate the broadcast receiver on all binding sets.
+ // We can loop up to HighestExternal only since we
+ // are only interested in finding binding set masters.
+ //
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ if ((Binding != NULL) &&
+ (Binding->CurrentSendBinding)) {
+
+ //
+ // It is a master, so find the current broadcast
+ // receiver, then advance it.
+ //
+
+ while (TRUE) {
+ if (Binding->ReceiveBroadcast) {
+ Binding->ReceiveBroadcast = FALSE;
+ Binding->NextBinding->ReceiveBroadcast = TRUE;
+ break;
+ } else {
+ Binding = Binding->NextBinding;
+ }
+ }
+ }
+ }
+ }
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+
+ //
+ // If RIP is bound, we don't do any of this, and
+ // we stop the timer from running.
+ //
+
+ if (Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ IpxDereferenceDevice (Device, DREF_LONG_TIMER);
+ return;
+ }
+
+
+ //
+ // If we have a virtual net, do our periodic broadcast.
+ //
+
+ if (Device->RipResponder) {
+ (VOID)RipQueueRequest (Device->VirtualNetworkNumber, RIP_RESPONSE);
+ }
+
+
+ //
+ // Update the real counters from the temp ones.
+ //
+
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DatagramBytesSent,
+ Device->TempDatagramBytesSent);
+ Device->Statistics.DatagramsSent += Device->TempDatagramsSent;
+
+ Device->TempDatagramBytesSent = 0;
+ Device->TempDatagramsSent = 0;
+
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DatagramBytesReceived,
+ Device->TempDatagramBytesReceived);
+ Device->Statistics.DatagramsReceived += Device->TempDatagramsReceived;
+
+ Device->TempDatagramBytesReceived = 0;
+ Device->TempDatagramsReceived = 0;
+
+
+ //
+ // We need to scan each hash bucket to see if there
+ // are any active entries which need to be re-RIPped
+ // for. We also scan for entries that should be timed
+ // out.
+ //
+
+ for (Segment = 0; Segment < Device->SegmentCount; Segment++) {
+
+ RouterSegment = &IpxDevice->Segments[Segment];
+
+ //
+ // Don't take the lock if the bucket is empty.
+ //
+
+ if (RouterSegment->Entries.Flink == &RouterSegment->Entries) {
+ continue;
+ }
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Scan through each entry looking for ones to age.
+ //
+
+ for (RouteEntry = RipGetFirstRoute (Segment);
+ RouteEntry != (PIPX_ROUTE_ENTRY)NULL;
+ RouteEntry = RipGetNextRoute (Segment)) {
+
+ if (RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY) {
+ continue;
+ }
+
+ ++RouteEntry->Timer;
+ if (RouteEntry->Timer >= Device->RipUsageTime) {
+
+ RipDeleteRoute (Segment, RouteEntry);
+ IpxFreeMemory(RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ continue;
+
+ }
+
+ //
+ // See if we should re-RIP for this segment. It has
+ // to have been around for RipAgeTime, and we also
+ // make sure that the Timer is not too high to
+ // prevent us from re-RIPping on unused routes.
+ //
+
+ ++RouteEntry->PRIVATE.Reserved[0];
+
+ if ((RouteEntry->PRIVATE.Reserved[0] >= Device->RipAgeTime) &&
+ (RouteEntry->Timer <= Device->RipAgeTime)) {
+
+ //
+ // If we successfully queue a request, then reset
+ // Reserved[0] so we don't re-RIP for a while.
+ //
+
+ if (RipQueueRequest (*(UNALIGNED ULONG *)RouteEntry->Network, RIP_REQUEST) == STATUS_PENDING) {
+ RouteEntry->PRIVATE.Reserved[0] = 0;
+ }
+ }
+ }
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+
+ }
+
+
+ //
+ // Now restart the timer for the next timeout.
+ //
+
+ if (Device->State == DEVICE_STATE_OPEN) {
+
+ CTEStartTimer(
+ &Device->RipLongTimer,
+ 60000, // one minute timeout
+ RipLongTimeout,
+ (PVOID)Device);
+
+ } else {
+
+ //
+ // Send a DOWN packet if needed, then stop ourselves.
+ //
+
+ if (Device->RipResponder) {
+
+ if (RipQueueRequest (Device->VirtualNetworkNumber, RIP_DOWN) != STATUS_PENDING) {
+
+ //
+ // We need to kick this event because the packet completion
+ // won't.
+ //
+
+ KeSetEvent(
+ &Device->UnloadEvent,
+ 0L,
+ FALSE);
+ }
+ }
+
+ IpxDereferenceDevice (Device, DREF_LONG_TIMER);
+
+ }
+
+} /* RipLongTimeout */
+
+
+VOID
+RipCleanupPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_RESERVED RipReserved
+ )
+
+/*++
+
+Routine Description:
+
+ This routine cleans up when a RIP packet times out.
+
+Arguments:
+
+ Device - The device.
+
+ RipReserved - The ProtocolReserved section of the RIP packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Segment;
+ IPX_DEFINE_LOCK_HANDLE_PARAM (LockHandle)
+
+ if (RipReserved->u.SR_RIP.RetryCount < 0xfe) {
+
+ if (RipReserved->u.SR_RIP.Network != 0xffffffff) {
+
+ IPX_DEBUG (RIP, ("Timing out RIP for network %lx\n",
+ REORDER_ULONG(RipReserved->u.SR_RIP.Network)));
+
+ Segment = RipGetSegment ((PUCHAR)&RipReserved->u.SR_RIP.Network);
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Fail all datagrams, etc. that were waiting for
+ // this route. This call releases the lock.
+ //
+
+ RipHandleRoutePending(
+ Device,
+ (PUCHAR)&(RipReserved->u.SR_RIP.Network),
+ LockHandle,
+ FALSE,
+ NULL,
+ 0,
+ 0);
+
+ } else {
+
+ //
+ // This was the initial query looking for networks --
+ // signal the init thread which is waiting.
+ //
+
+ IPX_DEBUG (AUTO_DETECT, ("Signalling auto-detect event\n"));
+ KeSetEvent(
+ &Device->AutoDetectEvent,
+ 0L,
+ FALSE);
+
+ }
+
+ } else if (RipReserved->u.SR_RIP.RetryCount == 0xff) {
+
+ //
+ // This is a DOWN message, set the device event that
+ // is waiting for it to complete.
+ //
+
+ KeSetEvent(
+ &Device->UnloadEvent,
+ 0L,
+ FALSE);
+ }
+
+ //
+ // Put the RIP packet back in the pool.
+ //
+
+ RipReserved->Identifier = IDENTIFIER_IPX;
+
+} /* RipCleanupPacket */
+
+
+VOID
+RipProcessResponse(
+ IN PDEVICE Device,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN RIP_PACKET UNALIGNED * RipPacket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a RIP response from the specified
+ local target, indicating a route to the network in the RIP
+ header.
+
+Arguments:
+
+ Device - The device.
+
+ LocalTarget - The router that the frame was received from.
+
+ RipPacket - The RIP response header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED RipReserved; // ProtocolReserved of RIP packet
+ ULONG Segment;
+ PIPX_ROUTE_ENTRY RouteEntry, OldRouteEntry;
+ PLIST_ENTRY p;
+ IPX_DEFINE_LOCK_HANDLE_PARAM (LockHandle)
+
+ //
+ // Since we have received a RIP response for this network.
+ // kill the waiting RIP packets for it if it exists.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (p = Device->WaitingRipPackets.Flink;
+ p != &Device->WaitingRipPackets;
+ p = p->Flink) {
+
+ RipReserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
+
+ if (RipReserved->u.SR_RIP.RetryCount >= 0xfe) {
+ continue;
+ }
+
+ if (RipReserved->u.SR_RIP.Network ==
+ RipPacket->NetworkEntry.NetworkNumber) {
+ break;
+ }
+
+ }
+
+ if (p == &Device->WaitingRipPackets) {
+
+ //
+ // No packets pending on this, return.
+ //
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+
+ //
+ // Put the RIP packet back in the pool.
+ //
+
+ IPX_DEBUG (RIP, ("Got RIP response for network %lx\n",
+ REORDER_ULONG(RipPacket->NetworkEntry.NetworkNumber)));
+
+ RipReserved->u.SR_RIP.RouteFound = TRUE;
+ if (!RipReserved->SendInProgress) {
+
+ //
+ // If the send is done destroy it now, otherwise
+ // when it pops up in RipShortTimeout it will get
+ // destroyed because RouteFound is TRUE.
+ //
+
+ RemoveEntryList (p);
+ RipReserved->Identifier = IDENTIFIER_IPX;
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &RipReserved->PoolLinkage, &Device->SListsLock);
+ --Device->RipPacketCount;
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ IpxDereferenceDevice (Device, DREF_RIP_PACKET);
+
+ } else {
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+
+
+ //
+ // Try to allocate and add a router segment unless the
+ // RIP router is active...if we don't that is fine, we'll
+ // just re-RIP later.
+ //
+
+ Segment = RipGetSegment ((PUCHAR)&RipPacket->NetworkEntry.NetworkNumber);
+
+ if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
+
+ RouteEntry = IpxAllocateMemory(sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ if (RouteEntry != (PIPX_ROUTE_ENTRY)NULL) {
+
+ *(UNALIGNED LONG *)RouteEntry->Network = RipPacket->NetworkEntry.NetworkNumber;
+#ifdef _PNP_POWER
+ RouteEntry->NicId = NIC_FROM_LOCAL_TARGET(LocalTarget);
+ RouteEntry->NdisBindingContext = NIC_ID_TO_BINDING(Device, RouteEntry->NicId)->Adapter->NdisBindingHandle;
+ // BUGBUG: What if this is NULL??
+#else
+ RouteEntry->NicId = LocalTarget->NicId;
+ RouteEntry->NdisBindingContext = Device->Bindings[LocalTarget->NicId]->Adapter->NdisBindingHandle; // BUGBUG: What if this is NULL??
+#endif
+ RouteEntry->Flags = 0;
+ RouteEntry->Timer = 0;
+ RouteEntry->PRIVATE.Reserved[0] = 0;
+ RouteEntry->Segment = Segment;
+ RouteEntry->HopCount = REORDER_USHORT(RipPacket->NetworkEntry.HopCount);
+ RouteEntry->TickCount = REORDER_USHORT(RipPacket->NetworkEntry.TickCount);
+ InitializeListHead (&RouteEntry->AlternateRoute);
+ InitializeListHead (&RouteEntry->NicLinkage);
+ RtlCopyMemory (RouteEntry->NextRouter, LocalTarget->MacAddress, 6);
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Replace any existing routes. This is OK because once
+ // we get the first response to a RIP packet on a given
+ // route, we will take the packet out of the queue and
+ // ignore further responses. We will only get a bad route
+ // if we do two requests really quickly and there
+ // are two routes, and the second response to the first
+ // request is picked up as the first response to the second
+ // request.
+ //
+
+ if ((OldRouteEntry = RipGetRoute (Segment, (PUCHAR)&(RipPacket->NetworkEntry.NetworkNumber))) != NULL) {
+
+ //
+ // These are saved so timeouts etc. happen right.
+ //
+
+ RouteEntry->Flags = OldRouteEntry->Flags;
+ RouteEntry->Timer = OldRouteEntry->Timer;
+
+ RipDeleteRoute (Segment, OldRouteEntry);
+ IpxFreeMemory(OldRouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+
+ }
+
+ RipAddRoute (Segment, RouteEntry);
+
+ } else {
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+ }
+
+ } else {
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+ }
+
+ //
+ // Complete all datagrams etc. that were waiting
+ // for this route. This call releases the lock.
+ //
+
+ RipHandleRoutePending(
+ Device,
+ (PUCHAR)&(RipPacket->NetworkEntry.NetworkNumber),
+ LockHandle,
+ TRUE,
+ LocalTarget,
+ (USHORT)(REORDER_USHORT(RipPacket->NetworkEntry.HopCount)),
+ (USHORT)(REORDER_USHORT(RipPacket->NetworkEntry.TickCount))
+ );
+
+} /* RipProcessResponse */
+
+VOID
+RipHandleRoutePending(
+ IN PDEVICE Device,
+ IN UCHAR Network[4],
+ IN CTELockHandle LockHandle,
+ IN BOOLEAN Success,
+ IN OPTIONAL PIPX_LOCAL_TARGET LocalTarget,
+ IN OPTIONAL USHORT HopCount,
+ IN OPTIONAL USHORT TickCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine cleans up pending datagrams, find route
+ requests, and GET_LOCAL_TARGET ioctls that were
+ waiting for a route to be found.
+
+ THIS ROUTINE IS CALLED WITH THE SEGMENT LOCK HELD AND
+ RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Device - The device.
+
+ Network - The network in question.
+
+ LockHandle - The handle used to acquire the lock.
+
+ Success - TRUE if the route was successfully found.
+
+ LocalTarget - If Success is TRUE, the local target for the route.
+
+ HopCount - If Success is TRUE, the hop count for the route,
+ in machine order.
+
+ TickCount - If Success is TRUE, the tick count for the route,
+ in machine order.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ LIST_ENTRY DatagramList;
+ LIST_ENTRY FindRouteList;
+ LIST_ENTRY GetLocalTargetList;
+ LIST_ENTRY ReripNetnumList;
+ PIPX_SEND_RESERVED WaitReserved; // ProtocolReserved of waiting packet
+ PIPX_FIND_ROUTE_REQUEST FindRouteRequest;
+ PREQUEST GetLocalTargetRequest;
+ PREQUEST ReripNetnumRequest;
+ PISN_ACTION_GET_LOCAL_TARGET GetLocalTarget;
+ PIPX_NETNUM_DATA NetnumData;
+ ULONG Segment;
+ PBINDING Binding, SendBinding;
+ PLIST_ENTRY p;
+ PNDIS_PACKET Packet;
+ PIPX_HEADER IpxHeader;
+ ULONG HeaderSize;
+ NDIS_STATUS NdisStatus;
+ ULONG NetworkUlong = *(UNALIGNED ULONG *)Network;
+
+
+ InitializeListHead (&DatagramList);
+ InitializeListHead (&FindRouteList);
+ InitializeListHead (&GetLocalTargetList);
+ InitializeListHead (&ReripNetnumList);
+
+
+ //
+ // Put all packets that were waiting for a route to
+ // this network on DatagramList. They will be sent
+ // or failed later in the routine.
+ //
+
+ Segment = RipGetSegment (Network);
+
+ p = Device->Segments[Segment].WaitingForRoute.Flink;
+
+ while (p != &Device->Segments[Segment].WaitingForRoute) {
+
+ WaitReserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
+ p = p->Flink;
+#if 0
+ if (*(UNALIGNED ULONG *)(((PIPX_HEADER)(&WaitReserved->Header[Device->IncludedHeaderOffset]))->DestinationNetwork) ==
+ NetworkUlong) {
+#endif
+ if (*(UNALIGNED ULONG *)(((PIPX_HEADER)(&WaitReserved->Header[MAC_HEADER_SIZE]))->DestinationNetwork) ==
+ NetworkUlong) {
+
+ RemoveEntryList (&WaitReserved->WaitLinkage);
+ InsertTailList (&DatagramList, &WaitReserved->WaitLinkage);
+ }
+
+ }
+
+ //
+ // Put all find route requests for this network on
+ // FindRouteList. They will be completed later in the
+ // routine.
+ //
+
+ p = Device->Segments[Segment].FindWaitingForRoute.Flink;
+
+ while (p != &Device->Segments[Segment].FindWaitingForRoute) {
+
+ FindRouteRequest = CONTAINING_RECORD (p, IPX_FIND_ROUTE_REQUEST, Linkage);
+ p = p->Flink;
+ if (*(UNALIGNED ULONG *)(FindRouteRequest->Network) ==
+ NetworkUlong) {
+
+ RemoveEntryList (&FindRouteRequest->Linkage);
+ InsertTailList (&FindRouteList, &FindRouteRequest->Linkage);
+ }
+
+ }
+
+ //
+ // Put all get local target action requests for this
+ // network on GetLocalTargetList. They will be completed
+ // later in the routine.
+ //
+
+ p = Device->Segments[Segment].WaitingLocalTarget.Flink;
+
+ while (p != &Device->Segments[Segment].WaitingLocalTarget) {
+
+ GetLocalTargetRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+ GetLocalTarget = (PISN_ACTION_GET_LOCAL_TARGET)REQUEST_INFORMATION(GetLocalTargetRequest);
+ if (GetLocalTarget->IpxAddress.NetworkAddress == NetworkUlong) {
+
+ RemoveEntryList (REQUEST_LINKAGE(GetLocalTargetRequest));
+ InsertTailList (&GetLocalTargetList, REQUEST_LINKAGE(GetLocalTargetRequest));
+ }
+
+ }
+
+ //
+ // Put all MIPX_RERIPNETNUM action requests for this
+ // network on ReripNetnumList. They will be completed
+ // later in the routine.
+ //
+
+ p = Device->Segments[Segment].WaitingReripNetnum.Flink;
+
+ while (p != &Device->Segments[Segment].WaitingReripNetnum) {
+
+ ReripNetnumRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+ NetnumData = (PIPX_NETNUM_DATA)REQUEST_INFORMATION(ReripNetnumRequest);
+ if (*(UNALIGNED ULONG *)NetnumData->netnum == NetworkUlong) {
+
+ RemoveEntryList (REQUEST_LINKAGE(ReripNetnumRequest));
+ InsertTailList (&ReripNetnumList, REQUEST_LINKAGE(ReripNetnumRequest));
+ }
+
+ }
+
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+
+ //
+ // For sends we will use the master binding of a binding
+ // set, but we'll return the real NicId for people who
+ // want that.
+ //
+
+ if (Success) {
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget));
+
+ if (Binding->BindingSetMember) {
+ SendBinding = Binding->MasterBinding;
+ FILL_LOCAL_TARGET(LocalTarget, MIN( Device->MaxBindings, SendBinding->NicId));
+ } else {
+ SendBinding = Binding;
+ }
+#else
+ Binding = Device->Bindings[LocalTarget->NicId];
+
+ if (Binding->BindingSetMember) {
+ SendBinding = Binding->MasterBinding;
+ LocalTarget->NicId = SendBinding->NicId;
+ } else {
+ SendBinding = Binding;
+ }
+#endif
+ }
+
+
+ //
+ // Now that the lock is free, process all packets on
+ // DatagramList.
+ //
+ // NOTE: May misorder packets if they come in right now...
+ //
+
+ for (p = DatagramList.Flink; p != &DatagramList ; ) {
+
+ WaitReserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
+ p = p->Flink;
+ Packet = CONTAINING_RECORD (WaitReserved, NDIS_PACKET, ProtocolReserved[0]);
+
+#if DBG
+ CTEAssert (!WaitReserved->SendInProgress);
+ WaitReserved->SendInProgress = TRUE;
+#endif
+
+ if (Success) {
+
+ IPX_DEBUG (RIP, ("Found queued packet %lx\n", WaitReserved));
+
+ if (REQUEST_INFORMATION(WaitReserved->u.SR_DG.Request) >
+ SendBinding->RealMaxDatagramSize) {
+
+ IPX_DEBUG (SEND, ("Queued send %d bytes too large (%d)\n",
+ REQUEST_INFORMATION(WaitReserved->u.SR_DG.Request),
+ SendBinding->RealMaxDatagramSize));
+
+ IpxSendComplete(
+ (NDIS_HANDLE)NULL,
+ Packet,
+ STATUS_INVALID_BUFFER_SIZE);
+
+ } else {
+
+#if 0
+ if (WaitReserved->DestinationType == DESTINATION_DEF) {
+ HeaderSize = SendBinding->DefHeaderSize;
+ } else {
+ HeaderSize = SendBinding->BcMcHeaderSize;
+ }
+
+ IpxHeader = (PIPX_HEADER)
+ (&WaitReserved->Header[HeaderSize]);
+#endif
+ IpxHeader = (PIPX_HEADER)
+ (&WaitReserved->Header[MAC_HEADER_SIZE]);
+
+ //
+ // Move the header to the correct location now that
+ // we know the NIC ID to send to.
+ //
+#if 0
+ if (HeaderSize != Device->IncludedHeaderOffset) {
+
+ RtlMoveMemory(
+ IpxHeader,
+ &WaitReserved->Header[Device->IncludedHeaderOffset],
+ sizeof(IPX_HEADER));
+
+ }
+#endif
+
+ if (Device->MultiCardZeroVirtual ||
+ (IpxHeader->DestinationSocket == SAP_SOCKET)) {
+
+ //
+ // These frames need to look like they come from the
+ // local network, not the virtual one.
+ //
+
+ *(UNALIGNED ULONG *)IpxHeader->SourceNetwork = SendBinding->LocalAddress.NetworkAddress;
+ RtlCopyMemory (IpxHeader->SourceNode, SendBinding->LocalAddress.NodeAddress, 6);
+ }
+
+ //
+ // Fill in the MAC header and submit the frame to NDIS.
+ //
+
+ if ((NdisStatus = IpxSendFrame(
+ LocalTarget,
+ Packet,
+ REQUEST_INFORMATION(WaitReserved->u.SR_DG.Request) + sizeof(IPX_HEADER),
+ sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ IpxSendComplete(
+ (NDIS_HANDLE)SendBinding->Adapter,
+ Packet,
+ NdisStatus);
+ }
+
+ }
+
+ } else {
+
+ IPX_DEBUG (RIP, ("Timing out packet %lx\n", WaitReserved));
+
+ IpxSendComplete(
+ (NDIS_HANDLE)NULL,
+ Packet,
+ STATUS_BAD_NETWORK_PATH);
+
+ }
+
+ }
+
+
+ //
+ // Since we round-robin outgoing rip packets, we just use the
+ // real NicId here for find route and get local target requests.
+ // We changed LocalTarget->NicId to be the master above.
+ //
+
+ if (Success) {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, MIN( Device->MaxBindings, Binding->NicId));
+#else
+ LocalTarget->NicId = Binding->NicId;
+#endif
+ }
+
+ for (p = FindRouteList.Flink; p != &FindRouteList ; ) {
+
+ FindRouteRequest = CONTAINING_RECORD (p, IPX_FIND_ROUTE_REQUEST, Linkage);
+ p = p->Flink;
+
+ if (Success) {
+
+ PUSHORT Counts;
+
+ IPX_DEBUG (RIP, ("Found queued find route %lx\n", FindRouteRequest));
+ FindRouteRequest->LocalTarget = *LocalTarget;
+
+ Counts = (PUSHORT)&FindRouteRequest->Reserved2;
+ Counts[0] = TickCount;
+ Counts[1] = HopCount;
+
+ } else {
+
+ IPX_DEBUG (RIP, ("Timing out find route %lx\n", FindRouteRequest));
+
+ }
+
+ (*Device->UpperDrivers[FindRouteRequest->Identifier].FindRouteCompleteHandler)(
+ FindRouteRequest,
+ Success);
+
+ }
+
+ for (p = GetLocalTargetList.Flink; p != &GetLocalTargetList ; ) {
+
+ GetLocalTargetRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+ GetLocalTarget = (PISN_ACTION_GET_LOCAL_TARGET)REQUEST_INFORMATION(GetLocalTargetRequest);
+
+ if (Success) {
+
+ IPX_DEBUG (RIP, ("Found queued LOCAL_TARGET action %lx\n", GetLocalTargetRequest));
+ GetLocalTarget->LocalTarget = *LocalTarget;
+ REQUEST_INFORMATION(GetLocalTargetRequest) = sizeof(ISN_ACTION_GET_LOCAL_TARGET);
+ REQUEST_STATUS(GetLocalTargetRequest) = STATUS_SUCCESS;
+
+ } else {
+
+ IPX_DEBUG (RIP, ("Timing out LOCAL_TARGET action %lx\n", GetLocalTargetRequest));
+ REQUEST_INFORMATION(GetLocalTargetRequest) = 0;
+ REQUEST_STATUS(GetLocalTargetRequest) = STATUS_BAD_NETWORK_PATH;
+ }
+
+ IpxCompleteRequest(GetLocalTargetRequest);
+ IpxFreeRequest(Device, GetLocalTargetRequest);
+
+ }
+
+ //
+ // NOTE: LocalTarget->NicId now points to the real binding
+ // not the master, so we use SendBinding->NicId below.
+ //
+
+ for (p = ReripNetnumList.Flink; p != &ReripNetnumList ; ) {
+
+ ReripNetnumRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+ NetnumData = (PIPX_NETNUM_DATA)REQUEST_INFORMATION(ReripNetnumRequest);
+
+ if (Success) {
+
+ IPX_DEBUG (RIP, ("Found queued MIPX_RERIPNETNUM action %lx\n", ReripNetnumRequest));
+ NetnumData->hopcount = HopCount;
+ NetnumData->netdelay = TickCount;
+ NetnumData->cardnum = (INT)(MIN( Device->MaxBindings, SendBinding->NicId) - 1);
+ RtlMoveMemory (NetnumData->router, LocalTarget->MacAddress, 6);
+
+ REQUEST_INFORMATION(ReripNetnumRequest) =
+ FIELD_OFFSET(NWLINK_ACTION, Data[0]) + sizeof(IPX_NETNUM_DATA);
+ REQUEST_STATUS(ReripNetnumRequest) = STATUS_SUCCESS;
+
+ } else {
+
+ IPX_DEBUG (RIP, ("Timing out MIPX_RERIPNETNUM action %lx\n", ReripNetnumRequest));
+ REQUEST_INFORMATION(ReripNetnumRequest) = 0;
+ REQUEST_STATUS(ReripNetnumRequest) = STATUS_BAD_NETWORK_PATH;
+ }
+
+ IpxCompleteRequest(ReripNetnumRequest);
+ IpxFreeRequest(Device, ReripNetnumRequest);
+
+ }
+
+} /* RipHandleRoutePending */
+
+
+NTSTATUS
+RipInsertLocalNetwork(
+ IN ULONG Network,
+ IN USHORT NicId,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN USHORT Count
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a router entry for a local network
+ and inserts it in the table.
+
+Arguments:
+
+ Network - The network.
+
+ NicId - The NIC ID used to route packets
+
+ NdisBindingHandle - The binding handle used for NdisSend
+
+ Count - The tick and hop count for this network (will be
+ 0 for the virtual net and 1 for attached nets)
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+ PIPX_ROUTE_ENTRY RouteEntry;
+ PDEVICE Device = IpxDevice;
+ ULONG Segment;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // BUGBUG: We should allocate the memory in the binding/device
+ // structure itself.
+ //
+
+ RouteEntry = IpxAllocateMemory(sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ if (RouteEntry == (PIPX_ROUTE_ENTRY)NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Segment = RipGetSegment ((PUCHAR)&Network);
+
+ *(UNALIGNED LONG *)RouteEntry->Network = Network;
+ RouteEntry->NicId = NicId;
+ RouteEntry->NdisBindingContext = NdisBindingContext;
+
+ if (NicId == 0) {
+ RouteEntry->Flags = IPX_ROUTER_PERMANENT_ENTRY;
+ } else {
+ RouteEntry->Flags = IPX_ROUTER_PERMANENT_ENTRY | IPX_ROUTER_LOCAL_NET;
+ }
+ RouteEntry->Segment = Segment;
+ RouteEntry->TickCount = Count;
+ RouteEntry->HopCount = 1;
+ InitializeListHead (&RouteEntry->AlternateRoute);
+ InitializeListHead (&RouteEntry->NicLinkage);
+
+ //
+ // RouteEntry->NextRouter is not used for the virtual net or
+ // when LOCAL_NET is set (i.e. every net that we will add here).
+ //
+
+ RtlZeroMemory (RouteEntry->NextRouter, 6);
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Make sure one doesn't exist.
+ //
+
+ if (RipGetRoute(Segment, (PUCHAR)&Network) != NULL) {
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ IpxFreeMemory (RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ return STATUS_DUPLICATE_NAME;
+ }
+
+ //
+ // Add this new entry.
+ //
+
+ if (RipAddRoute (Segment, RouteEntry)) {
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ return STATUS_SUCCESS;
+
+ } else {
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ IpxFreeMemory (RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+} /* RipInsertLocalNetwork */
+
+
+VOID
+RipAdjustForBindingChange(
+ IN USHORT NicId,
+ IN USHORT NewNicId,
+ IN IPX_BINDING_CHANGE_TYPE ChangeType
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when an auto-detect binding is
+ deleted or moved, or a WAN line goes down.
+
+ It scans the RIP database for routes equal to this NIC ID
+ and modifies them appropriately. If ChangeType is
+ IpxBindingDeleted it will subract one from any NIC IDs
+ in the database that are higher than NicId. It is assumed
+ that other code is readjusting the Device->Bindings
+ array.
+
+Arguments:
+
+ NicId - The NIC ID of the deleted binding.
+
+ NewNicId - The new NIC ID, for IpxBindingMoved changes.
+
+ ChangeType - Either IpxBindingDeleted, IpxBindingMoved,
+ or IpxBindingDown.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ UINT Segment;
+ CTELockHandle LockHandle;
+
+ for (Segment = 0; Segment < Device->SegmentCount; Segment++) {
+
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Scan through each entry comparing the NIC ID.
+ //
+
+ for (RouteEntry = RipGetFirstRoute (Segment);
+ RouteEntry != (PIPX_ROUTE_ENTRY)NULL;
+ RouteEntry = RipGetNextRoute (Segment)) {
+
+ if (RouteEntry->NicId == NicId) {
+
+ if (ChangeType != IpxBindingMoved) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Deleting route entry %lx, binding deleted\n", RouteEntry));
+ RipDeleteRoute (Segment, RouteEntry);
+
+ } else {
+
+ IPX_DEBUG (AUTO_DETECT, ("Changing NIC ID for route entry %lx\n", RouteEntry));
+ RouteEntry->NicId = NewNicId;
+
+ }
+#ifdef _PNP_POWER
+ //
+ // If the NicId is 0, we dont adjust the other entries' NicId's - this is to support the removal
+ // of the Virtual Net # which resides at NicId=0.
+ //
+ } else if (NicId && (ChangeType != IpxBindingDown) && (RouteEntry->NicId > NicId)) {
+#else
+ } else if ((ChangeType != IpxBindingDown) && (RouteEntry->NicId > NicId)) {
+#endif
+ IPX_DEBUG (AUTO_DETECT, ("Decrementing NIC ID for route entry %lx\n", RouteEntry));
+ --RouteEntry->NicId;
+
+ }
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+
+ }
+
+} /* RipAdjustForBindingChange */
+
+
+UINT
+RipGetSegment(
+ IN UCHAR Network[4]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the correct segment for the specified
+ network.
+
+Arguments:
+
+ Network - The network.
+
+Return Value:
+
+ The segment.
+
+--*/
+
+{
+
+ ULONG Total;
+
+ Total = Network[0] ^ Network[1] ^ Network[2] ^ Network[3];
+ return (Total % IpxDevice->SegmentCount);
+
+} /* RipGetSegment */
+
+
+PIPX_ROUTE_ENTRY
+RipGetRoute(
+ IN UINT Segment,
+ IN UCHAR Network[4]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the router table entry for the given
+ network, which is in the specified segment of the table.
+ THE SEGMENT LOCK MUST BE HELD. The returned data is valid
+ until the segment lock is released or other operations
+ (add/delete) are performed on the segment.
+
+Arguments:
+
+ Segment - The segment corresponding to the network.
+
+ Network - The network.
+
+Return Value:
+
+ The router table entry, or NULL if none exists for this network.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PROUTER_SEGMENT RouterSegment;
+ PIPX_ROUTE_ENTRY RouteEntry;
+
+ RouterSegment = &IpxDevice->Segments[Segment];
+
+ for (p = RouterSegment->Entries.Flink;
+ p != &RouterSegment->Entries;
+ p = p->Flink) {
+
+ RouteEntry = CONTAINING_RECORD(
+ p,
+ IPX_ROUTE_ENTRY,
+ PRIVATE.Linkage);
+
+ if ((*(UNALIGNED LONG *)RouteEntry->Network) ==
+ (*(UNALIGNED LONG *)Network)) {
+ return RouteEntry;
+ }
+ }
+
+ return NULL;
+
+} /* RipGetRoute */
+
+
+BOOLEAN
+RipAddRoute(
+ IN UINT Segment,
+ IN PIPX_ROUTE_ENTRY RouteEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stores a router table entry in the
+ table, which must belong in the specified segment.
+ THE SEGMENT LOCK MUST BE HELD. Storage for the entry
+ is allocated and filled in by the caller.
+
+Arguments:
+
+ Segment - The segment corresponding to the network.
+
+ RouteEntry - The router table entry.
+
+Return Value:
+
+ TRUE if the entry was successfully inserted.
+
+--*/
+
+{
+
+ IPX_DEBUG (RIP, ("Adding route for network %lx (%d)\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)RouteEntry->Network), Segment));
+ InsertTailList(
+ &IpxDevice->Segments[Segment].Entries,
+ &RouteEntry->PRIVATE.Linkage);
+
+ return TRUE;
+
+} /* RipAddRoute */
+
+
+BOOLEAN
+RipDeleteRoute(
+ IN UINT Segment,
+ IN PIPX_ROUTE_ENTRY RouteEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deletes a router table entry in the
+ table, which must belong in the specified segment.
+ THE SEGMENT LOCK MUST BE HELD. Storage for the entry
+ is freed by the caller.
+
+Arguments:
+
+ Segment - The segment corresponding to the network.
+
+ RouteEntry - The router table entry.
+
+Return Value:
+
+ TRUE if the entry was successfully deleted.
+
+--*/
+
+{
+
+ PROUTER_SEGMENT RouterSegment = &IpxDevice->Segments[Segment];
+
+ IPX_DEBUG (RIP, ("Deleting route for network %lx (%d)\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)RouteEntry->Network), Segment));
+
+ //
+ // If the current enumeration point for this segment is here,
+ // adjust the pointer before deleting the entry. We make it
+ // point to the previous entry so GetNextRoute will work.
+ //
+
+ if (RouterSegment->EnumerateLocation == &RouteEntry->PRIVATE.Linkage) {
+ RouterSegment->EnumerateLocation = RouterSegment->EnumerateLocation->Blink;
+ }
+
+ RemoveEntryList (&RouteEntry->PRIVATE.Linkage);
+
+ return TRUE;
+
+} /* RipDeleteRoute */
+
+
+PIPX_ROUTE_ENTRY
+RipGetFirstRoute(
+ IN UINT Segment
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the first router table entry in the
+ segment. THE SEGMENT LOCK MUST BE HELD. It is used in
+ conjunction with RipGetNextRoute to enumerate all the
+ entries in a segment.
+
+Arguments:
+
+ Segment - The segment being enumerated.
+
+Return Value:
+
+ The first router table entry, or NULL if the segment is empty.
+
+--*/
+
+{
+ PIPX_ROUTE_ENTRY FirstEntry;
+ PROUTER_SEGMENT RouterSegment = &IpxDevice->Segments[Segment];
+
+ RouterSegment->EnumerateLocation = RouterSegment->Entries.Flink;
+
+ if (RouterSegment->EnumerateLocation == &RouterSegment->Entries) {
+
+ return NULL;
+
+ } else {
+
+ FirstEntry = CONTAINING_RECORD(
+ RouterSegment->EnumerateLocation,
+ IPX_ROUTE_ENTRY,
+ PRIVATE.Linkage);
+
+ return FirstEntry;
+
+ }
+
+} /* RipGetFirstRoute */
+
+
+PIPX_ROUTE_ENTRY
+RipGetNextRoute(
+ IN UINT Segment
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the next router table entry in the
+ segment. THE SEGMENT LOCK MUST BE HELD. It is used in
+ conjunction with RipGetFirstRoute to enumerate all the
+ entries in a segment.
+
+ It is illegal to call RipGetNextRoute on a segment
+ without first calling RipGetFirstRoute. The segment
+ lock must be held for the duration of the enumeration
+ of a single segment. It is legal to stop enumerating
+ the segment in the middle.
+
+Arguments:
+
+ Segment - The segment being enumerated.
+
+Return Value:
+
+ The next router table entry, or NULL if the end of the
+ segment is reached.
+
+--*/
+
+{
+ PIPX_ROUTE_ENTRY NextEntry;
+ PROUTER_SEGMENT RouterSegment = &IpxDevice->Segments[Segment];
+
+ RouterSegment->EnumerateLocation = RouterSegment->EnumerateLocation->Flink;
+
+ if (RouterSegment->EnumerateLocation == &RouterSegment->Entries) {
+
+ return NULL;
+
+ } else {
+
+ NextEntry = CONTAINING_RECORD(
+ RouterSegment->EnumerateLocation,
+ IPX_ROUTE_ENTRY,
+ PRIVATE.Linkage);
+
+ return NextEntry;
+
+ }
+
+} /* RipGetNextRoute */
+
+
+VOID
+RipDropRemoteEntries(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deletes all non-local entries from the
+ RIP database. It is called when the WAN line goes up
+ or down and we want to remove all existing entries.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ UINT Segment;
+ CTELockHandle LockHandle;
+
+ for (Segment = 0; Segment < Device->SegmentCount; Segment++) {
+
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Scan through, deleting everything but local entries.
+ //
+
+ for (RouteEntry = RipGetFirstRoute (Segment);
+ RouteEntry != (PIPX_ROUTE_ENTRY)NULL;
+ RouteEntry = RipGetNextRoute (Segment)) {
+
+ if ((RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY) == 0) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Deleting route entry %lx, dropping remote entries\n", RouteEntry));
+ RipDeleteRoute (Segment, RouteEntry);
+
+ }
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+
+ }
+
+} /* RipDropRemoteEntries */
+
diff --git a/private/ntos/tdi/isnp/ipx/send.c b/private/ntos/tdi/isnp/ipx/send.c
new file mode 100644
index 000000000..fd9a62a7d
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/send.c
@@ -0,0 +1,1651 @@
+
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ This module contains code that implements the send engine for the
+ IPX transport provider.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - August-25-1995
+ Bug Fixes - tagged [SA]
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// BUGBUG Using the macro for performance reasons. Should be taken out
+// when NdisQueryPacket is optimized. In the near future (after PPC release)
+// move this to a header file and use it at other places.
+//
+#define IPX_PACKET_HEAD(Pkt) (Pkt)->Private.Head
+
+#if 0
+#define IpxGetMdlChainLength(Mdl, Length) { \
+ PMDL _Mdl = (Mdl); \
+ *(Length) = 0; \
+ while (_Mdl) { \
+ *(Length) += MmGetMdlByteCount(_Mdl); \
+ _Mdl = _Mdl->Next; \
+ } \
+}
+#endif
+
+VOID
+IpxSendComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to indicate that a connection-
+ oriented packet has been shipped and is no longer needed by the Physical
+ Provider.
+
+Arguments:
+
+ ProtocolBindingContext - The ADAPTER structure for this binding.
+
+ NdisPacket/RequestHandle - A pointer to the NDIS_PACKET that we sent.
+
+ NdisStatus - the completion status of the send.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(NdisPacket->ProtocolReserved);
+ PADAPTER Adapter = (PADAPTER)ProtocolBindingContext;
+ PREQUEST Request;
+ PADDRESS_FILE AddressFile;
+ PDEVICE Device = IpxDevice;
+ PBINDING Binding;
+ USHORT NewId, OldId;
+ ULONG NewOffset, OldOffset;
+ PIPX_HEADER IpxHeader;
+ IPX_LOCAL_TARGET LocalTarget;
+ PIO_STACK_LOCATION irpSp;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+#if DBG
+ if (Adapter != NULL) {
+ ASSERT_ADAPTER(Adapter);
+ }
+#endif
+
+ //
+ // See if this send was padded.
+ //
+
+ if (Reserved->PaddingBuffer) {
+
+ UINT Offset;
+ //
+ // Check if we simply need to re-adjust the buffer length. This will
+ // happen if we incremented the buffer length in MAC.C.
+ //
+
+ if (Reserved->PreviousTail) {
+ CTEAssert (NDIS_BUFFER_LINKAGE(Reserved->PaddingBuffer->NdisBuffer) == NULL);
+ NDIS_BUFFER_LINKAGE (Reserved->PreviousTail) = (PNDIS_BUFFER)NULL;
+ } else {
+ PNDIS_BUFFER LastBuffer = (PNDIS_BUFFER)Reserved->PaddingBuffer;
+ UINT BufferLength;
+
+ NdisQueryBufferOffset( LastBuffer, &Offset, &BufferLength );
+ NdisAdjustBufferLength( LastBuffer, (BufferLength - 1) );
+ }
+
+ Reserved->PaddingBuffer = NULL;
+
+ if (Reserved->Identifier < IDENTIFIER_IPX) {
+ NdisRecalculatePacketCounts (NdisPacket);
+ }
+ }
+
+FunctionStart:;
+
+ switch (Reserved->Identifier) {
+
+ case IDENTIFIER_IPX:
+
+// #if DBG
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+// #endif
+
+ //
+ // Check if this packet should be sent to all
+ // networks.
+ //
+
+ if (Reserved->u.SR_DG.CurrentNicId) {
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+ Reserved->u.SR_DG.Net0SendSucceeded = TRUE;
+ }
+
+ OldId = Reserved->u.SR_DG.CurrentNicId;
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (NewId = OldId+1; NewId <= Index; NewId++) {
+ if ((Binding = NIC_ID_TO_BINDING(Device, NewId))
+#else
+ for (NewId = OldId+1; NewId <= Device->HighestExternalNicId; NewId++) {
+ if ((Binding = Device->Bindings[NewId])
+#endif _PNP_POWER
+ &&
+ ((!Device->SingleNetworkActive) ||
+ (Device->ActiveNetworkWan == Binding->Adapter->MacInfo.MediumAsync))
+ &&
+ ((!Device->DisableDialoutSap) ||
+ (!Binding->DialOutAsync) ||
+ (!Reserved->u.SR_DG.OutgoingSap))) {
+
+ //
+ // The binding exists, and we either are not configured
+ // for "SingleNetworkActive", or we are and this binding
+ // is the right type (i.e. the active network is wan and
+ // this is a wan binding, or the active network is not
+ // wan and this is not a wan binding), and this is not
+ // an outgoing sap that we are trying to send with
+ // "DisableDialoutSap" set.
+ //
+
+ break;
+ }
+ }
+ }
+
+ if (NewId <= MIN (Device->MaxBindings, Device->HighestExternalNicId)) {
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif _PNP_POWER
+
+ //
+ // Yes, we found another net to send it on, so
+ // move the header around if needed and do so.
+ //
+
+ Reserved->u.SR_DG.CurrentNicId = NewId;
+ CTEAssert ((Reserved->DestinationType == DESTINATION_BCAST) ||
+ (Reserved->DestinationType == DESTINATION_MCAST));
+
+#if 0
+ NewOffset = Binding->BcMcHeaderSize;
+ OldOffset = Device->Bindings[OldId]->BcMcHeaderSize;
+
+ if (OldOffset != NewOffset) {
+
+ RtlMoveMemory(
+ &Reserved->Header[NewOffset],
+ &Reserved->Header[OldOffset],
+ sizeof(IPX_HEADER));
+
+ }
+
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[NewOffset]);
+#endif
+
+
+
+#if BACK_FILL
+ // This should be a normal packet. Backfill packet is never used for
+ // reserved other than IPX type
+
+ CTEAssert(!Reserved->BackFill);
+#endif
+
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[MAC_HEADER_SIZE]);
+
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&LocalTarget, NewId);
+#else
+ LocalTarget.NicId = NewId;
+#endif
+ RtlCopyMemory(LocalTarget.MacAddress, IpxHeader->DestinationNode, 6);
+
+ if (Device->MultiCardZeroVirtual ||
+ (IpxHeader->DestinationSocket == SAP_SOCKET)) {
+
+ //
+ // SAP frames need to look like they come from the
+ // local network, not the virtual one. The same is
+ // true if we are running multiple nets without
+ // a virtual net.
+ //
+
+ *(UNALIGNED ULONG *)IpxHeader->SourceNetwork = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory (IpxHeader->SourceNode, Binding->LocalAddress.NodeAddress, 6);
+ }
+
+ //
+ // Fill in the MAC header and submit the frame to NDIS.
+ //
+
+// #if DBG
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+// #endif
+
+ if ((NdisStatus = IpxSendFrame(
+ &LocalTarget,
+ NdisPacket,
+ REQUEST_INFORMATION(Reserved->u.SR_DG.Request) + sizeof(IPX_HEADER),
+ sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ Adapter = Binding->Adapter;
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif _PNP_POWER
+ goto FunctionStart;
+ }
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif _PNP_POWER
+
+ return;
+
+ } else {
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif _PNP_POWER
+ //
+ // If any of the sends succeeded then return
+ // success on the datagram send, otherwise
+ // use the most recent failure status.
+ //
+
+ if (Reserved->u.SR_DG.Net0SendSucceeded) {
+ NdisStatus = NDIS_STATUS_SUCCESS;
+ }
+
+ }
+
+ }
+
+
+#if 0
+ //
+ // NOTE: We don't NULL out the linkage field of the
+ // HeaderBuffer, which will leave the old buffer chain
+ // hanging off it; but that is OK because if we reuse
+ // this packet we will replace that chain with the new
+ // one, and before we free it we NULL it out.
+ //
+ // I.e. we don't do this:
+ //
+
+ NDIS_BUFFER_LINKAGE (Reserved->HeaderBuffer) = NULL;
+ NdisRecalculatePacketCounts (NdisPacket);
+#endif
+
+#if 0
+ {
+ ULONG ActualLength;
+ IpxGetMdlChainLength(NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer), &ActualLength);
+ if (ActualLength != REQUEST_INFORMATION(Reserved->u.SR_DG.Request)) {
+ DbgPrint ("IPX: At completion, IRP %lx has parameter length %d, buffer chain length %d\n",
+ Reserved->u.SR_DG.Request, REQUEST_INFORMATION(Reserved->u.SR_DG.Request), ActualLength);
+ DbgBreakPoint();
+ }
+ }
+#endif
+
+ //
+ // Save these so we can free the packet.
+ //
+
+ Request = Reserved->u.SR_DG.Request;
+ AddressFile = Reserved->u.SR_DG.AddressFile;
+
+
+#if BACK_FILL
+ // Check if this is backfilled. If so restore users Mdl back to its original shape
+ // Also, push the packet on to backfillpacket queue if the packet is not owned by the address
+
+ if (Reserved->BackFill) {
+
+ Reserved->HeaderBuffer->MappedSystemVa = Reserved->MappedSystemVa;
+ Reserved->HeaderBuffer->ByteCount = Reserved->UserLength;
+ Reserved->HeaderBuffer->StartVa = (PCHAR)((ULONG)Reserved->HeaderBuffer->MappedSystemVa & ~(PAGE_SIZE-1));
+ Reserved->HeaderBuffer->ByteOffset = (ULONG)Reserved->HeaderBuffer->MappedSystemVa & (PAGE_SIZE-1);
+
+ IPX_DEBUG(SEND, ("completeing back filled userMdl %x\n",Reserved->HeaderBuffer));
+
+ NdisPacket->Private.ValidCounts = FALSE;
+
+ NdisPacket->Private.Head = NULL;
+ NdisPacket->Private.Tail = NULL;
+
+ Reserved->HeaderBuffer = NULL;
+
+ if (Reserved->OwnedByAddress) {
+
+ // Reserved->Address->BackFillPacketInUse = FALSE;
+ InterlockedDecrement(&Reserved->Address->BackFillPacketInUse);
+
+ IPX_DEBUG(SEND, ("Freeing owned backfill %x\n", Reserved));
+
+ } else {
+
+ IPX_PUSH_ENTRY_LIST(
+ &Device->BackFillPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+ }
+ }
+ // not a back fill packet. Push it on sendpacket pool
+ else {
+
+ if (Reserved->OwnedByAddress) {
+
+ // Reserved->Address->SendPacketInUse = FALSE;
+ InterlockedDecrement(&Reserved->Address->SendPacketInUse);
+
+ } else {
+
+ IPX_PUSH_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+
+ }
+
+
+ }
+
+#else
+
+ if (Reserved->OwnedByAddress) {
+
+
+ Reserved->Address->SendPacketInUse = FALSE;
+
+ } else {
+
+ IPX_PUSH_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+
+ }
+#endif
+
+ ++Device->Statistics.PacketsSent;
+
+ //
+ // If this is a fast send irp, we bypass the file system and
+ // call the completion routine directly.
+ //
+
+ REQUEST_STATUS(Request) = NdisStatus;
+ irpSp = IoGetCurrentIrpStackLocation( Request );
+
+ if ( irpSp->MinorFunction == TDI_DIRECT_SEND_DATAGRAM ) {
+
+ Request->CurrentLocation++,
+ Request->Tail.Overlay.CurrentStackLocation++;
+
+ (VOID) irpSp->CompletionRoutine(
+ NULL,
+ Request,
+ irpSp->Context
+ );
+
+ } else {
+ IpxCompleteRequest (Request);
+ }
+
+ IpxFreeRequest(Device, Request);
+
+ IpxDereferenceAddressFileSync (AddressFile, AFREF_SEND_DGRAM);
+
+ break;
+
+ case IDENTIFIER_RIP_INTERNAL:
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+ break;
+
+ case IDENTIFIER_RIP_RESPONSE:
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ Reserved->Identifier = IDENTIFIER_IPX;
+ IPX_PUSH_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+
+ IpxDereferenceDevice (Device, DREF_RIP_PACKET);
+ break;
+
+#ifdef _PNP_POWER
+ case IDENTIFIER_NB:
+ case IDENTIFIER_SPX:
+
+ //
+ // See if this is an iterative send
+ //
+ if (OldId = Reserved->CurrentNicId) {
+
+ PNDIS_BUFFER HeaderBuffer;
+ UINT TempHeaderBufferLength;
+ PUCHAR Header;
+ PIPX_HEADER IpxHeader;
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+ Reserved->Net0SendSucceeded = TRUE;
+ }
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (NewId = OldId+1; NewId <= Index; NewId++) {
+ if (Binding = NIC_ID_TO_BINDING(Device, NewId)) {
+ //
+ // Found next NIC to send on
+ //
+ break;
+ }
+ }
+ }
+
+ if (NewId <= MIN (Device->MaxBindings, Device->HighestExternalNicId)) {
+
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // Yes, we found another net to send it on, so
+ // move the header around if needed and do so.
+ //
+ IPX_DEBUG(SEND, ("ISN iteration: OldId: %lx, NewId: %lx\n", OldId, NewId));
+ Reserved->CurrentNicId = NewId;
+#if 0
+ NewOffset = Binding->BcMcHeaderSize;
+ OldOffset = Device->Bindings[OldId]->BcMcHeaderSize;
+
+ if (OldOffset != NewOffset) {
+
+ RtlMoveMemory(
+ &Reserved->Header[NewOffset],
+ &Reserved->Header[OldOffset],
+ sizeof(IPX_HEADER));
+
+ }
+
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[NewOffset]);
+
+
+#if BACK_FILL
+ // This should be a normal packet. Backfill packet is never used for
+ // reserved other than IPX type
+
+ CTEAssert(!Reserved->BackFill);
+#endif
+#endif
+
+ NdisQueryPacket (NdisPacket, NULL, NULL, &HeaderBuffer, NULL);
+ NdisQueryBuffer(HeaderBuffer, &Header, &TempHeaderBufferLength);
+
+ IpxHeader = (PIPX_HEADER)(&Header[Device->IncludedHeaderOffset]);
+
+ IPX_DEBUG(SEND, ("SendComplete: IpxHeader: %lx\n", IpxHeader));
+ FILL_LOCAL_TARGET(&Reserved->LocalTarget, NewId);
+
+ //
+ // We don't need to so this since the macaddress is replaced in
+ // IpxSendFrame anyway. The LocalTarget is the same as the one on
+ // the original send - this is passed down for further sends.
+ //
+ // RtlCopyMemory(LocalTarget.MacAddress, IpxHeader->DestinationNode, 6);
+
+ //
+ // Fill in the MAC header and submit the frame to NDIS.
+ //
+
+ if ((NdisStatus = IpxSendFrame(
+ &Reserved->LocalTarget,
+ NdisPacket,
+ Reserved->PacketLength,
+ sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ Adapter = Binding->Adapter;
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ goto FunctionStart;
+ }
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+
+ return;
+
+ } else {
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // If any of the sends succeeded then return
+ // success on the datagram send, otherwise
+ // use the most recent failure status.
+ //
+ if (Reserved->Net0SendSucceeded) {
+ NdisStatus = NDIS_STATUS_SUCCESS;
+ }
+
+ }
+ }
+
+ //
+ // fall thru'
+ //
+#endif
+ default:
+
+ (*Device->UpperDrivers[Reserved->Identifier].SendCompleteHandler)(
+ NdisPacket,
+ NdisStatus);
+ break;
+ }
+
+} /* IpxSendComplete */
+
+
+NTSTATUS
+IpxTdiSendDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSendDatagram request for the transport
+ provider.
+
+Arguments:
+
+ Request - Pointer to the request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PNDIS_PACKET Packet;
+ PIPX_SEND_RESERVED Reserved;
+ PSINGLE_LIST_ENTRY s;
+ TDI_ADDRESS_IPX UNALIGNED * RemoteAddress;
+ TDI_ADDRESS_IPX TempAddress;
+ TA_ADDRESS UNALIGNED * AddressName;
+ PTDI_CONNECTION_INFORMATION Information;
+ PTDI_REQUEST_KERNEL_SENDDG Parameters;
+ PBINDING Binding;
+ IPX_LOCAL_TARGET TempLocalTarget;
+ PIPX_LOCAL_TARGET LocalTarget;
+ PDEVICE Device = IpxDevice;
+ UCHAR PacketType;
+ NTSTATUS Status;
+ PIPX_HEADER IpxHeader;
+ NDIS_STATUS NdisStatus;
+ USHORT LengthIncludingHeader;
+ IPX_DEFINE_SYNC_CONTEXT (SyncContext)
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+ PIO_STACK_LOCATION irpSp; \
+ BOOLEAN IsLoopback = FALSE;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ //
+ // Do a quick check of the validity of the address.
+ //
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ IPX_BEGIN_SYNC (&SyncContext);
+
+ if ((AddressFile->Size == sizeof (ADDRESS_FILE)) &&
+ (AddressFile->Type == IPX_ADDRESSFILE_SIGNATURE) &&
+ ((Address = AddressFile->Address) != NULL)) {
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (AddressFile->State != ADDRESSFILE_STATE_CLOSING) {
+
+ Parameters = (PTDI_REQUEST_KERNEL_SENDDG)REQUEST_PARAMETERS(Request);
+ Information = Parameters->SendDatagramInformation;
+
+ //
+ // Do a quick check if this address has only one entry.
+ //
+
+ AddressName = &((TRANSPORT_ADDRESS UNALIGNED *)(Information->RemoteAddress))->Address[0];
+
+ if ((AddressName->AddressType == TDI_ADDRESS_TYPE_IPX) &&
+ (AddressName->AddressLength >= sizeof(TDI_ADDRESS_IPX))) {
+
+ RemoteAddress = (TDI_ADDRESS_IPX UNALIGNED *)(AddressName->Address);
+
+ } else if ((RemoteAddress = IpxParseTdiAddress (Information->RemoteAddress)) == NULL) {
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INVALID_ADDRESS;
+ goto error_send_no_packet;
+ }
+
+ IPX_DEBUG (SEND, ("Send on %lx, network %lx socket %lx\n",
+ Address, RemoteAddress->NetworkAddress, RemoteAddress->Socket));
+
+#if 0
+ if (Parameters->SendLength > IpxDevice->RealMaxDatagramSize) {
+
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ Parameters->SendLength,
+ IpxDevice->RealMaxDatagramSize));
+
+ REQUEST_INFORMATION(Request) = 0;
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto error_send_no_packet;
+ }
+#endif
+ //
+ // Every address has one packet committed to it, use that
+ // if possible, otherwise take one out of the pool.
+ //
+
+
+#if BACK_FILL
+
+ // If the request is coming from the server, which resrves transport header space
+ // build the header in its space. Allocate a special packet to which does not contain
+ // mac and ipx headers in its reserved space.
+
+ if ((PMDL)REQUEST_NDIS_BUFFER(Request) &&
+ (((PMDL)REQUEST_NDIS_BUFFER(Request))->MdlFlags & MDL_NETWORK_HEADER) &&
+ (!(Information->OptionsLength < sizeof(IPX_DATAGRAM_OPTIONS))) &&
+ (RemoteAddress->NodeAddress[0] != 0xff)) {
+
+ //if (!Address->BackFillPacketInUse) {
+ if (InterlockedExchangeAdd(&Address->BackFillPacketInUse, 0) == 0) {
+ //Address->BackFillPacketInUse = TRUE;
+ InterlockedIncrement(&Address->BackFillPacketInUse);
+
+ Packet = PACKET(&Address->BackFillPacket);
+ Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ IPX_DEBUG(SEND, ("Getting owned backfill %x %x \n", Packet,Reserved));
+
+ }else {
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BackFillPacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ goto GotBackFillPacket;
+ }
+
+ //
+ // This function tries to allocate another packet pool.
+ //
+
+ s = IpxPopBackFillPacket(Device);
+
+ //
+ // Possibly we should queue the packet up to wait
+ // for one to become free.
+ //
+
+ if (s == NULL) {
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto error_send_no_packet;
+ }
+
+GotBackFillPacket:
+
+ Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+ IPX_DEBUG(SEND, ("getting backfill packet %x %x %x\n", s, Reserved, RemoteAddress->NodeAddress));
+ if(!Reserved->BackFill)DbgBreakPoint();
+
+ }
+
+ }else {
+
+ // if (!Address->SendPacketInUse) {
+ if (InterlockedExchangeAdd(&Address->SendPacketInUse, 0) == 0) {
+ // Address->SendPacketInUse = TRUE;
+ InterlockedIncrement(&Address->SendPacketInUse);
+
+ Packet = PACKET(&Address->SendPacket);
+ Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+
+ } else {
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ goto GotPacket;
+ }
+
+ //
+ // This function tries to allocate another packet pool.
+ //
+
+ s = IpxPopSendPacket(Device);
+
+ //
+ // Possibly we should queue the packet up to wait
+ // for one to become free.
+ //
+
+ if (s == NULL) {
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto error_send_no_packet;
+ }
+
+GotPacket:
+
+ Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+ Reserved->BackFill = FALSE;
+
+ }
+
+ }
+
+
+#else
+
+ if (!Address->SendPacketInUse) {
+
+ Address->SendPacketInUse = TRUE;
+ Packet = PACKET(&Address->SendPacket);
+ Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+
+ } else {
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ goto GotPacket;
+ }
+
+ //
+ // This function tries to allocate another packet pool.
+ //
+
+ s = IpxPopSendPacket(Device);
+
+ //
+ // Possibly we should queue the packet up to wait
+ // for one to become free.
+ //
+
+ if (s == NULL) {
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto error_send_no_packet;
+ }
+
+GotPacket:
+
+ Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ }
+
+
+#endif
+
+ IpxReferenceAddressFileLock (AddressFile, AFREF_SEND_DGRAM);
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+
+ //
+ // Save this now while we have Parameters available.
+ //
+
+ REQUEST_INFORMATION(Request) = Parameters->SendLength;
+ LengthIncludingHeader = (USHORT)(Parameters->SendLength + sizeof(IPX_HEADER));
+
+#if 0
+ {
+ ULONG ActualLength;
+ IpxGetMdlChainLength(REQUEST_NDIS_BUFFER(Request), &ActualLength);
+ if (ActualLength != Parameters->SendLength) {
+ DbgPrint ("IPX: IRP %lx has parameter length %d, buffer chain length %d\n",
+ Request, Parameters->SendLength, ActualLength);
+ DbgBreakPoint();
+ }
+ }
+#endif
+
+ Reserved->u.SR_DG.AddressFile = AddressFile;
+ Reserved->u.SR_DG.Request = Request;
+ CTEAssert (Reserved->Identifier == IDENTIFIER_IPX);
+
+
+ //
+ // Set this to 0; this means the packet is not one that
+ // should be broadcast on all nets. We will change it
+ // later if it turns out this is the case.
+ //
+
+ Reserved->u.SR_DG.CurrentNicId = 0;
+
+ //
+ // We need this to track these packets specially.
+ //
+
+ Reserved->u.SR_DG.OutgoingSap = AddressFile->IsSapSocket;
+
+ //
+ // Add the MDL chain after the pre-allocated header buffer.
+ // NOTE: THIS WILL ONLY WORK IF WE EVENTUALLY CALL
+ // NDISRECALCULATEPACKETCOUNTS (which we do in IpxSendFrame).
+ //
+ //
+#if BACK_FILL
+
+ if (Reserved->BackFill) {
+ Reserved->HeaderBuffer = REQUEST_NDIS_BUFFER(Request);
+
+ //remove the ipx mdl from the packet.
+ Reserved->UserLength = Reserved->HeaderBuffer->ByteCount;
+
+ IPX_DEBUG(SEND, ("back filling userMdl Reserved %x %x\n", Reserved->HeaderBuffer, Reserved));
+ } else {
+ NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = REQUEST_NDIS_BUFFER(Request);
+ }
+#else
+ NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = REQUEST_NDIS_BUFFER(Request);
+#endif
+
+
+ if (Information->OptionsLength < sizeof(IPX_DATAGRAM_OPTIONS)) {
+
+ //
+ // The caller did not supply the local target for this
+ // send, so we look it up ourselves.
+ //
+
+ UINT Segment;
+
+ //
+ // We calculate this now since we need to know
+ // if it is directed below.
+ //
+
+ if (RemoteAddress->NodeAddress[0] == 0xff) {
+ // BUGBUG: What about multicast?
+ if ((*(UNALIGNED ULONG *)(RemoteAddress->NodeAddress) != 0xffffffff) ||
+ (*(UNALIGNED USHORT *)(RemoteAddress->NodeAddress+4) != 0xffff)) {
+ Reserved->DestinationType = DESTINATION_MCAST;
+ } else {
+ Reserved->DestinationType = DESTINATION_BCAST;
+ }
+ } else {
+ Reserved->DestinationType = DESTINATION_DEF; // directed send
+ }
+
+ //
+ // If there are no options, then check if the
+ // caller is passing the packet type as a final byte
+ // in the remote address; if not use the default.
+ //
+
+ if (Information->OptionsLength == 0) {
+ if (AddressFile->ExtendedAddressing) {
+ PacketType = ((PUCHAR)(RemoteAddress+1))[0];
+ } else {
+ PacketType = AddressFile->DefaultPacketType;
+ }
+ } else {
+ PacketType = ((PUCHAR)(Information->Options))[0];
+ }
+
+ if ((Reserved->DestinationType != DESTINATION_DEF) &&
+ ((RemoteAddress->NetworkAddress == 0) ||
+ (Device->VirtualNetwork &&
+ (RemoteAddress->NetworkAddress == Device->SourceAddress.NetworkAddress)))) {
+
+ //
+ // This packet needs to be broadcast to all networks.
+ // Make sure it is not too big for any of them.
+ //
+
+ if (Parameters->SendLength > Device->RealMaxDatagramSize) {
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ Parameters->SendLength, Device->RealMaxDatagramSize));
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto error_send_with_packet;
+ }
+
+ //
+ // If this is a broadcast to the virtual net, we
+ // need to construct a fake remote address which
+ // has network 0 in there instead.
+ //
+
+ if (Device->VirtualNetwork &&
+ (RemoteAddress->NetworkAddress == Device->SourceAddress.NetworkAddress)) {
+
+ RtlCopyMemory (&TempAddress, (PVOID)RemoteAddress, sizeof(TDI_ADDRESS_IPX));
+ TempAddress.NetworkAddress = 0;
+ RemoteAddress = (TDI_ADDRESS_IPX UNALIGNED *)&TempAddress;
+ }
+
+ //
+ // If someone is sending to the SAP socket and
+ // we are running with multiple cards without a
+ // virtual network, AND this packet is a SAP response,
+ // then we log an error to warn them that the
+ // system may not work as they like (since there
+ // is no virtual network to advertise, we use
+ // the first card's net/node as our local address).
+ // We only do this once per boot, using the
+ // SapWarningLogged variable to control that.
+ //
+
+ if ((RemoteAddress->Socket == SAP_SOCKET) &&
+ (!Device->SapWarningLogged) &&
+ (Device->MultiCardZeroVirtual)) {
+
+ PNDIS_BUFFER FirstBuffer;
+ UINT FirstBufferLength;
+ USHORT UNALIGNED * FirstBufferData;
+
+ if ((FirstBuffer = REQUEST_NDIS_BUFFER(Request)) != NULL) {
+
+ NdisQueryBuffer(
+ FirstBuffer,
+ (PVOID *)&FirstBufferData,
+ &FirstBufferLength);
+
+ //
+ // The first two bytes of a SAP packet are the
+ // operation, 0x2 (in network order) is response.
+ //
+
+ if ((FirstBufferLength >= sizeof(USHORT)) &&
+ (*FirstBufferData == 0x0200)) {
+
+ Device->SapWarningLogged = TRUE;
+
+ IpxWriteGeneralErrorLog(
+ Device->DeviceObject,
+ EVENT_IPX_SAP_ANNOUNCE,
+ 777,
+ STATUS_NOT_SUPPORTED,
+ NULL,
+ 0,
+ NULL);
+ }
+ }
+ }
+
+
+ //
+ // In this case we do not RIP but instead set the
+ // packet up so it is sent to each network in turn.
+ //
+ // Special case: If this packet is from the SAP
+ // socket and we are running with multiple cards
+ // without a virtual network, we only send this
+ // on the card with NIC ID 1, so we leave
+ // CurrentNicId set to 0.
+ //
+
+ //
+ // BUGBUG: What if NicId 1 is invalid? Should scan
+ // for first valid one, fail send if none.
+ //
+
+ if ((Address->Socket != SAP_SOCKET) ||
+ (!Device->MultiCardZeroVirtual)) {
+
+ if (Device->SingleNetworkActive) {
+
+ if (Device->ActiveNetworkWan) {
+ Reserved->u.SR_DG.CurrentNicId = Device->FirstWanNicId;
+ } else {
+ Reserved->u.SR_DG.CurrentNicId = Device->FirstLanNicId;
+ }
+
+ } else {
+
+ Reserved->u.SR_DG.CurrentNicId = 1;
+
+ }
+
+ Reserved->u.SR_DG.Net0SendSucceeded = FALSE;
+
+ //
+ // In this case, we need to scan for the first
+ // non-dialout wan socket.
+ //
+
+ if ((Device->DisableDialoutSap) &&
+ (Address->Socket == SAP_SOCKET)) {
+
+ PBINDING TempBinding;
+
+ CTEAssert (Reserved->u.SR_DG.CurrentNicId <= Device->ValidBindings);
+ while (Reserved->u.SR_DG.CurrentNicId <= MIN (Device->MaxBindings, Device->ValidBindings)) {
+#ifdef _PNP_POWER
+// No need to lock the access path since he just looks at it
+//
+ TempBinding = NIC_ID_TO_BINDING(Device, Reserved->u.SR_DG.CurrentNicId);
+#else
+ TempBinding = Device->Bindings[Reserved->u.SR_DG.CurrentNicId];
+#endif _PNP_POWER
+ if ((TempBinding != NULL) &&
+ (!TempBinding->DialOutAsync)) {
+ break;
+ }
+ ++Reserved->u.SR_DG.CurrentNicId;
+ }
+ if (Reserved->u.SR_DG.CurrentNicId > MIN (Device->MaxBindings, Device->ValidBindings)) {
+ //
+ // [SA] Bug #17273 return proper error mesg.
+ //
+
+ // Status = STATUS_DEVICE_DOES_NOT_EXIST;
+ Status = STATUS_NETWORK_UNREACHABLE;
+
+ goto error_send_with_packet;
+ }
+ }
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&TempLocalTarget, Reserved->u.SR_DG.CurrentNicId);
+#else
+ TempLocalTarget.NicId = Reserved->u.SR_DG.CurrentNicId;
+#endif
+
+ } else {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&TempLocalTarget, 1);
+#else
+ TempLocalTarget.NicId = 1;
+#endif
+ }
+
+ RtlCopyMemory(TempLocalTarget.MacAddress, RemoteAddress->NodeAddress, 6);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(&TempLocalTarget));
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ } else {
+
+ Segment = RipGetSegment((PUCHAR)&RemoteAddress->NetworkAddress);
+
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // This call will return STATUS_PENDING if we need to
+ // RIP for the packet.
+ //
+
+ Status = RipGetLocalTarget(
+ Segment,
+ RemoteAddress,
+ IPX_FIND_ROUTE_RIP_IF_NEEDED,
+ &TempLocalTarget,
+ NULL);
+
+ if (Status == STATUS_SUCCESS) {
+
+ //
+ // We found the route, TempLocalTarget is filled in.
+ //
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ if (NIC_FROM_LOCAL_TARGET(&TempLocalTarget) == 0) {
+ IPX_DEBUG(LOOPB, ("Loopback TDI packet: remoteaddr: %lx\n", RemoteAddress));
+ IsLoopback = TRUE;
+ FILL_LOCAL_TARGET(&TempLocalTarget, 1);
+ }
+ Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(&TempLocalTarget));
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ if (Parameters->SendLength >
+ Binding->RealMaxDatagramSize) {
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ Parameters->SendLength,
+ Binding->RealMaxDatagramSize));
+
+ REQUEST_INFORMATION(Request) = 0;
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto error_send_with_packet;
+ }
+
+ if ((Device->DisableDialoutSap) &&
+ (Address->Socket == SAP_SOCKET) &&
+ (Binding->DialOutAsync)) {
+
+ REQUEST_INFORMATION(Request) = 0;
+ //
+ // [SA] Bug #17273 return proper error mesg.
+ //
+
+ // Status = STATUS_DEVICE_DOES_NOT_EXIST;
+ Status = STATUS_NETWORK_UNREACHABLE;
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+
+ goto error_send_with_packet;
+ }
+#else
+ if (TempLocalTarget.NicId == 0) {
+ IPX_DEBUG(LOOPB, ("Loopback TDI packet: remoteaddr: %lx\n", RemoteAddress));
+ IsLoopback = TRUE;
+ TempLocalTarget.NicId = 1;
+ }
+
+ if (Parameters->SendLength >
+ Device->Bindings[TempLocalTarget.NicId]->RealMaxDatagramSize) {
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ Parameters->SendLength,
+ Device->Bindings[TempLocalTarget.NicId]->RealMaxDatagramSize));
+
+ REQUEST_INFORMATION(Request) = 0;
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto error_send_with_packet;
+ }
+
+ if ((Device->DisableDialoutSap) &&
+ (Address->Socket == SAP_SOCKET) &&
+ (Device->Bindings[TempLocalTarget.NicId]->DialOutAsync)) {
+
+ REQUEST_INFORMATION(Request) = 0;
+ //
+ // [SA] Bug #17273 return proper error mesg.
+ //
+
+ // Status = STATUS_DEVICE_DOES_NOT_EXIST;
+ Status = STATUS_NETWORK_UNREACHABLE;
+ goto error_send_with_packet;
+ }
+#endif _PNP_POWER
+
+ } else if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this packet for transmission when the RIP
+ // response arrives. First we fill in the IPX
+ // header; the only thing we don't know is where
+ // exactly to fill it in, so we choose
+ // the most common location.
+ //
+
+ IpxConstructHeader(
+ &Reserved->Header[Device->IncludedHeaderOffset],
+ LengthIncludingHeader,
+ PacketType,
+ RemoteAddress,
+ &Address->LocalAddress);
+
+ //
+ // Adjust the 2nd mdl's size
+ //
+ NdisAdjustBufferLength(NDIS_BUFFER_LINKAGE(IPX_PACKET_HEAD(Packet)), sizeof(IPX_HEADER));
+
+ IPX_DEBUG (RIP, ("Queueing packet %lx\n", Reserved));
+
+ InsertTailList(
+ &Device->Segments[Segment].WaitingForRoute,
+ &Reserved->WaitLinkage);
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_END_SYNC (&SyncContext);
+
+ return STATUS_PENDING;
+
+ } else {
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ goto error_send_with_packet;
+
+ }
+ }
+
+ LocalTarget = &TempLocalTarget;
+
+ //
+ // Now we know the local target, we can figure out
+ // the offset for the IPX header.
+ //
+#ifdef _PNP_POWER
+// Remember that we have got the binding with ref above....
+
+#else
+ Binding = Device->Bindings[LocalTarget->NicId];
+#endif
+ IpxHeader = (PIPX_HEADER)&Reserved->Header[MAC_HEADER_SIZE];
+#if 0
+ if (Reserved->DestinationType == DESTINATION_DEF) {
+ IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->DefHeaderSize];
+ } else {
+ IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->BcMcHeaderSize];
+ }
+#endif
+
+ } else {
+
+ PacketType = ((PUCHAR)(Information->Options))[0];
+ LocalTarget = &((PIPX_DATAGRAM_OPTIONS)(Information->Options))->LocalTarget;
+
+ //
+ // Calculate the binding and the correct location
+ // for the IPX header. We can do this at the same
+ // time as we calculate the DestinationType which
+ // saves an if like the one 15 lines up.
+ //
+
+#ifdef _PNP_POWER
+// Get lock to ref.
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ //
+ // If a loopback packet, use the first binding as place holder
+ //
+ if (NIC_FROM_LOCAL_TARGET(LocalTarget) == 0) {
+ Binding = NIC_ID_TO_BINDING(Device, 1);
+ IsLoopback = TRUE;
+ } else {
+ Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget));
+ }
+
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (LocalTarget->NicId == 0) {
+ Binding = Device->Bindings[1];
+ IsLoopback = TRUE;
+ } else {
+ Binding = Device->Bindings[LocalTarget->NicId];
+ }
+#endif _PNP_POWER
+ if (Parameters->SendLength > Binding->RealMaxDatagramSize) {
+
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ Parameters->SendLength,
+ Binding->RealMaxDatagramSize));
+
+ REQUEST_INFORMATION(Request) = 0;
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto error_send_with_packet;
+ }
+
+#if 0
+ //
+ // This shouldn't be needed because even WAN bindings
+ // don't go away once they are added.
+ //
+
+ if (Binding == NULL) {
+ Status = STATUS_DEVICE_DOES_NOT_EXIST;
+ goto error_send_with_packet;
+ }
+#endif
+
+ if (RemoteAddress->NodeAddress[0] == 0xff) {
+ // BUGBUG: What about multicast?
+ if ((*(UNALIGNED ULONG *)(RemoteAddress->NodeAddress) != 0xffffffff) ||
+ (*(UNALIGNED USHORT *)(RemoteAddress->NodeAddress+4) != 0xffff)) {
+ Reserved->DestinationType = DESTINATION_MCAST;
+ } else {
+ Reserved->DestinationType = DESTINATION_BCAST;
+ }
+// IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->BcMcHeaderSize];
+ } else {
+ Reserved->DestinationType = DESTINATION_DEF; // directed send
+// IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->DefHeaderSize];
+ }
+ IpxHeader = (PIPX_HEADER)&Reserved->Header[MAC_HEADER_SIZE];
+
+ }
+
+
+ ++Device->TempDatagramsSent;
+ Device->TempDatagramBytesSent += Parameters->SendLength;
+
+
+#if BACK_FILL
+
+ if (Reserved->BackFill) {
+ Reserved->MappedSystemVa = Reserved->HeaderBuffer->MappedSystemVa;
+ IpxHeader = (PIPX_HEADER)((PCHAR)Reserved->HeaderBuffer->MappedSystemVa - sizeof(IPX_HEADER));
+ Reserved->HeaderBuffer->ByteOffset -= sizeof(IPX_HEADER);
+ (ULONG)Reserved->HeaderBuffer->MappedSystemVa-= sizeof(IPX_HEADER);
+ IPX_DEBUG(SEND, ("Adjusting backfill userMdl Ipxheader %x %x \n",Reserved->HeaderBuffer,IpxHeader));
+ }
+#endif
+
+ if (Device->MultiCardZeroVirtual ||
+ (Address->LocalAddress.Socket == SAP_SOCKET) ||
+ (RemoteAddress->Socket == SAP_SOCKET)) {
+
+ //
+ // SAP frames need to look like they come from the
+ // local network, not the virtual one. The same is
+ // true if we are running multiple nets without
+ // a virtual network number.
+ //
+ // If this is a binding set member and a local target
+ // was provided we will send using the real node of
+ // the binding, even if it was a slave. This is
+ // intentional. If no local target was provided then
+ // this will not be a binding slave.
+ //
+
+ IpxConstructHeader(
+ (PUCHAR)IpxHeader,
+ LengthIncludingHeader,
+ PacketType,
+ RemoteAddress,
+ &Binding->LocalAddress);
+
+ IpxHeader->SourceSocket = Address->SendSourceSocket;
+
+ } else {
+
+ IpxConstructHeader(
+ (PUCHAR)IpxHeader,
+ LengthIncludingHeader,
+ PacketType,
+ RemoteAddress,
+ &Address->LocalAddress);
+
+ }
+
+
+ //
+ // Fill in the MAC header and submit the frame to NDIS.
+ //
+
+// #if DBG
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+// #endif
+ //
+ // Adjust the 2nd mdl's size
+ //
+#if BACK_FILL
+ if (Reserved->BackFill) {
+ NdisAdjustBufferLength(Reserved->HeaderBuffer, (Reserved->HeaderBuffer->ByteCount+sizeof(IPX_HEADER)));
+ } else {
+ NdisAdjustBufferLength(NDIS_BUFFER_LINKAGE(IPX_PACKET_HEAD(Packet)), sizeof(IPX_HEADER));
+ }
+#else
+ NdisAdjustBufferLength(NDIS_BUFFER_LINKAGE(IPX_PACKET_HEAD(Packet)), sizeof(IPX_HEADER));
+#endif
+
+ IPX_DEBUG(SEND, ("Packet Head %x\n",IPX_PACKET_HEAD(Packet)));
+
+ if (IsLoopback) {
+ //
+ // Enque this packet to the LoopbackQueue on the binding.
+ // If the LoopbackRtn is not already scheduled, schedule it.
+ //
+
+ IPX_DEBUG(LOOPB, ("Packet: %lx, Addr: %lx, Addr->SendPacket: %lx\n", Packet, Address, Address->SendPacket));
+
+ //
+ // Recalculate packet counts here.
+ //
+ // NdisAdjustBufferLength (Reserved->HeaderBuffer, 17);
+#if BACK_FILL
+
+ if (Reserved->BackFill) {
+ //
+ // Set the Header pointer and chain the first MDL
+ //
+ Reserved->Header = (PCHAR)Reserved->HeaderBuffer->MappedSystemVa;
+ NdisChainBufferAtFront(Packet,(PNDIS_BUFFER)Reserved->HeaderBuffer);
+ }
+#endif
+ NdisRecalculatePacketCounts (Packet);
+#ifdef _PNP_POWER
+ IpxLoopbackEnque(Packet, NIC_ID_TO_BINDING(Device, 1)->Adapter);
+#else
+ IpxLoopbackEnque(Packet, Device->Bindings[1]->Adapter);
+#endif
+
+ } else {
+ if ((NdisStatus = (*Binding->SendFrameHandler)(
+ Binding->Adapter,
+ LocalTarget,
+ Packet,
+ Parameters->SendLength + sizeof(IPX_HEADER),
+ sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ IpxSendComplete(
+ (NDIS_HANDLE)Binding->Adapter,
+ Packet,
+ NdisStatus);
+ }
+ }
+
+ IPX_END_SYNC (&SyncContext);
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ return STATUS_PENDING;
+
+ } else {
+
+ //
+ // The address file state was closing.
+ //
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INVALID_HANDLE;
+ goto error_send_no_packet;
+
+ }
+
+ } else {
+
+ //
+ // The address file didn't look like one.
+ //
+
+ Status = STATUS_INVALID_HANDLE;
+ goto error_send_no_packet;
+ }
+
+ //
+ // Jump here if we want to fail the send and we have already
+ // allocated the packet and ref'ed the address file.
+ //
+
+error_send_with_packet:
+
+#if BACK_FILL
+ //
+ // Check if this is backfilled. If so, set the headerbuffer to NULL. Note that we dont need
+ // restore to restore the user's MDL since it was never touched when this error occurred.
+ // Also, push the packet on to backfillpacket queue if the packet is not owned by the address
+ //
+ if (Reserved->BackFill) {
+
+ Reserved->HeaderBuffer = NULL;
+
+ if (Reserved->OwnedByAddress) {
+ // Reserved->Address->BackFillPacketInUse = FALSE;
+ InterlockedDecrement(&Reserved->Address->BackFillPacketInUse);
+
+ IPX_DEBUG(SEND, ("Freeing owned backfill %x\n", Reserved));
+ } else {
+ IPX_PUSH_ENTRY_LIST(
+ &Device->BackFillPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+ }
+ } else {
+ // not a back fill packet. Push it on sendpacket pool
+ if (Reserved->OwnedByAddress) {
+ // Reserved->Address->SendPacketInUse = FALSE;
+ InterlockedDecrement(&Reserved->Address->SendPacketInUse);
+
+ } else {
+ IPX_PUSH_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+
+ }
+ }
+#else
+ if (Reserved->OwnedByAddress) {
+ Reserved->Address->SendPacketInUse = FALSE;
+ } else {
+ IPX_PUSH_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+ }
+#endif
+
+ IpxDereferenceAddressFileSync (AddressFile, AFREF_SEND_DGRAM);
+
+error_send_no_packet:
+
+ //
+ // Jump here if we fail before doing any of that.
+ //
+
+ IPX_END_SYNC (&SyncContext);
+
+ irpSp = IoGetCurrentIrpStackLocation( Request );
+ if ( irpSp->MinorFunction == TDI_DIRECT_SEND_DATAGRAM ) {
+
+ REQUEST_STATUS(Request) = Status;
+ Request->CurrentLocation++,
+ Request->Tail.Overlay.CurrentStackLocation++;
+
+ (VOID) irpSp->CompletionRoutine(
+ NULL,
+ Request,
+ irpSp->Context
+ );
+
+ IpxFreeRequest (DeviceObject, Request);
+ }
+
+ return Status;
+
+} /* IpxTdiSendDatagram */
+
+
+#if DBG
+VOID
+IpxConstructHeader(
+ IN PUCHAR Header,
+ IN USHORT PacketLength,
+ IN UCHAR PacketType,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PTDI_ADDRESS_IPX LocalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an IPX header in a packet.
+
+Arguments:
+
+ Header - The location at which the header should be built.
+
+ PacketLength - The length of the packet, including the IPX header.
+
+ PacketType - The packet type of the frame.
+
+ RemoteAddress - The remote IPX address.
+
+ LocalAddress - The local IPX address.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PIPX_HEADER IpxHeader = (PIPX_HEADER)Header;
+
+ IpxHeader->CheckSum = 0xffff;
+ IpxHeader->PacketLength[0] = (UCHAR)(PacketLength / 256);
+ IpxHeader->PacketLength[1] = (UCHAR)(PacketLength % 256);
+ IpxHeader->TransportControl = 0;
+ IpxHeader->PacketType = PacketType;
+
+ //
+ // These copies depend on the fact that the destination
+ // network is the first field in the 12-byte address.
+ //
+
+ RtlCopyMemory(IpxHeader->DestinationNetwork, (PVOID)RemoteAddress, 12);
+ RtlCopyMemory(IpxHeader->SourceNetwork, LocalAddress, 12);
+
+} /* IpxConstructHeader */
+#endif
+
+
diff --git a/private/ntos/tdi/isnp/ipx/sources.inc b/private/ntos/tdi/isnp/ipx/sources.inc
new file mode 100644
index 000000000..449026087
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/sources.inc
@@ -0,0 +1,74 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=nwlnkipx
+
+TARGETNAME=nwlnkipx
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\tdi.lib \
+ $(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..;..\..\inc;..\..\..\..\inc;..\..\..\..\..\inc
+
+NTPROFILEINPUT=yes
+
+
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+C_DEFINES=$(C_DEFINES) -D_NTDRIVER_ -DBACK_FILL=1 -DNDIS40=1 -D_PNP_POWER=1
+
+!IFDEF BUILD_FOR_3_51
+C_DEFINES=$(C_DEFINES) -D_NTIFS_
+!ENDIF
+
+SOURCES= \
+ ..\action.c \
+ ..\adapter.c \
+ ..\address.c \
+ ..\config.c \
+ ..\device.c \
+ ..\driver.c \
+ ..\event.c \
+ ..\ind.c \
+ ..\internal.c \
+ ..\nwlnkipx.rc \
+ ..\mac.c \
+ ..\ndis.c \
+ ..\packet.c \
+ ..\query.c \
+ ..\receive.c \
+ ..\rip.c \
+ ..\send.c \
+ ..\loopback.c
+
+PRECOMPILED_INCLUDE=..\precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
+
+SOURCES_USED=..\sources.inc
+
+
diff --git a/private/ntos/tdi/isnp/ipx/up/makefile b/private/ntos/tdi/isnp/ipx/up/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/up/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isnp/ipx/up/nwlnkipx.prf b/private/ntos/tdi/isnp/ipx/up/nwlnkipx.prf
new file mode 100644
index 000000000..0c4359235
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/up/nwlnkipx.prf
@@ -0,0 +1,89 @@
+IpxTdiSendDatagram@8
+IpxReceiveIndicationNew@36
+IpxSendFrame@16
+IpxReceiveComplete@4
+IpxSendFrame802_3802_2@20
+IpxReceivePacket@8
+IpxDerefAddressSync@4
+IpxSendComplete@12
+IpxSendFramePreFwd@16
+IpxReceiveIndication@28
+IpxInitializeBackFillPacket@12
+IpxpAllocateMemory@12
+IpxPopBackFillPacket@4
+IpxAllocateBackFillPool@4
+RipLongTimeout@8
+CTEStartTimer@16
+TdiCopyBufferToMdl@24
+IpxTdiQueryInformation@8
+IpxVerifyAddressFile@4
+IpxDispatchInternal@8
+IpxTransferData@28
+IpxInitLoopback@0
+RipGetFirstRoute@4
+IpxCreateAddress@8
+MacReturnMaxDataSize@20
+IpxLookupAddress@8
+IpxAbortLineChanges@4
+MacMapFrameType@12
+IpxInitializeReceiveBuffer@16
+IpxDispatchOpenClose@8
+IpxTdiSetEventHandler@4
+IpxCreateAddressFile@4
+IpxInternalBind@8
+IpxInitializeReceivePacket@8
+IpxIsAddressLocal@4
+IpxOpenAddress@8
+IpxAllocateReceiveBufferPool@4
+IpxSubmitNdisRequest@12
+IpxAddBroadcast@4
+IpxDestroyBinding@4
+RipAdjustForBindingChange@12
+IpxDispatchDeviceControl@8
+IpxAllocatePaddingBuffer@4
+TdiMapUserRequest@12
+CTEInitialize@0
+IpxInitializeSendPacket@12
+IpxpFreeMemory@12
+IpxInitializePaddingBuffer@12
+IpxAllocateSendPool@4
+RipCleanupPacket@8
+TdiRegisterDeviceObject@8
+TdiRegisterNetAddress@8
+IpxTdiAction@8
+IpxCreateBinding@20
+IpxDerefDevice@4
+MacInitializeBindingInfo@8
+IpxRegisterProtocol@4
+IpxInitializeNdis@8
+IpxGetConfigValue@24
+IpxCreateAdapter@12
+IpxResolveBindingSets@8
+IpxGetFrameType@24
+MacInitializeMacInfo@8
+IpxGetBindingValue@24
+RipQueueRequest@8
+RipShortTimeout@8
+IpxPopSendPacket@4
+IpxAllocateBindingPool@4
+IpxInternalQuery@20
+CTEInitTimer@4
+IpxRequestComplete@12
+IpxBroadcastOperation@4
+CTEInitEvent@8
+IpxPnPGetVirtualNetworkNumber@4
+IpxPnPGetAdapterParameters@12
+IpxOpenAdapterComplete@12
+IpxResolveAutoDetect@16
+IpxBindToAdapter@16
+TdiInitialize@0
+IpxPnPIsnIndicate@4
+IpxPnPUpdateBindingArray@12
+IpxBindAdapter@20
+IpxPnPUpdateDevice@4
+IpxGetConfiguration@12
+IpxAddExport@24
+IpxCreateDevice@16
+DriverEntry@8
+IpxReadLinkageInformation@4
+IpxFreeConfiguration@4
diff --git a/private/ntos/tdi/isnp/ipx/up/sources b/private/ntos/tdi/isnp/ipx/up/sources
new file mode 100644
index 000000000..85cdb3764
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/up/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+UP_DRIVER=yes
+
+TARGETPATH=obj
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/isnp/nb/action.c b/private/ntos/tdi/isnp/nb/action.c
new file mode 100644
index 000000000..9ff843a76
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/action.c
@@ -0,0 +1,221 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ action.c
+
+Abstract:
+
+ This module contains code which implements the TDI action
+ dispatch routines.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+typedef struct _NB_ACTION_GET_COUNTS {
+ USHORT MaximumNicId; // returns maximum NIC ID
+ USHORT NicIdCounts[32]; // session counts for first 32 NIC IDs
+} NB_ACTION_GET_COUNTS, *PNB_ACTION_GET_COUNTS;
+
+
+NTSTATUS
+NbiTdiAction(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles action requests.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the action.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ PADDRESS_FILE AddressFile;
+ PCONNECTION Connection;
+ UINT BufferLength;
+ UINT DataLength;
+ PNDIS_BUFFER NdisBuffer;
+ CTELockHandle LockHandle;
+ union {
+ PNB_ACTION_GET_COUNTS GetCounts;
+ } u; // BUGBUG: Make these unaligned??
+ PNWLINK_ACTION NwlinkAction;
+ UINT i;
+ static UCHAR BogusId[4] = { 0x01, 0x00, 0x00, 0x00 }; // old nwrdr uses this
+
+
+ //
+ // To maintain some compatibility with the NWLINK streams-
+ // based transport, we use the streams header format for
+ // our actions. The old transport expected the action header
+ // to be in InputBuffer and the output to go in OutputBuffer.
+ // We follow the TDI spec, which states that OutputBuffer
+ // is used for both input and output. Since IOCTL_TDI_ACTION
+ // is method out direct, this means that the output buffer
+ // is mapped by the MDL chain; for action the chain will
+ // only have one piece so we use it for input and output.
+ //
+
+ NdisBuffer = REQUEST_NDIS_BUFFER(Request);
+ if (NdisBuffer == NULL) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ NdisQueryBuffer (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength);
+
+ if ((!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MISN", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MIPX", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "XPIM", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), BogusId, 4))) {
+
+ return STATUS_NOT_SUPPORTED;
+ }
+
+
+ //
+ // Make sure we have enough room for just the header not
+ // including the data.
+ //
+
+ if (BufferLength < (UINT)(FIELD_OFFSET(NWLINK_ACTION, Data[0]))) {
+ NB_DEBUG (QUERY, ("Nwlink action failed, buffer too small\n"));
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ DataLength = BufferLength - FIELD_OFFSET(NWLINK_ACTION, Data[0]);
+
+
+ //
+ // Make sure that the correct file object is being used.
+ //
+
+ if (NwlinkAction->OptionType == NWLINK_OPTION_ADDRESS) {
+
+ if (REQUEST_OPEN_TYPE(Request) != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
+ NB_DEBUG (QUERY, ("Nwlink action failed, not address file\n"));
+ return STATUS_INVALID_HANDLE;
+ }
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ if ((AddressFile->Size != sizeof (ADDRESS_FILE)) ||
+ (AddressFile->Type != NB_ADDRESSFILE_SIGNATURE)) {
+
+ NB_DEBUG (QUERY, ("Nwlink action failed, bad address file\n"));
+ return STATUS_INVALID_HANDLE;
+ }
+
+ } else if (NwlinkAction->OptionType != NWLINK_OPTION_CONTROL) {
+
+ NB_DEBUG (QUERY, ("Nwlink action failed, option type %d\n", NwlinkAction->OptionType));
+ return STATUS_NOT_SUPPORTED;
+ }
+
+
+ //
+ // Handle the requests based on the action code. For these
+ // requests ActionHeader->ActionCode is 0, we use the
+ // Option field in the streams header instead.
+ //
+
+
+ Status = STATUS_SUCCESS;
+
+ switch (NwlinkAction->Option) {
+
+ case (I_MIPX | 351):
+
+ //
+ // A request for details on every binding.
+ //
+
+ if (DataLength < sizeof(NB_ACTION_GET_COUNTS)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.GetCounts = (PNB_ACTION_GET_COUNTS)(NwlinkAction->Data);
+
+ u.GetCounts->MaximumNicId = NbiDevice->MaximumNicId;
+
+ for (i = 0; i < 32 ; i++) {
+ u.GetCounts->NicIdCounts[i] = 0;
+ }
+
+ for (i = 0; i < CONNECTION_HASH_COUNT; i++) {
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Connection = Device->ConnectionHash[i].Connections;
+
+ while (Connection != NULL) {
+#if defined(_PNP_POWER)
+ if ((Connection->State == CONNECTION_STATE_ACTIVE) &&
+ (Connection->LocalTarget.NicHandle.NicId < 32)) {
+
+ ++u.GetCounts->NicIdCounts[Connection->LocalTarget.NicHandle.NicId];
+ }
+#else
+ if ((Connection->State == CONNECTION_STATE_ACTIVE) &&
+ (Connection->LocalTarget.NicId < 32)) {
+
+ ++u.GetCounts->NicIdCounts[Connection->LocalTarget.NicId];
+ }
+#endif _PNP_POWER
+ Connection = Connection->NextConnection;
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ break;
+
+ //
+ // The Option was not supported, so fail.
+ //
+
+ default:
+
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+
+
+ } // end of the long switch on NwlinkAction->Option
+
+
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ NB_DEBUG (QUERY, ("Nwlink action %lx failed, status %lx\n", NwlinkAction->Option, Status));
+ }
+#endif
+
+ return Status;
+
+} /* NbiTdiAction */
+
diff --git a/private/ntos/tdi/isnp/nb/address.c b/private/ntos/tdi/isnp/nb/address.c
new file mode 100644
index 000000000..2eb882b80
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/address.c
@@ -0,0 +1,2406 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ address.c
+
+Abstract:
+
+ This module contains code which implements the ADDRESS object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport address objects.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Map all generic accesses to the same one.
+//
+
+static GENERIC_MAPPING AddressGenericMapping =
+ { READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL };
+
+
+
+TDI_ADDRESS_NETBIOS UNALIGNED *
+NbiParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN BOOLEAN BroadcastAddressOk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, looking for an address
+ of type TDI_ADDRESS_TYPE_NETBIOS.
+
+Arguments:
+
+ Transport - The generic TDI address.
+
+ BroadcastAddressOk - TRUE if we should return the broadcast
+ address if found. If so, a value of (PVOID)-1 indicates
+ the broadcast address.
+
+Return Value:
+
+ A pointer to the Netbios address, or NULL if none is found,
+ or (PVOID)-1 if the broadcast address is found.
+
+--*/
+
+{
+ TA_ADDRESS UNALIGNED * addressName;
+ INT i;
+
+ addressName = &TransportAddress->Address[0];
+
+ //
+ // The name can be passed with multiple entries; we'll take and use only
+ // the Netbios one.
+ //
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++) {
+ if (addressName->AddressType == TDI_ADDRESS_TYPE_NETBIOS) {
+ if ((addressName->AddressLength == 0) &&
+ BroadcastAddressOk) {
+ return (PVOID)-1;
+ } else if (addressName->AddressLength == sizeof(TDI_ADDRESS_NETBIOS)) {
+ return ((TDI_ADDRESS_NETBIOS UNALIGNED *)(addressName->Address));
+ }
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+ return NULL;
+
+} /* NbiParseTdiAddress */
+
+
+BOOLEAN
+NbiValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, verifying that the
+ components of the address do not extend past the specified
+ length.
+
+Arguments:
+
+ TransportAddress - The generic TDI address.
+
+ TransportAddressLength - The specific length of TransportAddress.
+
+Return Value:
+
+ TRUE if the address is valid, FALSE otherwise.
+
+--*/
+
+{
+ PUCHAR AddressEnd = ((PUCHAR)TransportAddress) + TransportAddressLength;
+ TA_ADDRESS UNALIGNED * addressName;
+ INT i;
+
+ if (TransportAddressLength < sizeof(TransportAddress->TAAddressCount)) {
+ NbiPrint0 ("NbfValidateTdiAddress: runt address\n");
+ return FALSE;
+ }
+
+ addressName = &TransportAddress->Address[0];
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++) {
+ if (addressName->Address > AddressEnd) {
+ NbiPrint0 ("NbiValidateTdiAddress: address too short\n");
+ return FALSE;
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+
+ if ((PUCHAR)addressName > AddressEnd) {
+ NbiPrint0 ("NbiValidateTdiAddress: address too short\n");
+ return FALSE;
+ }
+ return TRUE;
+
+} /* NbiValidateTdiAddress */
+
+
+NTSTATUS
+NbiOpenAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens a file that points to an existing address object, or, if
+ the object doesn't exist, creates it (note that creation of the address
+ object includes registering the address, and may take many seconds to
+ complete, depending upon system configuration).
+
+ If the address already exists, and it has an ACL associated with it, the
+ ACL is checked for access rights before allowing creation of the address.
+
+Arguments:
+
+ Device - pointer to the device describing the Netbios transport.
+
+ Request - a pointer to the request used for the creation of the address.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ PFILE_FULL_EA_INFORMATION ea;
+ TRANSPORT_ADDRESS UNALIGNED *name;
+ TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress;
+ ULONG DesiredShareAccess;
+ CTELockHandle LockHandle;
+ PACCESS_STATE AccessState;
+ ACCESS_MASK GrantedAccess;
+ BOOLEAN AccessAllowed;
+ BOOLEAN found = FALSE;
+#ifdef ISN_NT
+ PIRP Irp = (PIRP)Request;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+#endif
+#if 0
+ TA_NETBIOS_ADDRESS FakeAddress;
+#endif
+
+
+ //
+ // The network name is in the EA, passed in the request.
+ //
+
+ ea = OPEN_REQUEST_EA_INFORMATION(Request);
+ if (ea == NULL) {
+ NbiPrint1("OpenAddress: REQUEST %lx has no EA\n", Request);
+ return STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+ //
+ // this may be a valid name; parse the name from the EA and use it if OK.
+ //
+
+ name = (PTRANSPORT_ADDRESS)&ea->EaName[ea->EaNameLength+1];
+#if 0
+ TdiBuildNetbiosAddress(
+ "ADAMBA67 ",
+ FALSE,
+ &FakeAddress);
+ name = (PTRANSPORT_ADDRESS)&FakeAddress;
+#endif
+
+ //
+ // The name can be passed with multiple entries; we'll take and use only
+ // the first one of type Netbios. This call returns (PVOID)-1 if the
+ // address is the broadcast address.
+ //
+
+ NetbiosAddress = NbiParseTdiAddress (name, TRUE);
+
+ if (NetbiosAddress == NULL) {
+ NbiPrint1("OpenAddress: REQUEST %lx has no Netbios Address\n", Request);
+ return STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+ //
+ // get an address file structure to represent this address.
+ //
+
+ AddressFile = NbiCreateAddressFile (Device);
+
+ if (AddressFile == (PADDRESS_FILE)NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // See if this address is already established. This call automatically
+ // increments the reference count on the address so that it won't disappear
+ // from underneath us after this call but before we have a chance to use it.
+ //
+ // To ensure that we don't create two address objects for the
+ // same address, we hold the device context addressResource until
+ // we have found the address or created a new one.
+ //
+
+ ExAcquireResourceExclusive (&Device->AddressResource, TRUE);
+
+#if defined(_PNP_POWER)
+
+ Address = NbiFindAddress (
+ Device,
+ ( NetbiosAddress == (PVOID)-1 ) ? (PVOID)-1 : NetbiosAddress->NetbiosName
+ );
+
+ if (Address == NULL) {
+
+#else
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Address = NbiLookupAddress (Device, NetbiosAddress);
+
+ if (Address == NULL) {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+#endif _PNP_POWER
+
+ //
+ // This address doesn't exist. Create it.
+ // This initializes the address with a ref
+ // of type ADDRESS_FILE, so if we fail here
+ // we need to remove that.
+ //
+
+ Address = NbiCreateAddress (
+ Device,
+ NetbiosAddress);
+
+ if (Address != (PADDRESS)NULL) {
+
+ //
+ // Set this now in case we have to deref.
+ //
+
+ AddressFile->AddressLock = &Address->Lock;
+
+#ifdef ISN_NT
+
+ //
+ // Initialize the shared access now. We use read access
+ // to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ IoSetShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &Address->u.ShareAccess);
+
+
+ //
+ // Assign the security descriptor (need to do this with
+ // the spinlock released because the descriptor is not
+ // mapped).
+ //
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ status = SeAssignSecurity(
+ NULL, // parent descriptor
+ AccessState->SecurityDescriptor,
+ &Address->SecurityDescriptor,
+ FALSE, // is directory
+ &AccessState->SubjectSecurityContext,
+ &AddressGenericMapping,
+ NonPagedPool);
+
+ if (!NT_SUCCESS(status)) {
+
+ //
+ // Error, return status.
+ //
+
+ IoRemoveShareAccess (IrpSp->FileObject, &Address->u.ShareAccess);
+ ExReleaseResource (&Device->AddressResource);
+ NbiDereferenceAddress (Address, AREF_ADDRESS_FILE);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ return status;
+
+ }
+
+#endif
+
+ ExReleaseResource (&Device->AddressResource);
+
+ //
+ // if the adapter isn't ready, we can't do any of this; get out
+ //
+#if defined(_PNP_POWER)
+ if (Device->State != DEVICE_STATE_OPEN) {
+#else
+ if (Device->State == DEVICE_STATE_STOPPING) {
+#endif _PNP_POWER
+ NbiDereferenceAddress (Address, AREF_ADDRESS_FILE);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ status = STATUS_DEVICE_NOT_READY;
+
+ } else {
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+#ifdef ISN_NT
+ AddressFile->FileObject = IrpSp->FileObject;
+#endif
+ AddressFile->Address = Address;
+
+ NB_INSERT_TAIL_LIST(
+ &Address->AddressFileDatabase,
+ &AddressFile->Linkage,
+ &Address->Lock);
+
+ if (NetbiosAddress == (PVOID)-1) {
+
+ AddressFile->OpenRequest = NULL;
+ AddressFile->State = ADDRESSFILE_STATE_OPEN;
+ status = STATUS_SUCCESS;
+
+ } else {
+
+ AddressFile->OpenRequest = Request;
+ AddressFile->State = ADDRESSFILE_STATE_OPENING;
+ status = STATUS_PENDING;
+
+ NbiStartRegistration (Address);
+ }
+
+ }
+
+ } else {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ //
+ // If the address could not be created, and is not in the
+ // process of being created, then we can't open up an address.
+ // Since we can't use the AddressLock to deref, we just destroy
+ // the address file.
+ //
+
+ NbiDestroyAddressFile (AddressFile);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ } else {
+
+#if !defined(_PNP_POWER)
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+#endif !_PNP_POWER
+ NB_DEBUG2 (ADDRESS, ("Add to address %lx\n", Address));
+
+ //
+ // Set this now in case we have to deref.
+ //
+
+ AddressFile->AddressLock = &Address->Lock;
+
+ //
+ // Make sure the types do not conflict.
+ //
+
+ if ((NetbiosAddress != (PVOID)-1) &&
+ (NetbiosAddress->NetbiosNameType != Address->NetbiosAddress.NetbiosNameType)) {
+
+ NB_DEBUG (ADDRESS, ("Address types conflict %lx\n", Address));
+ ExReleaseResource (&Device->AddressResource);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ status = STATUS_DUPLICATE_NAME;
+
+ } else {
+
+ //
+ // The address already exists. Check the ACL and see if we
+ // can access it. If so, simply use this address as our address.
+ //
+
+#ifdef ISN_NT
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ AccessAllowed = SeAccessCheck(
+ Address->SecurityDescriptor,
+ &AccessState->SubjectSecurityContext,
+ FALSE, // tokens locked
+ IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
+ (ACCESS_MASK)0, // previously granted
+ NULL, // privileges
+ &AddressGenericMapping,
+ Irp->RequestorMode,
+ &GrantedAccess,
+ &status);
+
+#else // ISN_NT
+
+ AccessAllowed = TRUE;
+
+#endif // ISN_NT
+
+ if (!AccessAllowed) {
+
+ NB_DEBUG (ADDRESS, ("Address access not allowed %lx\n", Address));
+ ExReleaseResource (&Device->AddressResource);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ } else {
+
+#ifdef ISN_NT
+
+ //
+ // Now check that we can obtain the desired share
+ // access. We use read access to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ status = IoCheckShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &Address->u.ShareAccess,
+ TRUE);
+
+#else // ISN_NT
+
+ status = STATUS_SUCCESS;
+
+#endif // ISN_NT
+
+ if (!NT_SUCCESS (status)) {
+
+ NB_DEBUG (ADDRESS, ("Address share access wrong %lx\n", Address));
+ ExReleaseResource (&Device->AddressResource);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ } else {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ //
+ // Insert the address file on the address
+ // list; we will pend this open if the address
+ // is still registering. If the address has
+ // already failed as duplicate, then we
+ // fail the open.
+ //
+
+ if (Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) {
+
+ NB_DEBUG (ADDRESS, ("Address duplicated %lx\n", Address));
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ status = STATUS_DUPLICATE_NAME;
+
+ } else {
+
+ InsertTailList (
+ &Address->AddressFileDatabase,
+ &AddressFile->Linkage);
+
+ //
+ // Start registration unless it is registered or
+ // it is the broadcast address.
+ //
+
+ if ((Address->State == ADDRESS_STATE_REGISTERING) &&
+ (NetbiosAddress != (PVOID)-1)) {
+
+ AddressFile->OpenRequest = Request;
+ AddressFile->State = ADDRESSFILE_STATE_OPENING;
+ status = STATUS_PENDING;
+
+ } else {
+
+ AddressFile->OpenRequest = NULL;
+ AddressFile->State = ADDRESSFILE_STATE_OPEN;
+ status = STATUS_SUCCESS;
+ }
+
+ AddressFile->Address = Address;
+#ifdef ISN_NT
+ AddressFile->FileObject = IrpSp->FileObject;
+#endif
+
+ NbiReferenceAddress (Address, AREF_ADDRESS_FILE);
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ }
+
+ }
+ }
+ }
+
+ //
+ // Remove the reference from NbiLookupAddress.
+ //
+
+ NbiDereferenceAddress (Address, AREF_LOOKUP);
+ }
+
+ return status;
+
+} /* NbiOpenAddress */
+
+
+VOID
+NbiStartRegistration(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the registration process for a netbios name
+ by sending out the first add name packet and starting the timer
+ so that NbiRegistrationTimeout is called after the correct timeout.
+
+Arguments:
+
+ Address - The address which is to be registered.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ NB_DEBUG2 (ADDRESS, ("StartRegistration of %lx\n", Address));
+
+ //
+ // First send out an add name packet.
+ //
+
+ NbiSendNameFrame(
+ Address,
+ (UCHAR)(Address->NameTypeFlag | NB_NAME_USED),
+ NB_CMD_ADD_NAME,
+ NULL,
+ NULL);
+
+ Address->RegistrationCount = 0;
+
+ //
+ // Now start the timer.
+ //
+
+ NbiReferenceAddress (Address, AREF_TIMER);
+
+ CTEInitTimer (&Address->RegistrationTimer);
+ CTEStartTimer(
+ &Address->RegistrationTimer,
+ Address->Device->BroadcastTimeout,
+ NbiRegistrationTimeout,
+ (PVOID)Address);
+
+} /* NbiStartRegistration */
+
+
+VOID
+NbiRegistrationTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the address registration
+ timer expires. It sends another add name if needed, or
+ checks the result if the correct number have been sent.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the address pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADDRESS Address = (PADDRESS)Context;
+ CTELockHandle LockHandle;
+ PADDRESS_FILE AddressFile, ReferencedAddressFile;
+ PLIST_ENTRY p;
+
+ ++Address->RegistrationCount;
+
+ if ((Address->RegistrationCount < Address->Device->BroadcastCount) &&
+ ((Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) == 0)) {
+
+ NB_DEBUG2 (ADDRESS, ("Send add name %d for %lx\n", Address->RegistrationCount+1, Address));
+
+ NbiSendNameFrame(
+ Address,
+ (UCHAR)(Address->NameTypeFlag | NB_NAME_USED),
+ NB_CMD_ADD_NAME,
+ NULL,
+ NULL);
+
+ CTEStartTimer(
+ &Address->RegistrationTimer,
+ Address->Device->BroadcastTimeout,
+ NbiRegistrationTimeout,
+ (PVOID)Address);
+
+ } else {
+
+ //
+ // The correct number of frames have been sent, see what
+ // happened.
+ //
+
+ NB_DEBUG2 (ADDRESS, ("Done with add names for %lx\n", Address));
+
+ ReferencedAddressFile = NULL;
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if ((Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) == 0) {
+ Address->State = ADDRESS_STATE_OPEN;
+ } else {
+ Address->State = ADDRESS_STATE_STOPPING;
+ }
+
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+
+ AddressFile = CONTAINING_RECORD (p, ADDRESS_FILE, Linkage);
+ CTEAssert (AddressFile->State == ADDRESSFILE_STATE_OPENING);
+ CTEAssert (AddressFile->OpenRequest != NULL);
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_TIMEOUT);
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_TIMEOUT);
+ }
+
+ //
+ // Now see what to do with this address file.
+ //
+
+ REQUEST_INFORMATION(AddressFile->OpenRequest) = 0;
+
+ if (Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) {
+
+ NB_DEBUG (ADDRESS, ("Open of address file %lx failed, duplicate\n", AddressFile));
+ REQUEST_STATUS(AddressFile->OpenRequest) = STATUS_DUPLICATE_NAME;
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ } else {
+
+ NB_DEBUG2 (ADDRESS, ("Complete open of address file %lx\n", AddressFile));
+ REQUEST_STATUS(AddressFile->OpenRequest) = STATUS_SUCCESS;
+ AddressFile->State = ADDRESSFILE_STATE_OPEN;
+
+ }
+
+ NbiCompleteRequest (AddressFile->OpenRequest);
+ NbiFreeRequest (Address->Device, AddressFile->OpenRequest);
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ ReferencedAddressFile = AddressFile;
+
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_TIMEOUT);
+ }
+
+ NbiDereferenceAddress (Address, AREF_TIMER);
+
+ }
+
+} /* NbiRegistrationTimeout */
+
+
+VOID
+NbiProcessFindName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_FIND_NAME frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADDRESS Address;
+ NB_CONNECTIONLESS UNALIGNED * NbConnectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
+ PDEVICE Device = NbiDevice;
+
+ if (PacketSize != sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME)) {
+ return;
+ }
+
+ //
+ // Quick check for any names starting with this character.
+ //
+
+ if (Device->AddressCounts[NbConnectionless->NameFrame.Name[0]] == 0) {
+ return;
+ }
+
+ //
+ // Always respond to broadcast requests.
+ //
+#if defined(_PNP_POWER)
+ if (RtlEqualMemory (NetbiosBroadcastName, NbConnectionless->NameFrame.Name, 16)) {
+
+ NbiSendNameFrame(
+ NULL,
+ NB_NAME_DUPLICATED, // this is what Novell machines use
+ NB_CMD_NAME_RECOGNIZED,
+ RemoteAddress,
+ NbConnectionless);
+
+ } else if (Address = NbiFindAddress(Device, (PUCHAR)NbConnectionless->NameFrame.Name)) {
+
+ NbiSendNameFrame(
+ Address,
+ (UCHAR)(Address->NameTypeFlag | NB_NAME_USED | NB_NAME_REGISTERED),
+ NB_CMD_NAME_RECOGNIZED,
+ RemoteAddress,
+ NbConnectionless);
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ } else if ( NbiFindAdapterAddress( NbConnectionless->NameFrame.Name, LOCK_NOT_ACQUIRED ) ) {
+
+ NbiSendNameFrame(
+ NULL,
+ (UCHAR)(NB_NAME_UNIQUE | NB_NAME_USED | NB_NAME_REGISTERED),
+ NB_CMD_NAME_RECOGNIZED,
+ RemoteAddress,
+ NbConnectionless);
+ }
+#else
+ if (RtlEqualMemory (NetbiosBroadcastName, NbConnectionless->NameFrame.Name, 16)) {
+
+ NbiSendNameFrame(
+ NULL,
+ NB_NAME_DUPLICATED, // this is what Novell machines use
+ NB_CMD_NAME_RECOGNIZED,
+ RemoteAddress,
+ (PTDI_ADDRESS_IPX)(NbConnectionless->IpxHeader.SourceNetwork));
+
+ } else if (Address = NbiFindAddress(Device, (PUCHAR)NbConnectionless->NameFrame.Name)) {
+
+ NbiSendNameFrame(
+ Address,
+ (UCHAR)(Address->NameTypeFlag | NB_NAME_USED | NB_NAME_REGISTERED),
+ NB_CMD_NAME_RECOGNIZED,
+ RemoteAddress,
+ (PTDI_ADDRESS_IPX)(NbConnectionless->IpxHeader.SourceNetwork));
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ }
+#endif _PNP_POWER
+} /* NbiProcessFindName */
+
+
+VOID
+NbiProcessAddName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_ADD_NAME frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADDRESS Address;
+ NB_CONNECTIONLESS UNALIGNED * NbConnectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
+ PDEVICE Device = NbiDevice;
+ CTELockHandle LockHandle;
+ BOOLEAN LocalFrame;
+
+
+ if (PacketSize != sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME)) {
+ return;
+ }
+
+ //
+ // Ignore any frame that came from us, except for the purpose
+ // of updating the cache.
+ //
+
+ if ((Device->Bind.QueryHandler)(
+ IPX_QUERY_IS_ADDRESS_LOCAL,
+#if defined(_PNP_POWER)
+ &RemoteAddress->NicHandle,
+#else
+ RemoteAddress->NicId,
+#endif _PNP_POWER
+ NbConnectionless->IpxHeader.SourceNetwork,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL) == STATUS_SUCCESS) {
+
+ LocalFrame = TRUE;
+
+ } else {
+
+ LocalFrame = FALSE;
+
+ }
+
+ if (!LocalFrame) {
+
+ if ((Device->AddressCounts[NbConnectionless->NameFrame.Name[0]] != 0) &&
+ (Address = NbiFindAddress(Device, (PUCHAR)NbConnectionless->NameFrame.Name))) {
+
+ if (NB_NODE_BROADCAST(NbConnectionless->IpxHeader.DestinationNode)) {
+
+ //
+ // If this frame is an add name (identified because it is a
+ // broadcast frame) then respond if we have it registered
+ // unique, or we have it group and someone is trying to add
+ // it unique.
+ //
+
+ if ((Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_UNIQUE) ||
+ ((Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_GROUP) &&
+ ((NbConnectionless->NameFrame.NameTypeFlag & NB_NAME_GROUP) == 0))) {
+
+ //
+ // According to GeorgeJ's doc, on a name in use we just
+ // echo back the name type flags from the request.
+ //
+
+ NbiSendNameFrame(
+ Address,
+ NbConnectionless->NameFrame.NameTypeFlag,
+ NB_CMD_NAME_IN_USE,
+ RemoteAddress,
+#if defined(_PNP_POWER)
+ NbConnectionless);
+#else
+ (PTDI_ADDRESS_IPX)(NbConnectionless->IpxHeader.SourceNetwork));
+#endif _PNP_POWER
+ }
+
+ } else if ((*(UNALIGNED ULONG *)NbConnectionless->IpxHeader.DestinationNetwork ==
+ *(UNALIGNED ULONG *)Device->Bind.Network) &&
+ NB_NODE_EQUAL(NbConnectionless->IpxHeader.DestinationNode, Device->Bind.Node)) {
+
+ //
+ // If this is an add name response (which will be sent
+ // directly to us) then we need to mark the address
+ // as such.
+ //
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+ Address->Flags |= ADDRESS_FLAGS_DUPLICATE_NAME;
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ }
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ }
+
+ }
+
+
+ //
+ // Pass this frame over to the netbios cache management
+ // routines to check if they need to update their cache.
+ //
+
+ CacheUpdateFromAddName (RemoteAddress, NbConnectionless, LocalFrame);
+
+} /* NbiProcessAddName */
+
+
+PADDRESS
+NbiCreateAddress(
+ IN PDEVICE Device,
+ IN TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a transport address and associates it with
+ the specified transport device context. The reference count in the
+ address is automatically set to 1, and the reference count of the
+ device context is incremented.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ NetbiosAddress - The name to assign to this address, or -1 if it
+ is the broadcast address.
+
+Return Value:
+
+ The newly created address, or NULL if none can be allocated.
+
+--*/
+
+{
+ PADDRESS Address;
+
+ Address = (PADDRESS)NbiAllocateMemory (sizeof(ADDRESS), MEMORY_ADDRESS, "Address");
+ if (Address == NULL) {
+ NB_DEBUG (ADDRESS, ("Create address %.16s failed\n",
+ (NetbiosAddress == (PVOID)-1) ? "<broadcast>" : NetbiosAddress->NetbiosName));
+ return NULL;
+ }
+
+ NB_DEBUG2 (ADDRESS, ("Create address %lx (%.16s)\n", Address,
+ (NetbiosAddress == (PVOID)-1) ? "<broadcast>" : NetbiosAddress->NetbiosName));
+ RtlZeroMemory (Address, sizeof(ADDRESS));
+
+ Address->Type = NB_ADDRESS_SIGNATURE;
+ Address->Size = sizeof (ADDRESS);
+ Address->State = ADDRESS_STATE_REGISTERING;
+ Address->Flags = 0;
+
+ Address->Device = Device;
+ Address->DeviceLock = &Device->Lock;
+ CTEInitLock (&Address->Lock.Lock);
+
+ InitializeListHead (&Address->AddressFileDatabase);
+
+ Address->ReferenceCount = 1;
+#if DBG
+ Address->RefTypes[AREF_ADDRESS_FILE] = 1;
+#endif
+
+ if (NetbiosAddress == (PVOID)-1) {
+ Address->NetbiosAddress.Broadcast = TRUE;
+ } else {
+ Address->NetbiosAddress.Broadcast = FALSE;
+ Address->NetbiosAddress.NetbiosNameType = NetbiosAddress->NetbiosNameType;
+ RtlCopyMemory (Address->NetbiosAddress.NetbiosName, NetbiosAddress->NetbiosName, 16);
+ ++Device->AddressCounts[NetbiosAddress->NetbiosName[0]];
+ }
+
+ if (Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_UNIQUE) {
+ Address->NameTypeFlag = NB_NAME_UNIQUE;
+ } else {
+ Address->NameTypeFlag = NB_NAME_GROUP;
+ }
+
+ //
+ // Now link this address into the specified device context's
+ // address database. To do this, we need to acquire the spin lock
+ // on the device context.
+ //
+
+ InsertTailList (&Device->AddressDatabase, &Address->Linkage);
+ ++Device->AddressCount;
+
+ NbiReferenceDevice (Device, DREF_ADDRESS);
+
+ return Address;
+
+} /* NbiCreateAddress */
+
+
+NTSTATUS
+NbiVerifyAddressFile (
+#if defined(_PNP_POWER)
+ IN PADDRESS_FILE AddressFile,
+ IN BOOLEAN ConflictIsOk
+#else
+ IN PADDRESS_FILE AddressFile
+#endif _PNP_POWER
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to verify that the pointer given us in a file
+ object is in fact a valid address file object. We also verify that the
+ address object pointed to by it is a valid address object, and reference
+ it to keep it from disappearing while we use it.
+
+Arguments:
+
+ AddressFile - potential pointer to a ADDRESS_FILE object
+
+ ConflictIsOk - TRUE if we should succeed the verify even if the
+ corresponding address is in CONFLICT. ( For Close and
+ cleanup we return STATUS_SUCCESS even if we are in conflict
+ so that the addressfile can be destroyed)
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_ADDRESS otherwise
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ NTSTATUS status = STATUS_SUCCESS;
+ PADDRESS Address;
+ BOOLEAN LockHeld = FALSE;
+
+ //
+ // try to verify the address file signature. If the signature is valid,
+ // verify the address pointed to by it and get the address spinlock.
+ // check the address's state, and increment the reference count if it's
+ // ok to use it. Note that the only time we return an error for state is
+ // if the address is closing.
+ //
+
+ try {
+
+ if ((AddressFile->Size == sizeof (ADDRESS_FILE)) &&
+ (AddressFile->Type == NB_ADDRESSFILE_SIGNATURE) ) {
+// (AddressFile->State != ADDRESSFILE_STATE_CLOSING) ) {
+
+ Address = AddressFile->Address;
+
+ if ((Address->Size == sizeof (ADDRESS)) &&
+ (Address->Type == NB_ADDRESS_SIGNATURE) ) {
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ LockHeld = TRUE;
+
+#if defined(_PNP_POWER)
+ if (Address->State != ADDRESS_STATE_STOPPING &&
+ ( ConflictIsOk || ( !(Address->Flags & ADDRESS_FLAGS_CONFLICT) )) ) {
+#else
+ if (Address->State != ADDRESS_STATE_STOPPING) {
+#endif _PNP_POWER
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_VERIFY);
+
+ } else {
+
+ NbiPrint1("NbiVerifyAddressFile: A %lx closing\n", Address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ } else {
+
+ NbiPrint1("NbiVerifyAddressFile: A %lx bad signature\n", Address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } else {
+
+ NbiPrint1("NbiVerifyAddressFile: AF %lx bad signature\n", AddressFile);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ NbiPrint1("NbiVerifyAddressFile: AF %lx exception\n", Address);
+ if (LockHeld) {
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ }
+ return GetExceptionCode();
+ }
+
+ return status;
+
+} /* NbiVerifyAddressFile */
+
+
+VOID
+NbiDestroyAddress(
+ IN PVOID Parameter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a transport address and removes all references
+ made by it to other objects in the transport. The address structure
+ is returned to nonpaged system pool. It is assumed
+ that the caller has already removed all addressfile structures associated
+ with this address.
+
+ It is called from a worker thread queue by NbiDerefAddress when
+ the reference count goes to 0.
+
+ This thread is only queued by NbiDerefAddress. The reason for
+ this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ Address - Pointer to a transport address structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PADDRESS Address = (PADDRESS)Parameter;
+ PDEVICE Device = Address->Device;
+ CTELockHandle LockHandle;
+
+ NB_DEBUG2 (ADDRESS, ("Destroy address %lx <%.16s>\n", Address,
+ Address->NetbiosAddress.Broadcast ? "<broadcast>" : Address->NetbiosAddress.NetbiosName));
+
+ SeDeassignSecurity (&Address->SecurityDescriptor);
+
+ //
+ // Delink this address from its associated device context's address
+ // database. To do this we must spin lock on the device context object,
+ // not on the address.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (!Address->NetbiosAddress.Broadcast) {
+ --Device->AddressCounts[Address->NetbiosAddress.NetbiosName[0]];
+ }
+ --Device->AddressCount;
+ RemoveEntryList (&Address->Linkage);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ NbiFreeMemory (Address, sizeof(ADDRESS), MEMORY_ADDRESS, "Address");
+
+ NbiDereferenceDevice (Device, DREF_ADDRESS);
+
+} /* NbiDestroyAddress */
+
+
+#if DBG
+VOID
+NbiRefAddress(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (Address->ReferenceCount > 0); // not perfect, but...
+
+ InterlockedIncrement( &Address->ReferenceCount );
+} /* NbiRefAddress */
+
+
+VOID
+NbiRefAddressLock(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address
+ when the device lock is already held.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (Address->ReferenceCount > 0); // not perfect, but...
+
+ InterlockedIncrement( &Address->ReferenceCount );
+
+} /* NbiRefAddressLock */
+#endif
+
+
+VOID
+NbiDerefAddress(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport address by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ NbiDestroyAddress to remove it from the system.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG newvalue;
+
+ newvalue = InterlockedDecrement( &Address->ReferenceCount );
+ //
+ // If we have deleted all references to this address, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ CTEAssert (newvalue >= 0);
+
+ if (newvalue == 0) {
+
+#if ISN_NT
+ ExInitializeWorkItem(
+ &Address->u.DestroyAddressQueueItem,
+ NbiDestroyAddress,
+ (PVOID)Address);
+ ExQueueWorkItem(&Address->u.DestroyAddressQueueItem, DelayedWorkQueue);
+#else
+ NbiDestroyAddress(Address);
+#endif
+
+ }
+
+} /* NbiDerefAddress */
+
+
+PADDRESS_FILE
+NbiCreateAddressFile(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates an address file from the pool of ther
+ specified device context. The reference count in the
+ address is automatically set to 1.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+Return Value:
+
+ The allocate address file or NULL.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PADDRESS_FILE AddressFile;
+ UINT i;
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ AddressFile = (PADDRESS_FILE)NbiAllocateMemory (sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile");
+ if (AddressFile == NULL) {
+ NB_DEBUG (ADDRESS, ("Create address file failed\n"));
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return NULL;
+ }
+
+ NB_DEBUG2 (ADDRESS, ("Create address file %lx\n", AddressFile));
+
+ RtlZeroMemory (AddressFile, sizeof(ADDRESS_FILE));
+
+ AddressFile->Type = NB_ADDRESSFILE_SIGNATURE;
+ AddressFile->Size = sizeof (ADDRESS_FILE);
+
+ InitializeListHead (&AddressFile->ReceiveDatagramQueue);
+ InitializeListHead (&AddressFile->ConnectionDatabase);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ AddressFile->Address = NULL;
+#ifdef ISN_NT
+ AddressFile->FileObject = NULL;
+#endif
+ AddressFile->Device = Device;
+ AddressFile->State = ADDRESSFILE_STATE_OPENING;
+ AddressFile->ReferenceCount = 1;
+#if DBG
+ AddressFile->RefTypes[AFREF_CREATE] = 1;
+#endif
+ AddressFile->CloseRequest = (PREQUEST)NULL;
+
+ //
+ // Initialize the request handlers.
+ //
+
+ for (i = 0; i < 6; i++) {
+ AddressFile->RegisteredHandler[i] = FALSE;
+ AddressFile->HandlerContexts[i] = NULL;
+ AddressFile->Handlers[i] = TdiDefaultHandlers[i];
+ }
+
+ CTEAssert (AddressFile->ConnectionHandler == TdiDefaultConnectHandler);
+ CTEAssert (AddressFile->DisconnectHandler == TdiDefaultDisconnectHandler);
+ CTEAssert (AddressFile->ErrorHandler == TdiDefaultErrorHandler);
+ CTEAssert (AddressFile->ReceiveHandler == TdiDefaultReceiveHandler);
+ CTEAssert (AddressFile->ReceiveDatagramHandler == TdiDefaultRcvDatagramHandler);
+ CTEAssert (AddressFile->ExpeditedDataHandler == TdiDefaultRcvExpeditedHandler);
+
+ return AddressFile;
+
+} /* NbiCreateAddressFile */
+
+
+NTSTATUS
+NbiDestroyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys an address file and removes all references
+ made by it to other objects in the transport.
+
+ This routine is only called by NbiDereferenceAddressFile. The reason
+ for this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address file object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ AddressFile Pointer to a transport address file structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ CTELockHandle LockHandle, LockHandle1;
+ PADDRESS Address;
+ PDEVICE Device;
+ PREQUEST CloseRequest;
+ BOOLEAN StopAddress;
+
+ NB_DEBUG2 (ADDRESS, ("Destroy address file %lx\n", AddressFile));
+
+ Address = AddressFile->Address;
+ Device = AddressFile->Device;
+
+ if (Address) {
+
+ //
+ // This addressfile was associated with an address.
+ //
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ //
+ // remove this addressfile from the address list and disassociate it from
+ // the file handle.
+ //
+
+ RemoveEntryList (&AddressFile->Linkage);
+ InitializeListHead (&AddressFile->Linkage);
+
+ if (Address->AddressFileDatabase.Flink == &Address->AddressFileDatabase) {
+
+ //
+ // This is the last open of this address, it will close
+ // due to normal dereferencing but we have to set the
+ // CLOSING flag too to stop further references.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle1);
+ Address->State = ADDRESS_STATE_STOPPING;
+ NB_FREE_LOCK (&Device->Lock, LockHandle1);
+
+ StopAddress = TRUE;
+
+ } else {
+
+ StopAddress = FALSE;
+ }
+
+ AddressFile->Address = NULL;
+
+#ifdef ISN_NT
+ AddressFile->FileObject->FsContext = NULL;
+ AddressFile->FileObject->FsContext2 = NULL;
+#endif
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ //
+ // We will already have been removed from the ShareAccess
+ // of the owning address.
+ //
+
+ if (StopAddress && (!Address->NetbiosAddress.Broadcast)) {
+
+ NbiSendNameFrame(
+ Address,
+ (UCHAR)(Address->NameTypeFlag |
+ NB_NAME_USED | NB_NAME_REGISTERED | NB_NAME_DEREGISTERED),
+ NB_CMD_DELETE_NAME,
+ NULL,
+ NULL);
+ }
+
+ //
+ // Now dereference the owning address.
+ //
+
+ NbiDereferenceAddress (Address, AREF_ADDRESS_FILE);
+
+ }
+
+ //
+ // Save this for later completion.
+ //
+
+ CloseRequest = AddressFile->CloseRequest;
+
+ //
+ // return the addressFile to the pool of address files
+ //
+
+ NbiFreeMemory (AddressFile, sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile");
+
+ if (CloseRequest != (PREQUEST)NULL) {
+ REQUEST_INFORMATION(CloseRequest) = 0;
+ REQUEST_STATUS(CloseRequest) = STATUS_SUCCESS;
+ NbiCompleteRequest (CloseRequest);
+ NbiFreeRequest (Device, CloseRequest);
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbiDestroyAddressFile */
+
+
+#if DBG
+VOID
+NbiRefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+
+ InterlockedIncrement( &AddressFile->ReferenceCount );
+} /* NbiRefAddressFile */
+
+
+VOID
+NbiRefAddressFileLock(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+ IT IS CALLED WITH THE ADDRESS LOCK HELD.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+
+ InterlockedIncrement( &AddressFile->ReferenceCount );
+
+} /* NbiRefAddressFileLock */
+
+#endif
+
+
+VOID
+NbiDerefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences an address file by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ NbiDestroyAddressFile to remove it from the system.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG newvalue;
+
+ newvalue = InterlockedDecrement( &AddressFile->ReferenceCount );
+
+ //
+ // If we have deleted all references to this address file, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ CTEAssert (newvalue >= 0);
+
+ if (newvalue == 0) {
+ NbiDestroyAddressFile (AddressFile);
+ }
+
+} /* NbiDerefAddressFile */
+
+#if !defined(_PNP_POWER)
+
+PADDRESS
+NbiLookupAddress(
+ IN PDEVICE Device,
+ IN TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the transport addresses defined for the given
+ device context and compares them with the specified NETWORK
+ NAME values. If an exact match is found, then a pointer to the
+ ADDRESS object is returned, and as a side effect, the reference
+ count to the address object is incremented. If the address is not
+ found, then NULL is returned.
+
+ NOTE: This routine must be called with the Device
+ spinlock held.
+
+Arguments:
+
+ Device - Pointer to the device object and its extension.
+
+ NetbiosAddress - The name to look up, or -1 if the broadcast
+ address is being searched for.
+
+Return Value:
+
+ Pointer to the ADDRESS object found, or NULL if not found.
+
+--*/
+
+{
+ PADDRESS Address;
+ PLIST_ENTRY p;
+
+ p = Device->AddressDatabase.Flink;
+
+ for (p = Device->AddressDatabase.Flink;
+ p != &Device->AddressDatabase;
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ if (Address->State == ADDRESS_STATE_STOPPING) {
+ continue;
+ }
+
+ if (Address->NetbiosAddress.Broadcast) {
+
+ //
+ // This address is the broadcast one, so no match
+ // unless we are looking for that.
+ //
+
+ if (NetbiosAddress != (PVOID)-1) {
+ continue;
+ }
+
+ } else {
+
+ //
+ // This address is not the broadcast, so if we are
+ // looking for that then no match, else compare the
+ // two names.
+ //
+
+ if (NetbiosAddress == (PVOID)-1) {
+ continue;
+ }
+
+ if (!RtlEqualMemory(
+ Address->NetbiosAddress.NetbiosName,
+ NetbiosAddress->NetbiosName,
+ 16)) {
+ continue;
+ }
+ }
+
+ //
+ // We found the match. Bump the reference count on the address, and
+ // return a pointer to the address object for the caller to use.
+ //
+
+ NbiReferenceAddressLock (Address, AREF_LOOKUP);
+ return Address;
+
+ } /* for */
+
+ //
+ // The specified address was not found.
+ //
+
+ return NULL;
+
+} /* NbiLookupAddress */
+#endif !_PNP_POWER
+
+
+PADDRESS
+NbiFindAddress(
+ IN PDEVICE Device,
+ IN PUCHAR NetbiosName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the transport addresses defined for the given
+ device context and compares them with the specified NetbiosName
+ values. If a match is found, the address is referenced and the
+ pointer is returned.
+
+ We ignore any addresses which are either STOPPING or are under
+ CONFLICT state.
+
+ A name in CONFLICT is dead for all practical purposes
+ except Close. This routine is called by various name service,
+ datagram and session sevice routines. We hide any names in CONFLICT
+ from these routines.
+
+ This routine is also called by NbiTdiOpenAddress().
+ A name could have been marked in CONFLICT ages ago(but is not closed
+ yet). We must allow another open of the same name as that might
+ succeed now.
+
+Arguments:
+
+ Device - Pointer to the device object and its extension.
+
+ NetbiosName - The name to look up, or -1 for the broadcast name.
+
+Return Value:
+
+ Pointer to the ADDRESS object found, or NULL if not found.
+
+--*/
+
+{
+ PADDRESS Address;
+ PLIST_ENTRY p;
+ CTELockHandle LockHandle;
+
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ p = Device->AddressDatabase.Flink;
+
+ for (p = Device->AddressDatabase.Flink;
+ p != &Device->AddressDatabase;
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+#if defined(_PNP_POWER)
+ if ( ( Address->State == ADDRESS_STATE_STOPPING ) ||
+ ( Address->Flags & ADDRESS_FLAGS_CONFLICT ) ) {
+#else
+ if (Address->State == ADDRESS_STATE_STOPPING) {
+#endif _PNP_POWER
+ continue;
+ }
+
+ if (Address->NetbiosAddress.Broadcast) {
+
+ //
+ // This address is the broadcast one, so no match
+ // unless we are looking for that.
+ //
+
+ if (NetbiosName != (PVOID)-1) {
+ continue;
+ }
+
+ } else {
+
+ //
+ // This address is not the broadcast, so if we are
+ // looking for that then no match, else compare the
+ // two names.
+ //
+
+ if ((NetbiosName == (PVOID)-1) ||
+ (!RtlEqualMemory(
+ Address->NetbiosAddress.NetbiosName,
+ NetbiosName,
+ 16))) {
+ continue;
+ }
+ }
+
+
+ //
+ // We found the match. Bump the reference count on the address, and
+ // return a pointer to the address object for the caller to use.
+ //
+
+ NbiReferenceAddressLock (Address, AREF_FIND);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return Address;
+
+ } /* for */
+
+ //
+ // The specified address was not found.
+ //
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return NULL;
+
+} /* NbiFindAddress */
+
+
+NTSTATUS
+NbiStopAddressFile(
+ IN PADDRESS_FILE AddressFile,
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to terminate all activity on an AddressFile and
+ destroy the object. We remove every connection and datagram associated
+ with this addressfile from the address database and terminate their
+ activity. Then, if there are no other outstanding addressfiles open on
+ this address, the address will go away.
+
+Arguments:
+
+ AddressFile - pointer to the addressFile to be stopped
+
+ Address - the owning address for this addressFile (we do not depend upon
+ the pointer in the addressFile because we want this routine to be safe)
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the request
+ is not for a real address.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PCONNECTION Connection;
+ PREQUEST Request;
+ PDEVICE Device = Address->Device;
+ CTELockHandle LockHandle1, LockHandle2;
+ LIST_ENTRY SendDatagramList;
+ PNB_SEND_RESERVED Reserved;
+ PREQUEST DatagramRequest;
+ NB_DEFINE_LOCK_HANDLE (LockHandle3)
+ CTELockHandle CancelLH;
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+ LIST_ENTRY DatagramQ;
+
+
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle1);
+
+ if (AddressFile->State == ADDRESSFILE_STATE_CLOSING) {
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+ return STATUS_SUCCESS;
+ }
+
+
+ //
+ // This prevents anybody else from being put on the
+ // ConnectionDatabase.
+ //
+
+ AddressFile->State = ADDRESSFILE_STATE_CLOSING;
+
+ while (!IsListEmpty (&AddressFile->ConnectionDatabase)) {
+
+ p = RemoveHeadList (&AddressFile->ConnectionDatabase);
+ Connection = CONTAINING_RECORD (p, CONNECTION, AddressFileLinkage);
+
+ CTEAssert (Connection->AddressFile == AddressFile);
+ Connection->AddressFileLinked = FALSE;
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if (Connection->ReferenceCount == 0) {
+
+ //
+ // The refcount is already 0, so we can just
+ // NULL out this field to complete the disassociate.
+ //
+
+ Connection->AddressFile = NULL;
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
+
+ } else {
+
+ //
+ // Mark this so we know to disassociate when the
+ // count goes to 0, but that there is no specific
+ // request pending on it. We also stop the connection
+ // to shut it down.
+ //
+
+ Connection->DisassociatePending = (PVOID)-1;
+ NbiReferenceConnectionLock (Connection, CREF_DISASSOC);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+
+ NB_BEGIN_SYNC (&SyncContext);
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle3);
+
+ //
+ // This call frees the connection lock.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_INVALID_ADDRESS
+ NB_LOCK_HANDLE_ARG (LockHandle3));
+
+ NB_END_SYNC (&SyncContext);
+
+ NbiDereferenceConnection (Connection, CREF_DISASSOC);
+
+ }
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle1);
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+
+
+ //
+ // Abort all pending send datagrams.
+ //
+ // BUGBUG: Also make them cancellable.
+ //
+
+ InitializeListHead (&SendDatagramList);
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ p = Device->WaitingDatagrams.Flink;
+
+ while (p != &Device->WaitingDatagrams) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ p = p->Flink;
+
+ if (Reserved->u.SR_DG.AddressFile == AddressFile) {
+
+ RemoveEntryList (&Reserved->WaitLinkage);
+ InsertTailList (&SendDatagramList, &Reserved->WaitLinkage);
+
+ }
+
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ for (p = SendDatagramList.Flink; p != &SendDatagramList; ) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+ p = p->Flink;
+
+ DatagramRequest = Reserved->u.SR_DG.DatagramRequest;
+
+ NB_DEBUG2 (DATAGRAM, ("Aborting datagram %lx on %lx\n", DatagramRequest, AddressFile));
+
+ REQUEST_STATUS(DatagramRequest) = STATUS_SUCCESS;
+
+ NbiCompleteRequest(DatagramRequest);
+ NbiFreeRequest (Device, DatagramRequest);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_SEND_DGRAM);
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ }
+
+
+ //
+ // Abort all pending receive datagrams.
+ //
+
+ InitializeListHead( &DatagramQ );
+
+ NB_GET_CANCEL_LOCK(&CancelLH);
+ NB_GET_LOCK (&Address->Lock, &LockHandle1);
+
+ while (!IsListEmpty(&AddressFile->ReceiveDatagramQueue)) {
+
+ p = RemoveHeadList (&AddressFile->ReceiveDatagramQueue);
+ Request = LIST_ENTRY_TO_REQUEST (p);
+
+ // Insert it on a private Q, so it can be completed later.
+ InsertTailList( &DatagramQ, p);
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_NETWORK_NAME_DELETED;
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+
+
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
+
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK(CancelLH);
+
+ for( p = DatagramQ.Flink; p != &DatagramQ; ) {
+ Request = LIST_ENTRY_TO_REQUEST ( p );
+
+ p = p->Flink;
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+
+ }
+
+
+ return STATUS_SUCCESS;
+
+} /* NbiStopAddressFile */
+
+
+NTSTATUS
+NbiCloseAddressFile(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to close the addressfile pointed to by a file
+ object. If there is any activity to be run down, we will run it down
+ before we terminate the addressfile. We remove every connection and
+ datagram associated with this addressfile from the address database
+ and terminate their activity. Then, if there are no other outstanding
+ addressfiles open on this address, the address will go away.
+
+Arguments:
+
+ Request - the close request.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the
+ request does not point to a real address.
+
+--*/
+
+{
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+ AddressFile->CloseRequest = Request;
+
+ //
+ // We assume that addressFile has already been verified
+ // at this point.
+ //
+
+ Address = AddressFile->Address;
+ CTEAssert (Address);
+
+ //
+ // Remove us from the access info for this address.
+ //
+
+ ExAcquireResourceExclusive (&Device->AddressResource, TRUE);
+#ifdef ISN_NT
+ IoRemoveShareAccess (AddressFile->FileObject, &Address->u.ShareAccess);
+#endif
+ ExReleaseResource (&Device->AddressResource);
+
+ NbiStopAddressFile (AddressFile, Address);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ return STATUS_PENDING;
+
+} /* NbiCloseAddressFile */
+
+#if defined(_PNP_POWER)
+
+
+PADAPTER_ADDRESS
+NbiCreateAdapterAddress(
+ IN PCHAR AdapterMacAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates an adapter address sttuctures which stores
+ the netbios name of an adapter. the netbios name has 12 0's
+ followed by the mac address of the adapter.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ AdapterMacAddress - pointer to the adapter mac address given to us
+ by IPX.
+
+Return Value:
+
+ The newly created address, or NULL if none can be allocated.
+ THIS ROUTINE MUST BE CALLED WITH THE DEVICE LOCK HELD.
+
+--*/
+
+{
+ PADAPTER_ADDRESS AdapterAddress;
+ CTELockHandle LockHandle;
+ PDEVICE Device = NbiDevice;
+
+ AdapterAddress = (PADAPTER_ADDRESS)NbiAllocateMemory (sizeof(ADAPTER_ADDRESS), MEMORY_ADAPTER_ADDRESS, "Adapter Address");
+ if (AdapterAddress == NULL) {
+ NB_DEBUG (ADDRESS, ("Create Adapter Address %<2.2x><2.2x><2.2x><2.2x><2.2x><2.2x> failed\n",
+ AdapterMacAddress[0],
+ AdapterMacAddress[1],
+ AdapterMacAddress[2],
+ AdapterMacAddress[3],
+ AdapterMacAddress[4],
+ AdapterMacAddress[5]
+ ));
+ return NULL;
+ }
+
+ AdapterAddress->Type = NB_ADAPTER_ADDRESS_SIGNATURE;
+ AdapterAddress->Size = sizeof (ADDRESS);
+
+ RtlZeroMemory(AdapterAddress->NetbiosName, 10);
+ RtlCopyMemory(&AdapterAddress->NetbiosName[10], AdapterMacAddress, 6);
+
+
+ InsertTailList (&Device->AdapterAddressDatabase, &AdapterAddress->Linkage);
+ ++Device->AddressCounts[AdapterAddress->NetbiosName[0]];
+
+ return AdapterAddress;
+
+} /* NbiCreateAdapterAddress */
+
+
+NTSTATUS
+NbiDestroyAdapterAddress(
+ IN PADAPTER_ADDRESS AdapterAddress OPTIONAL,
+ IN PCHAR AdapterMacAddress OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys the adapter address structure and removes it
+ from the list.
+
+Arguments:
+
+ AdapterAddress - Pointer to an adapter address structure to be destroyed
+ NULL if AdapterMacAddress is given.
+
+ AdapterMacAddress - Mac Address of the adapter which just got deleted. so find
+ the corresponding adapter address structure and remove it.
+ NULL if AdapterAddress is supplied.
+
+Return Value:
+
+ STATUS_SUCCESS or STATUS_UNSUCCESSFUL if address not found.
+
+ THIS ROUTINE ASSUMES THE THE DEVICE IS LOCK IS HELD BY THE CALLER
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ CTELockHandle LockHandle;
+ UCHAR NetbiosName[NB_NETBIOS_NAME_SIZE];
+
+
+ //
+
+ CTEAssert( AdapterAddress || AdapterMacAddress );
+ if ( !AdapterAddress ) {
+ RtlZeroMemory( NetbiosName, 10);
+ RtlCopyMemory( &NetbiosName[10], AdapterMacAddress, 6 );
+
+ AdapterAddress = NbiFindAdapterAddress( NetbiosName, LOCK_ACQUIRED );
+
+ if ( !AdapterAddress ) {
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ NB_DEBUG2 (ADDRESS, ("Destroy Adapter address %lx <%.16s>\n", AdapterAddress,AdapterAddress->NetbiosName));
+ RemoveEntryList (&AdapterAddress->Linkage);
+ ++Device->AddressCounts[AdapterAddress->NetbiosName[0]];
+
+ NbiFreeMemory (AdapterAddress, sizeof(ADAPTER_ADDRESS), MEMORY_ADAPTER_ADDRESS, "AdapterAddress");
+
+ return STATUS_SUCCESS;
+} /* NbiDestroyAdapterAddress */
+
+
+PADAPTER_ADDRESS
+NbiFindAdapterAddress(
+ IN PCHAR NetbiosName,
+ IN BOOLEAN LockHeld
+ )
+
+/*++
+
+Routine Description:
+
+ This routine finds an adapter address ( netbios name ) for the given
+ AdapterMacAddress and returns a pointer to it. Note that no reference
+ is done on this address, so if this routine is called without the device
+ lock, the caller must not use this pointer directly.
+
+Arguments:
+
+ NetbiosName - NetbiosName to be found.
+
+ LockHeld - is device lock already held or not.
+
+Return Value:
+
+ Pointer to the adapter address if found, NULL otherwise.
+
+--*/
+
+{
+
+ PLIST_ENTRY p;
+ CTELockHandle LockHandle;
+ PADAPTER_ADDRESS AdapterAddress;
+ PDEVICE Device = NbiDevice;
+
+
+ if ( !LockHeld ) {
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+ }
+ for ( p = Device->AdapterAddressDatabase.Flink;
+ p != &Device->AdapterAddressDatabase;
+ p = p->Flink ) {
+
+ AdapterAddress = CONTAINING_RECORD( p, ADAPTER_ADDRESS, Linkage );
+ if ( RtlEqualMemory(
+ NetbiosName,
+ AdapterAddress->NetbiosName,
+ NB_NETBIOS_NAME_SIZE ) ) {
+ break;
+ }
+ }
+
+
+ if ( !LockHeld ) {
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+ }
+
+ if ( p == &Device->AdapterAddressDatabase ) {
+ return NULL;
+ } else {
+ return AdapterAddress;
+ }
+
+} /* NbiFindAdapterAddress */
+
+#endif _PNP_POWER
diff --git a/private/ntos/tdi/isnp/nb/autodial.c b/private/ntos/tdi/isnp/nb/autodial.c
new file mode 100644
index 000000000..ec56e2351
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/autodial.c
@@ -0,0 +1,526 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ autodial.c
+
+Abstract:
+
+ NT specific routines for interfacing with the
+ RAS AutoDial driver (rasacd.sys).
+
+Author:
+
+ Anthony Discolo (adiscolo) Aug 30, 1995
+
+Revision History:
+
+ Who When What
+ -------- -------- ----------------------------------------------
+ adiscolo 08-30-95 created
+
+Notes:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef RASAUTODIAL
+
+#include <acd.h>
+#include <acdapi.h>
+
+//
+// Global variables
+//
+BOOLEAN fAcdLoadedG;
+ACD_DRIVER AcdDriverG;
+ULONG ulDriverIdG = 'Nbi ';
+
+
+
+VOID
+NbiRetryTdiConnect(
+ IN BOOLEAN fSuccess,
+ IN PVOID *pArgs
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called indirectly by the automatic
+ connection driver to continue the connection process
+ after an automatic connection has been made.
+
+Arguments:
+
+ fSuccess - TRUE if the connection attempt was successful.
+
+ pArgs - a pointer to the argument vector
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NTSTATUS status;
+ PDEVICE pDevice = pArgs[0];
+ PCONNECTION pConnection = pArgs[1];
+ PREQUEST pRequest = pArgs[2];
+ CTELockHandle ConnectionLH, DeviceLH;
+ CTELockHandle CancelLH;
+ BOOLEAN bLockFreed = FALSE;
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+#if notdef // DBG
+ DbgPrint("NbiRetryTdiConnect: fSuccess=%d, pConnection=0x%x\n", fSuccess, pConnection);
+#endif
+
+ status = NbiVerifyConnection(pConnection);
+ if (!NT_SUCCESS(status)) {
+ DbgPrint(
+ "NbiRetryTdiConnect: NbiVerifyConnection failed on connection 0x%x (status=0x%x)\n",
+ pConnection,
+ status);
+ return;
+ }
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_GET_LOCK (&pConnection->Lock, &ConnectionLH);
+ NB_GET_LOCK (&pDevice->Lock, &DeviceLH);
+
+#if notdef // DBG
+ DbgPrint(
+ "NbiRetryTdiConnect: AddressFile=0x%x, DisassociatePending=0x%x, ClosePending=0x%x\n",
+ pConnection->AddressFile,
+ pConnection->DisassociatePending,
+ pConnection->ClosePending);
+#endif
+
+ if ((pConnection->AddressFile != NULL) &&
+ (pConnection->AddressFile != (PVOID)-1) &&
+ (pConnection->DisassociatePending == NULL) &&
+ (pConnection->ClosePending == NULL))
+ {
+ NbiReferenceConnectionLock(pConnection, CREF_CONNECT);
+ //
+ // Clear the AUTOCONNECTING flag since we
+ // done with the automatic connection attempt.
+ // Set the AUTOCONNECTED flag to prevent us
+ // from attempting an automatic connection
+ // for this connection again.
+ //
+ pConnection->Flags &= ~CONNECTION_FLAGS_AUTOCONNECTING;
+ pConnection->Flags |= CONNECTION_FLAGS_AUTOCONNECTED;
+
+ pConnection->State = CONNECTION_STATE_CONNECTING;
+ pConnection->Retries = pDevice->ConnectionCount;
+ status = NbiTdiConnectFindName(
+ pDevice,
+ pRequest,
+ pConnection,
+ CancelLH,
+ ConnectionLH,
+ DeviceLH,
+ &bLockFreed);
+ }
+ else {
+ DbgPrint("NbiRetryTdiConnect: Connect on invalid connection 0x%x\n", pConnection);
+
+ pConnection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+ NB_FREE_LOCK (&pDevice->Lock, DeviceLH);
+ status = STATUS_INVALID_CONNECTION;
+ }
+ if (!bLockFreed) {
+ NB_FREE_LOCK (&pConnection->Lock, ConnectionLH);
+ NB_FREE_CANCEL_LOCK(CancelLH);
+ }
+ //
+ // Complete the irp if necessary.
+ //
+ if (status != STATUS_PENDING) {
+ REQUEST_INFORMATION(pRequest) = 0;
+ REQUEST_STATUS(pRequest) = status;
+
+ NbiCompleteRequest(pRequest);
+ NbiFreeRequest(pDevice, pRequest);
+ }
+ NbiDereferenceConnection(pConnection, CREF_VERIFY);
+} /* NbiRetryTdiConnect */
+
+
+
+BOOLEAN
+NbiCancelAutoDialRequest(
+ IN PVOID pArg,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN USHORT nArgs,
+ IN PVOID *pArgs
+ )
+{
+#if notdef // DBG
+ DbgPrint("NbiCancelAutodialRequest: pArg=0x%x\n", pArg);
+#endif
+ if (nArgs != 2)
+ return FALSE;
+
+ return (pArgs[1] == pArg);
+} // NbiCancelAutoDialRequest
+
+
+
+BOOLEAN
+NbiCancelTdiConnect(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest,
+ IN PCONNECTION pConnection
+ )
+
+/*++
+
+DESCRIPTION
+ This routine is called by the I/O system to cancel a connection
+ when we are attempting to restore an automatic connection.
+
+ARGUMENTS
+ pDevice: a pointer to the device object for this driver
+
+ pRequest: a pointer to the irp to be cancelled
+
+ pConnection: a pointer to the connnection to be cancelled
+
+RETURN VALUE
+ TRUE if the request was canceled; FALSE otherwise.
+
+--*/
+
+{
+ ACD_ADDR addr;
+
+ //
+ // Get the address of the connection.
+ //
+ addr.fType = ACD_ADDR_NB;
+ RtlCopyMemory(&addr.cNetbios, pConnection->RemoteName, 16);
+#ifdef notdef // DBG
+ DbgPrint(
+ "NbiCancelTdiConnect: pIrp=0x%x, RemoteName=%-15.15s, pConnection=0x%x\n",
+ pRequest,
+ addr.cNetbios,
+ pConnection);
+#endif
+ //
+ // Cancel the autodial request.
+ //
+ return (*AcdDriverG.lpfnCancelConnection)(
+ ulDriverIdG,
+ &addr,
+ NbiCancelAutoDialRequest,
+ pConnection);
+} // NbiCancelTdiConnect
+
+
+
+BOOLEAN
+NbiAttemptAutoDial(
+ IN PDEVICE pDevice,
+ IN PCONNECTION pConnection,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN PREQUEST pRequest
+ )
+
+/*++
+
+Routine Description:
+
+ Call the automatic connection driver to attempt an
+ automatic connection.
+
+Arguments:
+
+ pDevice - a pointer to the DEVICE structure for this connection
+
+ pConnection - a pointer to the CONNECTION block for this connection
+
+ ulFlags - connection flags to pass to the automatic
+ connection driver
+
+ pProc - a callback procedure when the automatic connection completes
+
+ pRequest - a pointer to the request irp
+
+Return Value:
+
+ TRUE if the automatic connection was started successfully,
+ FALSE otherwise.
+
+--*/
+
+{
+ ACD_ADDR addr;
+ PVOID pArgs[3];
+ BOOLEAN bSuccess;
+
+ //
+ // If we've already attempted an automatic connection
+ // on this connection, don't try it again.
+ //
+ if (pConnection->Flags & CONNECTION_FLAGS_AUTOCONNECTED)
+ return FALSE;
+ //
+ // Get the address of the connection.
+ //
+ addr.fType = ACD_ADDR_NB;
+ RtlCopyMemory(&addr.cNetbios, pConnection->RemoteName, 16);
+#ifdef notdef // DBG
+ DbgPrint("NbiAttemptAutoDial: szAddr=%15.15s\n", addr.cNetbios);
+#endif
+ //
+ // Attempt to start the connection.
+ // NbiRetryTdiConnect() will be called
+ // when the connection process has completed.
+ //
+ pArgs[0] = pDevice;
+ pArgs[1] = pConnection;
+ pArgs[2] = pRequest;
+ bSuccess = (*AcdDriverG.lpfnStartConnection)(
+ ulDriverIdG,
+ &addr,
+ ulFlags,
+ pProc,
+ 3,
+ pArgs);
+ if (bSuccess) {
+ //
+ // Set the AUTOCONNECTING flag so we know
+ // to also cancel the connection in the
+ // automatic connection driver if this
+ // request gets canceled.
+ //
+ pConnection->Flags |= CONNECTION_FLAGS_AUTOCONNECTING;
+ }
+} // NbiAttemptAutoDial
+
+
+
+VOID
+NbiNoteNewConnection(
+ IN PCONNECTION pConnection
+ )
+{
+ NTSTATUS status;
+ ACD_ADDR addr;
+ ACD_ADAPTER adapter;
+ ULONG i;
+ TDI_ADDRESS_IPX tdiIpxAddress;
+
+ addr.fType = ACD_ADDR_NB;
+ RtlCopyMemory(&addr.cNetbios, pConnection->RemoteName, 16);
+ //
+ // Determine the mac address of the adapter
+ // over which the connection has been made.
+ //
+ status = (pConnection->Device->Bind.QueryHandler)(
+ IPX_QUERY_IPX_ADDRESS,
+#if defined(_PNP_POWER)
+ &pConnection->LocalTarget.NicHandle,
+#else
+ pConnection->LocalTarget.NicId,
+#endif _PNP_POWER
+ &tdiIpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL);
+ if (status != STATUS_SUCCESS) {
+#if notdef // DBG
+ DbgPrint("NbiNoteNewConnection: QueryHandler(IPX_QUERY_IPX_ADDRESS) failed (status=0x%x)\n", status);
+ return;
+#endif
+ }
+ //
+ // Copy the source mac address to identify
+ // the adapter.
+ //
+ adapter.fType = ACD_ADAPTER_MAC;
+ for (i = 0; i < 6; i++)
+ adapter.cMac[i] = tdiIpxAddress.NodeAddress[i];
+#if notdef // DBG
+ DbgPrint(
+ "NbiNoteNewConnection: address=%-15.15s, remote mac=%02x:%02x:%02x:%02x:%02x:%02x\n",
+ addr.cNetbios,
+ adapter.cMac[0],
+ adapter.cMac[1],
+ adapter.cMac[2],
+ adapter.cMac[3],
+ adapter.cMac[4],
+ adapter.cMac[5]);
+#endif
+ //
+ // Simply notify the automatic connection driver
+ // that a successful connection has been made.
+ //
+ (*AcdDriverG.lpfnNewConnection)(
+ &addr,
+ &adapter);
+} // NbiNoteNewConnection
+
+
+
+VOID
+NbiAcdBind()
+{
+ NTSTATUS status;
+ UNICODE_STRING nameString;
+ IO_STATUS_BLOCK ioStatusBlock;
+ PIRP pIrp;
+ PFILE_OBJECT pAcdFileObject;
+ PDEVICE_OBJECT pAcdDeviceObject;
+ PACD_DRIVER pDriver = &AcdDriverG;
+
+ //
+ // Initialize the name of the automatic
+ // connection device.
+ //
+ RtlInitUnicodeString(&nameString, ACD_DEVICE_NAME);
+ //
+ // Get the file and device objects for the
+ // device.
+ //
+ status = IoGetDeviceObjectPointer(
+ &nameString,
+ SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
+ &pAcdFileObject,
+ &pAcdDeviceObject);
+ if (status != STATUS_SUCCESS)
+ return;
+ //
+ // Reference the device object.
+ //
+ ObReferenceObject(pAcdDeviceObject);
+ //
+ // Remove the reference IoGetDeviceObjectPointer()
+ // put on the file object.
+ //
+ ObDereferenceObject(pAcdFileObject);
+ //
+ // Initialize our part of the ACD_DRIVER
+ // structure.
+ //
+ KeInitializeSpinLock(&AcdDriverG.SpinLock);
+ AcdDriverG.ulDriverId = ulDriverIdG;
+ AcdDriverG.fEnabled = FALSE;
+ //
+ // Build a request to get the automatic
+ // connection driver entry points.
+ //
+ pIrp = IoBuildDeviceIoControlRequest(
+ IOCTL_INTERNAL_ACD_BIND,
+ pAcdDeviceObject,
+ (PVOID)&pDriver,
+ sizeof (pDriver),
+ NULL,
+ 0,
+ TRUE,
+ NULL,
+ &ioStatusBlock);
+ if (pIrp == NULL) {
+ ObDereferenceObject(pAcdDeviceObject);
+ return;
+ }
+ //
+ // Submit the request to the
+ // automatic connection driver.
+ //
+ status = IoCallDriver(pAcdDeviceObject, pIrp);
+ fAcdLoadedG = (status == STATUS_SUCCESS);
+ //
+ // Close the device.
+ //
+ ObDereferenceObject(pAcdDeviceObject);
+} // NbiAcdBind
+
+
+
+VOID
+NbiAcdUnbind()
+{
+ NTSTATUS status;
+ UNICODE_STRING nameString;
+ IO_STATUS_BLOCK ioStatusBlock;
+ PIRP pIrp;
+ PFILE_OBJECT pAcdFileObject;
+ PDEVICE_OBJECT pAcdDeviceObject;
+ PACD_DRIVER pDriver = &AcdDriverG;
+
+ //
+ // Don't bother to unbind if we
+ // didn't successfully bind in the
+ // first place.
+ //
+ if (!fAcdLoadedG)
+ return;
+ //
+ // Initialize the name of the automatic
+ // connection device.
+ //
+ RtlInitUnicodeString(&nameString, ACD_DEVICE_NAME);
+ //
+ // Get the file and device objects for the
+ // device.
+ //
+ status = IoGetDeviceObjectPointer(
+ &nameString,
+ SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
+ &pAcdFileObject,
+ &pAcdDeviceObject);
+ if (status != STATUS_SUCCESS)
+ return;
+ //
+ // Reference the device object.
+ //
+ ObReferenceObject(pAcdDeviceObject);
+ //
+ // Remove the reference IoGetDeviceObjectPointer()
+ // put on the file object.
+ //
+ ObDereferenceObject(pAcdFileObject);
+ //
+ // Build a request to unbind from
+ // the automatic connection driver.
+ //
+ pIrp = IoBuildDeviceIoControlRequest(
+ IOCTL_INTERNAL_ACD_UNBIND,
+ pAcdDeviceObject,
+ (PVOID)&pDriver,
+ sizeof (pDriver),
+ NULL,
+ 0,
+ TRUE,
+ NULL,
+ &ioStatusBlock);
+ if (pIrp == NULL) {
+ ObDereferenceObject(pAcdDeviceObject);
+ return;
+ }
+ //
+ // Submit the request to the
+ // automatic connection driver.
+ //
+ status = IoCallDriver(pAcdDeviceObject, pIrp);
+ //
+ // Close the device.
+ //
+ ObDereferenceObject(pAcdDeviceObject);
+} // NbiAcdUnbind
+
+#endif // RASAUTODIAL
diff --git a/private/ntos/tdi/isnp/nb/bind.c b/private/ntos/tdi/isnp/nb/bind.c
new file mode 100644
index 000000000..7dc20d0d5
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/bind.c
@@ -0,0 +1,593 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ driver.c
+
+Abstract:
+
+ This module contains the DriverEntry and other initialization
+ code for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 16-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,NbiBind)
+#endif
+
+#if defined(_PNP_POWER)
+//
+// local functions.
+//
+VOID
+NbiPnPNotification(
+ IN IPX_PNP_OPCODE OpCode,
+ IN PVOID PnPData
+ );
+#endif _PNP_POWER
+
+
+NTSTATUS
+NbiBind(
+ IN PDEVICE Device,
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine binds the Netbios module of ISN to the IPX
+ module, which provides the NDIS binding services.
+
+Arguments:
+
+ Device - Pointer to the Netbios device.
+
+ Config - Pointer to the configuration information.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatusBlock;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+/* union {
+ IPX_INTERNAL_BIND_INPUT Input;
+ IPX_INTERNAL_BIND_OUTPUT Output;
+ } Bind;
+*/
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &Config->BindName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = ZwCreateFile(
+ &Device->BindHandle,
+ SYNCHRONIZE | GENERIC_READ,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0L);
+
+ if (!NT_SUCCESS(Status)) {
+
+ NB_DEBUG (BIND, ("Could not open IPX (%ws) %lx\n",
+ Config->BindName.Buffer, Status));
+ NbiWriteGeneralErrorLog(
+ Device,
+ EVENT_TRANSPORT_ADAPTER_NOT_FOUND,
+ 1,
+ Status,
+ Config->BindName.Buffer,
+ 0,
+ NULL);
+ return Status;
+ }
+
+ //
+ // Fill in our bind data.
+ //
+
+#if defined(_PNP_POWER)
+ Device->BindInput.Version = ISN_VERSION;
+#else
+ Device->BindInput.Version = 1;
+#endif _PNP_POWER
+ Device->BindInput.Identifier = IDENTIFIER_NB;
+ Device->BindInput.BroadcastEnable = TRUE;
+ Device->BindInput.LookaheadRequired = 192;
+ Device->BindInput.ProtocolOptions = 0;
+ Device->BindInput.ReceiveHandler = NbiReceive;
+ Device->BindInput.ReceiveCompleteHandler = NbiReceiveComplete;
+ Device->BindInput.StatusHandler = NbiStatus;
+ Device->BindInput.SendCompleteHandler = NbiSendComplete;
+ Device->BindInput.TransferDataCompleteHandler = NbiTransferDataComplete;
+ Device->BindInput.FindRouteCompleteHandler = NbiFindRouteComplete;
+ Device->BindInput.LineUpHandler = NbiLineUp;
+ Device->BindInput.LineDownHandler = NbiLineDown;
+ Device->BindInput.ScheduleRouteHandler = NULL;
+#if defined(_PNP_POWER)
+ Device->BindInput.PnPHandler = NbiPnPNotification;
+#endif _PNP_POWER
+
+
+ Status = ZwDeviceIoControlFile(
+ Device->BindHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPX_INTERNAL_BIND, // IoControlCode
+ &Device->BindInput, // Input Buffer
+ sizeof(Device->BindInput), // Input Buffer Length
+ &Device->Bind, // OutputBuffer
+ sizeof(Device->Bind)); // OutputBufferLength
+
+ //
+ // We open synchronous, so this shouldn't happen.
+ //
+
+ CTEAssert (Status != STATUS_PENDING);
+
+ //
+ // Save the bind data.
+ //
+
+ if (Status == STATUS_SUCCESS) {
+
+ NB_DEBUG2 (BIND, ("Successfully bound to IPX (%ws)\n",
+ Config->BindName.Buffer));
+// RtlCopyMemory (&Device->Bind, &Bind.Output, sizeof(IPX_INTERNAL_BIND_OUTPUT));
+
+#if !defined(_PNP_POWER)
+ RtlZeroMemory (Device->ReservedNetbiosName, 16);
+ RtlCopyMemory (&Device->ReservedNetbiosName[10], Device->Bind.Node, 6);
+
+ Status = (*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_MAXIMUM_NIC_ID,
+ (USHORT)0,
+ &Device->MaximumNicId,
+ sizeof(Device->MaximumNicId),
+ NULL);
+ CTEAssert (Status == STATUS_SUCCESS);
+#endif !_PNP_POWER
+
+ } else {
+
+ NB_DEBUG (BIND, ("Could not bind to IPX (%ws) %lx\n",
+ Config->BindName.Buffer, Status));
+ NbiWriteGeneralErrorLog(
+ Device,
+ EVENT_TRANSPORT_BINDING_FAILED,
+ 1,
+ Status,
+ Config->BindName.Buffer,
+ 0,
+ NULL);
+ ZwClose(Device->BindHandle);
+ }
+
+ return Status;
+
+} /* NbiBind */
+
+
+VOID
+NbiUnbind(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This function closes the binding between the Netbios over
+ IPX module and the IPX module previously established by
+ NbiBind.
+
+Arguments:
+
+ Device - The netbios device object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ZwClose (Device->BindHandle);
+
+} /* NbiUnbind */
+
+
+VOID
+NbiStatus(
+ IN USHORT NicId,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This function receives a status indication from IPX,
+ corresponding to a status indication from an underlying
+ NDIS driver.
+
+Arguments:
+
+ NicId - The NIC ID of the underlying adapter.
+
+ GeneralStatus - The general status code.
+
+ StatusBuffer - The status buffer.
+
+ StatusBufferLength - The length of the status buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+} /* NbiStatus */
+
+
+VOID
+NbiLineUp(
+ IN USHORT NicId,
+ IN PIPX_LINE_INFO LineInfo,
+ IN NDIS_MEDIUM DeviceType,
+ IN PVOID ConfigurationData
+ )
+
+
+/*++
+
+Routine Description:
+
+ This function receives line up indications from IPX,
+ indicating that the specified adapter is now up with
+ the characteristics shown.
+
+Arguments:
+
+ NicId - The NIC ID of the underlying adapter.
+
+ LineInfo - Information about the adapter's medium.
+
+ DeviceType - The type of the adapter.
+
+ ConfigurationData - IPX-specific configuration data.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPXCP_CONFIGURATION Configuration = (PIPXCP_CONFIGURATION)ConfigurationData;
+
+ //
+ // Update queries have NULL as the ConfigurationData. These
+ // only indicate changes in LineInfo. BUGBUG Ignore these
+ // for the moment.
+ //
+
+ if (Configuration == NULL) {
+ return;
+ }
+
+#if !defined(_PNP_POWER)
+ //
+ // Since Netbios outgoing queries only go out on network 1,
+ // we ignore this (BUGBUG for the moment) unless that is
+ // the NIC it is on.
+ //
+
+ if (NicId == 1) {
+
+ RtlCopyMemory(NbiDevice->ConnectionlessHeader.SourceNetwork, Configuration->Network, 4);
+ RtlCopyMemory(NbiDevice->ConnectionlessHeader.SourceNode, Configuration->LocalNode, 6);
+
+ }
+#endif !_PNP_POWER
+} /* NbiLineUp */
+
+
+VOID
+NbiLineDown(
+ IN USHORT NicId
+ )
+
+
+/*++
+
+Routine Description:
+
+ This function receives line down indications from IPX,
+ indicating that the specified adapter is no longer
+ up.
+
+Arguments:
+
+ NicId - The NIC ID of the underlying adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+} /* NbiLineDown */
+
+#if defined(_PNP_POWER)
+
+VOID
+NbiPnPNotification(
+ IN IPX_PNP_OPCODE OpCode,
+ IN PVOID PnPData
+ )
+
+/*++
+
+Routine Description:
+
+ This function receives the notification about PnP events from IPX.
+
+Arguments:
+
+ OpCode - Type of the PnP event
+
+ PnPData - Data associated with this event.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PDEVICE Device = NbiDevice;
+ USHORT MaximumNicId = 0;
+ CTELockHandle LockHandle;
+ UCHAR PrevReservedName[NB_NETBIOS_NAME_SIZE];
+ UNICODE_STRING UnicodeDeviceName;
+
+
+ NB_DEBUG2( DEVICE, ("Received a pnp notification, opcode %d\n",OpCode ));
+
+ switch( OpCode ) {
+ case IPX_PNP_ADD_DEVICE : {
+ IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
+ BOOLEAN ReallocReceiveBuffers = FALSE;
+
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+
+ if ( PnPInfo->NewReservedAddress ) {
+
+ *(UNALIGNED ULONG *)Device->Bind.Network = PnPInfo->NetworkAddress;
+ RtlCopyMemory( Device->Bind.Node, PnPInfo->NodeAddress, 6);
+
+// RtlZeroMemory(Device->ReservedNetbiosName, NB_NETBIOS_NAME_SIZE);
+// RtlCopyMemory(&Device->ReservedNetbiosName[10], Device->Bind.Node, 6);
+
+ *(UNALIGNED ULONG *)Device->ConnectionlessHeader.SourceNetwork = *(UNALIGNED ULONG *)Device->Bind.Network;
+ RtlCopyMemory(Device->ConnectionlessHeader.SourceNode, Device->Bind.Node, 6);
+ }
+
+ if ( PnPInfo->FirstORLastDevice ) {
+ CTEAssert( PnPInfo->NewReservedAddress );
+ CTEAssert( Device->State != DEVICE_STATE_OPEN );
+
+
+ //
+ // we must do this while we still have the device lock.
+ //
+ if ( !Device->LongTimerRunning ) {
+ Device->LongTimerRunning = TRUE;
+ NbiReferenceDevice (Device, DREF_LONG_TIMER);
+
+ CTEStartTimer(
+ &Device->LongTimer,
+ LONG_TIMER_DELTA,
+ NbiLongTimeout,
+ (PVOID)Device);
+
+ }
+
+ Device->State = DEVICE_STATE_OPEN;
+
+ CTEAssert( !Device->MaximumNicId );
+
+ Device->Bind.LineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
+ Device->Bind.LineInfo.MaximumPacketSize = PnPInfo->LineInfo.MaximumSendSize;
+ ReallocReceiveBuffers = TRUE;
+ } else {
+ if ( PnPInfo->LineInfo.MaximumPacketSize > Device->CurMaxReceiveBufferSize ) {
+ ReallocReceiveBuffers = TRUE;
+ }
+ //
+ // MaxSendSize could become smaller.
+ //
+ Device->Bind.LineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
+ }
+
+ Device->MaximumNicId++;
+
+
+ //
+ //
+ NbiCreateAdapterAddress( PnPInfo->NodeAddress );
+
+ //
+ // And finally remove all the failed cache entries since we might
+ // find those routes using this new adapter
+ //
+ FlushFailedNetbiosCacheEntries(Device->NameCache);
+
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+
+
+ if ( ReallocReceiveBuffers ) {
+ PWORK_QUEUE_ITEM WorkItem;
+
+ WorkItem = NbiAllocateMemory( sizeof(WORK_QUEUE_ITEM), MEMORY_WORK_ITEM, "Alloc Rcv Buffer work item");
+
+ if ( WorkItem ) {
+ ExInitializeWorkItem( WorkItem, NbiReAllocateReceiveBufferPool, (PVOID) WorkItem );
+ ExQueueWorkItem( WorkItem, DelayedWorkQueue );
+ } else {
+ NB_DEBUG( DEVICE, ("Cannt schdule work item to realloc receive buffer pool\n"));
+ }
+ }
+ //
+ // Notify the TDI clients about the device creation
+ //
+ if ( PnPInfo->FirstORLastDevice ) {
+ UnicodeDeviceName.Buffer = Device->DeviceName;
+ UnicodeDeviceName.MaximumLength = Device->DeviceNameLength;
+ UnicodeDeviceName.Length = Device->DeviceNameLength - sizeof(WCHAR);
+
+ if ( !NT_SUCCESS( TdiRegisterDeviceObject(
+ &UnicodeDeviceName,
+ &Device->TdiRegistrationHandle ) )) {
+ NB_DEBUG( DEVICE, ("Failed to register nwlnknb with TDI\n"));
+ }
+ }
+
+ break;
+ }
+ case IPX_PNP_DELETE_DEVICE : {
+
+ IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
+
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE CacheName;
+ USHORT i,j,NetworksRemoved;
+
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+
+ CTEAssert( Device->MaximumNicId );
+ Device->MaximumNicId--;
+
+ if ( PnPInfo->FirstORLastDevice ) {
+ Device->State = DEVICE_STATE_LOADED;
+ Device->MaximumNicId = 0;
+
+ }
+
+
+ //
+ // MaximumSendSize could change if the card with the smallest send size just
+ // got removed. MaximumPacketSize could only become smaller and we ignore that
+ // since we dont need to(want to) realloc ReceiveBuffers.
+ //
+
+ Device->Bind.LineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
+
+ //
+ // Flush all the cache entries that are using this NicId in the local
+ // target.
+ //
+ RemoveInvalidRoutesFromNetbiosCacheTable( Device->NameCache, &PnPInfo->NicHandle );
+
+ NbiDestroyAdapterAddress( NULL, PnPInfo->NodeAddress );
+
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+
+/* //
+ // Now mark the previous reserved name in conflict if it has
+ // been registered by any of our client
+ //
+ if ( Address = NbiFindAddress( Device, PrevReservedName ) ) {
+ NB_GET_LOCK( &Address->Lock, &LockHandle );
+ Address->Flags |= ADDRESS_FLAGS_CONFLICT;
+ NB_FREE_LOCK( &Address->Lock, LockHandle );
+
+ NB_DEBUG( ADDRESS, ("Reserved Address %lx<%.16s> is marked CONFLICT\n",Address,Address->NetbiosAddress.NetbiosName));
+ //
+ // nbifindaddress added a reference, so deref
+ //
+ NbiDereferenceAddress( Address, AREF_FIND );
+ }
+*/
+
+ //
+ // inform tdi clients about the device deletion
+ //
+ if ( PnPInfo->FirstORLastDevice ) {
+ if ( !NT_SUCCESS( TdiDeregisterDeviceObject(
+ Device->TdiRegistrationHandle ) )) {
+ NB_DEBUG( DEVICE, ("Failed to Deregister nwlnknb with TDI\n"));
+ }
+ }
+
+ break;
+ }
+ case IPX_PNP_ADDRESS_CHANGE: {
+ IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
+ PADDRESS Address;
+ BOOLEAN ReservedNameClosing = FALSE;
+
+ CTEAssert( PnPInfo->NewReservedAddress );
+
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+ *(UNALIGNED ULONG *)Device->Bind.Network = PnPInfo->NetworkAddress;
+ RtlCopyMemory( Device->Bind.Node, PnPInfo->NodeAddress, 6);
+
+ *(UNALIGNED ULONG *)Device->ConnectionlessHeader.SourceNetwork = *(UNALIGNED ULONG *)Device->Bind.Network;
+ RtlCopyMemory(Device->ConnectionlessHeader.SourceNode, Device->Bind.Node, 6);
+
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+
+
+ break;
+ }
+ case IPX_PNP_TRANSLATE_DEVICE:
+ break;
+ case IPX_PNP_TRANSLATE_ADDRESS:
+ break;
+ default:
+ CTEAssert( FALSE );
+ }
+} /* NbiPnPNotification */
+
+#endif _PNP_POWER
diff --git a/private/ntos/tdi/isnp/nb/cache.c b/private/ntos/tdi/isnp/nb/cache.c
new file mode 100644
index 000000000..cbd27ad67
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/cache.c
@@ -0,0 +1,2746 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ cache.c
+
+Abstract:
+
+ This module contains the name cache routines for the Netbios
+ module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 20-December-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef RASAUTODIAL
+#include <acd.h>
+#include <acdapi.h>
+
+extern BOOLEAN fAcdLoadedG;
+extern ACD_DRIVER AcdDriverG;
+
+BOOLEAN
+NbiAttemptAutoDial(
+ IN PDEVICE pDevice,
+ IN PCONNECTION pConnection,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN PREQUEST pRequest
+ );
+
+VOID
+NbiRetryTdiConnect(
+ IN BOOLEAN fSuccess,
+ IN PVOID *pArgs
+ );
+#endif // RASAUTODIAL
+
+//
+// BUGBUG: We should change to monitor add name packets better,
+// so if we get an add for a different place we attempt to determine
+// if it is real or bogus and update if possible.
+//
+
+
+NTSTATUS
+CacheFindName(
+ IN PDEVICE Device,
+ IN FIND_NAME_TYPE Type,
+ IN PUCHAR RemoteName OPTIONAL,
+ OUT PNETBIOS_CACHE * CacheName
+)
+
+/*++
+
+Routine Description:
+
+ This routine looks up a particular remote name in the
+ Netbios name cache. If it cannot find it, a find name
+ request is queued up.
+
+ THIS REQUEST IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Type - Defines the type. The effect this has is:
+ FindNameConnect - On connects we will ignore an existing
+ cache entry if it got no response before.
+ FindNameNetbiosFindName - For these we ignore an existing
+ cache entry if it is for a group name -- this is
+ because the find name wants the address of every
+ machine, not just the network list.
+ FindNameOther - Normal handling is done.
+
+ RemoteName - The name to be discovered -- will be NULL if it
+ is the broadcast address.
+
+ CacheName - Returns the cache entry that was discovered.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY s;
+ PNETBIOS_CACHE FoundCacheName;
+ PNB_SEND_RESERVED Reserved;
+ PUCHAR RealRemoteName; // RemoteName or NetbiosBroadcastName
+
+ //
+ // First scan the netbios name cache to see if we know
+ // about this remote.
+ //
+
+ if (RemoteName) {
+ RealRemoteName = RemoteName;
+ } else {
+ RealRemoteName = NetbiosBroadcastName;
+ }
+
+ if ( FindInNetbiosCacheTable ( Device->NameCache,
+ RealRemoteName,
+ &FoundCacheName ) == STATUS_SUCCESS ) {
+
+ //
+ // If this is a netbios find name, we only can use unique
+ // names in the cache; for the group ones we need to requery
+ // because the cache only lists networks, not individual machines.
+ // For connect requests, if we find an empty cache entry we
+ // remove it and requery.
+ //
+
+ if ( FoundCacheName->Unique || (Type != FindNameNetbiosFindName) ) {
+
+ if (FoundCacheName->NetworksUsed > 0) {
+
+ *CacheName = FoundCacheName;
+ NB_DEBUG2 (CACHE, ("Found cache name <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
+ return STATUS_SUCCESS;
+
+ } else {
+
+ if (Type != FindNameConnect) {
+
+ if (FoundCacheName->FailedOnDownWan) {
+ NB_DEBUG2 (CACHE, ("Found cache name, but down wan <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ } else {
+ NB_DEBUG2 (CACHE, ("Found cache name, but no nets <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+ } else {
+
+ //
+ // This is a connect and the current cache entry
+ // has zero names; delete it.
+ //
+
+ RemoveFromNetbiosCacheTable ( Device->NameCache, FoundCacheName );
+ CTEAssert (FoundCacheName->ReferenceCount == 1);
+ if (--FoundCacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free unneeded empty cache entry %lx\n", FoundCacheName));
+ NbiFreeMemory(
+ FoundCacheName,
+ sizeof(NETBIOS_CACHE) + ((FoundCacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free due to replacement");
+ }
+
+ }
+ }
+ }
+ }
+
+
+ //
+ // There was no suitable cache entry for this network, first see
+ // if there is one pending.
+ //
+
+ for (p = Device->WaitingFindNames.Flink;
+ p != &Device->WaitingFindNames;
+ p = p->Flink) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ //
+ // For this purpose we ignore a packet if a route
+ // has been found and it was for a unique name. This
+ // is because the cache information has already been
+ // inserted for this name. Otherwise if the name has
+ // since been deleted from the cache, the request
+ // that is looking for this name will starve because
+ // FindNameTimeout will just destroy the packet.
+ //
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+ continue;
+ }
+
+ if (RtlEqualMemory(
+ Reserved->u.SR_FN.NetbiosName,
+ RealRemoteName, 16)) {
+
+ NB_DEBUG2 (CACHE, ("Cache name already pending <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
+
+ //
+ // There is already one pending. If it is for a group
+ // name and this is a netbios find name, we make sure
+ // the retry count is such that at least one more
+ // query will be sent, so the netbios find name
+ // buffer can be filled with the responses from this.
+ //
+
+ if ((Type == FindNameNetbiosFindName) &&
+ (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseGroup) &&
+ (Reserved->u.SR_FN.RetryCount == Device->BroadcastCount)) {
+
+ --Reserved->u.SR_FN.RetryCount;
+ }
+
+ return STATUS_PENDING;
+ }
+ }
+
+ s = NbiPopSendPacket(Device, TRUE);
+
+ if (s == NULL) {
+ NB_DEBUG (CACHE, ("Couldn't get packet to find <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+
+ //
+ // We have the packet, fill it in for this request.
+ //
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = FALSE;
+ Reserved->Type = SEND_TYPE_FIND_NAME;
+ RtlCopyMemory (Reserved->u.SR_FN.NetbiosName, RealRemoteName, 16);
+ Reserved->u.SR_FN.StatusAndSentOnUpLine = FNStatusNoResponse; // SentOnUpLine is FALSE
+ Reserved->u.SR_FN.RetryCount = 0;
+ Reserved->u.SR_FN.NewCache = NULL;
+ Reserved->u.SR_FN.SendTime = Device->FindNameTime;
+#if !defined(_PNP_POWER)
+ Reserved->u.SR_FN.CurrentNicId = 1;
+
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_MAX_TYPE_20_NIC_ID,
+ (USHORT)0,
+ &Reserved->u.SR_FN.MaximumNicId,
+ sizeof(USHORT),
+ NULL);
+
+ if (Reserved->u.SR_FN.MaximumNicId == 0) {
+ Reserved->u.SR_FN.MaximumNicId = 1; // code assumes at least one
+ }
+#endif !_PNP_POWER
+ NB_DEBUG2 (CACHE, ("Queued FIND_NAME %lx for <%.16s>\n",
+ Reserved, RemoteName ? RemoteName : "<broadcast>"));
+
+
+ InsertHeadList(
+ &Device->WaitingFindNames,
+ &Reserved->WaitLinkage);
+
+ ++Device->FindNamePacketCount;
+
+ if (!Device->FindNameTimerActive) {
+
+ Device->FindNameTimerActive = TRUE;
+ NbiReferenceDevice (Device, DREF_FN_TIMER);
+
+ CTEStartTimer(
+ &Device->FindNameTimer,
+ 1, // 1 ms, i.e. expire immediately
+ FindNameTimeout,
+ (PVOID)Device);
+ }
+
+ NbiReferenceDevice (Device, DREF_FIND_NAME);
+
+ return STATUS_PENDING;
+
+} /* CacheFindName */
+
+
+VOID
+FindNameTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the find name timer expires.
+ It is called every FIND_NAME_GRANULARITY milliseconds unless there
+ is nothing to do.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the device pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)Context;
+ PLIST_ENTRY p, q;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ PNETBIOS_CACHE FoundCacheName;
+ NDIS_STATUS NdisStatus;
+#if !defined(_PNP_POWER)
+ static IPX_LOCAL_TARGET BroadcastTarget = { 0, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
+#endif !_PNP_POWER
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ ++Device->FindNameTime;
+
+ if (Device->FindNamePacketCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("FindNameTimeout exiting\n"));
+
+ Device->FindNameTimerActive = FALSE;
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ NbiDereferenceDevice (Device, DREF_FN_TIMER);
+
+ return;
+ }
+
+ //
+ // Check what is on the queue; this is set up as a
+ // loop but in fact it rarely does (under no
+ // circumstances can we send more than one packet
+ // each time this function executes).
+ //
+#if defined(_PNP_POWER)
+ while (TRUE) {
+
+ p = Device->WaitingFindNames.Flink;
+ if (p == &Device->WaitingFindNames) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ if (Reserved->SendInProgress) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+
+ //
+ // This was a find name for a unique name which got a
+ // response but was not freed at the time (because
+ // SendInProgress was still TRUE) so we free it now.
+ //
+
+ (VOID)RemoveHeadList (&Device->WaitingFindNames);
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+ --Device->FindNamePacketCount;
+
+ //
+ // It is OK to do this with the lock held because
+ // it won't be the last one (we have the RIP_TIMER ref).
+ //
+
+ NbiDereferenceDevice (Device, DREF_FIND_NAME);
+ continue;
+ }
+
+ if (((SHORT)(Device->FindNameTime - Reserved->u.SR_FN.SendTime)) < 0) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ (VOID)RemoveHeadList (&Device->WaitingFindNames);
+
+
+ //
+ // Increment the counter and see if we have sent
+ // all the frames we need to (we will age out
+ // here if we got no response for a unique query,
+ // or if we are doing a global name or broadcast
+ // search). We also kill the query right now if
+ // we have not found anything but down wan lines
+ // to send it on.
+ //
+
+ if ((++Reserved->u.SR_FN.RetryCount > Device->BroadcastCount) ||
+ ((Reserved->u.SR_FN.RetryCount > 1) && (!NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved)))) {
+
+#if DBG
+ if (Reserved->u.SR_FN.RetryCount > Device->BroadcastCount) {
+ NB_DEBUG2 (CACHE, ("FindNameTimeout aging out %lx\n", Reserved));
+ } else {
+ NB_DEBUG2 (CACHE, ("FindNameTimeout no active nets %lx\n", Reserved));
+ }
+#endif
+
+ //
+ // This packet is stale, clean it up and continue.
+ //
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseGroup) {
+
+ CTEAssert (Reserved->u.SR_FN.NewCache != NULL);
+
+ //
+ // If this was a group name and we have a new
+ // cache entry that we have been building for it,
+ // then insert that in the queue and use it
+ // to succeed any pending connects. Because
+ // netbios find name requests can cause cache
+ // requests for group names to be queued even
+ // if we already have on in the database, we
+ // first scan for old ones and remove them.
+ //
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ Reserved->u.SR_FN.NetbiosName,
+ &FoundCacheName ) == STATUS_SUCCESS ) {
+
+ NB_DEBUG2 (CACHE, ("Found old group cache name <%.16s>\n", FoundCacheName->NetbiosName));
+
+ RemoveFromNetbiosCacheTable ( Device->NameCache, FoundCacheName );
+
+ if (--FoundCacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free replaced cache entry %lx\n", FoundCacheName));
+ NbiFreeMemory(
+ FoundCacheName,
+ sizeof(NETBIOS_CACHE) + ((FoundCacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free due to replacement");
+
+ }
+
+ }
+
+ Reserved->u.SR_FN.NewCache->TimeStamp = Device->CacheTimeStamp;
+
+ InsertInNetbiosCacheTable(
+ Device->NameCache,
+ Reserved->u.SR_FN.NewCache);
+
+ //
+ // Reference it for the moment since CacheHandlePending
+ // uses it after releasing the lock. CacheHandlePending
+ // will dereference it.
+ //
+
+ ++Reserved->u.SR_FN.NewCache->ReferenceCount;
+
+ //
+ // This call releases the locks
+ //
+
+ CacheHandlePending(
+ Device,
+ Reserved->u.SR_FN.NetbiosName,
+ NetbiosNameFound,
+ Reserved->u.SR_FN.NewCache
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ CTEAssert (Reserved->u.SR_FN.NewCache == NULL);
+
+ //
+ // Allocate an empty cache entry to record the
+ // fact that we could not find this name, unless
+ // there is already an entry for this name.
+ //
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ Reserved->u.SR_FN.NetbiosName,
+ &FoundCacheName ) == STATUS_SUCCESS ) {
+
+
+ NB_DEBUG2 (CACHE, ("Don't replace old group cache name with empty <%.16s>\n", FoundCacheName->NetbiosName));
+ } else {
+
+ PNETBIOS_CACHE EmptyCache;
+
+ //
+ // Nothing found.
+ //
+
+ EmptyCache = NbiAllocateMemory (sizeof(NETBIOS_CACHE), MEMORY_CACHE, "Cache Entry");
+ if (EmptyCache != NULL) {
+
+ RtlZeroMemory (EmptyCache, sizeof(NETBIOS_CACHE));
+
+ NB_DEBUG2 (CACHE, ("Allocate new empty cache %lx for <%.16s>\n",
+ EmptyCache, Reserved->u.SR_FN.NetbiosName));
+
+ RtlCopyMemory (EmptyCache->NetbiosName, Reserved->u.SR_FN.NetbiosName, 16);
+ EmptyCache->Unique = TRUE; // so we'll delete it if we see an add name
+ EmptyCache->ReferenceCount = 1;
+ EmptyCache->NetworksAllocated = 1;
+ EmptyCache->TimeStamp = Device->CacheTimeStamp;
+ EmptyCache->NetworksUsed = 0;
+ EmptyCache->FailedOnDownWan = (BOOLEAN)
+ !NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved);
+
+ InsertInNetbiosCacheTable (
+ Device->NameCache,
+ EmptyCache);
+ }
+ }
+
+ //
+ // Fail all datagrams, etc. that were waiting for
+ // this route. This call releases the lock.
+ //
+
+ CacheHandlePending(
+ Device,
+ Reserved->u.SR_FN.NetbiosName,
+ NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved) ?
+ NetbiosNameNotFoundNormal :
+ NetbiosNameNotFoundWanDown,
+ NULL
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ --Device->FindNamePacketCount;
+ NbiDereferenceDevice (Device, DREF_FIND_NAME);
+ continue;
+ }
+
+
+
+
+ //
+ // Send the packet out again. We first set the time so
+ // it won't be sent again until the appropriate timeout.
+ //
+
+ Reserved->u.SR_FN.SendTime = (USHORT)(Device->FindNameTime + Device->FindNameTimeout);
+
+ InsertTailList (&Device->WaitingFindNames, &Reserved->WaitLinkage);
+
+ CTEAssert (Reserved->Identifier == IDENTIFIER_NB);
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // If this is the first retry, we need to initialize the packet
+ //
+ if ( Reserved->u.SR_FN.RetryCount == 1 ) {
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address, which is
+ // what we want.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)(&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
+
+ Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
+ Header->NameFrame.ConnectionControlFlag = 0x00;
+ Header->NameFrame.DataStreamType = NB_CMD_FIND_NAME;
+ Header->NameFrame.DataStreamType2 = NB_CMD_FIND_NAME;
+ Header->NameFrame.NameTypeFlag = 0x00;
+
+ RtlCopyMemory(
+ Header->NameFrame.Name,
+ Reserved->u.SR_FN.NetbiosName,
+ 16);
+
+
+ }
+ //
+ // Now submit the packet to IPX.
+ //
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ NB_DEBUG2 (CACHE, ("FindNameTimeout sending %lx\n", Reserved));
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) +
+ sizeof(NB_NAME_FRAME));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &BroadcastTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+
+ break;
+
+ }
+#else
+ while (TRUE) {
+
+ p = Device->WaitingFindNames.Flink;
+ if (p == &Device->WaitingFindNames) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ if (Reserved->SendInProgress) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+
+ //
+ // This was a find name for a unique name which got a
+ // response but was not freed at the time (because
+ // SendInProgress was still TRUE) so we free it now.
+ //
+
+ (VOID)RemoveHeadList (&Device->WaitingFindNames);
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+ --Device->FindNamePacketCount;
+
+ //
+ // It is OK to do this with the lock held because
+ // it won't be the last one (we have the RIP_TIMER ref).
+ //
+
+ NbiDereferenceDevice (Device, DREF_FIND_NAME);
+ continue;
+ }
+
+ if (((SHORT)(Device->FindNameTime - Reserved->u.SR_FN.SendTime)) < 0) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ (VOID)RemoveHeadList (&Device->WaitingFindNames);
+
+ //
+ // Save this now, then change it if needed.
+ //
+
+ BroadcastTarget.NicId = Reserved->u.SR_FN.CurrentNicId;
+
+ if (Reserved->u.SR_FN.CurrentNicId == 1) {
+
+ //
+ // Increment the counter and see if we have sent
+ // all the frames we need to (we will age out
+ // here if we got no response for a unique query,
+ // or if we are doing a global name or broadcast
+ // search). We also kill the query right now if
+ // we have not found anything but down wan lines
+ // to send it on.
+ //
+
+ if ((++Reserved->u.SR_FN.RetryCount > Device->BroadcastCount) ||
+ ((Reserved->u.SR_FN.RetryCount > 1) && (!NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved)))) {
+
+#if DBG
+ if (Reserved->u.SR_FN.RetryCount > Device->BroadcastCount) {
+ NB_DEBUG2 (CACHE, ("FindNameTimeout aging out %lx\n", Reserved));
+ } else {
+ NB_DEBUG2 (CACHE, ("FindNameTimeout no active nets %lx\n", Reserved));
+ }
+#endif
+
+ //
+ // This packet is stale, clean it up and continue.
+ //
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseGroup) {
+
+ CTEAssert (Reserved->u.SR_FN.NewCache != NULL);
+
+ //
+ // If this was a group name and we have a new
+ // cache entry that we have been building for it,
+ // then insert that in the queue and use it
+ // to succeed any pending connects. Because
+ // netbios find name requests can cause cache
+ // requests for group names to be queued even
+ // if we already have on in the database, we
+ // first scan for old ones and remove them.
+ //
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ Reserved->u.SR_FN.NetbiosName,
+ &FoundCacheName ) == STATUS_SUCCESS ) {
+
+ NB_DEBUG2 (CACHE, ("Found old group cache name <%.16s>\n", FoundCacheName->NetbiosName));
+
+ RemoveFromNetbiosCacheTable ( Device->NameCache, FoundCacheName );
+
+ if (--FoundCacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free replaced cache entry %lx\n", FoundCacheName));
+ NbiFreeMemory(
+ FoundCacheName,
+ sizeof(NETBIOS_CACHE) + ((FoundCacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free due to replacement");
+
+ }
+ }
+
+ Reserved->u.SR_FN.NewCache->TimeStamp = Device->CacheTimeStamp;
+
+ InsertInNetbiosCacheTable(
+ Device->NameCache,
+ Reserved->u.SR_FN.NewCache);
+
+ //
+ // Reference it for the moment since CacheHandlePending
+ // uses it after releasing the lock. CacheHandlePending
+ // will dereference it.
+ //
+
+ ++Reserved->u.SR_FN.NewCache->ReferenceCount;
+
+ //
+ // This call releases the locks
+ //
+
+ CacheHandlePending(
+ Device,
+ Reserved->u.SR_FN.NetbiosName,
+ NetbiosNameFound,
+ Reserved->u.SR_FN.NewCache
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ CTEAssert (Reserved->u.SR_FN.NewCache == NULL);
+
+ //
+ // Allocate an empty cache entry to record the
+ // fact that we could not find this name, unless
+ // there is already an entry for this name.
+ //
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ Reserved->u.SR_FN.NetbiosName,
+ &FoundCacheName ) == STATUS_SUCCESS ) {
+
+
+ NB_DEBUG2 (CACHE, ("Don't replace old group cache name with empty <%.16s>\n", FoundCacheName->NetbiosName));
+
+ } else {
+
+ PNETBIOS_CACHE EmptyCache;
+
+ //
+ // Nothing found.
+ //
+
+ EmptyCache = NbiAllocateMemory (sizeof(NETBIOS_CACHE), MEMORY_CACHE, "Cache Entry");
+ if (EmptyCache != NULL) {
+
+ RtlZeroMemory (EmptyCache, sizeof(NETBIOS_CACHE));
+
+ NB_DEBUG2 (CACHE, ("Allocate new empty cache %lx for <%.16s>\n",
+ EmptyCache, Reserved->u.SR_FN.NetbiosName));
+
+ RtlCopyMemory (EmptyCache->NetbiosName, Reserved->u.SR_FN.NetbiosName, 16);
+ EmptyCache->Unique = TRUE; // so we'll delete it if we see an add name
+ EmptyCache->ReferenceCount = 1;
+ EmptyCache->NetworksAllocated = 1;
+ EmptyCache->TimeStamp = Device->CacheTimeStamp;
+ EmptyCache->NetworksUsed = 0;
+ EmptyCache->FailedOnDownWan = (BOOLEAN)
+ !NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved);
+
+ InsertInNetbiosCacheTable (
+ Device->NameCache,
+ EmptyCache);
+ }
+ }
+
+ //
+ // Fail all datagrams, etc. that were waiting for
+ // this route. This call releases the lock.
+ //
+
+ CacheHandlePending(
+ Device,
+ Reserved->u.SR_FN.NetbiosName,
+ NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved) ?
+ NetbiosNameNotFoundNormal :
+ NetbiosNameNotFoundWanDown,
+ NULL
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+ --Device->FindNamePacketCount;
+ NbiDereferenceDevice (Device, DREF_FIND_NAME);
+ continue;
+ }
+
+ }
+
+
+ //
+ // Increment the current NIC ID for next time.
+ //
+
+ if (Reserved->u.SR_FN.CurrentNicId >= Reserved->u.SR_FN.MaximumNicId) {
+ Reserved->u.SR_FN.CurrentNicId = 1;
+ } else {
+ ++Reserved->u.SR_FN.CurrentNicId;
+ }
+
+
+ //
+ // Send the packet out again. We first set the time so
+ // it won't be sent again until the appropriate timeout.
+ // If we are going to wrap around the maximum NIC ID
+ // after sending this packet we wait the full configured
+ // amount, otherwise we wait almost the minimum (but still
+ // insert ourselves at the back of the queue to be fair).
+ //
+
+ if (Reserved->u.SR_FN.CurrentNicId == 1) {
+ Reserved->u.SR_FN.SendTime = (USHORT)(Device->FindNameTime + Device->FindNameTimeout);
+ } else {
+ Reserved->u.SR_FN.SendTime = (USHORT)(Device->FindNameTime + 2);
+ }
+ InsertTailList (&Device->WaitingFindNames, &Reserved->WaitLinkage);
+
+ CTEAssert (Reserved->Identifier == IDENTIFIER_NB);
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address, which is
+ // what we want.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)(&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
+
+ Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
+ Header->NameFrame.ConnectionControlFlag = 0x00;
+ Header->NameFrame.DataStreamType = NB_CMD_FIND_NAME;
+ Header->NameFrame.DataStreamType2 = NB_CMD_FIND_NAME;
+ Header->NameFrame.NameTypeFlag = 0x00;
+
+ RtlCopyMemory(
+ Header->NameFrame.Name,
+ Reserved->u.SR_FN.NetbiosName,
+ 16);
+
+ //
+ // Now submit the packet to IPX.
+ //
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ NB_DEBUG2 (CACHE, ("FindNameTimeout sending %lx to %d\n", Reserved, BroadcastTarget.NicId));
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) +
+ sizeof(NB_NAME_FRAME));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &BroadcastTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+ if (NdisStatus == STATUS_DEVICE_DOES_NOT_EXIST) {
+
+ //
+ // This send was done on a down wan line. To avoid
+ // extensive delays sending find names on systems
+ // with a lot of wan lines, we loop around immediately
+ // and do the next send. We put this packet back on
+ // the head of the list and change its SendTime so
+ // it will be resent immediately.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ NB_DEBUG2 (CACHE, ("FindNameTimeout resending %lx, wan send failed\n", Reserved));
+
+ RemoveEntryList (&Reserved->WaitLinkage);
+ InsertHeadList (&Device->WaitingFindNames, &Reserved->WaitLinkage);
+ Reserved->u.SR_FN.SendTime = Device->FindNameTime;
+
+ continue;
+
+ } else {
+
+ //
+ // We keep track of when it finds a net that isn't
+ // a down wan line so that we can tell when datagram
+ // sends should fail (otherwise we succeed them, so
+ // the browser won't think this is a down wan line).
+ //
+
+ NB_SET_SR_FN_SENT_ON_UP_LINE (Reserved, TRUE);
+ }
+
+
+ break;
+
+ }
+#endif _PNP_POWER
+
+ //
+ // Since we did something this time, we restart the timer.
+ //
+
+ CTEStartTimer(
+ &Device->FindNameTimer,
+ FIND_NAME_GRANULARITY,
+ FindNameTimeout,
+ (PVOID)Device);
+
+} /* FindNameTimeout */
+
+
+VOID
+CacheHandlePending(
+ IN PDEVICE Device,
+ IN PUCHAR RemoteName,
+ IN NETBIOS_NAME_RESULT Result,
+ IN PNETBIOS_CACHE CacheName OPTIONAL
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine cleans up pending datagrams and connects
+ that were waiting for a route to be discovered to a
+ given Netbios NAME. THIS ROUTINE IS CALLED WITH
+ DEVICE->LOCK ACQUIRED AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Device - The device.
+
+ RemoteName - The netbios name that was being searched for.
+
+ Result - Indicates if the name was found, or not found due
+ to no response or wan lines being down.
+
+ CacheName - If Result is NetbiosNameFound, the cache entry for this name.
+ This entry has been referenced and this routine will deref it.
+
+ LockHandle - The handle used to acquire the lock.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ LIST_ENTRY DatagramList;
+ LIST_ENTRY ConnectList;
+ LIST_ENTRY AdapterStatusList;
+ LIST_ENTRY NetbiosFindNameList;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ PLIST_ENTRY p;
+ PREQUEST ConnectRequest, DatagramRequest, AdapterStatusRequest, NetbiosFindNameRequest;
+ PCONNECTION Connection;
+ PADDRESS_FILE AddressFile;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteAddress;
+ CTELockHandle CancelLH;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+
+
+ InitializeListHead (&DatagramList);
+ InitializeListHead (&ConnectList);
+ InitializeListHead (&AdapterStatusList);
+ InitializeListHead (&NetbiosFindNameList);
+
+ //
+ // Put all connect requests on ConnectList. They will
+ // be continued or failed later.
+ //
+
+ p = Device->WaitingConnects.Flink;
+
+ while (p != &Device->WaitingConnects) {
+
+ ConnectRequest = LIST_ENTRY_TO_REQUEST(p);
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(ConnectRequest);
+ p = p->Flink;
+
+ if (RtlEqualMemory (Connection->RemoteName, RemoteName, 16)) {
+
+ RemoveEntryList (REQUEST_LINKAGE(ConnectRequest));
+ InsertTailList (&ConnectList, REQUEST_LINKAGE(ConnectRequest));
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_W_ACK;
+ }
+
+ }
+
+
+ //
+ // Put all the datagrams on Datagram list. They will be
+ // sent or failed later.
+ //
+
+ p = Device->WaitingDatagrams.Flink;
+
+ while (p != &Device->WaitingDatagrams) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ p = p->Flink;
+
+ //
+ // Check differently based on whether we were looking for
+ // the broadcast address or not.
+ //
+
+ if (Reserved->u.SR_DG.RemoteName == (PVOID)-1) {
+ if (!RtlEqualMemory (RemoteName, NetbiosBroadcastName, 16)) {
+ continue;
+ }
+ } else {
+
+ if (!RtlEqualMemory (RemoteName, Reserved->u.SR_DG.RemoteName->NetbiosName, 16)) {
+ continue;
+ }
+ }
+
+ RemoveEntryList (&Reserved->WaitLinkage);
+ InsertTailList (&DatagramList, &Reserved->WaitLinkage);
+
+ //
+ // Reference this here with the lock held.
+ //
+
+ if (Result == NetbiosNameFound) {
+ ++CacheName->ReferenceCount;
+ }
+
+ }
+
+
+ //
+ // Put all the adapter status requests on AdapterStatus
+ // list. They will be sent or failed later.
+ //
+
+ p = Device->WaitingAdapterStatus.Flink;
+
+ while (p != &Device->WaitingAdapterStatus) {
+
+ AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ p = p->Flink;
+
+ RemoteAddress = (TDI_ADDRESS_NETBIOS UNALIGNED *)REQUEST_INFORMATION(AdapterStatusRequest);
+
+ if (!RtlEqualMemory(
+ RemoteName,
+ RemoteAddress->NetbiosName,
+ 16)) {
+ continue;
+ }
+
+ RemoveEntryList (REQUEST_LINKAGE(AdapterStatusRequest));
+ InsertTailList (&AdapterStatusList, REQUEST_LINKAGE(AdapterStatusRequest));
+
+ //
+ // Reference this here with the lock held.
+ //
+
+ if (Result == NetbiosNameFound) {
+ ++CacheName->ReferenceCount;
+ }
+
+ }
+
+
+ //
+ // Put all the netbios find name requests on NetbiosFindName
+ // list. They will be completed later.
+ //
+
+ p = Device->WaitingNetbiosFindName.Flink;
+
+ while (p != &Device->WaitingNetbiosFindName) {
+
+ NetbiosFindNameRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ p = p->Flink;
+
+ RemoteAddress = (TDI_ADDRESS_NETBIOS UNALIGNED *)REQUEST_INFORMATION(NetbiosFindNameRequest);
+
+ if (!RtlEqualMemory(
+ RemoteName,
+ RemoteAddress->NetbiosName,
+ 16)) {
+ continue;
+ }
+
+ RemoveEntryList (REQUEST_LINKAGE(NetbiosFindNameRequest));
+ InsertTailList (&NetbiosFindNameList, REQUEST_LINKAGE(NetbiosFindNameRequest));
+
+ }
+
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+
+ //
+ // Now that the lock is free, process all the packets on
+ // the various lists.
+ //
+
+ for (p = ConnectList.Flink; p != &ConnectList; ) {
+
+ ConnectRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(ConnectRequest);
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN)) {
+
+ if (Result == NetbiosNameFound) {
+
+ NB_DEBUG2 (CONNECTION, ("Found queued connect %lx on %lx\n", ConnectRequest, Connection));
+
+ //
+ // Continue with the connection sequence.
+ //
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_W_ROUTE;
+
+
+ if (!ConnectRequest->Cancel) {
+
+ IoSetCancelRoutine (ConnectRequest, NbiCancelConnectWaitResponse);
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle1 );
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ Connection->LocalTarget = CacheName->Networks[0].LocalTarget;
+ RtlCopyMemory(&Connection->RemoteHeader.DestinationNetwork, &CacheName->FirstResponse, 12);
+ NbiReferenceConnectionSync (Connection, CREF_FIND_ROUTE);
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network = CacheName->FirstResponse.NetworkAddress;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,CacheName->FirstResponse.NodeAddress,6);
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_RIP_IF_NEEDED;
+
+ //
+ // When this completes, we will send the session init.
+ // We don't call it if the client is for network 0,
+ // instead just fake as if no route could be found
+ // and we will use the local target we got here.
+ //
+
+ if (CacheName->FirstResponse.NetworkAddress != 0) {
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ } else {
+
+ NbiFindRouteComplete(
+ &Connection->FindRouteRequest,
+ FALSE);
+
+ }
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelling connect %lx on %lx\n", ConnectRequest, Connection));
+
+ goto AbortConnect;
+
+ //
+ // Jumps down into the else below.
+ //
+
+ }
+
+ } else {
+ BOOLEAN bAutodialAttempt = FALSE;
+
+ NB_DEBUG2 (CONNECTION, ("Timing out connect %lx on %lx\n", ConnectRequest, Connection));
+AbortConnect:
+
+ ASSERT (Connection->ConnectRequest == ConnectRequest);
+
+#ifdef RASAUTODIAL
+ if (fAcdLoadedG) {
+ CTELockHandle adirql;
+ BOOLEAN fEnabled;
+
+ //
+ // See if the automatic connection driver knows
+ // about this address before we search the
+ // network. If it does, we return STATUS_PENDING,
+ // and we will come back here via NbfRetryTdiConnect().
+ //
+ CTEGetLock(&AcdDriverG.SpinLock, &adirql);
+ fEnabled = AcdDriverG.fEnabled;
+ CTEFreeLock(&AcdDriverG.SpinLock, adirql);
+ if (fEnabled && NbiAttemptAutoDial(
+ Device,
+ Connection,
+ 0,
+ NbiRetryTdiConnect,
+ ConnectRequest))
+ {
+ NB_SYNC_FREE_LOCK(&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK(CancelLH);
+
+ bAutodialAttempt = TRUE;
+ }
+ }
+#endif // RASAUTODIAL
+
+ if (!bAutodialAttempt) {
+ Connection->ConnectRequest = NULL;
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ IoSetCancelRoutine( ConnectRequest, (PDRIVER_CANCEL)NULL );
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ REQUEST_STATUS(ConnectRequest) = STATUS_BAD_NETWORK_PATH;
+
+ NbiCompleteRequest(ConnectRequest);
+ NbiFreeRequest (Device, ConnectRequest);
+ }
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ }
+
+ } else {
+
+ // BUGBUG What happens to the IRP? Who completes it?
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_WAIT_CACHE);
+
+ }
+
+
+ for (p = DatagramList.Flink; p != &DatagramList; ) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+ p = p->Flink;
+
+ if (Result == NetbiosNameFound) {
+
+ NB_DEBUG2 (DATAGRAM, ("Found queued datagram %lx on %lx\n", Reserved->u.SR_DG.DatagramRequest, Reserved->u.SR_DG.AddressFile));
+
+ Reserved->u.SR_DG.Cache = CacheName;
+ Reserved->u.SR_DG.CurrentNetwork = 0;
+
+ //
+ // CacheName was referenced above.
+ //
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+ if ( REQUEST_NDIS_BUFFER( Reserved->u.SR_DG.DatagramRequest )) {
+ NdisChainBufferAtBack (Packet, REQUEST_NDIS_BUFFER(Reserved->u.SR_DG.DatagramRequest));
+ }
+
+ NbiTransmitDatagram (Reserved);
+
+ } else {
+
+ //
+ // BETABUGBUG: Should we send it once as a broadcast
+ // on net 0, just in case??
+ //
+
+ AddressFile = Reserved->u.SR_DG.AddressFile;
+ DatagramRequest = Reserved->u.SR_DG.DatagramRequest;
+
+ NB_DEBUG2 (DATAGRAM, ("Timing out datagram %lx on %lx\n", DatagramRequest, AddressFile));
+
+ //
+ // If the failure was due to a down wan line indicate
+ // that, otherwise return success (so the browser won't
+ // confuse this with a down wan line).
+ //
+
+ if (Result == NetbiosNameNotFoundWanDown) {
+ REQUEST_STATUS(DatagramRequest) = STATUS_DEVICE_DOES_NOT_EXIST;
+ REQUEST_INFORMATION(DatagramRequest) = 0;
+ } else {
+ REQUEST_STATUS(DatagramRequest) = STATUS_SUCCESS;
+ }
+
+ NbiCompleteRequest(DatagramRequest);
+ NbiFreeRequest (Device, DatagramRequest);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_SEND_DGRAM);
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+ }
+
+ }
+
+
+ for (p = AdapterStatusList.Flink; p != &AdapterStatusList; ) {
+
+ AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ if (Result == NetbiosNameFound) {
+
+ NB_DEBUG2 (QUERY, ("Found queued AdapterStatus %lx\n", AdapterStatusRequest));
+
+ //
+ // Continue with the AdapterStatus sequence. We put
+ // it in ActiveAdapterStatus, it will either get
+ // completed when a response is received or timed
+ // out by the long timeout.
+ //
+
+ REQUEST_STATUS(AdapterStatusRequest) = (NTSTATUS)CacheName;
+
+ //
+ // CacheName was referenced above.
+ //
+
+ REQUEST_INFORMATION (AdapterStatusRequest) = 0;
+
+ NB_INSERT_TAIL_LIST(
+ &Device->ActiveAdapterStatus,
+ REQUEST_LINKAGE (AdapterStatusRequest),
+ &Device->Lock);
+
+ NbiSendStatusQuery (AdapterStatusRequest);
+
+ } else {
+
+ NB_DEBUG2 (QUERY, ("Timing out AdapterStatus %lx\n", AdapterStatusRequest));
+
+ REQUEST_STATUS(AdapterStatusRequest) = STATUS_IO_TIMEOUT;
+
+ NbiCompleteRequest(AdapterStatusRequest);
+ NbiFreeRequest (Device, AdapterStatusRequest);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_QUERY);
+
+ }
+
+ }
+
+
+ for (p = NetbiosFindNameList.Flink; p != &NetbiosFindNameList; ) {
+
+ NetbiosFindNameRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ //
+ // In fact there is not much difference between success or
+ // failure, since in the successful case the information
+ // will already have been written to the buffer. Just
+ // complete the request with the appropriate status,
+ // which will already be stored in the request.
+ //
+
+ if (Result == NetbiosNameFound) {
+
+ if (CacheName->Unique) {
+
+ NB_DEBUG2 (QUERY, ("Found queued unique NetbiosFindName %lx\n", NetbiosFindNameRequest));
+
+ } else {
+
+ NB_DEBUG2 (QUERY, ("Found queued group NetbiosFindName %lx\n", NetbiosFindNameRequest));
+
+ }
+
+ } else {
+
+ CTEAssert (REQUEST_STATUS(NetbiosFindNameRequest) == STATUS_IO_TIMEOUT);
+ NB_DEBUG2 (QUERY, ("Timed out NetbiosFindName %lx\n", NetbiosFindNameRequest));
+
+ }
+
+ //
+ // This sets REQUEST_INFORMATION(Request) to the correct value.
+ //
+
+ NbiSetNetbiosFindNameInformation (NetbiosFindNameRequest);
+
+ NbiCompleteRequest(NetbiosFindNameRequest);
+ NbiFreeRequest (Device, NetbiosFindNameRequest);
+
+ NbiDereferenceDevice (Device, DREF_NB_FIND_NAME);
+
+ }
+
+
+ //
+ // We referenced this temporarily so we could use it in here,
+ // deref and check if we need to delete it.
+ //
+
+ if (Result == NetbiosNameFound) {
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle1);
+
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free newly allocated cache entry %lx\n", CacheName));
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free in CacheHandlePending");
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle1);
+
+ }
+
+} /* CacheHandlePending */
+
+
+VOID
+NbiProcessNameRecognized(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_NAME_RECOGNIZED frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PDEVICE Device = NbiDevice;
+ PNETBIOS_CACHE NameCache;
+ PREQUEST NetbiosFindNameRequest;
+ PNB_SEND_RESERVED Reserved;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteNetbiosAddress;
+ NB_CONNECTIONLESS UNALIGNED * Connectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
+ NB_DEFINE_LOCK_HANDLE(LockHandle)
+
+
+#if 0
+ //
+ // BETABUGBUG: We should handle responses from network 0
+ // differently -- if they are for a group name, we should
+ // keep them around but only until we get a non-zero
+ // response from the same card.
+ //
+
+ if (*(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork) == 0) {
+ return;
+ }
+#endif
+
+
+ //
+ // We need to scan our queue of pending find name packets
+ // to see if someone is waiting for this name.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (p = Device->WaitingFindNames.Flink;
+ p != &Device->WaitingFindNames;
+ p = p->Flink) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ //
+ // Find names which have already found unique names are
+ // "dead", waiting for FindNameTimeout to remove them,
+ // and should be ignored when scanning the list.
+ //
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+
+ continue;
+ }
+
+ if (RtlEqualMemory (Reserved->u.SR_FN.NetbiosName, Connectionless->NameFrame.Name, 16)) {
+ break;
+ }
+ }
+
+ if (p == &Device->WaitingFindNames) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+
+ //
+ // Scan for any netbios find name requests on the queue, and
+ // inform them about this remote. We need to do this on every
+ // response because group names need every computer recorded,
+ // but the normal cache only includes one entry per network.
+ //
+
+ for (p = Device->WaitingNetbiosFindName.Flink;
+ p != &Device->WaitingNetbiosFindName;
+ p = p->Flink) {
+
+ NetbiosFindNameRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ RemoteNetbiosAddress = (TDI_ADDRESS_NETBIOS UNALIGNED *)REQUEST_INFORMATION(NetbiosFindNameRequest);
+
+ if (!RtlEqualMemory(
+ Connectionless->NameFrame.Name,
+ RemoteNetbiosAddress->NetbiosName,
+ 16)) {
+ continue;
+ }
+
+ //
+ // This will update the request status if needed.
+ //
+
+ NbiUpdateNetbiosFindName(
+ NetbiosFindNameRequest,
+#if defined(_PNP_POWER)
+ &RemoteAddress->NicHandle,
+#else
+ RemoteAddress->NicId,
+#endif _PNP_POWER
+ (TDI_ADDRESS_IPX UNALIGNED *)Connectionless->IpxHeader.SourceNetwork,
+ (BOOLEAN)((Connectionless->NameFrame.NameTypeFlag & NB_NAME_GROUP) == 0));
+
+ }
+
+
+ //
+ // See what is up with this pending find name packet.
+ //
+
+ if (Reserved->u.SR_FN.NewCache == NULL) {
+
+ //
+ // This is the first response we have received, so we
+ // allocate the initial entry with room for a single
+ // entry.
+ //
+
+ NameCache = NbiAllocateMemory (sizeof(NETBIOS_CACHE), MEMORY_CACHE, "Cache Entry");
+ if (NameCache == NULL) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ NB_DEBUG2 (CACHE, ("Alloc new cache %lx for <%.16s>, net %lx\n",
+ NameCache, Reserved->u.SR_FN.NetbiosName,
+ *(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork)));
+
+ RtlCopyMemory (NameCache->NetbiosName, Connectionless->NameFrame.Name, 16);
+ NameCache->Unique = (BOOLEAN)((Connectionless->NameFrame.NameTypeFlag & NB_NAME_GROUP) == 0);
+ NameCache->ReferenceCount = 1;
+ RtlCopyMemory (&NameCache->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12);
+ NameCache->NetworksAllocated = 1;
+ NameCache->NetworksUsed = 1;
+ NameCache->Networks[0].Network = *(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork);
+
+ if (RtlEqualMemory (Connectionless->NameFrame.Name, NetbiosBroadcastName, 16)) {
+
+ NB_SET_SR_FN_STATUS (Reserved, FNStatusResponseGroup);
+ NameCache->Unique = FALSE;
+
+ } else {
+
+ NB_SET_SR_FN_STATUS(
+ Reserved,
+ NameCache->Unique ? FNStatusResponseUnique : FNStatusResponseGroup);
+
+ }
+
+ Reserved->u.SR_FN.NewCache = NameCache;
+
+ //
+ // If this packet was not routed to us and is for a group name,
+ // rather than use whatever local target it happened to come
+ // from we set it up so that it is broadcast on that net.
+ //
+
+ if ((RtlEqualMemory (RemoteAddress->MacAddress, Connectionless->IpxHeader.SourceNode, 6)) &&
+ (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseGroup)) {
+#if defined(_PNP_POWER)
+ NameCache->Networks[0].LocalTarget.NicHandle = RemoteAddress->NicHandle;
+#else
+ NameCache->Networks[0].LocalTarget.NicId = RemoteAddress->NicId;
+#endif _PNP_POWER
+ RtlCopyMemory (NameCache->Networks[0].LocalTarget.MacAddress, BroadcastAddress, 6);
+ RtlCopyMemory (NameCache->FirstResponse.NodeAddress, BroadcastAddress, 6);
+ } else {
+ NameCache->Networks[0].LocalTarget = *RemoteAddress;
+ }
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+
+ //
+ // Complete pending requests now, since it is a unique
+ // name we have all the information we will get.
+ //
+
+ NameCache->TimeStamp = Device->CacheTimeStamp;
+
+ InsertInNetbiosCacheTable(
+ Device->NameCache,
+ NameCache);
+
+ //
+ // Reference it since CacheHandlePending uses it
+ // with the lock released. CacheHandlePending
+ // will dereference it.
+ //
+
+ ++NameCache->ReferenceCount;
+
+ //
+ // This call releases the lock.
+ //
+
+ CacheHandlePending(
+ Device,
+ Reserved->u.SR_FN.NetbiosName,
+ NetbiosNameFound,
+ NameCache
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ //
+ // We already have a response to this frame.
+ //
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+
+ //
+ // BUGBUG: Should we check that the response is also
+ // unique? Not much to do since I don't know of an
+ // equivalent to the netbeui NAME_IN_CONFLICT.
+ //
+
+ } else {
+
+ //
+ // This is a group name.
+ //
+
+ if (Connectionless->NameFrame.NameTypeFlag & NB_NAME_GROUP) {
+
+ //
+ // Update our information about this network if needed.
+ // This may free the existing cache and allocate a new one.
+ //
+
+ Reserved->u.SR_FN.NewCache =
+ CacheUpdateNameCache(
+ Reserved->u.SR_FN.NewCache,
+ RemoteAddress,
+ (TDI_ADDRESS_IPX UNALIGNED *)
+ Connectionless->IpxHeader.SourceNetwork,
+ FALSE);
+
+ } else {
+
+ //
+ // BUGBUG: This respondent thinks it is a unique name
+ // but we think it is group, should we do something?
+ //
+
+ }
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+} /* NbiProcessNameRecognized */
+
+
+PNETBIOS_CACHE
+CacheUpdateNameCache(
+ IN PNETBIOS_CACHE NameCache,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN TDI_ADDRESS_IPX UNALIGNED * SourceAddress,
+ IN BOOLEAN ModifyQueue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to update a netbios cache entry
+ with a new network, if it is does not already contain
+ information about the network. It is called when a frame
+ is received advertising the appropriate cache entry, which
+ is either a group name or the broadcast name.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH IT HELD.
+
+Arguments:
+
+ NameCache - The name cache entry to update.
+
+ RemoteAddress - The remote address on which a frame was received.
+
+ IpxAddress - The source IPX address of the frame.
+
+ ModifyQueue - TRUE if we should update the queue which this
+ cache entry is in, if we reallocate it.
+
+Return Value:
+
+ The netbios cache entry, either the original or a reallocated one.
+
+--*/
+
+{
+
+ PDEVICE Device = NbiDevice;
+ USHORT NewNetworks;
+ PNETBIOS_CACHE NewNameCache;
+ PLIST_ENTRY OldPrevious;
+ UINT i;
+
+ //
+ // See if we already know about this network.
+ //
+
+ for (i = 0; i < NameCache->NetworksUsed; i++) {
+ if (NameCache->Networks[i].Network == SourceAddress->NetworkAddress) {
+ return NameCache;
+ }
+ }
+
+ //
+ // We need to add information about this network
+ // to the name cache entry. If we have to allocate
+ // a new one we do that.
+ //
+
+ NB_DEBUG2 (CACHE, ("Got new net %lx for <%.16s>\n",
+ SourceAddress->NetworkAddress,
+ NameCache->NetbiosName));
+
+ if (NameCache->NetworksUsed == NameCache->NetworksAllocated) {
+
+ //
+ // We double the number of entries allocated until
+ // we hit 16, then add 8 at a time.
+ //
+
+ if (NameCache->NetworksAllocated < 16) {
+ NewNetworks = NameCache->NetworksAllocated * 2;
+ } else {
+ NewNetworks = NameCache->NetworksAllocated + 8;
+ }
+
+
+ NewNameCache = NbiAllocateMemory(
+ sizeof(NETBIOS_CACHE) + ((NewNetworks-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Enlarge cache entry");
+
+ if (NewNameCache == NULL) {
+ return NameCache;
+ }
+
+ NB_DEBUG2 (CACHE, ("Expand cache %lx to %lx for <%.16s>\n",
+ NameCache, NewNameCache, NameCache->NetbiosName));
+
+ //
+ // Copy the new current data to the new one.
+ //
+
+ RtlCopyMemory(
+ NewNameCache,
+ NameCache,
+ sizeof(NETBIOS_CACHE) + ((NameCache->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)));
+
+ NewNameCache->NetworksAllocated = NewNetworks;
+ NewNameCache->ReferenceCount = 1;
+
+ if (ModifyQueue) {
+
+ //
+ // Insert at the same place as the old one. The time
+ // stamp is the same as the old one.
+ //
+
+
+ ReinsertInNetbiosCacheTable( Device->NameCache, NameCache, NewNameCache );
+
+ }
+
+ if (--NameCache->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free replaced cache entry %lx\n", NameCache));
+ NbiFreeMemory(
+ NameCache,
+ sizeof(NETBIOS_CACHE) + ((NameCache->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Enlarge existing");
+
+ }
+
+ NameCache = NewNameCache;
+
+ }
+
+ NameCache->Networks[NameCache->NetworksUsed].Network =
+ SourceAddress->NetworkAddress;
+
+ //
+ // If this packet was not routed to us, then store the local
+ // target for a correct broadcast.
+ //
+
+ if (RtlEqualMemory (RemoteAddress->MacAddress, SourceAddress->NodeAddress, 6)) {
+#if defined(_PNP_POWER)
+ NameCache->Networks[NameCache->NetworksUsed].LocalTarget.NicHandle = RemoteAddress->NicHandle;
+#else
+ NameCache->Networks[NameCache->NetworksUsed].LocalTarget.NicId = RemoteAddress->NicId;
+#endif _PNP_POWER
+ RtlCopyMemory (NameCache->Networks[NameCache->NetworksUsed].LocalTarget.MacAddress, BroadcastAddress, 6);
+ } else {
+ NameCache->Networks[NameCache->NetworksUsed].LocalTarget = *RemoteAddress;
+ }
+
+ ++NameCache->NetworksUsed;
+
+ return NameCache;
+
+} /* CacheUpdateNameCache */
+
+
+VOID
+CacheUpdateFromAddName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN NB_CONNECTIONLESS UNALIGNED * Connectionless,
+ IN BOOLEAN LocalFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when an add name frame is received.
+ If it is for a group name it checks if our cache entry for
+ that group name needs to be updated to include a new network;
+ for all frames it checks if our broadcast cache entry needs
+ to be updated to include a new network.
+
+Arguments:
+
+ RemoteAddress - The address the frame was received from.
+
+ Connectionless - The header of the received add name.
+
+ LocalFrame - TRUE if the frame was sent locally.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PUCHAR NetbiosName;
+ PNETBIOS_CACHE NameCache;
+ PLIST_ENTRY p;
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ NetbiosName = (PUCHAR)Connectionless->NameFrame.Name;
+
+ //
+ // First look up the broadcast name.
+ //
+ // BUGBUG: We should cache a pointer to the cache name
+ // for the broadcast entry, if there is one.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (!LocalFrame) {
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ NetbiosBroadcastName,
+ &NameCache ) == STATUS_SUCCESS ) {
+ //
+ // This will reallocate a cache entry and update the
+ // queue if necessary.
+ //
+
+ (VOID)CacheUpdateNameCache(
+ NameCache,
+ RemoteAddress,
+ (TDI_ADDRESS_IPX UNALIGNED *)(Connectionless->IpxHeader.SourceNetwork),
+ TRUE);
+ }
+
+ }
+
+
+ //
+ // Now see if our database needs to be updated based on this.
+ //
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ Connectionless->NameFrame.Name,
+ &NameCache ) == STATUS_SUCCESS ) {
+
+
+ if (!NameCache->Unique) {
+
+ if (!LocalFrame) {
+
+ //
+ // This will reallocate a cache entry and update the
+ // queue if necessary.
+ //
+
+ (VOID)CacheUpdateNameCache(
+ NameCache,
+ RemoteAddress,
+ (TDI_ADDRESS_IPX UNALIGNED *)(Connectionless->IpxHeader.SourceNetwork),
+ TRUE);
+
+ }
+
+ } else {
+
+ //
+ // To be safe, delete any unique names we get add
+ // names for (we will requery next time we need it).
+ // BUGBUG: Update the database instead -- but then
+ // we may not get the best route??
+ //
+
+ RemoveFromNetbiosCacheTable ( Device->NameCache, NameCache );
+
+ if (--NameCache->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free add named cache entry %lx\n", NameCache));
+ NbiFreeMemory(
+ NameCache,
+ sizeof(NETBIOS_CACHE) + ((NameCache->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Enlarge existing");
+
+ }
+
+ }
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+} /* CacheUpdateFromAddName */
+
+
+VOID
+NbiProcessDeleteName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_DELETE_NAME frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NB_CONNECTIONLESS UNALIGNED * Connectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
+ PUCHAR NetbiosName;
+ PNETBIOS_CACHE CacheName;
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ if (PacketSize != sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME)) {
+ return;
+ }
+
+ //
+ // We want to update our netbios cache to reflect the
+ // fact that this name is no longer valid.
+ //
+
+ NetbiosName = (PUCHAR)Connectionless->NameFrame.Name;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ NetbiosName,
+ &CacheName ) == STATUS_SUCCESS ) {
+
+ //
+ // We don't track group names since we don't know if
+ // this is the last person that owns it. We also drop
+ // the frame if does not come from the person we think
+ // owns this name.
+ //
+
+ if ((!CacheName->Unique) ||
+ (CacheName->NetworksUsed == 0) ||
+ (!RtlEqualMemory (&CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12))) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ NB_DEBUG2 (CACHE, ("Found cache name to delete <%.16s>\n", NetbiosName));
+
+ }else {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+
+ //
+ // We have a cache entry, take it out of the list. If no
+ // one else is using it, delete it; if not, they will delete
+ // it when they are done.
+ //
+
+
+ RemoveFromNetbiosCacheTable ( Device->NameCache, CacheName);
+
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ NB_DEBUG2 (CACHE, ("Free delete name cache entry %lx\n", CacheName));
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Name deleted");
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+} /* NbiProcessDeleteName */
+
+VOID
+InsertInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE CacheEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine inserts a new cache entry in the hash table
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ CacheEntry - Entry to be inserted.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ USHORT HashIndex;
+
+ //
+ // Keep a threshold of how many entries do we keep in the table.
+ // If it crosses the threshold, just remove the oldest entry
+ //
+ if ( CacheTable->CurrentEntries >= CacheTable->MaxHashIndex * NB_MAX_AVG_CACHE_ENTRIES_PER_BUCKET ) {
+ PNETBIOS_CACHE OldestCacheEntry = NULL;
+ PNETBIOS_CACHE NextEntry;
+ PLIST_ENTRY p;
+
+ for ( HashIndex = 0; HashIndex < CacheTable->MaxHashIndex; HashIndex++) {
+ if ( (p = CacheTable->Bucket[ HashIndex ].Blink ) != &CacheTable->Bucket[ HashIndex ] ) {
+ NextEntry = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+
+ if ( OldestCacheEntry ) {
+ if ( NextEntry->TimeStamp < OldestCacheEntry->TimeStamp ) {
+ OldestCacheEntry = NextEntry;
+ }
+ } else {
+ OldestCacheEntry = NextEntry;
+ }
+ }
+ }
+
+ CTEAssert( OldestCacheEntry );
+
+ NB_DEBUG2 (CACHE, ("Threshold exceeded, removing oldest cache entry %lx\n", OldestCacheEntry));
+ RemoveEntryList (&OldestCacheEntry->Linkage);
+ CacheTable->CurrentEntries--;
+
+ if (--OldestCacheEntry->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Freed cache entry %lx\n", OldestCacheEntry));
+
+ NbiFreeMemory(
+ OldestCacheEntry,
+ sizeof(NETBIOS_CACHE) + ((OldestCacheEntry->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Aged out");
+
+ }
+
+ }
+ HashIndex = ( ( CacheEntry->NetbiosName[0] & 0x0f ) << 4 ) + ( CacheEntry->NetbiosName[1] & 0x0f );
+ HashIndex = HashIndex % CacheTable->MaxHashIndex;
+
+ InsertHeadList( &CacheTable->Bucket[HashIndex], &CacheEntry->Linkage );
+ CacheTable->CurrentEntries++;
+} /* InsertInNetbiosCacheTable */
+
+
+__inline
+VOID
+ReinsertInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE OldEntry,
+ IN PNETBIOS_CACHE NewEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine inserts a new cache entry at the same place where
+ the old entry was.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ CacheEntry - Entry to be inserted.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PLIST_ENTRY OldPrevious;
+
+ OldPrevious = OldEntry->Linkage.Blink;
+ RemoveEntryList (&OldEntry->Linkage);
+ InsertHeadList (OldPrevious, &NewEntry->Linkage);
+} /* ReinsertInNetbiosCacheTable */
+
+__inline
+VOID
+RemoveFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE CacheEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes an entry from the cache table.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ CacheEntry - Entry to be removed.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Return Value:
+
+ None.
+--*/
+
+{
+ RemoveEntryList( &CacheEntry->Linkage );
+ CacheTable->CurrentEntries--;
+} /* RemoveFromNetbiosCacheTable */
+
+
+
+VOID
+FlushOldFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN USHORT AgeLimit
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes all the old entries from the hash table.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ AgeLimit - All the entries older than AgeLimit will be removed.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Return Value:
+
+ None.
+--*/
+
+{
+ USHORT HashIndex;
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE CacheName;
+
+ //
+ // run the hash table looking for old entries. Since new entries
+ // are stored at the head and all entries are time stamped when
+ // they are inserted, we scan backwards and stop once we find
+ // an entry which does not need to be aged.
+ // we repeat this for each bucket.
+
+ for ( HashIndex = 0; HashIndex < CacheTable->MaxHashIndex; HashIndex++) {
+ for (p = CacheTable->Bucket[ HashIndex ].Blink;
+ p != &CacheTable->Bucket[ HashIndex ];
+ ) {
+
+ CacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+ p = p->Blink;
+
+ //
+ // see if any entries have been around for more than agelimit
+ //
+
+ if ((USHORT)(NbiDevice->CacheTimeStamp - CacheName->TimeStamp) >= AgeLimit ) {
+
+ RemoveEntryList (&CacheName->Linkage);
+ CacheTable->CurrentEntries--;
+
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Aging out name cache entry %lx\n", CacheName));
+
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Aged out");
+
+ }
+
+ } else {
+
+ break;
+
+ }
+ } // for loop
+ } // for loop
+} /* FlushOldFromNetbiosCacheTable */
+
+VOID
+FlushFailedNetbiosCacheEntries(
+ IN PNETBIOS_CACHE_TABLE CacheTable
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes all the failed entries from the hash table.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Return Value:
+
+ None.
+--*/
+
+{
+ USHORT HashIndex;
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE CacheName;
+
+ //
+ // run the hash table looking for old entries. Since new entries
+ // are stored at the head and all entries are time stamped when
+ // they are inserted, we scan backwards and stop once we find
+ // an entry which does not need to be aged.
+ // we repeat this for each bucket.
+
+ for ( HashIndex = 0; HashIndex < CacheTable->MaxHashIndex; HashIndex++) {
+ for (p = CacheTable->Bucket[ HashIndex ].Blink;
+ p != &CacheTable->Bucket[ HashIndex ];
+ ) {
+
+ CacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+ p = p->Blink;
+
+ //
+ // flush all the failed cache entries.
+ // We do this when a new adapter appears, and there's a possiblity that
+ // the failed entries might succeed now on the new adapter.
+ //
+
+ if (CacheName->NetworksUsed == 0) {
+ RemoveEntryList (&CacheName->Linkage);
+ CacheTable->CurrentEntries--;
+ CTEAssert( CacheName->ReferenceCount == 1 );
+ CTEAssert( CacheName->NetworksAllocated == 1 );
+
+ NB_DEBUG2 (CACHE, ("Flushing out failed name cache entry %lx\n", CacheName));
+
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE),
+ MEMORY_CACHE,
+ "Aged out");
+
+ }
+ } // for loop
+ } // for loop
+} /* FlushFailedNetbiosCacheEntries */
+
+VOID
+RemoveInvalidRoutesFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN NIC_HANDLE UNALIGNED *InvalidNicHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes all invalid route entries from the hash table.
+ Routes become invalid when the binding is deleted in Ipx due to PnP
+ event.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ InvalidRouteNicId - NicId of the invalid routes.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Return Value:
+
+ None.
+--*/
+
+{
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE CacheName;
+ USHORT i,j,NetworksRemoved;
+ USHORT HashIndex;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Flush all the cache entries that are using this NicId in the local
+ // target.
+ //
+
+ for ( HashIndex = 0; HashIndex < Device->NameCache->MaxHashIndex; HashIndex++) {
+ for (p = Device->NameCache->Bucket[ HashIndex ].Flink;
+ p != &Device->NameCache->Bucket[ HashIndex ];
+ ) {
+
+ CacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+ p = p->Flink;
+
+
+ //
+ // Remove each of those routes which is using this NicId.
+ // if no routes left, then flush the cache entry also.
+ // ( unique names have only one route anyways )
+ //
+ for ( i = 0, NetworksRemoved = 0; i < CacheName->NetworksUsed; i++ ) {
+ if ( CacheName->Networks[i].LocalTarget.NicHandle.NicId == InvalidNicHandle->NicId ) {
+ CTEAssert( RtlEqualMemory( &CacheName->Networks[i].LocalTarget.NicHandle, InvalidNicHandle, sizeof(NIC_HANDLE)));
+ for ( j = i+1; j < CacheName->NetworksUsed; j++ ) {
+ CacheName->Networks[j-1] = CacheName->Networks[j];
+ }
+ NetworksRemoved++;
+ } else if ( CacheName->Networks[i].LocalTarget.NicHandle.NicId > InvalidNicHandle->NicId ) {
+ CacheName->Networks[i].LocalTarget.NicHandle.NicId--;
+ }
+ }
+ CTEAssert( NetworksRemoved <= CacheName->NetworksUsed );
+ if ( ! ( CacheName->NetworksUsed -= NetworksRemoved ) ) {
+ RemoveEntryList (&CacheName->Linkage);
+ CacheTable->CurrentEntries--;
+
+ NB_DEBUG2 (CACHE, ("Removed cache entry %lx bcoz route(NicId %d) deleted\n", CacheName, InvalidNicHandle->NicId ));
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Freed name cache entry %lx\n", CacheName));
+
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Aged out");
+
+ }
+ }
+ } // for loop
+ } // for loop
+} /* RemoveInvalidRoutesFromNetbiosCacheTable */
+
+
+NTSTATUS
+FindInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PUCHAR NameToBeFound,
+ OUT PNETBIOS_CACHE *CacheEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine finds a netbios name in the Hash Table and returns
+ the corresponding cache entry.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ CacheEntry - Pointer to the netbios cache entry if found.
+
+Return Value:
+
+ STATUS_SUCCESS - if successful.
+
+ STATUS_UNSUCCESSFUL - otherwise.
+
+--*/
+
+{
+ USHORT HashIndex;
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE FoundCacheName;
+
+
+ HashIndex = ( ( NameToBeFound[0] & 0x0f ) << 4 ) + ( NameToBeFound[1] & 0x0f );
+ HashIndex = HashIndex % CacheTable->MaxHashIndex;
+
+ for (p = ( CacheTable->Bucket[ HashIndex ] ).Flink;
+ p != &CacheTable->Bucket[ HashIndex ];
+ p = p->Flink) {
+
+ FoundCacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+
+ //
+ // See if this entry is for the same name we are looking for.
+
+ if ( RtlEqualMemory (FoundCacheName->NetbiosName, NameToBeFound, 16) ) {
+ *CacheEntry = FoundCacheName;
+ return STATUS_SUCCESS;
+ }
+ }
+
+ return STATUS_UNSUCCESSFUL;
+} /* FindInNetbiosCacheTable */
+
+NTSTATUS
+CreateNetbiosCacheTable(
+ IN OUT PNETBIOS_CACHE_TABLE *NewTable,
+ IN USHORT MaxHashIndex
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a new hash table for netbios cache
+ and initializes it.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Arguments:
+
+ NewTable - The pointer of the table to be created.
+
+ MaxHashIndex - Number of buckets in the hash table.
+
+Return Value:
+
+ STATUS_SUCCESS - if successful.
+
+ STATUS_INSUFFICIENT_RESOURCES - If cannot allocate memory.
+
+--*/
+
+{
+ USHORT i;
+
+ *NewTable = NbiAllocateMemory (sizeof(NETBIOS_CACHE_TABLE) + sizeof(LIST_ENTRY) * ( MaxHashIndex - 1) ,
+ MEMORY_CACHE, "Cache Table");
+
+ if ( *NewTable ) {
+ for ( i = 0; i < MaxHashIndex; i++ ) {
+ InitializeListHead(& (*NewTable)->Bucket[i] );
+ }
+
+ (*NewTable)->MaxHashIndex = MaxHashIndex;
+ (*NewTable)->CurrentEntries = 0;
+ return STATUS_SUCCESS;
+ }
+ else {
+ NB_DEBUG( CACHE, ("Cannot create Netbios Cache Table\n") );
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+} /* CreateNetbiosCacheTable */
+
+
+VOID
+DestroyNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes all entries from the hash table.
+ and free up the hash table.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+Return Value:
+
+ None.
+--*/
+
+{
+ USHORT HashIndex;
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE CacheName;
+
+
+ for ( HashIndex = 0; HashIndex < CacheTable->MaxHashIndex; HashIndex++) {
+ while (!IsListEmpty ( &( CacheTable->Bucket[ HashIndex ] ) ) ) {
+
+ p = RemoveHeadList ( &( CacheTable->Bucket[ HashIndex ] ));
+ CacheTable->CurrentEntries--;
+ CacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+
+ NB_DEBUG2 (CACHE, ("Free cache entry %lx\n", CacheName));
+
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free entries");
+
+ }
+ } // for loop
+
+ CTEAssert( CacheTable->CurrentEntries == 0 );
+
+ NbiFreeMemory (CacheTable, sizeof(NETBIOS_CACHE_TABLE) + sizeof(LIST_ENTRY) * ( CacheTable->MaxHashIndex - 1) ,
+ MEMORY_CACHE, "Free Cache Table");
+
+} /* DestroyNetbiosCacheTable */
+
+
diff --git a/private/ntos/tdi/isnp/nb/config.c b/private/ntos/tdi/isnp/nb/config.c
new file mode 100644
index 000000000..8689c5d20
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/config.c
@@ -0,0 +1,661 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ config.c
+
+Abstract:
+
+ This contains all routines necessary for the support of the dynamic
+ configuration of the ISN Netbios module.
+
+Author:
+
+ Adam Barr (adamba) 16-November-1993
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Local functions used to access the registry.
+//
+
+NTSTATUS
+NbiGetConfigValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+NbiAddBind(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+NbiAddExport(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+NbiReadLinkageInformation(
+ IN PCONFIG Config
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,NbiGetConfiguration)
+#pragma alloc_text(INIT,NbiFreeConfiguration)
+#pragma alloc_text(INIT,NbiGetConfigValue)
+#pragma alloc_text(INIT,NbiAddBind)
+#pragma alloc_text(INIT,NbiAddExport)
+#pragma alloc_text(INIT,NbiReadLinkageInformation)
+#endif
+
+
+
+NTSTATUS
+NbiGetConfiguration (
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath,
+ OUT PCONFIG * ConfigPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by Netbios to get information from the configuration
+ management routines. We read the registry, starting at RegistryPath,
+ to get the parameters. If they don't exist, we use the defaults
+ set in ipxcnfg.h file. A list of adapters to bind to is chained
+ on to the config information.
+
+Arguments:
+
+ DriverObject - Used for logging errors.
+
+ RegistryPath - The name of Netbios' node in the registry.
+
+ ConfigPtr - Returns the configuration information.
+
+Return Value:
+
+ Status - STATUS_SUCCESS if everything OK, STATUS_INSUFFICIENT_RESOURCES
+ otherwise.
+
+--*/
+{
+ PWSTR RegistryPathBuffer;
+ PCONFIG Config;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[CONFIG_PARAMETERS+2];
+ NTSTATUS Status;
+ ULONG One = 1;
+ ULONG Two = 2;
+ ULONG Three = 3;
+ ULONG Four = 4;
+ ULONG Five = 5;
+ ULONG Eight = 8;
+ ULONG FortyEight = 48;
+ ULONG Sixty = 60;
+ ULONG TwoFifty = 250;
+ ULONG FiveHundred = 500;
+ ULONG MaxMTU = 0xffffffff;
+
+ PWSTR Parameters = L"Parameters";
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[CONFIG_PARAMETERS] = {
+ { L"AckDelayTime", &TwoFifty } , // milliseconds
+ { L"AckWindow", &Two } ,
+ { L"AckWindowThreshold", &FiveHundred } , // milliseconds
+ { L"EnablePiggyBackAck", &One } ,
+ { L"Extensions", &One } ,
+ { L"RcvWindowMax", &Four } ,
+ { L"BroadcastCount", &Three } ,
+ { L"BroadcastTimeout", &One } , // half-seconds
+ { L"ConnectionCount", &Five } ,
+ { L"ConnectionTimeout", &Two } , // half-seconds
+ { L"InitPackets", &Eight } ,
+ { L"MaxPackets", &FortyEight } ,
+ { L"InitialRetransmissionTime", &FiveHundred } , // milliseconds
+ { L"Internet", &One } ,
+ { L"KeepAliveCount", &Eight } ,
+ { L"KeepAliveTimeout", &Sixty } , // half-seconds
+ { L"RetransmitMax", &Eight } ,
+ { L"RouterMTU", &MaxMTU } };
+ UINT i;
+
+
+ //
+ // Allocate memory for the main config structure.
+ //
+
+ Config = NbiAllocateMemory (sizeof(CONFIG), MEMORY_CONFIG, "Config");
+ if (Config == NULL) {
+ NbiWriteResourceErrorLog ((PVOID)DriverObject, sizeof(CONFIG), MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Config->DeviceName.Buffer = NULL;
+ Config->BindName.Buffer = NULL;
+ Config->DriverObject = DriverObject; // save this to log errors
+
+ //
+ // Read in the NDIS binding information (if none is present
+ // the array will be filled with all known drivers).
+ //
+ // NbiReadLinkageInformation expects a null-terminated path,
+ // so we have to create one from the UNICODE_STRING.
+ //
+
+ RegistryPathBuffer = (PWSTR)NbiAllocateMemory(RegistryPath->Length + sizeof(WCHAR),
+ MEMORY_CONFIG, "RegistryPathBuffer");
+ if (RegistryPathBuffer == NULL) {
+ NbiWriteResourceErrorLog ((PVOID)DriverObject, RegistryPath->Length + sizeof(WCHAR), MEMORY_CONFIG);
+ NbiFreeConfiguration(Config);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ RtlCopyMemory (RegistryPathBuffer, RegistryPath->Buffer, RegistryPath->Length);
+ *(PWCHAR)(((PUCHAR)RegistryPathBuffer)+RegistryPath->Length) = (WCHAR)'\0';
+
+ Config->RegistryPathBuffer = RegistryPathBuffer;
+
+
+ //
+ // Determine what name to export and who to bind to.
+ //
+
+ Status = NbiReadLinkageInformation (Config);
+
+ if (Status != STATUS_SUCCESS) {
+
+ //
+ // If it failed it logged an error.
+ //
+
+ NbiFreeConfiguration(Config);
+ return Status;
+ }
+
+
+ //
+ // Read the per-transport (as opposed to per-binding)
+ // parameters.
+ //
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Parameters key below Netbios
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Parameters;
+
+ //
+ // 2-18) Call NbiSetBindingValue for each of the keys we
+ // care about.
+ //
+
+ for (i = 0; i < CONFIG_PARAMETERS; i++) {
+
+ QueryTable[i+1].QueryRoutine = NbiGetConfigValue;
+ QueryTable[i+1].Flags = 0;
+ QueryTable[i+1].Name = ParameterValues[i].KeyName;
+ QueryTable[i+1].EntryContext = (PVOID)i;
+ QueryTable[i+1].DefaultType = REG_DWORD;
+ QueryTable[i+1].DefaultData = (PVOID)(ParameterValues[i].DefaultValue);
+ QueryTable[i+1].DefaultLength = sizeof(ULONG);
+
+ }
+
+ //
+ // 19) Stop
+ //
+
+ QueryTable[CONFIG_PARAMETERS+1].QueryRoutine = NULL;
+ QueryTable[CONFIG_PARAMETERS+1].Flags = 0;
+ QueryTable[CONFIG_PARAMETERS+1].Name = NULL;
+
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+
+ NbiFreeConfiguration(Config);
+ NbiWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 701,
+ Status,
+ Parameters,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ NbiFreeMemory (RegistryPathBuffer, RegistryPath->Length + sizeof(WCHAR), MEMORY_CONFIG, "RegistryPathBuffer");
+ *ConfigPtr = Config;
+
+ return STATUS_SUCCESS;
+
+} /* NbiGetConfiguration */
+
+
+VOID
+NbiFreeConfiguration (
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by Netbios to get free any storage that was allocated
+ by NbiGetConfiguration in producing the specified CONFIG structure.
+
+Arguments:
+
+ Config - A pointer to the configuration information structure.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if (Config->BindName.Buffer) {
+ NbiFreeMemory (Config->BindName.Buffer, Config->BindName.MaximumLength, MEMORY_CONFIG, "BindName");
+ }
+
+ if (Config->DeviceName.Buffer) {
+ NbiFreeMemory (Config->DeviceName.Buffer, Config->DeviceName.MaximumLength, MEMORY_CONFIG, "DeviceName");
+ }
+
+ NbiFreeMemory (Config, sizeof(CONFIG), MEMORY_CONFIG, "Config");
+
+} /* NbiFreeConfig */
+
+
+NTSTATUS
+NbiGetConfigValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each entry in the Parameters
+ node to set the config values. The table is set up
+ so that this function will be called with correct default
+ values for keys that are not present.
+
+Arguments:
+
+ ValueName - The name of the value (ignored).
+
+ ValueType - The type of the value (REG_DWORD -- ignored).
+
+ ValueData - The data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to the CONFIG structure.
+
+ EntryContext - The index in Config->Parameters to save the value.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+ ULONG Data = *(UNALIGNED ULONG *)ValueData;
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+
+ if ((ValueType != REG_DWORD) || (ValueLength != sizeof(ULONG))) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+
+ switch ( (ULONG) EntryContext ) {
+ case CONFIG_ROUTER_MTU:
+ if ( ( Data - sizeof(NB_CONNECTION) - sizeof(IPX_HEADER) ) <= 0 ) {
+ Config->Parameters[CONFIG_ROUTER_MTU] = 0xffffffff;
+ NbiWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 704,
+ STATUS_INVALID_PARAMETER,
+ ValueName,
+ 0,
+ NULL);
+ return STATUS_SUCCESS;
+ }
+ break;
+ default:
+ break;
+ }
+
+ NB_DEBUG2 (CONFIG, ("Config parameter %d, value %lx\n",
+ (ULONG)EntryContext, Data));
+ Config->Parameters[(ULONG)EntryContext] = Data;
+
+ return STATUS_SUCCESS;
+
+} /* NbiGetConfigValue */
+
+
+NTSTATUS
+NbiAddBind(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Bind" multi-string and
+ saves the information in a Config structure.
+
+Arguments:
+
+ ValueName - The name of the value ("Bind" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - A pointer to the Config structure.
+
+ EntryContext - A pointer to a count of binds that is incremented.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+ PULONG ValueReadOk = ((PULONG)EntryContext);
+ PWCHAR NameBuffer;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+
+ if (*ValueReadOk == 0) {
+
+ NB_DEBUG2 (CONFIG, ("Read bind value %ws\n", ValueData));
+
+ NameBuffer = (PWCHAR)NbiAllocateMemory (ValueLength, MEMORY_CONFIG, "BindName");
+ if (NameBuffer == NULL) {
+ NbiWriteResourceErrorLog ((PVOID)Config->DriverObject, ValueLength, MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (NameBuffer, ValueData, ValueLength);
+ Config->BindName.Buffer = NameBuffer;
+ Config->BindName.Length = (USHORT)(ValueLength - sizeof(WCHAR));
+ Config->BindName.MaximumLength = (USHORT)ValueLength;
+
+ //
+ // Set this to ignore any other callbacks and let the
+ // caller know we read something.
+ //
+
+ *ValueReadOk = 1;
+
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbiAddBind */
+
+
+NTSTATUS
+NbiAddExport(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Export" multi-string. It
+ saves the first callback string in the Config structure.
+
+Arguments:
+
+ ValueName - The name of the value ("Export" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - A pointer to the Config structure.
+
+ EntryContext - A pointer to a ULONG that goes to 1 after the
+ first call to this routine (so we know to ignore other ones).
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+ PULONG ValueReadOk = ((PULONG)EntryContext);
+ PWCHAR NameBuffer;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+
+ if (*ValueReadOk == 0) {
+
+ NB_DEBUG2 (CONFIG, ("Read export value %ws\n", ValueData));
+
+ NameBuffer = (PWCHAR)NbiAllocateMemory (ValueLength, MEMORY_CONFIG, "DeviceName");
+ if (NameBuffer == NULL) {
+ NbiWriteResourceErrorLog ((PVOID)Config->DriverObject, ValueLength, MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (NameBuffer, ValueData, ValueLength);
+ Config->DeviceName.Buffer = NameBuffer;
+ Config->DeviceName.Length = (USHORT)(ValueLength - sizeof(WCHAR));
+ Config->DeviceName.MaximumLength = (USHORT)ValueLength;
+
+ //
+ // Set this to ignore any other callbacks and let the
+ // caller know we read something.
+ //
+
+ *ValueReadOk = 1;
+
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbiAddExport */
+
+
+NTSTATUS
+NbiReadLinkageInformation(
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by Netbios to read its linkage information
+ from the registry.
+
+Arguments:
+
+ Config - The config structure which will have per-binding information
+ linked on to it.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[3];
+ PWSTR Subkey = L"Linkage";
+ PWSTR Bind = L"Bind";
+ PWSTR Export = L"Export";
+ ULONG ValueReadOk; // set to TRUE when a value is read correctly
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Linkage key below Netbios
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Subkey;
+
+ //
+ // 1) Call NbiAddExport for each string in "Export"
+ //
+
+ QueryTable[1].QueryRoutine = NbiAddExport;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[1].Name = Export;
+ QueryTable[1].EntryContext = (PVOID)&ValueReadOk;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 2) Stop
+ //
+
+ QueryTable[2].QueryRoutine = NULL;
+ QueryTable[2].Flags = 0;
+ QueryTable[2].Name = NULL;
+
+
+ ValueReadOk = 0;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if ((Status != STATUS_SUCCESS) || (ValueReadOk == 0)) {
+
+ NbiWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 702,
+ Status,
+ Export,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+
+ //
+ // 1) Change to call NbiAddBind for each string in "Bind"
+ //
+
+ QueryTable[1].QueryRoutine = NbiAddBind;
+ QueryTable[1].Flags = 0; // not required
+ QueryTable[1].Name = Bind;
+ QueryTable[1].EntryContext = (PVOID)&ValueReadOk;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ ValueReadOk = 0;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if ((Status != STATUS_SUCCESS) || (ValueReadOk == 0)) {
+
+ NbiWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 703,
+ Status,
+ Bind,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbiReadLinkageInformation */
+
diff --git a/private/ntos/tdi/isnp/nb/config.h b/private/ntos/tdi/isnp/nb/config.h
new file mode 100644
index 000000000..99b6c6357
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/config.h
@@ -0,0 +1,70 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ config.h
+
+Abstract:
+
+ Private include file for the ISN Netbios module.
+ file defines all constants and structures necessary for support of
+ the dynamic configuration of ST.
+
+Revision History:
+
+--*/
+
+
+//
+// These are used to index into the Parameters array in CONFIG.
+//
+
+#define CONFIG_ACK_DELAY_TIME 0
+#define CONFIG_ACK_WINDOW 1
+#define CONFIG_ACK_WINDOW_THRESHOLD 2
+#define CONFIG_ENABLE_PIGGYBACK_ACK 3
+#define CONFIG_EXTENSIONS 4
+#define CONFIG_RCV_WINDOW_MAX 5
+#define CONFIG_BROADCAST_COUNT 6
+#define CONFIG_BROADCAST_TIMEOUT 7
+#define CONFIG_CONNECTION_COUNT 8
+#define CONFIG_CONNECTION_TIMEOUT 9
+#define CONFIG_INIT_PACKETS 10
+#define CONFIG_MAX_PACKETS 11
+#define CONFIG_INIT_RETRANSMIT_TIME 12
+#define CONFIG_INTERNET 13
+#define CONFIG_KEEP_ALIVE_COUNT 14
+#define CONFIG_KEEP_ALIVE_TIMEOUT 15
+#define CONFIG_RETRANSMIT_MAX 16
+#define CONFIG_ROUTER_MTU 17
+#define CONFIG_PARAMETERS 18
+
+//
+// Main configuration structure.
+//
+
+typedef struct _CONFIG {
+
+ ULONG Parameters[CONFIG_PARAMETERS]; // index defined above
+ NDIS_STRING DeviceName; // device name exported
+ NDIS_STRING BindName; // device to bind to
+ PWSTR RegistryPathBuffer; // path to config info
+ PDRIVER_OBJECT DriverObject; // used for logging errors
+
+} CONFIG, * PCONFIG;
+
+
+NTSTATUS
+NbiGetConfiguration (
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath,
+ OUT PCONFIG * ConfigPtr
+ );
+
+VOID
+NbiFreeConfiguration (
+ IN PCONFIG Config
+ );
+
diff --git a/private/ntos/tdi/isnp/nb/connect.c b/private/ntos/tdi/isnp/nb/connect.c
new file mode 100644
index 000000000..7ee7204b5
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/connect.c
@@ -0,0 +1,3628 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ connect.c
+
+Abstract:
+
+ This routine contains the code to handle connect requests
+ for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 22-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+#ifdef RASAUTODIAL
+#include <acd.h>
+#include <acdapi.h>
+
+BOOLEAN
+NbiCancelTdiConnect(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest,
+ IN PCONNECTION pConnection
+ );
+#endif // RASAUTODIAL
+
+
+
+VOID
+NbiFindRouteComplete(
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a find route request
+ previously issued to IPX completes.
+
+Arguments:
+
+ FindRouteRequest - The find route request that was issued.
+
+ FoundRoute - TRUE if the route was found.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PDEVICE Device = NbiDevice;
+ UINT i;
+ BOOLEAN LocalRoute;
+ USHORT TickCount;
+ PREQUEST RequestToComplete;
+ PUSHORT Counts;
+ CTELockHandle LockHandle1, LockHandle2;
+ CTELockHandle CancelLH;
+
+ Connection = CONTAINING_RECORD (FindRouteRequest, CONNECTION, FindRouteRequest);
+
+ NB_GET_CANCEL_LOCK(&CancelLH);
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ Connection->FindRouteInProgress = FALSE;
+
+ if (FoundRoute) {
+
+ //
+ // See if the route is local or not (for local routes
+ // we use the real MAC address in the local target, but
+ // the NIC ID may not be what we expect.
+ //
+
+ LocalRoute = TRUE;
+
+ for (i = 0; i < 6; i++) {
+ if (FindRouteRequest->LocalTarget.MacAddress[i] != 0x00) {
+ LocalRoute = FALSE;
+ }
+ }
+
+ if (LocalRoute) {
+
+#if defined(_PNP_POWER)
+ Connection->LocalTarget.NicHandle = FindRouteRequest->LocalTarget.NicHandle;
+#else
+ Connection->LocalTarget.NicId = FindRouteRequest->LocalTarget.NicId;
+#endif _PNP_POWER
+
+ } else {
+
+ Connection->LocalTarget = FindRouteRequest->LocalTarget;
+
+ }
+
+ Counts = (PUSHORT)(&FindRouteRequest->Reserved2);
+ TickCount = Counts[0];
+
+ if (TickCount > 1) {
+
+ //
+ // Each tick is 55 ms, and for our timeout we use 10 ticks
+ // worth (this makes tick count of 1 be about 500 ms, the
+ // default).
+ //
+ // We get 55 milliseconds from
+ //
+ // 1 second * 1000 milliseconds 55 ms
+ // -------- ----------------- = -----
+ // 18.21 ticks 1 second tick
+ //
+
+ Connection->TickCount = TickCount;
+ Connection->BaseRetransmitTimeout = (TickCount * 550) / SHORT_TIMER_DELTA;
+ if (Connection->State != CONNECTION_STATE_ACTIVE) {
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+ }
+ }
+
+ Connection->HopCount = Counts[1];
+
+ }
+
+ //
+ // If the call failed we just use whatever route we had before
+ // (on a connect it will be from the name query response, on
+ // a listen from whatever the incoming connect frame had).
+ //
+
+ if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_C_W_ROUTE)) {
+
+ // we dont need to hold CancelSpinLock so release it,
+ // since we are releasing the locks out of order, we must
+ // swap the irql to get the priorities right.
+
+ NB_SWAP_IRQL( CancelLH, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ //
+ // Continue on with the session init frame.
+ //
+
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_LINE_INFO,
+
+#if defined(_PNP_POWER)
+ &Connection->LocalTarget.NicHandle,
+#else
+ Connection->LocalTarget.NicId,
+#endif _PNP_POWER
+ &Connection->LineInfo,
+ sizeof(IPX_LINE_INFO),
+ NULL);
+
+ // Maximum packet size is the lower of RouterMtu and MaximumSendSize.
+ Connection->MaximumPacketSize = NB_MIN( Device->RouterMtu - sizeof(IPX_HEADER) , Connection->LineInfo.MaximumSendSize ) - sizeof(NB_CONNECTION) ;
+
+ Connection->ReceiveWindowSize = 6;
+ Connection->SendWindowSize = 2;
+ Connection->MaxSendWindowSize = 6; // BUGBUG: Base on what he sent
+
+ //
+ // Don't set RcvSequenceMax yet because we don't know
+ // if the connection is old or new netbios.
+ //
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_W_ACK;
+
+ //
+ // We found a route, we need to start the connect
+ // process by sending out the session initialize
+ // frame. We start the timer to handle retries.
+ //
+ // CTEStartTimer doesn't deal with changing the
+ // expiration time of a running timer, so we have
+ // to stop it first. If we succeed in stopping the
+ // timer, then the CREF_TIMER reference from the
+ // previous starting of the timer remains, so we
+ // don't need to reference the connection again.
+ //
+
+ if (!CTEStopTimer (&Connection->Timer)) {
+ NbiReferenceConnectionLock (Connection, CREF_TIMER);
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ CTEStartTimer(
+ &Connection->Timer,
+ Device->ConnectionTimeout,
+ NbiConnectionTimeout,
+ (PVOID)Connection);
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ NbiSendSessionInitialize (Connection);
+
+ } else if ((Connection->State == CONNECTION_STATE_LISTENING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_L_W_ROUTE)) {
+
+ if (Connection->ListenRequest != NULL) {
+
+ NbiTransferReferenceConnection (Connection, CREF_LISTEN, CREF_ACTIVE);
+ RequestToComplete = Connection->ListenRequest;
+ Connection->ListenRequest = NULL;
+ IoSetCancelRoutine (RequestToComplete, (PDRIVER_CANCEL)NULL);
+
+ } else if (Connection->AcceptRequest != NULL) {
+
+ NbiTransferReferenceConnection (Connection, CREF_ACCEPT, CREF_ACTIVE);
+ RequestToComplete = Connection->AcceptRequest;
+ Connection->AcceptRequest = NULL;
+
+ } else {
+
+ CTEAssert (FALSE);
+ RequestToComplete = NULL;
+
+ }
+
+ // we dont need to hold CancelSpinLock so release it,
+ // since we are releasing the locks out of order, we must
+ // swap the irql to get the priorities right.
+
+ NB_SWAP_IRQL( CancelLH, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_LINE_INFO,
+#if defined(_PNP_POWER)
+ &Connection->LocalTarget.NicHandle,
+#else
+ Connection->LocalTarget.NicId,
+#endif _PNP_POWER
+ &Connection->LineInfo,
+ sizeof(IPX_LINE_INFO),
+ NULL);
+
+
+ // Take the lowest of MaximumPacketSize ( set from the sessionInit
+ // frame ), MaximumSendSize and RouterMtu.
+
+ if (Connection->MaximumPacketSize > Connection->LineInfo.MaximumSendSize - sizeof(NB_CONNECTION)) {
+
+ Connection->MaximumPacketSize = NB_MIN( Device->RouterMtu - sizeof(IPX_HEADER), Connection->LineInfo.MaximumSendSize ) - sizeof(NB_CONNECTION);
+
+ } else {
+
+ // Connection->MaximumPacketSize is what was set by the sender so already
+ // accounts for the header.
+ Connection->MaximumPacketSize = NB_MIN( Device->RouterMtu - sizeof(NB_CONNECTION) - sizeof(IPX_HEADER), Connection->MaximumPacketSize ) ;
+
+ }
+
+ Connection->ReceiveWindowSize = 6;
+ Connection->SendWindowSize = 2;
+ Connection->MaxSendWindowSize = 6; // BUGBUG: Base on what he sent
+
+ if (Connection->NewNetbios) {
+ CTEAssert (Connection->LocalRcvSequenceMax == 4); // should have been set
+ Connection->LocalRcvSequenceMax = Connection->ReceiveWindowSize;
+ }
+
+ Connection->State = CONNECTION_STATE_ACTIVE;
+ Connection->SubState = CONNECTION_SUBSTATE_A_IDLE;
+ Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
+
+ ++Device->Statistics.OpenConnections;
+
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ //
+ // StartWatchdog acquires TimerLock, so we have to
+ // free Lock first.
+ //
+
+
+ NbiStartWatchdog (Connection);
+
+ //
+ // This releases the connection lock, so that SessionInitAckData
+ // can't be freed before it is copied.
+ //
+
+ NbiSendSessionInitAck(
+ Connection,
+ Connection->SessionInitAckData,
+ Connection->SessionInitAckDataLength,
+ &LockHandle1);
+
+ if (RequestToComplete != NULL) {
+
+ REQUEST_STATUS(RequestToComplete) = STATUS_SUCCESS;
+
+ NbiCompleteRequest (RequestToComplete);
+ NbiFreeRequest (Device, RequestToComplete);
+
+ }
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_FIND_ROUTE);
+
+} /* NbiFindRouteComplete */
+
+
+NTSTATUS
+NbiOpenConnection(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to open a connection. Note that the connection that
+ is open is of little use until associated with an address; until then,
+ the only thing that can be done with it is close it.
+
+Arguments:
+
+ Device - Pointer to the device for this driver.
+
+ Request - Pointer to the request representing the open.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PFILE_FULL_EA_INFORMATION ea;
+#ifdef ISN_NT
+ PIRP Irp = (PIRP)Request;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+#endif
+
+ //
+ // First, try to make a connection object to represent this pending
+ // connection. Then fill in the relevant fields.
+ // In addition to the creation, if successful NbfCreateConnection
+ // will create a second reference which is removed once the request
+ // references the connection, or if the function exits before that.
+
+ if (!(Connection = NbiCreateConnection (Device))) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // set the connection context so we can connect the user to this data
+ // structure
+ //
+
+ ea = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+ RtlCopyMemory (
+ &Connection->Context,
+ &ea->EaName[ea->EaNameLength+1],
+ sizeof (PVOID));
+
+ //
+ // let file object point at connection and connection at file object
+ //
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)Connection;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_CONNECTION_FILE;
+#ifdef ISN_NT
+ Connection->FileObject = IrpSp->FileObject;
+#endif
+
+ return STATUS_SUCCESS;
+
+} /* NbiOpenConnection */
+
+
+VOID
+NbiStopConnection(
+ IN PCONNECTION Connection,
+ IN NTSTATUS DisconnectStatus
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to stop an active connection.
+
+ THIS ROUTINE IS CALLED WITH THE CONNECTION LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection to be stopped.
+
+ DisconnectStatus - The reason for the disconnect. One of:
+ STATUS_LINK_FAILED: We timed out trying to probe the remote.
+ STATUS_REMOTE_DISCONNECT: The remote sent a session end.
+ STATUS_LOCAL_DISCONNECT: The local side disconnected.
+ STATUS_CANCELLED: A send or receive on this connection was cancelled.
+ STATUS_INVALID_CONNECTION: The local side closed the connection.
+ STATUS_INVALID_ADDRESS: The local side closed the address.
+
+ LockHandle - The handle which the connection lock was acquired with.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST ListenRequest, AcceptRequest, SendRequest, ReceiveRequest,
+ DisconnectWaitRequest, ConnectRequest;
+ PREQUEST Request, TmpRequest;
+ BOOLEAN DerefForPacketize;
+ BOOLEAN DerefForWaitPacket;
+ BOOLEAN DerefForActive;
+ BOOLEAN DerefForWaitCache;
+ BOOLEAN SendSessionEnd;
+ BOOLEAN ActiveReceive;
+ BOOLEAN IndicateToClient;
+ BOOLEAN ConnectionWasActive;
+ PDEVICE Device = NbiDevice;
+ PADDRESS_FILE AddressFile;
+ NB_DEFINE_LOCK_HANDLE (LockHandle2)
+ NB_DEFINE_LOCK_HANDLE (LockHandle3)
+ CTELockHandle CancelLH;
+
+
+ NB_DEBUG2 (CONNECTION, ("Stop connection %lx (%lx)\n", Connection, DisconnectStatus));
+
+ //
+ // These flags control our actions after we set the state to
+ // DISCONNECT.
+ //
+
+ DerefForPacketize = FALSE;
+ DerefForWaitPacket = FALSE;
+ DerefForActive = FALSE;
+ DerefForWaitCache = FALSE;
+ SendSessionEnd = FALSE;
+ ActiveReceive = FALSE;
+ IndicateToClient = FALSE;
+ ConnectionWasActive = FALSE;
+
+ //
+ // These contain requests or queues of request to complete.
+ //
+
+ ListenRequest = NULL;
+ AcceptRequest = NULL;
+ SendRequest = NULL;
+ ReceiveRequest = NULL;
+ DisconnectWaitRequest = NULL;
+ ConnectRequest = NULL;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ --Device->Statistics.OpenConnections;
+
+ ConnectionWasActive = TRUE;
+
+ Connection->Status = DisconnectStatus;
+
+ if ((DisconnectStatus == STATUS_LINK_FAILED) ||
+ (DisconnectStatus == STATUS_LOCAL_DISCONNECT)) {
+
+ //
+ // Send out session end frames, but fewer if
+ // we timed out.
+ //
+ // BUGBUG: What about STATUS_CANCELLED?
+ //
+
+ Connection->Retries = (DisconnectStatus == STATUS_LOCAL_DISCONNECT) ?
+ Device->ConnectionCount :
+ (Device->ConnectionCount / 2);
+
+ SendSessionEnd = TRUE;
+ Connection->SubState = CONNECTION_SUBSTATE_D_W_ACK;
+
+ //
+ // CTEStartTimer doesn't deal with changing the
+ // expiration time of a running timer, so we have
+ // to stop it first. If we succeed in stopping the
+ // timer, then the CREF_TIMER reference from the
+ // previous starting of the timer remains, so we
+ // don't need to reference the connection again.
+ //
+
+ if (!CTEStopTimer (&Connection->Timer)) {
+ NbiReferenceConnectionLock (Connection, CREF_TIMER);
+ }
+
+ CTEStartTimer(
+ &Connection->Timer,
+ Device->ConnectionTimeout,
+ NbiConnectionTimeout,
+ (PVOID)Connection);
+
+ }
+
+ if (Connection->ReceiveState == CONNECTION_RECEIVE_TRANSFER) {
+ ActiveReceive = TRUE;
+ }
+
+ Connection->State = CONNECTION_STATE_DISCONNECT;
+ DerefForActive = TRUE;
+
+ if (Connection->DisconnectWaitRequest != NULL) {
+ DisconnectWaitRequest = Connection->DisconnectWaitRequest;
+ Connection->DisconnectWaitRequest = NULL;
+ }
+
+ if ((DisconnectStatus == STATUS_LINK_FAILED) ||
+ (DisconnectStatus == STATUS_REMOTE_DISCONNECT) ||
+ (DisconnectStatus == STATUS_CANCELLED)) {
+
+ IndicateToClient = TRUE;
+
+ }
+
+ //
+ // If we are inside NbiAssignSequenceAndSend, add
+ // a reference so the connection won't go away during it.
+ //
+
+ if (Connection->NdisSendsInProgress > 0) {
+ *(Connection->NdisSendReference) = TRUE;
+ NB_DEBUG2 (SEND, ("Adding CREF_NDIS_SEND to %lx\n", Connection));
+ NbiReferenceConnectionLock (Connection, CREF_NDIS_SEND);
+ }
+
+ //
+ // Clean up some other stuff.
+ //
+
+ Connection->ReceiveUnaccepted = 0;
+ Connection->CurrentIndicateOffset = 0;
+
+ //
+ // Update our counters. BUGBUG: Some of these we
+ // never use.
+ //
+
+ switch (DisconnectStatus) {
+
+ case STATUS_LOCAL_DISCONNECT:
+ ++Device->Statistics.LocalDisconnects;
+ break;
+ case STATUS_REMOTE_DISCONNECT:
+ ++Device->Statistics.RemoteDisconnects;
+ break;
+ case STATUS_LINK_FAILED:
+ ++Device->Statistics.LinkFailures;
+ break;
+ case STATUS_IO_TIMEOUT:
+ ++Device->Statistics.SessionTimeouts;
+ break;
+ case STATUS_CANCELLED:
+ ++Device->Statistics.CancelledConnections;
+ break;
+ case STATUS_REMOTE_RESOURCES:
+ ++Device->Statistics.RemoteResourceFailures;
+ break;
+ case STATUS_INVALID_CONNECTION:
+ case STATUS_INVALID_ADDRESS:
+ case STATUS_INSUFFICIENT_RESOURCES:
+ ++Device->Statistics.LocalResourceFailures;
+ break;
+ case STATUS_BAD_NETWORK_PATH:
+ case STATUS_REMOTE_NOT_LISTENING:
+ ++Device->Statistics.NotFoundFailures;
+ break;
+ default:
+ CTEAssert(FALSE);
+ break;
+ }
+
+ } else if (Connection->State == CONNECTION_STATE_CONNECTING) {
+
+ //
+ // There is a connect in progress. We have to find ourselves
+ // in the pending connect queue if we are there.
+ //
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_C_FIND_NAME) {
+ RemoveEntryList (REQUEST_LINKAGE(Connection->ConnectRequest));
+ DerefForWaitCache = TRUE;
+ }
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN) {
+
+ ConnectRequest = Connection->ConnectRequest;
+ Connection->ConnectRequest = NULL;
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ }
+
+ }
+
+
+ //
+ // If we allocated this memory, free it.
+ //
+
+ if (Connection->SessionInitAckDataLength > 0) {
+
+ NbiFreeMemory(
+ Connection->SessionInitAckData,
+ Connection->SessionInitAckDataLength,
+ MEMORY_CONNECTION,
+ "SessionInitAckData");
+ Connection->SessionInitAckData = NULL;
+ Connection->SessionInitAckDataLength = 0;
+
+ }
+
+
+ if (Connection->ListenRequest != NULL) {
+
+ ListenRequest = Connection->ListenRequest;
+ Connection->ListenRequest = NULL;
+ RemoveEntryList (REQUEST_LINKAGE(ListenRequest)); // take out of Device->ListenQueue
+
+ }
+
+ if (Connection->AcceptRequest != NULL) {
+
+ AcceptRequest = Connection->AcceptRequest;
+ Connection->AcceptRequest = NULL;
+
+ }
+
+
+ //
+ // BUGBUG: Do we need to stop the connection timer?
+ // I don't think so.
+ //
+
+
+
+ //
+ // A lot of this we only have to tear down if we were
+ // active before this, because once we are stopping nothing
+ // new will get started. BUGBUG: Some of the other stuff
+ // can be put inside this if also.
+ //
+
+ if (ConnectionWasActive) {
+
+ //
+ // Stop any receives. If there is one that is actively
+ // transferring we leave it and just run down the rest
+ // of the queue. If not, we queue the rest of the
+ // queue on the back of the current one and run
+ // down them all.
+ //
+
+ if (ActiveReceive) {
+
+ ReceiveRequest = Connection->ReceiveQueue.Head;
+
+ //
+ // Connection->ReceiveRequest will get set to NULL
+ // when the transfer completes.
+ //
+
+ } else {
+
+ ReceiveRequest = Connection->ReceiveRequest;
+ if (ReceiveRequest) {
+ REQUEST_SINGLE_LINKAGE (ReceiveRequest) = Connection->ReceiveQueue.Head;
+ } else {
+ ReceiveRequest = Connection->ReceiveQueue.Head;
+ }
+ Connection->ReceiveRequest = NULL;
+
+ }
+
+ Connection->ReceiveQueue.Head = NULL;
+
+
+ if ((Request = Connection->FirstMessageRequest) != NULL) {
+
+ //
+ // If the current request has some sends outstanding, then
+ // we dequeue it from the queue to let it complete when
+ // the sends complete. In that case we set SendRequest
+ // to be the rest of the queue, which will be aborted.
+ // If the current request has no sends, then we put
+ // queue everything to SendRequest to be aborted below.
+ //
+
+#if DBG
+ if (REQUEST_REFCOUNT(Request) > 100) {
+ DbgPrint ("Request %lx (%lx) has high refcount\n",
+ Connection, Request);
+ DbgBreakPoint();
+ }
+#endif
+ if (--REQUEST_REFCOUNT(Request) == 0) {
+
+ //
+ // NOTE: If this is a multi-request message, then
+ // the linkage of Request will already point to the
+ // send queue head, but we don't bother checking.
+ //
+
+ SendRequest = Request;
+ REQUEST_SINGLE_LINKAGE (Request) = Connection->SendQueue.Head;
+
+ } else {
+
+ if (Connection->FirstMessageRequest == Connection->LastMessageRequest) {
+
+ REQUEST_SINGLE_LINKAGE (Request) = NULL;
+
+ } else {
+
+ Connection->SendQueue.Head = REQUEST_SINGLE_LINKAGE (Connection->LastMessageRequest);
+ REQUEST_SINGLE_LINKAGE (Connection->LastMessageRequest) = NULL;
+
+ }
+
+ SendRequest = Connection->SendQueue.Head;
+
+ }
+
+ Connection->FirstMessageRequest = NULL;
+
+ } else {
+
+ //
+ // This may happen if we were sending a probe when a
+ // send was submitted, and the probe timed out.
+ //
+
+ SendRequest = Connection->SendQueue.Head;
+
+ }
+
+ Connection->SendQueue.Head = NULL;
+
+ }
+
+
+ if (Connection->OnWaitPacketQueue) {
+ Connection->OnWaitPacketQueue = FALSE;
+ RemoveEntryList (&Connection->WaitPacketLinkage);
+ DerefForWaitPacket = TRUE;
+ }
+
+ if (Connection->OnPacketizeQueue) {
+ Connection->OnPacketizeQueue = FALSE;
+ RemoveEntryList (&Connection->PacketizeLinkage);
+ DerefForPacketize = TRUE;
+ }
+
+ //
+ // BUGBUG: Should we check if DataAckPending is TRUE and
+ // send an ack??
+ //
+
+ Connection->DataAckPending = FALSE;
+ Connection->PiggybackAckTimeout = FALSE;
+ Connection->ReceivesWithoutAck = 0;
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ //
+ // We can't acquire TimerLock with Lock held, since
+ // we sometimes call ReferenceConnection (which does an
+ // interlocked add using Lock) with TimerLock held.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle3);
+
+ if (Connection->OnShortList) {
+ Connection->OnShortList = FALSE;
+ RemoveEntryList (&Connection->ShortList);
+ }
+
+ if (Connection->OnLongList) {
+ Connection->OnLongList = FALSE;
+ RemoveEntryList (&Connection->LongList);
+ }
+
+ if (Connection->OnDataAckQueue) {
+ Connection->OnDataAckQueue = FALSE;
+ RemoveEntryList (&Connection->DataAckLinkage);
+ Device->DataAckQueueChanged = TRUE;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle3);
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+
+ if (IndicateToClient) {
+
+ AddressFile = Connection->AddressFile;
+
+ if (AddressFile->RegisteredHandler[TDI_EVENT_DISCONNECT]) {
+
+ NB_DEBUG2 (CONNECTION, ("Session end indicated on connection %lx\n", Connection));
+
+ (*AddressFile->DisconnectHandler)(
+ AddressFile->HandlerContexts[TDI_EVENT_DISCONNECT],
+ Connection->Context,
+ 0, // DisconnectData
+ NULL,
+ 0, // DisconnectInformation
+ NULL,
+ TDI_DISCONNECT_RELEASE); // DisconnectReason. BUGBUG: Clean it up?
+
+ }
+
+ }
+
+
+ if (DisconnectWaitRequest != NULL) {
+
+ //
+ // Make the TDI tester happy by returning CONNECTION_RESET
+ // here.
+ //
+
+ if (DisconnectStatus == STATUS_REMOTE_DISCONNECT) {
+ REQUEST_STATUS(DisconnectWaitRequest) = STATUS_CONNECTION_RESET;
+ } else {
+ REQUEST_STATUS(DisconnectWaitRequest) = DisconnectStatus;
+ }
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (DisconnectWaitRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiCompleteRequest (DisconnectWaitRequest);
+ NbiFreeRequest (Device, DisconnectWaitRequest);
+
+ }
+
+ if (ConnectRequest != NULL) {
+
+ REQUEST_STATUS (ConnectRequest) = STATUS_LOCAL_DISCONNECT;
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (ConnectRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiCompleteRequest(ConnectRequest);
+ NbiFreeRequest (Device, ConnectRequest);
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ }
+
+ if (ListenRequest != NULL) {
+
+ REQUEST_INFORMATION(ListenRequest) = 0;
+ REQUEST_STATUS(ListenRequest) = STATUS_LOCAL_DISCONNECT;
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (ListenRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiCompleteRequest (ListenRequest);
+ NbiFreeRequest(Device, ListenRequest);
+
+ NbiDereferenceConnection (Connection, CREF_LISTEN);
+
+ }
+
+ if (AcceptRequest != NULL) {
+
+ REQUEST_INFORMATION(AcceptRequest) = 0;
+ REQUEST_STATUS(AcceptRequest) = STATUS_LOCAL_DISCONNECT;
+
+ NbiCompleteRequest (AcceptRequest);
+ NbiFreeRequest(Device, AcceptRequest);
+
+ NbiDereferenceConnection (Connection, CREF_ACCEPT);
+
+ }
+
+ while (ReceiveRequest != NULL) {
+
+ TmpRequest = REQUEST_SINGLE_LINKAGE (ReceiveRequest);
+
+ REQUEST_STATUS (ReceiveRequest) = DisconnectStatus;
+ REQUEST_INFORMATION (ReceiveRequest) = 0;
+
+ NB_DEBUG2 (RECEIVE, ("StopConnection aborting receive %lx\n", ReceiveRequest));
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (ReceiveRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiCompleteRequest (ReceiveRequest);
+ NbiFreeRequest (Device, ReceiveRequest);
+
+ ++Connection->ConnectionInfo.ReceiveErrors;
+
+ ReceiveRequest = TmpRequest;
+
+ NbiDereferenceConnection (Connection, CREF_RECEIVE);
+
+ }
+
+ while (SendRequest != NULL) {
+
+ TmpRequest = REQUEST_SINGLE_LINKAGE (SendRequest);
+
+ REQUEST_STATUS (SendRequest) = DisconnectStatus;
+ REQUEST_INFORMATION (SendRequest) = 0;
+
+ NB_DEBUG2 (SEND, ("StopConnection aborting send %lx\n", SendRequest));
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (SendRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiCompleteRequest (SendRequest);
+ NbiFreeRequest (Device, SendRequest);
+
+ ++Connection->ConnectionInfo.TransmissionErrors;
+
+ SendRequest = TmpRequest;
+
+ NbiDereferenceConnection (Connection, CREF_SEND);
+
+ }
+
+ if (SendSessionEnd) {
+ NbiSendSessionEnd (Connection);
+ }
+
+ if (DerefForWaitCache) {
+ NbiDereferenceConnection (Connection, CREF_WAIT_CACHE);
+ }
+
+ if (DerefForPacketize) {
+ NbiDereferenceConnection (Connection, CREF_PACKETIZE);
+ }
+
+ if (DerefForWaitPacket) {
+ NbiDereferenceConnection (Connection, CREF_W_PACKET);
+ }
+
+ if (DerefForActive) {
+ NbiDereferenceConnection (Connection, CREF_ACTIVE);
+ }
+
+} /* NbiStopConnection */
+
+
+NTSTATUS
+NbiCloseConnection(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to close a connection.
+
+Arguments:
+
+ Device - Pointer to the device for this driver.
+
+ Request - Pointer to the request representing the open.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ CTELockHandle LockHandle;
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_DEBUG2 (CONNECTION, ("Close connection %lx\n", Connection));
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (Connection->ReferenceCount == 0) {
+
+ //
+ // If we are associated with an address, we need
+ // to simulate a disassociate at this point.
+ //
+
+ if ((Connection->AddressFile != NULL) &&
+ (Connection->AddressFile != (PVOID)-1)) {
+
+ AddressFile = Connection->AddressFile;
+ Connection->AddressFile = (PVOID)-1;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Take this connection out of the address file's list.
+ //
+
+ Address = AddressFile->Address;
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (Connection->AddressFileLinked) {
+ Connection->AddressFileLinked = FALSE;
+ RemoveEntryList (&Connection->AddressFileLinkage);
+ }
+
+ //
+ // We are done.
+ //
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ Connection->AddressFile = NULL;
+
+ //
+ // Clean up the reference counts and complete any
+ // disassociate requests that pended.
+ //
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ }
+
+ //
+ // Even if the ref count is zero and some thread has already done cleanup,
+ // we can not destroy the connection bcoz some other thread might still be
+ // in HandleConnectionZero routine. This could happen when 2 threads call into
+ // HandleConnectionZero, one thread runs thru completion, close comes along
+ // and the other thread is still in HandleConnectionZero routine.
+ //
+
+ if ( Connection->CanBeDestroyed && ( Connection->ThreadsInHandleConnectionZero == 0 ) ) {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ NbiDestroyConnection(Connection);
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ Connection->ClosePending = Request;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ Status = STATUS_PENDING;
+
+ }
+
+ } else {
+
+ Connection->ClosePending = Request;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ Status = STATUS_PENDING;
+
+ }
+
+ return Status;
+
+} /* NbiCloseConnection */
+
+
+NTSTATUS
+NbiTdiAssociateAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the association of the connection and
+ the address for the user.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the associate.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+#ifdef ISN_NT
+ PFILE_OBJECT FileObject;
+#endif
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PTDI_REQUEST_KERNEL_ASSOCIATE Parameters;
+ CTELockHandle LockHandle;
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+
+ //
+ // The request request parameters hold
+ // get a pointer to the address FileObject, which points us to the
+ // transport's address object, which is where we want to put the
+ // connection.
+ //
+
+ Parameters = (PTDI_REQUEST_KERNEL_ASSOCIATE)REQUEST_PARAMETERS(Request);
+
+#ifdef ISN_NT
+
+ Status = ObReferenceObjectByHandle (
+ Parameters->AddressHandle,
+ 0L,
+ 0,
+ KernelMode,
+ (PVOID *)&FileObject,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+ return Status;
+ }
+
+ AddressFile = (PADDRESS_FILE)(FileObject->FsContext);
+
+#else
+
+ //
+ // I don't know how this works in a VxD.
+ //
+
+ AddressFile = (PADDRESS_FILE)(Parameters->AddressHandle);
+
+#endif
+
+ //
+ // Make sure the address file is valid, and reference it.
+ //
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_NOT_OK);
+#else
+ Status = NbiVerifyAddressFile (AddressFile);
+#endif _PNP_POWER
+
+ if (!NT_SUCCESS(Status)) {
+
+#ifdef ISN_NT
+ ObDereferenceObject (FileObject);
+#endif
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+ return Status;
+ }
+
+ NB_DEBUG2 (CONNECTION, ("Associate connection %lx with address file %lx\n",
+ Connection, AddressFile));
+
+
+ //
+ // Now insert the connection into the database of the address.
+ //
+
+ Address = AddressFile->Address;
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (Connection->AddressFile != NULL) {
+
+ //
+ // The connection is already associated with
+ // an address file.
+ //
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ Status = STATUS_INVALID_CONNECTION;
+
+ } else {
+
+ if (AddressFile->State == ADDRESSFILE_STATE_OPEN) {
+
+ Connection->AddressFile = AddressFile;
+ Connection->AddressFileLinked = TRUE;
+ InsertHeadList (&AddressFile->ConnectionDatabase, &Connection->AddressFileLinkage);
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ NbiTransferReferenceAddressFile (AddressFile, AFREF_VERIFY, AFREF_CONNECTION);
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ Status = STATUS_INVALID_ADDRESS;
+ }
+
+ }
+
+#ifdef ISN_NT
+
+ //
+ // We don't need the reference to the file object, we just
+ // used it to get from the handle to the object.
+ //
+
+ ObDereferenceObject (FileObject);
+
+#endif
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiAssociateAddress */
+
+
+NTSTATUS
+NbiTdiDisassociateAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the disassociation of the connection
+ and the address for the user.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the associate.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ NTSTATUS Status;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ CTELockHandle LockHandle;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ NB_DEBUG2 (CONNECTION, ("Disassociate connection %lx\n", Connection));
+
+
+ //
+ // First check if the connection is still active.
+ //
+
+ NB_BEGIN_SYNC (&SyncContext);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ if (Connection->State != CONNECTION_STATE_INACTIVE) {
+
+ //
+ // This releases the lock.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_INVALID_ADDRESS
+ NB_LOCK_HANDLE_ARG (LockHandle1));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ }
+
+ //
+ // BUGBUG: Keep the sync through the function??
+ //
+
+ NB_END_SYNC (&SyncContext);
+
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ //
+ // Make sure the connection is associated and is not in the
+ // middle of disassociating.
+ //
+
+ if ((Connection->AddressFile != NULL) &&
+ (Connection->AddressFile != (PVOID)-1) &&
+ (Connection->DisassociatePending == NULL)) {
+
+ if (Connection->ReferenceCount == 0) {
+
+ //
+ // Because the connection still has a reference to
+ // the address file, we know it is still valid. We
+ // set the connection address file to the temporary
+ // value of -1, which prevents somebody else from
+ // disassociating it and also prevents a new association.
+ //
+
+ AddressFile = Connection->AddressFile;
+ Connection->AddressFile = (PVOID)-1;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ Address = AddressFile->Address;
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (Connection->AddressFileLinked) {
+ Connection->AddressFileLinked = FALSE;
+ RemoveEntryList (&Connection->AddressFileLinkage);
+ }
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ Connection->AddressFile = NULL;
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ //
+ // Set this so when the count goes to 0 it will
+ // be disassociated and the request completed.
+ //
+
+ Connection->DisassociatePending = Request;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ Status = STATUS_PENDING;
+
+ }
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiDisassociateAddress */
+
+
+NTSTATUS
+NbiTdiListen(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine posts a listen on a connection.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the listen.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1, LockHandle2;
+ CTELockHandle CancelLH;
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ //
+ // The connection must be inactive, but associated and
+ // with no disassociate or close pending.
+ //
+
+ if ((Connection->State == CONNECTION_STATE_INACTIVE) &&
+ (Connection->AddressFile != NULL) &&
+ (Connection->AddressFile != (PVOID)-1) &&
+ (Connection->DisassociatePending == NULL) &&
+ (Connection->ClosePending == NULL)) {
+
+ Connection->State = CONNECTION_STATE_LISTENING;
+ Connection->SubState = CONNECTION_SUBSTATE_L_WAITING;
+
+ (VOID)NbiAssignConnectionId (Device, Connection); // BUGBUG: Check return code.
+
+
+ if (!Request->Cancel) {
+
+ NB_DEBUG2 (CONNECTION, ("Queued listen %lx on %lx\n", Request, Connection));
+ InsertTailList (&Device->ListenQueue, REQUEST_LINKAGE(Request));
+ IoSetCancelRoutine (Request, NbiCancelListen);
+ Connection->ListenRequest = Request;
+ NbiReferenceConnectionLock (Connection, CREF_LISTEN);
+ Status = STATUS_PENDING;
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled listen %lx on %lx\n", Request, Connection));
+ Connection->State = CONNECTION_STATE_INACTIVE;
+ Status = STATUS_CANCELLED;
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiListen */
+
+
+NTSTATUS
+NbiTdiAccept(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine accepts a connection to a remote machine. The
+ connection must previously have completed a listen with
+ the TDI_QUERY_ACCEPT flag on.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the accept.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1, LockHandle2;
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if ((Connection->State == CONNECTION_STATE_LISTENING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_L_W_ACCEPT)) {
+
+ Connection->SubState = CONNECTION_SUBSTATE_L_W_ROUTE;
+
+ NbiTransferReferenceConnection (Connection, CREF_W_ACCEPT, CREF_ACCEPT);
+ Connection->AcceptRequest = Request;
+
+ NbiReferenceConnectionLock (Connection, CREF_FIND_ROUTE);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network =
+ *(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,Connection->RemoteHeader.DestinationNode,6);
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_NO_RIP;
+
+ //
+ // When this completes, we will send the session init
+ // ack. We don't call it if the client is for network 0,
+ // instead just fake as if no route could be found
+ // and we will use the local target we got here.
+ // The accept is completed when this completes.
+ //
+
+ if (*(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork != 0) {
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ } else {
+
+ NbiFindRouteComplete(
+ &Connection->FindRouteRequest,
+ FALSE);
+
+ }
+
+ NB_DEBUG2 (CONNECTION, ("Accept received on %lx\n", Connection));
+
+ Status = STATUS_PENDING;
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Accept received on invalid connection %lx\n", Connection));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiAccept */
+
+
+NTSTATUS
+NbiTdiConnect(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine connects to a remote machine.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the connect.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteName;
+ PTDI_REQUEST_KERNEL_CONNECT Parameters;
+#if 0
+ PLARGE_INTEGER RequestedTimeout;
+ LARGE_INTEGER RealTimeout;
+#endif
+ PNETBIOS_CACHE CacheName;
+ CTELockHandle LockHandle1, LockHandle2;
+ CTELockHandle CancelLH;
+ BOOLEAN bLockFreed = FALSE;
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ //
+ // The connection must be inactive, but associated and
+ // with no disassociate or close pending.
+ //
+
+ if ((Connection->State == CONNECTION_STATE_INACTIVE) &&
+ (Connection->AddressFile != NULL) &&
+ (Connection->AddressFile != (PVOID)-1) &&
+ (Connection->DisassociatePending == NULL) &&
+ (Connection->ClosePending == NULL)) {
+
+ Parameters = (PTDI_REQUEST_KERNEL_CONNECT)REQUEST_PARAMETERS(Request);
+ RemoteName = NbiParseTdiAddress((PTRANSPORT_ADDRESS)(Parameters->RequestConnectionInformation->RemoteAddress), FALSE);
+
+ if (RemoteName == NULL) {
+
+ //
+ // There is no netbios remote address specified.
+ //
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ Status = STATUS_BAD_NETWORK_PATH;
+
+ } else {
+
+ NbiReferenceConnectionLock (Connection, CREF_CONNECT);
+ Connection->State = CONNECTION_STATE_CONNECTING;
+ RtlCopyMemory (Connection->RemoteName, RemoteName->NetbiosName, 16);
+
+ Connection->Retries = Device->ConnectionCount;
+
+ (VOID)NbiAssignConnectionId (Device, Connection); // BUGBUG: Check return code.
+
+ Status = NbiTdiConnectFindName(
+ Device,
+ Request,
+ Connection,
+ CancelLH,
+ LockHandle1,
+ LockHandle2,
+ &bLockFreed);
+
+ }
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Connect on invalid connection %lx\n", Connection));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ if (!bLockFreed) {
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ }
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiConnect */
+
+
+NTSTATUS
+NbiTdiConnectFindName(
+ IN PDEVICE Device,
+ IN PREQUEST Request,
+ IN PCONNECTION Connection,
+ IN CTELockHandle CancelLH,
+ IN CTELockHandle ConnectionLH,
+ IN CTELockHandle DeviceLH,
+ IN PBOOLEAN pbLockFreed
+ )
+{
+ NTSTATUS Status;
+ PNETBIOS_CACHE CacheName;
+
+ //
+ // See what is up with this Netbios name.
+ //
+
+ Status = CacheFindName(
+ Device,
+ FindNameConnect,
+ Connection->RemoteName,
+ &CacheName);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A request for routes to this name has been
+ // sent out on the net, we queue up this connect
+ // request and processing will be resumed when
+ // we get a response.
+ //
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_FIND_NAME;
+
+
+ if (!Request->Cancel) {
+
+ InsertTailList( &Device->WaitingConnects, REQUEST_LINKAGE(Request));
+ IoSetCancelRoutine (Request, NbiCancelConnectFindName);
+ Connection->ConnectRequest = Request;
+ NbiReferenceConnectionLock (Connection, CREF_WAIT_CACHE);
+ NB_DEBUG2 (CONNECTION, ("Queueing up connect %lx on %lx\n",
+ Request, Connection));
+
+ NB_FREE_LOCK (&Device->Lock, DeviceLH);
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled connect %lx on %lx\n", Request, Connection));
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ NB_FREE_LOCK (&Device->Lock, DeviceLH);
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ Status = STATUS_CANCELLED;
+ }
+
+ } else if (Status == STATUS_SUCCESS) {
+
+ //
+ // We don't need to worry about referencing CacheName
+ // because we stop using it before we release the lock.
+ //
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_W_ROUTE;
+
+
+ if (!Request->Cancel) {
+
+ IoSetCancelRoutine (Request, NbiCancelConnectWaitResponse);
+
+ // we dont need to hold CancelSpinLock so release it,
+ // since we are releasing the locks out of order, we must
+ // swap the irql to get the priorities right.
+
+ NB_SWAP_IRQL( CancelLH, ConnectionLH);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ Connection->LocalTarget = CacheName->Networks[0].LocalTarget;
+ RtlCopyMemory(&Connection->RemoteHeader.DestinationNetwork, &CacheName->FirstResponse, 12);
+
+ Connection->ConnectRequest = Request;
+ NbiReferenceConnectionLock (Connection, CREF_FIND_ROUTE);
+
+ NB_DEBUG2 (CONNECTION, ("Found connect cached %lx on %lx\n",
+ Request, Connection));
+
+ NB_FREE_LOCK (&Device->Lock, DeviceLH);
+ NB_FREE_LOCK (&Connection->Lock, ConnectionLH);
+
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network = CacheName->FirstResponse.NetworkAddress;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,CacheName->FirstResponse.NodeAddress,6);
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_RIP_IF_NEEDED;
+
+ //
+ // When this completes, we will send the session init.
+ // We don't call it if the client is for network 0,
+ // instead just fake as if no route could be found
+ // and we will use the local target we got here.
+ //
+
+ if (CacheName->FirstResponse.NetworkAddress != 0) {
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ } else {
+
+ NbiFindRouteComplete(
+ &Connection->FindRouteRequest,
+ FALSE);
+
+ }
+
+ Status = STATUS_PENDING;
+
+ //
+ // This jump is like falling out of the if, except
+ // it skips over freeing the connection lock since
+ // we just did that.
+ //
+
+ *pbLockFreed = TRUE;
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled connect %lx on %lx\n", Request, Connection));
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+ NB_FREE_LOCK (&Device->Lock, DeviceLH);
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ Status = STATUS_CANCELLED;
+ }
+
+ } else {
+
+ //
+ // We could not find or queue a request for
+ // this remote, fail it. When the refcount
+ // drops the state will go to INACTIVE and
+ // the connection ID will be deassigned.
+ //
+
+ if (Status == STATUS_DEVICE_DOES_NOT_EXIST) {
+ Status = STATUS_BAD_NETWORK_PATH;
+ }
+
+ NB_FREE_LOCK (&Device->Lock, DeviceLH);
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+ }
+
+ return Status;
+} /* NbiTdiConnectFindName */
+
+
+NTSTATUS
+NbiTdiDisconnect(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine connects to a remote machine.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the connect.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+ BOOLEAN DisconnectWait;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+ NB_DEFINE_LOCK_HANDLE (LockHandle2)
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+ CTELockHandle CancelLH;
+
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ DisconnectWait = (BOOLEAN)
+ ((((PTDI_REQUEST_KERNEL_DISCONNECT)(REQUEST_PARAMETERS(Request)))->RequestFlags &
+ TDI_DISCONNECT_WAIT) != 0);
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+
+ //
+ // We need to be inside a sync because NbiStopConnection
+ // expects that.
+ //
+
+ NB_BEGIN_SYNC (&SyncContext);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if (DisconnectWait) {
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ //
+ // This disconnect wait will get completed by
+ // NbiStopConnection.
+ //
+
+ if (Connection->DisconnectWaitRequest == NULL) {
+
+
+ if (!Request->Cancel) {
+
+ IoSetCancelRoutine (Request, NbiCancelDisconnectWait);
+ NB_DEBUG2 (CONNECTION, ("Disconnect wait queued on connection %lx\n", Connection));
+ Connection->DisconnectWaitRequest = Request;
+ Status = STATUS_PENDING;
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled disconnect wait on connection %lx\n", Connection));
+ Status = STATUS_CANCELLED;
+ }
+
+ } else {
+
+ //
+ // We got a second disconnect request and we already
+ // have one pending.
+ //
+
+ NB_DEBUG (CONNECTION, ("Disconnect wait failed, already queued on connection %lx\n", Connection));
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ } else if (Connection->State == CONNECTION_STATE_DISCONNECT) {
+
+ NB_DEBUG (CONNECTION, ("Disconnect wait submitted on disconnected connection %lx\n", Connection));
+ Status = Connection->Status;
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Disconnect wait failed, bad state on connection %lx\n", Connection));
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ } else {
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ // we dont need to hold CancelSpinLock so release it,
+ // since we are releasing the locks out of order, we must
+ // swap the irql to get the priorities right.
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ Connection->DisconnectRequest = Request;
+ Status = STATUS_PENDING;
+
+ NB_DEBUG2 (CONNECTION, ("Disconnect of active connection %lx\n", Connection));
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+
+ //
+ // This call releases the connection lock, sets
+ // the state to DISCONNECTING, and sends out
+ // the first session end.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_LOCAL_DISCONNECT
+ NB_LOCK_HANDLE_ARG (LockHandle1));
+
+ } else if (Connection->State == CONNECTION_STATE_DISCONNECT) {
+
+ //
+ // There is already a disconnect pending. Queue
+ // this one up so it completes when the refcount
+ // goes to zero.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Disconnect of disconnecting connection %lx\n", Connection));
+
+ if (Connection->DisconnectRequest == NULL) {
+ Connection->DisconnectRequest = Request;
+ Status = STATUS_PENDING;
+ } else {
+ Status = STATUS_SUCCESS;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ } else if ((Connection->State == CONNECTION_STATE_LISTENING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_L_W_ACCEPT)) {
+
+ //
+ // We were waiting for an accept, but instead we got
+ // a disconnect. Remove the reference and the teardown
+ // will proceed. The disconnect will complete when the
+ // refcount goes to zero.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Disconnect of accept pending connection %lx\n", Connection));
+
+ if (Connection->DisconnectRequest == NULL) {
+ Connection->DisconnectRequest = Request;
+ Status = STATUS_PENDING;
+ } else {
+ Status = STATUS_SUCCESS;
+ }
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiDereferenceConnection (Connection, CREF_W_ACCEPT);
+
+ } else if (Connection->State == CONNECTION_STATE_CONNECTING) {
+
+ // we dont need to hold CancelSpinLock so release it,
+ // since we are releasing the locks out of order, we must
+ // swap the irql to get the priorities right.
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ //
+ // We are connecting, and got a disconnect. We call
+ // NbiStopConnection which will handle this case
+ // and abort the connect.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Disconnect of connecting connection %lx\n", Connection));
+
+ if (Connection->DisconnectRequest == NULL) {
+ Connection->DisconnectRequest = Request;
+ Status = STATUS_PENDING;
+ } else {
+ Status = STATUS_SUCCESS;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ //
+ // This call releases the connection lock and
+ // aborts the connect request.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_LOCAL_DISCONNECT
+ NB_LOCK_HANDLE_ARG (LockHandle1));
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Disconnect of invalid connection (%d) %lx\n",
+ Connection->State, Connection));
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ }
+
+ NB_END_SYNC (&SyncContext);
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiDisconnect */
+
+
+BOOLEAN
+NbiAssignConnectionId(
+ IN PDEVICE Device,
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to assign a connection ID. It picks
+ one whose hash table has the fewest entries.
+
+ THIS ROUTINE IS CALLED WITH THE LOCK HELD AND RETURNS WITH
+ IT HELD. THE CONNECTION IS INSERTED INTO THE CORRECT HASH
+ ENTRY BY THIS CALL.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Connection - The connection that needs an ID assigned.
+
+Return Value:
+
+ TRUE if it could be successfully assigned.
+
+--*/
+
+{
+ UINT Hash;
+ UINT i;
+ USHORT ConnectionId, HashId;
+ PCONNECTION CurConnection;
+
+
+ CTEAssert (Connection->LocalConnectionId == 0xffff);
+
+ //
+ // Find the hash bucket with the fewest entries.
+ //
+
+ Hash = 0;
+ for (i = 1; i < CONNECTION_HASH_COUNT; i++) {
+ if (Device->ConnectionHash[i].ConnectionCount < Device->ConnectionHash[Hash].ConnectionCount) {
+ Hash = i;
+ }
+ }
+
+
+ //
+ // Now find a valid connection ID within that bucket.
+ //
+
+ ConnectionId = Device->ConnectionHash[Hash].NextConnectionId;
+
+ while (TRUE) {
+
+ //
+ // Scan through the list to see if this ID is in use.
+ //
+
+ HashId = (USHORT)(ConnectionId | (Hash << CONNECTION_HASH_SHIFT));
+
+ CurConnection = Device->ConnectionHash[Hash].Connections;
+
+ while (CurConnection != NULL) {
+ if (CurConnection->LocalConnectionId != HashId) {
+ CurConnection = CurConnection->NextConnection;
+ } else {
+ break;
+ }
+ }
+
+ if (CurConnection == NULL) {
+ break;
+ }
+
+ if (ConnectionId >= CONNECTION_MAXIMUM_ID) {
+ ConnectionId = 1;
+ } else {
+ ++ConnectionId;
+ }
+
+ //
+ // BUGBUG: What if we have 64K-1 sessions and loop forever?
+ //
+ }
+
+ if (Device->ConnectionHash[Hash].NextConnectionId >= CONNECTION_MAXIMUM_ID) {
+ Device->ConnectionHash[Hash].NextConnectionId = 1;
+ } else {
+ ++Device->ConnectionHash[Hash].NextConnectionId;
+ }
+
+ Connection->LocalConnectionId = HashId;
+ Connection->RemoteConnectionId = 0xffff;
+ NB_DEBUG2 (CONNECTION, ("Assigned ID %lx to %x\n", Connection->LocalConnectionId, Connection));
+
+ Connection->NextConnection = Device->ConnectionHash[Hash].Connections;
+ Device->ConnectionHash[Hash].Connections = Connection;
+ ++Device->ConnectionHash[Hash].ConnectionCount;
+
+ return TRUE;
+
+} /* NbiAssignConnectionId */
+
+
+VOID
+NbiDeassignConnectionId(
+ IN PDEVICE Device,
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to deassign a connection ID. It removes
+ the connection from the hash bucket for its ID.
+
+ THIS ROUTINE IS CALLED WITH THE LOCK HELD AND RETURNS WITH
+ IT HELD.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Connection - The connection that needs an ID assigned.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT Hash;
+ PCONNECTION CurConnection;
+ PCONNECTION * PrevConnection;
+
+ //
+ // Make sure the connection has a valid ID.
+ //
+
+ CTEAssert (Connection->LocalConnectionId != 0xffff);
+
+ Hash = (Connection->LocalConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
+
+ CurConnection = Device->ConnectionHash[Hash].Connections;
+ PrevConnection = &Device->ConnectionHash[Hash].Connections;
+
+ while (TRUE) {
+
+ CTEAssert (CurConnection != NULL);
+
+ //
+ // We can loop until we find it because it should be
+ // on here.
+ //
+
+ if (CurConnection == Connection) {
+ *PrevConnection = Connection->NextConnection;
+ --Device->ConnectionHash[Hash].ConnectionCount;
+ break;
+ }
+
+ PrevConnection = &CurConnection->NextConnection;
+ CurConnection = CurConnection->NextConnection;
+
+ }
+
+ Connection->LocalConnectionId = 0xffff;
+
+} /* NbiDeassignConnectionId */
+
+
+VOID
+NbiConnectionTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the connection timer expires.
+ This is either because we need to send the next session
+ initialize, or because our listen has timed out.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCONNECTION Connection = (PCONNECTION)Context;
+ PDEVICE Device = NbiDevice;
+ PREQUEST Request;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_LOCK_HANDLE (CancelLH)
+
+ //
+ // Take the lock and see what we need to do.
+ //
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN)) {
+
+ if (--Connection->Retries == 0) {
+
+ NB_DEBUG2 (CONNECTION, ("Timing out session initializes on %lx\n", Connection));
+
+ //
+ // We have just timed out this connect, we fail the
+ // request. When the reference count goes to 0 we
+ // will set the state to INACTIVE and deassign
+ // the connection ID.
+ //
+
+ Request = Connection->ConnectRequest;
+ Connection->ConnectRequest = NULL;
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ REQUEST_STATUS (Request) = STATUS_BAD_NETWORK_PATH;
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+
+ } else {
+
+ //
+ // Send the next session initialize.
+ //
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NbiSendSessionInitialize (Connection);
+
+ CTEStartTimer(
+ &Connection->Timer,
+ Device->ConnectionTimeout,
+ NbiConnectionTimeout,
+ (PVOID)Connection);
+
+ }
+
+ } else if (Connection->State == CONNECTION_STATE_DISCONNECT) {
+
+ if ((Connection->SubState != CONNECTION_SUBSTATE_D_W_ACK) ||
+ (--Connection->Retries == 0)) {
+
+ NB_DEBUG2 (CONNECTION, ("Timing out disconnect of %lx\n", Connection));
+
+ //
+ // Just dereference the connection, that will cause the
+ // disconnect to be completed, the state to be set
+ // to INACTIVE, and our connection ID deassigned.
+ //
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+
+ } else {
+
+ //
+ // Send the next session end.
+ //
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NbiSendSessionEnd(Connection);
+
+ CTEStartTimer(
+ &Connection->Timer,
+ Device->ConnectionTimeout,
+ NbiConnectionTimeout,
+ (PVOID)Connection);
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+
+ }
+
+} /* NbiConnectionTimeout */
+
+
+VOID
+NbiCancelListen(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a posted
+ listen.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1, LockHandle2;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PREQUEST Request = (PREQUEST)Irp;
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_LISTEN));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ if ((Connection->State == CONNECTION_STATE_LISTENING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_L_WAITING) &&
+ (Connection->ListenRequest == Request)) {
+
+ //
+ // When the reference count goes to 0, we will set the
+ // state to INACTIVE and deassign the connection ID.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled listen on %lx\n", Connection));
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+ Connection->ListenRequest = NULL;
+ RemoveEntryList (REQUEST_LINKAGE(Request));
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest(Device, Request);
+
+ NbiDereferenceConnection (Connection, CREF_LISTEN);
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Cancel listen on invalid connection %lx\n", Connection));
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ }
+
+} /* NbiCancelListen */
+
+
+VOID
+NbiCancelConnectFindName(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a connect
+ request which is waiting for the name to be found.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1, LockHandle2;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PREQUEST Request = (PREQUEST)Irp;
+ PLIST_ENTRY p;
+ BOOLEAN fCanceled = TRUE;
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_CONNECT));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_C_FIND_NAME) &&
+ (Connection->ConnectRequest == Request)) {
+
+ //
+ // Make sure the request is still on the queue
+ // before cancelling it.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ for (p = Device->WaitingConnects.Flink;
+ p != &Device->WaitingConnects;
+ p = p->Flink) {
+
+ if (LIST_ENTRY_TO_REQUEST(p) == Request) {
+ break;
+ }
+ }
+
+ if (p != &Device->WaitingConnects) {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled find name connect on %lx\n", Connection));
+
+ //
+ // When the reference count goes to 0, we will set the
+ // state to INACTIVE and deassign the connection ID.
+ //
+
+ Connection->ConnectRequest = NULL;
+ RemoveEntryList (REQUEST_LINKAGE(Request));
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+#ifdef RASAUTODIAL
+ if (Connection->Flags & CONNECTION_FLAGS_AUTOCONNECTING)
+ fCanceled = NbiCancelTdiConnect(Device, Request, Connection);
+#endif // RASAUTODIAL
+
+ if (fCanceled) {
+ NbiCompleteRequest (Request);
+ NbiFreeRequest(Device, Request);
+ }
+
+ NbiDereferenceConnection (Connection, CREF_WAIT_CACHE);
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Cancel connect not found on queue %lx\n", Connection));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ }
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Cancel connect on invalid connection %lx\n", Connection));
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ }
+
+} /* NbiCancelConnectFindName */
+
+
+VOID
+NbiCancelConnectWaitResponse(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a connect
+ request which is waiting for a rip or session init response
+ from the remote.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PREQUEST Request = (PREQUEST)Irp;
+ BOOLEAN TimerWasStopped = FALSE;
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_CONNECT));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN) &&
+ (Connection->ConnectRequest == Request)) {
+
+ //
+ // When the reference count goes to 0, we will set the
+ // state to INACTIVE and deassign the connection ID.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled wait response connect on %lx\n", Connection));
+
+ Connection->ConnectRequest = NULL;
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ if (CTEStopTimer (&Connection->Timer)) {
+ TimerWasStopped = TRUE;
+ }
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest(Device, Request);
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ if (TimerWasStopped) {
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+ }
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Cancel connect on invalid connection %lx\n", Connection));
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ }
+
+} /* NbiCancelConnectWaitResponse */
+
+
+VOID
+NbiCancelDisconnectWait(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a posted
+ disconnect wait.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1, LockHandle2;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PREQUEST Request = (PREQUEST)Irp;
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_DISCONNECT));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if (Connection->DisconnectWaitRequest == Request) {
+
+ Connection->DisconnectWaitRequest = NULL;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest(Device, Request);
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ }
+
+} /* NbiCancelDisconnectWait */
+
+
+PCONNECTION
+NbiLookupConnectionByContext(
+ IN PADDRESS_FILE AddressFile,
+ IN CONNECTION_CONTEXT ConnectionContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine looks up a connection based on the context.
+ The connection is assumed to be associated with the
+ specified address file.
+
+Arguments:
+
+ AddressFile - Pointer to an address file.
+
+ ConnectionContext - Connection context to find.
+
+Return Value:
+
+ A pointer to the connection we found
+
+--*/
+
+{
+ CTELockHandle LockHandle1, LockHandle2;
+ PLIST_ENTRY p;
+ PADDRESS Address = AddressFile->Address;
+ PCONNECTION Connection;
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle1);
+
+ for (p=AddressFile->ConnectionDatabase.Flink;
+ p != &AddressFile->ConnectionDatabase;
+ p=p->Flink) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, AddressFileLinkage);
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle2);
+
+ //
+ // BUGBUG: Does this spinlock ordering hurt us
+ // somewhere else?
+ //
+
+ if (Connection->Context == ConnectionContext) {
+
+ NbiReferenceConnection (Connection, CREF_BY_CONTEXT);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle2);
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+
+ return Connection;
+ }
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle2);
+
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+
+ return NULL;
+
+} /* NbiLookupConnectionByContext */
+
+
+PCONNECTION
+NbiCreateConnection(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a transport connection and associates it with
+ the specified transport device context. The reference count in the
+ connection is automatically set to 1, and the reference count of the
+ device context is incremented.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ connection.
+
+Return Value:
+
+ The newly created connection, or NULL if none can be allocated.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PNB_SEND_RESERVED SendReserved;
+ ULONG ConnectionSize;
+ ULONG HeaderLength;
+ NTSTATUS Status;
+ CTELockHandle LockHandle;
+
+ HeaderLength = Device->Bind.MacHeaderNeeded + sizeof(NB_CONNECTION);
+ ConnectionSize = FIELD_OFFSET (CONNECTION, SendPacketHeader[0]) + HeaderLength;
+
+ Connection = (PCONNECTION)NbiAllocateMemory (ConnectionSize, MEMORY_CONNECTION, "Connection");
+ if (Connection == NULL) {
+ NB_DEBUG (CONNECTION, ("Create connection failed\n"));
+ return NULL;
+ }
+
+ NB_DEBUG2 (CONNECTION, ("Create connection %lx\n", Connection));
+ RtlZeroMemory (Connection, ConnectionSize);
+
+
+#if defined(NB_OWN_PACKETS)
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (NbiInitializeSendPacket(
+ Device,
+ Connection->SendPacketPoolHandle,
+ &Connection->SendPacket,
+ Connection->SendPacketHeader,
+ HeaderLength) != STATUS_SUCCESS) {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ NB_DEBUG (CONNECTION, ("Could not initialize connection packet %lx\n", &Connection->SendPacket));
+ Connection->SendPacketInUse = TRUE;
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ SendReserved = SEND_RESERVED(&Connection->SendPacket);
+ SendReserved->u.SR_CO.Connection = Connection;
+ SendReserved->OwnedByConnection = TRUE;
+#ifdef NB_TRACK_POOL
+ SendReserved->Pool = NULL;
+#endif
+ }
+
+#else // !NB_OWN_PACKETS
+
+ //
+ // if we are using ndis packets, first create packet pool for 1 packet descriptor
+ //
+ NdisAllocatePacketPool( &Status, &Connection->SendPacketPoolHandle, 1, sizeof(NB_SEND_RESERVED));
+ if (!NT_SUCCESS(Status)){
+ NB_DEBUG (CONNECTION, ("Could not allocatee connection packet %lx\n", Status));
+ Connection->SendPacketInUse = TRUE;
+ } else {
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (NbiInitializeSendPacket(
+ Device,
+ Connection->SendPacketPoolHandle,
+ &Connection->SendPacket,
+ Connection->SendPacketHeader,
+ HeaderLength) != STATUS_SUCCESS) {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ NB_DEBUG (CONNECTION, ("Could not initialize connection packet %lx\n", &Connection->SendPacket));
+ Connection->SendPacketInUse = TRUE;
+
+ //
+ // Also free up the pool which we allocated above.
+ //
+ NdisFreePacketPool(Connection->SendPacketPoolHandle);
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ SendReserved = SEND_RESERVED(&Connection->SendPacket);
+ SendReserved->u.SR_CO.Connection = Connection;
+ SendReserved->OwnedByConnection = TRUE;
+#ifdef NB_TRACK_POOL
+ SendReserved->Pool = NULL;
+#endif
+ }
+ }
+
+#endif NB_OWN_PACKETS
+
+ Connection->Type = NB_CONNECTION_SIGNATURE;
+ Connection->Size = (USHORT)ConnectionSize;
+
+#if 0
+ Connection->AddressFileLinked = FALSE;
+ Connection->AddressFile = NULL;
+#endif
+
+ Connection->State = CONNECTION_STATE_INACTIVE;
+#if 0
+ Connection->SubState = 0;
+ Connection->ReferenceCount = 0;
+#endif
+
+ Connection->CanBeDestroyed = TRUE;
+
+ Connection->TickCount = 1;
+ Connection->HopCount = 1;
+
+ //
+ // Device->InitialRetransmissionTime is in milliseconds, as is
+ // SHORT_TIMER_DELTA.
+ //
+
+ Connection->BaseRetransmitTimeout = Device->InitialRetransmissionTime / SHORT_TIMER_DELTA;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+
+ //
+ // Device->KeepAliveTimeout is in half-seconds, while LONG_TIMER_DELTA
+ // is in milliseconds.
+ //
+
+ Connection->WatchdogTimeout = (Device->KeepAliveTimeout * 500) / LONG_TIMER_DELTA;
+
+
+ Connection->LocalConnectionId = 0xffff;
+
+ //
+ // When the connection becomes active we will replace the
+ // destination address of this header with the correct
+ // information.
+ //
+
+ RtlCopyMemory(&Connection->RemoteHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+
+ Connection->Device = Device;
+ Connection->DeviceLock = &Device->Lock;
+ CTEInitLock (&Connection->Lock.Lock);
+
+ CTEInitTimer (&Connection->Timer);
+
+ InitializeListHead (&Connection->NdisSendQueue);
+#if 0
+ Connection->NdisSendsInProgress = 0;
+ Connection->DisassociatePending = NULL;
+ Connection->ClosePending = NULL;
+ Connection->SessionInitAckData = NULL;
+ Connection->SessionInitAckDataLength = 0;
+ Connection->PiggybackAckTimeout = FALSE;
+ Connection->ReceivesWithoutAck = 0;
+#endif
+ Connection->Flags = 0;
+
+ NbiReferenceDevice (Device, DREF_CONNECTION);
+
+ return Connection;
+
+} /* NbiCreateConnection */
+
+
+NTSTATUS
+NbiVerifyConnection (
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to verify that the pointer given us in a file
+ object is in fact a valid connection object. We reference
+ it to keep it from disappearing while we use it.
+
+Arguments:
+
+ Connection - potential pointer to a CONNECTION object
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_CONNECTION otherwise
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ NTSTATUS status = STATUS_SUCCESS;
+ PDEVICE Device = NbiDevice;
+ BOOLEAN LockHeld = FALSE;
+
+ try {
+
+ if ((Connection->Size == FIELD_OFFSET (CONNECTION, SendPacketHeader[0]) +
+ NbiDevice->Bind.MacHeaderNeeded + sizeof(NB_CONNECTION)) &&
+ (Connection->Type == NB_CONNECTION_SIGNATURE)) {
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ LockHeld = TRUE;
+
+ if (Connection->State != CONNECTION_STATE_CLOSING) {
+
+ NbiReferenceConnectionLock (Connection, CREF_VERIFY);
+
+ } else {
+
+ NbiPrint1("NbiVerifyConnection: C %lx closing\n", Connection);
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ } else {
+
+ NbiPrint1("NbiVerifyConnection: C %lx bad signature\n", Connection);
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ NbiPrint1("NbiVerifyConnection: C %lx exception\n", Connection);
+ if (LockHeld) {
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+ return GetExceptionCode();
+ }
+
+ return status;
+
+} /* NbiVerifyConnection */
+
+
+VOID
+NbiDestroyConnection(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a transport connection and removes all references
+ made by it to other objects in the transport. The connection structure
+ is returned to nonpaged system pool.
+
+Arguments:
+
+ Connection - Pointer to a transport connection structure to be destroyed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = Connection->Device;
+#if 0
+ CTELockHandle LockHandle;
+#endif
+
+ NB_DEBUG2 (CONNECTION, ("Destroy connection %lx\n", Connection));
+
+ if (!Connection->SendPacketInUse) {
+ NbiDeinitializeSendPacket (Device, &Connection->SendPacket, Device->Bind.MacHeaderNeeded + sizeof(NB_CONNECTION));
+#if !defined(NB_OWN_PACKETS)
+ NdisFreePacketPool(Connection->SendPacketPoolHandle);
+#endif
+ }
+
+ NbiFreeMemory (Connection, (ULONG)Connection->Size, MEMORY_CONNECTION, "Connection");
+
+ NbiDereferenceDevice (Device, DREF_CONNECTION);
+
+} /* NbiDestroyConnection */
+
+
+#if DBG
+VOID
+NbiRefConnection(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ (VOID)ExInterlockedAddUlong (
+ &Connection->ReferenceCount,
+ 1,
+ &Connection->DeviceLock->Lock);
+
+ Connection->CanBeDestroyed = FALSE;
+
+ CTEAssert (Connection->ReferenceCount > 0);
+
+} /* NbiRefConnection */
+
+
+VOID
+NbiRefConnectionLock(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport connection
+ when the device lock is already held.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ ++Connection->ReferenceCount;
+ Connection->CanBeDestroyed = FALSE;
+
+ CTEAssert (Connection->ReferenceCount > 0);
+
+} /* NbiRefConnectionLock */
+
+
+VOID
+NbiRefConnectionSync(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport connection
+ when we are in a sync routine.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ (VOID)NB_ADD_ULONG (
+ &Connection->ReferenceCount,
+ 1,
+ Connection->DeviceLock);
+
+ Connection->CanBeDestroyed = FALSE;
+
+ CTEAssert (Connection->ReferenceCount > 0);
+
+} /* NbiRefConnectionSync */
+
+
+VOID
+NbiDerefConnection(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport connection by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ NbiHandleConnectionZero to complete any disconnect, disassociate,
+ or close requests that have pended on the connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+ CTELockHandle LockHandle;
+
+ NB_GET_LOCK( Connection->DeviceLock, &LockHandle );
+ CTEAssert( Connection->ReferenceCount );
+ if ( !(--Connection->ReferenceCount) ) {
+
+ Connection->ThreadsInHandleConnectionZero++;
+
+ NB_FREE_LOCK( Connection->DeviceLock, LockHandle );
+
+ //
+ // If the refcount has dropped to 0, then the connection can
+ // become inactive. We reacquire the spinlock and if it has not
+ // jumped back up then we handle any disassociates and closes
+ // that have pended.
+ //
+
+ NbiHandleConnectionZero (Connection);
+ } else {
+
+ NB_FREE_LOCK( Connection->DeviceLock, LockHandle );
+ }
+
+
+} /* NbiDerefConnection */
+
+
+#endif
+
+
+VOID
+NbiHandleConnectionZero(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles a connection's refcount going to 0.
+
+ BUGBUG: If two threads are in this at the same time and
+ the close has already come through, one of them might
+ destroy the connection while the other one is looking
+ at it. We minimize the chance of this by not derefing
+ the connection after calling CloseConnection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PDEVICE Device;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PREQUEST DisconnectPending;
+ PREQUEST DisassociatePending;
+ PREQUEST ClosePending;
+
+
+ Device = Connection->Device;
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+#if DBG
+ //
+ // Make sure if our reference count is zero, all the
+ // sub-reference counts are also zero.
+ //
+
+ if (Connection->ReferenceCount == 0) {
+
+ UINT i;
+ for (i = 0; i < CREF_TOTAL; i++) {
+ if (Connection->RefTypes[i] != 0) {
+ DbgPrint ("NBI: Connection reftype mismatch on %lx\n", Connection);
+ DbgBreakPoint();
+ }
+ }
+ }
+#endif
+
+ //
+ // If the connection was assigned an ID, then remove it
+ // (it is assigned one when it leaves INACTIVE).
+ //
+
+ if (Connection->LocalConnectionId != 0xffff) {
+ NbiDeassignConnectionId (Device, Connection);
+ }
+
+ //
+ // Complete any pending disconnects.
+ //
+
+ if (Connection->DisconnectRequest != NULL) {
+
+ DisconnectPending = Connection->DisconnectRequest;
+ Connection->DisconnectRequest = NULL;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ REQUEST_STATUS(DisconnectPending) = STATUS_SUCCESS;
+ NbiCompleteRequest (DisconnectPending);
+ NbiFreeRequest (Device, DisconnectPending);
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ }
+
+ //
+ // This should have been completed by NbiStopConnection,
+ // or else not allowed to be queued.
+ //
+
+ CTEAssert (Connection->DisconnectWaitRequest == NULL);
+
+
+ Connection->State = CONNECTION_STATE_INACTIVE;
+
+ //
+ // BUGBUG: Make NbiInitializeConnection() to take care of all this.
+ //
+
+ RtlZeroMemory (&Connection->ConnectionInfo, sizeof(TDI_CONNECTION_INFO));
+ Connection->TickCount = 1;
+ Connection->HopCount = 1;
+ Connection->BaseRetransmitTimeout = Device->InitialRetransmissionTime / SHORT_TIMER_DELTA;
+
+ Connection->ConnectionInfo.TransmittedTsdus = 0;
+ Connection->ConnectionInfo.TransmissionErrors = 0;
+ Connection->ConnectionInfo.ReceivedTsdus = 0;
+ Connection->ConnectionInfo.ReceiveErrors = 0;
+
+ //
+ // See if we need to do a disassociate now.
+ //
+
+ if ((Connection->ReferenceCount == 0) &&
+ (Connection->DisassociatePending != NULL)) {
+
+ //
+ // A disassociate pended, now we complete it.
+ //
+
+ DisassociatePending = Connection->DisassociatePending;
+ Connection->DisassociatePending = NULL;
+
+ //
+ // Set this so nobody else tries to disassociate.
+ //
+
+ AddressFile = Connection->AddressFile;
+ Connection->AddressFile = (PVOID)-1;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Take this connection out of the address file's list.
+ //
+
+ Address = AddressFile->Address;
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (Connection->AddressFileLinked) {
+ Connection->AddressFileLinked = FALSE;
+ RemoveEntryList (&Connection->AddressFileLinkage);
+ }
+
+ //
+ // We are done.
+ //
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ Connection->AddressFile = NULL;
+
+ //
+ // Clean up the reference counts and complete any
+ // disassociate requests that pended.
+ //
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
+
+ if (DisassociatePending != (PVOID)-1) {
+ REQUEST_STATUS(DisassociatePending) = STATUS_SUCCESS;
+ NbiCompleteRequest (DisassociatePending);
+ NbiFreeRequest (Device, DisassociatePending);
+ }
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+
+ //
+ // If a close was pending, complete that.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if ((Connection->ReferenceCount == 0) &&
+ (Connection->ClosePending)) {
+
+ ClosePending = Connection->ClosePending;
+ Connection->ClosePending = NULL;
+
+ //
+ // If we are associated with an address, we need
+ // to simulate a disassociate at this point.
+ //
+
+ if ((Connection->AddressFile != NULL) &&
+ (Connection->AddressFile != (PVOID)-1)) {
+
+ AddressFile = Connection->AddressFile;
+ Connection->AddressFile = (PVOID)-1;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Take this connection out of the address file's list.
+ //
+
+ Address = AddressFile->Address;
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (Connection->AddressFileLinked) {
+ Connection->AddressFileLinked = FALSE;
+ RemoveEntryList (&Connection->AddressFileLinkage);
+ }
+
+ //
+ // We are done.
+ //
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ Connection->AddressFile = NULL;
+
+ //
+ // Clean up the reference counts and complete any
+ // disassociate requests that pended.
+ //
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ //
+ // Even if the ref count is zero and we just cleaned up everything,
+ // we can not destroy the connection bcoz some other thread might still be
+ // in HandleConnectionZero routine. This could happen when 2 threads call into
+ // HandleConnectionZero, one thread runs thru completion, close comes along
+ // and the other thread is still in HandleConnectionZero routine.
+ //
+
+ CTEAssert( Connection->ThreadsInHandleConnectionZero );
+ if (ExInterlockedAddUlong ( &Connection->ThreadsInHandleConnectionZero, (ULONG)-1, &Device->Lock.Lock) == 1) {
+ NbiDestroyConnection(Connection);
+ }
+
+ REQUEST_STATUS(ClosePending) = STATUS_SUCCESS;
+ NbiCompleteRequest (ClosePending);
+ NbiFreeRequest (Device, ClosePending);
+
+ } else {
+
+ if ( Connection->ReferenceCount == 0 ) {
+ Connection->CanBeDestroyed = TRUE;
+ }
+
+ CTEAssert( Connection->ThreadsInHandleConnectionZero );
+ Connection->ThreadsInHandleConnectionZero--;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+} /* NbiHandleConnectionZero */
+
diff --git a/private/ntos/tdi/isnp/nb/datagram.c b/private/ntos/tdi/isnp/nb/datagram.c
new file mode 100644
index 000000000..e81579d1b
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/datagram.c
@@ -0,0 +1,1089 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ datagram.c
+
+Abstract:
+
+ This module contains the code to handle datagram reception
+ for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 28-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+
+VOID
+NbiProcessDatagram(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize,
+ IN BOOLEAN Broadcast
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles datagram indications.
+
+Arguments:
+
+ MacBindingHandle - A handle to use when calling NdisTransferData.
+
+ MacReceiveContext - A context to use when calling NdisTransferData.
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The lookahead buffer, starting at the IPX
+ header.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+ Broadcast - TRUE if the frame was a broadcast datagram.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PADDRESS Address;
+ NDIS_STATUS NdisStatus;
+ PUCHAR NetbiosName;
+ NB_CONNECTIONLESS UNALIGNED * Connectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)LookaheadBuffer;
+ PDEVICE Device = NbiDevice;
+ PSINGLE_LIST_ENTRY s;
+ PNB_RECEIVE_RESERVED ReceiveReserved;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ ULONG DataOffset;
+ UINT BytesTransferred;
+ PNDIS_PACKET Packet;
+ CTELockHandle LockHandle;
+
+
+ //
+ // See if there is an address that might want this.
+ //
+
+ if (Broadcast) {
+ NetbiosName = (PVOID)-1;
+ } else {
+ NetbiosName = (PUCHAR)Connectionless->Datagram.DestinationName;
+ if (Device->AddressCounts[NetbiosName[0]] == 0) {
+ return;
+ }
+ }
+
+ DataOffset = sizeof(IPX_HEADER) + sizeof(NB_DATAGRAM);
+
+#if defined(_PNP_POWER)
+ if ((PacketSize < DataOffset) ||
+ (PacketSize > DataOffset + Device->CurMaxReceiveBufferSize)) {
+#else
+ if ((PacketSize < DataOffset) ||
+ (PacketSize > DataOffset + Device->Bind.LineInfo.MaximumPacketSize)) {
+#endif _PNP_POWER
+
+ NB_DEBUG (DATAGRAM, ("Datagram length %d discarded\n", PacketSize));
+ return;
+ }
+
+ Address = NbiFindAddress (Device, NetbiosName);
+
+ if (Address == NULL) {
+ return;
+ }
+
+ //
+ // We need to cache the remote name if the packet came across the router.
+ // This allows this machine to get back to the RAS client which might
+ // have sent this datagram. We currently dont allow broadcasts to go out
+ // on the dial-in line.
+ // Dont cache some of the widely used group names, that would be too much
+ // to store in cache.
+ //
+
+#if 0
+ if ( Connectionless->IpxHeader.TransportControl &&
+ !( (Address->NetbiosAddress.NetbiosName[15] == 0x0 ) &&
+ (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) &&
+ !( (Address->NetbiosAddress.NetbiosName[15] == 0x01 ) &&
+ (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) &&
+ !( (Address->NetbiosAddress.NetbiosName[15] == 0x1E ) &&
+ (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) ) {
+#endif
+ if ( Connectionless->IpxHeader.TransportControl &&
+ ( (Address->NetbiosAddress.NetbiosName[15] == 0x1c ) &&
+ (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) ) {
+
+ PNETBIOS_CACHE CacheName;
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+ if ( FindInNetbiosCacheTable ( Device->NameCache,
+ Connectionless->Datagram.SourceName,
+ &CacheName ) != STATUS_SUCCESS ) {
+
+ CacheName = NbiAllocateMemory (sizeof(NETBIOS_CACHE), MEMORY_CACHE, "Cache Entry");
+ if (CacheName ) {
+ RtlCopyMemory (CacheName->NetbiosName, Connectionless->Datagram.SourceName, 16);
+ CacheName->Unique = TRUE;
+ CacheName->ReferenceCount = 1;
+ RtlCopyMemory (&CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12);
+ CacheName->NetworksAllocated = 1;
+ CacheName->NetworksUsed = 1;
+ CacheName->Networks[0].Network = *(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork);
+ CacheName->Networks[0].LocalTarget = *RemoteAddress;
+ NB_DEBUG2 (CACHE, ("Alloc new cache from Datagram %lx for <%.16s>\n",
+ CacheName, CacheName->NetbiosName));
+
+ CacheName->TimeStamp = Device->CacheTimeStamp;
+
+ InsertInNetbiosCacheTable(
+ Device->NameCache,
+ CacheName);
+
+ }
+ } else if ( CacheName->Unique ) {
+ //
+ // We already have an entry for this remote. We should update
+ // the address. This is so that if the ras client dials-out
+ // then dials-in again and gets a new address, we dont end up
+ // caching the old address.
+ //
+ if ( !RtlEqualMemory( &CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12) ) {
+
+ RtlCopyMemory (&CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12);
+ CacheName->Networks[0].Network = *(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork);
+ CacheName->Networks[0].LocalTarget = *RemoteAddress;
+
+ }
+ }
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+
+ //
+ // We need to allocate a packet and buffer for the transfer.
+ //
+
+ s = NbiPopReceivePacket (Device);
+ if (s == NULL) {
+ NbiDereferenceAddress (Address, AREF_FIND);
+ return;
+ }
+
+ ReceiveReserved = CONTAINING_RECORD (s, NB_RECEIVE_RESERVED, PoolLinkage);
+
+
+ s = NbiPopReceiveBuffer (Device);
+ if (s == NULL) {
+ ExInterlockedPushEntrySList(
+ &Device->ReceivePacketList,
+ &ReceiveReserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+ NbiDereferenceAddress (Address, AREF_FIND);
+ return;
+ }
+
+ ReceiveBuffer = CONTAINING_RECORD (s, NB_RECEIVE_BUFFER, PoolLinkage);
+
+ Packet = CONTAINING_RECORD (ReceiveReserved, NDIS_PACKET, ProtocolReserved[0]);
+ ReceiveReserved->u.RR_DG.ReceiveBuffer = ReceiveBuffer;
+
+
+ //
+ // Now that we have a packet and a buffer, set up the transfer.
+ // The indication to the TDI clients will happen at receive
+ // complete time.
+ //
+
+ NdisChainBufferAtFront (Packet, ReceiveBuffer->NdisBuffer);
+ ReceiveBuffer->Address = Address;
+
+ ReceiveReserved->Type = RECEIVE_TYPE_DATAGRAM;
+ CTEAssert (!ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = TRUE;
+
+ TdiCopyLookaheadData(
+ &ReceiveBuffer->RemoteName,
+ Connectionless->Datagram.SourceName,
+ 16,
+ (MacOptions & NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA) ? TDI_RECEIVE_COPY_LOOKAHEAD : 0);
+
+ (*Device->Bind.TransferDataHandler) (
+ &NdisStatus,
+ MacBindingHandle,
+ MacReceiveContext,
+ LookaheadBufferOffset + DataOffset,
+ PacketSize - DataOffset,
+ Packet,
+ &BytesTransferred);
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+#if DBG
+ if (NdisStatus == STATUS_SUCCESS) {
+ CTEAssert (BytesTransferred == PacketSize - DataOffset);
+ }
+#endif
+
+ NbiTransferDataComplete(
+ Packet,
+ NdisStatus,
+ BytesTransferred);
+
+ }
+
+} /* NbiProcessDatagram */
+
+
+VOID
+NbiIndicateDatagram(
+ IN PADDRESS Address,
+ IN PUCHAR RemoteName,
+ IN PUCHAR Data,
+ IN ULONG DataLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine indicates a datagram to clients on the specified
+ address. It is called from NbiReceiveComplete.
+
+Arguments:
+
+ Address - The address the datagram was sent to.
+
+ RemoteName - The source netbios address of the datagram.
+
+ Data - The data.
+
+ DataLength - The length of the data.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p, q;
+ PIRP Irp;
+ ULONG IndicateBytesCopied;
+ PREQUEST Request;
+ TA_NETBIOS_ADDRESS SourceName;
+ PTDI_CONNECTION_INFORMATION RemoteInformation;
+ PADDRESS_FILE AddressFile, ReferencedAddressFile;
+ PTDI_CONNECTION_INFORMATION DatagramInformation;
+ TDI_ADDRESS_NETBIOS UNALIGNED * DatagramAddress;
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ CTELockHandle CancelLH;
+
+ //
+ // Update our statistics.
+ //
+
+ ++Device->Statistics.DatagramsReceived;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DatagramBytesReceived,
+ DataLength);
+
+ //
+ // Call the client's ReceiveDatagram indication handler. He may
+ // want to accept the datagram that way.
+ //
+
+ TdiBuildNetbiosAddress (RemoteName, FALSE, &SourceName);
+ ReferencedAddressFile = NULL;
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+
+ //
+ // Find the next open address file in the list.
+ //
+
+ AddressFile = CONTAINING_RECORD (p, ADDRESS_FILE, Linkage);
+ if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
+ continue;
+ }
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_INDICATION);
+
+ //
+ // do we have a datagram receive request outstanding? If so, we will
+ // satisfy it first. We run through the receive datagram queue
+ // until we find a datagram with no remote address or with
+ // this sender's address as its remote address.
+ //
+
+ for (q = AddressFile->ReceiveDatagramQueue.Flink;
+ q != &AddressFile->ReceiveDatagramQueue;
+ q = q->Flink) {
+
+ Request = LIST_ENTRY_TO_REQUEST (q);
+ DatagramInformation = ((PTDI_REQUEST_KERNEL_RECEIVEDG)
+ REQUEST_PARAMETERS(Request))->ReceiveDatagramInformation;
+
+ if (DatagramInformation &&
+ (DatagramInformation->RemoteAddress) &&
+ (DatagramAddress = NbiParseTdiAddress(DatagramInformation->RemoteAddress, FALSE)) &&
+ (!RtlEqualMemory(
+ RemoteName,
+ DatagramAddress->NetbiosName,
+ 16))) {
+ continue;
+ }
+ break;
+ }
+
+ if (q != &AddressFile->ReceiveDatagramQueue) {
+
+ RemoveEntryList (q);
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile != NULL) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION);
+ }
+ ReferencedAddressFile = AddressFile;
+
+ //
+ // Do this deref now, we hold another one so it
+ // will stick around.
+ //
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
+
+ IndicateBytesCopied = 0;
+
+ //
+ // Fall past the else to copy the data.
+ //
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile != NULL) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION);
+ }
+ ReferencedAddressFile = AddressFile;
+
+ //
+ // No receive datagram requests; is there a kernel client?
+ //
+
+ if (AddressFile->RegisteredHandler[TDI_EVENT_RECEIVE_DATAGRAM]) {
+
+ IndicateBytesCopied = 0;
+
+ if ((*AddressFile->ReceiveDatagramHandler)(
+ AddressFile->HandlerContexts[TDI_EVENT_RECEIVE_DATAGRAM],
+ sizeof (TA_NETBIOS_ADDRESS),
+ &SourceName,
+ 0,
+ NULL,
+ TDI_RECEIVE_COPY_LOOKAHEAD,
+ DataLength, // indicated
+ DataLength, // available
+ &IndicateBytesCopied,
+ Data,
+ &Irp) != STATUS_MORE_PROCESSING_REQUIRED) {
+
+ //
+ // The client did not return a request, go to the
+ // next address file.
+ //
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+
+ }
+
+ Request = NbiAllocateRequest (Device, Irp);
+
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+ }
+
+ } else {
+
+ //
+ // The client has nothing posted and no handler,
+ // go on to the next address file.
+ //
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+
+ }
+
+ }
+
+ //
+ // We have a request; copy the actual user data.
+ //
+ if ( REQUEST_NDIS_BUFFER (Request) ) {
+
+ REQUEST_STATUS(Request) =
+ TdiCopyBufferToMdl (
+ Data,
+ IndicateBytesCopied,
+ DataLength - IndicateBytesCopied,
+ REQUEST_NDIS_BUFFER (Request),
+ 0,
+ &REQUEST_INFORMATION (Request));
+
+ } else {
+ //
+ // No buffer specified in the request
+ //
+ REQUEST_INFORMATION (Request) = 0;
+ //
+ // If there was any data to be copied, return error o/w success
+ //
+ REQUEST_STATUS(Request) = ( (DataLength - IndicateBytesCopied) ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS );
+ }
+
+ //
+ // Copy the addressing information.
+ //
+
+ RemoteInformation = ((PTDI_REQUEST_KERNEL_RECEIVEDG)
+ REQUEST_PARAMETERS(Request))->ReturnDatagramInformation;
+
+ if (RemoteInformation != NULL) {
+
+ RtlCopyMemory(
+ (PTA_NETBIOS_ADDRESS)RemoteInformation->RemoteAddress,
+ &SourceName,
+ (RemoteInformation->RemoteAddressLength < sizeof(TA_NETBIOS_ADDRESS)) ?
+ RemoteInformation->RemoteAddressLength : sizeof(TA_NETBIOS_ADDRESS));
+ }
+
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+
+ } // end of for loop through the address files
+
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle);
+
+
+ if (ReferencedAddressFile != NULL) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION);
+ }
+
+} /* NbiIndicateDatagram */
+
+
+NTSTATUS
+NbiTdiSendDatagram(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a datagram on an address.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the datagram send.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PADDRESS_FILE AddressFile;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteName;
+ PTDI_REQUEST_KERNEL_SENDDG Parameters;
+ PSINGLE_LIST_ENTRY s;
+ PNETBIOS_CACHE CacheName;
+ CTELockHandle LockHandle;
+ NTSTATUS Status;
+
+ //
+ // Make sure that the address is valid.
+ //
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_NOT_OK);
+#else
+ Status = NbiVerifyAddressFile (AddressFile);
+#endif _PNP_POWER
+
+ if (Status == STATUS_SUCCESS) {
+
+ Parameters = (PTDI_REQUEST_KERNEL_SENDDG)REQUEST_PARAMETERS(Request);
+ RemoteName = NbiParseTdiAddress((PTRANSPORT_ADDRESS)(Parameters->SendDatagramInformation->RemoteAddress), TRUE);
+
+
+ //
+ // Check that datagram size is less than the maximum allowable
+ // by the adapters. In the worst case this would be
+ // 576 - 64 = 512.
+ //
+
+#if defined(_PNP_POWER)
+ if ( ( Parameters->SendLength + sizeof(NB_DATAGRAM) ) > Device->Bind.LineInfo.MaximumSendSize ) {
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ NB_DEBUG(DATAGRAM, ("Datagram too large %d, Max allowed %d\n", Parameters->SendLength + sizeof(NB_DATAGRAM), Device->Bind.LineInfo.MaximumSendSize ));
+ return STATUS_INVALID_PARAMETER;
+ }
+#else
+ if ( ( Parameters->SendLength + sizeof(NB_DATAGRAM) ) > Device->Bind.LineInfo.MaximumPacketSize ) {
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ NB_DEBUG(DATAGRAM, ("Datagram too large %d, Max allowed %d\n", Parameters->SendLength + sizeof(NB_DATAGRAM), Device->Bind.LineInfo.MaximumPacketSize ));
+ return STATUS_INVALID_PARAMETER;
+ }
+#endif _PNP_POWER
+
+ if (RemoteName != NULL) {
+
+ //
+ // Get a packet to use in this send.
+ //
+
+ s = NbiPopSendPacket (Device, FALSE);
+
+ if (s != NULL) {
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ //
+ // Check on the cache status of this name.
+ //
+
+ Reserved->u.SR_DG.DatagramRequest = Request;
+ Reserved->u.SR_DG.AddressFile = AddressFile;
+ Reserved->u.SR_DG.RemoteName = RemoteName;
+
+ REQUEST_INFORMATION (Request) = Parameters->SendLength;
+
+ ++Device->Statistics.DatagramsSent;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DatagramBytesSent,
+ Parameters->SendLength);
+
+ if (Device->Internet) {
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Status = CacheFindName(
+ Device,
+ FindNameOther,
+ (RemoteName == (PVOID)-1) ? NULL : (PUCHAR)RemoteName->NetbiosName,
+ &CacheName);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A request for routes to this name has been
+ // sent out on the net, we queue up this datagram
+ // request and processing will be resumed when
+ // we get a response.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Queueing up datagram %lx on %lx\n",
+ Request, AddressFile));
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_SEND_DGRAM);
+
+ InsertTailList(
+ &Device->WaitingDatagrams,
+ &Reserved->WaitLinkage);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ } else if (Status == STATUS_SUCCESS) {
+
+ NB_DEBUG2 (CONNECTION, ("Found datagram cached %lx on %lx\n",
+ Request, AddressFile));
+
+ //
+ // We reference the cache name entry so it won't
+ // go away while we are using it.
+ //
+
+ Reserved->u.SR_DG.Cache = CacheName;
+ Reserved->u.SR_DG.CurrentNetwork = 0;
+ ++CacheName->ReferenceCount;
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_SEND_DGRAM);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+ if ( REQUEST_NDIS_BUFFER(Request) ) {
+ NdisChainBufferAtBack (Packet, REQUEST_NDIS_BUFFER(Request));
+ }
+
+ NbiTransmitDatagram(
+ Reserved);
+
+ Status = STATUS_PENDING;
+
+ } else {
+
+ //
+ // Only this failure gets passed back up to
+ // the caller, to avoid confusing the browser.
+ //
+
+ if (Status != STATUS_DEVICE_DOES_NOT_EXIST) {
+
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ REQUEST_INFORMATION (Request) = 0;
+ }
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+
+
+
+ }
+
+ } else {
+
+ //
+ // We are not in internet mode, so we do not
+ // need to do the name discovery.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Sending datagram direct %lx on %lx\n",
+ Request, AddressFile));
+
+ Reserved->u.SR_DG.Cache = NULL;
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_SEND_DGRAM);
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ if ( REQUEST_NDIS_BUFFER(Request) ) {
+ NdisChainBufferAtBack (Packet, REQUEST_NDIS_BUFFER(Request));
+ }
+ NbiTransmitDatagram(
+ Reserved);
+
+ Status = STATUS_PENDING;
+
+ }
+
+ } else {
+
+ //
+ // Could not allocate a packet for the datagram.
+ //
+
+ NB_DEBUG (DATAGRAM, ("Couldn't get packet to send DG %lx\n", Request));
+
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+ } else {
+
+ //
+ // There is no netbios remote address specified.
+ //
+
+ NB_DEBUG (DATAGRAM, ("No netbios address in DG %lx\n", Request));
+ Status = STATUS_BAD_NETWORK_PATH;
+
+ }
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ } else {
+
+ NB_DEBUG (DATAGRAM, ("Invalid address file for DG %lx\n", Request));
+
+ }
+
+ return Status;
+
+} /* NbiTdiSendDatagram */
+
+
+VOID
+NbiTransmitDatagram(
+ IN PNB_SEND_RESERVED Reserved
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a datagram to the next net in the
+ cache entry for the remote name.
+
+Arguments:
+
+ Reserved - The reserved section of the packet that has
+ been allocated for this send. Reserved->u.SR_DG.Cache
+ will be NULL if Internet mode is off, otherwise it
+ will contain the cache entry to use when sending
+ this datagram.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_PACKET Packet;
+ PNETBIOS_CACHE CacheName;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ ULONG HeaderLength;
+ ULONG PacketLength;
+ NDIS_STATUS NdisStatus;
+ IPX_LOCAL_TARGET TempLocalTarget;
+ PIPX_LOCAL_TARGET LocalTarget;
+ PDEVICE Device = NbiDevice;
+
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_DATAGRAM;
+
+ CacheName = Reserved->u.SR_DG.Cache;
+
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address, so we modify
+ // that for the current netbios cache entry if needed.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+
+ if (CacheName == NULL) {
+
+#if defined(_PNP_POWER)
+ //
+ // IPX will send this on all the Nics.
+ //
+ TempLocalTarget.NicHandle.NicId = 0;
+#else
+ TempLocalTarget.NicId = 1;
+#endif _PNP_POWER
+ RtlCopyMemory (TempLocalTarget.MacAddress, BroadcastAddress, 6);
+ LocalTarget = &TempLocalTarget;
+
+ } else {
+
+ if (CacheName->Unique) {
+ RtlCopyMemory (Header->IpxHeader.DestinationNetwork, &CacheName->FirstResponse, 12);
+ } else {
+ *(UNALIGNED ULONG *)Header->IpxHeader.DestinationNetwork = CacheName->Networks[Reserved->u.SR_DG.CurrentNetwork].Network;
+ RtlCopyMemory (&Header->IpxHeader.DestinationNode, BroadcastAddress, 6);
+ }
+
+ LocalTarget = &CacheName->Networks[Reserved->u.SR_DG.CurrentNetwork].LocalTarget;
+
+ }
+
+ HeaderLength = sizeof(IPX_HEADER) + sizeof(NB_DATAGRAM);
+
+ PacketLength = HeaderLength + REQUEST_INFORMATION(Reserved->u.SR_DG.DatagramRequest);
+
+ Header->IpxHeader.PacketLength[0] = (UCHAR)(PacketLength / 256);
+ Header->IpxHeader.PacketLength[1] = (UCHAR)(PacketLength % 256);
+ Header->IpxHeader.PacketType = 0x04;
+
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ Header->Datagram.ConnectionControlFlag = 0x00;
+ RtlCopyMemory(
+ Header->Datagram.SourceName,
+ Reserved->u.SR_DG.AddressFile->Address->NetbiosAddress.NetbiosName,
+ 16);
+
+ if (Reserved->u.SR_DG.RemoteName != (PVOID)-1) {
+
+ //
+ // This is a directed, as opposed to broadcast, datagram.
+ //
+
+ Header->Datagram.DataStreamType = NB_CMD_DATAGRAM;
+ RtlCopyMemory(
+ Header->Datagram.DestinationName,
+ Reserved->u.SR_DG.RemoteName->NetbiosName,
+ 16);
+
+ } else {
+
+ Header->Datagram.DataStreamType = NB_CMD_BROADCAST_DATAGRAM;
+ RtlZeroMemory(
+ Header->Datagram.DestinationName,
+ 16);
+
+ }
+
+
+ //
+ // Now send the frame (IPX will adjust the length of the
+ // first buffer and the whole frame correctly).
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), HeaderLength);
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ PacketLength,
+ HeaderLength)) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiTransmitDatagram */
+
+
+NTSTATUS
+NbiTdiReceiveDatagram(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiReceiveDatagram request for the transport
+ provider. Receive datagrams just get queued up to an address, and are
+ completed when a DATAGRAM or DATAGRAM_BROADCAST frame is received at
+ the address.
+
+Arguments:
+
+ Request - Describes this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ CTELockHandle LockHandle;
+ CTELockHandle CancelLH;
+
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_NOT_OK);
+#else
+ Status = NbiVerifyAddressFile (AddressFile);
+#endif _PNP_POWER
+
+ if (Status != STATUS_SUCCESS) {
+ return Status;
+ }
+
+ Address = AddressFile->Address;
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ return STATUS_INVALID_HANDLE;
+ }
+
+
+ if (Request->Cancel) {
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ return STATUS_CANCELLED;
+ }
+
+ InsertTailList (&AddressFile->ReceiveDatagramQueue, REQUEST_LINKAGE(Request));
+
+ IoSetCancelRoutine (Request, NbiCancelReceiveDatagram);
+
+ NB_DEBUG2 (DATAGRAM, ("RDG posted on %lx\n", AddressFile));
+
+ NbiTransferReferenceAddressFile (AddressFile, AFREF_VERIFY, AFREF_RCV_DGRAM);
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ return STATUS_PENDING;
+
+} /* NbiTdiReceiveDatagram */
+
+
+VOID
+NbiCancelReceiveDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a receive
+ datagram. The datagram is found on the address file's receive
+ datagram queue.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PLIST_ENTRY p;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PREQUEST Request = (PREQUEST)Irp;
+ BOOLEAN Found;
+ NB_DEFINE_LOCK_HANDLE(LockHandle)
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_RECEIVE_DATAGRAM));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_TRANSPORT_ADDRESS_FILE);
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+ Address = AddressFile->Address;
+
+ Found = FALSE;
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+
+ for (p = AddressFile->ReceiveDatagramQueue.Flink;
+ p != &AddressFile->ReceiveDatagramQueue;
+ p = p->Flink) {
+
+ if (LIST_ENTRY_TO_REQUEST(p) == Request) {
+
+ RemoveEntryList (p);
+ Found = TRUE;
+ break;
+ }
+ }
+
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ if (Found) {
+
+ NB_DEBUG (DATAGRAM, ("Cancelled datagram on %lx\n", AddressFile));
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest((PDEVICE)DeviceObject, Request);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
+
+ }
+
+} /* NbiCancelReceiveDatagram */
+
diff --git a/private/ntos/tdi/isnp/nb/device.c b/private/ntos/tdi/isnp/nb/device.c
new file mode 100644
index 000000000..d1a9af781
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/device.c
@@ -0,0 +1,461 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ device.c
+
+Abstract:
+
+ This module contains code which implements the DEVICE object.
+ Routines are provided to reference, and dereference transport device
+ context objects.
+
+ The transport device context object is a structure which contains a
+ system-defined DEVICE_OBJECT followed by information which is maintained
+ by the transport provider, called the context.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,NbiCreateDevice)
+#endif
+
+
+VOID
+NbiRefDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a device context.
+
+Arguments:
+
+ Device - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ CTEAssert (Device->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement (&Device->ReferenceCount);
+
+} /* NbiRefDevice */
+
+
+VOID
+NbiDerefDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a device context by decrementing the
+ reference count contained in the structure. Currently, we don't
+ do anything special when the reference count drops to zero, but
+ we could dynamically unload stuff then.
+
+Arguments:
+
+ Device - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&Device->ReferenceCount);
+
+ CTEAssert (result >= 0);
+
+ if (result == 0) {
+ NbiDestroyDevice (Device);
+ }
+
+} /* NbiDerefDevice */
+
+
+NTSTATUS
+NbiCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN OUT PDEVICE *DevicePtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates and initializes a device context structure.
+
+Arguments:
+
+
+ DriverObject - pointer to the IO subsystem supplied driver object.
+
+ Device - Pointer to a pointer to a transport device context object.
+
+ DeviceName - pointer to the name of the device this device object points to.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
+
+--*/
+
+{
+ NTSTATUS status;
+ PDEVICE_OBJECT deviceObject;
+ PDEVICE Device;
+ ULONG DeviceSize;
+ UINT i;
+
+
+ //
+ // Create the device object for the sample transport, allowing
+ // room at the end for the device name to be stored (for use
+ // in logging errors) and the RIP fields.
+ //
+
+ DeviceSize = sizeof(DEVICE) - sizeof(DEVICE_OBJECT) +
+ DeviceName->Length + sizeof(UNICODE_NULL);
+
+ status = IoCreateDevice(
+ DriverObject,
+ DeviceSize,
+ DeviceName,
+ FILE_DEVICE_TRANSPORT,
+ 0,
+ FALSE,
+ &deviceObject);
+
+ if (!NT_SUCCESS(status)) {
+ NB_DEBUG(DEVICE, ("Create device %ws failed %lx\n", DeviceName->Buffer, status));
+ return status;
+ }
+
+ deviceObject->Flags |= DO_DIRECT_IO;
+
+ Device = (PDEVICE)deviceObject;
+
+ NB_DEBUG2 (DEVICE, ("Create device %ws succeeded %lx\n", DeviceName->Buffer, Device));
+
+ //
+ // Initialize our part of the device context.
+ //
+
+ RtlZeroMemory(
+ ((PUCHAR)Device) + sizeof(DEVICE_OBJECT),
+ sizeof(DEVICE) - sizeof(DEVICE_OBJECT));
+
+ //
+ // Copy over the device name.
+ //
+
+ Device->DeviceNameLength = DeviceName->Length + sizeof(WCHAR);
+ Device->DeviceName = (PWCHAR)(Device+1);
+ RtlCopyMemory(
+ Device->DeviceName,
+ DeviceName->Buffer,
+ DeviceName->Length);
+ Device->DeviceName[DeviceName->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ //
+ // Initialize the reference count.
+ //
+
+ Device->ReferenceCount = 1;
+#if DBG
+ Device->RefTypes[DREF_CREATE] = 1;
+#endif
+
+#if DBG
+ RtlCopyMemory(Device->Signature1, "NDC1", 4);
+ RtlCopyMemory(Device->Signature2, "NDC2", 4);
+#endif
+
+ //
+ // BETABUGBUG: Clean this up a bit.
+ //
+
+ Device->Information.Version = 0x0100;
+ Device->Information.MaxSendSize = 65535;
+ Device->Information.MaxConnectionUserData = 0;
+ Device->Information.MaxDatagramSize = 500;
+ Device->Information.ServiceFlags =
+ TDI_SERVICE_CONNECTION_MODE | TDI_SERVICE_ERROR_FREE_DELIVERY |
+ TDI_SERVICE_MULTICAST_SUPPORTED | TDI_SERVICE_BROADCAST_SUPPORTED |
+ TDI_SERVICE_DELAYED_ACCEPTANCE | TDI_SERVICE_CONNECTIONLESS_MODE |
+ TDI_SERVICE_MESSAGE_MODE;
+ Device->Information.MinimumLookaheadData = 128;
+ Device->Information.MaximumLookaheadData = 1500;
+ Device->Information.NumberOfResources = 0;
+ KeQuerySystemTime (&Device->Information.StartTime);
+
+ Device->Statistics.Version = 0x0100;
+ Device->Statistics.MaximumSendWindow = 4;
+ Device->Statistics.AverageSendWindow = 4;
+
+ //
+ // Set this so we won't ignore the broadcast name.
+ //
+
+ Device->AddressCounts['*'] = 1;
+
+ //
+ // Initialize the resource that guards address ACLs.
+ //
+
+ ExInitializeResource (&Device->AddressResource);
+
+ //
+ // initialize the various fields in the device context
+ //
+
+ CTEInitLock (&Device->Interlock.Lock);
+ CTEInitLock (&Device->Lock.Lock);
+
+ CTEInitTimer (&Device->FindNameTimer);
+
+ Device->ControlChannelIdentifier = 1;
+
+ InitializeListHead (&Device->GlobalSendPacketList);
+ InitializeListHead (&Device->GlobalReceivePacketList);
+ InitializeListHead (&Device->GlobalReceiveBufferList);
+
+ InitializeListHead (&Device->AddressDatabase);
+#if defined(_PNP_POWER)
+ InitializeListHead (&Device->AdapterAddressDatabase);
+#endif _PNP_POWER
+
+ InitializeListHead (&Device->WaitingFindNames);
+
+ InitializeListHead (&Device->WaitingConnects);
+ InitializeListHead (&Device->WaitingDatagrams);
+
+ InitializeListHead (&Device->WaitingAdapterStatus);
+ InitializeListHead (&Device->ActiveAdapterStatus);
+
+ InitializeListHead (&Device->WaitingNetbiosFindName);
+
+ InitializeListHead (&Device->ReceiveDatagrams);
+ InitializeListHead (&Device->ConnectIndicationInProgress);
+
+ InitializeListHead (&Device->ListenQueue);
+
+ InitializeListHead (&Device->ReceiveCompletionQueue);
+
+ InitializeListHead (&Device->WaitPacketConnections);
+ InitializeListHead (&Device->PacketizeConnections);
+ InitializeListHead (&Device->DataAckConnections);
+
+ Device->MemoryUsage = 0;
+
+ InitializeListHead (&Device->SendPoolList);
+ InitializeListHead (&Device->ReceivePoolList);
+ InitializeListHead (&Device->ReceiveBufferPoolList);
+
+ ExInitializeSListHead( &Device->SendPacketList );
+ ExInitializeSListHead( &Device->ReceivePacketList );
+ Device->ReceiveBufferList.Next = NULL;
+
+ for (i = 0; i < CONNECTION_HASH_COUNT; i++) {
+ Device->ConnectionHash[i].Connections = NULL;
+ Device->ConnectionHash[i].ConnectionCount = 0;
+ Device->ConnectionHash[i].NextConnectionId = 1;
+ }
+
+ KeQuerySystemTime (&Device->NbiStartTime);
+
+ Device->State = DEVICE_STATE_CLOSED;
+
+ Device->Type = NB_DEVICE_SIGNATURE;
+ Device->Size - sizeof (DEVICE);
+
+
+ *DevicePtr = Device;
+ return STATUS_SUCCESS;
+
+} /* NbiCreateDevice */
+
+
+VOID
+NbiDestroyDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a device context structure.
+
+Arguments:
+
+ Device - Pointer to a pointer to a transport device context object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PNB_SEND_POOL SendPool;
+ PNB_SEND_PACKET SendPacket;
+ UINT SendPoolSize;
+ PNB_RECEIVE_POOL ReceivePool;
+ PNB_RECEIVE_PACKET ReceivePacket;
+ UINT ReceivePoolSize;
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ UINT ReceiveBufferPoolSize;
+ ULONG HeaderLength;
+ UINT i;
+
+ NB_DEBUG2 (DEVICE, ("Destroy device %lx\n", Device));
+
+ //
+ // Take all the connectionless packets out of its pools.
+ //
+
+ HeaderLength = Device->Bind.MacHeaderNeeded + sizeof(NB_CONNECTIONLESS);
+
+ SendPoolSize = FIELD_OFFSET (NB_SEND_POOL, Packets[0]) +
+ (sizeof(NB_SEND_PACKET) * Device->InitPackets) +
+ (HeaderLength * Device->InitPackets);
+
+ while (!IsListEmpty (&Device->SendPoolList)) {
+
+ p = RemoveHeadList (&Device->SendPoolList);
+ SendPool = CONTAINING_RECORD (p, NB_SEND_POOL, Linkage);
+
+ for (i = 0; i < SendPool->PacketCount; i++) {
+
+ SendPacket = &SendPool->Packets[i];
+ NbiDeinitializeSendPacket (Device, SendPacket, HeaderLength);
+
+ }
+
+ NB_DEBUG2 (PACKET, ("Free packet pool %lx\n", SendPool));
+
+#if !defined(NB_OWN_PACKETS)
+ NdisFreePacketPool(SendPool->PoolHandle);
+#endif
+
+ NbiFreeMemory (SendPool, SendPoolSize, MEMORY_PACKET, "SendPool");
+ }
+
+
+ ReceivePoolSize = FIELD_OFFSET (NB_RECEIVE_POOL, Packets[0]) +
+ (sizeof(NB_RECEIVE_PACKET) * Device->InitPackets);
+
+ while (!IsListEmpty (&Device->ReceivePoolList)) {
+
+ p = RemoveHeadList (&Device->ReceivePoolList);
+ ReceivePool = CONTAINING_RECORD (p, NB_RECEIVE_POOL, Linkage);
+
+ for (i = 0; i < ReceivePool->PacketCount; i++) {
+
+ ReceivePacket = &ReceivePool->Packets[i];
+ NbiDeinitializeReceivePacket (Device, ReceivePacket);
+
+ }
+
+ NB_DEBUG2 (PACKET, ("Free packet pool %lx\n", ReceivePool));
+#if !defined(NB_OWN_PACKETS)
+ NdisFreePacketPool(ReceivePool->PoolHandle);
+#endif
+ NbiFreeMemory (ReceivePool, ReceivePoolSize, MEMORY_PACKET, "ReceivePool");
+ }
+
+#if defined(_PNP_POWER)
+ NbiDestroyReceiveBufferPools( Device );
+
+ //
+ // Destroy adapter address list.
+ //
+ while(!IsListEmpty( &Device->AdapterAddressDatabase ) ){
+ PADAPTER_ADDRESS AdapterAddress;
+ AdapterAddress = CONTAINING_RECORD( Device->AdapterAddressDatabase.Flink, ADAPTER_ADDRESS, Linkage );
+ NbiDestroyAdapterAddress( AdapterAddress, NULL );
+ }
+#else
+ ReceiveBufferPoolSize = FIELD_OFFSET (NB_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(NB_RECEIVE_BUFFER) * Device->InitPackets) +
+ (Device->Bind.LineInfo.MaximumPacketSize * Device->InitPackets);
+
+ while (!IsListEmpty (&Device->ReceiveBufferPoolList)) {
+
+ p = RemoveHeadList (&Device->ReceiveBufferPoolList);
+ ReceiveBufferPool = CONTAINING_RECORD (p, NB_RECEIVE_BUFFER_POOL, Linkage);
+
+ for (i = 0; i < ReceiveBufferPool->BufferCount; i++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[i];
+ NbiDeinitializeReceiveBuffer (Device, ReceiveBuffer);
+
+ }
+
+ NB_DEBUG2 (PACKET, ("Free buffer pool %lx\n", ReceiveBufferPool));
+ NbiFreeMemory (ReceiveBufferPool, ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+ }
+#endif _PNP_POWER
+
+ NB_DEBUG (DEVICE, ("Final memory use is %d\n", Device->MemoryUsage));
+
+#if DBG
+ for (i = 0; i < MEMORY_MAX; i++) {
+ if (NbiMemoryTag[i].BytesAllocated != 0) {
+ NB_DEBUG (DEVICE, ("Tag %d: %d bytes left\n", i, NbiMemoryTag[i].BytesAllocated));
+ }
+ }
+#endif
+
+ //
+ // If we are being unloaded then someone is waiting for this
+ // event to finish the cleanup, since we may be at DISPATCH_LEVEL;
+ // otherwise it is during load and we can just kill ourselves here.
+ //
+
+ if (Device->UnloadWaiting) {
+
+ KeSetEvent(
+ &Device->UnloadEvent,
+ 0L,
+ FALSE);
+
+ } else {
+
+ CTEAssert (KeGetCurrentIrql() < DISPATCH_LEVEL);
+ ExDeleteResource (&Device->AddressResource);
+ IoDeleteDevice ((PDEVICE_OBJECT)Device);
+ }
+
+} /* NbiDestroyDevice */
+
diff --git a/private/ntos/tdi/isnp/nb/dirs b/private/ntos/tdi/isnp/nb/dirs
new file mode 100644
index 000000000..0dab2f056
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/dirs
@@ -0,0 +1,22 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=up mp
diff --git a/private/ntos/tdi/isnp/nb/driver.c b/private/ntos/tdi/isnp/nb/driver.c
new file mode 100644
index 000000000..c4df8cbe6
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/driver.c
@@ -0,0 +1,1794 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ driver.c
+
+Abstract:
+
+ This module contains the DriverEntry and other initialization
+ code for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 16-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+PDEVICE NbiDevice = NULL;
+DEFINE_LOCK_STRUCTURE(NbiGlobalPoolInterlock);
+
+#ifdef RSRC_TIMEOUT_DBG
+
+ULONG NbiGlobalDebugResTimeout = 1;
+LARGE_INTEGER NbiGlobalMaxResTimeout;
+ // the packet is allocated from ndis pool.
+NB_SEND_PACKET NbiGlobalDeathPacket; // try to use this first for sends
+UCHAR NbiGlobalDeathPacketHeader[100];
+
+VOID
+NbiInitDeathPacket()
+{
+
+ NDIS_HANDLE PoolHandle; // poolhandle for sendpacket below when
+ NTSTATUS Status;
+
+ //
+ // if we are using ndis packets, first create packet pool for 1 packet descriptor
+ //
+ NdisAllocatePacketPool( &Status, &PoolHandle, 1, sizeof(NB_SEND_RESERVED));
+ if (!NT_SUCCESS(Status)){
+ DbgPrint("Could not allocatee death packet %lx\n", Status);
+ NbiGlobalDebugResTimeout = 0;
+ } else {
+
+ if (NbiInitializeSendPacket(
+ NbiDevice,
+ PoolHandle,
+ &NbiGlobalDeathPacket,
+ NbiGlobalDeathPacketHeader,
+ NbiDevice->Bind.MacHeaderNeeded + sizeof(NB_CONNECTION)) != STATUS_SUCCESS) {
+
+ DbgPrint("Could not allocatee death packet %lx\n", Status);
+ NbiGlobalDebugResTimeout = 0;
+
+ //
+ // Also free up the pool which we allocated above.
+ //
+ NdisFreePacketPool(PoolHandle);
+ }
+ }
+
+}
+#endif //RSRC_TIMEOUT_DBG
+
+#if DBG
+
+ULONG NbiDebug = 0xffffffff;
+ULONG NbiDebug2 = 0x00000000;
+ULONG NbiMemoryDebug = 0x0002482c;
+
+UCHAR NbiTempDebugBuffer[150];
+UCHAR NbiDebugMemory[NB_MEMORY_LOG_SIZE][64];
+PUCHAR NbiDebugMemoryLoc = NbiDebugMemory[0];
+PUCHAR NbiDebugMemoryEnd = NbiDebugMemory[NB_MEMORY_LOG_SIZE];
+VOID
+NbiDebugMemoryLog(
+ IN PUCHAR FormatString,
+ ...
+)
+
+{
+ INT ArgLen;
+ va_list ArgumentPointer;
+
+ va_start(ArgumentPointer, FormatString);
+
+ //
+ // To avoid any overflows, copy this in a temp buffer first.
+ RtlZeroMemory (NbiTempDebugBuffer, 150);
+ ArgLen = vsprintf(NbiTempDebugBuffer,FormatString, ArgumentPointer);
+ va_end(ArgumentPointer);
+
+ if ( ArgLen > 64 ) {
+ CTEAssert( FALSE );
+ } else {
+ RtlZeroMemory (NbiDebugMemoryLoc, 64);
+ RtlCopyMemory( NbiDebugMemoryLoc, NbiTempDebugBuffer, ArgLen );
+
+ NbiDebugMemoryLoc += 64;
+ if (NbiDebugMemoryLoc >= NbiDebugMemoryEnd) {
+ NbiDebugMemoryLoc = NbiDebugMemory[0];
+ }
+ }
+
+} /* NbiDebugMemoryLog */
+
+
+DEFINE_LOCK_STRUCTURE(NbiMemoryInterlock);
+MEMORY_TAG NbiMemoryTag[MEMORY_MAX];
+
+#endif
+//
+// This is used only for CHK build. For
+// tracking the refcount problem on connection, this
+// is moved here for now.
+//
+DEFINE_LOCK_STRUCTURE(NbiGlobalInterlock);
+
+
+#ifdef RASAUTODIAL
+VOID
+NbiAcdBind();
+
+VOID
+NbiAcdUnbind();
+#endif
+
+#ifdef NB_PACKET_LOG
+
+ULONG NbiPacketLogDebug = NB_PACKET_LOG_RCV_OTHER | NB_PACKET_LOG_SEND_OTHER;
+USHORT NbiPacketLogSocket = 0;
+DEFINE_LOCK_STRUCTURE(NbiPacketLogLock);
+NB_PACKET_LOG_ENTRY NbiPacketLog[NB_PACKET_LOG_LENGTH];
+PNB_PACKET_LOG_ENTRY NbiPacketLogLoc = NbiPacketLog;
+PNB_PACKET_LOG_ENTRY NbiPacketLogEnd = &NbiPacketLog[NB_PACKET_LOG_LENGTH];
+
+VOID
+NbiLogPacket(
+ IN BOOLEAN Send,
+ IN PUCHAR DestMac,
+ IN PUCHAR SrcMac,
+ IN USHORT Length,
+ IN PVOID NbiHeader,
+ IN PVOID Data
+ )
+
+{
+
+ CTELockHandle LockHandle;
+ PNB_PACKET_LOG_ENTRY PacketLog;
+ LARGE_INTEGER TickCount;
+ ULONG DataLength;
+
+ CTEGetLock (&NbiPacketLogLock, &LockHandle);
+
+ PacketLog = NbiPacketLogLoc;
+
+ ++NbiPacketLogLoc;
+ if (NbiPacketLogLoc >= NbiPacketLogEnd) {
+ NbiPacketLogLoc = NbiPacketLog;
+ }
+ *(UNALIGNED ULONG *)NbiPacketLogLoc->TimeStamp = 0x3e3d3d3d; // "===>"
+
+ CTEFreeLock (&NbiPacketLogLock, LockHandle);
+
+ RtlZeroMemory (PacketLog, sizeof(NB_PACKET_LOG_ENTRY));
+
+ PacketLog->SendReceive = Send ? '>' : '<';
+
+ KeQueryTickCount(&TickCount);
+ _itoa (TickCount.LowPart % 100000, PacketLog->TimeStamp, 10);
+
+ RtlCopyMemory(PacketLog->DestMac, DestMac, 6);
+ RtlCopyMemory(PacketLog->SrcMac, SrcMac, 6);
+ PacketLog->Length[0] = Length / 256;
+ PacketLog->Length[1] = Length % 256;
+
+ if (Length < sizeof(IPX_HEADER)) {
+ RtlCopyMemory(&PacketLog->NbiHeader, NbiHeader, Length);
+ } else {
+ RtlCopyMemory(&PacketLog->NbiHeader, NbiHeader, sizeof(IPX_HEADER));
+ }
+
+ DataLength = Length - sizeof(IPX_HEADER);
+ if (DataLength < 14) {
+ RtlCopyMemory(PacketLog->Data, Data, DataLength);
+ } else {
+ RtlCopyMemory(PacketLog->Data, Data, 14);
+ }
+
+} /* NbiLogPacket */
+
+#endif // NB_PACKET_LOG
+
+
+//
+// Forward declaration of various routines used in this module.
+//
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+VOID
+NbiUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+NTSTATUS
+NbiDispatchDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbiDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbiDispatchInternal (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+NbiFreeResources (
+ IN PVOID Adapter
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,DriverEntry)
+#endif
+
+//
+// This prevents us from having a bss section.
+//
+
+ULONG _setjmpexused = 0;
+
+
+//
+// These two are used in various places in the driver.
+//
+
+#if defined(_PNP_POWER)
+IPX_LOCAL_TARGET BroadcastTarget = { {0}, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
+#endif _PNP_POWER
+
+UCHAR BroadcastAddress[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+UCHAR NetbiosBroadcastName[16] = { '*', 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ULONG NbiFailLoad = FALSE;
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs initialization of the Netbios ISN module.
+ It creates the device objects for the transport
+ provider and performs other driver initialization.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+ RegistryPath - The name of Netbios's node in the registry.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ static const NDIS_STRING ProtocolName = NDIS_STRING_CONST("Netbios/IPX Transport");
+ PDEVICE Device;
+ PIPX_HEADER IpxHeader;
+ CTELockHandle LockHandle;
+
+ PCONFIG Config = NULL;
+
+#if 0
+ DbgPrint ("NBI: FailLoad at %lx\n", &NbiFailLoad);
+ DbgBreakPoint();
+
+ if (NbiFailLoad) {
+ return STATUS_UNSUCCESSFUL;
+ }
+#endif
+
+ //
+ // Initialize the Common Transport Environment.
+ //
+
+ if (CTEInitialize() == 0) {
+ NB_DEBUG (DEVICE, ("CTEInitialize() failed\n"));
+ NbiWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_REGISTER_FAILED,
+ 101,
+ STATUS_UNSUCCESSFUL,
+ NULL,
+ 0,
+ NULL);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+#if DBG
+ CTEInitLock (&NbiGlobalInterlock);
+ CTEInitLock (&NbiMemoryInterlock);
+ {
+ UINT i;
+ for (i = 0; i < MEMORY_MAX; i++) {
+ NbiMemoryTag[i].Tag = i;
+ NbiMemoryTag[i].BytesAllocated = 0;
+ }
+ }
+#endif
+#ifdef NB_PACKET_LOG
+ CTEInitLock (&NbiPacketLogLock);
+#endif
+
+#if defined(NB_OWN_PACKETS)
+ CTEAssert (NDIS_PACKET_SIZE == FIELD_OFFSET(NDIS_PACKET, ProtocolReserved[0]));
+#endif
+
+ NB_DEBUG2 (DEVICE, ("ISN Netbios loaded\n"));
+
+ //
+ // This allocates the CONFIG structure and returns
+ // it in Config.
+ //
+
+ status = NbiGetConfiguration(DriverObject, RegistryPath, &Config);
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // If it failed it logged an error.
+ //
+
+ PANIC (" Failed to initialize transport, ISN Netbios initialization failed.\n");
+ return status;
+ }
+
+
+ //
+ // Initialize the driver object with this driver's entry points.
+ //
+
+ DriverObject->MajorFunction [IRP_MJ_CREATE] = NbiDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLOSE] = NbiDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLEANUP] = NbiDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL] = NbiDispatchInternal;
+ DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = NbiDispatchDeviceControl;
+
+ DriverObject->DriverUnload = NbiUnload;
+
+
+ //
+ // Create the device object which exports our name.
+ //
+
+ status = NbiCreateDevice (DriverObject, &Config->DeviceName, &Device);
+
+ if (!NT_SUCCESS (status)) {
+
+ NbiWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_CREATE_DEVICE,
+ 801,
+ status,
+ NULL,
+ 0,
+ NULL);
+
+ NbiFreeConfiguration(Config);
+ return status;
+ }
+
+ NbiDevice = Device;
+
+ //
+ // Initialize the global pool interlock
+ //
+ CTEInitLock (&NbiGlobalPoolInterlock);
+
+
+ //
+ // Save the relevant configuration parameters.
+ //
+
+ Device->AckDelayTime = (Config->Parameters[CONFIG_ACK_DELAY_TIME] / SHORT_TIMER_DELTA) + 1;
+ Device->AckWindow = Config->Parameters[CONFIG_ACK_WINDOW];
+ Device->AckWindowThreshold = Config->Parameters[CONFIG_ACK_WINDOW_THRESHOLD];
+ Device->EnablePiggyBackAck = Config->Parameters[CONFIG_ENABLE_PIGGYBACK_ACK];
+ Device->Extensions = Config->Parameters[CONFIG_EXTENSIONS];
+ Device->RcvWindowMax = Config->Parameters[CONFIG_RCV_WINDOW_MAX];
+ Device->BroadcastCount = Config->Parameters[CONFIG_BROADCAST_COUNT];
+ Device->BroadcastTimeout = Config->Parameters[CONFIG_BROADCAST_TIMEOUT] * 500;
+ Device->ConnectionCount = Config->Parameters[CONFIG_CONNECTION_COUNT];
+ Device->ConnectionTimeout = Config->Parameters[CONFIG_CONNECTION_TIMEOUT] * 500;
+ Device->InitPackets = Config->Parameters[CONFIG_INIT_PACKETS];
+ Device->MaxPackets = Config->Parameters[CONFIG_MAX_PACKETS];
+ Device->InitialRetransmissionTime = Config->Parameters[CONFIG_INIT_RETRANSMIT_TIME];
+ Device->Internet = Config->Parameters[CONFIG_INTERNET];
+ Device->KeepAliveCount = Config->Parameters[CONFIG_KEEP_ALIVE_COUNT];
+ Device->KeepAliveTimeout = Config->Parameters[CONFIG_KEEP_ALIVE_TIMEOUT];
+ Device->RetransmitMax = Config->Parameters[CONFIG_RETRANSMIT_MAX];
+ Device->RouterMtu = Config->Parameters[CONFIG_ROUTER_MTU];
+
+ Device->FindNameTimeout =
+ ((Config->Parameters[CONFIG_BROADCAST_TIMEOUT] * 500) + (FIND_NAME_GRANULARITY/2)) /
+ FIND_NAME_GRANULARITY;
+
+ Device->MaxReceiveBuffers = 20; // BUGBUG: Make it configurable?
+
+#if defined(_PNP_POWER)
+ //
+ // Make Tdi ready for pnp notifications before binding
+ // to IPX
+ //
+ TdiInitialize();
+
+ // Initialize the timer system. This should be done before
+ // binding to ipx because we should have timers intialized
+ // before ipx calls our pnp indications.
+
+ NbiInitializeTimers (Device);
+#endif _PNP_POWER
+
+ //
+ // Now bind to IPX via the internal interface.
+ //
+
+ status = NbiBind (Device, Config);
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // If it failed it logged an error.
+ //
+
+ NbiFreeConfiguration(Config);
+ NbiDereferenceDevice (Device, DREF_LOADED);
+ return status;
+ }
+
+#ifdef RSRC_TIMEOUT_DBG
+ NbiInitDeathPacket();
+ // NbiGlobalMaxResTimeout.QuadPart = 50; // 1*1000*10000;
+ NbiGlobalMaxResTimeout.QuadPart = 20*60*1000;
+ NbiGlobalMaxResTimeout.QuadPart *= 10000;
+#endif // RSRC_TIMEOUT_DBG
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ //
+ // Create Hash Table to store netbios cache entries
+ // For server create a big table, for workstation a small one
+ //
+
+ if ( MmIsThisAnNtAsSystem() ) {
+ status = CreateNetbiosCacheTable( &Device->NameCache, NB_NETBIOS_CACHE_TABLE_LARGE );
+ } else {
+ status = CreateNetbiosCacheTable( &Device->NameCache, NB_NETBIOS_CACHE_TABLE_SMALL );
+ }
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // If it failed it logged an error.
+ //
+
+ NB_FREE_LOCK(&Device->Lock, LockHandle);
+ NbiFreeConfiguration(Config);
+ NbiDereferenceDevice (Device, DREF_LOADED);
+ return status;
+ }
+
+ //
+ // Allocate our initial connectionless packet pool.
+ //
+
+ NbiAllocateSendPool (Device);
+
+ //
+ // Allocate our initial receive packet pool.
+ //
+
+ NbiAllocateReceivePool (Device);
+
+ //
+ // Allocate our initial receive buffer pool.
+ //
+ //
+#if !defined(_PNP_POWER)
+ NbiAllocateReceiveBufferPool (Device);
+#endif !_PNP_POWER
+
+#if defined(_PNP_POWER)
+ if ( DEVICE_STATE_CLOSED == Device->State ) {
+ Device->State = DEVICE_STATE_LOADED;
+ }
+#endif _PNP_POWER
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+#if !defined(_PNP_POWER)
+ //
+ // Start the timer system.
+ //
+
+ NbiInitializeTimers (Device);
+#endif !_PNP_POWER
+
+
+ //
+ // Fill in the default connnectionless header.
+ //
+
+ IpxHeader = &Device->ConnectionlessHeader;
+ IpxHeader->CheckSum = 0xffff;
+ IpxHeader->PacketLength[0] = 0;
+ IpxHeader->PacketLength[1] = 0;
+ IpxHeader->TransportControl = 0;
+ IpxHeader->PacketType = 0;
+ *(UNALIGNED ULONG *)(IpxHeader->DestinationNetwork) = 0;
+ RtlCopyMemory(IpxHeader->DestinationNode, BroadcastAddress, 6);
+ IpxHeader->DestinationSocket = NB_SOCKET;
+ IpxHeader->SourceSocket = NB_SOCKET;
+#if !defined(_PNP_POWER)
+ RtlCopyMemory(IpxHeader->SourceNetwork, Device->Bind.Network, 4);
+ RtlCopyMemory(IpxHeader->SourceNode, Device->Bind.Node, 6);
+
+ Device->State = DEVICE_STATE_OPEN;
+#endif !_PNP_POWER
+
+
+ NbiFreeConfiguration(Config);
+
+#ifdef RASAUTODIAL
+ //
+ // Get the automatic connection
+ // driver entry points.
+ //
+ NbiAcdBind();
+#endif
+
+ return STATUS_SUCCESS;
+
+} /* DriverEntry */
+
+VOID
+NbiUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unloads the sample transport driver.
+ It unbinds from any NDIS drivers that are open and frees all resources
+ associated with the transport. The I/O system will not call us until
+ nobody above has Netbios open.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ None. When the function returns, the driver is unloaded.
+
+--*/
+
+{
+ PNETBIOS_CACHE CacheName;
+ PDEVICE Device = NbiDevice;
+ PLIST_ENTRY p;
+
+ UNREFERENCED_PARAMETER (DriverObject);
+
+
+#ifdef RASAUTODIAL
+ //
+ // Unbind from the
+ // automatic connection driver.
+ //
+ NbiAcdUnbind();
+#endif
+
+ Device->State = DEVICE_STATE_STOPPING;
+
+ //
+ // Free the cache of netbios names.
+ //
+
+ DestroyNetbiosCacheTable( Device->NameCache );
+
+ //
+ // Cancel the long timer.
+ //
+
+ if (CTEStopTimer (&Device->LongTimer)) {
+ NbiDereferenceDevice (Device, DREF_LONG_TIMER);
+ }
+
+ //
+ // Unbind from the IPX driver.
+ //
+
+ NbiUnbind (Device);
+
+ //
+ // This event will get set when the reference count
+ // drops to 0.
+ //
+
+ KeInitializeEvent(
+ &Device->UnloadEvent,
+ NotificationEvent,
+ FALSE);
+ Device->UnloadWaiting = TRUE;
+
+ //
+ // Remove the reference for us being loaded.
+ //
+
+ NbiDereferenceDevice (Device, DREF_LOADED);
+
+ //
+ // Wait for our count to drop to zero.
+ //
+
+ KeWaitForSingleObject(
+ &Device->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ //
+ // Do the cleanup that has to happen at IRQL 0.
+ //
+
+ ExDeleteResource (&Device->AddressResource);
+ IoDeleteDevice ((PDEVICE_OBJECT)Device);
+
+} /* NbiUnload */
+
+
+VOID
+NbiFreeResources (
+ IN PVOID Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by Netbios to clean up the data structures associated
+ with a given Device. When this routine exits, the Device
+ should be deleted as it no longer has any assocaited resources.
+
+Arguments:
+
+ Device - Pointer to the Device we wish to clean up.
+
+Return Value:
+
+ None.
+
+--*/
+{
+#if 0
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY s;
+ PTP_PACKET packet;
+ PNDIS_PACKET ndisPacket;
+ PBUFFER_TAG BufferTag;
+#endif
+
+
+#if 0
+ //
+ // Clean up packet pool.
+ //
+
+ while ( Device->PacketPool.Next != NULL ) {
+ s = PopEntryList( &Device->PacketPool );
+ packet = CONTAINING_RECORD( s, TP_PACKET, Linkage );
+
+ NbiDeallocateSendPacket (Device, packet);
+ }
+
+ //
+ // Clean up receive packet pool
+ //
+
+ while ( Device->ReceivePacketPool.Next != NULL) {
+ s = PopEntryList (&Device->ReceivePacketPool);
+
+ //
+ // HACK: This works because Linkage is the first field in
+ // ProtocolReserved for a receive packet.
+ //
+
+ ndisPacket = CONTAINING_RECORD (s, NDIS_PACKET, ProtocolReserved[0]);
+
+ NbiDeallocateReceivePacket (Device, ndisPacket);
+ }
+
+
+ //
+ // Clean up receive buffer pool.
+ //
+
+ while ( Device->ReceiveBufferPool.Next != NULL ) {
+ s = PopEntryList( &Device->ReceiveBufferPool );
+ BufferTag = CONTAINING_RECORD (s, BUFFER_TAG, Linkage );
+
+ NbiDeallocateReceiveBuffer (Device, BufferTag);
+ }
+
+#endif
+
+} /* NbiFreeResources */
+
+
+NTSTATUS
+NbiDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the IPXNB device driver.
+ It accepts an I/O Request Packet, performs the request, and then
+ returns with the appropriate status.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ NTSTATUS Status;
+ PFILE_FULL_EA_INFORMATION openType;
+ BOOLEAN found;
+ PADDRESS_FILE AddressFile;
+ PCONNECTION Connection;
+ PREQUEST Request;
+ UINT i;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+
+#if !defined(_PNP_POWER)
+ if (Device->State != DEVICE_STATE_OPEN) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+#endif !_PNP_POWER
+
+ //
+ // Allocate a request to track this IRP.
+ //
+
+ Request = NbiAllocateRequest (Device, Irp);
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ MARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = STATUS_PENDING;
+ REQUEST_INFORMATION(Request) = 0;
+
+ //
+ // Case on the function that is being performed by the requestor. If the
+ // operation is a valid one for this device, then make it look like it was
+ // successfully completed, where possible.
+ //
+
+
+ switch (REQUEST_MAJOR_FUNCTION(Request)) {
+
+ //
+ // The Create function opens a transport object (either address or
+ // connection). Access checking is performed on the specified
+ // address to ensure security of transport-layer addresses.
+ //
+
+ case IRP_MJ_CREATE:
+
+#if defined(_PNP_POWER)
+ if (Device->State != DEVICE_STATE_OPEN) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ break;
+ }
+#endif _PNP_POWER
+
+ openType = OPEN_REQUEST_EA_INFORMATION(Request);
+
+ if (openType != NULL) {
+
+ found = TRUE;
+
+ for (i=0;i<openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiTransportAddress[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = NbiOpenAddress (Device, Request);
+ break;
+ }
+
+ //
+ // Connection?
+ //
+
+ found = TRUE;
+
+ for (i=0;i<openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiConnectionContext[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = NbiOpenConnection (Device, Request);
+ break;
+ }
+
+ } else {
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)(Device->ControlChannelIdentifier);
+ ++Device->ControlChannelIdentifier;
+ if (Device->ControlChannelIdentifier == 0) {
+ Device->ControlChannelIdentifier = 1;
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_CONTROL_CHANNEL_FILE;
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case IRP_MJ_CLOSE:
+
+#if defined(_PNP_POWER)
+ if ( (Device->State != DEVICE_STATE_OPEN) && (Device->State != DEVICE_STATE_LOADED) ) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ break;
+ }
+#endif _PNP_POWER
+
+ //
+ // The Close function closes a transport endpoint, terminates
+ // all outstanding transport activity on the endpoint, and unbinds
+ // the endpoint from its transport address, if any. If this
+ // is the last transport endpoint bound to the address, then
+ // the address is removed from the provider.
+ //
+
+ switch ((ULONG)REQUEST_OPEN_TYPE(Request)) {
+
+ case TDI_TRANSPORT_ADDRESS_FILE:
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ //
+ // This creates a reference to AddressFile.
+ //
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile(AddressFile, CONFLICT_IS_OK);
+#else
+ Status = NbiVerifyAddressFile(AddressFile);
+#endif _PNP_POWER
+
+ if (!NT_SUCCESS (Status)) {
+ Status = STATUS_INVALID_HANDLE;
+ } else {
+ Status = NbiCloseAddressFile (Device, Request);
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ }
+
+ break;
+
+ case TDI_CONNECTION_FILE:
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ //
+ // We don't call VerifyConnection because the I/O
+ // system should only give us one close and the file
+ // object should be valid. This helps avoid a window
+ // where two threads call HandleConnectionZero at the
+ // same time.
+ //
+
+ Status = NbiCloseConnection (Device, Request);
+
+ break;
+
+ case TDI_CONTROL_CHANNEL_FILE:
+
+ //
+ // See if it is one of the upper driver's control channels.
+ //
+
+ Status = STATUS_SUCCESS;
+
+ break;
+
+ default:
+
+ Status = STATUS_INVALID_HANDLE;
+
+ }
+
+ break;
+
+ case IRP_MJ_CLEANUP:
+
+#if defined(_PNP_POWER)
+ if ( (Device->State != DEVICE_STATE_OPEN) && (Device->State != DEVICE_STATE_LOADED) ) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ break;
+ }
+#endif _PNP_POWER
+
+ //
+ // Handle the two stage IRP for a file close operation. When the first
+ // stage hits, run down all activity on the object of interest. This
+ // do everything to it but remove the creation hold. Then, when the
+ // CLOSE irp hits, actually close the object.
+ //
+
+ switch ((ULONG)REQUEST_OPEN_TYPE(Request)) {
+
+ case TDI_TRANSPORT_ADDRESS_FILE:
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile(AddressFile, CONFLICT_IS_OK);
+#else
+ Status = NbiVerifyAddressFile(AddressFile);
+#endif _PNP_POWER
+
+ if (!NT_SUCCESS (Status)) {
+
+ Status = STATUS_INVALID_HANDLE;
+
+ } else {
+
+ NbiStopAddressFile (AddressFile, AddressFile->Address);
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case TDI_CONNECTION_FILE:
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection(Connection);
+
+ if (!NT_SUCCESS (Status)) {
+
+ Status = STATUS_INVALID_HANDLE;
+
+ } else {
+
+ NB_BEGIN_SYNC (&SyncContext);
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ //
+ // This call releases the lock.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_INVALID_CONNECTION
+ NB_LOCK_HANDLE_ARG (LockHandle1));
+
+ NB_END_SYNC (&SyncContext);
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case TDI_CONTROL_CHANNEL_FILE:
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+
+ Status = STATUS_INVALID_HANDLE;
+
+ }
+
+ break;
+
+ default:
+
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ } /* major function switch */
+
+ if (Status != STATUS_PENDING) {
+ UNMARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = Status;
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ return Status;
+
+} /* NbiDispatchOpenClose */
+
+
+NTSTATUS
+NbiDispatchDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ //
+ // Branch to the appropriate request handler. Preliminary checking of
+ // the size of the request block is performed here so that it is known
+ // in the handlers that the minimum input parameters are readable. It
+ // is *not* determined here whether variable length input fields are
+ // passed correctly; this is a check which must be made within each routine.
+ //
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+
+ default:
+
+ //
+ // Convert the user call to the proper internal device call.
+ //
+
+ Status = TdiMapUserRequest (DeviceObject, Irp, IrpSp);
+
+ if (Status == STATUS_SUCCESS) {
+
+ //
+ // If TdiMapUserRequest returns SUCCESS then the IRP
+ // has been converted into an IRP_MJ_INTERNAL_DEVICE_CONTROL
+ // IRP, so we dispatch it as usual. The IRP will
+ // be completed by this call.
+ //
+
+ Status = NbiDispatchInternal (DeviceObject, Irp);
+
+ } else {
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ }
+
+ break;
+ }
+
+ return Status;
+
+} /* NbiDeviceControl */
+
+
+NB_TDI_DISPATCH_ROUTINE NbiDispatchInternalTable[] = {
+ NbiTdiAssociateAddress,
+ NbiTdiDisassociateAddress,
+ NbiTdiConnect,
+ NbiTdiListen,
+ NbiTdiAccept,
+ NbiTdiDisconnect,
+ NbiTdiSend,
+ NbiTdiReceive,
+ NbiTdiSendDatagram,
+ NbiTdiReceiveDatagram,
+ NbiTdiSetEventHandler,
+ NbiTdiQueryInformation,
+ NbiTdiSetInformation,
+ NbiTdiAction
+ };
+
+
+NTSTATUS
+NbiDispatchInternal(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PREQUEST Request;
+ UCHAR MinorFunction;
+
+ if (Device->State != DEVICE_STATE_OPEN) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+
+ //
+ // Allocate a request to track this IRP.
+ //
+
+ Request = NbiAllocateRequest (Device, Irp);
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ MARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = STATUS_PENDING;
+ REQUEST_INFORMATION(Request) = 0;
+
+
+ //
+ // Branch to the appropriate request handler.
+ //
+
+ MinorFunction = REQUEST_MINOR_FUNCTION(Request) - 1;
+
+ if (MinorFunction <= (TDI_ACTION-1)) {
+
+ Status = (*NbiDispatchInternalTable[MinorFunction]) (
+ Device,
+ Request);
+
+ } else {
+
+ NB_DEBUG (DRIVER, ("Unsupported minor code %d\n", MinorFunction+1));
+ if ((MinorFunction+1) == TDI_DISCONNECT) {
+ Status = STATUS_SUCCESS;
+ } else {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ }
+
+ if (Status != STATUS_PENDING) {
+ UNMARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = Status;
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ return Status;
+
+} /* NbiDispatchInternal */
+
+
+PVOID
+NbipAllocateMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN BOOLEAN ChargeDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory, making sure it is within
+ the limit allowed by the device.
+
+Arguments:
+
+ BytesNeeded - The number of bytes to allocated.
+
+ ChargeDevice - TRUE if the device should be charged.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PVOID Memory;
+ PDEVICE Device = NbiDevice;
+
+ if (ChargeDevice) {
+ if ((Device->MemoryLimit != 0) &&
+ (((LONG)(Device->MemoryUsage + BytesNeeded) >
+ Device->MemoryLimit))) {
+
+ NbiPrint1 ("Nbi: Could not allocate %d: limit\n", BytesNeeded);
+ NbiWriteResourceErrorLog (Device, BytesNeeded, Tag);
+ return NULL;
+ }
+ }
+
+#if ISN_NT
+ Memory = ExAllocatePoolWithTag (NonPagedPool, BytesNeeded, ' IBN');
+#else
+ Memory = CTEAllocMem (BytesNeeded);
+#endif
+
+ if (Memory == NULL) {
+
+ NbiPrint1("Nbi: Could not allocate %d: no pool\n", BytesNeeded);
+
+ if (ChargeDevice) {
+ NbiWriteResourceErrorLog (Device, BytesNeeded, Tag);
+ }
+
+ return NULL;
+ }
+
+ if (ChargeDevice) {
+ Device->MemoryUsage += BytesNeeded;
+ }
+
+ return Memory;
+
+} /* NbipAllocateMemory */
+
+
+VOID
+NbipFreeMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN BOOLEAN ChargeDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees memory allocated with NbipAllocateMemory.
+
+Arguments:
+
+ Memory - The memory allocated.
+
+ BytesAllocated - The number of bytes to freed.
+
+ ChargeDevice - TRUE if the device should be charged.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+
+#if ISN_NT
+ ExFreePool (Memory);
+#else
+ CTEFreeMem (Memory);
+#endif
+
+ if (ChargeDevice) {
+ Device->MemoryUsage -= BytesAllocated;
+ }
+
+} /* NbipFreeMemory */
+
+#if DBG
+
+
+PVOID
+NbipAllocateTaggedMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory, charging it to the device.
+ If it cannot allocate memory it uses the Tag and Descriptor
+ to log an error.
+
+Arguments:
+
+ BytesNeeded - The number of bytes to allocated.
+
+ Tag - A unique ID used in the error log.
+
+ Description - A text description of the allocation.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PVOID Memory;
+
+ UNREFERENCED_PARAMETER(Description);
+
+ Memory = NbipAllocateMemory(BytesNeeded, Tag, (BOOLEAN)(Tag != MEMORY_CONFIG));
+
+ if (Memory) {
+ ExInterlockedAddUlong(
+ &NbiMemoryTag[Tag].BytesAllocated,
+ BytesNeeded,
+ &NbiMemoryInterlock);
+ }
+
+ return Memory;
+
+} /* NbipAllocateTaggedMemory */
+
+
+VOID
+NbipFreeTaggedMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees memory allocated with NbipAllocateTaggedMemory.
+
+Arguments:
+
+ Memory - The memory allocated.
+
+ BytesAllocated - The number of bytes to freed.
+
+ Tag - A unique ID used in the error log.
+
+ Description - A text description of the allocation.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UNREFERENCED_PARAMETER(Description);
+
+ ExInterlockedAddUlong(
+ &NbiMemoryTag[Tag].BytesAllocated,
+ (ULONG)(-(LONG)BytesAllocated),
+ &NbiMemoryInterlock);
+
+ NbipFreeMemory (Memory, BytesAllocated, (BOOLEAN)(Tag != MEMORY_CONFIG));
+
+} /* NbipFreeTaggedMemory */
+
+#endif
+
+
+VOID
+NbiWriteResourceErrorLog(
+ IN PDEVICE Device,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ an out of resources condition.
+
+Arguments:
+
+ Device - Pointer to the device context.
+
+ BytesNeeded - If applicable, the number of bytes that could not
+ be allocated.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ PUCHAR StringLoc;
+ ULONG TempUniqueError;
+ static WCHAR UniqueErrorBuffer[4] = L"000";
+ INT i;
+
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ Device->DeviceNameLength +
+ sizeof(UniqueErrorBuffer);
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)Device,
+ EntrySize
+ );
+
+ //
+ // Convert the error value into a buffer.
+ //
+
+ TempUniqueError = UniqueErrorValue;
+ for (i=1; i>=0; i--) {
+ UniqueErrorBuffer[i] = (WCHAR)((TempUniqueError % 10) + L'0');
+ TempUniqueError /= 10;
+ }
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = sizeof(ULONG);
+ errorLogEntry->NumberOfStrings = 2;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = EVENT_TRANSPORT_RESOURCE_POOL;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+ errorLogEntry->DumpData[0] = BytesNeeded;
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
+
+ StringLoc += Device->DeviceNameLength;
+ RtlCopyMemory (StringLoc, UniqueErrorBuffer, sizeof(UniqueErrorBuffer));
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* NbiWriteResourceErrorLog */
+
+
+VOID
+NbiWriteGeneralErrorLog(
+ IN PDEVICE Device,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN ULONG DumpDataCount,
+ IN ULONG DumpData[]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ a general problem as indicated by the parameters. It handles
+ event codes REGISTER_FAILED, BINDING_FAILED, ADAPTER_NOT_FOUND,
+ TRANSFER_DATA, TOO_MANY_LINKS, and BAD_PROTOCOL. All these
+ events have messages with one or two strings in them.
+
+Arguments:
+
+ Device - Pointer to the device context, or this may be
+ a driver object instead.
+
+ ErrorCode - The transport event code.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet.
+
+ FinalStatus - Used as the FinalStatus in the error log packet.
+
+ SecondString - If not NULL, the string to use as the %3
+ value in the error log packet.
+
+ DumpDataCount - The number of ULONGs of dump data.
+
+ DumpData - Dump data for the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG SecondStringSize;
+ PUCHAR StringLoc;
+ static WCHAR DriverName[8] = L"NwlnkNb";
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ (DumpDataCount * sizeof(ULONG));
+
+ if (Device->Type == IO_TYPE_DEVICE) {
+ EntrySize += (UCHAR)Device->DeviceNameLength;
+ } else {
+ EntrySize += sizeof(DriverName);
+ }
+
+ if (SecondString) {
+ SecondStringSize = (wcslen(SecondString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize += (UCHAR)SecondStringSize;
+ }
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)Device,
+ EntrySize
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = (USHORT)(DumpDataCount * sizeof(ULONG));
+ errorLogEntry->NumberOfStrings = (SecondString == NULL) ? 1 : 2;
+ errorLogEntry->StringOffset =
+ sizeof(IO_ERROR_LOG_PACKET) + ((DumpDataCount-1) * sizeof(ULONG));
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ if (DumpDataCount) {
+ RtlCopyMemory(errorLogEntry->DumpData, DumpData, DumpDataCount * sizeof(ULONG));
+ }
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ if (Device->Type == IO_TYPE_DEVICE) {
+ RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
+ StringLoc += Device->DeviceNameLength;
+ } else {
+ RtlCopyMemory (StringLoc, DriverName, sizeof(DriverName));
+ StringLoc += sizeof(DriverName);
+ }
+ if (SecondString) {
+ RtlCopyMemory (StringLoc, SecondString, SecondStringSize);
+ }
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* NbiWriteGeneralErrorLog */
+
+
+VOID
+NbiWriteOidErrorLog(
+ IN PDEVICE Device,
+ IN NTSTATUS ErrorCode,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR AdapterString,
+ IN ULONG OidValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ a problem querying or setting an OID on an adapter. It handles
+ event codes SET_OID_FAILED and QUERY_OID_FAILED.
+
+Arguments:
+
+ Device - Pointer to the device context.
+
+ ErrorCode - Used as the ErrorCode in the error log packet.
+
+ FinalStatus - Used as the FinalStatus in the error log packet.
+
+ AdapterString - The name of the adapter we were bound to.
+
+ OidValue - The OID which could not be set or queried.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG AdapterStringSize;
+ PUCHAR StringLoc;
+ static WCHAR OidBuffer[9] = L"00000000";
+ INT i;
+ UINT CurrentDigit;
+
+ AdapterStringSize = (wcslen(AdapterString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) -
+ sizeof(ULONG) +
+ Device->DeviceNameLength +
+ AdapterStringSize +
+ sizeof(OidBuffer);
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)Device,
+ EntrySize
+ );
+
+ //
+ // Convert the OID into a buffer.
+ //
+
+ for (i=7; i>=0; i--) {
+ CurrentDigit = OidValue & 0xf;
+ OidValue >>= 4;
+ if (CurrentDigit >= 0xa) {
+ OidBuffer[i] = (WCHAR)(CurrentDigit - 0xa + L'A');
+ } else {
+ OidBuffer[i] = (WCHAR)(CurrentDigit + L'0');
+ }
+ }
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = 0;
+ errorLogEntry->NumberOfStrings = 3;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) - sizeof(ULONG);
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
+ StringLoc += Device->DeviceNameLength;
+
+ RtlCopyMemory (StringLoc, OidBuffer, sizeof(OidBuffer));
+ StringLoc += sizeof(OidBuffer);
+
+ RtlCopyMemory (StringLoc, AdapterString, AdapterStringSize);
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* NbiWriteOidErrorLog */
+
diff --git a/private/ntos/tdi/isnp/nb/event.c b/private/ntos/tdi/isnp/nb/event.c
new file mode 100644
index 000000000..f6cff7105
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/event.c
@@ -0,0 +1,117 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ event.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiSetEventHandler
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+PVOID TdiDefaultHandlers[6] = {
+ TdiDefaultConnectHandler,
+ TdiDefaultDisconnectHandler,
+ TdiDefaultErrorHandler,
+ TdiDefaultReceiveHandler,
+ TdiDefaultRcvDatagramHandler,
+ TdiDefaultRcvExpeditedHandler
+ };
+
+
+NTSTATUS
+NbiTdiSetEventHandler(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetEventHandler request for the
+ transport provider. The caller (request dispatcher) verifies
+ that this routine will not be executed on behalf of a user-mode
+ client, as this request enables direct callouts at DISPATCH_LEVEL.
+
+Arguments:
+
+ Device - The netbios device object.
+
+ Request - Pointer to the request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ CTELockHandle LockHandle;
+ PTDI_REQUEST_KERNEL_SET_EVENT Parameters;
+ PADDRESS_FILE AddressFile;
+ UINT EventType;
+
+ UNREFERENCED_PARAMETER (Device);
+
+ //
+ // Get the Address this is associated with; if there is none, get out.
+ //
+
+ AddressFile = REQUEST_OPEN_CONTEXT(Request);
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_OK);
+#else
+ Status = NbiVerifyAddressFile (AddressFile);
+#endif _PNP_POWER
+
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ NB_GET_LOCK (&AddressFile->Address->Lock, &LockHandle);
+
+ Parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)REQUEST_PARAMETERS(Request);
+ EventType = (UINT)(Parameters->EventType);
+
+ if (Parameters->EventType > TDI_EVENT_RECEIVE_EXPEDITED) {
+
+ Status = STATUS_INVALID_PARAMETER;
+
+ } else {
+
+ if (Parameters->EventHandler == NULL) {
+ AddressFile->RegisteredHandler[EventType] = FALSE;
+ AddressFile->Handlers[EventType] = TdiDefaultHandlers[EventType];
+ AddressFile->HandlerContexts[EventType] = NULL;
+ } else {
+ AddressFile->Handlers[EventType] = Parameters->EventHandler;
+ AddressFile->HandlerContexts[EventType] = Parameters->EventContext;
+ AddressFile->RegisteredHandler[EventType] = TRUE;
+ }
+
+ }
+
+ NB_FREE_LOCK (&AddressFile->Address->Lock, LockHandle);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiSetEventHandler */
+
diff --git a/private/ntos/tdi/isnp/nb/frame.c b/private/ntos/tdi/isnp/nb/frame.c
new file mode 100644
index 000000000..bbc14fd56
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/frame.c
@@ -0,0 +1,1095 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ frame.c
+
+Abstract:
+
+ This module contains code which creates and sends various
+ types of frames.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#if defined(_PNP_POWER)
+
+VOID
+NbiSendNameFrame(
+ IN PADDRESS Address OPTIONAL,
+ IN UCHAR NameTypeFlag,
+ IN UCHAR DataStreamType,
+ IN PIPX_LOCAL_TARGET LocalTarget OPTIONAL,
+ IN NB_CONNECTIONLESS UNALIGNED * ReqFrame OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a name frame on the
+ specified address. It handles add name, name in use, and
+ delete name frames.
+
+Arguments:
+
+ Address - The address on which the frame is sent. This will
+ be NULL if we are responding to a request to the
+ broadcast address.
+
+ NameTypeFlag - The name type flag to use.
+
+ DataStreamType - The type of the command.
+
+ LocalTarget - If specified, the local target to use for the
+ send (if not, it will be broadcast).
+
+ ReqFrame - If specified, the request frame for which this
+ response is being sent. The reqframe contains the
+ destination ipx address and the netbios name.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ IPX_LOCAL_TARGET TempLocalTarget;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->u.SR_NF.Address = Address; // may be NULL
+ Reserved->Type = SEND_TYPE_NAME_FRAME;
+
+ //
+ // Frame that are not sent to a specific address are
+ // sent to all valid NIC IDs.
+ //
+
+ if (!ARGUMENT_PRESENT(LocalTarget)) {
+ Reserved->u.SR_NF.NameTypeFlag = NameTypeFlag;
+ Reserved->u.SR_NF.DataStreamType = DataStreamType;
+ }
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ if (ARGUMENT_PRESENT(ReqFrame)) {
+ RtlCopyMemory((PVOID)&Header->IpxHeader.DestinationNetwork, (PVOID)ReqFrame->IpxHeader.SourceNetwork, 12);
+ }
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
+
+ if (ARGUMENT_PRESENT(LocalTarget)) {
+ Header->IpxHeader.PacketType = 0x04;
+ } else {
+ Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
+ }
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
+ Header->NameFrame.ConnectionControlFlag = 0x00;
+ Header->NameFrame.DataStreamType = DataStreamType;
+ Header->NameFrame.NameTypeFlag = NameTypeFlag;
+
+ //
+ // DataStreamType2 is the same as DataStreamType except for
+ // name in use frames where it is set to the add name type.
+ //
+
+ Header->NameFrame.DataStreamType2 = (UCHAR)
+ ((DataStreamType != NB_CMD_NAME_IN_USE) ? DataStreamType : NB_CMD_ADD_NAME);
+
+ RtlCopyMemory(
+ Header->NameFrame.Name,
+ Address ? Address->NetbiosAddress.NetbiosName : ReqFrame->NameFrame.Name,
+ 16);
+
+ if (Address) {
+ NbiReferenceAddress (Address, AREF_NAME_FRAME);
+ } else {
+ NbiReferenceDevice (Device, DREF_NAME_FRAME);
+ }
+
+ //
+ // Now send the frame (because it is all in the first segment,
+ // IPX will adjust the length of the buffer correctly).
+ //
+
+ if (!ARGUMENT_PRESENT(LocalTarget)) {
+ LocalTarget = &BroadcastTarget;
+ }
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) +
+ sizeof(NB_NAME_FRAME));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendNameFrame */
+#else
+
+VOID
+NbiSendNameFrame(
+ IN PADDRESS Address OPTIONAL,
+ IN UCHAR NameTypeFlag,
+ IN UCHAR DataStreamType,
+ IN PIPX_LOCAL_TARGET LocalTarget OPTIONAL,
+ IN TDI_ADDRESS_IPX UNALIGNED * DestAddress OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a name frame on the
+ specified address. It handles add name, name in use, and
+ delete name frames.
+
+Arguments:
+
+ Address - The address on which the frame is sent. This will
+ be NULL if we are responding to a request to the
+ broadcast address.
+
+ NameTypeFlag - The name type flag to use.
+
+ DataStreamType - The type of the command.
+
+ LocalTarget - If specified, the local target to use for the
+ send (if not, it will be broadcast).
+
+ DestAddress - If specified, the destination IPX address to
+ use for the send (if not, it will be broadcast on net 0).
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ IPX_LOCAL_TARGET TempLocalTarget;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->u.SR_NF.Address = Address; // may be NULL
+ Reserved->Type = SEND_TYPE_NAME_FRAME;
+
+ //
+ // Frame that are not sent to a specific address are
+ // sent to all valid NIC IDs.
+ //
+
+ if (!ARGUMENT_PRESENT(LocalTarget)) {
+ Reserved->u.SR_NF.CurrentNicId = 1;
+ Reserved->u.SR_NF.NameTypeFlag = NameTypeFlag;
+ Reserved->u.SR_NF.DataStreamType = DataStreamType;
+ } else {
+ Reserved->u.SR_NF.CurrentNicId = 0;
+ }
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ if (ARGUMENT_PRESENT(DestAddress)) {
+ RtlCopyMemory((PVOID)&Header->IpxHeader.DestinationNetwork, (PVOID)DestAddress, 12);
+ }
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
+
+ if (ARGUMENT_PRESENT(LocalTarget)) {
+ Header->IpxHeader.PacketType = 0x04;
+ } else {
+ Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
+ }
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
+ Header->NameFrame.ConnectionControlFlag = 0x00;
+ Header->NameFrame.DataStreamType = DataStreamType;
+ Header->NameFrame.NameTypeFlag = NameTypeFlag;
+
+ //
+ // DataStreamType2 is the same as DataStreamType except for
+ // name in use frames where it is set to the add name type.
+ //
+
+ Header->NameFrame.DataStreamType2 = (UCHAR)
+ ((DataStreamType != NB_CMD_NAME_IN_USE) ? DataStreamType : NB_CMD_ADD_NAME);
+
+ RtlCopyMemory(
+ Header->NameFrame.Name,
+ Address ? Address->NetbiosAddress.NetbiosName : NetbiosBroadcastName,
+ 16);
+
+ if (Address) {
+ NbiReferenceAddress (Address, AREF_NAME_FRAME);
+ } else {
+ NbiReferenceDevice (Device, DREF_NAME_FRAME);
+ }
+
+ //
+ // Now send the frame (because it is all in the first segment,
+ // IPX will adjust the length of the buffer correctly).
+ //
+
+ if (!ARGUMENT_PRESENT(LocalTarget)) {
+ TempLocalTarget.NicId = 1; // BUGBUG: What if 1 isn't valid?
+ RtlCopyMemory (TempLocalTarget.MacAddress, BroadcastAddress, 6);
+ LocalTarget = &TempLocalTarget;
+ }
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) +
+ sizeof(NB_NAME_FRAME));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendNameFrame */
+#endif _PNP_POWER
+
+
+VOID
+NbiSendSessionInitialize(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a session initialize
+ frame for the specified connection.
+
+Arguments:
+
+ Connection - The connection on which the frame is sent.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTION UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ PNB_SESSION_INIT SessionInitMemory;
+ PNDIS_BUFFER SessionInitBuffer;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ return;
+ }
+
+
+ //
+ // Allocate a buffer for the extra portion of the
+ // session initialize.
+ //
+
+ SessionInitMemory = (PNB_SESSION_INIT)NbiAllocateMemory(sizeof(NB_SESSION_INIT), MEMORY_CONNECTION, "Session Initialize");
+ if (!SessionInitMemory) {
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ return;
+ }
+
+ //
+ // Allocate an NDIS buffer to map the extra buffer.
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &SessionInitBuffer,
+ Device->NdisBufferPoolHandle,
+ SessionInitMemory,
+ sizeof(NB_SESSION_INIT));
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbiFreeMemory (SessionInitMemory, sizeof(NB_SESSION_INIT), MEMORY_CONNECTION, "Session Initialize");
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_INIT;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(NB_CONNECTION)+sizeof(NB_SESSION_INIT)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(NB_CONNECTION)+sizeof(NB_SESSION_INIT)) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ if (Device->Extensions) {
+ Header->Session.ConnectionControlFlag = NB_CONTROL_SEND_ACK | NB_CONTROL_NEW_NB;
+ } else {
+ Header->Session.ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+ }
+ Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = 0xffff;
+ Header->Session.SendSequence = 0;
+ Header->Session.TotalDataLength = sizeof(NB_SESSION_INIT);
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = sizeof(NB_SESSION_INIT);
+ Header->Session.ReceiveSequence = 0;
+ if (Device->Extensions) {
+ Header->Session.ReceiveSequenceMax = 1; // low estimate for the moment
+ } else {
+ Header->Session.BytesReceived = 0;
+ }
+
+ RtlCopyMemory (SessionInitMemory->SourceName, Connection->AddressFile->Address->NetbiosAddress.NetbiosName, 16);
+ RtlCopyMemory (SessionInitMemory->DestinationName, Connection->RemoteName, 16);
+
+ //
+ // BUGBUG: What exactly should I put here?
+ //
+
+ SessionInitMemory->MaximumDataSize = (USHORT)Connection->MaximumPacketSize;
+ SessionInitMemory->StartTripTime = (USHORT)
+ ((Device->InitialRetransmissionTime * (Device->KeepAliveCount+1)) / 500);
+ SessionInitMemory->MaximumPacketTime = SessionInitMemory->StartTripTime + 12;
+
+ //
+ // BUGBUG: Should we ref the connection? It doesn't
+ // really matter which we do.
+ //
+
+ NbiReferenceDevice (Device, DREF_SESSION_INIT);
+
+ NdisChainBufferAtBack (Packet, SessionInitBuffer);
+
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &Connection->LocalTarget,
+ Packet,
+ sizeof(NB_CONNECTION) + sizeof(NB_SESSION_INIT),
+ sizeof(NB_CONNECTION))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendSessionInitialize */
+
+
+VOID
+NbiSendSessionInitAck(
+ IN PCONNECTION Connection,
+ IN PUCHAR ExtraData,
+ IN ULONG ExtraDataLength,
+ IN CTELockHandle * LockHandle OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a session initialize ack
+ frame for the specified connection. If extra data was
+ specified in the session initialize frame it is echoed
+ back to the remote.
+
+Arguments:
+
+ Connection - The connection on which the frame is sent.
+
+ ExtraData - Any extra data (after the SESSION_INIT buffer)
+ in the frame.
+
+ ExtraDataLength - THe length of the extra data.
+
+ LockHandle - If specified, indicates the connection lock
+ is held and should be released. This is for cases
+ where the ExtraData is in memory which may be freed
+ once the connection lock is released.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTION UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ ULONG SessionInitBufferLength;
+ PNB_SESSION_INIT SessionInitMemory;
+ PNDIS_BUFFER SessionInitBuffer;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ if (ARGUMENT_PRESENT(LockHandle)) {
+ NB_FREE_LOCK (&Connection->Lock, *LockHandle);
+ }
+ return;
+ }
+
+
+ //
+ // Allocate a buffer for the extra portion of the
+ // session initialize.
+ //
+
+ SessionInitBufferLength = sizeof(NB_SESSION_INIT) + ExtraDataLength;
+ SessionInitMemory = (PNB_SESSION_INIT)NbiAllocateMemory(SessionInitBufferLength, MEMORY_CONNECTION, "Session Initialize");
+ if (!SessionInitMemory) {
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ if (ARGUMENT_PRESENT(LockHandle)) {
+ NB_FREE_LOCK (&Connection->Lock, *LockHandle);
+ }
+ return;
+ }
+
+ //
+ // Save the extra data, now we can free the lock.
+ //
+
+ if (ExtraDataLength != 0) {
+ RtlCopyMemory (SessionInitMemory+1, ExtraData, ExtraDataLength);
+ }
+ if (ARGUMENT_PRESENT(LockHandle)) {
+ NB_FREE_LOCK (&Connection->Lock, *LockHandle);
+ }
+
+ //
+ // Allocate an NDIS buffer to map the extra buffer.
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &SessionInitBuffer,
+ Device->NdisBufferPoolHandle,
+ SessionInitMemory,
+ SessionInitBufferLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbiFreeMemory (SessionInitMemory, SessionInitBufferLength, MEMORY_CONNECTION, "Session Initialize");
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_INIT;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(NB_CONNECTION)+SessionInitBufferLength) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(NB_CONNECTION)+SessionInitBufferLength) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ if (Connection->NewNetbios) {
+ Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM | NB_CONTROL_NEW_NB;
+ } else {
+ Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM;
+ }
+ CTEAssert (Connection->CurrentSend.SendSequence == 0);
+ CTEAssert (Connection->ReceiveSequence == 1);
+ Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = Connection->RemoteConnectionId;
+ Header->Session.SendSequence = 0;
+ Header->Session.TotalDataLength = (USHORT)SessionInitBufferLength;
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = (USHORT)SessionInitBufferLength;
+ Header->Session.ReceiveSequence = 1;
+ if (Connection->NewNetbios) {
+ Header->Session.ReceiveSequenceMax = Connection->LocalRcvSequenceMax;
+ } else {
+ Header->Session.BytesReceived = 0;
+ }
+
+ RtlCopyMemory (SessionInitMemory->SourceName, Connection->AddressFile->Address->NetbiosAddress.NetbiosName, 16);
+ RtlCopyMemory (SessionInitMemory->DestinationName, Connection->RemoteName, 16);
+
+ //
+ // BUGBUG: What exactly should I put here?
+ //
+
+ SessionInitMemory->MaximumDataSize = (USHORT)Connection->MaximumPacketSize;
+ SessionInitMemory->StartTripTime = (USHORT)
+ ((Device->InitialRetransmissionTime * (Device->KeepAliveCount+1)) / 500);
+ SessionInitMemory->MaximumPacketTime = SessionInitMemory->StartTripTime + 12;
+
+ //
+ // BUGBUG: Should we ref the connection? It doesn't
+ // really matter which we do.
+ //
+
+ NbiReferenceDevice (Device, DREF_SESSION_INIT);
+
+ NdisChainBufferAtBack (Packet, SessionInitBuffer);
+
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &Connection->LocalTarget,
+ Packet,
+ sizeof(NB_CONNECTION) + SessionInitBufferLength,
+ sizeof(NB_CONNECTION))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendSessionInitAck */
+
+
+VOID
+NbiSendDataAck(
+ IN PCONNECTION Connection,
+ IN NB_ACK_TYPE AckType
+ IN NB_LOCK_HANDLE_PARAM (LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a data ack frame.
+
+ THIS ROUTINE IS CALLED WITH THE LOCK HANDLE HELD AND
+ RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection on which the frame is sent.
+
+ AckType - Indicates if this is a query to the remote,
+ a response to a received probe, or a request to resend.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTION UNALIGNED * Header;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, try for the connection
+ // packet. If that's not available, that's OK since data
+ // acks are connectionless anyway.
+ //
+
+ if (s == NULL) {
+
+ if (!Connection->SendPacketInUse) {
+
+ Connection->SendPacketInUse = TRUE;
+ Packet = PACKET(&Connection->SendPacket);
+ Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+ }
+
+ } else {
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ }
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_NO_DATA;
+ Reserved->u.SR_CO.Connection = Connection;
+ Reserved->u.SR_CO.PacketLength = sizeof(NB_CONNECTION);
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = sizeof(NB_CONNECTION) / 256;
+ Header->IpxHeader.PacketLength[1] = sizeof(NB_CONNECTION) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ switch (AckType) {
+ case NbiAckQuery: Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM | NB_CONTROL_SEND_ACK; break;
+ case NbiAckResponse: Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM; break;
+ case NbiAckResend: Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM | NB_CONTROL_RESEND; break;
+ }
+ Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = Connection->RemoteConnectionId;
+ Header->Session.SendSequence = Connection->CurrentSend.SendSequence;
+ Header->Session.TotalDataLength = (USHORT)Connection->CurrentSend.MessageOffset;
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = 0;
+
+#if 0
+ //
+ // These are set by NbiAssignSequenceAndSend.
+ //
+
+ Header->Session.ReceiveSequence = Connection->ReceiveSequence;
+ Header->Session.BytesReceived = (USHORT)Connection->CurrentReceive.MessageOffset;
+#endif
+
+ NbiReferenceConnectionSync(Connection, CREF_FRAME);
+
+ //
+ // Set this so we will accept a probe from a remote without
+ // the send ack bit on. However if we receive such a request
+ // we turn this flag off until we get something else from the
+ // remote.
+ //
+
+ Connection->IgnoreNextDosProbe = FALSE;
+
+ Connection->ReceivesWithoutAck = 0;
+
+ //
+ // This frees the lock. IPX will adjust the length of
+ // the first buffer correctly.
+ //
+
+ NbiAssignSequenceAndSend(
+ Connection,
+ Packet
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+} /* NbiSendDataAck */
+
+
+VOID
+NbiSendSessionEnd(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a session end
+ frame for the specified connection.
+
+Arguments:
+
+ Connection - The connection on which the frame is sent.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTION UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_NO_DATA;
+ Reserved->u.SR_CO.Connection = Connection;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = sizeof(NB_CONNECTION) / 256;
+ Header->IpxHeader.PacketLength[1] = sizeof(NB_CONNECTION) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header. We don't advance the
+ // send pointer, since it is the last frame of the session
+ // and we want it to stay the same in the case of resends.
+ //
+
+ Header->Session.ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+ Header->Session.DataStreamType = NB_CMD_SESSION_END;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = Connection->RemoteConnectionId;
+ Header->Session.SendSequence = Connection->CurrentSend.SendSequence;
+ Header->Session.TotalDataLength = 0;
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = 0;
+ Header->Session.ReceiveSequence = Connection->ReceiveSequence;
+ if (Connection->NewNetbios) {
+ Header->Session.ReceiveSequenceMax = Connection->LocalRcvSequenceMax;
+ } else {
+ Header->Session.BytesReceived = 0;
+ }
+
+ NbiReferenceConnection (Connection, CREF_FRAME);
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &Connection->LocalTarget,
+ Packet,
+ sizeof(NB_CONNECTION),
+ sizeof(NB_CONNECTION))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendSessionEnd */
+
+
+VOID
+NbiSendSessionEndAck(
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN NB_SESSION UNALIGNED * SessionEnd
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a session end
+ frame. Generally it is sent on a connection but we
+ are not tied to that, to allow us to respond to
+ session ends from unknown remotes.
+
+Arguments:
+
+ RemoteAddress - The remote IPX address.
+
+ LocalTarget - The local target of the remote.
+
+ SessionEnd - The received session end frame.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTION UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_NO_DATA;
+ Reserved->u.SR_CO.Connection = NULL;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ RtlCopyMemory(&Header->IpxHeader.DestinationNetwork, (PVOID)RemoteAddress, 12);
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(NB_CONNECTION)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(NB_CONNECTION)) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ Header->Session.ConnectionControlFlag = 0x00;
+ Header->Session.DataStreamType = NB_CMD_SESSION_END_ACK;
+ Header->Session.SourceConnectionId = SessionEnd->DestConnectionId;
+ Header->Session.DestConnectionId = SessionEnd->SourceConnectionId;
+ Header->Session.SendSequence = SessionEnd->ReceiveSequence;
+ Header->Session.TotalDataLength = 0;
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = 0;
+ if (SessionEnd->BytesReceived != 0) { // BUGBUG: Will this detect new netbios?
+ Header->Session.ReceiveSequence = SessionEnd->SendSequence + 1;
+ Header->Session.ReceiveSequenceMax = SessionEnd->SendSequence + 3;
+ } else {
+ Header->Session.ReceiveSequence = SessionEnd->SendSequence;
+ Header->Session.BytesReceived = 0;
+ }
+
+ NbiReferenceDevice (Device, DREF_FRAME);
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ sizeof(NB_CONNECTION),
+ sizeof(NB_CONNECTION))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendSessionEndAck */
+
diff --git a/private/ntos/tdi/isnp/nb/isnnb.h b/private/ntos/tdi/isnp/nb/isnnb.h
new file mode 100644
index 000000000..2d142e346
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/isnnb.h
@@ -0,0 +1,787 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ isnnb.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+#define NB_MAXIMUM_MAC 40
+
+#define NB_SOCKET 0x5504
+
+#if defined(_PNP_POWER)
+#define NB_NETBIOS_NAME_SIZE 16
+
+#define LOCK_ACQUIRED TRUE
+#define LOCK_NOT_ACQUIRED FALSE
+#endif _PNP_POWER
+
+//
+// Defined granularity of find name timeouts in milliseconds --
+// we make this the same as the spec'ed RIP gap to avoid
+// flooding routers.
+//
+
+#define FIND_NAME_GRANULARITY 55
+
+
+//
+// Defines the number of milliseconds between expirations of the
+// short and long timers.
+//
+
+#define MILLISECONDS 10000 // number of NT time units in one
+
+#define SHORT_TIMER_DELTA 100
+#define LONG_TIMER_DELTA 2000
+
+
+//
+// Convert a ushort netware order <-> machine order
+//
+
+#define REORDER_USHORT(_Ushort) ((((_Ushort) & 0xff00) >> 8) | (((_Ushort) & 0x00ff) << 8))
+
+//
+// Convert a ulong netware order <-> machine order
+//
+
+#define REORDER_ULONG(_Ulong) \
+ ((((_Ulong) & 0xff000000) >> 24) | \
+ (((_Ulong) & 0x00ff0000) >> 8) | \
+ (((_Ulong) & 0x0000ff00) << 8) | \
+ (((_Ulong) & 0x000000ff) << 24))
+
+
+
+#include <packon.h>
+
+//
+// Definition of the IPX header.
+//
+
+typedef struct _IPX_HEADER {
+ USHORT CheckSum;
+ UCHAR PacketLength[2];
+ UCHAR TransportControl;
+ UCHAR PacketType;
+ UCHAR DestinationNetwork[4];
+ UCHAR DestinationNode[6];
+ USHORT DestinationSocket;
+ UCHAR SourceNetwork[4];
+ UCHAR SourceNode[6];
+ USHORT SourceSocket;
+} IPX_HEADER, *PIPX_HEADER;
+
+
+//
+// Definition of the Netbios header for name frames.
+//
+
+typedef struct _NB_NAME_FRAME {
+ union {
+ struct {
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ };
+ UCHAR RoutingInfo[32];
+ };
+ UCHAR NameTypeFlag;
+ UCHAR DataStreamType2;
+ UCHAR Name[16];
+} NB_NAME_FRAME, *PNB_NAME_FRAME;
+
+//
+// Definition of the Netbios header for directed datagrams.
+//
+
+typedef struct _NB_DATAGRAM {
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ UCHAR SourceName[16];
+ UCHAR DestinationName[16];
+} NB_DATAGRAM, *PNB_DATAGRAM;
+
+//
+// Definition of the Netbios header for a status query.
+//
+
+typedef struct _NB_STATUS_QUERY {
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ UCHAR Padding[14];
+} NB_STATUS_QUERY, *PNB_STATUS_QUERY;
+
+//
+// Definition of the Netbios header for a status response
+// (this does not include the status buffer itself).
+//
+
+typedef struct _NB_STATUS_RESPONSE {
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+} NB_STATUS_RESPONSE, *PNB_STATUS_RESPONSE;
+
+
+//
+// Definition of the general Netbios connectionless header.
+//
+
+typedef struct _NB_CONNECTIONLESS {
+ IPX_HEADER IpxHeader;
+ union {
+ NB_NAME_FRAME NameFrame;
+ NB_DATAGRAM Datagram;
+ NB_STATUS_QUERY StatusQuery;
+ NB_STATUS_RESPONSE StatusResponse;
+ };
+} NB_CONNECTIONLESS, *PNB_CONNECTIONLESS;
+
+
+//
+// Definition of the Netbios session frame.
+//
+
+typedef struct _NB_SESSION {
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ USHORT SourceConnectionId;
+ USHORT DestConnectionId;
+ USHORT SendSequence;
+ USHORT TotalDataLength;
+ USHORT Offset;
+ USHORT DataLength;
+ USHORT ReceiveSequence;
+ union {
+ USHORT BytesReceived;
+ USHORT ReceiveSequenceMax;
+ };
+} NB_SESSION, *PNB_SESSION;
+
+
+//
+// Definition of the extra fields in a Netbios
+// session frame for session init and session init
+// ack.
+//
+
+typedef struct _NB_SESSION_INIT {
+ UCHAR SourceName[16];
+ UCHAR DestinationName[16];
+ USHORT MaximumDataSize;
+ USHORT MaximumPacketTime;
+ USHORT StartTripTime;
+} NB_SESSION_INIT, *PNB_SESSION_INIT;
+
+
+//
+// Definition of the general Netbios connection-oriented header.
+//
+
+typedef struct _NB_CONNECTION {
+ IPX_HEADER IpxHeader;
+ NB_SESSION Session;
+} NB_CONNECTION, *PNB_CONNECTION;
+
+
+//
+// Definition of a Netbios packet.
+//
+
+typedef union _NB_FRAME {
+ NB_CONNECTIONLESS Connectionless;
+ NB_CONNECTION Connection;
+} NB_FRAME, *PNB_FRAME;
+
+#include <packoff.h>
+
+
+//
+// Definitions for the DataStreamType field, with the
+// format used shown in the comment afterward.
+//
+
+#define NB_CMD_FIND_NAME 0x01 // NAME_FRAME
+#define NB_CMD_NAME_RECOGNIZED 0x02 // NAME_FRAME
+#define NB_CMD_ADD_NAME 0x03 // NAME_FRAME
+#define NB_CMD_NAME_IN_USE 0x04 // NAME_FRAME
+#define NB_CMD_DELETE_NAME 0x05 // NAME_FRAME
+#define NB_CMD_SESSION_DATA 0x06 // SESSION
+#define NB_CMD_SESSION_END 0x07 // SESSION
+#define NB_CMD_SESSION_END_ACK 0x08 // SESSION
+#define NB_CMD_STATUS_QUERY 0x09 // STATUS_QUERY
+#define NB_CMD_STATUS_RESPONSE 0x0a // STATUS_RESPONSE
+#define NB_CMD_DATAGRAM 0x0b // DATAGRAM
+#define NB_CMD_BROADCAST_DATAGRAM 0x0c // BROADCAST_DATAGRAM
+
+#ifdef RSRC_TIMEOUT_DBG
+#define NB_CMD_DEATH_PACKET 0x99 //
+#endif // RSRC_TIMEOUT_DBG
+
+//
+// Bit values in the NameTypeFlag of NB_NAME_FRAME frames.
+//
+
+#define NB_NAME_UNIQUE 0x00
+#define NB_NAME_GROUP 0x80
+#define NB_NAME_USED 0x40
+#define NB_NAME_REGISTERED 0x04
+#define NB_NAME_DUPLICATED 0x02
+#define NB_NAME_DEREGISTERED 0x01
+
+//
+// Bit values in the ConnectionControlFlag.
+//
+
+#define NB_CONTROL_SYSTEM 0x80
+#define NB_CONTROL_SEND_ACK 0x40
+#define NB_CONTROL_ATTENTION 0x20
+#define NB_CONTROL_EOM 0x10
+#define NB_CONTROL_RESEND 0x08
+#define NB_CONTROL_NEW_NB 0x01
+
+
+
+#define NB_DEVICE_SIGNATURE 0x1401
+#if defined(_PNP_POWER)
+#define NB_ADAPTER_ADDRESS_SIGNATURE 0x1403
+#endif _PNP_POWER
+#define NB_ADDRESS_SIGNATURE 0x1404
+#define NB_ADDRESSFILE_SIGNATURE 0x1405
+#define NB_CONNECTION_SIGNATURE 0x1406
+
+
+//
+// Useful in various places.
+//
+#if defined(_PNP_POWER)
+extern IPX_LOCAL_TARGET BroadcastTarget;
+#endif _PNP_POWER
+extern UCHAR BroadcastAddress[6];
+extern UCHAR NetbiosBroadcastName[16];
+
+
+//
+// Contains the default handler for each of the TDI event types
+// that are supported.
+//
+
+extern PVOID TdiDefaultHandlers[6];
+
+
+//
+// Define a structure that can track lock acquire/release.
+//
+
+typedef struct _NB_LOCK {
+ CTELock Lock;
+#if DBG
+ ULONG LockAcquired;
+ UCHAR LastAcquireFile[8];
+ ULONG LastAcquireLine;
+ UCHAR LastReleaseFile[8];
+ ULONG LastReleaseLine;
+#endif
+} NB_LOCK, *PNB_LOCK;
+
+
+
+#if DBG
+
+extern ULONG NbiDebug;
+extern ULONG NbiDebug2;
+extern ULONG NbiMemoryDebug;
+
+#define NB_MEMORY_LOG_SIZE 128
+extern UCHAR NbiDebugMemory[NB_MEMORY_LOG_SIZE][64];
+extern PUCHAR NbiDebugMemoryLoc;
+extern PUCHAR NbiDebugMemoryEnd;
+
+VOID
+NbiDebugMemoryLog(
+ IN PUCHAR FormatString,
+ ...
+);
+
+#define NB_DEBUG(_Flag, _Print) { \
+ if (NbiDebug & (NB_DEBUG_ ## _Flag)) { \
+ DbgPrint ("NBI: "); \
+ DbgPrint _Print; \
+ } \
+ if (NbiMemoryDebug & (NB_DEBUG_ ## _Flag)) { \
+ NbiDebugMemoryLog _Print; \
+ } \
+}
+
+#define NB_DEBUG2(_Flag, _Print) { \
+ if (NbiDebug2 & (NB_DEBUG_ ## _Flag)) { \
+ DbgPrint ("NBI: "); \
+ DbgPrint _Print; \
+ } \
+ if (NbiMemoryDebug & (NB_DEBUG_ ## _Flag)) { \
+ NbiDebugMemoryLog _Print; \
+ } \
+}
+
+#else
+
+#define NB_DEBUG(_Flag, _Print)
+#define NB_DEBUG2(_Flag, _Print)
+
+#endif
+
+
+//
+// These definitions are for abstracting IRPs from the
+// transport for portability.
+//
+
+#if ISN_NT
+
+typedef IRP REQUEST, *PREQUEST;
+typedef struct _REQUEST_LIST_HEAD {
+ PREQUEST Head; // list is empty if this is NULL
+ PREQUEST Tail; // undefined if the list is empty.
+} REQUEST_LIST_HEAD, *PREQUEST_LIST_HEAD;
+
+
+//
+// PREQUEST
+// NbiAllocateRequest(
+// IN PDEVICE Device,
+// IN PIRP Irp
+// );
+//
+// Allocates a request for the system-specific request structure.
+//
+
+#define NbiAllocateRequest(_Device,_Irp) \
+ (_Irp)
+
+
+//
+// BOOLEAN
+// IF_NOT_ALLOCATED(
+// IN PREQUEST Request
+// );
+//
+// Checks if a request was not successfully allocated.
+//
+
+#define IF_NOT_ALLOCATED(_Request) \
+ if (0)
+
+
+//
+// VOID
+// NbiFreeRequest(
+// IN PDEVICE Device,
+// IN PREQUEST Request
+// );
+//
+// Frees a previously allocated request.
+//
+
+#define NbiFreeRequest(_Device,_Request) \
+ ;
+
+
+//
+// VOID
+// MARK_REQUEST_PENDING(
+// IN PREQUEST Request
+// );
+//
+// Marks that a request will pend.
+//
+
+#define MARK_REQUEST_PENDING(_Request) \
+ IoMarkIrpPending(_Request)
+
+
+//
+// VOID
+// UNMARK_REQUEST_PENDING(
+// IN PREQUEST Request
+// );
+//
+// Marks that a request will not pend.
+//
+
+#define UNMARK_REQUEST_PENDING(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->Control) &= ~SL_PENDING_RETURNED)
+
+
+//
+// UCHAR
+// REQUEST_MAJOR_FUNCTION
+// IN PREQUEST Request
+// );
+//
+// Returns the major function code of a request.
+//
+
+#define REQUEST_MAJOR_FUNCTION(_Request) \
+ ((IoGetCurrentIrpStackLocation(_Request))->MajorFunction)
+
+
+//
+// UCHAR
+// REQUEST_MINOR_FUNCTION
+// IN PREQUEST Request
+// );
+//
+// Returns the minor function code of a request.
+//
+
+#define REQUEST_MINOR_FUNCTION(_Request) \
+ ((IoGetCurrentIrpStackLocation(_Request))->MinorFunction)
+
+
+//
+// PNDIS_BUFFER
+// REQUEST_NDIS_BUFFER
+// IN PREQUEST Request
+// );
+//
+// Returns the NDIS buffer chain associated with a request.
+//
+
+#define REQUEST_NDIS_BUFFER(_Request) \
+ ((PNDIS_BUFFER)((_Request)->MdlAddress))
+
+
+//
+// PVOID
+// REQUEST_OPEN_CONTEXT(
+// IN PREQUEST Request
+// );
+//
+// Gets the context associated with an opened address/connection/control channel.
+//
+
+#define REQUEST_OPEN_CONTEXT(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->FileObject)->FsContext)
+
+
+//
+// PVOID
+// REQUEST_OPEN_TYPE(
+// IN PREQUEST Request
+// );
+//
+// Gets the type associated with an opened address/connection/control channel.
+//
+
+#define REQUEST_OPEN_TYPE(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->FileObject)->FsContext2)
+
+
+//
+// PFILE_FULL_EA_INFORMATION
+// OPEN_REQUEST_EA_INFORMATION(
+// IN PREQUEST Request
+// );
+//
+// Returns the EA information associated with an open/close request.
+//
+
+#define OPEN_REQUEST_EA_INFORMATION(_Request) \
+ ((PFILE_FULL_EA_INFORMATION)((_Request)->AssociatedIrp.SystemBuffer))
+
+
+//
+// PTDI_REQUEST_KERNEL
+// REQUEST_PARAMETERS(
+// IN PREQUEST Request
+// );
+//
+// Obtains a pointer to the parameters of a request.
+//
+
+#define REQUEST_PARAMETERS(_Request) \
+ (&((IoGetCurrentIrpStackLocation(_Request))->Parameters))
+
+
+//
+// PLIST_ENTRY
+// REQUEST_LINKAGE(
+// IN PREQUEST Request
+// );
+//
+// Returns a pointer to a linkage field in the request.
+//
+
+#define REQUEST_LINKAGE(_Request) \
+ (&((_Request)->Tail.Overlay.ListEntry))
+
+
+//
+// PREQUEST
+// REQUEST_SINGLE_LINKAGE(
+// IN PREQUEST Request
+// );
+//
+// Used to access a single list linkage field in the request.
+//
+
+#define REQUEST_SINGLE_LINKAGE(_Request) \
+ (*((PREQUEST *)&((_Request)->Tail.Overlay.ListEntry.Flink)))
+
+
+//
+// ULONG
+// REQUEST_REFCOUNT(
+// IN PREQUEST Request
+// );
+//
+// Used to access a field in the request which can be used for
+// the reference count, as long as it is on a REQUEST_LIST.
+//
+
+#define REQUEST_REFCOUNT(_Request) \
+ (*((PULONG)&((_Request)->Tail.Overlay.ListEntry.Blink)))
+
+
+//
+// VOID
+// REQUEST_LIST_INSERT_TAIL(
+// IN PREQUEST_LIST_HEAD Head,
+// IN PREQUEST Entry
+// );
+//
+// Inserts a request into a single list linkage queue.
+//
+
+#define REQUEST_LIST_INSERT_TAIL(_Head,_Entry) { \
+ if ((_Head)->Head == NULL) { \
+ (_Head)->Head = (_Entry); \
+ (_Head)->Tail = (_Entry); \
+ } else { \
+ REQUEST_SINGLE_LINKAGE((_Head)->Tail) = (_Entry); \
+ (_Head)->Tail = (_Entry); \
+ } \
+}
+
+
+//
+// PREQUEST
+// LIST_ENTRY_TO_REQUEST(
+// IN PLIST_ENTRY ListEntry
+// );
+//
+// Returns a request given a linkage field in it.
+//
+
+#define LIST_ENTRY_TO_REQUEST(_ListEntry) \
+ ((PREQUEST)(CONTAINING_RECORD(_ListEntry, REQUEST, Tail.Overlay.ListEntry)))
+
+
+//
+// NTSTATUS
+// REQUEST_STATUS(
+// IN PREQUEST Request
+// );
+//
+// Used to access the status field of a request.
+//
+
+#define REQUEST_STATUS(_Request) \
+ (_Request)->IoStatus.Status
+
+
+//
+// ULONG
+// REQUEST_INFORMATION(
+// IN PREQUEST Request)
+// );
+//
+// Used to access the information field of a request.
+//
+
+#define REQUEST_INFORMATION(_Request) \
+ (_Request)->IoStatus.Information
+
+
+//
+// VOID
+// NbiCompleteRequest(
+// IN PREQUEST Request
+// );
+//
+// Completes a request whose status and information fields have
+// been filled in.
+//
+
+#define NbiCompleteRequest(_Request) \
+ IoCompleteRequest (_Request, IO_NETWORK_INCREMENT)
+
+#else
+
+//
+// These routines must be defined for portability to a VxD.
+//
+
+#endif
+
+//
+// some utility macros.
+
+// Minimum of two
+//
+#define NB_MIN( _a , _b ) ( ( (_a) < (_b) ) ? (_a) : (_b) )
+
+//
+// Swap the _s1 and _s2 of Type _T
+//
+
+#define NB_SWAP(_s1, _s2, _T) { \
+ _T _temp; \
+ _temp = (_s1); \
+ (_s1) = (_s2); \
+ (_s2) = _temp; \
+}
+
+#define NB_SWAP_IRQL( _s1, _s2 ) NB_SWAP( _s1, _s2, CTELockHandle )
+
+//
+// Define our own spinlock routines.
+//
+
+#if DBG
+
+#define NB_GET_LOCK(_Lock, _LockHandle) { \
+ CTEGetLock(&(_Lock)->Lock, _LockHandle); \
+ (_Lock)->LockAcquired = TRUE; \
+ strncpy((_Lock)->LastAcquireFile, strrchr(__FILE__,'\\')+1, 7); \
+ (_Lock)->LastAcquireLine = __LINE__; \
+}
+
+#define NB_FREE_LOCK(_Lock, _LockHandle) { \
+ (_Lock)->LockAcquired = FALSE; \
+ strncpy((_Lock)->LastReleaseFile, strrchr(__FILE__,'\\')+1, 7); \
+ (_Lock)->LastReleaseLine = __LINE__; \
+ CTEFreeLock(&(_Lock)->Lock, _LockHandle); \
+}
+
+#define NB_GET_LOCK_DPC(_Lock) { \
+ ExAcquireSpinLockAtDpcLevel(&(_Lock)->Lock); \
+ (_Lock)->LockAcquired = TRUE; \
+ strncpy((_Lock)->LastAcquireFile, strrchr(__FILE__,'\\')+1, 7); \
+ (_Lock)->LastAcquireLine = __LINE__; \
+}
+
+#define NB_FREE_LOCK_DPC(_Lock) { \
+ (_Lock)->LockAcquired = FALSE; \
+ strncpy((_Lock)->LastReleaseFile, strrchr(__FILE__,'\\')+1, 7); \
+ (_Lock)->LastReleaseLine = __LINE__; \
+ ExReleaseSpinLockFromDpcLevel(&(_Lock)->Lock); \
+}
+
+#else
+
+#define NB_GET_LOCK(_Lock, _LockHandle) CTEGetLock(&(_Lock)->Lock, _LockHandle)
+#define NB_FREE_LOCK(_Lock, _LockHandle) CTEFreeLock(&(_Lock)->Lock, _LockHandle)
+#define NB_GET_LOCK_DPC(_Lock) ExAcquireSpinLockAtDpcLevel(&(_Lock)->Lock)
+#define NB_FREE_LOCK_DPC(_Lock) ExReleaseSpinLockFromDpcLevel(&(_Lock)->Lock)
+
+#endif
+
+
+#define NB_GET_CANCEL_LOCK( _LockHandle ) IoAcquireCancelSpinLock( _LockHandle )
+
+#define NB_FREE_CANCEL_LOCK( _LockHandle ) IoReleaseCancelSpinLock( _LockHandle )
+
+
+//
+// Routines to optimize for a uni-processor environment.
+//
+
+
+#define NB_INCREMENT(_Long, _Lock) InterlockedIncrement(_Long)
+#define NB_DECREMENT(_Long, _Lock) InterlockedDecrement(_Long)
+
+#define NB_ADD_ULONG(_Pulong, _Ulong, _Lock) ExInterlockedAddUlong(_Pulong, _Ulong, &(_Lock)->Lock)
+
+#define NB_DEFINE_SYNC_CONTEXT(_SyncContext)
+#define NB_BEGIN_SYNC(_SyncContext)
+#define NB_END_SYNC(_SyncContext)
+
+#define NB_DEFINE_LOCK_HANDLE(_LockHandle) CTELockHandle _LockHandle;
+
+//
+// BUGBUG: Make these be NB_XXX_LOCK_DPC calls -- then the definitions
+// of the NB_SYNC_XXX_LOCK calls can be changed to not need _LockHandle
+// and many of the functions won't need that as a parameter.
+//
+
+#define NB_SYNC_GET_LOCK(_Lock, _LockHandle) NB_GET_LOCK(_Lock, _LockHandle)
+#define NB_SYNC_FREE_LOCK(_Lock, _LockHandle) NB_FREE_LOCK(_Lock, _LockHandle)
+
+#define NB_REMOVE_HEAD_LIST(_Queue, _Lock) ExInterlockedRemoveHeadList(_Queue, &(_Lock)->Lock)
+#define NB_LIST_WAS_EMPTY(_Queue, _OldHead) ((_OldHead) == NULL)
+#define NB_INSERT_HEAD_LIST(_Queue, _Entry, _Lock) ExInterlockedInsertHeadList(_Queue, _Entry, &(_Lock)->Lock)
+#define NB_INSERT_TAIL_LIST(_Queue, _Entry, _Lock) ExInterlockedInsertTailList(_Queue, _Entry, &(_Lock)->Lock)
+
+#define NB_POP_ENTRY_LIST(_Queue, _Lock) ExInterlockedPopEntryList(_Queue, &(_Lock)->Lock)
+#define NB_PUSH_ENTRY_LIST(_Queue, _Entry, _Lock) ExInterlockedPushEntryList(_Queue, _Entry, &(_Lock)->Lock)
+
+#define NB_LOCK_HANDLE_PARAM(_LockHandle) , IN CTELockHandle _LockHandle
+#define NB_LOCK_HANDLE_ARG(_LockHandle) , (_LockHandle)
+
+#define NB_SYNC_SWAP_IRQL( _s1, _s2 ) NB_SWAP( _s1, _s2, CTELockHandle )
+
+
+//
+// This macro adds a ULONG to a LARGE_INTEGER (should be
+// called with a spinlock held).
+//
+
+#define ADD_TO_LARGE_INTEGER(_LargeInteger,_Ulong) \
+ ExInterlockedAddLargeStatistic((_LargeInteger),(ULONG)(_Ulong))
+
+#define NB_DEBUG_DEVICE 0x00000001
+#define NB_DEBUG_ADDRESS 0x00000004
+#define NB_DEBUG_SEND 0x00000008
+#define NB_DEBUG_RECEIVE 0x00000020
+#define NB_DEBUG_CONFIG 0x00000040
+#define NB_DEBUG_PACKET 0x00000080
+#define NB_DEBUG_BIND 0x00000200
+#define NB_DEBUG_ADDRESS_FRAME 0x00000400
+#define NB_DEBUG_CONNECTION 0x00000800
+#define NB_DEBUG_QUERY 0x00001000
+#define NB_DEBUG_DRIVER 0x00002000
+#define NB_DEBUG_CACHE 0x00004000
+#define NB_DEBUG_DATAGRAM 0x00008000
+#define NB_DEBUG_TIMER 0x00010000
+#define NB_DEBUG_SEND_WINDOW 0x00020000
+
+
+
+//
+// NB_GET_NBHDR_BUFF - gets the nb header in the packet. It is always the
+// second buffer.
+//
+#define NB_GET_NBHDR_BUFF(Packet) (NDIS_BUFFER_LINKAGE((Packet)->Private.Head))
+
+
diff --git a/private/ntos/tdi/isnp/nb/mp/makefile b/private/ntos/tdi/isnp/nb/mp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/mp/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isnp/nb/mp/sources b/private/ntos/tdi/isnp/nb/mp/sources
new file mode 100644
index 000000000..dc48d81bb
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/mp/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+NT_UP=0
+
+TARGETPATH=\nt\public\sdk\lib
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/isnp/nb/nbcount/makefile b/private/ntos/tdi/isnp/nb/nbcount/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/nbcount/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isnp/nb/nbcount/nbcount.c b/private/ntos/tdi/isnp/nb/nbcount/nbcount.c
new file mode 100644
index 000000000..74a656f16
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/nbcount/nbcount.c
@@ -0,0 +1,177 @@
+/****************************************************************************
+* (c) Copyright 1990, 1993 Micro Computer Systems, Inc. All rights reserved.
+*****************************************************************************
+*
+* Title: IPX/SPX Compatible Source Routing Daemon for Windows NT
+*
+* Module: ipx/route/ipxroute.c
+*
+* Version: 1.00.00
+*
+* Date: 04-08-93
+*
+* Author: Brian Walker
+*
+*****************************************************************************
+*
+* Change Log:
+*
+* Date DevSFC Comment
+* -------- ------ -------------------------------------------------------
+*****************************************************************************
+*
+* Functional Description:
+*
+*
+****************************************************************************/
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <process.h>
+#include <ntstapi.h>
+#include <sys/stropts.h>
+#include <windows.h>
+#include "errno.h"
+#include "tdi.h"
+#include "isnkrnl.h"
+
+
+typedef struct _NB_ACTION_GET_COUNTS {
+ USHORT MaximumNicId; // returns maximum NIC ID
+ USHORT NicIdCounts[32]; // session counts for first 32 NIC IDs
+} NB_ACTION_GET_COUNTS, *PNB_ACTION_GET_COUNTS;
+
+HANDLE isnnbfd;
+wchar_t isnnbname[] = L"\\Device\\NwlnkNb";
+char pgmname[] = "NBCOUNT";
+
+/** **/
+
+#define INVALID_HANDLE (HANDLE)(-1)
+
+int do_isnnbioctl(HANDLE fd, int cmd, char *datap, int dlen);
+
+/*page*************************************************************
+ m a i n
+
+ This is the main routine that gets executed when a NET START
+ happens.
+
+ Arguments - None
+
+ Returns - Nothing
+********************************************************************/
+void _CRTAPI1 main(int argc, char **argv)
+{
+ UNICODE_STRING FileString;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatusBlock;
+ NTSTATUS Status;
+ NB_ACTION_GET_COUNTS GetCounts;
+ int rc;
+ int i;
+
+ /** Open the nwlnknb driver **/
+
+ RtlInitUnicodeString (&FileString, isnnbname);
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &FileString,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenFile(
+ &isnnbfd,
+ SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT);
+
+ if (!NT_SUCCESS(Status)) {
+ isnnbfd = INVALID_HANDLE;
+ printf("Could not open transport\n");
+ }
+
+ if (isnnbfd == INVALID_HANDLE) {
+ exit(1);
+ }
+
+ rc = do_isnnbioctl(isnnbfd, (I_MIPX | 351), (char *)&GetCounts, sizeof(NB_ACTION_GET_COUNTS));
+ if (rc == 0) {
+
+ printf("NB NIC count: %d\n", GetCounts.MaximumNicId);
+ for (i = 1; i <= GetCounts.MaximumNicId; i++) {
+ printf("NIC %d: %d sessions\n", i, GetCounts.NicIdCounts[i]);
+ }
+ }
+}
+
+
+/*page***************************************************************
+ d o _ i s n i p x i o c t l
+
+ Do the equivalent of a stream ioctl to isnnb
+
+ Arguments - fd = Handle to put on
+ cmd = Command to send
+ datap = Ptr to ctrl buffer
+ dlen = Ptr to len of data buffer
+
+ Returns - 0 = OK
+ else = Error
+********************************************************************/
+int do_isnnbioctl(HANDLE fd, int cmd, char *datap, int dlen)
+{
+ NTSTATUS Status;
+ UCHAR buffer[300];
+ PNWLINK_ACTION action;
+ IO_STATUS_BLOCK IoStatusBlock;
+ int rc;
+
+ /** Fill out the structure **/
+
+ action = (PNWLINK_ACTION)buffer;
+
+ action->Header.TransportId = ISN_ACTION_TRANSPORT_ID;
+ action->OptionType = NWLINK_OPTION_CONTROL;
+ action->BufferLength = sizeof(ULONG) + dlen;
+ action->Option = cmd;
+ RtlMoveMemory(action->Data, datap, dlen);
+
+ /** Issue the ioctl **/
+
+ Status = NtDeviceIoControlFile(
+ fd,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ IOCTL_TDI_ACTION,
+ NULL,
+ 0,
+ action,
+ FIELD_OFFSET(NWLINK_ACTION,Data) + dlen);
+
+ if (Status != STATUS_SUCCESS) {
+ if (Status == STATUS_INVALID_PARAMETER) {
+ rc = ERANGE;
+ } else {
+ rc = EINVAL;
+ }
+ } else {
+ if (dlen > 0) {
+ RtlMoveMemory (datap, action->Data, dlen);
+ }
+ rc = 0;
+ }
+
+ return rc;
+
+}
+
diff --git a/private/ntos/tdi/isnp/nb/nbcount/nbcount.rc b/private/ntos/tdi/isnp/nb/nbcount/nbcount.rc
new file mode 100644
index 000000000..ada219b24
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/nbcount/nbcount.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "NWLink Netbios Session Count Application"
+#define VER_INTERNALNAME_STR "nbcount.exe"
+#define VER_ORIGINALFILENAME_STR "nbcount.exe"
+
+#include "common.ver"
diff --git a/private/ntos/tdi/isnp/nb/nbcount/sources b/private/ntos/tdi/isnp/nb/nbcount/sources
new file mode 100644
index 000000000..f9dfe3561
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/nbcount/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1993 Micro Computer Systems, Inc.
+
+!ENDIF
+
+MAJORCOMP=nwlink
+MINORCOMP=nbcount
+
+TARGETNAME=nbcount
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=UMAPPL_NOLIB
+
+USE_CRTDLL=1
+
+C_DEFINES=$(C_DEFINES)
+
+!IF 0
+INCLUDES=..\h;..\..\..\..\..\inc;..\..\..\..\inc;..\..\..\inc
+!ELSE
+INCLUDES=..\h;$(BASEDIR)\private\inc;$(BASEDIR)\private\ntos\inc;$(BASEDIR)\private\ntos\streams\inc
+!ENDIF
+
+SOURCES= nbcount.c nbcount.rc
+
+UMTYPE=console
+UMAPPL=$(TARGETNAME)
+UMLIBS=$(BASEDIR)\public\sdk\lib\*\ntdll.lib \
+
diff --git a/private/ntos/tdi/isnp/nb/nbiprocs.h b/private/ntos/tdi/isnp/nb/nbiprocs.h
new file mode 100644
index 000000000..dff399019
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/nbiprocs.h
@@ -0,0 +1,1530 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ nbiprocs.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 16-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+//
+// MACROS.
+//
+//
+// Debugging aids
+//
+
+//
+// VOID
+// PANIC(
+// IN PSZ Message
+// );
+//
+
+#if DBG
+#define PANIC(Msg) \
+ CTEPrint ((Msg))
+#else
+#define PANIC(Msg)
+#endif
+
+
+//
+// These are define to allow CTEPrints that disappear when
+// DBG is 0.
+//
+
+#if DBG
+#define NbiPrint0(fmt) DbgPrint(fmt)
+#define NbiPrint1(fmt,v0) DbgPrint(fmt,v0)
+#define NbiPrint2(fmt,v0,v1) DbgPrint(fmt,v0,v1)
+#define NbiPrint3(fmt,v0,v1,v2) DbgPrint(fmt,v0,v1,v2)
+#define NbiPrint4(fmt,v0,v1,v2,v3) DbgPrint(fmt,v0,v1,v2,v3)
+#define NbiPrint5(fmt,v0,v1,v2,v3,v4) DbgPrint(fmt,v0,v1,v2,v3,v4)
+#define NbiPrint6(fmt,v0,v1,v2,v3,v4,v5) DbgPrint(fmt,v0,v1,v2,v3,v4,v5)
+#else
+#define NbiPrint0(fmt)
+#define NbiPrint1(fmt,v0)
+#define NbiPrint2(fmt,v0,v1)
+#define NbiPrint3(fmt,v0,v1,v2)
+#define NbiPrint4(fmt,v0,v1,v2,v3)
+#define NbiPrint5(fmt,v0,v1,v2,v3,v4)
+#define NbiPrint6(fmt,v0,v1,v2,v3,v4,v5)
+#endif
+
+
+//
+// Routines to log packets to a buffer.
+//
+
+#if DBG
+#define NB_PACKET_LOG 1
+#endif
+
+#ifdef NB_PACKET_LOG
+
+//
+// The size of this is 64 bytes for easy display.
+//
+
+typedef struct _NB_PACKET_LOG_ENTRY {
+ UCHAR SendReceive;
+ UCHAR TimeStamp[5]; // low 5 digits of tick count.
+ UCHAR DestMac[6];
+ UCHAR SrcMac[6];
+ UCHAR Length[2];
+ IPX_HEADER NbiHeader;
+ UCHAR Data[14];
+} NB_PACKET_LOG_ENTRY, *PNB_PACKET_LOG_ENTRY;
+
+#define NB_PACKET_LOG_LENGTH 128
+extern ULONG NbiPacketLogDebug;
+extern USHORT NbiPacketLogSocket;
+EXTERNAL_LOCK(NbiPacketLogLock);
+extern NB_PACKET_LOG_ENTRY NbiPacketLog[NB_PACKET_LOG_LENGTH];
+extern PNB_PACKET_LOG_ENTRY NbiPacketLogLoc;
+extern PNB_PACKET_LOG_ENTRY NbiPacketLogEnd;
+
+//
+// Bit fields in NbiPacketLogDebug
+//
+
+#define NB_PACKET_LOG_RCV_RIP 0x0001 // All RIP packets
+#define NB_PACKET_LOG_RCV_SPX 0x0002 // All SPX packets
+#define NB_PACKET_LOG_RCV_NB 0x0004 // All Netbios packets
+#define NB_PACKET_LOG_RCV_OTHER 0x0008 // All TDI client packets
+#define NB_PACKET_LOG_RCV_SOCKET 0x0010 // All packets to NbiPacketLogSocket
+#define NB_PACKET_LOG_RCV_ALL 0x0020 // All packets (even non-NB)
+
+#define NB_PACKET_LOG_SEND_RIP 0x0001 // All RIP packets
+#define NB_PACKET_LOG_SEND_SPX 0x0002 // All SPX packets
+#define NB_PACKET_LOG_SEND_NB 0x0004 // All Netbios packets
+#define NB_PACKET_LOG_SEND_OTHER 0x0008 // All TDI client packets
+#define NB_PACKET_LOG_SEND_SOCKET 0x0010 // All packets from NbiPacketLogSocket
+
+VOID
+NbiLogPacket(
+ IN BOOLEAN Send,
+ IN PUCHAR DestMac,
+ IN PUCHAR SrcMac,
+ IN USHORT Length,
+ IN PVOID NbiHeader,
+ IN PVOID Data
+ );
+
+#define PACKET_LOG(_Bit) (NbiPacketLogDebug & (_Bit))
+
+#else // NB_PACKET_LOG
+
+#define NbiLogPacket(_MacHeader,_Length,_NbiHeader,_Data)
+#define PACKET_LOG(_Bit) 0
+
+#endif // NB_PACKET_LOG
+
+
+#if DBG
+
+#define NbiReferenceDevice(_Device, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Device)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefDevice (_Device)
+
+#define NbiDereferenceDevice(_Device, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Device)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock); \
+ NbiDerefDevice (_Device)
+
+
+#define NbiReferenceAddress(_Address, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Address)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefAddress (_Address)
+
+#define NbiReferenceAddressLock(_Address, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Address)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefAddressLock (_Address)
+
+#define NbiDereferenceAddress(_Address, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Address)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock); \
+ NbiDerefAddress (_Address)
+
+
+#define NbiReferenceAddressFile(_AddressFile, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefAddressFile (_AddressFile)
+
+#define NbiReferenceAddressFileLock(_AddressFile, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefAddressFileLock (_AddressFile)
+
+#define NbiDereferenceAddressFile(_AddressFile, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock); \
+ NbiDerefAddressFile (_AddressFile)
+
+#define NbiTransferReferenceAddressFile(_AddressFile, _OldType, _NewType) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_AddressFile)->RefTypes[_NewType], \
+ 1, \
+ &NbiGlobalInterlock); \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_AddressFile)->RefTypes[_OldType], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock);
+
+
+#define NbiReferenceConnection(_Connection, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefConnection (_Connection)
+
+#define NbiReferenceConnectionLock(_Connection, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefConnectionLock (_Connection)
+
+#define NbiReferenceConnectionSync(_Connection, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefConnectionSync (_Connection)
+
+#define NbiDereferenceConnection(_Connection, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock); \
+ NbiDerefConnection (_Connection)
+
+#define NbiTransferReferenceConnection(_Connection, _OldType, _NewType) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_NewType], \
+ 1, \
+ &NbiGlobalInterlock); \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_OldType], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock);
+
+#else // DBG
+
+#define NbiReferenceDevice(_Device, _Type) \
+ InterlockedIncrement(&(_Device)->ReferenceCount)
+
+#define NbiDereferenceDevice(_Device, _Type) \
+ NbiDerefDevice (_Device)
+
+
+
+#define NbiReferenceAddress(_Address, _Type) \
+ InterlockedIncrement( &(_Address)->ReferenceCount )
+
+#define NbiReferenceAddressLock(_Address, _Type) \
+ InterlockedIncrement( &(_Address)->ReferenceCount )
+
+#define NbiDereferenceAddress(_Address, _Type) \
+ NbiDerefAddress (_Address)
+
+
+#define NbiReferenceAddressFile(_AddressFile, _Type) \
+ InterlockedIncrement( &(_AddressFile)->ReferenceCount )
+
+#define NbiReferenceAddressFileLock(_AddressFile, _Type) \
+ InterlockedIncrement( &(_AddressFile)->ReferenceCount )
+
+#define NbiDereferenceAddressFile(_AddressFile, _Type) \
+ if ( !InterlockedDecrement(&(_AddressFile)->ReferenceCount )) { \
+ NbiDestroyAddressFile (_AddressFile); \
+ }
+
+#define NbiTransferReferenceAddressFile(_AddressFile, _OldType, _NewType)
+
+
+#define NbiReferenceConnection(_Connection, _Type) { \
+ (VOID)ExInterlockedAddUlong( \
+ &(_Connection)->ReferenceCount, \
+ 1, \
+ &(_Connection)->DeviceLock->Lock); \
+ (_Connection)->CanBeDestroyed = FALSE; \
+}
+
+#define NbiReferenceConnectionLock(_Connection, _Type) { \
+ ++(_Connection)->ReferenceCount; \
+ (_Connection)->CanBeDestroyed = FALSE; \
+}
+
+#define NbiReferenceConnectionSync(_Connection, _Type) { \
+ (VOID)NB_ADD_ULONG( \
+ &(_Connection)->ReferenceCount, \
+ 1, \
+ (_Connection)->DeviceLock); \
+ (_Connection)->CanBeDestroyed = FALSE; \
+}
+
+#define NbiDereferenceConnection(_Connection, _Type) { \
+ CTELockHandle _LockHandle; \
+ NB_GET_LOCK( (_Connection)->DeviceLock, &_LockHandle ); \
+ if ( !(--(_Connection)->ReferenceCount) ) { \
+ (_Connection)->ThreadsInHandleConnectionZero++; \
+ NB_FREE_LOCK( (_Connection)->DeviceLock, _LockHandle ); \
+ NbiHandleConnectionZero (_Connection); \
+ } else { \
+ NB_FREE_LOCK( (_Connection)->DeviceLock, _LockHandle ); \
+ } \
+}
+
+
+#define NbiTransferReferenceConnection(_Connection, _OldType, _NewType)
+
+#endif // DBG
+
+
+
+#if DBG
+
+#define NbiAllocateMemory(_BytesNeeded,_Tag,_Description) \
+ NbipAllocateTaggedMemory(_BytesNeeded,_Tag,_Description)
+
+#define NbiFreeMemory(_Memory,_BytesAllocated,_Tag,_Description) \
+ NbipFreeTaggedMemory(_Memory,_BytesAllocated,_Tag,_Description)
+
+#else // DBG
+
+#define NbiAllocateMemory(_BytesNeeded,_Tag,_Description) \
+ NbipAllocateMemory(_BytesNeeded,_Tag,(BOOLEAN)((_Tag) != MEMORY_CONFIG))
+
+#define NbiFreeMemory(_Memory,_BytesAllocated,_Tag,_Description) \
+ NbipFreeMemory(_Memory,_BytesAllocated,(BOOLEAN)((_Tag) != MEMORY_CONFIG))
+
+
+#endif // DBG
+
+
+//
+// Definition of the callback routine where an NdisTransferData
+// call is not needed.
+//
+
+typedef VOID
+(*NB_CALLBACK_NO_TRANSFER) (
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+
+
+//
+// This routine compares two node addresses.
+//
+
+#define NB_NODE_EQUAL(_A,_B) \
+ ((*(UNALIGNED ULONG *)((PUCHAR)(_A)) == *(UNALIGNED ULONG *)((PUCHAR)(_B))) && \
+ (*(UNALIGNED USHORT *)(((PUCHAR)(_A))+4) == *(UNALIGNED USHORT *)(((PUCHAR)(_B))+4)))
+
+//
+// This routine checks if an address is the broadcast address.
+//
+
+#define NB_NODE_BROADCAST(_A) \
+ ((*(UNALIGNED ULONG *)((PUCHAR)(_A)) == 0xffffffff) && \
+ (*(UNALIGNED USHORT *)(((PUCHAR)(_A))+4) == 0xffff))
+
+
+//
+// Definition of the routine to handler a particular minor
+// code for an IOCTL_MJ_INTERNAL_DEVICE_CONTROL IRP.
+//
+
+typedef NTSTATUS
+(*NB_TDI_DISPATCH_ROUTINE) (
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+
+//
+// Routines in action.c
+//
+
+NTSTATUS
+NbiTdiAction(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+//
+// Routines in address.c
+//
+
+TDI_ADDRESS_NETBIOS UNALIGNED *
+NbiParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN BOOLEAN BroadcastAddressOk
+ );
+
+BOOLEAN
+NbiValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength
+ );
+
+NTSTATUS
+NbiOpenAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiStartRegistration(
+ IN PADDRESS Address
+ );
+
+VOID
+NbiRegistrationTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ );
+
+VOID
+NbiProcessFindName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+VOID
+NbiProcessAddName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+NTSTATUS
+NbiOpenConnection(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+PADDRESS
+NbiCreateAddress(
+ IN PDEVICE Device,
+ IN TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress
+ );
+
+NTSTATUS
+NbiVerifyAddressFile (
+#if defined(_PNP_POWER)
+ IN PADDRESS_FILE AddressFile,
+ IN BOOLEAN ConflictIsOk
+#else
+ IN PADDRESS_FILE AddressFile
+#endif _PNP_POWER
+ );
+
+VOID
+NbiDestroyAddress(
+ IN PVOID Parameter
+ );
+
+#if DBG
+
+VOID
+NbiRefAddress(
+ IN PADDRESS Address
+ );
+
+VOID
+NbiRefAddressLock(
+ IN PADDRESS Address
+ );
+
+#endif
+
+VOID
+NbiDerefAddress(
+ IN PADDRESS Address
+ );
+
+PADDRESS_FILE
+NbiCreateAddressFile(
+ IN PDEVICE Device
+ );
+
+NTSTATUS
+NbiDestroyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+#if DBG
+
+VOID
+NbiRefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+NbiRefAddressFileLock(
+ IN PADDRESS_FILE AddressFile
+ );
+
+#endif
+
+VOID
+NbiDerefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+#if !defined(_PNP_POWER)
+PADDRESS
+NbiLookupAddress(
+ IN PDEVICE Device,
+ IN TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress
+ );
+#endif !_PNP_POWER
+
+PADDRESS
+NbiFindAddress(
+ IN PDEVICE Device,
+ IN PUCHAR NetbiosName
+ );
+
+NTSTATUS
+NbiStopAddressFile(
+ IN PADDRESS_FILE AddressFile,
+ IN PADDRESS Address
+ );
+
+NTSTATUS
+NbiCloseAddressFile(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+#if defined(_PNP_POWER)
+PADAPTER_ADDRESS
+NbiCreateAdapterAddress(
+ IN PCHAR AdapterMacAddress
+ );
+
+NTSTATUS
+NbiDestroyAdapterAddress(
+ IN PADAPTER_ADDRESS AdapterAddress OPTIONAL,
+ IN PCHAR AdapterMacAddress OPTIONAL
+ );
+
+PADAPTER_ADDRESS
+NbiFindAdapterAddress(
+ IN PCHAR NetbiosName,
+ IN BOOLEAN LockHeld
+ );
+#endif _PNP_POWER
+
+
+//
+// Routines in bind.c
+//
+
+NTSTATUS
+NbiBind(
+ IN PDEVICE Device,
+ IN PCONFIG Config
+ );
+
+VOID
+NbiUnbind(
+ IN PDEVICE Device
+ );
+
+VOID
+NbiStatus(
+ IN USHORT NicId,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength
+ );
+
+VOID
+NbiLineUp(
+ IN USHORT NicId,
+ IN PIPX_LINE_INFO LineInfo,
+ IN NDIS_MEDIUM DeviceType,
+ IN PVOID ConfigurationData
+ );
+
+VOID
+NbiLineDown(
+ IN USHORT NicId
+ );
+
+
+//
+// Routines in cache.c
+//
+
+NTSTATUS
+CacheFindName(
+ IN PDEVICE Device,
+ IN FIND_NAME_TYPE Type,
+ IN PUCHAR RemoteName OPTIONAL,
+ OUT PNETBIOS_CACHE * CacheName
+);
+
+VOID
+FindNameTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ );
+
+VOID
+CacheHandlePending(
+ IN PDEVICE Device,
+ IN PUCHAR RemoteName,
+ IN NETBIOS_NAME_RESULT Result,
+ IN PNETBIOS_CACHE CacheName OPTIONAL
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiProcessNameRecognized(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+PNETBIOS_CACHE
+CacheUpdateNameCache(
+ IN PNETBIOS_CACHE NameCache,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN TDI_ADDRESS_IPX UNALIGNED * SourceAddress,
+ IN BOOLEAN ModifyQueue
+ );
+
+VOID
+CacheUpdateFromAddName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN NB_CONNECTIONLESS UNALIGNED * Connectionless,
+ IN BOOLEAN LocalFrame
+ );
+
+VOID
+NbiProcessDeleteName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+VOID
+InsertInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE CacheEntry
+ );
+
+VOID
+ReinsertInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE OldEntry,
+ IN PNETBIOS_CACHE NewEntry
+ );
+
+VOID
+RemoveFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE CacheEntry
+ );
+
+VOID
+FlushOldFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN USHORT AgeLimit
+ );
+
+VOID
+FlushFailedNetbiosCacheEntries(
+ IN PNETBIOS_CACHE_TABLE CacheTable
+ );
+
+VOID
+RemoveInvalidRoutesFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN NIC_HANDLE UNALIGNED *InvalidNicHandle
+ );
+
+NTSTATUS
+FindInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PUCHAR NameToBeFound,
+ OUT PNETBIOS_CACHE *CacheEntry
+ );
+
+NTSTATUS
+CreateNetbiosCacheTable(
+ IN OUT PNETBIOS_CACHE_TABLE *NewTable,
+ IN USHORT MaxHashIndex
+ );
+
+VOID
+DestroyNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable
+ );
+
+//
+// Routines in connect.c
+//
+
+VOID
+NbiFindRouteComplete(
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute
+ );
+
+NTSTATUS
+NbiOpenConnection(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiStopConnection(
+ IN PCONNECTION Connection,
+ IN NTSTATUS DisconnectStatus
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+NTSTATUS
+NbiCloseConnection(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiAssociateAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiDisassociateAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiListen(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiAccept(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiConnect(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiConnectFindName(
+ IN PDEVICE Device,
+ IN PREQUEST Request,
+ IN PCONNECTION Connection,
+ IN CTELockHandle CancelLH,
+ IN CTELockHandle ConnectionLH,
+ IN CTELockHandle DeviceLH,
+ IN PBOOLEAN pbLockFreed
+ );
+
+NTSTATUS
+NbiTdiDisconnect(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+BOOLEAN
+NbiAssignConnectionId(
+ IN PDEVICE Device,
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiDeassignConnectionId(
+ IN PDEVICE Device,
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiConnectionTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ );
+
+VOID
+NbiCancelListen(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+NbiCancelConnectFindName(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+NbiCancelConnectWaitResponse(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+NbiCancelDisconnectWait(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+PCONNECTION
+NbiLookupConnectionByContext(
+ IN PADDRESS_FILE AddressFile,
+ IN CONNECTION_CONTEXT ConnectionContext
+ );
+
+PCONNECTION
+NbiCreateConnection(
+ IN PDEVICE Device
+ );
+
+NTSTATUS
+NbiVerifyConnection (
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiDestroyConnection(
+ IN PCONNECTION Connection
+ );
+
+#if DBG
+VOID
+NbiRefConnection(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiRefConnectionLock(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiRefConnectionSync(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiDerefConnection(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiDerefConnectionSync(
+ IN PCONNECTION Connection
+ );
+#endif
+
+VOID
+NbiHandleConnectionZero(
+ IN PCONNECTION Connection
+ );
+
+
+//
+// Routines in datagram.c
+//
+
+VOID
+NbiProcessDatagram(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize,
+ IN BOOLEAN Broadcast
+ );
+
+VOID
+NbiIndicateDatagram(
+ IN PADDRESS Address,
+ IN PUCHAR RemoteName,
+ IN PUCHAR Data,
+ IN ULONG DataLength
+ );
+
+NTSTATUS
+NbiTdiSendDatagram(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiTransmitDatagram(
+ IN PNB_SEND_RESERVED Reserved
+ );
+
+NTSTATUS
+NbiTdiReceiveDatagram(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiCancelReceiveDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+
+//
+// Routines in device.c
+//
+
+VOID
+NbiRefDevice(
+ IN PDEVICE Device
+ );
+
+VOID
+NbiDerefDevice(
+ IN PDEVICE Device
+ );
+
+NTSTATUS
+NbiCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN OUT PDEVICE *DevicePtr
+ );
+
+VOID
+NbiDestroyDevice(
+ IN PDEVICE Device
+ );
+
+
+//
+// Routines in driver.c
+//
+
+PVOID
+NbipAllocateMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN BOOLEAN ChargeDevice
+ );
+
+VOID
+NbipFreeMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN BOOLEAN ChargeDevice
+ );
+
+#if DBG
+
+PVOID
+NbipAllocateTaggedMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ );
+
+VOID
+NbipFreeTaggedMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ );
+
+#endif
+
+VOID
+NbiWriteResourceErrorLog(
+ IN PDEVICE Device,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue
+ );
+
+VOID
+NbiWriteGeneralErrorLog(
+ IN PDEVICE Device,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN ULONG DumpDataCount,
+ IN ULONG DumpData[]
+ );
+
+VOID
+NbiWriteOidErrorLog(
+ IN PDEVICE Device,
+ IN NTSTATUS ErrorCode,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR AdapterString,
+ IN ULONG OidValue
+ );
+
+
+//
+// Routines in event.c
+//
+
+NTSTATUS
+NbiTdiSetEventHandler(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+//
+// Routines in frame.c
+//
+
+VOID
+NbiSendNameFrame(
+ IN PADDRESS Address,
+ IN UCHAR NameTypeFlag,
+ IN UCHAR DataStreamType,
+ IN PIPX_LOCAL_TARGET LocalTarget OPTIONAL,
+#if defined(_PNP_POWER)
+ IN NB_CONNECTIONLESS UNALIGNED * ReqFrame OPTIONAL
+#else
+ IN TDI_ADDRESS_IPX UNALIGNED * DestAddress OPTIONAL
+#endif _PNP_POWER
+ );
+
+VOID
+NbiSendSessionInitialize(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiSendSessionInitAck(
+ IN PCONNECTION Connection,
+ IN PUCHAR ExtraData,
+ IN ULONG ExtraDataLength,
+ IN CTELockHandle * LockHandle OPTIONAL
+ );
+
+VOID
+NbiSendDataAck(
+ IN PCONNECTION Connection,
+ IN NB_ACK_TYPE AckType
+ IN NB_LOCK_HANDLE_PARAM (LockHandle)
+ );
+
+VOID
+NbiSendSessionEnd(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiSendSessionEndAck(
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN NB_SESSION UNALIGNED * SessionEnd
+ );
+
+
+//
+// Routines in packet.c
+//
+
+NTSTATUS
+NbiInitializeSendPacket(
+ IN PDEVICE Device,
+ IN NDIS_HANDLE PoolHandle OPTIONAL,
+ IN PNB_SEND_PACKET Packet,
+ IN PUCHAR Header,
+ IN ULONG HeaderLength
+ );
+
+NTSTATUS
+NbiInitializeReceivePacket(
+ IN PDEVICE Device,
+ IN NDIS_HANDLE PoolHandle OPTIONAL,
+ IN PNB_RECEIVE_PACKET Packet
+ );
+
+NTSTATUS
+NbiInitializeReceiveBuffer(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer,
+ IN PUCHAR DataBuffer,
+ IN ULONG DataBufferLength
+ );
+
+VOID
+NbiDeinitializeSendPacket(
+ IN PDEVICE Device,
+ IN PNB_SEND_PACKET Packet,
+ IN ULONG HeaderLength
+ );
+
+VOID
+NbiDeinitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_PACKET Packet
+ );
+
+VOID
+NbiDeinitializeReceiveBuffer(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer
+ );
+
+VOID
+NbiAllocateSendPool(
+ IN PDEVICE Device
+ );
+
+VOID
+NbiAllocateReceivePool(
+ IN PDEVICE Device
+ );
+
+#if defined(_PNP_POWER)
+VOID
+NbiAllocateReceiveBufferPool(
+ IN PDEVICE Device,
+ IN UINT DataLength
+ );
+
+VOID
+NbiReAllocateReceiveBufferPool(
+ IN PWORK_QUEUE_ITEM WorkItem
+ );
+
+VOID
+NbiDestroyReceiveBufferPools(
+ IN PDEVICE Device
+ );
+
+VOID
+NbiPushReceiveBuffer (
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer
+ );
+#else
+VOID
+NbiAllocateReceiveBufferPool(
+ IN PDEVICE Device
+ );
+#endif _PNP_POWER
+
+PSINGLE_LIST_ENTRY
+NbiPopSendPacket(
+ IN PDEVICE Device,
+ IN BOOLEAN LockAcquired
+ );
+
+VOID
+NbiPushSendPacket(
+ IN PNB_SEND_RESERVED Reserved
+ );
+
+VOID
+NbiCheckForWaitPacket(
+ IN PCONNECTION Connection
+ );
+
+PSINGLE_LIST_ENTRY
+NbiPopReceivePacket(
+ IN PDEVICE Device
+ );
+
+PSINGLE_LIST_ENTRY
+NbiPopReceiveBuffer(
+ IN PDEVICE Device
+ );
+
+
+//
+// Routines in query.c
+//
+
+NTSTATUS
+NbiTdiQueryInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiStoreAdapterStatus(
+ IN ULONG MaximumLength,
+ IN USHORT NicId,
+ OUT PVOID * StatusBuffer,
+ OUT ULONG * StatusBufferLength,
+ OUT ULONG * ValidBufferLength
+ );
+
+VOID
+NbiUpdateNetbiosFindName(
+ IN PREQUEST Request,
+#if defined(_PNP_POWER)
+ IN PNIC_HANDLE NicHandle,
+#else
+ IN USHORT NicId,
+#endif _PNP_POWER
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteIpxAddress,
+ IN BOOLEAN Unique
+ );
+
+VOID
+NbiSetNetbiosFindNameInformation(
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiSetInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiProcessStatusQuery(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+VOID
+NbiSendStatusQuery(
+ IN PREQUEST Request
+ );
+
+VOID
+NbiProcessStatusResponse(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ );
+
+
+//
+// Routines in receive.c
+//
+
+
+VOID
+NbiReceive(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ );
+
+VOID
+NbiReceiveComplete(
+ IN USHORT NicId
+ );
+
+VOID
+NbiTransferDataComplete(
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ );
+
+VOID
+NbiAcknowledgeReceive(
+ IN PCONNECTION Connection
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiCompleteReceive(
+ IN PCONNECTION Connection,
+ IN BOOLEAN EndOfMessage,
+ IN CTELockHandle CancelLH
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+NTSTATUS
+NbiTdiReceive(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiCancelReceive(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+
+//
+// Routines in send.c
+//
+
+
+VOID
+NbiSendComplete(
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+NbiAssignSequenceAndSend(
+ IN PCONNECTION Connection,
+ IN PNDIS_PACKET Packet
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+NTSTATUS
+NbiTdiSend(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiPacketizeSend(
+ IN PCONNECTION Connection
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiReframeConnection(
+ IN PCONNECTION Connection,
+ IN USHORT ReceiveSequence,
+ IN USHORT BytesReceived,
+ IN BOOLEAN Resend
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiRestartConnection(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiAdvanceUnAckedByBytes(
+ IN PCONNECTION Connection,
+ IN ULONG BytesAcked
+ );
+
+VOID
+NbiAdvanceUnAckedBySequence(
+ IN PCONNECTION Connection,
+ IN USHORT ReceiveSequence
+ );
+
+VOID
+NbiCancelSend(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbiBuildBufferChainFromBufferChain (
+ IN NDIS_HANDLE BufferPoolHandle,
+ IN PNDIS_BUFFER CurrentSourceBuffer,
+ IN ULONG CurrentByteOffset,
+ IN ULONG DesiredLength,
+ OUT PNDIS_BUFFER *DestinationBuffer,
+ OUT PNDIS_BUFFER *NewSourceBuffer,
+ OUT ULONG *NewByteOffset,
+ OUT ULONG *ActualLength
+ );
+
+
+//
+// Routines in session.c
+//
+
+VOID
+NbiProcessSessionData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ );
+
+VOID
+NbiProcessDataAck(
+ IN PCONNECTION Connection,
+ IN NB_SESSION UNALIGNED * Sess,
+ IN PIPX_LOCAL_TARGET RemoteAddress
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiProcessSessionInitialize(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+VOID
+NbiProcessSessionInitAck(
+ IN PCONNECTION Connection,
+ IN NB_SESSION UNALIGNED * Sess
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiProcessSessionEnd(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+VOID
+NbiProcessSessionEndAck(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+
+//
+// Routines in timer.c
+//
+
+VOID
+NbiStartRetransmit(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiStartWatchdog(
+ IN PCONNECTION Connection
+ );
+
+#if DBG
+
+VOID
+NbiStopRetransmit(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiStopWatchdog(
+ IN PCONNECTION Connection
+ );
+
+#else
+
+#define NbiStopRetransmit(_Connection) \
+ (_Connection)->Retransmit = 0;
+
+#define NbiStopWatchdog(_Connection) \
+ (_Connection)->Watchdog = 0;
+
+#endif
+
+VOID
+NbiExpireRetransmit(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiExpireWatchdog(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiShortTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ );
+
+VOID
+NbiLongTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ );
+
+VOID
+NbiStartShortTimer(
+ IN PDEVICE Device
+ );
+
+VOID
+NbiInitializeTimers(
+ IN PDEVICE Device
+ );
+
diff --git a/private/ntos/tdi/isnp/nb/nbitypes.h b/private/ntos/tdi/isnp/nb/nbitypes.h
new file mode 100644
index 000000000..604df5fb5
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/nbitypes.h
@@ -0,0 +1,1511 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ nbitypes.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 16-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+//
+// For find name requests, defines the current status (SR_FN.Status).
+//
+
+typedef enum {
+ FNStatusNoResponse, // no response has been received
+ FNStatusResponseUnique, // response received, is a unique name
+ FNStatusResponseGroup // response received, is a group name
+};
+
+//
+// Defines the results we can get from sending a series of find
+// names to locate a netbios name.
+//
+
+typedef enum _NETBIOS_NAME_RESULT {
+ NetbiosNameFound, // name was located
+ NetbiosNameNotFoundNormal, // name not found, no response received
+ NetbiosNameNotFoundWanDown // name not found, all lines were down
+} NETBIOS_NAME_RESULT, *PNETBIOS_NAME_RESULT;
+
+
+//
+// Definition of the protocol reserved field of a send packet.
+//
+
+typedef struct _NB_SEND_RESERVED {
+ UCHAR Identifier; // 0 for NB packets
+ BOOLEAN SendInProgress; // used in an NdisSend
+ UCHAR Type; // what to do on completion
+ BOOLEAN OwnedByConnection; // if this is a connection's one packet
+#if defined(_PNP_POWER)
+ PVOID Reserved[SEND_RESERVED_COMMON_SIZE]; // used by ipx for even-padding and local target etc.
+#else
+ PVOID Reserved[2]; // used by ipx for even-padding
+#endif _PNP_POWER
+ LIST_ENTRY GlobalLinkage; // all packets are on this
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free queue
+ LIST_ENTRY WaitLinkage; // when waiting on other queues
+#ifdef NB_TRACK_POOL
+ PVOID Pool; // send pool it was allocated from
+#endif
+ union {
+ struct {
+ UCHAR NetbiosName[16]; // name being searched for
+ UCHAR StatusAndSentOnUpLine; // low nibble: look at FNStatusXXX enum
+ // high nibble: TRUE if while sending, found lan or up wan line
+ UCHAR RetryCount; // number of times sent
+ USHORT SendTime; // based on Device->FindNameTime
+#if !defined(_PNP_POWER)
+ USHORT CurrentNicId; // current nic id it is being sent on
+ USHORT MaximumNicId; // highest one it will be sent on
+#endif !_PNP_POWER
+ struct _NETBIOS_CACHE * NewCache; // new cache entry for group names
+ } SR_FN;
+ struct {
+ struct _ADDRESS * Address; // that owns this packet, if one does
+ PREQUEST Request; // send datagram request
+ struct _ADDRESS_FILE * AddressFile; // that this send is on
+#if !defined(_PNP_POWER)
+ USHORT CurrentNicId; // non-zero for frames that go to all
+#endif !_PNP_POWER
+ UCHAR NameTypeFlag; // save these two values for frames
+ UCHAR DataStreamType; // that need to be sent to all nic id's
+ } SR_NF;
+ struct {
+ PREQUEST DatagramRequest; // holds the passed-in request
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteName; // will be -1 for broadcast
+ struct _ADDRESS_FILE * AddressFile; // that the datagram was sent on
+ struct _NETBIOS_CACHE * Cache; // how to route to the netbios address
+ ULONG CurrentNetwork; // within the cache entry
+ } SR_DG;
+ struct {
+ struct _CONNECTION * Connection; // that this frame was sent on.
+ PREQUEST Request; // that this frame was sent for.
+ ULONG PacketLength; // total packet length.
+ BOOLEAN NoNdisBuffer; // none allocate for send
+ } SR_CO;
+ struct {
+ ULONG ActualBufferLength; // real length of allocated buffer.
+ } SR_AS;
+ } u;
+ PUCHAR Header; // points to the MAC/IPX/NB header
+ PNDIS_BUFFER HeaderBuffer; // the NDIS_BUFFER describing Header
+} NB_SEND_RESERVED, *PNB_SEND_RESERVED;
+
+//
+// Values for Type.
+//
+
+#define SEND_TYPE_NAME_FRAME 1
+#define SEND_TYPE_SESSION_INIT 2
+#define SEND_TYPE_FIND_NAME 3
+#define SEND_TYPE_DATAGRAM 4
+#define SEND_TYPE_SESSION_NO_DATA 5
+#define SEND_TYPE_SESSION_DATA 6
+#define SEND_TYPE_STATUS_QUERY 7
+#define SEND_TYPE_STATUS_RESPONSE 8
+
+#ifdef RSRC_TIMEOUT_DBG
+#define SEND_TYPE_DEATH_PACKET 9
+#endif //RSRC_TIMEOUT_DBG
+
+//
+// Macros to access StatusAndSentOnUpLine.
+//
+
+#define NB_GET_SR_FN_STATUS(_Reserved) \
+ ((_Reserved)->u.SR_FN.StatusAndSentOnUpLine & 0x0f)
+
+#define NB_SET_SR_FN_STATUS(_Reserved,_Value) \
+ (_Reserved)->u.SR_FN.StatusAndSentOnUpLine = \
+ (((_Reserved)->u.SR_FN.StatusAndSentOnUpLine & 0xf0) | (_Value));
+
+#define NB_GET_SR_FN_SENT_ON_UP_LINE(_Reserved) \
+ (((_Reserved)->u.SR_FN.StatusAndSentOnUpLine & 0xf0) != 0)
+
+#define NB_SET_SR_FN_SENT_ON_UP_LINE(_Reserved,_Value) \
+ (_Reserved)->u.SR_FN.StatusAndSentOnUpLine = \
+ (((_Reserved)->u.SR_FN.StatusAndSentOnUpLine & 0x0f) | ((_Value) << 4));
+
+
+//
+// Definition of the protocol reserved field of a receive packet.
+//
+
+typedef struct _NB_RECEIVE_RESERVED {
+ UCHAR Identifier; // 0 for NB packets
+ BOOLEAN TransferInProgress; // used in an NdisTransferData
+ UCHAR Type; // what to do on completion
+#if defined(_PNP_POWER)
+ PVOID Pool; // send pool it was allocated from
+#else
+
+#ifdef IPX_TRACK_POOL
+ PVOID Pool; // send pool it was allocated from
+#endif
+
+#endif _PNP_POWER
+ union {
+ struct {
+ struct _CONNECTION * Connection; // that the transfer is for
+ BOOLEAN EndOfMessage; // this was the last part of a message
+ BOOLEAN CompleteReceive; // receive should be completed
+ BOOLEAN NoNdisBuffer; // user's mdl chain was used
+ BOOLEAN PartialReceive; // (new nb) don't ack this packet
+ } RR_CO;
+ struct {
+ struct _NB_RECEIVE_BUFFER * ReceiveBuffer; // datagram receive buffer
+ } RR_DG;
+ struct {
+ PREQUEST Request; // for this request
+ } RR_AS;
+ } u;
+ LIST_ENTRY GlobalLinkage; // all packets are on this
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free queue
+} NB_RECEIVE_RESERVED, *PNB_RECEIVE_RESERVED;
+
+//
+// Values for Type.
+//
+
+#define RECEIVE_TYPE_DATAGRAM 1
+#define RECEIVE_TYPE_DATA 2
+#define RECEIVE_TYPE_ADAPTER_STATUS 3
+
+
+
+typedef struct _NB_RECEIVE_BUFFER {
+ LIST_ENTRY GlobalLinkage; // all buffers are on this
+#if defined(_PNP_POWER)
+ PVOID Pool; // receive buffer pool was allocated from
+#else
+#ifdef NB_TRACK_POOL
+ PVOID Pool; // receive buffer pool was allocated from
+#endif
+#endif _PNP_POWER
+ struct _ADDRESS * Address; // that the datagram is for
+ SINGLE_LIST_ENTRY PoolLinkage; // when in free pool
+ LIST_ENTRY WaitLinkage; // when in ReceiveDatagrams queue
+ PNDIS_BUFFER NdisBuffer; // describes the data
+ UCHAR RemoteName[16]; // datagram was received from
+ ULONG DataLength; // length for current one, not allocated
+ PUCHAR Data; // points to data to hold packet
+} NB_RECEIVE_BUFFER, *PNB_RECEIVE_BUFFER;
+
+
+//
+// Types to abstract NDIS packets. This is to allow us to
+// switch from using our own memory for packets to using
+// authentically allocated NDIS packets.
+//
+
+//#define NB_OWN_PACKETS 1
+
+#ifdef NB_OWN_PACKETS
+
+#define NDIS_PACKET_SIZE 48
+// #define NDIS_PACKET_SIZE FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])
+
+typedef struct _NB_SEND_PACKET {
+ UCHAR Data[NDIS_PACKET_SIZE+sizeof(NB_SEND_RESERVED)];
+} NB_SEND_PACKET, *PNB_SEND_PACKET;
+
+typedef struct _NB_RECEIVE_PACKET {
+ UCHAR Data[NDIS_PACKET_SIZE+sizeof(NB_RECEIVE_RESERVED)];
+} NB_RECEIVE_PACKET, *PNB_RECEIVE_PACKET;
+
+typedef struct _NB_SEND_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ NB_SEND_PACKET Packets[1];
+ // after the packets the header buffers are allocated also.
+} NB_SEND_POOL, *PNB_SEND_POOL;
+
+typedef struct _NB_RECEIVE_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ NB_RECEIVE_PACKET Packets[1];
+} NB_RECEIVE_POOL, *PNB_RECEIVE_POOL;
+
+#define PACKET(_Packet) ((PNDIS_PACKET)((_Packet)->Data))
+
+#define NbiAllocateSendPacket(_Device,_PoolHandle, _SendPacket,_Status) { \
+ NdisReinitializePacket((PNDIS_PACKET)((_SendPacket)->Data)); \
+ *(_Status) = STATUS_SUCCESS; \
+}
+
+#define NbiAllocateReceivePacket(_Device,_PoolHandle, _ReceivePacket,_Status) { \
+ NdisReinitializePacket((PNDIS_PACKET)((_ReceivePacket)->Data)); \
+ *(_Status) = STATUS_SUCCESS; \
+}
+
+#define NbiFreeSendPacket(_Device,_Packet)
+
+#define NbiFreeReceivePacket(_Device,_Packet)
+
+
+#else // NB_OWN_PACKETS
+
+typedef struct _NB_SEND_PACKET {
+ PNDIS_PACKET Packet;
+} NB_SEND_PACKET, *PNB_SEND_PACKET;
+
+typedef struct _NB_RECEIVE_PACKET {
+ PNDIS_PACKET Packet;
+} NB_RECEIVE_PACKET, *PNB_RECEIVE_PACKET;
+
+typedef struct _NB_PACKET_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ NDIS_HANDLE PoolHandle;
+ NB_SEND_PACKET Packets[1];
+ // after the packets the header buffers are allocated also.
+} NB_SEND_POOL, *PNB_SEND_POOL;
+
+typedef struct _NB_RECEIVE_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ NDIS_HANDLE PoolHandle;
+ NB_RECEIVE_PACKET Packets[1];
+} NB_RECEIVE_POOL, *PNB_RECEIVE_POOL;
+
+#define PACKET(_Packet) ((_Packet)->Packet)
+
+#define NbiAllocateSendPacket(_Device,_PoolHandle, _SendPacket,_Status) { \
+ NdisAllocatePacket(_Status, &(_SendPacket)->Packet, _PoolHandle); \
+}
+
+#define NbiAllocateReceivePacket(_Device, _PoolHandle, _ReceivePacket,_Status) { \
+ NdisAllocatePacket(_Status, &(_ReceivePacket)->Packet, _PoolHandle); \
+}
+
+#define NbiFreeSendPacket(_Device,_Packet) { \
+ NdisFreePacket(PACKET(_Packet)); \
+}
+
+#define NbiFreeReceivePacket(_Device,_Packet) { \
+ NdisFreePacket(PACKET(_Packet)); \
+}
+
+#endif // NB_OWN_PACKETS
+
+#define SEND_RESERVED(_Packet) ((PNB_SEND_RESERVED)((PACKET(_Packet))->ProtocolReserved))
+#define RECEIVE_RESERVED(_Packet) ((PNB_RECEIVE_RESERVED)((PACKET(_Packet))->ProtocolReserved))
+
+
+
+typedef struct _NB_RECEIVE_BUFFER_POOL {
+ LIST_ENTRY Linkage;
+ UINT BufferCount;
+ UINT BufferFree;
+#if defined(_PNP_POWER)
+ UINT BufferDataSize; // allocation size of each buffer data
+#endif _PNP_POWER
+ NB_RECEIVE_BUFFER Buffers[1];
+ // after the packets the data buffers are allocated also.
+} NB_RECEIVE_BUFFER_POOL, *PNB_RECEIVE_BUFFER_POOL;
+
+
+//
+// Tags for memory allocation.
+//
+
+#define MEMORY_CONFIG 0
+#define MEMORY_ADAPTER 1
+#define MEMORY_ADDRESS 2
+#define MEMORY_PACKET 3
+#define MEMORY_CACHE 4
+#define MEMORY_CONNECTION 5
+#define MEMORY_STATUS 6
+#define MEMORY_QUERY 7
+#if defined(_PNP_POWER)
+#define MEMORY_WORK_ITEM 8
+#define MEMORY_ADAPTER_ADDRESS 9
+#endif _PNP_POWER
+
+#if defined(_PNP_POWER)
+#define MEMORY_MAX 10
+#else
+#define MEMORY_MAX 8
+#endif _PNP_POWER
+
+#if DBG
+
+//
+// Holds the allocations for a specific memory type.
+//
+
+typedef struct _MEMORY_TAG {
+ ULONG Tag;
+ ULONG BytesAllocated;
+} MEMORY_TAG, *PMEMORY_TAG;
+
+EXTERNAL_LOCK(NbiMemoryInterlock);
+extern MEMORY_TAG NbiMemoryTag[MEMORY_MAX];
+
+#endif
+
+
+
+//
+// This structure holds a single remote network which a
+// Netbios name exists on.
+//
+
+typedef struct _NETBIOS_NETWORK {
+ ULONG Network;
+ IPX_LOCAL_TARGET LocalTarget;
+} NETBIOS_NETWORK, *PNETBIOS_NETWORK;
+
+//
+// This defines a netbios cache entry for a given name.
+//
+
+typedef struct _NETBIOS_CACHE {
+ UCHAR NetbiosName[16];
+ BOOLEAN Unique;
+ BOOLEAN FailedOnDownWan; // if NetworksUsed == 0, was it due to down wan lines?
+ USHORT TimeStamp; // in seconds - CacheTimeStamp when inserted
+ ULONG ReferenceCount;
+ LIST_ENTRY Linkage;
+ TDI_ADDRESS_IPX FirstResponse;
+ USHORT NetworksAllocated;
+ USHORT NetworksUsed;
+ NETBIOS_NETWORK Networks[1]; // may be more than one of these
+} NETBIOS_CACHE, *PNETBIOS_CACHE;
+
+typedef struct _NETBIOS_CACHE_TABLE {
+ USHORT MaxHashIndex;
+ USHORT CurrentEntries;
+ LIST_ENTRY Bucket[1];
+} NETBIOS_CACHE_TABLE, *PNETBIOS_CACHE_TABLE;
+
+#define NB_NETBIOS_CACHE_TABLE_LARGE 26 // for server
+#define NB_NETBIOS_CACHE_TABLE_SMALL 8 // for workstation
+#define NB_MAX_AVG_CACHE_ENTRIES_PER_BUCKET 8
+
+//
+// This defines the different kind of requests that can be made
+// to CacheFindName().
+//
+
+typedef enum _FIND_NAME_TYPE {
+ FindNameConnect,
+ FindNameNetbiosFindName,
+ FindNameOther
+} FIND_NAME_TYPE, *PFIND_NAME_TYPE;
+
+
+//
+// The number of hash entries in the non-inactive connection
+// database.
+//
+
+#define CONNECTION_HASH_COUNT 8
+
+//
+// Mask and shift to retrieve the hash number from a connection
+// ID.
+//
+
+#define CONNECTION_HASH_MASK 0xe000
+#define CONNECTION_HASH_SHIFT 13
+
+//
+// The maximum connection ID we can assign, not counting the
+// shifted-over hash id (which occupies the top 3 bits of the
+// real id we use on the wire). We can use all the bits except
+// the top one, to prevent an ID of 0xffff being used.
+//
+
+#define CONNECTION_MAXIMUM_ID (USHORT)(~CONNECTION_HASH_MASK & ~1)
+
+//
+// A single connection hash bucket.
+//
+
+typedef struct _CONNECTION_HASH {
+ struct _CONNECTION * Connections;
+ USHORT ConnectionCount;
+ USHORT NextConnectionId;
+} CONNECTION_HASH, *PCONNECTION_HASH;
+
+
+//
+// These are queued in the ConnectIndicationInProgress
+// queue to track indications to TDI clients.
+//
+
+typedef struct _CONNECT_INDICATION {
+ LIST_ENTRY Linkage;
+ UCHAR NetbiosName[16];
+ TDI_ADDRESS_IPX RemoteAddress;
+ USHORT ConnectionId;
+} CONNECT_INDICATION, *PCONNECT_INDICATION;
+
+//
+// This structure defines the per-device structure for NB
+// (one of these is allocated globally).
+//
+
+#define DREF_CREATE 0
+#define DREF_LOADED 1
+#define DREF_ADAPTER 2
+#define DREF_ADDRESS 3
+#define DREF_CONNECTION 4
+#define DREF_FN_TIMER 5
+#define DREF_FIND_NAME 6
+#define DREF_SESSION_INIT 7
+#define DREF_NAME_FRAME 8
+#define DREF_FRAME 9
+#define DREF_SHORT_TIMER 10
+#define DREF_LONG_TIMER 11
+#define DREF_STATUS_QUERY 12
+#define DREF_STATUS_RESPONSE 13
+#define DREF_STATUS_FRAME 14
+#define DREF_NB_FIND_NAME 15
+
+#define DREF_TOTAL 16
+
+typedef struct _DEVICE {
+
+ DEVICE_OBJECT DeviceObject; // the I/O system's device object.
+
+#if DBG
+ ULONG RefTypes[DREF_TOTAL];
+#endif
+
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+#if DBG
+ UCHAR Signature1[4]; // contains "IDC1"
+#endif
+
+ NB_LOCK Interlock; // GLOBAL lock for reference count.
+ // (used in ExInterlockedXxx calls)
+ NB_LOCK Lock;
+ LONG ReferenceCount; // activity count/this provider.
+
+ //
+ // These are kept around for error logging, and stored right
+ // after this structure.
+ //
+
+ PWCHAR DeviceName;
+#if defined(_PNP_POWER)
+ USHORT DeviceNameLength;
+#else
+ ULONG DeviceNameLength;
+#endif _PNP_POWER
+
+ LIST_ENTRY GlobalSendPacketList;
+ LIST_ENTRY GlobalReceivePacketList;
+ LIST_ENTRY GlobalReceiveBufferList;
+
+ //
+ // All send packet pools are chained on this list.
+ //
+
+ LIST_ENTRY SendPoolList;
+ LIST_ENTRY ReceivePoolList;
+ LIST_ENTRY ReceiveBufferPoolList;
+
+ SLIST_HEADER SendPacketList;
+ SLIST_HEADER ReceivePacketList;
+ SINGLE_LIST_ENTRY ReceiveBufferList;
+
+ //
+ // Receive requests waiting to be completed.
+ //
+
+ LIST_ENTRY ReceiveCompletionQueue;
+
+ //
+ // Connections waiting for send packets.
+ //
+
+ LIST_ENTRY WaitPacketConnections;
+
+ //
+ // Connections waiting to packetize.
+ //
+
+ LIST_ENTRY PacketizeConnections;
+
+ //
+ // Connections waiting to send a data ack.
+ //
+
+ LIST_ENTRY DataAckConnections;
+
+ //
+ // The list changed while we were processing it.
+ //
+
+ BOOLEAN DataAckQueueChanged;
+
+ //
+ // Information to manage the Netbios name cache.
+ //
+
+ LIST_ENTRY WaitingConnects; // connect requests waiting for a name
+ LIST_ENTRY WaitingDatagrams; // datagram requests waiting for a name
+ LIST_ENTRY WaitingAdapterStatus; // adapter status requests waiting for a name
+ LIST_ENTRY WaitingNetbiosFindName; // netbios find name requests waiting for a name
+
+ //
+ // Holds adapter status request which have a name and
+ // are waiting for a response. The long timeout aborts
+ // these after a couple of expirations (BUGBUG: currently we
+ // do not do resends).
+ //
+
+ LIST_ENTRY ActiveAdapterStatus;
+
+ //
+ // Receive datagrams waiting to be indicated.
+ //
+
+ LIST_ENTRY ReceiveDatagrams;
+
+ //
+ // In-progress connect indications (used to make
+ // sure we don't indicate the same packet twice).
+ //
+
+ LIST_ENTRY ConnectIndicationInProgress;
+
+ //
+ // Listens that have been posted to connections.
+ //
+
+ LIST_ENTRY ListenQueue;
+
+ UCHAR State;
+
+ //
+ // The following fields control the timer system.
+ // The short timer is used for retransmission and
+ // delayed acks, and the long timer is used for
+ // watchdog timeouts.
+ //
+ BOOLEAN ShortListActive; // ShortList is not empty.
+ BOOLEAN DataAckActive; // DataAckConnections is not empty.
+ BOOLEAN TimersInitialized; // has the timer system been initialized.
+ BOOLEAN ProcessingShortTimer; // TRUE if we are in ScanShortTimer.
+#if defined(_PNP_POWER)
+ BOOLEAN LongTimerRunning; // True if the long timer is running.
+#endif _PNP_POWER
+ LARGE_INTEGER ShortTimerStart; // tick count when the short timer was set.
+ CTETimer ShortTimer; // controls the short timer.
+ ULONG ShortAbsoluteTime; // up-count timer ticks, short timer.
+ CTETimer LongTimer; // kernel DPC object, long timer.
+ ULONG LongAbsoluteTime; // up-count timer ticks, long timer.
+ NB_LOCK TimerLock; // lock for following timer queues
+ LIST_ENTRY ShortList; // list of waiting connections
+ LIST_ENTRY LongList; // list of waiting connections
+
+
+ //
+ // Hash table of non-inactive connections.
+ //
+
+ CONNECTION_HASH ConnectionHash[CONNECTION_HASH_COUNT];
+
+ //
+ // Control the queue of waiting find names.
+ //
+
+ USHORT FindNameTime; // incremented each time the timer runs
+ BOOLEAN FindNameTimerActive; // TRUE if the timer is queued
+ CTETimer FindNameTimer; // runs every FIND_NAME_GRANULARITY
+ ULONG FindNameTimeout; // the retry count in timer ticks
+
+ ULONG FindNamePacketCount; // Count of packets on the queue
+ LIST_ENTRY WaitingFindNames; // FIND_NAME frames waiting to go out
+
+ //
+ // The cache of NETBIOS_CACHE entries.
+ //
+
+ PNETBIOS_CACHE_TABLE NameCache;
+
+ //
+ // The current time stamp, incremented every second.
+ //
+
+ USHORT CacheTimeStamp;
+
+ //
+ // Maximum valid NIC ID we can use.
+ //
+
+ USHORT MaximumNicId;
+
+
+ //
+ // Handle for our binding to the IPX driver.
+ //
+
+ HANDLE BindHandle;
+
+ //
+ // Holds the output from binding to IPX.
+ //
+ union {
+ IPX_INTERNAL_BIND_OUTPUT Bind;
+ IPX_INTERNAL_BIND_INPUT BindInput;
+ };
+
+ //
+ // Holds our reserved netbios name, which is 10 bytes
+ // of zeros followed by our node address.
+ //
+#if !defined(_PNP_POWER)
+ UCHAR ReservedNetbiosName[16];
+#endif !_PNP_POWER
+
+ //
+ // This holds the total memory allocated for the above structures.
+ //
+
+ LONG MemoryUsage;
+ LONG MemoryLimit;
+
+ //
+ // How many packets have been allocated.
+ //
+
+ ULONG AllocatedSendPackets;
+ ULONG AllocatedReceivePackets;
+ ULONG AllocatedReceiveBuffers;
+
+#if defined(_PNP_POWER)
+ //
+ // This is the size of each buffer in the receive buffer pool.
+ // We reallocate buffer pool when the LineInfo.MaxPacketSize changes(increases)
+ // from IPX because of a new adapter. The LineInfo.MaxPacketSize could
+ // also change(decrease) when a adapter disappears but our buffer pool size
+ // will stay at this value.
+ //
+ ULONG CurMaxReceiveBufferSize;
+#endif _PNP_POWER
+
+ //
+ // Other configuration parameters.
+ //
+
+ ULONG AckDelayTime; // converted to short timeouts, rounded up
+ ULONG AckWindow;
+ ULONG AckWindowThreshold;
+ ULONG EnablePiggyBackAck;
+ ULONG Extensions;
+ ULONG RcvWindowMax;
+ ULONG BroadcastCount;
+ ULONG BroadcastTimeout;
+ ULONG ConnectionCount;
+ ULONG ConnectionTimeout;
+ ULONG InitPackets;
+ ULONG MaxPackets;
+ ULONG InitialRetransmissionTime;
+ ULONG Internet;
+ ULONG KeepAliveCount;
+ ULONG KeepAliveTimeout;
+ ULONG RetransmitMax;
+ ULONG RouterMtu;
+
+ ULONG MaxReceiveBuffers;
+
+
+ //
+ // Where we tell upper drivers to put their headers.
+ //
+
+ ULONG IncludedHeaderOffset;
+
+ //
+ // The following field is a head of a list of ADDRESS objects that
+ // are defined for this transport provider. To edit the list, you must
+ // hold the spinlock of the device context object.
+ //
+
+ LIST_ENTRY AddressDatabase; // list of defined transport addresses.
+#if defined(_PNP_POWER)
+ LIST_ENTRY AdapterAddressDatabase; // list of netbios names made from adapter addresses.
+#endif _PNP_POWER
+
+ ULONG AddressCount; // number of addresses in the database.
+
+ NDIS_HANDLE NdisBufferPoolHandle;
+
+#if DBG
+ UCHAR Signature2[4]; // contains "IDC2"
+#endif
+
+ //
+ // This structure holds a pre-built IPX header which is used
+ // to quickly fill in common fields of outgoing connectionless
+ // frames.
+ //
+
+ IPX_HEADER ConnectionlessHeader;
+
+ //
+ // This event is used when unloading to signal that
+ // the reference count is now 0.
+ //
+
+ KEVENT UnloadEvent;
+ BOOLEAN UnloadWaiting;
+
+#if defined(_PNP_POWER)
+ HANDLE TdiRegistrationHandle;
+#endif _PNP_POWER
+
+ //
+ // Counters for most of the statistics that NB maintains;
+ // some of these are kept elsewhere. Including the structure
+ // itself wastes a little space but ensures that the alignment
+ // inside the structure is correct.
+ //
+
+ TDI_PROVIDER_STATISTICS Statistics;
+
+ //
+ // These are "temporary" versions of the other counters.
+ // During normal operations we update these, then during
+ // the short timer expiration we update the real ones.
+ //
+
+ ULONG TempFrameBytesSent;
+ ULONG TempFramesSent;
+ ULONG TempFrameBytesReceived;
+ ULONG TempFramesReceived;
+
+
+ //
+ // This contains the next unique indentified to use as
+ // the FsContext in the file object associated with an
+ // open of the control channel.
+ //
+
+ USHORT ControlChannelIdentifier;
+
+ //
+ // Counters for "active" time.
+ //
+
+ LARGE_INTEGER NbiStartTime;
+
+ //
+ // This array is used to quickly dismiss connectionless frames
+ // that are not destined for us. The count is the number
+ // of addresses with that first letter that are registered
+ // on this device.
+ //
+
+ UCHAR AddressCounts[256];
+
+ //
+ // This resource guards access to the ShareAccess
+ // and SecurityDescriptor fields in addresses.
+ //
+
+ ERESOURCE AddressResource;
+
+ //
+ // The following structure contains statistics counters for use
+ // by TdiQueryInformation and TdiSetInformation. They should not
+ // be used for maintenance of internal data structures.
+ //
+
+ TDI_PROVIDER_INFO Information; // information about this provider.
+
+} DEVICE, * PDEVICE;
+
+
+extern PDEVICE NbiDevice;
+EXTERNAL_LOCK(NbiGlobalPoolInterlock);
+
+//
+// This is used only for CHK build. For
+// tracking the refcount problem on connection, this
+// is moved here for now.
+//
+
+EXTERNAL_LOCK(NbiGlobalInterlock);
+
+
+//
+// device state definitions
+//
+#if defined(_PNP_POWER)
+#define DEVICE_STATE_CLOSED 0x00 // Initial state
+#define DEVICE_STATE_LOADED 0x01 // Loaded and bound to IPX but no adapters
+#define DEVICE_STATE_OPEN 0x02 // Fully operational
+#define DEVICE_STATE_STOPPING 0x03 // Unload has been initiated, The I/O system
+ // will not call us until nobody above has Netbios open.
+#else
+#define DEVICE_STATE_CLOSED 0x00
+#define DEVICE_STATE_OPEN 0x01
+#define DEVICE_STATE_STOPPING 0x02
+#endif _PNP_POWER
+
+
+#define NB_TDI_RESOURCES 9
+
+
+//
+// This structure is pointed to by the FsContext field in the FILE_OBJECT
+// for this Address. This structure is the base for all activities on
+// the open file object within the transport provider. All active connections
+// on the address point to this structure, although no queues exist here to do
+// work from. This structure also maintains a reference to an ADDRESS
+// structure, which describes the address that it is bound to.
+//
+
+#define AFREF_CREATE 0
+#define AFREF_RCV_DGRAM 1
+#define AFREF_SEND_DGRAM 2
+#define AFREF_VERIFY 3
+#define AFREF_INDICATION 4
+#define AFREF_TIMEOUT 5
+#define AFREF_CONNECTION 6
+
+#define AFREF_TOTAL 8
+
+typedef struct _ADDRESS_FILE {
+
+#if DBG
+ ULONG RefTypes[AFREF_TOTAL];
+#endif
+
+ CSHORT Type;
+ CSHORT Size;
+
+ LIST_ENTRY Linkage; // next address file on this address.
+ // also used for linkage in the
+ // look-aside list
+
+ ULONG ReferenceCount; // number of references to this object.
+
+ //
+ // the current state of the address file structure; this is either open or
+ // closing
+ //
+
+ UCHAR State;
+
+ PNB_LOCK AddressLock;
+
+ //
+ // The following fields are kept for housekeeping purposes.
+ //
+
+ PREQUEST OpenRequest; // the request used for open
+ struct _ADDRESS *Address; // address to which we are bound.
+#ifdef ISN_NT
+ PFILE_OBJECT FileObject; // easy backlink to file object.
+#endif
+ struct _DEVICE *Device; // device to which we are attached.
+
+ LIST_ENTRY ConnectionDatabase; // associated with this address.
+
+ LIST_ENTRY ReceiveDatagramQueue; // posted by the client.
+
+ //
+ // This holds the request used to close this address file,
+ // for pended completion.
+ //
+
+ PREQUEST CloseRequest;
+
+ //
+ // Handler for kernel event actions. First we have a set of booleans that
+ // indicate whether or not this address has an event handler of the given
+ // type registered.
+ //
+
+ BOOLEAN RegisteredHandler[6];
+
+ //
+ // This is a list of handlers for a given event. They can be
+ // accessed using the explicit names for type-checking, or the
+ // array (indexed by the event type) for speed.
+ //
+
+ union {
+ struct {
+ PTDI_IND_CONNECT ConnectionHandler;
+ PTDI_IND_DISCONNECT DisconnectHandler;
+ PTDI_IND_ERROR ErrorHandler;
+ PTDI_IND_RECEIVE ReceiveHandler;
+ PTDI_IND_RECEIVE_DATAGRAM ReceiveDatagramHandler;
+ PTDI_IND_RECEIVE_EXPEDITED ExpeditedDataHandler;
+ };
+ PVOID Handlers[6];
+ };
+
+ PVOID HandlerContexts[6];
+
+} ADDRESS_FILE, *PADDRESS_FILE;
+
+#define ADDRESSFILE_STATE_OPENING 0x00 // not yet open for business
+#define ADDRESSFILE_STATE_OPEN 0x01 // open for business
+#define ADDRESSFILE_STATE_CLOSING 0x02 // closing
+
+
+//
+// This structure defines a NETBIOS name as a character array for use when
+// passing preformatted NETBIOS names between internal routines. It is
+// not a part of the external interface to the transport provider.
+//
+
+typedef struct _NBI_NETBIOS_ADDRESS {
+ UCHAR NetbiosName[16];
+ USHORT NetbiosNameType;
+ BOOLEAN Broadcast;
+} NBI_NETBIOS_ADDRESS, *PNBI_NETBIOS_ADDRESS;
+
+//
+// This structure defines an ADDRESS, or active transport address,
+// maintained by the transport provider. It contains all the visible
+// components of the address (such as the TSAP and network name components),
+// and it also contains other maintenance parts, such as a reference count,
+// ACL, and so on. All outstanding connection-oriented and connectionless
+// data transfer requests are queued here.
+//
+
+#define AREF_ADDRESS_FILE 0
+#define AREF_LOOKUP 1
+#define AREF_RECEIVE 2
+#define AREF_NAME_FRAME 3
+#define AREF_TIMER 4
+#define AREF_FIND 5
+
+#define AREF_TOTAL 8
+
+
+typedef struct _ADDRESS {
+
+#if DBG
+ ULONG RefTypes[AREF_TOTAL];
+#endif
+
+ USHORT Size;
+ CSHORT Type;
+
+ LIST_ENTRY Linkage; // next address/this device object.
+ ULONG ReferenceCount; // number of references to this object.
+
+ NB_LOCK Lock;
+
+ //
+ // The following fields comprise the actual address itself.
+ //
+
+ PREQUEST Request; // pointer to address creation request.
+
+ UCHAR NameTypeFlag; // NB_NAME_UNIQUE or NB_NAME_GROUP
+
+ NBI_NETBIOS_ADDRESS NetbiosAddress; // our netbios name.
+
+ //
+ // The following fields are used to maintain state about this address.
+ //
+
+ ULONG Flags; // attributes of the address.
+ ULONG State; // current state of the address.
+ struct _DEVICE *Device; // device context to which we are attached.
+ PNB_LOCK DeviceLock;
+
+ //
+ // The following queues is used to hold send datagrams for this
+ // address. Receive datagrams are queued to the address file. Requests are
+ // processed in a first-in, first-out manner, so that the very next request
+ // to be serviced is always at the head of its respective queue. These
+ // queues are managed by the EXECUTIVE interlocked list management routines.
+ // The actual objects which get queued to this structure are request control
+ // blocks (RCBs).
+ //
+
+ LIST_ENTRY AddressFileDatabase; // list of defined address file objects
+
+ UCHAR SendPacketHeader[NB_MAXIMUM_MAC + sizeof(IPX_HEADER)];
+
+ //
+ // This timer is used for registering the name.
+ //
+
+ CTETimer RegistrationTimer;
+
+ //
+ // Number of times an add name frame has been sent.
+ //
+
+ ULONG RegistrationCount;
+
+#ifdef ISN_NT
+
+ //
+ // These two can be a union because they are not used
+ // concurrently.
+ //
+
+ union {
+
+ //
+ // This structure is used for checking share access.
+ //
+
+ SHARE_ACCESS ShareAccess;
+
+ //
+ // Used for delaying NbiDestroyAddress to a thread so
+ // we can access the security descriptor.
+ //
+
+ WORK_QUEUE_ITEM DestroyAddressQueueItem;
+
+ } u;
+
+ //
+ // This structure is used to hold ACLs on the address.
+
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+
+#endif
+
+} ADDRESS, *PADDRESS;
+
+//
+// Values for Flags
+//
+
+#define ADDRESS_FLAGS_DUPLICATE_NAME 0x00000002
+#if defined(_PNP_POWER)
+#define ADDRESS_FLAGS_CONFLICT 0x00000010
+#endif _PNP_POWER
+
+#if defined(_PNP_POWER)
+//
+// this booleans are passed to nbiverifyaddressfile calls.
+//
+#define CONFLICT_IS_OK TRUE
+#define CONFLICT_IS_NOT_OK FALSE
+#endif _PNP_POWER
+
+//
+// Values for State
+//
+
+#define ADDRESS_STATE_REGISTERING 1
+#define ADDRESS_STATE_OPEN 2
+#define ADDRESS_STATE_STOPPING 3
+
+#if defined(_PNP_POWER)
+//
+// This holds the adapters names i.e netbios names which are
+// created from adater node address to support adapter status
+// queries using adapter node addresses.
+//
+typedef struct _ADAPTER_ADDRESS {
+
+ USHORT Size;
+ CSHORT Type;
+
+ LIST_ENTRY Linkage; // next address/this device object.
+ NIC_HANDLE NicHandle; // NicHandle corresponding to this address.
+ UCHAR NetbiosName[16];
+} ADAPTER_ADDRESS, *PADAPTER_ADDRESS;
+#endif _PNP_POWER
+
+//
+// This defines the types of probe packets we can send.
+//
+
+typedef enum _NB_ACK_TYPE {
+ NbiAckQuery,
+ NbiAckResponse,
+ NbiAckResend
+} NB_ACK_TYPE, *PNB_ACK_TYPE;
+
+
+//
+// This defines the a packetizing location in a
+// send.
+//
+
+typedef struct _SEND_POINTER {
+ ULONG MessageOffset; // up count, bytes sent this message.
+ PREQUEST Request; // current send request in chain.
+ PNDIS_BUFFER Buffer; // current buffer in send chain.
+ ULONG BufferOffset; // current byte offset in current buffer.
+ USHORT SendSequence;
+} SEND_POINTER, *PSEND_POINTER;
+
+//
+// This defines the current location in a receive.
+//
+
+typedef struct _RECEIVE_POINTER {
+ ULONG MessageOffset; // up count, bytes received this message.
+ ULONG Offset; // up count, bytes received this request.
+ PNDIS_BUFFER Buffer; // current buffer in receive request.
+ ULONG BufferOffset; // current byte offset in current buffer.
+} RECEIVE_POINTER, *PRECEIVE_POINTER;
+
+
+//
+// This structure defines a connection, which controls a
+// session with a remote.
+//
+
+#define CREF_VERIFY 0
+#define CREF_LISTEN 1
+#define CREF_CONNECT 2
+#define CREF_WAIT_CACHE 3
+#define CREF_TIMER 4
+#define CREF_INDICATE 5
+#define CREF_ACTIVE 6
+#define CREF_FRAME 7
+#define CREF_BY_CONTEXT 8
+#define CREF_W_ACCEPT 9
+#define CREF_SEND 10
+#define CREF_RECEIVE 11
+#define CREF_PACKETIZE 12
+#define CREF_DISASSOC 13
+#define CREF_W_PACKET 14
+#define CREF_CANCEL 15
+#define CREF_NDIS_SEND 16
+#define CREF_SHORT_D_ACK 17
+#define CREF_LONG_D_ACK 18
+#define CREF_FIND_ROUTE 19
+#define CREF_ACCEPT 20
+
+#define CREF_TOTAL 24
+
+typedef struct _CONNECTION {
+
+#if DBG
+ ULONG RefTypes[CREF_TOTAL];
+#endif
+
+ CSHORT Type;
+ USHORT Size;
+
+ NB_LOCK Lock;
+ PNB_LOCK DeviceLock;
+
+ ULONG ReferenceCount; // number of references to this object.
+
+ CONNECTION_CONTEXT Context; // client-specified value.
+
+ ULONG State;
+ ULONG SubState;
+ ULONG ReceiveState; // SubState tracks sends when active.
+ ULONG NewNetbios; // 1 if we negotiated this.
+
+ REQUEST_LIST_HEAD SendQueue;
+ REQUEST_LIST_HEAD ReceiveQueue;
+
+ USHORT ReceiveSequence;
+
+ USHORT LocalRcvSequenceMax; // we advertise to him (will be near SendSequence)
+ USHORT RemoteRcvSequenceMax; // he advertises to us (will be near ReceiveSequence)
+ USHORT SendWindowSequenceLimit; // when this send window ends (may send past it however)
+
+ //
+ // RemoteRcvSequenceMax is the largest frame number that he expects to
+ // receive, while SendWindowSequenceLimit is one more than the max
+ // we can send. I.e. if he is advertising a window of 4 and we think
+ // the window should be 2, and the current send sequence is 7,
+ // RemoteRcvSequenceMax is 10 and SendWindowSequenceLimit is 9.
+ //
+
+ USHORT ReceiveWindowSize; // when it is open, how big to make it
+ USHORT SendWindowSize; // what we'll send, may be less than what he advertises
+ USHORT MaxSendWindowSize; // maximum we allow it to grow to
+
+ USHORT IncreaseWindowFailures; // how many windows after increase have had retransmits
+ BOOLEAN RetransmitThisWindow; // we had to retransmit in this send window
+ BOOLEAN SendWindowIncrease; // send window was just increased.
+ BOOLEAN ResponseTimeout; // we hit timeout in SEND_W or REMOTE_W
+
+ BOOLEAN SendBufferInUse; // current send's already queued on packet
+
+ ULONG Retries;
+
+ //
+ // Tracks the current send.
+ //
+
+ SEND_POINTER CurrentSend;
+
+ //
+ // Tracks the unacked point in the send.
+ //
+
+ SEND_POINTER UnAckedSend;
+
+ PREQUEST FirstMessageRequest; // first one in the message.
+ PREQUEST LastMessageRequest; // last one in the message.
+
+ ULONG CurrentMessageLength; // total length of current message.
+
+ //
+ // Tracks the current receive.
+ //
+
+ RECEIVE_POINTER CurrentReceive; // where to receive next data
+ RECEIVE_POINTER PreviousReceive; // stores it while transfer in progress
+
+ PREQUEST ReceiveRequest; // current one; not in ReceiveQueue
+ ULONG ReceiveLength; // length of ReceiveRequest
+
+ ULONG ReceiveUnaccepted; // by client...only indicate when == 0
+
+ ULONG CurrentIndicateOffset; // if previous frame was partially accepted.
+
+ IPX_LINE_INFO LineInfo; // for the adapter this connect is on.
+ ULONG MaximumPacketSize; // as negotiated during session init/ack
+
+ //
+ // Links us in the non-inactive connection hash bucket.
+ //
+
+ struct _CONNECTION * NextConnection;
+
+ //
+ // These are used to determine when to piggyback and when not to.
+ //
+
+ BOOLEAN NoPiggybackHeuristic; // we have reason to assume it would be bad.
+ BOOLEAN PiggybackAckTimeout; // we got a timeout last time we tried.
+ ULONG ReceivesWithoutAck; // used to do an auto ack.
+
+ //
+ // The following field is used as linkage in the device's
+ // PacketizeConnections queue.
+ //
+
+ LIST_ENTRY PacketizeLinkage;
+
+ //
+ // The following field is used as linkage in the device's
+ // WaitPacketConnections queue.
+ //
+
+ LIST_ENTRY WaitPacketLinkage;
+
+ //
+ // The following field is used as linkage in the device's
+ // DataAckConnections queue.
+ //
+
+ LIST_ENTRY DataAckLinkage;
+
+ //
+ // TRUE if we are on these queues.
+ //
+
+ BOOLEAN OnPacketizeQueue;
+ BOOLEAN OnWaitPacketQueue;
+ BOOLEAN OnDataAckQueue;
+
+ //
+ // TRUE if we have a piggyback ack pending.
+ //
+
+ BOOLEAN DataAckPending;
+
+ //
+ // TRUE if the current receive does not allow piggyback acks.
+ //
+
+ BOOLEAN CurrentReceiveNoPiggyback;
+
+ //
+ // Number of short timer expirations with the data ack queued.
+ //
+
+ ULONG DataAckTimeouts;
+
+ //
+ // Used to queue sends so that no two are outstanding at once.
+ //
+
+ ULONG NdisSendsInProgress;
+ LIST_ENTRY NdisSendQueue;
+
+ //
+ // This pointer is valid when NdisSendsInProgress is non-zero;
+ // it holds a pointer to a location on the stack of the thread
+ // which is inside NbiAssignSequenceAndSend. If this location
+ // is set to TRUE, it means the connection was stopped by another
+ // thread and a reference was added to keep the connection around.
+ //
+
+ PBOOLEAN NdisSendReference;
+
+ //
+ // These are used for timeouts.
+ //
+
+ ULONG BaseRetransmitTimeout; // config # of short timeouts we wait.
+ ULONG CurrentRetransmitTimeout; // possibly backed-off number
+ ULONG WatchdogTimeout; // how many long timeouts we wait.
+ ULONG Retransmit; // timer; based on Device->ShortAbsoluteTime
+ ULONG Watchdog; // timer; based on Device->LongAbsoluteTime
+ USHORT TickCount; // 18.21/second, # for 576-byte packet.
+ USHORT HopCount; // As returned by ipx on find route.
+ BOOLEAN OnShortList; // are we inserted in the list
+ BOOLEAN OnLongList; // are we inserted in the list
+ LIST_ENTRY ShortList; // queues us on Device->ShortList
+ LIST_ENTRY LongList; // queues us on Device->LongList
+
+ //
+ // These are valid when we have a connection established;
+ //
+
+ USHORT LocalConnectionId;
+ USHORT RemoteConnectionId;
+
+ PREQUEST DisassociatePending; // guarded by device lock.
+ PREQUEST ClosePending;
+
+ PREQUEST ConnectRequest;
+ PREQUEST ListenRequest;
+ PREQUEST AcceptRequest;
+ PREQUEST DisconnectRequest;
+ PREQUEST DisconnectWaitRequest;
+
+ ULONG CanBeDestroyed; // FALSE if reference is non-zero
+ ULONG ThreadsInHandleConnectionZero; // # of threads in HandleConnectionZero
+
+ //
+ // These are used to hold extra data that was sent on a session
+ // init, for use in sending the ack. Generally will be NULL and 0.
+ //
+
+ PUCHAR SessionInitAckData;
+ ULONG SessionInitAckDataLength;
+
+ IPX_LOCAL_TARGET LocalTarget; // for the remote when active.
+ IPX_HEADER RemoteHeader;
+
+ CTETimer Timer;
+
+ PADDRESS_FILE AddressFile; // guarded by device lock if associated.
+ LIST_ENTRY AddressFileLinkage; // guarded by device lock
+ ULONG AddressFileLinked; // TRUE if queued using AddressFileLinkage
+
+ PDEVICE Device;
+#ifdef ISN_NT
+ PFILE_OBJECT FileObject; // easy backlink to file object.
+#endif
+
+ CHAR RemoteName[16]; // for an active connection.
+
+ IPX_FIND_ROUTE_REQUEST FindRouteRequest; // use this to verify route.
+
+ TDI_CONNECTION_INFO ConnectionInfo; // can be queried from above.
+
+ BOOLEAN FindRouteInProgress; // we have a request pending.
+
+ BOOLEAN SendPacketInUse; // put this here to align packet/header.
+ BOOLEAN IgnoreNextDosProbe;
+
+ NTSTATUS Status; // status code for connection rundown.
+
+#ifdef RSRC_TIMEOUT_DBG
+ LARGE_INTEGER FirstMessageRequestTime;
+#endif //RSRC_TIMEOUT_DBG
+
+ NDIS_HANDLE SendPacketPoolHandle; // poolhandle for sendpacket below when
+ // the packet is allocated from ndis pool.
+
+ NB_SEND_PACKET SendPacket; // try to use this first for sends
+
+ ULONG Flags; // miscellaneous connection flags
+
+ UCHAR SendPacketHeader[1]; // connection is extended to include this
+
+ //
+ // NOTE: This is variable length structure!
+ // Do not add fields below this comment.
+ //
+} CONNECTION, *PCONNECTION;
+
+
+#define CONNECTION_STATE_INACTIVE 1
+#define CONNECTION_STATE_CONNECTING 2
+#define CONNECTION_STATE_LISTENING 3
+#define CONNECTION_STATE_ACTIVE 4
+#define CONNECTION_STATE_DISCONNECT 5
+#define CONNECTION_STATE_CLOSING 6
+
+
+#define CONNECTION_SUBSTATE_L_WAITING 1 // queued by a listen
+#define CONNECTION_SUBSTATE_L_W_ACCEPT 2 // waiting for user to accept
+#define CONNECTION_SUBSTATE_L_W_ROUTE 3 // waiting for rip response
+
+#define CONNECTION_SUBSTATE_C_FIND_NAME 1 // waiting for cache response
+#define CONNECTION_SUBSTATE_C_W_ACK 2 // waiting for session init ack
+#define CONNECTION_SUBSTATE_C_W_ROUTE 3 // waiting for rip response
+#define CONNECTION_SUBSTATE_C_DISCONN 4 // disconnect was issued
+
+#define CONNECTION_SUBSTATE_A_IDLE 1 // no sends in progress
+#define CONNECTION_SUBSTATE_A_PACKETIZE 2 // packetizing a send
+#define CONNECTION_SUBSTATE_A_W_ACK 3 // waiting for an ack
+#define CONNECTION_SUBSTATE_A_W_PACKET 4 // waiting for a packet
+#define CONNECTION_SUBSTATE_A_W_EOR 5 // waiting for eor to start packetizing
+#define CONNECTION_SUBSTATE_A_W_PROBE 6 // waiting for a keep-alive response
+#define CONNECTION_SUBSTATE_A_REMOTE_W 7 // remote shut down our window
+
+#define CONNECTION_RECEIVE_IDLE 1 // no receives queued
+#define CONNECTION_RECEIVE_ACTIVE 2 // receive is queued
+#define CONNECTION_RECEIVE_W_RCV 3 // waiting for receive to be posted
+#define CONNECTION_RECEIVE_INDICATE 4 // indication in progress
+#define CONNECTION_RECEIVE_TRANSFER 5 // transfer is in progress
+#define CONNECTION_RECEIVE_PENDING 6 // last request is queued for completion
+
+#define CONNECTION_SUBSTATE_D_W_ACK 1
+#define CONNECTION_SUBSTATE_D_GOT_ACK 2
+
+//
+// Bit values for Flags field in
+// the CONNECTION structure.
+//
+#define CONNECTION_FLAGS_AUTOCONNECTING 0x00000001 // RAS autodial in progress
+#define CONNECTION_FLAGS_AUTOCONNECTED 0x00000002 // RAS autodial connected
+
+#ifdef RSRC_TIMEOUT_DBG
+extern ULONG NbiGlobalDebugResTimeout;
+extern LARGE_INTEGER NbiGlobalMaxResTimeout;
+extern NB_SEND_PACKET NbiGlobalDeathPacket; // try to use this first for sends
+#endif //RSRC_TIMEOUT_DBG
diff --git a/private/ntos/tdi/isnp/nb/nwlnknb.ini b/private/ntos/tdi/isnp/nb/nwlnknb.ini
new file mode 100644
index 000000000..e2df88f54
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/nwlnknb.ini
@@ -0,0 +1,43 @@
+\Registry\Machine\System\CurrentControlSet\Services\NwlnkNb
+ Type = REG_DWORD 0x00000001
+ Start = REG_DWORD 0x00000003
+ ErrorControl = REG_DWORD 0x00000001
+ ImagePath = REG_EXPAND_SZ \SystemRoot\System32\drivers\nwlnknb.sys
+ DisplayName = NWLINK2 IPX Netbios Protocol
+ Group = TDI
+ DependOnService = REG_MULTI_SZ "NwlnkIpx"
+ DependOnGroup = REG_MULTI_SZ "NDIS"
+ Linkage
+ Bind = REG_MULTI_SZ "\Device\NwlnkIpx"
+ Export = REG_MULTI_SZ "\Device\NwlnkNb"
+ Route = REG_MULTI_SZ ""NwlnkIpx""
+ Disabled
+ Bind = REG_MULTI_SZ
+ Export = REG_MULTI_SZ
+ Route = REG_MULTI_SZ
+ Parameters
+ AckDelayTime = REG_DWORD 0x000000fa
+ AckWindow = REG_DWORD 0x00000002
+ AckWindowThreshold = REG_DWORD 0x000001f4
+ EnablePiggyBackAck = REG_DWORD 0x00000001
+ Extensions = REG_DWORD 0x00000001
+ RcvWindowMax = REG_DWORD 0x00000004
+ BroadcastCount = REG_DWORD 0x00000003
+ BroadcastTimeout = REG_DWORD 0x00000001
+ ConnectionCount = REG_DWORD 0x00000005
+ ConnectionTimeout = REG_DWORD 0x00000002
+ InitPackets= REG_DWORD 0x00000005
+ MaxPackets = REG_DWORD 0x0000001e
+ InitialRetransmissionTime = REG_DWORD 0x000001f4
+ Internet = REG_DWORD 0x00000001
+ KeepAliveCount = REG_DWORD 0x00000008
+ KeepAliveTimeout = REG_DWORD 0x0000003c
+ RetransmitMax = REG_DWORD 0x00000008
+ Performance
+ Library = Perfctrs.dll
+ Open = OpenNbfPerformanceData
+ Collect = CollectNbfPerformanceData
+ Close = CloseNbfPerformanceData
+\Registry\Machine\System\CurrentControlSet\Services\EventLog\System\NwlnkNb
+ EventMessageFile = REG_EXPAND_SZ %SystemRoot%\System32\netevent.dll
+ TypesSupported = REG_DWORD 0x00000007
diff --git a/private/ntos/tdi/isnp/nb/nwlnknb.rc b/private/ntos/tdi/isnp/nb/nwlnknb.rc
new file mode 100644
index 000000000..1b0163cf3
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/nwlnknb.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "NWLINK2 IPX Netbios Protocol Driver"
+#define VER_INTERNALNAME_STR "nwlnknb.sys"
+#define VER_ORIGINALFILENAME_STR "nwlnknb.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/tdi/isnp/nb/packet.c b/private/ntos/tdi/isnp/nb/packet.c
new file mode 100644
index 000000000..7e22534a8
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/packet.c
@@ -0,0 +1,1482 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ packet.c
+
+Abstract:
+
+ This module contains code that implements the SEND_PACKET and
+ RECEIVE_PACKET objects, which describe NDIS packets used
+ by the transport.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Local Function Protos
+//
+#if defined(_PNP_POWER)
+#if !defined(DBG)
+__inline
+#endif
+VOID
+NbiFreeReceiveBufferPool (
+ IN PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool
+ );
+#endif _PNP_POWER
+
+
+NTSTATUS
+NbiInitializeSendPacket(
+ IN PDEVICE Device,
+ IN NDIS_HANDLE PoolHandle OPTIONAL,
+ IN PNB_SEND_PACKET Packet,
+ IN PUCHAR Header,
+ IN ULONG HeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a send packet by chaining the
+ buffer for the header on it.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD,
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+ PoolHandle - Ndis packet pool handle if !NB_OWN_PACKETS
+
+ Packet - The packet to initialize.
+
+ Header - Points to storage for the header.
+
+ HeaderLength - The length of the header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ NTSTATUS Status;
+ PNDIS_BUFFER NdisBuffer;
+ PNDIS_BUFFER NdisNbBuffer;
+ PNB_SEND_RESERVED Reserved;
+ ULONG MacHeaderNeeded = NbiDevice->Bind.MacHeaderNeeded;
+
+ NbiAllocateSendPacket (Device, PoolHandle, Packet, &Status);
+
+ if (Status != STATUS_SUCCESS) {
+ // ERROR LOG
+ return Status;
+ }
+// DbgPrint("NbiInitializeSendPacket: PACKET is (%x)\n", PACKET(Packet));
+
+ //
+ // allocate the mac header.
+ //
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Device->NdisBufferPoolHandle,
+ Header,
+ MacHeaderNeeded);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbiFreeSendPacket (Device, Packet);
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NdisChainBufferAtFront (PACKET(Packet), NdisBuffer);
+
+// DbgPrint("NbiInitializeSendPacket: MAC header address is (%x)\n", NdisBuffer);
+ //
+ // Allocate the nb header
+ //
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisNbBuffer,
+ Device->NdisBufferPoolHandle,
+ Header + MacHeaderNeeded,
+ HeaderLength - MacHeaderNeeded);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NdisUnchainBufferAtFront (PACKET(Packet), &NdisBuffer);
+ CTEAssert (NdisBuffer);
+
+ NdisAdjustBufferLength (NdisBuffer, MacHeaderNeeded);
+ NdisFreeBuffer (NdisBuffer);
+ NbiFreeSendPacket (Device, Packet);
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // DbgPrint("NbiInitializeSendPacket: IPX header address is (%x)\n", NdisNbBuffer);
+ NdisChainBufferAtBack (PACKET(Packet), NdisNbBuffer);
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->Identifier = IDENTIFIER_NB;
+ Reserved->SendInProgress = FALSE;
+ Reserved->OwnedByConnection = FALSE;
+ Reserved->Header = Header;
+ Reserved->HeaderBuffer = NdisBuffer;
+
+ Reserved->Reserved[0] = NULL;
+ Reserved->Reserved[1] = NULL;
+
+ InsertHeadList(
+ &Device->GlobalSendPacketList,
+ &Reserved->GlobalLinkage);
+
+ return STATUS_SUCCESS;
+
+} /* NbiInitializeSendPacket */
+
+
+NTSTATUS
+NbiInitializeReceivePacket(
+ IN PDEVICE Device,
+ IN NDIS_HANDLE PoolHandle OPTIONAL,
+ IN PNB_RECEIVE_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive packet.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD,
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+ PoolHandle - Ndis packet pool handle if !NB_OWN_PACKETS
+
+ Packet - The packet to initialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ PNB_RECEIVE_RESERVED Reserved;
+
+ NbiAllocateReceivePacket (Device, PoolHandle, Packet, &Status);
+
+ if (Status != STATUS_SUCCESS) {
+ // ERROR LOG
+ return Status;
+ }
+
+ Reserved = RECEIVE_RESERVED(Packet);
+ Reserved->Identifier = IDENTIFIER_NB;
+ Reserved->TransferInProgress = FALSE;
+
+ InsertHeadList(
+ &Device->GlobalReceivePacketList,
+ &Reserved->GlobalLinkage);
+
+ return STATUS_SUCCESS;
+
+} /* NbiInitializeReceivePacket */
+
+
+NTSTATUS
+NbiInitializeReceiveBuffer(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer,
+ IN PUCHAR DataBuffer,
+ IN ULONG DataBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive buffer by allocating
+ an NDIS_BUFFER to describe the data buffer.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD,
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+ ReceiveBuffer - The receive buffer to initialize.
+
+ DataBuffer - The data buffer.
+
+ DataBufferLength - The length of the data buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ PNDIS_BUFFER NdisBuffer;
+
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Device->NdisBufferPoolHandle,
+ DataBuffer,
+ DataBufferLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ ReceiveBuffer->NdisBuffer = NdisBuffer;
+ ReceiveBuffer->Data = DataBuffer;
+ ReceiveBuffer->DataLength = 0;
+
+ InsertHeadList(
+ &Device->GlobalReceiveBufferList,
+ &ReceiveBuffer->GlobalLinkage);
+
+ return STATUS_SUCCESS;
+
+} /* NbiInitializeReceiveBuffer */
+
+
+
+VOID
+NbiDeinitializeSendPacket(
+ IN PDEVICE Device,
+ IN PNB_SEND_PACKET Packet,
+ IN ULONG HeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a send packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to deinitialize.
+
+ HeaderLength - The length of the first buffer on the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_BUFFER NdisBuffer;
+ PNB_SEND_RESERVED Reserved;
+ CTELockHandle LockHandle;
+ ULONG MacHeaderNeeded = NbiDevice->Bind.MacHeaderNeeded;
+
+ CTEAssert(HeaderLength > MacHeaderNeeded);
+ Reserved = SEND_RESERVED(Packet);
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Reserved->GlobalLinkage);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Free the mac header
+ //
+ // DbgPrint("NbiDeinitializeSendPacket: PACKET is (%x)\n", PACKET(Packet));
+ NdisUnchainBufferAtFront (PACKET(Packet), &NdisBuffer);
+ CTEAssert (NdisBuffer);
+ // DbgPrint("NbiDeinitializeSendPacket: MAC header address is (%x)\n", NdisBuffer);
+
+ NdisAdjustBufferLength (NdisBuffer, MacHeaderNeeded);
+ NdisFreeBuffer (NdisBuffer);
+
+ //
+ // Free the nb header
+ //
+ NdisUnchainBufferAtFront (PACKET(Packet), &NdisBuffer);
+ // DbgPrint("NbiDeinitializeSendPacket: IPX header address is (%x)\n", NdisBuffer);
+ CTEAssert (NdisBuffer);
+
+ NdisAdjustBufferLength (NdisBuffer, HeaderLength - MacHeaderNeeded);
+ NdisFreeBuffer (NdisBuffer);
+
+ //
+ // free the packet
+ //
+ NbiFreeSendPacket (Device, Packet);
+
+} /* NbiDeinitializeSendPacket */
+
+
+VOID
+NbiDeinitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to initialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNB_RECEIVE_RESERVED Reserved;
+ CTELockHandle LockHandle;
+
+ Reserved = RECEIVE_RESERVED(Packet);
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Reserved->GlobalLinkage);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ NbiFreeReceivePacket (Device, Packet);
+
+} /* NbiDeinitializeReceivePacket */
+
+
+
+VOID
+NbiDeinitializeReceiveBuffer(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a receive buffer.
+
+Arguments:
+
+ Device - The device.
+
+ ReceiveBuffer - The receive buffer.
+
+Return Value:
+
+ None.
+
+ THIS ROUTINE SHOULD BE CALLED WITH THE DEVICE LOCK HELD. If this
+ routine also called from the DestroyDevice routine, it is not
+ necessary to call this with the lock.
+
+--*/
+
+{
+#if defined(_PNP_POWER)
+ RemoveEntryList (&ReceiveBuffer->GlobalLinkage);
+#else
+ CTELockHandle LockHandle;
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+ RemoveEntryList (&ReceiveBuffer->GlobalLinkage);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+#endif _PNP_POWER
+
+ NdisFreeBuffer (ReceiveBuffer->NdisBuffer);
+
+} /* NbiDeinitializeReceiveBuffer */
+
+
+
+VOID
+NbiAllocateSendPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 packets to the pool for this device.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNB_SEND_POOL SendPool;
+ UINT SendPoolSize;
+ UINT PacketNum;
+ PNB_SEND_PACKET Packet;
+ PNB_SEND_RESERVED Reserved;
+ PUCHAR Header;
+ ULONG HeaderLength;
+ NTSTATUS Status;
+
+ HeaderLength = Device->Bind.MacHeaderNeeded + sizeof(NB_CONNECTIONLESS);
+ SendPoolSize = FIELD_OFFSET (NB_SEND_POOL, Packets[0]) +
+ (sizeof(NB_SEND_PACKET) * Device->InitPackets) +
+ (HeaderLength * Device->InitPackets);
+
+ SendPool = (PNB_SEND_POOL)NbiAllocateMemory (SendPoolSize, MEMORY_PACKET, "SendPool");
+ if (SendPool == NULL) {
+ NB_DEBUG (PACKET, ("Could not allocate send pool memory\n"));
+ return;
+ }
+
+ RtlZeroMemory (SendPool, SendPoolSize);
+
+
+#if !defined(NB_OWN_PACKETS)
+ //
+ // Now allocate the ndis packet pool
+ //
+ NdisAllocatePacketPool( &Status, &SendPool->PoolHandle, Device->InitPackets, sizeof(NB_SEND_RESERVED));
+ if (!NT_SUCCESS(Status)){
+ NB_DEBUG (PACKET, ("Could not allocate Ndis Packet Pool memory\n"));
+ NbiFreeMemory( SendPool, SendPoolSize, MEMORY_PACKET, "Send Pool Freed");
+ return;
+ }
+#endif
+
+ NB_DEBUG2 (PACKET, ("Initializing send pool %lx, %d packets, header %d\n",
+ SendPool, Device->InitPackets, HeaderLength));
+
+ Header = (PUCHAR)(&SendPool->Packets[Device->InitPackets]);
+
+ for (PacketNum = 0; PacketNum < Device->InitPackets; PacketNum++) {
+
+ Packet = &SendPool->Packets[PacketNum];
+
+ if (NbiInitializeSendPacket (
+ Device,
+#ifdef NB_OWN_PACKETS
+ NULL,
+#else
+ SendPool->PoolHandle,
+#endif
+ Packet,
+ Header,
+ HeaderLength) != STATUS_SUCCESS) {
+ NB_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->u.SR_NF.Address = NULL;
+#ifdef NB_TRACK_POOL
+ Reserved->Pool = SendPool;
+#endif
+
+ Header += HeaderLength;
+
+ }
+
+ SendPool->PacketCount = PacketNum;
+ SendPool->PacketFree = PacketNum;
+
+ for (PacketNum = 0; PacketNum < SendPool->PacketCount; PacketNum++) {
+
+ Packet = &SendPool->Packets[PacketNum];
+ Reserved = SEND_RESERVED(Packet);
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ }
+
+ InsertTailList (&Device->SendPoolList, &SendPool->Linkage);
+
+ Device->AllocatedSendPackets += SendPool->PacketCount;
+
+} /* NbiAllocateSendPool */
+
+
+VOID
+NbiAllocateReceivePool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 5 receive packets to the pool for this device.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNB_RECEIVE_POOL ReceivePool;
+ UINT ReceivePoolSize;
+ UINT PacketNum;
+ PNB_RECEIVE_PACKET Packet;
+ PNB_RECEIVE_RESERVED Reserved;
+ NTSTATUS Status;
+
+ ReceivePoolSize = FIELD_OFFSET (NB_RECEIVE_POOL, Packets[0]) +
+ (sizeof(NB_RECEIVE_PACKET) * Device->InitPackets);
+
+ ReceivePool = (PNB_RECEIVE_POOL)NbiAllocateMemory (ReceivePoolSize, MEMORY_PACKET, "ReceivePool");
+ if (ReceivePool == NULL) {
+ NB_DEBUG (PACKET, ("Could not allocate receive pool memory\n"));
+ return;
+ }
+
+ RtlZeroMemory (ReceivePool, ReceivePoolSize);
+
+#if !defined(NB_OWN_PACKETS)
+ //
+ // Now allocate the ndis packet pool
+ //
+ NdisAllocatePacketPool( &Status, &ReceivePool->PoolHandle, Device->InitPackets, sizeof(NB_RECEIVE_RESERVED));
+ if (!NT_SUCCESS(Status)){
+ NB_DEBUG (PACKET, ("Could not allocate Ndis Packet Pool memory\n"));
+ NbiFreeMemory( ReceivePool, ReceivePoolSize, MEMORY_PACKET, "Receive Pool Freed");
+ return;
+ }
+#endif NB_OWN_PACKETS
+
+ NB_DEBUG2 (PACKET, ("Initializing receive pool %lx, %d packets\n",
+ ReceivePool, Device->InitPackets));
+
+ for (PacketNum = 0; PacketNum < Device->InitPackets; PacketNum++) {
+
+ Packet = &ReceivePool->Packets[PacketNum];
+
+ if (NbiInitializeReceivePacket (
+ Device,
+#ifdef NB_OWN_PACKETS
+ NULL,
+#else
+ ReceivePool->PoolHandle,
+#endif
+ Packet) != STATUS_SUCCESS) {
+ NB_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = RECEIVE_RESERVED(Packet);
+#ifdef NB_TRACK_POOL
+ Reserved->Pool = ReceivePool;
+#endif
+
+ }
+
+ ReceivePool->PacketCount = PacketNum;
+ ReceivePool->PacketFree = PacketNum;
+
+ for (PacketNum = 0; PacketNum < ReceivePool->PacketCount; PacketNum++) {
+
+ Packet = &ReceivePool->Packets[PacketNum];
+ Reserved = RECEIVE_RESERVED(Packet);
+ ExInterlockedPushEntrySList(
+ &Device->ReceivePacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+// PushEntryList (&Device->ReceivePacketList, &Reserved->PoolLinkage);
+
+ }
+
+ InsertTailList (&Device->ReceivePoolList, &ReceivePool->Linkage);
+
+ Device->AllocatedReceivePackets += ReceivePool->PacketCount;
+
+} /* NbiAllocateReceivePool */
+
+
+#if defined(_PNP_POWER)
+
+VOID
+NbiAllocateReceiveBufferPool(
+ IN PDEVICE Device,
+ IN UINT DataLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds receive buffers to the pool for this device.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+ DataLength - Max length of the data in each buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ UINT ReceiveBufferPoolSize;
+ UINT BufferNum;
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ PUCHAR Data;
+
+
+ ReceiveBufferPoolSize = FIELD_OFFSET (NB_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(NB_RECEIVE_BUFFER) * Device->InitPackets) +
+ (DataLength * Device->InitPackets);
+
+ ReceiveBufferPool = (PNB_RECEIVE_BUFFER_POOL)NbiAllocateMemory (ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+ if (ReceiveBufferPool == NULL) {
+ NB_DEBUG (PACKET, ("Could not allocate receive buffer pool memory\n"));
+ return;
+ }
+
+ RtlZeroMemory (ReceiveBufferPool, ReceiveBufferPoolSize);
+
+ NB_DEBUG2 (PACKET, ("Initializing receive buffer pool %lx, %d buffers, data %d\n",
+ ReceiveBufferPool, Device->InitPackets, DataLength));
+
+ Data = (PUCHAR)(&ReceiveBufferPool->Buffers[Device->InitPackets]);
+
+ for (BufferNum = 0; BufferNum < Device->InitPackets; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+
+ if (NbiInitializeReceiveBuffer (Device, ReceiveBuffer, Data, DataLength) != STATUS_SUCCESS) {
+ NB_DEBUG (PACKET, ("Could not initialize buffer %lx\n", ReceiveBuffer));
+ break;
+ }
+
+ ReceiveBuffer->Pool = ReceiveBufferPool;
+
+ Data += DataLength;
+
+ }
+
+ ReceiveBufferPool->BufferCount = BufferNum;
+ ReceiveBufferPool->BufferFree = BufferNum;
+ ReceiveBufferPool->BufferDataSize = DataLength;
+
+ for (BufferNum = 0; BufferNum < ReceiveBufferPool->BufferCount; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+ PushEntryList (&Device->ReceiveBufferList, &ReceiveBuffer->PoolLinkage);
+
+ }
+
+ InsertTailList (&Device->ReceiveBufferPoolList, &ReceiveBufferPool->Linkage);
+
+ Device->AllocatedReceiveBuffers += ReceiveBufferPool->BufferCount;
+ Device->CurMaxReceiveBufferSize = DataLength;
+
+} /* NbiAllocateReceiveBufferPool */
+#else
+
+VOID
+NbiAllocateReceiveBufferPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds receive buffers to the pool for this device.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ UINT ReceiveBufferPoolSize;
+ UINT BufferNum;
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ UINT DataLength;
+ PUCHAR Data;
+
+ DataLength = Device->Bind.LineInfo.MaximumPacketSize;
+
+ ReceiveBufferPoolSize = FIELD_OFFSET (NB_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(NB_RECEIVE_BUFFER) * Device->InitPackets) +
+ (DataLength * Device->InitPackets);
+
+ ReceiveBufferPool = (PNB_RECEIVE_BUFFER_POOL)NbiAllocateMemory (ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+ if (ReceiveBufferPool == NULL) {
+ NB_DEBUG (PACKET, ("Could not allocate receive buffer pool memory\n"));
+ return;
+ }
+
+ RtlZeroMemory (ReceiveBufferPool, ReceiveBufferPoolSize);
+
+ NB_DEBUG2 (PACKET, ("Initializing receive buffer pool %lx, %d buffers, data %d\n",
+ ReceiveBufferPool, Device->InitPackets, DataLength));
+
+ Data = (PUCHAR)(&ReceiveBufferPool->Buffers[Device->InitPackets]);
+
+ for (BufferNum = 0; BufferNum < Device->InitPackets; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+
+ if (NbiInitializeReceiveBuffer (Device, ReceiveBuffer, Data, DataLength) != STATUS_SUCCESS) {
+ NB_DEBUG (PACKET, ("Could not initialize buffer %lx\n", ReceiveBuffer));
+ break;
+ }
+
+#ifdef NB_TRACK_POOL
+ ReceiveBuffer->Pool = ReceiveBufferPool;
+#endif
+
+ Data += DataLength;
+
+ }
+
+ ReceiveBufferPool->BufferCount = BufferNum;
+ ReceiveBufferPool->BufferFree = BufferNum;
+
+ for (BufferNum = 0; BufferNum < ReceiveBufferPool->BufferCount; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+ PushEntryList (&Device->ReceiveBufferList, &ReceiveBuffer->PoolLinkage);
+
+ }
+
+ InsertTailList (&Device->ReceiveBufferPoolList, &ReceiveBufferPool->Linkage);
+
+ Device->AllocatedReceiveBuffers += ReceiveBufferPool->BufferCount;
+
+} /* NbiAllocateReceiveBufferPool */
+#endif _PNP_POWER
+
+#if defined(_PNP_POWER)
+
+VOID
+NbiReAllocateReceiveBufferPool(
+ IN PWORK_QUEUE_ITEM WorkItem
+ )
+
+/*++
+
+Routine Description:
+
+ This routines destroys all the existing Buffer Pools and creates
+ new one using the larger packet size given to us by IPX because
+ a new card was inserted with a larger packet size.
+
+Arguments:
+
+ WorkItem - The work item that was allocated for this.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PDEVICE Device = NbiDevice;
+ CTELockHandle LockHandle;
+
+ NB_GET_LOCK ( &Device->Lock, &LockHandle );
+
+ if ( Device->Bind.LineInfo.MaximumPacketSize > Device->CurMaxReceiveBufferSize ) {
+
+#if DBG
+ DbgPrint("Reallocating new pools due to new maxpacketsize\n");
+#endif
+ NbiDestroyReceiveBufferPools( Device );
+ NbiAllocateReceiveBufferPool( Device, Device->Bind.LineInfo.MaximumPacketSize );
+
+ }
+
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+
+ NbiFreeMemory( WorkItem, sizeof(WORK_QUEUE_ITEM), MEMORY_WORK_ITEM, "Alloc Rcv Buff Work Item freed");
+}
+
+#if !defined(DBG)
+__inline
+#endif
+VOID
+NbiFreeReceiveBufferPool (
+ IN PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees the
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+{
+ PDEVICE Device = NbiDevice;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ UINT ReceiveBufferPoolSize,i;
+
+ CTEAssert( ReceiveBufferPool->BufferDataSize );
+
+ ReceiveBufferPoolSize = FIELD_OFFSET (NB_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(NB_RECEIVE_BUFFER) * Device->InitPackets) +
+ (ReceiveBufferPool->BufferDataSize * Device->InitPackets);
+
+ //
+ // Check if we can free this pool
+ //
+ CTEAssert(ReceiveBufferPool->BufferCount == ReceiveBufferPool->BufferFree );
+
+ for (i = 0; i < ReceiveBufferPool->BufferCount; i++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[i];
+ NbiDeinitializeReceiveBuffer (Device, ReceiveBuffer);
+
+ }
+
+ RemoveEntryList( &ReceiveBufferPool->Linkage );
+
+ NB_DEBUG2 (PACKET, ("Free buffer pool %lx\n", ReceiveBufferPool));
+
+ NbiFreeMemory (ReceiveBufferPool, ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+
+}
+
+
+VOID
+NbiDestroyReceiveBufferPools(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routines walks the ReceiveBufferPoolList and destroys the
+ pool which does not have any buffer in use.
+
+Arguments:
+
+Return Value:
+
+ None.
+
+ THIS ROUTINE COULD BE CALLED WITH THE DEVICE LOCK HELD. If this
+ routine is also called from the DestroyDevice routine, it is not
+ necessary to call this with the lock.
+
+--*/
+{
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY Unused;
+
+
+ //
+ // Clean up this list before we call NbiFreeReceiveBufferPool bcoz that will
+ // simply destroy all the buffer which might be queue here on this list.
+ // At the end of this routine we must start with a fresh ReceiveBufferList.
+ //
+ do {
+ Unused = PopEntryList( &Device->ReceiveBufferList );
+ } while( Unused );
+
+ //
+ // Now destroy each individual ReceiveBufferPool.
+ //
+ for ( p = Device->ReceiveBufferPoolList.Flink;
+ p != &Device->ReceiveBufferPoolList;
+ ) {
+
+
+ ReceiveBufferPool = CONTAINING_RECORD (p, NB_RECEIVE_BUFFER_POOL, Linkage);
+ p = p->Flink;
+
+ //
+ // This will destroy and unlink this Pool if none of its buffer is
+ // in use currently.
+ //
+
+ if ( ReceiveBufferPool->BufferCount == ReceiveBufferPool->BufferFree ) {
+ NbiFreeReceiveBufferPool( ReceiveBufferPool );
+ } else {
+ //
+ // When the device is stopping we must succeed in freeing the pool.
+ CTEAssert( Device->State != DEVICE_STATE_STOPPING );
+ }
+
+ }
+
+}
+
+
+VOID
+NbiPushReceiveBuffer (
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the receive buffer back to the free list.
+ It checks the size of this buffer. If it is smaller than the
+ the CurMaxReceiveBufferSize, then it does not return this back
+ to the free list, instead it destroys it and possibly also
+ destroys the pool associated with it. O/w it simply returns this
+ to the free list.
+
+Arguments:
+
+ ReceiveBuffer - Pointer to the buffer to be returned to the free list.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool = (PNB_RECEIVE_BUFFER_POOL)ReceiveBuffer->Pool;
+ PDEVICE Device = NbiDevice;
+ CTELockHandle LockHandle;
+#if defined(DBG)
+ ULONG BufLen = 0;
+#endif
+
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+
+#if defined(DBG)
+ NdisQueryBuffer( ReceiveBuffer->NdisBuffer, NULL, &BufLen );
+ CTEAssert( BufLen == ReceiveBufferPool->BufferDataSize );
+#endif
+
+ //
+ // This is an old buffer which was in use when we changed
+ // the CurMaxReceiveBufferSize due to new adapter. We must not
+ // return this buffer back to free list. Infact, if the pool
+ // associated with this buffer does not have any other buffers
+ // in use, we should free the pool also.
+ CTEAssert( ReceiveBufferPool->BufferFree < ReceiveBufferPool->BufferCount );
+ ReceiveBufferPool->BufferFree++;
+
+ if ( ReceiveBufferPool->BufferDataSize < Device->CurMaxReceiveBufferSize ) {
+
+#if DBG
+ DbgPrint("ReceiveBuffer %lx, not returned to pool %lx( Free %d)\n", ReceiveBuffer, ReceiveBufferPool, ReceiveBufferPool->BufferFree);
+#endif
+
+
+ if ( ReceiveBufferPool->BufferFree == ReceiveBufferPool->BufferCount ) {
+ NbiFreeReceiveBufferPool( ReceiveBufferPool );
+ }
+ } else {
+
+ PushEntryList( &Device->ReceiveBufferList, &ReceiveBuffer->PoolLinkage );
+
+
+ }
+
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+}
+#endif _PNP_POWER
+
+
+PSINGLE_LIST_ENTRY
+NbiPopSendPacket(
+ IN PDEVICE Device,
+ IN BOOLEAN LockAcquired
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool.
+ If there are no packets in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+ LockAcquired - TRUE if Device->Lock is acquired.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ CTELockHandle LockHandle;
+
+ s = ExInterlockedPopEntrySList(
+ &Device->SendPacketList,
+ &NbiGlobalPoolInterlock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (!LockAcquired) {
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+ }
+
+ if (Device->AllocatedSendPackets < Device->MaxPackets) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+
+ NbiAllocateSendPool (Device);
+
+
+ if (!LockAcquired) {
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+
+ s = ExInterlockedPopEntrySList(
+ &Device->SendPacketList,
+ &NbiGlobalPoolInterlock);
+
+ return s;
+ } else {
+
+ if (!LockAcquired) {
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+ return NULL;
+ }
+
+} /* NbiPopSendPacket */
+
+
+VOID
+NbiPushSendPacket(
+ IN PNB_SEND_RESERVED Reserved
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees a packet back to the device context's pool.
+ If there are connections waiting for packets, it removes
+ one from the list and inserts it on the packetize queue.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ PLIST_ENTRY p;
+ PCONNECTION Connection;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ //
+ // BUGBUG: Make this a function. Optimize for
+ // UP by not doing two checks?
+ //
+
+ if (!IsListEmpty (&Device->WaitPacketConnections)) {
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ p = RemoveHeadList (&Device->WaitPacketConnections);
+
+ //
+ // Take a connection off the WaitPacketQueue and put it
+ // on the PacketizeQueue. We don't worry about if the
+ // connection has stopped, that will get checked when
+ // the PacketizeQueue is run down.
+ //
+ // Since this is in send completion, we may not get
+ // a receive complete. We guard against this by calling
+ // NbiReceiveComplete from the long timer timeout.
+ //
+
+ if (p != &Device->WaitPacketConnections) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, WaitPacketLinkage);
+
+ CTEAssert (Connection->OnWaitPacketQueue);
+ Connection->OnWaitPacketQueue = FALSE;
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_W_PACKET) {
+
+ CTEAssert (!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ NbiTransferReferenceConnection (Connection, CREF_W_PACKET, CREF_PACKETIZE);
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ } else {
+
+ NbiDereferenceConnection (Connection, CREF_W_PACKET);
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ }
+
+} /* NbiPushSendPacket */
+
+
+VOID
+NbiCheckForWaitPacket(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks if a connection is on the wait packet
+ queue and if so takes it off and queues it to be packetized.
+ It is meant to be called when the connection's packet has
+ been freed.
+
+Arguments:
+
+ Connection - The connection to check.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle1);
+
+ if (Connection->OnWaitPacketQueue) {
+
+ Connection->OnWaitPacketQueue = FALSE;
+ RemoveEntryList (&Connection->WaitPacketLinkage);
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_W_PACKET) {
+
+ CTEAssert (!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ NbiTransferReferenceConnection (Connection, CREF_W_PACKET, CREF_PACKETIZE);
+
+ InsertTailList(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage);
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle1);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NbiDereferenceConnection (Connection, CREF_W_PACKET);
+
+ return;
+ }
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle1);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+} /* NbiCheckForWaitPacket */
+
+
+PSINGLE_LIST_ENTRY
+NbiPopReceivePacket(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool.
+ If there are no packets in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ CTELockHandle LockHandle;
+
+ s = ExInterlockedPopEntrySList(
+ &Device->ReceivePacketList,
+ &NbiGlobalPoolInterlock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedReceivePackets < Device->MaxPackets) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ NbiAllocateReceivePool (Device);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ s = ExInterlockedPopEntrySList(
+ &Device->ReceivePacketList,
+ &NbiGlobalPoolInterlock);
+
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* NbiPopReceivePacket */
+
+
+PSINGLE_LIST_ENTRY
+NbiPopReceiveBuffer(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a receive buffer from the device context's pool.
+ If there are no buffers in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the buffer to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated receive buffer.
+
+--*/
+
+{
+#if defined(_PNP_POWER)
+ PSINGLE_LIST_ENTRY s;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ CTELockHandle LockHandle;
+
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+
+ s = PopEntryList( &Device->ReceiveBufferList );
+
+
+ if ( !s ) {
+
+ //
+ // No buffer in the pool, see if we can allocate more.
+ //
+ if (Device->AllocatedReceiveBuffers < Device->MaxReceiveBuffers) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+
+ NbiAllocateReceiveBufferPool (Device, Device->CurMaxReceiveBufferSize );
+ s = PopEntryList(&Device->ReceiveBufferList);
+ }
+ }
+
+ if ( s ) {
+
+
+ //
+ // Decrement the BufferFree count on the corresponding ReceiveBufferPool.
+ // so that we know that
+ ReceiveBuffer = CONTAINING_RECORD( s, NB_RECEIVE_BUFFER, PoolLinkage );
+
+
+ ReceiveBufferPool = (PNB_RECEIVE_BUFFER_POOL)ReceiveBuffer->Pool;
+
+ CTEAssert( ReceiveBufferPool->BufferFree && ( ReceiveBufferPool->BufferFree <= ReceiveBufferPool->BufferCount ) );
+ CTEAssert( ReceiveBufferPool->BufferDataSize == Device->CurMaxReceiveBufferSize );
+
+ ReceiveBufferPool->BufferFree--;
+
+ }
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ return s;
+#else
+ PSINGLE_LIST_ENTRY s;
+ CTELockHandle LockHandle;
+
+ s = ExInterlockedPopEntryList(
+ &Device->ReceiveBufferList,
+ &Device->Lock.Lock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No buffer in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedReceiveBuffers < Device->MaxReceiveBuffers) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ NbiAllocateReceiveBufferPool (Device);
+ s = PopEntryList(&Device->ReceiveBufferList);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+#endif _PNP_POWER
+} /* NbiPopReceiveBuffer */
+
diff --git a/private/ntos/tdi/isnp/nb/precomp.h b/private/ntos/tdi/isnp/nb/precomp.h
new file mode 100644
index 000000000..a024f2d3d
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/precomp.h
@@ -0,0 +1,42 @@
+/*++
+
+Copyright (c) 1993-1995 Microsoft Corporation
+
+Module Name:
+
+ precomp.h
+
+Abstract:
+
+ Precompilation header file.
+
+Author:
+
+ Adam Barr (adamba) 08-Sep-1993
+
+Revision History:
+
+--*/
+
+#define ISN_NT 1
+
+//
+// These are needed for CTE
+//
+
+#if DBG
+#define DEBUG 1
+#endif
+
+#define NT 1
+
+#include <ntos.h>
+#include <tdikrnl.h>
+#include <ndis.h>
+#include <cxport.h>
+#include <bind.h>
+#include "isnnb.h"
+#include "config.h"
+#include "nbitypes.h"
+#include "nbiprocs.h"
+#include "zwapi.h"
diff --git a/private/ntos/tdi/isnp/nb/query.c b/private/ntos/tdi/isnp/nb/query.c
new file mode 100644
index 000000000..6ee33adf3
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/query.c
@@ -0,0 +1,1817 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ query.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiQueryInformation
+ o TdiSetInformation
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Remove the warning -- this is defined in windef also.
+//
+
+#ifdef FAR
+#undef FAR
+#endif
+
+#include <windef.h>
+#include <nb30.h>
+
+
+//
+// Useful macro to obtain the total length of a buffer chain.
+// BUGBUG: Make this use NDIS macros.
+//
+
+#define NbiGetBufferChainLength(Buffer, Length) { \
+ PNDIS_BUFFER _Buffer = (Buffer); \
+ *(Length) = 0; \
+ while (_Buffer) { \
+ *(Length) += MmGetMdlByteCount(_Buffer); \
+ _Buffer = _Buffer->Next; \
+ } \
+}
+
+
+NTSTATUS
+NbiTdiQueryInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiQueryInformation request for the transport
+ provider.
+
+Arguments:
+
+ Request - the request for the operation.
+
+Return Value:
+
+ The status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTDI_REQUEST_KERNEL_QUERY_INFORMATION Query;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PCONNECTION Connection;
+ union {
+ struct {
+ ULONG ActivityCount;
+ TA_NETBIOS_ADDRESS NbiAddress;
+ } AddressInfo;
+ TA_NETBIOS_ADDRESS BroadcastAddress;
+ TDI_ADDRESS_IPX IpxAddress;
+ TDI_DATAGRAM_INFO DatagramInfo;
+ struct {
+ FIND_NAME_HEADER Header;
+ FIND_NAME_BUFFER Buffer;
+ } FindNameInfo;
+ } TempBuffer;
+ IPX_SOURCE_ROUTING_INFO SourceRoutingInfo;
+ PADAPTER_STATUS AdapterStatus;
+ BOOLEAN RemoteAdapterStatus;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteAddress;
+ ULONG TargetBufferLength;
+ ULONG AdapterStatusLength;
+ ULONG ValidStatusLength;
+ ULONG ElementSize, TransportAddressSize;
+ PTRANSPORT_ADDRESS TransportAddress;
+ TA_ADDRESS UNALIGNED * CurAddress;
+ PNETBIOS_CACHE CacheName;
+ FIND_NAME_HEADER UNALIGNED * FindNameHeader;
+ UINT FindNameBufferLength;
+ NTSTATUS QueryStatus;
+ CTELockHandle LockHandle;
+ PLIST_ENTRY p;
+ BOOLEAN UsedConnection;
+ UINT i;
+
+
+ //
+ // what type of status do we want?
+ //
+
+ Query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)REQUEST_PARAMETERS(Request);
+
+ switch (Query->QueryType) {
+
+ case TDI_QUERY_ADDRESS_INFO:
+
+ //
+ // The caller wants the exact address value.
+ //
+
+ if (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_NOT_OK);
+#else
+ Status = NbiVerifyAddressFile (AddressFile);
+#endif _PNP_POWER
+
+ if (!NT_SUCCESS(Status)) {
+ break;
+ }
+
+ UsedConnection = FALSE;
+
+ } else if (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE) {
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+
+ if (!NT_SUCCESS(Status)) {
+ break;
+ }
+
+ UsedConnection = TRUE;
+
+ AddressFile = Connection->AddressFile;
+
+ } else {
+
+ Status = STATUS_INVALID_ADDRESS;
+ break;
+
+ }
+
+ Address = AddressFile->Address;
+
+ NB_DEBUG2 (QUERY, ("Query address info on %lx\n", AddressFile));
+
+ TempBuffer.AddressInfo.ActivityCount = 0;
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+
+ if (CONTAINING_RECORD (p, ADDRESS_FILE, Linkage)->State == ADDRESSFILE_STATE_OPEN) {
+ ++TempBuffer.AddressInfo.ActivityCount;
+ }
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ TdiBuildNetbiosAddress(
+ AddressFile->Address->NetbiosAddress.NetbiosName,
+ (BOOLEAN)(AddressFile->Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_GROUP),
+ &TempBuffer.AddressInfo.NbiAddress);
+
+ Status = TdiCopyBufferToMdl(
+ &TempBuffer.AddressInfo,
+ 0,
+ sizeof(ULONG) + sizeof(TA_NETBIOS_ADDRESS),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ if (UsedConnection) {
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ } else {
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ }
+
+ break;
+
+ case TDI_QUERY_CONNECTION_INFO:
+
+ //
+ // Connection info is queried on a connection,
+ // verify this.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ if (Connection->State != CONNECTION_STATE_ACTIVE) {
+
+ Status = STATUS_INVALID_CONNECTION;
+
+ } else {
+
+ //
+ // Assume 50 ms of delay for every hop after the
+ // first. The delay is returned as a negative number.
+ //
+
+ if (Connection->HopCount > 1) {
+ Connection->ConnectionInfo.Delay.HighPart = (ULONG)-1;
+ Connection->ConnectionInfo.Delay.LowPart =
+ -((Connection->HopCount-1) * 50 * MILLISECONDS);
+ } else {
+ Connection->ConnectionInfo.Delay.HighPart = 0;
+ Connection->ConnectionInfo.Delay.LowPart = 0;
+ }
+
+ //
+ // We have tick count; to convert to bytes/second we do:
+ //
+ // packet 576 bytes 18.21 ticks
+ // ---------------- * --------- * -----------
+ // tick_count ticks packet seconds
+ //
+ // to get 10489/tick_count = bytes/second. We
+ // double this because routers tend to
+ // overestimate it.
+ //
+ // Since tick_count has such a low granularity,
+ // a tick count of 1 gives us a throughput of
+ // only 84 kbps, which is much too low. In
+ // that case we return twice the link speed
+ // which is in 100 bps units; that corresponds
+ // to about 1/6 of our bandwidth in bytes/sec.
+ //
+
+ if (Connection->TickCount <= Connection->HopCount) {
+
+ Connection->ConnectionInfo.Throughput.QuadPart =
+ UInt32x32To64 (Connection->LineInfo.LinkSpeed, 2);
+
+ } else {
+
+ Connection->ConnectionInfo.Throughput.HighPart = 0;
+ Connection->ConnectionInfo.Throughput.LowPart =
+ 20978 / (Connection->TickCount - Connection->HopCount);
+
+ }
+
+ Connection->ConnectionInfo.Unreliable = FALSE;
+
+ Status = TdiCopyBufferToMdl (
+ &Connection->ConnectionInfo,
+ 0,
+ sizeof(TDI_CONNECTION_INFO),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ break;
+
+ case TDI_QUERY_PROVIDER_INFO:
+
+ NB_DEBUG2 (QUERY, ("Query provider info\n"));
+
+ Status = TdiCopyBufferToMdl (
+ &Device->Information,
+ 0,
+ sizeof (TDI_PROVIDER_INFO),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_BROADCAST_ADDRESS:
+
+ //
+ // for this provider, the broadcast address is a zero byte name,
+ // contained in a Transport address structure.
+ //
+
+ NB_DEBUG2 (QUERY, ("Query broadcast address\n"));
+
+ TempBuffer.BroadcastAddress.TAAddressCount = 1;
+ TempBuffer.BroadcastAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ TempBuffer.BroadcastAddress.Address[0].AddressLength = 0;
+
+ Status = TdiCopyBufferToMdl (
+ (PVOID)&TempBuffer.BroadcastAddress,
+ 0L,
+ sizeof (TempBuffer.BroadcastAddress.TAAddressCount) +
+ sizeof (TempBuffer.BroadcastAddress.Address[0].AddressType) +
+ sizeof (TempBuffer.BroadcastAddress.Address[0].AddressLength),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ break;
+
+ case TDI_QUERY_ADAPTER_STATUS:
+
+ //
+ // Determine if this is a local or remote query.
+ //
+
+ RemoteAdapterStatus = FALSE;
+
+ if (Query->RequestConnectionInformation != NULL) {
+
+ RemoteAddress = NbiParseTdiAddress(Query->RequestConnectionInformation->RemoteAddress, FALSE);
+
+ if (RemoteAddress == NULL) {
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+#if defined(_PNP_POWER)
+ if ( !NbiFindAdapterAddress(
+ RemoteAddress->NetbiosName,
+ LOCK_NOT_ACQUIRED ) ) {
+
+ RemoteAdapterStatus = TRUE;
+ }
+#else
+ if (!RtlEqualMemory(
+ RemoteAddress->NetbiosName,
+ Device->ReservedNetbiosName,
+ 16)) {
+
+ RemoteAdapterStatus = TRUE;
+
+ }
+#endif _PNP_POWER
+
+ }
+
+ if (RemoteAdapterStatus) {
+
+ //
+ // See if we have this name cached.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Status = CacheFindName(
+ Device,
+ FindNameOther,
+ RemoteAddress->NetbiosName,
+ &CacheName);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A request for routes to this name has been
+ // sent out on the net, we queue up this status
+ // request and processing will be resumed when
+ // we get a response.
+ //
+ // The status field in the request will hold
+ // the cache entry for the remote. The information
+ // field will hold the remote netbios name while
+ // it is in the WaitingAdapterStatus queue, and
+ // will hold a timeout value while we it is in
+ // the ActiveAdapterStatus queue.
+ //
+
+ NB_DEBUG2 (QUERY, ("Queueing up adapter status %lx\n", Request));
+
+ NbiReferenceDevice (Device, DREF_STATUS_QUERY);
+
+ REQUEST_INFORMATION (Request) = (ULONG)RemoteAddress;
+
+ InsertTailList(
+ &Device->WaitingAdapterStatus,
+ REQUEST_LINKAGE (Request));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ } else if (Status == STATUS_SUCCESS) {
+
+ NB_DEBUG2 (QUERY, ("Found adapter status cached %lx\n", Request));
+
+ //
+ // We reference the cache name entry so it won't
+ // go away while we are using it.
+ //
+
+ REQUEST_STATUS(Request) = (NTSTATUS)CacheName;
+ ++CacheName->ReferenceCount;
+
+ NbiReferenceDevice (Device, DREF_STATUS_QUERY);
+
+ REQUEST_INFORMATION (Request) = 0;
+
+ InsertTailList(
+ &Device->ActiveAdapterStatus,
+ REQUEST_LINKAGE (Request));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ NbiSendStatusQuery (Request);
+
+ Status = STATUS_PENDING;
+
+ } else {
+
+ if (Status != STATUS_INSUFFICIENT_RESOURCES) {
+ Status = STATUS_IO_TIMEOUT;
+ }
+
+ REQUEST_INFORMATION (Request) = 0;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ //
+ // Local adapter status.
+ //
+
+ NbiGetBufferChainLength (REQUEST_NDIS_BUFFER(Request), &TargetBufferLength);
+
+ Status = NbiStoreAdapterStatus(
+ TargetBufferLength,
+ 1, // NIC ID, was 0, changed to 1 for Bug #18026
+ // because for NicId = 0, Ipx returns virtual
+ // address. Netbios uses that to register the
+ // name (00...01) and fails.
+ &AdapterStatus,
+ &AdapterStatusLength,
+ &ValidStatusLength);
+
+ if (Status != STATUS_INSUFFICIENT_RESOURCES) {
+
+ //
+ // This should succeed since we know the length
+ // will fit.
+ //
+
+ (VOID)TdiCopyBufferToMdl(
+ AdapterStatus,
+ 0,
+ ValidStatusLength,
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ NbiFreeMemory (AdapterStatus, AdapterStatusLength, MEMORY_STATUS, "Adapter Status");
+
+ }
+
+ }
+
+ break;
+
+ case TDI_QUERY_FIND_NAME:
+
+ //
+ // Check that there is a valid Netbios remote address.
+ //
+
+ if ((Query->RequestConnectionInformation == NULL) ||
+ ((RemoteAddress = NbiParseTdiAddress(Query->RequestConnectionInformation->RemoteAddress, FALSE)) == NULL)) {
+
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+ //
+ // We assume the entire request buffer is in the first
+ // piece of the MDL chain (BUGBUG: Can we do this?).
+ // Make sure there is room for at least the header.
+ //
+
+ NdisQueryBuffer(REQUEST_NDIS_BUFFER(Request), (PVOID *)&FindNameHeader, &FindNameBufferLength);
+ if (FindNameBufferLength < sizeof(FIND_NAME_HEADER)) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // See if we have this name cached. We specify that this is
+ // a netbios name query, so this will only succeed if this is a
+ // unique name -- for a group name it will queue up a find
+ // name query and when we get the response we will fill in
+ // the request's buffer based on it.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Status = CacheFindName(
+ Device,
+ FindNameNetbiosFindName,
+ RemoteAddress->NetbiosName,
+ &CacheName);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A request for routes to this name has been
+ // sent out on the net, we queue up this find
+ // name request and processing will be resumed when
+ // we get a response.
+ //
+ // The information field will hold the remote
+ // netbios name while it is in the WaitingNetbiosFindName
+ // queue. The status will hold the current status --
+ // initially failure, then success, then overflow
+ // if the buffer is too small.
+ //
+
+ NB_DEBUG2 (QUERY, ("Queueing up find name %lx\n", Request));
+
+ NbiReferenceDevice (Device, DREF_NB_FIND_NAME);
+
+ FindNameHeader->node_count = 0;
+ FindNameHeader->reserved = 0;
+ FindNameHeader->unique_group = 0;
+
+ REQUEST_INFORMATION (Request) = (ULONG)RemoteAddress;
+
+ //
+ // Assume it fails, we update the status to
+ // SUCCESS or BUFFER_OVERFLOW if needed.
+ //
+
+ REQUEST_STATUS (Request) = STATUS_IO_TIMEOUT;
+
+ InsertTailList(
+ &Device->WaitingNetbiosFindName,
+ REQUEST_LINKAGE (Request));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ } else if (Status == STATUS_SUCCESS) {
+
+ NB_DEBUG2 (QUERY, ("Found find name cached %lx\n", Request));
+
+ //
+ // We don't need to reference the cache entry since
+ // we only use it here with the lock still held.
+ //
+
+ //
+ // Query the local address, which we will return as
+ // the destination address of this query. Since we
+ // use TempBuffer.IpxAddress for this query, we have
+ // to immediately copy it to its correct place in
+ // TempBuffer.FindNameInfo.Buffer.
+ //
+#if defined(_PNP_POWER)
+ if( (*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ &CacheName->Networks[0].LocalTarget.NicHandle,
+ &TempBuffer.IpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL) != STATUS_SUCCESS ) {
+ NB_DEBUG( QUERY, ("Ipx Query %d failed for Nic %x\n",IPX_QUERY_IPX_ADDRESS,
+ CacheName->Networks[0].LocalTarget.NicHandle.NicId ));
+
+ goto QueryFindNameFailed;
+ }
+#else
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ CacheName->Networks[0].LocalTarget.NicId,
+ &TempBuffer.IpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL);
+#endif _PNP_POWER
+
+ RtlMoveMemory (TempBuffer.FindNameInfo.Buffer.destination_addr, TempBuffer.IpxAddress.NodeAddress, 6);
+ TempBuffer.FindNameInfo.Buffer.access_control = 0x10; // standard token-ring values
+ TempBuffer.FindNameInfo.Buffer.frame_control = 0x40;
+ RtlCopyMemory (TempBuffer.FindNameInfo.Buffer.source_addr, CacheName->FirstResponse.NodeAddress, 6);
+
+ //
+ // Query source routing information about this remote, if any.
+ //
+
+ SourceRoutingInfo.Identifier = IDENTIFIER_NB;
+ RtlCopyMemory (SourceRoutingInfo.RemoteAddress, CacheName->FirstResponse.NodeAddress, 6);
+
+ QueryStatus = (*Device->Bind.QueryHandler)(
+ IPX_QUERY_SOURCE_ROUTING,
+#if defined(_PNP_POWER)
+ &CacheName->Networks[0].LocalTarget.NicHandle,
+#else
+ CacheName->Networks[0].LocalTarget.NicId,
+#endif _PNP_POWER
+ &SourceRoutingInfo,
+ sizeof(IPX_SOURCE_ROUTING_INFO),
+ NULL);
+
+ RtlZeroMemory(TempBuffer.FindNameInfo.Buffer.routing_info, 18);
+ if (QueryStatus != STATUS_SUCCESS) {
+ SourceRoutingInfo.SourceRoutingLength = 0;
+ } else if (SourceRoutingInfo.SourceRoutingLength > 0) {
+ RtlMoveMemory(
+ TempBuffer.FindNameInfo.Buffer.routing_info,
+ SourceRoutingInfo.SourceRouting,
+ SourceRoutingInfo.SourceRoutingLength);
+ }
+
+ TempBuffer.FindNameInfo.Buffer.length = (UCHAR)(14 + SourceRoutingInfo.SourceRoutingLength);
+
+ TempBuffer.FindNameInfo.Header.node_count = 1;
+ TempBuffer.FindNameInfo.Header.reserved = 0;
+ TempBuffer.FindNameInfo.Header.unique_group = 0; // unique
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // 33 is sizeof(FIND_NAME_BUFFER) without the padding.
+ //
+
+ Status = TdiCopyBufferToMdl (
+ (PVOID)&TempBuffer.FindNameInfo,
+ 0,
+ sizeof(FIND_NAME_HEADER) + 33,
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ } else {
+
+#if defined(_PNP_POWER)
+QueryFindNameFailed:
+#endif _PNP_POWER
+
+ if (Status != STATUS_INSUFFICIENT_RESOURCES) {
+ Status = STATUS_IO_TIMEOUT;
+ }
+
+ REQUEST_INFORMATION (Request) = 0;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ break;
+
+ case TDI_QUERY_PROVIDER_STATISTICS:
+
+ //
+ // BETABUGBUG: Keep track of more of these.
+ //
+
+ NB_DEBUG2 (QUERY, ("Query provider statistics\n"));
+
+ Status = TdiCopyBufferToMdl (
+ &Device->Statistics,
+ 0,
+ FIELD_OFFSET (TDI_PROVIDER_STATISTICS, ResourceStats[0]),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_DATAGRAM_INFO:
+
+ NB_DEBUG2 (QUERY, ("Query datagram info\n"));
+
+ TempBuffer.DatagramInfo.MaximumDatagramBytes = 0;
+ TempBuffer.DatagramInfo.MaximumDatagramCount = 0;
+
+ Status = TdiCopyBufferToMdl (
+ &TempBuffer.DatagramInfo,
+ 0,
+ sizeof(TempBuffer.DatagramInfo),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_DATA_LINK_ADDRESS:
+ case TDI_QUERY_NETWORK_ADDRESS:{
+#if defined(_PNP_POWER)
+ Status = (*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ (Query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS
+ ? IPX_QUERY_DATA_LINK_ADDRESS
+ : IPX_QUERY_NETWORK_ADDRESS ),
+ NULL,
+ Request,
+ 0,
+ NULL);
+#else
+ ULONG TransportAddressAllocSize;
+
+ if (Query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
+ ElementSize = (2 * sizeof(USHORT)) + 6;
+ } else {
+ ElementSize = (2 * sizeof(USHORT)) + sizeof(TDI_ADDRESS_IPX);
+ }
+
+// TransportAddress = CTEAllocMem(sizeof(int) + (ElementSize * Device->MaximumNicId));
+ TransportAddressAllocSize = sizeof(int) + ( ElementSize * Device->MaximumNicId);
+ TransportAddress = NbiAllocateMemory( TransportAddressAllocSize, MEMORY_QUERY, "Temp Query Allocation");
+
+ if (TransportAddress == NULL) {
+
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ TransportAddress->TAAddressCount = 0;
+ TransportAddressSize = sizeof(int);
+ CurAddress = (TA_ADDRESS UNALIGNED *)TransportAddress->Address;
+
+ for (i = 1; i <= Device->MaximumNicId; i++) {
+
+ Status = (*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ (USHORT)i,
+ &TempBuffer.IpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+ continue;
+ }
+
+ if (Query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
+ CurAddress->AddressLength = 6;
+ CurAddress->AddressType = TDI_ADDRESS_TYPE_UNSPEC;
+ RtlCopyMemory (CurAddress->Address, TempBuffer.IpxAddress.NodeAddress, 6);
+ } else {
+ CurAddress->AddressLength = sizeof(TDI_ADDRESS_IPX);
+ CurAddress->AddressType = TDI_ADDRESS_TYPE_IPX;
+ RtlCopyMemory (CurAddress->Address, &TempBuffer.IpxAddress, sizeof(TDI_ADDRESS_IPX));
+ }
+ ++TransportAddress->TAAddressCount;
+ TransportAddressSize += ElementSize;
+ CurAddress = (TA_ADDRESS UNALIGNED *)(((PUCHAR)CurAddress) + ElementSize);
+
+ }
+
+ Status = TdiCopyBufferToMdl (
+ TransportAddress,
+ 0,
+ TransportAddressSize,
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+// CTEFreeMem (TransportAddress);
+ NbiFreeMemory( TransportAddress, TransportAddressAllocSize, MEMORY_QUERY, "Temp Query Allocation");
+
+ }
+#endif _PNP_POWER
+ break;
+ }
+ default:
+
+ NB_DEBUG (QUERY, ("Invalid query type %d\n", Query->QueryType));
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ return Status;
+
+} /* NbiTdiQueryInformation */
+
+
+NTSTATUS
+NbiStoreAdapterStatus(
+ IN ULONG MaximumLength,
+ IN USHORT NicId,
+ OUT PVOID * StatusBuffer,
+ OUT ULONG * StatusBufferLength,
+ OUT ULONG * ValidBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates an ADAPTER_STATUS buffer and
+ fills it in. The buffer will be allocated at most
+ MaximumLength size. The caller is responsible for
+ freeing the buffer.
+
+Arguments:
+
+ MaximumLength - The maximum length to allocate.
+
+ NicId - The NIC ID the query was received on, or 0 for
+ a local query.
+
+ StatusBuffer - Returns the allocated buffer.
+
+ StatusBufferLength - Returns the length of the buffer.
+
+ ValidBufferLength - Returns the length of the buffer which
+ contains valid adapter status data.
+
+Return Value:
+
+ STATUS_SUCCESS - The buffer was written successfully.
+ STATUS_BUFFER_OVERFLOW - The buffer was written but not all
+ data could fit in MaximumLength bytes.
+ STATUS_INSUFFICIENT_RESOURCES - The buffer could not be allocated.
+
+--*/
+
+{
+
+ PADAPTER_STATUS AdapterStatus;
+ PNAME_BUFFER NameBuffer;
+ ADAPTER_STATUS TempAdapterStatus;
+#if !defined(_PNP_POWER)
+ TDI_ADDRESS_IPX IpxAddress;
+#endif !_PNP_POWER
+ PDEVICE Device = NbiDevice;
+ PADDRESS Address;
+ UCHAR NameCount;
+ ULONG LengthNeeded;
+ ULONG BytesWritten;
+ NTSTATUS Status;
+ PLIST_ENTRY p;
+ CTELockHandle LockHandle;
+
+
+ //
+ // First fill in the basic adapter status structure, to make
+ // it easier to copy over if the target buffer is really short.
+ //
+
+ RtlZeroMemory ((PVOID)&TempAdapterStatus, sizeof(ADAPTER_STATUS));
+
+#if defined(_PNP_POWER)
+ RtlCopyMemory (TempAdapterStatus.adapter_address, Device->Bind.Node, 6);
+#else
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ NicId,
+ &IpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL);
+
+ RtlCopyMemory (TempAdapterStatus.adapter_address, IpxAddress.NodeAddress, 6);
+#endif _PNP_POWER
+
+
+ //
+ // Some of the fields mean different things for Novell Netbios,
+ // as described in the comments.
+ //
+
+ TempAdapterStatus.rev_major = 0; // Jumpers
+ TempAdapterStatus.reserved0 = 0; // SelfTest
+ TempAdapterStatus.adapter_type = 0; // MajorVersion
+ TempAdapterStatus.rev_minor = 0; // MinorVersion
+
+ TempAdapterStatus.duration = 0; // ReportingPeriod
+ TempAdapterStatus.frmr_recv = 0; // ReceiveCRCErrors
+ TempAdapterStatus.frmr_xmit = 0; // ReceiveAlignErrors
+
+ TempAdapterStatus.iframe_recv_err = 0; // XmitCollisions
+ TempAdapterStatus.xmit_aborts = 0; // XmitAbort
+
+ TempAdapterStatus.xmit_success = Device->Statistics.DataFramesSent; // SuccessfulXmits
+ TempAdapterStatus.recv_success = Device->Statistics.DataFramesReceived; // SuccessfulReceive
+
+ TempAdapterStatus.iframe_xmit_err = (WORD)Device->Statistics.DataFramesResent; // XmitRetries
+ TempAdapterStatus.recv_buff_unavail = (WORD)Device->Statistics.DataFramesRejected; // ExhaustedResource
+
+ // t1_timeouts, ti_timeouts, and reserved1 are unused.
+
+ TempAdapterStatus.free_ncbs = 0xffff; // FreeBlocks
+ TempAdapterStatus.max_cfg_ncbs = 0xffff; // ConfiguredNCB
+ TempAdapterStatus.max_ncbs = 0xffff; // MaxNCB
+
+ // xmit_bug_unavail and max_dgram_size are unused.
+
+ TempAdapterStatus.pending_sess = (WORD)Device->Statistics.OpenConnections; // CurrentSessions
+ TempAdapterStatus.max_cfg_sess = 0xffff; // MaxSessionConfigured
+ TempAdapterStatus.max_sess = 0xffff; // MaxSessionPossible
+ TempAdapterStatus.max_sess_pkt_size =
+ Device->Bind.LineInfo.MaximumSendSize - sizeof(NB_CONNECTION); // MaxSessionPacketSize
+
+ TempAdapterStatus.name_count = 0;
+
+
+ //
+ // Do a quick estimate of how many names we need room for.
+ // This includes stopping addresses and the broadcast
+ // address, for the moment. BUGBUG: Fix this?
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ LengthNeeded = sizeof(ADAPTER_STATUS) + (Device->AddressCount * sizeof(NAME_BUFFER));
+
+ if (LengthNeeded > MaximumLength) {
+ LengthNeeded = MaximumLength;
+ }
+
+ AdapterStatus = NbiAllocateMemory(LengthNeeded, MEMORY_STATUS, "Adapter Status");
+ if (AdapterStatus == NULL) {
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ *StatusBuffer = AdapterStatus;
+ *StatusBufferLength = LengthNeeded;
+
+ if (LengthNeeded < sizeof(ADAPTER_STATUS)) {
+ RtlCopyMemory (AdapterStatus, &TempAdapterStatus, LengthNeeded);
+ *ValidBufferLength = LengthNeeded;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return STATUS_BUFFER_OVERFLOW;
+ }
+
+ RtlCopyMemory (AdapterStatus, &TempAdapterStatus, sizeof(ADAPTER_STATUS));
+
+ BytesWritten = sizeof(ADAPTER_STATUS);
+ NameBuffer = (PNAME_BUFFER)(AdapterStatus+1);
+ NameCount = 0;
+
+ //
+ // Scan through the device's address database, filling in
+ // the NAME_BUFFERs.
+ //
+
+ Status = STATUS_SUCCESS;
+
+ for (p = Device->AddressDatabase.Flink;
+ p != &Device->AddressDatabase;
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ //
+ // Ignore addresses that are shutting down.
+ //
+
+#if defined(_PNP_POWER)
+ if ((Address->State != ADDRESS_STATE_OPEN) ||
+ (Address->Flags & ADDRESS_FLAGS_CONFLICT)) {
+ continue;
+ }
+#else
+ if ((Address->State != ADDRESS_STATE_OPEN) != 0) {
+ continue;
+ }
+#endif _PNP_POWER
+
+ //
+ // Ignore the broadcast address.
+ //
+
+ if (Address->NetbiosAddress.Broadcast) {
+ continue;
+ }
+
+ //
+ // Ignore our reserved address.
+ //
+#if defined(_PNP_POWER)
+ if ( NbiFindAdapterAddress(
+ Address->NetbiosAddress.NetbiosName,
+ LOCK_ACQUIRED
+ )) {
+ continue;
+ }
+#else
+ if (RtlEqualMemory(
+ Address->NetbiosAddress.NetbiosName,
+ Device->ReservedNetbiosName,
+ 16)) {
+ continue;
+ }
+
+#endif _PNP_POWER
+ //
+ // Make sure we still have room.
+ //
+
+ if (BytesWritten + sizeof(NAME_BUFFER) > LengthNeeded) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ break;
+ }
+
+ RtlCopyMemory(
+ NameBuffer->name,
+ Address->NetbiosAddress.NetbiosName,
+ 16);
+
+ ++NameCount;
+ NameBuffer->name_num = NameCount;
+
+ NameBuffer->name_flags = REGISTERED;
+ if (Address->NameTypeFlag == NB_NAME_GROUP) {
+ NameBuffer->name_flags |= GROUP_NAME;
+ }
+
+ //
+ // BUGBUG: name_flags should be done more accurately.
+ //
+
+ BytesWritten += sizeof(NAME_BUFFER);
+ ++NameBuffer;
+
+ }
+
+ AdapterStatus->name_count = (WORD)NameCount;
+ *ValidBufferLength = BytesWritten;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return Status;
+
+} /* NbiStoreAdapterStatus */
+
+
+VOID
+NbiUpdateNetbiosFindName(
+ IN PREQUEST Request,
+#if defined(_PNP_POWER)
+ IN PNIC_HANDLE NicHandle,
+#else
+ IN USHORT NicId,
+#endif _PNP_POWER
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteIpxAddress,
+ IN BOOLEAN Unique
+ )
+
+/*++
+
+Routine Description:
+
+ This routine updates the find name request with the
+ new information received. It updates the status in
+ the request if needed.
+
+Arguments:
+
+ Request - The netbios find name request.
+
+ NicId - The NIC ID the response was received on.
+
+ RemoteIpxAddress - The IPX address of the remote.
+
+ Unique - TRUE if the name is unique.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ FIND_NAME_HEADER UNALIGNED * FindNameHeader;
+ FIND_NAME_BUFFER UNALIGNED * FindNameBuffer;
+ UINT FindNameBufferLength;
+ TDI_ADDRESS_IPX LocalIpxAddress;
+ IPX_SOURCE_ROUTING_INFO SourceRoutingInfo;
+ NTSTATUS QueryStatus;
+ UINT i;
+
+
+ NdisQueryBuffer(REQUEST_NDIS_BUFFER(Request), (PVOID *)&FindNameHeader, &FindNameBufferLength);
+
+ //
+ // Scan through the names saved so far and see if this one
+ // is there.
+ //
+
+ FindNameBuffer = (FIND_NAME_BUFFER UNALIGNED *)(FindNameHeader+1);
+
+ for (i = 0; i < FindNameHeader->node_count; i++) {
+
+ if (RtlEqualMemory(
+ FindNameBuffer->source_addr,
+ RemoteIpxAddress->NodeAddress,
+ 6)) {
+
+ //
+ // This remote already responded, ignore it.
+ //
+
+ return;
+
+ }
+
+ FindNameBuffer = (FIND_NAME_BUFFER UNALIGNED *)
+ (((PUCHAR)FindNameBuffer) + 33);
+
+ }
+
+ //
+ // Make sure there is room for this new node. 33 is
+ // sizeof(FIND_NAME_BUFFER) without padding.
+ //
+
+ if (FindNameBufferLength < sizeof(FIND_NAME_HEADER) + ((FindNameHeader->node_count+1) * 33)) {
+ REQUEST_STATUS(Request) = STATUS_BUFFER_OVERFLOW;
+ return;
+ }
+
+ //
+ // Query the local address, which we will return as
+ // the destination address of this query.
+ //
+
+#if defined(_PNP_POWER)
+ if( (*NbiDevice->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ NicHandle,
+ &LocalIpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL) != STATUS_SUCCESS ) {
+ //
+ // Ignore this response if the query fails. maybe the NicHandle
+ // is bad or it just got removed.
+ //
+ NB_DEBUG( QUERY, ("Ipx Query %d failed for Nic %x\n",IPX_QUERY_IPX_ADDRESS,
+ NicHandle->NicId ));
+ return;
+ }
+#else
+ (VOID)(*NbiDevice->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ NicId,
+ &LocalIpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL);
+#endif _PNP_POWER
+
+ FindNameBuffer->access_control = 0x10; // standard token-ring values
+ FindNameBuffer->frame_control = 0x40;
+ RtlMoveMemory (FindNameBuffer->destination_addr, LocalIpxAddress.NodeAddress, 6);
+ RtlCopyMemory (FindNameBuffer->source_addr, RemoteIpxAddress->NodeAddress, 6);
+
+ //
+ // Query source routing information about this remote, if any.
+ //
+
+ SourceRoutingInfo.Identifier = IDENTIFIER_NB;
+ RtlCopyMemory (SourceRoutingInfo.RemoteAddress, RemoteIpxAddress->NodeAddress, 6);
+
+ QueryStatus = (*NbiDevice->Bind.QueryHandler)(
+ IPX_QUERY_SOURCE_ROUTING,
+#if defined(_PNP_POWER)
+ NicHandle,
+#else
+ NicId,
+#endif _PNP_POWER
+ &SourceRoutingInfo,
+ sizeof(IPX_SOURCE_ROUTING_INFO),
+ NULL);
+
+ RtlZeroMemory(FindNameBuffer->routing_info, 18);
+ if (QueryStatus != STATUS_SUCCESS) {
+ SourceRoutingInfo.SourceRoutingLength = 0;
+ } else if (SourceRoutingInfo.SourceRoutingLength > 0) {
+ RtlMoveMemory(
+ FindNameBuffer->routing_info,
+ SourceRoutingInfo.SourceRouting,
+ SourceRoutingInfo.SourceRoutingLength);
+ }
+
+ FindNameBuffer->length = (UCHAR)(14 + SourceRoutingInfo.SourceRoutingLength);
+
+ ++FindNameHeader->node_count;
+ if (!Unique) {
+ FindNameHeader->unique_group = 1; // group
+ }
+
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+
+} /* NbiUpdateNetbiosFindName */
+
+
+VOID
+NbiSetNetbiosFindNameInformation(
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the REQUEST_INFORMATION field to the right
+ value based on the number of responses recorded in the netbios
+ find name request's buffer.
+
+Arguments:
+
+ Request - The netbios find name request.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ FIND_NAME_HEADER UNALIGNED * FindNameHeader;
+ UINT FindNameBufferLength;
+
+
+ NdisQueryBuffer(REQUEST_NDIS_BUFFER(Request), (PVOID *)&FindNameHeader, &FindNameBufferLength);
+
+ //
+ // 33 is sizeof(FIND_NAME_BUFFER) without the padding.
+ //
+
+ REQUEST_INFORMATION(Request) = sizeof(FIND_NAME_HEADER) + (FindNameHeader->node_count * 33);
+
+} /* NbiSetNetbiosFindNameInformation */
+
+
+NTSTATUS
+NbiTdiSetInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetInformation request for the transport
+ provider.
+
+Arguments:
+
+ Device - the device.
+
+ Request - the request for the operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (Device);
+ UNREFERENCED_PARAMETER (Request);
+
+ return STATUS_NOT_IMPLEMENTED;
+
+} /* NbiTdiSetInformation */
+
+
+VOID
+NbiProcessStatusQuery(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_STATUS_QUERY frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ IPX_LINE_INFO LineInfo;
+ ULONG ResponseSize;
+ NTSTATUS Status;
+ PNDIS_BUFFER AdapterStatusBuffer;
+ PADAPTER_STATUS AdapterStatus;
+ ULONG AdapterStatusLength;
+ ULONG ValidStatusLength;
+ PDEVICE Device = NbiDevice;
+ NB_CONNECTIONLESS UNALIGNED * Connectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
+
+
+ //
+ // The old stack does not include the 14 bytes of padding in
+ // the 802.3 or IPX length of the packet.
+ //
+
+ if (PacketSize < (sizeof(IPX_HEADER) + 2)) {
+ return;
+ }
+
+ //
+ // Get the maximum size we can send.
+ //
+#if defined(_PNP_POWER)
+ if( (*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_LINE_INFO,
+ &RemoteAddress->NicHandle,
+ &LineInfo,
+ sizeof(IPX_LINE_INFO),
+ NULL) != STATUS_SUCCESS ) {
+ //
+ // Bad NicHandle or it just got removed.
+ //
+ NB_DEBUG( QUERY, ("Ipx Query %d failed for Nic %x\n",IPX_QUERY_LINE_INFO,
+ RemoteAddress->NicHandle.NicId ));
+
+ return;
+ }
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+ if (s == NULL) {
+ return;
+ }
+#else
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+ if (s == NULL) {
+ return;
+ }
+
+ //
+ // Get the maximum size we can send.
+ //
+
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_LINE_INFO,
+ RemoteAddress->NicId,
+ &LineInfo,
+ sizeof(IPX_LINE_INFO),
+ NULL);
+#endif _PNP_POWER
+
+ ResponseSize = LineInfo.MaximumSendSize - sizeof(IPX_HEADER) - sizeof(NB_STATUS_RESPONSE);
+
+ //
+ // Get the local adapter status (this allocates a buffer).
+ //
+
+ Status = NbiStoreAdapterStatus(
+ ResponseSize,
+#if defined(_PNP_POWER)
+ RemoteAddress->NicHandle.NicId,
+#else
+ RemoteAddress->NicId,
+#endif _PNP_POWER
+ &AdapterStatus,
+ &AdapterStatusLength,
+ &ValidStatusLength);
+
+ if (Status == STATUS_INSUFFICIENT_RESOURCES) {
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ return;
+ }
+
+ //
+ // Allocate an NDIS buffer to map the extra buffer.
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &AdapterStatusBuffer,
+ Device->NdisBufferPoolHandle,
+ AdapterStatus,
+ ValidStatusLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbiFreeMemory (AdapterStatus, AdapterStatusLength, MEMORY_STATUS, "Adapter Status");
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ return;
+ }
+
+ NB_DEBUG2 (QUERY, ("Reply to AdapterStatus from %lx %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ *(UNALIGNED ULONG *)Connectionless->IpxHeader.SourceNetwork,
+ Connectionless->IpxHeader.SourceNode[0],
+ Connectionless->IpxHeader.SourceNode[1],
+ Connectionless->IpxHeader.SourceNode[2],
+ Connectionless->IpxHeader.SourceNode[3],
+ Connectionless->IpxHeader.SourceNode[4],
+ Connectionless->IpxHeader.SourceNode[5]));
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_STATUS_RESPONSE;
+ Reserved->u.SR_AS.ActualBufferLength = AdapterStatusLength;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ RtlCopyMemory(&Header->IpxHeader.DestinationNetwork, Connectionless->IpxHeader.SourceNetwork, 12);
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_STATUS_RESPONSE)+ValidStatusLength) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_STATUS_RESPONSE)+ValidStatusLength) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ Header->StatusResponse.ConnectionControlFlag = 0x00;
+ Header->StatusResponse.DataStreamType = NB_CMD_STATUS_RESPONSE;
+
+ NbiReferenceDevice (Device, DREF_STATUS_RESPONSE);
+
+ NdisChainBufferAtBack (Packet, AdapterStatusBuffer);
+
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ RemoteAddress,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE) + ValidStatusLength,
+ sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiProcessStatusQuery */
+
+
+VOID
+NbiSendStatusQuery(
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends NB_CMD_STATUS_QUERY frames.
+
+Arguments:
+
+ Request - Holds the request describing the remote adapter
+ status query. REQUEST_STATUS(Request) points
+ to the netbios cache entry for the remote name.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ PNETBIOS_CACHE CacheName;
+ PIPX_LOCAL_TARGET LocalTarget;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+ if (s == NULL) {
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_STATUS_QUERY;
+
+ CacheName = (PNETBIOS_CACHE)REQUEST_STATUS(Request);
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ RtlCopyMemory (Header->IpxHeader.DestinationNetwork, &CacheName->FirstResponse, 12);
+
+ LocalTarget = &CacheName->Networks[0].LocalTarget;
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_STATUS_QUERY)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_STATUS_QUERY)) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ Header->StatusResponse.ConnectionControlFlag = 0x00;
+ Header->StatusResponse.DataStreamType = NB_CMD_STATUS_QUERY;
+
+ NbiReferenceDevice (Device, DREF_STATUS_FRAME);
+
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) + sizeof(NB_STATUS_QUERY));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_STATUS_QUERY),
+ sizeof(IPX_HEADER) + sizeof(NB_STATUS_QUERY))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiProcessStatusQuery */
+
+
+VOID
+NbiProcessStatusResponse(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_STATUS_RESPONSE frames.
+
+Arguments:
+
+ MacBindingHandle - A handle to use when calling NdisTransferData.
+
+ MacReceiveContext - A context to use when calling NdisTransferData.
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The lookahead buffer, starting at the IPX
+ header.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ CTELockHandle LockHandle;
+ PREQUEST AdapterStatusRequest;
+ PNETBIOS_CACHE CacheName;
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY s;
+ PNDIS_BUFFER TargetBuffer;
+ ULONG TargetBufferLength, BytesToTransfer;
+ ULONG BytesTransferred;
+ NDIS_STATUS NdisStatus;
+ PNB_RECEIVE_RESERVED ReceiveReserved;
+ PNDIS_PACKET Packet;
+ BOOLEAN Found;
+ PNAME_BUFFER NameBuffer;
+ UINT i,NameCount = 0;
+ NB_CONNECTIONLESS UNALIGNED * Connectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)LookaheadBuffer;
+
+
+ if (PacketSize < (sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE))) {
+ return;
+ }
+
+ //
+ // Find out how many names are there.
+ //
+ NameBuffer = (PNAME_BUFFER)(LookaheadBuffer + sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE) + sizeof(ADAPTER_STATUS));
+ if ( LookaheadBufferSize > sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE) + sizeof(ADAPTER_STATUS) ) {
+ NameCount = (LookaheadBufferSize - (sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE) + sizeof(ADAPTER_STATUS)) ) /
+ sizeof(NAME_BUFFER);
+ }
+ //
+ // Find a request queued to this remote. If there are
+ // multiple requests outstanding for the same name we
+ // should get multiple responses, so we only need to
+ // find one.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Found = FALSE;
+ p = Device->ActiveAdapterStatus.Flink;
+
+ while (p != &Device->ActiveAdapterStatus) {
+
+ AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ CacheName = (PNETBIOS_CACHE)REQUEST_STATUS(AdapterStatusRequest);
+ if ( CacheName->Unique ) {
+ if (RtlEqualMemory(
+ &CacheName->FirstResponse,
+ Connectionless->IpxHeader.SourceNetwork,
+ 12)) {
+ Found = TRUE;
+ break;
+ }
+ } else if ( RtlEqualMemory( CacheName->NetbiosName,NetbiosBroadcastName,16)){
+ //
+ // It's a broadcast name. Any response is fine.
+ //
+ Found = TRUE;
+ break;
+ } else {
+ //
+ // It's group name. Make sure that this remote
+ // has this group name registered with him.
+ //
+ for (i =0;i<NameCount;i++) {
+ if ( (RtlEqualMemory(
+ CacheName->NetbiosName,
+ NameBuffer[i].name,
+ 16)) &&
+
+ (NameBuffer[i].name_flags & GROUP_NAME) ) {
+
+ Found = TRUE;
+ break;
+ }
+ }
+ }
+
+ }
+
+ if (!Found) {
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ NB_DEBUG2 (QUERY, ("Got response to AdapterStatus %lx\n", AdapterStatusRequest));
+
+ RemoveEntryList (REQUEST_LINKAGE(AdapterStatusRequest));
+
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free delete name cache entry %lx\n", CacheName));
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Name deleted");
+
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ s = NbiPopReceivePacket (Device);
+ if (s == NULL) {
+
+ REQUEST_INFORMATION (AdapterStatusRequest) = 0;
+ REQUEST_STATUS (AdapterStatusRequest) = STATUS_INSUFFICIENT_RESOURCES;
+
+ NbiCompleteRequest (AdapterStatusRequest);
+ NbiFreeRequest (Device, AdapterStatusRequest);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_QUERY);
+
+ return;
+ }
+
+ ReceiveReserved = CONTAINING_RECORD (s, NB_RECEIVE_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (ReceiveReserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ //
+ // Initialize the receive packet.
+ //
+
+ ReceiveReserved->Type = RECEIVE_TYPE_ADAPTER_STATUS;
+ ReceiveReserved->u.RR_AS.Request = AdapterStatusRequest;
+ REQUEST_STATUS(AdapterStatusRequest) = STATUS_SUCCESS;
+ CTEAssert (!ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = TRUE;
+
+ //
+ // Now that we have a packet and a buffer, set up the transfer.
+ // We will complete the request when the transfer completes.
+ //
+
+ TargetBuffer = REQUEST_NDIS_BUFFER (AdapterStatusRequest);
+
+ NdisChainBufferAtFront (Packet, TargetBuffer);
+
+ NbiGetBufferChainLength (TargetBuffer, &TargetBufferLength);
+ BytesToTransfer = PacketSize - (sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE));
+ if (TargetBufferLength < BytesToTransfer) {
+ BytesToTransfer = TargetBufferLength;
+ REQUEST_STATUS(AdapterStatusRequest) = STATUS_BUFFER_OVERFLOW;
+ }
+
+ (*Device->Bind.TransferDataHandler) (
+ &NdisStatus,
+ MacBindingHandle,
+ MacReceiveContext,
+ LookaheadBufferOffset + (sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE)),
+ BytesToTransfer,
+ Packet,
+ &BytesTransferred);
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+#if DBG
+ if (NdisStatus == STATUS_SUCCESS) {
+ CTEAssert (BytesTransferred == BytesToTransfer);
+ }
+#endif
+
+ NbiTransferDataComplete(
+ Packet,
+ NdisStatus,
+ BytesTransferred);
+
+ }
+
+} /* NbiProcessStatusResponse */
+
diff --git a/private/ntos/tdi/isnp/nb/receive.c b/private/ntos/tdi/isnp/nb/receive.c
new file mode 100644
index 000000000..54ce78944
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/receive.c
@@ -0,0 +1,1303 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ receive.c
+
+Abstract:
+
+ This module contains the code to handle receive indication
+ and posted receives for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 22-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// This routine is a no-op to put in the NbiCallbacks table so
+// we can avoid checking for runt session frames (this is because
+// of how the if is structure below).
+//
+
+VOID
+NbiProcessSessionRunt(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+{
+ return;
+}
+
+NB_CALLBACK_NO_TRANSFER NbiCallbacksNoTransfer[] = {
+ NbiProcessFindName,
+ NbiProcessNameRecognized,
+ NbiProcessAddName,
+ NbiProcessAddName, // processes name in use frames also
+ NbiProcessDeleteName,
+ NbiProcessSessionRunt, // in case get a short session packet
+ NbiProcessSessionEnd,
+ NbiProcessSessionEndAck,
+ NbiProcessStatusQuery
+ };
+
+#ifdef RSRC_TIMEOUT_DBG
+VOID
+NbiProcessDeathPacket(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_SESSION_DATA frames.
+
+Arguments:
+
+ MacBindingHandle - A handle to use when calling NdisTransferData.
+
+ MacReceiveContext - A context to use when calling NdisTransferData.
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The lookahead buffer, starting at the IPX
+ header.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)LookaheadBuffer;
+ NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
+ PCONNECTION Connection;
+ PDEVICE Device = NbiDevice;
+ ULONG Hash;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ DbgPrint("******Received death packet - connid %x\n",Sess->DestConnectionId);
+
+ if ( !NbiGlobalDebugResTimeout ) {
+ return;
+ }
+
+ if (Sess->DestConnectionId != 0xffff) {
+
+ //
+ // This is an active connection, find it using
+ // our session id.
+ //
+
+ Hash = (Sess->DestConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Connection = Device->ConnectionHash[Hash].Connections;
+
+ while (Connection != NULL) {
+
+ if (Connection->LocalConnectionId == Sess->DestConnectionId) {
+ break;
+ }
+ Connection = Connection->NextConnection;
+ }
+
+ if (Connection == NULL) {
+ DbgPrint("********No Connection found with %x id\n",Sess->DestConnectionId);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ DbgPrint("******Received death packet on conn %lx from <%.16s>\n",Connection,Connection->RemoteName);
+ DbgBreakPoint();
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+}
+#endif //RSRC_TIMEOUT_DBG
+
+
+VOID
+NbiReceive(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles receive indications from IPX.
+
+Arguments:
+
+ MacBindingHandle - A handle to use when calling NdisTransferData.
+
+ MacReceiveContext - A context to use when calling NdisTransferData.
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The lookahead buffer, starting at the IPX
+ header.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNB_FRAME NbFrame = (PNB_FRAME)LookaheadBuffer;
+ UCHAR DataStreamType;
+
+ //
+ // We know that this is a frame with a valid IPX header
+ // because IPX would not give it to use otherwise. However,
+ // it does not check the source socket.
+ //
+
+ if (NbFrame->Connectionless.IpxHeader.SourceSocket != NB_SOCKET) {
+ return;
+ }
+
+ ++NbiDevice->Statistics.PacketsReceived;
+
+ // First assume that the DataStreamType is at the normal place i.e 2nd byte
+ //
+
+ // Now see if this is a name frame.
+ //
+ if ( PacketSize == sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME) ) {
+ // In the internet mode, the DataStreamType2 becomes DataStreamType
+ if (NbFrame->Connectionless.IpxHeader.PacketType == 0x14 ) {
+ DataStreamType = NbFrame->Connectionless.NameFrame.DataStreamType2;
+ } else {
+ DataStreamType = NbFrame->Connectionless.NameFrame.DataStreamType;
+ }
+
+ // Is this a name frame?
+ // NB_CMD_FIND_NAME = 1 .... NB_CMD_DELETE_NAME = 5
+ //
+ if ((DataStreamType >= NB_CMD_FIND_NAME) && (DataStreamType <= NB_CMD_DELETE_NAME)) {
+ if (LookaheadBufferSize == PacketSize) {
+ (*NbiCallbacksNoTransfer[DataStreamType-1])(
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize);
+ }
+ return;
+ }
+
+ }
+
+#ifdef RSRC_TIMEOUT_DBG
+ if ((PacketSize >= sizeof(NB_CONNECTION)) &&
+ (NbFrame->Connection.Session.DataStreamType == NB_CMD_DEATH_PACKET)) {
+
+ NbiProcessDeathPacket(
+ MacBindingHandle,
+ MacReceiveContext,
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ LookaheadBufferOffset,
+ PacketSize);
+ }
+#endif //RSRC_TIMEOUT_DBG
+
+ if ((PacketSize >= sizeof(NB_CONNECTION)) &&
+ (NbFrame->Connection.Session.DataStreamType == NB_CMD_SESSION_DATA)) {
+
+ NbiProcessSessionData(
+ MacBindingHandle,
+ MacReceiveContext,
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ LookaheadBufferOffset,
+ PacketSize);
+
+ } else {
+
+ DataStreamType = NbFrame->Connectionless.NameFrame.DataStreamType;
+ // Handle NB_CMD_SESSION_END = 7 ... NB_CMD_STATUS_QUERY = 9
+ //
+ if ((DataStreamType >= NB_CMD_SESSION_END ) && (DataStreamType <= NB_CMD_STATUS_QUERY)) {
+ if (LookaheadBufferSize == PacketSize) {
+ (*NbiCallbacksNoTransfer[DataStreamType-1])(
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize);
+ }
+
+ } else if (DataStreamType == NB_CMD_STATUS_RESPONSE) {
+
+ NbiProcessStatusResponse(
+ MacBindingHandle,
+ MacReceiveContext,
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ LookaheadBufferOffset,
+ PacketSize);
+
+ } else if ((DataStreamType == NB_CMD_DATAGRAM) ||
+ (DataStreamType == NB_CMD_BROADCAST_DATAGRAM)) {
+
+ NbiProcessDatagram(
+ MacBindingHandle,
+ MacReceiveContext,
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ LookaheadBufferOffset,
+ PacketSize,
+ (BOOLEAN)(DataStreamType == NB_CMD_BROADCAST_DATAGRAM));
+
+ }
+
+ }
+
+} /* NbiReceive */
+
+
+VOID
+NbiReceiveComplete(
+ IN USHORT NicId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles receive complete indications from IPX.
+
+Arguments:
+
+ NicId - The NIC ID on which a receive was previously indicated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PLIST_ENTRY p;
+ PADDRESS Address;
+ PREQUEST Request;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ PDEVICE Device = NbiDevice;
+ LIST_ENTRY LocalList;
+ PCONNECTION Connection;
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+
+ //
+ // Complete any pending receive requests.
+ //
+
+
+ if (!IsListEmpty (&Device->ReceiveCompletionQueue)) {
+
+ p = NB_REMOVE_HEAD_LIST(
+ &Device->ReceiveCompletionQueue,
+ &Device->Lock);
+
+ while (!NB_LIST_WAS_EMPTY(&Device->ReceiveCompletionQueue, p)) {
+
+ Request = LIST_ENTRY_TO_REQUEST (p);
+
+ //
+ // BUGBUG: Cache the connection somewhere easier
+ // to retrieve?
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_DEBUG2 (RECEIVE, ("Completing receive %lx (%d), status %lx\n",
+ Request, REQUEST_INFORMATION(Request), REQUEST_STATUS(Request)));
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (NbiDevice, Request);
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
+
+ NbiDereferenceConnection (Connection, CREF_RECEIVE);
+
+ p = NB_REMOVE_HEAD_LIST(
+ &Device->ReceiveCompletionQueue,
+ &Device->Lock);
+
+ }
+
+ }
+
+
+ //
+ // Indicate any datagrams to clients.
+ //
+
+ if (!IsListEmpty (&Device->ReceiveDatagrams)) {
+
+ p = NB_REMOVE_HEAD_LIST(
+ &Device->ReceiveDatagrams,
+ &Device->Lock);
+
+ while (!NB_LIST_WAS_EMPTY(&Device->ReceiveDatagrams, p)) {
+
+ ReceiveBuffer = CONTAINING_RECORD (p, NB_RECEIVE_BUFFER, WaitLinkage);
+ Address = ReceiveBuffer->Address;
+
+ NbiIndicateDatagram(
+ Address,
+ ReceiveBuffer->RemoteName,
+ ReceiveBuffer->Data,
+ ReceiveBuffer->DataLength);
+
+#if defined(_PNP_POWER)
+ NbiPushReceiveBuffer ( ReceiveBuffer );
+#else
+ NB_PUSH_ENTRY_LIST(
+ &Device->ReceiveBufferList,
+ &ReceiveBuffer->PoolLinkage,
+ &Device->Lock);
+#endif _PNP_POWER
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ p = NB_REMOVE_HEAD_LIST(
+ &Device->ReceiveDatagrams,
+ &Device->Lock);
+
+ }
+ }
+
+
+ //
+ // Start packetizing connections.
+ //
+
+ if (!IsListEmpty (&Device->PacketizeConnections)) {
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ //
+ // Check again because it may just have become
+ // empty, and the code below depends on it being
+ // non-empty.
+ //
+
+ if (!IsListEmpty (&Device->PacketizeConnections)) {
+
+ //
+ // We copy the list locally, in case someone gets
+ // put back on it. We have to hack the end so
+ // it points to LocalList instead of PacketizeConnections.
+ //
+
+ LocalList = Device->PacketizeConnections;
+ LocalList.Flink->Blink = &LocalList;
+ LocalList.Blink->Flink = &LocalList;
+
+ InitializeListHead (&Device->PacketizeConnections);
+
+ //
+ // Set all these connections to not be on the list, so
+ // NbiStopConnection won't try to take them off.
+ //
+
+ for (p = LocalList.Flink; p != &LocalList; p = p->Flink) {
+ Connection = CONTAINING_RECORD (p, CONNECTION, PacketizeLinkage);
+ CTEAssert (Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = FALSE;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ while (TRUE) {
+
+ p = RemoveHeadList (&LocalList);
+ if (p == &LocalList) {
+ break;
+ }
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, PacketizeLinkage);
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if ((Connection->State == CONNECTION_STATE_ACTIVE) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_A_PACKETIZE)) {
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG (LockHandle)
+ );
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_PACKETIZE);
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+ }
+
+} /* NbiReceiveComplete */
+
+
+VOID
+NbiTransferDataComplete(
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles a transfer data complete indication from
+ IPX, indicating that a previously issued NdisTransferData
+ call has completed.
+
+Arguments:
+
+ Packet - The packet associated with the transfer.
+
+ Status - The status of the transfer.
+
+ BytesTransferred - The number of bytes transferred.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNB_RECEIVE_RESERVED ReceiveReserved;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ PADDRESS Address;
+ PCONNECTION Connection;
+ PNDIS_BUFFER CurBuffer, TmpBuffer;
+ PREQUEST AdapterStatusRequest;
+ PDEVICE Device = NbiDevice;
+ CTELockHandle CancelLH;
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+
+ ReceiveReserved = (PNB_RECEIVE_RESERVED)(Packet->ProtocolReserved);
+
+ switch (ReceiveReserved->Type) {
+
+ case RECEIVE_TYPE_DATA:
+
+ CTEAssert (ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = FALSE;
+
+ Connection = ReceiveReserved->u.RR_CO.Connection;
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ Connection->CurrentReceive = Connection->PreviousReceive;
+ Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ //
+ // BUGBUG: Send a resend ack?
+ //
+
+ } else {
+
+ //
+ // This aborts the current receive and
+ // releases the connection lock.
+ //
+
+ NbiCompleteReceive(
+ Connection,
+ ReceiveReserved->u.RR_CO.EndOfMessage,
+ CancelLH
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ } else {
+
+
+ Connection->CurrentReceive.Offset += BytesTransferred;
+ Connection->CurrentReceive.MessageOffset += BytesTransferred;
+
+ if (ReceiveReserved->u.RR_CO.CompleteReceive ||
+ (Connection->State != CONNECTION_STATE_ACTIVE)) {
+
+ if (ReceiveReserved->u.RR_CO.EndOfMessage) {
+
+ CTEAssert (!ReceiveReserved->u.RR_CO.PartialReceive);
+
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax; // harmless if NewNetbios is FALSE
+ Connection->CurrentReceive.MessageOffset = 0;
+ Connection->CurrentIndicateOffset = 0;
+
+ } else if (Connection->NewNetbios) {
+
+ if (ReceiveReserved->u.RR_CO.PartialReceive) {
+ Connection->CurrentIndicateOffset += BytesTransferred;
+ } else {
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax;
+ Connection->CurrentIndicateOffset = 0;
+ }
+ }
+
+ //
+ // This sends an ack and releases the connection lock.
+ //
+
+ NbiCompleteReceive(
+ Connection,
+ ReceiveReserved->u.RR_CO.EndOfMessage,
+ CancelLH
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle );
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
+
+ if (Connection->NewNetbios) {
+
+ //
+ // A partial receive should only happen if we are
+ // completing the receive.
+ //
+
+ CTEAssert (!ReceiveReserved->u.RR_CO.PartialReceive);
+
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax;
+ Connection->CurrentIndicateOffset = 0;
+
+ if ((Connection->CurrentReceiveNoPiggyback) ||
+ ((Device->AckWindow != 0) &&
+ (++Connection->ReceivesWithoutAck >= Device->AckWindow))) {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ }
+
+ }
+
+ //
+ // Free the NDIS buffer chain if we allocated one.
+ //
+
+ if (!ReceiveReserved->u.RR_CO.NoNdisBuffer) {
+
+ NdisQueryPacket (Packet, NULL, NULL, &CurBuffer, NULL);
+
+ while (CurBuffer) {
+ TmpBuffer = NDIS_BUFFER_LINKAGE (CurBuffer);
+ NdisFreeBuffer (CurBuffer);
+ CurBuffer = TmpBuffer;
+ }
+
+ }
+
+ NdisReinitializePacket (Packet);
+ ExInterlockedPushEntrySList(
+ &Device->ReceivePacketList,
+ &ReceiveReserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+
+ break;
+
+ case RECEIVE_TYPE_DATAGRAM:
+
+ CTEAssert (ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = FALSE;
+
+ ReceiveBuffer = ReceiveReserved->u.RR_DG.ReceiveBuffer;
+
+ //
+ // Free the packet used for the transfer.
+ //
+
+ ReceiveReserved->u.RR_DG.ReceiveBuffer = NULL;
+ NdisReinitializePacket (Packet);
+ ExInterlockedPushEntrySList(
+ &Device->ReceivePacketList,
+ &ReceiveReserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ //
+ // If it succeeded then queue it for indication,
+ // otherwise free the receive buffer also.
+ //
+
+ if (Status == STATUS_SUCCESS) {
+
+ ReceiveBuffer->DataLength = BytesTransferred;
+ NB_INSERT_HEAD_LIST(
+ &Device->ReceiveDatagrams,
+ &ReceiveBuffer->WaitLinkage,
+ &Device->Lock);
+
+ } else {
+
+ Address = ReceiveBuffer->Address;
+
+#if defined(_PNP_POWER)
+ NbiPushReceiveBuffer ( ReceiveBuffer );
+#else
+ NB_PUSH_ENTRY_LIST(
+ &Device->ReceiveBufferList,
+ &ReceiveBuffer->PoolLinkage,
+ &Device->Lock);
+#endif _PNP_POWER
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ }
+
+ break;
+
+ case RECEIVE_TYPE_ADAPTER_STATUS:
+
+ CTEAssert (ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = FALSE;
+
+ AdapterStatusRequest = ReceiveReserved->u.RR_AS.Request;
+
+ //
+ // Free the packet used for the transfer.
+ //
+
+ NdisReinitializePacket (Packet);
+ ExInterlockedPushEntrySList(
+ &Device->ReceivePacketList,
+ &ReceiveReserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ //
+ // Complete the request.
+ //
+
+ if (Status == STATUS_SUCCESS) {
+
+ //
+ // REQUEST_STATUS() is already to set to SUCCESS or
+ // BUFFER_OVERFLOW based on whether the buffer was
+ // big enough.
+ //
+
+ REQUEST_INFORMATION(AdapterStatusRequest) = BytesTransferred;
+
+ } else {
+
+ REQUEST_INFORMATION(AdapterStatusRequest) = 0;
+ REQUEST_STATUS(AdapterStatusRequest) = STATUS_UNEXPECTED_NETWORK_ERROR;
+
+ }
+
+ NbiCompleteRequest (AdapterStatusRequest);
+ NbiFreeRequest (Device, AdapterStatusRequest);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_QUERY);
+
+ break;
+
+ }
+
+} /* NbiTransferDataComplete */
+
+
+VOID
+NbiAcknowledgeReceive(
+ IN PCONNECTION Connection
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a receive needs to be acked to
+ the remote. It either sends a data ack or queues up a piggyback
+ ack request.
+
+ NOTE: THIS FUNCTION IS CALLED WITH THE CONNECTION LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - Pointer to the connection.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+
+ if (Connection->NewNetbios) {
+
+ //
+ // CurrentReceiveNoPiggyback is based on the bits he
+ // set in his frame, NoPiggybackHeuristic is based on
+ // guesses about the traffic pattern, it is set to
+ // TRUE if we think we should not piggyback.
+ //
+
+ if ((!Device->EnablePiggyBackAck) ||
+ (Connection->CurrentReceiveNoPiggyback) ||
+ (Connection->PiggybackAckTimeout) ||
+ (Connection->NoPiggybackHeuristic)) {
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ if (!Connection->DataAckPending) {
+
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+
+ //
+ // Some stacks can have multiple messages
+ // outstanding, so we may already have an
+ // ack queued.
+ //
+
+ Connection->DataAckTimeouts = 0;
+ Connection->DataAckPending = TRUE;
+
+ ++Device->Statistics.PiggybackAckQueued;
+
+ if (!Connection->OnDataAckQueue) {
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle1);
+
+ if (!Connection->OnDataAckQueue) {
+ Connection->OnDataAckQueue = TRUE;
+ InsertTailList (&Device->DataAckConnections, &Connection->DataAckLinkage);
+ }
+
+ if (!Device->DataAckActive) {
+ NbiStartShortTimer (Device);
+ Device->DataAckActive = TRUE;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle1);
+ }
+
+ //
+ // Clear this, since a message ack resets the count.
+ //
+
+ Connection->ReceivesWithoutAck = 0;
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ } else {
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+}
+
+
+VOID
+NbiCompleteReceive(
+ IN PCONNECTION Connection,
+ IN BOOLEAN EndOfMessage,
+ IN CTELockHandle CancelLH
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when we have filled up a receive request
+ and need to complete it.
+
+ NOTE: THIS FUNCTION IS CALLED WITH THE CONNECTION LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+ THIS ROUTINE ALSO HOLDS CANCEL SPIN LOCK WHEN IT IS CALLED
+ AND RELEASES IT WHEN IT RETURNS.
+Arguments:
+
+ Connection - Pointer to the connection.
+
+ EndOfMessage - BOOLEAN set to true if the message end was received.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST Request;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Complete the current receive request. If the connection
+ // has shut down then we complete it right here, otherwise
+ // we queue it for completion in the receive complete
+ // handler.
+ //
+
+ Request = Connection->ReceiveRequest;
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle );
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ if (Connection->State != CONNECTION_STATE_ACTIVE) {
+
+ Connection->ReceiveRequest = NULL; // StopConnection won't do this
+
+ REQUEST_STATUS(Request) = Connection->Status;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NB_DEBUG2 (RECEIVE, ("Completing receive %lx (%d), status %lx\n",
+ Request, REQUEST_INFORMATION(Request), REQUEST_STATUS(Request)));
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (NbiDevice, Request);
+
+ ++Connection->ConnectionInfo.ReceiveErrors;
+
+ NbiDereferenceConnection (Connection, CREF_RECEIVE);
+
+ } else {
+
+ REQUEST_INFORMATION (Request) = Connection->CurrentReceive.Offset;
+
+ if (EndOfMessage) {
+
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+
+ } else {
+
+ REQUEST_STATUS(Request) = STATUS_BUFFER_OVERFLOW;
+
+ }
+
+ //
+ // If we indicated to the client, adjust this down by the
+ // amount of data taken, when it hits zero we can reindicate.
+ //
+
+ if (Connection->ReceiveUnaccepted) {
+ NB_DEBUG2 (RECEIVE, ("Moving Unaccepted %d down by %d\n",
+ Connection->ReceiveUnaccepted, Connection->CurrentReceive.Offset));
+ if (Connection->CurrentReceive.Offset >= Connection->ReceiveUnaccepted) {
+ Connection->ReceiveUnaccepted = 0;
+ } else {
+ Connection->ReceiveUnaccepted -= Connection->CurrentReceive.Offset;
+ }
+ }
+
+ //
+ // BUGBUG: Check whether to activate another receive?
+ //
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_PENDING;
+ Connection->ReceiveRequest = NULL;
+
+ //
+ // This releases the lock.
+ //
+
+ if (Connection->NewNetbios) {
+
+ if (EndOfMessage) {
+
+ NbiAcknowledgeReceive(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ if (Connection->CurrentIndicateOffset != 0) {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResend
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else if ((Connection->CurrentReceiveNoPiggyback) ||
+ ((Device->AckWindow != 0) &&
+ (++Connection->ReceivesWithoutAck >= Device->AckWindow))) {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+ }
+
+ } else {
+
+ NbiSendDataAck(
+ Connection,
+ EndOfMessage ? NbiAckResponse : NbiAckResend
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ ++Connection->ConnectionInfo.ReceivedTsdus;
+
+ //
+ // This will complete the request inside ReceiveComplete,
+ // dereference the connection, and set the state to IDLE.
+ //
+
+ NB_INSERT_TAIL_LIST(
+ &Device->ReceiveCompletionQueue,
+ REQUEST_LINKAGE (Request),
+ &Device->Lock);
+
+ }
+
+} /* NbiCompleteReceive */
+
+
+NTSTATUS
+NbiTdiReceive(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does a receive on an active connection.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the receive.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ PCONNECTION Connection;
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ CTELockHandle CancelLH;
+
+ //
+ // First make sure the connection is valid.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ if (Connection->Type == NB_CONNECTION_SIGNATURE) {
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_BEGIN_SYNC (&SyncContext);
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ //
+ // Make sure the connection is in a good state.
+ //
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ //
+ // If the connection is idle then send it now, otherwise
+ // queue it.
+ //
+
+
+ if (!Request->Cancel) {
+
+ IoSetCancelRoutine (Request, NbiCancelReceive);
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle );
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ NbiReferenceConnectionSync (Connection, CREF_RECEIVE);
+
+ //
+ // Insert this in our queue, then see if we need
+ // to wake up the remote.
+ //
+
+ REQUEST_SINGLE_LINKAGE(Request) = NULL;
+ REQUEST_LIST_INSERT_TAIL(&Connection->ReceiveQueue, Request);
+
+ if (Connection->ReceiveState != CONNECTION_RECEIVE_W_RCV) {
+
+ NB_DEBUG2 (RECEIVE, ("Receive %lx, connection %lx idle\n", Request, Connection));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ } else {
+
+ NB_DEBUG2 (RECEIVE, ("Receive %lx, connection %lx awakened\n", Request, Connection));
+ Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
+
+ //
+ // This releases the lock.
+ //
+
+ if (Connection->NewNetbios) {
+
+ Connection->LocalRcvSequenceMax = (USHORT)
+ (Connection->ReceiveSequence + Connection->ReceiveWindowSize - 1);
+
+ }
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResend
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ NB_END_SYNC (&SyncContext);
+ return STATUS_PENDING;
+
+ } else {
+
+ NB_DEBUG2 (RECEIVE, ("Receive %lx, connection %lx cancelled\n", Request, Connection));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_END_SYNC (&SyncContext);
+
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ return STATUS_CANCELLED;
+
+ }
+
+ } else {
+
+ NB_DEBUG2 (RECEIVE, ("Receive connection %lx state is %d\n", Connection, Connection->State));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_END_SYNC (&SyncContext);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ return STATUS_INVALID_CONNECTION;
+
+ }
+
+ } else {
+
+ NB_DEBUG (RECEIVE, ("Receive connection %lx has bad signature\n", Connection));
+ return STATUS_INVALID_CONNECTION;
+
+ }
+
+} /* NbiTdiReceive */
+
+
+VOID
+NbiCancelReceive(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a receive.
+ The request is found on the connection's receive queue.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PREQUEST Request = (PREQUEST)Irp;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_RECEIVE));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+
+ //
+ // Just stop the connection, that will tear down any
+ // receives.
+ //
+ // BUGBUG: Do we care about cancelling non-active
+ // receives without stopping the connection??
+ //
+ // BUGBUG: This routine is the same as NbiCancelSend,
+ // so if we don't make it more specific, merge the two.
+ //
+
+ NbiReferenceConnectionSync (Connection, CREF_CANCEL);
+
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+
+ NB_BEGIN_SYNC (&SyncContext);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ //
+ // This frees the lock, cancels any sends, etc.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_CANCELLED
+ NB_LOCK_HANDLE_ARG (LockHandle));
+
+ NbiDereferenceConnection (Connection, CREF_CANCEL);
+
+ NB_END_SYNC (&SyncContext);
+
+} /* NbiCancelReceive */
+
diff --git a/private/ntos/tdi/isnp/nb/send.c b/private/ntos/tdi/isnp/nb/send.c
new file mode 100644
index 000000000..a4443c73c
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/send.c
@@ -0,0 +1,2886 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ This module contains the send routines for the Netbios
+ module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 22-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+
+VOID
+NbiSendComplete(
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+)
+
+/*++
+
+Routine Description:
+
+ This routine handles a send completion call from IPX.
+
+Arguments:
+
+ Packet - The packet which has been completed.
+
+ Status - The status of the send.
+
+Return Value:
+
+ None.
+
+--*/
+
+
+
+{
+ PDEVICE Device = NbiDevice;
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ PCONNECTION Connection;
+ PREQUEST DatagramRequest;
+ PREQUEST SendRequest, TmpRequest;
+ PNDIS_BUFFER CurBuffer, TmpBuffer;
+ PNETBIOS_CACHE CacheName;
+ PNDIS_BUFFER SecondBuffer;
+ PVOID SecondBufferMemory;
+ UINT SecondBufferLength;
+ ULONG oldvalue;
+ PNB_SEND_RESERVED Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
+ CTELockHandle CancelLH;
+#if defined(_PNP_POWER)
+ CTELockHandle LockHandle;
+#endif _PNP_POWER
+
+ //
+ // We jump back here if we re-call send from inside this
+ // function and it doesn't pend (to avoid stack overflow).
+ //
+
+FunctionStart:;
+
+ ++Device->Statistics.PacketsSent;
+
+ switch (Reserved->Type) {
+
+ case SEND_TYPE_SESSION_DATA:
+
+ //
+ // This was a send on a session. This references the
+ // IRP.
+ //
+
+ NB_DEBUG2 (SEND, ("Complete NDIS packet %lx\n", Reserved));
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ Connection = Reserved->u.SR_CO.Connection;
+ SendRequest = Reserved->u.SR_CO.Request;
+
+ if (!Reserved->u.SR_CO.NoNdisBuffer) {
+
+ CurBuffer = NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer));
+ while (CurBuffer) {
+ TmpBuffer = NDIS_BUFFER_LINKAGE (CurBuffer);
+ NdisFreeBuffer (CurBuffer);
+ CurBuffer = TmpBuffer;
+ }
+
+ }
+
+ //
+ // If NoNdisBuffer is TRUE, then we could set
+ // Connection->SendBufferInUse to FALSE here. The
+ // problem is that a new send might be in progress
+ // by the time this completes and it may have
+ // used the user buffer, then if we need to
+ // retransmit that packet we would use the buffer
+ // twice. We instead rely on the fact that whenever
+ // we make a new send active we set SendBufferInUse
+ // to FALSE. The net effect is that the user's buffer
+ // can be used the first time a send is packetize
+ // but not on resends.
+ //
+
+ NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = NULL;
+ NdisRecalculatePacketCounts (Packet);
+
+#if DBG
+ if (REQUEST_REFCOUNT(SendRequest) > 100) {
+ DbgPrint ("Request %lx (%lx) has high refcount\n",
+ Connection, SendRequest);
+ DbgBreakPoint();
+ }
+#endif
+
+#if defined(__PNP)
+ NB_GET_LOCK( &Connection->Lock, &LockHandle );
+ oldvalue = REQUEST_REFCOUNT(SendRequest)--;
+ if ( DEVICE_NETWORK_PATH_NOT_FOUND == Status ) {
+ Connection->LocalTarget = Reserved->LocalTarget;
+ }
+ NB_FREE_LOCK( &Connection->Lock, LockHandle );
+#else
+ oldvalue = NB_ADD_ULONG(
+ &REQUEST_REFCOUNT (SendRequest),
+ (ULONG)-1,
+ &Connection->Lock);
+#endif __PNP
+
+ if (oldvalue == 1) {
+
+ //
+ // If the refcount on this request is now zero then
+ // we already got the ack for it, which means
+ // that the ack-processing code has unlinked the
+ // request from Connection->SendQueue. So we
+ // can just run the queue of connections here
+ // and complete them.
+ //
+ // We dereference the connection for all but one
+ // of the requests, we hang on to that until a bit
+ // later so everything stays around.
+ //
+
+ while (TRUE) {
+
+ TmpRequest = REQUEST_SINGLE_LINKAGE (SendRequest);
+ NB_DEBUG2 (SEND, ("Completing request %lx from send complete\n", SendRequest));
+ REQUEST_STATUS (SendRequest) = STATUS_SUCCESS;
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (SendRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ NbiCompleteRequest (SendRequest);
+ NbiFreeRequest (Device, SendRequest);
+ ++Connection->ConnectionInfo.TransmittedTsdus;
+ SendRequest = TmpRequest;
+
+ if (SendRequest == NULL) {
+ break;
+ }
+ NbiDereferenceConnection (Connection, CREF_SEND);
+
+ }
+
+ }
+
+ if (Reserved->OwnedByConnection) {
+
+ Connection->SendPacketInUse = FALSE;
+
+ if (Connection->OnWaitPacketQueue) {
+
+ //
+ // This will put the connection on the packetize
+ // queue if appropriate.
+ //
+
+ NbiCheckForWaitPacket (Connection);
+
+ }
+
+ } else {
+
+ NbiPushSendPacket(Reserved);
+
+ }
+
+ if (oldvalue == 1) {
+ NbiDereferenceConnection (Connection, CREF_SEND);
+ }
+
+ break;
+
+ case SEND_TYPE_NAME_FRAME:
+
+ //
+ // The frame is an add name/delete name; put it back in
+ // the pool and deref the address.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+
+ Address = Reserved->u.SR_NF.Address;
+
+#if !defined(_PNP_POWER)
+ if ((Reserved->u.SR_NF.CurrentNicId) &&
+ (Reserved->u.SR_NF.CurrentNicId < Device->MaximumNicId)) {
+
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ IPX_LOCAL_TARGET TempLocalTarget;
+
+ //
+ // This is a name frame being sent to every address, so
+ // resent it to the next NIC ID. We hold the address
+ // reference through this send.
+ //
+
+ CTEAssert (Address != NULL);
+
+ ++Reserved->u.SR_NF.CurrentNicId;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
+
+ Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
+ Header->NameFrame.ConnectionControlFlag = 0x00;
+ Header->NameFrame.DataStreamType = Reserved->u.SR_NF.DataStreamType;
+ Header->NameFrame.NameTypeFlag = Reserved->u.SR_NF.NameTypeFlag;
+
+ //
+ // This is not a name in use frame so DataStreamType2
+ // is the same as DataStreamType.
+ //
+
+ Header->NameFrame.DataStreamType2 = Reserved->u.SR_NF.DataStreamType;
+
+ RtlCopyMemory(
+ Header->NameFrame.Name,
+ Address->NetbiosAddress.NetbiosName,
+ 16);
+
+ //
+ // Now send the frame (because it is all in the first segment,
+ // IPX will adjust the length of the buffer correctly).
+ //
+
+ TempLocalTarget.NicId = Reserved->u.SR_NF.CurrentNicId;
+ RtlCopyMemory (TempLocalTarget.MacAddress, BroadcastAddress, 6);
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME));
+ if ((Status =
+ (*Device->Bind.SendHandler)(
+ &TempLocalTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
+
+ goto FunctionStart;
+
+ }
+
+ return;
+
+ }
+#endif !_PNP_POWER
+
+ Reserved->SendInProgress = FALSE;
+
+ NbiPushSendPacket (Reserved);
+
+ if (Address) {
+ NbiDereferenceAddress (Address, AREF_NAME_FRAME);
+ } else {
+ NbiDereferenceDevice (Device, DREF_NAME_FRAME);
+ }
+
+ break;
+
+ case SEND_TYPE_SESSION_INIT:
+
+ //
+ // This is a session initialize or session init ack; free
+ // the second buffer, put the packet back in the pool and
+ // deref the device.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ NdisUnchainBufferAtBack (Packet, &SecondBuffer);
+ NdisQueryBuffer (SecondBuffer, &SecondBufferMemory, &SecondBufferLength);
+ CTEAssert (SecondBufferLength == sizeof(NB_SESSION_INIT));
+
+ NdisFreeBuffer(SecondBuffer);
+ NbiFreeMemory (SecondBufferMemory, sizeof(NB_SESSION_INIT), MEMORY_CONNECTION, "Session Initialize");
+
+ NbiPushSendPacket (Reserved);
+
+ NbiDereferenceDevice (Device, DREF_SESSION_INIT);
+
+ break;
+
+ case SEND_TYPE_SESSION_NO_DATA:
+
+ //
+ // This is a frame which was sent on a connection but
+ // has no data (ack, session end, session end ack).
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ Connection = Reserved->u.SR_CO.Connection;
+
+ if (Reserved->OwnedByConnection) {
+
+ CTEAssert (Connection != NULL);
+ Connection->SendPacketInUse = FALSE;
+
+ if (Connection->OnWaitPacketQueue) {
+
+ //
+ // This will put the connection on the packetize
+ // queue if appropriate.
+ //
+
+ NbiCheckForWaitPacket (Connection);
+
+ }
+
+ } else {
+
+ NbiPushSendPacket(Reserved);
+
+ }
+
+ if (Connection != NULL) {
+ NbiDereferenceConnection (Connection, CREF_FRAME);
+ } else {
+ NbiDereferenceDevice (Device, DREF_FRAME);
+ }
+
+ break;
+
+ case SEND_TYPE_FIND_NAME:
+
+ //
+ // The frame is a find name; just set SendInProgress to
+ // FALSE and FindNameTimeout will clean it up.
+ //
+#if defined(_PNP_POWER)
+ NB_GET_LOCK( &Device->Lock, &LockHandle);
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+ //
+ // We keep track of when it finds a net that isn't
+ // a down wan line so that we can tell when datagram
+ // sends should fail (otherwise we succeed them, so
+ // the browser won't think this is a down wan line).
+ //
+ if ( STATUS_SUCCESS == Status ) {
+ NB_SET_SR_FN_SENT_ON_UP_LINE (Reserved, TRUE);
+ } else {
+ NB_DEBUG( CACHE, ("Send complete of find name with failure %lx\n",Status ));
+ }
+ NB_FREE_LOCK(&Device->Lock, LockHandle);
+#else
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+#endif _PNP_POWER
+ break;
+
+ case SEND_TYPE_DATAGRAM:
+
+ //
+ // If there are any more networks to send this on then
+ // do so, otherwise put it back in the pool and complete
+ // the request.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ if ((Reserved->u.SR_DG.Cache == NULL) ||
+ (++Reserved->u.SR_DG.CurrentNetwork >=
+ Reserved->u.SR_DG.Cache->NetworksUsed)) {
+
+ AddressFile = Reserved->u.SR_DG.AddressFile;
+ DatagramRequest = Reserved->u.SR_DG.DatagramRequest;
+
+ NB_DEBUG2 (DATAGRAM, ("Completing datagram %lx on %lx\n", DatagramRequest, AddressFile));
+
+ //
+ // Remove any user buffers chained on this packet.
+ //
+
+ NdisReinitializePacket (Packet);
+ NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = NULL;
+ NdisChainBufferAtFront (Packet, Reserved->HeaderBuffer);
+
+ //
+ // Complete the request.
+ //
+
+ REQUEST_STATUS(DatagramRequest) = Status;
+
+ NbiCompleteRequest(DatagramRequest);
+ NbiFreeRequest (Device, DatagramRequest);
+
+ CacheName = Reserved->u.SR_DG.Cache;
+
+ NbiPushSendPacket (Reserved);
+
+ //
+ // Since we are no longer referencing the cache
+ // name, see if we should delete it (this will
+ // happen if the cache entry was aged out while
+ // the datagram was being processed).
+ //
+
+ if (CacheName != NULL) {
+
+ oldvalue = NB_ADD_ULONG(
+ &CacheName->ReferenceCount,
+ (ULONG)-1,
+ &Device->Lock);
+
+ if (oldvalue == 1) {
+
+ NB_DEBUG2 (CACHE, ("Free aged cache entry %lx\n", CacheName));
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free old cache");
+
+ }
+ }
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_SEND_DGRAM);
+
+ } else {
+
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ PIPX_LOCAL_TARGET LocalTarget;
+ ULONG HeaderLength;
+ ULONG PacketLength;
+
+ // send the datagram on the next net.
+ CTEAssert (!Reserved->u.SR_DG.Cache->Unique);
+ Reserved->SendInProgress = TRUE;
+
+ CacheName = Reserved->u.SR_DG.Cache;
+
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address, so we modify
+ // that for the current netbios cache entry if needed.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+
+
+ *(UNALIGNED ULONG *)Header->IpxHeader.DestinationNetwork = CacheName->Networks[Reserved->u.SR_DG.CurrentNetwork].Network;
+ RtlCopyMemory (&Header->IpxHeader.DestinationNode, BroadcastAddress, 6);
+
+ LocalTarget = &CacheName->Networks[Reserved->u.SR_DG.CurrentNetwork].LocalTarget;
+
+
+ HeaderLength = sizeof(IPX_HEADER) + sizeof(NB_DATAGRAM);
+
+ PacketLength = HeaderLength + REQUEST_INFORMATION(Reserved->u.SR_DG.DatagramRequest);
+
+ Header->IpxHeader.PacketLength[0] = (UCHAR)(PacketLength / 256);
+ Header->IpxHeader.PacketLength[1] = (UCHAR)(PacketLength % 256);
+ Header->IpxHeader.PacketType = 0x04;
+
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ Header->Datagram.ConnectionControlFlag = 0x00;
+ RtlCopyMemory(
+ Header->Datagram.SourceName,
+ Reserved->u.SR_DG.AddressFile->Address->NetbiosAddress.NetbiosName,
+ 16);
+
+ if (Reserved->u.SR_DG.RemoteName != (PVOID)-1) {
+
+ //
+ // This is a directed, as opposed to broadcast, datagram.
+ //
+
+ Header->Datagram.DataStreamType = NB_CMD_DATAGRAM;
+ RtlCopyMemory(
+ Header->Datagram.DestinationName,
+ Reserved->u.SR_DG.RemoteName->NetbiosName,
+ 16);
+
+ } else {
+
+ Header->Datagram.DataStreamType = NB_CMD_BROADCAST_DATAGRAM;
+ RtlZeroMemory(
+ Header->Datagram.DestinationName,
+ 16);
+
+ }
+
+
+ //
+ // Now send the frame (IPX will adjust the length of the
+ // first buffer and the whole frame correctly).
+ //
+
+ if ((Status =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ PacketLength,
+ HeaderLength)) != STATUS_PENDING) {
+
+ goto FunctionStart;
+ }
+
+ }
+
+ break;
+
+ case SEND_TYPE_STATUS_QUERY:
+
+ //
+ // This is an adapter status query, which is a simple
+ // packet.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ NbiPushSendPacket (Reserved);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_FRAME);
+
+ break;
+
+ case SEND_TYPE_STATUS_RESPONSE:
+
+ //
+ // This is an adapter status response, we have to free the
+ // second buffer.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ NdisUnchainBufferAtBack (Packet, &SecondBuffer);
+ NdisQueryBuffer (SecondBuffer, &SecondBufferMemory, &SecondBufferLength);
+
+ NdisFreeBuffer(SecondBuffer);
+ NbiFreeMemory (SecondBufferMemory, Reserved->u.SR_AS.ActualBufferLength, MEMORY_STATUS, "Adapter Status");
+
+ NbiPushSendPacket (Reserved);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_RESPONSE);
+
+ break;
+
+#ifdef RSRC_TIMEOUT_DBG
+ case SEND_TYPE_DEATH_PACKET:
+
+ //
+ // This is a session initialize or session init ack; free
+ // the second buffer, put the packet back in the pool and
+ // deref the device.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+ DbgPrint("********Death packet send completed status %lx\n",Status);
+ DbgBreakPoint();
+ break;
+#endif //RSRC_TIMEOUT_DBG
+
+ default:
+
+ CTEAssert (FALSE);
+ break;
+
+ }
+
+} /* NbiSendComplete */
+
+#if 0
+ULONG NbiLoudSendQueue = 1;
+#endif
+
+VOID
+NbiAssignSequenceAndSend(
+ IN PCONNECTION Connection,
+ IN PNDIS_PACKET Packet
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to ensure that receive sequence numbers on
+ packets are numbered correctly. It is called in place of the lower-level
+ send handler; after assigning the receive sequence number it locks out
+ other sends until the NdisSend call has returned (not necessarily completed),
+ insuring that the packets with increasing receive sequence numbers
+ are queue in the right order by the MAC.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE CONNECTION LOCK HELD, AND
+ RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection the send is on.
+
+ Packet - The packet to send.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS NdisStatus;
+ PNB_SEND_RESERVED Reserved;
+ PLIST_ENTRY p;
+ NB_CONNECTION UNALIGNED * Header;
+ PDEVICE Device = NbiDevice;
+ BOOLEAN NdisSendReference;
+ ULONG result;
+
+
+ Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
+
+ CTEAssert (Connection->State == CONNECTION_STATE_ACTIVE);
+
+ //
+ // If there is a send in progress, then queue this packet
+ // and return.
+ //
+
+ if (Connection->NdisSendsInProgress > 0) {
+
+ NB_DEBUG2 (SEND, ("Queueing send packet %lx on %lx\n", Reserved, Connection));
+ InsertTailList (&Connection->NdisSendQueue, &Reserved->WaitLinkage);
+ ++Connection->NdisSendsInProgress;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+ }
+
+ //
+ // No send in progress. Set the flag to true, and fill in the
+ // receive sequence fields in the packet.
+ //
+
+ Connection->NdisSendsInProgress = 1;
+ NdisSendReference = FALSE;
+ Connection->NdisSendReference = &NdisSendReference;
+
+ while (TRUE) {
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ Header->Session.ReceiveSequence = Connection->ReceiveSequence;
+ if (Connection->NewNetbios) {
+ Header->Session.ReceiveSequenceMax = Connection->LocalRcvSequenceMax;
+ } else {
+ Header->Session.BytesReceived = (USHORT)Connection->CurrentReceive.MessageOffset;
+ }
+
+ //
+ // Since we are acking as much as we know, we can clear
+ // this flag. The connection will eventually get removed
+ // from the queue by the long timeout.
+ //
+
+ Connection->DataAckPending = FALSE;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+ NdisStatus = (*Device->Bind.SendHandler)(
+ &Connection->LocalTarget,
+ Packet,
+ Reserved->u.SR_CO.PacketLength,
+ sizeof(NB_CONNECTION));
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+ //
+ // Take the ref count down, which may allow others
+ // to come through.
+ //
+
+ result = NB_ADD_ULONG(
+ &Connection->NdisSendsInProgress,
+ (ULONG)-1,
+ &Connection->Lock);
+
+ //
+ // We have now sent a packet, see if any queued up while we
+ // were doing it. If the count was zero after removing ours,
+ // then anything else queued is being processed, so we can
+ // exit. If the connection was stopped while we were sending,
+ // a special reference was added which we remove (NbiStopConnection
+ // sets NdisSendReference to TRUE, using the pointer saved
+ // in Connection->NdisSendReference).
+ //
+
+ if (result == 1) {
+ if (NdisSendReference) {
+ NB_DEBUG2 (SEND, ("Remove CREF_NDIS_SEND from %lx\n", Connection));
+ NbiDereferenceConnection (Connection, CREF_NDIS_SEND);
+ }
+ return;
+ }
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ p = RemoveHeadList(&Connection->NdisSendQueue);
+
+ //
+ // If the refcount was not zero, then nobody else should
+ // have taken packets off since they would have been
+ // blocked by us. So, the queue should not be empty.
+ //
+
+ ASSERT (p != &Connection->NdisSendQueue);
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ } // while loop
+
+ //
+ // We should never reach here.
+ //
+
+ CTEAssert (FALSE);
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+} /* NbiAssignSequenceAndSend */
+
+
+NTSTATUS
+NbiTdiSend(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does a send on an active connection.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the send.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PTDI_REQUEST_KERNEL_SEND Parameters;
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ CTELockHandle CancelLH;
+
+ //
+ // First make sure the connection is valid.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ if (Connection->Type == NB_CONNECTION_SIGNATURE) {
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_BEGIN_SYNC (&SyncContext);
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ //
+ // Make sure the connection is in a good state.
+ //
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ //
+ // If the connection is idle then send it now, otherwise
+ // queue it.
+ //
+
+
+ if (!Request->Cancel) {
+
+
+ Parameters = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request);
+
+ //
+ // For old netbios, don't allow sends greater than 64K-1.
+ //
+
+ if ((Connection->NewNetbios) ||
+ (Parameters->SendLength <= 0xffff)) {
+
+ IoSetCancelRoutine (Request, NbiCancelSend);
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle );
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ REQUEST_INFORMATION (Request) = Parameters->SendLength; // assume it succeeds.
+
+ REQUEST_REFCOUNT (Request) = 1; // refcount starts at 1.
+ NbiReferenceConnectionSync (Connection, CREF_SEND);
+
+ //
+ // NOTE: The connection send queue is managed such
+ // that the current send being packetized is not on
+ // the queue. For multiple-request messages, the
+ // first one is not on the queue, but its linkage
+ // field points to the next request in the message
+ // (which will be on the head of the queue).
+ //
+
+ if ((Parameters->SendFlags & TDI_SEND_PARTIAL) == 0) {
+
+ //
+ // This is a final send.
+ //
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_IDLE) {
+
+ NB_DEBUG2 (SEND, ("Send %lx, connection %lx idle\n", Request, Connection));
+
+ Connection->CurrentSend.Request = Request;
+ Connection->CurrentSend.MessageOffset = 0;
+ Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentSend.BufferOffset = 0;
+ Connection->SendBufferInUse = FALSE;
+
+ Connection->UnAckedSend = Connection->CurrentSend;
+
+ Connection->FirstMessageRequest = Request;
+#ifdef RSRC_TIMEOUT_DBG
+ KeQuerySystemTime(&Connection->FirstMessageRequestTime);
+
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Connection->FirstMessageRequestTime.QuadPart;
+#endif //RSRC_TIMEOUT_DBG
+
+ Connection->LastMessageRequest = Request;
+ Connection->CurrentMessageLength = Parameters->SendLength;
+
+ //
+ // This frees the connection lock.
+ //
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle)
+ );
+
+ } else if (Connection->SubState == CONNECTION_SUBSTATE_A_W_EOR) {
+
+ //
+ // We have been collecting partial sends waiting
+ // for a final one, which we have now received,
+ // so start packetizing.
+ //
+ // We chain it on the back of the send queue,
+ // in addition if this is the second request in the
+ // message, we have to link the first request (which
+ // is not on the queue) to this one.
+ //
+ //
+
+ NB_DEBUG2 (SEND, ("Send %lx, connection %lx got eor\n", Request, Connection));
+
+ Connection->LastMessageRequest = Request;
+ Connection->CurrentMessageLength += Parameters->SendLength;
+
+ if (Connection->SendQueue.Head == NULL) {
+ REQUEST_SINGLE_LINKAGE(Connection->FirstMessageRequest) = Request;
+ }
+ REQUEST_SINGLE_LINKAGE(Request) = NULL;
+ REQUEST_LIST_INSERT_TAIL(&Connection->SendQueue, Request);
+
+ Connection->UnAckedSend = Connection->CurrentSend;
+#ifdef RSRC_TIMEOUT_DBG
+ {
+ LARGE_INTEGER Time;
+
+ KeQuerySystemTime(&Time);
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Time.QuadPart;
+ }
+#endif //RSRC_TIMEOUT_DBG
+ //
+ // This frees the connection lock.
+ //
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle)
+ );
+
+ } else {
+
+ //
+ // The state is PACKETIZE, W_ACK, or W_PACKET.
+ //
+
+ NB_DEBUG2 (SEND, ("Send %lx, connection %lx busy\n", Request, Connection));
+
+ REQUEST_SINGLE_LINKAGE(Request) = NULL;
+ REQUEST_LIST_INSERT_TAIL(&Connection->SendQueue, Request);
+
+#ifdef RSRC_TIMEOUT_DBG
+ {
+ LARGE_INTEGER Time;
+ KeQuerySystemTime(&Time);
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Time.QuadPart;
+ }
+#endif //RSRC_TIMEOUT_DBG
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ //
+ // This is a partial send. We queue them up without
+ // packetizing until we get a final (this is because
+ // we have to put a correct Connection->CurrentMessageLength
+ // in the frames.
+ //
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_IDLE) {
+
+ //
+ // Start collecting partial sends. NOTE: Partial sends
+ // are always inserted in the send queue
+ //
+
+ Connection->CurrentSend.Request = Request;
+ Connection->CurrentSend.MessageOffset = 0;
+ Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentSend.BufferOffset = 0;
+ Connection->SendBufferInUse = FALSE;
+
+ Connection->FirstMessageRequest = Request;
+#ifdef RSRC_TIMEOUT_DBG
+ KeQuerySystemTime(&Connection->FirstMessageRequestTime);
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Connection->FirstMessageRequestTime.QuadPart;
+#endif //RSRC_TIMEOUT_DBG
+
+ Connection->CurrentMessageLength = Parameters->SendLength;
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_EOR;
+
+ } else if (Connection->SubState == CONNECTION_SUBSTATE_A_W_EOR) {
+
+ //
+ // We have got another partial send to add to our
+ // list. We chain it on the back of the send queue,
+ // in addition if this is the second request in the
+ // message, we have to link the first request (which
+ // is not on the queue) to this one.
+ //
+
+ Connection->LastMessageRequest = Request;
+ Connection->CurrentMessageLength += Parameters->SendLength;
+
+ if (Connection->SendQueue.Head == NULL) {
+ REQUEST_SINGLE_LINKAGE(Connection->FirstMessageRequest) = Request;
+ }
+ REQUEST_SINGLE_LINKAGE(Request) = NULL;
+ REQUEST_LIST_INSERT_TAIL(&Connection->SendQueue, Request);
+#ifdef RSRC_TIMEOUT_DBG
+ {
+ LARGE_INTEGER Time;
+ KeQuerySystemTime(&Time);
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Time.QuadPart;
+ }
+#endif //RSRC_TIMEOUT_DBG
+ } else {
+
+ REQUEST_SINGLE_LINKAGE(Request) = NULL;
+ REQUEST_LIST_INSERT_TAIL(&Connection->SendQueue, Request);
+
+#ifdef RSRC_TIMEOUT_DBG
+ {
+ LARGE_INTEGER Time;
+ KeQuerySystemTime(&Time);
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Time.QuadPart;
+ }
+#endif //RSRC_TIMEOUT_DBG
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ NB_END_SYNC (&SyncContext);
+ return STATUS_PENDING;
+
+ } else {
+
+ NB_DEBUG2 (SEND, ("Send %lx, too long for connection %lx (%d)\n", Request, Connection, Parameters->SendLength));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_END_SYNC (&SyncContext);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ return STATUS_INVALID_PARAMETER;
+
+ }
+
+ } else {
+
+ NB_DEBUG2 (SEND, ("Send %lx, connection %lx cancelled\n", Request, Connection));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_END_SYNC (&SyncContext);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ return STATUS_CANCELLED;
+
+ }
+
+ } else {
+
+ NB_DEBUG (SEND, ("Send connection %lx state is %d\n", Connection, Connection->State));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_END_SYNC (&SyncContext);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ return STATUS_INVALID_CONNECTION;
+
+ }
+
+ } else {
+
+ NB_DEBUG (SEND, ("Send connection %lx has bad signature\n", Connection));
+ return STATUS_INVALID_CONNECTION;
+
+ }
+
+} /* NbiTdiSend */
+
+
+VOID
+NbiPacketizeSend(
+ IN PCONNECTION Connection
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does a send on an active connection.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection.
+
+ LockHandle - The handle used to acquire the lock.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST Request;
+ PNDIS_PACKET Packet;
+ PNDIS_BUFFER BufferChain;
+ PNB_SEND_RESERVED Reserved;
+ PDEVICE Device = NbiDevice;
+ NB_CONNECTION UNALIGNED * Header;
+ ULONG PacketLength;
+ ULONG PacketSize;
+ ULONG DesiredLength;
+ ULONG ActualLength;
+ NTSTATUS Status;
+ PSINGLE_LIST_ENTRY s;
+ USHORT ThisSendSequence;
+ USHORT ThisOffset;
+ BOOLEAN ExitAfterSend;
+ UCHAR ConnectionControlFlag;
+ CTELockHandle DeviceLockHandle;
+
+ //
+ // We jump back here if we are talking new Netbios and it
+ // is OK to packetize another send.
+ //
+
+SendAnotherPacket:
+
+ //
+ // If we decide to packetize another send after this, we
+ // change ExitAfterSend to FALSE and SubState to PACKETIZE.
+ // Right now we don't change SubState in case it is W_PACKET.
+ //
+
+ ExitAfterSend = TRUE;
+
+ CTEAssert (Connection->CurrentSend.Request != NULL);
+
+ if (Connection->NewNetbios) {
+
+ //
+ // Check that we have send window, both that advertised
+ // by the remote and our own locally-decided window which
+ // may be smaller.
+ //
+
+ if (((USHORT)(Connection->CurrentSend.SendSequence-1) == Connection->RemoteRcvSequenceMax) ||
+ (((USHORT)(Connection->CurrentSend.SendSequence - Connection->UnAckedSend.SendSequence)) >= Connection->SendWindowSize)) {
+
+ //
+ // Keep track of whether we are waiting because of his window
+ // or because of our local window. If it is because of our local
+ // window then we may want to adjust it after this window
+ // is acked.
+ //
+
+ if ((USHORT)(Connection->CurrentSend.SendSequence-1) != Connection->RemoteRcvSequenceMax) {
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_ACK;
+ NB_DEBUG2 (SEND, ("Connection %lx local shut down at %lx, %lx\n", Connection, Connection->CurrentSend.SendSequence, Connection->UnAckedSend.SendSequence));
+ } else {
+ Connection->SubState = CONNECTION_SUBSTATE_A_REMOTE_W;
+ NB_DEBUG2 (SEND, ("Connection %lx remote shut down at %lx\n", Connection, Connection->CurrentSend.SendSequence));
+ }
+
+ //
+ // Start the timer so we will keep bugging him about
+ // this. BUGBUG: What if he doesn't get a receive down
+ // quickly -- but this is better than losing his ack
+ // and then dying. We won't really back off our timer
+ // because we will keep getting acks, and resetting it.
+ //
+
+ NbiStartRetransmit (Connection);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+
+ }
+
+ }
+
+ Request = Connection->CurrentSend.Request;
+
+ //
+ // If we are in this routine then we know that
+ // we are coming out of IDLE, W_ACK, or W_PACKET
+ // and we still have the lock held. We also know
+ // that there is a send request in progress. If
+ // an ack for none or part of the last packet was
+ // received, then our send pointers have been
+ // adjusted to reflect that.
+ //
+
+ //
+ // First get a packet for the current send.
+ //
+
+ if (!Connection->SendPacketInUse) {
+
+ Connection->SendPacketInUse = TRUE;
+ Packet = PACKET(&Connection->SendPacket);
+ Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
+
+ } else {
+
+ s = ExInterlockedPopEntrySList(
+ &Device->SendPacketList,
+ &NbiGlobalPoolInterlock);
+
+ if (s == NULL) {
+
+ //
+ // This function tries to allocate another packet pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ if (s == NULL) {
+
+ //
+ // It is possible to come in here and already be in
+ // W_PACKET state -- this is because we may packetize
+ // when in that state, and rather than always be
+ // checking that we weren't in W_PACKET, we go
+ // ahead and check again here.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_W_PACKET) {
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_PACKET;
+
+ NB_GET_LOCK (&Device->Lock, &DeviceLockHandle);
+ if (!Connection->OnWaitPacketQueue) {
+
+ NbiReferenceConnectionLock (Connection, CREF_W_PACKET);
+
+ Connection->OnWaitPacketQueue = TRUE;
+
+ InsertTailList(
+ &Device->WaitPacketConnections,
+ &Connection->WaitPacketLinkage
+ );
+
+// NB_INSERT_TAIL_LIST(
+// &Device->WaitPacketConnections,
+// &Connection->WaitPacketLinkage,
+// &Device->Lock);
+
+ }
+ NB_FREE_LOCK (&Device->Lock, DeviceLockHandle);
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+ }
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ }
+
+ //
+ // Set this now, we will change it later if needed.
+ //
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_ACK;
+
+
+ //
+ // Save these since they go in this next packet.
+ //
+
+ ThisSendSequence = Connection->CurrentSend.SendSequence;
+ ThisOffset = (USHORT)Connection->CurrentSend.MessageOffset;
+
+
+ //
+ // Now see if we need to copy the buffer chain.
+ //
+
+ PacketSize = Connection->MaximumPacketSize;
+
+ if (Connection->CurrentSend.MessageOffset + PacketSize >= Connection->CurrentMessageLength) {
+
+ PacketSize = Connection->CurrentMessageLength - Connection->CurrentSend.MessageOffset;
+
+ if ((Connection->CurrentSend.MessageOffset == 0) &&
+ (!Connection->SendBufferInUse)) {
+
+ //
+ // If the entire send remaining fits in one packet,
+ // and this is also the first packet in the send,
+ // then the entire send fits in one packet and
+ // we don't need to build a duplicate buffer chain.
+ //
+
+ BufferChain = Connection->CurrentSend.Buffer;
+ Reserved->u.SR_CO.NoNdisBuffer = TRUE;
+ Connection->CurrentSend.Buffer = NULL;
+ Connection->CurrentSend.BufferOffset = 0;
+ Connection->CurrentSend.MessageOffset = Connection->CurrentMessageLength;
+ Connection->CurrentSend.Request = NULL;
+ ++Connection->CurrentSend.SendSequence;
+ Connection->SendBufferInUse = TRUE;
+ if (Connection->NewNetbios) {
+ if ((ThisSendSequence == Connection->RemoteRcvSequenceMax) ||
+ ((((PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request))->SendFlags) &
+ TDI_SEND_NO_RESPONSE_EXPECTED)) { // BUGBUG: optimize this check
+ ConnectionControlFlag = NB_CONTROL_EOM | NB_CONTROL_SEND_ACK;
+ } else {
+ ConnectionControlFlag = NB_CONTROL_EOM;
+ }
+ Connection->PiggybackAckTimeout = FALSE;
+ } else {
+ ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+ }
+
+ if (BufferChain != NULL) {
+ NB_DEBUG2 (SEND, ("Send packet %lx on %lx (%d/%d), user buffer\n",
+ Reserved, Connection,
+ Connection->CurrentSend.SendSequence,
+ Connection->CurrentSend.MessageOffset));
+ NdisChainBufferAtBack (Packet, BufferChain);
+ } else {
+ NB_DEBUG2 (SEND, ("Send packet %lx on %lx (%d/%d), no buffer\n",
+ Reserved, Connection,
+ Connection->CurrentSend.SendSequence,
+ Connection->CurrentSend.MessageOffset));
+ }
+
+ goto GotBufferChain;
+
+ }
+
+ }
+
+ //
+ // We need to build a partial buffer chain. In the case
+ // where the current request is a partial one, we may
+ // build this from the ndis buffer chains of several
+ // requests.
+ //
+
+ if (PacketSize > 0) {
+
+ DesiredLength = PacketSize;
+
+ NB_DEBUG2 (SEND, ("Send packet %lx on %lx (%d/%d), allocate buffer\n",
+ Reserved, Connection,
+ Connection->CurrentSend.SendSequence,
+ Connection->CurrentSend.MessageOffset));
+
+ while (TRUE) {
+
+ Status = NbiBuildBufferChainFromBufferChain (
+ Device->NdisBufferPoolHandle,
+ Connection->CurrentSend.Buffer,
+ Connection->CurrentSend.BufferOffset,
+ DesiredLength,
+ &BufferChain,
+ &Connection->CurrentSend.Buffer,
+ &Connection->CurrentSend.BufferOffset,
+ &ActualLength);
+
+ if (Status != STATUS_SUCCESS) {
+
+ PNDIS_BUFFER CurBuffer, TmpBuffer;
+
+ NB_DEBUG2 (SEND, ("Allocate buffer chain failed for packet %lx\n", Reserved));
+
+ //
+ // We could not allocate resources for this send.
+ // We'll put the connection on the packetize
+ // queue and hope we get more resources later.
+ //
+
+ NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
+
+ CTEAssert (!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ //
+ // Connection->CurrentSend can stay where it is.
+ //
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ //
+ // Free any buffers we have allocated on previous calls
+ // to BuildBufferChain inside this same while(TRUE) loop,
+ // then free the packet.
+ //
+
+ CurBuffer = NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer));
+ while (CurBuffer) {
+ TmpBuffer = NDIS_BUFFER_LINKAGE (CurBuffer);
+ NdisFreeBuffer (CurBuffer);
+ CurBuffer = TmpBuffer;
+ }
+
+ NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = NULL;
+ NdisRecalculatePacketCounts (Packet);
+
+ if (Reserved->OwnedByConnection) {
+ Connection->SendPacketInUse = FALSE;
+ } else {
+ NbiPushSendPacket(Reserved);
+ }
+
+ return;
+
+ }
+
+ NdisChainBufferAtBack (Packet, BufferChain);
+ Connection->CurrentSend.MessageOffset += ActualLength;
+
+ DesiredLength -= ActualLength;
+
+ if (DesiredLength == 0) {
+
+ //
+ // We have gotten enough data for our packet.
+ //
+
+ if (Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength) {
+ Connection->CurrentSend.Request = NULL;
+ }
+ break;
+ }
+
+ //
+ // We ran out of buffer chain on this send, which means
+ // that we must have another one behind it (since we
+ // don't start packetizing partial sends until all of
+ // them are queued).
+ //
+
+ Request = REQUEST_SINGLE_LINKAGE(Request);
+ if (Request == NULL) {
+ KeBugCheck (NDIS_INTERNAL_ERROR);
+ }
+
+ Connection->CurrentSend.Request = Request;
+ Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentSend.BufferOffset = 0;
+
+ }
+
+ } else {
+
+ //
+ // This is a zero-length send (in general we will go
+ // through the code before the if that uses the user's
+ // buffer, but not on a resend).
+ //
+
+ Connection->CurrentSend.Buffer = NULL;
+ Connection->CurrentSend.BufferOffset = 0;
+ CTEAssert (Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength);
+ Connection->CurrentSend.Request = NULL;
+
+ NB_DEBUG2 (SEND, ("Send packet %lx on %lx (%d/%d), no alloc buf\n",
+ Reserved, Connection,
+ Connection->CurrentSend.SendSequence,
+ Connection->CurrentSend.MessageOffset));
+
+ }
+
+ Reserved->u.SR_CO.NoNdisBuffer = FALSE;
+
+ if (Connection->NewNetbios) {
+
+ ++Connection->CurrentSend.SendSequence;
+ if (Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength) {
+
+ if (((USHORT)(Connection->CurrentSend.SendSequence - Connection->UnAckedSend.SendSequence)) >= Connection->SendWindowSize) {
+
+ ConnectionControlFlag = NB_CONTROL_EOM | NB_CONTROL_SEND_ACK;
+
+ } else if ((ThisSendSequence == Connection->RemoteRcvSequenceMax) ||
+ ((((PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request))->SendFlags) &
+ TDI_SEND_NO_RESPONSE_EXPECTED)) { // BUGBUG: optimize this check
+
+ ConnectionControlFlag = NB_CONTROL_EOM | NB_CONTROL_SEND_ACK;
+
+ } else {
+
+ ConnectionControlFlag = NB_CONTROL_EOM;
+ }
+ Connection->PiggybackAckTimeout = FALSE;
+
+ } else if (((USHORT)(Connection->CurrentSend.SendSequence - Connection->UnAckedSend.SendSequence)) >= Connection->SendWindowSize) {
+
+ ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+
+ } else if (ThisSendSequence == Connection->RemoteRcvSequenceMax) {
+
+ ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+
+ } else {
+
+ ConnectionControlFlag = 0;
+ ExitAfterSend = FALSE;
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ }
+
+ } else {
+
+ ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+ if (Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength) {
+ ++Connection->CurrentSend.SendSequence;
+ }
+ }
+
+GotBufferChain:
+
+ //
+ // We have a packet and a buffer chain, there are
+ // no other resources required for a send so we can
+ // fill in the header and go.
+ //
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_DATA;
+ Reserved->u.SR_CO.Connection = Connection;
+ Reserved->u.SR_CO.Request = Connection->FirstMessageRequest;
+
+ PacketLength = PacketSize + sizeof(NB_CONNECTION);
+ Reserved->u.SR_CO.PacketLength = PacketLength;
+
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = (UCHAR)(PacketLength / 256);
+ Header->IpxHeader.PacketLength[1] = (UCHAR)(PacketLength % 256);
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header. BUGBUG: Put this in
+ // a contiguous buffer in the connection.
+ //
+
+ Header->Session.ConnectionControlFlag = ConnectionControlFlag;
+ Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = Connection->RemoteConnectionId;
+ Header->Session.SendSequence = ThisSendSequence;
+ Header->Session.TotalDataLength = (USHORT)Connection->CurrentMessageLength;
+ Header->Session.Offset = ThisOffset;
+ Header->Session.DataLength = (USHORT)PacketSize;
+
+#if 0
+ //
+ // These are set by NbiAssignSequenceAndSend.
+ //
+
+ Header->Session.ReceiveSequence = Connection->ReceiveSequence;
+ Header->Session.BytesReceived = (USHORT)Connection->CurrentReceive.MessageOffset;
+#endif
+
+ //
+ // Reference the request to account for this send.
+ //
+
+#if DBG
+ if (REQUEST_REFCOUNT(Request) > 100) {
+ DbgPrint ("Request %lx (%lx) has high refcount\n",
+ Connection, Request);
+ DbgBreakPoint();
+ }
+#endif
+ ++REQUEST_REFCOUNT (Request);
+
+ ++Device->TempFramesSent;
+ Device->TempFrameBytesSent += PacketSize;
+
+ //
+ // Start the timer.
+ //
+
+ NbiStartRetransmit (Connection);
+
+ //
+ // This frees the lock. IPX will adjust the length of
+ // the first buffer correctly.
+ //
+
+ NbiAssignSequenceAndSend(
+ Connection,
+ Packet
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ if (!ExitAfterSend) {
+
+ //
+ // BUGBUG: Did we need to reference the connection until we
+ // get the lock back??
+ //
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+ if ((Connection->State == CONNECTION_STATE_ACTIVE) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_A_PACKETIZE)) {
+
+ //
+ // Jump back to the beginning of the function to
+ // repacketize.
+
+ goto SendAnotherPacket;
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ }
+
+} /* NbiPacketizeSend */
+
+
+VOID
+NbiAdjustSendWindow(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adjusts a connection's send window if needed. It is
+ assumed that we just got an ack for a full send window.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Connection - The connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ if (Connection->RetransmitThisWindow) {
+
+ //
+ // Move it down. Check if this keeps happening.
+ //
+
+ if (Connection->SendWindowSize > 2) {
+ --Connection->SendWindowSize;
+ NB_DEBUG2 (SEND_WINDOW, ("Lower window to %d on %lx (%lx)\n", Connection->SendWindowSize, Connection, Connection->CurrentSend.SendSequence));
+ }
+
+ if (Connection->SendWindowIncrease) {
+
+ //
+ // We just increased the window.
+ //
+
+ ++Connection->IncreaseWindowFailures;
+ NB_DEBUG2 (SEND_WINDOW, ("%d consecutive increase failues on %lx (%lx)\n", Connection->IncreaseWindowFailures, Connection, Connection->CurrentSend.SendSequence));
+
+ if (Connection->IncreaseWindowFailures >= 2) {
+
+ if (Connection->MaxSendWindowSize > 2) {
+
+ //
+ // Lock ourselves at a smaller window.
+ //
+
+ Connection->MaxSendWindowSize = Connection->SendWindowSize;
+ NB_DEBUG2 (SEND_WINDOW, ("Lock send window at %d on %lx (%lx)\n", Connection->MaxSendWindowSize, Connection, Connection->CurrentSend.SendSequence));
+ }
+
+ Connection->IncreaseWindowFailures = 0;
+ }
+
+ Connection->SendWindowIncrease = FALSE;
+ }
+
+ } else {
+
+ //
+ // Increase it if allowed, and make a note
+ // in case this increase causes problems in
+ // the next window.
+ //
+
+ if (Connection->SendWindowSize < Connection->MaxSendWindowSize) {
+
+ ++Connection->SendWindowSize;
+ NB_DEBUG2 (SEND_WINDOW, ("Raise window to %d on %lx (%lx)\n", Connection->SendWindowSize, Connection, Connection->CurrentSend.SendSequence));
+ Connection->SendWindowIncrease = TRUE;
+
+ } else {
+
+ if (Connection->SendWindowIncrease) {
+
+ //
+ // We just increased it and nothing failed,
+ // which is good.
+ //
+
+ Connection->SendWindowIncrease = FALSE;
+ Connection->IncreaseWindowFailures = 0;
+ NB_DEBUG2 (SEND_WINDOW, ("Raised window OK on %lx (%lx)\n", Connection, Connection->CurrentSend.SendSequence));
+ }
+ }
+ }
+
+
+ //
+ // This controls when we'll check this again.
+ //
+
+ Connection->SendWindowSequenceLimit += Connection->SendWindowSize;
+
+} /* NbiAdjustSendWindow */
+
+
+VOID
+NbiReframeConnection(
+ IN PCONNECTION Connection,
+ IN USHORT ReceiveSequence,
+ IN USHORT BytesReceived,
+ IN BOOLEAN Resend
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when we have gotten an ack
+ for some data. It completes any sends that have
+ been acked, and if needed modifies the current send
+ pointer and queues the connection for repacketizing.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection.
+
+ ReceiveSequence - The receive sequence from the remote.
+
+ BytesReceived - The number of bytes received in this message.
+
+ Resend - If it is OK to resend based on this packet.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST Request, TmpRequest;
+ PREQUEST RequestToComplete;
+ PDEVICE Device = NbiDevice;
+ CTELockHandle CancelLH;
+
+
+ //
+ // BUGBUG: We should change to stop the timer
+ // only if we go idle, since otherwise we still
+ // want it running, or will restart it when we
+ // packetize.
+ //
+
+ //
+ // See how much is acked here.
+ //
+
+ if ((Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength) &&
+ (ReceiveSequence == (USHORT)(Connection->CurrentSend.SendSequence)) &&
+ (Connection->FirstMessageRequest != NULL)) {
+
+ // Special check for 0 length send which was not accepted by the remote.
+ // In this case it will pass the above 3 conditions yet, nothing
+ // is acked. BUG#10395
+ if (!Connection->CurrentSend.MessageOffset && Connection->CurrentSend.SendSequence == Connection->UnAckedSend.SendSequence ) {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+ }
+
+ //
+ // This acks the entire message.
+ //
+
+ NB_DEBUG2 (SEND, ("Got ack for entire message on %lx (%d)\n", Connection, Connection->CurrentSend.SendSequence));
+
+ NbiStopRetransmit (Connection);
+
+ Connection->CurrentSend.MessageOffset = 0; // BUGBUG: Needed?
+ Connection->UnAckedSend.MessageOffset = 0;
+
+ //
+ // We don't adjust the send window since we likely stopped
+ // packetizing before we hit it.
+ //
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+
+
+ if (Connection->NewNetbios) {
+
+ Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
+
+ //
+ // See if we need to adjust our send window.
+ //
+
+ if (((SHORT)(Connection->CurrentSend.SendSequence - Connection->SendWindowSequenceLimit)) >= 0) {
+
+ NbiAdjustSendWindow (Connection);
+
+ } else {
+
+ //
+ // Advance this, we won't get meaningful results until we
+ // send a full window in one message.
+ //
+
+ Connection->SendWindowSequenceLimit = Connection->CurrentSend.SendSequence + Connection->SendWindowSize;
+ }
+
+
+ }
+
+ Connection->RetransmitThisWindow = FALSE;
+
+ Request = Connection->FirstMessageRequest;
+
+ //
+ // We dequeue these requests from the connection's
+ // send queue.
+ //
+
+ if (Connection->FirstMessageRequest == Connection->LastMessageRequest) {
+
+ REQUEST_SINGLE_LINKAGE (Request) = NULL;
+
+ } else {
+
+ Connection->SendQueue.Head = REQUEST_SINGLE_LINKAGE (Connection->LastMessageRequest);
+ REQUEST_SINGLE_LINKAGE (Connection->LastMessageRequest) = NULL;
+
+ }
+
+#if DBG
+ if (REQUEST_REFCOUNT(Request) > 100) {
+ DbgPrint ("Request %lx (%lx) has high refcount\n",
+ Connection, Request);
+ DbgBreakPoint();
+ }
+#endif
+ if (--REQUEST_REFCOUNT(Request) == 0) {
+
+ RequestToComplete = Request;
+
+ } else {
+
+ //
+ // There are still sends pending, this will get
+ // completed when the last send completes. Since
+ // we have already unlinked the request from the
+ // connection's send queue we can do this without
+ // any locks.
+ //
+
+ RequestToComplete = NULL;
+
+ }
+
+ //
+ // Now see if there is a send to activate.
+ //
+
+ NbiRestartConnection (Connection);
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ //
+ // Now complete any requests we need to.
+ //
+
+ while (RequestToComplete != NULL) {
+
+ TmpRequest = REQUEST_SINGLE_LINKAGE (RequestToComplete);
+ REQUEST_STATUS (RequestToComplete) = STATUS_SUCCESS;
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (RequestToComplete, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ NbiCompleteRequest (RequestToComplete);
+ NbiFreeRequest (Device, RequestToComplete);
+ ++Connection->ConnectionInfo.TransmittedTsdus;
+ RequestToComplete = TmpRequest;
+
+ NbiDereferenceConnection (Connection, CREF_SEND);
+
+ }
+
+ } else if ((ReceiveSequence == Connection->CurrentSend.SendSequence) &&
+ (Connection->NewNetbios || (BytesReceived == Connection->CurrentSend.MessageOffset)) &&
+ (Connection->CurrentSend.Request != NULL)) {
+
+ //
+ // This acks whatever we sent last time, and we are
+ // not done packetizing this send, so we can repacketize.
+ // BUGBUG: With SendSequence changing as it does now,
+ // don't need the CurrentSend.Request check???
+ //
+
+ NB_DEBUG2 (SEND, ("Got full ack on %lx (%d)\n", Connection, Connection->CurrentSend.SendSequence));
+
+ NbiStopRetransmit (Connection);
+
+ if (Connection->NewNetbios) {
+
+ //
+ // If we are waiting for a window, and this does not open it
+ // anymore, then we don't reset our timers/retries.
+ //
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_REMOTE_W) {
+
+ if (Connection->RemoteRcvSequenceMax != BytesReceived) {
+ Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+
+ }
+
+ //
+ // Advance this, we won't get meaningful results until we
+ // send a full window in one message.
+ //
+
+ Connection->SendWindowSequenceLimit = Connection->CurrentSend.SendSequence + Connection->SendWindowSize;
+
+ } else {
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+ Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
+
+ if (((SHORT)(Connection->CurrentSend.SendSequence - Connection->SendWindowSequenceLimit)) >= 0) {
+
+ NbiAdjustSendWindow (Connection);
+
+ } else {
+
+ //
+ // Advance this, we won't get meaningful results until we
+ // send a full window in one message.
+ //
+
+ Connection->SendWindowSequenceLimit = Connection->CurrentSend.SendSequence + Connection->SendWindowSize;
+ }
+
+ }
+
+ } else {
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+ }
+
+ Connection->RetransmitThisWindow = FALSE;
+
+ Connection->UnAckedSend = Connection->CurrentSend;
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_PACKETIZE) {
+
+ //
+ // We may be on if this ack is duplicated.
+ //
+
+ NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
+
+ CTEAssert(!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ } else if( Connection->FirstMessageRequest ) {
+
+ //
+ // This acked part of the current send. If the
+ // remote is requesting a resend then we advance
+ // the current send location by the amount
+ // acked and resend from there. If he does
+ // not want a resend, just ignore this.
+ //
+ // We repacketize immediately because we have
+ // backed up the pointer, and this would
+ // cause us to ignore an ack for the amount
+ // sent. Since we don't release the lock
+ // until we have packetized, the current
+ // pointer will be advanced past there.
+ //
+ // BUGBUG: If he is acking more than we sent, we
+ // ignore this -- the remote is confused and there
+ // is nothing much we can do.
+ //
+
+ if (Resend) {
+
+ if (Connection->NewNetbios &&
+ (((Connection->UnAckedSend.SendSequence < Connection->CurrentSend.SendSequence) &&
+ (ReceiveSequence >= Connection->UnAckedSend.SendSequence) &&
+ (ReceiveSequence < Connection->CurrentSend.SendSequence)) ||
+ ((Connection->UnAckedSend.SendSequence > Connection->CurrentSend.SendSequence) &&
+ ((ReceiveSequence >= Connection->UnAckedSend.SendSequence) ||
+ (ReceiveSequence < Connection->CurrentSend.SendSequence))))) {
+
+ BOOLEAN SomethingAcked = (BOOLEAN)
+ (ReceiveSequence != Connection->UnAckedSend.SendSequence);
+
+ //
+ // New netbios and the receive sequence is valid.
+ //
+
+ NbiStopRetransmit (Connection);
+
+ //
+ // Advance our unacked pointer by the amount
+ // acked in this response.
+ //
+
+ NbiAdvanceUnAckedBySequence(
+ Connection,
+ ReceiveSequence);
+
+ Connection->RetransmitThisWindow = TRUE;
+
+ ++Connection->ConnectionInfo.TransmissionErrors;
+ ++Device->Statistics.DataFramesResent;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesResent,
+ Connection->CurrentSend.MessageOffset - Connection->UnAckedSend.MessageOffset);
+
+ //
+ // Packetize from that point on.
+ //
+
+ Connection->CurrentSend = Connection->UnAckedSend;
+
+ //
+ // If anything was acked, then reset the retry count.
+ //
+
+ if (SomethingAcked) {
+
+ //
+ // See if we need to adjust our send window.
+ //
+
+ if (((SHORT)(Connection->UnAckedSend.SendSequence - Connection->SendWindowSequenceLimit)) >= 0) {
+
+ NbiAdjustSendWindow (Connection);
+
+ }
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+
+ }
+
+ Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
+
+ //
+ // Now packetize. This will set the state to
+ // something meaningful and release the lock.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_PACKETIZE) {
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle)
+ );
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else if (!Connection->NewNetbios &&
+ ((ReceiveSequence == Connection->UnAckedSend.SendSequence) &&
+ (BytesReceived <= Connection->CurrentSend.MessageOffset))) {
+
+ ULONG BytesAcked =
+ BytesReceived - Connection->UnAckedSend.MessageOffset;
+
+ //
+ // Old netbios.
+ //
+
+ NbiStopRetransmit (Connection);
+
+ //
+ // Advance our unacked pointer by the amount
+ // acked in this response.
+ //
+
+ NbiAdvanceUnAckedByBytes(
+ Connection,
+ BytesAcked);
+
+ ++Connection->ConnectionInfo.TransmissionErrors;
+ ++Device->Statistics.DataFramesResent;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesResent,
+ Connection->CurrentSend.MessageOffset - Connection->UnAckedSend.MessageOffset);
+
+ //
+ // Packetize from that point on.
+ //
+
+ Connection->CurrentSend = Connection->UnAckedSend;
+
+ //
+ // If anything was acked, reset the retry count
+ //
+ if ( BytesAcked ) {
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+ }
+
+ //
+ // Now packetize. This will set the state to
+ // something meaningful and release the lock.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_PACKETIZE) {
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle)
+ );
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ if (Connection->NewNetbios &&
+ (((Connection->UnAckedSend.SendSequence < Connection->CurrentSend.SendSequence) &&
+ (ReceiveSequence >= Connection->UnAckedSend.SendSequence) &&
+ (ReceiveSequence < Connection->CurrentSend.SendSequence)) ||
+ ((Connection->UnAckedSend.SendSequence > Connection->CurrentSend.SendSequence) &&
+ ((ReceiveSequence >= Connection->UnAckedSend.SendSequence) ||
+ (ReceiveSequence < Connection->CurrentSend.SendSequence))))) {
+
+ BOOLEAN SomethingAcked = (BOOLEAN)
+ (ReceiveSequence != Connection->UnAckedSend.SendSequence);
+
+ //
+ // New netbios and the receive sequence is valid. We advance
+ // the back of our send window, but we don't repacketize.
+ //
+
+ //
+ // Advance our unacked pointer by the amount
+ // acked in this response.
+ //
+
+ NbiAdvanceUnAckedBySequence(
+ Connection,
+ ReceiveSequence);
+
+ Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
+
+ //
+ // If anything was acked, then reset the retry count.
+ //
+
+ if (SomethingAcked) {
+
+ //
+ // See if we need to adjust our send window.
+ //
+
+ if (((SHORT)(Connection->UnAckedSend.SendSequence - Connection->SendWindowSequenceLimit)) >= 0) {
+
+ NbiAdjustSendWindow (Connection);
+
+ }
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+
+
+ //
+ // Now packetize. This will set the state to
+ // something meaningful and release the lock.
+ //
+
+ if ((Connection->CurrentSend.Request != NULL) &&
+ (Connection->SubState != CONNECTION_SUBSTATE_A_PACKETIZE)) {
+
+ NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
+
+ CTEAssert(!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ }
+ }
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+} /* NbiReframeConnection */
+
+
+VOID
+NbiRestartConnection(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when have gotten an ack for
+ a full message, or received a response to a watchdog
+ probe, and need to check if the connection should
+ start packetizing.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Connection - The connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST Request, TmpRequest;
+ ULONG TempCount;
+ PTDI_REQUEST_KERNEL_SEND Parameters;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // See if there is a send to activate.
+ //
+
+ if (Connection->SendQueue.Head != NULL) {
+
+ //
+ // Take the first send off the queue and make
+ // it current.
+ //
+
+ Request = Connection->SendQueue.Head;
+ Connection->SendQueue.Head = REQUEST_SINGLE_LINKAGE (Request);
+
+ //
+ // BUGBUG: Cache the information about being EOM
+ // in a more easily accessible location?
+ //
+
+ Parameters = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request);
+ if ((Parameters->SendFlags & TDI_SEND_PARTIAL) == 0) {
+
+ //
+ // This is a one-request message.
+ //
+
+ Connection->CurrentSend.Request = Request;
+ Connection->CurrentSend.MessageOffset = 0;
+ Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentSend.BufferOffset = 0;
+ Connection->SendBufferInUse = FALSE;
+
+ Connection->UnAckedSend = Connection->CurrentSend;
+
+ Connection->FirstMessageRequest = Request;
+#ifdef RSRC_TIMEOUT_DBG
+ KeQuerySystemTime(&Connection->FirstMessageRequestTime);
+#endif //RSRC_TIMEOUT_DBG
+
+ Connection->LastMessageRequest = Request;
+ Connection->CurrentMessageLength = Parameters->SendLength;
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
+
+ CTEAssert (!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ } else {
+
+ //
+ // This is a multiple-request message. We scan
+ // to see if we have the end of message received
+ // yet.
+ //
+
+ TempCount = Parameters->SendLength;
+ TmpRequest = Request;
+ Request = REQUEST_SINGLE_LINKAGE(Request);
+
+ while (Request != NULL) {
+
+ TempCount += Parameters->SendLength;
+
+ Parameters = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request);
+ if ((Parameters->SendFlags & TDI_SEND_PARTIAL) == 0) {
+
+ Connection->CurrentSend.Request = TmpRequest;
+ Connection->CurrentSend.MessageOffset = 0;
+ Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (TmpRequest);
+ Connection->CurrentSend.BufferOffset = 0;
+ Connection->SendBufferInUse = FALSE;
+
+ Connection->UnAckedSend = Connection->CurrentSend;
+
+ Connection->FirstMessageRequest = TmpRequest;
+ Connection->LastMessageRequest = Request;
+#ifdef RSRC_TIMEOUT_DBG
+ KeQuerySystemTime(&Connection->FirstMessageRequestTime);
+#endif //RSRC_TIMEOUT_DBG
+
+ Connection->CurrentMessageLength = TempCount;
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
+
+ CTEAssert (!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ break;
+
+ }
+
+ Request = REQUEST_SINGLE_LINKAGE(Request);
+
+ }
+
+ if (Request == NULL) {
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_EOR;
+
+ }
+
+ }
+
+ } else {
+
+ Connection->FirstMessageRequest = NULL;
+ Connection->SubState = CONNECTION_SUBSTATE_A_IDLE;
+
+ NbiStartWatchdog (Connection);
+
+ }
+
+} /* NbiRestartConnection */
+
+
+VOID
+NbiAdvanceUnAckedByBytes(
+ IN PCONNECTION Connection,
+ IN ULONG BytesAcked
+ )
+
+/*++
+
+Routine Description:
+
+ This routine advances the Connection->UnAckedSend
+ send pointer by the specified number of bytes. It
+ assumes that there are enough send requests to
+ handle the number specified.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Connection - The connection.
+
+ BytesAcked - The number of bytes acked.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ ULONG CurSendBufferLength;
+ ULONG BytesLeft = BytesAcked;
+ ULONG TempBytes;
+
+ while (BytesLeft > 0) {
+
+ NdisQueryBuffer (Connection->UnAckedSend.Buffer, NULL, &CurSendBufferLength);
+
+ //
+ // See if bytes acked ends within the current buffer.
+ //
+
+ if (Connection->UnAckedSend.BufferOffset + BytesLeft <
+ CurSendBufferLength) {
+
+ Connection->UnAckedSend.BufferOffset += BytesLeft;
+ Connection->UnAckedSend.MessageOffset += BytesLeft;
+ break;
+
+ } else {
+
+ TempBytes = CurSendBufferLength - Connection->UnAckedSend.BufferOffset;
+ BytesLeft -= TempBytes;
+ Connection->UnAckedSend.MessageOffset += TempBytes;
+
+ //
+ // No, so advance the buffer.
+ //
+
+ Connection->UnAckedSend.BufferOffset = 0;
+ Connection->UnAckedSend.Buffer =
+ NDIS_BUFFER_LINKAGE (Connection->UnAckedSend.Buffer);
+
+ //
+ // Is there a next buffer in this request?
+ //
+
+ if (Connection->UnAckedSend.Buffer == NULL) {
+
+ //
+ // No, so advance the request unless we are done.
+ //
+
+ if (BytesLeft == 0) {
+ return;
+ }
+
+ Connection->UnAckedSend.Request =
+ REQUEST_SINGLE_LINKAGE(Connection->UnAckedSend.Request);
+
+ if (Connection->UnAckedSend.Request == NULL) {
+ KeBugCheck (NDIS_INTERNAL_ERROR);
+ }
+
+ Connection->UnAckedSend.Buffer =
+ REQUEST_NDIS_BUFFER (Connection->UnAckedSend.Request);
+
+ }
+ }
+ }
+
+} /* NbiAdvanceUnAckedByBytes */
+
+
+VOID
+NbiAdvanceUnAckedBySequence(
+ IN PCONNECTION Connection,
+ IN USHORT ReceiveSequence
+ )
+
+/*++
+
+Routine Description:
+
+ This routine advances the Connection->UnAckedSend
+ send pointer so that the next packet to send will be
+ the correct one for ReceiveSequence. UnAckedSend
+ must point to a known valid combination. It
+ assumes that there are enough send requests to
+ handle the sequence specified.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Connection - The connection.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ USHORT PacketsAcked;
+
+ //
+ // BUGBUG: Fix this to account for partial sends, where
+ // we might not have used the max. for all packets.
+ //
+
+ PacketsAcked = ReceiveSequence - Connection->UnAckedSend.SendSequence;
+
+ NbiAdvanceUnAckedByBytes(
+ Connection,
+ PacketsAcked * Connection->MaximumPacketSize);
+
+ Connection->UnAckedSend.SendSequence += PacketsAcked;
+
+} /* NbiAdvanceUnAckedBySequence */
+
+
+VOID
+NbiCancelSend(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a send
+ The request is found on the connection's send queue.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PREQUEST Request = (PREQUEST)Irp;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_SEND));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ //
+ // Just stop the connection, that will tear down any
+ // sends.
+ //
+ // BUGBUG: Do we care about cancelling non-active
+ // sends without stopping the connection??
+ //
+
+ NbiReferenceConnectionSync (Connection, CREF_CANCEL);
+
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+
+ NB_BEGIN_SYNC (&SyncContext);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ //
+ // This frees the lock, cancels any sends, etc.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_CANCELLED
+ NB_LOCK_HANDLE_ARG (LockHandle));
+
+ NbiDereferenceConnection (Connection, CREF_CANCEL);
+
+ NB_END_SYNC (&SyncContext);
+
+} /* NbiCancelSend */
+
+
+NTSTATUS
+NbiBuildBufferChainFromBufferChain (
+ IN NDIS_HANDLE BufferPoolHandle,
+ IN PNDIS_BUFFER CurrentSourceBuffer,
+ IN ULONG CurrentByteOffset,
+ IN ULONG DesiredLength,
+ OUT PNDIS_BUFFER *DestinationBuffer,
+ OUT PNDIS_BUFFER *NewSourceBuffer,
+ OUT ULONG *NewByteOffset,
+ OUT ULONG *ActualLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to build an NDIS_BUFFER chain from a source
+ NDIS_BUFFER chain and offset into it. We assume we don't know the
+ length of the source Mdl chain, and we must allocate the NDIS_BUFFERs
+ for the destination chain, which we do from the NDIS buffer pool.
+
+ If the system runs out of memory while we are building the destination
+ NDIS_BUFFER chain, we completely clean up the built chain and return with
+ NewCurrentMdl and NewByteOffset set to the current values of CurrentMdl
+ and ByteOffset.
+
+Environment:
+
+Arguments:
+
+ BufferPoolHandle - The buffer pool to allocate buffers from.
+
+ CurrentSourceBuffer - Points to the start of the NDIS_BUFFER chain
+ from which to draw the packet.
+
+ CurrentByteOffset - Offset within this NDIS_BUFFER to start the packet at.
+
+ DesiredLength - The number of bytes to insert into the packet.
+
+ DestinationBuffer - returned pointer to the NDIS_BUFFER chain describing
+ the packet.
+
+ NewSourceBuffer - returned pointer to the NDIS_BUFFER that would
+ be used for the next byte of packet. NULL if the source NDIS_BUFFER
+ chain was exhausted.
+
+ NewByteOffset - returned offset into the NewSourceBuffer for the next byte
+ of packet. NULL if the source NDIS_BUFFER chain was exhausted.
+
+ ActualLength - The actual length of the data copied.
+
+Return Value:
+
+ STATUS_SUCCESS if the build of the returned NDIS_BUFFER chain succeeded
+ and was the correct length.
+
+ STATUS_INSUFFICIENT_RESOURCES if we ran out of NDIS_BUFFERs while
+ building the destination chain.
+
+--*/
+{
+ ULONG AvailableBytes;
+ ULONG CurrentByteCount;
+ ULONG BytesCopied;
+ PNDIS_BUFFER OldNdisBuffer;
+ PNDIS_BUFFER NewNdisBuffer;
+ NDIS_STATUS NdisStatus;
+
+
+ OldNdisBuffer = CurrentSourceBuffer;
+ NdisQueryBuffer (OldNdisBuffer, NULL, &CurrentByteCount);
+
+ AvailableBytes = CurrentByteCount - CurrentByteOffset;
+ if (AvailableBytes > DesiredLength) {
+ AvailableBytes = DesiredLength;
+ }
+
+ //
+ // Build the first NDIS_BUFFER, which could conceivably be the only one...
+ //
+
+ NdisCopyBuffer(
+ &NdisStatus,
+ &NewNdisBuffer,
+ BufferPoolHandle,
+ OldNdisBuffer,
+ CurrentByteOffset,
+ AvailableBytes);
+
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ *NewSourceBuffer = CurrentSourceBuffer;
+ *NewByteOffset = CurrentByteOffset;
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ *DestinationBuffer = NewNdisBuffer;
+ BytesCopied = AvailableBytes;
+
+ //
+ // Was the first NDIS_BUFFER enough data.
+ //
+
+ if (BytesCopied == DesiredLength) {
+ if (CurrentByteOffset + AvailableBytes == CurrentByteCount) {
+ *NewSourceBuffer = CurrentSourceBuffer->Next;
+ *NewByteOffset = 0;
+ } else {
+ *NewSourceBuffer = CurrentSourceBuffer;
+ *NewByteOffset = CurrentByteOffset + AvailableBytes;
+ }
+ *ActualLength = BytesCopied;
+ return STATUS_SUCCESS;
+ }
+
+ if (CurrentSourceBuffer->Next == NULL) {
+
+ *NewSourceBuffer = NULL;
+ *NewByteOffset = 0;
+ *ActualLength = BytesCopied;
+ return STATUS_SUCCESS;
+
+ }
+
+ //
+ // Need more data, so follow the in Mdl chain to create a packet.
+ //
+
+ OldNdisBuffer = OldNdisBuffer->Next;
+ NdisQueryBuffer (OldNdisBuffer, NULL, &CurrentByteCount);
+
+ while (OldNdisBuffer != NULL) {
+
+ AvailableBytes = DesiredLength - BytesCopied;
+ if (AvailableBytes > CurrentByteCount) {
+ AvailableBytes = CurrentByteCount;
+ }
+
+ NdisCopyBuffer(
+ &NdisStatus,
+ &(NDIS_BUFFER_LINKAGE(NewNdisBuffer)),
+ BufferPoolHandle,
+ OldNdisBuffer,
+ 0,
+ AvailableBytes);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // ran out of resources. put back what we've used in this call and
+ // return the error.
+ //
+
+ while (*DestinationBuffer != NULL) {
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE(*DestinationBuffer);
+ NdisFreeBuffer (*DestinationBuffer);
+ *DestinationBuffer = NewNdisBuffer;
+ }
+
+ *NewByteOffset = CurrentByteOffset;
+ *NewSourceBuffer = CurrentSourceBuffer;
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE(NewNdisBuffer);
+
+ BytesCopied += AvailableBytes;
+
+ if (BytesCopied == DesiredLength) {
+ if (AvailableBytes == CurrentByteCount) {
+ *NewSourceBuffer = OldNdisBuffer->Next;
+ *NewByteOffset = 0;
+ } else {
+ *NewSourceBuffer = OldNdisBuffer;
+ *NewByteOffset = AvailableBytes;
+ }
+ *ActualLength = BytesCopied;
+ return STATUS_SUCCESS;
+ }
+
+ OldNdisBuffer = OldNdisBuffer->Next;
+ NdisQueryBuffer (OldNdisBuffer, NULL, &CurrentByteCount);
+
+ }
+
+ //
+ // We ran out of source buffer chain.
+ //
+
+ *NewSourceBuffer = NULL;
+ *NewByteOffset = 0;
+ *ActualLength = BytesCopied;
+ return STATUS_SUCCESS;
+
+} /* NbiBuildBufferChainFromBufferChain */
+
diff --git a/private/ntos/tdi/isnp/nb/session.c b/private/ntos/tdi/isnp/nb/session.c
new file mode 100644
index 000000000..fe998feb2
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/session.c
@@ -0,0 +1,2450 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ session.c
+
+Abstract:
+
+ This module contains the code to handle session frames
+ for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 28-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#ifdef RASAUTODIAL
+#include <acd.h>
+#include <acdapi.h>
+#endif // RASAUTODIAL
+#pragma hdrstop
+
+#ifdef RASAUTODIAL
+extern BOOLEAN fAcdLoadedG;
+extern ACD_DRIVER AcdDriverG;
+
+VOID
+NbiNoteNewConnection(
+ PCONNECTION pConnection
+ );
+#endif
+
+#ifdef RSRC_TIMEOUT_DBG
+VOID
+NbiSendDeathPacket(
+ IN PCONNECTION Connection,
+ IN CTELockHandle LockHandle
+ )
+{
+ PNDIS_PACKET Packet = PACKET(&NbiGlobalDeathPacket);
+ PNB_SEND_RESERVED Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
+ NB_CONNECTION UNALIGNED * Header;
+ PDEVICE Device = NbiDevice;
+ NDIS_STATUS NdisStatus;
+
+ if ( Reserved->SendInProgress ) {
+ DbgPrint("***Could not send death packet - in use\n");
+ NB_FREE_LOCK(&Connection->Lock, LockHandle);
+ return;
+ }
+
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_DEATH_PACKET;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(NB_CONNECTION)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(NB_CONNECTION)) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+ Header->Session.ConnectionControlFlag = 0;
+ Header->Session.DataStreamType = NB_CMD_DEATH_PACKET;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = Connection->RemoteConnectionId;
+ Header->Session.SendSequence = 0;
+ Header->Session.TotalDataLength = 0;
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = 0;
+
+
+ NB_FREE_LOCK(&Connection->Lock, LockHandle);
+
+ DbgPrint("*****Death packet is being sent for connection %lx, to <%.16s>\n",Connection, Connection->RemoteName);
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &Connection->LocalTarget,
+ Packet,
+ sizeof(NB_CONNECTION),
+ sizeof(NB_CONNECTION))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+}
+#endif //RSRC_TIMEOUT_DBG
+
+
+VOID
+NbiProcessSessionData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_SESSION_DATA frames.
+
+Arguments:
+
+ MacBindingHandle - A handle to use when calling NdisTransferData.
+
+ MacReceiveContext - A context to use when calling NdisTransferData.
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The lookahead buffer, starting at the IPX
+ header.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)LookaheadBuffer;
+ NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
+ PCONNECTION Connection;
+ PREQUEST Request;
+ PDEVICE Device = NbiDevice;
+ ULONG Hash;
+ ULONG ReceiveFlags;
+ ULONG IndicateBytesTransferred;
+ ULONG DataAvailable, DataIndicated;
+ ULONG DestBytes, BytesToTransfer;
+ PUCHAR DataHeader;
+ BOOLEAN Last, CompleteReceive, EndOfMessage, PartialReceive, CopyLookahead;
+ NTSTATUS Status;
+ NDIS_STATUS NdisStatus;
+ ULONG NdisBytesTransferred;
+ PIRP ReceiveIrp;
+ PSINGLE_LIST_ENTRY s;
+ PNB_RECEIVE_RESERVED ReceiveReserved;
+ PNDIS_PACKET Packet;
+ PNDIS_BUFFER BufferChain;
+ ULONG BufferChainLength;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ CTELockHandle CancelLH;
+
+ if (Sess->DestConnectionId != 0xffff) {
+
+ //
+ // This is an active connection, find it using
+ // our session id.
+ //
+
+ Hash = (Sess->DestConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Connection = Device->ConnectionHash[Hash].Connections;
+
+ while (Connection != NULL) {
+
+ if (Connection->LocalConnectionId == Sess->DestConnectionId) {
+ break;
+ }
+ Connection = Connection->NextConnection;
+ }
+
+ if (Connection == NULL) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ NbiReferenceConnectionLock (Connection, CREF_INDICATE);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // See what is happening with this connection.
+ //
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+#ifdef RSRC_TIMEOUT_DBG
+ if ( Connection->FirstMessageRequest && NbiGlobalDebugResTimeout ) {
+ LARGE_INTEGER CurrentTime, ElapsedTime;
+ KeQuerySystemTime(&CurrentTime);
+ ElapsedTime.QuadPart = CurrentTime.QuadPart - Connection->FirstMessageRequestTime.QuadPart;
+// DbgPrint("*****Elapsed %lx.%lx time\n",ElapsedTime.HighPart,ElapsedTime.LowPart);
+ if ( ElapsedTime.QuadPart > NbiGlobalMaxResTimeout.QuadPart ) {
+
+ DbgPrint("*****Connection %lx is not copleting irp %lx for %lx.%lx time\n",Connection, Connection->FirstMessageRequest,
+ ElapsedTime.HighPart,ElapsedTime.LowPart);
+ DbgPrint("************irp arrived at %lx.%lx current time %lx.%lx\n",
+ Connection->FirstMessageRequestTime.HighPart,Connection->FirstMessageRequestTime.LowPart,
+ CurrentTime.HighPart, CurrentTime.LowPart);
+
+ NbiSendDeathPacket( Connection, LockHandle );
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+ }
+ }
+#endif //RSRC_TIMEOUT_DBG
+
+ //
+ // The connection is up, see if this is data should
+ // be received.
+ //
+
+ if (Sess->ConnectionControlFlag & NB_CONTROL_SYSTEM) {
+
+ //
+ // This is an ack. This call releases
+ // the lock. BUGBUG: Does this need to
+ // be a function?
+ //
+
+ NbiProcessDataAck(
+ Connection,
+ Sess,
+ RemoteAddress
+ NB_LOCK_HANDLE_ARG (LockHandle)
+ );
+
+ } else {
+
+ //
+ // See if there is any piggyback ack here.
+ //
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK) {
+
+ //
+ // We are waiting for an ack, so see if this acks
+ // anything. Even the old netbios sometimes piggyback
+ // acks (and doesn't send the explicit ack).
+ //
+ // This releases the lock. BUGBUG: Fix this.
+ //
+
+ NbiReframeConnection(
+ Connection,
+ Sess->ReceiveSequence,
+ Sess->BytesReceived,
+ FALSE
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State != CONNECTION_STATE_ACTIVE) {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+ }
+
+ } else if ((Connection->NewNetbios) &&
+ (Connection->CurrentSend.SendSequence != Connection->UnAckedSend.SendSequence)) {
+
+ //
+ // For the new netbios, even if we are not waiting
+ // for an ack he may have acked something with this
+ // send and we should check, since it may allow
+ // us to open our send window.
+ //
+ // This releases the lock. BUGBUG: Fix this.
+ //
+
+ NbiReframeConnection(
+ Connection,
+ Sess->ReceiveSequence,
+ Sess->BytesReceived,
+ FALSE
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State != CONNECTION_STATE_ACTIVE) {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+ }
+
+ }
+
+ //
+ // This is data on the connection. First make sure
+ // it is the data we expect next.
+ //
+
+ if (Connection->NewNetbios) {
+
+ if (Sess->SendSequence != Connection->ReceiveSequence) {
+
+ ++Connection->ConnectionInfo.ReceiveErrors;
+ ++Device->Statistics.DataFramesRejected;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesRejected,
+ PacketSize - sizeof(NB_CONNECTION));
+
+ if ((Connection->ReceiveState == CONNECTION_RECEIVE_IDLE) ||
+ (Connection->ReceiveState == CONNECTION_RECEIVE_ACTIVE)) {
+
+ NB_ACK_TYPE AckType;
+
+ NB_DEBUG2 (RECEIVE, ("Got unexp data on %lx, %x(%d) expect %x(%d)\n",
+ Connection, Sess->SendSequence, Sess->Offset,
+ Connection->ReceiveSequence, Connection->CurrentReceive.MessageOffset));
+
+ //
+ // If we are receiving a packet we have already seen, just
+ // send a normal ack, otherwise force a resend. This test
+ // we do is equivalent to
+ // Sess->SendSequence < Connection->ReceiveSequence
+ // but rearranged so it works when the numbers wrap.
+ //
+
+ if ((SHORT)(Sess->SendSequence - Connection->ReceiveSequence) < 0) {
+
+ //
+ // Since this is a resend, check if the local
+ // target has changed.
+ //
+#if defined(_PNP_POWER)
+
+ if (!RtlEqualMemory (&Connection->LocalTarget, RemoteAddress, sizeof(IPX_LOCAL_TARGET))) {
+#if DBG
+ DbgPrint ("NBI: Switch local target for %lx, (%d,%d)\n", Connection,
+ Connection->LocalTarget.NicHandle.NicId, RemoteAddress->NicHandle.NicId);
+#endif
+ Connection->LocalTarget = *RemoteAddress;
+ }
+
+#else
+
+ if (!RtlEqualMemory (&Connection->LocalTarget, RemoteAddress, 8)) {
+#if DBG
+ DbgPrint ("NBI: Switch local target for %lx\n", Connection);
+#endif
+ Connection->LocalTarget = *RemoteAddress;
+ }
+
+#endif _PNP_POWER
+ AckType = NbiAckResponse;
+
+ } else {
+
+ AckType = NbiAckResend;
+ }
+
+ //
+ // This frees the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ AckType
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_DEBUG (RECEIVE, ("Got unexp on %lx RcvState %d, %x(%d) exp %x(%d)\n",
+ Connection, Connection->ReceiveState,
+ Sess->SendSequence, Sess->Offset,
+ Connection->ReceiveSequence, Connection->CurrentReceive.MessageOffset));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ } else {
+
+ //
+ // Old netbios.
+ //
+
+ if ((Sess->SendSequence != Connection->ReceiveSequence) ||
+ (Sess->Offset != Connection->CurrentReceive.MessageOffset)) {
+
+ ++Connection->ConnectionInfo.ReceiveErrors;
+ ++Device->Statistics.DataFramesRejected;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesRejected,
+ PacketSize - sizeof(NB_CONNECTION));
+
+ if ((Connection->ReceiveState == CONNECTION_RECEIVE_IDLE) ||
+ (Connection->ReceiveState == CONNECTION_RECEIVE_ACTIVE)) {
+
+ NB_ACK_TYPE AckType;
+
+ NB_DEBUG2 (RECEIVE, ("Got unexp on %lx, %x(%d) expect %x(%d)\n",
+ Connection, Sess->SendSequence, Sess->Offset,
+ Connection->ReceiveSequence, Connection->CurrentReceive.MessageOffset));
+
+ //
+ // If we are receiving the last packet again, just
+ // send a normal ack, otherwise force a resend.
+ //
+
+ if (((Sess->SendSequence == Connection->ReceiveSequence) &&
+ ((ULONG)(Sess->Offset + Sess->DataLength) == Connection->CurrentReceive.MessageOffset)) ||
+ (Sess->SendSequence == (USHORT)(Connection->ReceiveSequence-1))) {
+ AckType = NbiAckResponse;
+ } else {
+ AckType = NbiAckResend;
+ }
+
+ //
+ // This frees the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ AckType
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_DEBUG (RECEIVE, ("Got unexp on %lx RcvState %d, %x(%d) exp %x(%d)\n",
+ Connection, Connection->ReceiveState,
+ Sess->SendSequence, Sess->Offset,
+ Connection->ReceiveSequence, Connection->CurrentReceive.MessageOffset));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ }
+
+
+ IndicateBytesTransferred = 0;
+ DataAvailable = PacketSize - sizeof(NB_CONNECTION);
+ DataIndicated = LookaheadBufferSize - sizeof(NB_CONNECTION);
+ DataHeader = LookaheadBuffer + sizeof(NB_CONNECTION);
+
+ ++Device->TempFramesReceived;
+ Device->TempFrameBytesReceived += DataAvailable;
+
+ if (Connection->CurrentIndicateOffset) {
+ CTEAssert (DataAvailable >= Connection->CurrentIndicateOffset);
+ DataAvailable -= Connection->CurrentIndicateOffset;
+ if (DataIndicated >= Connection->CurrentIndicateOffset) {
+ DataIndicated -= Connection->CurrentIndicateOffset;
+ } else {
+ DataIndicated = 0;
+ }
+ DataHeader += Connection->CurrentIndicateOffset;
+ }
+
+ CopyLookahead = (BOOLEAN)(MacOptions & NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA);
+
+ if (Connection->NewNetbios) {
+ Last = (BOOLEAN)((Sess->ConnectionControlFlag & NB_CONTROL_EOM) != 0);
+ } else {
+ Last = (BOOLEAN)(Sess->Offset + Sess->DataLength == Sess->TotalDataLength);
+ }
+
+ Connection->CurrentReceiveNoPiggyback =
+ (BOOLEAN)((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) != 0);
+
+ if (Connection->ReceiveState == CONNECTION_RECEIVE_IDLE) {
+
+ //
+ // We don't have a receive posted, so see if we can
+ // get one from the queue or our client.
+ //
+
+ if (Connection->ReceiveQueue.Head != NULL) {
+
+ PTDI_REQUEST_KERNEL_RECEIVE ReceiveParameters;
+
+ Request = Connection->ReceiveQueue.Head;
+ Connection->ReceiveQueue.Head = REQUEST_SINGLE_LINKAGE(Request);
+ Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
+
+ Connection->ReceiveRequest = Request;
+ ReceiveParameters = (PTDI_REQUEST_KERNEL_RECEIVE)
+ (REQUEST_PARAMETERS(Request));
+ Connection->ReceiveLength = ReceiveParameters->ReceiveLength;
+
+ //
+ // If there is a send in progress, then we assume
+ // we are not in straight request-response mode
+ // and disable piggybacking of this ack.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_IDLE) {
+ Connection->NoPiggybackHeuristic = TRUE;
+ } else {
+ Connection->NoPiggybackHeuristic = (BOOLEAN)
+ ((ReceiveParameters->ReceiveFlags & TDI_RECEIVE_NO_RESPONSE_EXP) != 0);
+ }
+
+ Connection->CurrentReceive.Offset = 0;
+ Connection->CurrentReceive.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentReceive.BufferOffset = 0;
+
+ NB_DEBUG2 (RECEIVE, ("Activated receive %lx on %lx (%d)\n", Request, Connection, Connection->ReceiveSequence));
+
+ //
+ // Fall through the if and process the data.
+ //
+
+ } else {
+
+ if ((Connection->ReceiveUnaccepted == 0) &&
+ (Connection->AddressFile->RegisteredHandler[TDI_EVENT_RECEIVE])) {
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_INDICATE;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ ReceiveFlags = TDI_RECEIVE_AT_DISPATCH_LEVEL;
+ if (Last) {
+ ReceiveFlags |= TDI_RECEIVE_ENTIRE_MESSAGE;
+ }
+ if (CopyLookahead) {
+ ReceiveFlags |= TDI_RECEIVE_COPY_LOOKAHEAD;
+ }
+
+ Status = (*Connection->AddressFile->ReceiveHandler)(
+ Connection->AddressFile->HandlerContexts[TDI_EVENT_RECEIVE],
+ Connection->Context,
+ ReceiveFlags,
+ DataIndicated,
+ DataAvailable,
+ &IndicateBytesTransferred,
+ DataHeader,
+ &ReceiveIrp);
+
+ if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
+
+ //
+ // We got an IRP, activate it.
+ //
+
+ Request = NbiAllocateRequest (Device, ReceiveIrp);
+
+ IF_NOT_ALLOCATED(Request) {
+
+ ReceiveIrp->IoStatus.Information = 0;
+ ReceiveIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (ReceiveIrp, IO_NETWORK_INCREMENT);
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_W_RCV;
+
+ if (Connection->NewNetbios) {
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ Connection->LocalRcvSequenceMax =
+ (USHORT)(Connection->ReceiveSequence - 1);
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ CTEAssert (REQUEST_OPEN_CONTEXT(Request) == Connection);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ PTDI_REQUEST_KERNEL_RECEIVE ReceiveParameters;
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
+ Connection->ReceiveUnaccepted = DataAvailable - IndicateBytesTransferred;
+
+ Connection->ReceiveRequest = Request;
+ ReceiveParameters = (PTDI_REQUEST_KERNEL_RECEIVE)
+ (REQUEST_PARAMETERS(Request));
+ Connection->ReceiveLength = ReceiveParameters->ReceiveLength;
+
+ //
+ // If there is a send in progress, then we assume
+ // we are not in straight request-response mode
+ // and disable piggybacking of this ack.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_IDLE) {
+ Connection->NoPiggybackHeuristic = TRUE;
+ } else {
+ Connection->NoPiggybackHeuristic = (BOOLEAN)
+ ((ReceiveParameters->ReceiveFlags & TDI_RECEIVE_NO_RESPONSE_EXP) != 0);
+ }
+
+ Connection->CurrentReceive.Offset = 0;
+ Connection->CurrentReceive.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentReceive.BufferOffset = 0;
+
+ NbiReferenceConnectionSync (Connection, CREF_RECEIVE);
+
+ NB_DEBUG2 (RECEIVE, ("Indicate got receive %lx on %lx (%d)\n", Request, Connection, Connection->ReceiveSequence));
+
+ //
+ // Fall through the if and process the data.
+ //
+
+ } else {
+
+ //
+ // The connection has been stopped.
+ //
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+ }
+
+ } else if (Status == STATUS_SUCCESS) {
+
+ //
+ // He accepted some or all of the data.
+ //
+
+ NB_DEBUG2 (RECEIVE, ("Indicate took receive data %lx (%d)\n", Connection, Connection->ReceiveSequence));
+
+ if ( (IndicateBytesTransferred >= DataAvailable)) {
+
+ CTEAssert (IndicateBytesTransferred == DataAvailable);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax; // harmless if NewNetbios is FALSE
+ Connection->CurrentIndicateOffset = 0;
+ if ( Last ) {
+ Connection->CurrentReceive.MessageOffset = 0;
+ } else {
+ Connection->CurrentReceive.MessageOffset+= IndicateBytesTransferred;
+ }
+
+
+ ++Connection->ConnectionInfo.ReceivedTsdus;
+
+ //
+ // If there is a send in progress, then we assume
+ // we are not in straight request-response mode
+ // and disable piggybacking of this ack.
+ //
+
+ Connection->NoPiggybackHeuristic = (BOOLEAN)
+ (Connection->SubState != CONNECTION_SUBSTATE_A_IDLE);
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
+ Connection->ReceiveRequest = NULL;
+
+ //
+ // This releases the lock.
+ //
+
+ NbiAcknowledgeReceive(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ //
+ // We will do the easiest thing here, which
+ // is to send an ack for the amount he
+ // took, and force a retransmit on the
+ // remote. For net netbios we make a note
+ // of how many bytes were taken and ask
+ // for a resend.
+ //
+ // BUGBUG: Handle this better??
+ //
+
+#if DBG
+ DbgPrint ("NBI: Client took partial indicate data\n");
+#endif
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ Connection->CurrentReceive.MessageOffset +=
+ IndicateBytesTransferred;
+ Connection->ReceiveUnaccepted =
+ DataAvailable - IndicateBytesTransferred;
+ Connection->ReceiveState = CONNECTION_RECEIVE_W_RCV;
+
+ if (Connection->NewNetbios) {
+ Connection->CurrentIndicateOffset = IndicateBytesTransferred;
+ //
+ // NOTE: We don't advance ReceiveSequence
+ //
+ }
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ Connection->NewNetbios ?
+ NbiAckResend : NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ } else {
+
+ //
+ // No IRP returned.
+ //
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ Connection->ReceiveUnaccepted = DataAvailable;
+ Connection->ReceiveState = CONNECTION_RECEIVE_W_RCV;
+ NB_DEBUG (RECEIVE, ("Indicate got no receive on %lx (%lx)\n", Connection, Status));
+
+ if (Connection->NewNetbios) {
+
+ Connection->LocalRcvSequenceMax =
+ (USHORT)(Connection->ReceiveSequence - 1);
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ } else {
+
+ //
+ // No receive handler.
+ //
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_W_RCV;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ if (Connection->ReceiveUnaccepted == 0) {
+ NB_DEBUG (RECEIVE, ("No receive, no handler on %lx\n", Connection));
+ } else {
+ NB_DEBUG (RECEIVE, ("No receive, ReceiveUnaccepted %d on %lx\n",
+ Connection->ReceiveUnaccepted, Connection));
+ }
+
+ if (Connection->NewNetbios) {
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ Connection->LocalRcvSequenceMax =
+ (USHORT)(Connection->ReceiveSequence - 1);
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ }
+
+ } else if (Connection->ReceiveState != CONNECTION_RECEIVE_ACTIVE) {
+
+ //
+ // If we have a transfer in progress, or are waiting for
+ // a receive to be posted, then ignore this frame.
+ //
+
+ NB_DEBUG2 (RECEIVE, ("Got data on %lx, state %d (%d)\n", Connection, Connection->ReceiveState, Connection->ReceiveSequence));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ //
+ // At this point we have a receive and it is set to
+ // the correct current location.
+ //
+
+ DestBytes = Connection->ReceiveLength - Connection->CurrentReceive.Offset;
+ BytesToTransfer = DataAvailable - IndicateBytesTransferred;
+
+ if (DestBytes < BytesToTransfer) {
+
+ //
+ // If the data overflows the current receive, then make a
+ // note that we should complete the receive at the end of
+ // transfer data, but with EOR false.
+ //
+
+ EndOfMessage = FALSE;
+ CompleteReceive = TRUE;
+ PartialReceive = TRUE;
+ BytesToTransfer = DestBytes;
+
+ } else if (DestBytes == BytesToTransfer) {
+
+ //
+ // If the data just fills the current receive, then complete
+ // the receive; EOR depends on whether this is a DOL or not.
+ //
+
+ EndOfMessage = Last;
+ CompleteReceive = TRUE;
+ PartialReceive = FALSE;
+
+ } else {
+
+ //
+ // Complete the receive if this is a DOL.
+ //
+
+ EndOfMessage = Last;
+ CompleteReceive = Last;
+ PartialReceive = FALSE;
+
+ }
+
+ //
+ // If we can copy the data directly, then update our
+ // pointers, send an ack, and do the copy.
+ //
+
+ if ((BytesToTransfer > 0) &&
+ (IndicateBytesTransferred + BytesToTransfer <= DataIndicated)) {
+
+ ULONG BytesNow, BytesLeft;
+ PUCHAR CurTarget, CurSource;
+ ULONG CurTargetLen;
+ PNDIS_BUFFER CurBuffer;
+ ULONG CurByteOffset;
+
+ NB_DEBUG2 (RECEIVE, ("Direct copy of %d bytes %lx (%d)\n", BytesToTransfer, Connection, Connection->ReceiveSequence));
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_TRANSFER;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ CurBuffer = Connection->CurrentReceive.Buffer;
+ CurByteOffset = Connection->CurrentReceive.BufferOffset;
+
+ NdisQueryBuffer (CurBuffer, &CurTarget, &CurTargetLen);
+ CurTarget += CurByteOffset;
+ CurTargetLen -= CurByteOffset;
+
+ CurSource = DataHeader + IndicateBytesTransferred;
+ BytesLeft = BytesToTransfer;
+
+ while (TRUE) {
+
+ if (CurTargetLen < BytesLeft) {
+ BytesNow = CurTargetLen;
+ } else {
+ BytesNow = BytesLeft;
+ }
+ TdiCopyLookaheadData(
+ CurTarget,
+ CurSource,
+ BytesNow,
+ CopyLookahead ? TDI_RECEIVE_COPY_LOOKAHEAD : 0);
+
+ if (BytesNow == CurTargetLen) {
+ BytesLeft -= BytesNow;
+ CurBuffer = CurBuffer->Next;
+ CurByteOffset = 0;
+ if (BytesLeft > 0) {
+ NdisQueryBuffer (CurBuffer, &CurTarget, &CurTargetLen);
+ CurSource += BytesNow;
+ } else {
+ break;
+ }
+ } else {
+ CurByteOffset += BytesNow;
+ CTEAssert (BytesLeft == BytesNow);
+ break;
+ }
+
+ }
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ Connection->CurrentReceive.Buffer = CurBuffer;
+ Connection->CurrentReceive.BufferOffset = CurByteOffset;
+
+ Connection->CurrentReceive.Offset += BytesToTransfer;
+ Connection->CurrentReceive.MessageOffset += BytesToTransfer;
+
+ if (CompleteReceive ||
+ (Connection->State != CONNECTION_STATE_ACTIVE)) {
+
+ if (EndOfMessage) {
+
+ CTEAssert (!PartialReceive);
+
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax; // harmless if NewNetbios is FALSE
+ Connection->CurrentReceive.MessageOffset = 0;
+ Connection->CurrentIndicateOffset = 0;
+
+ } else if (Connection->NewNetbios) {
+
+ if (PartialReceive) {
+ Connection->CurrentIndicateOffset += BytesToTransfer;
+ } else {
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax;
+ Connection->CurrentIndicateOffset = 0;
+ }
+ }
+
+ //
+ // This sends an ack and releases the connection lock.
+ // and CANCEL Lock.
+ //
+
+ NbiCompleteReceive(
+ Connection,
+ EndOfMessage,
+ CancelLH
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ //
+ // CompleteReceive is FALSE, so EndOfMessage is FALSE.
+ //
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
+
+ //
+ // This releases the lock.
+ //
+
+ if (Connection->NewNetbios) {
+
+ //
+ // A partial receive should only happen if we are
+ // completing the receive.
+ //
+
+ CTEAssert (!PartialReceive);
+
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax;
+ Connection->CurrentIndicateOffset = 0;
+
+ if ((Connection->CurrentReceiveNoPiggyback) ||
+ ((Device->AckWindow != 0) &&
+ (++Connection->ReceivesWithoutAck >= Device->AckWindow))) {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+
+ //
+ // We have to set up a call to transfer data and send
+ // the ack after it completes (if it succeeds).
+ //
+
+ s = NbiPopReceivePacket (Device);
+ if (s == NULL) {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ ++Connection->ConnectionInfo.ReceiveErrors;
+ ++Device->Statistics.DataFramesRejected;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesRejected,
+ DataAvailable);
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+ }
+
+ ReceiveReserved = CONTAINING_RECORD (s, NB_RECEIVE_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (ReceiveReserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ //
+ // Initialize the receive packet.
+ //
+
+ ReceiveReserved->u.RR_CO.Connection = Connection;
+ ReceiveReserved->u.RR_CO.EndOfMessage = EndOfMessage;
+ ReceiveReserved->u.RR_CO.CompleteReceive = CompleteReceive;
+ ReceiveReserved->u.RR_CO.PartialReceive = PartialReceive;
+
+ ReceiveReserved->Type = RECEIVE_TYPE_DATA;
+ CTEAssert (!ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = TRUE;
+
+ //
+ // if we've got zero bytes left, avoid the TransferData below and
+ // just deliver.
+ //
+
+ if (BytesToTransfer <= 0) {
+
+ ReceiveReserved->u.RR_CO.NoNdisBuffer = TRUE;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_DEBUG2 (RECEIVE, ("TransferData of 0 bytes %lx (%d)\n", Connection, Connection->ReceiveSequence));
+ NbiTransferDataComplete(
+ Packet,
+ NDIS_STATUS_SUCCESS,
+ 0);
+
+ return;
+ }
+
+ //
+ // If needed, build a buffer chain to describe this
+ // to NDIS.
+ //
+
+ Connection->PreviousReceive = Connection->CurrentReceive;
+
+ if ((Connection->CurrentReceive.Offset == 0) &&
+ CompleteReceive) {
+
+ BufferChain = Connection->CurrentReceive.Buffer;
+ BufferChainLength = BytesToTransfer;
+ Connection->CurrentReceive.Buffer = NULL;
+ ReceiveReserved->u.RR_CO.NoNdisBuffer = TRUE;
+
+ } else {
+
+ if (NbiBuildBufferChainFromBufferChain (
+ Device->NdisBufferPoolHandle,
+ Connection->CurrentReceive.Buffer,
+ Connection->CurrentReceive.BufferOffset,
+ BytesToTransfer,
+ &BufferChain,
+ &Connection->CurrentReceive.Buffer,
+ &Connection->CurrentReceive.BufferOffset,
+ &BufferChainLength) != NDIS_STATUS_SUCCESS) {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_DEBUG2 (RECEIVE, ("Could not build receive buffer chain %lx (%d)\n", Connection, Connection->ReceiveSequence));
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ ReceiveReserved->u.RR_CO.NoNdisBuffer = FALSE;
+
+ }
+
+
+ NdisChainBufferAtFront (Packet, BufferChain);
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_TRANSFER;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NB_DEBUG2 (RECEIVE, ("TransferData of %d bytes %lx (%d)\n", BytesToTransfer, Connection, Connection->ReceiveSequence));
+
+ (*Device->Bind.TransferDataHandler) (
+ &NdisStatus,
+ MacBindingHandle,
+ MacReceiveContext,
+ LookaheadBufferOffset + sizeof(NB_CONNECTION) +
+ Connection->CurrentIndicateOffset + IndicateBytesTransferred,
+ BytesToTransfer,
+ Packet,
+ (PUINT)&NdisBytesTransferred);
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+#if DBG
+ if (NdisStatus == STATUS_SUCCESS) {
+ CTEAssert (NdisBytesTransferred == BytesToTransfer);
+ }
+#endif
+
+ NbiTransferDataComplete (
+ Packet,
+ NdisStatus,
+ NdisBytesTransferred);
+
+ }
+
+ return;
+
+ }
+
+ } else if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN)) {
+
+ //
+ // If this is the ack for the session initialize, then
+ // complete the pending connects. This routine releases
+ // the connection lock.
+ //
+
+ NbiProcessSessionInitAck(
+ Connection,
+ Sess
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+
+ } else {
+
+ //
+ // This is a session initialize frame.
+ //
+ // BUGBUG: If there is more data than in the lookahead
+ // buffer, we won't be able to echo it back in the
+ // response.
+ //
+
+ NbiProcessSessionInitialize(
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize);
+
+ }
+
+} /* NbiProcessSessionData */
+
+
+VOID
+NbiProcessDataAck(
+ IN PCONNECTION Connection,
+ IN NB_SESSION UNALIGNED * Sess,
+ IN PIPX_LOCAL_TARGET RemoteAddress
+ NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an ack on an active connection.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection.
+
+ Sess - The session frame.
+
+ RemoteAddress - The local target this packet was received from.
+
+ LockHandle - The handle used to acquire the lock.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ BOOLEAN Resend;
+
+ //
+ // Make sure we expect an ack right now.
+ //
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ if (((Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK) ||
+ (Connection->SubState == CONNECTION_SUBSTATE_A_REMOTE_W)) &&
+ ((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) == 0)) {
+
+ //
+ // We are waiting for an ack (because we completed
+ // packetizing a send, or ran out of receive window).
+ //
+ // This will complete any sends that are acked by
+ // this receive, and if necessary readjust the
+ // send pointer and requeue the connection for
+ // packetizing. It release the connection lock.
+ //
+
+ if (Connection->ResponseTimeout) {
+ Resend = TRUE;
+ Connection->ResponseTimeout = FALSE;
+ } else {
+ Resend = (BOOLEAN)
+ ((Sess->ConnectionControlFlag & NB_CONTROL_RESEND) != 0);
+ }
+
+ NbiReframeConnection(
+ Connection,
+ Sess->ReceiveSequence,
+ Sess->BytesReceived,
+ Resend
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else if ((Connection->SubState == CONNECTION_SUBSTATE_A_W_PROBE) &&
+ ((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) == 0)) {
+
+ //
+ // We had a probe outstanding and got a response. Restart
+ // the connection if needed (a send may have just been
+ // posted while the probe was outstanding).
+ //
+ // BUGBUG: We should check that the response is really
+ // correct.
+ //
+
+ if (Connection->NewNetbios) {
+ Connection->RemoteRcvSequenceMax = Sess->ReceiveSequenceMax;
+ }
+
+ NbiRestartConnection (Connection);
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ } else if ((Connection->SubState == CONNECTION_SUBSTATE_A_PACKETIZE) &&
+ ((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) == 0)) {
+
+ if (Connection->NewNetbios) {
+
+ //
+ // We are packetizing, reframe. In the unlikely
+ // event that this acks everything we may packetize
+ // in this call, but that is OK (the other thread
+ // will exit if we finish up). More normally we
+ // will just advance UnAcked send a bit.
+ //
+
+ NbiReframeConnection(
+ Connection,
+ Sess->ReceiveSequence,
+ Sess->BytesReceived,
+ (BOOLEAN)((Sess->ConnectionControlFlag & NB_CONTROL_RESEND) != 0)
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+#if 0
+
+ //
+ // BUGBUG: Should handle this case (i.e. may be in W_PACKET).
+ //
+
+ } else if ((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) == 0) {
+
+ DbgPrint ("NWLNKNB: Ignoring ack, state is %d\n", Connection->SubState);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+#endif
+
+ } else {
+
+ //
+ // We got a probe from the remote. Some old DOS clients
+ // send probes that do not have the send ack bit on,
+ // so we respond to any probe if none of the conditions
+ // above are true. This call releases the lock.
+ //
+ // We use the IgnoreNextDosProbe flag to ignore every
+ // second probe of this nature, to avoid a data ack
+ // war between two machines who each think they are
+ // responding to the other. This flag is set to FALSE
+ // whenever we send an ack or a probe.
+ //
+
+ if (!Connection->IgnoreNextDosProbe) {
+
+ //
+ // Since this is a probe, check if the local
+ // target has changed.
+ //
+
+ if (!RtlEqualMemory (&Connection->LocalTarget, RemoteAddress, 8)) {
+#if DBG
+ DbgPrint ("NBI: Switch local target for %lx\n", Connection);
+#endif
+ Connection->LocalTarget = *RemoteAddress;
+ }
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+ Connection->IgnoreNextDosProbe = TRUE;
+
+ } else {
+
+ Connection->IgnoreNextDosProbe = FALSE;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+
+ }
+
+} /* NbiProcessDataAck */
+
+
+VOID
+NbiProcessSessionInitialize(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_SESSION frames which have
+ a remote connection ID of 0xffff -- these are session
+ initialize frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ PacketBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)PacketBuffer;
+ NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
+ NB_SESSION_INIT UNALIGNED * SessInit = (NB_SESSION_INIT UNALIGNED *)(Sess+1);
+ CONNECT_INDICATION TempConnInd;
+ PCONNECT_INDICATION ConnInd;
+ PCONNECTION Connection;
+ PADDRESS Address;
+ PREQUEST Request, ListenRequest, AcceptRequest;
+ PDEVICE Device = NbiDevice;
+ PLIST_ENTRY p;
+ ULONG Hash;
+ TA_NETBIOS_ADDRESS SourceName;
+ PIRP AcceptIrp;
+ CONNECTION_CONTEXT ConnectionContext;
+ NTSTATUS AcceptStatus;
+ PADDRESS_FILE AddressFile, ReferencedAddressFile;
+ PTDI_REQUEST_KERNEL_LISTEN ListenParameters;
+ PTDI_CONNECTION_INFORMATION ListenInformation;
+ PTDI_CONNECTION_INFORMATION RemoteInformation;
+ TDI_ADDRESS_NETBIOS UNALIGNED * ListenAddress;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+ NB_DEFINE_LOCK_HANDLE (LockHandle2)
+ NB_DEFINE_LOCK_HANDLE (LockHandle3)
+ CTELockHandle CancelLH;
+
+ //
+ // Verify that the whole packet is there.
+ //
+
+ if (PacketSize < (sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT))) {
+#if DBG
+ DbgPrint ("NBI: Got short session initialize, %d/%d\n", PacketSize,
+ sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT));
+#endif
+ return;
+ }
+
+ //
+ // Verify that MaximumDataSize that remote can support is > 0
+ // Bug # 19405
+ //
+ if ( SessInit->MaximumDataSize == 0 ) {
+ NB_DEBUG(CONNECTION, ("Connect request with MaximumDataSize == 0\n"
+));
+ return;
+ }
+
+ //
+ // Make sure this is for an address we care about.
+ //
+
+ if (Device->AddressCounts[SessInit->DestinationName[0]] == 0) {
+ return;
+ }
+
+ Address = NbiFindAddress (Device, (PUCHAR)SessInit->DestinationName);
+
+ if (Address == NULL) {
+ return;
+ }
+
+ //
+ // First see if we have a session to this remote. We check
+ // this in case our ack of the session initialize was dropped,
+ // we don't want to reindicate our client.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle3);
+
+ for (Hash = 0; Hash < CONNECTION_HASH_COUNT; Hash++) {
+
+ Connection = Device->ConnectionHash[Hash].Connections;
+
+ while (Connection != NULL) {
+
+ if ((RtlEqualMemory (&Connection->RemoteHeader.DestinationNetwork, Conn->IpxHeader.SourceNetwork, 12)) &&
+ (Connection->RemoteConnectionId == Sess->SourceConnectionId) &&
+ (Connection->State != CONNECTION_STATE_DISCONNECT)) {
+
+ //
+ // Yes, we are talking to this remote, if it is active then
+ // respond, otherwise we are in the process of connecting
+ // and we will respond eventually.
+ //
+
+#if DBG
+ DbgPrint ("NBI: Got connect request on active connection %lx\n", Connection);
+#endif
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ NbiReferenceConnectionLock (Connection, CREF_INDICATE);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+ NbiSendSessionInitAck(
+ Connection,
+ (PUCHAR)(SessInit+1),
+ PacketSize - (sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT)),
+ NULL); // lock is not held
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+ }
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+ return;
+ }
+
+ Connection = Connection->NextConnection;
+ }
+ }
+
+
+ TdiBuildNetbiosAddress ((PUCHAR)SessInit->SourceName, FALSE, &SourceName);
+
+ //
+ // Scan the queue of listens to see if there is one that
+ // satisfies this request.
+ //
+ // NOTE: The device lock is held here.
+ //
+
+ for (p = Device->ListenQueue.Flink;
+ p != &Device->ListenQueue;
+ p = p->Flink) {
+
+ Request = LIST_ENTRY_TO_REQUEST (p);
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ if (Connection->AddressFile->Address != Address) {
+ continue;
+ }
+
+ //
+ // Check that this listen is not specific to a different
+ // netbios name.
+ //
+
+ ListenParameters = (PTDI_REQUEST_KERNEL_LISTEN)REQUEST_PARAMETERS(Request);
+ ListenInformation = ListenParameters->RequestConnectionInformation;
+
+ if (ListenInformation &&
+ (ListenInformation->RemoteAddress) &&
+ (ListenAddress = NbiParseTdiAddress(ListenInformation->RemoteAddress, FALSE)) &&
+ (!RtlEqualMemory(
+ SessInit->SourceName,
+ ListenAddress->NetbiosName,
+ 16))) {
+ continue;
+ }
+
+ //
+ // This connection is valid, so we use it.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Activating queued listen %lx\n", Connection));
+
+ RemoveEntryList (REQUEST_LINKAGE(Request));
+
+ RtlCopyMemory(&Connection->RemoteHeader.DestinationNetwork, Conn->IpxHeader.SourceNetwork, 12);
+ RtlCopyMemory (Connection->RemoteName, SessInit->SourceName, 16);
+ Connection->LocalTarget = *RemoteAddress;
+ Connection->RemoteConnectionId = Sess->SourceConnectionId;
+
+ Connection->SessionInitAckDataLength =
+ PacketSize - (sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT));
+ if (Connection->SessionInitAckDataLength > 0) {
+ Connection->SessionInitAckData = NbiAllocateMemory(
+ Connection->SessionInitAckDataLength, MEMORY_CONNECTION, "SessionInitAckData");
+ RtlCopyMemory(
+ Connection->SessionInitAckData,
+ (PUCHAR)(SessInit+1),
+ Connection->SessionInitAckDataLength);
+ }
+
+
+ Connection->MaximumPacketSize = SessInit->MaximumDataSize;
+
+ Connection->CurrentSend.SendSequence = 0;
+ Connection->UnAckedSend.SendSequence = 0;
+ Connection->RetransmitThisWindow = FALSE;
+ Connection->ReceiveSequence = 1;
+ Connection->CurrentReceive.MessageOffset = 0;
+ Connection->Retries = Device->KeepAliveCount;
+ if (Device->Extensions && ((Sess->ConnectionControlFlag & NB_CONTROL_NEW_NB) != 0)) {
+ Connection->NewNetbios = TRUE;
+ Connection->LocalRcvSequenceMax = 4; // may get modified after ripping based on card
+ Connection->RemoteRcvSequenceMax = Sess->ReceiveSequenceMax;
+ Connection->SendWindowSequenceLimit = 2;
+ if (Connection->RemoteRcvSequenceMax == 0) {
+ Connection->RemoteRcvSequenceMax = 1;
+ }
+ } else {
+ Connection->NewNetbios = FALSE;
+ }
+
+ //
+ // Save this information now for whenever we complete the listen.
+ //
+
+ RemoteInformation = ListenParameters->ReturnConnectionInformation;
+
+ if (RemoteInformation != NULL) {
+
+ RtlCopyMemory(
+ (PTA_NETBIOS_ADDRESS)RemoteInformation->RemoteAddress,
+ &SourceName,
+ (RemoteInformation->RemoteAddressLength < sizeof(TA_NETBIOS_ADDRESS)) ?
+ RemoteInformation->RemoteAddressLength : sizeof(TA_NETBIOS_ADDRESS));
+ }
+
+
+ if (ListenParameters->RequestFlags & TDI_QUERY_ACCEPT) {
+
+ //
+ // We have to wait for an accept before sending the
+ // session init ack, so we complete the listen and wait.
+ //
+
+ ListenRequest = Request;
+ Connection->ListenRequest = NULL;
+
+ NB_DEBUG2 (CONNECTION, ("Queued listen on %lx awaiting accept\n", Connection));
+
+ Connection->SubState = CONNECTION_SUBSTATE_L_W_ACCEPT;
+
+ NbiTransferReferenceConnection (Connection, CREF_LISTEN, CREF_W_ACCEPT);
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+ } else {
+
+ //
+ // We are ready to go, so we send out the find route request
+ // for the remote. We keep the listen alive and the CREF_LISTEN
+ // reference on until this completes.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Activating queued listen on %lx\n", Connection));
+
+ ListenRequest = NULL;
+
+ Connection->SubState = CONNECTION_SUBSTATE_L_W_ROUTE;
+
+ NbiReferenceConnectionLock (Connection, CREF_FIND_ROUTE);
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network =
+ *(UNALIGNED ULONG *)Conn->IpxHeader.SourceNetwork;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,Conn->IpxHeader.SourceNode,6);
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_NO_RIP;
+
+ //
+ // When this completes, we will send the session init
+ // ack. We don't call it if the client is for network 0,
+ // instead just fake as if no route could be found
+ // and we will use the local target we got here.
+ //
+
+ if (*(UNALIGNED ULONG *)Conn->IpxHeader.SourceNetwork != 0) {
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ } else {
+
+ NbiFindRouteComplete(
+ &Connection->FindRouteRequest,
+ FALSE);
+
+ }
+
+ }
+
+ //
+ // Complete the listen if needed.
+ //
+
+ if (ListenRequest != NULL) {
+
+ REQUEST_INFORMATION (ListenRequest) = 0;
+ REQUEST_STATUS (ListenRequest) = STATUS_SUCCESS;
+
+ NB_GET_CANCEL_LOCK ( &CancelLH );
+ IoSetCancelRoutine (ListenRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ NbiCompleteRequest (ListenRequest);
+ NbiFreeRequest (Device, ListenRequest);
+
+ }
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ return;
+
+ }
+
+ //
+ // We could not find a listen, so we indicate to every
+ // client. Make sure there is no session initialize for this
+ // remote being indicated. If there is not, we insert
+ // ourselves in the queue to block others.
+ //
+ // NOTE: The device lock is held here.
+ //
+
+ for (p = Device->ConnectIndicationInProgress.Flink;
+ p != &Device->ConnectIndicationInProgress;
+ p = p->Flink) {
+
+ ConnInd = CONTAINING_RECORD (p, CONNECT_INDICATION, Linkage);
+
+ if ((RtlEqualMemory(ConnInd->NetbiosName, SessInit->DestinationName, 16)) &&
+ (RtlEqualMemory(&ConnInd->RemoteAddress, Conn->IpxHeader.SourceNetwork, 12)) &&
+ (ConnInd->ConnectionId == Sess->SourceConnectionId)) {
+
+ //
+ // We are processing a request from this remote for
+ // the same ID, to avoid confusion we just exit.
+ //
+
+#if DBG
+ DbgPrint ("NBI: Already processing connect to <%.16s>\n", SessInit->DestinationName);
+#endif
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+ NbiDereferenceAddress (Address, AREF_FIND);
+ return;
+ }
+
+ }
+
+ RtlCopyMemory (&TempConnInd.RemoteAddress, SessInit->DestinationName, 16);
+ RtlCopyMemory (&TempConnInd.RemoteAddress, Conn->IpxHeader.SourceNetwork, 12);
+ TempConnInd.ConnectionId = Sess->SourceConnectionId;
+
+ InsertTailList (&Device->ConnectIndicationInProgress, &TempConnInd.Linkage);
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+
+ //
+ // Now scan through the address to find someone who has
+ // an indication routine registed and wants this connection.
+ //
+
+
+ ReferencedAddressFile = NULL;
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle1);
+
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+
+ //
+ // Find the next open address file in the list.
+ //
+
+ AddressFile = CONTAINING_RECORD (p, ADDRESS_FILE, Linkage);
+ if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
+ continue;
+ }
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_INDICATION);
+
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle1);
+
+ if (ReferencedAddressFile != NULL) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION);
+ }
+ ReferencedAddressFile = AddressFile;
+
+ //
+ // No posted listen requests; is there a kernel client?
+ //
+
+ if (AddressFile->RegisteredHandler[TDI_EVENT_CONNECT]) {
+
+ if ((*AddressFile->ConnectionHandler)(
+ AddressFile->HandlerContexts[TDI_EVENT_CONNECT],
+ sizeof (TA_NETBIOS_ADDRESS),
+ &SourceName,
+ 0, // user data
+ NULL,
+ 0, // options
+ NULL,
+ &ConnectionContext,
+ &AcceptIrp) != STATUS_MORE_PROCESSING_REQUIRED) {
+
+ //
+ // The client did not return a request, go to the
+ // next address file.
+ //
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle1);
+ continue;
+
+ }
+
+ AcceptRequest = NbiAllocateRequest (Device, AcceptIrp);
+
+ IF_NOT_ALLOCATED(AcceptRequest) {
+
+ AcceptStatus = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+ //
+ // The client accepted the connect, so activate
+ // the connection and complete the accept.
+ // listen. This lookup references the connection
+ // so we know it will remain valid.
+ //
+
+ Connection = NbiLookupConnectionByContext (
+ AddressFile,
+ ConnectionContext);
+
+ if (Connection != NULL) {
+
+ ASSERT (Connection->AddressFile == AddressFile);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle2);
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle3);
+
+ if ((Connection->State == CONNECTION_STATE_INACTIVE) &&
+ (Connection->DisassociatePending == NULL) &&
+ (Connection->ClosePending == NULL)) {
+
+ NB_DEBUG2 (CONNECTION, ("Indication on %lx returned connection %lx\n", AddressFile, Connection));
+
+ Connection->State = CONNECTION_STATE_LISTENING;
+ Connection->SubState = CONNECTION_SUBSTATE_L_W_ROUTE;
+
+ Connection->Retries = Device->KeepAliveCount;
+
+ RtlCopyMemory(&Connection->RemoteHeader.DestinationNetwork, Conn->IpxHeader.SourceNetwork, 12);
+ RtlCopyMemory (Connection->RemoteName, SessInit->SourceName, 16);
+ Connection->LocalTarget = *RemoteAddress;
+
+ Connection->SessionInitAckDataLength =
+ PacketSize - (sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT));
+ if (Connection->SessionInitAckDataLength > 0) {
+ Connection->SessionInitAckData = NbiAllocateMemory(
+ Connection->SessionInitAckDataLength, MEMORY_CONNECTION, "SessionInitAckData");
+ RtlCopyMemory(
+ Connection->SessionInitAckData,
+ (PUCHAR)(SessInit+1),
+ Connection->SessionInitAckDataLength);
+ }
+
+ Connection->MaximumPacketSize = SessInit->MaximumDataSize;
+
+ (VOID)NbiAssignConnectionId (Device, Connection); // BUGBUG: Check return code.
+ Connection->RemoteConnectionId = Sess->SourceConnectionId;
+
+ Connection->CurrentSend.SendSequence = 0;
+ Connection->UnAckedSend.SendSequence = 0;
+ Connection->RetransmitThisWindow = FALSE;
+ Connection->ReceiveSequence = 1;
+ Connection->CurrentReceive.MessageOffset = 0;
+ Connection->Retries = Device->KeepAliveCount;
+ if (Device->Extensions && ((Sess->ConnectionControlFlag & NB_CONTROL_NEW_NB) != 0)) {
+ Connection->NewNetbios = TRUE;
+ Connection->LocalRcvSequenceMax = 4; // may get modified after ripping based on card
+ Connection->RemoteRcvSequenceMax = Sess->ReceiveSequenceMax;
+ Connection->SendWindowSequenceLimit = 2;
+ if (Connection->RemoteRcvSequenceMax == 0) {
+ Connection->RemoteRcvSequenceMax = 1;
+ }
+ } else {
+ Connection->NewNetbios = FALSE;
+ }
+
+ NbiReferenceConnectionLock (Connection, CREF_ACCEPT);
+ NbiReferenceConnectionLock (Connection, CREF_FIND_ROUTE);
+
+ Connection->AcceptRequest = AcceptRequest;
+ AcceptStatus = STATUS_PENDING;
+
+ //
+ // Take us out of this list now, we will jump to
+ // FoundConnection which is past the removal below.
+ //
+
+ RemoveEntryList (&TempConnInd.Linkage);
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle2);
+
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network =
+ *(UNALIGNED ULONG *)Conn->IpxHeader.SourceNetwork;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,Conn->IpxHeader.SourceNode,6);
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_NO_RIP;
+
+ //
+ // When this completes, we will send the session init
+ // ack. We don't call it if the client is for network 0,
+ // instead just fake as if no route could be found
+ // and we will use the local target we got here.
+ // The accept is completed when this completes.
+ //
+
+ if (*(UNALIGNED ULONG *)Conn->IpxHeader.SourceNetwork != 0) {
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ } else {
+
+ NbiFindRouteComplete(
+ &Connection->FindRouteRequest,
+ FALSE);
+
+ }
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Indication on %lx returned invalid connection %lx\n", AddressFile, Connection));
+ AcceptStatus = STATUS_INVALID_CONNECTION;
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle2);
+
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_BY_CONTEXT);
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Indication on %lx returned unknown connection %lx\n", AddressFile, Connection));
+ AcceptStatus = STATUS_INVALID_CONNECTION;
+
+ }
+ }
+
+ //
+ // Complete the accept request in the failure case.
+ //
+
+ if (AcceptStatus != STATUS_PENDING) {
+
+ REQUEST_STATUS (AcceptRequest) = AcceptStatus;
+
+ NbiCompleteRequest (AcceptRequest);
+ NbiFreeRequest (Device, AcceptRequest);
+
+ } else {
+
+ //
+ // We found a connection, so we break; this is
+ // a jump since the while exit assumes the
+ // address lock is held.
+ //
+
+ goto FoundConnection;
+
+ }
+
+ }
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle1);
+
+ } // end of for loop through the address files
+
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle1);
+
+
+ //
+ // Take us out of the list that blocks other indications
+ // from this remote to this address.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle3);
+ RemoveEntryList (&TempConnInd.Linkage);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+FoundConnection:
+
+ if (ReferencedAddressFile != NULL) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION);
+ }
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+} /* NbiProcessSessionInitialize */
+
+
+VOID
+NbiProcessSessionInitAck(
+ IN PCONNECTION Connection,
+ IN NB_SESSION UNALIGNED * Sess
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles session init ack frames.
+
+ THIS ROUTINE IS CALLED WITH THE CONNECTION LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection.
+
+ Sess - The netbios header for the received frame.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST Request;
+ NB_SESSION_INIT UNALIGNED * SessInit = (NB_SESSION_INIT UNALIGNED *)(Sess+1);
+ BOOLEAN TimerWasStopped = FALSE;
+ CTELockHandle CancelLH;
+
+ if ((Sess->ConnectionControlFlag & NB_CONTROL_SYSTEM) &&
+ (Sess->SendSequence == 0x0000) &&
+ (Sess->ReceiveSequence == 0x0001)) {
+
+ NB_DEBUG2 (CONNECTION, ("Completing connect on %lx\n", Connection));
+
+ if (CTEStopTimer (&Connection->Timer)) {
+ TimerWasStopped = TRUE;
+ }
+
+ Connection->State = CONNECTION_STATE_ACTIVE;
+ Connection->SubState = CONNECTION_SUBSTATE_A_IDLE;
+ Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
+
+ if (Connection->Retries == NbiDevice->ConnectionCount) {
+ ++NbiDevice->Statistics.ConnectionsAfterNoRetry;
+ } else {
+ ++NbiDevice->Statistics.ConnectionsAfterRetry;
+ }
+ ++NbiDevice->Statistics.OpenConnections;
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ NbiStartWatchdog (Connection);
+
+ Connection->RemoteConnectionId = Sess->SourceConnectionId;
+
+ Connection->CurrentSend.SendSequence = 1;
+ Connection->UnAckedSend.SendSequence = 1;
+ Connection->RetransmitThisWindow = FALSE;
+ Connection->ReceiveSequence = 0;
+ Connection->CurrentReceive.MessageOffset = 0;
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ if (NbiDevice->Extensions && ((Sess->ConnectionControlFlag & NB_CONTROL_NEW_NB) != 0)) {
+ Connection->NewNetbios = TRUE;
+ Connection->LocalRcvSequenceMax =
+ (USHORT)(Connection->ReceiveWindowSize - 1);
+ Connection->RemoteRcvSequenceMax = Sess->ReceiveSequenceMax;
+ Connection->SendWindowSequenceLimit = 3;
+ } else {
+ Connection->NewNetbios = FALSE;
+ }
+
+ if (Connection->MaximumPacketSize > SessInit->MaximumDataSize) {
+ Connection->MaximumPacketSize = SessInit->MaximumDataSize;
+ }
+
+ Request = Connection->ConnectRequest;
+
+#ifdef RASAUTODIAL
+ //
+ // Check to see if we have to notify
+ // the automatic connection driver about
+ // this connection.
+ //
+ if (fAcdLoadedG) {
+ BOOLEAN fEnabled;
+ CTELockHandle AcdHandle;
+
+ CTEGetLock(&AcdDriverG.SpinLock, &AcdHandle);
+ fEnabled = AcdDriverG.fEnabled;
+ CTEFreeLock(&AcdDriverG.SpinLock, AcdHandle);
+ if (fEnabled)
+ NbiNoteNewConnection(Connection);
+ }
+#endif // RASAUTODIAL
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ REQUEST_STATUS (Request) = STATUS_SUCCESS;
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+
+ NbiTransferReferenceConnection (Connection, CREF_CONNECT, CREF_ACTIVE);
+
+ if (TimerWasStopped) {
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+} /* NbiProcessSessionInitAck */
+
+
+VOID
+NbiProcessSessionEnd(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_SESSION_END frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)PacketBuffer;
+ NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
+ PCONNECTION Connection;
+ PDEVICE Device = NbiDevice;
+ ULONG Hash;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+ NB_DEFINE_LOCK_HANDLE (LockHandle2)
+
+ //
+ // This is an active connection, find it using
+ // our session id (BUGBUG: Make this a function).
+ //
+
+ Hash = (Sess->DestConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ Connection = Device->ConnectionHash[Hash].Connections;
+
+ while (Connection != NULL) {
+
+ if (Connection->LocalConnectionId == Sess->DestConnectionId) {
+ break;
+ }
+ Connection = Connection->NextConnection;
+ }
+
+
+ //
+ // We reply to any session end, even if we don't know the
+ // connection, to speed up the disconnect on the remote.
+ //
+
+ if (Connection == NULL) {
+
+ NB_DEBUG (CONNECTION, ("Session end received on unknown id %lx\n", Sess->DestConnectionId));
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ NbiSendSessionEndAck(
+ (TDI_ADDRESS_IPX UNALIGNED *)(Conn->IpxHeader.SourceNetwork),
+ RemoteAddress,
+ Sess);
+ return;
+ }
+
+ NbiReferenceConnectionLock (Connection, CREF_INDICATE);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK) {
+
+ //
+ // We are waiting for an ack, so see if this acks
+ // anything. We do this in case a full send has been
+ // received by the remote but he did not send an
+ // ack before the session went down -- this will
+ // prevent us from failing a send which actually
+ // succeeded. If we are not in W_ACK this may ack
+ // part of a send, but in that case we don't care
+ // since StopConnection will abort it anyway and
+ // the amount successfully received by the remote
+ // doesn't matter.
+ //
+ // This releases the lock. BUGBUG: Fix this.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Session end at W_ACK, reframing %lx (%d)\n", Connection, Sess->ReceiveSequence));
+
+ NbiReframeConnection(
+ Connection,
+ Sess->ReceiveSequence,
+ Sess->BytesReceived,
+ FALSE
+ NB_LOCK_HANDLE_ARG(LockHandle1));
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Session end received on connection %lx\n", Connection));
+
+ }
+
+ //
+ // This call sets the state to DISCONNECT and
+ // releases the connection lock. It will also
+ // complete a disconnect wait request if one
+ // is pending, and indicate to our client
+ // if needed.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_REMOTE_DISCONNECT
+ NB_LOCK_HANDLE_ARG (LockHandle1));
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Session end received on inactive connection %lx\n", Connection));
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ }
+
+ NbiSendSessionEndAck(
+ (TDI_ADDRESS_IPX UNALIGNED *)(Conn->IpxHeader.SourceNetwork),
+ RemoteAddress,
+ Sess);
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+
+} /* NbiProcessSessionEnd */
+
+
+VOID
+NbiProcessSessionEndAck(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_SESSION_END_ACK frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)PacketBuffer;
+ NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
+ PCONNECTION Connection;
+ PDEVICE Device = NbiDevice;
+ ULONG Hash;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // This is an active connection, find it using
+ // our session id (BUGBUG: Make this a function).
+ //
+
+ Hash = (Sess->DestConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Connection = Device->ConnectionHash[Hash].Connections;
+
+ while (Connection != NULL) {
+
+ if (Connection->LocalConnectionId == Sess->DestConnectionId) {
+ break;
+ }
+ Connection = Connection->NextConnection;
+ }
+
+ if (Connection == NULL) {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ NbiReferenceConnectionLock (Connection, CREF_INDICATE);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // See what is happening with this connection.
+ //
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_DISCONNECT) {
+
+ //
+ // Stop the timer, when the reference goes away it
+ // will shut down. We set the substate so if the
+ // timer is running it will not restart (BUGBUG:
+ // there is a small window here, but it is not
+ // harmful, we will just have to timeout one
+ // more time).
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Got session end ack on %lx\n", Connection));
+
+ Connection->SubState = CONNECTION_SUBSTATE_D_GOT_ACK;
+ if (CTEStopTimer (&Connection->Timer)) {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+ } else {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+
+} /* NbiProcessSessionEndAck */
+
diff --git a/private/ntos/tdi/isnp/nb/sources.inc b/private/ntos/tdi/isnp/nb/sources.inc
new file mode 100644
index 000000000..f54b4918b
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/sources.inc
@@ -0,0 +1,69 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=nwlnknb
+
+TARGETNAME=nwlnknb
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\tdi.lib \
+ $(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..;..\inc;..\..\inc;..\..\..\..\inc;..\..\..\..\..\inc
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+C_DEFINES=$(C_DEFINES) -D_NTDRIVER_ -D_PNP_POWER=1 -DRASAUTODIAL
+#-DRSRC_TIMEOUT_DBG
+
+!IFDEF BUILD_FOR_3_51
+C_DEFINES= $(C_DEFINES) -D_NTIFS_
+!ENDIF
+
+SOURCES= \
+ ..\action.c \
+ ..\address.c \
+ ..\autodial.c \
+ ..\bind.c \
+ ..\cache.c \
+ ..\config.c \
+ ..\connect.c \
+ ..\datagram.c \
+ ..\device.c \
+ ..\driver.c \
+ ..\event.c \
+ ..\frame.c \
+ ..\nwlnknb.rc \
+ ..\packet.c \
+ ..\query.c \
+ ..\receive.c \
+ ..\send.c \
+ ..\session.c \
+ ..\timer.c
+
+PRECOMPILED_INCLUDE=..\precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
+ \ No newline at end of file
diff --git a/private/ntos/tdi/isnp/nb/timer.c b/private/ntos/tdi/isnp/nb/timer.c
new file mode 100644
index 000000000..381b120e5
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/timer.c
@@ -0,0 +1,1233 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ timer.c
+
+Abstract:
+
+ This module contains code which implements the timers for
+ netbios.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+ULONG NbiTickIncrement = 0;
+ULONG NbiShortTimerDeltaTicks = 0;
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,NbiInitializeTimers)
+#endif
+
+
+VOID
+NbiStartRetransmit(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the retransmit timer for the given connection.
+ The connection is inserted on the short list if it isn't on already.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - pointer to the connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // Insert us in the queue if we aren't in it.
+ //
+
+ Connection->Retransmit =
+ Device->ShortAbsoluteTime + Connection->CurrentRetransmitTimeout;
+
+ if (!Connection->OnShortList) {
+
+ CTEAssert (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ if (!Connection->OnShortList) {
+ Connection->OnShortList = TRUE;
+ InsertTailList (&Device->ShortList, &Connection->ShortList);
+ }
+
+ if (!Device->ShortListActive) {
+ NbiStartShortTimer (Device);
+ Device->ShortListActive = TRUE;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+ }
+
+} /* NbiStartRetransmit */
+
+
+VOID
+NbiStartWatchdog(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the watchdog timer for a connection.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - pointer to the connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+
+ Connection->Watchdog = Device->LongAbsoluteTime + Connection->WatchdogTimeout;
+
+ if (!Connection->OnLongList) {
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ if (!Connection->OnLongList) {
+ Connection->OnLongList = TRUE;
+ InsertTailList (&Device->LongList, &Connection->LongList);
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+ }
+
+} /* NbiStartWatchdog */
+
+#if DBG
+
+VOID
+NbiStopRetransmit(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stops the retransmit timer for a connection.
+
+Arguments:
+
+ Connection - pointer to the connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ Connection->Retransmit = 0;
+
+} /* NbiStopRetransmit */
+
+
+VOID
+NbiStopWatchdog(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stops the watchdog timer for a connection.
+
+Arguments:
+
+ Connection - pointer to the connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ Connection->Watchdog = 0;
+
+} /* NbiStopWatchdog */
+#endif
+
+
+VOID
+NbiExpireRetransmit(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the connection's retransmit timer
+ expires. It is called from NbiShortTimeout.
+
+Arguments:
+
+ Connection - Pointer to the connection whose timer has expired.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ BOOLEAN SendFindRoute;
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ SendFindRoute = FALSE;
+
+ ++Device->Statistics.ResponseTimerExpirations;
+
+ if (!(Connection->NewNetbios) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK)) {
+
+ if (--Connection->Retries == 0) {
+
+ //
+ // Shut down the connection. This will send
+ // out half the usual number of session end
+ // frames.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Wait for ack timeout of active connection %lx\n", Connection));
+
+ //
+ // This free the connection lock.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_LINK_FAILED
+ NB_LOCK_HANDLE_ARG (LockHandle)
+ );
+
+ } else {
+
+ //
+ // Set our current packetize location back to the
+ // spot of the last ack, and start up again.
+ //
+ // BUGBUG: Should we send a probe here?
+ //
+
+ Connection->CurrentSend = Connection->UnAckedSend;
+ Connection->RetransmitThisWindow = TRUE;
+ if (Connection->CurrentRetransmitTimeout < (Connection->BaseRetransmitTimeout*8)) {
+ Connection->CurrentRetransmitTimeout =
+ (Connection->CurrentRetransmitTimeout * 3) / 2;
+ }
+
+ NB_DEBUG2 (SEND, ("Connection %lx retransmit timeout\n", Connection));
+
+ //
+ // After half the retries, send a find route unless we
+ // are already doing one, or the connection is to network
+ // 0. When this completes we update the local target,
+ // for whatever good that does.
+ //
+
+ if ((!Connection->FindRouteInProgress) &&
+ (Connection->Retries == (Device->KeepAliveCount/2)) &&
+ (*(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork != 0)) {
+
+ SendFindRoute = TRUE;
+ Connection->FindRouteInProgress = TRUE;
+ NbiReferenceConnectionSync (Connection, CREF_FIND_ROUTE);
+
+ }
+
+ //
+ // This releases the lock.
+ //
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle)
+ );
+
+ }
+
+ } else if ((Connection->SubState == CONNECTION_SUBSTATE_A_W_PROBE) ||
+ (Connection->SubState == CONNECTION_SUBSTATE_A_REMOTE_W) ||
+ (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK)) {
+
+ if (--Connection->Retries == 0) {
+
+ //
+ // Shut down the connection. This will send
+ // out half the usual number of session end
+ // frames.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Probe timeout of active connection %lx\n", Connection));
+
+ //
+ // This free the connection lock.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_LINK_FAILED
+ NB_LOCK_HANDLE_ARG (LockHandle)
+ );
+
+ } else {
+
+ Connection->RetransmitThisWindow = TRUE;
+ if (Connection->CurrentRetransmitTimeout < (Connection->BaseRetransmitTimeout*8)) {
+ Connection->CurrentRetransmitTimeout =
+ (Connection->CurrentRetransmitTimeout * 3) / 2;
+ }
+
+ NbiStartRetransmit (Connection);
+
+ //
+ // After half the retries, send a find route unless we
+ // are already doing one, or the connection is to network
+ // 0. When this completes we update the local target,
+ // for whatever good that does.
+ //
+
+ if ((!Connection->FindRouteInProgress) &&
+ (Connection->Retries == (Device->KeepAliveCount/2)) &&
+ (*(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork != 0)) {
+
+ SendFindRoute = TRUE;
+ Connection->FindRouteInProgress = TRUE;
+ NbiReferenceConnectionSync (Connection, CREF_FIND_ROUTE);
+
+ }
+
+ //
+ // Set this so we know to retransmit when the ack
+ // is received.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_W_PROBE) {
+ Connection->ResponseTimeout = TRUE;
+ }
+
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckQuery
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ if (SendFindRoute) {
+
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network =
+ *(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,Connection->RemoteHeader.DestinationNode,6);
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_FORCE_RIP;
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+} /* NbiExpireRetansmit */
+
+
+VOID
+NbiExpireWatchdog(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the connection's watchdog timer
+ expires. It is called from NbiLongTimeout.
+
+Arguments:
+
+ Connection - Pointer to the connection whose timer has expired.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ //
+ // If we are not idle, then something else is happening
+ // so the watchdog is unnecessary.
+ //
+
+ if ((Connection->State == CONNECTION_STATE_ACTIVE) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_A_IDLE)) {
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_PROBE;
+ NbiStartRetransmit (Connection);
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckQuery
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+} /* NbiExpireWatchdog */
+
+
+VOID
+NbiShortTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called at regular intervals to see if any of
+ the short connection timers have expired, and if so to execute their
+ expiration routines.
+
+Arguments:
+
+ Event - The event controlling the timer.
+
+ Context - Points to our device.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PLIST_ENTRY p, nextp;
+ PDEVICE Device = (PDEVICE)Context;
+ PCONNECTION Connection;
+ BOOLEAN RestartTimer = FALSE;
+ LARGE_INTEGER CurrentTick;
+ LARGE_INTEGER TickDifference;
+ ULONG TickDelta;
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ //
+ // This prevents anybody from starting the timer while we
+ // are in this routine (the main reason for this is that it
+ // makes it easier to determine whether we should restart
+ // it at the end of this routine).
+ //
+
+ Device->ProcessingShortTimer = TRUE;
+
+ //
+ // Advance the up-counter used to mark time in SHORT_TIMER_DELTA units. If we
+ // advance it all the way to 0xf0000000, then reset it to 0x10000000.
+ // We also run all the lists, decreasing all counters by 0xe0000000.
+ //
+
+
+ KeQueryTickCount (&CurrentTick);
+
+ TickDifference.QuadPart = CurrentTick.QuadPart -
+ Device->ShortTimerStart.QuadPart;
+
+ TickDelta = TickDifference.LowPart / NbiShortTimerDeltaTicks;
+ if (TickDelta == 0) {
+ TickDelta = 1;
+ }
+
+ Device->ShortAbsoluteTime += TickDelta;
+
+ if (Device->ShortAbsoluteTime >= 0xf0000000) {
+
+ ULONG Timeout;
+
+ Device->ShortAbsoluteTime -= 0xe0000000;
+
+ p = Device->ShortList.Flink;
+ while (p != &Device->ShortList) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, ShortList);
+
+ Timeout = Connection->Retransmit;
+ if (Timeout) {
+ Connection->Retransmit = Timeout - 0xe0000000;
+ }
+
+ p = p->Flink;
+ }
+
+ }
+
+ p = Device->ShortList.Flink;
+ while (p != &Device->ShortList) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, ShortList);
+
+ ASSERT (Connection->OnShortList);
+
+ //
+ // To avoid problems with the refcount being 0, don't
+ // do this if we are in ADM.
+ //
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ if (Connection->Retransmit &&
+ (Device->ShortAbsoluteTime > Connection->Retransmit)) {
+
+ Connection->Retransmit = 0;
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+ NbiExpireRetransmit (Connection); // no locks held
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ }
+
+ }
+
+ if (!Connection->OnShortList) {
+
+ //
+ // The link has been taken out of the list while
+ // we were processing it. In this (rare) case we
+ // stop processing the whole list, we'll get it
+ // next time.
+ //
+
+ break;
+
+ }
+
+ nextp = p->Flink;
+
+ if (Connection->Retransmit == 0) {
+
+ Connection->OnShortList = FALSE;
+ RemoveEntryList(p);
+
+ //
+ // Do another check; that way if someone slipped in between
+ // the check of Connection->Tx and the OnShortList = FALSE and
+ // therefore exited without inserting, we'll catch that here.
+ //
+
+ if (Connection->Retransmit != 0) {
+ InsertTailList(&Device->ShortList, &Connection->ShortList);
+ Connection->OnShortList = TRUE;
+ }
+
+ }
+
+ p = nextp;
+
+ }
+
+ //
+ // If the list is empty note that, otherwise ShortListActive
+ // remains TRUE.
+ //
+
+ if (IsListEmpty (&Device->ShortList)) {
+ Device->ShortListActive = FALSE;
+ }
+
+
+ //
+ // Connection Data Ack timers. This queue is used to indicate
+ // that a piggyback ack is pending for this connection. We walk
+ // the queue, for each element we check if the connection has
+ // been on the queue for enough times through here,
+ // If so, we take it off and send an ack. Note that
+ // we have to be very careful how we walk the queue, since
+ // it may be changing while this is running.
+ //
+
+ for (p = Device->DataAckConnections.Flink;
+ p != &Device->DataAckConnections;
+ p = p->Flink) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, DataAckLinkage);
+
+ //
+ // Skip this connection if it is not queued or it is
+ // too recent to matter. We may skip incorrectly if
+ // the connection is just being queued, but that is
+ // OK, we will get it next time.
+ //
+
+ if (!Connection->DataAckPending) {
+ continue;
+ }
+
+ ++Connection->DataAckTimeouts;
+
+ if (Connection->DataAckTimeouts < Device->AckDelayTime) {
+ continue;
+ }
+
+ NbiReferenceConnectionSync (Connection, CREF_SHORT_D_ACK);
+
+ Device->DataAckQueueChanged = FALSE;
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+ //
+ // Check the correct connection flag, to ensure that a
+ // send has not just taken him off the queue.
+ //
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->DataAckPending) {
+
+ //
+ // Yes, we were waiting to piggyback an ack, but no send
+ // has come along. Turn off the flags and send an ack.
+ // We set PiggybackAckTimeout to TRUE so that we won't try
+ // to piggyback a response until we get back traffic.
+ //
+
+ Connection->DataAckPending = FALSE;
+ Connection->PiggybackAckTimeout = TRUE;
+ ++Device->Statistics.AckTimerExpirations;
+ ++Device->Statistics.PiggybackAckTimeouts;
+
+ //
+ // This call releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_SHORT_D_ACK);
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ //
+ // If the list has changed, then we need to stop processing
+ // since p->Flink is not valid.
+ //
+
+ if (Device->DataAckQueueChanged) {
+ break;
+ }
+
+ }
+
+ if (IsListEmpty (&Device->DataAckConnections)) {
+ Device->DataAckActive = FALSE;
+ }
+
+
+ //
+ // Update the real counters from the temp ones. We have
+ // TimerLock here, which is good enough.
+ //
+
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesSent,
+ Device->TempFrameBytesSent);
+ Device->Statistics.DataFramesSent += Device->TempFramesSent;
+
+ Device->TempFrameBytesSent = 0;
+ Device->TempFramesSent = 0;
+
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesReceived,
+ Device->TempFrameBytesReceived);
+ Device->Statistics.DataFramesReceived += Device->TempFramesReceived;
+
+ Device->TempFrameBytesReceived = 0;
+ Device->TempFramesReceived = 0;
+
+
+ //
+ // Determine if we have to restart the timer.
+ //
+
+ Device->ProcessingShortTimer = FALSE;
+
+ if ((Device->ShortListActive || Device->DataAckActive) &&
+ (Device->State != DEVICE_STATE_STOPPING)) {
+
+ RestartTimer = TRUE;
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+ if (RestartTimer) {
+
+ //
+ // Start up the timer again. Note that because we start the timer
+ // after doing work (above), the timer values will slip somewhat,
+ // depending on the load on the protocol. This is entirely acceptable
+ // and will prevent us from using the timer DPC in two different
+ // threads of execution.
+ //
+
+ KeQueryTickCount(&Device->ShortTimerStart);
+
+ CTEStartTimer(
+ &Device->ShortTimer,
+ SHORT_TIMER_DELTA,
+ NbiShortTimeout,
+ (PVOID)Device);
+
+ } else {
+
+ NbiDereferenceDevice (Device, DREF_SHORT_TIMER);
+
+ }
+
+} /* NbiShortTimeout */
+
+
+VOID
+NbiLongTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called at regular intervals to see if any of
+ the long connection timers have expired, and if so to execute their
+ expiration routines.
+
+Arguments:
+
+ Event - The event controlling the timer.
+
+ Context - Points to our device.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)Context;
+ PLIST_ENTRY p, nextp;
+ LIST_ENTRY AdapterStatusList;
+ PREQUEST AdapterStatusRequest;
+ PCONNECTION Connection;
+ PNETBIOS_CACHE CacheName;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+
+
+ //
+ // Advance the up-counter used to mark time in LONG_TIMER_DELTA units. If we
+ // advance it all the way to 0xf0000000, then reset it to 0x10000000.
+ // We also run all the lists, decreasing all counters by 0xe0000000.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ if (++Device->LongAbsoluteTime == 0xf0000000) {
+
+ ULONG Timeout;
+
+ Device->LongAbsoluteTime = 0x10000000;
+
+ p = Device->LongList.Flink;
+ while (p != &Device->LongList) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, LongList);
+
+ Timeout = Connection->Watchdog;
+ if (Timeout) {
+ Connection->Watchdog = Timeout - 0xe0000000;
+ }
+
+ p = p->Flink;
+ }
+
+ }
+
+
+ if ((Device->LongAbsoluteTime % 4) == 0) {
+
+ p = Device->LongList.Flink;
+ while (p != &Device->LongList) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, LongList);
+
+ ASSERT (Connection->OnLongList);
+
+ //
+ // To avoid problems with the refcount being 0, don't
+ // do this if we are in ADM.
+ //
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ if (Connection->Watchdog && (Device->LongAbsoluteTime > Connection->Watchdog)) {
+
+ Connection->Watchdog = 0;
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+ NbiExpireWatchdog (Connection); // no spinlocks held
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ }
+
+ }
+
+ if (!Connection->OnLongList) {
+
+ //
+ // The link has been taken out of the list while
+ // we were processing it. In this (rare) case we
+ // stop processing the whole list, we'll get it
+ // next time.
+ //
+
+#if DBG
+ DbgPrint ("NBI: Stop processing LongList, %lx removed\n", Connection);
+#endif
+ break;
+
+ }
+
+ nextp = p->Flink;
+
+ if (Connection->Watchdog == 0) {
+
+ Connection->OnLongList = FALSE;
+ RemoveEntryList(p);
+
+ if (Connection->Watchdog != 0) {
+ InsertTailList(&Device->LongList, &Connection->LongList);
+ Connection->OnLongList = TRUE;
+ }
+
+ }
+
+ p = nextp;
+
+ }
+
+ }
+
+
+ //
+ // Now scan the data ack queue, looking for connections with
+ // no acks queued that we can get rid of.
+ //
+ // Note: The timer spinlock is held here.
+ //
+
+ for (p = Device->DataAckConnections.Flink;
+ p != &Device->DataAckConnections;
+ p = p->Flink) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, DataAckLinkage);
+
+ if (Connection->DataAckPending) {
+ continue;
+ }
+
+ NbiReferenceConnectionSync (Connection, CREF_LONG_D_ACK);
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ //
+ // Have to check again, because the connection might
+ // just have been stopped, and it also might just have
+ // had a data ack queued.
+ //
+
+ if (Connection->OnDataAckQueue) {
+
+ Connection->OnDataAckQueue = FALSE;
+
+ RemoveEntryList (&Connection->DataAckLinkage);
+
+ if (Connection->DataAckPending) {
+ InsertTailList (&Device->DataAckConnections, &Connection->DataAckLinkage);
+ Connection->OnDataAckQueue = TRUE;
+ }
+
+ Device->DataAckQueueChanged = TRUE;
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ NbiDereferenceConnection (Connection, CREF_LONG_D_ACK);
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ //
+ // Since we have changed the list, we can't tell if p->Flink
+ // is valid, so break. The effect is that we gradually peel
+ // connections off the queue.
+ //
+
+ break;
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+
+ //
+ // Scan for any uncompleted receive IRPs, this may happen if
+ // the cable is pulled and we don't get any more ReceiveComplete
+ // indications.
+
+ NbiReceiveComplete((USHORT)0);
+
+
+ //
+ // Check if any adapter status queries are getting old.
+ //
+
+ InitializeListHead (&AdapterStatusList);
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ p = Device->ActiveAdapterStatus.Flink;
+
+ while (p != &Device->ActiveAdapterStatus) {
+
+ AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ p = p->Flink;
+
+ if (REQUEST_INFORMATION(AdapterStatusRequest) == 1) {
+
+ //
+ // BUGBUG: We should resend a certain number of times.
+ //
+
+ RemoveEntryList (REQUEST_LINKAGE(AdapterStatusRequest));
+ InsertTailList (&AdapterStatusList, REQUEST_LINKAGE(AdapterStatusRequest));
+
+ //
+ // We are going to abort this request, so dereference
+ // the cache entry it used.
+ //
+
+ CacheName = (PNETBIOS_CACHE)REQUEST_STATUS(AdapterStatusRequest);
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free delete name cache entry %lx\n", CacheName));
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Name deleted");
+
+ }
+
+ } else {
+
+ ++REQUEST_INFORMATION(AdapterStatusRequest);
+
+ }
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+
+ for (p = AdapterStatusList.Flink; p != &AdapterStatusList; ) {
+
+ AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ NB_DEBUG2 (QUERY, ("AdapterStatus %lx got name but no response\n", AdapterStatusRequest));
+
+ REQUEST_INFORMATION(AdapterStatusRequest) = 0;
+ REQUEST_STATUS(AdapterStatusRequest) = STATUS_IO_TIMEOUT;
+
+ NbiCompleteRequest(AdapterStatusRequest);
+ NbiFreeRequest (Device, AdapterStatusRequest);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_QUERY);
+
+ }
+
+ //
+ // See if a minute has passed and we need to check for empty
+ // cache entries to age out. We check for 64 seconds to make
+ // the mod operation faster.
+ //
+
+#if defined(_PNP_POWER)
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+#endif _PNP_POWER
+
+ ++Device->CacheTimeStamp;
+
+ if ((Device->CacheTimeStamp % 64) == 0) {
+
+
+ //
+ // flush all the entries which have been around for ten minutes
+ // (LONG_TIMER_DELTA is in milliseconds).
+ //
+
+ FlushOldFromNetbiosCacheTable( Device->NameCache, (600000 / LONG_TIMER_DELTA) );
+
+ }
+
+
+ //
+ // Start up the timer again. Note that because we start the timer
+ // after doing work (above), the timer values will slip somewhat,
+ // depending on the load on the protocol. This is entirely acceptable
+ // and will prevent us from using the timer DPC in two different
+ // threads of execution.
+ //
+
+ if (Device->State != DEVICE_STATE_STOPPING) {
+
+ CTEStartTimer(
+ &Device->LongTimer,
+ LONG_TIMER_DELTA,
+ NbiLongTimeout,
+ (PVOID)Device);
+
+ } else {
+#if defined(_PNP_POWER)
+ Device->LongTimerRunning = FALSE;
+#endif _PNP_POWER
+ NbiDereferenceDevice (Device, DREF_LONG_TIMER);
+ }
+
+#if defined(_PNP_POWER)
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+#endif _PNP_POWER
+} /* NbiLongTimeout */
+
+
+VOID
+NbiStartShortTimer(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the short timer, if it is not already running.
+
+Arguments:
+
+ Device - Pointer to our device context.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ //
+ // Start the timer unless it the DPC is already running (in
+ // which case it will restart the timer itself if needed),
+ // or some list is active (meaning the timer is already
+ // queued up).
+ //
+
+ if ((!Device->ProcessingShortTimer) &&
+ (!(Device->ShortListActive)) &&
+ (!(Device->DataAckActive))) {
+
+ NbiReferenceDevice (Device, DREF_SHORT_TIMER);
+
+ KeQueryTickCount(&Device->ShortTimerStart);
+
+ CTEStartTimer(
+ &Device->ShortTimer,
+ SHORT_TIMER_DELTA,
+ NbiShortTimeout,
+ (PVOID)Device);
+
+ }
+
+} /* NbiStartShortTimer */
+
+
+VOID
+NbiInitializeTimers(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the lightweight timer system for the transport
+ provider.
+
+Arguments:
+
+ Device - Pointer to our device.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ //
+ // NbiTickIncrement is the number of NT time increments
+ // which pass between each tick. NbiShortTimerDeltaTicks
+ // is the number of ticks which should happen in
+ // SHORT_TIMER_DELTA milliseconds (i.e. between each
+ // expiration of the short timer).
+ //
+
+ NbiTickIncrement = KeQueryTimeIncrement();
+
+ if (NbiTickIncrement > (SHORT_TIMER_DELTA * MILLISECONDS)) {
+ NbiShortTimerDeltaTicks = 1;
+ } else {
+ NbiShortTimerDeltaTicks = (SHORT_TIMER_DELTA * MILLISECONDS) / NbiTickIncrement;
+ }
+
+ //
+ // The AbsoluteTime cycles between 0x10000000 and 0xf0000000.
+ //
+
+ Device->ShortAbsoluteTime = 0x10000000;
+ Device->LongAbsoluteTime = 0x10000000;
+
+ CTEInitTimer (&Device->ShortTimer);
+ CTEInitTimer (&Device->LongTimer);
+
+#if !defined(_PNP_POWER)
+ //
+ // One reference for the long timer.
+ //
+
+ NbiReferenceDevice (Device, DREF_LONG_TIMER);
+
+ CTEStartTimer(
+ &Device->LongTimer,
+ LONG_TIMER_DELTA,
+ NbiLongTimeout,
+ (PVOID)Device);
+
+#endif !_PNP_POWER
+
+ Device->TimersInitialized = TRUE;
+ Device->ShortListActive = FALSE;
+ Device->ProcessingShortTimer = FALSE;
+
+ InitializeListHead (&Device->ShortList);
+ InitializeListHead (&Device->LongList);
+
+ CTEInitLock (&Device->TimerLock.Lock);
+
+} /* NbiInitializeTimers */
+
diff --git a/private/ntos/tdi/isnp/nb/up/makefile b/private/ntos/tdi/isnp/nb/up/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/up/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isnp/nb/up/sources b/private/ntos/tdi/isnp/nb/up/sources
new file mode 100644
index 000000000..85cdb3764
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/up/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+UP_DRIVER=yes
+
+TARGETPATH=obj
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/isnp/spx/dirs b/private/ntos/tdi/isnp/spx/dirs
new file mode 100644
index 000000000..0dab2f056
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/dirs
@@ -0,0 +1,22 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=up mp
diff --git a/private/ntos/tdi/isnp/spx/globals.c b/private/ntos/tdi/isnp/spx/globals.c
new file mode 100644
index 000000000..51fc80803
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/globals.c
@@ -0,0 +1,87 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ globals.c
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Global values
+PDEVICE SpxDevice = NULL;
+UNICODE_STRING IpxDeviceName = {0};
+HANDLE IpxHandle = NULL;
+
+LARGE_INTEGER Magic100000 = {
+ 0x1b478424,
+ 0xa7c5ac47
+ };
+// Line info
+IPX_LINE_INFO IpxLineInfo = {0};
+USHORT IpxMacHdrNeeded = 0;
+USHORT IpxInclHdrOffset= 0;
+
+// Entry Points into the IPX stack
+IPX_INTERNAL_SEND IpxSendPacket = NULL;
+IPX_INTERNAL_FIND_ROUTE IpxFindRoute = NULL;
+IPX_INTERNAL_QUERY IpxQuery = NULL;
+IPX_INTERNAL_TRANSFER_DATA IpxTransferData = NULL;
+
+#if DBG
+ULONG SpxDebugDump = 0;
+LONG SpxDumpInterval = DBG_DUMP_DEF_INTERVAL;
+ULONG SpxDebugLevel = DBG_LEVEL_ERR;
+ULONG SpxDebugSystems = DBG_COMP_MOST;
+#endif
+
+// Unload event triggered when ref count on device goes to zero.
+KEVENT SpxUnloadEvent = {0};
+
+// Maximum packet size quanta used during packet size negotiation
+ULONG SpxMaxPktSize[] = {
+ 576 - MIN_IPXSPX2_HDRSIZE,
+ 1024 - MIN_IPXSPX2_HDRSIZE,
+ 1474 - MIN_IPXSPX2_HDRSIZE,
+ 1492 - MIN_IPXSPX2_HDRSIZE,
+ 1500 - MIN_IPXSPX2_HDRSIZE,
+ 1954 - MIN_IPXSPX2_HDRSIZE,
+ 4002 - MIN_IPXSPX2_HDRSIZE,
+ 8192 - MIN_IPXSPX2_HDRSIZE,
+ 17314 - MIN_IPXSPX2_HDRSIZE,
+ 65535 - MIN_IPXSPX2_HDRSIZE
+ };
+
+ULONG SpxMaxPktSizeIndex = sizeof(SpxMaxPktSize)/sizeof(ULONG);
+
+
+// Global interlock
+CTELock SpxGlobalInterlock = {0};
+
+// Another one, used only for global queues for addr/conn
+CTELock SpxGlobalQInterlock = {0};
+PSPX_CONN_FILE SpxGlobalConnList = NULL;
+PSPX_ADDR_FILE SpxGlobalAddrList = NULL;
+
+SPX_CONNFILE_LIST SpxPktConnList = {NULL, NULL};
+SPX_CONNFILE_LIST SpxRecvConnList = {NULL, NULL};
+
+// Timer globals
+LONG SpxTimerCurrentTime = 0;
diff --git a/private/ntos/tdi/isnp/spx/h/fwddecls.h b/private/ntos/tdi/isnp/spx/h/fwddecls.h
new file mode 100644
index 000000000..feda4e76b
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/h/fwddecls.h
@@ -0,0 +1,28 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ fwddecls.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+struct _SPX_ADDR ;
+struct _SPX_ADDR_FILE ;
+struct _SPX_CONN_FILE ;
+struct _SPX_SEND_RESD ;
diff --git a/private/ntos/tdi/isnp/spx/h/globals.h b/private/ntos/tdi/isnp/spx/h/globals.h
new file mode 100644
index 000000000..e4fcf39a8
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/h/globals.h
@@ -0,0 +1,67 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ globals.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+extern PDEVICE SpxDevice;
+extern UNICODE_STRING IpxDeviceName;
+extern HANDLE IpxHandle;
+
+extern LARGE_INTEGER Magic100000;
+
+#if 1 // DBG
+extern ULONG SpxDebugDump;
+extern LONG SpxDumpInterval;
+extern ULONG SpxDebugLevel;
+extern ULONG SpxDebugSystems;
+
+#endif
+
+// More IPX info.
+extern IPX_LINE_INFO IpxLineInfo;
+extern USHORT IpxMacHdrNeeded;
+extern USHORT IpxInclHdrOffset;
+
+// Entry Points into the IPX stack
+extern IPX_INTERNAL_SEND IpxSendPacket;
+extern IPX_INTERNAL_FIND_ROUTE IpxFindRoute;
+extern IPX_INTERNAL_QUERY IpxQuery;
+extern IPX_INTERNAL_TRANSFER_DATA IpxTransferData;
+
+// Unload event
+extern KEVENT SpxUnloadEvent;
+
+extern ULONG SpxMaxPktSize[];
+extern ULONG SpxMaxPktSizeIndex;
+
+extern CTELock SpxGlobalInterlock;
+
+
+extern CTELock SpxGlobalQInterlock;
+extern PSPX_CONN_FILE SpxGlobalConnList;
+extern PSPX_ADDR_FILE SpxGlobalAddrList;
+
+extern SPX_CONNFILE_LIST SpxPktConnList;
+extern SPX_CONNFILE_LIST SpxRecvConnList;
+
+extern LONG SpxTimerCurrentTime;
diff --git a/private/ntos/tdi/isnp/spx/h/isnspx.h b/private/ntos/tdi/isnp/spx/h/isnspx.h
new file mode 100644
index 000000000..6080b0423
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/h/isnspx.h
@@ -0,0 +1,363 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ isnspx.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ SPX module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#define ISN_NT 1
+
+//
+// These are needed for CTE
+//
+
+#if DBG
+#define DEBUG 1
+#endif
+
+#define NT 1
+
+
+#include <ntddk.h>
+#include <tdikrnl.h>
+#include <ndis.h>
+#ifndef CTE_TYPEDEFS_DEFINED
+#include <cxport.h>
+#endif
+#include <bind.h>
+
+#include "wsnwlink.h"
+
+#define SPX_DEVICE_SIGNATURE (USHORT)(*(PUSHORT)"SD")
+#define SPX_ADDRESS_SIGNATURE (USHORT)(*(PUSHORT)"AD")
+#define SPX_ADDRESSFILE_SIGNATURE (USHORT)(*(PUSHORT)"AF")
+#define SPX_CONNFILE_SIGNATURE (USHORT)(*(PUSHORT)"CF")
+
+#define SPX_FILE_TYPE_CONTROL (ULONG)0x4701 // file is type control
+
+#define SPX_ADD_ULONG(_Pulong, _Ulong, _Lock) InterlockedExchangeAdd(_Pulong, _Ulong)
+
+typedef UCHAR BYTE, *PBYTE;
+typedef ULONG DWORD, *PDWORD;
+
+//
+// These definitions are for abstracting IRPs from the
+// transport for portability.
+//
+
+#if ISN_NT
+
+typedef IRP REQUEST, *PREQUEST;
+
+//
+// PREQUEST
+// SpxAllocateRequest(
+// IN PDEVICE Device,
+// IN PIRP Irp
+// );
+//
+// Allocates a request for the system-specific request structure.
+//
+
+#define SpxAllocateRequest(_Device,_Irp) \
+ (_Irp)
+
+//
+// BOOLEAN
+// IF_NOT_ALLOCATED(
+// IN PREQUEST Request
+// );
+//
+// Checks if a request was not successfully allocated.
+//
+
+#define IF_NOT_ALLOCATED(_Request) \
+ if (0)
+
+
+//
+// VOID
+// SpxFreeRequest(
+// IN PDEVICE Device,
+// IN PREQUEST Request
+// );
+//
+// Frees a previously allocated request.
+//
+
+#define SpxFreeRequest(_Device,_Request) \
+ ;
+
+
+//
+// VOID
+// MARK_REQUEST_PENDING(
+// IN PREQUEST Request
+// );
+//
+// Marks that a request will pend.
+//
+
+#define MARK_REQUEST_PENDING(_Request) \
+ IoMarkIrpPending(_Request)
+
+
+//
+// VOID
+// UNMARK_REQUEST_PENDING(
+// IN PREQUEST Request
+// );
+//
+// Marks that a request will not pend.
+//
+
+#define UNMARK_REQUEST_PENDING(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->Control) &= ~SL_PENDING_RETURNED)
+
+
+//
+// UCHAR
+// REQUEST_MAJOR_FUNCTION
+// IN PREQUEST Request
+// );
+//
+// Returns the major function code of a request.
+//
+
+#define REQUEST_MAJOR_FUNCTION(_Request) \
+ ((IoGetCurrentIrpStackLocation(_Request))->MajorFunction)
+
+
+//
+// UCHAR
+// REQUEST_MINOR_FUNCTION
+// IN PREQUEST Request
+// );
+//
+// Returns the minor function code of a request.
+//
+
+#define REQUEST_MINOR_FUNCTION(_Request) \
+ ((IoGetCurrentIrpStackLocation(_Request))->MinorFunction)
+
+
+//
+// PNDIS_BUFFER
+// REQUEST_NDIS_BUFFER
+// IN PREQUEST Request
+// );
+//
+// Returns the NDIS buffer chain associated with a request.
+//
+
+#define REQUEST_NDIS_BUFFER(_Request) \
+ ((PNDIS_BUFFER)((_Request)->MdlAddress))
+
+
+//
+// PVOID
+// REQUEST_TDI_BUFFER
+// IN PREQUEST Request
+// );
+//
+// Returns the TDI buffer chain associated with a request.
+//
+
+#define REQUEST_TDI_BUFFER(_Request) \
+ ((PVOID)((_Request)->MdlAddress))
+
+
+//
+// PVOID
+// REQUEST_OPEN_CONTEXT(
+// IN PREQUEST Request
+// );
+//
+// Gets the context associated with an opened address/connection/control channel.
+//
+
+#define REQUEST_OPEN_CONTEXT(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->FileObject)->FsContext)
+
+
+//
+// PVOID
+// REQUEST_OPEN_TYPE(
+// IN PREQUEST Request
+// );
+//
+// Gets the type associated with an opened address/connection/control channel.
+//
+
+#define REQUEST_OPEN_TYPE(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->FileObject)->FsContext2)
+
+
+//
+// PFILE_FULL_EA_INFORMATION
+// OPEN_REQUEST_EA_INFORMATION(
+// IN PREQUEST Request
+// );
+//
+// Returns the EA information associated with an open/close request.
+//
+
+#define OPEN_REQUEST_EA_INFORMATION(_Request) \
+ ((PFILE_FULL_EA_INFORMATION)((_Request)->AssociatedIrp.SystemBuffer))
+
+
+//
+// PTDI_REQUEST_KERNEL
+// REQUEST_PARAMETERS(
+// IN PREQUEST Request
+// );
+//
+// Obtains a pointer to the parameters of a request.
+//
+
+#define REQUEST_PARAMETERS(_Request) \
+ (&((IoGetCurrentIrpStackLocation(_Request))->Parameters))
+
+
+//
+// PLIST_ENTRY
+// REQUEST_LINKAGE(
+// IN PREQUEST Request
+// );
+//
+// Returns a pointer to a linkage field in the request.
+//
+
+#define REQUEST_LINKAGE(_Request) \
+ (&((_Request)->Tail.Overlay.ListEntry))
+
+
+//
+// PREQUEST
+// LIST_ENTRY_TO_REQUEST(
+// IN PLIST_ENTRY ListEntry
+// );
+//
+// Returns a request given a linkage field in it.
+//
+
+#define LIST_ENTRY_TO_REQUEST(_ListEntry) \
+ ((PREQUEST)(CONTAINING_RECORD(_ListEntry, REQUEST, Tail.Overlay.ListEntry)))
+
+
+//
+// PUNICODE_STRING
+// REQUEST_OPEN_NAME(
+// IN PREQUEST Request
+// );
+//
+// Used to access the RemainingName field of a request.
+//
+
+#define REQUEST_OPEN_NAME(_Request) \
+ (&((IoGetCurrentIrpStackLocation(_Request))->FileObject->FileName))
+
+//
+// NTSTATUS
+// REQUEST_STATUS(
+// IN PREQUEST Request
+// );
+//
+// Used to access the status field of a request.
+//
+
+#define REQUEST_STATUS(_Request) \
+ (_Request)->IoStatus.Status
+
+
+//
+// ULONG
+// REQUEST_INFORMATION(
+// IN PREQUEST Request)
+// );
+//
+// Used to access the information field of a request.
+//
+
+#define REQUEST_INFORMATION(_Request) \
+ (_Request)->IoStatus.Information
+
+
+//
+// VOID
+// SpxCompleteRequest(
+// IN PREQUEST Request
+// );
+//
+// Completes a request whose status and information fields have
+// been filled in.
+//
+
+#define SpxCompleteRequest(_Request) \
+ { \
+ CTELockHandle _CancelIrql; \
+ DBGPRINT(TDI, INFO, \
+ ("SpxCompleteRequest: Completing %lx with %lx\n", \
+ (_Request), REQUEST_STATUS(_Request))); \
+ \
+ IoAcquireCancelSpinLock( &_CancelIrql ); \
+ (_Request)->CancelRoutine = NULL; \
+ IoReleaseCancelSpinLock( _CancelIrql ); \
+ IoCompleteRequest (_Request, IO_NETWORK_INCREMENT); \
+ }
+
+#else
+
+//
+// These routines must be defined for portability to a VxD.
+//
+
+#endif
+
+#include "fwddecls.h"
+
+// BUGBUG: This should go in ntddk.h?
+#ifndef _NTIOAPI_
+#include "spxntdef.h"
+#endif
+
+#include "spxreg.h"
+#include "spxdev.h"
+#include "spxbind.h"
+#include "spxtimer.h"
+#include "spxpkt.h"
+#include "spxerror.h"
+#include "spxaddr.h"
+#include "spxconn.h"
+#include "spxrecv.h"
+#include "spxsend.h"
+#include "spxquery.h"
+#include "spxmem.h"
+#include "spxutils.h"
+
+
+// Globals
+#include "globals.h"
+
+
+
+
diff --git a/private/ntos/tdi/isnp/spx/h/spxaddr.h b/private/ntos/tdi/isnp/spx/h/spxaddr.h
new file mode 100644
index 000000000..b49a4791e
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/h/spxaddr.h
@@ -0,0 +1,426 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxaddr.h
+
+Abstract:
+
+
+Author:
+
+ Adam Barr (adamba ) Original Version
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#define DYNSKT_RANGE_START 0x4000
+#define DYNSKT_RANGE_END 0x7FFF
+#define SOCKET_UNIQUENESS 1
+
+// This structure is pointed to by the FsContext field in the FILE_OBJECT
+// for this Address. This structure is the base for all activities on
+// the open file object within the transport provider. All active connections
+// on the address point to this structure, although no queues exist here to do
+// work from. This structure also maintains a reference to an ADDRESS
+// structure, which describes the address that it is bound to.
+
+#define AFREF_CREATE 0
+#define AFREF_VERIFY 1
+#define AFREF_INDICATION 2
+#define AFREF_CONN_ASSOC 3
+
+#define AFREF_TOTAL 4
+
+typedef struct _SPX_ADDR_FILE {
+
+#if DBG
+ ULONG saf_RefTypes[AFREF_TOTAL];
+#endif
+
+ CSHORT saf_Type;
+ CSHORT saf_Size;
+
+ // number of references to this object.
+ ULONG saf_RefCount;
+
+ // Linkage in address list.
+ struct _SPX_ADDR_FILE * saf_Next;
+ struct _SPX_ADDR_FILE * saf_GlobalNext;
+
+ // List of associated connection/active or otherwise
+ struct _SPX_CONN_FILE * saf_AssocConnList;
+
+ // the current state of the address file structure; this is either open or
+ // closing
+ USHORT saf_Flags;
+
+ // address to which we are bound, pointer to its lock.
+ struct _SPX_ADDR * saf_Addr;
+ CTELock * saf_AddrLock;
+
+#ifdef ISN_NT
+ // easy backlink to file object.
+ PFILE_OBJECT saf_FileObject;
+#endif
+
+ // device to which we are attached.
+ struct _DEVICE * saf_Device;
+
+ // This holds the request used to close this address file,
+ // for pended completion.
+ PREQUEST saf_CloseReq;
+
+ // This function pointer points to a connection indication handler for this
+ // Address. Any time a connect request is received on the address, this
+ // routine is invoked.
+ PTDI_IND_CONNECT saf_ConnHandler;
+ PVOID saf_ConnHandlerCtx;
+
+ // The following function pointer always points to a TDI_IND_DISCONNECT
+ // handler for the address.
+ PTDI_IND_DISCONNECT saf_DiscHandler;
+ PVOID saf_DiscHandlerCtx;
+
+ // The following function pointer always points to a TDI_IND_RECEIVE
+ // event handler for connections on this address.
+ PTDI_IND_RECEIVE saf_RecvHandler;
+ PVOID saf_RecvHandlerCtx;
+
+ // Send possible handler
+ PTDI_IND_SEND_POSSIBLE saf_SendPossibleHandler;
+ PVOID saf_SendPossibleHandlerCtx;
+
+ // !!!We do not do datagrams or expedited data!!!
+
+ // The following function pointer always points to a TDI_IND_ERROR
+ // handler for the address.
+ PTDI_IND_ERROR saf_ErrHandler;
+ PVOID saf_ErrHandlerCtx;
+ PVOID saf_ErrHandlerOwner;
+
+
+} SPX_ADDR_FILE, *PSPX_ADDR_FILE;
+
+#define SPX_ADDRFILE_OPENING 0x0000 // not yet open for business
+#define SPX_ADDRFILE_OPEN 0x0001 // open for business
+#define SPX_ADDRFILE_CLOSING 0x0002 // closing
+#define SPX_ADDRFILE_STREAM 0x0004 // Opened for stream mode operation
+#define SPX_ADDRFILE_CONNIND 0x0008 // Connect ind in progress
+#define SPX_ADDRFILE_SPX2 0x0010 // Attempt SPX2 address file
+#define SPX_ADDRFILE_NOACKWAIT 0x0020 // Dont delay acks on assoc connections
+#define SPX_ADDRFILE_IPXHDR 0x0040 // Pass ipx hdr on all assoc connections
+// ***STOP*** ***STOP*** ***STOP*** ***STOP*** ***STOP*** ***STOP*** ***STOP***
+// If you are adding any more states to this beyond 0x0080, MAKE SURE to go
+// in code and change statements like (Flags & SPX_***) to
+// ((Flags & SPX_**) != 0)!!! I dont want to make that change that at this stage.
+// ***STOP*** ***STOP*** ***STOP*** ***STOP*** ***STOP*** ***STOP*** ***STOP***
+
+// This structure defines an ADDRESS, or active transport address,
+// maintained by the transport provider. It contains all the visible
+// components of the address (such as the TSAP and network name components),
+// and it also contains other maintenance parts, such as a reference count,
+// ACL, and so on.
+
+#define AREF_ADDR_FILE 0
+#define AREF_LOOKUP 1
+#define AREF_RECEIVE 2
+
+#define AREF_TOTAL 4
+
+typedef struct _SPX_ADDR {
+
+#if DBG
+ ULONG sa_RefTypes[AREF_TOTAL];
+#endif
+
+ USHORT sa_Size;
+ CSHORT sa_Type;
+
+ // number of references to this object.
+ ULONG sa_RefCount;
+
+ // next address/this device object.
+ struct _SPX_ADDR * sa_Next;
+
+ // The following fields are used to maintain state about this address.
+ // attributes of the address.
+ ULONG sa_Flags;
+
+ // Next addressfile for this address
+ struct _SPX_ADDR_FILE * sa_AddrFileList;
+
+ // List of inactive connections and active connections on this address file.
+ struct _SPX_CONN_FILE * sa_InactiveConnList;
+ struct _SPX_CONN_FILE * sa_ActiveConnList;
+
+ // This is the list of connections which have a POST_LISTEN on them. They
+ // do not have a local connection id at this point. But will, when they move
+ // from here to the ActiveConnList, when the listen is satisfied (no matter
+ // if the accept has not been posted yet, in the case of non-autoaccept listens)
+ struct _SPX_CONN_FILE * sa_ListenConnList;
+
+ CTELock sa_Lock;
+
+ // the socket this address corresponds to.
+ USHORT sa_Socket;
+
+ // device context to which we are attached.
+ struct _DEVICE * sa_Device;
+ CTELock * sa_DeviceLock;
+
+#ifdef ISN_NT
+
+ // These two can be a union because they are not used
+ // concurrently.
+ union {
+
+ // This structure is used for checking share access.
+ SHARE_ACCESS sa_ShareAccess;
+
+ // Used for delaying NbfDestroyAddress to a thread so
+ // we can access the security descriptor.
+ WORK_QUEUE_ITEM sa_DestroyAddrQueueItem;
+
+ } u;
+
+ // This structure is used to hold ACLs on the address.
+ PSECURITY_DESCRIPTOR sa_SecurityDescriptor;
+
+#endif
+
+} SPX_ADDR, *PSPX_ADDR;
+
+#define SPX_ADDR_CLOSING 0x00000001
+
+
+// ROUTINE PROTOTYPES
+
+VOID
+SpxAddrRef(
+ IN PSPX_ADDR Address);
+
+VOID
+SpxAddrLockRef(
+ IN PSPX_ADDR Address);
+
+VOID
+SpxAddrDeref(
+ IN PSPX_ADDR Address);
+
+VOID
+SpxAddrFileRef(
+ IN PSPX_ADDR_FILE pAddrFile);
+
+VOID
+SpxAddrFileLockRef(
+ IN PSPX_ADDR_FILE pAddrFile);
+
+VOID
+SpxAddrFileDeref(
+ IN PSPX_ADDR_FILE pAddrFile);
+
+PSPX_ADDR
+SpxAddrCreate(
+ IN PDEVICE Device,
+ IN USHORT Socket);
+
+NTSTATUS
+SpxAddrFileCreate(
+ IN PDEVICE Device,
+ IN PREQUEST Request,
+ OUT PSPX_ADDR_FILE * ppAddrFile);
+
+NTSTATUS
+SpxAddrOpen(
+ IN PDEVICE Device,
+ IN PREQUEST Request);
+
+NTSTATUS
+SpxAddrSetEventHandler(
+ IN PDEVICE Device,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxAddrFileVerify(
+ IN PSPX_ADDR_FILE pAddrFile);
+
+NTSTATUS
+SpxAddrFileStop(
+ IN PSPX_ADDR_FILE pAddrFile,
+ IN PSPX_ADDR Address);
+
+NTSTATUS
+SpxAddrFileCleanup(
+ IN PDEVICE Device,
+ IN PREQUEST Request);
+
+NTSTATUS
+SpxAddrFileClose(
+ IN PDEVICE Device,
+ IN PREQUEST Request);
+
+PSPX_ADDR
+SpxAddrLookup(
+ IN PDEVICE Device,
+ IN USHORT Socket);
+
+NTSTATUS
+SpxAddrConnByRemoteIdAddrLock(
+ IN PSPX_ADDR pSpxAddr,
+ IN USHORT SrcConnId,
+ IN PBYTE SrcIpxAddr,
+ OUT struct _SPX_CONN_FILE **ppSpxConnFile);
+
+NTSTATUS
+SpxAddrFileDestroy(
+ IN PSPX_ADDR_FILE pAddrFile);
+
+VOID
+SpxAddrDestroy(
+ IN PVOID Parameter);
+
+USHORT
+SpxAddrAssignSocket(
+ IN PDEVICE Device);
+
+BOOLEAN
+SpxAddrExists(
+ IN PDEVICE Device,
+ IN USHORT Socket);
+
+NTSTATUS
+spxAddrRemoveFromGlobalList(
+ IN PSPX_ADDR_FILE pSpxAddrFile);
+
+VOID
+spxAddrInsertIntoGlobalList(
+ IN PSPX_ADDR_FILE pSpxAddrFile);
+
+#if DBG
+#define SpxAddrReference(_Address, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_Address)->sa_RefTypes[_Type],\
+ 1, \
+ &SpxGlobalInterlock); \
+ SpxAddrRef (_Address); \
+ }
+
+#define SpxAddrLockReference(_Address, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_Address)->sa_RefTypes[_Type], \
+ 1, \
+ &SpxGlobalInterlock); \
+ SpxAddrLockRef (_Address); \
+ }
+
+#define SpxAddrDereference(_Address, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_Address)->sa_RefTypes[_Type], \
+ (ULONG)-1, \
+ &SpxGlobalInterlock); \
+ if (SPX_ADD_ULONG( \
+ &(_Address)->sa_RefCount, \
+ (ULONG)-1, \
+ &(_Address)->sa_Lock) == 1) { \
+ SpxAddrDestroy (_Address); \
+ }\
+ }
+
+
+#define SpxAddrFileReference(_AddressFile, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_AddressFile)->saf_RefTypes[_Type], \
+ 1, \
+ &SpxGlobalInterlock); \
+ SpxAddrFileRef (_AddressFile); \
+ }
+
+#define SpxAddrFileLockReference(_AddressFile, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_AddressFile)->saf_RefTypes[_Type], \
+ 1, \
+ &SpxGlobalInterlock); \
+ SpxAddrFileLockRef (_AddressFile); \
+ }
+
+#define SpxAddrFileDereference(_AddressFile, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_AddressFile)->saf_RefTypes[_Type], \
+ (ULONG)-1, \
+ &SpxGlobalInterlock); \
+ SpxAddrFileDeref (_AddressFile); \
+ }
+
+#define SpxAddrFileTransferReference(_AddressFile, _OldType, _NewType) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_AddressFile)->saf_RefTypes[_NewType], \
+ 1, \
+ &SpxGlobalInterlock); \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_AddressFile)->saf_RefTypes[_OldType], \
+ (ULONG)-1, \
+ &SpxGlobalInterlock); \
+ }
+
+#else // DBG
+
+#define SpxAddrReference(_Address, _Type) \
+ SPX_ADD_ULONG( \
+ &(_Address)->sa_RefCount, \
+ 1, \
+ (_Address)->sa_DeviceLock)
+
+#define SpxAddrLockReference(_Address, _Type) \
+ SPX_ADD_ULONG( \
+ &(_Address)->sa_RefCount, \
+ 1, \
+ (_Address)->sa_DeviceLock);
+
+#define SpxAddrDereference(_Address, _Type) \
+ if (SPX_ADD_ULONG( \
+ &(_Address)->sa_RefCount, \
+ (ULONG)-1, \
+ &(_Address)->sa_Lock) == 1) { \
+ SpxAddrDestroy (_Address); \
+ }
+
+#define SpxAddrFileReference(_AddressFile, _Type) \
+ SPX_ADD_ULONG( \
+ &(_AddressFile)->saf_RefCount, \
+ 1, \
+ (_AddressFile)->saf_AddrLock)
+
+#define SpxAddrFileLockReference(_AddressFile, _Type) \
+ SPX_ADD_ULONG( \
+ &(_AddressFile)->saf_RefCount, \
+ 1, \
+ (_AddressFile)->saf_AddrLock);
+
+#define SpxAddrFileDereference(_AddressFile, _Type) \
+ if (SPX_ADD_ULONG( \
+ &(_AddressFile)->saf_RefCount, \
+ (ULONG)-1, \
+ (_AddressFile)->saf_AddrLock) == 1) { \
+ SpxAddrFileDestroy (_AddressFile); \
+ }
+
+#define SpxAddrFileTransferReference(_AddressFile, _OldType, _NewType)
+
+#endif // DBG
diff --git a/private/ntos/tdi/isnp/spx/h/spxbind.h b/private/ntos/tdi/isnp/spx/h/spxbind.h
new file mode 100644
index 000000000..81ad6ac58
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/h/spxbind.h
@@ -0,0 +1,32 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxbind.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+NTSTATUS
+SpxInitBindToIpx(
+ VOID);
+
+VOID
+SpxUnbindFromIpx(
+ VOID);
+
diff --git a/private/ntos/tdi/isnp/spx/h/spxconn.h b/private/ntos/tdi/isnp/spx/h/spxconn.h
new file mode 100644
index 000000000..bb1173432
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/h/spxconn.h
@@ -0,0 +1,1666 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxconn.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 5-July-1995
+ Bug fixes - tagged [SA]
+
+--*/
+
+// Minimum value for RTT in ms.
+// BUGBUG: Have these be a derivate of registry values.
+#define SPX_T1_MIN 200
+#define MAX_RETRY_DELAY 5000 // 5 seconds
+#define SPX_DEF_RENEG_RETRYCOUNT 1 // All reneg pkts except min sent once
+
+// Some types
+typedef enum
+{
+ SPX_CALL_RECVLEVEL,
+ SPX_CALL_TDILEVEL
+} SPX_CALL_LEVEL;
+
+typedef enum
+{
+ SPX_REQ_DATA,
+ SPX_REQ_ORDREL,
+ SPX_REQ_DISC
+
+} SPX_SENDREQ_TYPE;
+
+// This structure is pointed to by the FsContext field in the FILE_OBJECT
+// for this Connection.
+
+#define CFREF_CREATE 0
+#define CFREF_VERIFY 1
+#define CFREF_INDICATION 2
+#define CFREF_BYCTX 3
+#define CFREF_BYID 4
+#define CFREF_ADDR 5
+#define CFREF_REQ 6
+#define CFREF_TIMER 7
+#define CFREF_PKTIZE 8
+#define CFREF_RECV 9
+#define CFREF_ABORTPKT 10
+#define CFREF_ERRORSTATE 11
+#define CFREF_FINDROUTE 12
+
+//
+// New state added to reflect an SPXI connection which is waiting for
+// a local disconnect after having indicated a RELEASE to AFD.
+//
+#define CFREF_DISCWAITSPX 13
+
+#define CFREF_TOTAL 14
+
+#define CFMAX_STATES 20
+
+typedef struct _SPX_CONN_FILE
+{
+
+#if DBG
+ ULONG scf_RefTypes[CFREF_TOTAL];
+
+#if 0
+//
+// Disabled for now - to enable logging of states, move this array *after* the Type/Size;
+// a change in their offset can cause problems since we assume the offset to be less than
+// the size of an AddressFile structure. (see SpxTdiQueryInformation)
+//
+ ULONG scf_StateBuffer[CFMAX_STATES];
+ ULONG scf_NextStatePtr;
+#endif
+
+#endif
+
+ CSHORT scf_Type;
+ CSHORT scf_Size;
+
+ // number of references to this object.
+ ULONG scf_RefCount;
+
+ // Linkage in device address file list. The connection can be on the device
+ // connection list, address inactive/listen/active list.
+ struct _SPX_CONN_FILE * scf_Next;
+ struct _SPX_CONN_FILE * scf_AssocNext;
+ struct _SPX_CONN_FILE * scf_GlobalActiveNext;
+
+ // Queued in a global list, stays here from creation to destroy.
+ struct _SPX_CONN_FILE * scf_GlobalNext;
+ struct _SPX_CONN_FILE * scf_PktNext;
+ struct _SPX_CONN_FILE * scf_ProcessRecvNext;
+
+ // the current state of the connection. One main state and multiple substates.
+ ULONG scf_Flags;
+
+ // More information
+ ULONG scf_Flags2;
+
+#if DBG
+ // Save the state of flags/flags2 before reinit. Overwritten every reinit.
+ ULONG scf_GhostFlags;
+ ULONG scf_GhostFlags2;
+ ULONG scf_GhostRefCount;
+ PREQUEST scf_GhostDiscReq;
+#endif
+
+ // Connection retry counts, or watchdog timer count when the connection goes
+ // active
+ union
+ {
+ LONG scf_CRetryCount;
+ LONG scf_WRetryCount;
+ };
+ LONG scf_RRetryCount;
+ USHORT scf_RRetrySeqNum;
+
+ union
+ {
+ ULONG scf_CTimerId;
+ ULONG scf_RTimerId; // Only after we turn active
+ };
+
+ ULONG scf_WTimerId; // Watchdog timer
+ ULONG scf_TTimerId; // TDI Connect/Disconnect timer
+ ULONG scf_ATimerId; // Ack timer id
+
+ // Variables used to manage the Retry timer tick value
+ // Note our timer subsytem fires at 100ms granularity.
+ int scf_BaseT1;
+ int scf_AveT1;
+ int scf_DevT1;
+
+ // Stored in HOST-ORDER
+ // LOCAL variables
+ USHORT scf_LocalConnId;
+ USHORT scf_SendSeqNum; // Debug dw +9a
+ USHORT scf_SentAllocNum; // dw +9c
+
+ // REMOTE variables
+ USHORT scf_RecvSeqNum; // dw +9e
+ USHORT scf_RecdAckNum; // dw +a0
+ USHORT scf_RecdAllocNum; // dw +a2
+
+ // RETRY sequence number
+ USHORT scf_RetrySeqNum;
+
+ // Saved ack number to be used in building the reneg ack packet.
+ // Note that our RecvSeqNum which we normally use is overwritten
+ // when we receive a renegotiate request.
+ USHORT scf_RenegAckAckNum;
+
+ // Stored in NETWORK-ORDER. scf_RemAckAddr contains the remote address
+ // for a data packet that had the ack bit set, buildAck will use this
+ // address.
+ BYTE scf_RemAddr[12];
+ BYTE scf_RemAckAddr[12];
+ USHORT scf_RemConnId; // Debug dw +be
+
+ // Maximum packet size (or size of first) reneg packet.
+ USHORT scf_RenegMaxPktSize;
+
+ // Local target to use in when sending acks. This is set to received
+ // data's indicated local target.
+ IPX_LOCAL_TARGET scf_AckLocalTarget;
+
+ // Maximum packet size to use for this connection
+ USHORT scf_MaxPktSize;
+ UCHAR scf_DataType;
+
+ // Local target to use in sends, initialized upon connect indication
+ // or when find_route completes
+ IPX_LOCAL_TARGET scf_LocalTarget;
+
+ // Connection lock
+ CTELock scf_Lock;
+
+ // address to which we are bound
+ struct _SPX_ADDR_FILE * scf_AddrFile;
+
+ // Connection context
+ CONNECTION_CONTEXT scf_ConnCtx;
+
+#ifdef ISN_NT
+ // easy backlink to file object.
+ PFILE_OBJECT scf_FileObject;
+#endif
+
+ // LIST_ENTRY of disconnect irps waiting for completion. There could be
+ // multiple disconnect inform irps.
+ LIST_ENTRY scf_DiscLinkage;
+
+ // LIST_ENTRY of send requests (intially contains connect/listen/accept also)
+ // on this connection.
+ LIST_ENTRY scf_ReqLinkage;
+
+ // Queue for completed requests awaiting completion
+ LIST_ENTRY scf_ReqDoneLinkage;
+ LIST_ENTRY scf_RecvDoneLinkage;
+
+ // Queue for pending receives
+ LIST_ENTRY scf_RecvLinkage;
+ PREQUEST scf_CurRecvReq;
+ ULONG scf_CurRecvOffset;
+ ULONG scf_CurRecvSize;
+
+ // Current request packetize info
+ PREQUEST scf_ReqPkt;
+ ULONG scf_ReqPktOffset;
+ ULONG scf_ReqPktSize;
+ ULONG scf_ReqPktFlags;
+ SPX_SENDREQ_TYPE scf_ReqPktType;
+
+ // Single linked list of sequenced send/disc packets
+ PSPX_SEND_RESD scf_SendSeqListHead;
+ PSPX_SEND_RESD scf_SendSeqListTail;
+
+ // Single linked list of send (unsequenced) packets
+ PSPX_SEND_RESD scf_SendListHead;
+ PSPX_SEND_RESD scf_SendListTail;
+
+ // Single linked list of buffered recv packets.
+ PSPX_RECV_RESD scf_RecvListHead;
+ PSPX_RECV_RESD scf_RecvListTail;
+
+ // Connect request
+ PREQUEST scf_ConnectReq;
+
+ // This holds the request used to close this address file,
+ // for pended completion. We also pend cleanup requests for connections.
+ PREQUEST scf_CleanupReq;
+ PREQUEST scf_CloseReq;
+
+#if DBG
+
+ // Packet being indicated, seq num, flags/flags2
+ USHORT scf_PktSeqNum;
+ ULONG scf_PktFlags;
+ ULONG scf_PktFlags2;
+
+ ULONG scf_IndBytes;
+ ULONG scf_IndLine;
+#endif
+
+#if DBG_WDW_CLOSE
+
+ // Keep track of how long the window was closed on this connection.
+ ULONG scf_WdwCloseAve;
+ LARGE_INTEGER scf_WdwCloseTime; // Time when wdw was closed
+#endif
+
+ // device to which we are attached.
+ struct _DEVICE * scf_Device;
+
+} SPX_CONN_FILE, *PSPX_CONN_FILE;
+
+
+// Basic states
+// Least significant byte of flags is used.
+// Mutually exclusive states are coded as numbers, others are bit flags.
+// Only main states are currently in form of numbers. Also, send and receive.
+//
+// Once we go active, we need SEND/RECEIVE/DISC substates to be mutually
+// exclusive with each other. As all three could be active at the same time.
+
+// Connection MAIN states. These are all mutually exclusive.
+#define SPX_CONNFILE_MAINMASK 0x00000007
+#define SPX_CONNFILE_ACTIVE 0x00000001
+#define SPX_CONNFILE_CONNECTING 0x00000002
+#define SPX_CONNFILE_LISTENING 0x00000003
+#define SPX_CONNFILE_DISCONN 0x00000004
+
+// Connecting states (VALID when CONNFILE_CONNECTING)
+#define SPX_CONNECT_MASK 0x000000F0
+#define SPX_CONNECT_SENTREQ 0x00000010
+#define SPX_CONNECT_NEG 0x00000020
+#define SPX_CONNECT_W_SETUP 0x00000030
+
+// Listening states (VALID when CONNFILE_LISTENING)
+#define SPX_LISTEN_MASK 0x000000F0
+#define SPX_LISTEN_RECDREQ 0x00000010
+#define SPX_LISTEN_SENTACK 0x00000020
+#define SPX_LISTEN_NEGACK 0x00000030
+#define SPX_LISTEN_SETUP 0x00000040
+
+// Connection SUB states
+// Send machine states (VALID when CONNFILE_ACTIVE)
+#define SPX_SEND_MASK 0x000000F0
+#define SPX_SEND_IDLE 0x00000000
+#define SPX_SEND_PACKETIZE 0x00000010
+#define SPX_SEND_RETRY 0x00000020
+#define SPX_SEND_RETRYWD 0x00000030
+#define SPX_SEND_RENEG 0x00000040
+#define SPX_SEND_RETRY2 0x00000050
+#define SPX_SEND_RETRY3 0x00000060
+#define SPX_SEND_WD 0x00000070 // We dont reneg pkt size on wdog
+ // Also we change to this state only
+ // 2nd time wdog fires w/out ack.
+#define SPX_SEND_NAK_RECD 0x00000080
+
+// Receive machine states (VALID when CONNFILE_ACTIVE)
+#define SPX_RECV_MASK 0x00000F00
+#define SPX_RECV_IDLE 0x00000000
+#define SPX_RECV_POSTED 0x00000100
+#define SPX_RECV_PROCESS_PKTS 0x00000200
+
+// Disconnect states (VALID when CONNFILE_DISCONN/CONNFILE_ACTIVE)
+// These are valid when either ACTIVE/DISCONN is set. We use these when
+// active for a orderly release, i.e. we receive pkt from remote, but we
+// stay active (setting SPX_DISC_RECV_ORDREL) until our client posts a
+// disconnect, which is when we move to disconnecting.
+#define SPX_DISC_MASK 0x0000F000
+#define SPX_DISC_IDLE 0x00000000
+#define SPX_DISC_ABORT 0x00001000
+#define SPX_DISC_SENT_IDISC 0x00002000
+#define SPX_DISC_POST_ORDREL 0x00003000
+#define SPX_DISC_SENT_ORDREL 0x00004000
+#define SPX_DISC_ORDREL_ACKED 0x00005000
+#define SPX_DISC_POST_IDISC 0x00006000
+
+// [SA] bug #14655 added flag to indicate that SpxConnInactivate already called for
+// this disconnecting connection
+//
+#define SPX_DISC_INACTIVATED 0x00007000
+
+// The following are not mutually exclusive.
+#define SPX_CONNFILE_RECVQ 0x00010000 // Process completed receives/pkts
+#define SPX_CONNFILE_RENEG_SIZE 0x00020000 // Size changed in renegotiate pkt
+#define SPX_CONNFILE_ACKQ 0x00040000 // Waiting to piggyback ack queue
+#define SPX_CONNFILE_PKTQ 0x00080000 // Waiting to packetize queue
+
+#define SPX_CONNFILE_ASSOC 0x00100000 // associated
+#define SPX_CONNFILE_NEG 0x00200000 // CR had neg set (for delayed accept)
+#define SPX_CONNFILE_SPX2 0x00400000
+#define SPX_CONNFILE_STREAM 0x00800000
+#define SPX_CONNFILE_R_TIMER 0x01000000 // Retry timer (only after ACTIVE)
+#define SPX_CONNFILE_C_TIMER 0x01000000 // Connect timer
+#define SPX_CONNFILE_W_TIMER 0x02000000 // Watchdog timer
+#define SPX_CONNFILE_T_TIMER 0x04000000 // tdi connect/disc timer specified
+#define SPX_CONNFILE_RENEG_PKT 0x08000000 // Renegotiate changed size, repacketize
+#define SPX_CONNFILE_IND_IDISC 0x10000000 // Indicated abortive disc to afd
+#define SPX_CONNFILE_IND_ODISC 0x20000000 // Indicated orderly release to afd
+
+#define SPX_CONNFILE_STOPPING 0x40000000
+#define SPX_CONNFILE_CLOSING 0x80000000 // closing
+
+#define SPX_CONNFILE2_PKT_NOIND 0x00000001
+#define SPX_CONNFILE2_RENEGRECD 0x00000002 // A renegotiate was received.
+ // scf_RenegAckAckNum set.
+#define SPX_CONNFILE2_PKT 0x00000004
+#define SPX_CONNFILE2_FINDROUTE 0x00000010 // A find route in progress on conn.
+#define SPX_CONNFILE2_NOACKWAIT 0x00000020 // Dont delay acks on connection, option
+#define SPX_CONNFILE2_IMMED_ACK 0x00000040 // Send an immediate ack,no back traffic
+#define SPX_CONNFILE2_IPXHDR 0x00000080 // Pass ipxhdr in receives
+
+//
+// [SA] Saves the IDisc flag passed to AbortiveDisc; this is TRUE only if there was
+// a remote disconnect on an SPX connection (in which case, we indicate TDI_DISCONNECT_RELEASE
+// else we indicate TDI_DISCONNECT_ABORT)
+//
+#define SPX_CONNFILE2_IDISC 0x00000100
+
+//
+// Indicates an SPXI connfile waiting for a local disconnect in response
+// to a TDI_DISCONNECT_RELEASE to AFD.
+//
+#define SPX_CONNFILE2_DISC_WAIT 0x00000200
+
+// FindRoute request structure
+typedef struct _SPX_FIND_ROUTE_REQUEST
+{
+ // !!!!This must be the first element in the structure
+ IPX_FIND_ROUTE_REQUEST fr_FindRouteReq;
+ PVOID fr_Ctx;
+
+} SPX_FIND_ROUTE_REQUEST, *PSPX_FIND_ROUTE_REQUEST;
+
+typedef struct _SPX_CONNFILE_LIST
+{
+ PSPX_CONN_FILE pcl_Head;
+ PSPX_CONN_FILE pcl_Tail;
+
+} SPX_CONNFILE_LIST, *PSPX_CONNFILE_LIST;
+
+// Exported routines
+
+NTSTATUS
+SpxConnOpen(
+ IN PDEVICE pDevice,
+ IN CONNECTION_CONTEXT pConnCtx,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnCleanup(
+ IN PDEVICE Device,
+ IN PREQUEST Request);
+
+NTSTATUS
+SpxConnClose(
+ IN PDEVICE Device,
+ IN PREQUEST Request);
+
+NTSTATUS
+SpxConnDisAssociate(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+spxConnDisAssoc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+SpxConnStop(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+NTSTATUS
+SpxConnAssociate(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnConnect(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnListen(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnAccept(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnAction(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnDisconnect(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnSend(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnRecv(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+VOID
+SpxConnFileRefByCtxLock(
+ IN PSPX_ADDR_FILE pSpxAddrFile,
+ IN CONNECTION_CONTEXT Ctx,
+ OUT PSPX_CONN_FILE * ppSpxConnFile,
+ OUT NTSTATUS * pStatus);
+
+NTSTATUS
+SpxConnFileVerify (
+ IN PSPX_CONN_FILE pConnFile);
+
+VOID
+SpxConnFileDeref(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+SpxConnConnectFindRouteComplete(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_FIND_ROUTE_REQUEST pFrReq,
+ IN BOOLEAN FoundRoute,
+ IN CTELockHandle LockHandle);
+
+VOID
+SpxConnActiveFindRouteComplete(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_FIND_ROUTE_REQUEST pFrReq,
+ IN BOOLEAN FoundRoute,
+ IN CTELockHandle LockHandle);
+
+BOOLEAN
+SpxConnPacketize(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN BOOLEAN fNormalState,
+ IN CTELockHandle LockHandleConn);
+
+#if DBG
+VOID
+SpxConnFileRef(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+SpxConnFileLockRef(
+ IN PSPX_CONN_FILE pSpxConnFile);
+#endif
+
+VOID
+SpxConnFileRefByIdLock (
+ IN USHORT ConnId,
+ OUT PSPX_CONN_FILE * ppSpxConnFile,
+ OUT PNTSTATUS pStatus);
+
+BOOLEAN
+SpxConnDequeuePktLock(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PNDIS_PACKET pPkt);
+
+VOID
+SpxConnSendAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+SpxConnSendNack(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN USHORT NumToSend,
+ IN CTELockHandle LockHandleConn);
+
+BOOLEAN
+SpxConnProcessAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PIPXSPX_HDR pAckHdr,
+ IN CTELockHandle lockHandle);
+
+VOID
+SpxConnProcessRenegReq(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN CTELockHandle lockHandle);
+
+VOID
+SpxConnProcessIDisc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle lockHandle);
+
+VOID
+SpxConnProcessOrdRel(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle lockHandle);
+
+BOOLEAN
+SpxConnDequeueRecvPktLock(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PNDIS_PACKET pPkt);
+
+BOOLEAN
+SpxConnDequeueSendPktLock(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PNDIS_PACKET pPkt);
+
+// LOCAL functions
+VOID
+spxConnHandleConnReq(
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr);
+
+VOID
+spxConnHandleSessPktFromClient(
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnHandleSessPktFromSrv(
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+ULONG
+spxConnConnectTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown);
+
+ULONG
+spxConnWatchdogTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown);
+
+ULONG
+spxConnRetryTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown);
+
+ULONG
+spxConnAckTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown);
+
+VOID
+spxConnCompletePended(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+SpxConnQWaitAck(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+USHORT
+spxConnGetId(
+ VOID);
+
+VOID
+spxConnInsertIntoActiveList(
+ IN PSPX_ADDR pSpxAddr,
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnInsertIntoInactiveList(
+ IN PSPX_ADDR pSpxAddr,
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+NTSTATUS
+spxConnRemoveFromGlobalList(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnInsertIntoGlobalList(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+NTSTATUS
+spxConnRemoveFromGlobalActiveList(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnPushIntoPktList(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnPopFromPktList(
+ IN PSPX_CONN_FILE * ppSpxConnFile);
+
+VOID
+spxConnPushIntoRecvList(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnPopFromRecvList(
+ IN PSPX_CONN_FILE * ppSpxConnFile);
+
+VOID
+spxConnInsertIntoGlobalActiveList(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnInsertIntoListenList(
+ IN PSPX_ADDR pSpxAddr,
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+NTSTATUS
+spxConnRemoveFromList(
+ IN PSPX_CONN_FILE * ppConnListHead,
+ IN PSPX_CONN_FILE pConnRemove);
+
+NTSTATUS
+spxConnRemoveFromAssocList(
+ IN PSPX_CONN_FILE * ppConnListHead,
+ IN PSPX_CONN_FILE pConnRemove);
+
+VOID
+spxConnInactivate(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+BOOLEAN
+spxConnGetPktByType(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN ULONG PktType,
+ IN BOOLEAN fSeqList,
+ IN PNDIS_PACKET * ppPkt);
+
+BOOLEAN
+spxConnGetPktBySeqNum(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN USHORT SeqNum,
+ IN PNDIS_PACKET * ppPkt);
+
+VOID
+spxConnResendPkts(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn);
+
+BOOLEAN
+spxConnCheckNegSize(
+ IN PUSHORT pNegSize);
+
+VOID
+spxConnSetNegSize(
+ IN OUT PNDIS_PACKET pPkt,
+ IN ULONG Size);
+
+BOOLEAN
+spxConnAcceptCr(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_ADDR pSpxAddr,
+ IN CTELockHandle LockHandleDev,
+ IN CTELockHandle LockHandleAddr,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+spxConnAbortConnect(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN CTELockHandle LockHandleDev,
+ IN CTELockHandle LockHandleAddr,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+spxConnCompleteConnect(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleDev,
+ IN CTELockHandle LockHandleAddr,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+SpxConnQueueRecv(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+spxConnProcessRecv(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PREQUEST pRequest,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+spxConnProcessIndData(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn);
+
+NTSTATUS
+spxConnOrderlyDisc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN PREQUEST pRequest,
+ IN CTELockHandle LockHandleConn);
+
+NTSTATUS
+spxConnInformedDisc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN PREQUEST pRequest,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+spxConnAbortiveDisc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn,
+ IN BOOLEAN Flag); // [SA] Bug #15249
+
+VOID
+spxConnAbortRecvs(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+spxConnAbortSends(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+spxConnResetSendQueue(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnAbortSendPkt(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_SEND_RESD pSendResd,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn);
+
+//
+// MACROS
+//
+#define SHIFT100000 16
+
+#define SPX_CONVERT100NSTOCENTISEC(Li) \
+ RtlExtendedMagicDivide((Li), Magic100000, SHIFT100000)
+
+#define UNSIGNED_BETWEEN_WITH_WRAP(Low, High, Target) \
+ ((Low <= High) ? ((Target >= Low) && (Target <= High)) : \
+ ((Target >= Low) || (Target <= High)))
+
+// This is with the assumption that the window size will never be greater
+// than the difference of 0x8000 and 0x1000. If High is < 1000 and Low
+// is > 8000 then we can assume a wrap happened. Otherwise, we assume no
+// wrap and do a straight compare.
+#define MAX_WINDOW_SIZE 0x6000
+#define DEFAULT_WINDOW_SIZE 8
+
+#define UNSIGNED_GREATER_WITH_WRAP(High, Low) \
+ (((High < 0x1000) && (Low > 0x8000)) ? TRUE : (High > Low))
+
+#define SPX_SET_ACKNUM(pSpxConnFile, RecdAckNum, RecdAllocNum) \
+ { \
+ DBGPRINT(SEND, DBG, \
+ ("SPX_SET_ACKNUM: %lx.%lx = %lx.%lx (%s.%d)\n", \
+ (RecdAckNum), (RecdAllocNum), \
+ ((pSpxConnFile)->scf_RecdAckNum), \
+ ((pSpxConnFile)->scf_RecdAllocNum), \
+ __FILE__, __LINE__)); \
+ \
+ if (UNSIGNED_GREATER_WITH_WRAP((RecdAckNum), \
+ ((pSpxConnFile)->scf_RecdAckNum))) \
+ { \
+ (pSpxConnFile)->scf_RecdAckNum = (RecdAckNum); \
+ } \
+ \
+ if (UNSIGNED_GREATER_WITH_WRAP((RecdAllocNum), \
+ ((pSpxConnFile)->scf_RecdAllocNum)))\
+ { \
+ (pSpxConnFile)->scf_RecdAllocNum = (RecdAllocNum); \
+ } \
+ }
+
+#define BEGIN_PROCESS_PACKET(pSpxConnFile, seqNum) \
+ { \
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_PKT); \
+ }
+
+#define END_PROCESS_PACKET(pSpxConnFile, fBuffered, fSuccess) \
+ { \
+ SPX_CONN_RESETFLAG2(pSpxConnFile, \
+ (SPX_CONNFILE2_PKT |SPX_CONNFILE2_RENEGRECD)); \
+ if (fSuccess) \
+ { \
+ SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_PKT_NOIND); \
+ SPX_SET_RECVNUM(pSpxConnFile, fBuffered); \
+ } \
+ }
+
+#define INCREMENT_WINDOW(pSpxConnFile) \
+ ((pSpxConnFile)->scf_SentAllocNum++)
+
+#define ADD_TO_WINDOW(pSpxConnFile, numPkts) \
+ ((pSpxConnFile)->scf_SentAllocNum += (numPkts))
+
+#if DBG_WDW_CLOSE
+#define SPX_SET_RECVNUM(pSpxConnFile, fBuffered) \
+ { \
+ (pSpxConnFile)->scf_RecvSeqNum++; \
+ if (!fBuffered) \
+ (pSpxConnFile)->scf_SentAllocNum++; \
+ \
+ if (fBuffered && \
+ (UNSIGNED_GREATER_WITH_WRAP( \
+ (pSpxConnFile)->scf_RecvSeqNum, \
+ (pSpxConnFile)->scf_SentAllocNum))) \
+ { \
+ KeQuerySystemTime( \
+ (PLARGE_INTEGER)&pSpxConnFile->scf_WdwCloseTime); \
+ } \
+ }
+#else
+#define SPX_SET_RECVNUM(pSpxConnFile, fBuffered) \
+ { \
+ (pSpxConnFile)->scf_RecvSeqNum++; \
+ if (!fBuffered) \
+ (pSpxConnFile)->scf_SentAllocNum++; \
+ }
+#endif
+
+
+#define SPX_CONN_SETNEXT_CUR_RECV(pSpxConnFile, pRequest) \
+ { \
+ RemoveEntryList(REQUEST_LINKAGE((pRequest))); \
+ pSpxConnFile->scf_CurRecvReq = NULL; \
+ pSpxConnFile->scf_CurRecvOffset = 0; \
+ pSpxConnFile->scf_CurRecvSize = 0; \
+ if (!IsListEmpty(&(pSpxConnFile)->scf_RecvLinkage)) \
+ { \
+ PTDI_REQUEST_KERNEL_RECEIVE _p; \
+ DBGPRINT(RECEIVE, DBG, \
+ ("spxConnProcessRecv: CURRECV %lx\n", pRequest)); \
+ \
+ (pSpxConnFile)->scf_CurRecvReq = \
+ LIST_ENTRY_TO_REQUEST( \
+ (pSpxConnFile)->scf_RecvLinkage.Flink); \
+ \
+ _p = (PTDI_REQUEST_KERNEL_RECEIVE) \
+ REQUEST_PARAMETERS((pSpxConnFile)->scf_CurRecvReq); \
+ \
+ (pSpxConnFile)->scf_CurRecvOffset = 0; \
+ (pSpxConnFile)->scf_CurRecvSize = (_p)->ReceiveLength; \
+ } \
+ if ((SPX_RECV_STATE(pSpxConnFile) == SPX_RECV_IDLE) || \
+ (SPX_RECV_STATE(pSpxConnFile) == SPX_RECV_POSTED)) \
+ { \
+ SPX_RECV_SETSTATE( \
+ pSpxConnFile, \
+ (pSpxConnFile->scf_CurRecvReq == NULL) ? \
+ SPX_RECV_IDLE : SPX_RECV_POSTED); \
+ } \
+ }
+
+#define SPX_INSERT_ADDR_ACTIVE(pSpxAddr, pSpxConnFile) \
+ { \
+ (pSpxConnFile)->scf_Next = (pSpxAddr)->sa_ActiveConnList; \
+ (pSpxAddr)->sa_ActiveConnList = pSpxConnFile; \
+ }
+
+#define SPX_INSERT_ADDR_INACTIVE(pSpxAddr, pSpxConnFile) \
+ { \
+ (pSpxConnFile)->scf_Next = (pSpxAddr)->sa_InactiveConnList; \
+ (pSpxAddr)->sa_InactiveConnList = pSpxConnFile; \
+ }
+
+#define SPX_INSERT_ADDR_LISTEN(pSpxAddr, pSpxConnFile) \
+ { \
+ (pSpxConnFile)->scf_Next = (pSpxAddr)->sa_ListenConnList; \
+ (pSpxAddr)->sa_ListenConnList = pSpxConnFile; \
+ }
+
+
+//
+// STATE MANIPULATION
+//
+
+#if 0
+//
+// Disabled for now
+//
+#define SPX_STORE_LAST_STATE(pSpxConnFile) \
+ (pSpxConnFile)->scf_StateBuffer[(pSpxConnFile)->scf_NextStatePtr++] = \
+ (pSpxConnFile)->scf_Flags; \
+ (pSpxConnFile)->scf_NextStatePtr %= CFMAX_STATES;
+#else
+
+#define SPX_STORE_LAST_STATE(pSpxConnFile)
+
+#endif
+
+#define SPX_MAIN_STATE(pSpxConnFile) \
+ ((pSpxConnFile)->scf_Flags & SPX_CONNFILE_MAINMASK)
+
+// #define SPX_CONN_IDLE(pSpxConnFile) \
+// ((BOOLEAN)(SPX_MAIN_STATE(pSpxConnFile) == 0))
+
+#define SPX_CONN_IDLE(pSpxConnFile) \
+ ((BOOLEAN)((SPX_MAIN_STATE(pSpxConnFile) == 0) || \
+ ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) && \
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED))))
+
+#define SPX_CONN_ACTIVE(pSpxConnFile) \
+ ((BOOLEAN)(SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_ACTIVE))
+
+#define SPX_CONN_CONNECTING(pSpxConnFile) \
+ ((BOOLEAN)(SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_CONNECTING))
+
+#define SPX_CONN_LISTENING(pSpxConnFile) \
+ ((BOOLEAN)(SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_LISTENING))
+
+#define SPX_CONN_DISC(pSpxConnFile) \
+ ((BOOLEAN)(SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN))
+
+#if DBG
+
+#define SPX_MAIN_SETSTATE(pSpxConnFile, newState) \
+ { \
+ SPX_STORE_LAST_STATE(pSpxConnFile) \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_CONNFILE_MAINMASK) | (newState));\
+ }
+
+#else
+
+#define SPX_MAIN_SETSTATE(pSpxConnFile, newState) \
+ { \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_CONNFILE_MAINMASK) | (newState));\
+ }
+
+#endif
+
+#define SPX_CONN_FLAG(pSpxConnFile, Flag) \
+ ((BOOLEAN)(((pSpxConnFile)->scf_Flags & (Flag)) != 0))
+
+#define SPX_CONN_FLAG2(pSpxConnFile, Flag) \
+ ((BOOLEAN)(((pSpxConnFile)->scf_Flags2 & (Flag)) != 0))
+
+#if DBG
+
+#define SPX_CONN_SETFLAG(pSpxConnFile, Flag) \
+ SPX_STORE_LAST_STATE(pSpxConnFile) \
+ ((pSpxConnFile)->scf_Flags |= (Flag))
+#else
+
+#define SPX_CONN_SETFLAG(pSpxConnFile, Flag) \
+ ((pSpxConnFile)->scf_Flags |= (Flag))
+
+#endif
+
+#define SPX_CONN_SETFLAG2(pSpxConnFile, Flag) \
+ ((pSpxConnFile)->scf_Flags2 |= (Flag))
+
+#define SPX_CONN_RESETFLAG(pSpxConnFile, Flag) \
+ ((pSpxConnFile)->scf_Flags &= ~(Flag))
+
+#define SPX_CONN_RESETFLAG2(pSpxConnFile, Flag) \
+ ((pSpxConnFile)->scf_Flags2 &= ~(Flag))
+
+#define SPX2_CONN(pSpxConnFile) \
+ (SPX_CONN_FLAG((pSpxConnFile), SPX_CONNFILE_SPX2))
+
+#define SPX_CONN_STREAM(pSpxConnFile) \
+ (SPX_CONN_FLAG((pSpxConnFile), SPX_CONNFILE_STREAM))
+
+#define SPX_CONN_MSG(pSpxConnFile) \
+ (!SPX_CONN_FLAG((pSpxConnFile), SPX_CONNFILE_STREAM))
+
+#define SPX_LISTEN_STATE(pSpxConnFile) \
+ ((pSpxConnFile)->scf_Flags & SPX_LISTEN_MASK)
+
+#define SPX_CONNECT_STATE(pSpxConnFile) \
+ ((pSpxConnFile)->scf_Flags & SPX_CONNECT_MASK)
+
+#define SPX_SEND_STATE(pSpxConnFile) \
+ ((pSpxConnFile)->scf_Flags & SPX_SEND_MASK)
+
+#define SPX_RECV_STATE(pSpxConnFile) \
+ ((pSpxConnFile)->scf_Flags & SPX_RECV_MASK)
+
+#define SPX_DISC_STATE(pSpxConnFile) \
+ ((pSpxConnFile)->scf_Flags & SPX_DISC_MASK)
+
+#if DBG
+
+#define SPX_LISTEN_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("LISTEN: %x -> %x\n", \
+ SPX_LISTEN_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ SPX_STORE_LAST_STATE(pSpxConnFile) \
+ pSpxConnFile->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_LISTEN_MASK) | (newState)); \
+ }
+
+#define SPX_CONNECT_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("CONNECT: %x -> %x\n", \
+ SPX_CONNECT_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ SPX_STORE_LAST_STATE(pSpxConnFile) \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_CONNECT_MASK) | (newState)); \
+ }
+
+#define SPX_SEND_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("SEND: %x -> %x\n", \
+ SPX_SEND_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ SPX_STORE_LAST_STATE(pSpxConnFile) \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_SEND_MASK) | (newState)); \
+ }
+
+#define SPX_RECV_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("RECV: %x -> %x\n", \
+ SPX_RECV_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ SPX_STORE_LAST_STATE(pSpxConnFile) \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_RECV_MASK) | (newState)); \
+ }
+
+#define SPX_DISC_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("DISC: %x -> %x\n", \
+ SPX_DISC_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ SPX_STORE_LAST_STATE(pSpxConnFile) \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_DISC_MASK) | (newState)); \
+ }
+
+#else
+
+#define SPX_LISTEN_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("LISTEN: %x -> %x\n", \
+ SPX_LISTEN_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ pSpxConnFile->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_LISTEN_MASK) | (newState)); \
+ }
+
+#define SPX_CONNECT_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("CONNECT: %x -> %x\n", \
+ SPX_CONNECT_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_CONNECT_MASK) | (newState)); \
+ }
+
+#define SPX_SEND_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("SEND: %x -> %x\n", \
+ SPX_SEND_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_SEND_MASK) | (newState)); \
+ }
+
+#define SPX_RECV_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("RECV: %x -> %x\n", \
+ SPX_RECV_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_RECV_MASK) | (newState)); \
+ }
+
+#define SPX_DISC_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("DISC: %x -> %x\n", \
+ SPX_DISC_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_DISC_MASK) | (newState)); \
+ }
+#endif //DBG
+#define SpxConnQueueSendPktTail(pSpxConnFile, pPkt) \
+ { \
+ PSPX_SEND_RESD _pSendResd; \
+ _pSendResd = (PSPX_SEND_RESD)((pPkt)->ProtocolReserved); \
+ _pSendResd->sr_Next = NULL; \
+ if ((pSpxConnFile)->scf_SendListTail != NULL) \
+ { \
+ (pSpxConnFile)->scf_SendListTail->sr_Next = _pSendResd; \
+ (pSpxConnFile)->scf_SendListTail = _pSendResd;\
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_SendListTail = \
+ (pSpxConnFile)->scf_SendListHead = _pSendResd; \
+ } \
+ }
+
+#define SpxConnQueueSendPktHead(pSpxConnFile, pPkt) \
+ { \
+ PSPX_SEND_RESD _pSendResd; \
+ _pSendResd = (PSPX_SEND_RESD)((pPkt)->ProtocolReserved); \
+ _pSendResd->sr_Next = NULL; \
+ if ((pSpxConnFile)->scf_SendListTail != NULL) \
+ { \
+ _pSendResd->sr_Next = (pSpxConnFile)->scf_SendListHead; \
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_SendListTail = _pSendResd; \
+ } \
+ (pSpxConnFile)->scf_SendListHead = _pSendResd; \
+ }
+
+#define SpxConnQueueSendSeqPktTail(pSpxConnFile, pPkt) \
+ { \
+ PSPX_SEND_RESD _pSendResd; \
+ _pSendResd = (PSPX_SEND_RESD)((pPkt)->ProtocolReserved); \
+ _pSendResd->sr_Next = NULL; \
+ if ((pSpxConnFile)->scf_SendSeqListTail != NULL) \
+ { \
+ (pSpxConnFile)->scf_SendSeqListTail->sr_Next = _pSendResd;\
+ (pSpxConnFile)->scf_SendSeqListTail = _pSendResd;\
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_SendSeqListTail = \
+ (pSpxConnFile)->scf_SendSeqListHead = _pSendResd; \
+ } \
+ }
+
+#define SpxConnQueueSendSeqPktHead(pSpxConnFile, pPkt) \
+ { \
+ PSPX_SEND_RESD _pSendResd; \
+ _pSendResd = (PSPX_SEND_RESD)((pPkt)->ProtocolReserved); \
+ _pSendResd->sr_Next = NULL; \
+ if ((pSpxConnFile)->scf_SendSeqListTail != NULL) \
+ { \
+ _pSendResd->sr_Next = (pSpxConnFile)->scf_SendSeqListHead;\
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_SendSeqListTail = _pSendResd; \
+ } \
+ (pSpxConnFile)->scf_SendSeqListHead = _pSendResd; \
+ }
+
+#define SpxConnQueueRecvPktTail(pSpxConnFile, pPkt) \
+ { \
+ PSPX_RECV_RESD _pRecvResd; \
+ _pRecvResd = (PSPX_RECV_RESD)((pPkt)->ProtocolReserved); \
+ _pRecvResd->rr_Next = NULL; \
+ if ((pSpxConnFile)->scf_RecvListTail != NULL) \
+ { \
+ (pSpxConnFile)->scf_RecvListTail->rr_Next = _pRecvResd; \
+ (pSpxConnFile)->scf_RecvListTail = _pRecvResd;\
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_RecvListTail = \
+ (pSpxConnFile)->scf_RecvListHead = _pRecvResd; \
+ } \
+ }
+
+#define SpxConnQueueRecvPktHead(pSpxConnFile, pPkt) \
+ { \
+ PSPX_RECV_RESD _pRecvResd; \
+ _pRecvResd = (PSPX_RECV_RESD)((pPkt)->ProtocolReserved); \
+ _pRecvResd->rr_Next = NULL; \
+ if ((pSpxConnFile)->scf_RecvListTail != NULL) \
+ { \
+ _pRecvResd->rr_Next = (pSpxConnFile)->scf_RecvListHead; \
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_RecvListTail = _pRecvResd; \
+ } \
+ (pSpxConnFile)->scf_RecvListHead = _pRecvResd; \
+ }
+
+#if DBG
+#define SpxConnFileReference(_ConnFile, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_ConnFile)->scf_RefTypes[_Type], \
+ 1, \
+ &SpxGlobalInterlock); \
+ SpxConnFileRef (_ConnFile); \
+ }
+
+#define SpxConnFileLockReference(_ConnFile, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_ConnFile)->scf_RefTypes[_Type], \
+ 1, \
+ &SpxGlobalInterlock); \
+ SpxConnFileLockRef (_ConnFile); \
+ }
+
+#define SpxConnFileDereference(_ConnFile, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_ConnFile)->scf_RefTypes[_Type], \
+ (ULONG)-1, \
+ &SpxGlobalInterlock); \
+ SpxConnFileDeref (_ConnFile); \
+ }
+
+#define SpxConnFileReferenceByCtx(_pAddrFile, _Ctx, _ppConnFile, _pStatus) \
+ { \
+ CTELockHandle _lockHandle; \
+ CTEGetLock((_pAddrFile)->saf_AddrLock, &(_lockHandle)); \
+ SpxConnFileRefByCtxLock((_pAddrFile), (_Ctx), (_ppConnFile),(_pStatus));\
+ CTEFreeLock((_pAddrFile)->saf_AddrLock, (_lockHandle)); \
+ }
+
+#define SpxConnFileReferenceByCtxLock(_pAddrFile, _Ctx, _ppConnFile, _pStatus) \
+ SpxConnFileRefByCtxLock((_pAddrFile), (_Ctx), (_ppConnFile),(_pStatus));
+
+#define SpxConnFileReferenceById(_ConnId, _ppConnFile, _pStatus) \
+ { \
+ CTELockHandle _l; \
+ CTEGetLock(&SpxDevice->dev_Lock, &(_l)); \
+ SpxConnFileRefByIdLock(_ConnId, _ppConnFile, _pStatus); \
+ CTEFreeLock(&SpxDevice->dev_Lock, _l); \
+ }
+
+#define SpxConnFileTransferReference(_ConnFile, _OldType, _NewType) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_ConnFile)->scf_RefTypes[_NewType], \
+ 1, \
+ &SpxGlobalInterlock); \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_ConnFile)->scf_RefTypes[_OldType], \
+ (ULONG)-1, \
+ &SpxGlobalInterlock); \
+ }
+
+#else // DBG
+
+#define SpxConnFileReference(_ConnFile, _Type) \
+ SPX_ADD_ULONG( \
+ &(_ConnFile)->scf_RefCount, \
+ 1, \
+ &(_ConnFile)->scf_Lock)
+
+#define SpxConnFileLockReference(_ConnFile, _Type) \
+ SPX_ADD_ULONG( \
+ &(_ConnFile)->scf_RefCount, \
+ 1, \
+ &(_ConnFile)->scf_Lock);
+
+#define SpxConnFileDereference(_ConnFile, _Type) \
+ { \
+ SpxConnFileDeref(_ConnFile); \
+ }
+
+#define SpxConnFileReferenceByCtx(_pAddrFile, _Ctx, _ppConnFile, _pStatus) \
+ { \
+ CTELockHandle _lockHandle; \
+ CTEGetLock((_pAddrFile)->saf_AddrLock, &(_lockHandle)); \
+ SpxConnFileRefByCtxLock((_pAddrFile), (_Ctx), (_ppConnFile),(_pStatus));\
+ CTEFreeLock((_pAddrFile)->saf_AddrLock, (_lockHandle)); \
+ }
+
+#define SpxConnFileReferenceByCtxLock(_pAddrFile, _Ctx, _ppConnFile, _pStatus) \
+ SpxConnFileRefByCtxLock((_pAddrFile), (_Ctx), (_ppConnFile),(_pStatus));
+
+#define SpxConnFileReferenceById(_ConnId, _ppConnFile, _pStatus) \
+ { \
+ CTELockHandle _lockHandle; \
+ CTEGetLock(&SpxDevice->dev_Lock, &(_lockHandle)); \
+ SpxConnFileRefByIdLock(_ConnId, _ppConnFile, _pStatus); \
+ CTEFreeLock(&SpxDevice->dev_Lock, (_lockHandle)); \
+ }
+
+#define SpxConnFileTransferReference(_ConnFile, _OldType, _NewType)
+
+#endif // DBG
+
+
+// Set the packet size. If we are spx1 or spx2 and !neg, check if we are different
+// nets, set to min then, else use the size indicated by IPX. If we are spx2, just
+// set it to our local max.
+//
+// Also always even out packet size and round down. This solves an issue with
+// data size needing to be even for some novell 802.2 clients.
+//
+// Fix after beta2 for tokring using receive size. Only if spx2 and neg.
+#if defined(_PNP_POWER)
+#define SPX_MAX_PKT_SIZE(pSpxConnFile, fSpx2Neg, fSpx2, pRemNet) \
+ { \
+ if (!fSpx2 && PARAM(CONFIG_BACKCOMP_SPX)) { \
+ (pSpxConnFile)->scf_MaxPktSize = SPX_MAX_PACKET; \
+ } \
+ else { \
+ IPX_LINE_INFO _i; \
+ \
+ (VOID)(*IpxQuery)( \
+ IPX_QUERY_LINE_INFO, \
+ &(pSpxConnFile)->scf_LocalTarget.NicHandle, \
+ &(_i), \
+ sizeof(IPX_LINE_INFO), \
+ NULL); \
+ \
+ (pSpxConnFile)->scf_MaxPktSize = (_i).MaximumPacketSize; \
+ if (!fSpx2Neg) \
+ { \
+ (pSpxConnFile)->scf_MaxPktSize = (_i).MaximumSendSize; \
+ } \
+ \
+ if ((pSpxConnFile)->scf_MaxPktSize < SPX_MAX_PACKET) \
+ { \
+ (pSpxConnFile)->scf_MaxPktSize = SPX_MAX_PACKET; \
+ } \
+ \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: Nets %lx.%lx Max Pkt %d\n", \
+ (*(UNALIGNED ULONG *)(pRemNet)), \
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network, \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ DBGPRINT(CONNECT, DBG, \
+ ("%s : %d.%d\n", __FILE__, __LINE__, fSpx2Neg)); \
+ \
+ if ((!fSpx2Neg) && \
+ ((*(UNALIGNED ULONG *)(pRemNet)) != 0) && \
+ ((*(UNALIGNED ULONG *)SpxDevice->dev_Network) != 0) && \
+ ((*(UNALIGNED ULONG *)(pRemNet)) != \
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network)) \
+ { \
+ if (PARAM(CONFIG_ROUTER_MTU) != 0) \
+ { \
+ DBGPRINT(CONNECT, ERR, \
+ ("SPX_MAX_PKT_SIZE: PARAM %lx Max Pkt %lx\n", \
+ PARAM(CONFIG_ROUTER_MTU), \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ \
+ (pSpxConnFile)->scf_MaxPktSize = \
+ (USHORT)(MIN(PARAM(CONFIG_ROUTER_MTU), \
+ (ULONG)((pSpxConnFile)->scf_MaxPktSize)));\
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_MaxPktSize = SPX_MAX_PACKET; \
+ } \
+ \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: Nets %lx.%lx Max Pkt %d\n", \
+ (*(UNALIGNED ULONG *)(pRemNet)), \
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network, \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: LineInfo Pkt %d\n", \
+ (_i).MaximumSendSize)); \
+ } \
+ } \
+ (pSpxConnFile)->scf_MaxPktSize &= ~((USHORT)1); \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: %lx.%d\n", \
+ (pSpxConnFile)->scf_MaxPktSize, \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ }
+#else
+#define SPX_MAX_PKT_SIZE(pSpxConnFile, fSpx2Neg, fSpx2, pRemNet) \
+ { \
+ if (!fSpx2 && PARAM(CONFIG_BACKCOMP_SPX)) { \
+ (pSpxConnFile)->scf_MaxPktSize = SPX_MAX_PACKET; \
+ } \
+ else { \
+ IPX_LINE_INFO _i; \
+ \
+ (VOID)(*IpxQuery)( \
+ IPX_QUERY_LINE_INFO, \
+ (pSpxConnFile)->scf_LocalTarget.NicId, \
+ &(_i), \
+ sizeof(IPX_LINE_INFO), \
+ NULL); \
+ \
+ (pSpxConnFile)->scf_MaxPktSize = (_i).MaximumPacketSize; \
+ if (!fSpx2Neg) \
+ { \
+ (pSpxConnFile)->scf_MaxPktSize = (_i).MaximumSendSize; \
+ } \
+ \
+ if ((pSpxConnFile)->scf_MaxPktSize < SPX_MAX_PACKET) \
+ { \
+ (pSpxConnFile)->scf_MaxPktSize = SPX_MAX_PACKET; \
+ } \
+ \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: Nets %lx.%lx Max Pkt %d\n", \
+ (*(UNALIGNED ULONG *)(pRemNet)), \
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network, \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ DBGPRINT(CONNECT, DBG, \
+ ("%s : %d.%d\n", __FILE__, __LINE__, fSpx2Neg)); \
+ \
+ if ((!fSpx2Neg) && \
+ ((*(UNALIGNED ULONG *)(pRemNet)) != 0) && \
+ ((*(UNALIGNED ULONG *)SpxDevice->dev_Network) != 0) && \
+ ((*(UNALIGNED ULONG *)(pRemNet)) != \
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network)) \
+ { \
+ if (PARAM(CONFIG_ROUTER_MTU) != 0) \
+ { \
+ DBGPRINT(CONNECT, ERR, \
+ ("SPX_MAX_PKT_SIZE: PARAM %lx Max Pkt %lx\n", \
+ PARAM(CONFIG_ROUTER_MTU), \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ \
+ (pSpxConnFile)->scf_MaxPktSize = \
+ (USHORT)(MIN(PARAM(CONFIG_ROUTER_MTU), \
+ (ULONG)((pSpxConnFile)->scf_MaxPktSize)));\
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_MaxPktSize = SPX_MAX_PACKET; \
+ } \
+ \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: Nets %lx.%lx Max Pkt %d\n", \
+ (*(UNALIGNED ULONG *)(pRemNet)), \
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network, \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: LineInfo Pkt %d\n", \
+ (_i).MaximumSendSize)); \
+ } \
+ } \
+ (pSpxConnFile)->scf_MaxPktSize &= ~((USHORT)1); \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: %lx.%d\n", \
+ (pSpxConnFile)->scf_MaxPktSize, \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ }
+#endif _PNP_POWER
+
+#if DBG
+#define SPX_SENDPACKET(pSpxConnFile, pNdisPkt, pSendResd) \
+ { \
+ NDIS_STATUS _n; \
+ \
+ ++SpxDevice->dev_Stat.PacketsSent; \
+ \
+ _n = (*IpxSendPacket)( \
+ &(pSpxConnFile)->scf_LocalTarget, \
+ (pNdisPkt), \
+ (pSendResd)->sr_Len, \
+ (pSendResd)->sr_HdrLen); \
+ \
+ if (_n != NDIS_STATUS_PENDING) \
+ { \
+ if (_n != NDIS_STATUS_SUCCESS) \
+ { \
+ DBGPRINT(SEND, ERR, \
+ ("SPX_SENDPACKET: Failed with %lx in %s.%lx\n", \
+ _n, __FILE__, __LINE__)); \
+ } \
+ \
+ SpxSendComplete( \
+ (pNdisPkt), \
+ _n); \
+ } \
+ }
+
+#define SPX_SENDACK(pSpxConnFile, pNdisPkt, pSendResd) \
+ { \
+ NDIS_STATUS _n; \
+ \
+ ++SpxDevice->dev_Stat.PacketsSent; \
+ \
+ _n = (*IpxSendPacket)( \
+ &(pSpxConnFile)->scf_AckLocalTarget, \
+ (pNdisPkt), \
+ (pSendResd)->sr_Len, \
+ (pSendResd)->sr_HdrLen); \
+ \
+ if (_n != NDIS_STATUS_PENDING) \
+ { \
+ if (_n != NDIS_STATUS_SUCCESS) \
+ { \
+ DBGPRINT(SEND, ERR, \
+ ("SPX_SENDPACKET: Failed with %lx in %s.%lx\n", \
+ _n, __FILE__, __LINE__)); \
+ } \
+ \
+ SpxSendComplete( \
+ (pNdisPkt), \
+ _n); \
+ } \
+ }
+
+#else // DBG
+#define SPX_SENDPACKET(pSpxConnFile, pNdisPkt, pSendResd) \
+ { \
+ NDIS_STATUS _n; \
+ \
+ ++SpxDevice->dev_Stat.PacketsSent; \
+ \
+ _n = (*IpxSendPacket)( \
+ &(pSpxConnFile)->scf_LocalTarget, \
+ (pNdisPkt), \
+ (pSendResd)->sr_Len, \
+ (pSendResd)->sr_HdrLen); \
+ \
+ if (_n != NDIS_STATUS_PENDING) \
+ { \
+ SpxSendComplete( \
+ (pNdisPkt), \
+ _n); \
+ } \
+ }
+#define SPX_SENDACK(pSpxConnFile, pNdisPkt, pSendResd) \
+ { \
+ NDIS_STATUS _n; \
+ \
+ ++SpxDevice->dev_Stat.PacketsSent; \
+ \
+ _n = (*IpxSendPacket)( \
+ &(pSpxConnFile)->scf_AckLocalTarget, \
+ (pNdisPkt), \
+ (pSendResd)->sr_Len, \
+ (pSendResd)->sr_HdrLen); \
+ \
+ if (_n != NDIS_STATUS_PENDING) \
+ { \
+ SpxSendComplete( \
+ (pNdisPkt), \
+ _n); \
+ } \
+ }
+
+#endif // DBG
+
+#define SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile) \
+ { \
+ if (!SPX_CONN_FLAG( \
+ (pSpxConnFile), \
+ SPX_CONNFILE_RECVQ)) \
+ { \
+ SPX_CONN_SETFLAG((pSpxConnFile), SPX_CONNFILE_RECVQ); \
+ SpxConnFileLockReference(pSpxConnFile, CFREF_RECV); \
+ SPX_QUEUE_TAIL_RECVLIST(pSpxConnFile); \
+ } \
+ }
+
+#define SPX_QUEUE_TAIL_PKTLIST(pSpxConnFile) \
+ { \
+ if (SpxPktConnList.pcl_Tail) \
+ { \
+ SpxPktConnList.pcl_Tail->scf_PktNext = pSpxConnFile; \
+ SpxPktConnList.pcl_Tail = pSpxConnFile; \
+ } \
+ else \
+ { \
+ SpxPktConnList.pcl_Tail = \
+ SpxPktConnList.pcl_Head = pSpxConnFile; \
+ } \
+ }
+
+#define SPX_QUEUE_TAIL_RECVLIST(pSpxConnFile) \
+ { \
+ if (SpxRecvConnList.pcl_Tail) \
+ { \
+ SpxRecvConnList.pcl_Tail->scf_ProcessRecvNext = pSpxConnFile; \
+ SpxRecvConnList.pcl_Tail = pSpxConnFile; \
+ } \
+ else \
+ { \
+ SpxRecvConnList.pcl_Tail = \
+ SpxRecvConnList.pcl_Head = pSpxConnFile; \
+ } \
+ }
+
+
diff --git a/private/ntos/tdi/isnp/spx/h/spxdev.h b/private/ntos/tdi/isnp/spx/h/spxdev.h
new file mode 100644
index 000000000..30c0adae5
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/h/spxdev.h
@@ -0,0 +1,204 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxdev.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ SPX module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba ) Original Version
+ Nikhil Kamkolkar (nikhilk) 17-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+
+// Hash buckets for SPX_ADDR done using socket number
+#define NUM_SPXADDR_HASH_BUCKETS 8
+#define NUM_SPXADDR_HASH_MASK 7
+#define NUM_SPXCONN_HASH_BUCKETS 8
+#define NUM_SPXCONN_HASH_MASK 7
+
+// This structure defines the per-device structure for SPX
+// (one of these is allocated globally).
+#define DREF_CREATE 0
+#define DREF_LOADED 1
+#define DREF_ADAPTER 2
+#define DREF_ADDRESS 3
+#define DREF_ORPHAN 4
+
+#define DREF_TOTAL 5
+
+typedef struct _DEVICE {
+
+ DEVICE_OBJECT dev_DevObj; // the I/O system's device object.
+
+#if DBG
+ ULONG dev_RefTypes[DREF_TOTAL];
+#endif
+
+ CSHORT dev_Type; // type of this structure
+ USHORT dev_Size; // size of this structure
+
+#if DBG
+ UCHAR dev_Signature1[4]; // contains "SPX1"
+#endif
+
+ // activity count/this provider.
+ LONG dev_RefCount;
+ UCHAR dev_State;
+
+ // number of adapters IPX is bound to.
+ USHORT dev_Adapters;
+
+ // GLOBAL lock for reference count (used in ExInterlockedXxx calls).
+ CTELock dev_Interlock;
+ CTELock dev_Lock;
+
+ // Hash table of lists of addresses opened on this device
+ struct _SPX_ADDR * dev_AddrHashTable[NUM_SPXADDR_HASH_BUCKETS];
+
+ // List of all active connections, later this be a tree.
+ struct _SPX_CONN_FILE * dev_GlobalActiveConnList[NUM_SPXCONN_HASH_BUCKETS];
+ USHORT dev_NextConnId;
+
+ // Other configuration parameters.
+ // Where the current socket allocation is.
+ USHORT dev_CurrentSocket;
+
+ // Our node and network.
+ UCHAR dev_Network[4];
+ UCHAR dev_Node[6];
+
+ // Pointer to the config information from registry
+ PCONFIG dev_ConfigInfo;
+
+ // Control channel identifier
+ ULONG dev_CcId;
+
+ // These are kept around for error logging, and stored right
+ // after this structure.
+ PWCHAR dev_DeviceName;
+#if defined(_PNP_POWER)
+ USHORT dev_DeviceNameLen;
+#else
+ ULONG dev_DeviceNameLen;
+#endif _PNP_POWER
+
+#if DBG
+ UCHAR dev_Signature2[4]; // contains "SPX2"
+#endif
+
+ // Handle to ndis buffer pool for spx stack.
+ NDIS_HANDLE dev_NdisBufferPoolHandle;
+
+ // registration handle with tdi clients.
+#if defined(_PNP_POWER)
+ HANDLE dev_TdiRegistrationHandle;
+#endif _PNP_POWER
+
+ // This interlock is used to guard access to the statistics
+ // define below.
+ KSPIN_LOCK dev_StatInterlock; // for ULONG quantities
+ KSPIN_LOCK dev_StatSpinLock; // for LARGE_INTEGER quantities
+
+ // Counters for most of the statistics that SPX maintains;
+ // some of these are kept elsewhere. Including the structure
+ // itself wastes a little space but ensures that the alignment
+ // inside the structure is correct.
+ TDI_PROVIDER_STATISTICS dev_Stat;
+
+ // This resource guards access to the ShareAccess
+ // and SecurityDescriptor fields in addresses.
+ ERESOURCE dev_AddrResource;
+
+ // The following structure contains statistics counters for use
+ // by TdiQueryInformation and TdiSetInformation. They should not
+ // be used for maintenance of internal data structures.
+ TDI_PROVIDER_INFO dev_ProviderInfo; // information about this provider.
+
+} DEVICE, * PDEVICE;
+
+// device state definitions
+#if defined(_PNP_POWER)
+#define DEVICE_STATE_CLOSED 0x00 // Initial state
+#define DEVICE_STATE_LOADED 0x01 // Loaded and bound to IPX but no adapters
+#define DEVICE_STATE_OPEN 0x02 // Fully operational
+#define DEVICE_STATE_STOPPING 0x03 // Unload has been initiated, The I/O system
+ // will not call us until nobody above has Netbios open.
+#else
+#define DEVICE_STATE_CLOSED 0x00
+#define DEVICE_STATE_OPEN 0x01
+#define DEVICE_STATE_STOPPING 0x02
+#endif _PNP_POWER
+
+
+// SPX device name
+#define SPX_DEVICE_NAME L"\\Device\\NwlnkSpx"
+
+#define SPX_TDI_RESOURCES 9
+
+
+// MACROS
+#if DBG
+
+#define SpxReferenceDevice(_Device, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_Device)->dev_RefTypes[_Type], \
+ 1, \
+ &SpxGlobalInterlock); \
+ \
+ (VOID)InterlockedIncrement ( \
+ &(_Device)->dev_RefCount); \
+ }
+
+#define SpxDereferenceDevice(_Device, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_Device)->dev_RefTypes[_Type], \
+ (ULONG)-1, \
+ &SpxGlobalInterlock); \
+ SpxDerefDevice (_Device); \
+ }
+
+#else
+
+#define SpxReferenceDevice(_Device, _Type) \
+ { \
+ (VOID)InterlockedIncrement ( \
+ &(_Device)->dev_RefCount); \
+ }
+
+#define SpxDereferenceDevice(_Device, _Type) \
+ SpxDerefDevice (_Device)
+
+#endif
+
+// EXPORTED ROUTINES
+
+VOID
+SpxDestroyDevice(
+ IN PDEVICE Device);
+
+VOID
+SpxDerefDevice(
+ IN PDEVICE Device);
+
+NTSTATUS
+SpxInitCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN OUT PDEVICE *DevicePtr);
diff --git a/private/ntos/tdi/isnp/spx/h/spxerror.h b/private/ntos/tdi/isnp/spx/h/spxerror.h
new file mode 100644
index 000000000..761342512
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/h/spxerror.h
@@ -0,0 +1,246 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ spxerror.h
+
+Abstract:
+
+ This module contains some error definitions for spx.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+
+Notes: Tab stop: 4
+--*/
+
+// Define the modules names for SPX - use the high bits.
+#define SPXDRVR 0x00010000
+#define SPXREG 0x00020000
+#define SPXDEV 0x00030000
+#define SPXBIND 0x00040000
+#define SPXRECV 0x00050000
+#define SPXSEND 0x00060000
+#define SPXTIMER 0x00070000
+#define SPXERROR 0x00080000
+#define SPXPKT 0x00090000
+#define SPXUTILS 0x000a0000
+#define SPXCPKT 0x000b0000
+#define SPXCONN 0x000c0000
+#define SPXADDR 0x000d0000
+#define SPXCUTIL 0x000e0000
+#define SPXINIT 0x000f0000
+#define SPXMEM 0x00100000
+#define SPXQUERY 0x00200000
+
+
+// DEBUGGING SUPPORT:
+// Debugging messages are provided per-subsystem defined here, and within
+// the subsystems, there are 4 levels of messages.
+//
+// The four levels of debug messages are:
+//
+// INFO: Informational messages, eg., entry exit in routines
+// DBG: Used when debugging some msgs are turned from info to dbg
+// WARN: Something went wrong, but its not an error, eg., packet was not ours
+// ERR: Error situations, but we can still run if a retry happens
+// FATAL: In this situation, the driver is not operational
+
+#define DBG_LEVEL_INFO 0x4000
+#define DBG_LEVEL_DBG 0x5000
+#define DBG_LEVEL_DBG1 0x5001
+#define DBG_LEVEL_DBG2 0x5002
+#define DBG_LEVEL_DBG3 0x5003
+#define DBG_LEVEL_WARN 0x6000
+#define DBG_LEVEL_ERR 0x7000
+#define DBG_LEVEL_FATAL 0x8000
+
+// SUBSYSTEMS
+#define DBG_COMP_DEVICE 0x00000001
+#define DBG_COMP_CREATE 0x00000002
+#define DBG_COMP_ADDRESS 0x00000004
+#define DBG_COMP_SEND 0x00000008
+#define DBG_COMP_NDIS 0x00000010
+#define DBG_COMP_RECEIVE 0x00000020
+#define DBG_COMP_CONFIG 0x00000040
+#define DBG_COMP_PACKET 0x00000080
+#define DBG_COMP_RESOURCES 0x00000100
+#define DBG_COMP_BIND 0x00000200
+#define DBG_COMP_UNLOAD 0x00000400
+#define DBG_COMP_DUMP 0x00000800
+#define DBG_COMP_REFCOUNTS 0x00001000
+#define DBG_COMP_SYSTEM 0x00002000
+#define DBG_COMP_CRITSEC 0x00004000
+#define DBG_COMP_UTILS 0x00008000
+#define DBG_COMP_TDI 0x00010000
+#define DBG_COMP_CONNECT 0x00020000
+#define DBG_COMP_DISC 0x00040000
+#define DBG_COMP_ACTION 0x00080000
+#define DBG_COMP_STATE 0x00100000
+
+#define DBG_COMP_MOST (DBG_COMP_DEVICE | \
+ DBG_COMP_CREATE | \
+ DBG_COMP_ADDRESS | \
+ DBG_COMP_SEND | \
+ DBG_COMP_NDIS | \
+ DBG_COMP_RECEIVE | \
+ DBG_COMP_CONFIG | \
+ DBG_COMP_PACKET | \
+ DBG_COMP_RESOURCES | \
+ DBG_COMP_BIND | \
+ DBG_COMP_UNLOAD | \
+ DBG_COMP_DUMP | \
+ DBG_COMP_REFCOUNTS | \
+ DBG_COMP_SYSTEM | \
+ DBG_COMP_CRITSEC | \
+ DBG_COMP_UTILS | \
+ DBG_COMP_TDI | \
+ DBG_COMP_CONNECT | \
+ DBG_COMP_DISC | \
+ DBG_COMP_ACTION | \
+ DBG_COMP_STATE)
+
+
+// More debugging support. These values define the dumping components.
+// There are a max of 32 such components that can be defined. Each of
+// these are associated with a dump routine. It one is specified and
+// enabled, periodically it is called. It is upto that component to
+// decide what it wants to do
+
+#define DBG_DUMP_DEF_INTERVAL 30 // In Seconds
+
+// This defines the number of times an error has to happen consecutively before
+// it gets logged again.
+#define ERROR_CONSEQ_FREQ 200
+#define ERROR_CONSEQ_TIME (60*30) // 30 minutes
+
+#ifdef DBG
+typedef VOID (*DUMP_ROUTINE)(VOID);
+
+extern
+BOOLEAN
+SpxDumpComponents(
+ IN PVOID Context);
+
+#endif
+
+//
+// PROTOTYPES
+//
+
+BOOLEAN
+SpxFilterErrorLogEntry(
+ IN NTSTATUS UniqueErrorCode,
+ IN NTSTATUS NtStatusCode,
+ IN PVOID RawDataBuf OPTIONAL,
+ IN LONG RawDataLen);
+VOID
+SpxWriteResourceErrorLog(
+ IN PDEVICE Device,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue);
+
+VOID
+SpxWriteGeneralErrorLog(
+ IN PDEVICE Device,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN PVOID RawDataBuf OPTIONAL,
+ IN LONG RawDataLen);
+
+
+//
+// MACROS
+//
+
+#if DBG
+#define LOG_ERROR(Error, NtStatus, SecondString, RawData, RawDataLen) \
+ { \
+ SpxWriteGeneralErrorLog( \
+ SpxDevice, \
+ Error, \
+ FILENUM | __LINE__, \
+ NtStatus, \
+ SecondString, \
+ RawData, \
+ RawDataLen); \
+ }
+
+#define RES_LOG_ERROR(BytesNeeded) \
+ { \
+ SpxWriteResourceErrorLog( \
+ SpxDevice, \
+ BytesNeeded, \
+ FILENUM | __LINE__); \
+ }
+
+#else
+
+#define LOG_ERROR(Error, NtStatus, SecondString, RawData, RawDataLen) \
+ { \
+ SpxWriteGeneralErrorLog( \
+ SpxDevice, \
+ Error, \
+ FILENUM | __LINE__, \
+ NtStatus, \
+ SecondString, \
+ RawData, \
+ RawDataLen); \
+ }
+
+#define RES_LOG_ERROR(BytesNeeded) \
+ { \
+ SpxWriteResourceErrorLog( \
+ SpxDevice, \
+ BytesNeeded, \
+ FILENUM | __LINE__); \
+ }
+
+#endif
+
+
+#if DBG
+
+#define DBGPRINT(Component, Level, Fmt) \
+ { \
+ if (((DBG_LEVEL_ ## Level) >= SpxDebugLevel) && \
+ (SpxDebugSystems & (DBG_COMP_ ## Component))) \
+ { \
+ DbgPrint("SPX: "); \
+ DbgPrint Fmt; \
+ } \
+ }
+
+#define DBGBRK(Level) \
+ { \
+ if ((DBG_LEVEL_ ## Level) >= SpxDebugLevel) \
+ DbgBreakPoint(); \
+ }
+
+#define TMPLOGERR() \
+ { \
+ DBGPRINT(MOST, ERR, \
+ ("TempErrLog: %s, Line %ld\n", __FILE__, __LINE__)); \
+ }
+
+#else
+#define DBGPRINT(Component, Level, Fmt)
+#define DBGBRK(Level)
+#define TMPLOGERR()
+#endif
+
+extern
+VOID
+SpxWriteErrorLogEntry(
+ IN NTSTATUS UniqueErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS NtStatusCode,
+ IN PVOID RawDataBuf OPTIONAL,
+ IN LONG RawDataLen);
diff --git a/private/ntos/tdi/isnp/spx/h/spxmem.h b/private/ntos/tdi/isnp/spx/h/spxmem.h
new file mode 100644
index 000000000..717c69a6b
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/h/spxmem.h
@@ -0,0 +1,142 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxmem.h
+
+Abstract:
+
+ This module contains memory management routines.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 17-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+
+#define QWORDSIZEBLOCK(Size) (((Size)+sizeof(LARGE_INTEGER)-1) & ~(sizeof(LARGE_INTEGER)-1))
+#define SPX_MEMORY_SIGNATURE *(PULONG)"SPXM"
+#define ZEROED_MEMORY_TAG 0xF0000000
+#define SPX_TAG *((PULONG)"SPX ")
+
+//
+// Definitions for the block management package
+//
+typedef UCHAR BLKID;
+
+// Add a BLKID_xxx and an entry to atalkBlkSize for every block client
+#define BLKID_TIMERLIST (BLKID)0
+#define BLKID_NDISSEND (BLKID)1
+#define BLKID_NDISRECV (BLKID)2
+#define NUM_BLKIDS (BLKID)3
+
+typedef struct _BLK_CHUNK
+{
+ struct _BLK_CHUNK * bc_Next; // Pointer to next in the link
+ SHORT bc_NumFrees; // Number of free blocks in the chunk
+ UCHAR bc_Age; // Number of invocations since the chunk free
+ BLKID bc_BlkId; // Id of the block
+ struct _BLK_HDR * bc_FreeHead; // Head of the list of free blocks
+
+#ifndef SPX_OWN_PACKETS
+ PVOID bc_ChunkCtx; // Used to store pool header if not own
+ // packets
+#else
+ PVOID bc_Padding; // Keep the header 16 bytes
+#endif
+
+ // This is followed by an array of N blks of size M such that the block header
+ // is exactly spxChunkSize[i]
+
+} BLK_CHUNK, *PBLK_CHUNK;
+
+typedef struct _BLK_HDR
+{
+ union
+ {
+ struct _BLK_HDR * bh_Next; // Valid when it is free
+ struct _BLK_CHUNK * bh_pChunk; // The parent chunk to which this blocks belong
+ // valid when it is allocated
+ };
+ PVOID bh_Padding; // Make the header 8 bytes
+} BLK_HDR, *PBLK_HDR;
+
+#define BC_OVERHEAD (8+8) // LARGE_INTEGER for SpxAllocMemory() header and
+ // POOL_HEADER for ExAllocatePool() header
+
+#define BLOCK_POOL_TIMER 1000 // Check interval (1 sec)
+#define MAX_BLOCK_POOL_AGE 3 // # of timer invocations before free
+
+ULONG
+spxBPAgePool(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown);
+
+
+#ifdef TRACK_MEMORY_USAGE
+
+#define SpxAllocateMemory(Size) SpxAllocMem((Size), FILENUM | __LINE__)
+
+extern
+PVOID
+SpxAllocMem(
+ IN ULONG Size,
+ IN ULONG FileLine
+);
+
+extern
+VOID
+SpxTrackMemoryUsage(
+ IN PVOID pMem,
+ IN BOOLEAN Alloc,
+ IN ULONG FileLine
+);
+
+#else
+
+#define SpxAllocateMemory(Size) SpxAllocMem(Size)
+#define SpxTrackMemoryUsage(pMem, Alloc, FileLine)
+
+extern
+PVOID
+SpxAllocMem(
+ IN ULONG Size
+);
+
+#endif // TRACK_MEMORY_USAGE
+
+VOID
+SpxFreeMemory(
+ IN PVOID pBuf);
+
+#define SpxAllocateZeroedMemory(Size) SpxAllocateMemory((Size) | ZEROED_MEMORY_TAG)
+
+
+extern
+NTSTATUS
+SpxInitMemorySystem(
+ IN PDEVICE pSpxDevice);
+
+extern
+VOID
+SpxDeInitMemorySystem(
+ IN PDEVICE pSpxDevice);
+
+PVOID
+SpxBPAllocBlock(
+ IN BLKID BlockId);
+
+VOID
+SpxBPFreeBlock(
+ IN PVOID pBlock,
+ IN BLKID BlockId);
+
diff --git a/private/ntos/tdi/isnp/spx/h/spxntdef.h b/private/ntos/tdi/isnp/spx/h/spxntdef.h
new file mode 100644
index 000000000..60f9c9e54
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/h/spxntdef.h
@@ -0,0 +1,72 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxntdef.h
+
+Abstract:
+
+ Missing nt definitions in ntddk.h
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+NTSTATUS
+NTAPI
+NtCreateFile(
+ OUT PHANDLE FileHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN PLARGE_INTEGER AllocationSize OPTIONAL,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN PVOID EaBuffer OPTIONAL,
+ IN ULONG EaLength
+ );
+
+NTSTATUS
+NTAPI
+NtClose(
+ IN HANDLE Handle
+ );
+
+NTSTATUS
+NTAPI
+NtDeviceIoControlFile(
+ IN HANDLE FileHandle,
+ IN HANDLE Event OPTIONAL,
+ IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+ IN PVOID ApcContext OPTIONAL,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN ULONG IoControlCode,
+ IN PVOID InputBuffer OPTIONAL,
+ IN ULONG InputBufferLength,
+ OUT PVOID OutputBuffer OPTIONAL,
+ IN ULONG OutputBufferLength
+ );
+
+NTSTATUS
+NTAPI
+NtWaitForSingleObject(
+ IN HANDLE Handle,
+ IN BOOLEAN Alertable,
+ IN PLARGE_INTEGER Timeout OPTIONAL
+ );
+
+
diff --git a/private/ntos/tdi/isnp/spx/h/spxpkt.h b/private/ntos/tdi/isnp/spx/h/spxpkt.h
new file mode 100644
index 000000000..b643ed95b
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/h/spxpkt.h
@@ -0,0 +1,466 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxpkt.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+// Use our own NDIS packets
+#define SPX_OWN_PACKETS 1
+
+// Offsets into the IPX header
+#define IPX_HDRSIZE 30 // Size of the IPX header
+#define IPX_CHECKSUM 0 // Checksum
+#define IPX_LENGTH 2 // Length
+#define IPX_XPORTCTL 4 // Transport Control
+#define IPX_PKTTYPE 5 // Packet Type
+#define IPX_DESTADDR 6 // Dest. Address (Total)
+#define IPX_DESTNET 6 // Dest. Network Address
+#define IPX_DESTNODE 10 // Dest. Node Address
+#define IPX_DESTSOCK 16 // Dest. Socket Number
+#define IPX_SRCADDR 18 // Source Address (Total)
+#define IPX_SRCNET 18 // Source Network Address
+#define IPX_SRCNODE 22 // Source Node Address
+#define IPX_SRCSOCK 28 // Source Socket Number
+
+#define IPX_NET_LEN 4
+#define IPX_NODE_LEN 6
+
+
+#include <packon.h>
+
+// Definition of the IPX/SPX header.
+typedef struct _IPXSPX_HEADER
+{
+ USHORT hdr_CheckSum;
+ USHORT hdr_PktLen;
+ UCHAR hdr_XportCtrl;
+ UCHAR hdr_PktType;
+ UCHAR hdr_DestNet[4];
+ UCHAR hdr_DestNode[6];
+ USHORT hdr_DestSkt;
+ UCHAR hdr_SrcNet[4];
+ UCHAR hdr_SrcNode[6];
+ USHORT hdr_SrcSkt;
+
+ // SPX Header Elements
+ UCHAR hdr_ConnCtrl;
+ UCHAR hdr_DataType;
+ USHORT hdr_SrcConnId;
+ USHORT hdr_DestConnId;
+ USHORT hdr_SeqNum;
+ USHORT hdr_AckNum;
+ USHORT hdr_AllocNum;
+
+ // For non-CR SPXII packets only
+ USHORT hdr_NegSize;
+
+} IPXSPX_HDR, *PIPXSPX_HDR;
+
+#include <packoff.h>
+
+// NDIS Packet size
+#define NDIS_PACKET_SIZE 48
+
+// Minimum header size (doesnt include neg size)
+#define MIN_IPXSPX_HDRSIZE (sizeof(IPXSPX_HDR) - sizeof(USHORT))
+#define MIN_IPXSPX2_HDRSIZE sizeof(IPXSPX_HDR)
+#define SPX_CR_PKTLEN 42
+
+// SPX packet type
+#define SPX_PKT_TYPE 0x5
+
+// Connection control fields
+#define SPX_CC_XHD 0x01
+#define SPX_CC_RES1 0x02
+#define SPX_CC_NEG 0x04
+#define SPX_CC_SPX2 0x08
+#define SPX_CC_EOM 0x10
+#define SPX_CC_ATN 0x20
+#define SPX_CC_ACK 0x40
+#define SPX_CC_SYS 0x80
+
+#define SPX_CC_CR (SPX_CC_ACK | SPX_CC_SYS)
+
+// Data stream types
+#define SPX2_DT_ORDREL 0xFD
+#define SPX2_DT_IDISC 0xFE
+#define SPX2_DT_IDISC_ACK 0xFF
+
+// Negotiation size
+#define SPX_MAX_PACKET 576
+#define SPX_NEG_MIN SPX_MAX_PACKET
+#define SPX_NEG_MAX 65535
+
+// No packet references connection. But if the sends are being aborted, and
+// the packet happens to be owned by ipx at the time, the pkt is dequeued from
+// conn, the ABORT flag is set and conn is referenced for packet.
+//
+// Send packet states
+// ABORT : Used for aborted packet. Calls AbortSendPkt().
+// IPXOWNS : Currently owned by ipx
+// FREEDATA: Frees the data associated with second ndis buffer desc
+// ACKREQ : Only for sequenced packets. Set by retry timer in packets it wants
+// resent (1 for spx1, all pending for spx2) with ack bit set.
+// DESTROY : Only for non-sequenced packets, dequeue packet from list and free.
+// REQ : For both seq/non-seq. A request is associated with the packet
+// SEQ : Packet is a sequenced packet.
+// LASTPKT : Packet is last packet comprising the request, if acked req is done.
+// EOM : Send EOM with the last packet for this request
+// ACKEDPKT: Send completion must only deref req with pkt and complete if zero.
+//
+
+#define SPX_SENDPKT_IDLE 0
+#define SPX_SENDPKT_ABORT 0x0002
+#define SPX_SENDPKT_IPXOWNS 0x0004
+#define SPX_SENDPKT_FREEDATA 0x0008
+#define SPX_SENDPKT_ACKREQ 0x0010
+#define SPX_SENDPKT_DESTROY 0x0020
+#define SPX_SENDPKT_REQ 0x0040
+#define SPX_SENDPKT_SEQ 0x0080
+#define SPX_SENDPKT_LASTPKT 0x0100
+#define SPX_SENDPKT_ACKEDPKT 0x0200
+#define SPX_SENDPKT_EOM 0x0400
+#define SPX_SENDPKT_REXMIT 0x0800
+
+// Packet types
+#define SPX_TYPE_CR 0x01
+#define SPX_TYPE_CRACK 0x02
+#define SPX_TYPE_SN 0x03
+#define SPX_TYPE_SNACK 0x04
+#define SPX_TYPE_SS 0x05
+#define SPX_TYPE_SSACK 0x06
+#define SPX_TYPE_RR 0x07
+#define SPX_TYPE_RRACK 0x08
+#define SPX_TYPE_IDISC 0x09
+#define SPX_TYPE_IDISCACK 0x0a
+#define SPX_TYPE_ORDREL 0x0b
+#define SPX_TYPE_ORDRELACK 0x0c
+#define SPX_TYPE_DATA 0x0d
+#define SPX_TYPE_DATAACK 0x0e
+#define SPX_TYPE_DATANACK 0x0f
+#define SPX_TYPE_PROBE 0x10
+
+// Definition of the protocol reserved field of a send packet.
+// BUGBUG: Make Len/HdrLen USHORTS, move to the end before the
+// sr_SentTime so we dont use padding space.
+typedef struct _SPX_SEND_RESD
+{
+ UCHAR sr_Id; // Set to SPX
+ UCHAR sr_Type; // What kind of packet
+ USHORT sr_State; // State of send packet
+ PVOID sr_Reserved1; // Needed by IPX
+ PVOID sr_Reserved2; // Needed by IPX
+#if defined(_PNP_POWER)
+ PVOID sr_Reserved[SEND_RESERVED_COMMON_SIZE-2]; // needed by IPX for local target
+#endif _PNP_POWER
+ ULONG sr_Len; // Length of packet
+ ULONG sr_HdrLen; // Included header length
+
+ struct _SPX_SEND_RESD * sr_Next; // Points to next packet
+ // in send queue in conn.
+ PREQUEST sr_Request; // request associated
+ ULONG sr_Offset; // Offset in mdl for sends
+
+#ifndef SPX_OWN_PACKETS
+ PVOID sr_FreePtr; // Ptr to use in free chunk
+#endif
+
+ struct _SPX_CONN_FILE * sr_ConnFile; // that this send is on
+ USHORT sr_SeqNum; // Seq num for seq pkts
+
+ // Quad word aligned.
+ LARGE_INTEGER sr_SentTime; // Time packet was sent
+ // Only valid for data pkt
+ // with ACKREQ set.
+
+} SPX_SEND_RESD, *PSPX_SEND_RESD;
+
+
+
+// Recv packet states
+#define SPX_RECVPKT_IDLE 0
+#define SPX_RECVPKT_BUFFERING 0x0001
+#define SPX_RECVPKT_IDISC 0x0002
+#define SPX_RECVPKT_ORD_DISC 0x0004
+#define SPX_RECVPKT_INDICATED 0x0008
+#define SPX_RECVPKT_SENDACK 0x0010
+#define SPX_RECVPKT_EOM 0x0020
+#define SPX_RECVPKT_IMMEDACK 0x0040
+
+#define SPX_RECVPKT_DISCMASK (SPX_RECVPKT_ORD_DISC | SPX_RECVPKT_IDISC)
+
+// Definition of the protocol reserved field of a receive packet.
+typedef struct _SPX_RECV_RESD
+{
+ UCHAR rr_Id; // Set to SPX
+ USHORT rr_State; // State of receive packet
+ struct _SPX_RECV_RESD * rr_Next; // Points to next packet
+ ULONG rr_DataOffset; // To indicate/copy from
+
+#ifndef SPX_OWN_PACKETS
+ PVOID rr_FreePtr; // Ptr to use in free chunk
+#endif
+
+#if DBG
+ USHORT rr_SeqNum; // Seq num of packet
+#endif
+
+ PREQUEST rr_Request; // request waiting on xfer
+ struct _SPX_CONN_FILE * rr_ConnFile; // that this recv is on
+
+} SPX_RECV_RESD, *PSPX_RECV_RESD;
+
+
+// Destination built as an assign of 3 ulongs.
+#define SpxBuildIpxHdr(pIpxSpxHdr, PktLen, pRemAddr, SrcSkt) \
+ { \
+ PBYTE pDestIpxAddr = (PBYTE)pIpxSpxHdr->hdr_DestNet; \
+ (pIpxSpxHdr)->hdr_CheckSum = 0xFFFF; \
+ PUTSHORT2SHORT((PUSHORT)(&(pIpxSpxHdr)->hdr_PktLen), (PktLen)); \
+ (pIpxSpxHdr)->hdr_XportCtrl = 0; \
+ (pIpxSpxHdr)->hdr_PktType = SPX_PKT_TYPE; \
+ *((UNALIGNED ULONG *)pDestIpxAddr) = \
+ *((UNALIGNED ULONG *)pRemAddr); \
+ *((UNALIGNED ULONG *)(pDestIpxAddr+4)) = \
+ *((UNALIGNED ULONG *)(pRemAddr+4)); \
+ *((UNALIGNED ULONG *)(pDestIpxAddr+8)) = \
+ *((UNALIGNED ULONG *)(pRemAddr+8)); \
+ *((UNALIGNED ULONG *)((pIpxSpxHdr)->hdr_SrcNet))= \
+ *((UNALIGNED ULONG *)(SpxDevice->dev_Network)); \
+ *((UNALIGNED ULONG *)((pIpxSpxHdr)->hdr_SrcNode)) = \
+ *((UNALIGNED ULONG *)SpxDevice->dev_Node); \
+ *((UNALIGNED USHORT *)((pIpxSpxHdr)->hdr_SrcNode+4)) = \
+ *((UNALIGNED USHORT *)(SpxDevice->dev_Node+4)); \
+ *((UNALIGNED USHORT *)&((pIpxSpxHdr)->hdr_SrcSkt)) = \
+ SrcSkt; \
+ }
+
+#define SpxCopyIpxAddr(pIpxSpxHdr, pDestIpxAddr) \
+ { \
+ PBYTE pRemAddr = (PBYTE)pIpxSpxHdr->hdr_SrcNet; \
+ *((UNALIGNED ULONG *)pDestIpxAddr) = \
+ *((UNALIGNED ULONG *)pRemAddr); \
+ *((UNALIGNED ULONG *)(pDestIpxAddr+4)) = \
+ *((UNALIGNED ULONG *)(pRemAddr+4)); \
+ *((UNALIGNED ULONG *)(pDestIpxAddr+8)) = \
+ *((UNALIGNED ULONG *)(pRemAddr+8)); \
+ }
+
+#ifndef SPX_OWN_PACKETS
+#define SpxAllocSendPacket(_Device,_SendPacket,_Status) \
+ { \
+ NDIS_HANDLE _Handle; \
+ NdisAllocatePacketPool(_Status, &(_Handle),1,sizeof(SPX_SEND_RESD));\
+ if (*(_Status) == NDIS_STATUS_SUCCESS) { \
+ NdisAllocatePacket(_Status, &(_SendPacket), (_Handle)); \
+ SEND_RESD(_SendPacket)->sr_PoolHandle = (_Handle); \
+ } \
+ }
+
+#define SpxAllocRecvPacket(_Device,_RecvPacket,_Status) \
+ { \
+ NDIS_HANDLE _Handle; \
+ NdisAllocatePacketPool(_Status, &(_Handle),1,sizeof(SPX_RECV_RESD));\
+ if (*(_Status) == NDIS_STATUS_SUCCESS) { \
+ NdisAllocatePacket(_Status, &(_RecvPacket), (_Handle)); \
+ RECV_RESD(_RecvPacket)->sr_PoolHandle = (_Handle); \
+ } \
+ }
+
+#define SpxFreeSendPacket(_Device,_Packet) \
+ { \
+ NDIS_HANDLE _Handle = SEND_RESD(_Packet)->sr_PoolHandle; \
+ NdisFreePacket(_Packet); \
+ NdisFreePacketPool(_Handle); \
+ }
+
+#define SpxFreeRecvPacket(_Device,_Packet) \
+ { \
+ NDIS_HANDLE _Handle = RECV_RESD(_Packet)->rr_PoolHandle; \
+ NdisFreePacket(_Packet); \
+ NdisFreePacketPool(_Handle); \
+ }
+
+#define SpxReInitSendPacket(_Packet)
+ {
+ NDIS_HANDLE _Handle = SEND_RESD(_Packet)->sr_PoolHandle;
+ NdisReInitializePacket(_Packet);
+ SEND_RESD(_Packet)->sr_PoolHandle = (_Handle);
+ }
+
+#define SpxReInitRecvPacket(_Packet)
+ {
+ NDIS_HANDLE _Handle = RECV_RESD(_Packet)->rr_PoolHandle;
+ NdisReInitializePacket(_Packet);
+ RECV_RESD(_Packet)->rr_PoolHandle = (_Handle);
+ }
+
+#define SEND_RESD(_Packet) ((PSPX_SEND_RESD)((_Packet)->ProtocolReserved))
+#define RECV_RESD(_Packet) ((PSPX_RECV_RESD)((_Packet)->ProtocolReserved))
+
+#else
+
+#define SpxAllocSendPacket(_Device, _SendPacket, _Status) \
+ { \
+ if (*(_SendPacket) = SpxBPAllocBlock(BLKID_NDISSEND)) \
+ *(_Status) = NDIS_STATUS_SUCCESS; \
+ else \
+ *(_Status) = NDIS_STATUS_RESOURCES; \
+ }
+
+#define SpxAllocRecvPacket(_Device,_RecvPacket,_Status) \
+ { \
+ if (*(_RecvPacket) = SpxBPAllocBlock(BLKID_NDISRECV)) \
+ *(_Status) = NDIS_STATUS_SUCCESS; \
+ else \
+ *(_Status) = NDIS_STATUS_RESOURCES; \
+ }
+
+#define SpxFreeSendPacket(_Device,_Packet) \
+ { \
+ SpxBPFreeBlock(_Packet, BLKID_NDISSEND); \
+ }
+
+#define SpxFreeRecvPacket(_Device,_Packet) \
+ { \
+ SpxBPFreeBlock(_Packet, BLKID_NDISRECV); \
+ }
+
+#define SpxReInitSendPacket(_Packet) \
+ { \
+ }
+
+#define SpxReInitRecvPacket(_Packet) \
+ { \
+ }
+
+#define SEND_RESD(_Packet) ((PSPX_SEND_RESD)((_Packet)->ProtocolReserved))
+#define RECV_RESD(_Packet) ((PSPX_RECV_RESD)((_Packet)->ProtocolReserved))
+
+#endif
+
+
+//
+// Routine Prototypes
+//
+
+VOID
+SpxPktBuildCr(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ IN struct _SPX_ADDR * pSpxAddr,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fSpx2);
+
+VOID
+SpxPktBuildCrAck(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ IN struct _SPX_ADDR * pSpxAddr,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fNeg,
+ IN BOOLEAN fSpx2);
+
+VOID
+SpxPktBuildSn(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State);
+
+VOID
+SpxPktBuildSs(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State);
+
+VOID
+SpxPktBuildSsAck(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State);
+
+VOID
+SpxPktBuildSnAck(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State);
+
+VOID
+SpxPktBuildRr(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT SeqNum,
+ IN USHORT State);
+
+VOID
+SpxPktBuildRrAck(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN USHORT MaxPktSize);
+
+VOID
+SpxPktBuildProbe(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fSpx2);
+
+VOID
+SpxPktBuildData(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN USHORT Length);
+
+VOID
+SpxCopyBufferChain(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_BUFFER * TargetChain,
+ IN NDIS_HANDLE PoolHandle,
+ IN PNDIS_BUFFER SourceChain,
+ IN UINT Offset,
+ IN UINT Length
+ );
+
+VOID
+SpxPktBuildAck(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fBuildNack,
+ IN USHORT NumToResend);
+
+VOID
+SpxPktBuildDisc(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ IN PREQUEST pRequest,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN UCHAR DataType);
+
+VOID
+SpxPktRecvRelease(
+ IN PNDIS_PACKET pPkt);
+
+VOID
+SpxPktSendRelease(
+ IN PNDIS_PACKET pPkt);
diff --git a/private/ntos/tdi/isnp/spx/h/spxquery.h b/private/ntos/tdi/isnp/spx/h/spxquery.h
new file mode 100644
index 000000000..68e0a1ca8
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/h/spxquery.h
@@ -0,0 +1,54 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxquery.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#define SPX_TDI_PROVIDERINFO_VERSION 0x0001
+#define SPX_PINFOSENDSIZE 0xFFFFFFFF
+#define SPX_PINFOMINMAXLOOKAHEAD 128
+
+//
+// Bug #14498: Indicate to AFD that we are capable of orderly disc so AFD can follow
+// these semantics.
+// In order to have SPXI connections work correctly, we OR this bit in at query time.
+// (see SpxTdiQueryInformation)
+//
+#define SPX_PINFOSERVICEFLAGS ( TDI_SERVICE_CONNECTION_MODE | \
+ TDI_SERVICE_DELAYED_ACCEPTANCE | \
+ TDI_SERVICE_MESSAGE_MODE | \
+ TDI_SERVICE_ERROR_FREE_DELIVERY) // | \
+ // TDI_SERVICE_ORDERLY_RELEASE )
+
+VOID
+SpxQueryInitProviderInfo(
+ PTDI_PROVIDER_INFO ProviderInfo);
+
+NTSTATUS
+SpxTdiQueryInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request);
+
+NTSTATUS
+SpxTdiSetInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request);
+
diff --git a/private/ntos/tdi/isnp/spx/h/spxrecv.h b/private/ntos/tdi/isnp/spx/h/spxrecv.h
new file mode 100644
index 000000000..0ce382990
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/h/spxrecv.h
@@ -0,0 +1,89 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxrecv.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+VOID
+SpxReceive(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize);
+
+VOID
+SpxTransferDataComplete(
+ IN PNDIS_PACKET pNdisPkt,
+ IN NDIS_STATUS NdisStatus,
+ IN UINT BytesTransferred);
+
+VOID
+SpxReceiveComplete(
+ IN USHORT NicId);
+
+VOID
+SpxRecvDataPacket(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize);
+
+VOID
+SpxRecvDiscPacket(
+ IN PUCHAR LookaheadBuffer,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN UINT LookaheadSize);
+
+VOID
+SpxRecvSysPacket(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize);
+
+VOID
+SpxRecvFlushBytes(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN ULONG BytesToFlush,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+SpxRecvProcessPkts(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn);
+
+BOOLEAN
+SpxRecvIndicatePendingData(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn);
+
diff --git a/private/ntos/tdi/isnp/spx/h/spxreg.h b/private/ntos/tdi/isnp/spx/h/spxreg.h
new file mode 100644
index 000000000..4e0cb469b
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/h/spxreg.h
@@ -0,0 +1,65 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxreg.h
+
+Abstract:
+
+ Private include file for the ISN SPX module.
+ file defines all constants and structures necessary for support of
+ the dynamic configuration of ST.
+
+Revision History:
+
+--*/
+
+#define HALFSEC_TO_MS_FACTOR 500
+#define IPX_REG_PATH L"NwlnkIpx\\Linkage"
+
+// These are used to index into the Parameters array in CONFIG.
+#define CONFIG_CONNECTION_COUNT 0
+#define CONFIG_CONNECTION_TIMEOUT 1
+#define CONFIG_INIT_PACKETS 2
+#define CONFIG_MAX_PACKETS 3
+#define CONFIG_INITIAL_RETRANSMIT_TIMEOUT 4
+#define CONFIG_KEEPALIVE_COUNT 5
+#define CONFIG_KEEPALIVE_TIMEOUT 6
+#define CONFIG_WINDOW_SIZE 7
+#define CONFIG_SOCKET_RANGE_START 8
+#define CONFIG_SOCKET_RANGE_END 9
+#define CONFIG_SOCKET_UNIQUENESS 10
+#define CONFIG_MAX_PACKET_SIZE 11
+#define CONFIG_REXMIT_COUNT 12
+
+// Hidden parameters
+#define CONFIG_DISABLE_SPX2 13
+#define CONFIG_ROUTER_MTU 14
+#define CONFIG_BACKCOMP_SPX 15
+
+#define CONFIG_PARAMETERS 16
+
+// Main configuration structure.
+typedef struct _CONFIG {
+
+ ULONG cf_Parameters[CONFIG_PARAMETERS]; // index defined above
+ NDIS_STRING cf_DeviceName; // device name exported
+ PWSTR cf_RegistryPathBuffer; // path to config info
+
+} CONFIG, * PCONFIG;
+
+
+#define PARAM(x) (SpxDevice->dev_ConfigInfo->cf_Parameters[(x)])
+
+
+NTSTATUS
+SpxInitGetConfiguration (
+ IN PUNICODE_STRING RegistryPath,
+ OUT PCONFIG * ConfigPtr);
+
+VOID
+SpxInitFreeConfiguration (
+ IN PCONFIG Config);
+
diff --git a/private/ntos/tdi/isnp/spx/h/spxsend.h b/private/ntos/tdi/isnp/spx/h/spxsend.h
new file mode 100644
index 000000000..40ef810ea
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/h/spxsend.h
@@ -0,0 +1,34 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxsend.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+VOID
+SpxSendComplete(
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus);
+
+VOID
+SpxSendPktRelease(
+ IN PNDIS_PACKET pPkt,
+ IN UINT BufCount);
diff --git a/private/ntos/tdi/isnp/spx/h/spxtimer.h b/private/ntos/tdi/isnp/spx/h/spxtimer.h
new file mode 100644
index 000000000..225037bd2
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/h/spxtimer.h
@@ -0,0 +1,101 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ spxtimer.h
+
+Abstract:
+
+ This module contains routines to schedule timer events.
+
+Author:
+
+ Jameel Hyder (jameelh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version
+
+Notes: Tab stop: 4
+--*/
+
+#define TIMER_DONT_REQUEUE 0
+#define TIMER_REQUEUE_CUR_VALUE 1
+
+typedef ULONG (*TIMER_ROUTINE)(IN PVOID Context, IN BOOLEAN TimerShuttingDown);
+
+extern
+NTSTATUS
+SpxTimerInit(
+ VOID);
+
+extern
+ULONG
+SpxTimerScheduleEvent(
+ IN TIMER_ROUTINE Worker, // Routine to invoke when time expires
+ IN ULONG DeltaTime, // Schedule after this much time
+ IN PVOID pContext); // Context to pass to the routine
+
+extern
+VOID
+SpxTimerFlushAndStop(
+ VOID);
+
+extern
+BOOLEAN
+SpxTimerCancelEvent(
+ IN ULONG TimerId,
+ IN BOOLEAN ReEnqueue);
+
+#define TMR_SIGNATURE *(PULONG)"ATMR"
+#if DBG
+#define VALID_TMR(pTmr) (((pTmr) != NULL) && \
+ ((pTmr)->tmr_Signature == TMR_SIGNATURE))
+#else
+#define VALID_TMR(pTmr) ((pTmr) != NULL)
+#endif
+typedef struct _TimerList
+{
+#if DBG
+ ULONG tmr_Signature;
+#endif
+ struct _TimerList * tmr_Next; // Link to next
+ struct _TimerList ** tmr_Prev; // Link to prev
+ struct _TimerList * tmr_Overflow; // Link to overflow entry in hash table
+ ULONG tmr_AbsTime; // Absolute time, for re-enqueue
+ ULONG tmr_RelDelta; // Relative to the previous entry
+ ULONG tmr_Id; // Unique Id for this event
+ BOOLEAN tmr_Cancelled; // Was the timer cancelled?
+ TIMER_ROUTINE tmr_Worker; // Real Worker
+ PVOID tmr_Context; // Real context
+} TIMERLIST, *PTIMERLIST;
+
+
+#define SpxGetCurrentTime() (SpxTimerCurrentTime/SPX_TIMER_FACTOR)
+#define SpxGetCurrentTick() SpxTimerCurrentTime
+
+// Keep this at a ONE second level.
+#define SPX_TIMER_FACTOR 10 // i.e. 10 ticks per second
+#define SPX_MS_TO_TICKS 100 // Divide ms by this to get ticks
+#define SPX_TIMER_TICK -1000000L // 100ms in 100ns units
+#define SPX_TIMER_WAIT 50 // Time to wait in FlushAndStop in ms
+#define TIMER_HASH_TABLE 32
+
+VOID
+spxTimerDpcRoutine(
+ IN PKDPC pKDpc,
+ IN PVOID pContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2);
+
+VOID
+spxTimerWorker(
+ IN PTIMERLIST pList);
+
+VOID
+spxTimerEnqueue(
+ PTIMERLIST pListNew);
+
+
diff --git a/private/ntos/tdi/isnp/spx/h/spxutils.h b/private/ntos/tdi/isnp/spx/h/spxutils.h
new file mode 100644
index 000000000..074a1649b
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/h/spxutils.h
@@ -0,0 +1,178 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxutils.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+// For PROTO_SPX, i'd return a device name from the dll of the form
+// \Device\NwlnkSpx\SpxStream (for SOCK_STREAM) or
+// \Device\NwlnkSpx\Spx (for SOCK_SEQPKT)
+//
+// and for PROTO_SPXII (the more common case we hope, even if
+// internally we degrade to SPX1 cause of the remote client's
+// limitations)
+// \Device\NwlnkSpx\Stream (for SOCK_STREAM) or
+// \Device\NwlnkSpx (for SOCK_SEQPKT)
+
+#define SOCKET1STREAM_SUFFIX L"\\SpxStream"
+#define SOCKET1_SUFFIX L"\\Spx"
+#define SOCKET2STREAM_SUFFIX L"\\Stream"
+#define SOCKET1_TYPE_SEQPKT 0
+#define SOCKET2_TYPE_SEQPKT 1
+#define SOCKET1_TYPE_STREAM 2
+#define SOCKET2_TYPE_STREAM 3
+
+#define IN_RANGE(_S, _RangeStart, _RangeEnd) \
+ ((_S >= _RangeStart) && (_S <= _RangeEnd))
+
+
+//
+// The following macros deal with on-the-wire integer and long values
+//
+// On the wire format is big-endian i.e. a long value of 0x01020304 is
+// represented as 01 02 03 04. Similarly an int value of 0x0102 is
+// represented as 01 02.
+//
+// The host format is not assumed since it will vary from processor to
+// processor.
+//
+
+// Get a byte from on-the-wire format to a short in the host format
+#define GETBYTE2SHORT(DstPtr, SrcPtr) \
+ *(PUSHORT)(DstPtr) = (USHORT) (*(PBYTE)(SrcPtr))
+
+// Get a byte from on-the-wire format to a short in the host format
+#define GETBYTE2ULONG(DstPtr, SrcPtr) \
+ *(PULONG)(DstPtr) = (ULONG) (*(PBYTE)(SrcPtr))
+
+// Get a short from on-the-wire format to a dword in the host format
+#define GETSHORT2ULONG(DstPtr, SrcPtr) \
+ *(PULONG)(DstPtr) = ((*((PBYTE)(SrcPtr)+0) << 8) + \
+ (*((PBYTE)(SrcPtr)+1) ))
+
+// Get a short from on-the-wire format to a dword in the host format
+#define GETSHORT2SHORT(DstPtr, SrcPtr) \
+ *(PUSHORT)(DstPtr) = ((*((PBYTE)(SrcPtr)+0) << 8) + \
+ (*((PBYTE)(SrcPtr)+1) ))
+
+// Get a dword from on-the-wire format to a dword in the host format
+#define GETULONG2ULONG(DstPtr, SrcPtr) \
+ *(PULONG)(DstPtr) = ((*((PBYTE)(SrcPtr)+0) << 24) + \
+ (*((PBYTE)(SrcPtr)+1) << 16) + \
+ (*((PBYTE)(SrcPtr)+2) << 8) + \
+ (*((PBYTE)(SrcPtr)+3) ))
+
+// Get a dword from on-the-wire format to a dword in the same format but
+// also watch out for alignment
+#define GETULONG2ULONG_NOCONV(DstPtr, SrcPtr) \
+ *((PBYTE)(DstPtr)+0) = *((PBYTE)(SrcPtr)+0); \
+ *((PBYTE)(DstPtr)+1) = *((PBYTE)(SrcPtr)+1); \
+ *((PBYTE)(DstPtr)+2) = *((PBYTE)(SrcPtr)+2); \
+ *((PBYTE)(DstPtr)+3) = *((PBYTE)(SrcPtr)+3);
+
+// Put a dword from the host format to a short to on-the-wire format
+#define PUTBYTE2BYTE(DstPtr, Src) \
+ *((PBYTE)(DstPtr)) = (BYTE)(Src)
+
+// Put a dword from the host format to a short to on-the-wire format
+#define PUTSHORT2BYTE(DstPtr, Src) \
+ *((PBYTE)(DstPtr)) = ((USHORT)(Src) % 256)
+
+// Put a dword from the host format to a short to on-the-wire format
+#define PUTSHORT2SHORT(DstPtr, Src) \
+ *((PBYTE)(DstPtr)+0) = (BYTE) ((USHORT)(Src) >> 8), \
+ *((PBYTE)(DstPtr)+1) = (BYTE)(Src)
+
+// Put a dword from the host format to a byte to on-the-wire format
+#define PUTULONG2BYTE(DstPtr, Src) \
+ *(PBYTE)(DstPtr) = (BYTE)(Src)
+
+// Put a dword from the host format to a short to on-the-wire format
+#define PUTULONG2SHORT(DstPtr, Src) \
+ *((PBYTE)(DstPtr)+0) = (BYTE) ((ULONG)(Src) >> 8), \
+ *((PBYTE)(DstPtr)+1) = (BYTE) (Src)
+
+// Put a dword from the host format to a dword to on-the-wire format
+#define PUTULONG2ULONG(DstPtr, Src) \
+ *((PBYTE)(DstPtr)+0) = (BYTE) ((ULONG)(Src) >> 24), \
+ *((PBYTE)(DstPtr)+1) = (BYTE) ((ULONG)(Src) >> 16), \
+ *((PBYTE)(DstPtr)+2) = (BYTE) ((ULONG)(Src) >> 8), \
+ *((PBYTE)(DstPtr)+3) = (BYTE) (Src)
+
+// Put a BYTE[4] array into another BYTE4 array.
+#define PUTBYTE42BYTE4(DstPtr, SrcPtr) \
+ *((PBYTE)(DstPtr)+0) = *((PBYTE)(SrcPtr)+0), \
+ *((PBYTE)(DstPtr)+1) = *((PBYTE)(SrcPtr)+1), \
+ *((PBYTE)(DstPtr)+2) = *((PBYTE)(SrcPtr)+2), \
+ *((PBYTE)(DstPtr)+3) = *((PBYTE)(SrcPtr)+3)
+
+// MIN/MAX macros
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+
+
+
+// Exported prototypes
+
+UINT
+SpxUtilWstrLength(
+ IN PWSTR Wstr);
+
+LONG
+SpxRandomNumber(
+ VOID);
+
+NTSTATUS
+SpxUtilGetSocketType(
+ PUNICODE_STRING RemainingFileName,
+ PBYTE SocketType);
+
+VOID
+SpxSleep(
+ IN ULONG TimeInMs);
+
+ULONG
+SpxBuildTdiAddress(
+ IN PVOID AddressBuffer,
+ IN ULONG AddressBufferLength,
+ IN UCHAR Network[4],
+ IN UCHAR Node[6],
+ IN USHORT Socket);
+
+VOID
+SpxBuildTdiAddressFromIpxAddr(
+ IN PVOID AddressBuffer,
+ IN PBYTE pIpxAddr);
+
+TDI_ADDRESS_IPX UNALIGNED *
+SpxParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress);
+
+BOOLEAN
+SpxValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength);
+
+VOID
+SpxCalculateNewT1(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ IN int NewT1);
diff --git a/private/ntos/tdi/isnp/spx/mp/makefile b/private/ntos/tdi/isnp/spx/mp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/mp/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isnp/spx/mp/sources b/private/ntos/tdi/isnp/spx/mp/sources
new file mode 100644
index 000000000..dc48d81bb
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/mp/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+NT_UP=0
+
+TARGETPATH=\nt\public\sdk\lib
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/isnp/spx/nwlnkspx.rc b/private/ntos/tdi/isnp/spx/nwlnkspx.rc
new file mode 100644
index 000000000..02175f21d
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/nwlnkspx.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "NWLINK2 SPX Protocol Driver"
+#define VER_INTERNALNAME_STR "nwlnkspx.sys"
+#define VER_ORIGINALFILENAME_STR "nwlnkspx.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/tdi/isnp/spx/precomp.h b/private/ntos/tdi/isnp/spx/precomp.h
new file mode 100644
index 000000000..d227d02f9
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/precomp.h
@@ -0,0 +1 @@
+#include "isnspx.h"
diff --git a/private/ntos/tdi/isnp/spx/sources.inc b/private/ntos/tdi/isnp/spx/sources.inc
new file mode 100644
index 000000000..419f580f1
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/sources.inc
@@ -0,0 +1,65 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=nwlnkspx
+
+TARGETNAME=nwlnkspx
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\tdi.lib \
+ $(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..;..\h;..\..\inc;..\..\..\..\inc;..\..\..\..\..\inc
+
+C_DEFINES=$(C_DEFINES) -D_NTDRIVER_ -D_PNP_POWER=1
+
+!IFDEF BUILD_FOR_3_51
+C_DEFINES=$(C_DEFINES) -D_NTIFS_
+!ENDIF
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=..\spxdrvr.c \
+ ..\spxreg.c \
+ ..\spxdev.c \
+ ..\spxbind.c \
+ ..\spxaddr.c \
+ ..\spxconn.c \
+ ..\spxcutil.c \
+ ..\spxcpkt.c \
+ ..\spxrecv.c \
+ ..\spxsend.c \
+ ..\spxquery.c \
+ ..\spxutils.c \
+ ..\spxmem.c \
+ ..\spxtimer.c \
+ ..\spxpkt.c \
+ ..\globals.c \
+ ..\spxerror.c \
+ ..\nwlnkspx.rc
+
+PRECOMPILED_INCLUDE=..\precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
diff --git a/private/ntos/tdi/isnp/spx/spxaddr.c b/private/ntos/tdi/isnp/spx/spxaddr.c
new file mode 100644
index 000000000..e9e85dc5c
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/spxaddr.c
@@ -0,0 +1,1729 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxaddr.c
+
+Abstract:
+
+ This module contains code which implements the ADDRESS object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport address objects.
+
+Author:
+
+ Adam Barr (adamba ) Original Version
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text( PAGE, SpxAddrFileCreate)
+#pragma alloc_text( PAGE, SpxAddrFileClose)
+#endif
+
+// Define module number for event logging entries
+#define FILENUM SPXADDR
+
+// Map all generic accesses to the same one.
+static GENERIC_MAPPING AddressGenericMapping =
+ { READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL };
+
+#define REORDER(_Socket) ((((_Socket) & 0xff00) >> 8) | (((_Socket) & 0x00ff) << 8))
+
+
+
+
+NTSTATUS
+SpxAddrOpen(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens a file that points to an existing address object, or, if
+ the object doesn't exist, creates it (note that creation of the address
+ object includes registering the address, and may take many seconds to
+ complete, depending upon system configuration).
+
+ If the address already exists, and it has an ACL associated with it, the
+ ACL is checked for access rights before allowing creation of the address.
+
+Arguments:
+
+ DeviceObject - pointer to the device object describing the ST transport.
+
+ Request - a pointer to the request used for the creation of the address.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PSPX_ADDR pAddr;
+ PSPX_ADDR_FILE pAddrFile;
+ PFILE_FULL_EA_INFORMATION ea;
+ TRANSPORT_ADDRESS UNALIGNED *name;
+ TA_ADDRESS UNALIGNED * AddressName;
+ USHORT Socket, hostSocket;
+ ULONG DesiredShareAccess;
+ CTELockHandle LockHandle, LockHandleAddr;
+ PACCESS_STATE AccessState;
+ ACCESS_MASK GrantedAccess;
+ BOOLEAN AccessAllowed;
+ int i;
+ BOOLEAN found = FALSE;
+
+#ifdef ISN_NT
+ PIRP Irp = (PIRP)Request;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+#endif
+
+
+ // The network name is in the EA, passed in the request.
+ ea = OPEN_REQUEST_EA_INFORMATION(Request);
+ if (ea == NULL)
+ {
+ DBGPRINT(TDI, ERR,
+ ("OpenAddress: REQUEST %lx has no EA\n", Request));
+
+ return STATUS_NONEXISTENT_EA_ENTRY;
+ }
+
+ // this may be a valid name; parse the name from the EA and use it if OK.
+ name = (PTRANSPORT_ADDRESS)&ea->EaName[ea->EaNameLength+1];
+ AddressName = (PTA_ADDRESS)&name->Address[0];
+
+ // The name can be passed with multiple entries; we'll take and use only
+ // the first one of type IPX.
+ for (i=0;i<name->TAAddressCount;i++)
+ {
+ if (AddressName->AddressType == TDI_ADDRESS_TYPE_IPX)
+ {
+ if (AddressName->AddressLength >= sizeof(TDI_ADDRESS_IPX))
+ {
+ Socket =
+ ((TDI_ADDRESS_IPX UNALIGNED *)&AddressName->Address[0])->Socket;
+
+ GETSHORT2SHORT(&hostSocket, &Socket);
+
+ DBGPRINT(CREATE, DBG,
+ ("SpxAddrOpen: Creating socket %lx.h%lx\n",
+ Socket, hostSocket ));
+
+ found = TRUE;
+ }
+ break;
+
+ }
+ else
+ {
+
+ AddressName = (PTA_ADDRESS)(AddressName->Address +
+ AddressName->AddressLength);
+ }
+ }
+
+ if (!found)
+ {
+ DBGPRINT(TDI, ERR,
+ ("OpenAddress: REQUEST %lx has no IPX Address\n", Request));
+
+ return STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+#ifdef SOCKET_RANGE_OPEN_LIMITATION_REMOVED
+ // Is the socket in our range if its in the range 0x4000-0x7FFF
+ if (IN_RANGE(hostSocket, DYNSKT_RANGE_START, DYNSKT_RANGE_END))
+ {
+ if (!IN_RANGE(
+ hostSocket,
+ PARAM(CONFIG_SOCKET_RANGE_START),
+ PARAM(CONFIG_SOCKET_RANGE_END)))
+ {
+ return(STATUS_INVALID_ADDRESS);
+ }
+ }
+#endif
+
+ // get an address file structure to represent this address.
+ status = SpxAddrFileCreate(Device, Request, &pAddrFile);
+ if (!NT_SUCCESS(status))
+ return status;
+
+ // See if this address is already established. This call automatically
+ // increments the reference count on the address so that it won't disappear
+ // from underneath us after this call but before we have a chance to use it.
+ //
+ // To ensure that we don't create two address objects for the
+ // same address, we hold the device context addressResource until
+ // we have found the address or created a new one.
+ ExAcquireResourceExclusive (&Device->dev_AddrResource, TRUE);
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+
+ // We checkfor/create sockets within the critical section.
+ if (Socket == 0)
+ {
+ Socket = SpxAddrAssignSocket(Device);
+
+ if (Socket == 0)
+ {
+ DBGPRINT(ADDRESS, ERR,
+ ("OpenAddress, no unique socket found\n"));
+
+ CTEFreeLock (&Device->dev_Lock, LockHandle);
+ ExReleaseResource (&Device->dev_AddrResource);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ DBGPRINT(ADDRESS, INFO,
+ ("OpenAddress, assigned socket %lx\n", Socket));
+ }
+
+ pAddr = SpxAddrLookup(Device, Socket);
+
+ if (pAddr == NULL)
+ {
+ CTEFreeLock (&Device->dev_Lock, LockHandle);
+
+ // This address doesn't exist. Create it.
+ // registering it. It also puts a ref of type ADDR_FILE on address.
+ pAddr = SpxAddrCreate(
+ Device,
+ Socket);
+
+ if (pAddr != (PSPX_ADDR)NULL)
+ {
+#ifdef ISN_NT
+
+ // Initialize the shared access now. We use read access
+ // to control all access.
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ IoSetShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &pAddr->u.sa_ShareAccess);
+
+
+ // Assign the security descriptor (need to do this with
+ // the spinlock released because the descriptor is not
+ // mapped).
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ status = SeAssignSecurity(
+ NULL, // parent descriptor
+ AccessState->SecurityDescriptor,
+ &pAddr->sa_SecurityDescriptor,
+ FALSE, // is directory
+ &AccessState->SubjectSecurityContext,
+ &AddressGenericMapping,
+ NonPagedPool);
+
+ if (!NT_SUCCESS(status))
+ {
+ // Error, return status.
+ IoRemoveShareAccess (IrpSp->FileObject, &pAddr->u.sa_ShareAccess);
+ ExReleaseResource (&Device->dev_AddrResource);
+ SpxAddrDereference (pAddr, AREF_ADDR_FILE);
+
+ SpxAddrFileDestroy(pAddrFile);
+ return status;
+ }
+
+#endif
+
+ ExReleaseResource (&Device->dev_AddrResource);
+
+ // if the adapter isn't ready, we can't do any of this; get out
+#if defined(_PNP_POWER)
+ if (Device->dev_State != DEVICE_STATE_OPEN)
+#else
+ if (Device->dev_State == DEVICE_STATE_STOPPING)
+#endif _PNP_POWER
+ {
+ SpxAddrDereference (pAddr, AREF_ADDR_FILE);
+
+ SpxAddrFileDestroy(pAddrFile);
+ status = STATUS_DEVICE_NOT_READY;
+ }
+ else
+ {
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)pAddrFile;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+#ifdef ISN_NT
+ pAddrFile->saf_FileObject = IrpSp->FileObject;
+#endif
+ CTEGetLock (&pAddr->sa_Lock, &LockHandleAddr);
+ pAddrFile->saf_Addr = pAddr;
+ pAddrFile->saf_AddrLock = &pAddr->sa_Lock;
+
+ // Set flags appropriately, note spx/stream flags are set at this
+ // point.
+ pAddrFile->saf_Flags &= ~SPX_ADDRFILE_OPENING;
+ pAddrFile->saf_Flags |= SPX_ADDRFILE_OPEN;
+
+ // Queue in the address list, removed in destroy.
+ pAddrFile->saf_Next = pAddr->sa_AddrFileList;
+ pAddr->sa_AddrFileList = pAddrFile;
+
+ CTEFreeLock (&pAddr->sa_Lock, LockHandleAddr);
+ status = STATUS_SUCCESS;
+ }
+ }
+ else
+ {
+ ExReleaseResource (&Device->dev_AddrResource);
+
+ // If the address could not be created, and is not in the process of
+ // being created, then we can't open up an address.
+
+ SpxAddrFileDestroy(pAddrFile);
+ }
+ }
+ else
+ {
+ CTEFreeLock (&Device->dev_Lock, LockHandle);
+
+ DBGPRINT(ADDRESS, ERR,
+ ("Add to address %lx\n", pAddr));
+
+ // The address already exists. Check the ACL and see if we
+ // can access it. If so, simply use this address as our address.
+
+#ifdef ISN_NT
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ AccessAllowed = SeAccessCheck(
+ pAddr->sa_SecurityDescriptor,
+ &AccessState->SubjectSecurityContext,
+ FALSE, // tokens locked
+ IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
+ (ACCESS_MASK)0, // previously granted
+ NULL, // privileges
+ &AddressGenericMapping,
+ Irp->RequestorMode,
+ &GrantedAccess,
+ &status);
+
+#else // ISN_NT
+
+ AccessAllowed = TRUE;
+
+#endif // ISN_NT
+
+ if (!AccessAllowed)
+ {
+ ExReleaseResource (&Device->dev_AddrResource);
+ SpxAddrFileDestroy(pAddrFile);
+ }
+ else
+ {
+#ifdef ISN_NT
+
+ // Now check that we can obtain the desired share
+ // access. We use read access to control all access.
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ status = IoCheckShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &pAddr->u.sa_ShareAccess,
+ TRUE);
+
+#else // ISN_NT
+
+ status = STATUS_SUCCESS;
+
+#endif // ISN_NT
+
+ if (!NT_SUCCESS (status))
+ {
+ ExReleaseResource (&Device->dev_AddrResource);
+ SpxAddrFileDestroy(pAddrFile);
+ }
+ else
+ {
+ ExReleaseResource (&Device->dev_AddrResource);
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+ CTEGetLock (&pAddr->sa_Lock, &LockHandleAddr);
+
+ pAddrFile->saf_Addr = pAddr;
+ pAddrFile->saf_AddrLock = &pAddr->sa_Lock;
+#ifdef ISN_NT
+ pAddrFile->saf_FileObject = IrpSp->FileObject;
+#endif
+ // Set flags appropriately, note spx/stream flags are set at this
+ // point.
+ pAddrFile->saf_Flags &= ~SPX_ADDRFILE_OPENING;
+ pAddrFile->saf_Flags |= SPX_ADDRFILE_OPEN;
+
+ SpxAddrLockReference (pAddr, AREF_ADDR_FILE);
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)pAddrFile;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ // Queue in the address list, removed in destroy.
+ pAddrFile->saf_Next = pAddr->sa_AddrFileList;
+ pAddr->sa_AddrFileList = pAddrFile;
+
+ CTEFreeLock (&pAddr->sa_Lock, LockHandleAddr);
+ CTEFreeLock (&Device->dev_Lock, LockHandle);
+
+ status = STATUS_SUCCESS;
+ }
+ }
+
+ // Remove the reference from SpxLookupAddress.
+ SpxAddrDereference (pAddr, AREF_LOOKUP);
+ }
+
+ return status;
+
+} // SpxAddrOpen
+
+
+
+
+NTSTATUS
+SpxAddrSetEventHandler(
+ IN PDEVICE Device,
+ IN PREQUEST pRequest
+ )
+{
+ CTELockHandle lockHandle;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ PSPX_ADDR_FILE
+ pSpxAddrFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+ PTDI_REQUEST_KERNEL_SET_EVENT
+ pParam = (PTDI_REQUEST_KERNEL_SET_EVENT)REQUEST_PARAMETERS(pRequest);
+
+ if ((status = SpxAddrFileVerify(pSpxAddrFile)) != STATUS_SUCCESS)
+ return(status);
+
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle);
+ switch (pParam->EventType)
+ {
+
+ case TDI_EVENT_ERROR:
+
+ break;
+
+ case TDI_EVENT_CONNECT:
+
+ pSpxAddrFile->saf_ConnHandler =
+ (PTDI_IND_CONNECT)(pParam->EventHandler);
+ pSpxAddrFile->saf_ConnHandlerCtx =
+ pParam->EventContext;
+
+ break;
+
+ case TDI_EVENT_RECEIVE:
+
+ pSpxAddrFile->saf_RecvHandler =
+ (PTDI_IND_RECEIVE)(pParam->EventHandler);
+ pSpxAddrFile->saf_RecvHandlerCtx =
+ pParam->EventContext;
+
+ break;
+
+ case TDI_EVENT_DISCONNECT:
+
+ pSpxAddrFile->saf_DiscHandler =
+ (PTDI_IND_DISCONNECT)(pParam->EventHandler);
+ pSpxAddrFile->saf_DiscHandlerCtx =
+ pParam->EventContext;
+
+ break;
+
+
+ case TDI_EVENT_SEND_POSSIBLE :
+
+ pSpxAddrFile->saf_SendPossibleHandler =
+ (PTDI_IND_SEND_POSSIBLE)(pParam->EventHandler);
+ pSpxAddrFile->saf_SendPossibleHandlerCtx =
+ pParam->EventContext;
+
+ break;
+
+ case TDI_EVENT_RECEIVE_DATAGRAM:
+ case TDI_EVENT_RECEIVE_EXPEDITED:
+ default:
+
+ status = STATUS_INVALID_PARAMETER;
+ }
+
+ CTEFreeLock(pSpxAddrFile->saf_AddrLock, lockHandle);
+
+ SpxAddrFileDereference(pSpxAddrFile, AFREF_VERIFY);
+ return(status);
+}
+
+
+
+PSPX_ADDR
+SpxAddrCreate(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a transport address and associates it with
+ the specified transport device context. The reference count in the
+ address is automatically set to 1, and the reference count of the
+ device context is incremented.
+
+ NOTE: This routine must be called with the Device
+ spinlock held.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ Socket - The socket to assign to this address.
+
+Return Value:
+
+ The newly created address, or NULL if none can be allocated.
+
+--*/
+
+{
+ PSPX_ADDR pAddr;
+ int index;
+ CTELockHandle lockHandle;
+
+ pAddr = (PSPX_ADDR)SpxAllocateZeroedMemory (sizeof(SPX_ADDR));
+ if (pAddr == NULL)
+ {
+ DBGPRINT(ADDRESS, INFO,
+ ("Create address %lx failed\n", (ULONG)Socket));
+
+ return NULL;
+ }
+
+ DBGPRINT(ADDRESS, INFO,
+ ("Create address %lx (%lx)\n", pAddr, (ULONG)Socket));
+
+ pAddr->sa_Type = SPX_ADDRESS_SIGNATURE;
+ pAddr->sa_Size = sizeof (SPX_ADDR);
+ pAddr->sa_Flags = 0;
+
+ pAddr->sa_Device = Device;
+ pAddr->sa_DeviceLock = &Device->dev_Lock;
+ CTEInitLock (&pAddr->sa_Lock);
+
+ // This reference is for the address file that will associated with this addr.
+ pAddr->sa_RefCount = 1;
+
+#if DBG
+ pAddr->sa_RefTypes[AREF_ADDR_FILE] = 1;
+#endif
+
+ pAddr->sa_Socket = Socket;
+
+ // Insert address into the device hash table.
+ index = (int)(Socket & NUM_SPXADDR_HASH_MASK);
+
+ CTEGetLock (&Device->dev_Lock, &lockHandle);
+ pAddr->sa_Next = Device->dev_AddrHashTable[index];
+ Device->dev_AddrHashTable[index] = pAddr;
+ CTEFreeLock (&Device->dev_Lock, lockHandle);
+
+ SpxReferenceDevice (Device, DREF_ADDRESS);
+
+ return pAddr;
+
+} // SpxAddrCreate
+
+
+
+
+NTSTATUS
+SpxAddrFileVerify(
+ IN PSPX_ADDR_FILE pAddrFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to verify that the pointer given us in a file
+ object is in fact a valid address file object. We also verify that the
+ address object pointed to by it is a valid address object, and reference
+ it to keep it from disappearing while we use it.
+
+Arguments:
+
+ AddressFile - potential pointer to a SPX_ADDR_FILE object
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_ADDRESS otherwise
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ NTSTATUS status = STATUS_SUCCESS;
+ PSPX_ADDR Address;
+
+ // try to verify the address file signature. If the signature is valid,
+ // verify the address pointed to by it and get the address spinlock.
+ // check the address's state, and increment the reference count if it's
+ // ok to use it. Note that the only time we return an error for state is
+ // if the address is closing.
+
+ try
+ {
+ if ((pAddrFile->saf_Size == sizeof (SPX_ADDR_FILE)) &&
+ (pAddrFile->saf_Type == SPX_ADDRESSFILE_SIGNATURE) )
+ {
+ Address = pAddrFile->saf_Addr;
+
+ if ((Address->sa_Size == sizeof (SPX_ADDR)) &&
+ (Address->sa_Type == SPX_ADDRESS_SIGNATURE) )
+ {
+ CTEGetLock (&Address->sa_Lock, &LockHandle);
+
+ if ((Address->sa_Flags & SPX_ADDR_CLOSING) == 0)
+ {
+ SpxAddrFileLockReference(pAddrFile, AFREF_VERIFY);
+ }
+ else
+ {
+ DBGPRINT(TDI, ERR,
+ ("StVerifyAddressFile: A %lx closing\n", Address));
+
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ CTEFreeLock (&Address->sa_Lock, LockHandle);
+ }
+ else
+ {
+ DBGPRINT(TDI, ERR,
+ ("StVerifyAddressFile: A %lx bad signature\n", Address));
+
+ status = STATUS_INVALID_ADDRESS;
+ }
+ }
+ else
+ {
+ DBGPRINT(TDI, ERR,
+ ("StVerifyAddressFile: AF %lx bad signature\n", pAddrFile));
+
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DBGPRINT(TDI, ERR,
+ ("SpxAddrFileVerify: AF %lx exception\n", Address));
+
+ return GetExceptionCode();
+ }
+
+ return status;
+
+} // SpxAddrFileVerify
+
+
+
+
+VOID
+SpxAddrDestroy(
+ IN PVOID Parameter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a transport address and removes all references
+ made by it to other objects in the transport. The address structure
+ is returned to nonpaged system pool. It is assumed
+ that the caller has already removed all addressfile structures associated
+ with this address.
+
+ It is called from a worker thread queue by SpxDerefAddress when
+ the reference count goes to 0.
+
+ This thread is only queued by SpxDerefAddress. The reason for
+ this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ Address - Pointer to a transport address structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PSPX_ADDR pAddr, *ppAddr;
+ CTELockHandle LockHandle;
+
+ PSPX_ADDR Address = (PSPX_ADDR)Parameter;
+ PDEVICE Device = Address->sa_Device;
+ int index = (int)(Address->sa_Socket & NUM_SPXADDR_HASH_MASK);
+
+ DBGPRINT(ADDRESS, INFO,
+ ("Destroy address %lx\n", Address));
+
+ SeDeassignSecurity (&Address->sa_SecurityDescriptor);
+
+ // Delink this address from its associated device context's address
+ // database. To do this we must spin lock on the device context object,
+ // not on the address.
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+ for (ppAddr = &Device->dev_AddrHashTable[index]; (pAddr = *ppAddr) != NULL;)
+ {
+ if (pAddr == Address)
+ {
+ *ppAddr = pAddr->sa_Next;
+ break;
+ }
+
+ ppAddr = &pAddr->sa_Next;
+ }
+ CTEFreeLock (&Device->dev_Lock, LockHandle);
+
+ SpxFreeMemory (Address);
+ SpxDereferenceDevice (Device, DREF_ADDRESS);
+
+}
+
+
+
+
+#if DBG
+
+VOID
+SpxAddrRef(
+ IN PSPX_ADDR Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (Address->sa_RefCount > 0); // not perfect, but...
+
+ (VOID)SPX_ADD_ULONG (
+ &Address->sa_RefCount,
+ 1,
+ Address->sa_DeviceLock);
+}
+
+
+
+
+VOID
+SpxAddrLockRef(
+ IN PSPX_ADDR Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address
+ when the device lock is already held.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (Address->sa_RefCount > 0); // not perfect, but...
+ (VOID)SPX_ADD_ULONG (
+ &Address->sa_RefCount,
+ 1,
+ Address->sa_DeviceLock);
+}
+#endif
+
+
+
+
+VOID
+SpxAddrDeref(
+ IN PSPX_ADDR Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport address by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ SpxDestroyAddress to remove it from the system.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+
+ oldvalue = SPX_ADD_ULONG (
+ &Address->sa_RefCount,
+ (ULONG)-1,
+ Address->sa_DeviceLock);
+
+ //
+ // If we have deleted all references to this address, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ CTEAssert (oldvalue != 0);
+
+ if (oldvalue == 1)
+ {
+#if ISN_NT
+ ExInitializeWorkItem(
+ &Address->u.sa_DestroyAddrQueueItem,
+ SpxAddrDestroy,
+ (PVOID)Address);
+ ExQueueWorkItem(&Address->u.sa_DestroyAddrQueueItem, DelayedWorkQueue);
+#else
+ SpxAddrDestroy(Address);
+#endif
+
+ }
+
+}
+
+
+
+
+NTSTATUS
+SpxAddrFileCreate(
+ IN PDEVICE Device,
+ IN PREQUEST Request,
+ OUT PSPX_ADDR_FILE * ppAddrFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates an address file from the pool of ther
+ specified device context. The reference count in the
+ address is automatically set to 1.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+Return Value:
+
+ The allocate address file or NULL.
+
+--*/
+
+{
+ NTSTATUS status;
+ BYTE socketType;
+ CTELockHandle LockHandle;
+ PSPX_ADDR_FILE pAddrFile;
+
+ // What is the address file type?
+ if (!NT_SUCCESS(status = SpxUtilGetSocketType(
+ REQUEST_OPEN_NAME(Request),
+ &socketType)))
+ {
+ return(status);
+ }
+
+ pAddrFile = (PSPX_ADDR_FILE)SpxAllocateZeroedMemory (sizeof(SPX_ADDR_FILE));
+ if (pAddrFile == NULL)
+ {
+ DBGPRINT(ADDRESS, ERR,
+ ("Create address file failed\n"));
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ DBGPRINT(ADDRESS, INFO,
+ ("Create address file %lx\n", pAddrFile));
+
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+
+ pAddrFile->saf_Type = SPX_ADDRESSFILE_SIGNATURE;
+ pAddrFile->saf_Size = sizeof (SPX_ADDR_FILE);
+
+ pAddrFile->saf_Addr = NULL;
+
+#ifdef ISN_NT
+ pAddrFile->saf_FileObject = NULL;
+#endif
+
+ pAddrFile->saf_Device = Device;
+ pAddrFile->saf_Flags = SPX_ADDRFILE_OPENING;
+ if ((socketType == SOCKET1_TYPE_SEQPKT) ||
+ (socketType == SOCKET1_TYPE_STREAM))
+ {
+ if (socketType == SOCKET1_TYPE_STREAM)
+ {
+ pAddrFile->saf_Flags |= SPX_ADDRFILE_STREAM;
+ }
+ }
+
+ if ((socketType == SOCKET2_TYPE_SEQPKT) ||
+ (socketType == SOCKET2_TYPE_STREAM))
+ {
+ pAddrFile->saf_Flags |= SPX_ADDRFILE_SPX2;
+ if (socketType == SOCKET2_TYPE_STREAM)
+ {
+ pAddrFile->saf_Flags |= SPX_ADDRFILE_STREAM;
+ }
+ }
+
+ pAddrFile->saf_RefCount = 1;
+
+#if DBG
+ pAddrFile->saf_RefTypes[AFREF_CREATE] = 1;
+#endif
+
+ pAddrFile->saf_CloseReq = (PREQUEST)NULL;
+
+ // Initialize the request handlers.
+ pAddrFile->saf_ConnHandler =
+ pAddrFile->saf_ConnHandlerCtx = NULL;
+ pAddrFile->saf_DiscHandler =
+ pAddrFile->saf_DiscHandlerCtx = NULL;
+ pAddrFile->saf_RecvHandler =
+ pAddrFile->saf_RecvHandlerCtx = NULL;
+ pAddrFile->saf_ErrHandler =
+ pAddrFile->saf_ErrHandlerCtx = NULL;
+
+ // Release lock
+ CTEFreeLock (&Device->dev_Lock, LockHandle);
+
+ // Put in the global list for our reference
+ spxAddrInsertIntoGlobalList(pAddrFile);
+
+ *ppAddrFile = pAddrFile;
+ return STATUS_SUCCESS;
+
+}
+
+
+
+
+NTSTATUS
+SpxAddrFileDestroy(
+ IN PSPX_ADDR_FILE pAddrFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys an address file and removes all references
+ made by it to other objects in the transport.
+
+ This routine is only called by SpxAddrFileDereference. The reason
+ for this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address file object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ pAddrFile Pointer to a transport address file structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ CTELockHandle LockHandle, LockHandle1;
+ PSPX_ADDR Address;
+ PDEVICE Device;
+ PREQUEST CloseRequest;
+ PSPX_ADDR_FILE pRemAddr, *ppRemAddr;
+
+ DBGPRINT(ADDRESS, INFO,
+ ("Destroy address file %lx\n", pAddrFile));
+
+ Address = pAddrFile->saf_Addr;
+ Device = pAddrFile->saf_Device;
+
+ if (Address)
+ {
+ CTEGetLock (&Device->dev_Lock, &LockHandle1);
+
+ // This addressfile was associated with an address.
+ CTEGetLock (&Address->sa_Lock, &LockHandle);
+
+ // If the last reference on the address is being removed, set the
+ // closing flag to prevent further references.
+
+ //if (Address->sa_RefCount == 1)
+
+ //
+ // ** The lock passed here is a dummy - it is pre-compiled out.
+ //
+ if (SPX_ADD_ULONG(&Address->sa_RefCount, 0, &Address->sa_Lock) == 1) {
+ Address->sa_Flags |= SPX_ADDR_CLOSING;
+ }
+
+ // Dequeue the address file from the address list.
+ for (ppRemAddr = &Address->sa_AddrFileList; (pRemAddr = *ppRemAddr) != NULL;)
+ {
+ if (pRemAddr == pAddrFile)
+ {
+ *ppRemAddr = pRemAddr->saf_Next;
+ break;
+ }
+
+ ppRemAddr = &pRemAddr->saf_Next;
+ }
+
+ pAddrFile->saf_Addr = NULL;
+
+#ifdef ISN_NT
+ pAddrFile->saf_FileObject->FsContext = NULL;
+ pAddrFile->saf_FileObject->FsContext2 = NULL;
+#endif
+
+ CTEFreeLock (&Address->sa_Lock, LockHandle);
+ CTEFreeLock (&Device->dev_Lock, LockHandle1);
+
+ // We will already have been removed from the ShareAccess
+ // of the owning address.
+ //
+ // Now dereference the owning address.
+ SpxAddrDereference(Address, AREF_ADDR_FILE);
+ }
+
+ // Save this for later completion.
+ CloseRequest = pAddrFile->saf_CloseReq;
+
+ // Remove from the global list
+ spxAddrRemoveFromGlobalList(pAddrFile);
+
+ // return the addressFile to the pool of address files
+ SpxFreeMemory (pAddrFile);
+
+ if (CloseRequest != (PREQUEST)NULL)
+ {
+ REQUEST_INFORMATION(CloseRequest) = 0;
+ REQUEST_STATUS(CloseRequest) = STATUS_SUCCESS;
+ SpxCompleteRequest (CloseRequest);
+ SpxFreeRequest (Device, CloseRequest);
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+
+
+
+#if DBG
+
+VOID
+SpxAddrFileRef(
+ IN PSPX_ADDR_FILE pAddrFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+
+Arguments:
+
+ pAddrFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (pAddrFile->saf_RefCount > 0); // not perfect, but...
+
+ (VOID)SPX_ADD_ULONG (
+ &pAddrFile->saf_RefCount,
+ 1,
+ pAddrFile->saf_AddrLock);
+
+} // SpxRefAddressFile
+
+
+
+
+VOID
+SpxAddrFileLockRef(
+ IN PSPX_ADDR_FILE pAddrFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+ IT IS CALLED WITH THE ADDRESS LOCK HELD.
+
+Arguments:
+
+ pAddrFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (pAddrFile->saf_RefCount > 0); // not perfect, but...
+ (VOID)SPX_ADD_ULONG (
+ &pAddrFile->saf_RefCount,
+ 1,
+ pAddrFile->saf_AddrLock);
+
+}
+#endif
+
+
+
+
+VOID
+SpxAddrFileDeref(
+ IN PSPX_ADDR_FILE pAddrFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences an address file by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ SpxDestroyAddressFile to remove it from the system.
+
+Arguments:
+
+ pAddrFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+
+ oldvalue = SPX_ADD_ULONG (
+ &pAddrFile->saf_RefCount,
+ (ULONG)-1,
+ pAddrFile->saf_AddrLock);
+
+ // If we have deleted all references to this address file, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ CTEAssert (oldvalue > 0);
+
+ if (oldvalue == 1)
+ {
+ SpxAddrFileDestroy(pAddrFile);
+ }
+
+}
+
+
+
+
+PSPX_ADDR
+SpxAddrLookup(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the transport addresses defined for the given
+ device context and compares them with the specified NETWORK
+ NAME values. If an exact match is found, then a pointer to the
+ ADDRESS object is returned, and as a side effect, the reference
+ count to the address object is incremented. If the address is not
+ found, then NULL is returned.
+
+ NOTE: This routine must be called with the Device
+ spinlock held.
+
+Arguments:
+
+ Device - Pointer to the device object and its extension.
+
+ Socket - The socket to look up.
+
+Return Value:
+
+ Pointer to the ADDRESS object found, or NULL if not found.
+
+--*/
+
+{
+ PSPX_ADDR Address;
+ int index = (int)(Socket & NUM_SPXADDR_HASH_MASK);
+
+ for (Address = Device->dev_AddrHashTable[index];
+ Address != NULL;
+ Address = Address->sa_Next)
+ {
+ if ((Address->sa_Flags & SPX_ADDR_CLOSING) != 0)
+ {
+ continue;
+ }
+
+ if (Address->sa_Socket == Socket)
+ {
+ // We found the match. Bump the reference count on the address, and
+ // return a pointer to the address object for the caller to use.
+ SpxAddrLockReference(Address, AREF_LOOKUP);
+ return Address;
+
+ }
+ }
+
+ // The specified address was not found.
+ return NULL;
+
+}
+
+
+
+
+BOOLEAN
+SpxAddrExists(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ )
+
+/*++
+
+Routine Description:
+
+ NOTE: This routine must be called with the Device
+ spinlock held.
+
+Arguments:
+
+ Device - Pointer to the device object and its extension.
+
+ Socket - The socket to look up.
+
+Return Value:
+
+ TRUE if so, else FALSE
+
+--*/
+
+{
+ PSPX_ADDR Address;
+ int index = (int)(Socket & NUM_SPXADDR_HASH_MASK);
+
+ for (Address = Device->dev_AddrHashTable[index];
+ Address != NULL;
+ Address = Address->sa_Next)
+ {
+ if ((Address->sa_Flags & SPX_ADDR_CLOSING) != 0)
+ {
+ continue;
+ }
+
+ if (Address->sa_Socket == Socket)
+ {
+ // We found the match
+ return TRUE;
+ }
+ }
+
+ // The specified address was not found.
+ return FALSE;
+
+} // SpxAddrExists
+
+
+
+
+NTSTATUS
+SpxAddrConnByRemoteIdAddrLock(
+ IN PSPX_ADDR pSpxAddr,
+ IN USHORT SrcConnId,
+ IN PBYTE SrcIpxAddr,
+ OUT PSPX_CONN_FILE *ppSpxConnFile
+ )
+{
+ PSPX_CONN_FILE pSpxConnFile;
+ NTSTATUS status = STATUS_INVALID_CONNECTION;
+
+ for (pSpxConnFile = pSpxAddr->sa_ActiveConnList;
+ pSpxConnFile != NULL;
+ pSpxConnFile = pSpxConnFile->scf_Next)
+ {
+ if ((pSpxConnFile->scf_RemConnId == SrcConnId) &&
+ (*((UNALIGNED ULONG *)SrcIpxAddr) ==
+ *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr)) &&
+ (*(UNALIGNED ULONG *)(SrcIpxAddr+4) ==
+ *(UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr+4)) &&
+ (*(UNALIGNED ULONG *)(SrcIpxAddr+8) ==
+ *(UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr+8)))
+ {
+ SpxConnFileReference(pSpxConnFile, CFREF_ADDR);
+ *ppSpxConnFile = pSpxConnFile;
+ status = STATUS_SUCCESS;
+ break;
+ }
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxAddrFileStop(
+ IN PSPX_ADDR_FILE pAddrFile,
+ IN PSPX_ADDR Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to terminate all activity on an pAddrFile and
+ destroy the object. We remove every connection and datagram associated
+ with this addressfile from the address database and terminate their
+ activity. Then, if there are no other outstanding addressfiles open on
+ this address, the address will go away.
+
+Arguments:
+
+ pAddrFile - pointer to the addressFile to be stopped
+
+ Address - the owning address for this addressFile (we do not depend upon
+ the pointer in the addressFile because we want this routine to be safe)
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the request
+ is not for a real address.
+
+--*/
+
+{
+ PSPX_CONN_FILE pSpxConnFile, pSpxConnFileNext;
+ CTELockHandle LockHandle;
+
+
+ DBGPRINT(ADDRESS, DBG,
+ ("SpxAddrFileStop: %lx\n", pAddrFile));
+
+ CTEGetLock (&Address->sa_Lock, &LockHandle);
+
+ if (pAddrFile->saf_Flags & SPX_ADDRFILE_CLOSING)
+ {
+ CTEFreeLock (&Address->sa_Lock, LockHandle);
+ return STATUS_SUCCESS;
+ }
+
+ pAddrFile->saf_Flags |= SPX_ADDRFILE_CLOSING;
+
+ pSpxConnFileNext = NULL;
+ if (pSpxConnFile = pAddrFile->saf_AssocConnList)
+ {
+ pSpxConnFileNext = pSpxConnFile;
+ SpxConnFileReference(pSpxConnFile, CFREF_ADDR);
+ }
+
+ while (pSpxConnFile)
+ {
+ if (pSpxConnFileNext = pSpxConnFile->scf_AssocNext)
+ {
+ SpxConnFileReference(pSpxConnFileNext, CFREF_ADDR);
+ }
+ CTEFreeLock (&Address->sa_Lock, LockHandle);
+
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxAddrFileClose: Assoc conn stop %lx when %lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RefCount));
+
+ SpxConnStop(pSpxConnFile);
+ SpxConnFileDereference(pSpxConnFile, CFREF_ADDR);
+
+ CTEGetLock (&Address->sa_Lock, &LockHandle);
+ pSpxConnFile = pSpxConnFileNext;
+ }
+
+ CTEFreeLock (&Address->sa_Lock, LockHandle);
+ return STATUS_SUCCESS;
+
+}
+
+
+
+
+NTSTATUS
+SpxAddrFileCleanup(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ Request - the close request.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the
+ request does not point to a real address.
+
+--*/
+
+{
+ PSPX_ADDR Address;
+ PSPX_ADDR_FILE pSpxAddrFile;
+ NTSTATUS status;
+
+ pSpxAddrFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ DBGPRINT(ADDRESS, INFO,
+ ("SpxAddrFileCleanup: %lx\n", pSpxAddrFile));
+
+ status = SpxAddrFileVerify(pSpxAddrFile);
+ if (!NT_SUCCESS (status))
+ {
+ return(status);
+ }
+
+ // We assume that addressFile has already been verified
+ // at this point.
+ Address = pSpxAddrFile->saf_Addr;
+ CTEAssert (Address);
+
+ SpxAddrFileStop(pSpxAddrFile, Address);
+ SpxAddrFileDereference(pSpxAddrFile, AFREF_VERIFY);
+ return STATUS_SUCCESS;
+}
+
+
+
+
+NTSTATUS
+SpxAddrFileClose(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to close the addressfile pointed to by a file
+ object. If there is any activity to be run down, we will run it down
+ before we terminate the addressfile. We remove every connection and
+ datagram associated with this addressfile from the address database
+ and terminate their activity. Then, if there are no other outstanding
+ addressfiles open on this address, the address will go away.
+
+Arguments:
+
+ Request - the close request.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the
+ request does not point to a real address.
+
+--*/
+
+{
+ PSPX_ADDR Address;
+ PSPX_ADDR_FILE pSpxAddrFile;
+ NTSTATUS status;
+
+ pSpxAddrFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ DBGPRINT(ADDRESS, DBG,
+ ("SpxAddrFileClose: %lx\n", pSpxAddrFile));
+
+ status = SpxAddrFileVerify(pSpxAddrFile);
+
+ if (!NT_SUCCESS (status))
+ {
+ return(status);
+ }
+
+ pSpxAddrFile->saf_CloseReq = Request;
+
+ // We assume that addressFile has already been verified
+ // at this point.
+ Address = pSpxAddrFile->saf_Addr;
+ CTEAssert (Address);
+
+ // Remove us from the access info for this address.
+ ExAcquireResourceExclusive (&Device->dev_AddrResource, TRUE);
+
+#ifdef ISN_NT
+ IoRemoveShareAccess (pSpxAddrFile->saf_FileObject, &Address->u.sa_ShareAccess);
+#endif
+
+ ExReleaseResource (&Device->dev_AddrResource);
+
+
+ SpxAddrFileDereference (pSpxAddrFile, AFREF_CREATE);
+ SpxAddrFileDereference(pSpxAddrFile, AFREF_VERIFY);
+ return STATUS_PENDING;
+
+} // SpxCloseAddressFile
+
+
+
+
+USHORT
+SpxAddrAssignSocket(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine assigns a socket that is unique within a range
+ of SocketUniqueness.
+
+Arguments:
+
+ Device - Pointer to the device context.
+
+Return Value:
+
+ The assigned socket number, or 0 if a unique one cannot
+ be found.
+
+--*/
+
+{
+ BOOLEAN wrapped = FALSE;
+ USHORT temp, Socket;
+
+ // We have to auto-assign a socket.
+ temp = Device->dev_CurrentSocket;
+ PUTSHORT2SHORT(
+ &Socket,
+ Device->dev_CurrentSocket);
+
+ while (TRUE)
+ {
+ Device->dev_CurrentSocket += (USHORT)PARAM(CONFIG_SOCKET_UNIQUENESS);
+ if (Device->dev_CurrentSocket > PARAM(CONFIG_SOCKET_RANGE_END))
+ {
+ Device->dev_CurrentSocket = (USHORT)PARAM(CONFIG_SOCKET_RANGE_START);
+ wrapped = TRUE;
+ }
+
+ if (!SpxAddrExists (Device, Socket))
+ {
+ break;
+ }
+
+ PUTSHORT2SHORT(
+ &Socket,
+ Device->dev_CurrentSocket);
+
+ if (wrapped && (Device->dev_CurrentSocket >= temp))
+ {
+ // If we have checked all possible values given SOCKET_UNIQUENESS...
+ // This may actually return ERROR even if there are
+ // available socket numbers although they may be
+ // implicitly in use due to SOCKET_UNIQUENESS being
+ // > 1. That is the way it is to work.
+
+ Socket = 0;
+ break;
+ }
+ }
+
+ DBGPRINT(ADDRESS, INFO,
+ ("OpenAddress, assigned socket %lx\n", Socket));
+
+ return(Socket);
+}
+
+
+
+
+VOID
+spxAddrInsertIntoGlobalList(
+ IN PSPX_ADDR_FILE pSpxAddrFile
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ pSpxAddrFile->saf_GlobalNext = SpxGlobalAddrList;
+ SpxGlobalAddrList = pSpxAddrFile;
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+
+ return;
+}
+
+
+
+
+NTSTATUS
+spxAddrRemoveFromGlobalList(
+ IN PSPX_ADDR_FILE pSpxAddrFile
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+ PSPX_ADDR_FILE pC, *ppC;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ for (ppC = &SpxGlobalAddrList;
+ (pC = *ppC) != NULL;)
+ {
+ if (pC == pSpxAddrFile)
+ {
+ DBGPRINT(SEND, INFO,
+ ("SpxAddrRemoveFromGlobal: %lx\n", pSpxAddrFile));
+
+ // Remove from list
+ *ppC = pC->saf_GlobalNext;
+ break;
+ }
+
+ ppC = &pC->saf_GlobalNext;
+ }
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+
+ if (pC == NULL)
+ status = STATUS_INVALID_ADDRESS;
+
+ return(status);
+}
+
+
+
+
diff --git a/private/ntos/tdi/isnp/spx/spxbind.c b/private/ntos/tdi/isnp/spx/spxbind.c
new file mode 100644
index 000000000..7610939f7
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/spxbind.c
@@ -0,0 +1,600 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxbind.c
+
+Abstract:
+
+ This module contains the code to bind to the IPX transport, as well as the
+ indication routines for the IPX transport not including the send/recv ones.
+
+Author:
+
+ Stefan Solomon (stefans) Original Version
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXBIND
+
+VOID
+SpxStatus (
+ IN USHORT NicId,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength);
+
+VOID
+SpxFindRouteComplete (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute);
+
+VOID
+SpxScheduleRoute (
+ IN PIPX_ROUTE_ENTRY RouteEntry);
+
+VOID
+SpxLineDown (
+ IN USHORT NicId);
+
+VOID
+SpxLineUp (
+ IN USHORT NicId,
+ IN PIPX_LINE_INFO LineInfo,
+ IN NDIS_MEDIUM DeviceType,
+ IN PVOID ConfigurationData);
+
+VOID
+SpxFindRouteComplete (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute);
+
+#if defined(_PNP_POWER)
+VOID
+SpxPnPNotification(
+ IN IPX_PNP_OPCODE OpCode,
+ IN PVOID PnPData
+ );
+#endif _PNP_POWER
+
+#if defined(_PNP_POWER)
+//
+// globals and externs
+//
+extern CTELock spxTimerLock;
+extern LARGE_INTEGER spxTimerTick;
+extern KTIMER spxTimer;
+extern KDPC spxTimerDpc;
+extern BOOLEAN spxTimerStopped;
+#endif _PNP_POWER
+
+NTSTATUS
+SpxInitBindToIpx(
+ VOID
+ )
+
+{
+ NTSTATUS status;
+ IO_STATUS_BLOCK ioStatusBlock;
+ OBJECT_ATTRIBUTES objectAttr;
+ PIPX_INTERNAL_BIND_INPUT pBindInput;
+ PIPX_INTERNAL_BIND_OUTPUT pBindOutput;
+
+ InitializeObjectAttributes(
+ &objectAttr,
+ &IpxDeviceName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ status = NtCreateFile(
+ &IpxHandle,
+ SYNCHRONIZE | GENERIC_READ,
+ &objectAttr,
+ &ioStatusBlock,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0L);
+
+ if (!NT_SUCCESS(status)) {
+ return status;
+ }
+
+ if ((pBindInput = CTEAllocMem(sizeof(IPX_INTERNAL_BIND_INPUT))) == NULL) {
+ NtClose(IpxHandle);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ // Fill in our bind data
+#if defined(_PNP_POWER)
+ pBindInput->Version = ISN_VERSION;
+#else
+ pBindInput->Version = 1;
+#endif _PNP_POWER
+ pBindInput->Identifier = IDENTIFIER_SPX;
+ pBindInput->BroadcastEnable = FALSE;
+ pBindInput->LookaheadRequired = IPX_HDRSIZE;
+ pBindInput->ProtocolOptions = 0;
+ pBindInput->ReceiveHandler = SpxReceive;
+ pBindInput->ReceiveCompleteHandler = SpxReceiveComplete;
+ pBindInput->StatusHandler = SpxStatus;
+ pBindInput->SendCompleteHandler = SpxSendComplete;
+ pBindInput->TransferDataCompleteHandler = SpxTransferDataComplete;
+ pBindInput->FindRouteCompleteHandler = SpxFindRouteComplete;
+ pBindInput->LineUpHandler = SpxLineUp;
+ pBindInput->LineDownHandler = SpxLineDown;
+ pBindInput->ScheduleRouteHandler = SpxScheduleRoute;
+#if defined(_PNP_POWER)
+ pBindInput->PnPHandler = SpxPnPNotification;
+#endif _PNP_POWER
+
+
+ // First get the length for the output buffer.
+ status = NtDeviceIoControlFile(
+ IpxHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &ioStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPX_INTERNAL_BIND, // IoControlCode
+ pBindInput, // Input Buffer
+ sizeof(IPX_INTERNAL_BIND_INPUT), // Input Buffer Length
+ NULL, // Output Buffer
+ 0);
+
+ if (status == STATUS_PENDING) {
+ status = NtWaitForSingleObject(
+ IpxHandle,
+ (BOOLEAN)FALSE,
+ NULL);
+ }
+
+ if (status != STATUS_BUFFER_TOO_SMALL) {
+ CTEFreeMem(pBindInput);
+ NtClose(IpxHandle);
+ return(STATUS_INVALID_PARAMETER);
+ }
+
+ if ((pBindOutput = CTEAllocMem(ioStatusBlock.Information)) == NULL) {
+ CTEFreeMem(pBindInput);
+ NtClose(IpxHandle);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ status = NtDeviceIoControlFile(
+ IpxHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &ioStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPX_INTERNAL_BIND, // IoControlCode
+ pBindInput, // Input Buffer
+ sizeof(IPX_INTERNAL_BIND_INPUT), // Input Buffer Length
+ pBindOutput, // Output Buffer
+ ioStatusBlock.Information);
+
+ if (status == STATUS_PENDING) {
+ status = NtWaitForSingleObject(
+ IpxHandle,
+ (BOOLEAN)FALSE,
+ NULL);
+ }
+
+ if (status == STATUS_SUCCESS) {
+
+ // Get all the info from the bind output buffer and save in
+ // appropriate places.
+ IpxLineInfo = pBindOutput->LineInfo;
+ IpxMacHdrNeeded = pBindOutput->MacHeaderNeeded;
+ IpxInclHdrOffset = pBindOutput->IncludedHeaderOffset;
+
+ IpxSendPacket = pBindOutput->SendHandler;
+ IpxFindRoute = pBindOutput->FindRouteHandler;
+ IpxQuery = pBindOutput->QueryHandler;
+ IpxTransferData = pBindOutput->TransferDataHandler;
+
+#if !defined(_PNP_POWER)
+ // Copy over the network node info.
+ RtlCopyMemory(
+ SpxDevice->dev_Network,
+ pBindOutput->Network,
+ IPX_NET_LEN);
+
+ RtlCopyMemory(
+ SpxDevice->dev_Node,
+ pBindOutput->Node,
+ IPX_NODE_LEN);
+
+
+ DBGPRINT(TDI, INFO,
+ ("SpxInitBindToIpx: Ipx Net %lx\n",
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network));
+
+ //
+ // Find out how many adapters IPX has, if this fails
+ // just assume one.
+ //
+
+ if ((*IpxQuery)(
+ IPX_QUERY_MAXIMUM_NIC_ID,
+ 0,
+ &SpxDevice->dev_Adapters,
+ sizeof(USHORT),
+ NULL) != STATUS_SUCCESS) {
+
+ SpxDevice->dev_Adapters = 1;
+
+ }
+#endif !_PNP_POWER
+ } else {
+
+ NtClose(IpxHandle);
+ status = STATUS_INVALID_PARAMETER;
+ }
+ CTEFreeMem(pBindInput);
+ CTEFreeMem(pBindOutput);
+
+ return status;
+}
+
+
+
+
+VOID
+SpxUnbindFromIpx(
+ VOID
+ )
+
+{
+ NtClose(IpxHandle);
+ return;
+}
+
+
+
+
+VOID
+SpxStatus(
+ IN USHORT NicId,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength
+ )
+
+{
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxStatus: CALLED WITH %lx\n",
+ GeneralStatus));
+
+ return;
+}
+
+
+
+VOID
+SpxFindRouteComplete (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute
+ )
+
+{
+ CTELockHandle lockHandle;
+ PSPX_FIND_ROUTE_REQUEST pSpxFrReq = (PSPX_FIND_ROUTE_REQUEST)FindRouteRequest;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)pSpxFrReq->fr_Ctx;
+
+ // This will be on a connection. Grab the lock, check the state and go from
+ // there.
+ if (pSpxConnFile == NULL)
+ {
+ // Should this ever happen?
+ KeBugCheck(0);
+ return;
+ }
+
+ // Check the state. The called routines release the lock, remove the reference.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ if (SPX_CONN_CONNECTING(pSpxConnFile))
+ {
+ // We are doing an active connect!
+ SpxConnConnectFindRouteComplete(
+ pSpxConnFile,
+ pSpxFrReq,
+ FoundRoute,
+ lockHandle);
+ }
+ else // For all others call active
+ {
+ SpxConnActiveFindRouteComplete(
+ pSpxConnFile,
+ pSpxFrReq,
+ FoundRoute,
+ lockHandle);
+ }
+
+ // Free the find route request.
+ SpxFreeMemory(pSpxFrReq);
+
+ return;
+}
+
+
+
+
+VOID
+SpxLineUp (
+ IN USHORT NicId,
+ IN PIPX_LINE_INFO LineInfo,
+ IN NDIS_MEDIUM DeviceType,
+ IN PVOID ConfigurationData
+ )
+
+{
+ // With PnP, our local address is changed when we get PnP
+ // notification.
+#if !defined(_PNP_POWER)
+
+ //
+ // If we get a line up for NicId 0, it means our local
+ // network number has changed, re-query from IPX.
+ //
+
+ if (NicId == 0) {
+
+ TDI_ADDRESS_IPX IpxAddress;
+
+ if ((*IpxQuery)(
+ IPX_QUERY_IPX_ADDRESS,
+ 0,
+ &IpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL) == STATUS_SUCCESS) {
+
+ RtlCopyMemory(
+ SpxDevice->dev_Network,
+ &IpxAddress.NetworkAddress,
+ IPX_NET_LEN);
+
+ DBGPRINT(TDI, INFO,
+ ("SpxLineUp: Ipx Net %lx\n",
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network));
+
+ //
+ // The node shouldn't change!
+ //
+
+ if (!RtlEqualMemory(
+ SpxDevice->dev_Node,
+ IpxAddress.NodeAddress,
+ IPX_NODE_LEN)) {
+
+ DBGPRINT(TDI, ERR,
+ ("SpxLineUp: Node address has changed\n"));
+ }
+ }
+
+ } else {
+
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxLineUp: CALLED WITH %lx\n",
+ NicId));
+ }
+
+ return;
+#endif !_PNP_POWER
+
+}
+
+
+
+
+VOID
+SpxLineDown (
+ IN USHORT NicId
+ )
+
+{
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxLineDown: CALLED WITH %lx\n",
+ NicId));
+
+ return;
+}
+
+
+
+
+VOID
+SpxScheduleRoute (
+ IN PIPX_ROUTE_ENTRY RouteEntry
+ )
+
+{
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxScheduleRoute: CALLED WITH %lx\n",
+ RouteEntry));
+
+ return;
+}
+
+#if defined(_PNP_POWER)
+VOID
+SpxPnPNotification(
+ IN IPX_PNP_OPCODE OpCode,
+ IN PVOID PnPData
+ )
+
+/*++
+
+Routine Description:
+
+ This function receives the notification about PnP events from IPX
+
+Arguments:
+
+ OpCode - Type of the PnP event
+
+ PnPData - Data associated with this event.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ USHORT MaximumNicId = 0;
+ CTELockHandle LockHandle;
+ NTSTATUS Status;
+ PDEVICE Device = SpxDevice;
+ UNICODE_STRING UnicodeDeviceName;
+
+ DBGPRINT(DEVICE, DBG,("Received a pnp notification, opcode %d\n",OpCode));
+
+ switch( OpCode ) {
+ case IPX_PNP_ADD_DEVICE : {
+ CTELockHandle TimerLockHandle;
+ IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
+
+
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+
+ if ( PnPInfo->FirstORLastDevice ) {
+ CTEAssert( PnPInfo->NewReservedAddress );
+ CTEAssert( Device->dev_State != DEVICE_STATE_OPEN );
+
+ *(UNALIGNED ULONG *)Device->dev_Network = PnPInfo->NetworkAddress;
+ RtlCopyMemory( Device->dev_Node, PnPInfo->NodeAddress, 6);
+
+ //
+ // Start the timer. It is possible that the timer
+ // was still running or we are still in the timer dpc
+ // from the previous ADD_DEVICE - DELETE_DEVICE execution
+ // cycle. But it is ok simply restart this, because
+ // KeSetTimer implicitly cancels the previous Dpc.
+ //
+
+ CTEGetLock(&spxTimerLock, &TimerLockHandle);
+ spxTimerStopped = FALSE;
+ CTEFreeLock(&spxTimerLock, TimerLockHandle);
+ KeSetTimer(&spxTimer,
+ spxTimerTick,
+ &spxTimerDpc);
+
+
+ Device->dev_State = DEVICE_STATE_OPEN;
+
+
+ CTEAssert( !Device->dev_Adapters );
+
+ IpxLineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
+ IpxLineInfo.MaximumPacketSize = PnPInfo->LineInfo.MaximumPacketSize;
+ // set the provider info
+ SpxDevice->dev_ProviderInfo.MaximumLookaheadData = IpxLineInfo.MaximumPacketSize;
+ // Set the window size in statistics
+ SpxDevice->dev_Stat.MaximumSendWindow =
+ SpxDevice->dev_Stat.AverageSendWindow = PARAM(CONFIG_WINDOW_SIZE) *
+ IpxLineInfo.MaximumSendSize;
+
+ }else {
+ IpxLineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
+ // Set the window size in statistics
+ SpxDevice->dev_Stat.MaximumSendWindow =
+ SpxDevice->dev_Stat.AverageSendWindow = PARAM(CONFIG_WINDOW_SIZE) *
+ IpxLineInfo.MaximumSendSize;
+
+ }
+
+ Device->dev_Adapters++;
+ CTEFreeLock ( &Device->dev_Lock, LockHandle );
+
+ //
+ // Notify the TDI clients about the device creation
+ //
+ if ( PnPInfo->FirstORLastDevice ) {
+ UnicodeDeviceName.Buffer = Device->dev_DeviceName;
+ UnicodeDeviceName.MaximumLength = Device->dev_DeviceNameLen;
+ UnicodeDeviceName.Length = Device->dev_DeviceNameLen - sizeof(WCHAR);
+
+ if ( !NT_SUCCESS( TdiRegisterDeviceObject(
+ &UnicodeDeviceName,
+ &Device->dev_TdiRegistrationHandle ) )) {
+ DBGPRINT(TDI,ERR, ("Failed to register Spx Device with TDI\n"));
+ }
+ }
+
+ break;
+ }
+ case IPX_PNP_DELETE_DEVICE : {
+
+ IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
+
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+
+ CTEAssert( Device->dev_Adapters );
+ Device->dev_Adapters--;
+
+ if ( PnPInfo->FirstORLastDevice ) {
+ Device->dev_State = DEVICE_STATE_LOADED;
+ Device->dev_Adapters = 0;
+ }
+
+ IpxLineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
+ CTEFreeLock ( &Device->dev_Lock, LockHandle );
+
+ if ( PnPInfo->FirstORLastDevice ) {
+ SpxTimerFlushAndStop();
+ //
+ // inform tdi clients about the device deletion
+ //
+ if ( !NT_SUCCESS( TdiDeregisterDeviceObject(
+ Device->dev_TdiRegistrationHandle ) )) {
+ DBGPRINT(TDI,ERR, ("Failed to Deregister Spx Device with TDI\n"));
+ }
+ }
+ //
+ // TBD: call ExNotifyCallback
+ //
+
+ break;
+ }
+ case IPX_PNP_ADDRESS_CHANGE: {
+ IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
+
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+ CTEAssert( PnPInfo->NewReservedAddress );
+
+ *(UNALIGNED ULONG *)Device->dev_Network = PnPInfo->NetworkAddress;
+ RtlCopyMemory( Device->dev_Node, PnPInfo->NodeAddress, 6);
+
+ CTEFreeLock ( &Device->dev_Lock, LockHandle );
+ break;
+ }
+ case IPX_PNP_TRANSLATE_DEVICE:
+ break;
+ case IPX_PNP_TRANSLATE_ADDRESS:
+ break;
+ default:
+ CTEAssert( FALSE );
+ }
+} /* NbiPnPNotification */
+
+#endif _PNP_POWER
diff --git a/private/ntos/tdi/isnp/spx/spxconn.c b/private/ntos/tdi/isnp/spx/spxconn.c
new file mode 100644
index 000000000..4528b64a4
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/spxconn.c
@@ -0,0 +1,3862 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxconn.c
+
+Abstract:
+
+ This module contains code which implements the CONNECTION object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport connection objects.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 5-July-1995
+ Bug fixes - tagged [SA]
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, SpxConnOpen)
+#pragma alloc_text(PAGE, SpxConnCleanup)
+#pragma alloc_text(PAGE, SpxConnClose)
+#endif
+
+// Define module number for event logging entries
+#define FILENUM SPXCONN
+
+VOID
+SpxFindRouteComplete (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute);
+
+
+NTSTATUS
+SpxConnOpen(
+ IN PDEVICE pDevice,
+ IN CONNECTION_CONTEXT ConnCtx,
+ IN PREQUEST pRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to create a connection object and associate the
+ passed ConnectionContext with it.
+
+Arguments:
+
+ pConnCtx - The TDI ConnectionContext to be associated with object
+
+Return Value:
+
+ STATUS_SUCCESS if connection was successfully opened
+ Error otherwise.
+
+--*/
+
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PSPX_CONN_FILE pSpxConnFile;
+
+#ifdef ISN_NT
+ PIRP Irp = (PIRP)pRequest;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+#endif
+
+
+ // Allocate memory for a connection object
+ if ((pSpxConnFile = SpxAllocateZeroedMemory(sizeof(SPX_CONN_FILE))) == NULL)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ // Initialize values
+ pSpxConnFile->scf_Flags = 0;
+ pSpxConnFile->scf_Type = SPX_CONNFILE_SIGNATURE;
+ pSpxConnFile->scf_Size = sizeof (SPX_CONN_FILE);
+
+ CTEInitLock (&pSpxConnFile->scf_Lock);
+
+ pSpxConnFile->scf_ConnCtx = ConnCtx;
+ pSpxConnFile->scf_Device = pDevice;
+
+ // Initialize list for requests.
+ InitializeListHead(&pSpxConnFile->scf_ReqLinkage);
+ InitializeListHead(&pSpxConnFile->scf_RecvLinkage);
+ InitializeListHead(&pSpxConnFile->scf_RecvDoneLinkage);
+ InitializeListHead(&pSpxConnFile->scf_ReqDoneLinkage);
+ InitializeListHead(&pSpxConnFile->scf_DiscLinkage);
+
+#ifdef ISN_NT
+ // easy backlink to file object.
+ pSpxConnFile->scf_FileObject = IrpSp->FileObject;
+#endif
+
+ // For connections we go from 0->0 with flags indicating if a close
+ // happened.
+ pSpxConnFile->scf_RefCount = 0;
+
+ // Insert into a global connection list.
+ spxConnInsertIntoGlobalList(pSpxConnFile);
+
+#if DBG
+
+ // Initialize this to 0xFFFF so we dont hit assert on first packet.
+ pSpxConnFile->scf_PktSeqNum = 0xFFFF;
+
+#endif
+
+ // Set values in the request.
+ REQUEST_OPEN_CONTEXT(pRequest) = (PVOID)pSpxConnFile;
+ REQUEST_OPEN_TYPE(pRequest) = (PVOID)TDI_CONNECTION_FILE;
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxConnOpen: Opened %lx\n", pSpxConnFile));
+
+ ASSERT(status == STATUS_SUCCESS);
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnCleanup(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ Request - the close request.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the
+ request does not point to a real connection
+
+--*/
+
+{
+ NTSTATUS status;
+ CTELockHandle lockHandle;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ // Verify connection file
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ DBGBRK(FATAL);
+ return (status);
+ }
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxConnFileCleanup: %lx.%lx when %lx\n",
+ pSpxConnFile, Request, pSpxConnFile->scf_RefCount));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ pSpxConnFile->scf_CleanupReq = Request;
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ // We have a reference, so it wont go to zero until stop returns. Therefore
+ // deref can expect flag to be set.
+ SpxConnStop(pSpxConnFile);
+ SpxConnFileDereference (pSpxConnFile, CFREF_VERIFY);
+
+ //
+ // If this is a connection which is waiting for a local disconnect,
+ // deref it since we dont expect a disconnect after a cleanup.
+ //
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ if (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_DISC_WAIT)) {
+
+ CTEAssert( (SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED) &&
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC));
+
+ CTEAssert(pSpxConnFile->scf_RefTypes[CFREF_DISCWAITSPX]);
+
+ SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_DISC_WAIT);
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ KdPrint(("Deref for DISCWAIT on connfile: %lx\n", pSpxConnFile));
+
+ SpxConnFileDereference (pSpxConnFile, CFREF_DISCWAITSPX);
+ } else {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+
+ return STATUS_PENDING;
+}
+
+
+
+
+NTSTATUS
+SpxConnClose(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ Request - the close request.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the
+ request does not point to a real connection
+
+--*/
+
+{
+ NTSTATUS status;
+ CTELockHandle lockHandle;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ // Verify connection file
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ DBGBRK(FATAL);
+ return (status);
+ }
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxConnFileClose: %lx when %lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RefCount));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ pSpxConnFile->scf_CloseReq = Request;
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_CLOSING);
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ SpxConnFileDereference (pSpxConnFile, CFREF_VERIFY);
+ return STATUS_PENDING;
+}
+
+
+
+
+VOID
+SpxConnStop(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+ !!!Connection must have a reference when this is called!!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ CTELockHandle lockHandle;
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxConnFileStop: %lx when %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RefCount,
+ pSpxConnFile->scf_Flags));
+
+ // Call disconnect and disassociate
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_STOPPING))
+ {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_STOPPING);
+ if (!SPX_CONN_IDLE(pSpxConnFile))
+ {
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_LOCAL_DISCONNECT,
+ SPX_CALL_TDILEVEL,
+ lockHandle,
+ FALSE); // [SA] Bug #15249
+
+ }
+ else
+ {
+ // Disassociate if we are associated.
+ spxConnDisAssoc(pSpxConnFile, lockHandle);
+ }
+
+ // Lock released at this point.
+ }
+ else
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+ return;
+}
+
+
+
+
+NTSTATUS
+SpxConnAssociate(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine moves the connection from the device list to the inactive
+ connection list in the address of the address file specified. The address
+ file is pointed to by the connection and is referenced for the associate.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ PSPX_ADDR_FILE pSpxAddrFile;
+ CTELockHandle lockHandle1, lockHandle2;
+
+ BOOLEAN derefAddr = FALSE, derefConn = FALSE;
+ PFILE_OBJECT pFileObj = NULL;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+ HANDLE AddrObjHandle =
+ ((PTDI_REQUEST_KERNEL_ASSOCIATE)(REQUEST_PARAMETERS(pRequest)))->AddressHandle;
+
+ do
+ {
+ // Get the handle to the address object from the irp and map it to
+ // the corres. file object.
+ status = ObReferenceObjectByHandle(
+ AddrObjHandle,
+ 0,
+ 0,
+ KernelMode,
+ (PVOID *)&pFileObj,
+ NULL);
+
+ if (!NT_SUCCESS(status))
+ break;
+
+ pSpxAddrFile = pFileObj->FsContext;
+ ASSERT(pFileObj->FsContext2 == (PVOID)TDI_TRANSPORT_ADDRESS_FILE);
+
+ // Verify address file/connection file
+ if ((status = SpxAddrFileVerify(pSpxAddrFile)) != STATUS_SUCCESS)
+ break;
+
+ derefAddr = TRUE;
+
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ break;
+
+ derefConn = TRUE;
+
+ // Grab the addres file lock, then the connection lock for associate.
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle1);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle2);
+ if (!SPX_CONN_FLAG(pSpxConnFile, (SPX_CONNFILE_CLOSING |
+ SPX_CONNFILE_STOPPING |
+ SPX_CONNFILE_ASSOC))
+ &&
+ !(pSpxAddrFile->saf_Flags & SPX_ADDRFILE_CLOSING))
+ {
+ derefAddr = FALSE;
+ SpxAddrFileTransferReference(
+ pSpxAddrFile, AFREF_VERIFY, AFREF_CONN_ASSOC);
+
+ // Queue in the inactive list in the address
+ pSpxConnFile->scf_Next = pSpxAddrFile->saf_Addr->sa_InactiveConnList;
+ pSpxAddrFile->saf_Addr->sa_InactiveConnList = pSpxConnFile;
+
+ // Queue in the assoc list in the address file
+ pSpxConnFile->scf_AssocNext = pSpxAddrFile->saf_AssocConnList;
+ pSpxAddrFile->saf_AssocConnList = pSpxConnFile;
+
+ // Remember the addrfile in the connection
+ pSpxConnFile->scf_AddrFile = pSpxAddrFile;
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_ASSOC);
+
+ status = STATUS_SUCCESS;
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxConnAssociate: %lx with address file %lx\n",
+ pSpxConnFile, pSpxAddrFile));
+ }
+ else
+ {
+ status = STATUS_INVALID_PARAMETER;
+ }
+ CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandle2);
+ CTEFreeLock (pSpxAddrFile->saf_AddrLock, lockHandle1);
+
+ // Dereference the file object corres. to the address object
+ ObDereferenceObject(pFileObj);
+
+ } while (FALSE);
+
+ if (derefAddr)
+ {
+ SpxAddrFileDereference(pSpxAddrFile, AFREF_VERIFY);
+ }
+
+ if (derefConn)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnDisAssociate(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ CTELockHandle lockHandle;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ // Verify connection file
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ return (status);
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ if (!SPX_CONN_IDLE(pSpxConnFile)
+ ||
+ (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC)))
+ {
+ status = STATUS_INVALID_CONNECTION;
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ // Unlink it if ok.
+ if (NT_SUCCESS(status))
+ {
+ SpxConnStop(pSpxConnFile);
+ }
+
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ return(status);
+}
+
+
+
+
+NTSTATUS
+spxConnDisAssoc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ CTELockHandle lockHandleAddr;
+ PSPX_ADDR_FILE pSpxAddrFile;
+
+ if (SPX_CONN_IDLE(pSpxConnFile)
+ &&
+ (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC)))
+ {
+ pSpxAddrFile = pSpxConnFile->scf_AddrFile;
+ }
+ else
+ {
+ status = STATUS_INVALID_CONNECTION;
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ // Unlink it if ok.
+ if (NT_SUCCESS(status))
+ {
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+
+ // Check again as we had released the lock
+ if (SPX_CONN_IDLE(pSpxConnFile)
+ &&
+ (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC)))
+ {
+ pSpxConnFile->scf_AddrFile = NULL;
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_ASSOC);
+
+ // Dequeue the connection from the address file
+ spxConnRemoveFromAssocList(
+ &pSpxAddrFile->saf_AssocConnList,
+ pSpxConnFile);
+
+ // Dequeue the connection file from the address list. It must be
+ // in the inactive list.
+ spxConnRemoveFromList(
+ &pSpxAddrFile->saf_Addr->sa_InactiveConnList,
+ pSpxConnFile);
+ }
+ else
+ {
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ CTEFreeLock (&pSpxConnFile->scf_Lock, LockHandleConn);
+ CTEFreeLock (pSpxAddrFile->saf_AddrLock, lockHandleAddr);
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxConnDisAssociate: %lx from address file %lx\n",
+ pSpxConnFile, pSpxAddrFile));
+
+ if (NT_SUCCESS(status))
+ {
+ // Remove reference on address for this association.
+ SpxAddrFileDereference(pSpxAddrFile, AFREF_CONN_ASSOC);
+ }
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnConnect(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ BUGBUG:
+ We need to have another timer that will be started on the connection
+ if the tdi client indicated a timeout value. 0 -> we do not start such
+ a timer, -1 implies, we let our connection timeout values do their thing.
+ Any other value will forcibly shutdown the connect process, when the timer
+ fires.
+
+Return Value:
+
+
+--*/
+
+{
+ PTDI_REQUEST_KERNEL_CONNECT pParam;
+ TDI_ADDRESS_IPX UNALIGNED * pTdiAddr;
+ PNDIS_PACKET pCrPkt;
+ NTSTATUS status;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PSPX_FIND_ROUTE_REQUEST pFindRouteReq;
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+ PSPX_ADDR pSpxAddr;
+ BOOLEAN locksHeld = TRUE;
+
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ // Unpack the connect parameters
+ pParam = (PTDI_REQUEST_KERNEL_CONNECT)REQUEST_PARAMETERS(pRequest);
+ pTdiAddr= SpxParseTdiAddress(
+ pParam->RequestConnectionInformation->RemoteAddress);
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnConnect: Remote SOCKET %lx on %lx.%lx\n",
+ pTdiAddr->Socket,
+ pSpxConnFile,
+ pRequest));
+
+ // Check if the connection is in a valid state
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ return(status);
+ }
+
+ do
+ {
+ if ((pFindRouteReq =
+ (PSPX_FIND_ROUTE_REQUEST)SpxAllocateMemory(
+ sizeof(SPX_FIND_ROUTE_REQUEST))) == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ // Check if connection is associated, if so, the association cannot
+ // go away until the reference above is removed. So we are safe in
+ // releasing the lock.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ status = STATUS_INVALID_ADDRESS;
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC))
+ {
+ status = STATUS_SUCCESS;
+ pSpxAddr = pSpxConnFile->scf_AddrFile->saf_Addr;
+
+ // See if this connection is to be a spx2 connection.
+ SPX_CONN_RESETFLAG(pSpxConnFile,
+ (SPX_CONNFILE_SPX2 |
+ SPX_CONNFILE_NEG |
+ SPX_CONNFILE_STREAM));
+
+ if ((PARAM(CONFIG_DISABLE_SPX2) == 0) &&
+ (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_SPX2))
+ {
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnConnect: SPX2 requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG(
+ pSpxConnFile, (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
+ }
+
+ if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_STREAM)
+ {
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnConnect: SOCK_STREAM requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_STREAM);
+ }
+
+ if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_NOACKWAIT)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnConnect: NOACKWAIT requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_NOACKWAIT);
+ }
+
+ if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_IPXHDR)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleConnReq: IPXHDR requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR);
+ }
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+
+ } while (FALSE);
+
+ if (!NT_SUCCESS(status))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnConnect: Failed %lx\n", status));
+
+ if (pFindRouteReq)
+ {
+ SpxFreeMemory(pFindRouteReq);
+ }
+
+ return(status);
+ }
+
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(&pSpxAddr->sa_Lock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ locksHeld = TRUE;
+
+ status = STATUS_INVALID_CONNECTION;
+ if (SPX_CONN_IDLE(pSpxConnFile) &&
+ ((pSpxConnFile->scf_LocalConnId = spxConnGetId()) != 0))
+ {
+ //
+ // If this was a post-inactivated file, clear the disconnect flags
+ //
+ if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED)) {
+
+ SPX_DISC_SETSTATE(pSpxConnFile, 0);
+ }
+
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_CONNECTING);
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
+
+ if (((USHORT)PARAM(CONFIG_WINDOW_SIZE) == 0) ||
+ ((USHORT)PARAM(CONFIG_WINDOW_SIZE) > MAX_WINDOW_SIZE))
+ {
+ PARAM(CONFIG_WINDOW_SIZE) = DEFAULT_WINDOW_SIZE;
+ }
+
+ pSpxConnFile->scf_SentAllocNum = (USHORT)(PARAM(CONFIG_WINDOW_SIZE) - 1);
+
+ // Move connection from inactive list to non-inactive list.
+ if (!NT_SUCCESS(spxConnRemoveFromList(
+ &pSpxAddr->sa_InactiveConnList,
+ pSpxConnFile)))
+ {
+ // This should never happen!
+ KeBugCheck(0);
+ }
+
+ // Put connection in the non-inactive list. Connection id must be set.
+ SPX_INSERT_ADDR_ACTIVE(
+ pSpxAddr,
+ pSpxConnFile);
+
+ // Insert in the global connection tree on device
+ spxConnInsertIntoGlobalActiveList(
+ pSpxConnFile);
+
+ // Store the remote address in the connection.
+ // !!NOTE!! We get both the network/socket in network form.
+ *((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) =
+ *((UNALIGNED ULONG *)(&pTdiAddr->NetworkAddress));
+
+ RtlCopyMemory(
+ pSpxConnFile->scf_RemAddr+4,
+ pTdiAddr->NodeAddress,
+ 6);
+
+ *((UNALIGNED USHORT *)(pSpxConnFile->scf_RemAddr+10)) =
+ *((UNALIGNED USHORT *)(&pTdiAddr->Socket));
+
+ // Ok, we are all set, build connect packet, queue it into connection
+ // with the connect request. Ndis buffer already describes this memory
+ // Build IPX header.
+
+ pCrPkt = NULL; // so it knows to allocate one.
+
+ SpxPktBuildCr(
+ pSpxConnFile,
+ pSpxAddr,
+ &pCrPkt,
+ SPX_SENDPKT_IDLE,
+ SPX2_CONN(pSpxConnFile));
+
+ if (pCrPkt != NULL)
+ {
+ // Remember the request in the connection
+ //
+ // Dont queue for the failure case since we complete it in SpxInternalDispatch.
+ //
+ InsertTailList(
+ &pSpxConnFile->scf_ReqLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ SpxConnQueueSendPktTail(pSpxConnFile, pCrPkt);
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pCrPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ // Initialize the find route request
+ *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Network)=
+ *((UNALIGNED ULONG *)pIpxSpxHdr->hdr_DestNet);
+
+ //
+ // [SA] Bug #15094
+ // We need to also pass in the node number to IPX so that IPX can
+ // compare the node addresses to determine the proper WAN NICid
+ //
+
+ // RtlCopyMemory (pFindRouteReq->fr_FindRouteReq.Node, pIpxSpxHdr->hdr_DestNode, 6) ;
+
+ *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Node)=
+ *((UNALIGNED ULONG *)pIpxSpxHdr->hdr_DestNode);
+
+ *((UNALIGNED USHORT *)(pFindRouteReq->fr_FindRouteReq.Node+4))=
+ *((UNALIGNED USHORT *)(pIpxSpxHdr->hdr_DestNode+4));
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnConnect: NETWORK %lx\n",
+ *((UNALIGNED ULONG *)pIpxSpxHdr->hdr_DestNet)));
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnConnect: NODE %02x-%02x-%02x-%02x-%02x-%02x\n",
+ pFindRouteReq->fr_FindRouteReq.Node[0], pFindRouteReq->fr_FindRouteReq.Node[1],
+ pFindRouteReq->fr_FindRouteReq.Node[2], pFindRouteReq->fr_FindRouteReq.Node[3],
+ pFindRouteReq->fr_FindRouteReq.Node[4], pFindRouteReq->fr_FindRouteReq.Node[5]));
+
+ pFindRouteReq->fr_FindRouteReq.Identifier = IDENTIFIER_SPX;
+ pFindRouteReq->fr_Ctx = pSpxConnFile;
+
+ // We wont force a rip for every connection. Only if its not
+ // in the IPX database.
+ pFindRouteReq->fr_FindRouteReq.Type = IPX_FIND_ROUTE_RIP_IF_NEEDED;
+
+ // Reference for the find route. So that abort connect wont
+ // free up the connection until we return from here.
+ SpxConnFileLockReference(pSpxConnFile, CFREF_FINDROUTE);
+ status = STATUS_PENDING;
+ }
+ else
+ {
+ // Abort connect attempt.
+ spxConnAbortConnect(
+ pSpxConnFile,
+ status,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ CTEAssert(pSpxConnFile->scf_ConnectReq == NULL);
+
+ locksHeld = FALSE;
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ if (locksHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(&pSpxAddr->sa_Lock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ // Start off the find route request, We send the packet in completion.
+ // The verify reference is kept until the connect request completes.
+ // If connecting to network 0 we don't do this, proceed to find
+ // route completion which will send the request on very card.
+
+ if (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0) {
+
+ SpxFindRouteComplete(
+ &pFindRouteReq->fr_FindRouteReq,
+ TRUE);
+
+ } else {
+
+ (*IpxFindRoute)(
+ &pFindRouteReq->fr_FindRouteReq);
+ }
+ }
+ else
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnConnect: Failed %lx\n", status));
+
+ SpxFreeMemory(pFindRouteReq);
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnListen(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ We assume the connection passed in is already associated with an address.
+ If it is not, we will die! Is that ok?
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ CTELockHandle lockHandle1, lockHandle2;
+ PSPX_ADDR pSpxAddr;
+
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ // Check if the connection is in a valid state
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ return(status);
+ }
+
+ // Check if connection is associated, if so, the association cannot
+ // go away until the reference above is removed. So we are safe in
+ // releasing the lock.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle2);
+ status = STATUS_INVALID_ADDRESS;
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC))
+ {
+ status = STATUS_SUCCESS;
+ pSpxAddr = pSpxConnFile->scf_AddrFile->saf_Addr;
+
+ // See if this connection is to be a spx2 connection.
+ SPX_CONN_RESETFLAG(pSpxConnFile,
+ (SPX_CONNFILE_SPX2 |
+ SPX_CONNFILE_NEG |
+ SPX_CONNFILE_STREAM));
+
+ if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_SPX2)
+ {
+ SPX_CONN_SETFLAG(
+ pSpxConnFile, (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
+ }
+
+ if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_STREAM)
+ {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_STREAM);
+ }
+
+ if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_NOACKWAIT)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnConnect: NOACKWAIT requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_NOACKWAIT);
+ }
+
+ if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_IPXHDR)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleConnReq: IPXHDR requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR);
+ }
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle2);
+
+ if (NT_SUCCESS(status))
+ {
+ CTEGetLock(&pSpxAddr->sa_Lock, &lockHandle1);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle2);
+ status = STATUS_INVALID_CONNECTION;
+ if (SPX_CONN_IDLE(pSpxConnFile))
+ {
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_LISTENING);
+
+ // Move connection from inactive list to listening list.
+ if (NT_SUCCESS(spxConnRemoveFromList(
+ &pSpxAddr->sa_InactiveConnList,
+ pSpxConnFile)))
+ {
+ // Put connection in the listening list.
+ SPX_INSERT_ADDR_LISTEN(pSpxAddr, pSpxConnFile);
+
+ InsertTailList(
+ &pSpxConnFile->scf_ReqLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ status = STATUS_PENDING;
+ }
+ else
+ {
+ // This should never happen!
+ KeBugCheck(0);
+ }
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle2);
+ CTEFreeLock(&pSpxAddr->sa_Lock, lockHandle1);
+ }
+
+
+ if (!NT_SUCCESS(status))
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnAccept(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_ADDR pSpxAddr;
+ NTSTATUS status;
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnAccept: %lx\n", pSpxConnFile));
+
+ // Check if the connection is in a valid state
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ return (status);
+ }
+
+ // Check if we are in the correct state and associated.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ status = STATUS_INVALID_CONNECTION;
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC))
+ {
+ status = STATUS_SUCCESS;
+ pSpxAddr = pSpxConnFile->scf_AddrFile->saf_Addr;
+ }
+ CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandleConn);
+
+ if (NT_SUCCESS(status))
+ {
+ // Grab all three locks
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ status = STATUS_INVALID_CONNECTION;
+ if ((SPX_CONN_LISTENING(pSpxConnFile)) &&
+ (SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_RECDREQ))
+ {
+ InsertTailList(
+ &pSpxConnFile->scf_ReqLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // Call acceptcr now.
+ spxConnAcceptCr(
+ pSpxConnFile,
+ pSpxAddr,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnAccept: Accepted\n"));
+
+ status = STATUS_PENDING;
+ }
+ else
+ {
+ // Free all locks.
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ }
+ }
+
+ // Remove reference. Note: Listen reference will exist if ok. And that will
+ // be transferred to the fact that the connection is active when accepted.
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnDisconnect(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+/*++
+
+Routine Description:
+
+ If active, we do the following.
+ If informative disconnect, just remember the request in the connection.
+ We do not ref for request. Assume it will always be checked for when
+ changing from disconnect to idle.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PTDI_REQUEST_KERNEL_DISCONNECT pParam;
+ NTSTATUS status;
+ CTELockHandle lockHandleConn;
+ BOOLEAN lockHeld;
+ SPX_SENDREQ_TYPE reqType;
+ int numDerefs = 0;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ pParam = (PTDI_REQUEST_KERNEL_DISCONNECT)REQUEST_PARAMETERS(pRequest);
+
+ // Check if the connection is in a valid state
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ return(status);
+ }
+
+ // Deref unless the disc request gets queued in as a send request.
+ numDerefs++;
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnDisconnect: %lx On %lx when %lx.%lx %lx Params %lx\n",
+ pRequest, pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile),
+ SPX_DISC_STATE(pSpxConnFile),
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC),
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC),
+ pParam->RequestFlags));
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnDisconnect: %lx\n", pSpxConnFile));
+
+ // Check if we are in the correct state and associated.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ lockHeld = TRUE;
+ switch (pParam->RequestFlags)
+ {
+ case TDI_DISCONNECT_WAIT:
+
+ // If informative disconnect, just remember in the connection.
+ status = STATUS_INVALID_CONNECTION;
+ if (!SPX_CONN_IDLE(pSpxConnFile))
+ {
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ status = STATUS_PENDING;
+ }
+
+ break;
+
+ case TDI_DISCONNECT_ABORT:
+ case TDI_DISCONNECT_RELEASE:
+
+ // NOTE! We don't honor the async disconnect symantics of tdi
+ // but map them to an abortive disconnect.
+ // NOTE! If our send list is not empty but our client tries to
+ // do a orderly release, we just queue the ord rel as a send
+ // data request. In process ack, we check for the next packet
+ // to not be a ord rel before giving up on window closure.
+ // NOTE! For spx1 connection, map TDI_DISCONNECT_RELEASE to
+ // TDI_DISCONNECT_ABORT (Informed disconnect)
+
+ if (!SPX2_CONN(pSpxConnFile))
+ {
+ pParam->RequestFlags = TDI_DISCONNECT_ABORT;
+ }
+
+ switch (SPX_MAIN_STATE(pSpxConnFile))
+ {
+ case SPX_CONNFILE_ACTIVE:
+
+ // Since we are not a timer disconnect, then we need to keep
+ // retrying the disconnect packet. Change state to DISCONN if this
+ // is not an orderly release or we previously received an orderly
+ // release and are now confirming it.
+ // Retry timer will now keep sending out the disconnect packet.
+
+ reqType = SPX_REQ_DISC;
+ if (pParam->RequestFlags == TDI_DISCONNECT_RELEASE)
+ {
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_POST_ORDREL);
+ reqType = SPX_REQ_ORDREL;
+ }
+ else
+ {
+ // Abortive disconnect
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_DISCONN);
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_POST_IDISC);
+ numDerefs++;
+
+ spxConnAbortSends(
+ pSpxConnFile,
+ STATUS_LOCAL_DISCONNECT,
+ SPX_CALL_TDILEVEL,
+ lockHandleConn);
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ // Abort all receives if we are informed disconnect.
+ spxConnAbortRecvs(
+ pSpxConnFile,
+ STATUS_LOCAL_DISCONNECT,
+ SPX_CALL_TDILEVEL,
+ lockHandleConn);
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ // Since we released the lock, a remote IDISC could have come
+ // in in which case we really don't want to queue in the disc
+ // request. Instead, we set it as the disc request in the
+ // connection if one is not already there.
+ if (SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_POST_IDISC)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnDisconnect: DISC not POST! %lx.%lx\n",
+ pSpxConnFile, SPX_DISC_STATE(pSpxConnFile)));
+
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ status = STATUS_PENDING;
+ break;
+ }
+ }
+
+ // !NOTE
+ // AbortSends might leave send requests around as packets might
+ // have been with ipx at the time. That is why SendComplete should
+ // never call AbortSends but must call AbortPkt else it may complete
+ // the following disconnect request prematurely.
+
+ // Creation reference for request.
+ REQUEST_INFORMATION(pRequest) = 1;
+
+ // If we have no current requests, queue it in and
+ // set it to be the current request, else just queue it in.
+ // There may be other pending requests in queue.
+ if (pSpxConnFile->scf_ReqPkt == NULL)
+ {
+ pSpxConnFile->scf_ReqPkt = pRequest;
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pSpxConnFile->scf_ReqPktSize = 0;
+ pSpxConnFile->scf_ReqPktType = reqType;
+ }
+
+ InsertTailList(
+ &pSpxConnFile->scf_ReqLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // Do not deref the connection, it is taken by the pending request
+ numDerefs--;
+
+ // We packetize only upto the window we have.
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE)
+ {
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_PACKETIZE);
+ SpxConnPacketize(
+ pSpxConnFile,
+ TRUE,
+ lockHandleConn);
+
+ lockHeld = FALSE;
+ }
+
+ status = STATUS_PENDING;
+ break;
+
+ case SPX_CONNFILE_CONNECTING:
+ case SPX_CONNFILE_LISTENING:
+
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_INSUFFICIENT_RESOURCES,
+ SPX_CALL_TDILEVEL,
+ lockHandleConn,
+ FALSE); // [SA] Bug #15249
+
+ lockHeld = FALSE;
+ status = STATUS_SUCCESS;
+ break;
+
+ case SPX_CONNFILE_DISCONN:
+
+ // When we queue in a disconnect as a send request, we expect
+ // to be able to set it into the scf_DiscReq when it is done.
+ // So we don't use scf_DiscReq here. This will be a problem if
+ // the client has a InformDiscReq pending, and a remote disconnect
+ // comes in, *and* the client then does a disc. We will be completing
+ // the request with STATUS_INVALID_CONNECTION.
+ status = STATUS_INVALID_CONNECTION;
+ if (pParam->RequestFlags != TDI_DISCONNECT_RELEASE)
+ {
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ status = STATUS_PENDING;
+
+ //
+ // If this is a disconnect for a connection which was already
+ // disconnected (but AFD's disconnect handler was not called
+ // because the connfile could not be placed in the inactive list),
+ // set this flag so that the disconnect is not called from
+ // ConnInactivate now that the disconnect has occured here.
+ //
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC)) {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
+ }
+
+ //
+ // If this was an SPXI connection where we indicated TDI_DISCONNECT_RELEASE
+ // to AFD, the ref count was bumped up to indicate a wait for local disconnect
+ // from AFD. Now that we have this disconnect, deref the connection file. Now
+ // we are ready to truly inactivate this connection file.
+ //
+ if (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_DISC_WAIT)) {
+
+ CTEAssert( (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED) &&
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC));
+
+ CTEAssert(pSpxConnFile->scf_RefTypes[CFREF_DISCWAITSPX]);
+
+ SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_DISC_WAIT);
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ lockHeld = FALSE;
+
+ SpxConnFileDereference(pSpxConnFile, CFREF_DISCWAITSPX);
+ }
+ }
+
+ break;
+
+ default:
+
+ // Should never happen!
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ break;
+
+ default:
+
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ }
+
+ DBGPRINT(CONNECT, INFO,
+ ("SpxConnDisconnect: returning for %lx.%lx\n", pSpxConnFile, status));
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnSend(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PTDI_REQUEST_KERNEL_SEND pParam;
+ NTSTATUS status;
+ CTELockHandle lockHandleConn;
+ BOOLEAN lockHeld;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ pParam = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(pRequest);
+
+ // Check if the connection is in a valid state
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ return(status);
+ }
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnSend: %lx.%lx.%lx.%lx\n",
+ pSpxConnFile, pRequest, pParam->SendLength, pParam->SendFlags));
+
+
+ // Check if we are in the correct state and associated.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ lockHeld = TRUE;
+
+ DBGPRINT(SEND, INFO,
+ ("Send: %lx.%lx.%lx\n",
+ pParam->SendLength, pParam->SendFlags, pRequest));
+
+ status = STATUS_PENDING;
+ do
+ {
+ if (SPX_CONN_ACTIVE(pSpxConnFile) &&
+ ((SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_POST_ORDREL) &&
+ (SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_SENT_ORDREL) &&
+ (SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_ORDREL_ACKED)))
+ {
+ // Creation reference for request.
+ REQUEST_INFORMATION(pRequest) = 1;
+
+ // If we have no current requests, queue it in and
+ // set it to be the current request, else just queue it in.
+ // There may be other pending requests in queue.
+ if (pSpxConnFile->scf_ReqPkt == NULL)
+ {
+ DBGPRINT(SEND, INFO,
+ ("%lx\n",
+ pRequest));
+
+ pSpxConnFile->scf_ReqPkt = pRequest;
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pSpxConnFile->scf_ReqPktSize = pParam->SendLength;
+ pSpxConnFile->scf_ReqPktFlags = pParam->SendFlags;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DATA;
+ }
+
+ InsertTailList(
+ &pSpxConnFile->scf_ReqLinkage,
+ REQUEST_LINKAGE(pRequest));
+ //
+ // Currently SPX implements DS_TYPE in such a way that the DS_TYPE field in a packet
+ // takes on the latest value from the connectionfile. Some customers complained that
+ // their apps assume that the DS_TYPE field should reflect the value at the time of
+ // the send (and Novell does this).
+ //
+ // So, instead of keeping a global value, we copy over the DS_TYPE value into the
+ // request if it pends. Look at spxpkt.c:SpxBuildData.
+ //
+ REQUEST_PARAMETERS(pRequest)->Others.Argument3 = (PVOID)pSpxConnFile->scf_DataType;
+
+ }
+ else
+ {
+ //
+ // [SA] Bug #14655
+ // Return the correct error message in case a send fails due to remote disconnect
+ //
+
+ if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ ((SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT) ||
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED)))
+ {
+ status = STATUS_REMOTE_DISCONNECT ;
+ }
+ else
+ {
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ break;
+ }
+
+ // We packetize only upto the window we have.
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE)
+ {
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_PACKETIZE);
+ SpxConnPacketize(pSpxConnFile, TRUE, lockHandleConn);
+ lockHeld = FALSE;
+ }
+
+ } while (FALSE);
+
+
+ if (lockHeld)
+ {
+ CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandleConn);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnRecv(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS status;
+ CTELockHandle lockHandle;
+ BOOLEAN fLockHeld;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ // Check if the connection is in a valid state
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ return(status);
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnReceive: %lx.%lx\n", pSpxConnFile, pRequest));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ fLockHeld = TRUE;
+ status = STATUS_INVALID_CONNECTION;
+ if (SPX_CONN_ACTIVE(pSpxConnFile) &&
+ !(SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC)))
+ {
+ status = STATUS_PENDING;
+
+ // This routine adds its own reference.
+ SpxConnQueueRecv(pSpxConnFile, pRequest);
+
+ // If recv pkt queue is non-empty then we have buffered data. Call
+ // process pkts/receives.
+ if ((SPX_RECV_STATE(pSpxConnFile) == SPX_RECV_IDLE) ||
+ (SPX_RECV_STATE(pSpxConnFile) == SPX_RECV_POSTED))
+ {
+ SpxRecvProcessPkts(pSpxConnFile, lockHandle);
+ fLockHeld = FALSE;
+ }
+ }
+
+ if (fLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnAction(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS Status;
+ UINT BufferLength;
+ UINT DataLength;
+ PNDIS_BUFFER NdisBuffer;
+ PNWLINK_ACTION NwlinkAction;
+ CTELockHandle lockHandle;
+ PIPX_SPXCONNSTATUS_DATA pGetStats;
+ PSPX_CONN_FILE pSpxConnFile = NULL;
+ PSPX_ADDR_FILE pSpxAddrFile = NULL;
+ static UCHAR BogusId[4] = { 0x01, 0x00, 0x00, 0x00 }; // old nwrdr uses this
+
+ //
+ // To maintain some compatibility with the NWLINK streams-
+ // based transport, we use the streams header format for
+ // our actions. The old transport expected the action header
+ // to be in InputBuffer and the output to go in OutputBuffer.
+ // We follow the TDI spec, which states that OutputBuffer
+ // is used for both input and output. Since IOCTL_TDI_ACTION
+ // is method out direct, this means that the output buffer
+ // is mapped by the MDL chain; for action the chain will
+ // only have one piece so we use it for input and output.
+ //
+
+ NdisBuffer = REQUEST_NDIS_BUFFER(pRequest);
+ if (NdisBuffer == NULL)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ NdisQueryBuffer(
+ REQUEST_NDIS_BUFFER(pRequest), (PVOID *)&NwlinkAction, &BufferLength);
+
+ if ((!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MISN", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MIPX", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "XPIM", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), BogusId, 4))) {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ // Make sure we have enough room for just the header not
+ // including the data.
+ if (BufferLength < (UINT)(FIELD_OFFSET(NWLINK_ACTION, Data[0])))
+ {
+ DBGPRINT(ACTION, ERR,
+ ("Nwlink action failed, buffer too small\n"));
+
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ DataLength = BufferLength - FIELD_OFFSET(NWLINK_ACTION, Data[0]);
+
+ // Make sure that the correct file object is being used.
+ switch (NwlinkAction->OptionType)
+ {
+ case NWLINK_OPTION_CONNECTION:
+
+ if (REQUEST_OPEN_TYPE(pRequest) != (PVOID)TDI_CONNECTION_FILE)
+ {
+ DBGPRINT(ACTION, ERR,
+ ("Nwlink action failed, not connection file\n"));
+
+ return STATUS_INVALID_HANDLE;
+ }
+
+ pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ if ((Status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ return(Status);
+
+ break;
+
+ case NWLINK_OPTION_ADDRESS:
+
+ if (REQUEST_OPEN_TYPE(pRequest) != (PVOID)TDI_TRANSPORT_ADDRESS_FILE)
+ {
+ DBGPRINT(ACTION, ERR,
+ ("Nwlink action failed, not address file\n"));
+
+ return STATUS_INVALID_HANDLE;
+ }
+
+ pSpxAddrFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ if ((Status = SpxAddrFileVerify(pSpxAddrFile)) != STATUS_SUCCESS)
+ return(Status);
+
+ break;
+
+ default:
+
+ DBGPRINT(ACTION, ERR,
+ ("Nwlink action failed, option type %d\n",
+ NwlinkAction->OptionType));
+
+ return STATUS_INVALID_HANDLE;
+ }
+
+ // Handle the requests based on the action code. For these
+ // requests ActionHeader->ActionCode is 0, we use the
+ // Option field in the streams header instead.
+
+ Status = STATUS_SUCCESS;
+
+ DBGPRINT(ACTION, INFO,
+ ("SpxConnAction: Option %x\n", NwlinkAction->Option));
+
+ switch (NwlinkAction->Option)
+ {
+
+ //
+ // This first group support the winsock helper dll.
+ // In most cases the corresponding sockopt is shown in
+ // the comment, as well as the contents of the Data
+ // part of the action buffer.
+ //
+
+ case MSPX_SETDATASTREAM:
+
+ if (pSpxConnFile == NULL)
+ {
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ if (DataLength >= 1)
+ {
+ DBGPRINT(ACTION, INFO,
+ ("%lx: MIPX_SETSENDPTYPE %x\n",
+ pSpxConnFile, NwlinkAction->Data[0]));
+
+ pSpxConnFile->scf_DataType = NwlinkAction->Data[0];
+ }
+ else
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+
+ case MSPX_SENDHEADER:
+
+ DBGPRINT(ACTION, INFO,
+ ("%lx: MSPX_SENDHEADER\n", pSpxAddrFile));
+
+ if (pSpxAddrFile == NULL)
+ {
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle);
+ pSpxAddrFile->saf_Flags |= SPX_ADDRFILE_IPXHDR;
+ CTEFreeLock(pSpxAddrFile->saf_AddrLock, lockHandle);
+ break ;
+
+ case MSPX_NOSENDHEADER:
+
+ DBGPRINT(ACTION, INFO,
+ ("%lx: MSPX_NOSENDHEADER\n", pSpxAddrFile));
+
+ if (pSpxAddrFile == NULL)
+ {
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle);
+ pSpxAddrFile->saf_Flags &= ~SPX_ADDRFILE_IPXHDR;
+ CTEFreeLock(pSpxAddrFile->saf_AddrLock, lockHandle);
+ break;
+
+ case MSPX_GETSTATS:
+
+ DBGPRINT(ACTION, INFO,
+ ("%lx: MSPX_GETSTATS\n", pSpxConnFile));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ if (!SPX_CONN_IDLE(pSpxConnFile))
+ {
+ USHORT TempRetryCount;
+
+ //
+ // Status fields are returned in network order.
+ //
+
+ pGetStats = (PIPX_SPXCONNSTATUS_DATA)&NwlinkAction->Data[0];
+
+ switch (SPX_MAIN_STATE(pSpxConnFile)) {
+ case SPX_CONNFILE_LISTENING: pGetStats->ConnectionState = 1; break;
+ case SPX_CONNFILE_CONNECTING: pGetStats->ConnectionState = 2; break;
+ case SPX_CONNFILE_ACTIVE: pGetStats->ConnectionState = 3; break;
+ case SPX_CONNFILE_DISCONN: pGetStats->ConnectionState = 4; break;
+ default: pGetStats->ConnectionState = 0;
+ }
+ pGetStats->WatchDogActive = 1; // Always 1
+ GETSHORT2SHORT( // scf_LocalConnId is in host order
+ &pGetStats->LocalConnectionId,
+ &pSpxConnFile->scf_LocalConnId);
+ pGetStats->RemoteConnectionId = pSpxConnFile->scf_RemConnId;
+
+ GETSHORT2SHORT(&pGetStats->LocalSequenceNumber, &pSpxConnFile->scf_SendSeqNum);
+ GETSHORT2SHORT(&pGetStats->LocalAckNumber, &pSpxConnFile->scf_RecvSeqNum);
+ GETSHORT2SHORT(&pGetStats->LocalAllocNumber, &pSpxConnFile->scf_SentAllocNum);
+ GETSHORT2SHORT(&pGetStats->RemoteAckNumber, &pSpxConnFile->scf_RecdAckNum);
+ GETSHORT2SHORT(&pGetStats->RemoteAllocNumber, &pSpxConnFile->scf_RecdAllocNum);
+
+ pGetStats->LocalSocket = pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket;
+
+ RtlZeroMemory(pGetStats->ImmediateAddress, 6);
+
+ // Remote network returned in net order.
+ *((ULONG UNALIGNED *)pGetStats->RemoteNetwork) =
+ *((ULONG UNALIGNED *)pSpxConnFile->scf_RemAddr);
+
+ RtlCopyMemory(
+ pGetStats->RemoteNode,
+ &pSpxConnFile->scf_RemAddr[4],
+ 6);
+
+ pGetStats->RemoteSocket = *((UNALIGNED USHORT *)(pSpxConnFile->scf_RemAddr+10));
+
+ TempRetryCount = (USHORT)pSpxConnFile->scf_WRetryCount;
+ GETSHORT2SHORT(&pGetStats->RetransmissionCount, &TempRetryCount);
+ GETSHORT2SHORT(&pGetStats->EstimatedRoundTripDelay, &pSpxConnFile->scf_BaseT1);
+ pGetStats->RetransmittedPackets = 0;
+ pGetStats->SuppressedPacket = 0;
+
+ DBGPRINT(ACTION, INFO,
+ ("SSeq %lx RSeq %lx RecdAck %lx RemAllocNum %lx\n",
+ pGetStats->LocalSequenceNumber,
+ pGetStats->LocalAckNumber,
+ pGetStats->RemoteAckNumber,
+ pGetStats->RemoteAllocNumber));
+
+ DBGPRINT(ACTION, INFO,
+ ("LocalSkt %lx RemSkt %lx LocConnId %lx RemConnId %lx\n",
+ pGetStats->LocalSocket,
+ pGetStats->RemoteSocket,
+ pGetStats->LocalConnectionId,
+ pGetStats->RemoteConnectionId));
+ }
+ else
+ {
+ Status = STATUS_INVALID_CONNECTION;
+ }
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ break;
+
+ case MSPX_NOACKWAIT:
+
+ DBGPRINT(ACTION, ERR,
+ ("%lx: MSPX_NOACKWAIT\n", pSpxAddrFile));
+
+ if (pSpxAddrFile == NULL)
+ {
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle);
+ pSpxAddrFile->saf_Flags |= SPX_ADDRFILE_NOACKWAIT;
+ CTEFreeLock(pSpxAddrFile->saf_AddrLock, lockHandle);
+ break;
+
+ case MSPX_ACKWAIT:
+
+ DBGPRINT(ACTION, ERR,
+ ("%lx: MSPX_ACKWAIT\n", pSpxAddrFile));
+
+ if (pSpxAddrFile == NULL)
+ {
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle);
+ pSpxAddrFile->saf_Flags &= ~SPX_ADDRFILE_NOACKWAIT;
+ CTEFreeLock(pSpxAddrFile->saf_AddrLock, lockHandle);
+ break;
+
+
+ //
+ // These are new for ISN (not supported in NWLINK).
+ //
+
+ // The Option was not supported, so fail.
+ default:
+
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+
+
+ } // end of the long switch on NwlinkAction->Option
+
+
+#if DBG
+ if (Status != STATUS_SUCCESS) {
+ DBGPRINT(ACTION, ERR,
+ ("Nwlink action %lx failed, status %lx\n",
+ NwlinkAction->Option, Status));
+ }
+
+#endif
+
+ if (pSpxConnFile)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ if (pSpxAddrFile)
+ {
+ SpxAddrFileDereference(pSpxAddrFile, AFREF_VERIFY);
+ }
+
+ return Status;
+}
+
+
+
+
+VOID
+SpxConnConnectFindRouteComplete(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_FIND_ROUTE_REQUEST pFrReq,
+ IN BOOLEAN FoundRoute,
+ IN CTELockHandle LockHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine is called with the connection lock held and the conn refd.
+ It should deal with both.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pCrPkt;
+ PSPX_SEND_RESD pSendResd;
+ ULONG Timeout;
+ NTSTATUS status = STATUS_BAD_NETWORK_PATH;
+
+ pSendResd = pSpxConnFile->scf_SendListHead;
+ pCrPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ DBGPRINT(CONNECT, INFO,
+ ("SpxConnConnectFindRouteComplete: %lx.%d\n",
+ pSpxConnFile, FoundRoute));
+
+#if defined(_PNP_POWER)
+
+ Timeout = PARAM(CONFIG_CONNECTION_TIMEOUT) * HALFSEC_TO_MS_FACTOR;
+#else
+ if (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0) {
+
+ // Here we are going to send on every NIC ID. We adjust the
+ // timeout down so that a full run through all the NIC IDs will
+ // take one normal timeout. We don't adjust the timer below
+ // 100 ms however.
+
+ Timeout = (PARAM(CONFIG_CONNECTION_TIMEOUT) * HALFSEC_TO_MS_FACTOR) / SpxDevice->dev_Adapters;
+ if (Timeout < (HALFSEC_TO_MS_FACTOR/5)) {
+ Timeout = HALFSEC_TO_MS_FACTOR / 5;
+ }
+
+ } else {
+
+ Timeout = PARAM(CONFIG_CONNECTION_TIMEOUT) * HALFSEC_TO_MS_FACTOR;
+ }
+#endif
+
+
+ // Timeout value is in half-seconds
+ if ((FoundRoute) &&
+ ((pSpxConnFile->scf_CTimerId =
+ SpxTimerScheduleEvent(
+ spxConnConnectTimer,
+ Timeout,
+ pSpxConnFile)) != 0))
+ {
+ // Add a reference for the connect timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+
+#if 0
+ {
+ int i;
+ char *address = pFrReq->fr_FindRouteReq.LocalTarget.MacAddress;
+
+ DbgPrint("FIND ROUTE LOCALTARGET.MAC:\n");
+ for (i= 0; i < 6; i++)
+ {
+ UCHAR ch1, ch2;
+
+ ch1 = ((address[i] >> 4) & 0x0F);
+ if (ch1 > 0x9)
+ {
+ ch1 -= 0xa;
+ ch1 += 'a';
+ }
+ else
+ {
+ ch1 += '0';
+ }
+
+ ch2 = (address[i] & 0x0F);
+ if (ch2 > 0x9)
+ {
+ ch2 -= 0xa;
+ ch2 += 'a';
+ }
+ else
+ {
+ ch2 += '0';
+ }
+
+ DbgPrint("%c%c", ch1, ch2);
+ }
+ DbgPrint("\n");
+
+ address = pSpxConnFile->scf_RemAddr+4;
+ DbgPrint("SPX DESTINATION ADDRESS:\n");
+ for (i= 0; i < 6; i++)
+ {
+ UCHAR ch1, ch2;
+
+ ch1 = ((address[i] >> 4) & 0x0F);
+ if (ch1 > 0x9)
+ {
+ ch1 -= 0xa;
+ ch1 += 'a';
+ }
+ else
+ {
+ ch1 += '0';
+ }
+
+ ch2 = (address[i] & 0x0F);
+ if (ch2 > 0x9)
+ {
+ ch2 -= 0xa;
+ ch2 += 'a';
+ }
+ else
+ {
+ ch2 += '0';
+ }
+
+ DbgPrint("%c%c", ch1, ch2);
+ }
+ DbgPrint("\n");
+ }
+
+ DbgPrint("NIC Id %lx\n", pFrReq->fr_FindRouteReq.LocalTarget.NicId);
+#endif
+
+ // If the mac address in local target is all zeros, fill it with our
+ // destination address. Also if this is a connect to network 0 fill
+ // it in with the destination address, and further down we will loop
+ // through all possible NIC IDs.
+ if (((*((UNALIGNED ULONG *)
+ (pFrReq->fr_FindRouteReq.LocalTarget.MacAddress+2)) == (ULONG)0)
+ &&
+ (*((UNALIGNED USHORT *)
+ (pFrReq->fr_FindRouteReq.LocalTarget.MacAddress+4)) == (USHORT)0))
+ ||
+ (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0))
+ {
+ DBGPRINT(CONNECT, INFO,
+ ("SpxConnConnectFindRouteComplete: LOCAL NET\n"));
+
+ RtlCopyMemory(
+ pFrReq->fr_FindRouteReq.LocalTarget.MacAddress,
+ pSpxConnFile->scf_RemAddr+4,
+ 6);
+ }
+
+ // We are all set to go ahead with the connect.
+ // Timer is started on connection
+ status = STATUS_SUCCESS;
+
+#if defined(_PNP_POWER)
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
+#else
+ if (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0) {
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT) * SpxDevice->dev_Adapters;
+ } else {
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
+ }
+#endif _PNP_POWER
+
+ SPX_CONN_SETFLAG(pSpxConnFile,
+ (SPX_CONNFILE_C_TIMER | SPX_CONNECT_SENTREQ));
+
+ pSpxConnFile->scf_LocalTarget = pFrReq->fr_FindRouteReq.LocalTarget;
+ pSpxConnFile->scf_AckLocalTarget= pFrReq->fr_FindRouteReq.LocalTarget;
+ if (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0) {
+#if defined(_PNP_POWER)
+ pSpxConnFile->scf_LocalTarget.NicHandle.NicId = 0;
+ pSpxConnFile->scf_AckLocalTarget.NicHandle.NicId = 0;
+#else
+ pSpxConnFile->scf_LocalTarget.NicId = 1;
+ pSpxConnFile->scf_AckLocalTarget.NicId = 1;
+#endif _PNP_POWER
+ }
+
+ // We will be giving the packet to ipx.
+ pSendResd->sr_State |= SPX_SENDPKT_IPXOWNS;
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandle);
+
+ // Send the packet
+ SPX_SENDPACKET(pSpxConnFile, pCrPkt, pSendResd);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandle);
+
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnConnectFindRouteComplete: FAILED on %lx.%d\n",
+ pSpxConnFile, FoundRoute));
+
+ spxConnAbortConnect(
+ pSpxConnFile,
+ status,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+ }
+
+ // Remove the reference for the call.
+ SpxConnFileDereference(pSpxConnFile, CFREF_FINDROUTE);
+ return;
+}
+
+
+
+
+VOID
+SpxConnActiveFindRouteComplete(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_FIND_ROUTE_REQUEST pFrReq,
+ IN BOOLEAN FoundRoute,
+ IN CTELockHandle LockHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine is called with the connection lock held and the conn refd.
+ It should deal with both.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ BOOLEAN fDisconnect = TRUE;
+
+ SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_FINDROUTE);
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnActiveFindRouteComplete: %lx.%lx\n",
+ pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ // If we are disconnecting, just remove the reference and exit.
+ if (SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_ACTIVE)
+ {
+ fDisconnect = FALSE;
+
+ // We are here if either the wdog or the retry timer did a find
+ // route. We need to save the info from the find route if it was
+ // successful and just restart the timers.
+ if (FoundRoute)
+ {
+ // If the mac address in local target is all zeros, fill it with our
+ // destination address.
+ if ((*((UNALIGNED ULONG *)
+ (pFrReq->fr_FindRouteReq.LocalTarget.MacAddress+2)) == (ULONG)0)
+ &&
+ (*((UNALIGNED USHORT *)
+ (pFrReq->fr_FindRouteReq.LocalTarget.MacAddress+4)) == (USHORT)0))
+ {
+ DBGPRINT(CONNECT, INFO,
+ ("SpxConnActiveFindRouteComplete: LOCAL NET\n"));
+
+ RtlCopyMemory(
+ pFrReq->fr_FindRouteReq.LocalTarget.MacAddress,
+ pSpxConnFile->scf_RemAddr+4,
+ 6);
+ }
+
+ pSpxConnFile->scf_LocalTarget = pFrReq->fr_FindRouteReq.LocalTarget;
+ }
+
+ // Depending on state restart the wdog or retry timer. Add reference
+ // for it.
+ switch (SPX_SEND_STATE(pSpxConnFile))
+ {
+ case SPX_SEND_RETRY:
+
+ // Set state to SPX_SEND_RETRYWD
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRYWD);
+
+ // Start retry timer.
+ if ((pSpxConnFile->scf_RTimerId =
+ SpxTimerScheduleEvent(
+ spxConnRetryTimer,
+ pSpxConnFile->scf_BaseT1,
+ pSpxConnFile)) != 0)
+ {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
+
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ }
+ else
+ {
+ fDisconnect = TRUE;
+ }
+
+ break;
+
+ case SPX_SEND_WD:
+
+ // Start watchdog timer.
+ if ((pSpxConnFile->scf_WTimerId =
+ SpxTimerScheduleEvent(
+ spxConnWatchdogTimer,
+ PARAM(CONFIG_KEEPALIVE_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) != 0)
+ {
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ }
+ else
+ {
+ fDisconnect = TRUE;
+ }
+
+ break;
+
+ case SPX_SEND_IDLE:
+ case SPX_SEND_PACKETIZE:
+
+ // Do nothing, remove reference and leave.
+ break;
+
+ default:
+
+ KeBugCheck(0);
+ }
+ }
+
+ if (fDisconnect)
+ {
+ DBGPRINT(CONNECT, DBG1,
+ ("SpxConnActiveFindRouteComplete: DISCONNECT %lx.%lx\n",
+ pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ // Abortive disc will reset the funky state if necessary.
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_INSUFFICIENT_RESOURCES,
+ SPX_CALL_TDILEVEL,
+ LockHandle,
+ FALSE); // [SA] Bug #15249
+ }
+ else
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandle);
+ }
+
+ SpxConnFileDereference(pSpxConnFile, CFREF_FINDROUTE);
+ return;
+}
+
+
+
+
+ULONG
+spxConnConnectTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown
+ )
+/*++
+
+Routine Description:
+
+ We enter this routine during the connection attempt. We could be at any
+ stage of sending either the CR or the SN packet. If we have reached the end of
+ the retry count, we need to know the substate at that point. For a CR, we give
+ up trying to connect, and for a SN we try the next lower packet size or if we
+ have reached the minimum packet size, we give up the connect.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)Context;
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+ BOOLEAN fAbort = FALSE, locksHeld = FALSE, sendPkt = FALSE;
+ PREQUEST pRequest = NULL;
+
+ // Get all locks
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ locksHeld = TRUE;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnConnectTimer: Entered\n"));
+
+ do
+ {
+ if ((!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER)) ||
+ (!SPX_CONN_CONNECTING(pSpxConnFile) &&
+ !SPX_CONN_LISTENING(pSpxConnFile)))
+ {
+ TimerShuttingDown = TRUE;
+ }
+
+ if (TimerShuttingDown)
+ {
+ break;
+ }
+
+ if (SPX_CONN_CONNECTING(pSpxConnFile))
+ {
+ switch (SPX_CONNECT_STATE(pSpxConnFile))
+ {
+ case SPX_CONNECT_SENTREQ:
+
+ // There should be only one packet in list, the cr.
+ CTEAssert(pSpxConnFile->scf_SendListHead ==
+ pSpxConnFile->scf_SendListTail);
+
+ pSendResd = pSpxConnFile->scf_SendListHead;
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd,
+ NDIS_PACKET,
+ ProtocolReserved);
+
+ if (pSpxConnFile->scf_CRetryCount-- == 0)
+ {
+ // No luck, we need to complete connect request with failure
+ ++SpxDevice->dev_Stat.NotFoundFailures;
+ fAbort = TRUE;
+ break;
+ }
+
+ // We need to resend the packet
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0)
+ {
+ // Try next time.
+ break;
+ }
+
+ pSendResd->sr_State |= SPX_SENDPKT_IPXOWNS;
+ sendPkt = TRUE;
+ break;
+
+ case SPX_CONNECT_NEG:
+
+ if (!spxConnGetPktByType(
+ pSpxConnFile,
+ SPX_TYPE_SN,
+ FALSE,
+ &pPkt))
+ {
+ KeBugCheck(0);
+ }
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0)
+ {
+ // Try when we come in next.
+ break;
+ }
+
+
+ // If we have exhausted current retries, try next smaller size.
+ // If this was the smallest size, we abort.
+ if (pSpxConnFile->scf_CRetryCount-- == 0)
+ {
+ // Have we tried the smallest size?
+ CTEAssert(pSpxConnFile->scf_MaxPktSize > 0);
+ if (!spxConnCheckNegSize(&pSpxConnFile->scf_MaxPktSize))
+ {
+ // Give up! Remove negotiate packet etc.
+ ++SpxDevice->dev_Stat.SessionTimeouts;
+ fAbort = TRUE;
+ break;
+ }
+
+ // Set neg pkt size to new lower size
+ spxConnSetNegSize(
+ pPkt,
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE);
+
+ pSpxConnFile->scf_CRetryCount =
+ PARAM(CONFIG_CONNECTION_COUNT);
+ }
+
+ // We need to resend the packet
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0);
+ pSendResd->sr_State |= SPX_SENDPKT_IPXOWNS;
+ sendPkt = TRUE;
+ break;
+
+ case SPX_CONNECT_W_SETUP:
+ default:
+
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnConnectTimer: state is W_Setup %lx\n",
+ pSpxConnFile));
+
+ KeBugCheck(0);
+ }
+ }
+ else
+ {
+ switch (SPX_LISTEN_STATE(pSpxConnFile))
+ {
+ case SPX_LISTEN_SETUP:
+
+ if (!spxConnGetPktByType(
+ pSpxConnFile,
+ SPX_TYPE_SS,
+ FALSE,
+ &pPkt))
+ {
+ KeBugCheck(0);
+ }
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0)
+ {
+ // Try when we come in next.
+ break;
+ }
+
+ // If we have exhausted current retries, try next smaller size.
+ // If this was the smallest size, we abort.
+ if (pSpxConnFile->scf_CRetryCount-- == 0)
+ {
+ // Have we tried the smallest size?
+ if (!spxConnCheckNegSize(&pSpxConnFile->scf_MaxPktSize))
+ {
+ // Give up! Remove negotiate packet etc. Have an abort
+ // kind of routine.
+ ++SpxDevice->dev_Stat.SessionTimeouts;
+ fAbort = TRUE;
+ break;
+ }
+
+ // Set neg pkt size to new lower size
+ spxConnSetNegSize(
+ pPkt,
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE);
+
+ pSpxConnFile->scf_CRetryCount =
+ PARAM(CONFIG_CONNECTION_COUNT);
+ }
+
+ // We need to resend the packet
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0);
+
+ pSendResd->sr_State |= SPX_SENDPKT_IPXOWNS;
+ sendPkt = TRUE;
+ break;
+
+ default:
+
+ KeBugCheck(0);
+
+ }
+ }
+
+ } while (FALSE);
+
+ if (fAbort)
+ {
+ CTEAssert(!sendPkt);
+
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnConnectTimer: Expired for %lx\n", pSpxConnFile));
+
+ spxConnAbortConnect(
+ pSpxConnFile,
+ STATUS_BAD_NETWORK_PATH,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ }
+
+ if (locksHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ }
+
+ if (sendPkt)
+ {
+ CTEAssert(!fAbort);
+
+#if !defined(_PNP_POWER)
+ if ((SPX_CONNECT_STATE(pSpxConnFile) == SPX_CONNECT_SENTREQ) &&
+ (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0)) {
+
+ // we are sending to all NICs because this is the initial
+ // connect frame and the remote network is 0.
+
+ pSpxConnFile->scf_LocalTarget.NicId = (USHORT)
+ ((pSpxConnFile->scf_LocalTarget.NicId % SpxDevice->dev_Adapters) + 1);
+
+ // we pass this a valid packet in pPkt, so it knows to
+ // just refresh the header and not update the protocol
+ // reserved variables.
+
+ SpxPktBuildCr(
+ pSpxConnFile,
+ pSpxConnFile->scf_AddrFile->saf_Addr,
+ &pPkt,
+ 0, // state will not be updated
+ SPX2_CONN(pSpxConnFile));
+
+ }
+#endif !_PNP_POWER
+
+ // Send the packet
+ SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ if (TimerShuttingDown || fAbort)
+ {
+ // Dereference connection for verify done in connect, for timer. This
+ // should complete any pending disconnects if they had come in in the
+ // meantime.
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ return(TIMER_DONT_REQUEUE);
+ }
+
+ return(TIMER_REQUEUE_CUR_VALUE);
+}
+
+
+
+
+ULONG
+spxConnWatchdogTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown
+ )
+/*++
+
+Routine Description:
+
+ This is started on a connection right after the CR or the CR ack is received.
+ During the connection establishment phase, it does nothing other than decrement
+ the retry count and upon reaching 0, it aborts the connection. When it goes off
+ and finds the connection is active, it sends a probe.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)Context;
+ CTELockHandle lockHandle;
+ PSPX_SEND_RESD pSendResd;
+ PSPX_FIND_ROUTE_REQUEST pFindRouteReq;
+ PNDIS_PACKET pProbe = NULL;
+ BOOLEAN lockHeld, fSpx2 = SPX2_CONN(pSpxConnFile),
+ fDisconnect = FALSE, fFindRoute = FALSE, fSendProbe = FALSE;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnWatchdogTimer: Entered\n"));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ lockHeld = TRUE;
+ do
+ {
+ if (TimerShuttingDown ||
+ (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER)) ||
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT))
+ {
+#if DBG
+ if ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_IDLE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_WD))
+ {
+ CTEAssert(FALSE);
+ }
+#endif
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ TimerShuttingDown = TRUE;
+ break;
+ }
+
+ // If the retry timer is active on this connection, and the watchdog
+ // timer happens to fire, just requeue ourselves for spx2. For spx1,
+ // we go ahead with sending a probe. Retry timer does the same things
+ // watchdog does for spx2.
+ switch (SPX_MAIN_STATE(pSpxConnFile))
+ {
+ case SPX_CONNFILE_ACTIVE:
+ case SPX_CONNFILE_DISCONN:
+
+ // Squash the race condition where a disconnect request is never
+ // packetized, because the send state was not IDLE.
+ if (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_POST_IDISC)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnWatchdogTimer: POST IDISC %lx\n",
+ pSpxConnFile));
+
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnWatchdogTimer: PKT POST IDISC %lx\n",
+ pSpxConnFile));
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_PACKETIZE);
+ SpxConnPacketize(
+ pSpxConnFile,
+ TRUE,
+ lockHandle);
+
+ lockHeld = FALSE;
+ break;
+ }
+ }
+
+ if (!fSpx2)
+ {
+ if (pSpxConnFile->scf_WRetryCount-- > 0)
+ {
+ fSendProbe = TRUE;
+ }
+ else
+ {
+ fDisconnect = TRUE;
+ }
+
+ break;
+ }
+
+ // SPX2 connection. Watchdog algorithm needs to do lots of goody
+ // stuff. If retry is active, just requeue ourselves.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER))
+ break;
+
+ // There is a race between watchdog and retry if its started. Who
+ // ever changes the state first gets to go do its thing.
+ switch (SPX_SEND_STATE(pSpxConnFile))
+ {
+ case SPX_SEND_IDLE:
+
+ // Enter WD state only if we fired for the second time witout
+ // an ack. This prevents PACKETIZE from blocking due to being
+ // in a non-idle state.
+ CTEAssert(pSpxConnFile->scf_WRetryCount != 0);
+ if ((pSpxConnFile->scf_WRetryCount)-- !=
+ (LONG)PARAM(CONFIG_KEEPALIVE_COUNT))
+ {
+ // We enter the WD state. Build and send a probe.
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_WD);
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ERRORSTATE);
+ }
+
+ fSendProbe = TRUE;
+ break;
+
+ case SPX_SEND_PACKETIZE:
+
+ // Do nothing.
+ break;
+
+ case SPX_SEND_RETRY:
+ case SPX_SEND_RETRYWD:
+ case SPX_SEND_RENEG:
+ case SPX_SEND_RETRY2:
+ case SPX_SEND_RETRY3:
+
+ // Do nothing. Send timer got in first.
+ DBGPRINT(CONNECT, DBG1,
+ ("SpxConnWDogTimer: When retry fired %lx\n",
+ pSpxConnFile));
+
+ break;
+
+ case SPX_SEND_WD:
+
+ // Decrement count. If not zero, send a probe. If half the
+ // count is reached, stop timer and call find route.
+ if (pSpxConnFile->scf_WRetryCount-- > 0)
+ {
+ if (pSpxConnFile->scf_WRetryCount !=
+ (LONG)PARAM(CONFIG_KEEPALIVE_COUNT)/2)
+ {
+ fSendProbe = TRUE;
+ break;
+ }
+
+ if ((pFindRouteReq =
+ (PSPX_FIND_ROUTE_REQUEST)SpxAllocateMemory(
+ sizeof(SPX_FIND_ROUTE_REQUEST))) == NULL)
+ {
+ fDisconnect = TRUE;
+ break;
+ }
+
+ // Remove timer reference/ Add find route request ref
+ fFindRoute = TRUE;
+ TimerShuttingDown = TRUE;
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_FINDROUTE);
+ SpxConnFileLockReference(pSpxConnFile, CFREF_FINDROUTE);
+
+ // Initialize the find route request
+ *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Network) =
+ *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr);
+
+ //
+ // [SA] Bug #15094
+ // We need to also pass in the node number to IPX so that IPX can
+ // compare the node addresses to determine the proper WAN NICid
+ //
+
+ // RtlCopyMemory (pFindRouteReq->fr_FindRouteReq.Node, pSpxConnFile->scf_RemAddr+4, 6);
+
+ *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Node)=
+ *((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr+4));
+
+ *((UNALIGNED USHORT *)(pFindRouteReq->fr_FindRouteReq.Node+4))=
+ *((UNALIGNED USHORT *)(pSpxConnFile->scf_RemAddr+8));
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnWDogTimer: NETWORK %lx\n",
+ *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr)));
+
+ pFindRouteReq->fr_FindRouteReq.Identifier= IDENTIFIER_SPX;
+ pFindRouteReq->fr_Ctx = pSpxConnFile;
+
+ // Make sure we have IPX re-rip.
+ pFindRouteReq->fr_FindRouteReq.Type = IPX_FIND_ROUTE_FORCE_RIP;
+ }
+ else
+ {
+ fDisconnect = TRUE;
+ }
+
+ break;
+
+ default:
+
+ KeBugCheck(0);
+ }
+
+ break;
+
+ case SPX_CONNFILE_CONNECTING:
+
+ if ((SPX_CONNECT_STATE(pSpxConnFile) == SPX_CONNECT_SENTREQ) ||
+ (SPX_CONNECT_STATE(pSpxConnFile) == SPX_CONNECT_NEG))
+ {
+ // Do nothing. Connect timer is active.
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnWDogTimer: CR Timer active %lx\n",
+ pSpxConnFile));
+
+ break;
+ }
+
+ if (!(pSpxConnFile->scf_WRetryCount--))
+ {
+ // Disconnect!
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnWatchdogTimer: Connection %lx.%lx expired\n",
+ pSpxConnFile->scf_LocalConnId, pSpxConnFile));
+
+ fDisconnect = TRUE;
+ }
+
+ break;
+
+ case SPX_CONNFILE_LISTENING:
+
+ if (SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_SETUP)
+ {
+ // Do nothing. Connect timer is active.
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnWDogTimer: CR Timer active %lx\n",
+ pSpxConnFile));
+
+ break;
+ }
+
+ if (!(pSpxConnFile->scf_WRetryCount--))
+ {
+ // Disconnect!
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnWatchdogTimer: Connection %lx.%lx expired\n",
+ pSpxConnFile->scf_LocalConnId, pSpxConnFile));
+
+ fDisconnect = TRUE;
+ }
+
+ break;
+
+ default:
+
+ // Should never happen!
+ KeBugCheck(0);
+ }
+
+ } while (FALSE);
+
+ if (fSendProbe)
+ {
+ CTEAssert(lockHeld);
+ CTEAssert(!fDisconnect);
+
+ DBGPRINT(CONNECT, DBG1,
+ ("spxConnWatchdogTimer: Send Probe from %lx.%lx\n",
+ pSpxConnFile->scf_LocalConnId, pSpxConnFile));
+
+ // Build a probe and send it out to the remote end.
+ SpxPktBuildProbe(
+ pSpxConnFile,
+ &pProbe,
+ (SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY),
+ fSpx2);
+
+ if (pProbe != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pProbe);
+ pSendResd = (PSPX_SEND_RESD)(pProbe->ProtocolReserved);
+ }
+ }
+
+ if (fDisconnect)
+ {
+ CTEAssert(lockHeld);
+ CTEAssert(!fSendProbe);
+
+ // Disconnect!
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnWatchdogTimer: Connection %lx.%lx expired\n",
+ pSpxConnFile->scf_LocalConnId, pSpxConnFile));
+
+ TimerShuttingDown = TRUE;
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+
+ // If spx2, check if we need to do anything special.
+ // AbortiveDisc will reset funky state if needed.
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_LINK_TIMEOUT,
+ SPX_CALL_TDILEVEL,
+ lockHandle,
+ FALSE); // [SA] Bug #15249
+
+ lockHeld = FALSE;
+ }
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ if (fFindRoute)
+ {
+ CTEAssert(!fSendProbe);
+ CTEAssert(!fDisconnect);
+ CTEAssert(TimerShuttingDown);
+
+ // Start off the find route request
+ (*IpxFindRoute)(
+ &pFindRouteReq->fr_FindRouteReq);
+ }
+
+ if (pProbe != NULL)
+ {
+ // Send the packet
+ SPX_SENDPACKET(pSpxConnFile, pProbe, pSendResd);
+ }
+
+ if (TimerShuttingDown)
+ {
+ // Dereference connection for verify done in connect, for timer. This
+ // should complete any pending disconnects if they had come in in the
+ // meantime.
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return((TimerShuttingDown ? TIMER_DONT_REQUEUE : TIMER_REQUEUE_CUR_VALUE));
+}
+
+
+
+ULONG
+spxConnRetryTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)Context;
+ PSPX_SEND_RESD pSendResd;
+ CTELockHandle lockHandleConn;
+ PIPXSPX_HDR pSendHdr;
+ PNDIS_PACKET pPkt;
+ PNDIS_PACKET pProbe = NULL;
+ PSPX_FIND_ROUTE_REQUEST pFindRouteReq;
+ USHORT reenqueueTime = TIMER_REQUEUE_CUR_VALUE;
+ BOOLEAN lockHeld, fResendPkt = FALSE, fDisconnect = FALSE,
+ fFindRoute = FALSE, fBackoffTimer = FALSE;
+ PREQUEST pRequest = NULL;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnRetryTimer: Entered\n"));
+
+ // Get lock
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ lockHeld = TRUE;
+
+ do
+ {
+ // If timer is not up, no send pkts, just return.
+ if (TimerShuttingDown ||
+ (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER)) ||
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT) ||
+ ((pSendResd = pSpxConnFile->scf_SendSeqListHead) == NULL))
+ {
+#if DBG
+ if ((pSendResd = pSpxConnFile->scf_SendSeqListHead) == NULL)
+ {
+ if ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_IDLE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_PACKETIZE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_WD))
+ {
+ CTEAssert(FALSE);
+ }
+ }
+#endif
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
+ TimerShuttingDown = TRUE;
+ break;
+ }
+
+ // In all other cases, reenqueue with potentially modified reenqueue
+ // time.
+ reenqueueTime = pSpxConnFile->scf_BaseT1;
+ DBGPRINT(SEND, INFO,
+ ("spxConnRetryTimer: BaseT1 %lx on %lx\n",
+ pSpxConnFile->scf_BaseT1, pSpxConnFile));
+
+ // If an ack for a packet was processed while we were out, reset
+ // retry count and return. Or if we are packetizing, return.
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_PACKETIZE)
+ {
+ break;
+ }
+ else if ((SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE) &&
+ (pSpxConnFile->scf_RetrySeqNum != pSendResd->sr_SeqNum))
+ {
+ pSpxConnFile->scf_RetrySeqNum = pSendResd->sr_SeqNum;
+ break;
+ }
+
+ // If packet is still with IPX, requeue for next time.
+ if (pSendResd->sr_State & SPX_SENDPKT_IPXOWNS)
+ {
+ break;
+ }
+
+ CTEAssert(pSendResd != NULL);
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ pSendHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ switch (SPX_SEND_STATE(pSpxConnFile))
+ {
+ case SPX_SEND_IDLE:
+
+ // Set ack bit in packet. pSendResd initialized at beginning.
+ pSendHdr->hdr_ConnCtrl |= SPX_CC_ACK;
+
+ // Do we backoff the timer?
+ fBackoffTimer =
+ (BOOLEAN)((pSendResd->sr_State & SPX_SENDPKT_REXMIT) != 0);
+
+ // We are going to resend this packet
+ pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
+ SPX_SENDPKT_ACKREQ |
+ SPX_SENDPKT_REXMIT);
+
+ ++SpxDevice->dev_Stat.ResponseTimerExpirations;
+
+ CTEAssert((ULONG)pSpxConnFile->scf_RRetryCount <=
+ PARAM(CONFIG_REXMIT_COUNT));
+
+ DBGPRINT(SEND, DBG1,
+ ("spxConnRetryTimer: Retry Count %lx on %lx\n",
+ pSpxConnFile->scf_RRetryCount, pSpxConnFile));
+
+ fResendPkt = TRUE;
+ if (pSpxConnFile->scf_RRetryCount-- != 0)
+ {
+ // We dont treat the IDISC packet as a data packet, so none
+ // of the fancy spx2 retry stuff if we are retrying the idisc.
+ if (SPX2_CONN(pSpxConnFile) &&
+ (SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_SENT_IDISC))
+ {
+ // We enter the RETRY state. Reference conn for this
+ // "funky" state.
+ CTEAssert(SPX2_CONN(pSpxConnFile));
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY);
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ERRORSTATE);
+ }
+ }
+ else
+ {
+ DBGPRINT(SEND, ERR,
+ ("spxConnRetryTimer: Retry Count over on %lx\n",
+ pSpxConnFile));
+
+ fDisconnect = TRUE;
+ fResendPkt = FALSE;
+ pSendResd->sr_State &= ~SPX_SENDPKT_IPXOWNS;
+ }
+
+ break;
+
+ case SPX_SEND_RETRY:
+
+ // When we have reached retry_count/2 limit, start locate route. Do
+ // not queue ourselves. Handle restarting timer in find route
+ // completion. If timer starts successfully in find route comp, then
+ // it will change our state to RETRYWD.
+
+ // Decrement count. If half the count is reached, stop timer and call
+ // find route.
+ if (pSpxConnFile->scf_RRetryCount-- !=
+ (LONG)PARAM(CONFIG_REXMIT_COUNT)/2)
+ {
+ // We are going to resend this packet
+ pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
+ SPX_SENDPKT_ACKREQ |
+ SPX_SENDPKT_REXMIT);
+
+ fResendPkt = TRUE;
+ fBackoffTimer = TRUE;
+ break;
+ }
+
+ if ((pFindRouteReq =
+ (PSPX_FIND_ROUTE_REQUEST)SpxAllocateMemory(
+ sizeof(SPX_FIND_ROUTE_REQUEST))) == NULL)
+ {
+ DBGPRINT(SEND, ERR,
+ ("spxConnRetryTimer: Alloc Mem %lx\n",
+ pSpxConnFile));
+
+ fDisconnect = TRUE;
+ break;
+ }
+
+ // Remove timer reference/ Add find route request ref
+ fFindRoute = TRUE;
+ TimerShuttingDown = TRUE;
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_FINDROUTE);
+ SpxConnFileLockReference(pSpxConnFile, CFREF_FINDROUTE);
+
+ // Initialize the find route request
+ *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Network)=
+ *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr);
+
+ //
+ // [SA] Bug #15094
+ // We need to also pass in the node number to IPX so that IPX can
+ // compare the node addresses to determine the proper WAN NICid
+ //
+
+ // RtlCopyMemory (pFindRouteReq->fr_FindRouteReq.Node, pSpxConnFile->scf_RemAddr+4, 6) ;
+
+ *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Node)=
+ *((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr+4));
+
+ *((UNALIGNED USHORT *)(pFindRouteReq->fr_FindRouteReq.Node+4)) =
+ *((UNALIGNED USHORT *)(pSpxConnFile->scf_RemAddr+8));
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnRetryTimer: NETWORK %lx\n",
+ *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr)));
+
+ pFindRouteReq->fr_FindRouteReq.Identifier= IDENTIFIER_SPX;
+ pFindRouteReq->fr_Ctx = pSpxConnFile;
+
+ // Make sure we have IPX re-rip.
+ pFindRouteReq->fr_FindRouteReq.Type = IPX_FIND_ROUTE_FORCE_RIP;
+ break;
+
+ case SPX_SEND_RETRYWD:
+
+ // Retry a watchdog packet WCount times (initialize to RETRY_COUNT).
+ // If process ack receives an ack (i.e. actual ack packet) while in
+ // this state, it will transition the state to RENEG.
+ //
+ // If the pending data gets acked while in this state, we go back
+ // to idle.
+ DBGPRINT(CONNECT, DBG1,
+ ("spxConnRetryTimer: Send Probe from %lx.%lx\n",
+ pSpxConnFile->scf_LocalConnId, pSpxConnFile));
+
+ // Use watchdog count here.
+ if (pSpxConnFile->scf_WRetryCount-- > 0)
+ {
+ // Build a probe and send it out to the remote end.
+ SpxPktBuildProbe(
+ pSpxConnFile,
+ &pProbe,
+ (SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY),
+ TRUE);
+
+ if (pProbe != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pProbe);
+ pSendResd = (PSPX_SEND_RESD)(pProbe->ProtocolReserved);
+ break;
+ }
+ }
+
+ // Just set state to retry data packet retry_count/2 times.
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY2);
+ break;
+
+ case SPX_SEND_RENEG:
+
+ // Renegotiate size. If we give up, goto RETRY3.
+ // For this both sides must have negotiated size to begin with.
+ // If they did not, we go on to retrying the data packet.
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG))
+ {
+ DBGPRINT(SEND, ERR,
+ ("spxConnRetryTimer: NO NEG FLAG SET: %lx - %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_Flags));
+
+ // Reset count to be
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY3);
+ break;
+ }
+
+ // Send reneg packet, if we get the rr ack, then we resend data
+ // on queue. Note that each time we goto a new negotiate size,
+ // we rebuild the data packets.
+ if (pSpxConnFile->scf_RRetryCount-- == 0)
+ {
+ // Reset count.
+ pSpxConnFile->scf_RRetryCount = SPX_DEF_RENEG_RETRYCOUNT;
+ if ((ULONG)pSpxConnFile->scf_MaxPktSize <=
+ (SpxMaxPktSize[0] + MIN_IPXSPX2_HDRSIZE))
+ {
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnRetryTimer: %lx MIN RENEG SIZE\n",
+ pSpxConnFile));
+ }
+
+ // Are we at the lowest possible reneg pkt size? If not, try
+ // next lower. When we do this, we free all pending send
+ // packets and reset the packetize queue to the first packet.
+ // Process ack will just do packetize and will not do anything
+ // more other than resetting state to proper value.
+ DBGPRINT(SEND, DBG3,
+ ("spxConnRetryTimer: RENEG: %lx - CURRENT %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_MaxPktSize));
+
+ if (!spxConnCheckNegSize(&pSpxConnFile->scf_MaxPktSize))
+ {
+ // We tried lowest size and failed to receive ack. Just
+ // retry data packet, and disc if no ack.
+ DBGPRINT(SEND, DBG3,
+ ("spxConnRetryTimer: RENEG(min), RETRY3: %lx - %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_MaxPktSize));
+
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY3);
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT);
+ break;
+ }
+
+ DBGPRINT(SEND, DBG3,
+ ("spxConnRetryTimer: RENEG(!min): %lx - ATTEMPT %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_MaxPktSize));
+ }
+
+ DBGPRINT(SEND, DBG3,
+ ("spxConnRetryTimer: %lx.%lx.%lx RENEG SEQNUM %lx ACKNUM %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_RRetryCount,
+ pSpxConnFile->scf_MaxPktSize,
+ (USHORT)(pSpxConnFile->scf_SendSeqListTail->sr_SeqNum + 1),
+ pSpxConnFile->scf_SentAllocNum));
+
+ // Use first unused data packet sequence number.
+ SpxPktBuildRr(
+ pSpxConnFile,
+ &pPkt,
+ (USHORT)(pSpxConnFile->scf_SendSeqListTail->sr_SeqNum + 1),
+ (SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY));
+
+ if (pPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ fResendPkt = TRUE;
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT);
+ }
+
+ break;
+
+ case SPX_SEND_RETRY2:
+
+ // Retry the data packet for remaining amount of RRetryCount. If not
+ // acked goto cleanup. If ack received while in this state, goto idle.
+
+ if (pSpxConnFile->scf_RRetryCount-- > 0)
+ {
+ // We are going to resend this packet
+ pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
+ SPX_SENDPKT_ACKREQ |
+ SPX_SENDPKT_REXMIT);
+
+ DBGPRINT(SEND, DBG3,
+ ("spxConnRetryTimer: 2nd try Resend on %lx\n",
+ pSpxConnFile));
+
+ fResendPkt = TRUE;
+ fBackoffTimer = TRUE;
+ }
+ else
+ {
+ DBGPRINT(SEND, ERR,
+ ("spxConnRetryTimer: Retry Count over on %lx\n",
+ pSpxConnFile));
+
+ fDisconnect = TRUE;
+ }
+
+ break;
+
+ case SPX_SEND_RETRY3:
+
+ // Send data packet for RETRY_COUNT times initialized in RRetryCount
+ // before state changed to this state. If ok, process ack moves us
+ // back to PKT/IDLE. If not, we disconnect.
+ // We are going to resend this packet
+
+ if (pSpxConnFile->scf_RRetryCount-- > 0)
+ {
+ DBGPRINT(SEND, DBG3,
+ ("spxConnRetryTimer: 3rd try Resend on %lx\n",
+ pSpxConnFile));
+
+ // We are going to resend this packet
+ pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
+ SPX_SENDPKT_ACKREQ |
+ SPX_SENDPKT_REXMIT);
+
+ fResendPkt = TRUE;
+ fBackoffTimer = TRUE;
+ }
+ else
+ {
+ DBGPRINT(SEND, ERR,
+ ("spxConnRetryTimer: Retry Count over on %lx\n",
+ pSpxConnFile));
+
+ fDisconnect = TRUE;
+ }
+
+ break;
+
+ case SPX_SEND_WD:
+
+ // Do nothing. Watchdog timer has fired, just requeue.
+ break;
+
+ default:
+
+ KeBugCheck(0);
+ }
+
+ if (fBackoffTimer)
+ {
+ // Increase retransmit timeout by 50% upto maximum indicated by
+ // initial retransmission value.
+
+ reenqueueTime += reenqueueTime/2;
+ if (reenqueueTime > MAX_RETRY_DELAY)
+ reenqueueTime = MAX_RETRY_DELAY;
+
+ pSpxConnFile->scf_BaseT1 =
+ pSpxConnFile->scf_AveT1 = reenqueueTime;
+ pSpxConnFile->scf_DevT1 = 0;
+
+ DBGPRINT(SEND, DBG,
+ ("spxConnRetryTimer: Backed retry on %lx.%lx %lx\n",
+ pSpxConnFile, pSendResd->sr_SeqNum, reenqueueTime));
+ }
+
+ if (fDisconnect)
+ {
+ CTEAssert(lockHeld);
+
+ // Do not requeue this timer.
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
+ TimerShuttingDown = TRUE;
+
+ // Disconnect the connection.
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_LINK_TIMEOUT,
+ SPX_CALL_TDILEVEL,
+ lockHandleConn,
+ FALSE); // [SA] Bug #15249
+
+ lockHeld = FALSE;
+ }
+
+ } while (FALSE);
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ }
+
+ if (fResendPkt)
+ {
+ DBGPRINT(SEND, DBG,
+ ("spxConnRetryTimer: Resend pkt on %lx.%lx\n",
+ pSpxConnFile, pSendResd->sr_SeqNum));
+
+ ++SpxDevice->dev_Stat.DataFramesResent;
+ ExInterlockedAddLargeStatistic(
+ &SpxDevice->dev_Stat.DataFrameBytesResent,
+ pSendResd->sr_Len - (SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE));
+ SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
+ }
+ else if (fFindRoute)
+ {
+ CTEAssert(!fResendPkt);
+ CTEAssert(!fDisconnect);
+ CTEAssert(TimerShuttingDown);
+
+ DBGPRINT(SEND, DBG3,
+ ("spxConnRetryTimer: Find route on %lx\n",
+ pSpxConnFile));
+
+ // Start off the find route request
+ (*IpxFindRoute)(
+ &pFindRouteReq->fr_FindRouteReq);
+ }
+ else if (pProbe != NULL)
+ {
+ // Send the packet
+ SPX_SENDPACKET(pSpxConnFile, pProbe, pSendResd);
+ }
+
+ if (TimerShuttingDown)
+ {
+ // Dereference connection for verify done in connect, for timer. This
+ // should complete any pending disconnects if they had come in in the
+ // meantime.
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ reenqueueTime = TIMER_DONT_REQUEUE;
+ }
+
+ DBGPRINT(SEND, INFO,
+ ("spxConnRetryTimer: Reenqueue time : %lx on %lx\n",
+ reenqueueTime, pSpxConnFile));
+
+ return(reenqueueTime);
+}
+
+
+
+
+ULONG
+spxConnAckTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)Context;
+ CTELockHandle lockHandleConn;
+
+ DBGPRINT(SEND, INFO,
+ ("spxConnAckTimer: Entered\n"));
+
+ // Get lock
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ if (!TimerShuttingDown &&
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ACKQ))
+ {
+ // We didnt have any back traffic, until we do a send from this
+ // end, send acks immediately. Dont try to piggyback.
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_ACKQ);
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_IMMED_ACK);
+
+ ++SpxDevice->dev_Stat.PiggybackAckTimeouts;
+
+ DBGPRINT(SEND, DBG,
+ ("spxConnAckTimer: Send ack on %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RecvSeqNum));
+
+ SpxConnSendAck(pSpxConnFile, lockHandleConn);
+ }
+ else
+ {
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_ACKQ);
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ }
+
+ // Dereference connection for verify done in connect, for timer. This
+ // should complete any pending disconnects if they had come in in the
+ // meantime.
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ return(TIMER_DONT_REQUEUE);
+}
+
+
+
+//
+// DISCONNECT ROUTINES
+//
+
+
+VOID
+spxConnAbortiveDisc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn,
+ IN BOOLEAN IDiscFlag // [SA] Bug #15249
+ )
+/*++
+
+Routine Description:
+
+ This is called when:
+ We time out or have insufficient resources -
+ STATUS_LINK_TIMEOUT/STATUS_INSUFFICIENT_RESOURCES
+ - We abort everything. Could be from watchdog or retry. Stop both.
+
+ We receive a informed disconnect packet -
+ STATUS_REMOTE_DISCONNECT
+ - We abort everything. Ack must be sent by caller as an orphan pkt.
+
+ We receive a informed disconnect ack pkt
+ STATUS_SUCCESS
+ - We abort everything
+ - Abort is done with status success (this completes our disc req in
+ the send queue)
+
+ NOTE: CALLED UNDER THE CONNECTION LOCK.
+
+Arguments:
+[SA] Bug #15249: Added IDiscFlag to indicate if this is an Informed Disconnect. If so, indicate
+ TDI_DISCONNECT_RELEASE to AFD so it allows a receive of buffered pkts. This flag is TRUE
+ only if this routine is called from SpxConnProcessIDisc for SPX connections.
+
+Return Value:
+
+
+--*/
+{
+ int numDerefs = 0;
+ PVOID pDiscHandlerCtx;
+ PTDI_IND_DISCONNECT pDiscHandler = NULL;
+ BOOLEAN lockHeld = TRUE;
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnAbortiveDisc: %lx - On %lx when %lx\n",
+ Status, pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ switch (Status) {
+ case STATUS_LINK_TIMEOUT: ++SpxDevice->dev_Stat.LinkFailures; break;
+ case STATUS_INSUFFICIENT_RESOURCES: ++SpxDevice->dev_Stat.LocalResourceFailures; break;
+ case STATUS_REMOTE_DISCONNECT: ++SpxDevice->dev_Stat.RemoteDisconnects; break;
+ case STATUS_SUCCESS:
+ case STATUS_LOCAL_DISCONNECT: ++SpxDevice->dev_Stat.LocalDisconnects; break;
+ }
+
+ switch (SPX_MAIN_STATE(pSpxConnFile))
+ {
+ case SPX_CONNFILE_ACTIVE:
+
+ // For transition from active to disconn.
+ numDerefs++;
+
+ case SPX_CONNFILE_DISCONN:
+
+ // If we are in any state other than idle/packetize,
+ // remove the reference for the funky state, and reset the send state to be
+ // idle.
+ if ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_IDLE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_PACKETIZE))
+ {
+#if DBG
+ if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnAbortiveDisc: When DISC STATE %lx.%lx\n",
+ pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
+ }
+#endif
+
+ DBGPRINT(CONNECT, DBG1,
+ ("spxConnAbortiveDisc: When SEND ERROR STATE %lx.%lx\n",
+ pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ numDerefs++;
+ }
+
+ // This can be called when a idisc is received, or if a timer
+ // disconnect is happening, or if we sent a idisc/ordrel, but the retries
+ // timed out and we are aborting the connection.
+ // So if we are already aborting, never mind.
+
+ //
+ // [SA] Bug #15249
+ // SPX_DISC_INACTIVATED indicates a DISC_ABORT'ing connection that has been
+ // inactivated (connfile removed from active conn. list)
+ //
+
+ if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ ((SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT) ||
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED)))
+ {
+ break;
+ }
+
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_DISCONN);
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_ABORT);
+
+ // Stop all timers.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_TTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER);
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_RTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_WTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ }
+#if 0
+ //
+ // [SA] We need to call AFD after aborting sends since this connection
+ // becomes a candidate for re-use as soon as the disconnect handler is
+ // called.
+ // We call the disconnect handler when the refcount falls to 0 and the
+ // connection transitions to the inactive list.
+ //
+
+ // NOTE! We indicate disconnect to afd *before* aborting sends to avoid
+ // afd from calling us again with a disconnect.
+ // Get disconnect handler if we have one. And we have not indicated
+ // abortive disconnect on this connection to afd.
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC))
+ {
+ // Yeah, we set the flag regardless of whether a handler is
+ // present.
+ pDiscHandler = pSpxConnFile->scf_AddrFile->saf_DiscHandler;
+ pDiscHandlerCtx = pSpxConnFile->scf_AddrFile->saf_DiscHandlerCtx;
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
+ }
+#endif
+ //
+ // [SA] Save the IDiscFlag in the Connection.
+ //
+ (IDiscFlag) ?
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_IDISC) :
+ SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_IDISC);
+
+ // Indicate disconnect to afd.
+ if (pDiscHandler != NULL)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnAbortiveDisc: Indicating to afd On %lx when %lx\n",
+ pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ // First complete all requests waiting for receive completion on
+ // this conn before indicating disconnect.
+ spxConnCompletePended(pSpxConnFile);
+
+
+ //
+ // [SA] bug #15249
+ // If not Informed disconnect, indicate DISCONNECT_ABORT to AFD
+ //
+
+ if (!IDiscFlag)
+ {
+ (*pDiscHandler)(
+ pDiscHandlerCtx,
+ pSpxConnFile->scf_ConnCtx,
+ 0, // Disc data
+ NULL,
+ 0, // Disc info
+ NULL,
+ TDI_DISCONNECT_ABORT);
+ }
+ else
+ {
+ //
+ // [SA] bug #15249
+ // Indicate DISCONNECT_RELEASE to AFD so it allows receive of packets
+ // it has buffered before the remote disconnect took place.
+ //
+
+ (*pDiscHandler)(
+ pDiscHandlerCtx,
+ pSpxConnFile->scf_ConnCtx,
+ 0, // Disc data
+ NULL,
+ 0, // Disc info
+ NULL,
+ TDI_DISCONNECT_RELEASE);
+ }
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ }
+
+ // Go through and kill all pending requests.
+ spxConnAbortRecvs(
+ pSpxConnFile,
+ Status,
+ CallLevel,
+ LockHandleConn);
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+
+ spxConnAbortSends(
+ pSpxConnFile,
+ Status,
+ CallLevel,
+ LockHandleConn);
+
+ lockHeld = FALSE;
+ break;
+
+ case SPX_CONNFILE_CONNECTING:
+ case SPX_CONNFILE_LISTENING:
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnAbortiveDisc: CONN/LIST Disc On %lx when %lx\n",
+ pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ lockHeld = FALSE;
+
+ {
+ CTELockHandle lockHandleAddr, lockHandleDev;
+
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+
+ // Ensure we are still in connecting/listening, else call abortive
+ // again.
+ switch (SPX_MAIN_STATE(pSpxConnFile))
+ {
+ case SPX_CONNFILE_CONNECTING:
+ case SPX_CONNFILE_LISTENING:
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnAbortiveDisc: CONN/LIST Disc2 On %lx when %lx\n",
+ pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ spxConnAbortConnect(
+ pSpxConnFile,
+ Status,
+ lockHandleDev,
+ lockHandleAddr,
+ LockHandleConn);
+
+ break;
+
+ case SPX_CONNFILE_ACTIVE:
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ CTEFreeLock(
+ pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(
+ &SpxDevice->dev_Lock, lockHandleDev);
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnAbortiveDisc: CHG ACT Disc2 On %lx when %lx\n",
+ pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ Status,
+ CallLevel,
+ LockHandleConn,
+ FALSE); // [SA] Bug #15249
+
+ break;
+
+ default:
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ CTEFreeLock(
+ pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(
+ &SpxDevice->dev_Lock, lockHandleDev);
+
+ break;
+ }
+ }
+
+ default:
+
+ // Already disconnected.
+ break;
+ }
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
diff --git a/private/ntos/tdi/isnp/spx/spxcpkt.c b/private/ntos/tdi/isnp/spx/spxcpkt.c
new file mode 100644
index 000000000..deb185201
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/spxcpkt.c
@@ -0,0 +1,4131 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxcpkt.c
+
+Abstract:
+
+ This module contains code which implements the CONNECTION object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport connection objects.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 14-July-1995
+ Bug fixes - tagged [SA]
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXCPKT
+
+VOID
+spxConnHandleConnReq(
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ BOOLEAN fNeg, fSpx2;
+ TA_IPX_ADDRESS srcIpxAddr;
+ PTDI_IND_CONNECT connHandler;
+ USHORT srcConnId, destConnId, destSkt,
+ pktLen, seqNum, ackNum, allocNum;
+ PVOID connHandlerCtx;
+ PREQUEST pListenReq;
+ PSPX_SEND_RESD pSendResd;
+ NTSTATUS status;
+ CTELockHandle lockHandle, lockHandleDev, lockHandleConn;
+ CONNECTION_CONTEXT connCtx;
+ PIRP acceptIrp;
+ PSPX_ADDR pSpxAddr;
+ PSPX_ADDR_FILE pSpxAddrFile, pSpxRefFile;
+ PSPX_CONN_FILE pSpxConnFile;
+ PNDIS_PACKET pCrAckPkt;
+ BOOLEAN connectAccepted = FALSE, delayAccept = FALSE,
+ addrLock = FALSE, tdiListen = FALSE;
+
+ // Convert hdr to host format as needed.
+ GETSHORT2SHORT(&pktLen, &pIpxSpxHdr->hdr_PktLen);
+ GETSHORT2SHORT(&destConnId, &pIpxSpxHdr->hdr_DestConnId);
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+ GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
+
+ // We keep and use the remote id in the net format. This maintains the
+ // 0x0 and 0xFFFF to be as in the host format.
+ srcConnId = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_SrcConnId;
+
+ // Verify Connect Request
+ if (((pIpxSpxHdr->hdr_ConnCtrl & (SPX_CC_ACK | SPX_CC_SYS)) !=
+ (SPX_CC_ACK | SPX_CC_SYS)) ||
+ (pIpxSpxHdr->hdr_DataType != 0) ||
+ (seqNum != 0) ||
+ (ackNum != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (destConnId != 0xFFFF))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnSysPacket: VerifyCR Failed %lx.%lx\n",
+ srcConnId, destConnId));
+ return;
+ }
+
+ // Get the destination socket from the header
+ destSkt = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_DestSkt;
+
+ SpxBuildTdiAddress(
+ &srcIpxAddr,
+ sizeof(srcIpxAddr),
+ (PBYTE)pIpxSpxHdr->hdr_SrcNet,
+ pIpxSpxHdr->hdr_SrcNode,
+ pIpxSpxHdr->hdr_SrcSkt);
+
+ // Ok, get the address object this is destined for.
+ CTEGetLock (&SpxDevice->dev_Lock, &lockHandleDev);
+ pSpxAddr = SpxAddrLookup(SpxDevice, destSkt);
+ CTEFreeLock (&SpxDevice->dev_Lock, lockHandleDev);
+ if (pSpxAddr == NULL)
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxReceive: No addr for %lx\n", destSkt));
+
+ return;
+ }
+
+ fSpx2 = ((PARAM(CONFIG_DISABLE_SPX2) == 0) &&
+ (BOOLEAN)(pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2));
+ fNeg = (BOOLEAN)(fSpx2 && (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_NEG));
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleConnReq: Received connect req! %d.%d\n",
+ fSpx2, fNeg));
+
+ CTEGetLock (&pSpxAddr->sa_Lock, &lockHandle);
+ addrLock = TRUE;
+
+ // We use a bit setting in the flag to prevent reentering
+ // per address file.
+ //
+ // We first search the list of non-inactive connections on the address
+ // this packet came in on to see if it is a duplicate. If it is, we just
+ // resend ack. Note we dont need to scan the global connection list.
+ status = SpxAddrConnByRemoteIdAddrLock(
+ pSpxAddr, srcConnId, pIpxSpxHdr->hdr_SrcNet, &pSpxConnFile);
+
+ if (NT_SUCCESS(status))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleConnReq: Received duplicate connect req! %lx\n",
+ pSpxConnFile));
+
+ if (SPX_CONN_ACTIVE(pSpxConnFile) ||
+ (SPX_CONN_LISTENING(pSpxConnFile) &&
+ ((SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_SENTACK) ||
+ (SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_SETUP))))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleConnReq: Sending Duplicate CR - ACK! %lx\n",
+ pSpxConnFile));
+
+ // Build and send an ack
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ SpxPktBuildCrAck(
+ pSpxConnFile,
+ pSpxAddr,
+ &pCrAckPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG),
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2));
+
+ if (pCrAckPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pCrAckPkt);
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock (&pSpxAddr->sa_Lock, lockHandle);
+ addrLock = FALSE;
+
+ // Send the CR Ack packet!
+ if (pCrAckPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pCrAckPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pCrAckPkt, pSendResd);
+ }
+ }
+
+ if (addrLock)
+ {
+ CTEFreeLock (&pSpxAddr->sa_Lock, lockHandle);
+ // We should return in this if, else addrLock should be set to
+ // FALSE.
+ }
+
+ // Deref the connection
+ SpxConnFileDereference(pSpxConnFile, CFREF_ADDR);
+
+ // Deref the address
+ SpxAddrDereference (pSpxAddr, AREF_LOOKUP);
+ return;
+ }
+
+ do
+ {
+ // New connection request:
+ // Assume we will be able to accept it and allocate a packet for the ack.
+ // Walk list of listening connections if any.
+
+ pSpxRefFile = NULL;
+ if ((pSpxConnFile = pSpxAddr->sa_ListenConnList) != NULL)
+ {
+ PTDI_REQUEST_KERNEL_LISTEN pParam;
+
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnIndicate: Listen available!\n"));
+
+ // dequeue connection
+ pSpxAddr->sa_ListenConnList = pSpxConnFile->scf_Next;
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ CTEAssert(!IsListEmpty(&pSpxConnFile->scf_ReqLinkage));
+ pListenReq = LIST_ENTRY_TO_REQUEST(pSpxConnFile->scf_ReqLinkage.Flink);
+ pParam = (PTDI_REQUEST_KERNEL_LISTEN)REQUEST_PARAMETERS(pListenReq);
+
+ // if autoaccept, acceptIrp = listenIrp, get connection id and
+ // process as we do for an indication. As the connection has a
+ // listen posted on it, it must have a reference for it.
+ //
+ // if !autoaccept, we need to complete the listen irp.
+ delayAccept = (BOOLEAN)((pParam->RequestFlags & TDI_QUERY_ACCEPT) != 0);
+ if (delayAccept)
+ {
+ // Remove the listen irp and prepare for completion.
+ // NOTE!! Here we do not remove the listen reference. This will
+ // be removed if disconnect happens, or if accept
+ // happens, it is transferred to being ref for connection
+ // being active.
+ RemoveEntryList(REQUEST_LINKAGE(pListenReq));
+ REQUEST_STATUS(pListenReq) = STATUS_SUCCESS;
+ REQUEST_INFORMATION(pListenReq) = 0;
+ }
+
+ // Are we ok with spx2?
+ if (!(SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2)) ||
+ !fSpx2)
+ {
+ // We better use spx only.
+ SPX_CONN_RESETFLAG(pSpxConnFile,
+ (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
+ fSpx2 = fNeg = FALSE;
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+
+ connectAccepted = TRUE;
+ tdiListen = TRUE;
+ }
+ else
+ {
+ // No listens available. Check for connect handlers.
+ // Walk list of address files indicating to each until accepted.
+ for (pSpxAddrFile = pSpxAddr->sa_AddrFileList;
+ pSpxAddrFile != NULL;
+ pSpxAddrFile = pSpxAddrFile->saf_Next)
+ {
+ if ((pSpxAddrFile->saf_Flags & (SPX_ADDRFILE_CLOSING |
+ SPX_ADDRFILE_CONNIND)) ||
+ ((connHandler = pSpxAddrFile->saf_ConnHandler) == NULL))
+ {
+ continue;
+ }
+
+ // Connect indication in progress, drop all subsequent.
+ pSpxAddrFile->saf_Flags |= SPX_ADDRFILE_CONNIND;
+
+ connHandlerCtx = pSpxAddrFile->saf_ConnHandlerCtx;
+ SpxAddrFileLockReference(pSpxAddrFile, AFREF_INDICATION);
+ CTEFreeLock(&pSpxAddr->sa_Lock, lockHandle);
+ addrLock = FALSE;
+
+ if (pSpxRefFile)
+ {
+ SpxAddrFileDereference(pSpxRefFile, AFREF_INDICATION);
+ pSpxRefFile = NULL;
+ }
+
+ // Make the indication. We are always returned an accept irp on
+ // indication. Else we fail to accept the connection.
+ status = (*connHandler)(
+ connHandlerCtx,
+ sizeof(srcIpxAddr),
+ (PVOID)&srcIpxAddr,
+ 0, // User data length
+ NULL, // User data
+ 0, // Option length
+ NULL, // Options
+ &connCtx,
+ &acceptIrp);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConn: indicate status %lx.%lx\n",
+ status, acceptIrp));
+
+ CTEGetLock (&pSpxAddr->sa_Lock, &lockHandle);
+ addrLock = TRUE;
+ pSpxAddrFile->saf_Flags &= ~SPX_ADDRFILE_CONNIND;
+
+ if (status == STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ CTEAssert(acceptIrp != NULL);
+
+ // Find the connection and accept the connection using that
+ // connection object.
+ SpxConnFileReferenceByCtxLock(
+ pSpxAddrFile,
+ connCtx,
+ &pSpxConnFile,
+ &status);
+
+ if (!NT_SUCCESS(status))
+ {
+ // The connection object is closing, or is not found
+ // in our list. The accept irp must have had the same
+ // connection object. AFD isnt behaving well.
+ KeBugCheck(0);
+ }
+
+ // Only for debugging.
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_BYCTX,
+ CFREF_VERIFY);
+
+ pListenReq = SpxAllocateRequest(
+ SpxDevice,
+ acceptIrp);
+
+ IF_NOT_ALLOCATED(pListenReq)
+ {
+ acceptIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT);
+
+ // Setup for dereference
+ pSpxRefFile = pSpxAddrFile;
+ break;
+ }
+
+ InsertTailList(
+ &pSpxConnFile->scf_ReqLinkage,
+ REQUEST_LINKAGE(pListenReq));
+
+ // Setup for dereference
+ pSpxRefFile = pSpxAddrFile;
+ connectAccepted = TRUE;
+
+ // See if this connection is to be a spx2 connection.
+ SPX_CONN_RESETFLAG(pSpxConnFile,
+ (SPX_CONNFILE_SPX2 |
+ SPX_CONNFILE_NEG |
+ SPX_CONNFILE_STREAM));
+
+ if ((pSpxAddrFile->saf_Flags & SPX_ADDRFILE_SPX2) && fSpx2)
+ {
+ SPX_CONN_SETFLAG(
+ pSpxConnFile, (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
+ }
+ else
+ {
+ fSpx2 = fNeg = FALSE;
+ }
+
+ if (pSpxAddrFile->saf_Flags & SPX_ADDRFILE_STREAM)
+ {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_STREAM);
+ }
+
+ if (pSpxAddrFile->saf_Flags & SPX_ADDRFILE_NOACKWAIT)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleConnReq: NOACKWAIT requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_NOACKWAIT);
+ }
+
+ if (pSpxAddrFile->saf_Flags & SPX_ADDRFILE_IPXHDR)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleConnReq: IPXHDR requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR);
+ }
+
+ break;
+ }
+ else
+ {
+ // We are not going to accept the connection on this address.
+ // Try next one.
+ pSpxRefFile = pSpxAddrFile;
+ continue;
+ }
+ }
+ }
+
+ } while (FALSE);
+
+ if (addrLock)
+ {
+ CTEFreeLock (&pSpxAddr->sa_Lock, lockHandle);
+ // No need for flag from this point on.
+ // addrLock = FALSE;
+ }
+
+ if (pSpxRefFile)
+ {
+ SpxAddrFileDereference(pSpxRefFile, AFREF_INDICATION);
+ pSpxRefFile = NULL;
+ }
+
+ if (connectAccepted)
+ {
+ CTEGetLock (&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock (&pSpxAddr->sa_Lock, &lockHandle);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ if (((USHORT)PARAM(CONFIG_WINDOW_SIZE) == 0) ||
+ ((USHORT)PARAM(CONFIG_WINDOW_SIZE) > MAX_WINDOW_SIZE))
+ {
+ PARAM(CONFIG_WINDOW_SIZE) = DEFAULT_WINDOW_SIZE;
+ }
+
+ pSpxConnFile->scf_LocalConnId = spxConnGetId();
+ pSpxConnFile->scf_RemConnId = srcConnId;
+ pSpxConnFile->scf_SendSeqNum = 0;
+ pSpxConnFile->scf_RecvSeqNum = 0;
+ pSpxConnFile->scf_RecdAckNum = 0;
+ pSpxConnFile->scf_RetrySeqNum = 0;
+ pSpxConnFile->scf_SentAllocNum = (USHORT)(PARAM(CONFIG_WINDOW_SIZE) - 1);
+ pSpxConnFile->scf_RecdAllocNum = allocNum;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnHandleConnReq: %lx CONN L.R %lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_LocalConnId,
+ pSpxConnFile->scf_RemConnId));
+
+ pSpxConnFile->scf_LocalTarget = *pRemoteAddr;
+ pSpxConnFile->scf_AckLocalTarget= *pRemoteAddr;
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAddr);
+
+ // Set max packet size in connection
+ SPX_MAX_PKT_SIZE(pSpxConnFile, (fSpx2 && fNeg), fSpx2, pIpxSpxHdr->hdr_SrcNet);
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleConnReq: Accept connect req on %lx.%lx..%lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_LocalConnId,
+ pSpxConnFile->scf_RecdAllocNum, pSpxConnFile->scf_MaxPktSize));
+
+ // Aborts must now deal with the lists. Need this as Accept has to
+ // deal with it.
+ // Put in non-inactive list. All processing now is equivalent to
+ // that when a listen is completed on a connection.
+ if ((!tdiListen) && (!NT_SUCCESS(spxConnRemoveFromList(
+ &pSpxAddr->sa_InactiveConnList,
+ pSpxConnFile))))
+ {
+ // Should never happen!
+ KeBugCheck(0);
+ }
+
+ SPX_INSERT_ADDR_ACTIVE(pSpxAddr, pSpxConnFile);
+
+ // Insert in the global connection tree on device.
+ spxConnInsertIntoGlobalActiveList(
+ pSpxConnFile);
+
+ SPX_CONN_SETFLAG(pSpxConnFile,
+ ((fNeg ? SPX_CONNFILE_NEG : 0) |
+ (fSpx2 ? SPX_CONNFILE_SPX2: 0)));
+
+ //
+ // If this was a post-inactivated file, clear the disconnect flags
+ //
+ if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED)) {
+
+ SPX_DISC_SETSTATE(pSpxConnFile, 0);
+ }
+#if 0
+ //
+ // Make sure that this connection got a local disconnect if it was an SPXI
+ // connection earlier, in response to a TDI_DISCONNECT_RELEASE.
+ //
+
+ CTEAssert(pSpxConnFile->scf_RefTypes[CFREF_DISCWAITSPX] == 0);
+#endif
+
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_LISTENING);
+ SPX_LISTEN_SETSTATE(pSpxConnFile, (delayAccept ? SPX_LISTEN_RECDREQ : 0));
+
+ if (!delayAccept)
+ {
+ spxConnAcceptCr(
+ pSpxConnFile,
+ pSpxAddr,
+ lockHandleDev,
+ lockHandle,
+ lockHandleConn);
+ }
+ else
+ {
+ // Release the locks.
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock (&pSpxAddr->sa_Lock, lockHandle);
+ CTEFreeLock (&SpxDevice->dev_Lock, lockHandleDev);
+
+ // Complete the listen irp. Note reference is not removed. Done when
+ // accept is posted.
+ SpxCompleteRequest(pListenReq);
+ }
+ } else {
+ ++SpxDevice->dev_Stat.NoListenFailures;
+ }
+
+ // Deref the address
+ SpxAddrDereference (pSpxAddr, AREF_LOOKUP);
+ return;
+}
+
+
+
+
+VOID
+spxConnHandleSessPktFromClient(
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+ Packet received from the client side of the connection.
+ Handles:
+ Session Negotiate
+ Sends Session Setup, when recd, handles SS Ack
+
+ STATE MACHINE:
+
+ RR
+ / \
+ / \ ReceivedAck(SPX1Connection)
+ / \
+ / \--------> ACTIVE
+ / ^
+ Send / |
+ ACK / |
+ / |
+ / RecvNeg/NoNeg |
+ / SendSS |
+ SA--------->SS---------------+
+ ^ | SSAckRecv
+ | |
+ +-----+
+ RecvNeg
+
+ RR - Received Connect Request
+ SA - Sent CR Ack
+ SS - Sent Session Setup
+
+ We move from SA to SS when connection is not negotiatiable and we
+ immediately send the SS, or when we receive negotiate packet and send the neg
+ ack and the session setup.
+
+ Note we could receive a negotiate packet when in SS, as our ack to the
+ negotiate could have been dropped. We deal with this.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PNDIS_PACKET pSnAckPkt, pSsPkt = NULL;
+ PSPX_SEND_RESD pSendResd, pSsSendResd;
+ USHORT srcConnId, destConnId,
+ pktLen, seqNum, negSize, ackNum, allocNum;
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+ BOOLEAN locksHeld = FALSE;
+
+ GETSHORT2SHORT(&pktLen, &pIpxSpxHdr->hdr_PktLen);
+ GETSHORT2SHORT(&destConnId, &pIpxSpxHdr->hdr_DestConnId);
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+ GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
+
+ // We keep and use the remote id in the net format. This maintains the
+ // 0x0 and 0xFFFF to be as in the host format.
+ srcConnId = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_SrcConnId;
+
+ // If spx2 we convert neg size field too
+ if (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2)
+ {
+ GETSHORT2SHORT(&negSize, &pIpxSpxHdr->hdr_NegSize);
+ CTEAssert(negSize > 0);
+ }
+
+ // Grab all three locks
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ locksHeld = TRUE;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnHandleSessPktFromClient: %lx\n", pSpxConnFile));
+
+ // Check substate
+ switch (SPX_LISTEN_STATE(pSpxConnFile))
+ {
+ case SPX_LISTEN_RECDREQ:
+
+ // Do nothing.
+ break;
+
+ case SPX_LISTEN_SETUP:
+
+ // Is this a setup ack? If so, yippee. Our ack to a negotiate packet
+ // could have been dropped, and so we could also get a negotiate packet
+ // in that case. If that happens, fall through.
+ // Verify Ss Ack
+ if (!SPX2_CONN(pSpxConnFile) ||
+ (pktLen != MIN_IPXSPX2_HDRSIZE) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_SYS | SPX_CC_SPX2)) !=
+ (SPX_CC_SYS | SPX_CC_SPX2)) ||
+ (pIpxSpxHdr->hdr_DataType != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId) ||
+ (seqNum != 0))
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnSysPacket: VerifySSACK Failed Checking SN %lx.%lx\n",
+ srcConnId, destConnId));
+
+ // Fall through to see if this is a neg packet
+ if (!(SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG)))
+ {
+ break;
+ }
+ }
+ else
+ {
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromClient: Recd SSACK %lx\n",
+ pSpxConnFile));
+
+ spxConnCompleteConnect(
+ pSpxConnFile,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ break;
+ }
+
+ case SPX_LISTEN_SENTACK:
+
+ // We expect a negotiate packet.
+ // We should have asked for SPX2/NEG to begin with.
+ // Verify Sn
+ if (((pSpxConnFile->scf_Flags & (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG)) !=
+ (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG)) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) !=
+ (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) ||
+ (pIpxSpxHdr->hdr_DataType != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId) ||
+ (seqNum != 0) ||
+ ((negSize < SPX_NEG_MIN) ||
+ (negSize > SPX_NEG_MAX)))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnSysPacket: VerifySN Failed %lx.%lx\n",
+ srcConnId, destConnId));
+
+ break;
+ }
+
+ // Remember max packet size in connection.
+ pSpxConnFile->scf_MaxPktSize = negSize;
+ CTEAssert(negSize > 0);
+
+ // Build sn ack, abort if we fail
+ SpxPktBuildSnAck(
+ pSpxConnFile,
+ &pSnAckPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY);
+
+ if (pSnAckPkt == NULL)
+ {
+ spxConnAbortConnect(
+ pSpxConnFile,
+ STATUS_INSUFFICIENT_RESOURCES,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ break;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromClient: Sending SNACK %lx\n",
+ pSpxConnFile));
+
+ // Queue in the packet.
+ SpxConnQueueSendPktTail(pSpxConnFile, pSnAckPkt);
+
+ // The session packet should already be on queue.
+ if (!spxConnGetPktByType(
+ pSpxConnFile,
+ SPX_TYPE_SS,
+ FALSE,
+ &pSsPkt))
+ {
+ KeBugCheck(0);
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromClient: Sending SS %lx\n",
+ pSpxConnFile));
+
+ pSsSendResd = (PSPX_SEND_RESD)(pSsPkt->ProtocolReserved);
+
+ // We need to resend the packet
+ if ((pSsSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0)
+ {
+ // Try next time.
+ pSsPkt = NULL;
+ }
+ else
+ {
+ // Set the size to the neg size indicated in connection.
+ // This could be lower than the size the packet was build
+ // with originally. But will never be higher.
+ pSsSendResd->sr_State |= SPX_SENDPKT_IPXOWNS;
+ spxConnSetNegSize(
+ pSsPkt,
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE);
+ }
+
+ // If we are actually LISTEN_SETUP, then send the ss packet also.
+ // We need to start the connect timer to resend the ss pkt.
+ if (SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_SENTACK)
+ {
+ if ((pSpxConnFile->scf_CTimerId =
+ SpxTimerScheduleEvent(
+ spxConnConnectTimer,
+ PARAM(CONFIG_CONNECTION_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) == 0)
+ {
+ spxConnAbortConnect(
+ pSpxConnFile,
+ STATUS_INSUFFICIENT_RESOURCES,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ break;
+ }
+
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+
+ SPX_LISTEN_SETSTATE(pSpxConnFile, SPX_LISTEN_SETUP);
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ locksHeld = FALSE;
+
+ // Send ack packet
+ pSendResd = (PSPX_SEND_RESD)(pSnAckPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pSnAckPkt, pSendResd);
+
+ // If we have to send the session setup packet, send that too.
+ if (pSsPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pSsPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pSsPkt, pSendResd);
+ }
+
+ break;
+
+ default:
+
+ // Ignore
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnSysPacket: UNKNOWN %lx.%lx\n",
+ srcConnId, destConnId));
+
+ break;
+ }
+
+ if (locksHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnHandleSessPktFromSrv(
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+ Packet received from the server side of the connection. This will both
+ release the lock and dereference the connection as it sees fit.
+
+ STATE MACHINE:
+
+ SR--CTimerExpires-->IDLE
+ /| \
+ / | \ ReceivedAck(SPX1Connection)
+ / | \
+ / | \--------> ACTIVE
+ (Neg) / | ^
+ Send / |RecvAck |
+ SN / |NoNeg |
+ / | |
+ / | |
+ / v |
+ SN--------->WS---------------+
+ RecvSNAck RecvSS
+
+ SR - Sent Connect request
+ SN - Sent Session Negotiate
+ WS - Waiting for session setup packet
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ BOOLEAN fNeg, fSpx2;
+ USHORT srcConnId, destConnId,
+ pktLen, seqNum, negSize, ackNum, allocNum;
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+ BOOLEAN cTimerCancelled = FALSE, fAbort = FALSE, locksHeld = FALSE;
+ PNDIS_PACKET pSsAckPkt, pSnPkt, pPkt = NULL;
+
+ // We should get a CR Ack, or if our substate is sent session neg
+ // we should get a session neg ack, or if we are waiting for session
+ // setup, we should get one of those.
+
+ fSpx2 = (BOOLEAN)(pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2);
+ fNeg = (BOOLEAN)(fSpx2 && (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_NEG));
+
+ GETSHORT2SHORT(&pktLen, &pIpxSpxHdr->hdr_PktLen);
+ GETSHORT2SHORT(&destConnId, &pIpxSpxHdr->hdr_DestConnId);
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+ GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
+
+ // We keep and use the remote id in the net format. This maintains the
+ // 0x0 and 0xFFFF to be as in the host format.
+ srcConnId = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_SrcConnId;
+
+ // If spx2 we convert neg size field too
+ if (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2)
+ {
+ GETSHORT2SHORT(&negSize, &pIpxSpxHdr->hdr_NegSize);
+ CTEAssert(negSize > 0);
+ }
+
+ // Grab all three locks
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ locksHeld = TRUE;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnHandleSessPktFromSrv: %lx\n", pSpxConnFile));
+
+ // Check substate
+ switch (SPX_CONNECT_STATE(pSpxConnFile))
+ {
+ case SPX_CONNECT_SENTREQ:
+
+ // Check if this qualifies as the ack.
+ // Verify CR Ack
+ if ((pIpxSpxHdr->hdr_DataType != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (seqNum != 0) ||
+ (ackNum != 0) ||
+ ((pktLen != MIN_IPXSPX_HDRSIZE) &&
+ ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
+ (pktLen != MIN_IPXSPX2_HDRSIZE))) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
+ ((negSize < SPX_NEG_MIN) ||
+ (negSize > SPX_NEG_MAX))))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleSessPktFromSrv: CRAck Invalid %lx %lx.%lx.%lx\n",
+ pSpxConnFile,
+ pktLen, negSize, pIpxSpxHdr->hdr_ConnCtrl));
+
+ break;
+ }
+
+ // !!!BUGBUG!!!
+ // From current spx code base:
+ // Do we need to send an ack to this ack? In case of SPX only?
+ // What if this ack is dropped? We need to send an ack, if in future
+ // we get CONNECT REQ Acks, until we reach active?
+ // * If they want an ack schedule it. The normal case is for this not
+ // * to happen, but some Novell mainframe front ends insist on having
+ // * this. And technically, it is OK for them to do this.
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnHandleSessPktFromSrv: Recd CRACK %lx\n", pSpxConnFile));
+
+ // Grab the remote alloc num/conn id (in net format)
+ pSpxConnFile->scf_SendSeqNum = 0;
+ pSpxConnFile->scf_RecvSeqNum = 0;
+ pSpxConnFile->scf_RecdAckNum = 0;
+ pSpxConnFile->scf_RemConnId = srcConnId;
+ pSpxConnFile->scf_RecdAllocNum = allocNum;
+
+ // If we have been looking for network 0, which means the
+ // packets were sent on all NIC IDs, update our local
+ // target now that we have received a response.
+
+#if defined(_PNP_POWER)
+ if (pSpxConnFile->scf_LocalTarget.NicHandle.NicId == 0) {
+#else
+ if (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0) {
+#endif _PNP_POWER
+ pSpxConnFile->scf_LocalTarget = *pRemoteAddr;
+ pSpxConnFile->scf_AckLocalTarget= *pRemoteAddr;
+ }
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnHandleSessPktFromSrv: %lx CONN L.R %lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_LocalConnId,
+ pSpxConnFile->scf_RemConnId));
+
+ if (!fSpx2 || !fNeg)
+ {
+ cTimerCancelled = SpxTimerCancelEvent(
+ pSpxConnFile->scf_CTimerId, FALSE);
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+
+ if ((pSpxConnFile->scf_WTimerId =
+ SpxTimerScheduleEvent(
+ spxConnWatchdogTimer,
+ PARAM(CONFIG_KEEPALIVE_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) == 0)
+ {
+ fAbort = TRUE;
+ break;
+ }
+
+ // Reference transferred to watchdog timer.
+ if (cTimerCancelled)
+ {
+ cTimerCancelled = FALSE;
+ }
+ else
+ {
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+ }
+
+ // Set max packet size, assume not spx2 or !neg, so pass in FALSE
+ SPX_MAX_PKT_SIZE(pSpxConnFile, FALSE, FALSE, pIpxSpxHdr->hdr_SrcNet);
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPSrv: Accept connect req on %lx.%lx.%lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_LocalConnId,
+ pSpxConnFile->scf_RecdAllocNum, pSpxConnFile->scf_MaxPktSize));
+
+ if (!fSpx2)
+ {
+ // Reset spx2 flags.
+ SPX_CONN_RESETFLAG(pSpxConnFile, (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
+
+ // Complete connect request, this free the lock.
+ // Cancels tdi timer too. Sets all necessary flags.
+ spxConnCompleteConnect(
+ pSpxConnFile,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ break;
+ }
+
+ if (!fNeg)
+ {
+ // Goto W_SETUP
+ // Reset all connect related flags, also spx2/neg flags.
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_NEG);
+ SPX_CONNECT_SETSTATE(pSpxConnFile, SPX_CONNECT_W_SETUP);
+ break;
+ }
+
+ // Reset max packet size. SPX2 and NEG.
+ SPX_MAX_PKT_SIZE(pSpxConnFile, TRUE, TRUE, pIpxSpxHdr->hdr_SrcNet);
+
+ CTEAssert(negSize > 0);
+ CTEAssert(pSpxConnFile->scf_MaxPktSize > 0);
+ pSpxConnFile->scf_MaxPktSize =
+ MIN(negSize, pSpxConnFile->scf_MaxPktSize);
+
+ pSpxConnFile->scf_MaxPktSize = (USHORT)
+ MIN(pSpxConnFile->scf_MaxPktSize, PARAM(CONFIG_MAX_PACKET_SIZE));
+
+ // For SPX2 with negotiation, we set up sneg packet and move to
+ // SPX_CONNECT_NEG.
+ SpxPktBuildSn(
+ pSpxConnFile,
+ &pSnPkt,
+ SPX_SENDPKT_IPXOWNS);
+
+ if (pSnPkt == NULL)
+ {
+ fAbort = TRUE;
+ break;
+ }
+
+ // Queue in packet
+ SpxConnQueueSendPktTail(pSpxConnFile, pSnPkt);
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromSrv: Sending SN %lx\n",
+ pSpxConnFile));
+
+ // Reset retry count for connect timer
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
+
+ // Change state.
+ SPX_CONNECT_SETSTATE(pSpxConnFile, SPX_CONNECT_NEG);
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ locksHeld = FALSE;
+
+ // Send the packet
+ pSendResd = (PSPX_SEND_RESD)(pSnPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pSnPkt, pSendResd);
+ break;
+
+ case SPX_CONNECT_NEG:
+
+ // We expect a session neg ack.
+ // We should have asked for SPX2/NEG to begin with.
+ // Verify SN Ack
+ if (((pSpxConnFile->scf_Flags & (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG)) !=
+ (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG)) ||
+ (pktLen != MIN_IPXSPX2_HDRSIZE) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) !=
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) ||
+ (pIpxSpxHdr->hdr_DataType != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId) ||
+ (seqNum != 0))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnSysPacket: VerifySNACK Failed %lx.%lx\n",
+ srcConnId, destConnId));
+
+ break;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromSrv: Recd SNACK %lx %lx.%lx\n",
+ pSpxConnFile, negSize, pSpxConnFile->scf_MaxPktSize));
+
+ if (negSize > pSpxConnFile->scf_MaxPktSize)
+ negSize = pSpxConnFile->scf_MaxPktSize;
+
+ // Get the size to use
+ if (negSize <= pSpxConnFile->scf_MaxPktSize)
+ {
+ pSpxConnFile->scf_MaxPktSize = negSize;
+ if (!spxConnGetPktByType(
+ pSpxConnFile,
+ SPX_TYPE_SN,
+ FALSE,
+ &pPkt))
+ {
+ KeBugCheck(0);
+ }
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0)
+ {
+ // Set abort flag and reference conn for the pkt.
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+ else
+ {
+ // Free the negotiate packet
+ SpxPktSendRelease(pPkt);
+ }
+
+ CTEAssert(pSpxConnFile->scf_Flags & SPX_CONNFILE_C_TIMER);
+ cTimerCancelled = SpxTimerCancelEvent(
+ pSpxConnFile->scf_CTimerId, FALSE);
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+
+ // Start the watchdog timer, if fail, we abort.
+ if ((pSpxConnFile->scf_WTimerId =
+ SpxTimerScheduleEvent(
+ spxConnWatchdogTimer,
+ PARAM(CONFIG_KEEPALIVE_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) == 0)
+ {
+ // Complete cr with error.
+ fAbort = TRUE;
+ break;
+ }
+
+ // Reference goes to watchdog timer.
+ if (cTimerCancelled)
+ {
+ cTimerCancelled = FALSE;
+ }
+ else
+ {
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ // We move to the W_SETUP state.
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+
+ SPX_CONNECT_SETSTATE(pSpxConnFile, SPX_CONNECT_W_SETUP);
+ }
+
+ break;
+
+ case SPX_CONNECT_W_SETUP:
+
+ // Does this qualify as a session setup packet?
+ // Verify SS
+ if (!SPX2_CONN(pSpxConnFile) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_SPX2)) !=
+ (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_SPX2)) ||
+ (pIpxSpxHdr->hdr_DataType != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId) ||
+ (seqNum != 0) ||
+ ((negSize < SPX_NEG_MIN) ||
+ (negSize > SPX_NEG_MAX)))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnSysPacket: VerifySS Failed %lx.%lx, %lx %lx.%lx\n",
+ srcConnId, destConnId, negSize,
+ pIpxSpxHdr->hdr_ConnCtrl,
+ (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_SPX2)));
+
+ break;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromSrv: Recd SS %lx\n", pSpxConnFile));
+
+ // Copy remote address over into connection (socket could change)
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAddr);
+
+ // Remember max packet size in connection.
+ pSpxConnFile->scf_MaxPktSize = negSize;
+
+ // Build ss ack, abort if we fail
+ SpxPktBuildSsAck(
+ pSpxConnFile,
+ &pSsAckPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY | SPX_SENDPKT_ABORT);
+
+ if (pSsAckPkt == NULL)
+ {
+ fAbort = TRUE;
+ break;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromSrv: Sending SSACK %lx\n",
+ pSpxConnFile));
+
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+
+ // We dont queue in the pkt as its already marked as abort.
+ // Queue in the packet.
+ // SpxConnQueueSendPktTail(pSpxConnFile, pSsAckPkt);
+
+ // Complete connect, this releases lock.
+ spxConnCompleteConnect(
+ pSpxConnFile,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+
+ // Send ack packet
+ pSendResd = (PSPX_SEND_RESD)(pSsAckPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pSsAckPkt, pSendResd);
+ break;
+
+ default:
+
+ // Ignore
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnSysPacket: UNKNOWN %lx.%lx\n",
+ srcConnId, destConnId));
+
+ break;
+ }
+
+ if (fAbort)
+ {
+ spxConnAbortConnect(
+ pSpxConnFile,
+ STATUS_INSUFFICIENT_RESOURCES,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ }
+
+ if (locksHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ }
+
+ if (cTimerCancelled)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnAbortConnect(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN CTELockHandle LockHandleDev,
+ IN CTELockHandle LockHandleAddr,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+ This routine abort a connection (both client and server side) in the middle
+ of a connection establishment.
+
+ !!! Called with connection lock held, releases lock before return !!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt;
+ PREQUEST pRequest = NULL;
+ int numDerefs = 0;
+
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnAbortConnect: %lx\n", pSpxConnFile));
+
+#if DBG
+ if (!SPX_CONN_CONNECTING(pSpxConnFile) && !SPX_CONN_LISTENING(pSpxConnFile))
+ {
+ KeBugCheck(0);
+ }
+#endif
+
+ if (Status == STATUS_INSUFFICIENT_RESOURCES) { // others should be counted elsewhere
+ ++SpxDevice->dev_Stat.LocalResourceFailures;
+ }
+
+ // Free up all the packets
+ while ((pSendResd = pSpxConnFile->scf_SendListHead) != NULL)
+ {
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // Set abort flag and reference conn for the pkt.
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+ }
+
+
+ // Cancel all timers
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_TTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER);
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_CTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_WTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ }
+
+ // We could be called from disconnect for an accept in which case there
+ // will be no queued request. But we need to remove the reference if there
+ // is no request (an accept/listen irp) and listen state is on.
+ CTEAssert(IsListEmpty(&pSpxConnFile->scf_DiscLinkage));
+ if (!IsListEmpty(&pSpxConnFile->scf_ReqLinkage))
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(pSpxConnFile->scf_ReqLinkage.Flink);
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+ REQUEST_STATUS(pRequest) = Status;
+ REQUEST_INFORMATION(pRequest) = 0;
+
+ // Save req in conn for deref to complete.
+ pSpxConnFile->scf_ConnectReq = pRequest;
+
+ numDerefs++;
+ }
+ else if (SPX_CONN_LISTENING(pSpxConnFile))
+ {
+ numDerefs++;
+ }
+
+ // Bug #20999
+ // Race condition was an abort came in from timer, but the connect state
+ // was left unchanged. Due to an extra ref on the connection from the
+ // aborted cr, the state remained so, and then the cr ack came in, and
+ // a session neg was built and queued on the connection. Although it should
+ // not have been. And we hit the assert in deref where the connection is
+ // being reinitialized. Since this can be called for both listening and
+ // connecting connections, do the below.
+ SPX_LISTEN_SETSTATE(pSpxConnFile, 0);
+ if (SPX_CONN_CONNECTING(pSpxConnFile))
+ {
+ SPX_CONNECT_SETSTATE(pSpxConnFile, 0);
+ }
+
+ CTEFreeLock (&pSpxConnFile->scf_Lock, LockHandleConn);
+ CTEFreeLock (pSpxConnFile->scf_AddrFile->saf_AddrLock, LockHandleAddr);
+ CTEFreeLock (&SpxDevice->dev_Lock, LockHandleDev);
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+VOID
+spxConnCompleteConnect(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleDev,
+ IN CTELockHandle LockHandleAddr,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+ This routine completes a connection (both client and server side)
+ !!! Called with connection lock held, releases lock before return !!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PREQUEST pRequest;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt;
+ int numDerefs = 0;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnCompleteConnect: %lx\n", pSpxConnFile));
+
+#if DBG
+ if (!SPX_CONN_CONNECTING(pSpxConnFile) && !SPX_CONN_LISTENING(pSpxConnFile))
+ {
+ DBGBRK(FATAL);
+ }
+#endif
+
+ // Free up all the packets
+ while ((pSendResd = pSpxConnFile->scf_SendListHead) != NULL)
+ {
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // Set abort flag and reference conn for the pkt.
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+ }
+
+
+ // Cancel tdi connect timer if we are connecting.
+ switch (SPX_MAIN_STATE(pSpxConnFile))
+ {
+ case SPX_CONNFILE_CONNECTING:
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_TTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER);
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_CTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+ }
+
+ if (pSpxConnFile->scf_CRetryCount == (LONG)(PARAM(CONFIG_CONNECTION_COUNT))) {
+ ++SpxDevice->dev_Stat.ConnectionsAfterNoRetry;
+ } else {
+ ++SpxDevice->dev_Stat.ConnectionsAfterRetry;
+ }
+
+ // Reset all connect related flags
+ SPX_MAIN_SETSTATE(pSpxConnFile, 0);
+ SPX_CONNECT_SETSTATE(pSpxConnFile, 0);
+ break;
+
+ case SPX_CONNFILE_LISTENING:
+
+ if (pSpxConnFile->scf_Flags & SPX_CONNFILE_C_TIMER)
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_CTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+ }
+
+ SPX_MAIN_SETSTATE(pSpxConnFile, 0);
+ SPX_LISTEN_SETSTATE(pSpxConnFile, 0);
+ break;
+
+ default:
+
+ KeBugCheck(0);
+
+ }
+
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_ACTIVE);
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ SPX_RECV_SETSTATE(pSpxConnFile, SPX_RECV_IDLE);
+
+ ++SpxDevice->dev_Stat.OpenConnections;
+
+ // Initialize timer values
+ pSpxConnFile->scf_BaseT1 =
+ pSpxConnFile->scf_AveT1 = PARAM(CONFIG_INITIAL_RETRANSMIT_TIMEOUT);
+ pSpxConnFile->scf_DevT1 = 0;
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+
+ pRequest = LIST_ENTRY_TO_REQUEST(pSpxConnFile->scf_ReqLinkage.Flink);
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+ REQUEST_STATUS(pRequest) = STATUS_SUCCESS;
+ REQUEST_INFORMATION(pRequest) = 0;
+
+ // When we complete the request, we essentially transfer the reference
+ // to the fact that the connection is active. This will be taken away
+ // when a Disconnect happens on the connection and we transition from
+ // ACTIVE to DISCONN.
+ // numDerefs++;
+
+ CTEFreeLock (&pSpxConnFile->scf_Lock, LockHandleConn);
+ CTEFreeLock (pSpxConnFile->scf_AddrFile->saf_AddrLock, LockHandleAddr);
+ CTEFreeLock (&SpxDevice->dev_Lock, LockHandleDev);
+
+ // Complete request
+ SpxCompleteRequest(pRequest);
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+BOOLEAN
+spxConnAcceptCr(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_ADDR pSpxAddr,
+ IN CTELockHandle LockHandleDev,
+ IN CTELockHandle LockHandleAddr,
+ IN CTELockHandle LockHandleConn
+ )
+{
+ PNDIS_PACKET pSsPkt, pCrAckPkt;
+ PSPX_SEND_RESD pSendResd;
+
+ BOOLEAN fNeg = SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG);
+ BOOLEAN fSpx2 = SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2);
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnAcceptCr: %lx.%d.%d\n",
+ pSpxConnFile, fSpx2, fNeg));
+
+ // Build and queue in packet.
+ SpxPktBuildCrAck(
+ pSpxConnFile,
+ pSpxAddr,
+ &pCrAckPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
+ fNeg,
+ fSpx2);
+
+ if ((pCrAckPkt != NULL) &&
+ (pSpxConnFile->scf_LocalConnId != 0))
+ {
+ // Queue in the packet.
+ SpxConnQueueSendPktTail(pSpxConnFile, pCrAckPkt);
+ }
+ else
+ {
+ goto AbortConnect;
+ }
+
+
+ // Start the timer
+ if ((pSpxConnFile->scf_WTimerId =
+ SpxTimerScheduleEvent(
+ spxConnWatchdogTimer,
+ PARAM(CONFIG_KEEPALIVE_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) != 0)
+ {
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+ }
+ else
+ {
+ goto AbortConnect;
+ }
+
+
+ // We start the connect timer for retrying ss which we send out now
+ // if we are not negotiating.
+ if (fSpx2)
+ {
+ // Build the session setup packet also for spx2.
+ SpxPktBuildSs(
+ pSpxConnFile,
+ &pSsPkt,
+ (USHORT)(fNeg ? 0 : SPX_SENDPKT_IPXOWNS));
+
+ if (pSsPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pSsPkt);
+ }
+ else
+ {
+ goto AbortConnect;
+ }
+
+ if (!fNeg)
+ {
+ if ((pSpxConnFile->scf_CTimerId =
+ SpxTimerScheduleEvent(
+ spxConnConnectTimer,
+ PARAM(CONFIG_CONNECTION_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) != 0)
+ {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
+
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ }
+ else
+ {
+ goto AbortConnect;
+ }
+ }
+ }
+
+ CTEAssert((fNeg && fSpx2) || (!fSpx2 && !fNeg));
+
+ // For a SPX connection, we immediately become active. This happens
+ // in the completeConnect routine. !!Dont change it here!!
+ if (!fSpx2)
+ {
+ spxConnCompleteConnect(
+ pSpxConnFile,
+ LockHandleDev,
+ LockHandleAddr,
+ LockHandleConn);
+ }
+ else
+ {
+ SPX_LISTEN_SETSTATE(
+ pSpxConnFile, (fNeg ? SPX_LISTEN_SENTACK : SPX_LISTEN_SETUP));
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ CTEFreeLock (&pSpxAddr->sa_Lock, LockHandleAddr);
+ CTEFreeLock (&SpxDevice->dev_Lock, LockHandleDev);
+ }
+
+ // Send the CR Ack packet!
+ pSendResd = (PSPX_SEND_RESD)(pCrAckPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pCrAckPkt, pSendResd);
+
+ if (fSpx2 && !fNeg)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pSsPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pSsPkt, pSendResd);
+ }
+
+ return(TRUE);
+
+
+AbortConnect:
+
+ spxConnAbortConnect(
+ pSpxConnFile,
+ STATUS_INSUFFICIENT_RESOURCES,
+ LockHandleDev,
+ LockHandleAddr,
+ LockHandleConn);
+
+ return (FALSE);
+}
+
+
+
+BOOLEAN
+SpxConnPacketize(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN BOOLEAN fNormalState,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+ The caller needs to set the state to packetize before calling this
+ routine. This can be called when SEND state is RENEG also.
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+ fNormalState - If true, it will assume it can release lock to send,
+ else, it just builds pkts without releasing lock and
+ releases lock at end. Used after reneg changes size.
+
+Return Value:
+
+
+--*/
+{
+ PLIST_ENTRY p;
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ USHORT windowSize;
+ ULONG dataLen;
+ USHORT sendFlags;
+ int numDerefs = 0;
+ BOOLEAN fFirstPass = TRUE, fSuccess = TRUE;
+ PREQUEST pRequest;
+
+#if DBG
+ if ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_PACKETIZE) &&
+ fNormalState)
+ {
+ DBGBRK(FATAL);
+ KeBugCheck(0);
+ }
+#endif
+
+ // Build all of the packets. The firsttime flag is used so
+ // that if we get a 0 byte send, we will send it. The firsttime
+ // flag will be set and we will build the packet and send it.
+ //
+ // FOR SPX1, we cannot trust the remote window size. So we only send
+ // stuff if window size is greater than 0 *AND* we do not have any pending
+ // sends. Dont get in here if we are ABORT. Dont want to be handling any
+ // more requests.
+ while((SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_ABORT) &&
+ ((pRequest = pSpxConnFile->scf_ReqPkt) != NULL) &&
+ ((pSpxConnFile->scf_ReqPktSize > 0) || fFirstPass))
+ {
+ fFirstPass = FALSE;
+ windowSize = pSpxConnFile->scf_RecdAllocNum -
+ pSpxConnFile->scf_SendSeqNum + 1;
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnPacketize: WINDOW %lx for %lx\n",
+ windowSize, pSpxConnFile));
+
+
+ DBGPRINT(SEND, DBG,
+ ("REMALLOC %lx SENDSEQ %lx\n",
+ pSpxConnFile->scf_RecdAllocNum,
+ pSpxConnFile->scf_SendSeqNum));
+
+
+ CTEAssert(windowSize >= 0);
+
+ // Disconnect/Orderly release is not subject to window closure.
+ if ((pSpxConnFile->scf_ReqPktType == SPX_REQ_DATA) &&
+ ((windowSize == 0) ||
+ (!SPX2_CONN(pSpxConnFile) &&
+ (pSpxConnFile->scf_SendSeqListHead != NULL))))
+ {
+ break;
+ }
+
+ if (pSpxConnFile->scf_ReqPktType == SPX_REQ_DATA)
+ {
+ CTEAssert(pRequest == pSpxConnFile->scf_ReqPkt);
+
+ // Get data length
+ dataLen = (ULONG)MIN(pSpxConnFile->scf_ReqPktSize,
+ (pSpxConnFile->scf_MaxPktSize -
+ ((SPX2_CONN(pSpxConnFile) ?
+ MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE))));
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnPacketize: %lx Sending %lx Size %lx Req %lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_SendSeqNum,
+ dataLen,
+ pSpxConnFile->scf_ReqPkt,
+ pSpxConnFile->scf_ReqPktSize));
+
+ // Build data packet. Handles 0-length for data. Puts in seq num in
+ // send resd section of packet also.
+ sendFlags =
+ (USHORT)((fNormalState ? SPX_SENDPKT_IPXOWNS : 0) |
+ SPX_SENDPKT_REQ |
+ SPX_SENDPKT_SEQ |
+ ((!SPX2_CONN(pSpxConnFile) || (windowSize == 1)) ?
+ SPX_SENDPKT_ACKREQ : 0));
+
+ if (dataLen == pSpxConnFile->scf_ReqPktSize)
+ {
+ // Last packet of send, ask for a ack.
+ sendFlags |= (SPX_SENDPKT_LASTPKT | SPX_SENDPKT_ACKREQ);
+ if ((pSpxConnFile->scf_ReqPktFlags & TDI_SEND_PARTIAL) == 0)
+ sendFlags |= SPX_SENDPKT_EOM;
+ }
+
+ SpxPktBuildData(
+ pSpxConnFile,
+ &pPkt,
+ sendFlags,
+ (USHORT)dataLen);
+ }
+ else
+ {
+ dataLen = 0;
+
+ DBGPRINT(SEND, DBG,
+ ("Building DISC packet on %lx ReqPktSize %lx\n",
+ pSpxConnFile, pSpxConnFile->scf_ReqPktSize));
+
+ // Build informed disc/orderly rel packet, associate with request
+ SpxPktBuildDisc(
+ pSpxConnFile,
+ pRequest,
+ &pPkt,
+ (USHORT)((fNormalState ? SPX_SENDPKT_IPXOWNS : 0) | SPX_SENDPKT_REQ |
+ SPX_SENDPKT_SEQ | SPX_SENDPKT_LASTPKT),
+ (UCHAR)((pSpxConnFile->scf_ReqPktType == SPX_REQ_ORDREL) ?
+ SPX2_DT_ORDREL : SPX2_DT_IDISC));
+ }
+
+ if (pPkt != NULL)
+ {
+ // If we were waiting to send an ack, we don't have to as we are
+ // piggybacking it now. Cancel ack timer, get out.
+ if (fNormalState && SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ACKQ))
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxConnPacketize: Piggyback happening for %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RecvSeqNum));
+
+ // We are sending data, allow piggybacks to happen.
+ SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_IMMED_ACK);
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_ACKQ);
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_ATimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ }
+
+ if (pSpxConnFile->scf_ReqPktType != SPX_REQ_DATA)
+ {
+ // For a disconnect set the state
+ if (pSpxConnFile->scf_ReqPktType == SPX_REQ_ORDREL)
+ {
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC))
+ {
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_DISCONN);
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_SENT_ORDREL);
+ numDerefs++;
+ }
+ else if (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_POST_ORDREL)
+ {
+ CTEAssert((SPX_MAIN_STATE(pSpxConnFile) ==
+ SPX_CONNFILE_ACTIVE) ||
+ (SPX_MAIN_STATE(pSpxConnFile) ==
+ SPX_CONNFILE_DISCONN));
+
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_SENT_ORDREL);
+ }
+ else
+ {
+ CTEAssert(
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_SENT_ORDREL));
+ }
+ }
+ else
+ {
+ CTEAssert(SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN);
+ CTEAssert(SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_POST_IDISC);
+
+ // Note we have send the idisc here.
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_SENT_IDISC);
+ }
+ }
+ }
+ else
+ {
+ fSuccess = FALSE;
+ break;
+ }
+
+
+ // Queue in packet, reference request for the packet
+ SpxConnQueueSendSeqPktTail(pSpxConnFile, pPkt);
+ REQUEST_INFORMATION(pRequest)++;
+
+ pSpxConnFile->scf_ReqPktSize -= dataLen;
+ pSpxConnFile->scf_ReqPktOffset += dataLen;
+
+ DBGPRINT(SEND, INFO,
+ ("SpxConnPacketize: Req %lx Size after pkt %lx.%lx\n",
+ pSpxConnFile->scf_ReqPkt, pSpxConnFile->scf_ReqPktSize,
+ dataLen));
+
+ // Even if window size if zero, setup next request is current one
+ // is done. We are here only after we have packetized this send req.
+ if (pSpxConnFile->scf_ReqPktSize == 0)
+ {
+ // This request has been fully packetized. Either go on to
+ // next request or we are done packetizing.
+ p = REQUEST_LINKAGE(pRequest);
+ if (p->Flink == &pSpxConnFile->scf_ReqLinkage)
+ {
+ DBGPRINT(SEND, INFO,
+ ("SpxConnPacketize: Req %lx done, no more\n",
+ pRequest));
+
+ pSpxConnFile->scf_ReqPkt = NULL;
+ pSpxConnFile->scf_ReqPktSize = 0;
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pRequest = NULL;
+ }
+ else
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(p->Flink);
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ PTDI_REQUEST_KERNEL_SEND pParam;
+
+ pParam = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(pRequest);
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnPacketize: Req done, setting next %lx.%lx\n",
+ pRequest, pParam->SendLength));
+
+ DBGPRINT(SEND, INFO,
+ ("-%lx-\n",
+ pRequest));
+
+ // Set parameters in connection for another go.
+ pSpxConnFile->scf_ReqPkt = pRequest;
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pSpxConnFile->scf_ReqPktFlags = pParam->SendFlags;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DATA;
+
+ if ((pSpxConnFile->scf_ReqPktSize = pParam->SendLength) == 0)
+ {
+ // Another zero length send.
+ fFirstPass = TRUE;
+ }
+ }
+ else
+ {
+ PTDI_REQUEST_KERNEL_DISCONNECT pParam;
+
+ pParam =
+ (PTDI_REQUEST_KERNEL_DISCONNECT)REQUEST_PARAMETERS(pRequest);
+
+ pSpxConnFile->scf_ReqPkt = pRequest;
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pSpxConnFile->scf_ReqPktSize = 0;
+ fFirstPass = TRUE;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DISC;
+ if (pParam->RequestFlags == TDI_DISCONNECT_RELEASE)
+ {
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_ORDREL;
+ }
+ }
+ }
+ }
+
+ if (fNormalState)
+ {
+ // Send the packet if we are not at the reneg state
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ ++SpxDevice->dev_Stat.DataFramesSent;
+ ExInterlockedAddLargeStatistic(
+ &SpxDevice->dev_Stat.DataFrameBytesSent,
+ dataLen);
+ SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ }
+
+ // Check if retry timer needs to be started.
+ if (!(SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER)))
+ {
+ if ((pSpxConnFile->scf_RTimerId =
+ SpxTimerScheduleEvent(
+ spxConnRetryTimer,
+ pSpxConnFile->scf_BaseT1,
+ pSpxConnFile)) != 0)
+ {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ }
+ else
+ {
+ DBGPRINT(SEND, ERR,
+ ("SpxConnPacketize: Failed to start retry timer\n"));
+
+ fSuccess = FALSE;
+ break;
+ }
+ }
+ }
+
+ // Dont overwrite an error state.
+ if (((fNormalState) &&
+ (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_PACKETIZE)) ||
+ ((SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_RETRY3) &&
+ (pSpxConnFile->scf_SendSeqListHead == NULL)))
+ {
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_RETRY3)
+ {
+ DBGPRINT(SEND, ERR,
+ ("COULD NOT PACKETIZE AFTER RENEG %lx\n", pSpxConnFile));
+
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ numDerefs++;
+ }
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ }
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(fSuccess);
+}
+
+
+
+
+VOID
+SpxConnQueueRecv(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PREQUEST pRequest
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PTDI_REQUEST_KERNEL_RECEIVE pParam;
+ NTSTATUS status = STATUS_PENDING;
+
+ if (IsListEmpty(&pSpxConnFile->scf_RecvLinkage))
+ {
+ pParam = (PTDI_REQUEST_KERNEL_RECEIVE)REQUEST_PARAMETERS(pRequest);
+ pSpxConnFile->scf_CurRecvReq = pRequest;
+ pSpxConnFile->scf_CurRecvOffset = 0;
+ pSpxConnFile->scf_CurRecvSize = pParam->ReceiveLength;
+ }
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnQueueRecv: %lx.%lx\n", pRequest, pParam->ReceiveLength));
+
+ // Reference connection for this recv.
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+
+ InsertTailList(
+ &pSpxConnFile->scf_RecvLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // RECV irps have no creation references.
+ REQUEST_INFORMATION(pRequest) = 0;
+ REQUEST_STATUS(pRequest) = STATUS_SUCCESS;
+
+ // State to receive_posted if we are idle.
+ if (SPX_RECV_STATE(pSpxConnFile) == SPX_RECV_IDLE)
+ {
+ SPX_RECV_SETSTATE(pSpxConnFile, SPX_RECV_POSTED);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnCompletePended(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+{
+ CTELockHandle lockHandleInter;
+ LIST_ENTRY ReqList, *p;
+ PREQUEST pRequest;
+
+ InitializeListHead(&ReqList);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnCompletePended: PENDING RECV REQUESTS IN DONE LIST! %lx\n",
+ pSpxConnFile));
+
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ p = pSpxConnFile->scf_RecvDoneLinkage.Flink;
+ while (p != &pSpxConnFile->scf_RecvDoneLinkage)
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+ InsertTailList(
+ &ReqList,
+ REQUEST_LINKAGE(pRequest));
+ }
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+
+ while (!IsListEmpty(&ReqList))
+ {
+ p = RemoveHeadList(&ReqList);
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ DBGPRINT(TDI, DBG,
+ ("SpxConnDiscPkt: PENDING REQ COMP %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+
+#if DBG
+ if (REQUEST_MINOR_FUNCTION(pRequest) == TDI_RECEIVE)
+ {
+ if ((REQUEST_STATUS(pRequest) == STATUS_SUCCESS) &&
+ (REQUEST_INFORMATION(pRequest) == 0))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxReceiveComplete: Completing %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+ }
+ }
+#endif
+
+ SpxCompleteRequest(pRequest);
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+VOID
+SpxConnQWaitAck(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ // If we are not already in ack queue, queue ourselves in starting
+ // ack timer.
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ACKQ))
+ {
+ // First start ack timer.
+ if ((pSpxConnFile->scf_ATimerId =
+ SpxTimerScheduleEvent(
+ spxConnAckTimer,
+ 100,
+ pSpxConnFile)) != 0)
+ {
+ // Reference connection for timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_ACKQ);
+ ++SpxDevice->dev_Stat.PiggybackAckQueued;
+ }
+ }
+
+ return;
+}
+
+
+
+
+
+VOID
+SpxConnSendAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt = NULL;
+
+ DBGPRINT(SEND, DBG,
+ ("spxConnSendAck: ACKING on %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RecvSeqNum));
+
+ // Build an ack packet, queue it in non-sequenced queue. Only if we are
+ // active.
+ if (SPX_CONN_ACTIVE(pSpxConnFile))
+ {
+ SpxPktBuildAck(
+ pSpxConnFile,
+ &pPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
+ FALSE,
+ 0);
+
+ if (pPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+ }
+ else
+ {
+ // Log error
+ DBGPRINT(SEND, ERR,
+ ("SpxConnSendAck: Could not allocate!\n"));
+ }
+ }
+#if DBG
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxConnSendAck: WHEN NOT ACTIVE STATE@!@\n"));
+ }
+#endif
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ // Send it.
+ if (pPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+
+ // Send the packet
+ SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxConnSendNack(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN USHORT NumToSend,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt = NULL;
+
+ DBGPRINT(SEND, DBG,
+ ("spxConnSendNack: NACKING on %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RecvSeqNum));
+
+ // Build an nack packet, queue it in non-sequenced queue. Only if we are
+ // active.
+ if (SPX_CONN_ACTIVE(pSpxConnFile))
+ {
+ SpxPktBuildAck(
+ pSpxConnFile,
+ &pPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
+ TRUE,
+ NumToSend);
+
+ if (pPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+ }
+ else
+ {
+ // Log error
+ DBGPRINT(SEND, ERR,
+ ("SpxConnSendAck: Could not allocate!\n"));
+ }
+ }
+#if DBG
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxConnSendAck: WHEN NOT ACTIVE STATE@!@\n"));
+ }
+#endif
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ // Send it.
+ if (pPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+
+ // Send the packet
+ SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ return;
+}
+
+
+
+
+
+BOOLEAN
+SpxConnProcessAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN CTELockHandle lockHandle
+ )
+/*++
+
+Routine Description:
+
+ !!!MUST BE CALLED WITH THE CONNECTION LOCK HELD!!!
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ PREQUEST pRequest;
+ PSPX_SEND_RESD pSendResd;
+ CTELockHandle interLockHandle;
+ USHORT seqNum = 0, ackNum;
+ int numDerefs = 0;
+ BOOLEAN fLastPkt, lockHeld = TRUE, fAbort = FALSE,
+ fResetRetryTimer, fResendPkt = FALSE, fResetSendQueue = FALSE;
+
+ if (pIpxSpxHdr != NULL)
+ {
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+
+ // Ack numbers should already be set in connection!
+ if (SPX2_CONN(pSpxConnFile))
+ {
+ switch (SPX_SEND_STATE(pSpxConnFile))
+ {
+ case SPX_SEND_RETRYWD:
+
+ // Did we receive an ack for pending data? If so, we goto
+ // idle and process the ack.
+ if (((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL) &&
+ (UNSIGNED_GREATER_WITH_WRAP(
+ pSpxConnFile->scf_RecdAckNum,
+ pSendResd->sr_SeqNum)))
+ {
+ DBGPRINT(SEND, ERR,
+ ("SpxConnProcessAck: Data acked RETRYWD %lx.%lx!\n",
+ pSpxConnFile, pSendResd->sr_SeqNum));
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ numDerefs++;
+ }
+ else
+ {
+ // Ok, we received an ack for our probe retry, goto
+ // renegotiate packet size.
+ // For this both sides must have negotiated size to begin with.
+ // If they did not, we go on to retrying the data packet.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG))
+ {
+ pSpxConnFile->scf_RRetryCount = SPX_DEF_RENEG_RETRYCOUNT;
+ if ((ULONG)pSpxConnFile->scf_MaxPktSize <=
+ (SpxMaxPktSize[0] + MIN_IPXSPX2_HDRSIZE))
+ {
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: %lx MIN RENEG SIZE\n",
+ pSpxConnFile));
+ }
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RENEG);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: %lx CONNECTION ENTERING RENEG\n",
+ pSpxConnFile));
+ }
+ else
+ {
+ DBGPRINT(SEND, ERR,
+ ("spxConnRetryTimer: NO NEG FLAG SET: %lx - %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_Flags));
+
+ // Reset count to be
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY3);
+ }
+ }
+
+ break;
+
+ case SPX_SEND_RENEG:
+
+ // We better have a data packet in the list.
+ CTEAssert(pSpxConnFile->scf_SendSeqListHead);
+
+#if DBG
+ if ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) ==
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2))
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: %lx.%lx.%lx RENEGACK SEQNUM %lx ACKNUM %lx EXPSEQ %lx\n",
+ pSpxConnFile,
+ pIpxSpxHdr->hdr_ConnCtrl,
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT),
+ seqNum,
+ ackNum,
+ (pSpxConnFile->scf_SendSeqListHead->sr_SeqNum + 1)));
+ }
+#endif
+
+ // Verify we received an RR ack. If so, we set state to
+ // SEND_RETRY3. First repacketize if we need to.
+ if ((SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT)) &&
+ ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) ==
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)))
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: RENEG! NEW %lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_MaxPktSize));
+
+ // Dont allow anymore reneg packet acks to be looked at.
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT);
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+
+ // Also set the new send sequence number.
+ pSpxConnFile->scf_SendSeqNum =
+ (USHORT)(pSpxConnFile->scf_SendSeqListTail->sr_SeqNum + 1);
+
+ // Get the max packet size we will really use. Retry timer
+ // could have sent other sizes by now, so we can't depend
+ // on whats set.
+ // Remember max packet size in connection.
+ GETSHORT2SHORT(
+ &pSpxConnFile->scf_MaxPktSize, &pIpxSpxHdr->hdr_NegSize);
+
+ // Basic sanity checking on the max packet size.
+ if (pSpxConnFile->scf_MaxPktSize < SPX_NEG_MIN)
+ pSpxConnFile->scf_MaxPktSize = SPX_NEG_MIN;
+
+ // Get ready to reset the send queue.
+ fResetSendQueue = TRUE;
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: RENEG DONE : RETRY3 %lx.%lx MP %lx!\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_SendSeqNum,
+ pSpxConnFile->scf_MaxPktSize));
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY3);
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: DUPLICATE RENEG ACK %lx!\n",
+ pSpxConnFile));
+ }
+
+ break;
+
+ case SPX_SEND_RETRY:
+ case SPX_SEND_RETRY2:
+ case SPX_SEND_RETRY3:
+
+ if (((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL) &&
+ (UNSIGNED_GREATER_WITH_WRAP(
+ pSpxConnFile->scf_RecdAckNum,
+ pSendResd->sr_SeqNum)))
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxConnProcessAck: Data acked %lx.%lx!\n",
+ pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
+
+#if DBG
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_RETRY3)
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: CONN RESTORED %lx.%lx!\n",
+ pSpxConnFile, pSendResd->sr_SeqNum));
+ }
+#endif
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ numDerefs++;
+ }
+
+ break;
+
+ case SPX_SEND_WD:
+
+ // Ok, we received an ack for our watchdog. Done.
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ numDerefs++;
+
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ break;
+
+ default:
+
+ break;
+ }
+
+#if DBG
+ if (seqNum != 0)
+ {
+ // We have a nack, which contains an implicit ack.
+ // Instead of nack processing, what we do is we resend a
+ // packet left unacked after ack processing. ONLY if we
+ // either enter the loop below (fResetRetryTimer is FALSE)
+ // or if seqNum is non-zero (SPX2 only NACK)
+ }
+#endif
+ }
+ }
+
+ // Once our numbers are updated, we check to see if any of our packets
+ // have been acked.
+ fResetRetryTimer = TRUE;
+ while (((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL) &&
+ ((SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE) ||
+ (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_PACKETIZE) ||
+ fResetSendQueue) &&
+ (UNSIGNED_GREATER_WITH_WRAP(
+ pSpxConnFile->scf_RecdAckNum,
+ pSendResd->sr_SeqNum)))
+ {
+ // Reset retry timer
+ if (fResetRetryTimer)
+ {
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER))
+ {
+ // This will either successfully restart or not affect the timer
+ // if it is currently running.
+ SpxTimerCancelEvent(
+ pSpxConnFile->scf_RTimerId,
+ TRUE);
+
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+ }
+
+ fResetRetryTimer = FALSE;
+ }
+
+ // Update the retry seq num.
+ pSpxConnFile->scf_RetrySeqNum = pSendResd->sr_SeqNum;
+
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ pRequest = pSendResd->sr_Request;
+
+#if DBG
+ if (fResetSendQueue)
+ {
+ DBGPRINT(SEND, ERR,
+ ("SpxConnProcessAck: Data acked RENEG %lx.%lx!\n",
+ pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
+ }
+#endif
+
+ DBGPRINT(SEND, DBG,
+ ("%lx Acked\n", pSendResd->sr_SeqNum));
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnProcessAck: %lx Seq %lx Acked Sr %lx Req %lx %lx.%lx\n",
+ pSpxConnFile,
+ pSendResd->sr_SeqNum,
+ pSendResd,
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // If this packet is the last one comprising this request, remove request
+ // from queue. Calculate retry time.
+ fLastPkt = (BOOLEAN)((pSendResd->sr_State & SPX_SENDPKT_LASTPKT) != 0);
+ if ((pSendResd->sr_State & SPX_SENDPKT_ACKREQ) &&
+ ((pSendResd->sr_State & SPX_SENDPKT_REXMIT) == 0) &&
+ ((pSendResd->sr_SeqNum + 1) == pSpxConnFile->scf_RecdAckNum))
+ {
+ LARGE_INTEGER li, ntTime;
+ int value;
+
+ // This is the packet which is being acked. Adjust round trip
+ // timer.
+ li = pSendResd->sr_SentTime;
+ if (li.LowPart && li.HighPart)
+ {
+ KeQuerySystemTime(&ntTime);
+
+ // Get the difference
+ ntTime.QuadPart = ntTime.QuadPart - li.QuadPart;
+
+ // Convert to milliseconds. If the highpart is 0, we
+ // take a shortcut.
+ if (ntTime.HighPart == 0)
+ {
+ value = ntTime.LowPart/10000;
+ }
+ else
+ {
+ ntTime = SPX_CONVERT100NSTOCENTISEC(ntTime);
+ value = ntTime.LowPart << 4;
+ }
+
+ // Set new time
+ SpxCalculateNewT1(pSpxConnFile, value);
+ }
+ }
+
+ if (fLastPkt)
+ {
+ // Set status
+ REQUEST_STATUS(pRequest) = STATUS_SUCCESS;
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+
+ // Remove creation reference
+ --(REQUEST_INFORMATION(pRequest));
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnProcessAck: LASTSEQ # %lx for Req %lx with %lx.%lx\n",
+ pSendResd->sr_SeqNum,
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ CTEAssert(REQUEST_INFORMATION(pRequest) != 0);
+ }
+
+ // Dequeue the packet
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_SEQ) != 0);
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ // Dereference request for the dequeing of the packet
+ --(REQUEST_INFORMATION(pRequest));
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnProcessAck: Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // Packet owned by IPX. What do we do now? Set acked pkt so request
+ // gets dereferenced in send completion. Note that the packet is already
+ // off the queue and is floating at this point.
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnProcessAck: IPXOWNS Pkt %lx with %lx.%lx\n",
+ pPkt, pRequest, REQUEST_STATUS(pRequest)));
+
+ pSendResd->sr_State |= SPX_SENDPKT_ACKEDPKT;
+ }
+
+ if (SPX2_CONN(pSpxConnFile) &&
+ (REQUEST_MINOR_FUNCTION(pRequest) == TDI_DISCONNECT) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_SENT_ORDREL))
+ {
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_ORDREL_ACKED);
+
+ // If we had received an ordrel in the meantime, we need
+ // to disconnect.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC))
+ {
+ fAbort = TRUE;
+ }
+ }
+
+ // All packets comprising a request have been acked!
+ if (REQUEST_INFORMATION(pRequest) == 0)
+ {
+ CTELockHandle lockHandleInter;
+
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ PTDI_REQUEST_KERNEL_SEND pParam;
+
+ pParam = (PTDI_REQUEST_KERNEL_SEND)
+ REQUEST_PARAMETERS(pRequest);
+
+ REQUEST_INFORMATION(pRequest) = pParam->SendLength;
+
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: QForComp Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_ReqDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // If connection is not already in recv queue, put it in
+ // there.
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Set the request in the connection, and deref for it.
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ numDerefs++;
+
+ }
+ }
+#if DBG
+ else if (fLastPkt)
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessAck: ReqFloating %lx.%lx\n",
+ pSpxConnFile, pRequest));
+ }
+#endif
+ }
+
+ // See if we reset the send queue and repacketize.
+ if (fResetSendQueue)
+ {
+ // Reset send queue and repacketize only if pkts left unacked.
+ if (pSpxConnFile->scf_SendSeqListHead)
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: Resetting send queue %lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_MaxPktSize));
+
+ spxConnResetSendQueue(pSpxConnFile);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: Repacketizing %lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_MaxPktSize));
+
+ SpxConnPacketize(pSpxConnFile, FALSE, lockHandle);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ }
+ else
+ {
+ // We just go back to idle state now.
+ DBGPRINT(SEND, ERR,
+ ("SpxConnProcessAck: All packets acked reneg ack! %lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_MaxPktSize));
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ numDerefs++;
+
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+ }
+ }
+
+ // See if we resend a packet.
+ if ((seqNum != 0) &&
+ !fAbort &&
+ ((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL) &&
+ (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE) &&
+ ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0))
+ {
+ PIPXSPX_HDR pSendHdr;
+
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ pSendHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ // Set ack bit in packet. pSendResd initialized at beginning.
+ pSendHdr->hdr_ConnCtrl |= SPX_CC_ACK;
+
+ // We are going to resend this packet
+ pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
+ SPX_SENDPKT_ACKREQ |
+ SPX_SENDPKT_REXMIT);
+
+ fResendPkt = TRUE;
+ }
+
+ // Push into packetize only if we received an ack. And if there arent any
+ // packets already waiting. Probably retransmit happening.
+ if (!fAbort &&
+ SPX_CONN_ACTIVE(pSpxConnFile) &&
+ (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE) &&
+ (pSpxConnFile->scf_ReqPkt != NULL) &&
+ (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_PKTQ)) &&
+ ((pSpxConnFile->scf_SendSeqListHead) == NULL) &&
+ (!SPX2_CONN(pSpxConnFile) ||
+ ((SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_ORDREL_ACKED) &&
+ (SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_SENT_ORDREL))))
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessAck: Recd ack pktizng\n", pSpxConnFile));
+
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_PKTQ);
+ SpxConnFileLockReference(pSpxConnFile, CFREF_PKTIZE);
+
+ CTEGetLock(&SpxGlobalQInterlock, &interLockHandle);
+ SPX_QUEUE_TAIL_PKTLIST(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, interLockHandle);
+ }
+ else if (fAbort)
+ {
+ // Set IDISC flag so Abortive doesnt reindicate.
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_SUCCESS,
+ SPX_CALL_RECVLEVEL,
+ lockHandle,
+ FALSE); // [SA] bug #15249
+
+ lockHeld = FALSE;
+ }
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ if (fResendPkt)
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: Resend pkt on %lx.%lx\n",
+ pSpxConnFile, pSendResd->sr_SeqNum));
+
+ ++SpxDevice->dev_Stat.DataFramesResent;
+ ExInterlockedAddLargeStatistic(
+ &SpxDevice->dev_Stat.DataFrameBytesResent,
+ pSendResd->sr_Len - (SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE));
+ SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(TRUE);
+}
+
+
+
+
+VOID
+SpxConnProcessRenegReq(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN CTELockHandle lockHandle
+ )
+/*++
+
+Routine Description:
+
+ !!!MUST BE CALLED WITH THE CONNECTION LOCK HELD!!!
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ USHORT seqNum, ackNum, allocNum, maxPktSize;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt = NULL;
+
+ // The remote sent us a renegotiate request. We need to send an ack back
+ // ONLY if we have not acked a data packet with that same sequence number.
+ // This is guaranteed by the fact that we will not accept the reneg request
+ // if we have already acked a data packet with the same seq num, as our
+ // receive seq number would be incremented already.
+ //
+ // Note that if we have pending send packets we may end up doing a reneg
+ // also.
+
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+ GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
+ GETSHORT2SHORT(&maxPktSize, &pIpxSpxHdr->hdr_PktLen);
+
+ // If the received seq num is less than the expected receive sequence number
+ // we ignore this request.
+ if (!UNSIGNED_GREATER_WITH_WRAP(
+ seqNum,
+ pSpxConnFile->scf_RecvSeqNum) &&
+ (seqNum != pSpxConnFile->scf_RecvSeqNum))
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessRenegReq: %lx ERROR RENSEQ %lx RECVSEQ %lx %lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ return;
+ }
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessRenegReq: %lx RENSEQ %lx RECVSEQ %lx MAXPKT %lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum, maxPktSize));
+
+ // Set ack numbers for connection.
+ SPX_SET_ACKNUM(
+ pSpxConnFile, ackNum, allocNum);
+
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *pRemoteAddr;
+
+ // Set RenegAckAckNum before calling buildrrack. If a previous reneg
+ // request was received with a greater maxpktsize, send an ack with
+ // that maxpktsize.
+ if (!SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_RENEGRECD))
+ {
+ pSpxConnFile->scf_RenegAckAckNum = pSpxConnFile->scf_RecvSeqNum;
+ pSpxConnFile->scf_RenegMaxPktSize= maxPktSize;
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_RENEGRECD);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessRenegReq: %lx SENT ALLOC NUM CURRENT %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_SentAllocNum));
+
+ // Adjust sentallocnum now that recvseqnum might have moved up.
+ pSpxConnFile->scf_SentAllocNum +=
+ (seqNum - pSpxConnFile->scf_RenegAckAckNum);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessRenegReq: %lx SENT ALLOC NUM ADJUSTED %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_SentAllocNum));
+ }
+
+ // The recvseqnum for the reneg is always >= the renegackacknum.
+ pSpxConnFile->scf_RecvSeqNum = seqNum;
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessRenegReq: %lx RESET RECVSEQ %lx SavedACKACK %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_RecvSeqNum,
+ pSpxConnFile->scf_RenegAckAckNum));
+
+ // Build and send an ack.
+ SpxPktBuildRrAck(
+ pSpxConnFile,
+ &pPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
+ pSpxConnFile->scf_RenegMaxPktSize);
+
+ if (pPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+ }
+#if DBG
+ else
+ {
+ // Log error
+ DBGPRINT(SEND, ERR,
+ ("SpxConnSendRenegReqAck: Could not allocate!\n"));
+ }
+#endif
+
+
+ // Check if we are an ack/nack packet in which case call process
+ // ack. Note that the spx2 orderly release ack is a normal spx2 ack.
+ SpxConnProcessAck(pSpxConnFile, NULL, lockHandle);
+
+ if (pPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+
+ // Send the packet
+ SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxConnProcessOrdRel(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle lockHandle
+ )
+/*++
+
+Routine Description:
+
+ !!!MUST BE CALLED WITH THE CONNECTION LOCK HELD!!!
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PVOID pDiscHandlerCtx;
+ PTDI_IND_DISCONNECT pDiscHandler = NULL;
+ int numDerefs = 0;
+ PNDIS_PACKET pPkt = NULL;
+ BOOLEAN lockHeld = TRUE, fAbort = FALSE;
+
+ if (SPX_CONN_ACTIVE(pSpxConnFile))
+ {
+ if (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ORDREL_ACKED)
+ {
+ fAbort = TRUE;
+ }
+
+ // Send an ack if one was asked for. And we are done with this pkt
+ // Update seq numbers and stuff.
+ SPX_SET_RECVNUM(pSpxConnFile, FALSE);
+
+ // Build and send an ack for this. Ordinary spx2 ack.
+ SpxPktBuildAck(
+ pSpxConnFile,
+ &pPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY | SPX_SENDPKT_ABORT,
+ FALSE,
+ 0);
+
+ if (pPkt != NULL)
+ {
+ // We don't queue this pkt in as we have the ABORT flag set in
+ // the packet, which implies the pkt is already dequeued.
+ // SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+
+ // Reference conn for the pkt.
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+
+ // Get disconnect handler if we have one. And have not indicated
+ // abortive disconnect on this connection to afd.
+
+ //
+ // Bug #14354 - odisc and idisc cross each other, leading to double disc to AFD
+ //
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC) &&
+ !SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC))
+ {
+ // Yeah, we set the flag regardless of whether a handler is
+ // present.
+ pDiscHandler =pSpxConnFile->scf_AddrFile->saf_DiscHandler;
+ pDiscHandlerCtx=pSpxConnFile->scf_AddrFile->saf_DiscHandlerCtx;
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC);
+ }
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ // Indicate disconnect to afd.
+ if (pDiscHandler != NULL)
+ {
+ (*pDiscHandler)(
+ pDiscHandlerCtx,
+ pSpxConnFile->scf_ConnCtx,
+ 0, // Disc data
+ NULL,
+ 0, // Disc info
+ NULL,
+ TDI_DISCONNECT_RELEASE);
+ }
+
+ // We abort any receives here if !fAbort else we abort conn.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+
+ if (fAbort)
+ {
+ // Set IDISC flag so Abortive doesnt reindicate.
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_SUCCESS,
+ SPX_CALL_RECVLEVEL,
+ lockHandle,
+ FALSE); // [SA] bug #15249
+
+ lockHeld = FALSE;
+ }
+ else
+ {
+ // Go through and kill all pending requests.
+ spxConnAbortRecvs(
+ pSpxConnFile,
+ STATUS_REMOTE_DISCONNECT,
+ SPX_CALL_RECVLEVEL,
+ lockHandle);
+
+ lockHeld = FALSE;
+ }
+ }
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ if (pPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+
+ // Send the packet
+ SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxConnProcessIDisc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle lockHandle
+ )
+/*++
+
+Routine Description:
+
+ !!!MUST BE CALLED WITH THE CONNECTION LOCK HELD!!!
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt = NULL;
+
+ SPX_SET_RECVNUM(pSpxConnFile, FALSE);
+
+ // Build and send an ack for the idisc. Need to modify data type
+ // and reset sys bit on ack.
+ // BUG #12344 - Fixing this led to the problem where we queue in
+ // the pkt below, but AbortSends could already have been called
+ // => this packet stays on queue without a ref, conn gets freed
+ // underneath, and in the sendcomplete we crash when this send
+ // completes.
+ //
+ // Fix is to setup this pkt as a aborted pkt to start with.
+
+ SpxPktBuildAck(
+ pSpxConnFile,
+ &pPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY | SPX_SENDPKT_ABORT,
+ FALSE,
+ 0);
+
+ if (pPkt != NULL)
+ {
+ PIPXSPX_HDR pSendHdr;
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ pSendHdr->hdr_ConnCtrl &= ~SPX_CC_SYS;
+ pSendHdr->hdr_DataType = SPX2_DT_IDISC_ACK;
+
+ // We don't queue this pkt in as we have the ABORT flag set in
+ // the packet, which implies the pkt is already dequeued.
+ // SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+
+ // Reference conn for the pkt.
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+
+ // We better not have any received pkts, we ignore disconnect
+ // pkts when that happens.
+ CTEAssert(pSpxConnFile->scf_RecvListTail == NULL);
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+
+#if DBG
+ if (pSpxConnFile->scf_SendSeqListHead != NULL)
+ {
+ DBGPRINT(CONNECT, DBG1,
+ ("SpxConnDiscPacket: DATA/DISC %lx.%lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_SendListHead,
+ pSpxConnFile->scf_SendSeqListHead));
+ }
+#endif
+
+ // Call abortive disconnect on connection.
+
+ //
+ // [SA] bug #15249
+ // This is an informed disconnect, hence pass DISCONNECT_RELEASE to AFD (TRUE in last param)
+ //
+ //
+ // We pass true only in the case of an SPX connection. SPX2 connections follow the
+ // exact semantics of Informed Disconnect.
+ //
+ if (!SPX2_CONN(pSpxConnFile)) {
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_REMOTE_DISCONNECT,
+ SPX_CALL_RECVLEVEL,
+ lockHandle,
+ TRUE);
+ } else {
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_REMOTE_DISCONNECT,
+ SPX_CALL_RECVLEVEL,
+ lockHandle,
+ FALSE);
+ }
+
+ if (pPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+
+ // Send the packet
+ SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnResetSendQueue(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PREQUEST pRequest;
+ PNDIS_PACKET pPkt;
+
+ pSendResd = pSpxConnFile->scf_SendSeqListHead;
+ CTEAssert(pSendResd != NULL);
+
+ pRequest = pSendResd->sr_Request;
+
+ // Reset the current send request values
+ pSpxConnFile->scf_ReqPkt = pSendResd->sr_Request;
+ pSpxConnFile->scf_ReqPktOffset = pSendResd->sr_Offset;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DATA;
+
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ PTDI_REQUEST_KERNEL_SEND pParam;
+
+ pParam = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(pRequest);
+
+ DBGPRINT(SEND, DBG3,
+ ("spxConnResetSendQueue: %lx.%lx.%lx Reset SEND Req to %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_Flags, pSpxConnFile->scf_Flags2,
+ pRequest, pParam->SendLength));
+
+ // Set parameters in connection for another go. Size parameter is
+ // original size - offset at this point.
+ pSpxConnFile->scf_ReqPktFlags = pParam->SendFlags;
+ pSpxConnFile->scf_ReqPktSize = pParam->SendLength -
+ pSpxConnFile->scf_ReqPktOffset;
+ }
+ else
+ {
+ PTDI_REQUEST_KERNEL_DISCONNECT pParam;
+
+ DBGPRINT(SEND, ERR,
+ ("spxConnResetSendQueue: %lx.%lx.%lx Reset DISC Req to %lx\n",
+ pSpxConnFile, pSpxConnFile->scf_Flags, pSpxConnFile->scf_Flags2,
+ pRequest));
+
+ DBGPRINT(SEND, ERR,
+ ("spxConnResetSendQueue: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ pParam =
+ (PTDI_REQUEST_KERNEL_DISCONNECT)REQUEST_PARAMETERS(pRequest);
+
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pSpxConnFile->scf_ReqPktSize = 0;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DISC;
+ if (pParam->RequestFlags == TDI_DISCONNECT_RELEASE)
+ {
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_ORDREL;
+ }
+ }
+
+ DBGPRINT(SEND, DBG3,
+ ("spxConnResetSendQueue: Seq Num for %lx is now %lx\n",
+ pSpxConnFile, pSpxConnFile->scf_SendSeqNum));
+
+ // When we are trying to abort a pkt and it is in use by ipx, we simply let
+ // it float.
+ do
+ {
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_REQ) != 0);
+ pRequest = pSendResd->sr_Request;
+
+ CTEAssert(REQUEST_INFORMATION(pRequest) != 0);
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ if (--(REQUEST_INFORMATION(pRequest)) == 0)
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ KeBugCheck(0);
+ }
+
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // We let send completion know that this packet is to be aborted.
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+
+ } while ((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL);
+
+ return;
+}
+
+
+
+
+VOID
+spxConnAbortSendPkt(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_SEND_RESD pSendResd,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+ Called to abort either a sequenced or a non-sequenced packet ONLY from
+ send completion.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LIST_ENTRY ReqList, *p;
+ PREQUEST pRequest;
+ PNDIS_PACKET pPkt;
+ int numDerefs = 0;
+
+ InitializeListHead(&ReqList);
+
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ if ((pSendResd->sr_State & SPX_SENDPKT_REQ) != 0)
+ {
+ pRequest = pSendResd->sr_Request;
+
+ CTEAssert(REQUEST_INFORMATION(pRequest) != 0);
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0);
+ if (--(REQUEST_INFORMATION(pRequest)) == 0)
+ {
+ // Remove request from list its on
+ // BUG #11626 - request is already removed from list.
+ // RemoveEntryList(REQUEST_LINKAGE(pRequest));
+
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendAbort: QForComp Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (CallLevel == SPX_CALL_RECVLEVEL)
+ {
+ CTELockHandle lockHandleInter;
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_ReqDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // If connection is not already in recv queue, put it in
+ // there.
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ else
+ {
+ InsertTailList(
+ &ReqList,
+ REQUEST_LINKAGE(pRequest));
+ }
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Set the request in the connection, and deref for it.
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ numDerefs++;
+ }
+ }
+ }
+
+ // Release
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ SpxConnFileDereference(pSpxConnFile, CFREF_ABORTPKT);
+
+ if (!IsListEmpty(&ReqList))
+ {
+ p = RemoveHeadList(&ReqList);
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ SpxCompleteRequest(pRequest);
+ numDerefs++;
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnAbortSends(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LIST_ENTRY ReqList, *p;
+ PSPX_SEND_RESD pSendResd;
+ PREQUEST pRequest;
+ PNDIS_PACKET pPkt;
+ int numDerefs = 0;
+
+ InitializeListHead(&ReqList);
+
+ // We better be in disconnect state, abortive/informed/orderly initiate.
+ CTEAssert(SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN);
+
+ // Reset the current send request values
+ pSpxConnFile->scf_ReqPkt = NULL;
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pSpxConnFile->scf_ReqPktSize = 0;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DATA;
+
+ // First go through the non-seq pkt queue.Just set abort flag if owned by ipx
+ while ((pSendResd = pSpxConnFile->scf_SendListHead) != NULL)
+ {
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_REQ) == 0);
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // Set abort flag and reference conn for the pkt if its not already.
+ // We only do this check for the non-sequenced packets.
+ // BUG #12344 (see SpxRecvDiscPacket())
+ if ((pSendResd->sr_State & SPX_SENDPKT_ABORT) == 0)
+ {
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+ }
+ }
+
+ // When we are trying to abort a pkt and it is in use by ipx, we simply let
+ // it float.
+ while ((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL)
+ {
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_REQ) != 0);
+ pRequest = pSendResd->sr_Request;
+
+ CTEAssert(REQUEST_INFORMATION(pRequest) != 0);
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ if (--(REQUEST_INFORMATION(pRequest)) == 0)
+ {
+ // Remove request from list its on
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+
+ // Set status
+ REQUEST_STATUS(pRequest) = Status;
+ REQUEST_INFORMATION(pRequest) = 0;
+
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendAbort: QForComp Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (CallLevel == SPX_CALL_RECVLEVEL)
+ {
+ CTELockHandle lockHandleInter;
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_ReqDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // If connection is not already in recv queue, put it in
+ // there.
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ else
+ {
+ InsertTailList(
+ &ReqList,
+ REQUEST_LINKAGE(pRequest));
+ }
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Set the request in the connection, and deref for it.
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ numDerefs++;
+ }
+ }
+
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // We let send completion know that this packet is to be aborted.
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+ }
+
+ // If retry timer state is on, then we need to reset and deref.
+ if ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_IDLE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_PACKETIZE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_WD))
+ {
+ DBGPRINT(SEND, DBG1,
+ ("spxConnAbortSends: When SEND ERROR STATE %lx.%lx\n",
+ pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ numDerefs++;
+ }
+
+ // Remove creation references on all sends.
+ if (!IsListEmpty(&pSpxConnFile->scf_ReqLinkage))
+ {
+ p = pSpxConnFile->scf_ReqLinkage.Flink;
+ while (p != &pSpxConnFile->scf_ReqLinkage)
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ // Remove request from list its on. Its complete or abort list for it.
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+
+ // Set status
+ REQUEST_STATUS(pRequest) = Status;
+
+ DBGPRINT(SEND, DBG1,
+ ("SpxSendAbort: %lx Aborting Send Request %lx with %lx.%lx\n",
+ pSpxConnFile, pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (--(REQUEST_INFORMATION(pRequest)) == 0)
+ {
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendAbort: QForComp Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (CallLevel == SPX_CALL_RECVLEVEL)
+ {
+ CTELockHandle lockHandleInter;
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_ReqDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // If connection is not already in recv queue, put it in
+ // there.
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ else
+ {
+ InsertTailList(
+ &ReqList,
+ REQUEST_LINKAGE(pRequest));
+ }
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG1,
+ ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Set the request in the connection, and deref for it.
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ numDerefs++;
+ }
+ }
+#if DBG
+ else
+ {
+ // Let it float,
+ DBGPRINT(SEND, DBG1,
+ ("SpxSendAbort: %lx Floating Send %lx with %lx.%lx\n",
+ pSpxConnFile, pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+ }
+#endif
+ }
+ }
+
+ // Release
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ while (!IsListEmpty(&ReqList))
+ {
+ p = RemoveHeadList(&ReqList);
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ SpxCompleteRequest(pRequest);
+ numDerefs++;
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnAbortRecvs(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LIST_ENTRY ReqList, *p;
+ PREQUEST pRequest;
+ PSPX_RECV_RESD pRecvResd;
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+ PBYTE pData;
+ ULONG dataLen;
+ int numDerefs = 0;
+
+ InitializeListHead(&ReqList);
+
+ // We better be in disconnect state, abortive/informed/orderly initiate.
+ // Reset the current receive request values
+ pSpxConnFile->scf_CurRecvReq = NULL;
+ pSpxConnFile->scf_CurRecvOffset = 0;
+ pSpxConnFile->scf_CurRecvSize = 0;
+
+ // If we have any buffered data, abort it.
+ // Buffered data that is 0 bytes long (only eom) may not have a ndis
+ // buffer associated with it.
+ while ((pRecvResd = pSpxConnFile->scf_RecvListHead) != NULL)
+ {
+ if ((pSpxConnFile->scf_RecvListHead = pRecvResd->rr_Next) == NULL)
+ {
+ pSpxConnFile->scf_RecvListTail = NULL;
+ }
+
+ pNdisPkt = (PNDIS_PACKET)
+ CONTAINING_RECORD(pRecvResd, NDIS_PACKET, ProtocolReserved);
+
+ DBGPRINT(RECEIVE, DBG1,
+ ("spxConnAbortRecvs: %lx in bufferlist on %lx\n",
+ pSpxConnFile, pNdisPkt));
+
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ if (pNdisBuffer != NULL)
+ {
+ NdisQueryBuffer(pNdisBuffer, &pData, &dataLen);
+ CTEAssert(pData != NULL);
+ CTEAssert(dataLen >= 0);
+
+ SpxFreeMemory(pData);
+ NdisFreeBuffer(pNdisBuffer);
+ }
+
+ // Packet consumed. Free it up.
+ numDerefs++;
+
+ // Free the ndis packet
+ SpxPktRecvRelease(pNdisPkt);
+ }
+
+ // If packets are on this queue, they are waiting for transfer data to
+ // complete. Can't do much about that, just go and remove creation refs
+ // on the receives.
+ if (!IsListEmpty(&pSpxConnFile->scf_RecvLinkage))
+ {
+ p = pSpxConnFile->scf_RecvLinkage.Flink;
+ while (p != &pSpxConnFile->scf_RecvLinkage)
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ // Remove request from list its on
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+
+ // Set status
+ REQUEST_STATUS(pRequest) = Status;
+
+ DBGPRINT(RECEIVE, DBG1,
+ ("SpxRecvAbort: Aborting Recv Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (REQUEST_INFORMATION(pRequest) == 0)
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxRecvAbort: QForComp Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (CallLevel == SPX_CALL_RECVLEVEL)
+ {
+ CTELockHandle lockHandleInter;
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_RecvDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // If connection is not already in recv queue, put it in
+ // there.
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ else
+ {
+ InsertTailList(
+ &ReqList,
+ REQUEST_LINKAGE(pRequest));
+ }
+ }
+#if DBG
+ else
+ {
+ // Let it float,
+ DBGPRINT(SEND, DBG1,
+ ("SpxSendAbort: %lx Floating Send %lx with %lx.%lx\n",
+ pSpxConnFile, pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+ }
+#endif
+ }
+ }
+
+ // Release
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ while (!IsListEmpty(&ReqList))
+ {
+ p = RemoveHeadList(&ReqList);
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ numDerefs++;
+
+ SpxCompleteRequest(pRequest);
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+#if 0
+
+VOID
+spxConnResendPkts(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ USHORT startSeqNum;
+ BOOLEAN fLockHeld = TRUE, fDone = FALSE;
+
+ pSendResd = pSpxConnFile->scf_SendSeqListHead;
+ if (pSendResd)
+ {
+ startSeqNum = pSendResd->sr_SeqNum;
+ DBGPRINT(SEND, DBG,
+ ("spxConnResendPkts: StartSeqNum %lx for resend on %lx\n",
+ startSeqNum, pSpxConnFile));
+
+ while (spxConnGetPktBySeqNum(pSpxConnFile, startSeqNum++, &pPkt))
+ {
+ CTEAssert(pPkt != NULL);
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ if (!(pSendResd->sr_State & SPX_SENDPKT_IPXOWNS))
+ {
+ DBGPRINT(SEND, DBG,
+ ("spxConnResendPkts: Pkt %lx.%lx resent on %lx\n",
+ pPkt, (startSeqNum - 1), pSpxConnFile));
+
+ // We are going to send this packet
+ pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
+ SPX_SENDPKT_REXMIT);
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("spxConnResendPkts: Pkt %lx.%lx owned by ipx on %lx\n",
+ pPkt, (startSeqNum - 1), pSpxConnFile));
+ break;
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ fLockHeld = FALSE;
+
+ // If pkt has the ack bit set, we break.
+ fDone = ((pSendResd->sr_State & SPX_SENDPKT_ACKREQ) != 0);
+
+ // Send the packet
+ SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
+ if (fDone)
+ {
+ break;
+ }
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ fLockHeld = TRUE;
+ }
+ }
+
+ if (fLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ }
+
+ return;
+}
+#endif
diff --git a/private/ntos/tdi/isnp/spx/spxcutil.c b/private/ntos/tdi/isnp/spx/spxcutil.c
new file mode 100644
index 000000000..3f85b2281
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/spxcutil.c
@@ -0,0 +1,1738 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxcutil.c
+
+Abstract:
+
+ This module contains code which implements the CONNECTION object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport connection objects.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 5-July-1995
+ Bug fixes - tagged [SA]
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+// Define module number for event logging entries
+#define FILENUM SPXCUTIL
+
+//
+// Minor utility routines
+//
+
+
+BOOLEAN
+spxConnCheckNegSize(
+ IN PUSHORT pNegSize
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ int i;
+
+ // We go thru table and see if this is the minimum size or if it
+ // can go down further. Return true if it is not the minimum size.
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnCheckNegSize: Current %lx Check Val %lx\n",
+ (ULONG)(*pNegSize - MIN_IPXSPX2_HDRSIZE),
+ SpxMaxPktSize[0]));
+
+ if ((ULONG)(*pNegSize - MIN_IPXSPX2_HDRSIZE) <= SpxMaxPktSize[0])
+ return(FALSE);
+
+ for (i = SpxMaxPktSizeIndex-1; i > 0; i--)
+ {
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnCheckNegSize: Current %lx Check Val %lx\n",
+ (ULONG)(*pNegSize - MIN_IPXSPX2_HDRSIZE),
+ SpxMaxPktSize[i]));
+
+ if (SpxMaxPktSize[i] < (ULONG)(*pNegSize - MIN_IPXSPX2_HDRSIZE))
+ break;
+ }
+
+ *pNegSize = (USHORT)(SpxMaxPktSize[i] + MIN_IPXSPX2_HDRSIZE);
+
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnCheckNegSize: Trying Size %lx Min size possible %lx\n",
+ *pNegSize, SpxMaxPktSize[0] + MIN_IPXSPX2_HDRSIZE));
+
+ return(TRUE);
+}
+
+
+
+
+VOID
+spxConnSetNegSize(
+ IN OUT PNDIS_PACKET pPkt,
+ IN ULONG Size
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_BUFFER pNdisBuffer;
+ UINT bufCount;
+ PSPX_SEND_RESD pSendResd;
+ PIPXSPX_HDR pIpxSpxHdr;
+
+ CTEAssert(Size > 0);
+ NdisQueryPacket(pPkt, NULL, &bufCount, &pNdisBuffer, NULL);
+ CTEAssert (bufCount == 3);
+
+ NdisGetNextBuffer(pNdisBuffer, &pNdisBuffer);
+ NdisGetNextBuffer(pNdisBuffer, &pNdisBuffer);
+ NdisAdjustBufferLength(pNdisBuffer, Size);
+
+ // Change it in send reserved
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Len = (Size + MIN_IPXSPX2_HDRSIZE);
+
+ // Change in ipx header
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ PUTSHORT2SHORT((PUSHORT)&pIpxSpxHdr->hdr_PktLen, (Size + MIN_IPXSPX2_HDRSIZE));
+
+ // Change in the neg packet field of the header.
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ (Size + MIN_IPXSPX2_HDRSIZE));
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnSetNegSize: Setting size to %lx Hdr %lx\n",
+ Size, (Size + MIN_IPXSPX2_HDRSIZE)));
+
+ return;
+}
+
+
+
+
+BOOLEAN
+SpxConnDequeueSendPktLock(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PNDIS_PACKET pPkt
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSr, pListHead, pListTail;
+ PSPX_SEND_RESD pSendResd;
+ BOOLEAN removed = TRUE;
+
+ // If we are sequenced or not decides which list we choose.
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ if ((pSendResd->sr_State & SPX_SENDPKT_SEQ) != 0)
+ {
+ pListHead = pSpxConnFile->scf_SendSeqListHead;
+ pListTail = pSpxConnFile->scf_SendSeqListTail;
+ }
+ else
+ {
+ pListHead = pSpxConnFile->scf_SendListHead;
+ pListTail = pSpxConnFile->scf_SendListTail;
+ }
+
+ // Most often, we will be at the head of the list.
+ if (pListHead == pSendResd)
+ {
+ if ((pListHead = pSendResd->sr_Next) == NULL)
+ {
+ DBGPRINT(SEND, INFO,
+ ("SpxConnDequeuePktLock: %lx first in list\n", pSendResd));
+
+ pListTail = NULL;
+ }
+ }
+ else
+ {
+ DBGPRINT(SEND, INFO,
+ ("SpxConnDequeuePktLock: %lx !first in list\n", pSendResd));
+
+ pSr = pListHead;
+ while (pSr != NULL)
+ {
+ if (pSr->sr_Next == pSendResd)
+ {
+ if ((pSr->sr_Next = pSendResd->sr_Next) == NULL)
+ {
+ pListTail = pSr;
+ }
+
+ break;
+ }
+
+ pSr = pSr->sr_Next;
+ }
+
+ if (pSr == NULL)
+ removed = FALSE;
+ }
+
+ if (removed)
+ {
+ if ((pSendResd->sr_State & SPX_SENDPKT_SEQ) != 0)
+ {
+ pSpxConnFile->scf_SendSeqListHead = pListHead;
+ pSpxConnFile->scf_SendSeqListTail = pListTail;
+ }
+ else
+ {
+ pSpxConnFile->scf_SendListHead = pListHead;
+ pSpxConnFile->scf_SendListTail = pListTail;
+ }
+ }
+
+ return(removed);
+}
+
+
+
+
+BOOLEAN
+SpxConnDequeueRecvPktLock(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PNDIS_PACKET pPkt
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_RECV_RESD pSr, pListHead, pListTail;
+ PSPX_RECV_RESD pRecvResd;
+ BOOLEAN removed = TRUE;
+
+ pRecvResd = (PSPX_RECV_RESD)(pPkt->ProtocolReserved);
+ pListHead = pSpxConnFile->scf_RecvListHead;
+ pListTail = pSpxConnFile->scf_RecvListTail;
+
+ // Most often, we will be at the head of the list.
+ if (pListHead == pRecvResd)
+ {
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnDequeuePktLock: %lx first in list\n", pRecvResd));
+
+ if ((pListHead = pRecvResd->rr_Next) == NULL)
+ {
+ pListTail = NULL;
+ }
+ }
+ else
+ {
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnDequeuePktLock: %lx !first in list\n", pRecvResd));
+
+ pSr = pListHead;
+ while (pSr != NULL)
+ {
+ if (pSr->rr_Next == pRecvResd)
+ {
+ if ((pSr->rr_Next = pRecvResd->rr_Next) == NULL)
+ {
+ pListTail = pSr;
+ }
+
+ break;
+ }
+
+ pSr = pSr->rr_Next;
+ }
+
+ if (pSr == NULL)
+ removed = FALSE;
+ }
+
+ if (removed)
+ {
+ pSpxConnFile->scf_RecvListHead = pListHead;
+ pSpxConnFile->scf_RecvListTail = pListTail;
+ }
+
+ return(removed);
+}
+
+
+
+
+BOOLEAN
+spxConnGetPktByType(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN ULONG PktType,
+ IN BOOLEAN fSeqList,
+ IN PNDIS_PACKET * ppPkt
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSr, *ppSr;
+
+ // Most often, we will be at the head of the list.
+ ppSr = (fSeqList ?
+ &pSpxConnFile->scf_SendSeqListHead :
+ &pSpxConnFile->scf_SendListHead);
+
+ for (; (pSr = *ppSr) != NULL; )
+ {
+ if (pSr->sr_Type == PktType)
+ {
+ *ppPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSr, NDIS_PACKET, ProtocolReserved);
+
+ DBGPRINT(SEND, INFO,
+ ("SpxConnFindByType: %lx.%lx.%d\n", pSr,*ppPkt, fSeqList));
+
+ break;
+ }
+
+ ppSr = &pSr->sr_Next;
+ }
+
+ return(pSr != NULL);
+}
+
+
+
+
+BOOLEAN
+spxConnGetPktBySeqNum(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN USHORT SeqNum,
+ IN PNDIS_PACKET * ppPkt
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSr, *ppSr;
+
+ // Most often, we will be at the head of the list.
+ ppSr = &pSpxConnFile->scf_SendSeqListHead;
+ for (; (pSr = *ppSr) != NULL; )
+ {
+ if (pSr->sr_SeqNum == SeqNum)
+ {
+ *ppPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSr, NDIS_PACKET, ProtocolReserved);
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnFindBySeq: %lx.%lx.%d\n", pSr,*ppPkt, SeqNum));
+
+ break;
+ }
+
+ ppSr = &pSr->sr_Next;
+ }
+
+ return(pSr != NULL);
+}
+
+
+
+
+USHORT
+spxConnGetId(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This must be called with the device lock held.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pSpxConnFile;
+ BOOLEAN wrapped = FALSE;
+ USHORT startConnId, retConnId;
+
+ startConnId = SpxDevice->dev_NextConnId;
+
+ // Search the global active list.
+ do
+ {
+ if ((SpxDevice->dev_NextConnId >= startConnId) && wrapped)
+ {
+ retConnId = 0;
+ break;
+ }
+
+ if (SpxDevice->dev_NextConnId == 0xFFFF)
+ {
+ wrapped = TRUE;
+ SpxDevice->dev_NextConnId = 1;
+ continue;
+ }
+
+ // BUGBUG: Later this be a tree.
+ for (pSpxConnFile = SpxDevice->dev_GlobalActiveConnList[
+ SpxDevice->dev_NextConnId & NUM_SPXCONN_HASH_MASK];
+ pSpxConnFile != NULL;
+ pSpxConnFile = pSpxConnFile->scf_GlobalActiveNext)
+ {
+ if (pSpxConnFile->scf_LocalConnId == SpxDevice->dev_NextConnId)
+ {
+ break;
+ }
+ }
+
+ // Increment for next time.
+ retConnId = SpxDevice->dev_NextConnId++;
+
+ // Ensure we are still legal. We could return if connfile is null.
+ if (SpxDevice->dev_NextConnId == 0xFFFF)
+ {
+ wrapped = TRUE;
+ SpxDevice->dev_NextConnId = 1;
+ }
+
+ if (pSpxConnFile != NULL)
+ {
+ continue;
+ }
+
+ break;
+
+ } while (TRUE);
+
+ return(retConnId);
+}
+
+
+
+
+NTSTATUS
+spxConnRemoveFromList(
+ IN PSPX_CONN_FILE * ppConnListHead,
+ IN PSPX_CONN_FILE pConnRemove
+ )
+
+/*++
+
+Routine Description:
+
+ This routine must be called with the address lock (and the lock of the remove
+ connection will usually also be, but is not needed) held.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pRemConn, *ppRemConn;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ // Dequeue the connection file from the address list. It must be
+ // in the inactive list.
+ for (ppRemConn = ppConnListHead;
+ (pRemConn = *ppRemConn) != NULL;)
+ {
+ if (pRemConn == pConnRemove)
+ {
+ *ppRemConn = pRemConn->scf_Next;
+ break;
+ }
+
+ ppRemConn = &pRemConn->scf_Next;
+ }
+
+ if (pRemConn == NULL)
+ {
+ DBGBRK(FATAL);
+ CTEAssert(0);
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+spxConnRemoveFromAssocList(
+ IN PSPX_CONN_FILE * ppConnListHead,
+ IN PSPX_CONN_FILE pConnRemove
+ )
+
+/*++
+
+Routine Description:
+
+ This routine must be called with the address lock (and the lock of the remove
+ connection will usually also be, but is not needed) held.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pRemConn, *ppRemConn;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ // Dequeue the connection file from the address list. It must be
+ // in the inactive list.
+ for (ppRemConn = ppConnListHead;
+ (pRemConn = *ppRemConn) != NULL;)
+ {
+ if (pRemConn == pConnRemove)
+ {
+ *ppRemConn = pRemConn->scf_AssocNext;
+ break;
+ }
+
+ ppRemConn = &pRemConn->scf_AssocNext;
+ }
+
+ if (pRemConn == NULL)
+ {
+ CTEAssert(0);
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ return(status);
+}
+
+
+
+
+VOID
+spxConnInsertIntoGlobalActiveList(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine must be called with the device lock held.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ int index = (int)(pSpxConnFile->scf_LocalConnId &
+ NUM_SPXCONN_HASH_MASK);
+
+ // For now, its just a linear list.
+ pSpxConnFile->scf_GlobalActiveNext =
+ SpxDevice->dev_GlobalActiveConnList[index];
+
+ SpxDevice->dev_GlobalActiveConnList[index] =
+ pSpxConnFile;
+
+ return;
+}
+
+
+
+
+NTSTATUS
+spxConnRemoveFromGlobalActiveList(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine must be called with the device lock held.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PSPX_CONN_FILE pC, *ppC;
+ int index = (int)(pSpxConnFile->scf_LocalConnId &
+ NUM_SPXCONN_HASH_MASK);
+ NTSTATUS status = STATUS_SUCCESS;
+
+ // For now, its just a linear list.
+ for (ppC = &SpxDevice->dev_GlobalActiveConnList[index];
+ (pC = *ppC) != NULL;)
+ {
+ if (pC == pSpxConnFile)
+ {
+ DBGPRINT(SEND, INFO,
+ ("SpxConnRemoveFromGlobal: %lx\n", pSpxConnFile));
+
+ // Remove from list
+ *ppC = pC->scf_GlobalActiveNext;
+ break;
+ }
+
+ ppC = &pC->scf_GlobalActiveNext;
+ }
+
+ if (pC == NULL)
+ status = STATUS_INVALID_CONNECTION;
+
+ return(status);
+}
+
+
+
+
+VOID
+spxConnInsertIntoGlobalList(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ pSpxConnFile->scf_GlobalNext = SpxGlobalConnList;
+ SpxGlobalConnList = pSpxConnFile;
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+
+ return;
+}
+
+
+
+
+NTSTATUS
+spxConnRemoveFromGlobalList(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+ PSPX_CONN_FILE pC, *ppC;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ for (ppC = &SpxGlobalConnList;
+ (pC = *ppC) != NULL;)
+ {
+ if (pC == pSpxConnFile)
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxConnRemoveFromGlobal: %lx\n", pSpxConnFile));
+
+ // Remove from list
+ *ppC = pC->scf_GlobalNext;
+ break;
+ }
+
+ ppC = &pC->scf_GlobalNext;
+ }
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+
+ if (pC == NULL)
+ status = STATUS_INVALID_CONNECTION;
+
+ return(status);
+}
+
+
+
+
+
+
+#if 0
+
+VOID
+spxConnPushIntoPktList(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ !!!MACROIZE!!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ pSpxConnFile->scf_PktNext = SpxPktConnList;
+ SpxPktConnList = pSpxConnFile;
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+
+ return;
+}
+
+
+
+
+VOID
+spxConnPopFromPktList(
+ IN PSPX_CONN_FILE * ppSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ !!!MACROIZE!!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ if ((*ppSpxConnFile = SpxPktConnList) != NULL)
+ {
+ SpxPktConnList = SpxPktConnList->scf_PktNext;
+ DBGPRINT(SEND, DBG,
+ ("SpxConnRemoveFromPkt: %lx\n", *ppSpxConnFile));
+ }
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+ return;
+}
+
+
+
+
+VOID
+spxConnPushIntoRecvList(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ !!!MACROIZE!!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ pSpxConnFile->scf_ProcessRecvNext = SpxRecvConnList;
+ SpxRecvConnList = pSpxConnFile;
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+
+ return;
+}
+
+
+
+
+VOID
+spxConnPopFromRecvList(
+ IN PSPX_CONN_FILE * ppSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ !!!MACROIZE!!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ if ((*ppSpxConnFile = SpxRecvConnList) != NULL)
+ {
+ SpxRecvConnList = SpxRecvConnList->scf_ProcessRecvNext;
+ DBGPRINT(SEND, INFO,
+ ("SpxConnRemoveFromRecv: %lx\n", *ppSpxConnFile));
+ }
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+ return;
+}
+
+#endif
+
+
+//
+// Reference/Dereference routines
+//
+
+
+#if DBG
+
+VOID
+SpxConnFileRef(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (pSpxConnFile->scf_RefCount >= 0); // not perfect, but...
+
+ (VOID)SPX_ADD_ULONG (
+ &pSpxConnFile->scf_RefCount,
+ 1,
+ &pSpxConnFile->scf_Lock);
+
+} // SpxRefConnectionFile
+
+
+
+
+VOID
+SpxConnFileLockRef(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+ IT IS CALLED WITH THE CONNECTION LOCK HELD.
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (pSpxConnFile->scf_RefCount >= 0); // not perfect, but...
+
+ (VOID)SPX_ADD_ULONG (
+ &pSpxConnFile->scf_RefCount,
+ 1,
+ &pSpxConnFile->scf_Lock);
+
+} // SpxRefConnectionFileLock
+
+#endif
+
+
+
+
+VOID
+SpxConnFileRefByIdLock (
+ IN USHORT ConnId,
+ OUT PSPX_CONN_FILE * ppSpxConnFile,
+ OUT PNTSTATUS pStatus
+ )
+
+/*++
+
+Routine Description:
+
+ !!!MUST BE CALLED WITH THE DEVICE LOCK HELD!!!
+
+ All active connections should be on the device active list. Later,
+ this data structure will be a tree, caching the last accessed
+ connection.
+
+Arguments:
+
+
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_CONNECTION otherwise
+
+--*/
+{
+ PSPX_CONN_FILE pSpxChkConn;
+
+ *pStatus = STATUS_SUCCESS;
+
+ for (pSpxChkConn =
+ SpxDevice->dev_GlobalActiveConnList[ConnId & NUM_SPXCONN_HASH_MASK];
+ pSpxChkConn != NULL;
+ pSpxChkConn = pSpxChkConn->scf_GlobalActiveNext)
+ {
+ if (pSpxChkConn->scf_LocalConnId == ConnId)
+ {
+ SpxConnFileReference(pSpxChkConn, CFREF_BYID);
+ *ppSpxConnFile = pSpxChkConn;
+ break;
+ }
+ }
+
+ if (pSpxChkConn == NULL)
+ {
+ *pStatus = STATUS_INVALID_CONNECTION;
+ }
+
+ return;
+
+}
+
+
+
+
+VOID
+SpxConnFileRefByCtxLock(
+ IN PSPX_ADDR_FILE pSpxAddrFile,
+ IN CONNECTION_CONTEXT Ctx,
+ OUT PSPX_CONN_FILE * ppSpxConnFile,
+ OUT PNTSTATUS pStatus
+ )
+/*++
+
+Routine Description:
+
+ !!!MUST BE CALLED WITH THE ADDRESS LOCK HELD!!!
+
+ Returns a referenced connection file with the associated context and
+ address file desired.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pSpxChkConn;
+
+ *pStatus = STATUS_SUCCESS;
+
+ for (pSpxChkConn = pSpxAddrFile->saf_Addr->sa_InactiveConnList;
+ pSpxChkConn != NULL;
+ pSpxChkConn = pSpxChkConn->scf_Next)
+ {
+ if ((pSpxChkConn->scf_ConnCtx == Ctx) &&
+ (pSpxChkConn->scf_AddrFile == pSpxAddrFile))
+ {
+ SpxConnFileReference(pSpxChkConn, CFREF_BYCTX);
+ *ppSpxConnFile = pSpxChkConn;
+ break;
+ }
+ }
+
+ if (pSpxChkConn == NULL)
+ {
+ *pStatus = STATUS_INVALID_CONNECTION;
+ }
+
+ return;
+}
+
+
+
+
+NTSTATUS
+SpxConnFileVerify (
+ IN PSPX_CONN_FILE pConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to verify that the pointer given us in a file
+ object is in fact a valid address file object. We also verify that the
+ address object pointed to by it is a valid address object, and reference
+ it to keep it from disappearing while we use it.
+
+Arguments:
+
+
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_CONNECTION otherwise
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ try
+ {
+ if ((pConnFile->scf_Size == sizeof (SPX_CONN_FILE)) &&
+ (pConnFile->scf_Type == SPX_CONNFILE_SIGNATURE))
+ {
+ CTEGetLock (&pConnFile->scf_Lock, &LockHandle);
+ if (!SPX_CONN_FLAG(pConnFile, SPX_CONNFILE_CLOSING))
+ {
+ SpxConnFileLockReference(pConnFile, CFREF_VERIFY);
+ }
+ else
+ {
+ DBGPRINT(TDI, ERR,
+ ("StVerifyConnFile: A %lx closing\n", pConnFile));
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+ CTEFreeLock (&pConnFile->scf_Lock, LockHandle);
+ }
+ else
+ {
+ DBGPRINT(TDI, ERR,
+ ("StVerifyAddressFile: AF %lx bad signature\n", pConnFile));
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DBGPRINT(TDI, ERR,
+ ("SpxVerifyConnFile: AF %lx exception\n", pConnFile));
+
+ return GetExceptionCode();
+ }
+
+ return status;
+
+} // SpxVerifyConnFile
+
+
+
+
+VOID
+SpxConnFileDeref(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences an address file by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ SpxDestroyConnectionFile to remove it from the system.
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+ BOOLEAN fDiscNotIndicated = FALSE;
+ BOOLEAN fIDiscFlag = FALSE;
+ BOOLEAN fSpx2;
+
+ CTEAssert(pSpxConnFile->scf_RefCount > 0);
+ oldvalue = SPX_ADD_ULONG (
+ &pSpxConnFile->scf_RefCount,
+ (ULONG)-1,
+ &pSpxConnFile->scf_Lock);
+
+ CTEAssert (oldvalue > 0);
+ if (oldvalue == 1)
+ {
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+ LIST_ENTRY discReqList, *p;
+ PREQUEST pDiscReq;
+ PSPX_ADDR_FILE pSpxAddrFile = NULL;
+ PREQUEST pCloseReq = NULL,
+ pCleanupReq = NULL,
+ pConnectReq = NULL;
+ BOOLEAN fDisassoc = FALSE;
+
+ InitializeListHead(&discReqList);
+
+ // We may not be associated at this point. Note: When we are active we
+ // always have a reference. So its not like we execute this code very often.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC))
+ {
+ pSpxAddrFile = pSpxConnFile->scf_AddrFile;
+ }
+ else
+ {
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_STOPPING))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Conn cleanup %lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_CleanupReq));
+
+ // Save this for later completion.
+ pCleanupReq = pSpxConnFile->scf_CleanupReq;
+ pSpxConnFile->scf_CleanupReq = NULL;
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_CLOSING))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Conn closing %lx\n",
+ pSpxConnFile));
+
+ // Save this for later completion.
+ pCloseReq = pSpxConnFile->scf_CloseReq;
+
+ //
+ // Null this out so on a re-entrant case, we dont try to complete this again.
+ //
+ pSpxConnFile->scf_CloseReq = NULL;
+ CTEAssert(pCloseReq != NULL);
+ }
+ }
+ CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandleConn);
+
+ if (pSpxAddrFile)
+ {
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ //if (pSpxConnFile->scf_RefCount == 0)
+
+ //
+ // ** The lock passed here is a dummy - it is pre-compiled out.
+ //
+ if (SPX_ADD_ULONG(&pSpxConnFile->scf_RefCount, 0, &pSpxConnFile->scf_Lock) == 0)
+ {
+ DBGPRINT(TDI, INFO,
+ ("SpxDerefConnectionFile: Conn is 0 %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_Flags));
+
+ // All pending requests on this connection are done. See if we
+ // need to complete the disconnect phase etc.
+ switch (SPX_MAIN_STATE(pSpxConnFile))
+ {
+ case SPX_CONNFILE_DISCONN:
+
+ // Disconnect is done. Move connection out of all the lists
+ // it is on, reset states etc.
+ DBGPRINT(TDI, INFO,
+ ("SpxDerefConnectionFile: Conn being inactivated %lx\n",
+ pSpxConnFile));
+
+ // Time to complete disc requests if present.
+ // There could be multiple of them.
+ p = pSpxConnFile->scf_DiscLinkage.Flink;
+ while (p != &pSpxConnFile->scf_DiscLinkage)
+ {
+ pDiscReq = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Disc on %lx.%lx\n",
+ pSpxConnFile, pDiscReq));
+
+ RemoveEntryList(REQUEST_LINKAGE(pDiscReq));
+
+ // Make sure Stacy is always wearing a particular
+ // kind of dress if she isn't already.
+ if (REQUEST_STATUS(pDiscReq) == STATUS_PENDING)
+ {
+ REQUEST_STATUS(pDiscReq) = STATUS_SUCCESS;
+ }
+
+ InsertTailList(
+ &discReqList,
+ REQUEST_LINKAGE(pDiscReq));
+ }
+
+ //
+ // Note the state here, and check after the conn has been inactivated.
+ //
+
+ //
+ // Bug #14354 - odisc and idisc cross each other, leading to double disc to AFD
+ //
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC) &&
+ !SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC)) {
+ fDiscNotIndicated = TRUE;
+ }
+
+ if (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IDISC)) {
+ fIDiscFlag = TRUE;
+ }
+
+ fSpx2 = (SPX2_CONN(pSpxConnFile)) ? TRUE : FALSE;
+
+ //
+ // [SA] Bug #14655
+ // Do not try to inactivate an already inactivated connection
+ //
+
+ if (!(SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED)) {
+ spxConnInactivate(pSpxConnFile);
+ } else {
+ //
+ // This is an SPXI connection which has got the local disconnect.
+ // Reset the flags now.
+ //
+ CTEAssert(!fDiscNotIndicated);
+
+ SPX_MAIN_SETSTATE(pSpxConnFile, 0);
+ SPX_DISC_SETSTATE(pSpxConnFile, 0);
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
+ }
+
+ //
+ // [SA] If we were waiting for sends to be aborted and did not indicate this
+ // disconnect to AFD; and AFD did not call a disconnect on this connection,
+ // then call the disonnect handler now.
+ //
+ if (fDiscNotIndicated) {
+ PVOID pDiscHandlerCtx;
+ PTDI_IND_DISCONNECT pDiscHandler = NULL;
+ ULONG discCode = 0;
+
+ pDiscHandler = pSpxConnFile->scf_AddrFile->saf_DiscHandler;
+ pDiscHandlerCtx = pSpxConnFile->scf_AddrFile->saf_DiscHandlerCtx;
+
+ // Indicate disconnect to afd.
+ if (pDiscHandler != NULL) {
+
+ //
+ // If this was an SPXI connection, the disconnect state is still
+ // DISCONN, so if this routine is re-entered, we need to prevent
+ // a re-indicate to AFD.
+ // Also, we need to wait for a local disconnect from AFD since
+ // we indicated a TDI_DISCONNECT_RELEASE. We bump up the ref count
+ // in this case.
+ //
+ if (!fSpx2) {
+ CTEAssert( (SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED) );
+
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
+
+ if (fIDiscFlag) {
+ SpxConnFileLockReference(pSpxConnFile, CFREF_DISCWAITSPX);
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_DISC_WAIT);
+ }
+ }
+
+ CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock (pSpxAddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock (&SpxDevice->dev_Lock, lockHandleDev);
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxDerefConnectionFile: Indicating to afd On %lx when %lx\n",
+ pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ // First complete all requests waiting for receive completion on
+ // this conn before indicating disconnect.
+ spxConnCompletePended(pSpxConnFile);
+
+ if (fIDiscFlag) {
+ //
+ // Indicate DISCONNECT_RELEASE to AFD so it allows receive of packets
+ // it has buffered before the remote disconnect took place.
+ //
+ discCode = TDI_DISCONNECT_RELEASE;
+ } else {
+ //
+ // [SA] bug #15249
+ // If not Informed disconnect, indicate DISCONNECT_ABORT to AFD
+ //
+ discCode = TDI_DISCONNECT_ABORT;
+ }
+
+ (*pDiscHandler)(
+ pDiscHandlerCtx,
+ pSpxConnFile->scf_ConnCtx,
+ 0, // Disc data
+ NULL,
+ 0, // Disc info
+ NULL,
+ discCode);
+
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ }
+ }
+
+ --SpxDevice->dev_Stat.OpenConnections;
+
+ break;
+
+ case SPX_CONNFILE_CONNECTING:
+ case SPX_CONNFILE_LISTENING:
+
+ // Get connect/accept request if present.
+ pConnectReq = pSpxConnFile->scf_ConnectReq;
+ pSpxConnFile->scf_ConnectReq = NULL;
+
+ spxConnInactivate(pSpxConnFile);
+ break;
+
+ case SPX_CONNFILE_ACTIVE:
+
+ KeBugCheck(0);
+
+ default:
+
+ CTEAssert(SPX_MAIN_STATE(pSpxConnFile) == 0);
+ break;
+ }
+
+ // If stopping, disassociate from the address file. Complete
+ // cleanup request.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_STOPPING))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Conn cleanup %lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_CleanupReq));
+
+ // Save this for later completion.
+ pCleanupReq = pSpxConnFile->scf_CleanupReq;
+ pSpxConnFile->scf_CleanupReq = NULL;
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_STOPPING);
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC))
+ {
+ DBGPRINT(TDI, INFO,
+ ("SpxDerefConnectionFile: Conn stopping %lx\n",
+ pSpxConnFile));
+
+ pSpxAddrFile = pSpxConnFile->scf_AddrFile;
+ SPX_CONN_RESETFLAG(pSpxConnFile,SPX_CONNFILE_ASSOC);
+
+ // Dequeue the connection from the address file
+ spxConnRemoveFromAssocList(
+ &pSpxAddrFile->saf_AssocConnList,
+ pSpxConnFile);
+
+ // Dequeue the connection file from the address list. It must
+ // be in the inactive list.
+ spxConnRemoveFromList(
+ &pSpxAddrFile->saf_Addr->sa_InactiveConnList,
+ pSpxConnFile);
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxConnDerefDisAssociate: %lx from addr file %lx\n",
+ pSpxConnFile, pSpxAddrFile));
+
+ fDisassoc = TRUE;
+ }
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_CLOSING))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Conn closing %lx\n",
+ pSpxConnFile));
+
+ // Save this for later completion.
+ pCloseReq = pSpxConnFile->scf_CloseReq;
+
+ //
+ // Null this out so on a re-entrant case, we dont try to complete this again.
+ //
+ pSpxConnFile->scf_CloseReq = NULL;
+ CTEAssert(pCloseReq != NULL);
+ }
+
+ CTEAssert(IsListEmpty(&pSpxConnFile->scf_ReqLinkage));
+ CTEAssert(IsListEmpty(&pSpxConnFile->scf_RecvLinkage));
+ CTEAssert(IsListEmpty(&pSpxConnFile->scf_DiscLinkage));
+ }
+ CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock (pSpxAddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock (&SpxDevice->dev_Lock, lockHandleDev);
+ }
+
+ if (fDisassoc)
+ {
+ // Remove reference on address for this association.
+ SpxAddrFileDereference(pSpxAddrFile, AFREF_CONN_ASSOC);
+ }
+
+ if (pConnectReq != (PREQUEST)NULL)
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Connect on %lx req %lx\n",
+ pSpxConnFile, pConnectReq));
+
+ // Status will already be set in here. We should be here only if
+ // connect is being aborted.
+ SpxCompleteRequest(pConnectReq);
+ }
+
+ while (!IsListEmpty(&discReqList))
+ {
+ p = RemoveHeadList(&discReqList);
+ pDiscReq = LIST_ENTRY_TO_REQUEST(p);
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnFileDeref: DISC REQ %lx.%lx Completing\n",
+ pSpxConnFile, pDiscReq));
+
+ SpxCompleteRequest(pDiscReq);
+ }
+
+ if (pCleanupReq != (PREQUEST)NULL)
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Cleanup complete %lx req %lx\n",
+ pSpxConnFile, pCleanupReq));
+
+ REQUEST_INFORMATION(pCleanupReq) = 0;
+ REQUEST_STATUS(pCleanupReq) = STATUS_SUCCESS;
+ SpxCompleteRequest (pCleanupReq);
+ }
+
+ if (pCloseReq != (PREQUEST)NULL)
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Freed %lx close req %lx\n",
+ pSpxConnFile, pCloseReq));
+
+ CTEAssert(pSpxConnFile->scf_RefCount == 0);
+
+ // Remove from the global list
+ if (!NT_SUCCESS(spxConnRemoveFromGlobalList(pSpxConnFile)))
+ {
+ KeBugCheck(0);
+ }
+
+ // Free it up.
+ SpxFreeMemory (pSpxConnFile);
+
+ REQUEST_INFORMATION(pCloseReq) = 0;
+ REQUEST_STATUS(pCloseReq) = STATUS_SUCCESS;
+ SpxCompleteRequest (pCloseReq);
+ }
+ }
+
+ return;
+
+} // SpxDerefConnectionFile
+
+
+
+
+VOID
+spxConnReInit(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ // Reinit all variables.
+ pSpxConnFile->scf_Flags2 = 0;
+
+ pSpxConnFile->scf_GlobalActiveNext = NULL;
+ pSpxConnFile->scf_PktNext = NULL;
+ pSpxConnFile->scf_CRetryCount = 0;
+ pSpxConnFile->scf_WRetryCount = 0;
+ pSpxConnFile->scf_RRetryCount = 0;
+ pSpxConnFile->scf_RRetrySeqNum = 0;
+
+ pSpxConnFile->scf_CTimerId =
+ pSpxConnFile->scf_RTimerId =
+ pSpxConnFile->scf_WTimerId =
+ pSpxConnFile->scf_TTimerId =
+ pSpxConnFile->scf_ATimerId = 0;
+
+ pSpxConnFile->scf_LocalConnId =
+ pSpxConnFile->scf_SendSeqNum =
+ pSpxConnFile->scf_SentAllocNum =
+ pSpxConnFile->scf_RecvSeqNum =
+ pSpxConnFile->scf_RetrySeqNum =
+ pSpxConnFile->scf_RecdAckNum =
+ pSpxConnFile->scf_RemConnId =
+ pSpxConnFile->scf_RecdAllocNum = 0;
+
+#if DBG
+ // Initialize so we dont hit breakpoint on seq 0
+ pSpxConnFile->scf_PktSeqNum = 0xFFFF;
+#endif
+
+ pSpxConnFile->scf_DataType = 0;
+
+ CTEAssert(IsListEmpty(&pSpxConnFile->scf_ReqLinkage));
+ CTEAssert(IsListEmpty(&pSpxConnFile->scf_DiscLinkage));
+ CTEAssert(IsListEmpty(&pSpxConnFile->scf_RecvLinkage));
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+ CTEAssert(pSpxConnFile->scf_RecvListTail == NULL);
+ CTEAssert(pSpxConnFile->scf_SendListHead == NULL);
+ CTEAssert(pSpxConnFile->scf_SendListTail == NULL);
+ CTEAssert(pSpxConnFile->scf_SendSeqListHead == NULL);
+ CTEAssert(pSpxConnFile->scf_SendSeqListTail == NULL);
+ pSpxConnFile->scf_CurRecvReq = NULL;
+ pSpxConnFile->scf_CurRecvOffset = 0;
+ pSpxConnFile->scf_CurRecvSize = 0;
+
+ pSpxConnFile->scf_ReqPkt = NULL;
+
+ return;
+}
+
+
+
+
+VOID
+spxConnInactivate(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+ !!! Called with dev/addr/connection lock held !!!
+
+Arguments:
+
+ This gets us back to associate SAVING the state of the STOPPING and
+ CLOSING flags so that dereference can go ahead and finish those.
+
+Return Value:
+
+
+--*/
+{
+ BOOLEAN fStopping, fClosing, fAborting;
+
+ fStopping = SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_STOPPING);
+ fClosing = SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_CLOSING);
+
+ //
+ // [SA] Bug #14655
+ // Save the disconnect states so that a proper error can be given in the case of
+ // a send after a remote disconnection.
+ //
+
+ //
+ // Bug #17729
+ // Dont retain these flags if a local disconnect has already occured.
+ //
+
+ fAborting = (!SPX2_CONN(pSpxConnFile) &&
+ !SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC) &&
+ (SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT));
+
+#if DBG
+ pSpxConnFile->scf_GhostFlags = pSpxConnFile->scf_Flags;
+ pSpxConnFile->scf_GhostFlags2 = pSpxConnFile->scf_Flags2;
+ pSpxConnFile->scf_GhostRefCount = pSpxConnFile->scf_RefCount;
+#endif
+
+ // Clear all flags, go back to the assoc state. Restore stop/close
+ pSpxConnFile->scf_Flags = SPX_CONNFILE_ASSOC;
+ SPX_CONN_SETFLAG(pSpxConnFile,
+ ((fStopping ? SPX_CONNFILE_STOPPING : 0) |
+ (fClosing ? SPX_CONNFILE_CLOSING : 0)));
+
+ //
+ // [SA] bug #14655
+ // In order to avoid a re-entry, mark connection as SPX_DISC_INACTIVATED
+ //
+ if (fAborting)
+ {
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_DISCONN);
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_INACTIVATED);
+ }
+
+ // Remove connection from global list on device
+ if (!NT_SUCCESS(spxConnRemoveFromGlobalActiveList(
+ pSpxConnFile)))
+ {
+ KeBugCheck(0);
+ }
+
+ // Remove connection from active list on address
+ if (!NT_SUCCESS(spxConnRemoveFromList(
+ &pSpxConnFile->scf_AddrFile->saf_Addr->sa_ActiveConnList,
+ pSpxConnFile)))
+ {
+ KeBugCheck(0);
+ }
+
+ // Put connection in inactive list on address
+ SPX_INSERT_ADDR_INACTIVE(
+ pSpxConnFile->scf_AddrFile->saf_Addr,
+ pSpxConnFile);
+
+ spxConnReInit(pSpxConnFile);
+ return;
+}
diff --git a/private/ntos/tdi/isnp/spx/spxdev.c b/private/ntos/tdi/isnp/spx/spxdev.c
new file mode 100644
index 000000000..431498686
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/spxdev.c
@@ -0,0 +1,242 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxdev.c
+
+Abstract:
+
+ This module contains code which implements the DEVICE_CONTEXT object.
+ Routines are provided to reference, and dereference transport device
+ context objects.
+
+ The transport device context object is a structure which contains a
+ system-defined DEVICE_OBJECT followed by information which is maintained
+ by the transport provider, called the context.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXDEV
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT, SpxInitCreateDevice)
+#pragma alloc_text(PAGE, SpxDestroyDevice)
+#endif
+
+
+
+
+VOID
+SpxDerefDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a device context by decrementing the
+ reference count contained in the structure. Currently, we don't
+ do anything special when the reference count drops to zero, but
+ we could dynamically unload stuff then.
+
+Arguments:
+
+ Device - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&Device->dev_RefCount);
+
+ CTEAssert (result >= 0);
+
+ if (result == 0)
+ {
+ // Close binding to IPX
+ SpxUnbindFromIpx();
+
+ // Set unload event.
+ KeSetEvent(&SpxUnloadEvent, IO_NETWORK_INCREMENT, FALSE);
+ }
+
+} // SpxDerefDevice
+
+
+
+
+NTSTATUS
+SpxInitCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN OUT PDEVICE * DevicePtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates and initializes a device context structure.
+
+Arguments:
+
+
+ DriverObject - pointer to the IO subsystem supplied driver object.
+
+ Device - Pointer to a pointer to a transport device context object.
+
+ DeviceName - pointer to the name of the device this device object points to.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
+
+--*/
+
+{
+ NTSTATUS status;
+ PDEVICE_OBJECT deviceObject;
+ PDEVICE Device;
+ ULONG DeviceSize;
+ ULONG DeviceNameOffset;
+
+
+ DBGPRINT(DEVICE, INFO,
+ ("SpxInitCreateDevice - Create device %ws\n", DeviceName->Buffer));
+
+ // Create the device object for the sample transport, allowing
+ // room at the end for the device name to be stored (for use
+ // in logging errors).
+ DeviceSize = sizeof(DEVICE) - sizeof(DEVICE_OBJECT) +
+ DeviceName->Length + sizeof(UNICODE_NULL);
+
+ status = IoCreateDevice(
+ DriverObject,
+ DeviceSize,
+ DeviceName,
+ FILE_DEVICE_TRANSPORT,
+ 0,
+ FALSE,
+ &deviceObject);
+
+ if (!NT_SUCCESS(status)) {
+ DBGPRINT(DEVICE, ERR, ("IoCreateDevice failed\n"));
+ return status;
+ }
+
+ deviceObject->Flags |= DO_DIRECT_IO;
+ Device = (PDEVICE)deviceObject;
+
+ DBGPRINT(DEVICE, INFO, ("IoCreateDevice succeeded %lx\n", Device));
+
+ // Initialize our part of the device context.
+ RtlZeroMemory(
+ ((PUCHAR)Device) + sizeof(DEVICE_OBJECT),
+ sizeof(DEVICE) - sizeof(DEVICE_OBJECT));
+
+ DeviceNameOffset = sizeof(DEVICE);
+
+ // Copy over the device name.
+ Device->dev_DeviceNameLen = DeviceName->Length + sizeof(WCHAR);
+ Device->dev_DeviceName = (PWCHAR)(((PUCHAR)Device) + DeviceNameOffset);
+
+ RtlCopyMemory(
+ Device->dev_DeviceName,
+ DeviceName->Buffer,
+ DeviceName->Length);
+
+ Device->dev_DeviceName[DeviceName->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ // Initialize the reference count.
+ Device->dev_RefCount = 1;
+
+#if DBG
+ Device->dev_RefTypes[DREF_CREATE] = 1;
+#endif
+
+#if DBG
+ RtlCopyMemory(Device->dev_Signature1, "IDC1", 4);
+ RtlCopyMemory(Device->dev_Signature2, "IDC2", 4);
+#endif
+
+ // Set next conn id to be used.
+ Device->dev_NextConnId = (USHORT)SpxRandomNumber();
+ if (Device->dev_NextConnId == 0xFFFF)
+ {
+ Device->dev_NextConnId = 1;
+ }
+
+ DBGPRINT(DEVICE, ERR,
+ ("SpxInitCreateDevice: Start Conn Id %lx\n", Device->dev_NextConnId));
+
+ // Initialize the resource that guards address ACLs.
+ ExInitializeResource (&Device->dev_AddrResource);
+
+ // initialize the various fields in the device context
+ CTEInitLock (&Device->dev_Interlock);
+ CTEInitLock (&Device->dev_Lock);
+ KeInitializeSpinLock (&Device->dev_StatInterlock);
+ KeInitializeSpinLock (&Device->dev_StatSpinLock);
+
+ Device->dev_State = DEVICE_STATE_CLOSED;
+ Device->dev_Type = SPX_DEVICE_SIGNATURE;
+ Device->dev_Size = sizeof (DEVICE);
+
+ Device->dev_Stat.Version = 0x100;
+
+ *DevicePtr = Device;
+ return STATUS_SUCCESS;
+
+} // SpxCreateDevice
+
+
+
+
+VOID
+SpxDestroyDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a device context structure.
+
+Arguments:
+
+ Device - Pointer to a pointer to a transport device context object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ExDeleteResource (&Device->dev_AddrResource);
+ IoDeleteDevice ((PDEVICE_OBJECT)Device);
+
+} // SpxDestroyDevice
diff --git a/private/ntos/tdi/isnp/spx/spxdrvr.c b/private/ntos/tdi/isnp/spx/spxdrvr.c
new file mode 100644
index 000000000..0e9935d1a
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/spxdrvr.c
@@ -0,0 +1,1008 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxdrvr.c
+
+Abstract:
+
+ This module contains the DriverEntry and other initialization
+ code for the SPX/SPXII module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) Original Version
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 14-July-1995
+ Bug fixes - tagged [SA]
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXDRVR
+
+// Forward declaration of various routines used in this module.
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath);
+
+NTSTATUS
+SpxDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+NTSTATUS
+SpxDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+NTSTATUS
+SpxDispatchInternal (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+NTSTATUS
+SpxDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+VOID
+SpxUnload(
+ IN PDRIVER_OBJECT DriverObject);
+
+VOID
+SpxTdiCancel(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT, DriverEntry)
+#pragma alloc_text(PAGE, SpxUnload)
+#pragma alloc_text(PAGE, SpxDispatchOpenClose)
+#pragma alloc_text(PAGE, SpxDispatch)
+#pragma alloc_text(PAGE, SpxDeviceControl)
+#pragma alloc_text(PAGE, SpxUnload)
+#endif
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs initialization of the SPX ISN module.
+ It creates the device objects for the transport
+ provider and performs other driver initialization.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+ RegistryPath - The name of ST's node in the registry.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ UNICODE_STRING deviceName;
+ NTSTATUS status = STATUS_SUCCESS;
+ BOOLEAN BoundToIpx = FALSE;
+
+ // DBGBRK(FATAL);
+
+ // Initialize the Common Transport Environment.
+ if (CTEInitialize() == 0) {
+ return (STATUS_UNSUCCESSFUL);
+ }
+
+ // We have this #define'd. Ugh, but CONTAINING_RECORD has problem owise.
+ CTEAssert(NDIS_PACKET_SIZE == FIELD_OFFSET(NDIS_PACKET, ProtocolReserved[0]));
+
+ // Create the device object. (IoCreateDevice zeroes the memory
+ // occupied by the object.)
+ RtlInitUnicodeString(&deviceName, SPX_DEVICE_NAME);
+ status = SpxInitCreateDevice(
+ DriverObject,
+ &deviceName,
+ &SpxDevice);
+
+ if (!NT_SUCCESS(status))
+ {
+ return(status);
+ }
+
+ do
+ {
+ CTEInitLock (&SpxGlobalInterlock);
+ CTEInitLock (&SpxGlobalQInterlock);
+
+ // Initialize the unload event
+ KeInitializeEvent(
+ &SpxUnloadEvent,
+ NotificationEvent,
+ FALSE);
+
+ // !!!The device is created at this point!!!
+ // Get information from the registry.
+ status = SpxInitGetConfiguration(
+ RegistryPath,
+ &SpxDevice->dev_ConfigInfo);
+
+ if (!NT_SUCCESS(status))
+ {
+ break;
+ }
+
+#if defined(_PNP_POWER)
+ //
+ // Make Tdi ready for pnp notifications before binding
+ // to IPX
+ //
+ TdiInitialize();
+
+ // Initialize the timer system. This should be done before
+ // binding to ipx because we should have timers intialized
+ // before ipx calls our pnp indications.
+ if (!NT_SUCCESS(status = SpxTimerInit()))
+ {
+ break;
+ }
+#endif _PNP_POWER
+
+ // Bind to the IPX transport.
+ if (!NT_SUCCESS(status = SpxInitBindToIpx()))
+ {
+ // BUGBUG: Have ipx name here as second string
+ LOG_ERROR(
+ EVENT_TRANSPORT_BINDING_FAILED,
+ status,
+ NULL,
+ NULL,
+ 0);
+
+ break;
+ }
+
+ BoundToIpx = TRUE;
+
+#if !defined(_PNP_POWER)
+ // Initialize the timer system
+ if (!NT_SUCCESS(status = SpxTimerInit()))
+ {
+ break;
+ }
+#endif !_PNP_POWER
+
+ // Initialize the block manager
+ if (!NT_SUCCESS(status = SpxInitMemorySystem(SpxDevice)))
+ {
+
+ // Stop the timer subsystem
+ SpxTimerFlushAndStop();
+ break;
+ }
+
+ // Initialize the driver object with this driver's entry points.
+ DriverObject->MajorFunction [IRP_MJ_CREATE] = SpxDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLOSE] = SpxDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLEANUP] = SpxDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL]
+ = SpxDispatch;
+ DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL]
+ = SpxDispatchInternal;
+ DriverObject->DriverUnload = SpxUnload;
+
+ // Initialize the provider info
+ SpxQueryInitProviderInfo(&SpxDevice->dev_ProviderInfo);
+ SpxDevice->dev_CurrentSocket = (USHORT)PARAM(CONFIG_SOCKET_RANGE_START);
+
+#if !defined(_PNP_POWER)
+ // We are open now.
+ SpxDevice->dev_State = DEVICE_STATE_OPEN;
+#endif !_PNP_POWER
+
+ // Set the window size in statistics
+ SpxDevice->dev_Stat.MaximumSendWindow =
+ SpxDevice->dev_Stat.AverageSendWindow = PARAM(CONFIG_WINDOW_SIZE) *
+ IpxLineInfo.MaximumSendSize;
+
+#if defined(_PNP_POWER)
+ if ( DEVICE_STATE_CLOSED == SpxDevice->dev_State ) {
+ SpxDevice->dev_State = DEVICE_STATE_LOADED;
+ }
+#endif _PNP_POWER
+
+ } while (FALSE);
+
+ if (!NT_SUCCESS(status) )
+ {
+ // Delete the device and any associated resources created.
+ if( BoundToIpx ) {
+ SpxDerefDevice(SpxDevice);
+ }
+ SpxDestroyDevice(SpxDevice);
+ }
+
+ return (status);
+}
+
+
+
+
+VOID
+SpxUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unloads the sample transport driver. The I/O system will not
+ call us until nobody above has ST open.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ None. When the function returns, the driver is unloaded.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (DriverObject);
+
+ // Stop the timer subsystem
+ SpxTimerFlushAndStop();
+
+ // Remove creation reference count on the IPX device object.
+ SpxDerefDevice(SpxDevice);
+
+ // Wait on the unload event.
+ KeWaitForSingleObject(
+ &SpxUnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL);
+
+ // Release the block memory stuff
+ SpxDeInitMemorySystem(SpxDevice);
+ SpxDestroyDevice(SpxDevice);
+ return;
+}
+
+
+
+NTSTATUS
+SpxDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the ST device driver.
+ It accepts an I/O Request Packet, performs the request, and then
+ returns with the appropriate status.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+
+ if (Device->dev_State != DEVICE_STATE_OPEN) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ // Make sure status information is consistent every time.
+ IoMarkIrpPending (Irp);
+ Irp->IoStatus.Status = STATUS_PENDING;
+ Irp->IoStatus.Information = 0;
+
+ // Case on the function that is being performed by the requestor. If the
+ // operation is a valid one for this device, then make it look like it was
+ // successfully completed, where possible.
+ switch (IrpSp->MajorFunction) {
+
+ case IRP_MJ_DEVICE_CONTROL:
+
+ Status = SpxDeviceControl (DeviceObject, Irp);
+ break;
+
+ default:
+
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ //
+ // Complete the Irp here instead of below.
+ //
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ } // major function switch
+
+ /* Commented out and re-located to the default case above.
+
+ if (Status != STATUS_PENDING) {
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ }
+ */
+
+ // Return the immediate status code to the caller.
+ return Status;
+
+} // SpxDispatch
+
+VOID
+SpxAssignControlChannelId(
+ IN PDEVICE Device,
+ IN PIRP Request
+ )
+/*++
+
+Routine Description:
+
+ This routine is required to ensure that the Device lock (to protect the ControlChannelId in the Device)
+ is not taken in a pageable routine (SpxDispatchOpenClose).
+
+ NOTE: SPX returns the ControlChannelId in the Request, but never uses it later when it comes down in a
+ close/cleanup. The CCID is a ULONG; in future, if we start using this field (as in IPX which uses these Ids
+ to determine lineup Irps to complete), then we may run out of numbers (since we monotonically increase the CCID);
+ though there is a low chance of that since we will probably run out of memory before that! Anyhow, if that
+ happens, one solution (used in IPX) is to make the CCID into a Large Integer and pack the values into the
+ REQUEST_OPEN_TYPE(Irp) too.
+
+
+Arguments:
+
+ Device - Pointer to the device object for this driver.
+
+ Request - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ CTELockHandle LockHandle;
+
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)(Device->dev_CcId);
+ ++Device->dev_CcId;
+ if (Device->dev_CcId == 0) {
+ Device->dev_CcId = 1;
+ }
+
+ CTEFreeLock (&Device->dev_Lock, LockHandle);
+}
+
+NTSTATUS
+SpxDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the ST device driver.
+ It accepts an I/O Request Packet, performs the request, and then
+ returns with the appropriate status.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ NTSTATUS Status;
+ BOOLEAN found;
+ PREQUEST Request;
+ UINT i;
+ PFILE_FULL_EA_INFORMATION openType;
+ CONNECTION_CONTEXT connCtx;
+
+
+#if !defined(_PNP_POWER)
+ if (Device->dev_State != DEVICE_STATE_OPEN) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+#endif !_PNP_POWER
+
+ // Allocate a request to track this IRP.
+ Request = SpxAllocateRequest (Device, Irp);
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+
+ // Make sure status information is consistent every time.
+ MARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = STATUS_PENDING;
+ REQUEST_INFORMATION(Request) = 0;
+
+ // Case on the function that is being performed by the requestor. If the
+ // operation is a valid one for this device, then make it look like it was
+ // successfully completed, where possible.
+ switch (REQUEST_MAJOR_FUNCTION(Request)) {
+
+ // The Create function opens a transport object (either address or
+ // connection). Access checking is performed on the specified
+ // address to ensure security of transport-layer addresses.
+ case IRP_MJ_CREATE:
+
+#if defined(_PNP_POWER)
+ if (Device->dev_State != DEVICE_STATE_OPEN) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ break;
+ }
+#endif _PNP_POWER
+
+ openType = OPEN_REQUEST_EA_INFORMATION(Request);
+
+ if (openType != NULL) {
+
+ found = TRUE;
+
+ for (i=0;i<openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiTransportAddress[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = SpxAddrOpen (Device, Request);
+ break;
+ }
+
+ // Connection?
+ found = TRUE;
+
+ for (i=0;i<openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiConnectionContext[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ if (openType->EaValueLength < sizeof(CONNECTION_CONTEXT))
+ {
+
+ DBGPRINT(CREATE, ERR,
+ ("Create: Context size %d\n", openType->EaValueLength));
+
+ Status = STATUS_EA_LIST_INCONSISTENT;
+ break;
+ }
+
+ connCtx =
+ *((CONNECTION_CONTEXT UNALIGNED *)
+ &openType->EaName[openType->EaNameLength+1]);
+
+ Status = SpxConnOpen(
+ Device,
+ connCtx,
+ Request);
+
+ break;
+ }
+
+ } else {
+
+ //
+ // Takes a lock in a Pageable routine - call another (non-paged) function to do that.
+ //
+ SpxAssignControlChannelId(Device, Request);
+
+ REQUEST_OPEN_TYPE(Request) = (PVOID)SPX_FILE_TYPE_CONTROL;
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case IRP_MJ_CLOSE:
+
+#if defined(_PNP_POWER)
+ if ((Device->dev_State != DEVICE_STATE_OPEN) && ( Device->dev_State != DEVICE_STATE_LOADED )) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ break;
+ }
+#endif _PNP_POWER
+
+ // The Close function closes a transport endpoint, terminates
+ // all outstanding transport activity on the endpoint, and unbinds
+ // the endpoint from its transport address, if any. If this
+ // is the last transport endpoint bound to the address, then
+ // the address is removed from the provider.
+ switch ((ULONG)REQUEST_OPEN_TYPE(Request)) {
+ case TDI_TRANSPORT_ADDRESS_FILE:
+
+ Status = SpxAddrFileClose(Device, Request);
+ break;
+
+ case TDI_CONNECTION_FILE:
+ Status = SpxConnClose(Device, Request);
+ break;
+
+ case SPX_FILE_TYPE_CONTROL:
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ break;
+
+ case IRP_MJ_CLEANUP:
+
+#if defined(_PNP_POWER)
+ if ((Device->dev_State != DEVICE_STATE_OPEN) && ( Device->dev_State != DEVICE_STATE_LOADED )) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ break;
+ }
+#endif _PNP_POWER
+
+ // Handle the two stage IRP for a file close operation. When the first
+ // stage hits, run down all activity on the object of interest. This
+ // do everything to it but remove the creation hold. Then, when the
+ // CLOSE irp hits, actually close the object.
+ switch ((ULONG)REQUEST_OPEN_TYPE(Request)) {
+ case TDI_TRANSPORT_ADDRESS_FILE:
+
+ Status = SpxAddrFileCleanup(Device, Request);
+ break;
+
+ case TDI_CONNECTION_FILE:
+
+ Status = SpxConnCleanup(Device, Request);
+ break;
+
+ case SPX_FILE_TYPE_CONTROL:
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ break;
+
+ default:
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ } // major function switch
+
+ if (Status != STATUS_PENDING) {
+ UNMARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = Status;
+ SpxCompleteRequest (Request);
+ SpxFreeRequest (Device, Request);
+ }
+
+ // Return the immediate status code to the caller.
+ return Status;
+
+} // SpxDispatchOpenClose
+
+
+
+
+NTSTATUS
+SpxDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ // Convert the user call to the proper internal device call.
+ Status = TdiMapUserRequest (DeviceObject, Irp, IrpSp);
+ if (Status == STATUS_SUCCESS) {
+
+ // If TdiMapUserRequest returns SUCCESS then the IRP
+ // has been converted into an IRP_MJ_INTERNAL_DEVICE_CONTROL
+ // IRP, so we dispatch it as usual. The IRP will
+ // be completed by this call.
+ Status = SpxDispatchInternal (DeviceObject, Irp);
+
+ //
+ // Return the proper error code here. If SpxDispatchInternal returns an error,
+ // then we used to map it to pending below; this is wrong since the client above
+ // us could wait for ever since the IO subsystem does not set the event if an
+ // error is returned and the Irp is not marked pending.
+ //
+
+ // Status = STATUS_PENDING;
+ } else {
+
+ DBGPRINT(TDI, DBG,
+ ("Unknown Tdi code in Irp: %lx\n", Irp));
+
+ //
+ // Complete the Irp....
+ //
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ }
+
+ return Status;
+
+} // SpxDeviceControl
+
+
+
+
+NTSTATUS
+SpxDispatchInternal (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ PREQUEST Request;
+ KIRQL oldIrql;
+ NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+
+
+ if (Device->dev_State != DEVICE_STATE_OPEN)
+ {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+
+ // Allocate a request to track this IRP.
+ Request = SpxAllocateRequest (Device, Irp);
+ IF_NOT_ALLOCATED(Request)
+ {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+
+ // Make sure status information is consistent every time.
+ MARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = STATUS_PENDING;
+ REQUEST_INFORMATION(Request) = 0;
+
+ // Cancel irp
+ IoAcquireCancelSpinLock(&oldIrql);
+ if (!Irp->Cancel)
+ {
+ IoSetCancelRoutine(Irp, (PDRIVER_CANCEL)SpxTdiCancel);
+ }
+ IoReleaseCancelSpinLock(oldIrql);
+
+ if (Irp->Cancel)
+ return STATUS_CANCELLED;
+
+ // Branch to the appropriate request handler. Preliminary checking of
+ // the size of the request block is performed here so that it is known
+ // in the handlers that the minimum input parameters are readable. It
+ // is *not* determined here whether variable length input fields are
+ // passed correctly; this is a check which must be made within each routine.
+ switch (REQUEST_MINOR_FUNCTION(Request))
+ {
+ case TDI_ACCEPT:
+
+ Status = SpxConnAccept(
+ Device,
+ Request);
+
+ break;
+
+ case TDI_SET_EVENT_HANDLER:
+
+ Status = SpxAddrSetEventHandler(
+ Device,
+ Request);
+
+ break;
+
+ case TDI_RECEIVE:
+
+ Status = SpxConnRecv(
+ Device,
+ Request);
+ break;
+
+
+ case TDI_SEND:
+
+ Status = SpxConnSend(
+ Device,
+ Request);
+ break;
+
+ case TDI_ACTION:
+
+ Status = SpxConnAction(
+ Device,
+ Request);
+ break;
+
+ case TDI_ASSOCIATE_ADDRESS:
+
+ Status = SpxConnAssociate(
+ Device,
+ Request);
+
+ break;
+
+ case TDI_DISASSOCIATE_ADDRESS:
+
+ Status = SpxConnDisAssociate(
+ Device,
+ Request);
+
+ break;
+
+ case TDI_CONNECT:
+
+ Status = SpxConnConnect(
+ Device,
+ Request);
+
+ break;
+
+ case TDI_DISCONNECT:
+
+ Status = SpxConnDisconnect(
+ Device,
+ Request);
+ break;
+
+ case TDI_LISTEN:
+
+ Status = SpxConnListen(
+ Device,
+ Request);
+ break;
+
+ case TDI_QUERY_INFORMATION:
+
+ Status = SpxTdiQueryInformation(
+ Device,
+ Request);
+
+ break;
+
+ case TDI_SET_INFORMATION:
+
+ Status = SpxTdiSetInformation(
+ Device,
+ Request);
+
+ break;
+
+ // Something we don't know about was submitted.
+ default:
+
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ if (Status != STATUS_PENDING)
+ {
+ UNMARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = Status;
+ IoAcquireCancelSpinLock(&oldIrql);
+ IoSetCancelRoutine(Irp, (PDRIVER_CANCEL)NULL);
+ IoReleaseCancelSpinLock(oldIrql);
+ SpxCompleteRequest (Request);
+ SpxFreeRequest (Device, Request);
+ }
+
+ // Return the immediate status code to the caller.
+ return Status;
+
+} // SpxDispatchInternal
+
+
+
+
+VOID
+SpxTdiCancel(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+/*++
+
+Routine Description:
+
+ This routine handles cancellation of IO requests
+
+Arguments:
+
+
+Return Value:
+--*/
+{
+ PREQUEST Request;
+ PSPX_ADDR_FILE pSpxAddrFile;
+ PSPX_ADDR pSpxAddr;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ CTELockHandle connectIrql;
+ CTELockHandle TempIrql;
+ PSPX_CONN_FILE pSpxConnFile;
+
+ Request = SpxAllocateRequest (Device, Irp);
+ IF_NOT_ALLOCATED(Request)
+ {
+ return;
+ }
+
+ DBGPRINT(TDI, ERR,
+ ("SpxTdiCancel: Cancel irp called %lx.%lx\n",
+ Irp, REQUEST_OPEN_CONTEXT(Request)));
+
+ switch ((ULONG)REQUEST_OPEN_TYPE(Request))
+ {
+ case TDI_CONNECTION_FILE:
+ pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(Request);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &connectIrql);
+
+ //
+ // Swap the irql
+ //
+ TempIrql = connectIrql;
+ connectIrql = Irp->CancelIrql;
+ Irp->CancelIrql = TempIrql;
+
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_STOPPING))
+ {
+ if (!SPX_CONN_IDLE(pSpxConnFile))
+ {
+ //
+ // This releases the lock
+ //
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_LOCAL_DISCONNECT,
+ SPX_CALL_TDILEVEL,
+ connectIrql,
+ FALSE); // [SA] bug #15249
+ }
+ }
+
+// SpxConnStop((PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(Request));
+ break;
+
+ case TDI_TRANSPORT_ADDRESS_FILE:
+
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+ pSpxAddrFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(Request);
+ pSpxAddr = pSpxAddrFile->saf_Addr;
+ SpxAddrFileStop(pSpxAddrFile, pSpxAddr);
+ break;
+
+ default:
+
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+ break;
+
+ }
+
+}
diff --git a/private/ntos/tdi/isnp/spx/spxerror.c b/private/ntos/tdi/isnp/spx/spxerror.c
new file mode 100644
index 000000000..7d2cc7444
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/spxerror.c
@@ -0,0 +1,316 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxerror.c
+
+Abstract:
+
+ This module contains code which provides error logging support.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXERROR
+
+LONG SpxLastRawDataLen = 0;
+NTSTATUS SpxLastUniqueErrorCode = STATUS_SUCCESS;
+NTSTATUS SpxLastNtStatusCode = STATUS_SUCCESS;
+ULONG SpxLastErrorCount = 0;
+LONG SpxLastErrorTime = 0;
+BYTE SpxLastRawData[PORT_MAXIMUM_MESSAGE_LENGTH - \
+ sizeof(IO_ERROR_LOG_PACKET)] = {0};
+
+BOOLEAN
+SpxFilterErrorLogEntry(
+ IN NTSTATUS UniqueErrorCode,
+ IN NTSTATUS NtStatusCode,
+ IN PVOID RawDataBuf OPTIONAL,
+ IN LONG RawDataLen
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+
+ int insertionStringLength = 0;
+
+ // Filter out events such that the same event recurring close together does not
+ // cause errorlog clogging. The scheme is - if the event is same as the last event
+ // and the elapsed time is > THRESHOLD and ERROR_CONSEQ_FREQ simulataneous errors
+ // have happened, then log it else skip
+ if ((UniqueErrorCode == SpxLastUniqueErrorCode) &&
+ (NtStatusCode == SpxLastNtStatusCode))
+ {
+ SpxLastErrorCount++;
+ if ((SpxLastRawDataLen == RawDataLen) &&
+ (RtlEqualMemory(SpxLastRawData, RawDataBuf, RawDataLen)) &&
+ ((SpxLastErrorCount % ERROR_CONSEQ_FREQ) != 0) &&
+ ((SpxGetCurrentTime() - SpxLastErrorTime) < ERROR_CONSEQ_TIME))
+ {
+ return(FALSE);
+ }
+ }
+
+ SpxLastUniqueErrorCode = UniqueErrorCode;
+ SpxLastNtStatusCode = NtStatusCode;
+ SpxLastErrorCount = 0;
+ SpxLastErrorTime = SpxGetCurrentTime();
+ if (RawDataLen != 0)
+ {
+ SpxLastRawDataLen = RawDataLen;
+ RtlCopyMemory(
+ SpxLastRawData,
+ RawDataBuf,
+ RawDataLen);
+ }
+
+ return(TRUE);
+}
+
+
+
+
+VOID
+SpxWriteResourceErrorLog(
+ IN PDEVICE Device,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ an out of resources condition.
+
+Arguments:
+
+ Device - Pointer to the device context.
+
+ BytesNeeded - If applicable, the number of bytes that could not
+ be allocated.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ PUCHAR StringLoc;
+ ULONG TempUniqueError;
+ static WCHAR UniqueErrorBuffer[4] = L"000";
+ UINT i;
+
+ if (!SpxFilterErrorLogEntry(
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ STATUS_INSUFFICIENT_RESOURCES,
+ (PVOID)&BytesNeeded,
+ sizeof(BytesNeeded)))
+ {
+ return;
+ }
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ Device->dev_DeviceNameLen +
+ sizeof(UniqueErrorBuffer);
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)Device,
+ EntrySize);
+
+ // Convert the error value into a buffer.
+ TempUniqueError = UniqueErrorValue;
+ for (i=1; i>=0; i--)
+ {
+ UniqueErrorBuffer[i] = (WCHAR)((TempUniqueError % 10) + L'0');
+ TempUniqueError /= 10;
+ }
+
+ if (errorLogEntry != NULL)
+ {
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = sizeof(ULONG);
+ errorLogEntry->NumberOfStrings = 2;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = EVENT_TRANSPORT_RESOURCE_POOL;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+ errorLogEntry->DumpData[0] = BytesNeeded;
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ RtlCopyMemory(
+ StringLoc, Device->dev_DeviceName, Device->dev_DeviceNameLen);
+
+ StringLoc += Device->dev_DeviceNameLen;
+ RtlCopyMemory(
+ StringLoc, UniqueErrorBuffer, sizeof(UniqueErrorBuffer));
+
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+}
+
+
+
+
+VOID
+SpxWriteGeneralErrorLog(
+ IN PDEVICE Device,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN PVOID RawDataBuf OPTIONAL,
+ IN LONG RawDataLen
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ a general problem as indicated by the parameters. It handles
+ event codes REGISTER_FAILED, BINDING_FAILED, ADAPTER_NOT_FOUND,
+ TRANSFER_DATA, TOO_MANY_LINKS, and BAD_PROTOCOL. All these
+ events have messages with one or two strings in them.
+
+Arguments:
+
+ Device - Pointer to the device context, or this may be
+ a driver object instead.
+
+ ErrorCode - The transport event code.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet.
+
+ FinalStatus - Used as the FinalStatus in the error log packet.
+
+ SecondString - If not NULL, the string to use as the %3
+ value in the error log packet.
+
+ RawDataBuf - The number of ULONGs of dump data.
+
+ RawDataLen - Dump data for the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG SecondStringSize;
+ PUCHAR StringLoc;
+ static WCHAR DriverName[4] = L"Spx";
+
+ if (!SpxFilterErrorLogEntry(
+ ErrorCode,
+ FinalStatus,
+ RawDataBuf,
+ RawDataLen))
+ {
+ return;
+ }
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) + RawDataLen;
+ if (Device->dev_Type == SPX_DEVICE_SIGNATURE)
+ {
+ EntrySize += (UCHAR)Device->dev_DeviceNameLen;
+ }
+ else
+ {
+ EntrySize += sizeof(DriverName);
+ }
+
+ if (SecondString)
+ {
+ SecondStringSize = (wcslen(SecondString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize += (UCHAR)SecondStringSize;
+ }
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)Device,
+ EntrySize);
+
+ if (errorLogEntry != NULL)
+ {
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = (USHORT)RawDataLen;
+ errorLogEntry->NumberOfStrings = (SecondString == NULL) ? 1 : 2;
+ errorLogEntry->StringOffset =
+ sizeof(IO_ERROR_LOG_PACKET) + RawDataLen;
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ if (RawDataLen != 0)
+ {
+ RtlCopyMemory(errorLogEntry->DumpData, RawDataBuf, RawDataLen);
+ }
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ if (Device->dev_Type == SPX_DEVICE_SIGNATURE)
+ {
+ RtlCopyMemory(
+ StringLoc, Device->dev_DeviceName, Device->dev_DeviceNameLen);
+
+ StringLoc += Device->dev_DeviceNameLen;
+ }
+ else
+ {
+ RtlCopyMemory (StringLoc, DriverName, sizeof(DriverName));
+ StringLoc += sizeof(DriverName);
+ }
+
+ if (SecondString)
+ {
+ RtlCopyMemory (StringLoc, SecondString, SecondStringSize);
+ }
+
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+ return;
+}
diff --git a/private/ntos/tdi/isnp/spx/spxmem.c b/private/ntos/tdi/isnp/spx/spxmem.c
new file mode 100644
index 000000000..9cd400e5b
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/spxmem.c
@@ -0,0 +1,897 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxmem.c
+
+Abstract:
+
+ This module contains code which implements the memory allocation wrappers.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+ Jameel Hyder (jameelh) Initial Version
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text( INIT, SpxInitMemorySystem)
+#pragma alloc_text( PAGE, SpxDeInitMemorySystem)
+#endif
+
+// Define module number for event logging entries
+#define FILENUM SPXMEM
+
+// Globals for this module
+// Some block sizes (like NDISSEND/NDISRECV are filled in after binding with IPX)
+USHORT spxBlkSize[NUM_BLKIDS] = // Size of each block
+ {
+ sizeof(BLK_HDR)+sizeof(TIMERLIST), // BLKID_TIMERLIST
+ 0, // BLKID_NDISSEND
+ 0 // BLKID_NDISRECV
+ };
+
+USHORT spxChunkSize[NUM_BLKIDS] = // Size of each Chunk
+ {
+ 512-BC_OVERHEAD, // BLKID_TIMERLIST
+ 512-BC_OVERHEAD, // BLKID_NDISSEND
+ 512-BC_OVERHEAD // BLKID_NDISRECV
+ };
+
+
+// Filled in after binding with IPX
+// Reference for below.
+// ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/
+// (sizeof(BLK_HDR)+sizeof(TIMERLIST)), // BLKID_TIMERLIST
+USHORT spxNumBlks[NUM_BLKIDS] = // Number of blocks per chunk
+ {
+ ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/
+ (sizeof(BLK_HDR)+sizeof(TIMERLIST)), // BLKID_TIMERLIST
+ 0, // BLKID_NDISSEND
+ 0 // BLKID_NDISRECV
+ };
+
+CTELock spxBPLock[NUM_BLKIDS] = { 0 };
+PBLK_CHUNK spxBPHead[NUM_BLKIDS] = { 0 };
+
+
+
+
+NTSTATUS
+SpxInitMemorySystem(
+ IN PDEVICE pSpxDevice
+ )
+/*++
+
+Routine Description:
+
+ !!! MUST BE CALLED AFTER BINDING TO IPX!!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LONG i;
+ NDIS_STATUS ndisStatus;
+
+ // Try to allocate the ndis buffer pool.
+ NdisAllocateBufferPool(
+ &ndisStatus,
+ &pSpxDevice->dev_NdisBufferPoolHandle,
+ 20);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ return(STATUS_INSUFFICIENT_RESOURCES);
+
+ for (i = 0; i < NUM_BLKIDS; i++)
+ CTEInitLock (&spxBPLock[i]);
+
+ // Set the sizes in the block id info arrays.
+ for (i = 0; i < NUM_BLKIDS; i++)
+ {
+ // BUGBUG: Do it.
+ switch (i)
+ {
+ case BLKID_NDISSEND:
+
+#ifdef SPX_OWN_PACKETS
+ spxBlkSize[i] = sizeof(BLK_HDR) +
+ sizeof(SPX_SEND_RESD) +
+ NDIS_PACKET_SIZE +
+ IpxMacHdrNeeded +
+ MIN_IPXSPX2_HDRSIZE;
+#else
+ spxBlkSize[i] = sizeof(PNDIS_PACKET);
+#endif
+
+ //
+ // Round the block size up to the next 8-byte boundary.
+ //
+ spxBlkSize[i] = QWORDSIZEBLOCK(spxBlkSize[i]);
+
+ // Set number blocks
+ spxNumBlks[i] = ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/spxBlkSize[i];
+ break;
+
+ case BLKID_NDISRECV:
+
+#ifdef SPX_OWN_PACKETS
+ spxBlkSize[i] = sizeof(BLK_HDR) +
+ sizeof(SPX_RECV_RESD) +
+ NDIS_PACKET_SIZE;
+#else
+ spxBlkSize[i] = sizeof(PNDIS_PACKET);
+#endif
+
+ //
+ // Round the block size up to the next 8-byte boundary.
+ //
+ spxBlkSize[i] = QWORDSIZEBLOCK(spxBlkSize[i]);
+
+ // Set number blocks
+ spxNumBlks[i] = ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/spxBlkSize[i];
+ break;
+
+ default:
+
+ break;
+ }
+
+ }
+
+ SpxTimerScheduleEvent((TIMER_ROUTINE)spxBPAgePool,
+ BLOCK_POOL_TIMER,
+ NULL);
+}
+
+
+
+
+VOID
+SpxDeInitMemorySystem(
+ IN PDEVICE pSpxDevice
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LONG i, j, NumBlksPerChunk;
+ PBLK_CHUNK pChunk, pFree;
+
+ for (i = 0; i < NUM_BLKIDS; i++)
+ {
+ NumBlksPerChunk = spxNumBlks[i];
+ for (pChunk = spxBPHead[i];
+ pChunk != NULL; )
+ {
+ DBGPRINT(RESOURCES, ERR,
+ ("SpxInitMemorySystem: Freeing %lx\n", pChunk));
+
+ CTEAssert (pChunk->bc_NumFrees == NumBlksPerChunk);
+
+ if ((pChunk->bc_BlkId == BLKID_NDISSEND) ||
+ (pChunk->bc_BlkId == BLKID_NDISRECV))
+ {
+ PBLK_HDR pBlkHdr;
+
+ // We need to free the Ndis stuff for these guys
+ for (j = 0, pBlkHdr = pChunk->bc_FreeHead;
+ j < NumBlksPerChunk;
+ j++, pBlkHdr = pBlkHdr->bh_Next)
+ {
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+
+#ifdef SPX_OWN_PACKETS
+ // Only need to free the ndis buffer.
+ pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
+
+ if (pChunk->bc_BlkId == BLKID_NDISSEND)
+ {
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ if (pNdisBuffer == NULL)
+ {
+ // Something is terribly awry.
+ KeBugCheck(0);
+ }
+
+ NdisFreeBuffer(pNdisBuffer);
+
+ //
+ // Free the second MDL also
+ //
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ if (pNdisBuffer == NULL)
+ {
+ // Something is terribly awry.
+ KeBugCheck(0);
+ }
+
+ NdisFreeBuffer(pNdisBuffer);
+ }
+#else
+ // Need to free both the packet and the buffer.
+ ppNdisPkt = (PNDIS_PACKET *)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
+
+ if (pChunk->bc_BlkId == BLKID_NDISSEND)
+ {
+
+ NdisUnchainBufferAtFront(*ppNdisPkt, &pNdisBuffer);
+ if (pNdisBuffer == NULL)
+ {
+ // Something is terribly awry.
+ KeBugCheck(0);
+ }
+
+ NdisFreeBuffer(pNdisBuffer);
+ }
+ NdisFreePacket(*ppNdisPkt);
+#endif
+ }
+ }
+ pFree = pChunk;
+ pChunk = pChunk->bc_Next;
+
+#ifndef SPX_OWN_PACKETS
+ // Free the ndis packet pool in chunk
+ NdisFreePacketPool((NDIS_HANDLE)pFree->bc_ChunkCtx);
+#endif
+ SpxFreeMemory(pFree);
+ }
+ }
+
+ // Free up the ndis buffer pool
+ NdisFreeBufferPool(
+ pSpxDevice->dev_NdisBufferPoolHandle);
+
+ return;
+}
+
+
+
+
+PVOID
+SpxAllocMem(
+#ifdef TRACK_MEMORY_USAGE
+ IN ULONG Size,
+ IN ULONG FileLine
+#else
+ IN ULONG Size
+#endif // TRACK_MEMORY_USAGE
+ )
+/*++
+
+Routine Description:
+
+ Allocate a block of non-paged memory. This is just a wrapper over ExAllocPool.
+ Allocation failures are error-logged. We always allocate a ULONG more than
+ the specified size to accomodate the size. This is used by SpxFreeMemory
+ to update the statistics.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PBYTE pBuf;
+ BOOLEAN zeroed;
+
+ // round up the size so that we can put a signature at the end
+ // that is on a LARGE_INTEGER boundary
+ zeroed = ((Size & ZEROED_MEMORY_TAG) == ZEROED_MEMORY_TAG);
+
+ Size = QWORDSIZEBLOCK(Size & ~ZEROED_MEMORY_TAG);
+
+ // Do the actual memory allocation. Allocate eight extra bytes so
+ // that we can store the size of the allocation for the free routine
+ // and still keep the buffer quadword aligned.
+
+ if ((pBuf = ExAllocatePoolWithTag(NonPagedPool, Size + sizeof(LARGE_INTEGER)
+#if DBG
+ + sizeof(ULONG)
+#endif
+ ,SPX_TAG)) == NULL)
+ {
+ DBGPRINT(RESOURCES, FATAL,
+ ("SpxAllocMemory: failed - size %lx\n", Size));
+
+ TMPLOGERR();
+ return NULL;
+ }
+
+ // Save the size of this block in the four extra bytes we allocated.
+ *((PULONG)pBuf) = (Size + sizeof(LARGE_INTEGER));
+
+ // Return a pointer to the memory after the size longword.
+ pBuf += sizeof(LARGE_INTEGER);
+
+#if DBG
+ *((PULONG)(pBuf+Size)) = SPX_MEMORY_SIGNATURE;
+ DBGPRINT(RESOURCES, INFO,
+ ("SpxAllocMemory: %lx Allocated %lx bytes @%lx\n",
+ *(PULONG)((PBYTE)(&Size) - sizeof(Size)), Size, pBuf));
+#endif
+
+ SpxTrackMemoryUsage((PVOID)(pBuf - sizeof(LARGE_INTEGER)), TRUE, FileLine);
+
+ if (zeroed)
+ RtlZeroMemory(pBuf, Size);
+
+ return (pBuf);
+}
+
+
+
+
+VOID
+SpxFreeMemory(
+ IN PVOID pBuf
+ )
+/*++
+
+Routine Description:
+
+ Free the block of memory allocated via SpxAllocMemory. This is
+ a wrapper around ExFreePool.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PULONG pRealBuffer;
+
+ // Get a pointer to the block allocated by ExAllocatePool --
+ // we allocate a LARGE_INTEGER at the front.
+ pRealBuffer = ((PULONG)pBuf - 2);
+
+ SpxTrackMemoryUsage(pRealBuffer, FALSE, 0);
+
+#if DBG
+ // Check the signature at the end
+ if (*(PULONG)((PCHAR)pRealBuffer + *(PULONG)pRealBuffer)
+ != SPX_MEMORY_SIGNATURE)
+ {
+ DBGPRINT(RESOURCES, FATAL,
+ ("SpxFreeMemory: Memory overrun on block %lx\n", pRealBuffer));
+
+ DBGBRK(FATAL);
+ }
+
+ *(PULONG)((PCHAR)pRealBuffer + *(PULONG)pRealBuffer) = 0;
+#endif
+
+#if DBG
+ *pRealBuffer = 0;
+#endif
+
+ // Free the pool and return.
+ ExFreePool(pRealBuffer);
+}
+
+
+
+
+#ifdef TRACK_MEMORY_USAGE
+
+#define MAX_PTR_COUNT 4*1024
+#define MAX_MEM_USERS 512
+CTELock spxMemTrackLock = {0};
+CTELockHandle lockHandle = {0};
+struct
+{
+ PVOID mem_Ptr;
+ ULONG mem_FileLine;
+} spxMemPtrs[MAX_PTR_COUNT] = {0};
+
+struct
+{
+ ULONG mem_FL;
+ ULONG mem_Count;
+} spxMemUsage[MAX_MEM_USERS] = {0};
+
+VOID
+SpxTrackMemoryUsage(
+ IN PVOID pMem,
+ IN BOOLEAN Alloc,
+ IN ULONG FileLine
+ )
+/*++
+
+Routine Description:
+
+ Keep track of memory usage by storing and clearing away pointers as and
+ when they are allocated or freed. This helps in keeping track of memory
+ leaks.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ static int i = 0;
+ int j, k;
+
+ CTEGetLock (&spxMemTrackLock, &lockHandle);
+
+ if (Alloc)
+ {
+ for (j = 0; j < MAX_PTR_COUNT; i++, j++)
+ {
+ i = i & (MAX_PTR_COUNT-1);
+ if (spxMemPtrs[i].mem_Ptr == NULL)
+ {
+ spxMemPtrs[i].mem_Ptr = pMem;
+ spxMemPtrs[i++].mem_FileLine = FileLine;
+ break;
+ }
+ }
+
+ for (k = 0; k < MAX_MEM_USERS; k++)
+ {
+ if (spxMemUsage[k].mem_FL == FileLine)
+ {
+ spxMemUsage[k].mem_Count ++;
+ break;
+ }
+ }
+ if (k == MAX_MEM_USERS)
+ {
+ for (k = 0; k < MAX_MEM_USERS; k++)
+ {
+ if (spxMemUsage[k].mem_FL == 0)
+ {
+ spxMemUsage[k].mem_FL = FileLine;
+ spxMemUsage[k].mem_Count = 1;
+ break;
+ }
+ }
+ }
+ if (k == MAX_MEM_USERS)
+ {
+ DBGPRINT(RESOURCES, ERR,
+ ("SpxTrackMemoryUsage: Out of space on spxMemUsage !!!\n"));
+
+ DBGBRK(FATAL);
+ }
+ }
+ else
+ {
+ for (j = 0, k = i; j < MAX_PTR_COUNT; j++, k--)
+ {
+ k = k & (MAX_PTR_COUNT-1);
+ if (spxMemPtrs[k].mem_Ptr == pMem)
+ {
+ spxMemPtrs[k].mem_Ptr = 0;
+ spxMemPtrs[k].mem_FileLine = 0;
+ break;
+ }
+ }
+ }
+
+ CTEFreeLock (&spxMemTrackLock, lockHandle);
+
+ if (j == MAX_PTR_COUNT)
+ {
+ DBGPRINT(RESOURCES, ERR,
+ ("SpxTrackMemoryUsage: %s\n", Alloc ? "Table Full" : "Can't find"));
+
+ DBGBRK(FATAL);
+ }
+}
+
+#endif // TRACK_MEMORY_USAGE
+
+
+
+
+PVOID
+SpxBPAllocBlock(
+ IN BLKID BlockId
+ )
+/*++
+
+Routine Description:
+
+ Alloc a block of memory from the block pool package. This is written to speed up
+ operations where a lot of small fixed size allocations/frees happen. Going to
+ ExAllocPool() in these cases is expensive.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PBLK_HDR pBlk = NULL;
+ PBLK_CHUNK pChunk, *ppChunkHead;
+ USHORT BlkSize;
+ CTELockHandle lockHandle;
+ PSPX_SEND_RESD pSendResd;
+ PSPX_RECV_RESD pRecvResd;
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+ PNDIS_BUFFER pNdisIpxSpxBuffer;
+
+
+ CTEAssert (BlockId < NUM_BLKIDS);
+
+ if (BlockId < NUM_BLKIDS)
+ {
+ BlkSize = spxBlkSize[BlockId];
+ ppChunkHead = &spxBPHead[BlockId];
+
+ CTEGetLock(&spxBPLock[BlockId], &lockHandle);
+
+ for (pChunk = *ppChunkHead;
+ pChunk != NULL;
+ pChunk = pChunk->bc_Next)
+ {
+ CTEAssert(pChunk->bc_BlkId == BlockId);
+ if (pChunk->bc_NumFrees > 0)
+ {
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxBPAllocBlock: Found space in Chunk %lx\n", pChunk));
+#ifdef PROFILING
+ InterlockedIncrement( &SpxStatistics.stat_NumBPHits);
+#endif
+ break;
+ }
+ }
+
+ if (pChunk == NULL)
+ {
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxBPAllocBlock: Allocating a new chunk for Id %d\n", BlockId));
+
+#ifdef PROFILING
+ InterlockedIncrement( &SpxStatistics.stat_NumBPMisses);
+#endif
+ pChunk = SpxAllocateMemory(spxChunkSize[BlockId]);
+ if (pChunk != NULL)
+ {
+ LONG i, j;
+ PBLK_HDR pBlkHdr;
+ USHORT NumBlksPerChunk;
+
+ NumBlksPerChunk = spxNumBlks[BlockId];
+ pChunk->bc_NumFrees = NumBlksPerChunk;
+ pChunk->bc_BlkId = BlockId;
+ pChunk->bc_FreeHead = (PBLK_HDR)((PBYTE)pChunk + sizeof(BLK_CHUNK));
+
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxBPAllocBlock: Initializing chunk %lx\n", pChunk));
+
+ // Initialize the blocks in the chunk
+ for (i = 0, pBlkHdr = pChunk->bc_FreeHead;
+ i < NumBlksPerChunk;
+ i++, pBlkHdr = pBlkHdr->bh_Next)
+ {
+ NDIS_STATUS ndisStatus;
+
+ pBlkHdr->bh_Next = (PBLK_HDR)((PBYTE)pBlkHdr + BlkSize);
+ if (BlockId == BLKID_NDISSEND)
+ {
+ PBYTE pHdrMem;
+
+#ifdef SPX_OWN_PACKETS
+ // Point to the ndis packet,initialize it.
+ pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
+ NdisReinitializePacket(pNdisPkt);
+
+ // Allocate a ndis buffer descriptor describing hdr memory
+ // and queue it in.
+ pHdrMem = (PBYTE)pNdisPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD);
+
+ NdisAllocateBuffer(
+ &ndisStatus,
+ &pNdisBuffer,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ pHdrMem,
+ IpxMacHdrNeeded);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ // Link the buffer descriptor into the packet descriptor
+ NdisChainBufferAtBack(
+ pNdisPkt,
+ pNdisBuffer);
+
+
+ NdisAllocateBuffer(
+ &ndisStatus,
+ &pNdisIpxSpxBuffer,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ pHdrMem + IpxMacHdrNeeded,
+ MIN_IPXSPX2_HDRSIZE);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ // Link the buffer descriptor into the packet descriptor
+ NdisChainBufferAtBack(
+ pNdisPkt,
+ pNdisIpxSpxBuffer);
+
+
+
+ pSendResd = (PSPX_SEND_RESD)pNdisPkt->ProtocolReserved;
+
+#else
+ // Allocate a ndis packet pool for this chunk
+ NdisAllocatePacketPool();
+ etc.
+#endif
+
+
+ // Initialize elements of the protocol reserved structure.
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = SPX_SENDPKT_IDLE;
+ }
+ else if (BlockId == BLKID_NDISRECV)
+ {
+#ifdef SPX_OWN_PACKETS
+ // Point to the ndis packet,initialize it.
+ pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
+ NdisReinitializePacket(pNdisPkt);
+
+ pRecvResd = (PSPX_RECV_RESD)pNdisPkt->ProtocolReserved;
+
+#else
+ // Allocate a ndis packet pool for this chunk
+ NdisAllocatePacketPool();
+ etc.
+#endif
+
+ // Initialize elements of the protocol reserved structure.
+ pRecvResd->rr_Id = IDENTIFIER_SPX;
+ pRecvResd->rr_State = SPX_RECVPKT_IDLE;
+ }
+ }
+
+ if (i != NumBlksPerChunk)
+ {
+ // This has to be a failure from Ndis for send blocks!!!
+ // Undo a bunch of stuff
+ CTEAssert (BlockId == BLKID_NDISSEND);
+ pBlkHdr = pChunk->bc_FreeHead;
+ for (j = 0, pBlkHdr = pChunk->bc_FreeHead;
+ j < i; j++, pBlkHdr = pBlkHdr->bh_Next)
+ {
+ NdisUnchainBufferAtFront(
+ (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR)),
+ &pNdisBuffer);
+
+ CTEAssert(pNdisBuffer != NULL);
+ NdisFreeBuffer(pNdisBuffer);
+
+ NdisUnchainBufferAtFront(
+ (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR)),
+ &pNdisIpxSpxBuffer);
+
+ if (pNdisIpxSpxBuffer)
+ {
+ NdisFreeBuffer(pNdisIpxSpxBuffer);
+ }
+ }
+
+ SpxFreeMemory(pChunk);
+ pChunk = NULL;
+ }
+ else
+ {
+ // Successfully initialized the chunk, link it in
+ pChunk->bc_Next = *ppChunkHead;
+ *ppChunkHead = pChunk;
+ }
+ }
+ }
+
+ if (pChunk != NULL)
+ {
+ CTEAssert(pChunk->bc_BlkId == BlockId);
+ DBGPRINT(RESOURCES, INFO,
+ ("SpxBPAllocBlock: Allocating a block out of chunk %lx(%d) for Id %d\n",
+ pChunk, pChunk->bc_NumFrees, BlockId));
+
+ pChunk->bc_NumFrees --;
+ pChunk->bc_Age = 0; // Reset age
+ pBlk = pChunk->bc_FreeHead;
+ pChunk->bc_FreeHead = pBlk->bh_Next;
+ pBlk->bh_pChunk = pChunk;
+
+ // Skip the block header!
+ pBlk++;
+ }
+
+ CTEFreeLock(&spxBPLock[BlockId], lockHandle);
+ }
+
+ return pBlk;
+}
+
+
+
+VOID
+SpxBPFreeBlock(
+ IN PVOID pBlock,
+ IN BLKID BlockId
+ )
+/*++
+
+Routine Description:
+
+ Return a block to its owning chunk.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PBLK_CHUNK pChunk;
+ PBLK_HDR pBlkHdr = (PBLK_HDR)((PCHAR)pBlock - sizeof(BLK_HDR));
+ CTELockHandle lockHandle;
+
+ CTEGetLock(&spxBPLock[BlockId], &lockHandle);
+
+ for (pChunk = spxBPHead[BlockId];
+ pChunk != NULL;
+ pChunk = pChunk->bc_Next)
+ {
+ CTEAssert(pChunk->bc_BlkId == BlockId);
+ if (pBlkHdr->bh_pChunk == pChunk)
+ {
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxBPFreeBlock: Returning Block %lx to chunk %lx for Id %d\n",
+ pBlkHdr, pChunk, BlockId));
+
+ CTEAssert (pChunk->bc_NumFrees < spxNumBlks[BlockId]);
+ pChunk->bc_NumFrees ++;
+ pBlkHdr->bh_Next = pChunk->bc_FreeHead;
+ pChunk->bc_FreeHead = pBlkHdr;
+ break;
+ }
+ }
+ CTEAssert ((pChunk != NULL) && (pChunk->bc_FreeHead == pBlkHdr));
+
+ CTEFreeLock(&spxBPLock[BlockId], lockHandle);
+ return;
+}
+
+
+
+
+ULONG
+spxBPAgePool(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown
+ )
+/*++
+
+Routine Description:
+
+ Age out the block pool of unused blocks
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PBLK_CHUNK pChunk, *ppChunk, pFree = NULL;
+ LONG i, j, NumBlksPerChunk;
+ CTELockHandle lockHandle;
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+
+ if (TimerShuttingDown)
+ {
+ return TIMER_DONT_REQUEUE;
+ }
+
+ for (i = 0; i < NUM_BLKIDS; i++)
+ {
+ NumBlksPerChunk = spxNumBlks[i];
+ CTEGetLock(&spxBPLock[i], &lockHandle);
+
+ for (ppChunk = &spxBPHead[i];
+ (pChunk = *ppChunk) != NULL; )
+ {
+ if ((pChunk->bc_NumFrees == NumBlksPerChunk) &&
+ (++(pChunk->bc_Age) >= MAX_BLOCK_POOL_AGE))
+ {
+ DBGPRINT(SYSTEM, INFO,
+ ("spxBPAgePool: freeing Chunk %lx, Id %d\n",
+ pChunk, pChunk->bc_BlkId));
+
+ *ppChunk = pChunk->bc_Next;
+#ifdef PROFILING
+ InterlockedIncrement( &SpxStatistics.stat_NumBPAge);
+#endif
+ if (pChunk->bc_BlkId == BLKID_NDISSEND)
+ {
+ PBLK_HDR pBlkHdr;
+
+ // We need to free Ndis stuff for these guys
+ pBlkHdr = pChunk->bc_FreeHead;
+ for (j = 0, pBlkHdr = pChunk->bc_FreeHead;
+ j < NumBlksPerChunk;
+ j++, pBlkHdr = pBlkHdr->bh_Next)
+ {
+ pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
+ NdisUnchainBufferAtFront(
+ pNdisPkt,
+ &pNdisBuffer);
+
+ NdisFreeBuffer(pNdisBuffer);
+
+ NdisUnchainBufferAtFront(
+ pNdisPkt,
+ &pNdisBuffer);
+
+ NdisFreeBuffer(pNdisBuffer);
+ }
+ }
+
+ SpxFreeMemory(pChunk);
+ }
+ else
+ {
+ ppChunk = &pChunk->bc_Next;
+ }
+ }
+ CTEFreeLock(&spxBPLock[i], lockHandle);
+ }
+
+ return TIMER_REQUEUE_CUR_VALUE;
+}
diff --git a/private/ntos/tdi/isnp/spx/spxpkt.c b/private/ntos/tdi/isnp/spx/spxpkt.c
new file mode 100644
index 000000000..5f472d8cd
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/spxpkt.c
@@ -0,0 +1,1594 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxpkt.c
+
+Abstract:
+
+ This module contains code that builds various spx packets.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+// Define module number for event logging entries
+#define FILENUM SPXPKT
+
+VOID
+SpxPktBuildCr(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_ADDR pSpxAddr,
+ IN OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fSpx2
+ )
+/*++
+
+Routine Description:
+
+ NOTE: If *ppPkt is NULL, we allocate a packet. If not, we just
+ recreate the data and don't update the packet's state.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pCrPkt;
+ PSPX_SEND_RESD pSendResd;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr;
+
+ if (*ppPkt == NULL) {
+
+ SpxAllocSendPacket(SpxDevice, &pCrPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnHandleConnReq: Could not allocate ndis packet\n"));
+ return;
+ }
+
+ } else {
+
+ pCrPkt = *ppPkt;
+ }
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pCrPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ NdisQueryPacket(pCrPkt, NULL, NULL, &pNdisMacHdr, NULL);
+ pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr);
+ if (!fSpx2)
+ {
+ NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE);
+ }
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ MIN_IPXSPX_HDRSIZE,
+ pSpxConnFile->scf_RemAddr,
+ pSpxAddr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | SPX_CC_ACK |
+ (fSpx2 ? (SPX_CC_SPX2 | SPX_CC_NEG) : 0));
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId = 0xFFFF;
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ pIpxSpxHdr->hdr_AckNum = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+
+ // Initialize
+
+ if (*ppPkt == NULL) {
+
+ pSendResd = (PSPX_SEND_RESD)(pCrPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_CR;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = State;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Len = pSendResd->sr_HdrLen = MIN_IPXSPX_HDRSIZE;
+
+ *ppPkt = pCrPkt;
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildCrAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_ADDR pSpxAddr,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fNeg,
+ IN BOOLEAN fSpx2
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pCrAckPkt;
+ PSPX_SEND_RESD pSendResd;
+ PIPXSPX_HDR pIpxSpxHdr;
+ NDIS_STATUS ndisStatus;
+ USHORT hdrLen;
+ PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr;
+
+ *ppPkt = NULL;
+
+ SpxAllocSendPacket(SpxDevice, &pCrAckPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnHandleConnReq: Could not allocate ndis packet\n"));
+ return;
+ }
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pCrAckPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ hdrLen = (SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE);
+
+ NdisQueryPacket(pCrAckPkt, NULL, NULL, &pNdisMacHdr, NULL);
+ pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr);
+ if (!SPX2_CONN(pSpxConnFile))
+ {
+ NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE);
+ }
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ hdrLen,
+ pSpxConnFile->scf_RemAddr,
+ pSpxAddr->sa_Socket);
+
+ pIpxSpxHdr->hdr_ConnCtrl =
+ (SPX_CC_SYS |
+ (fSpx2 ? SPX_CC_SPX2 : 0) |
+ (fNeg ? SPX_CC_NEG : 0));
+
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ pIpxSpxHdr->hdr_AckNum = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+
+ if (SPX2_CONN(pSpxConnFile))
+ {
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnBuildCrAck: Spx2 packet size %d.%lx\n",
+ pSpxConnFile->scf_MaxPktSize));
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+ }
+
+
+ pSendResd = (PSPX_SEND_RESD)(pCrAckPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_CRACK;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = State;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Len = pSendResd->sr_HdrLen = hdrLen;
+
+ *ppPkt = pCrAckPkt;
+ return;
+}
+
+
+
+VOID
+SpxPktBuildSn(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_BUFFER pBuf;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PBYTE pData;
+
+ do
+ {
+ *ppPkt = NULL;
+
+ // Allocate a ndis packet for the cr.
+ SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ CTEAssert(pSpxConnFile->scf_MaxPktSize != 0);
+ DBGPRINT(SEND, DBG,
+ ("SpxPktBuildSn: Data size %lx\n", pSpxConnFile->scf_MaxPktSize));
+
+ if ((pData =
+ SpxAllocateMemory(
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE)) == NULL)
+ {
+ SpxPktSendRelease(pPkt);
+ break;
+ }
+
+ // Build ndis buffer desc
+ NdisAllocateBuffer(
+ &ndisStatus,
+ &pBuf,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ pData,
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ SpxPktSendRelease(pPkt);
+ SpxFreeMemory(pData);
+ break;
+ }
+
+ // Chain at back.
+ NdisChainBufferAtBack(
+ pPkt,
+ pBuf);
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ pSpxConnFile->scf_MaxPktSize,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl = ( SPX_CC_SYS | SPX_CC_ACK |
+ SPX_CC_NEG | SPX_CC_SPX2);
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ pIpxSpxHdr->hdr_AckNum = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+
+ // Init the data part to indicate no neg values
+ *(UNALIGNED ULONG *)pData = 0;
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_SN;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = (State | SPX_SENDPKT_FREEDATA);
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE;
+ pSendResd->sr_Len = pSpxConnFile->scf_MaxPktSize;
+
+ *ppPkt = pPkt;
+
+ } while (FALSE);
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildSnAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PSPX_SEND_RESD pSendResd;
+
+ do
+ {
+ *ppPkt = NULL;
+
+ // Allocate a ndis packet for the cr.
+ SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ MIN_IPXSPX2_HDRSIZE,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2);
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ pIpxSpxHdr->hdr_AckNum = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_SNACK;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = State;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Len = pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE;
+
+ *ppPkt = pPkt;
+
+ } while (FALSE);
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildSs(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_BUFFER pBuf;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PBYTE pData;
+
+ do
+ {
+ *ppPkt = NULL;
+
+ // Allocate a ndis packet for the cr.
+ SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+
+ CTEAssert(pSpxConnFile->scf_MaxPktSize != 0);
+ DBGPRINT(SEND, DBG,
+ ("SpxPktBuildSs: Data size %lx\n", pSpxConnFile->scf_MaxPktSize));
+
+ if ((pData =
+ SpxAllocateMemory(
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE)) == NULL)
+ {
+ SpxPktSendRelease(pPkt);
+ break;
+ }
+
+ // Build ndis buffer desc
+ NdisAllocateBuffer(
+ &ndisStatus,
+ &pBuf,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ pData,
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ SpxPktSendRelease(pPkt);
+ SpxFreeMemory(pData);
+ break;
+ }
+
+ // Chain at back.
+ NdisChainBufferAtBack(
+ pPkt,
+ pBuf);
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ pSpxConnFile->scf_MaxPktSize,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl =
+ (SPX_CC_SYS | SPX_CC_ACK | SPX_CC_SPX2 |
+ ((pSpxConnFile->scf_Flags & SPX_CONNFILE_NEG) ? SPX_CC_NEG : 0));
+
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ pIpxSpxHdr->hdr_AckNum = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+
+ // Init the data part to indicate no neg values
+ *(UNALIGNED ULONG *)pData = 0;
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_SS;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = (State | SPX_SENDPKT_FREEDATA);
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE;
+ pSendResd->sr_Len = pSpxConnFile->scf_MaxPktSize;
+
+ *ppPkt = pPkt;
+ } while (FALSE);
+
+ return;
+}
+
+
+
+VOID
+SpxPktBuildSsAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PSPX_SEND_RESD pSendResd;
+
+ do
+ {
+ *ppPkt = NULL;
+
+ // Allocate a ndis packet for the cr.
+ SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ MIN_IPXSPX2_HDRSIZE,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl =
+ (SPX_CC_SYS | SPX_CC_SPX2 |
+ ((pSpxConnFile->scf_Flags & SPX_CONNFILE_NEG) ? SPX_CC_NEG : 0));
+
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ pIpxSpxHdr->hdr_AckNum = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_SSACK;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = State;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Len = pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE;
+
+ *ppPkt = pPkt;
+
+ } while (FALSE);
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildRr(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT SeqNum,
+ IN USHORT State
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_BUFFER pBuf;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PBYTE pData;
+
+ do
+ {
+ *ppPkt = NULL;
+
+ // Allocate a ndis packet for the cr.
+ SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ if ((pData =
+ SpxAllocateMemory(
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE)) == NULL)
+ {
+ SpxPktSendRelease(pPkt);
+ break;
+ }
+
+ // Build ndis buffer desc
+ NdisAllocateBuffer(
+ &ndisStatus,
+ &pBuf,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ pData,
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ SpxPktSendRelease(pPkt);
+ SpxFreeMemory(pData);
+ break;
+ }
+
+ // Chain at back.
+ NdisChainBufferAtBack(
+ pPkt,
+ pBuf);
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ pSpxConnFile->scf_MaxPktSize,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl = ( SPX_CC_SYS | SPX_CC_ACK |
+ SPX_CC_NEG | SPX_CC_SPX2);
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+
+ // For a renegotiate request, we use the sequence number of
+ // the first waiting data packet. Passed in.
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SeqNum,
+ SeqNum);
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AckNum,
+ pSpxConnFile->scf_RecvSeqNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+
+ // Init the data part to indicate no neg values
+ *(UNALIGNED ULONG *)pData = 0;
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_RR;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = (State | SPX_SENDPKT_FREEDATA);
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_SeqNum = SeqNum;
+ pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE;
+ pSendResd->sr_Len = pSpxConnFile->scf_MaxPktSize;
+
+ *ppPkt = pPkt;
+
+ } while (FALSE);
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildRrAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN USHORT MaxPktSize
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PSPX_SEND_RESD pSendResd;
+
+ do
+ {
+ *ppPkt = NULL;
+
+ // Allocate a ndis packet for the cr.
+ SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ MIN_IPXSPX2_HDRSIZE,
+ pSpxConnFile->scf_RemAckAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2);
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SeqNum,
+ pSpxConnFile->scf_SendSeqNum);
+
+ // For the RrAck, ack number will be the appropriate number
+ // for the last data packet received.
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AckNum,
+ pSpxConnFile->scf_RenegAckAckNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ MaxPktSize);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxPktBuildRrAck: SEQ %lx ACKNUM %lx ALLOCNUM %lx MAXPKT %lx\n",
+ pSpxConnFile->scf_SendSeqNum,
+ pSpxConnFile->scf_RenegAckAckNum,
+ pSpxConnFile->scf_SentAllocNum,
+ MaxPktSize));
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_RRACK;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = State;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Len = pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE;
+
+ *ppPkt = pPkt;
+
+ } while (FALSE);
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildDisc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PREQUEST pRequest,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN UCHAR DataType
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pDiscPkt;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ USHORT hdrLen;
+ PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr;
+
+
+ *ppPkt = NULL;
+
+ SpxAllocSendPacket(SpxDevice, &pDiscPkt, &ndisStatus);
+ if (ndisStatus == NDIS_STATUS_SUCCESS)
+ {
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pDiscPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ hdrLen = SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE;
+ NdisQueryPacket(pDiscPkt, NULL, NULL, &pNdisMacHdr, NULL);
+ pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr);
+ if (!SPX2_CONN(pSpxConnFile))
+ {
+ NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE);
+ }
+
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ hdrLen,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl =
+ (SPX_CC_ACK |
+ (SPX2_CONN(pSpxConnFile) ? SPX_CC_SPX2 : 0) |
+ ((DataType == SPX2_DT_IDISC) ? 0 : SPX_CC_EOM));
+
+ pIpxSpxHdr->hdr_DataType = DataType;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId =
+ *((UNALIGNED USHORT *)&pSpxConnFile->scf_RemConnId);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SeqNum,
+ pSpxConnFile->scf_SendSeqNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AckNum,
+ pSpxConnFile->scf_RecvSeqNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+
+ if (SPX2_CONN(pSpxConnFile))
+ {
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+ }
+
+ pSendResd = (PSPX_SEND_RESD)(pDiscPkt->ProtocolReserved);
+
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_State = State;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_Type =
+ ((DataType == SPX2_DT_IDISC) ? SPX_TYPE_IDISC : SPX_TYPE_ORDREL);
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Request = pRequest;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Offset = 0;
+ pSendResd->sr_SeqNum = pSpxConnFile->scf_SendSeqNum;
+ pSendResd->sr_Len =
+ pSendResd->sr_HdrLen = hdrLen;
+
+ *ppPkt = pDiscPkt;
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildProbe(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fSpx2
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pProbe;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ USHORT hdrLen;
+ PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr;
+
+
+ *ppPkt = NULL;
+
+ SpxAllocSendPacket(SpxDevice, &pProbe, &ndisStatus);
+ if (ndisStatus == NDIS_STATUS_SUCCESS)
+ {
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pProbe +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ hdrLen = (fSpx2 ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE);
+
+ NdisQueryPacket(pProbe, NULL, NULL, &pNdisMacHdr, NULL);
+ pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr);
+ if (!fSpx2)
+ {
+ NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE);
+ }
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ hdrLen,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | SPX_CC_ACK |
+ (fSpx2 ? SPX_CC_SPX2 : 0));
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId =
+ *((UNALIGNED USHORT *)&pSpxConnFile->scf_RemConnId);
+
+ if (fSpx2)
+ {
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+ }
+ else
+ {
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SeqNum,
+ pSpxConnFile->scf_SendSeqNum);
+ }
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AckNum,
+ pSpxConnFile->scf_RecvSeqNum);
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+
+ pSendResd = (PSPX_SEND_RESD)(pProbe->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_PROBE;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = State;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Len =
+ pSendResd->sr_HdrLen = (fSpx2 ? MIN_IPXSPX2_HDRSIZE
+ : MIN_IPXSPX_HDRSIZE);
+
+ *ppPkt = pProbe;
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildData(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN USHORT Length
+ )
+/*++
+
+Routine Description:
+
+ Handles zero length sends.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_BUFFER pNdisBuffer;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pDataPkt;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ USHORT hdrLen;
+ PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr;
+
+ *ppPkt = NULL;
+
+ SpxAllocSendPacket(SpxDevice, &pDataPkt, &ndisStatus);
+ if (ndisStatus == NDIS_STATUS_SUCCESS)
+ {
+ // Make a ndis buffer descriptor for the data if present.
+ if (Length > 0)
+ {
+ SpxCopyBufferChain(
+ &ndisStatus,
+ &pNdisBuffer,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ REQUEST_TDI_BUFFER(pSpxConnFile->scf_ReqPkt),
+ pSpxConnFile->scf_ReqPktOffset,
+ Length);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ // Free the send packet
+ SpxPktSendRelease(pDataPkt);
+ return;
+ }
+
+ // Chain this in the packet
+ NdisChainBufferAtBack(pDataPkt, pNdisBuffer);
+ }
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pDataPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ hdrLen = SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE;
+ Length += hdrLen;
+
+ NdisQueryPacket(pDataPkt, NULL, NULL, &pNdisMacHdr, NULL);
+ pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr);
+ if (!SPX2_CONN(pSpxConnFile))
+ {
+ NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE);
+ }
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ Length,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl =
+ (((State & SPX_SENDPKT_ACKREQ) ? SPX_CC_ACK : 0) |
+ ((State & SPX_SENDPKT_EOM) ? SPX_CC_EOM : 0) |
+ (SPX2_CONN(pSpxConnFile) ? SPX_CC_SPX2 : 0));
+
+ pIpxSpxHdr->hdr_DataType = (UCHAR)REQUEST_PARAMETERS(pSpxConnFile->scf_ReqPkt)->Others.Argument3;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId =
+ *((UNALIGNED USHORT *)&pSpxConnFile->scf_RemConnId);
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SeqNum,
+ pSpxConnFile->scf_SendSeqNum);
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AckNum,
+ pSpxConnFile->scf_RecvSeqNum);
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+
+ if (SPX2_CONN(pSpxConnFile))
+ {
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+ }
+
+ pSendResd = (PSPX_SEND_RESD)(pDataPkt->ProtocolReserved);
+
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_State = State;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_Type = SPX_TYPE_DATA;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Request = pSpxConnFile->scf_ReqPkt;
+ pSendResd->sr_Offset = pSpxConnFile->scf_ReqPktOffset;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_SeqNum = pSpxConnFile->scf_SendSeqNum;
+ pSendResd->sr_Len = Length;
+ pSendResd->sr_HdrLen = hdrLen;
+
+ if (State & SPX_SENDPKT_ACKREQ)
+ {
+ KeQuerySystemTime((PLARGE_INTEGER)&pSendResd->sr_SentTime);
+ }
+
+ CTEAssert(pSendResd->sr_Len <= pSpxConnFile->scf_MaxPktSize);
+ *ppPkt = pDataPkt;
+
+ // Ok, allocation succeeded. Increment send seq.
+ pSpxConnFile->scf_SendSeqNum++;
+ }
+
+ return;
+}
+
+
+VOID
+SpxCopyBufferChain(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_BUFFER * TargetChain,
+ IN NDIS_HANDLE PoolHandle,
+ IN PNDIS_BUFFER SourceChain,
+ IN UINT Offset,
+ IN UINT Length
+ )
+/*++
+
+Routine Description:
+
+ Creates a TargetBufferChain from the SourceBufferChain. The copy begins at
+ the 'Offset' location in the source chain. It copies 'Length' bytes. It also
+ handles Length = 0. If we run out of source chain before copying length amount
+ of bytes or run out of memory to create any more buffers for the target chain,
+ we clean up the partial chain created so far.
+
+Arguments:
+
+ Status - Status of the request.
+ TargetChain - Pointer to the allocated buffer descriptor.
+ PoolHandle - Handle that is used to specify the pool.
+ SourceChain - Pointer to the descriptor of the source memory.
+ Offset - The Offset in the sources memory from which the copy is to
+ begin
+ Length - Number of Bytes to copy.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UINT BytesBeforeCurBuffer = 0;
+ PNDIS_BUFFER CurBuffer = SourceChain;
+ UINT BytesLeft;
+ UINT AvailableBytes;
+ PNDIS_BUFFER NewNdisBuffer, StartTargetChain;
+
+ CTEAssert( SourceChain );
+
+ // First of all find the source buffer that contains data that starts at
+ // Offset.
+ NdisQueryBuffer( CurBuffer, NULL, &AvailableBytes );
+ while ( BytesBeforeCurBuffer + AvailableBytes <= Offset ) {
+ BytesBeforeCurBuffer += AvailableBytes;
+ CurBuffer = CurBuffer->Next;
+ if ( CurBuffer ) {
+ NdisQueryBuffer( CurBuffer, NULL, &AvailableBytes );
+ } else {
+ break;
+ }
+ }
+
+ if ( ! CurBuffer ) {
+ *Status = STATUS_UNSUCCESSFUL;
+ return;
+ }
+
+ //
+ // Copy the first buffer. This takes care of Length = 0.
+ //
+ BytesLeft = Length;
+
+ //
+ // ( Offset - BytesBeforeCurBuffer ) gives us the offset within this buffer.
+ //
+
+ AvailableBytes -= ( Offset - BytesBeforeCurBuffer );
+
+ if ( AvailableBytes > BytesLeft ) {
+ AvailableBytes = BytesLeft;
+ }
+
+ NdisCopyBuffer(
+ Status,
+ &NewNdisBuffer,
+ PoolHandle,
+ CurBuffer,
+ Offset - BytesBeforeCurBuffer,
+ AvailableBytes);
+
+ if ( *Status != NDIS_STATUS_SUCCESS ) {
+ return;
+ }
+
+ StartTargetChain = NewNdisBuffer;
+ BytesLeft -= AvailableBytes;
+
+ //
+ // Did the first buffer have enough data. If so, we r done.
+ //
+ if ( ! BytesLeft ) {
+ *TargetChain = StartTargetChain;
+ return;
+ }
+
+ //
+ // Now follow the Mdl chain and copy more buffers.
+ //
+ CurBuffer = CurBuffer->Next;
+ NdisQueryBuffer( CurBuffer, NULL, &AvailableBytes );
+ while ( CurBuffer ) {
+
+ if ( AvailableBytes > BytesLeft ) {
+ AvailableBytes = BytesLeft;
+ }
+
+ NdisCopyBuffer(
+ Status,
+ &(NDIS_BUFFER_LINKAGE(NewNdisBuffer)),
+ PoolHandle,
+ CurBuffer,
+ 0,
+ AvailableBytes);
+
+ if ( *Status != NDIS_STATUS_SUCCESS ) {
+
+ //
+ // ran out of resources. put back what we've used in this call and
+ // return the error.
+ //
+
+ while ( StartTargetChain != NULL) {
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE( StartTargetChain );
+ NdisFreeBuffer ( StartTargetChain );
+ StartTargetChain = NewNdisBuffer;
+ }
+
+ return;
+ }
+
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE(NewNdisBuffer);
+ BytesLeft -= AvailableBytes;
+
+ if ( ! BytesLeft ) {
+ *TargetChain = StartTargetChain;
+ return;
+ }
+
+ CurBuffer = CurBuffer->Next;
+ NdisQueryBuffer( CurBuffer, NULL, &AvailableBytes );
+ }
+
+ //
+ // Ran out of source chain. This should not happen.
+ //
+
+ CTEAssert( FALSE );
+
+ // For Retail build we clean up anyways.
+
+ while ( StartTargetChain != NULL) {
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE( StartTargetChain );
+ NdisFreeBuffer ( StartTargetChain );
+ StartTargetChain = NewNdisBuffer;
+ }
+
+ *Status = STATUS_UNSUCCESSFUL;
+ return;
+}
+
+
+VOID
+SpxPktBuildAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fBuildNack,
+ IN USHORT NumToResend
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ PIPXSPX_HDR pIpxSpxHdr;
+ NDIS_STATUS ndisStatus;
+ USHORT hdrLen;
+ PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr;
+
+ BOOLEAN fSpx2 = SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2);
+
+ *ppPkt = NULL;
+
+ SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ DBGPRINT(SEND, ERR,
+ ("SpxPktBuildAck: Could not allocate ndis packet\n"));
+ return;
+ }
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ hdrLen = SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE;
+ NdisQueryPacket(pPkt, NULL, NULL, &pNdisMacHdr, NULL);
+ pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr);
+ if (!fSpx2)
+ {
+ NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE);
+ }
+
+ // Send where data came from
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ hdrLen,
+ pSpxConnFile->scf_RemAckAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | (fSpx2 ? SPX_CC_SPX2 : 0));
+
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AckNum,
+ pSpxConnFile->scf_RecvSeqNum);
+
+ if (fSpx2)
+ {
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ if (fBuildNack)
+ {
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SeqNum,
+ NumToResend);
+ }
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+ }
+ else
+ {
+ // Put current send seq number in packet for spx1
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SeqNum,
+ pSpxConnFile->scf_SendSeqNum);
+ }
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = (fBuildNack ? SPX_TYPE_DATANACK : SPX_TYPE_DATAACK);
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = State;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Len = pSendResd->sr_HdrLen = hdrLen;
+
+ *ppPkt = pPkt;
+ return;
+}
+
+
+
+VOID
+SpxPktRecvRelease(
+ IN PNDIS_PACKET pPkt
+ )
+{
+ ((PSPX_RECV_RESD)(pPkt->ProtocolReserved))->rr_State = SPX_RECVPKT_IDLE;
+ SpxFreeRecvPacket(SpxDevice, pPkt);
+ return;
+}
+
+
+
+
+VOID
+SpxPktSendRelease(
+ IN PNDIS_PACKET pPkt
+ )
+{
+ PNDIS_BUFFER pBuf, pIpxSpxBuf, pFreeBuf;
+ UINT bufCount;
+
+ CTEAssert((((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_State &
+ SPX_SENDPKT_IPXOWNS) == 0);
+
+ NdisQueryPacket(pPkt, NULL, &bufCount, &pBuf, NULL);
+
+ // BufCount == 1 for only the header. That's ok, we just reset the length
+ // and free the packet to the buffer pools. Else we need to free user buffers
+ // before that.
+
+ NdisUnchainBufferAtFront(
+ pPkt,
+ &pBuf);
+
+ NdisUnchainBufferAtFront(
+ pPkt,
+ &pIpxSpxBuf);
+
+ //
+ // Set the header length to the max. that can be needed.
+ //
+ NdisAdjustBufferLength(pIpxSpxBuf, MIN_IPXSPX2_HDRSIZE);
+
+ while (bufCount-- > 2)
+ {
+ PBYTE pData;
+ ULONG dataLen;
+
+ NdisUnchainBufferAtBack(
+ pPkt,
+ &pFreeBuf);
+
+ // See if we free data associated with the buffer
+ if ((((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_State &
+ SPX_SENDPKT_FREEDATA) != 0)
+ {
+ NdisQueryBuffer(pFreeBuf, &pData, &dataLen);
+ CTEAssert(pData != NULL);
+ SpxFreeMemory(pData);
+ }
+
+ CTEAssert(pFreeBuf != NULL);
+ NdisFreeBuffer(pFreeBuf);
+ }
+
+ NdisReinitializePacket(pPkt);
+
+ // Initialize elements of the protocol reserved structure.
+ ((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_Id = IDENTIFIER_SPX;
+ ((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_State = SPX_SENDPKT_IDLE;
+ ((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_Reserved1= NULL;
+ ((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_Reserved2= NULL;
+
+ NdisChainBufferAtFront(
+ pPkt,
+ pBuf);
+
+ NdisChainBufferAtBack(
+ pPkt,
+ pIpxSpxBuf);
+
+ SpxFreeSendPacket(SpxDevice, pPkt);
+ return;
+}
diff --git a/private/ntos/tdi/isnp/spx/spxquery.c b/private/ntos/tdi/isnp/spx/spxquery.c
new file mode 100644
index 000000000..047ecabe8
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/spxquery.c
@@ -0,0 +1,259 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxquery.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiQueryInformation
+
+Author:
+
+ Adam Barr (adamba) Initial Version
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Discardable code after Init time
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT, SpxQueryInitProviderInfo)
+#endif
+
+// Define module number for event logging entries
+#define FILENUM SPXQUERY
+
+// Useful macro to obtain the total length of an MDL chain.
+#define SpxGetMdlChainLength(Mdl, Length) { \
+ PMDL _Mdl = (Mdl); \
+ *(Length) = 0; \
+ while (_Mdl) { \
+ *(Length) += MmGetMdlByteCount(_Mdl); \
+ _Mdl = _Mdl->Next; \
+ } \
+}
+
+
+
+VOID
+SpxQueryInitProviderInfo(
+ PTDI_PROVIDER_INFO ProviderInfo
+ )
+{
+ // Initialize to defaults first
+ RtlZeroMemory((PVOID)ProviderInfo, sizeof(TDI_PROVIDER_INFO));
+
+ ProviderInfo->Version = SPX_TDI_PROVIDERINFO_VERSION;
+ KeQuerySystemTime (&ProviderInfo->StartTime);
+ ProviderInfo->MinimumLookaheadData = SPX_PINFOMINMAXLOOKAHEAD;
+ ProviderInfo->MaximumLookaheadData = IpxLineInfo.MaximumPacketSize;
+ ProviderInfo->MaxSendSize = SPX_PINFOSENDSIZE;
+ ProviderInfo->ServiceFlags = SPX_PINFOSERVICEFLAGS;
+ return;
+}
+
+
+
+
+NTSTATUS
+SpxTdiQueryInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiQueryInformation request for the transport
+ provider.
+
+Arguments:
+
+ Request - the request for the operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PSPX_ADDR_FILE AddressFile;
+ PSPX_CONN_FILE ConnectionFile;
+ PTDI_REQUEST_KERNEL_QUERY_INFORMATION query;
+ struct {
+ ULONG ActivityCount;
+ TA_IPX_ADDRESS SpxAddress;
+ } AddressInfo;
+
+
+
+ // what type of status do we want?
+ query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)REQUEST_PARAMETERS(Request);
+
+ switch (query->QueryType)
+ {
+ case TDI_QUERY_CONNECTION_INFO:
+
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ case TDI_QUERY_ADDRESS_INFO:
+
+ // The caller wants the exact address value.
+
+ ConnectionFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(Request);
+ status = SpxConnFileVerify(ConnectionFile);
+
+ if (status == STATUS_SUCCESS) {
+ AddressFile = ConnectionFile->scf_AddrFile;
+ SpxConnFileDereference(ConnectionFile, CFREF_VERIFY);
+ } else {
+ AddressFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(Request);
+ }
+
+ status = SpxAddrFileVerify(AddressFile);
+
+ if (status == STATUS_SUCCESS)
+ {
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxTdiQuery: Net.Socket %lx.%lx\n",
+ *(PULONG)Device->dev_Network,
+ AddressFile->saf_Addr->sa_Socket));
+
+ AddressInfo.ActivityCount = 0;
+ (VOID)SpxBuildTdiAddress(
+ &AddressInfo.SpxAddress,
+ sizeof(TA_IPX_ADDRESS),
+ Device->dev_Network,
+ Device->dev_Node,
+ AddressFile->saf_Addr->sa_Socket);
+
+ status = TdiCopyBufferToMdl(
+ &AddressInfo,
+ 0,
+ sizeof(AddressInfo),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ SpxAddrFileDereference(AddressFile, AFREF_VERIFY);
+
+ }
+
+ break;
+
+ case TDI_QUERY_PROVIDER_INFO: {
+ BYTE socketType;
+ TDI_PROVIDER_INFO providerInfo = Device->dev_ProviderInfo;
+
+ //
+ // The device name extension comes down in the Irp
+ //
+ if (!NT_SUCCESS(status = SpxUtilGetSocketType(
+ REQUEST_OPEN_NAME(Request),
+ &socketType))) {
+ DBGPRINT(RECEIVE, ERR, ("TDI_QUERY_PROVIDER_INFO: SpxUtilGetSocketType failed: %lx\n", status));
+ return(status);
+ }
+
+ //
+ // The Catapult folks had a problem where AFD was discarding buffered sends on the NT box when it got a
+ // local disconnect on SPX1. This was because the Orderly release flag was always set in the provider
+ // info. AFD queries this once per device type. We detect the device above and OR in the orderly release
+ // flag if this query came down on an SPX2 endpoint.
+ // This is to make sure that AFD follows the correct disconnect semantics for SPX1 and SPX2 (SPX1 does
+ // only abortive; SPX2 does both abortive and orderly).
+ //
+ // BUGBUG: this will still not solve the problem completely since a connection that starts off as an SPX2
+ // one can still be negotiated to SPX1 if the remote supports only SPX1.
+ //
+ if ((socketType == SOCKET2_TYPE_SEQPKT) ||
+ (socketType == SOCKET2_TYPE_STREAM)) {
+
+ DBGPRINT(RECEIVE, INFO, ("TDI_QUERY_PROVIDER_INFO: SPX2 socket\n"));
+ providerInfo.ServiceFlags |= TDI_SERVICE_ORDERLY_RELEASE;
+ } else {
+ DBGPRINT(RECEIVE, INFO, ("TDI_QUERY_PROVIDER_INFO: SPX1 socket\n"));
+ }
+
+ status = TdiCopyBufferToMdl (
+ &providerInfo,
+ 0,
+ sizeof (TDI_PROVIDER_INFO),
+ REQUEST_TDI_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+ }
+
+ case TDI_QUERY_PROVIDER_STATISTICS:
+
+ status = TdiCopyBufferToMdl (
+ &Device->dev_Stat,
+ 0,
+ FIELD_OFFSET (TDI_PROVIDER_STATISTICS, ResourceStats[0]),
+ REQUEST_TDI_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ default:
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ return status;
+
+} // SpxTdiQueryInformation
+
+
+
+NTSTATUS
+SpxTdiSetInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetInformation request for the transport
+ provider.
+
+Arguments:
+
+ Device - the device.
+
+ Request - the request for the operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (Device);
+ UNREFERENCED_PARAMETER (Request);
+
+ return STATUS_NOT_IMPLEMENTED;
+
+} // SpxTdiSetInformation
+
diff --git a/private/ntos/tdi/isnp/spx/spxrecv.c b/private/ntos/tdi/isnp/spx/spxrecv.c
new file mode 100644
index 000000000..2408f25e8
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/spxrecv.c
@@ -0,0 +1,2837 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxrecv.c
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 5-July-1995
+ Bug fixes - tagged [SA]
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXRECV
+
+VOID
+SpxReceive(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ )
+
+{
+ PIPXSPX_HDR pHdr;
+
+ // We have a separate routine to process SYS packets. DATA packets are
+ // processed within this routine.
+ if (LookaheadBufferSize < MIN_IPXSPX_HDRSIZE)
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxReceive: Invalid length %lx\n", LookaheadBufferSize));
+
+ return;
+ }
+
+ ++SpxDevice->dev_Stat.PacketsReceived;
+
+ pHdr = (PIPXSPX_HDR)LookaheadBuffer;
+ if ((pHdr->hdr_ConnCtrl & SPX_CC_SYS) == 0)
+ {
+ // Check for data packets
+ if ((pHdr->hdr_DataType != SPX2_DT_ORDREL) &&
+ (pHdr->hdr_DataType != SPX2_DT_IDISC) &&
+ (pHdr->hdr_DataType != SPX2_DT_IDISC_ACK))
+ {
+ // HANDLE DATA PACKET
+ SpxRecvDataPacket(
+ MacBindingHandle,
+ MacReceiveContext,
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ LookaheadBufferOffset,
+ PacketSize);
+ }
+ else
+ {
+ // The whole packet better be in the lookahead, else we ignore.
+ if (LookaheadBufferSize == PacketSize)
+ {
+ SpxRecvDiscPacket(
+ LookaheadBuffer,
+ RemoteAddress,
+ LookaheadBufferSize);
+ }
+ }
+ }
+ else
+ {
+ SpxRecvSysPacket(
+ MacBindingHandle,
+ MacReceiveContext,
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ LookaheadBufferOffset,
+ PacketSize);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxTransferDataComplete(
+ IN PNDIS_PACKET pNdisPkt,
+ IN NDIS_STATUS NdisStatus,
+ IN UINT BytesTransferred
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pSpxConnFile;
+ PREQUEST pRequest;
+ PSPX_RECV_RESD pRecvResd;
+ CTELockHandle lockHandle;
+ NTSTATUS status;
+ BOOLEAN fAck, fEom, fBuffered, fImmedAck, fLockHeld;
+ PNDIS_BUFFER pNdisBuffer;
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxTransferData: For %lx with status %lx\n", pNdisPkt, NdisStatus));
+
+ pRecvResd = RECV_RESD(pNdisPkt);
+ pSpxConnFile = pRecvResd->rr_ConnFile;
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ fLockHeld = TRUE;
+
+ fEom = ((pRecvResd->rr_State & SPX_RECVPKT_EOM) != 0);
+ fImmedAck = ((pRecvResd->rr_State & SPX_RECVPKT_IMMEDACK) != 0);
+ fBuffered = ((pRecvResd->rr_State & SPX_RECVPKT_BUFFERING) != 0);
+ fAck = ((pRecvResd->rr_State & SPX_RECVPKT_SENDACK) != 0);
+
+ // Check if receive is done. If we remove the reference for this
+ // packet and it goes to zero, that means the receive was aborted.
+ // Move to the completion queue.
+ // If receive is filled up, then remove the creation reference
+ // i.e. just complete the receive at this point.
+ // There can be only one packet per receive, we dont support
+ // out of order reception.
+
+ if (!fBuffered)
+ {
+ // Get pointer to the buffer descriptor and its memory.
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ CTEAssert((pNdisBuffer != NULL) || (BytesTransferred == 0));
+
+ // BUG #11772
+ // On MP-machines scf_CurRecvReq could be set to NULL. Get the req
+ // from the recv packet.
+ // pRequest = pSpxConnFile->scf_CurRecvReq;
+ // CTEAssert(pRequest == pRecvResd->rr_Request);
+ pRequest = pRecvResd->rr_Request;
+
+ // Remove reference for this packet.
+ --(REQUEST_INFORMATION(pRequest));
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS)
+ {
+ pSpxConnFile->scf_CurRecvOffset += BytesTransferred;
+ pSpxConnFile->scf_CurRecvSize -= BytesTransferred;
+
+#if DBG
+ if ((pRecvResd->rr_State & SPX_RECVPKT_INDICATED) != 0)
+ {
+ if (BytesTransferred != 0)
+ {
+ CTEAssert (pSpxConnFile->scf_IndBytes != 0);
+ pSpxConnFile->scf_IndBytes -= BytesTransferred;
+ }
+ }
+#endif
+
+ if (REQUEST_INFORMATION(pRequest) == 0)
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxTransferDataComplete: Request %lx ref %lx Cur %lx.%lx\n",
+ pRequest, REQUEST_INFORMATION(pRequest),
+ REQUEST_STATUS(pRequest),
+ pSpxConnFile->scf_CurRecvSize));
+
+ if (SPX_CONN_STREAM(pSpxConnFile) ||
+ (pSpxConnFile->scf_CurRecvSize == 0) ||
+ fEom ||
+ ((REQUEST_STATUS(pRequest) != STATUS_SUCCESS) &&
+ (REQUEST_STATUS(pRequest) != STATUS_RECEIVE_PARTIAL)))
+ {
+ CTELockHandle lockHandleInter;
+
+ // We are done with this receive.
+ REQUEST_INFORMATION(pRequest) = pSpxConnFile->scf_CurRecvOffset;
+
+ status = STATUS_SUCCESS;
+ if (!SPX_CONN_STREAM(pSpxConnFile) &&
+ (pSpxConnFile->scf_CurRecvSize == 0) &&
+ !fEom)
+ {
+ status = STATUS_RECEIVE_PARTIAL;
+ }
+
+ if ((REQUEST_STATUS(pRequest) != STATUS_SUCCESS) &&
+ (REQUEST_STATUS(pRequest) != STATUS_RECEIVE_PARTIAL))
+ {
+ status = REQUEST_STATUS(pRequest);
+ }
+
+ REQUEST_STATUS(pRequest) = status;
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxTransferDataComplete: Request %lx ref %lx Cur %lx.%lx\n",
+ pRequest, REQUEST_INFORMATION(pRequest),
+ REQUEST_STATUS(pRequest),
+ pSpxConnFile->scf_CurRecvSize));
+
+ // Dequeue this request, Set next recv if one exists.
+ SPX_CONN_SETNEXT_CUR_RECV(pSpxConnFile, pRequest);
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_RecvDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ }
+ }
+
+ if (pNdisBuffer != NULL)
+ {
+ NdisFreeBuffer(pNdisBuffer);
+ }
+ }
+ else
+ {
+ // Buffered receive, queue it in if successful.
+ // BUG #18363
+ // IF WE DISCONNECTED in the meantime, we need to just dump this
+ // packet.
+ if (SPX_CONN_ACTIVE(pSpxConnFile) &&
+ (NdisStatus == NDIS_STATUS_SUCCESS))
+ {
+ // Queue packet in connection. Reference connection for this.
+ SpxConnQueueRecvPktTail(pSpxConnFile, pNdisPkt);
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxTransferData: Buffering: %lx Pkt %lx Size %lx F %lx\n",
+ pSpxConnFile, pNdisPkt, BytesTransferred, pRecvResd->rr_State));
+
+ // There could either be queued receives. (This could happen in
+ // a partial receive case. Or if a receive got queued in while we
+ // were processing this packet (Possible on MP)), or a packet was
+ // buffered while we were completing some receives
+
+ CTEAssert(pSpxConnFile->scf_RecvListHead);
+
+ if ((pSpxConnFile->scf_CurRecvReq != NULL) ||
+ ((pSpxConnFile->scf_RecvListHead->rr_State &
+ SPX_RECVPKT_INDICATED) == 0))
+ {
+ CTELockHandle interLockHandle;
+
+ // Push this connection into a ProcessRecv queue which will be
+ // dealt with in receive completion.
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxRecvTransferData: Queueing for recvp %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_Flags));
+
+ // Get the global q lock, push into recv list.
+ CTEGetLock(&SpxGlobalQInterlock, &interLockHandle);
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, interLockHandle);
+ }
+ }
+ else
+ {
+ PBYTE pData;
+ ULONG dataLen;
+
+ // Get pointer to the buffer descriptor and its memory.
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ if (pNdisBuffer != NULL)
+ {
+ NdisQueryBuffer(pNdisBuffer, &pData, &dataLen);
+ CTEAssert(pData != NULL);
+ CTEAssert(dataLen >= 0);
+
+ // Free the data, ndis buffer.
+ if (pNdisBuffer != NULL)
+ {
+ NdisFreeBuffer(pNdisBuffer);
+ }
+ SpxFreeMemory(pData);
+ }
+
+ // Dont send ack, set status to be failure so we free packet/buffer.
+ fAck = FALSE;
+ NdisStatus = NDIS_STATUS_FAILURE;
+ }
+ }
+
+ END_PROCESS_PACKET(
+ pSpxConnFile, fBuffered, (NdisStatus == NDIS_STATUS_SUCCESS));
+
+ if (fAck)
+ {
+ // Rem ack addr should have been copied in receive.
+
+ // #17564
+ if (fImmedAck ||
+ SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_NOACKWAIT) ||
+ SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IMMED_ACK))
+ {
+ SpxConnSendAck(pSpxConnFile, lockHandle);
+ fLockHeld = FALSE;
+ }
+ else
+ {
+ SpxConnQWaitAck(pSpxConnFile);
+ }
+ }
+
+ if (fLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ if (!fBuffered || (NdisStatus != STATUS_SUCCESS))
+ {
+ // Free the ndis packet/buffer
+ SpxPktRecvRelease(pNdisPkt);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxReceiveComplete(
+ IN USHORT NicId
+ )
+
+{
+ CTELockHandle lockHandleInter, lockHandle;
+ PREQUEST pRequest;
+ BOOLEAN fConnLockHeld, fInterlockHeld;
+ PSPX_CONN_FILE pSpxConnFile;
+ int numDerefs = 0;
+
+ // See if any connections need recv processing. This will also take
+ // care of any acks opening up window so our sends go to the max.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ fInterlockHeld = TRUE;
+
+ while ((pSpxConnFile = SpxRecvConnList.pcl_Head) != NULL)
+ {
+ // Reset for each connection
+ numDerefs = 0;
+
+ if ((SpxRecvConnList.pcl_Head = pSpxConnFile->scf_ProcessRecvNext) == NULL)
+ SpxRecvConnList.pcl_Tail = NULL;
+
+ // Reset next field to NULL
+ pSpxConnFile->scf_ProcessRecvNext = NULL;
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnRemoveFromRecv: %lx\n", pSpxConnFile));
+
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+
+ do
+ {
+ // Complete pending requests.
+ while (!IsListEmpty(&pSpxConnFile->scf_ReqDoneLinkage))
+ {
+ pRequest =
+ LIST_ENTRY_TO_REQUEST(pSpxConnFile->scf_ReqDoneLinkage.Flink);
+
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ DBGPRINT(TDI, DBG,
+ ("SpxReceiveComplete: Completing %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ CTEAssert (REQUEST_MINOR_FUNCTION(pRequest) != TDI_RECEIVE);
+ SpxCompleteRequest(pRequest);
+ numDerefs++;
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ }
+
+ // Call process pkts if we have any packets or if any receives to
+ // complete. Note this will call even when there are no receives
+ // queued and the first packet has already been indicated.
+ if ((SPX_RECV_STATE(pSpxConnFile) != SPX_RECV_PROCESS_PKTS) &&
+ (!IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage) ||
+ (pSpxConnFile->scf_RecvListHead != NULL)))
+ {
+ // We have the flag reference on the connection.
+ SpxRecvProcessPkts(pSpxConnFile, lockHandle);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ }
+
+#if DBG
+ if (!IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxReceiveComplete: RecvDone left %lx\n",
+ pSpxConnFile));
+ }
+#endif
+
+ // Hmm. This check is rather expensive, and essentially we are doing
+ // it twice. Should look to see if this can be modified safely.
+ } while ((!IsListEmpty(&pSpxConnFile->scf_ReqDoneLinkage)) ||
+ ((SPX_RECV_STATE(pSpxConnFile) != SPX_RECV_PROCESS_PKTS) &&
+ ((!IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage)) ||
+ ((pSpxConnFile->scf_RecvListHead != NULL) &&
+ ((pSpxConnFile->scf_RecvListHead->rr_State &
+ (SPX_RECVPKT_BUFFERING | SPX_RECVPKT_INDICATED)) ==
+ SPX_RECVPKT_BUFFERING)))));
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_RECVQ);
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_RECV,
+ CFREF_VERIFY);
+
+ numDerefs++;
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ }
+
+
+ // First see if we need to packetize.
+ while ((pSpxConnFile = SpxPktConnList.pcl_Head) != NULL)
+ {
+ if ((SpxPktConnList.pcl_Head = pSpxConnFile->scf_PktNext) == NULL)
+ SpxPktConnList.pcl_Tail = NULL;
+
+ // Reset next field to NULL
+ pSpxConnFile->scf_PktNext = NULL;
+
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnRemoveFromPkt: %lx\n", pSpxConnFile));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ fConnLockHeld = TRUE;
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxReceiveComplete: Packetizing %lx\n", pSpxConnFile));
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_PKTQ);
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE)
+ {
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_PACKETIZE);
+ if (SpxConnPacketize(
+ pSpxConnFile,
+ TRUE,
+ lockHandle))
+ {
+ // Done.
+ fConnLockHeld = FALSE;
+ }
+ }
+
+ if (fConnLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ SpxConnFileDereference(pSpxConnFile, CFREF_PKTIZE);
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ }
+
+ if (fInterlockHeld)
+ {
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+
+ return;
+}
+
+
+
+
+//
+// PACKET HANDLING ROUTINES
+//
+
+
+VOID
+SpxRecvSysPacket(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ )
+/*++
+
+Routine Description:
+
+ This is called to indicate an incoming system packet.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ PIPXSPX_HDR pHdr;
+ USHORT srcConnId, destConnId,
+ pktLen, ackNum, allocNum;
+ PSPX_CONN_FILE pSpxConnFile;
+ CTELockHandle lockHandle;
+ BOOLEAN lockHeld = FALSE;
+
+ pHdr = (PIPXSPX_HDR)LookaheadBuffer;
+
+ // check minimum length
+ if (PacketSize < MIN_IPXSPX_HDRSIZE)
+ {
+ return;
+ }
+
+ // Convert hdr to host format as needed.
+ GETSHORT2SHORT(&pktLen, &pHdr->hdr_PktLen);
+ GETSHORT2SHORT(&destConnId, &pHdr->hdr_DestConnId);
+
+ if ((pktLen < MIN_IPXSPX_HDRSIZE) ||
+ (pktLen > PacketSize) ||
+ (pHdr->hdr_PktType != SPX_PKT_TYPE))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxRecvSysPacket: Packet Size %lx.%lx\n",
+ pktLen, PacketSize));
+
+ return;
+ }
+
+ if ((pktLen == SPX_CR_PKTLEN) &&
+ (destConnId == 0xFFFF) &&
+ (pHdr->hdr_ConnCtrl & SPX_CC_CR))
+ {
+ spxConnHandleConnReq(
+ pHdr,
+ pRemoteAddr);
+
+ return;
+ }
+
+ //
+ // [SA] Bug #14917
+ // Some SPX SYS packets (no extended ack field) may come in with the SPX2 bit set.
+ // Make sure we don't discard these packets.
+ //
+
+ // if ((pHdr->hdr_ConnCtrl & SPX_CC_SPX2) && (pktLen < MIN_IPXSPX2_HDRSIZE))
+ // {
+ // return;
+ // }
+
+ GETSHORT2SHORT(&ackNum, &pHdr->hdr_AckNum);
+ GETSHORT2SHORT(&allocNum, &pHdr->hdr_AllocNum);
+
+ // We keep and use the remote id in the net format. This maintains the
+ // 0x0 and 0xFFFF to be as in the host format.
+ srcConnId = *(USHORT UNALIGNED *)&pHdr->hdr_SrcConnId;
+
+ if ((srcConnId == 0) || (srcConnId == 0xFFFF) || (destConnId == 0))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnSysPacket: Incorrect conn id %lx.%lx\n",
+ srcConnId, destConnId));
+
+ return;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnSysPacket: packet received dest %lx src %lx\n",
+ pHdr->hdr_DestSkt, pHdr->hdr_SrcSkt));
+
+ // Find the connection this is destined for and reference it.
+ SpxConnFileReferenceById(destConnId, &pSpxConnFile, &status);
+ if (!NT_SUCCESS(status))
+ {
+ DBGPRINT(RECEIVE, WARN,
+ ("SpxConnSysPacket: Id %lx NOT FOUND\n", destConnId));
+ return;
+ }
+
+ do
+ {
+
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnSysPacket: Id %lx Conn %lx\n",
+ destConnId, pSpxConnFile));
+
+ // This could be one of many packets. Connection ack/Session negotiate/
+ // Session setup, Data Ack, Probe/Ack, Renegotiate/Ack. We shunt
+ // off all the packets to different routines but process the data
+ // ack packets here.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ //
+ // We have the connection. We should update the dest. sock # in
+ // it in case it changed. Unix machines do do that sometimes.
+ // SCO bug 7676
+ //
+ SpxCopyIpxAddr(pHdr, pSpxConnFile->scf_RemAddr);
+
+ lockHeld = TRUE;
+
+ // Restart watchdog timer if started.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER))
+ {
+ // This will either successfully restart or not affect the timer
+ // if it is currently running.
+ SpxTimerCancelEvent(
+ pSpxConnFile->scf_WTimerId,
+ TRUE);
+
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+ }
+
+ switch (SPX_MAIN_STATE(pSpxConnFile))
+ {
+ case SPX_CONNFILE_CONNECTING:
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ lockHeld = FALSE;
+
+ spxConnHandleSessPktFromSrv(
+ pHdr,
+ pRemoteAddr,
+ pSpxConnFile);
+
+ break;
+
+ case SPX_CONNFILE_LISTENING:
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ lockHeld = FALSE;
+
+ spxConnHandleSessPktFromClient(
+ pHdr,
+ pRemoteAddr,
+ pSpxConnFile);
+
+ break;
+
+ case SPX_CONNFILE_ACTIVE:
+ case SPX_CONNFILE_DISCONN:
+
+ // NOTE: Our ack to a session setup might get dropped.
+ // But the SS Ack is similar to a normal SPX2 ack.
+ // We dont have to do anything special.
+
+ // Received ack/nack/reneg/reneg ack/disc associated packet.
+ // Disc packets except ordrel ack have non-zero datastream type.
+ if ((pHdr->hdr_ConnCtrl &
+ (SPX_CC_SYS | SPX_CC_ACK | SPX_CC_NEG | SPX_CC_SPX2)) ==
+ (SPX_CC_SYS | SPX_CC_ACK | SPX_CC_NEG | SPX_CC_SPX2))
+ {
+ // We received a renegotiate packet. Ignore all ack values
+ // in a reneg req.
+ SpxConnProcessRenegReq(pSpxConnFile, pHdr, pRemoteAddr, lockHandle);
+ lockHeld = FALSE;
+ break;
+ }
+
+ // Set ack numbers for connection.
+ SPX_SET_ACKNUM(
+ pSpxConnFile, ackNum, allocNum);
+
+ // Check if we are an ack/nack packet in which case call process
+ // ack. Note that the spx2 orderly release ack is a normal spx2 ack.
+ if (((pHdr->hdr_ConnCtrl & SPX_CC_ACK) == 0) &&
+ (pHdr->hdr_DataType == 0))
+ {
+ SpxConnProcessAck(pSpxConnFile, pHdr, lockHandle);
+ lockHeld = FALSE;
+ }
+ else
+ {
+ // Just process the numbers we got.
+ SpxConnProcessAck(pSpxConnFile, NULL, lockHandle);
+ lockHeld = FALSE;
+ }
+
+ // If the remote wants us to send an ack, do it.
+ if (pHdr->hdr_ConnCtrl & SPX_CC_ACK)
+ {
+ // First copy the remote address in connection.
+ SpxCopyIpxAddr(pHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *pRemoteAddr;
+
+ if (!lockHeld)
+ {
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ lockHeld = TRUE;
+ }
+
+ SpxConnSendAck(pSpxConnFile, lockHandle);
+ lockHeld = FALSE;
+ break;
+ }
+
+ break;
+
+ default:
+
+ // Ignore this packet.
+ DBGPRINT(RECEIVE, WARN,
+ ("SpxConnSysPacket: Ignoring packet, state is not active\n"));
+ break;
+ }
+
+ } while (FALSE);
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ // Remove reference added on connection
+ SpxConnFileDereference(pSpxConnFile, CFREF_BYID);
+ return;
+}
+
+
+
+
+VOID
+SpxRecvDiscPacket(
+ IN PUCHAR LookaheadBuffer,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN UINT LookaheadSize
+ )
+/*++
+
+Routine Description:
+
+ This is called to indicate an incoming connection.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS status;
+ PIPXSPX_HDR pHdr;
+ USHORT srcConnId, destConnId,
+ pktLen, seqNum, ackNum, allocNum;
+ PSPX_CONN_FILE pSpxConnFile;
+ CTELockHandle lockHandle;
+ BOOLEAN lockHeld;
+
+ pHdr = (PIPXSPX_HDR)LookaheadBuffer;
+
+ // check minimum length
+ if (LookaheadSize < MIN_IPXSPX_HDRSIZE)
+ {
+ return;
+ }
+
+ // Convert hdr to host format as needed.
+ GETSHORT2SHORT(&pktLen, &pHdr->hdr_PktLen);
+ GETSHORT2SHORT(&destConnId, &pHdr->hdr_DestConnId);
+ GETSHORT2SHORT(&seqNum, &pHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pHdr->hdr_AckNum);
+ GETSHORT2SHORT(&allocNum, &pHdr->hdr_AllocNum);
+
+ if ((pktLen < MIN_IPXSPX_HDRSIZE) ||
+ (pHdr->hdr_PktType != SPX_PKT_TYPE))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxRecvDiscPacket: Packet Size %lx\n",
+ pktLen));
+
+ return;
+ }
+
+ // We keep and use the remote id in the net format. This maintains the
+ // 0x0 and 0xFFFF to be as in the host format.
+ srcConnId = *(USHORT UNALIGNED *)&pHdr->hdr_SrcConnId;
+ if ((srcConnId == 0) || (srcConnId == 0xFFFF) || (destConnId == 0))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnDiscPacket: Incorrect conn id %lx.%lx\n",
+ srcConnId, destConnId));
+
+ return;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnDiscPacket: packet received dest %lx src %lx\n",
+ pHdr->hdr_DestSkt, pHdr->hdr_SrcSkt));
+
+ // Find the connection this is destined for and reference it.
+ SpxConnFileReferenceById(destConnId, &pSpxConnFile, &status);
+ if (!NT_SUCCESS(status))
+ {
+ DBGPRINT(RECEIVE, WARN,
+ ("SpxConnDiscPacket: Id %lx NOT FOUND", destConnId));
+
+ return;
+ }
+
+ do
+ {
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnDiscPacket: Id %lx Conn %lx DiscType %lx\n",
+ destConnId, pSpxConnFile, pHdr->hdr_DataType));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ lockHeld = TRUE;
+
+ // Unless we are in the active/disconnecting, but send state = idle
+ // and recv state = idle/recv posted, we ignore all disconnect packets.
+ if (((SPX_MAIN_STATE(pSpxConnFile) != SPX_CONNFILE_ACTIVE) &&
+ (SPX_MAIN_STATE(pSpxConnFile) != SPX_CONNFILE_DISCONN)) ||
+ ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_IDLE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_PACKETIZE)) ||
+ ((SPX_RECV_STATE(pSpxConnFile) != SPX_RECV_IDLE) &&
+ (SPX_RECV_STATE(pSpxConnFile) != SPX_RECV_POSTED)) ||
+ !(IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage)) ||
+ (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_PKT)))
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDiscPacket: %lx, %lx, %lx.%lx, %d.%d\n",
+ pSpxConnFile,
+ SPX_MAIN_STATE(pSpxConnFile),
+ SPX_SEND_STATE(pSpxConnFile), SPX_RECV_STATE(pSpxConnFile),
+ (IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage)),
+ (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_PKT))));
+
+ break;
+ }
+
+ // If we have received a disconnect, process received ack to complete any
+ // pending sends before we allow the disconnect. This ack number will be
+ // the last word on this session.
+ SPX_SET_ACKNUM(
+ pSpxConnFile, ackNum, allocNum);
+
+ SpxConnProcessAck(pSpxConnFile, NULL, lockHandle);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+
+ switch (pHdr->hdr_DataType)
+ {
+ case SPX2_DT_ORDREL:
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDiscPacket: Recd ORDREl!\n"));
+
+ // BUGBUG: Need to deal with all sthe states.
+ // Restart watchdog timer if started.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER))
+ {
+ // This will either successfully restart or not affect the timer
+ // if it is currently running.
+ SpxTimerCancelEvent(
+ pSpxConnFile->scf_WTimerId,
+ TRUE);
+
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+ }
+
+ // On receive, we do check the seq num for the orderly release, just
+ // like for a data packet.
+ // If this was not already indicated, indicate it now. That is all
+ // we do for an orderly release. When our client does a orderly rel
+ // and we receive the ack for that, call abortive with success.
+
+ // Verify ord rel packet, this checks if seq nums match also.
+ if ((pktLen != MIN_IPXSPX2_HDRSIZE) ||
+ ((pHdr->hdr_ConnCtrl &
+ (SPX_CC_ACK | SPX_CC_EOM | SPX_CC_SPX2)) !=
+ (SPX_CC_ACK | SPX_CC_EOM | SPX_CC_SPX2)) ||
+ (pHdr->hdr_DataType != SPX2_DT_ORDREL) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId))
+ {
+ DBGPRINT(CONNECT, DBG1,
+ ("SpxConnDiscPacket: OR Failed/Ignored %lx, %lx.%lx.%lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum,
+ pSpxConnFile->scf_RecvListTail));
+
+ break;
+ }
+
+ // If it passed above test, but seq number is incorrect, schedule
+ // to send an ack.
+ if (seqNum != pSpxConnFile->scf_RecvSeqNum)
+ {
+ USHORT NumToResend;
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnDiscPacket: Unexpected seq on %lx, %lx.%lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
+
+ // Calculate number to be resent. If we expect sequence 1 and receive
+ // 2 for eg., we need to send a nack, else we send an ack.
+ if (SPX2_CONN(pSpxConnFile) &&
+ UNSIGNED_GREATER_WITH_WRAP(
+ seqNum,
+ pSpxConnFile->scf_RecvSeqNum) &&
+ !UNSIGNED_GREATER_WITH_WRAP(
+ seqNum,
+ pSpxConnFile->scf_SentAllocNum))
+ {
+ NumToResend = (USHORT)(seqNum - pSpxConnFile->scf_RecvSeqNum + 1);
+ SpxConnSendNack(pSpxConnFile, NumToResend, lockHandle);
+ lockHeld = FALSE;
+ }
+
+ break;
+ }
+
+ // Copy address for when ack is to be sent.
+ SpxCopyIpxAddr(pHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *pRemoteAddr;
+
+ if (pSpxConnFile->scf_RecvListHead == NULL)
+ {
+ // No received data, go ahead and process now.
+ DBGPRINT(CONNECT, INFO,
+ ("SpxConnDiscPacket: NO DATA ORDREL %lx.%lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_RecvListHead,
+ pSpxConnFile->scf_SendSeqListHead));
+
+ SpxConnProcessOrdRel(pSpxConnFile, lockHandle);
+ lockHeld = FALSE;
+ }
+ else
+ {
+ // No received data, go ahead and process now.
+ DBGPRINT(CONNECT, DBG1,
+ ("SpxConnDiscPacket: DATA ORDREL %lx.%lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_RecvListHead,
+ pSpxConnFile->scf_SendSeqListHead));
+
+ // Set flag in last recd buffer
+ pSpxConnFile->scf_RecvListTail->rr_State |= SPX_RECVPKT_ORD_DISC;
+ }
+
+ break;
+
+ case SPX2_DT_IDISC:
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDiscPacket: %lx Recd IDISC %lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_RefCount));
+
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnDiscPacket: SEND %d. RECV %d.%lx!\n",
+ IsListEmpty(&pSpxConnFile->scf_ReqLinkage),
+ IsListEmpty(&pSpxConnFile->scf_RecvLinkage),
+ pSpxConnFile->scf_RecvDoneLinkage));
+
+ if (!((pktLen == MIN_IPXSPX_HDRSIZE) ||
+ ((pHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
+ (pktLen == MIN_IPXSPX2_HDRSIZE))) ||
+ !(pHdr->hdr_ConnCtrl & SPX_CC_ACK) ||
+ (pHdr->hdr_DataType != SPX2_DT_IDISC) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnDiscPacket:IDISC Ignored %lx.%lx.%lx.%lx\n",
+ pSpxConnFile, seqNum,
+ pSpxConnFile->scf_RecvSeqNum,
+ pSpxConnFile->scf_RecvListTail));
+ break;
+ }
+
+ // Copy address for when ack is to be sent.
+ SpxCopyIpxAddr(pHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *pRemoteAddr;
+
+ if (pSpxConnFile->scf_RecvListHead == NULL)
+ {
+ // No received data, go ahead and process now.
+ DBGPRINT(CONNECT, INFO,
+ ("SpxConnDiscPacket: NO RECV DATA IDISC %lx.%lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_RecvListHead,
+ pSpxConnFile->scf_SendSeqListHead));
+
+ SpxConnProcessIDisc(pSpxConnFile, lockHandle);
+
+ lockHeld = FALSE;
+ }
+ else
+ {
+ // Set flag in last recd buffer
+
+ pSpxConnFile->scf_RecvListTail->rr_State |= SPX_RECVPKT_IDISC;
+ }
+
+ break;
+
+ case SPX2_DT_IDISC_ACK:
+
+ // Done with informed disconnect. Call abort connection with
+ // status success. That completes the pending disconnect request
+ // with status_success.
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDiscPacket: %lx Recd IDISC ack!\n", pSpxConnFile));
+
+ if (!((pktLen == MIN_IPXSPX_HDRSIZE) ||
+ ((pHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
+ (pktLen == MIN_IPXSPX2_HDRSIZE))) ||
+ (pHdr->hdr_DataType != SPX2_DT_IDISC_ACK) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnDiscPacket:Ver idisc ack Failed %lx, %lx.%lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
+ break;
+ }
+
+ // We should be in the right state to accept this.
+ if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_SENT_IDISC))
+ {
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_SUCCESS,
+ SPX_CALL_RECVLEVEL,
+ lockHandle,
+ FALSE); // [SA] bug #15249
+
+ lockHeld = FALSE;
+ }
+
+ break;
+
+ default:
+
+ KeBugCheck(0);
+ }
+
+
+ } while (FALSE);
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ // Remove reference added on connection
+ SpxConnFileDereference(pSpxConnFile, CFREF_BYID);
+ return;
+}
+
+
+
+
+VOID
+SpxRecvBufferPkt(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT LookaheadOffset,
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN UINT PacketSize,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+ This is called to indicate an incoming connection.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pNdisPkt;
+ PSPX_RECV_RESD pRecvResd;
+ ULONG bytesCopied;
+ BOOLEAN fEom;
+ NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
+ PBYTE pData = NULL;
+ PNDIS_BUFFER pNdisBuffer = NULL;
+
+ if (PacketSize > 0)
+ {
+ // Allocate memory for this data.
+ if (pData = (PBYTE)SpxAllocateMemory(PacketSize))
+ {
+ // Describe memory with a ndis buffer descriptor.
+ NdisAllocateBuffer(
+ &ndisStatus,
+ &pNdisBuffer,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ pData,
+ PacketSize);
+ }
+ else
+ {
+ ndisStatus = NDIS_STATUS_RESOURCES;
+ }
+ }
+
+ if (ndisStatus == NDIS_STATUS_SUCCESS)
+ {
+ // Allocate a ndis receive packet.
+ SpxAllocRecvPacket(SpxDevice, &pNdisPkt, &ndisStatus);
+ if (ndisStatus == NDIS_STATUS_SUCCESS)
+ {
+ // Queue the buffer into the packet if there is one.
+ if (pNdisBuffer)
+ {
+ NdisChainBufferAtBack(
+ pNdisPkt,
+ pNdisBuffer);
+ }
+
+ fEom = ((SPX_CONN_MSG(pSpxConnFile) &&
+ (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_EOM)) ||
+ SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR));
+
+ pRecvResd = RECV_RESD(pNdisPkt);
+ pRecvResd->rr_DataOffset= 0;
+
+#if DBG
+ // Store seq number
+ GETSHORT2SHORT(&pRecvResd->rr_SeqNum , &pIpxSpxHdr->hdr_SeqNum);
+#endif
+
+ pRecvResd->rr_State =
+ (SPX_RECVPKT_BUFFERING |
+ (SPX_CONN_FLAG2(
+ pSpxConnFile, SPX_CONNFILE2_PKT_NOIND) ? SPX_RECVPKT_INDICATED : 0) |
+ (fEom ? SPX_RECVPKT_EOM : 0) |
+ ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_ACK) ? SPX_RECVPKT_SENDACK : 0));
+
+ if (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_ACK)
+ {
+ // copy the remote address in connection.
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *pRemoteAddr;
+ }
+
+ pRecvResd->rr_Request = NULL;
+ pRecvResd->rr_ConnFile = pSpxConnFile;
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxRecvBufferPkt: %lx Len %lx DataPts %lx F %lx\n",
+ pSpxConnFile, PacketSize, pData, pRecvResd->rr_State));
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ // Call ndis transfer data. Copy ENTIRE packet. copySize has
+ // been modified so use original values.
+ ndisStatus = NDIS_STATUS_SUCCESS;
+ bytesCopied = 0;
+ if (PacketSize > 0)
+ {
+ (*IpxTransferData)(
+ &ndisStatus,
+ MacBindingHandle,
+ MacReceiveContext,
+ LookaheadOffset,
+ PacketSize,
+ pNdisPkt,
+ &bytesCopied);
+ }
+
+ if (ndisStatus != STATUS_PENDING)
+ {
+ SpxTransferDataComplete(
+ pNdisPkt,
+ ndisStatus,
+ bytesCopied);
+ }
+
+ // BUG: FDDI returns pending which screws us up here. Stupid bug
+ ndisStatus = NDIS_STATUS_SUCCESS;
+ }
+ }
+
+ // ASSERT: Lock will be freed in the success case.
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxRecvBufferPkt: FAILED!\n"));
+
+ END_PROCESS_PACKET(pSpxConnFile, FALSE, FALSE);
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ if (pData != NULL)
+ {
+ SpxFreeMemory(pData);
+ }
+
+ if (pNdisBuffer != NULL)
+ {
+ NdisFreeBuffer(pNdisBuffer);
+ }
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxRecvDataPacket(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadSize,
+ IN UINT LookaheadOffset,
+ IN UINT PacketSize
+ )
+/*++
+
+Routine Description:
+
+ This is called to indicate an incoming connection.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ PIPXSPX_HDR pIpxSpxHdr;
+ USHORT srcConnId, destConnId,
+ pktLen, seqNum, ackNum, allocNum;
+ ULONG receiveFlags;
+ PSPX_CONN_FILE pSpxConnFile;
+ PTDI_IND_RECEIVE pRecvHandler;
+ PVOID pRecvCtx;
+ PIRP pRecvIrp;
+ ULONG bytesTaken, iOffset, copySize, bytesCopied;
+ CTELockHandle lockHandle;
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+ PSPX_RECV_RESD pRecvResd;
+ NDIS_STATUS ndisStatus;
+ PREQUEST pRequest = NULL;
+ BOOLEAN fEom,
+ fImmedAck = FALSE, fLockHeld = FALSE, fPktDone = FALSE;
+
+ pIpxSpxHdr = (PIPXSPX_HDR)LookaheadBuffer;
+
+ // check minimum length
+ if (PacketSize < MIN_IPXSPX_HDRSIZE)
+ {
+ return;
+ }
+
+ // Convert hdr to host format as needed.
+ GETSHORT2SHORT(&pktLen, &pIpxSpxHdr->hdr_PktLen);
+ GETSHORT2SHORT(&destConnId, &pIpxSpxHdr->hdr_DestConnId);
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+
+ if ((pktLen < MIN_IPXSPX_HDRSIZE) ||
+ (pktLen > PacketSize) ||
+ (pIpxSpxHdr->hdr_PktType != SPX_PKT_TYPE))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnDataPacket: Packet Size %lx.%lx\n",
+ pktLen, PacketSize));
+
+ return;
+ }
+
+ // We keep and use the remote id in the net format.
+ srcConnId = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_SrcConnId;
+
+ if ((srcConnId == 0) || (srcConnId == 0xFFFF) || (destConnId == 0))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnDataPacket: Incorrect conn id %lx.%lx\n",
+ srcConnId, destConnId));
+
+ return;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnDataPacket: packet received dest %lx src %lx seq %lx\n",
+ pIpxSpxHdr->hdr_DestSkt, pIpxSpxHdr->hdr_SrcSkt, seqNum));
+
+ if ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
+ (pktLen < MIN_IPXSPX2_HDRSIZE))
+ {
+ return;
+ }
+
+ // Find the connection this is destined for and reference it.
+ SpxConnFileReferenceById(destConnId, &pSpxConnFile, &status);
+ if (!NT_SUCCESS(status))
+ {
+ DBGPRINT(RECEIVE, WARN,
+ ("SpxConnDataPacket: Id %lx NOT FOUND", destConnId));
+ return;
+ }
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+
+#if 0
+ //
+ // We have the connection. We should update the dest. sock # in
+ // it in case it changed. Unix machines do do that sometimes.
+ // SCO bug 7676
+ //
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAddr);
+#endif
+
+ fLockHeld = TRUE;
+ do
+ {
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnDataPacket: Id %lx Conn %lx\n",
+ destConnId, pSpxConnFile));
+
+ // Restart watchdog timer if started.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER))
+ {
+ // This will either successfully restart or not affect the timer
+ // if it is currently running.
+ SpxTimerCancelEvent(
+ pSpxConnFile->scf_WTimerId,
+ TRUE);
+
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+ }
+
+ if (SPX_CONN_ACTIVE(pSpxConnFile))
+ {
+ // Verify data packet, this checks if seq nums match also.
+ if ((pIpxSpxHdr->hdr_SrcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId) ||
+ !((pktLen >= MIN_IPXSPX_HDRSIZE) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
+ (pktLen >= MIN_IPXSPX2_HDRSIZE))))
+ {
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnDataPacket: Failed %lx, %lx.%lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
+
+ break;
+ }
+
+ // If it passed above test, but seq number is incorrect, schedule
+ // to send an ack.
+ if (seqNum != pSpxConnFile->scf_RecvSeqNum)
+ {
+ USHORT NumToResend;
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnDataPacket: Unexpected seq on %lx, %lx.%lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
+
+ ++SpxDevice->dev_Stat.DataFramesRejected;
+ ExInterlockedAddLargeStatistic(
+ &SpxDevice->dev_Stat.DataFrameBytesRejected,
+ pktLen - (SPX2_CONN(pSpxConnFile) ?
+ MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE));
+
+ //
+ // Bug #16975: Set the remote ack addr for use in SpxConnSendAck()
+ //
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *RemoteAddress;
+
+ // Calculate number to be resent. If we expect sequence 1 and receive
+ // 2 for eg., we need to send a nack, else we send an ack.
+ if (SPX2_CONN(pSpxConnFile) &&
+ UNSIGNED_GREATER_WITH_WRAP(
+ seqNum,
+ pSpxConnFile->scf_RecvSeqNum) &&
+ !UNSIGNED_GREATER_WITH_WRAP(
+ seqNum,
+ pSpxConnFile->scf_SentAllocNum))
+ {
+ NumToResend = (USHORT)(seqNum - pSpxConnFile->scf_RecvSeqNum + 1);
+ SpxConnSendNack(pSpxConnFile, NumToResend, lockHandle);
+ fLockHeld = FALSE;
+ }
+ else
+ {
+ SpxConnSendAck(pSpxConnFile, lockHandle);
+ fLockHeld = FALSE;
+ }
+
+ break;
+ }
+
+ // If we have received an orderly release, we accept no more data
+ // packets.
+ if (SPX_CONN_FLAG(
+ pSpxConnFile,
+ (SPX_CONNFILE_IND_IDISC |
+ SPX_CONNFILE_IND_ODISC))
+
+ ||
+
+ ((pSpxConnFile->scf_RecvListTail != NULL) &&
+ ((pSpxConnFile->scf_RecvListTail->rr_State &
+ SPX_RECVPKT_DISCMASK) != 0)))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnDataPacket: After ord rel %lx, %lx.%lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
+
+ break;
+ }
+
+ // We are processing a packet OR a receive is about to complete.
+ if (!SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_PKT))
+ {
+ BEGIN_PROCESS_PACKET(pSpxConnFile, seqNum);
+ }
+ else
+ {
+ // Already processing a packet. Or a receive is waiting to
+ // complete. Get out.
+ break;
+ }
+
+ // Set ack numbers for connection.
+ SPX_SET_ACKNUM(
+ pSpxConnFile, ackNum, allocNum);
+
+ SpxConnProcessAck(pSpxConnFile, NULL, lockHandle);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+
+ iOffset = MIN_IPXSPX2_HDRSIZE;
+ if (!SPX2_CONN(pSpxConnFile))
+ {
+ iOffset = 0;
+ if (!SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR))
+ {
+ iOffset = MIN_IPXSPX_HDRSIZE;
+ }
+ }
+
+ copySize = pktLen - iOffset;
+ fEom = ((SPX_CONN_MSG(pSpxConnFile) &&
+ (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_EOM)) ||
+ SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR));
+
+ // Do we attempt to piggyback? If not, fImmedAck is true.
+ // For SPX1 we dont piggyback.
+ // Bug #18253
+ fImmedAck = (!SPX2_CONN(pSpxConnFile) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_EOM) == 0));
+
+ // If we do not have EOM to indicate AND we are a zero-sized packet
+ // then just consume this packet.
+ if (!fEom && (copySize == 0))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnDataPacket: ZERO LENGTH PACKET NO EOM %lx.%lx\n",
+ pSpxConnFile, seqNum));
+
+ fPktDone = TRUE;
+ break;
+ }
+
+ receiveFlags = TDI_RECEIVE_NORMAL;
+ receiveFlags |= ((fEom ? TDI_RECEIVE_ENTIRE_MESSAGE : 0) |
+ (((MacOptions &
+ NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA) != 0) ?
+ TDI_RECEIVE_COPY_LOOKAHEAD : 0));
+
+ ++SpxDevice->dev_Stat.DataFramesReceived;
+ ExInterlockedAddLargeStatistic(
+ &SpxDevice->dev_Stat.DataFrameBytesReceived,
+ copySize);
+
+ // Ok, we accept this packet. Depending on our state.
+ switch (SPX_RECV_STATE(pSpxConnFile))
+ {
+ case SPX_RECV_PROCESS_PKTS:
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDataPacket: recv completions on %lx\n",
+ pSpxConnFile));
+
+ goto BufferPacket;
+
+ case SPX_RECV_IDLE:
+
+ // If recv q is non-empty we are buffering data.
+ // Also, if no receive handler goto buffer data. Also, if receives
+ // are being completed, buffer this packet.
+ if ((pSpxConnFile->scf_RecvListHead != NULL) ||
+ !(IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage)) ||
+ !(pRecvHandler = pSpxConnFile->scf_AddrFile->saf_RecvHandler))
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDataPacket: RecvListHead non-null %lx\n",
+ pSpxConnFile));
+
+ goto BufferPacket;
+ }
+
+ if (!SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_PKT_NOIND))
+ {
+ pRecvCtx = pSpxConnFile->scf_AddrFile->saf_RecvHandlerCtx;
+
+ // Don't indicate this packet again.
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_PKT_NOIND);
+
+#if DBG
+ CTEAssert(pSpxConnFile->scf_CurRecvReq == NULL);
+
+ // Debug code to ensure we dont reindicate data/indicate
+ // when previously indicated data waiting with afd.
+
+ //
+ // Comment this out for Buf # 10394. we'r hitting this assert
+ // even when there was no data loss.
+ //
+ // CTEAssert(pSpxConnFile->scf_IndBytes == 0);
+ CTEAssert(pSpxConnFile->scf_PktSeqNum != seqNum);
+
+ pSpxConnFile->scf_PktSeqNum = seqNum;
+ pSpxConnFile->scf_PktFlags = pSpxConnFile->scf_Flags;
+ pSpxConnFile->scf_PktFlags2 = pSpxConnFile->scf_Flags2;
+
+ pSpxConnFile->scf_IndBytes = copySize;
+ pSpxConnFile->scf_IndLine = __LINE__;
+
+
+#endif
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ bytesTaken = 0;
+ status = (*pRecvHandler)(
+ pRecvCtx,
+ pSpxConnFile->scf_ConnCtx,
+ receiveFlags,
+ LookaheadSize - iOffset,
+ copySize,
+ &bytesTaken,
+ LookaheadBuffer + iOffset,
+ &pRecvIrp);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDataPacket: IND Flags %lx.%lx ConnID %lx,\
+ %lx Ctx %lx SEQ %lx Size %lx . %lx .%lx IND Status %lx\n",
+ pIpxSpxHdr->hdr_ConnCtrl,
+ receiveFlags,
+ destConnId,
+ pSpxConnFile,
+ pSpxConnFile->scf_ConnCtx,
+ seqNum,
+ LookaheadSize - iOffset,
+ copySize,
+ bytesTaken,
+ status));
+
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnDataPacket: %x %x %x %x %x %x %x %x %x %x %x %x\n",
+ *(LookaheadBuffer+iOffset),
+ *(LookaheadBuffer+iOffset+1),
+ *(LookaheadBuffer+iOffset+2),
+ *(LookaheadBuffer+iOffset+3),
+ *(LookaheadBuffer+iOffset+4),
+ *(LookaheadBuffer+iOffset+5),
+ *(LookaheadBuffer+iOffset+6),
+ *(LookaheadBuffer+iOffset+7),
+ *(LookaheadBuffer+iOffset+8),
+ *(LookaheadBuffer+iOffset+9),
+ *(LookaheadBuffer+iOffset+10),
+ *(LookaheadBuffer+iOffset+11)));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+
+ if (status == STATUS_SUCCESS)
+ {
+ // Assume all data accepted.
+ CTEAssert((bytesTaken != 0) || fEom);
+ fPktDone = TRUE;
+
+#if DBG
+ // Set this to 0, since we just indicated, there could
+ // not have been other data.
+ pSpxConnFile->scf_IndBytes = 0;
+#endif
+
+ break;
+ }
+
+ if (status == STATUS_MORE_PROCESSING_REQUIRED)
+ {
+
+ // Queue irp into connection, change state to receive
+ // posted and fall thru.
+ pRequest = SpxAllocateRequest(
+ SpxDevice,
+ pRecvIrp);
+
+ IF_NOT_ALLOCATED(pRequest)
+ {
+ pRecvIrp->IoStatus.Status =
+ STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (pRecvIrp, IO_NETWORK_INCREMENT);
+ break;
+ }
+
+ // If there was indicated but not received data waiting
+ // (which in this path there will never be, the request
+ // could be completed given the data filled it up, and
+ // the lock released.
+ SpxConnQueueRecv(
+ pSpxConnFile,
+ pRequest);
+
+ CTEAssert(pRequest == pSpxConnFile->scf_CurRecvReq);
+ }
+ else if (IsListEmpty(&pSpxConnFile->scf_RecvLinkage))
+ {
+ // Data was not accepted. Need to buffer data and
+ // reduce window.
+ goto BufferPacket;
+ }
+
+ // Fall through to recv_posted.
+ }
+ else
+ {
+ DBGPRINT(RECEIVE, WARN,
+ ("SpxConnDataPacket: !!!Ignoring %lx Seq %lx\n",
+ pSpxConnFile,
+ seqNum));
+
+ break;
+ }
+
+ case SPX_RECV_POSTED:
+
+ if (pSpxConnFile->scf_RecvListHead != NULL)
+ {
+ // This can happen also. Buffer packet if it does.
+ goto BufferPacket;
+ }
+
+ // If a receive irp is posted, then process the receive irp. If
+ // we fell thru we MAY already will have an irp.
+ if (pRequest == NULL)
+ {
+ CTEAssert(!IsListEmpty(&pSpxConnFile->scf_RecvLinkage));
+ CTEAssert(pSpxConnFile->scf_CurRecvReq != NULL);
+ pRequest = pSpxConnFile->scf_CurRecvReq;
+ }
+
+ // Process receive. Here we do not need to worry about
+ // indicated yet not received data. We just deal with
+ // servicing the current packet.
+ CTEAssert(pRequest == pSpxConnFile->scf_CurRecvReq);
+ if ((LookaheadSize == PacketSize) &&
+ (pSpxConnFile->scf_CurRecvSize >= copySize))
+ {
+ bytesCopied = 0;
+ status = STATUS_SUCCESS;
+ if (copySize > 0)
+ {
+ status = TdiCopyBufferToMdl(
+ LookaheadBuffer,
+ iOffset,
+ copySize,
+ REQUEST_TDI_BUFFER(pRequest),
+ pSpxConnFile->scf_CurRecvOffset,
+ &bytesCopied);
+
+ CTEAssert(NT_SUCCESS(status));
+ if (!NT_SUCCESS(status))
+ {
+ // Abort request with this status. Reset request
+ // queue to next request if one is available.
+ }
+
+ DBGPRINT(RECEIVE, DBG,
+ ("BytesCopied %lx CopySize %lx, Recv Size %lx.%lx\n",
+ bytesCopied, copySize,
+ pSpxConnFile->scf_CurRecvSize,
+ pSpxConnFile->scf_CurRecvOffset));
+ }
+
+ // Update current request values and see if this request
+ // is to be completed. Either zero or fEom.
+ pSpxConnFile->scf_CurRecvOffset += bytesCopied;
+ pSpxConnFile->scf_CurRecvSize -= bytesCopied;
+
+#if DBG
+ // Decrement indicated data count
+ if (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_PKT_NOIND))
+ {
+ if (bytesCopied != 0)
+ {
+ CTEAssert (pSpxConnFile->scf_IndBytes != 0);
+ pSpxConnFile->scf_IndBytes -= bytesCopied;
+ }
+ }
+#endif
+
+ if (SPX_CONN_STREAM(pSpxConnFile) ||
+ (pSpxConnFile->scf_CurRecvSize == 0) ||
+ fEom)
+ {
+ CTELockHandle lockHandleInter;
+
+ // Set status
+ REQUEST_STATUS(pRequest) = STATUS_SUCCESS;
+ REQUEST_INFORMATION(pRequest)=
+ pSpxConnFile->scf_CurRecvOffset;
+
+ if (!SPX_CONN_STREAM(pSpxConnFile) &&
+ (pSpxConnFile->scf_CurRecvSize == 0) &&
+ !fEom)
+ {
+ REQUEST_STATUS(pRequest) = STATUS_RECEIVE_PARTIAL;
+ }
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnData: Completing recv %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Dequeue this request, Set next recv if one exists.
+ SPX_CONN_SETNEXT_CUR_RECV(pSpxConnFile, pRequest);
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_RecvDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+
+ fPktDone = TRUE;
+ }
+ else
+ {
+ // Need to allocate a ndis receive packet for transfer
+ // data.
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDataPacket: %lx.%lx Tranfer data needed!\n",
+ copySize, pSpxConnFile->scf_CurRecvSize));
+
+ if (copySize > pSpxConnFile->scf_CurRecvSize)
+ {
+ // Partial receive. Buffer and then deal with it.
+ goto BufferPacket;
+ }
+
+ // Allocate a ndis receive packet.
+ SpxAllocRecvPacket(SpxDevice, &pNdisPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ // Describe the receive irp's data with a ndis buffer
+ // descriptor.
+ if (copySize > 0)
+ {
+ SpxCopyBufferChain(
+ &ndisStatus,
+ &pNdisBuffer,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ REQUEST_TDI_BUFFER(pRequest),
+ pSpxConnFile->scf_CurRecvOffset,
+ copySize);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ // Free the recv packet
+ SpxPktRecvRelease(pNdisPkt);
+ break;
+ }
+
+ // Queue the buffer into the packet
+ // Link the buffer descriptor into the packet descriptor
+ NdisChainBufferAtBack(
+ pNdisPkt,
+ pNdisBuffer);
+ }
+
+ // Don't care about whether this is indicated or not here
+ // as it is not a buffering packet.
+ pRecvResd = RECV_RESD(pNdisPkt);
+ pRecvResd->rr_Id = IDENTIFIER_SPX;
+ pRecvResd->rr_State =
+ ((fEom ? SPX_RECVPKT_EOM : 0) |
+ (SPX_CONN_FLAG2(
+ pSpxConnFile, SPX_CONNFILE2_PKT_NOIND) ? SPX_RECVPKT_INDICATED : 0) |
+ (fImmedAck ? SPX_RECVPKT_IMMEDACK : 0) |
+ ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_ACK) ?
+ SPX_RECVPKT_SENDACK : 0));
+
+ if (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_ACK)
+ {
+ // copy the remote address in connection.
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *RemoteAddress;
+ }
+
+ pRecvResd->rr_Request = pRequest;
+ pRecvResd->rr_ConnFile = pSpxConnFile;
+
+ // reference receive request
+ REQUEST_INFORMATION(pRequest)++;
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ fLockHeld = FALSE;
+
+ // Call ndis transfer data.
+ ndisStatus = NDIS_STATUS_SUCCESS;
+ bytesCopied = 0;
+ if (copySize > 0)
+ {
+ (*IpxTransferData)(
+ &ndisStatus,
+ MacBindingHandle,
+ MacReceiveContext,
+ iOffset + LookaheadOffset,
+ copySize,
+ pNdisPkt,
+ &bytesCopied);
+ }
+
+ if (ndisStatus != STATUS_PENDING)
+ {
+ SpxTransferDataComplete(
+ pNdisPkt,
+ ndisStatus,
+ bytesCopied);
+ }
+ }
+
+ break;
+
+ default:
+
+ KeBugCheck(0);
+ break;
+ }
+
+ break;
+
+BufferPacket:
+
+ SpxRecvBufferPkt(
+ pSpxConnFile,
+ MacBindingHandle,
+ MacReceiveContext,
+ iOffset + LookaheadOffset,
+ pIpxSpxHdr,
+ copySize,
+ RemoteAddress,
+ lockHandle);
+
+ fLockHeld = FALSE;
+ }
+
+ } while (FALSE);
+
+ // Here we process a received ack.
+ if (!fLockHeld)
+ {
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ fLockHeld = TRUE;
+ }
+
+ // Send an ack if one was asked for. And we are done with this packet.
+ if (fPktDone)
+ {
+ END_PROCESS_PACKET(pSpxConnFile, FALSE, TRUE);
+ }
+
+ if ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_ACK) && fPktDone)
+ {
+ if (!fLockHeld)
+ {
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ fLockHeld = TRUE;
+ }
+
+ // First copy the remote address in connection.
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *RemoteAddress;
+
+ // #17564
+ if (fImmedAck ||
+ SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_NOACKWAIT) ||
+ SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IMMED_ACK))
+ {
+ SpxConnSendAck(pSpxConnFile, lockHandle);
+ fLockHeld = FALSE;
+ }
+ else
+ {
+ SpxConnQWaitAck(pSpxConnFile);
+ }
+ }
+
+ if (fLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ // Deref the connection
+ SpxConnFileDereference(pSpxConnFile, CFREF_BYID);
+ return;
+}
+
+
+
+
+VOID
+SpxRecvFlushBytes(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN ULONG BytesToFlush,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+ PSPX_RECV_RESD pRecvResd;
+ PBYTE pData;
+ ULONG dataLen, copyLen;
+ BOOLEAN fLockHeld = TRUE, fWdwOpen = FALSE;
+ USHORT discState = 0;
+ int numPkts = 0, numDerefs = 0;
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxRecvFlushBytes: %lx Flush %lx\n",
+ pSpxConnFile, BytesToFlush));
+
+ while (((pRecvResd = pSpxConnFile->scf_RecvListHead) != NULL) &&
+ ((BytesToFlush > 0) ||
+ ((pRecvResd->rr_State & SPX_RECVPKT_INDICATED) != 0)))
+ {
+ // A buffering recv packet will have ATMOST one ndis buffer descriptor
+ // queued in, which will describe a segment of memory we have
+ // allocated. An offset will also be present indicating the data
+ // to start reading from (or to indicate from to AFD).
+ CTEAssert((pRecvResd->rr_State & SPX_RECVPKT_BUFFERING) != 0);
+ pNdisPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pRecvResd, NDIS_PACKET, ProtocolReserved);
+
+ NdisQueryPacket(pNdisPkt, NULL, NULL, &pNdisBuffer, NULL);
+
+ // Initialize pData
+ pData = NULL;
+ dataLen = 0;
+
+ if (pNdisBuffer != NULL)
+ {
+ NdisQueryBuffer(pNdisBuffer, &pData, &dataLen);
+ CTEAssert(pData != NULL);
+ CTEAssert(dataLen >= 0);
+ }
+
+ if ((BytesToFlush == 0) && (dataLen != 0))
+ {
+ // Don't flush this packet.
+ break;
+ }
+
+ // Allow for zero data, eom only packets.
+ copyLen = MIN((dataLen - pRecvResd->rr_DataOffset), BytesToFlush);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxRecvFlushBytes: %lx Pkt %lx DataLen %lx Copy %lx Flush %lx\n",
+ pSpxConnFile, pNdisPkt, dataLen, copyLen, BytesToFlush));
+
+ // Adjust various values to see whats done whats not
+ pRecvResd->rr_DataOffset += (USHORT)copyLen;
+ BytesToFlush -= (ULONG)copyLen;
+
+#if DBG
+ if (copyLen != 0)
+ {
+ CTEAssert (pSpxConnFile->scf_IndBytes != 0);
+ pSpxConnFile->scf_IndBytes -= copyLen;
+ }
+#endif
+
+ if (pRecvResd->rr_DataOffset == dataLen)
+ {
+ // Packet consumed. Free it up. Check if disc happened.
+ discState = (pRecvResd->rr_State & SPX_RECVPKT_DISCMASK);
+ CTEAssert((discState == 0) ||
+ (pRecvResd == pSpxConnFile->scf_RecvListTail));
+
+ numDerefs++;
+ SpxConnDequeueRecvPktLock(pSpxConnFile, pNdisPkt);
+ if (pNdisBuffer != NULL)
+ {
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ CTEAssert(pNdisBuffer != NULL);
+ NdisFreeBuffer(pNdisBuffer);
+ SpxFreeMemory(pData);
+ }
+
+ SpxPktRecvRelease(pNdisPkt);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxRecvFlushBytes: !!!ALL INDICATED on %lx.%lx.%lx.%lx\n",
+ pSpxConnFile, pNdisPkt, pNdisBuffer, pData));
+
+ INCREMENT_WINDOW(pSpxConnFile);
+ fWdwOpen = TRUE;
+ }
+ else
+ {
+ // Took only part of this packet. Get out.
+ break;
+ }
+ }
+
+ if (fWdwOpen && (pSpxConnFile->scf_RecvListHead == NULL))
+ {
+ // Send an ack as our windows probably opened up. Dont wait to
+ // piggyback here...
+ DBGPRINT(RECEIVE, DBG,
+ ("spxRecvFlushBytes: Send ACK %lx\n",
+ pSpxConnFile));
+
+#if DBG_WDW_CLOSE
+ // If packets been indicated we have started buffering. Also
+ // check if window is now zero.
+ {
+ LARGE_INTEGER li, ntTime;
+ int value;
+
+ li = pSpxConnFile->scf_WdwCloseTime;
+ if (li.LowPart && li.HighPart)
+ {
+ KeQuerySystemTime(&ntTime);
+
+ // Get the difference
+ ntTime.QuadPart = ntTime.QuadPart - li.QuadPart;
+
+ // Convert to milliseconds. If the highpart is 0, we
+ // take a shortcut.
+ if (ntTime.HighPart == 0)
+ {
+ value = ntTime.LowPart/10000;
+ }
+ else
+ {
+ ntTime = SPX_CONVERT100NSTOCENTISEC(ntTime);
+ value = ntTime.LowPart << 4;
+ }
+
+ // Set new average close time
+ pSpxConnFile->scf_WdwCloseAve += value;
+ pSpxConnFile->scf_WdwCloseAve /= 2;
+ DBGPRINT(RECEIVE, DBG,
+ ("V %ld AVE %ld\n",
+ value, pSpxConnFile->scf_WdwCloseAve));
+ }
+ }
+#endif
+
+ SpxConnSendAck(pSpxConnFile, LockHandleConn);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ }
+
+ // Check if disconnect happened
+ switch (discState)
+ {
+ case SPX_RECVPKT_IDISC:
+
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+
+ DBGPRINT(RECEIVE, ERR,
+ ("spxRecvFlushBytes: Buffered IDISC %lx\n",
+ pSpxConnFile));
+
+ SpxConnProcessIDisc(pSpxConnFile, LockHandleConn);
+ fLockHeld = FALSE;
+ break;
+
+ case SPX_RECVPKT_ORD_DISC:
+
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+
+ DBGPRINT(RECEIVE, ERR,
+ ("spxRecvFlushBytes: Buffered ORDREL %lx\n",
+ pSpxConnFile));
+
+ SpxConnProcessOrdRel(pSpxConnFile, LockHandleConn);
+ fLockHeld = FALSE;
+ break;
+
+ case (SPX_RECVPKT_IDISC | SPX_RECVPKT_ORD_DISC):
+
+ // IDISC has more priority.
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+
+ DBGPRINT(RECEIVE, ERR,
+ ("spxRecvFlushBytes: Buffered IDISC *AND* ORDREL %lx\n",
+ pSpxConnFile));
+
+ SpxConnProcessIDisc(pSpxConnFile, LockHandleConn);
+ fLockHeld = FALSE;
+ break;
+
+ default:
+
+ break;
+ }
+
+ if (fLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+BOOLEAN
+SpxRecvIndicatePendingData(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+ BOOLEAN - Receive was queued => TRUE
+
+--*/
+{
+ ULONG indicateFlags;
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+ PREQUEST pRequest;
+ PIRP pRecvIrp;
+ ULONG bytesTaken, totalSize, bufSize;
+ PTDI_IND_RECEIVE pRecvHandler;
+ PVOID pRecvCtx;
+ PSPX_RECV_RESD pRecvResd;
+ NTSTATUS status;
+ PBYTE lookaheadData;
+ ULONG lookaheadSize;
+ BOOLEAN fLockHeld = TRUE, fRecvQueued = FALSE;
+
+
+ while ((pRecvHandler = pSpxConnFile->scf_AddrFile->saf_RecvHandler) &&
+ ((pRecvResd = pSpxConnFile->scf_RecvListHead) != NULL) &&
+ (IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage)) &&
+ ((pRecvResd->rr_State & SPX_RECVPKT_BUFFERING) != 0) &&
+ ((pRecvResd->rr_State & SPX_RECVPKT_INDICATED) == 0))
+ {
+ // Once a receive is queued we better get out.
+ CTEAssert(!fRecvQueued);
+
+ // Initialize lookahead values
+ lookaheadData = NULL;
+ lookaheadSize = 0;
+
+ // We have no indicated but pending data, and there is some data to
+ // indicate. Figure out how much. Indicate upto end of message or as
+ // much as we have.
+
+ // A buffering recv packet will have ATMOST one ndis buffer descriptor
+ // queued in, which will describe a segment of memory we have
+ // allocated. An offset will also be present indicating the data
+ // to start reading from (or to indicate from to AFD).
+ CTEAssert((pRecvResd->rr_State & SPX_RECVPKT_BUFFERING) != 0);
+ pNdisPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pRecvResd, NDIS_PACKET, ProtocolReserved);
+
+ NdisQueryPacket(pNdisPkt, NULL, NULL, &pNdisBuffer, NULL);
+ if (pNdisBuffer != NULL)
+ {
+ NdisQueryBuffer(pNdisBuffer, &lookaheadData, &lookaheadSize);
+ CTEAssert(lookaheadData != NULL);
+ CTEAssert(lookaheadSize >= 0);
+ }
+
+ // Allow for zero data, eom only packets.
+ lookaheadSize -= pRecvResd->rr_DataOffset;
+ totalSize = lookaheadSize;
+ lookaheadData += pRecvResd->rr_DataOffset;
+
+ // If this packet contained data then eom must also have been
+ // indicated at the time all the data was consumed.
+ CTEAssert((lookaheadSize > 0) ||
+ ((pRecvResd->rr_DataOffset == 0) &&
+ ((pRecvResd->rr_State & SPX_RECVPKT_EOM) != 0)));
+
+#if DBG
+ CTEAssert (pSpxConnFile->scf_CurRecvReq == NULL);
+
+ // Debug code to ensure we dont reindicate data/indicate
+ // when previously indicated data waiting with afd.
+ CTEAssert(pSpxConnFile->scf_IndBytes == 0);
+ CTEAssert(pSpxConnFile->scf_PktSeqNum != pRecvResd->rr_SeqNum);
+
+ pSpxConnFile->scf_PktSeqNum = pRecvResd->rr_SeqNum;
+ pSpxConnFile->scf_PktFlags = pSpxConnFile->scf_Flags;
+ pSpxConnFile->scf_PktFlags2 = pSpxConnFile->scf_Flags2;
+#endif
+
+ pRecvResd->rr_State |= SPX_RECVPKT_INDICATED;
+
+ // Go ahead and walk the list of waiting packets. Get total size.
+ while ((pRecvResd->rr_Next != NULL) &&
+ ((pRecvResd->rr_State & SPX_RECVPKT_EOM) == 0))
+ {
+ // Check next packet.
+ pRecvResd = pRecvResd->rr_Next;
+
+#if DBG
+ CTEAssert(pSpxConnFile->scf_PktSeqNum != pRecvResd->rr_SeqNum);
+
+ pSpxConnFile->scf_PktSeqNum = pRecvResd->rr_SeqNum;
+ pSpxConnFile->scf_PktFlags = pSpxConnFile->scf_Flags;
+ pSpxConnFile->scf_PktFlags2 = pSpxConnFile->scf_Flags2;
+#endif
+
+ pRecvResd->rr_State |= SPX_RECVPKT_INDICATED;
+
+ pNdisPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pRecvResd, NDIS_PACKET, ProtocolReserved);
+
+ NdisQueryPacket(pNdisPkt, NULL, NULL, NULL, &bufSize);
+ CTEAssert(bufSize >= 0);
+
+ // Allow for zero data, eom only packets.
+ totalSize += bufSize;
+ }
+
+#if DBG
+ pSpxConnFile->scf_IndBytes = totalSize;
+ pSpxConnFile->scf_IndLine = __LINE__;
+
+ // There better not be any pending receives. If so, we have data
+ // corruption about to happen.
+ if (!IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage))
+ {
+ DBGBRK(FATAL);
+ KeBugCheck(0);
+ }
+#endif
+
+ indicateFlags = TDI_RECEIVE_NORMAL | TDI_RECEIVE_COPY_LOOKAHEAD;
+ if ((pRecvResd->rr_State & SPX_RECVPKT_EOM) != 0)
+ {
+ indicateFlags |= TDI_RECEIVE_ENTIRE_MESSAGE;
+ }
+
+ pRecvCtx = pSpxConnFile->scf_AddrFile->saf_RecvHandlerCtx;
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ bytesTaken = 0;
+ status = (*pRecvHandler)(
+ pRecvCtx,
+ pSpxConnFile->scf_ConnCtx,
+ indicateFlags,
+ lookaheadSize,
+ totalSize,
+ &bytesTaken,
+ lookaheadData,
+ &pRecvIrp);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnIndicatePendingData: IND Flags %lx Size %lx .%lx IND Status %lx\n",
+ indicateFlags,
+ totalSize,
+ bytesTaken,
+ status));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ if (status == STATUS_SUCCESS)
+ {
+ // Assume all data accepted. Free bytesTaken worth of data packets.
+ // Sometimes AFD returns STATUS_SUCCESS to just flush the data, so
+ // we can't assume it took only one packet (since lookahead only
+ // had that information).
+ CTEAssert(bytesTaken == totalSize);
+ SpxRecvFlushBytes(pSpxConnFile, totalSize, LockHandleConn);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ continue;
+ }
+ else if (status == STATUS_MORE_PROCESSING_REQUIRED)
+ {
+
+ // Queue irp into connection, change state to receive
+ // posted and fall thru.
+ pRequest = SpxAllocateRequest(
+ SpxDevice,
+ pRecvIrp);
+
+ IF_NOT_ALLOCATED(pRequest)
+ {
+ pRecvIrp->IoStatus.Status =
+ STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (pRecvIrp, IO_NETWORK_INCREMENT);
+ return (FALSE);
+ }
+
+ SpxConnQueueRecv(
+ pSpxConnFile,
+ pRequest);
+
+ fRecvQueued = TRUE;
+ }
+
+ break;
+ }
+
+ if (fLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ }
+
+ return fRecvQueued;
+}
+
+
+
+
+VOID
+SpxRecvProcessPkts(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+ Handle buffered data, complete irp if necessary. Set state to idle
+ if list becomes empty.
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+ BOOLEAN: More data left to indicate => TRUE
+
+--*/
+{
+ ULONG remainingDataLen, copyLen, bytesCopied;
+ PREQUEST pRequest;
+ NTSTATUS status;
+ BOOLEAN fEom;
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+ PSPX_RECV_RESD pRecvResd;
+ ULONG dataLen;
+ PBYTE pData;
+ LIST_ENTRY *p;
+ BOOLEAN fLockHeld = TRUE, fMoreData = TRUE, fWdwOpen = FALSE;
+ USHORT discState = 0;
+ int numDerefs = 0;
+
+ if (SPX_RECV_STATE(pSpxConnFile) != SPX_RECV_PROCESS_PKTS)
+ {
+ SPX_RECV_SETSTATE(pSpxConnFile, SPX_RECV_PROCESS_PKTS);
+
+ProcessReceives:
+
+ while ((pSpxConnFile->scf_CurRecvReq != NULL) &&
+ ((pRecvResd = pSpxConnFile->scf_RecvListHead) != NULL))
+ {
+ // A buffering recv packet will have one ndis buffer descriptor
+ // queued in, which will describe a segment of memory we have
+ // allocated. An offset will also be present indicating the data
+ // to start reading from (or to indicate from to AFD).
+ CTEAssert((pRecvResd->rr_State & SPX_RECVPKT_BUFFERING) != 0);
+
+ pNdisPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pRecvResd, NDIS_PACKET, ProtocolReserved);
+
+ NdisQueryPacket(pNdisPkt, NULL, NULL, &pNdisBuffer, NULL);
+
+ // Initialize pData
+ pData = NULL;
+ dataLen = 0;
+
+ if (pNdisBuffer != NULL)
+ {
+ NdisQueryBuffer(pNdisBuffer, &pData, &dataLen);
+ CTEAssert(pData != NULL);
+ CTEAssert(dataLen >= 0);
+ }
+
+ // Allow for zero data, eom only packets.
+ remainingDataLen = dataLen - pRecvResd->rr_DataOffset;
+
+ // If this packet contained data then eom must also have been
+ // indicated at the time all the data was consumed.
+ CTEAssert((remainingDataLen > 0) ||
+ ((pRecvResd->rr_DataOffset == 0) &&
+ ((pRecvResd->rr_State & SPX_RECVPKT_EOM) != 0)));
+
+ status = STATUS_SUCCESS;
+ copyLen = 0;
+ if (remainingDataLen > 0)
+ {
+ copyLen = MIN(remainingDataLen, pSpxConnFile->scf_CurRecvSize);
+ status = TdiCopyBufferToMdl(
+ pData,
+ pRecvResd->rr_DataOffset,
+ copyLen,
+ REQUEST_TDI_BUFFER(pSpxConnFile->scf_CurRecvReq),
+ pSpxConnFile->scf_CurRecvOffset,
+ &bytesCopied);
+
+ CTEAssert(NT_SUCCESS(status));
+ if (!NT_SUCCESS(status))
+ {
+ // Abort request with this status. Reset request
+ // queue to next request if one is available.
+ copyLen = pSpxConnFile->scf_CurRecvSize;
+ }
+ }
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessRecdPkts: %lx Pkt %lx Data %lx Size %lx F %lx\n",
+ pSpxConnFile, pNdisPkt, pData, copyLen, pRecvResd->rr_State));
+
+ // Adjust various values to see whats done whats not
+ pRecvResd->rr_DataOffset += (USHORT)copyLen;
+ pSpxConnFile->scf_CurRecvSize -= (USHORT)copyLen;
+ pSpxConnFile->scf_CurRecvOffset += (USHORT)copyLen;
+
+#if DBG
+ // If this packet was part of indicated data count, decrement.
+ if ((pRecvResd->rr_State & SPX_RECVPKT_INDICATED) != 0)
+ {
+ if (copyLen != 0)
+ {
+ CTEAssert (pSpxConnFile->scf_IndBytes != 0);
+ pSpxConnFile->scf_IndBytes -= copyLen;
+ }
+ }
+#endif
+
+ // Set fEom/discState (init to 0) only if all of packet was consumed.
+ fEom = FALSE;
+ if (pRecvResd->rr_DataOffset == dataLen)
+ {
+ fEom = (BOOLEAN)((pRecvResd->rr_State & SPX_RECVPKT_EOM) != 0);
+
+ // Remember if disconnect needed to happen. If set, this better be
+ // last packet received. Again, only if entire pkt was consumed.
+ discState = (pRecvResd->rr_State & SPX_RECVPKT_DISCMASK);
+ CTEAssert((discState == 0) ||
+ (pRecvResd == pSpxConnFile->scf_RecvListTail));
+
+ // Packet consumed. Free it up.
+ numDerefs++;
+
+ SpxConnDequeueRecvPktLock(pSpxConnFile, pNdisPkt);
+ INCREMENT_WINDOW(pSpxConnFile);
+
+ fWdwOpen = TRUE;
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessRecdPkts: %lx Pkt %lx Data %lx DEQUEUED\n",
+ pSpxConnFile, pNdisPkt, pData));
+
+ if (pNdisBuffer != NULL)
+ {
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ NdisFreeBuffer(pNdisBuffer);
+ SpxFreeMemory(pData);
+ }
+
+ SpxPktRecvRelease(pNdisPkt);
+ }
+ else
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessRecdPkts: %lx Pkt %lx PARTIAL USE %lx.%lx\n",
+ pSpxConnFile, pNdisPkt, pRecvResd->rr_DataOffset, dataLen));
+ }
+
+ // Don't complete until we are out of all packets and stream mode or...
+ if (((pSpxConnFile->scf_RecvListHead == NULL) &&
+ SPX_CONN_STREAM(pSpxConnFile)) ||
+ (pSpxConnFile->scf_CurRecvSize == 0) ||
+ fEom)
+ {
+ // Done with receive, move to completion or complete depending on
+ // call level.
+ pRequest = pSpxConnFile->scf_CurRecvReq;
+
+ // Set status. Complete with error from TdiCopy if so.
+ REQUEST_INFORMATION(pRequest) = pSpxConnFile->scf_CurRecvOffset;
+ REQUEST_STATUS(pRequest) = status;
+
+ // Ensure we dont overwrite an error status.
+ if (!SPX_CONN_STREAM(pSpxConnFile) &&
+ (pSpxConnFile->scf_CurRecvSize == 0) &&
+ !fEom &&
+ NT_SUCCESS(status))
+ {
+ REQUEST_STATUS(pRequest) = STATUS_RECEIVE_PARTIAL;
+ }
+
+ // Dequeue this request, set next recv if one exists.
+ SPX_CONN_SETNEXT_CUR_RECV(pSpxConnFile, pRequest);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessRecdPkts: %lx Recv %lx with %lx.%lx\n",
+ pSpxConnFile, pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+#if DBG
+ if ((REQUEST_STATUS(pRequest) == STATUS_SUCCESS) &&
+ (REQUEST_INFORMATION(pRequest) == 0))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxReceiveComplete: Completing %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+ }
+#endif
+
+ // Request is done. Move to receive completion list. There
+ // could already be previously queued requests in here.
+ InsertTailList(
+ &pSpxConnFile->scf_RecvDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+ }
+
+ CTEAssert((discState == 0) ||
+ (pSpxConnFile->scf_RecvListHead == NULL));
+ }
+
+ // Complete any completed receives
+ while ((p = pSpxConnFile->scf_RecvDoneLinkage.Flink) !=
+ &pSpxConnFile->scf_RecvDoneLinkage)
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ DBGPRINT(TDI, DBG,
+ ("SpxConnDiscPkt: PENDING REQ COMP %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+#if DBG
+ if ((REQUEST_STATUS(pRequest) == STATUS_SUCCESS) &&
+ (REQUEST_INFORMATION(pRequest) == 0))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxReceiveComplete: Completing %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+ }
+#endif
+
+ SpxCompleteRequest(pRequest);
+ numDerefs++;
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ }
+
+ fMoreData = ((pSpxConnFile->scf_RecvListHead != NULL) &&
+ ((pSpxConnFile->scf_RecvListHead ->rr_State &
+ SPX_RECVPKT_BUFFERING) != 0) &&
+ ((pSpxConnFile->scf_RecvListHead->rr_State &
+ SPX_RECVPKT_INDICATED) == 0));
+
+ while (fMoreData)
+ {
+ // Bug #21036
+ // If there is a receive waiting to be processed, we better not
+ // indicate data before we finish it.
+ if (pSpxConnFile->scf_CurRecvReq != NULL)
+ goto ProcessReceives;
+
+ // If a receive was queued the goto beginning again.
+ if (SpxRecvIndicatePendingData(pSpxConnFile, LockHandleConn))
+ {
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ goto ProcessReceives;
+ }
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ fMoreData = ((pSpxConnFile->scf_RecvListHead != NULL) &&
+ ((pSpxConnFile->scf_RecvListHead ->rr_State &
+ SPX_RECVPKT_BUFFERING) != 0) &&
+ ((pSpxConnFile->scf_RecvListHead->rr_State &
+ SPX_RECVPKT_INDICATED) == 0));
+ }
+
+ // Set state
+ SPX_RECV_SETSTATE(
+ pSpxConnFile,
+ (pSpxConnFile->scf_CurRecvReq == NULL) ?
+ SPX_RECV_IDLE : SPX_RECV_POSTED);
+ }
+#if DBG
+ else
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("spxConnProcessRecdPkts: Already processing pkts %lx\n",
+ pSpxConnFile));
+ }
+#endif
+
+ if (fWdwOpen && (pSpxConnFile->scf_RecvListHead == NULL))
+ {
+ // Send an ack as our windows probably opened up. Dont wait to
+ // piggyback here...
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessRecdPkts: Send ACK %lx\n",
+ pSpxConnFile));
+
+#if DBG_WDW_CLOSE
+ // If packets been indicated we have started buffering. Also
+ // check if window is now zero.
+ {
+ LARGE_INTEGER li, ntTime;
+ int value;
+
+ li = pSpxConnFile->scf_WdwCloseTime;
+ if (li.LowPart && li.HighPart)
+ {
+ KeQuerySystemTime(&ntTime);
+
+ // Get the difference
+ ntTime.QuadPart = ntTime.QuadPart - li.QuadPart;
+
+ // Convert to milliseconds. If the highpart is 0, we
+ // take a shortcut.
+ if (ntTime.HighPart == 0)
+ {
+ value = ntTime.LowPart/10000;
+ }
+ else
+ {
+ ntTime = SPX_CONVERT100NSTOCENTISEC(ntTime);
+ value = ntTime.LowPart << 4;
+ }
+
+ // Set new average close time
+ pSpxConnFile->scf_WdwCloseAve += value;
+ pSpxConnFile->scf_WdwCloseAve /= 2;
+ DBGPRINT(RECEIVE, DBG,
+ ("V %ld AVE %ld\n",
+ value, pSpxConnFile->scf_WdwCloseAve));
+ }
+ }
+#endif
+
+ SpxConnSendAck(pSpxConnFile, LockHandleConn);
+ fLockHeld = FALSE;
+ }
+
+ // Check if disconnect happened
+ switch (discState)
+ {
+ case SPX_RECVPKT_IDISC:
+
+ CTEAssert(!fMoreData);
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+
+ if (!fLockHeld)
+ {
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ }
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessRecdPkts: Buffered IDISC %lx\n",
+ pSpxConnFile, fMoreData));
+
+ SpxConnProcessIDisc(pSpxConnFile, LockHandleConn);
+ fLockHeld = FALSE;
+ break;
+
+ case SPX_RECVPKT_ORD_DISC:
+
+ CTEAssert(!fMoreData);
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+
+ if (!fLockHeld)
+ {
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ }
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessRecdPkts: Buffered ORDREL %lx\n",
+ pSpxConnFile, fMoreData));
+
+ SpxConnProcessOrdRel(pSpxConnFile, LockHandleConn);
+ fLockHeld = FALSE;
+ break;
+
+ case (SPX_RECVPKT_IDISC | SPX_RECVPKT_ORD_DISC):
+
+ // IDISC has more priority.
+ CTEAssert(!fMoreData);
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+
+ if (!fLockHeld)
+ {
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ }
+
+ DBGPRINT(RECEIVE, ERR,
+ ("spxConnProcessRecdPkts: Buffered IDISC *AND* ORDREL %lx\n",
+ pSpxConnFile, fMoreData));
+
+ SpxConnProcessIDisc(pSpxConnFile, LockHandleConn);
+ fLockHeld = FALSE;
+ break;
+
+ default:
+
+ break;
+ }
+
+ if (fLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
diff --git a/private/ntos/tdi/isnp/spx/spxreg.c b/private/ntos/tdi/isnp/spx/spxreg.c
new file mode 100644
index 000000000..4389dca5f
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/spxreg.c
@@ -0,0 +1,400 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxreg.c
+
+Abstract:
+
+ This contains all routines necessary for the support of the dynamic
+ configuration of the ISN SPX module.
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXREG
+
+// Local functions used to access the registry.
+NTSTATUS
+SpxInitReadIpxDeviceName(
+ VOID);
+
+NTSTATUS
+SpxInitSetIpxDeviceName(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext);
+
+NTSTATUS
+SpxInitGetConfigValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext);
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT, SpxInitGetConfiguration)
+#pragma alloc_text(INIT, SpxInitFreeConfiguration)
+#pragma alloc_text(INIT, SpxInitGetConfigValue)
+#pragma alloc_text(INIT, SpxInitReadIpxDeviceName)
+#pragma alloc_text(INIT, SpxInitSetIpxDeviceName)
+#endif
+
+
+NTSTATUS
+SpxInitGetConfiguration (
+ IN PUNICODE_STRING RegistryPath,
+ OUT PCONFIG * ConfigPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by SPX to get information from the configuration
+ management routines. We read the registry, starting at RegistryPath,
+ to get the parameters. If they don't exist, we use the defaults
+ set in ipxcnfg.h file. A list of adapters to bind to is chained
+ on to the config information.
+
+Arguments:
+
+ RegistryPath - The name of ST's node in the registry.
+
+ ConfigPtr - Returns the configuration information.
+
+Return Value:
+
+ Status - STATUS_SUCCESS if everything OK, STATUS_INSUFFICIENT_RESOURCES
+ otherwise.
+
+--*/
+{
+ NTSTATUS Status;
+ UINT i;
+ PWSTR RegistryPathBuffer;
+ PCONFIG Config;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[CONFIG_PARAMETERS+2];
+
+ ULONG Zero = 0;
+ ULONG Two = 2;
+ ULONG Four = 4;
+ ULONG Five = 5;
+ ULONG Eight = 8;
+ ULONG Twelve = 12;
+ ULONG Fifteen = 15;
+ ULONG Thirty = 30;
+ ULONG FiveHundred = 500;
+ ULONG Hex4000 = 0x4000;
+ ULONG Hex7FFF = 0x7FFF;
+ ULONG FourK = 4096;
+
+ PWSTR Parameters = L"Parameters";
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[CONFIG_PARAMETERS] = {
+ { L"ConnectionCount", &Five },
+ { L"ConnectionTimeout", &Two },
+ { L"InitPackets", &Five },
+ { L"MaxPackets", &Thirty},
+ { L"InitialRetransmissionTime", &FiveHundred},
+ { L"KeepAliveCount", &Eight},
+ { L"KeepAliveTimeout", &Twelve},
+ { L"WindowSize", &Four},
+ { L"SpxSocketRangeStart", &Hex4000},
+ { L"SpxSocketRangeEnd", &Hex7FFF},
+ { L"SpxSocketUniqueness", &Eight},
+ { L"MaxPacketSize", &FourK},
+ { L"RetransmissionCount", &Eight},
+ { L"DisableSpx2", &Zero},
+ { L"RouterMtu", &Zero},
+ { L"BackCompSpx", &Zero}
+ };
+
+ if (!NT_SUCCESS(SpxInitReadIpxDeviceName()))
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Allocate memory for the main config structure.
+ Config = CTEAllocMem (sizeof(CONFIG));
+ if (Config == NULL) {
+ TMPLOGERR();
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Config->cf_DeviceName.Buffer = NULL;
+
+ // SpxReadLinkageInformation expects a null-terminated path,
+ // so we have to create one from the UNICODE_STRING.
+ RegistryPathBuffer = (PWSTR)CTEAllocMem(RegistryPath->Length + sizeof(WCHAR));
+
+ if (RegistryPathBuffer == NULL) {
+
+ SpxInitFreeConfiguration(Config);
+
+ TMPLOGERR();
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (
+ RegistryPathBuffer,
+ RegistryPath->Buffer,
+ RegistryPath->Length);
+
+ *(PWCHAR)(((PUCHAR)RegistryPathBuffer)+RegistryPath->Length) = (WCHAR)'\0';
+
+ Config->cf_RegistryPathBuffer = RegistryPathBuffer;
+
+ // Read the per-transport (as opposed to per-binding)
+ // parameters.
+ //
+ // Set up QueryTable to do the following:
+ // 1) Switch to the Parameters key below SPX
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Parameters;
+
+ // 2-14) Call SpxSetBindingValue for each of the keys we
+ // care about.
+ for (i = 0; i < CONFIG_PARAMETERS; i++) {
+
+ QueryTable[i+1].QueryRoutine = SpxInitGetConfigValue;
+ QueryTable[i+1].Flags = 0;
+ QueryTable[i+1].Name = ParameterValues[i].KeyName;
+ QueryTable[i+1].EntryContext = (PVOID)i;
+ QueryTable[i+1].DefaultType = REG_DWORD;
+ QueryTable[i+1].DefaultData = (PVOID)(ParameterValues[i].DefaultValue);
+ QueryTable[i+1].DefaultLength = sizeof(ULONG);
+ }
+
+ // 15) Stop
+ QueryTable[CONFIG_PARAMETERS+1].QueryRoutine = NULL;
+ QueryTable[CONFIG_PARAMETERS+1].Flags = 0;
+ QueryTable[CONFIG_PARAMETERS+1].Name = NULL;
+
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->cf_RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+ SpxInitFreeConfiguration(Config);
+
+ TMPLOGERR();
+ return Status;
+ }
+
+ CTEFreeMem (RegistryPathBuffer);
+ *ConfigPtr = Config;
+
+ return STATUS_SUCCESS;
+
+} // SpxInitGetConfiguration
+
+
+
+
+VOID
+SpxInitFreeConfiguration (
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by SPX to get free any storage that was allocated
+ by SpxGetConfiguration in producing the specified CONFIG structure.
+
+Arguments:
+
+ Config - A pointer to the configuration information structure.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ CTEFreeMem (Config);
+
+} // SpxInitFreeConfig
+
+
+
+
+NTSTATUS
+SpxInitGetConfigValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each entry in the Parameters
+ node to set the config values. The table is set up
+ so that this function will be called with correct default
+ values for keys that are not present.
+
+Arguments:
+
+ ValueName - The name of the value (ignored).
+
+ ValueType - The type of the value (REG_DWORD -- ignored).
+
+ ValueData - The data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to the CONFIG structure.
+
+ EntryContext - The index in Config->Parameters to save the value.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+
+ if ((ValueType != REG_DWORD) || (ValueLength != sizeof(ULONG))) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ DBGPRINT(CONFIG, INFO,
+ ("Config parameter %d, value %lx\n",
+ (ULONG)EntryContext, *(UNALIGNED ULONG *)ValueData));
+
+ Config->cf_Parameters[(ULONG)EntryContext] = *(UNALIGNED ULONG *)ValueData;
+ return STATUS_SUCCESS;
+
+} // SpxInitGetConfigValue
+
+
+
+
+NTSTATUS
+SpxInitReadIpxDeviceName(
+ VOID
+ )
+
+{
+ NTSTATUS Status;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+ PWSTR Export = L"Export";
+ PWSTR IpxRegistryPath = IPX_REG_PATH;
+
+ // Set up QueryTable to do the following:
+ //
+ // 1) Call SetIpxDeviceName for the string in "Export"
+ QueryTable[0].QueryRoutine = SpxInitSetIpxDeviceName;
+ QueryTable[0].Flags = 0;
+ QueryTable[0].Name = Export;
+ QueryTable[0].EntryContext = NULL;
+ QueryTable[0].DefaultType = REG_NONE;
+
+ // 2) Stop
+ QueryTable[1].QueryRoutine = NULL;
+ QueryTable[1].Flags = 0;
+ QueryTable[1].Name = NULL;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ IpxRegistryPath,
+ QueryTable,
+ NULL,
+ NULL);
+
+ return Status;
+}
+
+
+
+
+NTSTATUS
+SpxInitSetIpxDeviceName(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Export" multi-string and
+ saves the information in a ConfigurationInfo structure.
+
+Arguments:
+
+ ValueName - The name of the value ("Export" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - NULL.
+
+ EntryContext - NULL.
+
+Return Value:
+
+ status
+
+--*/
+
+{
+ PWSTR fileName;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ fileName = (PWSTR)CTEAllocMem(ValueLength);
+ if (fileName != NULL) {
+ RtlCopyMemory(fileName, ValueData, ValueLength);
+ RtlInitUnicodeString (&IpxDeviceName, fileName);
+ }
+ else
+ {
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ return(status);
+}
+
diff --git a/private/ntos/tdi/isnp/spx/spxsend.c b/private/ntos/tdi/isnp/spx/spxsend.c
new file mode 100644
index 000000000..6b856953d
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/spxsend.c
@@ -0,0 +1,262 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxsend.c
+
+Abstract:
+
+ This module contains code that implements the send engine for the
+ SPX transport provider.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+// Define module number for event logging entries
+#define FILENUM SPXSEND
+
+VOID
+SpxSendComplete(
+ IN PNDIS_PACKET pNdisPkt,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to indicate that a connection-
+ oriented packet has been shipped and is no longer needed by the Physical
+ Provider.
+
+Arguments:
+
+ ProtocolBindingContext - The ADAPTER structure for this binding.
+
+ NdisPacket/RequestHandle - A pointer to the NDIS_PACKET that we sent.
+
+ NdisStatus - the completion status of the send.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PSPX_CONN_FILE pSpxConnFile;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_BUFFER pNdisBuffer;
+ CTELockHandle lockHandle;
+ UINT bufCount;
+ PREQUEST pRequest = NULL;
+ BOOLEAN completeReq = FALSE, freePkt = FALSE,
+ orphaned = FALSE, lockHeld = FALSE;
+
+ pSendResd = (PSPX_SEND_RESD)(pNdisPkt->ProtocolReserved);
+
+#if DBG
+ if (NdisStatus != NDIS_STATUS_SUCCESS)
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: For %lx with status **%lx**\n",
+ pNdisPkt, NdisStatus));
+ }
+#endif
+
+ // IPX changes the length set for the first ndis buffer descriptor.
+ // Change it back to its original value here.
+ NdisQueryPacket(pNdisPkt, NULL, &bufCount, &pNdisBuffer, NULL);
+ NdisAdjustBufferLength(pNdisBuffer, IpxMacHdrNeeded + MIN_IPXSPX2_HDRSIZE);
+
+ do
+ {
+ pSpxConnFile = pSendResd->sr_ConnFile;
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ lockHeld = TRUE;
+#if defined(__PNP)
+ //
+ // if IPX gave us a new LocalTarget, use for our next send.
+ //
+ // But if we are sending connect requests by iterating over NicIds,
+ // dont update the local target bcoz that will screw up our iteration
+ // logic.
+ //
+ if ( DEVICE_NETWORK_PATH_NOT_FOUND == NdisStatus
+ &&
+ !(
+ SPX_CONN_CONNECTING(pSpxConnFile) &&
+ (SPX_CONNECT_STATE(pSpxConnFile) == SPX_CONNECT_SENTREQ) &&
+ (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0)
+ ) ) {
+
+ pSpxConnFile->scf_LocalTarget = pSendResd->LocalTarget;
+
+ //
+ // Renegotiate the max packet size if we have an active SPX2
+ // session going on and we negotiated the max size originally.
+ //
+ if ( SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_ACTIVE &&
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2) &&
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG) ) {
+
+ //
+ // this call will get the local max size on this new local target
+ // from IPX.
+ //
+ SPX_MAX_PKT_SIZE(pSpxConnFile, TRUE, TRUE, *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr );
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RENEG);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: %lx CONNECTION ENTERING RENEG\n",
+ pSpxConnFile));
+ }
+
+ }
+#endif __PNP
+
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0);
+
+ // IPX dont own this packet nomore.
+ pSendResd->sr_State &= ~SPX_SENDPKT_IPXOWNS;
+
+ // If a send packet has been aborted, then we need to call
+ // abort send to go ahead and free up this packet, and deref associated
+ // request, if there is one, potentially completing it.
+ if ((pSendResd->sr_State & SPX_SENDPKT_ABORT) != 0)
+ {
+ spxConnAbortSendPkt(
+ pSpxConnFile,
+ pSendResd,
+ SPX_CALL_TDILEVEL,
+ lockHandle);
+
+ lockHeld = FALSE;
+ break;
+ }
+
+ // If there is an associated request, remove reference on it. BUT for a
+ // sequenced packet only if it has been acked and is waiting for the request
+ // to be dereferenced. It is already dequeued from queue, just free it up.
+ if ((((pSendResd->sr_State & SPX_SENDPKT_REQ) != 0) &&
+ ((pSendResd->sr_State & SPX_SENDPKT_SEQ) == 0)) ||
+ ((pSendResd->sr_State & SPX_SENDPKT_ACKEDPKT) != 0))
+ {
+ freePkt = (BOOLEAN)((pSendResd->sr_State & SPX_SENDPKT_ACKEDPKT) != 0);
+
+ pRequest = pSendResd->sr_Request;
+ CTEAssert(pRequest != NULL);
+
+ DBGPRINT(SEND, DBG,
+ ("IpxSendComplete: ReqRef before dec %lx.%lx\n",
+ pRequest, REQUEST_INFORMATION(pRequest)));
+
+ // Deref the request and see if we complete it now. We always have our
+ // own reference on the request.
+ // !!! Status should already have been set in request...!!!
+ if (--(REQUEST_INFORMATION(pRequest)) == 0)
+ {
+ CTEAssert(REQUEST_STATUS(pRequest) != STATUS_PENDING);
+
+ completeReq = TRUE;
+
+ // If this is acked already, request is not on list.
+ // BUG #11626
+ if ((pSendResd->sr_State & SPX_SENDPKT_ACKEDPKT) == 0)
+ {
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+ }
+ }
+ }
+
+ // Do we destroy this packet?
+ if ((pSendResd->sr_State & SPX_SENDPKT_DESTROY) != 0)
+ {
+ // Remove this packet from the send list in the connection.
+ DBGPRINT(SEND, INFO,
+ ("IpxSendComplete: destroy packet...\n"));
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pNdisPkt);
+ freePkt = TRUE;
+ }
+
+ } while (FALSE);
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ if (freePkt)
+ {
+ DBGPRINT(SEND, INFO,
+ ("IpxSendComplete: free packet...\n"));
+
+ SpxPktSendRelease(pNdisPkt);
+ }
+
+ if (completeReq)
+ {
+ // If this is a send request, set info to data sent, else it will be
+ // zero.
+ if (REQUEST_MINOR_FUNCTION(pRequest) == TDI_SEND)
+ {
+ PTDI_REQUEST_KERNEL_SEND pParam;
+
+ pParam = (PTDI_REQUEST_KERNEL_SEND)
+ REQUEST_PARAMETERS(pRequest);
+
+ REQUEST_INFORMATION(pRequest) = pParam->SendLength;
+ DBGPRINT(SEND, DBG,
+ ("IpxSendComplete: complete req %lx.%lx...\n",
+ REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ CTEAssert(pRequest != NULL);
+ CTEAssert(REQUEST_STATUS(pRequest) != STATUS_PENDING);
+ SpxCompleteRequest(pRequest);
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: %lx DISC Request %lx with %lx.%lx\n",
+ pSpxConnFile, pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: %lx.%lx.%lx\n",
+ pSpxConnFile->scf_RefCount,
+ pSpxConnFile->scf_Flags,
+ pSpxConnFile->scf_Flags2));
+
+ // Set the request in the connection, and deref for it.
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+ }
+
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+
+} // SpxSendComplete
+
+
+
diff --git a/private/ntos/tdi/isnp/spx/spxtimer.c b/private/ntos/tdi/isnp/spx/spxtimer.c
new file mode 100644
index 000000000..bdb4e1d7f
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/spxtimer.c
@@ -0,0 +1,637 @@
+/*
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ spxtimer.c
+
+Abstract:
+
+ This file implements the timer routines used by the stack.
+
+Author:
+
+ Jameel Hyder (jameelh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+
+Revision History:
+ 23 Feb 1993 Initial Version
+
+Notes: Tab stop: 4
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXTIMER
+
+// Discardable code after Init time
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT, SpxTimerInit)
+#endif
+
+// Globals for this module
+PTIMERLIST spxTimerList = NULL;
+PTIMERLIST spxTimerTable[TIMER_HASH_TABLE] = {0};
+PTIMERLIST spxTimerActive = NULL;
+CTELock spxTimerLock = {0};
+LARGE_INTEGER spxTimerTick = {0};
+KTIMER spxTimer = {0};
+KDPC spxTimerDpc = {0};
+ULONG spxTimerId = 1;
+LONG spxTimerCount = 0;
+USHORT spxTimerDispatchCount = 0;
+BOOLEAN spxTimerStopped = FALSE;
+
+
+NTSTATUS
+SpxTimerInit(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Initialize the timer component for the appletalk stack.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+#if !defined(_PNP_POWER)
+ BOOLEAN TimerStarted;
+#endif !_PNP_POWER
+
+ // Initialize the timer and its associated Dpc. timer will be kicked
+ // off when we get the first card arrival notification from ipx
+ KeInitializeTimer(&spxTimer);
+ CTEInitLock(&spxTimerLock);
+ KeInitializeDpc(&spxTimerDpc, spxTimerDpcRoutine, NULL);
+ spxTimerTick = RtlConvertLongToLargeInteger(SPX_TIMER_TICK);
+#if !defined(_PNP_POWER)
+ TimerStarted = KeSetTimer(&spxTimer,
+ spxTimerTick,
+ &spxTimerDpc);
+ CTEAssert(!TimerStarted);
+#endif !_PNP_POWER
+ return STATUS_SUCCESS;
+}
+
+
+
+
+ULONG
+SpxTimerScheduleEvent(
+ IN TIMER_ROUTINE Worker, // Routine to invoke when time expires
+ IN ULONG MsTime, // Schedule after this much time
+ IN PVOID pContext // Context(s) to pass to the routine
+ )
+/*++
+
+Routine Description:
+
+ Insert an event in the timer event list. If the list is empty, then
+ fire off a timer. The time is specified in ms. We convert to ticks.
+ Each tick is currently 100ms. It may not be zero or negative. The internal
+ timer fires at 100ms granularity.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PTIMERLIST pList;
+ CTELockHandle lockHandle;
+ ULONG DeltaTime;
+ ULONG Id = 0;
+
+ // Convert to ticks.
+ DeltaTime = MsTime/SPX_MS_TO_TICKS;
+ if (DeltaTime == 0)
+ {
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxTimerScheduleEvent: Converting %ld to ticks %ld\n",
+ MsTime, DeltaTime));
+
+ DeltaTime = 1;
+ }
+
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxTimerScheduleEvent: Converting %ld to ticks %ld\n",
+ MsTime, DeltaTime));
+
+ // Negative or Zero DeltaTime is invalid.
+ CTEAssert (DeltaTime > 0);
+
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxTimerScheduleEvent: Routine %lx, Time %d, Context %lx\n",
+ Worker, DeltaTime, pContext));
+
+ CTEGetLock(&spxTimerLock, &lockHandle);
+
+ if (spxTimerStopped)
+ {
+ DBGPRINT(SYSTEM, FATAL,
+ ("SpxTimerScheduleEvent: Called after Flush !!\n"));
+ }
+
+ else do
+ {
+ pList = SpxBPAllocBlock(BLKID_TIMERLIST);
+
+ if (pList == NULL)
+ {
+ break;
+ }
+
+#if DBG
+ pList->tmr_Signature = TMR_SIGNATURE;
+#endif
+ pList->tmr_Cancelled = FALSE;
+ pList->tmr_Worker = Worker;
+ pList->tmr_AbsTime = DeltaTime;
+ pList->tmr_Context = pContext;
+
+ Id = pList->tmr_Id = spxTimerId++;
+
+ // Take care of wrap around
+ if (spxTimerId == 0)
+ spxTimerId = 1;
+
+ // Enqueue this handler
+ spxTimerEnqueue(pList);
+ } while (FALSE);
+
+ CTEFreeLock(&spxTimerLock, lockHandle);
+
+ return Id;
+}
+
+
+
+VOID
+spxTimerDpcRoutine(
+ IN PKDPC pKDpc,
+ IN PVOID pContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+/*++
+
+Routine Description:
+
+ This is called in at DISPATCH_LEVEL when the timer expires. The entry at
+ the head of the list is decremented and if ZERO unlinked and dispatched.
+ If the list is non-empty, the timer is fired again.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PTIMERLIST pList, *ppList;
+ BOOLEAN TimerStarted;
+ ULONG ReEnqueueTime;
+ CTELockHandle lockHandle;
+
+ pKDpc; pContext; SystemArgument1; SystemArgument2;
+
+#if defined(_PNP_POWER)
+ CTEGetLock(&spxTimerLock, &lockHandle);
+ if (spxTimerStopped)
+ {
+ DBGPRINT(SYSTEM, ERR,
+ ("spxTimerDpc: Enetered after Flush !!!\n"));
+
+ CTEFreeLock(&spxTimerLock, lockHandle);
+ return;
+ }
+#else
+ if (spxTimerStopped)
+ {
+ DBGPRINT(SYSTEM, ERR,
+ ("spxTimerDpc: Enetered after Flush !!!\n"));
+ return;
+ }
+
+ CTEGetLock(&spxTimerLock, &lockHandle);
+#endif _PNP_POWER
+
+ SpxTimerCurrentTime ++; // Update our relative time
+
+#ifdef PROFILING
+ // This is the only place where this is changed. And it always increases.
+ SpxStatistics.stat_ElapsedTime = SpxTimerCurrentTime;
+#endif
+
+ // We should never be here if we have no work to do
+ if ((spxTimerList != NULL))
+ {
+ // Careful here. If two guys wanna go off together - let them !!
+ if (spxTimerList->tmr_RelDelta != 0)
+ (spxTimerList->tmr_RelDelta)--;
+
+ // Dispatch the entry if it is ready to go
+ if (spxTimerList->tmr_RelDelta == 0)
+ {
+ pList = spxTimerList;
+ CTEAssert(VALID_TMR(pList));
+
+ // Unlink from the list
+ spxTimerList = pList->tmr_Next;
+ if (spxTimerList != NULL)
+ spxTimerList->tmr_Prev = &spxTimerList;
+
+ // Unlink from the hash table now
+ for (ppList = &spxTimerTable[pList->tmr_Id % TIMER_HASH_TABLE];
+ *ppList != NULL;
+ ppList = &((*ppList)->tmr_Overflow))
+ {
+ CTEAssert(VALID_TMR(*ppList));
+ if (*ppList == pList)
+ {
+ *ppList = pList->tmr_Overflow;
+ break;
+ }
+ }
+
+ CTEAssert (*ppList == pList->tmr_Overflow);
+
+ DBGPRINT(SYSTEM, INFO,
+ ("spxTimerDpcRoutine: Dispatching %lx\n",
+ pList->tmr_Worker));
+
+ spxTimerDispatchCount ++;
+ spxTimerCount --;
+ spxTimerActive = pList;
+ CTEFreeLock(&spxTimerLock, lockHandle);
+
+ // If reenqueue time is 0, do not requeue. If 1, then requeue with
+ // current value, else use value specified.
+ ReEnqueueTime = (*pList->tmr_Worker)(pList->tmr_Context, FALSE);
+ DBGPRINT(SYSTEM, INFO,
+ ("spxTimerDpcRoutine: Reenequeu time %lx.%lx\n",
+ ReEnqueueTime, pList->tmr_AbsTime));
+
+ CTEGetLock(&spxTimerLock, &lockHandle);
+
+ spxTimerActive = NULL;
+ spxTimerDispatchCount --;
+
+ if (ReEnqueueTime != TIMER_DONT_REQUEUE)
+ {
+ // If this chappie was cancelled while it was running
+ // and it wants to be re-queued, do it right away.
+ if (pList->tmr_Cancelled)
+ {
+ (*pList->tmr_Worker)(pList->tmr_Context, FALSE);
+ SpxBPFreeBlock(pList, BLKID_TIMERLIST);
+ }
+ else
+ {
+ if (ReEnqueueTime != TIMER_REQUEUE_CUR_VALUE)
+ {
+ pList->tmr_AbsTime = ReEnqueueTime/SPX_MS_TO_TICKS;
+ if (pList->tmr_AbsTime == 0)
+ {
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxTimerDispatch: Requeue at %ld\n",
+ pList->tmr_AbsTime));
+ }
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxTimerDispatch: Requeue at %ld.%ld\n",
+ ReEnqueueTime, pList->tmr_AbsTime));
+ }
+
+ spxTimerEnqueue(pList);
+ }
+ }
+ else
+ {
+ SpxBPFreeBlock(pList, BLKID_TIMERLIST);
+ }
+ }
+ }
+
+#if defined(_PNP_POWER)
+ if (!spxTimerStopped)
+ {
+ TimerStarted = KeSetTimer(&spxTimer,
+ spxTimerTick,
+ &spxTimerDpc);
+
+ // it is possible that while we were here in Dpc, PNP_ADD_DEVICE
+ // restarted the timer, so this assert is commented out for PnP
+// CTEAssert(!TimerStarted);
+ }
+
+ CTEFreeLock(&spxTimerLock, lockHandle);
+#else
+ CTEFreeLock(&spxTimerLock, lockHandle);
+
+ if (!spxTimerStopped)
+ {
+ TimerStarted = KeSetTimer(&spxTimer,
+ spxTimerTick,
+ &spxTimerDpc);
+ CTEAssert(!TimerStarted);
+ }
+#endif _PNP_POWER
+}
+
+
+VOID
+spxTimerEnqueue(
+ IN PTIMERLIST pListNew
+ )
+/*++
+
+Routine Description:
+
+ Here is a thesis on the code that follows.
+
+ The timer events are maintained as a list which the timer dpc routine
+ looks at every timer tick. The list is maintained in such a way that only
+ the head of the list needs to be updated every tick i.e. the entire list
+ is never scanned. The way this is achieved is by keeping delta times
+ relative to the previous entry.
+
+ Every timer tick, the relative time at the head of the list is decremented.
+ When that goes to ZERO, the head of the list is unlinked and dispatched.
+
+ To give an example, we have the following events queued at time slots
+ X Schedule A after 10 ticks.
+ X+3 Schedule B after 5 ticks.
+ X+5 Schedule C after 4 ticks.
+ X+8 Schedule D after 6 ticks.
+
+ So A will schedule at X+10, B at X+8 (X+3+5), C at X+9 (X+5+4) and
+ D at X+14 (X+8+6).
+
+ The above example covers all the situations.
+
+ - NULL List.
+ - Inserting at head of list.
+ - Inserting in the middle of the list.
+ - Appending to the list tail.
+
+ The list will look as follows.
+
+ BEFORE AFTER
+ ------ -----
+
+ X Head -->| Head -> A(10) ->|
+ A(10)
+
+ X+3 Head -> A(7) ->| Head -> B(5) -> A(2) ->|
+ B(5)
+
+ X+5 Head -> B(3) -> A(2) ->| Head -> B(3) -> C(1) -> A(1) ->|
+ C(4)
+
+ X+8 Head -> C(1) -> A(1) ->| Head -> C(1) -> A(1) -> D(4) ->|
+ D(6)
+
+ The granularity is one tick. THIS MUST BE CALLED WITH THE TIMER LOCK HELD.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PTIMERLIST pList, *ppList;
+ ULONG DeltaTime = pListNew->tmr_AbsTime;
+
+ // The DeltaTime is adjusted in every pass of the loop to reflect the
+ // time after the previous entry that the new entry will schedule.
+ for (ppList = &spxTimerList;
+ (pList = *ppList) != NULL;
+ ppList = &pList->tmr_Next)
+ {
+ CTEAssert(VALID_TMR(pList));
+ if (DeltaTime <= pList->tmr_RelDelta)
+ {
+ pList->tmr_RelDelta -= DeltaTime;
+ break;
+ }
+ DeltaTime -= pList->tmr_RelDelta;
+ }
+
+
+ // Link this in the chain
+ pListNew->tmr_RelDelta = DeltaTime;
+ pListNew->tmr_Next = pList;
+ pListNew->tmr_Prev = ppList;
+ *ppList = pListNew;
+ if (pList != NULL)
+ {
+ pList->tmr_Prev = &pListNew->tmr_Next;
+ }
+
+ // Now link it in the hash table
+ pListNew->tmr_Overflow = spxTimerTable[pListNew->tmr_Id % TIMER_HASH_TABLE];
+ spxTimerTable[pListNew->tmr_Id % TIMER_HASH_TABLE] = pListNew;
+ spxTimerCount ++;
+}
+
+
+
+
+VOID
+SpxTimerFlushAndStop(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Force all entries in the timer queue to be dispatched immediately. No
+ more queue'ing of timer routines is permitted after this. The timer
+ essentially shuts down.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PTIMERLIST pList;
+ CTELockHandle lockHandle;
+
+ CTEAssert (KeGetCurrentIrql() == LOW_LEVEL);
+
+ DBGPRINT(SYSTEM, ERR,
+ ("SpxTimerFlushAndStop: Entered\n"));
+
+ CTEGetLock(&spxTimerLock, &lockHandle);
+
+ spxTimerStopped = TRUE;
+
+ KeCancelTimer(&spxTimer);
+
+ if (spxTimerList != NULL)
+ {
+ // Dispatch all entries right away
+ while (spxTimerList != NULL)
+ {
+ pList = spxTimerList;
+ CTEAssert(VALID_TMR(pList));
+ spxTimerList = pList->tmr_Next;
+
+ DBGPRINT(SYSTEM, INFO,
+ ("spxTimerFlushAndStop: Dispatching %lx\n",
+ pList->tmr_Worker));
+
+ // The timer routines assume they are being called at DISPATCH
+ // level. This is OK since we are calling with SpinLock held.
+
+ (*pList->tmr_Worker)(pList->tmr_Context, TRUE);
+
+ spxTimerCount --;
+ SpxBPFreeBlock(pList, BLKID_TIMERLIST);
+ }
+ RtlZeroMemory(spxTimerTable, sizeof(spxTimerTable));
+ }
+
+ CTEFreeLock(&spxTimerLock, lockHandle);
+
+ // Wait for all timer routines to complete
+ while (spxTimerDispatchCount != 0)
+ {
+ SpxSleep(SPX_TIMER_WAIT);
+ }
+}
+
+
+
+
+BOOLEAN
+SpxTimerCancelEvent(
+ IN ULONG TimerId,
+ IN BOOLEAN ReEnqueue
+ )
+/*++
+
+Routine Description:
+
+ Cancel a previously scheduled timer event, if it hasn't fired already.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PTIMERLIST pList, *ppList;
+ CTELockHandle lockHandle;
+
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxTimerCancelEvent: Entered for TimerId %ld\n", TimerId));
+
+ CTEAssert(TimerId != 0);
+
+ CTEGetLock(&spxTimerLock, &lockHandle);
+
+ for (ppList = &spxTimerTable[TimerId % TIMER_HASH_TABLE];
+ (pList = *ppList) != NULL;
+ ppList = &pList->tmr_Overflow)
+ {
+ CTEAssert(VALID_TMR(pList));
+ // If we find it, cancel it
+ if (pList->tmr_Id == TimerId)
+ {
+ // Unlink this from the hash table
+ *ppList = pList->tmr_Overflow;
+
+ // ... and from the list
+ if (pList->tmr_Next != NULL)
+ {
+ pList->tmr_Next->tmr_RelDelta += pList->tmr_RelDelta;
+ pList->tmr_Next->tmr_Prev = pList->tmr_Prev;
+ }
+ *(pList->tmr_Prev) = pList->tmr_Next;
+
+ spxTimerCount --;
+ if (ReEnqueue)
+ spxTimerEnqueue(pList);
+ else SpxBPFreeBlock(pList, BLKID_TIMERLIST);
+ break;
+ }
+ }
+
+ // If we could not find it in the list, see if it currently running.
+ // If so mark him to not reschedule itself, only if reenqueue was false.
+ if (pList == NULL)
+ {
+ if ((spxTimerActive != NULL) &&
+ (spxTimerActive->tmr_Id == TimerId) &&
+ !ReEnqueue)
+ {
+ spxTimerActive->tmr_Cancelled = TRUE;
+ }
+ }
+
+ CTEFreeLock(&spxTimerLock, lockHandle);
+
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxTimerCancelEvent: %s for Id %ld\n",
+ (pList != NULL) ? "Success" : "Failure", TimerId));
+
+ return (pList != NULL);
+}
+
+
+
+
+#if DBG
+
+VOID
+SpxTimerDumpList(
+ VOID
+ )
+{
+ PTIMERLIST pList;
+ ULONG CumTime = 0;
+ CTELockHandle lockHandle;
+
+ DBGPRINT(DUMP, FATAL,
+ ("TIMER LIST: (Times are in %dms units\n", 1000));
+ DBGPRINT(DUMP, FATAL,
+ ("\tTimerId Time(Abs) Time(Rel) Routine Address\n"));
+
+ CTEGetLock(&spxTimerLock, &lockHandle);
+
+ for (pList = spxTimerList;
+ pList != NULL;
+ pList = pList->tmr_Next)
+ {
+ CumTime += pList->tmr_RelDelta;
+ DBGPRINT(DUMP, FATAL,
+ ("\t% 6lx %5d %5ld %lx\n",
+ pList->tmr_Id, pList->tmr_AbsTime, CumTime, pList->tmr_Worker));
+ }
+
+ CTEFreeLock(&spxTimerLock, lockHandle);
+}
+
+#endif
diff --git a/private/ntos/tdi/isnp/spx/spxutils.c b/private/ntos/tdi/isnp/spx/spxutils.c
new file mode 100644
index 000000000..024a36988
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/spxutils.c
@@ -0,0 +1,484 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxutils.c
+
+Abstract:
+
+ This contains all utility routines for the ISN SPX module.
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXUTILS
+
+UINT
+SpxUtilWstrLength(
+ IN PWSTR Wstr
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ UINT length = 0;
+
+ while (*Wstr++)
+ {
+ length += sizeof(WCHAR);
+ }
+
+ return length;
+}
+
+
+
+
+LONG
+SpxRandomNumber(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LARGE_INTEGER Li;
+ static LONG seed = 0;
+
+ // Return a positive pseudo-random number; simple linear congruential
+ // algorithm. ANSI C "rand()" function.
+
+ if (seed == 0)
+ {
+ KeQuerySystemTime(&Li);
+ seed = Li.LowPart;
+ }
+
+ seed *= (0x41C64E6D + 0x3039);
+
+ return (seed & 0x7FFFFFFF);
+}
+
+
+
+
+NTSTATUS
+SpxUtilGetSocketType(
+ PUNICODE_STRING RemainingFileName,
+ PBYTE SocketType
+ )
+/*++
+
+Routine Description:
+
+ For PROTO_SPX, i'd return a device name from the dll of the form
+ \Device\IsnSpx\SpxStream (for SOCK_STREAM) or
+ \Device\IsnSpx\Spx (for SOCK_SEQPKT)
+
+ and for PROTO_SPXII (the more common case we hope, even if
+ internally we degrade to SPX1 cause of the remote client's
+ limitations)
+ \Device\IsnSpx\Stream (for SOCK_STREAM) or
+ \Device\IsnSpx (for SOCK_SEQPKT)
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ UNICODE_STRING typeString;
+
+ *SocketType = SOCKET2_TYPE_SEQPKT;
+
+ // Check for the socket type
+ do
+ {
+ if (RemainingFileName->Length == 0)
+ {
+ break;
+ }
+
+ if ((UINT)RemainingFileName->Length ==
+ SpxUtilWstrLength(SOCKET1STREAM_SUFFIX))
+ {
+ RtlInitUnicodeString(&typeString, SOCKET1STREAM_SUFFIX);
+
+ // Case insensitive compare
+ if (RtlEqualUnicodeString(&typeString, RemainingFileName, TRUE))
+ {
+ *SocketType = SOCKET1_TYPE_STREAM;
+ break;
+ }
+ }
+
+ if ((UINT)RemainingFileName->Length ==
+ SpxUtilWstrLength(SOCKET1_SUFFIX))
+ {
+ RtlInitUnicodeString(&typeString, SOCKET1_SUFFIX);
+
+ // Case insensitive compare
+ if (RtlEqualUnicodeString(&typeString, RemainingFileName, TRUE))
+ {
+ *SocketType = SOCKET1_TYPE_SEQPKT;
+ break;
+ }
+ }
+
+ if ((UINT)RemainingFileName->Length ==
+ SpxUtilWstrLength(SOCKET2STREAM_SUFFIX))
+ {
+ RtlInitUnicodeString(&typeString, SOCKET2STREAM_SUFFIX);
+
+ // Case insensitive compare
+ if (RtlEqualUnicodeString(&typeString, RemainingFileName, TRUE))
+ {
+ *SocketType = SOCKET2_TYPE_STREAM;
+ break;
+ }
+ }
+
+ status = STATUS_NO_SUCH_DEVICE;
+
+ } while (FALSE);
+
+ return(status);
+}
+
+
+
+
+#define ONE_MS_IN_100ns -10000L // 1ms in 100ns units
+
+VOID
+SpxSleep(
+ IN ULONG TimeInMs
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ KTIMER SleepTimer;
+
+ ASSERT (KeGetCurrentIrql() == LOW_LEVEL);
+
+ KeInitializeTimer(&SleepTimer);
+
+ KeSetTimer(&SleepTimer,
+ RtlConvertLongToLargeInteger(TimeInMs * ONE_MS_IN_100ns),
+ NULL);
+
+ KeWaitForSingleObject(&SleepTimer, UserRequest, KernelMode, FALSE, NULL);
+ return;
+}
+
+
+
+
+TDI_ADDRESS_IPX UNALIGNED *
+SpxParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, looking for an address
+ of type TDI_ADDRESS_TYPE_IPX.
+
+Arguments:
+
+ Transport - The generic TDI address.
+
+Return Value:
+
+ A pointer to the IPX address, or NULL if none is found.
+
+--*/
+
+{
+ TA_ADDRESS UNALIGNED * addressName;
+ INT i;
+
+ addressName = &TransportAddress->Address[0];
+
+ // The name can be passed with multiple entries; we'll take and use only
+ // the IPX one.
+ for (i=0;i<TransportAddress->TAAddressCount;i++)
+ {
+ if (addressName->AddressType == TDI_ADDRESS_TYPE_IPX)
+ {
+ if (addressName->AddressLength >= sizeof(TDI_ADDRESS_IPX))
+ {
+ return ((TDI_ADDRESS_IPX UNALIGNED *)(addressName->Address));
+ }
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+ return NULL;
+
+} // SpxParseTdiAddress
+
+
+
+BOOLEAN
+SpxValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, verifying that the
+ components of the address do not extend past the specified
+ length.
+
+Arguments:
+
+ TransportAddress - The generic TDI address.
+
+ TransportAddressLength - The specific length of TransportAddress.
+
+Return Value:
+
+ TRUE if the address is valid, FALSE otherwise.
+
+--*/
+
+{
+ PUCHAR AddressEnd = ((PUCHAR)TransportAddress) + TransportAddressLength;
+ TA_ADDRESS UNALIGNED * addressName;
+ INT i;
+
+ if (TransportAddressLength < sizeof(TransportAddress->TAAddressCount))
+ {
+ DBGPRINT(TDI, ERR,
+ ("SpxValidateTdiAddress: runt address\n"));
+
+ return FALSE;
+ }
+
+ addressName = &TransportAddress->Address[0];
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++)
+ {
+ if (addressName->Address > AddressEnd)
+ {
+ DBGPRINT(TDI, ERR,
+ ("SpxValidateTdiAddress: address too short\n"));
+
+ return FALSE;
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+
+ if ((PUCHAR)addressName > AddressEnd)
+ {
+ DBGPRINT(TDI, ERR,
+ ("SpxValidateTdiAddress: address too short\n"));
+
+ return FALSE;
+ }
+ return TRUE;
+
+} // SpxValidateTdiAddress
+
+
+
+
+ULONG
+SpxBuildTdiAddress(
+ IN PVOID AddressBuffer,
+ IN ULONG AddressBufferLength,
+ IN UCHAR Network[4],
+ IN UCHAR Node[6],
+ IN USHORT Socket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine fills in a TRANSPORT_ADDRESS in the specified
+ buffer, given the socket, network and node. It will write
+ less than the full address if the buffer is too short.
+
+Arguments:
+
+ AddressBuffer - The buffer that will hold the address.
+
+ AddressBufferLength - The length of the buffer.
+
+ Network - The network number.
+
+ Node - The node address.
+
+ Socket - The socket.
+
+Return Value:
+
+ The number of bytes written into AddressBuffer.
+
+--*/
+
+{
+ TA_IPX_ADDRESS UNALIGNED * SpxAddress;
+ TA_IPX_ADDRESS TempAddress;
+
+ if (AddressBufferLength >= sizeof(TA_IPX_ADDRESS))
+ {
+ SpxAddress = (TA_IPX_ADDRESS UNALIGNED *)AddressBuffer;
+ }
+ else
+ {
+ SpxAddress = (TA_IPX_ADDRESS UNALIGNED *)&TempAddress;
+ }
+
+ SpxAddress->TAAddressCount = 1;
+ SpxAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX);
+ SpxAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
+ SpxAddress->Address[0].Address[0].NetworkAddress = *(UNALIGNED LONG *)Network;
+ SpxAddress->Address[0].Address[0].Socket = Socket;
+ RtlCopyMemory(SpxAddress->Address[0].Address[0].NodeAddress, Node, 6);
+
+ if (AddressBufferLength >= sizeof(TA_IPX_ADDRESS))
+ {
+ return sizeof(TA_IPX_ADDRESS);
+ }
+ else
+ {
+ RtlCopyMemory(AddressBuffer, &TempAddress, AddressBufferLength);
+ return AddressBufferLength;
+ }
+
+} // SpxBuildTdiAddress
+
+
+
+VOID
+SpxBuildTdiAddressFromIpxAddr(
+ IN PVOID AddressBuffer,
+ IN PBYTE pIpxAddr
+ )
+{
+ TA_IPX_ADDRESS UNALIGNED * SpxAddress;
+
+ SpxAddress = (TA_IPX_ADDRESS UNALIGNED *)AddressBuffer;
+ SpxAddress->TAAddressCount = 1;
+ SpxAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX);
+ SpxAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
+ SpxAddress->Address[0].Address[0].NetworkAddress = *(UNALIGNED LONG *)pIpxAddr;
+ RtlCopyMemory(
+ SpxAddress->Address[0].Address[0].NodeAddress,
+ pIpxAddr+4,
+ 6);
+
+ GETSHORT2SHORT(
+ &SpxAddress->Address[0].Address[0].Socket,
+ pIpxAddr + 10);
+
+ return;
+}
+
+
+
+VOID
+SpxCalculateNewT1(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ IN int NewT1
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ NewT1 - New value for the RTT in ms.
+
+Return Value:
+
+
+--*/
+{
+ int baseT1, error;
+
+ //
+ // VAN JACOBSEN Algorithm. From Internetworking with Tcp/ip
+ // (Comer) book.
+ //
+
+ error = NewT1 - (pSpxConnFile->scf_AveT1 >> 3);
+ pSpxConnFile->scf_AveT1 += error;
+ if (pSpxConnFile->scf_AveT1 <= 0) // Make sure not too small
+ {
+ pSpxConnFile->scf_AveT1 = SPX_T1_MIN;
+ }
+
+ if (error < 0)
+ error = -error;
+
+ error -= (pSpxConnFile->scf_DevT1 >> 2);
+ pSpxConnFile->scf_DevT1 += error;
+ if (pSpxConnFile->scf_DevT1 <= 0)
+ pSpxConnFile->scf_DevT1 = 1;
+
+ baseT1 = (((pSpxConnFile->scf_AveT1 >> 2) + pSpxConnFile->scf_DevT1) >> 1);
+
+ // If less then min - set it
+ if (baseT1 < SPX_T1_MIN)
+ baseT1 = SPX_T1_MIN;
+
+ // Set the new value
+ DBGPRINT(TDI, DBG,
+ ("SpxCalculateNewT1: Old value %lx New %lx\n",
+ pSpxConnFile->scf_BaseT1, baseT1));
+
+ pSpxConnFile->scf_BaseT1 = baseT1;
+
+ // At the time of restarting the timer,we convert this to a tick value.
+ return;
+}
+
diff --git a/private/ntos/tdi/isnp/spx/up/makefile b/private/ntos/tdi/isnp/spx/up/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/up/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isnp/spx/up/sources b/private/ntos/tdi/isnp/spx/up/sources
new file mode 100644
index 000000000..85cdb3764
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/up/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+UP_DRIVER=yes
+
+TARGETPATH=obj
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/loopback/connect.c b/private/ntos/tdi/loopback/connect.c
new file mode 100644
index 000000000..10376e3e8
--- /dev/null
+++ b/private/ntos/tdi/loopback/connect.c
@@ -0,0 +1,1593 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ connect.c
+
+Abstract:
+
+ This module implements connection logic for the loopback Transport
+ Provider driver for NT LAN Manager.
+
+Author:
+
+ Chuck Lenzmeier (chuckl) 15-Aug-1991
+
+Revision History:
+
+--*/
+
+#include "loopback.h"
+
+//
+// Local declarations
+//
+
+STATIC
+NTSTATUS
+CompleteConnection (
+ IN PIRP ListenIrp,
+ IN PIRP ConnectIrp
+ );
+
+STATIC
+VOID
+IndicateConnect (
+ IN PLOOP_ENDPOINT Endpoint
+ );
+
+
+NTSTATUS
+LoopAccept (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an Accept request.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+
+ IrpSp - Pointer to current stack location in IRP
+
+Return Value:
+
+ NTSTATUS - Status of request
+
+--*/
+
+{
+ NTSTATUS status;
+ PTDI_REQUEST_KERNEL_ACCEPT acceptRequest;
+ PLOOP_CONNECTION connection;
+ PLOOP_ENDPOINT endpoint;
+
+ IF_DEBUG(LOOP1) DbgPrint( " Accept request\n" );
+
+ acceptRequest = (PTDI_REQUEST_KERNEL_ACCEPT)&IrpSp->Parameters;
+
+ ACQUIRE_LOOP_LOCK( "Accept initial" );
+
+ //
+ // Verify that the connection is in the proper state.
+ //
+
+ connection = (PLOOP_CONNECTION)IrpSp->FileObject->FsContext;
+
+ if ( connection == NULL ) {
+ RELEASE_LOOP_LOCK( "Accept control channel" );
+ IF_DEBUG(LOOP2) DbgPrint( " Can't Accept on control channel\n" );
+ status = STATUS_INVALID_PARAMETER;
+ goto complete;
+ }
+
+ if ( GET_BLOCK_STATE(connection) != BlockStateBound ) {
+ RELEASE_LOOP_LOCK( "Accept conn not bound" );
+ IF_DEBUG(LOOP2) DbgPrint( " Connection not bound\n" );
+ status = STATUS_INVALID_PARAMETER;
+ goto complete;
+ }
+
+ //
+ // There must be an indication in progress on the endpoint.
+ //
+ // *** The loopback driver does not support delayed accept on
+ // TdiListen, but does on connect indications.
+ //
+
+ endpoint = connection->Endpoint;
+
+ if ( endpoint->IndicatingConnectIrp == NULL ) {
+ RELEASE_LOOP_LOCK( "Endpoint not indicating connect" );
+ IF_DEBUG(LOOP2) DbgPrint( " Endpoint not indicating connect\n" );
+ status = STATUS_INVALID_PARAMETER;
+ goto complete;
+ }
+
+ //
+ // Link the connections together. Indicate that the connect
+ // indication is no longer in progress.
+ //
+
+ CompleteConnection( Irp, endpoint->IndicatingConnectIrp );
+
+ endpoint->IndicatingConnectIrp = NULL;
+
+ RELEASE_LOOP_LOCK( "Accept connect completed" );
+
+ IF_DEBUG(LOOP1) DbgPrint( " Accept request complete\n" );
+ return STATUS_SUCCESS;
+
+complete:
+
+ //
+ // Complete the Accept request.
+ //
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest( Irp, 0 );
+
+ IF_DEBUG(LOOP1) DbgPrint( " Accept request complete\n" );
+ return status;
+
+} // LoopAccept
+
+
+NTSTATUS
+LoopAssociateAddress (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an Associate Address request.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+
+ IrpSp - Pointer to current stack location in IRP
+
+Return Value:
+
+ NTSTATUS - Status of request
+
+--*/
+
+{
+ NTSTATUS status;
+ PTDI_REQUEST_KERNEL_ASSOCIATE associateRequest;
+ PLOOP_CONNECTION connection;
+ PFILE_OBJECT endpointFileObject = NULL;
+ PLOOP_ENDPOINT endpoint;
+
+ IF_DEBUG(LOOP1) DbgPrint( " Associate request\n" );
+
+ associateRequest = (PTDI_REQUEST_KERNEL_ASSOCIATE)&IrpSp->Parameters;
+
+ //
+ // Translate the address handle to a pointer to the address endpoint
+ // file object. Get a pointer to the loopback endpoint block.
+ // Verify that it is really a loopback endpoint.
+ //
+
+ status = ObReferenceObjectByHandle (
+ associateRequest->AddressHandle,
+ 0,
+ 0,
+ KernelMode,
+ (PVOID *)&endpointFileObject,
+ NULL);
+
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(LOOP2) DbgPrint( " Invalid endpoint handle\n" );
+ goto complete;
+ }
+
+ ACQUIRE_LOOP_LOCK( "Associate initial" );
+
+ endpoint = (PLOOP_ENDPOINT)endpointFileObject->FsContext;
+ status = LoopVerifyEndpoint( endpoint );
+
+ if ( !NT_SUCCESS(status) ) {
+ RELEASE_LOOP_LOCK( "Associate bad endpoint pointer" );
+ IF_DEBUG(LOOP2) DbgPrint( " Invalid endpoint pointer\n" );
+ goto complete;
+ }
+
+ //
+ // Verify that the connection is in the proper state.
+ //
+
+ connection = (PLOOP_CONNECTION)IrpSp->FileObject->FsContext;
+
+ if ( connection == NULL ) {
+ RELEASE_LOOP_LOCK( "Associate control channel" );
+ IF_DEBUG(LOOP2) DbgPrint( " Can't Associate on control channel\n" );
+ status = STATUS_INVALID_PARAMETER;
+ goto complete;
+ }
+
+ if ( GET_BLOCK_STATE(connection) != BlockStateUnbound ) {
+ RELEASE_LOOP_LOCK( "Associate conn not unbound" );
+ IF_DEBUG(LOOP2) DbgPrint( " Connection not unbound\n" );
+ status = STATUS_INVALID_PARAMETER;
+ goto complete;
+ }
+
+ //
+ // Verify that the endpoint is in the proper state.
+ //
+
+ if ( GET_BLOCK_STATE(endpoint) != BlockStateActive ) {
+ RELEASE_LOOP_LOCK( "Associate endpoint not active" );
+ IF_DEBUG(LOOP2) DbgPrint( " Endpoint not active\n" );
+ status = STATUS_INVALID_PARAMETER;
+ goto complete;
+ }
+
+ //
+ // Link this connection into the endpoint's connection list.
+ // Reference the endpoint block. Indicate that the connection has
+ // been bound to an address. Dereference the endpoint file object.
+ //
+
+ InsertTailList(
+ &endpoint->ConnectionList,
+ &connection->EndpointListEntry
+ );
+
+ endpoint->BlockHeader.ReferenceCount++;
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " New refcnt on endpoint %lx is %lx\n",
+ endpoint, endpoint->BlockHeader.ReferenceCount );
+ }
+
+ SET_BLOCK_STATE( connection, BlockStateBound );
+
+ connection->Endpoint = endpoint;
+
+ RELEASE_LOOP_LOCK( "Associate done" );
+
+ status = STATUS_SUCCESS;
+
+complete:
+
+ //
+ // Dereference the endpoint file object, if necessary.
+ //
+
+ if ( endpointFileObject != NULL ) {
+ ObDereferenceObject( endpointFileObject );
+ }
+
+ //
+ // Complete the Associate request.
+ //
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest( Irp, 0 );
+
+ IF_DEBUG(LOOP1) DbgPrint( " Associate request complete\n" );
+ return status;
+
+} // LoopAssociateAddress
+
+
+NTSTATUS
+LoopConnect (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a Connect request.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+
+ IrpSp - Pointer to current stack location in IRP
+
+Return Value:
+
+ NTSTATUS - Status of request
+
+--*/
+
+{
+ NTSTATUS status;
+ PTDI_REQUEST_KERNEL_CONNECT connectRequest;
+ CHAR netbiosName[NETBIOS_NAME_LENGTH+1];
+ PLOOP_CONNECTION connection;
+ PLOOP_ENDPOINT remoteEndpoint;
+ BOOLEAN firstConnect;
+
+ IF_DEBUG(LOOP1) DbgPrint( " Connect request\n" );
+
+ //
+ // Parse the remote address.
+ //
+
+ connectRequest = (PTDI_REQUEST_KERNEL_CONNECT)&IrpSp->Parameters;
+
+ status = LoopParseAddress(
+ (PTA_NETBIOS_ADDRESS)connectRequest->
+ RequestConnectionInformation->RemoteAddress,
+ netbiosName
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(LOOP2) DbgPrint( " Invalid remote address\n" );
+ goto complete;
+ }
+
+ netbiosName[NETBIOS_NAME_LENGTH] = 0; // ensure null-termination
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Address to connect to: \"%s\"\n", netbiosName );
+ }
+
+ //
+ // Make sure that the connection is in the right state.
+ //
+
+ ACQUIRE_LOOP_LOCK( "Connect initial" );
+
+ connection = (PLOOP_CONNECTION)IrpSp->FileObject->FsContext;
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Connection address: %lx\n", connection );
+ }
+
+ if ( connection == NULL ) {
+ RELEASE_LOOP_LOCK( "Connect control channel" );
+ IF_DEBUG(LOOP2) DbgPrint( " Can't Connect on control channel\n" );
+ status = STATUS_INVALID_PARAMETER;
+ goto complete;
+ }
+
+ if ( GET_BLOCK_STATE(connection) != BlockStateBound ) {
+ RELEASE_LOOP_LOCK( "Connection not bound" );
+ IF_DEBUG(LOOP2) DbgPrint( " Local endpoint not bound\n" );
+ status = STATUS_INVALID_PARAMETER;
+ goto complete;
+ }
+
+ //
+ // Find an endpoint with the target address.
+ //
+
+ remoteEndpoint = LoopFindBoundAddress( netbiosName );
+
+ if ( remoteEndpoint == NULL ) {
+ RELEASE_LOOP_LOCK( "Connect no such address" );
+ IF_DEBUG(LOOP2) DbgPrint( " Address does not exist\n" );
+ status = STATUS_INVALID_PARAMETER;
+ goto complete;
+ }
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Target endpoint address: %lx\n", remoteEndpoint );
+ }
+
+ //
+ // Set the connection state to Connecting, to prevent further
+ // connects or listens.
+ //
+
+ SET_BLOCK_STATE( connection, BlockStateConnecting );
+
+ //
+ // Determine whether this is the first active incoming Connect for
+ // the remote endpoint.
+ //
+
+ firstConnect = (BOOLEAN)( remoteEndpoint->IncomingConnectList.Flink ==
+ &remoteEndpoint->IncomingConnectList );
+
+ //
+ // Queue the Connect to the remote endpoint's Incoming Connect list,
+ // in order to prevent another Connect from getting ahead of this
+ // one.
+ //
+
+ InsertTailList(
+ &remoteEndpoint->IncomingConnectList,
+ &Irp->Tail.Overlay.ListEntry
+ );
+
+ IoMarkIrpPending( Irp );
+
+ if ( !firstConnect || (remoteEndpoint->IndicatingConnectIrp != NULL) ) {
+
+ //
+ // A pending Connect already exists, or a Connect indication is
+ // in progress. This Connect remains behind the already pending
+ // Connect.
+ //
+
+ IF_DEBUG(LOOP2) DbgPrint( " Connect already pending\n" );
+
+ RELEASE_LOOP_LOCK( "Connect connects pending" );
+
+ } else {
+
+ //
+ // Indicate the incoming Connect.
+ //
+ // *** Note that IndicateConnect returns with the loopback
+ // driver spin lock released.
+ //
+
+ IF_DEBUG(LOOP2) DbgPrint( " LoopConnect indicating connect\n" );
+ IndicateConnect( remoteEndpoint );
+
+ }
+
+ IF_DEBUG(LOOP1) DbgPrint( " Connect request complete\n" );
+ return status;
+
+complete:
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest( Irp, 0 );
+
+ IF_DEBUG(LOOP1) DbgPrint( " Connect request complete\n" );
+ return status;
+
+} // LoopConnect
+
+
+VOID
+LoopDereferenceConnection (
+ IN PLOOP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to dereference a connection block. If the
+ reference count on the block goes to one, and the connection is in
+ the process of disconnecting, the connection block is reset to the
+ Bound state. If the reference count on the block goes to zero, the
+ connection block is deleted.
+
+ The Loopback device object's spin lock must be held when this
+ routine is called.
+
+Arguments:
+
+ Connection - Supplies a pointer to a connection block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIRP disconnectIrp = NULL;
+ PIRP closeIrp = NULL;
+
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " Dereferencing connection %lx; old refcnt %lx\n",
+ Connection, Connection->BlockHeader.ReferenceCount );
+ }
+
+ ASSERT( (LONG)Connection->BlockHeader.ReferenceCount > 0 );
+
+ if ( --Connection->BlockHeader.ReferenceCount != 0 ) {
+ return;
+ }
+
+ //
+ // The reference count has gone to zero. Save the address of the
+ // pending Disconnect IRP, if any -- we'll complete the IRP later.
+ // If the connection state is Disconnecting, reset it to Bound. If
+ // the connection state is Closed, delete it.
+ //
+
+ disconnectIrp = Connection->DisconnectIrp;
+ Connection->DisconnectIrp = NULL;
+
+ //
+ // If the connection state is Disconnecting, reset it to Bound or
+ // Unbound, depending on the state of the endpoint. If the
+ // connection state is Closed, delete the connection. Note that the
+ // connection state may also be Closing, which means that an
+ // inactive connection's handle has been closed. We do nothing in
+ // this case; instead we wait until the Close IRP arrives.
+ //
+
+ if ( GET_BLOCK_STATE(Connection) == BlockStateDisconnecting ) {
+
+ if ( GET_BLOCK_STATE(Connection->Endpoint) == BlockStateActive ) {
+
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " Resetting connection %lx to Bound\n",
+ Connection );
+ }
+ SET_BLOCK_STATE( Connection, BlockStateBound );
+
+ } else {
+
+ PLOOP_ENDPOINT endpoint;
+
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " Resetting connection %lx to Unbound\n",
+ Connection );
+ }
+ endpoint = Connection->Endpoint;
+ ASSERT( endpoint != NULL );
+ Connection->Endpoint = NULL;
+
+ SET_BLOCK_STATE( Connection, BlockStateUnbound );
+
+ RemoveEntryList( &Connection->EndpointListEntry );
+ LoopDereferenceEndpoint( endpoint );
+
+ }
+
+ RELEASE_LOOP_LOCK( "Reset connection done" );
+
+ } else if ( GET_BLOCK_STATE(Connection) == BlockStateClosed ) {
+
+ //
+ // The connection file object has been closed, so we can
+ // deallocate the connection block now.
+ //
+
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " Deleting connection %lx\n", Connection );
+ }
+
+ //
+ // Save the address of the pending Close IRP, if any -- we'll
+ // complete the IRP later.
+ //
+
+ closeIrp = Connection->CloseIrp;
+ Connection->CloseIrp = NULL;
+
+ //
+ // Unlink the connection from the endpoint's connection list.
+ //
+
+ if ( Connection->Endpoint != NULL ) {
+ RemoveEntryList( &Connection->EndpointListEntry );
+ LoopDereferenceEndpoint( Connection->Endpoint );
+ }
+
+ //
+ // Unlink the connection from the device's connection list.
+ //
+
+ RemoveEntryList( &Connection->DeviceListEntry );
+
+ RELEASE_LOOP_LOCK( "DerefConn deleting" );
+
+ ObDereferenceObject( Connection->DeviceObject );
+
+ //
+ // Deallocate the connection block.
+ //
+
+ DEBUG SET_BLOCK_TYPE( Connection, BlockTypeGarbage );
+ DEBUG SET_BLOCK_STATE( Connection, BlockStateDead );
+ DEBUG SET_BLOCK_SIZE( Connection, -1 );
+ DEBUG Connection->BlockHeader.ReferenceCount = -1;
+ DEBUG Connection->Endpoint = NULL;
+ DEBUG Connection->RemoteConnection = NULL;
+
+ ExFreePool( Connection );
+
+ } else {
+
+ ASSERT( GET_BLOCK_STATE(Connection) == BlockStateClosing );
+
+ RELEASE_LOOP_LOCK( "DerefConn closing -- no action" );
+
+ }
+
+ //
+ // If a Disconnect IRP is pending, complete it now.
+ //
+
+ if ( disconnectIrp != NULL ) {
+
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " Completing Disconnect IRP %lx\n",
+ disconnectIrp );
+ }
+ disconnectIrp->IoStatus.Status = STATUS_SUCCESS;
+ disconnectIrp->IoStatus.Information = 0;
+
+ IoCompleteRequest( disconnectIrp, 2 );
+
+ }
+
+ //
+ // If a Close IRP is pending, complete it now.
+ //
+
+ if ( closeIrp != NULL ) {
+
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " Completing Close IRP %lx\n", closeIrp );
+ }
+ closeIrp->IoStatus.Status = STATUS_SUCCESS;
+ closeIrp->IoStatus.Information = 0;
+
+ IoCompleteRequest( closeIrp, 2 );
+
+ }
+
+ ACQUIRE_LOOP_LOCK( "DerefConn done" );
+
+ return;
+
+} // LoopDereferenceConnection
+
+
+NTSTATUS
+LoopDisassociateAddress (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a Disassociate Address request.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+
+ IrpSp - Pointer to current stack location in IRP
+
+Return Value:
+
+ NTSTATUS - Status of request
+
+--*/
+
+{
+ NTSTATUS status;
+ PLOOP_CONNECTION connection;
+ PLOOP_ENDPOINT endpoint;
+
+ IF_DEBUG(LOOP1) DbgPrint( " Disassociate request\n" );
+
+ ACQUIRE_LOOP_LOCK( "Disassociate initial" );
+
+ //
+ // Verify that the connection is in the proper state.
+ //
+
+ connection = (PLOOP_CONNECTION)IrpSp->FileObject->FsContext;
+
+ if ( connection == NULL ) {
+ RELEASE_LOOP_LOCK( "Disassociate control channel" );
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Can't Disassociate on control channel\n" );
+ }
+ status = STATUS_INVALID_PARAMETER;
+ goto complete;
+ }
+
+ if ( GET_BLOCK_STATE(connection) != BlockStateBound ) {
+ RELEASE_LOOP_LOCK( "Associate conn not bound" );
+ IF_DEBUG(LOOP2) DbgPrint( " Connection not bound\n" );
+ status = STATUS_INVALID_PARAMETER;
+ goto complete;
+ }
+
+ //
+ // Remove this connection from the endpoint's connection list.
+ // Dereference the endpoint block. Indicate that the connection is
+ // no longer bound to an address.
+ //
+
+ endpoint = connection->Endpoint;
+ ASSERT( endpoint != NULL );
+ connection->Endpoint = NULL;
+
+ SET_BLOCK_STATE( connection, BlockStateUnbound );
+
+ RemoveEntryList( &connection->EndpointListEntry );
+ LoopDereferenceEndpoint( endpoint );
+
+ RELEASE_LOOP_LOCK( "Disassociate done" );
+
+ status = STATUS_SUCCESS;
+
+complete:
+
+ //
+ // Complete the Disassociate request.
+ //
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest( Irp, 0 );
+
+ IF_DEBUG(LOOP1) DbgPrint( " Disassociate request complete\n" );
+ return status;
+
+} // LoopDisassociate
+
+
+NTSTATUS
+LoopDisconnect (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a Disconnect request.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+
+ IrpSp - Pointer to current stack location in IRP
+
+Return Value:
+
+ NTSTATUS - Status of request
+
+--*/
+
+{
+ NTSTATUS status;
+ PTDI_REQUEST_KERNEL_DISCONNECT disconnectRequest;
+ PLOOP_CONNECTION connection;
+
+ IF_DEBUG(LOOP1) DbgPrint( " Disconnect request\n" );
+
+ disconnectRequest = (PTDI_REQUEST_KERNEL_DISCONNECT)&IrpSp->Parameters;
+ connection = (PLOOP_CONNECTION)IrpSp->FileObject->FsContext;
+ IF_DEBUG(LOOP2) DbgPrint( " Connection: %lx\n", connection );
+
+ ACQUIRE_LOOP_LOCK( "Disconnect initial" );
+
+ if ( connection == NULL ) {
+ RELEASE_LOOP_LOCK( "Disconnect control channel" );
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Can't Disconnect on control channel\n" );
+ }
+ status = STATUS_INVALID_PARAMETER;
+ goto complete;
+ }
+
+ //
+ // If the connection state is Bound, then this Disconnect must have
+ // been issued from within a Connect indication.
+ //
+
+ if ( GET_BLOCK_STATE(connection) == BlockStateBound ) {
+
+ PIRP connectIrp = connection->Endpoint->IndicatingConnectIrp;
+
+ if ( connectIrp != NULL ) {
+
+ //
+ // Abort the indicating Connect.
+ //
+
+ connection->Endpoint->IndicatingConnectIrp = NULL;
+
+ RELEASE_LOOP_LOCK( "Disconnect abort indication" );
+
+ connectIrp->IoStatus.Status = STATUS_DISCONNECTED;
+ IoCompleteRequest( connectIrp, 2 );
+
+ } else {
+
+ RELEASE_LOOP_LOCK( "Disconnect bound, no indication" );
+
+ }
+
+ status = STATUS_SUCCESS;
+ goto complete;
+
+ }
+
+ if ( GET_BLOCK_STATE(connection) != BlockStateActive ) {
+
+ RELEASE_LOOP_LOCK( "Disconnect closing" );
+ IF_DEBUG(LOOP2) DbgPrint( " Connection already disconnected\n" );
+
+ status = STATUS_SUCCESS;
+ goto complete;
+
+ }
+
+ //
+ // Set the disconnect IRP pointer in the connection. The IRP will
+ // be completed when the connection is actually deleted.
+ //
+
+ IoMarkIrpPending( Irp );
+ connection->DisconnectIrp = Irp;
+
+ SET_BLOCK_STATE( connection, BlockStateDisconnecting );
+ LoopDoDisconnect( connection, TRUE );
+
+ RELEASE_LOOP_LOCK( "Disconnect done" );
+
+ return STATUS_PENDING;
+
+complete:
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest( Irp, 2 );
+
+ IF_DEBUG(LOOP1) DbgPrint( " Disconnect request complete\n" );
+ return status;
+
+} // LoopDisconnect
+
+
+VOID
+LoopDoDisconnect (
+ IN PLOOP_CONNECTION Connection,
+ IN BOOLEAN ClientInitiated
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does the work in disconnecting a connection. It is
+ called by LoopDisconnect and LoopDispatchClose.
+
+ The loopback device object's spin lock must be held when this
+ function is called. The lock is still held when the function
+ returns.
+
+Arguments:
+
+ Connection - Pointer to connection block
+
+ ClientInitiated - Indicates whether the local client initiated the
+ disconnect, either by issuing a TdiDisconnect or by closing the
+ endpoint
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLOOP_CONNECTION remoteConnection;
+ PLOOP_ENDPOINT endpoint;
+ PLIST_ENTRY listEntry;
+ PIRP pendingIrp;
+ PTDI_IND_DISCONNECT disconnectHandler;
+ PVOID disconnectContext;
+
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " DoDisconnect called for connection %lx\n",
+ Connection );
+ }
+
+ //
+ // If there is a remote connection, run it down first.
+ //
+
+ remoteConnection = Connection->RemoteConnection;
+ Connection->RemoteConnection = NULL;
+
+ if ( (remoteConnection != NULL) &&
+ (GET_BLOCK_STATE(remoteConnection) == BlockStateActive) ) {
+ SET_BLOCK_STATE( remoteConnection, BlockStateDisconnecting );
+ LoopDoDisconnect( remoteConnection, FALSE );
+ }
+
+ //
+ // Abort pending receives and sends.
+ //
+
+ listEntry = RemoveHeadList( &Connection->PendingReceiveList );
+
+ while ( listEntry != &Connection->PendingReceiveList ) {
+
+ LoopDereferenceConnection( Connection );
+
+ RELEASE_LOOP_LOCK( "DoDisc complete Receive" );
+
+ pendingIrp = CONTAINING_RECORD(
+ listEntry,
+ IRP,
+ Tail.Overlay.ListEntry
+ );
+ pendingIrp->IoStatus.Status = STATUS_DISCONNECTED;
+ IoCompleteRequest( pendingIrp, 2 );
+
+ ACQUIRE_LOOP_LOCK( "DoDisc complete Receive done" );
+
+ listEntry = RemoveHeadList( &Connection->PendingReceiveList );
+ }
+
+ listEntry = RemoveHeadList( &Connection->IncomingSendList );
+
+ while ( listEntry != &Connection->IncomingSendList ) {
+
+ LoopDereferenceConnection( remoteConnection );
+ LoopDereferenceConnection( Connection );
+
+ RELEASE_LOOP_LOCK( "DoDisc complete Send" );
+
+ pendingIrp = CONTAINING_RECORD(
+ listEntry,
+ IRP,
+ Tail.Overlay.ListEntry
+ );
+ pendingIrp->IoStatus.Status = STATUS_DISCONNECTED;
+ IoCompleteRequest( pendingIrp, 2 );
+
+ ACQUIRE_LOOP_LOCK( "DoDisc complete Send done" );
+
+ listEntry = RemoveHeadList( &Connection->IncomingSendList );
+ }
+
+ //
+ // If this is a remotely-initiated disconnect, and the local client
+ // has established a disconnect event handler, call that handler
+ // now.
+ //
+
+ endpoint = Connection->Endpoint;
+ disconnectHandler = endpoint->DisconnectHandler;
+ disconnectContext = endpoint->DisconnectContext;
+
+ if ( !ClientInitiated && (disconnectHandler != NULL) ) {
+ RELEASE_LOOP_LOCK( "DoDisc call handler" );
+ (VOID)disconnectHandler(
+ disconnectContext,
+ Connection->ConnectionContext,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ TDI_DISCONNECT_ABORT
+ );
+ ACQUIRE_LOOP_LOCK( "DoDisc call handler done" );
+ }
+
+ //
+ // Dereference the connection. This will result in the completion
+ // of the disconnect IRP, if the reference count goes to zero.
+ //
+
+ LoopDereferenceConnection( Connection );
+
+ return;
+
+} // LoopDoDisconnect
+
+
+NTSTATUS
+LoopListen (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a Listen request.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+
+ IrpSp - Pointer to current stack location in IRP
+
+Return Value:
+
+ NTSTATUS - Status of request
+
+--*/
+
+{
+ NTSTATUS status;
+ PLOOP_CONNECTION connection;
+ PLOOP_ENDPOINT endpoint;
+
+ IrpSp; // prevent compiler warnings
+
+ IF_DEBUG(LOOP1) DbgPrint( " Listen request\n" );
+
+ connection = (PLOOP_CONNECTION)IrpSp->FileObject->FsContext;
+ IF_DEBUG(LOOP2) DbgPrint( " Connection address: %lx\n", connection );
+
+ //
+ // !!! When the DELAYED_ACCEPT bit is defined, check here to ensure
+ // that it isn't set by the client. The loopback driver doesn't
+ // support delayed accept on Listen requests.
+ //
+
+ //
+ // Make sure the connection is in the right state.
+ //
+
+ ACQUIRE_LOOP_LOCK( "Listen initial" );
+
+ if ( connection == NULL ) {
+ RELEASE_LOOP_LOCK( "Listen control channel" );
+ IF_DEBUG(LOOP2) DbgPrint( " Can't Listen on control channel\n" );
+ status = STATUS_INVALID_PARAMETER;
+ goto complete;
+ }
+
+ if ( GET_BLOCK_STATE(connection) != BlockStateBound ) {
+ RELEASE_LOOP_LOCK( "Listen not bound" );
+ IF_DEBUG(LOOP2) DbgPrint( " Connection not bound\n" );
+ status = STATUS_INVALID_PARAMETER;
+ goto complete;
+ }
+
+ //
+ // Set the connection state to Connecting, to prevent further
+ // connects or listens.
+ //
+
+ SET_BLOCK_STATE( connection, BlockStateConnecting );
+
+ endpoint = connection->Endpoint;
+ IF_DEBUG(LOOP2) DbgPrint( " Endpoint address: %lx\n", endpoint );
+
+ //
+ // Queue the Listen to the endpoint's Pending Listen list.
+ //
+
+ InsertTailList(
+ &endpoint->PendingListenList,
+ &Irp->Tail.Overlay.ListEntry
+ );
+
+ IoMarkIrpPending( Irp );
+
+ //
+ // Check for a pending connect.
+ //
+
+ if ( (endpoint->IndicatingConnectIrp != NULL) ||
+ (endpoint->IncomingConnectList.Flink ==
+ &endpoint->IncomingConnectList) ) {
+
+ //
+ // There is no pending Connect, or a Connect indication is
+ // already in progress.
+ //
+
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " No pending Connect; leaving IRP %lx queued \n",
+ Irp );
+ }
+
+ RELEASE_LOOP_LOCK( "Listen no Connect" );
+
+ } else {
+
+ //
+ // There is a pending Connect. Call IndicateConnect to
+ // satisfy the Listen.
+ //
+ // *** Note that IndicateConnect returns with the loopback
+ // driver spin lock released.
+ //
+
+ IF_DEBUG(LOOP2) DbgPrint( " LoopListen indicating connect\n" );
+ IndicateConnect( endpoint );
+
+ }
+
+ IF_DEBUG(LOOP1) DbgPrint( " Listen request complete\n" );
+ return status;
+
+complete:
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest( Irp, 2 );
+
+ IF_DEBUG(LOOP1) DbgPrint( " Listen request complete\n" );
+ return status;
+
+} // LoopListen
+
+
+NTSTATUS
+CompleteConnection (
+ IN PIRP ListenIrp,
+ IN PIRP ConnectIrp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine completes the process of creating a connection. It
+ creates a connection block for each end of the connection and links
+ them together. The connection blocks are also linked off of their
+ respective endpoint blocks.
+
+ This routine must be called with the loopback device spin lock held.
+ The lock remains held when the function returns, although it is
+ released and reacquired during the function's operation.
+
+Arguments:
+
+ ListenIrp - Pointer to IRP used for Listen request
+
+ ConnectIrp - Pointer to IRP used for Connect request
+
+Return Value:
+
+ NTSTATUS - Indicates whether the connection was successfully created
+
+--*/
+
+{
+ NTSTATUS status;
+ PLOOP_CONNECTION listenerConnection;
+ PLOOP_CONNECTION connectorConnection;
+ PLOOP_ENDPOINT listenerEndpoint;
+ PLOOP_ENDPOINT connectorEndpoint;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL parameters;
+ PTDI_CONNECTION_INFORMATION connInfo;
+ TA_NETBIOS_ADDRESS connectorAddress;
+ TA_NETBIOS_ADDRESS listenerAddress;
+ int length;
+
+ //
+ // Get pointers.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation( ListenIrp );
+ listenerConnection = (PLOOP_CONNECTION)irpSp->FileObject->FsContext;
+ listenerEndpoint = listenerConnection->Endpoint;
+ irpSp = IoGetCurrentIrpStackLocation( ConnectIrp );
+ connectorConnection = (PLOOP_CONNECTION)irpSp->FileObject->FsContext;
+ connectorEndpoint = connectorConnection->Endpoint;
+
+ //
+ // Update the connection blocks.
+ //
+
+ listenerConnection->RemoteConnection = connectorConnection;
+ SET_BLOCK_STATE( listenerConnection, BlockStateActive );
+
+ connectorConnection->RemoteConnection = listenerConnection;
+ SET_BLOCK_STATE( connectorConnection, BlockStateActive );
+
+ //
+ // Increment the reference counts on the connections to account for
+ // the active link.
+ //
+
+ listenerConnection->BlockHeader.ReferenceCount++;
+ connectorConnection->BlockHeader.ReferenceCount++;
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " New refcnt on connection %lx is %lx\n",
+ listenerConnection,
+ listenerConnection->BlockHeader.ReferenceCount );
+ DbgPrint( " New refcnt on connection %lx is %lx\n",
+ connectorConnection,
+ connectorConnection->BlockHeader.ReferenceCount );
+ }
+
+ //
+ // Save the addresses of the connector and the listener.
+ //
+
+ connectorAddress.TAAddressCount = 1;
+ connectorAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ connectorAddress.Address[0].AddressLength = sizeof(TDI_ADDRESS_NETBIOS);
+ connectorAddress.Address[0].Address[0].NetbiosNameType =
+ TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ RtlMoveMemory(
+ connectorAddress.Address[0].Address[0].NetbiosName,
+ connectorEndpoint->NetbiosName,
+ NETBIOS_NAME_LENGTH
+ );
+
+ listenerAddress.TAAddressCount = 1;
+ listenerAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ listenerAddress.Address[0].AddressLength = sizeof(TDI_ADDRESS_NETBIOS);
+ listenerAddress.Address[0].Address[0].NetbiosNameType =
+ TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ RtlMoveMemory(
+ listenerAddress.Address[0].Address[0].NetbiosName,
+ listenerEndpoint->NetbiosName,
+ NETBIOS_NAME_LENGTH
+ );
+
+ //
+ // Complete the Listen (or Accept) and Connect I/O requests.
+ //
+
+ RELEASE_LOOP_LOCK( "CompleteConnection complete IRPs" );
+
+ irpSp = IoGetCurrentIrpStackLocation( ListenIrp );
+ parameters = (PTDI_REQUEST_KERNEL)&irpSp->Parameters;
+ connInfo = parameters->ReturnConnectionInformation;
+
+ status = STATUS_SUCCESS;
+
+ if ( connInfo != NULL ) {
+
+ length = connInfo->RemoteAddressLength;
+
+ if ( length != 0 ) {
+ length = MIN( sizeof(connectorAddress), length );
+ RtlMoveMemory(
+ connInfo->RemoteAddress,
+ &connectorAddress,
+ length
+ );
+ if ( length < sizeof(connectorAddress) ) {
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+ }
+
+ connInfo->UserDataLength = 0;
+ connInfo->OptionsLength = 0;
+
+ }
+
+ ListenIrp->IoStatus.Status = status;
+
+ irpSp = IoGetCurrentIrpStackLocation( ConnectIrp );
+ parameters = (PTDI_REQUEST_KERNEL)&irpSp->Parameters;
+ connInfo = parameters->ReturnConnectionInformation;
+
+ status = STATUS_SUCCESS;
+
+ if ( connInfo != NULL ) {
+
+ length = connInfo->RemoteAddressLength;
+
+ if ( length != 0 ) {
+ length = MIN( sizeof(listenerAddress), length );
+ RtlMoveMemory(
+ connInfo->RemoteAddress,
+ &listenerAddress,
+ length
+ );
+ if ( length < sizeof(listenerAddress) ) {
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+ }
+
+ connInfo->UserDataLength = 0;
+ connInfo->OptionsLength = 0;
+
+ }
+
+ ConnectIrp->IoStatus.Status = status;
+
+ IoCompleteRequest( ListenIrp, 2 );
+ IoCompleteRequest( ConnectIrp, 2 );
+
+ ACQUIRE_LOOP_LOCK( "CompleteConnection complete IRPs done" );
+
+ return STATUS_SUCCESS;
+
+} // CompleteConnection
+
+
+VOID
+IndicateConnect (
+ IN PLOOP_ENDPOINT Endpoint
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does the work of indicating an incoming connect.
+
+ The loopback device object's spin lock must be held when this
+ function is called.
+
+ *** The lock is released when the function returns.
+
+Arguments:
+
+ Endpoint - Pointer to receiving (listening) endpoint block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NTSTATUS status;
+ PLIST_ENTRY listEntry;
+ PIRP listenIrp;
+ PIRP connectIrp;
+ PTDI_IND_CONNECT connectHandler;
+ PVOID connectContext;
+ PVOID connectionContext;
+ PIO_STACK_LOCATION connectIrpSp;
+ PLOOP_ENDPOINT connectingEndpoint;
+ TA_NETBIOS_ADDRESS address;
+
+ //
+ // Reference the endpoint to prevent it from going away while this
+ // routine is running.
+ //
+
+ Endpoint->BlockHeader.ReferenceCount++;
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " New refcnt on endpoint %lx is %lx\n",
+ Endpoint,
+ Endpoint->BlockHeader.ReferenceCount );
+ }
+
+ //
+ // If the endpoint has a pending Listen, satisfy it with this
+ // Connect. If there is no pending Listen, and a Connect handler
+ // has been enabled on the endpoint, call it.
+ //
+
+ while ( TRUE ) {
+
+ //
+ // We have a Connect pending. Is there a pending Listen?
+ //
+
+ listEntry = RemoveHeadList( &Endpoint->PendingListenList );
+
+ if ( listEntry != &Endpoint->PendingListenList ) {
+
+ //
+ // Found a pending Listen. Use it to satisfy the first
+ // incoming Connect.
+ //
+
+ listenIrp = CONTAINING_RECORD(
+ listEntry,
+ IRP,
+ Tail.Overlay.ListEntry
+ );
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Listen IRP pending: %lx\n", listenIrp );
+ }
+
+ listEntry = RemoveHeadList(
+ &Endpoint->IncomingConnectList
+ );
+ ASSERT( listEntry != &Endpoint->IncomingConnectList );
+ connectIrp = CONTAINING_RECORD(
+ listEntry,
+ IRP,
+ Tail.Overlay.ListEntry
+ );
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Connect IRP pending: %lx\n", connectIrp );
+ }
+
+ CompleteConnection( listenIrp, connectIrp );
+
+ //
+ // Fall to bottom of loop to handle more incoming Connects.
+ //
+
+ } else {
+
+ //
+ // No pending Listen. Is there a Connection handler?
+ //
+
+ connectHandler = Endpoint->ConnectHandler;
+ connectContext = Endpoint->ConnectContext;
+
+ if ( connectHandler == NULL ) {
+
+ //
+ // No Connect handler. The Connect must remain queued.
+ //
+
+ IF_DEBUG(LOOP2) DbgPrint( " No Connect handler\n" );
+
+ break;
+
+ }
+
+ //
+ // The endpoint has a Connect handler. Call it. If it
+ // returns STATUS_EVENT_DONE, it handled the event by
+ // issuing a TdiAccept or TdiDisconnect from within the
+ // handler. If it returns STATUS_EVENT_PENDING, it also
+ // returns a connection context value indicating which
+ // connection it will use to issue a TdiAccept or
+ // TdiDisconect at a later time. If it returns
+ // STATUS_INSUFFICIENT_RESOURCES, it can't accept a new
+ // connection at this time, so we need to return an error to
+ // the Connect.
+ //
+ // First, remove the first Connect from the Incoming Connect
+ // list, and make it the Indicating Connect. It must be
+ // removed from the list to ensure that it isn't completed
+ // by LoopCleanup while we're indicating it.
+ //
+
+ listEntry = RemoveHeadList(
+ &Endpoint->IncomingConnectList
+ );
+ ASSERT( listEntry != &Endpoint->IncomingConnectList );
+ connectIrp = CONTAINING_RECORD(
+ listEntry,
+ IRP,
+ Tail.Overlay.ListEntry
+ );
+ Endpoint->IndicatingConnectIrp = connectIrp;
+
+ RELEASE_LOOP_LOCK( "IndicateConnect calling handler" );
+
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Connect handler: %lx\n", connectHandler );
+ }
+
+ //
+ // Build a TRANSPORT_ADDRESS describing the connector.
+ //
+
+ connectIrpSp = IoGetCurrentIrpStackLocation( connectIrp );
+ connectingEndpoint =
+ ((PLOOP_CONNECTION)connectIrpSp->FileObject->FsContext)->
+ Endpoint;
+
+ address.TAAddressCount = 1;
+ address.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ address.Address[0].AddressLength = sizeof(TDI_ADDRESS_NETBIOS);
+ address.Address[0].Address[0].NetbiosNameType =
+ TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ RtlMoveMemory(
+ address.Address[0].Address[0].NetbiosName,
+ connectingEndpoint->NetbiosName,
+ NETBIOS_NAME_LENGTH
+ );
+
+ //
+ // Call the Connect handler.
+ //
+
+ status = connectHandler(
+ connectContext,
+ sizeof(address),
+ &address,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ &connectionContext
+ );
+
+ ACQUIRE_LOOP_LOCK( "IndicateConnect after calling handler" );
+
+ if ( status == STATUS_EVENT_DONE ) {
+
+ //
+ // The Connect handler issued a TdiAccept or a
+ // TdiDisconnect, so the indicating Connect has already
+ // been completed.
+ //
+ // *** Note that Endpoint->IndicatingConnectIrp is
+ // cleared within LoopAccept or LoopDisconnect.
+ //
+
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Connect handler handled event\n" );
+ }
+
+ //
+ // Fall to bottom of loop to handle more incoming
+ // Connects.
+ //
+
+ } else if ( status == STATUS_EVENT_PENDING ) {
+
+ //
+ // The Connect handler has delayed the issuance of the
+ // TdiAccept or TdiDisconnect. Leave the indication
+ // pending.
+ //
+ // *** Note that Endpoint->IndicatingConnectIrp is
+ // cleared within LoopAccept or LoopDisconnect.
+ //
+
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Connect handler pended event\n" );
+ }
+
+ break;
+
+ } else {
+
+ //
+ // The Connect handler couldn't accept the connection,
+ // because it was out of resources. Abort the Connect.
+ //
+
+ ASSERT( status == STATUS_INSUFFICIENT_RESOURCES );
+
+ IF_DEBUG(LOOP2) DbgPrint( " No resources\n" );
+
+ Endpoint->IndicatingConnectIrp = NULL;
+
+ RELEASE_LOOP_LOCK( "IndicateConnect aborting connect" );
+
+ connectIrp->IoStatus.Status = status;
+ IoCompleteRequest( connectIrp, 2 );
+
+ ACQUIRE_LOOP_LOCK( "IndicateConnect connect aborted" );
+
+ //
+ // Fall to bottom of loop to handle more incoming
+ // Connects.
+ //
+
+ }
+
+ } // pending listen?
+
+ //
+ // If we get here, we need to indicate the next incoming
+ // Connect, if there is one.
+ //
+
+ if ( (GET_BLOCK_STATE(Endpoint) != BlockStateActive) ||
+ (Endpoint->IncomingConnectList.Flink ==
+ &Endpoint->IncomingConnectList) ) {
+
+ //
+ // No more Connects, or endpoint no longer active. Leave.
+ //
+
+ break;
+
+ }
+
+ //
+ // Process the next Connect.
+ //
+
+ } // while ( TRUE )
+
+ //
+ // Remote the endpoint reference acquired at the start of this
+ // routine.
+ //
+
+ LoopDereferenceEndpoint( Endpoint );
+
+ RELEASE_LOOP_LOCK( "IndicateConnect done" );
+
+ return;
+
+} // IndicateConnect
diff --git a/private/ntos/tdi/loopback/datagram.c b/private/ntos/tdi/loopback/datagram.c
new file mode 100644
index 000000000..0c5ec7c02
--- /dev/null
+++ b/private/ntos/tdi/loopback/datagram.c
@@ -0,0 +1,848 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ datagram.c
+
+Abstract:
+
+ This module implements datagram logic for the loopback Transport
+ Provider driver for NT LAN Manager.
+
+Author:
+
+ Chuck Lenzmeier (chuckl) 15-Aug-1991
+
+Revision History:
+
+--*/
+
+#include "loopback.h"
+
+//
+// Local declarations
+//
+
+STATIC
+VOID
+CompleteReceiveDatagram (
+ IN PIRP ReceiveIrp,
+ IN PIRP SendIrp
+ );
+
+STATIC
+VOID
+IndicateReceiveDatagram (
+ IN PLOOP_CONNECTION ReceivingConnection,
+ IN PIRP InitialSendIrp
+ );
+
+
+NTSTATUS
+LoopReceiveDatagram (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a Receive Datagram request.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+
+ IrpSp - Pointer to current stack location in IRP
+
+Return Value:
+
+ NTSTATUS - Status of request
+
+--*/
+
+{
+ PLOOP_ENDPOINT receivingEndpoint;
+ PLOOP_CONNECTION sendingConnection;
+
+ IF_DEBUG(LOOP1) DbgPrint( " Receive Datagram request\n" );
+
+ //
+ // Verify that the receiving endpoint is connected.
+ //
+
+ receivingEndpoint = (PLOOP_ENDPOINT)IrpSp->FileObject->FsContext;
+
+ if ( receivingConnection == NULL ) {
+ IF_DEBUG(LOOP2) DbgPrint( " Can't Receive on control channel\n" );
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ IoCompleteRequest( Irp, 0 );
+ IF_DEBUG(LOOP1) DbgPrint( " Receive request complete\n" );
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ sendingConnection = receivingConnection->RemoteConnection;
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Receiving connection: %lx\n", receivingConnection );
+ DbgPrint( " Sending connection: %lx\n", sendingConnection );
+ }
+
+ ACQUIRE_LOOP_LOCK( "Receive initial" );
+
+ if ( (sendingConnection == NULL) ||
+ (GET_BLOCK_STATE(receivingConnection) != BlockStateActive) ) {
+ RELEASE_LOOP_LOCK( "Receive closing" );
+ IF_DEBUG(LOOP2) DbgPrint( " Connection not connected\n" );
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ IoCompleteRequest( Irp, 0 );
+ IF_DEBUG(LOOP1) DbgPrint( " Receive request complete\n" );
+ return STATUS_DISCONNECTED;
+ }
+
+ //
+ // Queue the Receive to the connection's Pending Receive list.
+ //
+
+ InsertTailList(
+ &receivingConnection->PendingReceiveList,
+ &Irp->Tail.Overlay.ListEntry
+ );
+
+ IoMarkIrpPending( Irp );
+
+ //
+ // Check for pending data.
+ //
+
+ if ( (receivingConnection->IndicatingSendIrp != NULL) ||
+ (receivingConnection->IncomingSendList.Flink ==
+ &receivingConnection->IncomingSendList) ) {
+
+ //
+ // There is no pending Send, or an indication is already in
+ // progress. Reference the connection to account for the
+ // Receive IRP.
+ //
+
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " No pending Send; leaving IRP %lx queued \n", Irp );
+ }
+ receivingConnection->BlockHeader.ReferenceCount++;
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " New refcnt on connection %lx is %lx\n",
+ receivingConnection,
+ receivingConnection->BlockHeader.ReferenceCount );
+ }
+
+ RELEASE_LOOP_LOCK( "Receive no Send" );
+
+ } else {
+
+ //
+ // There is pending data. Call IndicateReceive to satisfy
+ // the Receive.
+ //
+ // *** Note that IndicateReceive returns with the loopback
+ // driver spin lock released.
+ //
+
+ IF_DEBUG(LOOP2) DbgPrint( " LoopReceive indicating receive\n" );
+ IndicateReceive( receivingConnection, NULL );
+
+ }
+
+ IF_DEBUG(LOOP1) DbgPrint( " Receive request %lx complete\n", Irp );
+ return STATUS_PENDING;
+
+} // LoopReceive
+
+
+NTSTATUS
+LoopSend (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a Send request.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+
+ IrpSp - Pointer to current stack location in IRP
+
+Return Value:
+
+ NTSTATUS - Status of request
+
+--*/
+
+{
+ PLOOP_CONNECTION sendingConnection;
+ PLOOP_CONNECTION receivingConnection;
+ BOOLEAN firstSend;
+
+ IF_DEBUG(LOOP1) DbgPrint( " Send request\n" );
+
+ //
+ // Verify that the sending connection is connected.
+ //
+
+ sendingConnection = (PLOOP_CONNECTION)IrpSp->FileObject->FsContext;
+
+ if ( sendingConnection == NULL ) {
+ IF_DEBUG(LOOP2) DbgPrint( " Can't Send on control channel\n" );
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ IoCompleteRequest( Irp, 0 );
+ IF_DEBUG(LOOP1) DbgPrint( " Send request complete\n" );
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ receivingConnection = sendingConnection->RemoteConnection;
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Sending connection: %lx\n", sendingConnection );
+ DbgPrint( " Receiving connection: %lx\n", receivingConnection );
+ }
+
+ ACQUIRE_LOOP_LOCK( "Send initial" );
+
+ if ( (receivingConnection == NULL) ||
+ (GET_BLOCK_STATE(sendingConnection) != BlockStateActive) ) {
+ RELEASE_LOOP_LOCK( "Send closing" );
+ IF_DEBUG(LOOP2) DbgPrint( " Connection not connected\n" );
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ IoCompleteRequest( Irp, 0 );
+ IF_DEBUG(LOOP1) DbgPrint( " Send request complete\n" );
+ return STATUS_DISCONNECTED;
+ }
+
+ //
+ // Reference both ends.
+ //
+
+ sendingConnection->BlockHeader.ReferenceCount++;
+ receivingConnection->BlockHeader.ReferenceCount++;
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " New refcnt on connection %lx is %lx\n",
+ sendingConnection,
+ sendingConnection->BlockHeader.ReferenceCount );
+ DbgPrint( " New refcnt on connection %lx is %lx\n",
+ receivingConnection,
+ receivingConnection->BlockHeader.ReferenceCount );
+ }
+
+ //
+ // Determine whether this is the first active incoming Send for the
+ // receiving connection.
+ //
+
+ firstSend = (BOOLEAN)( receivingConnection->IncomingSendList.Flink ==
+ &receivingConnection->IncomingSendList );
+
+ //
+ // Queue the Send to the receiving connection's Incoming Send list,
+ // in order to prevent another Send from getting ahead of this one.
+ //
+
+ InsertTailList(
+ &receivingConnection->IncomingSendList,
+ &Irp->Tail.Overlay.ListEntry
+ );
+
+ IoMarkIrpPending( Irp );
+
+ if ( !firstSend || (receivingConnection->IndicatingSendIrp != NULL) ) {
+
+ //
+ // Pending data already exists, or an indication is already in
+ // progress. This Send remains behind the already pending data.
+ //
+
+ IF_DEBUG(LOOP2) DbgPrint( " Data already pending\n" );
+
+ RELEASE_LOOP_LOCK( "Send sends pending" );
+
+ } else {
+
+ //
+ // Indicate the incoming data.
+ //
+ // *** Note that IndicateReceive returns with the loopback
+ // driver spin lock released.
+ //
+
+ IF_DEBUG(LOOP2) DbgPrint( " LoopSend indicating receive\n" );
+ IndicateReceive( receivingConnection, Irp );
+
+ }
+
+ IF_DEBUG(LOOP1) DbgPrint( " Send request %lx complete\n", Irp );
+ return STATUS_PENDING;
+
+} // LoopSend
+
+
+VOID
+CompleteReceive (
+ IN PIRP ReceiveIrp,
+ IN PIRP SendIrp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine completes the process of sending a message. It copies
+ the message from the source buffer into the destination buffer.
+
+ The reference counts on the owning connections must have been
+ incremented to account for the requesting IRPs in order to prevent
+ their deletion.
+
+Arguments:
+
+ ReceiveIrp - Pointer to IRP used for Receive request
+
+ SendIrp - Pointer to IRP used for Send request
+
+Return Value:
+
+ NTSTATUS - Indicates whether the connection was successfully created
+
+--*/
+
+{
+ NTSTATUS status;
+ PIO_STACK_LOCATION sendIrpSp;
+ PIO_STACK_LOCATION receiveIrpSp;
+ ULONG copyLength;
+ PTDI_REQUEST_KERNEL_SEND sendRequest;
+ PTDI_REQUEST_KERNEL_RECEIVE receiveRequest;
+ PLOOP_CONNECTION sendingConnection;
+ PLOOP_CONNECTION receivingConnection;
+
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Send IRP %lx completes receive IRP %lx\n",
+ SendIrp, ReceiveIrp );
+ }
+
+ //
+ // Copy the data from the source buffer into the destination buffer.
+ //
+ // *** Note that we special-case zero-length copies. We don't
+ // bother to call LoopCopyData. Part of the reason for this
+ // is that a zero-length send or receive issued from user mode
+ // yields an IRP that has a NULL MDL address.
+ //
+
+ sendIrpSp = IoGetCurrentIrpStackLocation( SendIrp );
+ sendRequest = (PTDI_REQUEST_KERNEL_SEND)&sendIrpSp->Parameters;
+ copyLength = sendRequest->SendLength;
+ IF_DEBUG(LOOP4) {
+ DbgPrint( " Send request at %lx, send length %lx\n",
+ sendRequest, copyLength );
+ }
+ receiveIrpSp = IoGetCurrentIrpStackLocation( ReceiveIrp );
+ receiveRequest = (PTDI_REQUEST_KERNEL_RECEIVE)&receiveIrpSp->Parameters;
+ IF_DEBUG(LOOP4) {
+ DbgPrint( " Receive request at %lx, receive length %lx\n",
+ receiveRequest, receiveRequest->ReceiveLength );
+ }
+ status = STATUS_SUCCESS;
+ if ( copyLength > receiveRequest->ReceiveLength ) {
+ status = STATUS_BUFFER_OVERFLOW;
+ copyLength = receiveRequest->ReceiveLength;
+ }
+
+ if ( copyLength != 0 ) {
+
+ ASSERT( ReceiveIrp->MdlAddress != NULL );
+ ASSERT( SendIrp->MdlAddress != NULL );
+
+ LoopCopyData(
+ ReceiveIrp->MdlAddress,
+ SendIrp->MdlAddress,
+ copyLength
+ );
+
+ }
+
+ //
+ // Complete the Receive and Send requests.
+ //
+
+ receivingConnection =
+ (PLOOP_CONNECTION)receiveIrpSp->FileObject->FsContext;
+ sendingConnection =
+ (PLOOP_CONNECTION)sendIrpSp->FileObject->FsContext;
+
+ ReceiveIrp->IoStatus.Status = status;
+ ReceiveIrp->IoStatus.Information = copyLength;
+
+ SendIrp->IoStatus.Status = STATUS_SUCCESS;
+ SendIrp->IoStatus.Information = copyLength;
+
+ IoCompleteRequest( ReceiveIrp, 2 );
+ IoCompleteRequest( SendIrp, 2 );
+
+ //
+ // Dereference the connections.
+ //
+
+ ACQUIRE_LOOP_LOCK( "CompleteReceive dereference" );
+ LoopDereferenceConnection( receivingConnection );
+ LoopDereferenceConnection( sendingConnection );
+ RELEASE_LOOP_LOCK( "CompleteReceive dereference" );
+
+ return;
+
+} // CompleteReceive
+
+
+VOID
+IndicateReceive (
+ IN PLOOP_CONNECTION ReceivingConnection,
+ IN PIRP InitialSendIrp
+ )
+{
+ NTSTATUS status;
+ PLOOP_ENDPOINT receivingEndpoint;
+ PLOOP_CONNECTION sendingConnection;
+ PLIST_ENTRY listEntry;
+ PIRP receiveIrp;
+ PIRP sendIrp;
+ PTDI_IND_RECEIVE receiveHandler;
+ PVOID receiveContext;
+ PIO_STACK_LOCATION sendIrpSp;
+ PTDI_REQUEST_KERNEL_SEND sendRequest;
+ ULONG length;
+ PMDL mdl;
+ PVOID address;
+ ULONG bytesTaken;
+
+ receivingEndpoint = ReceivingConnection->Endpoint;
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Receiving endpoint: %lx\n", receivingEndpoint );
+ }
+
+ //
+ // Reference the receiving connection to prevent it from going away
+ // while this routine is running.
+ //
+
+ ReceivingConnection->BlockHeader.ReferenceCount++;
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " New refcnt on connection %lx is %lx\n",
+ ReceivingConnection,
+ ReceivingConnection->BlockHeader.ReferenceCount );
+ }
+
+ //
+ // Capture the address of the sending connection, as the receiving
+ // connection's pointer can be zeroed if a Disconnect occurs.
+ //
+
+ sendingConnection = ReceivingConnection->RemoteConnection;
+ ASSERT( sendingConnection != NULL );
+
+ //
+ // If the receiving connection has a pending Receive, satisfy it
+ // with this Send. If there is no pending Receive, and a Receive
+ // handler has been enabled on the receiving connection, call it.
+ // If the Receive handler returns with a Receive IRP, use it to
+ // satisfy this Send. If the Receive handler doesn't return an IRP,
+ // leave this Send pending.
+ //
+ // !!! Note that the current implementation only works because
+ // partial sends are not supported.
+ //
+
+ while ( TRUE ) {
+
+ //
+ // We have a Send pending. Is there a pending Receive?
+ //
+
+ listEntry = RemoveHeadList( &ReceivingConnection->PendingReceiveList );
+
+ if ( listEntry != &ReceivingConnection->PendingReceiveList ) {
+
+ //
+ // Found a pending Receive. Use it to satisfy the first
+ // incoming Send.
+ //
+
+ receiveIrp = CONTAINING_RECORD(
+ listEntry,
+ IRP,
+ Tail.Overlay.ListEntry
+ );
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Receive IRP pending: %lx\n", receiveIrp );
+ }
+
+ listEntry = RemoveHeadList(
+ &ReceivingConnection->IncomingSendList
+ );
+ ASSERT( listEntry != &ReceivingConnection->IncomingSendList );
+ sendIrp = CONTAINING_RECORD(
+ listEntry,
+ IRP,
+ Tail.Overlay.ListEntry
+ );
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Send IRP pending: %lx\n", sendIrp );
+ }
+
+ //
+ // If this is the first time through the loop, and we were
+ // called to process a newly queued Send, dereference the
+ // receiving connection -- LoopSend referenced the
+ // connection an extra time in case the Send had to remain
+ // queued.
+ //
+
+ if ( InitialSendIrp != NULL ) {
+ LoopDereferenceConnection( ReceivingConnection );
+ }
+
+ RELEASE_LOOP_LOCK( "IndicateReceive pending Receive" );
+
+ CompleteReceive( receiveIrp, sendIrp );
+
+ ACQUIRE_LOOP_LOCK( "IndicateReceive pending Receive completed" );
+
+ //
+ // Fall to bottom of loop to handle more incoming Sends.
+ //
+
+ } else {
+
+ //
+ // No pending Receive. Is there a Receive handler?
+ //
+
+ receiveHandler = receivingEndpoint->ReceiveHandler;
+ receiveContext = receivingEndpoint->ReceiveContext;
+
+ if ( receiveHandler == NULL ) {
+
+ //
+ // No Receive handler. The Send must remain queued.
+ //
+
+ IF_DEBUG(LOOP2) DbgPrint( " No Receive handler\n" );
+
+ break;
+
+ }
+
+ //
+ // The receiving endpoint has a Receive handler. Call it.
+ // If it returns STATUS_SUCCESS, it completely handled the
+ // data. If it returns STATUS_MORE_PROCESSING_REQUIRED, it
+ // also returns a Receive IRP describing where to put the
+ // data. Any other return status means the receiver can't
+ // take the data just now, so we leave the Send queued and
+ // wait for the receiver to post a Receive IRP.
+ //
+ // !!! Note that we don't currently handle partial data
+ // acceptance.
+ //
+ // First, remove the first Send from the Incoming Send list,
+ // and make it the Indicating Send. It must be removed from
+ // the list to ensure that it isn't completed by
+ // LoopDoDisconnection while we're indicating it.
+ //
+
+ listEntry = RemoveHeadList(
+ &ReceivingConnection->IncomingSendList
+ );
+ ASSERT( listEntry != &ReceivingConnection->IncomingSendList );
+ sendIrp = CONTAINING_RECORD(
+ listEntry,
+ IRP,
+ Tail.Overlay.ListEntry
+ );
+ ReceivingConnection->IndicatingSendIrp = sendIrp;
+
+ RELEASE_LOOP_LOCK( "IndicateReceive calling Receive handler" );
+
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Receive handler: %lx\n", receiveHandler );
+ DbgPrint( " Send IRP: %lx\n", sendIrp );
+ }
+
+ sendIrpSp = IoGetCurrentIrpStackLocation( sendIrp );
+ sendRequest = (PTDI_REQUEST_KERNEL_SEND)&sendIrpSp->Parameters;
+
+ length = sendRequest->SendLength;
+ ASSERTMSG(
+ "Loopback driver doesn't handle partial or expedited sends",
+ sendRequest->SendFlags == 0
+ );
+
+ //
+ // Map the send buffer, if necessary.
+ //
+
+ mdl = sendIrp->MdlAddress;
+ if ( MmGetMdlByteCount(mdl) == 0 ) {
+ address = NULL;
+ } else {
+ address = MmGetSystemAddressForMdl( mdl );
+ }
+
+ //
+ // Call the Receive handler.
+ //
+
+ status = receiveHandler(
+ receiveContext,
+ ReceivingConnection->ConnectionContext,
+ 0,
+ MmGetMdlByteCount( mdl ),
+ length,
+ &bytesTaken,
+ address,
+ &receiveIrp
+ );
+
+ ACQUIRE_LOOP_LOCK( "IndicateReceive after calling handler" );
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Indication for send IRP %lx done\n", sendIrp );
+ }
+
+ ReceivingConnection->IndicatingSendIrp = NULL;
+
+ if ( status == STATUS_SUCCESS ) {
+
+ //
+ // The Receive handler completely handled the data.
+ // Complete the Send.
+ //
+
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Receive handler handled data\n" );
+ }
+
+ ASSERTMSG(
+ "Loopback driver doesn't handle partial acceptance "
+ "of indications",
+ bytesTaken == length
+ );
+
+ //
+ // Dereference the sending and receiving connections --
+ // LoopSend referenced the connections when it queued
+ // the Send.
+ //
+
+ LoopDereferenceConnection( ReceivingConnection );
+ LoopDereferenceConnection( sendingConnection );
+
+ RELEASE_LOOP_LOCK( "IndicateReceive completely handled" );
+
+ //
+ // Complete the Send IRP.
+ //
+
+ sendIrp->IoStatus.Status = STATUS_SUCCESS;
+ sendIrp->IoStatus.Information = sendRequest->SendLength;
+
+ IoCompleteRequest( sendIrp, 2 );
+
+ ACQUIRE_LOOP_LOCK( "IndicateReceive send completed" );
+
+ //
+ // Fall to bottom of loop to handle more incoming
+ // Sends.
+ //
+
+ } else if ( status == STATUS_MORE_PROCESSING_REQUIRED ) {
+
+ //
+ // The Receive handler returned a Receive IRP to be used
+ // to satisfy the Send.
+ //
+
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Receive handler returned IRP: %lx\n",
+ receiveIrp );
+ }
+
+ ASSERTMSG(
+ "Loopback driver doesn't handle partial acceptance "
+ "of indications",
+ bytesTaken == 0
+ );
+
+ //
+ // Complete the Receive using the current Send.
+ //
+ // *** Note that the pending Send references both the
+ // sending and receiving connections.
+
+ RELEASE_LOOP_LOCK( "IndicateReceive complete new Receive" );
+
+ CompleteReceive( receiveIrp, sendIrp );
+
+ ACQUIRE_LOOP_LOCK( "IndicateReceive new receive completed" );
+
+ //
+ // Fall to bottom of loop to handle more incoming
+ // Sends.
+ //
+
+ } else {
+
+ //
+ // The Receive handler couldn't take the data. This
+ // Send will have to wait until receiver can post a
+ // Receive IRP.
+ //
+ // *** Because we didn't hold the spin lock around the
+ // call to the Receive handler, it's possible that
+ // the receiver has already posted a Receive IRP.
+ // Because we were in the middle of an indication,
+ // that Receive would have been queued to the
+ // Pending Receive list, and we should go get it
+ // now. If the receiver hasn't posted a Receive
+ // yet, then this Send will be put back on the
+ // Incoming Send list before the Receive does come
+ // in (since we're now holding the lock).
+ //
+
+ ASSERT( status == STATUS_DATA_NOT_ACCEPTED );
+
+ IF_DEBUG(LOOP2) DbgPrint( " Data not accepted\n" );
+
+ if ( GET_BLOCK_STATE(ReceivingConnection) !=
+ BlockStateActive ) {
+
+ //
+ // The connection is closing. Abort the current
+ // Send and leave.
+ //
+
+ LoopDereferenceConnection( ReceivingConnection );
+ LoopDereferenceConnection( sendingConnection );
+
+ RELEASE_LOOP_LOCK( "IndicateReceive disconnecting" );
+
+ sendIrp->IoStatus.Status = STATUS_DISCONNECTED;
+ IoCompleteRequest( sendIrp, 2 );
+
+ ACQUIRE_LOOP_LOCK( "IndicateReceive send aborted" );
+
+ break;
+
+ }
+
+ listEntry = RemoveHeadList(
+ &ReceivingConnection->PendingReceiveList
+ );
+
+ if ( listEntry !=
+ &ReceivingConnection->PendingReceiveList ) {
+
+ //
+ // A Receive has been posted. Use it to satisfy
+ // this Send.
+ //
+
+ receiveIrp = CONTAINING_RECORD(
+ listEntry,
+ IRP,
+ Tail.Overlay.ListEntry
+ );
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Receive IRP pending: %lx\n",
+ receiveIrp );
+ }
+
+ //
+ // Complete the Receive using the current Send.
+ //
+
+ RELEASE_LOOP_LOCK(
+ "IndicateReceive complete posted Receive"
+ );
+
+ CompleteReceive( receiveIrp, sendIrp );
+
+ ACQUIRE_LOOP_LOCK(
+ "IndicateReceive posted receive completed"
+ );
+
+ //
+ // Fall to bottom of loop to handle more incoming
+ // Sends.
+ //
+
+ } else {
+
+ //
+ // The handler didn't take the data, and it didn't
+ // post a Receive IRP. Requeue the current send and
+ // get out.
+ //
+
+ InsertHeadList(
+ &ReceivingConnection->IncomingSendList,
+ &sendIrp->Tail.Overlay.ListEntry
+ );
+
+ break;
+
+ }
+
+ }
+
+ } // pending receive?
+
+ //
+ // If we get here, we need to indicate the next incoming Send,
+ // if there is one.
+ //
+
+ InitialSendIrp = NULL;
+
+ if ( (GET_BLOCK_STATE(ReceivingConnection) != BlockStateActive) ||
+ (ReceivingConnection->IncomingSendList.Flink ==
+ &ReceivingConnection->IncomingSendList) ) {
+
+ //
+ // No more Sends, or connection no longer active. Leave.
+ //
+
+ break;
+
+ }
+
+ //
+ // Process the next Send.
+ //
+
+ } // while ( TRUE )
+
+ //
+ // Remove the connection reference acquired at the start of this
+ // routine.
+ //
+
+ LoopDereferenceConnection( ReceivingConnection );
+
+ RELEASE_LOOP_LOCK( "IndicateReceive done" );
+
+ return;
+
+} // IndicateReceive
+
diff --git a/private/ntos/tdi/loopback/endpoint.c b/private/ntos/tdi/loopback/endpoint.c
new file mode 100644
index 000000000..fd252d291
--- /dev/null
+++ b/private/ntos/tdi/loopback/endpoint.c
@@ -0,0 +1,373 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ endpoint.c
+
+Abstract:
+
+ This module implements endpoint logic for the loopback Transport
+ Provider driver for NT LAN Manager.
+
+Author:
+
+ Chuck Lenzmeier (chuckl) 15-Aug-1991
+
+Revision History:
+
+--*/
+
+#include "loopback.h"
+
+
+VOID
+LoopDereferenceEndpoint (
+ IN PLOOP_ENDPOINT Endpoint
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to dereference an endpoint block. If the
+ reference count on the block goes to zero, the endpoint block is
+ deleted.
+
+ The Loopback device object's spin lock must be held when this
+ routine is called.
+
+Arguments:
+
+ Endpoint - Supplies a pointer to an endpoint block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIRP closeIrp;
+
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " Dereferencing endpoint %lx; old refcnt %lx\n",
+ Endpoint, Endpoint->BlockHeader.ReferenceCount );
+ }
+
+ ASSERT( (LONG)Endpoint->BlockHeader.ReferenceCount > 0 );
+
+ if ( --Endpoint->BlockHeader.ReferenceCount != 0 ) {
+ return;
+ }
+
+ IF_DEBUG(LOOP3) DbgPrint( " Deleting endpoint %lx\n", Endpoint );
+
+ RemoveEntryList( &Endpoint->DeviceListEntry );
+
+ RELEASE_LOOP_LOCK( "DerefEndp deleting" );
+
+ ObDereferenceObject( Endpoint->DeviceObject );
+
+ //
+ // If a Close IRP is pending, complete it now.
+ //
+
+ closeIrp = Endpoint->CloseIrp;
+
+ if ( closeIrp != NULL ) {
+
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " Completing Close IRP %lx\n", closeIrp );
+ }
+ closeIrp->IoStatus.Status = STATUS_SUCCESS;
+ closeIrp->IoStatus.Information = 0;
+
+ IoCompleteRequest( closeIrp, 2 );
+
+ }
+
+ DEBUG SET_BLOCK_TYPE( Endpoint, BlockTypeGarbage );
+ DEBUG SET_BLOCK_STATE( Endpoint, BlockStateDead );
+ DEBUG SET_BLOCK_SIZE( Endpoint, -1 );
+ DEBUG Endpoint->BlockHeader.ReferenceCount = -1;
+ DEBUG Endpoint->DeviceObject = NULL;
+
+ ExFreePool( Endpoint );
+
+ ACQUIRE_LOOP_LOCK( "DerefEndp done" );
+
+ return;
+
+} // LoopDereferenceEndpoint
+
+
+PLOOP_ENDPOINT
+LoopFindBoundAddress (
+ IN PCHAR NetbiosName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine searches the list of endpoints for the loopback device
+ for one that has the specified address bound to it.
+
+ The loopback device object's spin lock must be owned when this
+ function is called.
+
+Arguments:
+
+ NetbiosName - Pointer to NetBIOS name string, formatted according
+ to TDI specification.
+
+Return Value:
+
+ PLOOP_OBJECT - Pointer to LOOP_ENDPOINT block if matching address
+ found, else NULL
+
+--*/
+
+{
+ PLIST_ENTRY listEntry;
+ PLOOP_ENDPOINT endpoint;
+ LONG compareResult;
+ CLONG i;
+
+ listEntry = LoopDeviceObject->EndpointList.Flink;
+
+ while ( listEntry != &LoopDeviceObject->EndpointList ) {
+
+ endpoint = CONTAINING_RECORD(
+ listEntry,
+ LOOP_ENDPOINT,
+ DeviceListEntry
+ );
+
+ if ( GET_BLOCK_STATE(endpoint) == BlockStateActive ) {
+
+ compareResult = 0;
+ for ( i = 0; i < NETBIOS_NAME_LENGTH; i++ ) {
+ if ( endpoint->NetbiosName[i] != NetbiosName[i] ) {
+ compareResult = 1;
+ break;
+ }
+ }
+
+ if ( compareResult == 0 ) {
+ return endpoint;
+ }
+
+ }
+
+ listEntry = listEntry->Flink;
+
+ }
+
+ return NULL;
+
+} // LoopFindBoundAddress
+
+
+NTSTATUS
+LoopSetEventHandler (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a Set Receive Handler request.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+
+ IrpSp - Pointer to current stack location in IRP
+
+Return Value:
+
+ NTSTATUS - Status of request
+
+--*/
+
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PTDI_REQUEST_KERNEL_SET_EVENT setEventRequest;
+ PLOOP_ENDPOINT endpoint;
+ PVOID handler;
+ PVOID context;
+ PSZ s;
+
+ IrpSp; // prevent compiler warnings
+
+ IF_DEBUG(LOOP1) DbgPrint( " SetEventHandler request\n" );
+
+ setEventRequest = (PTDI_REQUEST_KERNEL_SET_EVENT)&IrpSp->Parameters;
+
+ handler = setEventRequest->EventHandler;
+ context = setEventRequest->EventContext;
+
+ //
+ // Get the endpoint address and update the handler address.
+ //
+
+ ACQUIRE_LOOP_LOCK( "SetEventHandler initial" );
+
+ endpoint = (PLOOP_ENDPOINT)IrpSp->FileObject->FsContext;
+ IF_DEBUG(LOOP2) DbgPrint( " Endpoint address: %lx\n", endpoint );
+
+ if ( endpoint == NULL ) {
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Can't SetEventHandler on control channel\n" );
+ }
+ status = STATUS_INVALID_PARAMETER;
+ goto complete;
+ }
+
+ if ( GET_BLOCK_TYPE(endpoint) != BlockTypeLoopEndpoint ) {
+ status = STATUS_INVALID_PARAMETER;
+ goto complete;
+ }
+
+ switch ( setEventRequest->EventType ) {
+
+ case TDI_EVENT_CONNECT:
+
+ IF_DEBUG(LOOP2) s = "connect";
+
+ endpoint->ConnectHandler = (PTDI_IND_CONNECT)handler;
+ endpoint->ConnectContext = context;
+
+ break;
+
+ case TDI_EVENT_DISCONNECT:
+
+ IF_DEBUG(LOOP2) s = "disconnect";
+
+ endpoint->DisconnectHandler = (PTDI_IND_DISCONNECT)handler;
+ endpoint->DisconnectContext = context;
+
+ break;
+
+ case TDI_EVENT_ERROR:
+
+ IF_DEBUG(LOOP2) s = "error";
+
+ endpoint->ErrorHandler = (PTDI_IND_ERROR)handler;
+ endpoint->ErrorContext = context;
+
+ break;
+
+ case TDI_EVENT_RECEIVE:
+
+ IF_DEBUG(LOOP2) s = "receive";
+
+ endpoint->ReceiveHandler = (PTDI_IND_RECEIVE)handler;
+ endpoint->ReceiveContext = context;
+
+ break;
+
+ case TDI_EVENT_RECEIVE_DATAGRAM:
+
+ IF_DEBUG(LOOP2) s = "receive datagram";
+
+ endpoint->ReceiveDatagramHandler = (PTDI_IND_RECEIVE_DATAGRAM)handler;
+ endpoint->ReceiveDatagramContext = context;
+
+ break;
+
+ case TDI_EVENT_RECEIVE_EXPEDITED:
+
+ IF_DEBUG(LOOP2) s = "receive expedited";
+
+ endpoint->ReceiveExpeditedHandler =
+ (PTDI_IND_RECEIVE_EXPEDITED)handler;
+ endpoint->ReceiveExpeditedContext = context;
+
+ break;
+
+ default:
+
+ DEBUG {
+ DbgPrint( " Invalid event type: %lx\n",
+ setEventRequest->EventType );
+ }
+ ASSERT( FALSE );
+ status = STATUS_INVALID_PARAMETER;
+ goto complete;
+
+ }
+
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " New %s handler address: %lx, context: %lx\n",
+ s, handler, context );
+ }
+
+complete:
+
+ RELEASE_LOOP_LOCK( "SetEventHandler final" );
+
+ //
+ // Complete the I/O request.
+ //
+
+ Irp->IoStatus.Status = status;
+
+ IoCompleteRequest( Irp, 2 );
+
+ IF_DEBUG(LOOP1) DbgPrint( " SetReceiveHandler request complete\n" );
+ return status;
+
+} // LoopSetEventHandler
+
+
+NTSTATUS
+LoopVerifyEndpoint (
+ IN PLOOP_ENDPOINT Endpoint
+ )
+
+/*++
+
+Routine Description:
+
+ This routine verifies that the specified endpoint block is really
+ an endpoint created by the loopback driver.
+
+ The loopback device object's spin lock must be owned when this
+ function is called.
+
+Arguments:
+
+ Endpoint - Pointer to endpoint block
+
+Return Value:
+
+ NTSTATUS - STATUS_SUCCESS or STATUS_INVALID_PARAMETER
+
+--*/
+
+{
+ PLIST_ENTRY listEntry;
+
+ listEntry = LoopDeviceObject->EndpointList.Flink;
+
+ while ( listEntry != &LoopDeviceObject->EndpointList ) {
+
+ if ( CONTAINING_RECORD( listEntry, LOOP_ENDPOINT, DeviceListEntry ) ==
+ Endpoint ) {
+ return STATUS_SUCCESS;
+ }
+
+ listEntry = listEntry->Flink;
+
+ }
+
+ return STATUS_INVALID_PARAMETER;
+
+} // LoopVerifyEndpoint
+
diff --git a/private/ntos/tdi/loopback/info.c b/private/ntos/tdi/loopback/info.c
new file mode 100644
index 000000000..6d71c41f6
--- /dev/null
+++ b/private/ntos/tdi/loopback/info.c
@@ -0,0 +1,183 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ info.c
+
+Abstract:
+
+ This module implements query/set information logic for the loopback
+ Transport Provider driver for NT LAN Manager.
+
+Author:
+
+ Chuck Lenzmeier (chuckl) 6-Nov-1991
+
+Revision History:
+
+--*/
+
+#include "loopback.h"
+
+#include <windef.h>
+#include <nb30.h>
+
+
+NTSTATUS
+LoopQueryInformation (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This function handles the TdiQueryInformation request.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+
+ IrpSp - Pointer to current stack location in IRP
+
+Return Value:
+
+ NTSTATUS - Status of request
+
+--*/
+
+{
+ NTSTATUS status;
+ PTDI_REQUEST_KERNEL_QUERY_INFORMATION queryRequest;
+
+ IF_DEBUG(LOOP1) DbgPrint( " Query Information request\n" );
+
+ queryRequest = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&IrpSp->Parameters;
+
+ switch ( queryRequest->QueryType ) {
+
+ case TDI_QUERY_BROADCAST_ADDRESS:
+ {
+ PTA_NETBIOS_ADDRESS address;
+
+ if ( Irp->MdlAddress->ByteCount < sizeof(TA_NETBIOS_ADDRESS) ) {
+
+ status = STATUS_BUFFER_TOO_SMALL;
+
+ } else {
+
+ address = MmGetSystemAddressForMdl( Irp->MdlAddress );
+
+ address->TAAddressCount = 1;
+ address->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ address->Address[0].AddressLength = 0;
+
+ Irp->IoStatus.Information = sizeof(TA_NETBIOS_ADDRESS);
+
+ status = STATUS_SUCCESS;
+
+ }
+
+ break;
+ }
+
+ case TDI_QUERY_PROVIDER_INFORMATION:
+ {
+ PTDI_PROVIDER_INFO providerInfo;
+
+ if ( Irp->MdlAddress->ByteCount < sizeof(TDI_PROVIDER_INFO) ) {
+
+ status = STATUS_BUFFER_TOO_SMALL;
+
+ } else {
+
+ providerInfo = MmGetSystemAddressForMdl( Irp->MdlAddress );
+
+ ACQUIRE_LOOP_LOCK( "Query Information copy provider info" );
+ RtlMoveMemory(
+ providerInfo,
+ &LoopProviderInfo,
+ sizeof(TDI_PROVIDER_INFO)
+ );
+ RELEASE_LOOP_LOCK( "Query Information copy provider info done" );
+
+ Irp->IoStatus.Information = sizeof(TDI_PROVIDER_INFO);
+
+ status = STATUS_SUCCESS;
+
+ }
+
+ break;
+ }
+
+ case TDI_QUERY_ADAPTER_STATUS:
+ {
+ PADAPTER_STATUS adapterStatus;
+ PNAME_BUFFER name;
+
+ if ( Irp->MdlAddress->ByteCount <
+ (sizeof(ADAPTER_STATUS) + sizeof(NAME_BUFFER)) ) {
+
+ status = STATUS_BUFFER_TOO_SMALL;
+
+ } else {
+
+ adapterStatus = MmGetSystemAddressForMdl( Irp->MdlAddress );
+
+ RtlZeroMemory(
+ adapterStatus,
+ sizeof(ADAPTER_STATUS) + sizeof(NAME_BUFFER)
+ );
+
+ adapterStatus->rev_major = 3;
+ adapterStatus->rev_minor = 0x02;
+ adapterStatus->free_ncbs = 0xffff;
+ adapterStatus->max_cfg_ncbs = 0xffff;
+ adapterStatus->max_ncbs = 0xffff;
+ adapterStatus->max_dgram_size = 0xffff;
+ adapterStatus->max_cfg_sess = 0xffff;
+ adapterStatus->max_sess = 0xffff;
+ adapterStatus->max_sess_pkt_size = 0xffff;
+ adapterStatus->name_count = 1;
+
+ name = (PNAME_BUFFER)(adapterStatus + 1);
+ name->name_num = 1;
+ name->name_flags = REGISTERED | UNIQUE_NAME;
+
+ Irp->IoStatus.Information =
+ sizeof(ADAPTER_STATUS) + sizeof(NAME_BUFFER);
+
+ status = STATUS_SUCCESS;
+
+ }
+
+ break;
+ }
+
+ case TDI_QUERY_SESSION_STATUS:
+
+ status = STATUS_NOT_IMPLEMENTED;
+
+ break;
+
+ default:
+
+ status = STATUS_INVALID_PARAMETER;
+
+ }
+
+ //
+ // Complete the Query Information request.
+ //
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest( Irp, 0 );
+
+ IF_DEBUG(LOOP1) DbgPrint( " Query Information request complete\n" );
+ return status;
+
+} // LoopQueryInformation
+
diff --git a/private/ntos/tdi/loopback/loopback.c b/private/ntos/tdi/loopback/loopback.c
new file mode 100644
index 000000000..00880f56d
--- /dev/null
+++ b/private/ntos/tdi/loopback/loopback.c
@@ -0,0 +1,1284 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ loopback.c
+
+Abstract:
+
+ This module implements a loopback Transport Provider driver for NT
+ LAN Manager.
+
+Author:
+
+ Chuck Lenzmeier (chuckl) 8-Oct-1989
+
+Revision History:
+
+--*/
+
+#include "loopback.h"
+
+extern POBJECT_TYPE *IoDeviceObjectType;
+
+//
+// Global variables
+//
+
+ULONG LoopDebug = 0;
+
+//
+// The address of the loopback device object (there's only one) is kept
+// in global storage to avoid having to pass it from routine to routine.
+//
+
+PLOOP_DEVICE_OBJECT LoopDeviceObject;
+
+//
+// LoopProviderInfo is a structure containing information that may be
+// obtained using TdiQueryInformation.
+//
+
+TDI_PROVIDER_INFO LoopProviderInfo;
+
+//
+// I/O system forward declarations
+//
+
+STATIC
+NTSTATUS
+LoopDispatchCleanup (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+STATIC
+NTSTATUS
+LoopDispatchClose (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+STATIC
+NTSTATUS
+LoopDispatchCreate (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+STATIC
+NTSTATUS
+LoopDispatchDeviceControl (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+STATIC
+NTSTATUS
+LoopDispatchInternalDeviceControl (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+STATIC
+VOID
+LoopUnload (
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+
+NTSTATUS
+DriverEntry (
+ IN PDRIVER_OBJECT DriverObject
+ )
+
+/*++
+
+Routine Description:
+
+ This is the initialization routine for the LAN Manager loopback
+ driver. This routine creates the device object for the loopback
+ device and performs all other driver initialization.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ STRING deviceName;
+ UNICODE_STRING unicodeString;
+
+#ifdef MEMPRINT
+ MemPrintInitialize( );
+#endif
+
+ IF_DEBUG(LOOP1) DbgPrint( "LoopInitialize entered\n" );
+
+ //
+ // Create the device object. (IoCreateDevice zeroes the memory
+ // occupied by the object.)
+ //
+
+ RtlInitString( &deviceName, LOOPBACK_DEVICE_NAME );
+
+ status = RtlAnsiStringToUnicodeString(
+ &unicodeString,
+ &deviceName,
+ TRUE
+ );
+
+ ASSERT( NT_SUCCESS(status) );
+
+ status = IoCreateDevice(
+ DriverObject, // DriverObject
+ LOOP_DEVICE_EXTENSION_LENGTH, // DeviceExtension
+ &unicodeString, // DeviceName
+ FILE_DEVICE_NETWORK, // DeviceType
+ 0, // DeviceCharacteristics
+ FALSE, // Exclusive
+ (PDEVICE_OBJECT *) &LoopDeviceObject // DeviceObject
+ );
+
+ RtlFreeUnicodeString( &unicodeString );
+
+ if ( !NT_SUCCESS(status) ) {
+ return status;
+ }
+
+ IF_DEBUG(LOOP1) DbgPrint( " Loop device object: %lx\n", LoopDeviceObject );
+
+ //
+ // Initialize the driver object for this driver's entry points.
+ //
+
+ DriverObject->MajorFunction[IRP_MJ_CREATE] = LoopDispatchCreate;
+ DriverObject->MajorFunction[IRP_MJ_CLEANUP] = LoopDispatchCleanup;
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] = LoopDispatchClose;
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
+ LoopDispatchDeviceControl;
+ DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
+ LoopDispatchInternalDeviceControl;
+ DriverObject->DriverUnload = LoopUnload;
+
+ //
+ // Allocate the spin lock.
+ //
+
+ KeInitializeSpinLock( &LoopDeviceObject->SpinLock );
+
+ DEBUG LoopDeviceObject->SavedIrql = (KIRQL)-1;
+
+ //
+ // Initialize the address and connection endpoint list heads.
+ //
+
+ InitializeListHead( &LoopDeviceObject->EndpointList );
+ InitializeListHead( &LoopDeviceObject->ConnectionList );
+
+ //
+ // Initialize the provider information structure.
+ //
+
+ RtlZeroMemory( &LoopProviderInfo, sizeof(LoopProviderInfo) );
+ LoopProviderInfo.Version = 2; // !!! Need to get this into tdi2.h
+ LoopProviderInfo.MaxTsduSize = MAXULONG;
+ LoopProviderInfo.MaxDatagramSize = MAXULONG;
+ LoopProviderInfo.ServiceFlags = TDI_SERVICE_CONNECTION_MODE |
+ TDI_SERVICE_CONNECTIONLESS_MODE |
+ TDI_SERVICE_ERROR_FREE_DELIVERY |
+ TDI_SERVICE_BROADCAST_SUPPORTED |
+ TDI_SERVICE_MULTICAST_SUPPORTED;
+ LoopProviderInfo.MinimumLookaheadData = 256;
+ LoopProviderInfo.MaximumLookaheadData = 256;
+
+ IF_DEBUG(LOOP1) DbgPrint( "LoopInitialize complete\n" );
+
+ return STATUS_SUCCESS;
+
+} // LoopInitialize
+
+
+NTSTATUS
+LoopDispatchCleanup(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the dispatch routine for Cleanup functions for the LAN
+ Manager loopback driver.
+
+Arguments:
+
+ DeviceObject - Pointer to device object for target device
+
+ Irp - Pointer to I/O request packet
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+--*/
+
+{
+ PIO_STACK_LOCATION irpSp;
+ PBLOCK_HEADER blockHeader;
+ PLOOP_ENDPOINT endpoint;
+ PLIST_ENTRY listEntry;
+ PIRP pendingIrp;
+ PLOOP_CONNECTION connection;
+ BLOCK_STATE oldState;
+ PLOOP_CONNECTION previousConnection;
+
+ DeviceObject; // not otherwise referenced if !DBG
+
+ ASSERT( DeviceObject == (PDEVICE_OBJECT)LoopDeviceObject );
+ // only one loopback device
+
+ IF_DEBUG(LOOP1) {
+ DbgPrint( "LoopDispatchCleanup entered for IRP %lx\n", Irp );
+ }
+
+ //
+ // Initialize the I/O status block.
+ //
+
+ Irp->IoStatus.Status = STATUS_PENDING;
+ Irp->IoStatus.Information = 0;
+
+ //
+ // Get a pointer to the current stack location in the IRP.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ ASSERT( irpSp->MajorFunction == IRP_MJ_CLEANUP );
+
+ ACQUIRE_LOOP_LOCK( "DispatchCleanup initial" );
+
+ blockHeader = (PBLOCK_HEADER)irpSp->FileObject->FsContext;
+
+ if ( blockHeader == NULL ) {
+
+ //
+ // A control channel is being cleaned up. We need do nothing.
+ //
+
+ IF_DEBUG(LOOP2) DbgPrint( " cleaning up control channel\n" );
+
+ } else if ( GET_BLOCK_TYPE(blockHeader) == BlockTypeLoopConnection ) {
+
+ //
+ // A connection file object is being cleaned up. Reference the
+ // connection to keep it around while we perform the cleanup.
+ //
+
+ connection = (PLOOP_CONNECTION)blockHeader;
+ IF_DEBUG(LOOP2) DbgPrint( " Connection address: %lx\n", connection );
+
+ connection->BlockHeader.ReferenceCount++;
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " New refcnt on connection %lx is %lx\n",
+ connection, connection->BlockHeader.ReferenceCount );
+ }
+
+ //
+ // Acquire the spin lock. Set the connection state to Closing.
+ // This will prevent other requests from being initiated.
+ //
+ // *** Note the assumption that this routine is only entered
+ // once. (That's the way the I/O system is supposed to
+ // work.) We don't check to see if the cleanup has already
+ // been initiated.
+ //
+ // *** In the rundown code, we release the lock, then reacquire
+ // it temporarily to remove things from lists and
+ // dereference the connection. We do this because we don't
+ // want to hold a spin lock for a long time.
+ //
+
+ oldState = GET_BLOCK_STATE( connection );
+ SET_BLOCK_STATE( connection, BlockStateClosing );
+
+ //
+ // If a Connect or Listen is active, abort it now.
+ //
+
+ if ( oldState == BlockStateConnecting ) {
+
+ pendingIrp = connection->ConnectOrListenIrp;
+ connection->ConnectOrListenIrp = NULL;
+
+ ASSERT( pendingIrp != NULL );
+
+ RemoveEntryList( &pendingIrp->Tail.Overlay.ListEntry );
+
+ RELEASE_LOOP_LOCK( "DispatchCleanup complete conn/listen" );
+
+ pendingIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ IoCompleteRequest( pendingIrp, 2 );
+
+ ACQUIRE_LOOP_LOCK( "DispatchCleanup conn/listen completed" );
+
+ }
+
+ //
+ // Disconnect the connection, if necessary.
+ //
+
+ if ( oldState == BlockStateActive ) {
+ LoopDoDisconnect( connection, TRUE );
+ }
+
+ //
+ // If the connection was bound, unbind it now.
+ //
+
+ if ( oldState == BlockStateBound ) {
+ endpoint = connection->Endpoint;
+ ASSERT( endpoint != NULL );
+ connection->Endpoint = NULL;
+ RemoveEntryList( &connection->EndpointListEntry );
+ LoopDereferenceEndpoint( endpoint );
+ }
+
+ //
+ // Dereference the connection.
+ //
+
+ LoopDereferenceConnection( connection );
+
+ RELEASE_LOOP_LOCK( "DispatchCleanup(conn) done" );
+
+ } else {
+
+ //
+ // An endpoint file object is being cleaned up.
+ //
+
+ endpoint = (PLOOP_ENDPOINT)blockHeader;
+ IF_DEBUG(LOOP2) DbgPrint( " Endpoint address: %lx\n", endpoint );
+
+ //
+ // Acquire the spin lock. Set the endpoint state to Closing.
+ // This will prevent other requests (Listens and Connects) from
+ // being initiated.
+ //
+ // *** Note the assumption that this routine is only entered
+ // once. (That's the way the I/O system is supposed to
+ // work.) We don't check to see if the cleanup has already
+ // been initiated.
+ //
+ // *** In the rundown code, we release the lock, then reacquire
+ // it temporarily to remove things from lists and
+ // dereference the endpoint. We do this because we don't
+ // want to hold a spin lock for a long time.
+ //
+
+ SET_BLOCK_STATE( endpoint, BlockStateClosing );
+
+ //
+ // Abort pending listens.
+ //
+
+ listEntry = RemoveHeadList( &endpoint->PendingListenList );
+
+ while ( listEntry != &endpoint->PendingListenList ) {
+
+ //
+ // A pending listen was found. Complete the listen with an
+ // error status. Get the next listen.
+ //
+
+ RELEASE_LOOP_LOCK( "DispatchCleanup complete Listen" );
+
+ pendingIrp = CONTAINING_RECORD(
+ listEntry,
+ IRP,
+ Tail.Overlay.ListEntry
+ );
+ pendingIrp->IoStatus.Status = STATUS_ENDPOINT_CLOSED;
+ IoCompleteRequest( pendingIrp, 2 );
+
+ ACQUIRE_LOOP_LOCK( "DispatchCleanup dequeue Listen" );
+
+ listEntry = RemoveHeadList( &endpoint->PendingListenList );
+ }
+
+ //
+ // Abort pending connects.
+ //
+
+ listEntry = RemoveHeadList( &endpoint->IncomingConnectList );
+
+ while ( listEntry != &endpoint->IncomingConnectList ) {
+
+ //
+ // A pending connect was found. Complete the connect with
+ // an error status. Get the next connect.
+ //
+
+ RELEASE_LOOP_LOCK( "DispatchCleanup complete Connect" );
+
+ pendingIrp = CONTAINING_RECORD(
+ listEntry,
+ IRP,
+ Tail.Overlay.ListEntry
+ );
+ pendingIrp->IoStatus.Status = STATUS_ENDPOINT_CLOSED;
+ IoCompleteRequest( pendingIrp, 2 );
+
+ ACQUIRE_LOOP_LOCK( "DispatchCleanup complete Connect" );
+
+ listEntry = RemoveHeadList( &endpoint->IncomingConnectList );
+ }
+
+ //
+ // Disconnect or unbind all bound connections.
+ //
+ // *** This loop is complicated by the fact that we can't remove
+ // connections from the list before disconnecting them, yet
+ // we want to keep the list consistent while we walk it. Be
+ // careful making changes to this loop!
+ //
+
+ previousConnection = NULL;
+
+ listEntry = endpoint->ConnectionList.Flink;
+
+ while ( listEntry != &endpoint->ConnectionList ) {
+
+ //
+ // A bound connection was found. If the connection's
+ // reference count is not already 0, reference it to keep it
+ // from going away. If the count is 0, skip to the next
+ // connection.
+ //
+
+ connection = CONTAINING_RECORD(
+ listEntry,
+ LOOP_CONNECTION,
+ EndpointListEntry
+ );
+
+ if ( connection->BlockHeader.ReferenceCount == 0 ) {
+
+ //
+ // Find the next connection in the list and loop.
+ //
+
+ listEntry = listEntry->Flink;
+ continue;
+
+ }
+
+ connection->BlockHeader.ReferenceCount++;
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " New refcnt on connection %lx is %lx\n",
+ connection, connection->BlockHeader.ReferenceCount );
+ }
+
+ //
+ // Dereference the previous connection, if any.
+ //
+
+ if ( previousConnection != NULL ) {
+ LoopDereferenceConnection( previousConnection );
+ }
+ previousConnection = connection;
+
+ //
+ // Disconnect or unbind the current connection. It won't be
+ // deleted.
+ //
+
+ if ( GET_BLOCK_STATE(connection) == BlockStateActive ) {
+
+ //
+ // Disconnect the connection.
+ //
+
+ SET_BLOCK_STATE( connection, BlockStateDisconnecting );
+ LoopDoDisconnect( connection, TRUE );
+
+ //
+ // Find the next connection in the list.
+ //
+
+ listEntry = listEntry->Flink;
+
+ } else if ( GET_BLOCK_STATE(connection) == BlockStateBound ) {
+
+ //
+ // Find the next connection in the list.
+ //
+
+ listEntry = listEntry->Flink;
+
+ //
+ // Unbind the connection.
+ //
+
+ ASSERT( connection->Endpoint == endpoint );
+ connection->Endpoint = NULL;
+ RemoveEntryList( &connection->EndpointListEntry );
+ SET_BLOCK_STATE( connection, BlockStateUnbound );
+ LoopDereferenceEndpoint( connection->Endpoint );
+
+ } else {
+
+ //
+ // Find the next connection in the list.
+ //
+
+ listEntry = listEntry->Flink;
+
+ }
+
+ }
+
+ //
+ // Dereference the previous connection, if any.
+ //
+
+ if ( previousConnection != NULL ) {
+ LoopDereferenceConnection( previousConnection );
+ }
+
+ //
+ // The spin lock is still held here. Cancel the receive handler.
+ //
+ // *** Note that we do not dereference the endpoint here. That is
+ // done in the Close handler. We have already set the state
+ // of the endpoint to closing, which will prevent any further
+ // activity from occurring.
+ //
+
+ endpoint->FileObject = NULL;
+ endpoint->ReceiveHandler = NULL;
+
+ RELEASE_LOOP_LOCK( "DispatchCleanup final" );
+
+ } // connection vs. endpoint
+
+ //
+ // Successful completion. Complete the I/O request.
+ //
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest( Irp, 2 );
+
+ IF_DEBUG(LOOP1) {
+ DbgPrint( "LoopDispatchCleanup complete for IRP %lx\n", Irp );
+ }
+
+ return STATUS_SUCCESS;
+
+} // LoopDispatchCleanup
+
+
+NTSTATUS
+LoopDispatchClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the dispatch routine for Close functions for the LAN
+ Manager loopback driver.
+
+Arguments:
+
+ DeviceObject - Pointer to device object for target device
+
+ Irp - Pointer to I/O request packet
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+--*/
+
+{
+ PIO_STACK_LOCATION irpSp;
+ PBLOCK_HEADER blockHeader;
+ PLOOP_ENDPOINT endpoint;
+ PLOOP_CONNECTION connection;
+
+ DeviceObject; // not otherwise referenced if !DBG
+
+ ASSERT( DeviceObject == (PDEVICE_OBJECT)LoopDeviceObject );
+ // only one loopback device
+
+ IF_DEBUG(LOOP1) {
+ DbgPrint( "LoopDispatchClose entered for IRP %lx\n", Irp );
+ }
+
+ //
+ // Initialize the I/O status block.
+ //
+
+ Irp->IoStatus.Status = STATUS_PENDING;
+ Irp->IoStatus.Information = 0;
+
+ //
+ // Get a pointer to the current stack location in the IRP.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ ASSERT( irpSp->MajorFunction == IRP_MJ_CLOSE );
+
+ ACQUIRE_LOOP_LOCK( "DispatchClose initial" );
+
+ blockHeader = (PBLOCK_HEADER)irpSp->FileObject->FsContext;
+
+ if ( blockHeader == NULL ) {
+
+ //
+ // A control channel is being closed. We need do nothing.
+ //
+
+ IF_DEBUG(LOOP2) DbgPrint( " closing control channel\n" );
+
+ } else if ( GET_BLOCK_TYPE(blockHeader) == BlockTypeLoopConnection ) {
+
+ //
+ // A connection file object is being closed.
+ //
+
+ connection = (PLOOP_CONNECTION)blockHeader;
+ IF_DEBUG(LOOP2) DbgPrint( " Connection address: %lx\n", connection );
+
+ //
+ // All external references to the file object (and thus the
+ // connection) are gone, but the connection block hasn't been
+ // deleted. This implies that a Disconnect is in progress,
+ // and when that operation completes, the connection block will
+ // be deleted. We need to set up for the Close IRP to be
+ // completed at that time. Reference and dereference the
+ // connection to allow it to be deleted.
+ //
+
+ connection->BlockHeader.ReferenceCount++;
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " New refcnt on connection %lx is %lx\n",
+ connection, connection->BlockHeader.ReferenceCount );
+ }
+
+ SET_BLOCK_STATE( connection, BlockStateClosed );
+
+ connection->CloseIrp = Irp;
+ IoMarkIrpPending( Irp );
+
+ LoopDereferenceConnection( connection );
+
+ RELEASE_LOOP_LOCK( "DispatchClose(conn) final" );
+
+ } else {
+
+ ASSERT( GET_BLOCK_TYPE(blockHeader) == BlockTypeLoopEndpoint );
+
+ endpoint = (PLOOP_ENDPOINT)irpSp->FileObject->FsContext;
+ IF_DEBUG(LOOP2) DbgPrint( " Endpoint address: %lx\n", endpoint );
+
+ //
+ // All external references to the file object (and thus the
+ // endpoint) are gone. Normally, the only remaining internal
+ // reference to the endpoint is the one that keeps the endpoint
+ // "open". Eliminate that reference. The CloseIrp field in the
+ // endpoint is used to remember the IRP that must be completed
+ // when the reference count goes to 0.
+ //
+ // *** Because LoopDereferenceEndpoint may or may not complete
+ // the Close IRP, we return STATUS_PENDING from the service
+ // call. We must mark this fact in the IRP before calling
+ // LoopDereferenceEndpoint.
+ //
+
+ endpoint->CloseIrp = Irp;
+ IoMarkIrpPending( Irp );
+
+ LoopDereferenceEndpoint( endpoint );
+
+ RELEASE_LOOP_LOCK( "DispatchClose final" );
+
+ }
+ IF_DEBUG(LOOP1) {
+ DbgPrint( "LoopDispatchClose complete (pending) for IRP %lx\n",
+ Irp );
+ }
+
+ return STATUS_PENDING;
+
+} // LoopDispatchClose
+
+
+NTSTATUS
+LoopDispatchCreate(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the dispatch routine for Create functions for the LAN
+ Manager loopback driver.
+
+Arguments:
+
+ DeviceObject - Pointer to device object for target device
+
+ Irp - Pointer to I/O request packet
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+--*/
+
+{
+ NTSTATUS status;
+ BLOCK_TYPE type;
+ PIO_STACK_LOCATION irpSp;
+ PLOOP_ENDPOINT endpoint;
+ PLOOP_ENDPOINT existingEndpoint;
+ PLOOP_CONNECTION connection;
+
+ DeviceObject; // not otherwise referenced if !DBG
+
+ ASSERT( DeviceObject == (PDEVICE_OBJECT)LoopDeviceObject );
+ // only one loopback device
+
+ IF_DEBUG(LOOP1) {
+ DbgPrint( "LoopDispatchCreate entered for IRP %lx\n", Irp );
+ }
+
+ //
+ // Initialize the I/O status block.
+ //
+
+ Irp->IoStatus.Status = STATUS_PENDING;
+ Irp->IoStatus.Information = 0;
+
+ //
+ // Get a pointer to the current stack location in the IRP.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ ASSERT( irpSp->MajorFunction == IRP_MJ_CREATE );
+
+ //
+ // Determine whether an address endpoint or a connection endpoint is
+ // being created, or if a control channel is being opened.
+ //
+
+ if ( Irp->AssociatedIrp.SystemBuffer == NULL ) {
+
+ //
+ // A control channel is being opened. This channel is used
+ // only to get provider information and to determine the
+ // provider's broadcast address.
+ //
+
+ IF_DEBUG(LOOP2) DbgPrint( " opening control channel\n" );
+
+ irpSp->FileObject->FsContext = NULL;
+
+ } else {
+
+ status = LoopGetEndpointTypeFromEa(
+ (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer,
+ &type
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest( Irp, 0 );
+ return status;
+ }
+
+ if ( type == BlockTypeLoopEndpoint ) {
+
+ //
+ // An address endpoint is being created.
+ //
+ // Allocate a LOOP_ENDPOINT block to describe the transport
+ // endpoint. Initialize it.
+ //
+
+ endpoint = ExAllocatePool( NonPagedPool, sizeof(LOOP_ENDPOINT) );
+ if ( endpoint == NULL ) {
+ IF_DEBUG(LOOP2) DbgPrint( " Unable to allocate pool\n" );
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest( Irp, 0 );
+ IF_DEBUG(LOOP1) {
+ DbgPrint( "LoopDispatchCreate complete for IRP %lx\n",
+ Irp );
+ }
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Endpoint allocated: %lx\n", endpoint );
+ }
+ SET_BLOCK_TYPE( endpoint, BlockTypeLoopEndpoint );
+ SET_BLOCK_STATE( endpoint, BlockStateActive );
+ SET_BLOCK_SIZE( endpoint, sizeof(LOOP_ENDPOINT) );
+ endpoint->BlockHeader.ReferenceCount = 1; // for file object
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " New refcnt on endpoint %lx is %lx\n",
+ endpoint, endpoint->BlockHeader.ReferenceCount );
+ }
+
+ InitializeListHead( &endpoint->ConnectionList );
+ InitializeListHead( &endpoint->PendingListenList );
+ InitializeListHead( &endpoint->IncomingConnectList );
+ endpoint->IndicatingConnectIrp = NULL;
+
+ endpoint->FileObject = irpSp->FileObject;
+ endpoint->ConnectHandler = NULL;
+ endpoint->ReceiveHandler = NULL;
+ endpoint->ReceiveDatagramHandler = NULL;
+ endpoint->ReceiveExpeditedHandler = NULL;
+ endpoint->DisconnectHandler = NULL;
+ endpoint->ErrorHandler = NULL;
+ endpoint->CloseIrp = NULL;
+
+ //
+ // Save a pointer to the endpoint block in the file object
+ // so that we can find it when file-based requests are
+ // issued.
+ //
+
+ irpSp->FileObject->FsContext = (PVOID)endpoint;
+
+ //
+ // Reference the loopback device object.
+ //
+
+ ObReferenceObject( LoopDeviceObject );
+
+ endpoint->DeviceObject = LoopDeviceObject;
+
+ //
+ // The EA contains the address to be bound to the endpoint.
+ // Verify that the address is not already bound.
+ //
+ // !!! This should really be a share-mode/SECURITY_DESCRIPTOR
+ // check.
+ //
+
+ LoopParseAddressFromEa(
+ (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer,
+ endpoint->NetbiosName
+ );
+ endpoint->NetbiosName[NETBIOS_NAME_LENGTH] = 0;
+
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Address to bind: \"%s\"\n",
+ endpoint->NetbiosName );
+ }
+
+ ACQUIRE_LOOP_LOCK( "DispatchCreate(endp) initial" );
+
+ existingEndpoint = LoopFindBoundAddress( endpoint->NetbiosName );
+
+ if ( existingEndpoint != NULL ) {
+
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Duplicate address at endpoint %lx\n",
+ existingEndpoint );
+ }
+
+ RELEASE_LOOP_LOCK( "DispatchCreate duplicate address" );
+
+ ObDereferenceObject( LoopDeviceObject );
+
+ DEBUG SET_BLOCK_TYPE( endpoint, BlockTypeGarbage );
+ DEBUG SET_BLOCK_STATE( endpoint, BlockStateDead );
+ DEBUG SET_BLOCK_SIZE( endpoint, -1 );
+ DEBUG endpoint->BlockHeader.ReferenceCount = -1;
+ DEBUG endpoint->DeviceObject = NULL;
+ ExFreePool( endpoint );
+
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ IoCompleteRequest( Irp, 0 );
+
+ IF_DEBUG(LOOP1) {
+ DbgPrint( "LoopDispatchCreate complete for IRP %lx\n",
+ Irp );
+ }
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // Link the new endpoint into the loopback device's endpoint
+ // list.
+ //
+
+ InsertTailList(
+ &LoopDeviceObject->EndpointList,
+ &endpoint->DeviceListEntry
+ );
+
+ RELEASE_LOOP_LOCK( "DispatchCreate(endp) final" );
+
+ } else {
+
+ //
+ // A connection endpoint is being created.
+ //
+ // Allocate a LOOP_CONNECTION block to describe the connection.
+ // Initialize it.
+ //
+
+ connection = ExAllocatePool(
+ NonPagedPool,
+ sizeof(LOOP_CONNECTION)
+ );
+ if ( connection == NULL ) {
+ IF_DEBUG(LOOP2) DbgPrint( " Unable to allocate pool\n" );
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest( Irp, 0 );
+ IF_DEBUG(LOOP1) {
+ DbgPrint( "LoopDispatchCreate complete for IRP %lx\n",
+ Irp );
+ }
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Connection allocated: %lx\n", connection );
+ }
+ SET_BLOCK_TYPE( connection, BlockTypeLoopConnection );
+ SET_BLOCK_STATE( connection, BlockStateUnbound );
+ SET_BLOCK_SIZE( connection, sizeof(LOOP_CONNECTION) );
+ connection->BlockHeader.ReferenceCount = 0; // not connected
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " New refcnt on connection %lx is %lx\n",
+ connection,
+ connection->BlockHeader.ReferenceCount );
+ }
+
+ connection->Endpoint = NULL;
+ connection->RemoteConnection = NULL;
+ connection->ConnectionContext = LoopGetConnectionContextFromEa(
+ Irp->AssociatedIrp.SystemBuffer
+ );
+
+ InitializeListHead( &connection->PendingReceiveList );
+ InitializeListHead( &connection->IncomingSendList );
+
+ connection->FileObject = irpSp->FileObject;
+
+ connection->IndicatingSendIrp = NULL;
+ connection->ConnectOrListenIrp = NULL;
+ connection->CloseIrp = NULL;
+ connection->DisconnectIrp = NULL;
+
+ //
+ // Save a pointer to the connection block in the file object
+ // so that we can find it when file-based requests are
+ // issued.
+ //
+
+ irpSp->FileObject->FsContext = (PVOID)connection;
+
+ //
+ // Reference the loopback device object.
+ //
+
+ ObReferenceObject( LoopDeviceObject );
+
+ connection->DeviceObject = LoopDeviceObject;
+
+ //
+ // Link the new connection into the loopback device's connection
+ // list.
+ //
+
+ ExInterlockedInsertTailList(
+ &LoopDeviceObject->ConnectionList,
+ &connection->DeviceListEntry,
+ &LoopDeviceObject->SpinLock
+ );
+
+ }
+
+ }
+
+ //
+ // Successful completion. Complete the I/O request.
+ //
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest( Irp, 2 );
+
+ IF_DEBUG(LOOP1) {
+ DbgPrint( "LoopDispatchCreate complete for IRP %lx\n", Irp );
+ }
+
+ return STATUS_SUCCESS;
+
+} // LoopDispatchCreate
+
+
+NTSTATUS
+LoopDispatchDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the dispatch routine for Device Control functions for the
+ LAN Manager loopback driver.
+
+Arguments:
+
+ DeviceObject - Pointer to device object for target device
+
+ Irp - Pointer to I/O request packet
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+--*/
+
+{
+ NTSTATUS status;
+ PIO_STACK_LOCATION irpSp;
+
+ ASSERT( DeviceObject == (PDEVICE_OBJECT)LoopDeviceObject );
+ // only one loopback device
+
+ IF_DEBUG(LOOP1) {
+ DbgPrint( "LoopDispatchDeviceControl entered for IRP %lx\n", Irp );
+ }
+
+ //
+ // Initialize the I/O status block.
+ //
+
+ Irp->IoStatus.Status = STATUS_PENDING;
+ Irp->IoStatus.Information = 0;
+
+ //
+ // Get a pointer to the current stack location in the IRP.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ ASSERT( irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL );
+
+ //
+ // Convert the (external) device control into internal format, then
+ // treat it as if it had arrived that way.
+ //
+
+ status = TdiMapUserRequest( DeviceObject, Irp, irpSp );
+
+ if ( !NT_SUCCESS(status) ) {
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest( Irp, 0 );
+
+ return status;
+
+ }
+
+ return LoopDispatchInternalDeviceControl( DeviceObject, Irp );
+
+} // LoopDispatchDeviceControl
+
+
+NTSTATUS
+LoopDispatchInternalDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the dispatch routine for Internal Device Control functions
+ for the LAN Manager loopback driver.
+
+Arguments:
+
+ DeviceObject - Pointer to device object for target device
+
+ Irp - Pointer to I/O request packet
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+--*/
+
+{
+ PIO_STACK_LOCATION irpSp;
+
+ DeviceObject; // not otherwise referenced if !DBG
+
+ ASSERT( DeviceObject == (PDEVICE_OBJECT)LoopDeviceObject );
+ // only one loopback device
+
+ IF_DEBUG(LOOP1) {
+ DbgPrint( "LoopDispatchInternalDeviceControl entered for IRP %lx\n",
+ Irp );
+ }
+
+ //
+ // Initialize the I/O status block.
+ //
+
+ Irp->IoStatus.Status = STATUS_PENDING;
+ Irp->IoStatus.Information = 0;
+
+ //
+ // Get a pointer to the current stack location in the IRP.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ ASSERT( irpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL );
+
+ //
+ // Case on the control code.
+ //
+
+ switch ( irpSp->MinorFunction ) {
+
+ case TDI_ACCEPT:
+
+ return LoopAccept( Irp, irpSp );
+
+ case TDI_ASSOCIATE_ADDRESS:
+
+ return LoopAssociateAddress( Irp, irpSp );
+
+ case TDI_CONNECT:
+
+ return LoopConnect( Irp, irpSp );
+
+ case TDI_DISASSOCIATE_ADDRESS:
+
+ return LoopDisassociateAddress( Irp, irpSp );
+
+ case TDI_DISCONNECT:
+
+ return LoopDisconnect( Irp, irpSp );
+
+ case TDI_LISTEN:
+
+ return LoopListen( Irp, irpSp );
+
+ case TDI_QUERY_INFORMATION:
+
+ return LoopQueryInformation( Irp, irpSp );
+
+ case TDI_RECEIVE:
+
+ return LoopReceive( Irp, irpSp );
+
+ case TDI_SEND:
+
+ return LoopSend( Irp, irpSp );
+
+ case TDI_SET_EVENT_HANDLER:
+
+ return LoopSetEventHandler( Irp, irpSp );
+
+ case TDI_SEND_DATAGRAM:
+
+ //
+ // !!! Need to implement this request.
+ //
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest( Irp, 0 );
+
+ return STATUS_SUCCESS;
+
+ case TDI_RECEIVE_DATAGRAM:
+ case TDI_SET_INFORMATION:
+
+ //
+ // !!! Need to implement these requests.
+ //
+
+ Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
+ IoCompleteRequest( Irp, 0 );
+
+ return STATUS_NOT_IMPLEMENTED;
+
+ default:
+
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Invalid device control function: %lx\n",
+ irpSp->Parameters.DeviceIoControl.IoControlCode );
+ }
+
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ IoCompleteRequest( Irp, 0 );
+
+ return STATUS_INVALID_PARAMETER;
+
+ }
+
+ return STATUS_INVALID_PARAMETER; // can't get here
+
+} // LoopDispatchInternalDeviceControl
+
+
+VOID
+LoopUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+
+/*++
+
+Routine Description:
+
+ This is the unload routine for the LAN Manager loopback driver.
+
+Arguments:
+
+ DriverObject - Pointer to driver object for this driver.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DriverObject; // prevent compiler warnings
+
+ return;
+
+} // LoopUnload
diff --git a/private/ntos/tdi/loopback/loopback.h b/private/ntos/tdi/loopback/loopback.h
new file mode 100644
index 000000000..150a26ffb
--- /dev/null
+++ b/private/ntos/tdi/loopback/loopback.h
@@ -0,0 +1,433 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ loopback.h
+
+Abstract:
+
+ This module is the main include file for the LAN Manager loopback
+ driver.
+
+Author:
+
+ Chuck Lenzmeier (chuckl) 27-Jun-1991
+
+Revision History:
+
+--*/
+
+#ifndef _LOOP_
+#define _LOOP_
+
+//
+// "System" include files
+//
+
+#include <ntos.h>
+
+#include <tdikrnl.h>
+
+//
+// Network include files.
+//
+
+#include "status.h"
+
+//
+// Local, independent include files
+//
+
+#include "loopdbg.h"
+
+#define LOOPBACK_DEVICE_NAME "\\Device\\Loop"
+
+//
+// The length of a NetBIOS name. Fixed by the protocol.
+//
+
+#define NETBIOS_NAME_LENGTH 16
+
+//
+// Simple MIN and MAX macros. Watch out for side effects!
+//
+
+#define MIN(a,b) ( ((a) < (b)) ? (a) : (b) )
+#define MAX(a,b) ( ((a) < (b)) ? (b) : (a) )
+
+//
+// Macros for accessing the block header structure.
+//
+// *** Note that the existing usage of these macros assumes that the block
+// header is the first element in the block!
+//
+
+#define GET_BLOCK_STATE(block) ( ((PBLOCK_HEADER)(block))->State )
+#define SET_BLOCK_STATE(block,state) ( ((PBLOCK_HEADER)(block))->State = state )
+
+#define GET_BLOCK_TYPE(block) ( ((PBLOCK_HEADER)(block))->Type )
+#define SET_BLOCK_TYPE(block,type) ( ((PBLOCK_HEADER)(block))->Type = type )
+
+#define GET_BLOCK_SIZE(block) ( ((PBLOCK_HEADER)(block))->Size )
+#define SET_BLOCK_SIZE(block,size) ( ((PBLOCK_HEADER)(block))->Size = size )
+
+//
+// Local macros
+//
+
+//
+// Macros for lock debugging.
+//
+// *** Note that the test for recursion only works on uniprocessors.
+//
+
+#if LOOPDBG && defined(LOOPLOCK)
+
+#define ACQUIRE_LOOP_LOCK(instance) { \
+ IF_DEBUG(LOOP5) \
+ DbgPrint( "Acquire loop lock, %s\n", \
+ (instance) ); \
+ if ( LoopDeviceObject->SavedIrql != (KIRQL)-1 ) { \
+ DbgPrint( "Recursive lock acquisition attempt\n" ); \
+ DbgBreakPoint( ); \
+ } \
+ KeAcquireSpinLock( \
+ &LoopDeviceObject->SpinLock, \
+ &LoopDeviceObject->SavedIrql \
+ ); \
+ }
+
+#define RELEASE_LOOP_LOCK(instance) { \
+ KIRQL oldIrql; \
+ IF_DEBUG(LOOP5) \
+ DbgPrint( "Release loop lock, %s\n", \
+ (instance) ); \
+ ASSERT( LoopDeviceObject->SavedIrql != (KIRQL)-1 ); \
+ oldIrql = LoopDeviceObject->SavedIrql; \
+ LoopDeviceObject->SavedIrql = (KIRQL)-1; \
+ KeReleaseSpinLock( \
+ &LoopDeviceObject->SpinLock, \
+ oldIrql \
+ ); \
+ }
+
+#else // LOOPDBG && defined(LOOPLOCK)
+
+#define ACQUIRE_LOOP_LOCK(instance) \
+ KeAcquireSpinLock( \
+ &LoopDeviceObject->SpinLock, \
+ &LoopDeviceObject->SavedIrql \
+ ) \
+
+#define RELEASE_LOOP_LOCK(instance) \
+ KeReleaseSpinLock( \
+ &LoopDeviceObject->SpinLock, \
+ LoopDeviceObject->SavedIrql \
+ ) \
+
+#endif // else LOOPDBG && defined(LOOPLOCK)
+
+//
+// Local types
+//
+
+//
+// The loopback driver's device object is a standard I/O system device
+// object followed by fields specific to the device.
+//
+
+typedef struct _LOOP_DEVICE_OBJECT {
+
+ DEVICE_OBJECT DeviceObject;
+
+ //
+ // List of active address endpoints.
+ //
+
+ LIST_ENTRY EndpointList;
+
+ //
+ // List of active connection endpoints.
+ //
+
+ LIST_ENTRY ConnectionList;
+
+ //
+ // Spin lock synchronizing access to fields in the device object
+ // and to structures maintained by the device driver.
+ //
+
+ KSPIN_LOCK SpinLock;
+
+ //
+ // SavedIrql is used so that one routine can call another with the
+ // lock held and the called routine can release (and possibly
+ // reacquire it). SavedIrql is set *after* the lock is acquired.
+ //
+
+ KIRQL SavedIrql;
+
+} LOOP_DEVICE_OBJECT, *PLOOP_DEVICE_OBJECT;
+
+#define LOOP_DEVICE_EXTENSION_LENGTH (sizeof(LOOP_DEVICE_OBJECT) - \
+ sizeof(DEVICE_OBJECT))
+
+//
+// BLOCK_TYPE is an enumerated type defining the various types of
+// data blocks used by the driver.
+//
+
+typedef enum _BLOCK_TYPE {
+ BlockTypeGarbage = 0,
+ BlockTypeLoopConnection = 0x29290001,
+ BlockTypeLoopEndpoint = 0x29290002
+} BLOCK_TYPE, *PBLOCK_TYPE;
+
+//
+// BLOCK_STATE is an enumerated type defining the various states that
+// blocks can be in. Initializing is used (relatively rarely) to
+// indicate that creation/initialization of a block is in progress.
+// Active is the state blocks are usually in. Closing is used to
+// indicate that a block is being prepared for deletion; when the
+// reference count on the block reaches 0, the block will be deleted.
+// Dead is used when debugging code is enabled to indicate that the
+// block has been deleted.
+//
+
+typedef enum _BLOCK_STATE {
+ BlockStateDead,
+ BlockStateUnbound,
+ BlockStateBound,
+ BlockStateConnecting,
+ BlockStateActive,
+ BlockStateDisconnecting,
+ BlockStateClosing,
+ BlockStateClosed,
+ // The following is defined just to know how many states there are
+ BlockStateMax
+} BLOCK_STATE, *PBLOCK_STATE;
+
+
+//
+// BLOCK_HEADER is the standard block header that appears at the
+// beginning of most driver-private data structures. This header is
+// used primarily for debugging and tracing. The Type and State fields
+// are described above. The Size field indicates how much space was
+// allocated for the block. ReferenceCount indicates the number of
+// reasons why the block should not be deallocated. The count is set to
+// 2 by the allocation routine, to account for 1) the fact that the
+// block is "open" and 2) the pointer returned to the caller. When the
+// block is closed, State is set to Closing, and the ReferenceCount is
+// decremented. When all references (pointers) to the block are
+// deleted, and the reference count reaches 0, the block is deleted.
+//
+
+typedef struct _BLOCK_HEADER {
+ BLOCK_TYPE Type;
+ BLOCK_STATE State;
+ ULONG ReferenceCount;
+ CLONG Size;
+} BLOCK_HEADER, *PBLOCK_HEADER;
+
+//
+// The file object obtained when the loopback Transport Provider is
+// opened points to a LOOP_ENDPOINT record, which has context consisting
+// of a pointer to the file object and a list of connections created
+// over the endpoint.
+//
+
+typedef struct _LOOP_ENDPOINT {
+ BLOCK_HEADER BlockHeader;
+ LIST_ENTRY DeviceListEntry;
+ LIST_ENTRY ConnectionList;
+ LIST_ENTRY PendingListenList;
+ LIST_ENTRY IncomingConnectList;
+ PIRP IndicatingConnectIrp;
+ PLOOP_DEVICE_OBJECT DeviceObject;
+ PFILE_OBJECT FileObject;
+ PTDI_IND_CONNECT ConnectHandler;
+ PVOID ConnectContext;
+ PTDI_IND_RECEIVE ReceiveHandler;
+ PVOID ReceiveContext;
+ PTDI_IND_RECEIVE_DATAGRAM ReceiveDatagramHandler;
+ PVOID ReceiveDatagramContext;
+ PTDI_IND_RECEIVE_EXPEDITED ReceiveExpeditedHandler;
+ PVOID ReceiveExpeditedContext;
+ PTDI_IND_DISCONNECT DisconnectHandler;
+ PVOID DisconnectContext;
+ PTDI_IND_ERROR ErrorHandler;
+ PVOID ErrorContext;
+ PIRP CloseIrp;
+ CHAR NetbiosName[NETBIOS_NAME_LENGTH+1];
+} LOOP_ENDPOINT, *PLOOP_ENDPOINT;
+
+//
+// Each connection is represented by two LOOP_CONNECTION structures, one
+// for each end of the connection.
+//
+
+typedef struct _LOOP_CONNECTION {
+ BLOCK_HEADER BlockHeader;
+ LIST_ENTRY DeviceListEntry;
+ LIST_ENTRY EndpointListEntry;
+ PLOOP_ENDPOINT Endpoint;
+ PLOOP_DEVICE_OBJECT DeviceObject;
+ PFILE_OBJECT FileObject;
+ struct _LOOP_CONNECTION *RemoteConnection;
+ PVOID ConnectionContext;
+ LIST_ENTRY PendingReceiveList;
+ LIST_ENTRY IncomingSendList;
+ PIRP IndicatingSendIrp;
+ PIRP ConnectOrListenIrp;
+ PIRP DisconnectIrp;
+ PIRP CloseIrp;
+} LOOP_CONNECTION, *PLOOP_CONNECTION;
+
+//
+// Global variables
+//
+
+//
+// The address of the loopback device object (there's only one) is kept
+// in global storage to avoid having to pass it from routine to routine.
+//
+
+extern PLOOP_DEVICE_OBJECT LoopDeviceObject;
+
+//
+// LoopProviderInfo is a structure containing information that may be
+// obtained using TdiQueryInformation.
+//
+
+extern TDI_PROVIDER_INFO LoopProviderInfo;
+
+
+//
+// Global declarations
+//
+
+NTSTATUS
+LoopAccept (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+LoopAssociateAddress (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+LoopConnect (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+VOID
+LoopCopyData (
+ IN PMDL Destination,
+ IN PMDL Source,
+ IN ULONG Length
+ );
+
+NTSTATUS
+LoopCreate (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+VOID
+LoopDereferenceConnection (
+ IN PLOOP_CONNECTION Connection
+ );
+
+VOID
+LoopDereferenceEndpoint (
+ IN PLOOP_ENDPOINT Endpoint
+ );
+
+NTSTATUS
+LoopDisassociateAddress (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+LoopDisconnect (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+VOID
+LoopDoDisconnect (
+ IN PLOOP_CONNECTION Conection,
+ IN BOOLEAN ClientInitiated
+ );
+
+PLOOP_ENDPOINT
+LoopFindBoundAddress (
+ IN PCHAR NetbiosName
+ );
+
+PVOID
+LoopGetConnectionContextFromEa (
+ PFILE_FULL_EA_INFORMATION Ea
+ );
+
+NTSTATUS
+LoopGetEndpointTypeFromEa (
+ PFILE_FULL_EA_INFORMATION Ea,
+ PBLOCK_TYPE Type
+ );
+
+NTSTATUS
+LoopListen (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+LoopParseAddress (
+ IN PTA_NETBIOS_ADDRESS Address,
+ OUT PCHAR NetbiosName
+ );
+
+NTSTATUS
+LoopParseAddressFromEa (
+ IN PFILE_FULL_EA_INFORMATION Ea,
+ OUT PCHAR NetbiosName
+ );
+
+NTSTATUS
+LoopQueryInformation (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+LoopReceive (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+LoopSend (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+LoopSetEventHandler (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+LoopVerifyEndpoint (
+ IN PLOOP_ENDPOINT Endpoint
+ );
+
+#endif // def _LOOP_
diff --git a/private/ntos/tdi/loopback/loopdbg.h b/private/ntos/tdi/loopback/loopdbg.h
new file mode 100644
index 000000000..4024f5e4e
--- /dev/null
+++ b/private/ntos/tdi/loopback/loopdbg.h
@@ -0,0 +1,58 @@
+#ifndef _LOOPDBG_
+#define _LOOPDBG_
+
+#ifdef MEMPRINT
+#include <memprint.h>
+#endif
+
+//
+// Debugging macros
+//
+
+#ifndef DBG
+#define DBG 0
+#endif
+
+#if !DBG
+
+#undef LOOPDBG
+#define LOOPDBG 0
+
+#else
+
+#ifndef LOOPDBG
+#define LOOPDBG 0
+#endif
+
+#endif
+
+#undef IF_DEBUG
+
+#if !DEVL
+#define STATIC static
+#else
+#define STATIC
+#endif
+
+#if !LOOPDBG
+
+#define DEBUG if (FALSE)
+#define IF_DEBUG(flag) if (FALSE)
+
+#else
+
+#define DEBUG if (TRUE)
+#define IF_DEBUG(flag) if (LoopDebug & (DEBUG_ ## flag))
+extern ULONG LoopDebug;
+
+#define PRINT_LITERAL(literal) DbgPrint( #literal" = %lx\n", (literal) )
+
+#define DEBUG_LOOP1 0x00000001
+#define DEBUG_LOOP2 0x00000002
+#define DEBUG_LOOP3 0x00000004
+#define DEBUG_LOOP4 0x00000008
+#define DEBUG_LOOP5 0x00000010
+
+#endif // else !LOOPDBG
+
+#endif // ndef _LOOPDBG_
diff --git a/private/ntos/tdi/loopback/loopsub.c b/private/ntos/tdi/loopback/loopsub.c
new file mode 100644
index 000000000..003161e5f
--- /dev/null
+++ b/private/ntos/tdi/loopback/loopsub.c
@@ -0,0 +1,379 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ loopsub.c
+
+Abstract:
+
+ This module implements common functions for the loopback Transport
+ Provider driver for NT LAN Manager.
+
+Author:
+
+ Chuck Lenzmeier (chuckl) 15-Aug-1991
+
+Revision History:
+
+--*/
+
+#include "loopback.h"
+
+
+VOID
+LoopCopyData (
+ IN PMDL Destination,
+ IN PMDL Source,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies data from the storage described by one MDL chain
+ into the storage described by another MDL chain.
+
+Arguments:
+
+ Destination - Pointer to first MDL in Destination chain
+
+ Source - Pointer to first MDL in Source chain
+
+ Length - Amount of data to copy. Caller must ensure that the Source
+ and Destination chains are at least this long.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCHAR sourceAddress;
+ ULONG sourceLength;
+
+ PCHAR destinationAddress;
+ ULONG destinationLength;
+
+ ULONG copyLength;
+
+ //
+ // Get the virtual address of the first source buffer, mapping it
+ // if necessary. Also get the length of the buffer.
+ //
+
+ sourceAddress = MmGetSystemAddressForMdl( Source );
+ sourceLength = MmGetMdlByteCount( Source );
+
+ //
+ // Get the virtual address of the first destination buffer, mapping
+ // it if necessary. Also get the length of the buffer.
+ //
+
+ destinationAddress = MmGetSystemAddressForMdl( Destination );
+ destinationLength = MmGetMdlByteCount( Destination );
+
+ //
+ // Loop copying data.
+ //
+
+ do {
+
+ //
+ // The amount to copy in this pass is the minimum of 1) the
+ // amount remaining in the current source buffer, 2) the amount
+ // remaining in the current destination buffer, and 3) the
+ // amount remaining in the overall copy operation.
+ //
+
+ copyLength = sourceLength;
+ if ( copyLength > destinationLength ) copyLength = destinationLength;
+ if ( copyLength > Length ) copyLength = Length;
+
+ //
+ // Copy from the source buffer into the destination buffer.
+ //
+
+#ifndef TIMING
+ IF_DEBUG(LOOP4) {
+ DbgPrint( " copying %lx bytes from %lx to %lx\n",
+ copyLength, sourceAddress, destinationAddress );
+ DbgPrint( " source data: %lx, %lx\n",
+ *(PULONG)sourceAddress, *((PULONG)sourceAddress + 1) );
+ }
+ RtlMoveMemory( destinationAddress, sourceAddress, copyLength );
+#else
+ if ( (NtGlobalFlag & 0x20000000) == 0 ) {
+ RtlMoveMemory( destinationAddress, sourceAddress, copyLength );
+ } else {
+ RtlMoveMemory(
+ destinationAddress,
+ sourceAddress,
+ (copyLength > 200) ? 200 : copyLength
+ );
+ }
+#endif
+
+ //
+ // If all of the requested data has been copied, leave.
+ //
+
+ Length -= copyLength;
+
+ if ( Length == 0 ) {
+
+ return;
+
+ }
+
+ //
+ // If we have used up all of the current source buffer, move to
+ // the next buffer. Get the virtual address of the next buffer,
+ // mapping it if necessary. Also get the length of the buffer.
+ // If we haven't used up the current source buffer, simply
+ // update the source pointer and the remaining length.
+ //
+
+ if ( copyLength == sourceLength ) {
+
+ Source = Source->Next;
+
+ sourceAddress = MmGetSystemAddressForMdl( Source );
+ sourceLength = MmGetMdlByteCount( Source );
+
+ } else {
+
+ sourceAddress += copyLength;
+ sourceLength -= copyLength;
+
+ }
+
+ //
+ // If we have used up all of the current destination buffer,
+ // move to the next buffer. Get the virtual address of the next
+ // buffer, mapping it if necessary. Also get the length of the
+ // buffer. If we haven't used up the current destination
+ // buffer, simply update the destination pointer and the
+ // remaining length.
+ //
+
+ if ( copyLength == destinationLength ) {
+
+ Destination = Destination->Next;
+
+ destinationAddress = MmGetSystemAddressForMdl( Destination );
+ destinationLength = MmGetMdlByteCount( Destination );
+
+ } else {
+
+ destinationAddress += copyLength;
+ destinationLength -= copyLength;
+
+ }
+
+ } while ( TRUE );
+
+ //
+ // Can't get here.
+ //
+
+ ASSERTMSG( FALSE, "Can't get here!" );
+
+} // LoopCopyData
+
+
+PVOID
+LoopGetConnectionContextFromEa (
+ PFILE_FULL_EA_INFORMATION Ea
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the connection context specified in an EA.
+
+Arguments:
+
+ Ea - Pointer to EA buffer
+
+Return Value:
+
+ PVOID - Connection context
+
+--*/
+
+{
+ PVOID ctx;
+
+ RtlMoveMemory( &ctx, &Ea->EaName[Ea->EaNameLength + 1], sizeof(PVOID) );
+
+ return ctx;
+
+} // LoopGetConnectionContextFromEa
+
+
+NTSTATUS
+LoopGetEndpointTypeFromEa (
+ PFILE_FULL_EA_INFORMATION Ea,
+ PBLOCK_TYPE Type
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether an EA describes an address or a
+ connection.
+
+Arguments:
+
+ Ea - Pointer to EA buffer
+
+ Type - Returns block type
+
+Return Value:
+
+ NTSTATUS - STATUS_INVALID_PARAMETER if EA is not valid
+
+--*/
+
+{
+ //
+ // First check for address type.
+ //
+
+ if ( (Ea->EaNameLength == TDI_TRANSPORT_ADDRESS_LENGTH) &&
+ (strcmp( Ea->EaName, TdiTransportAddress ) == 0) ) {
+ *Type = BlockTypeLoopEndpoint;
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Next check for connection type.
+ //
+
+ if ( (Ea->EaNameLength == TDI_CONNECTION_CONTEXT_LENGTH) &&
+ (strcmp( Ea->EaName, TdiConnectionContext ) == 0) ) {
+ *Type = BlockTypeLoopConnection;
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Invalid type.
+ //
+
+ return STATUS_INVALID_PARAMETER;
+
+} // LoopGetEndpointTypeFromEa
+
+
+NTSTATUS
+LoopParseAddress (
+ IN PTA_NETBIOS_ADDRESS Address,
+ OUT PCHAR NetbiosName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine parses the input AddressString according to conventions
+ defined for transport address strings as defined in the TDI
+ specification. It converts the name from that form into a "standard"
+ NetBIOS name.
+
+Arguments:
+
+ Address - Pointer to a transport address in the TDI format.
+
+ NetbiosName - A 16-character space into which the NULL-terminated
+ NetBIOS name is written.
+
+Return Value:
+
+ NTSTATUS - Indicates whether the address string was valid.
+
+--*/
+
+{
+ //
+ // If the input address is not a single unique address in NetBIOS
+ // format, reject it.
+ //
+
+ if ( (Address->TAAddressCount != 1) ||
+ (Address->Address[0].AddressType != TDI_ADDRESS_TYPE_NETBIOS) ||
+ (Address->Address[0].AddressLength != sizeof(TDI_ADDRESS_NETBIOS)) ||
+ (Address->Address[0].Address[0].NetbiosNameType !=
+ TDI_ADDRESS_NETBIOS_TYPE_UNIQUE) ) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // Copy the name into the output buffer.
+ //
+
+ RtlMoveMemory(
+ NetbiosName,
+ Address->Address[0].Address[0].NetbiosName,
+ NETBIOS_NAME_LENGTH
+ );
+
+ return STATUS_SUCCESS;
+
+} // LoopParseAddress
+
+
+NTSTATUS
+LoopParseAddressFromEa (
+ IN PFILE_FULL_EA_INFORMATION Ea,
+ OUT PCHAR NetbiosName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine parses the input EA according to conventions defined
+ for transport address strings as defined in the TDI specification.
+ It converts the name from that form into a "standard" NetBIOS name.
+
+Arguments:
+
+ Ea - Pointer to an EA in the TDI format.
+
+ NetbiosName - A 16-character space into which the NULL-terminated
+ NetBIOS name is written.
+
+Return Value:
+
+ NTSTATUS - Indicates whether the address string was valid.
+
+--*/
+
+{
+ TA_NETBIOS_ADDRESS nbAddress;
+
+ if ( Ea->EaValueLength != sizeof(TA_NETBIOS_ADDRESS) ) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ RtlMoveMemory(
+ &nbAddress,
+ &Ea->EaName[Ea->EaNameLength + 1],
+ sizeof(TA_NETBIOS_ADDRESS)
+ );
+
+ //
+ // Pass the value portion of the EA, which is a TRANSPORT_ADDRESS,
+ // to LoopParseAddress.
+ //
+
+ return LoopParseAddress( &nbAddress, NetbiosName );
+
+} // LoopParseAddressFromEa
+
diff --git a/private/ntos/tdi/loopback/makefile b/private/ntos/tdi/loopback/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/loopback/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/loopback/sources b/private/ntos/tdi/loopback/sources
new file mode 100644
index 000000000..dcbcb8f31
--- /dev/null
+++ b/private/ntos/tdi/loopback/sources
@@ -0,0 +1,46 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=tdi
+MINORCOMP=loopback
+
+TARGETNAME=loopback
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\tdi.lib
+
+INCLUDES=..\inc;..\..\inc;..\..\..\inc
+
+SOURCES= \
+ connect.c \
+ endpoint.c \
+ info.c \
+ loopback.c \
+ loopsub.c \
+ transfer.c
+
+!IFNDEF 386_WARNING_LEVEL
+386_WARNING_LEVEL=/W3
+!ENDIF
diff --git a/private/ntos/tdi/loopback/transfer.c b/private/ntos/tdi/loopback/transfer.c
new file mode 100644
index 000000000..d80fb44fb
--- /dev/null
+++ b/private/ntos/tdi/loopback/transfer.c
@@ -0,0 +1,859 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ transfer.c
+
+Abstract:
+
+ This module implements data transfer logic for the loopback
+ Transport Provider driver for NT LAN Manager.
+
+Author:
+
+ Chuck Lenzmeier (chuckl) 15-Aug-1991
+
+Revision History:
+
+--*/
+
+#include "loopback.h"
+
+//
+// Local declarations
+//
+
+STATIC
+VOID
+CompleteReceive (
+ IN PIRP ReceiveIrp,
+ IN PIRP SendIrp
+ );
+
+STATIC
+VOID
+IndicateReceive (
+ IN PLOOP_CONNECTION ReceivingConnection,
+ IN PIRP InitialSendIrp
+ );
+
+
+NTSTATUS
+LoopReceive (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a Receive request.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+
+ IrpSp - Pointer to current stack location in IRP
+
+Return Value:
+
+ NTSTATUS - Status of request
+
+--*/
+
+{
+ PLOOP_CONNECTION receivingConnection;
+ PLOOP_CONNECTION sendingConnection;
+
+ IF_DEBUG(LOOP1) DbgPrint( " Receive request\n" );
+
+ //
+ // Verify that the receiving connection is connected.
+ //
+
+ receivingConnection = (PLOOP_CONNECTION)IrpSp->FileObject->FsContext;
+
+ if ( receivingConnection == NULL ) {
+ IF_DEBUG(LOOP2) DbgPrint( " Can't Receive on control channel\n" );
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ IoCompleteRequest( Irp, 0 );
+ IF_DEBUG(LOOP1) DbgPrint( " Receive request complete\n" );
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ sendingConnection = receivingConnection->RemoteConnection;
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Receiving connection: %lx\n", receivingConnection );
+ DbgPrint( " Sending connection: %lx\n", sendingConnection );
+ }
+
+ ACQUIRE_LOOP_LOCK( "Receive initial" );
+
+ if ( (sendingConnection == NULL) ||
+ (GET_BLOCK_STATE(receivingConnection) != BlockStateActive) ) {
+ RELEASE_LOOP_LOCK( "Receive closing" );
+ IF_DEBUG(LOOP2) DbgPrint( " Connection not connected\n" );
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ IoCompleteRequest( Irp, 0 );
+ IF_DEBUG(LOOP1) DbgPrint( " Receive request complete\n" );
+ return STATUS_DISCONNECTED;
+ }
+
+ //
+ // Queue the Receive to the connection's Pending Receive list.
+ //
+
+ InsertTailList(
+ &receivingConnection->PendingReceiveList,
+ &Irp->Tail.Overlay.ListEntry
+ );
+
+ IoMarkIrpPending( Irp );
+
+ //
+ // Check for pending data.
+ //
+
+ if ( (receivingConnection->IndicatingSendIrp != NULL) ||
+ (receivingConnection->IncomingSendList.Flink ==
+ &receivingConnection->IncomingSendList) ) {
+
+ //
+ // There is no pending Send, or an indication is already in
+ // progress. Reference the connection to account for the
+ // Receive IRP.
+ //
+
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " No pending Send; leaving IRP %lx queued \n", Irp );
+ }
+ receivingConnection->BlockHeader.ReferenceCount++;
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " New refcnt on connection %lx is %lx\n",
+ receivingConnection,
+ receivingConnection->BlockHeader.ReferenceCount );
+ }
+
+ RELEASE_LOOP_LOCK( "Receive no Send" );
+
+ } else {
+
+ //
+ // There is pending data. Call IndicateReceive to satisfy
+ // the Receive.
+ //
+ // *** Note that IndicateReceive returns with the loopback
+ // driver spin lock released.
+ //
+
+ IF_DEBUG(LOOP2) DbgPrint( " LoopReceive indicating receive\n" );
+ IndicateReceive( receivingConnection, NULL );
+
+ }
+
+ IF_DEBUG(LOOP1) DbgPrint( " Receive request %lx complete\n", Irp );
+ return STATUS_PENDING;
+
+} // LoopReceive
+
+
+NTSTATUS
+LoopSend (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a Send request.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+
+ IrpSp - Pointer to current stack location in IRP
+
+Return Value:
+
+ NTSTATUS - Status of request
+
+--*/
+
+{
+ PLOOP_CONNECTION sendingConnection;
+ PLOOP_CONNECTION receivingConnection;
+ BOOLEAN firstSend;
+
+ IF_DEBUG(LOOP1) DbgPrint( " Send request\n" );
+
+ //
+ // Verify that the sending connection is connected.
+ //
+
+ sendingConnection = (PLOOP_CONNECTION)IrpSp->FileObject->FsContext;
+
+ if ( sendingConnection == NULL ) {
+ IF_DEBUG(LOOP2) DbgPrint( " Can't Send on control channel\n" );
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ IoCompleteRequest( Irp, 0 );
+ IF_DEBUG(LOOP1) DbgPrint( " Send request complete\n" );
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ receivingConnection = sendingConnection->RemoteConnection;
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Sending connection: %lx\n", sendingConnection );
+ DbgPrint( " Receiving connection: %lx\n", receivingConnection );
+ }
+
+ ACQUIRE_LOOP_LOCK( "Send initial" );
+
+ if ( (receivingConnection == NULL) ||
+ (GET_BLOCK_STATE(sendingConnection) != BlockStateActive) ) {
+ RELEASE_LOOP_LOCK( "Send closing" );
+ IF_DEBUG(LOOP2) DbgPrint( " Connection not connected\n" );
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ IoCompleteRequest( Irp, 0 );
+ IF_DEBUG(LOOP1) DbgPrint( " Send request complete\n" );
+ return STATUS_DISCONNECTED;
+ }
+
+ //
+ // Reference both ends.
+ //
+
+ sendingConnection->BlockHeader.ReferenceCount++;
+ receivingConnection->BlockHeader.ReferenceCount++;
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " New refcnt on connection %lx is %lx\n",
+ sendingConnection,
+ sendingConnection->BlockHeader.ReferenceCount );
+ DbgPrint( " New refcnt on connection %lx is %lx\n",
+ receivingConnection,
+ receivingConnection->BlockHeader.ReferenceCount );
+ }
+
+ //
+ // Determine whether this is the first active incoming Send for the
+ // receiving connection.
+ //
+
+ firstSend = (BOOLEAN)( receivingConnection->IncomingSendList.Flink ==
+ &receivingConnection->IncomingSendList );
+
+ //
+ // Queue the Send to the receiving connection's Incoming Send list,
+ // in order to prevent another Send from getting ahead of this one.
+ //
+
+ InsertTailList(
+ &receivingConnection->IncomingSendList,
+ &Irp->Tail.Overlay.ListEntry
+ );
+
+ IoMarkIrpPending( Irp );
+
+ if ( !firstSend || (receivingConnection->IndicatingSendIrp != NULL) ) {
+
+ //
+ // Pending data already exists, or an indication is already in
+ // progress. This Send remains behind the already pending data.
+ //
+
+ IF_DEBUG(LOOP2) DbgPrint( " Data already pending\n" );
+
+ RELEASE_LOOP_LOCK( "Send sends pending" );
+
+ } else {
+
+ //
+ // Indicate the incoming data.
+ //
+ // *** Note that IndicateReceive returns with the loopback
+ // driver spin lock released.
+ //
+
+ IF_DEBUG(LOOP2) DbgPrint( " LoopSend indicating receive\n" );
+ IndicateReceive( receivingConnection, Irp );
+
+ }
+
+ IF_DEBUG(LOOP1) DbgPrint( " Send request %lx complete\n", Irp );
+ return STATUS_PENDING;
+
+} // LoopSend
+
+
+VOID
+CompleteReceive (
+ IN PIRP ReceiveIrp,
+ IN PIRP SendIrp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine completes the process of sending a message. It copies
+ the message from the source buffer into the destination buffer.
+
+ The reference counts on the owning connections must have been
+ incremented to account for the requesting IRPs in order to prevent
+ their deletion.
+
+Arguments:
+
+ ReceiveIrp - Pointer to IRP used for Receive request
+
+ SendIrp - Pointer to IRP used for Send request
+
+Return Value:
+
+ NTSTATUS - Indicates whether the connection was successfully created
+
+--*/
+
+{
+ NTSTATUS status;
+ PIO_STACK_LOCATION sendIrpSp;
+ PIO_STACK_LOCATION receiveIrpSp;
+ ULONG copyLength;
+ PTDI_REQUEST_KERNEL_SEND sendRequest;
+ PTDI_REQUEST_KERNEL_RECEIVE receiveRequest;
+ PLOOP_CONNECTION sendingConnection;
+ PLOOP_CONNECTION receivingConnection;
+
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Send IRP %lx completes receive IRP %lx\n",
+ SendIrp, ReceiveIrp );
+ }
+
+ //
+ // Copy the data from the source buffer into the destination buffer.
+ //
+ // *** Note that we special-case zero-length copies. We don't
+ // bother to call LoopCopyData. Part of the reason for this
+ // is that a zero-length send or receive issued from user mode
+ // yields an IRP that has a NULL MDL address.
+ //
+
+ sendIrpSp = IoGetCurrentIrpStackLocation( SendIrp );
+ sendRequest = (PTDI_REQUEST_KERNEL_SEND)&sendIrpSp->Parameters;
+ copyLength = sendRequest->SendLength;
+ IF_DEBUG(LOOP4) {
+ DbgPrint( " Send request at %lx, send length %lx\n",
+ sendRequest, copyLength );
+ }
+ receiveIrpSp = IoGetCurrentIrpStackLocation( ReceiveIrp );
+ receiveRequest = (PTDI_REQUEST_KERNEL_RECEIVE)&receiveIrpSp->Parameters;
+ IF_DEBUG(LOOP4) {
+ DbgPrint( " Receive request at %lx, receive length %lx\n",
+ receiveRequest, receiveRequest->ReceiveLength );
+ }
+ status = STATUS_SUCCESS;
+ if ( copyLength > receiveRequest->ReceiveLength ) {
+ status = STATUS_BUFFER_OVERFLOW;
+ copyLength = receiveRequest->ReceiveLength;
+ }
+
+ if ( copyLength != 0 ) {
+
+ ASSERT( ReceiveIrp->MdlAddress != NULL );
+ ASSERT( SendIrp->MdlAddress != NULL );
+
+ LoopCopyData(
+ ReceiveIrp->MdlAddress,
+ SendIrp->MdlAddress,
+ copyLength
+ );
+
+ }
+
+ //
+ // Complete the Receive and Send requests.
+ //
+
+ receivingConnection =
+ (PLOOP_CONNECTION)receiveIrpSp->FileObject->FsContext;
+ sendingConnection =
+ (PLOOP_CONNECTION)sendIrpSp->FileObject->FsContext;
+
+ ReceiveIrp->IoStatus.Status = status;
+ ReceiveIrp->IoStatus.Information = copyLength;
+
+ SendIrp->IoStatus.Status = STATUS_SUCCESS;
+ SendIrp->IoStatus.Information = copyLength;
+
+ IoCompleteRequest( ReceiveIrp, 2 );
+ IoCompleteRequest( SendIrp, 2 );
+
+ //
+ // Dereference the connections.
+ //
+
+ ACQUIRE_LOOP_LOCK( "CompleteReceive dereference" );
+ LoopDereferenceConnection( receivingConnection );
+ LoopDereferenceConnection( sendingConnection );
+ RELEASE_LOOP_LOCK( "CompleteReceive dereference" );
+
+ return;
+
+} // CompleteReceive
+
+
+VOID
+IndicateReceive (
+ IN PLOOP_CONNECTION ReceivingConnection,
+ IN PIRP InitialSendIrp
+ )
+{
+ NTSTATUS status;
+ PLOOP_ENDPOINT receivingEndpoint;
+ PLOOP_CONNECTION sendingConnection;
+ PLIST_ENTRY listEntry;
+ PIRP receiveIrp;
+ PIRP sendIrp;
+ PTDI_IND_RECEIVE receiveHandler;
+ PVOID receiveContext;
+ PIO_STACK_LOCATION sendIrpSp;
+ PTDI_REQUEST_KERNEL_SEND sendRequest;
+ ULONG length;
+ PMDL mdl;
+ PVOID address;
+ ULONG bytesTaken;
+
+ receivingEndpoint = ReceivingConnection->Endpoint;
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Receiving endpoint: %lx\n", receivingEndpoint );
+ }
+
+ //
+ // Reference the receiving connection to prevent it from going away
+ // while this routine is running.
+ //
+
+ ReceivingConnection->BlockHeader.ReferenceCount++;
+ IF_DEBUG(LOOP3) {
+ DbgPrint( " New refcnt on connection %lx is %lx\n",
+ ReceivingConnection,
+ ReceivingConnection->BlockHeader.ReferenceCount );
+ }
+
+ //
+ // Capture the address of the sending connection, as the receiving
+ // connection's pointer can be zeroed if a Disconnect occurs.
+ //
+
+ sendingConnection = ReceivingConnection->RemoteConnection;
+ ASSERT( sendingConnection != NULL );
+
+ //
+ // If the receiving connection has a pending Receive, satisfy it
+ // with this Send. If there is no pending Receive, and a Receive
+ // handler has been enabled on the receiving connection, call it.
+ // If the Receive handler returns with a Receive IRP, use it to
+ // satisfy this Send. If the Receive handler doesn't return an IRP,
+ // leave this Send pending.
+ //
+ // !!! Note that the current implementation only works because
+ // partial sends are not supported.
+ //
+
+ while ( TRUE ) {
+
+ //
+ // We have a Send pending. Is there a pending Receive?
+ //
+
+ listEntry = RemoveHeadList( &ReceivingConnection->PendingReceiveList );
+
+ if ( listEntry != &ReceivingConnection->PendingReceiveList ) {
+
+ //
+ // Found a pending Receive. Use it to satisfy the first
+ // incoming Send.
+ //
+
+ receiveIrp = CONTAINING_RECORD(
+ listEntry,
+ IRP,
+ Tail.Overlay.ListEntry
+ );
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Receive IRP pending: %lx\n", receiveIrp );
+ }
+
+ listEntry = RemoveHeadList(
+ &ReceivingConnection->IncomingSendList
+ );
+ ASSERT( listEntry != &ReceivingConnection->IncomingSendList );
+ sendIrp = CONTAINING_RECORD(
+ listEntry,
+ IRP,
+ Tail.Overlay.ListEntry
+ );
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Send IRP pending: %lx\n", sendIrp );
+ }
+
+ //
+ // If this is the first time through the loop, and we were
+ // called to process a newly queued Send, dereference the
+ // receiving connection -- LoopSend referenced the
+ // connection an extra time in case the Send had to remain
+ // queued.
+ //
+
+ if ( InitialSendIrp != NULL ) {
+ LoopDereferenceConnection( ReceivingConnection );
+ }
+
+ RELEASE_LOOP_LOCK( "IndicateReceive pending Receive" );
+
+ CompleteReceive( receiveIrp, sendIrp );
+
+ ACQUIRE_LOOP_LOCK( "IndicateReceive pending Receive completed" );
+
+ //
+ // Fall to bottom of loop to handle more incoming Sends.
+ //
+
+ } else {
+
+ //
+ // No pending Receive. Is there a Receive handler?
+ //
+
+ receiveHandler = receivingEndpoint->ReceiveHandler;
+ receiveContext = receivingEndpoint->ReceiveContext;
+
+ if ( receiveHandler == NULL ) {
+
+ //
+ // No Receive handler. The Send must remain queued.
+ //
+
+ IF_DEBUG(LOOP2) DbgPrint( " No Receive handler\n" );
+
+ break;
+
+ }
+
+ //
+ // The receiving endpoint has a Receive handler. Call it.
+ // If it returns STATUS_SUCCESS, it completely handled the
+ // data. If it returns STATUS_MORE_PROCESSING_REQUIRED, it
+ // also returns a Receive IRP describing where to put the
+ // data. Any other return status means the receiver can't
+ // take the data just now, so we leave the Send queued and
+ // wait for the receiver to post a Receive IRP.
+ //
+ // !!! Note that we don't currently handle partial data
+ // acceptance.
+ //
+ // First, remove the first Send from the Incoming Send list,
+ // and make it the Indicating Send. It must be removed from
+ // the list to ensure that it isn't completed by
+ // LoopDoDisconnection while we're indicating it.
+ //
+
+ listEntry = RemoveHeadList(
+ &ReceivingConnection->IncomingSendList
+ );
+ ASSERT( listEntry != &ReceivingConnection->IncomingSendList );
+ sendIrp = CONTAINING_RECORD(
+ listEntry,
+ IRP,
+ Tail.Overlay.ListEntry
+ );
+ ReceivingConnection->IndicatingSendIrp = sendIrp;
+
+ RELEASE_LOOP_LOCK( "IndicateReceive calling Receive handler" );
+
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Receive handler: %lx\n", receiveHandler );
+ DbgPrint( " Send IRP: %lx\n", sendIrp );
+ }
+
+ sendIrpSp = IoGetCurrentIrpStackLocation( sendIrp );
+ sendRequest = (PTDI_REQUEST_KERNEL_SEND)&sendIrpSp->Parameters;
+
+ length = sendRequest->SendLength;
+ ASSERTMSG(
+ "Loopback driver doesn't handle partial or expedited sends",
+ sendRequest->SendFlags == 0
+ );
+
+ //
+ // Map the send buffer, if necessary.
+ //
+
+ mdl = sendIrp->MdlAddress;
+ if ( MmGetMdlByteCount(mdl) == 0 ) {
+ address = NULL;
+ } else {
+ address = MmGetSystemAddressForMdl( mdl );
+ }
+
+ //
+ // Call the Receive handler.
+ //
+
+ status = receiveHandler(
+ receiveContext,
+ ReceivingConnection->ConnectionContext,
+ 0,
+ MmGetMdlByteCount( mdl ),
+ length,
+ &bytesTaken,
+ address,
+ &receiveIrp
+ );
+
+ ACQUIRE_LOOP_LOCK( "IndicateReceive after calling handler" );
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Indication for send IRP %lx done\n", sendIrp );
+ }
+
+ ReceivingConnection->IndicatingSendIrp = NULL;
+
+ if ( status == STATUS_SUCCESS ) {
+
+ //
+ // The Receive handler completely handled the data.
+ // Complete the Send.
+ //
+
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Receive handler handled data\n" );
+ }
+
+ ASSERTMSG(
+ "Loopback driver doesn't handle partial acceptance "
+ "of indications",
+ bytesTaken == length
+ );
+
+ //
+ // Dereference the sending and receiving connections --
+ // LoopSend referenced the connections when it queued
+ // the Send.
+ //
+
+ LoopDereferenceConnection( ReceivingConnection );
+ LoopDereferenceConnection( sendingConnection );
+
+ RELEASE_LOOP_LOCK( "IndicateReceive completely handled" );
+
+ //
+ // Complete the Send IRP.
+ //
+
+ sendIrp->IoStatus.Status = STATUS_SUCCESS;
+ sendIrp->IoStatus.Information = sendRequest->SendLength;
+
+ IoCompleteRequest( sendIrp, 2 );
+
+ ACQUIRE_LOOP_LOCK( "IndicateReceive send completed" );
+
+ //
+ // Fall to bottom of loop to handle more incoming
+ // Sends.
+ //
+
+ } else if ( status == STATUS_MORE_PROCESSING_REQUIRED ) {
+
+ //
+ // The Receive handler returned a Receive IRP to be used
+ // to satisfy the Send.
+ //
+
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Receive handler returned IRP: %lx\n",
+ receiveIrp );
+ }
+
+ ASSERTMSG(
+ "Loopback driver doesn't handle partial acceptance "
+ "of indications",
+ bytesTaken == 0
+ );
+
+ //
+ // Complete the Receive using the current Send.
+ //
+ // *** Note that the pending Send references both the
+ // sending and receiving connections.
+
+ RELEASE_LOOP_LOCK( "IndicateReceive complete new Receive" );
+
+ CompleteReceive( receiveIrp, sendIrp );
+
+ ACQUIRE_LOOP_LOCK( "IndicateReceive new receive completed" );
+
+ //
+ // Fall to bottom of loop to handle more incoming
+ // Sends.
+ //
+
+ } else {
+
+ //
+ // The Receive handler couldn't take the data. This
+ // Send will have to wait until receiver can post a
+ // Receive IRP.
+ //
+ // *** Because we didn't hold the spin lock around the
+ // call to the Receive handler, it's possible that
+ // the receiver has already posted a Receive IRP.
+ // Because we were in the middle of an indication,
+ // that Receive would have been queued to the
+ // Pending Receive list, and we should go get it
+ // now. If the receiver hasn't posted a Receive
+ // yet, then this Send will be put back on the
+ // Incoming Send list before the Receive does come
+ // in (since we're now holding the lock).
+ //
+
+ ASSERT( status == STATUS_DATA_NOT_ACCEPTED );
+
+ IF_DEBUG(LOOP2) DbgPrint( " Data not accepted\n" );
+
+ if ( GET_BLOCK_STATE(ReceivingConnection) !=
+ BlockStateActive ) {
+
+ //
+ // The connection is closing. Abort the current
+ // Send and leave.
+ //
+
+ LoopDereferenceConnection( ReceivingConnection );
+ LoopDereferenceConnection( sendingConnection );
+
+ RELEASE_LOOP_LOCK( "IndicateReceive disconnecting" );
+
+ sendIrp->IoStatus.Status = STATUS_DISCONNECTED;
+ IoCompleteRequest( sendIrp, 2 );
+
+ ACQUIRE_LOOP_LOCK( "IndicateReceive send aborted" );
+
+ break;
+
+ }
+
+ listEntry = RemoveHeadList(
+ &ReceivingConnection->PendingReceiveList
+ );
+
+ if ( listEntry !=
+ &ReceivingConnection->PendingReceiveList ) {
+
+ //
+ // A Receive has been posted. Use it to satisfy
+ // this Send.
+ //
+
+ receiveIrp = CONTAINING_RECORD(
+ listEntry,
+ IRP,
+ Tail.Overlay.ListEntry
+ );
+ IF_DEBUG(LOOP2) {
+ DbgPrint( " Receive IRP pending: %lx\n",
+ receiveIrp );
+ }
+
+ //
+ // Complete the Receive using the current Send.
+ //
+ //
+ // If this is the first time through the loop, and
+ // we were called to process a newly queued Send,
+ // dereference the receiving connection -- LoopSend
+ // referenced the connection an extra time in case
+ // the Send had to remain queued.
+ //
+
+ if ( InitialSendIrp != NULL ) {
+ LoopDereferenceConnection( ReceivingConnection );
+ }
+
+ RELEASE_LOOP_LOCK(
+ "IndicateReceive complete posted Receive"
+ );
+
+ CompleteReceive( receiveIrp, sendIrp );
+
+ ACQUIRE_LOOP_LOCK(
+ "IndicateReceive posted receive completed"
+ );
+
+ //
+ // Fall to bottom of loop to handle more incoming
+ // Sends.
+ //
+
+ } else {
+
+ //
+ // The handler didn't take the data, and it didn't
+ // post a Receive IRP. Requeue the current send and
+ // get out.
+ //
+
+ InsertHeadList(
+ &ReceivingConnection->IncomingSendList,
+ &sendIrp->Tail.Overlay.ListEntry
+ );
+
+ break;
+
+ }
+
+ }
+
+ } // pending receive?
+
+ //
+ // If we get here, we need to indicate the next incoming Send,
+ // if there is one.
+ //
+
+ InitialSendIrp = NULL;
+
+ if ( (GET_BLOCK_STATE(ReceivingConnection) != BlockStateActive) ||
+ (ReceivingConnection->IncomingSendList.Flink ==
+ &ReceivingConnection->IncomingSendList) ) {
+
+ //
+ // No more Sends, or connection no longer active. Leave.
+ //
+
+ break;
+
+ }
+
+ //
+ // Process the next Send.
+ //
+
+ } // while ( TRUE )
+
+ //
+ // Remove the connection reference acquired at the start of this
+ // routine.
+ //
+
+ LoopDereferenceConnection( ReceivingConnection );
+
+ RELEASE_LOOP_LOCK( "IndicateReceive done" );
+
+ return;
+
+} // IndicateReceive
+
diff --git a/private/ntos/tdi/nbf/action.c b/private/ntos/tdi/nbf/action.c
new file mode 100644
index 000000000..84a51695a
--- /dev/null
+++ b/private/ntos/tdi/nbf/action.c
@@ -0,0 +1,642 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ action.c
+
+Abstract:
+
+ This module contains support for the TdiAction handler.
+
+Author:
+
+ David Beaver (dbeaver) 2-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+typedef struct _QUERY_INDICATION {
+ UCHAR Command;
+ USHORT Data2;
+ UCHAR DestinationName[16];
+ UCHAR SourceName[16];
+} QUERY_INDICATION, *PQUERY_INDICATION;
+
+typedef struct _ACTION_QUERY_INDICATION {
+ TDI_ACTION_HEADER Header;
+ QUERY_INDICATION QueryIndication;
+} ACTION_QUERY_INDICATION, *PACTION_QUERY_INDICATION;
+
+
+typedef struct _DATAGRAM_INDICATION {
+ UCHAR DestinationName[16];
+ UCHAR SourceName[16];
+ USHORT DatagramBufferLength;
+ UCHAR DatagramBuffer[1];
+} DATAGRAM_INDICATION, *PDATAGRAM_INDICATION;
+
+typedef struct _ACTION_DATAGRAM_INDICATION {
+ TDI_ACTION_HEADER Header;
+ DATAGRAM_INDICATION DatagramIndication;
+} ACTION_DATAGRAM_INDICATION, *PACTION_DATAGRAM_INDICATION;
+
+
+#define QUERY_INDICATION_CODE 1
+#define DATAGRAM_INDICATION_CODE 2
+
+
+
+VOID
+NbfCancelAction(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+
+
+NTSTATUS
+NbfTdiAction(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiAction request for the transport
+ provider.
+
+Arguments:
+
+ DeviceContext - The device context for the operation
+
+ Irp - the Irp for the requested operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_ACTION_HEADER ActionHeader;
+ LARGE_INTEGER timeout = {0,0};
+ PTP_REQUEST tpRequest;
+ KIRQL oldirql, cancelirql;
+
+
+ //
+ // what type of status do we want?
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ ActionHeader = (PTDI_ACTION_HEADER)MmGetSystemAddressForMdl (Irp->MdlAddress);
+
+
+ //
+ // Handle the requests based on the action code.
+ //
+
+ switch (ActionHeader->ActionCode) {
+
+ case QUERY_INDICATION_CODE:
+ case DATAGRAM_INDICATION_CODE:
+
+ //
+ // These two requests are sent by RAS to "MABF"
+ //
+
+ if (!RtlEqualMemory ((PVOID)(&ActionHeader->TransportId), "MABF", 4)) {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ //
+ // They should be sent on the control channel
+ //
+
+ if (irpSp->FileObject->FsContext2 != (PVOID)NBF_FILE_TYPE_CONTROL) {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+
+ //
+ // Create a request to describe this.
+ //
+
+ status = NbfCreateRequest (
+ Irp, // IRP for this request.
+ DeviceContext, // context.
+ REQUEST_FLAGS_DC, // partial flags.
+ Irp->MdlAddress,
+ MmGetMdlByteCount(Irp->MdlAddress),
+ timeout,
+ &tpRequest);
+
+ if (NT_SUCCESS (status)) {
+
+ NbfReferenceDeviceContext ("Action", DeviceContext, DCREF_REQUEST);
+ tpRequest->Owner = DeviceContextType;
+ tpRequest->FrameContext = (USHORT)irpSp->FileObject->FsContext;
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
+
+ //
+ // Disallow these requests on a stopping device.
+ //
+
+ if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+ NbfCompleteRequest (tpRequest, STATUS_DEVICE_NOT_READY, 0);
+
+ } else {
+
+ if (ActionHeader->ActionCode == QUERY_INDICATION_CODE) {
+
+ InsertTailList (
+ &DeviceContext->QueryIndicationQueue,
+ &tpRequest->Linkage);
+
+ } else {
+
+ InsertTailList (
+ &DeviceContext->DatagramIndicationQueue,
+ &tpRequest->Linkage);
+
+ }
+
+ DeviceContext->IndicationQueuesInUse = TRUE;
+
+
+ //
+ // If this IRP has been cancelled, then call the
+ // cancel routine.
+ //
+
+ if (Irp->Cancel) {
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
+ Irp->CancelIrql = cancelirql;
+ NbfCancelAction((PDEVICE_OBJECT)DeviceContext, Irp);
+ return STATUS_PENDING;
+ }
+
+ IoSetCancelRoutine(Irp, NbfCancelAction);
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ }
+
+ status = STATUS_PENDING;
+
+ }
+
+ break;
+
+ default:
+
+ status = STATUS_NOT_IMPLEMENTED;
+
+ }
+
+
+ return status;
+
+}
+
+
+VOID
+NbfCancelAction(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel an Action.
+ What is done to cancel it is specific to each action.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PIO_STACK_LOCATION IrpSp;
+ PTP_REQUEST Request;
+ PLIST_ENTRY p;
+ BOOLEAN Found;
+ PTDI_ACTION_HEADER ActionHeader;
+ PLIST_ENTRY QueueHead, QueueEnd;
+
+ PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (IrpSp->MinorFunction == TDI_ACTION));
+
+ ActionHeader = (PTDI_ACTION_HEADER)MmGetSystemAddressForMdl (Irp->MdlAddress);
+
+ switch (ActionHeader->ActionCode) {
+
+ case QUERY_INDICATION_CODE:
+ case DATAGRAM_INDICATION_CODE:
+
+ //
+ // Scan through the appropriate queue, looking for this IRP.
+ // If we find it, we just remove it from the queue; there
+ // is nothing else involved in cancelling.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ if (ActionHeader->ActionCode == QUERY_INDICATION_CODE) {
+ QueueHead = DeviceContext->QueryIndicationQueue.Flink;
+ QueueEnd = &DeviceContext->QueryIndicationQueue;
+ } else {
+ QueueHead = DeviceContext->DatagramIndicationQueue.Flink;
+ QueueEnd = &DeviceContext->DatagramIndicationQueue;
+ }
+
+ Found = FALSE;
+ for (p = QueueHead; p != QueueEnd; p = p->Flink) {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ if (Request->IoRequestPacket == Irp) {
+
+ //
+ // Found it, remove it from the list here.
+ //
+
+ RemoveEntryList (p);
+
+ Found = TRUE;
+ break;
+
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ if (Found) {
+
+ NbfCompleteRequest (Request, STATUS_CANCELLED, 0);
+
+ } else {
+
+#if DBG
+ DbgPrint("NBF: Tried to cancel action %lx on %lx, not found\n",
+ Irp, DeviceContext);
+#endif
+ }
+
+ break;
+
+ default:
+
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+ break;
+
+ }
+
+
+}
+
+
+VOID
+NbfStopControlChannel(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN USHORT ChannelIdentifier
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when an MJ_CLEANUP IRP is received
+ on a control channel. It walks the device context's list of
+ pending action requests and cancels those associated with
+ this channel (as identified by ChannelIdentifier.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ ChannelIdentifier - The identifier for this open of the control
+ channel, which is stored in Request->FrameContext for requests
+ made on this channel.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ KIRQL oldirql, cancelirql;
+ PTP_REQUEST Request;
+ PLIST_ENTRY p;
+ UINT i;
+ BOOLEAN FoundRequest;
+ PLIST_ENTRY QueueHead, QueueEnd;
+
+
+ //
+ // Scan both queues, looking for requests. Since the list
+ // may change, we scan until we find one, then remove it
+ // and complete it. We then start scanning at the beginning
+ // again. We continue until we find none on the queue that
+ // belong to this control channel.
+ //
+ // The outer loop only runs twice; the first time it
+ // processes QueryIndicationQueue, the second time
+ // DatagramIndicationQueue.
+ //
+
+ for (i = 0; i < 2; i++) {
+
+ do {
+
+ //
+ // Loop until we do not find a request on this
+ // pass through the queue.
+ //
+
+ FoundRequest = FALSE;
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ if (i == 0) {
+ QueueHead = DeviceContext->QueryIndicationQueue.Flink;
+ QueueEnd = &DeviceContext->QueryIndicationQueue;
+ } else {
+ QueueHead = DeviceContext->DatagramIndicationQueue.Flink;
+ QueueEnd = &DeviceContext->DatagramIndicationQueue;
+ }
+
+
+ //
+ // Scan the appropriate queue for a request on this
+ // channel.
+ //
+
+ for (p = QueueHead; p != QueueEnd; p = p->Flink) {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ if (Request->FrameContext == ChannelIdentifier) {
+
+ //
+ // Found it, remove it from the list here.
+ //
+
+ IoSetCancelRoutine(Request->IoRequestPacket, NULL);
+ RemoveEntryList (p);
+
+ FoundRequest = TRUE;
+ break;
+
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ //
+ // If we found a request, then complete it and loop
+ // back to the top of the while loop to rescan the
+ // list. If not, then we will exit the while loop
+ // now.
+ //
+
+ if (FoundRequest) {
+
+ NbfCompleteRequest (Request, STATUS_CANCELLED, 0);
+
+ }
+
+ } while (FoundRequest);
+
+ }
+
+}
+
+
+VOID
+NbfActionQueryIndication(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNBF_HDR_CONNECTIONLESS UiFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called after a UI frame of type NAME_QUERY,
+ ADD_NAME_QUERY, or ADD_GROUP_NAME_QUERY has been processed.
+ It checks if there is a QUERY.INDICATION IRP waiting to
+ be completed, and if so completes it.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ UiFrame - Pointer to the incoming frame. The first byte of
+ information is the first byte of the NetBIOS connectionless
+ header.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ KIRQL oldirql, cancelirql;
+ PTP_REQUEST Request;
+ PLIST_ENTRY p;
+ PMDL Mdl;
+ PACTION_QUERY_INDICATION ActionHeader;
+ PQUERY_INDICATION QueryIndication;
+
+
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ if (!IsListEmpty (&DeviceContext->QueryIndicationQueue)) {
+
+ p = RemoveHeadList (&DeviceContext->QueryIndicationQueue);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ IoSetCancelRoutine(Request->IoRequestPacket,NULL);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ Mdl = Request->Buffer2;
+ ActionHeader = (PACTION_QUERY_INDICATION)
+ (MmGetSystemAddressForMdl(Mdl));
+ QueryIndication = &ActionHeader->QueryIndication;
+
+ //
+ // Copy over data from frame (note that dest and source
+ // address are copied with one call).
+ //
+
+ QueryIndication->Command = UiFrame->Command;
+ RtlCopyMemory ((PUCHAR)(&QueryIndication->Data2), (PUCHAR)(&UiFrame->Data2Low), 2);
+ RtlCopyMemory ((PUCHAR)(QueryIndication->DestinationName),
+ (PUCHAR)(UiFrame->DestinationName),
+ 2 * NETBIOS_NAME_LENGTH);
+
+ NbfCompleteRequest (Request, STATUS_SUCCESS, sizeof(ACTION_QUERY_INDICATION));
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ }
+}
+
+
+VOID
+NbfActionDatagramIndication(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNBF_HDR_CONNECTIONLESS UiFrame,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called after a datagram frame has been
+ received. It checks if there is a DATAGRAM.INDICATION IRP
+ waiting to be completed, and if so completes it.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ UiFrame - Pointer to the incoming frame. The first byte of
+ information is the first byte of the NetBIOS connectionless
+ header.
+
+ Length - The length of the frame starting at UiFrame.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ KIRQL oldirql, cancelirql;
+ PTP_REQUEST Request;
+ PLIST_ENTRY p;
+ PACTION_DATAGRAM_INDICATION ActionHeader;
+ PDATAGRAM_INDICATION DatagramIndication;
+ ULONG CopyLength;
+ PMDL Mdl;
+ NTSTATUS Status;
+
+
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ if (!IsListEmpty (&DeviceContext->DatagramIndicationQueue)) {
+
+ p = RemoveHeadList (&DeviceContext->DatagramIndicationQueue);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ IoSetCancelRoutine(Request->IoRequestPacket, NULL);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ Mdl = Request->Buffer2;
+ ActionHeader = (PACTION_DATAGRAM_INDICATION)
+ (MmGetSystemAddressForMdl(Mdl));
+ DatagramIndication = &ActionHeader->DatagramIndication;
+
+ //
+ // Copy over data from frame (note that dest and source
+ // address are copied with one call).
+ //
+
+ RtlCopyMemory ((PUCHAR)(DatagramIndication->DestinationName),
+ (PUCHAR)(UiFrame->DestinationName),
+ 2 * NETBIOS_NAME_LENGTH);
+
+ if ((Length-sizeof(NBF_HDR_CONNECTIONLESS)) <=
+ (ULONG)DatagramIndication->DatagramBufferLength) {
+
+ CopyLength = Length - sizeof(NBF_HDR_CONNECTIONLESS);
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ CopyLength = DatagramIndication->DatagramBufferLength;
+ Status = STATUS_BUFFER_OVERFLOW;
+
+ }
+
+
+ RtlCopyMemory(
+ (PUCHAR)DatagramIndication->DatagramBuffer,
+ ((PUCHAR)UiFrame) + sizeof(NBF_HDR_CONNECTIONLESS),
+ CopyLength);
+ DatagramIndication->DatagramBufferLength = (USHORT)CopyLength;
+
+ NbfCompleteRequest (Request, Status, CopyLength +
+ FIELD_OFFSET (ACTION_DATAGRAM_INDICATION, DatagramIndication.DatagramBuffer[0]));
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ }
+}
+
diff --git a/private/ntos/tdi/nbf/address.c b/private/ntos/tdi/nbf/address.c
new file mode 100644
index 000000000..f5bda0cc7
--- /dev/null
+++ b/private/ntos/tdi/nbf/address.c
@@ -0,0 +1,3046 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ address.c
+
+Abstract:
+
+ This module contains code which implements the TP_ADDRESS object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport address objects.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#if DBG
+#define NbfDbgShowAddr(TNA)\
+ { \
+ if ((TNA) == NULL) { \
+ NbfPrint0("<NetBios broadcast>\n"); \
+ } else { \
+ NbfPrint6("%c %c %c %c %d (%c)\n", \
+ (TNA)->NetbiosName[0], \
+ (TNA)->NetbiosName[1], \
+ (TNA)->NetbiosName[4], \
+ (TNA)->NetbiosName[6], \
+ (TNA)->NetbiosName[15], \
+ (TNA)->NetbiosNameType + 'A'); \
+ } \
+ }
+#else
+#define NbfDbgShowAddr(TNA)
+#endif
+
+//
+// Map all generic accesses to the same one.
+//
+
+STATIC GENERIC_MAPPING AddressGenericMapping =
+ { READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL };
+
+
+VOID
+AddressTimeoutHandler(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is executed as a DPC at DISPATCH_LEVEL when the timeout
+ period for the ADD_NAME_QUERY/ADD_NAME_RECOGNIZED protocol expires.
+ The retry count in the Address object is decremented, and if it reaches 0,
+ the address is registered. If the retry count has not reached zero,
+ then the ADD NAME QUERY is retried.
+
+Arguments:
+
+ Dpc - Pointer to a system DPC object.
+
+ DeferredContext - Pointer to the TP_ADDRESS block representing the
+ address that is being registered.
+
+ SystemArgument1 - Not used.
+
+ SystemArgument2 - Not used.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PTP_ADDRESS_FILE addressFile;
+ PTP_ADDRESS address;
+ PDEVICE_CONTEXT DeviceContext;
+ PLIST_ENTRY p;
+ LARGE_INTEGER timeout;
+
+ Dpc, SystemArgument1, SystemArgument2; // prevent compiler warnings
+
+ ENTER_NBF;
+
+
+ address = (PTP_ADDRESS)DeferredContext;
+ DeviceContext = address->Provider;
+
+ //
+ // We are waiting for an ADD_NAME_RECOGNIZED indicating that there is a
+ // conflict. Decrement the retry count, and if it dropped to zero,
+ // then we've waited a sufficiently long time. If there was no conflict,
+ // complete all waiting file opens for the address.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&address->SpinLock);
+
+ if ((address->Flags & ADDRESS_FLAGS_QUICK_REREGISTER) != 0) {
+
+ BOOLEAN DuplicateName;
+ PTP_CONNECTION Connection;
+
+ DuplicateName = ((address->Flags & (ADDRESS_FLAGS_DUPLICATE_NAME|ADDRESS_FLAGS_CONFLICT)) != 0);
+
+ for (p=address->ConnectionDatabase.Flink;
+ p != &address->ConnectionDatabase;
+ p=p->Flink) {
+
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressList);
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) != 0) {
+ continue;
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&address->SpinLock);
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_W_ADDRESS) != 0) {
+
+ if (DuplicateName) {
+
+ NbfStopConnection (Connection, STATUS_DUPLICATE_NAME);
+
+ } else {
+
+ //
+ // Continue with the connection attempt.
+ //
+ ULONG NameQueryTimeout;
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_W_ADDRESS;
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ KeQueryTickCount (&Connection->ConnectStartTime);
+
+ NameQueryTimeout = Connection->Provider->NameQueryTimeout;
+ if (Connection->Provider->MacInfo.MediumAsync &&
+ !Connection->Provider->MediumSpeedAccurate) {
+ NameQueryTimeout = NAME_QUERY_TIMEOUT / 10;
+ }
+
+ NbfSendNameQuery (
+ Connection,
+ TRUE);
+
+ NbfStartConnectionTimer (
+ Connection,
+ ConnectionEstablishmentTimeout,
+ NameQueryTimeout);
+ }
+
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&address->SpinLock);
+
+ }
+
+ address->Flags &= ~ADDRESS_FLAGS_QUICK_REREGISTER;
+
+ RELEASE_DPC_SPIN_LOCK (&address->SpinLock);
+ NbfDereferenceAddress ("Timer, registered", address, AREF_TIMER);
+
+ } else if ((address->Flags & (ADDRESS_FLAGS_DUPLICATE_NAME|ADDRESS_FLAGS_CONFLICT)) != 0) {
+
+ PIRP irp;
+
+ //
+ // the address registration has failed. We signal the user in
+ // the normal way (by failing the open of the address). Now clean up
+ // the transport's data structures.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("AddressTimeoutHandler %lx: duplicate\n", address);
+ }
+
+ address->Flags &= ~ADDRESS_FLAGS_REGISTERING;
+// address->Flags |= ADDRESS_FLAGS_STOPPING;
+
+ //
+ // BUGBUG: This is probably all overkill, the
+ // uframes handler will already have called
+ // NbfStopAddress, which will tear off all
+ // the address files etc., and set the
+ // STOPPING flag which prevents further opens.
+ //
+
+ p = address->AddressFileDatabase.Flink;
+ while (p != &address->AddressFileDatabase) {
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+ p = p->Flink;
+
+ if (addressFile->Irp != NULL) {
+ irp = addressFile->Irp;
+ addressFile->Irp = NULL;
+ RELEASE_DPC_SPIN_LOCK (&address->SpinLock);
+ irp->IoStatus.Information = 0;
+ irp->IoStatus.Status = STATUS_DUPLICATE_NAME;
+ LEAVE_NBF;
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+ ENTER_NBF;
+
+ NbfStopAddressFile (addressFile, address);
+
+ ACQUIRE_DPC_SPIN_LOCK (&address->SpinLock);
+ }
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&address->SpinLock);
+
+ //
+ // There will be no more timer events happening, so we dereference the
+ // address to account for the timer.
+ //
+
+ NbfStopAddress (address);
+ NbfDereferenceAddress ("Timer, dup address", address, AREF_TIMER);
+
+ } else {
+
+ //
+ // has the address registration succeeded?
+ //
+
+ if (--(address->Retries) <= 0) { // if retry count exhausted.
+ PIRP irp;
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("AddressTimeoutHandler %lx: successful.\n", address);
+ }
+
+ address->Flags &= ~ADDRESS_FLAGS_REGISTERING;
+
+ p = address->AddressFileDatabase.Flink;
+
+ while (p != &address->AddressFileDatabase) {
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+ p = p->Flink;
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint3 ("AddressTimeoutHandler %lx: Completing IRP %lx for file %lx\n",
+ address,
+ addressFile->Irp,
+ addressFile);
+ }
+
+ if (addressFile->Irp != NULL) {
+ irp = addressFile->Irp;
+ addressFile->Irp = NULL;
+ addressFile->State = ADDRESSFILE_STATE_OPEN;
+ RELEASE_DPC_SPIN_LOCK (&address->SpinLock);
+ irp->IoStatus.Information = 0;
+ irp->IoStatus.Status = STATUS_SUCCESS;
+
+ LEAVE_NBF;
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+ ENTER_NBF;
+
+ ACQUIRE_DPC_SPIN_LOCK (&address->SpinLock);
+ }
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&address->SpinLock);
+
+ //
+ // Dereference the address if we're all done.
+ //
+
+ NbfDereferenceAddress ("Timer, registered", address, AREF_TIMER);
+
+ } else {
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2 ("AddressTimeoutHandler %lx: step %x.\n",
+ address,
+ DeviceContext->AddNameQueryRetries - address->Retries);
+ }
+
+ //
+ // restart the timer if we haven't yet completed registration
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&address->SpinLock);
+
+ timeout.LowPart = (ULONG)(-(LONG)DeviceContext->AddNameQueryTimeout);
+ timeout.HighPart = -1;
+ KeSetTimer (&address->Timer,*(PTIME)&timeout, &address->Dpc);
+ (VOID)NbfSendAddNameQuery (address); // send another ADD_NAME_QUERY.
+ }
+
+ }
+
+ LEAVE_NBF;
+ return;
+
+} /* AddressTimeoutHandler */
+
+
+TDI_ADDRESS_NETBIOS UNALIGNED *
+NbfParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN BOOLEAN BroadcastAddressOk
+)
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, looking for an address
+ of type TDI_ADDRESS_TYPE_NETBIOS.
+
+Arguments:
+
+ Transport - The generic TDI address.
+
+ BroadcastAddressOk - TRUE if we should return the broadcast
+ address if found. If so, a value of (PVOID)-1 indicates
+ the broadcast address.
+
+Return Value:
+
+ A pointer to the Netbios address, or NULL if none is found,
+ or (PVOID)-1 if the broadcast address is found.
+
+--*/
+
+{
+ TA_ADDRESS UNALIGNED * addressName;
+ INT i;
+
+ addressName = &TransportAddress->Address[0];
+
+ //
+ // The name can be passed with multiple entries; we'll take and use only
+ // the Netbios one.
+ //
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++) {
+ if (addressName->AddressType == TDI_ADDRESS_TYPE_NETBIOS) {
+ if ((addressName->AddressLength == 0) &&
+ BroadcastAddressOk) {
+ return (PVOID)-1;
+ } else if (addressName->AddressLength ==
+ sizeof(TDI_ADDRESS_NETBIOS)) {
+ return((TDI_ADDRESS_NETBIOS UNALIGNED *)(addressName->Address));
+ }
+ }
+
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+ return NULL;
+
+} /* NbfParseTdiAddress */
+
+
+BOOLEAN
+NbfValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength
+)
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, verifying that the
+ components of the address do not extend past the specified
+ length.
+
+Arguments:
+
+ TransportAddress - The generic TDI address.
+
+ TransportAddressLength - The specific length of TransportAddress.
+
+Return Value:
+
+ TRUE if the address is valid, FALSE otherwise.
+
+--*/
+
+{
+ PUCHAR AddressEnd = ((PUCHAR)TransportAddress) + TransportAddressLength;
+ TA_ADDRESS UNALIGNED * addressName;
+ INT i;
+
+ if (TransportAddressLength < sizeof(TransportAddress->TAAddressCount)) {
+ NbfPrint0 ("NbfValidateTdiAddress: runt address\n");
+ return FALSE;
+ }
+
+ addressName = &TransportAddress->Address[0];
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++) {
+ if (addressName->Address > AddressEnd) {
+ NbfPrint0 ("NbfValidateTdiAddress: address too short\n");
+ return FALSE;
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+
+ if ((PUCHAR)addressName > AddressEnd) {
+ NbfPrint0 ("NbfValidateTdiAddress: address too short\n");
+ return FALSE;
+ }
+ return TRUE;
+
+} /* NbfValidateTdiAddress */
+
+
+NTSTATUS
+NbfOpenAddress(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens a file that points to an existing address object, or, if
+ the object doesn't exist, creates it (note that creation of the address
+ object includes registering the address, and may take many seconds to
+ complete, depending upon system configuration).
+
+ If the address already exists, and it has an ACL associated with it, the
+ ACL is checked for access rights before allowing creation of the address.
+
+Arguments:
+
+ DeviceObject - pointer to the device object describing the NBF transport.
+
+ Irp - a pointer to the Irp used for the creation of the address.
+
+ IrpSp - a pointer to the Irp stack location.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ NTSTATUS status;
+ PTP_ADDRESS address;
+ PTP_ADDRESS_FILE addressFile;
+ PNBF_NETBIOS_ADDRESS networkName; // Network name string.
+ PFILE_FULL_EA_INFORMATION ea;
+ TRANSPORT_ADDRESS UNALIGNED *name;
+ TDI_ADDRESS_NETBIOS UNALIGNED *netbiosName;
+ ULONG DesiredShareAccess;
+ KIRQL oldirql;
+ PACCESS_STATE AccessState;
+ ACCESS_MASK GrantedAccess;
+ BOOLEAN AccessAllowed;
+ BOOLEAN QuickAdd = FALSE;
+
+ DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+
+ //
+ // The network name is in the EA, passed in AssociatedIrp.SystemBuffer
+ //
+
+ ea = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+ if (ea == NULL) {
+ NbfPrint1("OpenAddress: IRP %lx has no EA\n", Irp);
+ return STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+ //
+ // this may be a valid name; parse the name from the EA and use it if OK.
+ //
+
+ name = (TRANSPORT_ADDRESS UNALIGNED *)&ea->EaName[ea->EaNameLength+1];
+
+ if (!NbfValidateTdiAddress(name, ea->EaValueLength)) {
+ return STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+ //
+ // The name can have with multiple entries; we'll use the Netbios one.
+ // This call returns NULL if not Netbios address is found, (PVOID)-1
+ // if it is the broadcast address, and a pointer to a Netbios
+ // address otherwise.
+ //
+
+ netbiosName = NbfParseTdiAddress(name, TRUE);
+
+ if (netbiosName != NULL) {
+ if (netbiosName != (PVOID)-1) {
+ networkName = (PNBF_NETBIOS_ADDRESS)ExAllocatePoolWithTag (
+ NonPagedPool,
+ sizeof (NBF_NETBIOS_ADDRESS),
+ 'nFBN');
+ if (networkName == NULL) {
+ PANIC ("NbfOpenAddress: PANIC! could not allocate networkName!\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 1,
+ sizeof(TA_NETBIOS_ADDRESS),
+ ADDRESS_RESOURCE_ID);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // get the name to local storage
+ //
+
+ if ((netbiosName->NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_GROUP) ||
+ (netbiosName->NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_QUICK_GROUP)) {
+ networkName->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_GROUP;
+ } else {
+ networkName->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ }
+ RtlCopyMemory (networkName->NetbiosName, netbiosName->NetbiosName, 16);
+
+ if ((netbiosName->NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_QUICK_UNIQUE) ||
+ (netbiosName->NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_QUICK_GROUP)) {
+ QuickAdd = TRUE;
+ }
+ } else {
+ networkName = NULL;
+ }
+
+ } else {
+ NbfPrint1("OpenAddress: IRP %lx has no NETBIOS address\n", Irp);
+ return STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("OpenAddress %s: ",
+ ((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ "shared" : "exclusive");
+ NbfDbgShowAddr (networkName);
+ }
+
+ //
+ // get an address file structure to represent this address.
+ //
+
+ status = NbfCreateAddressFile (DeviceContext, &addressFile);
+
+ if (!NT_SUCCESS (status)) {
+ if (networkName != NULL) {
+ ExFreePool (networkName);
+ }
+ return status;
+ }
+
+ //
+ // See if this address is already established. This call automatically
+ // increments the reference count on the address so that it won't disappear
+ // from underneath us after this call but before we have a chance to use it.
+ //
+ // To ensure that we don't create two address objects for the
+ // same address, we hold the device context AddressResource until
+ // we have found the address or created a new one.
+ //
+
+ ExAcquireResourceExclusive (&DeviceContext->AddressResource, TRUE);
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ address = NbfLookupAddress (DeviceContext, networkName);
+
+ if (address == NULL) {
+
+ //
+ // This address doesn't exist. Create it, and start the process of
+ // registering it.
+ //
+
+ status = NbfCreateAddress (
+ DeviceContext,
+ networkName,
+ &address);
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ if (NT_SUCCESS (status)) {
+
+ //
+ // Initialize the shared access now. We use read access
+ // to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ IoSetShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &address->u.ShareAccess);
+
+
+ //
+ // Assign the security descriptor (need to do this with
+ // the spinlock released because the descriptor is not
+ // mapped. BUGBUG: Need to synchronize Assign and Access).
+ //
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ status = SeAssignSecurity(
+ NULL, // parent descriptor
+ AccessState->SecurityDescriptor,
+ &address->SecurityDescriptor,
+ FALSE, // is directory
+ &AccessState->SubjectSecurityContext,
+ &AddressGenericMapping,
+ PagedPool);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint3 ("Assign security A %lx AF %lx, status %lx\n",
+ address,
+ addressFile,
+ status);
+ }
+
+ if (!NT_SUCCESS(status)) {
+
+ //
+ // Error, return status.
+ //
+
+ IoRemoveShareAccess (IrpSp->FileObject, &address->u.ShareAccess);
+ ExReleaseResource (&DeviceContext->AddressResource);
+ NbfDereferenceAddress ("Device context stopping", address, AREF_TEMP_CREATE);
+ NbfDereferenceAddressFile (addressFile);
+ return status;
+
+ }
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ //
+ // if the adapter isn't ready, we can't do any of this; get out
+ //
+
+ if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint3("OpenAddress A %lx AF %lx: DeviceContext %lx not open\n",
+ address,
+ addressFile,
+ DeviceContext);
+ }
+ NbfDereferenceAddressFile (addressFile);
+ status = STATUS_DEVICE_NOT_READY;
+
+ } else {
+
+ IrpSp->FileObject->FsContext = (PVOID)addressFile;
+ IrpSp->FileObject->FsContext2 =
+ (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+ addressFile->FileObject = IrpSp->FileObject;
+ addressFile->Irp = Irp;
+ addressFile->Address = address;
+
+ NbfReferenceAddress("Opened new", address, AREF_OPEN);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2("OpenAddress A %lx AF %lx: created.\n",
+ address,
+ addressFile);
+ }
+
+ ExInterlockedInsertTailList(
+ &address->AddressFileDatabase,
+ &addressFile->Linkage,
+ &address->SpinLock);
+
+
+ //
+ // Begin address registration unless this is the broadcast
+ // address (which is a "fake" address with no corresponding
+ // Netbios address) or the reserved address, which we know
+ // is unique since it is based on the adapter address.
+ //
+ // Also, for "quick" add names, do not register.
+ //
+
+ if ((networkName != NULL) &&
+ (!RtlEqualMemory (networkName->NetbiosName,
+ DeviceContext->ReservedNetBIOSAddress,
+ NETBIOS_NAME_LENGTH)) &&
+ (!QuickAdd)) {
+
+ NbfRegisterAddress (address); // begin address registration.
+ status = STATUS_PENDING;
+
+ } else {
+
+ address->Flags &= ~ADDRESS_FLAGS_NEEDS_REG;
+ addressFile->Irp = NULL;
+ addressFile->State = ADDRESSFILE_STATE_OPEN;
+ status = STATUS_SUCCESS;
+
+ }
+
+ }
+
+ NbfDereferenceAddress("temp create", address, AREF_TEMP_CREATE);
+
+ } else {
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ //
+ // If the address could not be created, and is not in the process of
+ // being created, then we can't open up an address.
+ //
+
+ if (networkName != NULL) {
+ ExFreePool (networkName);
+ }
+
+ NbfDereferenceAddressFile (addressFile);
+
+ }
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ //
+ // The address already exists. Check the ACL and see if we
+ // can access it. If so, simply use this address as our address.
+ //
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ AccessAllowed = SeAccessCheck(
+ address->SecurityDescriptor,
+ &AccessState->SubjectSecurityContext,
+ FALSE, // tokens locked
+ IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
+ (ACCESS_MASK)0, // previously granted
+ NULL, // privileges
+ &AddressGenericMapping,
+ Irp->RequestorMode,
+ &GrantedAccess,
+ &status);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint4 ("Access check A %lx AF %lx, %s (%lx)\n",
+ address,
+ addressFile,
+ AccessAllowed ? "allowed" : "not allowed",
+ status);
+ }
+
+ if (AccessAllowed) {
+
+ //
+ // Access was successful, make sure Status is right.
+ //
+
+ status = STATUS_SUCCESS;
+
+ //
+ // BUGBUG: Compare DesiredAccess to GrantedAccess?
+ //
+
+
+ //
+ // Check that the name is of the correct type (unique vs. group)
+ // We don't need to check this for the broadcast address.
+ //
+ // BUGBUG: This code is structured funny, the only reason
+ // this is inside this if is to avoid indenting too much.
+ //
+
+ if (networkName != NULL) {
+ if (address->NetworkName->NetbiosNameType !=
+ networkName->NetbiosNameType) {
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2 ("Address types differ: old %c, new %c\n",
+ address->NetworkName->NetbiosNameType + 'A',
+ networkName->NetbiosNameType + 'A');
+ }
+
+ status = STATUS_DUPLICATE_NAME;
+
+ }
+ }
+
+ }
+
+
+ if (!NT_SUCCESS (status)) {
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2("OpenAddress A %lx AF %lx: ACL bad.\n",
+ address,
+ addressFile);
+ }
+
+ NbfDereferenceAddressFile (addressFile);
+
+ } else {
+
+ //
+ // Now check that we can obtain the desired share
+ // access. We use read access to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ status = IoCheckShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &address->u.ShareAccess,
+ TRUE);
+
+ if (!NT_SUCCESS (status)) {
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2("OpenAddress A %lx AF %lx: ShareAccess problem.\n",
+ address,
+ addressFile);
+ }
+
+ NbfDereferenceAddressFile (addressFile);
+
+ } else {
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock, &oldirql);
+
+ //
+ // now, if the address registered, we simply return success after
+ // pointing the file object at the address file (which points to
+ // the address). If the address registration is pending, we mark
+ // the registration pending and let the registration completion
+ // routine complete the open. If the address is bad, we simply
+ // fail the open.
+ //
+
+ if ((address->Flags &
+ (ADDRESS_FLAGS_CONFLICT |
+ ADDRESS_FLAGS_REGISTERING |
+ ADDRESS_FLAGS_DEREGISTERING |
+ ADDRESS_FLAGS_DUPLICATE_NAME |
+ ADDRESS_FLAGS_NEEDS_REG |
+ ADDRESS_FLAGS_STOPPING |
+ ADDRESS_FLAGS_BAD_ADDRESS |
+ ADDRESS_FLAGS_CLOSED)) == 0) {
+
+ InsertTailList (
+ &address->AddressFileDatabase,
+ &addressFile->Linkage);
+
+ addressFile->Irp = NULL;
+ addressFile->Address = address;
+ addressFile->FileObject = IrpSp->FileObject;
+ addressFile->State = ADDRESSFILE_STATE_OPEN;
+
+ NbfReferenceAddress("open ready", address, AREF_OPEN);
+
+ IrpSp->FileObject->FsContext = (PVOID)addressFile;
+ IrpSp->FileObject->FsContext2 =
+ (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2("OpenAddress A %lx AF %lx: address ready.\n",
+ address,
+ addressFile);
+ }
+
+ status = STATUS_SUCCESS;
+
+ } else {
+
+ //
+ // if the address is still registering, make the open pending.
+ //
+
+ if ((address->Flags & (ADDRESS_FLAGS_REGISTERING | ADDRESS_FLAGS_NEEDS_REG)) != 0) {
+
+ InsertTailList (
+ &address->AddressFileDatabase,
+ &addressFile->Linkage);
+
+ addressFile->Irp = Irp;
+ addressFile->Address = address;
+ addressFile->FileObject = IrpSp->FileObject;
+
+ NbfReferenceAddress("open registering", address, AREF_OPEN);
+
+ IrpSp->FileObject->FsContext = (PVOID)addressFile;
+ IrpSp->FileObject->FsContext2 =
+ (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2("OpenAddress A %lx AF %lx: address registering.\n",
+ address,
+ addressFile);
+ }
+
+ status = STATUS_PENDING;
+
+ } else {
+
+ if ((address->Flags & ADDRESS_FLAGS_CONFLICT) != 0) {
+ status = STATUS_DUPLICATE_NAME;
+ } else {
+ status = STATUS_DRIVER_INTERNAL_ERROR;
+ }
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint3("OpenAddress A %lx AF %lx: address flags %lx.\n",
+ address,
+ addressFile,
+ address->Flags);
+ }
+
+ NbfDereferenceAddressFile (addressFile);
+
+ }
+ }
+ }
+ }
+
+
+ //
+ // This isn't needed since it was not used in the
+ // creation of the address.
+ //
+
+ if (networkName != NULL) {
+ ExFreePool (networkName);
+ }
+
+ //
+ // Remove the reference from NbfLookupAddress.
+ //
+
+ NbfDereferenceAddress ("Done opening", address, AREF_LOOKUP);
+ }
+
+ return status;
+} /* NbfOpenAddress */
+
+
+VOID
+NbfAllocateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS *TransportAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for a transport address. Some minimal
+ initialization is done on the address.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ Address - Pointer to a place where this routine will return a pointer
+ to a transport address structure. Returns NULL if no storage
+ can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PTP_ADDRESS Address;
+ PSEND_PACKET_TAG SendTag;
+ NDIS_STATUS NdisStatus;
+ PNDIS_PACKET NdisPacket;
+ PNDIS_BUFFER NdisBuffer;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + sizeof(TP_ADDRESS)) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("NBF: Could not allocate address: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 101,
+ sizeof(TP_ADDRESS),
+ ADDRESS_RESOURCE_ID);
+ *TransportAddress = NULL;
+ return;
+ }
+
+ Address = (PTP_ADDRESS)ExAllocatePoolWithTag (
+ NonPagedPool,
+ sizeof (TP_ADDRESS),
+ 'aFBN');
+ if (Address == NULL) {
+ PANIC("NBF: Could not allocate address: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 201,
+ sizeof(TP_ADDRESS),
+ ADDRESS_RESOURCE_ID);
+ *TransportAddress = NULL;
+ return;
+ }
+ RtlZeroMemory (Address, sizeof(TP_ADDRESS));
+
+ NdisAllocatePacketPool(
+ &NdisStatus,
+ &Address->UIFramePoolHandle,
+ 1,
+ sizeof(SEND_PACKET_TAG));
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ PANIC("NBF: Could not allocate address UI frame pool: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 311,
+ sizeof(SEND_PACKET_TAG),
+ ADDRESS_RESOURCE_ID);
+ ExFreePool (Address);
+ *TransportAddress = NULL;
+ return;
+ }
+
+
+ //
+ // This code is similar to NbfAllocateUIFrame.
+ //
+
+ Address->UIFrame = (PTP_UI_FRAME) ExAllocatePoolWithTag (
+ NonPagedPool,
+ DeviceContext->UIFrameLength,
+ 'uFBN');
+ if (Address->UIFrame == NULL) {
+ PANIC("NBF: Could not allocate address UI frame: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 411,
+ DeviceContext->UIFrameLength,
+ ADDRESS_RESOURCE_ID);
+ NdisFreePacketPool (Address->UIFramePoolHandle);
+ ExFreePool (Address);
+ *TransportAddress = NULL;
+ return;
+ }
+ RtlZeroMemory (Address->UIFrame, DeviceContext->UIFrameLength);
+
+
+ NdisAllocatePacket (
+ &NdisStatus,
+ &NdisPacket,
+ Address->UIFramePoolHandle);
+
+ ASSERT (NdisStatus == NDIS_STATUS_SUCCESS);
+
+ Address->UIFrame->NdisPacket = NdisPacket;
+ Address->UIFrame->DataBuffer = NULL;
+ SendTag = (PSEND_PACKET_TAG)NdisPacket->ProtocolReserved;
+ SendTag->Type = TYPE_ADDRESS_FRAME;
+ SendTag->Owner = (PVOID)Address;
+ SendTag->Frame = Address->UIFrame;
+
+ //
+ // Make the packet header known to the packet descriptor
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ DeviceContext->NdisBufferPool,
+ Address->UIFrame->Header,
+ DeviceContext->UIFrameHeaderLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ PANIC("NBF: Could not allocate address UI frame buffer: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 511,
+ 0,
+ UI_FRAME_RESOURCE_ID);
+ ExFreePool (Address->UIFrame);
+ NdisFreePacketPool (Address->UIFramePoolHandle);
+ ExFreePool (Address);
+ *TransportAddress = NULL;
+ return;
+ }
+
+ NdisChainBufferAtFront (NdisPacket, NdisBuffer);
+
+ DeviceContext->MemoryUsage +=
+ sizeof(TP_ADDRESS) +
+ sizeof(NDIS_PACKET) + sizeof(SEND_PACKET_TAG) +
+ DeviceContext->UIFrameLength;
+ ++DeviceContext->AddressAllocated;
+
+ Address->Type = NBF_ADDRESS_SIGNATURE;
+ Address->Size = sizeof (TP_ADDRESS);
+
+ Address->Provider = DeviceContext;
+ KeInitializeSpinLock (&Address->SpinLock);
+// KeInitializeSpinLock (&Address->Interlock);
+
+ InitializeListHead (&Address->ConnectionDatabase);
+ InitializeListHead (&Address->AddressFileDatabase);
+ InitializeListHead (&Address->SendDatagramQueue);
+
+ KeInitializeDpc (&Address->Dpc, AddressTimeoutHandler, (PVOID)Address);
+ KeInitializeTimer (&Address->Timer);
+
+ //
+ // For each address, allocate a receive packet and a receive buffer.
+ //
+
+ NbfAddReceivePacket (DeviceContext);
+ NbfAddReceiveBuffer (DeviceContext);
+
+ *TransportAddress = Address;
+
+} /* NbfAllocateAddress */
+
+
+VOID
+NbfDeallocateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS TransportAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for a transport address.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ Address - Pointer to a transport address structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_BUFFER NdisBuffer;
+
+ NdisUnchainBufferAtFront (TransportAddress->UIFrame->NdisPacket, &NdisBuffer);
+ if (NdisBuffer != NULL) {
+ NdisFreeBuffer (NdisBuffer);
+ }
+ ExFreePool (TransportAddress->UIFrame);
+ NdisFreePacketPool (TransportAddress->UIFramePoolHandle);
+
+ ExFreePool (TransportAddress);
+ --DeviceContext->AddressAllocated;
+
+ DeviceContext->MemoryUsage -=
+ sizeof(TP_ADDRESS) +
+ sizeof(NDIS_PACKET) + sizeof(SEND_PACKET_TAG) +
+ DeviceContext->UIFrameLength;
+
+ //
+ // Remove the resources which allocating this caused.
+ //
+
+ NbfRemoveReceivePacket (DeviceContext);
+ NbfRemoveReceiveBuffer (DeviceContext);
+
+} /* NbfDeallocateAddress */
+
+
+NTSTATUS
+NbfCreateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNBF_NETBIOS_ADDRESS NetworkName,
+ OUT PTP_ADDRESS *Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a transport address and associates it with
+ the specified transport device context. The reference count in the
+ address is automatically set to 1, and the reference count of the
+ device context is incremented.
+
+ NOTE: This routine must be called with the DeviceContext
+ spinlock held.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ NetworkName - Pointer to an NBF_NETBIOS_ADDRESS type containing the network
+ name to be associated with this address, if any.
+ NOTE: This has only the basic NetbiosNameType values, not the
+ QUICK_ ones.
+
+ Address - Pointer to a place where this routine will return a pointer
+ to a transport address structure.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_ADDRESS pAddress;
+ PLIST_ENTRY p;
+
+
+ p = RemoveHeadList (&DeviceContext->AddressPool);
+ if (p == &DeviceContext->AddressPool) {
+
+ if ((DeviceContext->AddressMaxAllocated == 0) ||
+ (DeviceContext->AddressAllocated < DeviceContext->AddressMaxAllocated)) {
+
+ NbfAllocateAddress (DeviceContext, &pAddress);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Allocated address at %lx\n", pAddress);
+ }
+
+ } else {
+
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 401,
+ sizeof(TP_ADDRESS),
+ ADDRESS_RESOURCE_ID);
+ pAddress = NULL;
+
+ }
+
+ if (pAddress == NULL) {
+ ++DeviceContext->AddressExhausted;
+ PANIC ("NbfCreateAddress: Could not allocate address object!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ } else {
+
+ pAddress = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+
+ }
+
+ ++DeviceContext->AddressInUse;
+ if (DeviceContext->AddressInUse > DeviceContext->AddressMaxInUse) {
+ ++DeviceContext->AddressMaxInUse;
+ }
+
+ DeviceContext->AddressTotal += DeviceContext->AddressInUse;
+ ++DeviceContext->AddressSamples;
+
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS | NBF_DEBUG_UFRAMES) {
+ NbfPrint1 ("NbfCreateAddress %lx: ", pAddress);
+ NbfDbgShowAddr (NetworkName);
+ }
+
+ //
+ // Initialize all of the static data for this address.
+ //
+
+ pAddress->ReferenceCount = 1;
+
+#if DBG
+ {
+ UINT Counter;
+ for (Counter = 0; Counter < NUMBER_OF_AREFS; Counter++) {
+ pAddress->RefTypes[Counter] = 0;
+ }
+
+ // This reference is removed by the caller.
+
+ pAddress->RefTypes[AREF_TEMP_CREATE] = 1;
+ }
+#endif
+
+ pAddress->Flags = ADDRESS_FLAGS_NEEDS_REG;
+ InitializeListHead (&pAddress->AddressFileDatabase);
+
+ pAddress->NetworkName = NetworkName;
+ if ((NetworkName != (PNBF_NETBIOS_ADDRESS)NULL) &&
+ (NetworkName->NetbiosNameType ==
+ TDI_ADDRESS_NETBIOS_TYPE_GROUP)) {
+
+ pAddress->Flags |= ADDRESS_FLAGS_GROUP;
+
+ }
+
+ if (NetworkName != (PNBF_NETBIOS_ADDRESS)NULL) {
+ ++DeviceContext->AddressCounts[NetworkName->NetbiosName[0]];
+ }
+
+ //
+ // Now link this address into the specified device context's
+ // address database. To do this, we need to acquire the spin lock
+ // on the device context.
+ //
+
+ InsertTailList (&DeviceContext->AddressDatabase, &pAddress->Linkage);
+ pAddress->Provider = DeviceContext;
+ NbfReferenceDeviceContext ("Create Address", DeviceContext, DCREF_ADDRESS); // count refs to the device context.
+
+ *Address = pAddress; // return the address.
+ return STATUS_SUCCESS; // not finished yet.
+} /* NbfCreateAddress */
+
+
+VOID
+NbfRegisterAddress(
+ PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the registration process of the transport address
+ specified, if it has not already been started.
+
+Arguments:
+
+ Address - Pointer to a transport address object to begin registering
+ on the network.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ LARGE_INTEGER Timeout;
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ if (!(Address->Flags & ADDRESS_FLAGS_NEEDS_REG)) {
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfRegisterAddress %lx: NEEDS_REG 0.\n", Address);
+ }
+
+ return;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfRegisterAddress %lx: registering.\n", Address);
+ }
+
+
+ Address->Flags &= ~ADDRESS_FLAGS_NEEDS_REG;
+ Address->Flags |= ADDRESS_FLAGS_REGISTERING;
+
+ RtlZeroMemory (Address->UniqueResponseAddress, 6);
+
+ //
+ // Keep a reference on this address until the registration process
+ // completes or is aborted. It will be aborted in UFRAMES.C, in
+ // either the NAME_IN_CONFLICT or ADD_NAME_RESPONSE frame handlers.
+ //
+
+ NbfReferenceAddress ("start registration", Address, AREF_TIMER);
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ //
+ // Now start registration process by starting up a retransmission timer
+ // and begin sending ADD_NAME_QUERY NetBIOS frames.
+ //
+ // On an async line that is disconnected, we only send one packet
+ // with a short timeout.
+ //
+
+ if (Address->Provider->MacInfo.MediumAsync && !Address->Provider->MediumSpeedAccurate) {
+ Address->Retries = 1;
+ Timeout.LowPart = (ULONG)(-(ADD_NAME_QUERY_TIMEOUT / 10));
+ } else {
+ Address->Retries = Address->Provider->AddNameQueryRetries;
+ Timeout.LowPart = (ULONG)(-(LONG)Address->Provider->AddNameQueryTimeout);
+ }
+ Timeout.HighPart = -1;
+ KeSetTimer (&Address->Timer, *(PTIME)&Timeout, &Address->Dpc);
+
+ (VOID)NbfSendAddNameQuery (Address); // send first ADD_NAME_QUERY.
+} /* NbfRegisterAddress */
+
+
+NTSTATUS
+NbfVerifyAddressObject (
+ IN PTP_ADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to verify that the pointer given us in a file
+ object is in fact a valid address file object. We also verify that the
+ address object pointed to by it is a valid address object, and reference
+ it to keep it from disappearing while we use it.
+
+Arguments:
+
+ AddressFile - potential pointer to a TP_ADDRESS_FILE object
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_ADDRESS otherwise
+
+--*/
+
+{
+ KIRQL oldirql;
+ NTSTATUS status = STATUS_SUCCESS;
+ PTP_ADDRESS address;
+
+ //
+ // try to verify the address file signature. If the signature is valid,
+ // verify the address pointed to by it and get the address spinlock.
+ // check the address's state, and increment the reference count if it's
+ // ok to use it. Note that the only time we return an error for state is
+ // if the address is closing.
+ //
+
+ try {
+
+ if ((AddressFile != (PTP_ADDRESS_FILE)NULL) &&
+ (AddressFile->Size == sizeof (TP_ADDRESS_FILE)) &&
+ (AddressFile->Type == NBF_ADDRESSFILE_SIGNATURE) ) {
+// (AddressFile->State != ADDRESSFILE_STATE_CLOSING) ) {
+
+ address = AddressFile->Address;
+
+ if ((address != (PTP_ADDRESS)NULL) &&
+ (address->Size == sizeof (TP_ADDRESS)) &&
+ (address->Type == NBF_ADDRESS_SIGNATURE) ) {
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock, &oldirql);
+
+ if ((address->Flags & ADDRESS_FLAGS_STOPPING) == 0) {
+
+ NbfReferenceAddress ("verify", address, AREF_VERIFY);
+
+ } else {
+
+ NbfPrint1("NbfVerifyAddress: A %lx closing\n", address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ } else {
+
+ NbfPrint1("NbfVerifyAddress: A %lx bad signature\n", address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } else {
+
+ NbfPrint1("NbfVerifyAddress: AF %lx bad signature\n", AddressFile);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ NbfPrint1("NbfVerifyAddress: AF %lx exception\n", address);
+ return GetExceptionCode();
+ }
+
+ return status;
+
+}
+
+VOID
+NbfDestroyAddress(
+ IN PVOID Parameter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a transport address and removes all references
+ made by it to other objects in the transport. The address structure
+ is returned to nonpaged system pool or our lookaside list. It is assumed
+ that the caller has already removed all addressfile structures associated
+ with this address.
+
+ The routine is called from a worker thread so that the security
+ descriptor can be accessed.
+
+ This worked thread is only queued by NbfDerefAddress. The reason
+ for this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ Address - Pointer to a transport address structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_ADDRESS Address = (PTP_ADDRESS)Parameter;
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfDestroyAddress %lx:.\n", Address);
+ }
+
+ DeviceContext = Address->Provider;
+
+ SeDeassignSecurity (&Address->SecurityDescriptor);
+
+ //
+ // Delink this address from its associated device context's address
+ // database. To do this we must spin lock on the device context object,
+ // not on the address.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ if (Address->NetworkName) {
+ --DeviceContext->AddressCounts[Address->NetworkName->NetbiosName[0]];
+ }
+
+ RemoveEntryList (&Address->Linkage);
+
+ if (Address->NetworkName != NULL) {
+ ExFreePool (Address->NetworkName);
+ Address->NetworkName = NULL;
+ }
+
+ //
+ // Now we can deallocate the transport address object.
+ //
+
+ DeviceContext->AddressTotal += DeviceContext->AddressInUse;
+ ++DeviceContext->AddressSamples;
+ --DeviceContext->AddressInUse;
+
+ if ((DeviceContext->AddressAllocated - DeviceContext->AddressInUse) >
+ DeviceContext->AddressInitAllocated) {
+ NbfDeallocateAddress (DeviceContext, Address);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Deallocated address at %lx\n", Address);
+ }
+ } else {
+ InsertTailList (&DeviceContext->AddressPool, &Address->Linkage);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ NbfDereferenceDeviceContext ("Destroy Address", DeviceContext, DCREF_ADDRESS); // just housekeeping.
+
+} /* NbfDestroyAddress */
+
+
+#if DBG
+VOID
+NbfRefAddress(
+ IN PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ ASSERT (Address->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement (&Address->ReferenceCount);
+
+} /* NbfRefAddress */
+#endif
+
+
+VOID
+NbfDerefAddress(
+ IN PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport address by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ NbfDestroyAddress to remove it from the system.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&Address->ReferenceCount);
+
+ //
+ // If we have deleted all references to this address, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ ASSERT (result >= 0);
+
+ if (result == 0) {
+
+ ExInitializeWorkItem(
+ &Address->u.DestroyAddressQueueItem,
+ NbfDestroyAddress,
+ (PVOID)Address);
+ ExQueueWorkItem(&Address->u.DestroyAddressQueueItem, DelayedWorkQueue);
+ }
+} /* NbfDerefAddress */
+
+
+
+VOID
+NbfAllocateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS_FILE *TransportAddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for an address file. Some
+ minimal initialization is done on the object.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ TransportAddressFile - Pointer to a place where this routine will return
+ a pointer to a transport address file structure. It returns NULL if no
+ storage can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PTP_ADDRESS_FILE AddressFile;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + sizeof(TP_ADDRESS_FILE)) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("NBF: Could not allocate address file: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 102,
+ sizeof(TP_ADDRESS_FILE),
+ ADDRESS_FILE_RESOURCE_ID);
+ *TransportAddressFile = NULL;
+ return;
+ }
+
+ AddressFile = (PTP_ADDRESS_FILE)ExAllocatePoolWithTag (
+ NonPagedPool,
+ sizeof (TP_ADDRESS_FILE),
+ 'fFBN');
+ if (AddressFile == NULL) {
+ PANIC("NBF: Could not allocate address file: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 202,
+ sizeof(TP_ADDRESS_FILE),
+ ADDRESS_FILE_RESOURCE_ID);
+ *TransportAddressFile = NULL;
+ return;
+ }
+ RtlZeroMemory (AddressFile, sizeof(TP_ADDRESS_FILE));
+
+ DeviceContext->MemoryUsage += sizeof(TP_ADDRESS_FILE);
+ ++DeviceContext->AddressFileAllocated;
+
+ AddressFile->Type = NBF_ADDRESSFILE_SIGNATURE;
+ AddressFile->Size = sizeof (TP_ADDRESS_FILE);
+
+ InitializeListHead (&AddressFile->ReceiveDatagramQueue);
+ InitializeListHead (&AddressFile->ConnectionDatabase);
+
+ *TransportAddressFile = AddressFile;
+
+} /* NbfAllocateAddressFile */
+
+
+VOID
+NbfDeallocateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS_FILE TransportAddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for an address file.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ TransportAddressFile - Pointer to a transport address file structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ExFreePool (TransportAddressFile);
+ --DeviceContext->AddressFileAllocated;
+ DeviceContext->MemoryUsage -= sizeof(TP_ADDRESS_FILE);
+
+} /* NbfDeallocateAddressFile */
+
+
+NTSTATUS
+NbfCreateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS_FILE * AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates an address file from the pool of ther
+ specified device context. The reference count in the
+ address is automatically set to 1.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ AddressFile - Pointer to a place where this routine will return a pointer
+ to a transport address file structure.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PLIST_ENTRY p;
+ PTP_ADDRESS_FILE addressFile;
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ p = RemoveHeadList (&DeviceContext->AddressFilePool);
+ if (p == &DeviceContext->AddressFilePool) {
+
+ if ((DeviceContext->AddressFileMaxAllocated == 0) ||
+ (DeviceContext->AddressFileAllocated < DeviceContext->AddressFileMaxAllocated)) {
+
+ NbfAllocateAddressFile (DeviceContext, &addressFile);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Allocated address file at %lx\n", addressFile);
+ }
+
+ } else {
+
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 402,
+ sizeof(TP_ADDRESS_FILE),
+ ADDRESS_FILE_RESOURCE_ID);
+ addressFile = NULL;
+
+ }
+
+ if (addressFile == NULL) {
+ ++DeviceContext->AddressFileExhausted;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ PANIC ("NbfCreateAddressFile: Could not allocate address file object!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ } else {
+
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+
+ }
+
+ ++DeviceContext->AddressFileInUse;
+ if (DeviceContext->AddressFileInUse > DeviceContext->AddressFileMaxInUse) {
+ ++DeviceContext->AddressFileMaxInUse;
+ }
+
+ DeviceContext->AddressFileTotal += DeviceContext->AddressFileInUse;
+ ++DeviceContext->AddressFileSamples;
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+
+ InitializeListHead (&addressFile->ConnectionDatabase);
+ addressFile->Address = NULL;
+ addressFile->FileObject = NULL;
+ addressFile->Provider = DeviceContext;
+ addressFile->State = ADDRESSFILE_STATE_OPENING;
+ addressFile->ConnectIndicationInProgress = FALSE;
+ addressFile->ReferenceCount = 1;
+ addressFile->CloseIrp = (PIRP)NULL;
+
+ //
+ // Initialize the request handlers.
+ //
+
+ addressFile->RegisteredConnectionHandler = FALSE;
+ addressFile->ConnectionHandler = TdiDefaultConnectHandler;
+ addressFile->ConnectionHandlerContext = NULL;
+ addressFile->RegisteredDisconnectHandler = FALSE;
+ addressFile->DisconnectHandler = TdiDefaultDisconnectHandler;
+ addressFile->DisconnectHandlerContext = NULL;
+ addressFile->RegisteredReceiveHandler = FALSE;
+ addressFile->ReceiveHandler = TdiDefaultReceiveHandler;
+ addressFile->ReceiveHandlerContext = NULL;
+ addressFile->RegisteredReceiveDatagramHandler = FALSE;
+ addressFile->ReceiveDatagramHandler = TdiDefaultRcvDatagramHandler;
+ addressFile->ReceiveDatagramHandlerContext = NULL;
+ addressFile->RegisteredExpeditedDataHandler = FALSE;
+ addressFile->ExpeditedDataHandler = TdiDefaultRcvExpeditedHandler;
+ addressFile->ExpeditedDataHandlerContext = NULL;
+ addressFile->RegisteredErrorHandler = FALSE;
+ addressFile->ErrorHandler = TdiDefaultErrorHandler;
+ addressFile->ErrorHandlerContext = NULL;
+
+
+ *AddressFile = addressFile;
+ return STATUS_SUCCESS;
+
+} /* NbfCreateAddress */
+
+
+NTSTATUS
+NbfDestroyAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys an address file and removes all references
+ made by it to other objects in the transport.
+
+ This routine is only called by NbfDereferenceAddressFile. The reason
+ for this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address file object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ AddressFile Pointer to a transport address file structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PTP_ADDRESS address;
+ PDEVICE_CONTEXT DeviceContext;
+ PIRP CloseIrp;
+
+
+ address = AddressFile->Address;
+ DeviceContext = AddressFile->Provider;
+
+ if (address) {
+
+ //
+ // This addressfile was associated with an address.
+ //
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock, &oldirql);
+
+ //
+ // remove this addressfile from the address list and disassociate it from
+ // the file handle.
+ //
+
+ RemoveEntryList (&AddressFile->Linkage);
+ InitializeListHead (&AddressFile->Linkage);
+
+ if (address->AddressFileDatabase.Flink == &address->AddressFileDatabase) {
+
+ //
+ // This is the last open of this address, it will close
+ // due to normal dereferencing but we have to set the
+ // CLOSING flag too to stop further references.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql1);
+ address->Flags |= ADDRESS_FLAGS_STOPPING;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql1);
+
+ }
+
+ AddressFile->Address = NULL;
+
+ AddressFile->FileObject->FsContext = NULL;
+ AddressFile->FileObject->FsContext2 = NULL;
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ //
+ // We will already have been removed from the ShareAccess
+ // of the owning address.
+ //
+
+ //
+ // Now dereference the owning address.
+ //
+
+ NbfDereferenceAddress ("Close", address, AREF_OPEN); // remove the creation hold
+
+ }
+
+ //
+ // Save this for later completion.
+ //
+
+ CloseIrp = AddressFile->CloseIrp;
+
+ //
+ // return the addressFile to the pool of address files
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ DeviceContext->AddressFileTotal += DeviceContext->AddressFileInUse;
+ ++DeviceContext->AddressFileSamples;
+ --DeviceContext->AddressFileInUse;
+
+ if ((DeviceContext->AddressFileAllocated - DeviceContext->AddressFileInUse) >
+ DeviceContext->AddressFileInitAllocated) {
+ NbfDeallocateAddressFile (DeviceContext, AddressFile);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Deallocated address file at %lx\n", AddressFile);
+ }
+ } else {
+ InsertTailList (&DeviceContext->AddressFilePool, &AddressFile->Linkage);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+
+ if (CloseIrp != (PIRP)NULL) {
+ CloseIrp->IoStatus.Information = 0;
+ CloseIrp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest (CloseIrp, IO_NETWORK_INCREMENT);
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbfDestroyAddressFile */
+
+
+VOID
+NbfReferenceAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ ASSERT (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement (&AddressFile->ReferenceCount);
+
+} /* NbfReferenceAddressFile */
+
+
+VOID
+NbfDereferenceAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences an address file by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ NbfDestroyAddressFile to remove it from the system.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&AddressFile->ReferenceCount);
+
+ //
+ // If we have deleted all references to this address file, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ ASSERT (result >= 0);
+
+ if (result == 0) {
+ NbfDestroyAddressFile (AddressFile);
+ }
+} /* NbfDerefAddressFile */
+
+
+PTP_ADDRESS
+NbfLookupAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNBF_NETBIOS_ADDRESS NetworkName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the transport addresses defined for the given
+ device context and compares them with the specified NETWORK
+ NAME values. If an exact match is found, then a pointer to the
+ TP_ADDRESS object is returned, and as a side effect, the reference
+ count to the address object is incremented. If the address is not
+ found, then NULL is returned.
+
+ NOTE: This routine must be called with the DeviceContext
+ spinlock held.
+
+Arguments:
+
+ DeviceContext - Pointer to the device object and its extension.
+ NetworkName - Pointer to an NBF_NETBIOS_ADDRESS structure containing the
+ network name.
+
+Return Value:
+
+ Pointer to the TP_ADDRESS object found, or NULL if not found.
+
+--*/
+
+{
+ PTP_ADDRESS address;
+ PLIST_ENTRY p;
+ ULONG i;
+
+
+ p = DeviceContext->AddressDatabase.Flink;
+
+ for (p = DeviceContext->AddressDatabase.Flink;
+ p != &DeviceContext->AddressDatabase;
+ p = p->Flink) {
+
+ address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+
+ if ((address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ continue;
+ }
+
+ //
+ // If the network name is specified and the network names don't match,
+ // then the addresses don't match.
+ //
+
+ i = NETBIOS_NAME_LENGTH; // length of a Netbios name
+
+ if (address->NetworkName != NULL) {
+ if (NetworkName != NULL) {
+ if (!RtlEqualMemory (
+ address->NetworkName->NetbiosName,
+ NetworkName->NetbiosName,
+ i)) {
+ continue;
+ }
+ } else {
+ continue;
+ }
+
+ } else {
+ if (NetworkName != NULL) {
+ continue;
+ }
+ }
+
+ //
+ // We found the match. Bump the reference count on the address, and
+ // return a pointer to the address object for the caller to use.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2 ("NbfLookupAddress DC %lx: found %lx ", DeviceContext, address);
+ NbfDbgShowAddr (NetworkName);
+ }
+
+ NbfReferenceAddress ("lookup", address, AREF_LOOKUP);
+ return address;
+
+ } /* for */
+
+ //
+ // The specified address was not found.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfLookupAddress DC %lx: did not find ", address);
+ NbfDbgShowAddr (NetworkName);
+ }
+
+ return NULL;
+
+} /* NbfLookupAddress */
+
+
+PTP_CONNECTION
+NbfLookupRemoteName(
+ IN PTP_ADDRESS Address,
+ IN PUCHAR RemoteName,
+ IN UCHAR RemoteSessionNumber
+ )
+
+/*++
+
+Routine Description:
+
+
+ This routine scans the connections associated with the
+ given address, and determines if there is an connection
+ associated with the specific remote address and session
+ number which is becoming active. This is used
+ in determining whether name queries should be processed,
+ or ignored as duplicates.
+
+Arguments:
+
+ Address - Pointer to the address object.
+
+ RemoteName - The 16-character Netbios name of the remote.
+
+ RemoteSessionNumber - The session number assigned to this
+ connection by the remote.
+
+Return Value:
+
+ The connection if one is found, NULL otherwise.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PLIST_ENTRY p;
+ PTP_CONNECTION connection;
+ BOOLEAN Found = FALSE;
+
+
+ //
+ // Hold the spinlock so the connection database doesn't
+ // change.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ for (p=Address->ConnectionDatabase.Flink;
+ p != &Address->ConnectionDatabase;
+ p=p->Flink) {
+
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressList);
+
+ try {
+
+ ACQUIRE_C_SPIN_LOCK (&connection->SpinLock, &oldirql1);
+
+ if (((connection->Flags2 & CONNECTION_FLAGS2_REMOTE_VALID) != 0) &&
+ ((connection->Flags & CONNECTION_FLAGS_READY) == 0)) {
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql1);
+
+ //
+ // If the remote names match, and the connection's RSN is
+ // the same (or zero, which is a temporary condition where
+ // we should err on the side of caution), then return the
+ // connection, which will cause the NAME_QUERY to be ignored.
+ //
+
+ if ((RtlEqualMemory(RemoteName, connection->RemoteName, NETBIOS_NAME_LENGTH)) &&
+ ((connection->Rsn == RemoteSessionNumber) || (connection->Rsn == 0))) {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ NbfReferenceConnection ("Lookup found", connection, CREF_LISTENING);
+ Found = TRUE;
+
+ }
+
+ } else {
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql1);
+
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DbgPrint ("NBF: Got exception in NbfLookupRemoteName\n");
+ DbgBreakPoint();
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql1);
+
+ return (PTP_CONNECTION)NULL;
+ }
+
+ if (Found) {
+ return connection;
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return (PTP_CONNECTION)NULL;
+
+}
+
+
+BOOLEAN
+NbfMatchNetbiosAddress(
+ IN PTP_ADDRESS Address,
+ IN UCHAR NameType,
+ IN PUCHAR NetBIOSName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to compare the addressing information in a
+ TP_ADDRESS object with the 16-byte NetBIOS name in a frame header.
+ If they match, then this routine returns TRUE, else it returns FALSE.
+
+Arguments:
+
+ Address - Pointer to a TP_ADDRESS object.
+
+ NameType - One of NETBIOS_NAME_TYPE_GROUP, NETBIOS_NAME_TYPE_UNIQUE,
+ or NETBIOS_NAME_TYPE_EITHER. Controls what type we are matching
+ on, if it matters.
+
+ NetBIOSName - Pointer to a 16-byte character string (non-terminated),
+ or NULL if this is a received broadcast address.
+
+Return Value:
+
+ BOOLEAN, TRUE if match, FALSE if not.
+
+--*/
+
+{
+
+ PULONG AddressNamePointer;
+ ULONG UNALIGNED * NetbiosNamePointer;
+
+ //
+ // If this is address is the Netbios broadcast address, the comparison
+ // succeeds only if the passed in address is also NULL.
+ //
+
+ if (Address->NetworkName == NULL) {
+
+ if (NetBIOSName == NULL) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+
+ } else if (NetBIOSName == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Do a quick check of the first character in the names.
+ //
+
+ if (Address->NetworkName->NetbiosName[0] != NetBIOSName[0]) {
+ return FALSE;
+ }
+
+ //
+ // If name type is important and it doesn't match
+ // this address' type, fail.
+ //
+
+ if (NameType != NETBIOS_NAME_TYPE_EITHER) {
+
+ if (Address->NetworkName->NetbiosNameType != (USHORT)NameType) {
+
+ return FALSE;
+ }
+ }
+
+ IF_NBFDBG (NBF_DEBUG_DATAGRAMS) {
+ NbfPrint2 ("MatchNetbiosAddress %lx: compare %.16s to ", Address, NetBIOSName);
+ NbfDbgShowAddr (Address->NetworkName);
+ }
+
+ //
+ // Now compare the 16-character Netbios names as ULONGs
+ // for speed. We know the one stored in the address
+ // structure is aligned.
+ //
+
+ AddressNamePointer = (PULONG)(Address->NetworkName->NetbiosName);
+ NetbiosNamePointer = (ULONG UNALIGNED *)NetBIOSName;
+
+ if ((AddressNamePointer[0] == NetbiosNamePointer[0]) &&
+ (AddressNamePointer[1] == NetbiosNamePointer[1]) &&
+ (AddressNamePointer[2] == NetbiosNamePointer[2]) &&
+ (AddressNamePointer[3] == NetbiosNamePointer[3])) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+
+} /* NbfMatchNetbiosAddress */
+
+
+VOID
+NbfStopAddress(
+ IN PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to terminate all activity on an address and
+ destroy the object. This is done in a graceful manner; i.e., all
+ outstanding addressfiles are removed from the addressfile database, and
+ all their activities are shut down.
+
+Arguments:
+
+ Address - Pointer to a TP_ADDRESS object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PTP_ADDRESS_FILE addressFile;
+ PLIST_ENTRY p;
+ PDEVICE_CONTEXT DeviceContext;
+
+ DeviceContext = Address->Provider;
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ //
+ // If we're already stopping this address, then don't try to do it again.
+ //
+
+ if (!(Address->Flags & ADDRESS_FLAGS_STOPPING)) {
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfStopAddress %lx: stopping\n", Address);
+ }
+
+ NbfReferenceAddress ("Stopping", Address, AREF_TEMP_STOP);
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql1);
+ Address->Flags |= ADDRESS_FLAGS_STOPPING;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql1);
+
+ //
+ // Run down all addressfiles on this address. This
+ // will leave the address with no references
+ // potentially, but we don't need a temp one
+ // because every place that calls NbfStopAddress
+ // already has a temp reference.
+ //
+
+ while (!IsListEmpty (&Address->AddressFileDatabase)) {
+ p = RemoveHeadList (&Address->AddressFileDatabase);
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+
+ addressFile->Address = NULL;
+ addressFile->FileObject->FsContext = NULL;
+ addressFile->FileObject->FsContext2 = NULL;
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ //
+ // Run-down this addressFile without the lock on.
+ // We don't care about removing ourselves from
+ // the address' ShareAccess because we are
+ // tearing it down.
+ //
+
+ NbfStopAddressFile (addressFile, Address);
+
+ //
+ // return the addressFile to the pool of address files
+ //
+
+ NbfDereferenceAddressFile (addressFile);
+
+ NbfDereferenceAddress ("stop address", Address, AREF_OPEN);
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ NbfDereferenceAddress ("Stopping", Address, AREF_TEMP_STOP);
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfStopAddress %lx: already stopping\n", Address);
+ }
+
+ }
+
+} /* NbfStopAddress */
+
+
+NTSTATUS
+NbfStopAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile,
+ IN PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to terminate all activity on an AddressFile and
+ destroy the object. We remove every connection and datagram associated
+ with this addressfile from the address database and terminate their
+ activity. Then, if there are no other outstanding addressfiles open on
+ this address, the address will go away.
+
+Arguments:
+
+ AddressFile - pointer to the addressFile to be stopped
+
+ Address - the owning address for this addressFile (we do not depend upon
+ the pointer in the addressFile because we want this routine to be safe)
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the Irp does not
+ point to a real address.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ LIST_ENTRY localIrpList;
+ PLIST_ENTRY p, pFlink;
+ PIRP irp;
+ PTP_CONNECTION connection;
+
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ if (AddressFile->State == ADDRESSFILE_STATE_CLOSING) {
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfStopAddressFile %lx: already closing.\n", AddressFile);
+ }
+ return STATUS_SUCCESS;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfStopAddressFile %lx: closing.\n", AddressFile);
+ }
+
+
+ AddressFile->State = ADDRESSFILE_STATE_CLOSING;
+ InitializeListHead (&localIrpList);
+
+ //
+ // Run down all connections on this addressfile, and
+ // preform the equivalent of NbfDestroyAssociation
+ // on them.
+ //
+
+ while (!IsListEmpty (&AddressFile->ConnectionDatabase)) {
+ p = RemoveHeadList (&AddressFile->ConnectionDatabase);
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressFileList);
+
+ try {
+
+ ACQUIRE_C_SPIN_LOCK (&connection->SpinLock, &oldirql1);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) == 0) {
+
+ //
+ // It is in the process of being disassociated already.
+ //
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql1);
+ continue;
+ }
+
+ connection->Flags2 &= ~CONNECTION_FLAGS2_ASSOCIATED;
+ connection->Flags2 |= CONNECTION_FLAGS2_DESTROY; // BUGBUG: Is this needed?
+ RemoveEntryList (&connection->AddressList);
+ InitializeListHead (&connection->AddressList);
+ InitializeListHead (&connection->AddressFileList);
+ connection->AddressFile = NULL;
+
+ NbfReferenceConnection ("Close AddressFile", connection, CREF_STOP_ADDRESS);
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql1);
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DbgPrint ("NBF: Got exception in NbfStopAddressFile\n");
+ DbgBreakPoint();
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql1);
+ continue;
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+#if DBG
+ if (NbfDisconnectDebug) {
+ STRING remoteName, localName;
+ remoteName.Length = NETBIOS_NAME_LENGTH - 1;
+ remoteName.Buffer = connection->RemoteName;
+ localName.Length = NETBIOS_NAME_LENGTH - 1;
+ localName.Buffer = AddressFile->Address->NetworkName->NetbiosName;
+ NbfPrint2( "TpStopEndpoint stopping connection to %S from %S\n",
+ &remoteName, &localName );
+ }
+#endif
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql1);
+ NbfStopConnection (connection, STATUS_LOCAL_DISCONNECT);
+ KeLowerIrql (oldirql1);
+ NbfDereferenceConnection ("Close AddressFile", connection, CREF_STOP_ADDRESS);
+
+ NbfDereferenceAddress ("Destroy association", Address, AREF_CONNECTION);
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ }
+
+ //
+ // now remove all of the datagrams owned by this addressfile
+ //
+
+ //
+ // If the address has a datagram send in progress, skip the
+ // first one, it will complete when the NdisSend completes.
+ //
+
+ p = Address->SendDatagramQueue.Flink;
+ if (Address->Flags & ADDRESS_FLAGS_SEND_IN_PROGRESS) {
+ ASSERT (p != &Address->SendDatagramQueue);
+ p = p->Flink;
+ }
+
+ for ( ;
+ p != &Address->SendDatagramQueue;
+ p = pFlink ) {
+
+ pFlink = p->Flink;
+ irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ if (IoGetCurrentIrpStackLocation(irp)->FileObject->FsContext == AddressFile) {
+ RemoveEntryList (p);
+ InitializeListHead (p);
+ InsertTailList (&localIrpList, p);
+ }
+
+ }
+
+ for (p = AddressFile->ReceiveDatagramQueue.Flink;
+ p != &AddressFile->ReceiveDatagramQueue;
+ p = pFlink ) {
+
+ pFlink = p->Flink;
+ RemoveEntryList (p);
+ InitializeListHead (p);
+ InsertTailList (&localIrpList, p);
+ }
+
+ //
+ // and finally, signal failure if the address file was waiting for a
+ // registration to complete (Irp is set to NULL when this succeeds).
+ //
+
+ if (AddressFile->Irp != NULL) {
+ PIRP irp=AddressFile->Irp;
+#if DBG
+ if ((Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) == 0) {
+ DbgPrint ("NBF: AddressFile %lx closed while opening!!\n", AddressFile);
+ DbgBreakPoint();
+ }
+#endif
+ AddressFile->Irp = NULL;
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ irp->IoStatus.Information = 0;
+ irp->IoStatus.Status = STATUS_DUPLICATE_NAME;
+
+ LEAVE_NBF;
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+ ENTER_NBF;
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ }
+
+ //
+ // cancel all the datagrams on this address file
+ //
+
+ while (!IsListEmpty (&localIrpList)) {
+ KIRQL cancelIrql;
+
+ p = RemoveHeadList (&localIrpList);
+ irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ IoSetCancelRoutine(irp, NULL);
+ IoReleaseCancelSpinLock(cancelIrql);
+ irp->IoStatus.Information = 0;
+ irp->IoStatus.Status = STATUS_NETWORK_NAME_DELETED;
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+
+ NbfDereferenceAddress ("Datagram aborted", Address, AREF_REQUEST);
+ }
+
+} /* NbfStopAddressFile */
+
+
+NTSTATUS
+NbfCloseAddress(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to close the addressfile pointed to by a file
+ object. If there is any activity to be run down, we will run it down
+ before we terminate the addressfile. We remove every connection and
+ datagram associated with this addressfile from the address database
+ and terminate their activity. Then, if there are no other outstanding
+ addressfiles open on this address, the address will go away.
+
+Arguments:
+
+ Irp - the Irp Address - Pointer to a TP_ADDRESS object.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the Irp does not
+ point to a real address.
+
+--*/
+
+{
+ PTP_ADDRESS address;
+ PTP_ADDRESS_FILE addressFile;
+
+ addressFile = IrpSp->FileObject->FsContext;
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfCloseAddress AF %lx:\n", addressFile);
+ }
+
+ addressFile->CloseIrp = Irp;
+
+ //
+ // We assume that addressFile has already been verified
+ // at this point.
+ //
+
+ address = addressFile->Address;
+ ASSERT (address);
+
+ //
+ // Remove us from the access info for this address.
+ //
+
+ ExAcquireResourceExclusive (&addressFile->Provider->AddressResource, TRUE);
+ IoRemoveShareAccess (addressFile->FileObject, &address->u.ShareAccess);
+ ExReleaseResource (&addressFile->Provider->AddressResource);
+
+
+ NbfStopAddressFile (addressFile, address);
+ NbfDereferenceAddressFile (addressFile);
+
+ //
+ // This removes a reference added by our caller.
+ //
+
+ NbfDereferenceAddress ("IRP_MJ_CLOSE", address, AREF_VERIFY);
+
+ return STATUS_PENDING;
+
+} /* NbfCloseAddress */
+
+
+NTSTATUS
+NbfSendDatagramsOnAddress(
+ PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to acquire a hold on the SendDatagramQueue of
+ the specified address, prepare the next datagram for shipment, and
+ call NbfSendUIMdlFrame to actually do the work. When NbfSendUIMdlFrame
+ is finished, it will cause an I/O completion routine in UFRAMES.C to
+ be called, at which time this routine is called again to handle the
+ next datagram in the pipeline.
+
+ NOTE: This routine must be called at a point where the address
+ has another reference that will keep it around.
+
+Arguments:
+
+ Address - a pointer to the address object to send the datagram on.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PLIST_ENTRY p;
+ PIRP Irp;
+ TDI_ADDRESS_NETBIOS UNALIGNED * remoteAddress;
+ PIO_STACK_LOCATION irpSp;
+ PDEVICE_CONTEXT DeviceContext;
+ PUCHAR SingleSR;
+ UINT SingleSRLength;
+ UINT HeaderLength;
+ PUCHAR LocalName;
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfSendDatagramsOnAddress %lx:\n", Address);
+ }
+
+ DeviceContext = Address->Provider;
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ if (!(Address->Flags & ADDRESS_FLAGS_SEND_IN_PROGRESS)) {
+
+ //
+ // If the queue is empty, don't do anything.
+ //
+
+ if (IsListEmpty (&Address->SendDatagramQueue)) {
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Mark the address's send datagram queue as held so that the
+ // MDL and NBF header will not be used for two requests at the
+ // same time.
+ //
+
+ Address->Flags |= ADDRESS_FLAGS_SEND_IN_PROGRESS;
+
+ //
+ // We own the hold, and we've released the spinlock. So pick off the
+ // next datagram to be sent, and ship it.
+ //
+
+ p = Address->SendDatagramQueue.Flink;
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+
+ //
+ // If there is no remote Address specified (the Address specified has
+ // length 0), this is a broadcast datagram. If anything is specified, it
+ // will be used as a netbios address.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ remoteAddress = NbfParseTdiAddress (
+ ((PTDI_REQUEST_KERNEL_SENDDG)(&irpSp->Parameters))->
+ SendDatagramInformation->RemoteAddress,
+ TRUE);
+ ASSERT (remoteAddress != NULL);
+
+ //
+ // Build the MAC header. DATAGRAM frames go out as
+ // single-route source routing.
+ //
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SingleSR,
+ &SingleSRLength);
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ Address->UIFrame->Header,
+ DeviceContext->NetBIOSAddress.Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS) +
+ Irp->IoStatus.Information,
+ SingleSR,
+ SingleSRLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&(Address->UIFrame->Header[HeaderLength]));
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // Build the correct Netbios header.
+ //
+
+ if (Address->NetworkName != NULL) {
+ LocalName = Address->NetworkName->NetbiosName;
+ } else {
+ LocalName = DeviceContext->ReservedNetBIOSAddress;
+ }
+
+ if (remoteAddress == (PVOID)-1) {
+
+ ConstructDatagramBroadcast (
+ (PNBF_HDR_CONNECTIONLESS)&(Address->UIFrame->Header[HeaderLength]),
+ LocalName);
+
+ } else {
+
+ ConstructDatagram (
+ (PNBF_HDR_CONNECTIONLESS)&(Address->UIFrame->Header[HeaderLength]),
+ (PNAME)remoteAddress->NetbiosName,
+ LocalName);
+
+ }
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+
+
+ //
+ // Update our statistics for this datagram.
+ //
+
+ ++DeviceContext->Statistics.DatagramsSent;
+ ADD_TO_LARGE_INTEGER(
+ &DeviceContext->Statistics.DatagramBytesSent,
+ Irp->IoStatus.Information);
+
+
+ //
+ // Munge the packet length, append the data, and send it.
+ //
+
+ NbfSetNdisPacketLength(Address->UIFrame->NdisPacket, HeaderLength);
+
+ if (Irp->MdlAddress) {
+ NdisChainBufferAtBack (Address->UIFrame->NdisPacket, (PNDIS_BUFFER)Irp->MdlAddress);
+ }
+
+ NbfSendUIMdlFrame (
+ Address);
+
+
+ //
+ // The hold will be released in the I/O completion handler in
+ // UFRAMES.C. At that time, if there is another outstanding datagram
+ // to send, it will reset the hold and call this routine again.
+ //
+
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ }
+
+ return STATUS_SUCCESS;
+} /* NbfSendDatagramsOnAddress */
diff --git a/private/ntos/tdi/nbf/autodial.c b/private/ntos/tdi/nbf/autodial.c
new file mode 100644
index 000000000..85bea057e
--- /dev/null
+++ b/private/ntos/tdi/nbf/autodial.c
@@ -0,0 +1,502 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ autodial.c
+
+Abstract:
+
+ This module contains code that interacts with the
+ automatic connection driver (rasacd.sys):
+
+ o NbfNoteNewConnection
+ o NbfAcdBind
+ o NbfAcdUnbind
+
+Author:
+
+ Anthony Discolo (adiscolo) 6 September 1995
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef RASAUTODIAL
+
+#include <acd.h>
+#include <acdapi.h>
+
+//
+// Global variables.
+//
+BOOLEAN fAcdLoadedG;
+ACD_DRIVER AcdDriverG;
+ULONG ulDriverIdG = 'Nbf ';
+
+
+
+BOOLEAN
+NbfCancelAutoDialRequest(
+ IN PVOID pArg,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN USHORT nArgs,
+ IN PVOID *pArgs
+ )
+{
+ if (nArgs != 1)
+ return FALSE;
+
+ return (pArgs[0] == pArg);
+} // NbfCancelAutoDialRequest
+
+
+
+VOID
+NbfRetryTdiConnect(
+ IN BOOLEAN fSuccess,
+ IN PVOID *pArgs
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called indirectly by the automatic
+ connection driver to continue the connection process
+ after an automatic connection has been made.
+
+Arguments:
+
+ fSuccess - TRUE if the connection attempt was successful.
+
+ pArgs - a pointer to the argument vector
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTP_CONNECTION pConnection = pArgs[0];
+ KIRQL irql;
+ BOOL fStopping;
+
+ //
+ // Check for a destroyed connection.
+ //
+ if (pConnection == NULL)
+ return;
+ status = NbfVerifyConnectionObject(pConnection);
+ if (status != STATUS_SUCCESS) {
+ DbgPrint(
+ "NbfRetryTdiConnect: NbfVerifyConnectionObject failed (status=0x%x)\n",
+ status);
+ return;
+ }
+#ifdef notdef // DBG
+ DbgPrint(
+ "NbfRetryTdiConnect: fSuccess=%d, pConnection=0x%x, STOPPING=%d\n",
+ fSuccess,
+ pConnection,
+ pConnection->Flags2 & CONNECTION_FLAGS2_STOPPING);
+#endif
+ KeRaiseIrql(DISPATCH_LEVEL, &irql);
+ //
+ // Check to see if the connection
+ // is closing.
+ //
+ ACQUIRE_DPC_SPIN_LOCK(&pConnection->SpinLock);
+ fStopping = (pConnection->Flags2 & CONNECTION_FLAGS2_STOPPING);
+ //
+ // Clear the automatic connection
+ // in-progress flag, and set the
+ // autoconnected flag.
+ //
+ pConnection->Flags2 &= ~CONNECTION_FLAGS2_AUTOCONNECTING;
+ pConnection->Flags2 |= CONNECTION_FLAGS2_AUTOCONNECTED;
+ RELEASE_DPC_SPIN_LOCK(&pConnection->SpinLock);
+ if (!fStopping) {
+ if (fSuccess) {
+ //
+ // Restart the name query.
+ //
+ pConnection->Retries =
+ (USHORT)pConnection->Provider->NameQueryRetries;
+ NbfSendNameQuery (
+ pConnection,
+ TRUE);
+ NbfStartConnectionTimer (
+ pConnection,
+ ConnectionEstablishmentTimeout,
+ pConnection->Provider->NameQueryTimeout);
+ }
+ else {
+ //
+ // Terminate the connection with an error.
+ //
+ NbfStopConnection(pConnection, STATUS_BAD_NETWORK_PATH);
+ }
+ }
+ KeLowerIrql(irql);
+ NbfDereferenceConnection ("NbfRetryTdiConnect", pConnection, CREF_BY_ID);
+} /* NbfRetryTdiConnect */
+
+
+
+BOOLEAN
+NbfCancelTdiConnect(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ )
+
+/*++
+
+DESCRIPTION
+ This routine is called by the I/O system to cancel a connection
+ when we are attempting to restore an automatic connection.
+
+ARGUMENTS
+ pDeviceObject: a pointer to the device object for this driver
+
+ pIrp: a pointer to the irp to be cancelled
+
+RETURN VALUE
+ TRUE if the request was canceled; FALSE otherwise.
+
+--*/
+
+{
+ PIO_STACK_LOCATION pIrpSp;
+ PTP_CONNECTION pConnection;
+ ACD_ADDR addr;
+
+ UNREFERENCED_PARAMETER(pDeviceObject);
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pConnection = pIrpSp->FileObject->FsContext;
+ if (pConnection == NULL)
+ return FALSE;
+#ifdef notdef // DBG
+ DbgPrint(
+ "NbfCancelTdiConnect: pIrp=0x%x, pConnection=0x%x\n",
+ pIrp,
+ pConnection);
+#endif
+ //
+ // Get the address of the connection.
+ //
+ addr.fType = ACD_ADDR_NB;
+ RtlCopyMemory(&addr.cNetbios, pConnection->CalledAddress.NetbiosName, 15);
+ //
+ // Cancel the autodial request.
+ //
+ return (*AcdDriverG.lpfnCancelConnection)(
+ ulDriverIdG,
+ &addr,
+ NbfCancelAutoDialRequest,
+ pConnection);
+} // NbfCancelTdiConnect
+
+
+
+BOOLEAN
+NbfAttemptAutoDial(
+ IN PTP_CONNECTION pConnection,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN PVOID pArg
+ )
+
+/*++
+
+Routine Description:
+
+ Call the automatic connection driver to attempt an
+ automatic connection.
+
+Arguments:
+
+ pConnection - a pointer to the TP_CONNECTION block for this connection
+
+ ulFlags - connection flags to pass to the automatic
+ connection driver
+
+ pProc - a callback procedure when the automatic connection completes
+
+ pArg - the single parameter to the callback procedure
+
+Return Value:
+
+ TRUE if the automatic connection was started successfully,
+ FALSE otherwise.
+
+--*/
+
+{
+ ACD_ADDR addr;
+ PVOID pArgs[1];
+ BOOLEAN bSuccess;
+
+ //
+ // If we've already attempted an automatic
+ // connection on this connection, then
+ // don't try again.
+ //
+ if (pConnection->Flags2 & CONNECTION_FLAGS2_AUTOCONNECTED)
+ return FALSE;
+ //
+ // Get the address of the connection.
+ //
+ addr.fType = ACD_ADDR_NB;
+ RtlCopyMemory(&addr.cNetbios, pConnection->CalledAddress.NetbiosName, 15);
+#ifdef notdef // DBG
+ DbgPrint("NbfAttemptAutoDial: szAddr=%15.15s\n", addr.cNetbios);
+#endif
+ //
+ // Attempt to start the connection.
+ // NbfRetryTdiConnect() will be called
+ // when the connection process has completed.
+ //
+ pArgs[0] = pArg;
+ bSuccess = (*AcdDriverG.lpfnStartConnection)(
+ ulDriverIdG,
+ &addr,
+ ulFlags,
+ pProc,
+ 1,
+ pArgs);
+ if (bSuccess) {
+ //
+ // Set the CONNECTION_FLAGS2_AUTOCONNECTING flag on
+ // the connection. This will prevent it from being
+ // aborted during the automatic connection process.
+ //
+ pConnection->Flags2 |= CONNECTION_FLAGS2_AUTOCONNECTING;
+ }
+
+ return bSuccess;
+} // NbfAttemptAutoDial
+
+
+
+VOID
+NbfNoteNewConnection(
+ PTP_CONNECTION pConnection,
+ PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+ Inform the automatic connection driver of a successful
+ new connection.
+
+Arguments:
+ Connection - a pointer to a connection object
+
+ DeviceContext - a pointer to the device context
+
+Return Value:
+ None.
+
+--*/
+
+{
+ KIRQL irql;
+ ACD_ADDR addr;
+ ACD_ADAPTER adapter;
+ ULONG ulcChars;
+
+ addr.fType = ACD_ADDR_NB;
+ RtlCopyMemory(&addr.cNetbios, pConnection->CalledAddress.NetbiosName, 15);
+#ifdef notdef // DBG
+ DbgPrint("NbfNoteNewConnection: szAddr=%15.15s\n", addr.cNetbios);
+#endif
+ //
+ // Eliminate the "/Device/Nbf_" prefix when
+ // copying the adapter name.
+ //
+ adapter.fType = ACD_ADAPTER_NAME;
+ ulcChars = DeviceContext->DeviceNameLength - 12;
+ if (ulcChars >= ACD_ADAPTER_NAME_LEN)
+ ulcChars = ACD_ADAPTER_NAME_LEN - 1;
+ RtlCopyMemory(
+ adapter.szName,
+ &DeviceContext->DeviceName[12],
+ ulcChars * sizeof (WCHAR));
+ adapter.szName[ulcChars] = L'\0';
+ //
+ // Simply notify the automatic connection driver
+ // that a successful connection has been made.
+ //
+ (*AcdDriverG.lpfnNewConnection)(
+ &addr,
+ &adapter);
+} // NbfNoteNewConnection
+
+
+
+VOID
+NbfAcdBind()
+{
+ NTSTATUS status;
+ UNICODE_STRING nameString;
+ IO_STATUS_BLOCK ioStatusBlock;
+ PIRP pIrp;
+ PFILE_OBJECT pAcdFileObject;
+ PDEVICE_OBJECT pAcdDeviceObject;
+ PACD_DRIVER pDriver = &AcdDriverG;
+
+ //
+ // Initialize the name of the automatic
+ // connection device.
+ //
+ RtlInitUnicodeString(&nameString, ACD_DEVICE_NAME);
+ //
+ // Get the file and device objects for the
+ // device.
+ //
+ status = IoGetDeviceObjectPointer(
+ &nameString,
+ SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
+ &pAcdFileObject,
+ &pAcdDeviceObject);
+ if (status != STATUS_SUCCESS)
+ return;
+ //
+ // Reference the device object.
+ //
+ ObReferenceObject(pAcdDeviceObject);
+ //
+ // Remove the reference IoGetDeviceObjectPointer()
+ // put on the file object.
+ //
+ ObDereferenceObject(pAcdFileObject);
+ //
+ // Initialize our part of the ACD_DRIVER
+ // structure.
+ //
+ KeInitializeSpinLock(&AcdDriverG.SpinLock);
+ AcdDriverG.ulDriverId = ulDriverIdG;
+ AcdDriverG.fEnabled = FALSE;
+ //
+ // Build a request to get the automatic
+ // connection driver entry points.
+ //
+ pIrp = IoBuildDeviceIoControlRequest(
+ IOCTL_INTERNAL_ACD_BIND,
+ pAcdDeviceObject,
+ (PVOID)&pDriver,
+ sizeof (pDriver),
+ NULL,
+ 0,
+ TRUE,
+ NULL,
+ &ioStatusBlock);
+ if (pIrp == NULL) {
+ ObDereferenceObject(pAcdDeviceObject);
+ return;
+ }
+ //
+ // Submit the request to the
+ // automatic connection driver.
+ //
+ status = IoCallDriver(pAcdDeviceObject, pIrp);
+ fAcdLoadedG = (status == STATUS_SUCCESS);
+ //
+ // Close the device.
+ //
+ ObDereferenceObject(pAcdDeviceObject);
+} // NbfAcdBind
+
+
+
+VOID
+NbfAcdUnbind()
+{
+ NTSTATUS status;
+ UNICODE_STRING nameString;
+ IO_STATUS_BLOCK ioStatusBlock;
+ PIRP pIrp;
+ PFILE_OBJECT pAcdFileObject;
+ PDEVICE_OBJECT pAcdDeviceObject;
+ PACD_DRIVER pDriver = &AcdDriverG;
+
+ //
+ // Don't bother to unbind if we
+ // didn't successfully bind in the
+ // first place.
+ //
+ if (!fAcdLoadedG)
+ return;
+ //
+ // Initialize the name of the automatic
+ // connection device.
+ //
+ RtlInitUnicodeString(&nameString, ACD_DEVICE_NAME);
+ //
+ // Get the file and device objects for the
+ // device.
+ //
+ status = IoGetDeviceObjectPointer(
+ &nameString,
+ SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
+ &pAcdFileObject,
+ &pAcdDeviceObject);
+ if (status != STATUS_SUCCESS)
+ return;
+ //
+ // Reference the device object.
+ //
+ ObReferenceObject(pAcdDeviceObject);
+ //
+ // Remove the reference IoGetDeviceObjectPointer()
+ // put on the file object.
+ //
+ ObDereferenceObject(pAcdFileObject);
+ //
+ // Build a request to unbind from
+ // the automatic connection driver.
+ //
+ pIrp = IoBuildDeviceIoControlRequest(
+ IOCTL_INTERNAL_ACD_UNBIND,
+ pAcdDeviceObject,
+ (PVOID)&pDriver,
+ sizeof (pDriver),
+ NULL,
+ 0,
+ TRUE,
+ NULL,
+ &ioStatusBlock);
+ if (pIrp == NULL) {
+ ObDereferenceObject(pAcdDeviceObject);
+ return;
+ }
+ //
+ // Submit the request to the
+ // automatic connection driver.
+ //
+ status = IoCallDriver(pAcdDeviceObject, pIrp);
+ //
+ // Close the device.
+ //
+ ObDereferenceObject(pAcdDeviceObject);
+} // NbfAcdUnbind
+
+#endif // RASAUTODIAL
+
diff --git a/private/ntos/tdi/nbf/connect.c b/private/ntos/tdi/nbf/connect.c
new file mode 100644
index 000000000..af2aec64b
--- /dev/null
+++ b/private/ntos/tdi/nbf/connect.c
@@ -0,0 +1,1700 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ connect.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiAccept
+ o TdiListen
+ o TdiConnect
+ o TdiDisconnect
+ o TdiAssociateAddress
+ o TdiDisassociateAddress
+ o OpenConnection
+ o CloseConnection
+
+Author:
+
+ David Beaver (dbeaver) 1 July 1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef notdef // RASAUTODIAL
+#include <acd.h>
+#include <acdapi.h>
+#endif // RASAUTODIAL
+
+#ifdef notdef // RASAUTODIAL
+extern BOOLEAN fAcdLoadedG;
+extern ACD_DRIVER AcdDriverG;
+
+//
+// Imported functions.
+//
+VOID
+NbfRetryPreTdiConnect(
+ IN BOOLEAN fSuccess,
+ IN PVOID *pArgs
+ );
+
+BOOLEAN
+NbfAttemptAutoDial(
+ IN PTP_CONNECTION Connection,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN PVOID pArg
+ );
+
+VOID
+NbfCancelPreTdiConnect(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ );
+#endif // RASAUTODIAL
+
+NTSTATUS
+NbfTdiConnectCommon(
+ IN PIRP Irp
+ );
+
+
+
+NTSTATUS
+NbfTdiAccept(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiAccept request for the transport provider.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_CONNECTION connection;
+ PIO_STACK_LOCATION irpSp;
+ KIRQL oldirql;
+ NTSTATUS status;
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint0 ("NbfTdiAccept: Entered.\n");
+ }
+
+ //
+ // Get the connection this is associated with; if there is none, get out.
+ // This adds a connection reference of type BY_ID if successful.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // This adds a connection reference of type BY_ID if successful.
+ //
+
+ status = NbfVerifyConnectionObject (connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ //
+ // just set the connection flags to allow reads and writes to proceed.
+ //
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ //
+ // Turn off the stopping flag for this connection.
+ //
+
+ connection->Flags2 &= ~CONNECTION_FLAGS2_STOPPING;
+ connection->Status = STATUS_PENDING;
+
+ connection->Flags2 |= CONNECTION_FLAGS2_ACCEPTED;
+
+
+ if (connection->AddressFile->ConnectIndicationInProgress) {
+ connection->Flags2 |= CONNECTION_FLAGS2_INDICATING;
+ }
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_WAITING_SC) != 0) {
+
+ //
+ // We previously completed a listen, now the user is
+ // coming back with an accept, Set this flag to allow
+ // the connection to proceed.
+ //
+ // BUGBUG: If the connection has gone down in the
+ // meantime, we have just reenabled it.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+ connection->Flags |= CONNECTION_FLAGS_READY;
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ INCREMENT_COUNTER (connection->Provider, OpenConnections);
+
+ //
+ // Set this flag to enable disconnect indications; once
+ // the client has accepted he expects those.
+ //
+
+ connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ NbfSendSessionConfirm (connection);
+
+ } else {
+
+ //
+ // This accept is being called at some point before
+ // the link is up; directly from the connection handler
+ // or at some point slightly later. We don't set
+ // FLAGS2_REQ_COMPLETED now because the reference
+ // count is not high enough; we set it when we get
+ // the session initialize.
+ //
+ // BUGBUG: If the connection goes down in the meantime,
+ // we won't indicate the disconnect.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ }
+
+ NbfDereferenceConnection ("Temp TdiAccept", connection, CREF_BY_ID);
+
+ KeLowerIrql (oldirql);
+
+ return STATUS_SUCCESS;
+
+} /* NbfTdiAccept */
+
+
+NTSTATUS
+NbfTdiAssociateAddress(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the association of the connection and the address for
+ the user.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PFILE_OBJECT fileObject;
+ PTP_ADDRESS_FILE addressFile;
+ PTP_ADDRESS oldAddress;
+ PTP_CONNECTION connection;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL_ASSOCIATE parameters;
+ PDEVICE_CONTEXT deviceContext;
+
+ KIRQL oldirql, oldirql2;
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint0 ("TdiAssociateAddress: Entered.\n");
+ }
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ //
+ // verify that the operation is taking place on a connection. At the same
+ // time we do this, we reference the connection. This ensures it does not
+ // get removed out from under us. Note also that we do the connection
+ // lookup within a try/except clause, thus protecting ourselves against
+ // really bogus handles
+ //
+
+ connection = irpSp->FileObject->FsContext;
+ status = NbfVerifyConnectionObject (connection);
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+
+ //
+ // Make sure this connection is ready to be associated.
+ //
+
+ oldAddress = (PTP_ADDRESS)NULL;
+
+ try {
+
+ ACQUIRE_C_SPIN_LOCK (&connection->SpinLock, &oldirql2);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) &&
+ ((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) {
+
+ //
+ // The connection is already associated with
+ // an active connection...bad!
+ //
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql2);
+ NbfDereferenceConnection ("Temp Ref Associate", connection, CREF_BY_ID);
+
+ return STATUS_INVALID_CONNECTION;
+
+ } else {
+
+ //
+ // See if there is an old association hanging around...
+ // this happens if the connection has been disassociated,
+ // but not closed.
+ //
+
+ if (connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) {
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint0 ("NbfTdiAssociateAddress: removing association.\n");
+ }
+
+ //
+ // Save this; since it is non-null this address
+ // will be dereferenced after the connection
+ // spinlock is released.
+ //
+
+ oldAddress = connection->AddressFile->Address;
+
+ //
+ // Remove the old association.
+ //
+
+ connection->Flags2 &= ~CONNECTION_FLAGS2_ASSOCIATED;
+ RemoveEntryList (&connection->AddressList);
+ RemoveEntryList (&connection->AddressFileList);
+ InitializeListHead (&connection->AddressList);
+ InitializeListHead (&connection->AddressFileList);
+ connection->AddressFile = NULL;
+
+ }
+
+ }
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql2);
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DbgPrint ("NBF: Got exception 1 in NbfTdiAssociateAddress\n");
+ DbgBreakPoint();
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql2);
+ NbfDereferenceConnection ("Temp Ref Associate", connection, CREF_BY_ID);
+ return GetExceptionCode();
+ }
+
+
+ //
+ // If we removed an old association, dereference the
+ // address.
+ //
+
+ if (oldAddress != (PTP_ADDRESS)NULL) {
+
+ NbfDereferenceAddress("Removed old association", oldAddress, AREF_CONNECTION);
+
+ }
+
+
+ deviceContext = connection->Provider;
+
+ parameters = (PTDI_REQUEST_KERNEL_ASSOCIATE)&irpSp->Parameters;
+
+ //
+ // get a pointer to the address File Object, which points us to the
+ // transport's address object, which is where we want to put the
+ // connection.
+ //
+
+ status = ObReferenceObjectByHandle (
+ parameters->AddressHandle,
+ 0L,
+ 0,
+ KernelMode,
+ (PVOID *) &fileObject,
+ NULL);
+
+ if (NT_SUCCESS(status)) {
+
+ //
+ // we might have one of our address objects; verify that.
+ //
+
+ addressFile = fileObject->FsContext;
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint3 ("NbfTdiAssociateAddress: Connection %lx Irp %lx AddressFile %lx \n",
+ connection, Irp, addressFile);
+ }
+
+ if (NT_SUCCESS (NbfVerifyAddressObject (addressFile))) {
+
+ //
+ // have an address and connection object. Add the connection to the
+ // address object database. Also add the connection to the address
+ // file object db (used primarily for cleaning up). Reference the
+ // address to account for one more reason for it staying open.
+ //
+
+ ACQUIRE_SPIN_LOCK (&addressFile->Address->SpinLock, &oldirql);
+ if ((addressFile->Address->Flags & ADDRESS_FLAGS_STOPPING) == 0) {
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint2 ("NbfTdiAssociateAddress: Valid Address %lx %lx\n",
+ addressFile->Address, addressFile);
+ }
+
+ try {
+
+ ACQUIRE_C_SPIN_LOCK (&connection->SpinLock, &oldirql2);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) {
+
+ NbfReferenceAddress (
+ "Connection associated",
+ addressFile->Address,
+ AREF_CONNECTION);
+
+#if DBG
+ if (!(IsListEmpty(&connection->AddressList))) {
+ DbgPrint ("NBF: C %lx, new A %lx, in use\n",
+ connection, addressFile->Address);
+ DbgBreakPoint();
+ }
+#endif
+ InsertTailList (
+ &addressFile->Address->ConnectionDatabase,
+ &connection->AddressList);
+
+#if DBG
+ if (!(IsListEmpty(&connection->AddressFileList))) {
+ DbgPrint ("NBF: C %lx, new AF %lx, in use\n",
+ connection, addressFile);
+ DbgBreakPoint();
+ }
+#endif
+ InsertTailList (
+ &addressFile->ConnectionDatabase,
+ &connection->AddressFileList);
+
+ connection->AddressFile = addressFile;
+ connection->Flags2 |= CONNECTION_FLAGS2_ASSOCIATED;
+ connection->Flags2 &= ~CONNECTION_FLAGS2_DISASSOCIATED;
+
+ if (addressFile->ConnectIndicationInProgress) {
+ connection->Flags2 |= CONNECTION_FLAGS2_INDICATING;
+ }
+
+ status = STATUS_SUCCESS;
+
+ } else {
+
+ //
+ // The connection is closing, stop the
+ // association.
+ //
+
+ status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql2);
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DbgPrint ("NBF: Got exception 2 in NbfTdiAssociateAddress\n");
+ DbgBreakPoint();
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql2);
+
+ status = GetExceptionCode();
+ }
+
+ } else {
+
+ status = STATUS_INVALID_HANDLE; //BUGBUG: should this be more informative?
+ }
+
+ RELEASE_SPIN_LOCK (&addressFile->Address->SpinLock, oldirql);
+
+ NbfDereferenceAddress ("Temp associate", addressFile->Address, AREF_VERIFY);
+
+ } else {
+
+ status = STATUS_INVALID_HANDLE;
+ }
+
+ //
+ // Note that we don't keep a reference to this file object around.
+ // That's because the IO subsystem manages the object for us; we simply
+ // want to keep the association. We only use this association when the
+ // IO subsystem has asked us to close one of the file object, and then
+ // we simply remove the association.
+ //
+
+ ObDereferenceObject (fileObject);
+
+ } else {
+ status = STATUS_INVALID_HANDLE;
+ }
+
+ NbfDereferenceConnection ("Temp Ref Associate", connection, CREF_BY_ID);
+
+ return status;
+
+} /* TdiAssociateAddress */
+
+
+NTSTATUS
+NbfTdiDisassociateAddress(
+ IN PIRP Irp
+ )
+/*++
+
+Routine Description:
+
+ This routine performs the disassociation of the connection and the address
+ for the user. If the connection has not been stopped, it will be stopped
+ here.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ KIRQL oldirql;
+ PIO_STACK_LOCATION irpSp;
+ PTP_CONNECTION connection;
+ NTSTATUS status;
+// PDEVICE_CONTEXT DeviceContext;
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint0 ("TdiDisassociateAddress: Entered.\n");
+ }
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // If successful this adds a reference of type BY_ID.
+ //
+
+ status = NbfVerifyConnectionObject (connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ if ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) == 0) {
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ NbfStopConnection (connection, STATUS_LOCAL_DISCONNECT);
+ } else {
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ }
+
+ //
+ // and now we disassociate the address. This only removes
+ // the appropriate reference for the connection, the
+ // actually disassociation will be done later.
+ //
+ // The DISASSOCIATED flag is used to make sure that
+ // only one person removes this reference.
+ //
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) &&
+ ((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) {
+ connection->Flags2 |= CONNECTION_FLAGS2_DISASSOCIATED;
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ } else {
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ }
+
+ KeLowerIrql (oldirql);
+
+ NbfDereferenceConnection ("Temp use in Associate", connection, CREF_BY_ID);
+
+ return STATUS_SUCCESS;
+
+} /* TdiDisassociateAddress */
+
+
+
+NTSTATUS
+NbfTdiConnect(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiConnect request for the transport provider.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTP_CONNECTION connection;
+ KIRQL oldirql;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL parameters;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteAddress;
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint0 ("NbfTdiConnect: Entered.\n");
+ }
+
+ //
+ // is the file object a connection?
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // If successful this adds a reference of type BY_ID.
+ //
+
+ status = NbfVerifyConnectionObject (connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ parameters = (PTDI_REQUEST_KERNEL)(&irpSp->Parameters);
+
+ //
+ // Check that the remote is a Netbios address.
+ //
+
+ if (!NbfValidateTdiAddress(
+ parameters->RequestConnectionInformation->RemoteAddress,
+ parameters->RequestConnectionInformation->RemoteAddressLength)) {
+
+ NbfDereferenceConnection ("Invalid Address", connection, CREF_BY_ID);
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+ RemoteAddress = NbfParseTdiAddress((PTRANSPORT_ADDRESS)(parameters->RequestConnectionInformation->RemoteAddress), FALSE);
+
+ if (RemoteAddress == NULL) {
+
+ NbfDereferenceConnection ("Not Netbios", connection, CREF_BY_ID);
+ return STATUS_BAD_NETWORK_PATH;
+
+ }
+
+ //
+ // copy the called address someplace we can use it.
+ //
+
+ connection->CalledAddress.NetbiosNameType =
+ RemoteAddress->NetbiosNameType;
+
+ RtlCopyMemory(
+ connection->CalledAddress.NetbiosName,
+ RemoteAddress->NetbiosName,
+ 16);
+
+#ifdef notdef // RASAUTODIAL
+ if (fAcdLoadedG) {
+ KIRQL adirql;
+ BOOLEAN fEnabled;
+
+ //
+ // See if the automatic connection driver knows
+ // about this address before we search the
+ // network. If it does, we return STATUS_PENDING,
+ // and we will come back here via NbfRetryTdiConnect().
+ //
+ ACQUIRE_SPIN_LOCK(&AcdDriverG.SpinLock, &adirql);
+ fEnabled = AcdDriverG.fEnabled;
+ RELEASE_SPIN_LOCK(&AcdDriverG.SpinLock, adirql);
+ if (fEnabled && NbfAttemptAutoDial(
+ connection,
+ ACD_NOTIFICATION_PRECONNECT,
+ NbfRetryPreTdiConnect,
+ Irp))
+ {
+ ACQUIRE_SPIN_LOCK(&connection->SpinLock, &oldirql);
+ connection->Flags2 |= CONNECTION_FLAGS2_AUTOCONNECT;
+ connection->Status = STATUS_PENDING;
+ RELEASE_SPIN_LOCK(&connection->SpinLock, oldirql);
+ NbfDereferenceConnection ("Automatic connection", connection, CREF_BY_ID);
+ //
+ // Set a special cancel routine on the irp
+ // in case we get cancelled during the
+ // automatic connection.
+ //
+ IoSetCancelRoutine(Irp, NbfCancelPreTdiConnect);
+ return STATUS_PENDING;
+ }
+ }
+#endif // RASAUTODIAL
+
+ return NbfTdiConnectCommon(Irp);
+} // NbfTdiConnect
+
+
+
+NTSTATUS
+NbfTdiConnectCommon(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiConnect request for the transport provider.
+ Note: the caller needs to call NbfVerifyConnectionObject(pConnection)
+ before calling this routine.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTP_CONNECTION connection;
+ LARGE_INTEGER timeout = {0,0};
+ KIRQL oldirql, cancelirql;
+ PTP_REQUEST tpRequest;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL parameters;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteAddress;
+ ULONG NameQueryTimeout;
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint0 ("NbfTdiConnectCommon: Entered.\n");
+ }
+
+ //
+ // is the file object a connection?
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+ connection = irpSp->FileObject->FsContext;
+ parameters = (PTDI_REQUEST_KERNEL)(&irpSp->Parameters);
+
+ //
+ // fix up the timeout if required; no connect request should take more
+ // than 15 seconds if there is someone out there. We'll assume that's
+ // what the user wanted if they specify -1 as the timer length.
+ //
+
+ if (parameters->RequestSpecific != NULL) {
+ if ((((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart == -1) &&
+ (((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart == -1)) {
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint1 ("TdiConnect: Modifying user timeout to %lx seconds.\n",
+ TDI_TIMEOUT_CONNECT);
+ }
+
+ timeout.LowPart = (ULONG)(-TDI_TIMEOUT_CONNECT * 10000000L); // n * 10 ** 7 => 100ns units
+ if (timeout.LowPart != 0) {
+ timeout.HighPart = -1L;
+ } else {
+ timeout.HighPart = 0;
+ }
+
+ } else {
+
+ timeout.LowPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart;
+ timeout.HighPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart;
+ }
+ }
+
+ //
+ // We need a request object to keep track of this TDI request.
+ // Attach this request to the new connection object.
+ //
+
+ status = NbfCreateRequest (
+ Irp, // IRP for this request.
+ connection, // context.
+ REQUEST_FLAGS_CONNECTION, // partial flags.
+ NULL,
+ 0,
+ timeout,
+ &tpRequest);
+
+ if (!NT_SUCCESS (status)) { // couldn't make the request.
+ NbfDereferenceConnection ("Throw away", connection, CREF_BY_ID);
+ return status; // return with failure.
+ } else {
+
+ // Reference the connection since NbfDestroyRequest derefs it.
+
+ NbfReferenceConnection("For connect request", connection, CREF_REQUEST);
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ tpRequest->Owner = ConnectionType;
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ if ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) != 0) {
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ IoReleaseCancelSpinLock (cancelirql);
+ NbfCompleteRequest (
+ tpRequest,
+ connection->Status,
+ 0);
+ KeLowerIrql (oldirql);
+ NbfDereferenceConnection("Temporary Use 1", connection, CREF_BY_ID);
+ return STATUS_PENDING;
+ } else {
+ InsertTailList (&connection->InProgressRequest,&tpRequest->Linkage);
+
+ //
+ // Initialize this now, we cut these down on an async medium
+ // that is disconnected.
+ //
+
+ connection->Retries = (USHORT)connection->Provider->NameQueryRetries;
+ NameQueryTimeout = connection->Provider->NameQueryTimeout;
+
+ if (connection->Provider->MacInfo.MediumAsync) {
+
+ //
+ // If we are on an async medium, then we need to send out
+ // a committed NAME_QUERY frame right from the start, since
+ // the FIND_NAME frames are not forwarded by the gateway.
+ //
+
+ connection->Flags2 |= (CONNECTION_FLAGS2_CONNECTOR | // we're the initiator.
+ CONNECTION_FLAGS2_WAIT_NR); // wait for NAME_RECOGNIZED.
+
+ //
+ // Because we may call NbfTdiConnect twice
+ // via an automatic connection, check to see
+ // if an LSN has already been assigned.
+ //
+ if (!(connection->Flags2 & CONNECTION_FLAGS2_GROUP_LSN)) {
+ connection->Flags2 |= CONNECTION_FLAGS2_GROUP_LSN;
+
+ if (NbfAssignGroupLsn(connection) != STATUS_SUCCESS) {
+
+ //
+ // Could not find an empty LSN; have to fail.
+ //
+ RemoveEntryList(&tpRequest->Linkage);
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ IoReleaseCancelSpinLock (cancelirql);
+ NbfCompleteRequest (
+ tpRequest,
+ connection->Status,
+ 0);
+ KeLowerIrql (oldirql);
+ NbfDereferenceConnection("Temporary Use 1", connection, CREF_BY_ID);
+ return STATUS_PENDING;
+
+ }
+ }
+
+ if (!connection->Provider->MediumSpeedAccurate) {
+
+ //
+ // The link is not up, so we cut our timeouts down.
+ // We still send one frame so that loopback works.
+ //
+
+ connection->Retries = 1;
+ NameQueryTimeout = NAME_QUERY_TIMEOUT / 10;
+
+ }
+
+ } else {
+
+ //
+ // Normal connection, we send out a FIND_NAME first.
+ //
+
+ connection->Flags2 |= (CONNECTION_FLAGS2_CONNECTOR | // we're the initiator.
+ CONNECTION_FLAGS2_WAIT_NR_FN); // wait for NAME_RECOGNIZED.
+
+ }
+
+ connection->Flags2 &= ~(CONNECTION_FLAGS2_STOPPING |
+ CONNECTION_FLAGS2_INDICATING);
+ connection->Status = STATUS_PENDING;
+
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ //
+ // Check if the IRP has been cancelled.
+ //
+
+ if (Irp->Cancel) {
+ Irp->CancelIrql = cancelirql;
+ NbfCancelConnection((PDEVICE_OBJECT)(connection->Provider), Irp);
+ KeLowerIrql (oldirql);
+ NbfDereferenceConnection ("IRP cancelled", connection, CREF_BY_ID); // release lookup hold.
+ return STATUS_PENDING;
+ }
+
+ IoSetCancelRoutine(Irp, NbfCancelConnection);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ }
+ }
+
+
+ //
+ // On "easily disconnected" networks, quick reregister
+ // (one ADD_NAME_QUERY) the address if NEED_REREGISTER
+ // is set (happens when we get a five-second period
+ // with no multicast activity). If we are currently
+ // quick reregistering, wait for it to complete.
+ //
+
+ if (connection->Provider->EasilyDisconnected) {
+
+ PTP_ADDRESS Address;
+ LARGE_INTEGER Timeout;
+
+ //
+ // If the address needs (or is) reregistering, then do wait,
+ // setting a flag so the connect will be resumed when the
+ // reregistration times out.
+ //
+
+ Address = connection->AddressFile->Address;
+
+ ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ if ((Address->Flags &
+ (ADDRESS_FLAGS_NEED_REREGISTER | ADDRESS_FLAGS_QUICK_REREGISTER)) != 0) {
+
+ connection->Flags2 |= CONNECTION_FLAGS2_W_ADDRESS;
+
+ if (Address->Flags & ADDRESS_FLAGS_NEED_REREGISTER) {
+
+ Address->Flags &= ~ADDRESS_FLAGS_NEED_REREGISTER;
+ Address->Flags |= ADDRESS_FLAGS_QUICK_REREGISTER;
+
+ NbfReferenceAddress ("start registration", Address, AREF_TIMER);
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ //
+ // Now start reregistration process by starting up a retransmission timer
+ // and begin sending ADD_NAME_QUERY NetBIOS frames.
+ //
+
+ Address->Retries = 1;
+ Timeout.LowPart = (ULONG)(-(LONG)Address->Provider->AddNameQueryTimeout);
+ Timeout.HighPart = -1;
+ KeSetTimer (&Address->Timer, *(PTIME)&Timeout, &Address->Dpc);
+
+ (VOID)NbfSendAddNameQuery (Address); // send first ADD_NAME_QUERY.
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ }
+ KeLowerIrql (oldirql);
+
+ NbfDereferenceConnection("Temporary Use 4", connection, CREF_BY_ID);
+
+ return STATUS_PENDING; // things are started.
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ }
+
+ }
+
+ //
+ // Send the NAME_QUERY frame as a FIND.NAME to get a NAME_RECOGNIZED
+ // frame back. The first time we send this frame, we are just looking
+ // for the data link information to decide whether we already have
+ // a link with the remote NetBIOS name. If we do, we can reuse it.
+ // If we don't, then we make one first, and then use it. A consequence
+ // of this is that we really engage in an extra non-committal NQ/NR
+ // exchange up front to locate the remote guy, and then commit to an actual
+ // LSN with a second NQ/NR sequence to establish the transport connection
+ //
+
+ NbfSendNameQuery (
+ connection,
+ TRUE);
+
+ //
+ // Start the connection timer (do this at the end, so that
+ // if we get delayed in this routine the connection won't
+ // get into an unexpected state).
+ //
+
+ NbfStartConnectionTimer (
+ connection,
+ ConnectionEstablishmentTimeout,
+ NameQueryTimeout);
+
+ KeLowerIrql (oldirql);
+
+ NbfDereferenceConnection("Temporary Use 3", connection, CREF_BY_ID);
+
+ return STATUS_PENDING; // things are started.
+
+} /* TdiConnect */
+
+
+
+NTSTATUS
+NbfTdiDisconnect(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiDisconnect request for the transport provider.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_CONNECTION connection;
+ LARGE_INTEGER timeout;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL parameters;
+ KIRQL oldirql;
+ NTSTATUS status;
+
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint0 ("TdiDisconnect: Entered.\n");
+ }
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // If successful this adds a reference of type BY_ID.
+ //
+
+ status = NbfVerifyConnectionObject (connection);
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+#if DBG
+ if (NbfDisconnectDebug) {
+ STRING remoteName;
+ STRING localName;
+ remoteName.Length = NETBIOS_NAME_LENGTH - 1;
+ remoteName.Buffer = connection->RemoteName;
+ localName.Length = NETBIOS_NAME_LENGTH - 1;
+ localName.Buffer = connection->AddressFile->Address->NetworkName->NetbiosName;
+ NbfPrint2( "TdiDisconnect entered for connection to %S from %S\n",
+ &remoteName, &localName );
+ }
+#endif
+
+ //
+ // if the connection is currently stopping, there's no reason to blow
+ // it away...
+ //
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) != 0) {
+#if 0
+ NbfPrint2 ("TdiDisconnect: ignoring disconnect %lx, connection stopping (%lx)\n",
+ connection, connection->Status);
+#endif
+
+ //
+ // In case a connect indication is in progress.
+ //
+
+ connection->Flags2 |= CONNECTION_FLAGS2_DISCONNECT;
+
+ //
+ // If possible, queue the disconnect. This flag is cleared
+ // when the indication is about to be done.
+ //
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_REQ_COMPLETED) &&
+ (connection->Flags2 & CONNECTION_FLAGS2_LDISC) == 0) {
+#if DBG
+ DbgPrint ("NBF: Queueing disconnect irp %lx\n", Irp);
+#endif
+ connection->Flags2 |= CONNECTION_FLAGS2_LDISC;
+ status = STATUS_SUCCESS;
+ } else {
+ status = connection->Status;
+ }
+
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ KeLowerIrql (oldirql);
+ NbfDereferenceConnection ("Ignoring disconnect", connection, CREF_BY_ID); // release our lookup reference.
+ return status;
+
+ }
+
+ connection->Flags2 &= ~ (CONNECTION_FLAGS2_ACCEPTED |
+ CONNECTION_FLAGS2_PRE_ACCEPT |
+ CONNECTION_FLAGS2_WAITING_SC);
+
+ connection->Flags2 |= CONNECTION_FLAGS2_DISCONNECT;
+ connection->Flags2 |= CONNECTION_FLAGS2_LDISC;
+
+ //
+ // Set this flag so the disconnect IRP is completed.
+ //
+ // BUGBUG: If the connection goes down before we can
+ // call NbfStopConnection with STATUS_LOCAL_DISCONNECT,
+ // the disconnect IRP won't get completed.
+ //
+
+ connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+
+// connection->DisconnectIrp = Irp;
+
+ //
+ // fix up the timeout if required; no disconnect request should take very
+ // long. However, the user can cause the timeout to not happen if they
+ // desire that.
+ //
+
+ parameters = (PTDI_REQUEST_KERNEL)(&irpSp->Parameters);
+
+ //
+ // fix up the timeout if required; no disconnect request should take more
+ // than 15 seconds. We'll assume that's what the user wanted if they
+ // specify -1 as the timer.
+ //
+
+ if (parameters->RequestSpecific != NULL) {
+ if ((((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart == -1) &&
+ (((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart == -1)) {
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint1 ("TdiDisconnect: Modifying user timeout to %lx seconds.\n",
+ TDI_TIMEOUT_CONNECT);
+ }
+
+ timeout.LowPart = (ULONG)(-TDI_TIMEOUT_DISCONNECT * 10000000L); // n * 10 ** 7 => 100ns units
+ if (timeout.LowPart != 0) {
+ timeout.HighPart = -1L;
+ } else {
+ timeout.HighPart = 0;
+ }
+
+ } else {
+ timeout.LowPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart;
+ timeout.HighPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart;
+ }
+ }
+
+ //
+ // Now the reason for the disconnect
+ //
+
+ if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_RELEASE) {
+ connection->Flags2 |= CONNECTION_FLAGS2_DESTROY;
+ } else if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_ABORT) {
+ connection->Flags2 |= CONNECTION_FLAGS2_ABORT;
+ } else if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_WAIT) {
+ connection->Flags2 |= CONNECTION_FLAGS2_ORDREL;
+ }
+
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint1 ("TdiDisconnect calling NbfStopConnection %lx\n", connection);
+ }
+
+ //
+ // This will get passed to IoCompleteRequest during TdiDestroyConnection
+ //
+
+ NbfStopConnection (connection, STATUS_LOCAL_DISCONNECT); // starts the abort sequence.
+
+ KeLowerIrql (oldirql);
+
+ NbfDereferenceConnection ("Disconnecting", connection, CREF_BY_ID); // release our lookup reference.
+
+ //
+ // This request will be completed by TdiDestroyConnection once
+ // the connection reference count drops to 0.
+ //
+
+ return STATUS_SUCCESS;
+} /* TdiDisconnect */
+
+
+NTSTATUS
+NbfTdiListen(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiListen request for the transport provider.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTP_CONNECTION connection;
+ LARGE_INTEGER timeout = {0,0};
+ KIRQL oldirql, cancelirql;
+ PTP_REQUEST tpRequest;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL_LISTEN parameters;
+ PTDI_CONNECTION_INFORMATION ListenInformation;
+ TDI_ADDRESS_NETBIOS UNALIGNED * ListenAddress;
+ PVOID RequestBuffer2;
+ ULONG RequestBuffer2Length;
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint0 ("TdiListen: Entered.\n");
+ }
+
+ //
+ // validate this connection
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // If successful this adds a reference of type BY_ID.
+ //
+
+ status = NbfVerifyConnectionObject (connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ parameters = (PTDI_REQUEST_KERNEL_LISTEN)&irpSp->Parameters;
+
+ //
+ // Record the remote address if there is one.
+ //
+
+ ListenInformation = parameters->RequestConnectionInformation;
+
+ if ((ListenInformation != NULL) &&
+ (ListenInformation->RemoteAddress != NULL)) {
+
+ if ((NbfValidateTdiAddress(
+ ListenInformation->RemoteAddress,
+ ListenInformation->RemoteAddressLength)) &&
+ ((ListenAddress = NbfParseTdiAddress(ListenInformation->RemoteAddress, FALSE)) != NULL)) {
+
+ RequestBuffer2 = (PVOID)ListenAddress->NetbiosName,
+ RequestBuffer2Length = NETBIOS_NAME_LENGTH;
+
+ } else {
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint0 ("TdiListen: Create Request Failed, bad address.\n");
+ }
+
+ NbfDereferenceConnection ("Bad address", connection, CREF_BY_ID);
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+ } else {
+
+ RequestBuffer2 = NULL;
+ RequestBuffer2Length = 0;
+ }
+
+ //
+ // We need a request object to keep track of this TDI request.
+ // Attach this request to the new connection object.
+ //
+
+ status = NbfCreateRequest (
+ Irp, // IRP for this request.
+ connection, // context.
+ REQUEST_FLAGS_CONNECTION, // partial flags.
+ RequestBuffer2,
+ RequestBuffer2Length,
+ timeout, // timeout value (can be 0).
+ &tpRequest);
+
+
+ if (!NT_SUCCESS (status)) { // couldn't make the request.
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint1 ("TdiListen: Create Request Failed, reason: %lx.\n", status);
+ }
+
+ NbfDereferenceConnection ("For create", connection, CREF_BY_ID);
+ return status; // return with failure.
+ }
+
+ // Reference the connection since NbfDestroyRequest derefs it.
+
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_C_SPIN_LOCK (&connection->SpinLock, &oldirql);
+ tpRequest->Owner = ConnectionType;
+
+ NbfReferenceConnection("For listen request", connection, CREF_REQUEST);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) != 0) {
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock,oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ NbfCompleteRequest (
+ tpRequest,
+ connection->Status,
+ 0);
+ NbfDereferenceConnection("Temp create", connection, CREF_BY_ID);
+ return STATUS_PENDING;
+
+ } else {
+
+ InsertTailList (&connection->InProgressRequest,&tpRequest->Linkage);
+ connection->Flags2 |= (CONNECTION_FLAGS2_LISTENER | // we're the passive one.
+ CONNECTION_FLAGS2_WAIT_NQ); // wait for NAME_QUERY.
+ connection->Flags2 &= ~(CONNECTION_FLAGS2_INDICATING |
+ CONNECTION_FLAGS2_STOPPING);
+ connection->Status = STATUS_PENDING;
+
+ //
+ // If TDI_QUERY_ACCEPT is not set, then we set PRE_ACCEPT to
+ // indicate that when the listen completes we do not have to
+ // wait for a TDI_ACCEPT to continue.
+ //
+
+ if ((parameters->RequestFlags & TDI_QUERY_ACCEPT) == 0) {
+ connection->Flags2 |= CONNECTION_FLAGS2_PRE_ACCEPT;
+ }
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock,oldirql);
+
+ //
+ // Check if the IRP has been cancelled.
+ //
+
+ if (Irp->Cancel) {
+ Irp->CancelIrql = cancelirql;
+ NbfCancelConnection((PDEVICE_OBJECT)(connection->Provider), Irp);
+ NbfDereferenceConnection ("IRP cancelled", connection, CREF_BY_ID); // release lookup hold.
+ return STATUS_PENDING;
+ }
+
+ IoSetCancelRoutine(Irp, NbfCancelConnection);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ }
+
+ //
+ // Wait for an incoming NAME_QUERY frame. The remainder of the
+ // connectionless protocol to set up a connection is processed
+ // in the NAME_QUERY frame handler.
+ //
+
+ NbfDereferenceConnection("Temp create", connection, CREF_BY_ID);
+
+ return STATUS_PENDING; // things are started.
+} /* TdiListen */
+
+
+NTSTATUS
+NbfOpenConnection (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to open a connection. Note that the connection that
+ is open is of little use until associated with an address; until then,
+ the only thing that can be done with it is close it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+ IrpSp - Pointer to current IRP stack frame.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ NTSTATUS status;
+ PTP_CONNECTION connection;
+ PFILE_FULL_EA_INFORMATION ea;
+
+ UNREFERENCED_PARAMETER (Irp);
+
+ //
+ // BUGBUG: check ea to make sure it's correct
+ //
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint0 ("NbfOpenConnection: Entered.\n");
+ }
+
+ DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+
+ //
+ // First, try to make a connection object to represent this pending
+ // connection. Then fill in the relevant fields.
+ // In addition to the creation, if successful NbfCreateConnection
+ // will create a second reference which is removed once the request
+ // references the connection, or if the function exits before that.
+
+ status = NbfCreateConnection (DeviceContext, &connection);
+ if (!NT_SUCCESS (status)) {
+ return status; // sorry, we couldn't make one.
+ }
+
+ //
+ // set the connection context so we can connect the user to this data
+ // structure
+ //
+
+ ea = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+ RtlCopyMemory (
+ &connection->Context,
+ &ea->EaName[ea->EaNameLength+1],
+ sizeof (PVOID));
+
+ //
+ // let file object point at connection and connection at file object
+ //
+
+ IrpSp->FileObject->FsContext = (PVOID)connection;
+ IrpSp->FileObject->FsContext2 = (PVOID)TDI_CONNECTION_FILE;
+ connection->FileObject = IrpSp->FileObject;
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint1 ("NBFOpenConnection: Opened Connection %lx.\n",
+ connection);
+ }
+
+ return status;
+
+} /* NbfOpenConnection */
+
+#if DBG
+VOID
+ConnectionCloseTimeout(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+
+{
+ PTP_CONNECTION Connection;
+
+ Dpc, SystemArgument1, SystemArgument2; // prevent compiler warnings
+
+ Connection = (PTP_CONNECTION)DeferredContext;
+
+ DbgPrint ("NBF: Close of connection %lxpending for 2 minutes\n", Connection);
+ DbgBreakPoint();
+
+}
+#endif
+
+
+NTSTATUS
+NbfCloseConnection (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to close a connection. There may be actions in
+ progress on this connection, so we note the closing IRP, mark the
+ connection as closing, and complete it somewhere down the road (when all
+ references have been removed).
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+ IrpSp - Pointer to current IRP stack frame.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ KIRQL oldirql;
+ PTP_CONNECTION connection;
+
+ UNREFERENCED_PARAMETER (DeviceObject);
+ UNREFERENCED_PARAMETER (Irp);
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint0 ("NbfCloseConnection: Entered.\n");
+ }
+
+ //
+ // is the file object a connection?
+ //
+
+ connection = IrpSp->FileObject->FsContext;
+
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ //
+ // We duplicate the code from VerifyConnectionObject,
+ // although we don't actually call that since it does
+ // a reference, which we don't want (to avoid bouncing
+ // the reference count up from 0 if this is a dead
+ // link).
+ //
+
+ try {
+
+ if ((connection->Size == sizeof (TP_CONNECTION)) &&
+ (connection->Type == NBF_CONNECTION_SIGNATURE)) {
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) {
+
+ status = STATUS_SUCCESS;
+
+ } else {
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ } else {
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ KeLowerIrql (oldirql);
+ return GetExceptionCode();
+ }
+
+ if (!NT_SUCCESS (status)) {
+ KeLowerIrql (oldirql);
+ return status;
+ }
+
+ //
+ // We recognize it; is it closing already?
+ //
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) != 0) {
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ KeLowerIrql (oldirql);
+#if DBG
+ NbfPrint1("Closing already-closing connection %lx\n", connection);
+#endif
+ return STATUS_INVALID_CONNECTION;
+ }
+
+ connection->Flags2 |= CONNECTION_FLAGS2_CLOSING;
+
+ //
+ // if there is activity on the connection, tear it down.
+ //
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) == 0) {
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ NbfStopConnection (connection, STATUS_LOCAL_DISCONNECT);
+ ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ }
+
+ //
+ // If the connection is still associated, disassociate it.
+ //
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) &&
+ ((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) {
+ connection->Flags2 |= CONNECTION_FLAGS2_DISASSOCIATED;
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ } else {
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ }
+
+ //
+ // Save this to complete the IRP later.
+ //
+
+ connection->CloseIrp = Irp;
+
+#if 0
+ //
+ // make it impossible to use this connection from the file object
+ //
+
+ IrpSp->FileObject->FsContext = NULL;
+ IrpSp->FileObject->FsContext2 = NULL;
+ connection->FileObject = NULL;
+#endif
+
+#if DBG
+ {
+ LARGE_INTEGER Timeout;
+ BOOLEAN AlreadyInserted;
+
+ Timeout.LowPart = (ULONG)(-(120*SECONDS));
+ Timeout.HighPart = -1;
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ AlreadyInserted = KeCancelTimer (&connection->Timer);
+
+ KeInitializeDpc (
+ &connection->Dpc,
+ ConnectionCloseTimeout,
+ (PVOID)connection);
+
+ KeSetTimer (
+ &connection->Timer,
+ Timeout,
+ &connection->Dpc);
+
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ if (AlreadyInserted) {
+ DbgPrint ("NBF: Cancelling connection timer for debug %lx\n", connection);
+ NbfDereferenceConnection ("debug", connection, CREF_TIMER);
+ }
+
+ }
+#endif
+
+ KeLowerIrql (oldirql);
+
+ //
+ // dereference for the creation. Note that this dereference
+ // here won't have any effect until the regular reference count
+ // hits zero.
+ //
+
+ NbfDereferenceConnectionSpecial (" Closing Connection", connection, CREF_SPECIAL_CREATION);
+
+ return STATUS_PENDING;
+
+} /* NbfCloseConnection */
+
+
diff --git a/private/ntos/tdi/nbf/connobj.c b/private/ntos/tdi/nbf/connobj.c
new file mode 100644
index 000000000..1e7e9221b
--- /dev/null
+++ b/private/ntos/tdi/nbf/connobj.c
@@ -0,0 +1,2413 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ connobj.c
+
+Abstract:
+
+ This module contains code which implements the TP_CONNECTION object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport connection objects.
+
+ A word about connection reference counts:
+
+ With TDI version 2, connections live on even after they have been stopped.
+ This necessitated changing the way NBF handles connection reference counts,
+ making the stopping of a connection only another way station in the life
+ of a connection, rather than its demise. Reference counts now work like
+ this:
+
+ Connection State Reference Count Flags
+ ------------------ ----------------- --------
+ Opened, no activity 1 0
+ Open, Associated 2 FLAGS2_ASSOCIATED
+ Open, Assoc., Connected 3 FLAGS_READY
+ Above + activity >3 varies
+ Open, Assoc., Stopping >3 FLAGS_STOPPING
+ Open, Assoc., Stopped 3 FLAGS_STOPPING
+ Open, Disassoc. Complete 2 FLAGS_STOPPING
+ FLAGS2_ASSOCIATED == 0
+ Closing 1 FLAGS2_CLOSING
+ Closed 0 FLAGS2_CLOSING
+
+ Note that keeping the stopping flag set when the connection has fully
+ stopped avoids using the connection until it is connected again; the
+ CLOSING flag serves the same purpose. This allows a connection to run
+ down in its own time.
+
+
+Author:
+
+ David Beaver (dbeaver) 1 July 1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef RASAUTODIAL
+#include <acd.h>
+#include <acdapi.h>
+#endif // RASAUTODIAL
+
+#ifdef RASAUTODIAL
+extern BOOLEAN fAcdLoadedG;
+extern ACD_DRIVER AcdDriverG;
+
+//
+// Imported routines
+//
+BOOLEAN
+NbfAttemptAutoDial(
+ IN PTP_CONNECTION Connection,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN PVOID pArg
+ );
+
+VOID
+NbfRetryTdiConnect(
+ IN BOOLEAN fSuccess,
+ IN PVOID *pArgs
+ );
+
+BOOLEAN
+NbfCancelTdiConnect(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ );
+#endif // RASAUTODIAL
+
+
+
+VOID
+ConnectionEstablishmentTimeout(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is executed as a DPC at DISPATCH_LEVEL when the timeout
+ period for the NAME_QUERY/NAME_RECOGNIZED protocol expires. The retry
+ count in the Connection object is decremented, and if it reaches 0,
+ the connection is aborted. If the retry count has not reached zero,
+ then the NAME QUERY is retried. The following cases are covered by
+ this routine:
+
+ 1. Initial NAME_QUERY timeout for find_name portion of connection setup.
+
+ NQ(find_name) ------------------->
+ [TIMEOUT]
+ NQ(find_name) ------------------->
+ <------------------- NR(find_name)
+
+ 2. Secondary NAME_QUERY timeout for connection setup.
+
+ NQ(connection) ------------------->
+ [TIMEOUT]
+ NQ(connection) ------------------->
+ <------------------- NR(connection)
+
+ There is another case where the data link connection does not get
+ established within a reasonable amount of time. This is handled by
+ the link layer routines.
+
+Arguments:
+
+ Dpc - Pointer to a system DPC object.
+
+ DeferredContext - Pointer to the TP_CONNECTION block representing the
+ request that has timed out.
+
+ SystemArgument1 - Not used.
+
+ SystemArgument2 - Not used.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PTP_CONNECTION Connection;
+
+ Dpc, SystemArgument1, SystemArgument2; // prevent compiler warnings
+
+ ENTER_NBF;
+
+ Connection = (PTP_CONNECTION)DeferredContext;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint1 ("ConnectionEstablishmentTimeout: Entered for connection %lx.\n",
+ Connection);
+ }
+
+ //
+ // If this connection is being run down, then we can't do anything.
+ //
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ if (Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) {
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ NbfDereferenceConnection ("Connect timed out", Connection, CREF_TIMER);
+ LEAVE_NBF;
+ return;
+ }
+
+
+ if (Connection->Flags2 & (CONNECTION_FLAGS2_WAIT_NR_FN | CONNECTION_FLAGS2_WAIT_NR)) {
+
+ //
+ // We are waiting for a commital or non-commital NAME_RECOGNIZED frame.
+ // Decrement the retry count, and possibly resend the NAME_QUERY.
+ //
+
+ if (--(Connection->Retries) == 0) { // if retry count exhausted.
+
+ NTSTATUS StopStatus;
+
+ //
+ // See if we got a no listens response, or just
+ // nothing.
+ //
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_NO_LISTEN) != 0) {
+
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_NO_LISTEN;
+ StopStatus = STATUS_REMOTE_NOT_LISTENING; // no listens
+
+ } else {
+
+ StopStatus = STATUS_BAD_NETWORK_PATH; // name not found.
+
+ }
+
+#ifdef RASAUTODIAL
+ //
+ // If this is a connect operation that has
+ // returned with STATUS_BAD_NETWORK_PATH, then
+ // attempt to create an automatic connection.
+ //
+ if (fAcdLoadedG &&
+ StopStatus == STATUS_BAD_NETWORK_PATH)
+ {
+ KIRQL adirql;
+ BOOLEAN fEnabled;
+
+ ACQUIRE_SPIN_LOCK(&AcdDriverG.SpinLock, &adirql);
+ fEnabled = AcdDriverG.fEnabled;
+ RELEASE_SPIN_LOCK(&AcdDriverG.SpinLock, adirql);
+ if (fEnabled && NbfAttemptAutoDial(
+ Connection,
+ 0,
+ NbfRetryTdiConnect,
+ Connection))
+ {
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ goto done;
+ }
+ }
+#endif // RASAUTODIAL
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ NbfStopConnection (Connection, StopStatus);
+
+ } else {
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ //
+ // We make source routing optional on every second
+ // name query (whenever Retries is even).
+ //
+
+ NbfSendNameQuery (
+ Connection,
+ (BOOLEAN)((Connection->Retries & 1) ? FALSE : TRUE));
+
+ NbfStartConnectionTimer (
+ Connection,
+ ConnectionEstablishmentTimeout,
+ Connection->Provider->NameQueryTimeout);
+
+ }
+
+ } else {
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ }
+
+
+ //
+ // Dereference the connection, to account for the fact that the
+ // timer went off. Note that if we restarted the timer using
+ // NbfStartConnectionTimer, the reference count has already been
+ // incremented to account for the new timer.
+ //
+
+done:
+ NbfDereferenceConnection ("Timer timed out",Connection, CREF_TIMER);
+
+ LEAVE_NBF;
+ return;
+
+} /* ConnectionEstablishmentTimeout */
+
+
+VOID
+NbfAllocateConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_CONNECTION *TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for a transport connection. Some
+ minimal initialization is done.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - the device context for this connection to be
+ associated with.
+
+ TransportConnection - Pointer to a place where this routine will
+ return a pointer to a transport connection structure. Returns
+ NULL if the storage cannot be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PTP_CONNECTION Connection;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + sizeof(TP_CONNECTION)) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("NBF: Could not allocate connection: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 103,
+ sizeof(TP_CONNECTION),
+ CONNECTION_RESOURCE_ID);
+ *TransportConnection = NULL;
+ return;
+ }
+
+ Connection = (PTP_CONNECTION)ExAllocatePoolWithTag (
+ NonPagedPool,
+ sizeof (TP_CONNECTION),
+ 'cFBN');
+ if (Connection == NULL) {
+ PANIC("NBF: Could not allocate connection: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 203,
+ sizeof(TP_CONNECTION),
+ CONNECTION_RESOURCE_ID);
+ *TransportConnection = NULL;
+ return;
+ }
+ RtlZeroMemory (Connection, sizeof(TP_CONNECTION));
+
+ DeviceContext->MemoryUsage += sizeof(TP_CONNECTION);
+ ++DeviceContext->ConnectionAllocated;
+
+ Connection->Type = NBF_CONNECTION_SIGNATURE;
+ Connection->Size = sizeof (TP_CONNECTION);
+
+ Connection->Provider = DeviceContext;
+ Connection->ProviderInterlock = &DeviceContext->Interlock;
+ KeInitializeSpinLock (&Connection->SpinLock);
+ KeInitializeDpc (
+ &Connection->Dpc,
+ ConnectionEstablishmentTimeout,
+ (PVOID)Connection);
+ KeInitializeTimer (&Connection->Timer);
+
+
+ InitializeListHead (&Connection->LinkList);
+ InitializeListHead (&Connection->AddressFileList);
+ InitializeListHead (&Connection->AddressList);
+ InitializeListHead (&Connection->PacketWaitLinkage);
+ InitializeListHead (&Connection->PacketizeLinkage);
+ InitializeListHead (&Connection->SendQueue);
+ InitializeListHead (&Connection->ReceiveQueue);
+ InitializeListHead (&Connection->InProgressRequest);
+ InitializeListHead (&Connection->DeferredQueue);
+
+ NbfAddSendPacket (DeviceContext);
+ NbfAddSendPacket (DeviceContext);
+ NbfAddUIFrame (DeviceContext);
+
+ *TransportConnection = Connection;
+
+} /* NbfAllocateConnection */
+
+
+VOID
+NbfDeallocateConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for a transport connection.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - the device context for this connection to be
+ associated with.
+
+ TransportConnection - Pointer to a transport connection structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ExFreePool (TransportConnection);
+ --DeviceContext->ConnectionAllocated;
+ DeviceContext->MemoryUsage -= sizeof(TP_CONNECTION);
+
+ NbfRemoveSendPacket (DeviceContext);
+ NbfRemoveSendPacket (DeviceContext);
+ NbfRemoveUIFrame (DeviceContext);
+
+} /* NbfDeallocateConnection */
+
+
+NTSTATUS
+NbfCreateConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_CONNECTION *TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a transport connection. The reference count in the
+ connection is automatically set to 1, and the reference count in the
+ DeviceContext is incremented.
+
+Arguments:
+
+ Address - the address for this connection to be associated with.
+
+ TransportConnection - Pointer to a place where this routine will
+ return a pointer to a transport connection structure.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_CONNECTION Connection;
+ KIRQL oldirql;
+ PLIST_ENTRY p;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint0 ("NbfCreateConnection: Entered.\n");
+ }
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ p = RemoveHeadList (&DeviceContext->ConnectionPool);
+ if (p == &DeviceContext->ConnectionPool) {
+
+ if ((DeviceContext->ConnectionMaxAllocated == 0) ||
+ (DeviceContext->ConnectionAllocated < DeviceContext->ConnectionMaxAllocated)) {
+
+ NbfAllocateConnection (DeviceContext, &Connection);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Allocated connection at %lx\n", Connection);
+ }
+
+ } else {
+
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 403,
+ sizeof(TP_CONNECTION),
+ CONNECTION_RESOURCE_ID);
+ Connection = NULL;
+
+ }
+
+ if (Connection == NULL) {
+ ++DeviceContext->ConnectionExhausted;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ PANIC ("NbfCreateConnection: Could not allocate connection object!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ } else {
+
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+#if DBG
+ InitializeListHead (p);
+#endif
+
+ }
+
+ ++DeviceContext->ConnectionInUse;
+ if (DeviceContext->ConnectionInUse > DeviceContext->ConnectionMaxInUse) {
+ ++DeviceContext->ConnectionMaxInUse;
+ }
+
+ DeviceContext->ConnectionTotal += DeviceContext->ConnectionInUse;
+ ++DeviceContext->ConnectionSamples;
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint1 ("NbfCreateConnection: Connection at %lx.\n", Connection);
+ }
+
+ //
+ // We have two references; one is for creation, and the
+ // other is a temporary one so that the connection won't
+ // go away before the creator has a chance to access it.
+ //
+
+ Connection->SpecialRefCount = 1;
+ Connection->ReferenceCount = -1; // this is -1 based
+
+#if DBG
+ {
+ UINT Counter;
+ for (Counter = 0; Counter < NUMBER_OF_CREFS; Counter++) {
+ Connection->RefTypes[Counter] = 0;
+ }
+
+ // This reference is removed by NbfCloseConnection
+
+ Connection->RefTypes[CREF_SPECIAL_CREATION] = 1;
+ }
+#endif
+
+ //
+ // Initialize the request queues & components of this connection.
+ //
+
+ InitializeListHead (&Connection->SendQueue);
+ InitializeListHead (&Connection->ReceiveQueue);
+ InitializeListHead (&Connection->InProgressRequest);
+ InitializeListHead (&Connection->AddressList);
+ InitializeListHead (&Connection->AddressFileList);
+ Connection->SpecialReceiveIrp = (PIRP)NULL;
+ Connection->Flags = 0;
+ Connection->Flags2 = 0;
+ Connection->DeferredFlags = 0;
+ Connection->Lsn = 0;
+ Connection->Rsn = 0;
+ Connection->Retries = 0; // no retries yet.
+ Connection->MessageBytesReceived = 0; // no data yet
+ Connection->MessageBytesAcked = 0;
+ Connection->MessageInitAccepted = 0;
+ Connection->ReceiveBytesUnaccepted = 0;
+ Connection->CurrentReceiveAckQueueable = FALSE;
+ Connection->CurrentReceiveSynchronous = FALSE;
+ Connection->ConsecutiveSends = 0;
+ Connection->ConsecutiveReceives = 0;
+ Connection->Link = NULL; // no datalink connection yet.
+ Connection->LinkSpinLock = NULL;
+ Connection->Context = NULL; // no context yet.
+ Connection->Status = STATUS_PENDING; // default NbfStopConnection status.
+ Connection->SendState = CONNECTION_SENDSTATE_IDLE;
+ Connection->CurrentReceiveIrp = (PIRP)NULL;
+ Connection->DisconnectIrp = (PIRP)NULL;
+ Connection->CloseIrp = (PIRP)NULL;
+ Connection->AddressFile = NULL;
+ Connection->IndicationInProgress = FALSE;
+ Connection->OnDataAckQueue = FALSE;
+ Connection->OnPacketWaitQueue = FALSE;
+ Connection->TransferBytesPending = 0;
+ Connection->TotalTransferBytesPending = 0;
+
+ RtlZeroMemory (&Connection->NetbiosHeader, sizeof(NBF_HDR_CONNECTION));
+
+#if DBG
+ Connection->Destroyed = FALSE;
+ Connection->TotalReferences = 0;
+ Connection->TotalDereferences = 0;
+ Connection->NextRefLoc = 0;
+ ExInterlockedInsertHeadList (&NbfGlobalConnectionList, &Connection->GlobalLinkage, &NbfGlobalInterlock);
+ StoreConnectionHistory (Connection, TRUE);
+#endif
+
+ //
+ // Now assign this connection an ID. This is used later to identify the
+ // connection across multiple processes.
+ //
+ // The high bit of the ID is not user, it is off for connection
+ // initiating NAME.QUERY frames and on for ones that are the result
+ // of a FIND.NAME request.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ Connection->ConnectionId = DeviceContext->UniqueIdentifier;
+ ++DeviceContext->UniqueIdentifier;
+ if (DeviceContext->UniqueIdentifier == 0x8000) {
+ DeviceContext->UniqueIdentifier = 1;
+ }
+
+ NbfReferenceDeviceContext ("Create Connection", DeviceContext, DCREF_CONNECTION);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ *TransportConnection = Connection; // return the connection.
+
+ return STATUS_SUCCESS;
+} /* NbfCreateConnection */
+
+
+NTSTATUS
+NbfVerifyConnectionObject (
+ IN PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to verify that the pointer given us in a file
+ object is in fact a valid connection object.
+
+Arguments:
+
+ Connection - potential pointer to a TP_CONNECTION object.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_CONNECTION otherwise
+
+--*/
+
+{
+ KIRQL oldirql;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ //
+ // try to verify the connection signature. If the signature is valid,
+ // get the connection spinlock, check its state, and increment the
+ // reference count if it's ok to use it. Note that being in the stopping
+ // state is an OK place to be and reference the connection; we can
+ // disassociate the address while running down.
+ //
+
+ try {
+
+ if ((Connection != (PTP_CONNECTION)NULL) &&
+ (Connection->Size == sizeof (TP_CONNECTION)) &&
+ (Connection->Type == NBF_CONNECTION_SIGNATURE)) {
+
+ ACQUIRE_C_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) {
+
+ NbfReferenceConnection ("Verify Temp Use", Connection, CREF_BY_ID);
+
+ } else {
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ } else {
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ return GetExceptionCode();
+ }
+
+ return status;
+
+}
+
+
+NTSTATUS
+NbfDestroyAssociation(
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys the association between a transport connection and
+ the address it was formerly associated with. The only action taken is
+ to disassociate the address and remove the connection from all address
+ queues.
+
+ This routine is only called by NbfDereferenceConnection. The reason for
+ this is that there may be multiple streams of execution which are
+ simultaneously referencing the same connection object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection structure to
+ be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql2;
+ PTP_ADDRESS_FILE addressFile;
+ BOOLEAN NotAssociated = FALSE;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint1 ("NbfDestroyAssociation: Entered for connection %lx.\n",
+ TransportConnection);
+ }
+
+ try {
+
+ ACQUIRE_C_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql2);
+ if ((TransportConnection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) == 0) {
+#if DBG
+ if (!(IsListEmpty(&TransportConnection->AddressList)) ||
+ !(IsListEmpty(&TransportConnection->AddressFileList))) {
+ DbgPrint ("NBF: C %lx, AF %lx, freed while still queued\n",
+ TransportConnection, TransportConnection->AddressFile);
+ DbgBreakPoint();
+ }
+#endif
+ RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
+ NotAssociated = TRUE;
+ } else {
+ TransportConnection->Flags2 &= ~CONNECTION_FLAGS2_ASSOCIATED;
+ RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DbgPrint ("NBF: Got exception 1 in NbfDestroyAssociation\n");
+ DbgBreakPoint();
+
+ RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
+ }
+
+ if (NotAssociated) {
+ return STATUS_SUCCESS;
+ }
+
+ addressFile = TransportConnection->AddressFile;
+
+ //
+ // Delink this connection from its associated address connection
+ // database. To do this we must spin lock on the address object as
+ // well as on the connection,
+ //
+
+ ACQUIRE_SPIN_LOCK (&addressFile->Address->SpinLock, &oldirql);
+
+ try {
+
+ ACQUIRE_C_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql2);
+ RemoveEntryList (&TransportConnection->AddressFileList);
+ RemoveEntryList (&TransportConnection->AddressList);
+
+ InitializeListHead (&TransportConnection->AddressList);
+ InitializeListHead (&TransportConnection->AddressFileList);
+
+ //
+ // remove the association between the address and the connection.
+ //
+
+ TransportConnection->AddressFile = NULL;
+
+ RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DbgPrint ("NBF: Got exception 2 in NbfDestroyAssociation\n");
+ DbgBreakPoint();
+
+ RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
+ }
+
+ RELEASE_SPIN_LOCK (&addressFile->Address->SpinLock, oldirql);
+
+ //
+ // and remove a reference to the address
+ //
+
+ NbfDereferenceAddress ("Destroy association", addressFile->Address, AREF_CONNECTION);
+
+
+ return STATUS_SUCCESS;
+
+} /* NbfDestroyAssociation */
+
+
+NTSTATUS
+NbfIndicateDisconnect(
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine indicates a remote disconnection on this connection if it
+ is necessary to do so. No other action is taken here.
+
+ This routine is only called by NbfDereferenceConnection. The reason for
+ this is that there may be multiple streams of execution which are
+ simultaneously referencing the same connection object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection structure to
+ be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_ADDRESS_FILE addressFile;
+ PDEVICE_CONTEXT DeviceContext;
+ ULONG DisconnectReason;
+ PIRP DisconnectIrp;
+ KIRQL oldirql;
+ ULONG Lflags2;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint1 ("NbfIndicateDisconnect: Entered for connection %lx.\n",
+ TransportConnection);
+ }
+
+ try {
+
+ ACQUIRE_C_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql);
+
+ if (((TransportConnection->Flags2 & CONNECTION_FLAGS2_REQ_COMPLETED) != 0)) {
+
+ ASSERT (TransportConnection->Lsn == 0);
+
+ //
+ // Turn off all but the still-relevant bits in the flags.
+ //
+
+ Lflags2 = TransportConnection->Flags2;
+ TransportConnection->Flags2 &=
+ (CONNECTION_FLAGS2_ASSOCIATED |
+ CONNECTION_FLAGS2_DISASSOCIATED |
+ CONNECTION_FLAGS2_CLOSING);
+ TransportConnection->Flags2 |= CONNECTION_FLAGS2_STOPPING;
+
+ //
+ // Clean up other stuff -- basically everything gets
+ // done here except for the flags and the status, since
+ // they are used to block other requests. When the connection
+ // is given back to us (in Accept, Connect, or Listen)
+ // they are cleared.
+ //
+
+ TransportConnection->NetbiosHeader.TransmitCorrelator = 0;
+ TransportConnection->Retries = 0; // no retries yet.
+ TransportConnection->MessageBytesReceived = 0; // no data yet
+ TransportConnection->MessageBytesAcked = 0;
+ TransportConnection->MessageInitAccepted = 0;
+ TransportConnection->ReceiveBytesUnaccepted = 0;
+ TransportConnection->ConsecutiveSends = 0;
+ TransportConnection->ConsecutiveReceives = 0;
+ TransportConnection->SendState = CONNECTION_SENDSTATE_IDLE;
+
+ TransportConnection->TransmittedTsdus = 0;
+ TransportConnection->ReceivedTsdus = 0;
+
+ TransportConnection->CurrentReceiveIrp = (PIRP)NULL;
+
+ DisconnectIrp = TransportConnection->DisconnectIrp;
+ TransportConnection->DisconnectIrp = (PIRP)NULL;
+
+ if ((TransportConnection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) != 0) {
+ addressFile = TransportConnection->AddressFile;
+ } else {
+ addressFile = NULL;
+ }
+
+ RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
+
+
+ DeviceContext = TransportConnection->Provider;
+
+
+ //
+ // If this connection was stopped by a call to TdiDisconnect,
+ // we have to complete that. We save the Irp so we can return
+ // the connection to the pool before we complete the request.
+ //
+
+
+ if (DisconnectIrp != (PIRP)NULL ||
+ (Lflags2 & CONNECTION_FLAGS2_LDISC) != 0) {
+
+ if (DisconnectIrp != (PIRP)NULL) {
+ IF_NBFDBG (NBF_DEBUG_SETUP) {
+ NbfPrint1("IndicateDisconnect %lx, complete IRP\n", TransportConnection);
+ }
+
+ //
+ // Now complete the IRP if needed. This will be non-null
+ // only if TdiDisconnect was called, and we have not
+ // yet completed it.
+ //
+
+ DisconnectIrp->IoStatus.Information = 0;
+ DisconnectIrp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest (DisconnectIrp, IO_NETWORK_INCREMENT);
+ }
+
+ } else if ((TransportConnection->Status != STATUS_LOCAL_DISCONNECT) &&
+ (addressFile != NULL) &&
+ (addressFile->RegisteredDisconnectHandler == TRUE)) {
+
+ //
+ // This was a remotely spawned disconnect, so indicate that
+ // to our client. Note that in the comparison above we
+ // check the status first, since if it is LOCAL_DISCONNECT
+ // addressFile may be NULL (BUGBUG: This is sort of a hack
+ // for PDK2, we should really indicate the disconnect inside
+ // NbfStopConnection, where we know addressFile is valid).
+ //
+
+ IF_NBFDBG (NBF_DEBUG_SETUP) {
+ NbfPrint1("IndicateDisconnect %lx, indicate\n", TransportConnection);
+ }
+
+ //
+ // if the disconnection was remotely spawned, then indicate
+ // disconnect. In the case that a disconnect was issued at
+ // the same time as the connection went down remotely, we
+ // won't do this because DisconnectIrp will be non-NULL.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint1 ("NbfIndicateDisconnect calling DisconnectHandler, refcnt=%ld\n",
+ TransportConnection->ReferenceCount);
+ }
+
+ //
+ // Invoke the user's disconnection event handler, if any. We do this here
+ // so that any outstanding sends will complete before we tear down the
+ // connection.
+ //
+
+ DisconnectReason = 0;
+ if (TransportConnection->Flags2 & CONNECTION_FLAGS2_ABORT) {
+ DisconnectReason |= TDI_DISCONNECT_ABORT;
+ }
+ if (TransportConnection->Flags2 & CONNECTION_FLAGS2_DESTROY) {
+ DisconnectReason |= TDI_DISCONNECT_RELEASE;
+ }
+
+ (*addressFile->DisconnectHandler)(
+ addressFile->DisconnectHandlerContext,
+ TransportConnection->Context,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ TDI_DISCONNECT_ABORT);
+
+#if MAGIC
+ if (NbfEnableMagic) {
+ extern VOID NbfSendMagicBullet (PDEVICE_CONTEXT, PTP_LINK);
+ NbfSendMagicBullet (DeviceContext, NULL);
+ }
+#endif
+ }
+
+ } else {
+
+ //
+ // The client does not yet think that this connection
+ // is up...generally this happens due to request count
+ // fluctuation during connection setup.
+ //
+
+ RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
+
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DbgPrint ("NBF: Got exception in NbfIndicateDisconnect\n");
+ DbgBreakPoint();
+
+ RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
+ }
+
+
+ return STATUS_SUCCESS;
+
+} /* NbfIndicateDisconnect */
+
+
+NTSTATUS
+NbfDestroyConnection(
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a transport connection and removes all references
+ made by it to other objects in the transport. The connection structure
+ is returned to our lookaside list. It is assumed that the caller
+ has removed all IRPs from the connections's queues first.
+
+ This routine is only called by NbfDereferenceConnection. The reason for
+ this is that there may be multiple streams of execution which are
+ simultaneously referencing the same connection object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection structure to
+ be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PDEVICE_CONTEXT DeviceContext;
+ PIRP CloseIrp;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint1 ("NbfDestroyConnection: Entered for connection %lx.\n",
+ TransportConnection);
+ }
+
+#if DBG
+ if (TransportConnection->Destroyed) {
+ NbfPrint1 ("attempt to destroy already-destroyed connection 0x%lx\n", TransportConnection);
+ DbgBreakPoint ();
+ }
+ if (!(TransportConnection->Flags2 & CONNECTION_FLAGS2_STOPPING)) {
+ NbfPrint1 ("attempt to destroy unstopped connection 0x%lx\n", TransportConnection);
+ DbgBreakPoint ();
+ }
+ TransportConnection->Destroyed = TRUE;
+ ACQUIRE_SPIN_LOCK (&NbfGlobalInterlock, &oldirql);
+ RemoveEntryList (&TransportConnection->GlobalLinkage);
+ RELEASE_SPIN_LOCK (&NbfGlobalInterlock, oldirql);
+#endif
+
+ DeviceContext = TransportConnection->Provider;
+
+ //
+ // Destroy any association that this connection has.
+ //
+
+ NbfDestroyAssociation (TransportConnection);
+
+ //
+ // Clear out any associated nasties hanging around the connection. Note
+ // that the current flags are set to STOPPING; this way anyone that may
+ // maliciously try to use the connection after it's dead and gone will
+ // just get ignored.
+ //
+
+ ASSERT (TransportConnection->Lsn == 0);
+
+ TransportConnection->Flags = 0;
+ TransportConnection->Flags2 = CONNECTION_FLAGS2_CLOSING;
+ TransportConnection->NetbiosHeader.TransmitCorrelator = 0;
+ TransportConnection->Retries = 0; // no retries yet.
+ TransportConnection->MessageBytesReceived = 0; // no data yet
+ TransportConnection->MessageBytesAcked = 0;
+ TransportConnection->MessageInitAccepted = 0;
+ TransportConnection->ReceiveBytesUnaccepted = 0;
+
+
+ //
+ // Now complete the close IRP. This will be set to non-null
+ // when CloseConnection was called.
+ //
+
+ CloseIrp = TransportConnection->CloseIrp;
+
+ if (CloseIrp != (PIRP)NULL) {
+
+ TransportConnection->CloseIrp = (PIRP)NULL;
+ CloseIrp->IoStatus.Information = 0;
+ CloseIrp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest (CloseIrp, IO_NETWORK_INCREMENT);
+
+ } else {
+
+#if DBG
+ NbfPrint1("Connection %x destroyed, no CloseIrp!!\n", TransportConnection);
+#endif
+
+ }
+
+ //
+ // Return the connection to the provider's pool.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ DeviceContext->ConnectionTotal += DeviceContext->ConnectionInUse;
+ ++DeviceContext->ConnectionSamples;
+ --DeviceContext->ConnectionInUse;
+
+ if ((DeviceContext->ConnectionAllocated - DeviceContext->ConnectionInUse) >
+ DeviceContext->ConnectionInitAllocated) {
+ NbfDeallocateConnection (DeviceContext, TransportConnection);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Deallocated connection at %lx\n", TransportConnection);
+ }
+ } else {
+ InsertTailList (&DeviceContext->ConnectionPool, &TransportConnection->LinkList);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ NbfDereferenceDeviceContext ("Destroy Connection", DeviceContext, DCREF_CONNECTION);
+
+ return STATUS_SUCCESS;
+
+} /* NbfDestroyConnection */
+
+
+#if DBG
+VOID
+NbfRefConnection(
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport connection.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint2 ("NbfReferenceConnection: entered for connection %lx, "
+ "current level=%ld.\n",
+ TransportConnection,
+ TransportConnection->ReferenceCount);
+ }
+
+#if DBG
+ StoreConnectionHistory( TransportConnection, TRUE );
+#endif
+
+ result = InterlockedIncrement (&TransportConnection->ReferenceCount);
+
+ if (result == 0) {
+
+ //
+ // The first increment causes us to increment the
+ // "ref count is not zero" special ref.
+ //
+
+ ExInterlockedAddUlong(
+ (PULONG)(&TransportConnection->SpecialRefCount),
+ 1,
+ TransportConnection->ProviderInterlock);
+
+#if DBG
+ ++TransportConnection->RefTypes[CREF_SPECIAL_TEMP];
+#endif
+
+ }
+
+ ASSERT (result >= 0);
+
+} /* NbfRefConnection */
+#endif
+
+
+VOID
+NbfDerefConnection(
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport connection by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ NbfDestroyConnection to remove it from the system.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint2 ("NbfDereferenceConnection: entered for connection %lx, "
+ "current level=%ld.\n",
+ TransportConnection,
+ TransportConnection->ReferenceCount);
+ }
+
+#if DBG
+ StoreConnectionHistory( TransportConnection, FALSE );
+#endif
+
+ result = InterlockedDecrement (&TransportConnection->ReferenceCount);
+
+ //
+ // If all the normal references to this connection are gone, then
+ // we can remove the special reference that stood for
+ // "the regular ref count is non-zero".
+ //
+
+ if (result < 0) {
+
+ //
+ // If the refcount is -1, then we need to disconnect from
+ // the link and indicate disconnect. However, we need to
+ // do this before we actually do the special deref, since
+ // otherwise the connection might go away while we
+ // are doing that.
+ //
+ // Note that both these routines are protected in that if they
+ // are called twice, the second call will have no effect.
+ //
+
+
+ //
+ // If both the connection and its link are active, then they have
+ // mutual references to each other. We remove the link's
+ // reference to the connection in NbfStopConnection, now
+ // the reference count has fallen enough that we know it
+ // is okay to remove the connection's reference to the
+ // link.
+ //
+
+ if (NbfDisconnectFromLink (TransportConnection, TRUE)) {
+
+ //
+ // if the reference count goes to one, we can safely indicate the
+ // user about disconnect states. That reference should
+ // be for the connection's creation.
+ //
+
+ NbfIndicateDisconnect (TransportConnection);
+
+ }
+
+ //
+ // Now it is OK to let the connection go away.
+ //
+
+ NbfDereferenceConnectionSpecial ("Regular ref gone", TransportConnection, CREF_SPECIAL_TEMP);
+
+ }
+
+} /* NbfDerefConnection */
+
+
+VOID
+NbfDerefConnectionSpecial(
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routines completes the dereferencing of a connection.
+ It may be called any time, but it does not do its work until
+ the regular reference count is also 0.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint3 ("NbfDereferenceConnectionSpecial: entered for connection %lx, "
+ "current level=%ld (%ld).\n",
+ TransportConnection,
+ TransportConnection->ReferenceCount,
+ TransportConnection->SpecialRefCount);
+ }
+
+#if DBG
+ StoreConnectionHistory( TransportConnection, FALSE );
+#endif
+
+
+ ACQUIRE_SPIN_LOCK (TransportConnection->ProviderInterlock, &oldirql);
+
+ --TransportConnection->SpecialRefCount;
+
+ if ((TransportConnection->SpecialRefCount == 0) &&
+ (TransportConnection->ReferenceCount == -1)) {
+
+ //
+ // If we have deleted all references to this connection, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the connection any longer.
+ //
+
+#if DBG
+ {
+ BOOLEAN TimerCancelled;
+ TimerCancelled = KeCancelTimer (&TransportConnection->Timer);
+ ASSERT (TimerCancelled);
+ }
+#endif
+
+ RELEASE_SPIN_LOCK (TransportConnection->ProviderInterlock, oldirql);
+
+ NbfDestroyConnection (TransportConnection);
+
+ } else {
+
+ RELEASE_SPIN_LOCK (TransportConnection->ProviderInterlock, oldirql);
+
+ }
+
+} /* NbfDerefConnectionSpecial */
+
+
+VOID
+NbfClearConnectionLsn(
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine clears the LSN field in a connection. To do this is
+ acquires the device context lock, and modifies the table value
+ for that LSN depending on the type of the connection.
+
+ NOTE: This routine is called with the connection spinlock held,
+ or in a state where nobody else will be accessing the
+ connection.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ KIRQL oldirql;
+
+ DeviceContext = TransportConnection->Provider;
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ if (TransportConnection->Lsn != 0) {
+
+ if (TransportConnection->Flags2 & CONNECTION_FLAGS2_GROUP_LSN) {
+
+ //
+ // It was to a group address; the count should be
+ // LSN_TABLE_MAX.
+ //
+
+ ASSERT(DeviceContext->LsnTable[TransportConnection->Lsn] == LSN_TABLE_MAX);
+
+ DeviceContext->LsnTable[TransportConnection->Lsn] = 0;
+
+ TransportConnection->Flags2 &= ~CONNECTION_FLAGS2_GROUP_LSN;
+
+ } else {
+
+ ASSERT(DeviceContext->LsnTable[TransportConnection->Lsn] > 0);
+
+ --(DeviceContext->LsnTable[TransportConnection->Lsn]);
+
+ }
+
+ TransportConnection->Lsn = 0;
+
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+}
+
+
+PTP_CONNECTION
+NbfLookupConnectionById(
+ IN PTP_ADDRESS Address,
+ IN USHORT ConnectionId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine accepts a connection identifier and an address and
+ returns a pointer to the connection object, TP_CONNECTION. If the
+ connection identifier is not found on the address, then NULL is returned.
+ This routine automatically increments the reference count of the
+ TP_CONNECTION structure if it is found. It is assumed that the
+ TP_ADDRESS structure is already held with a reference count.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+ ConnectionId - Identifier of the connection for this address.
+
+Return Value:
+
+ A pointer to the connection we found
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PLIST_ENTRY p;
+ PTP_CONNECTION Connection;
+ BOOLEAN Found = FALSE;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint2 ("NbfLookupConnectionById: entered, Address: %lx ID: %lx\n",
+ Address, ConnectionId);
+ }
+
+ //
+ // Currently, this implementation is inefficient, but brute force so
+ // that a system can get up and running. Later, a cache of the mappings
+ // of popular connection id's and pointers to their TP_CONNECTION structures
+ // will be searched first.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ for (p=Address->ConnectionDatabase.Flink;
+ p != &Address->ConnectionDatabase;
+ p=p->Flink) {
+
+
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressList);
+
+ try {
+
+ ACQUIRE_C_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
+
+ if (((Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) == 0) &&
+ (Connection->ConnectionId == ConnectionId)) {
+
+ // This reference is removed by the calling function
+ NbfReferenceConnection ("Lookup up for request", Connection, CREF_BY_ID);
+ Found = TRUE;
+ }
+
+ RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DbgPrint ("NBF: Got exception in NbfLookupConnectionById\n");
+ DbgBreakPoint();
+
+ RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+ }
+
+ if (Found) {
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ return Connection;
+ }
+
+
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return NULL;
+
+} /* NbfLookupConnectionById */
+
+
+PTP_CONNECTION
+NbfLookupConnectionByContext(
+ IN PTP_ADDRESS Address,
+ IN CONNECTION_CONTEXT ConnectionContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine accepts a connection identifier and an address and
+ returns a pointer to the connection object, TP_CONNECTION. If the
+ connection identifier is not found on the address, then NULL is returned.
+ This routine automatically increments the reference count of the
+ TP_CONNECTION structure if it is found. It is assumed that the
+ TP_ADDRESS structure is already held with a reference count.
+
+ BUGBUG: Should the ConnectionDatabase go in the address file?
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+ ConnectionContext - Connection Context for this address.
+
+Return Value:
+
+ A pointer to the connection we found
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PLIST_ENTRY p;
+ BOOLEAN Found = FALSE;
+ PTP_CONNECTION Connection;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint2 ("NbfLookupConnectionByContext: entered, Address: %lx Context: %lx\n",
+ Address, ConnectionContext);
+ }
+
+ //
+ // Currently, this implementation is inefficient, but brute force so
+ // that a system can get up and running. Later, a cache of the mappings
+ // of popular connection id's and pointers to their TP_CONNECTION structures
+ // will be searched first.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ for (p=Address->ConnectionDatabase.Flink;
+ p != &Address->ConnectionDatabase;
+ p=p->Flink) {
+
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressList);
+
+ try {
+
+ ACQUIRE_C_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
+
+ if (Connection->Context == ConnectionContext) {
+ // This reference is removed by the calling function
+ NbfReferenceConnection ("Lookup up for request", Connection, CREF_LISTENING);
+ Found = TRUE;
+ }
+
+ RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DbgPrint ("NBF: Got exception in NbfLookupConnectionById\n");
+ DbgBreakPoint();
+
+ RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+ }
+
+ if (Found) {
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ return Connection;
+ }
+
+
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return NULL;
+
+} /* NbfLookupConnectionByContext */
+
+
+PTP_CONNECTION
+NbfLookupListeningConnection(
+ IN PTP_ADDRESS Address,
+ IN PUCHAR RemoteName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the connection database on an address to find
+ a TP_CONNECTION object which has LSN=0 and CONNECTION_FLAGS_WAIT_NQ
+ flag set. It returns a pointer to the found connection object (and
+ simultaneously resets the flag) or NULL if it could not be found.
+ The reference count is also incremented atomically on the connection.
+
+ The list is scanned for listens posted to this specific remote
+ name, or to those with no remote name specified.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+ RemoteName - The name of the remote.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PTP_CONNECTION Connection;
+ PLIST_ENTRY p, q;
+ PTP_REQUEST ListenRequest;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint0 ("NbfLookupListeningConnection: Entered.\n");
+ }
+
+ //
+ // Currently, this implementation is inefficient, but brute force so
+ // that a system can get up and running. Later, a cache of the mappings
+ // of popular connection id's and pointers to their TP_CONNECTION structures
+ // will be searched first.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ for (p=Address->ConnectionDatabase.Flink;
+ p != &Address->ConnectionDatabase;
+ p=p->Flink) {
+
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressList);
+ if ((Connection->Lsn == 0) &&
+ (Connection->Flags2 & CONNECTION_FLAGS2_WAIT_NQ)) {
+
+ q = Connection->InProgressRequest.Flink;
+ if (q != &Connection->InProgressRequest) {
+ ListenRequest = CONTAINING_RECORD (q, TP_REQUEST, Linkage);
+ if ((ListenRequest->Buffer2 != NULL) &&
+ (!RtlEqualMemory(
+ ListenRequest->Buffer2,
+ RemoteName,
+ NETBIOS_NAME_LENGTH))) {
+ continue;
+ }
+ } else {
+ continue;
+ }
+ // This reference is removed by the calling function
+ NbfReferenceConnection ("Found Listening", Connection, CREF_LISTENING);
+ ACQUIRE_C_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_WAIT_NQ;
+ RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint1 ("NbfLookupListeningConnection: Found Connection %lx\n",Connection);
+ }
+ return Connection;
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint0 ("NbfLookupListeningConnection: Found No Connection!\n");
+ }
+
+ return NULL;
+
+} /* NbfLookupListeningConnection */
+
+
+VOID
+NbfStopConnection(
+ IN PTP_CONNECTION Connection,
+ IN NTSTATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to terminate all activity on a connection and
+ destroy the object. This is done in a graceful manner; i.e., all
+ outstanding requests are terminated by cancelling them, etc. It is
+ assumed that the caller has a reference to this connection object,
+ but this routine will do the dereference for the one issued at creation
+ time.
+
+ Orderly release is a function of this routine, but it is not a provided
+ service of this transport provider, so there is no code to do it here.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+ Status - The status that caused us to stop the connection. This
+ will determine what status pending requests are aborted with,
+ and also how we proceed during the stop (whether to send a
+ session end, and whether to indicate disconnect).
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL cancelirql;
+ PLIST_ENTRY p;
+ PIRP Irp;
+ PTP_REQUEST Request;
+ BOOLEAN TimerWasCleared;
+ ULONG DisconnectReason;
+ PULONG StopCounter;
+ PDEVICE_CONTEXT DeviceContext;
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint3 ("NbfStopConnection: Entered for connection %lx LSN %x RSN %x.\n",
+ Connection, Connection->Lsn, Connection->Rsn);
+ }
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ DeviceContext = Connection->Provider;
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ if (!(Connection->Flags2 & CONNECTION_FLAGS2_STOPPING)) {
+
+ //
+ // We are stopping the connection, record statistics
+ // about it.
+ //
+
+ if (Connection->Flags & CONNECTION_FLAGS_READY) {
+ DECREMENT_COUNTER (DeviceContext, OpenConnections);
+ }
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_STOPPING;
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_REMOTE_VALID;
+ Connection->Status = Status;
+
+ if (Connection->Link != NULL) {
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Connection->Flags &= ~(CONNECTION_FLAGS_READY|
+ CONNECTION_FLAGS_WAIT_SI|
+ CONNECTION_FLAGS_WAIT_SC); // no longer open for business
+ Connection->SendState = CONNECTION_SENDSTATE_IDLE;
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ }
+
+ //
+ // If this flag was on, turn it off.
+ //
+ Connection->Flags &= ~CONNECTION_FLAGS_W_RESYNCH;
+
+ //
+ // Stop the timer if it was running.
+ //
+
+ TimerWasCleared = KeCancelTimer (&Connection->Timer);
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint2 ("NbfStopConnection: Timer for connection %lx "
+ "%s canceled.\n", Connection,
+ TimerWasCleared ? "was" : "was NOT" );
+ }
+
+
+ switch (Status) {
+
+ case STATUS_LOCAL_DISCONNECT:
+ StopCounter = &DeviceContext->Statistics.LocalDisconnects;
+ break;
+ case STATUS_REMOTE_DISCONNECT:
+ StopCounter = &DeviceContext->Statistics.RemoteDisconnects;
+ break;
+ case STATUS_LINK_FAILED:
+ StopCounter = &DeviceContext->Statistics.LinkFailures;
+ break;
+ case STATUS_IO_TIMEOUT:
+ StopCounter = &DeviceContext->Statistics.SessionTimeouts;
+ break;
+ case STATUS_CANCELLED:
+ StopCounter = &DeviceContext->Statistics.CancelledConnections;
+ break;
+ case STATUS_REMOTE_RESOURCES:
+ StopCounter = &DeviceContext->Statistics.RemoteResourceFailures;
+ break;
+ case STATUS_INSUFFICIENT_RESOURCES:
+ StopCounter = &DeviceContext->Statistics.LocalResourceFailures;
+ break;
+ case STATUS_BAD_NETWORK_PATH:
+ StopCounter = &DeviceContext->Statistics.NotFoundFailures;
+ break;
+ case STATUS_REMOTE_NOT_LISTENING:
+ StopCounter = &DeviceContext->Statistics.NoListenFailures;
+ break;
+
+ default:
+ StopCounter = NULL;
+ break;
+
+ }
+
+ if (StopCounter != NULL) {
+ (*StopCounter)++;
+ }
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ //
+ // Run down all TdiConnect/TdiDisconnect/TdiListen requests.
+ //
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ while (TRUE) {
+ p = RemoveHeadList (&Connection->InProgressRequest);
+ if (p == &Connection->InProgressRequest) {
+ break;
+ }
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ IoSetCancelRoutine(Request->IoRequestPacket, NULL);
+ IoReleaseCancelSpinLock(cancelirql);
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ LARGE_INTEGER MilliSeconds, Time;
+ ULONG junk;
+ KeQuerySystemTime (&Time);
+ MilliSeconds.LowPart = Time.LowPart;
+ MilliSeconds.HighPart = Time.HighPart;
+ MilliSeconds.QuadPart = MilliSeconds.QuadPart -
+ (Request->Time).QuadPart;
+ MilliSeconds = RtlExtendedLargeIntegerDivide (MilliSeconds, 10000L, &junk);
+ NbfPrint3 ("NbfStopConnection: Canceling pending CONNECT, Irp: %lx Time Pending: %ld%ld msec\n",
+ Request->IoRequestPacket, MilliSeconds.HighPart, MilliSeconds.LowPart);
+ }
+#endif
+
+ NbfCompleteRequest (Request, Connection->Status, 0);
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ }
+
+
+ if (Connection->Link == NULL) {
+
+ //
+ // We are stopping early on.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ IoReleaseCancelSpinLock (cancelirql);
+
+ if (TimerWasCleared) {
+ NbfDereferenceConnection ("Stopping timer", Connection, CREF_TIMER); // account for timer reference.
+ }
+
+
+ ASSERT (Connection->SendState == CONNECTION_SENDSTATE_IDLE);
+ ASSERT (!Connection->OnPacketWaitQueue);
+ ASSERT (!Connection->OnDataAckQueue);
+ ASSERT (!(Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_ACK));
+ ASSERT (IsListEmpty(&Connection->SendQueue));
+ ASSERT (IsListEmpty(&Connection->ReceiveQueue));
+
+ return;
+
+ }
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ IoReleaseCancelSpinLock (cancelirql);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // If this connection is waiting to packetize,
+ // remove it from the device context queue it is on.
+ //
+ // NOTE: If the connection is currently in the
+ // packetize queue, it will eventually go to get
+ // packetized and at that point it will get
+ // removed.
+ //
+
+ if (Connection->OnPacketWaitQueue) {
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint1("Stop waiting connection, flags %lx\n",
+ Connection->Flags);
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+ Connection->OnPacketWaitQueue = FALSE;
+ ASSERT ((Connection->Flags & CONNECTION_FLAGS_SEND_SE) == 0);
+ Connection->Flags &= ~(CONNECTION_FLAGS_STARVED|CONNECTION_FLAGS_W_PACKETIZE);
+ RemoveEntryList (&Connection->PacketWaitLinkage);
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+ }
+
+
+ //
+ // If we are on the data ack queue, then take ourselves off.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+ if (Connection->OnDataAckQueue) {
+ RemoveEntryList (&Connection->DataAckLinkage);
+ Connection->OnDataAckQueue = FALSE;
+ DeviceContext->DataAckQueueChanged = TRUE;
+ }
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ //
+ // If this connection is waiting to send a piggyback ack,
+ // remove it from the device context queue for that, and
+ // send a data ack (which will get there before the
+ // SessionEnd).
+ //
+
+ if ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_ACK) != 0) {
+
+#if DBG
+ {
+ extern ULONG NbfDebugPiggybackAcks;
+ if (NbfDebugPiggybackAcks) {
+ NbfPrint1("Stop waiting connection, deferred flags %lx\n",
+ Connection->DeferredFlags);
+ }
+ }
+#endif
+
+ Connection->DeferredFlags &=
+ ~(CONNECTION_FLAGS_DEFERRED_ACK | CONNECTION_FLAGS_DEFERRED_NOT_Q);
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ NbfSendDataAck (Connection);
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ if (TimerWasCleared) {
+ NbfDereferenceConnection ("Stopping timer", Connection, CREF_TIMER); // account for timer reference.
+ }
+
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+
+ //
+ // Run down all TdiSend requests on this connection.
+ //
+
+ while (TRUE) {
+ p = RemoveHeadList (&Connection->SendQueue);
+ if (p == &Connection->SendQueue) {
+ break;
+ }
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ IoSetCancelRoutine(Irp, NULL);
+ IoReleaseCancelSpinLock(cancelirql);
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint1("NbfStopConnection: Canceling pending SEND, Irp: %lx\n",
+ Irp);
+ }
+#endif
+ NbfCompleteSendIrp (Irp, Connection->Status, 0);
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ ++Connection->TransmissionErrors;
+ }
+
+ //
+ // NOTE: We hold the connection spinlock AND the
+ // cancel spinlock here.
+ //
+
+ Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE;
+
+ //
+ // Run down all TdiReceive requests on this connection.
+ //
+
+ while (TRUE) {
+ p = RemoveHeadList (&Connection->ReceiveQueue);
+ if (p == &Connection->ReceiveQueue) {
+ break;
+ }
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ IoSetCancelRoutine(Irp, NULL);
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint1 ("NbfStopConnection: Canceling pending RECEIVE, Irp: %lx\n",
+ Irp);
+ }
+#endif
+
+ //
+ // It is OK to call this with the locks held.
+ //
+ NbfCompleteReceiveIrp (Irp, Connection->Status, 0);
+
+ ++Connection->ReceiveErrors;
+ }
+
+
+ //
+ // NOTE: We hold the connection spinlock AND the
+ // cancel spinlock here.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ //
+ // If we aren't DESTROYing the link, then send a SESSION_END frame
+ // to the remote side. When the SESSION_END frame is acknowleged,
+ // we will decrement the connection's reference count by one, removing
+ // its creation reference. This will cause the connection object to
+ // be disposed of, and will begin running down the link.
+ // DGB: add logic to avoid blowing away link if one doesn't exist yet.
+ //
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ DisconnectReason = 0;
+ if (Connection->Flags2 & CONNECTION_FLAGS2_ABORT) {
+ DisconnectReason |= TDI_DISCONNECT_ABORT;
+ }
+ if (Connection->Flags2 & CONNECTION_FLAGS2_DESTROY) {
+ DisconnectReason |= TDI_DISCONNECT_RELEASE;
+ }
+
+ if (Connection->Link != NULL) {
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ if ((Status == STATUS_LOCAL_DISCONNECT) ||
+ (Status == STATUS_CANCELLED)) {
+
+ //
+ // (note that a connection should only get stopped
+ // with STATUS_INSUFFICIENT_RESOURCES if it is not
+ // yet connected to the remote).
+ //
+
+ //
+ // If this is done, when this packet is destroyed
+ // it will dereference the connection for CREF_LINK.
+ //
+
+ NbfSendSessionEnd (
+ Connection,
+ (BOOLEAN)((DisconnectReason & TDI_DISCONNECT_ABORT) != 0));
+
+ } else {
+
+ //
+ // Not attached to the link anymore; this dereference
+ // will allow our reference to fall below 3, which
+ // will cause NbfDisconnectFromLink to be called.
+ //
+
+ NbfDereferenceConnection("Stopped", Connection, CREF_LINK);
+
+ }
+
+ } else {
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ }
+
+
+ //
+ // Note that we've blocked all new requests being queued during the
+ // time we have been in this teardown code; NbfDestroyConnection also
+ // sets the connection flags to STOPPING when returning the
+ // connection to the queue. This avoids lingerers using non-existent
+ // connections.
+ //
+
+ } else {
+
+ //
+ // The connection was already stopping; it may have a
+ // SESSION_END pending in which case we should kill
+ // it.
+ //
+
+ if ((Status != STATUS_LOCAL_DISCONNECT) &&
+ (Status != STATUS_CANCELLED)) {
+
+ if (Connection->Flags & CONNECTION_FLAGS_SEND_SE) {
+
+ ASSERT (Connection->Link != NULL);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ Connection->Flags &= ~CONNECTION_FLAGS_SEND_SE;
+
+ if (Connection->OnPacketWaitQueue) {
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+#if DBG
+ DbgPrint ("NBF: Removing connection %lx from PacketWait for SESSION_END\n", Connection);
+#endif
+ Connection->OnPacketWaitQueue = FALSE;
+ RemoveEntryList (&Connection->PacketWaitLinkage);
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+ }
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ NbfDereferenceConnection("Stopped again", Connection, CREF_LINK);
+ return;
+
+ }
+ }
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ }
+} /* NbfStopConnection */
+
+
+VOID
+NbfCancelConnection(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a connect
+ or a listen. It is simple since there can only be one of these
+ active on a connection; we just stop the connection, the IRP
+ will get completed as part of normal session teardown.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PIO_STACK_LOCATION IrpSp;
+ PTP_CONNECTION Connection;
+ PTP_REQUEST Request;
+ PLIST_ENTRY p;
+ BOOLEAN fCanceled = TRUE;
+
+ UNREFERENCED_PARAMETER (DeviceObject);
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (IrpSp->MinorFunction == TDI_CONNECT || IrpSp->MinorFunction == TDI_LISTEN));
+
+ Connection = IrpSp->FileObject->FsContext;
+
+ //
+ // Since this IRP is still in the cancellable state, we know
+ // that the connection is still around (although it may be in
+ // the process of being torn down).
+ //
+
+ ACQUIRE_C_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ NbfReferenceConnection ("Cancelling Send", Connection, CREF_TEMP);
+
+ p = RemoveHeadList (&Connection->InProgressRequest);
+ ASSERT (p != &Connection->InProgressRequest);
+
+ RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ ASSERT (Request->IoRequestPacket == Irp);
+#ifdef RASAUTODIAL
+ //
+ // If there's an automatic connection in
+ // progress, cancel it.
+ //
+ if (Connection->Flags2 & CONNECTION_FLAGS2_AUTOCONNECTING)
+ fCanceled = NbfCancelTdiConnect(NULL, Irp);
+#endif // RASAUTODIAL
+
+ if (fCanceled)
+ IoSetCancelRoutine(Request->IoRequestPacket, NULL);
+
+ IoReleaseCancelSpinLock(Irp->CancelIrql);
+
+ if (fCanceled) {
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint2("NBF: Cancelled in-progress connect/listen %lx on %lx\n",
+ Request->IoRequestPacket, Connection);
+ }
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+ NbfCompleteRequest (Request, STATUS_CANCELLED, 0);
+ NbfStopConnection (Connection, STATUS_LOCAL_DISCONNECT); // prevent indication to clients
+ KeLowerIrql (oldirql);
+ }
+
+ NbfDereferenceConnection ("Cancel done", Connection, CREF_TEMP);
+
+}
+
+#if 0
+VOID
+NbfWaitConnectionOnLink(
+ IN PTP_CONNECTION Connection,
+ IN ULONG Flags
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to suspend a connection's activities because
+ the specified session-oriented frame could not be sent due to link
+ problems. Routines in FRAMESND.C call this.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+ Flags - Field containing bitflag set to indicate starved frame to be sent.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint0 ("NbfWaitConnectionOnLink: Entered.\n");
+ }
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ if (((Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) == 0) ||
+ (Flags == CONNECTION_FLAGS_SEND_SE)) {
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ Connection->Flags |= Flags;
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ }
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+} /* NbfWaitConnectionOnLink */
+#endif
+
+
+VOID
+NbfStartConnectionTimer(
+ IN PTP_CONNECTION Connection,
+ IN PKDEFERRED_ROUTINE TimeoutFunction,
+ IN ULONG WaitTime
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to start a timeout on NAME_QUERY/NAME_RECOGNIZED
+ activities on a connection.
+
+Arguments:
+
+ TransportConnection - Pointer to a TP_CONNECTION object.
+
+ TimeoutFunction - The function to call when the timer fires.
+
+ WaitTime - a longword containing the low order time to wait.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LARGE_INTEGER Timeout;
+ BOOLEAN AlreadyInserted;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint1 ("NbfStartConnectionTimer: Entered for connection %lx.\n",
+ Connection );
+ }
+
+ //
+ // Start the timer. Unlike the link timers, this is simply a kernel-
+ // managed object.
+ //
+
+ Timeout.LowPart = (ULONG)(-(LONG)WaitTime);
+ Timeout.HighPart = -1;
+
+ //
+ // Take the lock so we synchronize the cancelling with
+ // restarting the timer. This is so two threads won't
+ // both fail to cancel and then start the timer at the
+ // same time (it messes up the reference count).
+ //
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ AlreadyInserted = KeCancelTimer (&Connection->Timer);
+
+ KeInitializeDpc (
+ &Connection->Dpc,
+ TimeoutFunction,
+ (PVOID)Connection);
+
+ KeSetTimer (
+ &Connection->Timer,
+ Timeout,
+ &Connection->Dpc);
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ //
+ // If the timer wasn't already running, reference the connection to
+ // account for the new timer. If the timer was already started,
+ // then KeCancelTimer will have returned TRUE. In this
+ // case, the prior call to NbfStartConnectionTimer referenced the
+ // connection, so we don't do it again here.
+ //
+
+ if ( !AlreadyInserted ) {
+
+ // This reference is removed in ConnectionEstablishmentTimeout,
+ // or when the timer is cancelled.
+
+ NbfReferenceConnection ("starting timer", Connection, CREF_TIMER);
+ }
+
+} /* NbfStartConnectionTimer */
+
diff --git a/private/ntos/tdi/nbf/devctx.c b/private/ntos/tdi/nbf/devctx.c
new file mode 100644
index 000000000..0d6179e60
--- /dev/null
+++ b/private/ntos/tdi/nbf/devctx.c
@@ -0,0 +1,408 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ devctx.c
+
+Abstract:
+
+ This module contains code which implements the DEVICE_CONTEXT object.
+ Routines are provided to reference, and dereference transport device
+ context objects. Currently, there is no need to create them or destroy
+ them, as this is handled at configuration time. If it is later required
+ to dynamically load/unload the transport provider's device object and
+ associated context, then we can add the create and destroy functions.
+
+ The transport device context object is a structure which contains a
+ system-defined DEVICE_OBJECT followed by information which is maintained
+ by the transport provider, called the context.
+
+Author:
+
+ David Beaver (dbeaver) 1 -July 1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+#ifdef ALLOC_PRAGMA
+#ifndef _PNP_POWER
+#pragma alloc_text(INIT,NbfCreateDeviceContext)
+#else
+#pragma alloc_text(PAGE,NbfCreateDeviceContext)
+#endif
+
+#endif
+
+
+VOID
+NbfRefDeviceContext(
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a device context.
+
+Arguments:
+
+ DeviceContext - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_DEVCTX) {
+ NbfPrint0 ("NbfRefDeviceContext: Entered.\n");
+ }
+
+ ASSERT (DeviceContext->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement (&DeviceContext->ReferenceCount);
+
+} /* NbfRefDeviceContext */
+
+
+VOID
+NbfDerefDeviceContext(
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a device context by decrementing the
+ reference count contained in the structure. Currently, we don't
+ do anything special when the reference count drops to zero, but
+ we could dynamically unload stuff then.
+
+Arguments:
+
+ DeviceContext - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ IF_NBFDBG (NBF_DEBUG_DEVCTX) {
+ NbfPrint0 ("NbfDerefDeviceContext: Entered.\n");
+ }
+
+ result = InterlockedDecrement (&DeviceContext->ReferenceCount);
+
+ ASSERT (result >= 0);
+
+ if (result == 0) {
+ NbfDestroyDeviceContext (DeviceContext);
+ }
+
+} /* NbfDerefDeviceContext */
+
+
+
+NTSTATUS
+NbfCreateDeviceContext(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN OUT PDEVICE_CONTEXT *DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates and initializes a device context structure.
+
+Arguments:
+
+
+ DriverObject - pointer to the IO subsystem supplied driver object.
+
+ DeviceContext - Pointer to a pointer to a transport device context object.
+
+ DeviceName - pointer to the name of the device this device object points to.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
+
+--*/
+
+{
+ NTSTATUS status;
+ PDEVICE_OBJECT deviceObject;
+ PDEVICE_CONTEXT deviceContext;
+ USHORT i;
+
+
+ //
+ // Create the device object for NETBEUI.
+ //
+
+ status = IoCreateDevice(
+ DriverObject,
+ sizeof (DEVICE_CONTEXT) - sizeof (DEVICE_OBJECT) +
+ (DeviceName->Length + sizeof(UNICODE_NULL)),
+ DeviceName,
+ FILE_DEVICE_TRANSPORT,
+ 0,
+ FALSE,
+ &deviceObject);
+
+ if (!NT_SUCCESS(status)) {
+ return status;
+ }
+
+ deviceObject->Flags |= DO_DIRECT_IO;
+
+ deviceContext = (PDEVICE_CONTEXT)deviceObject;
+
+ //
+ // Initialize our part of the device context.
+ //
+
+ RtlZeroMemory(
+ ((PUCHAR)deviceContext) + sizeof(DEVICE_OBJECT),
+ sizeof(DEVICE_CONTEXT) - sizeof(DEVICE_OBJECT));
+
+ //
+ // Copy over the device name.
+ //
+
+ deviceContext->DeviceNameLength = DeviceName->Length + sizeof(WCHAR);
+ deviceContext->DeviceName = (PWCHAR)(deviceContext+1);
+ RtlCopyMemory(
+ deviceContext->DeviceName,
+ DeviceName->Buffer,
+ DeviceName->Length);
+ deviceContext->DeviceName[DeviceName->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ //
+ // Initialize device context fields.
+ //
+
+ deviceContext->NetmanVariables = NULL; // no variables yet.
+
+ //
+ // Initialize the reference count.
+ //
+
+ deviceContext->ReferenceCount = 1;
+
+#if DBG
+ {
+ UINT Counter;
+ for (Counter = 0; Counter < NUMBER_OF_DCREFS; Counter++) {
+ deviceContext->RefTypes[Counter] = 0;
+ }
+
+ // This reference is removed by the caller.
+
+ deviceContext->RefTypes[DCREF_CREATION] = 1;
+ }
+#endif
+
+ //
+ // initialize the various fields in the device context
+ //
+
+ KeInitializeSpinLock (&deviceContext->Interlock);
+ KeInitializeSpinLock (&deviceContext->SpinLock);
+ KeInitializeSpinLock (&deviceContext->LinkSpinLock);
+ KeInitializeSpinLock (&deviceContext->TimerSpinLock);
+ KeInitializeSpinLock (&deviceContext->LoopbackSpinLock);
+ KeInitializeSpinLock (&deviceContext->SendPoolListLock);
+ KeInitializeSpinLock (&deviceContext->RcvPoolListLock);
+
+ deviceContext->LinkTreeRoot = NULL;
+ deviceContext->LastLink = NULL;
+ deviceContext->LinkTreeElements = 0;
+
+ deviceContext->LoopbackLinks[0] = NULL;
+ deviceContext->LoopbackLinks[1] = NULL;
+ deviceContext->LoopbackInProgress = FALSE;
+ KeInitializeDpc(
+ &deviceContext->LoopbackDpc,
+ NbfProcessLoopbackQueue,
+ (PVOID)deviceContext
+ );
+
+ deviceContext->WanThreadQueued = FALSE;
+ ExInitializeWorkItem(
+ &deviceContext->WanDelayedQueueItem,
+ NbfProcessWanDelayedQueue,
+ (PVOID)deviceContext);
+
+
+ deviceContext->UniqueIdentifier = 1;
+ deviceContext->ControlChannelIdentifier = 1;
+
+ InitializeListHead (&deviceContext->ConnectionPool);
+ InitializeListHead (&deviceContext->AddressPool);
+ InitializeListHead (&deviceContext->AddressFilePool);
+ InitializeListHead (&deviceContext->AddressDatabase);
+ InitializeListHead (&deviceContext->LinkPool);
+ InitializeListHead (&deviceContext->LinkDeferred);
+ InitializeListHead (&deviceContext->PacketWaitQueue);
+ InitializeListHead (&deviceContext->PacketizeQueue);
+ InitializeListHead (&deviceContext->DataAckQueue);
+ InitializeListHead (&deviceContext->DeferredRrQueue);
+ InitializeListHead (&deviceContext->RequestPool);
+ InitializeListHead (&deviceContext->UIFramePool);
+ deviceContext->PacketPool.Next = NULL;
+ deviceContext->ReceivePacketPool.Next = NULL;
+ deviceContext->ReceiveBufferPool.Next = NULL;
+ InitializeListHead (&deviceContext->ReceiveInProgress);
+ InitializeListHead (&deviceContext->ShortList);
+ InitializeListHead (&deviceContext->LongList);
+ InitializeListHead (&deviceContext->PurgeList);
+ InitializeListHead (&deviceContext->LoopbackQueue);
+ InitializeListHead (&deviceContext->FindNameQueue);
+ InitializeListHead (&deviceContext->StatusQueryQueue);
+ InitializeListHead (&deviceContext->IrpCompletionQueue);
+
+ InitializeListHead (&deviceContext->QueryIndicationQueue);
+ InitializeListHead (&deviceContext->DatagramIndicationQueue);
+ deviceContext->IndicationQueuesInUse = FALSE;
+
+ //
+ // Equivalent to setting ShortListActive, DataAckQueueActive,
+ // and LinkDeferredActive to FALSE.
+ //
+
+ deviceContext->a.AnyActive = 0;
+
+ deviceContext->ProcessingShortTimer = FALSE;
+ deviceContext->DataAckQueueChanged = FALSE;
+ deviceContext->StalledConnectionCount = (USHORT)0;
+
+ deviceContext->EasilyDisconnected = FALSE;
+
+ //
+ // Initialize provider statistics.
+ //
+
+ deviceContext->Statistics.Version = 0x0100;
+
+#if 0
+ deviceContext->Information.Version = 2; // BUGBUG: define TDI_VERSION in TDI.H.
+ deviceContext->Information.MaxTsduSize = NBF_MAX_TSDU_SIZE;
+ deviceContext->Information.MaxDatagramSize = NBF_MAX_DATAGRAM_SIZE;
+ deviceContext->Information.MaxConnectionUserData = NBF_MAX_CONNECTION_USER_DATA;
+ deviceContext->Information.ServiceFlags = NBF_SERVICE_FLAGS;
+ deviceContext->Information.TransmittedTsdus = 0;
+ deviceContext->Information.ReceivedTsdus = 0;
+ deviceContext->Information.TransmissionErrors = 0;
+ deviceContext->Information.ReceiveErrors = 0;
+ deviceContext->Information.MinimumLookaheadData = NBF_MIN_LOOKAHEAD_DATA;
+ deviceContext->Information.MaximumLookaheadData = NBF_MAX_LOOKAHEAD_DATA;
+ deviceContext->Information.DiscardedFrames = 0;
+ deviceContext->Information.OversizeTsdusReceived = 0;
+ deviceContext->Information.UndersizeTsdusReceived = 0;
+ deviceContext->Information.MulticastTsdusReceived = 0;
+ deviceContext->Information.BroadcastTsdusReceived = 0;
+ deviceContext->Information.MulticastTsdusTransmitted = 0;
+ deviceContext->Information.BroadcastTsdusTransmitted = 0;
+ deviceContext->Information.SendTimeouts = 0;
+ deviceContext->Information.ReceiveTimeouts = 0;
+ deviceContext->Information.ConnectionIndicationsReceived = 0;
+ deviceContext->Information.ConnectionIndicationsAccepted = 0;
+ deviceContext->Information.ConnectionsInitiated = 0;
+ deviceContext->Information.ConnectionsAccepted = 0;
+#endif
+
+ deviceContext->State = DEVICECONTEXT_STATE_OPENING;
+
+ //
+ // Loopback buffer is not allocated.
+ //
+
+ deviceContext->LookaheadContiguous = NULL;
+
+ //
+ // Initialize the resource that guards address ACLs.
+ //
+
+ ExInitializeResource (&deviceContext->AddressResource);
+
+ //
+ // No LSNs are in use.
+ //
+
+ for (i=0; i<(NETBIOS_SESSION_LIMIT+1); i++) {
+ deviceContext->LsnTable[i] = 0;
+ }
+ deviceContext->NextLsnStart = 1;
+
+ //
+ // No addresses are in use.
+ //
+
+ for (i=0; i<256; i++) {
+ deviceContext->AddressCounts[i] = 0;
+ }
+
+ //
+ // set the netbios multicast address for this network type
+ //
+
+ for (i=0; i<HARDWARE_ADDRESS_LENGTH; i++) {
+ deviceContext->LocalAddress.Address [i] = 0; // set later
+ deviceContext->NetBIOSAddress.Address [i] = 0;
+ }
+
+ deviceContext->Type = NBF_DEVICE_CONTEXT_SIGNATURE;
+ deviceContext->Size = sizeof (DEVICE_CONTEXT);
+
+ *DeviceContext = deviceContext;
+ return STATUS_SUCCESS;
+}
+
+
+VOID
+NbfDestroyDeviceContext(
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a device context structure.
+
+Arguments:
+
+ DeviceContext - Pointer to a pointer to a transport device context object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ExDeleteResource (&DeviceContext->AddressResource);
+ IoDeleteDevice ((PDEVICE_OBJECT)DeviceContext);
+ return;
+}
diff --git a/private/ntos/tdi/nbf/dlc.c b/private/ntos/tdi/nbf/dlc.c
new file mode 100644
index 000000000..893bffd49
--- /dev/null
+++ b/private/ntos/tdi/nbf/dlc.c
@@ -0,0 +1,3270 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ dlc.c
+
+Abstract:
+
+ This module contains code which implements the data link layer for the
+ transport provider.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Macros
+
+
+//
+// These two functions are used by the loopback indicator.
+//
+
+STATIC
+VOID
+NbfCopyFromPacketToBuffer(
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT BytesToCopy,
+ OUT PCHAR Buffer,
+ OUT PUINT BytesCopied
+ );
+
+
+VOID
+NbfProcessSabme(
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PTP_LINK Link,
+ IN PDLC_U_FRAME Header,
+ IN PVOID MacHeader,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a received SABME frame.
+
+Arguments:
+
+ Command - Boolean set to TRUE if command, else FALSE if response.
+
+ PollFinal - Boolean set to TRUE if Poll or Final.
+
+ Link - Pointer to a transport link object.
+
+ Header - Pointer to a DLC U-type frame.
+
+ MacHeader - Pointer to the MAC header of the packet.
+
+ DeviceContext - The device context of this adapter.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PUCHAR SourceRouting;
+ UINT SourceRoutingLength;
+ UCHAR TempSR[MAX_SOURCE_ROUTING];
+ PUCHAR ResponseSR;
+
+#if DBG
+ UCHAR *s;
+#endif
+
+ Header; // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessSabme: Entered.\n");
+ }
+
+ //
+ // Format must be: SABME-c/x, on a real link object.
+ //
+
+ if (!Command || (Link == NULL)) {
+ return;
+ }
+
+ //
+ // Build response routing information. We do this on the SABME, even
+ // though we already did in on the Name Query, because the client may
+ // choose a different route (if there were multiple routes) than we
+ // did.
+ //
+
+ MacReturnSourceRouting(
+ &DeviceContext->MacInfo,
+ MacHeader,
+ &SourceRouting,
+ &SourceRoutingLength);
+
+ if (SourceRouting != NULL) {
+
+ RtlCopyMemory(
+ TempSR,
+ SourceRouting,
+ SourceRoutingLength);
+
+ MacCreateNonBroadcastReplySR(
+ &DeviceContext->MacInfo,
+ TempSR,
+ SourceRoutingLength,
+ &ResponseSR);
+
+ } else {
+
+ ResponseSR = NULL;
+
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ Link->Header,
+ SourceAddress->Address,
+ DeviceContext->LocalAddress.Address,
+ 0, // PacketLength, filled in later
+ ResponseSR,
+ SourceRoutingLength,
+ (PUINT)&(Link->HeaderLength));
+
+ //
+ // We optimize for fourteen-byte headers by putting
+ // the correct Dsap/Ssap at the end, so we can fill
+ // in new packets as one 16-byte move.
+ //
+
+ if (Link->HeaderLength <= 14) {
+ Link->Header[Link->HeaderLength] = DSAP_NETBIOS_OVER_LLC;
+ Link->Header[Link->HeaderLength+1] = DSAP_NETBIOS_OVER_LLC;
+ }
+
+ //
+ // Process the SABME.
+ //
+
+ Link->LinkBusy = FALSE; // he's cleared his busy condition.
+
+ switch (Link->State) {
+
+ case LINK_STATE_ADM:
+
+ //
+ // Remote station is initiating this link. Send UA and wait for
+ // his checkpoint before setting READY state.
+ //
+
+ // Moving out of ADM, add special reference
+ NbfReferenceLinkSpecial("Waiting for Poll", Link, LREF_NOT_ADM);
+
+ Link->State = LINK_STATE_W_POLL; // wait for RR-c/p.
+
+ // Don't start T1, but prepare for timing the response
+ FakeStartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME));
+
+ NbfResetLink (Link);
+ NbfSendUa (Link, PollFinal); // releases lock
+ IF_NBFDBG (NBF_DEBUG_SETUP) {
+ NbfPrint4("ADM SABME on %lx %x-%x-%x\n",
+ Link,
+ Link->HardwareAddress.Address[3],
+ Link->HardwareAddress.Address[4],
+ Link->HardwareAddress.Address[5]);
+ }
+ StartTi (Link);
+#if DBG
+ s = "ADM";
+#endif
+ break;
+
+ case LINK_STATE_CONNECTING:
+
+ //
+ // We've sent a SABME and are waiting for a UA. He's sent a
+ // SABME at the same time, so we tried to do it at the same time.
+ // The only balanced thing we can do at this time is to respond
+ // with UA and duplicate the effort. To not send anything would
+ // be bad because the link would never complete.
+ //
+
+ //
+ // BUGBUG: What about timers here?
+ //
+
+ Link->State = LINK_STATE_W_POLL; // wait for RR-c/p.
+ NbfSendUa (Link, PollFinal); // releases lock
+ StartTi (Link);
+#if DBG
+ s = "CONNECTING";
+#endif
+ break;
+
+ case LINK_STATE_W_POLL:
+
+ //
+ // We're waiting for his initial poll on a RR-c/p. Instead, we
+ // got a SABME, so this is really a link reset.
+ //
+ // Unfortunately, if we happen to get two SABMEs
+ // and respond to the second one with another UA
+ // (when he has sent the RR-c/p and is expecting
+ // an RR-r/f), he will send a FRMR. So, we ignore
+ // this frame.
+ //
+
+ // Link->State = LINK_STATE_W_POLL; // wait for RR-c/p.
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ StartTi(Link);
+#if DBG
+ s = "W_POLL";
+#endif
+ break;
+
+ case LINK_STATE_READY:
+
+ //
+ // Link is already balanced. He's resetting the link.
+ //
+
+ case LINK_STATE_W_FINAL:
+
+ //
+ // We're waiting for a RR-r/f from the remote guy but instead
+ // he sent this SABME. We have to assume he wants to reset the link.
+ //
+
+ case LINK_STATE_W_DISC_RSP:
+
+ //
+ // We're waiting for a response from our DISC-c/p but instead of
+ // a UA-r/f, we got this SABME. He wants to initiate the link
+ // again because a transport connection has been initiated while
+ // we were taking the link down.
+ //
+
+ Link->State = LINK_STATE_W_POLL; // wait for RR-c/p.
+
+ // Don't start T1, but prepare for timing the response
+ FakeStartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME));
+
+ NbfResetLink (Link); // reset this connection.
+ NbfSendUa (Link, PollFinal); // releases lock.
+ StartTi(Link);
+#if DBG
+ s = "READY/W_FINAL/W_DISC_RSP";
+#endif
+ break;
+
+ default:
+
+ ASSERT (FALSE);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "Unknown link state";
+#endif
+
+ } /* switch */
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 (" NbfProcessSabme: Processed, State was %s.\n", s);
+ }
+#endif
+
+} /* NbfProcessSabme */
+
+
+VOID
+NbfProcessUa(
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PTP_LINK Link,
+ IN PDLC_U_FRAME Header
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a received UA frame.
+
+Arguments:
+
+ Command - Boolean set to TRUE if command, else FALSE if response.
+
+ PollFinal - Boolean set to TRUE if Poll or Final.
+
+ Link - Pointer to a transport link object.
+
+ Header - Pointer to a DLC U-type frame.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+#if DBG
+ UCHAR *s;
+#endif
+
+ PollFinal, Header; // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessUa: Entered.\n");
+ }
+
+ //
+ // Format must be: UA-r/x, on a real link object.
+ //
+
+ if (Command || (Link == NULL)) {
+ return;
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
+
+ Link->LinkBusy = FALSE; // he's cleared his busy condition.
+
+ switch (Link->State) {
+
+ case LINK_STATE_ADM:
+
+ //
+ // Received an unnumbered acknowlegement while in ADM. Somehow
+ // the remote station is confused, so tell him we're disconnected.
+ //
+
+ NbfSendDm (Link, FALSE); // indicate we're disconnected, release lock
+#if DBG
+ s = "ADM";
+#endif
+ break;
+
+ case LINK_STATE_CONNECTING:
+
+ //
+ // We've sent a SABME and have just received the UA.
+ //
+
+ UpdateBaseT1Timeout (Link); // got response to poll.
+
+ Link->State = LINK_STATE_W_FINAL; // wait for RR-r/f.
+ Link->SendRetries = (UCHAR)Link->LlcRetries;
+ NbfSendRr (Link, TRUE, TRUE); // send RR-c/p, StartT1, release lock
+#if DBG
+ s = "CONNECTING";
+#endif
+ break;
+
+ case LINK_STATE_READY:
+
+ //
+ // Link is already balanced. He's confused; throw it away.
+ //
+
+ case LINK_STATE_W_POLL:
+
+ //
+ // We're waiting for his initial poll on a RR-c/p. Instead, we
+ // got a UA, so he is confused. Throw it away.
+ //
+
+ case LINK_STATE_W_FINAL:
+
+ //
+ // We're waiting for a RR-r/f from the remote guy but instead
+ // he sent this UA. He is confused. Throw it away.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "READY/W_POLL/W_FINAL";
+#endif
+ break;
+
+ case LINK_STATE_W_DISC_RSP:
+
+ //
+ // We've sent a DISC-c/p and have received the correct response.
+ // Disconnect this link.
+ //
+
+ Link->State = LINK_STATE_ADM; // completed disconnection.
+
+ //
+ // This is the normal "clean" disconnect path, so we stop
+ // all the timers here since we won't call NbfStopLink.
+ //
+
+ StopT1 (Link);
+ StopT2 (Link);
+ StopTi (Link);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ // Moving to ADM, dereference link
+ NbfDereferenceLinkSpecial ("Got UA for DISC", Link, LREF_NOT_ADM); // decrement link's last ref.
+
+#if DBG
+ s = "W_DISC_RSP";
+#endif
+ break;
+
+ default:
+
+ ASSERT (FALSE);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "Unknown link state";
+#endif
+
+ } /* switch */
+
+} /* NbfProcessUa */
+
+
+VOID
+NbfProcessDisc(
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PTP_LINK Link,
+ IN PDLC_U_FRAME Header
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a received DISC frame.
+
+Arguments:
+
+ Command - Boolean set to TRUE if command, else FALSE if response.
+
+ PollFinal - Boolean set to TRUE if Poll or Final.
+
+ Link - Pointer to a transport link object.
+
+ Header - Pointer to a DLC U-type frame.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+#if DBG
+ UCHAR *s;
+#endif
+
+ Header; // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessDisc: Entered.\n");
+ }
+
+ //
+ // Format must be: DISC-c/x, on a real link object.
+ //
+
+ if (!Command || (Link == NULL)) {
+ return;
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
+
+ Link->LinkBusy = FALSE; // he's cleared his busy condition.
+
+ switch (Link->State) {
+
+ case LINK_STATE_ADM:
+
+ //
+ // Received a DISC while in ADM. Simply report disconnected mode.
+ //
+
+#if DBG
+ s = "ADM";
+#endif
+ NbfSendDm (Link, PollFinal); // indicate we're disconnected, release lock
+ break;
+
+ case LINK_STATE_READY:
+
+ //
+ // Link is balanced. Kill the link.
+ //
+
+ Link->State = LINK_STATE_ADM; // we're reset now.
+ NbfSendUa (Link, PollFinal); // Send UA-r/x, release lock
+#if DBG
+ if (NbfDisconnectDebug) {
+ NbfPrint0( "NbfProcessDisc calling NbfStopLink\n" );
+ }
+#endif
+ NbfStopLink (Link); // say goodnight, gracie
+
+ // Moving to ADM, remove reference
+ NbfDereferenceLinkSpecial("Stopping link", Link, LREF_NOT_ADM);
+
+#if DBG
+ s = "READY";
+#endif
+ break;
+
+ case LINK_STATE_CONNECTING:
+
+ //
+ // We've sent a SABME and have just received a DISC. That means
+ // we have crossed a disconnection and reconnection. Throw away
+ // the disconnect.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "CONNECTING";
+#endif
+ break;
+
+ case LINK_STATE_W_POLL:
+
+ //
+ // We're waiting for his initial poll on a RR-c/p. Instead, we
+ // got a DISC, so he wants to drop the link.
+ //
+
+ case LINK_STATE_W_FINAL:
+
+ //
+ // We're waiting for a RR-r/f from the remote guy but instead
+ // he sent DISC, so he wants to drop the link.
+ //
+
+ case LINK_STATE_W_DISC_RSP:
+
+ //
+ // We've sent a DISC-c/p and have received a DISC from him as well.
+ // Disconnect this link.
+ //
+
+ Link->State = LINK_STATE_ADM; // we're reset now.
+ NbfSendUa (Link, PollFinal); // Send UA-r/x, release lock.
+
+ NbfStopLink (Link);
+
+ // moving to ADM, remove reference
+ NbfDereferenceLinkSpecial ("Got DISC on W_DIS_RSP", Link, LREF_NOT_ADM); // remove its "alive" ref.
+
+#if DBG
+ s = "W_POLL/W_FINAL/W_DISC_RSP";
+#endif
+ break;
+
+ default:
+
+ ASSERT (FALSE);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "Unknown link state";
+#endif
+
+ } /* switch */
+
+} /* NbfProcessDisc */
+
+
+VOID
+NbfProcessDm(
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PTP_LINK Link,
+ IN PDLC_U_FRAME Header
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a received DM frame.
+
+Arguments:
+
+ Command - Boolean set to TRUE if command, else FALSE if response.
+
+ PollFinal - Boolean set to TRUE if Poll or Final.
+
+ Link - Pointer to a transport link object.
+
+ Header - Pointer to a DLC U-type frame.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+#if DBG
+ UCHAR *s;
+#endif
+
+ Header; // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessDm: Entered.\n");
+ }
+
+ //
+ // Format must be: DM-r/x, on a real link object.
+ //
+
+ if (Command || (Link == NULL)) {
+ return;
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
+
+ Link->LinkBusy = FALSE; // he's cleared his busy condition.
+
+ switch (Link->State) {
+
+ case LINK_STATE_ADM:
+
+ //
+ // Received a DM while in ADM. Do nothing.
+ //
+
+ case LINK_STATE_CONNECTING:
+
+ //
+ // We've sent a SABME and have just received a DM. That means
+ // we have crossed a disconnection and reconnection. Throw away
+ // the disconnect mode indicator, we will reconnect in time.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "ADM/CONNECTING";
+#endif
+ break;
+
+ case LINK_STATE_READY:
+
+ //
+ // Link is balanced and he is in ADM, so we have to shut down.
+ //
+
+#if DBG
+ if (NbfDisconnectDebug) {
+ NbfPrint0( "NbfProcessDm calling NbfStopLink\n" );
+ }
+#endif
+
+ case LINK_STATE_W_POLL:
+
+ //
+ // We're waiting for his initial poll on a RR-c/p. Instead, we
+ // got a DM, so he has dropped the link.
+ //
+
+ case LINK_STATE_W_FINAL:
+
+ //
+ // We're waiting for a RR-r/f from the remote guy but instead
+ // he sent DM, so he has already dropped the link.
+ //
+
+ case LINK_STATE_W_DISC_RSP:
+
+ //
+ // We've sent a DISC-c/p and have received a DM from him, indicating
+ // that he is now in ADM. While technically not what we expected,
+ // this protocol is commonly used in place of UA-r/f, so just treat
+ // as though we got a UA-r/f. Disconnect the link normally.
+ //
+
+ Link->State = LINK_STATE_ADM; // we're reset now.
+ NbfSendDm (Link, FALSE); // indicate disconnected, release lock
+
+ NbfStopLink (Link);
+
+ // moving to ADM, remove reference
+ NbfDereferenceLinkSpecial ("Got DM in W_DISC_RSP", Link, LREF_NOT_ADM); // remove its "alive" ref.
+
+#if DBG
+ s = "READY/W_FINAL/W_POLL/W_DISC_RSP";
+#endif
+ break;
+
+ default:
+
+ ASSERT (FALSE);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "Unknown link state";
+#endif
+
+ } /* switch */
+
+} /* NbfProcessDm */
+
+
+VOID
+NbfProcessFrmr(
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PTP_LINK Link,
+ IN PDLC_U_FRAME Header
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a received FRMR response frame.
+
+Arguments:
+
+ Command - Boolean set to TRUE if command, else FALSE if response.
+
+ PollFinal - Boolean set to TRUE if Poll or Final.
+
+ Link - Pointer to a transport link object.
+
+ Header - Pointer to a DLC U-type frame.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+#if DBG
+ UCHAR *s;
+#endif
+ ULONG DumpData[6];
+
+ PollFinal, Header; // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessFrmr: Entered.\n");
+ }
+
+ //
+ // Log an error, this shouldn't happen.
+ //
+
+ DumpData[0] = Link->State;
+ DumpData[1] = Link->Flags;
+ DumpData[2] = (Header->Information.FrmrInfo.Command << 8) +
+ (Header->Information.FrmrInfo.Ctrl);
+ DumpData[3] = (Header->Information.FrmrInfo.Vs << 16) +
+ (Header->Information.FrmrInfo.Vr << 8) +
+ (Header->Information.FrmrInfo.Reason);
+ DumpData[4] = (Link->SendState << 24) +
+ (Link->NextSend << 16) +
+ (Link->LastAckReceived << 8) +
+ (Link->SendWindowSize);
+ DumpData[5] = (Link->ReceiveState << 24) +
+ (Link->NextReceive << 16) +
+ (Link->LastAckSent << 8) +
+ (Link->ReceiveWindowSize);
+
+ NbfWriteGeneralErrorLog(
+ Link->Provider,
+ EVENT_TRANSPORT_BAD_PROTOCOL,
+ 1,
+ STATUS_LINK_FAILED,
+ L"FRMR",
+ 6,
+ DumpData);
+
+
+ ++Link->Provider->FrmrReceived;
+
+ //
+ // Format must be: FRMR-r/x, on a real link object.
+ //
+
+ if (Command || (Link == NULL)) {
+ return;
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
+
+ switch (Link->State) {
+
+ case LINK_STATE_ADM:
+
+ //
+ // Received a FRMR while in ADM. Report disconnected mode.
+ //
+
+#if DBG
+ s = "ADM";
+#endif
+ NbfSendDm (Link, FALSE); // indicate disconnected, release lock
+ break;
+
+ case LINK_STATE_READY:
+
+ //
+ // Link is balanced and he reported a protocol error.
+ //
+#if 0
+ // We want to reset the link, but not quite as fully
+ // as NbfResetLink. This code is the same as what
+ // is in there, except for:
+ //
+ // - resetting the send/receive numbers
+ // - removing packets from the WackQ
+ //
+
+ StopT1 (Link);
+ StopT2 (Link);
+ Link->Flags &= LINK_FLAGS_DEFERRED_MASK; // keep deferred operations
+
+ Link->SendWindowSize = 1;
+ Link->LinkBusy = FALSE;
+
+ Link->ReceiveWindowSize = 1;
+ Link->WindowErrors = 0;
+ Link->BestWindowSize = 1;
+ Link->WorstWindowSize = Link->MaxWindowSize;
+ Link->Flags |= LINK_FLAGS_JUMP_START;
+
+ Link->CurrentT1Timeout = Link->Provider->DefaultT1Timeout;
+ Link->BaseT1Timeout = Link->Provider->DefaultT1Timeout << DLC_TIMER_ACCURACY;
+ Link->CurrentPollRetransmits = 0;
+ Link->CurrentPollOutstanding = FALSE;
+ Link->T2Timeout = Link->Provider->DefaultT2Timeout;
+ Link->TiTimeout = Link->Provider->DefaultTiTimeout;
+ Link->LlcRetries = Link->Provider->LlcRetries;
+ Link->MaxWindowSize = Link->Provider->LlcMaxWindowSize;
+
+ //
+ // The rest is similar to NbfActivateLink
+ //
+
+ Link->State = LINK_STATE_CONNECTING;
+ Link->SendState = SEND_STATE_DOWN;
+ Link->ReceiveState = RECEIVE_STATE_DOWN;
+ Link->SendRetries = (UCHAR)Link->LlcRetries;
+
+ NbfSendSabme (Link, TRUE); // send SABME/p, StartT1, release lock
+#else
+ Link->State = LINK_STATE_ADM; // we're reset now.
+ NbfSendDm (Link, FALSE); // indicate disconnected, release lock
+
+ NbfStopLink (Link);
+
+ // moving to ADM, remove reference
+ NbfDereferenceLinkSpecial("Got DM in W_POLL", Link, LREF_NOT_ADM);
+#endif
+
+#if DBG
+ NbfPrint1("Received FRMR on link %lx\n", Link);
+#endif
+
+#if DBG
+ s = "READY";
+#endif
+ break;
+
+ case LINK_STATE_CONNECTING:
+
+ //
+ // We've sent a SABME and have just received a FRMR.
+ //
+
+ case LINK_STATE_W_POLL:
+
+ //
+ // We're waiting for his initial poll on a RR-c/p. Instead, we
+ // got a FRMR.
+ //
+
+ case LINK_STATE_W_FINAL:
+
+ //
+ // We're waiting for a RR-r/f from the remote guy but instead
+ // he sent FRMR.
+ //
+
+ case LINK_STATE_W_DISC_RSP:
+
+ //
+ // We've sent a DISC-c/p and have received a FRMR.
+ //
+
+ Link->State = LINK_STATE_ADM; // we're reset now.
+ NbfSendDm (Link, FALSE); // indicate disconnected, release lock
+
+ // moving to ADM, remove reference
+ NbfDereferenceLinkSpecial("Got DM in W_POLL", Link, LREF_NOT_ADM);
+
+#if DBG
+ s = "CONN/W_POLL/W_FINAL/W_DISC_RSP";
+#endif
+ break;
+
+ default:
+
+ ASSERT (FALSE);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "Unknown link state";
+#endif
+
+ } /* switch */
+
+} /* NbfProcessFrmr */
+
+
+VOID
+NbfProcessTest(
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PTP_LINK Link,
+ IN PDLC_U_FRAME Header
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a received TEST frame.
+
+Arguments:
+
+ Command - Boolean set to TRUE if command, else FALSE if response.
+
+ PollFinal - Boolean set to TRUE if Poll or Final.
+
+ Link - Pointer to a transport link object.
+
+ Header - Pointer to a DLC U-type frame.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ Header, PollFinal; // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessTest: Entered.\n");
+ }
+
+ //
+ // Process only: TEST-c/x.
+ //
+
+ // BUGBUG: respond to TEST on a link that is NULL.
+
+ if (!Command || (Link == NULL)) {
+ return;
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+
+#if DBG
+ PANIC ("NbfSendTest: Received Test Packet, not processing....\n");
+#endif
+ //NbfSendTest (Link, FALSE, PollFinal, Psdu);
+
+} /* NbfProcessTest */
+
+
+VOID
+NbfProcessXid(
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PTP_LINK Link,
+ IN PDLC_U_FRAME Header
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a received XID frame.
+
+Arguments:
+
+ Command - Boolean set to TRUE if command, else FALSE if response.
+
+ PollFinal - Boolean set to TRUE if Poll or Final.
+
+ Link - Pointer to a transport link object.
+
+ Header - Pointer to a DLC U-type frame.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ Header; // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessXid: Entered.\n");
+ }
+
+ //
+ // Process only: XID-c/x.
+ //
+
+ // BUGBUG: respond to XID with a link that is NULL.
+
+ if (!Command || (Link == NULL)) {
+ return;
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
+
+ NbfSendXid (Link, FALSE, PollFinal); // releases lock
+
+} /* NbfProcessXid */
+
+
+VOID
+NbfProcessSFrame(
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PTP_LINK Link,
+ IN PDLC_S_FRAME Header,
+ IN UCHAR CommandByte
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a received RR, RNR, or REJ frame.
+
+Arguments:
+
+ Command - Boolean set to TRUE if command, else FALSE if response.
+
+ PollFinal - Boolean set to TRUE if Poll or Final.
+
+ Link - Pointer to a transport link object.
+
+ Header - Pointer to a DLC S-type frame.
+
+ CommandByte - The command byte of the frame (RR, RNR, or REJ).
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+#if DBG
+ UCHAR *s;
+#endif
+ BOOLEAN Resend;
+ BOOLEAN AckedPackets;
+ UCHAR AckSequenceNumber;
+ UCHAR OldLinkSendRetries;
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint2 (" NbfProcessSFrame %s: Entered, Link: %lx\n", Link,
+ Command == DLC_CMD_RR ? "RR" : (Command == DLC_CMD_RNR ? "RNR" : "REJ"));
+ }
+
+ //
+ // Process any of: RR-x/x, RNR-x/x, REJ-x/x
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
+
+ if (CommandByte == DLC_CMD_RNR) {
+ Link->LinkBusy = TRUE; // he's set a busy condition.
+ } else {
+ Link->LinkBusy = FALSE; // busy condition cleared.
+ }
+
+ switch (Link->State) {
+
+ case LINK_STATE_ADM:
+
+ //
+ // We're disconnected. Tell him.
+ //
+
+#if DBG
+ s = "ADM";
+#endif
+ NbfSendDm (Link, PollFinal); // releases lock
+ break;
+
+ case LINK_STATE_READY:
+
+ //
+ // Link is balanced. Note that the sections below surrounded by
+ // if (Command && PollFinal) variants are all disjoint sets.
+ // That's the only reason the Spinlock stuff works right. DO NOT
+ // attempt to fiddle this unless you figure out the locking first!
+ //
+
+ //
+ // If the AckSequenceNumber is not valid, ignore it. The
+ // number should be between the first packet on the WackQ
+ // and one more than the last packet. These correspond to
+ // Link->LastAckReceived and Link->NextSend.
+ //
+
+ AckSequenceNumber = (UCHAR)(Header->RcvSeq >> 1);
+
+ if (Link->NextSend >= Link->LastAckReceived) {
+
+ //
+ // There is no 127 -> 0 wrap between the two...
+ //
+
+ if ((AckSequenceNumber < Link->LastAckReceived) ||
+ (AckSequenceNumber > Link->NextSend)) {
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ DbgPrint("NbfResendLlcPackets: %.2x-%.2x-%.2x-%.2x-%.2x-%.2x Unexpected N(R) %d, LastAck %d NextSend %d\n",
+ Link->HardwareAddress.Address[0],
+ Link->HardwareAddress.Address[1],
+ Link->HardwareAddress.Address[2],
+ Link->HardwareAddress.Address[3],
+ Link->HardwareAddress.Address[4],
+ Link->HardwareAddress.Address[5],
+ AckSequenceNumber, Link->LastAckReceived, Link->NextSend);
+#endif
+ break;
+
+ }
+
+ } else {
+
+ //
+ // There is a 127 -> 0 wrap between the two...
+ //
+
+ if ((AckSequenceNumber < Link->LastAckReceived) &&
+ (AckSequenceNumber > Link->NextSend)) {
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ DbgPrint("NbfResendLlcPackets: %.2x-%.2x-%.2x-%.2x-%.2x-%.2x Unexpected N(R) %d, LastAck %d NextSend %d\n",
+ Link->HardwareAddress.Address[0],
+ Link->HardwareAddress.Address[1],
+ Link->HardwareAddress.Address[2],
+ Link->HardwareAddress.Address[3],
+ Link->HardwareAddress.Address[4],
+ Link->HardwareAddress.Address[5],
+ AckSequenceNumber, Link->LastAckReceived, Link->NextSend);
+#endif
+ break;
+
+ }
+
+ }
+
+
+ //
+ // We always resend on a REJ, and never on an RNR;
+ // for an RR we may change Resend to TRUE below.
+ // If we get a REJ on a WAN line (T1 is more than
+ // five seconds) then we pretend this was a final
+ // so we will resend even if a poll was outstanding.
+ //
+
+ if (CommandByte == DLC_CMD_REJ) {
+ Resend = TRUE;
+ if (Link->CurrentT1Timeout >= ((5 * SECONDS) / SHORT_TIMER_DELTA)) {
+ PollFinal = TRUE;
+ }
+ OldLinkSendRetries = (UCHAR)Link->SendRetries;
+ } else {
+ Resend = FALSE;
+ }
+
+
+#if 0
+ //
+ // If we've got a request with no poll, must have fired T2 on
+ // the other side (or, if the other side is OS/2, he lost a
+ // packet and knows it or is telling me to lower the window size).
+ // In the T2 case, we've Acked current stuff, mark the window as
+ // needing adjustment at some future time. In the OS/2 cases, this
+ // is also the right thing to do.
+ //
+
+ if ((!Command) && (!PollFinal)) {
+ ;
+ }
+#endif
+
+ if (PollFinal) {
+
+ if (Command) {
+
+ //
+ // If he is checkpointing, then we must respond with RR-r/f to
+ // update him on the status of our reception of his I-frames.
+ //
+
+ StopT2 (Link); // we acked some I-frames.
+ NbfSendRr (Link, FALSE, PollFinal); // releases lock
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ } else {
+
+ //
+ // If we were checkpointing, and he has sent an RR-r/f, we
+ // can clear the checkpoint condition. Any packets which
+ // are still waiting for acknowlegement at this point must
+ // now be resent.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessRr: he's responded to our checkpoint.\n");
+ }
+ if (Link->SendState != SEND_STATE_CHECKPOINTING) {
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessRr: BUGBUG: not ckpting, but final received.\n");
+ }
+ } else if (CommandByte == DLC_CMD_RR) {
+ OldLinkSendRetries = (UCHAR)Link->SendRetries;
+ Resend = TRUE;
+ UpdateBaseT1Timeout (Link); // gor response to poll
+ }
+ StopT1 (Link); // checkpointing finished.
+ Link->SendRetries = (UCHAR)Link->LlcRetries;
+ Link->SendState = SEND_STATE_READY;
+ StartTi (Link);
+ }
+ }
+
+ //
+ // NOTE: The link spinlock is held here.
+ //
+
+ //
+ // The N(R) in this frame acknowleges some (or all) of our packets.
+ // We'll ack packets on our send queue if this is a final when we
+ // call Resend. This call must come after the checkpoint
+ // acknowlegement check so that an RR-r/f is always sent BEFORE
+ // any new I-frames. This allows us to always send I-frames as
+ // commands.
+ //
+
+ if (Link->WackQ.Flink != &Link->WackQ) {
+
+ //
+ // NOTE: ResendLlcPackets may release and reacquire
+ // the link spinlock.
+ //
+
+ AckedPackets = ResendLlcPackets(
+ Link,
+ AckSequenceNumber,
+ Resend);
+
+ if (Resend && (!AckedPackets) && (Link->State == LINK_STATE_READY)) {
+
+ //
+ // To prevent stalling, pretend this RR wasn't
+ // received.
+ //
+
+ if (OldLinkSendRetries == 1) {
+
+ CancelT1Timeout (Link); // we are stopping a polling state
+
+ Link->State = LINK_STATE_W_DISC_RSP; // we are awaiting a DISC/f.
+ Link->SendState = SEND_STATE_DOWN;
+ Link->ReceiveState = RECEIVE_STATE_DOWN;
+ Link->SendRetries = (UCHAR)Link->LlcRetries;
+
+#if DBG
+ DbgPrint ("NBF: No ack teardown of %lx\n", Link);
+#endif
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ NbfStopLink (Link);
+
+ StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME)); // retransmit timer.
+ NbfSendDisc (Link, TRUE); // send DISC-c/p.
+
+ } else {
+
+ StopTi (Link);
+ Link->SendRetries = OldLinkSendRetries-1;
+
+ if (Link->SendState != SEND_STATE_CHECKPOINTING) {
+ Link->SendState = SEND_STATE_CHECKPOINTING;
+ NbfSendRr (Link, TRUE, TRUE);// send RR-c/p, StartT1, release lock
+ } else {
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ }
+
+ }
+#if DBG
+ s = "READY";
+#endif
+ break; // No need to RestartLinkTraffic
+
+ } else if (AckedPackets) {
+
+ Link->SendRetries = (UCHAR)Link->LlcRetries;
+
+ }
+
+ }
+
+
+ //
+ // If the link send state is READY, get the link going
+ // again.
+ //
+ // NOTE: RestartLinkTraffic releases the link spinlock.
+ //
+
+ if (Link->SendState == SEND_STATE_READY) {
+ RestartLinkTraffic (Link);
+ } else {
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ }
+#if DBG
+ s = "READY";
+#endif
+ break;
+
+ case LINK_STATE_CONNECTING:
+
+ //
+ // We've sent a SABME and are waiting for a UA. He's sent a
+ // RR too early, so just let the SABME timeout.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "CONNECTING";
+#endif
+ break;
+
+ case LINK_STATE_W_POLL:
+
+ //
+ // We're waiting for his initial poll on a RR-c/p. If he just
+ // sends something without a poll, we'll let that get by.
+ //
+
+ if (!Command) {
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "W_POLL";
+#endif
+ break; // don't allow this protocol.
+ }
+ Link->State = LINK_STATE_READY; // we're up!
+
+ FakeUpdateBaseT1Timeout (Link);
+ NbfSendRr (Link, FALSE, PollFinal); // send RR-r/x, release lock
+ NbfCompleteLink (Link); // fire up the connections.
+ IF_NBFDBG (NBF_DEBUG_SETUP) {
+ NbfPrint4("W_POLL RR on %lx %x-%x-%x\n",
+ Link,
+ Link->HardwareAddress.Address[3],
+ Link->HardwareAddress.Address[4],
+ Link->HardwareAddress.Address[5]);
+ }
+ StartTi (Link);
+
+#if DBG
+ s = "W_POLL";
+#endif
+ break;
+
+ case LINK_STATE_W_FINAL:
+
+ //
+ // We're waiting for a RR-r/f from the remote guy.
+ //
+
+ if (Command || !PollFinal) { // wait for final.
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "W_FINAL";
+#endif
+ break; // we sent RR-c/p.
+ }
+ Link->State = LINK_STATE_READY; // we're up.
+ StopT1 (Link); // poll was acknowleged.
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ NbfCompleteLink (Link); // fire up the connections.
+ StartTi (Link);
+#if DBG
+ s = "W_FINAL";
+#endif
+ break;
+
+ case LINK_STATE_W_DISC_RSP:
+
+ //
+ // We're waiting for a response from our DISC-c/p but instead of
+ // a UA-r/f, we got this RR. Throw the packet away.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "W_DISC_RSP";
+#endif
+ break;
+
+ default:
+
+ ASSERT (FALSE);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "Unknown link state";
+#endif
+
+ } /* switch */
+
+#if DBG
+ if (CommandByte == DLC_CMD_REJ) {
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 (" NbfProcessRej: (%s) REJ received.\n", s);
+ }
+ }
+#endif
+
+} /* NbfProcessSFrame */
+
+
+VOID
+NbfInsertInLoopbackQueue (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN UCHAR LinkIndex
+ )
+
+/*++
+
+Routine Description:
+
+ This routine places a packet on the loopback queue, and
+ queues a DPC to do the indication if needed.
+
+Arguments:
+
+ DeviceContext - The device context in question.
+
+ NdisPacket - The packet to place on the loopback queue.
+
+ LinkIndex - The index of the loopback link to indicate to.
+
+Return Value:
+
+ None:
+
+--*/
+
+{
+ PSEND_PACKET_TAG SendPacketTag;
+ KIRQL oldirql;
+
+ SendPacketTag = (PSEND_PACKET_TAG)NdisPacket->ProtocolReserved;
+ SendPacketTag->OnLoopbackQueue = TRUE;
+
+ SendPacketTag->LoopbackLinkIndex = LinkIndex;
+
+ ACQUIRE_SPIN_LOCK(&DeviceContext->LoopbackSpinLock, &oldirql);
+
+ InsertTailList(&DeviceContext->LoopbackQueue, &SendPacketTag->Linkage);
+
+ if (!DeviceContext->LoopbackInProgress) {
+
+ KeInsertQueueDpc(&DeviceContext->LoopbackDpc, NULL, NULL);
+ DeviceContext->LoopbackInProgress = TRUE;
+
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->LoopbackSpinLock, oldirql);
+
+}
+
+
+VOID
+NbfProcessLoopbackQueue (
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+
+/*++
+
+Routine Description:
+
+ This is the DPC routine which processes items on the
+ loopback queue. It processes a single request off the
+ queue (if there is one), then if there is another request
+ it requeues itself.
+
+Arguments:
+
+ Dpc - The system DPC object.
+
+ DeferredContext - A pointer to the device context.
+
+ SystemArgument1, SystemArgument2 - Not used.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ PNDIS_PACKET NdisPacket;
+ PNDIS_BUFFER FirstBuffer;
+ PVOID LookaheadBuffer;
+ UINT LookaheadBufferSize;
+ UINT BytesCopied;
+ UINT PacketSize;
+ ULONG HeaderLength;
+ PTP_LINK Link;
+ PSEND_PACKET_TAG SendPacketTag;
+ PLIST_ENTRY p;
+
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(SystemArgument1);
+ UNREFERENCED_PARAMETER(SystemArgument2);
+
+
+ DeviceContext = (PDEVICE_CONTEXT)DeferredContext;
+
+ ACQUIRE_DPC_SPIN_LOCK(&DeviceContext->LoopbackSpinLock);
+
+ if (!IsListEmpty(&DeviceContext->LoopbackQueue)) {
+
+ p = RemoveHeadList(&DeviceContext->LoopbackQueue);
+
+ //
+ // BUGBUG: This depends on the fact that the Linkage field is
+ // the first one in ProtocolReserved.
+ //
+
+ NdisPacket = CONTAINING_RECORD(p, NDIS_PACKET, ProtocolReserved[0]);
+
+ SendPacketTag = (PSEND_PACKET_TAG)NdisPacket->ProtocolReserved;
+ SendPacketTag->OnLoopbackQueue = FALSE;
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LoopbackSpinLock);
+
+
+ //
+ // Determine the data needed to indicate. We don't guarantee
+ // that we will have the correct lookahead length, but since
+ // we know that any header we prepend is a single piece,
+ // and that's all we'll have to look at in an indicated packet,
+ // that's not a concern.
+ //
+ // Unfortunately that last paragraph is bogus since for
+ // indications to our client we need more data...
+ //
+
+ NdisQueryPacket(NdisPacket, NULL, NULL, &FirstBuffer, &PacketSize);
+
+ NdisQueryBuffer(FirstBuffer, &LookaheadBuffer, &LookaheadBufferSize);
+
+ if ((LookaheadBufferSize != PacketSize) &&
+ (LookaheadBufferSize < NBF_MAX_LOOPBACK_LOOKAHEAD)) {
+
+ //
+ // There is not enough contiguous data in the
+ // packet's first buffer, so we merge it into
+ // DeviceContext->LookaheadContiguous.
+ //
+
+ if (PacketSize > NBF_MAX_LOOPBACK_LOOKAHEAD) {
+ LookaheadBufferSize = NBF_MAX_LOOPBACK_LOOKAHEAD;
+ } else {
+ LookaheadBufferSize = PacketSize;
+ }
+
+ NbfCopyFromPacketToBuffer(
+ NdisPacket,
+ 0,
+ LookaheadBufferSize,
+ DeviceContext->LookaheadContiguous,
+ &BytesCopied);
+
+ ASSERT (BytesCopied == LookaheadBufferSize);
+
+ LookaheadBuffer = DeviceContext->LookaheadContiguous;
+
+ }
+
+
+ //
+ // Now determine which link to loop it back to;
+ // UI frames are not indicated on any link.
+ //
+
+ SendPacketTag = (PSEND_PACKET_TAG)NdisPacket->ProtocolReserved;
+
+ //
+ // Hold DeviceContext->LinkSpinLock until we get a
+ // reference.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ switch (SendPacketTag->LoopbackLinkIndex) {
+
+ case LOOPBACK_TO_CONNECTOR:
+
+ Link = DeviceContext->LoopbackLinks[CONNECTOR_LINK];
+ break;
+
+ case LOOPBACK_TO_LISTENER:
+
+ Link = DeviceContext->LoopbackLinks[LISTENER_LINK];
+ break;
+
+ case LOOPBACK_UI_FRAME:
+ default:
+
+ Link = (PTP_LINK)NULL;
+ break;
+
+ }
+
+ //
+ // For non-null links, we have to reference them.
+ // We use LREF_TREE since that is what
+ // NbfGeneralReceiveHandler expects.
+ //
+
+ if (Link != (PTP_LINK)NULL) {
+ NbfReferenceLink("loopback indication", Link, LREF_TREE);
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ MacReturnHeaderLength(
+ &DeviceContext->MacInfo,
+ LookaheadBuffer,
+ &HeaderLength);
+
+ DeviceContext->LoopbackHeaderLength = HeaderLength;
+
+ //
+ // Process the receive like any other. We don't have to
+ // worry about frame padding since we construct the
+ // frame ourselves.
+ //
+
+ NbfGeneralReceiveHandler(
+ DeviceContext,
+ (NDIS_HANDLE)NdisPacket,
+ &DeviceContext->LocalAddress, // since it is loopback
+ Link,
+ LookaheadBuffer, // header
+ PacketSize - HeaderLength, // total packet size
+ (PDLC_FRAME)((PUCHAR)LookaheadBuffer + HeaderLength), // l/a data
+ LookaheadBufferSize - HeaderLength, // lookahead data length
+ TRUE
+ );
+
+
+ //
+ // Now complete the send.
+ //
+
+ NbfSendCompletionHandler(
+ DeviceContext->NdisBindingHandle,
+ NdisPacket,
+ NDIS_STATUS_SUCCESS
+ );
+
+
+ ACQUIRE_DPC_SPIN_LOCK(&DeviceContext->LoopbackSpinLock);
+
+ if (!IsListEmpty(&DeviceContext->LoopbackQueue)) {
+
+ KeInsertQueueDpc(&DeviceContext->LoopbackDpc, NULL, NULL);
+
+ //
+ // Remove these two lines if it is decided thet
+ // NbfReceiveComplete should be called after every
+ // loopback indication.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LoopbackSpinLock);
+ return;
+
+ } else {
+
+ DeviceContext->LoopbackInProgress = FALSE;
+
+ }
+
+ } else {
+
+ //
+ // This shouldn't happen!
+ //
+
+ DeviceContext->LoopbackInProgress = FALSE;
+
+#if DBG
+ NbfPrint1("Loopback queue empty for device context %x\n", DeviceContext);
+#endif
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LoopbackSpinLock);
+
+ NbfReceiveComplete(
+ (NDIS_HANDLE)DeviceContext
+ );
+
+} /* NbfProcessLoopbackQueue */
+
+
+NDIS_STATUS
+NbfReceiveIndication (
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a frame has been received on the physical link.
+ This routine is time critical, so we only allocate a
+ buffer and copy the packet into it. We also perform minimal
+ validation on this packet. It gets queued to the device context
+ to allow for processing later.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+ ReceiveContext - A magic cookie for the MAC.
+
+ HeaderBuffer - pointer to a buffer containing the packet header.
+
+ HeaderBufferSize - the size of the header.
+
+ LookaheadBuffer - pointer to a buffer containing the negotiated minimum
+ amount of buffer I get to look at (not including header).
+
+ LookaheadBufferSize - the size of the above. May be less than asked
+ for, if that's all there is.
+
+ PacketSize - Overall size of the packet (not including header).
+
+Return Value:
+
+ NDIS_STATUS - status of operation, one of:
+
+ NDIS_STATUS_SUCCESS if packet accepted,
+ NDIS_STATUS_NOT_RECOGNIZED if not recognized by protocol,
+ NDIS_any_other_thing if I understand, but can't handle.
+
+--*/
+{
+ PDEVICE_CONTEXT DeviceContext;
+ KIRQL oldirql;
+ PTP_LINK Link;
+ HARDWARE_ADDRESS SourceAddressBuffer;
+ PHARDWARE_ADDRESS SourceAddress;
+ UINT RealPacketSize;
+ PDLC_FRAME DlcHeader;
+ BOOLEAN Multicast;
+
+ ENTER_NBF;
+
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ PUCHAR p;
+ SHORT i;
+ NbfPrint2 ("NbfReceiveIndication: Packet, Size: 0x0%lx LookaheadSize: 0x0%lx\n 00:",
+ PacketSize, LookaheadBufferSize);
+ p = (PUCHAR)LookaheadBuffer;
+ for (i=0;i<25;i++) {
+ NbfPrint1 (" %2x",p[i]);
+ }
+ NbfPrint0 ("\n");
+ }
+
+ DeviceContext = (PDEVICE_CONTEXT)BindingContext;
+
+ RealPacketSize = 0;
+
+ //
+ // Obtain the packet length; this may optionally adjust
+ // the lookahead buffer forward if the header we wish
+ // to remove spills over into what the MAC considers
+ // data. If it determines that the header is not
+ // valid, it keeps RealPacketSize at 0.
+ //
+
+ MacReturnPacketLength(
+ &DeviceContext->MacInfo,
+ HeaderBuffer,
+ HeaderBufferSize,
+ PacketSize,
+ &RealPacketSize,
+ &LookaheadBuffer,
+ &LookaheadBufferSize
+ );
+
+ if (RealPacketSize < 2) {
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint1 ("NbfReceiveIndication: Discarding packet, bad length %lx\n",
+ HeaderBuffer);
+ }
+ return NDIS_STATUS_NOT_RECOGNIZED;
+ }
+
+ //
+ // We've negotiated at least a contiguous DLC header passed back in the
+ // lookahead buffer. Check it to see if we want this packet.
+ //
+
+ DlcHeader = (PDLC_FRAME)LookaheadBuffer;
+
+ if (((*(USHORT UNALIGNED *)(&DlcHeader->Dsap)) &
+ (USHORT)((DLC_SSAP_MASK << 8) | DLC_DSAP_MASK)) !=
+ (USHORT)((DSAP_NETBIOS_OVER_LLC << 8) | DSAP_NETBIOS_OVER_LLC)) {
+
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint1 ("NbfReceiveIndication: Discarding lookahead data, not NetBIOS: %lx\n",
+ LookaheadBuffer);
+ }
+ LEAVE_NBF;
+ return NDIS_STATUS_NOT_RECOGNIZED; // packet was processed.
+ }
+
+
+ //
+ // Check that the packet is not too long.
+ //
+
+ if (PacketSize > DeviceContext->MaxReceivePacketSize) {
+#if DBG
+ NbfPrint2("NbfReceiveIndication: Ignoring packet length %d, max %d\n",
+ PacketSize, DeviceContext->MaxReceivePacketSize);
+#endif
+ return NDIS_STATUS_NOT_RECOGNIZED;
+ }
+
+ MacReturnSourceAddress(
+ &DeviceContext->MacInfo,
+ HeaderBuffer,
+ &SourceAddressBuffer,
+ &SourceAddress,
+ &Multicast
+ );
+
+ //
+ // Record how many multicast packets we get, to monitor
+ // general network activity.
+ //
+
+ if (Multicast) {
+ ++DeviceContext->MulticastPacketCount;
+ }
+
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ //
+ // Unless this is a UI frame find the Link this packet belongs to.
+ // If there is not a recognized link, pass the frame on to be handled
+ // by the receive complete code.
+ //
+
+ if ((((PDLC_U_FRAME)LookaheadBuffer)->Command) != DLC_CMD_UI) {
+
+ // This adds a link reference if it is found
+
+ Link = NbfFindLink (DeviceContext, SourceAddress->Address);
+
+ if (Link != NULL) {
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 ("NbfReceiveIndication: Found link, Link: %lx\n", Link);
+ }
+
+ }
+
+ } else {
+
+ Link = NULL;
+
+ }
+
+
+ NbfGeneralReceiveHandler(
+ DeviceContext,
+ ReceiveContext,
+ SourceAddress,
+ Link,
+ HeaderBuffer, // header
+ RealPacketSize, // total data length in packet
+ (PDLC_FRAME)LookaheadBuffer, // lookahead data
+ LookaheadBufferSize, // lookahead data length
+ FALSE // not loopback
+ );
+
+ KeLowerIrql (oldirql);
+
+ return STATUS_SUCCESS;
+
+} /* NbfReceiveIndication */
+
+
+VOID
+NbfGeneralReceiveHandler (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PTP_LINK Link,
+ IN PVOID HeaderBuffer,
+ IN UINT PacketSize,
+ IN PDLC_FRAME DlcHeader,
+ IN UINT DlcSize,
+ IN BOOLEAN Loopback
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from either NbfReceiveIndication
+ or NbfProcessLoopbackQueue. It continues the processing of
+ indicated data once the link has been determined.
+
+ This routine is time critical, so we only allocate a
+ buffer and copy the packet into it. We also perform minimal
+ validation on this packet. It gets queued to the device context
+ to allow for processing later.
+
+Arguments:
+
+ DeviceContext - The device context of this adapter.
+
+ ReceiveContext - A magic cookie for the MAC.
+
+ SourceAddress - The source address of the packet.
+
+ Link - The link that this packet was received on, may be NULL
+ if the link was not found. If not NULL, Link will have
+ a reference of type LREF_TREE.
+
+ HeaderBuffer - pointer to the packet header.
+
+ PacketSize - Overall size of the packet (not including header).
+
+ DlcHeader - Points to the DLC header of the packet.
+
+ DlcSize - The length of the packet indicated, starting from DlcHeader.
+
+ Loopback - TRUE if this was called by NbfProcessLoopbackQueue;
+ used to determine whether to call NdisTransferData or
+ NbfTransferLoopbackData.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PNDIS_PACKET NdisPacket;
+ NTSTATUS Status;
+ PNDIS_BUFFER NdisBuffer;
+ NDIS_STATUS NdisStatus;
+ PSINGLE_LIST_ENTRY linkage;
+ UINT BytesTransferred;
+ BOOLEAN Command;
+ BOOLEAN PollFinal;
+ PRECEIVE_PACKET_TAG ReceiveTag;
+ PBUFFER_TAG BufferTag;
+ PUCHAR SourceRouting;
+ UINT SourceRoutingLength;
+ PDLC_I_FRAME IHeader;
+ PDLC_U_FRAME UHeader;
+ PDLC_S_FRAME SHeader;
+ PTP_ADDRESS DatagramAddress;
+ UINT NdisBufferLength;
+ PVOID BufferPointer;
+
+ ENTER_NBF;
+
+
+ INCREMENT_COUNTER (DeviceContext, PacketsReceived);
+
+ Command = (BOOLEAN)!(DlcHeader->Ssap & DLC_SSAP_RESPONSE);
+
+ if (Link == (PTP_LINK)NULL) {
+ UHeader = (PDLC_U_FRAME)DlcHeader;
+ if (((UHeader->Command & ~DLC_U_PF) == DLC_CMD_UI) && Command) {
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfGeneralReceiveHandler: Processing packet as UI frame.\n");
+ }
+
+ MacReturnSourceRouting(
+ &DeviceContext->MacInfo,
+ HeaderBuffer,
+ &SourceRouting,
+ &SourceRoutingLength);
+
+ if (SourceRoutingLength > MAX_SOURCE_ROUTING) {
+ Status = STATUS_ABANDONED;
+ }
+ else {
+ Status = NbfProcessUi (
+ DeviceContext,
+ SourceAddress,
+ HeaderBuffer,
+ (PUCHAR)UHeader,
+ DlcSize,
+ SourceRouting,
+ SourceRoutingLength,
+ &DatagramAddress);
+ }
+ } else {
+
+ //
+ // or drop on the floor. (BUGBUG: Note that state tables say that
+ // we'll always handle a DM with a DM response. This should change.)
+ //
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfReceiveIndication: it's not a UI frame!\n");
+ }
+ Status = STATUS_SUCCESS;
+ }
+
+ if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
+
+ LEAVE_NBF;
+ return;
+
+ } else if (((PNBF_HDR_CONNECTIONLESS)((PUCHAR)UHeader + 3))->Command ==
+ NBF_CMD_STATUS_RESPONSE) {
+
+ (VOID)NbfProcessStatusResponse(
+ DeviceContext,
+ ReceiveContext,
+ (PNBF_HDR_CONNECTIONLESS)((PUCHAR)UHeader + 3),
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+ return;
+
+ } else {
+ goto HandleAtComplete; // only datagrams will get through this
+ }
+ }
+
+
+ //
+ // At this point we have a link reference count of type LREF_TREE
+ //
+
+ ++Link->PacketsReceived;
+
+ //
+ // deal with I-frames first; they are what we expect the most of...
+ //
+
+ if (!(DlcHeader->Byte1 & DLC_I_INDICATOR)) {
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 ("NbfReceiveIndication: I-frame encountered.\n");
+ }
+ if (DlcSize >= 4 + sizeof (NBF_HDR_CONNECTION)) {
+ IHeader = (PDLC_I_FRAME)DlcHeader;
+ NbfProcessIIndicate (
+ Command,
+ (BOOLEAN)(IHeader->RcvSeq & DLC_I_PF),
+ Link,
+ (PUCHAR)DlcHeader,
+ DlcSize,
+ PacketSize,
+ ReceiveContext,
+ Loopback);
+ } else {
+#if DBG
+// IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 ("NbfReceiveIndication: Runt I-frame, discarded!\n");
+// }
+#endif
+ ;
+ }
+
+ } else if (((DlcHeader->Byte1 & DLC_U_INDICATOR) == DLC_U_INDICATOR)) {
+
+ //
+ // different case switches for S and U frames, because structures
+ // are different.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint0 ("NbfReceiveIndication: U-frame encountered.\n");
+ }
+
+ UHeader = (PDLC_U_FRAME)DlcHeader;
+ PollFinal = (BOOLEAN)(UHeader->Command & DLC_U_PF);
+ switch (UHeader->Command & ~DLC_U_PF) {
+
+ case DLC_CMD_SABME:
+ NbfProcessSabme (Command, PollFinal, Link, UHeader,
+ HeaderBuffer, SourceAddress, DeviceContext);
+ break;
+
+ case DLC_CMD_DISC:
+ NbfProcessDisc (Command, PollFinal, Link, UHeader);
+ break;
+
+ case DLC_CMD_UA:
+ NbfProcessUa (Command, PollFinal, Link, UHeader);
+ break;
+
+ case DLC_CMD_DM:
+ NbfProcessDm (Command, PollFinal, Link, UHeader);
+ break;
+
+ case DLC_CMD_FRMR:
+ NbfProcessFrmr (Command, PollFinal, Link, UHeader);
+ break;
+
+ case DLC_CMD_UI:
+
+ ASSERT (FALSE);
+ break;
+
+ case DLC_CMD_XID:
+ PANIC ("ReceiveIndication: XID!\n");
+ NbfProcessXid (Command, PollFinal, Link, UHeader);
+ break;
+
+ case DLC_CMD_TEST:
+ PANIC ("NbfReceiveIndication: TEST!\n");
+ NbfProcessTest (Command, PollFinal, Link, UHeader);
+ break;
+
+ default:
+ PANIC ("NbfReceiveIndication: bad U-frame, packet dropped.\n");
+
+ } /* switch */
+
+ } else {
+
+ //
+ // We have an S-frame.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 ("NbfReceiveIndication: S-frame encountered.\n");
+ }
+ SHeader = (PDLC_S_FRAME)DlcHeader;
+ PollFinal = (BOOLEAN)(SHeader->RcvSeq & DLC_S_PF);
+ switch (SHeader->Command) {
+
+ case DLC_CMD_RR:
+ case DLC_CMD_RNR:
+ case DLC_CMD_REJ:
+ NbfProcessSFrame (Command, PollFinal, Link, SHeader, SHeader->Command);
+ break;
+
+ default:
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfReceiveIndication: bad S-frame.\n");
+ }
+
+ } /* switch */
+
+ } // if U-frame or S-frame
+
+ //
+ // If we reach here, the packet has been processed. If it needs
+ // to be copied, we will jump to HandleAtComplete.
+ //
+
+ NbfDereferenceLinkMacro ("Done with Indicate frame", Link, LREF_TREE);
+ LEAVE_NBF;
+ return;
+
+HandleAtComplete:;
+
+ //
+ // At this point we DO NOT have any link references added in
+ // this function.
+ //
+
+ linkage = ExInterlockedPopEntryList(
+ &DeviceContext->ReceivePacketPool,
+ &DeviceContext->Interlock);
+
+ if (linkage != NULL) {
+ NdisPacket = CONTAINING_RECORD( linkage, NDIS_PACKET, ProtocolReserved[0] );
+ } else {
+ // PANIC ("NbfReceiveIndicate: Discarding Packet, no receive packets.\n");
+ DeviceContext->ReceivePacketExhausted++;
+ LEAVE_NBF;
+ return;
+ }
+ ReceiveTag = (PRECEIVE_PACKET_TAG)(NdisPacket->ProtocolReserved);
+
+ linkage = ExInterlockedPopEntryList(
+ &DeviceContext->ReceiveBufferPool,
+ &DeviceContext->Interlock);
+
+ if (linkage != NULL) {
+ BufferTag = CONTAINING_RECORD( linkage, BUFFER_TAG, Linkage);
+ } else {
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceivePacketPool,
+ &ReceiveTag->Linkage,
+ &DeviceContext->Interlock);
+ // PANIC ("NbfReceiveIndicate: Discarding Packet, no receive buffers.\n");
+ DeviceContext->ReceiveBufferExhausted++;
+ LEAVE_NBF;
+ return;
+ }
+
+ NdisAdjustBufferLength (BufferTag->NdisBuffer, PacketSize);
+ NdisChainBufferAtFront (NdisPacket, BufferTag->NdisBuffer);
+
+ //
+ // DatagramAddress has a reference of type AREF_PROCESS_DATAGRAM,
+ // unless this is a datagram intended for RAS only, in which case
+ // it is NULL.
+ //
+
+ BufferTag->Address = DatagramAddress;
+
+ //
+ // set up async return status so we can tell when it has happened;
+ // can never get return of NDIS_STATUS_PENDING in synch completion routine
+ // for NdisTransferData, so we know it has completed when this status
+ // changes
+ //
+
+ BufferTag->NdisStatus = NDIS_STATUS_PENDING;
+ ReceiveTag->PacketType = TYPE_AT_COMPLETE;
+
+ ExInterlockedInsertTailList(
+ &DeviceContext->ReceiveInProgress,
+ &BufferTag->Linkage,
+ &DeviceContext->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 ("NbfReceiveIndicate: Packet on Queue: %lx\n",NdisPacket);
+ }
+
+ //
+ // receive packet is mapped at initalize
+ //
+
+ //
+ // Determine how to handle the data transfer.
+ //
+
+ if (Loopback) {
+
+ NbfTransferLoopbackData(
+ &NdisStatus,
+ DeviceContext,
+ ReceiveContext,
+ DeviceContext->MacInfo.TransferDataOffset,
+ PacketSize,
+ NdisPacket,
+ &BytesTransferred
+ );
+
+ } else {
+
+ NdisTransferData (
+ &NdisStatus,
+ DeviceContext->NdisBindingHandle,
+ ReceiveContext,
+ DeviceContext->MacInfo.TransferDataOffset,
+ PacketSize,
+ NdisPacket,
+ &BytesTransferred);
+
+ }
+
+ //
+ // handle the various error codes
+ //
+
+ switch (NdisStatus) {
+ case NDIS_STATUS_SUCCESS: // received packet
+ BufferTag->NdisStatus = NDIS_STATUS_SUCCESS;
+
+ if (BytesTransferred == PacketSize) { // Did we get the entire packet?
+ ReceiveTag->PacketType = TYPE_AT_INDICATE;
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceivePacketPool,
+ &ReceiveTag->Linkage,
+ &DeviceContext->Interlock);
+ LEAVE_NBF;
+ return;
+ }
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint2 ("NbfReceiveIndicate: Discarding Packet, Partial transfer: 0x0%lx of 0x0%lx transferred\n",
+ BytesTransferred, PacketSize);
+ }
+ break;
+
+ case NDIS_STATUS_PENDING: // waiting async complete from NdisTransferData
+ LEAVE_NBF;
+ return;
+ break;
+
+ default: // something broke; certainly we'll never get NdisTransferData
+ // asynch completion with this error status...
+ break;
+ }
+
+ //
+ // receive failed, for some reason; cleanup and fail return
+ // BUGBUG: Statistics go here
+ //
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 ("NbfReceiveIndicate: Discarding Packet, transfer failed: %s\n",
+ NbfGetNdisStatus (NdisStatus));
+ }
+#endif
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+ RemoveEntryList (&BufferTag->Linkage);
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ ReceiveTag->PacketType = TYPE_AT_INDICATE;
+
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceivePacketPool,
+ &ReceiveTag->Linkage,
+ &DeviceContext->Interlock);
+
+ NdisQueryBuffer (NdisBuffer, &BufferPointer, &NdisBufferLength);
+ BufferTag = CONTAINING_RECORD (
+ BufferPointer,
+ BUFFER_TAG,
+ Buffer[0]
+ );
+ NdisAdjustBufferLength (NdisBuffer, BufferTag->Length); // reset to good value
+
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceiveBufferPool,
+ (PSINGLE_LIST_ENTRY)&BufferTag->Linkage,
+ &DeviceContext->Interlock);
+
+ if (DatagramAddress) {
+ NbfDereferenceAddress ("DG TransferData failed", DatagramAddress, AREF_PROCESS_DATAGRAM);
+ }
+
+ LEAVE_NBF;
+ return;
+
+} /* NbfGeneralReceiveHandler */
+
+
+
+VOID
+NbfTransferDataComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus,
+ IN UINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that an NdisTransferData has completed. We use this indication
+ to start stripping buffers from the receive queue.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+ NdisPacket/RequestHandle - An identifier for the request that completed.
+
+ NdisStatus - The completion status for the request.
+
+ BytesTransferred - Number of bytes actually transferred.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)BindingContext;
+ PRECEIVE_PACKET_TAG ReceiveTag;
+ PTP_CONNECTION Connection;
+ KIRQL oldirql1;
+ PTP_REQUEST Request;
+ PNDIS_BUFFER NdisBuffer;
+ UINT NdisBufferLength;
+ PVOID BufferPointer;
+ PBUFFER_TAG BufferTag;
+
+ //
+ // Put the NDIS status into a place we can use in packet processing.
+ // Note that this complete indication may be occuring during the call
+ // to NdisTransferData in the receive indication.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint2 (" NbfTransferDataComplete: Entered, Packet: %lx bytes transferred: 0x0%x\n",
+ NdisPacket, BytesTransferred);
+ }
+ ReceiveTag = (PRECEIVE_PACKET_TAG)(NdisPacket->ProtocolReserved);
+
+ //
+ // note that the processing below depends on having only one packet
+ // transfer outstanding at a time. NDIS is supposed to guarentee this.
+ //
+
+ switch (ReceiveTag->PacketType) {
+
+ case TYPE_AT_COMPLETE: // datagrams
+
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ NdisQueryBuffer (NdisBuffer, &BufferPointer, &NdisBufferLength);
+ BufferTag = CONTAINING_RECORD( BufferPointer, BUFFER_TAG, Buffer[0]);
+ BufferTag->NdisStatus = NdisStatus;
+
+ ReceiveTag->PacketType = TYPE_AT_INDICATE;
+
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceivePacketPool,
+ &ReceiveTag->Linkage,
+ &DeviceContext->Interlock);
+
+ break;
+
+ case TYPE_AT_INDICATE: // I-frames
+
+ //
+ // The transfer for this packet is complete. Was it successful??
+ //
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql1);
+
+ Connection = ReceiveTag->Connection;
+
+ //
+ // rip all of the NDIS_BUFFERs we've used off the chain and return them.
+ //
+
+ if (ReceiveTag->AllocatedNdisBuffer) {
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ while (NdisBuffer != NULL) {
+ NdisFreeBuffer (NdisBuffer);
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ }
+ } else {
+ NdisReinitializePacket (NdisPacket);
+ }
+
+
+ if ((NdisStatus != NDIS_STATUS_SUCCESS) ||
+ (!DeviceContext->MacInfo.SingleReceive)) {
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ ULONG DumpData[2];
+ DumpData[0] = BytesTransferred;
+ DumpData[1] = ReceiveTag->BytesToTransfer;
+
+ NbfWriteGeneralErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_TRANSFER_DATA,
+ 603,
+ NdisStatus,
+ NULL,
+ 2,
+ DumpData);
+
+ // Drop the packet.
+#if DBG
+ NbfPrint1 ("NbfTransferDataComplete: status %s\n",
+ NbfGetNdisStatus (NdisStatus));
+#endif
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ Connection->Flags |= CONNECTION_FLAGS_TRANSFER_FAIL;
+
+ } else {
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ }
+
+ Connection->TransferBytesPending -= ReceiveTag->BytesToTransfer;
+
+ if ((Connection->TransferBytesPending == 0) &&
+ (Connection->Flags & CONNECTION_FLAGS_TRANSFER_FAIL)) {
+
+ Connection->CurrentReceiveMdl = Connection->SavedCurrentReceiveMdl;
+ Connection->ReceiveByteOffset = Connection->SavedReceiveByteOffset;
+ Connection->MessageBytesReceived -= Connection->TotalTransferBytesPending;
+ Connection->Flags &= ~CONNECTION_FLAGS_TRANSFER_FAIL;
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ if ((Connection->Flags & CONNECTION_FLAGS_VERSION2) == 0) {
+ NbfSendNoReceive (Connection);
+ }
+ NbfSendReceiveOutstanding (Connection);
+
+ ReceiveTag->CompleteReceive = FALSE;
+
+ } else {
+
+ //
+ // BUGBUG: If we have more data outstanding, this can't
+ // be the last piece; i.e. we can't handle having
+ // the last piece complete asynchronously before
+ // an earlier piece.
+ //
+#if DBG
+ if (Connection->TransferBytesPending > 0) {
+ ASSERT (!ReceiveTag->CompleteReceive);
+ }
+#endif
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ }
+
+ if (!Connection->CurrentReceiveSynchronous) {
+ NbfDereferenceReceiveIrp ("TransferData complete", IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp), RREF_RECEIVE);
+ }
+
+
+ //
+ // dereference the connection to say we've done the I frame processing.
+ // This reference was done before calling NdisTransferData.
+ //
+
+ if (ReceiveTag->TransferDataPended) {
+ NbfDereferenceConnection("TransferData done", Connection, CREF_TRANSFER_DATA);
+ }
+
+
+ } else {
+
+ ASSERT (NdisStatus == STATUS_SUCCESS);
+ ASSERT (!ReceiveTag->TransferDataPended);
+ ASSERT (Connection->CurrentReceiveSynchronous);
+
+ if (!Connection->SpecialReceiveIrp) {
+ Connection->CurrentReceiveIrp->IoStatus.Information += BytesTransferred;
+ }
+
+ }
+
+
+ //
+ // see if we've completed the current receive. If so, move to the next one.
+ //
+
+ if (ReceiveTag->CompleteReceive) {
+ CompleteReceive (Connection, ReceiveTag->EndOfMessage, (ULONG)BytesTransferred);
+ }
+
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceivePacketPool,
+ &ReceiveTag->Linkage,
+ &DeviceContext->Interlock);
+
+ KeLowerIrql (oldirql1);
+
+ break;
+
+ case TYPE_STATUS_RESPONSE: // response to remote adapter status
+
+ //
+ // BUGBUG: Handle failure.
+ //
+
+#if DBG
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ DbgPrint ("NBF: STATUS_RESPONSE TransferData failed\n");
+ }
+#endif
+
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ ASSERT (NdisBuffer);
+ NdisFreeBuffer (NdisBuffer);
+
+ Request = (PTP_REQUEST)ReceiveTag->Connection;
+
+ if (ReceiveTag->CompleteReceive) {
+ NbfCompleteRequest(
+ Request,
+ ReceiveTag->EndOfMessage ? STATUS_SUCCESS : STATUS_BUFFER_OVERFLOW,
+ Request->BytesWritten);
+ }
+
+ NbfDereferenceRequest("Status xfer done", Request, RREF_STATUS);
+
+ ReceiveTag->PacketType = TYPE_AT_INDICATE;
+
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceivePacketPool,
+ &ReceiveTag->Linkage,
+ &DeviceContext->Interlock);
+
+ break;
+
+ default:
+#if DBG
+ NbfPrint1 ("NbfTransferDataComplete: Bang! Packet Transfer failed, unknown packet type: %ld\n",
+ ReceiveTag->PacketType);
+ DbgBreakPoint ();
+#endif
+ break;
+ }
+
+ //
+ // BUGBUG: Statistics need to be kept here.
+ //
+
+ return;
+
+} // NbfTransferDataComplete
+
+
+
+VOID
+NbfReceiveComplete (
+ IN NDIS_HANDLE BindingContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a connection(less) frame has been received on the
+ physical link. We dispatch to the correct packet handler here.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+ Nbf uses the DeviceContext for this parameter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ UINT i;
+ NTSTATUS Status;
+ KIRQL oldirql2;
+ BOOLEAN Command;
+ PDLC_U_FRAME UHeader;
+ PDLC_FRAME DlcHeader;
+ PLIST_ENTRY linkage;
+ UINT NdisBufferLength;
+ PVOID BufferPointer;
+ PBUFFER_TAG BufferTag;
+ PTP_ADDRESS Address;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+ PTP_CONNECTION Connection;
+ PTP_LINK Link;
+
+ ENTER_NBF;
+
+ //
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfReceiveComplete: Entered.\n");
+ }
+
+ DeviceContext = (PDEVICE_CONTEXT) BindingContext;
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql2);
+
+ //
+ // Complete all pending receives. Do a quick check
+ // without the lock.
+ //
+
+ while (!IsListEmpty (&DeviceContext->IrpCompletionQueue)) {
+
+ linkage = ExInterlockedRemoveHeadList(
+ &DeviceContext->IrpCompletionQueue,
+ &DeviceContext->Interlock);
+
+ if (linkage != NULL) {
+
+ Irp = CONTAINING_RECORD (linkage, IRP, Tail.Overlay.ListEntry);
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ Connection = IRP_RECEIVE_CONNECTION(IrpSp);
+
+ if (Connection == NULL) {
+#if DBG
+ DbgPrint ("Connection of Irp %lx is NULL\n", Irp);
+ DbgBreakPoint();
+#endif
+ }
+
+ IRP_RECEIVE_REFCOUNT(IrpSp) = 0;
+ IRP_RECEIVE_IRP (IrpSp) = NULL;
+
+ LEAVE_NBF;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ ENTER_NBF;
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ if (Connection->Flags & CONNECTION_FLAGS_RC_PENDING) {
+
+ Connection->Flags &= ~CONNECTION_FLAGS_RC_PENDING;
+
+ if (Connection->Flags & CONNECTION_FLAGS_PEND_INDICATE) {
+
+ Connection->Flags &= ~CONNECTION_FLAGS_PEND_INDICATE;
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // We got an indicate (and sent a NO_RECEIVE) while
+ // this was in progress, so send the receive outstanding
+ // now.
+ //
+
+ NbfSendReceiveOutstanding (Connection);
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ }
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ }
+
+ NbfDereferenceConnectionMacro ("receive completed", Connection, CREF_RECEIVE_IRP);
+
+ } else {
+
+ //
+ // ExInterlockedRemoveHeadList returned NULL, so don't
+ // bother looping back.
+ //
+
+ break;
+
+ }
+
+ }
+
+
+ //
+ // Packetize all waiting connections
+ //
+
+ if (!IsListEmpty(&DeviceContext->PacketizeQueue)) {
+
+ PacketizeConnections (DeviceContext);
+
+ }
+
+ if (!IsListEmpty (&DeviceContext->DeferredRrQueue)) {
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->Interlock);
+
+ while (!IsListEmpty(&DeviceContext->DeferredRrQueue)) {
+
+ linkage = RemoveHeadList (&DeviceContext->DeferredRrQueue);
+
+ Link = CONTAINING_RECORD (linkage, TP_LINK, DeferredRrLinkage);
+
+ Link->OnDeferredRrQueue = FALSE;
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->Interlock);
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ StopT2 (Link); // we're acking, so no delay req'd.
+ NbfSendRr (Link, FALSE, FALSE); // releases lock
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->Interlock);
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->Interlock);
+
+ }
+
+
+ //
+ // Get every waiting packet, in order...
+ //
+
+
+ if (!IsListEmpty (&DeviceContext->ReceiveInProgress)) {
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ while (!IsListEmpty (&DeviceContext->ReceiveInProgress)) {
+
+ linkage = RemoveHeadList (&DeviceContext->ReceiveInProgress);
+ BufferTag = CONTAINING_RECORD( linkage, BUFFER_TAG, Linkage);
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 (" NbfReceiveComplete: Processing Buffer %lx\n", BufferTag);
+ }
+
+ //
+ // NdisTransferData may have failed at async completion; check and
+ // see. If it did, then we discard this packet. If we're still waiting
+ // for transfer to complete, go back to sleep and hope (no guarantee!)
+ // we get waken up later.
+ //
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 (" NbfReceiveComplete: NdisStatus: %s.\n",
+ NbfGetNdisStatus(BufferTag->NdisStatus));
+ }
+#endif
+ if (BufferTag->NdisStatus == NDIS_STATUS_PENDING) {
+ InsertHeadList (&DeviceContext->ReceiveInProgress, linkage);
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfReceiveComplete: Status pending, returning packet to queue.\n");
+ }
+ KeLowerIrql (oldirql2);
+ LEAVE_NBF;
+ return;
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ if (BufferTag->NdisStatus != NDIS_STATUS_SUCCESS) {
+#if DBG
+ NbfPrint1 (" NbfReceiveComplete: Failed return from Transfer data, reason: %s\n",
+ NbfGetNdisStatus (BufferTag->NdisStatus));
+#endif
+ // BUGBUG: some statistics go here for lost packet
+
+ goto FreeBuffer; // skip the buffer, continue with while loop
+ }
+
+ //
+ // Have a buffer. Since I allocated the storage for it, I know it's
+ // virtually contiguous and can treat it that way, which I will
+ // henceforth.
+ //
+
+ NdisQueryBuffer (BufferTag->NdisBuffer, &BufferPointer, &NdisBufferLength);
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ PUCHAR pc;
+ NbfPrint0 (" NbfRC Packet: \n ");
+ pc = (PUCHAR)BufferPointer;
+ for (i=0;i<25;i++) {
+ NbfPrint1 (" %2x",pc[i]);
+ }
+ NbfPrint0 ("\n");
+ }
+
+ //
+ // Determine what address this is for, which is stored
+ // in the buffer tag header.
+ //
+
+ Address = BufferTag->Address;
+
+ //
+ // Process the frame as a UI frame; only datagrams should
+ // be processed here. If Address is NULL then this datagram
+ // is not needed for any bound address and should be given
+ // to RAS only.
+ //
+
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfReceiveComplete: Delivering this frame manually.\n");
+ }
+ DlcHeader = (PDLC_FRAME)BufferPointer;
+ Command = (BOOLEAN)!(DlcHeader->Ssap & DLC_SSAP_RESPONSE);
+ UHeader = (PDLC_U_FRAME)DlcHeader;
+
+ BufferPointer = (PUCHAR)BufferPointer + 3;
+ NdisBufferLength -= 3; // 3 less bytes.
+
+ if (Address != NULL) {
+
+ //
+ // Indicate it or complete posted datagrams.
+ //
+
+ Status = NbfIndicateDatagram (
+ DeviceContext,
+ Address,
+ BufferPointer, // the Dsdu, with some tweaking
+ NdisBufferLength);
+
+ //
+ // Dereference the address.
+ //
+
+ NbfDereferenceAddress ("Datagram done", Address, AREF_PROCESS_DATAGRAM);
+
+ }
+
+ //
+ // Let the RAS clients have a crack at this if they want
+ // (they only want directed datagrams, not broadcast).
+ //
+
+ if ((((PNBF_HDR_CONNECTIONLESS)BufferPointer)->Command == NBF_CMD_DATAGRAM) &&
+ (DeviceContext->IndicationQueuesInUse)) {
+
+ NbfActionDatagramIndication(
+ DeviceContext,
+ (PNBF_HDR_CONNECTIONLESS)BufferPointer,
+ NdisBufferLength);
+
+ }
+
+ BufferPointer = (PUCHAR)BufferPointer - 3;
+ NdisBufferLength += 3; // 3 more bytes.
+
+ //
+ // Finished with buffer; return to pool.
+ //
+
+FreeBuffer:;
+
+ NdisAdjustBufferLength (BufferTag->NdisBuffer, BufferTag->Length);
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceiveBufferPool,
+ (PSINGLE_LIST_ENTRY)&BufferTag->Linkage,
+ &DeviceContext->Interlock);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ } // if queue not empty
+
+ KeLowerIrql (oldirql2);
+ LEAVE_NBF;
+ return;
+
+} /* NbfReceiveComplete */
+
+
+VOID
+NbfTransferLoopbackData (
+ OUT PNDIS_STATUS NdisStatus,
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called instead of NdisTransferData for
+ loopback indications. It copies the data from the
+ source packet to the receive packet.
+
+Arguments:
+
+ NdisStatus - Returns the status of the operation.
+
+ DeviceContext - The device context.
+
+ ReceiveContext - A pointer to the source packet.
+
+ ByteOffset - The offset from the start of the source packet
+ that the transfer should begin at.
+
+ BytesToTransfer - The number of bytes to transfer.
+
+ Packet - A pointer to the receive packet.
+
+ BytesTransferred - Returns the number of bytes copied.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PACKET SourcePacket = (PNDIS_PACKET)ReceiveContext;
+
+ NdisCopyFromPacketToPacket(
+ Packet,
+ 0,
+ BytesToTransfer,
+ SourcePacket,
+ DeviceContext->LoopbackHeaderLength + ByteOffset,
+ BytesTransferred
+ );
+
+ *NdisStatus = NDIS_STATUS_SUCCESS; // BUGBUG: what if BytesTransferred is too small
+
+}
+
+
+VOID
+NbfCopyFromPacketToBuffer(
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT BytesToCopy,
+ OUT PCHAR Buffer,
+ OUT PUINT BytesCopied
+ )
+
+/*++
+
+Routine Description:
+
+ Copy from an ndis packet into a buffer.
+
+Arguments:
+
+ Packet - The packet to copy from.
+
+ Offset - The offset from which to start the copy.
+
+ BytesToCopy - The number of bytes to copy from the packet.
+
+ Buffer - The destination of the copy.
+
+ BytesCopied - The number of bytes actually copied. Can be less then
+ BytesToCopy if the packet is shorter than BytesToCopy.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ //
+ // Holds the number of ndis buffers comprising the packet.
+ //
+ UINT NdisBufferCount;
+
+ //
+ // Points to the buffer from which we are extracting data.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // Holds the virtual address of the current buffer.
+ //
+ PVOID VirtualAddress;
+
+ //
+ // Holds the length of the current buffer of the packet.
+ //
+ UINT CurrentLength;
+
+ //
+ // Keep a local variable of BytesCopied so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesCopied = 0;
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesCopied = 0;
+ if (!BytesToCopy) return;
+
+ //
+ // Get the first buffer.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &NdisBufferCount,
+ &CurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!NdisBufferCount) return;
+
+ NdisQueryBuffer(
+ CurrentBuffer,
+ &VirtualAddress,
+ &CurrentLength
+ );
+
+ while (LocalBytesCopied < BytesToCopy) {
+
+ if (!CurrentLength) {
+
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.
+ //
+
+ if (!CurrentBuffer) break;
+
+ NdisQueryBuffer(
+ CurrentBuffer,
+ &VirtualAddress,
+ &CurrentLength
+ );
+ continue;
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (Offset) {
+
+ if (Offset > CurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ Offset -= CurrentLength;
+ CurrentLength = 0;
+ continue;
+
+ } else {
+
+ VirtualAddress = (PCHAR)VirtualAddress + Offset;
+ CurrentLength -= Offset;
+ Offset = 0;
+
+ }
+
+ }
+
+ //
+ // Copy the data.
+ //
+
+
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ AmountToMove =
+ ((CurrentLength <= (BytesToCopy - LocalBytesCopied))?
+ (CurrentLength):(BytesToCopy - LocalBytesCopied));
+
+ RtlCopyMemory(
+ Buffer,
+ VirtualAddress,
+ AmountToMove
+ );
+
+ Buffer = (PCHAR)Buffer + AmountToMove;
+ VirtualAddress = (PCHAR)VirtualAddress + AmountToMove;
+
+ LocalBytesCopied += AmountToMove;
+ CurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ *BytesCopied = LocalBytesCopied;
+
+}
+
diff --git a/private/ntos/tdi/nbf/event.c b/private/ntos/tdi/nbf/event.c
new file mode 100644
index 000000000..6cb072d8a
--- /dev/null
+++ b/private/ntos/tdi/nbf/event.c
@@ -0,0 +1,190 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ event.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiSetEventHandler
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+NTSTATUS
+NbfTdiSetEventHandler(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetEventHandler request for the
+ transport provider. The caller (request dispatcher) verifies
+ that this routine will not be executed on behalf of a user-mode
+ client, as this request enables direct callouts at DISPATCH_LEVEL.
+
+Arguments:
+
+ Irp - Pointer to the IRP for this request
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS rc=STATUS_SUCCESS;
+ KIRQL oldirql;
+ PTDI_REQUEST_KERNEL_SET_EVENT parameters;
+ PIO_STACK_LOCATION irpSp;
+ PTP_ADDRESS address;
+ PTP_ADDRESS_FILE addressFile;
+ NTSTATUS status;
+
+ //
+ // Get the Address this is associated with; if there is none, get out.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ addressFile = irpSp->FileObject->FsContext;
+ status = NbfVerifyAddressObject (addressFile);
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ address = addressFile->Address;
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock, &oldirql);
+
+ parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)&irpSp->Parameters;
+
+ switch (parameters->EventType) {
+
+ case TDI_EVENT_RECEIVE:
+
+ if (parameters->EventHandler == NULL) {
+ addressFile->ReceiveHandler =
+ (PTDI_IND_RECEIVE)TdiDefaultReceiveHandler;
+ addressFile->ReceiveHandlerContext = NULL;
+ addressFile->RegisteredReceiveHandler = FALSE;
+ } else {
+ addressFile->ReceiveHandler =
+ (PTDI_IND_RECEIVE)parameters->EventHandler;
+ addressFile->ReceiveHandlerContext = parameters->EventContext;
+ addressFile->RegisteredReceiveHandler = TRUE;
+ }
+
+ break;
+
+ case TDI_EVENT_RECEIVE_EXPEDITED:
+
+ if (parameters->EventHandler == NULL) {
+ addressFile->ExpeditedDataHandler =
+ (PTDI_IND_RECEIVE_EXPEDITED)TdiDefaultRcvExpeditedHandler;
+ addressFile->ExpeditedDataHandlerContext = NULL;
+ addressFile->RegisteredExpeditedDataHandler = FALSE;
+ } else {
+ addressFile->ExpeditedDataHandler =
+ (PTDI_IND_RECEIVE_EXPEDITED)parameters->EventHandler;
+ addressFile->ExpeditedDataHandlerContext = parameters->EventContext;
+ addressFile->RegisteredExpeditedDataHandler = TRUE;
+ }
+
+ break;
+
+ case TDI_EVENT_RECEIVE_DATAGRAM:
+
+ if (parameters->EventHandler == NULL) {
+ addressFile->ReceiveDatagramHandler =
+ (PTDI_IND_RECEIVE_DATAGRAM)TdiDefaultRcvDatagramHandler;
+ addressFile->ReceiveDatagramHandlerContext = NULL;
+ addressFile->RegisteredReceiveDatagramHandler = FALSE;
+ } else {
+ addressFile->ReceiveDatagramHandler =
+ (PTDI_IND_RECEIVE_DATAGRAM)parameters->EventHandler;
+ addressFile->ReceiveDatagramHandlerContext = parameters->EventContext;
+ addressFile->RegisteredReceiveDatagramHandler = TRUE;
+ }
+
+ break;
+
+ case TDI_EVENT_ERROR:
+
+ if (parameters->EventHandler == NULL) {
+ addressFile->ErrorHandler =
+ (PTDI_IND_ERROR)TdiDefaultErrorHandler;
+ addressFile->ErrorHandlerContext = NULL;
+ addressFile->RegisteredErrorHandler = FALSE;
+ } else {
+ addressFile->ErrorHandler =
+ (PTDI_IND_ERROR)parameters->EventHandler;
+ addressFile->ErrorHandlerContext = parameters->EventContext;
+ addressFile->RegisteredErrorHandler = TRUE;
+ }
+
+ break;
+
+ case TDI_EVENT_DISCONNECT:
+
+ if (parameters->EventHandler == NULL) {
+ addressFile->DisconnectHandler =
+ (PTDI_IND_DISCONNECT)TdiDefaultDisconnectHandler;
+ addressFile->DisconnectHandlerContext = NULL;
+ addressFile->RegisteredDisconnectHandler = FALSE;
+ } else {
+ addressFile->DisconnectHandler =
+ (PTDI_IND_DISCONNECT)parameters->EventHandler;
+ addressFile->DisconnectHandlerContext = parameters->EventContext;
+ addressFile->RegisteredDisconnectHandler = TRUE;
+ }
+
+ break;
+
+ case TDI_EVENT_CONNECT:
+
+ if (parameters->EventHandler == NULL) {
+ addressFile->ConnectionHandler =
+ (PTDI_IND_CONNECT)TdiDefaultConnectHandler;
+ addressFile->ConnectionHandlerContext = NULL;
+ addressFile->RegisteredConnectionHandler = FALSE;
+ } else {
+ addressFile->ConnectionHandler =
+ (PTDI_IND_CONNECT)parameters->EventHandler;
+ addressFile->ConnectionHandlerContext = parameters->EventContext;
+ addressFile->RegisteredConnectionHandler = TRUE;
+ }
+ break;
+
+ default:
+
+ rc = STATUS_INVALID_PARAMETER;
+
+ } /* switch */
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ NbfDereferenceAddress ("Set event handler", address, AREF_VERIFY);
+
+ return rc;
+} /* TdiSetEventHandler */
diff --git a/private/ntos/tdi/nbf/framecon.c b/private/ntos/tdi/nbf/framecon.c
new file mode 100644
index 000000000..6905d9668
--- /dev/null
+++ b/private/ntos/tdi/nbf/framecon.c
@@ -0,0 +1,1087 @@
+
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ framecon.c
+
+Abstract:
+
+ This module contains routines which build NetBIOS Frames Protocol frames,
+ both connection-oriented and connectionless. The following frames are
+ constructed by routines in this module:
+
+ o NBF_CMD_ADD_GROUP_NAME_QUERY
+ o NBF_CMD_ADD_NAME_QUERY
+ o NBF_CMD_NAME_IN_CONFLICT
+ o NBF_CMD_STATUS_QUERY
+ o NBF_CMD_TERMINATE_TRACE
+ o NBF_CMD_DATAGRAM
+ o NBF_CMD_DATAGRAM_BROADCAST
+ o NBF_CMD_NAME_QUERY
+ o NBF_CMD_ADD_NAME_RESPONSE
+ o NBF_CMD_NAME_RECOGNIZED
+ o NBF_CMD_STATUS_RESPONSE
+ o NBF_CMD_TERMINATE_TRACE2
+ o NBF_CMD_DATA_ACK
+ o NBF_CMD_DATA_FIRST_MIDDLE
+ o NBF_CMD_DATA_ONLY_LAST
+ o NBF_CMD_SESSION_CONFIRM
+ o NBF_CMD_SESSION_END
+ o NBF_CMD_SESSION_INITIALIZE
+ o NBF_CMD_NO_RECEIVE
+ o NBF_CMD_RECEIVE_OUTSTANDING
+ o NBF_CMD_RECEIVE_CONTINUE
+ o NBF_CMD_SESSION_ALIVE
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+VOID
+ConstructAddGroupNameQuery(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN USHORT Correlator, // correlator for ADD_NAME_RESPONSE.
+ IN PNAME GroupName // NetBIOS group name to be added.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_ADD_GROUP_NAME_QUERY connectionless
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 44-byte connectionless frame buffer.
+
+ Correlator - Correlator for ADD_NAME_RESPONSE frame.
+
+ GroupName - Pointer to NetBIOS group name to be added.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ USHORT i;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructAddGroupNameQuery: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_ADD_GROUP_NAME_QUERY;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTIONLESS);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0; // reserved field, MBZ.
+ RawFrame->Data2Low = 0;
+ RawFrame->Data2High = 0;
+ TRANSMIT_CORR(RawFrame) = Correlator;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ for (i=0; i<NETBIOS_NAME_LENGTH; i++) {
+ RawFrame->DestinationName [i] = 0;
+ RawFrame->SourceName [i] = GroupName [i];
+ }
+} /* ConstructAddGroupNameQuery */
+
+
+VOID
+ConstructAddNameQuery(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN USHORT Correlator, // correlator for ADD_NAME_RESPONSE.
+ IN PNAME Name // NetBIOS name to be added.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_ADD_NAME_QUERY connectionless
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 44-byte connectionless frame buffer.
+
+ Correlator - Correlator for ADD_NAME_RESPONSE frame.
+
+ Name - Pointer to NetBIOS name to be added.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ USHORT i;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructAddNameQuery: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_ADD_NAME_QUERY;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTIONLESS);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0; // reserved field, MBZ.
+ RawFrame->Data2Low = 0;
+ RawFrame->Data2High = 0;
+ TRANSMIT_CORR(RawFrame) = Correlator;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ for (i=0; i<NETBIOS_NAME_LENGTH; i++) {
+ RawFrame->DestinationName [i] = 0;
+ RawFrame->SourceName [i] = Name [i];
+ }
+} /* ConstructAddNameQuery */
+
+
+VOID
+ConstructNameInConflict(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN PNAME ConflictingName, // NetBIOS name that is conflicting.
+ IN PNAME SendingPermanentName // NetBIOS permanent node name of sender.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_NAME_IN_CONFLICT connectionless
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 44-byte connectionless frame buffer.
+
+ Conflictingname - Pointer to NetBIOS name that is conflicting.
+
+ SendingPermanentName - Pointer to NetBIOS permanent node name of sender.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ USHORT i;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructNameInConflict: Entered (BUGBUG).\n");
+ }
+
+ RawFrame->Command = NBF_CMD_NAME_IN_CONFLICT;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTIONLESS);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0; // reserved field, MBZ.
+ RawFrame->Data2Low = 0;
+ RawFrame->Data2High = 0;
+ TRANSMIT_CORR(RawFrame) = (USHORT)0;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ for (i=0; i<NETBIOS_NAME_LENGTH; i++) {
+ RawFrame->DestinationName [i] = ConflictingName[i];
+ RawFrame->SourceName [i] = SendingPermanentName[i];
+ }
+
+} /* ConstructNameInConflict */
+
+
+VOID
+ConstructStatusQuery(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN UCHAR RequestType, // type of request.
+ IN USHORT BufferLength, // length of user's status buffer.
+ IN USHORT Correlator, // correlator for STATUS_RESPONSE.
+ IN PNAME ReceiverName, // NetBIOS name of receiver.
+ IN PNAME SendingPermanentName // NetBIOS permanent node name of sender.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_STATUS_QUERY connectionless
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 44-byte connectionless frame buffer.
+
+ RequestType - Type of request. One of:
+ 0 - request is 1.x or 2.0.
+ 1 - first request, 2.1 or above.
+ >1 - subsequent request, 2.1 or above.
+
+ BufferLength - Length of user's status buffer.
+
+ Correlator - Correlator for STATUS_RESPONSE frame.
+
+ ReceiverName - Pointer to NetBIOS name of receiver.
+
+ SendingPermanentName - Pointer to NetBIOS permanent node name of sender.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ SHORT i;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint1 ("ConstructStatusQuery: Entered, frame: %lx\n", RawFrame);
+ }
+
+ RawFrame->Command = NBF_CMD_STATUS_QUERY;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTIONLESS);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = RequestType;
+ RawFrame->Data2Low = (UCHAR)(BufferLength & 0xff);
+ RawFrame->Data2High = (UCHAR)(BufferLength >> 8);
+ TRANSMIT_CORR(RawFrame) = (USHORT)0;
+ RESPONSE_CORR(RawFrame) = Correlator;
+ for (i=0; i<NETBIOS_NAME_LENGTH; i++) {
+ RawFrame->DestinationName [i] = ReceiverName [i];
+ RawFrame->SourceName [i] = SendingPermanentName [i];
+ }
+
+} /* ConstructStatusQuery */
+
+
+VOID
+ConstructDatagram(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN PNAME ReceiverName, // NetBIOS name of receiver.
+ IN PNAME SenderName // NetBIOS name of sender.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_DATAGRAM connectionless
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 44-byte connectionless frame buffer.
+
+ ReceiverName - Pointer to a NetBIOS name of the receiver.
+
+ SenderName - Pointer to a NetBIOS name of the sender.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ USHORT i;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructDatagram: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_DATAGRAM;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTIONLESS);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0; // reserved field, MBZ.
+ RawFrame->Data2Low = 0;
+ RawFrame->Data2High = 0;
+ TRANSMIT_CORR(RawFrame) = (USHORT)0;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ for (i=0; i<NETBIOS_NAME_LENGTH; i++) {
+ RawFrame->DestinationName [i] = ReceiverName [i];
+ RawFrame->SourceName [i] = SenderName [i];
+ }
+} /* ConstructDatagram */
+
+
+VOID
+ConstructDatagramBroadcast(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN PNAME SenderName // NetBIOS name of sender.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_DATAGRAM_BROADCAST connectionless
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 44-byte connectionless frame buffer.
+
+ SenderName - Pointer to a NetBIOS name of the sender.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ USHORT i;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructDatagramBroadcast: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_DATAGRAM_BROADCAST;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTIONLESS);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0; // reserved field, MBZ.
+ RawFrame->Data2Low = 0;
+ RawFrame->Data2High = 0;
+ TRANSMIT_CORR(RawFrame) = (USHORT)0;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ for (i=0; i<NETBIOS_NAME_LENGTH; i++) {
+ RawFrame->DestinationName [i] = 0;
+ RawFrame->SourceName [i] = SenderName [i];
+ }
+} /* ConstructDatagramBroadcast */
+
+
+VOID
+ConstructNameQuery(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN UCHAR NameType, // type of name.
+ IN UCHAR LocalSessionNumber, // LSN assigned to session (0=FIND_NAME).
+ IN USHORT Correlator, // correlator in NAME_RECOGNIZED.
+ IN PNAME SenderName, // NetBIOS name of sender.
+ IN PNAME ReceiverName // NetBIOS name of receiver.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_NAME_QUERY connectionless
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 44-byte connectionless frame buffer.
+
+ NameType - Type of name, one of the following:
+ NAME_QUERY_LSN_FIND_NAME
+
+ LocalSessionNumber - LSN assigned to session (0=FIND.NAME).
+
+ Correlator - Correlator in NAME_RECOGNIZED.
+
+ SenderName - Pointer to a NetBIOS name of the sender.
+
+ ReceiverName - Pointer to a NetBIOS name of the receiver.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ SHORT i;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint1 ("ConstructNameQuery: Entered, frame: %lx\n", RawFrame);
+ }
+
+ RawFrame->Command = NBF_CMD_NAME_QUERY;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTIONLESS);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0; // reserved field, MBZ.
+ RawFrame->Data2Low = LocalSessionNumber;
+ RawFrame->Data2High = NameType;
+ TRANSMIT_CORR(RawFrame) = (USHORT)0;
+ RESPONSE_CORR(RawFrame) = Correlator;
+ for (i=0; i<NETBIOS_NAME_LENGTH; i++) {
+ RawFrame->DestinationName [i] = ReceiverName [i];
+ RawFrame->SourceName [i] = SenderName [i];
+ }
+} /* ConstructNameQuery */
+
+
+VOID
+ConstructAddNameResponse(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN UCHAR NameType, // type of name.
+ IN USHORT Correlator, // correlator from ADD_[GROUP_]NAME_QUERY.
+ IN PNAME Name // NetBIOS name being responded to.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_ADD_NAME_RESPONSE connectionless
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 44-byte connectionless frame buffer.
+
+ NameType - Type of name, either group or unique.
+
+ Correlator - Correlator from ADD_[GROUP]NAME_QUERY.
+
+ Name - Pointer to NetBIOS name being responded to.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ USHORT i;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructAddNameResponse: Entered (BUGBUG).\n");
+ }
+
+ RawFrame->Command = NBF_CMD_ADD_NAME_RESPONSE;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTIONLESS);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0; // reserved field, MBZ.
+ RawFrame->Data2Low = NameType;
+ RawFrame->Data2High = 0;
+ TRANSMIT_CORR(RawFrame) = Correlator;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ for (i=0; i<NETBIOS_NAME_LENGTH; i++) {
+ RawFrame->DestinationName [i] = Name [i];
+ RawFrame->SourceName [i] = Name [i];
+ }
+} /* ConstructAddNameResponse */
+
+
+VOID
+ConstructNameRecognized(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN UCHAR NameType, // type of name.
+ IN UCHAR LocalSessionNumber, // LSN assigned to session.
+ IN USHORT NameQueryCorrelator, // correlator from NAME_QUERY.
+ IN USHORT Correlator, // correlator expected from next response.
+ IN PNAME SenderName, // NetBIOS name of sender.
+ IN PNAME ReceiverName // NetBIOS name of receiver.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_NAME_RECOGNIZED connectionless
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 44-byte connectionless frame buffer.
+
+ NameType - Type of name, either group or unique.
+
+ LocalSessionNumber - LSN assigned to session. Special values are:
+ NAME_RECOGNIZED_LSN_NO_LISTENS // no listens available.
+ NAME_RECOGNIZED_LSN_FIND_NAME // this is a find name response.
+ NAME_RECOGNIZED_LSN_NO_RESOURCE // listen available, but no resources.
+
+ NameQueryCorrelator - Correlator from NAME_QUERY.
+
+ Correlator - Correlator expected from next response.
+
+ SenderName - Pointer to a NetBIOS name of the sender.
+
+ ReceiverName - Pointer to a NetBIOS name of the receiver.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ USHORT i;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructNameRecognized: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_NAME_RECOGNIZED;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTIONLESS);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0; // reserved field, MBZ.
+ RawFrame->Data2Low = LocalSessionNumber;
+ RawFrame->Data2High = NameType;
+ TRANSMIT_CORR(RawFrame) = NameQueryCorrelator;
+ RESPONSE_CORR(RawFrame) = Correlator;
+ for (i=0; i<NETBIOS_NAME_LENGTH; i++) {
+ RawFrame->DestinationName [i] = ReceiverName [i];
+ RawFrame->SourceName [i] = SenderName [i];
+ }
+} /* ConstructNameRecognized */
+
+
+VOID
+ConstructStatusResponse(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN UCHAR RequestType, // type of request, defined below.
+ IN BOOLEAN Truncated, // data is truncated.
+ IN BOOLEAN DataOverflow, // too much data for user's buffer.
+ IN USHORT DataLength, // length of data sent.
+ IN USHORT Correlator, // correlator from STATUS_QUERY.
+ IN PNAME ReceivingPermanentName, // NetBIOS permanent node name of receiver.
+ IN PNAME SenderName // NetBIOS name of sender.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_STATUS_RESPONSE connectionless
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 44-byte connectionless frame buffer.
+
+ RequestType - type of request, one of the below:
+ 0 - request is 1.x or 2.0.
+ >0 - number of names, 2.1 or above.
+
+ Truncated - TRUE if there are more names.
+
+ DataOverflow - TRUE if the total data is larger than the user's buffer.
+
+ DataLength - The length of the data in Buffer.
+
+ Correlator - Correlator from STATUS_QUERY.
+
+ ReceivingPermanentName - Pointer to the NetBIOS permanent node name of the receiver,
+ as passed in the STATUS_QUERY frame.
+
+ SenderName - Pointer to a NetBIOS name of the sender.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ SHORT i;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructStatusResponse: Entered (BUGBUG).\n");
+ }
+
+ RawFrame->Command = NBF_CMD_STATUS_RESPONSE;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTIONLESS);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = RequestType;
+ RawFrame->Data2Low = (UCHAR)(DataLength & 0xff);
+ RawFrame->Data2High = (UCHAR)((DataLength >> 8) +
+ (Truncated << 7) +
+ (DataOverflow << 6));
+ TRANSMIT_CORR(RawFrame) = Correlator;
+ RESPONSE_CORR(RawFrame) = 0;
+ for (i=0; i<NETBIOS_NAME_LENGTH; i++) {
+ RawFrame->DestinationName [i] = ReceivingPermanentName [i];
+ RawFrame->SourceName [i] = SenderName [i];
+ }
+
+} /* ConstructStatusResponse */
+
+
+VOID
+ConstructDataAck(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN USHORT Correlator, // correlator from DATA_ONLY_LAST.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_DATA_ACK connection-oriented
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 14-byte connection-oriented buffer.
+
+ Correlator - Correlator from DATA_ONLY_LAST being acked.
+
+ LocalSessionNumber - Session number of SENDER.
+
+ RemoteSessionNumber - Session number of RECEIVER.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructDataAck: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_DATA_ACK;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTION);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0;
+ RawFrame->Data2Low = 0;
+ RawFrame->Data2High = 0;
+ TRANSMIT_CORR(RawFrame) = Correlator;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ RawFrame->SourceSessionNumber = LocalSessionNumber;
+ RawFrame->DestinationSessionNumber = RemoteSessionNumber;
+} /* ConstructDataAck */
+
+
+VOID
+ConstructDataOnlyLast(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN BOOLEAN Resynched, // TRUE if we are resynching.
+ IN USHORT Correlator, // correlator for RECEIVE_CONTINUE.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_DATA_ONLY_LAST connection-oriented
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 14-byte connection-oriented buffer.
+
+ Resynched - TRUE if we are resynching and should set the
+ correct bit in the frame.
+
+ Correlator - Correlator for RECEIVE_CONTINUE, if any.
+
+ LocalSessionNumber - Session number of SENDER.
+
+ RemoteSessionNumber - Session number of RECEIVER.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructDataOnlyLast: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_DATA_ONLY_LAST;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTION);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0;
+ ASSERT (TRUE == (UCHAR)1);
+ RawFrame->Data2Low = Resynched;
+ RawFrame->Data2High = (UCHAR)0;
+ TRANSMIT_CORR(RawFrame) = (USHORT)0;
+ RESPONSE_CORR(RawFrame) = Correlator;
+ RawFrame->SourceSessionNumber = LocalSessionNumber;
+ RawFrame->DestinationSessionNumber = RemoteSessionNumber;
+} /* ConstructDataOnlyLast */
+
+
+VOID
+ConstructSessionConfirm(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN UCHAR Options, // bitflag options, defined below.
+ IN USHORT MaximumUserBufferSize, // max size of user frame on session.
+ IN USHORT Correlator, // correlator from SESSION_INITIALIZE.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_SESSION_CONFIRM connection-oriented
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 14-byte connection-oriented buffer.
+
+ Options - Bitflag options, any of the following:
+ SESSION_CONFIRM_OPTIONS_20 // set if NETBIOS 2.0 or above.
+ SESSION_CONFIRM_NO_ACK // set if NO.ACK protocol supported.
+
+ MaximumUserBufferSize - Maximum size of user data per frame on this
+ session, in bytes. This is limited by the following constant:
+ SESSION_CONFIRM_MAXIMUM_FRAME_SIZE // defined limit of this field.
+
+ Correlator - Correlator from SESSION_INITIALIZE.
+
+ LocalSessionNumber - Session number of SENDER.
+
+ RemoteSessionNumber - Session number of RECEIVER.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructSessionConfirm: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_SESSION_CONFIRM;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTION);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = Options;
+ RawFrame->Data2Low = (UCHAR)(MaximumUserBufferSize & 0xff);
+ RawFrame->Data2High = (UCHAR)(MaximumUserBufferSize >> 8);
+ TRANSMIT_CORR(RawFrame) = Correlator;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ RawFrame->SourceSessionNumber = LocalSessionNumber;
+ RawFrame->DestinationSessionNumber = RemoteSessionNumber;
+} /* ConstructSessionConfirm */
+
+
+VOID
+ConstructSessionEnd(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN USHORT Reason, // reason for termination, defined below.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_SESSION_END connection-oriented
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 14-byte connection-oriented buffer.
+
+ Reason - Reason code for termination, any of the following:
+ SESSION_END_REASON_HANGUP // normal termination via HANGUP.
+ SESSION_END_REASON_ABEND // abnormal session termination.
+
+ LocalSessionNumber - Session number of SENDER.
+
+ RemoteSessionNumber - Session number of RECEIVER.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructSessionEnd: Entered (BUGBUG).\n");
+ }
+
+ RawFrame->Command = NBF_CMD_SESSION_END;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTION);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0;
+ RawFrame->Data2Low = (UCHAR)(Reason & 0xff);
+ RawFrame->Data2High = (UCHAR)(Reason >> 8);
+ TRANSMIT_CORR(RawFrame) = (USHORT)0;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ RawFrame->SourceSessionNumber = LocalSessionNumber;
+ RawFrame->DestinationSessionNumber = RemoteSessionNumber;
+} /* ConstructSessionEnd */
+
+
+VOID
+ConstructSessionInitialize(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN UCHAR Options, // bitflag options, defined below.
+ IN USHORT MaximumUserBufferSize, // max size of user frame on session.
+ IN USHORT NameRecognizedCorrelator, // correlator from NAME_RECOGNIZED.
+ IN USHORT Correlator, // correlator for SESSION_CONFIRM.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_SESSION_INITIALIZE connection-oriented
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 14-byte connection-oriented buffer.
+
+ Options - Bitflag options, any of the following:
+ SESSION_INITIALIZE_OPTIONS_20 // set if NETBIOS 2.0 or above.
+ SESSION_INITIALIZE_NO_ACK // set if NO.ACK protocol supported.
+
+ MaximumUserBufferSize - Maximum size of user data per frame on this
+ session, in bytes. This is limited by the following constant:
+ SESSION_INITIALIZE_MAXIMUM_FRAME_SIZE // defined limit of this field.
+
+ NameRecognizedCorrelator - Correlator from NAME_RECOGNIZED.
+
+ Correlator - Correlator for SESSION_CONFIRM.
+
+ LocalSessionNumber - Session number of SENDER.
+
+ RemoteSessionNumber - Session number of RECEIVER.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructSessionInitialize: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_SESSION_INITIALIZE;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTION);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = Options;
+ RawFrame->Data2Low = (UCHAR)(MaximumUserBufferSize & 0xff);
+ RawFrame->Data2High = (UCHAR)(MaximumUserBufferSize >> 8);
+ TRANSMIT_CORR(RawFrame) = NameRecognizedCorrelator;
+ RESPONSE_CORR(RawFrame) = Correlator;
+ RawFrame->SourceSessionNumber = LocalSessionNumber;
+ RawFrame->DestinationSessionNumber = RemoteSessionNumber;
+} /* ConstructSessionInitialize */
+
+
+VOID
+ConstructNoReceive(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN USHORT Options, // option bitflags, defined below.
+ IN USHORT BytesAccepted, // number of bytes accepted.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_NO_RECEIVE connection-oriented
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 14-byte connection-oriented buffer.
+
+ Options - Bitflag options, any of the following:
+ NO_RECEIVE_OPTIONS_PARTIAL_NO_ACK // NO.ACK data partially received.
+
+ BytesAccepted - Number of bytes accepted, current outstanding message.
+
+ LocalSessionNumber - Session number of SENDER.
+
+ RemoteSessionNumber - Session number of RECEIVER.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+// Options; // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructNoReceive: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_NO_RECEIVE;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTION);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ if (Options == NO_RECEIVE_PARTIAL_NO_ACK) {
+ RawFrame->Data1 = NO_RECEIVE_PARTIAL_NO_ACK;
+ } else {
+ RawFrame->Data1 = 0;
+ }
+ RawFrame->Data2Low = (UCHAR)(BytesAccepted & 0xff);
+ RawFrame->Data2High = (UCHAR)(BytesAccepted >> 8);
+ TRANSMIT_CORR(RawFrame) = (USHORT)0;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ RawFrame->SourceSessionNumber = LocalSessionNumber;
+ RawFrame->DestinationSessionNumber = RemoteSessionNumber;
+} /* ConstructNoReceive */
+
+
+VOID
+ConstructReceiveOutstanding(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN USHORT BytesAccepted, // number of bytes accepted.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_RECEIVE_OUTSTANDING connection-oriented
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 14-byte connection-oriented buffer.
+
+ BytesAccepted - Number of bytes accepted, current outstanding message.
+
+ LocalSessionNumber - Session number of SENDER.
+
+ RemoteSessionNumber - Session number of RECEIVER.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructReceiveOutstanding: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_RECEIVE_OUTSTANDING;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTION);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0;
+ RawFrame->Data2Low = (UCHAR)(BytesAccepted & 0xff);
+ RawFrame->Data2High = (UCHAR)(BytesAccepted >> 8);
+ TRANSMIT_CORR(RawFrame) = (USHORT)0;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ RawFrame->SourceSessionNumber = LocalSessionNumber;
+ RawFrame->DestinationSessionNumber = RemoteSessionNumber;
+} /* ConstructReceiveOutstanding */
+
+
+VOID
+ConstructReceiveContinue(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN USHORT Correlator, // correlator from DATA_FIRST_MIDDLE
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_RECEIVE_CONTINUE connection-oriented
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 14-byte connection-oriented buffer.
+
+ Correlator - The correlator from the DATA_FIRST_MIDDLE frame.
+
+ LocalSessionNumber - Session number of SENDER.
+
+ RemoteSessionNumber - Session number of RECEIVER.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructReceiveContinue: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_RECEIVE_CONTINUE;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTION);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0;
+ RawFrame->Data2Low = 0;
+ RawFrame->Data2High = 0;
+ TRANSMIT_CORR(RawFrame) = Correlator;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ RawFrame->SourceSessionNumber = LocalSessionNumber;
+ RawFrame->DestinationSessionNumber = RemoteSessionNumber;
+} /* ConstructReceiveContinue */
+
+#if 0
+
+VOID
+ConstructSessionAlive(
+ IN PNBF_HDR_CONNECTION RawFrame // frame buffer to format.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_SESSION_ALIVE connection-oriented
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 14-byte connection-oriented buffer.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructSessionAlive: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_SESSION_ALIVE;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTION);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0;
+ RawFrame->Data2Low = 0;
+ RawFrame->Data2High = 0;
+ TRANSMIT_CORR(RawFrame) = (USHORT)0;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ RawFrame->SourceSessionNumber = 0;
+ RawFrame->DestinationSessionNumber = 0;
+} /* ConstructSessionAlive */
+
+#endif
diff --git a/private/ntos/tdi/nbf/framesnd.c b/private/ntos/tdi/nbf/framesnd.c
new file mode 100644
index 000000000..e4c356d99
--- /dev/null
+++ b/private/ntos/tdi/nbf/framesnd.c
@@ -0,0 +1,2504 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ framesnd.c
+
+Abstract:
+
+ This module contains routines which build and send NetBIOS Frames Protocol
+ frames and data link frames for other modules. These routines call on the
+ ones in FRAMECON.C to do the construction work.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#if DBG
+ULONG NbfSendsIssued = 0;
+ULONG NbfSendsCompletedInline = 0;
+ULONG NbfSendsCompletedOk = 0;
+ULONG NbfSendsCompletedFail = 0;
+ULONG NbfSendsPended = 0;
+ULONG NbfSendsCompletedAfterPendOk = 0;
+ULONG NbfSendsCompletedAfterPendFail = 0;
+
+ULONG NbfPacketPanic = 0;
+#endif
+
+
+NTSTATUS
+NbfSendAddNameQuery(
+ IN PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a ADD_NAME_QUERY frame to register the specified
+ address.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_UI_FRAME RawFrame;
+ PUCHAR SingleSR;
+ UINT SingleSRLength;
+ UINT HeaderLength;
+
+ DeviceContext = Address->Provider;
+
+
+ //
+ // Allocate a UI frame from the pool.
+ //
+
+ Status = NbfCreateConnectionlessFrame (DeviceContext, &RawFrame);
+ if (!NT_SUCCESS (Status)) { // couldn't make frame.
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint3 ("NbfSendAddNameQuery: Sending Frame: %lx, NdisPacket: %lx MacHeader: %lx\n",
+ RawFrame, RawFrame->NdisPacket, RawFrame->Header);
+ }
+
+
+ //
+ // Build the MAC header. ADD_NAME_QUERY frames go out as
+ // single-route source routing.
+ //
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SingleSR,
+ &SingleSRLength);
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ RawFrame->Header,
+ DeviceContext->NetBIOSAddress.Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS),
+ SingleSR,
+ SingleSRLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // Build the appropriate Netbios header based on the type
+ // of the address.
+ //
+
+ if ((Address->Flags & ADDRESS_FLAGS_GROUP) != 0) {
+
+ ConstructAddGroupNameQuery (
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ 0, // correlator we don't use.
+ Address->NetworkName->NetbiosName);
+
+ } else {
+
+ ConstructAddNameQuery (
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ 0, // correlator we don't use.
+ Address->NetworkName->NetbiosName);
+
+ }
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+
+
+ //
+ // Munge the packet length and send the it.
+ //
+
+ NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ FALSE); // no loopback (MC frame).
+
+ return STATUS_SUCCESS;
+} /* NbfSendAddNameQuery */
+
+
+VOID
+NbfSendNameQuery(
+ IN PTP_CONNECTION Connection,
+ IN BOOLEAN SourceRoutingOptional
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a NAME_QUERY frame of the appropriate type given the
+ state of the specified connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+ SourceRoutingOptional - TRUE if source routing should be removed if
+ we are configured that way.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_ADDRESS Address;
+ PTP_UI_FRAME RawFrame;
+ PUCHAR NameQuerySR;
+ UINT NameQuerySRLength;
+ PUCHAR NameQueryAddress;
+ UINT HeaderLength;
+ UCHAR Lsn;
+ UCHAR NameType;
+
+ Address = Connection->AddressFile->Address;
+ DeviceContext = Address->Provider;
+
+
+ //
+ // Allocate a UI frame from the pool.
+ //
+
+ Status = NbfCreateConnectionlessFrame(DeviceContext, &RawFrame);
+ if (!NT_SUCCESS (Status)) { // couldn't make frame.
+ return;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint2 ("NbfSendNameQuery: Sending Frame: %lx, NdisPacket: %lx\n",
+ RawFrame, RawFrame->NdisPacket);
+ }
+
+
+ //
+ // Build the MAC header.
+ //
+
+ if (((Connection->Flags2 & CONNECTION_FLAGS2_WAIT_NR) != 0) &&
+ ((Connection->Flags2 & CONNECTION_FLAGS2_GROUP_LSN) == 0)) {
+
+ //
+ // This is the second find name to a unique name; this
+ // means that we already have a link and we can send this
+ // frame directed to it.
+ //
+
+ ASSERT (Connection->Link != NULL);
+
+ MacReturnSourceRouting(
+ &DeviceContext->MacInfo,
+ Connection->Link->Header,
+ &NameQuerySR,
+ &NameQuerySRLength);
+
+ NameQueryAddress = Connection->Link->HardwareAddress.Address;
+
+ } else {
+
+ //
+ // Standard NAME_QUERY frames go out as
+ // single-route source routing, except if
+ // it is optional and we are configured
+ // that way.
+ //
+
+ if (SourceRoutingOptional &&
+ Connection->Provider->MacInfo.QueryWithoutSourceRouting) {
+
+ NameQuerySR = NULL;
+ NameQuerySRLength = 0;
+
+ } else {
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &NameQuerySR,
+ &NameQuerySRLength);
+
+ }
+
+ NameQueryAddress = DeviceContext->NetBIOSAddress.Address;
+
+ }
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ RawFrame->Header,
+ NameQueryAddress,
+ DeviceContext->LocalAddress.Address,
+ sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS),
+ NameQuerySR,
+ NameQuerySRLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // Build the Netbios header.
+ //
+
+ Lsn = (UCHAR)((Connection->Flags2 & CONNECTION_FLAGS2_WAIT_NR_FN) ?
+ NAME_QUERY_LSN_FIND_NAME : Connection->Lsn);
+
+ NameType = (UCHAR)((Connection->AddressFile->Address->Flags & ADDRESS_FLAGS_GROUP) ?
+ NETBIOS_NAME_TYPE_GROUP : NETBIOS_NAME_TYPE_UNIQUE);
+
+ ConstructNameQuery (
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ NameType, // type of our name.
+ Lsn, // calculated, above.
+ (USHORT)Connection->ConnectionId, // corr. in 1st NAME_RECOGNIZED.
+ Address->NetworkName->NetbiosName, // NetBIOS name of sender.
+ Connection->CalledAddress.NetbiosName); // NetBIOS name of receiver.
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+
+
+ //
+ // Munge the packet length and send the it.
+ //
+
+ NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ FALSE); // no loopback (MC frame)
+
+} /* NbfSendNameQuery */
+
+
+VOID
+NbfSendNameRecognized(
+ IN PTP_ADDRESS Address,
+ IN UCHAR LocalSessionNumber, // LSN assigned to session.
+ IN PNBF_HDR_CONNECTIONLESS Header,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a NAME_RECOGNIZED frame of the appropriate type
+ in response to the NAME_QUERY pointed to by Header.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+ LocalSessionNumber - The LSN to use in the frame.
+
+ Header - Pointer to the connectionless NetBIOS header of the
+ NAME_QUERY frame.
+
+ SourceAddress - Pointer to the source hardware address in the received
+ frame.
+
+ SourceRoutingInformation - Pointer to source routing information, if any.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_UI_FRAME RawFrame;
+ UINT HeaderLength;
+ PUCHAR ReplySR;
+ UINT ReplySRLength;
+ UCHAR TempSR[MAX_SOURCE_ROUTING];
+ UCHAR NameType;
+
+ DeviceContext = Address->Provider;
+
+
+ //
+ // Allocate a UI frame from the pool.
+ //
+
+ Status = NbfCreateConnectionlessFrame (DeviceContext, &RawFrame);
+ if (!NT_SUCCESS (Status)) { // couldn't make frame.
+ return;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint2 ("NbfSendNameRecognized: Sending Frame: %lx, NdisPacket: %lx\n",
+ RawFrame, RawFrame->NdisPacket);
+ }
+
+
+ //
+ // Build the MAC header. NAME_RECOGNIZED frames go out as
+ // directed source routing unless configured for general-route.
+ //
+
+ if (DeviceContext->MacInfo.AllRoutesNameRecognized) {
+
+ MacReturnGeneralRouteSR(
+ &DeviceContext->MacInfo,
+ &ReplySR,
+ &ReplySRLength);
+
+ } else {
+
+ if (SourceRouting != NULL) {
+
+ RtlCopyMemory(
+ TempSR,
+ SourceRouting,
+ SourceRoutingLength);
+
+ MacCreateNonBroadcastReplySR(
+ &DeviceContext->MacInfo,
+ TempSR,
+ SourceRoutingLength,
+ &ReplySR);
+
+ ReplySRLength = SourceRoutingLength;
+
+ } else {
+
+ ReplySR = NULL;
+ }
+ }
+
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ RawFrame->Header,
+ SourceAddress->Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS),
+ ReplySR,
+ ReplySRLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // Build the Netbios header.
+ //
+
+ NameType = (UCHAR)((Address->Flags & ADDRESS_FLAGS_GROUP) ?
+ NETBIOS_NAME_TYPE_GROUP : NETBIOS_NAME_TYPE_UNIQUE);
+
+ ConstructNameRecognized ( // build a good response.
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ NameType, // type of local name.
+ LocalSessionNumber, // return our LSN.
+ RESPONSE_CORR(Header), // new xmit corr.
+ 0, // our response correlator (unused).
+ Header->DestinationName, // our NetBIOS name.
+ Header->SourceName); // his NetBIOS name.
+
+ //
+ // BUGBUG: Use Address->NetworkName->Address[0].Address[0].NetbiosName
+ // instead of Header->DestinationName?
+ //
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+
+
+ //
+ // Munge the packet length and send the it.
+ //
+
+ NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ FALSE); // no loopback (MC frame)
+
+} /* NbfSendNameRecognized */
+
+
+VOID
+NbfSendNameInConflict(
+ IN PTP_ADDRESS Address,
+ IN PUCHAR ConflictingName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a NAME_IN_CONFLICT frame.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+ ConflictingName - The NetBIOS name which is in conflict.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_UI_FRAME RawFrame;
+ UINT HeaderLength;
+ PUCHAR SingleSR;
+ UINT SingleSRLength;
+
+ DeviceContext = Address->Provider;
+
+
+ //
+ // Allocate a UI frame from the pool.
+ //
+
+ Status = NbfCreateConnectionlessFrame (DeviceContext, &RawFrame);
+ if (!NT_SUCCESS (Status)) { // couldn't make frame.
+ return;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint2 ("NbfSendNameRecognized: Sending Frame: %lx, NdisPacket: %lx\n",
+ RawFrame, RawFrame->NdisPacket);
+ }
+
+
+ //
+ // Build the MAC header. ADD_NAME_QUERY frames go out as
+ // single-route source routing.
+ //
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SingleSR,
+ &SingleSRLength);
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ RawFrame->Header,
+ DeviceContext->NetBIOSAddress.Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS),
+ SingleSR,
+ SingleSRLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // Build the Netbios header.
+ //
+
+ ConstructNameInConflict (
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ ConflictingName, // his NetBIOS name.
+ DeviceContext->ReservedNetBIOSAddress); // our reserved NetBIOS name.
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+
+
+ //
+ // Munge the packet length and send the it.
+ //
+
+ NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ FALSE); // no loopback (MC frame)
+
+} /* NbfSendNameInConflict */
+
+
+VOID
+NbfSendSessionInitialize(
+ IN PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a SESSION_INITIALIZE frame on the specified connection.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET Packet;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_LINK Link;
+
+ NbfReferenceConnection("send Session Initialize", Connection, CREF_FRAME_SEND);
+
+ DeviceContext = Connection->Provider;
+ Link = Connection->Link;
+ Status = NbfCreatePacket (DeviceContext, Connection->Link, &Packet);
+
+ if (!NT_SUCCESS (Status)) { // if we couldn't make frame.
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendSessionInitialize: NbfCreatePacket failed.\n");
+ }
+#endif
+ NbfWaitPacket (Connection, CONNECTION_FLAGS_SEND_SI);
+ NbfDereferenceConnection("Couldn't get SI packet", Connection, CREF_FRAME_SEND);
+ return;
+ }
+
+
+ //
+ // Initialize the Netbios header.
+ //
+
+ ConstructSessionInitialize (
+ (PNBF_HDR_CONNECTION)&(Packet->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]),
+ SESSION_INIT_OPTIONS_20 | SESSION_INIT_NO_ACK |
+ SESSION_INIT_OPTIONS_LF, // supported options BUGBUG: Set LF correctly.
+ (USHORT)(Connection->Link->MaxFrameSize - sizeof(NBF_HDR_CONNECTION) - sizeof(DLC_I_FRAME)),
+ // maximum frame size/this session.
+ Connection->NetbiosHeader.TransmitCorrelator, // correlator from NAME_RECOGNIZED.
+ 0, // correlator for expected SESSION_CONFIRM.
+ Connection->Lsn, // our local session number.
+ Connection->Rsn); // his session number (our RSN).
+
+ //
+ // Now send the packet on the connection via the link. If there are
+ // conditions on the link which make it impossible to send the packet,
+ // then the packet will be queued to the WackQ, and then timeouts will
+ // restart the link. This is acceptable when the traffic level is so
+ // high that we encounter this condition.
+ //
+
+ //
+ // Set this so NbfDestroyPacket will dereference the connection.
+ //
+
+ Packet->Owner = Connection;
+ Packet->Action = PACKET_ACTION_CONNECTION;
+
+ Packet->NdisIFrameLength =
+ Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION);
+
+ MacModifyHeader(
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION));
+
+ NbfSetNdisPacketLength(
+ Packet->NdisPacket,
+ Packet->NdisIFrameLength);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Status = SendOnePacket (Connection, Packet, FALSE, NULL); // fire and forget.
+
+ if (Status == STATUS_LINK_FAILED) {
+ NbfDereferencePacket (Packet); // destroy the packet.
+ }
+
+ return;
+} /* NbfSendSessionInitialize */
+
+
+VOID
+NbfSendSessionConfirm(
+ IN PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a SESSION_CONFIRM frame on the specified connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET Packet;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_LINK Link;
+
+ NbfReferenceConnection("send Session Confirm", Connection, CREF_FRAME_SEND);
+
+ DeviceContext = Connection->Provider;
+ Link = Connection->Link;
+ Status = NbfCreatePacket (DeviceContext, Connection->Link, &Packet);
+
+ if (!NT_SUCCESS (Status)) { // if we couldn't make frame.
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendSessionConfirm: NbfCreatePacket failed.\n");
+ }
+#endif
+ NbfWaitPacket (Connection, CONNECTION_FLAGS_SEND_SC);
+ NbfDereferenceConnection("Couldn't get SC packet", Connection, CREF_FRAME_SEND);
+ return;
+ }
+
+
+ //
+ // Initialize the Netbios header.
+ //
+
+ ConstructSessionConfirm (
+ (PNBF_HDR_CONNECTION)&(Packet->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]),
+ SESSION_CONFIRM_OPTIONS_20 | SESSION_CONFIRM_NO_ACK, // supported options.
+ (USHORT)(Connection->Link->MaxFrameSize - sizeof(NBF_HDR_CONNECTION) - sizeof(DLC_I_FRAME)),
+ // maximum frame size/this session.
+ Connection->NetbiosHeader.TransmitCorrelator, // correlator from NAME_RECOGNIZED.
+ Connection->Lsn, // our local session number.
+ Connection->Rsn); // his session number (our RSN).
+
+ //
+ // Now send the packet on the connection via the link. If there are
+ // conditions on the link which make it impossible to send the packet,
+ // then the packet will be queued to the WackQ, and then timeouts will
+ // restart the link. This is acceptable when the traffic level is so
+ // high that we encounter this condition.
+ //
+
+ //
+ // Set this so NbfDestroyPacket will dereference the connection.
+ //
+
+ Packet->Owner = Connection;
+ Packet->Action = PACKET_ACTION_CONNECTION;
+
+ Packet->NdisIFrameLength =
+ Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION);
+
+ MacModifyHeader(
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION));
+
+ NbfSetNdisPacketLength(
+ Packet->NdisPacket,
+ Packet->NdisIFrameLength);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Status = SendOnePacket (Connection, Packet, FALSE, NULL); // fire and forget.
+
+ if (Status == STATUS_LINK_FAILED) {
+ NbfDereferencePacket (Packet); // destroy the packet.
+ }
+
+ return;
+} /* NbfSendSessionConfirm */
+
+
+VOID
+NbfSendSessionEnd(
+ IN PTP_CONNECTION Connection,
+ IN BOOLEAN Abort
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a SESSION_END frame on the specified connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+ Abort - Boolean set to TRUE if the connection is abnormally terminating.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET Packet;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_LINK Link;
+
+ NbfReferenceConnection("send Session End", Connection, CREF_FRAME_SEND);
+
+ DeviceContext = Connection->Provider;
+ Link = Connection->Link;
+
+ Status = NbfCreatePacket (DeviceContext, Connection->Link, &Packet);
+
+ if (!NT_SUCCESS (Status)) { // if we couldn't make frame.
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendSessionEnd: NbfCreatePacket failed.\n");
+ }
+#endif
+ NbfWaitPacket (Connection, CONNECTION_FLAGS_SEND_SE);
+ NbfDereferenceConnection("Couldn't get SE packet", Connection, CREF_FRAME_SEND);
+ return;
+ }
+
+ //
+ // The following statements instruct the packet destructor to run
+ // down this connection when the packet is acknowleged.
+ //
+
+ Packet->Owner = Connection;
+ Packet->Action = PACKET_ACTION_END;
+
+
+ //
+ // Initialize the Netbios header.
+ //
+
+ ConstructSessionEnd (
+ (PNBF_HDR_CONNECTION)&(Packet->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]),
+ (USHORT)(Abort ? // reason for termination.
+ SESSION_END_REASON_ABEND :
+ SESSION_END_REASON_HANGUP),
+ Connection->Lsn, // our local session number.
+ Connection->Rsn); // his session number (our RSN).
+
+ //
+ // Now send the packet on the connection via the link. If there are
+ // conditions on the link which make it impossible to send the packet,
+ // then the packet will be queued to the WackQ, and then timeouts will
+ // restart the link. This is acceptable when the traffic level is so
+ // high that we encounter this condition.
+ //
+ // Note that we force an ack for this packet, as we want to make sure we
+ // run down the connection and link correctly.
+ //
+
+ Packet->NdisIFrameLength =
+ Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION);
+
+ MacModifyHeader(
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION));
+
+ NbfSetNdisPacketLength(
+ Packet->NdisPacket,
+ Packet->NdisIFrameLength);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Status = SendOnePacket (Connection, Packet, TRUE, NULL); // fire and forget.
+
+ if (Status == STATUS_LINK_FAILED) {
+ NbfDereferencePacket (Packet); // destroy the packet.
+ }
+
+ return;
+} /* NbfSendSessionEnd */
+
+
+VOID
+NbfSendNoReceive(
+ IN PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a NO_RECEIVE frame on the specified connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET Packet;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_LINK Link;
+ USHORT MessageBytesToAck;
+
+ NbfReferenceConnection("send No Receive", Connection, CREF_FRAME_SEND);
+
+ DeviceContext = Connection->Provider;
+ Link = Connection->Link;
+ Status = NbfCreatePacket (DeviceContext, Connection->Link, &Packet);
+
+ if (!NT_SUCCESS (Status)) { // if we couldn't make frame.
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendNoReceive: NbfCreatePacket failed.\n");
+ }
+#endif
+ NbfDereferenceConnection("Couldn't get NR packet", Connection, CREF_FRAME_SEND);
+ return;
+ }
+
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ MessageBytesToAck = (USHORT)
+ (Connection->MessageBytesReceived + Connection->MessageInitAccepted - Connection->MessageBytesAcked);
+ Connection->Flags |= CONNECTION_FLAGS_W_RESYNCH;
+
+ //
+ // Initialize the Netbios header.
+ //
+
+ ConstructNoReceive (
+ (PNBF_HDR_CONNECTION)&(Packet->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]),
+ (USHORT)0, // options
+ MessageBytesToAck, // number of bytes accepted.
+ Connection->Lsn, // our local session number.
+ Connection->Rsn); // his session number (our RSN).
+
+ //
+ // Now send the packet on the connection via the link. If there are
+ // conditions on the link which make it impossible to send the packet,
+ // then the packet will be queued to the WackQ, and then timeouts will
+ // restart the link. This is acceptable when the traffic level is so
+ // high that we encounter this condition.
+ //
+
+ //
+ // Set this so NbfDestroyPacket will dereference the connection.
+ //
+
+ Packet->Owner = Connection;
+ Packet->Action = PACKET_ACTION_CONNECTION;
+
+ Packet->NdisIFrameLength =
+ Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION);
+
+ MacModifyHeader(
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION));
+
+ NbfSetNdisPacketLength(
+ Packet->NdisPacket,
+ Packet->NdisIFrameLength);
+
+ Status = SendOnePacket (Connection, Packet, FALSE, NULL); // fire and forget.
+
+ if (Status != STATUS_LINK_FAILED) {
+ ExInterlockedAddUlong(
+ &Connection->MessageBytesAcked,
+ MessageBytesToAck,
+ Connection->LinkSpinLock);
+ } else {
+ NbfDereferencePacket (Packet); // destroy the packet.
+ }
+
+ return;
+} /* NbfSendNoReceive */
+
+
+VOID
+NbfSendReceiveContinue(
+ IN PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a RECEIVE_CONTINUE frame on the specified connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET Packet;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_LINK Link;
+ USHORT MessageBytesToAck;
+
+ NbfReferenceConnection("send Receive Continue", Connection, CREF_FRAME_SEND);
+
+ DeviceContext = Connection->Provider;
+ Link = Connection->Link;
+ Status = NbfCreatePacket (DeviceContext, Connection->Link, &Packet);
+
+ if (!NT_SUCCESS (Status)) { // if we couldn't make frame.
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendReceiveContinue: NbfCreatePacket failed.\n");
+ }
+#endif
+ NbfWaitPacket (Connection, CONNECTION_FLAGS_SEND_RC);
+ NbfDereferenceConnection("Couldn't get RC packet", Connection, CREF_FRAME_SEND);
+ return;
+ }
+
+ //
+ // Save this variable now since it is what we are implicitly ack'ing.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ MessageBytesToAck = (USHORT)
+ (Connection->MessageBytesReceived + Connection->MessageInitAccepted - Connection->MessageBytesAcked);
+
+ //
+ // Initialize the Netbios header.
+ //
+
+ ConstructReceiveContinue (
+ (PNBF_HDR_CONNECTION)&(Packet->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]),
+ Connection->NetbiosHeader.TransmitCorrelator, // correlator from DFM
+ Connection->Lsn, // our local session number.
+ Connection->Rsn); // his session number (our RSN).
+
+ //
+ // Now send the packet on the connection via the link. If there are
+ // conditions on the link which make it impossible to send the packet,
+ // then the packet will be queued to the WackQ, and then timeouts will
+ // restart the link. This is acceptable when the traffic level is so
+ // high that we encounter this condition.
+ //
+
+ //
+ // Set this so NbfDestroyPacket will dereference the connection.
+ //
+
+ Packet->Owner = Connection;
+ Packet->Action = PACKET_ACTION_CONNECTION;
+
+ Packet->NdisIFrameLength =
+ Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION);
+
+ MacModifyHeader(
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION));
+
+ NbfSetNdisPacketLength(
+ Packet->NdisPacket,
+ Packet->NdisIFrameLength);
+
+ Status = SendOnePacket (Connection, Packet, FALSE, NULL); // fire and forget.
+
+ if (Status != STATUS_LINK_FAILED) {
+ ExInterlockedAddUlong(
+ &Connection->MessageBytesAcked,
+ MessageBytesToAck,
+ Connection->LinkSpinLock);
+ } else {
+ NbfDereferencePacket (Packet); // destroy the packet.
+ }
+
+ return;
+} /* NbfSendReceiveContinue */
+
+
+VOID
+NbfSendReceiveOutstanding(
+ IN PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a RECEIVE_OUTSTANDING frame on the specified connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET Packet;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_LINK Link;
+ USHORT MessageBytesToAck;
+
+ NbfReferenceConnection("send Receive Outstanding", Connection, CREF_FRAME_SEND);
+
+ DeviceContext = Connection->Provider;
+ Link = Connection->Link;
+ Status = NbfCreatePacket (DeviceContext, Connection->Link, &Packet);
+
+ if (!NT_SUCCESS (Status)) { // if we couldn't make frame.
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendReceiveOutstanding: NbfCreatePacket failed.\n");
+ }
+#endif
+ NbfWaitPacket (Connection, CONNECTION_FLAGS_SEND_RO);
+ NbfDereferenceConnection("Couldn't get RO packet", Connection, CREF_FRAME_SEND);
+ return;
+ }
+
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ MessageBytesToAck = (USHORT)
+ (Connection->MessageBytesReceived + Connection->MessageInitAccepted - Connection->MessageBytesAcked);
+ Connection->Flags |= CONNECTION_FLAGS_W_RESYNCH;
+
+ //
+ // Initialize the Netbios header.
+ //
+
+ ConstructReceiveOutstanding (
+ (PNBF_HDR_CONNECTION)&(Packet->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]),
+ MessageBytesToAck, // number of bytes accepted.
+ Connection->Lsn, // our local session number.
+ Connection->Rsn); // his session number (our RSN).
+
+
+ //
+ // Now send the packet on the connection via the link. If there are
+ // conditions on the link which make it impossible to send the packet,
+ // then the packet will be queued to the WackQ, and then timeouts will
+ // restart the link. This is acceptable when the traffic level is so
+ // high that we encounter this condition.
+ //
+
+ //
+ // Set this so NbfDestroyPacket will dereference the connection.
+ //
+
+ Packet->Owner = Connection;
+ Packet->Action = PACKET_ACTION_CONNECTION;
+
+ Packet->NdisIFrameLength =
+ Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION);
+
+ MacModifyHeader(
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION));
+
+ NbfSetNdisPacketLength(
+ Packet->NdisPacket,
+ Packet->NdisIFrameLength);
+
+ Status = SendOnePacket (Connection, Packet, FALSE, NULL); // fire and forget.
+
+ if (Status != STATUS_LINK_FAILED) {
+ ExInterlockedAddUlong(
+ &Connection->MessageBytesAcked,
+ MessageBytesToAck,
+ Connection->LinkSpinLock);
+ } else {
+ NbfDereferencePacket (Packet); // destroy the packet.
+ }
+
+ return;
+} /* NbfSendReceiveOutstanding */
+
+
+VOID
+NbfSendDataAck(
+ IN PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a DATA_ACK frame on the specified connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET Packet;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_LINK Link;
+
+ NbfReferenceConnection("send Data Ack", Connection, CREF_FRAME_SEND);
+
+ DeviceContext = Connection->Provider;
+ Link = Connection->Link;
+ Status = NbfCreatePacket (DeviceContext, Connection->Link, &Packet);
+
+ if (!NT_SUCCESS (Status)) { // if we couldn't make frame.
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendDataAck: NbfCreatePacket failed.\n");
+ }
+#endif
+ NbfWaitPacket (Connection, CONNECTION_FLAGS_SEND_DA);
+ NbfDereferenceConnection("Couldn't get DA packet", Connection, CREF_FRAME_SEND);
+ return;
+ }
+
+
+ //
+ // Initialize the Netbios header.
+ //
+
+ ConstructDataAck (
+ (PNBF_HDR_CONNECTION)&(Packet->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]),
+ Connection->NetbiosHeader.TransmitCorrelator, // correlator from DATA_ONLY_LAST.
+ Connection->Lsn, // our local session number.
+ Connection->Rsn); // his session number (our RSN).
+
+ //
+ // Now send the packet on the connection via the link. If there are
+ // conditions on the link which make it impossible to send the packet,
+ // then the packet will be queued to the WackQ, and then timeouts will
+ // restart the link. This is acceptable when the traffic level is so
+ // high that we encounter this condition. Note that Data Ack will be
+ // seeing this condition frequently when send windows close after large
+ // sends.
+ //
+
+ //
+ // Set this so NbfDestroyPacket will dereference the connection.
+ //
+
+ Packet->Owner = Connection;
+ Packet->Action = PACKET_ACTION_CONNECTION;
+
+ Packet->NdisIFrameLength =
+ Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION);
+
+ MacModifyHeader(
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION));
+
+ NbfSetNdisPacketLength(
+ Packet->NdisPacket,
+ Packet->NdisIFrameLength);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Status = SendOnePacket (Connection, Packet, FALSE, NULL); // fire and forget.
+
+ if (Status == STATUS_LINK_FAILED) {
+ NbfDereferencePacket (Packet); // destroy the packet.
+ }
+
+ return;
+} /* NbfSendDataAck */
+
+
+VOID
+NbfSendDm(
+ IN PTP_LINK Link,
+ IN BOOLEAN PollFinal
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a DM-r/x DLC frame on the specified link.
+
+ NOTE: This routine is called with the link spinlock held,
+ and returns with it released. IT MUST BE CALLED AT DPC
+ LEVEL.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ PollFinal - TRUE if poll/final bit should be set.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET RawFrame;
+ PDLC_U_FRAME DlcHeader; // S-format frame alias.
+
+ Status = NbfCreatePacket (Link->Provider, Link, &RawFrame);
+ if (NT_SUCCESS (Status)) {
+
+ RawFrame->Owner = NULL;
+ RawFrame->Action = PACKET_ACTION_NULL;
+
+ //
+ // set the packet length correctly (Note that the NDIS_BUFFER
+ // gets returned to the proper length in NbfDestroyPacket)
+ //
+
+ MacModifyHeader(&Link->Provider->MacInfo, RawFrame->Header, sizeof(DLC_FRAME));
+ NbfSetNdisPacketLength (RawFrame->NdisPacket, Link->HeaderLength + sizeof(DLC_FRAME));
+
+ //
+ // Format LLC DM-r/x header.
+ //
+
+ DlcHeader = (PDLC_U_FRAME)&(RawFrame->Header[Link->HeaderLength]);
+ DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC;
+ DlcHeader->Ssap = DSAP_NETBIOS_OVER_LLC | DLC_SSAP_RESPONSE;
+ DlcHeader->Command = (UCHAR)(DLC_CMD_DM | (PollFinal ? DLC_U_PF : 0));
+
+ //
+ // This releases the spin lock.
+ //
+
+ SendControlPacket (Link, RawFrame);
+
+ } else {
+ RELEASE_DPC_SPIN_LOCK(&Link->SpinLock);
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendDm: packet not sent.\n");
+ }
+#endif
+ }
+} /* NbfSendDm */
+
+
+VOID
+NbfSendUa(
+ IN PTP_LINK Link,
+ IN BOOLEAN PollFinal
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a UA-r/x DLC frame on the specified link.
+
+ NOTE: This routine is called with the link spinlock held,
+ and returns with it released. IT MUST BE CALLED AT DPC
+ LEVEL.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ PollFinal - TRUE if poll/final bit should be set.
+
+ OldIrql - The IRQL at which Link->SpinLock was acquired.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET RawFrame;
+ PDLC_U_FRAME DlcHeader; // U-format frame alias.
+
+ Status = NbfCreatePacket (Link->Provider, Link, &RawFrame);
+ if (NT_SUCCESS (Status)) {
+
+ RawFrame->Owner = NULL;
+ RawFrame->Action = PACKET_ACTION_NULL;
+
+ //
+ // set the packet length correctly (Note that the NDIS_BUFFER
+ // gets returned to the proper length in NbfDestroyPacket)
+ //
+
+ MacModifyHeader(&Link->Provider->MacInfo, RawFrame->Header, sizeof(DLC_FRAME));
+ NbfSetNdisPacketLength (RawFrame->NdisPacket, Link->HeaderLength + sizeof(DLC_FRAME));
+
+ // Format LLC UA-r/x header.
+ //
+
+ DlcHeader = (PDLC_U_FRAME)&(RawFrame->Header[Link->HeaderLength]);
+ DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC;
+ DlcHeader->Ssap = DSAP_NETBIOS_OVER_LLC | DLC_SSAP_RESPONSE;
+ DlcHeader->Command = (UCHAR)(DLC_CMD_UA | (PollFinal ? DLC_U_PF : 0));
+
+ //
+ // This releases the spin lock.
+ //
+
+ SendControlPacket (Link, RawFrame);
+
+ } else {
+ RELEASE_DPC_SPIN_LOCK(&Link->SpinLock);
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendUa: packet not sent.\n");
+ }
+#endif
+ }
+} /* NbfSendUa */
+
+
+VOID
+NbfSendSabme(
+ IN PTP_LINK Link,
+ IN BOOLEAN PollFinal
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a SABME-c/x DLC frame on the specified link.
+
+ NOTE: This routine is called with the link spinlock held,
+ and returns with it released.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ PollFinal - TRUE if poll/final bit should be set.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PLIST_ENTRY p;
+ PTP_PACKET RawFrame, packet;
+ PDLC_U_FRAME DlcHeader; // S-format frame alias.
+
+ Status = NbfCreatePacket (Link->Provider, Link, &RawFrame);
+ if (NT_SUCCESS (Status)) {
+
+ RawFrame->Owner = NULL;
+ RawFrame->Action = PACKET_ACTION_NULL;
+
+ //
+ // set the packet length correctly (Note that the NDIS_BUFFER
+ // gets returned to the proper length in NbfDestroyPacket)
+ //
+
+ MacModifyHeader(&Link->Provider->MacInfo, RawFrame->Header, sizeof(DLC_FRAME));
+ NbfSetNdisPacketLength (RawFrame->NdisPacket, Link->HeaderLength + sizeof(DLC_FRAME));
+
+ //
+ // Format LLC SABME-c/x header.
+ //
+
+ DlcHeader = (PDLC_U_FRAME)&(RawFrame->Header[Link->HeaderLength]);
+ DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC;
+ DlcHeader->Ssap = DSAP_NETBIOS_OVER_LLC;
+ DlcHeader->Command = (UCHAR)(DLC_CMD_SABME | (PollFinal ? DLC_U_PF : 0));
+
+ //
+ // Set up so that T1 will be started when the send
+ // completes.
+ //
+
+ if (PollFinal) {
+ if (Link->Provider->MacInfo.MediumAsync) {
+ RawFrame->NdisIFrameLength = Link->HeaderLength + sizeof(DLC_S_FRAME);
+ RawFrame->Link = Link;
+ NbfReferenceLink ("Sabme/p", Link, LREF_START_T1);
+ } else {
+ StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME));
+ }
+ }
+
+ //
+ // This releases the spin lock.
+ //
+
+ SendControlPacket (Link, RawFrame);
+
+ //
+ // Reset the link state based on having sent this packet..
+ // Note that a SABME can be sent under some conditions on an existing
+ // link. If it is, it means we want to reset this link to a known state.
+ // We'll do that; note that that involves ditching any packets outstanding
+ // on the link.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ Link->NextSend = 0;
+ Link->LastAckReceived = 0;
+ Link->NextReceive = 0; // expect next packet to be sequence 0
+ Link->NextReceive = 0;
+ Link->LastAckSent = 0;
+ Link->NextReceive = 0;
+ Link->LastAckSent = 0;
+
+ while (!IsListEmpty (&Link->WackQ)) {
+ p = RemoveHeadList (&Link->WackQ);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ packet = CONTAINING_RECORD (p, TP_PACKET, Linkage);
+ NbfDereferencePacket (packet);
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ } else {
+ if (PollFinal) {
+ StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME));
+ }
+ RELEASE_DPC_SPIN_LOCK(&Link->SpinLock);
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendSabme: packet not sent.\n");
+ }
+#endif
+ }
+} /* NbfSendSabme */
+
+
+VOID
+NbfSendDisc(
+ IN PTP_LINK Link,
+ IN BOOLEAN PollFinal
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a DISC-c/x DLC frame on the specified link.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ PollFinal - TRUE if poll/final bit should be set.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET RawFrame;
+ PDLC_U_FRAME DlcHeader; // S-format frame alias.
+ KIRQL oldirql;
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ Status = NbfCreatePacket (Link->Provider, Link, &RawFrame);
+ if (NT_SUCCESS (Status)) {
+
+ RawFrame->Owner = NULL;
+ RawFrame->Action = PACKET_ACTION_NULL;
+
+ //
+ // set the packet length correctly (Note that the NDIS_BUFFER
+ // gets returned to the proper length in NbfDestroyPacket)
+ //
+
+ MacModifyHeader(&Link->Provider->MacInfo, RawFrame->Header, sizeof(DLC_FRAME));
+ NbfSetNdisPacketLength (RawFrame->NdisPacket, Link->HeaderLength + sizeof(DLC_FRAME));
+
+ //
+ // Format LLC DISC-c/x header.
+ //
+
+ DlcHeader = (PDLC_U_FRAME)&(RawFrame->Header[Link->HeaderLength]);
+ DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC;
+ DlcHeader->Ssap = DSAP_NETBIOS_OVER_LLC;
+ DlcHeader->Command = (UCHAR)(DLC_CMD_DISC | (PollFinal ? DLC_U_PF : 0));
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ //
+ // This releases the spin lock.
+ //
+
+ SendControlPacket (Link, RawFrame);
+
+ } else {
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendDisc: packet not sent.\n");
+ }
+#endif
+ }
+
+ KeLowerIrql (oldirql);
+
+} /* NbfSendDisc */
+
+
+VOID
+NbfSendRr(
+ IN PTP_LINK Link,
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a RR-x/x DLC frame on the specified link.
+
+ NOTE: This routine is called with the link spinlock held,
+ and returns with it released. THIS ROUTINE MUST BE CALLED
+ AT DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ Command - TRUE if command bit should be set.
+
+ PollFinal - TRUE if poll/final bit should be set.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET RawFrame;
+ PDLC_S_FRAME DlcHeader; // S-format frame alias.
+
+ Status = NbfCreateRrPacket (Link->Provider, Link, &RawFrame);
+ if (NT_SUCCESS (Status)) {
+
+ RawFrame->Owner = NULL;
+
+ //
+ // RawFrame->Action will be set to PACKET_ACTION_RR if
+ // NbfCreateRrPacket got a packet from the RrPacketPool
+ // and PACKET_ACTION_NULL if it got one from the regular
+ // pool.
+ //
+
+ //
+ // set the packet length correctly (Note that the NDIS_BUFFER
+ // gets returned to the proper length in NbfDestroyPacket)
+ //
+
+ MacModifyHeader(&Link->Provider->MacInfo, RawFrame->Header, sizeof(DLC_S_FRAME));
+ NbfSetNdisPacketLength (RawFrame->NdisPacket, Link->HeaderLength + sizeof(DLC_S_FRAME));
+
+ //
+ // Format LLC RR-x/x header.
+ //
+
+ DlcHeader = (PDLC_S_FRAME)&(RawFrame->Header[Link->HeaderLength]);
+ DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC;
+ DlcHeader->Ssap = (UCHAR)(DSAP_NETBIOS_OVER_LLC | (Command ? 0 : DLC_SSAP_RESPONSE));
+ DlcHeader->Command = DLC_CMD_RR;
+ DlcHeader->RcvSeq = (UCHAR)(PollFinal ? DLC_S_PF : 0);
+
+ //
+ // If this is a command frame (which will always be a
+ // poll with the current code) set up so that T1 will
+ // be started when the send completes.
+ //
+
+ if (Command) {
+ if (Link->Provider->MacInfo.MediumAsync) {
+ RawFrame->NdisIFrameLength = Link->HeaderLength + sizeof(DLC_S_FRAME);
+ RawFrame->Link = Link;
+ NbfReferenceLink ("Rr/p", Link, LREF_START_T1);
+ } else {
+ StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME));
+ }
+ }
+
+ //
+ // This puts Link->NextReceive into DlcHeader->RcvSeq
+ // and releases the spinlock.
+ //
+
+ SendControlPacket (Link, RawFrame);
+
+ } else {
+ if (Command) {
+ StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME));
+ }
+ RELEASE_DPC_SPIN_LOCK(&Link->SpinLock);
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendRr: packet not sent.\n");
+ }
+#endif
+ }
+} /* NbfSendRr */
+
+#if 0
+
+//
+// These functions are not currently called, so they are commented
+// out.
+//
+
+
+VOID
+NbfSendRnr(
+ IN PTP_LINK Link,
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a RNR-x/x DLC frame on the specified link.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ Command - TRUE if command bit should be set.
+
+ PollFinal - TRUE if poll/final bit should be set.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET RawFrame;
+ PDLC_S_FRAME DlcHeader; // S-format frame alias.
+ KIRQL oldirql;
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ Status = NbfCreatePacket (Link->Provider, Link, &RawFrame);
+ if (NT_SUCCESS (Status)) {
+
+ RawFrame->Owner = NULL;
+ RawFrame->Action = PACKET_ACTION_NULL;
+
+ //
+ // set the packet length correctly (Note that the NDIS_BUFFER
+ // gets returned to the proper length in NbfDestroyPacket)
+ //
+
+ MacModifyHeader(&Link->Provider->MacInfo, RawFrame->Header, sizeof(DLC_S_FRAME));
+ NbfSetNdisPacketLength (RawFrame->NdisPacket, Link->HeaderLength + sizeof(DLC_S_FRAME));
+
+ //
+ // Format LLC RR-x/x header.
+ //
+
+ DlcHeader = (PDLC_S_FRAME)&(RawFrame->Header[Link->HeaderLength]);
+ DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC;
+ DlcHeader->Ssap = (UCHAR)(DSAP_NETBIOS_OVER_LLC | (Command ? 0 : DLC_SSAP_RESPONSE));
+ DlcHeader->Command = DLC_CMD_RNR;
+ DlcHeader->RcvSeq = (UCHAR)(PollFinal ? DLC_S_PF : 0);
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ //
+ // This puts Link->NextReceive into DlcHeader->RcvSeq
+ // and releases the spin lock.
+ //
+
+ SendControlPacket (Link, RawFrame);
+
+ } else {
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendRnr: packet not sent.\n");
+ }
+#endif
+ }
+ KeLowerIrql (oldirql);
+} /* NbfSendRnr */
+
+
+VOID
+NbfSendTest(
+ IN PTP_LINK Link,
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PMDL Psdu
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a TEST-x/x DLC frame on the specified link.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ Command - TRUE if command bit should be set.
+
+ PollFinal - TRUE if poll/final bit should be set.
+
+ Psdu - Pointer to an MDL chain describing received TEST-c frame's storage.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ Link, Command, PollFinal, Psdu; // prevent compiler warnings
+
+ PANIC ("NbfSendTest: Entered (BUGBUG).\n");
+} /* NbfSendTest */
+
+
+VOID
+NbfSendFrmr(
+ IN PTP_LINK Link,
+ IN BOOLEAN PollFinal
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a FRMR-r/x DLC frame on the specified link.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ PollFinal - TRUE if poll/final bit should be set.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ Link, PollFinal; // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint0 ("NbfSendFrmr: Entered (BUGBUG).\n");
+ }
+} /* NbfSendFrmr */
+
+#endif
+
+
+VOID
+NbfSendXid(
+ IN PTP_LINK Link,
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends an XID-x/x DLC frame on the specified link.
+
+ NOTE: This routine is called with the link spinlock held,
+ and returns with it released.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ Command - TRUE if command bit should be set.
+
+ PollFinal - TRUE if poll/final bit should be set.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ Link, Command, PollFinal; // prevent compiler warnings
+
+ RELEASE_DPC_SPIN_LOCK(&Link->SpinLock);
+ PANIC ("NbfSendXid: Entered (BUGBUG).\n");
+} /* NbfSendXid */
+
+
+VOID
+NbfSendRej(
+ IN PTP_LINK Link,
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a REJ-x/x DLC frame on the specified link.
+
+ NOTE: This function is called with Link->SpinLock held and
+ returns with it released. THIS MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ Command - TRUE if command bit should be set.
+
+ PollFinal - TRUE if poll/final bit should be set.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET RawFrame;
+ PDLC_S_FRAME DlcHeader; // S-format frame alias.
+
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint0 ("NbfSendRej: Entered.\n");
+ }
+
+ Status = NbfCreatePacket (Link->Provider, Link, &RawFrame);
+ if (NT_SUCCESS (Status)) {
+
+ RawFrame->Owner = NULL;
+ RawFrame->Action = PACKET_ACTION_NULL;
+
+ //
+ // set the packet length correctly (Note that the NDIS_BUFFER
+ // gets returned to the proper length in NbfDestroyPacket)
+ //
+
+ MacModifyHeader(&Link->Provider->MacInfo, RawFrame->Header, sizeof(DLC_S_FRAME));
+ NbfSetNdisPacketLength (RawFrame->NdisPacket, Link->HeaderLength + sizeof(DLC_S_FRAME));
+
+ //
+ // Format LLC REJ-x/x header.
+ //
+
+ DlcHeader = (PDLC_S_FRAME)&(RawFrame->Header[Link->HeaderLength]);
+ DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC;
+ DlcHeader->Ssap = (UCHAR)(DSAP_NETBIOS_OVER_LLC | (Command ? 0 : DLC_SSAP_RESPONSE));
+ DlcHeader->Command = DLC_CMD_REJ;
+ DlcHeader->RcvSeq = (UCHAR)(PollFinal ? DLC_S_PF : 0);
+
+ //
+ // This puts Link->NextReceive into DlcHeader->RcvSeq
+ // and releases the spin lock.
+ //
+
+ SendControlPacket (Link, RawFrame);
+
+ } else {
+ RELEASE_DPC_SPIN_LOCK(&Link->SpinLock);
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendRej: packet not sent.\n");
+ }
+#endif
+ }
+} /* NbfSendRej */
+
+
+NTSTATUS
+NbfCreateConnectionlessFrame(
+ PDEVICE_CONTEXT DeviceContext,
+ PTP_UI_FRAME *RawFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a connectionless frame (either from the local
+ device context pool or out of non-paged pool).
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the frame to.
+
+ RawFrame - Pointer to a place where we will return a pointer to the
+ allocated frame.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PTP_UI_FRAME UIFrame;
+ PLIST_ENTRY p;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint0 ("NbfCreateConnectionlessFrame: Entered.\n");
+ }
+
+ //
+ // Make sure that structure padding hasn't happened.
+ //
+
+ ASSERT (sizeof(NBF_HDR_CONNECTIONLESS) == 44);
+
+ p = ExInterlockedRemoveHeadList (
+ &DeviceContext->UIFramePool,
+ &DeviceContext->Interlock);
+
+ if (p == NULL) {
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfCreateConnectionlessFrame: PANIC! no more UI frames in pool!\n");
+ }
+#endif
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+ ++DeviceContext->UIFrameExhausted;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ UIFrame = (PTP_UI_FRAME) CONTAINING_RECORD (p, TP_UI_FRAME, Linkage);
+
+ *RawFrame = UIFrame;
+
+ return STATUS_SUCCESS;
+} /* NbfCreateConnectionlessFrame */
+
+
+VOID
+NbfDestroyConnectionlessFrame(
+ PDEVICE_CONTEXT DeviceContext,
+ PTP_UI_FRAME RawFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a connectionless frame by either returning it
+ to the device context's pool or to the system's non-paged pool.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to return the frame to.
+
+ RawFrame - Pointer to a frame to be returned.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PNDIS_BUFFER HeaderBuffer;
+ PNDIS_BUFFER NdisBuffer;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint0 ("NbfDestroyConnectionlessFrame: Entered.\n");
+ }
+
+ //
+ // Strip off and unmap the buffers describing data and header.
+ //
+
+ NdisUnchainBufferAtFront (RawFrame->NdisPacket, &HeaderBuffer);
+
+ // data buffers get thrown away
+
+ NdisUnchainBufferAtFront (RawFrame->NdisPacket, &NdisBuffer);
+ while (NdisBuffer != NULL) {
+ NdisFreeBuffer (NdisBuffer);
+ NdisUnchainBufferAtFront (RawFrame->NdisPacket, &NdisBuffer);
+ }
+
+ NDIS_BUFFER_LINKAGE(HeaderBuffer) = (PNDIS_BUFFER)NULL;
+
+ //
+ // If this UI frame has some transport-created data,
+ // free the buffer now.
+ //
+
+ if (RawFrame->DataBuffer) {
+ ExFreePool (RawFrame->DataBuffer);
+ RawFrame->DataBuffer = NULL;
+ }
+
+ NdisChainBufferAtFront (RawFrame->NdisPacket, HeaderBuffer);
+
+ ExInterlockedInsertTailList (
+ &DeviceContext->UIFramePool,
+ &RawFrame->Linkage,
+ &DeviceContext->Interlock);
+
+} /* NbfDestroyConnectionlessFrame */
+
+
+VOID
+NbfSendUIFrame(
+ PDEVICE_CONTEXT DeviceContext,
+ PTP_UI_FRAME RawFrame,
+ IN BOOLEAN Loopback
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a connectionless frame by calling the physical
+ provider's Send service. When the request completes, or if the service
+ does not return successfully, then the frame is deallocated.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ RawFrame - Pointer to a connectionless frame to be sent.
+
+ Loopback - A boolean flag set to TRUE if the source hardware address
+ of the packet should be set to zeros.
+
+ SourceRoutingInformation - Pointer to optional source routing information.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS NdisStatus;
+ PUCHAR DestinationAddress;
+
+ UNREFERENCED_PARAMETER(Loopback);
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint2 ("NbfSendUIFrame: Entered, RawFrame: %lx NdisPacket %lx\n",
+ RawFrame, RawFrame->NdisPacket);
+ DbgPrint ("NbfSendUIFrame: MacHeader: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x \n",
+ RawFrame->Header[0],
+ RawFrame->Header[1],
+ RawFrame->Header[2],
+ RawFrame->Header[3],
+ RawFrame->Header[4],
+ RawFrame->Header[5],
+ RawFrame->Header[6],
+ RawFrame->Header[7],
+ RawFrame->Header[8],
+ RawFrame->Header[9],
+ RawFrame->Header[10],
+ RawFrame->Header[11],
+ RawFrame->Header[12],
+ RawFrame->Header[13]);
+ }
+#endif
+
+ //
+ // Send the packet.
+ //
+
+#if DBG
+ NbfSendsIssued++;
+#endif
+
+ //
+ // Loopback will be FALSE for multicast frames or other
+ // frames that we know are not directly addressed to
+ // our hardware address.
+ //
+
+ if (Loopback) {
+
+ //
+ // See if this frame should be looped back.
+ //
+
+ MacReturnDestinationAddress(
+ &DeviceContext->MacInfo,
+ RawFrame->Header,
+ &DestinationAddress);
+
+ if (RtlEqualMemory(
+ DestinationAddress,
+ DeviceContext->LocalAddress.Address,
+ DeviceContext->MacInfo.AddressLength)) {
+
+ NbfInsertInLoopbackQueue(
+ DeviceContext,
+ RawFrame->NdisPacket,
+ LOOPBACK_UI_FRAME
+ );
+
+ NdisStatus = NDIS_STATUS_PENDING;
+
+ goto NoNdisSend;
+
+ }
+
+ }
+
+ INCREMENT_COUNTER (DeviceContext, PacketsSent);
+
+ NdisSend (
+ &NdisStatus,
+ (NDIS_HANDLE)DeviceContext->NdisBindingHandle,
+ RawFrame->NdisPacket);
+
+NoNdisSend:
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+
+#if DBG
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+ NbfSendsCompletedOk++;
+ } else {
+ NbfSendsCompletedFail++;
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint1 ("NbfSendUIFrame: NdisSend failed, status other Pending or Complete: %s.\n",
+ NbfGetNdisStatus(NdisStatus));
+ }
+ }
+#endif
+
+ NbfDestroyConnectionlessFrame (DeviceContext, RawFrame);
+
+ } else {
+
+#if DBG
+ NbfSendsPended++;
+#endif
+ }
+
+} /* NbfSendUIFrame */
+
+
+VOID
+NbfSendUIMdlFrame(
+ PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a connectionless frame by calling the NbfSendUIFrame.
+ It is intended that this routine be used for sending datagrams and
+ braodcast datagrams.
+
+ The datagram to be sent is described in the NDIS packet contained
+ in the Address. When the send completes, the send completion handler
+ returns the NDIS buffer describing the datagram to the buffer pool and
+ marks the address ndis packet as usable again. Thus, all datagram and
+ UI frames are sequenced through the address they are sent on.
+
+Arguments:
+
+ Address - pointer to the address from which to send this datagram.
+
+ SourceRoutingInformation - Pointer to optional source routing information.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+// NTSTATUS Status;
+ NDIS_STATUS NdisStatus;
+ PDEVICE_CONTEXT DeviceContext;
+ PUCHAR DestinationAddress;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint0 ("NbfSendUIMdlFrame: Entered.\n");
+ }
+
+
+ //
+ // Send the packet.
+ //
+
+ DeviceContext = Address->Provider;
+
+ INCREMENT_COUNTER (DeviceContext, PacketsSent);
+
+ MacReturnDestinationAddress(
+ &DeviceContext->MacInfo,
+ Address->UIFrame->Header,
+ &DestinationAddress);
+
+ if (RtlEqualMemory(
+ DestinationAddress,
+ DeviceContext->LocalAddress.Address,
+ DeviceContext->MacInfo.AddressLength)) {
+
+ //
+ // This packet is sent to ourselves; we should loop it
+ // back.
+ //
+
+ NbfInsertInLoopbackQueue(
+ DeviceContext,
+ Address->UIFrame->NdisPacket,
+ LOOPBACK_UI_FRAME
+ );
+
+ NdisStatus = NDIS_STATUS_PENDING;
+
+ } else {
+
+ NdisSend (
+ &NdisStatus,
+ (NDIS_HANDLE)Address->Provider->NdisBindingHandle,
+ Address->UIFrame->NdisPacket);
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+
+ NbfSendDatagramCompletion (Address, Address->UIFrame->NdisPacket, NdisStatus);
+
+#if DBG
+ if (NdisStatus != NDIS_STATUS_SUCCESS) { // This is an error, trickle it up
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint1 ("NbfSendUIMdlFrame: NdisSend failed, status other Pending or Complete: %s.\n",
+ NbfGetNdisStatus(NdisStatus));
+ }
+ }
+#endif
+ }
+
+} /* NbfSendUIMdlFrame */
+
+
+VOID
+NbfSendDatagramCompletion(
+ IN PTP_ADDRESS Address,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called as an I/O completion handler at the time a
+ NbfSendUIMdlFrame send request is completed. Because this handler is only
+ associated with NbfSendUIMdlFrame, and because NbfSendUIMdlFrame is only
+ used with datagrams and broadcast datagrams, we know that the I/O being
+ completed is a datagram. Here we complete the in-progress datagram, and
+ start-up the next one if there is one.
+
+Arguments:
+
+ Address - Pointer to a transport address on which the datagram
+ is queued.
+
+ NdisPacket - pointer to the NDIS packet describing this request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PIRP Irp;
+ PLIST_ENTRY p;
+ KIRQL oldirql;
+ PNDIS_BUFFER HeaderBuffer;
+
+ NdisPacket; // prevent compiler warnings.
+
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint0 ("NbfSendDatagramCompletion: Entered.\n");
+ }
+
+
+ //
+ // Dequeue the current request and return it to the client. Release
+ // our hold on the send datagram queue.
+ //
+ // *** There may be no current request, if the one that was queued
+ // was aborted or timed out. If this is the case, we added a
+ // special reference to the address, so we still want to deref
+ // when we are done (I don't think this is true - adb 3/22/93).
+ //
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ p = RemoveHeadList (&Address->SendDatagramQueue);
+
+ if (p != &Address->SendDatagramQueue) {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint0 ("NbfDestroyConnectionlessFrame: Entered.\n");
+ }
+
+ //
+ // Strip off and unmap the buffers describing data and header.
+ //
+
+ NdisUnchainBufferAtFront (Address->UIFrame->NdisPacket, &HeaderBuffer);
+
+ // drop the rest of the packet
+
+ NdisReinitializePacket (Address->UIFrame->NdisPacket);
+
+ NDIS_BUFFER_LINKAGE(HeaderBuffer) = (PNDIS_BUFFER)NULL;
+ NdisChainBufferAtFront (Address->UIFrame->NdisPacket, HeaderBuffer);
+
+ //
+ // Ignore NdisStatus; datagrams always "succeed". The Information
+ // field was filled in when we queued the datagram.
+ //
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ Address->Flags &= ~ADDRESS_FLAGS_SEND_IN_PROGRESS;
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ //
+ // Send more datagrams on the Address if possible.
+ //
+
+ NbfSendDatagramsOnAddress (Address); // do more datagrams.
+
+ } else {
+
+ ASSERT (FALSE);
+
+ Address->Flags &= ~ADDRESS_FLAGS_SEND_IN_PROGRESS;
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ }
+
+ NbfDereferenceAddress ("Complete datagram", Address, AREF_REQUEST);
+
+} /* NbfSendDatagramCompletion */
diff --git a/private/ntos/tdi/nbf/iframes.c b/private/ntos/tdi/nbf/iframes.c
new file mode 100644
index 000000000..d14eeb505
--- /dev/null
+++ b/private/ntos/tdi/nbf/iframes.c
@@ -0,0 +1,3339 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ iframes.c
+
+Abstract:
+
+ This module contains routines called to handle i-frames received
+ from the data link provider. Most of these routines are called at receive
+ indication time.
+
+ Also included here are routines that process data at receive completion
+ time. These are limited to handling DFM/DOL frames.
+
+ The following frame types are cracked by routines in this module:
+
+ o NBF_CMD_DATA_ACK
+ o NBF_CMD_DATA_FIRST_MIDDLE
+ o NBF_CMD_DATA_ONLY_LAST
+ o NBF_CMD_SESSION_CONFIRM
+ o NBF_CMD_SESSION_END
+ o NBF_CMD_SESSION_INITIALIZE
+ o NBF_CMD_NO_RECEIVE
+ o NBF_CMD_RECEIVE_OUTSTANDING
+ o NBF_CMD_RECEIVE_CONTINUE
+ o NBF_CMD_SESSION_ALIVE
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode, DISPATCH_LEVEL.
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+extern ULONG StartTimerDelayedAck;
+
+#define NbfUsePiggybackAcks 1
+#if DBG
+extern ULONG NbfDebugPiggybackAcks;
+#endif
+
+
+VOID
+NbfAcknowledgeDataOnlyLast(
+ IN PTP_CONNECTION Connection,
+ IN ULONG MessageLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes care of acknowledging a DOL which has
+ been received. It either sends a DATA_ACK right away, or
+ queues a request for a piggyback ack.
+
+ NOTE: This routine is called with the connection spinlock
+ held, and it returns with it released. IT MUST BE CALLED
+ AT DPC LEVEL.
+
+Arguments:
+
+ Connection - Pointer to a transport connection (TP_CONNECTION).
+
+ MessageLength - the total length (including all DFMs and this
+ DOL) of the message.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+
+
+ //
+ // Determine if we need to ack at all.
+ //
+
+ if (Connection->CurrentReceiveNoAck) {
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ return;
+ }
+
+
+ //
+ // Determine if a piggyback ack is feasible.
+ //
+ if (NbfUsePiggybackAcks &&
+ Connection->CurrentReceiveAckQueueable) {
+
+ //
+ // The sender allows it, see if we want to.
+ //
+
+#if 0
+ //
+ // First reset this variable, to be safe.
+ //
+
+ Connection->CurrentReceiveAckQueueable = FALSE;
+#endif
+
+ //
+ // For long sends, don't bother since these
+ // often happen without back traffic.
+ //
+
+ if (MessageLength >= 8192L) {
+#if DBG
+ if (NbfDebugPiggybackAcks) {
+ NbfPrint0("M");
+ }
+#endif
+ goto NormalDataAck;
+ }
+
+ //
+ // If there have been two receives in a row with
+ // no sends in between, don't wait for back traffic.
+ //
+
+ if (Connection->ConsecutiveReceives >= 2) {
+#if DBG
+ if (NbfDebugPiggybackAcks) {
+ NbfPrint0("R");
+ }
+#endif
+ goto NormalDataAck;
+ }
+
+ //
+ // Do not put a stopping connection on the DataAckQueue
+ //
+
+ if ((Connection->Flags & CONNECTION_FLAGS_READY) == 0) {
+#if DBG
+ if (NbfDebugPiggybackAcks) {
+ NbfPrint0("S");
+ }
+#endif
+ goto NormalDataAck;
+ }
+
+ //
+ // Queue the piggyback ack request. If the timer expires
+ // before a DFM or DOL is sent, a normal DATA ACK will
+ // be sent.
+ //
+ // Connection->Header.TransmitCorrelator has already been filled in.
+ //
+
+ //
+ // BAD! We shouldn't already have an ack queued.
+ //
+
+ ASSERT ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_ACK) == 0);
+
+ KeQueryTickCount (&Connection->ConnectStartTime);
+ Connection->DeferredFlags |= CONNECTION_FLAGS_DEFERRED_ACK;
+
+#if DBG
+ if (NbfDebugPiggybackAcks) {
+ NbfPrint0("Q");
+ }
+#endif
+
+ DeviceContext = Connection->Link->Provider;
+
+ if (!Connection->OnDataAckQueue) {
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ if (!Connection->OnDataAckQueue) {
+
+ Connection->OnDataAckQueue = TRUE;
+ InsertTailList (&DeviceContext->DataAckQueue, &Connection->DataAckLinkage);
+
+ if (!(DeviceContext->a.i.DataAckQueueActive)) {
+
+ StartTimerDelayedAck++;
+ NbfStartShortTimer (DeviceContext);
+ DeviceContext->a.i.DataAckQueueActive = TRUE;
+
+ }
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ INCREMENT_COUNTER (DeviceContext, PiggybackAckQueued);
+
+ return;
+
+ }
+
+NormalDataAck:;
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ NbfSendDataAck (Connection);
+
+} /* NbfAcknowledgeDataOnlyLast */
+
+
+NTSTATUS
+ProcessSessionConfirm(
+ IN PTP_CONNECTION Connection,
+ IN PNBF_HDR_CONNECTION IFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles an incoming SESSION_CONFIRM NetBIOS frame.
+
+Arguments:
+
+ Connection - Pointer to a transport connection (TP_CONNECTION).
+
+ IFrame - Pointer to NetBIOS connection-oriented header.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL cancelirql;
+ PLIST_ENTRY p;
+ PTP_REQUEST request;
+ PTDI_CONNECTION_INFORMATION remoteInformation;
+ USHORT HisMaxDataSize;
+ NTSTATUS status;
+ PIO_STACK_LOCATION irpSp;
+ ULONG returnLength;
+ TA_NETBIOS_ADDRESS TempAddress;
+// BOOLEAN TimerWasSet;
+
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ NbfPrint1 ("ProcessSessionConfirm: Entered, Flags: %lx\n", Connection->Flags);
+ }
+
+ Connection->IndicationInProgress = FALSE;
+
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ if ((Connection->Flags & CONNECTION_FLAGS_WAIT_SC) != 0) {
+ Connection->Flags &= ~CONNECTION_FLAGS_WAIT_SC;
+
+ //
+ // Get his capability bits and maximum frame size.
+ //
+
+ if (IFrame->Data1 & SESSION_CONFIRM_OPTIONS_20) {
+ Connection->Flags |= CONNECTION_FLAGS_VERSION2;
+ }
+
+ if (Connection->Link->Loopback) {
+ Connection->MaximumDataSize = 0x8000;
+ } else {
+ Connection->MaximumDataSize = (USHORT)
+ (Connection->Link->MaxFrameSize - sizeof(NBF_HDR_CONNECTION) - sizeof(DLC_I_FRAME));
+
+ HisMaxDataSize = (USHORT)(IFrame->Data2Low + IFrame->Data2High*256);
+ if (HisMaxDataSize < Connection->MaximumDataSize) {
+ Connection->MaximumDataSize = HisMaxDataSize;
+ }
+ }
+
+ //
+ // Build a standard Netbios header for speed when sending
+ // data frames.
+ //
+
+ ConstructDataOnlyLast(
+ &Connection->NetbiosHeader,
+ FALSE,
+ (USHORT)0,
+ Connection->Lsn,
+ Connection->Rsn);
+
+ //
+ // Turn off the connection request timer if there is one, and set
+ // this connection's state to READY.
+ //
+
+ Connection->Flags |= CONNECTION_FLAGS_READY;
+
+ INCREMENT_COUNTER (Connection->Provider, OpenConnections);
+
+ //
+ // Record that the connect request has been successfully
+ // completed by TpCompleteRequest.
+ //
+
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+
+ if (Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) {
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ Connection->IndicationInProgress = FALSE;
+ IoReleaseCancelSpinLock (cancelirql);
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Complete the TdiConnect request.
+ //
+
+ p = RemoveHeadList (&Connection->InProgressRequest);
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ //
+ // Now complete the request and get out.
+ //
+
+ if (p == &Connection->InProgressRequest) {
+
+ Connection->IndicationInProgress = FALSE;
+ IoReleaseCancelSpinLock (cancelirql);
+ return STATUS_SUCCESS;
+
+ }
+
+
+ //
+ // We have a completed connection with a queued connect. Complete
+ // the connect.
+ //
+
+ request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ IoSetCancelRoutine(request->IoRequestPacket, NULL);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ irpSp = IoGetCurrentIrpStackLocation (request->IoRequestPacket);
+ remoteInformation =
+ ((PTDI_REQUEST_KERNEL)(&irpSp->Parameters))->ReturnConnectionInformation;
+ if (remoteInformation != NULL) {
+ try {
+ if (remoteInformation->RemoteAddressLength != 0) {
+
+ //
+ // Build a temporary TA_NETBIOS_ADDRESS, then
+ // copy over as many bytes as fit.
+ //
+
+ TdiBuildNetbiosAddress(
+ Connection->CalledAddress.NetbiosName,
+ (BOOLEAN)(Connection->CalledAddress.NetbiosNameType ==
+ TDI_ADDRESS_NETBIOS_TYPE_GROUP),
+ &TempAddress);
+
+ if (remoteInformation->RemoteAddressLength >=
+ sizeof (TA_NETBIOS_ADDRESS)) {
+
+ returnLength = sizeof(TA_NETBIOS_ADDRESS);
+ remoteInformation->RemoteAddressLength = returnLength;
+
+ } else {
+
+ returnLength = remoteInformation->RemoteAddressLength;
+
+ }
+
+ RtlCopyMemory(
+ (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress,
+ &TempAddress,
+ returnLength);
+
+ } else {
+
+ returnLength = 0;
+ }
+
+ status = STATUS_SUCCESS;
+
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+
+ returnLength = 0;
+ status = GetExceptionCode ();
+
+ }
+
+ } else {
+
+ status = STATUS_SUCCESS;
+ returnLength = 0;
+
+ }
+
+ if (status == STATUS_SUCCESS) {
+
+ if ((ULONG)Connection->Retries == Connection->Provider->NameQueryRetries) {
+
+ INCREMENT_COUNTER (Connection->Provider, ConnectionsAfterNoRetry);
+
+ } else {
+
+ INCREMENT_COUNTER (Connection->Provider, ConnectionsAfterRetry);
+
+ }
+
+ }
+
+ //
+ // Don't clear this until now, so that the connection is all
+ // set up before we allow more indications.
+ //
+
+ Connection->IndicationInProgress = FALSE;
+
+ NbfCompleteRequest (request, status, returnLength);
+
+ } else {
+
+ Connection->IndicationInProgress = FALSE;
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ }
+
+ return STATUS_SUCCESS;
+} /* ProcessSessionConfirm */
+
+
+NTSTATUS
+ProcessSessionEnd(
+ IN PTP_CONNECTION Connection,
+ IN PNBF_HDR_CONNECTION IFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles an incoming SESSION_END NetBIOS frame.
+
+Arguments:
+
+ Connection - Pointer to a transport connection (TP_CONNECTION).
+
+ IFrame - Pointer to NetBIOS connection-oriented header.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ USHORT data2;
+ NTSTATUS StopStatus;
+
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ NbfPrint0 ("ProcessSessionEnd: Entered.\n");
+ }
+
+ //
+ // Handle the error code in the Data2 field. Current protocol says
+ // if the field is 0, then this is a normal HANGUP.NCB operation.
+ // If the field is 1, then this is an abnormal session end, caused
+ // by something like a SEND.NCB timing out. Of course, new protocol
+ // may be added in the future, so we handle only these specific cases.
+ //
+
+ data2 = (USHORT)(IFrame->Data2Low + IFrame->Data2High*256);
+ switch (data2) {
+ case 0:
+ case 1:
+ StopStatus = STATUS_REMOTE_DISCONNECT;
+ break;
+
+ default:
+ PANIC ("ProcessSessionEnd: frame not expected.\n");
+ StopStatus = STATUS_INVALID_NETWORK_RESPONSE;
+ }
+#if DBG
+ if (NbfDisconnectDebug) {
+ STRING remoteName, localName;
+ remoteName.Length = NETBIOS_NAME_LENGTH - 1;
+ remoteName.Buffer = Connection->RemoteName;
+ localName.Length = NETBIOS_NAME_LENGTH - 1;
+ localName.Buffer = Connection->AddressFile->Address->NetworkName->NetbiosName;
+ NbfPrint3( "SessionEnd received for connection to %S from %S; reason %s\n",
+ &remoteName, &localName,
+ data2 == 0 ? "NORMAL" : data2 == 1 ? "ABORT" : "UNKNOWN" );
+ }
+#endif
+
+ //
+ // Run-down this connection.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint0 ("ProcessSessionEnd calling NbfStopConnection\n");
+ }
+ NbfStopConnection (Connection, StopStatus); // disconnected by the other end
+
+ Connection->IndicationInProgress = FALSE;
+
+ return STATUS_SUCCESS;
+} /* ProcessSessionEnd */
+
+
+NTSTATUS
+ProcessSessionInitialize(
+ IN PTP_CONNECTION Connection,
+ IN PNBF_HDR_CONNECTION IFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles an incoming SESSION_INITIALIZE NetBIOS frame.
+
+Arguments:
+
+ Connection - Pointer to a transport connection (TP_CONNECTION).
+
+ IFrame - Pointer to NetBIOS connection-oriented header.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL cancelirql;
+ PLIST_ENTRY p;
+ PTP_REQUEST request;
+ PIO_STACK_LOCATION irpSp;
+ USHORT HisMaxDataSize;
+ ULONG returnLength;
+ PTDI_CONNECTION_INFORMATION remoteInformation;
+ NTSTATUS status;
+ TA_NETBIOS_ADDRESS TempAddress;
+
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ NbfPrint1 ("ProcessSessionInitialize: Entered, Flags: %lx\n", Connection->Flags);
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ if ((Connection->Flags & CONNECTION_FLAGS_WAIT_SI) != 0) {
+ Connection->Flags &= ~CONNECTION_FLAGS_WAIT_SI;
+
+ //
+ // Get his capability bits and maximum frame size.
+ //
+
+ if (IFrame->Data1 & SESSION_INIT_OPTIONS_20) {
+ Connection->Flags |= CONNECTION_FLAGS_VERSION2;
+ }
+
+ if (Connection->Link->Loopback) {
+ Connection->MaximumDataSize = 0x8000;
+ } else {
+ Connection->MaximumDataSize = (USHORT)
+ (Connection->Link->MaxFrameSize - sizeof(NBF_HDR_CONNECTION) - sizeof(DLC_I_FRAME));
+
+ HisMaxDataSize = (USHORT)(IFrame->Data2Low + IFrame->Data2High*256);
+ if (HisMaxDataSize < Connection->MaximumDataSize) {
+ Connection->MaximumDataSize = HisMaxDataSize;
+ }
+ }
+
+ //
+ // Build a standard Netbios header for speed when sending
+ // data frames.
+ //
+
+ ConstructDataOnlyLast(
+ &Connection->NetbiosHeader,
+ FALSE,
+ (USHORT)0,
+ Connection->Lsn,
+ Connection->Rsn);
+
+ //
+ // Save his session initialize correlator so we can send it
+ // in the session confirm frame.
+ //
+
+ Connection->NetbiosHeader.TransmitCorrelator = RESPONSE_CORR(IFrame);
+
+ //
+ // Turn off the connection request timer if there is one (we're done).
+ // Do this with the lock held in case the connection is about to
+ // be closed, to not interfere with the timer started when the
+ // connection started then.
+ //
+
+ if (KeCancelTimer (&Connection->Timer)) {
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ NbfDereferenceConnection ("Timer canceled", Connection, CREF_TIMER); // remove timer reference.
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ }
+
+ //
+ // Now, complete the listen request on the connection (if there was
+ // one) and continue with as much of the protocol request as possible.
+ // if the user has "pre-accepted" the connection, we'll just continue
+ // onward here and complete the entire connection setup. If the user
+ // was indicated and has not yet accepted, we'll just put the
+ // connection into the proper state and fall out the bottom without
+ // completing anything.
+ //
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ if (((Connection->Flags2 & CONNECTION_FLAGS2_ACCEPTED) != 0) ||
+ ((Connection->Flags2 & CONNECTION_FLAGS2_PRE_ACCEPT) != 0)) {
+
+ IF_NBFDBG (NBF_DEBUG_SETUP) {
+ NbfPrint1("SessionInitialize: Accepted connection %lx\n", Connection);
+ }
+ //
+ // we've already accepted the connection; allow it to proceed.
+ // this is the normal path for kernel mode indication clients,
+ // or for those who don't specify TDI_QUERY_ACCEPT on the listen.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ Connection->Flags |= CONNECTION_FLAGS_READY;
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ INCREMENT_COUNTER (Connection->Provider, OpenConnections);
+
+ //
+ // Record that the listen request has been successfully
+ // completed by NbfCompleteRequest.
+ //
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+
+ status = STATUS_SUCCESS;
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ NbfSendSessionConfirm (Connection);
+
+ } else {
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_DISCONNECT) != 0) {
+
+ //
+ // we disconnected, destroy the connection
+ //
+ IF_NBFDBG (NBF_DEBUG_SETUP) {
+ NbfPrint1("SessionInitialize: Disconnected connection %lx\n", Connection);
+ }
+
+ status = STATUS_LOCAL_DISCONNECT;
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ NbfStopConnection (Connection, STATUS_LOCAL_DISCONNECT);
+
+ } else {
+
+ //
+ // we've done nothing, wait for the user to accept on this
+ // connection. This is the "normal" path for non-indication
+ // clients.
+ //
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_WAITING_SC;
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ status = STATUS_SUCCESS;
+ }
+ }
+
+ //
+ // Now, if there was no queued listen, we have done everything we can
+ // for this connection, so we simply exit and leave everything up to
+ // the user. If we've gotten an indication response that allows the
+ // connection to proceed, we will come out of here with a connection
+ // that's up and running.
+ //
+
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ p = RemoveHeadList (&Connection->InProgressRequest);
+ if (p == &Connection->InProgressRequest) {
+
+ Connection->IndicationInProgress = FALSE;
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ IoReleaseCancelSpinLock (cancelirql);
+ return STATUS_SUCCESS;
+
+ }
+
+ //
+ // We have a completed connection with a queued listen. Complete
+ // the listen and let the user do an accept at some time down the
+ // road.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ IoSetCancelRoutine(request->IoRequestPacket, NULL);
+ IoReleaseCancelSpinLock (cancelirql);
+
+ irpSp = IoGetCurrentIrpStackLocation (request->IoRequestPacket);
+ remoteInformation =
+ ((PTDI_REQUEST_KERNEL)(&irpSp->Parameters))->ReturnConnectionInformation;
+ if (remoteInformation != NULL) {
+ try {
+ if (remoteInformation->RemoteAddressLength != 0) {
+
+ //
+ // Build a temporary TA_NETBIOS_ADDRESS, then
+ // copy over as many bytes as fit.
+ //
+
+ TdiBuildNetbiosAddress(
+ Connection->CalledAddress.NetbiosName,
+ (BOOLEAN)(Connection->CalledAddress.NetbiosNameType ==
+ TDI_ADDRESS_NETBIOS_TYPE_GROUP),
+ &TempAddress);
+
+ if (remoteInformation->RemoteAddressLength >=
+ sizeof (TA_NETBIOS_ADDRESS)) {
+
+ returnLength = sizeof(TA_NETBIOS_ADDRESS);
+ remoteInformation->RemoteAddressLength = returnLength;
+
+ } else {
+
+ returnLength = remoteInformation->RemoteAddressLength;
+
+ }
+
+ RtlCopyMemory(
+ (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress,
+ &TempAddress,
+ returnLength);
+
+ } else {
+
+ returnLength = 0;
+ }
+
+ status = STATUS_SUCCESS;
+
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+
+ returnLength = 0;
+ status = GetExceptionCode ();
+
+ }
+
+ } else {
+
+ status = STATUS_SUCCESS;
+ returnLength = 0;
+
+ }
+
+ //
+ // Don't clear this until now, so that the connection is all
+ // set up before we allow more indications.
+ //
+
+ Connection->IndicationInProgress = FALSE;
+
+ NbfCompleteRequest (request, status, 0);
+
+ } else {
+
+ Connection->IndicationInProgress = FALSE;
+#if DBG
+ NbfPrint3 ("ProcessSessionInitialize: C %lx, Flags %lx, Flags2 %lx\n",
+ Connection, Connection->Flags, Connection->Flags2);
+#endif
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ }
+
+ return STATUS_SUCCESS;
+} /* ProcessSessionInitialize */
+
+
+NTSTATUS
+ProcessNoReceive(
+ IN PTP_CONNECTION Connection,
+ IN PNBF_HDR_CONNECTION IFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles an incoming NO_RECEIVE NetBIOS frame.
+
+ NOTE: This routine is called with the connection spinlock
+ held and returns with it released.
+
+Arguments:
+
+ Connection - Pointer to a transport connection (TP_CONNECTION).
+
+ IFrame - Pointer to NetBIOS connection-oriented header.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (IFrame); // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ NbfPrint0 ("ProcessNoReceive: Entered.\n");
+ }
+
+ switch (Connection->SendState) {
+ case CONNECTION_SENDSTATE_W_PACKET: // waiting for free packet.
+ case CONNECTION_SENDSTATE_PACKETIZE: // send being packetized.
+ case CONNECTION_SENDSTATE_W_LINK: // waiting for good link conditions.
+ case CONNECTION_SENDSTATE_W_EOR: // waiting for TdiSend(EOR).
+ case CONNECTION_SENDSTATE_W_ACK: // waiting for DATA_ACK.
+// Connection->SendState = CONNECTION_SENDSTATE_W_RCVCONT;
+//
+// this used to be here, and is right for the other side of the connection. It's
+// wrong here.
+// Connection->Flags |= CONNECTION_FLAGS_W_RESYNCH;
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ ReframeSend (Connection, IFrame->Data2Low + IFrame->Data2High*256);
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ break;
+
+ case CONNECTION_SENDSTATE_W_RCVCONT: // waiting for RECEIVE_CONTINUE.
+ case CONNECTION_SENDSTATE_IDLE: // no sends being processed.
+ PANIC ("ProcessNoReceive: Frame not expected.\n");
+ break;
+
+ default:
+ PANIC ("ProcessNoReceive: Invalid SendState.\n");
+ }
+
+ //
+ // Don't clear this until ReframeSend has been called
+ //
+
+ Connection->IndicationInProgress = FALSE;
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ return STATUS_SUCCESS;
+} /* ProcessNoReceive */
+
+
+NTSTATUS
+ProcessReceiveOutstanding(
+ IN PTP_CONNECTION Connection,
+ IN PNBF_HDR_CONNECTION IFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles an incoming RECEIVE_OUTSTANDING NetBIOS frame.
+
+ NOTE: This routine is called with the connection spinlock
+ held and returns with it released.
+
+Arguments:
+
+ Connection - Pointer to a transport connection (TP_CONNECTION).
+
+ IFrame - Pointer to NetBIOS connection-oriented header.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ NbfPrint0 ("ProcessReceiveOutstanding: Entered.\n");
+ }
+
+ switch (Connection->SendState) {
+ case CONNECTION_SENDSTATE_W_PACKET: // waiting for free packet.
+ case CONNECTION_SENDSTATE_PACKETIZE: // send being packetized.
+ case CONNECTION_SENDSTATE_W_LINK: // waiting for good link conditions.
+ case CONNECTION_SENDSTATE_W_EOR: // waiting for TdiSend(EOR).
+ case CONNECTION_SENDSTATE_W_ACK: // waiting for DATA_ACK.
+ case CONNECTION_SENDSTATE_W_RCVCONT: // waiting for RECEIVE_CONTINUE.
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ ReframeSend (Connection, IFrame->Data2Low + IFrame->Data2High*256);
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ if ((Connection->Flags & CONNECTION_FLAGS_READY) != 0) {
+ Connection->Flags |= CONNECTION_FLAGS_RESYNCHING;
+ Connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
+ }
+ break;
+
+ case CONNECTION_SENDSTATE_IDLE: // no sends being processed.
+ PANIC ("ProcessReceiveOutstanding: Frame not expected.\n");
+ break;
+
+ default:
+ PANIC ("ProcessReceiveOutstanding: Invalid SendState.\n");
+ }
+
+ //
+ // Don't clear this until ReframeSend has been called
+ //
+
+ Connection->IndicationInProgress = FALSE;
+
+ //
+ // Now start packetizing the connection again since we've reframed
+ // the current send. If we were idle or in a bad state, then the
+ // packetizing routine will detect that.
+ //
+ // *** StartPacketizingConnection releases the Connection spin lock.
+ //
+
+ StartPacketizingConnection (Connection, FALSE);
+ return STATUS_SUCCESS;
+} /* ProcessReceiveOutstanding */
+
+
+NTSTATUS
+ProcessReceiveContinue(
+ IN PTP_CONNECTION Connection,
+ IN PNBF_HDR_CONNECTION IFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles an incoming RECEIVE_CONTINUE NetBIOS frame.
+
+ NOTE: This routine is called with the connection spinlock
+ held and returns with it released.
+
+Arguments:
+
+ Connection - Pointer to a transport connection (TP_CONNECTION).
+
+ IFrame - Pointer to NetBIOS connection-oriented header.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ NbfPrint0 ("ProcessReceiveContinue: Entered.\n");
+ }
+
+ switch (Connection->SendState) {
+ case CONNECTION_SENDSTATE_W_PACKET: // waiting for free packet.
+ case CONNECTION_SENDSTATE_PACKETIZE: // send being packetized.
+ case CONNECTION_SENDSTATE_W_LINK: // waiting for good link conditions.
+ case CONNECTION_SENDSTATE_W_EOR: // waiting for TdiSend(EOR).
+ case CONNECTION_SENDSTATE_W_ACK: // waiting for DATA_ACK.
+ case CONNECTION_SENDSTATE_W_RCVCONT: // waiting for RECEIVE_CONTINUE.
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ ReframeSend (Connection, Connection->sp.MessageBytesSent);
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ Connection->Flags |= CONNECTION_FLAGS_RESYNCHING;
+ Connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
+ break;
+
+ case CONNECTION_SENDSTATE_IDLE: // no sends being processed.
+ PANIC ("ProcessReceiveContinue: Frame not expected.\n");
+ break;
+
+ default:
+ PANIC ("ProcessReceiveContinue: Invalid SendState.\n");
+ }
+
+ //
+ // Don't clear this until ReframeSend has been called
+ //
+
+ Connection->IndicationInProgress = FALSE;
+
+ //
+ // Now start packetizing the connection again since we've reframed
+ // the current send. If we were idle or in a bad state, then the
+ // packetizing routine will detect that.
+ //
+ // *** StartPacketizingConnection releases the Connection spin lock.
+ //
+
+ StartPacketizingConnection (Connection, FALSE);
+ return STATUS_SUCCESS;
+} /* ProcessReceiveContinue */
+
+
+NTSTATUS
+ProcessSessionAlive(
+ IN PTP_CONNECTION Connection,
+ IN PNBF_HDR_CONNECTION IFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles an incoming SESSION_ALIVE NetBIOS frame. This
+ routine is by far the simplest in the transport because it does nothing.
+ The SESSION_ALIVE frame is simply a dummy frame that is sent on the
+ reliable data link layer to determine if the data link is still active;
+ no NetBIOS level protocol processing is performed.
+
+Arguments:
+
+ Connection - Pointer to a transport connection (TP_CONNECTION).
+
+ IFrame - Pointer to NetBIOS connection-oriented header.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (Connection); // prevent compiler warnings
+ UNREFERENCED_PARAMETER (IFrame); // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ NbfPrint0 ("ProcessSessionAlive: Entered.\n");
+ }
+
+ Connection->IndicationInProgress = FALSE;
+
+ return STATUS_SUCCESS;
+} /* ProcessSessionAlive */
+
+
+VOID
+NbfProcessIIndicate(
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PTP_LINK Link,
+ IN PUCHAR DlcHeader,
+ IN UINT DlcIndicatedLength,
+ IN UINT DlcTotalLength,
+ IN NDIS_HANDLE ReceiveContext,
+ IN BOOLEAN Loopback
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a received I frame at indication time. It will do
+ all necessary verification processing of the frame and pass those frames
+ that are valid on to the proper handling routines.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Command - Boolean set to TRUE if command, else FALSE if response.
+
+ PollFinal - Boolean set to TRUE if Poll or Final.
+
+ Link - Pointer to a transport link object.
+
+ Header - Pointer to a DLC I-type frame.
+
+ DlcHeader - A pointer to the start of the DLC header in the packet.
+
+ DlcIndicatedLength - The length of the packet indicated, starting at
+ DlcHeader.
+
+ DlcTotalLength - The total length of the packet, starting at DlcHeader.
+
+ ReceiveContext - A magic value for NDIS that indicates which packet we're
+ talking about.
+
+ Loopback - Is this a loopback indication; used to determine whether
+ to call NdisTransferData or NbfTransferLoopbackData.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+#if DBG
+ UCHAR *s;
+#endif
+ PNBF_HDR_CONNECTION nbfHeader;
+ PDLC_I_FRAME header;
+ NTSTATUS Status;
+ UCHAR lsn, rsn;
+ PTP_CONNECTION connection;
+ PUCHAR DataHeader;
+ ULONG DataTotalLength;
+ PLIST_ENTRY p;
+ BOOLEAN ConnectionFound;
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessIIndicate: Entered.\n");
+ }
+
+ //
+ // Process any of: I-x/x.
+ //
+
+ header = (PDLC_I_FRAME)DlcHeader;
+ nbfHeader = (PNBF_HDR_CONNECTION)((PUCHAR)header + 4); // skip DLC hdr.
+
+ //
+ // Verify signatures. We test the signature as a 16-bit
+ // word as specified in the NetBIOS Formats and Protocols manual,
+ // with the assert guarding us against big-endian systems.
+ //
+
+ ASSERT ((((PUCHAR)(&nbfHeader->Length))[0] + ((PUCHAR)(&nbfHeader->Length))[1]*256) ==
+ HEADER_LENGTH(nbfHeader));
+
+ if (HEADER_LENGTH(nbfHeader) != sizeof(NBF_HDR_CONNECTION)) {
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 ("NbfProcessIIndicate: Dropped I frame, Too short or long.\n");
+ }
+ return; // frame too small or too large.
+ }
+
+ if (HEADER_SIGNATURE(nbfHeader) != NETBIOS_SIGNATURE) {
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 ("NbfProcessIIndicate: Dropped I frame, Signature bad.\n");
+ }
+ return; // invalid signature in frame.
+ }
+
+ DataHeader = (PUCHAR)DlcHeader + (4 + sizeof(NBF_HDR_CONNECTION));
+ DataTotalLength = DlcTotalLength - (4 + sizeof(NBF_HDR_CONNECTION));
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
+
+ switch (Link->State) {
+
+ case LINK_STATE_READY:
+
+ //
+ // Link is balanced. This code is extremely critical since
+ // it is the most-covered path in the system for small and
+ // large I/O. Be very careful in adding code here as it will
+ // seriously affect the overall performance of the LAN. It is
+ // first in the list of possible states for that reason.
+ //
+
+#if DBG
+ s = "READY";
+#endif
+ Link->LinkBusy = FALSE;
+
+ //
+ // The I-frame's N(S) should match our V(R). If it
+ // doesn't, issue a reject. Otherwise, increment our V(R).
+ //
+
+ if ((UCHAR)((header->SendSeq >> 1) & 0x7F) != Link->NextReceive) {
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessIIndicate: N(S) != V(R).\n");
+ }
+
+ if (Link->ReceiveState == RECEIVE_STATE_REJECTING) {
+
+
+ //
+ // We already sent a reject, only respond if
+ // he is polling.
+ //
+
+ if (Command & PollFinal) {
+ NbfSendRr(Link, FALSE, TRUE); // releases lock
+ } else {
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ }
+
+ } else {
+
+ Link->ReceiveState = RECEIVE_STATE_REJECTING;
+
+ //
+ // NbfSendRej releases the spinlock.
+ //
+
+ if (Command) {
+ NbfSendRej (Link, FALSE, PollFinal);
+ } else {
+ NbfSendRej (Link, FALSE, FALSE);
+ }
+ }
+
+ //
+ // Update our "bytes rejected" counters.
+ //
+
+ ADD_TO_LARGE_INTEGER(
+ &Link->Provider->Statistics.DataFrameBytesRejected,
+ DataTotalLength);
+ ++Link->Provider->Statistics.DataFramesRejected;
+
+ //
+ // Discard this packet.
+ //
+
+ break;
+
+ }
+
+
+ //
+ // Find the transport connection object associated with this frame.
+ // Because there may be several NetBIOS (transport) connections
+ // over the same data link connection, and the ConnectionContext
+ // value represents a data link connection to a specific address,
+ // we simply use the RSN field in the frame to index into the
+ // connection database for this link object.
+ //
+ // We do this before processing the rest of the LLC header,
+ // in case the connection is busy and we have to ignore
+ // the frame.
+ //
+
+ ConnectionFound = FALSE;
+
+ lsn = nbfHeader->DestinationSessionNumber;
+ rsn = nbfHeader->SourceSessionNumber;
+
+ if ((lsn == 0) || (lsn > NETBIOS_SESSION_LIMIT)) {
+
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ NbfPrint0 ("NbfProcessIIndicate: Invalid LSN.\n");
+ }
+
+ } else {
+
+ p = Link->ConnectionDatabase.Flink;
+ while (p != &Link->ConnectionDatabase) {
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+ if (connection->Lsn >= lsn) { // assumes ordered list
+ break;
+ }
+ p = p->Flink;
+ }
+
+ // Don't use compound if 'cause Connection may be garbage
+
+ if (p == &Link->ConnectionDatabase) {
+#if DBG
+ NbfPrint2 ("NbfProcessIIndicate: Connection not found in database: \n Lsn %x Link %lx",
+ lsn, Link);
+ NbfPrint6 ("Remote: %x-%x-%x-%x-%x-%x\n",
+ Link->HardwareAddress.Address[0], Link->HardwareAddress.Address[1],
+ Link->HardwareAddress.Address[2], Link->HardwareAddress.Address[3],
+ Link->HardwareAddress.Address[4], Link->HardwareAddress.Address[5]);
+#endif
+ } else if (connection->Lsn != lsn) {
+#if DBG
+ NbfPrint0 ("NbfProcessIIndicate: Connection in database doesn't match.\n");
+#endif
+ } else if (connection->Rsn != rsn) {
+#if DBG
+ NbfPrint3 ("NbfProcessIIndicate: Connection lsn %d had rsn %d, got frame for %d\n",
+ connection->Lsn, connection->Rsn, rsn);
+#endif
+ } else {
+
+ //
+ // The connection is good, proceed.
+ //
+
+ ConnectionFound = TRUE;
+
+ if (connection->IndicationInProgress) {
+ NbfPrint1("ProcessIIndicate: Indication in progress on %lx\n", connection);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ return;
+ }
+
+ //
+ // Set this, it prevents other I-frames from being received
+ // on this connection. The various ProcessXXX routines
+ // that are called from the switch below will clear
+ // this flag when they determine it is OK to be reentered.
+ //
+
+ connection->IndicationInProgress = TRUE;
+
+
+ // This reference is removed before this function returns or
+ // we are done with the LINK_STATE_READY part of the outer switch.
+
+ NbfReferenceConnection ("Processing IFrame", connection, CREF_PROCESS_DATA);
+
+
+ }
+
+ }
+
+
+ //
+ // As long as we don't have to drop this frame, adjust the link
+ // state correctly. If ConnectionFound is FALSE, then we exit
+ // right after doing this.
+ //
+
+
+ //
+ // The I-frame we expected arrived, clear rejecting state.
+ //
+
+ if (Link->ReceiveState == RECEIVE_STATE_REJECTING) {
+ Link->ReceiveState = RECEIVE_STATE_READY;
+ }
+
+ Link->NextReceive = (UCHAR)((Link->NextReceive+1) & 0x7f);
+
+ //
+ // If he is checkpointing, we need to respond with RR-c/f. If
+ // we respond, then stop the delayed ack timer. Otherwise, we
+ // need to start it because this is an I-frame that will not be
+ // acked immediately.
+ //
+
+ if (Command && PollFinal) {
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessI: he's checkpointing.\n");
+ }
+ Link->RemoteNoPoll = FALSE;
+ StopT2 (Link); // we're acking, so no delay req'd.
+ NbfSendRr (Link, FALSE, TRUE); // releases lock
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ } else {
+
+ if (Link->RemoteNoPoll) {
+
+ if ((++Link->ConsecutiveIFrames) == Link->Provider->MaxConsecutiveIFrames) {
+
+ //
+ // This appears to be one of those remotes which
+ // never polls, so we send an RR if there are two
+ // frames outstanding (StopT2 sets ConsecutiveIFrames
+ // to 0).
+ //
+
+ StopT2 (Link); // we're acking, so no delay req'd.
+ NbfSendRr (Link, FALSE, FALSE); // releases lock
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ } else {
+
+ StartT2 (Link);
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->Provider->Interlock);
+ if (!Link->OnDeferredRrQueue) {
+ InsertTailList(
+ &Link->Provider->DeferredRrQueue,
+ &Link->DeferredRrLinkage);
+ Link->OnDeferredRrQueue = TRUE;
+ }
+ RELEASE_DPC_SPIN_LOCK (&Link->Provider->Interlock);
+
+ }
+
+ } else {
+
+ StartT2 (Link); // start delayed ack sequence.
+ }
+
+ //
+ // If he is responding to a checkpoint, we need to clear our
+ // send state. Any packets which are still waiting for acknowlegement
+ // at this point must now be resent.
+ //
+
+ if ((!Command) && PollFinal) {
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessI: he's responding to our checkpoint.\n");
+ }
+ if (Link->SendState != SEND_STATE_CHECKPOINTING) {
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 (" NbfProcessI: BUGBUG: Ckpt but SendState=%ld.\n",
+ Link->SendState);
+ }
+ }
+ StopT1 (Link); // checkpoint completed.
+ Link->SendState = SEND_STATE_READY;
+ StartTi (Link);
+ }
+
+ }
+
+ //
+ // Now, if we could not find the connection or the sequence
+ // numbers did not match, return. We don't call ResendLlcPackets
+ // in this case, but that is OK (eventually we will poll).
+ //
+
+ if (!ConnectionFound) {
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ return;
+ }
+
+ ASSERT (connection->LinkSpinLock == &Link->SpinLock);
+
+ //
+ // The N(R) in this frame may acknowlege some WackQ packets.
+ // We delay checking this until after processing the I-frame,
+ // so that we can get IndicationInProgress set to FALSE
+ // before we start resending the WackQ.
+ //
+
+ switch (nbfHeader->Command) {
+
+ case NBF_CMD_DATA_FIRST_MIDDLE:
+ case NBF_CMD_DATA_ONLY_LAST:
+
+ //
+ // First see if this packet has a piggyback ack -- we process
+ // this even if we throw the packet away below.
+ //
+ // This is a bit ugly since theoretically the piggyback
+ // ack bits in a DFM and a DOL could be different, but
+ // they aren't.
+ //
+ if (NbfUsePiggybackAcks) {
+ ASSERT (DFM_OPTIONS_ACK_INCLUDED == DOL_OPTIONS_ACK_INCLUDED);
+
+ if ((nbfHeader->Data1 & DFM_OPTIONS_ACK_INCLUDED) != 0) {
+
+ //
+ // This returns with the connection spinlock held
+ // but may release it and reacquire it.
+ //
+
+ CompleteSend(
+ connection,
+ TRANSMIT_CORR(nbfHeader));
+
+ }
+ }
+
+ //
+ // NOTE: The connection spinlock is held here.
+ //
+
+ //
+ // If the connection is not ready, drop the frame.
+ //
+
+ if ((connection->Flags & CONNECTION_FLAGS_READY) == 0) {
+ connection->IndicationInProgress = FALSE;
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ Status = STATUS_SUCCESS;
+ goto SkipProcessIndicateData;
+ }
+
+ //
+ // A quick check for the three flags that are
+ // rarely set.
+ //
+
+ if ((connection->Flags & (CONNECTION_FLAGS_W_RESYNCH |
+ CONNECTION_FLAGS_RC_PENDING |
+ CONNECTION_FLAGS_RECEIVE_WAKEUP)) == 0) {
+ goto NoFlagsSet;
+ }
+
+ //
+ // If we are waiting for a resynch bit to be set in an
+ // incoming frame, toss the frame if it isn't set.
+ // Otherwise, clear the wait condition.
+ //
+
+ if (connection->Flags & CONNECTION_FLAGS_W_RESYNCH) {
+ if ((nbfHeader->Data2Low == 1) && (nbfHeader->Data2High == 0)) {
+ connection->Flags &= ~CONNECTION_FLAGS_W_RESYNCH;
+ } else {
+ connection->IndicationInProgress = FALSE;
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ NbfPrint0 ("NbfProcessIIndicate: Discarded DFM/DOL, waiting for resynch.\n");
+ }
+
+ Status = STATUS_SUCCESS;
+ goto SkipProcessIndicateData;
+ }
+ }
+
+ //
+ // If we have a previous receive that is pending
+ // completion, then we need to ignore this frame.
+ // This may be common on MP, so rather than drop
+ // it and wait for a poll, we send a NO_RECEIVE,
+ // then a RCV_OUTSTANDING when we have some
+ // resources.
+ //
+
+ if (connection->Flags & CONNECTION_FLAGS_RC_PENDING) {
+
+ //
+ // Hack the connection object so the NO_RECEIVE
+ // looks right.
+ //
+
+ connection->MessageBytesReceived = 0;
+ connection->MessageBytesAcked = 0;
+ connection->MessageInitAccepted = 0;
+
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ NbfSendNoReceive (connection);
+
+ ACQUIRE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ //
+ // We now turn on the PEND_INDICATE flag to show
+ // that we need to send RCV_OUTSTANDING when the
+ // receive completes. If RC_PENDING is now off,
+ // it means the receive was just completed, so
+ // we ourselves need to send the RCV_OUTSTANDING.
+ //
+
+ if ((connection->Flags & CONNECTION_FLAGS_RC_PENDING) == 0) {
+
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+ NbfSendReceiveOutstanding (connection);
+ ACQUIRE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ } else {
+
+ connection->Flags |= CONNECTION_FLAGS_PEND_INDICATE;
+
+ }
+
+ connection->IndicationInProgress = FALSE;
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ NbfPrint0 ("NbfProcessIIndicate: Discarded DFM/DOL, receive complete pending.\n");
+ }
+
+ Status = STATUS_SUCCESS;
+ goto SkipProcessIndicateData;
+ }
+
+ //
+ // If we are discarding data received on this connection
+ // because we've sent a no receive, ditch it.
+ //
+
+ if (connection->Flags & CONNECTION_FLAGS_RECEIVE_WAKEUP) {
+ connection->IndicationInProgress = FALSE;
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 ("NbfProcessIIndicate: In wakeup state, discarding frame.\n");
+ }
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ Status = STATUS_SUCCESS;
+ goto SkipProcessIndicateData;
+ }
+
+NoFlagsSet:;
+
+ //
+ // The connection spinlock is held here.
+ //
+
+ if (nbfHeader->Command == NBF_CMD_DATA_FIRST_MIDDLE) {
+
+ //
+ // NOTE: This release connection->LinkSpinLock.
+ //
+
+ Status = ProcessIndicateData (
+ connection,
+ DlcHeader,
+ DlcIndicatedLength,
+ DataHeader,
+ DataTotalLength,
+ ReceiveContext,
+ FALSE,
+ Loopback);
+
+ //
+ // If the receive-continue bit is set in this frame, then we must
+ // reply with a RECEIVE_CONTINUE frame saying that he can continue
+ // sending. This old protocol option allowed a sender to send a
+ // single frame over to see if there was a receive posted before
+ // sending the entire message and potentially dropping the entire
+ // message. Because the TDI is indication-based, we cannot know
+ // if there is NO receive available until we actually try perform
+ // the indication, so we simply say that there is one posted.
+ // (This will only happen on DFMs.)
+ //
+
+ if (nbfHeader->Data1 & 0x01) {
+
+ //
+ // Save this to use in RECEIVE_CONTINUE.
+ //
+
+ connection->NetbiosHeader.TransmitCorrelator =
+ RESPONSE_CORR(nbfHeader);
+
+ NbfSendReceiveContinue (connection);
+ }
+ } else {
+
+ //
+ // Keep track of how many consecutive receives we have had.
+ //
+
+ connection->ConsecutiveReceives++;
+ connection->ConsecutiveSends = 0;
+
+ //
+ // Save this information now, it will be needed
+ // when the ACK for this DOL is sent.
+ //
+
+ connection->CurrentReceiveAckQueueable =
+ (nbfHeader->Data1 & DOL_OPTIONS_ACK_W_DATA_ALLOWED);
+
+ connection->CurrentReceiveNoAck =
+ (nbfHeader->Data1 & DOL_OPTIONS_NO_ACK);
+
+ connection->NetbiosHeader.TransmitCorrelator =
+ RESPONSE_CORR(nbfHeader);
+
+ //
+ // NOTE: This release connection->LinkSpinLock.
+ //
+
+ Status = ProcessIndicateData (
+ connection,
+ DlcHeader,
+ DlcIndicatedLength,
+ DataHeader,
+ DataTotalLength,
+ ReceiveContext,
+ TRUE,
+ Loopback);
+ }
+
+ //
+ // Update our "bytes received" counters.
+ //
+
+ Link->Provider->TempIFrameBytesReceived += DataTotalLength;
+ ++Link->Provider->TempIFramesReceived;
+
+SkipProcessIndicateData:
+
+ break;
+
+ case NBF_CMD_DATA_ACK:
+
+ connection->IndicationInProgress = FALSE;
+
+ //
+ // This returns with the lock held.
+ //
+
+ CompleteSend(
+ connection,
+ TRANSMIT_CORR(nbfHeader));
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ case NBF_CMD_SESSION_CONFIRM:
+
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+ Status = ProcessSessionConfirm (
+ connection,
+ nbfHeader);
+ break;
+
+ case NBF_CMD_SESSION_END:
+
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+ Status = ProcessSessionEnd (
+ connection,
+ nbfHeader);
+ break;
+
+ case NBF_CMD_SESSION_INITIALIZE:
+
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+ Status = ProcessSessionInitialize (
+ connection,
+ nbfHeader);
+ break;
+
+ case NBF_CMD_NO_RECEIVE:
+
+ //
+ // This releases the connection spinlock.
+ //
+
+ Status = ProcessNoReceive (
+ connection,
+ nbfHeader);
+ break;
+
+ case NBF_CMD_RECEIVE_OUTSTANDING:
+
+ //
+ // This releases the connection spinlock.
+ //
+
+ Status = ProcessReceiveOutstanding (
+ connection,
+ nbfHeader);
+ break;
+
+ case NBF_CMD_RECEIVE_CONTINUE:
+
+ //
+ // This releases the connection spinlock.
+ //
+
+ Status = ProcessReceiveContinue (
+ connection,
+ nbfHeader);
+ break;
+
+ case NBF_CMD_SESSION_ALIVE:
+
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+ Status = ProcessSessionAlive (
+ connection,
+ nbfHeader);
+ break;
+
+ //
+ // An unrecognized command was found in a NetBIOS frame. Because
+ // this is a connection-oriented frame, we should probably shoot
+ // the sender, but for now we will simply discard the packet.
+ //
+ // BUGBUG: trash the session here-- protocol violation.
+ //
+
+ default:
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+ PANIC ("NbfProcessIIndicate: Unknown NBF command byte.\n");
+ connection->IndicationInProgress = FALSE;
+ Status = STATUS_SUCCESS;
+ } /* switch */
+
+ //
+ // A status of STATUS_MORE_PROCESSING_REQUIRED means
+ // that the connection reference count was inherited
+ // by the routine we called, so we don't do the dereference
+ // here.
+ //
+
+ if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
+ NbfDereferenceConnectionMacro("ProcessIIndicate done", connection, CREF_PROCESS_DATA);
+ }
+
+
+ //
+ // The N(R) in this frame acknowleges some (or all) of our packets.
+ // This call must come after the checkpoint acknowlegement check
+ // so that an RR-r/f is always sent BEFORE any new I-frames. This
+ // allows us to always send I-frames as commands.
+ // If he responded to a checkpoint, then resend all left-over
+ // packets.
+ //
+
+ // Link->NextSend = (UCHAR)(header->RcvSeq >> 1) < Link->NextSend ?
+ // Link->NextSend : (UCHAR)(header->RcvSeq >> 1);
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ if (Link->WackQ.Flink != &Link->WackQ) {
+
+ UCHAR AckSequenceNumber = (UCHAR)(header->RcvSeq >> 1);
+
+ //
+ // Verify that the sequence number is reasonable.
+ //
+
+ if (Link->NextSend >= Link->LastAckReceived) {
+
+ //
+ // There is no 127 -> 0 wrap between the two...
+ //
+
+ if ((AckSequenceNumber < Link->LastAckReceived) ||
+ (AckSequenceNumber > Link->NextSend)) {
+ goto NoResend;
+ }
+
+ } else {
+
+ //
+ // There is a 127 -> 0 wrap between the two...
+ //
+
+ if ((AckSequenceNumber < Link->LastAckReceived) &&
+ (AckSequenceNumber > Link->NextSend)) {
+ goto NoResend;
+ }
+
+ }
+
+ //
+ // NOTE: ResendLlcPackets may release and
+ // reacquire the link spinlock.
+ //
+
+ (VOID)ResendLlcPackets(
+ Link,
+ AckSequenceNumber,
+ (BOOLEAN)((!Command) && PollFinal));
+
+NoResend:;
+
+ }
+
+
+ //
+ // Get link going again.
+ //
+ // NOTE: RestartLinkTraffic releases the link spinlock
+ //
+
+ RestartLinkTraffic (Link);
+ break;
+
+ case LINK_STATE_ADM:
+
+ //
+ // used to be, we'd just blow off the other guy with a DM and go home.
+ // it seems that OS/2 likes to believe (under some conditions) that
+ // it has a link up and it is still potentially active (probably
+ // because we return the same connection number to him that he used
+ // to be using). This would all be ok, except for the fact that we
+ // may have a connection hanging on this link waiting for a listen
+ // to finish. If we're in that state, go ahead and accept the
+ // connect.
+ // Set our values for link packet serial numbers to what he wants.
+ //
+
+ if (!IsListEmpty (&Link->ConnectionDatabase)) {
+ if (nbfHeader->Command == NBF_CMD_SESSION_INITIALIZE) {
+
+ //
+ // OK, we're at the only legal case. We've gotten an SI
+ // and we have a connection on this link. If the connection
+ // is waiting SI, we will go ahead and make believe we did
+ // all the correct stuff before we got it.
+ //
+
+ for (
+ p = Link->ConnectionDatabase.Flink, connection = NULL;
+ p != &Link->ConnectionDatabase ;
+ p = p->Flink, connection = NULL
+ ) {
+
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+ if ((connection->Flags & CONNECTION_FLAGS_WAIT_SI) != 0) {
+ // This reference is removed below
+ NbfReferenceConnection ("Found Listener at session init", connection, CREF_ADM_SESS);
+ break;
+ }
+ }
+
+ //
+ // Well, we've looked through the connections, if we have one,
+ // make it the connection of the day. Note that it will
+ // complete when we call ProcessSessionInitialize.
+ //
+
+ if (connection != NULL) {
+
+ Link->NextReceive = (UCHAR)(header->SendSeq >> 1) & (UCHAR)0x7f;
+ Link->NextSend = (UCHAR)(header->RcvSeq >> 1) & (UCHAR)0x7F;
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ NbfCompleteLink (Link); // completes the listening connection
+
+ Status = ProcessSessionInitialize (
+ connection,
+ nbfHeader);
+ NbfDereferenceConnection ("Processed SessInit", connection, CREF_ADM_SESS);
+
+#if DBG
+ s = "ADM";
+#endif
+
+ // Link is ready for use.
+
+ break;
+ }
+ }
+
+ //
+ // we've got a connection on a link that's in state admin.
+ // really bad, kill it and the link.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ if (NbfDisconnectDebug) {
+ NbfPrint0( "NbfProcessIIndicate calling NbfStopLink\n" );
+ }
+#endif
+ NbfStopLink (Link);
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ }
+
+ //
+ // We're disconnected. Tell him.
+ //
+
+ NbfSendDm (Link, PollFinal); // releases lock
+#if DBG
+ s = "ADM";
+#endif
+ break;
+
+ case LINK_STATE_CONNECTING:
+
+ //
+ // We've sent a SABME and are waiting for a UA. He's sent an
+ // I-frame too early, so just let the SABME time out.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "CONNECTING";
+#endif
+ break;
+
+ case LINK_STATE_W_POLL:
+
+ //
+ // We're waiting for his initial poll on a RR-c/p. If he starts
+ // with an I-frame, then we'll let him squeak by.
+ //
+
+ if (!Command) {
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "W_POLL";
+#endif
+ break;
+ }
+
+ Link->State = LINK_STATE_READY; // we're up!
+ StopT1 (Link); // no longer waiting.
+ FakeUpdateBaseT1Timeout (Link);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ NbfCompleteLink (Link); // fire up the connections.
+ StartTi (Link);
+ NbfProcessIIndicate ( // recursive, but safe
+ Command,
+ PollFinal,
+ Link,
+ DlcHeader,
+ DlcIndicatedLength,
+ DlcTotalLength,
+ ReceiveContext,
+ Loopback);
+#if DBG
+ s = "W_POLL";
+#endif
+ break;
+
+ case LINK_STATE_W_FINAL:
+
+ //
+ // We're waiting for a RR-r/f from the remote guy. I-r/f will do.
+ //
+
+ if (Command || !PollFinal) { // don't allow this protocol.
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "W_FINAL";
+#endif
+ break; // we sent RR-c/p.
+ }
+
+ Link->State = LINK_STATE_READY; // we're up.
+ StopT1 (Link); // no longer waiting.
+ StartT2 (Link); // we have an unacked I-frame.
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ NbfCompleteLink (Link); // fire up the connections.
+ StartTi (Link);
+ NbfProcessIIndicate ( // recursive, but safe
+ Command,
+ PollFinal,
+ Link,
+ DlcHeader,
+ DlcIndicatedLength,
+ DlcTotalLength,
+ ReceiveContext,
+ Loopback);
+#if DBG
+ s = "W_FINAL";
+#endif
+ break;
+
+ case LINK_STATE_W_DISC_RSP:
+
+ //
+ // We're waiting for a response from our DISC-c/p but instead of
+ // a UA-r/f, we got this I-frame. Throw the packet away.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "W_DISC_RSP";
+#endif
+ break;
+
+
+ default:
+
+ ASSERT (FALSE);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+#if DBG
+ s = "Unknown link state";
+#endif
+
+ } /* switch */
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 (" NbfProcessIIndicate: (%s) I-Frame processed.\n", s);
+ }
+#endif
+
+ return;
+} /* NbfProcessIIndicate */
+
+
+NTSTATUS
+ProcessIndicateData(
+ IN PTP_CONNECTION Connection,
+ IN PUCHAR DlcHeader,
+ IN UINT DlcIndicatedLength,
+ IN PUCHAR DataHeader,
+ IN UINT DataTotalLength,
+ IN NDIS_HANDLE ReceiveContext,
+ IN BOOLEAN Last,
+ IN BOOLEAN Loopback
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to process data received in a DATA_FIRST_MIDDLE
+ or DATA_ONLY_LAST frame. We attempt to satisfy as many TdiReceive
+ requests as possible with this data.
+
+ If a receive is already active on this Connection, then we copy as much
+ data into the active receive's buffer as possible. If all the data is
+ copied and the receive request's buffer has not been filled, then the
+ Last flag is checked, and if it is TRUE, we go ahead and complete the
+ current receive with the TDI_END_OF_RECORD receive indicator. If Last
+ is FALSE, we simply return.
+
+ If more (uncopied) data remains in the frame, or if there is no active
+ receive outstanding, then an indication is issued to the owning address's
+ receive event handler. The event handler can take one of three actions:
+
+ 1. Return STATUS_SUCCESS, in which case the transport will assume that
+ all of the indicated data has been accepted by the client.
+
+ 3. Return STATUS_DATA_NOT_ACCEPTED, in which case the transport will
+ discard the data and set the CONNECTION_FLAGS_RECEIVE_WAKEUP bitflag
+ in the Connection, indicating that remaining data is to be discarded
+ until a receive becomes available.
+
+ NOTE: This routine is called with Connection->LinkSpinLock held,
+ and returns with it released. THIS ROUTINE MUST BE CALLED AT
+ DPC LEVEL.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+ DlcHeader - The pointer handed to us as the start of the NBF header by NDIS;
+ use this to compute the offset into the packet to start the transfer
+ of data to user buffers.
+
+ DlcIndicatedLength - The amount of NBF data available at indicate.
+
+ DataHeader - A pointer to the start of the data in the packet.
+
+ DataTotalLength - The total length of the packet, starting at DataHeader.
+
+ ReceiveContext - An NDIS handle that identifies the packet we are currently
+ processing.
+
+ Last - Boolean value that indicates whether this is the last piece of data
+ in a message. The DATA_ONLY_LAST processor sets this flag to TRUE when
+ calling this routine, and the DATA_FIRST_MIDDLE processor resets this
+ flag to FALSE when calling this routine.
+
+ Loopback - Is this a loopback indication; used to determine whether
+ to call NdisTransferData or NbfTransferLoopbackData.
+
+
+Return Value:
+
+ STATUS_SUCCESS if we've consumed the packet,
+
+--*/
+
+{
+ NTSTATUS status, tmpstatus;
+ PDEVICE_CONTEXT deviceContext;
+ NDIS_STATUS ndisStatus;
+ PNDIS_PACKET ndisPacket;
+ PSINGLE_LIST_ENTRY linkage;
+ PIRP irp;
+ PIO_STACK_LOCATION irpSp;
+ PNDIS_BUFFER ndisBuffer;
+ ULONG destBytes;
+ ULONG bufferChainLength;
+ ULONG indicateBytesTransferred;
+ ULONG ReceiveFlags;
+ ULONG ndisBytesTransferred;
+ UINT BytesToTransfer;
+ ULONG bytesIndicated;
+ ULONG DataOffset = (PUCHAR)DataHeader - (PUCHAR)DlcHeader;
+ PRECEIVE_PACKET_TAG receiveTag;
+ PTP_ADDRESS_FILE addressFile;
+ PMDL SavedCurrentMdl;
+ ULONG SavedCurrentByteOffset;
+ BOOLEAN ActivatedLongReceive = FALSE;
+ BOOLEAN CompleteReceiveBool, EndOfMessage;
+ ULONG DumpData[2];
+
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint4 (" ProcessIndicateData: Entered, PacketStart: %lx Offset: %lx \n TotalLength %ld DlcIndicatedLength: %ld\n",
+ DlcHeader, DataOffset, DataTotalLength, DlcIndicatedLength);
+ }
+
+
+ //
+ // copy this packet into our receive buffer.
+ //
+
+ deviceContext = Connection->Provider;
+
+ if ((Connection->Flags & CONNECTION_FLAGS_RCV_CANCELLED) != 0) {
+
+ //
+ // A receive in progress was cancelled; we toss the data,
+ // but do send the DOL if it was the last piece of the
+ // send.
+ //
+
+ if (Last) {
+
+ Connection->Flags &= ~CONNECTION_FLAGS_RCV_CANCELLED;
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ NbfSendDataAck (Connection);
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ }
+
+ Connection->IndicationInProgress = FALSE;
+
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Initialize this to zero, in case we do not indicate or
+ // the client does not fill it in.
+ //
+
+ indicateBytesTransferred = 0;
+
+ if (!(Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE)) {
+
+ //
+ // check first to see if there is a receive available. If there is,
+ // use it before doing an indication.
+ //
+
+ if (Connection->ReceiveQueue.Flink != &Connection->ReceiveQueue) {
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ProcessIndicateData: Found receive. Prepping.\n");
+ }
+
+ //
+ // Found a receive, so make it the active one and
+ // cycle around again.
+ //
+
+ Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
+ Connection->MessageBytesReceived = 0;
+ Connection->MessageBytesAcked = 0;
+ Connection->MessageInitAccepted = 0;
+ Connection->CurrentReceiveIrp =
+ CONTAINING_RECORD (Connection->ReceiveQueue.Flink,
+ IRP, Tail.Overlay.ListEntry);
+ Connection->CurrentReceiveSynchronous =
+ deviceContext->MacInfo.SingleReceive;
+ Connection->CurrentReceiveMdl =
+ Connection->CurrentReceiveIrp->MdlAddress;
+ Connection->ReceiveLength =
+ IRP_RECEIVE_LENGTH (IoGetCurrentIrpStackLocation (Connection->CurrentReceiveIrp));
+ Connection->ReceiveByteOffset = 0;
+ status = STATUS_SUCCESS;
+ goto NormalReceive;
+ }
+
+ //
+ // A receive is not active. Post a receive event.
+ //
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) == 0) {
+ Connection->IndicationInProgress = FALSE;
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ return STATUS_SUCCESS;
+ }
+
+ addressFile = Connection->AddressFile;
+
+ if ((!addressFile->RegisteredReceiveHandler) ||
+ (Connection->ReceiveBytesUnaccepted != 0)) {
+
+ //
+ // There is no receive posted to the Connection, and
+ // no event handler. Set the RECEIVE_WAKEUP bit, so that when a
+ // receive does become available, it will restart the
+ // current send. Also send a NoReceive to tell the other
+ // guy he needs to resynch.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ProcessIndicateData: ReceiveQueue empty. Setting RECEIVE_WAKEUP.\n");
+ }
+ Connection->Flags |= CONNECTION_FLAGS_RECEIVE_WAKEUP;
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Connection->IndicationInProgress = FALSE;
+
+ // NbfSendNoReceive (Connection);
+ return STATUS_SUCCESS;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ProcessIndicateData: Receive not active. Posting event.\n");
+ }
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ LEAVE_NBF;
+
+ //
+ // Indicate to the user. For BytesAvailable we
+ // always use DataTotalLength; for BytesIndicated we use
+ // MIN (DlcIndicatedLength - DataOffset, DataTotalLength).
+ //
+ // To clarify BytesIndicated, on an Ethernet packet
+ // which is padded DataTotalLength will be shorter; on an
+ // Ethernet packet which is not padded and which is
+ // completely indicated, the two will be equal; and
+ // on a long Ethernet packet DlcIndicatedLength - DataOffset
+ // will be shorter.
+ //
+
+ bytesIndicated = DlcIndicatedLength - DataOffset;
+ if (DataTotalLength <= bytesIndicated) {
+ bytesIndicated = DataTotalLength;
+ }
+
+ ReceiveFlags = TDI_RECEIVE_AT_DISPATCH_LEVEL;
+ if (Last) {
+ ReceiveFlags |= TDI_RECEIVE_ENTIRE_MESSAGE;
+ }
+ if (deviceContext->MacInfo.CopyLookahead) {
+ ReceiveFlags |= TDI_RECEIVE_COPY_LOOKAHEAD;
+ }
+
+ status = (*addressFile->ReceiveHandler)(
+ addressFile->ReceiveHandlerContext,
+ Connection->Context,
+ ReceiveFlags,
+ bytesIndicated,
+ DataTotalLength, // BytesAvailable
+ &indicateBytesTransferred,
+ DataHeader,
+ &irp);
+ ENTER_NBF;
+
+ if (status == STATUS_MORE_PROCESSING_REQUIRED) {
+
+ ULONG SpecialIrpLength;
+ PTDI_REQUEST_KERNEL_RECEIVE Parameters;
+
+ //
+ // The client's event handler has returned an IRP in the
+ // form of a TdiReceive that is to be associated with this
+ // data. The request will be installed at the front of the
+ // ReceiveQueue, and then made the active receive request.
+ // This request will be used to accept the incoming data, which
+ // will happen below.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ProcessIndicateData: Status=STATUS_MORE_PROCESSING_REQUIRED.\n");
+ NbfPrint4 (" ProcessIndicateData: Irp=%lx, Mdl=%lx, UserBuffer=%lx, Count=%ld.\n",
+ irp, irp->MdlAddress, irp->UserBuffer,
+ MmGetMdlByteCount (irp->MdlAddress));
+ }
+
+ //
+ // Queueing a receive of any kind causes a Connection reference;
+ // that's what we've just done here, so make the Connection stick
+ // around. We create a request to keep a packets outstanding ref
+ // count for the current IRP; we queue this on the connection's
+ // receive queue so we can treat it like a normal receive. If
+ // we can't get a request to describe this irp, we can't keep it
+ // around hoping for better later; we simple fail it with
+ // insufficient resources. Note this is only likely to happen if
+ // we've completely run out of transport memory.
+ //
+
+ irp->IoStatus.Information = 0; // byte transfer count.
+ irp->IoStatus.Status = STATUS_PENDING;
+ irpSp = IoGetCurrentIrpStackLocation (irp);
+
+ ASSERT (irpSp->FileObject->FsContext == Connection);
+
+ Parameters = (PTDI_REQUEST_KERNEL_RECEIVE)&irpSp->Parameters;
+ SpecialIrpLength = Parameters->ReceiveLength;
+
+ //
+ // If the packet is a DOL, and it will fit entirely
+ // inside this posted IRP, then we don't bother
+ // creating a request, because we don't need any of
+ // that overhead. We also don't set ReceiveBytes
+ // Unaccepted, since this receive would clear it
+ // anyway.
+ //
+
+ if (Last &&
+ (SpecialIrpLength >= (DataTotalLength - indicateBytesTransferred))) {
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ Connection->SpecialReceiveIrp = irp;
+
+ Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
+ Connection->ReceiveLength = SpecialIrpLength;
+ Connection->MessageBytesReceived = 0;
+ Connection->MessageInitAccepted = indicateBytesTransferred;
+ Connection->MessageBytesAcked = 0;
+ Connection->CurrentReceiveIrp = NULL;
+ Connection->CurrentReceiveSynchronous = TRUE;
+ Connection->CurrentReceiveMdl = irp->MdlAddress;
+ Connection->ReceiveByteOffset = 0;
+ if ((Parameters->ReceiveFlags & TDI_RECEIVE_NO_RESPONSE_EXP) != 0) {
+ Connection->CurrentReceiveAckQueueable = FALSE;
+ }
+
+#if DBG
+ //
+ // switch our reference from PROCESS_DATA to
+ // RECEIVE_IRP, this is OK because the RECEIVE_IRP
+ // reference won't be removed until Transfer
+ // DataComplete, which is the last thing
+ // we call.
+ //
+
+ NbfReferenceConnection("Special IRP", Connection, CREF_RECEIVE_IRP);
+ NbfDereferenceConnection("ProcessIIndicate done", Connection, CREF_PROCESS_DATA);
+#endif
+
+ } else {
+ KIRQL cancelIrql;
+
+ //
+ // The normal path, for longer receives.
+ //
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ IRP_RECEIVE_IRP(irpSp) = irp;
+ if (deviceContext->MacInfo.SingleReceive) {
+ IRP_RECEIVE_REFCOUNT(irpSp) = 1;
+ } else {
+#if DBG
+ IRP_RECEIVE_REFCOUNT(irpSp) = 1;
+ NbfReferenceReceiveIrpLocked ("Transfer Data", irpSp, RREF_RECEIVE);
+#else
+ IRP_RECEIVE_REFCOUNT(irpSp) = 2; // include one for first xfer
+#endif
+ }
+
+ //
+ // If the Connection is stopping, abort this request.
+ //
+
+ if ((Connection->Flags & CONNECTION_FLAGS_READY) == 0) {
+ Connection->IndicationInProgress = FALSE;
+
+ NbfReferenceConnection("Special IRP stopping", Connection, CREF_RECEIVE_IRP);
+ NbfCompleteReceiveIrp (
+ irp,
+ Connection->Status,
+ 0);
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ if (!deviceContext->MacInfo.SingleReceive) {
+ NbfDereferenceReceiveIrp ("Not ready", irpSp, RREF_RECEIVE);
+ }
+ return STATUS_SUCCESS; // we have consumed the packet
+
+ }
+
+ //
+ // If this IRP has been cancelled, complete it now.
+ //
+
+ if (irp->Cancel) {
+
+ Connection->Flags |= CONNECTION_FLAGS_RECEIVE_WAKEUP;
+
+ Connection->IndicationInProgress = FALSE;
+
+ NbfReferenceConnection("Special IRP cancelled", Connection, CREF_RECEIVE_IRP);
+
+ //
+ // It is safe to call this with locks held.
+ //
+ NbfCompleteReceiveIrp (irp, STATUS_CANCELLED, 0);
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ if (!deviceContext->MacInfo.SingleReceive) {
+ NbfDereferenceReceiveIrp ("Cancelled", irpSp, RREF_RECEIVE);
+ }
+
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Insert the request on the head of the connection's
+ // receive queue, so it can be handled like a normal
+ // receive.
+ //
+
+ InsertHeadList (&Connection->ReceiveQueue, &irp->Tail.Overlay.ListEntry);
+
+ IoSetCancelRoutine(irp, NbfCancelReceive);
+
+ //
+ // Release the cancel spinlock out of order. Since we were
+ // at DPC level when we acquired it, we don't have to fiddle
+ // with swapping irqls.
+ //
+ ASSERT(cancelIrql == DISPATCH_LEVEL);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
+ Connection->ReceiveLength = Parameters->ReceiveLength;
+ Connection->MessageBytesReceived = 0;
+ Connection->MessageInitAccepted = indicateBytesTransferred;
+ Connection->ReceiveBytesUnaccepted = DataTotalLength - indicateBytesTransferred;
+ Connection->MessageBytesAcked = 0;
+ Connection->CurrentReceiveIrp = irp;
+ Connection->CurrentReceiveSynchronous =
+ deviceContext->MacInfo.SingleReceive;
+ Connection->CurrentReceiveMdl = irp->MdlAddress;
+ Connection->ReceiveByteOffset = 0;
+
+#if DBG
+ //
+ // switch our reference from PROCESS_DATA to
+ // REQUEST, this is OK because the REQUEST
+ // reference won't be removed until Transfer
+ // DataComplete, which is the last thing
+ // we call.
+ //
+
+ NbfReferenceConnection("Special IRP", Connection, CREF_RECEIVE_IRP);
+ NbfDereferenceConnection("ProcessIIndicate done", Connection, CREF_PROCESS_DATA);
+#endif
+ //
+ // Make a note so we know what to do below.
+ //
+
+ ActivatedLongReceive = TRUE;
+
+#if DBG
+ NbfReceives[NbfReceivesNext].Irp = irp;
+ NbfReceivesNext = (NbfReceivesNext++) % TRACK_TDI_LIMIT;
+#endif
+ }
+
+ } else if (status == STATUS_SUCCESS) {
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ProcessIndicateData: Status=STATUS_SUCCESS.\n");
+ }
+
+ //
+ // The client has accepted some or all of the indicated data in
+ // the event handler. Update MessageBytesReceived variable in
+ // the Connection so that if we are called upon to ACK him
+ // at the byte level, then we can correctly report the
+ // number of bytes received thus far. If this is a DOL,
+ // then reset the number of bytes received, since this value
+ // always at zero for new messages. If the data indicated wasn't
+ // all the data in this packet, flow control to the sender that
+ // didn't get all of the data.
+ //
+
+ if (Last && (indicateBytesTransferred >= DataTotalLength)) {
+
+ ASSERT (indicateBytesTransferred == DataTotalLength);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // This will send a DATA ACK or queue a request for
+ // a piggyback ack.
+ //
+ // NOTE: It will also release the connection spinlock.
+ //
+
+ Connection->MessageBytesReceived = 0;
+ Connection->MessageInitAccepted = indicateBytesTransferred;
+
+ NbfAcknowledgeDataOnlyLast(
+ Connection,
+ Connection->MessageBytesReceived
+ );
+
+ Connection->IndicationInProgress = FALSE;
+ return STATUS_SUCCESS;
+
+ } else {
+
+ //
+ // This gets gory.
+ // If this packet wasn't a DOL, we have no way of knowing how
+ // much the client will take of the data in this send that is
+ // now arriving. Pathological clients will break this protocol
+ // if they do things like taking part of the receive at indicate
+ // immediate and then return an irp (this would make the byte
+ // count wrong for the irp).
+ //
+ // Since the client did not take all the data that we
+ // told him about, he will eventually post a receive.
+ // If this has not already happened then we set the
+ // RECEIVE_WAKEUP bit and send a NO_RECEIVE.
+ //
+
+#if DBG
+ NbfPrint0("NBF: Indicate returned SUCCESS but did not take all data\n");
+#endif
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ Connection->MessageBytesReceived = 0;
+ Connection->MessageInitAccepted = indicateBytesTransferred;
+ Connection->ReceiveBytesUnaccepted = DataTotalLength - indicateBytesTransferred;
+ Connection->MessageBytesAcked = 0;
+
+ if (Connection->ReceiveQueue.Flink == &Connection->ReceiveQueue) {
+
+ //
+ // There is no receive posted to the Connection.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ProcessIndicateData: ReceiveQueue empty. Setting RECEIVE_WAKEUP.\n");
+ }
+
+ if (indicateBytesTransferred == DataTotalLength) {
+
+ //
+ // This means he took everything, but it was not
+ // a DOL; there is no need to do anything since
+ // the rest of the data will be right behind.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ } else {
+
+ Connection->Flags |= CONNECTION_FLAGS_RECEIVE_WAKEUP;
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ NbfSendNoReceive (Connection);
+
+ }
+
+ Connection->IndicationInProgress = FALSE;
+
+ return STATUS_SUCCESS;
+
+ } else {
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ProcessIndicateData: Found receive. Prepping.\n");
+ }
+
+ //
+ // Found a receive, so make it the active one. This will cause
+ // an NdisTransferData below, so we don't dereference the
+ // Connection here.
+ //
+
+ Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
+ Connection->CurrentReceiveIrp =
+ CONTAINING_RECORD (Connection->ReceiveQueue.Flink,
+ IRP, Tail.Overlay.ListEntry);
+ Connection->CurrentReceiveSynchronous =
+ deviceContext->MacInfo.SingleReceive;
+ Connection->CurrentReceiveMdl =
+ Connection->CurrentReceiveIrp->MdlAddress;
+ Connection->ReceiveLength =
+ IRP_RECEIVE_LENGTH (IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp));
+ Connection->ReceiveByteOffset = 0;
+ }
+
+ }
+
+ } else { // STATUS_DATA_NOT_ACCEPTED or other
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ProcessIndicateData: Status=STATUS_DATA_NOT_ACCEPTED.\n");
+ }
+
+ //
+ // Either there is no event handler installed (the default
+ // handler returns this code) or the event handler is not
+ // able to process the received data at this time. If there
+ // is a TdiReceive request outstanding on this Connection's
+ // ReceiveQueue, then we may use it to receive this data.
+ // If there is no request outstanding, then we must initiate
+ // flow control at the transport level.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Connection->ReceiveBytesUnaccepted = DataTotalLength;
+
+ if (Connection->ReceiveQueue.Flink == &Connection->ReceiveQueue) {
+
+ //
+ // There is no receive posted to the Connection, and
+ // the event handler didn't want to accept the incoming
+ // data. Set the RECEIVE_WAKEUP bit, so that when a
+ // receive does become available, it will restart the
+ // current send. Also send a NoReceive to tell the other
+ // guy he needs to resynch.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ProcessIndicateData: ReceiveQueue empty. Setting RECEIVE_WAKEUP.\n");
+ }
+ Connection->Flags |= CONNECTION_FLAGS_RECEIVE_WAKEUP;
+ Connection->IndicationInProgress = FALSE;
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ return STATUS_SUCCESS;
+
+ } else {
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ProcessIndicateData: Found receive. Prepping.\n");
+ }
+
+ //
+ // Found a receive, so make it the active one. This will cause
+ // an NdisTransferData below, so we don't dereference the
+ // Connection here.
+ //
+
+ Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
+ Connection->MessageBytesReceived = 0;
+ Connection->MessageBytesAcked = 0;
+ Connection->MessageInitAccepted = 0;
+ Connection->CurrentReceiveIrp =
+ CONTAINING_RECORD (Connection->ReceiveQueue.Flink,
+ IRP, Tail.Overlay.ListEntry);
+ Connection->CurrentReceiveSynchronous =
+ deviceContext->MacInfo.SingleReceive;
+ Connection->CurrentReceiveMdl =
+ Connection->CurrentReceiveIrp->MdlAddress;
+ Connection->ReceiveLength =
+ IRP_RECEIVE_LENGTH (IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp));
+ Connection->ReceiveByteOffset = 0;
+ }
+
+ }
+
+ } else {
+
+ //
+ // A receive is active, set the status to show
+ // that so far.
+ //
+
+ status = STATUS_SUCCESS;
+
+ }
+
+
+NormalReceive:;
+
+ //
+ // NOTE: The connection spinlock is held here.
+ //
+ // We should only get through here if a receive is active
+ // and we have not released the lock since checking or
+ // making one active.
+ //
+
+ ASSERT(Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE);
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint2 (" ProcessIndicateData: Receive is active. ReceiveLengthLength: %ld Offset: %ld.\n",
+ Connection->ReceiveLength, Connection->MessageBytesReceived);
+ }
+
+ destBytes = Connection->ReceiveLength - Connection->MessageBytesReceived;
+
+ //
+ // If we just activated a non-special receive IRP, we already
+ // added a refcount for this transfer.
+ //
+
+ if (!Connection->CurrentReceiveSynchronous && !ActivatedLongReceive) {
+ NbfReferenceReceiveIrpLocked ("Transfer Data", IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp), RREF_RECEIVE);
+ }
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+
+ //
+ // Determine how much data remains to be transferred.
+ //
+
+ ASSERT (indicateBytesTransferred <= DataTotalLength);
+ BytesToTransfer = DataTotalLength - indicateBytesTransferred;
+
+ if (destBytes < BytesToTransfer) {
+
+ //
+ // If the data overflows the current receive, then make a
+ // note that we should complete the receive at the end of
+ // transfer data, but with EOR false.
+ //
+
+ EndOfMessage = FALSE;
+ CompleteReceiveBool = TRUE;
+ BytesToTransfer = destBytes;
+
+ } else if (destBytes == BytesToTransfer) {
+
+ //
+ // If the data just fills the current receive, then complete
+ // the receive; EOR depends on whether this is a DOL or not.
+ //
+
+ EndOfMessage = Last;
+ CompleteReceiveBool = TRUE;
+
+ } else {
+
+ //
+ // Complete the receive if this is a DOL.
+ //
+
+ EndOfMessage = Last;
+ CompleteReceiveBool = Last;
+
+ }
+
+
+ //
+ // If we can copy the data directly, then do so.
+ //
+
+ if ((BytesToTransfer > 0) &&
+ (DataOffset + indicateBytesTransferred + BytesToTransfer <= DlcIndicatedLength)) {
+
+ //
+ // All the data that we need to transfer is available in
+ // the indication, so copy it directly.
+ //
+
+ ULONG BytesNow, BytesLeft;
+ PUCHAR CurTarget, CurSource;
+ ULONG CurTargetLen;
+ PMDL CurMdl;
+ ULONG CurByteOffset;
+
+ //
+ // First we advance the connection pointers by the appropriate
+ // number of bytes, so that we can reallow indications (only
+ // do this if needed).
+ //
+
+ CurMdl = Connection->CurrentReceiveMdl;
+ CurByteOffset = Connection->ReceiveByteOffset;
+
+ if (!deviceContext->MacInfo.ReceiveSerialized) {
+
+ SavedCurrentMdl = CurMdl;
+ SavedCurrentByteOffset = CurByteOffset;
+
+ BytesLeft = BytesToTransfer;
+ CurTargetLen = MmGetMdlByteCount (CurMdl) - CurByteOffset;
+ while (TRUE) {
+ if (BytesLeft >= CurTargetLen) {
+ BytesLeft -= CurTargetLen;
+ CurMdl = CurMdl->Next;
+ CurByteOffset = 0;
+ if (BytesLeft == 0) {
+ break;
+ }
+ CurTargetLen = MmGetMdlByteCount (CurMdl);
+ } else {
+ CurByteOffset += BytesLeft;
+ break;
+ }
+ }
+
+ Connection->CurrentReceiveMdl = CurMdl;
+ Connection->ReceiveByteOffset = CurByteOffset;
+ Connection->MessageBytesReceived += BytesToTransfer;
+
+ //
+ // Set this up, we know the transfer won't
+ // "fail" but another one at the same time
+ // might.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ if (Connection->TransferBytesPending == 0) {
+ Connection->TransferBytesPending = BytesToTransfer;
+ Connection->TotalTransferBytesPending = BytesToTransfer;
+ Connection->SavedCurrentReceiveMdl = SavedCurrentMdl;
+ Connection->SavedReceiveByteOffset = SavedCurrentByteOffset;
+ } else {
+ Connection->TransferBytesPending += BytesToTransfer;
+ Connection->TotalTransferBytesPending += BytesToTransfer;
+ }
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Connection->IndicationInProgress = FALSE;
+
+ //
+ // Restore these for the next section of code.
+ //
+
+ CurMdl = SavedCurrentMdl;
+ CurByteOffset = SavedCurrentByteOffset;
+
+ }
+
+ CurTarget = (PUCHAR)(MmGetSystemAddressForMdl(CurMdl)) + CurByteOffset;
+ CurTargetLen = MmGetMdlByteCount(CurMdl) - CurByteOffset;
+ CurSource = DataHeader + indicateBytesTransferred;
+
+ BytesLeft = BytesToTransfer;
+
+ while (TRUE) {
+
+ if (CurTargetLen < BytesLeft) {
+ BytesNow = CurTargetLen;
+ } else {
+ BytesNow = BytesLeft;
+ }
+ TdiCopyLookaheadData(
+ CurTarget,
+ CurSource,
+ BytesNow,
+ deviceContext->MacInfo.CopyLookahead ? TDI_RECEIVE_COPY_LOOKAHEAD : 0);
+
+ if (BytesNow == CurTargetLen) {
+ BytesLeft -= BytesNow;
+ CurMdl = CurMdl->Next;
+ CurByteOffset = 0;
+ if (BytesLeft > 0) {
+ CurTarget = MmGetSystemAddressForMdl(CurMdl);
+ CurTargetLen = MmGetMdlByteCount(CurMdl);
+ CurSource += BytesNow;
+ } else {
+ break;
+ }
+ } else {
+ CurByteOffset += BytesNow;
+ ASSERT (BytesLeft == BytesNow);
+ break;
+ }
+
+ }
+
+ if (deviceContext->MacInfo.ReceiveSerialized) {
+
+ //
+ // If we delayed updating these, do it now.
+ //
+
+ Connection->CurrentReceiveMdl = CurMdl;
+ Connection->ReceiveByteOffset = CurByteOffset;
+ Connection->MessageBytesReceived += BytesToTransfer;
+ Connection->IndicationInProgress = FALSE;
+
+ } else {
+
+ //
+ // Check if something else failed and we are the
+ // last to complete, if so then back up our
+ // receive pointers and send a receive
+ // outstanding to make him resend.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Connection->TransferBytesPending -= BytesToTransfer;
+
+ if ((Connection->TransferBytesPending == 0) &&
+ (Connection->Flags & CONNECTION_FLAGS_TRANSFER_FAIL)) {
+
+ Connection->CurrentReceiveMdl = Connection->SavedCurrentReceiveMdl;
+ Connection->ReceiveByteOffset = Connection->SavedReceiveByteOffset;
+ Connection->MessageBytesReceived -= Connection->TotalTransferBytesPending;
+ Connection->Flags &= ~CONNECTION_FLAGS_TRANSFER_FAIL;
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ NbfSendReceiveOutstanding (Connection);
+
+ if (!Connection->SpecialReceiveIrp &&
+ !Connection->CurrentReceiveSynchronous) {
+ NbfDereferenceReceiveIrp ("TransferData complete", IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp), RREF_RECEIVE);
+ }
+
+ return status;
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ }
+
+ }
+
+ //
+ // Now that the transfer is complete, simulate a call to
+ // TransferDataComplete.
+ //
+
+
+ if (!Connection->SpecialReceiveIrp) {
+
+ Connection->CurrentReceiveIrp->IoStatus.Information += BytesToTransfer;
+ if (!Connection->CurrentReceiveSynchronous) {
+ NbfDereferenceReceiveIrp ("TransferData complete", IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp), RREF_RECEIVE);
+ }
+
+ }
+
+ //
+ // see if we've completed the current receive. If so, move to the next one.
+ //
+
+ if (CompleteReceiveBool) {
+ CompleteReceive (Connection, EndOfMessage, BytesToTransfer);
+ }
+
+ return status;
+
+ }
+
+
+ //
+ // Get a packet for the coming transfer
+ //
+
+ linkage = ExInterlockedPopEntryList(
+ &deviceContext->ReceivePacketPool,
+ &deviceContext->Interlock);
+
+ if (linkage != NULL) {
+ ndisPacket = CONTAINING_RECORD( linkage, NDIS_PACKET, ProtocolReserved[0] );
+ } else {
+ deviceContext->ReceivePacketExhausted++;
+ if (!Connection->CurrentReceiveSynchronous) {
+ NbfDereferenceReceiveIrp ("No receive packet", IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp), RREF_RECEIVE);
+ }
+
+ //
+ // We could not get a receive packet. We do have an active
+ // receive, so we just send a receive outstanding to
+ // get him to resend. Hopefully we will have a receive
+ // packet available when the data is resent.
+ //
+
+ if ((Connection->Flags & CONNECTION_FLAGS_VERSION2) == 0) {
+ NbfSendNoReceive (Connection);
+ }
+ NbfSendReceiveOutstanding (Connection);
+
+#if DBG
+ NbfPrint0 (" ProcessIndicateData: Discarding Packet, no receive packets\n");
+#endif
+ Connection->IndicationInProgress = FALSE;
+
+ return status;
+ }
+
+ //
+ // Initialize the receive packet.
+ //
+
+ receiveTag = (PRECEIVE_PACKET_TAG)(ndisPacket->ProtocolReserved);
+ // receiveTag->PacketType = TYPE_AT_INDICATE;
+ receiveTag->Connection = Connection;
+ receiveTag->TransferDataPended = TRUE;
+
+ receiveTag->EndOfMessage = EndOfMessage;
+ receiveTag->CompleteReceive = CompleteReceiveBool;
+
+
+ //
+ // if we've got zero bytes left, avoid the TransferData below and
+ // just deliver.
+ //
+
+ if (BytesToTransfer <= 0) {
+ Connection->IndicationInProgress = FALSE;
+ receiveTag->TransferDataPended = FALSE;
+ receiveTag->AllocatedNdisBuffer = FALSE;
+ receiveTag->BytesToTransfer = 0;
+ NbfTransferDataComplete (
+ deviceContext,
+ ndisPacket,
+ NDIS_STATUS_SUCCESS,
+ 0);
+
+ return status;
+ }
+
+ //
+ // describe the right part of the user buffer to NDIS. If we can't get
+ // the mdl for the packet, drop dead. Bump the request reference count
+ // so that we know we need to hold open receives until the NDIS transfer
+ // data requests complete.
+ //
+
+ SavedCurrentMdl = Connection->CurrentReceiveMdl;
+ SavedCurrentByteOffset = Connection->ReceiveByteOffset;
+
+ if ((Connection->ReceiveByteOffset == 0) &&
+ (CompleteReceiveBool)) {
+
+ //
+ // If we are transferring into the beginning of
+ // the current MDL, and we will be completing the
+ // receive after the transfer, then we don't need to
+ // copy it.
+ //
+
+ ndisBuffer = (PNDIS_BUFFER)Connection->CurrentReceiveMdl;
+ bufferChainLength = BytesToTransfer;
+ Connection->CurrentReceiveMdl = NULL;
+ // Connection->ReceiveByteOffset = 0;
+ receiveTag->AllocatedNdisBuffer = FALSE;
+ tmpstatus = STATUS_SUCCESS;
+
+ } else {
+
+ tmpstatus = BuildBufferChainFromMdlChain (
+ deviceContext,
+ Connection->CurrentReceiveMdl,
+ Connection->ReceiveByteOffset,
+ BytesToTransfer,
+ &ndisBuffer,
+ &Connection->CurrentReceiveMdl,
+ &Connection->ReceiveByteOffset,
+ &bufferChainLength);
+
+ receiveTag->AllocatedNdisBuffer = TRUE;
+
+ }
+
+
+ if ((!NT_SUCCESS (tmpstatus)) || (bufferChainLength != BytesToTransfer)) {
+
+ DumpData[0] = bufferChainLength;
+ DumpData[1] = BytesToTransfer;
+
+ NbfWriteGeneralErrorLog(
+ deviceContext,
+ EVENT_TRANSPORT_TRANSFER_DATA,
+ 604,
+ tmpstatus,
+ NULL,
+ 2,
+ DumpData);
+
+ if (!Connection->CurrentReceiveSynchronous) {
+ NbfDereferenceReceiveIrp ("No MDL chain", IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp), RREF_RECEIVE);
+ }
+
+ //
+ // Restore our old state and make him resend.
+ //
+
+ Connection->CurrentReceiveMdl = SavedCurrentMdl;
+ Connection->ReceiveByteOffset = SavedCurrentByteOffset;
+
+ if ((Connection->Flags & CONNECTION_FLAGS_VERSION2) == 0) {
+ NbfSendNoReceive (Connection);
+ }
+ NbfSendReceiveOutstanding (Connection);
+
+ Connection->IndicationInProgress = FALSE;
+
+ ExInterlockedPushEntryList(
+ &deviceContext->ReceivePacketPool,
+ &receiveTag->Linkage,
+ &deviceContext->Interlock);
+
+ return status;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint3 (" ProcessIndicateData: Mdl: %lx user buffer: %lx user offset: %lx \n",
+ ndisBuffer, Connection->CurrentReceiveMdl, Connection->ReceiveByteOffset);
+ }
+
+ NdisChainBufferAtFront (ndisPacket, ndisBuffer);
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 (" ProcessIndicateData: Transferring Complete Packet: %lx\n",
+ ndisPacket);
+ }
+
+ //
+ // update the number of bytes received; OK to do this
+ // unprotected since IndicationInProgress is still FALSE.
+ //
+ //
+
+ Connection->MessageBytesReceived += BytesToTransfer;
+
+ //
+ // We have to do this for two reasons: for MACs that
+ // are not receive-serialized, to keep track of it,
+ // and for MACs where transfer data can pend, so
+ // we have stuff saved to handle failure later (if
+ // the MAC is synchronous on transfers and it fails,
+ // we fill these fields in before calling CompleteTransferData).
+ //
+
+ if (!deviceContext->MacInfo.SingleReceive) {
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ receiveTag->BytesToTransfer = BytesToTransfer;
+ if (Connection->TransferBytesPending == 0) {
+ Connection->TransferBytesPending = BytesToTransfer;
+ Connection->TotalTransferBytesPending = BytesToTransfer;
+ Connection->SavedCurrentReceiveMdl = SavedCurrentMdl;
+ Connection->SavedReceiveByteOffset = SavedCurrentByteOffset;
+ } else {
+ Connection->TransferBytesPending += BytesToTransfer;
+ Connection->TotalTransferBytesPending += BytesToTransfer;
+ }
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ }
+
+ //
+ // We have now updated all the connection counters (BUGBUG
+ // assuming the TransferData will succeed) and this
+ // packet's location in the request is secured, so we
+ // can be reentered.
+ //
+
+ Connection->IndicationInProgress = FALSE;
+
+ if (Loopback) {
+
+ NbfTransferLoopbackData(
+ &ndisStatus,
+ deviceContext,
+ ReceiveContext,
+ deviceContext->MacInfo.TransferDataOffset +
+ DataOffset + indicateBytesTransferred,
+ BytesToTransfer,
+ ndisPacket,
+ (PUINT)&ndisBytesTransferred
+ );
+
+ } else {
+
+ NdisTransferData (
+ &ndisStatus,
+ deviceContext->NdisBindingHandle,
+ ReceiveContext,
+ deviceContext->MacInfo.TransferDataOffset +
+ DataOffset + indicateBytesTransferred,
+ BytesToTransfer,
+ ndisPacket,
+ (PUINT)&ndisBytesTransferred);
+
+ }
+
+ //
+ // handle the various completion codes
+ //
+
+ if ((ndisStatus == NDIS_STATUS_SUCCESS) &&
+ (ndisBytesTransferred == BytesToTransfer)) {
+
+ //
+ // deallocate the buffers and such that we've used if at indicate
+ //
+
+ receiveTag->TransferDataPended = FALSE;
+
+ NbfTransferDataComplete (
+ deviceContext,
+ ndisPacket,
+ ndisStatus,
+ BytesToTransfer);
+
+ } else if (ndisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // Because TransferDataPended stays TRUE, this reference will
+ // be removed in TransferDataComplete. It is OK to do this
+ // now, even though TransferDataComplete may already have been
+ // called, because we also hold the ProcessIIndicate reference
+ // so there will be no "bounce".
+ //
+
+ NbfReferenceConnection ("TransferData pended", Connection, CREF_TRANSFER_DATA);
+
+ } else {
+
+ //
+ // something broke; certainly we'll never get NdisTransferData
+ // asynch completion with this error status. We set things up
+ // to that NbfTransferDataComplete will do the right thing.
+ //
+
+ if (deviceContext->MacInfo.SingleReceive) {
+ Connection->TransferBytesPending = BytesToTransfer;
+ Connection->TotalTransferBytesPending = BytesToTransfer;
+ Connection->SavedCurrentReceiveMdl = SavedCurrentMdl;
+ Connection->SavedReceiveByteOffset = SavedCurrentByteOffset;
+ receiveTag->BytesToTransfer = BytesToTransfer;
+ }
+
+ receiveTag->TransferDataPended = FALSE;
+
+ NbfTransferDataComplete (
+ deviceContext,
+ ndisPacket,
+ ndisStatus,
+ BytesToTransfer);
+
+ }
+
+ return status; // which only means we've dealt with the packet
+
+} /* ProcessIndicateData */
diff --git a/private/ntos/tdi/nbf/info.c b/private/ntos/tdi/nbf/info.c
new file mode 100644
index 000000000..f1cf8890b
--- /dev/null
+++ b/private/ntos/tdi/nbf/info.c
@@ -0,0 +1,3487 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ info.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiQueryInformation
+ o TdiSetInformation
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Only the following routine is active in this module. All is is commented
+// out waiting for the definition of Get/Set info in TDI version 2.
+//
+
+//
+// Useful macro to obtain the total length of an MDL chain.
+//
+
+#define NbfGetMdlChainLength(Mdl, Length) { \
+ PMDL _Mdl = (Mdl); \
+ *(Length) = 0; \
+ while (_Mdl) { \
+ *(Length) += MmGetMdlByteCount(_Mdl); \
+ _Mdl = _Mdl->Next; \
+ } \
+}
+
+
+//
+// Local functions used to satisfy various requests.
+//
+
+VOID
+NbfStoreProviderStatistics(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTDI_PROVIDER_STATISTICS ProviderStatistics
+ );
+
+VOID
+NbfStoreAdapterStatus(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN PVOID StatusBuffer
+ );
+
+VOID
+NbfStoreNameBuffers(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PVOID Buffer,
+ IN ULONG BufferLength,
+ IN ULONG NamesToSkip,
+ OUT PULONG NamesWritten,
+ OUT PULONG TotalNameCount OPTIONAL,
+ OUT PBOOLEAN Truncated
+ );
+
+
+NTSTATUS
+NbfTdiQueryInformation(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiQueryInformation request for the transport
+ provider.
+
+Arguments:
+
+ Irp - the Irp for the requested operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PIO_STACK_LOCATION irpSp;
+ PVOID adapterStatus;
+ PTDI_REQUEST_KERNEL_QUERY_INFORMATION query;
+ PTA_NETBIOS_ADDRESS broadcastAddress;
+ PTDI_PROVIDER_STATISTICS ProviderStatistics;
+ PTDI_CONNECTION_INFO ConnectionInfo;
+ ULONG TargetBufferLength;
+ PFIND_NAME_HEADER FindNameHeader;
+ LARGE_INTEGER timeout = {0,0};
+ PTP_REQUEST tpRequest;
+ PTP_CONNECTION Connection;
+ PTP_ADDRESS_FILE AddressFile;
+ PTP_ADDRESS Address;
+ ULONG NamesWritten, TotalNameCount, BytesWritten;
+ BOOLEAN Truncated;
+ BOOLEAN RemoteAdapterStatus;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteAddress;
+ struct {
+ ULONG ActivityCount;
+ TA_NETBIOS_ADDRESS TaAddressBuffer;
+ } AddressInfo;
+ PTRANSPORT_ADDRESS TaAddress;
+ TDI_DATAGRAM_INFO DatagramInfo;
+ BOOLEAN UsedConnection;
+ PLIST_ENTRY p;
+ KIRQL oldirql;
+
+ //
+ // what type of status do we want?
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&irpSp->Parameters;
+
+ switch (query->QueryType) {
+
+#if 0
+ case 0x12345678:
+
+ {
+ typedef struct _NBF_CONNECTION_STATUS {
+ UCHAR LocalName[16];
+ UCHAR RemoteName[16];
+ BOOLEAN SendActive;
+ BOOLEAN ReceiveQueued;
+ BOOLEAN ReceiveActive;
+ BOOLEAN ReceiveWakeUp;
+ ULONG Flags;
+ ULONG Flags2;
+ } NBF_CONNECTION_STATUS, *PNBF_CONNECTION_STATUS;
+
+ PNBF_CONNECTION_STATUS CurStatus;
+ ULONG TotalStatus;
+ ULONG AllowedStatus;
+ PLIST_ENRY q;
+
+ CurStatus = MmGetSystemAddressForMdl (Irp->MdlAddress);
+ TotalStatus = 0;
+ AllowedStatus = MmGetMdlByteCount (Irp->MdlAddress) / sizeof(NBF_CONNECTION_STATUS);
+
+ for (p = DeviceContext->AddressDatabase.Flink;
+ p != &DeviceContext->AddressDatabase;
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+
+ if ((Address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ continue;
+ }
+
+ for (q = Address->ConnectionDatabase.Flink;
+ q != &Address->ConnectionDatabase;
+ q = q->Flink) {
+
+ Connection = CONTAINING_RECORD (q, TP_CONNECTION, AddressList);
+
+ if ((Connection->Flags & CONNECTION_FLAGS_READY) == 0) {
+ continue;
+ }
+
+ if (TotalStatus >= AllowedStatus) {
+ continue;
+ }
+
+ RtlMoveMemory (CurStatus->LocalName, Address->NetworkName->NetbiosName, 16);
+ RtlMoveMemory (CurStatus->RemoteName, Connection->RemoteName, 16);
+
+ CurStatus->Flags = Connection->Flags;
+ CurStatus->Flags2 = Connection->Flags2;
+ CurStatus->SendActive = (BOOLEAN)(!IsListEmpty(&Connection->SendQueue));
+ CurStatus->ReceiveQueued = (BOOLEAN)(!IsListEmpty(&Connection->ReceiveQueue));
+ CurStatus->ReceiveActive = (BOOLEAN)((Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE) != 0);
+ CurStatus->ReceiveWakeUp = (BOOLEAN)((Connection->Flags & CONNECTION_FLAGS_RECEIVE_WAKEUP) != 0);
+
+ ++CurStatus;
+ ++TotalStatus;
+
+ }
+ }
+
+ Irp->IoStatus.Information = TotalStatus * sizeof(NBF_CONNECTION_STATUS);
+ status = STATUS_SUCCESS;
+
+ }
+
+ break;
+#endif
+
+ case TDI_QUERY_CONNECTION_INFO:
+
+ //
+ // Connection info is queried on a connection,
+ // verify this.
+ //
+
+ Connection = irpSp->FileObject->FsContext;
+
+ status = NbfVerifyConnectionObject (Connection);
+
+ if (!NT_SUCCESS (status)) {
+#if DBG
+ NbfPrint2 ("TdiQueryInfo: Invalid Connection %lx Irp %lx\n", Connection, Irp);
+#endif
+ return status;
+ }
+
+ ConnectionInfo = ExAllocatePoolWithTag (
+ NonPagedPool,
+ sizeof (TDI_CONNECTION_INFO),
+ ' FBN');
+
+ if (ConnectionInfo == NULL) {
+
+ PANIC ("NbfQueryInfo: Cannot allocate connection info!\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 6,
+ sizeof(TDI_CONNECTION_INFO),
+ 0);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else if ((Connection->Flags & CONNECTION_FLAGS_READY) == 0) {
+
+ status = STATUS_INVALID_CONNECTION;
+ ExFreePool (ConnectionInfo);
+
+ } else {
+
+ PTP_LINK Link = Connection->Link;
+
+ RtlZeroMemory ((PVOID)ConnectionInfo, sizeof(TDI_CONNECTION_INFO));
+
+
+ //
+ // Get link delay and throughput.
+ //
+
+ if (Link->Delay == 0xffffffff) {
+
+ //
+ // If delay is not known, assume 0.
+ //
+
+ ConnectionInfo->Delay.HighPart = 0;
+ ConnectionInfo->Delay.LowPart = 0;
+
+ } else {
+
+ //
+ // Copy the delay as an NT relative time.
+ //
+
+ ConnectionInfo->Delay.HighPart = -1L;
+ ConnectionInfo->Delay.LowPart = (ULONG)-((LONG)(Link->Delay));
+
+ }
+
+ if (DeviceContext->MacInfo.MediumAsync) {
+
+ ULONG PacketsSent;
+ ULONG PacketsResent;
+ ULONG MultiplyFactor;
+
+ //
+ // Calculate the packets sent and resent since the
+ // last time the throughput was queried.
+ //
+
+ PacketsSent = Link->PacketsSent - Connection->LastPacketsSent;
+ PacketsResent = Link->PacketsResent - Connection->LastPacketsResent;
+
+ //
+ // Save these for next time.
+ //
+
+ Connection->LastPacketsSent = Link->PacketsSent;
+ Connection->LastPacketsResent = Link->PacketsResent;
+
+ //
+ // To convert exactly from 100 bits-per-second to
+ // bytes-per-second, we need to multiply by 12.5.
+ // Using lower numbers will give worse throughput.
+ // If there have been no errors we use 12, if there
+ // have been 20% or more errors we use 1, and in
+ // between we subtract 11 * (error%/20%) from 12
+ // and use that.
+ //
+
+ if (PacketsResent == 0 || PacketsSent <= 10) {
+
+ MultiplyFactor = 12;
+
+ } else if ((PacketsSent / PacketsResent) <= 5) {
+
+ MultiplyFactor = 1;
+
+ } else {
+
+ //
+ // error%/20% is error%/(1/5), which is 5*error%,
+ // which is 5 * (resent/send).
+ //
+
+ ASSERT (((11 * 5 * PacketsResent) / PacketsSent) <= 11);
+ MultiplyFactor = 12 - ((11 * 5 * PacketsResent) / PacketsSent);
+
+ }
+
+ ConnectionInfo->Throughput.QuadPart =
+ UInt32x32To64(DeviceContext->MediumSpeed, MultiplyFactor);
+
+ } else if (!Link->ThroughputAccurate) {
+
+ //
+ // If throughput is not known, then guess. We
+ // have MediumSpeed in units of 100 bps; we
+ // return four times that number as the throughput,
+ // which corresponds to about 1/3 of the
+ // maximum bandwidth expressed in bytes/sec.
+ //
+
+ ConnectionInfo->Throughput.QuadPart =
+ UInt32x32To64(DeviceContext->MediumSpeed, 4);
+
+ } else {
+
+ //
+ // Throughput is accurate, return it.
+ //
+
+ ConnectionInfo->Throughput = Link->Throughput;
+
+ }
+
+
+ //
+ // Calculate reliability using the sent/resent ratio,
+ // if there has been enough activity to make it
+ // worthwhile. >10% resent is unreliable.
+ //
+
+ if ((Link->PacketsResent > 0) &&
+ (Link->PacketsSent > 20)) {
+
+ ConnectionInfo->Unreliable =
+ ((Link->PacketsSent / Link->PacketsResent) < 10);
+
+ } else {
+
+ ConnectionInfo->Unreliable = FALSE;
+
+ }
+
+ ConnectionInfo->TransmittedTsdus = Connection->TransmittedTsdus;
+ ConnectionInfo->ReceivedTsdus = Connection->ReceivedTsdus;
+ ConnectionInfo->TransmissionErrors = Connection->TransmissionErrors;
+ ConnectionInfo->ReceiveErrors = Connection->ReceiveErrors;
+
+ status = TdiCopyBufferToMdl (
+ (PVOID)ConnectionInfo,
+ 0L,
+ sizeof(TDI_CONNECTION_INFO),
+ Irp->MdlAddress,
+ 0,
+ &(Irp->IoStatus.Information));
+
+ ExFreePool (ConnectionInfo);
+ }
+
+ NbfDereferenceConnection ("query connection info", Connection, CREF_BY_ID);
+
+ break;
+
+ case TDI_QUERY_ADDRESS_INFO:
+
+ if (irpSp->FileObject->FsContext2 == (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
+
+ AddressFile = irpSp->FileObject->FsContext;
+
+ status = NbfVerifyAddressObject(AddressFile);
+
+ if (!NT_SUCCESS (status)) {
+#if DBG
+ NbfPrint2 ("TdiQueryInfo: Invalid AddressFile %lx Irp %lx\n", AddressFile, Irp);
+#endif
+ return status;
+ }
+
+ UsedConnection = FALSE;
+
+ } else if (irpSp->FileObject->FsContext2 == (PVOID)TDI_CONNECTION_FILE) {
+
+ Connection = irpSp->FileObject->FsContext;
+
+ status = NbfVerifyConnectionObject (Connection);
+
+ if (!NT_SUCCESS (status)) {
+#if DBG
+ NbfPrint2 ("TdiQueryInfo: Invalid Connection %lx Irp %lx\n", Connection, Irp);
+#endif
+ return status;
+ }
+
+ AddressFile = Connection->AddressFile;
+
+ UsedConnection = TRUE;
+
+ } else {
+
+ return STATUS_INVALID_ADDRESS;
+
+ }
+
+ Address = AddressFile->Address;
+
+ TdiBuildNetbiosAddress(
+ Address->NetworkName->NetbiosName,
+ (BOOLEAN)(Address->Flags & ADDRESS_FLAGS_GROUP ? TRUE : FALSE),
+ &AddressInfo.TaAddressBuffer);
+
+ //
+ // Count the active addresses.
+ //
+
+ AddressInfo.ActivityCount = 0;
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+ ++AddressInfo.ActivityCount;
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ status = TdiCopyBufferToMdl (
+ &AddressInfo,
+ 0,
+ sizeof(ULONG) + sizeof(TA_NETBIOS_ADDRESS),
+ Irp->MdlAddress,
+ 0,
+ &Irp->IoStatus.Information);
+
+ if (UsedConnection) {
+
+ NbfDereferenceConnection ("query address info", Connection, CREF_BY_ID);
+
+ } else {
+
+ NbfDereferenceAddress ("query address info", Address, AREF_VERIFY);
+
+ }
+
+ break;
+
+ case TDI_QUERY_BROADCAST_ADDRESS:
+
+ //
+ // for this provider, the broadcast address is a zero byte name,
+ // contained in a Transport address structure.
+ //
+
+ broadcastAddress = ExAllocatePoolWithTag (
+ NonPagedPool,
+ sizeof (TA_NETBIOS_ADDRESS),
+ ' FBN');
+ if (broadcastAddress == NULL) {
+ PANIC ("NbfQueryInfo: Cannot allocate broadcast address!\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 2,
+ sizeof(TA_NETBIOS_ADDRESS),
+ 0);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ } else {
+
+ broadcastAddress->TAAddressCount = 1;
+ broadcastAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ broadcastAddress->Address[0].AddressLength = 0;
+
+ Irp->IoStatus.Information =
+ sizeof (broadcastAddress->TAAddressCount) +
+ sizeof (broadcastAddress->Address[0].AddressType) +
+ sizeof (broadcastAddress->Address[0].AddressLength);
+
+ status = TdiCopyBufferToMdl (
+ (PVOID)broadcastAddress,
+ 0L,
+ Irp->IoStatus.Information,
+ Irp->MdlAddress,
+ 0,
+ &(Irp->IoStatus.Information));
+
+ ExFreePool (broadcastAddress);
+ }
+
+ break;
+
+ case TDI_QUERY_PROVIDER_INFO:
+
+ status = TdiCopyBufferToMdl (
+ &(DeviceContext->Information),
+ 0,
+ sizeof (TDI_PROVIDER_INFO),
+ Irp->MdlAddress,
+ 0,
+ &Irp->IoStatus.Information);
+ break;
+
+ case TDI_QUERY_PROVIDER_STATISTICS:
+
+ //
+ // BUGBUG: This information is probablt available somewhere else.
+ //
+
+ NbfGetMdlChainLength (Irp->MdlAddress, &TargetBufferLength);
+
+ if (TargetBufferLength < sizeof(TDI_PROVIDER_STATISTICS) + ((NBF_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS))) {
+
+ Irp->IoStatus.Information = 0;
+ status = STATUS_BUFFER_OVERFLOW;
+
+ } else {
+
+ ProviderStatistics = ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(TDI_PROVIDER_STATISTICS) +
+ ((NBF_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS)),
+ ' FBN');
+
+ if (ProviderStatistics == NULL) {
+
+ PANIC ("NbfQueryInfo: Cannot allocate provider statistics!\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 7,
+ sizeof(TDI_PROVIDER_STATISTICS),
+ 0);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ NbfStoreProviderStatistics (DeviceContext, ProviderStatistics);
+
+ status = TdiCopyBufferToMdl (
+ (PVOID)ProviderStatistics,
+ 0L,
+ sizeof(TDI_PROVIDER_STATISTICS) +
+ ((NBF_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS)),
+ Irp->MdlAddress,
+ 0,
+ &(Irp->IoStatus.Information));
+
+ ExFreePool (ProviderStatistics);
+ }
+
+ }
+
+ break;
+
+ case TDI_QUERY_SESSION_STATUS:
+
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ case TDI_QUERY_ADAPTER_STATUS:
+
+ NbfGetMdlChainLength (Irp->MdlAddress, &TargetBufferLength);
+
+ //
+ // Determine if this is a local or remote query. It is
+ // local if there is no remote address specific at all,
+ // or if it is equal to our reserved address.
+ //
+
+ RemoteAdapterStatus = FALSE;
+
+ if (query->RequestConnectionInformation != NULL) {
+
+ if (!NbfValidateTdiAddress(
+ query->RequestConnectionInformation->RemoteAddress,
+ query->RequestConnectionInformation->RemoteAddressLength)) {
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+ RemoteAddress = NbfParseTdiAddress(query->RequestConnectionInformation->RemoteAddress, FALSE);
+
+ if (!RemoteAddress) {
+ return STATUS_BAD_NETWORK_PATH;
+ }
+ if (!RtlEqualMemory(
+ RemoteAddress->NetbiosName,
+ DeviceContext->ReservedNetBIOSAddress,
+ NETBIOS_NAME_LENGTH)) {
+
+ RemoteAdapterStatus = TRUE;
+
+ }
+ }
+
+ if (RemoteAdapterStatus) {
+
+ //
+ // We need a request object to keep track of this TDI request.
+ // Attach this request to the device context.
+ //
+
+ status = NbfCreateRequest (
+ Irp, // IRP for this request.
+ DeviceContext, // context.
+ REQUEST_FLAGS_DC, // partial flags.
+ Irp->MdlAddress, // the data to be received.
+ TargetBufferLength, // length of the data.
+ timeout, // do this ourselves here.
+ &tpRequest);
+
+ if (NT_SUCCESS (status)) {
+
+ NbfReferenceDeviceContext ("Remote status", DeviceContext, DCREF_REQUEST);
+ tpRequest->Owner = DeviceContextType;
+
+ //
+ // Allocate a temp buffer to hold our results.
+ //
+
+ tpRequest->ResponseBuffer = ExAllocatePoolWithTag(
+ NonPagedPool,
+ TargetBufferLength,
+ ' FBN');
+
+ if (tpRequest->ResponseBuffer == NULL) {
+
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 12,
+ TargetBufferLength,
+ 0);
+ NbfCompleteRequest (tpRequest, STATUS_INSUFFICIENT_RESOURCES, 0);
+
+ } else {
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
+
+ if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
+ NbfCompleteRequest (tpRequest, STATUS_DEVICE_NOT_READY, 0);
+
+ } else {
+
+ PUCHAR SingleSR;
+ UINT SingleSRLength;
+
+ InsertTailList (
+ &DeviceContext->StatusQueryQueue,
+ &tpRequest->Linkage);
+
+ tpRequest->FrameContext = DeviceContext->UniqueIdentifier | 0x8000;
+ ++DeviceContext->UniqueIdentifier;
+ if (DeviceContext->UniqueIdentifier == 0x8000) {
+ DeviceContext->UniqueIdentifier = 1;
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ //
+ // The request is queued. Now send out the first packet and
+ // start the timer.
+ //
+
+ tpRequest->Retries = DeviceContext->GeneralRetries;
+ tpRequest->BytesWritten = 0;
+
+ //
+ // STATUS_QUERY frames go out as
+ // single-route source routing.
+ //
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SingleSR,
+ &SingleSRLength);
+
+ NbfSendStatusQuery(
+ DeviceContext,
+ tpRequest,
+ &DeviceContext->NetBIOSAddress,
+ SingleSR,
+ SingleSRLength);
+
+ }
+
+ }
+
+ //
+ // As long as the request is created, pend here.
+ // The IRP will complete when the request completes.
+ //
+
+ status = STATUS_PENDING;
+
+ }
+
+ } else {
+
+ //
+ // Local.
+ //
+
+ adapterStatus = ExAllocatePoolWithTag (
+ NonPagedPool,
+ TargetBufferLength,
+ ' FBN');
+
+ if (adapterStatus == NULL) {
+ PANIC("NbfQueryInfo: PANIC! Could not allocate adapter status buffer\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 3,
+ TargetBufferLength,
+ 0);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NbfStoreAdapterStatus (
+ DeviceContext,
+ NULL,
+ 0,
+ adapterStatus);
+
+ NbfStoreNameBuffers (
+ DeviceContext,
+ (PUCHAR)adapterStatus + sizeof(ADAPTER_STATUS),
+ TargetBufferLength - sizeof(ADAPTER_STATUS),
+ 0,
+ &NamesWritten,
+ &TotalNameCount,
+ &Truncated);
+
+ ((PADAPTER_STATUS)adapterStatus)->name_count = (WORD)TotalNameCount;
+
+ BytesWritten = sizeof(ADAPTER_STATUS) + (NamesWritten * sizeof(NAME_BUFFER));
+
+ status = TdiCopyBufferToMdl (
+ adapterStatus,
+ 0,
+ BytesWritten,
+ Irp->MdlAddress,
+ 0,
+ &Irp->IoStatus.Information);
+
+ if (Truncated) {
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+
+ ExFreePool (adapterStatus);
+
+ }
+
+ break;
+
+ case TDI_QUERY_FIND_NAME:
+
+ NbfGetMdlChainLength (Irp->MdlAddress, &TargetBufferLength);
+
+ //
+ // Check that there is a valid Netbios remote address.
+ //
+
+ if (!NbfValidateTdiAddress(
+ query->RequestConnectionInformation->RemoteAddress,
+ query->RequestConnectionInformation->RemoteAddressLength)) {
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+ RemoteAddress = NbfParseTdiAddress(query->RequestConnectionInformation->RemoteAddress, FALSE);
+
+ if (!RemoteAddress) {
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+ //
+ // We need a request object to keep track of this TDI request.
+ // Attach this request to the device context.
+ //
+
+ status = NbfCreateRequest (
+ Irp, // IRP for this request.
+ DeviceContext, // context.
+ REQUEST_FLAGS_DC, // partial flags.
+ Irp->MdlAddress, // the data to be received.
+ TargetBufferLength, // length of the data.
+ timeout, // do this ourselves here.
+ &tpRequest);
+
+ if (NT_SUCCESS (status)) {
+
+ NbfReferenceDeviceContext ("Find name", DeviceContext, DCREF_REQUEST);
+ tpRequest->Owner = DeviceContextType;
+
+ //
+ // Allocate a temp buffer to hold our results.
+ //
+
+ tpRequest->ResponseBuffer = ExAllocatePoolWithTag(
+ NonPagedPool,
+ TargetBufferLength,
+ ' FBN');
+
+ if (tpRequest->ResponseBuffer == NULL) {
+
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 4,
+ TargetBufferLength,
+ 0);
+ NbfCompleteRequest (tpRequest, STATUS_INSUFFICIENT_RESOURCES, 0);
+
+ } else {
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
+
+ if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
+ NbfCompleteRequest (tpRequest, STATUS_DEVICE_NOT_READY, 0);
+
+ } else {
+
+ InsertTailList (
+ &DeviceContext->FindNameQueue,
+ &tpRequest->Linkage);
+
+ tpRequest->FrameContext = DeviceContext->UniqueIdentifier | 0x8000;
+ ++DeviceContext->UniqueIdentifier;
+ if (DeviceContext->UniqueIdentifier == 0x8000) {
+ DeviceContext->UniqueIdentifier = 1;
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ //
+ // The request is queued. Now send out the first packet and
+ // start the timer.
+ //
+ // We fill in the FIND_NAME_HEADER in the buffer, but
+ // set BytesWritten to 0; we don't include the header
+ // in BytesWritten until we get a response, so that
+ // a BytesWritten of 0 means "no response".
+ //
+
+ tpRequest->Retries = DeviceContext->GeneralRetries;
+ tpRequest->BytesWritten = 0;
+ FindNameHeader = (PFIND_NAME_HEADER)tpRequest->ResponseBuffer;
+ FindNameHeader->node_count = 0;
+ FindNameHeader->unique_group = NETBIOS_NAME_TYPE_UNIQUE;
+
+ NbfSendQueryFindName (DeviceContext, tpRequest);
+
+ }
+
+ }
+
+ //
+ // As long as the request is created, pend here.
+ // The IRP will complete when the request completes.
+ //
+
+ status = STATUS_PENDING;
+ }
+
+ break;
+
+ case TDI_QUERY_DATA_LINK_ADDRESS:
+ case TDI_QUERY_NETWORK_ADDRESS:
+
+ TaAddress = (PTRANSPORT_ADDRESS)&AddressInfo.TaAddressBuffer;
+ TaAddress->TAAddressCount = 1;
+ TaAddress->Address[0].AddressLength = 6;
+ if (query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
+ TaAddress->Address[0].AddressType =
+ DeviceContext->MacInfo.MediumAsync ?
+ NdisMediumWan : DeviceContext->MacInfo.MediumType;
+ } else {
+ TaAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_UNSPEC;
+ }
+ RtlCopyMemory (TaAddress->Address[0].Address, DeviceContext->LocalAddress.Address, 6);
+
+ status = TdiCopyBufferToMdl (
+ &AddressInfo.TaAddressBuffer,
+ 0,
+ sizeof(TRANSPORT_ADDRESS)+5,
+ Irp->MdlAddress,
+ 0,
+ &Irp->IoStatus.Information);
+ break;
+
+ case TDI_QUERY_DATAGRAM_INFO:
+
+ DatagramInfo.MaximumDatagramBytes = 0;
+ DatagramInfo.MaximumDatagramCount = 0;
+
+ status = TdiCopyBufferToMdl (
+ &DatagramInfo,
+ 0,
+ sizeof(DatagramInfo),
+ Irp->MdlAddress,
+ 0,
+ &Irp->IoStatus.Information);
+ break;
+
+ default:
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ return status;
+
+} /* NbfTdiQueryInformation */
+
+//
+// Quick macros, assumes DeviceContext and ProviderStatistics exist.
+//
+
+#define STORE_RESOURCE_STATS_1(_ResourceNum,_ResourceId,_ResourceName) \
+{ \
+ PTDI_PROVIDER_RESOURCE_STATS RStats = &ProviderStatistics->ResourceStats[_ResourceNum]; \
+ RStats->ResourceId = (_ResourceId); \
+ RStats->MaximumResourceUsed = DeviceContext->_ResourceName ## MaxInUse; \
+ if (DeviceContext->_ResourceName ## Samples > 0) { \
+ RStats->AverageResourceUsed = DeviceContext->_ResourceName ## Total / DeviceContext->_ResourceName ## Samples; \
+ } else { \
+ RStats->AverageResourceUsed = 0; \
+ } \
+ RStats->ResourceExhausted = DeviceContext->_ResourceName ## Exhausted; \
+}
+
+#define STORE_RESOURCE_STATS_2(_ResourceNum,_ResourceId,_ResourceName) \
+{ \
+ PTDI_PROVIDER_RESOURCE_STATS RStats = &ProviderStatistics->ResourceStats[_ResourceNum]; \
+ RStats->ResourceId = (_ResourceId); \
+ RStats->MaximumResourceUsed = DeviceContext->_ResourceName ## Allocated; \
+ RStats->AverageResourceUsed = DeviceContext->_ResourceName ## Allocated; \
+ RStats->ResourceExhausted = DeviceContext->_ResourceName ## Exhausted; \
+}
+
+
+VOID
+NbfStoreProviderStatistics(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTDI_PROVIDER_STATISTICS ProviderStatistics
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes the TDI_PROVIDER_STATISTICS structure
+ from the device context into ProviderStatistics.
+
+Arguments:
+
+ DeviceContext - a pointer to the device context.
+
+ ProviderStatistics - The buffer that holds the result. It is assumed
+ that it is long enough.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Copy all the statistics up to NumberOfResources
+ // in one move.
+ //
+
+ RtlCopyMemory(
+ ProviderStatistics,
+ &DeviceContext->Statistics,
+ FIELD_OFFSET (TDI_PROVIDER_STATISTICS, NumberOfResources));
+
+ //
+ // Calculate AverageSendWindow.
+ //
+
+ if (DeviceContext->SendWindowSamples > 0) {
+ ProviderStatistics->AverageSendWindow =
+ DeviceContext->SendWindowTotal / DeviceContext->SendWindowSamples;
+ } else {
+ ProviderStatistics->AverageSendWindow = 1;
+ }
+
+ //
+ // Copy the resource statistics.
+ //
+
+ ProviderStatistics->NumberOfResources = NBF_TDI_RESOURCES;
+
+ STORE_RESOURCE_STATS_1 (0, LINK_RESOURCE_ID, Link);
+ STORE_RESOURCE_STATS_1 (1, ADDRESS_RESOURCE_ID, Address);
+ STORE_RESOURCE_STATS_1 (2, ADDRESS_FILE_RESOURCE_ID, AddressFile);
+ STORE_RESOURCE_STATS_1 (3, CONNECTION_RESOURCE_ID, Connection);
+ STORE_RESOURCE_STATS_1 (4, REQUEST_RESOURCE_ID, Request);
+
+ STORE_RESOURCE_STATS_2 (5, UI_FRAME_RESOURCE_ID, UIFrame);
+ STORE_RESOURCE_STATS_2 (6, PACKET_RESOURCE_ID, Packet);
+ STORE_RESOURCE_STATS_2 (7, RECEIVE_PACKET_RESOURCE_ID, ReceivePacket);
+ STORE_RESOURCE_STATS_2 (8, RECEIVE_BUFFER_RESOURCE_ID, ReceiveBuffer);
+
+} /* NbfStoreProviderStatistics */
+
+
+VOID
+NbfStoreAdapterStatus(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN PVOID StatusBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes the ADAPTER_STATUS structure for the
+ device context into StatusBuffer. The name_count field is
+ initialized to zero; NbfStoreNameBuffers is used to write
+ name buffers.
+
+Arguments:
+
+ DeviceContext - a pointer to the device context.
+
+ SourceRouting - If this is a remote request, the source
+ routing information from the frame.
+
+ SourceRoutingLength - The length of SourceRouting.
+
+ StatusBuffer - The buffer that holds the result. It is assumed
+ that it is at least sizeof(ADAPTER_STATUS) bytes long.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PADAPTER_STATUS AdapterStatus = (PADAPTER_STATUS)StatusBuffer;
+ UINT MaxUserData;
+
+ RtlZeroMemory ((PVOID)AdapterStatus, sizeof(ADAPTER_STATUS));
+
+ RtlCopyMemory (AdapterStatus->adapter_address, DeviceContext->LocalAddress.Address, 6);
+ AdapterStatus->rev_major = 0x03;
+
+ switch (DeviceContext->MacInfo.MediumType) {
+ case NdisMedium802_5: AdapterStatus->adapter_type = 0xff; break;
+ default: AdapterStatus->adapter_type = 0xfe; break;
+ }
+
+ AdapterStatus->frmr_recv = (WORD)DeviceContext->FrmrReceived;
+ AdapterStatus->frmr_xmit = (WORD)DeviceContext->FrmrTransmitted;
+
+ AdapterStatus->recv_buff_unavail = (WORD)(DeviceContext->ReceivePacketExhausted + DeviceContext->ReceiveBufferExhausted);
+ AdapterStatus->xmit_buf_unavail = (WORD)DeviceContext->PacketExhausted;
+
+ AdapterStatus->xmit_success = (WORD)(DeviceContext->Statistics.DataFramesSent - DeviceContext->Statistics.DataFramesResent);
+ AdapterStatus->recv_success = (WORD)DeviceContext->Statistics.DataFramesReceived;
+ AdapterStatus->iframe_recv_err = (WORD)DeviceContext->Statistics.DataFramesRejected;
+ AdapterStatus->iframe_xmit_err = (WORD)DeviceContext->Statistics.DataFramesResent;
+
+ AdapterStatus->t1_timeouts = (WORD)DeviceContext->Statistics.ResponseTimerExpirations;
+ AdapterStatus->ti_timeouts = (WORD)DeviceContext->TiExpirations;
+ AdapterStatus->xmit_aborts = (WORD)0;
+
+
+ AdapterStatus->free_ncbs = (WORD)0xffff;
+ AdapterStatus->max_cfg_ncbs = (WORD)0xffff;
+ AdapterStatus->max_ncbs = (WORD)0xffff;
+ AdapterStatus->pending_sess = (WORD)DeviceContext->Statistics.OpenConnections;
+ AdapterStatus->max_cfg_sess = (WORD)0xffff;
+ AdapterStatus->max_sess = (WORD)0xffff;
+
+
+ MacReturnMaxDataSize(
+ &DeviceContext->MacInfo,
+ NULL,
+ 0,
+ DeviceContext->MaxSendPacketSize,
+ TRUE,
+ &MaxUserData);
+ AdapterStatus->max_dgram_size = (WORD)(MaxUserData - (sizeof(DLC_FRAME) + sizeof(NBF_HDR_CONNECTIONLESS)));
+
+ MacReturnMaxDataSize(
+ &DeviceContext->MacInfo,
+ SourceRouting,
+ SourceRoutingLength,
+ DeviceContext->MaxSendPacketSize,
+ FALSE,
+ &MaxUserData);
+ AdapterStatus->max_sess_pkt_size = (WORD)(MaxUserData - (sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION)));
+
+ return;
+
+} /* NbfStoreAdapterStatus */
+
+
+VOID
+NbfStoreNameBuffers(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PVOID Buffer,
+ IN ULONG BufferLength,
+ IN ULONG NamesToSkip,
+ OUT PULONG NamesWritten,
+ OUT PULONG TotalNameCount OPTIONAL,
+ OUT PBOOLEAN Truncated
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes NAME_BUFFER structures for the
+ device context into NameBuffer. It can skip a specified
+ number of names at the beginning, and returns the number
+ of names written into NameBuffer. If a name will only
+ partially fit, it is not written.
+
+Arguments:
+
+ DeviceContext - a pointer to the device context.
+
+ NameBuffer - The buffer to write the names into.
+
+ NameBufferLength - The length of NameBuffer.
+
+ NamesToSkip - The number of names to skip.
+
+ NamesWritten - Returns the number of names written.
+
+ TotalNameCount - Returns the total number of names available,
+ if specified.
+
+ Truncated - More names are available than were written.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG NameCount = 0;
+ ULONG BytesWritten = 0;
+ KIRQL oldirql;
+ PLIST_ENTRY p;
+ PNAME_BUFFER NameBuffer = (PNAME_BUFFER)Buffer;
+ PTP_ADDRESS address;
+
+
+ //
+ // Spin through the address list for this device context.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ p = DeviceContext->AddressDatabase.Flink;
+
+ for (p = DeviceContext->AddressDatabase.Flink;
+ p != &DeviceContext->AddressDatabase;
+ p = p->Flink) {
+
+ address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+
+ //
+ // Ignore addresses that are shutting down.
+ //
+
+ if ((address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ continue;
+ }
+
+ //
+ // Ignore the broadcast address.
+ //
+
+ if (address->NetworkName == NULL) {
+ continue;
+ }
+
+ //
+ // Ignore the reserved address.
+ //
+
+ if ((address->NetworkName->NetbiosName[0] == 0) &&
+ (RtlEqualMemory(
+ address->NetworkName->NetbiosName,
+ DeviceContext->ReservedNetBIOSAddress,
+ NETBIOS_NAME_LENGTH))) {
+
+ continue;
+ }
+
+ //
+ // Check if we are still skipping.
+ //
+
+ if (NameCount < NamesToSkip) {
+ ++NameCount;
+ continue;
+ }
+
+ //
+ // Make sure we still have room.
+ //
+
+ if (BytesWritten + sizeof(NAME_BUFFER) > BufferLength) {
+ break;
+ }
+
+ RtlCopyMemory(
+ NameBuffer->name,
+ address->NetworkName->NetbiosName,
+ NETBIOS_NAME_LENGTH);
+
+ ++NameCount;
+ NameBuffer->name_num = (UCHAR)NameCount;
+
+ NameBuffer->name_flags = REGISTERED;
+ if (address->Flags & ADDRESS_FLAGS_GROUP) {
+ NameBuffer->name_flags |= GROUP_NAME;
+ }
+
+ // BUGBUG: name_flags should be done more accurately.
+
+ BytesWritten += sizeof(NAME_BUFFER);
+ ++NameBuffer;
+
+ }
+
+ *NamesWritten = NameBuffer - (PNAME_BUFFER)Buffer;
+
+ if (p == &DeviceContext->AddressDatabase) {
+
+ *Truncated = FALSE;
+ if (ARGUMENT_PRESENT(TotalNameCount)) {
+ *TotalNameCount = NameCount;
+ }
+
+ } else {
+
+ *Truncated = TRUE;
+
+ //
+ // If requested, continue through the list and count
+ // all the addresses.
+ //
+
+ if (ARGUMENT_PRESENT(TotalNameCount)) {
+
+ for ( ;
+ p != &DeviceContext->AddressDatabase;
+ p = p->Flink) {
+
+ address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+
+ //
+ // Ignore addresses that are shutting down.
+ //
+
+ if ((address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ continue;
+ }
+
+ //
+ // Ignore the broadcast address.
+ //
+
+ if (address->NetworkName == NULL) {
+ continue;
+ }
+
+ //
+ // Ignore the reserved address, since we count it no matter what.
+ //
+
+ if ((address->NetworkName->NetbiosName[0] == 0) &&
+ (RtlEqualMemory(
+ address->NetworkName->NetbiosName,
+ DeviceContext->ReservedNetBIOSAddress,
+ NETBIOS_NAME_LENGTH))) {
+
+ continue;
+ }
+
+ ++NameCount;
+
+ }
+
+ *TotalNameCount = NameCount;
+
+ }
+
+ }
+
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ return;
+
+} /* NbfStoreNameBuffers */
+
+
+NTSTATUS
+NbfProcessStatusQuery(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address OPTIONAL,
+ IN PNBF_HDR_CONNECTIONLESS UiFrame,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a STATUS.QUERY packet.
+
+Arguments:
+
+ DeviceContext - a pointer to the device context the frame was received on.
+
+ Address - The address we are responding from, or NULL if the STATUS.QUERY
+ was sent to the reserved address.
+
+ UiFrame - The packet in question, starting at the Netbios header.
+
+ SourceAddress - The source hardware address of the packet.
+
+ SourceRouting - Source routing data in the query.
+
+ SourceRoutingLength - The length of SourceRouting.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ NDIS_STATUS NdisStatus;
+ PTP_UI_FRAME RawFrame;
+ PVOID ResponseBuffer;
+ UINT ResponseBufferLength;
+ ULONG NamesWritten, TotalNameCount;
+ ULONG BytesWritten;
+ UCHAR RequestType;
+ BOOLEAN Truncated, UsersBufferTooShort;
+ USHORT UsersBufferLength;
+ UINT HeaderLength;
+ UCHAR TempSR[MAX_SOURCE_ROUTING];
+ PUCHAR ResponseSR;
+ PNDIS_BUFFER NdisBuffer;
+
+ //
+ // Allocate a buffer to hold the status.
+ //
+
+ MacReturnMaxDataSize(
+ &DeviceContext->MacInfo,
+ SourceRouting,
+ SourceRoutingLength,
+ DeviceContext->CurSendPacketSize,
+ FALSE,
+ &ResponseBufferLength);
+
+ ResponseBufferLength -= (sizeof(DLC_FRAME) + sizeof(NBF_HDR_CONNECTIONLESS));
+
+ UsersBufferLength = (UiFrame->Data2High * 256) + UiFrame->Data2Low;
+
+ //
+ // See how big to make our buffer; if the amount remaining in the user's
+ // buffer is less than our max size, chop it down.
+ //
+
+ if (UiFrame->Data1 <= 1) {
+
+ //
+ // This is the initial request.
+ //
+
+ if (ResponseBufferLength > (UINT)UsersBufferLength) {
+ ResponseBufferLength = UsersBufferLength;
+ }
+
+ } else {
+
+ //
+ // Subsequent request; compensate for already-sent data.
+ //
+
+ UsersBufferLength -= (sizeof(ADAPTER_STATUS) + (UiFrame->Data1 * sizeof(NAME_BUFFER)));
+
+ if (ResponseBufferLength > (UINT)UsersBufferLength) {
+ ResponseBufferLength = UsersBufferLength;
+ }
+
+ }
+
+ //
+ // If the remote station is asking for no data, ignore this request.
+ // This prevents us from trying to allocate 0 bytes of pool.
+ //
+
+ if ( (LONG)ResponseBufferLength <= 0 ) {
+ return STATUS_ABANDONED;
+ }
+
+ ResponseBuffer = ExAllocatePoolWithTag(
+ NonPagedPool,
+ ResponseBufferLength,
+ ' FBN');
+
+ if (ResponseBuffer == NULL) {
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 5,
+ ResponseBufferLength,
+ 0);
+ return STATUS_ABANDONED;
+ }
+
+
+ //
+ // Fill in the response buffer.
+ //
+
+ if (UiFrame->Data1 <= 1) {
+
+ //
+ // First request.
+ //
+
+ NbfStoreAdapterStatus (
+ DeviceContext,
+ SourceRouting,
+ SourceRoutingLength,
+ ResponseBuffer);
+
+ NbfStoreNameBuffers (
+ DeviceContext,
+ (PUCHAR)ResponseBuffer + sizeof(ADAPTER_STATUS),
+ ResponseBufferLength - sizeof(ADAPTER_STATUS),
+ 0,
+ &NamesWritten,
+ &TotalNameCount,
+ &Truncated);
+
+ BytesWritten = sizeof(ADAPTER_STATUS) + (NamesWritten * sizeof(NAME_BUFFER));
+
+ //
+ // If the data was truncated, but we are returning the maximum
+ // that the user requested, report that as "user's buffer
+ // too short" instead of "truncated".
+ //
+
+ if (Truncated && (ResponseBufferLength >= (UINT)UsersBufferLength)) {
+ Truncated = FALSE;
+ UsersBufferTooShort = TRUE;
+ } else {
+ UsersBufferTooShort = FALSE;
+ }
+
+ ((PADAPTER_STATUS)ResponseBuffer)->name_count = (WORD)TotalNameCount;
+
+ } else {
+
+ NbfStoreNameBuffers (
+ DeviceContext,
+ ResponseBuffer,
+ ResponseBufferLength,
+ UiFrame->Data1,
+ &NamesWritten,
+ NULL,
+ &Truncated);
+
+ BytesWritten = NamesWritten * sizeof(NAME_BUFFER);
+
+ if (Truncated && (ResponseBufferLength >= (UINT)UsersBufferLength)) {
+ Truncated = FALSE;
+ UsersBufferTooShort = TRUE;
+ } else {
+ UsersBufferTooShort = FALSE;
+ }
+
+ }
+
+ //
+ // Allocate a UI frame from the pool.
+ //
+
+ Status = NbfCreateConnectionlessFrame (DeviceContext, &RawFrame);
+ if (!NT_SUCCESS (Status)) { // couldn't make frame.
+ ExFreePool (ResponseBuffer);
+ return STATUS_ABANDONED;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_DEVCTX) {
+ NbfPrint2 ("NbfProcessStatusQuery: Sending Frame: %lx, NdisPacket: %lx\n",
+ RawFrame, RawFrame->NdisPacket);
+ }
+
+
+ //
+ // Build the MAC header. STATUS_RESPONSE frames go out as
+ // non-broadcast source routing.
+ //
+
+ if (SourceRouting != NULL) {
+
+ RtlCopyMemory(
+ TempSR,
+ SourceRouting,
+ SourceRoutingLength);
+
+ MacCreateNonBroadcastReplySR(
+ &DeviceContext->MacInfo,
+ TempSR,
+ SourceRoutingLength,
+ &ResponseSR);
+
+ } else {
+
+ ResponseSR = NULL;
+
+ }
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ RawFrame->Header,
+ SourceAddress->Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS) + BytesWritten,
+ ResponseSR,
+ SourceRoutingLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // Build the Netbios header.
+ //
+
+ switch (UiFrame->Data1) {
+ case 0: // pre 2.1 request
+ RequestType = (UCHAR)0;
+ break;
+ case 1: // 2.1, first request
+ RequestType = (UCHAR)NamesWritten;
+ break;
+ default: // 2.1, subsequent request
+ RequestType = (UCHAR)(UiFrame->Data1 + NamesWritten);
+ break;
+ }
+
+ ConstructStatusResponse (
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ RequestType, // request type.
+ Truncated, // more data.
+ UsersBufferTooShort, // user's buffer too small
+ (USHORT)BytesWritten, // bytes in response
+ RESPONSE_CORR(UiFrame), // correlator
+ UiFrame->SourceName, // receiver permanent name
+ (ARGUMENT_PRESENT(Address)) ?
+ Address->NetworkName->NetbiosName :
+ DeviceContext->ReservedNetBIOSAddress); // source name
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+
+
+ //
+ // Munge the packet length (now, before we append the second
+ // buffer).
+ //
+
+ NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
+
+
+ //
+ // Now, if we have any name data, attach our buffer onto the frame.
+ // Note that it's possible at the end of the user's buffer for us
+ // to not have room for any names, and thus we'll have no data to
+ // send.
+ //
+
+ if ( BytesWritten != 0 ) {
+
+ RawFrame->DataBuffer = ResponseBuffer;
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ DeviceContext->NdisBufferPool,
+ ResponseBuffer,
+ BytesWritten);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ PANIC ("ConstructStatusResponse: NdisAllocateBuffer failed.\n");
+ NbfDestroyConnectionlessFrame (DeviceContext, RawFrame);
+ return STATUS_ABANDONED;
+ }
+
+ NdisChainBufferAtBack (RawFrame->NdisPacket, NdisBuffer);
+
+ } else {
+
+ RawFrame->DataBuffer = NULL;
+
+ }
+
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ FALSE); // no loopback (MC frame)
+
+ return STATUS_ABANDONED;
+
+} /* NbfProcessStatusQuery */
+
+
+VOID
+NbfSendQueryFindName(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_REQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will send a FIND.NAME packet for the specified
+ find name request, and start the request timer.
+
+Arguments:
+
+ DeviceContext - a pointer to the device context to send the find name on.
+
+ Request - The find name request.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ TDI_ADDRESS_NETBIOS UNALIGNED * remoteAddress;
+ PIO_STACK_LOCATION irpSp;
+ NTSTATUS Status;
+ PTP_UI_FRAME RawFrame;
+ PUCHAR SingleSR;
+ UINT SingleSRLength;
+ UINT HeaderLength;
+ LARGE_INTEGER Timeout;
+
+ irpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket);
+
+ remoteAddress = NbfParseTdiAddress(
+ ((PTDI_REQUEST_KERNEL_QUERY_INFORMATION)(&irpSp->Parameters))->
+ RequestConnectionInformation->RemoteAddress, FALSE);
+
+ //
+ // Start the timer for this request.
+ //
+
+ Request->Flags |= REQUEST_FLAGS_TIMER; // there is a timeout on this request.
+ KeInitializeTimer (&Request->Timer); // set to not-signaled state.
+ NbfReferenceRequest ("Find Name: timer", Request, RREF_TIMER); // one for the timer
+ Timeout.LowPart = (ULONG)(-(LONG)DeviceContext->GeneralTimeout);
+ Timeout.HighPart = -1;
+ KeSetTimer (&Request->Timer, Timeout, &Request->Dpc);
+
+ //
+ // Allocate a UI frame from the pool.
+ //
+
+ Status = NbfCreateConnectionlessFrame (DeviceContext, &RawFrame);
+ if (!NT_SUCCESS (Status)) { // couldn't make frame.
+ return;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_DEVCTX) {
+ NbfPrint2 ("NbfSendFindNames: Sending Frame: %lx, NdisPacket: %lx\n",
+ RawFrame, RawFrame->NdisPacket);
+ }
+
+
+ //
+ // Build the MAC header. NAME_QUERY frames go out as
+ // single-route source routing.
+ //
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SingleSR,
+ &SingleSRLength);
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ RawFrame->Header,
+ DeviceContext->NetBIOSAddress.Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS),
+ SingleSR,
+ SingleSRLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // Build the Netbios header.
+ //
+
+ ConstructNameQuery (
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ NETBIOS_NAME_TYPE_UNIQUE, // call from a unique name.
+ NAME_QUERY_LSN_FIND_NAME, // LSN
+ Request->FrameContext, // corr. in 1st NAME_RECOGNIZED.
+ DeviceContext->ReservedNetBIOSAddress,
+ (PNAME)remoteAddress->NetbiosName);
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+
+
+ //
+ // Munge the packet length.
+ //
+
+ NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ FALSE); // no loopback (MC frame)
+
+} /* NbfSendQueryFindName */
+
+
+NTSTATUS
+NbfProcessQueryNameRecognized(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR Packet,
+ PNBF_HDR_CONNECTIONLESS UiFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a NAME.RECOGNIZED request with a
+ correlator of 0, indicating it was a response to a previous
+ FIND.NAME packet.
+
+Arguments:
+
+ DeviceContext - a pointer to the device context the frame was received on.
+
+ Packet - The packet in question, starting at the MAC header.
+
+ UiFrame - The packet, starting at the Netbios header.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ KIRQL oldirql;
+ PTP_REQUEST Request;
+ PFIND_NAME_BUFFER FindNameBuffer;
+ PFIND_NAME_HEADER FindNameHeader;
+ PUCHAR DestinationAddress;
+ HARDWARE_ADDRESS SourceAddressBuffer;
+ PHARDWARE_ADDRESS SourceAddress;
+ PUCHAR SourceRouting;
+ UINT SourceRoutingLength;
+ PUCHAR TargetBuffer;
+ USHORT FrameContext;
+ PLIST_ENTRY p;
+
+
+ MacReturnDestinationAddress(
+ &DeviceContext->MacInfo,
+ Packet,
+ &DestinationAddress);
+
+ MacReturnSourceAddress(
+ &DeviceContext->MacInfo,
+ Packet,
+ &SourceAddressBuffer,
+ &SourceAddress,
+ NULL);
+
+ MacReturnSourceRouting(
+ &DeviceContext->MacInfo,
+ Packet,
+ &SourceRouting,
+ &SourceRoutingLength);
+
+ //
+ // Find the request that this is for, using the frame context.
+ //
+
+ FrameContext = TRANSMIT_CORR(UiFrame);
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ for (p=DeviceContext->FindNameQueue.Flink;
+ p != &DeviceContext->FindNameQueue;
+ p=p->Flink) {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+
+ if (Request->FrameContext == FrameContext) {
+
+ break;
+
+ }
+
+ }
+
+ if (p == &DeviceContext->FindNameQueue) {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ return STATUS_SUCCESS;
+
+ }
+
+ NbfReferenceRequest ("Name Recognized", Request, RREF_FIND_NAME);
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ //
+ // Make sure that this physical address has not
+ // responded yet.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql);
+
+ //
+ // Make sure this request is not stopping.
+ //
+
+ if ((Request->Flags & REQUEST_FLAGS_STOPPING) != 0) {
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ NbfDereferenceRequest ("Stopping", Request, RREF_STATUS);
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // If this is the first response, update BytesWritten to include
+ // the header that is already written in ResponseBuffer.
+ //
+
+ if (Request->BytesWritten == 0) {
+ Request->BytesWritten = sizeof(FIND_NAME_HEADER);
+ }
+
+ TargetBuffer = Request->ResponseBuffer;
+ FindNameBuffer = (PFIND_NAME_BUFFER)(TargetBuffer + sizeof(FIND_NAME_HEADER));
+
+ for ( ; FindNameBuffer < (PFIND_NAME_BUFFER)(TargetBuffer + Request->BytesWritten); FindNameBuffer++) {
+
+ if (RtlEqualMemory (FindNameBuffer->source_addr, SourceAddress->Address, 6)) {
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ NbfDereferenceRequest ("Duplicate NR", Request, RREF_FIND_NAME);
+ return STATUS_SUCCESS;
+
+ }
+
+ }
+
+ //
+ // This is a new address, update if there is room.
+ //
+
+ if ((Request->BytesWritten + sizeof(FIND_NAME_BUFFER)) >
+ Request->Buffer2Length) {
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
+ RemoveEntryList (&Request->Linkage);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ NbfCompleteRequest (Request, STATUS_SUCCESS, Request->BytesWritten);
+ NbfDereferenceRequest ("No Buffer", Request, RREF_FIND_NAME);
+ return STATUS_SUCCESS;
+
+ }
+
+ FindNameHeader = (PFIND_NAME_HEADER)TargetBuffer;
+ FindNameHeader->unique_group = UiFrame->Data2High;
+
+ Request->BytesWritten += sizeof(FIND_NAME_BUFFER);
+ ++FindNameHeader->node_count;
+
+ RtlCopyMemory(FindNameBuffer->source_addr, SourceAddress->Address, 6);
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+
+ RtlCopyMemory(FindNameBuffer->destination_addr, DestinationAddress, 6);
+ FindNameBuffer->length = 14;
+
+ if (DeviceContext->MacInfo.MediumType == NdisMedium802_5) {
+
+ //
+ // token-ring, copy the correct fields.
+ //
+
+ FindNameBuffer->access_control = Packet[0];
+ FindNameBuffer->frame_control = Packet[1];
+
+ if (SourceRouting != NULL) {
+ RtlCopyMemory (FindNameBuffer->routing_info, SourceRouting, SourceRoutingLength);
+ FindNameBuffer->length += SourceRoutingLength;
+ }
+
+ } else {
+
+ //
+ // non-token-ring, nothing else is significant.
+ //
+
+ FindNameBuffer->access_control = 0x0;
+ FindNameBuffer->frame_control = 0x0;
+
+ }
+
+
+ //
+ // If this is a unique name, complete the request now.
+ //
+
+ if (UiFrame->Data2High == NETBIOS_NAME_TYPE_UNIQUE) {
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
+ RemoveEntryList (&Request->Linkage);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ NbfCompleteRequest(Request, STATUS_SUCCESS, Request->BytesWritten);
+
+ }
+
+ NbfDereferenceRequest ("NR processed", Request, RREF_FIND_NAME);
+ return STATUS_SUCCESS;
+
+} /* NbfProcessQueryNameRecognized */
+
+
+VOID
+NbfSendStatusQuery(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_REQUEST Request,
+ IN PHARDWARE_ADDRESS DestinationAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will send a STATUS.NAME packet for the specified
+ find name request, and start the request timer.
+
+Arguments:
+
+ DeviceContext - a pointer to the device context to send the status query on.
+
+ Request - The find name request.
+
+ DestinationAddress - The hardware destination address of the frame.
+
+ SourceRouting - Optional source routing information in the frame.
+
+ SourceRoutingLength - The length of SourceRouting.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ TDI_ADDRESS_NETBIOS UNALIGNED * remoteAddress;
+ PIO_STACK_LOCATION irpSp;
+ NTSTATUS Status;
+ PTP_UI_FRAME RawFrame;
+ PUCHAR SingleSR;
+ UINT SingleSRLength;
+ UINT HeaderLength;
+ LARGE_INTEGER Timeout;
+ UCHAR RequestType;
+
+ irpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket);
+
+ remoteAddress = NbfParseTdiAddress(
+ ((PTDI_REQUEST_KERNEL_QUERY_INFORMATION)(&irpSp->Parameters))->
+ RequestConnectionInformation->RemoteAddress, FALSE);
+
+ //
+ // Start the timer for this request.
+ //
+
+ Request->Flags |= REQUEST_FLAGS_TIMER; // there is a timeout on this request.
+ KeInitializeTimer (&Request->Timer); // set to not-signaled state.
+ NbfReferenceRequest ("Find Name: timer", Request, RREF_TIMER); // one for the timer
+ Timeout.LowPart = (ULONG)(-(LONG)DeviceContext->GeneralTimeout);
+ Timeout.HighPart = -1;
+ KeSetTimer (&Request->Timer, Timeout, &Request->Dpc);
+
+ //
+ // Allocate a UI frame from the pool.
+ //
+
+ Status = NbfCreateConnectionlessFrame (DeviceContext, &RawFrame);
+ if (!NT_SUCCESS (Status)) { // couldn't make frame.
+ return;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_DEVCTX) {
+ NbfPrint2 ("NbfSendFindNames: Sending Frame: %lx, NdisPacket: %lx\n",
+ RawFrame, RawFrame->NdisPacket);
+ }
+
+
+ //
+ // Build the MAC header. STATUS_QUERY frames go out as
+ // single-route source routing.
+ //
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SingleSR,
+ &SingleSRLength);
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ RawFrame->Header,
+ DeviceContext->NetBIOSAddress.Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS),
+ SingleSR,
+ SingleSRLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // Build the Netbios header.
+ //
+
+ //
+ // Determine what RequestType should be.
+ //
+
+ if (Request->BytesWritten == 0) {
+
+ //
+ // No way to know if he is 2.1 or not, so we put a 1 here
+ // instead of 0.
+ //
+
+ RequestType = 1;
+
+ } else {
+
+ RequestType = (UCHAR)((Request->BytesWritten - sizeof(ADAPTER_STATUS)) / sizeof(NAME_BUFFER));
+
+ }
+
+ ConstructStatusQuery (
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ RequestType, // request status type.
+ (USHORT)Request->Buffer2Length, // user's buffer length
+ Request->FrameContext, // corr. in 1st NAME_RECOGNIZED.
+ (PNAME)remoteAddress->NetbiosName,
+ DeviceContext->ReservedNetBIOSAddress);
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+
+
+ //
+ // Munge the packet length.
+ //
+
+ NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ FALSE); // no loopback (MC frame)
+
+} /* NbfSendStatusQuery */
+
+
+NTSTATUS
+NbfProcessStatusResponse(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PNBF_HDR_CONNECTIONLESS UiFrame,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a STATUS.RESPONSE packet.
+
+Arguments:
+
+ DeviceContext - a pointer to the device context the frame was received on.
+
+ ReceiveContext - The context for calling NdisTransferData.
+
+ UiFrame - The packet in question, starting at the Netbios header.
+
+ SourceAddress - The source hardware address of the packet.
+
+ SourceRouting - Source routing data in the query.
+
+ SourceRoutingLength - The length of SourceRouting.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ KIRQL oldirql;
+ PTP_REQUEST Request;
+ PUCHAR TargetBuffer;
+ USHORT FrameContext;
+ USHORT NamesReceived;
+ USHORT ResponseLength, ResponseBytesToCopy;
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY linkage;
+ NDIS_STATUS ndisStatus;
+ PNDIS_BUFFER NdisBuffer;
+ PNDIS_PACKET ndisPacket;
+ ULONG ndisBytesTransferred;
+ PRECEIVE_PACKET_TAG receiveTag;
+ NDIS_STATUS NdisStatus;
+
+
+ //
+ // Find the request that this is for, using the frame context.
+ //
+
+ FrameContext = TRANSMIT_CORR(UiFrame);
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ for (p=DeviceContext->StatusQueryQueue.Flink;
+ p != &DeviceContext->StatusQueryQueue;
+ p=p->Flink) {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+
+ if (Request->FrameContext == FrameContext) {
+
+ break;
+
+ }
+
+ }
+
+ if (p == &DeviceContext->StatusQueryQueue) {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ return STATUS_SUCCESS;
+
+ }
+
+ NbfReferenceRequest ("Status Response", Request, RREF_STATUS);
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql);
+
+ //
+ // Make sure this request is not stopping.
+ //
+
+ if ((Request->Flags & REQUEST_FLAGS_STOPPING) != 0) {
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ NbfDereferenceRequest ("Stopping", Request, RREF_STATUS);
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // See if this is packet has new data.
+ //
+
+ if (Request->BytesWritten == 0) {
+
+ NamesReceived = 0;
+
+ } else {
+
+ NamesReceived = (USHORT)(Request->BytesWritten - sizeof(ADAPTER_STATUS)) / sizeof(NAME_BUFFER);
+
+ }
+
+ if ((UiFrame->Data1 > 0) && (UiFrame->Data1 <= NamesReceived)) {
+
+ //
+ // If it is a post-2.1 response, but we already got
+ // this data, ignore it.
+ //
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ NbfDereferenceRequest ("Duplicate SR", Request, RREF_STATUS);
+ return STATUS_SUCCESS;
+
+ }
+
+
+ //
+ // This is new data, append if there is room.
+ //
+
+ ResponseLength = ((UiFrame->Data2High & 0x3f) * 256) + UiFrame->Data2Low;
+
+ if ((ULONG)(Request->BytesWritten + ResponseLength) >
+ Request->Buffer2Length) {
+
+ ResponseBytesToCopy = (USHORT)(Request->Buffer2Length - Request->BytesWritten);
+
+ } else {
+
+ ResponseBytesToCopy = ResponseLength;
+
+ }
+
+ //
+ // Allocate a receive packer for this operation.
+ //
+
+ linkage = ExInterlockedPopEntryList(
+ &DeviceContext->ReceivePacketPool,
+ &DeviceContext->Interlock);
+
+ if (linkage != NULL) {
+ ndisPacket = CONTAINING_RECORD( linkage, NDIS_PACKET, ProtocolReserved[0] );
+ } else {
+
+ //
+ // Could not get a packet, oh well, it is connectionless.
+ //
+
+ DeviceContext->ReceivePacketExhausted++;
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ return STATUS_SUCCESS;
+ }
+
+ receiveTag = (PRECEIVE_PACKET_TAG)(ndisPacket->ProtocolReserved);
+ receiveTag->PacketType = TYPE_STATUS_RESPONSE;
+ receiveTag->Connection = (PTP_CONNECTION)Request;
+
+ TargetBuffer = (PUCHAR)Request->ResponseBuffer + Request->BytesWritten;
+
+ //
+ // Allocate an MDL to describe the part of the buffer we
+ // want transferred.
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ DeviceContext->NdisBufferPool,
+ TargetBuffer,
+ ResponseBytesToCopy);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceivePacketPool,
+ linkage,
+ &DeviceContext->Interlock);
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Assume success, if not we fail the request.
+ //
+
+ Request->BytesWritten += ResponseBytesToCopy;
+
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+
+ NdisChainBufferAtFront(ndisPacket, NdisBuffer);
+
+ //
+ // See if the response was too big (we can complete the
+ // request here since we still reference it).
+ //
+
+ if ((ResponseLength > ResponseBytesToCopy) ||
+ (UiFrame->Data2High & 0x40)) {
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
+ RemoveEntryList (&Request->Linkage);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ receiveTag->CompleteReceive = TRUE;
+ receiveTag->EndOfMessage = FALSE;
+
+ } else {
+
+ //
+ // If we are done, complete the packet, otherwise send off
+ // the next request (unless it is a pre-2.1 response).
+ //
+
+ if ((UiFrame->Data1 > 0) && (UiFrame->Data2High & 0x80)) {
+
+ UCHAR TempSR[MAX_SOURCE_ROUTING];
+ PUCHAR ResponseSR;
+
+ receiveTag->CompleteReceive = FALSE;
+
+ //
+ // Try to cancel the timer, no harm if we fail.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql);
+ if ((Request->Flags & REQUEST_FLAGS_TIMER) != 0) {
+
+ Request->Flags &= ~REQUEST_FLAGS_TIMER;
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ if (KeCancelTimer (&Request->Timer)) {
+ NbfDereferenceRequest ("Status Response: stop timer", Request, RREF_TIMER);
+ }
+
+ } else {
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ }
+
+ Request->Retries = DeviceContext->GeneralRetries;
+
+ //
+ // Send a STATUS_QUERY directed.
+ //
+
+ if (SourceRouting != NULL) {
+
+ RtlCopyMemory(
+ TempSR,
+ SourceRouting,
+ SourceRoutingLength);
+
+ MacCreateNonBroadcastReplySR(
+ &DeviceContext->MacInfo,
+ TempSR,
+ SourceRoutingLength,
+ &ResponseSR);
+
+ } else {
+
+ ResponseSR = NULL;
+
+ }
+
+ NbfSendStatusQuery(
+ DeviceContext,
+ Request,
+ SourceAddress,
+ ResponseSR,
+ SourceRoutingLength);
+
+ } else {
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
+ RemoveEntryList (&Request->Linkage);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ receiveTag->CompleteReceive = TRUE;
+ receiveTag->EndOfMessage = TRUE;
+
+ }
+
+ }
+
+ //
+ // Now do the actual data transfer.
+ //
+
+ NdisTransferData (
+ &ndisStatus,
+ DeviceContext->NdisBindingHandle,
+ ReceiveContext,
+ DeviceContext->MacInfo.TransferDataOffset +
+ 3 + sizeof(NBF_HDR_CONNECTIONLESS),
+ ResponseBytesToCopy,
+ ndisPacket,
+ (PUINT)&ndisBytesTransferred);
+
+ if (ndisStatus != NDIS_STATUS_PENDING) {
+
+ NbfTransferDataComplete(
+ (NDIS_HANDLE)DeviceContext,
+ ndisPacket,
+ ndisStatus,
+ ndisBytesTransferred);
+
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbfProcessStatusResponse */
+
+
+NTSTATUS
+NbfTdiSetInformation(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetInformation request for the transport
+ provider.
+
+Arguments:
+
+ Irp - the Irp for the requested operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (Irp); // prevent compiler warnings
+
+ return STATUS_NOT_IMPLEMENTED;
+
+} /* NbfTdiQueryInformation */
+
+#if 0
+
+NTSTATUS
+NbfQueryInfoEndpoint(
+ IN PTP_ENDPOINT Endpoint,
+ IN PTDI_REQ_QUERY_INFORMATION TdiRequest,
+ IN ULONG TdiRequestLength,
+ OUT PTDI_ENDPOINT_INFO InfoBuffer,
+ IN ULONG InfoBufferLength,
+ OUT PULONG InformationSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns information for the specified endpoint.
+
+Arguments:
+
+ Endpoint - Pointer to transport endpoint context.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+ InfoBuffer - Pointer to output buffer to return information into.
+
+ InfoBufferLength - Length of output buffer.
+
+ InformationSize - Pointer to ulong where actual size of returned
+ information is to be stored.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+
+ TdiRequest, TdiRequestLength; // prevent compiler warnings
+
+ if (InfoBufferLength < sizeof (TDI_ENDPOINT_INFO)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ ACQUIRE_SPIN_LOCK (&Endpoint->SpinLock, &oldirql);
+
+ *InfoBuffer = Endpoint->Information; // structure copy.
+
+ RELEASE_SPIN_LOCK (&Endpoint->SpinLock, oldirql);
+
+ *InformationSize = sizeof (Endpoint->Information);
+
+ return STATUS_SUCCESS;
+} /* NbfQueryInfoEndpoint */
+
+
+NTSTATUS
+NbfQueryInfoConnection(
+ IN PTP_CONNECTION Connection,
+ IN PTDI_REQUEST_KERNEL TdiRequest,
+ IN ULONG TdiRequestLength,
+ OUT PTDI_CONNECTION_INFO InfoBuffer,
+ IN ULONG InfoBufferLength,
+ OUT PULONG InformationSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns information for the specified connection.
+
+Arguments:
+
+ Connection - Pointer to transport connection object.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+ InfoBuffer - Pointer to output buffer to return information into.
+
+ InfoBufferLength - Length of output buffer.
+
+ InformationSize - Pointer to ulong where actual size of returned
+ information is to be stored.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+
+ TdiRequest, TdiRequestLength; // prevent compiler warnings
+
+ if (InfoBufferLength < sizeof (TDI_CONNECTION_INFO)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ ACQUIRE_C_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ *InfoBuffer = Connection->Information; // structure copy.
+
+ RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ *InformationSize = sizeof (Connection->Information);
+
+ return STATUS_SUCCESS;
+} /* NbfQueryInfoConnection */
+
+
+NTSTATUS
+NbfQueryInfoAddress(
+ IN PTP_ADDRESS Address,
+ IN PTDI_REQUEST_KERNEL TdiRequest,
+ IN ULONG TdiRequestLength,
+ OUT PTDI_ADDRESS_INFO InfoBuffer,
+ IN ULONG InfoBufferLength,
+ OUT PULONG InformationSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns information for the specified address. We
+ don't acquire a spinlock in this routine because there are no statistics
+ which must be read atomically.
+
+Arguments:
+
+ Address - Pointer to transport address object.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+ InfoBuffer - Pointer to output buffer to return information into.
+
+ InfoBufferLength - Length of output buffer.
+
+ InformationSize - Pointer to ulong where actual size of returned
+ information is to be stored.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ SHORT i;
+ PSZ p, q;
+
+ TdiRequest, TdiRequestLength; // prevent compiler warnings
+
+ //
+ // Calculate whether his buffer is big enough to return the entire
+ // information. The total size of the address information is the
+ // size of the fixed part, plus the size of the variable-length flat
+ // string in the NETWORK_NAME component of the TRANSPORT_ADDRESS
+ // component.
+ //
+
+ if (InfoBufferLength <
+ sizeof (TDI_ADDRESS_INFO) +
+ Address->NetworkName.Length)
+ {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Copy both the fixed part of the address information, and the variable
+ // part. The variable part comes from the NETWORK_NAME component of the
+ // TRANSPORT_ADDRESS structure. This component contains a FLAT_STRING,
+ // which is of variable length.
+ //
+
+ InfoBuffer->Address.AddressComponents = Address->AddressComponents;
+ InfoBuffer->Address.Tsap = Address->Tsap;
+
+ InfoBuffer->Address.NetworkName.Name.Length =
+ Address->NetworkName.Length;
+
+ p = Address->NetworkName.Buffer; // p = ptr, source string.
+ q = InfoBuffer->Address.NetworkName.Name.Buffer; // q = ptr, dest string.
+ for (i=0; i<InfoBuffer->Address.NetworkName.Name.Length; i++) {
+ *(q++) = *(p++);
+ }
+
+ *InformationSize = sizeof (TDI_ADDRESS_INFO) +
+ Address->NetworkName.Length;
+
+ return STATUS_SUCCESS;
+} /* NbfQueryInfoAddress */
+
+
+NTSTATUS
+NbfQueryInfoProvider(
+ IN PDEVICE_CONTEXT Provider,
+ IN PTDI_REQUEST_KERNEL TdiRequest,
+ IN ULONG TdiRequestLength,
+ OUT PTDI_PROVIDER_INFO InfoBuffer,
+ IN ULONG InfoBufferLength,
+ OUT PULONG InformationSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns information for the transport provider.
+
+Arguments:
+
+ Provider - Pointer to device context for provider.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+ InfoBuffer - Pointer to output buffer to return information into.
+
+ InfoBufferLength - Length of output buffer.
+
+ InformationSize - Pointer to ulong where actual size of returned
+ information is to be stored.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+
+ TdiRequest, TdiRequestLength; // prevent compiler warnings
+
+ if (InfoBufferLength < sizeof (TDI_PROVIDER_INFO)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ ACQUIRE_SPIN_LOCK (&Provider->SpinLock, &oldirql);
+
+ *InfoBuffer = Provider->Information; // structure copy.
+
+ RELEASE_SPIN_LOCK (&Provider->SpinLock, oldirql);
+
+ *InformationSize = sizeof (Provider->Information);
+
+ return STATUS_SUCCESS;
+} /* NbfQueryInfoProvider */
+
+
+NTSTATUS
+NbfQueryInfoNetman(
+ IN PDEVICE_CONTEXT Provider,
+ IN PTDI_REQUEST_KERNEL TdiRequest,
+ IN ULONG TdiRequestLength,
+ OUT PTDI_NETMAN_INFO InfoBuffer,
+ IN ULONG InfoBufferLength,
+ OUT PULONG InformationSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns information for the specified network-managable
+ variable managed by the transport provider.
+
+Arguments:
+
+ Provider - Pointer to device context for provider.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+ InfoBuffer - Pointer to output buffer to return information into.
+
+ InfoBufferLength - Length of output buffer.
+
+ InformationSize - Pointer to ulong where actual size of returned
+ information is to be stored.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PFLAT_STRING p;
+ PTP_VARIABLE v;
+ PTDI_NETMAN_VARIABLE n;
+ USHORT i;
+ ULONG NameOffset, ValueOffset;
+
+ TdiRequest, TdiRequestLength; // prevent compiler warnings
+ InfoBufferLength, InformationSize;
+
+ //
+ // check param lengths here.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Provider->SpinLock, &oldirql);
+ NbfReferenceDeviceContext ("Query InfoNetMan", Provider, DCREF_QUERY_INFO);
+ for (v=Provider->NetmanVariables; v != NULL; v=v->Fwdlink) {
+ if (TdiRequest->Identification == v->VariableSerialNumber) {
+
+ //
+ // Return the variable information here.
+ //
+
+ NameOffset = sizeof (TDI_NETMAN_INFO);
+ ValueOffset = NameOffset + (sizeof (FLAT_STRING)-1) +
+ v->VariableName.Length;
+
+ InfoBuffer->VariableName = NameOffset;
+ InfoBuffer->VariableValue = ValueOffset;
+
+ //
+ // Copy the variable name to the user's buffer.
+ //
+
+ p = (PFLAT_STRING)((PUCHAR)InfoBuffer + NameOffset);
+ p->MaximumLength = v->VariableName.Length;
+ p->Length = v->VariableName.Length;
+ for (i=0; i<v->VariableName.Length; i++) {
+ p->Buffer [i] = v->VariableName.Buffer [i];
+ }
+
+ //
+ // Now copy the variable's contents to the user's buffer.
+ //
+
+ n = (PTDI_NETMAN_VARIABLE)((PUCHAR)InfoBuffer + ValueOffset);
+ n->VariableType = v->VariableType;
+
+ switch (v->VariableType) {
+
+ case NETMAN_VARTYPE_ULONG:
+ n->Value.LongValue = v->Value.LongValue;
+ break;
+
+ case NETMAN_VARTYPE_HARDWARE_ADDRESS:
+ n->Value.HardwareAddressValue =
+ v->Value.HardwareAddressValue;
+ break;
+
+ case NETMAN_VARTYPE_STRING:
+ p = &n->Value.StringValue;
+ p->MaximumLength = v->Value.StringValue.Length;
+ p->Length = v->Value.StringValue.Length;
+ for (i=0; i<v->Value.StringValue.Length; i++) {
+ p->Buffer [i] = v->Value.StringValue.Buffer [i];
+ }
+
+ } /* switch */
+
+ RELEASE_SPIN_LOCK (&Provider->SpinLock, oldirql);
+ NbfDereferenceDeviceContext ("Query InfoNetMan success", Provider, DCREF_QUERY_INFO);
+ return STATUS_SUCCESS;
+ } /* if */
+ } /* for */
+
+ RELEASE_SPIN_LOCK (&Provider->SpinLock, oldirql);
+
+ NbfDereferenceDeviceContext ("Query InfoNetMan no exist", Provider, DCREF_QUERY_INFO);
+
+ return STATUS_INVALID_INFO_CLASS; // variable does not exist.
+} /* NbfQueryInfoNetman */
+
+
+NTSTATUS
+NbfSetInfoEndpoint(
+ IN PTP_ENDPOINT Endpoint,
+ IN PTDI_REQUEST_KERNEL TdiRequest,
+ IN ULONG TdiRequestLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets information for the specified endpoint.
+
+Arguments:
+
+ Endpoint - Pointer to transport endpoint context.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PTDI_ENDPOINT_INFO InfoBuffer;
+
+ if (TdiRequestLength !=
+ sizeof (TDI_ENDPOINT_INFO) + sizeof (TDI_REQ_SET_INFORMATION) -
+ sizeof (TDI_INFO_BUFFER)) {
+ return STATUS_BUFFER_TOO_SMALL; // buffer sizes must match.
+ }
+
+ InfoBuffer = (PTDI_ENDPOINT_INFO)&TdiRequest->InfoBuffer;
+
+ if ((InfoBuffer->MinimumLookaheadData <= NBF_MAX_LOOKAHEAD_DATA) ||
+ (InfoBuffer->MaximumLookaheadData <= NBF_MAX_LOOKAHEAD_DATA) ||
+ (InfoBuffer->MinimumLookaheadData > InfoBuffer->MaximumLookaheadData)) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ ACQUIRE_SPIN_LOCK (&Endpoint->SpinLock, &oldirql);
+
+ //
+ // Set minimum lookahead data size. This is the number of bytes of
+ // contiguous data that will be supplied to TDI_IND_RECEIVE and
+ // TDI_IND_RECEIVE_DATAGRAM event handlers at indication time.
+ //
+
+ Endpoint->Information.MinimumLookaheadData = InfoBuffer->MinimumLookaheadData;
+
+ //
+ // Set maximum lookahead data size. This is the number of bytes of
+ // contiguous data that will be supplied to TDI_IND_RECEIVE and
+ // TDI_IND_RECEIVE_DATAGRAM event handlers at indication time.
+ //
+
+ Endpoint->Information.MaximumLookaheadData = InfoBuffer->MaximumLookaheadData;
+
+ //
+ // Reset all the statistics to his new values.
+ //
+
+ Endpoint->Information.TransmittedTsdus = InfoBuffer->TransmittedTsdus;
+ Endpoint->Information.ReceivedTsdus = InfoBuffer->ReceivedTsdus;
+ Endpoint->Information.TransmissionErrors = InfoBuffer->TransmissionErrors;
+ Endpoint->Information.ReceiveErrors = InfoBuffer->ReceiveErrors;
+ Endpoint->Information.PriorityLevel = InfoBuffer->PriorityLevel;
+ Endpoint->Information.SecurityLevel = InfoBuffer->SecurityLevel;
+ Endpoint->Information.SecurityCompartment = InfoBuffer->SecurityCompartment;
+
+ //
+ // The State and Event fields are read-only, so we DON'T set them here.
+ //
+
+ RELEASE_SPIN_LOCK (&Endpoint->SpinLock, oldirql);
+
+ return STATUS_SUCCESS;
+} /* NbfSetInfoEndpoint */
+
+
+NTSTATUS
+NbfSetInfoAddress(
+ IN PTP_ADDRESS Address,
+ IN PTDI_REQUEST_KERNEL TdiRequest,
+ IN ULONG TdiRequestLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets information for the specified address. Currently,
+ all the user-visible fields in the transport address object are read-only.
+
+Arguments:
+
+ Address - Pointer to transport address object.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ Address, TdiRequest, TdiRequestLength; // prevent compiler warnings
+
+ return STATUS_SUCCESS;
+} /* NbfSetInfoAddress */
+
+
+NTSTATUS
+NbfSetInfoConnection(
+ IN PTP_CONNECTION Connection,
+ IN PTDI_REQUEST_KERNEL TdiRequest,
+ IN ULONG TdiRequestLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets information for the specified connection.
+
+Arguments:
+
+ Connection - Pointer to transport connection object.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PTDI_CONNECTION_INFO InfoBuffer;
+
+ if (TdiRequestLength !=
+ sizeof (TDI_CONNECTION_INFO) + sizeof (TDI_REQ_SET_INFORMATION) -
+ sizeof (TDI_INFO_BUFFER)) {
+ return STATUS_BUFFER_TOO_SMALL; // buffer sizes must match.
+ }
+
+ InfoBuffer = (PTDI_CONNECTION_INFO)&TdiRequest->InfoBuffer;
+
+ ACQUIRE_C_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ //
+ // Reset all the statistics to his new values.
+ //
+
+ Connection->Information.TransmittedTsdus = InfoBuffer->TransmittedTsdus;
+ Connection->Information.ReceivedTsdus = InfoBuffer->ReceivedTsdus;
+ Connection->Information.TransmissionErrors = InfoBuffer->TransmissionErrors;
+ Connection->Information.ReceiveErrors = InfoBuffer->ReceiveErrors;
+
+ //
+ // The State and Event fields are read-only, so we DON'T set them here.
+ //
+
+ RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ return STATUS_SUCCESS;
+} /* NbfSetInfoConnection */
+
+
+NTSTATUS
+NbfSetInfoProvider(
+ IN PDEVICE_CONTEXT Provider,
+ IN PTDI_REQUEST_KERNEL TdiRequest,
+ IN ULONG TdiRequestLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets information for the specified transport provider.
+
+Arguments:
+
+ Provider - Pointer to device context.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PTDI_PROVIDER_INFO InfoBuffer;
+
+ if (TdiRequestLength !=
+ sizeof (TDI_PROVIDER_INFO) + sizeof (TDI_REQ_SET_INFORMATION) -
+ sizeof (TDI_INFO_BUFFER)) {
+ return STATUS_BUFFER_TOO_SMALL; // buffer sizes must match.
+ }
+
+ InfoBuffer = (PTDI_PROVIDER_INFO)&TdiRequest->InfoBuffer;
+
+ //
+ // By changing the service flags the caller can request additional
+ // or fewer services on the fly. Make sure that he is requesting
+ // services we can provide, or else fail the request.
+ //
+
+ if (InfoBuffer->ServiceFlags & ~NBF_SERVICE_FLAGS) {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ ACQUIRE_SPIN_LOCK (&Provider->SpinLock, &oldirql);
+
+ //
+ // Reset all the statistics to his new values.
+ //
+
+ Provider->Information.TransmittedTsdus = InfoBuffer->TransmittedTsdus;
+ Provider->Information.ReceivedTsdus = InfoBuffer->ReceivedTsdus;
+ Provider->Information.TransmissionErrors = InfoBuffer->TransmissionErrors;
+ Provider->Information.ReceiveErrors = InfoBuffer->ReceiveErrors;
+ Provider->Information.DiscardedFrames = InfoBuffer->DiscardedFrames;
+ Provider->Information.ReceiveErrors = InfoBuffer->ReceiveErrors;
+ Provider->Information.OversizeTsdusReceived = InfoBuffer->OversizeTsdusReceived;
+ Provider->Information.UndersizeTsdusReceived = InfoBuffer->UndersizeTsdusReceived;
+ Provider->Information.MulticastTsdusReceived = InfoBuffer->MulticastTsdusReceived;
+ Provider->Information.BroadcastTsdusReceived = InfoBuffer->BroadcastTsdusReceived;
+ Provider->Information.MulticastTsdusTransmitted = InfoBuffer->MulticastTsdusTransmitted;
+ Provider->Information.BroadcastTsdusTransmitted = InfoBuffer->BroadcastTsdusTransmitted;
+ Provider->Information.SendTimeouts = InfoBuffer->SendTimeouts;
+ Provider->Information.ReceiveTimeouts = InfoBuffer->ReceiveTimeouts;
+ Provider->Information.ConnectionIndicationsReceived = InfoBuffer->ConnectionIndicationsReceived;
+ Provider->Information.ConnectionIndicationsAccepted = InfoBuffer->ConnectionIndicationsAccepted;
+ Provider->Information.ConnectionsInitiated = InfoBuffer->ConnectionsInitiated;
+ Provider->Information.ConnectionsAccepted = InfoBuffer->ConnectionsAccepted;
+
+ //
+ // The following fields are read-only, so we DON'T set them here:
+ // Version, MaxTsduSize, MaxConnectionUserData, MinimumLookaheadData,
+ // MaximumLookaheadData.
+ //
+
+ RELEASE_SPIN_LOCK (&Provider->SpinLock, oldirql);
+
+ return STATUS_SUCCESS;
+} /* NbfSetInfoProvider */
+
+
+NTSTATUS
+NbfSetInfoNetman(
+ IN PDEVICE_CONTEXT Provider,
+ IN PTDI_REQ_SET_INFORMATION TdiRequest,
+ IN ULONG TdiRequestLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets information for the specified transport provider's
+ network-managable variable.
+
+Arguments:
+
+ Provider - Pointer to device context.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTDI_NETMAN_INFO InfoBuffer;
+
+ Provider; // prevent compiler warnings
+
+ if (TdiRequestLength !=
+ sizeof (TDI_NETMAN_INFO) + sizeof (TDI_REQ_SET_INFORMATION) -
+ sizeof (TDI_INFO_BUFFER)) {
+ return STATUS_BUFFER_TOO_SMALL; // buffer sizes must match.
+ }
+
+ InfoBuffer = (PTDI_NETMAN_INFO)&TdiRequest->InfoBuffer;
+
+ //
+ // BUGBUG: set the network-managable variable here.
+ //
+
+ return STATUS_SUCCESS;
+} /* NbfSetInfoNetman */
+
+
+NTSTATUS
+NbfTdiQueryInformation(
+ IN PTP_ENDPOINT Endpoint,
+ IN PTDI_REQ_QUERY_INFORMATION TdiRequest,
+ IN ULONG TdiRequestLength,
+ OUT PTDI_INFO_BUFFER InfoBuffer,
+ IN ULONG InfoBufferLength,
+ OUT PULONG InformationSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiQueryInformation request for the transport
+ provider.
+
+Arguments:
+
+ Endpoint - Pointer to transport endpoint context.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+ InfoBuffer - Pointer to output buffer to return information into.
+
+ InfoBufferLength - Length of output buffer.
+
+ InformationSize - Pointer to ulong where actual size of returned
+ information is to be stored.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_CONNECTION Connection;
+
+ switch (TdiRequest->InformationClass) {
+
+ //
+ // ENDPOINT information: return information about the endpoint
+ // to which this request was submitted.
+ //
+
+ case TDI_INFO_CLASS_ENDPOINT:
+ Status = NbfQueryInfoEndpoint (
+ Endpoint,
+ TdiRequest,
+ TdiRequestLength,
+ (PTDI_ENDPOINT_INFO)InfoBuffer,
+ InfoBufferLength,
+ InformationSize);
+ break;
+
+ //
+ // CONNECTION information: return information about a connection
+ // that is associated with the endpoint on which this request was
+ // submitted.
+ //
+
+ case TDI_INFO_CLASS_CONNECTION:
+ // This causes a connection reference which is removed below.
+ Connection = NbfLookupConnectionById (
+ Endpoint,
+ TdiRequest->Identification);
+ if (Connection == NULL) {
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ Status = NbfQueryInfoConnection (
+ Connection,
+ TdiRequest,
+ TdiRequestLength,
+ (PTDI_CONNECTION_INFO)InfoBuffer,
+ InfoBufferLength,
+ InformationSize);
+
+ NbfDereferenceConnection("Query Connection Info", Connection, CREF_BY_ID);
+ break;
+
+ //
+ // ADDRESS information: return information about the address object
+ // that is associated with the endpoint on which this request was
+ // submitted.
+ //
+
+ case TDI_INFO_CLASS_ADDRESS:
+ Status = NbfQueryInfoAddress (
+ Endpoint->BoundAddress,
+ TdiRequest,
+ TdiRequestLength,
+ (PTDI_ADDRESS_INFO)InfoBuffer,
+ InfoBufferLength,
+ InformationSize);
+ break;
+
+ //
+ // PROVIDER information: return information about the transport
+ // provider itself.
+ //
+
+ case TDI_INFO_CLASS_PROVIDER:
+ Status = NbfQueryInfoProvider (
+ Endpoint->BoundAddress->Provider,
+ TdiRequest,
+ TdiRequestLength,
+ (PTDI_PROVIDER_INFO)InfoBuffer,
+ InfoBufferLength,
+ InformationSize);
+ break;
+
+ //
+ // NETMAN information: return information about the network-managable
+ // variables managed by the provider itself.
+ //
+
+ case TDI_INFO_CLASS_NETMAN:
+ Status = NbfQueryInfoNetman (
+ Endpoint->BoundAddress->Provider,
+ TdiRequest,
+ TdiRequestLength,
+ (PTDI_NETMAN_INFO)InfoBuffer,
+ InfoBufferLength,
+ InformationSize);
+ break;
+
+ default:
+ Status = STATUS_INVALID_INFO_CLASS;
+
+ } /* switch */
+
+ return Status;
+} /* TdiQueryInformation */
+
+
+NTSTATUS
+TdiSetInformation(
+ IN PTP_ENDPOINT Endpoint,
+ IN PTDI_REQ_SET_INFORMATION TdiRequest,
+ IN ULONG TdiRequestLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetInformation request for the transport
+ provider.
+
+Arguments:
+
+ Endpoint - Pointer to transport endpoint context.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_CONNECTION Connection;
+
+ switch (TdiRequest->InformationClass) {
+
+ //
+ // ENDPOINT information: set information on the endpoint
+ // to which this request was submitted.
+ //
+
+ case TDI_INFO_CLASS_ENDPOINT:
+ Status = NbfSetInfoEndpoint (
+ Endpoint,
+ TdiRequest,
+ TdiRequestLength);
+ break;
+
+ //
+ // CONNECTION information: set information for a connection
+ // that is associated with the endpoint on which this request
+ // was submitted.
+ //
+
+ case TDI_INFO_CLASS_CONNECTION:
+ // This causes a connection reference which is removed below.
+ Connection = NbfLookupConnectionById (
+ Endpoint,
+ TdiRequest->Identification);
+ if (Connection == NULL) {
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ Status = NbfSetInfoConnection (
+ Connection,
+ TdiRequest,
+ TdiRequestLength);
+
+ NbfDereferenceConnection("Set Connection Info", Connection, CREF_BY_ID);
+ break;
+
+ //
+ // ADDRESS information: set information for the address object
+ // that is associated with the endpoint on which this request
+ // was submitted.
+ //
+
+ case TDI_INFO_CLASS_ADDRESS:
+ Status = NbfSetInfoAddress (
+ Endpoint->BoundAddress,
+ TdiRequest,
+ TdiRequestLength);
+ break;
+
+ //
+ // PROVIDER information: set information for the transport
+ // provider itself.
+ //
+
+ case TDI_INFO_CLASS_PROVIDER:
+ Status = NbfSetInfoProvider (
+ Endpoint->BoundAddress->Provider,
+ TdiRequest,
+ TdiRequestLength);
+ break;
+
+ //
+ // NETMAN information: set information for the network-managable
+ // variables managed by the provider itself.
+ //
+
+ case TDI_INFO_CLASS_NETMAN:
+ Status = NbfSetInfoNetman (
+ Endpoint->BoundAddress->Provider,
+ TdiRequest,
+ TdiRequestLength);
+ break;
+
+ default:
+ Status = STATUS_INVALID_INFO_CLASS;
+
+ } /* switch */
+
+ return Status;
+} /* TdiSetInformation */
+
+#endif
diff --git a/private/ntos/tdi/nbf/link.c b/private/ntos/tdi/nbf/link.c
new file mode 100644
index 000000000..e99bbb8f4
--- /dev/null
+++ b/private/ntos/tdi/nbf/link.c
@@ -0,0 +1,2315 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ link.c
+
+Abstract:
+
+ This module contains code which implements the TP_LINK object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport link objects.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+extern ULONG StartTimerLinkDeferredAdd;
+extern ULONG StartTimerLinkDeferredDelete;
+
+#if DBG
+// The following is here for debugging purposes to make it easy to change
+// the maximum packet size.
+
+ULONG MaxUserPacketData = 18000;
+#endif
+
+#if 0
+
+VOID
+DisconnectCompletionHandler(
+ IN PTP_LINK TransportLink
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called as an I/O completion handler at the time a
+ TdiDisconnect request is completed. Here we dereference the link
+ object, and optionally reference it again and start up the link if
+ some transport connection started up on the link during the time we
+ were trying to shut it down.
+
+Arguments:
+
+ TransportLink - Pointer to a transport link object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint1 ("DisconnectCompletionHandler: Entered for link %lx.\n",
+ TransportLink);
+ }
+
+ //
+ // The following call will dereference this link for the last time,
+ // unless another transport connection has been assigned to the link
+ // during the time the data link layer was bringing the link down and
+ // when we got here. If this condition exists, then now is the time
+ // to bring the link back up, else destroy it.
+ //
+
+ // BUGBUG: don't forget to check for bringing it back up again.
+
+ // BUGBUG: Is this right??? - ADB 6/26
+
+ NbfDereferenceLink ("Disconnecting", TransportLink, LREF_CONNECTION); // this makes it go away.
+#if DBG
+ NbfPrint0("Disconnecting Completion Handler\n");
+#endif
+
+} /* DisconnectCompletionHandler */
+#endif
+
+
+VOID
+NbfCompleteLink(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the UA-r/x handler, NbfWaitLink, and
+ NbfActivateLink to startup the NBF connections associated with
+ a link because they were waiting for the link to become established.
+
+ When we get here, the link has been established, so we need to
+ start the next set of connection-establishment protocols:
+
+ SESSION_INIT ----------------->
+ <----------------- SESSION_CONFIRM
+
+ (TdiConnect completes) (TdiListen completes)
+
+ NOTE: THIS ROUTINE MUST BE CALLED FROM DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PTP_CONNECTION Connection;
+ BOOLEAN TimerWasCleared;
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint1 ("NbfCompleteLink: Entered for link %lx.\n", Link);
+ }
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ //
+ // Officially declare that this link is ready for I-frame business.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ //
+ // We can now send and receive I-frames on this link. We are in ABME.
+ //
+
+ //
+ // This probably isn't necessary, but to be safe for now.. (adb 6/28)
+ //
+ if (Link->State == LINK_STATE_ADM) {
+ // Moving out of ADM, add special reference
+ NbfReferenceLinkSpecial("To READY in NbfCompleteLink", Link, LREF_NOT_ADM);
+ }
+
+ Link->State = LINK_STATE_READY;
+ Link->SendState = SEND_STATE_READY;
+ Link->ReceiveState = RECEIVE_STATE_READY;
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ //
+ // Complete all of the listens first, so they will be expecting
+ // incoming SESSION_INITIALIZEs. Then do the connects.
+ //
+
+ // This creates a connection reference which is removed below.
+ while ((Connection=NbfLookupPendingListenOnLink (Link)) != NULL) {
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // This loop looks unnecessary, let's make sure... - adb 9/11/91
+ //
+ ASSERT(Connection->Flags & CONNECTION_FLAGS_WAIT_SI);
+
+ Connection->Flags |= CONNECTION_FLAGS_WAIT_SI; // wait session initialize.
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ NbfDereferenceConnection ("Pending listen", Connection, CREF_P_LINK);
+ } /* while */
+
+ //
+ // And do the connects. If there are connections in progress, they'll
+ // also have timers associated with them. Cancel those timers.
+ //
+
+ while ((Connection=NbfLookupPendingConnectOnLink (Link)) != NULL) {
+ TimerWasCleared = KeCancelTimer (&Connection->Timer);
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint2 ("NbfCompleteLink: Timer for connection %lx %s canceled.\n",
+ Connection, TimerWasCleared ? "was" : "was NOT" );
+ }
+ if (TimerWasCleared) {
+ NbfDereferenceConnection("Cancel timer", Connection, CREF_TIMER);
+ }
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ Connection->Flags |= CONNECTION_FLAGS_WAIT_SC; // wait session confirm.
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // No timeout for this frame is required since the link is responsible
+ // for reliable delivery. If we can't send this frame, however, the
+ // data link connection will happily keep quiet without timeouts.
+ //
+
+ NbfSendSessionInitialize (Connection);
+ NbfDereferenceConnection ("NbfCompleteLink", Connection, CREF_P_CONNECT);
+ } /* while */
+
+} /* NbfCompleteLink */
+
+
+VOID
+NbfAllocateLink(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_LINK *TransportLink
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for a data link connection. It
+ performs minimal initialization of the object.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ link.
+
+ TransportLink - Pointer to a place where this routine will return a
+ pointer to an allocated transport link structure. Returns
+ NULL if no storage can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PTP_LINK Link;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + sizeof(TP_LINK)) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("NBF: Could not allocate link: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 105,
+ sizeof(TP_LINK),
+ LINK_RESOURCE_ID);
+ *TransportLink = NULL;
+ return;
+ }
+ Link = (PTP_LINK)ExAllocatePoolWithTag (
+ NonPagedPool,
+ sizeof (TP_LINK),
+ 'lFBN');
+ if (Link == NULL) {
+ PANIC("NBF: Could not allocate link: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 205,
+ sizeof(TP_LINK),
+ LINK_RESOURCE_ID);
+ *TransportLink = NULL;
+ return;
+ }
+ RtlZeroMemory (Link, sizeof(TP_LINK));
+
+ ++DeviceContext->LinkAllocated;
+ DeviceContext->MemoryUsage += sizeof(TP_LINK);
+
+ Link->Type = NBF_LINK_SIGNATURE;
+ Link->Size = sizeof (TP_LINK);
+
+ KeInitializeSpinLock (&Link->SpinLock);
+ Link->Provider = DeviceContext;
+ Link->ProviderInterlock = &DeviceContext->Interlock;
+
+ InitializeListHead (&Link->Linkage);
+ InitializeListHead (&Link->ConnectionDatabase);
+ InitializeListHead (&Link->WackQ);
+ InitializeListHead (&Link->NdisSendQueue);
+ InitializeListHead (&Link->ShortList);
+ Link->OnShortList = FALSE;
+ InitializeListHead (&Link->LongList);
+ Link->OnLongList = FALSE;
+ InitializeListHead (&Link->PurgeList);
+
+ Link->T1 = 0; // 0 indicates they are not in the list
+ Link->T2 = 0;
+ Link->Ti = 0;
+
+ NbfAddSendPacket (DeviceContext);
+ NbfAddReceivePacket (DeviceContext);
+
+ *TransportLink = Link;
+
+} /* NbfAllocateLink */
+
+
+VOID
+NbfDeallocateLink(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_LINK TransportLink
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for a data link connection.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ link.
+
+ TransportLink - Pointer to the transport link structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ExFreePool (TransportLink);
+ --DeviceContext->LinkAllocated;
+ DeviceContext->MemoryUsage -= sizeof(TP_LINK);
+
+ NbfRemoveSendPacket (DeviceContext);
+ NbfRemoveReceivePacket (DeviceContext);
+
+} /* NbfDeallocateLink */
+
+
+NTSTATUS
+NbfCreateLink(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PHARDWARE_ADDRESS HardwareAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN USHORT LoopbackLinkIndex,
+ OUT PTP_LINK *TransportLink
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a data link connection between the local
+ data link station and the specified remote data link address.
+ As an option (Passive=TRUE), the caller may specify that instead
+ of a Connect activity, a Listen is to be performed instead.
+
+ Normally, if a link to the remote address is not already active,
+ then a link object is allocated, the reference count in the link
+ is set to 1, and the reference count of the device context is
+ incremented.
+
+ If a link is already active to the remote address, then the existing
+ link object is referenced with NbfReferenceLink() so that it can be
+ shared between the transport connections.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ link.
+
+ HardwareAddress - Pointer to a HARDWARE_ADDRESS type containing the
+ hardware address of the REMOTE link station to connect to/listen for.
+
+ LoopbackLinkIndex - In the case that this turns out to be created
+ as one of the LoopbackLinks, this will indicate which one to
+ use.
+
+ TransportLink - Pointer to a place where this routine will return a
+ pointer to an allocated transport link structure.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_LINK Link;
+ PLIST_ENTRY p;
+ UCHAR TempSR[MAX_SOURCE_ROUTING];
+ PUCHAR ResponseSR;
+ USHORT i;
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint1 ("NbfCreateLink: Entered, DeviceContext: %lx\n", DeviceContext);
+ }
+
+ //
+ // Walk the list of addresses to see if we already have a link to this
+ // remote address.
+ //
+
+ // This adds a reference if the link is found.
+
+ Link = NbfFindLink (DeviceContext, HardwareAddress->Address);
+
+
+ if (Link == (PTP_LINK)NULL) {
+
+ //
+ // If necessary, check whether we are looking for one of
+ // the loopback links (NbfFindLink won't find those).
+ //
+
+ if (RtlEqualMemory(
+ HardwareAddress->Address,
+ DeviceContext->LocalAddress.Address,
+ DeviceContext->MacInfo.AddressLength)) {
+
+ Link = DeviceContext->LoopbackLinks[LoopbackLinkIndex];
+
+ if (Link != (PTP_LINK)NULL) {
+
+ //
+ // Add a reference to simulate the one from NbfFindLink
+ //
+ // BUGBUG: This needs to be atomically done with
+ // the assignment above.
+ //
+
+ NbfReferenceLink ("Found loopback link", Link, LREF_TREE);
+
+ } else {
+
+ //
+ // May have the first loopback link; need to make sure the
+ // buffer for indications is allocated.
+ //
+
+ if (DeviceContext->LookaheadContiguous == NULL) {
+
+ DeviceContext->LookaheadContiguous =
+ ExAllocatePoolWithTag (
+ NonPagedPool,
+ NBF_MAX_LOOPBACK_LOOKAHEAD,
+ ' FBN');
+ if (DeviceContext->LookaheadContiguous == NULL) {
+ PANIC ("NbfCreateLink: Could not allocate loopback buffer!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+
+ if (Link != (PTP_LINK)NULL) {
+
+ //
+ // Found the link structure here, so use the existing link.
+ //
+
+#if DBG
+ //
+ // These two operations have no net effect, so if not in debug
+ // mode we can remove them.
+ //
+
+ // This reference is removed by NbfDisconnectFromLink
+ // (this assumes that NbfConnectToLink is always called
+ // if this function returns success).
+
+ NbfReferenceLink ("New Ref, Found existing link", Link, LREF_CONNECTION); // extra reference.
+
+ // Now we can remove the NbfFindLinkInTree reference.
+
+ NbfDereferenceLink ("Found link in tree", Link, LREF_TREE);
+#endif
+
+ *TransportLink = Link; // return pointer to the link.
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint0 ("NbfCreateLink: returning ptr to existing link object.\n");
+ }
+ return STATUS_SUCCESS; // all done.
+
+ } /* if LINK != NULL */
+
+
+ //
+ // We don't have an existing link, so we have to create one.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint0 ("NbfCreateLink: using new link object.\n");
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ p = RemoveHeadList (&DeviceContext->LinkPool);
+ if (p == &DeviceContext->LinkPool) {
+
+ if ((DeviceContext->LinkMaxAllocated == 0) ||
+ (DeviceContext->LinkAllocated < DeviceContext->LinkMaxAllocated)) {
+
+ NbfAllocateLink (DeviceContext, &Link);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Allocated link at %lx\n", Link);
+ }
+
+ } else {
+
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 405,
+ sizeof(TP_LINK),
+ LINK_RESOURCE_ID);
+ Link = NULL;
+
+ }
+
+ if (Link == NULL) {
+ ++DeviceContext->LinkExhausted;
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+ PANIC ("NbfCreateConnection: Could not allocate link object!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ } else {
+
+ Link = CONTAINING_RECORD (p, TP_LINK, Linkage);
+
+ }
+
+ ++DeviceContext->LinkInUse;
+ ASSERT(DeviceContext->LinkInUse > 0);
+
+ if (DeviceContext->LinkInUse > DeviceContext->LinkMaxInUse) {
+ ++DeviceContext->LinkMaxInUse;
+ }
+
+ DeviceContext->LinkTotal += DeviceContext->LinkInUse;
+ ++DeviceContext->LinkSamples;
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint1 ("NbfCreateLink: Link at %lx.\n", Link);
+ }
+
+ //
+ // Initialize all of the static data for this link.
+ //
+
+ Link->SpecialRefCount = 1;
+ Link->ReferenceCount = 0;
+#if DBG
+ {
+ UINT Counter;
+ for (Counter = 0; Counter < NUMBER_OF_LREFS; Counter++) {
+ Link->RefTypes[Counter] = 0;
+ }
+
+ // This reference is removed by NbfDisconnectFromLink
+ // (this assumes that NbfConnectToLink is always called
+ // if this function returns success).
+ //
+
+ Link->RefTypes[LREF_CONNECTION] = 1;
+ Link->RefTypes[LREF_SPECIAL_TEMP] = 1;
+ }
+ Link->Destroyed = FALSE;
+ Link->TotalReferences = 0;
+ Link->TotalDereferences = 0;
+ Link->NextRefLoc = 0;
+ ExInterlockedInsertHeadList (&NbfGlobalLinkList, &Link->GlobalLinkage, &NbfGlobalInterlock);
+ StoreLinkHistory (Link, TRUE);
+#endif
+ Link->Flags = 0; // in the beginning, the link is closed.
+ Link->DeferredFlags = 0;
+ Link->State = LINK_STATE_ADM; // async disconnected mode.
+
+ Link->NdisSendsInProgress = 0;
+ Link->ResendingPackets = FALSE;
+
+ //
+ // Initialize the counters
+ //
+
+ Link->FrmrsReceived = 0;
+ Link->FrmrsTransmitted = 0;
+ Link->ErrorIFramesReceived = 0;
+ Link->ErrorIFramesTransmitted = 0;
+ Link->AbortedTransmissions = 0;
+ Link->BuffersNotAvailable = 0;
+ Link->SuccessfulTransmits = 0;
+ Link->SuccessfulReceives = 0;
+ Link->T1Expirations = 0;
+ Link->TiExpirations = 0;
+
+#if DBG
+ Link->CreatePacketFailures = 0;
+#endif
+
+
+ //
+ // At first, the delay and throughput are unknown.
+ //
+
+ Link->Delay = 0xffffffff;
+ Link->Throughput.HighPart = 0xffffffff;
+ Link->Throughput.LowPart = 0xffffffff;
+ Link->ThroughputAccurate = FALSE;
+ Link->CurrentT1Backoff = FALSE;
+
+ Link->OnDeferredRrQueue = FALSE;
+ InitializeListHead (&Link->DeferredRrLinkage);
+
+
+ //
+ // Determine the maximum sized data frame that can be sent
+ // on this link, based on the source routing information and
+ // the size of the MAC header ("data frame" means the frame
+ // without the MAC header). We don't assume the worst case
+ // about source routing since we create a link in response
+ // to a received frame, so if there is no source routing it
+ // is because we are not going over a bridge. The exception
+ // is if we are creating a link to a group name, in which
+ // case we come back later and hack the MaxFrameSize in.
+ //
+
+ MacReturnMaxDataSize(
+ &DeviceContext->MacInfo,
+ SourceRouting,
+ SourceRoutingLength,
+ DeviceContext->CurSendPacketSize,
+ FALSE,
+ (PUINT)&(Link->MaxFrameSize));
+
+
+#if DBG
+ if (Link->MaxFrameSize > MaxUserPacketData) {
+ Link->MaxFrameSize = MaxUserPacketData;
+ }
+#endif
+
+ // Link->Provider = DeviceContext;
+
+ //
+ // Build the default MAC header. I-frames go out as
+ // non-broadcast source routing.
+ //
+
+ if (SourceRouting != NULL) {
+
+ RtlCopyMemory(
+ TempSR,
+ SourceRouting,
+ SourceRoutingLength);
+
+ MacCreateNonBroadcastReplySR(
+ &DeviceContext->MacInfo,
+ TempSR,
+ SourceRoutingLength,
+ &ResponseSR);
+
+ } else {
+
+ ResponseSR = NULL;
+
+ }
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ Link->Header,
+ HardwareAddress->Address,
+ DeviceContext->LocalAddress.Address,
+ 0, // PacketLength, filled in later
+ ResponseSR,
+ SourceRoutingLength,
+ (PUINT)&(Link->HeaderLength));
+
+ //
+ // We optimize for fourteen-byte headers by putting
+ // the correct Dsap/Ssap at the end, so we can fill
+ // in new packets as one 16-byte move.
+ //
+
+ if (Link->HeaderLength <= 14) {
+ Link->Header[Link->HeaderLength] = DSAP_NETBIOS_OVER_LLC;
+ Link->Header[Link->HeaderLength+1] = DSAP_NETBIOS_OVER_LLC;
+ }
+
+ Link->RespondToPoll = FALSE;
+ Link->NumberOfConnectors = 0;
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ NbfResetLink (Link);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ Link->ActiveConnectionCount = 0;
+ if (!IsListEmpty(&Link->ConnectionDatabase)) {
+
+ //
+ // Not good; we've got something left over...
+ //
+#if DBG
+ NbfPrint1 ("NbfCreateLink: Link 0x%lx has connections at startup, disconnecting...\n", Link);
+ DbgBreakPoint();
+#endif
+ //
+ // BUGBUG: This won't work, the link ref count will be bad.
+ //
+ NbfStopLink (Link);
+ }
+
+ for (i=0; i<(USHORT)DeviceContext->MacInfo.AddressLength; i++) {
+ Link->HardwareAddress.Address[i] = HardwareAddress->Address[i];
+ }
+ MacReturnMagicAddress (&DeviceContext->MacInfo, HardwareAddress, &Link->MagicAddress);
+
+ //
+ // Determine if this is a loopback link.
+ //
+
+ if (RtlEqualMemory(
+ HardwareAddress->Address,
+ DeviceContext->LocalAddress.Address,
+ DeviceContext->MacInfo.AddressLength)) {
+
+ //
+ // Yes, just fill it in, no need to do deferred processing
+ // since this link does not go in the tree.
+ //
+
+ if (LoopbackLinkIndex == LISTENER_LINK) {
+ Link->LoopbackDestinationIndex = LOOPBACK_TO_CONNECTOR;
+ } else {
+ Link->LoopbackDestinationIndex = LOOPBACK_TO_LISTENER;
+ }
+
+ Link->Loopback = TRUE;
+ DeviceContext->LoopbackLinks[LoopbackLinkIndex] = Link;
+
+ } else {
+
+ Link->Loopback = FALSE;
+
+ //
+ // Now put the link in the deferred operations queue and go away. We'll
+ // insert this link in the tree at some future time (soon).
+ //
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint6 ("NbfCreateLink: link to deferred queue %lx %lx %lx %lx %lx Flags: %lx \n",
+ Link, Link->DeferredList.Flink, Link->DeferredList.Blink,
+ DeviceContext->LinkDeferred.Flink, DeviceContext->LinkDeferred.Blink,
+ Link->Flags);
+ }
+
+ //
+ // We should not have any deferred flags yet!
+ //
+
+ ASSERT ((Link->DeferredFlags & LINK_FLAGS_DEFERRED_MASK) == 0);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+ if ((Link->DeferredFlags & LINK_FLAGS_DEFERRED_DELETE) == 0) {
+ Link->DeferredFlags |= LINK_FLAGS_DEFERRED_ADD;
+ InsertTailList (&DeviceContext->LinkDeferred, &Link->DeferredList);
+
+ if (!(DeviceContext->a.i.LinkDeferredActive)) {
+ StartTimerLinkDeferredAdd++;
+ NbfStartShortTimer (DeviceContext);
+ DeviceContext->a.i.LinkDeferredActive = TRUE;
+ }
+ }
+ else {
+ Link->DeferredFlags = LINK_FLAGS_DEFERRED_ADD;
+ if (!(DeviceContext->a.i.LinkDeferredActive)) {
+ StartTimerLinkDeferredAdd++;
+ NbfStartShortTimer (DeviceContext);
+ DeviceContext->a.i.LinkDeferredActive = TRUE;
+ }
+ }
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint6 ("NbfCreateLink: link on deferred queue %lx %lx %lx %lx %lx Flags: %lx \n",
+ Link, Link->DeferredList.Flink, Link->DeferredList.Blink,
+ DeviceContext->LinkDeferred.Flink, DeviceContext->LinkDeferred.Blink,
+ Link->DeferredFlags);
+ }
+
+ }
+
+ NbfReferenceDeviceContext ("Create Link", DeviceContext, DCREF_LINK); // count refs to the device context.
+ *TransportLink = Link; // return a pointer to the link object.
+ return STATUS_SUCCESS;
+} /* NbfCreateLink */
+
+
+NTSTATUS
+NbfDestroyLink(
+ IN PTP_LINK TransportLink
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a transport link and removes all references
+ made to it by other objects in the transport. The link is expected
+ to still be on the splay tree of links. This routine merely marks the
+ link as needing to be deleted and pushes it onto the deferred operations
+ queue. The deferred operations processor actually removes the link from
+ tree and returns the link to pool.
+
+Arguments:
+
+ TransportLink - Pointer to a transport link structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PTP_PACKET packet;
+ PLIST_ENTRY pkt;
+ PDEVICE_CONTEXT DeviceContext;
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint1 ("NbfDestroyLink: Entered for link %lx.\n", TransportLink);
+ }
+
+#if DBG
+ if (TransportLink->Destroyed) {
+ NbfPrint1 ("attempt to destroy already-destroyed link 0x%lx\n", TransportLink);
+ DbgBreakPoint ();
+ }
+ TransportLink->Destroyed = TRUE;
+#if 1
+ ACQUIRE_SPIN_LOCK (&NbfGlobalInterlock, &oldirql);
+ RemoveEntryList (&TransportLink->GlobalLinkage);
+ RELEASE_SPIN_LOCK (&NbfGlobalInterlock, oldirql);
+#else
+ ExInterlockedRemoveHeadList (TransportLink->GlobalLinkage.Blink, &NbfGlobalInterlock);
+#endif
+#endif
+
+ DeviceContext = TransportLink->Provider;
+
+ //
+ // In case there's a holdover from the DISC link shutdown protocol
+ //
+
+ //
+ // We had better be in ADM, otherwise the reference count should
+ // be non-zero and what are we doing in NbfDestroyLink?
+ //
+
+ ASSERT(TransportLink->State == LINK_STATE_ADM);
+ // TransportLink->State = LINK_STATE_ADM;
+
+ StopT1 (TransportLink);
+ StopT2 (TransportLink);
+ StopTi (TransportLink);
+
+
+ //
+ // Make sure we are not in the deferred timer queue.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->TimerSpinLock, &oldirql);
+
+ if (TransportLink->OnShortList) {
+ TransportLink->OnShortList = FALSE;
+ RemoveEntryList (&TransportLink->ShortList);
+ }
+
+ if (TransportLink->OnLongList) {
+ TransportLink->OnLongList = FALSE;
+ RemoveEntryList (&TransportLink->LongList);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->TimerSpinLock, oldirql);
+
+ ASSERT (!TransportLink->OnDeferredRrQueue);
+
+ //
+ // Now free this link object's resources.
+ // BUGBUG: later, we'll spin through the WackQ and verify that sequencing
+ // is correct and we've gotten an implicit ack for these packets. This
+ // maybe should be handled in ResendLlcPackets for non-final, non-command
+ // packets.
+ //
+
+ while (!IsListEmpty (&TransportLink->WackQ)) {
+ pkt = RemoveHeadList (&TransportLink->WackQ);
+ packet = CONTAINING_RECORD (pkt, TP_PACKET, Linkage);
+#if DBG
+ // IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint1 ("NbfDereferenceLink: Destroying packets on Link WackQ! %lx\n", packet);
+ // }
+#endif
+ NbfDereferencePacket (packet);
+
+ }
+
+ //
+ // The NDIS send queue should be empty!!
+ //
+
+ ASSERT (IsListEmpty (&TransportLink->NdisSendQueue));
+
+#if DBG
+ if (!IsListEmpty (&TransportLink->ConnectionDatabase)) {
+ NbfPrint1 ("NbfDestroyLink: link 0x%lx still has connections\n", TransportLink);
+ DbgBreakPoint ();
+ }
+#endif
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ DeviceContext->LinkTotal += DeviceContext->LinkInUse;
+ ++DeviceContext->LinkSamples;
+ ASSERT(DeviceContext->LinkInUse > 0);
+ --DeviceContext->LinkInUse;
+
+ ASSERT(DeviceContext->LinkAllocated > DeviceContext->LinkInUse);
+
+ if ((DeviceContext->LinkAllocated - DeviceContext->LinkInUse) >
+ DeviceContext->LinkInitAllocated) {
+ NbfDeallocateLink (DeviceContext, TransportLink);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Deallocated link at %lx\n", TransportLink);
+ }
+ } else {
+ InsertTailList (&DeviceContext->LinkPool, &TransportLink->Linkage);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ NbfDereferenceDeviceContext ("Destroy Link", DeviceContext, DCREF_LINK); // just housekeeping.
+
+ return STATUS_SUCCESS;
+
+} /* NbfDestroyLink */
+
+
+VOID
+NbfDisconnectLink(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine calls the data link provider to disconnect a data link
+ connection associated with a TP_LINK object.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint1 ("NbfDisconnectLink: Entered for link %lx.\n", Link);
+ }
+
+ ACQUIRE_SPIN_LOCK (&Link->SpinLock, &oldirql);
+
+ if ((Link->Flags & LINK_FLAGS_LOCAL_DISC) != 0) {
+
+ Link->Flags &= ~LINK_FLAGS_LOCAL_DISC;
+
+ if (Link->State == LINK_STATE_ADM) {
+
+ RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql);
+
+ } else {
+
+ PLIST_ENTRY p;
+ PTP_PACKET packet;
+
+ Link->State = LINK_STATE_W_DISC_RSP; // we are awaiting a DISC/f.
+ Link->SendState = SEND_STATE_DOWN;
+ Link->ReceiveState = RECEIVE_STATE_DOWN;
+ StopT1 (Link);
+ StopT2 (Link);
+ StopTi (Link);
+
+ //
+ // check for left over packets on the link WackQ; we'll never get
+ // acked for these if the link is in W_DISC_RSP.
+ //
+
+ while (!IsListEmpty (&Link->WackQ)) {
+ p = RemoveHeadList (&Link->WackQ);
+ RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql);
+ packet = CONTAINING_RECORD (p, TP_PACKET, Linkage);
+ NbfDereferencePacket (packet);
+ ACQUIRE_SPIN_LOCK (&Link->SpinLock, &oldirql);
+ }
+
+ Link->SendRetries = (UCHAR)Link->LlcRetries;
+ StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME)); // retransmit timer.
+ RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql);
+ NbfSendDisc (Link, TRUE); // send DISC-c/p.
+
+ }
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql);
+
+ }
+
+} /* NbfDisconnectLink */
+
+#if DBG
+
+VOID
+NbfRefLink(
+ IN PTP_LINK TransportLink
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport link. If we are
+ currently in the state waiting for disconnect response, we do not
+ reference; this avoids the link "bouncing" during disconnect (trying to
+ disconnect multiple times).
+
+Arguments:
+
+ TransportLink - Pointer to a transport link object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint2 ("NbfReferenceLink: Entered for link %lx, current level=%ld.\n",
+ TransportLink, TransportLink->ReferenceCount);
+ }
+
+#if DBG
+ StoreLinkHistory( TransportLink, TRUE );
+#endif
+
+ result = InterlockedIncrement (&TransportLink->ReferenceCount);
+
+ if (result == 0) {
+
+ //
+ // The first increment causes us to increment the
+ // "ref count is not zero" special ref.
+ //
+
+ NbfReferenceLinkSpecial ("first ref", TransportLink, LREF_SPECIAL_TEMP);
+
+ }
+
+ ASSERT (result >= 0);
+
+} /* NbfRefLink */
+#endif
+
+
+VOID
+NbfDerefLink(
+ IN PTP_LINK TransportLink
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport link by decrementing the
+ reference count contained in the structure.
+
+ There are two special reference counts, 1 and 0. If, after dereferencing,
+ the reference count is one (1), then we initiate a disconnect protocol
+ sequence (DISC/UA) to terminate the connection. When this request
+ completes, the completion routine will dereference the link object again.
+ While this protocol is in progress, we will not allow the link to be
+ incremented again.
+
+ If the reference count becomes 0 after dereferencing, then we are in
+ the disconnection request completion handler, and we should actually
+ destroy the link object. We place the link on the deferred operations
+ queue and let the link get deleted later at a safe time.
+
+ Warning: Watch out for cases where a link is going down, and it is
+ suddenly needed again. Keep a bitflag for that in the link object.
+
+Arguments:
+
+ TransportLink - Pointer to a transport link object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint2 ("NbfDereferenceLink: Entered for link %lx, current level=%ld.\n",
+ TransportLink, TransportLink->ReferenceCount);
+ }
+
+#if DBG
+ StoreLinkHistory( TransportLink, FALSE );
+#endif
+
+ result = InterlockedDecrement(&TransportLink->ReferenceCount);
+
+ //
+ // If all the normal references to this link are gone, then
+ // we can remove the special reference that stood for
+ // "the regular ref count is non-zero".
+ //
+
+
+ if (result < 0) {
+
+ //
+ // If the refcount is -1 we want to call DisconnectLink,
+ // we do this before removing the special ref so that
+ // the link does not go away during the call.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint0 ("NbfDereferenceLink: refcnt=1, disconnecting Link object.\n");
+ }
+
+ NbfDisconnectLink (TransportLink);
+
+ //
+ // Now it is OK to let the link go away.
+ //
+
+ NbfDereferenceLinkSpecial ("Regular ref 0", TransportLink, LREF_SPECIAL_TEMP);
+
+ }
+
+} /* NbfDerefLink */
+
+
+VOID
+NbfRefLinkSpecial(
+ IN PTP_LINK TransportLink
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the special reference count on a transport link.
+
+Arguments:
+
+ TransportLink - Pointer to a transport link object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG result;
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint3 ("NbfRefLinkSpecial: Entered for link %lx, current level=%ld (%ld).\n",
+ TransportLink, TransportLink->ReferenceCount, TransportLink->SpecialRefCount);
+ }
+
+#if DBG
+ StoreLinkHistory( TransportLink, TRUE );
+#endif
+
+ result = ExInterlockedAddUlong (
+ (PULONG)&TransportLink->SpecialRefCount,
+ 1,
+ TransportLink->ProviderInterlock);
+
+} /* NbfRefLinkSpecial */
+
+
+VOID
+NbfDerefLinkSpecial(
+ IN PTP_LINK TransportLink
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport link by decrementing the
+ special reference count contained in the structure.
+
+ The special reference may be decremented at any time, however
+ the effect of those dereferences only happen when the normal
+ reference count is 0, to prevent the link from going away
+ while the operations due to the ->0 transition of the
+ normal reference count are done.
+
+ If the special reference count becomes 0 after dereferencing, then we
+ are in the disconnection request completion handler, and we should actually
+ destroy the link object. We place the link on the deferred operations
+ queue and let the link get deleted later at a safe time.
+
+ Warning: Watch out for cases where a link is going down, and it is
+ suddenly needed again. Keep a bitflag for that in the link object.
+
+Arguments:
+
+ TransportLink - Pointer to a transport link object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ ULONG OldRefCount;
+ PDEVICE_CONTEXT DeviceContext = TransportLink->Provider;
+
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint3 ("NbfDerefLinkSpecial: Entered for link %lx, current level=%ld (%ld).\n",
+ TransportLink, TransportLink->ReferenceCount, TransportLink->SpecialRefCount);
+ }
+
+#if DBG
+ StoreLinkHistory( TransportLink, FALSE );
+#endif
+
+ //
+ // Links stay in the device context tree with a ref count
+ // of 0. Routines that scan this queue check the DEFERRED_DELETE
+ // flag, so we need to synchronize the decrementing of the
+ // ref count with setting that flag. DeviceContext->LinkSpinLock
+ // is used to synchronize this.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->LinkSpinLock, &oldirql1);
+
+ OldRefCount = ExInterlockedAddUlong (
+ (PULONG)&TransportLink->SpecialRefCount,
+ (ULONG)-1,
+ TransportLink->ProviderInterlock);
+
+ ASSERT (OldRefCount > 0);
+
+ if ((OldRefCount == 1) &&
+ (TransportLink->ReferenceCount == -1)) {
+
+ if (TransportLink->Loopback) {
+
+ //
+ // It is a loopback link, hence not in the link
+ // tree so we don't need to queue a deferred removal.
+ //
+
+ if (TransportLink == DeviceContext->LoopbackLinks[0]) {
+ DeviceContext->LoopbackLinks[0] = NULL;
+ } else if (TransportLink == DeviceContext->LoopbackLinks[1]) {
+ DeviceContext->LoopbackLinks[1] = NULL;
+ } else {
+#if DBG
+ NbfPrint0("Destroying unknown loopback link!!\n");
+#endif
+ ASSERT(FALSE);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->LinkSpinLock, oldirql1);
+
+ NbfDestroyLink (TransportLink);
+
+ } else {
+
+ //
+ // Not only are all transport connections gone, but the data link
+ // provider does not have a reference to this object, so we can
+ // safely delete it from the system. Make sure we haven't already
+ // been here before we try to insert this link.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint6 ("NbfDerefLink: link to deferred queue %lx %lx %lx %lx %lx Flags: %lx \n",
+ TransportLink, TransportLink->DeferredList.Flink,
+ TransportLink->DeferredList.Blink, DeviceContext->LinkDeferred.Flink,
+ DeviceContext->LinkDeferred.Blink, TransportLink->Flags);
+ }
+
+ if ((TransportLink->DeferredFlags & LINK_FLAGS_DEFERRED_MASK) == 0) {
+
+ TransportLink->DeferredFlags |= LINK_FLAGS_DEFERRED_DELETE;
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->TimerSpinLock, &oldirql);
+ InsertTailList (&DeviceContext->LinkDeferred, &TransportLink->DeferredList);
+ if (!(DeviceContext->a.i.LinkDeferredActive)) {
+ StartTimerLinkDeferredDelete++;
+ NbfStartShortTimer (DeviceContext);
+ DeviceContext->a.i.LinkDeferredActive = TRUE;
+ }
+ RELEASE_SPIN_LOCK (&DeviceContext->TimerSpinLock, oldirql);
+
+ } else {
+
+ TransportLink->DeferredFlags |= LINK_FLAGS_DEFERRED_DELETE;
+
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->LinkSpinLock, oldirql1);
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint0 ("NbfDereferenceLink: refcnt=0, link placed on deferred operations queue.\n");
+ }
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint6 ("NbfDerefLink: link on deferred queue %lx %lx %lx %lx %lx Flags: %lx \n",
+ TransportLink, TransportLink->DeferredList.Flink,
+ TransportLink->DeferredList.Blink, DeviceContext->LinkDeferred.Flink,
+ DeviceContext->LinkDeferred.Blink, TransportLink->DeferredFlags);
+ }
+
+ }
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->LinkSpinLock, oldirql1);
+
+ }
+
+} /* NbfDerefLinkSpecial */
+
+
+NTSTATUS
+NbfAssignGroupLsn(
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to assign a global LSN to the connection
+ in question. If successful, it fills in the connection's LSN
+ appropriately.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection object.
+
+Return Value:
+
+ STATUS_SUCCESS if we got an LSN for the connection;
+ STATUS_INSUFFICIENT_RESOURCES if we didn't.
+
+--*/
+
+{
+ KIRQL oldirql;
+ UCHAR Lsn;
+ PDEVICE_CONTEXT DeviceContext;
+ BOOLEAN FoundLsn = FALSE;
+
+ DeviceContext = TransportConnection->Provider;
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ //
+ // Scan through the device context tables to find an LSN that
+ // is not in use, starting with NextLsnStart+128.
+ //
+
+ Lsn = (UCHAR)DeviceContext->NextLsnStart;
+
+ do {
+
+ if (DeviceContext->LsnTable[Lsn] == 0) {
+ DeviceContext->LsnTable[Lsn] = LSN_TABLE_MAX;
+ FoundLsn = TRUE;
+ break;
+ }
+
+ Lsn = (Lsn % NETBIOS_SESSION_LIMIT) + 1;
+
+ } while (Lsn != DeviceContext->NextLsnStart);
+
+ DeviceContext->NextLsnStart = (DeviceContext->NextLsnStart % 64) + 1;
+
+ if (!FoundLsn) {
+
+ //
+ // Could not find an empty LSN; have to fail.
+ //
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+ TransportConnection->Lsn = Lsn;
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ return STATUS_SUCCESS;
+
+}
+
+
+NTSTATUS
+NbfConnectToLink(
+ IN PTP_LINK Link,
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to establish a linkage between a transport
+ connection and a transport link. We find a session number in one
+ of two ways. If the last connection on the link's list has a number less
+ than the maximum session number, we simply increment it's number and
+ assign it to this session. If that doesn't work, we scan through the
+ sessions associated with this link until we find a hole in the LSNs;
+ we then use the first number in that hole. If that fails, we've used
+ the number of sessions we can create on this link and we fail.
+
+ It is assumed that the caller holds at least temporary references
+ on both the connection and link objects, or they could go away during
+ the call sequence or during this routine's execution.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ TransportConnection - Pointer to a transport connection object.
+
+Return Value:
+
+ STATUS_SUCCESS if we got an LSN for the connection;
+ STATUS_INSUFFICIENT_RESOURCES if we didn't.
+
+--*/
+
+{
+ KIRQL oldirql;
+ UCHAR lastSession=0;
+ PTP_CONNECTION connection;
+ PLIST_ENTRY p;
+ PDEVICE_CONTEXT DeviceContext;
+ UCHAR Lsn;
+ BOOLEAN FoundLsn;
+
+ //
+ // Assign an LSN for a new connection. If this connection makes for more
+ // connections than the maximum, blow off the creation.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint2 ("NbfConnectToLink: Entered for connection %lx, link %lx.\n",
+ TransportConnection, Link);
+ }
+
+ DeviceContext = Link->Provider;
+
+ ACQUIRE_SPIN_LOCK (&Link->SpinLock, &oldirql);
+#if DBG
+ if (!(IsListEmpty(&TransportConnection->LinkList)) ||
+ (TransportConnection->Link != NULL)) {
+ DbgPrint ("Connecting C %lx to L %lx, appears to be in use\n", TransportConnection, Link);
+ DbgBreakPoint();
+ }
+#endif
+
+ if ((TransportConnection->Flags2 & CONNECTION_FLAGS2_GROUP_LSN) == 0) {
+
+ //
+ // This connection is to a remote unique name, which means
+ // we need to assign the LSN here based on the link. We
+ // scan through our LSN table starting with NextLsnStart
+ // (which cycles from 1 to 64) to find an LSN which is not
+ // used by any connections on this link.
+ //
+
+ ASSERT (TransportConnection->Lsn == 0);
+
+ FoundLsn = FALSE;
+ Lsn = (UCHAR)DeviceContext->NextLsnStart;
+
+ //
+ // First scan through the database until we reach
+ // Lsn (or hit the end of the database).
+ //
+
+ for (p = Link->ConnectionDatabase.Flink;
+ p != &Link->ConnectionDatabase;
+ p = p->Flink) {
+
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+ if (connection->Lsn >= Lsn) {
+ break;
+ }
+ }
+
+ //
+ // p now points to the first element after Lsn's spot.
+ // We now scan forwards until we hit NETBIOS_SESSION_LIMIT,
+ // looking for an Lsn that is available.
+ //
+
+ for ( ; Lsn <= NETBIOS_SESSION_LIMIT; ++Lsn) {
+
+ //
+ // At some point (perhaps right away) we may
+ // pass the end of the database without finding
+ // an LSN. If we have not yet done this, see
+ // if we need to skip this lsn because it is
+ // in use by a connection on this link.
+ //
+
+ if (p != &Link->ConnectionDatabase) {
+ if (connection->Lsn == Lsn) {
+ p = p->Flink;
+ if (p != &Link->ConnectionDatabase) {
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+ }
+ continue;
+ }
+ }
+
+ //
+ // This lsn is not in use on this link, see if
+ // there is room for it to be used.
+ //
+
+ if (DeviceContext->LsnTable[Lsn] < LSN_TABLE_MAX) {
+ ++(DeviceContext->LsnTable[Lsn]);
+ TransportConnection->Lsn = Lsn;
+ InsertTailList (p, &TransportConnection->LinkList);
+ FoundLsn = TRUE;
+ break;
+ }
+
+ }
+
+ DeviceContext->NextLsnStart = (DeviceContext->NextLsnStart % 64) + 1;
+
+ } else {
+
+ //
+ // This connection is to a group name; we already assigned
+ // the LSN on a global basis.
+ //
+
+ FoundLsn = TRUE;
+
+ //
+ // Find the spot for this LSN in the database.
+ //
+
+ p = Link->ConnectionDatabase.Flink;
+ while (p != &Link->ConnectionDatabase) {
+
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+ if (TransportConnection->Lsn < connection->Lsn) {
+ InsertTailList (p, &TransportConnection->LinkList);
+ break;
+ }
+ p = p->Flink;
+
+ }
+
+ if (p == &Link->ConnectionDatabase) {
+ InsertTailList (&Link->ConnectionDatabase, &TransportConnection->LinkList);
+ }
+
+ }
+
+ if (!FoundLsn) {
+
+ ULONG DumpData = NETBIOS_SESSION_LIMIT;
+
+ ASSERT (Link->ActiveConnectionCount == NETBIOS_SESSION_LIMIT);
+
+ RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql);
+
+ PANIC ("NbfConnectToLink: PANIC! too many active connections!\n");
+
+ NbfWriteGeneralErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_TOO_MANY_LINKS,
+ 602,
+ STATUS_INSUFFICIENT_RESOURCES,
+ NULL,
+ 1,
+ &DumpData);
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+ TransportConnection->Link = Link;
+ TransportConnection->LinkSpinLock = &Link->SpinLock;
+ TransportConnection->Flags |= CONNECTION_FLAGS_WAIT_LINK_UP;
+
+ TransportConnection->LastPacketsSent = Link->PacketsSent;
+ TransportConnection->LastPacketsResent = Link->PacketsResent;
+
+ Link->ActiveConnectionCount++;
+
+ //
+ // Note that the connection is already inserted in the
+ // link's ConnectionDatabase.
+ //
+
+ // This reference is removed in NbfDisconnectFromLink
+ NbfReferenceConnection("Adding link", TransportConnection, CREF_LINK);
+
+ RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql);
+
+ return STATUS_SUCCESS; // we did it!
+
+} /* NbfConnectToLink */
+
+
+BOOLEAN
+NbfDisconnectFromLink(
+ IN PTP_CONNECTION TransportConnection,
+ IN BOOLEAN VerifyReferenceCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to terminate a linkage between a transport
+ connection and its associated transport link. If it turns out that
+ this is the last connection to be removed from this link, then the
+ link's disconnection protocol is engaged.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection object.
+
+ VerifyReferenceCount - TRUE if we should check that the refcount
+ is still -1 before removing the connection from the link.
+ If it is not, it means someone just referenced us and we
+ exit.
+
+Return Value:
+
+ FALSE if VerifyReferenceCount was TRUE but the refcount was
+ not -1; TRUE otherwise.
+
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PTP_LINK Link;
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint2 ("NbfDisconnectFromLink: Entered for connection %lx, link %lx.\n",
+ TransportConnection, TransportConnection->Link);
+ }
+
+ ACQUIRE_C_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql);
+ Link = TransportConnection->Link;
+ if (Link != NULL) {
+
+ ACQUIRE_SPIN_LOCK (&Link->SpinLock, &oldirql1);
+
+ if ((VerifyReferenceCount) &&
+ (TransportConnection->ReferenceCount != -1)) {
+
+ RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql1);
+ RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
+ return FALSE;
+
+ }
+
+ TransportConnection->Link = NULL;
+ TransportConnection->LinkSpinLock = NULL;
+ RemoveEntryList (&TransportConnection->LinkList);
+#if DBG
+ InitializeListHead (&TransportConnection->LinkList);
+#endif
+
+ //
+ // If this was the last connection being serviced by this link,
+ // then we can shut the link down. It still has a reference
+ // from the device context, which will go away in the DM/UA
+ // DLC frame handler.
+ //
+
+ if (--Link->ActiveConnectionCount == 0) {
+
+ //
+ // only want to send DISC if the remote was NOT the originator
+ // of the disconnect.
+ //
+
+ if ((TransportConnection->Status == STATUS_LOCAL_DISCONNECT) ||
+ (TransportConnection->Status == STATUS_CANCELLED)) {
+
+ //
+ // This is a local disconnect of the last connection
+ // on the link, let's get the disconnect ball rolling.
+ //
+
+ Link->Flags |= LINK_FLAGS_LOCAL_DISC;
+
+ //
+ // When the link reference count drops down to 1,
+ // that will cause the DISC to get sent.
+ //
+
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql1);
+
+ //
+ // Clear these now that we are off the link's database.
+ //
+
+ NbfClearConnectionLsn (TransportConnection);
+ TransportConnection->Rsn = 0;
+
+ RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
+
+ if ((TransportConnection->Flags2 & CONNECTION_FLAGS2_CONNECTOR) != 0) {
+
+ (VOID)InterlockedDecrement(&Link->NumberOfConnectors);
+ }
+
+ //
+ // All done with this connection's reference to link.
+ //
+
+ NbfDereferenceLink ("Disconnecting connection",Link, LREF_CONNECTION);
+
+ } else {
+
+ //
+ // A group LSN may have been assigned even though Link is NULL.
+ //
+
+ if ((TransportConnection->Flags2 & CONNECTION_FLAGS2_GROUP_LSN) != 0) {
+ NbfClearConnectionLsn (TransportConnection);
+ }
+
+ RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
+
+ }
+
+ return TRUE;
+
+} /* NbfDisconnectFromLink */
+
+
+PTP_CONNECTION
+NbfLookupPendingListenOnLink(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the LSN database on a transport link object to find
+ a TP_CONNECTION object which has the CONNECTION_FLAGS_WAIT_LINK_UP and
+ CONNECTION_FLAGS2_LISTENER flags set. It returns a pointer to the found
+ connection object (and simultaneously resets the LINK_UP flag) or NULL
+ if it could not be found. The reference count is also incremented
+ atomically on the connection.
+
+ NOTE: THIS ROUTINE MUST BE CALLED FROM DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_CONNECTION connection;
+ PLIST_ENTRY p;
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ for (p = Link->ConnectionDatabase.Flink;
+ p != &Link->ConnectionDatabase;
+ p = p->Flink) {
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+ if ((connection->Flags & CONNECTION_FLAGS_WAIT_LINK_UP) &&
+ (connection->Flags2 & CONNECTION_FLAGS2_LISTENER) &&
+ ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) == 0)) {
+ // This reference is removed by the calling function
+ NbfReferenceConnection ("Found Pending Listen", connection, CREF_P_LINK);
+ connection->Flags &= ~CONNECTION_FLAGS_WAIT_LINK_UP;
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ return connection;
+ }
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ return NULL;
+
+} /* NbfLookupPendingListenOnLink */
+
+
+PTP_CONNECTION
+NbfLookupPendingConnectOnLink(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the LSN database on a transport link object to find
+ a TP_CONNECTION object which has the CONNECTION_FLAGS_WAIT_LINK_UP and
+ CONNECTION_FLAGS2_CONNECTOR flags set. It returns a pointer to the found
+ connection object (and simultaneously resets the LINK_UP flag) or NULL
+ if it could not be found. The reference count is also incremented
+ atomically on the connection.
+
+ NOTE: THIS ROUTINE MUST BE CALLED FROM DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_CONNECTION connection;
+ PLIST_ENTRY p;
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ for (p = Link->ConnectionDatabase.Flink;
+ p != &Link->ConnectionDatabase;
+ p = p->Flink) {
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+ if ((connection->Flags & CONNECTION_FLAGS_WAIT_LINK_UP) &&
+ (connection->Flags2 & CONNECTION_FLAGS2_CONNECTOR) &&
+ ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) == 0)) {
+ // This reference is removed by the calling function
+ NbfReferenceConnection ("Found pending Connect", connection, CREF_P_CONNECT);
+ connection->Flags &= ~CONNECTION_FLAGS_WAIT_LINK_UP;
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ return connection;
+ }
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ return NULL;
+
+} /* NbfLookupPendingConnectOnLink */
+
+
+VOID
+NbfActivateLink(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine activates a link if it is not already active. The other
+ related routines, NbfCreateLink and NbfConnectToLink, simply set up data
+ structures which represent active links so that we can reuse links
+ wherever possible.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint1 ("NbfActivateLink: Entered for link %lx.\n", Link);
+ }
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ switch (Link->State) {
+ case LINK_STATE_READY:
+ NbfCompleteLink (Link);
+ break;
+
+ case LINK_STATE_ADM:
+
+ // Moving out of ADM, add reference
+
+ NbfReferenceLinkSpecial("Wait on ADM", Link, LREF_NOT_ADM);
+
+ //
+ // Intentionally fall through to the next case.
+ //
+
+ case LINK_STATE_W_DISC_RSP:
+ case LINK_STATE_CONNECTING:
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ Link->State = LINK_STATE_CONNECTING;
+ Link->SendState = SEND_STATE_DOWN;
+ Link->ReceiveState = RECEIVE_STATE_DOWN;
+ Link->SendRetries = (UCHAR)Link->LlcRetries;
+ NbfSendSabme (Link, TRUE); // send SABME/p, StartT1, release lock
+ break;
+
+ }
+} /* NbfActivateLink */
+
+
+VOID
+NbfWaitLink(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine waits for a remote link activation if it is not already
+ active.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint1 ("NbfWaitLink: Entered for link %lx.\n", Link);
+ }
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ switch (Link->State) {
+ case LINK_STATE_READY:
+ NbfCompleteLink (Link);
+ break;
+
+ case LINK_STATE_W_DISC_RSP:
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ Link->State = LINK_STATE_CONNECTING;
+ Link->SendState = SEND_STATE_DOWN;
+ Link->ReceiveState = RECEIVE_STATE_DOWN;
+ NbfSendSabme (Link, TRUE); // send SABME/p, StartT1, release lock
+ break;
+
+ }
+} /* NbfWaitLink */
+
+
+VOID
+NbfStopLink(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine terminates a link and all outstanding connections attached
+ to the link. It is called from routines such as ExpireT2Timer, because
+ the remote connection partner seems dead or inoperative. As a consequence
+ of this routine being called, every outstanding connection will have its
+ disconnect handler called (in NbfStopConnection).
+
+ NOTE: THIS ROUTINE MUST BE CALLED FROM DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PTP_PACKET packet;
+ PTP_CONNECTION connection;
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint1 ("NbfStopLink: Entered for link %lx.\n", Link);
+ }
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ // Take a reference so the link won't go away inside this function
+
+ NbfReferenceLink("Temp in NbfStopLink", Link, LREF_STOPPING);
+
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ StopT1 (Link);
+ StopT2 (Link);
+ StopTi (Link);
+
+ p = RemoveHeadList (&Link->ConnectionDatabase);
+
+ while (p != &Link->ConnectionDatabase) {
+
+ //
+ // This will allow this connection to be "removed"
+ // from its link's list in NbfDisconnectFromLink, even if
+ // its not on a list.
+ //
+ InitializeListHead (p);
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint1 ("NbfStopLink stopping connection, refcnt=%ld",
+ connection->ReferenceCount);
+ }
+#if DBG
+ if (NbfDisconnectDebug) {
+ STRING remoteName, localName;
+ remoteName.Length = NETBIOS_NAME_LENGTH - 1;
+ remoteName.Buffer = connection->RemoteName;
+ localName.Length = NETBIOS_NAME_LENGTH - 1;
+ localName.Buffer = connection->AddressFile->Address->NetworkName->NetbiosName;
+ NbfPrint2( "TpStopLink stopping connection to %S from %S\n",
+ &remoteName, &localName );
+ }
+#endif
+ NbfStopConnection (connection, STATUS_LINK_FAILED);
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ p = RemoveHeadList (&Link->ConnectionDatabase);
+ }
+
+ //
+ // We hold the link spinlock here.
+ //
+
+ //
+ // check for left over packets on the link WackQ; we'll never get
+ // acked for these if the link is in ADM mode.
+ //
+
+ while (!IsListEmpty (&Link->WackQ)) {
+ p = RemoveHeadList (&Link->WackQ);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ packet = CONTAINING_RECORD (p, TP_PACKET, Linkage);
+ NbfDereferencePacket (packet);
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ StopT1 (Link);
+ StopT2 (Link);
+ StopTi (Link);
+
+
+ //
+ // Make sure we are not waiting for a deferred RR to be sent.
+ //
+
+ if (Link->OnDeferredRrQueue) {
+
+ ACQUIRE_DPC_SPIN_LOCK (Link->ProviderInterlock);
+ if (Link->OnDeferredRrQueue) {
+ RemoveEntryList (&Link->DeferredRrLinkage);
+ Link->OnDeferredRrQueue = FALSE;
+ }
+ RELEASE_DPC_SPIN_LOCK (Link->ProviderInterlock);
+
+ }
+
+ // Remove the temporary reference.
+
+ NbfDereferenceLink ("Temp in NbfStopLink", Link, LREF_STOPPING);
+
+
+} /* NbfStopLink */
+
+
+VOID
+NbfResetLink(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by DLC.C routines only to reset this link
+ object and restart in-progress transport data transfers.
+
+ NOTE: This routine is called with the link spinlock acquired
+ at *OldIrqlP, and will return with it held, although it may
+ release it in the interim.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ OldIrqlP - Pointer to where the IRQL at which Link->SpinLock
+ was acquired is stored.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PTP_PACKET packet;
+ PLIST_ENTRY p;
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint1 ("NbfResetLink: Entered for link %lx.\n", Link);
+ }
+
+ //
+ // Reset the link state to waiting for connection to start.
+ // Note that this is NOT the same as initiating a new link, as some things
+ // don't change, such as provider (devicecontext binding stays the same),
+ // Max Packet Length (can't change if provider doesn't), and other things
+ // that would bind this link structure to a different provider or provider
+ // type. Note also that we acquire the spinlock because, in the case of a
+ // link that's dropped (remotely) and is restarting, activities on this
+ // link could be occurring while we're in this routine.
+ //
+
+ StopT1 (Link);
+ StopT2 (Link);
+ // StopTi (Link);
+ Link->Flags = 0; // clear this, keep DeferredFlags
+
+ Link->SendState = SEND_STATE_DOWN; // send side is down.
+ Link->NextSend = 0;
+ Link->LastAckReceived = 0;
+ if (Link->Provider->MacInfo.MediumAsync) {
+ Link->SendWindowSize = (UCHAR)Link->Provider->RecommendedSendWindow;
+ Link->PrevWindowSize = (UCHAR)Link->Provider->RecommendedSendWindow;
+ } else {
+ Link->SendWindowSize = (UCHAR)1;
+ Link->PrevWindowSize = (UCHAR)1;
+ }
+ Link->WindowsUntilIncrease = 1;
+ Link->LinkBusy = FALSE;
+ Link->ConsecutiveLastPacketLost = 0;
+
+ //
+ // check for left over packets on the link WackQ; we'll never get
+ // acked for these if the link is resetting.
+ //
+
+ while (!IsListEmpty (&Link->WackQ)) {
+ p = RemoveHeadList (&Link->WackQ);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ packet = CONTAINING_RECORD (p, TP_PACKET, Linkage);
+ NbfDereferencePacket (packet);
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ }
+
+ Link->ReceiveState = RECEIVE_STATE_DOWN; // receive side down.
+ Link->NextReceive = 0;
+ Link->LastAckSent = 0;
+ Link->ReceiveWindowSize = 1;
+
+ Link->WindowErrors = 0;
+ Link->BestWindowSize = 1;
+ Link->WorstWindowSize = (UCHAR)Link->MaxWindowSize;
+ Link->Flags |= LINK_FLAGS_JUMP_START;
+
+ //
+ // This must be accurate before we set up timeouts.
+ //
+
+ Link->CurrentT1Timeout = Link->Provider->DefaultT1Timeout;
+ Link->BaseT1Timeout = Link->Provider->DefaultT1Timeout << DLC_TIMER_ACCURACY;
+ Link->MinimumBaseT1Timeout = Link->Provider->MinimumT1Timeout << DLC_TIMER_ACCURACY;
+ Link->BaseT1RecalcThreshhold = Link->MaxFrameSize / 2;
+ Link->CurrentPollRetransmits = 0;
+ Link->CurrentT1Backoff = FALSE;
+ Link->CurrentPollOutstanding = FALSE;
+ Link->RemoteNoPoll = TRUE;
+ Link->ConsecutiveIFrames = 0;
+ Link->T2Timeout = Link->Provider->DefaultT2Timeout;
+ Link->TiTimeout = Link->Provider->DefaultTiTimeout;
+ Link->LlcRetries = Link->Provider->LlcRetries;
+ Link->MaxWindowSize = Link->Provider->LlcMaxWindowSize;
+
+ Link->SendRetries = (UCHAR)Link->LlcRetries;
+
+} /* NbfResetLink */
+
+
+VOID
+NbfDumpLinkInfo (
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when any of the link timers fire and the
+ link send state is not ready. This gives us a way to track the
+ link state when strange things are happening.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ Link; // avoid compiler warnings in non-debug versions
+
+#if DBG
+ NbfPrint4 ("NbfDumpLinkInfo: Link %lx : State: %x SendState: %x ReceiveState: %x\n",
+ Link, Link->State, Link->SendState, Link->ReceiveState);
+ NbfPrint1 (" Flags: %lx\n",Link->Flags);
+ NbfPrint4 (" NextReceive: %d LastAckRcvd: %d NextSend: %d LastAckSent: %d\n",
+ Link->NextReceive, Link->LastAckReceived, Link->NextSend, Link->LastAckSent);
+#endif
+
+}
diff --git a/private/ntos/tdi/nbf/linktree.c b/private/ntos/tdi/nbf/linktree.c
new file mode 100644
index 000000000..5c62fd8b8
--- /dev/null
+++ b/private/ntos/tdi/nbf/linktree.c
@@ -0,0 +1,537 @@
+/*++
+
+Copyright (c) 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ linktree.c
+
+Abstract:
+
+ This module contains code which implements the management of the link
+ splay tree. This splay tree is maintained to minimize the lookup time
+ needed with each individual packet that comes in. To this end, we create a
+ ULARGE_INTEGER that contains the transport address of the remote and
+ do a ULARGE_INTEGER comaprison of the addresses (rather than comparing
+ the bytes 1 by 1). Assuming that the ULARGE_INTEGER comparison routines are
+ optimized for the hardware on the machine, this should be as fast as or
+ faster than comparing bytes.
+
+ DEBUG: there is currently code in the comparison routines that will let
+ me fine-tune the search and ordering algorithm as we gain more
+ experience with it.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+NTSTATUS
+NbfAddLinkToTree(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds a link to the tree of links maintained for this device.
+ Note that since this routine needs to modify the link tree, it is called
+ in the context of a deferred processing routine, and must have exclusive
+ access to the tree. The spinlock is taken by the routine that calls this
+ one, as this operation must be atomic in the eyes of the rest of NBF.
+ Note further that this routine insists that there not be a link with this
+ address in the tree.
+
+ As the final operation of this insertion, the splay tree is balanced.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ STATUS_SUCCESS if the link is successfully added,
+ STATUS_DRIVER_INTERNAL_ERROR if there was a problem adding
+ the link (implying the tree was in a bad state).
+
+--*/
+{
+ PTP_LINK treeLink;
+ PRTL_SPLAY_LINKS linkLink;
+
+ //
+ // initialize the link and check for the trivial case.
+ //
+
+ RtlInitializeSplayLinks (Link);
+ linkLink = DeviceContext->LinkTreeRoot;
+ if (linkLink == NULL) { // null tree, make this the parent
+ DeviceContext->LinkTreeRoot = (PRTL_SPLAY_LINKS)Link;
+ DeviceContext->LinkTreeElements++;
+ DeviceContext->LastLink = Link;
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Wasn't a null tree, so set up for the addition
+ //
+
+ treeLink = (PTP_LINK) linkLink;
+
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint1 ("NbfAddLinkToTree: starting insert, Elements: %ld \n",DeviceContext->LinkTreeElements);
+ }
+
+ //
+ // find the proper spot to put this link.
+ //
+
+ do {
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint3 ("NbfAddLinkToTree: searching, Link: %lx LC: %lx RC: %lx\n",
+ linkLink, RtlLeftChild (linkLink), RtlRightChild (linkLink));
+ }
+
+ //
+ // Bad news == means we already have this link, someone is messed up.
+ // it's possible to be adding and deleting things at the same time;
+ // that's
+ //
+
+ if ((treeLink->MagicAddress).QuadPart == (Link->MagicAddress).QuadPart) {
+
+ //
+ // First make sure we don't have the splay tree in a loop.
+ //
+
+ ASSERT (treeLink != Link);
+
+ //
+ // This link is already in the tree. This is OK if it is
+ // due to be deleted; we can just do the delete right now,
+ // since AddLinkToTree is only called from the deferred
+ // timer routine.
+ //
+
+ if (treeLink->DeferredFlags & LINK_FLAGS_DEFERRED_DELETE) {
+
+ //
+ // It will be in the deferred list. We remove it,
+ // we don't worry about LinkDeferredActive since
+ // the timeout routine that is calling us handles
+ // that.
+ //
+
+ RemoveEntryList (&treeLink->DeferredList);
+
+ treeLink->DeferredFlags &= ~LINK_FLAGS_DEFERRED_DELETE;
+ NbfRemoveLinkFromTree (DeviceContext, treeLink);
+ NbfDestroyLink (treeLink);
+
+#if DBG
+ NbfPrint2 ("NbfAddLinkToTree: Link %lx removed for %lx\n",
+ treeLink, Link);
+#endif
+
+ //
+ // Now that that link is out of the tree, call
+ // ourselves recursively to do the insert.
+ //
+
+ return NbfAddLinkToTree (DeviceContext, Link);
+
+ } else {
+
+ ASSERTMSG ("NbfAddLinkToTree: Found identical Link in tree!\n", FALSE);
+ return STATUS_DRIVER_INTERNAL_ERROR;
+
+ }
+
+ }
+
+ //
+ // traverse the tree for the correct spot
+ //
+
+ if ((Link->MagicAddress).QuadPart < (treeLink->MagicAddress).QuadPart) {
+ if ((linkLink = RtlLeftChild (linkLink)) == NULL) {
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint0 ("NbfAddLinkToTree: Adding link as LC.\n");
+ }
+ RtlInsertAsLeftChild ((PRTL_SPLAY_LINKS)treeLink,
+ (PRTL_SPLAY_LINKS)Link);
+ // DeviceContext->LinkTreeRoot = RtlSplay (DeviceContext->LinkTreeRoot);
+ DeviceContext->LinkTreeElements++;
+ return STATUS_SUCCESS;
+
+ } else {
+ treeLink = (PTP_LINK) linkLink;
+ continue;
+ } // Left Child
+
+ } else { // is greater
+ if ((linkLink = RtlRightChild (linkLink)) == NULL) {
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint0 ("NbfAddLinkToTree: Adding link as RC.\n");
+ }
+ RtlInsertAsRightChild ((PRTL_SPLAY_LINKS)treeLink,
+ (PRTL_SPLAY_LINKS)Link);
+ // DeviceContext->LinkTreeRoot = RtlSplay (DeviceContext->LinkTreeRoot);
+ DeviceContext->LinkTreeElements++;
+ return STATUS_SUCCESS;
+
+ } else {
+ treeLink = (PTP_LINK) linkLink;
+ continue;
+ } // Right Child
+
+ } // end else addresses comparison
+
+ } while (TRUE);
+
+
+} // NbfAddLinkToTree
+
+
+NTSTATUS
+NbfRemoveLinkFromTree(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes a link from the tree of links.
+ Note that since this routine needs to modify the link tree, it is called
+ in the context of a deferred processing routine, and must have exclusive
+ access to the tree. The spinlock is taken by the routine that calls this
+ one, as this operation must be atomic in the eyes of the rest of NBF.
+ Note further that this routine insists that there not be a link with this
+ address in the tree.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+ DeviceContext - pointer to the device context on which this
+
+Return Value:
+
+ STATUS_SUCCESS if the link was removed,
+ STATUS_DRIVER_INTERNAL_ERROR if there was a problem removing
+ the link (implying the tree was in a bad state).
+
+--*/
+{
+ DeviceContext->LinkTreeRoot = RtlDelete ((PRTL_SPLAY_LINKS)Link);
+ DeviceContext->LinkTreeElements--;
+ if (DeviceContext->LastLink == Link) {
+ DeviceContext->LastLink = (PTP_LINK)DeviceContext->LinkTreeRoot;
+ }
+ return STATUS_SUCCESS;
+
+} //NbfRemoveLinkFromTree
+
+
+
+PTP_LINK
+NbfFindLinkInTree(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR Remote
+ )
+
+/*++
+
+Routine Description:
+
+ This routine traverses the link tree looking for the given remote address.
+ The link tree spinlock is held while looking for the link. After the link
+ is found, it's reference count is incremented.
+
+ NOTE: This function is called with the device context LinkSpinLock
+ held.
+
+Arguments:
+
+ DeviceContext - pointer to the device this address is associated with.
+
+ Remote - pointer to the hardware address of the remote node.
+
+Return Value:
+
+ Pointer to the link in the tree that matches this remote address. If
+ no link is found, NULL is returned.
+
+--*/
+{
+ PTP_LINK link;
+ PRTL_SPLAY_LINKS linkLink;
+ ULARGE_INTEGER Magic = {0,0};
+
+
+ //
+ // Are there even any links in the tree?
+ //
+
+ if (DeviceContext->LinkTreeElements <= 0) {
+ return NULL;
+ }
+
+ linkLink = DeviceContext->LinkTreeRoot;
+
+ //
+ // Make a magic number for this link
+ //
+
+ MacReturnMagicAddress (&DeviceContext->MacInfo, Remote, &Magic);
+
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint1 ("NbfFindLinkInTree: starting search, Elements: %ld \n",
+ DeviceContext->LinkTreeElements);
+ }
+
+ //
+ // Do a quick check if the last link found is this one.
+ //
+
+ ASSERT (DeviceContext->LastLink != NULL);
+
+ if ((DeviceContext->LastLink->MagicAddress).QuadPart == Magic.QuadPart) {
+
+ link = DeviceContext->LastLink;
+
+ } else {
+
+ //
+ // find the link.
+ //
+
+ link = (PTP_LINK) linkLink; // depends upon splay links being first
+ // subfield in link!
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint3 ("NbfFindLinkInTree: searching, Link: %lx LC: %lx RC: %lx \n",
+ linkLink, RtlLeftChild (linkLink), RtlRightChild (linkLink));
+ }
+
+ do {
+
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint4 ("NbfFindLinkInTree: Comparing: %lx%lx to %lx%lx\n",
+ link->MagicAddress.HighPart,link->MagicAddress.LowPart,
+ Magic.HighPart, Magic.LowPart);
+ }
+
+ if ((link->MagicAddress).QuadPart == Magic.QuadPart) {
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint0 ("NbfFindLinkInTree: equal, going to end.\n");
+ }
+ break;
+
+ } else {
+ if ((link->MagicAddress).QuadPart < Magic.QuadPart) {
+ if ((linkLink = RtlRightChild (linkLink)) == NULL) {
+
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint0 ("NbfFindLinkInTree: Link Not Found.\n");
+ }
+ return NULL;
+
+ } else {
+ link = (PTP_LINK) linkLink;
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint3 ("NbfFindLinkInTree: less, took right child, Link: %lx LC: %lx RC: %lx \n",
+ linkLink, RtlLeftChild (linkLink), RtlRightChild (linkLink));
+ }
+ continue;
+ }
+
+ } else { // is greater
+ if ((linkLink = RtlLeftChild (linkLink)) == NULL) {
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint0 ("NbfFindLinkInTree: Link Not Found.\n");
+ }
+ return NULL;
+
+ } else {
+ link = (PTP_LINK) linkLink;
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint3 ("NbfFindLinkInTree: greater, took left child, Link: %lx LC: %lx RC: %lx \n",
+ linkLink, RtlLeftChild (linkLink), RtlRightChild (linkLink));
+ }
+ continue;
+ } // got left child branch
+ } // greater branch
+ } // equal to branch
+ } while (TRUE);
+
+ DeviceContext->LastLink = link;
+
+ }
+
+ //
+ // Only break out when we've actually found a match..
+ //
+
+ if ((link->DeferredFlags & LINK_FLAGS_DEFERRED_DELETE) != 0) {
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint0 ("NbfFindLinkInTree: Link Found but delete pending.\n");
+ }
+ return NULL;
+ }
+
+ //
+ // Mark the link as in use and say we don't need the tree stable any more.
+ //
+
+ NbfReferenceLink ("Found in tree", link, LREF_TREE);
+
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint0 ("NbfFindLinkInTree: Link Found.\n");
+ }
+
+ return link;
+
+} // NbfFindLinkInTree
+
+
+PTP_LINK
+NbfFindLink(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR Remote
+ )
+
+/*++
+
+Routine Description:
+
+ This routine looks for a link in the link tree, and if
+ not found there in the deferred queue.
+
+Arguments:
+
+ DeviceContext - pointer to the device this address is associated with.
+
+ Remote - pointer to the hardware address of the remote node.
+
+Return Value:
+
+ Pointer to the link in the tree that matches this remote address. If
+ no link is found, NULL is returned.
+
+--*/
+
+{
+ PTP_LINK Link;
+ BOOLEAN MatchedLink;
+ PLIST_ENTRY p;
+ UINT i;
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ Link = NbfFindLinkInTree (DeviceContext, Remote);
+
+ if (Link == NULL) {
+
+ //
+ // Not found there, try in deferred queue.
+ //
+
+ MatchedLink = FALSE; // Assume failure
+
+ //
+ // Hold the spinlock while we walk the deferred list. We need
+ // TimerSpinLock to stop the list from changing, and we need
+ // LinkSpinLock to synchronize checking DEFERRED_DELETE and
+ // referencing the link.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ for (p = DeviceContext->LinkDeferred.Flink;
+ p != &DeviceContext->LinkDeferred;
+ p = p->Flink) {
+
+ //
+ // BUGBUG: What about taking a lock while we walk
+ // this list? It won't be removed from at the front,
+ // but it may be added to at the back.
+ //
+
+ //
+ // We're probably still getting this link to the splay tree.
+ // find it and process normally.
+ //
+
+ Link = CONTAINING_RECORD (p, TP_LINK, DeferredList);
+
+ //
+ // NOTE: We know that the link is not going to be destroyed
+ // now, because we have increased the semaphore. We
+ // reference the link if DEFERRED_DELETE is not on; the
+ // setting of this flag is synchronized (also using
+ // DeviceContext->LinkSpinLock) with the refcount going
+ // to 0).
+ //
+
+ if ((Link->DeferredFlags & LINK_FLAGS_DEFERRED_DELETE) != 0) {
+ continue; // we're deleting link, can't handle
+ }
+
+ for (i=0; i<(UINT)DeviceContext->MacInfo.AddressLength; i++) {
+ if (Remote[i] != Link->HardwareAddress.Address[i]){
+ break;
+ }
+ }
+
+ if (i == (UINT)DeviceContext->MacInfo.AddressLength) { // addresses match. Deliver packet.
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 ("NbfFindLink: Found link on deferred queue, Link: %lx\n",
+ Link);
+ }
+ NbfReferenceLink ("Got Frame on Deferred", Link, LREF_TREE);
+ MatchedLink = TRUE;
+ break;
+ }
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ //
+ // If this didn't find the link, make note of that.
+ //
+
+ if (MatchedLink == FALSE) {
+
+ Link = (PTP_LINK)NULL;
+
+ }
+
+ } else {
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 ("NbfFindLink: Found link in tree, Link: %lx\n", Link);
+ }
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ return Link;
+
+}
diff --git a/private/ntos/tdi/nbf/makefile b/private/ntos/tdi/nbf/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/nbf/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/nbf/nbf.h b/private/ntos/tdi/nbf/nbf.h
new file mode 100644
index 000000000..2efb3f50d
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbf.h
@@ -0,0 +1,166 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ nbf.h
+
+Abstract:
+
+ Private include file for the NBF (NetBIOS Frames Protocol) transport
+ provider subcomponent of the NTOS project.
+
+Author:
+
+ Stephen E. Jones (stevej) 25-Oct-1989
+
+Revision History:
+
+ David Beaver (dbeaver) 24-Sep-1990
+ Remove PDI and PC586-specific support; add NDIS support
+
+--*/
+
+#ifndef _NBF_
+#define _NBF_
+
+#include <ntddk.h>
+
+typedef struct _RTL_SPLAY_LINKS {
+ struct _RTL_SPLAY_LINKS *Parent;
+ struct _RTL_SPLAY_LINKS *LeftChild;
+ struct _RTL_SPLAY_LINKS *RightChild;
+} RTL_SPLAY_LINKS;
+typedef RTL_SPLAY_LINKS *PRTL_SPLAY_LINKS;
+
+#define RtlInitializeSplayLinks(Links) { \
+ PRTL_SPLAY_LINKS _SplayLinks; \
+ _SplayLinks = (PRTL_SPLAY_LINKS)(Links); \
+ _SplayLinks->Parent = _SplayLinks; \
+ _SplayLinks->LeftChild = NULL; \
+ _SplayLinks->RightChild = NULL; \
+ }
+
+#define RtlLeftChild(Links) ( \
+ (PRTL_SPLAY_LINKS)(Links)->LeftChild \
+ )
+
+#define RtlRightChild(Links) ( \
+ (PRTL_SPLAY_LINKS)(Links)->RightChild \
+ )
+
+#define RtlInsertAsLeftChild(ParentLinks,ChildLinks) { \
+ PRTL_SPLAY_LINKS _SplayParent; \
+ PRTL_SPLAY_LINKS _SplayChild; \
+ _SplayParent = (PRTL_SPLAY_LINKS)(ParentLinks); \
+ _SplayChild = (PRTL_SPLAY_LINKS)(ChildLinks); \
+ _SplayParent->LeftChild = _SplayChild; \
+ _SplayChild->Parent = _SplayParent; \
+ }
+
+#define RtlInsertAsRightChild(ParentLinks,ChildLinks) { \
+ PRTL_SPLAY_LINKS _SplayParent; \
+ PRTL_SPLAY_LINKS _SplayChild; \
+ _SplayParent = (PRTL_SPLAY_LINKS)(ParentLinks); \
+ _SplayChild = (PRTL_SPLAY_LINKS)(ChildLinks); \
+ _SplayParent->RightChild = _SplayChild; \
+ _SplayChild->Parent = _SplayParent; \
+ }
+
+
+PRTL_SPLAY_LINKS
+NTAPI
+RtlDelete (
+ PRTL_SPLAY_LINKS Links
+ );
+
+
+VOID
+NTAPI
+RtlGetCallersAddress(
+ OUT PVOID *CallersAddress,
+ OUT PVOID *CallersCaller
+ );
+
+#include <tdikrnl.h> // Transport Driver Interface.
+
+#include <ndis.h> // Physical Driver Interface.
+
+#if DEVL
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+#include "nbfconst.h" // private NETBEUI constants.
+#include "nbfmac.h" // mac-specific definitions
+#include "nbfhdrs.h" // private NETBEUI protocol headers.
+#include "nbftypes.h" // private NETBEUI types.
+#include "nbfcnfg.h" // configuration information.
+#include "nbfprocs.h" // private NETBEUI function prototypes.
+#ifdef MEMPRINT
+#include "memprint.h" // drt's memory debug print
+#endif
+
+
+#ifndef NBF_LOCKS
+
+#define ACQUIRE_SPIN_LOCK(lock,irql) KeAcquireSpinLock(lock,irql)
+#define RELEASE_SPIN_LOCK(lock,irql) KeReleaseSpinLock(lock,irql)
+
+#if 0
+#define ACQUIRE_DPC_SPIN_LOCK(lock) \
+ { KIRQL OldIrql; ASSERT ((lock != NULL) && (KeGetCurrentIrql() == DISPATCH_LEVEL)); KeAcquireSpinLock(lock,&OldIrql); }
+#define RELEASE_DPC_SPIN_LOCK(lock) \
+ { ASSERT(lock != NULL); KeReleaseSpinLock(lock,DISPATCH_LEVEL); }
+#else
+#define ACQUIRE_DPC_SPIN_LOCK(lock) KeAcquireSpinLockAtDpcLevel(lock)
+#define RELEASE_DPC_SPIN_LOCK(lock) KeReleaseSpinLockFromDpcLevel(lock)
+#endif
+
+#define ENTER_NBF
+#define LEAVE_NBF
+
+#else
+
+VOID
+NbfAcquireSpinLock(
+ IN PKSPIN_LOCK Lock,
+ OUT PKIRQL OldIrql,
+ IN PSZ LockName,
+ IN PSZ FileName,
+ IN ULONG LineNumber
+ );
+
+VOID
+NbfReleaseSpinLock(
+ IN PKSPIN_LOCK Lock,
+ IN KIRQL OldIrql,
+ IN PSZ LockName,
+ IN PSZ FileName,
+ IN ULONG LineNumber
+ );
+
+#define ACQUIRE_SPIN_LOCK(lock,irql) \
+ NbfAcquireSpinLock( lock, irql, #lock, __FILE__, __LINE__ )
+#define RELEASE_SPIN_LOCK(lock,irql) \
+ NbfReleaseSpinLock( lock, irql, #lock, __FILE__, __LINE__ )
+
+#define ACQUIRE_DPC_SPIN_LOCK(lock) \
+ { \
+ KIRQL OldIrql; \
+ NbfAcquireSpinLock( lock, &OldIrql, #lock, __FILE__, __LINE__ ); \
+ }
+#define RELEASE_DPC_SPIN_LOCK(lock) \
+ NbfReleaseSpinLock( lock, DISPATCH_LEVEL, #lock, __FILE__, __LINE__ )
+
+#define ENTER_NBF \
+ NbfAcquireSpinLock( (PKSPIN_LOCK)NULL, (PKIRQL)NULL, "(Global)", __FILE__, __LINE__ )
+#define LEAVE_NBF \
+ NbfReleaseSpinLock( (PKSPIN_LOCK)NULL, (KIRQL)-1, "(Global)", __FILE__, __LINE__ )
+
+#endif
+
+
+#endif // def _NBF_
diff --git a/private/ntos/tdi/nbf/nbf.rc b/private/ntos/tdi/nbf/nbf.rc
new file mode 100644
index 000000000..be3b9d409
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbf.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "NetBEUI Frames Protocol Driver"
+#define VER_INTERNALNAME_STR "nbf.sys"
+#define VER_ORIGINALFILENAME_STR "nbf.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/tdi/nbf/nbfcnfg.c b/private/ntos/tdi/nbf/nbfcnfg.c
new file mode 100644
index 000000000..30d0a02f3
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbfcnfg.c
@@ -0,0 +1,1155 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ nbfconfig.c
+
+Abstract:
+
+ This contains all routines necessary for the support of the dynamic
+ configuration of NBF. Note that the parts of this file that are
+ called at initialization time will be replaced by calls to the configuration manager over time.
+
+Author:
+
+ David Beaver (dbeaver) 13-Feb-1991
+
+Revision History:
+
+ David Beaver (dbeaver) 1-July-1991
+ modified to use new tdi interface
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Local functions used to access the registry.
+//
+
+VOID
+NbfFreeConfigurationInfo (
+ IN PCONFIG_DATA ConfigurationInfo
+ );
+
+NTSTATUS
+NbfOpenParametersKey(
+ IN HANDLE NbfConfigHandle,
+ OUT PHANDLE ParametersHandle
+ );
+
+VOID
+NbfCloseParametersKey(
+ IN HANDLE ParametersHandle
+ );
+
+NTSTATUS
+NbfCountEntries(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+NbfAddBind(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+NbfAddExport(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+VOID
+NbfReadLinkageInformation(
+ IN PWSTR RegistryPathBuffer,
+ IN PCONFIG_DATA * ConfigurationInfo
+ );
+
+ULONG
+NbfReadSingleParameter(
+ IN HANDLE ParametersHandle,
+ IN PWCHAR ValueName,
+ IN ULONG DefaultValue
+ );
+
+VOID
+NbfWriteSingleParameter(
+ IN HANDLE ParametersHandle,
+ IN PWCHAR ValueName,
+ IN ULONG ValueData
+ );
+
+UINT
+NbfWstrLength(
+ IN PWSTR Wstr
+ );
+
+#ifdef ALLOC_PRAGMA
+#ifndef _PNP_POWER
+#pragma alloc_text(INIT,NbfWstrLength)
+#pragma alloc_text(INIT,NbfConfigureTransport)
+#pragma alloc_text(INIT,NbfFreeConfigurationInfo)
+#pragma alloc_text(INIT,NbfOpenParametersKey)
+#pragma alloc_text(INIT,NbfCloseParametersKey)
+#pragma alloc_text(INIT,NbfCountEntries)
+#pragma alloc_text(INIT,NbfAddBind)
+#pragma alloc_text(INIT,NbfAddExport)
+#pragma alloc_text(INIT,NbfReadLinkageInformation)
+#pragma alloc_text(INIT,NbfReadSingleParameter)
+#pragma alloc_text(INIT,NbfWriteSingleParameter)
+#else
+#pragma alloc_text(PAGE,NbfWstrLength)
+#pragma alloc_text(PAGE,NbfConfigureTransport)
+#pragma alloc_text(PAGE,NbfFreeConfigurationInfo)
+#pragma alloc_text(PAGE,NbfOpenParametersKey)
+#pragma alloc_text(PAGE,NbfCloseParametersKey)
+#pragma alloc_text(PAGE,NbfCountEntries)
+#pragma alloc_text(PAGE,NbfAddBind)
+#pragma alloc_text(PAGE,NbfAddExport)
+#pragma alloc_text(PAGE,NbfReadLinkageInformation)
+#pragma alloc_text(PAGE,NbfReadSingleParameter)
+#pragma alloc_text(PAGE,NbfWriteSingleParameter)
+#endif
+#endif
+
+UINT
+NbfWstrLength(
+ IN PWSTR Wstr
+ )
+{
+ UINT Length = 0;
+ while (*Wstr++) {
+ Length += sizeof(WCHAR);
+ }
+ return Length;
+}
+
+#define InsertAdapter(ConfigurationInfo, Subscript, Name) \
+{ \
+ PWSTR _S; \
+ PWSTR _N = (Name); \
+ UINT _L = NbfWstrLength(_N)+sizeof(WCHAR); \
+ _S = (PWSTR)ExAllocatePoolWithTag(NonPagedPool, _L, ' FBN'); \
+ if (_S != NULL) { \
+ RtlCopyMemory(_S, _N, _L); \
+ RtlInitUnicodeString (&(ConfigurationInfo)->Names[Subscript], _S); \
+ } \
+}
+
+#define InsertDevice(ConfigurationInfo, Subscript, Name) \
+{ \
+ PWSTR _S; \
+ PWSTR _N = (Name); \
+ UINT _L = NbfWstrLength(_N)+sizeof(WCHAR); \
+ _S = (PWSTR)ExAllocatePoolWithTag(NonPagedPool, _L, ' FBN'); \
+ if (_S != NULL) { \
+ RtlCopyMemory(_S, _N, _L); \
+ RtlInitUnicodeString (&(ConfigurationInfo)->Names[(ConfigurationInfo)->DevicesOffset+Subscript], _S); \
+ } \
+}
+
+
+#define RemoveAdapter(ConfigurationInfo, Subscript) \
+ ExFreePool ((ConfigurationInfo)->Names[Subscript].Buffer)
+
+#define RemoveDevice(ConfigurationInfo, Subscript) \
+ ExFreePool ((ConfigurationInfo)->Names[(ConfigurationInfo)->DevicesOffset+Subscript].Buffer)
+
+
+
+//
+// These strings are used in various places by the registry.
+//
+
+#define DECLARE_STRING(_str_) WCHAR Str ## _str_[] = L#_str_
+
+
+#define READ_HIDDEN_CONFIG(_Field) \
+{ \
+ ConfigurationInfo->_Field = \
+ NbfReadSingleParameter( \
+ ParametersHandle, \
+ Str ## _Field, \
+ ConfigurationInfo->_Field); \
+}
+
+#define WRITE_HIDDEN_CONFIG(_Field) \
+{ \
+ NbfWriteSingleParameter( \
+ ParametersHandle, \
+ Str ## _Field, \
+ ConfigurationInfo->_Field); \
+}
+
+
+
+NTSTATUS
+NbfConfigureTransport (
+ IN PUNICODE_STRING RegistryPath,
+ IN PCONFIG_DATA * ConfigurationInfoPtr
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by NBF to get information from the configuration
+ management routines. We read the registry, starting at RegistryPath,
+ to get the parameters. If they don't exist, we use the defaults
+ set in nbfcnfg.h file.
+
+Arguments:
+
+ RegistryPath - The name of NBF's node in the registry.
+
+ ConfigurationInfoPtr - A pointer to the configuration information structure.
+
+Return Value:
+
+ Status - STATUS_SUCCESS if everything OK, STATUS_INSUFFICIENT_RESOURCES
+ otherwise.
+
+--*/
+{
+
+ NTSTATUS OpenStatus;
+ HANDLE ParametersHandle;
+ HANDLE NbfConfigHandle;
+ NTSTATUS Status;
+ ULONG Disposition;
+ PWSTR RegistryPathBuffer;
+ OBJECT_ATTRIBUTES TmpObjectAttributes;
+ PCONFIG_DATA ConfigurationInfo;
+
+ DECLARE_STRING(InitRequests);
+ DECLARE_STRING(InitLinks);
+ DECLARE_STRING(InitConnections);
+ DECLARE_STRING(InitAddressFiles);
+ DECLARE_STRING(InitAddresses);
+
+ DECLARE_STRING(MaxRequests);
+ DECLARE_STRING(MaxLinks);
+ DECLARE_STRING(MaxConnections);
+ DECLARE_STRING(MaxAddressFiles);
+ DECLARE_STRING(MaxAddresses);
+
+ DECLARE_STRING(InitPackets);
+ DECLARE_STRING(InitReceivePackets);
+ DECLARE_STRING(InitReceiveBuffers);
+ DECLARE_STRING(InitUIFrames);
+
+ DECLARE_STRING(SendPacketPoolSize);
+ DECLARE_STRING(ReceivePacketPoolSize);
+ DECLARE_STRING(MaxMemoryUsage);
+
+ DECLARE_STRING(DefaultT1Timeout);
+ DECLARE_STRING(DefaultT2Timeout);
+ DECLARE_STRING(DefaultTiTimeout);
+ DECLARE_STRING(LlcRetries);
+ DECLARE_STRING(LlcMaxWindowSize);
+ DECLARE_STRING(MaximumIncomingFrames);
+
+ DECLARE_STRING(NameQueryRetries);
+ DECLARE_STRING(NameQueryTimeout);
+ DECLARE_STRING(AddNameQueryRetries);
+ DECLARE_STRING(AddNameQueryTimeout);
+ DECLARE_STRING(GeneralRetries);
+ DECLARE_STRING(GeneralTimeout);
+ DECLARE_STRING(WanNameQueryRetries);
+
+ DECLARE_STRING(UseDixOverEthernet);
+ DECLARE_STRING(QueryWithoutSourceRouting);
+ DECLARE_STRING(AllRoutesNameRecognized);
+ DECLARE_STRING(MinimumSendWindowLimit);
+
+ //
+ // Open the registry.
+ //
+
+ InitializeObjectAttributes(
+ &TmpObjectAttributes,
+ RegistryPath, // name
+ OBJ_CASE_INSENSITIVE, // attributes
+ NULL, // root
+ NULL // security descriptor
+ );
+
+ Status = ZwCreateKey(
+ &NbfConfigHandle,
+ KEY_WRITE,
+ &TmpObjectAttributes,
+ 0, // title index
+ NULL, // class
+ 0, // create options
+ &Disposition); // disposition
+
+ if (!NT_SUCCESS(Status)) {
+ NbfPrint1("NBF: Could not open/create NBF key: %lx\n", Status);
+ return Status;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_REGISTRY) {
+ NbfPrint2("%s NBF key: %lx\n",
+ (Disposition == REG_CREATED_NEW_KEY) ? "created" : "opened",
+ NbfConfigHandle);
+ }
+
+
+ OpenStatus = NbfOpenParametersKey (NbfConfigHandle, &ParametersHandle);
+
+ if (OpenStatus != STATUS_SUCCESS) {
+ return OpenStatus;
+ }
+
+ //
+ // Read in the NDIS binding information (if none is present
+ // the array will be filled with all known drivers).
+ //
+ // NbfReadLinkageInformation expects a null-terminated path,
+ // so we have to create one from the UNICODE_STRING.
+ //
+
+ RegistryPathBuffer = (PWSTR)ExAllocatePoolWithTag(
+ NonPagedPool,
+ RegistryPath->Length + sizeof(WCHAR),
+ ' FBN');
+ if (RegistryPathBuffer == NULL) {
+ NbfCloseParametersKey (ParametersHandle);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ RtlCopyMemory (RegistryPathBuffer, RegistryPath->Buffer, RegistryPath->Length);
+ *(PWCHAR)(((PUCHAR)RegistryPathBuffer)+RegistryPath->Length) = (WCHAR)'\0';
+
+ NbfReadLinkageInformation (RegistryPathBuffer, ConfigurationInfoPtr);
+
+ if (*ConfigurationInfoPtr == NULL) {
+ ExFreePool (RegistryPathBuffer);
+ NbfCloseParametersKey (ParametersHandle);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ ConfigurationInfo = *ConfigurationInfoPtr;
+
+
+ //
+ // Configure the initial values for some NBF resources.
+ //
+
+ ConfigurationInfo->InitRequests = 1;
+ ConfigurationInfo->InitLinks = 2;
+ ConfigurationInfo->InitConnections = 2;
+ ConfigurationInfo->InitAddressFiles = 0;
+ ConfigurationInfo->InitAddresses = 0;
+
+ //
+ // These are the initial values; remember that the
+ // resources above also allocate some of these each
+ // time they are allocated (shown in the comment).
+ //
+
+ ConfigurationInfo->InitPackets = 30; // + link + 2*conn
+ ConfigurationInfo->InitReceivePackets = 10; // + link + addr
+ ConfigurationInfo->InitReceiveBuffers = 5; // + addr
+ ConfigurationInfo->InitUIFrames = 5; // + addr + conn
+
+ //
+ // Set the size of the packet pools and the total
+ // allocateable by NBF.
+ //
+
+ ConfigurationInfo->SendPacketPoolSize = 100;
+ ConfigurationInfo->ReceivePacketPoolSize = 30;
+ ConfigurationInfo->MaxMemoryUsage = 0; // no limit
+
+
+ //
+ // Now initialize the timeout etc. values.
+ //
+
+ ConfigurationInfo->DefaultT1Timeout = DLC_DEFAULT_T1;
+ ConfigurationInfo->DefaultT2Timeout = DLC_DEFAULT_T2;
+ ConfigurationInfo->DefaultTiTimeout = DLC_DEFAULT_TI;
+ ConfigurationInfo->LlcRetries = DLC_RETRIES;
+ ConfigurationInfo->LlcMaxWindowSize = DLC_WINDOW_LIMIT;
+ ConfigurationInfo->MaximumIncomingFrames = 4;
+ ConfigurationInfo->NameQueryRetries = NAME_QUERY_RETRIES;
+ ConfigurationInfo->NameQueryTimeout = NAME_QUERY_TIMEOUT;
+ ConfigurationInfo->AddNameQueryRetries = ADD_NAME_QUERY_RETRIES;
+ ConfigurationInfo->AddNameQueryTimeout = ADD_NAME_QUERY_TIMEOUT;
+ ConfigurationInfo->GeneralRetries = NAME_QUERY_RETRIES;
+ ConfigurationInfo->GeneralTimeout = NAME_QUERY_TIMEOUT;
+ ConfigurationInfo->WanNameQueryRetries = WAN_NAME_QUERY_RETRIES;
+
+ ConfigurationInfo->UseDixOverEthernet = 0;
+ ConfigurationInfo->QueryWithoutSourceRouting = 0;
+ ConfigurationInfo->AllRoutesNameRecognized = 0;
+ ConfigurationInfo->MinimumSendWindowLimit = 2;
+
+
+ //
+ // Now read the optional "hidden" parameters; if these do
+ // not exist then the current values are used. Note that
+ // the current values will be 0 unless they have been
+ // explicitly initialized above.
+ //
+ // NOTE: These macros expect "ConfigurationInfo" and
+ // "ParametersHandle" to exist when they are expanded.
+ //
+
+ READ_HIDDEN_CONFIG (InitRequests);
+ READ_HIDDEN_CONFIG (InitLinks);
+ READ_HIDDEN_CONFIG (InitConnections);
+ READ_HIDDEN_CONFIG (InitAddressFiles);
+ READ_HIDDEN_CONFIG (InitAddresses);
+
+ READ_HIDDEN_CONFIG (MaxRequests);
+ READ_HIDDEN_CONFIG (MaxLinks);
+ READ_HIDDEN_CONFIG (MaxConnections);
+ READ_HIDDEN_CONFIG (MaxAddressFiles);
+ READ_HIDDEN_CONFIG (MaxAddresses);
+
+ READ_HIDDEN_CONFIG (InitPackets);
+ READ_HIDDEN_CONFIG (InitReceivePackets);
+ READ_HIDDEN_CONFIG (InitReceiveBuffers);
+ READ_HIDDEN_CONFIG (InitUIFrames);
+
+ READ_HIDDEN_CONFIG (SendPacketPoolSize);
+ READ_HIDDEN_CONFIG (ReceivePacketPoolSize);
+ READ_HIDDEN_CONFIG (MaxMemoryUsage);
+
+ READ_HIDDEN_CONFIG (DefaultT1Timeout);
+ READ_HIDDEN_CONFIG (DefaultT2Timeout);
+ READ_HIDDEN_CONFIG (DefaultTiTimeout);
+ READ_HIDDEN_CONFIG (LlcRetries);
+ READ_HIDDEN_CONFIG (LlcMaxWindowSize);
+ READ_HIDDEN_CONFIG (MaximumIncomingFrames);
+
+ READ_HIDDEN_CONFIG (NameQueryRetries);
+ READ_HIDDEN_CONFIG (NameQueryTimeout);
+ READ_HIDDEN_CONFIG (AddNameQueryRetries);
+ READ_HIDDEN_CONFIG (AddNameQueryTimeout);
+ READ_HIDDEN_CONFIG (GeneralRetries);
+ READ_HIDDEN_CONFIG (GeneralTimeout);
+ READ_HIDDEN_CONFIG (WanNameQueryRetries);
+
+ READ_HIDDEN_CONFIG (UseDixOverEthernet);
+ READ_HIDDEN_CONFIG (QueryWithoutSourceRouting);
+ READ_HIDDEN_CONFIG (AllRoutesNameRecognized);
+ READ_HIDDEN_CONFIG (MinimumSendWindowLimit);
+
+
+ //
+ // Print out some config info, to make sure it is read right.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_REGISTRY) {
+ NbfPrint2("Links: init %d, max %d\n",
+ ConfigurationInfo->InitLinks,
+ ConfigurationInfo->MaxLinks);
+ NbfPrint3("Timeouts (NBF ticks): T1 %d, T2 %d, Ti %d\n",
+ ConfigurationInfo->DefaultT1Timeout / SHORT_TIMER_DELTA,
+ ConfigurationInfo->DefaultT2Timeout / SHORT_TIMER_DELTA,
+ ConfigurationInfo->DefaultTiTimeout / LONG_TIMER_DELTA);
+ NbfPrint2("Pools: send %d, receive %d\n",
+ ConfigurationInfo->SendPacketPoolSize,
+ ConfigurationInfo->ReceivePacketPoolSize);
+ NbfPrint1("Max mem %d\n",
+ ConfigurationInfo->MaxMemoryUsage);
+ NbfPrint2("NQRetries %d, NQTimeout %d\n",
+ ConfigurationInfo->NameQueryRetries,
+ ConfigurationInfo->NameQueryTimeout / SHORT_TIMER_DELTA);
+ }
+
+ //
+ // Save the "hidden" parameters, these may not exist in
+ // the registry.
+ //
+ // NOTE: These macros expect "ConfigurationInfo" and
+ // "ParametersHandle" to exist when they are expanded.
+ //
+
+ //
+ // 5/22/92 - don't write the parameters that are set
+ // based on Size, since otherwise these will overwrite
+ // those values since hidden parameters are set up
+ // after the Size-based configuration is done.
+ //
+
+ WRITE_HIDDEN_CONFIG (MaxRequests);
+ WRITE_HIDDEN_CONFIG (MaxLinks);
+ WRITE_HIDDEN_CONFIG (MaxConnections);
+ WRITE_HIDDEN_CONFIG (MaxAddressFiles);
+ WRITE_HIDDEN_CONFIG (MaxAddresses);
+
+ WRITE_HIDDEN_CONFIG (DefaultT1Timeout);
+ WRITE_HIDDEN_CONFIG (DefaultT2Timeout);
+ WRITE_HIDDEN_CONFIG (DefaultTiTimeout);
+ WRITE_HIDDEN_CONFIG (LlcRetries);
+ WRITE_HIDDEN_CONFIG (LlcMaxWindowSize);
+ WRITE_HIDDEN_CONFIG (MaximumIncomingFrames);
+
+ WRITE_HIDDEN_CONFIG (NameQueryRetries);
+ WRITE_HIDDEN_CONFIG (NameQueryTimeout);
+ WRITE_HIDDEN_CONFIG (AddNameQueryRetries);
+ WRITE_HIDDEN_CONFIG (AddNameQueryTimeout);
+ WRITE_HIDDEN_CONFIG (GeneralRetries);
+ WRITE_HIDDEN_CONFIG (GeneralTimeout);
+ WRITE_HIDDEN_CONFIG (WanNameQueryRetries);
+
+ WRITE_HIDDEN_CONFIG (UseDixOverEthernet);
+ WRITE_HIDDEN_CONFIG (QueryWithoutSourceRouting);
+ WRITE_HIDDEN_CONFIG (AllRoutesNameRecognized);
+
+ // ZwFlushKey (ParametersHandle);
+
+ ExFreePool (RegistryPathBuffer);
+ NbfCloseParametersKey (ParametersHandle);
+ ZwClose (NbfConfigHandle);
+
+ return STATUS_SUCCESS;
+
+} /* NbfConfigureTransport */
+
+
+VOID
+NbfFreeConfigurationInfo (
+ IN PCONFIG_DATA ConfigurationInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NBF to get free any storage that was allocated
+ by NbfConfigureTransport in producing the specified CONFIG_DATA structure.
+
+Arguments:
+
+ ConfigurationInfo - A pointer to the configuration information structure.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UINT i;
+
+ for (i=0; i<ConfigurationInfo->NumAdapters; i++) {
+ RemoveAdapter (ConfigurationInfo, i);
+ RemoveDevice (ConfigurationInfo, i);
+ }
+ ExFreePool (ConfigurationInfo);
+
+} /* NbfFreeConfigurationInfo */
+
+
+NTSTATUS
+NbfOpenParametersKey(
+ IN HANDLE NbfConfigHandle,
+ OUT PHANDLE ParametersHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NBF to open the NBF "Parameters" key.
+
+Arguments:
+
+ ParametersHandle - Returns the handle used to read parameters.
+
+Return Value:
+
+ The status of the request.
+
+--*/
+{
+
+ NTSTATUS Status;
+ HANDLE ParamHandle;
+ PWSTR ParametersString = L"Parameters";
+ UNICODE_STRING ParametersKeyName;
+ OBJECT_ATTRIBUTES TmpObjectAttributes;
+
+ //
+ // Open the NBF parameters key.
+ //
+
+ RtlInitUnicodeString (&ParametersKeyName, ParametersString);
+
+ InitializeObjectAttributes(
+ &TmpObjectAttributes,
+ &ParametersKeyName, // name
+ OBJ_CASE_INSENSITIVE, // attributes
+ NbfConfigHandle, // root
+ NULL // security descriptor
+ );
+
+
+ Status = ZwOpenKey(
+ &ParamHandle,
+ KEY_READ,
+ &TmpObjectAttributes);
+
+ if (!NT_SUCCESS(Status)) {
+
+ NbfPrint1("Could not open parameters key: %lx\n", Status);
+ return Status;
+
+ }
+
+ IF_NBFDBG (NBF_DEBUG_REGISTRY) {
+ NbfPrint1("Opened parameters key: %lx\n", ParamHandle);
+ }
+
+
+ *ParametersHandle = ParamHandle;
+
+
+ //
+ // All keys successfully opened or created.
+ //
+
+ return STATUS_SUCCESS;
+
+} /* NbfOpenParametersKey */
+
+VOID
+NbfCloseParametersKey(
+ IN HANDLE ParametersHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NBF to close the "Parameters" key.
+ It closes the handles passed in and does any other work needed.
+
+Arguments:
+
+ ParametersHandle - The handle used to read other parameters.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ZwClose (ParametersHandle);
+
+} /* NbfCloseParametersKey */
+
+
+NTSTATUS
+NbfCountEntries(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called with the "Bind" and "Export" multi-strings.
+ It counts the number of name entries required in the
+ CONFIGURATION_DATA structure and then allocates it.
+
+Arguments:
+
+ ValueName - The name of the value ("Bind" or "Export" -- ignored).
+
+ ValueType - The type of the value (REG_MULTI_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to a pointer to the ConfigurationInfo structure.
+ When the "Export" callback is made this is filled in
+ with the allocate structure.
+
+ EntryContext - A pointer to a counter holding the total number
+ of name entries required.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ ULONG StringCount;
+ PWCHAR ValuePointer = (PWCHAR)ValueData;
+ PCONFIG_DATA * ConfigurationInfo = (PCONFIG_DATA *)Context;
+ PULONG TotalCount = ((PULONG)EntryContext);
+ ULONG OldTotalCount = *TotalCount;
+
+#if DBG
+ ASSERT (ValueType == REG_MULTI_SZ);
+#else
+ UNREFERENCED_PARAMETER(ValueType);
+#endif
+
+ //
+ // Count the number of strings in the multi-string; first
+ // check that it is NULL-terminated to make the rest
+ // easier.
+ //
+
+ if ((ValueLength < 2) ||
+ (ValuePointer[(ValueLength/2)-1] != (WCHAR)'\0')) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ StringCount = 0;
+ while (*ValuePointer != (WCHAR)'\0') {
+ while (*ValuePointer != (WCHAR)'\0') {
+ ++ValuePointer;
+ }
+ ++StringCount;
+ ++ValuePointer;
+ if ((ULONG)((PUCHAR)ValuePointer - (PUCHAR)ValueData) >= ValueLength) {
+ break;
+ }
+ }
+
+ (*TotalCount) += StringCount;
+
+ if (*ValueName == (WCHAR)'E') {
+
+ //
+ // This is "Export", allocate the config data structure.
+ //
+
+ *ConfigurationInfo = ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof (CONFIG_DATA) +
+ ((*TotalCount-1) * sizeof(NDIS_STRING)),
+ ' FBN');
+
+ if (*ConfigurationInfo == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(
+ *ConfigurationInfo,
+ sizeof(CONFIG_DATA) + ((*TotalCount-1) * sizeof(NDIS_STRING)));
+
+ (*ConfigurationInfo)->DevicesOffset = OldTotalCount;
+
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbfCountEntries */
+
+
+NTSTATUS
+NbfAddBind(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Bind" multi-string and
+ saves the information in a ConfigurationInfo structure.
+
+Arguments:
+
+ ValueName - The name of the value ("Bind" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to the ConfigurationInfo structure.
+
+ EntryContext - A pointer to a count of binds that is incremented.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG_DATA ConfigurationInfo = *(PCONFIG_DATA *)Context;
+ PULONG CurBindNum = ((PULONG)EntryContext);
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+
+ InsertAdapter(
+ ConfigurationInfo,
+ *CurBindNum,
+ (PWSTR)(ValueData));
+
+ ++(*CurBindNum);
+
+ return STATUS_SUCCESS;
+
+} /* NbfAddBind */
+
+
+NTSTATUS
+NbfAddExport(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Export" multi-string and
+ saves the information in a ConfigurationInfo structure.
+
+Arguments:
+
+ ValueName - The name of the value ("Export" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to the ConfigurationInfo structure.
+
+ EntryContext - A pointer to a count of exports that is incremented.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG_DATA ConfigurationInfo = *(PCONFIG_DATA *)Context;
+ PULONG CurExportNum = ((PULONG)EntryContext);
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+
+ InsertDevice(
+ ConfigurationInfo,
+ *CurExportNum,
+ (PWSTR)(ValueData));
+
+ ++(*CurExportNum);
+
+ return STATUS_SUCCESS;
+
+} /* NbfAddExport */
+
+
+VOID
+NbfReadLinkageInformation(
+ IN PWSTR RegistryPathBuffer,
+ IN PCONFIG_DATA * ConfigurationInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NBF to read its linkage information
+ from the registry. If there is none present, then ConfigData
+ is filled with a list of all the adapters that are known
+ to NBF.
+
+Arguments:
+
+ RegistryPathBuffer - The null-terminated root of the NBF registry tree.
+
+ ConfigurationInfo - Returns NBF's current configuration.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UINT ConfigBindings;
+ UINT NameCount = 0;
+ NTSTATUS Status;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[6];
+ PWSTR Subkey = L"Linkage";
+ PWSTR Bind = L"Bind";
+ PWSTR Export = L"Export";
+ ULONG BindCount, ExportCount;
+ UINT i;
+
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Linkage key below NBF
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Subkey;
+
+ //
+ // 2) Call NbfCountEntries for the "Bind" multi-string
+ //
+
+ QueryTable[1].QueryRoutine = NbfCountEntries;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ QueryTable[1].Name = Bind;
+ QueryTable[1].EntryContext = (PVOID)&NameCount;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Call NbfCountEntries for the "Export" multi-string
+ //
+
+ QueryTable[2].QueryRoutine = NbfCountEntries;
+ QueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ QueryTable[2].Name = Export;
+ QueryTable[2].EntryContext = (PVOID)&NameCount;
+ QueryTable[2].DefaultType = REG_NONE;
+
+ //
+ // 4) Call NbfAddBind for each string in "Bind"
+ //
+
+ QueryTable[3].QueryRoutine = NbfAddBind;
+ QueryTable[3].Flags = 0;
+ QueryTable[3].Name = Bind;
+ QueryTable[3].EntryContext = (PVOID)&BindCount;
+ QueryTable[3].DefaultType = REG_NONE;
+
+ //
+ // 5) Call NbfAddExport for each string in "Export"
+ //
+
+ QueryTable[4].QueryRoutine = NbfAddExport;
+ QueryTable[4].Flags = 0;
+ QueryTable[4].Name = Export;
+ QueryTable[4].EntryContext = (PVOID)&ExportCount;
+ QueryTable[4].DefaultType = REG_NONE;
+
+ //
+ // 6) Stop
+ //
+
+ QueryTable[5].QueryRoutine = NULL;
+ QueryTable[5].Flags = 0;
+ QueryTable[5].Name = NULL;
+
+
+ BindCount = 0;
+ ExportCount = 0;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ RegistryPathBuffer,
+ QueryTable,
+ (PVOID)ConfigurationInfo,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+ return;
+ }
+
+ //
+ // Make sure that BindCount and ExportCount match, if not
+ // remove the extras.
+ //
+
+ if (BindCount < ExportCount) {
+
+ for (i=BindCount; i<ExportCount; i++) {
+ RemoveDevice (*ConfigurationInfo, i);
+ }
+ ConfigBindings = BindCount;
+
+ } else if (ExportCount < BindCount) {
+
+ for (i=ExportCount; i<BindCount; i++) {
+ RemoveAdapter (*ConfigurationInfo, i);
+ }
+ ConfigBindings = ExportCount;
+
+ } else {
+
+ ConfigBindings = BindCount; // which is equal to ExportCount
+
+ }
+
+ (*ConfigurationInfo)->NumAdapters = ConfigBindings;
+
+} /* NbfReadLinkageInformation */
+
+
+ULONG
+NbfReadSingleParameter(
+ IN HANDLE ParametersHandle,
+ IN PWCHAR ValueName,
+ IN ULONG DefaultValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NBF to read a single parameter
+ from the registry. If the parameter is found it is stored
+ in Data.
+
+Arguments:
+
+ ParametersHandle - A pointer to the open registry.
+
+ ValueName - The name of the value to search for.
+
+ DefaultValue - The default value.
+
+Return Value:
+
+ The value to use; will be the default if the value is not
+ found or is not in the correct range.
+
+--*/
+
+{
+ ULONG InformationBuffer[32]; // declare ULONG to get it aligned
+ PKEY_VALUE_FULL_INFORMATION Information =
+ (PKEY_VALUE_FULL_INFORMATION)InformationBuffer;
+ UNICODE_STRING ValueKeyName;
+ ULONG InformationLength;
+ ULONG ReturnValue;
+ NTSTATUS Status;
+
+ RtlInitUnicodeString (&ValueKeyName, ValueName);
+
+ Status = ZwQueryValueKey(
+ ParametersHandle,
+ &ValueKeyName,
+ KeyValueFullInformation,
+ (PVOID)Information,
+ sizeof (InformationBuffer),
+ &InformationLength);
+
+ if ((Status == STATUS_SUCCESS) &&
+ (Information->DataLength == sizeof(ULONG))) {
+
+ RtlCopyMemory(
+ (PVOID)&ReturnValue,
+ ((PUCHAR)Information) + Information->DataOffset,
+ sizeof(ULONG));
+
+ if (ReturnValue < 0) {
+
+ ReturnValue = DefaultValue;
+
+ }
+
+ } else {
+
+ ReturnValue = DefaultValue;
+
+ }
+
+ return ReturnValue;
+
+} /* NbfReadSingleParameter */
+
+
+VOID
+NbfWriteSingleParameter(
+ IN HANDLE ParametersHandle,
+ IN PWCHAR ValueName,
+ IN ULONG ValueData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NBF to write a single parameter
+ from the registry.
+
+Arguments:
+
+ ParametersHandle - A pointer to the open registry.
+
+ ValueName - The name of the value to store.
+
+ ValueData - The data to store at the value.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UNICODE_STRING ValueKeyName;
+ NTSTATUS Status;
+ ULONG TmpValueData = ValueData;
+
+ RtlInitUnicodeString (&ValueKeyName, ValueName);
+
+ Status = ZwSetValueKey(
+ ParametersHandle,
+ &ValueKeyName,
+ 0,
+ REG_DWORD,
+ (PVOID)&TmpValueData,
+ sizeof(ULONG));
+
+ if (!NT_SUCCESS(Status)) {
+ NbfPrint1("NBF: Could not write dword key: %lx\n", Status);
+ }
+
+} /* NbfWriteSingleParameter */
+
diff --git a/private/ntos/tdi/nbf/nbfcnfg.h b/private/ntos/tdi/nbf/nbfcnfg.h
new file mode 100644
index 000000000..ca8c382f3
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbfcnfg.h
@@ -0,0 +1,102 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ nbfcnfg.h
+
+Abstract:
+
+ Private include file for the NBF (NetBIOS Frames Protocol) transport. This
+ file defines all constants and structures necessary for support of
+ the dynamic configuration of NBF. Note that this file will be replaced
+ by calls to the configuration manager over time.
+
+Author:
+
+ David Beaver (dbeaver) 13-Feb-1991
+
+Revision History:
+
+--*/
+
+#ifndef _NBFCONFIG_
+#define _NBFCONFIG_
+
+//
+// Define the devices we support; this is in leiu of a real configuration
+// manager.
+//
+
+#define NBF_SUPPORTED_ADAPTERS 10
+
+#define NE3200_ADAPTER_NAME L"\\Device\\NE320001"
+#define ELNKII_ADAPTER_NAME L"\\Device\\Elnkii" // adapter we will talk to
+#define ELNKMC_ADAPTER_NAME L"\\Device\\Elnkmc01"
+#define ELNK16_ADAPTER_NAME L"\\Device\\Elnk1601"
+#define SONIC_ADAPTER_NAME L"\\Device\\Sonic01"
+#define LANCE_ADAPTER_NAME L"\\Device\\Lance01"
+#define PC586_ADAPTER_NAME L"\\Device\\Pc586"
+#define IBMTOK_ADAPTER_NAME L"\\Device\\Ibmtok01"
+#define PROTEON_ADAPTER_NAME L"\\Device\\Proteon01"
+#define WDLAN_ADAPTER_NAME L"\\Device\\Wdlan01"
+
+
+//
+// configuration structure.
+//
+
+typedef struct {
+
+ ULONG InitRequests;
+ ULONG InitLinks;
+ ULONG InitConnections;
+ ULONG InitAddressFiles;
+ ULONG InitAddresses;
+ ULONG MaxRequests;
+ ULONG MaxLinks;
+ ULONG MaxConnections;
+ ULONG MaxAddressFiles;
+ ULONG MaxAddresses;
+ ULONG InitPackets;
+ ULONG InitReceivePackets;
+ ULONG InitReceiveBuffers;
+ ULONG InitUIFrames;
+ ULONG SendPacketPoolSize;
+ ULONG ReceivePacketPoolSize;
+ ULONG MaxMemoryUsage;
+ ULONG DefaultT1Timeout;
+ ULONG DefaultT2Timeout;
+ ULONG DefaultTiTimeout;
+ ULONG LlcRetries;
+ ULONG LlcMaxWindowSize;
+ ULONG MaximumIncomingFrames;
+ ULONG NameQueryRetries;
+ ULONG NameQueryTimeout;
+ ULONG AddNameQueryRetries;
+ ULONG AddNameQueryTimeout;
+ ULONG GeneralRetries;
+ ULONG GeneralTimeout;
+ ULONG WanNameQueryRetries;
+
+ ULONG UseDixOverEthernet;
+ ULONG QueryWithoutSourceRouting;
+ ULONG AllRoutesNameRecognized;
+ ULONG MinimumSendWindowLimit;
+
+ //
+ // Names contains NumAdapters pairs of NDIS adapter names (which
+ // nbf binds to) and device names (which nbf exports). The nth
+ // adapter name is in location n and the device name is in
+ // DevicesOffset+n (DevicesOffset may be different from NumAdapters
+ // if the registry Bind and Export strings are different sizes).
+ //
+
+ ULONG NumAdapters;
+ ULONG DevicesOffset;
+ NDIS_STRING Names[1];
+
+} CONFIG_DATA, *PCONFIG_DATA;
+
+#endif
diff --git a/private/ntos/tdi/nbf/nbfconst.h b/private/ntos/tdi/nbf/nbfconst.h
new file mode 100644
index 000000000..9ca5f4072
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbfconst.h
@@ -0,0 +1,436 @@
+
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ nbfconst.h
+
+Abstract:
+
+ This header file defines manifest constants for the NT NBF transport
+ provider. It is included by nbf.h.
+
+Author:
+
+ Stephen E. Jones (stevej) 25-Oct-1989
+
+Revision History:
+
+ David Beaver (dbeaver) 24-Sep-1990
+ Remove pc586- and PDI-specific support. Add NDIS support. Note
+ changes to be made here if MAC dependence of NDIS changes. (search
+ for (PDI)
+
+--*/
+
+#ifndef _NBFCONST_
+#define _NBFCONST_
+
+
+//
+// DEBUGGING SUPPORT. DBG is a macro that is turned on at compile time
+// to enable debugging code in the system. If this is turned on, then
+// you can use the IF_NBFDBG(flags) macro in the NBF code to selectively
+// enable a piece of debugging code in the transport. This macro tests
+// NbfDebug, a global ULONG defined in NBFDRVR.C.
+//
+
+#if DBG
+
+#define NBF_DEBUG_SENDENG 0x00000001 // sendeng.c debugging.
+#define NBF_DEBUG_RCVENG 0x00000002 // rcveng.c debugging.
+#define NBF_DEBUG_IFRAMES 0x00000004 // displays sent/rec'd iframes.
+#define NBF_DEBUG_UFRAMES 0x00000008 // displays sent/rec'd uframes.
+#define NBF_DEBUG_DLCFRAMES 0x00000010 // displays sent/rec'd dlc frames.
+#define NBF_DEBUG_ADDRESS 0x00000020 // address.c debugging.
+#define NBF_DEBUG_CONNECT 0x00000040 // connect.c debugging.
+#define NBF_DEBUG_CONNOBJ 0x00000080 // connobj.c debugging.
+#define NBF_DEBUG_DEVCTX 0x00000100 // devctx.c debugging.
+#define NBF_DEBUG_DLC 0x00000200 // dlc.c data link engine debugging.
+#define NBF_DEBUG_INFO 0x00000400 // info.c debugging
+#define NBF_DEBUG_EVENT 0x00000800 // event.c debugging.
+#define NBF_DEBUG_FRAMECON 0x00001000 // framecon.c debugging.
+#define NBF_DEBUG_FRAMESND 0x00002000 // framesnd.c debugging.
+#define NBF_DEBUG_DYNAMIC 0x00004000 // dynamic allocation debugging.
+#define NBF_DEBUG_LINK 0x00008000 // link.c debugging.
+#define NBF_DEBUG_RESOURCE 0x00010000 // resource allocation debugging.
+#define NBF_DEBUG_DISPATCH 0x00020000 // IRP request dispatching.
+#define NBF_DEBUG_PACKET 0x00040000 // packet.c debugging.
+#define NBF_DEBUG_REQUEST 0x00080000 // request.c debugging.
+#define NBF_DEBUG_TIMER 0x00100000 // timer.c debugging.
+#define NBF_DEBUG_DLCRETRANSMIT 0x00200000 // DLC REJ debugging.
+#define NBF_DEBUG_REGISTRY 0x00400000 // registry access.
+#define NBF_DEBUG_NDIS 0x00800000 // NDIS related information
+#define NBF_DEBUG_LINKTREE 0x01000000 // Link splay tree debugging
+#define NBF_DEBUG_TEARDOWN 0x02000000 // link/connection teardown info
+#define NBF_DEBUG_REFCOUNTS 0x04000000 // link/connection ref/deref information
+#define NBF_DEBUG_IRP 0x08000000 // irp completion debugging
+#define NBF_DEBUG_DATAGRAMS 0x10000000 // datagram send/receive
+#define NBF_DEBUG_SETUP 0x20000000 // debug session setup
+#define NBF_DEBUG_CONFIG 0x40000000 // debug configuration
+
+//
+// past here are debug things that are really frequent; don't use them
+// unless you want LOTS of output
+//
+#define NBF_DEBUG_TIMERDPC 0x10000000 // the timer DPC
+#define NBF_DEBUG_PKTCONTENTS 0x20000000 // dump packet contents in dbg
+#define NBF_DEBUG_TIMERCODE 0x40000000 // enable check code in timer
+#define NBF_DEBUG_TRACKTDI 0x80000000 // store tdi info when set
+
+
+extern ULONG NbfDebug; // in NBFDRVR.C.
+extern BOOLEAN NbfDisconnectDebug; // in NBFDRVR.C.
+
+#define TRACK_TDI_LIMIT 25
+#define TRACK_TDI_CAPTURE 36 // chosen to make debug line up nice
+typedef struct {
+ PVOID Request;
+ PIRP Irp;
+ PVOID Connection;
+ UCHAR Contents[TRACK_TDI_CAPTURE];
+ } NBF_SEND;
+
+typedef struct {
+ PVOID Request;
+ PIRP Irp;
+ NTSTATUS Status;
+ PVOID NothingYet;
+ } NBF_SEND_COMPLETE;
+
+typedef struct {
+ PVOID Request;
+ PIRP Irp;
+ PVOID Connection;
+ PVOID NothingYet;
+ } NBF_RECEIVE;
+
+typedef struct {
+ PVOID Request;
+ PIRP Irp;
+ NTSTATUS Status;
+ UCHAR Contents[TRACK_TDI_CAPTURE];
+ } NBF_RECEIVE_COMPLETE;
+
+extern NBF_SEND NbfSends[TRACK_TDI_LIMIT+1];
+extern LONG NbfSendsNext;
+
+extern NBF_SEND_COMPLETE NbfCompletedSends[TRACK_TDI_LIMIT+1];
+extern LONG NbfCompletedSendsNext;
+
+extern NBF_RECEIVE NbfReceives[TRACK_TDI_LIMIT+1];
+extern LONG NbfReceivesNext;
+
+extern NBF_RECEIVE_COMPLETE NbfCompletedReceives[TRACK_TDI_LIMIT+1];
+extern LONG NbfCompletedReceivesNext;
+
+#endif
+
+//
+// some convenient constants used for timing. All values are in clock ticks.
+//
+
+#define MICROSECONDS 10
+#define MILLISECONDS 10000 // MICROSECONDS*1000
+#define SECONDS 10000000 // MILLISECONDS*1000
+
+
+//
+// BUGBUG: temporary things used by nbf that are caused by the change-over from
+// (never implimented) PDI support to NDIS support. They may be removed pending
+// resolution of NDIS issues about MAC support.
+//
+
+#define PDI_SOURCE_ROUTE 0x00000002 // source routing field is specified.
+#define PDI_HARDWARE_ADDRESS 0x00000004 // hardware address field is specified.
+#define PDI_TRUNCATED 0x00000001 // PSDU was truncated.
+#define PDI_FRAGMENT 0x00000002 // PSDU was fragmented.
+#define PDI_BROADCAST 0x00000004 // PSDU was broadcast.
+#define PDI_MULTICAST 0x00000008 // PSDU was multicast/functional.
+#define PDI_SOURCE_ROUTING 0x00000010 // PSDU contained source routing information.
+
+
+
+//
+// MAJOR PROTOCOL IDENTIFIERS THAT CHARACTERIZE THIS DRIVER.
+//
+
+#define NBF_DEVICE_NAME L"\\Device\\Nbf"// name of our driver.
+#ifdef _PNP_POWER
+#define NBF_NAME L"Nbf" // name for protocol chars.
+#endif
+#define DSAP_NETBIOS_OVER_LLC 0xf0 // NETBEUI always has DSAP 0xf0.
+#define PSAP_LLC 0 // LLC always runs over PSAP 0.
+#define MAX_SOURCE_ROUTE_LENGTH 32 // max. bytes of SR. info.
+#define MAX_NETWORK_NAME_LENGTH 128 // # bytes in netname in TP_ADDRESS.
+#define MAX_USER_PACKET_DATA 1500 // max. user bytes per DFM/DOL.
+
+#define NBF_FILE_TYPE_CONTROL (ULONG)0x4701 // file is type control
+
+
+//
+// MAJOR CONFIGURATION PARAMETERS THAT WILL BE MOVED TO THE INIT-LARGE_INTEGER
+// CONFIGURATION MANAGER.
+//
+
+#define MAX_REQUESTS 30
+#define MAX_UI_FRAMES 25
+#define MAX_SEND_PACKETS 40
+#define MAX_RECEIVE_PACKETS 30
+#define MAX_RECEIVE_BUFFERS 15
+#define MAX_LINKS 10
+#define MAX_CONNECTIONS 10
+#define MAX_ADDRESSFILES 10
+#define MAX_ADDRESSES 10
+
+#define MIN_UI_FRAMES 5 // + one per address + one per connection
+#define MIN_SEND_PACKETS 20 // + one per link + one per connection
+#define MIN_RECEIVE_PACKETS 10 // + one per link + one per address
+#define MIN_RECEIVE_BUFFERS 5 // + one per address
+
+#define SEND_PACKET_RESERVED_LENGTH (sizeof (SEND_PACKET_TAG))
+#define RECEIVE_PACKET_RESERVED_LENGTH (sizeof (RECEIVE_PACKET_TAG))
+
+
+#define ETHERNET_HEADER_SIZE 14 // BUGBUG: used for current NDIS compliance
+#define ETHERNET_PACKET_SIZE 1514
+
+#define MAX_DEFERRED_TRAVERSES 6 // number of times we can go through
+ // the deferred operations queue and
+ // not do anything without causing an
+ // error indication
+
+
+//
+// NETBIOS PROTOCOL CONSTANTS.
+//
+
+#define NETBIOS_NAME_LENGTH 16
+#define NETBIOS_SESSION_LIMIT 254 // max # of sessions/link. (abs limit is 254)
+
+#define NAME_QUERY_RETRIES 3 // 2 retrie(s), plus the first one.
+#define ADD_NAME_QUERY_RETRIES 3 // 1 retrie(s) plus the first one.
+#define WAN_NAME_QUERY_RETRIES 5 // for NdisMediumWan only.
+
+#define NAME_QUERY_TIMEOUT (500*MILLISECONDS)
+#define ADD_NAME_QUERY_TIMEOUT (500*MILLISECONDS)
+
+//
+// DATA LINK PROTOCOL CONSTANTS.
+//
+// There are two timers, short and long. T1, T2, and the purge
+// timer are run off of the short timer, Ti and the adaptive timer
+// is run off of the long one.
+//
+
+#define SHORT_TIMER_DELTA (50*MILLISECONDS)
+#define LONG_TIMER_DELTA (1*SECONDS)
+
+#define DLC_DEFAULT_T1 (600 * MILLISECONDS)
+#define DLC_DEFAULT_T2 (150 * MILLISECONDS)
+#define DLC_DEFAULT_TI (30 * SECONDS)
+#define DLC_RETRIES (8) // number of poll retries at LLC level.
+#define DLC_RETRANSMIT_THRESHOLD (10) // up to n retransmissions acceptable.
+#define DLC_WINDOW_LIMIT (10) // incr. to 127 when packet pool expanded.
+
+#define DLC_TIMER_ACCURACY 8 // << between BaseT1Timeout and CurrentT1Timeout
+
+
+#define TIMER_ADAPTIVE_TICKS ((DLC_DEFAULT_T1*60)/LONG_TIMER_DELTA) // time between adaptive runs.
+#define TIMER_PURGE_TICKS ((DLC_DEFAULT_T1*10)/SHORT_TIMER_DELTA) // time between adaptive purges.
+
+
+//
+// TDI defined timeouts
+//
+
+#define TDI_TIMEOUT_SEND 60L // sends go 120 seconds
+#define TDI_TIMEOUT_RECEIVE 0L // receives
+#define TDI_TIMEOUT_CONNECT 60L
+#define TDI_TIMEOUT_LISTEN 0L // listens default to never.
+#define TDI_TIMEOUT_DISCONNECT 60L // should be 30
+#define TDI_TIMEOUT_NAME_REGISTRATION 60L
+
+
+
+//
+// GENERAL CAPABILITIES STATEMENTS THAT CANNOT CHANGE.
+//
+
+#define NBF_MAX_TSDU_SIZE 65535 // maximum TSDU size supported by NetBIOS.
+#define NBF_MAX_DATAGRAM_SIZE 512 // maximum Datagram size supported by NetBIOS.
+#define NBF_MAX_CONNECTION_USER_DATA 0 // no user data supported on connect.
+#define NBF_SERVICE_FLAGS ( \
+ TDI_SERVICE_CONNECTION_MODE | \
+ TDI_SERVICE_CONNECTIONLESS_MODE | \
+ TDI_SERVICE_MESSAGE_MODE | \
+ TDI_SERVICE_ERROR_FREE_DELIVERY | \
+ TDI_SERVICE_BROADCAST_SUPPORTED | \
+ TDI_SERVICE_MULTICAST_SUPPORTED | \
+ TDI_SERVICE_DELAYED_ACCEPTANCE )
+
+#define NBF_MIN_LOOKAHEAD_DATA 256 // minimum guaranteed lookahead data.
+#define NBF_MAX_LOOKAHEAD_DATA 256 // maximum guaranteed lookahead data.
+
+#define NBF_MAX_LOOPBACK_LOOKAHEAD 192 // how much is copied over for loopback
+
+//
+// Number of TDI resources that we report.
+//
+
+#define NBF_TDI_RESOURCES 9
+
+
+//
+// NetBIOS name types used in the NetBIOS Frames Protocol Connectionless PDUs.
+//
+
+#define NETBIOS_NAME_TYPE_UNIQUE 0x00 // name is unique on the network.
+#define NETBIOS_NAME_TYPE_GROUP 0x01 // name is a group name.
+#define NETBIOS_NAME_TYPE_EITHER 0x02 // used in NbfMatchNetbiosAddress
+
+//
+// STATUS_QUERY request types. If the sender is following pre-2.1 protocol,
+// then a simple request-response exchange is performed. Later versions
+// store the "total number of names received so far" in the request type
+// field, except for the first request, which must contain a 1 in this field.
+//
+
+#define STATUS_QUERY_REQUEST_TYPE_PRE21 0x00 // request is 1.x or 2.0.
+#define STATUS_QUERY_REQUEST_TYPE_FIRST 0x01 // first request, 2.1 or above.
+
+//
+// If the LocalSessionNumber field contains a 0, then the request is really
+// a FIND.NAME. If the field is non-zero, then it is the local session
+// number that will be provided in all connection-oriented headers thereafter.
+//
+
+#define NAME_QUERY_LSN_FIND_NAME 0x00 // LSN for FIND.NAME request.
+
+//
+// NAME_RECOGNIZED LocalSessionNumber status values. If the connection
+// request was rejected, then one of the following values is placed in
+// the LocalSessionNumber field. NAME_RECOGNIZED can also be used as a
+// FIND.NAME response, in which case the NO_LISTENS status is overloaded
+// to also mean a FIND.NAME.
+//
+
+#define NAME_RECOGNIZED_LSN_NO_LISTENS 0x00 // no listens available.
+#define NAME_RECOGNIZED_LSN_FIND_NAME 0x00 // this is a find name response.
+#define NAME_RECOGNIZED_LSN_NO_RESOURCE 0xff // listen available, but no resources.
+
+//
+// STATUS_RESPONSE response types. If the sender is following pre-2.1
+// protocol, then a simple request-response exchange is performed. Later
+// versions store the "total number of names sent so far" in the request
+// type field. This value is cumulative, and includes the count of names
+// sent with the current response, as well as from previous responses.
+//
+
+#define STATUS_RESPONSE_PRE21 0x00 // request is 1.x or 2.0.
+#define STATUS_RESPONSE_FIRST 0x01 // first request, 2.1 or above.
+
+//
+// DATA_FIRST_MIDDLE option bitflags.
+//
+
+#define DFM_OPTIONS_RECEIVE_CONTINUE 0x01 // RECEIVE_CONTINUE requested.
+#define DFM_OPTIONS_NO_ACK 0x02 // no DATA_ACK frame expected.
+#define DFM_OPTIONS_RESYNCH 0x04 // set resynch indicator/this frame.
+#define DFM_OPTIONS_ACK_INCLUDED 0x08 // piggyback ack included.
+
+//
+// DATA_ONLY_LAST option bitflags.
+//
+
+#define DOL_OPTIONS_RESYNCH 0x01 // set resynch indicator/this frame.
+#define DOL_OPTIONS_NO_ACK 0x02 // no DATA_ACK frame expected.
+#define DOL_OPTIONS_ACK_W_DATA_ALLOWED 0x04 // piggyback ack allowed.
+#define DOL_OPTIONS_ACK_INCLUDED 0x08 // piggyback ack included.
+
+//
+// SESSION_CONFIRM option bitflags.
+//
+
+#define SESSION_CONFIRM_OPTIONS_20 0x01 // set if NETBIOS 2.0 or above.
+#define SESSION_CONFIRM_NO_ACK 0x80 // set if NO.ACK protocol supported.
+
+//
+// SESSION_END reason codes.
+//
+
+#define SESSION_END_REASON_HANGUP 0x0000 // normal termination via HANGUP.
+#define SESSION_END_REASON_ABEND 0x0001 // abnormal session termination.
+
+//
+// SESSION_INITIALIZE option bitflags.
+//
+
+#define SESSION_INIT_OPTIONS_20 0x01 // set if NETBIOS 2.0 or above.
+#define SESSION_INIT_OPTIONS_LF 0x0E // Maximum largest frame value
+#define SESSION_INIT_NO_ACK 0x80 // set if NO.ACK protocol supported.
+
+//
+// NO_RECEIVE option bitflags.
+//
+
+#define NO_RECEIVE_PARTIAL_NO_ACK 0x02 // NO.ACK data partially received.
+
+//
+// Resource IDs for query and error logging.
+//
+
+#define LINK_RESOURCE_ID 11
+#define ADDRESS_RESOURCE_ID 12
+#define ADDRESS_FILE_RESOURCE_ID 13
+#define CONNECTION_RESOURCE_ID 14
+#define REQUEST_RESOURCE_ID 15
+
+#define UI_FRAME_RESOURCE_ID 21
+#define PACKET_RESOURCE_ID 22
+#define RECEIVE_PACKET_RESOURCE_ID 23
+#define RECEIVE_BUFFER_RESOURCE_ID 24
+
+
+//
+// memory management additions
+//
+
+//
+// Fake IOCTLs used for kernel mode testing.
+//
+
+#define IOCTL_NBF_BASE FILE_DEVICE_TRANSPORT
+
+#define _NBF_CONTROL_CODE(request,method) \
+ ((IOCTL_NBF_BASE)<<16 | (request<<2) | method)
+
+#define IOCTL_TDI_SEND_TEST _NBF_CONTROL_CODE(26,0)
+#define IOCTL_TDI_RECEIVE_TEST _NBF_CONTROL_CODE(27,0)
+#define IOCTL_TDI_SERVER_TEST _NBF_CONTROL_CODE(28,0)
+
+//
+// More debugging stuff
+//
+
+#define NBF_REQUEST_SIGNATURE ((CSHORT)0x4702)
+#define NBF_LINK_SIGNATURE ((CSHORT)0x4703)
+#define NBF_CONNECTION_SIGNATURE ((CSHORT)0x4704)
+#define NBF_ADDRESSFILE_SIGNATURE ((CSHORT)0x4705)
+#define NBF_ADDRESS_SIGNATURE ((CSHORT)0x4706)
+#define NBF_DEVICE_CONTEXT_SIGNATURE ((CSHORT)0x4707)
+#define NBF_PACKET_SIGNATURE ((CSHORT)0x4708)
+
+#if DBG
+extern PVOID * NbfConnectionTable;
+extern PVOID * NbfRequestTable;
+extern PVOID * NbfUiFrameTable;
+extern PVOID * NbfSendPacketTable;
+extern PVOID * NbfLinkTable;
+extern PVOID * NbfAddressFileTable;
+extern PVOID * NbfAddressTable;
+#endif
+
+#endif // _NBFCONST_
diff --git a/private/ntos/tdi/nbf/nbfdebug.c b/private/ntos/tdi/nbf/nbfdebug.c
new file mode 100644
index 000000000..2f5aadbd7
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbfdebug.c
@@ -0,0 +1,646 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ nbfdebug.c
+
+Abstract:
+
+ This module contains code that implements debug things for NBF. It is
+ compiled only if debug is on in the compile phase.
+
+Author:
+
+ David Beaver (dbeaver) 18-Apr-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ David Beaver (dbeaver) 1-July-1991
+ modified to use new TDI interface
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#if DBG
+
+VOID
+DisplayOneFrame(
+ PTP_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a temporary debugging aid that displays an I-frame
+ before it is sent. This ensures that we have formatted all our packets
+ correctly.
+
+Arguments:
+
+ Packet - Pointer to a TP_PACKET representing an I-frame to be displayed.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PCH s, e;
+ ULONG ns, nr; // I-frame (NetBIOS) cracking.
+ PNBF_HDR_CONNECTION NbfHeader;
+ PDLC_I_FRAME DlcHeader;
+ BOOLEAN Command, PollFinal;
+ BOOLEAN IsUFrame=FALSE;
+ UCHAR CmdByte;
+
+ PDLC_S_FRAME SFrame; // DLC frame cracking.
+ PDLC_U_FRAME UFrame;
+
+ DlcHeader = (PDLC_I_FRAME)&(Packet->Header[14]);
+ NbfHeader = (PNBF_HDR_CONNECTION)&(Packet->Header[18]);
+ ns = DlcHeader->SendSeq >> 1;
+ nr = DlcHeader->RcvSeq >> 1;
+ PollFinal = (BOOLEAN)(DlcHeader->RcvSeq & DLC_I_PF);
+ Command = (BOOLEAN)!(DlcHeader->Ssap & DLC_SSAP_RESPONSE);
+
+ if (DlcHeader->SendSeq & DLC_I_INDICATOR) {
+ IF_NBFDBG (NBF_DEBUG_DLCFRAMES) {
+ } else {
+ return; // if DLCFRAMES not set, don't print.
+ }
+
+ SFrame = (PDLC_S_FRAME)DlcHeader; // alias.
+ UFrame = (PDLC_U_FRAME)DlcHeader; // alias.
+ CmdByte = SFrame->Command;
+ IsUFrame = (BOOLEAN)((UFrame->Command & DLC_U_INDICATOR) == DLC_U_INDICATOR);
+ if (IsUFrame) {
+ CmdByte = (UCHAR)(UFrame->Command & ~DLC_U_PF);
+ }
+
+ switch (CmdByte) {
+ case DLC_CMD_RR:
+ s = "RR";
+ PollFinal = (BOOLEAN)(SFrame->RcvSeq & DLC_S_PF);
+ DbgPrint ("DLC: %s-%s/%s(%ld) ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0",
+ (ULONG)(SFrame->RcvSeq >> 1));
+ break;
+
+ case DLC_CMD_RNR:
+ s = "RNR";
+ PollFinal = (BOOLEAN)(SFrame->RcvSeq & DLC_S_PF);
+ DbgPrint ("DLC: %s-%s/%s(%ld) ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0",
+ (ULONG)(SFrame->RcvSeq >> 1));
+ break;
+
+ case DLC_CMD_REJ:
+ s = "REJ";
+ PollFinal = (BOOLEAN)(SFrame->RcvSeq & DLC_S_PF);
+ DbgPrint ("DLC: %s-%s/%s(%ld) ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0",
+ (ULONG)(SFrame->RcvSeq >> 1));
+ break;
+
+ case DLC_CMD_SABME:
+ s = "SABME";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_DISC:
+ s = "DISC";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_UA:
+ s = "UA";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_DM:
+ s = "DM";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_FRMR:
+ s = "FRMR";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_XID:
+ s = "XID";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_TEST:
+ s = "TEST";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ default:
+ s = "(UNKNOWN)";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ }
+ return;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ } else {
+ return; // if IFRAMES not set, don't print.
+ }
+
+ switch (NbfHeader->Command) {
+ case NBF_CMD_ADD_GROUP_NAME_QUERY:
+ s = "ADD_GROUP_NAME_QUERY"; break;
+
+ case NBF_CMD_ADD_NAME_QUERY:
+ s = "ADD_NAME_QUERY"; break;
+
+ case NBF_CMD_NAME_IN_CONFLICT:
+ s = "NAME_IN_CONFLICT"; break;
+
+ case NBF_CMD_STATUS_QUERY:
+ s = "STATUS_QUERY"; break;
+
+ case NBF_CMD_TERMINATE_TRACE:
+ s = "TERMINATE_TRACE"; break;
+
+ case NBF_CMD_DATAGRAM:
+ s = "DATAGRAM"; break;
+
+ case NBF_CMD_DATAGRAM_BROADCAST:
+ s = "BROADCAST_DATAGRAM"; break;
+
+ case NBF_CMD_NAME_QUERY:
+ s = "NAME_QUERY"; break;
+
+ case NBF_CMD_ADD_NAME_RESPONSE:
+ s = "ADD_NAME_RESPONSE"; break;
+
+ case NBF_CMD_NAME_RECOGNIZED:
+ s = "NAME_RECOGNIZED"; break;
+
+ case NBF_CMD_STATUS_RESPONSE:
+ s = "STATUS_RESPONSE"; break;
+
+ case NBF_CMD_TERMINATE_TRACE2:
+ s = "TERMINATE_TRACE2"; break;
+
+ case NBF_CMD_DATA_ACK:
+ s = "DATA_ACK"; break;
+
+ case NBF_CMD_DATA_FIRST_MIDDLE:
+ s = "DATA_FIRST_MIDDLE"; break;
+
+ case NBF_CMD_DATA_ONLY_LAST:
+ s = "DATA_ONLY_LAST"; break;
+
+ case NBF_CMD_SESSION_CONFIRM:
+ s = "SESSION_CONFIRM"; break;
+
+ case NBF_CMD_SESSION_END:
+ s = "SESSION_END"; break;
+
+ case NBF_CMD_SESSION_INITIALIZE:
+ s = "SESSION_INITIALIZE"; break;
+
+ case NBF_CMD_NO_RECEIVE:
+ s = "NO_RECEIVE"; break;
+
+ case NBF_CMD_RECEIVE_OUTSTANDING:
+ s = "RECEIVE_OUTSTANDING"; break;
+
+ case NBF_CMD_RECEIVE_CONTINUE:
+ s = "RECEIVE_CONTINUE"; break;
+
+ case NBF_CMD_SESSION_ALIVE:
+ s = "SESSION_ALIVE"; break;
+
+ default:
+ s = "<<<<UNKNOWN I PACKET TYPE>>>>";
+ } /* switch */
+
+ if (HEADER_LENGTH(NbfHeader) != 14) {
+ e = "(LENGTH IN ERROR) ";
+ } else if (HEADER_SIGNATURE(NbfHeader) != NETBIOS_SIGNATURE) {
+ e = "(SIGNATURE IN ERROR) ";
+ } else {
+ e = "";
+ }
+
+ DbgPrint ("DLC: I-%s/%s, N(S)=%ld, N(R)=%ld %s",
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0",
+ ns, nr, e);
+ DbgPrint (s);
+ DbgPrint (" ( D1=%ld, D2=%ld, XC=%ld, RC=%ld )\n",
+ (ULONG)NbfHeader->Data1,
+ (ULONG)(NbfHeader->Data2Low+NbfHeader->Data2High*256),
+ TRANSMIT_CORR(NbfHeader),
+ RESPONSE_CORR(NbfHeader));
+} /* DisplayOneFrame */
+
+
+VOID
+NbfDisplayUIFrame(
+ PTP_UI_FRAME OuterFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a temporary debugging aid that displays a UI frame
+ before it is sent by NbfSendUIFrame. This ensures that we have formatted
+ all our UI frames correctly.
+
+Arguments:
+
+ RawFrame - Pointer to a connectionless frame to be sent.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PCH s, e;
+ UCHAR ReceiverName [17];
+ UCHAR SenderName [17];
+ BOOLEAN PollFinal, Command;
+ PDLC_S_FRAME SFrame;
+ PDLC_U_FRAME UFrame;
+ USHORT i;
+ PDLC_FRAME DlcHeader;
+ PNBF_HDR_CONNECTIONLESS NbfHeader;
+
+ //
+
+ DlcHeader = (PDLC_FRAME)&(OuterFrame->Header[14]);
+ NbfHeader = (PNBF_HDR_CONNECTIONLESS)&(OuterFrame->Header[17]);
+
+ if (DlcHeader->Byte1 != DLC_CMD_UI) {
+
+ IF_NBFDBG (NBF_DEBUG_DLCFRAMES) {
+ } else {
+ return; // don't print this if DLCFRAMES is off.
+ }
+
+ Command = (BOOLEAN)!(DlcHeader->Ssap & DLC_SSAP_RESPONSE);
+ SFrame = (PDLC_S_FRAME)DlcHeader; // alias.
+ UFrame = (PDLC_U_FRAME)DlcHeader; // alias.
+ switch (DlcHeader->Byte1) {
+ case DLC_CMD_RR:
+ s = "RR";
+ PollFinal = (BOOLEAN)(SFrame->RcvSeq & DLC_S_PF);
+ DbgPrint ("DLC: %s-%s/%s(%ld) ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0",
+ (ULONG)(SFrame->RcvSeq >> 1));
+ break;
+
+ case DLC_CMD_RNR:
+ s = "RNR";
+ PollFinal = (BOOLEAN)(SFrame->RcvSeq & DLC_S_PF);
+ DbgPrint ("DLC: %s-%s/%s(%ld) ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0",
+ (ULONG)(SFrame->RcvSeq >> 1));
+ break;
+
+ case DLC_CMD_REJ:
+ s = "REJ";
+ PollFinal = (BOOLEAN)(SFrame->RcvSeq & DLC_S_PF);
+ DbgPrint ("DLC: %s-%s/%s(%ld) ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0",
+ (ULONG)(SFrame->RcvSeq >> 1));
+ break;
+
+ case DLC_CMD_SABME:
+ s = "SABME";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_DISC:
+ s = "DISC";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_UA:
+ s = "UA";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_DM:
+ s = "DM";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_FRMR:
+ s = "FRMR";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_XID:
+ s = "XID";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_TEST:
+ s = "TEST";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ default:
+ s = "(UNKNOWN)";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ }
+ return;
+ }
+
+ //
+ // We know that this is an I-frame, because the bottom bit of the
+ // first byte in the DLC header is cleared. Go ahead and print it
+ // as though it were a NetBIOS packet, which it should be.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ } else {
+ return; // don't print this if IFRAMES is off.
+ }
+
+ switch (NbfHeader->Command) {
+ case NBF_CMD_ADD_GROUP_NAME_QUERY:
+ s = "ADD_GROUP_NAME_QUERY"; break;
+
+ case NBF_CMD_ADD_NAME_QUERY:
+ s = "ADD_NAME_QUERY"; break;
+
+ case NBF_CMD_NAME_IN_CONFLICT:
+ s = "NAME_IN_CONFLICT"; break;
+
+ case NBF_CMD_STATUS_QUERY:
+ s = "STATUS_QUERY"; break;
+
+ case NBF_CMD_TERMINATE_TRACE:
+ s = "TERMINATE_TRACE"; break;
+
+ case NBF_CMD_DATAGRAM:
+ s = "DATAGRAM"; break;
+
+ case NBF_CMD_DATAGRAM_BROADCAST:
+ s = "BROADCAST_DATAGRAM"; break;
+
+ case NBF_CMD_NAME_QUERY:
+ s = "NAME_QUERY"; break;
+
+ case NBF_CMD_ADD_NAME_RESPONSE:
+ s = "ADD_NAME_RESPONSE"; break;
+
+ case NBF_CMD_NAME_RECOGNIZED:
+ s = "NAME_RECOGNIZED"; break;
+
+ case NBF_CMD_STATUS_RESPONSE:
+ s = "STATUS_RESPONSE"; break;
+
+ case NBF_CMD_TERMINATE_TRACE2:
+ s = "TERMINATE_TRACE2"; break;
+
+ case NBF_CMD_DATA_ACK:
+ s = "DATA_ACK"; break;
+
+ case NBF_CMD_DATA_FIRST_MIDDLE:
+ s = "DATA_FIRST_MIDDLE"; break;
+
+ case NBF_CMD_DATA_ONLY_LAST:
+ s = "DATA_ONLY_LAST"; break;
+
+ case NBF_CMD_SESSION_CONFIRM:
+ s = "SESSION_CONFIRM"; break;
+
+ case NBF_CMD_SESSION_END:
+ s = "SESSION_END"; break;
+
+ case NBF_CMD_SESSION_INITIALIZE:
+ s = "SESSION_INITIALIZE"; break;
+
+ case NBF_CMD_NO_RECEIVE:
+ s = "NO_RECEIVE"; break;
+
+ case NBF_CMD_RECEIVE_OUTSTANDING:
+ s = "RECEIVE_OUTSTANDING"; break;
+
+ case NBF_CMD_RECEIVE_CONTINUE:
+ s = "RECEIVE_CONTINUE"; break;
+
+ case NBF_CMD_SESSION_ALIVE:
+ s = "SESSION_ALIVE"; break;
+
+ default:
+ s = "<<<<UNKNOWN UI PACKET TYPE>>>>";
+ } /* switch */
+
+ for (i=0; i<16; i++) { // copy NetBIOS names.
+ SenderName [i] = NbfHeader->SourceName [i];
+ ReceiverName [i] = NbfHeader->DestinationName [i];
+ }
+ SenderName [16] = 0; // install zero bytes.
+ ReceiverName [16] = 0;
+
+ if (HEADER_LENGTH(NbfHeader) != 44) {
+ e = "(LENGTH IN ERROR) ";
+ } else if (HEADER_SIGNATURE(NbfHeader) != NETBIOS_SIGNATURE) {
+ e = "(SIGNATURE IN ERROR) ";
+ } else {
+ e = "";
+ }
+
+ DbgPrint ("[UI] %s", e);
+ DbgPrint (s);
+ DbgPrint (" ( D1=%ld, D2=%ld, XC=%ld, RC=%ld, ",
+ (ULONG)NbfHeader->Data1,
+ (ULONG)(NbfHeader->Data2Low+NbfHeader->Data2High*256),
+ TRANSMIT_CORR(NbfHeader),
+ RESPONSE_CORR(NbfHeader));
+ DbgPrint ("'%s'->'%s' ) ---->\n", SenderName, ReceiverName);
+} /* NbfDisplayUIFrame */
+
+
+VOID
+NbfHexDumpLine(
+ PCHAR pch,
+ ULONG len,
+ PCHAR s,
+ PCHAR t
+ )
+/*++
+
+Routine Description:
+
+ This routine builds a line of text containing hex and printable characters.
+
+Arguments:
+
+ IN pch - Supplies buffer to be displayed.
+ IN len - Supplies the length of the buffer in bytes.
+ IN s - Supplies the start of the buffer to be loaded with the string
+ of hex characters.
+ IN t - Supplies the start of the buffer to be loaded with the string
+ of printable ascii characters.
+
+
+Return Value:
+
+ none.
+
+--*/
+{
+ static UCHAR rghex[] = "0123456789ABCDEF";
+
+ UCHAR c;
+ UCHAR *hex, *asc;
+
+
+ hex = s;
+ asc = t;
+
+ *(asc++) = '*';
+ while (len--) {
+ c = *(pch++);
+ *(hex++) = rghex [c >> 4] ;
+ *(hex++) = rghex [c & 0x0F];
+ *(hex++) = ' ';
+ *(asc++) = (c < ' ' || c > '~') ? (CHAR )'.' : c;
+ }
+ *(asc++) = '*';
+ *asc = 0;
+ *hex = 0;
+
+}
+
+
+VOID
+NbfFormattedDump(
+ PCHAR far_p,
+ ULONG len
+ )
+/*++
+
+Routine Description:
+
+ This routine outputs a buffer in lines of text containing hex and
+ printable characters.
+
+Arguments:
+
+ IN far_p - Supplies buffer to be displayed.
+ IN len - Supplies the length of the buffer in bytes.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ ULONG l;
+ char s[80], t[80];
+
+ while (len) {
+ l = len < 16 ? len : 16;
+
+ DbgPrint ("\n%lx ", far_p);
+ NbfHexDumpLine (far_p, l, s, t);
+ DbgPrint ("%s%.*s%s", s, 1 + ((16 - l) * 3), "", t);
+
+ len -= l;
+ far_p += l;
+ }
+ DbgPrint ("\n");
+}
+
+#endif
diff --git a/private/ntos/tdi/nbf/nbfdrvr.c b/private/ntos/tdi/nbf/nbfdrvr.c
new file mode 100644
index 000000000..2f42766ff
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbfdrvr.c
@@ -0,0 +1,2493 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ nbfdrvr.c
+
+Abstract:
+
+ This module contains code which defines the NetBIOS Frames Protocol
+ transport provider's device object.
+
+Author:
+
+ David Beaver (dbeaver) 2-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+//#pragma warning(error:4101) // Unreferenced local variable
+
+//
+// This is a list of all the device contexts that NBF owns,
+// used while unloading.
+//
+
+LIST_ENTRY NbfDeviceList = {0,0}; // initialized for real at runtime.
+
+#ifdef _PNP_POWER
+
+//
+// Global variables this is a copy of the path in the registry for
+// configuration data.
+//
+
+UNICODE_STRING NbfRegistryPath;
+
+//
+// We need the driver object to create device context structures.
+//
+
+PDRIVER_OBJECT NbfDriverObject;
+
+#endif
+
+
+#ifdef NBF_LOCKS // see spnlckdb.c
+
+extern KSPIN_LOCK NbfGlobalLock;
+
+#endif // def NBF_LOCKS
+
+//
+// The debugging longword, containing a bitmask as defined in NBFCONST.H.
+// If a bit is set, then debugging is turned on for that component.
+//
+
+#if DBG
+
+ULONG NbfDebug = 0;
+BOOLEAN NbfDisconnectDebug;
+
+NBF_SEND NbfSends[TRACK_TDI_LIMIT+1];
+LONG NbfSendsNext;
+
+NBF_SEND_COMPLETE NbfCompletedSends[TRACK_TDI_LIMIT+1];
+LONG NbfCompletedSendsNext;
+
+NBF_RECEIVE NbfReceives[TRACK_TDI_LIMIT+1];
+LONG NbfReceivesNext;
+
+NBF_RECEIVE_COMPLETE NbfCompletedReceives[TRACK_TDI_LIMIT+1];
+LONG NbfCompletedReceivesNext=0;
+
+PVOID * NbfConnectionTable;
+PVOID * NbfRequestTable;
+PVOID * NbfUiFrameTable;
+PVOID * NbfSendPacketTable;
+PVOID * NbfLinkTable;
+PVOID * NbfAddressFileTable;
+PVOID * NbfAddressTable;
+
+
+LIST_ENTRY NbfGlobalRequestList;
+LIST_ENTRY NbfGlobalLinkList;
+LIST_ENTRY NbfGlobalConnectionList;
+KSPIN_LOCK NbfGlobalInterlock;
+KSPIN_LOCK NbfGlobalHistoryLock;
+
+PVOID
+TtdiSend ();
+
+PVOID
+TtdiReceive ();
+
+PVOID
+TtdiServer ();
+
+KEVENT TdiSendEvent;
+KEVENT TdiReceiveEvent;
+KEVENT TdiServerEvent;
+
+#endif
+
+#if MAGIC
+
+BOOLEAN NbfEnableMagic = FALSE; // Controls sending of magic bullets.
+
+#endif // MAGIC
+
+//
+// This prevents us from having a bss section
+//
+
+ULONG _setjmpexused = 0;
+
+//
+// Forward declaration of various routines used in this module.
+//
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+VOID
+NbfUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+VOID
+NbfFreeConfigurationInfo (
+ IN PCONFIG_DATA ConfigurationInfo
+ );
+
+NTSTATUS
+NbfDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfDispatchInternal(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+VOID
+NbfDeallocateResources(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+#ifdef RASAUTODIAL
+VOID
+NbfAcdBind();
+
+VOID
+NbfAcdUnbind();
+#endif // RASAUTODIAL
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,DriverEntry)
+#ifdef _PNP_POWER
+#pragma alloc_text(PAGE,NbfInitializeOneDeviceContext)
+#endif
+#endif
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs initialization of the NetBIOS Frames Protocol
+ transport driver. It creates the device objects for the transport
+ provider and performs other driver initialization.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+ RegistryPath - The name of NBF's node in the registry.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ ULONG j;
+ UNICODE_STRING nameString;
+ NTSTATUS status;
+ UINT SuccessfulOpens;
+
+ PCONFIG_DATA NbfConfig = NULL;
+
+ //
+
+ ASSERT (sizeof (SHORT) == 2);
+
+#ifdef MEMPRINT
+ MemPrintInitialize ();
+#endif
+
+#ifdef NBF_LOCKS
+ KeInitializeSpinLock( &NbfGlobalLock );
+#endif
+
+#if DBG
+ InitializeListHead (&NbfGlobalRequestList);
+ InitializeListHead (&NbfGlobalLinkList);
+ InitializeListHead (&NbfGlobalConnectionList);
+ KeInitializeSpinLock (&NbfGlobalInterlock);
+ KeInitializeSpinLock (&NbfGlobalHistoryLock);
+#endif
+
+#ifdef _PNP_POWER
+
+ NbfRegistryPath = *RegistryPath;
+ NbfRegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
+ RegistryPath->MaximumLength,
+ ' FBN');
+
+ if (NbfRegistryPath.Buffer == NULL) {
+ PANIC(" Failed to allocate Registry Path!\n");
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ RtlCopyMemory(NbfRegistryPath.Buffer, RegistryPath->Buffer,
+ RegistryPath->MaximumLength);
+ NbfDriverObject = DriverObject;
+ RtlInitUnicodeString( &nameString, NBF_NAME);
+ TdiInitialize();
+
+#else // NOT _PNP_POWER
+
+ //
+ // This allocates the CONFIG_DATA structure and returns
+ // it in NbfConfig.
+ //
+
+ status = NbfConfigureTransport(RegistryPath, &NbfConfig);
+
+ if (!NT_SUCCESS (status)) {
+ PANIC (" Failed to initialize transport, Nbf initialization failed.\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // make ourselves known to the NDIS wrapper.
+ //
+
+ RtlInitUnicodeString( &nameString, NBF_DEVICE_NAME );
+#endif
+
+ status = NbfRegisterProtocol (&nameString);
+
+ if (!NT_SUCCESS (status)) {
+
+#ifdef _PNP_POWER
+
+ //
+ // No configuration info read at startup when using PNP
+ //
+
+ ExFreePool(NbfRegistryPath.Buffer);
+#else
+ //
+ // Free up config info for non PNP mode operation.
+ //
+
+ NbfFreeConfigurationInfo(NbfConfig);
+#endif
+ PANIC ("NbfInitialize: RegisterProtocol failed!\n");
+
+ NbfWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_REGISTER_FAILED,
+ 607,
+ status,
+ NULL,
+ 0,
+ NULL);
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+
+ //
+ // Initialize the driver object with this driver's entry points.
+ //
+
+ DriverObject->MajorFunction [IRP_MJ_CREATE] = NbfDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLOSE] = NbfDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLEANUP] = NbfDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL] = NbfDispatchInternal;
+ DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = NbfDispatch;
+
+ DriverObject->DriverUnload = NbfUnload;
+
+ //
+ // Initialize the global list of devices.
+ //
+
+ InitializeListHead (&NbfDeviceList);
+
+#ifndef _PNP_POWER
+
+#if DBG
+
+ //
+ // Allocate the debugging tables. In the PNP case we don't need these
+ // until we are activated by ProtocolBindAdapter
+ //
+
+ NbfConnectionTable = (PVOID *)ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(PVOID) *
+ (NbfConfig->InitConnections + 2 +
+ NbfConfig->InitRequests + 2 +
+ NbfConfig->InitUIFrames + 2 +
+ NbfConfig->InitPackets + 2 +
+ NbfConfig->InitLinks + 2 +
+ NbfConfig->InitAddressFiles + 2 +
+ NbfConfig->InitAddresses + 2),
+ ' FBN');
+
+ ASSERT (NbfConnectionTable);
+
+ NbfRequestTable = NbfConnectionTable + (NbfConfig->InitConnections + 2);
+ NbfUiFrameTable = NbfRequestTable + (NbfConfig->InitRequests + 2);
+ NbfSendPacketTable = NbfUiFrameTable + (NbfConfig->InitUIFrames + 2);
+ NbfLinkTable = NbfSendPacketTable + (NbfConfig->InitPackets + 2);
+ NbfAddressFileTable = NbfLinkTable + (NbfConfig->InitLinks + 2);
+ NbfAddressTable = NbfAddressFileTable + (NbfConfig->InitAddressFiles + 2);
+#endif
+
+
+ SuccessfulOpens = 0;
+
+ for (j=0;j<NbfConfig->NumAdapters;j++ ) {
+
+ //
+ // Loop through all the adapters that are in the configuration
+ // information structure. Allocate a device object for each
+ // one that we find.
+ //
+ SuccessfulOpens += NbfInitializeOneDeviceContext(&status,
+ DriverObject,
+ NbfConfig, j
+ );
+
+ }
+
+ NbfFreeConfigurationInfo(NbfConfig);
+
+#ifdef RASAUTODIAL
+ //
+ // Get the automatic connection
+ // driver entry points.
+ //
+ if (SuccessfulOpens > 0)
+ NbfAcdBind();
+#endif // RASAUTODIAL
+
+ return ((SuccessfulOpens>0) ? STATUS_SUCCESS :STATUS_DEVICE_DOES_NOT_EXIST);
+#else // _PNP_POWER
+ return(status);
+#endif
+
+}
+
+VOID
+NbfUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unloads the NetBIOS Frames Protocol transport driver.
+ It unbinds from any NDIS drivers that are open and frees all resources
+ associated with the transport. The I/O system will not call us until
+ nobody above has NBF open.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ None. When the function returns, the driver is unloaded.
+
+--*/
+
+{
+
+ PDEVICE_CONTEXT DeviceContext;
+ PLIST_ENTRY p;
+
+
+ UNREFERENCED_PARAMETER (DriverObject);
+
+
+#ifdef RASAUTODIAL
+ //
+ // Unbind from the
+ // automatic connection driver.
+ //
+ NbfAcdUnbind();
+#endif // RASAUTODIAL
+
+ //
+ // Walk the list of device contexts.
+ //
+
+ while (!IsListEmpty (&NbfDeviceList)) {
+
+ p = RemoveHeadList (&NbfDeviceList);
+ DeviceContext = CONTAINING_RECORD (p, DEVICE_CONTEXT, Linkage);
+
+ DeviceContext->State = DEVICECONTEXT_STATE_STOPPING;
+
+ //
+ // Remove all the storage associated with the device.
+ //
+
+ NbfFreeResources (DeviceContext);
+
+ //
+ // Free the packet pools, etc. and close the
+ // adapter.
+ //
+
+ NbfCloseNdis (DeviceContext);
+
+ //
+ // And remove the creation reference from the device
+ // context.
+ //
+
+ NbfDereferenceDeviceContext ("Unload", DeviceContext, DCREF_CREATION);
+
+ }
+
+ //
+ // Finally, remove ourselves as an NDIS protocol.
+ //
+
+ NbfDeregisterProtocol();
+
+ return;
+
+}
+
+
+VOID
+NbfFreeResources (
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by NBF to clean up the data structures associated
+ with a given DeviceContext. When this routine exits, the DeviceContext
+ should be deleted as it no longer has any assocaited resources.
+
+Arguments:
+
+ DeviceContext - Pointer to the DeviceContext we wish to clean up.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY s;
+ PTP_PACKET packet;
+ PTP_UI_FRAME uiFrame;
+ PTP_ADDRESS address;
+ PTP_CONNECTION connection;
+ PTP_REQUEST request;
+ PTP_LINK link;
+ PTP_ADDRESS_FILE addressFile;
+ PNDIS_PACKET ndisPacket;
+ PBUFFER_TAG BufferTag;
+
+
+ //
+ // Stop the timers.
+ //
+
+ NbfStopTimerSystem (DeviceContext);
+
+
+ //
+ // Clean up packet pool.
+ //
+
+ while ( DeviceContext->PacketPool.Next != NULL ) {
+ s = PopEntryList( &DeviceContext->PacketPool );
+ packet = CONTAINING_RECORD( s, TP_PACKET, Linkage );
+
+ NbfDeallocateSendPacket (DeviceContext, packet);
+ }
+
+ //
+ // Clean up UI frame pool.
+ //
+
+ while ( !IsListEmpty( &DeviceContext->UIFramePool ) ) {
+ p = RemoveHeadList( &DeviceContext->UIFramePool );
+ uiFrame = CONTAINING_RECORD (p, TP_UI_FRAME, Linkage );
+
+ NbfDeallocateUIFrame (DeviceContext, uiFrame);
+ }
+
+ //
+ // Clean up address pool.
+ //
+
+ while ( !IsListEmpty (&DeviceContext->AddressPool) ) {
+ p = RemoveHeadList (&DeviceContext->AddressPool);
+ address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+
+ NbfDeallocateAddress (DeviceContext, address);
+ }
+
+ //
+ // Clean up address file pool.
+ //
+
+ while ( !IsListEmpty (&DeviceContext->AddressFilePool) ) {
+ p = RemoveHeadList (&DeviceContext->AddressFilePool);
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+
+ NbfDeallocateAddressFile (DeviceContext, addressFile);
+ }
+
+ //
+ // Clean up connection pool.
+ //
+
+ while ( !IsListEmpty (&DeviceContext->ConnectionPool) ) {
+ p = RemoveHeadList (&DeviceContext->ConnectionPool);
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+
+ NbfDeallocateConnection (DeviceContext, connection);
+ }
+
+ //
+ // Clean up link pool.
+ //
+
+ while ( !IsListEmpty (&DeviceContext->LinkPool) ) {
+ p = RemoveHeadList (&DeviceContext->LinkPool);
+ link = CONTAINING_RECORD (p, TP_LINK, Linkage);
+
+ NbfDeallocateLink (DeviceContext, link);
+ }
+
+ //
+ // Clean up request pool.
+ //
+
+ while ( !IsListEmpty( &DeviceContext->RequestPool ) ) {
+ p = RemoveHeadList( &DeviceContext->RequestPool );
+ request = CONTAINING_RECORD (p, TP_REQUEST, Linkage );
+
+ NbfDeallocateRequest (DeviceContext, request);
+ }
+
+ //
+ // Clean up receive packet pool
+ //
+
+ while ( DeviceContext->ReceivePacketPool.Next != NULL) {
+ s = PopEntryList (&DeviceContext->ReceivePacketPool);
+
+ //
+ // HACK: This works because Linkage is the first field in
+ // ProtocolReserved for a receive packet.
+ //
+
+ ndisPacket = CONTAINING_RECORD (s, NDIS_PACKET, ProtocolReserved[0]);
+
+ NbfDeallocateReceivePacket (DeviceContext, ndisPacket);
+ }
+
+
+ //
+ // Clean up receive buffer pool.
+ //
+
+ while ( DeviceContext->ReceiveBufferPool.Next != NULL ) {
+ s = PopEntryList( &DeviceContext->ReceiveBufferPool );
+ BufferTag = CONTAINING_RECORD (s, BUFFER_TAG, Linkage );
+
+ NbfDeallocateReceiveBuffer (DeviceContext, BufferTag);
+ }
+
+
+ return;
+
+} /* NbfFreeResources */
+
+
+NTSTATUS
+NbfDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the NBF device driver.
+ It accepts an I/O Request Packet, performs the request, and then
+ returns with the appropriate status.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IrpSp;
+ PDEVICE_CONTEXT DeviceContext;
+
+ ENTER_NBF;
+
+ //
+ // Check to see if NBF has been initialized; if not, don't allow any use.
+ // Note that this only covers any user mode code use; kernel TDI clients
+ // will fail on their creation of an endpoint.
+ //
+
+ DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+ if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
+ LEAVE_NBF;
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ IoMarkIrpPending (Irp);
+ Irp->IoStatus.Status = STATUS_PENDING;
+ Irp->IoStatus.Information = 0;
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ //
+ // Case on the function that is being performed by the requestor. If the
+ // operation is a valid one for this device, then make it look like it was
+ // successfully completed, where possible.
+ //
+
+
+ switch (IrpSp->MajorFunction) {
+
+ case IRP_MJ_DEVICE_CONTROL:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatch: IRP_MJ_DEVICE_CONTROL.\n");
+ }
+
+ Status = NbfDeviceControl (DeviceObject, Irp, IrpSp);
+ break;
+
+ default:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatch: OTHER (DEFAULT).\n");
+ }
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ } /* major function switch */
+
+ if (Status == STATUS_PENDING) {
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatch: request PENDING from handler.\n");
+ }
+ } else {
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatch: request COMPLETED by handler.\n");
+ }
+
+ LEAVE_NBF;
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ ENTER_NBF;
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ LEAVE_NBF;
+ return Status;
+} /* NbfDispatch */
+
+
+NTSTATUS
+NbfDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the NBF device driver.
+ It accepts an I/O Request Packet, performs the request, and then
+ returns with the appropriate status.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PDEVICE_CONTEXT DeviceContext;
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IrpSp;
+ PFILE_FULL_EA_INFORMATION openType;
+ USHORT i;
+ BOOLEAN found;
+ PTP_ADDRESS_FILE AddressFile;
+ PTP_CONNECTION Connection;
+
+ ENTER_NBF;
+
+ //
+ // Check to see if NBF has been initialized; if not, don't allow any use.
+ // Note that this only covers any user mode code use; kernel TDI clients
+ // will fail on their creation of an endpoint.
+ //
+
+ DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+ if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
+ LEAVE_NBF;
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ IoMarkIrpPending (Irp);
+ Irp->IoStatus.Status = STATUS_PENDING;
+ Irp->IoStatus.Information = 0;
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ //
+ // Case on the function that is being performed by the requestor. If the
+ // operation is a valid one for this device, then make it look like it was
+ // successfully completed, where possible.
+ //
+
+
+ switch (IrpSp->MajorFunction) {
+
+ //
+ // The Create function opens a transport object (either address or
+ // connection). Access checking is performed on the specified
+ // address to ensure security of transport-layer addresses.
+ //
+
+ case IRP_MJ_CREATE:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatch: IRP_MJ_CREATE.\n");
+ }
+
+ openType =
+ (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+
+ if (openType != NULL) {
+
+ found = TRUE;
+
+ for (i=0;i<(USHORT)openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiTransportAddress[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = NbfOpenAddress (DeviceObject, Irp, IrpSp);
+ break;
+ }
+
+ //
+ // Connection?
+ //
+
+ found = TRUE;
+
+ for (i=0;i<(USHORT)openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiConnectionContext[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = NbfOpenConnection (DeviceObject, Irp, IrpSp);
+ break;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint1 ("NbfDispatchOpenClose: IRP_MJ_CREATE on invalid type, type was: %s\n",
+ openType->EaName);
+ }
+
+ } else {
+
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchOpenClose: IRP_MJ_CREATE on control channel!\n");
+ }
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ IrpSp->FileObject->FsContext = (PVOID)(DeviceContext->ControlChannelIdentifier);
+ ++DeviceContext->ControlChannelIdentifier;
+ if (DeviceContext->ControlChannelIdentifier == 0) {
+ DeviceContext->ControlChannelIdentifier = 1;
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ IrpSp->FileObject->FsContext2 = (PVOID)NBF_FILE_TYPE_CONTROL;
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case IRP_MJ_CLOSE:
+
+ //
+ // The Close function closes a transport endpoint, terminates
+ // all outstanding transport activity on the endpoint, and unbinds
+ // the endpoint from its transport address, if any. If this
+ // is the last transport endpoint bound to the address, then
+ // the address is removed from the provider.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatch: IRP_MJ_CLOSE.\n");
+ }
+
+ switch ((ULONG)IrpSp->FileObject->FsContext2) {
+ case TDI_TRANSPORT_ADDRESS_FILE:
+ AddressFile = (PTP_ADDRESS_FILE)IrpSp->FileObject->FsContext;
+
+ //
+ // This creates a reference to AddressFile->Address
+ // which is removed by NbfCloseAddress.
+ //
+
+ Status = NbfVerifyAddressObject(AddressFile);
+
+ if (!NT_SUCCESS (Status)) {
+ Status = STATUS_INVALID_HANDLE;
+ } else {
+ Status = NbfCloseAddress (DeviceObject, Irp, IrpSp);
+ }
+
+ break;
+
+ case TDI_CONNECTION_FILE:
+
+ //
+ // This is a connection
+ //
+
+ Connection = (PTP_CONNECTION)IrpSp->FileObject->FsContext;
+ Status = NbfVerifyConnectionObject (Connection);
+ if (NT_SUCCESS (Status)) {
+
+ Status = NbfCloseConnection (DeviceObject, Irp, IrpSp);
+ NbfDereferenceConnection ("Temporary Use",Connection, CREF_BY_ID);
+
+ }
+
+ break;
+
+ case NBF_FILE_TYPE_CONTROL:
+
+ //
+ // this always succeeds
+ //
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint1 ("NbfDispatch: IRP_MJ_CLOSE on unknown file type %lx.\n",
+ IrpSp->FileObject->FsContext2);
+ }
+
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ break;
+
+ case IRP_MJ_CLEANUP:
+
+ //
+ // Handle the two stage IRP for a file close operation. When the first
+ // stage hits, run down all activity on the object of interest. This
+ // do everything to it but remove the creation hold. Then, when the
+ // CLOSE irp hits, actually close the object.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatch: IRP_MJ_CLEANUP.\n");
+ }
+
+ switch ((ULONG)IrpSp->FileObject->FsContext2) {
+ case TDI_TRANSPORT_ADDRESS_FILE:
+ AddressFile = (PTP_ADDRESS_FILE)IrpSp->FileObject->FsContext;
+ Status = NbfVerifyAddressObject(AddressFile);
+ if (!NT_SUCCESS (Status)) {
+
+ Status = STATUS_INVALID_HANDLE;
+
+ } else {
+
+ NbfStopAddressFile (AddressFile, AddressFile->Address);
+ NbfDereferenceAddress ("IRP_MJ_CLEANUP", AddressFile->Address, AREF_VERIFY);
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case TDI_CONNECTION_FILE:
+
+ Connection = (PTP_CONNECTION)IrpSp->FileObject->FsContext;
+ Status = NbfVerifyConnectionObject (Connection);
+ if (NT_SUCCESS (Status)) {
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+ NbfStopConnection (Connection, STATUS_LOCAL_DISCONNECT);
+ KeLowerIrql (oldirql);
+ Status = STATUS_SUCCESS;
+ NbfDereferenceConnection ("Temporary Use",Connection, CREF_BY_ID);
+ }
+
+ break;
+
+ case NBF_FILE_TYPE_CONTROL:
+
+ NbfStopControlChannel(
+ (PDEVICE_CONTEXT)DeviceObject,
+ (USHORT)IrpSp->FileObject->FsContext
+ );
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint1 ("NbfDispatch: IRP_MJ_CLEANUP on unknown file type %lx.\n",
+ IrpSp->FileObject->FsContext2);
+ }
+
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ break;
+
+ default:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatch: OTHER (DEFAULT).\n");
+ }
+
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ } /* major function switch */
+
+ if (Status == STATUS_PENDING) {
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatch: request PENDING from handler.\n");
+ }
+ } else {
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatch: request COMPLETED by handler.\n");
+ }
+
+ LEAVE_NBF;
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ ENTER_NBF;
+ }
+
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ LEAVE_NBF;
+ return Status;
+} /* NbfDispatchOpenClose */
+
+
+NTSTATUS
+NbfDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+ IrpSp - Pointer to current IRP stack frame.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDeviceControl: Entered.\n");
+ }
+
+
+ //
+ // Branch to the appropriate request handler. Preliminary checking of
+ // the size of the request block is performed here so that it is known
+ // in the handlers that the minimum input parameters are readable. It
+ // is *not* determined here whether variable length input fields are
+ // passed correctly; this is a check which must be made within each routine.
+ //
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+
+#if MAGIC
+ case IOCTL_TDI_MAGIC_BULLET:
+
+ //
+ // Special: send the magic bullet (to trigger the Sniffer).
+ //
+
+ NbfPrint1 ("NBF: Sending user MagicBullet on %lx\n", DeviceContext);
+ {
+ extern VOID NbfSendMagicBullet (PDEVICE_CONTEXT, PTP_LINK);
+ NbfSendMagicBullet (DeviceContext, NULL);
+ }
+
+ if (IrpSp->Parameters.DeviceIoControl.Type3InputBuffer != NULL) {
+ NbfPrint0 ("NBF: DbgBreakPoint after MagicBullet\n");
+ DbgBreakPoint();
+ }
+
+ Status = STATUS_SUCCESS;
+ break;
+#endif
+
+#if DBG
+ case IOCTL_TDI_SEND_TEST:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDeviceControl: Internal IOCTL: start send side test\n");
+ }
+
+ (VOID) KeSetEvent( &TdiSendEvent, 0, FALSE );
+
+ break;
+
+ case IOCTL_TDI_RECEIVE_TEST:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDeviceControl: Internal IOCTL: start receive side test\n");
+ }
+
+ (VOID) KeSetEvent( &TdiReceiveEvent, 0, FALSE );
+
+ break;
+
+ case IOCTL_TDI_SERVER_TEST:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDeviceControl: Internal IOCTL: start receive side test\n");
+ }
+
+ (VOID) KeSetEvent( &TdiServerEvent, 0, FALSE );
+
+ break;
+#endif
+
+ default:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDeviceControl: invalid request type.\n");
+ }
+
+ //
+ // Convert the user call to the proper internal device call.
+ //
+
+ Status = TdiMapUserRequest (DeviceObject, Irp, IrpSp);
+
+ if (Status == STATUS_SUCCESS) {
+
+ //
+ // If TdiMapUserRequest returns SUCCESS then the IRP
+ // has been converted into an IRP_MJ_INTERNAL_DEVICE_CONTROL
+ // IRP, so we dispatch it as usual. The IRP will
+ // be completed by this call.
+ //
+ // NbfDispatchInternal expects to complete the IRP,
+ // so we change Status to PENDING so we don't.
+ //
+
+ (VOID)NbfDispatchInternal (DeviceObject, Irp);
+ Status = STATUS_PENDING;
+
+ }
+ }
+
+ return Status;
+} /* NbfDeviceControl */
+
+
+NTSTATUS
+NbfDispatchInternal (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE_CONTEXT DeviceContext;
+ PIO_STACK_LOCATION IrpSp;
+#if DBG
+ KIRQL IrqlOnEnter = KeGetCurrentIrql();
+#endif
+
+ ENTER_NBF;
+
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfInternalDeviceControl: Entered.\n");
+ }
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+
+
+ if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
+ LEAVE_NBF;
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ IoMarkIrpPending (Irp);
+ Irp->IoStatus.Status = STATUS_PENDING;
+ Irp->IoStatus.Information = 0;
+
+
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ {
+ PULONG Temp=(PULONG)&IrpSp->Parameters;
+ NbfPrint5 ("Got IrpSp %lx %lx %lx %lx %lx\n", Temp++, Temp++,
+ Temp++, Temp++, Temp++);
+ }
+ }
+
+ //
+ // Branch to the appropriate request handler. Preliminary checking of
+ // the size of the request block is performed here so that it is known
+ // in the handlers that the minimum input parameters are readable. It
+ // is *not* determined here whether variable length input fields are
+ // passed correctly; this is a check which must be made within each routine.
+ //
+
+ switch (IrpSp->MinorFunction) {
+
+ case TDI_ACCEPT:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiAccept request.\n");
+ }
+
+ Status = NbfTdiAccept (Irp);
+ break;
+
+ case TDI_ACTION:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiAction request.\n");
+ }
+
+ Status = NbfTdiAction (DeviceContext, Irp);
+ break;
+
+ case TDI_ASSOCIATE_ADDRESS:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiAccept request.\n");
+ }
+
+ Status = NbfTdiAssociateAddress (Irp);
+ break;
+
+ case TDI_DISASSOCIATE_ADDRESS:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiDisassociateAddress request.\n");
+ }
+
+ Status = NbfTdiDisassociateAddress (Irp);
+ break;
+
+ case TDI_CONNECT:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiConnect request\n");
+ }
+
+ Status = NbfTdiConnect (Irp);
+
+ break;
+
+ case TDI_DISCONNECT:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiDisconnect request.\n");
+ }
+
+ Status = NbfTdiDisconnect (Irp);
+ break;
+
+ case TDI_LISTEN:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiListen request.\n");
+ }
+
+ Status = NbfTdiListen (Irp);
+ break;
+
+ case TDI_QUERY_INFORMATION:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiQueryInformation request.\n");
+ }
+
+ Status = NbfTdiQueryInformation (DeviceContext, Irp);
+ break;
+
+ case TDI_RECEIVE:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiReceive request.\n");
+ }
+
+ Status = NbfTdiReceive (Irp);
+ break;
+
+ case TDI_RECEIVE_DATAGRAM:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiReceiveDatagram request.\n");
+ }
+
+ Status = NbfTdiReceiveDatagram (Irp);
+ break;
+
+ case TDI_SEND:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiSend request.\n");
+ }
+
+ Status = NbfTdiSend (Irp);
+ break;
+
+ case TDI_SEND_DATAGRAM:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiSendDatagram request.\n");
+ }
+
+ Status = NbfTdiSendDatagram (Irp);
+ break;
+
+ case TDI_SET_EVENT_HANDLER:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiSetEventHandler request.\n");
+ }
+
+ //
+ // Because this request will enable direct callouts from the
+ // transport provider at DISPATCH_LEVEL to a client-specified
+ // routine, this request is only valid in kernel mode, denying
+ // access to this request in user mode.
+ //
+
+ Status = NbfTdiSetEventHandler (Irp);
+ break;
+
+ case TDI_SET_INFORMATION:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiSetInformation request.\n");
+ }
+
+ Status = NbfTdiSetInformation (Irp);
+ break;
+
+#if DBG
+ case 0x7f:
+
+ //
+ // Special: send the magic bullet (to trigger the Sniffer).
+ //
+
+ NbfPrint1 ("NBF: Sending MagicBullet on %lx\n", DeviceContext);
+ {
+ extern VOID NbfSendMagicBullet (PDEVICE_CONTEXT, PTP_LINK);
+ NbfSendMagicBullet (DeviceContext, NULL);
+ }
+
+ Status = STATUS_SUCCESS;
+ break;
+#endif
+
+ //
+ // Something we don't know about was submitted.
+ //
+
+ default:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint1 ("NbfDispatchInternal: invalid request type %lx\n",
+ IrpSp->MinorFunction);
+ }
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ if (Status == STATUS_PENDING) {
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: request PENDING from handler.\n");
+ }
+ } else {
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: request COMPLETED by handler.\n");
+ }
+
+ LEAVE_NBF;
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ ENTER_NBF;
+ }
+
+
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint1 ("NbfDispatchInternal: exiting, status: %lx\n",Status);
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ LEAVE_NBF;
+#if DBG
+ ASSERT (KeGetCurrentIrql() == IrqlOnEnter);
+#endif
+
+ return Status;
+
+} /* NbfDispatchInternal */
+
+
+VOID
+NbfWriteResourceErrorLog(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN ULONG BytesNeeded,
+ IN ULONG ResourceId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ an out of resources condition. It will handle event codes
+ RESOURCE_POOL, RESOURCE_LIMIT, and RESOURCE_SPECIFIC.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context.
+
+ ErrorCode - The transport event code.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet.
+
+ BytesNeeded - If applicable, the number of bytes that could not
+ be allocated.
+
+ ResourceId - The resource ID of the allocated structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ PWSTR SecondString;
+ ULONG SecondStringSize;
+ PUCHAR StringLoc;
+ WCHAR ResourceIdBuffer[3];
+ WCHAR SizeBuffer[2];
+ WCHAR SpecificMaxBuffer[11];
+ ULONG SpecificMax;
+ INT i;
+
+ switch (ErrorCode) {
+
+ case EVENT_TRANSPORT_RESOURCE_POOL:
+ SecondString = NULL;
+ SecondStringSize = 0;
+ break;
+
+ case EVENT_TRANSPORT_RESOURCE_LIMIT:
+ SecondString = SizeBuffer;
+ SecondStringSize = sizeof(SizeBuffer);
+
+ switch (DeviceContext->MemoryLimit) {
+ case 100000: SizeBuffer[0] = L'1'; break;
+ case 250000: SizeBuffer[0] = L'2'; break;
+ case 0: SizeBuffer[0] = L'3'; break;
+ default: SizeBuffer[0] = L'0'; break;
+ }
+ SizeBuffer[1] = 0;
+ break;
+
+ case EVENT_TRANSPORT_RESOURCE_SPECIFIC:
+ switch (ResourceId) {
+ case UI_FRAME_RESOURCE_ID: SpecificMax = DeviceContext->SendPacketPoolSize; break;
+ case PACKET_RESOURCE_ID: SpecificMax = DeviceContext->SendPacketPoolSize; break;
+ case RECEIVE_PACKET_RESOURCE_ID: SpecificMax = DeviceContext->ReceivePacketPoolSize; break;
+ case RECEIVE_BUFFER_RESOURCE_ID: SpecificMax = DeviceContext->SendPacketPoolSize+DeviceContext->ReceivePacketPoolSize; break;
+ case ADDRESS_RESOURCE_ID: SpecificMax = DeviceContext->MaxAddresses; break;
+ case ADDRESS_FILE_RESOURCE_ID: SpecificMax = DeviceContext->MaxAddressFiles; break;
+ case CONNECTION_RESOURCE_ID: SpecificMax = DeviceContext->MaxConnections; break;
+ case LINK_RESOURCE_ID: SpecificMax = DeviceContext->MaxLinks; break;
+ case REQUEST_RESOURCE_ID: SpecificMax = DeviceContext->MaxRequests; break;
+ }
+
+ for (i=9; i>=0; i--) {
+ SpecificMaxBuffer[i] = (WCHAR)((SpecificMax % 10) + L'0');
+ SpecificMax /= 10;
+ if (SpecificMax == 0) {
+ break;
+ }
+ }
+ SecondString = SpecificMaxBuffer + i;
+ SecondStringSize = sizeof(SpecificMaxBuffer) - (i * sizeof(WCHAR));
+ SpecificMaxBuffer[10] = 0;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ DeviceContext->DeviceNameLength +
+ sizeof(ResourceIdBuffer) +
+ SecondStringSize;
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)DeviceContext,
+ EntrySize
+ );
+
+ //
+ // Convert the resource ID into a buffer.
+ //
+
+ ResourceIdBuffer[1] = (WCHAR)((ResourceId % 10) + L'0');
+ ResourceId /= 10;
+ ASSERT(ResourceId <= 9);
+ ResourceIdBuffer[0] = (WCHAR)((ResourceId % 10) + L'0');
+ ResourceIdBuffer[2] = 0;
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = sizeof(ULONG);
+ errorLogEntry->NumberOfStrings = (SecondString == NULL) ? 2 : 3;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+ errorLogEntry->DumpData[0] = BytesNeeded;
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ RtlCopyMemory (StringLoc, DeviceContext->DeviceName, DeviceContext->DeviceNameLength);
+ StringLoc += DeviceContext->DeviceNameLength;
+
+ RtlCopyMemory (StringLoc, ResourceIdBuffer, sizeof(ResourceIdBuffer));
+ StringLoc += sizeof(ResourceIdBuffer);
+
+ if (SecondString) {
+ RtlCopyMemory (StringLoc, SecondString, SecondStringSize);
+ }
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* NbfWriteResourceErrorLog */
+
+
+VOID
+NbfWriteGeneralErrorLog(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN ULONG DumpDataCount,
+ IN ULONG DumpData[]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ a general problem as indicated by the parameters. It handles
+ event codes REGISTER_FAILED, BINDING_FAILED, ADAPTER_NOT_FOUND,
+ TRANSFER_DATA, TOO_MANY_LINKS, and BAD_PROTOCOL. All these
+ events have messages with one or two strings in them.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context, or this may be
+ a driver object instead.
+
+ ErrorCode - The transport event code.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet.
+
+ FinalStatus - Used as the FinalStatus in the error log packet.
+
+ SecondString - If not NULL, the string to use as the %3
+ value in the error log packet.
+
+ DumpDataCount - The number of ULONGs of dump data.
+
+ DumpData - Dump data for the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG SecondStringSize;
+ PUCHAR StringLoc;
+ PWSTR DriverName;
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ (DumpDataCount * sizeof(ULONG));
+
+ if (DeviceContext->Type == IO_TYPE_DEVICE) {
+ EntrySize += (UCHAR)DeviceContext->DeviceNameLength;
+ } else {
+ DriverName = L"Nbf";
+ EntrySize += 4 * sizeof(WCHAR);
+ }
+
+ if (SecondString) {
+ SecondStringSize = (wcslen(SecondString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize += (UCHAR)SecondStringSize;
+ }
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)DeviceContext,
+ EntrySize
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = (USHORT)(DumpDataCount * sizeof(ULONG));
+ errorLogEntry->NumberOfStrings = (SecondString == NULL) ? 1 : 2;
+ errorLogEntry->StringOffset =
+ sizeof(IO_ERROR_LOG_PACKET) + ((DumpDataCount-1) * sizeof(ULONG));
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ if (DumpDataCount) {
+ RtlCopyMemory(errorLogEntry->DumpData, DumpData, DumpDataCount * sizeof(ULONG));
+ }
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ if (DeviceContext->Type == IO_TYPE_DEVICE) {
+ RtlCopyMemory (StringLoc, DeviceContext->DeviceName, DeviceContext->DeviceNameLength);
+ StringLoc += DeviceContext->DeviceNameLength;
+ } else {
+ RtlCopyMemory (StringLoc, DriverName, 4 * sizeof(WCHAR));
+ StringLoc += 4 * sizeof(WCHAR);
+ }
+ if (SecondString) {
+ RtlCopyMemory (StringLoc, SecondString, SecondStringSize);
+ }
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* NbfWriteGeneralErrorLog */
+
+
+VOID
+NbfWriteOidErrorLog(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NTSTATUS ErrorCode,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR AdapterString,
+ IN ULONG OidValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ a problem querying or setting an OID on an adapter. It handles
+ event codes SET_OID_FAILED and QUERY_OID_FAILED.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context.
+
+ ErrorCode - Used as the ErrorCode in the error log packet.
+
+ FinalStatus - Used as the FinalStatus in the error log packet.
+
+ AdapterString - The name of the adapter we were bound to.
+
+ OidValue - The OID which could not be set or queried.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG AdapterStringSize;
+ PUCHAR StringLoc;
+ WCHAR OidBuffer[9];
+ INT i;
+ UINT CurrentDigit;
+
+ AdapterStringSize = (wcslen(AdapterString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) -
+ sizeof(ULONG) +
+ DeviceContext->DeviceNameLength +
+ AdapterStringSize +
+ sizeof(OidBuffer);
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)DeviceContext,
+ EntrySize
+ );
+
+ //
+ // Convert the OID into a buffer.
+ //
+
+ for (i=7; i>=0; i--) {
+ CurrentDigit = OidValue & 0xf;
+ OidValue >>= 4;
+ if (CurrentDigit >= 0xa) {
+ OidBuffer[i] = (WCHAR)(CurrentDigit - 0xa + L'A');
+ } else {
+ OidBuffer[i] = (WCHAR)(CurrentDigit + L'0');
+ }
+ }
+ OidBuffer[8] = 0;
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = 0;
+ errorLogEntry->NumberOfStrings = 3;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) - sizeof(ULONG);
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ RtlCopyMemory (StringLoc, DeviceContext->DeviceName, DeviceContext->DeviceNameLength);
+ StringLoc += DeviceContext->DeviceNameLength;
+
+ RtlCopyMemory (StringLoc, OidBuffer, sizeof(OidBuffer));
+ StringLoc += sizeof(OidBuffer);
+
+ RtlCopyMemory (StringLoc, AdapterString, AdapterStringSize);
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* NbfWriteOidErrorLog */
+
+ULONG
+NbfInitializeOneDeviceContext(
+ OUT PNDIS_STATUS NdisStatus,
+ IN PDRIVER_OBJECT DriverObject,
+ IN PCONFIG_DATA NbfConfig,
+ IN INT AdapterIndex
+ )
+/*++
+
+Routine Description:
+
+ This routine creates and initializes one nbf device context. In order to
+ do this it must successfully open and bind to the adapter described by
+ nbfconfig->names[adapterindex].
+
+Arguments:
+
+ NdisStatus - The outputted status of the operations.
+
+ DriverObject - the nbf driver object.
+
+ NbfConfig - the transport configuration information from the registry.
+
+ AdapterIndex - which adapter to bind with.
+
+Return Value:
+
+ The number of successful binds.
+
+--*/
+
+{
+ ULONG i, j;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_REQUEST Request;
+ PTP_LINK Link;
+ PTP_CONNECTION Connection;
+ PTP_ADDRESS_FILE AddressFile;
+ PTP_ADDRESS Address;
+ PTP_UI_FRAME UIFrame;
+ PTP_PACKET Packet;
+ PNDIS_PACKET NdisPacket;
+ PRECEIVE_PACKET_TAG ReceiveTag;
+ PBUFFER_TAG BufferTag;
+ NTSTATUS status;
+ UINT SuccessfulOpens;
+ UINT MaxUserData;
+ ULONG InitReceivePackets;
+ BOOLEAN UniProcessor;
+#ifdef _PNP_POWER
+ PDEVICE_OBJECT DeviceObject;
+ UNICODE_STRING DeviceString;
+ UCHAR PermAddr[sizeof(TA_ADDRESS)+TDI_ADDRESS_LENGTH_NETBIOS];
+ PTA_ADDRESS pAddress = (PTA_ADDRESS)PermAddr;
+ PTDI_ADDRESS_NETBIOS NetBIOSAddress =
+ (PTDI_ADDRESS_NETBIOS)pAddress->Address;
+
+ pAddress->AddressLength = TDI_ADDRESS_LENGTH_NETBIOS;
+ pAddress->AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ NetBIOSAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+#endif
+ //
+ // Determine if we are on a uniprocessor.
+ //
+
+ if (*KeNumberProcessors == 1) {
+ UniProcessor = TRUE;
+ } else {
+ UniProcessor = FALSE;
+ }
+
+ {
+ j = AdapterIndex;
+ //
+ // Loop through all the adapters that are in the configuration
+ // information structure. Allocate a device object for each
+ // one that we find.
+ //
+
+ status = NbfCreateDeviceContext(
+ DriverObject,
+ &NbfConfig->Names[NbfConfig->DevicesOffset+j],
+ &DeviceContext
+ );
+
+ if (!NT_SUCCESS (status)) {
+ NbfWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_BINDING_FAILED,
+ 707,
+ status,
+ NbfConfig->Names[j].Buffer,
+ 0,
+ NULL);
+ *NdisStatus = status;
+ return(0);
+ }
+
+ DeviceContext->UniProcessor = UniProcessor;
+
+ //
+ // Initialize the timer and retry values (note that the link timeouts
+ // are converted from NT ticks to NBF ticks). These values may
+ // be modified by NbfInitializeNdis.
+ //
+
+ DeviceContext->DefaultT1Timeout = NbfConfig->DefaultT1Timeout / SHORT_TIMER_DELTA;
+ DeviceContext->DefaultT2Timeout = NbfConfig->DefaultT2Timeout / SHORT_TIMER_DELTA;
+ DeviceContext->DefaultTiTimeout = NbfConfig->DefaultTiTimeout / LONG_TIMER_DELTA;
+ DeviceContext->LlcRetries = NbfConfig->LlcRetries;
+ DeviceContext->LlcMaxWindowSize = NbfConfig->LlcMaxWindowSize;
+ DeviceContext->MaxConsecutiveIFrames = (UCHAR)NbfConfig->MaximumIncomingFrames;
+ DeviceContext->NameQueryRetries = NbfConfig->NameQueryRetries;
+ DeviceContext->NameQueryTimeout = NbfConfig->NameQueryTimeout;
+ DeviceContext->AddNameQueryRetries = NbfConfig->AddNameQueryRetries;
+ DeviceContext->AddNameQueryTimeout = NbfConfig->AddNameQueryTimeout;
+ DeviceContext->GeneralRetries = NbfConfig->GeneralRetries;
+ DeviceContext->GeneralTimeout = NbfConfig->GeneralTimeout;
+ DeviceContext->MinimumSendWindowLimit = NbfConfig->MinimumSendWindowLimit;
+
+ //
+ // Initialize our counter that records memory usage.
+ //
+
+ DeviceContext->MemoryUsage = 0;
+ DeviceContext->MemoryLimit = NbfConfig->MaxMemoryUsage;
+
+ DeviceContext->MaxRequests = NbfConfig->MaxRequests;
+ DeviceContext->MaxLinks = NbfConfig->MaxLinks;
+ DeviceContext->MaxConnections = NbfConfig->MaxConnections;
+ DeviceContext->MaxAddressFiles = NbfConfig->MaxAddressFiles;
+ DeviceContext->MaxAddresses = NbfConfig->MaxAddresses;
+
+ //
+ // Now fire up NDIS so this adapter talks
+ //
+
+ status = NbfInitializeNdis (DeviceContext,
+ NbfConfig,
+ j);
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // Log an error if we were failed to
+ // open this adapter.
+ //
+
+ NbfWriteGeneralErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_BINDING_FAILED,
+ 601,
+ status,
+ NbfConfig->Names[j].Buffer,
+ 0,
+ NULL);
+
+ NbfDereferenceDeviceContext ("Initialize NDIS failed", DeviceContext, DCREF_CREATION);
+ *NdisStatus = status;
+ return(0);
+
+ }
+
+#if 0
+ DbgPrint("Opened %S as %S\n", &NbfConfig->Names[j], &nameString);
+#endif
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint6 ("NbfInitialize: NDIS returned: %x %x %x %x %x %x as local address.\n",
+ DeviceContext->LocalAddress.Address[0],
+ DeviceContext->LocalAddress.Address[1],
+ DeviceContext->LocalAddress.Address[2],
+ DeviceContext->LocalAddress.Address[3],
+ DeviceContext->LocalAddress.Address[4],
+ DeviceContext->LocalAddress.Address[5]);
+ }
+
+ //
+ // Initialize our provider information structure; since it
+ // doesn't change, we just keep it around and copy it to
+ // whoever requests it.
+ //
+
+
+ MacReturnMaxDataSize(
+ &DeviceContext->MacInfo,
+ NULL,
+ 0,
+ DeviceContext->MaxSendPacketSize,
+ TRUE,
+ &MaxUserData);
+
+ DeviceContext->Information.Version = 0x0100;
+ DeviceContext->Information.MaxSendSize = 0x1fffe; // 128k - 2
+ DeviceContext->Information.MaxConnectionUserData = 0;
+ DeviceContext->Information.MaxDatagramSize =
+ MaxUserData - (sizeof(DLC_FRAME) + sizeof(NBF_HDR_CONNECTIONLESS));
+ DeviceContext->Information.ServiceFlags = NBF_SERVICE_FLAGS;
+ if (DeviceContext->MacInfo.MediumAsync) {
+ DeviceContext->Information.ServiceFlags |= TDI_SERVICE_POINT_TO_POINT;
+ }
+ DeviceContext->Information.MinimumLookaheadData =
+ 240 - (sizeof(DLC_FRAME) + sizeof(NBF_HDR_CONNECTIONLESS));
+ DeviceContext->Information.MaximumLookaheadData =
+ DeviceContext->MaxReceivePacketSize - (sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION));
+ DeviceContext->Information.NumberOfResources = NBF_TDI_RESOURCES;
+ KeQuerySystemTime (&DeviceContext->Information.StartTime);
+
+
+ //
+ // Allocate various structures we will need.
+ //
+
+ ENTER_NBF;
+
+ //
+ // The TP_UI_FRAME structure has a CHAR[1] field at the end
+ // which we expand upon to include all the headers needed;
+ // the size of the MAC header depends on what the adapter
+ // told us about its max header size.
+ //
+
+ DeviceContext->UIFrameHeaderLength =
+ DeviceContext->MacInfo.MaxHeaderLength +
+ sizeof(DLC_FRAME) +
+ sizeof(NBF_HDR_CONNECTIONLESS);
+
+ DeviceContext->UIFrameLength =
+ FIELD_OFFSET(TP_UI_FRAME, Header[0]) +
+ DeviceContext->UIFrameHeaderLength;
+
+
+ //
+ // The TP_PACKET structure has a CHAR[1] field at the end
+ // which we expand upon to include all the headers needed;
+ // the size of the MAC header depends on what the adapter
+ // told us about its max header size. TP_PACKETs are used
+ // for connection-oriented frame as well as for
+ // control frames, but since DLC_I_FRAME and DLC_S_FRAME
+ // are the same size, the header is the same size.
+ //
+
+ ASSERT (sizeof(DLC_I_FRAME) == sizeof(DLC_S_FRAME));
+
+ DeviceContext->PacketHeaderLength =
+ DeviceContext->MacInfo.MaxHeaderLength +
+ sizeof(DLC_I_FRAME) +
+ sizeof(NBF_HDR_CONNECTION);
+
+ DeviceContext->PacketLength =
+ FIELD_OFFSET(TP_PACKET, Header[0]) +
+ DeviceContext->PacketHeaderLength;
+
+
+ //
+ // The BUFFER_TAG structure has a CHAR[1] field at the end
+ // which we expand upong to include all the frame data.
+ //
+
+ DeviceContext->ReceiveBufferLength =
+ DeviceContext->MaxReceivePacketSize +
+ FIELD_OFFSET(BUFFER_TAG, Buffer[0]);
+
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NBFDRVR: pre-allocating requests.\n");
+ }
+ for (i=0; i<NbfConfig->InitRequests; i++) {
+
+ NbfAllocateRequest (DeviceContext, &Request);
+
+ if (Request == NULL) {
+ PANIC ("NbfInitialize: insufficient memory to allocate requests.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ InsertTailList (&DeviceContext->RequestPool, &Request->Linkage);
+#if DBG
+ NbfRequestTable[i+1] = (PVOID)Request;
+#endif
+ }
+#if DBG
+ NbfRequestTable[0] = (PVOID)NbfConfig->InitRequests;
+ NbfRequestTable[NbfConfig->InitRequests + 1] = (PVOID)
+ ((NBF_REQUEST_SIGNATURE << 16) | sizeof (TP_REQUEST));
+ InitializeListHead (&NbfGlobalRequestList);
+#endif
+
+ DeviceContext->RequestInitAllocated = NbfConfig->InitRequests;
+ DeviceContext->RequestMaxAllocated = NbfConfig->MaxRequests;
+
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint2 ("%d requests, %ld\n", NbfConfig->InitRequests, DeviceContext->MemoryUsage);
+ }
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NBFDRVR: allocating links.\n");
+ }
+ for (i=0; i<NbfConfig->InitLinks; i++) {
+
+ NbfAllocateLink (DeviceContext, &Link);
+
+ if (Link == NULL) {
+ PANIC ("NbfInitialize: insufficient memory to allocate links.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ InsertTailList (&DeviceContext->LinkPool, &Link->Linkage);
+#if DBG
+ NbfLinkTable[i+1] = (PVOID)Link;
+#endif
+ }
+#if DBG
+ NbfLinkTable[0] = (PVOID)NbfConfig->InitLinks;
+ NbfLinkTable[NbfConfig->InitLinks+1] = (PVOID)
+ ((NBF_LINK_SIGNATURE << 16) | sizeof (TP_LINK));
+#endif
+
+ DeviceContext->LinkInitAllocated = NbfConfig->InitLinks;
+ DeviceContext->LinkMaxAllocated = NbfConfig->MaxLinks;
+
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint2 ("%d links, %ld\n", NbfConfig->InitLinks, DeviceContext->MemoryUsage);
+ }
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NBFDRVR: allocating connections.\n");
+ }
+ for (i=0; i<NbfConfig->InitConnections; i++) {
+
+ NbfAllocateConnection (DeviceContext, &Connection);
+
+ if (Connection == NULL) {
+ PANIC ("NbfInitialize: insufficient memory to allocate connections.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ InsertTailList (&DeviceContext->ConnectionPool, &Connection->LinkList);
+#if DBG
+ NbfConnectionTable[i+1] = (PVOID)Connection;
+#endif
+ }
+#if DBG
+ NbfConnectionTable[0] = (PVOID)NbfConfig->InitConnections;
+ NbfConnectionTable[NbfConfig->InitConnections+1] = (PVOID)
+ ((NBF_CONNECTION_SIGNATURE << 16) | sizeof (TP_CONNECTION));
+#endif
+
+ DeviceContext->ConnectionInitAllocated = NbfConfig->InitConnections;
+ DeviceContext->ConnectionMaxAllocated = NbfConfig->MaxConnections;
+
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint2 ("%d connections, %ld\n", NbfConfig->InitConnections, DeviceContext->MemoryUsage);
+ }
+
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NBFDRVR: allocating AddressFiles.\n");
+ }
+ for (i=0; i<NbfConfig->InitAddressFiles; i++) {
+
+ NbfAllocateAddressFile (DeviceContext, &AddressFile);
+
+ if (AddressFile == NULL) {
+ PANIC ("NbfInitialize: insufficient memory to allocate Address Files.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ InsertTailList (&DeviceContext->AddressFilePool, &AddressFile->Linkage);
+#if DBG
+ NbfAddressFileTable[i+1] = (PVOID)AddressFile;
+#endif
+ }
+#if DBG
+ NbfAddressFileTable[0] = (PVOID)NbfConfig->InitAddressFiles;
+ NbfAddressFileTable[NbfConfig->InitAddressFiles + 1] = (PVOID)
+ ((NBF_ADDRESSFILE_SIGNATURE << 16) |
+ sizeof (TP_ADDRESS_FILE));
+#endif
+
+ DeviceContext->AddressFileInitAllocated = NbfConfig->InitAddressFiles;
+ DeviceContext->AddressFileMaxAllocated = NbfConfig->MaxAddressFiles;
+
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint2 ("%d address files, %ld\n", NbfConfig->InitAddressFiles, DeviceContext->MemoryUsage);
+ }
+
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NBFDRVR: allocating addresses.\n");
+ }
+ for (i=0; i<NbfConfig->InitAddresses; i++) {
+
+ NbfAllocateAddress (DeviceContext, &Address);
+ if (Address == NULL) {
+ PANIC ("NbfInitialize: insufficient memory to allocate addresses.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ InsertTailList (&DeviceContext->AddressPool, &Address->Linkage);
+#if DBG
+ NbfAddressTable[i+1] = (PVOID)Address;
+#endif
+ }
+#if DBG
+ NbfAddressTable[0] = (PVOID)NbfConfig->InitAddresses;
+ NbfAddressTable[NbfConfig->InitAddresses + 1] = (PVOID)
+ ((NBF_ADDRESS_SIGNATURE << 16) | sizeof (TP_ADDRESS));
+#endif
+
+ DeviceContext->AddressInitAllocated = NbfConfig->InitAddresses;
+ DeviceContext->AddressMaxAllocated = NbfConfig->MaxAddresses;
+
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint2 ("%d addresses, %ld\n", NbfConfig->InitAddresses, DeviceContext->MemoryUsage);
+ }
+
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NBFDRVR: allocating UI frames.\n");
+ }
+
+ for (i=0; i<NbfConfig->InitUIFrames; i++) {
+
+ NbfAllocateUIFrame (DeviceContext, &UIFrame);
+
+ if (UIFrame == NULL) {
+ PANIC ("NbfInitialize: insufficient memory to allocate UI frames.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ InsertTailList (&(DeviceContext->UIFramePool), &UIFrame->Linkage);
+#if DBG
+ NbfUiFrameTable[i+1] = UIFrame;
+#endif
+ }
+#if DBG
+ NbfUiFrameTable[0] = (PVOID)NbfConfig->InitUIFrames;
+#endif
+
+ DeviceContext->UIFrameInitAllocated = NbfConfig->InitUIFrames;
+
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint2 ("%d UI frames, %ld\n", NbfConfig->InitUIFrames, DeviceContext->MemoryUsage);
+ }
+
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NBFDRVR: allocating I frames.\n");
+ NbfPrint1 ("NBFDRVR: Packet pool header: %lx\n",&DeviceContext->PacketPool);
+ }
+
+ for (i=0; i<NbfConfig->InitPackets; i++) {
+
+ NbfAllocateSendPacket (DeviceContext, &Packet);
+ if (Packet == NULL) {
+ PANIC ("NbfInitialize: insufficient memory to allocate packets.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ PushEntryList (&DeviceContext->PacketPool, (PSINGLE_LIST_ENTRY)&Packet->Linkage);
+#if DBG
+ NbfSendPacketTable[i+1] = Packet;
+#endif
+ }
+#if DBG
+ NbfSendPacketTable[0] = (PVOID)NbfConfig->InitPackets;
+ NbfSendPacketTable[NbfConfig->InitPackets+1] = (PVOID)
+ ((NBF_PACKET_SIGNATURE << 16) | sizeof (TP_PACKET));
+#endif
+
+ DeviceContext->PacketInitAllocated = NbfConfig->InitPackets;
+
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint2 ("%d send packets, %ld\n", NbfConfig->InitPackets, DeviceContext->MemoryUsage);
+ }
+
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NBFDRVR: allocating RR frames.\n");
+ NbfPrint1 ("NBFDRVR: Packet pool header: %lx\n",&DeviceContext->RrPacketPool);
+ }
+
+ for (i=0; i<10; i++) {
+
+ NbfAllocateSendPacket (DeviceContext, &Packet);
+ if (Packet == NULL) {
+ PANIC ("NbfInitialize: insufficient memory to allocate packets.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ Packet->Action = PACKET_ACTION_RR;
+ PushEntryList (&DeviceContext->RrPacketPool, (PSINGLE_LIST_ENTRY)&Packet->Linkage);
+ }
+
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint2 ("%d send packets, %ld\n", 10, DeviceContext->MemoryUsage);
+ }
+
+
+ // Allocate receive Ndis packets
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NBFDRVR: allocating Ndis Receive packets.\n");
+ }
+ if (DeviceContext->MacInfo.SingleReceive) {
+ InitReceivePackets = 2;
+ } else {
+ InitReceivePackets = NbfConfig->InitReceivePackets;
+ }
+ for (i=0; i<InitReceivePackets; i++) {
+
+ NbfAllocateReceivePacket (DeviceContext, &NdisPacket);
+
+ if (NdisPacket == NULL) {
+ PANIC ("NbfInitialize: insufficient memory to allocate packet MDLs.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ ReceiveTag = (PRECEIVE_PACKET_TAG)NdisPacket->ProtocolReserved;
+ PushEntryList (&DeviceContext->ReceivePacketPool, &ReceiveTag->Linkage);
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ PNDIS_BUFFER NdisBuffer;
+ NdisQueryPacket(NdisPacket, NULL, NULL, &NdisBuffer, NULL);
+ NbfPrint2 ("NbfInitialize: Created NDIS Pkt: %x Buffer: %x\n",
+ NdisPacket, NdisBuffer);
+ }
+ }
+
+ DeviceContext->ReceivePacketInitAllocated = InitReceivePackets;
+
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint2 ("%d receive packets, %ld\n", InitReceivePackets, DeviceContext->MemoryUsage);
+ }
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NBFDRVR: allocating Ndis Receive buffers.\n");
+ }
+
+ for (i=0; i<NbfConfig->InitReceiveBuffers; i++) {
+
+ NbfAllocateReceiveBuffer (DeviceContext, &BufferTag);
+
+ if (BufferTag == NULL) {
+ PANIC ("NbfInitialize: Unable to allocate receive packet.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ PushEntryList (&DeviceContext->ReceiveBufferPool, (PSINGLE_LIST_ENTRY)&BufferTag->Linkage);
+
+ }
+
+ DeviceContext->ReceiveBufferInitAllocated = NbfConfig->InitReceiveBuffers;
+
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint2 ("%d receive buffers, %ld\n", NbfConfig->InitReceiveBuffers, DeviceContext->MemoryUsage);
+ }
+
+ DeviceContext->State = DEVICECONTEXT_STATE_OPEN;
+
+ //
+ // Start the link-level timers running.
+ //
+
+ NbfInitializeTimerSystem (DeviceContext);
+
+
+ //
+ // Now link the device into the global list.
+ //
+
+ InsertTailList (&NbfDeviceList, &DeviceContext->Linkage);
+
+ ++SuccessfulOpens;
+
+#ifdef _PNP_POWER
+ DeviceObject = (PDEVICE_OBJECT) DeviceContext;
+ DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+
+ RtlInitUnicodeString(&DeviceString, DeviceContext->DeviceName);
+ status = TdiRegisterDeviceObject(&DeviceString,
+ &DeviceContext->TdiDeviceHandle);
+
+ if (!NT_SUCCESS (status)) {
+ --SuccessfulOpens;
+ RemoveEntryList(&DeviceContext->Linkage);
+ goto cleanup;
+ }
+
+ RtlCopyMemory(NetBIOSAddress->NetbiosName,
+ DeviceContext->ReservedNetBIOSAddress, 16);
+
+
+ status = TdiRegisterNetAddress(pAddress,
+ &DeviceContext->ReservedAddressHandle);
+
+ if (!NT_SUCCESS (status)) {
+ --SuccessfulOpens;
+ RemoveEntryList(&DeviceContext->Linkage);
+ goto cleanup;
+ }
+#endif
+
+ LEAVE_NBF;
+ *NdisStatus = NDIS_STATUS_SUCCESS;
+
+ return(1);;
+
+cleanup:
+
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 501,
+ DeviceContext->MemoryUsage,
+ 0);
+
+ //
+ // Cleanup whatever device context we were initializing
+ // when we failed.
+ //
+ *NdisStatus = status;
+ ASSERT(status != STATUS_SUCCESS);
+
+ NbfFreeResources (DeviceContext);
+ NbfCloseNdis (DeviceContext);
+ NbfDereferenceDeviceContext ("Load failed", DeviceContext, DCREF_CREATION);
+
+
+ LEAVE_NBF;
+ }
+ return(0);
+}
diff --git a/private/ntos/tdi/nbf/nbfhdrs.h b/private/ntos/tdi/nbf/nbfhdrs.h
new file mode 100644
index 000000000..9dfa5966f
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbfhdrs.h
@@ -0,0 +1,257 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ nbfhdrs.h
+
+Abstract:
+
+ This module defines private structure definitions describing the layout
+ of the NetBIOS Frames Protocol headers for the NT NBF transport
+ provider.
+
+Author:
+
+ Stephen E. Jones (stevej) 25-Oct-1989
+
+Revision History:
+
+ David Beaver (dbeaver) 24-Sep-1990
+ remove pc586 and PDI specific code; add NDIS support
+
+--*/
+
+#ifndef _NBFHDRS_
+#define _NBFHDRS_
+
+//
+// Pack these headers, as they are sent fully packed on the network.
+//
+
+#ifdef PACKING
+
+#ifdef __STDC__
+#pragma Off(Align_members)
+#else
+#pragma pack(1)
+#endif // def __STDC__
+
+#endif // def PACKING
+
+#define NETBIOS_SIGNATURE_1 0xef // signature in NetBIOS frames.
+#define NETBIOS_SIGNATURE_0 0xff // 1st byte.
+#define NETBIOS_SIGNATURE 0xefff
+
+//
+// NetBIOS Frames Protocol Command Codes.
+//
+
+#define NBF_CMD_ADD_GROUP_NAME_QUERY 0x00
+#define NBF_CMD_ADD_NAME_QUERY 0x01
+#define NBF_CMD_NAME_IN_CONFLICT 0x02
+#define NBF_CMD_STATUS_QUERY 0x03
+#define NBF_CMD_TERMINATE_TRACE 0x07
+#define NBF_CMD_DATAGRAM 0x08
+#define NBF_CMD_DATAGRAM_BROADCAST 0x09
+#define NBF_CMD_NAME_QUERY 0x0a
+#define NBF_CMD_ADD_NAME_RESPONSE 0x0d
+#define NBF_CMD_NAME_RECOGNIZED 0x0e
+#define NBF_CMD_STATUS_RESPONSE 0x0f
+#define NBF_CMD_TERMINATE_TRACE2 0x13
+#define NBF_CMD_DATA_ACK 0x14
+#define NBF_CMD_DATA_FIRST_MIDDLE 0x15
+#define NBF_CMD_DATA_ONLY_LAST 0x16
+#define NBF_CMD_SESSION_CONFIRM 0x17
+#define NBF_CMD_SESSION_END 0x18
+#define NBF_CMD_SESSION_INITIALIZE 0x19
+#define NBF_CMD_NO_RECEIVE 0x1a
+#define NBF_CMD_RECEIVE_OUTSTANDING 0x1b
+#define NBF_CMD_RECEIVE_CONTINUE 0x1c
+#define NBF_CMD_SESSION_ALIVE 0x1f
+
+//
+// NBF Transport Layer Header.
+//
+
+typedef struct _NBF_HDR_GENERIC {
+ USHORT Length; // Length of this header in bytes.
+ UCHAR Signature [2]; // always {0xef, 0xff} for NBF.
+ UCHAR Command; // command code, NBF_CMD_xxx.
+ UCHAR Data1; // optional parameter.
+ USHORT Data2; // optional parameter.
+ USHORT TransmitCorrelator; // transmit correlator parameter.
+ USHORT ResponseCorrelator; // response correlator parameter.
+} NBF_HDR_GENERIC;
+typedef NBF_HDR_GENERIC UNALIGNED *PNBF_HDR_GENERIC;
+
+typedef struct _NBF_HDR_CONNECTION {
+ USHORT Length; // length of the header in bytes (14).
+ USHORT Signature; // always {0xef, 0xff} for NBF.
+ UCHAR Command; // command code, NBF_CMD_xxx.
+ UCHAR Data1; // optional parameter.
+ UCHAR Data2Low, Data2High; // Intel-formatted DW parameter.
+ USHORT TransmitCorrelator; // Intel-formatted DW param. (transmit correlator).
+ USHORT ResponseCorrelator; // Intel-formatted DW param. (response correlator).
+ UCHAR DestinationSessionNumber; // connection identifier of packet receiver.
+ UCHAR SourceSessionNumber; // connection identifier of packet sender.
+} NBF_HDR_CONNECTION;
+typedef NBF_HDR_CONNECTION UNALIGNED *PNBF_HDR_CONNECTION;
+
+typedef struct _NBF_HDR_CONNECTIONLESS {
+ USHORT Length; // length of the header in bytes (44).
+ USHORT Signature; // always {0xef, 0xff} for NBF.
+ UCHAR Command; // command code, NBF_CMD_xxx.
+ UCHAR Data1; // optional parameter.
+ UCHAR Data2Low, Data2High; // Intel-formatted DW parameter.
+ USHORT TransmitCorrelator; // Intel-formatted DW param. (transmit correlator).
+ USHORT ResponseCorrelator; // Intel-formatted DW param. (response correlator).
+ UCHAR DestinationName [NETBIOS_NAME_LENGTH]; // name of packet receiver.
+ UCHAR SourceName [NETBIOS_NAME_LENGTH]; // name of packet sender.
+} NBF_HDR_CONNECTIONLESS;
+typedef NBF_HDR_CONNECTIONLESS UNALIGNED *PNBF_HDR_CONNECTIONLESS;
+
+//
+// These macros are used to retrieve the transmit and response
+// correlators from an NBF_HDR_CONNECTION(LESS). The first two
+// are general, the second two are used when the correlators
+// are known to be WORD aligned.
+//
+
+#define TRANSMIT_CORR(_Hdr) (*(USHORT UNALIGNED *)(&(_Hdr)->TransmitCorrelator))
+#define RESPONSE_CORR(_Hdr) (*(USHORT UNALIGNED *)(&(_Hdr)->ResponseCorrelator))
+
+#define TRANSMIT_CORR_A(_Hdr) ((_Hdr)->TransmitCorrelator)
+#define RESPONSE_CORR_A(_Hdr) ((_Hdr)->ResponseCorrelator)
+
+#define HEADER_LENGTH(_Hdr) (*(USHORT UNALIGNED *)(&(_Hdr)->Length))
+#define HEADER_SIGNATURE(_Hdr) (*(USHORT UNALIGNED *)(&(_Hdr)->Signature))
+
+#define HEADER_LENGTH_A(_Hdr) ((_Hdr)->Length)
+#define HEADER_SIGNATURE_A(_Hdr) ((_Hdr)->Signature)
+
+typedef union _NBF_HDR {
+ NBF_HDR_GENERIC Generic;
+ NBF_HDR_CONNECTION ConnectionOrientedFrame;
+ NBF_HDR_CONNECTIONLESS ConnectionlessFrame;
+} NBF_HDR;
+typedef NBF_HDR UNALIGNED *PNBF_HDR;
+
+//
+// The following structures define I-frame, U-frame, and S-frame DLC headers.
+//
+
+#define DLC_SSAP_RESPONSE 0x0001 // if (ssap & DLC_SSAP_RESP), it's a response.
+#define DLC_SSAP_GLOBAL 0x00ff // the global SAP.
+#define DLC_SSAP_NULL 0x0000 // the null SAP.
+#define DLC_SSAP_MASK 0x00fe // mask to wipe out the response bit.
+#define DLC_DSAP_MASK 0x00fe // mask to wipe out the group SAP bit.
+
+#define DLC_CMD_RR 0x01 // command code for RR.
+#define DLC_CMD_RNR 0x05 // command code for RNR.
+#define DLC_CMD_REJ 0x09 // command code for REJ.
+
+#define DLC_CMD_SABME 0x6f // command code for SABME.
+#define DLC_CMD_DISC 0x43 // command code for DISC.
+#define DLC_CMD_UA 0x63 // command code for UA.
+#define DLC_CMD_DM 0x0f // command code for DM.
+#define DLC_CMD_FRMR 0x87 // command code for FRMR.
+#define DLC_CMD_UI 0x03 // command code for UI.
+#define DLC_CMD_XID 0xaf // command code for XID.
+#define DLC_CMD_TEST 0xe3 // command code for TEST.
+
+typedef struct _DLC_XID_INFORMATION {
+ UCHAR FormatId; // format of this XID frame.
+ UCHAR Info1; // first information byte.
+ UCHAR Info2; // second information byte.
+} DLC_XID_INFORMATION;
+typedef DLC_XID_INFORMATION UNALIGNED *PDLC_XID_INFORMATION;
+
+typedef struct _DLC_TEST_INFORMATION {
+ UCHAR Buffer [10]; // this buffer is actually arbitrarily large.
+} DLC_TEST_INFORMATION;
+typedef DLC_TEST_INFORMATION UNALIGNED *PDLC_TEST_INFORMATION;
+
+typedef struct _DLC_FRMR_INFORMATION {
+ UCHAR Command; // format: mmmpmm11, m=modifiers, p=poll/final.
+ UCHAR Ctrl; // control field of rejected frame.
+ UCHAR Vs; // our next send when error was detected.
+ UCHAR Vr; // our next receive when error was detected.
+ UCHAR Reason; // reason for sending FRMR: 000VZYXW.
+} DLC_FRMR_INFORMATION;
+typedef DLC_FRMR_INFORMATION UNALIGNED *PDLC_FRMR_INFORMATION;
+
+typedef struct _DLC_U_FRAME {
+ UCHAR Dsap; // Destination Service Access Point.
+ UCHAR Ssap; // Source Service Access Point.
+ UCHAR Command; // command code.
+ union { // information field for FRMR, TEST, XID.
+ DLC_XID_INFORMATION XidInfo; // XID information.
+ DLC_TEST_INFORMATION TestInfo; // TEST information.
+ DLC_FRMR_INFORMATION FrmrInfo; // FRMR information.
+ NBF_HDR_CONNECTIONLESS NbfHeader; // UI frame contains NetBIOS header.
+ } Information;
+} DLC_U_FRAME;
+typedef DLC_U_FRAME UNALIGNED *PDLC_U_FRAME;
+
+#define DLC_U_INDICATOR 0x03 // (cmd & DLC_U_IND) == DLC_U_IND --> U-frame.
+#define DLC_U_PF 0x10 // (cmd & DLC_U_PF) -> poll/final set.
+
+typedef struct _DLC_S_FRAME {
+ UCHAR Dsap; // Destination Service Access Point.
+ UCHAR Ssap; // Source Service Access Point.
+ UCHAR Command; // RR, RNR, REJ command code.
+ UCHAR RcvSeq; // receive seq #, bottom bit is poll/final.
+} DLC_S_FRAME;
+typedef DLC_S_FRAME UNALIGNED *PDLC_S_FRAME;
+
+#define DLC_S_PF 0x01 // (rcvseq & DLC_S_PF) means poll/final set.
+
+typedef struct _DLC_I_FRAME {
+ UCHAR Dsap; // Destination Service Access Point.
+ UCHAR Ssap; // Source Service Access Point.
+ UCHAR SendSeq; // send sequence number, bottom bit 0.
+ UCHAR RcvSeq; // rcv sequence number, bottom bit p/f.
+} DLC_I_FRAME;
+typedef DLC_I_FRAME UNALIGNED *PDLC_I_FRAME;
+
+#define DLC_I_PF 0x01 // (rcvseq & DLC_I_PF) means poll/final set.
+#define DLC_I_INDICATOR 0x01 // !(sndseq & DLC_I_INDICATOR) indicates I-frame.
+
+typedef struct _DLC_FRAME {
+ UCHAR Dsap; // Destination Service Access Point.
+ UCHAR Ssap; // Source Service Access Point.
+ UCHAR Byte1; // command byte.
+} DLC_FRAME;
+typedef DLC_FRAME UNALIGNED *PDLC_FRAME;
+
+
+//
+// This macro builds a DLC UI-frame header.
+//
+
+#define NbfBuildUIFrameHeader(_Header) \
+{ \
+ PDLC_FRAME DlcHeader = (PDLC_FRAME)(_Header); \
+ DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC; \
+ DlcHeader->Ssap = DSAP_NETBIOS_OVER_LLC; \
+ DlcHeader->Byte1 = DLC_CMD_UI; \
+}
+
+
+//
+// Resume previous structure packing method.
+//
+
+#ifdef PACKING
+
+#ifdef __STDC__
+#pragma Pop(Align_members)
+#else
+#pragma pack()
+#endif // def __STDC__
+
+#endif // def PACKING
+
+#endif // def _NBFHDRS_
diff --git a/private/ntos/tdi/nbf/nbfmac.c b/private/ntos/tdi/nbf/nbfmac.c
new file mode 100644
index 000000000..bbc418c19
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbfmac.c
@@ -0,0 +1,417 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ nbfmac.c
+
+Abstract:
+
+ This module contains code which implements Mac type dependent code for
+ the NBF transport.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode (Actually, unimportant)
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+UCHAR SingleRouteSourceRouting[] = { 0xc2, 0x70 };
+UCHAR GeneralRouteSourceRouting[] = { 0x82, 0x70 };
+ULONG DefaultSourceRoutingLength = 2;
+
+//
+// This is the interpretation of the length bits in
+// the 802.5 source-routing information.
+//
+
+ULONG SR802_5Lengths[8] = { 516, 1500, 2052, 4472,
+ 8144, 11407, 17800, 17800 };
+
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE,MacInitializeMacInfo)
+#pragma alloc_text(PAGE,MacSetNetBIOSMulticast)
+#endif
+
+
+VOID
+MacInitializeMacInfo(
+ IN NDIS_MEDIUM MacType,
+ IN BOOLEAN UseDix,
+ OUT PNBF_NDIS_IDENTIFICATION MacInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Fills in the MacInfo table based on MacType.
+
+Arguments:
+
+ MacType - The MAC type we wish to decode.
+
+ UseDix - TRUE if we should use DIX encoding on 802.3.
+
+ MacInfo - The MacInfo structure to fill in.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ switch (MacType) {
+ case NdisMedium802_3:
+ MacInfo->DestinationOffset = 0;
+ MacInfo->SourceOffset = 6;
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->AddressLength = 6;
+ if (UseDix) {
+ MacInfo->TransferDataOffset = 3;
+ MacInfo->MaxHeaderLength = 17;
+ MacInfo->MediumType = NdisMediumDix;
+ } else {
+ MacInfo->TransferDataOffset = 0;
+ MacInfo->MaxHeaderLength = 14;
+ MacInfo->MediumType = NdisMedium802_3;
+ }
+ MacInfo->MediumAsync = FALSE;
+ break;
+ case NdisMedium802_5:
+ MacInfo->DestinationOffset = 2;
+ MacInfo->SourceOffset = 8;
+ MacInfo->SourceRouting = TRUE;
+ MacInfo->AddressLength = 6;
+ MacInfo->TransferDataOffset = 0;
+ MacInfo->MaxHeaderLength = 32;
+ MacInfo->MediumType = NdisMedium802_5;
+ MacInfo->MediumAsync = FALSE;
+ break;
+ case NdisMediumFddi:
+ MacInfo->DestinationOffset = 1;
+ MacInfo->SourceOffset = 7;
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->AddressLength = 6;
+ MacInfo->TransferDataOffset = 0;
+ MacInfo->MaxHeaderLength = 13;
+ MacInfo->MediumType = NdisMediumFddi;
+ MacInfo->MediumAsync = FALSE;
+ break;
+ case NdisMediumWan:
+ MacInfo->DestinationOffset = 0;
+ MacInfo->SourceOffset = 6;
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->AddressLength = 6;
+ MacInfo->TransferDataOffset = 0;
+ MacInfo->MaxHeaderLength = 14;
+ MacInfo->MediumType = NdisMedium802_3;
+ MacInfo->MediumAsync = TRUE;
+ break;
+ default:
+ ASSERT(FALSE);
+ }
+}
+
+VOID
+MacConstructHeader (
+ IN PNBF_NDIS_IDENTIFICATION MacInfo,
+ IN PUCHAR Buffer,
+ IN PUCHAR DestinationAddress,
+ IN PUCHAR SourceAddress,
+ IN UINT PacketLength,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ OUT PUINT HeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to construct the Mac header for the particular
+ network type we're talking to.
+
+Arguments:
+
+ MacInfo - Describes the mac we wish to build a header for.
+
+ Buffer - Where to build the header.
+
+ DestinationAddress - the address this packet is to be sent to.
+
+ SourceAddress - Our address. Passing it in as a parameter allows us to play
+ games with source if we need to.
+
+ PacketLength - The length of this packet. Note that this does not
+ includes the Mac header.
+
+ SourceRouting - Optional source routing information.
+
+ SourceRoutingLength - The length of SourceRouting.
+
+ HeaderLength - Returns the length of the constructed header.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // Note network order of bytes.
+ //
+
+ switch (MacInfo->MediumType) {
+
+ case NdisMedium802_3:
+
+ *(ULONG UNALIGNED *)&Buffer[6] = *(ULONG UNALIGNED *)&SourceAddress[0];
+ Buffer[10] = SourceAddress[4];
+ Buffer[11] = SourceAddress[5];
+
+ *(ULONG UNALIGNED *)&Buffer[0] = *(ULONG UNALIGNED *)&DestinationAddress[0];
+ Buffer[4] = DestinationAddress[4];
+ Buffer[5] = DestinationAddress[5];
+
+ Buffer[12] = (UCHAR)(PacketLength >> 8);
+ Buffer[13] = (UCHAR)PacketLength;
+
+ *HeaderLength = 14;
+
+ break;
+
+ case NdisMediumDix:
+
+ *(ULONG UNALIGNED *)&Buffer[6] = *(ULONG UNALIGNED *)&SourceAddress[0];
+ Buffer[10] = SourceAddress[4];
+ Buffer[11] = SourceAddress[5];
+
+ *(ULONG UNALIGNED *)&Buffer[0] = *(ULONG UNALIGNED *)&DestinationAddress[0];
+ Buffer[4] = DestinationAddress[4];
+ Buffer[5] = DestinationAddress[5];
+
+ Buffer[12] = 0x80;
+ Buffer[13] = 0xd5;
+
+ Buffer[14] = (UCHAR)(PacketLength >> 8);
+ Buffer[15] = (UCHAR)PacketLength;
+
+ Buffer[16] = 0x00;
+ *HeaderLength = 17;
+
+ break;
+
+ case NdisMedium802_5:
+
+ Buffer[0] = TR_HEADER_BYTE_0;
+ Buffer[1] = TR_HEADER_BYTE_1;
+
+ ASSERT (TR_ADDRESS_LENGTH == 6);
+
+ *(ULONG UNALIGNED *)&Buffer[8] = *(ULONG UNALIGNED *)&SourceAddress[0];
+ Buffer[12] = SourceAddress[4];
+ Buffer[13] = SourceAddress[5];
+
+ *(ULONG UNALIGNED *)&Buffer[2] = *(ULONG UNALIGNED *)&DestinationAddress[0];
+ Buffer[6] = DestinationAddress[4];
+ Buffer[7] = DestinationAddress[5];
+
+ *HeaderLength = 14;
+ if (SourceRouting != NULL) {
+ RtlCopyMemory (&Buffer[14], SourceRouting, SourceRoutingLength);
+ Buffer[8] |= 0x80; // add SR bit in source address
+ *HeaderLength = 14 + SourceRoutingLength;
+ }
+
+ break;
+
+ case NdisMediumFddi:
+
+ Buffer[0] = FDDI_HEADER_BYTE;
+
+ *(ULONG UNALIGNED *)&Buffer[7] = *(ULONG UNALIGNED *)&SourceAddress[0];
+ Buffer[11] = SourceAddress[4];
+ Buffer[12] = SourceAddress[5];
+
+ *(ULONG UNALIGNED *)&Buffer[1] = *(ULONG UNALIGNED *)&DestinationAddress[0];
+ Buffer[5] = DestinationAddress[4];
+ Buffer[6] = DestinationAddress[5];
+
+ *HeaderLength = 13;
+
+ break;
+
+ default:
+ PANIC ("MacConstructHeader: PANIC! called with unsupported Mac type.\n");
+ }
+}
+
+
+VOID
+MacReturnMaxDataSize(
+ IN PNBF_NDIS_IDENTIFICATION MacInfo,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN UINT DeviceMaxFrameSize,
+ IN BOOLEAN AssumeWorstCase,
+ OUT PUINT MaxFrameSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the space available for user data in a MAC packet.
+ This will be the available space after the MAC header; all LLC and NBF
+ headers will be included in this space.
+
+Arguments:
+
+ MacInfo - Describes the MAC we wish to decode.
+
+ SourceRouting - If we are concerned about a reply to a specific
+ frame, then this information is used.
+
+ SourceRouting - The length of SourceRouting.
+
+ MaxFrameSize - The maximum frame size as returned by the adapter.
+
+ AssumeWorstCase - TRUE if we should be pessimistic.
+
+ MaxDataSize - The maximum data size computed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ switch (MacInfo->MediumType) {
+
+ case NdisMedium802_3:
+
+ //
+ // For 802.3, we always have a 14-byte MAC header.
+ //
+
+ *MaxFrameSize = DeviceMaxFrameSize - 14;
+ break;
+
+ case NdisMediumDix:
+
+ //
+ // For DIX, we have the 14-byte MAC header plus
+ // the three-byte DIX header.
+ //
+
+ *MaxFrameSize = DeviceMaxFrameSize - 17;
+ break;
+
+ case NdisMedium802_5:
+
+ //
+ // For 802.5, if we have source routing information then
+ // use that, otherwise assume the worst if told to.
+ //
+
+ if (SourceRouting && SourceRoutingLength >= 2) {
+
+ UINT SRLength;
+
+ SRLength = SR802_5Lengths[(SourceRouting[1] & 0x70) >> 4];
+ DeviceMaxFrameSize -= (SourceRoutingLength + 14);
+
+ if (DeviceMaxFrameSize < SRLength) {
+ *MaxFrameSize = DeviceMaxFrameSize;
+ } else {
+ *MaxFrameSize = SRLength;
+ }
+
+ } else {
+
+ if (!AssumeWorstCase) {
+ *MaxFrameSize = DeviceMaxFrameSize - 16;
+ } else if (DeviceMaxFrameSize < (544+sizeof(DLC_FRAME)+sizeof(NBF_HDR_CONNECTIONLESS))) {
+ *MaxFrameSize = DeviceMaxFrameSize - 32;
+ } else {
+ *MaxFrameSize = 512 + sizeof(DLC_FRAME) + sizeof(NBF_HDR_CONNECTIONLESS);
+ }
+ }
+
+ break;
+
+ case NdisMediumFddi:
+
+ //
+ // For FDDI, we always have a 13-byte MAC header.
+ //
+
+ *MaxFrameSize = DeviceMaxFrameSize - 13;
+ break;
+
+ }
+}
+
+
+
+VOID
+MacSetNetBIOSMulticast (
+ IN NDIS_MEDIUM Type,
+ IN PUCHAR Buffer
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the NetBIOS broadcast address into a buffer provided
+ by the user.
+
+Arguments:
+
+ Type the Mac Medium type.
+
+ Buffer the buffer to put the multicast address in.
+
+
+Return Value:
+
+ none.
+
+--*/
+{
+ switch (Type) {
+ case NdisMedium802_3:
+ case NdisMediumDix:
+ Buffer[0] = 0x03;
+ Buffer[ETHERNET_ADDRESS_LENGTH-1] = 0x01;
+ break;
+
+ case NdisMedium802_5:
+ Buffer[0] = 0xc0;
+ Buffer[TR_ADDRESS_LENGTH-1] = 0x80;
+ break;
+
+ case NdisMediumFddi:
+ Buffer[0] = 0x03;
+ Buffer[FDDI_ADDRESS_LENGTH-1] = 0x01;
+ break;
+
+ default:
+ PANIC ("MacSetNetBIOSAddress: PANIC! called with unsupported Mac type.\n");
+ }
+}
diff --git a/private/ntos/tdi/nbf/nbfmac.h b/private/ntos/tdi/nbf/nbfmac.h
new file mode 100644
index 000000000..8710f1d20
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbfmac.h
@@ -0,0 +1,766 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ mac.h
+
+Abstract:
+
+ This header file defines manifest constants and necessary macros for use
+ by transports dealing with multiple MAC cards through the NDIS interface.
+
+Author:
+
+ David Beaver (dbeaver) 02-Oct-1990
+
+Revision History:
+
+--*/
+
+#ifndef _MAC_
+#define _MAC_
+
+//
+// MAC-specific definitions, some of which get used below
+//
+
+#define MAX_MAC_HEADER_LENGTH 32
+#define MAX_SOURCE_ROUTING 18
+#define MAX_DEFAULT_SR 2
+
+#define ETHERNET_ADDRESS_LENGTH 6
+#define ETHERNET_PACKET_LENGTH 1514 // max size of an ethernet packet
+#define ETHERNET_HEADER_LENGTH 14 // size of the ethernet MAC header
+#define ETHERNET_DATA_LENGTH_OFFSET 12
+#define ETHERNET_DESTINATION_OFFSET 0
+#define ETHERNET_SOURCE_OFFSET 6
+
+#define TR_ADDRESS_LENGTH 6
+#define TR_ADDRESS_OFFSET 2
+#define TR_SPECIFIC_OFFSET 0
+#define TR_PACKET_LENGTH 1514 // max size of a TR packet //BUGBUG
+#define TR_HEADER_LENGTH 36 // size of the MAC header w/o source routing
+#define TR_DATA_LENGTH_OFFSET 0
+#define TR_DESTINATION_OFFSET 2
+#define TR_SOURCE_OFFSET 8
+#define TR_ROUTING_OFFSET 14 // starts at the 14th byte
+#define TR_GR_BCAST_LENGTH 2
+#define TR_GR_BROADCAST 0xC270 // what a general route b'cast looks like
+#define TR_ROUTING_LENGTH_MASK 0x1F // low 5 bits in byte
+#define TR_DIRECTION_MASK 0x80 // returns direction bit
+
+#define TR_PREAMBLE_AC 0x10 // how would these be specified?
+#define TR_PREAMBLE_FC 0x40
+
+#define TR_HEADER_BYTE_0 0x10
+#define TR_HEADER_BYTE_1 0x40
+
+#define FDDI_ADDRESS_LENGTH 6
+#define FDDI_HEADER_BYTE 0x57
+
+
+
+//
+// We need this to define information about the MAC. Note that
+// it is a strange structure in that the first four elements
+// are for use internally by the nbfmac routines, while the
+// DeviceContext knows about and uses the last two.
+//
+
+typedef struct _NBF_NDIS_IDENTIFICATION {
+ NDIS_MEDIUM MediumType;
+ BOOLEAN SourceRouting;
+ BOOLEAN MediumAsync;
+ BOOLEAN QueryWithoutSourceRouting;
+ BOOLEAN AllRoutesNameRecognized;
+ ULONG DestinationOffset;
+ ULONG SourceOffset;
+ ULONG AddressLength;
+ ULONG TransferDataOffset;
+ ULONG MaxHeaderLength;
+ BOOLEAN CopyLookahead;
+ BOOLEAN ReceiveSerialized;
+ BOOLEAN TransferSynchronous;
+ BOOLEAN SingleReceive;
+} NBF_NDIS_IDENTIFICATION, *PNBF_NDIS_IDENTIFICATION;
+
+
+
+VOID
+MacConstructHeader(
+ IN PNBF_NDIS_IDENTIFICATION MacInfo,
+ IN PUCHAR Buffer,
+ IN PUCHAR DestinationAddress,
+ IN PUCHAR SourceAddress,
+ IN UINT PacketLength,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ OUT PUINT HeaderLength
+ );
+
+VOID
+MacReturnMaxDataSize(
+ IN PNBF_NDIS_IDENTIFICATION MacInfo,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN UINT DeviceMaxFrameSize,
+ IN BOOLEAN AssumeWorstCase,
+ OUT PUINT MaxFrameSize
+ );
+
+VOID
+MacInitializeMacInfo(
+ IN NDIS_MEDIUM MacType,
+ IN BOOLEAN UseDix,
+ OUT PNBF_NDIS_IDENTIFICATION MacInfo
+ );
+
+
+extern UCHAR SingleRouteSourceRouting[];
+extern UCHAR GeneralRouteSourceRouting[];
+extern ULONG DefaultSourceRoutingLength;
+
+
+//++
+//
+// VOID
+// MacReturnDestinationAddress(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// IN PVOID Packet,
+// OUT PVOID * DestinationAddress
+// );
+//
+// Routine Description:
+//
+// Returns the a pointer to the destination address in the packet.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// Packet - The packet data.
+//
+// DestinationAddress - Returns the start of the destination address.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacReturnDestinationAddress(_MacInfo, _Packet, _DestinationAddress) \
+ *(_DestinationAddress) = ((PUCHAR)(_Packet)) + (_MacInfo)->DestinationOffset
+
+
+//++
+//
+// VOID
+// MacReturnSourceAddress(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// IN PVOID Packet,
+// OUT PHARDWARE_ADDRESS SourceAddressBuffer,
+// OUT PHARDWARE_ADDRESS * SourceAddress,
+// OUT BOOLEAN * Multicast OPTIONAL
+// );
+//
+// Routine Description:
+//
+// Copies the source address in the packet into SourceAddress.
+// NOTE THAT IT MAY COPY THE DATA, UNLIKE ReturnDestinationAddress
+// AND ReturnSourceRouting. Optionally, indicates whether the
+// destination address is a multicast address.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// Packet - The packet data.
+//
+// SourceAddressBuffer - A buffer to hold the source address,
+// if needed.
+//
+// SourceAddress - Returns a pointer to the source address.
+//
+// Multicast - Optional pointer to a BOOLEAN to receive indication
+// of whether the destination was a multicast address.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+//
+// NOTE: The default case below handles Ethernet and FDDI.
+//
+
+#define MacReturnSourceAddress(_MacInfo, _Packet, _SourceAddressBuffer, \
+ _SourceAddress, _Multicast) \
+{ \
+ PUCHAR TmpPacket = (PUCHAR)(_Packet); \
+ PUCHAR SrcBuffer = (PUCHAR)(_SourceAddressBuffer); \
+ \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_5: \
+ if (ARGUMENT_PRESENT(_Multicast)) { \
+ *(PBOOLEAN)(_Multicast) = TmpPacket[2] & 0x80; \
+ } \
+ if (TmpPacket[8] & 0x80) { \
+ *(PULONG)SrcBuffer = *(ULONG UNALIGNED *)(&TmpPacket[8]) & ~0x80;\
+ SrcBuffer[4] = TmpPacket[12]; \
+ SrcBuffer[5] = TmpPacket[13]; \
+ *(_SourceAddress) = (PHARDWARE_ADDRESS)SrcBuffer; \
+ } else { \
+ *(_SourceAddress) = (PHARDWARE_ADDRESS)(TmpPacket + 8); \
+ } \
+ break; \
+ default: \
+ if (ARGUMENT_PRESENT(_Multicast)) { \
+ *(PBOOLEAN)(_Multicast) = TmpPacket[0] & 0x01; \
+ } \
+ *(_SourceAddress) = (PHARDWARE_ADDRESS)(TmpPacket + \
+ (_MacInfo)->SourceOffset); \
+ break; \
+ } \
+}
+
+
+//++
+//
+// VOID
+// MacReturnSourceRouting(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// IN PVOID Packet,
+// OUT PVOID * SourceRouting
+// OUT PUINT SourceRoutingLength
+// );
+//
+// Routine Description:
+//
+// Returns the a pointer to the source routing info in the packet.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// Packet - The packet data.
+//
+// SourceRouting - Returns the start of the source routing information,
+// or NULL if none is present.
+//
+// SourceRoutingLength - Returns the length of the source routing
+// information.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacReturnSourceRouting(_MacInfo, _Packet, _SourceRouting, _SourceRoutingLength) \
+{ \
+ PUCHAR TmpPacket = (PUCHAR)(_Packet); \
+ *(_SourceRoutingLength) = 0; \
+ if ((_MacInfo)->SourceRouting) { \
+ if (TmpPacket[8] & 0x80) { \
+ *(_SourceRouting) = TmpPacket + 14; \
+ *(_SourceRoutingLength) = TmpPacket[14] & 0x1f; \
+ } else { \
+ *(_SourceRouting) = NULL; \
+ } \
+ } else { \
+ *(_SourceRouting) = NULL; \
+ } \
+}
+
+//++
+//
+// VOID
+// MacIsMulticast(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// IN PVOID Packet,
+// OUT PBOOLEAN Multicast
+// );
+//
+// Routine Description:
+//
+// Returns TRUE if the packet is sent to the multicast address.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// Packet - The packet data.
+//
+// Multicast - Returns the result.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacIsMulticast(_MacInfo, _Packet, _Multicast) \
+{ \
+ PUCHAR TmpPacket = (PUCHAR)(_Packet); \
+ \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_5: \
+ *(_Multicast) = ((TmpPacket[2] & 0x80) != 0); \
+ break; \
+ default: \
+ *(_Multicast) = ((TmpPacket[0] & 0x01) != 0); \
+ break; \
+ } \
+}
+
+//++
+//
+// VOID
+// MacReturnPacketLength(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// IN PVOID Header,
+// IN UINT PacketLength,
+// OUT PUINT DataLength
+// );
+//
+// Routine Description:
+//
+// Returns the length of data in the packet given the header.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// Header - The packet header.
+//
+// PacketLength - The length of the data (not including header).
+//
+// DataLength - Returns the length of the data. Unchanged if the
+// packet is not recognized. Should be initialized by caller to 0.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacReturnPacketLength(_MacInfo, _Header, _HeaderLength, _PacketLength, _DataLength, _LookaheadBuffer, _LookaheadBufferLength) \
+{ \
+ PUCHAR TmpPacket = (PUCHAR)(_Header); \
+ UINT TmpLength; \
+ \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_3: \
+ if ((_HeaderLength) >= 14) { \
+ TmpLength = (TmpPacket[12] << 8) | TmpPacket[13]; \
+ if (TmpLength <= 0x600) { \
+ if (TmpLength <= (_PacketLength)) { \
+ *(_DataLength) = TmpLength; \
+ } \
+ } \
+ } \
+ break; \
+ case NdisMedium802_5: \
+ if (((_HeaderLength) >= 14) && \
+ (!(TmpPacket[8] & 0x80) || \
+ ((_HeaderLength) >= \
+ (UINT)(14 + (TmpPacket[14] & 0x1f))))) { \
+ *(_DataLength) = (_PacketLength); \
+ } \
+ break; \
+ case NdisMediumFddi: \
+ if ((_HeaderLength) >= 13) { \
+ *(_DataLength) = (_PacketLength); \
+ } \
+ break; \
+ case NdisMediumDix: \
+ if ((TmpPacket[12] == 0x80) && (TmpPacket[13] == 0xd5)) { \
+ if (*(_LookaheadBufferLength) >= 3) { \
+ TmpPacket = (PUCHAR)(*(_LookaheadBuffer)); \
+ TmpLength = (TmpPacket[0] << 8) | TmpPacket[1]; \
+ if (TmpLength <= (_PacketLength)-3) { \
+ *(_DataLength) = TmpLength; \
+ *(_LookaheadBuffer) = (PVOID)(TmpPacket + 3); \
+ *(_LookaheadBufferLength) -= 3; \
+ } \
+ } \
+ } \
+ break; \
+ } \
+}
+
+//++
+//
+// VOID
+// MacReturnHeaderLength(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// IN PVOID Packet,
+// OUT PVOID HeaderLength,
+// );
+//
+// Routine Description:
+//
+// Returns the length of the MAC header in a packet (this
+// is used for loopback indications to separate header
+// and data).
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// Header - The packet header.
+//
+// HeaderLength - Returns the length of the header.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacReturnHeaderLength(_MacInfo, _Header, _HeaderLength) \
+{ \
+ PUCHAR TmpPacket = (PUCHAR)(_Header); \
+ \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_3: \
+ case NdisMediumDix: \
+ *(_HeaderLength) = 14; \
+ break; \
+ case NdisMedium802_5: \
+ if (TmpPacket[8] & 0x80) { \
+ *(_HeaderLength) = (TmpPacket[14] & 0x1f) + 14; \
+ } else { \
+ *(_HeaderLength) = 14; \
+ } \
+ break; \
+ case NdisMediumFddi: \
+ *(_HeaderLength) = 13; \
+ break; \
+ } \
+}
+
+//++
+//
+// VOID
+// MacReturnSingleRouteSR(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// OUT PVOID * SingleRouteSR,
+// OUT PUINT SingleRouteSRLength
+// );
+//
+// Routine Description:
+//
+// Returns the a pointer to the standard single route broadcast
+// source routing information for the media type. This is used
+// for ADD_NAME_QUERY, DATAGRAM, NAME_IN_CONFLICT, NAME_QUERY,
+// and STATUS_QUERY frames.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// SingleRouteSR - Returns a pointer to the data.
+//
+// SingleRouteSRLength - The length of SingleRouteSR.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacReturnSingleRouteSR(_MacInfo, _SingleRouteSR, _SingleRouteSRLength) \
+{ \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_5: \
+ *(_SingleRouteSR) = SingleRouteSourceRouting; \
+ *(_SingleRouteSRLength) = DefaultSourceRoutingLength; \
+ break; \
+ default: \
+ *(_SingleRouteSR) = NULL; \
+ break; \
+ } \
+}
+
+
+//++
+//
+// VOID
+// MacReturnGeneralRouteSR(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// OUT PVOID * GeneralRouteSR,
+// OUT PUINT GeneralRouteSRLength
+// );
+//
+// Routine Description:
+//
+// Returns the a pointer to the standard general route broadcast
+// source routing information for the media type. This is used
+// for NAME_RECOGNIZED frames.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// GeneralRouteSR - Returns a pointer to the data.
+//
+// GeneralRouteSRLength - The length of GeneralRouteSR.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacReturnGeneralRouteSR(_MacInfo, _GeneralRouteSR, _GeneralRouteSRLength) \
+{ \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_5: \
+ *(_GeneralRouteSR) = GeneralRouteSourceRouting; \
+ *(_GeneralRouteSRLength) = DefaultSourceRoutingLength; \
+ break; \
+ default: \
+ *(_GeneralRouteSR) = NULL; \
+ break; \
+ } \
+}
+
+#if 0
+
+//++
+//
+// VOID
+// MacCreateGeneralRouteReplySR(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// IN PUCHAR ExistingSR,
+// IN UINT ExistingSRLength,
+// OUT PUCHAR * NewSR
+// );
+//
+// Routine Description:
+//
+// This modifies an existing source routing entry to make
+// it into a general-route source routing entry. The assumption
+// is that is to reply to existing source routing, so the
+// direction bit is also reversed. In addition, if it is
+// determined that no source routing is needed in the reply,
+// then NULL is returned.
+//
+// Note that the information is modified in-place, but a
+// separate pointer is returned (to allow NULL to be returned).
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// ExistingSR - The existing source routing to be modified.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacCreateGeneralRouteReplySR(_MacInfo, _ExistingSR, _ExistingSRLength, _NewSR) \
+{ \
+ if (_ExistingSR) { \
+ PUCHAR TmpSR = (PUCHAR)(_ExistingSR); \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_5: \
+ TmpSR[0] = (TmpSR[0] & 0x1f) | 0x80; \
+ TmpSR[1] = (TmpSR[1] ^ 0x80); \
+ *(_NewSR) = (_ExistingSR); \
+ break; \
+ default: \
+ *(_NewSR) = (_ExistingSR); \
+ break; \
+ } \
+ } else { \
+ *(_NewSR) = NULL; \
+ } \
+}
+#endif
+
+
+//++
+//
+// VOID
+// MacCreateNonBroadcastReplySR(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// IN PUCHAR ExistingSR,
+// IN UINT ExistingSRLength,
+// OUT PUCHAR * NewSR
+// );
+//
+// Routine Description:
+//
+// This modifies an existing source routing entry to make
+// it into a non-broadcast source routing entry. The assumption
+// is that is to reply to existing source routing, so the
+// direction bit is also reversed. In addition, if it is
+// determined that no source routing is needed in the reply,
+// then NULL is returned.
+//
+// Note that the information is modified in-place, but a
+// separate pointer is returned (to allow NULL to be returned).
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// ExistingSR - The existing source routing to be modified.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacCreateNonBroadcastReplySR(_MacInfo, _ExistingSR, _ExistingSRLength, _NewSR) \
+{ \
+ if (_ExistingSR) { \
+ PUCHAR TmpSR = (PUCHAR)(_ExistingSR); \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_5: \
+ if ((_ExistingSRLength) == 2) { \
+ *(_NewSR) = NULL; \
+ } else { \
+ TmpSR[0] = (TmpSR[0] & 0x1f); \
+ TmpSR[1] = (TmpSR[1] ^ 0x80); \
+ *(_NewSR) = (_ExistingSR); \
+ } \
+ break; \
+ default: \
+ *(_NewSR) = (_ExistingSR); \
+ break; \
+ } \
+ } else { \
+ *(_NewSR) = NULL; \
+ } \
+}
+
+
+//++
+//
+// VOID
+// MacModifyHeader(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// IN PUCHAR Header,
+// IN UINT PacketLength
+// );
+//
+// Routine Description:
+//
+// Modifies a pre-built packet header to include the
+// packet length. Used for connection-oriented traffic
+// where the header is pre-built.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// Header - The header to modify.
+//
+// PacketLength - Packet length (not including the header).
+// Currently this is the only field that cannot be pre-built.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacModifyHeader(_MacInfo, _Header, _PacketLength) \
+{ \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_3: \
+ (_Header)[12] = (UCHAR)((_PacketLength) >> 8); \
+ (_Header)[13] = (UCHAR)((_PacketLength) & 0xff); \
+ break; \
+ case NdisMediumDix: \
+ (_Header)[14] = (UCHAR)((_PacketLength) >> 8); \
+ (_Header)[15] = (UCHAR)((_PacketLength) & 0xff); \
+ break; \
+ } \
+}
+
+
+//++
+//
+// VOID
+// MacReturnMagicAddress(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// IN PVOID Address,
+// OUT PULARGE_INTEGER Magic
+// );
+//
+// Routine Description:
+//
+// MacReturnMagicAddress returns the link as a 64 bit number.
+// We then find the link in the link trees by doing a large
+// integer comparison.
+//
+// The number is constructed by assigning the last four bytes of
+// the address as the low longword, and the first two bytes as
+// the high one. For 802_5 we need to mask off the source routing
+// bit in byte 0 of the address.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// Address - The address we are encoding.
+//
+// Magic - Returns the magic number for this address.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacReturnMagicAddress(_MacInfo, _Address, _Magic) \
+{ \
+ PUCHAR TempAddr = (PUCHAR)(_Address); \
+ \
+ (_Magic)->LowPart = *((LONG UNALIGNED *)(TempAddr + 2)); \
+ if ((_MacInfo)->MediumType == NdisMedium802_5) { \
+ (_Magic)->HighPart = ((TempAddr[0] & 0x7f) << 8) + TempAddr[1]; \
+ } else { \
+ (_Magic)->HighPart = (TempAddr[0] << 8) + TempAddr[1]; \
+ } \
+}
+
+
+VOID
+MacSetNetBIOSMulticast (
+ IN NDIS_MEDIUM Type,
+ IN PUCHAR Buffer
+ );
+
+
+
+// VOID
+// NbfSetNdisPacketLength (
+// IN NDIS_PACKET Packet,
+// IN ULONG Length
+// );
+//
+// NB: This is not a general purpose macro; it assumes that we are setting the
+// length of an NDIS packet with only one NDIS_BUFFER chained. We do
+// this to save time during the sending of short control packets.
+//
+
+#define NbfSetNdisPacketLength(_packet,_length) { \
+ PNDIS_BUFFER NdisBuffer; \
+ NdisQueryPacket((_packet), NULL, NULL, &NdisBuffer, NULL); \
+ NdisAdjustBufferLength(NdisBuffer, (_length)); \
+ NdisRecalculatePacketCounts(_packet); \
+}
+
+#endif // ifdef _MAC_
+
diff --git a/private/ntos/tdi/nbf/nbfndis.c b/private/ntos/tdi/nbf/nbfndis.c
new file mode 100644
index 000000000..9dd7902bd
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbfndis.c
@@ -0,0 +1,1956 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ nbfndis.c
+
+Abstract:
+
+ This module contains code which implements the routines used to interface
+ NBF and NDIS. All callback routines (except for Transfer Data,
+ Send Complete, and ReceiveIndication) are here, as well as those routines
+ called to initialize NDIS.
+
+Author:
+
+ David Beaver (dbeaver) 13-Feb-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ David Beaver (dbeaver) 1-July-1991
+ modify to use new TDI interface
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef NBF_LOCKS // see spnlckdb.c
+
+VOID
+NbfFakeSendCompletionHandler(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ );
+
+VOID
+NbfFakeTransferDataComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus,
+ IN UINT BytesTransferred
+ );
+
+#endif
+
+
+//
+// This is a one-per-driver variable used in binding
+// to the NDIS interface.
+//
+
+NDIS_HANDLE NbfNdisProtocolHandle = (NDIS_HANDLE)NULL;
+
+
+NDIS_STATUS
+NbfSubmitNdisRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN PNDIS_STRING AdapterName
+ );
+
+VOID
+NbfOpenAdapterComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN NDIS_STATUS OpenErrorStatus
+ );
+
+VOID
+NbfCloseAdapterComplete(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+NbfResetComplete(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+NbfRequestComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS NdisStatus
+ );
+
+VOID
+NbfStatusIndication (
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength
+ );
+
+VOID
+NbfProcessStatusClosing(
+ IN PVOID Parameter
+ );
+
+VOID
+NbfStatusComplete (
+ IN NDIS_HANDLE NdisBindingContext
+ );
+
+
+#ifdef _PNP_POWER
+VOID
+NbfProtocolBindAdapter(
+ OUT PNDIS_STATUS NdisStatus,
+ IN NDIS_HANDLE BindContext,
+ IN PNDIS_STRING DeviceName,
+ IN PVOID SystemSpecific1,
+ IN PVOID SystemSpecific2
+ );
+VOID
+NbfProtocolUnbindAdapter(
+ OUT PNDIS_STATUS NdisStatus,
+ IN NDIS_HANDLE ProtocolBindContext,
+ IN PNDIS_HANDLE UnbindContext
+ );
+#endif
+
+#ifdef ALLOC_PRAGMA
+#ifndef _PNP_POWER
+#pragma alloc_text(INIT,NbfRegisterProtocol)
+#pragma alloc_text(INIT,NbfSubmitNdisRequest)
+#pragma alloc_text(INIT,NbfInitializeNdis)
+#else // PNP_POWER
+#pragma alloc_text(PAGE,NbfProtocolBindAdapter)
+#pragma alloc_text(PAGE,NbfProtocolUnbindAdapter)
+#pragma alloc_text(PAGE,NbfRegisterProtocol)
+#pragma alloc_text(PAGE,NbfSubmitNdisRequest)
+#pragma alloc_text(PAGE,NbfInitializeNdis)
+#endif
+#endif
+
+
+NTSTATUS
+NbfRegisterProtocol (
+ IN PUNICODE_STRING NameString
+ )
+
+/*++
+
+Routine Description:
+
+ This routine introduces this transport to the NDIS interface.
+
+Arguments:
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+ STATUS_SUCCESS if all goes well,
+ Failure status if we tried to register and couldn't,
+ STATUS_INSUFFICIENT_RESOURCES if we couldn't even try to register.
+
+--*/
+
+{
+ NDIS_STATUS ndisStatus;
+
+ PNDIS_PROTOCOL_CHARACTERISTICS ProtChars; // Used temporarily to register
+
+ ProtChars = ExAllocatePoolWithTag(
+ NonPagedPool,
+#ifndef _PNP_POWER
+ sizeof(NDIS_PROTOCOL_CHARACTERISTICS) +
+#else
+ sizeof(NDIS40_PROTOCOL_CHARACTERISTICS) +
+#endif
+ NameString->MaximumLength,
+ ' FBN');
+
+ if (ProtChars == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Set up the characteristics of this protocol
+ //
+#ifndef _PNP_POWER
+ ProtChars->MajorNdisVersion = 3;
+#else
+ ProtChars->MajorNdisVersion = 4;
+ ProtChars->ReceivePacketHandler = NULL;
+ ProtChars->TranslateHandler = NULL;
+ ProtChars->BindAdapterHandler = NbfProtocolBindAdapter; // FIX ME!!!
+ ProtChars->UnbindAdapterHandler = NbfProtocolUnbindAdapter; // FIX ME!!!
+#endif
+ ProtChars->MinorNdisVersion = 0;
+
+ ProtChars->Name.Length = NameString->Length;
+ ProtChars->Name.Buffer = (PWCHAR)(ProtChars+1);
+ RtlCopyMemory (ProtChars->Name.Buffer, NameString->Buffer, NameString->Length);
+ ProtChars->Name.Buffer[NameString->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ ProtChars->OpenAdapterCompleteHandler = NbfOpenAdapterComplete;
+ ProtChars->CloseAdapterCompleteHandler = NbfCloseAdapterComplete;
+ ProtChars->ResetCompleteHandler = NbfResetComplete;
+ ProtChars->RequestCompleteHandler = NbfRequestComplete;
+
+#ifdef NBF_LOCKS
+ ProtChars->SendCompleteHandler = NbfFakeSendCompletionHandler;
+ ProtChars->TransferDataCompleteHandler = NbfFakeTransferDataComplete;
+#else
+ ProtChars->SendCompleteHandler = NbfSendCompletionHandler;
+ ProtChars->TransferDataCompleteHandler = NbfTransferDataComplete;
+#endif
+
+ ProtChars->ReceiveHandler = NbfReceiveIndication;
+ ProtChars->ReceiveCompleteHandler = NbfReceiveComplete;
+ ProtChars->StatusHandler = NbfStatusIndication;
+ ProtChars->StatusCompleteHandler = NbfStatusComplete;
+
+ NdisRegisterProtocol (
+ &ndisStatus,
+ &NbfNdisProtocolHandle,
+ ProtChars,
+ (UINT)sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + NameString->MaximumLength);
+
+ ExFreePool (ProtChars);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS) {
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint1("NbfInitialize: NdisRegisterProtocol failed: %s\n",
+ NbfGetNdisStatus(ndisStatus));
+ }
+#endif
+ return (NTSTATUS)ndisStatus;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+VOID
+NbfDeregisterProtocol (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes this transport to the NDIS interface.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS ndisStatus;
+
+ if (NbfNdisProtocolHandle != (NDIS_HANDLE)NULL) {
+ NdisDeregisterProtocol (
+ &ndisStatus,
+ NbfNdisProtocolHandle);
+ NbfNdisProtocolHandle = (NDIS_HANDLE)NULL;
+ }
+}
+
+
+NDIS_STATUS
+NbfSubmitNdisRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN PNDIS_STRING AdapterString
+ )
+
+/*++
+
+Routine Description:
+
+ This routine passed an NDIS_REQUEST to the MAC and waits
+ until it has completed before returning the final status.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context for this driver.
+
+ NdisRequest - Pointer to the NDIS_REQUEST to submit.
+
+ AdapterString - The name of the adapter, in case an error needs
+ to be logged.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NDIS_STATUS NdisStatus;
+
+ NdisRequest(
+ &NdisStatus,
+ DeviceContext->NdisBindingHandle,
+ NdisRequest);
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint1 ("OID %lx pended.\n",
+ NdisRequest->DATA.QUERY_INFORMATION.Oid);
+ }
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &DeviceContext->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = DeviceContext->NdisRequestStatus;
+
+ KeResetEvent(
+ &DeviceContext->NdisRequestEvent
+ );
+
+ }
+
+ if (NdisStatus == STATUS_SUCCESS) {
+
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ if (NdisRequest->RequestType == NdisRequestSetInformation) {
+ NbfPrint1 ("Nbfdrvr: Set OID %lx succeeded.\n",
+ NdisRequest->DATA.SET_INFORMATION.Oid);
+ } else {
+ NbfPrint1 ("Nbfdrvr: Query OID %lx succeeded.\n",
+ NdisRequest->DATA.QUERY_INFORMATION.Oid);
+ }
+ }
+
+ } else {
+#if DBG
+ if (NdisRequest->RequestType == NdisRequestSetInformation) {
+ NbfPrint2 ("Nbfdrvr: Set OID %lx failed: %s.\n",
+ NdisRequest->DATA.SET_INFORMATION.Oid, NbfGetNdisStatus(NdisStatus));
+ } else {
+ NbfPrint2 ("Nbfdrvr: Query OID %lx failed: %s.\n",
+ NdisRequest->DATA.QUERY_INFORMATION.Oid, NbfGetNdisStatus(NdisStatus));
+ }
+#endif
+ NbfWriteOidErrorLog(
+ DeviceContext,
+ NdisRequest->RequestType == NdisRequestSetInformation ?
+ EVENT_TRANSPORT_SET_OID_FAILED : EVENT_TRANSPORT_QUERY_OID_FAILED,
+ NdisStatus,
+ AdapterString->Buffer,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid);
+ }
+
+ return NdisStatus;
+}
+
+
+NTSTATUS
+NbfInitializeNdis (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PCONFIG_DATA NbfConfig,
+ IN UINT ConfigInfoNameIndex
+ )
+
+/*++
+
+Routine Description:
+
+ This routine introduces this transport to the NDIS interface and sets up
+ any necessary NDIS data structures (Buffer pools and such). It will be
+ called for each adapter opened by this transport.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ ULONG SendPacketReservedLength;
+ ULONG ReceivePacketReservedLen;
+ ULONG SendPacketPoolSize;
+ ULONG ReceivePacketPoolSize;
+ NDIS_STATUS NdisStatus;
+ NDIS_STATUS OpenErrorStatus;
+ NDIS_MEDIUM NbfSupportedMedia[] = { NdisMedium802_3, NdisMedium802_5, NdisMediumFddi, NdisMediumWan };
+ UINT SelectedMedium;
+ NDIS_REQUEST NbfRequest;
+ UCHAR NbfDataBuffer[6];
+ NDIS_OID NbfOid;
+ UCHAR WanProtocolId[6] = { 0x80, 0x00, 0x00, 0x00, 0x80, 0xd5 };
+ ULONG WanHeaderFormat = NdisWanHeaderEthernet;
+ ULONG MinimumLookahead = 128 + sizeof(DLC_FRAME) + sizeof(NBF_HDR_CONNECTIONLESS);
+ ULONG MacOptions;
+ PNDIS_STRING AdapterString;
+
+
+ //
+ // Initialize this adapter for NBF use through NDIS
+ //
+
+ //
+ // This event is used in case any of the NDIS requests
+ // pend; we wait until it is set by the completion
+ // routine, which also sets NdisRequestStatus.
+ //
+
+ KeInitializeEvent(
+ &DeviceContext->NdisRequestEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ DeviceContext->NdisBindingHandle = NULL;
+ AdapterString = (PNDIS_STRING)&NbfConfig->Names[ConfigInfoNameIndex];
+
+ NdisOpenAdapter (
+ &NdisStatus,
+ &OpenErrorStatus,
+ &DeviceContext->NdisBindingHandle,
+ &SelectedMedium,
+ NbfSupportedMedia,
+ sizeof (NbfSupportedMedia) / sizeof(NDIS_MEDIUM),
+ NbfNdisProtocolHandle,
+ (NDIS_HANDLE)DeviceContext,
+ AdapterString,
+ 0,
+ NULL);
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint1 ("Adapter %S open pended.\n", AdapterString);
+ }
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &DeviceContext->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = DeviceContext->NdisRequestStatus;
+
+ KeResetEvent(
+ &DeviceContext->NdisRequestEvent
+ );
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint1 ("Adapter %S successfully opened.\n", AdapterString);
+ }
+#endif
+ } else {
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint2 ("Adapter open %S failed, status: %s.\n",
+ AdapterString,
+ NbfGetNdisStatus (NdisStatus));
+ }
+#endif
+ NbfWriteGeneralErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_ADAPTER_NOT_FOUND,
+ 807,
+ NdisStatus,
+ AdapterString->Buffer,
+ 0,
+ NULL);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Get the information we need about the adapter, based on
+ // the media type.
+ //
+
+ MacInitializeMacInfo(
+ NbfSupportedMedia[SelectedMedium],
+ (BOOLEAN)(NbfConfig->UseDixOverEthernet != 0),
+ &DeviceContext->MacInfo);
+ DeviceContext->MacInfo.QueryWithoutSourceRouting =
+ NbfConfig->QueryWithoutSourceRouting ? TRUE : FALSE;
+ DeviceContext->MacInfo.AllRoutesNameRecognized =
+ NbfConfig->AllRoutesNameRecognized ? TRUE : FALSE;
+
+
+ //
+ // Set the multicast/functional addresses first so we avoid windows where we
+ // receive only part of the addresses.
+ //
+
+ MacSetNetBIOSMulticast (
+ DeviceContext->MacInfo.MediumType,
+ DeviceContext->NetBIOSAddress.Address);
+
+
+ switch (DeviceContext->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+ case NdisMediumDix:
+
+ //
+ // Fill in the data for our multicast list.
+ //
+
+ RtlCopyMemory(NbfDataBuffer, DeviceContext->NetBIOSAddress.Address, 6);
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ NbfRequest.RequestType = NdisRequestSetInformation;
+ NbfRequest.DATA.SET_INFORMATION.Oid = OID_802_3_MULTICAST_LIST;
+ NbfRequest.DATA.SET_INFORMATION.InformationBuffer = &NbfDataBuffer;
+ NbfRequest.DATA.SET_INFORMATION.InformationBufferLength = 6;
+
+ break;
+
+ case NdisMedium802_5:
+
+ //
+ // For token-ring, we pass the last four bytes of the
+ // Netbios functional address.
+ //
+
+ //
+ // Fill in the OVB for our functional address.
+ //
+
+ RtlCopyMemory(NbfDataBuffer, ((PUCHAR)(DeviceContext->NetBIOSAddress.Address)) + 2, 4);
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ NbfRequest.RequestType = NdisRequestSetInformation;
+ NbfRequest.DATA.SET_INFORMATION.Oid = OID_802_5_CURRENT_FUNCTIONAL;
+ NbfRequest.DATA.SET_INFORMATION.InformationBuffer = &NbfDataBuffer;
+ NbfRequest.DATA.SET_INFORMATION.InformationBufferLength = 4;
+
+ break;
+
+ case NdisMediumFddi:
+
+ //
+ // Fill in the data for our multicast list.
+ //
+
+ RtlCopyMemory(NbfDataBuffer, DeviceContext->NetBIOSAddress.Address, 6);
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ NbfRequest.RequestType = NdisRequestSetInformation;
+ NbfRequest.DATA.SET_INFORMATION.Oid = OID_FDDI_LONG_MULTICAST_LIST;
+ NbfRequest.DATA.SET_INFORMATION.InformationBuffer = &NbfDataBuffer;
+ NbfRequest.DATA.SET_INFORMATION.InformationBufferLength = 6;
+
+ break;
+
+ }
+
+ NdisStatus = NbfSubmitNdisRequest (DeviceContext, &NbfRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+
+ switch (DeviceContext->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+ case NdisMediumDix:
+
+ if (DeviceContext->MacInfo.MediumAsync) {
+ NbfOid = OID_WAN_CURRENT_ADDRESS;
+ } else {
+ NbfOid = OID_802_3_CURRENT_ADDRESS;
+ }
+ break;
+
+ case NdisMedium802_5:
+
+ NbfOid = OID_802_5_CURRENT_ADDRESS;
+ break;
+
+ case NdisMediumFddi:
+
+ NbfOid = OID_FDDI_LONG_CURRENT_ADDR;
+ break;
+
+ default:
+
+ NdisStatus = NDIS_STATUS_FAILURE;
+ break;
+
+ }
+ NbfRequest.RequestType = NdisRequestQueryInformation;
+ NbfRequest.DATA.QUERY_INFORMATION.Oid = NbfOid;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBuffer = DeviceContext->LocalAddress.Address;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 6;
+
+ NdisStatus = NbfSubmitNdisRequest (DeviceContext, &NbfRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Set up the reserved Netbios address.
+ //
+
+ RtlZeroMemory(DeviceContext->ReservedNetBIOSAddress, 10);
+ RtlCopyMemory(&DeviceContext->ReservedNetBIOSAddress[10], DeviceContext->LocalAddress.Address, 6);
+
+
+
+ //
+ // Now query the maximum packet sizes.
+ //
+
+ NbfRequest.RequestType = NdisRequestQueryInformation;
+ NbfRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_FRAME_SIZE;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(DeviceContext->MaxReceivePacketSize);
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = NbfSubmitNdisRequest (DeviceContext, &NbfRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ NbfRequest.RequestType = NdisRequestQueryInformation;
+ NbfRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(DeviceContext->MaxSendPacketSize);
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = NbfSubmitNdisRequest (DeviceContext, &NbfRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ DeviceContext->CurSendPacketSize = DeviceContext->MaxSendPacketSize;
+
+
+ //
+ // Now set the minimum lookahead size.
+ //
+
+ NbfRequest.RequestType = NdisRequestSetInformation;
+ NbfRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_CURRENT_LOOKAHEAD;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBuffer = &MinimumLookahead;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = NbfSubmitNdisRequest (DeviceContext, &NbfRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now query the link speed for non-wan media
+ //
+
+ if (!DeviceContext->MacInfo.MediumAsync) {
+
+ NbfRequest.RequestType = NdisRequestQueryInformation;
+ NbfRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_LINK_SPEED;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(DeviceContext->MediumSpeed);
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = NbfSubmitNdisRequest (DeviceContext, &NbfRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ DeviceContext->MediumSpeedAccurate = TRUE;
+
+ DeviceContext->MinimumT1Timeout = 8; // == 400 ms
+
+ } else {
+
+ //
+ // On an wan media, this isn't valid until we get an
+ // WAN_LINE_UP indication. Set the timeouts to
+ // low values for now.
+ //
+
+ DeviceContext->DefaultT1Timeout = 8;
+ DeviceContext->MinimumT1Timeout = 8;
+
+ DeviceContext->MediumSpeedAccurate = FALSE;
+
+
+ //
+ // Back off our connectionless timeouts to 2 seconds.
+ //
+
+ DeviceContext->NameQueryTimeout = 2 * SECONDS;
+ DeviceContext->AddNameQueryTimeout = 2 * SECONDS;
+ DeviceContext->GeneralTimeout = 2 * SECONDS;
+
+ //
+ // Use the WAN parameter for name query retries.
+ //
+
+ DeviceContext->NameQueryRetries = NbfConfig->WanNameQueryRetries;
+
+ //
+ // Use this until we know better.
+ //
+
+ DeviceContext->RecommendedSendWindow = 1;
+
+ }
+
+ //
+ // On media that use source routing, we double our name query
+ // retry count if we are configured to try both ways (with and
+ // without source routing).
+ //
+
+ if ((DeviceContext->MacInfo.QueryWithoutSourceRouting) &&
+ (DeviceContext->MacInfo.SourceRouting)) {
+ DeviceContext->NameQueryRetries *= 2;
+ }
+
+
+ //
+ // For wan, specify our protocol ID and header format.
+ // We don't query the medium subtype because we don't
+ // case (since we require ethernet emulation).
+ //
+
+ if (DeviceContext->MacInfo.MediumAsync) {
+
+ NbfRequest.RequestType = NdisRequestSetInformation;
+ NbfRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_PROTOCOL_TYPE;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBuffer = WanProtocolId;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 6;
+
+ NdisStatus = NbfSubmitNdisRequest (DeviceContext, &NbfRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ NbfRequest.RequestType = NdisRequestSetInformation;
+ NbfRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_HEADER_FORMAT;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBuffer = &WanHeaderFormat;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = NbfSubmitNdisRequest (DeviceContext, &NbfRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+
+ //
+ // Now query the MAC's optional characteristics.
+ //
+
+ NbfRequest.RequestType = NdisRequestQueryInformation;
+ NbfRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAC_OPTIONS;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBuffer = &MacOptions;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = NbfSubmitNdisRequest (DeviceContext, &NbfRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+#if 1
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+#else
+ MacOptions = 0;
+#endif
+ }
+
+ DeviceContext->MacInfo.CopyLookahead =
+ (BOOLEAN)((MacOptions & NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA) != 0);
+ DeviceContext->MacInfo.ReceiveSerialized =
+ (BOOLEAN)((MacOptions & NDIS_MAC_OPTION_RECEIVE_SERIALIZED) != 0);
+ DeviceContext->MacInfo.TransferSynchronous =
+ (BOOLEAN)((MacOptions & NDIS_MAC_OPTION_TRANSFERS_NOT_PEND) != 0);
+ DeviceContext->MacInfo.SingleReceive =
+ (BOOLEAN)(DeviceContext->MacInfo.ReceiveSerialized && DeviceContext->MacInfo.TransferSynchronous);
+
+
+#if 0
+ //
+ // Now set our options if needed.
+ //
+ // Don't allow early indications because we can't determine
+ // if the CRC has been checked yet.
+ //
+
+ if ((DeviceContext->MacInfo.MediumType == NdisMedium802_3) ||
+ (DeviceContext->MacInfo.MediumType == NdisMediumDix)) {
+
+ ULONG ProtocolOptions = NDIS_PROT_OPTION_ESTIMATED_LENGTH;
+
+ NbfRequest.RequestType = NdisRequestSetInformation;
+ NbfRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_PROTOCOL_OPTIONS;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBuffer = &ProtocolOptions;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = NbfSubmitNdisRequest (DeviceContext, &NbfRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ }
+#endif
+
+
+ //
+ // Calculate the NDIS-related stuff.
+ //
+
+ SendPacketReservedLength = sizeof (SEND_PACKET_TAG);
+ ReceivePacketReservedLen = sizeof (RECEIVE_PACKET_TAG);
+
+
+ //
+ // The send packet pool is used for UI frames and regular packets.
+ //
+
+ SendPacketPoolSize = NbfConfig->SendPacketPoolSize;
+
+ //
+ // The receive packet pool is used in transfer data.
+ //
+ // For a MAC that will only have one receive active, we
+ // don't need multiple receive packets. Allow an extra
+ // one for loopback.
+ //
+
+ if (DeviceContext->MacInfo.SingleReceive) {
+ ReceivePacketPoolSize = 2;
+ } else {
+ ReceivePacketPoolSize = NbfConfig->ReceivePacketPoolSize;
+ }
+
+
+ // Allocate Packet pool descriptors for dynamic packet allocation.
+
+ DeviceContext->SendPacketPoolDesc = ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(NBF_POOL_LIST_DESC),
+ ' FBN');
+
+ if (DeviceContext->SendPacketPoolDesc == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(DeviceContext->SendPacketPoolDesc,
+ sizeof(NBF_POOL_LIST_DESC));
+
+ DeviceContext->SendPacketPoolDesc->NumElements =
+ DeviceContext->SendPacketPoolDesc->TotalElements = (USHORT)SendPacketPoolSize;
+
+ NdisAllocatePacketPool (
+ &NdisStatus,
+ &DeviceContext->SendPacketPoolDesc->PoolHandle,
+ SendPacketPoolSize,
+ SendPacketReservedLength);
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint0 ("NdisInitializePacketPool successful.\n");
+ }
+
+ } else {
+#if DBG
+ NbfPrint1 ("NbfInitialize: NdisInitializePacketPool failed, reason: %s.\n",
+ NbfGetNdisStatus (NdisStatus));
+#endif
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 109,
+ SendPacketPoolSize,
+ 0);
+ ExFreePool (DeviceContext->SendPacketPoolDesc);
+ DeviceContext->SendPacketPoolDesc = NULL;
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ DeviceContext->SendPacketPoolSize = SendPacketPoolSize;
+
+ DeviceContext->MemoryUsage +=
+ (SendPacketPoolSize *
+ (sizeof(NDIS_PACKET) + SendPacketReservedLength));
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ DbgPrint ("send pool %d hdr %d, %ld\n",
+ SendPacketPoolSize,
+ SendPacketReservedLength,
+ DeviceContext->MemoryUsage);
+ }
+#endif
+
+
+ // Allocate Packet pool descriptors for dynamic packet allocation.
+
+ DeviceContext->ReceivePacketPoolDesc = ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(NBF_POOL_LIST_DESC),
+ ' FBN');
+
+ if (DeviceContext->ReceivePacketPoolDesc == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(DeviceContext->ReceivePacketPoolDesc,
+ sizeof(NBF_POOL_LIST_DESC));
+
+ DeviceContext->ReceivePacketPoolDesc->NumElements =
+ DeviceContext->ReceivePacketPoolDesc->TotalElements = (USHORT)ReceivePacketPoolSize;
+
+ NdisAllocatePacketPool(
+ &NdisStatus,
+ &DeviceContext->ReceivePacketPoolDesc->PoolHandle,
+ ReceivePacketPoolSize,
+ ReceivePacketReservedLen);
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint1 ("NdisInitializePacketPool successful, Pool: %lx\n",
+ DeviceContext->ReceivePacketPoolDesc->PoolHandle);
+ }
+ } else {
+#if DBG
+ NbfPrint1 ("NbfInitialize: NdisInitializePacketPool failed, reason: %s.\n",
+ NbfGetNdisStatus (NdisStatus));
+#endif
+ ExFreePool (DeviceContext->SendPacketPoolDesc);
+ ExFreePool(DeviceContext->ReceivePacketPoolDesc);
+ DeviceContext->SendPacketPoolDesc = NULL;
+ DeviceContext->ReceivePacketPoolDesc = NULL;
+ NbfCloseNdis (DeviceContext);
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 209,
+ ReceivePacketPoolSize,
+ 0);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ DeviceContext->ReceivePacketPoolSize = ReceivePacketPoolSize;
+
+ DeviceContext->MemoryUsage +=
+ (ReceivePacketPoolSize *
+ (sizeof(NDIS_PACKET) + ReceivePacketReservedLen));
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ DbgPrint ("receive pool %d hdr %d, %ld\n",
+ ReceivePacketPoolSize,
+ ReceivePacketReservedLen,
+ DeviceContext->MemoryUsage);
+ }
+#endif
+
+
+ //
+ // Allocate the buffer pool; as an estimate, allocate
+ // one per send or receive packet.
+ //
+
+ NdisAllocateBufferPool (
+ &NdisStatus,
+ &DeviceContext->NdisBufferPool,
+ SendPacketPoolSize + ReceivePacketPoolSize);
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint0 ("NdisAllocateBufferPool successful.\n");
+ }
+
+ } else {
+#if DBG
+ NbfPrint1 ("NbfInitialize: NdisAllocateBufferPool failed, reason: %s.\n",
+ NbfGetNdisStatus (NdisStatus));
+#endif
+ ExFreePool(DeviceContext->SendPacketPoolDesc);
+ ExFreePool(DeviceContext->ReceivePacketPoolDesc);
+ DeviceContext->SendPacketPoolDesc = NULL;
+ DeviceContext->ReceivePacketPoolDesc = NULL;
+ DeviceContext->NdisBufferPool = NULL;
+ NbfCloseNdis (DeviceContext);
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 309,
+ SendPacketPoolSize + ReceivePacketPoolSize,
+ 0);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now that everything is set up, we enable the filter
+ // for packet reception.
+ //
+
+ //
+ // Fill in the OVB for packet filter.
+ //
+
+ switch (DeviceContext->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+ case NdisMediumDix:
+ case NdisMediumFddi:
+
+ RtlStoreUlong((PULONG)NbfDataBuffer,
+ (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_MULTICAST));
+ break;
+
+ case NdisMedium802_5:
+
+ RtlStoreUlong((PULONG)NbfDataBuffer,
+ (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_FUNCTIONAL));
+ break;
+
+ default:
+
+ NdisStatus = NDIS_STATUS_FAILURE;
+ break;
+
+ }
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ NbfRequest.RequestType = NdisRequestSetInformation;
+ NbfRequest.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ NbfRequest.DATA.SET_INFORMATION.InformationBuffer = &NbfDataBuffer;
+ NbfRequest.DATA.SET_INFORMATION.InformationBufferLength = sizeof(ULONG);
+
+ NbfSubmitNdisRequest (DeviceContext, &NbfRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ return STATUS_SUCCESS;
+
+} /* NbfInitializeNdis */
+
+
+VOID
+NbfCloseNdis (
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unbinds the transport from the NDIS interface and does
+ any other work required to undo what was done in NbfInitializeNdis.
+ It is written so that it can be called from within NbfInitializeNdis
+ if it fails partway through.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NDIS_STATUS ndisStatus;
+
+ //
+ // Close the NDIS binding.
+ //
+
+ if (DeviceContext->NdisBindingHandle != (NDIS_HANDLE)NULL) {
+
+ //
+ // This event is used in case any of the NDIS requests
+ // pend; we wait until it is set by the completion
+ // routine, which also sets NdisRequestStatus.
+ //
+
+ KeInitializeEvent(
+ &DeviceContext->NdisRequestEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ NdisCloseAdapter(
+ &ndisStatus,
+ DeviceContext->NdisBindingHandle);
+
+ if (ndisStatus == NDIS_STATUS_PENDING) {
+
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint0 ("Adapter close pended.\n");
+ }
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &DeviceContext->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ ndisStatus = DeviceContext->NdisRequestStatus;
+
+ KeResetEvent(
+ &DeviceContext->NdisRequestEvent
+ );
+
+ }
+
+ //
+ // We ignore ndisStatus.
+ //
+
+ }
+
+ if (DeviceContext->SendPacketPoolDesc != NULL &&
+ DeviceContext->SendPacketPoolDesc->PoolHandle != NULL) {
+ NdisFreePacketPool (DeviceContext->SendPacketPoolDesc->PoolHandle);
+ ExFreePool(DeviceContext->SendPacketPoolDesc);
+ DeviceContext->SendPacketPoolDesc = NULL;
+ }
+
+ if (DeviceContext->ReceivePacketPoolDesc != NULL &&
+ DeviceContext->ReceivePacketPoolDesc->PoolHandle != NULL) {
+ NdisFreePacketPool (DeviceContext->ReceivePacketPoolDesc->PoolHandle);
+ ExFreePool(DeviceContext->ReceivePacketPoolDesc);
+ DeviceContext->ReceivePacketPoolDesc = NULL;
+ }
+
+ if (DeviceContext->NdisBufferPool != NULL) {
+ NdisFreeBufferPool (DeviceContext->NdisBufferPool);
+ }
+
+} /* NbfCloseNdis */
+
+
+VOID
+NbfOpenAdapterComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN NDIS_STATUS OpenErrorStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that an open adapter
+ is complete. Since we only ever have one outstanding, and then only
+ during initialization, all we do is record the status and set
+ the event to signalled to unblock the initialization thread.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+ OpenErrorStatus - More status information.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)BindingContext;
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint1 ("Nbfdrvr: NbfOpenAdapterCompleteNDIS Status: %s\n",
+ NbfGetNdisStatus (NdisStatus));
+ }
+#endif
+
+ ENTER_NBF;
+
+ DeviceContext->NdisRequestStatus = NdisStatus;
+ KeSetEvent(
+ &DeviceContext->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+ LEAVE_NBF;
+ return;
+}
+
+VOID
+NbfCloseAdapterComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a close adapter
+ is complete. Currently we don't close adapters, so this is not
+ a problem.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)BindingContext;
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint1 ("Nbfdrvr: NbfCloseAdapterCompleteNDIS Status: %s\n",
+ NbfGetNdisStatus (NdisStatus));
+ }
+#endif
+
+ ENTER_NBF;
+
+ DeviceContext->NdisRequestStatus = NdisStatus;
+ KeSetEvent(
+ &DeviceContext->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+ LEAVE_NBF;
+ return;
+}
+
+VOID
+NbfResetComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a reset adapter
+ is complete. Currently we don't reset adapters, so this is not
+ a problem.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(BindingContext);
+ UNREFERENCED_PARAMETER(NdisStatus);
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint1 ("Nbfdrvr: NbfResetCompleteNDIS Status: %s\n",
+ NbfGetNdisStatus (NdisStatus));
+ }
+#endif
+
+ return;
+}
+
+VOID
+NbfRequestComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a request is complete.
+ Since we only ever have one request outstanding, and then only
+ during initialization, all we do is record the status and set
+ the event to signalled to unblock the initialization thread.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisRequest - The object describing the request.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)BindingContext;
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint2 ("Nbfdrvr: NbfRequestComplete request: %i, NDIS Status: %s\n",
+ NdisRequest->RequestType,NbfGetNdisStatus (NdisStatus));
+ }
+#endif
+
+ ENTER_NBF;
+
+ DeviceContext->NdisRequestStatus = NdisStatus;
+ KeSetEvent(
+ &DeviceContext->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+ LEAVE_NBF;
+ return;
+}
+
+VOID
+NbfStatusIndication (
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ )
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ PNDIS_WAN_LINE_UP LineUp;
+ KIRQL oldirql;
+ PTP_LINK Link;
+
+ DeviceContext = (PDEVICE_CONTEXT)NdisBindingContext;
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ switch (NdisStatus) {
+
+ case NDIS_STATUS_WAN_LINE_UP:
+
+ //
+ // A wan line is connected.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ //
+ // If this happens before we are ready, then make
+ // a note of it, otherwise make the device ready.
+ //
+
+ DeviceContext->MediumSpeedAccurate = TRUE;
+
+ LineUp = (PNDIS_WAN_LINE_UP)StatusBuffer;
+
+ //
+ // See if this is a new lineup for this protocol type
+ //
+ if (LineUp->ProtocolType == 0x80D5) {
+ NDIS_HANDLE TransportHandle;
+
+ *((ULONG UNALIGNED *)(&TransportHandle)) =
+ *((ULONG UNALIGNED *)(&LineUp->LocalAddress[2]));
+
+ //
+ // See if this is a new lineup
+ //
+ if (TransportHandle == NULL) {
+ *((ULONG UNALIGNED *)(&LineUp->LocalAddress[2])) = *((ULONG UNALIGNED *)(&DeviceContext));
+// ETH_COPY_NETWORK_ADDRESS(DeviceContext->LocalAddress.Address, LineUp->LocalAddress);
+// ETH_COPY_NETWORK_ADDRESS(&DeviceContext->ReservedNetBIOSAddress[10], DeviceContext->LocalAddress.Address);
+ }
+
+ //
+ // Calculate minimum link timeouts based on the speed,
+ // which is passed in StatusBuffer.
+ //
+ // The formula is (max_frame_size * 2) / speed + 0.4 sec.
+ // This expands to
+ //
+ // MFS (bytes) * 2 8 bits
+ // ------------------- x ------ == timeout (sec),
+ // speed (100 bits/sec) byte
+ //
+ // which is (MFS * 16 / 100) / speed. We then convert it into
+ // the 50 ms units that NBF uses and add 8 (which is
+ // 0.4 seconds in 50 ms units).
+ //
+ // As a default timeout we use the min + 0.2 seconds
+ // unless the configured default is more.
+ //
+
+ if (LineUp->LinkSpeed > 0) {
+ DeviceContext->MediumSpeed = LineUp->LinkSpeed;
+ }
+
+ if (LineUp->MaximumTotalSize > 0) {
+#if DBG
+ if (LineUp->MaximumTotalSize > DeviceContext->MaxSendPacketSize) {
+ DbgPrint ("Nbf: Bad LINE_UP size, %d (> %d)\n",
+ LineUp->MaximumTotalSize, DeviceContext->MaxSendPacketSize);
+ }
+ if (LineUp->MaximumTotalSize < 128) {
+ DbgPrint ("NBF: Bad LINE_UP size, %d (< 128)\n",
+ LineUp->MaximumTotalSize);
+ }
+#endif
+ DeviceContext->CurSendPacketSize = LineUp->MaximumTotalSize;
+ }
+
+ if (LineUp->SendWindow == 0) {
+ DeviceContext->RecommendedSendWindow = 3;
+ } else {
+ DeviceContext->RecommendedSendWindow = LineUp->SendWindow + 1;
+ }
+
+ DeviceContext->MinimumT1Timeout =
+ ((((DeviceContext->CurSendPacketSize * 16) / 100) / DeviceContext->MediumSpeed) *
+ ((1 * SECONDS) / (50 * MILLISECONDS))) + 8;
+
+ if (DeviceContext->DefaultT1Timeout < DeviceContext->MinimumT1Timeout) {
+ DeviceContext->DefaultT1Timeout = DeviceContext->MinimumT1Timeout + 4;
+ }
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ break;
+
+ case NDIS_STATUS_WAN_LINE_DOWN:
+
+ //
+ // An wan line is disconnected.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ DeviceContext->MediumSpeedAccurate = FALSE;
+
+ //
+ // Set the timeouts to small values (0.4 seconds)
+ //
+
+ DeviceContext->DefaultT1Timeout = 8;
+ DeviceContext->MinimumT1Timeout = 8;
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+
+ //
+ // Stop the link on this device context (there
+ // will only be one).
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ if (DeviceContext->LinkTreeElements > 0) {
+
+ Link = (PTP_LINK)DeviceContext->LinkTreeRoot;
+ if ((Link->DeferredFlags & LINK_FLAGS_DEFERRED_DELETE) == 0) {
+
+ NbfReferenceLink ("Wan line down", Link, LREF_TREE);
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ //
+ // Put the link in ADM to shut it down.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ if (Link->State != LINK_STATE_ADM) {
+ Link->State = LINK_STATE_ADM;
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ NbfDereferenceLinkSpecial ("Wan line down", Link, LREF_NOT_ADM);
+ } else {
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ }
+
+ //
+ // Now stop it to destroy all connections on it.
+ //
+
+ NbfStopLink (Link);
+
+ NbfDereferenceLink ("Wan line down", Link, LREF_TREE);
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ }
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ }
+
+ break;
+
+ case NDIS_STATUS_WAN_FRAGMENT:
+
+ //
+ // A fragment has been received on the wan line.
+ // Send a reject back to him.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ if (DeviceContext->LinkTreeElements > 0) {
+
+ Link = (PTP_LINK)DeviceContext->LinkTreeRoot;
+ NbfReferenceLink ("Async line down", Link, LREF_TREE);
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ NbfSendRej (Link, FALSE, FALSE); // release lock
+ NbfDereferenceLink ("Async line down", Link, LREF_TREE);
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ }
+
+ break;
+
+ case NDIS_STATUS_CLOSING:
+
+ //
+ // The adapter is shutting down. We queue a worker
+ // thread to handle this.
+ //
+
+ ExInitializeWorkItem(
+ &DeviceContext->StatusClosingQueueItem,
+ NbfProcessStatusClosing,
+ (PVOID)DeviceContext);
+ ExQueueWorkItem(&DeviceContext->StatusClosingQueueItem, DelayedWorkQueue);
+
+ break;
+
+ default:
+ break;
+
+ }
+
+ KeLowerIrql (oldirql);
+
+}
+
+
+VOID
+NbfProcessStatusClosing(
+ IN PVOID Parameter
+ )
+
+/*++
+
+Routine Description:
+
+ This is the thread routine which restarts packetizing
+ that has been delayed on WAN to allow RRs to come in.
+ This is very similar to PacketizeConnections.
+
+Arguments:
+
+ Parameter - A pointer to the device context.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ PLIST_ENTRY p;
+#if 0
+ PTP_ADDRESS Address;
+#endif
+ PTP_LINK Link;
+ PTP_REQUEST Request;
+ NDIS_STATUS ndisStatus;
+ KIRQL oldirql;
+
+ DeviceContext = (PDEVICE_CONTEXT)Parameter;
+
+ //
+ // Prevent new activity on the connection.
+ //
+
+ DeviceContext->State = DEVICECONTEXT_STATE_DOWN;
+
+
+#if 0
+ //
+ // Stop all the addresses.
+ //
+
+ while ((p = ExInterlockedRemoveHeadList(
+ &DeviceContext->AddressDatabase,
+ &DeviceContext->SpinLock)) != NULL) {
+
+ Address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+ InitializeListHead(p);
+
+ NbfStopAddress (Address);
+
+ }
+#endif
+
+ //
+ // To speed things along, stop all the links too.
+ //
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ DeviceContext->LastLink = NULL;
+
+ while (DeviceContext->LinkTreeRoot != NULL) {
+
+ Link = (PTP_LINK)DeviceContext->LinkTreeRoot;
+ DeviceContext->LinkTreeRoot = RtlDelete ((PRTL_SPLAY_LINKS)Link);
+ DeviceContext->LinkTreeElements--;
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+ if (Link->OnShortList) {
+ RemoveEntryList (&Link->ShortList);
+ }
+ if (Link->OnLongList) {
+ RemoveEntryList (&Link->LongList);
+ }
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ if (Link->State != LINK_STATE_ADM) {
+ Link->State = LINK_STATE_ADM;
+ NbfSendDm (Link, FALSE); // send DM/0, release lock
+ // moving to ADM, remove reference
+ NbfDereferenceLinkSpecial("Expire T1 in CONNECTING mode", Link, LREF_NOT_ADM);
+ } else {
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ }
+ NbfStopLink (Link);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ KeLowerIrql (oldirql);
+
+
+ //
+ // Shutdown the control channel.
+ //
+
+ while ((p = ExInterlockedRemoveHeadList(
+ &DeviceContext->QueryIndicationQueue,
+ &DeviceContext->SpinLock)) != NULL) {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ NbfCompleteRequest (Request, STATUS_INVALID_DEVICE_STATE, 0);
+ }
+
+ while ((p = ExInterlockedRemoveHeadList(
+ &DeviceContext->DatagramIndicationQueue,
+ &DeviceContext->SpinLock)) != NULL) {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ NbfCompleteRequest (Request, STATUS_INVALID_DEVICE_STATE, 0);
+ }
+
+ while ((p = ExInterlockedRemoveHeadList(
+ &DeviceContext->StatusQueryQueue,
+ &DeviceContext->SpinLock)) != NULL) {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ NbfCompleteRequest (Request, STATUS_INVALID_DEVICE_STATE, 0);
+ }
+
+ while ((p = ExInterlockedRemoveHeadList(
+ &DeviceContext->FindNameQueue,
+ &DeviceContext->SpinLock)) != NULL) {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ NbfCompleteRequest (Request, STATUS_INVALID_DEVICE_STATE, 0);
+ }
+
+
+ //
+ // Close the NDIS binding.
+ //
+
+ KeInitializeEvent(
+ &DeviceContext->NdisRequestEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ NdisCloseAdapter(
+ &ndisStatus,
+ DeviceContext->NdisBindingHandle);
+
+ if (ndisStatus == NDIS_STATUS_PENDING) {
+
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint0 ("Adapter close pended.\n");
+ }
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &DeviceContext->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ ndisStatus = DeviceContext->NdisRequestStatus;
+
+ KeResetEvent(
+ &DeviceContext->NdisRequestEvent
+ );
+
+ }
+
+ DeviceContext->NdisBindingHandle = NULL;
+
+ //
+ // We ignore ndisStatus.
+ //
+
+#if 0
+ //
+ // Remove all the storage associated with the device.
+ //
+
+ NbfFreeResources (DeviceContext);
+
+ NdisFreePacketPool (DeviceContext->SendPacketPoolHandle);
+ NdisFreePacketPool (DeviceContext->ReceivePacketPoolHandle);
+ NdisFreeBufferPool (DeviceContext->NdisBufferPoolHandle);
+#endif
+
+ //
+ // And remove the creation reference from the device
+ // context.
+ //
+
+ NbfDereferenceDeviceContext ("Unload", DeviceContext, DCREF_CREATION);
+
+} /* NbfProcessStatusClosing */
+
+
+VOID
+NbfStatusComplete (
+ IN NDIS_HANDLE NdisBindingContext
+ )
+{
+ UNREFERENCED_PARAMETER (NdisBindingContext);
+
+}
+
+#if DBG
+
+PUCHAR
+NbfGetNdisStatus(
+ NDIS_STATUS GeneralStatus
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the string describing the NDIS error
+ denoted by GeneralStatus.
+
+Arguments:
+
+ GeneralStatus - the status you wish to make readable.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ static NDIS_STATUS Status[] = {
+ NDIS_STATUS_SUCCESS,
+ NDIS_STATUS_PENDING,
+
+ NDIS_STATUS_ADAPTER_NOT_FOUND,
+ NDIS_STATUS_ADAPTER_NOT_OPEN,
+ NDIS_STATUS_ADAPTER_NOT_READY,
+ NDIS_STATUS_ADAPTER_REMOVED,
+ NDIS_STATUS_BAD_CHARACTERISTICS,
+ NDIS_STATUS_BAD_VERSION,
+ NDIS_STATUS_CLOSING,
+ NDIS_STATUS_DEVICE_FAILED,
+ NDIS_STATUS_FAILURE,
+ NDIS_STATUS_INVALID_DATA,
+ NDIS_STATUS_INVALID_LENGTH,
+ NDIS_STATUS_INVALID_OID,
+ NDIS_STATUS_INVALID_PACKET,
+ NDIS_STATUS_MULTICAST_FULL,
+ NDIS_STATUS_NOT_INDICATING,
+ NDIS_STATUS_NOT_RECOGNIZED,
+ NDIS_STATUS_NOT_RESETTABLE,
+ NDIS_STATUS_NOT_SUPPORTED,
+ NDIS_STATUS_OPEN_FAILED,
+ NDIS_STATUS_OPEN_LIST_FULL,
+ NDIS_STATUS_REQUEST_ABORTED,
+ NDIS_STATUS_RESET_IN_PROGRESS,
+ NDIS_STATUS_RESOURCES,
+ NDIS_STATUS_UNSUPPORTED_MEDIA
+ };
+ static PUCHAR String[] = {
+ "SUCCESS",
+ "PENDING",
+
+ "ADAPTER_NOT_FOUND",
+ "ADAPTER_NOT_OPEN",
+ "ADAPTER_NOT_READY",
+ "ADAPTER_REMOVED",
+ "BAD_CHARACTERISTICS",
+ "BAD_VERSION",
+ "CLOSING",
+ "DEVICE_FAILED",
+ "FAILURE",
+ "INVALID_DATA",
+ "INVALID_LENGTH",
+ "INVALID_OID",
+ "INVALID_PACKET",
+ "MULTICAST_FULL",
+ "NOT_INDICATING",
+ "NOT_RECOGNIZED",
+ "NOT_RESETTABLE",
+ "NOT_SUPPORTED",
+ "OPEN_FAILED",
+ "OPEN_LIST_FULL",
+ "REQUEST_ABORTED",
+ "RESET_IN_PROGRESS",
+ "RESOURCES",
+ "UNSUPPORTED_MEDIA"
+ };
+
+ static UCHAR BadStatus[] = "UNDEFINED";
+#define StatusCount (sizeof(Status)/sizeof(NDIS_STATUS))
+ INT i;
+
+ for (i=0; i<StatusCount; i++)
+ if (GeneralStatus == Status[i])
+ return String[i];
+ return BadStatus;
+#undef StatusCount
+}
+#endif
diff --git a/private/ntos/tdi/nbf/nbfpnp.c b/private/ntos/tdi/nbf/nbfpnp.c
new file mode 100644
index 000000000..844abf8ad
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbfpnp.c
@@ -0,0 +1,210 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ nbfpnp.c
+
+Abstract:
+
+ This module contains code which allocates and initializes all data
+ structures needed to activate a plug and play binding. It also informs
+ tdi (and thus nbf clients) of new devices and protocol addresses.
+
+Author:
+
+ Jim McNelis (jimmcn) 1-Jan-1996
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef _PNP_POWER
+PCONFIG_DATA NbfConfig = NULL;
+SuccessfulOpens = 0;
+
+#ifdef RASAUTODIAL
+VOID
+NbfAcdBind();
+
+VOID
+NbfAcdUnbind();
+#endif // RASAUTODIAL
+
+VOID
+NbfProtocolBindAdapter(
+ OUT PNDIS_STATUS NdisStatus,
+ IN NDIS_HANDLE BindContext,
+ IN PNDIS_STRING DeviceName,
+ IN PVOID SystemSpecific1,
+ IN PVOID SystemSpecific2
+ )
+/*++
+
+Routine Description:
+
+ This routine activates a transport binding and exposes the new device
+ and associated addresses to transport clients. This is done by reading
+ the registry, and performing any one time initialization of the transport
+ and then natching the device to bind to with the linkage information from
+ the registry. If we have a match for that device the bind will be
+ performed.
+
+Arguments:
+
+ NdisStatus - The status of the bind.
+
+ BindContext - A context used for NdisCompleteBindAdapter() if
+ STATUS_PENDING is returned.
+
+ DeviceName - The name of the device that we are binding with.
+
+ SystemSpecific1 - Unused (a pointer to an NDIS_STRING to use with
+ NdisOpenProtocolConfiguration. This is not used by nbf
+ since there is no adapter specific information when
+ configuring the protocol via the registry.
+
+ SystemSpecific2 - Currently unused.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ ULONG j;
+ NTSTATUS status;
+
+ if (NbfConfig == NULL) {
+ //
+ // This allocates the CONFIG_DATA structure and returns
+ // it in NbfConfig.
+ //
+
+
+
+ status = NbfConfigureTransport(&NbfRegistryPath, &NbfConfig);
+
+ if (!NT_SUCCESS (status)) {
+ PANIC (" Failed to initialize transport, Nbf binding failed.\n");
+ *NdisStatus = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+#if DBG
+
+ //
+ // Allocate the debugging tables.
+ //
+
+ NbfConnectionTable = (PVOID *)ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(PVOID) *
+ (NbfConfig->InitConnections + 2 +
+ NbfConfig->InitRequests + 2 +
+ NbfConfig->InitUIFrames + 2 +
+ NbfConfig->InitPackets + 2 +
+ NbfConfig->InitLinks + 2 +
+ NbfConfig->InitAddressFiles + 2 +
+ NbfConfig->InitAddresses + 2),
+ ' FBN');
+
+ ASSERT (NbfConnectionTable);
+
+#if 0
+ if (NbfConnectionTable == NULL) {
+ *NdisStatus = NDIS_STATUS_RESOURCES;
+ return;
+ }
+#endif
+
+
+ NbfRequestTable = NbfConnectionTable + (NbfConfig->InitConnections + 2);
+ NbfUiFrameTable = NbfRequestTable + (NbfConfig->InitRequests + 2);
+ NbfSendPacketTable = NbfUiFrameTable + (NbfConfig->InitUIFrames + 2);
+ NbfLinkTable = NbfSendPacketTable + (NbfConfig->InitPackets + 2);
+ NbfAddressFileTable = NbfLinkTable + (NbfConfig->InitLinks + 2);
+ NbfAddressTable = NbfAddressFileTable +
+ (NbfConfig->InitAddressFiles + 2);
+#endif
+ }
+
+ for (j=0;j<NbfConfig->NumAdapters;j++ ) {
+
+ //
+ // Loop through all the adapters that are in the configuration
+ // information structure until we find the one that ndis is calling
+ // Protocol bind adapter for.
+ //
+ if (NdisEqualString(DeviceName, &NbfConfig->Names[j], TRUE)) {
+ break;
+ }
+
+ }
+
+ SuccessfulOpens += NbfInitializeOneDeviceContext(NdisStatus,
+ NbfDriverObject,
+ NbfConfig, j
+ );
+
+ if (SuccessfulOpens == 1 && *NdisStatus == NDIS_STATUS_SUCCESS) {
+
+#if DBG
+ DbgPrint("Calling NbfAcdBind()\n");
+#endif
+ //
+ // If this is the first successful open.
+ //
+#ifdef RASAUTODIAL
+ //
+ // Get the automatic connection
+ // driver entry points.
+ //
+ NbfAcdBind();
+#endif // RASAUTODIAL
+ }
+ return;
+}
+VOID
+NbfProtocolUnbindAdapter(
+ OUT PNDIS_STATUS NdisStatus,
+ IN NDIS_HANDLE ProtocolBindContext,
+ IN PNDIS_HANDLE UnbindContext
+ )
+/*++
+
+Routine Description:
+
+ This routine deactivates a transport binding. Currently unimplemented.
+
+Arguments:
+
+ NdisStatus - The status of the bind.
+
+ ProtocolBindContext - the context from the openadapter call
+
+ UnbindContext - A context for async unbinds.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ *NdisStatus = STATUS_NOT_IMPLEMENTED;
+ return;
+}
+
+#endif // _PNP_POWER
diff --git a/private/ntos/tdi/nbf/nbfprocs.h b/private/ntos/tdi/nbf/nbfprocs.h
new file mode 100644
index 000000000..9449f0563
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbfprocs.h
@@ -0,0 +1,2322 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ nbfprocs.h
+
+Abstract:
+
+ This header file defines private functions for the NT NBF transport
+ provider.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Revision History:
+
+--*/
+
+#ifndef _NBFPROCS_
+#define _NBFPROCS_
+
+//
+// MACROS.
+//
+//
+// Debugging aids
+//
+
+//
+// VOID
+// IF_NBFDBG(
+// IN PSZ Message
+// );
+//
+
+#if DBG
+#define IF_NBFDBG(flags) \
+ if (NbfDebug & (flags))
+#else
+#define IF_NBFDBG(flags) \
+ if (0)
+#endif
+
+//
+// VOID
+// PANIC(
+// IN PSZ Message
+// );
+//
+
+#if DBG
+#define PANIC(Msg) \
+ DbgPrint ((Msg))
+#else
+#define PANIC(Msg)
+#endif
+
+
+//
+// These are define to allow DbgPrints that disappear when
+// DBG is 0.
+//
+
+#if DBG
+#define NbfPrint0(fmt) DbgPrint(fmt)
+#define NbfPrint1(fmt,v0) DbgPrint(fmt,v0)
+#define NbfPrint2(fmt,v0,v1) DbgPrint(fmt,v0,v1)
+#define NbfPrint3(fmt,v0,v1,v2) DbgPrint(fmt,v0,v1,v2)
+#define NbfPrint4(fmt,v0,v1,v2,v3) DbgPrint(fmt,v0,v1,v2,v3)
+#define NbfPrint5(fmt,v0,v1,v2,v3,v4) DbgPrint(fmt,v0,v1,v2,v3,v4)
+#define NbfPrint6(fmt,v0,v1,v2,v3,v4,v5) DbgPrint(fmt,v0,v1,v2,v3,v4,v5)
+#else
+#define NbfPrint0(fmt)
+#define NbfPrint1(fmt,v0)
+#define NbfPrint2(fmt,v0,v1)
+#define NbfPrint3(fmt,v0,v1,v2)
+#define NbfPrint4(fmt,v0,v1,v2,v3)
+#define NbfPrint5(fmt,v0,v1,v2,v3,v4)
+#define NbfPrint6(fmt,v0,v1,v2,v3,v4,v5)
+#endif
+
+//
+// The REFCOUNTS message take up a lot of room, so make
+// removing them easy.
+//
+
+#if 1
+#define IF_REFDBG IF_NBFDBG (NBF_DEBUG_REFCOUNTS)
+#else
+#define IF_REFDBG if (0)
+#endif
+
+#if DBG
+#define NbfReferenceLink( Reason, Link, Type)\
+ if ((Link)->Destroyed) { \
+ DbgPrint("NBF: Attempt to reference destroyed link %lx\n", Link); \
+ DbgBreakPoint(); \
+ } \
+ IF_REFDBG { \
+ DbgPrint ("RefL %x: %s %s, %ld : %ld\n", Link, Reason, __FILE__, __LINE__, (Link)->ReferenceCount);\
+ }\
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)(&(Link)->RefTypes[Type]), \
+ 1, \
+ &NbfGlobalInterlock); \
+ NbfRefLink (Link)
+
+#define NbfDereferenceLink(Reason, Link, Type)\
+ if ((Link)->Destroyed) { \
+ DbgPrint("NBF: Attempt to dereference destroyed link %lx\n", Link); \
+ DbgBreakPoint(); \
+ } \
+ IF_REFDBG { \
+ DbgPrint ("DeRefL %x: %s %s, %ld : %ld\n", Link, Reason, __FILE__, __LINE__, (Link)->ReferenceCount);\
+ } \
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)(&(Link)->RefTypes[Type]), \
+ (ULONG)-1, \
+ &NbfGlobalInterlock); \
+ NbfDerefLink (Link)
+
+#define NbfDereferenceLinkMacro(Reason, Link, Type)\
+ NbfDereferenceLink(Reason, Link, Type)
+
+#define NbfReferenceLinkSpecial( Reason, Link, Type)\
+ if ((Link)->Destroyed) { \
+ DbgPrint("NBF: Attempt to special reference destroyed link %lx\n", Link); \
+ DbgBreakPoint(); \
+ } \
+ IF_REFDBG { \
+ DbgPrint ("RefLS %x: %s %s, %ld : %ld\n", Link, Reason, __FILE__, __LINE__, (Link)->SpecialRefCount);\
+ }\
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)(&(Link)->RefTypes[Type]), \
+ 1, \
+ &NbfGlobalInterlock); \
+ NbfRefLinkSpecial (Link)
+
+#define NbfDereferenceLinkSpecial(Reason, Link, Type)\
+ if ((Link)->Destroyed) { \
+ DbgPrint("NBF: Attempt to special dereference destroyed link %lx\n", Link); \
+ DbgBreakPoint(); \
+ } \
+ IF_REFDBG { \
+ DbgPrint ("DeRefLS %x: %s %s, %ld : %ld\n", Link, Reason, __FILE__, __LINE__, (Link)->SpecialRefCount);\
+ } \
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)(&(Link)->RefTypes[Type]), \
+ (ULONG)-1, \
+ &NbfGlobalInterlock); \
+ NbfDerefLinkSpecial (Link)
+
+#define NbfReferenceConnection(Reason, Connection, Type)\
+ if ((Connection)->Destroyed) { \
+ DbgPrint("NBF: Attempt to reference destroyed conn %lx\n", Connection); \
+ DbgBreakPoint(); \
+ } \
+ IF_REFDBG { \
+ DbgPrint ("RefC %x: %s %s, %ld : %ld\n", Connection, Reason, __FILE__, __LINE__, (Connection)->ReferenceCount);\
+ } \
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)(&(Connection)->RefTypes[Type]), \
+ 1, \
+ &NbfGlobalInterlock); \
+ NbfRefConnection (Connection)
+
+#define NbfDereferenceConnection(Reason, Connection, Type)\
+ if ((Connection)->Destroyed) { \
+ DbgPrint("NBF: Attempt to dereference destroyed conn %lx\n", Connection); \
+ DbgBreakPoint(); \
+ } \
+ IF_REFDBG { \
+ DbgPrint ("DeRefC %x: %s %s, %ld : %ld\n", Connection, Reason, __FILE__, __LINE__, (Connection)->ReferenceCount);\
+ } \
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)&((Connection)->RefTypes[Type]), \
+ (ULONG)-1, \
+ &NbfGlobalInterlock); \
+ NbfDerefConnection (Connection)
+
+#define NbfDereferenceConnectionMacro(Reason, Connection, Type)\
+ NbfDereferenceConnection(Reason, Connection, Type)
+
+#define NbfDereferenceConnectionSpecial(Reason, Connection, Type)\
+ IF_REFDBG { \
+ DbgPrint ("DeRefCL %x: %s %s, %ld : %ld\n", Connection, Reason, __FILE__, __LINE__, (Connection)->ReferenceCount);\
+ } \
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)&((Connection)->RefTypes[Type]), \
+ (ULONG)-1, \
+ &NbfGlobalInterlock); \
+ NbfDerefConnectionSpecial (Connection)
+
+#define NbfReferenceRequest( Reason, Request, Type)\
+ if ((Request)->Destroyed) { \
+ DbgPrint("NBF: Attempt to reference destroyed req %lx\n", Request); \
+ DbgBreakPoint(); \
+ } \
+ IF_REFDBG { \
+ DbgPrint ("RefR %x: %s %s, %ld : %ld\n", Request, Reason, __FILE__, __LINE__, (Request)->ReferenceCount);}\
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)(&(Request)->RefTypes[Type]), \
+ 1, \
+ &NbfGlobalInterlock); \
+ NbfRefRequest (Request)
+
+#define NbfDereferenceRequest(Reason, Request, Type)\
+ if ((Request)->Destroyed) { \
+ DbgPrint("NBF: Attempt to dereference destroyed req %lx\n", Request); \
+ DbgBreakPoint(); \
+ } \
+ IF_REFDBG { \
+ DbgPrint ("DeRefR %x: %s %s, %ld : %ld\n", Request, Reason, __FILE__, __LINE__, (Request)->ReferenceCount);\
+ } \
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)(&(Request)->RefTypes[Type]), \
+ (ULONG)-1, \
+ &NbfGlobalInterlock); \
+ NbfDerefRequest (Request)
+
+#define NbfReferenceSendIrp( Reason, IrpSp, Type)\
+ IF_REFDBG { \
+ DbgPrint ("RefSI %x: %s %s, %ld : %ld\n", IrpSp, Reason, __FILE__, __LINE__, IRP_SEND_REFCOUNT(IrpSp));}\
+ NbfRefSendIrp (IrpSp)
+
+#define NbfDereferenceSendIrp(Reason, IrpSp, Type)\
+ IF_REFDBG { \
+ DbgPrint ("DeRefSI %x: %s %s, %ld : %ld\n", IrpSp, Reason, __FILE__, __LINE__, IRP_SEND_REFCOUNT(IrpSp));\
+ } \
+ NbfDerefSendIrp (IrpSp)
+
+#define NbfReferenceReceiveIrpLocked( Reason, IrpSp, Type)\
+ IF_REFDBG { \
+ DbgPrint ("RefRI %x: %s %s, %ld : %ld\n", IrpSp, Reason, __FILE__, __LINE__, IRP_RECEIVE_REFCOUNT(IrpSp));}\
+ NbfRefReceiveIrpLocked (IrpSp)
+
+#define NbfDereferenceReceiveIrp(Reason, IrpSp, Type)\
+ IF_REFDBG { \
+ DbgPrint ("DeRefRI %x: %s %s, %ld : %ld\n", IrpSp, Reason, __FILE__, __LINE__, IRP_RECEIVE_REFCOUNT(IrpSp));\
+ } \
+ NbfDerefReceiveIrp (IrpSp)
+
+#define NbfDereferenceReceiveIrpLocked(Reason, IrpSp, Type)\
+ IF_REFDBG { \
+ DbgPrint ("DeRefRILocked %x: %s %s, %ld : %ld\n", IrpSp, Reason, __FILE__, __LINE__, IRP_RECEIVE_REFCOUNT(IrpSp));\
+ } \
+ NbfDerefReceiveIrpLocked (IrpSp)
+
+#define NbfReferenceAddress( Reason, Address, Type)\
+ IF_REFDBG { \
+ DbgPrint ("RefA %x: %s %s, %ld : %ld\n", Address, Reason, __FILE__, __LINE__, (Address)->ReferenceCount);}\
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)(&(Address)->RefTypes[Type]), \
+ 1, \
+ &NbfGlobalInterlock); \
+ NbfRefAddress (Address)
+
+#define NbfDereferenceAddress(Reason, Address, Type)\
+ IF_REFDBG { \
+ DbgPrint ("DeRefA %x: %s %s, %ld : %ld\n", Address, Reason, __FILE__, __LINE__, (Address)->ReferenceCount);\
+ } \
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)(&(Address)->RefTypes[Type]), \
+ (ULONG)-1, \
+ &NbfGlobalInterlock); \
+ NbfDerefAddress (Address)
+
+#define NbfReferenceDeviceContext( Reason, DeviceContext, Type)\
+ IF_REFDBG { \
+ DbgPrint ("RefDC %x: %s %s, %ld : %ld\n", DeviceContext, Reason, __FILE__, __LINE__, (DeviceContext)->ReferenceCount);}\
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)(&(DeviceContext)->RefTypes[Type]), \
+ 1, \
+ &NbfGlobalInterlock); \
+ NbfRefDeviceContext (DeviceContext)
+
+#define NbfDereferenceDeviceContext(Reason, DeviceContext, Type)\
+ IF_REFDBG { \
+ DbgPrint ("DeRefDC %x: %s %s, %ld : %ld\n", DeviceContext, Reason, __FILE__, __LINE__, (DeviceContext)->ReferenceCount);\
+ } \
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)(&(DeviceContext)->RefTypes[Type]), \
+ (ULONG)-1, \
+ &NbfGlobalInterlock); \
+ NbfDerefDeviceContext (DeviceContext)
+
+#else
+#if defined(NBF_UP)
+#define NbfReferenceLink(Reason, Link, Type) \
+ { \
+ ULONG _ref; \
+ _ref = ++(Link)->ReferenceCount; \
+ if ( _ref == 0 ) { \
+ NbfReferenceLinkSpecial ("first ref", (Link), LREF_SPECIAL_TEMP); \
+ } \
+ }
+#else
+#define NbfReferenceLink(Reason, Link, Type) \
+ if (InterlockedIncrement( \
+ &(Link)->ReferenceCount) == 0) { \
+ NbfReferenceLinkSpecial ("first ref", (Link), LREF_SPECIAL_TEMP); \
+ }
+#endif
+
+#define NbfDereferenceLink(Reason, Link, Type)\
+ NbfDereferenceLinkMacro(Reason,Link,Type)
+
+#if defined(NBF_UP)
+#define NbfDereferenceLinkMacro(Reason, Link, Type){ \
+ ULONG _ref; \
+ _ref = --(Link)->ReferenceCount; \
+ if (_ref < 0) { \
+ NbfDisconnectLink (Link); \
+ NbfDerefLinkSpecial (Link); \
+ } \
+}
+#else
+#define NbfDereferenceLinkMacro(Reason, Link, Type){ \
+ if (InterlockedDecrement( \
+ &(Link)->ReferenceCount) < 0) { \
+ NbfDisconnectLink (Link); \
+ NbfDerefLinkSpecial (Link); \
+ } \
+}
+#endif
+
+#define NbfReferenceLinkSpecial(Reason, Link, Type)\
+ NbfRefLinkSpecial (Link)
+
+#define NbfDereferenceLinkSpecial(Reason, Link, Type)\
+ NbfDerefLinkSpecial (Link)
+
+#define NbfReferenceConnection(Reason, Connection, Type)\
+ if (InterlockedIncrement( \
+ &(Connection)->ReferenceCount) == 0) { \
+ ExInterlockedAddUlong( \
+ (PULONG)(&(Connection)->SpecialRefCount), \
+ 1, \
+ (Connection)->ProviderInterlock); \
+ }
+
+#define NbfDereferenceConnection(Reason, Connection, Type)\
+ NbfDerefConnection (Connection)
+
+#define NbfDereferenceConnectionMacro(Reason, Connection, Type){ \
+ if (InterlockedDecrement( \
+ &(Connection)->ReferenceCount) < 0) { \
+ if (NbfDisconnectFromLink (Connection, TRUE)) { \
+ NbfIndicateDisconnect (Connection); \
+ } \
+ NbfDerefConnectionSpecial (Connection); \
+ } \
+}
+
+#define NbfDereferenceConnectionSpecial(Reason, Connection, Type)\
+ NbfDerefConnectionSpecial (Connection)
+
+#define NbfReferenceRequest(Reason, Request, Type)\
+ (VOID)InterlockedIncrement( \
+ &(Request)->ReferenceCount)
+
+#define NbfDereferenceRequest(Reason, Request, Type)\
+ NbfDerefRequest (Request)
+
+#define NbfReferenceSendIrp(Reason, IrpSp, Type)\
+ (VOID)InterlockedIncrement( \
+ &IRP_SEND_REFCOUNT(IrpSp))
+
+#define NbfDereferenceSendIrp(Reason, IrpSp, Type) {\
+ PIO_STACK_LOCATION _IrpSp = (IrpSp); \
+ if (InterlockedDecrement( \
+ &IRP_SEND_REFCOUNT(_IrpSp)) == 0) { \
+ PIRP _Irp = IRP_SEND_IRP(_IrpSp); \
+ IRP_SEND_REFCOUNT(_IrpSp) = 0; \
+ IRP_SEND_IRP (_IrpSp) = NULL; \
+ IoCompleteRequest (_Irp, IO_NETWORK_INCREMENT); \
+ } \
+}
+
+#define NbfReferenceReceiveIrpLocked(Reason, IrpSp, Type)\
+ ++IRP_RECEIVE_REFCOUNT(IrpSp)
+
+#define NbfDereferenceReceiveIrp(Reason, IrpSp, Type)\
+ NbfDerefReceiveIrp (IrpSp)
+
+#define NbfDereferenceReceiveIrpLocked(Reason, IrpSp, Type) { \
+ if (--IRP_RECEIVE_REFCOUNT(IrpSp) == 0) { \
+ ExInterlockedInsertTailList( \
+ &(IRP_DEVICE_CONTEXT(IrpSp)->IrpCompletionQueue), \
+ &(IRP_RECEIVE_IRP(IrpSp))->Tail.Overlay.ListEntry, \
+ &(IRP_DEVICE_CONTEXT(IrpSp)->Interlock)); \
+ } \
+}
+
+#define NbfReferenceAddress(Reason, Address, Type)\
+ (VOID)InterlockedIncrement(&(Address)->ReferenceCount)
+
+#define NbfDereferenceAddress(Reason, Address, Type)\
+ NbfDerefAddress (Address)
+
+#define NbfReferenceDeviceContext(Reason, DeviceContext, Type)\
+ NbfRefDeviceContext (DeviceContext)
+
+#define NbfDereferenceDeviceContext(Reason, DeviceContext, Type)\
+ NbfDerefDeviceContext (DeviceContext)
+
+#define NbfReferencePacket(Packet) \
+ (VOID)InterlockedIncrement(&(Packet)->ReferenceCount)
+
+#define NbfDereferencePacket(Packet){ \
+ if (InterlockedDecrement ( \
+ &(Packet)->ReferenceCount) == 0) { \
+ NbfDestroyPacket (Packet); \
+ } \
+}
+
+#endif
+
+
+//
+// Error and statistics Macros
+//
+
+
+// VOID
+// LogErrorToSystem(
+// NTSTATUS ErrorType,
+// PUCHAR ErrorDescription
+// )
+
+/*++
+
+Routine Description:
+
+ This routine is called to log an error from the transport to the system.
+ Errors that are of system interest should be logged using this interface.
+ For now, this macro is defined trivially. (BUGBUG)
+
+Arguments:
+
+ ErrorType - The error type, a conventional NT status
+
+ ErrorDescription - A pointer to a string describing the error.
+
+Return Value:
+
+ none.
+
+--*/
+
+#if DBG
+#define LogErrorToSystem( ErrorType, ErrorDescription) \
+ DbgPrint ("Logging error: File: %s Line: %ld \n Description: %s\n",__FILE__, __LINE__, ErrorDescription)
+#else
+#define LogErrorToSystem( ErrorType, ErrorDescription)
+#endif
+
+
+//
+// Routines in TIMER.C (lightweight timer system package).
+// Note that all the start and stop routines for the timers assume that you
+// have the link spinlock when you call them!
+// Note also that, with the latest revisions, the timer system now works by
+// putting those links that have timers running on a list of links to be looked
+// at for each clock tick. This list is ordered, with the most recently inserted
+// elements at the tail of the list. Note further that anything already on the
+// is moved to the end of the list if the timer is restarted; thus, the list
+// order is preserved.
+//
+
+VOID
+NbfStartShortTimer(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+VOID
+NbfInitializeTimerSystem(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+VOID
+NbfStopTimerSystem(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+
+VOID
+StartT1(
+ IN PTP_LINK Link,
+ IN ULONG PacketSize
+ );
+
+VOID
+StartT2(
+ IN PTP_LINK Link
+ );
+
+VOID
+StartTi(
+ IN PTP_LINK Link
+ );
+
+#if DBG
+
+VOID
+StopT1(
+ IN PTP_LINK Link
+ );
+
+VOID
+StopT2(
+ IN PTP_LINK Link
+ );
+
+VOID
+StopTi(
+ IN PTP_LINK Link
+ );
+
+#else
+
+#define StopT1(_Link) \
+ { \
+ (_Link)->CurrentPollOutstanding = FALSE; \
+ (_Link)->T1 = 0; \
+ }
+
+#define StopT2(_Link) \
+ { \
+ (_Link)->ConsecutiveIFrames = 0; \
+ (_Link)->T2 = 0; \
+ }
+
+#define StopTi(_Link) \
+ (_Link)->Ti = 0;
+
+#endif
+
+
+//
+// These functions may become macros once they are finished.
+//
+
+ULONG
+GetTimerInterval(
+ IN PTP_LINK Link
+ );
+
+VOID
+BackoffCurrentT1Timeout(
+ IN PTP_LINK Link
+ );
+
+VOID
+UpdateBaseT1Timeout(
+ IN PTP_LINK Link
+ );
+
+VOID
+CancelT1Timeout(
+ IN PTP_LINK Link
+ );
+
+VOID
+UpdateDelayAndThroughput(
+ IN PTP_LINK Link,
+ IN ULONG TimerInterval
+ );
+
+VOID
+FakeStartT1(
+ IN PTP_LINK Link,
+ IN ULONG PacketSize
+ );
+
+VOID
+FakeUpdateBaseT1Timeout(
+ IN PTP_LINK Link
+ );
+
+
+//
+// These macros are used to create and destroy packets, due
+// to the allocation or deallocation of structure which
+// need them.
+//
+
+#define NbfAddUIFrame(DeviceContext) { \
+ PTP_UI_FRAME _UIFrame; \
+ NbfAllocateUIFrame ((DeviceContext), &_UIFrame); \
+ if (_UIFrame != NULL) { \
+ ExInterlockedInsertTailList( \
+ &(DeviceContext)->UIFramePool, \
+ &_UIFrame->Linkage, \
+ &(DeviceContext)->Interlock); \
+ } \
+}
+
+#define NbfRemoveUIFrame(DeviceContext) { \
+ PLIST_ENTRY p; \
+ if (DeviceContext->UIFrameAllocated > DeviceContext->UIFrameInitAllocated) { \
+ p = ExInterlockedRemoveHeadList( \
+ &(DeviceContext)->UIFramePool, \
+ &(DeviceContext)->Interlock); \
+ if (p != NULL) { \
+ NbfDeallocateUIFrame((DeviceContext), \
+ (PTP_UI_FRAME)CONTAINING_RECORD(p, TP_UI_FRAME, Linkage)); \
+ } \
+ } \
+}
+
+
+#define NbfAddSendPacket(DeviceContext) { \
+ PTP_PACKET _SendPacket; \
+ NbfAllocateSendPacket ((DeviceContext), &_SendPacket); \
+ if (_SendPacket != NULL) { \
+ ExInterlockedPushEntryList( \
+ &(DeviceContext)->PacketPool, \
+ (PSINGLE_LIST_ENTRY)&_SendPacket->Linkage, \
+ &(DeviceContext)->Interlock); \
+ } \
+}
+
+#define NbfRemoveSendPacket(DeviceContext) { \
+ PSINGLE_LIST_ENTRY s; \
+ if (DeviceContext->PacketAllocated > DeviceContext->PacketInitAllocated) { \
+ s = ExInterlockedPopEntryList( \
+ &(DeviceContext)->PacketPool, \
+ &(DeviceContext)->Interlock); \
+ if (s != NULL) { \
+ NbfDeallocateSendPacket((DeviceContext), \
+ (PTP_PACKET)CONTAINING_RECORD(s, TP_PACKET, Linkage)); \
+ } \
+ } \
+}
+
+
+#define NbfAddReceivePacket(DeviceContext) { \
+ if (!(DeviceContext)->MacInfo.SingleReceive) { \
+ PNDIS_PACKET _ReceivePacket; \
+ NbfAllocateReceivePacket ((DeviceContext), &_ReceivePacket); \
+ if (_ReceivePacket != NULL) { \
+ ExInterlockedPushEntryList( \
+ &(DeviceContext)->ReceivePacketPool, \
+ &((PRECEIVE_PACKET_TAG)_ReceivePacket->ProtocolReserved)->Linkage, \
+ &(DeviceContext)->Interlock); \
+ } \
+ } \
+}
+
+#define NbfRemoveReceivePacket(DeviceContext) { \
+ PSINGLE_LIST_ENTRY s; \
+ if (DeviceContext->ReceivePacketAllocated > DeviceContext->ReceivePacketInitAllocated) { \
+ s = ExInterlockedPopEntryList( \
+ &(DeviceContext)->ReceivePacketPool, \
+ &(DeviceContext)->Interlock); \
+ if (s != NULL) { \
+ NbfDeallocateReceivePacket((DeviceContext), \
+ (PNDIS_PACKET)CONTAINING_RECORD(s, NDIS_PACKET, ProtocolReserved[0])); \
+ } \
+ } \
+}
+
+
+#define NbfAddReceiveBuffer(DeviceContext) { \
+ if (!(DeviceContext)->MacInfo.SingleReceive) { \
+ PBUFFER_TAG _ReceiveBuffer; \
+ NbfAllocateReceiveBuffer ((DeviceContext), &_ReceiveBuffer); \
+ if (_ReceiveBuffer != NULL) { \
+ ExInterlockedPushEntryList( \
+ &(DeviceContext)->ReceiveBufferPool, \
+ (PSINGLE_LIST_ENTRY)&_ReceiveBuffer->Linkage, \
+ &(DeviceContext)->Interlock); \
+ } \
+ } \
+}
+
+#define NbfRemoveReceiveBuffer(DeviceContext) { \
+ PSINGLE_LIST_ENTRY s; \
+ if (DeviceContext->ReceiveBufferAllocated > DeviceContext->ReceiveBufferInitAllocated) { \
+ s = ExInterlockedPopEntryList( \
+ &(DeviceContext)->ReceiveBufferPool, \
+ &(DeviceContext)->Interlock); \
+ if (s != NULL) { \
+ NbfDeallocateReceiveBuffer(DeviceContext, \
+ (PBUFFER_TAG)CONTAINING_RECORD(s, BUFFER_TAG, Linkage)); \
+ } \
+ } \
+}
+
+
+//
+// These routines are used to maintain counters.
+//
+
+#define INCREMENT_COUNTER(_DeviceContext,_Field) \
+ ++(_DeviceContext)->Statistics._Field
+
+#define DECREMENT_COUNTER(_DeviceContext,_Field) \
+ --(_DeviceContext)->Statistics._Field
+
+#define ADD_TO_LARGE_INTEGER(_LargeInteger,_Ulong) \
+ ExInterlockedAddLargeStatistic((_LargeInteger), (ULONG)(_Ulong))
+
+
+
+//
+// Routines in PACKET.C (TP_PACKET object manager).
+//
+
+VOID
+NbfAllocateUIFrame(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_UI_FRAME *TransportUIFrame
+ );
+
+VOID
+NbfAllocateSendPacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_PACKET *TransportSendPacket
+ );
+
+VOID
+NbfAllocateReceivePacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PNDIS_PACKET *TransportReceivePacket
+ );
+
+VOID
+NbfAllocateReceiveBuffer(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PBUFFER_TAG *TransportReceiveBuffer
+ );
+
+VOID
+NbfDeallocateUIFrame(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_UI_FRAME TransportUIFrame
+ );
+
+VOID
+NbfDeallocateSendPacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_PACKET TransportSendPacket
+ );
+
+VOID
+NbfDeallocateReceivePacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNDIS_PACKET TransportReceivePacket
+ );
+
+VOID
+NbfDeallocateReceiveBuffer(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PBUFFER_TAG TransportReceiveBuffer
+ );
+
+NTSTATUS
+NbfCreatePacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_LINK Link,
+ OUT PTP_PACKET *Packet
+ );
+
+NTSTATUS
+NbfCreateRrPacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_LINK Link,
+ OUT PTP_PACKET *Packet
+ );
+
+VOID
+NbfDestroyPacket(
+ IN PTP_PACKET Packet
+ );
+VOID
+NbfGrowSendPacketPool(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+#if DBG
+VOID
+NbfReferencePacket(
+ IN PTP_PACKET Packet
+ );
+
+VOID
+NbfDereferencePacket(
+ IN PTP_PACKET Packet
+ );
+#endif
+
+VOID
+NbfWaitPacket(
+ IN PTP_CONNECTION Connection,
+ IN ULONG Flags
+ );
+
+#if DBG
+#define MAGIC 1
+extern BOOLEAN NbfEnableMagic;
+#else
+#define MAGIC 0
+#endif
+
+#if MAGIC
+VOID
+NbfSendMagicBullet (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_LINK Link
+ );
+#endif
+
+//
+// Routines in RCVENG.C (Receive engine).
+//
+
+VOID
+AwakenReceive(
+ IN PTP_CONNECTION Connection
+ );
+
+VOID
+ActivateReceive(
+ IN PTP_CONNECTION Connection
+ );
+
+VOID
+CompleteReceive (
+ IN PTP_CONNECTION Connection,
+ IN BOOLEAN EndOfMessage,
+ IN ULONG BytesTransferred
+ );
+
+VOID
+NbfCancelReceive(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+NbfCancelReceiveDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+//
+// Routines in SEND.C (Receive engine).
+//
+
+NTSTATUS
+NbfTdiSend(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfTdiSendDatagram(
+ IN PIRP Irp
+ );
+
+//
+// Routines in SENDENG.C (Send engine).
+//
+
+#if DBG
+
+VOID
+InitializeSend(
+ PTP_CONNECTION Connection
+ );
+
+#else
+
+// See SENDENG.C for the fully-commented description of InitializeSend.
+
+#define InitializeSend(_conn_) { \
+ PIRP _irp_; \
+ (_conn_)->SendState = CONNECTION_SENDSTATE_PACKETIZE; \
+ _irp_ = CONTAINING_RECORD ((_conn_)->SendQueue.Flink, \
+ IRP, \
+ Tail.Overlay.ListEntry); \
+ (_conn_)->FirstSendIrp = (_conn_)->sp.CurrentSendIrp = _irp_; \
+ (_conn_)->FirstSendMdl = (_conn_)->sp.CurrentSendMdl = \
+ _irp_->MdlAddress; \
+ (_conn_)->FirstSendByteOffset = (_conn_)->sp.SendByteOffset = 0; \
+ (_conn_)->sp.MessageBytesSent = 0; \
+ (_conn_)->CurrentSendLength = \
+ IRP_SEND_LENGTH(IoGetCurrentIrpStackLocation(_irp_)); \
+ (_conn_)->StallCount = 0; \
+ (_conn_)->StallBytesSent = 0; \
+ if ((_conn_)->NetbiosHeader.ResponseCorrelator == 0xffff) { \
+ (_conn_)->NetbiosHeader.ResponseCorrelator = 1; \
+ } else { \
+ ++((_conn_)->NetbiosHeader.ResponseCorrelator); \
+ } \
+}
+
+#endif
+
+// See SENDENG.C for the fully-commented description of
+// StartPacketizingConnection. On a free build this is a
+// macro for speed.
+
+#if DBG
+
+VOID
+StartPacketizingConnection(
+ PTP_CONNECTION Connection,
+ IN BOOLEAN Immediate
+ );
+
+#else
+
+#define StartPacketizingConnection(_conn_,_immed_) { \
+ PDEVICE_CONTEXT _devctx_; \
+ _devctx_ = (_conn_)->Provider; \
+ if (((_conn_)->SendState == CONNECTION_SENDSTATE_PACKETIZE) && \
+ !((_conn_)->Flags & CONNECTION_FLAGS_PACKETIZE)) { \
+ (_conn_)->Flags |= CONNECTION_FLAGS_PACKETIZE; \
+ if (!(_immed_)) { \
+ NbfReferenceConnection("Packetize", \
+ (_conn_), \
+ CREF_PACKETIZE_QUEUE); \
+ } \
+ ExInterlockedInsertTailList (&_devctx_->PacketizeQueue, \
+ &(_conn_)->PacketizeLinkage, \
+ &_devctx_->SpinLock); \
+ RELEASE_DPC_SPIN_LOCK ((_conn_)->LinkSpinLock); \
+ } else { \
+ RELEASE_DPC_SPIN_LOCK ((_conn_)->LinkSpinLock); \
+ if (_immed_) { \
+ NbfDereferenceConnection("temp TdiSend", (_conn_), CREF_BY_ID); \
+ } \
+ } \
+ if (_immed_) { \
+ PacketizeConnections (_devctx_); \
+ } \
+}
+
+#endif
+
+VOID
+PacketizeConnections(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+VOID
+PacketizeSend(
+ IN PTP_CONNECTION Connection,
+ IN BOOLEAN Direct
+ );
+
+BOOLEAN
+ResendLlcPackets(
+ IN PTP_LINK Link,
+ IN UCHAR AckSequenceNumber,
+ IN BOOLEAN Resend
+ );
+
+VOID
+CompleteSend(
+ IN PTP_CONNECTION Connection,
+ IN USHORT Correlator
+ );
+
+VOID
+FailSend(
+ IN PTP_CONNECTION Connection,
+ IN NTSTATUS RequestStatus,
+ IN BOOLEAN StopConnection
+ );
+
+VOID
+ReframeSend(
+ IN PTP_CONNECTION Connection,
+ IN ULONG BytesReceived
+ );
+
+VOID
+NbfCancelSend(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+SendOnePacket(
+ IN PTP_CONNECTION Connection,
+ IN PTP_PACKET Packet,
+ IN BOOLEAN ForceAck,
+ OUT PBOOLEAN LinkCheckpoint OPTIONAL
+ );
+
+VOID
+SendControlPacket(
+ IN PTP_LINK Link,
+ IN PTP_PACKET Packet
+ );
+
+VOID
+NbfNdisSend(
+ IN PTP_LINK Link,
+ IN PTP_PACKET Packet
+ );
+
+VOID
+RestartLinkTraffic(
+ IN PTP_LINK Link
+ );
+
+VOID
+NbfSendCompletionHandler(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ );
+
+NTSTATUS
+BuildBufferChainFromMdlChain (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PMDL CurrentMdl,
+ IN ULONG ByteOffset,
+ IN ULONG DesiredLength,
+ OUT PNDIS_BUFFER *Destination,
+ OUT PMDL *NewCurrentMdl,
+ OUT ULONG *NewByteOffset,
+ OUT ULONG *TrueLength
+ );
+
+//
+// Routines in DEVCTX.C (TP_DEVCTX object manager).
+//
+
+VOID
+NbfRefDeviceContext(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+VOID
+NbfDerefDeviceContext(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+NTSTATUS
+NbfCreateDeviceContext(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN OUT PDEVICE_CONTEXT *DeviceContext
+ );
+
+VOID
+NbfDestroyDeviceContext(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+
+//
+// Routines in ADDRESS.C (TP_ADDRESS object manager).
+//
+
+#if DBG
+VOID
+NbfRefAddress(
+ IN PTP_ADDRESS Address
+ );
+#endif
+
+VOID
+NbfDerefAddress(
+ IN PTP_ADDRESS Address
+ );
+
+VOID
+NbfAllocateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS_FILE *TransportAddressFile
+ );
+
+VOID
+NbfDeallocateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS_FILE TransportAddressFile
+ );
+
+NTSTATUS
+NbfCreateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS_FILE * AddressFile
+ );
+
+VOID
+NbfReferenceAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile
+ );
+
+VOID
+NbfDereferenceAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile
+ );
+
+VOID
+NbfDestroyAddress(
+ IN PVOID Parameter
+ );
+
+NTSTATUS
+NbfOpenAddress(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+NbfCloseAddress(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+VOID
+NbfStopAddress(
+ IN PTP_ADDRESS Address
+ );
+
+VOID
+NbfRegisterAddress(
+ IN PTP_ADDRESS Address
+ );
+
+BOOLEAN
+NbfMatchNetbiosAddress(
+ IN PTP_ADDRESS Address,
+ IN UCHAR NameType,
+ IN PUCHAR NetBIOSName
+ );
+
+VOID
+NbfAllocateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS *TransportAddress
+ );
+
+VOID
+NbfDeallocateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS TransportAddress
+ );
+
+NTSTATUS
+NbfCreateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNBF_NETBIOS_ADDRESS NetworkName,
+ OUT PTP_ADDRESS *Address
+ );
+
+PTP_ADDRESS
+NbfLookupAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNBF_NETBIOS_ADDRESS NetworkName
+ );
+
+PTP_CONNECTION
+NbfLookupRemoteName(
+ IN PTP_ADDRESS Address,
+ IN PUCHAR RemoteName,
+ IN UCHAR RemoteSessionNumber
+ );
+
+NTSTATUS
+NbfStopAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile,
+ IN PTP_ADDRESS Address
+ );
+
+VOID
+AddressTimeoutHandler(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+TDI_ADDRESS_NETBIOS UNALIGNED *
+NbfParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN BOOLEAN BroadcastAddressOk
+);
+
+BOOLEAN
+NbfValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength
+);
+
+NTSTATUS
+NbfVerifyAddressObject (
+ IN PTP_ADDRESS_FILE AddressFile
+ );
+
+NTSTATUS
+NbfSendDatagramsOnAddress(
+ PTP_ADDRESS Address
+ );
+
+//
+// Routines in CONNECT.C.
+//
+
+NTSTATUS
+NbfTdiAccept(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfTdiConnect(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfTdiDisconnect(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfTdiDisassociateAddress (
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfTdiAssociateAddress(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfTdiListen(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfOpenConnection(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+NbfCloseConnection(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+//
+//
+// Routines in CONNOBJ.C (TP_CONNECTION object manager).
+//
+
+#if DBG
+VOID
+NbfRefConnection(
+ IN PTP_CONNECTION TransportConnection
+ );
+#endif
+
+VOID
+NbfDerefConnection(
+ IN PTP_CONNECTION TransportConnection
+ );
+
+VOID
+NbfDerefConnectionSpecial(
+ IN PTP_CONNECTION TransportConnection
+ );
+
+VOID
+NbfClearConnectionLsn(
+ IN PTP_CONNECTION TransportConnection
+ );
+
+VOID
+NbfStopConnection(
+ IN PTP_CONNECTION TransportConnection,
+ IN NTSTATUS Status
+ );
+
+VOID
+NbfCancelConnection(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+NbfStartConnectionTimer(
+ IN PTP_CONNECTION TransportConnection,
+ IN PKDEFERRED_ROUTINE TimeoutFunction,
+ IN ULONG WaitTime
+ );
+
+PTP_CONNECTION
+NbfLookupListeningConnection(
+ IN PTP_ADDRESS Address,
+ IN PUCHAR RemoteName
+ );
+
+PTP_CONNECTION
+NbfLookupConnectingConnection(
+ IN PTP_ADDRESS Address
+ );
+
+VOID
+NbfAllocateConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_CONNECTION *TransportConnection
+ );
+
+VOID
+NbfDeallocateConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_CONNECTION TransportConnection
+ );
+
+NTSTATUS
+NbfCreateConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_CONNECTION *TransportConnection
+ );
+
+PTP_CONNECTION
+NbfLookupConnectionById(
+ IN PTP_ADDRESS Address,
+ IN USHORT ConnectionId
+ );
+
+PTP_CONNECTION
+NbfLookupConnectionByContext(
+ IN PTP_ADDRESS Address,
+ IN CONNECTION_CONTEXT ConnectionContext
+ );
+
+#if 0
+VOID
+NbfWaitConnectionOnLink(
+ IN PTP_CONNECTION Connection,
+ IN ULONG Flags
+ );
+#endif
+
+VOID
+ConnectionEstablishmentTimeout(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+NTSTATUS
+NbfVerifyConnectionObject (
+ IN PTP_CONNECTION Connection
+ );
+
+NTSTATUS
+NbfIndicateDisconnect(
+ IN PTP_CONNECTION TransportConnection
+ );
+
+//
+// Routines in INFO.C (QUERY_INFO manager).
+//
+
+NTSTATUS
+NbfTdiQueryInformation(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfTdiSetInformation(
+ IN PIRP Irp
+ );
+
+VOID
+NbfSendQueryFindName(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_REQUEST Request
+ );
+
+NTSTATUS
+NbfProcessQueryNameRecognized(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR Packet,
+ PNBF_HDR_CONNECTIONLESS UiFrame
+ );
+
+VOID
+NbfSendStatusQuery(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_REQUEST Request,
+ IN PHARDWARE_ADDRESS DestinationAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ );
+
+NTSTATUS
+NbfProcessStatusResponse(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PNBF_HDR_CONNECTIONLESS UiFrame,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ );
+
+NTSTATUS
+NbfProcessStatusQuery(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address OPTIONAL,
+ IN PNBF_HDR_CONNECTIONLESS UiFrame,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ );
+
+//
+// Routines in EVENT.C.
+//
+
+NTSTATUS
+NbfTdiSetEventHandler(
+ IN PIRP Irp
+ );
+
+//
+// Routines in REQUEST.C (TP_REQUEST object manager).
+//
+
+
+VOID
+TdiRequestTimeoutHandler(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+#if DBG
+VOID
+NbfRefRequest(
+ IN PTP_REQUEST Request
+ );
+#endif
+
+VOID
+NbfDerefRequest(
+ IN PTP_REQUEST Request
+ );
+
+VOID
+NbfCompleteRequest(
+ IN PTP_REQUEST Request,
+ IN NTSTATUS Status,
+ IN ULONG Information
+ );
+
+#if DBG
+VOID
+NbfRefSendIrp(
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+VOID
+NbfDerefSendIrp(
+ IN PIO_STACK_LOCATION IrpSp
+ );
+#endif
+
+VOID
+NbfCompleteSendIrp(
+ IN PIRP Irp,
+ IN NTSTATUS Status,
+ IN ULONG Information
+ );
+
+#if DBG
+VOID
+NbfRefReceiveIrpLocked(
+ IN PIO_STACK_LOCATION IrpSp
+ );
+#endif
+
+VOID
+NbfDerefReceiveIrp(
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+#if DBG
+VOID
+NbfDerefReceiveIrpLocked(
+ IN PIO_STACK_LOCATION IrpSp
+ );
+#endif
+
+VOID
+NbfCompleteReceiveIrp(
+ IN PIRP Irp,
+ IN NTSTATUS Status,
+ IN ULONG Information
+ );
+
+VOID
+NbfAllocateRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_REQUEST *TransportRequest
+ );
+
+VOID
+NbfDeallocateRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_REQUEST TransportRequest
+ );
+
+NTSTATUS
+NbfCreateRequest(
+ IN PIRP Irp,
+ IN PVOID Context,
+ IN ULONG Flags,
+ IN PMDL Buffer2,
+ IN ULONG Buffer2Length,
+ IN LARGE_INTEGER Timeout,
+ OUT PTP_REQUEST * TpRequest
+ );
+
+//
+// Routines in LINK.C (TP_LINK object manager).
+//
+
+NTSTATUS
+NbfDestroyLink(
+ IN PTP_LINK TransportLink
+ );
+
+VOID
+NbfDisconnectLink(
+ IN PTP_LINK Link
+ );
+
+#if DBG
+VOID
+NbfRefLink(
+ IN PTP_LINK TransportLink
+ );
+#endif
+
+VOID
+NbfDerefLink(
+ IN PTP_LINK TransportLink
+ );
+
+VOID
+NbfRefLinkSpecial(
+ IN PTP_LINK TransportLink
+ );
+
+VOID
+NbfDerefLinkSpecial(
+ IN PTP_LINK TransportLink
+ );
+
+VOID
+NbfResetLink(
+ IN PTP_LINK Link
+ );
+
+VOID
+NbfStopLink(
+ IN PTP_LINK Link
+ );
+
+VOID
+NbfCompleteLink(
+ IN PTP_LINK Link
+ );
+
+VOID
+NbfActivateLink(
+ IN PTP_LINK Link
+ );
+
+VOID
+NbfWaitLink(
+ IN PTP_LINK Link
+ );
+
+BOOLEAN
+NbfDisconnectFromLink(
+ IN PTP_CONNECTION TransportConnection,
+ IN BOOLEAN VerifyReferenceCount
+ );
+
+NTSTATUS
+NbfAssignGroupLsn(
+ IN PTP_CONNECTION TransportConnection
+ );
+
+NTSTATUS
+NbfConnectToLink(
+ IN PTP_LINK Link,
+ IN PTP_CONNECTION TransportConnection
+ );
+
+PTP_CONNECTION
+NbfLookupPendingConnectOnLink(
+ IN PTP_LINK Link
+ );
+
+PTP_CONNECTION
+NbfLookupPendingListenOnLink(
+ IN PTP_LINK Link
+ );
+
+VOID
+NbfAllocateLink(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_LINK *TransportLink
+ );
+
+VOID
+NbfDeallocateLink(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_LINK TransportLink
+ );
+
+NTSTATUS
+NbfCreateLink(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PHARDWARE_ADDRESS HardwareAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN USHORT LoopbackLinkIndex,
+ OUT PTP_LINK *TransportLink
+ );
+
+VOID
+NbfDumpLinkInfo (
+ IN PTP_LINK Link
+ );
+
+//
+// routines in linktree.c
+//
+
+
+NTSTATUS
+NbfAddLinkToTree (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_LINK Link
+ );
+
+NTSTATUS
+NbfRemoveLinkFromTree(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_LINK Link
+ );
+
+PTP_LINK
+NbfFindLinkInTree(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR Remote
+ );
+
+PTP_LINK
+NbfFindLink(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR Remote
+ );
+
+//
+// Routines in DLC.C (LLC frame cracker, entrypoints from NDIS interface).
+//
+
+VOID
+NbfInsertInLoopbackQueue (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN UCHAR LinkIndex
+ );
+
+VOID
+NbfProcessLoopbackQueue (
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+NDIS_STATUS
+NbfReceiveIndication(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+VOID
+NbfGeneralReceiveHandler (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PTP_LINK Link,
+ IN PVOID HeaderBuffer,
+ IN UINT PacketSize,
+ IN PDLC_FRAME DlcHeader,
+ IN UINT DlcSize,
+ IN BOOLEAN Loopback
+ );
+
+VOID
+NbfReceiveComplete (
+ IN NDIS_HANDLE BindingContext
+ );
+
+VOID
+NbfProcessWanDelayedQueue(
+ IN PVOID Parameter
+ );
+
+VOID
+NbfTransferDataComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ );
+
+
+VOID
+NbfTransferLoopbackData (
+ OUT PNDIS_STATUS NdisStatus,
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+
+//
+// Routines in UFRAMES.C, the UI-frame NBF frame processor.
+//
+
+NTSTATUS
+NbfIndicateDatagram(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address,
+ IN PUCHAR Dsdu,
+ IN ULONG Length
+ );
+
+NTSTATUS
+NbfProcessUi(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR Header,
+ IN PUCHAR DlcHeader,
+ IN ULONG DlcLength,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ OUT PTP_ADDRESS * DatagramAddress
+ );
+
+//
+// Routines in IFRAMES.C, the I-frame NBF frame processor.
+//
+
+VOID
+NbfAcknowledgeDataOnlyLast(
+ IN PTP_CONNECTION Connection,
+ IN ULONG MessageLength
+ );
+
+VOID
+NbfProcessIIndicate(
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PTP_LINK Link,
+ IN PUCHAR DlcHeader,
+ IN UINT DlcIndicatedLength,
+ IN UINT DlcTotalLength,
+ IN NDIS_HANDLE ReceiveContext,
+ IN BOOLEAN Loopback
+ );
+
+NTSTATUS
+ProcessIndicateData(
+ IN PTP_CONNECTION Connection,
+ IN PUCHAR DlcHeader,
+ IN UINT DlcIndicatedLength,
+ IN PUCHAR DataHeader,
+ IN UINT DataTotalLength,
+ IN NDIS_HANDLE ReceiveContext,
+ IN BOOLEAN Last,
+ IN BOOLEAN Loopback
+ );
+
+//
+// Routines in RCV.C (data copying routines for receives).
+//
+
+NTSTATUS
+NbfTdiReceive(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfTdiReceiveDatagram(
+ IN PIRP Irp
+ );
+
+//
+// Routines in FRAMESND.C, the UI-frame (non-link) shipper.
+//
+
+VOID
+NbfSendNameQuery(
+ IN PTP_CONNECTION Connection,
+ IN BOOLEAN SourceRoutingOptional
+ );
+
+VOID
+NbfSendNameRecognized(
+ IN PTP_ADDRESS Address,
+ IN UCHAR LocalSessionNumber, // LSN assigned to session.
+ IN PNBF_HDR_CONNECTIONLESS Header,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ );
+
+VOID
+NbfSendNameInConflict(
+ IN PTP_ADDRESS Address,
+ IN PUCHAR ConflictingName
+ );
+
+NTSTATUS
+NbfSendAddNameQuery(
+ IN PTP_ADDRESS Address
+ );
+
+VOID
+NbfSendSessionInitialize(
+ IN PTP_CONNECTION Connection
+ );
+
+VOID
+NbfSendSessionConfirm(
+ IN PTP_CONNECTION Connection
+ );
+
+VOID
+NbfSendSessionEnd(
+ IN PTP_CONNECTION Connection,
+ IN BOOLEAN Abort
+ );
+
+VOID
+NbfSendNoReceive(
+ IN PTP_CONNECTION Connection
+ );
+
+VOID
+NbfSendReceiveContinue(
+ IN PTP_CONNECTION Connection
+ );
+
+VOID
+NbfSendReceiveOutstanding(
+ IN PTP_CONNECTION Connection
+ );
+
+VOID
+NbfSendDataAck(
+ IN PTP_CONNECTION Connection
+ );
+
+VOID
+NbfSendSabme(
+ IN PTP_LINK Link,
+ IN BOOLEAN PollFinal
+ );
+
+VOID
+NbfSendDisc(
+ IN PTP_LINK Link,
+ IN BOOLEAN PollFinal
+ );
+
+VOID
+NbfSendUa(
+ IN PTP_LINK Link,
+ IN BOOLEAN PollFinal
+ );
+
+VOID
+NbfSendDm(
+ IN PTP_LINK Link,
+ IN BOOLEAN PollFinal
+ );
+
+VOID
+NbfSendRr(
+ IN PTP_LINK Link,
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal
+ );
+
+#if 0
+
+//
+// These functions are not currently called, so they are commented
+// out.
+//
+
+VOID
+NbfSendRnr(
+ IN PTP_LINK Link,
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal
+ );
+
+VOID
+NbfSendTest(
+ IN PTP_LINK Link,
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PMDL Psdu
+ );
+
+VOID
+NbfSendFrmr(
+ IN PTP_LINK Link,
+ IN BOOLEAN PollFinal
+ );
+
+#endif
+
+VOID
+NbfSendXid(
+ IN PTP_LINK Link,
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal
+ );
+
+VOID
+NbfSendRej(
+ IN PTP_LINK Link,
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal
+ );
+
+NTSTATUS
+NbfCreateConnectionlessFrame(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_UI_FRAME *OuterFrame
+ );
+
+VOID
+NbfDestroyConnectionlessFrame(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_UI_FRAME RawFrame
+ );
+
+VOID
+NbfSendUIFrame(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_UI_FRAME RawFrame,
+ IN BOOLEAN Loopback
+ );
+
+VOID
+NbfSendUIMdlFrame(
+ IN PTP_ADDRESS Address
+ );
+
+VOID
+NbfSendDatagramCompletion(
+ IN PTP_ADDRESS Address,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ );
+
+//
+// Routines in FRAMECON.C, the NetBIOS Frames Protocol Frame Constructors.
+// To understand the various constant parameters to these functions (such
+// as special data1 & data2 values, see NBFCONST.H for details.
+//
+
+VOID
+ConstructAddGroupNameQuery(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN USHORT Correlator, // correlator for ADD_NAME_RESPONSE.
+ IN PNAME GroupName // NetBIOS group name to be added.
+ );
+
+VOID
+ConstructAddNameQuery(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN USHORT Correlator, // correlator for ADD_NAME_RESPONSE.
+ IN PNAME Name // NetBIOS name to be added.
+ );
+
+VOID
+ConstructNameInConflict(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN PNAME ConflictingName, // NetBIOS name that is conflicting.
+ IN PNAME SendingPermanentName // NetBIOS permanent node name of sender.
+ );
+
+VOID
+ConstructStatusQuery(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN UCHAR RequestType, // type of request, defined below.
+ IN USHORT BufferLength, // length of user's status buffer.
+ IN USHORT Correlator, // correlator for STATUS_RESPONSE.
+ IN PNAME ReceiverName, // NetBIOS name of receiver.
+ IN PNAME SendingPermanentName // NetBIOS permanent node name of sender.
+ );
+
+VOID
+ConstructTerminateTrace(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame // frame buffer to format.
+ );
+
+VOID
+ConstructDatagram(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN PNAME ReceiverName, // NetBIOS name of receiver.
+ IN PNAME SenderName // NetBIOS name of sender.
+ );
+
+VOID
+ConstructDatagramBroadcast(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN PNAME SenderName // NetBIOS name of sender.
+ );
+
+VOID
+ConstructNameQuery(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN UCHAR NameType, // type of name.
+ IN UCHAR LocalSessionNumber, // LSN assigned to session (0=FIND_NAME).
+ IN USHORT Correlator, // correlator in NAME_RECOGNIZED.
+ IN PNAME SenderName, // NetBIOS name of sender.
+ IN PNAME ReceiverName // NetBIOS name of sender.
+ );
+
+VOID
+ConstructAddNameResponse(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN UCHAR NameType, // type of name.
+ IN USHORT Correlator, // correlator from ADD_[GROUP_]NAME_QUERY.
+ IN PNAME Name // NetBIOS name being responded to.
+ );
+
+VOID
+ConstructNameRecognized(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN UCHAR NameType, // type of name.
+ IN UCHAR LocalSessionNumber, // LSN assigned to session.
+ IN USHORT NameQueryCorrelator, // correlator from NAME_QUERY.
+ IN USHORT Correlator, // correlator expected from next response.
+ IN PNAME SenderName, // NetBIOS name of sender.
+ IN PNAME ReceiverName // NetBIOS name of receiver.
+ );
+
+VOID
+ConstructStatusResponse(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN UCHAR RequestType, // type of request, defined below.
+ IN BOOLEAN Truncated, // data is truncated.
+ IN BOOLEAN DataOverflow, // too much data for user's buffer.
+ IN USHORT DataLength, // length of data sent.
+ IN USHORT Correlator, // correlator from STATUS_QUERY.
+ IN PNAME ReceivingPermanentName, // NetBIOS permanent node name of receiver.
+ IN PNAME SenderName // NetBIOS name of sender.
+ );
+
+VOID
+ConstructDataAck(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN USHORT Correlator, // correlator from DATA_ONLY_LAST.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ );
+
+VOID
+ConstructDataOnlyLast(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN BOOLEAN Resynched, // TRUE if we are resynching.
+ IN USHORT Correlator, // correlator for RECEIVE_CONTINUE.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ );
+
+VOID
+ConstructSessionConfirm(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN UCHAR Options, // bitflag options, defined below.
+ IN USHORT MaximumUserBufferSize, // max size of user frame on session.
+ IN USHORT Correlator, // correlator from SESSION_INITIALIZE.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ );
+
+VOID
+ConstructSessionEnd(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN USHORT Reason, // reason for termination, defined below.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ );
+
+VOID
+ConstructSessionInitialize(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN UCHAR Options, // bitflag options, defined below.
+ IN USHORT MaximumUserBufferSize, // max size of user frame on session.
+ IN USHORT NameRecognizedCorrelator, // correlator from NAME_RECOGNIZED.
+ IN USHORT Correlator, // correlator for SESSION_CONFIRM.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ );
+
+VOID
+ConstructNoReceive(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN USHORT Options, // option bitflags, defined below.
+ IN USHORT BytesAccepted, // number of bytes accepted.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ );
+
+VOID
+ConstructReceiveOutstanding(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN USHORT BytesAccepted, // number of bytes accepted.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ );
+
+VOID
+ConstructReceiveContinue(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN USHORT Correlator, // correlator from DATA_FIRST_MIDDLE
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ );
+
+#if 0
+VOID
+ConstructSessionAlive(
+ IN PNBF_HDR_CONNECTION RawFrame // frame buffer to format.
+ );
+#endif
+
+//
+// Routines in nbfndis.c.
+//
+
+#if DBG
+PUCHAR
+NbfGetNdisStatus (
+ IN NDIS_STATUS NdisStatus
+ );
+#endif
+
+//
+// Routines in nbfdrvr.c
+//
+
+VOID
+NbfWriteResourceErrorLog(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN ULONG BytesNeeded,
+ IN ULONG ResourceId
+ );
+
+VOID
+NbfWriteGeneralErrorLog(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN ULONG DumpDataCount,
+ IN ULONG DumpData[]
+ );
+
+VOID
+NbfWriteOidErrorLog(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NTSTATUS ErrorCode,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR AdapterString,
+ IN ULONG OidValue
+ );
+
+VOID
+NbfFreeResources(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+
+extern
+ULONG
+NbfInitializeOneDeviceContext(
+ OUT PNDIS_STATUS NdisStatus,
+ IN PDRIVER_OBJECT DriverObject,
+ IN PCONFIG_DATA NbfConfig,
+ IN INT AdapterIndex
+ );
+//
+// routines in nbfcnfg.c
+//
+
+NTSTATUS
+NbfConfigureTransport (
+ IN PUNICODE_STRING RegistryPath,
+ IN PCONFIG_DATA * ConfigData
+ );
+
+//
+// Routines in nbfndis.c
+//
+
+NTSTATUS
+NbfRegisterProtocol (
+ IN PUNICODE_STRING NameString
+ );
+
+VOID
+NbfDeregisterProtocol (
+ VOID
+ );
+
+
+NTSTATUS
+NbfInitializeNdis (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PCONFIG_DATA ConfigInfo,
+ IN UINT ConfigInfoNameIndex
+ );
+
+VOID
+NbfCloseNdis (
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+
+//
+// Routines in action.c
+//
+
+NTSTATUS
+NbfTdiAction(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PIRP Irp
+ );
+
+VOID
+NbfActionQueryIndication(
+ PDEVICE_CONTEXT DeviceContext,
+ PNBF_HDR_CONNECTIONLESS UiFrame
+ );
+
+VOID
+NbfActionDatagramIndication(
+ PDEVICE_CONTEXT DeviceContext,
+ PNBF_HDR_CONNECTIONLESS UiFrame,
+ ULONG Length
+ );
+
+VOID
+NbfStopControlChannel(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN USHORT ChannelIdentifier
+ );
+
+
+//
+// Routines in nbfdebug.c
+//
+
+#if DBG
+
+VOID
+DisplayOneFrame(
+ PTP_PACKET Packet
+ );
+
+VOID
+NbfDisplayUIFrame(
+ PTP_UI_FRAME OuterFrame
+ );
+
+VOID
+NbfFormattedDump(
+ PCHAR far_p,
+ ULONG len
+ );
+
+#endif
+
+#endif // def _NBFPROCS_
diff --git a/private/ntos/tdi/nbf/nbftypes.h b/private/ntos/tdi/nbf/nbftypes.h
new file mode 100644
index 000000000..a72e9fe1b
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbftypes.h
@@ -0,0 +1,2202 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ nbftypes.h
+
+Abstract:
+
+ This module defines private data structures and types for the NT
+ NBF transport provider.
+
+Author:
+
+ David Beaver (dbeaver) 1 July 1991
+
+Revision History:
+
+--*/
+
+#ifndef _NBFTYPES_
+#define _NBFTYPES_
+
+//
+// This structure defines a NETBIOS name as a character array for use when
+// passing preformatted NETBIOS names between internal routines. It is
+// not a part of the external interface to the transport provider.
+//
+
+#define NETBIOS_NAME_SIZE 16
+
+typedef struct _NBF_NETBIOS_ADDRESS {
+ UCHAR NetbiosName[NETBIOS_NAME_SIZE];
+ USHORT NetbiosNameType;
+} NBF_NETBIOS_ADDRESS, *PNBF_NETBIOS_ADDRESS;
+
+typedef UCHAR NAME;
+typedef NAME UNALIGNED *PNAME;
+
+
+//
+// This structure defines things associated with a TP_REQUEST, or outstanding
+// TDI request, maintained on a queue somewhere in the transport. All
+// requests other than open/close require that a TP_REQUEST block be built.
+//
+
+#if DBG
+#define REQUEST_HISTORY_LENGTH 20
+extern KSPIN_LOCK NbfGlobalInterlock;
+#endif
+
+//
+// the types of potential owners of requests
+//
+
+typedef enum _REQUEST_OWNER {
+ ConnectionType,
+ AddressType,
+ DeviceContextType
+} REQUEST_OWNER;
+
+//typedef
+//NTSTATUS
+//(*PTDI_TIMEOUT_ACTION)(
+// IN PTP_REQUEST Request
+// );
+
+//
+// The request itself
+//
+
+#if DBG
+#define RREF_CREATION 0
+#define RREF_PACKET 1
+#define RREF_TIMER 2
+#define RREF_RECEIVE 3
+#define RREF_FIND_NAME 4
+#define RREF_STATUS 5
+
+#define NUMBER_OF_RREFS 8
+#endif
+
+typedef struct _TP_REQUEST {
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+ LIST_ENTRY Linkage; // used by ExInterlocked routines.
+ KSPIN_LOCK SpinLock; // spinlock for other fields.
+ // (used in KeAcquireSpinLock calls)
+#if DBG
+ LONG RefTypes[NUMBER_OF_RREFS];
+#endif
+ LONG ReferenceCount; // reasons why we can't destroy this req.
+
+ struct _DEVICE_CONTEXT *Provider; // pointer to the device context.
+ PKSPIN_LOCK ProviderInterlock; // &Provider->Interlock.
+
+ PIRP IoRequestPacket; // pointer to IRP for this request.
+
+ //
+ // The following two fields are used to quickly reference the basic
+ // components of the requests without worming through the IRP's stack.
+ //
+
+ PVOID Buffer2; // second buffer in the request.
+ ULONG Buffer2Length; // length of the second buffer.
+
+ //
+ // The following two fields (Flags and Context) are used to clean up
+ // queued requests which must be canceled or abnormally completed.
+ // The Flags field contains bitflags indicating the state of the request,
+ // and the specific queue type that the request is located on. The
+ // Context field contains a pointer to the owning structure (TP_CONNECTION
+ // or TP_ADDRESS) so that the cleanup routines can perform post-cleanup
+ // operations on the owning structure, such as dereferencing, etc.
+ //
+
+ ULONG Flags; // disposition of this request.
+ PVOID Context; // context of this request.
+ REQUEST_OWNER Owner; // what type of owner this request has.
+
+#if DBG
+ LARGE_INTEGER Time; // time when request created
+#endif
+
+ KTIMER Timer; // kernel timer for this request.
+ KDPC Dpc; // DPC object for timeouts.
+
+ //
+ // These fields are used for FIND.NAME and STATUS.QUERY requests.
+ //
+
+ ULONG Retries; // timeouts remaining.
+ USHORT BytesWritten; // usage varies.
+ USHORT FrameContext; // identifies request.
+ PVOID ResponseBuffer; // temp alloc to hold data.
+
+#if DBG
+ LIST_ENTRY GlobalLinkage;
+ ULONG TotalReferences;
+ ULONG TotalDereferences;
+ ULONG NextRefLoc;
+ struct {
+ PVOID Caller;
+ PVOID CallersCaller;
+ } History[REQUEST_HISTORY_LENGTH];
+ BOOLEAN Completed;
+ BOOLEAN Destroyed;
+#endif
+
+} TP_REQUEST, *PTP_REQUEST;
+
+#ifdef _PNP_POWER
+//
+// in nbfdrvr.c
+//
+
+extern UNICODE_STRING NbfRegistryPath;
+
+//
+// We need the driver object to create device context structures.
+//
+
+extern PDRIVER_OBJECT NbfDriverObject;
+
+#endif // _PNP_POWER
+#if DBG
+extern KSPIN_LOCK NbfGlobalHistoryLock;
+extern LIST_ENTRY NbfGlobalRequestList;
+#define StoreRequestHistory(_req,_ref) { \
+ KIRQL oldIrql; \
+ KeAcquireSpinLock (&NbfGlobalHistoryLock, &oldIrql); \
+ if ((_req)->Destroyed) { \
+ DbgPrint ("request touched after being destroyed 0x%lx\n", \
+ (_req)); \
+ DbgBreakPoint(); \
+ } \
+ RtlGetCallersAddress( \
+ &(_req)->History[(_req)->NextRefLoc].Caller, \
+ &(_req)->History[(_req)->NextRefLoc].CallersCaller \
+ ); \
+ if ((_ref)) { \
+ (_req)->TotalReferences++; \
+ } else { \
+ (_req)->TotalDereferences++; \
+ (_req)->History[(_req)->NextRefLoc].Caller = \
+ (PVOID)((ULONG)(_req)->History[(_req)->NextRefLoc].Caller & \
+ ~0x80000000); \
+ } \
+ if (++(_req)->NextRefLoc == REQUEST_HISTORY_LENGTH) { \
+ (_req)->NextRefLoc = 0; \
+ } \
+ KeReleaseSpinLock (&NbfGlobalHistoryLock, oldIrql); \
+}
+#endif
+
+#define NBF_ALLOCATION_TYPE_REQUEST 1
+
+#define REQUEST_FLAGS_TIMER 0x0001 // a timer is active for this request.
+#define REQUEST_FLAGS_TIMED_OUT 0x0002 // a timer expiration occured on this request.
+#define REQUEST_FLAGS_ADDRESS 0x0004 // request is attached to a TP_ADDRESS.
+#define REQUEST_FLAGS_CONNECTION 0x0008 // request is attached to a TP_CONNECTION.
+#define REQUEST_FLAGS_STOPPING 0x0010 // request is being killed.
+#define REQUEST_FLAGS_EOR 0x0020 // TdiSend request has END_OF_RECORD mark.
+#define REQUEST_FLAGS_PIGGYBACK 0x0040 // TdiSend that can be piggyback ack'ed.
+#define REQUEST_FLAGS_DC 0x0080 // request is attached to a TP_DEVICE_CONTEXT
+
+//
+// This defines the TP_SEND_IRP_PARAMETERS, which is masked onto the
+// Parameters section of a send IRP's stack location.
+//
+
+typedef struct _TP_SEND_IRP_PARAMETERS {
+ TDI_REQUEST_KERNEL_SEND Request;
+ LONG ReferenceCount;
+ PVOID Irp;
+} TP_SEND_IRP_PARAMETERS, *PTP_SEND_IRP_PARAMETERS;
+
+#define IRP_SEND_LENGTH(_IrpSp) \
+ (((PTP_SEND_IRP_PARAMETERS)&(_IrpSp)->Parameters)->Request.SendLength)
+
+#define IRP_SEND_FLAGS(_IrpSp) \
+ (((PTP_SEND_IRP_PARAMETERS)&(_IrpSp)->Parameters)->Request.SendFlags)
+
+#define IRP_SEND_REFCOUNT(_IrpSp) \
+ (((PTP_SEND_IRP_PARAMETERS)&(_IrpSp)->Parameters)->ReferenceCount)
+
+#define IRP_SEND_IRP(_IrpSp) \
+ (((PTP_SEND_IRP_PARAMETERS)&(_IrpSp)->Parameters)->Irp)
+
+#define IRP_SEND_CONNECTION(_IrpSp) \
+ ((PTP_CONNECTION)((_IrpSp)->FileObject->FsContext))
+
+#define IRP_DEVICE_CONTEXT(_IrpSp) \
+ ((PDEVICE_CONTEXT)((_IrpSp)->DeviceObject))
+
+
+//
+// This defines the TP_RECEIVE_IRP_PARAMETERS, which is masked onto the
+// Parameters section of a receive IRP's stack location.
+//
+
+typedef struct _TP_RECEIVE_IRP_PARAMETERS {
+ TDI_REQUEST_KERNEL_RECEIVE Request;
+ LONG ReferenceCount;
+ PIRP Irp;
+} TP_RECEIVE_IRP_PARAMETERS, *PTP_RECEIVE_IRP_PARAMETERS;
+
+#define IRP_RECEIVE_LENGTH(_IrpSp) \
+ (((PTP_RECEIVE_IRP_PARAMETERS)&(_IrpSp)->Parameters)->Request.ReceiveLength)
+
+#define IRP_RECEIVE_FLAGS(_IrpSp) \
+ (((PTP_RECEIVE_IRP_PARAMETERS)&(_IrpSp)->Parameters)->Request.ReceiveFlags)
+
+#define IRP_RECEIVE_REFCOUNT(_IrpSp) \
+ (((PTP_RECEIVE_IRP_PARAMETERS)&(_IrpSp)->Parameters)->ReferenceCount)
+
+#define IRP_RECEIVE_IRP(_IrpSp) \
+ (((PTP_RECEIVE_IRP_PARAMETERS)&(_IrpSp)->Parameters)->Irp)
+
+#define IRP_RECEIVE_CONNECTION(_IrpSp) \
+ ((PTP_CONNECTION)((_IrpSp)->FileObject->FsContext))
+
+
+
+//
+// This structure defines a TP_UI_FRAME, or connectionless frame header,
+// that is manipulated by the FRAME.C routines.
+//
+
+typedef struct _TP_UI_FRAME {
+ PNDIS_PACKET NdisPacket;
+ LIST_ENTRY Linkage; // used by ExInterLocked routines.
+ PVOID DataBuffer; // for transport-created data.
+ UCHAR Header[1]; // the header in the frame (MAC + DLC + NBF)
+} TP_UI_FRAME, *PTP_UI_FRAME;
+
+
+//
+// This structure defines a TP_VARIABLE, or network managable variable,
+// maintained in a linked list on the device context.
+//
+
+typedef struct _TP_VARIABLE {
+
+ struct _TP_VARIABLE *Fwdlink; // next variable in provider's chain.
+
+ ULONG VariableSerialNumber; // identifier for this variable.
+ ULONG VariableType; // type of this variable (see TDI.H).
+ STRING VariableName; // allocated variable name.
+
+ union {
+ ULONG LongValue;
+ HARDWARE_ADDRESS HardwareAddressValue;
+ STRING StringValue; // allocated string value, if of that type.
+ } Value;
+
+} TP_VARIABLE, *PTP_VARIABLE;
+
+
+//
+// This structure defines a TP_CONNECTION, or active transport connection,
+// maintained on a transport address.
+//
+
+#if DBG
+#define CONNECTION_HISTORY_LENGTH 50
+
+#define CREF_SPECIAL_CREATION 0
+#define CREF_SPECIAL_TEMP 1
+#define CREF_COMPLETE_SEND 2
+#define CREF_SEND_IRP 3
+#define CREF_ADM_SESS 4
+#define CREF_TRANSFER_DATA 5
+#define CREF_FRAME_SEND 6
+#define CREF_TIMER 7
+#define CREF_BY_ID 8
+#define CREF_LINK 9
+#define CREF_SESSION_END 10
+#define CREF_LISTENING 11
+#define CREF_P_LINK 12
+#define CREF_P_CONNECT 13
+#define CREF_PACKETIZE 14
+#define CREF_RECEIVE_IRP 15
+#define CREF_PROCESS_DATA 16
+#define CREF_REQUEST 17
+#define CREF_TEMP 18
+#define CREF_DATA_ACK_QUEUE 19
+#define CREF_ASSOCIATE 20
+#define CREF_STOP_ADDRESS 21
+#define CREF_PACKETIZE_QUEUE 22
+#define CREF_STALLED 23
+
+#define NUMBER_OF_CREFS 24
+#endif
+
+//
+// This structure holds our "complex send pointer" indicating
+// where we are in the packetization of a send.
+//
+
+typedef struct _TP_SEND_POINTER {
+ ULONG MessageBytesSent; // up count, bytes sent/this msg.
+ PIRP CurrentSendIrp; // ptr, current send request in chain.
+ PMDL CurrentSendMdl; // ptr, current MDL in send chain.
+ ULONG SendByteOffset; // current byte offset in current MDL.
+} TP_SEND_POINTER, *PTP_SEND_POINTER;
+
+typedef struct _TP_CONNECTION {
+
+#if DBG
+ ULONG RefTypes[NUMBER_OF_CREFS];
+#endif
+
+#if DBG
+ ULONG LockAcquired;
+ UCHAR LastAcquireFile[8];
+ ULONG LastAcquireLine;
+ ULONG Padding;
+ UCHAR LastReleaseFile[8];
+ ULONG LastReleaseLine;
+#endif
+
+ CSHORT Type;
+ USHORT Size;
+
+ LIST_ENTRY LinkList; // used for link thread or for free
+ // resource list
+ KSPIN_LOCK SpinLock; // spinlock for connection protection.
+ PKSPIN_LOCK LinkSpinLock; // pointer to link's spinlock
+
+ LONG ReferenceCount; // number of references to this object.
+ LONG SpecialRefCount; // controls freeing of connection.
+
+ //
+ // The following lists are used to associate this connection with a
+ // particular address.
+ //
+
+ LIST_ENTRY AddressList; // list of connections for given address
+ LIST_ENTRY AddressFileList; // list for connections bound to a
+ // given address reference
+
+ //
+ // The following field is used as linkage in the device context's
+ // PacketizeQueue
+ //
+
+ LIST_ENTRY PacketizeLinkage;
+
+ //
+ // The following field is used as linkage in the device context's
+ // PacketWaitQueue.
+ //
+
+ LIST_ENTRY PacketWaitLinkage;
+
+ //
+ // The following field points to the TP_LINK object that describes the
+ // (active) data link connection for this transport connection. To be
+ // valid, this field is non-NULL.
+ //
+
+ struct _TP_LINK *Link; // pointer to transport link object.
+ struct _TP_ADDRESS_FILE *AddressFile; // pointer to owning Address.
+ struct _DEVICE_CONTEXT *Provider; // device context to which we are attached.
+ PKSPIN_LOCK ProviderInterlock; // &Provider->Interlock
+ PFILE_OBJECT FileObject; // easy backlink to file object.
+
+ //
+ // The following field contains the actual ID we expose to the TDI client
+ // to represent this connection. A unique one is created from the address.
+ //
+
+ USHORT ConnectionId; // unique identifier.
+ UCHAR SessionNumber; // the session number used in the packet header
+
+ //
+ // This field is used to keep the reason for the connection disconnect
+ // around until connection deletion time.
+ //
+
+ BOOLEAN RemoteDisconnect; // was this connection remotely disonnected?
+
+ //
+ // The following field is specified by the user at connection open time.
+ // It is the context that the user associates with the connection so that
+ // indications to and from the client can be associated with a particular
+ // connection.
+ //
+
+ CONNECTION_CONTEXT Context; // client-specified value.
+
+ //
+ // The following two queues are used to associate TdiSend and TdiReceive
+ // IRPs with this connection. New arrivals are placed at the end of
+ // the queues (really a linked list) and IRPs are processed at the
+ // front of the queues. The first TdiSend IRP on the SendQueue is
+ // the current TdiSend being processed, and the first TdiReceive IRP
+ // on the ReceiveQueue is the first TdiReceive being processed, PROVIDED
+ // the CONNECTION_FLAGS_ACTIVE_RECEIVE flag is set. If this flag is not
+ // set, then the first TdiReceive IRP on the ReceiveQueue is not active.
+ // These queues are managed by the EXECUTIVE interlocked list manipuation
+ // routines.
+ //
+
+ LIST_ENTRY SendQueue; // FIFO of outstanding TdiSends.
+ LIST_ENTRY ReceiveQueue; // FIFO of outstanding TdiReceives.
+
+ //
+ // The following fields are used to maintain state for the current receive.
+ //
+
+ ULONG MessageBytesReceived; // up count, bytes recd/this msg.
+ ULONG MessageBytesAcked; // bytes acked (NR or RO) this msg.
+ ULONG MessageInitAccepted; // bytes accepted during indication.
+
+ //
+ // These fields are only valid if the CONNECTION_FLAGS_ACTIVE_RECEIVE
+ // flag is set.
+ //
+
+ PIRP SpecialReceiveIrp; // a "no-request" receive IRP exists.
+ PIRP CurrentReceiveIrp; // ptr, current receive IRP.
+ PMDL CurrentReceiveMdl; // ptr, current MDL in receive chain.
+ ULONG ReceiveByteOffset; // current byte offset in current MDL.
+ ULONG ReceiveLength; // current receive length, in bytes (total)
+ ULONG ReceiveBytesUnaccepted; // by client...only indicate when == 0
+
+ //
+ // The following fields are used to maintain state for the active send.
+ // They only have meaning if the connection's SendState is not IDLE.
+ // Because the TDI client may submit multiple TdiSend requests to comprise
+ // a full message, we have to keep a complex pointer to the first byte of
+ // unACKed data (hence the first three fields). We also have a complex
+ // pointer to the first byte of unsent data (hence the last three fields).
+ //
+
+ ULONG SendState; // send state machine variable.
+
+ PIRP FirstSendIrp; // ptr, 1st TdiSend's IRP.
+ PMDL FirstSendMdl; // ptr, 1st unacked MDL in chain/this msg.
+ ULONG FirstSendByteOffset; // pre-acked bytes in that MDL.
+
+ TP_SEND_POINTER sp; // current send loc, defined above.
+ ULONG CurrentSendLength; // how long is this send (total)
+ ULONG StallCount; // times in a row we looked stalled.
+ ULONG StallBytesSent; // bytes sent last time we checked.
+
+ //
+ // This is TRUE if we need don't need to reference the current
+ // receive IRP during transfers (because it is a special
+ // receive or the driver doesn't pend transfers).
+ //
+
+ BOOLEAN CurrentReceiveSynchronous;
+
+ //
+ // This field will be TRUE if the last DOL received allowed
+ // piggyback acks.
+ //
+
+ BOOLEAN CurrentReceiveAckQueueable;
+
+ //
+ //
+ // This field will be TRUE if the last DOL received was
+ // sent NO.ACK.
+ //
+
+ BOOLEAN CurrentReceiveNoAck;
+
+ //
+ // These fields handle asynchronous TransferData calls.
+ //
+
+ ULONG TransferBytesPending; // bytes pending in current transfers
+ ULONG TotalTransferBytesPending; // bytes since TransferBytesPending was 0;
+ // how much we back off if a transfer fails
+ PMDL SavedCurrentReceiveMdl; // used to back off by TotalTransferPending bytes
+ ULONG SavedReceiveByteOffset; // used to back off by TotalTransferPending bytes
+
+ //
+ // This field will be TRUE if we are in the middle of
+ // processing a receive indication on this connection and
+ // we are not yet in a state where another indication
+ // can be handled.
+ //
+ // It is stored as a INT since access to it is guarded
+ // by the connection's link spinlock, unlike the variables
+ // around it (BUGBUG: What about Alpha?)
+ //
+
+ UINT IndicationInProgress;
+
+ //
+ // The following field is used as a linkage when on the device
+ // context's DataAckQueue.
+ //
+
+ LIST_ENTRY DataAckLinkage;
+
+ //
+ // TRUE if the connection is on the data ack queue.
+ // Also an INT so access can be non-guarded.
+ //
+
+ UINT OnDataAckQueue;
+
+ //
+ // These keep track of the number of consecutive sends or
+ // receives on this connection. This is used in determining when
+ // to queue a data ack.
+ //
+
+ ULONG ConsecutiveSends;
+ ULONG ConsecutiveReceives;
+
+ //
+ // The following list head is used as a pointer to a TdiListen/TdiConnect
+ // request which is in progress. Although manipulated
+ // with queue instructions, there will only be one request in the queue.
+ // This is done for consistency with respect to TpCreateRequest, which
+ // does a great job of creating a request and associating it atomically
+ // with a supervisory object.
+ //
+
+ LIST_ENTRY InProgressRequest; // TdiListen/TdiConnect
+
+ //
+ // If the connection is being disconnected as a result of
+ // a TdiDisconnect call (RemoteDisconnect is FALSE) then this
+ // will hold the IRP passed to TdiDisconnect. It is needed
+ // when the TdiDisconnect request is completed.
+ //
+
+ PIRP DisconnectIrp;
+
+ //
+ // If the connection is being closed, this will hold
+ // the IRP passed to TdiCloseConnection. It is needed
+ // when the request is completed.
+ //
+
+ PIRP CloseIrp;
+
+ //
+ // These fields are used for deferred operations on connections; the only
+ // deferred operation currently supported is piggyback ACK
+ //
+
+ ULONG DeferredFlags;
+#if DBG
+ ULONG DeferredPasses;
+#endif
+ LIST_ENTRY DeferredQueue;
+
+ //
+ // The following fields are used for connection housekeeping.
+ //
+
+ ULONG Flags; // attributes guarded by LinkSpinLock
+ ULONG Flags2; // attributes guarded by SpinLock
+ UINT OnPacketWaitQueue; // TRUE if on PacketWaitQueue
+ UCHAR Lsn; // local session number (1-254).
+ UCHAR Rsn; // remote session number (1-254).
+ USHORT Retries; // retry limit for NAME_QUERY shipments.
+ KTIMER Timer; // kernel timer for timeouts on NQ/NR.
+ LARGE_INTEGER ConnectStartTime; // when we sent the committed NQ.
+ KDPC Dpc; // DPC object for timeouts.
+ NTSTATUS Status; // status code for connection rundown.
+ ULONG LastPacketsSent; // The value that was in Link->XXX the
+ ULONG LastPacketsResent; // last time we calculated the throughput.
+ NBF_NETBIOS_ADDRESS CalledAddress; // TdiConnect request's T.A.
+ USHORT MaximumDataSize; // maximum I-frame data size for NBF.
+
+ NBF_HDR_CONNECTION NetbiosHeader; // pre-built Netbios header; we store
+ // the current send and reply correlators
+ // in the appropriate spots in this.
+
+ //
+ // These are for CONNECTION_INFO queries.
+ //
+
+ ULONG TransmittedTsdus; // TSDUs sent on this connection.
+ ULONG ReceivedTsdus; // TSDUs received on this connection.
+ ULONG TransmissionErrors; // TSDUs transmitted in error/this connection.
+ ULONG ReceiveErrors; // TSDUs received in error/this connection.
+
+ //
+ // The following structure contains statistics counters for use
+ // by TdiQueryInformation and TdiSetInformation. They should not
+ // be used for maintenance of internal data structures.
+ //
+
+ // TDI_CONNECTION_INFO Information; // information about this connection.
+
+#if DBG
+ LIST_ENTRY GlobalLinkage;
+ ULONG TotalReferences;
+ ULONG TotalDereferences;
+ ULONG NextRefLoc;
+ struct {
+ PVOID Caller;
+ PVOID CallersCaller;
+ } History[CONNECTION_HISTORY_LENGTH];
+ BOOLEAN Destroyed;
+#endif
+ CHAR RemoteName[16];
+
+} TP_CONNECTION, *PTP_CONNECTION;
+
+#if DBG
+extern KSPIN_LOCK NbfGlobalHistoryLock;
+extern LIST_ENTRY NbfGlobalConnectionList;
+#define StoreConnectionHistory(_conn,_ref) { \
+ KIRQL oldIrql; \
+ KeAcquireSpinLock (&NbfGlobalHistoryLock, &oldIrql); \
+ if ((_conn)->Destroyed) { \
+ DbgPrint ("connection touched after being destroyed 0x%lx\n", \
+ (_conn)); \
+ DbgBreakPoint(); \
+ } \
+ RtlGetCallersAddress( \
+ &(_conn)->History[(_conn)->NextRefLoc].Caller, \
+ &(_conn)->History[(_conn)->NextRefLoc].CallersCaller \
+ ); \
+ if ((_ref)) { \
+ (_conn)->TotalReferences++; \
+ } else { \
+ (_conn)->TotalDereferences++; \
+ (_conn)->History[(_conn)->NextRefLoc].Caller = \
+ (PVOID)((ULONG)(_conn)->History[(_conn)->NextRefLoc].Caller | 1); \
+ } \
+ if (++(_conn)->NextRefLoc == CONNECTION_HISTORY_LENGTH) { \
+ (_conn)->NextRefLoc = 0; \
+ } \
+ KeReleaseSpinLock (&NbfGlobalHistoryLock, oldIrql); \
+}
+#endif
+
+#define CONNECTION_FLAGS_VERSION2 0x00000001 // remote netbios is version 2.0.
+#define CONNECTION_FLAGS_RECEIVE_WAKEUP 0x00000002 // send a RECEIVE_OUTSTANDING when a receive arrives.
+#define CONNECTION_FLAGS_ACTIVE_RECEIVE 0x00000004 // a receive is active.
+#define CONNECTION_FLAGS_WAIT_SI 0x00000020 // waiting for a SESSION_INITIALIZE.
+#define CONNECTION_FLAGS_WAIT_SC 0x00000040 // waiting for a SESSION_CONFIRM.
+#define CONNECTION_FLAGS_WAIT_LINK_UP 0x00000080 // waiting for DDI to est. connection.
+#define CONNECTION_FLAGS_READY 0x00000200 // sends/rcvs/discons valid.
+#define CONNECTION_FLAGS_RC_PENDING 0x00001000 // a receive is pending completion
+#define CONNECTION_FLAGS_W_PACKETIZE 0x00002000 // w/for a packet to packetize.
+#define CONNECTION_FLAGS_PACKETIZE 0x00004000 // we're on the PacketizeQueue.
+#define CONNECTION_FLAGS_W_RESYNCH 0x00008000 // waiting for resynch indicator. (receive)
+#define CONNECTION_FLAGS_SEND_SI 0x00010000 // w/for a packet to send SI.
+#define CONNECTION_FLAGS_SEND_SC 0x00020000 // w/for a packet to send SC.
+#define CONNECTION_FLAGS_SEND_DA 0x00040000 // w/for a packet to send DA.
+#define CONNECTION_FLAGS_SEND_RO 0x00080000 // w/for a packet to send RO.
+#define CONNECTION_FLAGS_SEND_RC 0x00100000 // w/for a packet to send RC.
+#define CONNECTION_FLAGS_SEND_SE 0x00200000 // w/for a packet to send SE.
+#define CONNECTION_FLAGS_SEND_NR 0x00400000 // w/for a packet to send NR.
+#define CONNECTION_FLAGS_NO_INDICATE 0x00800000 // don't take packets at indication time
+#define CONNECTION_FLAGS_FAILING_TO_EOR 0x01000000 // wait for an EOF in an incoming request before sending
+#define CONNECTION_FLAGS_RESYNCHING 0x02000000 // engaged send side resynch
+#define CONNECTION_FLAGS_RCV_CANCELLED 0x10000000 // current receive was cancelled
+#define CONNECTION_FLAGS_PEND_INDICATE 0x20000000 // new data received during RC_PENDING
+#define CONNECTION_FLAGS_TRANSFER_FAIL 0x40000000 // a transfer data call failed
+
+#define CONNECTION_FLAGS2_STOPPING 0x00000001 // connection is running down.
+#define CONNECTION_FLAGS2_WAIT_NR 0x00000002 // waiting for NAME_RECOGNIZED.
+#define CONNECTION_FLAGS2_WAIT_NQ 0x00000004 // waiting for NAME_QUERY.
+#define CONNECTION_FLAGS2_WAIT_NR_FN 0x00000008 // waiting for FIND NAME response.
+#define CONNECTION_FLAGS2_CLOSING 0x00000010 // connection is closing
+#define CONNECTION_FLAGS2_ASSOCIATED 0x00000020 // associated with address
+#define CONNECTION_FLAGS2_DISCONNECT 0x00000040 // disconnect done on connection
+#define CONNECTION_FLAGS2_ACCEPTED 0x00000080 // accept done on connection
+#define CONNECTION_FLAGS2_REQ_COMPLETED 0x00000100 // Listen/Connect request completed.
+#define CONNECTION_FLAGS2_DISASSOCIATED 0x00000200 // associate CRef has been removed
+#define CONNECTION_FLAGS2_DISCONNECTED 0x00000400 // disconnect has been indicated
+#define CONNECTION_FLAGS2_NO_LISTEN 0x00000800 // no_listen received during setup
+#define CONNECTION_FLAGS2_REMOTE_VALID 0x00001000 // Connection->RemoteName is valid
+#define CONNECTION_FLAGS2_GROUP_LSN 0x00002000 // connection LSN is globally assigned
+#define CONNECTION_FLAGS2_W_ADDRESS 0x00004000 // waiting for address reregistration.
+#define CONNECTION_FLAGS2_PRE_ACCEPT 0x00008000 // no TdiAccept after listen completes
+#define CONNECTION_FLAGS2_ABORT 0x00010000 // abort this connection.
+#define CONNECTION_FLAGS2_ORDREL 0x00020000 // we're in orderly release.
+#define CONNECTION_FLAGS2_DESTROY 0x00040000 // destroy this connection.
+#define CONNECTION_FLAGS2_LISTENER 0x00100000 // we were the passive listener.
+#define CONNECTION_FLAGS2_CONNECTOR 0x00200000 // we were the active connector.
+#define CONNECTION_FLAGS2_WAITING_SC 0x00400000 // the connection is waiting for
+ // and accept to send the
+ // session confirm
+#define CONNECTION_FLAGS2_INDICATING 0x00800000 // connection was manipulated while
+ // indication was in progress
+
+#define CONNECTION_FLAGS2_LDISC 0x01000000 // Local disconnect req.
+#ifdef RASAUTODIAL
+#define CONNECTION_FLAGS2_AUTOCONNECTING 0x02000000 // RAS autodial in progress
+#define CONNECTION_FLAGS2_AUTOCONNECTED 0x04000000 // RAS autodial done
+#endif // RASAUTODIAL
+
+#define CONNECTION_FLAGS_STARVED ( \
+ CONNECTION_FLAGS_SEND_SI | \
+ CONNECTION_FLAGS_SEND_SC | \
+ CONNECTION_FLAGS_SEND_DA | \
+ CONNECTION_FLAGS_SEND_RO | \
+ CONNECTION_FLAGS_SEND_RC | \
+ CONNECTION_FLAGS_SEND_NR | \
+ CONNECTION_FLAGS_SEND_SE \
+ )
+
+#define CONNECTION_FLAGS_DEFERRED_ACK 0x00000001 // send piggyback ack first opportunity
+#define CONNECTION_FLAGS_DEFERRED_ACK_2 0x00000002 // deferred ack wasn't sent
+#define CONNECTION_FLAGS_DEFERRED_NOT_Q 0x00000004 // DEFERRED_ACK set, but not on DataAckQueue
+#define CONNECTION_FLAGS_DEFERRED_SENDS 0x80000000 // print completed sends
+
+#define CONNECTION_SENDSTATE_IDLE 0 // no sends being processed.
+#define CONNECTION_SENDSTATE_PACKETIZE 1 // send being packetized.
+#define CONNECTION_SENDSTATE_W_PACKET 2 // waiting for free packet.
+#define CONNECTION_SENDSTATE_W_LINK 3 // waiting for good link conditions.
+#define CONNECTION_SENDSTATE_W_EOR 4 // waiting for TdiSend(EOR).
+#define CONNECTION_SENDSTATE_W_ACK 5 // waiting for DATA_ACK.
+#define CONNECTION_SENDSTATE_W_RCVCONT 6 // waiting for RECEIVE_CONTINUE.
+
+
+//
+// This structure is pointed to by the FsContext field in the FILE_OBJECT
+// for this Address. This structure is the base for all activities on
+// the open file object within the transport provider. All active connections
+// on the address point to this structure, although no queues exist here to do
+// work from. This structure also maintains a reference to a TP_ADDRESS
+// structure, which describes the address that it is bound to. Thus, a
+// connection will point to this structure, which describes the address the
+// connection was associated with. When the address file closes, all connections
+// opened on this address file get closed, too. Note that this may leave an
+// address hanging around, with other references.
+//
+
+typedef struct _TP_ADDRESS_FILE {
+
+ CSHORT Type;
+ CSHORT Size;
+
+ LIST_ENTRY Linkage; // next address file on this address.
+ // also used for linkage in the
+ // look-aside list
+
+ LONG ReferenceCount; // number of references to this object.
+
+ //
+ // This structure is edited after taking the Address spinlock for the
+ // owning address. This ensures that the address and this structure
+ // will never get out of syncronization with each other.
+ //
+
+ //
+ // The following field points to a list of TP_CONNECTION structures,
+ // one per connection open on this address. This list of connections
+ // is used to help the cleanup process if a process closes an address
+ // before disassociating all connections on it. By design, connections
+ // will stay around until they are explicitly
+ // closed; we use this database to ensure that we clean up properly.
+ //
+
+ LIST_ENTRY ConnectionDatabase; // list of defined transport connections.
+
+ //
+ // the current state of the address file structure; this is either open or
+ // closing
+ //
+
+ UCHAR State;
+
+ //
+ // The following fields are kept for housekeeping purposes.
+ //
+
+ PIRP Irp; // the irp used for open or close
+ struct _TP_ADDRESS *Address; // address to which we are bound.
+ PFILE_OBJECT FileObject; // easy backlink to file object.
+ struct _DEVICE_CONTEXT *Provider; // device context to which we are attached.
+
+ //
+ // The following queue is used to queue receive datagram requests
+ // on this address file. Send datagram requests are queued on the
+ // address itself. These queues are managed by the EXECUTIVE interlocked
+ // list management routines. The actual objects which get queued to this
+ // structure are request control blocks (RCBs).
+ //
+
+ LIST_ENTRY ReceiveDatagramQueue; // FIFO of outstanding TdiReceiveDatagrams.
+
+ //
+ // This holds the Irp used to close this address file,
+ // for pended completion.
+ //
+
+ PIRP CloseIrp;
+
+ //
+ // is this address file currently indicating a connection request? if yes, we
+ // need to mark connections that are manipulated during this time.
+ //
+
+ BOOLEAN ConnectIndicationInProgress;
+
+ //
+ // handler for kernel event actions. First we have a set of booleans that
+ // indicate whether or not this address has an event handler of the given
+ // type registered.
+ //
+
+ BOOLEAN RegisteredConnectionHandler;
+ BOOLEAN RegisteredDisconnectHandler;
+ BOOLEAN RegisteredReceiveHandler;
+ BOOLEAN RegisteredReceiveDatagramHandler;
+ BOOLEAN RegisteredExpeditedDataHandler;
+ BOOLEAN RegisteredErrorHandler;
+
+ //
+ // This function pointer points to a connection indication handler for this
+ // Address. Any time a connect request is received on the address, this
+ // routine is invoked.
+ //
+ //
+
+ PTDI_IND_CONNECT ConnectionHandler;
+ PVOID ConnectionHandlerContext;
+
+ //
+ // The following function pointer always points to a TDI_IND_DISCONNECT
+ // handler for the address. If the NULL handler is specified in a
+ // TdiSetEventHandler, this this points to an internal routine which
+ // simply returns successfully.
+ //
+
+ PTDI_IND_DISCONNECT DisconnectHandler;
+ PVOID DisconnectHandlerContext;
+
+ //
+ // The following function pointer always points to a TDI_IND_RECEIVE
+ // event handler for connections on this address. If the NULL handler
+ // is specified in a TdiSetEventHandler, then this points to an internal
+ // routine which does not accept the incoming data.
+ //
+
+ PTDI_IND_RECEIVE ReceiveHandler;
+ PVOID ReceiveHandlerContext;
+
+ //
+ // The following function pointer always points to a TDI_IND_RECEIVE_DATAGRAM
+ // event handler for the address. If the NULL handler is specified in a
+ // TdiSetEventHandler, this this points to an internal routine which does
+ // not accept the incoming data.
+ //
+
+ PTDI_IND_RECEIVE_DATAGRAM ReceiveDatagramHandler;
+ PVOID ReceiveDatagramHandlerContext;
+
+ //
+ // An expedited data handler. This handler is used if expedited data is
+ // expected; it never is in NBF, thus this handler should always point to
+ // the default handler.
+ //
+
+ PTDI_IND_RECEIVE_EXPEDITED ExpeditedDataHandler;
+ PVOID ExpeditedDataHandlerContext;
+
+ //
+ // The following function pointer always points to a TDI_IND_ERROR
+ // handler for the address. If the NULL handler is specified in a
+ // TdiSetEventHandler, this this points to an internal routine which
+ // simply returns successfully.
+ //
+
+ PTDI_IND_ERROR ErrorHandler;
+ PVOID ErrorHandlerContext;
+ PVOID ErrorHandlerOwner;
+
+
+} TP_ADDRESS_FILE, *PTP_ADDRESS_FILE;
+
+#define ADDRESSFILE_STATE_OPENING 0x00 // not yet open for business
+#define ADDRESSFILE_STATE_OPEN 0x01 // open for business
+#define ADDRESSFILE_STATE_CLOSING 0x02 // closing
+
+
+//
+// This structure defines a TP_ADDRESS, or active transport address,
+// maintained by the transport provider. It contains all the visible
+// components of the address (such as the TSAP and network name components),
+// and it also contains other maintenance parts, such as a reference count,
+// ACL, and so on. All outstanding connection-oriented and connectionless
+// data transfer requests are queued here.
+//
+
+#if DBG
+#define AREF_TIMER 0
+#define AREF_TEMP_CREATE 1
+#define AREF_OPEN 2
+#define AREF_VERIFY 3
+#define AREF_LOOKUP 4
+#define AREF_FRAME_SEND 5
+#define AREF_CONNECTION 6
+#define AREF_TEMP_STOP 7
+#define AREF_REQUEST 8
+#define AREF_PROCESS_UI 9
+#define AREF_PROCESS_DATAGRAM 10
+#define AREF_TIMER_SCAN 11
+
+#define NUMBER_OF_AREFS 12
+#endif
+
+typedef struct _TP_ADDRESS {
+
+#if DBG
+ ULONG RefTypes[NUMBER_OF_AREFS];
+#endif
+
+ USHORT Size;
+ CSHORT Type;
+
+ LIST_ENTRY Linkage; // next address/this device object.
+ LONG ReferenceCount; // number of references to this object.
+
+ //
+ // The following spin lock is acquired to edit this TP_ADDRESS structure
+ // or to scan down or edit the list of address files.
+ //
+
+ KSPIN_LOCK SpinLock; // lock to manipulate this structure.
+
+ //
+ // The following fields comprise the actual address itself.
+ //
+
+ PIRP Irp; // pointer to address creation IRP.
+ PNBF_NETBIOS_ADDRESS NetworkName; // this address
+
+ //
+ // The following fields are used to maintain state about this address.
+ //
+
+ ULONG Flags; // attributes of the address.
+ struct _DEVICE_CONTEXT *Provider; // device context to which we are attached.
+
+ //
+ // The following queues is used to hold send datagrams for this
+ // address. Receive datagrams are queued to the address file. Requests are
+ // processed in a first-in, first-out manner, so that the very next request
+ // to be serviced is always at the head of its respective queue. These
+ // queues are managed by the EXECUTIVE interlocked list management routines.
+ // The actual objects which get queued to this structure are request control
+ // blocks (RCBs).
+ //
+
+ LIST_ENTRY SendDatagramQueue; // FIFO of outstanding TdiSendDatagrams.
+
+ //
+ // The following field points to a list of TP_CONNECTION structures,
+ // one per active, connecting, or disconnecting connections on this
+ // address. By definition, if a connection is on this list, then
+ // it is visible to the client in terms of receiving events and being
+ // able to post requests by naming the ConnectionId. If the connection
+ // is not on this list, then it is not valid, and it is guaranteed that
+ // no indications to the client will be made with reference to it, and
+ // no requests specifying its ConnectionId will be accepted by the transport.
+ //
+
+ LIST_ENTRY ConnectionDatabase; // list of defined transport connections.
+ LIST_ENTRY AddressFileDatabase; // list of defined address file objects
+
+ //
+ // The packet pool of size 1 that holds the UI frame, and the
+ // frame that is allocated out of it.
+ //
+
+ NDIS_HANDLE UIFramePoolHandle;
+ PTP_UI_FRAME UIFrame; // DLC-UI/NBF header for datagram sends.
+
+ //
+ // The following fields are used to register this address on the network.
+ //
+
+ ULONG Retries; // retries of ADD_NAME_QUERY left to go.
+ KTIMER Timer; // kernel timer for timeouts on ANQ/ANR.
+ KDPC Dpc; // DPC object for timeout.
+
+ //
+ // These two can be a union because they are not used
+ // concurrently.
+ //
+
+ union {
+
+ //
+ // This structure is used for checking share access.
+ //
+
+ SHARE_ACCESS ShareAccess;
+
+ //
+ // Used for delaying NbfDestroyAddress to a thread so
+ // we can access the security descriptor.
+ //
+
+ WORK_QUEUE_ITEM DestroyAddressQueueItem;
+
+ } u;
+
+ //
+ // This structure is used to hold ACLs on the address.
+
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+
+ //
+ // If we get an ADD_NAME_RESPONSE frame, this holds the address
+ // of the remote we got it from (used to check for duplicate names).
+ //
+
+ UCHAR UniqueResponseAddress[6];
+
+ //
+ // Set to TRUE once we send a name in conflict frame, so that
+ // we don't flood the network with them on every response.
+ //
+
+ BOOLEAN NameInConflictSent;
+
+} TP_ADDRESS, *PTP_ADDRESS;
+
+#define ADDRESS_FLAGS_GROUP 0x00000001 // set if group, otherwise unique.
+#define ADDRESS_FLAGS_CONFLICT 0x00000002 // address in conflict detected.
+#define ADDRESS_FLAGS_REGISTERING 0x00000004 // registration in progress.
+#define ADDRESS_FLAGS_DEREGISTERING 0x00000008 // deregistration in progress.
+#define ADDRESS_FLAGS_DUPLICATE_NAME 0x00000010 // duplicate name was found on net.
+#define ADDRESS_FLAGS_NEEDS_REG 0x00000020 // address must be registered.
+#define ADDRESS_FLAGS_STOPPING 0x00000040 // TpStopAddress is in progress.
+#define ADDRESS_FLAGS_BAD_ADDRESS 0x00000080 // name in conflict on associated address.
+#define ADDRESS_FLAGS_SEND_IN_PROGRESS 0x00000100 // send datagram process active.
+#define ADDRESS_FLAGS_CLOSED 0x00000200 // address has been closed;
+ // existing activity can
+ // complete, nothing new can start
+#define ADDRESS_FLAGS_NEED_REREGISTER 0x00000400 // quick-reregister on next connect.
+#define ADDRESS_FLAGS_QUICK_REREGISTER 0x00000800 // address is quick-reregistering.
+
+
+//
+// This structure defines a TP_LINK, or established data link object,
+// maintained by the transport provider. Each data link connection with
+// a remote machine is represented by this object. Zero, one, or several
+// transport connections can be multiplexed over the same data link connection.
+// This object is managed by routines in LINK.C.
+//
+
+#if DBG
+#define LREF_SPECIAL_CONN 0
+#define LREF_SPECIAL_TEMP 1
+#define LREF_CONNECTION 2
+#define LREF_STOPPING 3
+#define LREF_START_T1 4
+#define LREF_TREE 5
+#define LREF_NOT_ADM 6
+#define LREF_NDIS_SEND 7
+
+#define NUMBER_OF_LREFS 8
+#endif
+
+#if DBG
+#define LINK_HISTORY_LENGTH 20
+#endif
+
+typedef struct _TP_LINK {
+
+ RTL_SPLAY_LINKS SplayLinks; // for the link splay tree
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+#if DBG
+ ULONG RefTypes[NUMBER_OF_LREFS];
+#endif
+
+ LIST_ENTRY Linkage; // for list of free links or deferred
+ // operation queue
+ KSPIN_LOCK SpinLock; // lock to manipulate this structure.
+
+ LONG ReferenceCount; // number of references to this object.
+ LONG SpecialRefCount; // controls freeing of the link.
+
+ //
+ // information about the remote hardware this link is talking to.
+ //
+
+ BOOLEAN Loopback; // TRUE if this is a loopback link.
+ UCHAR LoopbackDestinationIndex; // if Loopback, the index.
+
+ HARDWARE_ADDRESS HardwareAddress; // hardware address of remote.
+ ULARGE_INTEGER MagicAddress; // numerical representation of the
+ // hardware address used for quick
+ // comparisons
+ UCHAR Header[MAX_MAC_HEADER_LENGTH]; // a place to stick a prebuilt packet
+ // header.
+ ULONG HeaderLength; // length of Header for this link
+
+ //
+ // Vital conditions surrounding the data link connnection.
+ //
+
+ ULONG MaxFrameSize; // maximum size of NetBIOS frame, MAC
+ // dependent.
+
+ //
+ // Connections associated with this link. We keep a simple list of
+ // connections because it's unlikely we'll get more than a few connections
+ // on a given link (we're assuming that the server or redir will be the
+ // biggest user of the net in the vast majority of environments). We've
+ // made the link lookup be via a splay tree, which vastly speeds the
+ // process of getting to the proper link; as long as there are only a few
+ // connections, the connection lookup will be fast. If this becomes a
+ // problem down the road, we can make this connection list be a splay tree
+ // also.
+ //
+
+ LIST_ENTRY ConnectionDatabase;
+ ULONG ActiveConnectionCount; // # connections in above list.
+
+ //
+ // The following fields are used to maintain state about this link.
+ // One other field is implicit-- the address of this object is the
+ // ConnectionContext value as described in the PDI spec.
+ //
+
+ ULONG Flags; // attributes of the link.
+ ULONG DeferredFlags; // when on the deferred queue.
+ ULONG State; // link state variable.
+
+ //
+ // Send-side state.
+ //
+
+ ULONG PacketsSent; // number of packets sent.
+ ULONG PacketsResent; // number of packets resent.
+ UCHAR SendState; // send-side state variable.
+ UCHAR NextSend; // next N(S) we should send.
+ UCHAR LastAckReceived; // last N(R) we received.
+ UCHAR SendWindowSize; // current send window size.
+ UCHAR PrevWindowSize; // size last time we dropped a frame.
+ UCHAR WindowsUntilIncrease; // how many windows until size increases.
+ UCHAR SendRetries; // number of retries left/this checkpoint.
+ UCHAR ConsecutiveLastPacketLost; // consecutive windows with last packet dropped.
+ ULONG NdisSendsInProgress; // >0 if sends queued to NdisSendQueue.
+ LIST_ENTRY NdisSendQueue; // queue of sends to pass to NdisSend.
+ LIST_ENTRY WackQ; // sent packets waiting LLC acks.
+
+ BOOLEAN OnDeferredRrQueue;
+ LIST_ENTRY DeferredRrLinkage;
+
+ //
+ // Receive-side state.
+ //
+
+ ULONG PacketsReceived; // number of packets received.
+ UCHAR ReceiveState; // receive-side state variable.
+ UCHAR NextReceive; // next expected N(S) we should receive.
+ UCHAR LastAckSent; // last N(R) we sent.
+ UCHAR ReceiveWindowSize; // current receive window size.
+ BOOLEAN RespondToPoll; // remote guy is polling-- we must final.
+ BOOLEAN ResendingPackets; // ResendLlcPackets in progress
+ BOOLEAN LinkBusy; // received RNR (really send-side state).
+
+ //
+ // Timer, used to determine delay and throughput.
+ //
+
+ ULONG Delay; // an NT time, but only LowPart is saved.
+ LARGE_INTEGER Throughput;
+
+ //
+ // These are counters needed by ADAPTER_STATUS queries.
+ //
+
+ USHORT FrmrsReceived;
+ USHORT FrmrsTransmitted;
+ USHORT ErrorIFramesReceived;
+ USHORT ErrorIFramesTransmitted;
+ USHORT AbortedTransmissions;
+ USHORT BuffersNotAvailable;
+ ULONG SuccessfulTransmits;
+ ULONG SuccessfulReceives;
+ USHORT T1Expirations;
+ USHORT TiExpirations;
+
+ //
+ // Timeout state. There is one kernel timer for this transport that is set
+ // to go off at regular intervals. This timer increments the current time,
+ // which is then used to compare against the timer queues. The timer queues
+ // are ordered, so whenever the first element is not expired, the rest of
+ // the queue is not expired. This allows us to have hundreds of timers
+ // running with very little system overhead.
+ // A value of 0 indicates that the timer is not active.
+ //
+
+ ULONG T1; // retry timer.
+ ULONG T2; // delayed ack timer.
+ ULONG Ti; // inactivity timer.
+ BOOLEAN OnShortList; // TRUE if link is in ShortList
+ BOOLEAN OnLongList; // TRUE if link is in LongList
+ LIST_ENTRY ShortList; // list of links waiting t1 or t2
+ LIST_ENTRY LongList; // list of links waiting ti
+
+ LIST_ENTRY PurgeList;
+
+ //
+ // This counter is used to keep track of whether there are
+ // any "connectors" (connections initiated by this side) on
+ // this link. If there are none, and we are on an easily
+ // disconnected link, then we handle the inactivity timeout
+ // differently.
+ //
+
+ LONG NumberOfConnectors;
+
+ //
+ // BaseT1Timeout is the current T1 timeout computed based on
+ // the response to previous poll frames. T1Timeout is the
+ // value to be used for the next T1, and will generally be
+ // based on BaseT1Timeout but may be more if T1 is backing
+ // off. T2Timeout and TiTimeout are independent of these.
+ //
+
+ ULONG BaseT1Timeout; // Timeout value for T1, << 16.
+ ULONG CurrentT1Timeout; // Current backed-off T1 timeout.
+ ULONG MinimumBaseT1Timeout; // Minimum value, based on link speed.
+ ULONG BaseT1RecalcThreshhold; // Only recalc BaseT1 on frames > this.
+ ULONG CurrentPollRetransmits; // Current retransmits waiting for final.
+ BOOLEAN ThroughputAccurate; // Is the throughput on this link accurate?
+ BOOLEAN CurrentT1Backoff; // the last poll frame had retransmits
+ BOOLEAN CurrentPollOutstanding; // Check that we have a poll outstanding.
+ LARGE_INTEGER CurrentTimerStart; // Time that current timing was begun.
+ ULONG CurrentPollSize; // Size of current poll packet.
+ ULONG T2Timeout; // Timeout value for T2.
+ ULONG TiTimeout; // Timeout value for Ti.
+ ULONG LlcRetries; // total retry count for this link.
+ ULONG MaxWindowSize; // maximum send window size.
+ ULONG TiStartPacketsReceived; // PacketsReceived when Ti was started.
+
+ //
+ // Adaptive window algorithm state.
+ //
+
+ ULONG WindowErrors; // # retransmissions/this adaptive run.
+ UCHAR BestWindowSize; // our best window from experience.
+ UCHAR WorstWindowSize; // our worst window from experience.
+
+ //
+ // Keep track of remotes that never poll so we can send
+ // an RR every two frames.
+ //
+
+ BOOLEAN RemoteNoPoll; // We think remote doesn't poll
+ UCHAR ConsecutiveIFrames; // number received since polling
+
+#if DBG
+ UCHAR CreatePacketFailures; // consecutive failures
+#endif
+
+ LIST_ENTRY DeferredList; // for threading on deferred list
+
+ struct _DEVICE_CONTEXT *Provider;
+ PKSPIN_LOCK ProviderInterlock; // &Provider->Interlock
+
+#if DBG
+ LIST_ENTRY GlobalLinkage;
+ ULONG TotalReferences;
+ ULONG TotalDereferences;
+ ULONG NextRefLoc;
+ struct {
+ PVOID Caller;
+ PVOID CallersCaller;
+ } History[LINK_HISTORY_LENGTH];
+ BOOLEAN Destroyed;
+#endif
+
+} TP_LINK, *PTP_LINK;
+
+#if DBG
+extern KSPIN_LOCK NbfGlobalHistoryLock;
+extern LIST_ENTRY NbfGlobalLinkList;
+#define StoreLinkHistory(_link,_ref) { \
+ KIRQL oldIrql; \
+ KeAcquireSpinLock (&NbfGlobalHistoryLock, &oldIrql); \
+ if ((_link)->Destroyed) { \
+ DbgPrint ("link touched after being destroyed 0x%lx\n", (_link)); \
+ DbgBreakPoint(); \
+ } \
+ RtlGetCallersAddress( \
+ &(_link)->History[(_link)->NextRefLoc].Caller, \
+ &(_link)->History[(_link)->NextRefLoc].CallersCaller \
+ ); \
+ if ((_ref)) { \
+ (_link)->TotalReferences++; \
+ } else { \
+ (_link)->TotalDereferences++; \
+ (_link)->History[(_link)->NextRefLoc].Caller = \
+ (PVOID)((ULONG)(_link)->History[(_link)->NextRefLoc].Caller & \
+ ~0x80000000); \
+ } \
+ if (++(_link)->NextRefLoc == LINK_HISTORY_LENGTH) { \
+ (_link)->NextRefLoc = 0; \
+ } \
+ KeReleaseSpinLock (&NbfGlobalHistoryLock, oldIrql); \
+}
+#endif
+
+#define LINK_FLAGS_JUMP_START 0x00000040 // run adaptive alg/every sent window.
+#define LINK_FLAGS_LOCAL_DISC 0x00000080 // link was stopped locally.
+
+//
+// deferred flags, used for processing at timer tick if needed
+//
+
+#define LINK_FLAGS_DEFERRED_DELETE 0x00010000 // delete at next opportunity
+#define LINK_FLAGS_DEFERRED_ADD 0x00020000 // add to splay tree, next opportunity
+#define LINK_FLAGS_DEFERRED_MASK 0x00030000 // (LINK_FLAGS_DEFERRED_DELETE | LINK_FLAGS_DEFERRED_ADD)
+
+#define LINK_STATE_ADM 1 // asynchronous disconnected mode.
+#define LINK_STATE_READY 2 // asynchronous balanced mode extended.
+#define LINK_STATE_BUSY 3 // all link buffers are busy, sent RNR
+#define LINK_STATE_CONNECTING 4 // waiting SABME response (UA-r/f).
+#define LINK_STATE_W_POLL 5 // waiting initial checkpoint.
+#define LINK_STATE_W_FINAL 6 // waiting final from initial checkpoint.
+#define LINK_STATE_W_DISC_RSP 7 // waiting disconnect response.
+
+#define SEND_STATE_DOWN 0 // asynchronous disconnected mode.
+#define SEND_STATE_READY 1 // completely ready to send.
+#define SEND_STATE_REJECTING 2 // other guy is rejecting.
+#define SEND_STATE_CHECKPOINTING 3 // we're checkpointing (can't send data).
+
+#define RECEIVE_STATE_DOWN 0 // asynchronous disconnected mode.
+#define RECEIVE_STATE_READY 1 // we're ready to receive.
+#define RECEIVE_STATE_REJECTING 2 // we're rejecting.
+
+
+//
+// This structure defines the DEVICE_OBJECT and its extension allocated at
+// the time the transport provider creates its device object.
+//
+
+#if DBG
+#define DCREF_CREATION 0
+#define DCREF_ADDRESS 1
+#define DCREF_CONNECTION 2
+#define DCREF_LINK 3
+#define DCREF_QUERY_INFO 4
+#define DCREF_SCAN_TIMER 5
+#define DCREF_REQUEST 6
+
+#define NUMBER_OF_DCREFS 8
+#endif
+
+
+typedef struct _NBF_POOL_LIST_DESC {
+ NDIS_HANDLE PoolHandle;
+ USHORT NumElements;
+ USHORT TotalElements;
+ struct _NBF_POOL_LIST_DESC *Next;
+} NBF_POOL_LIST_DESC, *PNBF_POOL_LIST_DESC;
+
+typedef struct _DEVICE_CONTEXT {
+
+ DEVICE_OBJECT DeviceObject; // the I/O system's device object.
+
+#if DBG
+ ULONG RefTypes[NUMBER_OF_DCREFS];
+#endif
+
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+ LIST_ENTRY Linkage; // links them on NbfDeviceList;
+
+ KSPIN_LOCK Interlock; // GLOBAL spinlock for reference count.
+ // (used in ExInterlockedXxx calls)
+ LONG ReferenceCount; // activity count/this provider.
+
+
+ //
+ // This protects the LoopbackQueue.
+ //
+
+ KSPIN_LOCK LoopbackSpinLock;
+
+ //
+ // The queue of packets waiting to be looped back.
+ //
+
+ LIST_ENTRY LoopbackQueue;
+
+ //
+ // These two links are used for loopback.
+ //
+
+ PTP_LINK LoopbackLinks[2];
+
+ //
+ // This buffer is used for loopback indications; a
+ // contiguous piece is copied into it. It is allocated
+ // (of size NBF_MAX_LOOPBACK_LOOKAHEAD) when one of
+ // the LoopbackLinks become non-NULL.
+ //
+
+ PUCHAR LookaheadContiguous;
+
+ //
+ // This holds the length of the header in the currently
+ // indicating loopback packet.
+ //
+
+ ULONG LoopbackHeaderLength;
+
+ //
+ // Used for processing the loopback queue.
+ //
+
+ KDPC LoopbackDpc;
+
+ //
+ // Determines if a LoopbackDpc is in progress.
+ //
+
+ BOOLEAN LoopbackInProgress;
+
+ //
+ // Determines if a WanDelayedDpc is in progress.
+ //
+
+ BOOLEAN WanThreadQueued;
+
+ //
+ // Used for momentarily delaying WAN packetizing to
+ // allow RR's to be received.
+ //
+
+ WORK_QUEUE_ITEM WanDelayedQueueItem;
+
+ //
+ // The queue of FIND.NAME requests waiting to be processed.
+ //
+
+ LIST_ENTRY FindNameQueue;
+
+ //
+ // The queue of STATUS.QUERY requests waiting to be processed.
+ //
+
+ LIST_ENTRY StatusQueryQueue;
+
+ //
+ // The queue of QUERY.INDICATION requests waiting to be completed.
+ //
+
+ LIST_ENTRY QueryIndicationQueue;
+
+ //
+ // The queue of DATAGRAM.INDICATION requests waiting to be completed.
+ //
+
+ LIST_ENTRY DatagramIndicationQueue;
+
+ //
+ // The queue of (currently receive only) IRPs waiting to complete.
+ //
+
+ LIST_ENTRY IrpCompletionQueue;
+
+ //
+ // This boolean is TRUE if either of the above two have ever
+ // had anything on them.
+ //
+
+ BOOLEAN IndicationQueuesInUse;
+
+ //
+ // Following are protected by Global Device Context SpinLock
+ //
+
+ KSPIN_LOCK SpinLock; // lock to manipulate this object.
+ // (used in KeAcquireSpinLock calls)
+
+ //
+ // the device context state, among open, closing
+ //
+
+ UCHAR State;
+
+ //
+ // Used when processing a STATUS_CLOSING indication.
+ //
+
+ WORK_QUEUE_ITEM StatusClosingQueueItem;
+
+ //
+ // The following queue holds free TP_LINK objects available for allocation.
+ //
+
+ LIST_ENTRY LinkPool;
+
+ //
+ // These counters keep track of resources uses by TP_LINK objects.
+ //
+
+ ULONG LinkAllocated;
+ ULONG LinkInitAllocated;
+ ULONG LinkMaxAllocated;
+ ULONG LinkInUse;
+ ULONG LinkMaxInUse;
+ ULONG LinkExhausted;
+ ULONG LinkTotal;
+ ULONG LinkSamples;
+
+
+ //
+ // The following queue holds free TP_ADDRESS objects available for allocation.
+ //
+
+ LIST_ENTRY AddressPool;
+
+ //
+ // These counters keep track of resources uses by TP_ADDRESS objects.
+ //
+
+ ULONG AddressAllocated;
+ ULONG AddressInitAllocated;
+ ULONG AddressMaxAllocated;
+ ULONG AddressInUse;
+ ULONG AddressMaxInUse;
+ ULONG AddressExhausted;
+ ULONG AddressTotal;
+ ULONG AddressSamples;
+
+
+ //
+ // The following queue holds free TP_ADDRESS_FILE objects available for allocation.
+ //
+
+ LIST_ENTRY AddressFilePool;
+
+ //
+ // These counters keep track of resources uses by TP_ADDRESS_FILE objects.
+ //
+
+ ULONG AddressFileAllocated;
+ ULONG AddressFileInitAllocated;
+ ULONG AddressFileMaxAllocated;
+ ULONG AddressFileInUse;
+ ULONG AddressFileMaxInUse;
+ ULONG AddressFileExhausted;
+ ULONG AddressFileTotal;
+ ULONG AddressFileSamples;
+
+
+ //
+ // The following queue holds free TP_CONNECTION objects available for allocation.
+ //
+
+ LIST_ENTRY ConnectionPool;
+
+ //
+ // These counters keep track of resources uses by TP_CONNECTION objects.
+ //
+
+ ULONG ConnectionAllocated;
+ ULONG ConnectionInitAllocated;
+ ULONG ConnectionMaxAllocated;
+ ULONG ConnectionInUse;
+ ULONG ConnectionMaxInUse;
+ ULONG ConnectionExhausted;
+ ULONG ConnectionTotal;
+ ULONG ConnectionSamples;
+
+
+ //
+ // The following is a free list of TP_REQUEST blocks which have been
+ // previously allocated and are available for use.
+ //
+
+ LIST_ENTRY RequestPool; // free request block pool.
+
+ //
+ // These counters keep track of resources uses by TP_REQUEST objects.
+ //
+
+ ULONG RequestAllocated;
+ ULONG RequestInitAllocated;
+ ULONG RequestMaxAllocated;
+ ULONG RequestInUse;
+ ULONG RequestMaxInUse;
+ ULONG RequestExhausted;
+ ULONG RequestTotal;
+ ULONG RequestSamples;
+
+
+ //
+ // The following list comprises a pool of UI NetBIOS frame headers
+ // that are manipulated by the routines in FRAMESND.C.
+ //
+
+ LIST_ENTRY UIFramePool; // free UI frames (TP_UI_FRAME objects).
+
+ //
+ // These counters keep track of resources uses by TP_UI_FRAME objects.
+ //
+
+ ULONG UIFrameLength;
+ ULONG UIFrameHeaderLength;
+ ULONG UIFrameAllocated;
+ ULONG UIFrameInitAllocated;
+ ULONG UIFrameExhausted;
+
+
+ //
+ // The following queue holds I-frame Send packets managed by PACKET.C.
+ //
+
+ SINGLE_LIST_ENTRY PacketPool;
+
+ //
+ // These counters keep track of resources uses by TP_PACKET objects.
+ //
+
+ ULONG PacketLength;
+ ULONG PacketHeaderLength;
+ ULONG PacketAllocated;
+ ULONG PacketInitAllocated;
+ ULONG PacketExhausted;
+
+
+ //
+ // The following queue holds RR-frame Send packets managed by PACKET.C.
+ //
+
+ SINGLE_LIST_ENTRY RrPacketPool;
+
+
+ //
+ // The following queue contains Receive packets
+ //
+
+ SINGLE_LIST_ENTRY ReceivePacketPool;
+
+ //
+ // These counters keep track of resources uses by NDIS_PACKET objects.
+ //
+
+ ULONG ReceivePacketAllocated;
+ ULONG ReceivePacketInitAllocated;
+ ULONG ReceivePacketExhausted;
+
+
+ //
+ // This queue contains pre-allocated receive buffers
+ //
+
+ SINGLE_LIST_ENTRY ReceiveBufferPool;
+
+ //
+ // These counters keep track of resources uses by TP_PACKET objects.
+ //
+
+ ULONG ReceiveBufferLength;
+ ULONG ReceiveBufferAllocated;
+ ULONG ReceiveBufferInitAllocated;
+ ULONG ReceiveBufferExhausted;
+
+
+ //
+ // This holds the total memory allocated for the above structures.
+ //
+
+ ULONG MemoryUsage;
+ ULONG MemoryLimit;
+
+
+ //
+ // The following field is a head of a list of TP_ADDRESS objects that
+ // are defined for this transport provider. To edit the list, you must
+ // hold the spinlock of the device context object.
+ //
+
+ LIST_ENTRY AddressDatabase; // list of defined transport addresses.
+
+ //
+ // The following field is the pointer to the root of the splay tree of
+ // links that are associated with this Device Context. You must hold the
+ // LinkSpinLock to modify this list. You must set the LinkTreeSemaphore
+ // to traverse this list without modifying it. Note that all modify
+ // operations are deferred to timer(DPC)-time operations.
+ //
+
+ KSPIN_LOCK LinkSpinLock; // protects these values
+ PTP_LINK LastLink; // the last link found in the tree.
+ PRTL_SPLAY_LINKS LinkTreeRoot; // pointer to root of the tree.
+ ULONG LinkTreeElements; // how many elements in the tree
+ LIST_ENTRY LinkDeferred; // Deferred operations on links.
+ ULONG DeferredNotSatisfied; // how many times we've come to the
+ // deferred well and not gotten it clear.
+
+ //
+ // The following queue holds connections which are waiting on available
+ // packets. As each new packet becomes available, a connection is removed
+ // from this queue and placed on the PacketizeQueue.
+ //
+
+ LIST_ENTRY PacketWaitQueue; // queue of packet-starved connections.
+ LIST_ENTRY PacketizeQueue; // queue of ready-to-packetize connections.
+
+ //
+ // The following queue holds connections which are waiting to send
+ // a piggyback ack. In that case the CONNECTION_FLAGS_DEFERRED_ACK
+ // bit in DeferredFlags will be set.
+ //
+
+ LIST_ENTRY DataAckQueue;
+
+ //
+ // The following queue holds links which are waiting to send an
+ // RR frame because the remote they are talking to never polls.
+ //
+
+ LIST_ENTRY DeferredRrQueue;
+
+ //
+ // Used to track when the queue has changed.
+ //
+
+ BOOLEAN DataAckQueueChanged;
+
+ //
+ // When this hits thirty seconds we checked for stalled connections.
+ //
+
+ USHORT StalledConnectionCount;
+
+ //
+ // This queue contains receives that are in progress
+ //
+
+ LIST_ENTRY ReceiveInProgress;
+
+ //
+ // NDIS fields
+ //
+
+ //
+ // following is used to keep adapter information.
+ //
+
+ NDIS_HANDLE NdisBindingHandle;
+
+ //
+ // The following fields are used for talking to NDIS. They keep information
+ // for the NDIS wrapper to use when determining what pool to use for
+ // allocating storage.
+ //
+
+ KSPIN_LOCK SendPoolListLock; // protects these values
+ PNBF_POOL_LIST_DESC SendPacketPoolDesc;
+ KSPIN_LOCK RcvPoolListLock; // protects these values
+ PNBF_POOL_LIST_DESC ReceivePacketPoolDesc;
+ NDIS_HANDLE NdisBufferPool;
+
+ //
+ // These are kept around for error logging.
+ //
+
+ ULONG SendPacketPoolSize;
+ ULONG ReceivePacketPoolSize;
+ ULONG MaxRequests;
+ ULONG MaxLinks;
+ ULONG MaxConnections;
+ ULONG MaxAddressFiles;
+ ULONG MaxAddresses;
+ PWCHAR DeviceName;
+ ULONG DeviceNameLength;
+
+ //
+ // This is the Mac type we must build the packet header for and know the
+ // offsets for.
+ //
+
+ NBF_NDIS_IDENTIFICATION MacInfo; // MAC type and other info
+ ULONG MaxReceivePacketSize; // does not include the MAC header
+ ULONG MaxSendPacketSize; // includes the MAC header
+ ULONG CurSendPacketSize; // may be smaller for async
+ USHORT RecommendedSendWindow; // used for Async lines
+ BOOLEAN EasilyDisconnected; // TRUE over wireless nets.
+
+ //
+ // some MAC addresses we use in the transport
+ //
+
+ HARDWARE_ADDRESS LocalAddress; // our local hardware address.
+ HARDWARE_ADDRESS NetBIOSAddress; // NetBIOS functional address, used for TR
+
+ //
+ // The reserved Netbios address; consists of 10 zeroes
+ // followed by LocalAddress;
+ //
+
+ UCHAR ReservedNetBIOSAddress[NETBIOS_NAME_LENGTH];
+#ifdef _PNP_POWER
+ HANDLE TdiDeviceHandle;
+ HANDLE ReservedAddressHandle;
+#endif
+
+ //
+ // These are used while initializing the MAC driver.
+ //
+
+ KEVENT NdisRequestEvent; // used for pended requests.
+ NDIS_STATUS NdisRequestStatus; // records request status.
+
+ //
+ // This next field maintains a unique number which can next be assigned
+ // as a connection identifier. It is incremented by one each time a
+ // value is allocated.
+ //
+
+ USHORT UniqueIdentifier; // starts at 0, wraps around 2^16-1.
+
+ //
+ // This contains the next unique indentified to use as
+ // the FsContext in the file object associated with an
+ // open of the control channel.
+ //
+
+ USHORT ControlChannelIdentifier;
+
+ //
+ // The following fields are used to implement the lightweight timer
+ // system in the protocol provider. Each TP_LINK object in the device
+ // context's LinkDatabase contains three lightweight timers that are
+ // serviced by a DPC routine, which receives control by kernel functions.
+ // There is one kernel timer for this transport that is set
+ // to go off at regular intervals. This timer increments the Absolute time,
+ // which is then used to compare against the timer queues. The timer queues
+ // are ordered, so whenever the first element is not expired, the rest of
+ // the queue is not expired. This allows us to have hundreds of timers
+ // running with very low system overhead.
+ // A value of -1 indicates that the timer is not active.
+ //
+
+ LARGE_INTEGER ShortTimerStart; // when the short timer was set.
+ KDPC ShortTimerSystemDpc; // kernel DPC object, short timer.
+ KTIMER ShortSystemTimer; // kernel timer object, short timer.
+ ULONG ShortAbsoluteTime; // up-count timer ticks, short timer.
+ ULONG AdaptivePurge; // absolute time of next purge (short timer).
+ KDPC LongTimerSystemDpc; // kernel DPC object, long timer.
+ KTIMER LongSystemTimer; // kernel timer object, long timer.
+ ULONG LongAbsoluteTime; // up-count timer ticks, long timer.
+ union _DC_ACTIVE {
+ struct _DC_INDIVIDUAL {
+ BOOLEAN ShortListActive; // ShortList is not empty.
+ BOOLEAN DataAckQueueActive; // DataAckQueue is not empty.
+ BOOLEAN LinkDeferredActive; // LinkDeferred is not empty.
+ } i;
+ ULONG AnyActive; // used to check all four at once.
+ } a;
+ BOOLEAN TimersInitialized; // has the timer system been initialized.
+ BOOLEAN ProcessingShortTimer; // TRUE if we are in ScanShortTimer.
+ KSPIN_LOCK TimerSpinLock; // lock for following timer queues
+ LIST_ENTRY ShortList; // list of links waiting T1 or T2
+ LIST_ENTRY LongList; // list of links waiting Ti expire
+ LIST_ENTRY PurgeList; // list of links waiting LAT expire
+
+ //
+ // These fields are used on "easily disconnected" adapters.
+ // Every time the long timer expires, it notes if there has
+ // been any multicast traffic received. If there has not been,
+ // it increments LongTimeoutsWithoutMulticast. Activity is
+ // recorded by incrementing MulticastPacket when MC
+ // packets are received, and zeroing it when the long timer
+ // expires.
+ //
+
+ ULONG LongTimeoutsWithoutMulticast; // LongTimer timeouts since traffic.
+ ULONG MulticastPacketCount; // How many MC packets rcved, this timeout.
+
+ //
+ // This information is used to keep track of the speed of
+ // the underlying medium.
+ //
+
+ ULONG MediumSpeed; // in units of 100 bytes/sec
+ BOOLEAN MediumSpeedAccurate; // if FALSE, can't use the link.
+
+ //
+ // This is TRUE if we are on a UP system.
+ //
+
+ BOOLEAN UniProcessor;
+
+ //
+ // Configuration information on how soon we should send
+ // an unasked for RR with a non-polling remote.
+ //
+
+ UCHAR MaxConsecutiveIFrames;
+
+ //
+ // This is configuration information controlling the default
+ // value of timers and retry counts.
+ //
+
+ ULONG DefaultT1Timeout;
+ ULONG MinimumT1Timeout;
+ ULONG DefaultT2Timeout;
+ ULONG DefaultTiTimeout;
+ ULONG LlcRetries;
+ ULONG LlcMaxWindowSize;
+ ULONG NameQueryRetries;
+ ULONG NameQueryTimeout;
+ ULONG AddNameQueryRetries;
+ ULONG AddNameQueryTimeout;
+ ULONG GeneralRetries;
+ ULONG GeneralTimeout;
+ ULONG MinimumSendWindowLimit; // how low we can lock a connection's window
+
+ //
+ // Counters for most of the statistics that NBF maintains;
+ // some of these are kept elsewhere. Including the structure
+ // itself wastes a little space but ensures that the alignment
+ // inside the structure is correct.
+ //
+
+ TDI_PROVIDER_STATISTICS Statistics;
+
+ //
+ // These are "temporary" versions of the other counters.
+ // During normal operations we update these, then during
+ // the short timer expiration we update the real ones.
+ //
+
+ ULONG TempIFrameBytesSent;
+ ULONG TempIFramesSent;
+ ULONG TempIFrameBytesReceived;
+ ULONG TempIFramesReceived;
+
+ //
+ // Some counters needed for Netbios adapter status.
+ //
+
+ ULONG TiExpirations;
+ ULONG FrmrReceived;
+ ULONG FrmrTransmitted;
+
+ //
+ // These are used to compute AverageSendWindow.
+ //
+
+ ULONG SendWindowTotal;
+ ULONG SendWindowSamples;
+
+ //
+ // Counters for "active" time.
+ //
+
+ LARGE_INTEGER NbfStartTime;
+
+ //
+ // This resource guards access to the ShareAccess
+ // and SecurityDescriptor fields in addresses.
+ //
+
+ ERESOURCE AddressResource;
+
+ //
+ // This array is used to keep track of which LSNs are
+ // available for use by Netbios sessions. LSNs can be
+ // re-used for sessions to unique names if they are on
+ // different links, but must be committed beforehand
+ // for group names. The maximum value that can fit in
+ // an array element is defined by LSN_TABLE_MAX.
+ //
+
+ UCHAR LsnTable[NETBIOS_SESSION_LIMIT+1];
+
+ //
+ // This is where we start looking in LsnTable for an
+ // unused LSN. We cycle from 0-63 to prevent quick
+ // down-and-up connections from getting funny data.
+ //
+
+ ULONG NextLsnStart;
+
+ //
+ // This array is used to quickly dismiss UI frames that
+ // are not destined for us. The count is the number
+ // of addresses with that first letter that are registered
+ // on this device.
+ //
+
+ UCHAR AddressCounts[256];
+
+ //
+ // The following structure contains statistics counters for use
+ // by TdiQueryInformation and TdiSetInformation. They should not
+ // be used for maintenance of internal data structures.
+ //
+
+ TDI_PROVIDER_INFO Information; // information about this provider.
+
+ PTP_VARIABLE NetmanVariables; // list of network managable variables.
+
+ //
+ // The magic bullet is a packet that is sent under certain debugging
+ // conditions. This allows the transport to signal packet capture devices
+ // that a particular condiion has been met. This packet has the current
+ // devicecontext as the source, and 0x04 in every other byte of the packet.
+ //
+
+ UCHAR MagicBullet[32]; //
+
+} DEVICE_CONTEXT, *PDEVICE_CONTEXT;
+
+//
+// device context state definitions
+//
+
+#define DEVICECONTEXT_STATE_OPENING 0x00
+#define DEVICECONTEXT_STATE_OPEN 0x01
+#define DEVICECONTEXT_STATE_DOWN 0x02
+#define DEVICECONTEXT_STATE_STOPPING 0x03
+
+//
+// This is the maximum value that can go in an element
+// of LsnTable (should be 0xff if they are UCHARs,
+// 0xffff for USHORTs, etc.).
+//
+
+#define LSN_TABLE_MAX 0xff
+
+
+#define MAGIC_BULLET_FOOD 0x04
+
+
+//
+// These are constants for the LoopbackLinks elements.
+// The distinctions are arbitrary; the listener link
+// is the one established from ProcessNameQuery, and
+// the connector link is the one established from
+// ProcessNameRecognized.
+//
+
+#define LISTENER_LINK 0
+#define CONNECTOR_LINK 1
+
+
+//
+// This structure defines the packet object, used to represent a DLC I-frame
+// in some portion of its lifetime. The PACKET.C module contains routines
+// to manage this object.
+//
+
+typedef struct _TP_PACKET {
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+ PNDIS_PACKET NdisPacket; // ptr to owning Ndis Packet
+ ULONG NdisIFrameLength; // Length of NdisPacket
+
+ LIST_ENTRY Linkage; // used to chain packets together.
+ LONG ReferenceCount; // activity count/this packet.
+ BOOLEAN PacketSent; // packet completed by NDIS.
+ BOOLEAN PacketNoNdisBuffer; // chain on this packet was not allocated.
+
+ UCHAR Action; // what to do when we're acked.
+ BOOLEAN PacketizeConnection; // restart packetizing when completed.
+
+ PVOID Owner; // ptr to owning connection or IrpSp.
+ PTP_LINK Link; // ptr to link it was sent on.
+ PDEVICE_CONTEXT Provider; // The owner of this packet.
+ PKSPIN_LOCK ProviderInterlock; // &Provider->Interlock.
+
+ UCHAR Header[1]; // the MAC, DLC, and NBF headers
+
+} TP_PACKET, *PTP_PACKET;
+
+
+//
+// The following values are placed in the Action field in the TP_PACKET
+// object to indicate what action, if any, should be taken when the packet
+// is destroyed.
+//
+
+#define PACKET_ACTION_NULL 0 // no special action should be taken.
+#define PACKET_ACTION_IRP_SP 1 // Owner is an IRP_SP, deref when done.
+#define PACKET_ACTION_CONNECTION 2 // Owner is a TP_CONNECTION, deref when done.
+#define PACKET_ACTION_END 3 // shutdown session (sent SESSION_END).
+#define PACKET_ACTION_RR 5 // packet is an RR, put back in RR pool.
+
+//
+// Types used to hold information in the send and receive NDIS packets
+//
+
+typedef struct _SEND_PACKET_TAG {
+ LIST_ENTRY Linkage; // used for threading on loopback queue
+ BOOLEAN OnLoopbackQueue; // TRUE if the packet is on a loopback queue
+ UCHAR LoopbackLinkIndex; // index of other link for loopback packets
+ USHORT Type; // identifier for packet type
+ PVOID Frame; // backpointer to owning NBF structure
+ PVOID Owner; // backpointer for owning nbf construct
+ // (like address, devicecontext, etc)
+ } SEND_PACKET_TAG, *PSEND_PACKET_TAG;
+
+//
+// Packet types used in send completion
+//
+
+#define TYPE_I_FRAME 1
+#define TYPE_UI_FRAME 2
+#define TYPE_ADDRESS_FRAME 3
+
+//
+// LoopbackLinkIndex values.
+//
+
+#define LOOPBACK_TO_LISTENER 0
+#define LOOPBACK_TO_CONNECTOR 1
+#define LOOPBACK_UI_FRAME 2
+
+//
+// receive packet used to hold information about this receive
+//
+
+typedef struct _RECEIVE_PACKET_TAG {
+ SINGLE_LIST_ENTRY Linkage; // used for threading in pool
+ PTP_CONNECTION Connection; // connection this receive is occuring on
+ ULONG BytesToTransfer; // for I-frame, bytes in this transfer
+ UCHAR PacketType; // the type of packet we're processing
+ BOOLEAN AllocatedNdisBuffer; // did we allocate our own NDIS_BUFFERs
+ BOOLEAN EndOfMessage; // does this receive complete the message
+ BOOLEAN CompleteReceive; // complete the receive after TransferData?
+ BOOLEAN TransferDataPended; // TRUE if TransferData returned PENDING
+ } RECEIVE_PACKET_TAG, *PRECEIVE_PACKET_TAG;
+
+#define TYPE_AT_INDICATE 1
+#define TYPE_AT_COMPLETE 2
+#define TYPE_STATUS_RESPONSE 3
+
+//
+// receive buffer descriptor (built in memory at the beginning of the buffer)
+//
+
+typedef struct _BUFFER_TAG {
+ LIST_ENTRY Linkage; // thread in pool and on receive queue
+ NDIS_STATUS NdisStatus; // completion status for send
+ PTP_ADDRESS Address; // the address this datagram is for.
+ PNDIS_BUFFER NdisBuffer; // describes the rest of the buffer
+ ULONG Length; // the length of the buffer
+ UCHAR Buffer[1]; // the actual storage (accessed through the NDIS_BUFFER)
+ } BUFFER_TAG, *PBUFFER_TAG;
+
+#endif // def _NBFTYPES_
+
diff --git a/private/ntos/tdi/nbf/packet.c b/private/ntos/tdi/nbf/packet.c
new file mode 100644
index 000000000..2b6de5b25
--- /dev/null
+++ b/private/ntos/tdi/nbf/packet.c
@@ -0,0 +1,1808 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ packet.c
+
+Abstract:
+
+ This module contains code that implements the TP_PACKET object, which
+ describes a DLC I-frame at some point in its lifetime. Routines are
+ provided to allocate packets for shipment, to ship packets, to reference
+ packets, to dereference packets, to mark a connection as waiting for a
+ packet to become available, to satisfy the next waiting connection for
+ a packet, and to destroy packets (return them to the pool).
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// This is temporary; this is the quota that we charge for a receive
+// packet for now, until we fix the problem with token-ring needing
+// big packets and using all the memory. The number is the actual
+// value for Ethernet.
+//
+
+#if 1
+#define RECEIVE_BUFFER_QUOTA(_DeviceContext) 1533
+#else
+#define RECEIVE_BUFFER_QUOTA(_DeviceContext) (_DeviceContext)->ReceiveBufferLength
+#endif
+
+#define PACKET_POOL_GROW_COUNT 32
+
+#if DBG
+ULONG NbfCreatePacketThreshold = 5;
+extern ULONG NbfPacketPanic;
+#endif
+
+NDIS_STATUS
+NbfAllocateNdisSendPacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PNDIS_PACKET *NdisPacket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a recieve packet from the receive packet pool.
+ It Grows the packet pool if necessary.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ UIFrame - Returns a pointer to the frame, or NULL if no storage
+ can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNBF_POOL_LIST_DESC SendPacketPoolDesc;
+ NDIS_STATUS NdisStatus;
+ KIRQL oldirql;
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SendPoolListLock, &oldirql);
+ for (SendPacketPoolDesc = DeviceContext->SendPacketPoolDesc;
+ SendPacketPoolDesc != NULL;
+ SendPacketPoolDesc = SendPacketPoolDesc->Next) {
+
+ NdisAllocatePacket (
+ &NdisStatus,
+ NdisPacket,
+ SendPacketPoolDesc->PoolHandle);
+
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SendPoolListLock, oldirql);
+ return(NdisStatus);
+ }
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage +
+ PACKET_POOL_GROW_COUNT *
+ (sizeof(NDIS_PACKET) + sizeof(SEND_PACKET_TAG))) >
+ DeviceContext->MemoryLimit)) {
+
+ PANIC("NBF: Could not grow packet pool: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 106,
+ DeviceContext->UIFrameLength,
+ UI_FRAME_RESOURCE_ID);
+ RELEASE_SPIN_LOCK (&DeviceContext->SendPoolListLock, oldirql);
+ return(NdisStatus);
+ }
+ }
+
+ DeviceContext->MemoryUsage +=
+ (PACKET_POOL_GROW_COUNT *
+ (sizeof(NDIS_PACKET) + sizeof(SEND_PACKET_TAG)));
+
+ // Allocate Packet pool descriptors for dynamic packet allocation.
+
+ SendPacketPoolDesc = ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(NBF_POOL_LIST_DESC),
+ ' FBN');
+
+ if (DeviceContext->SendPacketPoolDesc == NULL) {
+ return(NdisStatus);
+ }
+
+ RtlZeroMemory(SendPacketPoolDesc, sizeof(NBF_POOL_LIST_DESC));
+
+ SendPacketPoolDesc->NumElements =
+ SendPacketPoolDesc->TotalElements = PACKET_POOL_GROW_COUNT;
+
+ NdisAllocatePacketPool ( &NdisStatus, &SendPacketPoolDesc->PoolHandle,
+ PACKET_POOL_GROW_COUNT, sizeof (SEND_PACKET_TAG));
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+#if DBG
+ NbfPrint1 ("NbfGrowSendPacketPool: NdisInitializePacketPool failed, reason: %s.\n",
+ NbfGetNdisStatus (NdisStatus));
+#endif
+ RELEASE_SPIN_LOCK (&DeviceContext->SendPoolListLock, oldirql);
+ ExFreePool (SendPacketPoolDesc);
+ return(NdisStatus);
+ }
+ SendPacketPoolDesc->Next = DeviceContext->SendPacketPoolDesc;
+ DeviceContext->SendPacketPoolDesc = SendPacketPoolDesc;
+ RELEASE_SPIN_LOCK (&DeviceContext->SendPoolListLock, oldirql);
+ NdisAllocatePacket ( &NdisStatus, NdisPacket,
+ SendPacketPoolDesc->PoolHandle);
+
+ return(NdisStatus);
+}
+
+NDIS_STATUS
+NbfAllocateNdisRcvPacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PNDIS_PACKET *NdisPacket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a recieve packet from the receive packet pool.
+ It Grows the packet pool if necessary.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ UIFrame - Returns a pointer to the frame, or NULL if no storage
+ can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNBF_POOL_LIST_DESC RcvPacketPoolDesc;
+ NDIS_STATUS NdisStatus;
+ KIRQL oldirql;
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->RcvPoolListLock, &oldirql);
+ for (RcvPacketPoolDesc = DeviceContext->ReceivePacketPoolDesc;
+ RcvPacketPoolDesc != NULL;
+ RcvPacketPoolDesc = RcvPacketPoolDesc->Next) {
+
+ NdisAllocatePacket (
+ &NdisStatus,
+ NdisPacket,
+ RcvPacketPoolDesc->PoolHandle);
+
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+ RELEASE_SPIN_LOCK (&DeviceContext->RcvPoolListLock, oldirql);
+ return(NdisStatus);
+ }
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage +
+ PACKET_POOL_GROW_COUNT *
+ (sizeof(NDIS_PACKET) + sizeof(SEND_PACKET_TAG))) >
+ DeviceContext->MemoryLimit)) {
+
+ PANIC("NBF: Could not grow packet pool: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 106,
+ DeviceContext->UIFrameLength,
+ UI_FRAME_RESOURCE_ID);
+ RELEASE_SPIN_LOCK (&DeviceContext->RcvPoolListLock, oldirql);
+ return(NdisStatus);
+ }
+ }
+
+ DeviceContext->MemoryUsage +=
+ (PACKET_POOL_GROW_COUNT *
+ (sizeof(NDIS_PACKET) + sizeof(SEND_PACKET_TAG)));
+
+ // Allocate Packet pool descriptors for dynamic packet allocation.
+
+ RcvPacketPoolDesc = ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(NBF_POOL_LIST_DESC),
+ ' FBN');
+
+ if (RcvPacketPoolDesc == NULL) {
+ RELEASE_SPIN_LOCK (&DeviceContext->RcvPoolListLock, oldirql);
+ return(NdisStatus);
+ }
+
+ RtlZeroMemory(RcvPacketPoolDesc, sizeof(NBF_POOL_LIST_DESC));
+
+ RcvPacketPoolDesc->NumElements =
+ RcvPacketPoolDesc->TotalElements = PACKET_POOL_GROW_COUNT;
+
+ NdisAllocatePacketPool ( &NdisStatus, &RcvPacketPoolDesc->PoolHandle,
+ PACKET_POOL_GROW_COUNT, sizeof (RECEIVE_PACKET_TAG));
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+#if DBG
+ NbfPrint1 ("NbfGrowSendPacketPool: NdisInitializePacketPool failed, reason: %s.\n",
+ NbfGetNdisStatus (NdisStatus));
+#endif
+ RELEASE_SPIN_LOCK (&DeviceContext->RcvPoolListLock, oldirql);
+ ExFreePool (RcvPacketPoolDesc);
+ return(NdisStatus);
+ }
+ RcvPacketPoolDesc->Next = DeviceContext->ReceivePacketPoolDesc;
+ DeviceContext->ReceivePacketPoolDesc = RcvPacketPoolDesc;
+ RELEASE_SPIN_LOCK (&DeviceContext->RcvPoolListLock, oldirql);
+ NdisAllocatePacket ( &NdisStatus, NdisPacket,
+ RcvPacketPoolDesc->PoolHandle);
+
+ return(NdisStatus);
+}
+
+
+VOID
+NbfAllocateUIFrame(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_UI_FRAME *TransportUIFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for a UI frame. Some initialization
+ is done here.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ UIFrame - Returns a pointer to the frame, or NULL if no storage
+ can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ PNDIS_PACKET NdisPacket;
+ PSEND_PACKET_TAG SendTag;
+ PTP_UI_FRAME UIFrame;
+ PNDIS_BUFFER NdisBuffer;
+ PNBF_POOL_LIST_DESC SendPacketPoolDesc;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + DeviceContext->UIFrameLength) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("NBF: Could not allocate UI frame: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 106,
+ DeviceContext->UIFrameLength,
+ UI_FRAME_RESOURCE_ID);
+ *TransportUIFrame = NULL;
+ return;
+ }
+
+ UIFrame = (PTP_UI_FRAME) ExAllocatePoolWithTag (
+ NonPagedPool,
+ DeviceContext->UIFrameLength,
+ 'uFBN');
+ if (UIFrame == NULL) {
+ PANIC("NBF: Could not allocate UI frame: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 206,
+ DeviceContext->UIFrameLength,
+ UI_FRAME_RESOURCE_ID);
+ *TransportUIFrame = NULL;
+ return;
+ }
+ RtlZeroMemory (UIFrame, DeviceContext->UIFrameLength);
+
+ DeviceContext->MemoryUsage += DeviceContext->UIFrameLength;
+ NdisStatus = NbfAllocateNdisSendPacket(DeviceContext, &NdisPacket);
+#if 0
+ for (SendPacketPoolDesc = DeviceContext->SendPacketPoolDesc;
+ SendPacketPoolDesc != NULL;
+ SendPacketPoolDesc = SendPacketPoolDesc->Next) {
+
+ NdisAllocatePacket (
+ &NdisStatus,
+ &NdisPacket,
+ SendPacketPoolDesc->PoolHandle);
+
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS)
+ break;
+ }
+#endif
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ ExFreePool (UIFrame);
+#if 0
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 306,
+ 0,
+ UI_FRAME_RESOURCE_ID);
+#endif
+ *TransportUIFrame = NULL;
+ return;
+ }
+
+
+ UIFrame->NdisPacket = NdisPacket;
+ UIFrame->DataBuffer = NULL;
+ SendTag = (PSEND_PACKET_TAG)NdisPacket->ProtocolReserved;
+ SendTag->Type = TYPE_UI_FRAME;
+ SendTag->Frame = UIFrame;
+ SendTag->Owner = DeviceContext;
+
+ //
+ // Make the packet header known to the packet descriptor
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ DeviceContext->NdisBufferPool,
+ UIFrame->Header,
+ DeviceContext->UIFrameHeaderLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 406,
+ 0,
+ UI_FRAME_RESOURCE_ID);
+ NdisFreePacket (NdisPacket);
+ ExFreePool (UIFrame);
+ *TransportUIFrame = NULL;
+ return;
+ }
+
+ NdisChainBufferAtFront (NdisPacket, NdisBuffer);
+
+ ++DeviceContext->UIFrameAllocated;
+
+ *TransportUIFrame = UIFrame;
+
+} /* NbfAllocateUIFrame */
+
+
+VOID
+NbfDeallocateUIFrame(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_UI_FRAME TransportUIFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for a UI frame.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ UIFrame - A pointer to the frame.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PACKET NdisPacket = TransportUIFrame->NdisPacket;
+ PNDIS_BUFFER NdisBuffer;
+
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ if (NdisBuffer != NULL) {
+ NdisFreeBuffer (NdisBuffer);
+ }
+
+ NdisFreePacket (NdisPacket);
+ ExFreePool (TransportUIFrame);
+ --DeviceContext->UIFrameAllocated;
+
+ DeviceContext->MemoryUsage -= DeviceContext->UIFrameLength;
+
+} /* NbfDeallocateUIFrame */
+
+
+VOID
+NbfAllocateSendPacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_PACKET *TransportSendPacket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for a send packet. Some initialization
+ is done here.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ TransportSendPacket - Returns a pointer to the packet, or NULL if no
+ storage can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PTP_PACKET Packet;
+ NDIS_STATUS NdisStatus;
+ PNDIS_PACKET NdisPacket;
+ PSEND_PACKET_TAG SendTag;
+ PNDIS_BUFFER NdisBuffer;
+ PNBF_POOL_LIST_DESC SendPacketPoolDesc;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + DeviceContext->PacketLength) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("NBF: Could not allocate send packet: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 107,
+ DeviceContext->PacketLength,
+ PACKET_RESOURCE_ID);
+ *TransportSendPacket = NULL;
+ return;
+ }
+
+ Packet = (PTP_PACKET)ExAllocatePoolWithTag (
+ NonPagedPool,
+ DeviceContext->PacketLength,
+ 'pFBN');
+ if (Packet == NULL) {
+ PANIC("NBF: Could not allocate send packet: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 207,
+ DeviceContext->PacketLength,
+ PACKET_RESOURCE_ID);
+ *TransportSendPacket = NULL;
+ return;
+ }
+ RtlZeroMemory (Packet, DeviceContext->PacketLength);
+
+ DeviceContext->MemoryUsage += DeviceContext->PacketLength;
+
+ NdisStatus = NbfAllocateNdisSendPacket(DeviceContext, &NdisPacket);
+#if 0
+ for (SendPacketPoolDesc = DeviceContext->SendPacketPoolDesc;
+ SendPacketPoolDesc != NULL;
+ SendPacketPoolDesc = SendPacketPoolDesc->Next) {
+
+ NdisAllocatePacket (
+ &NdisStatus,
+ &NdisPacket,
+ SendPacketPoolDesc->PoolHandle);
+
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS)
+ break;
+ }
+#endif
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ ExFreePool (Packet);
+#if 0
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 307,
+ 0,
+ PACKET_RESOURCE_ID);
+#endif
+ *TransportSendPacket = NULL;
+ return;
+ }
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ DeviceContext->NdisBufferPool,
+ Packet->Header,
+ DeviceContext->PacketHeaderLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 407,
+ 0,
+ PACKET_RESOURCE_ID);
+ NdisFreePacket (NdisPacket);
+ ExFreePool (Packet);
+ *TransportSendPacket = NULL;
+ return;
+ }
+
+ NdisChainBufferAtFront (NdisPacket, NdisBuffer);
+
+ Packet->NdisPacket = NdisPacket;
+ SendTag = (PSEND_PACKET_TAG)NdisPacket->ProtocolReserved;
+ SendTag->Type = TYPE_I_FRAME;
+ SendTag->Frame = Packet;
+ SendTag->Owner = DeviceContext;
+
+ Packet->Type = NBF_PACKET_SIGNATURE;
+ Packet->Size = sizeof (TP_PACKET);
+ Packet->Provider = DeviceContext;
+ Packet->Owner = NULL; // no connection/irpsp yet.
+ Packet->Action = PACKET_ACTION_IRP_SP;
+ Packet->PacketizeConnection = FALSE;
+ Packet->PacketNoNdisBuffer = FALSE;
+ Packet->ProviderInterlock = &DeviceContext->Interlock;
+// KeInitializeSpinLock (&Packet->Interlock);
+
+ ++DeviceContext->PacketAllocated;
+
+ *TransportSendPacket = Packet;
+
+} /* NbfAllocateSendPacket */
+
+
+VOID
+NbfDeallocateSendPacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_PACKET TransportSendPacket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for a send packet.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ TransportSendPacket - A pointer to the send packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PACKET NdisPacket = TransportSendPacket->NdisPacket;
+ PNDIS_BUFFER NdisBuffer;
+
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ if (NdisBuffer != NULL) {
+ NdisFreeBuffer (NdisBuffer);
+ }
+
+ NdisFreePacket (NdisPacket);
+ ExFreePool (TransportSendPacket);
+
+ --DeviceContext->PacketAllocated;
+ DeviceContext->MemoryUsage -= DeviceContext->PacketLength;
+
+} /* NbfDeallocateSendPacket */
+
+
+VOID
+NbfAllocateReceivePacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PNDIS_PACKET *TransportReceivePacket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for a receive packet. Some initialization
+ is done here.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ TransportReceivePacket - Returns a pointer to the packet, or NULL if no
+ storage can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS NdisStatus;
+ PNDIS_PACKET NdisPacket;
+ PRECEIVE_PACKET_TAG ReceiveTag;
+
+ //
+ // This does not count in DeviceContext->MemoryUsage because
+ // the storage is allocated when we allocate the packet pool.
+ //
+
+ NdisStatus = NbfAllocateNdisRcvPacket(DeviceContext, &NdisPacket);
+#if 0
+ NdisAllocatePacket (
+ &NdisStatus,
+ &NdisPacket,
+ DeviceContext->ReceivePacketPoolDesc->PoolHandle);
+#endif
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+#if 0
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 309,
+ 0,
+ RECEIVE_PACKET_RESOURCE_ID);
+#endif
+ *TransportReceivePacket = NULL;
+ return;
+ }
+
+ ReceiveTag = (PRECEIVE_PACKET_TAG)(NdisPacket->ProtocolReserved);
+ ReceiveTag->PacketType = TYPE_AT_INDICATE;
+
+ ++DeviceContext->ReceivePacketAllocated;
+
+ *TransportReceivePacket = NdisPacket;
+
+} /* NbfAllocateReceivePacket */
+
+
+VOID
+NbfDeallocateReceivePacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNDIS_PACKET TransportReceivePacket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for a receive packet.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ TransportReceivePacket - A pointer to the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NdisFreePacket (TransportReceivePacket);
+
+ --DeviceContext->ReceivePacketAllocated;
+
+} /* NbfDeallocateReceivePacket */
+
+
+VOID
+NbfAllocateReceiveBuffer(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PBUFFER_TAG *TransportReceiveBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for a receive buffer. Some initialization
+ is done here.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ TransportReceiveBuffer - Returns a pointer to the buffer, or NULL if no
+ storage can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PBUFFER_TAG BufferTag;
+ NDIS_STATUS NdisStatus;
+ PNDIS_BUFFER NdisBuffer;
+
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + RECEIVE_BUFFER_QUOTA(DeviceContext)) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("NBF: Could not allocate receive buffer: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 108,
+ RECEIVE_BUFFER_QUOTA(DeviceContext),
+ RECEIVE_BUFFER_RESOURCE_ID);
+ *TransportReceiveBuffer = NULL;
+ return;
+ }
+
+ //
+ // BUGBUG: The Aligned doesn't help since the header makes it unaligned.
+ //
+
+ BufferTag = (PBUFFER_TAG)ExAllocatePoolWithTag (
+ NonPagedPoolCacheAligned,
+ DeviceContext->ReceiveBufferLength,
+ 'tFBN');
+
+ if (BufferTag == NULL) {
+ PANIC("NBF: Could not allocate receive buffer: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 208,
+ DeviceContext->ReceiveBufferLength,
+ RECEIVE_BUFFER_RESOURCE_ID);
+
+ *TransportReceiveBuffer = NULL;
+ return;
+ }
+
+ DeviceContext->MemoryUsage += RECEIVE_BUFFER_QUOTA(DeviceContext);
+
+ //
+ // point to the buffer for NDIS
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ DeviceContext->NdisBufferPool,
+ BufferTag->Buffer,
+ DeviceContext->MaxReceivePacketSize);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ PANIC("NBF: Could not allocate receive buffer: no buffer\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 308,
+ 0,
+ RECEIVE_BUFFER_RESOURCE_ID);
+ ExFreePool (BufferTag);
+ *TransportReceiveBuffer = NULL;
+ return;
+ }
+
+ BufferTag->Length = DeviceContext->MaxReceivePacketSize;
+ BufferTag->NdisBuffer = NdisBuffer;
+
+ ++DeviceContext->ReceiveBufferAllocated;
+
+ *TransportReceiveBuffer = BufferTag;
+
+} /* NbfAllocateReceiveBuffer */
+
+
+VOID
+NbfDeallocateReceiveBuffer(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PBUFFER_TAG TransportReceiveBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for a receive buffer.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ TransportReceiveBuffer - A pointer to the buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NdisFreeBuffer (TransportReceiveBuffer->NdisBuffer);
+ ExFreePool (TransportReceiveBuffer);
+
+ --DeviceContext->ReceiveBufferAllocated;
+ DeviceContext->MemoryUsage -= RECEIVE_BUFFER_QUOTA(DeviceContext);
+
+} /* NbfDeallocateReceiveBuffer */
+
+
+NTSTATUS
+NbfCreatePacket(
+ PDEVICE_CONTEXT DeviceContext,
+ PTP_LINK Link,
+ PTP_PACKET *Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool,
+ and prepares the MAC and DLC headers for use by the connection.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ Link - The link the packet will be sent over.
+
+ Packet - Pointer to a place where we will return a pointer to the
+ allocated packet.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PSINGLE_LIST_ENTRY s;
+ PTP_PACKET ThePacket;
+ PDLC_I_FRAME DlcHdr;
+#if DBG
+ PNBF_HDR_CONNECTION NbfHdr;
+#endif
+ typedef struct _SIXTEEN_BYTES {
+ ULONG Data[4];
+ } SIXTEEN_BYTES, *PSIXTEEN_BYTES;
+
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NbfCreatePacket: Entered.\n");
+ }
+
+ //
+ // Make sure that structure packing hasn't happened.
+ //
+
+ ASSERT (sizeof(NBF_HDR_CONNECTION) == 14);
+
+#if defined(NBF_UP)
+ s = DeviceContext->PacketPool.Next;
+ if (s != NULL) {
+ DeviceContext->PacketPool.Next = s->Next;
+ }
+#else
+ s = ExInterlockedPopEntryList (
+ &DeviceContext->PacketPool,
+ &DeviceContext->Interlock);
+#endif
+
+ if (s == NULL) {
+ NbfGrowSendPacketPool(DeviceContext);
+
+#if defined(NBF_UP)
+ s = DeviceContext->PacketPool.Next;
+ if (s != NULL) {
+ DeviceContext->PacketPool.Next = s->Next;
+ }
+#else
+ s = ExInterlockedPopEntryList (
+ &DeviceContext->PacketPool,
+ &DeviceContext->Interlock);
+#endif
+ if (s == NULL) {
+#if DBG
+ ++Link->CreatePacketFailures;
+ if ((ULONG)Link->CreatePacketFailures >= NbfCreatePacketThreshold) {
+ if (NbfPacketPanic) {
+ NbfPrint1 ("NbfCreatePacket: PANIC! no more packets in provider's pool (%d times).\n",
+ Link->CreatePacketFailures);
+ }
+ Link->CreatePacketFailures = 0;
+ }
+#endif
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+ ++DeviceContext->PacketExhausted;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ }
+#if DBG
+ Link->CreatePacketFailures = 0;
+#endif
+
+ ThePacket = CONTAINING_RECORD (s, TP_PACKET, Linkage);
+
+ //
+ // NOTE: ThePacket->Action and ThePacket->Owner are filled
+ // in by the caller of this function.
+ //
+
+ ThePacket->ReferenceCount = 1; // automatic ref count of 1.
+ ThePacket->Link = NULL; // no link yet.
+ ThePacket->PacketSent = FALSE;
+ ASSERT (ThePacket->Action == PACKET_ACTION_IRP_SP);
+ ASSERT (ThePacket->PacketNoNdisBuffer == FALSE);
+ ASSERT (ThePacket->PacketizeConnection == FALSE);
+
+ //
+ // Initialize the MAC header for this packet, using the connection's
+ // link pre-built header.
+ //
+
+ if (Link->HeaderLength <= 14) {
+
+ *(PSIXTEEN_BYTES)ThePacket->Header = *(PSIXTEEN_BYTES)Link->Header;
+
+ } else {
+
+ RtlCopyMemory(
+ ThePacket->Header,
+ Link->Header,
+ Link->HeaderLength);
+
+ //
+ // Initialize the TP_FRAME_CONNECTION header for this packet.
+ //
+
+ DlcHdr = (PDLC_I_FRAME)&(ThePacket->Header[Link->HeaderLength]);
+ DlcHdr->Dsap = DSAP_NETBIOS_OVER_LLC;
+ DlcHdr->Ssap = DSAP_NETBIOS_OVER_LLC;
+#if DBG
+ DlcHdr->SendSeq = 0; // known values, will assist debugging.
+ DlcHdr->RcvSeq = 0; // these are assigned at shipment time.
+#endif
+
+ }
+
+
+#if DBG
+ NbfHdr = (PNBF_HDR_CONNECTION)&(ThePacket->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]);
+ NbfHdr->Command = 0xff; // to assist debugging-- assigned later.
+ NbfHdr->Data1 = 0xff; // to assist debugging-- assigned later.
+ NbfHdr->Data2Low = 0xff; // to assist debugging-- assigned later.
+ NbfHdr->Data2High = 0xff; // to assist debugging-- assigned later.
+ TRANSMIT_CORR(NbfHdr) = 0xffff; // to assist debugging-- assigned later.
+ RESPONSE_CORR(NbfHdr) = 0xffff; // to assist debugging-- assigned later.
+ NbfHdr->DestinationSessionNumber = 0xff; // to assist debugging-- assigned later.
+ NbfHdr->SourceSessionNumber = 0xff; // to assist debugging-- assigned later.
+#endif
+
+ *Packet = ThePacket; // return pointer to the packet.
+ return STATUS_SUCCESS;
+} /* NbfCreatePacket */
+
+
+NTSTATUS
+NbfCreateRrPacket(
+ PDEVICE_CONTEXT DeviceContext,
+ PTP_LINK Link,
+ PTP_PACKET *Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates an RR packet from the device context's pool,
+ and prepares the MAC and DLC headers for use by the connection.
+ It first looks in the special RR packet pool, then in the regular
+ packet pool.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ Link - The link the packet will be sent over.
+
+ Packet - Pointer to a place where we will return a pointer to the
+ allocated packet.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PTP_PACKET ThePacket;
+ PDLC_I_FRAME DlcHdr;
+ NTSTATUS Status;
+#if DBG
+ PNBF_HDR_CONNECTION NbfHdr;
+#endif
+ typedef struct _SIXTEEN_BYTES {
+ ULONG Data[4];
+ } SIXTEEN_BYTES, *PSIXTEEN_BYTES;
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NbfCreateRrPacket: Entered.\n");
+ }
+
+ //
+ // Make sure that structure packing hasn't happened.
+ //
+
+ ASSERT (sizeof(NBF_HDR_CONNECTION) == 14);
+
+#if defined(NBF_UP)
+ s = DeviceContext->RrPacketPool.Next;
+ if (s != NULL) {
+ DeviceContext->RrPacketPool.Next = s->Next;
+ }
+#else
+ s = ExInterlockedPopEntryList (
+ &DeviceContext->RrPacketPool,
+ &DeviceContext->Interlock);
+#endif
+
+ if (s == NULL) {
+#if DBG
+ ++Link->CreatePacketFailures;
+ if ((ULONG)Link->CreatePacketFailures >= NbfCreatePacketThreshold) {
+ if (NbfPacketPanic) {
+ NbfPrint1 ("NbfCreateRrPacket: PANIC! no more packets in provider's pool (%d times).\n",
+ Link->CreatePacketFailures);
+ }
+ Link->CreatePacketFailures = 0;
+ }
+#endif
+ //
+ // Try to get one from the regular pool, and mark it so
+ // it goes back there.
+ //
+
+ Status = NbfCreatePacket(
+ DeviceContext,
+ Link,
+ Packet);
+
+ if (Status == STATUS_SUCCESS) {
+ (*Packet)->Action = PACKET_ACTION_NULL;
+ }
+ return Status;
+ }
+#if DBG
+ Link->CreatePacketFailures = 0;
+#endif
+
+ ThePacket = CONTAINING_RECORD (s, TP_PACKET, Linkage);
+
+ //
+ // NOTE: ThePacket->Owner is filled in by the caller of this
+ // function.
+ //
+
+ ThePacket->ReferenceCount = 1; // automatic ref count of 1.
+ ThePacket->Link = NULL; // no link yet.
+ ThePacket->PacketSent = FALSE;
+ ASSERT (ThePacket->Action == PACKET_ACTION_RR);
+ ASSERT (ThePacket->PacketNoNdisBuffer == FALSE);
+
+ //
+ // Initialize the MAC header for this packet, using the connection's
+ // link pre-built header.
+ //
+
+ if (Link->HeaderLength <= 14) {
+
+ *(PSIXTEEN_BYTES)ThePacket->Header = *(PSIXTEEN_BYTES)Link->Header;
+
+ } else {
+
+ RtlCopyMemory(
+ ThePacket->Header,
+ Link->Header,
+ Link->HeaderLength);
+
+ //
+ // Initialize the TP_FRAME_CONNECTION header for this packet.
+ //
+
+ DlcHdr = (PDLC_I_FRAME)&(ThePacket->Header[Link->HeaderLength]);
+ DlcHdr->Dsap = DSAP_NETBIOS_OVER_LLC;
+ DlcHdr->Ssap = DSAP_NETBIOS_OVER_LLC;
+#if DBG
+ DlcHdr->SendSeq = 0; // known values, will assist debugging.
+ DlcHdr->RcvSeq = 0; // these are assigned at shipment time.
+#endif
+
+ }
+
+
+#if DBG
+ NbfHdr = (PNBF_HDR_CONNECTION)&(ThePacket->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]);
+ NbfHdr->Command = 0xff; // to assist debugging-- assigned later.
+ NbfHdr->Data1 = 0xff; // to assist debugging-- assigned later.
+ NbfHdr->Data2Low = 0xff; // to assist debugging-- assigned later.
+ NbfHdr->Data2High = 0xff; // to assist debugging-- assigned later.
+ TRANSMIT_CORR(NbfHdr) = 0xffff; // to assist debugging-- assigned later.
+ RESPONSE_CORR(NbfHdr) = 0xffff; // to assist debugging-- assigned later.
+ NbfHdr->DestinationSessionNumber = 0xff; // to assist debugging-- assigned later.
+ NbfHdr->SourceSessionNumber = 0xff; // to assist debugging-- assigned later.
+#endif
+
+ *Packet = ThePacket; // return pointer to the packet.
+ return STATUS_SUCCESS;
+} /* NbfCreateRrPacket */
+
+
+VOID
+NbfDestroyPacket(
+ PTP_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a packet, thereby returning it to the pool. If
+ it is determined that there is at least one connection waiting for a
+ packet to become available (and it just has), then the connection is
+ removed from the device context's list and AdvanceSend is called to
+ prep the connection further.
+
+Arguments:
+
+ Packet - Pointer to a packet to be returned to the pool.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_CONNECTION Connection;
+ PLIST_ENTRY p;
+ PNDIS_BUFFER HeaderBuffer;
+ PNDIS_BUFFER NdisBuffer;
+ ULONG Flags;
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint2 ("NbfDestroyPacket: Entered, Packet: %lx, NdisPacket: %lx\n",
+ Packet, Packet->NdisPacket);
+ }
+
+ DeviceContext = Packet->Provider;
+
+ //
+ // Strip off and unmap the buffers describing data and header.
+ //
+
+ if (Packet->PacketNoNdisBuffer) {
+
+ //
+ // If the NDIS_BUFFER chain is not ours, then we can't
+ // start unchaining since that would mess up the queue;
+ // instead we just drop the rest of the chain after the
+ // header.
+ //
+
+ NdisQueryPacket (Packet->NdisPacket, NULL, NULL, &HeaderBuffer, NULL);
+ ASSERT (HeaderBuffer != NULL);
+
+ NDIS_BUFFER_LINKAGE(HeaderBuffer) = (PNDIS_BUFFER)NULL;
+ NdisRecalculatePacketCounts (Packet->NdisPacket);
+
+ Packet->PacketNoNdisBuffer = FALSE;
+
+ } else {
+
+ NdisUnchainBufferAtFront (Packet->NdisPacket, &HeaderBuffer);
+ ASSERT (HeaderBuffer != NULL);
+
+ //
+ // Return all the NDIS_BUFFERs to the system.
+ //
+
+ NdisUnchainBufferAtFront (Packet->NdisPacket, &NdisBuffer);
+ while (NdisBuffer != NULL) {
+ NdisFreeBuffer (NdisBuffer);
+ NdisUnchainBufferAtFront (Packet->NdisPacket, &NdisBuffer);
+ }
+
+ NDIS_BUFFER_LINKAGE(HeaderBuffer) = (PNDIS_BUFFER)NULL;
+ NdisChainBufferAtFront (Packet->NdisPacket, HeaderBuffer);
+
+ }
+
+
+ //
+ // invoke the packet deallocate action specified in this packet.
+ //
+
+ switch (Packet->Action) {
+
+ case PACKET_ACTION_NULL:
+ // PANIC ("NbfDestroyPacket: no action.\n");
+ Packet->Action = PACKET_ACTION_IRP_SP;
+ break;
+
+ case PACKET_ACTION_IRP_SP:
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint2 ("NbfDestroyPacket: Packet %x deref IrpSp %x.\n", Packet, Packet->Owner);
+ }
+ NbfDereferenceSendIrp("Destroy packet", (PIO_STACK_LOCATION)(Packet->Owner), RREF_PACKET);
+ break;
+
+ case PACKET_ACTION_CONNECTION:
+ NbfDereferenceConnection ("Destroy packet", (PTP_CONNECTION)(Packet->Owner), CREF_FRAME_SEND);
+ Packet->Action = PACKET_ACTION_IRP_SP;
+ break;
+
+ case PACKET_ACTION_END:
+ NbfDereferenceConnection ("SessionEnd destroyed", (PTP_CONNECTION)(Packet->Owner), CREF_FRAME_SEND);
+ NbfDereferenceConnection ("SessionEnd destroyed", (PTP_CONNECTION)(Packet->Owner), CREF_LINK);
+ Packet->Action = PACKET_ACTION_IRP_SP;
+ break;
+
+ case PACKET_ACTION_RR:
+#if defined(NBF_UP)
+ ((PSINGLE_LIST_ENTRY)&Packet->Linkage)->Next =
+ DeviceContext->RrPacketPool.Next;
+ DeviceContext->RrPacketPool.Next =
+ &((PSINGLE_LIST_ENTRY)&Packet->Linkage)->Next;
+#else
+ ExInterlockedPushEntryList (
+ &DeviceContext->RrPacketPool,
+ (PSINGLE_LIST_ENTRY)&Packet->Linkage,
+ &DeviceContext->Interlock);
+#endif
+ return;
+
+ default:
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint1 ("NbfDestroyPacket: invalid action (%ld).\n", Packet->Action);
+ }
+ ASSERT (FALSE);
+ }
+
+
+ //
+ // Put the packet back for use again.
+ //
+
+#if defined(NBF_UP)
+ ((PSINGLE_LIST_ENTRY)&Packet->Linkage)->Next =
+ DeviceContext->PacketPool.Next;
+ DeviceContext->PacketPool.Next =
+ &((PSINGLE_LIST_ENTRY)&Packet->Linkage)->Next;
+#else
+ ExInterlockedPushEntryList (
+ &DeviceContext->PacketPool,
+ (PSINGLE_LIST_ENTRY)&Packet->Linkage,
+ &DeviceContext->Interlock);
+#endif
+
+ //
+ // If there is a connection waiting to ship out more packets, then
+ // wake it up and start packetizing again.
+ //
+ // We do a quick check without the lock; there is a small
+ // window where we may not take someone off, but this
+ // window exists anyway and we assume that more packets
+ // will be freed in the future.
+ //
+
+ if (IsListEmpty (&DeviceContext->PacketWaitQueue)) {
+ return;
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ if (!(IsListEmpty(&DeviceContext->PacketWaitQueue))) {
+
+ //
+ // Remove a connection from the "packet starved" queue.
+ //
+
+ p = RemoveHeadList (&DeviceContext->PacketWaitQueue);
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, PacketWaitLinkage);
+ Connection->OnPacketWaitQueue = FALSE;
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // If this connection is starved because it couldn't send a
+ // control packet (SI, SC, RO, RC, or DA) then start that
+ // operation up again. Otherwise, just start packetizing.
+ //
+
+ if (Connection->Flags & CONNECTION_FLAGS_STARVED) {
+
+ Flags = Connection->Flags & CONNECTION_FLAGS_STARVED;
+
+ if ((Flags & (Flags-1)) != 0) {
+
+ //
+ // More than one bit is on, use only the low one
+ // (an arbitrary choice).
+ //
+
+#if DBG
+ DbgPrint ("NBF: Connection %lx has two flag bits on %lx\n", Connection, Connection->Flags);
+#endif
+ Flags &= ~(Flags-1);
+
+ }
+
+ Connection->Flags &= ~Flags;
+
+ if ((Connection->Flags & CONNECTION_FLAGS_W_PACKETIZE) ||
+ (Connection->Flags & CONNECTION_FLAGS_STARVED)) {
+
+ //
+ // We are waiting for both a specific packet and
+ // to packetize, or for two specific packets, so
+ // put ourselves back on the queue.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+ if (!Connection->OnPacketWaitQueue) {
+ Connection->OnPacketWaitQueue = TRUE;
+ InsertTailList(
+ &DeviceContext->PacketWaitQueue,
+ &Connection->PacketWaitLinkage);
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+ }
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ if (Flags & CONNECTION_FLAGS_SEND_SI) {
+ NbfSendSessionInitialize (Connection);
+ } else if (Flags & CONNECTION_FLAGS_SEND_SC) {
+ NbfSendSessionConfirm (Connection);
+ } else if (Flags & CONNECTION_FLAGS_SEND_RO) {
+ NbfSendReceiveOutstanding (Connection);
+ } else if (Flags & CONNECTION_FLAGS_SEND_RC) {
+ NbfSendReceiveContinue (Connection);
+ } else if (Flags & CONNECTION_FLAGS_SEND_SE) {
+ NbfSendSessionEnd (
+ Connection,
+ FALSE);
+ } else if (Flags & CONNECTION_FLAGS_SEND_DA) {
+ NbfSendDataAck (Connection);
+ } else {
+ IF_NBFDBG (NBF_DEBUG_PACKET) {
+ NbfPrint0 ("NbfDestroyPacket: connection flags mismanaged.\n");
+ }
+ }
+
+ } else {
+
+ //
+ // Place the connection on the packetize queue and start
+ // packetizing the next connection to be serviced. If he
+ // is already on the packetize queue for some reason, then
+ // don't do this.
+ //
+ // We shouldn't be packetizing in this case!! - adb (7/3/91).
+ // This used to be a check that did nothing if FLAGS_PACKETIZE
+ // was set, but if that happens something is wrong...
+ //
+
+ ASSERT (Connection->Flags & CONNECTION_FLAGS_W_PACKETIZE);
+ Connection->Flags &= ~CONNECTION_FLAGS_W_PACKETIZE;
+
+ Connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
+
+ if ((Connection->Flags & CONNECTION_FLAGS_READY) &&
+ !(Connection->Flags & CONNECTION_FLAGS_PACKETIZE)) {
+
+ Connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
+
+ NbfReferenceConnection ("Packet available", Connection, CREF_PACKETIZE_QUEUE);
+
+ ExInterlockedInsertTailList(
+ &DeviceContext->PacketizeQueue,
+ &Connection->PacketizeLinkage,
+ &DeviceContext->SpinLock);
+ }
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ PacketizeConnections (DeviceContext);
+
+ }
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ }
+
+} /* NbfDestroyPacket */
+
+VOID NbfGrowSendPacketPool(PDEVICE_CONTEXT DeviceContext)
+{
+
+ NDIS_STATUS NdisStatus;
+ PNBF_POOL_LIST_DESC SendPacketPoolDesc;
+ PTP_PACKET TransportSendPacket;
+ UINT i;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + DeviceContext->PacketLength) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("NBF: Could not grow send packet pool: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 107,
+ DeviceContext->PacketLength,
+ PACKET_RESOURCE_ID);
+ return;
+ }
+
+ for (i = 0; i < PACKET_POOL_GROW_COUNT; i += 1) {
+ NbfAllocateSendPacket(DeviceContext, &TransportSendPacket);
+
+ if (TransportSendPacket != NULL) {
+ ExInterlockedPushEntryList(&(DeviceContext)->PacketPool,
+ (PSINGLE_LIST_ENTRY)&TransportSendPacket->Linkage,
+ &(DeviceContext)->Interlock);
+ }
+ else {
+ break;
+ }
+ }
+
+ if (i == PACKET_POOL_GROW_COUNT) {
+ return;
+ }
+
+#ifdef DBG
+ DbgBreakPoint();
+#endif // DBG
+
+}
+
+#if DBG
+VOID
+NbfReferencePacket(
+ PTP_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increases the number of reasons why a packet cannot be
+ discarded.
+
+Arguments:
+
+ Packet - Pointer to a packet to be referenced.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ IF_NBFDBG (NBF_DEBUG_PACKET) {
+ NbfPrint3 ("NbfReferencePacket: Entered, NdisPacket: %lx Packet: %lx Ref Count: %lx.\n",
+ Packet->NdisPacket, Packet, Packet->ReferenceCount);
+ }
+
+ result = InterlockedIncrement (&Packet->ReferenceCount);
+
+ ASSERT (result >= 0);
+
+} /* NbfReferencePacket */
+
+
+VOID
+NbfDereferencePacket(
+ PTP_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport packet by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ NbfDestroyPacket to remove it from the system.
+
+Arguments:
+
+ Packet - Pointer to a packet object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&Packet->ReferenceCount);
+
+ //
+ // If we have deleted all references to this packet, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the packet any longer.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_PACKET) {
+ NbfPrint1 ("NbfDereferencePacket: Entered, result: %lx\n", result);
+ }
+
+ ASSERT (result >= 0);
+
+ if (result == 0) {
+ NbfDestroyPacket (Packet);
+ }
+
+} /* NbfDereferencePacket */
+#endif
+
+
+VOID
+NbfWaitPacket(
+ PTP_CONNECTION Connection,
+ ULONG Flags
+ )
+
+/*++
+
+Routine Description:
+
+ This routine causes the specified connection to be put into a wait
+ state pending the availability of a packet to send the specified
+ frame.
+
+Arguments:
+
+ Connection - Pointer to the connection object to be paused.
+
+ Flags - Bitflag indicating which specific frame should be resent.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+
+ IF_NBFDBG (NBF_DEBUG_PACKET) {
+ NbfPrint0 ("NbfWaitPacket: Entered.\n");
+ }
+
+ DeviceContext = Connection->Provider;
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // Now put this connection on the device context's PacketWaitQueue,
+ // but only if it isn't already queued there. This state is managed
+ // with the OnPacketWaitQueue variable.
+ //
+ // If the connection is stopping, don't queue him either.
+ //
+
+ if ((Connection->Flags & CONNECTION_FLAGS_READY) ||
+ (Flags == CONNECTION_FLAGS_SEND_SE)) {
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ //
+ // Turn on the bitflag that indicates which frame we couldn't send.
+ //
+
+#if DBG
+ if (Flags == CONNECTION_FLAGS_SEND_SE) {
+ DbgPrint ("NBF: Inserting connection %lx on PacketWait for SESSION_END\n", Connection);
+ }
+#endif
+ Connection->Flags |= Flags;
+
+ if (!Connection->OnPacketWaitQueue) {
+
+ Connection->OnPacketWaitQueue = TRUE;
+ InsertTailList (
+ &DeviceContext->PacketWaitQueue,
+ &Connection->PacketWaitLinkage);
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+} /* NbfWaitPacket */
+
+
+#if MAGIC
+VOID
+NbfSendMagicBullet (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a magic bullet on the net that can be used to trigger
+ sniffers or other such things.
+
+Arguments:
+
+ DeviceContext - pointer to the device context
+
+ Link - This is needed to call NbfCreatePacket
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ NDIS_STATUS NdisStatus;
+ PTP_UI_FRAME RawFrame;
+ PUCHAR Header;
+ PNDIS_BUFFER NdisBuffer;
+ UINT i;
+
+ UNREFERENCED_PARAMETER (Link); // no longer needed
+
+ Status = NbfCreateConnectionlessFrame (DeviceContext, &RawFrame);
+ if (!NT_SUCCESS (Status)) { // couldn't make frame.
+#if DBG
+ DbgPrint ("NbfSendMagicBullet: Couldn't allocate frame!\n");
+#endif
+ return;
+ }
+
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ DeviceContext->NdisBufferPool,
+ DeviceContext->MagicBullet,
+ 32);
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ Header = (PUCHAR)&RawFrame->Header;
+
+ for (i=0;i<6;i++) {
+ Header[i] = MAGIC_BULLET_FOOD;
+ Header[i+6] = DeviceContext->LocalAddress.Address[i];
+ }
+
+ Header[12] = 0;
+ Header[13] = (UCHAR)(DeviceContext->UIFrameHeaderLength + 18);
+
+ for (i=14;i<DeviceContext->UIFrameHeaderLength;i++) {
+ Header[i] = MAGIC_BULLET_FOOD;
+ }
+
+ NdisChainBufferAtBack (RawFrame->NdisPacket, NdisBuffer);
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ FALSE); // no loopback
+
+ }
+
+ return;
+
+}
+#endif
+
diff --git a/private/ntos/tdi/nbf/precomp.h b/private/ntos/tdi/nbf/precomp.h
new file mode 100644
index 000000000..4b3c3c642
--- /dev/null
+++ b/private/ntos/tdi/nbf/precomp.h
@@ -0,0 +1,219 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ nbf.h
+
+Abstract:
+
+ Private include file for the NBF (NetBIOS Frames Protocol) transport
+ provider subcomponent of the NTOS project.
+
+Author:
+
+ Stephen E. Jones (stevej) 25-Oct-1989
+
+Revision History:
+
+ David Beaver (dbeaver) 24-Sep-1990
+ Remove PDI and PC586-specific support; add NDIS support
+
+--*/
+
+#include <ntddk.h>
+
+#include <windef.h>
+#include <nb30.h>
+//#include <ntiologc.h>
+//#include <ctype.h>
+//#include <assert.h>
+//#include <stdio.h>
+//#include <stdlib.h>
+//#include <memory.h>
+//#include <nt.h>
+//#include <ntrtl.h>
+//#include <nturtl.h>
+//#include <string.h>
+//#include <windows.h>
+
+#ifdef BUILD_FOR_511
+#define ExAllocatePoolWithTag(a,b,c) ExAllocatePool(a,b)
+#endif
+
+typedef struct _RTL_SPLAY_LINKS {
+ struct _RTL_SPLAY_LINKS *Parent;
+ struct _RTL_SPLAY_LINKS *LeftChild;
+ struct _RTL_SPLAY_LINKS *RightChild;
+} RTL_SPLAY_LINKS;
+typedef RTL_SPLAY_LINKS *PRTL_SPLAY_LINKS;
+
+#define RtlInitializeSplayLinks(Links) { \
+ PRTL_SPLAY_LINKS _SplayLinks; \
+ _SplayLinks = (PRTL_SPLAY_LINKS)(Links); \
+ _SplayLinks->Parent = _SplayLinks; \
+ _SplayLinks->LeftChild = NULL; \
+ _SplayLinks->RightChild = NULL; \
+ }
+
+#define RtlLeftChild(Links) ( \
+ (PRTL_SPLAY_LINKS)(Links)->LeftChild \
+ )
+
+#define RtlRightChild(Links) ( \
+ (PRTL_SPLAY_LINKS)(Links)->RightChild \
+ )
+
+#define RtlInsertAsLeftChild(ParentLinks,ChildLinks) { \
+ PRTL_SPLAY_LINKS _SplayParent; \
+ PRTL_SPLAY_LINKS _SplayChild; \
+ _SplayParent = (PRTL_SPLAY_LINKS)(ParentLinks); \
+ _SplayChild = (PRTL_SPLAY_LINKS)(ChildLinks); \
+ _SplayParent->LeftChild = _SplayChild; \
+ _SplayChild->Parent = _SplayParent; \
+ }
+
+#define RtlInsertAsRightChild(ParentLinks,ChildLinks) { \
+ PRTL_SPLAY_LINKS _SplayParent; \
+ PRTL_SPLAY_LINKS _SplayChild; \
+ _SplayParent = (PRTL_SPLAY_LINKS)(ParentLinks); \
+ _SplayChild = (PRTL_SPLAY_LINKS)(ChildLinks); \
+ _SplayParent->RightChild = _SplayChild; \
+ _SplayChild->Parent = _SplayParent; \
+ }
+
+
+PRTL_SPLAY_LINKS
+NTAPI
+RtlDelete (
+ PRTL_SPLAY_LINKS Links
+ );
+
+
+#include <tdikrnl.h> // Transport Driver Interface.
+
+#include <ndis.h> // Physical Driver Interface.
+
+#if DEVL
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+#include "nbfconst.h" // private NETBEUI constants.
+#include "nbfmac.h" // mac-specific definitions
+#include "nbfhdrs.h" // private NETBEUI protocol headers.
+#include "nbftypes.h" // private NETBEUI types.
+#include "nbfcnfg.h" // configuration information.
+#include "nbfprocs.h" // private NETBEUI function prototypes.
+#ifdef MEMPRINT
+#include "memprint.h" // drt's memory debug print
+#endif
+
+#if defined(NT_UP) && defined(DRIVERS_UP)
+#define NBF_UP 1
+#endif
+
+#ifndef NBF_LOCKS
+
+#if !defined(NBF_UP)
+
+#define ACQUIRE_SPIN_LOCK(lock,irql) KeAcquireSpinLock(lock,irql)
+#define RELEASE_SPIN_LOCK(lock,irql) KeReleaseSpinLock(lock,irql)
+#define ACQUIRE_DPC_SPIN_LOCK(lock) KeAcquireSpinLockAtDpcLevel(lock)
+#define RELEASE_DPC_SPIN_LOCK(lock) KeReleaseSpinLockFromDpcLevel(lock)
+
+#else // NBF_UP
+
+#define ACQUIRE_SPIN_LOCK(lock,irql) ExAcquireSpinLock(lock,irql)
+#define RELEASE_SPIN_LOCK(lock,irql) ExReleaseSpinLock(lock,irql)
+#define ACQUIRE_DPC_SPIN_LOCK(lock)
+#define RELEASE_DPC_SPIN_LOCK(lock)
+
+#endif
+
+#if DBG
+
+#define ACQUIRE_C_SPIN_LOCK(lock,irql) { \
+ PTP_CONNECTION _conn = CONTAINING_RECORD(lock,TP_CONNECTION,SpinLock); \
+ KeAcquireSpinLock(lock,irql); \
+ _conn->LockAcquired = TRUE; \
+ strncpy(_conn->LastAcquireFile, strrchr(__FILE__,'\\')+1, 7); \
+ _conn->LastAcquireLine = __LINE__; \
+}
+#define RELEASE_C_SPIN_LOCK(lock,irql) { \
+ PTP_CONNECTION _conn = CONTAINING_RECORD(lock,TP_CONNECTION,SpinLock); \
+ _conn->LockAcquired = FALSE; \
+ strncpy(_conn->LastReleaseFile, strrchr(__FILE__,'\\')+1, 7); \
+ _conn->LastReleaseLine = __LINE__; \
+ KeReleaseSpinLock(lock,irql); \
+}
+
+#define ACQUIRE_DPC_C_SPIN_LOCK(lock) { \
+ PTP_CONNECTION _conn = CONTAINING_RECORD(lock,TP_CONNECTION,SpinLock); \
+ KeAcquireSpinLockAtDpcLevel(lock); \
+ _conn->LockAcquired = TRUE; \
+ strncpy(_conn->LastAcquireFile, strrchr(__FILE__,'\\')+1, 7); \
+ _conn->LastAcquireLine = __LINE__; \
+}
+#define RELEASE_DPC_C_SPIN_LOCK(lock) { \
+ PTP_CONNECTION _conn = CONTAINING_RECORD(lock,TP_CONNECTION,SpinLock); \
+ _conn->LockAcquired = FALSE; \
+ strncpy(_conn->LastReleaseFile, strrchr(__FILE__,'\\')+1, 7); \
+ _conn->LastReleaseLine = __LINE__; \
+ KeReleaseSpinLockFromDpcLevel(lock); \
+}
+
+#else // DBG
+
+#define ACQUIRE_C_SPIN_LOCK(lock,irql) ACQUIRE_SPIN_LOCK(lock,irql)
+#define RELEASE_C_SPIN_LOCK(lock,irql) RELEASE_SPIN_LOCK(lock,irql)
+#define ACQUIRE_DPC_C_SPIN_LOCK(lock) ACQUIRE_DPC_SPIN_LOCK(lock)
+#define RELEASE_DPC_C_SPIN_LOCK(lock) RELEASE_DPC_SPIN_LOCK(lock)
+
+#endif // DBG
+
+#define ENTER_NBF
+#define LEAVE_NBF
+
+#else
+
+VOID
+NbfAcquireSpinLock(
+ IN PKSPIN_LOCK Lock,
+ OUT PKIRQL OldIrql,
+ IN PSZ LockName,
+ IN PSZ FileName,
+ IN ULONG LineNumber
+ );
+
+VOID
+NbfReleaseSpinLock(
+ IN PKSPIN_LOCK Lock,
+ IN KIRQL OldIrql,
+ IN PSZ LockName,
+ IN PSZ FileName,
+ IN ULONG LineNumber
+ );
+
+#define ACQUIRE_SPIN_LOCK(lock,irql) \
+ NbfAcquireSpinLock( lock, irql, #lock, __FILE__, __LINE__ )
+#define RELEASE_SPIN_LOCK(lock,irql) \
+ NbfReleaseSpinLock( lock, irql, #lock, __FILE__, __LINE__ )
+
+#define ACQUIRE_DPC_SPIN_LOCK(lock) \
+ { \
+ KIRQL OldIrql; \
+ NbfAcquireSpinLock( lock, &OldIrql, #lock, __FILE__, __LINE__ ); \
+ }
+#define RELEASE_DPC_SPIN_LOCK(lock) \
+ NbfReleaseSpinLock( lock, DISPATCH_LEVEL, #lock, __FILE__, __LINE__ )
+
+#define ENTER_NBF \
+ NbfAcquireSpinLock( (PKSPIN_LOCK)NULL, (PKIRQL)NULL, "(Global)", __FILE__, __LINE__ )
+#define LEAVE_NBF \
+ NbfReleaseSpinLock( (PKSPIN_LOCK)NULL, (KIRQL)-1, "(Global)", __FILE__, __LINE__ )
+
+#endif
+
diff --git a/private/ntos/tdi/nbf/rcv.c b/private/ntos/tdi/nbf/rcv.c
new file mode 100644
index 000000000..8fdc87af9
--- /dev/null
+++ b/private/ntos/tdi/nbf/rcv.c
@@ -0,0 +1,309 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ rcv.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiReceive
+ o TdiReceiveDatagram
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+NTSTATUS
+NbfTdiReceive(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiReceive request for the transport provider.
+
+Arguments:
+
+ Irp - I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTP_CONNECTION connection;
+ KIRQL oldirql;
+ PIO_STACK_LOCATION irpSp;
+
+ //
+ // verify that the operation is taking place on a connection. At the same
+ // time we do this, we reference the connection. This ensures it does not
+ // get removed out from under us. Note also that we do the connection
+ // lookup within a try/except clause, thus protecting ourselves against
+ // really bogus handles
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // Check that this is really a connection.
+ //
+
+ if ((connection->Size != sizeof (TP_CONNECTION)) ||
+ (connection->Type != NBF_CONNECTION_SIGNATURE)) {
+#if DBG
+ NbfPrint2 ("TdiReceive: Invalid Connection %lx Irp %lx\n", connection, Irp);
+#endif
+ return STATUS_INVALID_CONNECTION;
+ }
+
+ //
+ // Initialize bytes transferred here.
+ //
+
+ Irp->IoStatus.Information = 0; // reset byte transfer count.
+
+ // This reference is removed by NbfDestroyRequest.
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ if ((connection->Flags & CONNECTION_FLAGS_READY) == 0) {
+
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ Irp->IoStatus.Status = connection->Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ status = STATUS_PENDING;
+
+ } else {
+ KIRQL cancelIrql;
+
+ //
+ // Once the reference is in, LinkSpinLock will be valid.
+ //
+
+ NbfReferenceConnection("TdiReceive request", connection, CREF_RECEIVE_IRP);
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ ACQUIRE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ IRP_RECEIVE_IRP(irpSp) = Irp;
+ IRP_RECEIVE_REFCOUNT(irpSp) = 1;
+
+#if DBG
+ NbfReceives[NbfReceivesNext].Irp = Irp;
+ NbfReceives[NbfReceivesNext].Request = NULL;
+ NbfReceives[NbfReceivesNext].Connection = (PVOID)connection;
+ NbfReceivesNext = (NbfReceivesNext++) % TRACK_TDI_LIMIT;
+#endif
+
+ //
+ // If this IRP has been cancelled, complete it now.
+ //
+
+ if (Irp->Cancel) {
+
+#if DBG
+ NbfCompletedReceives[NbfCompletedReceivesNext].Irp = Irp;
+ NbfCompletedReceives[NbfCompletedReceivesNext].Request = NULL;
+ NbfCompletedReceives[NbfCompletedReceivesNext].Status = STATUS_CANCELLED;
+ {
+ ULONG i,j,k;
+ PUCHAR va;
+ PMDL mdl;
+
+ mdl = Irp->MdlAddress;
+
+ NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = (UCHAR)0;
+
+ i = 1;
+ while (i<TRACK_TDI_CAPTURE) {
+ if (mdl == NULL) break;
+ va = MmGetSystemAddressForMdl (mdl);
+ j = MmGetMdlByteCount (mdl);
+
+ for (i=i,k=0;i<TRACK_TDI_CAPTURE&k<j;i++,k++) {
+ NbfCompletedReceives[NbfCompletedReceivesNext].Contents[i] = *va++;
+ }
+ mdl = mdl->Next;
+ }
+ }
+
+ NbfCompletedReceivesNext = (NbfCompletedReceivesNext++) % TRACK_TDI_LIMIT;
+#endif
+
+ //
+ // It is safe to do this with locks held.
+ //
+ NbfCompleteReceiveIrp (Irp, STATUS_CANCELLED, 0);
+
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ } else {
+
+ //
+ // Insert onto the receive queue, and make the IRP
+ // cancellable.
+ //
+
+ InsertTailList (&connection->ReceiveQueue,&Irp->Tail.Overlay.ListEntry);
+ IoSetCancelRoutine(Irp, NbfCancelReceive);
+
+ //
+ // Release the cancel spinlock out of order. Since we were
+ // already at dpc level when it was acquired, we don't
+ // need to swap irqls.
+ //
+ ASSERT(cancelIrql == DISPATCH_LEVEL);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ //
+ // This call releases the link spinlock, and references the
+ // connection first if it needs to access it after
+ // releasing the lock.
+ //
+
+ AwakenReceive (connection); // awaken if sleeping.
+
+ }
+
+ status = STATUS_PENDING;
+
+ }
+
+ KeLowerIrql (oldirql);
+
+ return status;
+} /* TdiReceive */
+
+
+NTSTATUS
+NbfTdiReceiveDatagram(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiReceiveDatagram request for the transport
+ provider. Receive datagrams just get queued up to an address, and are
+ completed when a DATAGRAM or DATAGRAM_BROADCAST frame is received at
+ the address.
+
+Arguments:
+
+ Irp - I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ KIRQL oldirql;
+ PTP_ADDRESS address;
+ PTP_ADDRESS_FILE addressFile;
+ PIO_STACK_LOCATION irpSp;
+ KIRQL cancelIrql;
+
+ //
+ // verify that the operation is taking place on an address. At the same
+ // time we do this, we reference the address. This ensures it does not
+ // get removed out from under us. Note also that we do the address
+ // lookup within a try/except clause, thus protecting ourselves against
+ // really bogus handles
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+ addressFile = irpSp->FileObject->FsContext;
+
+ status = NbfVerifyAddressObject (addressFile);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+#if DBG
+ if (((PTDI_REQUEST_KERNEL_RECEIVEDG)(&irpSp->Parameters))->ReceiveLength > 0) {
+ ASSERT (Irp->MdlAddress != NULL);
+ }
+#endif
+
+ address = addressFile->Address;
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ ACQUIRE_SPIN_LOCK (&address->SpinLock,&oldirql);
+
+ if ((address->Flags & (ADDRESS_FLAGS_STOPPING | ADDRESS_FLAGS_CONFLICT)) != 0) {
+
+ RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = (address->Flags & ADDRESS_FLAGS_STOPPING) ?
+ STATUS_NETWORK_NAME_DELETED : STATUS_DUPLICATE_NAME;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ } else {
+
+ //
+ // If this IRP has been cancelled, then call the
+ // cancel routine.
+ //
+
+ if (Irp->Cancel) {
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ } else {
+
+ IoSetCancelRoutine(Irp, NbfCancelReceiveDatagram);
+ NbfReferenceAddress ("Receive datagram", address, AREF_REQUEST);
+ InsertTailList (&addressFile->ReceiveDatagramQueue,&Irp->Tail.Overlay.ListEntry);
+ RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
+ IoReleaseCancelSpinLock(cancelIrql);
+ }
+
+ }
+
+ NbfDereferenceAddress ("Temp rcv datagram", address, AREF_VERIFY);
+
+ return STATUS_PENDING;
+
+} /* TdiReceiveDatagram */
+
diff --git a/private/ntos/tdi/nbf/rcveng.c b/private/ntos/tdi/nbf/rcveng.c
new file mode 100644
index 000000000..f3b3eab33
--- /dev/null
+++ b/private/ntos/tdi/nbf/rcveng.c
@@ -0,0 +1,823 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ rcveng.c
+
+Abstract:
+
+ This module contains code that implements the receive engine for the
+ Jetbeui transport provider. This code is responsible for the following
+ basic activities:
+
+ 1. Transitioning a TdiReceive request from an inactive state on the
+ connection's ReceiveQueue to the active state on that connection
+ (ActivateReceive).
+
+ 2. Advancing the status of the active receive request by copying 0 or
+ more bytes of data from an incoming DATA_FIRST_MIDDLE or DATA_ONLY_LAST
+ NBF frame.
+
+ 3. Completing receive requests.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+VOID
+ActivateReceive(
+ PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine activates the next TdiReceive request on the specified
+ connection object if there is no active request on that connection
+ already. This allows the request to accept data on the connection.
+
+ NOTE: THIS FUNCTION MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PIRP Irp;
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ActivateReceive: Entered.\n");
+ }
+
+ //
+ // The ACTIVE_RECEIVE bitflag will be set on the connection if
+ // the receive-fields in the CONNECTION object are valid. If
+ // this flag is cleared, then we try to make the next TdiReceive
+ // request in the ReceiveQueue the active request.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ if (!(Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE)) {
+ if (!IsListEmpty (&Connection->ReceiveQueue)) {
+
+ //
+ // Found a receive, so make it the active one.
+ //
+
+ Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
+
+ Irp = CONTAINING_RECORD(
+ Connection->ReceiveQueue.Flink,
+ IRP,
+ Tail.Overlay.ListEntry);
+ Connection->MessageBytesReceived = 0;
+ Connection->MessageBytesAcked = 0;
+ Connection->MessageInitAccepted = 0;
+ Connection->CurrentReceiveIrp = Irp;
+ Connection->CurrentReceiveSynchronous =
+ Connection->Provider->MacInfo.SingleReceive;
+ Connection->CurrentReceiveMdl = Irp->MdlAddress;
+ Connection->ReceiveLength = IRP_RECEIVE_LENGTH(IoGetCurrentIrpStackLocation(Irp));
+ Connection->ReceiveByteOffset = 0;
+ }
+ }
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ActivateReceive: Exiting.\n");
+ }
+} /* ActivateReceive */
+
+
+VOID
+AwakenReceive(
+ PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to reactivate a sleeping connection with the
+ RECEIVE_WAKEUP bitflag set because data arrived for which no receive
+ was available. The caller has made a receive available at the connection,
+ so here we activate the next receive, and send the appropriate protocol
+ to restart the message at the first byte offset past the one received
+ by the last receive.
+
+ NOTE: THIS FUNCTION MUST BE CALLED AT DPC LEVEL. IT IS CALLED
+ WITH CONNECTION->LINKSPINLOCK HELD.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" AwakenReceive: Entered.\n");
+ }
+
+ //
+ // If the RECEIVE_WAKEUP bitflag is set, then awaken the connection.
+ //
+
+ if (Connection->Flags & CONNECTION_FLAGS_RECEIVE_WAKEUP) {
+ if (Connection->ReceiveQueue.Flink != &Connection->ReceiveQueue) {
+ Connection->Flags &= ~CONNECTION_FLAGS_RECEIVE_WAKEUP;
+
+ //
+ // Found a receive, so turn off the wakeup flag, activate
+ // the next receive, and send the protocol.
+ //
+
+ //
+ // Quick fix: So there is no window where a receive
+ // is active but the bit is not on (otherwise we could
+ // accept whatever data happens to show up in the
+ // interim).
+ //
+
+ Connection->Flags |= CONNECTION_FLAGS_W_RESYNCH;
+
+ NbfReferenceConnection ("temp AwakenReceive", Connection, CREF_BY_ID); // release lookup hold.
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ ActivateReceive (Connection);
+
+ //
+ // BUGBUG: What if this fails? The successful queueing
+ // of a RCV_O should cause ActivateReceive to be called.
+ //
+ // NOTE: Send this after ActivateReceive, since that
+ // is where the MessageBytesAcked/Received variables
+ // are initialized.
+ //
+
+ NbfSendReceiveOutstanding (Connection);
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" AwakenReceive: Returned from NbfSendReceive.\n");
+ }
+
+ NbfDereferenceConnection("temp AwakenReceive", Connection, CREF_BY_ID);
+ return;
+ }
+ }
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+} /* AwakenReceive */
+
+
+VOID
+CompleteReceive(
+ PTP_CONNECTION Connection,
+ BOOLEAN EndOfMessage,
+ IN ULONG BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by ProcessIncomingData when the current receive
+ must be completed. Depending on whether the current frame being
+ processed is a DATA_FIRST_MIDDLE or DATA_ONLY_LAST, and also whether
+ all of the data was processed, the EndOfMessage flag will be set accordingly
+ by the caller to indicate that a message boundary was received.
+
+ NOTE: THIS FUNCTION MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+ EndOfMessage - BOOLEAN set to true if TDI_END_OF_RECORD should be reported.
+
+ BytesTransferred - Number of bytes copied in this receive.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PIRP Irp;
+ ULONG BytesReceived;
+ PIO_STACK_LOCATION IrpSp;
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" CompleteReceive: Entered.\n");
+ }
+
+
+ if (Connection->SpecialReceiveIrp) {
+
+ PIRP Irp = Connection->SpecialReceiveIrp;
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = BytesTransferred;
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Connection->Flags |= CONNECTION_FLAGS_RC_PENDING;
+ Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE;
+ Connection->SpecialReceiveIrp = FALSE;
+
+ ++Connection->ReceivedTsdus;
+
+ ExInterlockedInsertHeadList(
+ &Connection->Provider->IrpCompletionQueue,
+ &Irp->Tail.Overlay.ListEntry,
+ Connection->ProviderInterlock);
+
+ //
+ // NOTE: NbfAcknowledgeDataOnlyLast releases
+ // the connection spinlock.
+ //
+
+ NbfAcknowledgeDataOnlyLast(
+ Connection,
+ Connection->MessageBytesReceived
+ );
+
+ } else {
+ KIRQL cancelIrql;
+
+ if (EndOfMessage) {
+
+ //
+ // The messages has been completely received, ack it.
+ //
+ // We set DEFERRED_ACK and DEFERRED_NOT_Q here, which
+ // will cause an ack to be piggybacked if any data is
+ // sent during the call to CompleteReceive. If this
+ // does not happen, then we will call AcknowledgeDataOnlyLast
+ // which will will send a DATA ACK or queue a request for
+ // a piggyback ack. We do this *after* calling CompleteReceive
+ // so we know that we will complete the receive back to
+ // the client before we ack the data, to prevent the
+ // next receive from being sent before this one is
+ // completed.
+ //
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Connection->DeferredFlags |=
+ (CONNECTION_FLAGS_DEFERRED_ACK | CONNECTION_FLAGS_DEFERRED_NOT_Q);
+ Connection->Flags |= CONNECTION_FLAGS_RC_PENDING;
+
+ } else {
+
+ //
+ // Send a receive outstanding (even though we don't
+ // know that we have a receive) to get him to
+ // reframe his send. Pre-2.0 clients require a
+ // no receive before the receive outstanding.
+ //
+ // BUGBUG: what if this fails (due to no send packets)?
+ //
+
+ if ((Connection->Flags & CONNECTION_FLAGS_VERSION2) == 0) {
+ NbfSendNoReceive (Connection);
+ }
+ NbfSendReceiveOutstanding (Connection);
+
+ //
+ // If there is a receive posted, make it current and
+ // send a receive outstanding.
+ //
+ // BUGBUG: need general function for this, which sends
+ // NO_RECEIVE if appropriate.
+ //
+
+ ActivateReceive (Connection);
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ }
+
+ //
+ // If we indicated to the client, adjust this down by the
+ // amount of data taken, when it hits zero we can reindicate.
+ //
+
+ if (Connection->ReceiveBytesUnaccepted) {
+ if (Connection->MessageBytesReceived >= Connection->ReceiveBytesUnaccepted) {
+ Connection->ReceiveBytesUnaccepted = 0;
+ } else {
+ Connection->ReceiveBytesUnaccepted -= Connection->MessageBytesReceived;
+ }
+ }
+
+ //
+ // NOTE: The connection lock is held here.
+ //
+
+ if (IsListEmpty (&Connection->ReceiveQueue)) {
+
+ ASSERT ((Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) != 0);
+
+ //
+ // Release the cancel spinlock out of order. Since we were
+ // already at DPC level when it was acquired, there is no
+ // need to swap irqls.
+ //
+ ASSERT(cancelIrql == DISPATCH_LEVEL);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ } else {
+
+ Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE;
+ BytesReceived = Connection->MessageBytesReceived;
+
+
+ //
+ // Complete the TdiReceive request at the head of the
+ // connection's ReceiveQueue.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" CompleteReceive: Normal IRP is present.\n");
+ }
+
+ p = RemoveHeadList (&Connection->ReceiveQueue);
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+
+ IoSetCancelRoutine(Irp, NULL);
+
+ //
+ // Release the cancel spinlock out of order. Since we were
+ // already at DPC level when it was acquired, there is no
+ // need to swap irqls.
+ //
+ ASSERT(cancelIrql == DISPATCH_LEVEL);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ //
+ // If this request should generate no back traffic, then
+ // disable piggyback acks for it.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ if (IRP_RECEIVE_FLAGS(IrpSp) & TDI_RECEIVE_NO_RESPONSE_EXP) {
+ Connection->CurrentReceiveAckQueueable = FALSE;
+ }
+
+#if DBG
+ NbfCompletedReceives[NbfCompletedReceivesNext].Irp = Irp;
+ NbfCompletedReceives[NbfCompletedReceivesNext].Request = NULL;
+ NbfCompletedReceives[NbfCompletedReceivesNext].Status =
+ EndOfMessage ? STATUS_SUCCESS : STATUS_BUFFER_OVERFLOW;
+ {
+ ULONG i,j,k;
+ PUCHAR va;
+ PMDL mdl;
+
+ mdl = Irp->MdlAddress;
+
+ if (BytesReceived > TRACK_TDI_CAPTURE) {
+ NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = 0xFF;
+ } else {
+ NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = (UCHAR)BytesReceived;
+ }
+
+ i = 1;
+ while (i<TRACK_TDI_CAPTURE) {
+ if (mdl == NULL) break;
+ va = MmGetSystemAddressForMdl (mdl);
+ j = MmGetMdlByteCount (mdl);
+
+ for (i=i,k=0;i<TRACK_TDI_CAPTURE&k<j;i++,k++) {
+ NbfCompletedReceives[NbfCompletedReceivesNext].Contents[i] = *va++;
+ }
+ mdl = mdl->Next;
+ }
+ }
+
+ NbfCompletedReceivesNext = (NbfCompletedReceivesNext++) % TRACK_TDI_LIMIT;
+#endif
+ ++Connection->ReceivedTsdus;
+
+ //
+ // This can be called with locks held.
+ //
+ NbfCompleteReceiveIrp(
+ Irp,
+ EndOfMessage ? STATUS_SUCCESS : STATUS_BUFFER_OVERFLOW,
+ BytesReceived);
+
+ }
+
+
+ //
+ // If NOT_Q is still set, that means that the deferred ack was
+ // not satisfied by anything resulting from the call to
+ // CompleteReceive, so we need to ack or queue an ack here.
+ //
+
+
+ if ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_NOT_Q) != 0) {
+
+ Connection->DeferredFlags &=
+ ~(CONNECTION_FLAGS_DEFERRED_ACK | CONNECTION_FLAGS_DEFERRED_NOT_Q);
+
+ //
+ // NOTE: NbfAcknowledgeDataOnlyLast releases
+ // the connection spinlock.
+ //
+
+ NbfAcknowledgeDataOnlyLast(
+ Connection,
+ Connection->MessageBytesReceived
+ );
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ }
+
+ }
+
+} /* CompleteReceive */
+
+
+VOID
+NbfCancelReceive(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a receive.
+ The receive is found on the connection's receive queue; if it
+ is the current request it is cancelled and the connection
+ goes into "cancelled receive" mode, otherwise it is cancelled
+ silently.
+
+ In "cancelled receive" mode the connection makes it appear to
+ the remote the data is being received, but in fact it is not
+ indicated to the transport or buffered on our end
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PIO_STACK_LOCATION IrpSp;
+ PIRP ReceiveIrp;
+ PTP_CONNECTION Connection;
+ PLIST_ENTRY p;
+ ULONG BytesReceived;
+ BOOLEAN Found;
+
+ UNREFERENCED_PARAMETER (DeviceObject);
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (IrpSp->MinorFunction == TDI_RECEIVE));
+
+ Connection = IrpSp->FileObject->FsContext;
+
+ //
+ // Since this IRP is still in the cancellable state, we know
+ // that the connection is still around (although it may be in
+ // the process of being torn down).
+ //
+
+ //
+ // See if this is the IRP for the current receive request.
+ //
+
+ ACQUIRE_SPIN_LOCK (Connection->LinkSpinLock, &oldirql);
+
+ BytesReceived = Connection->MessageBytesReceived;
+
+ p = Connection->ReceiveQueue.Flink;
+
+ //
+ // If there is a receive active and it is not a special
+ // IRP, then see if this is it.
+ //
+
+ if (((Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE) != 0) &&
+ (!Connection->SpecialReceiveIrp)) {
+
+ ReceiveIrp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+
+ if (ReceiveIrp == Irp) {
+
+ //
+ // yes, it is the active receive. Turn on the RCV_CANCELLED
+ // bit instructing the connection to drop the rest of the
+ // data received (until the DOL comes in).
+ //
+
+ Connection->Flags |= CONNECTION_FLAGS_RCV_CANCELLED;
+ Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE;
+
+ (VOID)RemoveHeadList (&Connection->ReceiveQueue);
+
+#if DBG
+ NbfCompletedReceives[NbfCompletedReceivesNext].Irp = ReceiveIrp;
+ NbfCompletedReceives[NbfCompletedReceivesNext].Request = NULL;
+ NbfCompletedReceives[NbfCompletedReceivesNext].Status = STATUS_CANCELLED;
+ {
+ ULONG i,j,k;
+ PUCHAR va;
+ PMDL mdl;
+
+ mdl = ReceiveIrp->MdlAddress;
+
+ if (BytesReceived > TRACK_TDI_CAPTURE) {
+ NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = 0xFF;
+ } else {
+ NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = (UCHAR)BytesReceived;
+ }
+
+ i = 1;
+ while (i<TRACK_TDI_CAPTURE) {
+ if (mdl == NULL) break;
+ va = MmGetSystemAddressForMdl (mdl);
+ j = MmGetMdlByteCount (mdl);
+
+ for (i=i,k=0;i<TRACK_TDI_CAPTURE&k<j;i++,k++) {
+ NbfCompletedReceives[NbfCompletedReceivesNext].Contents[i] = *va++;
+ }
+ mdl = mdl->Next;
+ }
+ }
+
+ NbfCompletedReceivesNext = (NbfCompletedReceivesNext++) % TRACK_TDI_LIMIT;
+#endif
+
+ RELEASE_SPIN_LOCK (Connection->LinkSpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+#if DBG
+ DbgPrint("NBF: Canceled in-progress receive %lx on %lx\n",
+ Irp, Connection);
+#endif
+
+ //
+ // The following dereference will complete the I/O, provided removes
+ // the last reference on the request object. The I/O will complete
+ // with the status and information stored in the Irp. Therefore,
+ // we set those values here before the dereference.
+ //
+
+ NbfCompleteReceiveIrp (ReceiveIrp, STATUS_CANCELLED, 0);
+ return;
+
+ }
+
+ }
+
+
+ //
+ // If we fall through to here, the IRP was not the active receive.
+ // Scan through the list, looking for this IRP.
+ //
+
+ Found = FALSE;
+
+ while (p != &Connection->ReceiveQueue) {
+
+ ReceiveIrp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ if (ReceiveIrp == Irp) {
+
+ //
+ // Found it, remove it from the list here.
+ //
+
+ RemoveEntryList (p);
+
+ Found = TRUE;
+
+#if DBG
+ NbfCompletedReceives[NbfCompletedReceivesNext].Irp = ReceiveIrp;
+ NbfCompletedReceives[NbfCompletedReceivesNext].Request = NULL;
+ NbfCompletedReceives[NbfCompletedReceivesNext].Status = STATUS_CANCELLED;
+ {
+ ULONG i,j,k;
+ PUCHAR va;
+ PMDL mdl;
+
+ mdl = ReceiveIrp->MdlAddress;
+
+ if (BytesReceived > TRACK_TDI_CAPTURE) {
+ NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = 0xFF;
+ } else {
+ NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = (UCHAR)BytesReceived;
+ }
+
+ i = 1;
+ while (i<TRACK_TDI_CAPTURE) {
+ if (mdl == NULL) break;
+ va = MmGetSystemAddressForMdl (mdl);
+ j = MmGetMdlByteCount (mdl);
+
+ for (i=i,k=0;i<TRACK_TDI_CAPTURE&k<j;i++,k++) {
+ NbfCompletedReceives[NbfCompletedReceivesNext].Contents[i] = *va++;
+ }
+ mdl = mdl->Next;
+ }
+ }
+
+ NbfCompletedReceivesNext = (NbfCompletedReceivesNext++) % TRACK_TDI_LIMIT;
+#endif
+
+ RELEASE_SPIN_LOCK (Connection->LinkSpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+#if DBG
+ DbgPrint("NBF: Canceled receive %lx on %lx\n",
+ ReceiveIrp, Connection);
+#endif
+
+ //
+ // The following dereference will complete the I/O, provided removes
+ // the last reference on the request object. The I/O will complete
+ // with the status and information stored in the Irp. Therefore,
+ // we set those values here before the dereference.
+ //
+
+ NbfCompleteReceiveIrp (ReceiveIrp, STATUS_CANCELLED, 0);
+ break;
+
+ }
+
+ p = p->Flink;
+
+ }
+
+ if (!Found) {
+
+ //
+ // We didn't find it!
+ //
+
+#if DBG
+ DbgPrint("NBF: Tried to cancel receive %lx on %lx, not found\n",
+ Irp, Connection);
+#endif
+ RELEASE_SPIN_LOCK (Connection->LinkSpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+ }
+
+}
+
+
+VOID
+NbfCancelReceiveDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a receive
+ datagram. The receive is looked for on the address file's
+ receive datagram queue; if it is found it is cancelled.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PIO_STACK_LOCATION IrpSp;
+ PTP_ADDRESS_FILE AddressFile;
+ PTP_ADDRESS Address;
+ PLIST_ENTRY p;
+ BOOLEAN Found;
+
+ UNREFERENCED_PARAMETER (DeviceObject);
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (IrpSp->MinorFunction == TDI_RECEIVE_DATAGRAM));
+
+ AddressFile = IrpSp->FileObject->FsContext;
+ Address = AddressFile->Address;
+
+ //
+ // Since this IRP is still in the cancellable state, we know
+ // that the address file is still around (although it may be in
+ // the process of being torn down). See if the IRP is on the list.
+ //
+
+ Found = FALSE;
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ for (p = AddressFile->ReceiveDatagramQueue.Flink;
+ p != &AddressFile->ReceiveDatagramQueue;
+ p = p->Flink) {
+
+ if (CONTAINING_RECORD(p, IRP, Tail.Overlay.ListEntry) == Irp) {
+ RemoveEntryList (p);
+ Found = TRUE;
+ break;
+ }
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ if (Found) {
+
+#if DBG
+ DbgPrint("NBF: Canceled receive datagram %lx on %lx\n",
+ Irp, AddressFile);
+#endif
+
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ NbfDereferenceAddress ("Receive DG cancelled", Address, AREF_REQUEST);
+
+ } else {
+
+#if DBG
+ DbgPrint("NBF: Tried to cancel receive datagram %lx on %lx, not found\n",
+ Irp, AddressFile);
+#endif
+
+ }
+
+} /* NbfCancelReceiveDatagram */
+
diff --git a/private/ntos/tdi/nbf/request.c b/private/ntos/tdi/nbf/request.c
new file mode 100644
index 000000000..5547e31ee
--- /dev/null
+++ b/private/ntos/tdi/nbf/request.c
@@ -0,0 +1,1376 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ request.c
+
+Abstract:
+
+ This module contains code which implements the TP_REQUEST object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport request objects.
+
+Author:
+
+ David Beaver (dbeaver) 1 July 1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef RASAUTODIAL
+#include <acd.h>
+#include <acdapi.h>
+#endif // RASAUTODIAL
+
+//
+// External variables
+//
+#ifdef RASAUTODIAL
+extern BOOLEAN fAcdLoadedG;
+extern ACD_DRIVER AcdDriverG;
+
+//
+// Imported routines
+//
+VOID
+NbfNoteNewConnection(
+ PTP_CONNECTION Connection,
+ PDEVICE_CONTEXT DeviceContext
+ );
+#endif // RASAUTODIAL
+
+
+VOID
+NbfTdiRequestTimeoutHandler(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is executed as a DPC at DISPATCH_LEVEL when a request
+ such as TdiSend, TdiReceive, TdiSendDatagram, TdiReceiveDatagram, etc.,
+ encounters a timeout. This routine cleans up the activity and cancels it.
+
+Arguments:
+
+ Dpc - Pointer to a system DPC object.
+
+ DeferredContext - Pointer to the TP_REQUEST block representing the
+ request that has timed out.
+
+ SystemArgument1 - Not used.
+
+ SystemArgument2 - Not used.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PTP_REQUEST Request;
+ PTP_CONNECTION Connection;
+#if DBG
+ LARGE_INTEGER time, difference;
+#endif
+ PIO_STACK_LOCATION IrpSp;
+ PTDI_REQUEST_KERNEL_QUERY_INFORMATION query;
+ PDEVICE_CONTEXT DeviceContext;
+
+ Dpc, SystemArgument1, SystemArgument2; // prevent compiler warnings
+
+ ENTER_NBF;
+
+ Request = (PTP_REQUEST)DeferredContext;
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint1 ("RequestTimeoutHandler: Entered, Request %lx\n", Request);
+ }
+
+ ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql);
+ Request->Flags &= ~REQUEST_FLAGS_TIMER;
+ if ((Request->Flags & REQUEST_FLAGS_STOPPING) == 0) {
+
+#if DBG
+ KeQuerySystemTime (&time);
+ difference.QuadPart = time.QuadPart - (Request->Time).QuadPart;
+ NbfPrint1 ("RequestTimeoutHandler: Request timed out, queued for %ld seconds\n",
+ difference.LowPart / SECONDS);
+#endif
+
+ //
+ // find reason for timeout
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket);
+ if (IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) {
+ switch (IrpSp->MinorFunction) {
+
+ //
+ // none of these should time out.
+ //
+
+ case TDI_SEND:
+ case TDI_ACCEPT:
+ case TDI_SET_INFORMATION:
+ case TDI_SET_EVENT_HANDLER:
+ case TDI_SEND_DATAGRAM:
+ case TDI_RECEIVE_DATAGRAM:
+ case TDI_RECEIVE:
+
+#if DBG
+ NbfPrint1 ("RequestTimeoutHandler: Request: %lx Timed out, and shouldn't have!\n",
+ Request);
+#endif
+ ASSERT (FALSE);
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ NbfCompleteRequest (Request, STATUS_IO_TIMEOUT, 0);
+ break;
+
+
+ case TDI_LISTEN:
+ case TDI_CONNECT:
+
+#if DBG
+ NbfPrint2 ("RequestTimeoutHandler: %s Failed, Request: %lx\n",
+ IrpSp->MinorFunction == TDI_LISTEN ?
+ "Listen" :
+ IrpSp->MinorFunction == TDI_CONNECT ?
+ "Connect" : "Disconnect",
+ Request);
+#endif
+ Connection = (PTP_CONNECTION)(Request->Context);
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+
+ //
+ // Since these requests are part of the connection
+ // itself, we just stop the connection and the
+ // request will get torn down then. If we get the
+ // situation where the request times out before
+ // it is queued to the connection, then the code
+ // that is about to queue it will check the STOPPING
+ // flag and complete it then.
+ //
+ // Don't stop the connection if an automatic connection
+ // is in progress.
+ //
+
+#if DBG
+ DbgPrint("RequestTimeoutHandler: AUTOCONNECTING=0x%x\n", Connection->Flags2 & CONNECTION_FLAGS2_AUTOCONNECTING);
+#endif
+ if (!(Connection->Flags2 & CONNECTION_FLAGS2_AUTOCONNECTING))
+ NbfStopConnection (Connection, STATUS_IO_TIMEOUT);
+ break;
+
+ case TDI_DISCONNECT:
+
+ //
+ // We don't create requests for TDI_DISCONNECT any more.
+ //
+
+ ASSERT(FALSE);
+ break;
+
+ case TDI_QUERY_INFORMATION:
+
+ DeviceContext = (PDEVICE_CONTEXT)IrpSp->FileObject->DeviceObject;
+ query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&IrpSp->Parameters;
+
+ IF_NBFDBG (NBF_DEBUG_DEVCTX) {
+ NbfPrint1 ("RequestTimeout: %lx:\n", DeviceContext);
+ }
+
+ //
+ // Determine if the request is done, or if we should
+ // requeue it.
+ //
+
+ --Request->Retries;
+
+ if (Request->Retries > 0) {
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+
+ //
+ // Send another packet out, and restart the timer.
+ //
+
+ if (query->QueryType == TDI_QUERY_FIND_NAME) {
+
+ NbfSendQueryFindName (
+ DeviceContext,
+ Request);
+
+ } else if (query->QueryType == TDI_QUERY_ADAPTER_STATUS) {
+
+ PUCHAR SingleSR;
+ UINT SingleSRLength;
+
+ //
+ // Send the STATUS_QUERY frames out as
+ // single-route source routing.
+ //
+ // BUGBUG: On a second status query this should
+ // really be sent directed, but currently we
+ // don't record the address anywhere.
+ //
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SingleSR,
+ &SingleSRLength);
+
+ NbfSendStatusQuery (
+ DeviceContext,
+ Request,
+ &DeviceContext->NetBIOSAddress,
+ SingleSR,
+ SingleSRLength);
+
+ } else {
+
+ ASSERT (FALSE);
+
+ }
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+
+ //
+ // That's it, we retried enough, complete it.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
+ RemoveEntryList (&Request->Linkage);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ if (Request->BytesWritten > 0) {
+
+ NbfCompleteRequest (Request, STATUS_SUCCESS, Request->BytesWritten);
+
+ } else {
+
+ NbfCompleteRequest (Request, STATUS_IO_TIMEOUT, Request->BytesWritten);
+
+ }
+
+
+ }
+
+ break;
+
+ default:
+#if DBG
+ NbfPrint2 ("RequestTimeoutHandler: Unknown Request Timed out, Request: %lx Type: %x\n",
+ Request, IrpSp->MinorFunction);
+#endif
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ break;
+
+ } // end of switch
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+
+ }
+
+ NbfDereferenceRequest ("Timeout", Request, RREF_TIMER); // for the timeout
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ NbfDereferenceRequest ("Timeout: stopping", Request, RREF_TIMER); // for the timeout
+
+ }
+
+ LEAVE_NBF;
+ return;
+
+} /* RequestTimeoutHandler */
+
+
+VOID
+NbfAllocateRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_REQUEST *TransportRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a request packet from nonpaged pool and initializes
+ it to a known state.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ TransportRequest - Pointer to a place where this routine will return
+ a pointer to a transport request structure. It returns NULL if no
+ storage can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PTP_REQUEST Request;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + sizeof(TP_REQUEST)) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("NBF: Could not allocate request: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 104,
+ sizeof(TP_REQUEST),
+ REQUEST_RESOURCE_ID);
+ *TransportRequest = NULL;
+ return;
+ }
+
+ Request = (PTP_REQUEST)ExAllocatePoolWithTag (
+ NonPagedPool,
+ sizeof (TP_REQUEST),
+ 'rFBN');
+ if (Request == NULL) {
+ PANIC("NBF: Could not allocate request: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 204,
+ sizeof(TP_REQUEST),
+ REQUEST_RESOURCE_ID);
+ *TransportRequest = NULL;
+ return;
+ }
+ RtlZeroMemory (Request, sizeof(TP_REQUEST));
+
+ DeviceContext->MemoryUsage += sizeof(TP_REQUEST);
+ ++DeviceContext->RequestAllocated;
+
+ Request->Type = NBF_REQUEST_SIGNATURE;
+ Request->Size = sizeof (TP_REQUEST);
+
+ Request->ResponseBuffer = NULL;
+
+ Request->Provider = DeviceContext;
+ Request->ProviderInterlock = &DeviceContext->Interlock;
+ KeInitializeSpinLock (&Request->SpinLock);
+ KeInitializeDpc (&Request->Dpc, NbfTdiRequestTimeoutHandler, (PVOID)Request);
+ KeInitializeTimer (&Request->Timer); // set to not-signaled state.
+
+ *TransportRequest = Request;
+
+} /* NbfAllocateRequest */
+
+
+VOID
+NbfDeallocateRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_REQUEST TransportRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees a request packet.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ TransportRequest - Pointer to a transport request structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ExFreePool (TransportRequest);
+ --DeviceContext->RequestAllocated;
+ DeviceContext->MemoryUsage -= sizeof(TP_REQUEST);
+
+} /* NbfDeallocateRequest */
+
+
+NTSTATUS
+NbfCreateRequest(
+ IN PIRP Irp,
+ IN PVOID Context,
+ IN ULONG Flags,
+ IN PMDL Buffer2,
+ IN ULONG Buffer2Length,
+ IN LARGE_INTEGER Timeout,
+ OUT PTP_REQUEST * TpRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a transport request and associates it with the
+ specified IRP, context, and queue. All major requests, including
+ TdiSend, TdiSendDatagram, TdiReceive, and TdiReceiveDatagram requests,
+ are composed in this manner.
+
+Arguments:
+
+ Irp - Pointer to an IRP which was received by the transport for this
+ request.
+
+ Context - Pointer to anything to associate this request with. This
+ value is not interpreted except at request cancelation time.
+
+ Flags - A set of bitflags indicating the disposition of this request.
+
+ Timeout - Timeout value (if non-zero) to start a timer for this request.
+ If zero, then no timer is activated for the request.
+
+ TpRequest - If the function returns STATUS_SUCCESS, this will return
+ pointer to the TP_REQUEST structure allocated.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_REQUEST Request;
+ PLIST_ENTRY p;
+ PIO_STACK_LOCATION irpSp;
+#if DBG
+ LARGE_INTEGER Time;
+#endif
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint0 ("NbfCreateRequest: Entered.\n");
+ }
+
+ irpSp = IoGetCurrentIrpStackLocation(Irp);
+ DeviceContext = (PDEVICE_CONTEXT)irpSp->FileObject->DeviceObject;
+
+#if DBG
+ if (!MmIsNonPagedSystemAddressValid (DeviceContext->RequestPool.Flink)) {
+ NbfPrint2 ("NbfCreateRequest: RequestList hosed: %lx DeviceContext: %lx\n",
+ &DeviceContext->RequestPool, DeviceContext);
+ }
+#endif
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ p = RemoveHeadList (&DeviceContext->RequestPool);
+ if (p == &DeviceContext->RequestPool) {
+
+ if ((DeviceContext->RequestMaxAllocated == 0) ||
+ (DeviceContext->RequestAllocated < DeviceContext->RequestMaxAllocated)) {
+
+ NbfAllocateRequest (DeviceContext, &Request);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Allocated request at %lx\n", Request);
+ }
+
+ } else {
+
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 404,
+ sizeof(TP_REQUEST),
+ REQUEST_RESOURCE_ID);
+ Request = NULL;
+
+ }
+
+ if (Request == NULL) {
+ ++DeviceContext->RequestExhausted;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ PANIC ("NbfCreateConnection: Could not allocate request object!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ } else {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+
+ }
+
+ ++DeviceContext->RequestInUse;
+ if (DeviceContext->RequestInUse > DeviceContext->RequestMaxInUse) {
+ ++DeviceContext->RequestMaxInUse;
+ }
+
+ DeviceContext->RequestTotal += DeviceContext->RequestInUse;
+ ++DeviceContext->RequestSamples;
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+
+ //
+ // fill out the request.
+ //
+
+ // Request->Provider = DeviceContext;
+ Request->IoRequestPacket = Irp;
+ Request->Buffer2 = Buffer2;
+ Request->Buffer2Length = Buffer2Length;
+ Request->Flags = Flags;
+ Request->Context = Context;
+ Request->ReferenceCount = 1; // initialize reference count.
+
+#if DBG
+ {
+ UINT Counter;
+ for (Counter = 0; Counter < NUMBER_OF_RREFS; Counter++) {
+ Request->RefTypes[Counter] = 0;
+ }
+
+ // This reference is removed by NbfCompleteRequest
+
+ Request->RefTypes[RREF_CREATION] = 1;
+ }
+#endif
+
+#if DBG
+ Request->Completed = FALSE;
+ Request->Destroyed = FALSE;
+ Request->TotalReferences = 0;
+ Request->TotalDereferences = 0;
+ Request->NextRefLoc = 0;
+ ExInterlockedInsertHeadList (&NbfGlobalRequestList, &Request->GlobalLinkage, &NbfGlobalInterlock);
+ StoreRequestHistory (Request, TRUE);
+#endif
+
+#if DBG
+ KeQuerySystemTime (&Time); // ugly, but effective
+ Request->Time.LowPart = Time.LowPart;
+ Request->Time.HighPart = Time.HighPart;
+#endif
+
+ IF_NBFDBG (NBF_DEBUG_IRP) {
+ if (Irp->MdlAddress != NULL) {
+ PMDL mdl;
+ NbfPrint2 ("NbfCreateRequest: Map request %lx Irp %lx MdlChain \n",
+ Request, Request->IoRequestPacket);
+ mdl = Request->Buffer2;
+ while (mdl != NULL) {
+ NbfPrint4 ("Mdl %lx Va %lx StartVa %lx Flags %x\n",
+ mdl, MmGetSystemAddressForMdl(mdl), MmGetMdlVirtualAddress(mdl),
+ mdl->MdlFlags);
+ mdl = mdl->Next;
+ }
+ }
+ }
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint3 ("NbfCreateRequest: Request %lx Buffer2: %lx Irp: %lx\n", Request,
+ Buffer2, Irp);
+ }
+
+ if ((Timeout.LowPart == 0) && (Timeout.HighPart == 0)) {
+
+ // no timeout
+ } else {
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint3 ("NbfCreateRequest: Starting timer %lx%lx Flags %lx\n",
+ Timeout.HighPart, Timeout.LowPart, Request->Flags);
+ }
+ Request->Flags |= REQUEST_FLAGS_TIMER; // there is a timeout on this request.
+ KeInitializeTimer (&Request->Timer); // set to not-signaled state.
+ NbfReferenceRequest ("Create: timer", Request, RREF_TIMER); // one for the timer
+ KeSetTimer (&Request->Timer, Timeout, &Request->Dpc);
+ }
+
+ *TpRequest = Request;
+
+ return STATUS_SUCCESS;
+} /* NbfCreateRequest */
+
+
+VOID
+NbfDestroyRequest(
+ IN PTP_REQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns a request block to the free pool.
+
+Arguments:
+
+ Request - Pointer to a TP_REQUEST block to return to the free pool.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PIO_STACK_LOCATION irpSp;
+ PDEVICE_CONTEXT DeviceContext;
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint0 ("NbfDestroyRequest: Entered.\n");
+ }
+
+#if DBG
+ if (Request->Destroyed) {
+ NbfPrint1 ("attempt to destroy already-destroyed request 0x%lx\n", Request);
+ DbgBreakPoint ();
+ }
+ Request->Destroyed = TRUE;
+#if 1
+ ACQUIRE_SPIN_LOCK (&NbfGlobalInterlock, &oldirql);
+ RemoveEntryList (&Request->GlobalLinkage);
+ RELEASE_SPIN_LOCK (&NbfGlobalInterlock, oldirql);
+#else
+ ExInterlockedRemoveHeadList (Request->GlobalLinkage.Blink, &NbfGlobalInterlock);
+#endif
+#endif
+ ASSERT(Request->Completed);
+
+ //
+ // Return the request to the caller with whatever status is in the IRP.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_IRP) {
+ NbfPrint1 ("NbfCompleteRequest: Completing IRP: %lx\n",
+ Request->IoRequestPacket);
+ }
+
+ //
+ // Now dereference the owner of this request so that we are safe when
+ // we finally tear down the {connection, address}. The problem we're
+ // facing here is that we can't allow the user to assume semantics;
+ // the end of life for a connection must truly be the real end of life.
+ // for that to occur, we reference the owning object when the request is
+ // created and we dereference it just before we return it to the pool.
+ //
+
+ switch (Request->Owner) {
+ case ConnectionType:
+ NbfDereferenceConnection ("Removing Connection",((PTP_CONNECTION)Request->Context), CREF_REQUEST);
+ break;
+
+#if DBG
+ case AddressType:
+ ASSERT (FALSE);
+ NbfDereferenceAddress ("Removing Address", ((PTP_ADDRESS)Request->Context), AREF_REQUEST);
+ break;
+#endif
+
+ case DeviceContextType:
+ NbfDereferenceDeviceContext ("Removing Address", ((PDEVICE_CONTEXT)Request->Context), DCREF_REQUEST);
+ break;
+ }
+
+ //
+ // Unmap a possibly mapped buffer. We've only mapped the buffer if the
+ // Irp Major function is not method 0. (of 0, 1, 2, and 3.)
+ //
+
+ IF_NBFDBG (NBF_DEBUG_IRP) {
+ {
+ PMDL mdl;
+ NbfPrint2 ("NbfDestroyRequest: Unmap request %lx Irp %lx MdlChain \n",
+ Request, Request->IoRequestPacket);
+ mdl = Request->Buffer2;
+ while (mdl != NULL) {
+ NbfPrint4 ("Mdl %lx Va %lx StartVa %lx Flags %x\n",
+ mdl, MmGetSystemAddressForMdl(mdl), MmGetMdlVirtualAddress(mdl),
+ mdl->MdlFlags);
+ mdl = mdl->Next;
+ }
+ }
+ }
+
+ irpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket);
+ DeviceContext = Request->Provider;
+
+ LEAVE_NBF;
+ IoCompleteRequest (Request->IoRequestPacket, IO_NETWORK_INCREMENT);
+ ENTER_NBF;
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ //
+ // Put the request back on the free list. NOTE: we have the
+ // lock held here.
+ //
+
+
+ DeviceContext->RequestTotal += DeviceContext->RequestInUse;
+ ++DeviceContext->RequestSamples;
+ --DeviceContext->RequestInUse;
+
+ if ((DeviceContext->RequestAllocated - DeviceContext->RequestInUse) >
+ DeviceContext->RequestInitAllocated) {
+ NbfDeallocateRequest (DeviceContext, Request);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Deallocated request at %lx\n", Request);
+ }
+ } else {
+ InsertTailList (&DeviceContext->RequestPool, &Request->Linkage);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+} /* NbfDestroyRequest */
+
+
+#if DBG
+VOID
+NbfRefRequest(
+ IN PTP_REQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport request.
+
+Arguments:
+
+ Request - Pointer to a TP_REQUEST block.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint1 ("NbfRefRequest: Entered, ReferenceCount: %x\n",
+ Request->ReferenceCount);
+ }
+
+#if DBG
+ StoreRequestHistory( Request, TRUE );
+#endif
+
+ ASSERT (Request->ReferenceCount > 0);
+
+ result = InterlockedIncrement (&Request->ReferenceCount);
+
+} /* NbfRefRequest */
+#endif
+
+
+VOID
+NbfDerefRequest(
+ IN PTP_REQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport request by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ NbfDestroyRequest to remove it from the system.
+
+Arguments:
+
+ Request - Pointer to a transport request object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint1 ("NbfDerefRequest: Entered, ReferenceCount: %x\n",
+ Request->ReferenceCount);
+ }
+
+#if DBG
+ StoreRequestHistory( Request, FALSE );
+#endif
+
+ result = InterlockedDecrement (&Request->ReferenceCount);
+
+ ASSERT (result >= 0);
+
+ //
+ // If we have deleted all references to this request, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the request any longer.
+ //
+
+ if (result == 0) {
+ NbfDestroyRequest (Request);
+ }
+
+} /* NbfDerefRequest */
+
+
+VOID
+NbfCompleteRequest(
+ IN PTP_REQUEST Request,
+ IN NTSTATUS Status,
+ IN ULONG Information
+ )
+
+/*++
+
+Routine Description:
+
+ This routine completes a transport request object, completing the I/O,
+ stopping the timeout, and freeing up the request object itself.
+
+Arguments:
+
+ Request - Pointer to a transport request object.
+
+ Status - Actual return status to be assigned to the request. This
+ value may be overridden if the timed-out bitflag is set in the request.
+
+ Information - the information field for the I/O Status Block.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+ NTSTATUS FinalStatus = Status;
+ NTSTATUS CopyStatus;
+ BOOLEAN TimerWasSet;
+
+ ASSERT (Status != STATUS_PENDING);
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint2 ("NbfCompleteRequest: Entered Request %lx, Request->Flags %lx\n",
+ Request, Request->Flags);
+ }
+
+#if DBG
+ if (Request->Completed) {
+ NbfPrint1 ("attempt to completed already-completed request 0x%lx\n", Request);
+ DbgBreakPoint ();
+ }
+ Request->Completed = TRUE;
+#endif
+
+ ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql);
+
+ if ((Request->Flags & REQUEST_FLAGS_STOPPING) == 0) {
+ Request->Flags |= REQUEST_FLAGS_STOPPING;
+
+ //
+ // Cancel the pending timeout on this request. Not all requests
+ // have their timer set. If this request has the TIMER bit set,
+ // then the timer needs to be cancelled. If it cannot be cancelled,
+ // then the timer routine will be run, so we just return and let
+ // the timer routine worry about cleaning up this request.
+ //
+
+ if ((Request->Flags & REQUEST_FLAGS_TIMER) != 0) {
+ Request->Flags &= ~REQUEST_FLAGS_TIMER;
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ TimerWasSet = KeCancelTimer (&Request->Timer);
+
+ if (TimerWasSet) {
+ NbfDereferenceRequest ("Complete: stop timer", Request, RREF_TIMER);
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint1 ("NbfCompleteRequest: Canceled timer: %lx.\n", &Request->Timer);
+ }
+ }
+
+ } else {
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ }
+
+ Irp = Request->IoRequestPacket;
+
+#ifdef RASAUTODIAL
+ //
+ // If this is a connect operation that has
+ // returned with either STATUS_SUCCESS or
+ // STATUS_BAD_NETWORK_PATH, then
+ // inform the automatic connection driver.
+ //
+ if (fAcdLoadedG) {
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ if (IrpSp->MinorFunction == TDI_CONNECT &&
+ FinalStatus == STATUS_SUCCESS)
+ {
+ KIRQL adirql;
+ BOOLEAN fEnabled;
+
+ ACQUIRE_SPIN_LOCK(&AcdDriverG.SpinLock, &adirql);
+ fEnabled = AcdDriverG.fEnabled;
+ RELEASE_SPIN_LOCK(&AcdDriverG.SpinLock, adirql);
+ if (fEnabled) {
+ NbfNoteNewConnection(
+ IrpSp->FileObject->FsContext,
+ (PDEVICE_CONTEXT)IrpSp->FileObject->DeviceObject);
+ }
+ }
+ }
+#endif // RASAUTODIAL
+
+ //
+ // For requests associated with a device context, we need
+ // to copy the data from the temp buffer to the MDL and
+ // free the temp buffer.
+ //
+
+ if (Request->ResponseBuffer != NULL) {
+
+ if ((FinalStatus == STATUS_SUCCESS) ||
+ (FinalStatus == STATUS_BUFFER_OVERFLOW)) {
+
+ CopyStatus = TdiCopyBufferToMdl (
+ Request->ResponseBuffer,
+ 0L,
+ Information,
+ Irp->MdlAddress,
+ 0,
+ &Information);
+
+ if (CopyStatus != STATUS_SUCCESS) {
+ FinalStatus = CopyStatus;
+ }
+
+ }
+
+ ExFreePool (Request->ResponseBuffer);
+ Request->ResponseBuffer = NULL;
+
+ }
+
+ //
+ // Install the return code in the IRP so that when we call NbfDestroyRequest,
+ // it will get completed with the proper return status.
+ //
+
+ Irp->IoStatus.Status = FinalStatus;
+ Irp->IoStatus.Information = Information;
+
+ //
+ // The entire transport is done with this request.
+ //
+
+ NbfDereferenceRequest ("Complete", Request, RREF_CREATION); // remove creation reference.
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+
+ }
+
+} /* NbfCompleteRequest */
+
+
+#if DBG
+VOID
+NbfRefSendIrp(
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a send IRP.
+
+Arguments:
+
+ IrpSp - Pointer to the IRP's stack location.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint1 ("NbfRefSendIrp: Entered, ReferenceCount: %x\n",
+ IRP_SEND_REFCOUNT(IrpSp));
+ }
+
+ ASSERT (IRP_SEND_REFCOUNT(IrpSp) > 0);
+
+ InterlockedIncrement (&IRP_SEND_REFCOUNT(IrpSp));
+
+} /* NbfRefSendIrp */
+
+
+VOID
+NbfDerefSendIrp(
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport send IRP by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IoCompleteRequest to actually complete the IRP.
+
+Arguments:
+
+ Request - Pointer to a transport send IRP's stack location.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint1 ("NbfDerefSendIrp: Entered, ReferenceCount: %x\n",
+ IRP_SEND_REFCOUNT(IrpSp));
+ }
+
+ result = InterlockedDecrement (&IRP_SEND_REFCOUNT(IrpSp));
+
+ ASSERT (result >= 0);
+
+ //
+ // If we have deleted all references to this request, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the request any longer.
+ //
+
+ if (result == 0) {
+
+ PIRP Irp = IRP_SEND_IRP(IrpSp);
+
+ IRP_SEND_REFCOUNT(IrpSp) = 0;
+ IRP_SEND_IRP (IrpSp) = NULL;
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ }
+
+} /* NbfDerefSendIrp */
+#endif
+
+
+VOID
+NbfCompleteSendIrp(
+ IN PIRP Irp,
+ IN NTSTATUS Status,
+ IN ULONG Information
+ )
+
+/*++
+
+Routine Description:
+
+ This routine completes a transport send IRP.
+
+Arguments:
+
+ Irp - Pointer to a send IRP.
+
+ Status - Actual return status to be assigned to the request. This
+ value may be overridden if the timed-out bitflag is set in the request.
+
+ Information - the information field for the I/O Status Block.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ PTP_CONNECTION Connection;
+
+ ASSERT (Status != STATUS_PENDING);
+
+ Connection = IRP_SEND_CONNECTION(IrpSp);
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint2 ("NbfCompleteSendIrp: Entered IRP %lx, connection %lx\n",
+ Irp, Connection);
+ }
+
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = Information;
+
+ NbfDereferenceSendIrp ("Complete", IrpSp, RREF_CREATION); // remove creation reference.
+
+ NbfDereferenceConnectionMacro ("Removing Connection", Connection, CREF_SEND_IRP);
+
+} /* NbfCompleteSendIrp */
+
+
+#if DBG
+VOID
+NbfRefReceiveIrpLocked(
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a receive IRP.
+
+Arguments:
+
+ IrpSp - Pointer to the IRP's stack location.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint1 ("NbfRefReceiveIrpLocked: Entered, ReferenceCount: %x\n",
+ IRP_RECEIVE_REFCOUNT(IrpSp));
+ }
+
+ ASSERT (IRP_RECEIVE_REFCOUNT(IrpSp) > 0);
+
+ IRP_RECEIVE_REFCOUNT(IrpSp)++;
+
+} /* NbfRefReceiveIrpLocked */
+#endif
+
+
+VOID
+NbfDerefReceiveIrp(
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport receive IRP by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IoCompleteRequest to actually complete the IRP.
+
+Arguments:
+
+ Request - Pointer to a transport receive IRP's stack location.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG result;
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint1 ("NbfDerefReceiveIrp: Entered, ReferenceCount: %x\n",
+ IRP_RECEIVE_REFCOUNT(IrpSp));
+ }
+
+ result = ExInterlockedAddUlong (
+ (PULONG)&IRP_RECEIVE_REFCOUNT(IrpSp),
+ (ULONG)-1,
+ (IRP_RECEIVE_CONNECTION(IrpSp)->LinkSpinLock));
+
+ ASSERT (result > 0);
+
+ //
+ // If we have deleted all references to this request, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the request any longer.
+ //
+
+ if (result == 1) {
+
+ PIRP Irp = IRP_RECEIVE_IRP(IrpSp);
+
+ ExInterlockedInsertTailList(
+ &(IRP_DEVICE_CONTEXT(IrpSp)->IrpCompletionQueue),
+ &Irp->Tail.Overlay.ListEntry,
+ &(IRP_DEVICE_CONTEXT(IrpSp)->Interlock));
+
+ }
+
+} /* NbfDerefReceiveIrp */
+
+
+#if DBG
+VOID
+NbfDerefReceiveIrpLocked(
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport receive IRP by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IoCompleteRequest to actually complete the IRP.
+
+Arguments:
+
+ Request - Pointer to a transport receive IRP's stack location.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG result;
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint1 ("NbfDerefReceiveIrpLocked: Entered, ReferenceCount: %x\n",
+ IRP_RECEIVE_REFCOUNT(IrpSp));
+ }
+
+ result = IRP_RECEIVE_REFCOUNT(IrpSp)--;
+
+ ASSERT (result > 0);
+
+ //
+ // If we have deleted all references to this request, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the request any longer.
+ //
+
+ if (result == 1) {
+
+ PIRP Irp = IRP_RECEIVE_IRP(IrpSp);
+
+ ExInterlockedInsertTailList(
+ &(IRP_DEVICE_CONTEXT(IrpSp)->IrpCompletionQueue),
+ &Irp->Tail.Overlay.ListEntry,
+ &(IRP_DEVICE_CONTEXT(IrpSp)->Interlock));
+
+ }
+
+} /* NbfDerefReceiveIrpLocked */
+#endif
+
+
+VOID
+NbfCompleteReceiveIrp(
+ IN PIRP Irp,
+ IN NTSTATUS Status,
+ IN ULONG Information
+ )
+
+/*++
+
+Routine Description:
+
+ This routine completes a transport receive IRP.
+
+ NOTE: THIS ROUTINE MUST BE CALLED WITH THE CONNECTION SPINLOCK
+ HELD.
+
+Arguments:
+
+ Irp - Pointer to a receive IRP.
+
+ Status - Actual return status to be assigned to the request. This
+ value may be overridden if the timed-out bitflag is set in the request.
+
+ Information - the information field for the I/O Status Block.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ PTP_CONNECTION Connection;
+
+ ASSERT (Status != STATUS_PENDING);
+
+ Connection = IRP_RECEIVE_CONNECTION(IrpSp);
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint2 ("NbfCompleteReceiveIrp: Entered IRP %lx, connection %lx\n",
+ Irp, Connection);
+ }
+
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = Information;
+
+ NbfDereferenceReceiveIrpLocked ("Complete", IrpSp, RREF_CREATION); // remove creation reference.
+
+} /* NbfCompleteReceiveIrp */
diff --git a/private/ntos/tdi/nbf/send.c b/private/ntos/tdi/nbf/send.c
new file mode 100644
index 000000000..a8a6cc7f3
--- /dev/null
+++ b/private/ntos/tdi/nbf/send.c
@@ -0,0 +1,503 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiSend
+ o TdiSendDatagram
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+NTSTATUS
+NbfTdiSend(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSend request for the transport provider.
+
+ NOTE: THIS FUNCTION MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql, cancelIrql;
+ PTP_CONNECTION connection;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL_SEND parameters;
+ PIRP TempIrp;
+
+ //
+ // Determine which connection this send belongs on.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // Check that this is really a connection.
+ //
+
+ if ((connection->Size != sizeof (TP_CONNECTION)) ||
+ (connection->Type != NBF_CONNECTION_SIGNATURE)) {
+#if DBG
+ NbfPrint2 ("TdiSend: Invalid Connection %lx Irp %lx\n", connection, Irp);
+#endif
+ return STATUS_INVALID_CONNECTION;
+ }
+
+#if DBG
+ Irp->IoStatus.Information = 0; // initialize it.
+ Irp->IoStatus.Status = 0x01010101; // initialize it.
+#endif
+
+ //
+ // Interpret send options.
+ //
+
+#if DBG
+ parameters = (PTDI_REQUEST_KERNEL_SEND)(&irpSp->Parameters);
+ if ((parameters->SendFlags & TDI_SEND_PARTIAL) != 0) {
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint0 ("NbfTdiSend: TDI_END_OF_RECORD not found.\n");
+ }
+ }
+#endif
+
+ //
+ // Now we have a reference on the connection object. Queue up this
+ // send to the connection object.
+ //
+
+ //
+ // We would normally add a connection reference of type
+ // CREF_SEND_IRP, however we delay doing this until we
+ // know we are not going to call PacketizeSend with the
+ // second parameter TRUE. If we do call that it assumes
+ // we have not added the reference.
+ //
+
+ IRP_SEND_IRP(irpSp) = Irp;
+ IRP_SEND_REFCOUNT(irpSp) = 1;
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ if ((connection->Flags & CONNECTION_FLAGS_READY) == 0) {
+
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ Irp->IoStatus.Status = connection->Status;
+ Irp->IoStatus.Information = 0;
+
+ NbfDereferenceSendIrp ("Complete", irpSp, RREF_CREATION); // remove creation reference.
+
+ } else {
+
+ //
+ // Once the reference is in, LinkSpinLock will stay valid.
+ //
+
+ NbfReferenceConnection ("Verify Temp Use", connection, CREF_BY_ID);
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ ACQUIRE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+#if DBG
+ NbfSends[NbfSendsNext].Irp = Irp;
+ NbfSends[NbfSendsNext].Request = NULL;
+ NbfSends[NbfSendsNext].Connection = (PVOID)connection;
+ {
+ ULONG i,j;
+ PUCHAR va;
+ PMDL mdl;
+
+ mdl = Irp->MdlAddress;
+ if (parameters->SendLength > TRACK_TDI_CAPTURE) {
+ NbfSends[NbfSendsNext].Contents[0] = 0xFF;
+ } else {
+ NbfSends[NbfSendsNext].Contents[0] = (UCHAR)parameters->SendLength;
+ }
+
+ i = 1;
+ while (i < TRACK_TDI_CAPTURE) {
+ if (mdl == NULL) break;
+ for ( va = MmGetSystemAddressForMdl (mdl),
+ j = MmGetMdlByteCount (mdl);
+ (i < TRACK_TDI_CAPTURE) && (j > 0);
+ i++, j-- ) {
+ NbfSends[NbfSendsNext].Contents[i] = *va++;
+ }
+ mdl = mdl->Next;
+ }
+ }
+
+ NbfSendsNext++;
+ if (NbfSendsNext >= TRACK_TDI_LIMIT) NbfSendsNext = 0;
+#endif
+
+ //
+ // If this IRP has been cancelled already, complete it now.
+ //
+
+ if (Irp->Cancel) {
+
+#if DBG
+ NbfCompletedSends[NbfCompletedSendsNext].Irp = Irp;
+ NbfCompletedSends[NbfCompletedSendsNext].Status = STATUS_CANCELLED;
+ NbfCompletedSendsNext = (NbfCompletedSendsNext++) % TRACK_TDI_LIMIT;
+#endif
+
+ NbfReferenceConnection("TdiSend cancelled", connection, CREF_SEND_IRP);
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ NbfCompleteSendIrp (Irp, STATUS_CANCELLED, 0);
+ KeLowerIrql (oldirql);
+
+ NbfDereferenceConnection ("IRP cancelled", connection, CREF_BY_ID); // release lookup hold.
+ return STATUS_PENDING;
+ }
+
+ //
+ // Insert onto the send queue, and make the IRP
+ // cancellable.
+ //
+
+ InsertTailList (&connection->SendQueue,&Irp->Tail.Overlay.ListEntry);
+ IoSetCancelRoutine(Irp, NbfCancelSend);
+
+ //
+ // Release the cancel spinlock out of order. We were at DPC level
+ // when we acquired both the cancel and link spinlocks, so the irqls
+ // don't need to be swapped.
+ //
+ ASSERT(cancelIrql == DISPATCH_LEVEL);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ //
+ // If this connection is waiting for an EOR to appear because a non-EOR
+ // send failed at some point in the past, fail this send. Clear the
+ // flag that causes this if this request has the EOR set.
+ //
+ // BUGBUG: Should the FailSend status be clearer here?
+ //
+
+ if ((connection->Flags & CONNECTION_FLAGS_FAILING_TO_EOR) != 0) {
+
+ NbfReferenceConnection("TdiSend failing to EOR", connection, CREF_SEND_IRP);
+
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ //
+ // BUGBUG: Should we save status from real failure?
+ //
+
+ FailSend (connection, STATUS_LINK_FAILED, TRUE);
+
+ parameters = (PTDI_REQUEST_KERNEL_SEND)(&irpSp->Parameters);
+ if ( (parameters->SendFlags & TDI_SEND_PARTIAL) == 0) {
+ connection->Flags &= ~CONNECTION_FLAGS_FAILING_TO_EOR;
+ }
+
+ KeLowerIrql (oldirql);
+
+ NbfDereferenceConnection ("Failing to EOR", connection, CREF_BY_ID); // release lookup hold.
+ return STATUS_PENDING;
+ }
+
+
+ //
+ // If the send state is either IDLE or W_EOR, then we should
+ // begin packetizing this send. Otherwise, some other event
+ // will cause it to be packetized.
+ //
+
+ //
+ // NOTE: If we call StartPacketizingConnection, we make
+ // sure that it is the last operation we do on this
+ // connection. This allows us to "hand off" the reference
+ // we have to that function, which converts it into
+ // a reference for being on the packetize queue.
+ //
+
+// NbfPrint2 ("TdiSend: Sending, connection %lx send state %lx\n",
+// connection, connection->SendState);
+
+ switch (connection->SendState) {
+
+ case CONNECTION_SENDSTATE_IDLE:
+
+ InitializeSend (connection); // sets state to PACKETIZE
+
+ //
+ // If we can, packetize right now.
+ //
+
+ if (!(connection->Flags & CONNECTION_FLAGS_PACKETIZE)) {
+
+ ASSERT (!(connection->Flags2 & CONNECTION_FLAGS2_STOPPING));
+ connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
+
+#if DBG
+ NbfReferenceConnection ("Packetize", connection, CREF_PACKETIZE_QUEUE);
+ NbfDereferenceConnection("temp TdiSend", connection, CREF_BY_ID);
+#endif
+
+ //
+ // This releases the spinlock. Note that PacketizeSend
+ // assumes that the current SendIrp has a reference
+ // of type RREF_PACKET;
+ //
+
+#if DBG
+ NbfReferenceSendIrp ("Packetize", irpSp, RREF_PACKET);
+#else
+ ++IRP_SEND_REFCOUNT(irpSp); // OK since it was just queued.
+#endif
+ PacketizeSend (connection, TRUE);
+
+ } else {
+
+#if DBG
+ NbfReferenceConnection("TdiSend packetizing", connection, CREF_SEND_IRP);
+ NbfDereferenceConnection ("Stopping or already packetizing", connection, CREF_BY_ID); // release lookup hold.
+#endif
+
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ }
+
+ break;
+
+ case CONNECTION_SENDSTATE_W_EOR:
+ connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
+
+ //
+ // Adjust the send variables on the connection so that
+ // they correctly point to this new send. We can't call
+ // InitializeSend to do that, because we need to keep
+ // track of the other outstanding sends on this connection
+ // which have been sent but are a part of this message.
+ //
+
+ TempIrp = CONTAINING_RECORD(
+ connection->SendQueue.Flink,
+ IRP,
+ Tail.Overlay.ListEntry);
+
+ connection->sp.CurrentSendIrp = TempIrp;
+ connection->sp.CurrentSendMdl = TempIrp->MdlAddress;
+ connection->sp.SendByteOffset = 0;
+ connection->CurrentSendLength +=
+ IRP_SEND_LENGTH(IoGetCurrentIrpStackLocation(TempIrp));
+
+ //
+ // StartPacketizingConnection removes the CREF_BY_ID
+ // reference.
+ //
+
+ NbfReferenceConnection("TdiSend W_EOR", connection, CREF_SEND_IRP);
+
+ StartPacketizingConnection (connection, TRUE);
+ break;
+
+ default:
+// NbfPrint2 ("TdiSend: Sending, unknown state! connection %lx send state %lx\n",
+// connection, connection->SendState);
+ //
+ // The connection is in another state (such as
+ // W_ACK or W_LINK), we just need to make sure
+ // to call InitializeSend if the new one is
+ // the first one on the list.
+ //
+
+ //
+ // BUGBUG: Currently InitializeSend sets SendState,
+ // we should fix this.
+ //
+
+ if (connection->SendQueue.Flink == &Irp->Tail.Overlay.ListEntry) {
+ ULONG SavedSendState;
+ SavedSendState = connection->SendState;
+ InitializeSend (connection);
+ connection->SendState = SavedSendState;
+ }
+
+#if DBG
+ NbfReferenceConnection("TdiSend other", connection, CREF_SEND_IRP);
+ NbfDereferenceConnection("temp TdiSend", connection, CREF_BY_ID);
+#endif
+
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ }
+
+ }
+
+ KeLowerIrql (oldirql);
+ return STATUS_PENDING;
+
+} /* TdiSend */
+
+
+NTSTATUS
+NbfTdiSendDatagram(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSendDatagram request for the transport
+ provider.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ KIRQL oldirql;
+ PTP_ADDRESS_FILE addressFile;
+ PTP_ADDRESS address;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL_SENDDG parameters;
+ UINT MaxUserData;
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+ addressFile = irpSp->FileObject->FsContext;
+
+ status = NbfVerifyAddressObject (addressFile);
+ if (!NT_SUCCESS (status)) {
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint2 ("TdiSendDG: Invalid address %lx Irp %lx\n",
+ addressFile, Irp);
+ }
+ return status;
+ }
+
+ address = addressFile->Address;
+ parameters = (PTDI_REQUEST_KERNEL_SENDDG)(&irpSp->Parameters);
+
+ //
+ // Check that the length is short enough.
+ //
+
+ MacReturnMaxDataSize(
+ &address->Provider->MacInfo,
+ NULL,
+ 0,
+ address->Provider->MaxSendPacketSize,
+ FALSE,
+ &MaxUserData);
+
+ if (parameters->SendLength >
+ (MaxUserData - sizeof(DLC_FRAME) - sizeof(NBF_HDR_CONNECTIONLESS))) {
+
+ NbfDereferenceAddress("tmp send datagram", address, AREF_VERIFY);
+ return STATUS_INVALID_PARAMETER;
+
+ }
+
+ //
+ // If we are on a disconnected RAS link, then fail the datagram
+ // immediately.
+ //
+
+ if ((address->Provider->MacInfo.MediumAsync) &&
+ (!address->Provider->MediumSpeedAccurate)) {
+
+ NbfDereferenceAddress("tmp send datagram", address, AREF_VERIFY);
+ return STATUS_DEVICE_NOT_READY;
+ }
+
+ //
+ // Check that the target address includes a Netbios component.
+ //
+
+ if (!(NbfValidateTdiAddress(
+ parameters->SendDatagramInformation->RemoteAddress,
+ parameters->SendDatagramInformation->RemoteAddressLength)) ||
+ (NbfParseTdiAddress(parameters->SendDatagramInformation->RemoteAddress, TRUE) == NULL)) {
+
+ NbfDereferenceAddress("tmp send datagram", address, AREF_VERIFY);
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock,&oldirql);
+
+ if ((address->Flags & (ADDRESS_FLAGS_STOPPING | ADDRESS_FLAGS_CONFLICT)) != 0) {
+
+ RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = (address->Flags & ADDRESS_FLAGS_STOPPING) ?
+ STATUS_NETWORK_NAME_DELETED : STATUS_DUPLICATE_NAME;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ } else {
+
+ NbfReferenceAddress ("Send datagram", address, AREF_REQUEST);
+ Irp->IoStatus.Information = parameters->SendLength;
+ InsertTailList (
+ &address->SendDatagramQueue,
+ &Irp->Tail.Overlay.ListEntry);
+ RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
+
+ //
+ // The request is queued. Ship the next request at the head of the queue,
+ // provided the completion handler is not active. We serialize this so
+ // that only one MDL and NBF datagram header needs to be statically
+ // allocated for reuse by all send datagram requests.
+ //
+
+ (VOID)NbfSendDatagramsOnAddress (address);
+
+ }
+
+ NbfDereferenceAddress("tmp send datagram", address, AREF_VERIFY);
+
+ return STATUS_PENDING;
+
+} /* NbfTdiSendDatagram */
diff --git a/private/ntos/tdi/nbf/sendeng.c b/private/ntos/tdi/nbf/sendeng.c
new file mode 100644
index 000000000..1b6556581
--- /dev/null
+++ b/private/ntos/tdi/nbf/sendeng.c
@@ -0,0 +1,3657 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ sendeng.c
+
+Abstract:
+
+ This module contains code that implements the send engine for the
+ Jetbeui transport provider. This code is responsible for the following
+ basic activities, including some subordinate glue.
+
+ 1. Packetizing TdiSend requests already queued up on a TP_CONNECTION
+ object, using I-frame packets acquired from the PACKET.C module,
+ and turning them into shippable packets and placing them on the
+ TP_LINK's WackQ. In the process of doing this, the packets are
+ actually submitted as I/O requests to the Physical Provider, in
+ the form of PdiSend requests.
+
+ 2. Retiring packets queued to a TP_LINK's WackQ and returning them to
+ the device context's pool for use by other links. In the process
+ of retiring acked packets, step 1 may be reactivated.
+
+ 3. Resending packets queued to a TP_LINK's WackQ because of a reject
+ condition on the link. This involves no state update in the
+ TP_CONNECTION object.
+
+ 4. Handling of Send completion events from the Physical Provider,
+ to allow proper synchronization of the reuse of packets.
+
+ 5. Completion of TdiSend requests. This is triggered by the receipt
+ (in IFRAMES.C) of a DataAck frame, or by a combination of other
+ frames when the proper protocol has been negotiated. One routine
+ in this routine is responsible for the actual mechanics of TdiSend
+ request completion.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#if DBG
+extern ULONG NbfSendsIssued;
+extern ULONG NbfSendsCompletedInline;
+extern ULONG NbfSendsCompletedOk;
+extern ULONG NbfSendsCompletedFail;
+extern ULONG NbfSendsPended;
+extern ULONG NbfSendsCompletedAfterPendOk;
+extern ULONG NbfSendsCompletedAfterPendFail;
+#endif
+
+
+//
+// Temporary variables to control piggyback ack usage.
+//
+#define NbfUsePiggybackAcks 1
+#if DBG
+ULONG NbfDebugPiggybackAcks = 0;
+#endif
+
+
+#if DBG
+//
+// *** This is the original version of StartPacketizingConnection, which
+// is now a macro on the free build. It has been left here as the
+// fully-commented version of the code.
+//
+
+VOID
+StartPacketizingConnection(
+ PTP_CONNECTION Connection,
+ IN BOOLEAN Immediate
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to place a connection on the PacketizeQueue
+ of its device context object. Then this routine starts packetizing
+ the first connection on that queue.
+
+ *** The Connection LinkSpinLock must be held on entry to this routine.
+
+ *** THIS FUNCTION MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+ Immediate - TRUE if the connection should be packetized
+ immediately; FALSE if the connection should be queued
+ up for later packetizing (implies that ReceiveComplete
+ will be called in the future, which packetizes always).
+
+ NOTE: If this is TRUE, it also implies that we have
+ a connection reference of type CREF_BY_ID which we
+ will "convert" into the CREF_PACKETIZE_QUEUE one.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("StartPacketizingConnection: Entered for connection %lx.\n",
+ Connection);
+ }
+
+ DeviceContext = Connection->Provider;
+
+ //
+ // If this connection's SendState is set to PACKETIZE and if
+ // we are not already on the PacketizeQueue, then go ahead and
+ // append us to the end of that queue, and remember that we're
+ // on it by setting the CONNECTION_FLAGS_PACKETIZE bitflag.
+ //
+ // Also don't queue it if the connection is stopping.
+ //
+
+ if ((Connection->SendState == CONNECTION_SENDSTATE_PACKETIZE) &&
+ !(Connection->Flags & CONNECTION_FLAGS_PACKETIZE) &&
+ (Connection->Flags & CONNECTION_FLAGS_READY)) {
+
+ ASSERT (!(Connection->Flags2 & CONNECTION_FLAGS2_STOPPING));
+
+ Connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
+
+ if (!Immediate) {
+ NbfReferenceConnection ("Packetize", Connection, CREF_PACKETIZE_QUEUE);
+ } else {
+#if DBG
+ NbfReferenceConnection ("Packetize", Connection, CREF_PACKETIZE_QUEUE);
+ NbfDereferenceConnection("temp TdiSend", Connection, CREF_BY_ID);
+#endif
+ }
+
+ ExInterlockedInsertTailList(
+ &DeviceContext->PacketizeQueue,
+ &Connection->PacketizeLinkage,
+ &DeviceContext->SpinLock);
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ if (Immediate) {
+ NbfDereferenceConnection("temp TdiSend", Connection, CREF_BY_ID);
+ }
+ }
+
+ if (Immediate) {
+ PacketizeConnections (DeviceContext);
+ }
+
+} /* StartPacketizingConnection */
+#endif
+
+
+VOID
+PacketizeConnections(
+ PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to packetize all connections waiting on the
+ PacketizeQueue of the DeviceContext.
+
+
+Arguments:
+
+ DeviceContext - Pointer to a DEVICE_CONTEXT object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PTP_CONNECTION Connection;
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("PacketizeConnections: Entered for device context %lx.\n",
+ DeviceContext);
+ }
+
+ //
+ // Pick connections off of the device context's packetization queue
+ // until there are no more left to pick off. For each one, we call
+ // PacketizeSend. Note this routine can be executed concurrently
+ // on multiple processors and it doesn't matter; multiple connections
+ // may be packetized concurrently.
+ //
+
+ while (TRUE) {
+
+ p = ExInterlockedRemoveHeadList(
+ &DeviceContext->PacketizeQueue,
+ &DeviceContext->SpinLock);
+
+ if (p == NULL) {
+ break;
+ }
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, PacketizeLinkage);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ if (Connection->SendState != CONNECTION_SENDSTATE_PACKETIZE) {
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ NbfDereferenceConnection ("No longer packetizing", Connection, CREF_PACKETIZE_QUEUE);
+ } else {
+ NbfReferenceSendIrp ("Packetize", IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp), RREF_PACKET);
+ PacketizeSend (Connection, FALSE); // releases the lock.
+ }
+ }
+
+} /* PacketizeConnections */
+
+
+VOID
+PacketizeSend(
+ IN PTP_CONNECTION Connection,
+ IN BOOLEAN Direct
+ )
+
+/*++
+
+Routine Description:
+
+ This routine packetizes the current TdiSend request on the specified
+ connection as much as limits will permit. A given here is that there
+ is an active send on the connection that needs further packetization.
+
+ NOTE: This routine is called with the connection spinlock held and
+ returns with it released. THIS FUNCTION MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+ Direct - TRUE if we are called from TdiSend. This implies that
+ the connection does not have a reference of type CREF_SEND_IRP,
+ which we need to add before we leave.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG MaxFrameSize, FrameSize;
+ ULONG PacketBytes;
+ PNDIS_BUFFER PacketDescriptor;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_PACKET Packet;
+ NTSTATUS Status;
+ PNBF_HDR_CONNECTION NbfHeader;
+ BOOLEAN LinkCheckpoint;
+ BOOLEAN SentPacket = FALSE;
+ BOOLEAN ExitAfterSendOnePacket = FALSE;
+ PIO_STACK_LOCATION IrpSp;
+ ULONG LastPacketLength;
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("PacketizeSend: Entered for connection %lx.\n", Connection);
+ }
+
+ DeviceContext = Connection->Provider;
+
+ ASSERT (Connection->SendState == CONNECTION_SENDSTATE_PACKETIZE);
+
+ //
+ // Just loop until one of three events happens: (1) we run out of
+ // packets from NbfCreatePacket, (2) we completely packetize the send,
+ // or (3) we can't send any more packets because SendOnePacket failed.
+ //
+
+#if DBG
+
+ //
+ // Convert the queue reference into a packetize one. It is OK
+ // to do this with the lock held because we know that the refcount
+ // must already be at least one, so we don't drop to zero.
+ //
+
+ NbfReferenceConnection ("PacketizeSend", Connection, CREF_PACKETIZE);
+ NbfDereferenceConnection ("Off packetize queue", Connection, CREF_PACKETIZE_QUEUE);
+#endif
+
+ MaxFrameSize = Connection->MaximumDataSize;
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("PacketizeSend: MaxFrameSize for user data=%ld.\n", MaxFrameSize);
+ }
+
+
+ //
+ // It is possible for a frame to arrive during the middle of this loop
+ // (such as a NO_RECEIVE) that will put us into a new state (such as
+ // W_RCVCONT). For this reason, we have to check the state every time
+ // (at the end of the loop).
+ //
+
+ do {
+
+ if (!NT_SUCCESS (NbfCreatePacket (DeviceContext, Connection->Link, &Packet))) {
+
+ //
+ // We need a packet to finish packetizing the current send, but
+ // there are no more packets available in the pool right now.
+ // Set our send state to W_PACKET, and put this connection on
+ // the PacketWaitQueue of the device context object. Then,
+ // when NbfDestroyPacket frees up a packet, it will check this
+ // queue for starved connections, and if it finds one, it will
+ // take a connection off the list and set its send state to
+ // SENDSTATE_PACKETIZE and put it on the PacketizeQueue.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint0 ("PacketizeSend: NbfCreatePacket failed.\n");
+ }
+ Connection->SendState = CONNECTION_SENDSTATE_W_PACKET;
+
+ //
+ // Clear the PACKETIZE flag, indicating that we're no longer
+ // on the PacketizeQueue or actively packetizing. The flag
+ // was set by StartPacketizingConnection to indicate that
+ // the connection was already on the PacketizeQueue.
+ //
+ // Don't queue him if the connection is stopping.
+ //
+
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+#if DBG
+ if (Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) {
+ DbgPrint ("NBF: BUGBUG! Trying to PacketWait stopping connection %lx\n", Connection);
+ DbgBreakPoint();
+ }
+#endif
+ Connection->Flags |= CONNECTION_FLAGS_W_PACKETIZE;
+ if (!Connection->OnPacketWaitQueue) {
+ Connection->OnPacketWaitQueue = TRUE;
+ InsertTailList(
+ &DeviceContext->PacketWaitQueue,
+ &Connection->PacketWaitLinkage);
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ if (!SentPacket) {
+ NbfDereferenceSendIrp ("No packet", IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp), RREF_PACKET);
+ }
+ if (Direct) {
+ NbfReferenceConnection ("Delayed request ref", Connection, CREF_SEND_IRP);
+ }
+
+ NbfDereferenceConnection ("No packet", Connection, CREF_PACKETIZE);
+ return;
+
+ }
+
+ //
+ // Set the length of the packet now, while only the
+ // header is attached.
+ //
+
+ NbfSetNdisPacketLength(
+ Packet->NdisPacket,
+ Connection->Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION));
+
+ // Add a reference count to the request, and keep track of
+ // which request it is. We rely on NbfDestroyPacket to
+ // remove the reference.
+
+ IrpSp = IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp);
+
+ Packet->Owner = IrpSp;
+ // Packet->Action = PACKET_ACTION_IRP_SP;
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint2 ("PacketizeSend: Packet %x ref IrpSp %x.\n", Packet, Packet->Owner);
+ }
+
+ //
+ // For performance reasons, the first time through here on
+ // a direct call, we have a IrpSp reference already.
+ //
+
+ if (SentPacket) {
+ NbfReferenceSendIrp ("Packetize", IrpSp, RREF_PACKET);
+ }
+
+ //
+ // Now build a DATA_ONLY_LAST header in this frame. If it
+ // turns out we need a DFM, we change it. The header we copy
+ // already has ResponseCorrelator set to our current correlator
+ // and TransmitCorrelator set to the last one we received from
+ // him (if we do not piggyback an ack, then we zero out
+ // TransmitCorrelator).
+ //
+
+ NbfHeader = (PNBF_HDR_CONNECTION)&(Packet->Header[Connection->Link->HeaderLength + sizeof(DLC_I_FRAME)]);
+ *(NBF_HDR_CONNECTION UNALIGNED *)NbfHeader = Connection->NetbiosHeader;
+
+ ASSERT (RESPONSE_CORR(NbfHeader) != 0);
+
+ //
+ // Determine if we need the resynch bit here.
+ //
+
+ if (Connection->Flags & CONNECTION_FLAGS_RESYNCHING) {
+
+ NbfHeader->Data2Low = 1;
+ Connection->Flags &= ~CONNECTION_FLAGS_RESYNCHING;
+
+ } else {
+
+ NbfHeader->Data2Low = 0;
+
+ }
+
+
+ //
+ // build an NDIS_BUFFER chain that describes the buffer we're using, and
+ // thread it off the NdisBuffer. This chain may not complete the
+ // packet, as the remaining part of the MDL chain may be shorter than
+ // the packet.
+ //
+
+ FrameSize = MaxFrameSize;
+
+ //
+ // Check if we have less than FrameSize left to send.
+ //
+
+ if (Connection->sp.MessageBytesSent + FrameSize > Connection->CurrentSendLength) {
+
+ FrameSize = Connection->CurrentSendLength - Connection->sp.MessageBytesSent;
+
+ }
+
+
+ //
+ // Make a copy of the MDL chain for this send, unless
+ // there are zero bytes left.
+ //
+
+ if (FrameSize != 0) {
+
+ //
+ // If the whole send will fit inside one packet,
+ // then there is no need to duplicate the MDL
+ // (note that this may include multi-MDL sends).
+ //
+
+ if ((Connection->sp.SendByteOffset == 0) &&
+ (Connection->CurrentSendLength == FrameSize)) {
+
+ PacketDescriptor = (PNDIS_BUFFER)Connection->sp.CurrentSendMdl;
+ PacketBytes = FrameSize;
+ Connection->sp.CurrentSendMdl = NULL;
+ Connection->sp.SendByteOffset = FrameSize;
+ Packet->PacketNoNdisBuffer = TRUE;
+
+ } else {
+
+ Status = BuildBufferChainFromMdlChain (
+ DeviceContext,
+ Connection->sp.CurrentSendMdl,
+ Connection->sp.SendByteOffset,
+ FrameSize,
+ &PacketDescriptor,
+ &Connection->sp.CurrentSendMdl,
+ &Connection->sp.SendByteOffset,
+ &PacketBytes);
+
+ if (!NT_SUCCESS(Status)) {
+
+ if (NbfHeader->Data2Low) {
+ Connection->Flags |= CONNECTION_FLAGS_RESYNCHING;
+ }
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ NbfDereferencePacket (Packet); // remove creation hold.
+ goto BufferChainFailure;
+ }
+
+ }
+
+ //
+ // Chain the buffers to the packet, unless there
+ // are zero bytes of data.
+ //
+
+ Connection->sp.MessageBytesSent += PacketBytes;
+ NdisChainBufferAtBack (Packet->NdisPacket, PacketDescriptor);
+
+ } else {
+
+ PacketBytes = 0;
+ Connection->sp.CurrentSendMdl = NULL;
+
+ }
+
+ {
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ {PNDIS_BUFFER NdisBuffer;
+ NdisQueryPacket(Packet->NdisPacket, NULL, NULL, &NdisBuffer, NULL);
+ NbfPrint1 ("PacketizeSend: NDIS_BUFFER Built, chain is: %lx is Packet->Head\n", NdisBuffer);
+ NdisGetNextBuffer (NdisBuffer, &NdisBuffer);
+ while (NdisBuffer != NULL) {
+ NbfPrint1 (" %lx is Next\n",
+ NdisBuffer);
+ NdisGetNextBuffer (NdisBuffer, &NdisBuffer);
+ }}
+ }
+
+ //
+ // Have we run out of Mdl Chain in this request?
+ //
+
+#if DBG
+ if (PacketBytes < FrameSize) {
+ ASSERT (Connection->sp.CurrentSendMdl == NULL);
+ }
+#endif
+
+ if ((Connection->sp.CurrentSendMdl == NULL) ||
+ (Connection->CurrentSendLength <= Connection->sp.MessageBytesSent)) {
+
+ //
+ // Yep. We know that we've exhausted the current request's buffer
+ // here, so see if there's another request without EOF set that we
+ // can build start throwing into this packet.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint0 ("PacketizeSend: Used up entire request.\n");
+ }
+
+ if (!(IRP_SEND_FLAGS(IrpSp) & TDI_SEND_PARTIAL)) {
+
+ //
+ // We are sending the last packet in a message. Change
+ // the packet type and indicate in the connection object's
+ // send state that we are waiting for a DATA_ACK NetBIOS-
+ // level acknowlegement.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint0 ("PacketizeSend: Request has EOR, making pkt a DOL.\n");
+ }
+
+ //
+ // Keep track of how many consecutive sends we have done.
+ //
+
+ Connection->ConsecutiveSends++;
+ Connection->ConsecutiveReceives = 0;
+
+ //
+ // Change it to a DOL with piggyback ack allowed if wanted.
+ //
+
+ ASSERT (NbfHeader->Command == NBF_CMD_DATA_ONLY_LAST);
+ if (!(IRP_SEND_FLAGS(IrpSp) &
+ TDI_SEND_NO_RESPONSE_EXPECTED) &&
+ (Connection->ConsecutiveSends < 2)) {
+ if (NbfUsePiggybackAcks) {
+ NbfHeader->Data1 |= DOL_OPTIONS_ACK_W_DATA_ALLOWED;
+ }
+ }
+
+ Connection->SendState = CONNECTION_SENDSTATE_W_ACK;
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+ ExitAfterSendOnePacket = TRUE;
+
+ } else {
+
+ //
+ // We are sending the last packet in this request. If there
+ // are more requests in the connection's SendQueue, then
+ // advance complex send pointer to point to the next one
+ // in line. Otherwise, if there aren't any more requests
+ // ready to packetize, then we enter the W_EOR state and
+ // stop packetizing. Note that we're waiting here for the TDI
+ // client to come up with data to send; we're just hanging out
+ // until then.
+ //
+ // DGB: Note that this will allow the last packet in the
+ // request to be smaller than the max packet length. This
+ // is not addressed anywhere that I can find in the NBF
+ // spec, and will be interesting to test against a non-NT
+ // NBF protocol.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint0 ("PacketizeSend: Request doesn't have EOR.\n");
+ }
+
+ NbfHeader->Command = NBF_CMD_DATA_FIRST_MIDDLE;
+
+ if (Connection->sp.CurrentSendIrp->Tail.Overlay.ListEntry.Flink == &Connection->SendQueue) {
+
+ Connection->SendState = CONNECTION_SENDSTATE_W_EOR;
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+ ExitAfterSendOnePacket = TRUE;
+
+ } else {
+
+ Connection->sp.CurrentSendIrp =
+ CONTAINING_RECORD (
+ Connection->sp.CurrentSendIrp->Tail.Overlay.ListEntry.Flink,
+ IRP,
+ Tail.Overlay.ListEntry);
+ Connection->sp.CurrentSendMdl =
+ Connection->sp.CurrentSendIrp->MdlAddress;
+ Connection->sp.SendByteOffset = 0;
+ Connection->CurrentSendLength +=
+ IRP_SEND_LENGTH(IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp));
+ }
+ }
+
+ } else {
+
+ NbfHeader->Command = NBF_CMD_DATA_FIRST_MIDDLE;
+
+ }
+
+ //
+ // Before we release the spinlock, see if we want to
+ // piggyback an ack on here.
+ //
+
+ if ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_ACK) != 0) {
+
+ //
+ // Turn off the flags. We don't take it off the queue,
+ // that will be handled by the timer function.
+ //
+
+ Connection->DeferredFlags &=
+ ~(CONNECTION_FLAGS_DEFERRED_ACK | CONNECTION_FLAGS_DEFERRED_NOT_Q);
+
+ ASSERT (DOL_OPTIONS_ACK_INCLUDED == DFM_OPTIONS_ACK_INCLUDED);
+
+#if DBG
+ if (NbfDebugPiggybackAcks) {
+ NbfPrint0("A");
+ }
+#endif
+
+ //
+ // TRANSMIT_CORR(NbfHeader) is already set correctly.
+ //
+
+ NbfHeader->Data1 |= DOL_OPTIONS_ACK_INCLUDED;
+
+ } else {
+
+ TRANSMIT_CORR(NbfHeader) = (USHORT)0;
+
+ }
+
+ //
+ // To prevent a send "crossing" the receive and
+ // causing a bogus piggyback ack timeout (this
+ // only matters if a receive indication is in
+ // progress).
+ //
+
+ Connection->CurrentReceiveAckQueueable = FALSE;
+
+ SentPacket = TRUE;
+ LastPacketLength =
+ sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION) + PacketBytes;
+
+ MacModifyHeader(
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ LastPacketLength);
+
+ Packet->NdisIFrameLength = LastPacketLength;
+
+ ASSERT (Connection->LinkSpinLock == &Connection->Link->SpinLock);
+
+ Status = SendOnePacket (Connection, Packet, FALSE, &LinkCheckpoint);
+
+ if (Status == STATUS_LINK_FAILED) {
+
+ //
+ // If SendOnePacket failed due to the link being
+ // dead, then we tear down the link.
+ //
+
+ FailSend (Connection, STATUS_LINK_FAILED, TRUE); // fail the send
+ NbfDereferencePacket (Packet); // remove creation hold.
+ if (Direct) {
+ NbfReferenceConnection ("Delayed request ref", Connection, CREF_SEND_IRP);
+ }
+ NbfDereferenceConnection ("Send failed", Connection, CREF_PACKETIZE);
+
+ return;
+
+ } else {
+
+ //
+ // SendOnePacket returned success, so update our counters;
+ //
+
+ DeviceContext->TempIFrameBytesSent += PacketBytes;
+ ++DeviceContext->TempIFramesSent;
+
+ if ((Status == STATUS_SUCCESS) && LinkCheckpoint) {
+
+ //
+ // We are checkpointing; this means that SendOnePacket
+ // will already have set the state to W_LINK and turned
+ // off the PACKETIZE flag, so we should leave. When
+ // the checkpoint response is received, we will
+ // resume packetizing. We don't have to worry about
+ // doing all the other recovery stuff (resetting
+ // the piggyback ack flag, complex send pointer, etc.)
+ // because the send did in fact succeed.
+ //
+
+ if (Direct) {
+#if DBG
+ NbfReferenceConnection ("Delayed request ref", Connection, CREF_SEND_IRP);
+ NbfDereferenceConnection ("Link checkpoint", Connection, CREF_PACKETIZE);
+#endif
+ } else {
+ NbfDereferenceConnection ("Link checkpoint", Connection, CREF_PACKETIZE);
+ }
+ return;
+
+ } else if (ExitAfterSendOnePacket ||
+ (Status == STATUS_MORE_PROCESSING_REQUIRED)) {
+
+ if (Direct) {
+#if DBG
+ NbfReferenceConnection ("Delayed request ref", Connection, CREF_SEND_IRP);
+ NbfDereferenceConnection ("Packetize done", Connection, CREF_PACKETIZE);
+#endif
+ } else {
+ NbfDereferenceConnection ("Packetize done", Connection, CREF_PACKETIZE);
+ }
+ return;
+
+ }
+ }
+ }
+
+BufferChainFailure:;
+
+ //
+ // Note that we may have fallen out of the BuildBuffer... if above with
+ // Status set to STATUS_INSUFFICIENT_RESOURCES. if we have, we'll just
+ // stick this connection back onto the packetize queue and hope the
+ // system gets more resources later.
+ //
+
+
+ if (!NT_SUCCESS (Status)) {
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint0 ("PacketizeSend: SendOnePacket failed.\n");
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // Indicate we're waiting on favorable link conditions.
+ //
+
+ Connection->SendState = CONNECTION_SENDSTATE_W_LINK;
+
+ //
+ // Clear the PACKETIZE flag, indicating that we're no longer
+ // on the PacketizeQueue or actively packetizing. The flag
+ // was set by StartPacketizingConnection to indicate that
+ // the connection was already on the PacketizeQueue.
+ //
+
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // If we are exiting and we sent a packet without
+ // polling, we need to start T1.
+ //
+
+ if (Direct) {
+
+ //
+ // We have to do the CREF_SEND_IRP reference that is missing.
+ //
+
+#if DBG
+ NbfReferenceConnection("TdiSend", Connection, CREF_SEND_IRP);
+ NbfDereferenceConnection ("Send failed", Connection, CREF_PACKETIZE);
+#endif
+ } else {
+ NbfDereferenceConnection ("Send failed", Connection, CREF_PACKETIZE);
+ }
+
+ return;
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // It is probable that a NetBIOS frame arrived while we released
+ // the connection's spin lock, so our state has probably changed.
+ // When we cycle around this loop again, we will have the lock
+ // again, so we can test the connection's send state.
+ //
+
+ } while (Connection->SendState == CONNECTION_SENDSTATE_PACKETIZE);
+
+ //
+ // Clear the PACKETIZE flag, indicating that we're no longer on the
+ // PacketizeQueue or actively packetizing. The flag was set by
+ // StartPacketizingConnection to indicate that the connection was
+ // already on the PacketizeQueue.
+ //
+
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+
+ if (Direct) {
+#if DBG
+ NbfReferenceConnection ("Delayed request ref", Connection, CREF_SEND_IRP);
+ NbfDereferenceConnection ("PacketizeSend done", Connection, CREF_PACKETIZE);
+#endif
+ } else {
+ NbfDereferenceConnection ("PacketizeSend done", Connection, CREF_PACKETIZE);
+ }
+
+} /* PacketizeSend */
+
+
+VOID
+CompleteSend(
+ PTP_CONNECTION Connection,
+ IN USHORT Correlator
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called because the connection partner acknowleged
+ an entire message at the NetBIOS Frames Protocol level, either through
+ a DATA_ACK response, or a RECEIVE_OUTSTANDING, or RECEIVE_CONTINUE,
+ or NO_RECEIVE response where the number of bytes specified exactly
+ matches the number of bytes sent in the message. Here we retire all
+ of the TdiSends on the connection's SendQueue up to and including the
+ one with the TDI_END_OF_RECORD bitflag set. For each request, we
+ complete the I/O.
+
+ NOTE: This function is called with the connection spinlock
+ held and returns with it held, but it may release it in the
+ middle. THIS FUNCTION MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+ Correlator - The correlator in the DATA_ACK or piggybacked ack.
+
+ OldIrqlP - Returns the IRQL at which the connection spinlock
+ was acquired.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+ PLIST_ENTRY p;
+ BOOLEAN EndOfRecord;
+ KIRQL cancelIrql;
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("CompleteSend: Entered for connection %lx.\n", Connection);
+ }
+
+
+ //
+ // Make sure that the correlator is the expect one, and
+ // that we are in a good state (don't worry about locking
+ // since this is an unusual case anyway).
+ //
+
+ if (Correlator != Connection->NetbiosHeader.ResponseCorrelator) {
+ NbfPrint0 ("NbfCompleteSend: ack ignored, wrong correlator\n");
+ return;
+ }
+
+ if (Connection->SendState != CONNECTION_SENDSTATE_W_ACK) {
+ NbfPrint0 ("NbfCompleteSend: ack not expected\n");
+ return;
+ }
+
+ //
+ // Pick off TP_REQUEST objects from the connection's SendQueue until
+ // we find one with an END_OF_RECORD mark embedded in it.
+ //
+
+ while (!(IsListEmpty(&Connection->SendQueue))) {
+
+ //
+ // We know for a fact that we wouldn't be calling this routine if
+ // we hadn't received an acknowlegement for an entire message,
+ // since NBF doesn't provide stream mode sends. Therefore, we
+ // know that we will run into a request with the END_OF_RECORD
+ // mark set BEFORE we will run out of requests on that queue,
+ // so there is no reason to check to see if we ran off the end.
+ // Note that it's possible that the send has been failed and the
+ // connection not yet torn down; if this has happened, we could be
+ // removing from an empty queue here. Make sure that doesn't happen.
+ //
+
+ p = RemoveHeadList(&Connection->SendQueue);
+
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ EndOfRecord = !(IRP_SEND_FLAGS(IrpSp) & TDI_SEND_PARTIAL);
+
+#if DBG
+ NbfCompletedSends[NbfCompletedSendsNext].Irp = Irp;
+ NbfCompletedSends[NbfCompletedSendsNext].Request = NULL;
+ NbfCompletedSends[NbfCompletedSendsNext].Status = STATUS_SUCCESS;
+ NbfCompletedSendsNext = (NbfCompletedSendsNext++) % TRACK_TDI_LIMIT;
+#endif
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_TRACKTDI) {
+ if ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_SENDS) != 0){
+ NbfPrint1 ("CompleteSend: Completing send request %lx\n", Irp);
+ if (++Connection->DeferredPasses >= 4) {
+ Connection->DeferredFlags &= ~CONNECTION_FLAGS_DEFERRED_SENDS;
+ Connection->DeferredPasses = 0;
+ }
+
+ }
+
+ }
+#endif
+
+
+ //
+ // Complete the send. Note that this may not actually call
+ // IoCompleteRequest for the Irp until sometime later, if the
+ // in-progress LLC resending going on below us needs to complete.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // Since the irp is no longer on the send list, the cancel routine
+ // cannot find it and will just return. We must grab the cancel
+ // spinlock to lock out the cancel function while we null out
+ // the Irp->CancelRoutine field.
+ //
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ IoSetCancelRoutine(Irp, NULL);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ NbfCompleteSendIrp (
+ Irp,
+ STATUS_SUCCESS,
+ IRP_SEND_LENGTH(IrpSp));
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ ++Connection->TransmittedTsdus;
+
+ if (EndOfRecord) {
+ break;
+ }
+
+ }
+
+ //
+ // We've finished processing the current send. Update our state.
+ //
+ // Note: The connection spinlock is held here.
+ //
+
+ Connection->SendState = CONNECTION_SENDSTATE_IDLE;
+
+ //
+ // If there is another send pending on the connection, then initialize
+ // it and start packetizing it.
+ //
+
+ if (!(IsListEmpty (&Connection->SendQueue))) {
+
+ InitializeSend (Connection);
+
+ //
+ // This code is similar to calling StartPacketizingConnection
+ // with the second parameter FALSE.
+ //
+
+ if ((!(Connection->Flags & CONNECTION_FLAGS_PACKETIZE)) &&
+ (Connection->Flags & CONNECTION_FLAGS_READY)) {
+
+ Connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
+
+ NbfReferenceConnection ("Packetize", Connection, CREF_PACKETIZE_QUEUE);
+
+ ExInterlockedInsertTailList(
+ &Connection->Provider->PacketizeQueue,
+ &Connection->PacketizeLinkage,
+ &Connection->Provider->SpinLock);
+
+ }
+
+ }
+
+ //
+ // NOTE: We return with the lock held.
+ //
+
+} /* CompleteSend */
+
+
+VOID
+FailSend(
+ IN PTP_CONNECTION Connection,
+ IN NTSTATUS RequestStatus,
+ IN BOOLEAN StopConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called because something on the link caused this send to be
+ unable to complete. There are a number of possible reasons for this to have
+ happened, but all will fail with the common error STATUS_LINK_FAILED.
+ or NO_RECEIVE response where the number of bytes specified exactly
+ Here we retire all of the TdiSends on the connection's SendQueue up to
+ and including the current one, which is the one that failed.
+
+ Later - Actually, a send failing is cause for the entire circuit to wave
+ goodbye to this life. We now simply tear down the connection completly.
+ Any future sends on this connection will be blown away.
+
+ NOTE: THIS FUNCTION MUST BE CALLED WITH THE SPINLOCK HELD.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+ PLIST_ENTRY p;
+ BOOLEAN EndOfRecord;
+ BOOLEAN GotCurrent = FALSE;
+ KIRQL cancelIrql;
+
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("FailSend: Entered for connection %lx.\n", Connection);
+ }
+
+
+ //
+ // Pick off IRP objects from the connection's SendQueue until
+ // we get to this one. If this one does NOT have an EOF mark set, we'll
+ // need to keep going until we hit one that does have EOF set. Note that
+ // this may cause us to continue failing sends that have not yet been
+ // queued. (We do all this because NBF does not provide stream mode sends.)
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ NbfReferenceConnection ("Failing Send", Connection, CREF_COMPLETE_SEND);
+
+ do {
+ if (IsListEmpty (&Connection->SendQueue)) {
+
+ //
+ // got an empty list, so we've run out of send requests to fail
+ // without running into an EOR. Set the connection flag that will
+ // cause all further sends to be failed up to an EOR and get out
+ // of here.
+ //
+
+ Connection->Flags |= CONNECTION_FLAGS_FAILING_TO_EOR;
+ break;
+ }
+ p = RemoveHeadList (&Connection->SendQueue);
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ if (Irp == Connection->sp.CurrentSendIrp) {
+ GotCurrent = TRUE;
+ }
+ EndOfRecord = !(IRP_SEND_FLAGS(IrpSp) & TDI_SEND_PARTIAL);
+
+#if DBG
+ NbfCompletedSends[NbfCompletedSendsNext].Irp = Irp;
+ NbfCompletedSends[NbfCompletedSendsNext].Status = RequestStatus;
+ NbfCompletedSendsNext = (NbfCompletedSendsNext++) % TRACK_TDI_LIMIT;
+#endif
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ IoSetCancelRoutine(Irp, NULL);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ //
+ // The following dereference will complete the I/O, provided removes
+ // the last reference on the request object. The I/O will complete
+ // with the status and information stored in the Irp. Therefore,
+ // we set those values here before the dereference.
+ //
+
+ NbfCompleteSendIrp (Irp, RequestStatus, 0);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ ++Connection->TransmissionErrors;
+
+ } while (!EndOfRecord & !GotCurrent);
+
+ //
+ // We've finished processing the current send. Update our state.
+ //
+
+ Connection->SendState = CONNECTION_SENDSTATE_IDLE;
+ Connection->sp.CurrentSendIrp = NULL;
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // Blow away this connection; a failed send is a terrible thing to waste.
+ // Note that we are not on any packetizing queues or similar things at this
+ // point; we'll just disappear into the night.
+ //
+
+#if MAGIC
+ if (NbfEnableMagic) {
+ extern VOID NbfSendMagicBullet (PDEVICE_CONTEXT, PTP_LINK);
+ NbfSendMagicBullet (Connection->Provider, Connection->Link);
+ }
+#endif
+
+ if (StopConnection) {
+#if DBG
+ if (NbfDisconnectDebug) {
+ STRING remoteName, localName;
+ remoteName.Length = NETBIOS_NAME_LENGTH - 1;
+ remoteName.Buffer = Connection->RemoteName;
+ localName.Length = NETBIOS_NAME_LENGTH - 1;
+ localName.Buffer = Connection->AddressFile->Address->NetworkName->NetbiosName;
+ NbfPrint2( "FailSend stopping connection to %S from %S\n",
+ &remoteName, &localName );
+ }
+#endif
+ NbfStopConnection (Connection, STATUS_LINK_FAILED);
+ }
+
+#if DBG
+ //DbgBreakPoint ();
+#endif
+
+ NbfDereferenceConnection ("FailSend", Connection, CREF_COMPLETE_SEND);
+
+} /* FailSend */
+
+#if DBG
+//
+// *** This is the original version of InitializeSend, which is now a macro.
+// It has been left here as the fully-commented version of the code.
+//
+
+
+VOID
+InitializeSend(
+ PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called whenever the next send on a connection should
+ be initialized; that is, all of the fields associated with the state
+ of the current send are set to refer to the first send on the SendQueue.
+
+ WARNING: This routine is executed with the Connection lock acquired
+ since it must be atomically executed with the caller's setup.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("InitializeSend: Entered for connection %lx.\n", Connection);
+ }
+
+ ASSERT (!IsListEmpty (&Connection->SendQueue));
+
+ Connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
+ Connection->FirstSendIrp =
+ CONTAINING_RECORD (Connection->SendQueue.Flink, IRP, Tail.Overlay.ListEntry);
+ Connection->FirstSendMdl = Connection->FirstSendIrp->MdlAddress;
+ Connection->FirstSendByteOffset = 0;
+ Connection->sp.MessageBytesSent = 0;
+ Connection->sp.CurrentSendIrp = Connection->FirstSendIrp;
+ Connection->sp.CurrentSendMdl = Connection->FirstSendMdl;
+ Connection->sp.SendByteOffset = Connection->FirstSendByteOffset;
+ Connection->CurrentSendLength =
+ IRP_SEND_LENGTH(IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp));
+ Connection->StallCount = 0;
+ Connection->StallBytesSent = 0;
+
+ //
+ // The send correlator isn't used for much; it is used so we
+ // can distinguish which send a piggyback ack is acking.
+ //
+
+ if (Connection->NetbiosHeader.ResponseCorrelator == 0xffff) {
+ Connection->NetbiosHeader.ResponseCorrelator = 1;
+ } else {
+ ++Connection->NetbiosHeader.ResponseCorrelator;
+ }
+
+} /* InitializeSend */
+#endif
+
+
+VOID
+ReframeSend(
+ PTP_CONNECTION Connection,
+ ULONG BytesReceived
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to reset the send state variables in the connection
+ object to correctly point to the first byte of data to be transmitted.
+ In essence, this is the byte-level acknowlegement processor at the NetBIOS
+ level for this transport.
+
+ This is not straightforward because potentially multiple send requests
+ may be posted to the connection to comprise a single message. When a
+ send request has its TDI_END_OF_RECORD option bitflag set, then that
+ send is the last one to be sent in a logical message. Therefore, we
+ assume that the multiple-send scenario is the general case.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+ BytesReceived - Number of bytes received thus far.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PIRP Irp;
+ PMDL Mdl;
+ ULONG Offset;
+ ULONG BytesLeft;
+ ULONG MdlBytes;
+ PLIST_ENTRY p;
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint3 ("ReframeSend: Entered for connection %lx, Flags: %lx Current Mdl: %lx\n",
+ Connection, Connection->Flags, Connection->sp.CurrentSendMdl);
+ }
+
+ //
+ // The caller is responsible for restarting the packetization process
+ // on this connection. In some cases (i.e., NO_RECEIVE handler) we
+ // don't want to start packetizing, so that's why we do it elsewhere.
+ //
+
+ //
+ // Examine all of the send requests and associated MDL chains starting
+ // with the first one at the head of the connection's SendQueue, advancing
+ // our complex current send pointer through the requests and MDL chains
+ // until we reach the byte count he's specified.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // In the case where a local disconnect has been issued, and we get a frame
+ // that causes us to reframe the send our FirstSendIrp and FirstMdl
+ // pointers are stale. Catch this condition and prevent faults caused by
+ // this. A better fix would be to change the logic that switches the
+ // connection sendstate from idle to W_LINK to not do that. However, this
+ // is a broader change than fixing it right here.
+ //
+
+ if (IsListEmpty(&Connection->SendQueue)) {
+ RELEASE_DPC_SPIN_LOCK(Connection->LinkSpinLock);
+ return;
+ }
+
+ BytesLeft = BytesReceived;
+ Irp = Connection->FirstSendIrp;
+ Mdl = Connection->FirstSendMdl;
+ if (Mdl) {
+ MdlBytes = MmGetMdlByteCount (Mdl);
+ } else {
+ MdlBytes = 0; // zero-length send
+ }
+ Offset = Connection->FirstSendByteOffset;
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_TRACKTDI) {
+ NbfPrint3 ("ReFrameSend: Called with Connection %lx FirstSend %lx CurrentSend %lx\n",
+ Connection, Connection->FirstSendIrp, Connection->sp.CurrentSendIrp);
+ Connection->DeferredFlags |= CONNECTION_FLAGS_DEFERRED_SENDS;
+ Connection->DeferredPasses = 0;
+ }
+#endif
+
+ //
+ // We loop through while we have acked bytes left to account for,
+ // advancing our pointers and completing any sends that have been
+ // completely acked.
+ //
+
+ while (BytesLeft != 0) {
+
+ if (Mdl == NULL) {
+ KIRQL cancelIrql;
+
+ //
+ // We have exhausted the MDL chain on this request, so it has
+ // been implicitly acked. That means we must complete the I/O
+ // by dereferencing the request before we reframe further.
+ //
+
+ p = RemoveHeadList (&Connection->SendQueue);
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+
+ //
+ // Since the irp is no longer on the list, the cancel routine
+ // won't find it. Grab the cancel spinlock to synchronize
+ // and complete the irp.
+ //
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ IoSetCancelRoutine(Irp, NULL);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ NbfCompleteSendIrp (Irp, STATUS_SUCCESS, Offset);
+
+ //
+ // Now continue with the next request in the list.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ p = Connection->SendQueue.Flink;
+ if (p == &Connection->SendQueue) {
+
+ ULONG DumpData[2];
+
+ //
+ // The byte acknowledgement was for more than the
+ // total length of sends we have outstanding; to
+ // avoid problems we tear down the connection.
+ //
+#if DBG
+ NbfPrint2 ("NbfReframeSend: Got %d extra bytes acked on %lx\n",
+ BytesLeft, Connection);
+ ASSERT (FALSE);
+#endif
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ DumpData[0] = Offset;
+ DumpData[1] = BytesLeft;
+
+ NbfWriteGeneralErrorLog(
+ Connection->Provider,
+ EVENT_TRANSPORT_BAD_PROTOCOL,
+ 1,
+ STATUS_INVALID_NETWORK_RESPONSE,
+ L"REFRAME",
+ 2,
+ DumpData);
+
+ NbfStopConnection (Connection, STATUS_INVALID_NETWORK_RESPONSE);
+
+ return;
+
+ }
+
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ Mdl = Irp->MdlAddress;
+ MdlBytes = MmGetMdlByteCount (Mdl);
+ Offset = 0;
+
+ } else if (MdlBytes > (Offset + BytesLeft)) {
+
+ //
+ // This MDL has more data than we really need. Just use
+ // part of it. Then get out, because we're done.
+ //
+
+ Offset += BytesLeft;
+ BytesLeft = 0;
+ break;
+
+ } else {
+
+ //
+ // This MDL does not have enough data to satisfy the ACK, so
+ // use as much data as it has, and cycle around again.
+ //
+
+ Offset = 0;
+ BytesLeft -= MdlBytes;
+ Mdl = Mdl->Next;
+
+ if (Mdl != NULL) {
+ MdlBytes = MmGetMdlByteCount (Mdl);
+ }
+
+ }
+ }
+
+ //
+ // Tmp debugging; we want to see if we got byte acked
+ // for the entire send. This will break if we have
+ // non-EOR sends.
+ //
+
+#if DBG
+ if (BytesReceived != 0) {
+ ASSERTMSG ("NbfReframeSend: Byte ack for entire send\n",
+ Mdl != NULL);
+ }
+#endif
+
+ //
+ // We've acked some data, possibly on a byte or message boundary.
+ // We must pretend we're sending a new message all over again,
+ // starting with the byte immediately after the last one he acked.
+ //
+
+ Connection->FirstSendIrp = Irp;
+ Connection->FirstSendMdl = Mdl;
+ Connection->FirstSendByteOffset = Offset;
+
+ //
+ // Since we haven't started sending this new reframed message yet,
+ // we set our idea of the current complex send pointer to the first
+ // complex send pointer.
+ //
+
+ Connection->sp.MessageBytesSent = 0;
+ Connection->sp.CurrentSendIrp = Irp;
+ Connection->sp.CurrentSendMdl = Mdl;
+ Connection->sp.SendByteOffset = Offset;
+ Connection->CurrentSendLength -= BytesReceived;
+ Connection->StallCount = 0;
+ Connection->StallBytesSent = 0;
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_TRACKTDI) {
+
+ {
+ PLIST_ENTRY p;
+ NbfPrint0 ("ReFrameSend: Walking Send List:\n");
+
+ for (
+ p = Connection->SendQueue.Flink;
+ p != &Connection->SendQueue;
+ p=p->Flink ) {
+
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ NbfPrint1 (" Irp %lx\n", Irp);
+ }
+ }}
+#endif
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+} /* ReframeSend */
+
+
+VOID
+NbfCancelSend(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a send.
+ The send is found on the connection's send queue; if it is the
+ current request it is cancelled and the connection is torn down,
+ otherwise it is silently cancelled.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PIO_STACK_LOCATION IrpSp;
+ PTP_CONNECTION Connection;
+ PIRP SendIrp;
+ PLIST_ENTRY p;
+ BOOLEAN Found;
+
+ UNREFERENCED_PARAMETER (DeviceObject);
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (IrpSp->MinorFunction == TDI_SEND));
+
+ Connection = IrpSp->FileObject->FsContext;
+
+ //
+ // Since this IRP is still in the cancellable state, we know
+ // that the connection is still around (although it may be in
+ // the process of being torn down).
+ //
+
+
+ //
+ // See if this is the IRP for the current send request.
+ //
+
+ ACQUIRE_SPIN_LOCK (Connection->LinkSpinLock, &oldirql);
+ NbfReferenceConnection ("Cancelling Send", Connection, CREF_COMPLETE_SEND);
+
+ p = Connection->SendQueue.Flink;
+ SendIrp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+
+ if (SendIrp == Irp) {
+
+ //
+ // yes, it is the first one on the send queue, so
+ // trash the send/connection. The first send is a special case
+ // there are multiple pointers to the send request. Just stop the
+ // connection.
+ //
+
+ // p = RemoveHeadList (&Connection->SendQueue);
+
+#if DBG
+ NbfCompletedSends[NbfCompletedSendsNext].Irp = SendIrp;
+ NbfCompletedSends[NbfCompletedSendsNext].Status = STATUS_CANCELLED;
+ NbfCompletedSendsNext = (NbfCompletedSendsNext++) % TRACK_TDI_LIMIT;
+#endif
+
+ //
+ // Prevent anyone from getting in to packetize before we
+ // call NbfStopConnection.
+ //
+
+ Connection->SendState = CONNECTION_SENDSTATE_IDLE;
+
+ RELEASE_SPIN_LOCK (Connection->LinkSpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+#if DBG
+ DbgPrint("NBF: Canceled in-progress send %lx on %lxn",
+ SendIrp, Connection);
+#endif
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql1);
+
+ //
+ // The following dereference will complete the I/O, provided removes
+ // the last reference on the request object. The I/O will complete
+ // with the status and information stored in the Irp. Therefore,
+ // we set those values here before the dereference.
+ //
+
+ // NbfCompleteSendIrp (SendIrp, STATUS_CANCELLED, 0);
+
+ //
+ // Since we are cancelling the current send, blow away
+ // the connection.
+ //
+
+ NbfStopConnection (Connection, STATUS_CANCELLED);
+
+ KeLowerIrql (oldirql1);
+
+ } else {
+
+ //
+ // Scan through the list, looking for this IRP. If we
+ // cancel anything up to the first EOR on the list
+ // we still tear down the connection since this would
+ // mess up our packetizing otherwise. We set CancelledFirstEor
+ // to FALSE when we pass an IRP without SEND_PARTIAL.
+ //
+ // NO MATTER WHAT WE MUST SHUT DOWN THE CONNECTION!!!!
+
+#if 0
+ if (!(IRP_SEND_FLAGS(IoGetCurrentIrpStackLocation(SendIrp)) & TDI_SEND_PARTIAL)) {
+ CancelledFirstEor = FALSE;
+ } else {
+ CancelledFirstEor = TRUE;
+ }
+#endif
+
+ Found = FALSE;
+ p = p->Flink;
+ while (p != &Connection->SendQueue) {
+
+ SendIrp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ if (SendIrp == Irp) {
+
+ //
+ // Found it, remove it from the list here.
+ //
+
+ RemoveEntryList (p);
+
+ Found = TRUE;
+
+#if DBG
+ NbfCompletedSends[NbfCompletedSendsNext].Irp = SendIrp;
+ NbfCompletedSends[NbfCompletedSendsNext].Status = STATUS_CANCELLED;
+ NbfCompletedSendsNext = (NbfCompletedSendsNext++) % TRACK_TDI_LIMIT;
+#endif
+
+ RELEASE_SPIN_LOCK (Connection->LinkSpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+#if DBG
+ DbgPrint("NBF: Canceled queued send %lx on %lx\n",
+ SendIrp, Connection);
+#endif
+
+ //
+ // The following dereference will complete the I/O, provided removes
+ // the last reference on the request object. The I/O will complete
+ // with the status and information stored in the Irp. Therefore,
+ // we set those values here before the dereference.
+ //
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql1);
+
+ NbfCompleteSendIrp (SendIrp, STATUS_CANCELLED, 0);
+ //
+ // STOP THE CONNECTION NO MATTER WHAT!!!
+ //
+ NbfStopConnection (Connection, STATUS_CANCELLED);
+
+ KeLowerIrql (oldirql1);
+ break;
+
+ }
+#if 0
+ else {
+
+ if (CancelledFirstEor && (!(IRP_SEND_FLAGS(IoGetCurrentIrpStackLocation(SendIrp)) & TDI_SEND_PARTIAL))) {
+ CancelledFirstEor = FALSE;
+ }
+ }
+#endif
+
+ p = p->Flink;
+
+ }
+
+ if (!Found) {
+
+ //
+ // We didn't find it!
+ //
+
+#if DBG
+ DbgPrint("NBF: Tried to cancel send %lx on %lx, not found\n",
+ Irp, Connection);
+#endif
+ RELEASE_SPIN_LOCK (Connection->LinkSpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+ }
+
+ }
+
+ NbfDereferenceConnection ("Cancelling Send", Connection, CREF_COMPLETE_SEND);
+
+}
+
+
+BOOLEAN
+ResendPacket (
+ PTP_LINK Link,
+ PTP_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine resends a packet on the link. Since this is a resend, we
+ are careful to not reset the state unless all resends have completed.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a TP_LINK object.
+
+ Packet - pointer to packet to be resent.
+
+Return Value:
+
+ True if resending should continue; FALSE otherwise.
+
+--*/
+
+{
+ BOOLEAN PollFinal;
+ PDLC_I_FRAME DlcHeader;
+ UINT DataLength;
+
+
+ //
+
+ DlcHeader = (PDLC_I_FRAME)&(Packet->Header[Link->HeaderLength]);
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint3 ("ReSendPacket: %lx NdisPacket: %lx # %x\n",
+ Packet, Packet->NdisPacket,
+ DlcHeader->RcvSeq >>1);
+ IF_NBFDBG (NBF_DEBUG_PKTCONTENTS) {
+ {PUCHAR q;
+ USHORT i;
+ q = Packet->Header;
+ for (i=0;i<20;i++) {
+ NbfPrint1 (" %2x",q[i]);
+ }
+ NbfPrint0 ("\n");}
+ }
+ }
+
+ DataLength = Packet->NdisIFrameLength;
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ Link->WindowErrors++;
+
+ PollFinal = (BOOLEAN)((DlcHeader->RcvSeq & DLC_I_PF) != 0);
+
+ StopT2 (Link); // since this is potentially acking some frames
+
+ if (Link->Provider->MacInfo.MediumAsync) {
+ if (PollFinal) {
+ ASSERT (Packet->Link != NULL);
+ NbfReferenceLink ("ResendPacket", Link, LREF_START_T1);
+ } else {
+ StartT1 (Link, 0);
+ }
+ } else {
+ StartT1 (Link, PollFinal ? DataLength : 0); // restart transmission timer
+ }
+
+ //
+ // Update the expected next receive in case it's changed
+ //
+
+ if (PollFinal) {
+
+ DlcHeader->RcvSeq = DLC_I_PF; // set the poll bit.
+ Link->SendState = SEND_STATE_CHECKPOINTING;
+
+ Link->ResendingPackets = FALSE;
+
+ } else {
+
+ DlcHeader->RcvSeq = 0;
+
+ }
+
+ //
+ // DlcHeader->RcvSeq has Link->NextReceive inserted by NbfNdisSend.
+ //
+
+ NbfReferencePacket (Packet); // so we don't remove it in send completion
+
+ NbfReferenceLink ("ResendPacket", Link, LREF_NDIS_SEND);
+
+ ASSERT (Packet->PacketSent == TRUE);
+ Packet->PacketSent = FALSE;
+
+ //
+ // Update our "bytes resent" counters.
+ //
+
+ DataLength -=
+ Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION);
+
+
+ ADD_TO_LARGE_INTEGER(
+ &Link->Provider->Statistics.DataFrameBytesResent,
+ DataLength);
+ ++Link->Provider->Statistics.DataFramesResent;
+
+
+ //
+ // Send the packet (this release the link spinlock).
+ //
+
+ NbfNdisSend (Link, Packet);
+
+ ++Link->PacketsResent;
+
+ NbfDereferenceLink ("ResendPacket", Link, LREF_NDIS_SEND);
+
+ //
+ // if this packet has POLL set, stop the resending so the
+ // link doesn't get all twisted up.
+ //
+
+ if (PollFinal) {
+
+ //
+ // so we're in the state of having sent a poll and not
+ // sending anything else until we get a final. This avoids
+ // overrunning the remote. Note that we leave the routine
+ // with state LINK_SENDSTATE_REJECTING, which guarentees
+ // we won't start any new sends until we traverse through
+ // this routine again.
+ //
+ //
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+ResendLlcPackets (
+ PTP_LINK Link,
+ UCHAR AckSequenceNumber,
+ BOOLEAN Resend
+ )
+
+/*++
+
+Routine Description:
+
+ This routine advances the state of a data link connection by retiring
+ all of the packets on the link's WackQ that have send sequence numbers
+ logically less than that number specified as the AckSequenceNumber, and
+ resending those above that number. The packets are disposed of by
+ dereferencing them. We cannot simply destroy them because this
+ acknowlegement might arrive even before the Physical Provider has had a
+ chance to issue a completion event for the associated I/O.
+
+ NOTE: This function is called with the link spinlock held and
+ returns with it held, but it may release it in between. THIS
+ ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a TP_LINK object.
+
+ AckSequenceNumber - An unsigned number specifing the sequence number of
+ the first packet within the window that is NOT acknowleged.
+
+ Resend - if TRUE, resend packets. If FALSE, just remove them from the
+ wackq and get out.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PTP_PACKET packet;
+ PLIST_ENTRY p, p1;
+ UCHAR packetSeq;
+ BOOLEAN passedAck = FALSE;
+ PDLC_I_FRAME DlcHeader;
+ SCHAR Difference;
+ BOOLEAN ReturnValue = FALSE;
+// NDIS_STATUS ndisStatus;
+
+ //
+ // Move through the queue, releasing those we've been acked for and resending
+ // others above that.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint3 ("ResendLlcPackets: Link %lx, Ack: %x, LinkLastAck: %x.\n",
+ Link, AckSequenceNumber, Link->LastAckReceived);
+ NbfPrint0 ("RLP: Walking WackQ, Packets:\n");
+ p = Link->WackQ.Flink; // p = ptr, 1st pkt's linkage.
+ while (p != &Link->WackQ) {
+ packet = CONTAINING_RECORD (p, TP_PACKET, Linkage);
+ DlcHeader = (PDLC_I_FRAME)&(packet->Header[Link->HeaderLength]);
+ NbfPrint4 ("RLP: Pkt: %lx # %x Flags: %d %d\n", packet,
+ (UCHAR)(DlcHeader->SendSeq >> 1), packet->PacketSent, packet->PacketNoNdisBuffer);
+ p = packet->Linkage.Flink;
+ }
+ }
+
+ //
+ // If somebody else is resending LLC packets (which means they
+ // are in this function with Resend == TRUE), then ignore
+ // this frame. This is because it may ack a frame that he
+ // is in the middle of resending, which will cause problems.
+ //
+ // BUGBUG: This isn't a great solution, we should keep track
+ // of where the other guy is and avoid stepping on him. This
+ // might mess up his walking of the queue however.
+ //
+
+ if (Link->ResendingPackets) {
+ NbfPrint1("ResendLlcPackets: Someone else resending on %lx\n", Link);
+ return TRUE;
+ }
+
+ //
+ // We have already checked that AckSequenceNumber is reasonable.
+ //
+
+ Link->LastAckReceived = AckSequenceNumber;
+
+ if (Resend) {
+
+ //
+ // Only one person can be resending or potentially resending
+ // at one time.
+ //
+
+ Link->ResendingPackets = TRUE;
+ }
+
+ //
+ // Resend as many packets as we have window to send. We spin through the
+ // queue and remove those packets that have been acked or that are
+ // sequence numbered logically below the current ack number. The flags
+ // PACKET_FLAGS_RESEND and PACKET_FLAGS_SENT correspond to the three states
+ // a packet on this queue can be in:
+ //
+ // 1) if _RESEND is set, the packet has not been acked
+ //
+ // 2) if _SENT is set, the packet send has completed (conversely, if NOT
+ // set, the packet has not yet been completely sent, thus it is
+ // unnecessary to resend it).
+ // 3) if _RESEND and _SENT are both set, the packet has been sent and not
+ // acked and is grist for our mills.
+ // 4) if neither is set, the world is coming to an end next Thursday.
+ //
+
+ p=Link->WackQ.Flink;
+ while (p != &Link->WackQ) {
+ packet = CONTAINING_RECORD (p, TP_PACKET, Linkage);
+ DlcHeader = (PDLC_I_FRAME)&(packet->Header[Link->HeaderLength]);
+
+ //
+ // if both bits aren't set we can't do a thing with this packet, or,
+ // for that matter, with the rest of the packet list. We can't
+ // have reached the ack number yet, as these packets haven't even
+ // completed sending.
+ // (Later) actually, we can have reached passedAck, and if we did
+ // we're in a world of hurt. We can't send more regular packets,
+ // but we can't send any resend packets either. Force the link to
+ // checkpoint and things will clear themselves up later.
+ //
+
+ if (!(packet->PacketSent)) {
+ if (passedAck) {
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint2 ("ResendLLCPacket: Can't send WACKQ Packet RcvSeq %x %x \n",
+ DlcHeader->RcvSeq, DlcHeader->SendSeq);
+ }
+
+ if (Link->SendState != SEND_STATE_CHECKPOINTING) {
+
+ //
+ // Don't start checkpointing if we already are.
+ //
+
+ Link->SendState = SEND_STATE_CHECKPOINTING;
+ StopTi (Link);
+ StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME)); // start checkpoint timeout.
+ Link->ResendingPackets = FALSE;
+
+ //
+ // Try this...in this case don't actually send
+ // an RR, since his response might put us right
+ // back here. When T1 expires we will recover.
+ //
+ // NbfSendRr (Link, TRUE, TRUE);
+
+ } else {
+
+ Link->ResendingPackets = FALSE;
+
+ }
+
+ return TRUE;
+ }
+
+ //
+ // Don't break, since passedAck is FALSE all we will
+ // do in the next section is TpDereferencePacket, which
+ // is correct.
+ //
+ // break;
+ }
+
+ //
+ // This loop is somewhat schizo; at this point, if we've not yet reached
+ // the ack number, we'll be ditching the packet. If we've gone through
+ // the ack number, we'll be re-transmitting. Note that in the first
+ // personality, we are always looking at the beginning of the list.
+ //
+
+ //
+ // NOTE: Link spinlock is held here.
+ //
+
+ packetSeq = (UCHAR)(DlcHeader->SendSeq >> 1);
+ if (!passedAck){
+
+ //
+ // Compute the signed difference here; see if
+ // packetSeq is equal to or "greater than"
+ // LastAckReceived.
+ //
+
+ Difference = packetSeq - Link->LastAckReceived;
+
+ if (((Difference >= 0) && (Difference < 0x40)) ||
+ (Difference < -0x40)) {
+
+ //
+ // We have found a packet on the queue that was
+ // not acknowledged by LastAckReceived.
+ //
+
+ if (Link->SendState == SEND_STATE_CHECKPOINTING) {
+
+ //
+ // If we are checkpointing, we should not do any of
+ // the passedAck things (i.e. any of the things which
+ // potentially involve sending packets) - adb 7/30/91.
+ //
+
+ if (Resend) {
+ Link->ResendingPackets = FALSE;
+ }
+ return TRUE;
+ }
+
+ if (!Resend) {
+
+ //
+ // If we are not supposed to resend, then exit.
+ // Since there are still packets on the queue
+ // we restart T1.
+ //
+
+ StopTi (Link);
+ StartT1 (Link, 0); // start checkpoint timeout.
+ return TRUE;
+ }
+
+ //
+ // Lock out senders, so we maintain packet sequences properly
+ //
+
+ Link->SendState = SEND_STATE_REJECTING; // we're resending.
+
+ passedAck = TRUE;
+
+ //
+ // Note that we don't advance the pointer to the next packet;
+ // thus, we will resend this packet on the next pass through
+ // the while loop (taking the passedAck branch).
+ //
+
+ } else {
+ p1 = RemoveHeadList (&Link->WackQ);
+ ASSERTMSG (" ResendLLCPacket: Packet not at queue head!\n", (p == p1));
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ ReturnValue = TRUE;
+ NbfDereferencePacket (packet);
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ p = Link->WackQ.Flink;
+ }
+
+ } else {
+// NbfPrint1 ("RLP: # %x\n",packetSeq);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ //
+ // If this call returns FALSE (because we checkpoint)
+ // it clears ResendingPacket before it returns.
+ //
+
+ if (!ResendPacket (Link, packet)) {
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ return ReturnValue;
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ p = p->Flink;
+ }
+ }
+
+ //
+ // NOTE: Link spinlock is held here.
+ //
+
+ if (passedAck) {
+
+ //
+ // If we exit through here with passedAck TRUE, it means that we
+ // successfully called ResendPacket on every packet in the
+ // WackQ, which means we did not resend a poll packet, so we
+ // can start sending normally again. We have to clear
+ // ResendingPackets here.
+ //
+
+ Link->SendState = SEND_STATE_READY;
+ Link->ResendingPackets = FALSE;
+ StartTi (Link);
+
+ } else if (!Resend) {
+
+ //
+ // If Resend is FALSE (in which case passedAck will also be FALSE,
+ // by the way), and the WackQ is empty, that means that we
+ // successfully acknowledged all the packets on a non-final
+ // frame. In this case T1 may be running, but in fact is not
+ // needed since there are no sends outstanding.
+ //
+
+ if (Link->WackQ.Flink == &Link->WackQ) {
+ StopT1 (Link); // BUGBUG: StartTi??
+ }
+ Link->SendState = SEND_STATE_READY;
+ StartTi (Link);
+
+ } else {
+
+ //
+ // Resend is TRUE, but passedAck is FALSE; we came in
+ // expecting to resend, but didn't. This means that
+ // we have emptied the queue after receiving an
+ // RR/f, i.e. this send window is done and we can
+ // update our send window size, etc.
+ //
+
+ Link->ResendingPackets = FALSE;
+
+ if (Link->Provider->MacInfo.MediumAsync) {
+ return ReturnValue;
+ }
+
+ if (Link->WindowErrors > 0) {
+
+ //
+ // We had transmit errors on this window.
+ //
+
+ Link->PrevWindowSize = Link->SendWindowSize;
+
+ //
+ // We use 100 ms delay as the cutoff for a LAN.
+ //
+
+ if (Link->Delay < (100*MILLISECONDS)) {
+
+ //
+ // On a LAN, if we have a special case
+ // if one packet was lost; this means the
+ // final packet was retransmitted once. In
+ // that case, we keep track of Consecutive
+ // LastPacketLost, and if it reaches 2, then
+ // we lock the send window at its current
+ // value minus one.
+ //
+
+ if (Link->WindowErrors == 1) {
+
+ ++Link->ConsecutiveLastPacketLost;
+
+ if (Link->ConsecutiveLastPacketLost >= 2) {
+
+ //
+ // Freeze the window wherever it was.
+ //
+
+ if (Link->SendWindowSize > Link->Provider->MinimumSendWindowLimit) {
+ Link->MaxWindowSize = Link->SendWindowSize - 1;
+ Link->SendWindowSize = (UCHAR)Link->MaxWindowSize;
+ }
+
+ }
+
+ //
+ // Otherwise, we leave the window where it is.
+ //
+
+ } else {
+
+ Link->ConsecutiveLastPacketLost = 0;
+ Link->SendWindowSize -= (UCHAR)Link->WindowErrors;
+
+ }
+
+ } else {
+
+ //
+ // On a WAN we cut the send window in half,
+ // regardless of how many frames were retransmitted.
+ //
+
+ Link->SendWindowSize /= 2;
+ Link->WindowsUntilIncrease = 1; // in case Prev is also 1.
+ Link->ConsecutiveLastPacketLost = 0;
+
+ }
+
+ if ((SCHAR)Link->SendWindowSize < 1) {
+ Link->SendWindowSize = 1;
+ }
+
+ //
+ // Reset our counters for the next window.
+ //
+
+ Link->WindowErrors = 0;
+
+ } else {
+
+ //
+ // We have successfully sent a window of data, increase
+ // the send window size unless we are at the limit.
+ // We use 100 ms delay as the WAN/LAN cutoff.
+ //
+
+ if ((ULONG)Link->SendWindowSize < Link->MaxWindowSize) {
+
+ if (Link->Delay < (100*MILLISECONDS)) {
+
+ //
+ // On a LAN, increase the send window by 1.
+ //
+ // BUGBUG: Need to determine optimal window
+ // size.
+ //
+
+ Link->SendWindowSize++;
+
+ } else {
+
+ //
+ // On a WAN, increase the send window by 1 until
+ // we hit PrevWindowSize, then do it more slowly.
+ //
+
+ if (Link->SendWindowSize < Link->PrevWindowSize) {
+
+ Link->SendWindowSize++;
+
+ //
+ // If we just increased it to the previous window
+ // size, prepare for the next time through here.
+ //
+
+ if (Link->SendWindowSize == Link->PrevWindowSize) {
+ Link->WindowsUntilIncrease = Link->SendWindowSize;
+ }
+
+ } else {
+
+ //
+ // We passed the previous size, so only update every
+ // WindowsUntilIncrease times.
+ //
+
+ if (--Link->WindowsUntilIncrease == 0) {
+
+ Link->SendWindowSize++;
+ Link->WindowsUntilIncrease = Link->SendWindowSize;
+
+ }
+ }
+ }
+
+ if ((ULONG)Link->SendWindowSize > Link->Provider->Statistics.MaximumSendWindow) {
+ Link->Provider->Statistics.MaximumSendWindow = Link->SendWindowSize;
+ }
+
+ }
+
+ //
+ // Clear this since we had no errors.
+ //
+
+ Link->ConsecutiveLastPacketLost = 0;
+
+ }
+
+ }
+
+ return ReturnValue;
+
+} /* ResendLlcPackets */
+
+
+VOID
+NbfSendCompletionHandler(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to indicate that a connection-
+ oriented packet has been shipped and is no longer needed by the Physical
+ Provider.
+
+Arguments:
+
+ NdisContext - the value associated with the adapter binding at adapter
+ open time (which adapter we're talking on).
+
+ NdisPacket/RequestHandle - A pointer to the NDIS_PACKET that we sent.
+
+ NdisStatus - the completion status of the send.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PSEND_PACKET_TAG SendContext;
+ PTP_PACKET Packet;
+ KIRQL oldirql1;
+ ProtocolBindingContext; // avoid compiler warnings
+
+#if DBG
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfSendsCompletedAfterPendFail++;
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint2 ("NbfSendComplete: Entered for packet %lx, Status %s\n",
+ NdisPacket, NbfGetNdisStatus (NdisStatus));
+ }
+ } else {
+ NbfSendsCompletedAfterPendOk++;
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint2 ("NbfSendComplete: Entered for packet %lx, Status %s\n",
+ NdisPacket, NbfGetNdisStatus (NdisStatus));
+ }
+ }
+#endif
+
+ SendContext = (PSEND_PACKET_TAG)&NdisPacket->ProtocolReserved[0];
+
+ switch (SendContext->Type) {
+ case TYPE_I_FRAME:
+
+ //
+ // Just dereference the packet. There are a couple possibilities here.
+ // First, the I/O completion might happen before an ACK is received,
+ // in which case this will remove one of the references, but not both.
+ // Second, the LLC ACK for this packet may have already been processed,
+ // in which case this will destroy the packet. Third, this packet may
+ // be resent, either before or after this call, in which case the deref
+ // won't destroy the packet.
+ //
+ // NbfDereferencePacket will call PacketizeSend if it determines that
+ // there is at least one connection waiting to be packetized because
+ // of out-of-resource conditions or because its window has been opened.
+ //
+
+ Packet = ((PTP_PACKET)SendContext->Frame);
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql1);
+
+ if (Packet->Provider->MacInfo.MediumAsync) {
+
+ if (Packet->Link) {
+
+ ASSERT (Packet->NdisIFrameLength > 0);
+
+ ACQUIRE_DPC_SPIN_LOCK (&Packet->Link->SpinLock);
+ StartT1 (Packet->Link, Packet->NdisIFrameLength);
+ RELEASE_DPC_SPIN_LOCK (&Packet->Link->SpinLock);
+
+ NbfDereferenceLink ("Send completed", Packet->Link, LREF_START_T1);
+ }
+
+ if (Packet->PacketizeConnection) {
+
+ PTP_CONNECTION Connection = IRP_SEND_CONNECTION((PIO_STACK_LOCATION)(Packet->Owner));
+ PDEVICE_CONTEXT DeviceContext = Packet->Provider;
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ if ((Connection->SendState == CONNECTION_SENDSTATE_PACKETIZE) &&
+ (Connection->Flags & CONNECTION_FLAGS_READY)) {
+
+ ASSERT (Connection->Flags & CONNECTION_FLAGS_PACKETIZE);
+
+ ACQUIRE_DPC_SPIN_LOCK(&DeviceContext->SpinLock);
+
+ NbfReferenceConnection ("Delayed packetizing", Connection, CREF_PACKETIZE_QUEUE);
+ InsertTailList(&DeviceContext->PacketizeQueue, &Connection->PacketizeLinkage);
+
+ if (!DeviceContext->WanThreadQueued) {
+
+ DeviceContext->WanThreadQueued = TRUE;
+ ExQueueWorkItem(&DeviceContext->WanDelayedQueueItem, DelayedWorkQueue);
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ } else {
+
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ NbfDereferenceConnection ("PacketizeConnection FALSE", Connection, CREF_TEMP);
+
+ Packet->PacketizeConnection = FALSE;
+
+ }
+ }
+#if DBG
+ if (Packet->PacketSent) {
+ DbgPrint ("NbfSendCompletionHandler: Packet %lx already completed\n", Packet);
+ DbgBreakPoint();
+ }
+#endif
+ Packet->PacketSent = TRUE;
+
+ NbfDereferencePacket (Packet);
+
+ KeLowerIrql (oldirql1);
+ break;
+
+ case TYPE_UI_FRAME:
+
+ //
+ // just destroy the frame; name stuff doesn't depend on having any
+ // of the sent message left around after the send completed.
+ //
+
+ NbfDestroyConnectionlessFrame ((PDEVICE_CONTEXT)SendContext->Owner,
+ (PTP_UI_FRAME)SendContext->Frame);
+ break;
+
+ case TYPE_ADDRESS_FRAME:
+
+ //
+ // Addresses get their own frames; let the address know it's ok to
+ // use the frame again.
+ //
+
+ NbfSendDatagramCompletion ((PTP_ADDRESS)SendContext->Owner,
+ NdisPacket,
+ NdisStatus );
+ break;
+ }
+
+ return;
+
+} /* NbfSendCompletionHandler */
+
+
+NTSTATUS
+SendOnePacket(
+ IN PTP_CONNECTION Connection,
+ IN PTP_PACKET Packet,
+ IN BOOLEAN ForceAck,
+ OUT PBOOLEAN LinkCheckpoint OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a connection-oriented packet by calling the NDIS
+ Send service. At least one event will occur following
+ (or during) the Send request's processing. (1) The Send request
+ will complete through the I/O system, calling IoCompleteRequest.
+ (2) The sequenced packet will be acknowleged at the LLC level, or it
+ will be rejected and reset at the LLC level. If the packet is resent,
+ then it remains queued at the TP_LINK object. If the packet is ACKed,
+ then is removed from the link's WackQ and the Action field in the
+ TP_PACKET structure dictates what operation to perform next.
+
+ NOTE: This routine is called with the link spinlock held. THIS
+ ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+ NOTE: This routine will now accept all frames unless the link
+ is down. If the link cannot send, the packet will be queued and
+ sent when possible.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+ Packet - Pointer to a TP_PACKET object.
+
+ ForceAck - Boolean that, if true, indicates this packet should always have
+ the Poll bit set; this force the other side to ack immediately,
+ which is necessary for correct session teardown.
+
+ LinkCheckpoint - If specified, will return TRUE if the link has
+ just entered a checkpoint state. In this case the status
+ will be STATUS_SUCCESS, but the connection should stop
+ packetizing now (in fact, to close a window, the connection
+ is put into the W_LINK state if this status will be
+ returned, so he must stop because somebody else may
+ already be doing it).
+
+Return Value:
+
+ STATUS_LINK_FAILED - the link is dead or not ready.
+ STATUS_SUCCESS - the packet has been sent.
+ STATUS_INSUFFICIENT_RESOURCES - the packet has been queued.
+
+--*/
+
+{
+ PTP_LINK Link;
+ PDLC_I_FRAME DlcHeader;
+ PNDIS_BUFFER ndisBuffer;
+ ULONG SendsOutstanding;
+ BOOLEAN Poll = FALSE;
+ NTSTATUS Status;
+
+ IF_NBFDBG (NBF_DEBUG_PACKET) {
+ NbfPrint3 ("SendOnePacket: Entered, connection %lx, packet %lx DnisPacket %lx.\n",
+ Connection, Packet, Packet->NdisPacket);
+ }
+
+ Link = Connection->Link;
+
+ IF_NBFDBG (NBF_DEBUG_PACKET) {
+ UINT PLength, PCount;
+ UINT BLength;
+ PVOID BAddr;
+ NdisQueryPacket(Packet->NdisPacket, &PCount, NULL, &ndisBuffer, &PLength);
+ NbfPrint3 ("Sending Data Packet: %lx, Length: %lx Pages: %lx\n",
+ Packet->NdisPacket, PLength, PCount);
+ while (ndisBuffer != NULL) {
+ NdisQueryBuffer(ndisBuffer, &BAddr, &BLength);
+ NbfPrint3 ("Sending Data Packet: Buffer %08lx Length %08lx Va %08lx\n",
+ ndisBuffer, BLength, BAddr);
+ NdisGetNextBuffer (ndisBuffer, &ndisBuffer);
+ }
+ }
+
+ //
+ // If the general state of the link is not READY, then we can't ship.
+ // This failure can be expected under some conditions, and may not cause
+ // failure of the send.
+ //
+
+ if (Link->State != LINK_STATE_READY) {
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("SendOnePacket: Link state is not READY (%ld).\n", Link->State);
+ }
+
+ //
+ // determine what to do with this problem. If we shouldn't be sending
+ // here, percolate an error upward.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint3 ("SendOnePacket: Link Bad state, link: %lx Link Flags %lx Link State %lx\n",
+ Link, Link->Flags, Link->State);
+ }
+ return STATUS_LINK_FAILED;
+ }
+
+
+ SendsOutstanding = (((ULONG)Link->NextSend+128L-(ULONG)Link->LastAckReceived)%128L);
+
+ //
+ // Format LLC header while we've got the spinlock to atomically update
+ // the link's state information.
+ //
+
+ DlcHeader = (PDLC_I_FRAME)&(Packet->Header[Link->HeaderLength]);
+ DlcHeader->SendSeq = (UCHAR)(Link->NextSend << 1);
+ Link->NextSend = (UCHAR)((Link->NextSend + 1) & 0x7f);
+ DlcHeader->RcvSeq = 0; // Link->NextReceive is inserted by NbfNdisSend
+
+ //
+ // Before we release the spinlock, we append the packet to the
+ // end of the link's WackQ, so that if an ACK arrives before the NdisSend
+ // completes, it will be on the queue already. Also, mark the packet as
+ // needing resend, which is canceled by AckLLCPackets, and used by
+ // ResendLLCPackets. Thus, all packets will need to be resent until they
+ // are acked.
+ //
+
+ ASSERT (Packet->PacketSent == FALSE);
+
+ InsertTailList (&Link->WackQ, &Packet->Linkage);
+ //SrvCheckListIntegrity( &Link->WackQ, 200 );
+
+
+ //
+ // If the send state is not READY, we can't ship.
+ // This failure is mostly caused by flow control or retransmit in progress,
+ // and is never cause for failure of the send.
+ //
+
+ if ((Link->SendState != SEND_STATE_READY) ||
+ (Link->LinkBusy) ||
+ (SendsOutstanding >= (ULONG)Link->SendWindowSize)) {
+
+ if ((Link->SendWindowSize == 1) || ForceAck) {
+ DlcHeader->RcvSeq |= DLC_I_PF; // set the poll bit.
+ if (Link->Provider->MacInfo.MediumAsync) {
+ Packet->Link = Link;
+ }
+ }
+
+ Packet->PacketSent = TRUE; // allows it to be resent.
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+#if DBG
+ if (Link->SendState != SEND_STATE_READY) {
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("SendOnePacket: Link send state not READY (%ld).\n", Link->SendState);
+ }
+ } else if (Link->LinkBusy) {
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ PANIC ("SendOnePacket: Link is busy.\n");
+ }
+ } else if (SendsOutstanding >= (ULONG)Link->SendWindowSize) {
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint3 ("SendOnePacket: No link send window; N(S)=%ld,LAR=%ld,SW=%ld.\n",
+ Link->NextSend, Link->LastAckReceived, Link->SendWindowSize);
+ }
+ }
+#endif
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Reference the packet since it is given to the NDIS driver.
+ //
+
+#if DBG
+ NbfReferencePacket (Packet);
+#else
+ ++Packet->ReferenceCount; // OK since it is not queued anywhere.
+#endif
+
+ //
+ // If this is the last I-frame in the window, then indicate that we
+ // should checkpoint. Also checkpoint if the sender is requesting
+ // acknowledgement (currently on SendSessionEnd does this).
+ // By default, this will also be a command frame.
+ //
+
+ if (((SendsOutstanding+1) >= (ULONG)Link->SendWindowSize) ||
+ ForceAck) {
+ Link->SendState = SEND_STATE_CHECKPOINTING;
+ StopTi (Link);
+ DlcHeader->RcvSeq |= DLC_I_PF; // set the poll bit.
+ Poll = TRUE;
+
+ }
+
+
+ //
+ // If we are polling, and the caller cares about it, then
+ // we set LinkCheckpoint, and also set up the connection to
+ // be waiting for resources. We do this now, before the send,
+ // so that even if the ack is receive right away, we will
+ // be in a good state. When we return LinkCheckpoint TRUE
+ // the caller realizes that he no longer owns the right
+ // to "packetize" and exits immediately.
+ //
+ // We also want to start our retransmission timer so, if this
+ // packet gets dropped, we will know to retransmit it. The
+ // exception is if LinkCheckpoint was specified, then we
+ // only StartT1 of we are not polling (the caller will
+ // ensure it is started if he exits before we poll).
+ //
+
+ if (ARGUMENT_PRESENT(LinkCheckpoint)) {
+
+ if (Poll) {
+
+ //
+ // If the connection still has send state PACKETIZE,
+ // then change it to W_LINK. If it is something else
+ // (such as W_PACKET or W_ACK) then don't worry, when
+ // that condition clears he will repacketize and the
+ // link conditions will be re-examined. In all
+ // case we turn off the PACKETIZE flag, because when
+ // we return with LinkCheckpoint TRUE he will stop
+ // packetizing, and to close the window we turn it
+ // off now (before the NdisSend) rather than then.
+ //
+
+ ASSERT (Connection->LinkSpinLock == &Link->SpinLock);
+ if (Connection->SendState == CONNECTION_SENDSTATE_PACKETIZE) {
+ Connection->SendState = CONNECTION_SENDSTATE_W_LINK;
+ }
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+
+ if (Link->Provider->MacInfo.MediumAsync) {
+ Packet->Link = Link;
+ NbfReferenceLink ("Send I-frame", Link, LREF_START_T1);
+ } else {
+ StartT1 (Link, Packet->NdisIFrameLength);
+ }
+ *LinkCheckpoint = TRUE;
+
+ } else {
+
+ StartT1 (Link, 0);
+ *LinkCheckpoint = FALSE;
+
+ }
+
+ } else {
+
+ //
+ // If LinkCheckpoint is not true, then we are sending
+ // an I-frame other than DFM/DOL. In this case, as
+ // an optimization, we'll set W_LINK if a) we are
+ // polling b) we are IDLE (to avoid messing up other
+ // states such as W_ACK). This will avoid a window
+ // where we don't go W_LINK until after the next
+ // send tries to packetize and fails.
+ //
+
+ if (Poll) {
+
+ ASSERT (Connection->LinkSpinLock == &Link->SpinLock);
+ if (Connection->SendState == CONNECTION_SENDSTATE_IDLE) {
+ Connection->SendState = CONNECTION_SENDSTATE_W_LINK;
+ }
+
+ }
+
+ //
+ // This is an optimization; we know that if LinkCheckpoint
+ // is present than we are being called from PacketizeSend;
+ // in this case the Link will have the LREF_CONNECTION
+ // reference and the connection will have the CREF_PACKETIZE
+ // reference, so we don't have to reference the link
+ // again.
+ //
+
+ NbfReferenceLink ("SendOnePacket", Link, LREF_NDIS_SEND);
+
+
+ //
+ // Start the retransmission timer.
+ //
+
+ if (Link->Provider->MacInfo.MediumAsync) {
+ if (Poll) {
+ Packet->Link = Link;
+ NbfReferenceLink ("ResendPacket", Link, LREF_START_T1);
+ } else {
+ StartT1 (Link, 0);
+ }
+ } else {
+ StartT1 (Link, Poll ? Packet->NdisIFrameLength : 0);
+ }
+
+ }
+
+ //
+ // Since this I-frame contains an N(R), it is potentially ACKing some
+ // previously received I-frames as reverse traffic. So we stop our
+ // delayed acknowlegement timer.
+ //
+
+ StopT2 (Link);
+
+ if ((Link->Provider->MacInfo.MediumAsync) &&
+ (ARGUMENT_PRESENT(LinkCheckpoint)) &&
+ (Link->SendWindowSize >= 3) &&
+ (!Poll) && (SendsOutstanding == (ULONG)(Link->SendWindowSize-2))) {
+
+ Status = STATUS_MORE_PROCESSING_REQUIRED;
+
+ Connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
+ NbfReferenceConnection ("PacketizeConnection TRUE", Connection, CREF_TEMP);
+ Packet->PacketizeConnection = TRUE;
+
+ } else {
+
+ Status = STATUS_SUCCESS;
+ }
+
+ //
+ // Send the packet; no locks held. Note that if the send fails, we will
+ // NOT fail upward; we allow things to continue onward. This lets us retry
+ // the send multiple times before we crap out; additionally, it keeps us
+ // from failing obscurely when sending control Iframes.
+ //
+ // NOTE: NbfNdisSend releases the link spinlock.
+ //
+
+ NbfNdisSend (Link, Packet);
+
+ Link->PacketsSent++;
+
+ //
+ // Remove the reference made above if needed.
+ //
+
+ if (!ARGUMENT_PRESENT(LinkCheckpoint)) {
+ NbfDereferenceLink ("SendOnePacket", Link, LREF_NDIS_SEND);
+ }
+
+ return Status;
+
+} /* SendOnePacket */
+
+
+VOID
+SendControlPacket(
+ IN PTP_LINK Link,
+ IN PTP_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a connection-oriented packet by calling the Physical
+ Provider's Send service. While SendOnePacket is used to send an I-
+ frame, this routine is used to send one of the following: RR, RNR, REJ,
+ SABME, UA, DISC, DM, FRMR, TEST, and XID.
+
+ NOTE: This function is called with the link spinlock held,
+ and returns with it released. IT MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a TP_LINK object.
+
+ Packet - Pointer to a TP_PACKET object.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ USHORT i;
+ PUCHAR p;
+ PNDIS_BUFFER ndisBuffer;
+
+ IF_NBFDBG (NBF_DEBUG_PACKET) {
+ NbfPrint3 ("SendControlPacket: Entered for link %lx, packet %lx, NdisPacket %lx\n 00:",
+ Link, Packet, Packet->NdisPacket);
+ IF_NBFDBG (NBF_DEBUG_PKTCONTENTS) {
+ UINT PLength, PCount;
+ UINT BLength;
+ PVOID BAddr;
+ p = Packet->Header;
+ for (i=0;i<20;i++) {
+ NbfPrint1 (" %2x",p[i]);
+ }
+ NbfPrint0 ("\n");
+ NdisQueryPacket(Packet->NdisPacket, &PCount, NULL, &ndisBuffer, &PLength);
+ NbfPrint3 ("Sending Control Packet: %lx, Length: %lx Pages: %lx\n",
+ Packet->NdisPacket, PLength, PCount);
+ while (ndisBuffer != NULL) {
+ NdisQueryBuffer (ndisBuffer, &BAddr, &BLength);
+ NbfPrint3 ("Sending Control Packet: Buffer %08lx Length %08lx Va %08lx\n",
+ ndisBuffer, BLength, BAddr);
+ NdisGetNextBuffer (ndisBuffer, &ndisBuffer);
+ }
+ }
+ }
+
+ ASSERT (Packet->PacketSent == FALSE);
+
+ NbfReferenceLink ("SendControlPacket", Link, LREF_NDIS_SEND);
+
+ //
+ // Send the packet (we have the lock, NbfNdisSend released
+ // it.
+ //
+
+ NbfNdisSend (Link, Packet);
+
+ NbfDereferenceLink ("SendControlPacket", Link, LREF_NDIS_SEND);
+
+} /* SendControlPacket */
+
+
+VOID
+NbfNdisSend(
+ IN PTP_LINK Link,
+ IN PTP_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to ensure that receive sequence numbers on
+ packets are numbered correctly. It is called in place of NdisSend
+ and after assigning the receive sequence number it locks out other
+ sends until the NdisSend call has returned (not necessarily completed),
+ insuring that the packets with increasing receive sequence numbers
+ are queue in the right order by the MAC.
+
+ NOTE: This routine is called with the link spinlock held,
+ and it returns with it released. THIS ROUTINE MUST BE CALLED
+ AT DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a TP_LINK object.
+
+ Packet - Pointer to a TP_PACKET object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ PLIST_ENTRY p;
+ PDLC_S_FRAME DlcHeader;
+ PNDIS_PACKET TmpNdisPacket;
+ ULONG result;
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ if (Link->Provider->UniProcessor) {
+
+ //
+ // On a uni-processor, we can send without fear of
+ // being interrupted by an incoming packet.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ DlcHeader = (PDLC_S_FRAME)&(Packet->Header[Link->HeaderLength]);
+
+ if ((DlcHeader->Command & DLC_U_INDICATOR) != DLC_U_INDICATOR) {
+
+ //
+ // It's not a U-frame, so we assign RcvSeq.
+ //
+
+ DlcHeader->RcvSeq |= (UCHAR)(Link->NextReceive << 1);
+
+ }
+
+#if DBG
+ NbfSendsIssued++;
+#endif
+
+ INCREMENT_COUNTER (Link->Provider, PacketsSent);
+
+ if (Link->Loopback) {
+
+ //
+ // This packet is sent to ourselves; we should loop it
+ // back.
+ //
+
+ NbfInsertInLoopbackQueue(
+ Link->Provider,
+ Packet->NdisPacket,
+ Link->LoopbackDestinationIndex
+ );
+
+ NdisStatus = NDIS_STATUS_PENDING;
+
+ } else {
+
+ NdisSend (
+ &NdisStatus,
+ Link->Provider->NdisBindingHandle,
+ Packet->NdisPacket);
+
+ }
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("NbfNdisSend: NdisSend completed Status: %s.\n",
+ NbfGetNdisStatus(NdisStatus));
+ }
+
+ switch (NdisStatus) {
+
+ case NDIS_STATUS_PENDING:
+#if DBG
+ NbfSendsPended++;
+#endif
+ break;
+
+ case NDIS_STATUS_SUCCESS:
+#if DBG
+ NbfSendsCompletedInline++;
+ NbfSendsCompletedOk++;
+#endif
+ NbfSendCompletionHandler (Link->Provider->NdisBindingHandle,
+ Packet->NdisPacket,
+ NDIS_STATUS_SUCCESS);
+ break;
+
+ default:
+#if DBG
+ NbfSendsCompletedInline++;
+ NbfSendsCompletedFail++;
+#endif
+ NbfSendCompletionHandler (Link->Provider->NdisBindingHandle,
+ Packet->NdisPacket,
+ NDIS_STATUS_SUCCESS);
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("NbfNdisSend failed, status not Pending or Complete: %lx.\n",
+ NbfGetNdisStatus (NdisStatus));
+ }
+ break;
+
+ }
+
+ } else {
+
+ //
+ // If there is a send in progress, then queue this packet
+ // and return.
+ //
+
+ if (Link->NdisSendsInProgress > 0) {
+
+ p = (PLIST_ENTRY)(Packet->NdisPacket->MacReserved);
+ InsertTailList (&Link->NdisSendQueue, p);
+ ++Link->NdisSendsInProgress;
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ return;
+
+ }
+
+ //
+ // No send in progress. Set the flag to true, and fill in the
+ // receive sequence field in the packet (note that the RcvSeq
+ // field is in the same place for I- and S-frames.
+ //
+
+ Link->NdisSendsInProgress = 1;
+
+ while (TRUE) {
+
+ DlcHeader = (PDLC_S_FRAME)&(Packet->Header[Link->HeaderLength]);
+
+ if ((DlcHeader->Command & DLC_U_INDICATOR) != DLC_U_INDICATOR) {
+
+ //
+ // It's not a U-frame, so we assign RcvSeq.
+ //
+
+ DlcHeader->RcvSeq |= (UCHAR)(Link->NextReceive << 1);
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+#if DBG
+ NbfSendsIssued++;
+#endif
+
+ INCREMENT_COUNTER (Link->Provider, PacketsSent);
+
+ if (Link->Loopback) {
+
+ //
+ // This packet is sent to ourselves; we should loop it
+ // back.
+ //
+
+ NbfInsertInLoopbackQueue(
+ Link->Provider,
+ Packet->NdisPacket,
+ Link->LoopbackDestinationIndex
+ );
+
+ NdisStatus = NDIS_STATUS_PENDING;
+
+ } else {
+
+ NdisSend (
+ &NdisStatus,
+ Link->Provider->NdisBindingHandle,
+ Packet->NdisPacket);
+
+ }
+
+ //
+ // Take the ref count down, which may allow others
+ // to come through.
+ //
+
+ result = ExInterlockedAddUlong(
+ &Link->NdisSendsInProgress,
+ (ULONG)-1,
+ &Link->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("NbfNdisSend: NdisSend completed Status: %s.\n",
+ NbfGetNdisStatus(NdisStatus));
+ }
+
+ switch (NdisStatus) {
+
+ case NDIS_STATUS_PENDING:
+#if DBG
+ NbfSendsPended++;
+#endif
+ break;
+
+ case NDIS_STATUS_SUCCESS:
+#if DBG
+ NbfSendsCompletedInline++;
+ NbfSendsCompletedOk++;
+#endif
+ NbfSendCompletionHandler (Link->Provider->NdisBindingHandle,
+ Packet->NdisPacket,
+ NDIS_STATUS_SUCCESS);
+ break;
+
+ default:
+#if DBG
+ NbfSendsCompletedInline++;
+ NbfSendsCompletedFail++;
+#endif
+ NbfSendCompletionHandler (Link->Provider->NdisBindingHandle,
+ Packet->NdisPacket,
+ NDIS_STATUS_SUCCESS);
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("NbfNdisSend failed, status not Pending or Complete: %lx.\n",
+ NbfGetNdisStatus (NdisStatus));
+ }
+ break;
+
+ }
+
+ //
+ // We have now sent a packet, see if any queued up while we
+ // were doing it. If the count was zero after removing ours,
+ // then anything else queued is being processed, so we can
+ // exit.
+ //
+
+ if (result == 1) {
+ return;
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ p = RemoveHeadList(&Link->NdisSendQueue);
+
+ //
+ // If the refcount was not zero, then nobody else should
+ // have taken packets off since they would have been
+ // blocked by us. So, the queue should not be empty.
+ //
+
+ ASSERT (p != &Link->NdisSendQueue);
+
+ //
+ // Get back the TP_PACKET by using the Frame pointer in the
+ // ProtocolReserved field of the NDIS_PACKET.
+ //
+
+ TmpNdisPacket = CONTAINING_RECORD (p, NDIS_PACKET, MacReserved[0]);
+ Packet = (PTP_PACKET)(((PSEND_PACKET_TAG)(&TmpNdisPacket->ProtocolReserved[0]))->Frame);
+
+ } // while loop
+
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ }
+
+} /* NbfNdisSend */
+
+
+VOID
+RestartLinkTraffic(
+ PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine continues the activities of the connections on a link.
+
+ NOTE: This function is called with the link spinlock held and
+ it returns with it released. THIS FUNCTION MUST BE CALLED AT
+ DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a TP_LINK object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PTP_CONNECTION connection;
+ PLIST_ENTRY p;
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("RestartLinkTraffic: Entered for link %lx.\n", Link);
+ }
+
+ //
+ // Link conditions may have cleared up. Make all connections on this
+ // link eligible for more packetization if they are in W_LINK state.
+ //
+
+ for (p = Link->ConnectionDatabase.Flink;
+ p != &Link->ConnectionDatabase;
+ p = p->Flink) {
+
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+
+ ASSERT (connection->LinkSpinLock == &Link->SpinLock);
+
+ //
+ // If we tried to send a plain-ole data frame DFM/DOL, but
+ // link conditions were not satisfactory, then we changed
+ // send state to W_LINK. Check for that now, and possibly
+ // start repacketizing.
+ //
+
+ if (connection->SendState == CONNECTION_SENDSTATE_W_LINK) {
+ if (!(IsListEmpty (&connection->SendQueue))) {
+
+ connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
+
+ //
+ // This is similar to calling StartPacketizingConnection
+ // with the Immediate set to FALSE.
+ //
+
+ if (!(connection->Flags & CONNECTION_FLAGS_PACKETIZE) &&
+ (connection->Flags & CONNECTION_FLAGS_READY)) {
+
+ ASSERT (!(connection->Flags2 & CONNECTION_FLAGS2_STOPPING));
+ connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
+
+ NbfReferenceConnection ("Packetize", connection, CREF_PACKETIZE_QUEUE);
+
+ ExInterlockedInsertTailList(
+ &connection->Provider->PacketizeQueue,
+ &connection->PacketizeLinkage,
+ &connection->Provider->SpinLock);
+
+ }
+
+ } else {
+ connection->SendState = CONNECTION_SENDSTATE_IDLE;
+ }
+ }
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+} /* RestartLinkTraffic */
+
+
+VOID
+NbfProcessWanDelayedQueue(
+ IN PVOID Parameter
+ )
+
+/*++
+
+Routine Description:
+
+ This is the thread routine which restarts packetizing
+ that has been delayed on WAN to allow RRs to come in.
+ This is very similar to PacketizeConnections.
+
+Arguments:
+
+ Parameter - A pointer to the device context.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ PLIST_ENTRY p;
+ PTP_CONNECTION Connection;
+ KIRQL oldirql;
+
+ DeviceContext = (PDEVICE_CONTEXT)Parameter;
+
+ //
+ // Packetize all waiting connections
+ //
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+ ASSERT (DeviceContext->WanThreadQueued);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ while (!IsListEmpty(&DeviceContext->PacketizeQueue)) {
+
+ p = RemoveHeadList(&DeviceContext->PacketizeQueue);
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, PacketizeLinkage);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ if (Connection->SendState != CONNECTION_SENDSTATE_PACKETIZE) {
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ NbfDereferenceConnection ("No longer packetizing", Connection, CREF_PACKETIZE_QUEUE);
+ } else {
+ NbfReferenceSendIrp ("Packetize", IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp), RREF_PACKET);
+ PacketizeSend (Connection, FALSE); // releases the lock.
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ }
+
+ DeviceContext->WanThreadQueued = FALSE;
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ KeLowerIrql (oldirql);
+
+} /* NbfProcessWanDelayedQueue */
+
+
+NTSTATUS
+BuildBufferChainFromMdlChain (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PMDL CurrentMdl,
+ IN ULONG ByteOffset,
+ IN ULONG DesiredLength,
+ OUT PNDIS_BUFFER *Destination,
+ OUT PMDL *NewCurrentMdl,
+ OUT ULONG *NewByteOffset,
+ OUT ULONG *TrueLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to build an NDIS_BUFFER chain from a source Mdl chain and
+ offset into it. We assume we don't know the length of the source Mdl chain,
+ and we must allocate the NDIS_BUFFERs for the destination chain, which
+ we do from the NDIS buffer pool.
+
+ The NDIS_BUFFERs that are returned are mapped and locked. (Actually, the pages in
+ them are in the same state as those in the source MDLs.)
+
+ If the system runs out of memory while we are building the destination
+ NDIS_BUFFER chain, we completely clean up the built chain and return with
+ NewCurrentMdl and NewByteOffset set to the current values of CurrentMdl
+ and ByteOffset. TrueLength is set to 0.
+
+Environment:
+
+ Kernel Mode, Source Mdls locked. It is recommended, although not required,
+ that the source Mdls be mapped and locked prior to calling this routine.
+
+Arguments:
+
+ BufferPoolHandle - The buffer pool to allocate buffers from.
+
+ CurrentMdl - Points to the start of the Mdl chain from which to draw the
+ packet.
+
+ ByteOffset - Offset within this MDL to start the packet at.
+
+ DesiredLength - The number of bytes to insert into the packet.
+
+ Destination - returned pointer to the NDIS_BUFFER chain describing the packet.
+
+ NewCurrentMdl - returned pointer to the Mdl that would be used for the next
+ byte of packet. NULL if the source Mdl chain was exhausted.
+
+ NewByteOffset - returned offset into the NewCurrentMdl for the next byte of
+ packet. NULL if the source Mdl chain was exhausted.
+
+ TrueLength - The actual length of the returned NDIS_BUFFER Chain. If less than
+ DesiredLength, the source Mdl chain was exhausted.
+
+Return Value:
+
+ STATUS_SUCCESS if the build of the returned NDIS_BUFFER chain succeeded (even if
+ shorter than the desired chain).
+
+ STATUS_INSUFFICIENT_RESOURCES if we ran out of NDIS_BUFFERs while building the
+ destination chain.
+
+--*/
+{
+ ULONG AvailableBytes;
+ PMDL OldMdl;
+ PNDIS_BUFFER NewNdisBuffer;
+ NDIS_STATUS NdisStatus;
+
+ //
+
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint3 ("BuildBufferChain: Mdl: %lx Offset: %ld Length: %ld\n",
+ CurrentMdl, ByteOffset, DesiredLength);
+ }
+
+ AvailableBytes = MmGetMdlByteCount (CurrentMdl) - ByteOffset;
+ if (AvailableBytes > DesiredLength) {
+ AvailableBytes = DesiredLength;
+ }
+
+ OldMdl = CurrentMdl;
+ *NewCurrentMdl = OldMdl;
+ *NewByteOffset = ByteOffset + AvailableBytes;
+ *TrueLength = AvailableBytes;
+
+
+ //
+ // Build the first NDIS_BUFFER, which could conceivably be the only one...
+ //
+
+ NdisCopyBuffer(
+ &NdisStatus,
+ &NewNdisBuffer,
+ DeviceContext->NdisBufferPool,
+ OldMdl,
+ ByteOffset,
+ AvailableBytes);
+
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ *NewByteOffset = ByteOffset;
+ *TrueLength = 0;
+ *Destination = NULL;
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ *Destination = NewNdisBuffer;
+
+
+// IF_NBFDBG (NBF_DEBUG_SENDENG) {
+// PVOID PAddr, UINT PLen;
+// NdisQueryBuffer (NewNdisBuffer, &PAddr, &PLen);
+// NbfPrint4 ("BuildBufferChain: (start)Built Mdl: %lx Length: %lx, Next: %lx Va: %lx\n",
+// NewNdisBuffer, PLen, NDIS_BUFFER_LINKAGE(NewNdisBuffer), PAddr);
+// }
+
+ //
+ // Was the first NDIS_BUFFER enough data, or are we out of Mdls?
+ //
+
+ if ((AvailableBytes == DesiredLength) || (OldMdl->Next == NULL)) {
+ if (*NewByteOffset >= MmGetMdlByteCount (OldMdl)) {
+ *NewCurrentMdl = OldMdl->Next;
+ *NewByteOffset = 0;
+ }
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Need more data, so follow the in Mdl chain to create a packet.
+ //
+
+ OldMdl = OldMdl->Next;
+ *NewCurrentMdl = OldMdl;
+
+ while (OldMdl != NULL) {
+ AvailableBytes = DesiredLength - *TrueLength;
+ if (AvailableBytes > MmGetMdlByteCount (OldMdl)) {
+ AvailableBytes = MmGetMdlByteCount (OldMdl);
+ }
+
+ NdisCopyBuffer(
+ &NdisStatus,
+ &(NDIS_BUFFER_LINKAGE(NewNdisBuffer)),
+ DeviceContext->NdisBufferPool,
+ OldMdl,
+ 0,
+ AvailableBytes);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // ran out of resources. put back what we've used in this call and
+ // return the error.
+ //
+
+ while (*Destination != NULL) {
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE(*Destination);
+ NdisFreeBuffer (*Destination);
+ *Destination = NewNdisBuffer;
+ }
+
+ *NewByteOffset = ByteOffset;
+ *TrueLength = 0;
+ *NewCurrentMdl = CurrentMdl;
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE(NewNdisBuffer);
+
+ *TrueLength += AvailableBytes;
+ *NewByteOffset = AvailableBytes;
+
+// IF_NBFDBG (NBF_DEBUG_SENDENG) {
+// PVOID PAddr, UINT PLen;
+// NdisQueryBuffer (NewNdisBuffer, &PAddr, &PLen);
+// NbfPrint4 ("BuildBufferChain: (continue) Built Mdl: %lx Length: %lx, Next: %lx Va: %lx\n",
+// NewNdisBuffer, PLen, NDIS_BUFFER_LINKAGE(NewNdisBuffer), PAddr);
+// }
+
+ if (*TrueLength == DesiredLength) {
+ if (*NewByteOffset == MmGetMdlByteCount (OldMdl)) {
+ *NewCurrentMdl = OldMdl->Next;
+ *NewByteOffset = 0;
+ }
+ return STATUS_SUCCESS;
+ }
+ OldMdl = OldMdl->Next;
+ *NewCurrentMdl = OldMdl;
+
+ } // while (mdl chain exists)
+
+ *NewCurrentMdl = NULL;
+ *NewByteOffset = 0;
+ return STATUS_SUCCESS;
+
+} // BuildBufferChainFromMdlChain
+
diff --git a/private/ntos/tdi/nbf/sources b/private/ntos/tdi/nbf/sources
new file mode 100644
index 000000000..6d6ab7f87
--- /dev/null
+++ b/private/ntos/tdi/nbf/sources
@@ -0,0 +1,79 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=nbf
+
+TARGETNAME=nbf
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\tdi.lib \
+ $(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..\..\inc;..\..\..\inc
+
+#C_DEFINES = -DRASAUTODIAL
+C_DEFINES = -DRASAUTODIAL -D_PNP_POWER
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=action.c \
+ address.c \
+ autodial.c \
+ connect.c \
+ connobj.c \
+ devctx.c \
+ dlc.c \
+ event.c \
+ framecon.c \
+ framesnd.c \
+ iframes.c \
+ info.c \
+ link.c \
+ linktree.c \
+ nbf.rc \
+ nbfcnfg.c \
+ nbfdrvr.c \
+ nbfdebug.c \
+ nbfmac.c \
+ nbfndis.c \
+ nbfpnp.c \
+ packet.c \
+ rcv.c \
+ rcveng.c \
+ request.c \
+ send.c \
+ sendeng.c \
+ spnlckdb.c \
+ timer.c \
+ uframes.c
+
+!IFNDEF 386_WARNING_LEVEL
+386_WARNING_LEVEL=/W3
+!ENDIF
+
+PRECOMPILED_INCLUDE=precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
diff --git a/private/ntos/tdi/nbf/spnlckdb.c b/private/ntos/tdi/nbf/spnlckdb.c
new file mode 100644
index 000000000..485431ad5
--- /dev/null
+++ b/private/ntos/tdi/nbf/spnlckdb.c
@@ -0,0 +1,156 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ spnlckdb.c
+
+Abstract:
+
+ This module contains code which allows debugging of spinlock related NBF
+ problems. Most of this code is conditional on the manifest constant
+ NBF_LOCKS.
+
+Author:
+
+ David Beaver 13-Feb-1991
+ (From Chuck Lenzmeier, Jan 1991)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef NBF_LOCKS
+
+KSPIN_LOCK NbfGlobalLock = NULL;
+PKTHREAD NbfGlobalLockOwner = NULL;
+ULONG NbfGlobalLockRecursionCount = 0;
+ULONG NbfGlobalLockMaxRecursionCount = 0;
+KIRQL NbfGlobalLockPreviousIrql = (KIRQL)-1;
+BOOLEAN NbfGlobalLockPrint = 1;
+
+#define PRINT_ERR if ( (NbfGlobalLockPrint & 1) != 0 ) DbgPrint
+#define PRINT_INFO if ( (NbfGlobalLockPrint & 2) != 0 ) DbgPrint
+
+VOID
+NbfAcquireSpinLock(
+ IN PKSPIN_LOCK Lock,
+ OUT PKIRQL OldIrql,
+ IN PSZ LockName,
+ IN PSZ FileName,
+ IN ULONG LineNumber
+ )
+{
+ KIRQL previousIrql;
+
+ PKTHREAD currentThread = KeGetCurrentThread( );
+
+ if ( NbfGlobalLockOwner == currentThread ) {
+
+ ASSERT( Lock != NULL ); // else entering NBF with lock held
+
+ ASSERT( NbfGlobalLockRecursionCount != 0 );
+ NbfGlobalLockRecursionCount++;
+ if ( NbfGlobalLockRecursionCount > NbfGlobalLockMaxRecursionCount ) {
+ NbfGlobalLockMaxRecursionCount = NbfGlobalLockRecursionCount;
+ }
+
+ PRINT_INFO( "NBF reentered from %s/%ld, new count %ld\n",
+ FileName, LineNumber, NbfGlobalLockRecursionCount );
+
+ } else {
+
+ ASSERT( Lock == NULL ); // else missing an ENTER_NBF call
+
+ KeAcquireSpinLock( &NbfGlobalLock, &previousIrql );
+
+ ASSERT( NbfGlobalLockRecursionCount == 0 );
+ NbfGlobalLockOwner = currentThread;
+ NbfGlobalLockPreviousIrql = previousIrql;
+ NbfGlobalLockRecursionCount = 1;
+
+ PRINT_INFO( "NBF entered from %s/%ld\n", FileName, LineNumber );
+
+ }
+
+ ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
+
+ return;
+
+} // NbfAcquireSpinLock
+
+VOID
+NbfReleaseSpinLock(
+ IN PKSPIN_LOCK Lock,
+ IN KIRQL OldIrql,
+ IN PSZ LockName,
+ IN PSZ FileName,
+ IN ULONG LineNumber
+ )
+{
+ PKTHREAD currentThread = KeGetCurrentThread( );
+ KIRQL previousIrql;
+
+ ASSERT( NbfGlobalLockOwner == currentThread );
+ ASSERT( NbfGlobalLockRecursionCount != 0 );
+ ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
+
+ if ( --NbfGlobalLockRecursionCount == 0 ) {
+
+ ASSERT( Lock == NULL ); // else not exiting NBF, but releasing lock
+
+ NbfGlobalLockOwner = NULL;
+ previousIrql = NbfGlobalLockPreviousIrql;
+ NbfGlobalLockPreviousIrql = (KIRQL)-1;
+
+ PRINT_INFO( "NBF exited from %s/%ld\n", FileName, LineNumber );
+
+ KeReleaseSpinLock( &NbfGlobalLock, previousIrql );
+
+ } else {
+
+ ASSERT( Lock != NULL ); // else exiting NBF with lock held
+
+ PRINT_INFO( "NBF semiexited from %s/%ld, new count %ld\n",
+ FileName, LineNumber, NbfGlobalLockRecursionCount );
+
+ }
+
+ return;
+
+} // NbfReleaseSpinLock
+
+VOID
+NbfFakeSendCompletionHandler(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ )
+{
+ ENTER_NBF;
+ NbfSendCompletionHandler (ProtocolBindingContext, NdisPacket, NdisStatus);
+ LEAVE_NBF;
+}
+
+VOID
+NbfFakeTransferDataComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus,
+ IN UINT BytesTransferred
+ )
+{
+ ENTER_NBF;
+ NbfTransferDataComplete (BindingContext, NdisPacket, NdisStatus, BytesTransferred);
+ LEAVE_NBF;
+}
+
+#endif // def NBF_LOCKS
diff --git a/private/ntos/tdi/nbf/testnbf.c b/private/ntos/tdi/nbf/testnbf.c
new file mode 100644
index 000000000..91a3ca645
--- /dev/null
+++ b/private/ntos/tdi/nbf/testnbf.c
@@ -0,0 +1,1466 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ testtdi.c
+
+Abstract:
+
+ Kernel Mode test program for any Tdi network provider. This routine is an
+ example of how to use the TDI interface at the kernel level.
+
+Author:
+
+ Dave Beaver (DBeaver) 5 June 1991
+
+Revision History:
+
+--*/
+
+#include "nbf.h"
+#include <ctype.h>
+
+#define TRANSPORT_NAME L"\\Device\\Nbf"
+
+PSZ ServerName = "DCTDISERVER ";
+PSZ ClientName = "DCTDICLIENT ";
+PSZ AnyName = "* ";
+
+static PUCHAR TextBuffer; // dynamically allocated non-paged buffer.
+ULONG c9_Xmt = 0xff;
+ULONG c9_Rcv = 0xff;
+ULONG c9_Iteration = 0xffffffff;
+
+static ULONG TextBufferLength; // size of the above in bytes.
+#define BUFFER_SIZE 0xffff
+PUCHAR RBuff;
+PUCHAR XBuff;
+UCHAR c9_ListBlock[512];
+UCHAR c9_ConnBlock[512];
+
+extern KEVENT TdiSendEvent;
+extern KEVENT TdiReceiveEvent;
+extern KEVENT TdiServerEvent;
+
+ULONG ApcContext;
+
+NTSTATUS
+TSTRCVCompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ DbgPrint ("TSTRCVCompletion event: %lx\n" , Context);
+// KeSetEvent ((PKEVENT)Context, 0, TRUE);
+ return STATUS_MORE_PROCESSING_REQUIRED;
+ UNREFERENCED_PARAMETER( DeviceObject );
+ UNREFERENCED_PARAMETER( Irp );
+}
+
+#define InitWaitObject(_event)\
+ KeInitializeEvent (\
+ _event,\
+ SynchronizationEvent,\
+ FALSE)
+
+VOID
+NbfTestTimer(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+NTSTATUS
+TtdiOpenAddress (
+ IN PHANDLE FileHandle,
+ IN PSZ Name
+ );
+
+NTSTATUS
+TtdiOpenConnection (
+ IN PHANDLE FileHandle,
+ IN ULONG ConnectionContext
+ );
+
+
+NTSTATUS
+TtdiOpenAddress (
+ IN PHANDLE FileHandle,
+ IN PSZ Name)
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ NTSTATUS Status;
+ UNICODE_STRING NameString;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PFILE_FULL_EA_INFORMATION EaBuffer;
+ PTDI_ADDRESS_NETBIOS AddressName;
+ PTRANSPORT_ADDRESS Address;
+ PTA_ADDRESS AddressType;
+ int i;
+
+ DbgPrint ("TtdiOpenAddress: Opening ");
+ DbgPrint (Name);
+ DbgPrint (".\n");
+ RtlInitUnicodeString (&NameString, TRANSPORT_NAME);
+ InitializeObjectAttributes (
+ &ObjectAttributes,
+ &NameString,
+ 0,
+ NULL,
+ NULL);
+
+ EaBuffer = (PFILE_FULL_EA_INFORMATION)ExAllocatePool (NonPagedPool, 100);
+ if (EaBuffer == NULL) {
+ DbgBreakPoint ();
+ }
+
+ EaBuffer->NextEntryOffset =0;
+ EaBuffer->Flags = 0;
+ EaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
+ EaBuffer->EaValueLength = sizeof (TDI_ADDRESS_NETBIOS);
+
+ for (i=0;i<(int)EaBuffer->EaNameLength;i++) {
+ EaBuffer->EaName[i] = TdiTransportAddress[i];
+ }
+
+ Address = (PTRANSPORT_ADDRESS)&EaBuffer->EaName[EaBuffer->EaNameLength+1];
+ Address->TAAddressCount = 1;
+
+ AddressType = (PTA_ADDRESS)((PUCHAR)Address + sizeof (Address->TAAddressCount));
+
+ AddressType->AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ AddressType->AddressLength = TDI_ADDRESS_LENGTH_NETBIOS;
+
+ AddressName = (PTDI_ADDRESS_NETBIOS)((PUCHAR)AddressType +
+ sizeof (AddressType->AddressType) + sizeof (AddressType->AddressLength));
+ AddressName->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ AddressName->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+
+ for (i=0;i<16;i++) {
+ AddressName->NetbiosName[i] = Name[i];
+ }
+
+ Status = IoCreateFile (
+ FileHandle,
+ 0, // desired access.
+ &ObjectAttributes, // object attributes.
+ &IoStatusBlock, // returned status information.
+ 0, // block size (unused).
+ FO_SYNCHRONOUS_IO, // file attributes.
+ 0,
+ 0,
+ 0, // create options.
+ EaBuffer, // EA buffer.
+ (PUCHAR)&AddressName->NetbiosName[i] - (PUCHAR)EaBuffer + 1, // ea length
+ CreateFileTypeNone,
+ (PVOID)NULL,
+ 0 ); // EA length.
+
+ if (!NT_SUCCESS( Status )) {
+ DbgPrint ("TtdiOpenAddress: FAILURE, NtCreateFile returned status code=%lC.\n", Status);
+ return Status;
+ }
+
+ Status = IoStatusBlock.Status;
+
+ if (!(NT_SUCCESS( Status ))) {
+ DbgPrint ("TtdiOpenAddress: FAILURE, IoStatusBlock.Status contains status code=%lC.\n", Status);
+ }
+
+ DbgPrint ("TtdiOpenAddress: returning\n");
+
+ return Status;
+} /* TtdiOpenAddress */
+
+
+NTSTATUS
+TtdiOpenConnection (IN PHANDLE FileHandle, IN ULONG ConnectionContext)
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ NTSTATUS Status;
+ UNICODE_STRING NameString;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PFILE_FULL_EA_INFORMATION EaBuffer;
+ int i;
+
+ DbgPrint ("TtdiOpenConnection: Opening Context %lx...\n ",
+ ConnectionContext);
+ RtlInitUnicodeString (&NameString, TRANSPORT_NAME);
+ InitializeObjectAttributes (
+ &ObjectAttributes,
+ &NameString,
+ 0,
+ NULL,
+ NULL);
+
+ EaBuffer = (PFILE_FULL_EA_INFORMATION)ExAllocatePool (NonPagedPool, 100);
+ if (EaBuffer == NULL) {
+ DbgBreakPoint ();
+ }
+
+ EaBuffer->NextEntryOffset =0;
+ EaBuffer->Flags = 0;
+ EaBuffer->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
+ EaBuffer->EaValueLength = sizeof (ULONG);
+ for (i=0;i<(int)EaBuffer->EaNameLength;i++) {
+ EaBuffer->EaName[i] = TdiConnectionContext[i];
+ }
+
+ RtlMoveMemory (
+ &EaBuffer->EaName[EaBuffer->EaValueLength + 1],
+ &ConnectionContext,
+ sizeof (PVOID));
+
+ Status = NtCreateFile (
+ FileHandle,
+ 0,
+ &ObjectAttributes, // object attributes.
+ &IoStatusBlock, // returned status information.
+ 0, // block size (unused).
+ FO_SYNCHRONOUS_IO, // file attributes.
+ 0,
+ 0,
+ 0, // create options.
+ EaBuffer, // EA buffer.
+ 100); // EA length.
+
+ if (!NT_SUCCESS( Status )) {
+ DbgPrint ("TtdiOpenConnection: FAILURE, NtCreateFile returned status code=%lC.\n", Status);
+ return Status;
+ }
+
+ Status = IoStatusBlock.Status;
+
+ if (!(NT_SUCCESS( Status ))) {
+ DbgPrint ("TtdiOpenConnection: FAILURE, IoStatusBlock.Status contains status code=%lC.\n", Status);
+ }
+
+ DbgPrint ("TtdiOpenConnection: returning\n");
+
+ return Status;
+} /* TtdiOpenEndpoint */
+
+NTSTATUS
+CloseAddress (IN HANDLE FileHandle)
+{
+ NTSTATUS Status;
+
+ Status = NtClose (FileHandle);
+
+ if (!(NT_SUCCESS( Status ))) {
+ DbgPrint ("CloseAddress: FAILURE, NtClose returned status code=%lC.\n", Status);
+ } else {
+ DbgPrint ("CloseAddress: NT_SUCCESS.\n");
+ }
+
+ return Status;
+} /* CloseAddress */
+
+
+BOOLEAN
+TtdiSend()
+{
+ USHORT i, Iteration, Increment;
+ HANDLE RdrHandle, RdrConnectionHandle;
+ KEVENT Event1;
+ PFILE_OBJECT AddressObject, ConnectionObject;
+ PDEVICE_OBJECT DeviceObject;
+ NTSTATUS Status;
+ PMDL SendMdl, ReceiveMdl;
+ IO_STATUS_BLOCK Iosb1;
+ TDI_CONNECTION_INFORMATION RequestInformation;
+ TDI_CONNECTION_INFORMATION ReturnInformation;
+ PTRANSPORT_ADDRESS ListenBlock;
+ PTRANSPORT_ADDRESS ConnectBlock;
+ PTDI_ADDRESS_NETBIOS temp;
+ PUCHAR MessageBuffer;
+ ULONG MessageBufferLength;
+ ULONG CurrentBufferLength;
+ PUCHAR SendBuffer;
+ ULONG SendBufferLength;
+ PIRP Irp;
+
+ Status = KeWaitForSingleObject (&TdiSendEvent, Suspended, KernelMode, FALSE, NULL);
+
+ SendBufferLength = (ULONG)BUFFER_SIZE;
+ MessageBufferLength = (ULONG)BUFFER_SIZE;
+
+
+ DbgPrint( "\n****** Start of Send Test ******\n" );
+
+ XBuff = ExAllocatePool (NonPagedPool, BUFFER_SIZE);
+ if (XBuff == (PVOID)NULL) {
+ DbgPrint ("Unable to allocate nonpaged pool for send buffer exiting\n");
+ return FALSE;
+ }
+ RBuff = ExAllocatePool (NonPagedPool, BUFFER_SIZE);
+ if (RBuff == (PVOID)NULL) {
+ DbgPrint ("Unable to allocate nonpaged pool for receive buffer exiting\n");
+ return FALSE;
+ }
+
+ ListenBlock = ExAllocatePool (NonPagedPool, sizeof (TRANSPORT_ADDRESS) +
+ sizeof (TDI_ADDRESS_NETBIOS));
+ ConnectBlock = ExAllocatePool (NonPagedPool, sizeof (TRANSPORT_ADDRESS) +
+ sizeof (TDI_ADDRESS_NETBIOS));
+
+ ListenBlock->TAAddressCount = 1;
+ ListenBlock->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ ListenBlock->Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
+ temp = (PTDI_ADDRESS_NETBIOS)ListenBlock->Address[0].Address;
+
+ temp->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ for (i=0;i<16;i++) {
+ temp->NetbiosName[i] = ClientName[i];
+ }
+
+ ConnectBlock->TAAddressCount = 1;
+ ConnectBlock->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ ConnectBlock->Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
+ temp = (PTDI_ADDRESS_NETBIOS)ConnectBlock->Address[0].Address;
+
+ temp->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ for (i=0;i<16;i++) {
+ temp->NetbiosName[i] = ServerName[i];
+ }
+
+ //
+ // Create an event for the synchronous I/O requests that we'll be issuing.
+ //
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Status = TtdiOpenAddress (&RdrHandle, AnyName);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Send Test: FAILED on open of client: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ Status = ObReferenceObjectByHandle (
+ RdrHandle,
+ 0L,
+ NULL,
+ KernelMode,
+ (PVOID *) &AddressObject,
+ NULL);
+
+ //
+ // Open the connection on the transport.
+ //
+
+ Status = TtdiOpenConnection (&RdrConnectionHandle, 1);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Send Test: FAILED on open of server Connection: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ Status = ObReferenceObjectByHandle (
+ RdrConnectionHandle,
+ 0L,
+ NULL,
+ KernelMode,
+ (PVOID *) &ConnectionObject,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Send Test: FAILED on open of server Connection: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ //
+ // Get a pointer to the stack location for the first driver. This will be
+ // used to pass the original function codes and parameters.
+ //
+
+ DeviceObject = IoGetRelatedDeviceObject( ConnectionObject );
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_ASSOCIATE_ADDRESS,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+
+ //
+ // Get a pointer to the stack location for the first driver. This will be
+ // used to pass the original function codes and parameters.
+ //
+
+ TdiBuildAssociateAddress (Irp,
+ DeviceObject,
+ ConnectionObject,
+ TSTRCVCompletion,
+ &Event1,
+ RdrHandle);
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+// IoFreeIrp (Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Send Test: FAILED Event1 Wait Associate: %lC ******\n", Status );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Send Test: FAILED Associate Iosb status: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+ DbgPrint( "\n****** Send Test: AssociateAddress FAILED Status: %lC ******\n", Status );
+ return FALSE;
+ } else {
+ DbgPrint ("********** Send Test: Success AssociateAddress\n");
+ }
+ }
+
+ //
+ // Post a TdiConnect to the client endpoint.
+ //
+
+ RequestInformation.RemoteAddress = ConnectBlock;
+ RequestInformation.RemoteAddressLength = sizeof (TRANSPORT_ADDRESS) +
+ sizeof (TDI_ADDRESS_NETBIOS);
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_CONNECT,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+ TdiBuildConnect (
+ Irp,
+ DeviceObject,
+ ConnectionObject,
+ TSTRCVCompletion,
+ &Event1,
+ 0,
+ &RequestInformation,
+ &ReturnInformation);
+
+ InitWaitObject (&Event1);
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+// IoFreeIrp (Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Send Test: FAILED Event1 Wait Connect: %lC ******\n", Status );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Send Test: FAILED Iosb status Connect: %lC ******\n", Status );
+ return FALSE;
+ } else {
+ DbgPrint ("********** Send Test: Success Connect Iosb\n");
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+ DbgPrint( "\n****** Send Test: Connect FAILED Status: %lC ******\n", Status );
+ return FALSE;
+ } else {
+ DbgPrint ("********** Send Test: Success Connect Immediate\n");
+ }
+ }
+
+ DbgPrint( "\n****** Send Test: SUCCESSFUL TdiConnect: ******\n");
+
+ //
+ // Send/receive 1 or 10 messages.
+ //
+
+ SendBuffer = (PUCHAR)ExAllocatePool (NonPagedPool, SendBufferLength);
+ if (SendBuffer == NULL) {
+ DbgPrint ("\n****** Send Test: ExAllocatePool failed! ******\n");
+ }
+ SendMdl = IoAllocateMdl (SendBuffer, SendBufferLength, FALSE, FALSE, NULL);
+ MmBuildMdlForNonPagedPool (SendMdl);
+
+ MessageBuffer=(PUCHAR)ExAllocatePool (NonPagedPool, MessageBufferLength);
+ if (MessageBuffer == NULL) {
+ DbgPrint ("\n****** Send Test: ExAllocatePool failed! ******\n");
+ }
+ ReceiveMdl = IoAllocateMdl (MessageBuffer, MessageBufferLength, FALSE, FALSE, NULL);
+ MmBuildMdlForNonPagedPool (ReceiveMdl);
+
+ //
+ // Cycle the buffer length from 0 up through the maximum for Tdi. after a
+ // couple of shots at the full range in one byte steps, increment by ever
+ // increasing amounts to get to the max.
+ //
+
+ CurrentBufferLength = 0;
+ Increment = 1;
+ for (Iteration=1; Iteration<(USHORT)c9_Iteration; Iteration++) {
+ CurrentBufferLength += Increment;
+ if (CurrentBufferLength > MessageBufferLength) {
+ CurrentBufferLength = 0;
+ Increment = 1;
+ }
+ if (CurrentBufferLength > 7500) {
+ Increment++;
+ }
+ if ((USHORT)((Iteration / 100) * 100) == Iteration) {
+ DbgPrint ("Iteration #%d Buffer Length: %lx Buffer Start: %x\n",
+ Iteration, CurrentBufferLength,Iteration % 256);
+ }
+ for (i=0; i<(USHORT)CurrentBufferLength; i++) {
+ SendBuffer [i] = (UCHAR)(i + Iteration % 256 );
+ MessageBuffer [i] = 0; // zap this sucker with something.
+ }
+
+ //
+ // Now issue a send on the client side.
+ //
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_SEND,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+ TdiBuildSend (Irp,
+ DeviceObject,
+ ConnectionObject,
+ TSTRCVCompletion,
+ &Event1,
+ ReceiveMdl,
+ 0,
+ CurrentBufferLength);
+
+ InitWaitObject (&Event1);
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+// IoFreeIrp (Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Send Test: FAILED Event1 Wait Send: %lC %d ******\n",
+ Status, Iteration );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Send Test: FAILED Iosb status Send: %lC %d ******\n",
+ Status, Iteration );
+ return FALSE;
+ } else {
+ DbgPrint ("********** Send Test: Success SendIosb\n");
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+ DbgPrint( "\n****** Send Test: Send FAILED Status: %lC %d ******\n",
+ Status, Iteration );
+ return FALSE;
+ } else {
+ DbgPrint ("********** Send Test: Success Send Immediate\n");
+ }
+ }
+
+ if (Iosb1.Information != CurrentBufferLength) {
+ DbgPrint ("SendTest: Bytes sent <> Send buffer size.\n");
+ DbgPrint ("SendTest: BytesToSend=%ld. BytesSent=%ld.\n",
+ CurrentBufferLength, Iosb1.Information);
+ }
+
+ }
+
+ //
+ // We're done with this endpoint. Close it and get out.
+ //
+
+ Status = CloseAddress (RdrHandle);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Send Test: FAILED on 2nd Close: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ DbgPrint( "\n****** End of Send Test ******\n" );
+ return TRUE;
+} /* Send */
+
+
+BOOLEAN
+TtdiReceive()
+{
+ USHORT i, Iteration, Increment;
+ SHORT j,k;
+ HANDLE SvrHandle, SvrConnectionHandle;
+ PFILE_OBJECT AddressObject, ConnectionObject;
+ PDEVICE_OBJECT DeviceObject;
+ NTSTATUS Status;
+ PMDL SendMdl, ReceiveMdl;
+ IO_STATUS_BLOCK Iosb1;
+ TDI_CONNECTION_INFORMATION RequestInformation;
+ TDI_CONNECTION_INFORMATION ReturnInformation;
+ PTRANSPORT_ADDRESS ListenBlock;
+ PTRANSPORT_ADDRESS ConnectBlock;
+ PTDI_ADDRESS_NETBIOS temp;
+ PUCHAR MessageBuffer;
+ ULONG MessageBufferLength;
+ ULONG CurrentBufferLength;
+ PUCHAR SendBuffer;
+ ULONG SendBufferLength;
+ PIRP Irp;
+ KEVENT Event1;
+
+ Status = KeWaitForSingleObject (&TdiReceiveEvent, Suspended, KernelMode, FALSE, NULL);
+
+ SendBufferLength = (ULONG)BUFFER_SIZE;
+ MessageBufferLength = (ULONG)BUFFER_SIZE;
+
+
+ DbgPrint( "\n****** Start of Receive Test ******\n" );
+
+ XBuff = ExAllocatePool (NonPagedPool, BUFFER_SIZE);
+ if (XBuff == (PVOID)NULL) {
+ DbgPrint ("Unable to allocate nonpaged pool for send buffer exiting\n");
+ return FALSE;
+ }
+ RBuff = ExAllocatePool (NonPagedPool, BUFFER_SIZE);
+ if (RBuff == (PVOID)NULL) {
+ DbgPrint ("Unable to allocate nonpaged pool for receive buffer exiting\n");
+ return FALSE;
+ }
+
+ ListenBlock = ExAllocatePool (NonPagedPool, sizeof (TRANSPORT_ADDRESS) +
+ sizeof (TDI_ADDRESS_NETBIOS));
+ ConnectBlock = ExAllocatePool (NonPagedPool, sizeof (TRANSPORT_ADDRESS) +
+ sizeof (TDI_ADDRESS_NETBIOS));
+
+ ListenBlock->TAAddressCount = 1;
+ ListenBlock->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ ListenBlock->Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
+ temp = (PTDI_ADDRESS_NETBIOS)ListenBlock->Address[0].Address;
+
+ temp->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ for (i=0;i<16;i++) {
+ temp->NetbiosName[i] = ClientName[i];
+ }
+
+ ConnectBlock->TAAddressCount = 1;
+ ConnectBlock->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ ConnectBlock->Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
+ temp = (PTDI_ADDRESS_NETBIOS)ConnectBlock->Address[0].Address;
+
+ temp->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ for (i=0;i<16;i++) {
+ temp->NetbiosName[i] = ServerName[i];
+ }
+
+ //
+ // Create an event for the synchronous I/O requests that we'll be issuing.
+ //
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Status = TtdiOpenAddress (&SvrHandle, ServerName);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED on open of server Address: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ Status = ObReferenceObjectByHandle (
+ SvrHandle,
+ 0L,
+ NULL,
+ KernelMode,
+ (PVOID *) &AddressObject,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED on open of server Address: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ Status = TtdiOpenConnection (&SvrConnectionHandle, 2);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED on open of server Connection: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ Status = ObReferenceObjectByHandle (
+ SvrConnectionHandle,
+ 0L,
+ NULL,
+ KernelMode,
+ (PVOID *) &ConnectionObject,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED on open of server Connection: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ //
+ // Get a pointer to the stack location for the first driver. This will be
+ // used to pass the original function codes and parameters.
+ //
+
+ DeviceObject = IoGetRelatedDeviceObject( ConnectionObject );
+
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_ASSOCIATE_ADDRESS,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+ DbgPrint ("Build Irp %lx, Handle %lx \n",
+ Irp, SvrHandle);
+
+ TdiBuildAssociateAddress (
+ Irp,
+ DeviceObject,
+ ConnectionObject,
+ TSTRCVCompletion,
+ &Event1,
+ SvrHandle);
+ InitWaitObject (&Event1);
+
+ {
+ PULONG Temp=(PULONG)IoGetNextIrpStackLocation (Irp);
+ DbgPrint ("Built IrpSp %lx %lx %lx %lx %lx \n", *(Temp++), *(Temp++),
+ *(Temp++), *(Temp++), *(Temp++));
+ }
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+// IoFreeIrp (Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Event1 Wait Associate: %lC ******\n", Status );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Associate Iosb status: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+ DbgPrint( "\n****** Receive Test: AssociateAddress FAILED Status: %lC ******\n", Status );
+ return FALSE;
+ } else {
+ DbgPrint ("********** Receive Test: Success AssociateAddress\n");
+ }
+ }
+
+ RequestInformation.RemoteAddress = ConnectBlock;
+ RequestInformation.RemoteAddressLength = sizeof (TRANSPORT_ADDRESS) +
+ sizeof (TDI_ADDRESS_NETBIOS);
+
+ //
+ // Post a TdiListen to the server endpoint.
+ //
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_LISTEN,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+ TdiBuildListen (
+ Irp,
+ DeviceObject,
+ ConnectionObject,
+ TSTRCVCompletion,
+ &Event1,
+ 0,
+ &RequestInformation,
+ &ReturnInformation);
+ InitWaitObject (&Event1);
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+// IoFreeIrp (Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Event1 Wait Listen: %lC ******\n", Status );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Listen Iosb status: %lC ******\n", Status );
+ return FALSE;
+ } else {
+ DbgPrint ("********** Receive Test: Success Listen IOSB\n");
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+ DbgPrint( "\n****** Receive Test: Listen FAILED Status: %lC ******\n", Status );
+ return FALSE;
+ } else {
+ DbgPrint ("********** Receive Test: Success Listen Immediate\n");
+ }
+ }
+
+
+ DbgPrint ("\n****** Receive Test: LISTEN just completed! ******\n");
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_ACCEPT,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+ TdiBuildAccept (Irp, DeviceObject, ConnectionObject, NULL, NULL, &RequestInformation, NULL, 0);
+ InitWaitObject (&Event1);
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+// IoFreeIrp (Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Event1 Wait Accept: %lC ******\n", Status );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Accept Iosb status: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+ DbgPrint( "\n****** Receive Test: Accept FAILED Status: %lC ******\n", Status );
+ return FALSE;
+ }
+ }
+
+ //
+ // We have the connection data now. Sanity check it.
+ //
+
+ DbgPrint ("\n****** Receive Test: LISTEN completed successfully! ******\n");
+
+ //
+ // Receive/receive 1 or 10 messages.
+ //
+
+ SendBuffer = (PUCHAR)ExAllocatePool (NonPagedPool, SendBufferLength);
+ if (SendBuffer == NULL) {
+ DbgPrint ("\n****** Send Test: ExAllocatePool failed! ******\n");
+ }
+ SendMdl = IoAllocateMdl (SendBuffer, SendBufferLength, FALSE, FALSE, NULL);
+ MmBuildMdlForNonPagedPool (SendMdl);
+
+ MessageBuffer=(PUCHAR)ExAllocatePool (NonPagedPool, MessageBufferLength);
+ if (MessageBuffer == NULL) {
+ DbgPrint ("\n****** Send Test: ExAllocatePool failed! ******\n");
+ }
+ ReceiveMdl = IoAllocateMdl (MessageBuffer, MessageBufferLength, FALSE, FALSE, NULL);
+ MmBuildMdlForNonPagedPool (ReceiveMdl);
+
+ //
+ // Cycle the buffer length from 0 up through the maximum for Tdi. after a
+ // couple of shots at the full range in one byte steps, increment by ever
+ // increasing amounts to get to the max.
+ //
+
+ CurrentBufferLength = 0;
+ Increment = 1;
+ for (Iteration=1; Iteration<(USHORT)c9_Iteration; Iteration++) {
+ CurrentBufferLength += Increment;
+ if (CurrentBufferLength > MessageBufferLength) {
+ CurrentBufferLength = 0;
+ Increment = 1;
+ }
+ if (CurrentBufferLength > 7500) {
+ Increment++;
+ }
+ if ((USHORT)((Iteration / 100) * 100) == Iteration) {
+ DbgPrint ("Iteration #%d Buffer Length: %lx Buffer Start: %x\n",
+ Iteration, CurrentBufferLength,Iteration % 256);
+ }
+ for (i=0; i<(USHORT)CurrentBufferLength; i++) {
+ SendBuffer [i] = (UCHAR)(i + Iteration % 256 );
+ MessageBuffer [i] = 0; // zap this sucker with something.
+ }
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_RECEIVE,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+ TdiBuildReceive (Irp,
+ DeviceObject,
+ ConnectionObject,
+ TSTRCVCompletion,
+ &Event1,
+ ReceiveMdl,
+ MessageBufferLength);
+
+ InitWaitObject (&Event1);
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+// IoFreeIrp (Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Event1 Wait Receive: %lC ******\n", Status );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Receive Iosb status: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+ DbgPrint( "\n****** Receive Test: Listen FAILED Status: %lC ******\n", Status );
+ return FALSE;
+ }
+ }
+
+ //
+ // The receive completed. Make sure the data is correct.
+ //
+
+ if (Iosb1.Information != CurrentBufferLength) {
+ DbgPrint ("Iteration #%d Buffer Length: %lx Buffer Start: %x\n",
+ Iteration, CurrentBufferLength,Iteration % 256);
+ DbgPrint ("ReceiveTest: Bytes received <> bytes sent.\n");
+ DbgPrint ("ReceiveTest: BytesToSend=%ld. BytesReceived=%ld.\n",
+ CurrentBufferLength, Iosb1.Information);
+ }
+
+ if (i == (USHORT)CurrentBufferLength) {
+// DbgPrint ("ReceiveTest: Message contains correct data.\n");
+ } else {
+ DbgPrint ("ReceiveTest: Message data corrupted at offset %lx of %lx.\n", (ULONG)i, (ULONG)SendBufferLength);
+ DbgPrint ("ReceiveTest: Data around corrupted location:\n");
+ for (j=-4;j<=3;j++) {
+ DbgPrint ("%08lx ", (ULONG) i+j*16);
+ for (k=(SHORT)i+(j*(SHORT)16);k<(SHORT)i+((j+(SHORT)1)*(SHORT)16);k++) {
+ DbgPrint ("%02x",MessageBuffer [k]);
+ }
+ for (k=(SHORT)i+(j*(SHORT)16);k<(SHORT)i+((j+(SHORT)1)*(SHORT)16);k++) {
+ DbgPrint ("%c",MessageBuffer [k]);
+ }
+ DbgPrint ("\n");
+ }
+ DbgPrint ("ReceiveTest: End of Corrupt Data.\n");
+ }
+ }
+
+ //
+ // We're done with this endpoint. Close it and get out.
+ //
+
+ Status = CloseAddress (SvrHandle);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED on 1st Close: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ DbgPrint( "\n****** End of Receive Test ******\n" );
+ return TRUE;
+} /* Receive */
+
+BOOLEAN
+TtdiServer()
+{
+ USHORT i;
+ HANDLE RdrHandle, SrvConnectionHandle;
+ KEVENT Event1;
+ PFILE_OBJECT AddressObject, ConnectionObject;
+ PDEVICE_OBJECT DeviceObject;
+ NTSTATUS Status;
+ PMDL ReceiveMdl;
+ IO_STATUS_BLOCK Iosb1;
+ TDI_CONNECTION_INFORMATION RequestInformation;
+ TDI_CONNECTION_INFORMATION ReturnInformation;
+ PTRANSPORT_ADDRESS ListenBlock;
+ PTRANSPORT_ADDRESS ConnectBlock;
+ PTDI_ADDRESS_NETBIOS temp;
+ PUCHAR MessageBuffer;
+ ULONG MessageBufferLength;
+ ULONG CurrentBufferLength;
+ PIRP Irp;
+
+ Status = KeWaitForSingleObject (&TdiServerEvent, Suspended, KernelMode, FALSE, NULL);
+
+ MessageBufferLength = (ULONG)BUFFER_SIZE;
+
+
+ DbgPrint( "\n****** Start of Server Test ******\n" );
+
+ RBuff = ExAllocatePool (NonPagedPool, BUFFER_SIZE);
+ if (RBuff == (PVOID)NULL) {
+ DbgPrint ("Unable to allocate nonpaged pool for receive buffer exiting\n");
+ return FALSE;
+ }
+
+ ListenBlock = ExAllocatePool (NonPagedPool, sizeof (TRANSPORT_ADDRESS) +
+ sizeof (TDI_ADDRESS_NETBIOS));
+ ConnectBlock = ExAllocatePool (NonPagedPool, sizeof (TRANSPORT_ADDRESS) +
+ sizeof (TDI_ADDRESS_NETBIOS));
+
+ ListenBlock->TAAddressCount = 1;
+ ListenBlock->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ ListenBlock->Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
+ temp = (PTDI_ADDRESS_NETBIOS)ListenBlock->Address[0].Address;
+
+ temp->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ for (i=0;i<16;i++) {
+ temp->NetbiosName[i] = AnyName[i];
+ }
+
+ ConnectBlock->TAAddressCount = 1;
+ ConnectBlock->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ ConnectBlock->Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
+ temp = (PTDI_ADDRESS_NETBIOS)ConnectBlock->Address[0].Address;
+
+ temp->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ for (i=0;i<16;i++) {
+ temp->NetbiosName[i] = ServerName[i];
+ }
+
+ //
+ // Create an event for the synchronous I/O requests that we'll be issuing.
+ //
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Status = TtdiOpenAddress (&RdrHandle, ServerName);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Server Test: FAILED on open of client: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ Status = ObReferenceObjectByHandle (
+ RdrHandle,
+ 0L,
+ NULL,
+ KernelMode,
+ (PVOID *) &AddressObject,
+ NULL);
+
+ //
+ // Now loop forever trying to get a connection from a remote client to
+ // this server. We will create connections until we run out of resources,
+ // and we will echo the data we are sent back along the same connection.
+ // Sends and Receives are always asynchronous, while listens are
+ // synchronous.
+ //
+
+ while (TRUE) {
+
+ //
+ // Open the connection on the transport.
+ //
+
+ Status = TtdiOpenConnection (&SrvConnectionHandle, 1);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Server Test: FAILED on open of server Connection: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ Status = ObReferenceObjectByHandle (
+ SrvConnectionHandle,
+ 0L,
+ NULL,
+ KernelMode,
+ (PVOID *) &ConnectionObject,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Server Test: FAILED on open of server Connection: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ //
+ // Get a pointer to the stack location for the first driver. This will be
+ // used to pass the original function codes and parameters.
+ //
+
+ DeviceObject = IoGetRelatedDeviceObject( ConnectionObject );
+
+ //
+ // Now register the device handler for receives
+ //
+
+// Irp = TdiBuildInternalDeviceControlIrp (
+// TDI_SET_EVENT_HANDLER,
+// DeviceObject,
+// ConnectionObject,
+// &Event1,
+// &Iosb1);
+
+// TdiBuildSetEventHandler (Irp,
+// DeviceObject,
+// ConnectionObject,
+// TSTRCVCompletion,
+// &Event1,
+// TDI_RECEIVE_HANDLER,
+// TdiTestReceiveHandler,
+// ConnectionObject);
+
+// Status = IoCallDriver (DeviceObject, Irp);
+
+// if (Status == STATUS_PENDING) {
+// Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+// if (!NT_SUCCESS(Status)) {
+// DbgPrint( "\n****** Server Test: FAILED Event1 Wait Register: %lC ******\n", Status );
+// return FALSE;
+// }
+// if (!NT_SUCCESS(Iosb1.Status)) {
+// DbgPrint( "\n****** Server Test: FAILED Register Iosb status: %lC ******\n", Status );
+// return FALSE;
+// }
+//
+// } else {
+// if (!NT_SUCCESS (Status)) {
+// DbgPrint( "\n****** Server Test: RegisterHandler FAILED Status: %lC ******\n", Status );
+// return FALSE;
+// }
+// }
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_ASSOCIATE_ADDRESS,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+ TdiBuildAssociateAddress (Irp,
+ DeviceObject,
+ ConnectionObject,
+ TSTRCVCompletion,
+ &Event1,
+ RdrHandle);
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+ // IoFreeIrp (Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Server Test: FAILED Event1 Wait Associate: %lC ******\n", Status );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Server Test: FAILED Associate Iosb status: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+ DbgPrint( "\n****** Server Test: AssociateAddress FAILED Status: %lC ******\n", Status );
+ return FALSE;
+ }
+ }
+
+ //
+ // Post a TdiListen to the server endpoint.
+ //
+
+ RequestInformation.RemoteAddress = ListenBlock;
+ RequestInformation.RemoteAddressLength = sizeof (TRANSPORT_ADDRESS) +
+ sizeof (TDI_ADDRESS_NETBIOS);
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_LISTEN,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+ TdiBuildListen (
+ Irp,
+ DeviceObject,
+ ConnectionObject,
+ TSTRCVCompletion,
+ &Event1,
+ 0,
+ &RequestInformation,
+ NULL);
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Server Test: FAILED Event1 Wait Listen: %lC ******\n", Status );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Server Test: FAILED Listen Iosb status: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+ DbgPrint( "\n****** Server Test: Listen FAILED Status: %lC ******\n", Status );
+ return FALSE;
+ }
+ }
+
+ DbgPrint ("\n****** Server Test: LISTEN just completed! ******\n");
+
+ //
+ // accept the connection from the remote
+ //
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_ACCEPT,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+ TdiBuildAccept (
+ Irp,
+ DeviceObject,
+ ConnectionObject,
+ NULL,
+ NULL,
+ &RequestInformation,
+ NULL,
+ 0);
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+ // IoFreeIrp (Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Event1 Wait Accept: %lC ******\n", Status );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Accept Iosb status: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+ DbgPrint( "\n****** Accept Test: Listen FAILED Status: %lC ******\n", Status );
+ return FALSE;
+ }
+ }
+
+ //
+ // Get a buffer for the continued read/write loop.
+ //
+
+ MessageBuffer=(PUCHAR)ExAllocatePool (NonPagedPool, MessageBufferLength);
+ if (MessageBuffer == NULL) {
+ DbgPrint ("\n****** Send Test: ExAllocatePool failed! ******\n");
+ }
+ ReceiveMdl = IoAllocateMdl (MessageBuffer, MessageBufferLength, FALSE, FALSE, NULL);
+ MmBuildMdlForNonPagedPool (ReceiveMdl);
+
+ //
+ // have a receive buffer, and a connection; go ahead and read and write
+ // until the remote disconnects.
+ //
+
+ while (TRUE) {
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_RECEIVE,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+ TdiBuildReceive (Irp,
+ DeviceObject,
+ ConnectionObject,
+ TSTRCVCompletion,
+ &Event1,
+ ReceiveMdl,
+ MessageBufferLength);
+
+ InitWaitObject (&Event1);
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Event1 Wait Receive: %lC ******\n", Status );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Receive Iosb status: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+
+ //
+ // Check to see if the remote has disconnected, which is
+ // the only reason for us shutting down/
+ //
+
+ if (Status == STATUS_REMOTE_DISCONNECT) {
+
+ //
+ // We've been disconnected from; get out
+ //
+
+ NtClose (SrvConnectionHandle);
+ break;
+ }
+
+ DbgPrint( "\n****** Receive Test: Listen FAILED Status: %lC ******\n", Status );
+ return FALSE;
+ } else {
+
+ //
+ // successful return, what length is the data?
+ //
+
+ CurrentBufferLength = Iosb1.Information;
+ }
+ }
+
+ //
+ // send the data back
+ //
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_SEND,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+ TdiBuildSend (Irp,
+ DeviceObject,
+ ConnectionObject,
+ TSTRCVCompletion,
+ &Event1,
+ ReceiveMdl,
+ 0,
+ CurrentBufferLength);
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Event1 Wait Send: %lC ******\n", Status );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Send Iosb status: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+
+ DbgPrint( "\n****** Receive Test: Send FAILED Status: %lC ******\n", Status );
+ NtClose (SrvConnectionHandle);
+ break;
+
+ }
+ }
+ } // end of receive/send while
+
+ IoFreeMdl (ReceiveMdl);
+ ExFreePool (MessageBuffer);
+
+ }
+
+ //
+ // We're done with this address. Close it and get out.
+ //
+
+ Status = CloseAddress (RdrHandle);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Send Test: FAILED on 2nd Close: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ DbgPrint( "\n****** End of Send Test ******\n" );
+ return TRUE;
+} /* Server */
diff --git a/private/ntos/tdi/nbf/testtdi.c b/private/ntos/tdi/nbf/testtdi.c
new file mode 100644
index 000000000..6cf1b335f
--- /dev/null
+++ b/private/ntos/tdi/nbf/testtdi.c
@@ -0,0 +1,291 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ tstrcv.c
+
+Abstract:
+
+ start receive side tests utility
+
+Author:
+
+ Dave Beaver (dbeaver) 24-Mar-1991
+
+Revision History:
+
+--*/
+
+//
+// download a ub board
+//
+
+typedef unsigned char uchar_t;
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <string.h>
+//#include <windows.h>
+#include <nbf.h>
+
+#define TDIDEV "\\Device\\Nbf"
+char Tdidevice[] = TDIDEV; /* default device */
+char *Tdidev = Tdidevice;
+
+HANDLE FileHandle;
+
+VOID
+usage(
+ VOID
+ );
+
+
+NTSTATUS
+main (
+ IN SHORT argc,
+ IN PSZ argv[]
+ )
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ NTSTATUS Status;
+ STRING NameString;
+ UNICODE_STRING unicodeString;
+ PUCHAR buffer;
+ ULONG IoControlCode;
+ int n;
+ CHAR c;
+
+ for( n = 1; n < argc && argv[n][0] == '-' ; ++n ) {
+ c = argv[n][1];
+
+ switch( c ) {
+
+ case 's': // send test
+ IoControlCode = IOCTL_TDI_SEND_TEST;
+ break;
+
+ case 'r': // receive test
+ IoControlCode = IOCTL_TDI_RECEIVE_TEST;
+
+ break;
+
+ case 'b': /* both test */
+ IoControlCode = IOCTL_TDI_SERVER_TEST;
+
+ break;
+
+ default:
+ usage ();
+ break;
+
+ }
+ }
+
+ printf ("Opening TDI device: %s \n", Tdidev);
+ RtlInitString (&NameString, Tdidev);
+ Status = RtlAnsiStringToUnicodeString(
+ &unicodeString,
+ &NameString,
+ TRUE);
+
+ buffer = (PUCHAR)malloc (100);
+
+ Status = TdiOpenNetbiosAddress (&FileHandle, buffer, (PVOID)&NameString, NULL);
+
+ RtlFreeUnicodeString(&unicodeString);
+ free (buffer);
+
+ if (!NT_SUCCESS( Status )) {
+ printf ("FAILURE, Unable to open TDI driver %s, status: %lx.\n",
+ Tdidev,Status);
+ return (Status);
+ }
+
+ if (!(NT_SUCCESS( IoStatusBlock.Status ))) {
+ printf ("FAILURE, Unable to open TDI driver %s, IoStatusBlock.Status: %lx.\n",
+ Tdidev, IoStatusBlock.Status);
+ return (IoStatusBlock.Status);
+ }
+
+ //
+ // start the test
+ //
+
+ printf("Starting test.... ");
+ Status = NtDeviceIoControlFile(
+ FileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ IoControlCode,
+ NULL,
+ 0,
+ NULL,
+ 0);
+
+ if (!NT_SUCCESS( Status )) {
+ printf ("FAILURE, Unable to start test: %lx.\n", Status);
+ return (Status);
+ }
+
+ if (!(NT_SUCCESS( IoStatusBlock.Status ))) {
+ printf ("FAILURE, Unable to start test: %lx.\n", IoStatusBlock.Status);
+ return (IoStatusBlock.Status);
+ }
+
+ NtClose (FileHandle);
+
+ return STATUS_SUCCESS;
+
+}
+
+
+NTSTATUS
+TdiOpenNetbiosAddress (
+ IN OUT PHANDLE FileHandle,
+ IN PUCHAR Buffer,
+ IN PVOID DeviceName,
+ IN PVOID Address)
+
+/*++
+
+Routine Description:
+
+ Opens an address on the given file handle and device.
+
+Arguments:
+
+ FileHandle - the returned handle to the file object that is opened.
+
+ Buffer - pointer to a buffer that the ea is to be built in. This buffer
+ must be at least 40 bytes long.
+
+ DeviceName - the Unicode string that points to the device object.
+
+ Name - the address to be registered. If this pointer is NULL, the routine
+ will attempt to open a "control channel" to the device; that is, it
+ will attempt to open the file object with a null ea pointer, and if the
+ transport provider allows for that, will return that handle.
+
+Return Value:
+
+ An informative error code if something goes wrong. STATUS_SUCCESS if the
+ returned file handle is valid.
+
+--*/
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PFILE_FULL_EA_INFORMATION EaBuffer;
+ PTRANSPORT_ADDRESS TAAddress;
+ PTA_ADDRESS AddressType;
+ PTDI_ADDRESS_NETBIOS AddressName;
+ PSZ Name;
+ ULONG Length;
+ int i;
+
+ if (Address != NULL) {
+ Name = (PSZ)Address;
+ try {
+ Length = sizeof (FILE_FULL_EA_INFORMATION) +
+ sizeof (TRANSPORT_ADDRESS) +
+ sizeof (TDI_ADDRESS_NETBIOS);
+ EaBuffer = (PFILE_FULL_EA_INFORMATION)Buffer;
+
+ if (EaBuffer == NULL) {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ EaBuffer->NextEntryOffset =0;
+ EaBuffer->Flags = 0;
+ EaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
+ EaBuffer->EaValueLength = sizeof (TDI_ADDRESS_NETBIOS) +
+ sizeof (TRANSPORT_ADDRESS);
+
+ for (i=0;i<(int)EaBuffer->EaNameLength;i++) {
+ EaBuffer->EaName[i] = TdiTransportAddress[i];
+ }
+
+ TAAddress = (PTRANSPORT_ADDRESS)&EaBuffer->EaName[EaBuffer->EaNameLength+1];
+ TAAddress->TAAddressCount = 1;
+
+ AddressType = (PTA_ADDRESS)((PUCHAR)TAAddress + sizeof (TAAddress->TAAddressCount));
+
+ AddressType->AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ AddressType->AddressLength = TDI_ADDRESS_LENGTH_NETBIOS;
+
+ AddressName = (PTDI_ADDRESS_NETBIOS)((PUCHAR)AddressType +
+ sizeof (AddressType->AddressType) + sizeof (AddressType->AddressLength));
+ AddressName->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+
+ for (i=0;i<16;i++) {
+ AddressName->NetbiosName[i] = Name[i];
+ }
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ //
+ // Couldn't touch the passed parameters; just return an error
+ // status.
+ //
+
+ return GetExceptionCode();
+ }
+ } else {
+ EaBuffer = NULL;
+ Length = 0;
+ }
+
+ InitializeObjectAttributes (
+ &ObjectAttributes,
+ DeviceName,
+ 0,
+ NULL,
+ NULL);
+
+ Status = NtCreateFile (
+ FileHandle,
+ FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, // desired access.
+ &ObjectAttributes, // object attributes.
+ &IoStatusBlock, // returned status information.
+ 0, // block size (unused).
+ 0, // file attributes.
+ FILE_SHARE_READ | FILE_SHARE_WRITE, // share access.
+ FILE_CREATE, // create disposition.
+ 0, // create options.
+ EaBuffer, // EA buffer.
+ Length); // EA length.
+
+ if (!NT_SUCCESS( Status )) {
+ return Status;
+ }
+
+ Status = IoStatusBlock.Status;
+
+ if (!(NT_SUCCESS( Status ))) {
+ }
+
+ return Status;
+} /* TdiOpenNetbiosAddress */
+
+VOID
+usage(
+ VOID
+ )
+{
+ printf( "usage: tsttdi [-r] [-s] -[b]\n");
+ printf( "usage: -r run receive test.\n" );
+ printf( "usage: -b run server test.\n" );
+ printf( "usage: -s run send test.\n" );
+ printf( "\n" );
+ exit( 1 );
+}
+
diff --git a/private/ntos/tdi/nbf/timer.c b/private/ntos/tdi/nbf/timer.c
new file mode 100644
index 000000000..0664f0aa6
--- /dev/null
+++ b/private/ntos/tdi/nbf/timer.c
@@ -0,0 +1,2762 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ timer.c
+
+Abstract:
+
+ This module contains code that implements the lightweight timer system
+ for the NBF protocol provider. This is not a general-purpose timer system;
+ rather, it is specific to servicing LLC (802.2) links with three timers
+ each.
+
+ Services are provided in macro form (see NBFPROCS.H) to start and stop
+ timers. This module contains the code that gets control when the timer
+ in the device context expires as a result of calling kernel services.
+ The routine scans the device context's link database, looking for timers
+ that have expired, and for those that have expired, their expiration
+ routines are executed.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+ULONG StartTimer = 0;
+ULONG StartTimerSet = 0;
+ULONG StartTimerT1 = 0;
+ULONG StartTimerT2 = 0;
+ULONG StartTimerDelayedAck = 0;
+ULONG StartTimerLinkDeferredAdd = 0;
+ULONG StartTimerLinkDeferredDelete = 0;
+
+
+#if DBG
+extern ULONG NbfDebugPiggybackAcks;
+ULONG NbfDebugShortTimer = 0;
+#endif
+
+#if DBG
+//
+// These are temp, to track how the timers are working
+//
+ULONG TimerInsertsAtEnd = 0;
+ULONG TimerInsertsEmpty = 0;
+ULONG TimerInsertsInMiddle = 0;
+#endif
+
+//
+// These are constants calculated by InitializeTimerSystem
+// to be the indicated amound divided by the tick increment.
+//
+
+ULONG NbfTickIncrement = 0;
+ULONG NbfTwentyMillisecondsTicks = 0;
+ULONG NbfShortTimerDeltaTicks = 0;
+ULONG NbfMaximumIntervalTicks = 0; // usually 60 seconds in ticks
+
+LARGE_INTEGER DueTimeDelta = { (ULONG)(-SHORT_TIMER_DELTA), -1 };
+
+VOID
+ExpireT2Timer(
+ PTP_LINK Link
+ );
+
+VOID
+StopStalledConnections(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+
+
+ULONG
+GetTimerInterval(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ GetTimerInterval returns the difference in time between the
+ current time and Link->CurrentTimerStart (in ticks).
+ We limit the interval to 60 seconds. A value of 0 may
+ be returned which should be interpreted as 1/2.
+
+ NOTE: This routine should be called with the link spinlock
+ held.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ The interval.
+
+--*/
+
+{
+
+ LARGE_INTEGER CurrentTick;
+ LARGE_INTEGER Interval;
+
+
+ //
+ // Determine the current tick; the start tick has been saved
+ // in Link->CurrentTimerStart.
+ //
+
+ KeQueryTickCount (&CurrentTick);
+
+ //
+ // Determine the difference between now and then.
+ //
+
+ Interval.QuadPart = CurrentTick.QuadPart -
+ (Link->CurrentTimerStart).QuadPart;
+
+ //
+ // If the gap is too big, return 1 minute.
+ //
+
+ if (Interval.HighPart != 0 || (Interval.LowPart > NbfMaximumIntervalTicks)) {
+ return NbfMaximumIntervalTicks;
+ }
+
+ return Interval.LowPart;
+
+} /* GetTimerInterval */
+
+
+VOID
+BackoffCurrentT1Timeout(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called if T1 expires and we are about to
+ retransmit a poll frame. It backs off CurrentT1Timeout,
+ up to a limit of 10 seconds.
+
+ NOTE: This routine should be called with the link spinlock
+ held.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // We must have previously sent a poll frame if we are
+ // calling this.
+ //
+ // BUGBUG: we need spinlock guarding for MP.
+ //
+
+ if (!Link->CurrentPollOutstanding) {
+ return;
+ }
+
+ ++Link->CurrentPollRetransmits;
+
+ //
+ // T1 backs off 1.5 times each time.
+ //
+
+ Link->CurrentT1Timeout += (Link->CurrentT1Timeout >> 1);
+
+ //
+ // Limit T1 to 10 seconds.
+ //
+
+ if (Link->CurrentT1Timeout > ((10 * SECONDS) / SHORT_TIMER_DELTA)) {
+ Link->CurrentT1Timeout = (10 * SECONDS) / SHORT_TIMER_DELTA;
+ }
+
+} /* BackoffCurrentT1Timeout */
+
+
+VOID
+UpdateBaseT1Timeout(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a response to a poll frame is
+ received. StartT1 will have been called when the frame is
+ sent. The routine updates the link's T1 timeout as well
+ as delay and throughput.
+
+ NOTE: This routine should be called with the link spinlock
+ held.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Delay;
+ ULONG ShiftedTicksDelay;
+
+ //
+ // We must have previously sent a poll frame if we are
+ // calling this.
+ //
+
+ if (!Link->CurrentPollOutstanding) {
+ return;
+ }
+
+ Delay = GetTimerInterval (Link);
+
+ if (Link->CurrentPollRetransmits == 0) {
+
+ //
+ // Convert the delay into NBF ticks, shifted by
+ // DLC_TIMER_ACCURACY and also multiplied by 4.
+ // We want to divide by SHORT_TIMER_DELTA, then
+ // shift left by DLC_TIMER_ACCURACY+2. We divide
+ // by NbfShortTimerDeltaTicks because the Delay
+ // is returned in ticks.
+ //
+ // We treat a delay of 0 as 1/2, so we use 1
+ // shifted left by (DLC_TIMER_ACCURACY+1).
+ //
+
+ if (Delay == 0) {
+
+ ShiftedTicksDelay = (1 << (DLC_TIMER_ACCURACY + 1)) /
+ NbfShortTimerDeltaTicks;
+
+ } else {
+
+ ShiftedTicksDelay = (Delay << (DLC_TIMER_ACCURACY + 2)) /
+ NbfShortTimerDeltaTicks;
+
+ }
+
+
+ //
+ // Use the timing information to update BaseT1Timeout,
+ // if the last frame sent was large enough to matter
+ // (we use half of the max frame size here). This is
+ // so we don't shrink the timeout too much after sending
+ // a short frame. However, we update even for small frames
+ // if the last time we sent a poll we had to retransmit
+ // it, since that means T1 is much too small and we should
+ // increase it as much as we can. We also update for any
+ // size frame if the new delay is bigger than the current
+ // value, so we can ramp up quickly if needed.
+ //
+
+ if (ShiftedTicksDelay > Link->BaseT1Timeout) {
+
+ //
+ // If our new delay is more, than we weight it evenly
+ // with the previous value.
+ //
+
+ Link->BaseT1Timeout = (Link->BaseT1Timeout +
+ ShiftedTicksDelay) / 2;
+
+ } else if (Link->CurrentT1Backoff) {
+
+ //
+ // If we got a retransmit last time, then weight
+ // the new timer more heavily than usual.
+ //
+
+ Link->BaseT1Timeout = ((Link->BaseT1Timeout * 3) +
+ ShiftedTicksDelay) / 4;
+
+ } else if (Link->CurrentPollSize >= Link->BaseT1RecalcThreshhold) {
+
+ //
+ // Normally, the new timeout is 7/8 the previous value and
+ // 1/8 the newly observed delay.
+ //
+
+ Link->BaseT1Timeout = ((Link->BaseT1Timeout * 7) +
+ ShiftedTicksDelay) / 8;
+
+ }
+
+ //
+ // Restrict the real timeout to a minimum based on
+ // the link speed (always >= 400 ms).
+ //
+
+ if (Link->BaseT1Timeout < Link->MinimumBaseT1Timeout) {
+
+ Link->BaseT1Timeout = Link->MinimumBaseT1Timeout;
+
+ }
+
+
+ //
+ // Update link delay and throughput also. Remember
+ // that a delay of 0 should be interpreted as 1/2.
+ //
+
+ UpdateDelayAndThroughput(
+ Link,
+ (Delay == 0) ?
+ (NbfTickIncrement / 2) :
+ (Delay * NbfTickIncrement));
+
+
+ //
+ // We had no retransmits last time, so go back to current base.
+ //
+
+ Link->CurrentT1Timeout = Link->BaseT1Timeout >> DLC_TIMER_ACCURACY;
+
+ Link->CurrentT1Backoff = FALSE;
+
+ } else {
+
+ Link->CurrentT1Backoff = TRUE;
+
+ if (!(Link->ThroughputAccurate)) {
+
+ //
+ // If we are just starting up, we have to update the
+ // throughput even on a retransmit, so we get *some*
+ // value there.
+ //
+
+ UpdateDelayAndThroughput(
+ Link,
+ (Delay == 0) ?
+ (NbfTickIncrement / 2) :
+ (Delay * NbfTickIncrement));
+
+ }
+
+ }
+
+} /* UpdateBaseT1Timeout */
+
+
+VOID
+CancelT1Timeout(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when we have not received any
+ responses to a poll frame and are giving up rather
+ than retransmitting.
+
+ NOTE: This routine should be called with the link spinlock
+ held.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // We must have previously sent a poll frame if we are
+ // calling this.
+ //
+ // BUGBUG: We need spinlock guarding for MP.
+ //
+
+ if (!Link->CurrentPollOutstanding) {
+ return;
+ }
+
+ //
+ // We are stopping a polling condition, so reset T1.
+ //
+
+ Link->CurrentT1Timeout = Link->BaseT1Timeout >> DLC_TIMER_ACCURACY;
+
+ Link->CurrentT1Backoff = FALSE;
+
+ //
+ // Again, this isn't safe on MP (or UP, maybe).
+ //
+
+ Link->CurrentPollOutstanding = FALSE;
+
+} /* CancelT1Timeout */
+
+
+VOID
+UpdateDelayAndThroughput(
+ IN PTP_LINK Link,
+ IN ULONG TimerInterval
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a response packet used to time
+ link delay has been received. It is assumed that StartT1
+ or FakeStartT1 was called when the initial packet was sent.
+
+ NOTE: For now, we also calculate throughput based on this.
+
+ NOTE: This routine should be called with the link spinlock
+ held.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ TimerInterval - The link delay measured.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG PacketSize;
+
+
+ if (Link->Delay == 0xffffffff) {
+
+ //
+ // If delay is unknown, use this.
+ //
+
+ Link->Delay = TimerInterval;
+
+ } else if (Link->CurrentPollSize <= 64) {
+
+ //
+ // Otherwise, for small frames calculate the new
+ // delay by averaging with the old one.
+ //
+
+ Link->Delay = (Link->Delay + TimerInterval) / 2;
+
+ }
+
+
+ //
+ // Calculate the packet size times the number of time units
+ // in 10 milliseconds, which will allow us to calculate
+ // throughput in bytes/10ms (we later multiply by 100
+ // to obtain the real throughput in bytes/s).
+ //
+ // Given the size of MILLISECONDS, this allows packets of up
+ // to ~20K, so for bigger packets we just assume that (since
+ // throughput won't be an issue there).
+ //
+
+ if (Link->CurrentPollSize > 20000) {
+ PacketSize = 20000 * (10 * MILLISECONDS);
+ } else {
+ PacketSize = Link->CurrentPollSize * (10*MILLISECONDS);
+ }
+
+ //
+ // If throughput is not accurate, then we will use this
+ // packet only to calculate it. To avoid being confused
+ // by very small packets, assume a minimum size of 64.
+ //
+
+ if ((!Link->ThroughputAccurate) && (PacketSize < (64*(10*MILLISECONDS)))) {
+ PacketSize = 64 * (10*MILLISECONDS);
+ }
+
+ //
+ // PacketSize is going to be divided by TimerInterval;
+ // to prevent a zero throughput, we boost it up if needed.
+ //
+
+ if (PacketSize < TimerInterval) {
+ PacketSize = TimerInterval;
+ }
+
+
+ if (Link->CurrentPollSize >= 512) {
+
+ //
+ // Calculate throughput here by removing the established delay
+ // from the time.
+ //
+
+ if ((Link->Delay + (2*MILLISECONDS)) < TimerInterval) {
+
+ //
+ // If the current delay is less than the new timer
+ // interval (plus 2 ms), then subtract it off for a
+ // more accurate throughput calculation.
+ //
+
+ TimerInterval -= Link->Delay;
+
+ }
+
+ //
+ // We assume by this point (sending a > 512-byte frame) we
+ // already have something established as Link->Throughput.
+ //
+
+ if (!(Link->ThroughputAccurate)) {
+
+ Link->Throughput.QuadPart =
+ UInt32x32To64((PacketSize / TimerInterval), 100);
+
+ Link->ThroughputAccurate = TRUE;
+
+#if 0
+ NbfPrint2 ("INT: %ld.%1.1d us\n",
+ TimerInterval / 10, TimerInterval % 10);
+ NbfPrint4 ("D: %ld.%1.1d us T: %ld (%d)/s\n",
+ Link->Delay / 10, Link->Delay % 10,
+ Link->Throughput.LowPart, Link->CurrentPollSize);
+#endif
+
+ } else {
+
+ LARGE_INTEGER TwiceThroughput;
+
+ //
+ // New throughput is the average of the old throughput, and
+ // the current packet size divided by the delay just observed.
+ // First we calculate the sum, then we shift right by one.
+ //
+
+ TwiceThroughput.QuadPart = Link->Throughput.QuadPart +
+ UInt32x32To64((PacketSize / TimerInterval), 100);
+
+ Link->Throughput.QuadPart = TwiceThroughput.QuadPart >> 1;
+ }
+
+ } else if (!(Link->ThroughputAccurate)) {
+
+ //
+ // We don't have accurate throughput, so just get an estimate
+ // by ignoring the delay on this small frame.
+ //
+
+ Link->Throughput.QuadPart =
+ UInt32x32To64((PacketSize / TimerInterval), 100);
+
+ }
+
+} /* UpdateDelayAndThroughput */
+
+
+VOID
+FakeStartT1(
+ IN PTP_LINK Link,
+ IN ULONG PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called before sending a packet that will be used
+ to time link delay, but where StartT1 will not be started.
+ It is assumed that FakeUpdateBaseT1Timeout will be called
+ when the response is received. This is used for timing
+ frames that have a known immediate response, but are not
+ poll frames.
+
+ NOTE: This routine should be called with the link spinlock
+ held.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ PacketSize - The size of the packet that was just sent.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ Link->CurrentPollSize = PacketSize;
+ KeQueryTickCount(&Link->CurrentTimerStart);
+
+} /* FakeStartT1 */
+
+
+VOID
+FakeUpdateBaseT1Timeout(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a response to a frame is
+ received, and we called FakeStartT1 when the initial
+ frame was sent. This is used for timing frames that have
+ a known immediate response, but are not poll frames.
+
+ NOTE: This routine should be called with the link spinlock
+ held.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ None.
+
+--*/
+
+
+{
+ ULONG Delay;
+
+ Delay = GetTimerInterval (Link);
+
+ //
+ // Convert the delay into NBF ticks, shifted by
+ // DLC_TIMER_ACCURACY and also multiplied by 4.
+ // We want to divide by SHORT_TIMER_DELTA, then
+ // shift left by DLC_TIMER_ACCURACY+2. We divide
+ // by NbfShortTimerDeltaTicks because the Delay
+ // is returned in ticks. We treat a Delay of 0
+ // as 1/2 and calculate ((1/2) << x) as (1 << (x-1)).
+ //
+ // This timeout is treated as the correct value.
+ //
+
+ if (Delay == 0) {
+
+ Link->BaseT1Timeout = (1 << (DLC_TIMER_ACCURACY + 1)) /
+ NbfShortTimerDeltaTicks;
+
+ } else {
+
+ Link->BaseT1Timeout = (Delay << (DLC_TIMER_ACCURACY + 2)) /
+ NbfShortTimerDeltaTicks;
+
+ }
+
+ //
+ // Restrict the real timeout to a minimum based on
+ // the link speed (always >= 400 ms).
+ //
+
+ if (Link->BaseT1Timeout < Link->MinimumBaseT1Timeout) {
+ Link->BaseT1Timeout = Link->MinimumBaseT1Timeout;
+ }
+
+ Link->CurrentT1Timeout = Link->BaseT1Timeout >> DLC_TIMER_ACCURACY;
+
+ //
+ // Update link delay and throughput also.
+ //
+
+ UpdateDelayAndThroughput(
+ Link,
+ (Delay == 0) ?
+ (NbfTickIncrement / 2) :
+ (Delay * NbfTickIncrement));
+
+} /* FakeUpdateBaseT1Timeout */
+
+
+VOID
+StartT1(
+ IN PTP_LINK Link,
+ IN ULONG PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the T1 timer for the given link. If the link was
+ already on the list, it is moved to the tail. If not, it is inserted at
+ tail.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Link - pointer to the link of interest.
+
+ PollPacketSize - If a poll packet was just sent it is its size;
+ otherwise this will be 0 (when non-poll I-frames are sent).
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext = Link->Provider;
+
+ if (PacketSize > 0) {
+
+ //
+ // If we are sending an initial poll frame, then do timing stuff.
+ //
+
+ Link->CurrentPollRetransmits = 0;
+ Link->CurrentPollSize = PacketSize;
+ Link->CurrentPollOutstanding = TRUE;
+ KeQueryTickCount(&Link->CurrentTimerStart);
+
+ } else {
+
+ Link->CurrentPollOutstanding = FALSE;
+
+ }
+
+
+ //
+ // Insert us in the queue if we aren't in it.
+ //
+
+ Link->T1 = DeviceContext->ShortAbsoluteTime+Link->CurrentT1Timeout;
+
+ if (!Link->OnShortList) {
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ if (!Link->OnShortList) {
+ Link->OnShortList = TRUE;
+ InsertTailList (&DeviceContext->ShortList, &Link->ShortList);
+ }
+
+ if (!DeviceContext->a.i.ShortListActive) {
+
+ StartTimerT1++;
+ NbfStartShortTimer (DeviceContext);
+ DeviceContext->a.i.ShortListActive = TRUE;
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+ }
+
+}
+
+
+VOID
+StartT2(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds the given link to the T2 queue and starts the timer.
+ If the link is already on the queue, it is moved to the queue end.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Link - pointer to the link of interest.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext = Link->Provider;
+
+
+ if (DeviceContext->MacInfo.MediumAsync) {
+
+ //
+ // On an async line, expire it as soon as possible.
+ //
+
+ Link->T2 = DeviceContext->ShortAbsoluteTime;
+
+ } else {
+
+ Link->T2 = DeviceContext->ShortAbsoluteTime+Link->T2Timeout;
+
+ }
+
+
+ if (!Link->OnShortList) {
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ if (!Link->OnShortList) {
+ Link->OnShortList = TRUE;
+ InsertTailList (&DeviceContext->ShortList, &Link->ShortList);
+ }
+
+ if (!DeviceContext->a.i.ShortListActive) {
+
+ StartTimerT2++;
+ NbfStartShortTimer (DeviceContext);
+ DeviceContext->a.i.ShortListActive = TRUE;
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+ }
+
+}
+
+
+VOID
+StartTi(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds the given link to the Ti queue and starts the timer.
+ As above, if the link is already on the queue it is moved to the queue end.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Link - pointer to the link of interest.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext = Link->Provider;
+
+
+ //
+ // On an easily disconnected link, with only server connections
+ // on this link, we set a long Ti timeout, and when it
+ // expires with no activity we start checkpointing, otherwise
+ // we assume things are OK.
+ //
+
+ if (DeviceContext->EasilyDisconnected && Link->NumberOfConnectors == 0) {
+ Link->Ti = DeviceContext->LongAbsoluteTime + (2 * Link->TiTimeout);
+ Link->TiStartPacketsReceived = Link->PacketsReceived;
+ } else {
+ Link->Ti = DeviceContext->LongAbsoluteTime+Link->TiTimeout;
+ }
+
+
+ if (!Link->OnLongList) {
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ if (!Link->OnLongList) {
+ Link->OnLongList = TRUE;
+ InsertTailList (&DeviceContext->LongList, &Link->LongList);
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+ }
+
+
+}
+
+#if DBG
+
+VOID
+StopT1(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine
+
+Arguments:
+
+ Link - pointer to the link of interest.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Again, this isn't safe on MP (or UP, maybe).
+ //
+
+ Link->CurrentPollOutstanding = FALSE;
+ Link->T1 = 0;
+
+}
+
+
+VOID
+StopT2(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine
+
+Arguments:
+
+ Link - pointer to the link of interest.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ Link->ConsecutiveIFrames = 0;
+ Link->T2 = 0;
+
+}
+
+
+VOID
+StopTi(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine
+
+Arguments:
+
+ Link - pointer to the link of interest.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ Link->Ti = 0;
+}
+#endif
+
+
+VOID
+ExpireT1Timer(
+ PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a link's T1 timer expires. T1 is the
+ retransmission timer, and is used to remember that a response is
+ expected to any of the following: (1) a checkpoint, (2) a transmitted
+ I-frame, (3) a SABME, or (4) a DISC. Cases 3 and 4 are actually
+ special forms of a checkpoint, since they are sent by this protocol
+ implementation with the poll bit set, effectively making them a
+ checkpoint sequence.
+
+Arguments:
+
+ Link - Pointer to the TP_LINK object whose T1 timer has expired.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDLC_I_FRAME DlcHeader;
+
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("ExpireT1Timer: Entered.\n");
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ switch (Link->State) {
+
+ case LINK_STATE_ADM:
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("ExpireT1Timer: State=ADM, timeout not expected.\n");
+ }
+ break;
+
+ case LINK_STATE_READY:
+
+ //
+ // We've sent an I-frame and haven't received an acknowlegement
+ // yet, or we are checkpointing, and must retry the checkpoint.
+ // Another possibility is that we're rejecting, and he hasn't
+ // sent anything yet.
+ //
+
+ switch (Link->SendState) {
+
+ case SEND_STATE_DOWN:
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("ExpireT1Timer: Link READY but SendState=DOWN.\n");
+ }
+ break;
+
+ case SEND_STATE_READY:
+
+ //
+ // We sent an I-frame and didn't get an acknowlegement.
+ // Initiate a checkpoint sequence.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ {PTP_PACKET packet;
+ PLIST_ENTRY p;
+ NbfPrint0 ("ExpireT1Timer: Link State=READY, SendState=READY .\n");
+ NbfDumpLinkInfo (Link);
+ p=Link->WackQ.Flink;
+ NbfPrint0 ("ExpireT1Timer: Link WackQ entries:\n");
+ while (p != &Link->WackQ) {
+ packet = CONTAINING_RECORD (p, TP_PACKET, Linkage);
+ DlcHeader = (PDLC_I_FRAME)&(packet->Header[Link->HeaderLength]);
+ NbfPrint2 (" %08lx %03d\n", p,
+ (DlcHeader->SendSeq >> 1));
+ p = p->Flink;
+ }}
+ }
+
+ Link->SendRetries = (UCHAR)Link->LlcRetries;
+ Link->SendState = SEND_STATE_CHECKPOINTING;
+ // Don't BackoffT1Timeout yet.
+ NbfSendRr (Link, TRUE, TRUE);// send RR-c/p, StartT1, release lock
+ break;
+
+ case SEND_STATE_REJECTING:
+
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("ExpireT1Timer: Link State=READY, SendState=REJECTING.\n");
+ NbfPrint0 ("so what do we do here? consult the manual...\n");
+ }
+ Link->SendState = SEND_STATE_CHECKPOINTING;
+// Link->SendRetries = Link->LlcRetries;
+// break; // DGB: doing nothing is obviously wrong, we've
+// // gotten a T1 expiration during resend. Try
+// // an RR to say hey.
+
+ case SEND_STATE_CHECKPOINTING:
+
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("ExpireT1Timer: Link State=READY, SendState=CHECKPOINTING.\n");
+ NbfDumpLinkInfo (Link);
+ }
+ if (--Link->SendRetries == 0) {
+
+ //
+ // We have not gotten any response to RR-p packets,
+ // initiate orderly link teardown.
+ //
+
+ CancelT1Timeout (Link); // we are stopping a polling state
+
+ Link->State = LINK_STATE_W_DISC_RSP; // we are awaiting a DISC/f.
+ Link->SendState = SEND_STATE_DOWN;
+ Link->ReceiveState = RECEIVE_STATE_DOWN;
+ Link->SendRetries = (UCHAR)Link->LlcRetries;
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ NbfStopLink (Link);
+
+ StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME)); // retransmit timer.
+ NbfSendDisc (Link, TRUE); // send DISC-c/p.
+
+#if DBG
+ if (NbfDisconnectDebug) {
+ NbfPrint0( "ExpireT1Timer sending DISC (checkpoint failed)\n" );
+ }
+#endif
+ } else {
+
+ BackoffCurrentT1Timeout (Link);
+ NbfSendRr (Link, TRUE, TRUE); // send RR-c/p, StartT1, release lock.
+
+ }
+ break;
+
+ default:
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint1 ("ExpireT1Timer: Link State=READY, SendState=%ld (UNKNOWN).\n",
+ Link->SendState);
+ }
+ }
+ break;
+
+ case LINK_STATE_CONNECTING:
+
+ //
+ // We sent a SABME-c/p and have not yet received UA-r/f. This
+ // means we must decrement the retry count and if it is not yet
+ // zero, we issue another SABME command, because he has probably
+ // dropped our first one.
+ //
+
+ if (--Link->SendRetries == 0) {
+
+ CancelT1Timeout (Link); // we are stopping a polling state
+
+ Link->State = LINK_STATE_ADM;
+ NbfSendDm (Link, FALSE); // send DM/0, release lock
+#if DBG
+ if (NbfDisconnectDebug) {
+ NbfPrint0( "ExpireT1Timer calling NbfStopLink (no response to SABME)\n" );
+ }
+#endif
+ NbfStopLink (Link);
+
+ // moving to ADM, remove reference
+ NbfDereferenceLinkSpecial("Expire T1 in CONNECTING mode", Link, LREF_NOT_ADM);
+
+ return; // skip extra spinlock release.
+ } else {
+ BackoffCurrentT1Timeout (Link);
+ NbfSendSabme (Link, TRUE); // send SABME/p, StartT1, release lock
+ }
+ break;
+
+ case LINK_STATE_W_POLL:
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("ExpireT1Timer: State=W_POLL, timeout not expected.\n");
+ }
+ break;
+
+ case LINK_STATE_W_FINAL:
+
+ //
+ // We sent our initial RR-c/p and have not received his RR-r/f.
+ // We have to restart the checkpoint, unless our retries have
+ // run out, in which case we just abort the link.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("ExpireT1Timer: Link State=W_FINAL.\n");
+ NbfDumpLinkInfo (Link);
+ }
+
+ if (--Link->SendRetries == 0) {
+
+ CancelT1Timeout (Link); // we are stopping a polling state
+
+ Link->State = LINK_STATE_ADM;
+ NbfSendDm (Link, FALSE); // send DM/0, release lock
+#if DBG
+ if (NbfDisconnectDebug) {
+ NbfPrint0( "ExpireT1Timer calling NbfStopLink (no final received)\n" );
+ }
+#endif
+ NbfStopLink (Link);
+
+ // moving to ADM, remove reference
+ NbfDereferenceLinkSpecial("Expire T1 in W_FINAL mode", Link, LREF_NOT_ADM);
+
+ return; // skip extra spinlock release.
+
+ } else {
+
+ BackoffCurrentT1Timeout (Link);
+ NbfSendRr (Link, TRUE, TRUE); // send RR-c/p, StartT1, release lock
+
+ }
+ break;
+
+ case LINK_STATE_W_DISC_RSP:
+
+ //
+ // We sent a DISC-c/p to disconnect this link and are awaiting
+ // his response, either a UA-r/f or DM-r/f. We have to issue
+ // the DISC again, unless we've tried a few times, in which case
+ // we just shut the link down.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint0 ("ExpireT1Timer: Link State=W_DISC_RESP.\n");
+ NbfDumpLinkInfo (Link);
+ }
+
+ if (--Link->SendRetries == 0) {
+
+ CancelT1Timeout (Link); // we are stopping a polling state
+
+ Link->State = LINK_STATE_ADM;
+ NbfSendDm (Link, FALSE); // send DM/0, release lock
+#if DBG
+ if (NbfDisconnectDebug) {
+ NbfPrint0( "ExpireT1Timer calling NbfStopLink (no response to DISC)\n" );
+ }
+#endif
+ NbfStopLink (Link);
+
+ // moving to ADM, remove reference
+ NbfDereferenceLinkSpecial("Expire T1 in W_DISC_RSP mode", Link, LREF_NOT_ADM);
+
+ return; // skip extra spinlock release.
+
+ } else {
+
+ // we don't bother calling BackoffCurrentT1Timeout for DISCs.
+ ++Link->CurrentPollRetransmits;
+ StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME)); // startup timer again.
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ NbfSendDisc (Link, TRUE); // send DISC/p.
+
+ }
+ break;
+
+ default:
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint1 ("ExpireT1Timer: State=%ld (UNKNOWN), timeout not expected.\n",
+ Link->State);
+ }
+ }
+
+
+} /* ExpireT1Timer */
+
+
+VOID
+ExpireT2Timer(
+ PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a link's T2 timer expires. T2 is the
+ delayed acknowlegement timer in the LLC connection-oriented procedures.
+ The T2 timer is started when a valid I-frame is received but not
+ immediately acknowleged. Then, if reverse I-frame traffic is sent,
+ the timer is stopped, since the reverse traffic will acknowlege the
+ received I-frames. If no reverse I-frame traffic becomes available
+ to send, then this timer fires, causing a RR-r/0 to be sent so as
+ to acknowlege the received but as yet unacked I-frames.
+
+Arguments:
+
+ Link - Pointer to the TP_LINK object whose T2 timer has expired.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("ExpireT2Timer: Entered.\n");
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ NbfSendRr (Link, FALSE, FALSE); // send RR-r/f, release lock.
+
+} /* ExpireT2Timer */
+
+
+VOID
+ExpireTiTimer(
+ PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a link's Ti timer expires. Ti is the
+ inactivity timer, and serves as a keep-alive on a link basis, to
+ periodically perform some protocol exchange with the remote connection
+ partner that will implicitly reveal whether the link is still active
+ or not. This implementation simply uses a checkpoint sequence, but
+ some other protocols may choose to add protocol, including sending
+ a NetBIOS SESSION_ALIVE frame. If a checkpoint sequence is already
+ in progress, then we do nothing.
+
+ This timer expiration routine is self-perpetuating; that is, it starts
+ itself after finishing its tasks every time.
+
+Arguments:
+
+ Link - Pointer to the TP_LINK object whose Ti timer has expired.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("ExpireTiTimer: Entered.\n");
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ if ((Link->State != LINK_STATE_ADM) &&
+ (Link->State != LINK_STATE_W_DISC_RSP) &&
+ (Link->SendState != SEND_STATE_CHECKPOINTING)) {
+
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("ExpireTiTimer: Entered.\n");
+ NbfDumpLinkInfo (Link);
+ }
+
+ if (Link->Provider->EasilyDisconnected && Link->NumberOfConnectors == 0) {
+
+ //
+ // On an easily disconnected network with only server connections,
+ // if there has been no activity in this timeout period then
+ // we trash the connection.
+ //
+
+ if (Link->PacketsReceived == Link->TiStartPacketsReceived) {
+
+ Link->State = LINK_STATE_ADM;
+ NbfSendDm (Link, FALSE); // send DM/0, release lock
+#if DBG
+ if (NbfDisconnectDebug) {
+ NbfPrint0( "ExpireT1Timer calling NbfStopLink (no final received)\n" );
+ }
+#endif
+ NbfStopLink (Link);
+
+ // moving to ADM, remove reference
+ NbfDereferenceLinkSpecial("Expire T1 in W_FINAL mode", Link, LREF_NOT_ADM);
+
+ } else {
+
+ //
+ // There was traffic, restart the timer.
+ //
+
+ StartTi (Link);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ }
+
+ } else {
+
+#if 0
+ if ((Link->SendState == SEND_STATE_READY) &&
+ (Link->T1 == 0) &&
+ (!IsListEmpty (&Link->WackQ))) {
+
+ //
+ // If we think the link is idle but there are packets
+ // on the WackQ, the link is messed up, disconnect it.
+ //
+
+ NbfPrint1 ("NBF: Link %d hung at Ti expiration, recovering\n", Link);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ NbfStopLink (Link);
+
+ } else {
+#endif
+
+ Link->SendState = SEND_STATE_CHECKPOINTING;
+ Link->PacketsSent = 0;
+ Link->PacketsResent = 0;
+ Link->PacketsReceived = 0;
+ NbfSendRr (Link, TRUE, TRUE); // send RR-c/p, StartT1, release lock.
+
+#if 0
+ }
+#endif
+
+ }
+
+ } else {
+
+ Link->PacketsSent = 0;
+ Link->PacketsResent = 0;
+ Link->PacketsReceived = 0;
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ if (Link->SendState == SEND_STATE_REJECTING) {
+ NbfPrint0 ("ExpireTiTimer: link state == rejecting, shouldn't be\n");
+ }
+#endif
+
+ }
+
+#if 0
+ //
+ // Startup the inactivity timer again.
+ //
+
+ if (Link->State != LINK_STATE_ADM) {
+ StartTi (Link);
+ }
+#endif
+
+} /* ExpireTiTimer */
+
+#if 0
+
+VOID
+ExpirePurgeTimer(
+ PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the device context's periodic adaptive
+ window algorithm timer expires. The timer perpetuates itself on a
+ regular basis.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context whose purge timer has expired.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PTP_LINK Link;
+ PLIST_ENTRY p;
+
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("ExpirePurgeTimer: Entered.\n");
+ }
+
+ //
+ // Scan through the link database on this device context and clear
+ // their worst window size limit. This will allow stuck links to
+ // grow their window again even though they encountered temporary
+ // congestion at the remote link station's adapter.
+ //
+
+ while (!IsListEmpty (&DeviceContext->PurgeList)) {
+ p = RemoveHeadList (&DeviceContext->PurgeList);
+ Link = CONTAINING_RECORD (p, TP_LINK, PurgeList);
+ Link->WorstWindowSize = Link->MaxWindowSize; // maximum window possible.
+
+ }
+
+ //
+ // Restart purge timer.
+ //
+
+ DeviceContext->AdaptivePurge = DeviceContext->ShortAbsoluteTime + TIMER_PURGE_TICKS;
+
+
+} /* ExpirePurgeTimer */
+#endif
+
+
+VOID
+ScanShortTimersDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called at DISPATCH_LEVEL by the system at regular
+ intervals to determine if any link-level timers have expired, and
+ if they have, to execute their expiration routines.
+
+Arguments:
+
+ DeferredContext - Pointer to our DEVICE_CONTEXT object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PLIST_ENTRY p, nextp;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_LINK Link;
+ PTP_CONNECTION Connection;
+ BOOLEAN RestartTimer = FALSE;
+ LARGE_INTEGER CurrentTick;
+ LARGE_INTEGER TickDifference;
+ ULONG TickDelta;
+
+
+ Dpc, SystemArgument1, SystemArgument2; // prevent compiler warnings
+
+ ENTER_NBF;
+
+ IF_NBFDBG (NBF_DEBUG_TIMERDPC) {
+ NbfPrint0 ("ScanShortTimersDpc: Entered.\n");
+ }
+
+ DeviceContext = DeferredContext;
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ //
+ // This prevents anybody from starting the timer while we
+ // are in this routine (the main reason for this is that it
+ // makes it easier to determine whether we should restart
+ // it at the end of this routine).
+ //
+
+ DeviceContext->ProcessingShortTimer = TRUE;
+
+ //
+ // Advance the up-counter used to mark time in SHORT_TIMER_DELTA units. If we
+ // advance it all the way to 0xf0000000, then reset it to 0x10000000.
+ // We also run all the lists, decreasing all counters by 0xe0000000.
+ //
+
+
+ KeQueryTickCount (&CurrentTick);
+
+ TickDifference.QuadPart = CurrentTick.QuadPart -
+ (DeviceContext->ShortTimerStart).QuadPart;
+
+ TickDelta = TickDifference.LowPart / NbfShortTimerDeltaTicks;
+ if (TickDelta == 0) {
+ TickDelta = 1;
+ }
+
+ DeviceContext->ShortAbsoluteTime += TickDelta;
+
+ if (DeviceContext->ShortAbsoluteTime >= 0xf0000000) {
+
+ ULONG Timeout;
+
+ DeviceContext->ShortAbsoluteTime -= 0xe0000000;
+
+ p = DeviceContext->ShortList.Flink;
+ while (p != &DeviceContext->ShortList) {
+
+ Link = CONTAINING_RECORD (p, TP_LINK, ShortList);
+
+ Timeout = Link->T1;
+ if (Timeout) {
+ Link->T1 = Timeout - 0xe0000000;
+ }
+
+ Timeout = Link->T2;
+ if (Timeout) {
+ Link->T2 = Timeout - 0xe0000000;
+ }
+
+ p = p->Flink;
+ }
+
+ }
+
+ //
+ // now, as the timers are started, links are added to the end of the
+ // respective queue for that timer. since we know the additions are
+ // done in an orderly fashion and are sequential, we must only traverse
+ // a particular timer list to the first entry that is greater than our
+ // timer. That entry and all further entries will not need service.
+ // When a timer is cancelled, we remove the link from the list. With all
+ // of this fooling around, we wind up only visiting those links that are
+ // actually in danger of timing out, minimizing time in this routine.
+ //
+
+ // T1 timers first; this is the link-level response expected timer, and is
+ // the shortest one.
+ // T2 timers. This is the iframe response expected timer, and is typically
+ // about 300 ms.
+
+ p = DeviceContext->ShortList.Flink;
+ while (p != &DeviceContext->ShortList) {
+
+ Link = CONTAINING_RECORD (p, TP_LINK, ShortList);
+
+ ASSERT (Link->OnShortList);
+
+ //
+ // To avoid problems with the refcount being 0, don't
+ // do this if we are in ADM.
+ //
+
+ if (Link->State != LINK_STATE_ADM) {
+
+ if (Link->T1 && (DeviceContext->ShortAbsoluteTime > Link->T1)) {
+
+ Link->T1 = 0;
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ ExpireT1Timer (Link); // no spinlocks held
+ INCREMENT_COUNTER (DeviceContext, ResponseTimerExpirations);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ }
+
+ if (Link->T2 && (DeviceContext->ShortAbsoluteTime > Link->T2)) {
+
+ Link->T2 = 0;
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ ExpireT2Timer (Link); // no spinlocks held
+ INCREMENT_COUNTER (DeviceContext, AckTimerExpirations);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ }
+
+ }
+
+ if (!Link->OnShortList) {
+
+ //
+ // The link has been taken out of the list while
+ // we were processing it. In this (rare) case we
+ // stop processing the whole list, we'll get it
+ // next time.
+ //
+
+#if DBG
+ DbgPrint ("NBF: Stop processing ShortList, %lx removed\n", Link);
+#endif
+ break;
+
+ }
+
+ nextp = p->Flink;
+
+ if ((Link->T1 == 0) && (Link->T2 == 0)) {
+ Link->OnShortList = FALSE;
+ RemoveEntryList(p);
+
+ //
+ // Do another check; that way if someone slipped in between
+ // the check of Link->Tx and the OnShortList = FALSE and
+ // therefore exited without inserting, we'll catch that here.
+ //
+
+ if ((Link->T1 != 0) || (Link->T2 != 0)) {
+ InsertTailList(&DeviceContext->ShortList, &Link->ShortList);
+ Link->OnShortList = TRUE;
+ }
+
+ }
+
+ p = nextp;
+
+ }
+
+ //
+ // If the list is empty note that, otherwise ShortListActive
+ // remains TRUE.
+ //
+
+ if (IsListEmpty (&DeviceContext->ShortList)) {
+ DeviceContext->a.i.ShortListActive = FALSE;
+ }
+
+ //
+ // NOTE: DeviceContext->TimerSpinLock is held here.
+ //
+
+
+ //
+ // Connection Data Ack timers. This queue is used to indicate
+ // that a piggyback ack is pending for this connection. We walk
+ // the queue, for each element we check if the connection has
+ // been on the queue for NbfDeferredPasses times through
+ // here. If so, we take it off and send an ack. Note that
+ // we have to be very careful how we walk the queue, since
+ // it may be changing while this is running.
+ //
+ // NOTE: There is no expiration time for connections on this
+ // queue; it "expires" every time ScanShortTimersDpc runs.
+ //
+
+
+ for (p = DeviceContext->DataAckQueue.Flink;
+ p != &DeviceContext->DataAckQueue;
+ p = p->Flink) {
+
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, DataAckLinkage);
+
+ //
+ // Skip this connection if it is not queued or it is
+ // too recent to matter. We may skip incorrectly if
+ // the connection is just being queued, but that is
+ // OK, we will get it next time.
+ //
+
+ if (((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_ACK) == 0) &&
+ ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_NOT_Q) == 0)) {
+ continue;
+ }
+
+ TickDifference.QuadPart = CurrentTick.QuadPart -
+ (Connection->ConnectStartTime).QuadPart;
+
+ if ((TickDifference.HighPart == 0) &&
+ (TickDifference.LowPart <= NbfTwentyMillisecondsTicks)) {
+ continue;
+ }
+
+ NbfReferenceConnection ("ScanShortTimersDpc", Connection, CREF_DATA_ACK_QUEUE);
+
+ DeviceContext->DataAckQueueChanged = FALSE;
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ //
+ // Check the correct connection flag, to ensure that a
+ // send has not just taken him off the queue.
+ //
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ if (((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_ACK) != 0) &&
+ ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_NOT_Q) == 0)) {
+
+ //
+ // Yes, we were waiting to piggyback an ack, but no send
+ // has come along. Turn off the flags and send an ack.
+ //
+ // We have to ensure we nest the spin lock acquisition
+ // correctly.
+ //
+
+ Connection->DeferredFlags &= ~CONNECTION_FLAGS_DEFERRED_ACK;
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ INCREMENT_COUNTER (DeviceContext, PiggybackAckTimeouts);
+
+#if DBG
+ if (NbfDebugPiggybackAcks) {
+ NbfPrint0("T");
+ }
+#endif
+
+ NbfSendDataAck (Connection);
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ }
+
+ NbfDereferenceConnection ("ScanShortTimersDpc", Connection, CREF_DATA_ACK_QUEUE);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ //
+ // If the list has changed, then we need to stop processing
+ // since p->Flink is not valid.
+ //
+
+ if (DeviceContext->DataAckQueueChanged) {
+ break;
+ }
+
+ }
+
+ if (IsListEmpty (&DeviceContext->DataAckQueue)) {
+ DeviceContext->a.i.DataAckQueueActive = FALSE;
+ }
+
+#if 0
+
+ //
+ // NOTE: This is currently disabled, it may be reenabled
+ // at some point - adamba 9/1/92
+ //
+ // If the adaptive purge timer has expired, then run the purge
+ // algorithm on all affected links.
+ //
+
+ if (DeviceContext->ShortAbsoluteTime > DeviceContext->AdaptivePurge) {
+ DeviceContext->AdaptivePurge = DeviceContext->ShortAbsoluteTime +
+ TIMER_PURGE_TICKS;
+ ExpirePurgeTimer (DeviceContext);
+ }
+#endif
+
+ //
+ // deferred processing. We will handle all link structure additions and
+ // deletions here; we must be the exclusive user of the link tree to do
+ // this. We verify that we are by examining the semaphore that tells us
+ // how many readers of the tree are curretly processing it. If there are
+ // any readers, we simply increment our "deferred processing locked out"
+ // counter and do something else. If we defer too many times, we simply
+ // bugcheck, as something is wrong somewhere in the system.
+ //
+
+ if (!IsListEmpty (&DeviceContext->LinkDeferred)) {
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ //
+ // now do additions or deletions if we can.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ while (!IsListEmpty (&DeviceContext->LinkDeferred)) {
+ p = RemoveHeadList (&DeviceContext->LinkDeferred);
+ DeviceContext->DeferredNotSatisfied = 0;
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ //
+ // now do an addition or deletion if we can.
+ //
+
+ Link = CONTAINING_RECORD (p, TP_LINK, DeferredList);
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint4 ("ScanShortTimersDPC: link off deferred queue %lx %lx %lx Flags: %lx \n",
+ Link, DeviceContext->LinkDeferred.Flink,
+ DeviceContext->LinkDeferred.Blink, Link->DeferredFlags);
+ }
+ Link->DeferredList.Flink = Link->DeferredList.Blink =
+ &Link->DeferredList;
+
+ if ((Link->DeferredFlags & LINK_FLAGS_DEFERRED_MASK) == 0) {
+ // Tried to do an operation we don't understand; whine.
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint2 ("ScanTimerDPC: Attempting deferred operation on nothing! \nScanTimerDPC: Link: %lx, DeviceContext->DeferredQueue: %lx\n",
+ Link, &DeviceContext->LinkDeferred);
+ DbgBreakPoint ();
+ }
+ InitializeListHead (&DeviceContext->LinkDeferred);
+ // We could have a hosed deferred operations queue here;
+ // BUGBUG: take some time to figure out if it is ok.
+
+ }
+
+ if ((Link->DeferredFlags & LINK_FLAGS_DEFERRED_ADD) != 0) {
+
+ Link->DeferredFlags &= ~LINK_FLAGS_DEFERRED_ADD;
+
+ if ((Link->DeferredFlags & LINK_FLAGS_DEFERRED_DELETE) != 0) {
+
+ //
+ // It is being added and deleted; just destroy it.
+ //
+ Link->DeferredFlags &= ~LINK_FLAGS_DEFERRED_DELETE;
+ NbfDestroyLink (Link);
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint1 ("ScanTimerDPC: deferred processing: Add AND Delete link: %lx\n",Link);
+ }
+
+ } else {
+
+ NbfAddLinkToTree (DeviceContext, Link);
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint1 ("ScanTimerDPC: deferred processing: Added link to tree: %lx\n",Link);
+ }
+
+ }
+
+ } else if ((Link->DeferredFlags & LINK_FLAGS_DEFERRED_DELETE) != 0) {
+ Link->DeferredFlags &= ~LINK_FLAGS_DEFERRED_DELETE;
+ NbfRemoveLinkFromTree (DeviceContext, Link);
+ NbfDestroyLink (Link);
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint1 ("ScanTimerDPC: deferred processing: returning link %lx to LinkPool.\n", Link);
+ }
+
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+ }
+
+ InitializeListHead (&DeviceContext->LinkDeferred);
+
+ DeviceContext->a.i.LinkDeferredActive = FALSE;
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ }
+
+
+ //
+ // Update the real counters from the temp ones.
+ //
+
+ ADD_TO_LARGE_INTEGER(
+ &DeviceContext->Statistics.DataFrameBytesSent,
+ DeviceContext->TempIFrameBytesSent);
+ DeviceContext->Statistics.DataFramesSent += DeviceContext->TempIFramesSent;
+
+ DeviceContext->TempIFrameBytesSent = 0;
+ DeviceContext->TempIFramesSent = 0;
+
+ ADD_TO_LARGE_INTEGER(
+ &DeviceContext->Statistics.DataFrameBytesReceived,
+ DeviceContext->TempIFrameBytesReceived);
+ DeviceContext->Statistics.DataFramesReceived += DeviceContext->TempIFramesReceived;
+
+ DeviceContext->TempIFrameBytesReceived = 0;
+ DeviceContext->TempIFramesReceived = 0;
+
+
+ //
+ // Determine if we have to restart the timer.
+ //
+
+ DeviceContext->ProcessingShortTimer = FALSE;
+
+ if (DeviceContext->a.AnyActive &&
+ (DeviceContext->State != DEVICECONTEXT_STATE_STOPPING)) {
+
+ RestartTimer = TRUE;
+
+ }
+
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ if (RestartTimer) {
+
+ //
+ // Start up the timer again. Note that because we start the timer
+ // after doing work (above), the timer values will slip somewhat,
+ // depending on the load on the protocol. This is entirely acceptable
+ // and will prevent us from using the timer DPC in two different
+ // threads of execution.
+ //
+
+ KeQueryTickCount(&DeviceContext->ShortTimerStart);
+ KeSetTimer (
+ &DeviceContext->ShortSystemTimer,
+ DueTimeDelta,
+ &DeviceContext->ShortTimerSystemDpc);
+
+ } else {
+
+#if DBG
+ if (NbfDebugShortTimer) {
+ DbgPrint("x");
+ }
+#endif
+ NbfDereferenceDeviceContext ("Don't restart short timer", DeviceContext, DCREF_SCAN_TIMER);
+
+ }
+
+
+ LEAVE_NBF;
+ return;
+
+} /* ScanShortTimersDpc */
+
+
+VOID
+ScanLongTimersDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called at DISPATCH_LEVEL by the system at regular
+ intervals to determine if any long timers have expired, and
+ if they have, to execute their expiration routines.
+
+Arguments:
+
+ DeferredContext - Pointer to our DEVICE_CONTEXT object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LARGE_INTEGER DueTime;
+ PLIST_ENTRY p, nextp;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_LINK Link;
+ PTP_CONNECTION Connection;
+
+ Dpc, SystemArgument1, SystemArgument2; // prevent compiler warnings
+
+ ENTER_NBF;
+
+ IF_NBFDBG (NBF_DEBUG_TIMERDPC) {
+ NbfPrint0 ("ScanLongTimersDpc: Entered.\n");
+ }
+
+ DeviceContext = DeferredContext;
+
+ //
+ // Advance the up-counter used to mark time in LONG_TIMER_DELTA units. If we
+ // advance it all the way to 0xf0000000, then reset it to 0x10000000.
+ // We also run all the lists, decreasing all counters by 0xe0000000.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ if (++DeviceContext->LongAbsoluteTime == 0xf0000000) {
+
+ ULONG Timeout;
+
+ DeviceContext->LongAbsoluteTime = 0x10000000;
+
+ p = DeviceContext->LongList.Flink;
+ while (p != &DeviceContext->LongList) {
+
+ Link = CONTAINING_RECORD (p, TP_LINK, LongList);
+
+ Timeout = Link->Ti;
+ if (Timeout) {
+ Link->Ti = Timeout - 0xe0000000;
+ }
+
+ p = p->Flink;
+ }
+
+ }
+
+ //
+ // now, as the timers are started, links are added to the end of the
+ // respective queue for that timer. since we know the additions are
+ // done in an orderly fashion and are sequential, we must only traverse
+ // a particular timer list to the first entry that is greater than our
+ // timer. That entry and all further entries will not need service.
+ // When a timer is cancelled, we remove the link from the list. With all
+ // of this fooling around, we wind up only visiting those links that are
+ // actually in danger of timing out, minimizing time in this routine.
+ //
+
+
+ //
+ // Ti timers. This is the inactivity timer for the link, used when no
+ // activity has occurred on the link in some time. We only check this
+ // every four expirations of the timer since the granularity is usually
+ // in the 30 second range.
+ // NOTE: DeviceContext->TimerSpinLock is held here.
+ //
+
+ if ((DeviceContext->LongAbsoluteTime % 4) == 0) {
+
+ p = DeviceContext->LongList.Flink;
+ while (p != &DeviceContext->LongList) {
+
+ Link = CONTAINING_RECORD (p, TP_LINK, LongList);
+
+ ASSERT (Link->OnLongList);
+
+ //
+ // To avoid problems with the refcount being 0, don't
+ // do this if we are in ADM.
+ //
+
+#if DBG
+ if (Link->SendState == SEND_STATE_REJECTING) {
+ NbfPrint0 ("Timer: link state == rejecting, shouldn't be\n");
+ }
+#endif
+
+ if (Link->State != LINK_STATE_ADM) {
+
+ if (Link->Ti && (DeviceContext->LongAbsoluteTime > Link->Ti)) {
+
+ Link->Ti = 0;
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ ExpireTiTimer (Link); // no spinlocks held
+ ++DeviceContext->TiExpirations;
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ }
+
+ }
+
+ if (!Link->OnLongList) {
+
+ //
+ // The link has been taken out of the list while
+ // we were processing it. In this (rare) case we
+ // stop processing the whole list, we'll get it
+ // next time.
+ //
+
+#if DBG
+ DbgPrint ("NBF: Stop processing LongList, %lx removed\n", Link);
+#endif
+ break;
+
+ }
+
+ nextp = p->Flink;
+
+ if (Link->Ti == 0) {
+
+ Link->OnLongList = FALSE;
+ RemoveEntryList(p);
+
+ if (Link->Ti != 0) {
+ InsertTailList(&DeviceContext->LongList, &Link->LongList);
+ Link->OnLongList = TRUE;
+ }
+
+ }
+
+ p = nextp;
+
+ }
+
+ }
+
+
+ //
+ // Now scan the data ack queue, looking for connections with
+ // no acks queued that we can get rid of.
+ //
+ // Note: The timer spinlock is held here.
+ //
+
+ p = DeviceContext->DataAckQueue.Flink;
+
+ while (p != &DeviceContext->DataAckQueue &&
+ !DeviceContext->DataAckQueueChanged) {
+
+ Connection = CONTAINING_RECORD (DeviceContext->DataAckQueue.Flink, TP_CONNECTION, DataAckLinkage);
+
+ if ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_ACK) != 0) {
+ p = p->Flink;
+ continue;
+ }
+
+ NbfReferenceConnection ("ScanShortTimersDpc", Connection, CREF_DATA_ACK_QUEUE);
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ //
+ // Have to check again, because the connection might
+ // just have been stopped.
+ //
+
+ if (Connection->OnDataAckQueue) {
+ Connection->OnDataAckQueue = FALSE;
+
+ RemoveEntryList (&Connection->DataAckLinkage);
+
+ if ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_ACK) != 0) {
+ InsertTailList (&DeviceContext->DataAckQueue, &Connection->DataAckLinkage);
+ Connection->OnDataAckQueue = TRUE;
+ }
+
+ DeviceContext->DataAckQueueChanged = TRUE;
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ NbfDereferenceConnection ("ScanShortTimersDpc", Connection, CREF_DATA_ACK_QUEUE);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ //
+ // Since we have changed the list, we can't tell if p->Flink
+ // is valid, so break. The effect is that we gradually peel
+ // connections off the queue.
+ //
+
+ break;
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+
+ //
+ // See if we got any multicast traffic last time.
+ //
+
+ if (DeviceContext->MulticastPacketCount == 0) {
+
+ ++DeviceContext->LongTimeoutsWithoutMulticast;
+
+ if (DeviceContext->EasilyDisconnected &&
+ (DeviceContext->LongTimeoutsWithoutMulticast > 5)) {
+
+ PLIST_ENTRY p;
+ PTP_ADDRESS address;
+
+ //
+ // We have had five timeouts in a row with no
+ // traffic, mark all the addresses as needing
+ // reregistration next time a connect is
+ // done on them.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ for (p = DeviceContext->AddressDatabase.Flink;
+ p != &DeviceContext->AddressDatabase;
+ p = p->Flink) {
+
+ address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+ address->Flags |= ADDRESS_FLAGS_NEED_REREGISTER;
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ DeviceContext->LongTimeoutsWithoutMulticast = 0;
+
+ }
+
+ } else {
+
+ DeviceContext->LongTimeoutsWithoutMulticast = 0;
+
+ }
+
+ DeviceContext->MulticastPacketCount = 0;
+
+
+ //
+ // Every thirty seconds, check for stalled connections
+ //
+
+ ++DeviceContext->StalledConnectionCount;
+
+ if (DeviceContext->StalledConnectionCount ==
+ (USHORT)((30 * SECONDS) / LONG_TIMER_DELTA)) {
+
+ DeviceContext->StalledConnectionCount = 0;
+ StopStalledConnections (DeviceContext);
+
+ }
+
+
+ //
+ // Scan for any uncompleted receive IRPs, this may happen if
+ // the cable is pulled and we don't get any more ReceiveComplete
+ // indications.
+
+ NbfReceiveComplete((NDIS_HANDLE)DeviceContext);
+
+
+ //
+ // Start up the timer again. Note that because we start the timer
+ // after doing work (above), the timer values will slip somewhat,
+ // depending on the load on the protocol. This is entirely acceptable
+ // and will prevent us from using the timer DPC in two different
+ // threads of execution.
+ //
+
+ if (DeviceContext->State != DEVICECONTEXT_STATE_STOPPING) {
+ DueTime.HighPart = -1;
+ DueTime.LowPart = (ULONG)-(LONG_TIMER_DELTA); // delta time to next click.
+ KeSetTimer (
+ &DeviceContext->LongSystemTimer,
+ DueTime,
+ &DeviceContext->LongTimerSystemDpc);
+ } else {
+ NbfDereferenceDeviceContext ("Don't restart long timer", DeviceContext, DCREF_SCAN_TIMER);
+ }
+
+ LEAVE_NBF;
+ return;
+
+} /* ScanLongTimersDpc */
+
+
+VOID
+StopStalledConnections(
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from ScanLongTimersDpc every 30 seconds.
+ It checks for connections that have not made any progress in
+ their sends in the last two minutes, and stops them.
+
+Arguments:
+
+ DeviceContext - The device context to check.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PTP_ADDRESS Address, PrevAddress;
+ PTP_CONNECTION Connection, StalledConnection;
+ PLIST_ENTRY p, q;
+
+
+ //
+ // If we have crossed a thirty-second interval, then
+ // check each address for connections that have not
+ // made any progress in two minutes.
+ //
+
+ PrevAddress = NULL;
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ for (p = DeviceContext->AddressDatabase.Flink;
+ p != &DeviceContext->AddressDatabase;
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (
+ p,
+ TP_ADDRESS,
+ Linkage);
+
+ if ((Address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ continue;
+ }
+
+ //
+ // By referencing the address, we ensure that it will stay
+ // in the AddressDatabase, this its Flink will stay valid.
+ //
+
+ NbfReferenceAddress("checking for dead connections", Address, AREF_TIMER_SCAN);
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ if (PrevAddress) {
+ NbfDereferenceAddress ("done checking", PrevAddress, AREF_TIMER_SCAN);
+ }
+
+ //
+ // Scan this addresses connection database for connections
+ // that have not made progress in the last two minutes; we
+ // kill the first one we find.
+ //
+
+ StalledConnection = NULL;
+
+ ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ for (q = Address->ConnectionDatabase.Flink;
+ q != &Address->ConnectionDatabase;
+ q = q->Flink) {
+
+ Connection = CONTAINING_RECORD (q, TP_CONNECTION, AddressList);
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ if (!IsListEmpty (&Connection->SendQueue)) {
+
+ //
+ // If there is a connection on the queue...
+ //
+
+ if (Connection->StallBytesSent == Connection->sp.MessageBytesSent) {
+
+ //
+ // ...and it has not made any progress...
+ //
+
+ if (Connection->StallCount >= 4) {
+
+ //
+ // .. four times in a row, the connection is dead.
+ //
+
+ if (!StalledConnection) {
+ StalledConnection = Connection;
+ NbfReferenceConnection ("stalled", Connection, CREF_STALLED);
+ }
+#if DBG
+ DbgPrint ("NBF: Found connection %lx [%d for %d] stalled on %lx\n",
+ Connection, Connection->StallBytesSent, Connection->StallCount, Address);
+#endif
+
+ } else {
+
+ //
+ // If it is stuck, increment the count.
+ //
+
+ ++Connection->StallCount;
+
+ }
+
+ } else {
+
+ Connection->StallBytesSent = Connection->sp.MessageBytesSent;
+
+ }
+
+ }
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ if (StalledConnection) {
+
+ PTP_LINK Link = StalledConnection->Link;
+
+#if DBG
+ DbgPrint("NBF: Stopping stalled connection %lx, link %lx\n", StalledConnection, Link);
+#endif
+
+ FailSend (StalledConnection, STATUS_IO_TIMEOUT, TRUE); // fail the send
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ if (Link->State == LINK_STATE_READY) {
+ CancelT1Timeout (Link);
+ Link->State = LINK_STATE_W_DISC_RSP;
+ Link->SendState = SEND_STATE_DOWN;
+ Link->ReceiveState = RECEIVE_STATE_DOWN;
+ Link->SendRetries = (UCHAR)Link->LlcRetries;
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ NbfStopLink (Link);
+ StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME)); // retransmit timer.
+ NbfSendDisc (Link, TRUE); // send DISC-c/p.
+ } else {
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ NbfStopLink (Link);
+ }
+
+ NbfDereferenceConnection ("stalled", StalledConnection, CREF_STALLED);
+
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ PrevAddress = Address;
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ if (PrevAddress) {
+ NbfDereferenceAddress ("done checking", PrevAddress, AREF_TIMER_SCAN);
+ }
+
+} /* StopStalledConnections */
+
+
+VOID
+NbfStartShortTimer(
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the short timer, if it is not already running.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ //
+ // Start the timer unless it the DPC is already running (in
+ // which case it will restart the timer itself if needed),
+ // or some list is active (meaning the timer is already
+ // queued up).
+ //
+ // We use a trick to check all four active lists at the
+ // same time, but this depends on some alignment and
+ // size assumptions.
+ //
+
+ ASSERT (sizeof(ULONG) >= 3 * sizeof(BOOLEAN));
+ ASSERT ((PVOID)&DeviceContext->a.AnyActive ==
+ (PVOID)&DeviceContext->a.i.ShortListActive);
+
+ StartTimer++;
+
+ if ((!DeviceContext->ProcessingShortTimer) &&
+ (!(DeviceContext->a.AnyActive))) {
+
+#if DBG
+ if (NbfDebugShortTimer) {
+ DbgPrint("X");
+ }
+#endif
+
+ NbfReferenceDeviceContext ("Start short timer", DeviceContext, DCREF_SCAN_TIMER);
+
+ KeQueryTickCount(&DeviceContext->ShortTimerStart);
+ StartTimerSet++;
+ KeSetTimer (
+ &DeviceContext->ShortSystemTimer,
+ DueTimeDelta,
+ &DeviceContext->ShortTimerSystemDpc);
+
+ }
+
+} /* NbfStartShortTimer */
+
+
+VOID
+NbfInitializeTimerSystem(
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the lightweight timer system for the transport
+ provider.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LARGE_INTEGER DueTime;
+
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("NbfInitializeTimerSystem: Entered.\n");
+ }
+
+ //
+ // Set these up.
+ //
+
+ NbfTickIncrement = KeQueryTimeIncrement();
+
+ if (NbfTickIncrement > (20 * MILLISECONDS)) {
+ NbfTwentyMillisecondsTicks = 1;
+ } else {
+ NbfTwentyMillisecondsTicks = (20 * MILLISECONDS) / NbfTickIncrement;
+ }
+
+ if (NbfTickIncrement > (SHORT_TIMER_DELTA)) {
+ NbfShortTimerDeltaTicks = 1;
+ } else {
+ NbfShortTimerDeltaTicks = (SHORT_TIMER_DELTA) / NbfTickIncrement;
+ }
+
+ //
+ // MaximumIntervalTicks represents 60 seconds, unless the value
+ // when shifted out by the accuracy required is too big.
+ //
+
+ if ((((ULONG)0xffffffff) >> (DLC_TIMER_ACCURACY+2)) > ((60 * SECONDS) / NbfTickIncrement)) {
+ NbfMaximumIntervalTicks = (60 * SECONDS) / NbfTickIncrement;
+ } else {
+ NbfMaximumIntervalTicks = ((ULONG)0xffffffff) >> (DLC_TIMER_ACCURACY + 2);
+ }
+
+ //
+ // The AbsoluteTime cycles between 0x10000000 and 0xf0000000.
+ //
+
+ DeviceContext->ShortAbsoluteTime = 0x10000000; // initialize our timer click up-counter.
+ DeviceContext->LongAbsoluteTime = 0x10000000; // initialize our timer click up-counter.
+
+ DeviceContext->AdaptivePurge = TIMER_PURGE_TICKS;
+
+ DeviceContext->MulticastPacketCount = 0;
+ DeviceContext->LongTimeoutsWithoutMulticast = 0;
+
+ KeInitializeDpc(
+ &DeviceContext->ShortTimerSystemDpc,
+ ScanShortTimersDpc,
+ DeviceContext);
+
+ KeInitializeDpc(
+ &DeviceContext->LongTimerSystemDpc,
+ ScanLongTimersDpc,
+ DeviceContext);
+
+ KeInitializeTimer (&DeviceContext->ShortSystemTimer);
+
+ KeInitializeTimer (&DeviceContext->LongSystemTimer);
+
+ DueTime.HighPart = -1;
+ DueTime.LowPart = (ULONG)-(LONG_TIMER_DELTA);
+
+ //
+ // One reference for the long timer.
+ //
+
+ NbfReferenceDeviceContext ("Long timer active", DeviceContext, DCREF_SCAN_TIMER);
+
+ KeSetTimer (
+ &DeviceContext->LongSystemTimer,
+ DueTime,
+ &DeviceContext->LongTimerSystemDpc);
+
+ DeviceContext->TimersInitialized = TRUE;
+
+} /* NbfInitializeTimerSystem */
+
+
+VOID
+NbfStopTimerSystem(
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stops the lightweight timer system for the transport
+ provider.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ //
+ // For now we ignore what happens if the timer is currently
+ // running when we do this.
+ //
+
+ if (DeviceContext->TimersInitialized) {
+
+ if (KeCancelTimer(
+ &DeviceContext->LongSystemTimer)) {
+ NbfDereferenceDeviceContext ("Long timer cancelled", DeviceContext, DCREF_SCAN_TIMER);
+ }
+
+ if (KeCancelTimer(
+ &DeviceContext->ShortSystemTimer)) {
+ NbfDereferenceDeviceContext ("Short timer cancelled", DeviceContext, DCREF_SCAN_TIMER);
+ }
+
+ }
+
+}
diff --git a/private/ntos/tdi/nbf/uframes.c b/private/ntos/tdi/nbf/uframes.c
new file mode 100644
index 000000000..654f92ff6
--- /dev/null
+++ b/private/ntos/tdi/nbf/uframes.c
@@ -0,0 +1,2974 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ uframes.c
+
+Abstract:
+
+ This module contains a routine called NbfProcessUi, that gets control
+ from routines in DLC.C when a DLC UI frame is received. Here we
+ decode the encapsulated connectionless NetBIOS frame and dispatch
+ to the correct NetBIOS frame handler.
+
+ The following frame types are cracked by routines in this module:
+
+ o NBF_CMD_ADD_GROUP_NAME_QUERY
+ o NBF_CMD_ADD_NAME_QUERY
+ o NBF_CMD_NAME_IN_CONFLICT
+ o NBF_CMD_STATUS_QUERY
+ o NBF_CMD_TERMINATE_TRACE
+ o NBF_CMD_DATAGRAM
+ o NBF_CMD_DATAGRAM_BROADCAST
+ o NBF_CMD_NAME_QUERY
+ o NBF_CMD_ADD_NAME_RESPONSE
+ o NBF_CMD_NAME_RECOGNIZED
+ o NBF_CMD_STATUS_RESPONSE
+ o NBF_CMD_TERMINATE_TRACE2
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode, DISPATCH_LEVEL.
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+
+VOID
+NbfListenTimeout(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is executed as a DPC at DISPATCH_LEVEL when the timeout
+ period for the session setup after listening a connection occurs. This
+ will occur if the remote has discovered our name and we do not get a
+ connection started within some reasonable period of time. In this
+ routine we simply tear down the connection (and, most likely, the link
+ associated with it).
+
+Arguments:
+
+ Dpc - Pointer to a system DPC object.
+
+ DeferredContext - Pointer to the TP_CONNECTION block representing the
+ request that has timed out.
+
+ SystemArgument1 - Not used.
+
+ SystemArgument2 - Not used.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PTP_CONNECTION Connection;
+
+ Dpc, SystemArgument1, SystemArgument2; // prevent compiler warnings
+
+ ENTER_NBF;
+
+ Connection = (PTP_CONNECTION)DeferredContext;
+
+ //
+ // If this connection is being run down, then we can't do anything.
+ //
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) ||
+ ((Connection->Flags & CONNECTION_FLAGS_WAIT_SI) == 0)) {
+
+ //
+ // The connection is stopping, or the SESSION_INITIALIZE
+ // has already been processed.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint1 ("ListenTimeout: connection %lx stopping.\n",
+ Connection);
+ }
+
+ NbfDereferenceConnection ("Listen timeout, ignored", Connection, CREF_TIMER);
+ LEAVE_NBF;
+ return;
+ }
+
+ //
+ // We connected to the link before sending the NAME_RECOGNIZED,
+ // so we disconnect from it now.
+ //
+
+#if DBG
+ if (NbfDisconnectDebug) {
+ STRING remoteName, localName;
+ remoteName.Length = NETBIOS_NAME_LENGTH - 1;
+ remoteName.Buffer = Connection->RemoteName;
+ localName.Length = NETBIOS_NAME_LENGTH - 1;
+ localName.Buffer = Connection->AddressFile->Address->NetworkName->NetbiosName;
+ NbfPrint2( "NbfListenTimeout disconnecting connection to %S from %S\n",
+ &remoteName, &localName );
+ }
+#endif
+
+ //
+ // BUBGUG: This is really ugly and I doubt it is correct.
+ //
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_ACCEPTED) != 0) {
+
+ //
+ // This connection is up, we stop it.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint1 ("ListenTimeout: connection %lx, accepted.\n",
+ Connection);
+ }
+
+ //
+ // Set this so that the client will get a disconnect
+ // indication.
+ //
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ NbfStopConnection (Connection, STATUS_IO_TIMEOUT);
+
+ } else if (Connection->Link != (PTP_LINK)NULL) {
+
+ //
+ // This connection is from a listen...we want to
+ // silently reset the listen.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint1 ("ListenTimeout: connection %lx, listen restarted.\n",
+ Connection);
+ }
+
+ Connection->Flags &= ~CONNECTION_FLAGS_WAIT_SI;
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_REMOTE_VALID;
+ Connection->Flags2 |= CONNECTION_FLAGS2_WAIT_NQ;
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ NbfDereferenceConnection ("Timeout", Connection, CREF_LINK);
+ (VOID)NbfDisconnectFromLink (Connection, FALSE);
+
+ } else {
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint1 ("ListenTimeout: connection %lx, link down.\n",
+ Connection);
+ }
+
+ }
+
+
+ NbfDereferenceConnection("Listen Timeout", Connection, CREF_TIMER);
+
+ LEAVE_NBF;
+ return;
+
+} /* ListenTimeout */
+
+
+NTSTATUS
+ProcessAddGroupNameQuery(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address,
+ IN PNBF_HDR_CONNECTIONLESS Header,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an incoming ADD_GROUP_NAME_QUERY frame. Because
+ our caller has already verified that the destination name in the frame
+ matches the transport address passed to us, we must simply transmit an
+ ADD_NAME_RESPONSE frame and exit with STATUS_ABANDONED.
+
+ When we return STATUS_MORE_PROCESSING_REQUIRED, the caller of
+ this routine will continue to call us for each address for the device
+ context. When we return STATUS_SUCCESS, the caller will switch to the
+ next address.
+ When we return any other status code, including STATUS_ABANDONED, the
+ caller will stop distributing the frame.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ Address - Pointer to the transport address object.
+
+ Header - Pointer to the connectionless NetBIOS header of the frame.
+
+ SourceAddress - Pointer to the source hardware address in the received
+ frame.
+
+ SourceRouting - Pointer to the source routing information in
+ the frame.
+
+ SourceRoutingLength - Length of the source routing information.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_UI_FRAME RawFrame; // ptr to allocated connectionless frame.
+ UINT HeaderLength;
+ UCHAR TempSR[MAX_SOURCE_ROUTING];
+ PUCHAR ResponseSR;
+
+ UNREFERENCED_PARAMETER (SourceAddress);
+ UNREFERENCED_PARAMETER (Address);
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessAddGroupNameQuery %lx: [%.16s].\n", Address, Header->DestinationName);
+ }
+
+ //
+ // Allocate a UI frame from the pool.
+ //
+
+ if (NbfCreateConnectionlessFrame (DeviceContext, &RawFrame) != STATUS_SUCCESS) {
+ return STATUS_ABANDONED; // no resources to do this.
+ }
+
+
+ //
+ // Build the MAC header. ADD_NAME_RESPONSE frames go out as
+ // non-broadcast source routing.
+ //
+
+ if (SourceRouting != NULL) {
+
+ RtlCopyMemory(
+ TempSR,
+ SourceRouting,
+ SourceRoutingLength);
+
+ MacCreateNonBroadcastReplySR(
+ &DeviceContext->MacInfo,
+ TempSR,
+ SourceRoutingLength,
+ &ResponseSR);
+
+ } else {
+
+ ResponseSR = NULL;
+
+ }
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ RawFrame->Header,
+ SourceAddress->Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS),
+ ResponseSR,
+ SourceRoutingLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // Build the Netbios header.
+ //
+
+ ConstructAddNameResponse (
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ NETBIOS_NAME_TYPE_UNIQUE, // type of name is UNIQUE.
+ RESPONSE_CORR(Header), // correlator from rec'd frame.
+ (PUCHAR)Header->SourceName); // NetBIOS name being responded to.
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+
+
+ //
+ // Munge the packet length and send it.
+ //
+
+ NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ FALSE); // no loopback.
+
+ return STATUS_ABANDONED; // don't forward frame to other addr's.
+} /* ProcessAddGroupNameQuery */
+
+
+NTSTATUS
+ProcessAddNameQuery(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address,
+ IN PNBF_HDR_CONNECTIONLESS Header,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an incoming ADD_NAME_QUERY frame. Because
+ our caller has already verified that the destination name in the frame
+ matches the transport address passed to us, we must simply transmit an
+ ADD_NAME_RESPONSE frame and exit with STATUS_ABANDONED.
+
+ When we return STATUS_MORE_PROCESSING_REQUIRED, the caller of
+ this routine will continue to call us for each address for the device
+ context. When we return STATUS_SUCCESS, the caller will switch to the
+ next address. When we return any other status code, including
+ STATUS_ABANDONED, the caller will stop distributing the frame.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ Address - Pointer to the transport address object.
+
+ Header - Pointer to the connectionless NetBIOS header of the frame.
+
+ SourceAddress - Pointer to the source hardware address in the received
+ frame.
+
+ SourceRouting - Pointer to the source routing information in
+ the frame.
+
+ SourceRoutingLength - Length of the source routing information.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_UI_FRAME RawFrame; // ptr to allocated connectionless frame.
+ UINT HeaderLength;
+ UCHAR TempSR[MAX_SOURCE_ROUTING];
+ PUCHAR ResponseSR;
+
+ Address, SourceAddress; // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessAddNameQuery %lx: [%.16s].\n", Address, Header->DestinationName);
+ }
+
+ //
+ // Allocate a UI frame from the pool.
+ //
+
+ if (NbfCreateConnectionlessFrame (DeviceContext, &RawFrame) != STATUS_SUCCESS) {
+ return STATUS_ABANDONED; // no resources to do this.
+ }
+
+
+ //
+ // Build the MAC header. ADD_NAME_RESPONSE frames go out as
+ // non-broadcast source routing.
+ //
+
+ if (SourceRouting != NULL) {
+
+ RtlCopyMemory(
+ TempSR,
+ SourceRouting,
+ SourceRoutingLength);
+
+ MacCreateNonBroadcastReplySR(
+ &DeviceContext->MacInfo,
+ TempSR,
+ SourceRoutingLength,
+ &ResponseSR);
+
+ } else {
+
+ ResponseSR = NULL;
+
+ }
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ RawFrame->Header,
+ SourceAddress->Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS),
+ ResponseSR,
+ SourceRoutingLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // Build the Netbios header.
+ //
+
+ ConstructAddNameResponse (
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ NETBIOS_NAME_TYPE_UNIQUE, // type of name is UNIQUE.
+ RESPONSE_CORR(Header), // correlator from received frame.
+ (PUCHAR)Header->SourceName); // NetBIOS name being responded to
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+
+
+ //
+ // Munge the packet length and send it.
+ //
+
+ NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ FALSE); // no loopback.
+
+ return STATUS_ABANDONED; // don't forward frame to other addr's.
+} /* ProcessAddNameQuery */
+
+
+NTSTATUS
+ProcessNameInConflict(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address,
+ IN PNBF_HDR_CONNECTIONLESS Header,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an incoming NAME_IN_CONFLICT frame.
+ Although we can't disrupt any traffic on this address, it is considered
+ invalid and cannot be used for any new address files or new connections.
+ Therefore, we just mark the address as invalid.
+
+ When we return STATUS_MORE_PROCESSING_REQUIRED, the caller of
+ this routine will continue to call us for each address for the device
+ context. When we return STATUS_SUCCESS, the caller will switch to the
+ next address. When we return any other status code, including
+ STATUS_ABANDONED, the caller will stop distributing the frame.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ Address - Pointer to the transport address object.
+
+ Header - Pointer to the connectionless NetBIOS header of the frame.
+
+ SourceAddress - Pointer to the source hardware address in the received
+ frame.
+
+ SourceRouting - Pointer to the source routing information in
+ the frame.
+
+ SourceRoutingLength - Length of the source routing information.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ DeviceContext, Header, SourceAddress; // prevent compiler warnings
+
+
+ //
+ // Ignore this if we are registering/deregistering (the name will
+ // go away anyway) or if we have already marked this name as
+ // in conflict and logged an error.
+ //
+
+ if (Address->Flags & (ADDRESS_FLAGS_REGISTERING | ADDRESS_FLAGS_DEREGISTERING | ADDRESS_FLAGS_CONFLICT)) {
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessNameInConflict %lx: address marked [%.16s].\n", Address, Header->SourceName);
+ }
+ return STATUS_ABANDONED;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessNameInConflict %lx: [%.16s].\n", Address, Header->SourceName);
+ }
+
+#if 0
+ ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ Address->Flags |= ADDRESS_FLAGS_CONFLICT;
+
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ DbgPrint ("NBF: Name-in-conflict on <%.16s> from ", Header->DestinationName);
+ DbgPrint ("%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ SourceAddress->Address[0],
+ SourceAddress->Address[1],
+ SourceAddress->Address[2],
+ SourceAddress->Address[3],
+ SourceAddress->Address[4],
+ SourceAddress->Address[5]);
+#endif
+
+ NbfWriteGeneralErrorLog(
+ Address->Provider,
+ EVENT_TRANSPORT_BAD_PROTOCOL,
+ 2,
+ STATUS_DUPLICATE_NAME,
+ L"NAME_IN_CONFLICT",
+ 16/sizeof(ULONG),
+ (PULONG)(Header->DestinationName));
+
+ return STATUS_ABANDONED;
+
+} /* ProcessNameInConflict */
+
+
+NTSTATUS
+NbfIndicateDatagram(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address,
+ IN PUCHAR Dsdu,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an incoming DATAGRAM or DATAGRAM_BROADCAST frame.
+ BROADCAST and normal datagrams have the same receive logic, except
+ for broadcast datagrams Address will be the broadcast address.
+
+ When we return STATUS_MORE_PROCESSING_REQUIRED, the caller of
+ this routine will continue to call us for each address for the device
+ context. When we return STATUS_SUCCESS, the caller will switch to the
+ next address. When we return any other status code, including
+ STATUS_ABANDONED, the caller will stop distributing the frame.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ Address - Pointer to the transport address object.
+
+ Dsdu - Pointer to a Mdl buffer that contains the received datagram.
+ The first byte of information in the buffer is the first byte in
+ the NetBIOS connectionless header, and it is already negotiated that
+ the data link layer will provide at least the entire NetBIOS header
+ as contiguous data.
+
+ Length - The length of the MDL pointed to by Dsdu.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PLIST_ENTRY p, q;
+ PIRP irp;
+ PIO_STACK_LOCATION irpSp;
+ ULONG IndicateBytesCopied, MdlBytesCopied, BytesToCopy;
+ TA_NETBIOS_ADDRESS SourceName;
+ TA_NETBIOS_ADDRESS DestinationName;
+ PTDI_CONNECTION_INFORMATION remoteInformation;
+ ULONG returnLength;
+ PTP_ADDRESS_FILE addressFile, prevaddressFile;
+ PTDI_CONNECTION_INFORMATION DatagramInformation;
+ TDI_ADDRESS_NETBIOS UNALIGNED * DatagramAddress;
+ PNBF_HDR_CONNECTIONLESS Header = (PNBF_HDR_CONNECTIONLESS)Dsdu;
+
+ IF_NBFDBG (NBF_DEBUG_DATAGRAMS) {
+ NbfPrint0 ("NbfIndicateDatagram: Entered.\n");
+ }
+
+ //
+ // If this datagram wasn't big enough for a transport header, then don't
+ // let the caller look at any data.
+ //
+
+ if (Length < sizeof(NBF_HDR_CONNECTIONLESS)) {
+ IF_NBFDBG (NBF_DEBUG_DATAGRAMS) {
+ NbfPrint0 ("NbfIndicateDatagram: Short datagram abandoned.\n");
+ }
+ return STATUS_ABANDONED;
+ }
+
+ //
+ // Update our statistics.
+ //
+
+ ++DeviceContext->Statistics.DatagramsReceived;
+ ADD_TO_LARGE_INTEGER(
+ &DeviceContext->Statistics.DatagramBytesReceived,
+ Length - sizeof(NBF_HDR_CONNECTIONLESS));
+
+
+ //
+ // Call the client's ReceiveDatagram indication handler. He may
+ // want to accept the datagram that way.
+ //
+
+ TdiBuildNetbiosAddress ((PUCHAR)Header->SourceName, FALSE, &SourceName);
+ TdiBuildNetbiosAddress ((PUCHAR)Header->DestinationName, FALSE, &DestinationName);
+
+
+ ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ //
+ // Find the first open address file in the list.
+ //
+
+ p = Address->AddressFileDatabase.Flink;
+ while (p != &Address->AddressFileDatabase) {
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+ if (addressFile->State != ADDRESSFILE_STATE_OPEN) {
+ p = p->Flink;
+ continue;
+ }
+ NbfReferenceAddressFile(addressFile);
+ break;
+ }
+
+ while (p != &Address->AddressFileDatabase) {
+
+ //
+ // do we have a datagram receive request outstanding? If so, we will
+ // satisfy it first. We run through the receive datagram queue
+ // until we find a datagram with no remote address or with
+ // this sender's address as its remote address.
+ //
+
+ for (q = addressFile->ReceiveDatagramQueue.Flink;
+ q != &addressFile->ReceiveDatagramQueue;
+ q = q->Flink) {
+
+ irp = CONTAINING_RECORD (q, IRP, Tail.Overlay.ListEntry);
+ DatagramInformation = ((PTDI_REQUEST_KERNEL_RECEIVEDG)
+ &((IoGetCurrentIrpStackLocation(irp))->
+ Parameters))->ReceiveDatagramInformation;
+
+ if (DatagramInformation &&
+ (DatagramInformation->RemoteAddress) &&
+ (DatagramAddress = NbfParseTdiAddress(DatagramInformation->RemoteAddress, FALSE)) &&
+ (!RtlEqualMemory(
+ Header->SourceName,
+ DatagramAddress->NetbiosName,
+ NETBIOS_NAME_LENGTH))) {
+ continue;
+ }
+ break;
+ }
+
+ if (q != &addressFile->ReceiveDatagramQueue) {
+ KIRQL cancelIrql;
+
+
+ RemoveEntryList (q);
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_DATAGRAMS) {
+ NbfPrint0 ("NbfIndicateDatagram: Receive datagram request found, copying.\n");
+ }
+
+ //
+ // Copy the actual user data.
+ //
+
+ MdlBytesCopied = 0;
+
+ BytesToCopy = Length - sizeof(NBF_HDR_CONNECTIONLESS);
+
+ if (BytesToCopy > 0) {
+ status = TdiCopyBufferToMdl (
+ Dsdu,
+ sizeof(NBF_HDR_CONNECTIONLESS), // offset
+ BytesToCopy, // length
+ irp->MdlAddress,
+ 0,
+ &MdlBytesCopied);
+ } else {
+ status = STATUS_SUCCESS;
+ }
+
+ //
+ // Copy the addressing information.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (irp);
+ remoteInformation =
+ ((PTDI_REQUEST_KERNEL_RECEIVEDG)(&irpSp->Parameters))->
+ ReturnDatagramInformation;
+ if (remoteInformation != NULL) {
+ try {
+ if (remoteInformation->RemoteAddressLength != 0) {
+ if (remoteInformation->RemoteAddressLength >=
+ sizeof (TA_NETBIOS_ADDRESS)) {
+
+ RtlCopyMemory (
+ (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress,
+ &SourceName,
+ sizeof (TA_NETBIOS_ADDRESS));
+
+ returnLength = sizeof(TA_NETBIOS_ADDRESS);
+ remoteInformation->RemoteAddressLength = returnLength;
+
+ } else {
+
+ RtlCopyMemory (
+ (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress,
+ &SourceName,
+ remoteInformation->RemoteAddressLength);
+
+ returnLength = remoteInformation->RemoteAddressLength;
+ remoteInformation->RemoteAddressLength = returnLength;
+
+ }
+
+ } else {
+
+ returnLength = 0;
+ }
+
+ status = STATUS_SUCCESS;
+
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+
+ returnLength = 0;
+ status = GetExceptionCode ();
+
+ }
+
+ }
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ IoSetCancelRoutine(irp, NULL);
+ IoReleaseCancelSpinLock(cancelIrql);
+ irp->IoStatus.Information = MdlBytesCopied;
+ irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+
+ NbfDereferenceAddress ("Receive DG done", Address, AREF_REQUEST);
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ //
+ // no receive datagram requests; is there a kernel client?
+ //
+
+ if (addressFile->RegisteredReceiveDatagramHandler) {
+
+ IndicateBytesCopied = 0;
+
+ status = (*addressFile->ReceiveDatagramHandler)(
+ addressFile->ReceiveDatagramHandlerContext,
+ sizeof (TA_NETBIOS_ADDRESS),
+ &SourceName,
+ 0,
+ NULL,
+ TDI_RECEIVE_COPY_LOOKAHEAD,
+ Length - sizeof(NBF_HDR_CONNECTIONLESS), // indicated
+ Length - sizeof(NBF_HDR_CONNECTIONLESS), // available
+ &IndicateBytesCopied,
+ Dsdu + sizeof(NBF_HDR_CONNECTIONLESS),
+ &irp);
+
+ if (status == STATUS_SUCCESS) {
+
+ //
+ // The client accepted the datagram and so we're done.
+ //
+
+ } else if (status == STATUS_DATA_NOT_ACCEPTED) {
+
+ //
+ // The client did not accept the datagram and we need to satisfy
+ // a TdiReceiveDatagram, if possible.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_DATAGRAMS) {
+ NbfPrint0 ("NbfIndicateDatagram: Picking off a rcv datagram request from this address.\n");
+ }
+ status = STATUS_MORE_PROCESSING_REQUIRED;
+
+ } else if (status == STATUS_MORE_PROCESSING_REQUIRED) {
+
+ //
+ // The client returned an IRP that we should queue up to the
+ // address to satisfy the request.
+ //
+
+ irp->IoStatus.Status = STATUS_PENDING; // init status information.
+ irp->IoStatus.Information = 0;
+ irpSp = IoGetCurrentIrpStackLocation (irp); // get current stack loctn.
+ if ((irpSp->MajorFunction != IRP_MJ_INTERNAL_DEVICE_CONTROL) ||
+ (irpSp->MinorFunction != TDI_RECEIVE_DATAGRAM)) {
+ irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+ return status;
+ }
+
+ //
+ // Now copy the actual user data.
+ //
+
+ MdlBytesCopied = 0;
+
+ BytesToCopy = Length - sizeof(NBF_HDR_CONNECTIONLESS) - IndicateBytesCopied;
+
+ if (BytesToCopy > 0) {
+ status = TdiCopyBufferToMdl (
+ Dsdu,
+ sizeof(NBF_HDR_CONNECTIONLESS) + IndicateBytesCopied,
+ BytesToCopy,
+ irp->MdlAddress,
+ 0,
+ &MdlBytesCopied);
+ } else {
+ status = STATUS_SUCCESS;
+ }
+
+ irp->IoStatus.Information = MdlBytesCopied;
+ irp->IoStatus.Status = status;
+ LEAVE_NBF;
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+ ENTER_NBF;
+ }
+ }
+ }
+
+ //
+ // Save this to dereference it later.
+ //
+
+ prevaddressFile = addressFile;
+
+ //
+ // Reference the next address file on the list, so it
+ // stays around.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ p = p->Flink;
+ while (p != &Address->AddressFileDatabase) {
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+ if (addressFile->State != ADDRESSFILE_STATE_OPEN) {
+ p = p->Flink;
+ continue;
+ }
+ NbfReferenceAddressFile(addressFile);
+ break;
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ //
+ // Now dereference the previous address file with
+ // the lock released.
+ //
+
+ NbfDereferenceAddressFile (prevaddressFile);
+
+ ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ } // end of while loop
+
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ return status; // to dispatcher.
+} /* NbfIndicateDatagram */
+
+
+NTSTATUS
+ProcessNameQuery(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address,
+ IN PNBF_HDR_CONNECTIONLESS Header,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an incoming NAME_QUERY frame. There are two
+ types of NAME_QUERY frames, with basically the same layout. If the
+ session number in the frame is 0, then the frame is really a request
+ for information about the name, and not a request to establish a
+ session. If the session number is non-zero, then the frame is a
+ connection request that we use to satisfy a listen.
+
+ With the new version of TDI, we now indicate the user that a request
+ for connection has been received, iff there is no outstanding listen.
+ If this does occur, the user can return a connection that is to be used
+ to accept the connection on.
+
+ When we return STATUS_MORE_PROCESSING_REQUIRED, the caller of
+ this routine will continue to call us for each address for the device
+ context. When we return STATUS_SUCCESS, the caller will switch to the
+ next address. When we return any other status code, including
+ STATUS_ABANDONED, the caller will stop distributing the frame.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ Address - Pointer to the transport address object.
+
+ Header - Pointer to the connectionless NetBIOS header of the frame.
+
+ SourceAddress - Pointer to the source hardware address in the received
+ frame.
+
+ SourceRouting - Pointer to the source routing information in
+ the frame.
+
+ SourceRoutingLength - Length of the source routing information.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTP_UI_FRAME RawFrame;
+ PTP_CONNECTION Connection;
+ PTP_LINK Link;
+ UCHAR NameType;
+ BOOLEAN ConnectIndicationBlocked = FALSE;
+ PLIST_ENTRY p;
+ UINT HeaderLength;
+ PUCHAR GeneralSR;
+ UINT GeneralSRLength;
+ BOOLEAN UsedListeningConnection = FALSE;
+ PTP_ADDRESS_FILE addressFile, prevaddressFile;
+ PIRP acceptIrp;
+
+ CONNECTION_CONTEXT connectionContext;
+ TA_NETBIOS_ADDRESS RemoteAddress;
+
+ //
+ // If we are just registering or deregistering this address, then don't
+ // allow state changes. Just throw the packet away, and let the frame
+ // distributor try the next address.
+ //
+ // Also drop it if the address is in conflict.
+ //
+
+ if (Address->Flags & (ADDRESS_FLAGS_REGISTERING | ADDRESS_FLAGS_DEREGISTERING | ADDRESS_FLAGS_CONFLICT)) {
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessNameQuery %lx: address not stable [%.16s].\n", Address, Header->SourceName);
+ }
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Process this differently depending on whether it is a find name
+ // request or an incoming connection.
+ //
+
+ if (Header->Data2Low == 0) {
+
+ //
+ // This is a find-name request. Respond with a NAME_RECOGNIZED frame.
+ //
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessNameQuery %lx: find name [%.16s].\n", Address, Header->SourceName);
+ }
+
+ NbfSendNameRecognized(
+ Address,
+ 0, // LSN 0 == FIND_NAME response
+ Header,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+
+ return STATUS_ABANDONED; // don't allow multiple responses.
+
+ } else { // (if Data2Low is non-zero)
+
+ //
+ // This is an incoming connection request. If we have a listening
+ // connection on this address, then continue with the connection setup.
+ // If there is no outstanding listen, then indicate any kernel mode
+ // clients that want to know about this frame. If a listen was posted,
+ // then a connection has already been set up for it. The LSN field of
+ // the connection is set to 0, so we look for the first 0 LSN in the
+ // database.
+ //
+
+ //
+ // First, check if we already have an active connection with
+ // this remote on this address. If so, we resend the NAME_RECOGNIZED
+ // if we have not yet received the SESSION_INITIALIZE; otherwise
+ // we ignore the frame.
+ //
+
+ //
+ // If successful this adds a reference of type CREF_LISTENING.
+ //
+
+ if (Connection = NbfLookupRemoteName(Address, (PUCHAR)Header->SourceName, Header->Data2Low)) {
+
+ //
+ // We have an active connection on this guy, see if he
+ // still appears to be waiting to a NAME_RECOGNIZED.
+ //
+
+ if (((Connection->Flags & CONNECTION_FLAGS_WAIT_SI) != 0) &&
+ (Connection->Link != (PTP_LINK)NULL) &&
+ (Connection->Link->State == LINK_STATE_ADM)) {
+
+ //
+ // Yes, he must have dropped a previous NAME_RECOGNIZED
+ // so we send another one.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2("Dup NAME_QUERY found: %lx [%.16s]\n", Connection, Header->SourceName);
+ }
+
+ NbfSendNameRecognized(
+ Address,
+ Connection->Lsn,
+ Header,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+
+ } else {
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2("Dup NAME_QUERY ignored: %lx [%.16s]\n", Connection, Header->SourceName);
+ }
+
+ }
+
+ NbfDereferenceConnection ("Lookup done", Connection, CREF_LISTENING);
+
+ return STATUS_ABANDONED;
+
+ }
+
+ // If successful, this adds a reference which is removed before
+ // this function returns.
+
+ Connection = NbfLookupListeningConnection (Address, (PUCHAR)Header->SourceName);
+ if (Connection == NULL) {
+
+ //
+ // not having a listening connection is not reason to bail out here.
+ // we need to indicate to the user that a connect attempt occurred,
+ // and see if there is a desire to use this connection. We
+ // indicate in order to all address files that are
+ // using this address.
+ //
+ // If we already have an indication pending on this address,
+ // we ignore this frame (the NAME_QUERY may have come from
+ // a different address, but we can't know that). Also, if
+ // there is already an active connection on this remote
+ // name, then we ignore the frame.
+ //
+
+
+ ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ p = Address->AddressFileDatabase.Flink;
+ while (p != &Address->AddressFileDatabase) {
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+ if (addressFile->State != ADDRESSFILE_STATE_OPEN) {
+ p = p->Flink;
+ continue;
+ }
+ NbfReferenceAddressFile(addressFile);
+ break;
+ }
+
+ while (p != &Address->AddressFileDatabase) {
+
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ if ((addressFile->RegisteredConnectionHandler == TRUE) &&
+ (!addressFile->ConnectIndicationInProgress)) {
+
+
+ TdiBuildNetbiosAddress (
+ (PUCHAR)Header->SourceName,
+ FALSE,
+ &RemoteAddress);
+
+ addressFile->ConnectIndicationInProgress = TRUE;
+
+ //
+ // we have a connection handler, now indicate that a connection
+ // attempt occurred.
+ //
+
+ status = (addressFile->ConnectionHandler)(
+ addressFile->ConnectionHandlerContext,
+ sizeof (TA_NETBIOS_ADDRESS),
+ &RemoteAddress,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ &connectionContext,
+ &acceptIrp);
+
+ if (status == STATUS_MORE_PROCESSING_REQUIRED) {
+
+ //
+ // the user has connected a currently open connection, but
+ // we have to figure out which one it is.
+ //
+
+ //
+ // If successful this adds a reference of type LISTENING
+ // (the same what NbfLookupListeningConnection adds).
+ //
+
+ Connection = NbfLookupConnectionByContext (
+ Address,
+ connectionContext);
+
+ if (Connection == NULL) {
+
+ //
+ // BUGBUG: We have to tell the client that
+ // his connection is bogus (or has this
+ // already happened??).
+ //
+
+ NbfPrint0("STATUS_MORE_PROCESSING, connection not found\n");
+ addressFile->ConnectIndicationInProgress = FALSE;
+ acceptIrp->IoStatus.Status = STATUS_INVALID_CONNECTION;
+ IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT);
+
+ goto whileend; // try next address file
+
+ } else {
+
+ if (Connection->AddressFile->Address != Address) {
+ addressFile->ConnectIndicationInProgress = FALSE;
+
+ NbfPrint0("STATUS_MORE_PROCESSING, address wrong\n");
+ NbfStopConnection (Connection, STATUS_INVALID_ADDRESS);
+ NbfDereferenceConnection("Bad Address", Connection, CREF_LISTENING);
+ Connection = NULL;
+ acceptIrp->IoStatus.Status = STATUS_INVALID_ADDRESS;
+ IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT);
+
+ goto whileend; // try next address file
+ }
+
+ //
+ // OK, we have a valid connection. If the response to
+ // this connection was disconnect, we need to reject
+ // the connection request and return. If it was accept
+ // or not specified (to be done later), we simply
+ // fall through and continue processing on the U Frame.
+ //
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_DISCONNECT) != 0) {
+
+// Connection->Flags2 &= ~CONNECTION_FLAGS2_DISCONNECT;
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ NbfPrint0("STATUS_MORE_PROCESSING, disconnect\n");
+ addressFile->ConnectIndicationInProgress = FALSE;
+ NbfDereferenceConnection("Disconnecting", Connection, CREF_LISTENING);
+ Connection = NULL;
+ acceptIrp->IoStatus.Status = STATUS_INVALID_CONNECTION;
+ IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT);
+
+ goto whileend; // try next address file
+ }
+
+ }
+
+ //
+ // Make a note that we have to set
+ // addressFile->ConnectIndicationInProgress to
+ // FALSE once the address is safely stored
+ // in the connection.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint4 ("ProcessNameQuery %lx: indicate DONE, context %lx conn %lx [%.16s].\n", Address, connectionContext, Connection, Header->SourceName);
+ }
+ IF_NBFDBG (NBF_DEBUG_SETUP) {
+ NbfPrint6 ("Link is %x-%x-%x-%x-%x-%x\n",
+ SourceAddress->Address[0],
+ SourceAddress->Address[1],
+ SourceAddress->Address[2],
+ SourceAddress->Address[3],
+ SourceAddress->Address[4],
+ SourceAddress->Address[5]);
+ }
+
+ //
+ // Set up our flags...we turn on REQ_COMPLETED
+ // so that disconnect will be indicated if the
+ // connection goes down before a session init
+ // is received.
+ //
+
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_STOPPING;
+ Connection->Status = STATUS_PENDING;
+ Connection->Flags2 |= (CONNECTION_FLAGS2_ACCEPTED |
+ CONNECTION_FLAGS2_REQ_COMPLETED);
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ ConnectIndicationBlocked = TRUE;
+ NbfDereferenceAddressFile (addressFile);
+ acceptIrp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT);
+ ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
+ break; // exit the while
+
+#if 0
+ } else if (status == STATUS_EVENT_PENDING) {
+
+ //
+ // user has returned a connectionContext, use that for further
+ // processing of the connection. First validate it so
+ // we can know we won't just start a connection and never
+ // finish.
+ //
+ //
+ // If successful this adds a reference of type LISTENING
+ // (the same what NbfLookupListeningConnection adds).
+ //
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameQuery %lx: indicate PENDING, context %lx [%.16s].\n", Address, connectionContext, Header->SourceName);
+ }
+
+
+ Connection = NbfLookupConnectionByContext (
+ Address,
+ connectionContext);
+
+ if (Connection == NULL) {
+
+ //
+ // BUGBUG: We have to tell the client that
+ // his connection is bogus (or has this
+ // already happened??).
+ //
+
+ NbfPrint0("STATUS_MORE_PROCESSING, but connection not found\n");
+ addressFile->ConnectIndicationInProgress = FALSE;
+
+ goto whileend; // try next address file.
+
+ } else {
+
+ if (Connection->AddressFile->Address != Address) {
+ addressFile->ConnectIndicationInProgress = FALSE;
+ NbfStopConnection (Connection, STATUS_INVALID_ADDRESS);
+ NbfDereferenceConnection("Bad Address", Connection, CREF_LISTENING);
+ Connection = NULL;
+
+ goto whileend; // try next address file.
+ }
+
+ }
+
+ //
+ // Make a note that we have to set
+ // addressFile->ConnectionIndicatInProgress to
+ // FALSE once the address is safely stored
+ // in the connection.
+ //
+
+ ConnectIndicationBlocked = TRUE;
+ NbfDereferenceAddressFile (addressFile);
+ ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
+ break; // exit the while
+#endif
+
+ } else if (status == STATUS_INSUFFICIENT_RESOURCES) {
+
+ //
+ // we know the address, but can't create a connection to
+ // use on it. This gets passed to the network as a response
+ // saying I'm here, but can't help.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessNameQuery %lx: indicate RESOURCES [%.16s].\n", Address, Header->SourceName);
+ }
+
+ addressFile->ConnectIndicationInProgress = FALSE;
+
+ //
+ // We should send a NR with LSN 0xff, indicating
+ // no resources, but LM 2.0 does not interpret
+ // that correctly. So, we send LSN 0 (no listens)
+ // instead.
+ //
+
+ NbfSendNameRecognized(
+ Address,
+ 0,
+ Header,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+
+ NbfDereferenceAddressFile (addressFile);
+ return STATUS_ABANDONED;
+
+ } else {
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessNameQuery %lx: indicate invalid [%.16s].\n", Address, Header->SourceName);
+ }
+
+ addressFile->ConnectIndicationInProgress = FALSE;
+
+ goto whileend; // try next address file
+
+ } // end status ifs
+
+ } else {
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessNameQuery %lx: no handler [%.16s].\n", Address, Header->SourceName);
+ }
+
+ goto whileend; // try next address file
+
+ } // end no indication handler
+
+whileend:
+ //
+ // Jumping here is like a continue, except that the
+ // addressFile pointer is advanced correctly.
+ //
+
+ //
+ // Save this to dereference it later.
+ //
+
+ prevaddressFile = addressFile;
+
+ //
+ // Reference the next address file on the list, so it
+ // stays around.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ p = p->Flink;
+ while (p != &Address->AddressFileDatabase) {
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+ if (addressFile->State != ADDRESSFILE_STATE_OPEN) {
+ p = p->Flink;
+ continue;
+ }
+ NbfReferenceAddressFile(addressFile);
+ break;
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ //
+ // Now dereference the previous address file with
+ // the lock released.
+ //
+
+ NbfDereferenceAddressFile (prevaddressFile);
+
+ ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ } // end of loop through the address files.
+
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ if (Connection == NULL) {
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessNameQuery %lx: no connection [%.16s].\n", Address, Header->SourceName);
+ }
+
+ //
+ // We still did not find a connection after looping
+ // through the address files.
+ //
+
+ NbfSendNameRecognized(
+ Address,
+ 0, // LSN 0 == No listens
+ Header,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+
+ //
+ // We used to return MORE_PROCESSING_REQUIRED, but
+ // since we matched with this address, no other
+ // address is going to match, so abandon it.
+ //
+
+ return STATUS_ABANDONED;
+
+ }
+
+ } else { // end connection == null
+
+ UsedListeningConnection = TRUE;
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameQuery %lx: found listen %lx: [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+ }
+
+
+ //
+ // At this point the connection has a reference of type
+ // CREF_LISTENING. Allocate a UI frame from the pool.
+ //
+
+ status = NbfCreateConnectionlessFrame (DeviceContext, &RawFrame);
+ if (!NT_SUCCESS (status)) { // no resources to respond.
+ PANIC ("ProcessNameQuery: Can't get UI Frame, dropping query\n");
+ if (ConnectIndicationBlocked) {
+ addressFile->ConnectIndicationInProgress = FALSE;
+ }
+ if (UsedListeningConnection) {
+ Connection->Flags2 |= CONNECTION_FLAGS2_WAIT_NQ;
+ } else {
+ Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+ NbfStopConnection (Connection, STATUS_INSUFFICIENT_RESOURCES);
+ }
+ NbfDereferenceConnection("Can't get UI Frame", Connection, CREF_LISTENING);
+ return STATUS_ABANDONED;
+ }
+
+ //
+ // Build the MAC header. NAME_RECOGNIZED frames go out as
+ // general-route source routing.
+ //
+
+ MacReturnGeneralRouteSR(
+ &DeviceContext->MacInfo,
+ &GeneralSR,
+ &GeneralSRLength);
+
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ RawFrame->Header,
+ SourceAddress->Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS),
+ GeneralSR,
+ GeneralSRLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // Before we continue, store the remote guy's transport address
+ // into the TdiListen's TRANSPORT_CONNECTION buffer. This allows
+ // the client to determine who called him.
+ //
+
+ Connection->CalledAddress.NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+
+ TdiCopyLookaheadData(
+ Connection->CalledAddress.NetbiosName,
+ Header->SourceName,
+ 16,
+ DeviceContext->MacInfo.CopyLookahead ? TDI_RECEIVE_COPY_LOOKAHEAD : 0);
+
+ RtlCopyMemory( Connection->RemoteName, Connection->CalledAddress.NetbiosName, 16 );
+ Connection->Flags2 |= CONNECTION_FLAGS2_REMOTE_VALID;
+
+ if (ConnectIndicationBlocked) {
+ addressFile->ConnectIndicationInProgress = FALSE;
+ }
+
+ //
+ // Now formulate a reply.
+ //
+
+ NameType = (UCHAR)((Address->Flags & ADDRESS_FLAGS_GROUP) ?
+ NETBIOS_NAME_TYPE_GROUP : NETBIOS_NAME_TYPE_UNIQUE);
+
+ //
+ // We have a listening connection on the address now. Create a link
+ // for it to be associated with and make that link ready. Respond to
+ // the sender with a name_recognized frame. then we will receive our
+ // first connection-oriented frame, SESSION_INITIALIZE, handled
+ // in IFRAMES.C. Then we respond with SESSION_CONFIRM, and then
+ // the TdiListen completes.
+ //
+
+ // If successful, this adds a link reference which is removed
+ // in NbfDisconnectFromLink. It does NOT add a link reference.
+
+ status = NbfCreateLink (
+ DeviceContext,
+ SourceAddress, // remote hardware address.
+ SourceRouting,
+ SourceRoutingLength,
+ LISTENER_LINK, // for loopback link
+ &Link); // resulting link.
+
+ if (NT_SUCCESS (status)) { // link established.
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ // If successful, this adds a connection reference
+ // which is removed in NbfDisconnectFromLink
+
+ if (((Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) == 0) &&
+ ((status = NbfConnectToLink (Link, Connection)) == STATUS_SUCCESS)) {
+
+ Connection->Flags |= CONNECTION_FLAGS_WAIT_SI; // wait for SI.
+ Connection->Retries = 1;
+ Connection->Rsn = Header->Data2Low; // save remote LSN.
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ NbfWaitLink (Link); // start link going.
+
+ ConstructNameRecognized ( // build a good response.
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ NameType, // type of local name.
+ Connection->Lsn, // return our LSN.
+ RESPONSE_CORR(Header), // new xmit corr.
+ 0, // our response correlator (unused).
+ Header->DestinationName,// our NetBIOS name.
+ Header->SourceName); // his NetBIOS name.
+
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+ NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
+
+ //
+ // Now, to avoid problems with hanging listens, we'll start the
+ // connection timer and give a limited period for the connection
+ // to succeed. This avoids waiting forever for those first few
+ // frames to be exchanged. When the timeout occurs, the
+ // the dereference will cause the circuit to be torn down.
+ //
+ // The maximum delay we can accomodate on a link is
+ // NameQueryRetries * NameQueryTimeout (assuming the
+ // remote has the same timeous). There are three
+ // exchanges of packets until the SESSION_INITIALIZE
+ // shows up, to be safe we multiply by four.
+ //
+
+ NbfStartConnectionTimer(
+ Connection,
+ NbfListenTimeout,
+ 4 * DeviceContext->NameQueryRetries * DeviceContext->NameQueryTimeout);
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ TRUE); // loopback if needed.
+
+ IF_NBFDBG (NBF_DEBUG_SETUP) {
+ NbfPrint2("Connection %lx on link %lx\n", Connection, Link);
+ }
+
+ NbfDereferenceConnection("ProcessNameQuery", Connection, CREF_LISTENING);
+ return STATUS_ABANDONED; // successful!
+ }
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ //
+ // We don't have a free LSN to allocate, so fall through to
+ // report "no resources".
+ //
+
+ // We did a link reference since NbfCreateLink succeeded,
+ // but since NbfConnectToLink failed we will never remove
+ // that reference in NbfDisconnectFromLink, so do it here.
+
+ NbfDereferenceLink ("No more LSNS", Link, LREF_CONNECTION);
+
+ ASSERT (Connection->Lsn == 0);
+
+ }
+
+ //
+ // If we fall through here, then we couldn't get resources to set
+ // up this connection, so just send him a "no resources" reply.
+ //
+
+ if (UsedListeningConnection) {
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_WAIT_NQ; // put this back.
+
+ } else {
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+ NbfStopConnection (Connection, STATUS_INSUFFICIENT_RESOURCES);
+
+ }
+
+ //
+ // We should send a NR with LSN 0xff, indicating
+ // no resources, but LM 2.0 does not interpret
+ // that correctly. So, we send LSN 0 (no listens)
+ // instead.
+ //
+
+ ConstructNameRecognized (
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ NameType,
+ 0, // LSN=0 means no listens
+ RESPONSE_CORR(Header),
+ 0,
+ Header->DestinationName, // our NetBIOS name.
+ Header->SourceName); // his NetBIOS name.
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+ NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ TRUE); // loopback if needed.
+
+ NbfDereferenceConnection("ProcessNameQuery done", Connection, CREF_LISTENING);
+ }
+
+ return STATUS_ABANDONED;
+
+} /* ProcessNameQuery */
+
+
+NTSTATUS
+ProcessAddNameResponse(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address,
+ IN PNBF_HDR_CONNECTIONLESS Header,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an incoming ADD_NAME_RESPONSE frame.
+
+ When we return STATUS_MORE_PROCESSING_REQUIRED, the caller of
+ this routine will continue to call us for each address for the device
+ context. When we return STATUS_SUCCESS, the caller will switch to the
+ next address. When we return any other status code, including
+ STATUS_ABANDONED, the caller will stop distributing the frame.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ Address - Pointer to the transport address object.
+
+ Header - Pointer to the connectionless NetBIOS header of the frame.
+
+ SourceAddress - Pointer to the source hardware address in the received
+ frame.
+
+ SourceRouting - Pointer to the source routing information in
+ the frame.
+
+ SourceRoutingLength - Length of the source routing information.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ BOOLEAN SendNameInConflict = FALSE;
+ UNREFERENCED_PARAMETER(DeviceContext);
+
+ ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ //
+ // If we aren't trying to register this address, then the sender of
+ // this frame is bogus. We cannot allow our state to change based
+ // on the reception of a random frame.
+ //
+
+ if (!(Address->Flags & ADDRESS_FLAGS_REGISTERING)) {
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+ IF_NBFDBG (NBF_DEBUG_ADDRESS | NBF_DEBUG_UFRAMES) {
+ NbfPrint2("ProcessAddNameResponse %lx: not registering [%.16s]\n", Address, Header->SourceName);
+ }
+ return STATUS_ABANDONED; // just destroy the packet.
+ }
+
+ //
+ // Unfortunately, we are registering this address and another host
+ // on the network is also attempting to register the same NetBIOS
+ // name on the same network. Because he got to us first, we cannot
+ // register our name. Thus, the address must die. We set this flag
+ // and on the next timeout we will shut down.
+ //
+
+ Address->Flags |= ADDRESS_FLAGS_DUPLICATE_NAME;
+
+ if (Header->Data2Low == NETBIOS_NAME_TYPE_UNIQUE) {
+
+ //
+ // If we have already gotten a response from someone saying
+ // this address is uniquely owned, then make sure any future
+ // responses come from the same MAC address.
+ //
+
+ if ((*((LONG UNALIGNED *)Address->UniqueResponseAddress) == 0) &&
+ (*((SHORT UNALIGNED *)(&Address->UniqueResponseAddress[4])) == 0)) {
+
+ RtlMoveMemory(Address->UniqueResponseAddress, SourceAddress->Address, 6);
+
+ } else if (!RtlEqualMemory(
+ Address->UniqueResponseAddress,
+ SourceAddress->Address,
+ 6)) {
+
+ if (!Address->NameInConflictSent) {
+ SendNameInConflict = TRUE;
+ }
+
+ }
+
+ } else {
+
+ //
+ // For group names, make sure nobody else decided that it was
+ // a unique address.
+ //
+
+ if ((*((LONG UNALIGNED *)Address->UniqueResponseAddress) != 0) ||
+ (*((SHORT UNALIGNED *)(&Address->UniqueResponseAddress[4])) != 0)) {
+
+ if (!Address->NameInConflictSent) {
+ SendNameInConflict = TRUE;
+ }
+
+ }
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ if (SendNameInConflict) {
+
+ Address->NameInConflictSent = TRUE;
+ NbfSendNameInConflict(
+ Address,
+ (PUCHAR)Header->DestinationName);
+
+ }
+
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS | NBF_DEBUG_UFRAMES) {
+ NbfPrint2("ProcessAddNameResponse %lx: stopping [%.16s]\n", Address, Header->SourceName);
+ }
+
+ return STATUS_ABANDONED; // done with this frame.
+} /* ProcessAddNameResponse */
+
+
+NTSTATUS
+ProcessNameRecognized(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address,
+ IN PNBF_HDR_CONNECTIONLESS Header,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an incoming NAME_RECOGNIZED frame. This frame
+ is received because we issued a NAME_QUERY frame to actively initiate
+ a connection with a remote host.
+
+ When we return STATUS_MORE_PROCESSING_REQUIRED, the caller of
+ this routine will continue to call us for each address for the device
+ context. When we return STATUS_SUCCESS, the caller will switch to the
+ next address. When we return any other status code, including
+ STATUS_ABANDONED, the caller will stop distributing the frame.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ Address - Pointer to the transport address object.
+
+ Header - Pointer to the connectionless NetBIOS header of the frame.
+
+ SourceAddress - Pointer to the source hardware address in the received
+ frame.
+
+ SourceRouting - Pointer to the source routing information in
+ the frame.
+
+ SourceRoutingLength - Length of the source routing information.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTP_CONNECTION Connection;
+ PTP_LINK Link;
+ BOOLEAN TimerCancelled;
+
+
+ if (Address->Flags & (ADDRESS_FLAGS_REGISTERING | ADDRESS_FLAGS_DEREGISTERING | ADDRESS_FLAGS_CONFLICT)) {
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessNameRecognized %lx: address not stable [%.16s].\n", Address, Header->SourceName);
+ }
+ return STATUS_ABANDONED; // invalid address state, drop packet.
+ }
+
+ //
+ // Find names and connections both require a TP_CONNECTION to work.
+ // In either case, the ConnectionId field of the TP_CONNECTION object
+ // was sent as the response correlator in the NAME_QUERY frame, so
+ // we should get the same correlator back in this frame in the
+ // transmit correlator. Because this number is unique across
+ // all the connections on an address, we can determine if the frame
+ // was for this address or not.
+ //
+
+ // this causes a reference which is removed before this function returns.
+
+ Connection = NbfLookupConnectionById (
+ Address,
+ TRANSMIT_CORR(Header));
+
+ //
+ // has he been deleted while we were waiting?
+ //
+
+ if (Connection == NULL) {
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessNameRecognized %lx: no connection [%.16s].\n", Address, Header->SourceName);
+ }
+ return STATUS_ABANDONED;
+ }
+
+ //
+ // This frame is a response to a NAME_QUERY frame that we previously
+ // sent to him. Either he's returning "insufficient resources",
+ // indicating that a session cannot be established, or he's initiated
+ // his side of the connection.
+ //
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) != 0) {
+
+ //
+ // Connection is stopping, don't process this.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameRecognized %lx: connection %lx stopping [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+ NbfDereferenceConnection("Name Recognized, stopping", Connection, CREF_BY_ID);
+
+ return STATUS_ABANDONED;
+ }
+
+ if (Header->Data2Low == 0x00 ||
+ (Header->Data2Low > 0x00 && (Connection->Flags2 & CONNECTION_FLAGS2_WAIT_NR_FN))) { // no listens, or FIND.NAME response.
+
+ if (!(Connection->Flags2 & CONNECTION_FLAGS2_CONNECTOR)) {
+
+ //
+ // This is just a find name request, we are not trying to
+ // establish a connection. Currently, there is no reason
+ // for this to occur, so just save some room to add this
+ // extra feature later to support NETBIOS find name.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameRecognized %lx: connection %lx not connector [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+ NbfDereferenceConnection("Unexpected FN Response", Connection, CREF_BY_ID);
+ return STATUS_ABANDONED; // we processed the frame.
+ }
+
+ //
+ // We're setting up a session. If we are waiting for the first NAME
+ // RECOGNIZED, then setup the link and send the second NAME_QUERY.
+ // If we're waiting for the second NAME_RECOGNIZED, then he didn't
+ // have an LSN to finish the connection, so tear it down.
+ //
+
+ if (Connection->Flags2 & CONNECTION_FLAGS2_WAIT_NR_FN) {
+
+ //
+ // Now that we know the data link address of the remote host
+ // we're connecting to, we need to create a TP_LINK object to
+ // represent the data link between these two machines. If there
+ // is already a data link there, then the object will be reused.
+ //
+
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_WAIT_NR_FN;
+
+ if (Header->Data2High == NETBIOS_NAME_TYPE_UNIQUE) {
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ //
+ // The Netbios address we are connecting to is a
+ // unique name
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameRecognized %lx: connection %lx send 2nd NQ [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+
+ // If successful, this adds a link reference which is removed
+ // in NbfDisconnectFromLink
+
+ status = NbfCreateLink (
+ DeviceContext,
+ SourceAddress, // remote hardware address.
+ SourceRouting,
+ SourceRoutingLength,
+ CONNECTOR_LINK, // for loopback link
+ &Link); // resulting link.
+
+ if (!NT_SUCCESS (status)) { // no resources.
+ NbfStopConnection (Connection, STATUS_INSUFFICIENT_RESOURCES);
+ NbfDereferenceConnection ("No Resources for link", Connection, CREF_BY_ID);
+ return STATUS_ABANDONED;
+ }
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ // If successful, this adds a connection reference which is
+ // removed in NbfDisconnectFromLink. It does NOT add a link ref.
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) ||
+ ((status = NbfConnectToLink (Link, Connection)) != STATUS_SUCCESS)) {
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ // Connection stopping or no LSN's available on this link.
+ // We did a link reference since NbfCreateLink succeeded,
+ // but since NbfConnectToLink failed we will never remove
+ // that reference in NbfDisconnectFromLink, so do it here.
+
+ NbfDereferenceLink ("Can't connect to link", Link, LREF_CONNECTION); // most likely destroys this.
+
+ NbfStopConnection (Connection, STATUS_INSUFFICIENT_RESOURCES);
+ NbfDereferenceConnection ("Cant connect to link", Connection, CREF_BY_ID);
+ return STATUS_ABANDONED;
+ }
+
+ (VOID)InterlockedIncrement(&Link->NumberOfConnectors);
+
+ } else {
+
+ //
+ // We are connecting to a group name; we have to
+ // assign an LSN now, but we don't connect to
+ // the link until we get a committed name response.
+ //
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_GROUP_LSN;
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameRecognized %lx: connection %lx send 2nd NQ GROUP [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+ if (NbfAssignGroupLsn(Connection) != STATUS_SUCCESS) {
+
+ //
+ // Could not find an empty LSN; have to fail.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ NbfStopConnection (Connection, STATUS_INSUFFICIENT_RESOURCES);
+ NbfDereferenceConnection("Can't get group LSN", Connection, CREF_BY_ID);
+ return STATUS_ABANDONED;
+
+ }
+
+ }
+
+
+ //
+ // Send the second NAME_QUERY frame, committing our LSN to
+ // the remote guy.
+ //
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_WAIT_NR;
+ Connection->Retries = (USHORT)DeviceContext->NameQueryRetries;
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ NbfStartConnectionTimer (
+ Connection,
+ ConnectionEstablishmentTimeout,
+ DeviceContext->NameQueryTimeout);
+
+ KeQueryTickCount (&Connection->ConnectStartTime);
+
+ NbfSendNameQuery(
+ Connection,
+ TRUE);
+
+ NbfDereferenceConnection ("Done with lookup", Connection, CREF_BY_ID); // release lookup hold.
+ return STATUS_ABANDONED; // we processed the frame.
+
+ } else if (Connection->Flags2 & CONNECTION_FLAGS2_WAIT_NR) {
+
+ if (Connection->Link) {
+
+ if (RtlEqualMemory(
+ Connection->Link->HardwareAddress.Address,
+ SourceAddress->Address,
+ 6)) {
+
+ //
+ // Unfortunately, he's telling us that he doesn't have resources
+ // to allocate an LSN. We set a flag to record this and
+ // ignore the frame.
+ //
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_NO_LISTEN;
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameRecognized %lx: connection %lx no listens [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+ } else {
+
+ //
+ // This response comes from a different remote from the
+ // last one. For unique names this indicates a duplicate
+ // name on the network.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ if (Header->Data2High == NETBIOS_NAME_TYPE_UNIQUE) {
+
+ if (!Address->NameInConflictSent) {
+
+ Address->NameInConflictSent = TRUE;
+ NbfSendNameInConflict(
+ Address,
+ (PUCHAR)Header->SourceName);
+
+ }
+ }
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameRecognized %lx: connection %lx name in conflict [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+ }
+
+ } else {
+
+ //
+ // The response came back so fast the connection is
+ // not stable, ignore it.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ }
+
+ NbfDereferenceConnection ("No remote resources", Connection, CREF_BY_ID); // release our lookup hold.
+ return STATUS_ABANDONED; // we processed the frame.
+
+ } else {
+
+ //
+ // Strange state. This should never happen, because we should be
+ // either waiting for a first or second name recognized frame. It
+ // is possible that the remote station received two frames because
+ // of our retransmits, and so he responded to both. Toss the frame.
+ //
+
+ if (Connection->Link) {
+
+ if (!RtlEqualMemory(
+ Connection->Link->HardwareAddress.Address,
+ SourceAddress->Address,
+ 6)) {
+
+ //
+ // This response comes from a different remote from the
+ // last one. For unique names this indicates a duplicate
+ // name on the network.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ if (Header->Data2High == NETBIOS_NAME_TYPE_UNIQUE) {
+
+ if (!Address->NameInConflictSent) {
+
+ Address->NameInConflictSent = TRUE;
+ NbfSendNameInConflict(
+ Address,
+ (PUCHAR)Header->SourceName);
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // This is the same remote, just ignore it.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ }
+
+ } else {
+
+ //
+ // The response came back so fast the connection is
+ // not stable, ignore it.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ }
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameRecognized %lx: connection %lx unexpected [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+ NbfDereferenceConnection ("Tossing second response Done with lookup", Connection, CREF_BY_ID); // release our lookup hold.
+ return STATUS_ABANDONED; // we processed the frame.
+
+ }
+
+ } else if (Header->Data2Low == 0xff) { // no resources to complete connection.
+
+ if (Connection->Flags2 & CONNECTION_FLAGS2_WAIT_NR) {
+
+ //
+ // The recipient of our previously-sent NAME_QUERY frame that we sent
+ // to actively establish a connection has unfortunately run out of
+ // resources and cannot setup his side of the connection. We have to
+ // report "no resources" on the TdiConnect.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameRecognized %lx: connection %lx no resources [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint0 ("ProcessNameRecognized: No resources.\n");
+ }
+
+ NbfStopConnection (Connection, STATUS_REMOTE_RESOURCES);
+ NbfDereferenceConnection ("No Resources", Connection, CREF_BY_ID); // release our lookup hold.
+ return STATUS_ABANDONED; // we processed the frame.
+
+ } else {
+
+ //
+ // We don't have a committed NAME_QUERY out there, so
+ // we ignore this frame.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameRecognized %lx: connection %lx unexpected no resources [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+ NbfDereferenceConnection ("Tossing second response Done with lookup", Connection, CREF_BY_ID); // release our lookup hold.
+ return STATUS_ABANDONED; // we processed the frame.
+
+ }
+
+ } else { // Data2Low is in the range 0x01-0xfe
+
+ if (Connection->Flags2 & CONNECTION_FLAGS2_WAIT_NR) {
+
+ //
+ // This is a successful response to a second NAME_QUERY we sent when
+ // we started processing a TdiConnect request. Clear the "waiting
+ // for Name Recognized" bit in the connection flags so that the
+ // connection timer doesn't blow us away when it times out.
+ //
+ // BUGBUG: What prevents the timeout routine from running while
+ // we're in here and destroying the connection/link by
+ // calling NbfStopConnection?
+ //
+
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_WAIT_NR;
+
+ //
+ // Before we continue, store the remote guy's transport address
+ // into the TdiConnect's TRANSPORT_CONNECTION buffer. This allows
+ // the client to determine who responded to his TdiConnect.
+ //
+ // BUGBUG: this used to be done prior to sending the second
+ // Name Query, but since I fixed the Buffer2 problem, meaning
+ // that I really do overwrite the input buffer with the
+ // output buffer, that was screwing up the second query.
+ // Note that doing the copy after sending is probably unsafe
+ // in the case where the second Name Recognized arrives
+ // right away.
+ //
+
+ Connection->CalledAddress.NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ TdiCopyLookaheadData(
+ Connection->CalledAddress.NetbiosName,
+ Header->SourceName,
+ 16,
+ DeviceContext->MacInfo.CopyLookahead ? TDI_RECEIVE_COPY_LOOKAHEAD : 0);
+
+ RtlCopyMemory( Connection->RemoteName, Header->SourceName, 16 );
+
+ Connection->Rsn = Header->Data2Low; // save his remote LSN.
+
+ //
+ // Save the correlator from the NR for eventual use in the
+ // SESSION_INITIALIZE frame.
+ //
+
+ Connection->NetbiosHeader.TransmitCorrelator = RESPONSE_CORR(Header);
+
+ //
+ // Cancel the timer; it would have no effect since WAIT_NR
+ // is not set, but there is no need for it to run. We cancel
+ // it with the lock held so it won't interfere with the
+ // timer's use when a connection is closing.
+ //
+
+ TimerCancelled = KeCancelTimer (&Connection->Timer);
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_GROUP_LSN) != 0) {
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ //
+ // The Netbios address we are connecting to is a
+ // group name; we need to connect to the link
+ // now that we have the committed session.
+ //
+
+ // If successful, this adds a link reference which is removed
+ // in NbfDisconnectFromLink
+
+ status = NbfCreateLink (
+ DeviceContext,
+ SourceAddress, // remote hardware address.
+ SourceRouting,
+ SourceRoutingLength,
+ CONNECTOR_LINK, // for loopback link
+ &Link); // resulting link.
+
+ if (!NT_SUCCESS (status)) { // no resources.
+ NbfStopConnection (Connection, STATUS_INSUFFICIENT_RESOURCES);
+ NbfDereferenceConnection ("No Resources for link", Connection, CREF_BY_ID);
+
+ if (TimerCancelled) {
+ NbfDereferenceConnection("NR received, cancel timer", Connection, CREF_TIMER);
+ }
+
+ return STATUS_ABANDONED;
+ }
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ // If successful, this adds a connection reference which is
+ // removed in NbfDisconnectFromLink. It does NOT add a link ref.
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) ||
+ ((status = NbfConnectToLink (Link, Connection)) != STATUS_SUCCESS)) {
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ if (TimerCancelled) {
+ NbfDereferenceConnection("NR received, cancel timer", Connection, CREF_TIMER);
+ }
+
+ // Connection stopping or no LSN's available on this link.
+ // We did a link reference since NbfCreateLink succeeded,
+ // but since NbfConnectToLink failed we will never remove
+ // that reference in NbfDisconnectFromLink, so do it here.
+
+ NbfDereferenceLink ("Can't connect to link", Link, LREF_CONNECTION); // most likely destroys this.
+
+ NbfStopConnection (Connection, STATUS_INSUFFICIENT_RESOURCES);
+ NbfDereferenceConnection ("Cant connect to link", Connection, CREF_BY_ID);
+ return STATUS_ABANDONED;
+ }
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ (VOID)InterlockedIncrement(&Link->NumberOfConnectors);
+
+ } else {
+
+ //
+ // It's to a unique address, we set up the link
+ // before we sent out the committed NAME_QUERY.
+ //
+
+ Link = Connection->Link;
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ }
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameRecognized %lx: connection %lx session up! [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+ //
+ // When we sent the committed NAME_QUERY, we stored that
+ // time in Connection->ConnectStartTime; we can now use
+ // that for a rough estimate of the link delay, if this
+ // is the first connection on the link. For async lines
+ // we do not do this because the delay introduced by the
+ // gateway messes up the timing.
+ //
+
+ if (!DeviceContext->MacInfo.MediumAsync) {
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ if (Link->State == LINK_STATE_ADM) {
+
+ //
+ // HACK: Set the necessary variables in the link
+ // so that FakeUpdateBaseT1Timeout works. These
+ // variables are the same ones that FakeStartT1 sets.
+ //
+
+ Link->CurrentPollSize = Link->HeaderLength + sizeof(DLC_FRAME) + sizeof(NBF_HDR_CONNECTIONLESS);
+ Link->CurrentTimerStart = Connection->ConnectStartTime;
+ FakeUpdateBaseT1Timeout (Link);
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ }
+
+ if (TimerCancelled) {
+ NbfDereferenceConnection("NR received, cancel timer", Connection, CREF_TIMER);
+ }
+
+ NbfActivateLink (Connection->Link); // start link going.
+
+ //
+ // We'll get control again in LINK.C when the data link has either
+ // been established, denied, or destroyed. This happens at I/O
+ // completion time from NbfCreateLink's PdiConnect request.
+ //
+
+ } else {
+
+ //
+ // We don't have a committed NAME_QUERY out there, so
+ // we ignore this frame.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameRecognized %lx: connection %lx unexpected session up! [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+ NbfDereferenceConnection ("Tossing second response Done with lookup", Connection, CREF_BY_ID); // release our lookup hold.
+ return STATUS_ABANDONED; // we processed the frame.
+
+ }
+
+
+ }
+
+ NbfDereferenceConnection("ProcessNameRecognized lookup", Connection, CREF_BY_ID);
+ return STATUS_ABANDONED; // don't distribute packet.
+} /* ProcessNameRecognized */
+
+
+NTSTATUS
+NbfProcessUi(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR Header,
+ IN PUCHAR DlcHeader,
+ IN ULONG DlcLength,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ OUT PTP_ADDRESS * DatagramAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the data link provider as an
+ indication that a DLC UI-frame has been received on the data link.
+ Here we dispatch to the correct UI-frame handler.
+
+ Part of this routine's job is to optionally distribute the frame to
+ every address that needs to look at it.
+ We accomplish this by lock-stepping through the address database,
+ and for each address that matches the address this frame is aimed at,
+ calling the frame handler.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ SourceAddress - Pointer to the source hardware address in the received
+ frame.
+
+ Header - Points to the MAC header of the incoming packet.
+
+ DlcHeader - Points to the DLC header of the incoming packet.
+
+ DlcLength - Actual length in bytes of the packet, starting at the
+ DlcHeader.
+
+ SourceRouting - Source routing information in the MAC header.
+
+ SourceRoutingLength - The length of SourceRouting.
+
+ DatagramAddress - If this function returns STATUS_MORE_PROCESSING_
+ REQUIRED, this will be the address the datagram should be
+ indicated to.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_ADDRESS Address;
+ PNBF_HDR_CONNECTIONLESS UiFrame;
+ NTSTATUS status;
+ PLIST_ENTRY Flink;
+ UCHAR MatchType;
+ BOOLEAN MatchedAddress;
+ PUCHAR MatchName;
+ ULONG NetbiosLength = DlcLength - 3;
+
+ UiFrame = (PNBF_HDR_CONNECTIONLESS)(DlcHeader + 3);
+
+ //
+ // Verify that this frame is long enough to examine and that it
+ // has the proper signature. We can't test the signature as a
+ // 16-bit word as specified in the NetBIOS Formats and Protocols
+ // manual because this is processor-dependent.
+ //
+
+ if ((NetbiosLength < sizeof (NBF_HDR_CONNECTIONLESS)) ||
+ (HEADER_LENGTH(UiFrame) != sizeof (NBF_HDR_CONNECTIONLESS)) ||
+ (HEADER_SIGNATURE(UiFrame) != NETBIOS_SIGNATURE)) {
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint0 ("NbfProcessUi: Bad size or NetBIOS signature.\n");
+ }
+ return STATUS_ABANDONED; // frame too small or too large.
+ }
+
+ //
+ // If this frame has a correlator with the high bit on, it was due
+ // to a FIND.NAME request; we don't handle those here since they
+ // are not per-address.
+ //
+
+ if ((UiFrame->Command == NBF_CMD_NAME_RECOGNIZED) &&
+ (TRANSMIT_CORR(UiFrame) & 0x8000)) {
+
+ //
+ // Make sure the frame is sent to our reserved address;
+ // if not, drop it.
+ //
+
+ if (RtlEqualMemory(
+ UiFrame->DestinationName,
+ DeviceContext->ReservedNetBIOSAddress,
+ NETBIOS_NAME_LENGTH)) {
+
+ return NbfProcessQueryNameRecognized(
+ DeviceContext,
+ Header,
+ UiFrame);
+ } else {
+
+ return STATUS_ABANDONED;
+
+ }
+ }
+
+ //
+ // If this is a STATUS_RESPONSE, process that separately.
+ //
+
+ if (UiFrame->Command == NBF_CMD_STATUS_RESPONSE) {
+
+ //
+ // Make sure the frame is sent to our reserved address;
+ // if not, drop it.
+ //
+
+ if (RtlEqualMemory(
+ UiFrame->DestinationName,
+ DeviceContext->ReservedNetBIOSAddress,
+ NETBIOS_NAME_LENGTH)) {
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+
+ } else {
+
+ return STATUS_ABANDONED;
+
+ }
+ }
+
+ //
+ // If this is a STATUS_QUERY, check if it is to our reserved
+ // address. If so, we process it. If not, we fall through to
+ // the normal checking. This ensures that queries to our
+ // reserved address are always processed, even if nobody
+ // has opened that address yet.
+ //
+
+ if (UiFrame->Command == NBF_CMD_STATUS_QUERY) {
+
+ if (RtlEqualMemory(
+ UiFrame->DestinationName,
+ DeviceContext->ReservedNetBIOSAddress,
+ NETBIOS_NAME_LENGTH)) {
+
+ return NbfProcessStatusQuery(
+ DeviceContext,
+ NULL,
+ UiFrame,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+
+ }
+
+ }
+
+ //
+ // We have a valid connectionless NetBIOS protocol frame that's not a
+ // datagram, so deliver it to every address which matches the destination
+ // name in the frame. Some frames
+ // (NAME_QUERY) cannot be delivered to multiple recipients. Therefore,
+ // if a frame handler returns STATUS_MORE_PROCESSING_REQUIRED, we continue
+ // through the remaining addresses. Otherwise simply get out and assume
+ // that the frame was eaten. Thus, STATUS_SUCCESS means that the handler
+ // ate the frame and that no other addresses can have it.
+ //
+
+ //
+ // Determine what kind of lookup we want to do.
+ //
+
+ switch (UiFrame->Command) {
+
+ case NBF_CMD_NAME_QUERY:
+ case NBF_CMD_DATAGRAM:
+ case NBF_CMD_DATAGRAM_BROADCAST:
+ case NBF_CMD_ADD_NAME_QUERY:
+ case NBF_CMD_STATUS_QUERY:
+ case NBF_CMD_ADD_NAME_RESPONSE:
+ case NBF_CMD_NAME_RECOGNIZED:
+
+ MatchType = NETBIOS_NAME_TYPE_EITHER;
+ break;
+
+ case NBF_CMD_ADD_GROUP_NAME_QUERY:
+ case NBF_CMD_NAME_IN_CONFLICT:
+
+ MatchType = NETBIOS_NAME_TYPE_UNIQUE;
+ break;
+
+ default:
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint1 ("NbfProcessUi: Frame delivered; Unrecognized command %x.\n",
+ UiFrame->Command);
+ }
+ return STATUS_SUCCESS;
+ break;
+
+ }
+
+ if ((UiFrame->Command == NBF_CMD_ADD_GROUP_NAME_QUERY) ||
+ (UiFrame->Command == NBF_CMD_ADD_NAME_QUERY)) {
+
+ MatchName = (PUCHAR)UiFrame->SourceName;
+
+ } else if (UiFrame->Command == NBF_CMD_DATAGRAM_BROADCAST) {
+
+ MatchName = NULL;
+
+ } else {
+
+ MatchName = (PUCHAR)UiFrame->DestinationName;
+
+ }
+
+ if (MatchName && DeviceContext->AddressCounts[MatchName[0]] == 0) {
+ status = STATUS_ABANDONED;
+ goto RasIndication;
+ }
+
+
+ MatchedAddress = FALSE;
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ for (Flink = DeviceContext->AddressDatabase.Flink;
+ Flink != &DeviceContext->AddressDatabase;
+ Flink = Flink->Flink) {
+
+ Address = CONTAINING_RECORD (
+ Flink,
+ TP_ADDRESS,
+ Linkage);
+
+ if ((Address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ continue;
+ }
+
+ if (NbfMatchNetbiosAddress (Address,
+ MatchType,
+ MatchName)) {
+
+ NbfReferenceAddress ("UI Frame", Address, AREF_PROCESS_UI); // prevent address from being destroyed.
+ MatchedAddress = TRUE;
+ break;
+
+ }
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ if (MatchedAddress) {
+
+ //
+ // If the datagram's destination name does not match the address's
+ // network name and TSAP components, then skip this address. Some
+ // frames have the source and destination names backwards for this
+ // algorithm, so we account for that here. Also, broadcast datagrams
+ // have no destination name in the frame, but get delivered to every
+ // address anyway.
+ //
+
+#if 0
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ USHORT i;
+ NbfPrint0 ("NbfProcessUi: SourceName: ");
+ for (i=0;i<16;i++) {
+ NbfPrint1 ("%c",UiFrame->SourceName[i]);
+ }
+ NbfPrint0 (" Destination Name:");
+ for (i=0;i<16;i++) {
+ NbfPrint1 ("%c",UiFrame->DestinationName[i]);
+ }
+ NbfPrint0 ("\n");
+ }
+#endif
+
+ //
+ // Deliver the frame to the current address.
+ //
+
+ switch (UiFrame->Command) {
+
+ case NBF_CMD_NAME_QUERY:
+
+ status = ProcessNameQuery (
+ DeviceContext,
+ Address,
+ UiFrame,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+
+ break;
+
+ case NBF_CMD_DATAGRAM:
+ case NBF_CMD_DATAGRAM_BROADCAST:
+
+ //
+ // Reference the datagram so it sticks around until the
+ // ReceiveComplete, when it is processed.
+ //
+
+ if ((Address->Flags & ADDRESS_FLAGS_CONFLICT) == 0) {
+ NbfReferenceAddress ("Datagram indicated", Address, AREF_PROCESS_DATAGRAM);
+ *DatagramAddress = Address;
+ status = STATUS_MORE_PROCESSING_REQUIRED;
+ } else {
+ status = STATUS_ABANDONED;
+ }
+ break;
+
+ case NBF_CMD_ADD_GROUP_NAME_QUERY:
+
+ //
+ // did this frame originate with us? If so, we don't want to
+ // do any processing of it.
+ //
+
+ if (RtlEqualMemory (
+ SourceAddress,
+ DeviceContext->LocalAddress.Address,
+ DeviceContext->MacInfo.AddressLength)) {
+
+ if ((Address->Flags & ADDRESS_FLAGS_REGISTERING) != 0) {
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint0 ("NbfProcessUI: loopback AddGroupNameQuery dropped\n");
+ }
+ status = STATUS_ABANDONED;
+ break;
+ }
+ }
+
+ status = ProcessAddGroupNameQuery (
+ DeviceContext,
+ Address,
+ UiFrame,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+ break;
+
+ case NBF_CMD_ADD_NAME_QUERY:
+
+ //
+ // did this frame originate with us? If so, we don't want to
+ // do any processing of it.
+ //
+
+ if (RtlEqualMemory (
+ SourceAddress,
+ DeviceContext->LocalAddress.Address,
+ DeviceContext->MacInfo.AddressLength)) {
+
+ if ((Address->Flags & ADDRESS_FLAGS_REGISTERING) != 0) {
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint0 ("NbfProcessUI: loopback AddNameQuery dropped\n");
+ }
+ status = STATUS_ABANDONED;
+ break;
+ }
+ }
+
+ status = ProcessAddNameQuery (
+ DeviceContext,
+ Address,
+ UiFrame,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+ break;
+
+ case NBF_CMD_NAME_IN_CONFLICT:
+
+ status = ProcessNameInConflict (
+ DeviceContext,
+ Address,
+ UiFrame,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+
+ break;
+
+ case NBF_CMD_STATUS_QUERY:
+
+ status = NbfProcessStatusQuery (
+ DeviceContext,
+ Address,
+ UiFrame,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+
+ break;
+
+ case NBF_CMD_ADD_NAME_RESPONSE:
+
+ status = ProcessAddNameResponse (
+ DeviceContext,
+ Address,
+ UiFrame,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+
+ break;
+
+ case NBF_CMD_NAME_RECOGNIZED:
+
+ status = ProcessNameRecognized (
+ DeviceContext,
+ Address,
+ UiFrame,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+
+ } /* switch on NetBIOS frame command code */
+
+ NbfDereferenceAddress ("Done", Address, AREF_PROCESS_UI); // done with previous address.
+
+ } else {
+
+ status = STATUS_ABANDONED;
+
+ }
+
+
+RasIndication:;
+
+ //
+ // Let the RAS clients have a crack at this if they want
+ //
+
+ if (DeviceContext->IndicationQueuesInUse) {
+
+ //
+ // If RAS has datagram indications posted, and this is a
+ // datagram that nobody wanted, then receive it anyway.
+ //
+
+ if ((UiFrame->Command == NBF_CMD_DATAGRAM) &&
+ (status == STATUS_ABANDONED)) {
+
+ *DatagramAddress = NULL;
+ status = STATUS_MORE_PROCESSING_REQUIRED;
+
+ } else if ((UiFrame->Command == NBF_CMD_ADD_NAME_QUERY) ||
+ (UiFrame->Command == NBF_CMD_ADD_GROUP_NAME_QUERY) ||
+ (UiFrame->Command == NBF_CMD_NAME_QUERY)) {
+
+ NbfActionQueryIndication(
+ DeviceContext,
+ UiFrame);
+
+ }
+ }
+
+
+ return status;
+
+} /* NbfProcessUi */
+
diff --git a/private/ntos/tdi/st/address.c b/private/ntos/tdi/st/address.c
new file mode 100644
index 000000000..3a4434a95
--- /dev/null
+++ b/private/ntos/tdi/st/address.c
@@ -0,0 +1,2247 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ address.c
+
+Abstract:
+
+ This module contains code which implements the TP_ADDRESS object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport address objects.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+//
+// Map all generic accesses to the same one.
+//
+
+STATIC GENERIC_MAPPING AddressGenericMapping =
+ { READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL };
+
+VOID
+StDestroyAddress(
+ IN PVOID Parameter
+ );
+
+
+NTSTATUS
+StOpenAddress(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens a file that points to an existing address object, or, if
+ the object doesn't exist, creates it (note that creation of the address
+ object includes registering the address, and may take many seconds to
+ complete, depending upon system configuration).
+
+ If the address already exists, and it has an ACL associated with it, the
+ ACL is checked for access rights before allowing creation of the address.
+
+Arguments:
+
+ DeviceObject - pointer to the device object describing the ST transport.
+
+ Irp - a pointer to the Irp used for the creation of the address.
+
+ IrpSp - a pointer to the Irp stack location.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ NTSTATUS status;
+ PTP_ADDRESS address;
+ PTP_ADDRESS_FILE addressFile;
+ PST_NETBIOS_ADDRESS networkName; // Network name string.
+ PFILE_FULL_EA_INFORMATION ea;
+ TRANSPORT_ADDRESS UNALIGNED *name;
+ TA_ADDRESS UNALIGNED *addressName;
+ TDI_ADDRESS_NETBIOS UNALIGNED *netbiosName;
+ ULONG DesiredShareAccess;
+ KIRQL oldirql;
+ PACCESS_STATE AccessState;
+ ACCESS_MASK GrantedAccess;
+ BOOLEAN AccessAllowed;
+ int i;
+ BOOLEAN found = FALSE;
+
+ DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+
+ //
+ // The network name is in the EA, passed in AssociatedIrp.SystemBuffer
+ //
+
+ ea = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+ if (ea == NULL) {
+ StPrint1("OpenAddress: IRP %lx has no EA\n", Irp);
+ return STATUS_NONEXISTENT_EA_ENTRY;
+ }
+
+ //
+ // this may be a valid name; parse the name from the EA and use it if OK.
+ //
+
+ name = (PTRANSPORT_ADDRESS)&ea->EaName[ea->EaNameLength+1];
+ addressName = (PTA_ADDRESS)&name->Address[0];
+
+ //
+ // The name can be passed with multiple entries; we'll take and use only
+ // the first one.
+ //
+
+ for (i=0;i<name->TAAddressCount;i++) {
+ if (addressName->AddressType == TDI_ADDRESS_TYPE_NETBIOS) {
+ if (addressName->AddressLength != 0) {
+ netbiosName = (PTDI_ADDRESS_NETBIOS)&addressName->Address[0];
+ networkName = (PST_NETBIOS_ADDRESS)ExAllocatePool (
+ NonPagedPool,
+ sizeof (ST_NETBIOS_ADDRESS));
+ if (networkName == NULL) {
+ PANIC ("StOpenAddress: PANIC! could not allocate networkName!\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TA_NETBIOS_ADDRESS), 1);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // get the name to local storage
+ //
+
+ if ((netbiosName->NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_GROUP) ||
+ (netbiosName->NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_QUICK_GROUP)) {
+ networkName->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_GROUP;
+ } else {
+ networkName->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ }
+ RtlCopyMemory (networkName->NetbiosName, netbiosName->NetbiosName, 16);
+
+ found = TRUE;
+ } else {
+ networkName = NULL;
+ found = TRUE;
+ }
+
+ break;
+
+ } else {
+
+ addressName = (PTA_ADDRESS)(addressName->Address +
+ addressName->AddressLength);
+
+ }
+
+ }
+
+ if (!found) {
+ StPrint1("OpenAddress: IRP %lx has no NETBIOS address\n", Irp);
+ return STATUS_NONEXISTENT_EA_ENTRY;
+ }
+
+ //
+ // get an address file structure to represent this address.
+ //
+
+ status = StCreateAddressFile (DeviceContext, &addressFile);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ //
+ // See if this address is already established. This call automatically
+ // increments the reference count on the address so that it won't disappear
+ // from underneath us after this call but before we have a chance to use it.
+ //
+ // To ensure that we don't create two address objects for the
+ // same address, we hold the device context AddressResource until
+ // we have found the address or created a new one.
+ //
+
+ ExAcquireResourceExclusive (&DeviceContext->AddressResource, TRUE);
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ address = StLookupAddress (DeviceContext, networkName);
+
+ if (address == NULL) {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ //
+ // This address doesn't exist. Create it, and start the process of
+ // registering it.
+ //
+
+ status = StCreateAddress (
+ DeviceContext,
+ networkName,
+ &address);
+
+ if (NT_SUCCESS (status)) {
+
+ //
+ // Initialize the shared access now. We use read access
+ // to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ IoSetShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &address->ShareAccess);
+
+
+ //
+ // Assign the security descriptor (need to do this with
+ // the spinlock released because the descriptor is not
+ // mapped. BUGBUG: Need to synchronize Assign and Access).
+ //
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ status = SeAssignSecurity(
+ NULL, // parent descriptor
+ AccessState->SecurityDescriptor,
+ &address->SecurityDescriptor,
+ FALSE, // is directory
+ &AccessState->SubjectSecurityContext,
+ &AddressGenericMapping,
+ PagedPool);
+
+ if (!NT_SUCCESS(status)) {
+
+ //
+ // Error, return status.
+ //
+
+ IoRemoveShareAccess (IrpSp->FileObject, &address->ShareAccess);
+ ExReleaseResource (&DeviceContext->AddressResource);
+ StDereferenceAddress ("Device context stopping", address);
+ StDereferenceAddressFile (addressFile);
+ return status;
+
+ }
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ //
+ // if the adapter isn't ready, we can't do any of this; get out
+ //
+
+ if (DeviceContext->State == DEVICECONTEXT_STATE_STOPPING) {
+ StDereferenceAddress ("Device context stopping", address);
+ StDereferenceAddressFile (addressFile);
+ status = STATUS_DEVICE_NOT_READY;
+
+ } else {
+
+ IrpSp->FileObject->FsContext = (PVOID)addressFile;
+ IrpSp->FileObject->FsContext2 =
+ (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+ addressFile->FileObject = IrpSp->FileObject;
+ addressFile->Irp = Irp;
+ addressFile->Address = address;
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock, &oldirql);
+ InsertTailList (&address->AddressFileDatabase, &addressFile->Linkage);
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+
+ //
+ // Begin address registration unless this is the broadcast
+ // address (which is a "fake" address with no corresponding
+ // Netbios address) or the reserved address, which we know
+ // is unique since it is based on the adapter address.
+ //
+
+ if ((networkName != NULL) &&
+ (!RtlEqualMemory (networkName->NetbiosName,
+ DeviceContext->ReservedNetBIOSAddress,
+ NETBIOS_NAME_LENGTH))) {
+
+ StRegisterAddress (address); // begin address registration.
+ status = STATUS_PENDING;
+
+ } else {
+
+ address->Flags &= ~ADDRESS_FLAGS_NEEDS_REG;
+ addressFile->Irp = NULL;
+ addressFile->State = ADDRESSFILE_STATE_OPEN;
+ status = STATUS_SUCCESS;
+
+ }
+
+ }
+
+ } else {
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ //
+ // If the address could not be created, and is not in the process of
+ // being created, then we can't open up an address.
+ //
+
+ if (networkName != NULL) {
+ ExFreePool (networkName);
+ }
+
+ StDereferenceAddressFile (addressFile);
+
+ }
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ //
+ // The address already exists. Check the ACL and see if we
+ // can access it. If so, simply use this address as our address.
+ //
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ AccessAllowed = SeAccessCheck(
+ address->SecurityDescriptor,
+ &AccessState->SubjectSecurityContext,
+ FALSE, // tokens locked
+ IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
+ (ACCESS_MASK)0, // previously granted
+ NULL, // privileges
+ &AddressGenericMapping,
+ Irp->RequestorMode,
+ &GrantedAccess,
+ &status);
+
+ if (AccessAllowed) {
+
+ //
+ // Access was successful, make sure Status is right.
+ //
+
+ status = STATUS_SUCCESS;
+
+ //
+ // Check that the name is of the correct type (unique vs. group)
+ // We don't need to check this for the broadcast address.
+ //
+
+ if (networkName != NULL) {
+ if (address->NetworkName->NetbiosNameType !=
+ networkName->NetbiosNameType) {
+
+ status = STATUS_DUPLICATE_NAME;
+
+ }
+ }
+
+ }
+
+
+ if (!NT_SUCCESS (status)) {
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ StDereferenceAddressFile (addressFile);
+
+ } else {
+
+ //
+ // Now check that we can obtain the desired share
+ // access. We use read access to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ status = IoCheckShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &address->ShareAccess,
+ TRUE);
+
+ if (!NT_SUCCESS (status)) {
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ StDereferenceAddressFile (addressFile);
+
+ } else {
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock, &oldirql);
+
+ //
+ // now, if the address registered, we simply return success after
+ // pointing the file object at the address file (which points to
+ // the address). If the address registration is pending, we mark
+ // the registration pending and let the registration completion
+ // routine complete the open. If the address is bad, we simply
+ // fail the open.
+ //
+
+ if ((address->Flags &
+ (ADDRESS_FLAGS_CONFLICT |
+ ADDRESS_FLAGS_REGISTERING |
+ ADDRESS_FLAGS_DEREGISTERING |
+ ADDRESS_FLAGS_DUPLICATE_NAME |
+ ADDRESS_FLAGS_NEEDS_REG |
+ ADDRESS_FLAGS_STOPPING |
+ ADDRESS_FLAGS_BAD_ADDRESS |
+ ADDRESS_FLAGS_CLOSED)) == 0) {
+
+ InsertTailList (
+ &address->AddressFileDatabase,
+ &addressFile->Linkage);
+
+ addressFile->Irp = NULL;
+ addressFile->Address = address;
+ addressFile->FileObject = IrpSp->FileObject;
+ addressFile->State = ADDRESSFILE_STATE_OPEN;
+
+ StReferenceAddress("open ready", address);
+
+ IrpSp->FileObject->FsContext = (PVOID)addressFile;
+ IrpSp->FileObject->FsContext2 =
+ (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ status = STATUS_SUCCESS;
+
+ } else {
+
+ //
+ // if the address is still registering, make the open pending.
+ //
+
+ if ((address->Flags & (ADDRESS_FLAGS_REGISTERING | ADDRESS_FLAGS_NEEDS_REG)) != 0) {
+
+ InsertTailList (
+ &address->AddressFileDatabase,
+ &addressFile->Linkage);
+
+ addressFile->Irp = Irp;
+ addressFile->Address = address;
+ addressFile->FileObject = IrpSp->FileObject;
+
+ StReferenceAddress("open registering", address);
+
+ IrpSp->FileObject->FsContext = (PVOID)addressFile;
+ IrpSp->FileObject->FsContext2 =
+ (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ status = STATUS_PENDING;
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ StDereferenceAddressFile (addressFile);
+
+ status = STATUS_DRIVER_INTERNAL_ERROR;
+
+ }
+ }
+ }
+ }
+
+ //
+ // Remove the reference from StLookupAddress.
+ //
+
+ StDereferenceAddress ("Done opening", address);
+ }
+
+ return status;
+} /* StOpenAddress */
+
+
+VOID
+StAllocateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS *TransportAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for a transport address. Some minimal
+ initialization is done on the address.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ Address - Pointer to a place where this routine will return a pointer
+ to a transport address structure. Returns NULL if no storage
+ can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PTP_ADDRESS Address;
+ PSEND_PACKET_TAG SendTag;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + sizeof(TP_ADDRESS)) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("ST: Could not allocate address: limit\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_ADDRESS), 101);
+ *TransportAddress = NULL;
+ return;
+ }
+
+ Address = (PTP_ADDRESS)ExAllocatePool (NonPagedPool, sizeof (TP_ADDRESS));
+ if (Address == NULL) {
+ PANIC("ST: Could not allocate address: no pool\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_ADDRESS), 201);
+ *TransportAddress = NULL;
+ return;
+ }
+ RtlZeroMemory (Address, sizeof(TP_ADDRESS));
+
+ DeviceContext->MemoryUsage += sizeof(TP_ADDRESS);
+ ++DeviceContext->AddressAllocated;
+
+ StAllocateSendPacket (DeviceContext, &(Address->Packet));
+ if (Address->Packet == NULL) {
+ ExFreePool (Address);
+ *TransportAddress = NULL;
+ return;
+ }
+ --DeviceContext->PacketAllocated; // AllocatePacket added one
+
+ //
+ // Need to modify the address packets to belong to
+ // the address, not the device context.
+ //
+
+ SendTag = (PSEND_PACKET_TAG)(Address->Packet->NdisPacket->ProtocolReserved);
+ SendTag->Type = TYPE_G_FRAME;
+ SendTag->Packet = Address->Packet;
+ SendTag->Owner = (PVOID)Address;
+
+
+ Address->Type = ST_ADDRESS_SIGNATURE;
+ Address->Size = sizeof (TP_ADDRESS);
+
+ Address->Provider = DeviceContext;
+ KeInitializeSpinLock (&Address->SpinLock);
+
+ InitializeListHead (&Address->ConnectionDatabase);
+ InitializeListHead (&Address->AddressFileDatabase);
+ InitializeListHead (&Address->SendDatagramQueue);
+
+ //
+ // For each address, allocate a receive packet, a receive buffer,
+ // and a UI frame.
+ //
+
+ StAddReceivePacket (DeviceContext);
+ StAddReceiveBuffer (DeviceContext);
+
+ *TransportAddress = Address;
+
+} /* StAllocateAddress */
+
+
+VOID
+StDeallocateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS TransportAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for a transport address.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ Address - Pointer to a transport address structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ if (TransportAddress->NetworkName != NULL) {
+ ExFreePool (TransportAddress->NetworkName);
+ }
+ StDeallocateSendPacket (DeviceContext, TransportAddress->Packet);
+ ++DeviceContext->PacketAllocated;
+
+ ExFreePool (TransportAddress);
+ --DeviceContext->AddressAllocated;
+ DeviceContext->MemoryUsage -= sizeof(TP_ADDRESS);
+
+ //
+ // Remove the resources which allocating this caused.
+ //
+
+ StRemoveReceivePacket (DeviceContext);
+ StRemoveReceiveBuffer (DeviceContext);
+
+} /* StDeallocateAddress */
+
+
+NTSTATUS
+StCreateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PST_NETBIOS_ADDRESS NetworkName,
+ OUT PTP_ADDRESS *Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a transport address and associates it with
+ the specified transport device context. The reference count in the
+ address is automatically set to 1, and the reference count of the
+ device context is incremented.
+
+ NOTE: This routine must be called with the DeviceContext
+ spinlock held.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ NetworkName - Pointer to an ST_NETBIOS_ADDRESS type containing the network
+ name to be associated with this address, if any.
+
+ Address - Pointer to a place where this routine will return a pointer
+ to a transport address structure.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_ADDRESS pAddress;
+ PLIST_ENTRY p;
+
+
+ p = RemoveHeadList (&DeviceContext->AddressPool);
+ if (p == &DeviceContext->AddressPool) {
+
+ if ((DeviceContext->AddressMaxAllocated == 0) ||
+ (DeviceContext->AddressAllocated < DeviceContext->AddressMaxAllocated)) {
+
+ StAllocateAddress (DeviceContext, &pAddress);
+
+ } else {
+
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_ADDRESS), 401);
+ pAddress = NULL;
+
+ }
+
+ if (pAddress == NULL) {
+ ++DeviceContext->AddressExhausted;
+ PANIC ("StCreateConnection: Could not allocate address object!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ } else {
+
+ pAddress = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+
+ }
+
+ ++DeviceContext->AddressInUse;
+ if (DeviceContext->AddressInUse > DeviceContext->AddressMaxInUse) {
+ ++DeviceContext->AddressMaxInUse;
+ }
+
+ DeviceContext->AddressTotal += DeviceContext->AddressInUse;
+ ++DeviceContext->AddressSamples;
+
+
+ //
+ // Initialize all of the static data for this address.
+ //
+
+ pAddress->ReferenceCount = 1;
+
+ pAddress->Flags = ADDRESS_FLAGS_NEEDS_REG;
+ InitializeListHead (&pAddress->AddressFileDatabase);
+
+ ExInitializeWorkItem(
+ &pAddress->DestroyAddressQueueItem,
+ StDestroyAddress,
+ (PVOID)pAddress);
+
+ pAddress->NetworkName = NetworkName;
+ if ((NetworkName != (PST_NETBIOS_ADDRESS)NULL) &&
+ (NetworkName->NetbiosNameType ==
+ TDI_ADDRESS_NETBIOS_TYPE_GROUP)) {
+
+ pAddress->Flags |= ADDRESS_FLAGS_GROUP;
+
+ }
+
+ //
+ // Now link this address into the specified device context's
+ // address database. To do this, we need to acquire the spin lock
+ // on the device context.
+ //
+
+ InsertTailList (&DeviceContext->AddressDatabase, &pAddress->Linkage);
+ pAddress->Provider = DeviceContext;
+ StReferenceDeviceContext ("Create Address", DeviceContext); // count refs to the device context.
+
+ *Address = pAddress; // return the address.
+ return STATUS_SUCCESS; // not finished yet.
+} /* StCreateAddress */
+
+
+VOID
+StRegisterAddress(
+ PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the registration process of the transport address
+ specified, if it has not already been started.
+
+Arguments:
+
+ Address - Pointer to a transport address object to begin registering
+ on the network.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PLIST_ENTRY p;
+ PIRP irp;
+ PTP_ADDRESS_FILE addressFile;
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ if (!(Address->Flags & ADDRESS_FLAGS_NEEDS_REG)) {
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return;
+ }
+
+ Address->Flags &= ~ADDRESS_FLAGS_NEEDS_REG;
+ Address->Flags |= ADDRESS_FLAGS_REGISTERING;
+
+ //
+ // Keep a reference on this address until the registration process
+ // completes or is aborted. It will be aborted in UFRAMES.C, in
+ // either the NAME_IN_CONFLICT or ADD_NAME_RESPONSE frame handlers.
+ //
+
+ StReferenceAddress ("start registration", Address);
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ //
+ // Normally we would add the name on the network, then
+ // do the following in our timeout logic, but for ST
+ // we assume that all names are OK.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ Address->Flags &= ~ADDRESS_FLAGS_REGISTERING;
+
+ p = Address->AddressFileDatabase.Flink;
+
+ while (p != &Address->AddressFileDatabase) {
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+ p = p->Flink;
+
+ if (addressFile->Irp != NULL) {
+ irp = addressFile->Irp;
+ addressFile->Irp = NULL;
+ addressFile->State = ADDRESSFILE_STATE_OPEN;
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ irp->IoStatus.Information = 0;
+ irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ //
+ // Dereference the address if we're all done.
+ //
+
+ StDereferenceAddress ("Timer, registered", Address);
+
+} /* StRegisterAddress */
+
+
+NTSTATUS
+StVerifyAddressObject (
+ IN PTP_ADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to verify that the pointer given us in a file
+ object is in fact a valid address file object. We also verify that the
+ address object pointed to by it is a valid address object, and reference
+ it to keep it from disappearing while we use it.
+
+Arguments:
+
+ AddressFile - potential pointer to a TP_ADDRESS_FILE object
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_ADDRESS otherwise
+
+--*/
+
+{
+ KIRQL oldirql;
+ NTSTATUS status = STATUS_SUCCESS;
+ PTP_ADDRESS address;
+
+ //
+ // try to verify the address file signature. If the signature is valid,
+ // verify the address pointed to by it and get the address spinlock.
+ // check the address's state, and increment the reference count if it's
+ // ok to use it. Note that the only time we return an error for state is
+ // if the address is closing.
+ //
+
+ try {
+
+ if ((AddressFile->Size == sizeof (TP_ADDRESS_FILE)) &&
+ (AddressFile->Type == ST_ADDRESSFILE_SIGNATURE) ) {
+// (AddressFile->State != ADDRESSFILE_STATE_CLOSING) ) {
+
+ address = AddressFile->Address;
+
+ if ((address->Size == sizeof (TP_ADDRESS)) &&
+ (address->Type == ST_ADDRESS_SIGNATURE) ) {
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock, &oldirql);
+
+ if ((address->Flags & ADDRESS_FLAGS_STOPPING) == 0) {
+
+ StReferenceAddress ("verify", address);
+
+ } else {
+
+ StPrint1("StVerifyAddress: A %lx closing\n", address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ } else {
+
+ StPrint1("StVerifyAddress: A %lx bad signature\n", address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } else {
+
+ StPrint1("StVerifyAddress: AF %lx bad signature\n", AddressFile);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ StPrint1("StVerifyAddress: AF %lx exception\n", address);
+ return GetExceptionCode();
+ }
+
+ return status;
+
+}
+
+VOID
+StDestroyAddress(
+ IN PVOID Parameter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a transport address and removes all references
+ made by it to other objects in the transport. The address structure
+ is returned to nonpaged system pool or our lookaside list. It is assumed
+ that the caller has already removed all addressfile structures associated
+ with this address.
+
+ The routine is called from a worker thread so that the security
+ descriptor can be accessed.
+
+ This worked thread is only queued by StfDerefAddress. The reason
+ for this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ Address - Pointer to a transport address structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_ADDRESS Address = (PTP_ADDRESS)Parameter;
+
+ DeviceContext = Address->Provider;
+
+ SeDeassignSecurity (&Address->SecurityDescriptor);
+
+ //
+ // Delink this address from its associated device context's address
+ // database. To do this we must spin lock on the device context object,
+ // not on the address.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ RemoveEntryList (&Address->Linkage);
+
+ //
+ // Now we can deallocate the transport address object.
+ //
+
+ DeviceContext->AddressTotal += DeviceContext->AddressInUse;
+ ++DeviceContext->AddressSamples;
+ --DeviceContext->AddressInUse;
+
+ if ((DeviceContext->AddressAllocated - DeviceContext->AddressInUse) >
+ DeviceContext->AddressInitAllocated) {
+ StDeallocateAddress (DeviceContext, Address);
+ } else {
+ InsertTailList (&DeviceContext->AddressPool, &Address->Linkage);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ StDereferenceDeviceContext ("Destroy Address", DeviceContext); // just housekeeping.
+
+} /* StDestroyAddress */
+
+
+VOID
+StRefAddress(
+ IN PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ ASSERT (Address->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement (&Address->ReferenceCount);
+
+} /* StRefAddress */
+
+
+VOID
+StDerefAddress(
+ IN PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport address by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ StDestroyAddress to remove it from the system.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&Address->ReferenceCount);
+
+ //
+ // If we have deleted all references to this address, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ ASSERT (result >= 0);
+
+ //
+ // Defer the actual call to StDestroyAddress to a thread
+ // so the paged security descriptor can be accessed at IRQL 0.
+ //
+
+ if (result == 0) {
+ ExQueueWorkItem(&Address->DestroyAddressQueueItem, DelayedWorkQueue);
+ }
+} /* StDerefAddress */
+
+
+
+VOID
+StAllocateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS_FILE *TransportAddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for an address file. Some
+ minimal initialization is done on the object.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ TransportAddressFile - Pointer to a place where this routine will return
+ a pointer to a transport address file structure. It returns NULL if no
+ storage can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PTP_ADDRESS_FILE AddressFile;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + sizeof(TP_ADDRESS_FILE)) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("ST: Could not allocate address file: limit\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_ADDRESS_FILE), 102);
+ *TransportAddressFile = NULL;
+ return;
+ }
+
+ AddressFile = (PTP_ADDRESS_FILE)ExAllocatePool (NonPagedPool, sizeof (TP_ADDRESS_FILE));
+ if (AddressFile == NULL) {
+ PANIC("ST: Could not allocate address file: no pool\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_ADDRESS_FILE), 202);
+ *TransportAddressFile = NULL;
+ return;
+ }
+ RtlZeroMemory (AddressFile, sizeof(TP_ADDRESS_FILE));
+
+ DeviceContext->MemoryUsage += sizeof(TP_ADDRESS_FILE);
+ ++DeviceContext->AddressFileAllocated;
+
+ AddressFile->Type = ST_ADDRESSFILE_SIGNATURE;
+ AddressFile->Size = sizeof (TP_ADDRESS_FILE);
+
+ InitializeListHead (&AddressFile->ReceiveDatagramQueue);
+ InitializeListHead (&AddressFile->ConnectionDatabase);
+
+ *TransportAddressFile = AddressFile;
+
+} /* StAllocateAddressFile */
+
+
+VOID
+StDeallocateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS_FILE TransportAddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for an address file.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ TransportAddressFile - Pointer to a transport address file structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ExFreePool (TransportAddressFile);
+ --DeviceContext->AddressFileAllocated;
+ DeviceContext->MemoryUsage -= sizeof(TP_ADDRESS_FILE);
+
+} /* StDeallocateAddressFile */
+
+
+NTSTATUS
+StCreateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS_FILE * AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates an address file from the pool of ther
+ specified device context. The reference count in the
+ address is automatically set to 1.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ AddressFile - Pointer to a place where this routine will return a pointer
+ to a transport address file structure.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PLIST_ENTRY p;
+ PTP_ADDRESS_FILE addressFile;
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ p = RemoveHeadList (&DeviceContext->AddressFilePool);
+ if (p == &DeviceContext->AddressFilePool) {
+
+ if ((DeviceContext->AddressFileMaxAllocated == 0) ||
+ (DeviceContext->AddressFileAllocated < DeviceContext->AddressFileMaxAllocated)) {
+
+ StAllocateAddressFile (DeviceContext, &addressFile);
+ } else {
+
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_ADDRESS_FILE), 402);
+ addressFile = NULL;
+
+ }
+
+ if (addressFile == NULL) {
+ ++DeviceContext->AddressFileExhausted;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ PANIC ("StCreateConnection: Could not allocate address file object!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ } else {
+
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+
+ }
+
+ ++DeviceContext->AddressFileInUse;
+ if (DeviceContext->AddressFileInUse > DeviceContext->AddressFileMaxInUse) {
+ ++DeviceContext->AddressFileMaxInUse;
+ }
+
+ DeviceContext->AddressFileTotal += DeviceContext->AddressFileInUse;
+ ++DeviceContext->AddressFileSamples;
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+
+ InitializeListHead (&addressFile->ConnectionDatabase);
+ addressFile->Address = NULL;
+ addressFile->FileObject = NULL;
+ addressFile->Provider = DeviceContext;
+ addressFile->State = ADDRESSFILE_STATE_OPENING;
+ addressFile->ConnectIndicationInProgress = FALSE;
+ addressFile->ReferenceCount = 1;
+ addressFile->CloseIrp = (PIRP)NULL;
+
+ //
+ // Initialize the request handlers.
+ //
+
+ addressFile->RegisteredConnectionHandler = FALSE;
+ addressFile->ConnectionHandler = TdiDefaultConnectHandler;
+ addressFile->ConnectionHandlerContext = NULL;
+ addressFile->RegisteredDisconnectHandler = FALSE;
+ addressFile->DisconnectHandler = TdiDefaultDisconnectHandler;
+ addressFile->DisconnectHandlerContext = NULL;
+ addressFile->RegisteredReceiveHandler = FALSE;
+ addressFile->ReceiveHandler = TdiDefaultReceiveHandler;
+ addressFile->ReceiveHandlerContext = NULL;
+ addressFile->RegisteredReceiveDatagramHandler = FALSE;
+ addressFile->ReceiveDatagramHandler = TdiDefaultRcvDatagramHandler;
+ addressFile->ReceiveDatagramHandlerContext = NULL;
+ addressFile->RegisteredExpeditedDataHandler = FALSE;
+ addressFile->ExpeditedDataHandler = TdiDefaultRcvExpeditedHandler;
+ addressFile->ExpeditedDataHandlerContext = NULL;
+ addressFile->RegisteredErrorHandler = FALSE;
+ addressFile->ErrorHandler = TdiDefaultErrorHandler;
+ addressFile->ErrorHandlerContext = NULL;
+
+
+ *AddressFile = addressFile;
+ return STATUS_SUCCESS;
+
+} /* StCreateAddress */
+
+
+NTSTATUS
+StDestroyAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys an address file and removes all references
+ made by it to other objects in the transport.
+
+ This routine is only called by StDereferenceAddressFile. The reason
+ for this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address file object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ AddressFile Pointer to a transport address file structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PTP_ADDRESS address;
+ PDEVICE_CONTEXT DeviceContext;
+ PIRP CloseIrp;
+
+
+ address = AddressFile->Address;
+ DeviceContext = AddressFile->Provider;
+
+ if (address) {
+
+ //
+ // This addressfile was associated with an address.
+ //
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock, &oldirql);
+
+ //
+ // remove this addressfile from the address list and disassociate it from
+ // the file handle.
+ //
+
+ RemoveEntryList (&AddressFile->Linkage);
+ InitializeListHead (&AddressFile->Linkage);
+
+ if (address->AddressFileDatabase.Flink == &address->AddressFileDatabase) {
+
+ //
+ // This is the last open of this address, it will close
+ // due to normal dereferencing but we have to set the
+ // CLOSING flag too to stop further references.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql1);
+ address->Flags |= ADDRESS_FLAGS_STOPPING;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql1);
+
+ }
+
+ AddressFile->Address = NULL;
+
+ AddressFile->FileObject->FsContext = NULL;
+ AddressFile->FileObject->FsContext2 = NULL;
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ //
+ // We will already have been removed from the ShareAccess
+ // of the owning address.
+ //
+
+ //
+ // Now dereference the owning address.
+ //
+
+ StDereferenceAddress ("Close", address); // remove the creation hold
+
+ }
+
+ //
+ // Save this for later completion.
+ //
+
+ CloseIrp = AddressFile->CloseIrp;
+
+ //
+ // return the addressFile to the pool of address files
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ DeviceContext->AddressFileTotal += DeviceContext->AddressFileInUse;
+ ++DeviceContext->AddressFileSamples;
+ --DeviceContext->AddressFileInUse;
+
+ if ((DeviceContext->AddressFileAllocated - DeviceContext->AddressFileInUse) >
+ DeviceContext->AddressFileInitAllocated) {
+ StDeallocateAddressFile (DeviceContext, AddressFile);
+ } else {
+ InsertTailList (&DeviceContext->AddressFilePool, &AddressFile->Linkage);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+
+ if (CloseIrp != (PIRP)NULL) {
+ CloseIrp->IoStatus.Information = 0;
+ CloseIrp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest (CloseIrp, IO_NETWORK_INCREMENT);
+ }
+
+ return STATUS_SUCCESS;
+
+} /* StDestroyAddress */
+
+
+VOID
+StReferenceAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ ASSERT (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement (&AddressFile->ReferenceCount);
+
+} /* StReferenceAddressFile */
+
+
+VOID
+StDereferenceAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences an address file by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ StDestroyAddressFile to remove it from the system.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&AddressFile->ReferenceCount);
+
+ //
+ // If we have deleted all references to this address file, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ ASSERT (result >= 0);
+
+ if (result == 0) {
+ StDestroyAddressFile (AddressFile);
+ }
+} /* StDerefAddressFile */
+
+
+PTP_ADDRESS
+StLookupAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PST_NETBIOS_ADDRESS NetworkName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the transport addresses defined for the given
+ device context and compares them with the specified NETWORK
+ NAME values. If an exact match is found, then a pointer to the
+ TP_ADDRESS object is returned, and as a side effect, the reference
+ count to the address object is incremented. If the address is not
+ found, then NULL is returned.
+
+ NOTE: This routine must be called with the DeviceContext
+ spinlock held.
+
+Arguments:
+
+ DeviceContext - Pointer to the device object and its extension.
+ NetworkName - Pointer to an ST_NETBIOS_ADDRESS structure containing the
+ network name.
+
+Return Value:
+
+ Pointer to the TP_ADDRESS object found, or NULL if not found.
+
+--*/
+
+{
+ PTP_ADDRESS address;
+ PLIST_ENTRY p;
+ ULONG i;
+
+
+ p = DeviceContext->AddressDatabase.Flink;
+
+ for (p = DeviceContext->AddressDatabase.Flink;
+ p != &DeviceContext->AddressDatabase;
+ p = p->Flink) {
+
+ address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+
+ if ((address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ continue;
+ }
+
+ //
+ // If the network name is specified and the network names don't match,
+ // then the addresses don't match.
+ //
+
+ i = NETBIOS_NAME_LENGTH; // length of a Netbios name
+
+ if (address->NetworkName != NULL) {
+ if (NetworkName != NULL) {
+ if (!RtlEqualMemory (
+ address->NetworkName->NetbiosName,
+ NetworkName->NetbiosName,
+ i)) {
+ continue;
+ }
+ } else {
+ continue;
+ }
+
+ } else {
+ if (NetworkName != NULL) {
+ continue;
+ }
+ }
+
+ //
+ // We found the match. Bump the reference count on the address, and
+ // return a pointer to the address object for the caller to use.
+ //
+
+ StReferenceAddress ("lookup", address);
+ return address;
+
+ } /* for */
+
+ //
+ // The specified address was not found.
+ //
+
+ return NULL;
+
+} /* StLookupAddress */
+
+
+PTP_CONNECTION
+StLookupRemoteName(
+ IN PTP_ADDRESS Address,
+ IN PUCHAR RemoteName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the connections associated with an
+ address, and determines if there is an connection
+ associated with the specific remote address.
+
+Arguments:
+
+ Address - Pointer to the address.
+
+ RemoteName - The 16-character Netbios name of the remote.
+
+Return Value:
+
+ The connection if one is found, NULL otherwise.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PLIST_ENTRY p;
+ PTP_CONNECTION connection;
+
+
+ //
+ // Hold the spinlock so the connection database doesn't
+ // change.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ for (p=Address->ConnectionDatabase.Flink;
+ p != &Address->ConnectionDatabase;
+ p=p->Flink) {
+
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressList);
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql1);
+
+ if (((connection->Flags2 & CONNECTION_FLAGS2_REMOTE_VALID) != 0) &&
+ ((connection->Flags & CONNECTION_FLAGS_READY) != 0)) {
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql1);
+
+ //
+ // If the remote names match, then return the
+ // connection.
+ //
+
+ if (RtlEqualMemory(RemoteName, connection->RemoteName, NETBIOS_NAME_LENGTH)) {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ StReferenceConnection ("Lookup found", connection);
+ return connection;
+
+ }
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql1);
+
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return (PTP_CONNECTION)NULL;
+
+}
+
+
+BOOLEAN
+StMatchNetbiosAddress(
+ IN PTP_ADDRESS Address,
+ IN PUCHAR NetBIOSName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to compare the addressing information in a
+ TP_ADDRESS object with the 16-byte NetBIOS name in a frame header.
+ If they match, then this routine returns TRUE, else it returns FALSE.
+
+Arguments:
+
+ Address - Pointer to a TP_ADDRESS object.
+
+ NetBIOSName - Pointer to a 16-byte character string (non-terminated),
+ or NULL if this is a received broadcast address.
+
+Return Value:
+
+ BOOLEAN, TRUE if match, FALSE if not.
+
+--*/
+
+{
+
+ PULONG AddressNamePointer;
+ ULONG UNALIGNED * NetbiosNamePointer;
+
+ //
+ // If this is address is the Netbios broadcast address, the comparison
+ // succeeds only if the passed in address is also NULL.
+ //
+
+ if (Address->NetworkName == NULL) {
+
+ if (NetBIOSName == NULL) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+
+ } else if (NetBIOSName == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Do a quick check of the first character in the names.
+ //
+
+ if (Address->NetworkName->NetbiosName[0] != NetBIOSName[0]) {
+ return FALSE;
+ }
+
+ //
+ // Now compare the 16-character Netbios names as ULONGs
+ // for speed. We know the one stored in the address
+ // structure is aligned.
+ //
+
+ AddressNamePointer = (PULONG)(Address->NetworkName->NetbiosName);
+ NetbiosNamePointer = (ULONG UNALIGNED *)NetBIOSName;
+
+ if ((AddressNamePointer[0] == NetbiosNamePointer[0]) &&
+ (AddressNamePointer[1] == NetbiosNamePointer[1]) &&
+ (AddressNamePointer[2] == NetbiosNamePointer[2]) &&
+ (AddressNamePointer[3] == NetbiosNamePointer[3])) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+
+} /* StMatchNetbiosAddress */
+
+
+VOID
+StStopAddress(
+ IN PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to terminate all activity on an address and
+ destroy the object. This is done in a graceful manner; i.e., all
+ outstanding addressfiles are removed from the addressfile database, and
+ all their activities are shut down.
+
+Arguments:
+
+ Address - Pointer to a TP_ADDRESS object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PTP_ADDRESS_FILE addressFile;
+ PLIST_ENTRY p;
+ PDEVICE_CONTEXT DeviceContext;
+
+ DeviceContext = Address->Provider;
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ //
+ // If we're already stopping this address, then don't try to do it again.
+ //
+
+ if (!(Address->Flags & ADDRESS_FLAGS_STOPPING)) {
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql1);
+ Address->Flags |= ADDRESS_FLAGS_STOPPING;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql1);
+
+ //
+ // Run down all addressfiles on this address. This
+ // will leave the address with no references
+ // potentially, but we don't need a temp one
+ // because every place that calls StStopAddress
+ // already has a temp reference.
+ //
+
+ while (!IsListEmpty (&Address->AddressFileDatabase)) {
+ p = RemoveHeadList (&Address->AddressFileDatabase);
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+
+ addressFile->Address = NULL;
+ addressFile->FileObject->FsContext = NULL;
+ addressFile->FileObject->FsContext2 = NULL;
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ //
+ // Run-down this addressFile without the lock on.
+ // We don't care about removing ourselves from
+ // the address' ShareAccess because we are
+ // tearing it down.
+ //
+
+ StStopAddressFile (addressFile, Address);
+
+ //
+ // return the addressFile to the pool of address files
+ //
+
+ StDereferenceAddressFile (addressFile);
+
+ StDereferenceAddress ("stop address", Address);
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ return;
+
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+} /* StStopAddress */
+
+
+NTSTATUS
+StStopAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile,
+ IN PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to terminate all activity on an AddressFile and
+ destroy the object. We remove every connection and datagram associated
+ with this addressfile from the address database and terminate their
+ activity. Then, if there are no other outstanding addressfiles open on
+ this address, the address will go away.
+
+Arguments:
+
+ AddressFile - pointer to the addressFile to be stopped
+
+ Address - the owning address for this addressFile (we do not depend upon
+ the pointer in the addressFile because we want this routine to be safe)
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the Irp does not
+ point to a real address.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ LIST_ENTRY localList;
+ PLIST_ENTRY p, pFlink;
+ PTP_REQUEST request;
+ PTP_CONNECTION connection;
+
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ if (AddressFile->State == ADDRESSFILE_STATE_CLOSING) {
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ return STATUS_SUCCESS;
+ }
+
+
+ AddressFile->State = ADDRESSFILE_STATE_CLOSING;
+ InitializeListHead (&localList);
+
+ //
+ // Run down all connections on this addressfile, and
+ // preform the equivalent of StDestroyAssociation
+ // on them.
+ //
+
+ while (!IsListEmpty (&AddressFile->ConnectionDatabase)) {
+ p = RemoveHeadList (&AddressFile->ConnectionDatabase);
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressFileList);
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql1);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) == 0) {
+
+ //
+ // It is in the process of being disassociated already.
+ //
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql1);
+ continue;
+ }
+
+ connection->Flags2 &= ~CONNECTION_FLAGS2_ASSOCIATED;
+ connection->Flags |= CONNECTION_FLAGS_DESTROY; // BUGBUG: Is this needed?
+ RemoveEntryList (&connection->AddressList);
+ InitializeListHead (&connection->AddressList);
+ InitializeListHead (&connection->AddressFileList);
+ connection->AddressFile = NULL;
+
+ StReferenceConnection ("Close AddressFile", connection);
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql1);
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ StStopConnection (connection, STATUS_LOCAL_DISCONNECT);
+ StDereferenceConnection ("Close AddressFile", connection);
+
+ StDereferenceAddress ("Destroy association", Address);
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ }
+
+ //
+ // now remove all of the datagrams owned by this addressfile
+ //
+
+ for (p = Address->SendDatagramQueue.Flink;
+ p != &Address->SendDatagramQueue;
+ p = pFlink ) {
+
+ pFlink = p->Flink;
+ request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ if ((PTP_ADDRESS_FILE)(request->Owner) == AddressFile) {
+ RemoveEntryList (p);
+ InitializeListHead (p);
+ InsertTailList (&localList, p);
+ }
+
+ }
+
+ for (p = AddressFile->ReceiveDatagramQueue.Flink;
+ p != &AddressFile->ReceiveDatagramQueue;
+ p = pFlink ) {
+
+ pFlink = p->Flink;
+ RemoveEntryList (p);
+ InitializeListHead (p);
+ InsertTailList (&localList, p);
+ }
+
+ //
+ // and finally, signal failure if the address file was waiting for a
+ // registration to complete (Irp is set to NULL when this succeeds).
+ //
+
+ if (AddressFile->Irp != NULL) {
+ PIRP irp=AddressFile->Irp;
+ AddressFile->Irp = NULL;
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ irp->IoStatus.Information = 0;
+ irp->IoStatus.Status = STATUS_DUPLICATE_NAME;
+
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ }
+
+ //
+ // cancel all the datagrams on this address file
+ //
+
+ while (!IsListEmpty (&localList)) {
+
+ p = RemoveHeadList (&localList);
+ request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+
+ StCompleteRequest (request, STATUS_NETWORK_NAME_DELETED, 0);
+
+ }
+
+
+} /* StStopAddressFile */
+
+
+NTSTATUS
+StCloseAddress(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to close the addressfile pointed to by a file
+ object. If there is any activity to be run down, we will run it down
+ before we terminate the addressfile. We remove every connection and
+ datagram associated with this addressfile from the address database
+ and terminate their activity. Then, if there are no other outstanding
+ addressfiles open on this address, the address will go away.
+
+Arguments:
+
+ Irp - the Irp Address - Pointer to a TP_ADDRESS object.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the Irp does not
+ point to a real address.
+
+--*/
+
+{
+ PTP_ADDRESS address;
+ PTP_ADDRESS_FILE addressFile;
+
+ addressFile = IrpSp->FileObject->FsContext;
+ addressFile->CloseIrp = Irp;
+
+ //
+ // We assume that addressFile has already been verified
+ // at this point.
+ //
+
+ address = addressFile->Address;
+ ASSERT (address);
+
+ //
+ // Remove us from the access info for this address.
+ //
+
+ ExAcquireResourceExclusive (&addressFile->Provider->AddressResource, TRUE);
+ IoRemoveShareAccess (addressFile->FileObject, &address->ShareAccess);
+ ExReleaseResource (&addressFile->Provider->AddressResource);
+
+
+ StStopAddressFile (addressFile, address);
+ StDereferenceAddressFile (addressFile);
+
+ //
+ // This removes a reference added by our caller.
+ //
+
+ StDereferenceAddress ("IRP_MJ_CLOSE", address);
+
+ return STATUS_PENDING;
+
+} /* StCloseAddress */
+
+
+NTSTATUS
+StSendDatagramsOnAddress(
+ PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to acquire a hold on the SendDatagramQueue of
+ the specified address, prepare the next datagram for shipment, and
+ call StSendUIMdlFrame to actually do the work. When StSendUIMdlFrame
+ is finished, it will cause an I/O completion routine in UFRAMES.C to
+ be called, at which time this routine is called again to handle the
+ next datagram in the pipeline.
+
+Arguments:
+
+ Address - a pointer to the address object to send the datagram on.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PLIST_ENTRY p;
+ PTP_REQUEST request;
+ PTA_NETBIOS_ADDRESS remoteTA;
+ PIO_STACK_LOCATION irpSp;
+ PDEVICE_CONTEXT DeviceContext;
+ PUCHAR SourceRouting;
+ UINT SourceRoutingLength;
+ UINT HeaderLength;
+ PST_HEADER StHeader;
+ PSEND_PACKET_TAG SendTag;
+
+ DeviceContext = Address->Provider;
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ StReferenceAddress ("Send datagram", Address); // keep it around
+
+ if (!(Address->Flags & ADDRESS_FLAGS_SEND_IN_PROGRESS)) {
+
+ //
+ // If the queue is empty, don't do anything.
+ //
+
+ if (IsListEmpty (&Address->SendDatagramQueue)) {
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ StDereferenceAddress ("Queue empty", Address);
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Mark the address's send datagram queue as held so that the
+ // MDL and ST header will not be used for two requests at the
+ // same time.
+ //
+
+ Address->Flags |= ADDRESS_FLAGS_SEND_IN_PROGRESS;
+
+ //
+ // We own the hold, and we've released the spinlock. So pick off the
+ // next datagram to be sent, and ship it.
+ //
+
+ p = Address->SendDatagramQueue.Flink;
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+
+ //
+ // If there is no remote Address specified (the Address specified has
+ // length 0), this is a broadcast datagram. If anything is specified, it
+ // will be used as a netbios address.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (request->IoRequestPacket);
+
+ remoteTA = ((PTDI_REQUEST_KERNEL_SENDDG)(&irpSp->Parameters))->
+ SendDatagramInformation->RemoteAddress;
+
+ //
+ // Build the MAC header. DATAGRAM frames go out as
+ // single-route source routing.
+ //
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SourceRouting,
+ &SourceRoutingLength);
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ Address->Packet->Header,
+ DeviceContext->MulticastAddress.Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof(ST_HEADER) + request->Buffer2Length,
+ SourceRouting,
+ SourceRoutingLength,
+ &HeaderLength);
+
+ //
+ // Build the header: 'G', dest, source
+ //
+
+ StHeader = (PST_HEADER)(&Address->Packet->Header[HeaderLength]);
+
+ StHeader->Signature = ST_SIGNATURE;
+ StHeader->Command = ST_CMD_DATAGRAM;
+ StHeader->Flags = 0;
+
+ RtlCopyMemory (StHeader->Source, Address->NetworkName->NetbiosName, 16);
+
+ if (remoteTA->Address[0].AddressLength == 0) {
+
+ //
+ // A broadcast datagram
+ //
+
+ RtlZeroMemory (StHeader->Destination, 16);
+ StHeader->Flags |= ST_FLAGS_BROADCAST;
+
+ } else {
+
+ RtlCopyMemory (StHeader->Destination, remoteTA->Address[0].Address[0].NetbiosName, 16);
+
+ }
+
+ HeaderLength += sizeof(ST_HEADER);
+
+ SendTag = (PSEND_PACKET_TAG)(Address->Packet->NdisPacket->ProtocolReserved);
+ SendTag->Type = TYPE_G_FRAME;
+ SendTag->Packet = Address->Packet;
+ SendTag->Owner = (PVOID)Address;
+
+ //
+ // Update our statistics for this datagram.
+ //
+
+ ++DeviceContext->DatagramsSent;
+ ADD_TO_LARGE_INTEGER(
+ &DeviceContext->DatagramBytesSent,
+ request->Buffer2Length);
+
+
+ //
+ // Munge the packet length, append the data, and send it.
+ //
+
+ StSetNdisPacketLength(Address->Packet->NdisPacket, HeaderLength);
+
+ if (request->Buffer2) {
+ NdisChainBufferAtBack (Address->Packet->NdisPacket, (PNDIS_BUFFER)request->Buffer2);
+ }
+
+ (VOID)StSendAddressFrame (
+ Address);
+
+
+ //
+ // The hold will be released in the I/O completion handler.
+ // At that time, if there is another outstanding datagram
+ // to send, it will reset the hold and call this routine again.
+ //
+
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ }
+
+ StDereferenceAddress ("Sent datagram", Address); // all done
+
+ return STATUS_SUCCESS;
+
+} /* StSendDatagramsOnAddress */
diff --git a/private/ntos/tdi/st/connect.c b/private/ntos/tdi/st/connect.c
new file mode 100644
index 000000000..8cb05b03b
--- /dev/null
+++ b/private/ntos/tdi/st/connect.c
@@ -0,0 +1,1137 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ connect.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiAccept
+ o TdiListen
+ o TdiConnect
+ o TdiDisconnect
+ o TdiAssociateAddress
+ o TdiDisassociateAddress
+ o OpenConnection
+ o CloseConnection
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+NTSTATUS
+StTdiAccept(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiAccept request for the transport provider.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_CONNECTION connection;
+ PIO_STACK_LOCATION irpSp;
+ KIRQL oldirql;
+ NTSTATUS status;
+
+ //
+ // Get the connection this is associated with; if there is none, get out.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // This adds a connection reference if successful.
+ //
+
+ status = StVerifyConnectionObject (connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ //
+ // just set the connection flags to allow reads and writes to proceed.
+ //
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+
+ //
+ // Turn off the stopping flag for this connection.
+ //
+
+ connection->Flags &= ~CONNECTION_FLAGS_STOPPING;
+ connection->Status = STATUS_PENDING;
+
+ connection->Flags2 |= CONNECTION_FLAGS2_ACCEPTED;
+
+
+ if (connection->AddressFile->ConnectIndicationInProgress) {
+ connection->Flags2 |= CONNECTION_FLAGS2_INDICATING;
+ }
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_WAIT_ACCEPT) != 0) {
+
+ //
+ // We previously completed a listen, now the user is
+ // coming back with an accept, Set this flag to allow
+ // the connection to proceed.
+ //
+
+ connection->Flags |= CONNECTION_FLAGS_READY;
+
+ INCREMENT_COUNTER (connection->Provider, OpenConnections);
+
+ //
+ // Set this flag to enable disconnect indications; once
+ // the client has accepted he expects those.
+ //
+
+ connection->Flags2 &= ~CONNECTION_FLAGS2_WAIT_ACCEPT;
+ connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+
+ StReferenceConnection("Pended listen completed", connection);
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+
+ } else {
+
+ //
+ // This accept is being called at some point before
+ // the link is up; directly from the connection handler
+ // or at some point slightly later.
+ //
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+
+ }
+
+ StDereferenceConnection ("Temp TdiAccept", connection);
+
+ return STATUS_SUCCESS;
+
+} /* StTdiAccept */
+
+
+NTSTATUS
+StTdiAssociateAddress(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the association of the connection and the address for
+ the user.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PFILE_OBJECT fileObject;
+ PTP_ADDRESS_FILE addressFile;
+ PTP_ADDRESS oldAddress;
+ PTP_CONNECTION connection;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL_ASSOCIATE parameters;
+ PDEVICE_CONTEXT deviceContext;
+
+ KIRQL oldirql, oldirql2;
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ //
+ // verify that the operation is taking place on a connection. At the same
+ // time we do this, we reference the connection. This ensures it does not
+ // get removed out from under us. Note also that we do the connection
+ // lookup within a try/except clause, thus protecting ourselves against
+ // really bogus handles
+ //
+
+ connection = irpSp->FileObject->FsContext;
+ status = StVerifyConnectionObject (connection);
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+
+ //
+ // Make sure this connection is ready to be associated.
+ //
+
+ oldAddress = (PTP_ADDRESS)NULL;
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql2);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) &&
+ ((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) {
+
+ //
+ // The connection is already associated with
+ // an active connection...bad!
+ //
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql2);
+ StDereferenceConnection ("Temp Ref Associate", connection);
+
+ return STATUS_INVALID_CONNECTION;
+
+ } else {
+
+ //
+ // See if there is an old association hanging around...
+ // this happens if the connection has been disassociated,
+ // but not closed.
+ //
+
+ if (connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) {
+
+ //
+ // Save this; since it is non-null this address
+ // will be dereferenced after the connection
+ // spinlock is released.
+ //
+
+ oldAddress = connection->AddressFile->Address;
+
+ //
+ // Remove the old association.
+ //
+
+ connection->Flags2 &= ~CONNECTION_FLAGS2_ASSOCIATED;
+ RemoveEntryList (&connection->AddressList);
+ RemoveEntryList (&connection->AddressFileList);
+ InitializeListHead (&connection->AddressList);
+ InitializeListHead (&connection->AddressFileList);
+ connection->AddressFile = NULL;
+
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql2);
+
+ //
+ // If we removed an old association, dereference the
+ // address.
+ //
+
+ if (oldAddress != (PTP_ADDRESS)NULL) {
+
+ StDereferenceAddress("Removed old association", oldAddress);
+
+ }
+
+
+ deviceContext = connection->Provider;
+
+ parameters = (PTDI_REQUEST_KERNEL_ASSOCIATE)&irpSp->Parameters;
+
+ //
+ // get a pointer to the address File Object, which points us to the
+ // transport's address object, which is where we want to put the
+ // connection.
+ //
+
+ status = ObReferenceObjectByHandle (
+ parameters->AddressHandle,
+ 0L,
+ 0,
+ KernelMode,
+ (PVOID *) &fileObject,
+ NULL);
+
+ if (NT_SUCCESS(status)) {
+
+ //
+ // we might have one of our address objects; verify that.
+ //
+
+ addressFile = fileObject->FsContext;
+
+ if (NT_SUCCESS (StVerifyAddressObject (addressFile))) {
+
+ //
+ // have an address and connection object. Add the connection to the
+ // address object database. Also add the connection to the address
+ // file object db (used primarily for cleaning up). Reference the
+ // address to account for one more reason for it staying open.
+ //
+
+ ACQUIRE_SPIN_LOCK (&addressFile->Address->SpinLock, &oldirql);
+ if ((addressFile->Address->Flags & ADDRESS_FLAGS_STOPPING) == 0) {
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql2);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) {
+
+ StReferenceAddress (
+ "Connection associated",
+ addressFile->Address);
+
+ InsertTailList (
+ &addressFile->Address->ConnectionDatabase,
+ &connection->AddressList);
+
+ InsertTailList (
+ &addressFile->ConnectionDatabase,
+ &connection->AddressFileList);
+
+ connection->AddressFile = addressFile;
+ connection->Flags2 |= CONNECTION_FLAGS2_ASSOCIATED;
+ connection->Flags2 &= ~CONNECTION_FLAGS2_DISASSOCIATED;
+
+ if (addressFile->ConnectIndicationInProgress) {
+ connection->Flags2 |= CONNECTION_FLAGS2_INDICATING;
+ }
+
+ status = STATUS_SUCCESS;
+
+ } else {
+
+ //
+ // The connection is closing, stop the
+ // association.
+ //
+
+ status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql2);
+
+ } else {
+
+ status = STATUS_INVALID_HANDLE;
+ }
+
+ RELEASE_SPIN_LOCK (&addressFile->Address->SpinLock, oldirql);
+
+ StDereferenceAddress ("Temp associate", addressFile->Address);
+
+ } else {
+
+ status = STATUS_INVALID_HANDLE;
+ }
+
+ //
+ // Note that we don't keep a reference to this file object around.
+ // That's because the IO subsystem manages the object for us; we simply
+ // want to keep the association. We only use this association when the
+ // IO subsystem has asked us to close one of the file object, and then
+ // we simply remove the association.
+ //
+
+ ObDereferenceObject (fileObject);
+
+ } else {
+ status = STATUS_INVALID_HANDLE;
+ }
+
+ StDereferenceConnection ("Temp Ref Associate", connection);
+
+ return status;
+
+} /* TdiAssociateAddress */
+
+
+NTSTATUS
+StTdiDisassociateAddress(
+ IN PIRP Irp
+ )
+/*++
+
+Routine Description:
+
+ This routine performs the disassociation of the connection and the address
+ for the user. If the connection has not been stopped, it will be stopped
+ here.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ KIRQL oldirql;
+ PIO_STACK_LOCATION irpSp;
+ PTP_CONNECTION connection;
+ NTSTATUS status;
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // If successful this adds a reference.
+ //
+
+ status = StVerifyConnectionObject (connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+ if ((connection->Flags & CONNECTION_FLAGS_STOPPING) == 0) {
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ StStopConnection (connection, STATUS_LOCAL_DISCONNECT);
+
+ } else {
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ }
+
+ //
+ // and now we disassociate the address. This only removes
+ // the appropriate reference for the connection, the
+ // actually disassociation will be done later.
+ //
+ // The DISASSOCIATED flag is used to make sure that
+ // only one person removes this reference.
+ //
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+ if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) &&
+ ((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) {
+ connection->Flags2 |= CONNECTION_FLAGS2_DISASSOCIATED;
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ } else {
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ }
+
+ StDereferenceConnection ("Temp use in Associate", connection);
+
+ return STATUS_SUCCESS;
+
+} /* TdiDisassociateAddress */
+
+
+NTSTATUS
+StTdiConnect(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiConnect request for the transport provider.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTP_CONNECTION connection;
+ PSTRING GeneralBroadcastSourceRoute = NULL; // BUGBUG: define this later.
+ LARGE_INTEGER timeout = {0,0};
+ KIRQL oldirql, cancelirql;
+ PTP_REQUEST tpRequest;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL parameters;
+ PTA_NETBIOS_ADDRESS RemoteAddress;
+ ULONG RemoteAddressLength;
+
+ //
+ // is the file object a connection?
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // If successful this adds a reference.
+ //
+
+ status = StVerifyConnectionObject (connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ parameters = (PTDI_REQUEST_KERNEL)(&irpSp->Parameters);
+
+ //
+ // fix up the timeout if required; no connect request should take more
+ // than 15 seconds if there is someone out there. We'll assume that's
+ // what the user wanted if they specify -1 as the timer length.
+ //
+
+ if (parameters->RequestSpecific != NULL) {
+ if ((((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart == -1) &&
+ (((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart == -1)) {
+
+ timeout.LowPart = (ULONG)(-TDI_TIMEOUT_CONNECT * 10000000L); // n * 10 ** 7 => 100ns units
+ if (timeout.LowPart != 0) {
+ timeout.HighPart = -1L;
+ } else {
+ timeout.HighPart = 0;
+ }
+
+ } else {
+
+ timeout.LowPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart;
+ timeout.HighPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart;
+ }
+ }
+
+ //
+ // Check that the remote is a Netbios address.
+ //
+
+ RemoteAddress = (PTA_NETBIOS_ADDRESS)
+ (parameters->RequestConnectionInformation->RemoteAddress);
+
+ if (RemoteAddress->Address[0].AddressType != TDI_ADDRESS_TYPE_NETBIOS) {
+
+ StDereferenceConnection ("Not Netbios", connection);
+ return STATUS_BAD_NETWORK_PATH; // don't even try to find it.
+
+ }
+
+ //
+ // copy the called address someplace we can use it.
+ //
+
+ RemoteAddressLength = parameters->RequestConnectionInformation->RemoteAddressLength;
+
+ if (RemoteAddressLength > sizeof(TA_NETBIOS_ADDRESS)) {
+ RemoteAddressLength = sizeof(TA_NETBIOS_ADDRESS);
+ }
+
+ RtlCopyMemory(
+ connection->CalledAddress.NetbiosName,
+ RemoteAddress->Address[0].Address[0].NetbiosName,
+ 16);
+
+ //
+ // We need a request object to keep track of this TDI request.
+ // Attach this request to the new connection object.
+ //
+
+ status = StCreateRequest (
+ Irp, // IRP for this request.
+ connection, // context.
+ REQUEST_FLAGS_CONNECTION, // partial flags.
+ NULL,
+ 0,
+ timeout,
+ &tpRequest);
+
+ if (!NT_SUCCESS (status)) { // couldn't make the request.
+ StDereferenceConnection ("Throw away", connection);
+ return status; // return with failure.
+ } else {
+
+ // Reference the connection since StDestroyRequest derefs it.
+
+ StReferenceConnection("For connect request", connection);
+
+ tpRequest->Owner = ConnectionType;
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock,&oldirql);
+ if ((connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
+ RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
+ IoReleaseCancelSpinLock (cancelirql);
+ StCompleteRequest (
+ tpRequest,
+ connection->Status,
+ 0);
+ StDereferenceConnection("Temporary Use 1", connection);
+ return STATUS_PENDING;
+ } else {
+ InsertTailList (&connection->InProgressRequest,&tpRequest->Linkage);
+
+ connection->Flags |= CONNECTION_FLAGS_CONNECTOR; // we're the initiator.
+
+ connection->Flags &= ~CONNECTION_FLAGS_STOPPING;
+ connection->Status = STATUS_PENDING;
+
+ connection->Flags2 &= ~CONNECTION_FLAGS2_INDICATING;
+ RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
+
+ //
+ // Check if the IRP has been cancelled.
+ //
+
+ if (Irp->Cancel) {
+ Irp->CancelIrql = cancelirql;
+ StCancelConnection((PDEVICE_OBJECT)(connection->Provider), Irp);
+ StDereferenceConnection ("IRP cancelled", connection); // release lookup hold.
+ return STATUS_PENDING;
+ }
+
+ Irp->CancelRoutine = StCancelConnection;
+ IoReleaseCancelSpinLock(cancelirql);
+
+ }
+ }
+
+ status = StSendConnect (
+ connection);
+
+ if (!NT_SUCCESS(status)) { // can't send the name request
+ StStopConnection (connection, status);
+ StDereferenceConnection("Temporary Use 2", connection);
+
+ //
+ // Note that this return status isn't really a lie. We are waiting
+ // for the connection to run down.
+ //
+
+ return STATUS_PENDING;
+ }
+
+
+ StDereferenceConnection("Temporary Use 3", connection);
+
+ return STATUS_PENDING; // things are started.
+
+} /* TdiConnect */
+
+
+NTSTATUS
+StTdiDisconnect(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiDisconnect request for the transport provider.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_CONNECTION connection;
+ LARGE_INTEGER timeout;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL parameters;
+ KIRQL oldirql;
+ NTSTATUS status;
+
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // If successful this adds a reference.
+ //
+
+ status = StVerifyConnectionObject (connection);
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+
+ //
+ // if the connection is currently stopping, there's no reason to blow
+ // it away...
+ //
+
+ if ((connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ StDereferenceConnection ("Ignoring disconnect", connection); // release our lookup reference.
+ return connection->Status;
+
+ } else {
+ connection->Flags2 &= ~ (CONNECTION_FLAGS2_ACCEPTED |
+ CONNECTION_FLAGS2_PRE_ACCEPT |
+ CONNECTION_FLAGS2_WAIT_ACCEPT);
+ connection->Flags2 |= CONNECTION_FLAGS2_DISCONNECT;
+
+ //
+ // Set this flag so the disconnect IRP is completed.
+ //
+ // BUGBUG: If the connection goes down before we can
+ // call StStopConnection with STATUS_LOCAL_DISCONNECT,
+ // the disconnect IRP won't get completed.
+ //
+
+ connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+
+ connection->DisconnectIrp = Irp;
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ }
+
+ //
+ // fix up the timeout if required; no disconnect request should take very
+ // long. However, the user can cause the timeout to not happen if they
+ // desire that.
+ //
+
+ parameters = (PTDI_REQUEST_KERNEL)(&irpSp->Parameters);
+
+ //
+ // fix up the timeout if required; no disconnect request should take more
+ // than 15 seconds. We'll assume that's what the user wanted if they
+ // specify -1 as the timer.
+ //
+
+ if (parameters->RequestSpecific != NULL) {
+ if ((((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart == -1) &&
+ (((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart == -1)) {
+
+ timeout.LowPart = (ULONG)(-TDI_TIMEOUT_DISCONNECT * 10000000L); // n * 10 ** 7 => 100ns units
+ if (timeout.LowPart != 0) {
+ timeout.HighPart = -1L;
+ } else {
+ timeout.HighPart = 0;
+ }
+
+ } else {
+ timeout.LowPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart;
+ timeout.HighPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart;
+ }
+ }
+
+ //
+ // Now the reason for the disconnect
+ //
+
+ if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_RELEASE) {
+ connection->Flags |= CONNECTION_FLAGS_DESTROY;
+ } else if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_ABORT) {
+ connection->Flags |= CONNECTION_FLAGS_ABORT;
+ } else if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_WAIT) {
+ connection->Flags |= CONNECTION_FLAGS_ORDREL;
+ }
+
+ //
+ // This will get passed to IoCompleteRequest during TdiDestroyConnection
+ //
+
+ StStopConnection (connection, STATUS_LOCAL_DISCONNECT); // starts the abort sequence.
+ StDereferenceConnection ("Disconnecting", connection); // release our lookup reference.
+
+ //
+ // This request will be completed by TdiDestroyConnection once
+ // the connection reference count drops to 0.
+ //
+
+ return STATUS_PENDING;
+} /* TdiDisconnect */
+
+
+NTSTATUS
+StTdiListen(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiListen request for the transport provider.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTP_CONNECTION connection;
+ LARGE_INTEGER timeout = {0,0};
+ KIRQL oldirql, cancelirql;
+ PTP_REQUEST tpRequest;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL_LISTEN parameters;
+
+ //
+ // validate this connection
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // If successful this adds a reference.
+ //
+
+ status = StVerifyConnectionObject (connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ parameters = (PTDI_REQUEST_KERNEL_LISTEN)&irpSp->Parameters;
+
+ //
+ // We need a request object to keep track of this TDI request.
+ // Attach this request to the new connection object.
+ //
+
+ status = StCreateRequest (
+ Irp, // IRP for this request.
+ connection, // context.
+ REQUEST_FLAGS_CONNECTION, // partial flags.
+ NULL,
+ 0,
+ timeout, // timeout value (can be 0).
+ &tpRequest);
+
+
+ if (!NT_SUCCESS (status)) { // couldn't make the request.
+
+ StDereferenceConnection ("For create", connection);
+ return status; // return with failure.
+ }
+
+ // Reference the connection since StDestroyRequest derefs it.
+
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+ tpRequest->Owner = ConnectionType;
+
+ StReferenceConnection("For listen request", connection);
+
+ if ((connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ StCompleteRequest (
+ tpRequest,
+ connection->Status,
+ 0);
+ StDereferenceConnection("Temp create", connection);
+ return STATUS_PENDING;
+
+ } else {
+
+ InsertTailList (&connection->InProgressRequest,&tpRequest->Linkage);
+ connection->Flags |= CONNECTION_FLAGS_LISTENER | // we're the passive one.
+ CONNECTION_FLAGS_WAIT_LISTEN; // waiting for a connect
+ connection->Flags2 &= ~CONNECTION_FLAGS2_INDICATING;
+ connection->Flags &= ~CONNECTION_FLAGS_STOPPING;
+ connection->Status = STATUS_PENDING;
+
+ //
+ // If TDI_QUERY_ACCEPT is not set, then we set PRE_ACCEPT to
+ // indicate that when the listen completes we do not have to
+ // wait for a TDI_ACCEPT to continue.
+ //
+
+ if ((parameters->RequestFlags & TDI_QUERY_ACCEPT) == 0) {
+ connection->Flags2 |= CONNECTION_FLAGS2_PRE_ACCEPT;
+ }
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
+
+ //
+ // Check if the IRP has been cancelled.
+ //
+
+ if (Irp->Cancel) {
+ Irp->CancelIrql = cancelirql;
+ StCancelConnection((PDEVICE_OBJECT)(connection->Provider), Irp);
+ StDereferenceConnection ("IRP cancelled", connection); // release lookup hold.
+ return STATUS_PENDING;
+ }
+
+ Irp->CancelRoutine = StCancelConnection;
+ IoReleaseCancelSpinLock(cancelirql);
+
+ }
+
+ //
+ // Wait for an incoming NAME_QUERY frame. The remainder of the
+ // connectionless protocol to set up a connection is processed
+ // in the NAME_QUERY frame handler.
+ //
+
+ StDereferenceConnection("Temp create", connection);
+
+ return STATUS_PENDING; // things are started.
+} /* TdiListen */
+
+
+NTSTATUS
+StOpenConnection (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to open a connection. Note that the connection that
+ is open is of little use until associated with an address; until then,
+ the only thing that can be done with it is close it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+ IrpSp - Pointer to current IRP stack frame.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ NTSTATUS status;
+ PTP_CONNECTION connection;
+ PFILE_FULL_EA_INFORMATION ea;
+
+ UNREFERENCED_PARAMETER (Irp);
+
+ DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+
+ //
+ // First, try to make a connection object to represent this pending
+ // connection. Then fill in the relevant fields.
+ // In addition to the creation, if successful StCreateConnection
+ // will create a second reference which is removed once the request
+ // references the connection, or if the function exits before that.
+
+ status = StCreateConnection (DeviceContext, &connection);
+ if (!NT_SUCCESS (status)) {
+ return status; // sorry, we couldn't make one.
+ }
+
+ //
+ // set the connection context so we can connect the user to this data
+ // structure
+ //
+
+ ea = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+ RtlCopyMemory (
+ &connection->Context,
+ &ea->EaName[ea->EaNameLength+1],
+ sizeof (PVOID));
+
+ //
+ // let file object point at connection and connection at file object
+ //
+
+ IrpSp->FileObject->FsContext = (PVOID)connection;
+ IrpSp->FileObject->FsContext2 = (PVOID)TDI_CONNECTION_FILE;
+ connection->FileObject = IrpSp->FileObject;
+
+ return status;
+
+} /* StOpenConnection */
+
+
+NTSTATUS
+StCloseConnection (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to close a connection. There may be actions in
+ progress on this connection, so we note the closing IRP, mark the
+ connection as closing, and complete it somewhere down the road (when all
+ references have been removed).
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+ IrpSp - Pointer to current IRP stack frame.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ KIRQL oldirql;
+ PTP_CONNECTION connection;
+
+ UNREFERENCED_PARAMETER (DeviceObject);
+ UNREFERENCED_PARAMETER (Irp);
+
+ //
+ // is the file object a connection?
+ //
+
+ connection = IrpSp->FileObject->FsContext;
+
+
+ //
+ // We duplicate the code from VerifyConnectionObject,
+ // although we don't actually call that since it does
+ // a reference, which we don't want (to avoid bouncing
+ // the reference count up from 0 if this is a dead
+ // link).
+ //
+
+ try {
+
+ if ((connection->Size == sizeof (TP_CONNECTION)) &&
+ (connection->Type == ST_CONNECTION_SIGNATURE)) {
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) {
+
+ status = STATUS_SUCCESS;
+
+ } else {
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+
+ } else {
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ return GetExceptionCode();
+ }
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ //
+ // We recognize it; is it closing already?
+ //
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) != 0) {
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ StDereferenceConnection("Temp Close", connection);
+ return STATUS_INVALID_CONNECTION;
+ }
+
+ connection->Flags2 |= CONNECTION_FLAGS2_CLOSING;
+
+ //
+ // if there is activity on the connection, tear it down.
+ //
+
+ if ((connection->Flags & CONNECTION_FLAGS_STOPPING) == 0) {
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ StStopConnection (connection, STATUS_LOCAL_DISCONNECT);
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+ }
+
+ //
+ // If the connection is still associated, disassociate it.
+ //
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) &&
+ ((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) {
+ connection->Flags2 |= CONNECTION_FLAGS2_DISASSOCIATED;
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ } else {
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ }
+
+
+ //
+ // Save this to complete the IRP later.
+ //
+
+ connection->CloseIrp = Irp;
+
+ //
+ // make it impossible to use this connection from the file object
+ //
+
+ IrpSp->FileObject->FsContext = NULL;
+ IrpSp->FileObject->FsContext2 = NULL;
+ connection->FileObject = NULL;
+
+ //
+ // dereference for the creation. Note that this dereference
+ // here won't have any effect until the regular reference count
+ // hits zero.
+ //
+
+ StDereferenceConnectionSpecial (" Closing Connection", connection);
+
+ return STATUS_PENDING;
+
+} /* StCloseConnection */
+
diff --git a/private/ntos/tdi/st/connobj.c b/private/ntos/tdi/st/connobj.c
new file mode 100644
index 000000000..27c28665a
--- /dev/null
+++ b/private/ntos/tdi/st/connobj.c
@@ -0,0 +1,1375 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ connobj.c
+
+Abstract:
+
+ This module contains code which implements the TP_CONNECTION object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport connection objects.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+
+VOID
+StAllocateConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_CONNECTION *TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for a transport connection. Some
+ minimal initialization is done.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - the device context for this connection to be
+ associated with.
+
+ TransportConnection - Pointer to a place where this routine will
+ return a pointer to a transport connection structure. Returns
+ NULL if the storage cannot be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PTP_CONNECTION Connection;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + sizeof(TP_CONNECTION)) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("ST: Could not allocate connection: limit\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_CONNECTION), 103);
+ *TransportConnection = NULL;
+ return;
+ }
+
+ Connection = (PTP_CONNECTION)ExAllocatePool (NonPagedPool,
+ sizeof (TP_CONNECTION));
+ if (Connection == NULL) {
+ PANIC("ST: Could not allocate connection: no pool\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_CONNECTION), 203);
+ *TransportConnection = NULL;
+ return;
+ }
+ RtlZeroMemory (Connection, sizeof(TP_CONNECTION));
+
+ DeviceContext->MemoryUsage += sizeof(TP_CONNECTION);
+ ++DeviceContext->ConnectionAllocated;
+
+ Connection->Type = ST_CONNECTION_SIGNATURE;
+ Connection->Size = sizeof (TP_CONNECTION);
+
+ Connection->Provider = DeviceContext;
+ Connection->ProviderInterlock = &DeviceContext->Interlock;
+ KeInitializeSpinLock (&Connection->SpinLock);
+
+ InitializeListHead (&Connection->LinkList);
+ InitializeListHead (&Connection->AddressFileList);
+ InitializeListHead (&Connection->AddressList);
+ InitializeListHead (&Connection->PacketWaitLinkage);
+ InitializeListHead (&Connection->PacketizeLinkage);
+ InitializeListHead (&Connection->SendQueue);
+ InitializeListHead (&Connection->ReceiveQueue);
+ InitializeListHead (&Connection->InProgressRequest);
+
+ StAddSendPacket (DeviceContext);
+
+ *TransportConnection = Connection;
+
+} /* StAllocateConnection */
+
+
+VOID
+StDeallocateConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for a transport connection.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - the device context for this connection to be
+ associated with.
+
+ TransportConnection - Pointer to a transport connection structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ExFreePool (TransportConnection);
+ --DeviceContext->ConnectionAllocated;
+ DeviceContext->MemoryUsage -= sizeof(TP_CONNECTION);
+
+ StRemoveSendPacket (DeviceContext);
+
+} /* StDeallocateConnection */
+
+
+NTSTATUS
+StCreateConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_CONNECTION *TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a transport connection. The reference count in the
+ connection is automatically set to 1, and the reference count in the
+ DeviceContext is incremented.
+
+Arguments:
+
+ Address - the address for this connection to be associated with.
+
+ TransportConnection - Pointer to a place where this routine will
+ return a pointer to a transport connection structure.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_CONNECTION Connection;
+ KIRQL oldirql;
+ PLIST_ENTRY p;
+ UINT TempDataLen;
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ p = RemoveHeadList (&DeviceContext->ConnectionPool);
+ if (p == &DeviceContext->ConnectionPool) {
+
+ if ((DeviceContext->ConnectionMaxAllocated == 0) ||
+ (DeviceContext->ConnectionAllocated < DeviceContext->ConnectionMaxAllocated)) {
+
+ StAllocateConnection (DeviceContext, &Connection);
+
+ } else {
+
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_CONNECTION), 403);
+ Connection = NULL;
+
+ }
+
+ if (Connection == NULL) {
+ ++DeviceContext->ConnectionExhausted;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ PANIC ("StCreateConnection: Could not allocate connection object!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ } else {
+
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+
+ }
+
+ ++DeviceContext->ConnectionInUse;
+ if (DeviceContext->ConnectionInUse > DeviceContext->ConnectionMaxInUse) {
+ ++DeviceContext->ConnectionMaxInUse;
+ }
+
+ DeviceContext->ConnectionTotal += DeviceContext->ConnectionInUse;
+ ++DeviceContext->ConnectionSamples;
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+
+ //
+ // We have two references; one is for creation, and the
+ // other is a temporary one so that the connection won't
+ // go away before the creator has a chance to access it.
+ //
+
+ Connection->SpecialRefCount = 1;
+ Connection->ReferenceCount = -1; // this is -1 based
+
+ //
+ // Initialize the request queues & components of this connection.
+ //
+
+ InitializeListHead (&Connection->SendQueue);
+ InitializeListHead (&Connection->ReceiveQueue);
+ InitializeListHead (&Connection->InProgressRequest);
+ InitializeListHead (&Connection->AddressList);
+ InitializeListHead (&Connection->AddressFileList);
+ Connection->SpecialReceiveIrp = (PIRP)NULL;
+ Connection->Flags = 0;
+ Connection->Flags2 = 0;
+ Connection->MessageBytesReceived = (USHORT)0; // no data yet
+ Connection->MessageBytesAcked = (USHORT)0;
+ Connection->Context = NULL; // no context yet.
+ Connection->Status = STATUS_PENDING; // default StStopConnection status.
+ Connection->SendState = CONNECTION_SENDSTATE_IDLE;
+ Connection->CurrentReceiveRequest = (PTP_REQUEST)NULL;
+ Connection->DisconnectIrp = (PIRP)NULL;
+ Connection->CloseIrp = (PIRP)NULL;
+ Connection->AddressFile = NULL;
+ Connection->IndicationInProgress = FALSE;
+
+ MacReturnMaxDataSize(
+ &DeviceContext->MacInfo,
+ NULL,
+ 0,
+ DeviceContext->MaxSendPacketSize,
+ &TempDataLen);
+ Connection->MaximumDataSize = TempDataLen - sizeof(ST_HEADER);
+
+ StReferenceDeviceContext ("Create Connection", DeviceContext);
+
+ *TransportConnection = Connection; // return the connection.
+
+ return STATUS_SUCCESS;
+} /* StCreateConnection */
+
+
+NTSTATUS
+StVerifyConnectionObject (
+ IN PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to verify that the pointer given us in a file
+ object is in fact a valid connection object.
+
+Arguments:
+
+ Connection - potential pointer to a TP_CONNECTION object.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_CONNECTION otherwise
+
+--*/
+
+{
+ KIRQL oldirql;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ //
+ // try to verify the connection signature. If the signature is valid,
+ // get the connection spinlock, check its state, and increment the
+ // reference count if it's ok to use it. Note that being in the stopping
+ // state is an OK place to be and reference the connection; we can
+ // disassociate the address while running down.
+ //
+
+ try {
+
+ if ((Connection->Size == sizeof (TP_CONNECTION)) &&
+ (Connection->Type == ST_CONNECTION_SIGNATURE)) {
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) {
+
+ StReferenceConnection ("Verify Temp Use", Connection);
+
+ } else {
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ } else {
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ return GetExceptionCode();
+ }
+
+ return status;
+
+}
+
+
+NTSTATUS
+StDestroyAssociation(
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys the association between a transport connection and
+ the address it was formerly associated with. The only action taken is
+ to disassociate the address and remove the connection from all address
+ queues.
+
+ This routine is only called by StDereferenceConnection. The reason for
+ this is that there may be multiple streams of execution which are
+ simultaneously referencing the same connection object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection structure to
+ be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql2;
+ PTP_ADDRESS_FILE addressFile;
+
+
+ ACQUIRE_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql2);
+ if ((TransportConnection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) == 0) {
+ RELEASE_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
+ return STATUS_SUCCESS;
+ } else {
+ TransportConnection->Flags2 &= ~CONNECTION_FLAGS2_ASSOCIATED;
+ RELEASE_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
+ }
+
+ addressFile = TransportConnection->AddressFile;
+
+ //
+ // Delink this connection from its associated address connection
+ // database. To do this we must spin lock on the address object as
+ // well as on the connection,
+ //
+
+ ACQUIRE_SPIN_LOCK (&addressFile->Address->SpinLock, &oldirql);
+ ACQUIRE_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql2);
+ RemoveEntryList (&TransportConnection->AddressFileList);
+ RemoveEntryList (&TransportConnection->AddressList);
+
+ InitializeListHead (&TransportConnection->AddressList);
+ InitializeListHead (&TransportConnection->AddressFileList);
+
+ //
+ // remove the association between the address and the connection.
+ //
+
+ TransportConnection->AddressFile = NULL;
+
+ RELEASE_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
+ RELEASE_SPIN_LOCK (&addressFile->Address->SpinLock, oldirql);
+
+ //
+ // and remove a reference to the address
+ //
+
+ StDereferenceAddress ("Destroy association", addressFile->Address);
+
+
+ return STATUS_SUCCESS;
+
+} /* StDestroyAssociation */
+
+
+NTSTATUS
+StIndicateDisconnect(
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine indicates a remote disconnection on this connection if it
+ is necessary to do so. No other action is taken here.
+
+ This routine is only called by StDereferenceConnection. The reason for
+ this is that there may be multiple streams of execution which are
+ simultaneously referencing the same connection object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection structure to
+ be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_ADDRESS_FILE addressFile;
+ PDEVICE_CONTEXT DeviceContext;
+ ULONG DisconnectReason;
+ PIRP DisconnectIrp;
+ KIRQL oldirql;
+
+ ACQUIRE_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql);
+
+ if (((TransportConnection->Flags2 & CONNECTION_FLAGS2_REQ_COMPLETED) != 0)) {
+
+ //
+ // Turn off all but the still-relevant bits in the flags.
+ //
+
+ ASSERT (TransportConnection->Flags & CONNECTION_FLAGS_STOPPING);
+
+ TransportConnection->Flags = CONNECTION_FLAGS_STOPPING;
+ TransportConnection->Flags2 &=
+ (CONNECTION_FLAGS2_ASSOCIATED |
+ CONNECTION_FLAGS2_DISASSOCIATED |
+ CONNECTION_FLAGS2_CLOSING);
+
+ //
+ // Clean up other stuff -- basically everything gets
+ // done here except for the flags and the status, since
+ // they are used to block other requests. When the connection
+ // is given back to us (in Accept, Connect, or Listen)
+ // they are cleared.
+ //
+
+ TransportConnection->MessageBytesReceived = (USHORT)0; // no data yet
+ TransportConnection->MessageBytesAcked = (USHORT)0;
+
+ TransportConnection->CurrentReceiveRequest = (PTP_REQUEST)NULL;
+
+ DisconnectIrp = TransportConnection->DisconnectIrp;
+ TransportConnection->DisconnectIrp = (PIRP)NULL;
+
+ RELEASE_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
+
+
+ DeviceContext = TransportConnection->Provider;
+ addressFile = TransportConnection->AddressFile;
+
+
+ //
+ // If this connection was stopped by a call to TdiDisconnect,
+ // we have to complete that. We save the Irp so we can return
+ // the connection to the pool before we complete the request.
+ //
+
+
+ if (DisconnectIrp != (PIRP)NULL) {
+
+ //
+ // Now complete the IRP if needed. This will be non-null
+ // only if TdiDisconnect was called, and we have not
+ // yet completed it.
+ //
+
+ DisconnectIrp->IoStatus.Information = 0;
+ DisconnectIrp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest (DisconnectIrp, IO_NETWORK_INCREMENT);
+
+ } else if ((TransportConnection->Status != STATUS_LOCAL_DISCONNECT) &&
+ (addressFile->RegisteredDisconnectHandler == TRUE)) {
+
+ //
+ // This was a remotely spawned disconnect, so indicate that
+ // to our client. Note that in the comparison above we
+ // check the status first, since if it is LOCAL_DISCONNECT
+ // addressFile may be NULL (BUGBUG: This is sort of a hack
+ // for PDK2, we should really indicate the disconnect inside
+ // StStopConnection, where we know addressFile is valid).
+ //
+
+ //
+ // if the disconnection was remotely spawned, then indicate
+ // disconnect. In the case that a disconnect was issued at
+ // the same time as the connection went down remotely, we
+ // won't do this because DisconnectIrp will be non-NULL.
+ //
+
+ //
+ // Invoke the user's disconnection event handler, if any. We do this here
+ // so that any outstanding sends will complete before we tear down the
+ // connection.
+ //
+
+ DisconnectReason = 0;
+ if (TransportConnection->Flags & CONNECTION_FLAGS_ABORT) {
+ DisconnectReason |= TDI_DISCONNECT_ABORT;
+ }
+ if (TransportConnection->Flags & CONNECTION_FLAGS_DESTROY) {
+ DisconnectReason |= TDI_DISCONNECT_RELEASE;
+ }
+
+ (*addressFile->DisconnectHandler)(
+ addressFile->DisconnectHandlerContext,
+ TransportConnection->Context,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ DisconnectReason);
+
+ }
+
+ } else {
+
+ //
+ // The client does not yet think that this connection
+ // is up...generally this happens due to request count
+ // fluctuation during connection setup.
+ //
+
+ RELEASE_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
+
+ }
+
+
+ return STATUS_SUCCESS;
+
+} /* StIndicateDisconnect */
+
+
+NTSTATUS
+StDestroyConnection(
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a transport connection and removes all references
+ made by it to other objects in the transport. The connection structure
+ is returned to our lookaside list. It is assumed that the caller
+ has removed all IRPs from the connections's queues first.
+
+ This routine is only called by StDereferenceConnection. The reason for
+ this is that there may be multiple streams of execution which are
+ simultaneously referencing the same connection object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection structure to
+ be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PDEVICE_CONTEXT DeviceContext;
+ PIRP CloseIrp;
+
+
+ DeviceContext = TransportConnection->Provider;
+
+ //
+ // Destroy any association that this connection has.
+ //
+
+ StDestroyAssociation (TransportConnection);
+
+ //
+ // Clear out any associated nasties hanging around the connection. Note
+ // that the current flags are set to STOPPING; this way anyone that may
+ // maliciously try to use the connection after it's dead and gone will
+ // just get ignored.
+ //
+
+ TransportConnection->Flags = CONNECTION_FLAGS_STOPPING;
+ TransportConnection->Flags2 = CONNECTION_FLAGS2_CLOSING;
+ TransportConnection->MessageBytesReceived = (USHORT)0; // no data yet
+ TransportConnection->MessageBytesAcked = (USHORT)0;
+
+
+ //
+ // Now complete the close IRP. This will be set to non-null
+ // when CloseConnection was called.
+ //
+
+ CloseIrp = TransportConnection->CloseIrp;
+
+ if (CloseIrp != (PIRP)NULL) {
+
+ TransportConnection->CloseIrp = (PIRP)NULL;
+ CloseIrp->IoStatus.Information = 0;
+ CloseIrp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest (CloseIrp, IO_NETWORK_INCREMENT);
+
+ }
+
+ //
+ // Return the connection to the provider's pool.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ DeviceContext->ConnectionTotal += DeviceContext->ConnectionInUse;
+ ++DeviceContext->ConnectionSamples;
+ --DeviceContext->ConnectionInUse;
+
+ if ((DeviceContext->ConnectionAllocated - DeviceContext->ConnectionInUse) >
+ DeviceContext->ConnectionInitAllocated) {
+ StDeallocateConnection (DeviceContext, TransportConnection);
+ } else {
+ InsertTailList (&DeviceContext->ConnectionPool, &TransportConnection->LinkList);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ StDereferenceDeviceContext ("Destroy Connection", DeviceContext);
+
+ return STATUS_SUCCESS;
+
+} /* StDestroyConnection */
+
+
+VOID
+StRefConnection(
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport connection.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedIncrement (&TransportConnection->ReferenceCount);
+
+ if (result == 0) {
+
+ //
+ // The first increment causes us to increment the
+ // "ref count is not zero" special ref.
+ //
+
+ ExInterlockedAddUlong(
+ (PULONG)(&TransportConnection->SpecialRefCount),
+ 1,
+ TransportConnection->ProviderInterlock);
+
+ }
+
+ ASSERT (result >= 0);
+
+} /* StRefConnection */
+
+
+VOID
+StDerefConnection(
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport connection by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ StDestroyConnection to remove it from the system.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&TransportConnection->ReferenceCount);
+
+ //
+ // If all the normal references to this connection are gone, then
+ // we can remove the special reference that stood for
+ // "the regular ref count is non-zero".
+ //
+
+ if (result < 0) {
+
+ //
+ // If the refcount is -1, then we need to indicate
+ // disconnect. However, we need to
+ // do this before we actually do the special deref, since
+ // otherwise the connection might go away while we
+ // are doing that.
+ //
+
+ StIndicateDisconnect (TransportConnection);
+
+ //
+ // Now it is OK to let the connection go away.
+ //
+
+ StDereferenceConnectionSpecial ("Regular ref gone", TransportConnection);
+
+ }
+
+} /* StDerefConnection */
+
+
+VOID
+StDerefConnectionSpecial(
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routines completes the dereferencing of a connection.
+ It may be called any time, but it does not do its work until
+ the regular reference count is also 0.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+
+ ACQUIRE_SPIN_LOCK (TransportConnection->ProviderInterlock, &oldirql);
+
+ --TransportConnection->SpecialRefCount;
+
+ if ((TransportConnection->SpecialRefCount == 0) &&
+ (TransportConnection->ReferenceCount == -1)) {
+
+ //
+ // If we have deleted all references to this connection, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the connection any longer.
+ //
+
+ RELEASE_SPIN_LOCK (TransportConnection->ProviderInterlock, oldirql);
+
+ StDestroyConnection (TransportConnection);
+
+ } else {
+
+ RELEASE_SPIN_LOCK (TransportConnection->ProviderInterlock, oldirql);
+
+ }
+
+} /* StDerefConnectionSpecial */
+
+
+PTP_CONNECTION
+StFindConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR LocalName,
+ IN PUCHAR RemoteName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the connections associated with a
+ device context, and determines if there is an connection
+ associated with the specific remote address on the
+ specific local address.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context.
+
+ LocalName - The 16-character Netbios name of the local address.
+
+ RemoteName - The 16-character Netbios name of the remote.
+
+Return Value:
+
+ The connection if one is found, NULL otherwise.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PLIST_ENTRY Flink;
+ PTP_ADDRESS Address;
+ BOOLEAN MatchedAddress = FALSE;
+ PTP_CONNECTION Connection;
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ for (Flink = DeviceContext->AddressDatabase.Flink;
+ Flink != &DeviceContext->AddressDatabase;
+ Flink = Flink->Flink) {
+
+ Address = CONTAINING_RECORD (
+ Flink,
+ TP_ADDRESS,
+ Linkage);
+
+ if ((Address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ continue;
+ }
+
+ if (StMatchNetbiosAddress (Address, LocalName)) {
+
+ StReferenceAddress ("Looking for connection", Address); // prevent address from being destroyed.
+ MatchedAddress = TRUE;
+ break;
+
+ }
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ if (!MatchedAddress) {
+ return NULL;
+ }
+
+ Connection = StLookupRemoteName (Address, RemoteName);
+
+ StDereferenceAddress ("Looking for connection", Address);
+
+ return Connection;
+
+}
+
+
+PTP_CONNECTION
+StLookupConnectionByContext(
+ IN PTP_ADDRESS Address,
+ IN CONNECTION_CONTEXT ConnectionContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine accepts a connection identifier and an address and
+ returns a pointer to the connection object, TP_CONNECTION. If the
+ connection identifier is not found on the address, then NULL is returned.
+ This routine automatically increments the reference count of the
+ TP_CONNECTION structure if it is found. It is assumed that the
+ TP_ADDRESS structure is already held with a reference count.
+
+ BUGBUG: Should the ConnectionDatabase go in the address file?
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+ ConnectionContext - Connection Context for this address.
+
+Return Value:
+
+ A pointer to the connection we found
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PLIST_ENTRY p;
+ PTP_CONNECTION Connection;
+
+ //
+ // Currently, this implementation is inefficient, but brute force so
+ // that a system can get up and running. Later, a cache of the mappings
+ // of popular connection id's and pointers to their TP_CONNECTION structures
+ // will be searched first.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ for (p=Address->ConnectionDatabase.Flink;
+ p != &Address->ConnectionDatabase;
+ p=p->Flink) {
+
+
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressList);
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
+
+ if ((Connection->Context == ConnectionContext) &&
+ ((Connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0)) {
+ // This reference is removed by the calling function
+ StReferenceConnection ("Lookup up for request", Connection);
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return Connection;
+ }
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return NULL;
+
+} /* StLookupConnectionByContext */
+
+
+PTP_CONNECTION
+StLookupListeningConnection(
+ IN PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the connection database on an address to find
+ a TP_CONNECTION object which has CONNECTION_FLAGS_WAIT_NQ
+ flag set. It returns a pointer to the found connection object (and
+ simultaneously resets the flag) or NULL if it could not be found.
+ The reference count is also incremented atomically on the connection.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PTP_CONNECTION Connection;
+ PLIST_ENTRY p;
+
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ for (p=Address->ConnectionDatabase.Flink;
+ p != &Address->ConnectionDatabase;
+ p=p->Flink) {
+
+
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressList);
+ if (Connection->Flags & CONNECTION_FLAGS_WAIT_LISTEN) {
+
+ // This reference is removed by the calling function
+ StReferenceConnection ("Found Listening", Connection);
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
+ Connection->Flags &= ~CONNECTION_FLAGS_WAIT_LISTEN;
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return Connection;
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return NULL;
+
+} /* StLookupListeningConnection */
+
+
+VOID
+StStopConnection(
+ IN PTP_CONNECTION Connection,
+ IN NTSTATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to terminate all activity on a connection and
+ destroy the object. This is done in a graceful manner; i.e., all
+ outstanding requests are terminated by cancelling them, etc. It is
+ assumed that the caller has a reference to this connection object,
+ but this routine will do the dereference for the one issued at creation
+ time.
+
+ Orderly release is a function of this routine, but it is not a provided
+ service of this transport provider, so there is no code to do it here.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+ Status - The status that caused us to stop the connection. This
+ will determine what status pending requests are aborted with,
+ and also how we proceed during the stop (whether to send a
+ session end, and whether to indicate disconnect).
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1, cancelirql;
+ PLIST_ENTRY p;
+ PIRP Irp;
+ PTP_REQUEST Request;
+ ULONG DisconnectReason;
+ PULONG StopCounter;
+ PDEVICE_CONTEXT DeviceContext;
+ BOOLEAN WasConnected;
+
+
+ DeviceContext = Connection->Provider;
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ if (!(Connection->Flags & CONNECTION_FLAGS_STOPPING)) {
+
+ //
+ // We are stopping the connection, record statistics
+ // about it.
+ //
+
+ if (Connection->Flags & CONNECTION_FLAGS_READY) {
+
+ DECREMENT_COUNTER (DeviceContext, OpenConnections);
+ WasConnected = TRUE;
+
+ } else {
+
+ WasConnected = FALSE;
+
+ }
+
+ Connection->Flags &= ~CONNECTION_FLAGS_READY; // no longer open for business
+ Connection->Flags |= CONNECTION_FLAGS_STOPPING;
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_REMOTE_VALID;
+ Connection->SendState = CONNECTION_SENDSTATE_IDLE;
+ Connection->Status = Status;
+
+ //
+ // If this connection is waiting to packetize,
+ // remove it from the device context queue it is on.
+ //
+ // NOTE: If the connection is currently in the
+ // packetize queue, it will eventually go to get
+ // packetized and at that point it will get
+ // removed.
+ //
+
+ if (Connection->Flags & CONNECTION_FLAGS_SUSPENDED) {
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql1);
+ RemoveEntryList (&Connection->PacketWaitLinkage);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql1);
+ }
+
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+
+ //
+ // Run down all TdiSend requests on this connection.
+ //
+
+ while (TRUE) {
+ p = RemoveHeadList (&Connection->SendQueue);
+ if (p == &Connection->SendQueue) {
+ break;
+ }
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ Irp->CancelRoutine = (PDRIVER_CANCEL)NULL;
+ IoReleaseCancelSpinLock(cancelirql);
+ StCompleteSendIrp (Irp, Connection->Status, 0);
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ }
+
+ //
+ // NOTE: We hold the connection spinlock AND the
+ // cancel spinlock here.
+ //
+
+ Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE;
+
+ //
+ // Run down all TdiReceive requests on this connection.
+ //
+
+ while (TRUE) {
+ p = RemoveHeadList (&Connection->ReceiveQueue);
+ if (p == &Connection->ReceiveQueue) {
+ break;
+ }
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ Request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL;
+ IoReleaseCancelSpinLock(cancelirql);
+
+ StCompleteRequest (Request, Connection->Status, 0);
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ }
+
+
+ //
+ // NOTE: We hold the connection spinlock AND the
+ // cancel spinlock here.
+ //
+
+ //
+ // Run down all TdiConnect/TdiDisconnect/TdiListen requests.
+ //
+
+ while (TRUE) {
+ p = RemoveHeadList (&Connection->InProgressRequest);
+ if (p == &Connection->InProgressRequest) {
+ break;
+ }
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ Request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL;
+ IoReleaseCancelSpinLock(cancelirql);
+
+ StCompleteRequest (Request, Connection->Status, 0);
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ }
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ //
+ // If we aren't DESTROYing the link, then send a SESSION_END frame
+ // to the remote side. When the SESSION_END frame is acknowleged,
+ // we will decrement the connection's reference count by one, removing
+ // its creation reference. This will cause the connection object to
+ // be disposed of, and will begin running down the link.
+ // DGB: add logic to avoid blowing away link if one doesn't exist yet.
+ //
+
+ DisconnectReason = 0;
+ if (Connection->Flags & CONNECTION_FLAGS_ABORT) {
+ DisconnectReason |= TDI_DISCONNECT_ABORT;
+ }
+ if (Connection->Flags & CONNECTION_FLAGS_DESTROY) {
+ DisconnectReason |= TDI_DISCONNECT_RELEASE;
+ }
+
+ //
+ // When this completes we will dereference the connection.
+ //
+
+ if (WasConnected) {
+ StSendDisconnect (Connection);
+ }
+
+
+ switch (Status) {
+
+ case STATUS_LOCAL_DISCONNECT:
+ StopCounter = &DeviceContext->LocalDisconnects;
+ break;
+ case STATUS_REMOTE_DISCONNECT:
+ StopCounter = &DeviceContext->RemoteDisconnects;
+ break;
+ case STATUS_LINK_FAILED:
+ StopCounter = &DeviceContext->LinkFailures;
+ break;
+ case STATUS_IO_TIMEOUT:
+ StopCounter = &DeviceContext->SessionTimeouts;
+ break;
+ case STATUS_CANCELLED:
+ StopCounter = &DeviceContext->CancelledConnections;
+ break;
+ case STATUS_REMOTE_RESOURCES:
+ StopCounter = &DeviceContext->RemoteResourceFailures;
+ break;
+ case STATUS_INSUFFICIENT_RESOURCES:
+ StopCounter = &DeviceContext->LocalResourceFailures;
+ break;
+ case STATUS_BAD_NETWORK_PATH:
+ StopCounter = &DeviceContext->NotFoundFailures;
+ break;
+ case STATUS_REMOTE_NOT_LISTENING:
+ StopCounter = &DeviceContext->NoListenFailures;
+ break;
+
+ default:
+ StopCounter = NULL;
+ break;
+
+ }
+
+ if (StopCounter != NULL) {
+
+ *StopCounter = *StopCounter + 1;
+
+ }
+
+
+ //
+ // Note that we've blocked all new requests being queued during the
+ // time we have been in this teardown code; StDestroyConnection also
+ // sets the connection flags to STOPPING when returning the
+ // connection to the queue. This avoids lingerers using non-existent
+ // connections.
+ //
+
+ } else {
+
+ //
+ // The connection was already stopping.
+ //
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ }
+
+} /* StStopConnection */
+
+
+VOID
+StCancelConnection(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a connect
+ or a listen. It is simple since there can only be one of these
+ active on a connection; we just stop the connection, the IRP
+ will get completed as part of normal session teardown.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PIO_STACK_LOCATION IrpSp;
+ PTP_CONNECTION Connection;
+ PTP_REQUEST Request;
+ PLIST_ENTRY p;
+
+ UNREFERENCED_PARAMETER (DeviceObject);
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (IrpSp->MinorFunction == TDI_CONNECT || IrpSp->MinorFunction == TDI_LISTEN));
+
+ Connection = IrpSp->FileObject->FsContext;
+
+ //
+ // Since this IRP is still in the cancellable state, we know
+ // that the connection is still around (although it may be in
+ // the process of being torn down).
+ //
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ StReferenceConnection ("Cancelling Send", Connection);
+
+ p = RemoveHeadList (&Connection->InProgressRequest);
+ ASSERT (p != &Connection->InProgressRequest);
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ ASSERT (Request->IoRequestPacket == Irp);
+ Request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL;
+
+ IoReleaseCancelSpinLock(Irp->CancelIrql);
+
+ StCompleteRequest (Request, STATUS_CANCELLED, 0);
+ StStopConnection (Connection, STATUS_CANCELLED);
+
+ StDereferenceConnection ("Cancel done", Connection);
+
+}
+
diff --git a/private/ntos/tdi/st/devctx.c b/private/ntos/tdi/st/devctx.c
new file mode 100644
index 000000000..94cc2f385
--- /dev/null
+++ b/private/ntos/tdi/st/devctx.c
@@ -0,0 +1,256 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ devctx.c
+
+Abstract:
+
+ This module contains code which implements the DEVICE_CONTEXT object.
+ Routines are provided to reference, and dereference transport device
+ context objects.
+
+ The transport device context object is a structure which contains a
+ system-defined DEVICE_OBJECT followed by information which is maintained
+ by the transport provider, called the context.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+VOID
+StRefDeviceContext(
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a device context.
+
+Arguments:
+
+ DeviceContext - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ASSERT (DeviceContext->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement (&DeviceContext->ReferenceCount);
+
+} /* StRefDeviceContext */
+
+
+VOID
+StDerefDeviceContext(
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a device context by decrementing the
+ reference count contained in the structure. Currently, we don't
+ do anything special when the reference count drops to zero, but
+ we could dynamically unload stuff then.
+
+Arguments:
+
+ DeviceContext - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&DeviceContext->ReferenceCount);
+
+ ASSERT (result >= 0);
+
+ if (result == 0) {
+ StDestroyDeviceContext (DeviceContext);
+ }
+
+} /* StDerefDeviceContext */
+
+
+
+NTSTATUS
+StCreateDeviceContext(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN OUT PDEVICE_CONTEXT *DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates and initializes a device context structure.
+
+Arguments:
+
+
+ DriverObject - pointer to the IO subsystem supplied driver object.
+
+ DeviceContext - Pointer to a pointer to a transport device context object.
+
+ DeviceName - pointer to the name of the device this device object points to.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
+
+--*/
+
+{
+ NTSTATUS status;
+ PDEVICE_OBJECT deviceObject;
+ PDEVICE_CONTEXT deviceContext;
+ USHORT i;
+
+
+ //
+ // Create the device object for the sample transport, allowing
+ // room at the end for the device name to be stored (for use
+ // in logging errors).
+ //
+
+ status = IoCreateDevice(
+ DriverObject,
+ sizeof (DEVICE_CONTEXT) - sizeof (DEVICE_OBJECT) +
+ (DeviceName->Length + sizeof(UNICODE_NULL)),
+ DeviceName,
+ FILE_DEVICE_TRANSPORT,
+ 0,
+ FALSE,
+ &deviceObject);
+
+ if (!NT_SUCCESS(status)) {
+ return status;
+ }
+
+ deviceObject->Flags |= DO_DIRECT_IO;
+
+ deviceContext = (PDEVICE_CONTEXT)deviceObject;
+
+ //
+ // Initialize our part of the device context.
+ //
+
+ RtlZeroMemory(
+ ((PUCHAR)deviceContext) + sizeof(DEVICE_OBJECT),
+ sizeof(DEVICE_CONTEXT) - sizeof(DEVICE_OBJECT));
+
+ //
+ // Copy over the device name.
+ //
+
+ deviceContext->DeviceNameLength = DeviceName->Length + sizeof(WCHAR);
+ deviceContext->DeviceName = (PWCHAR)(deviceContext+1);
+ RtlCopyMemory(
+ deviceContext->DeviceName,
+ DeviceName->Buffer,
+ DeviceName->Length);
+ deviceContext->DeviceName[DeviceName->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ //
+ // Initialize the reference count.
+ //
+
+ deviceContext->ReferenceCount = 1;
+
+ //
+ // initialize the various fields in the device context
+ //
+
+ KeInitializeSpinLock (&deviceContext->Interlock);
+ KeInitializeSpinLock (&deviceContext->SpinLock);
+
+ deviceContext->ControlChannelIdentifier = 1;
+
+ InitializeListHead (&deviceContext->ConnectionPool);
+ InitializeListHead (&deviceContext->AddressPool);
+ InitializeListHead (&deviceContext->AddressFilePool);
+ InitializeListHead (&deviceContext->AddressDatabase);
+ InitializeListHead (&deviceContext->PacketWaitQueue);
+ InitializeListHead (&deviceContext->PacketizeQueue);
+ InitializeListHead (&deviceContext->RequestPool);
+ deviceContext->PacketPool.Next = NULL;
+ deviceContext->ReceivePacketPool.Next = NULL;
+ deviceContext->ReceiveBufferPool.Next = NULL;
+ InitializeListHead (&deviceContext->ReceiveInProgress);
+ InitializeListHead (&deviceContext->IrpCompletionQueue);
+
+
+ deviceContext->State = DEVICECONTEXT_STATE_CLOSED;
+
+ //
+ // Initialize the resource that guards address ACLs.
+ //
+
+ ExInitializeResource (&deviceContext->AddressResource);
+
+ //
+ // set the netbios multicast address for this network type
+ //
+
+ for (i=0; i<HARDWARE_ADDRESS_LENGTH; i++) {
+ deviceContext->LocalAddress.Address [i] = 0; // set later
+ deviceContext->MulticastAddress.Address [i] = 0;
+ }
+
+ deviceContext->Type = ST_DEVICE_CONTEXT_SIGNATURE;
+ deviceContext->Size - sizeof (DEVICE_CONTEXT);
+
+ *DeviceContext = deviceContext;
+ return STATUS_SUCCESS;
+}
+
+
+VOID
+StDestroyDeviceContext(
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a device context structure.
+
+Arguments:
+
+ DeviceContext - Pointer to a pointer to a transport device context object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ExDeleteResource (&DeviceContext->AddressResource);
+ IoDeleteDevice ((PDEVICE_OBJECT)DeviceContext);
+ return;
+}
diff --git a/private/ntos/tdi/st/event.c b/private/ntos/tdi/st/event.c
new file mode 100644
index 000000000..9c98c9596
--- /dev/null
+++ b/private/ntos/tdi/st/event.c
@@ -0,0 +1,185 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ event.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiSetEventHandler
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+NTSTATUS
+StTdiSetEventHandler(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetEventHandler request for the
+ transport provider. The caller (request dispatcher) verifies
+ that this routine will not be executed on behalf of a user-mode
+ client, as this request enables direct callouts at DISPATCH_LEVEL.
+
+Arguments:
+
+ Irp - Pointer to the IRP for this request
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS rc=STATUS_SUCCESS;
+ KIRQL oldirql;
+ PTDI_REQUEST_KERNEL_SET_EVENT parameters;
+ PIO_STACK_LOCATION irpSp;
+ PTP_ADDRESS address;
+ PTP_ADDRESS_FILE addressFile;
+ NTSTATUS status;
+
+ //
+ // Get the Address this is associated with; if there is none, get out.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ addressFile = irpSp->FileObject->FsContext;
+ status = StVerifyAddressObject (addressFile);
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ address = addressFile->Address;
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock, &oldirql);
+
+ parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)&irpSp->Parameters;
+
+ switch (parameters->EventType) {
+
+ case TDI_EVENT_RECEIVE:
+
+ if (parameters->EventHandler == NULL) {
+ addressFile->ReceiveHandler =
+ (PTDI_IND_RECEIVE)TdiDefaultReceiveHandler;
+ addressFile->ReceiveHandlerContext = NULL;
+ addressFile->RegisteredReceiveHandler = FALSE;
+ } else {
+ addressFile->ReceiveHandler =
+ (PTDI_IND_RECEIVE)parameters->EventHandler;
+ addressFile->ReceiveHandlerContext = parameters->EventContext;
+ addressFile->RegisteredReceiveHandler = TRUE;
+ }
+
+ break;
+
+ case TDI_EVENT_RECEIVE_EXPEDITED:
+
+ if (parameters->EventHandler == NULL) {
+ addressFile->ExpeditedDataHandler =
+ (PTDI_IND_RECEIVE_EXPEDITED)TdiDefaultRcvExpeditedHandler;
+ addressFile->ExpeditedDataHandlerContext = NULL;
+ addressFile->RegisteredExpeditedDataHandler = FALSE;
+ } else {
+ addressFile->ExpeditedDataHandler =
+ (PTDI_IND_RECEIVE_EXPEDITED)parameters->EventHandler;
+ addressFile->ExpeditedDataHandlerContext = parameters->EventContext;
+ addressFile->RegisteredExpeditedDataHandler = TRUE;
+ }
+
+ break;
+
+ case TDI_EVENT_RECEIVE_DATAGRAM:
+
+ if (parameters->EventHandler == NULL) {
+ addressFile->ReceiveDatagramHandler =
+ (PTDI_IND_RECEIVE_DATAGRAM)TdiDefaultRcvDatagramHandler;
+ addressFile->ReceiveDatagramHandlerContext = NULL;
+ addressFile->RegisteredReceiveDatagramHandler = FALSE;
+ } else {
+ addressFile->ReceiveDatagramHandler =
+ (PTDI_IND_RECEIVE_DATAGRAM)parameters->EventHandler;
+ addressFile->ReceiveDatagramHandlerContext = parameters->EventContext;
+ addressFile->RegisteredReceiveDatagramHandler = TRUE;
+ }
+
+ break;
+
+ case TDI_EVENT_ERROR:
+
+ if (parameters->EventHandler == NULL) {
+ addressFile->ErrorHandler =
+ (PTDI_IND_ERROR)TdiDefaultErrorHandler;
+ addressFile->ErrorHandlerContext = NULL;
+ addressFile->RegisteredErrorHandler = FALSE;
+ } else {
+ addressFile->ErrorHandler =
+ (PTDI_IND_ERROR)parameters->EventHandler;
+ addressFile->ErrorHandlerContext = parameters->EventContext;
+ addressFile->RegisteredErrorHandler = TRUE;
+ }
+
+ break;
+
+ case TDI_EVENT_DISCONNECT:
+
+ if (parameters->EventHandler == NULL) {
+ addressFile->DisconnectHandler =
+ (PTDI_IND_DISCONNECT)TdiDefaultDisconnectHandler;
+ addressFile->DisconnectHandlerContext = NULL;
+ addressFile->RegisteredDisconnectHandler = FALSE;
+ } else {
+ addressFile->DisconnectHandler =
+ (PTDI_IND_DISCONNECT)parameters->EventHandler;
+ addressFile->DisconnectHandlerContext = parameters->EventContext;
+ addressFile->RegisteredDisconnectHandler = TRUE;
+ }
+
+ break;
+
+ case TDI_EVENT_CONNECT:
+
+ if (parameters->EventHandler == NULL) {
+ addressFile->ConnectionHandler =
+ (PTDI_IND_CONNECT)TdiDefaultConnectHandler;
+ addressFile->ConnectionHandlerContext = NULL;
+ addressFile->RegisteredConnectionHandler = FALSE;
+ } else {
+ addressFile->ConnectionHandler =
+ (PTDI_IND_CONNECT)parameters->EventHandler;
+ addressFile->ConnectionHandlerContext = parameters->EventContext;
+ addressFile->RegisteredConnectionHandler = TRUE;
+ }
+ break;
+
+ default:
+
+ rc = STATUS_INVALID_PARAMETER;
+
+ } /* switch */
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ StDereferenceAddress ("Set event handler", address);
+
+ return rc;
+} /* TdiSetEventHandler */
diff --git a/private/ntos/tdi/st/framesnd.c b/private/ntos/tdi/st/framesnd.c
new file mode 100644
index 000000000..0d9f5cff7
--- /dev/null
+++ b/private/ntos/tdi/st/framesnd.c
@@ -0,0 +1,371 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ framesnd.c
+
+Abstract:
+
+ This module contains routines which build and send Sample transport
+ frames for other modules.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+
+NTSTATUS
+StSendConnect(
+ IN PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a CONNECT frame of the appropriate type given the
+ state of the specified connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE_CONTEXT DeviceContext;
+ PUCHAR SourceRouting;
+ UINT SourceRoutingLength;
+ UINT HeaderLength;
+ PSEND_PACKET_TAG SendTag;
+ PTP_PACKET Packet;
+ PST_HEADER StHeader;
+
+
+ DeviceContext = Connection->Provider;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ Status = StCreatePacket (DeviceContext, &Packet);
+ if (!NT_SUCCESS (Status)) { // couldn't make frame.
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ SendTag = (PSEND_PACKET_TAG)(Packet->NdisPacket->ProtocolReserved);
+ SendTag->Type = TYPE_C_FRAME;
+ SendTag->Packet = Packet;
+ SendTag->Owner = (PVOID)Connection;
+
+ //
+ // Build the MAC header.
+ //
+
+ //
+ // CONNECT frames go out as
+ // single-route source routing.
+ //
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SourceRouting,
+ &SourceRoutingLength);
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ DeviceContext->MulticastAddress.Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof(ST_HEADER),
+ SourceRouting,
+ SourceRoutingLength,
+ &HeaderLength);
+
+
+ //
+ // Build the header: 'C', dest, source
+ //
+
+ StHeader = (PST_HEADER)(&Packet->Header[HeaderLength]);
+
+ StHeader->Signature = ST_SIGNATURE;
+ StHeader->Command = ST_CMD_CONNECT;
+ StHeader->Flags = 0;
+
+ RtlCopyMemory (StHeader->Destination, Connection->CalledAddress.NetbiosName, 16);
+ RtlCopyMemory (StHeader->Source, Connection->AddressFile->Address->NetworkName->NetbiosName, 16);
+
+ HeaderLength += sizeof(ST_HEADER);
+
+ //
+ // Modify the packet length and send the it.
+ //
+
+ StSetNdisPacketLength(Packet->NdisPacket, HeaderLength);
+
+ StNdisSend (Packet);
+
+ return STATUS_SUCCESS;
+} /* StSendConnect */
+
+
+NTSTATUS
+StSendDisconnect(
+ IN PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a DISCONNECT frame of the appropriate type given the
+ state of the specified connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE_CONTEXT DeviceContext;
+ PUCHAR SourceRouting;
+ UINT SourceRoutingLength;
+ UINT HeaderLength;
+ PSEND_PACKET_TAG SendTag;
+ PTP_PACKET Packet;
+ PST_HEADER StHeader;
+
+
+ DeviceContext = Connection->Provider;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ Status = StCreatePacket (DeviceContext, &Packet);
+ if (!NT_SUCCESS (Status)) { // couldn't make frame.
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ SendTag = (PSEND_PACKET_TAG)(Packet->NdisPacket->ProtocolReserved);
+ SendTag->Type = TYPE_D_FRAME;
+ SendTag->Packet = Packet;
+ SendTag->Owner = (PVOID)Connection;
+
+ //
+ // Build the MAC header.
+ //
+
+ //
+ // CONNECT frames go out as
+ // single-route source routing.
+ //
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SourceRouting,
+ &SourceRoutingLength);
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ DeviceContext->MulticastAddress.Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof(ST_HEADER),
+ SourceRouting,
+ SourceRoutingLength,
+ &HeaderLength);
+
+
+ //
+ // Build the header: 'D', dest, source
+ //
+
+ StHeader = (PST_HEADER)(&Packet->Header[HeaderLength]);
+
+ StHeader->Signature = ST_SIGNATURE;
+ StHeader->Command = ST_CMD_DISCONNECT;
+ StHeader->Flags = 0;
+
+ RtlCopyMemory (StHeader->Destination, Connection->CalledAddress.NetbiosName, 16);
+ RtlCopyMemory (StHeader->Source, Connection->AddressFile->Address->NetworkName->NetbiosName, 16);
+
+ HeaderLength += sizeof(ST_HEADER);
+
+ //
+ // Modify the packet length and send the it.
+ //
+
+ StSetNdisPacketLength(Packet->NdisPacket, HeaderLength);
+
+ StNdisSend (Packet);
+
+ return STATUS_SUCCESS;
+
+} /* StSendDisconnect */
+
+
+NTSTATUS
+StSendAddressFrame(
+ PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ It is intended that this routine be used for sending datagrams and
+ braodcast datagrams.
+
+ The datagram to be sent is described in the NDIS packet contained
+ in the Address. When the send completes, the send completion handler
+ returns the NDIS buffer describing the datagram to the buffer pool and
+ marks the address ndis packet as usable again. Thus, all datagram
+ frames are sequenced through the address they are sent on.
+
+Arguments:
+
+ Address - pointer to the address from which to send this datagram.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+
+
+ //
+ // Send the packet.
+ //
+
+ DeviceContext = Address->Provider;
+
+ INCREMENT_COUNTER (DeviceContext, PacketsSent);
+
+ StNdisSend (Address->Packet);
+
+ return STATUS_PENDING;
+} /* StSendAddressFrame */
+
+
+VOID
+StSendDatagramCompletion(
+ IN PTP_ADDRESS Address,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called as an I/O completion handler at the time a
+ StSendUIMdlFrame send request is completed. Because this handler is only
+ associated with StSendUIMdlFrame, and because StSendUIMdlFrame is only
+ used with datagrams and broadcast datagrams, we know that the I/O being
+ completed is a datagram. Here we complete the in-progress datagram, and
+ start-up the next one if there is one.
+
+Arguments:
+
+ Address - Pointer to a transport address on which the datagram
+ is queued.
+
+ NdisPacket - pointer to the NDIS packet describing this request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PTP_REQUEST Request;
+ PLIST_ENTRY p;
+ KIRQL oldirql;
+ PNDIS_BUFFER HeaderBuffer;
+
+ UNREFERENCED_PARAMETER(NdisPacket);
+
+ StReferenceAddress ("Complete datagram", Address);
+
+ //
+ // Dequeue the current request and return it to the client. Release
+ // our hold on the send datagram queue.
+ //
+ // *** There may be no current request, if the one that was queued
+ // was aborted or timed out.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ p = RemoveHeadList (&Address->SendDatagramQueue);
+
+ if (p != &Address->SendDatagramQueue) {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+
+ //
+ // Strip off and unmap the buffers describing data and header.
+ //
+
+ NdisUnchainBufferAtFront (Address->Packet->NdisPacket, &HeaderBuffer);
+
+ // drop the rest of the packet
+
+ NdisReinitializePacket (Address->Packet->NdisPacket);
+
+ NDIS_BUFFER_LINKAGE(HeaderBuffer) = (PNDIS_BUFFER)NULL;
+ NdisChainBufferAtFront (Address->Packet->NdisPacket, HeaderBuffer);
+
+ //
+ // Ignore NdisStatus; datagrams always "succeed".
+ //
+
+ StCompleteRequest (Request, STATUS_SUCCESS, Request->Buffer2Length);
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ Address->Flags &= ~ADDRESS_FLAGS_SEND_IN_PROGRESS;
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ //
+ // Send more datagrams on the Address if possible.
+ //
+
+ StSendDatagramsOnAddress (Address); // do more datagrams.
+
+ } else {
+
+ Address->Flags &= ~ADDRESS_FLAGS_SEND_IN_PROGRESS;
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ }
+
+ StDereferenceAddress ("Complete datagram", Address);
+
+} /* StSendDatagramCompletion */
diff --git a/private/ntos/tdi/st/iframes.c b/private/ntos/tdi/st/iframes.c
new file mode 100644
index 000000000..59b171c92
--- /dev/null
+++ b/private/ntos/tdi/st/iframes.c
@@ -0,0 +1,808 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ iframes.c
+
+Abstract:
+
+ This module contains routines called to handle i-frames received
+ from the NDIS driver. Most of these routines are called at receive
+ indication time.
+
+Environment:
+
+ Kernel mode, DISPATCH_LEVEL.
+
+Revision History:
+
+--*/
+
+#include "st.h"
+#if 27
+ULONG StNoisyReceives = 0;
+ULONG StRcvLoc = 0;
+ULONG StRcvs[10];
+#endif
+
+
+
+NTSTATUS
+StProcessIIndicate(
+ IN PTP_CONNECTION Connection,
+ IN PST_HEADER StHeader,
+ IN UINT StIndicatedLength,
+ IN UINT StTotalLength,
+ IN NDIS_HANDLE ReceiveContext,
+ IN BOOLEAN Last
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a received I frame at indication time. It will do
+ all necessary verification processing of the frame and pass those frames
+ that are valid on to the proper handling routines.
+
+Arguments:
+
+ Connection - The connection that the data is destined for.
+
+ StHeader - A pointer to the start of the ST header in the packet.
+
+ StIndicatedLength - The length of the packet indicated, starting at
+ StHeader.
+
+ StTotalLength - The total length of the packet, starting at StHeader.
+
+ ReceiveContext - A magic value for NDIS that indicates which packet we're
+ talking about, used for calling TransferData
+
+ Last - TRUE if this is the last packet in a send.
+
+Return Value:
+
+ STATUS_SUCCESS if we've consumed the packet, but
+ STATUS_MORE_PROCESSING_REQUIRED if we did so and also
+ activated a receive; this tells the caller not to
+ remove the connection refcount.
+
+--*/
+
+{
+ KIRQL oldirql;
+ NTSTATUS status, tmpstatus;
+ KIRQL cancelirql;
+ PDEVICE_CONTEXT deviceContext;
+ NDIS_STATUS ndisStatus;
+ PNDIS_PACKET ndisPacket;
+ PSINGLE_LIST_ENTRY linkage;
+ PIRP irp;
+ PIO_STACK_LOCATION irpSp;
+ PNDIS_BUFFER ndisBuffer;
+ ULONG destBytes;
+ ULONG bufferChainLength;
+ ULONG indicateBytesTransferred;
+ ULONG ndisBytesTransferred;
+ PUCHAR DataHeader;
+ ULONG DataTotalLength;
+ ULONG DataIndicatedLength;
+ UINT BytesToTransfer;
+ ULONG bytesIndicated;
+ PRECEIVE_PACKET_TAG receiveTag;
+ PTP_ADDRESS address;
+ PTP_ADDRESS_FILE addressFile;
+ PMDL SavedCurrentMdl;
+ ULONG SavedCurrentByteOffset;
+ LARGE_INTEGER time;
+ ULONG DumpData[2];
+ BOOLEAN CancelSpinLockHeld = FALSE;
+#if 27
+ if (StNoisyReceives) {
+ DbgPrint ("Indicate %d, Total %d\n", StIndicatedLength, StTotalLength);
+ }
+ if (StTotalLength > 1000) {
+ StRcvs[StRcvLoc] = StTotalLength;
+ StRcvLoc = (StRcvLoc + 1) % 10;
+ }
+#endif
+
+
+ //
+ // copy this packet into our receive buffer.
+ //
+
+ deviceContext = Connection->Provider;
+ addressFile = Connection->AddressFile;
+ address = addressFile->Address;
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ //
+ // If we have a previous receive that is pending
+ // completion, then we need to ignore this frame.
+ // This may be common on MP.
+ //
+
+ if (Connection->Flags2 & CONNECTION_FLAGS2_RC_PENDING) {
+
+ Connection->IndicationInProgress = FALSE;
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ return STATUS_SUCCESS;
+ }
+
+ DataHeader = (PUCHAR)StHeader + sizeof(ST_HEADER);
+ DataTotalLength = StTotalLength - sizeof(ST_HEADER);
+ DataIndicatedLength = StIndicatedLength - sizeof(ST_HEADER);
+
+ //
+ // Initialize this to zero, in case we do not indicate or
+ // the client does not fill it in.
+ //
+
+ indicateBytesTransferred = 0;
+
+ if (!(Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE)) {
+
+ //
+ // check first to see if there is a receive available. If there is,
+ // use it before doing an indication.
+ //
+
+ if (Connection->ReceiveQueue.Flink != &Connection->ReceiveQueue) {
+
+ //
+ // Found a receive, so make it the active one and
+ // cycle around again.
+ //
+
+ Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
+ Connection->MessageBytesReceived = 0;
+ Connection->MessageBytesAcked = 0;
+ Connection->CurrentReceiveRequest =
+ CONTAINING_RECORD (Connection->ReceiveQueue.Flink,
+ TP_REQUEST, Linkage);
+ Connection->CurrentReceiveMdl =
+ Connection->CurrentReceiveRequest->Buffer2;
+ Connection->ReceiveLength =
+ Connection->CurrentReceiveRequest->Buffer2Length;
+ Connection->ReceiveByteOffset = 0;
+ status = STATUS_SUCCESS;
+ goto NormalReceive;
+ }
+
+ //
+ // A receive is not active. Post a receive event.
+ //
+
+ if (!addressFile->RegisteredReceiveHandler) {
+
+ //
+ // There is no receive posted to the Connection, and
+ // no event handler. Set the RECEIVE_WAKEUP bit, so that when a
+ // receive does become available, it will restart the
+ // current send. Also send a NoReceive to tell the other
+ // guy he needs to resynch.
+ //
+
+ Connection->IndicationInProgress = FALSE;
+ return STATUS_SUCCESS;
+ }
+
+ if ((Connection->Flags & CONNECTION_FLAGS_READY) == 0) {
+ Connection->IndicationInProgress = FALSE;
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ return STATUS_SUCCESS;
+ }
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ //
+ // Indicate to the user. For BytesAvailable we
+ // always use DataTotalLength; for BytesIndicated we use
+ // MIN (DataIndicatedLength, DataTotalLength).
+ //
+ // To clarify BytesIndicated, on an Ethernet packet
+ // which is padded DataTotalLength will be shorter; on an
+ // Ethernet packet which is not padded and which is
+ // completely indicated, the two will be equal; and
+ // on a long Ethernet packet DataIndicatedLength
+ // will be shorter.
+ //
+
+ bytesIndicated = DataIndicatedLength;
+ if (DataTotalLength < bytesIndicated) {
+ bytesIndicated = DataTotalLength;
+ }
+
+ status = (*addressFile->ReceiveHandler)(
+ addressFile->ReceiveHandlerContext,
+ Connection->Context,
+ deviceContext->MacInfo.CopyLookahead ?
+ TDI_RECEIVE_COPY_LOOKAHEAD : 0, // ReceiveFlags
+ bytesIndicated,
+ DataTotalLength, // BytesAvailable
+ &indicateBytesTransferred,
+ DataHeader,
+ &irp);
+
+ if (status == STATUS_SUCCESS) {
+
+ //
+ // The client has accepted some or all of the indicated data in
+ // the event handler. Update MessageBytesReceived variable in
+ // the Connection.
+ //
+
+ Connection->MessageBytesReceived += indicateBytesTransferred;
+ Connection->IndicationInProgress = FALSE;
+
+ return STATUS_SUCCESS;
+
+ } else if (status == STATUS_DATA_NOT_ACCEPTED) {
+
+ //
+ // Either there is no event handler installed (the default
+ // handler returns this code) or the event handler is not
+ // able to process the received data at this time. If there
+ // is a TdiReceive request outstanding on this Connection's
+ // ReceiveQueue, then we may use it to receive this data.
+ // If there is no request outstanding, then we must initiate
+ // flow control at the transport level.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ if (Connection->ReceiveQueue.Flink == &Connection->ReceiveQueue) {
+
+ //
+ // There is no receive posted to the Connection, and
+ // the event handler didn't want to accept the incoming
+ // data.
+ //
+
+ Connection->IndicationInProgress = FALSE;
+ return STATUS_SUCCESS;
+
+ } else {
+
+ //
+ // Found a receive, so make it the active one. This will cause
+ // an NdisTransferData below, so we don't dereference the
+ // Connection here.
+ //
+
+ Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
+ Connection->MessageBytesReceived = 0;
+ Connection->MessageBytesAcked = 0;
+ Connection->CurrentReceiveRequest =
+ CONTAINING_RECORD (Connection->ReceiveQueue.Flink,
+ TP_REQUEST, Linkage);
+ Connection->CurrentReceiveMdl =
+ Connection->CurrentReceiveRequest->Buffer2;
+ Connection->ReceiveLength =
+ Connection->CurrentReceiveRequest->Buffer2Length;
+ Connection->ReceiveByteOffset = 0;
+ }
+
+ } else if (status == STATUS_MORE_PROCESSING_REQUIRED) {
+
+ PTP_REQUEST SpecialIrpRequest;
+ ULONG SpecialIrpLength;
+
+ //
+ // The client's event handler has returned an IRP in the
+ // form of a TdiReceive that is to be associated with this
+ // data. The request will be installed at the front of the
+ // ReceiveQueue, and then made the active receive request.
+ // This request will be used to accept the incoming data, which
+ // will happen below.
+ //
+
+ //
+ // Queueing a receive of any kind causes a Connection reference;
+ // that's what we've just done here, so make the Connection stick
+ // around. We create a request to keep a packets outstanding ref
+ // count for the current IRP; we queue this on the connection's
+ // receive queue so we can treat it like a normal receive. If
+ // we can't get a request to describe this irp, we can't keep it
+ // around hoping for better later; we simple fail it with
+ // insufficient resources. Note this is only likely to happen if
+ // we've completely run out of transport memory.
+ //
+
+ irp->IoStatus.Information = 0; // byte transfer count.
+ irp->IoStatus.Status = STATUS_PENDING;
+ irpSp = IoGetCurrentIrpStackLocation (irp);
+
+ ASSERT (irpSp->FileObject->FsContext == Connection);
+
+ SpecialIrpLength =
+ ((PTDI_REQUEST_KERNEL_RECEIVE)&irpSp->Parameters)->ReceiveLength;
+
+ //
+ // The normal path, for longer receives.
+ //
+
+ time.HighPart = 0;
+ time.LowPart = 0;
+
+ status = StCreateRequest (
+ irp,
+ Connection,
+ REQUEST_FLAGS_CONNECTION | REQUEST_FLAGS_SEND_RCV,
+ irp->MdlAddress,
+ ((PTDI_REQUEST_KERNEL_RECEIVE )&irpSp->Parameters)->ReceiveLength,
+ time,
+ &SpecialIrpRequest);
+
+ if (!NT_SUCCESS (status)) {
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ Connection->ReceiveByteOffset = 0;
+ Connection->Flags |= CONNECTION_FLAGS_RECEIVE_WAKEUP;
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ Connection->IndicationInProgress = FALSE;
+
+ irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // If the Connection is stopping, abort this request.
+ //
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ if ((Connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
+ Connection->IndicationInProgress = FALSE;
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ IoReleaseCancelSpinLock(cancelirql);
+ StCompleteRequest (
+ SpecialIrpRequest,
+ Connection->Status,
+ 0);
+ return STATUS_SUCCESS; // we have consumed the packet
+
+ }
+
+ //
+ // Insert the request on the head of the connection's
+ // receive queue, so it can be handled like a normal
+ // receive.
+ //
+
+ InsertHeadList (&Connection->ReceiveQueue, &SpecialIrpRequest->Linkage);
+
+ Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
+ Connection->ReceiveLength = ((PTDI_REQUEST_KERNEL_RECEIVE )&irpSp->Parameters)->ReceiveLength;
+ Connection->MessageBytesReceived = indicateBytesTransferred;
+ Connection->MessageBytesAcked = 0;
+ Connection->CurrentReceiveRequest = SpecialIrpRequest;
+ Connection->CurrentReceiveMdl = irp->MdlAddress;
+ Connection->ReceiveByteOffset = 0;
+ Connection->CurrentReceiveRequest->Owner = ConnectionType;
+
+ //
+ // If this IRP has been cancelled, then call the
+ // cancel routine.
+ //
+
+ if (irp->Cancel) {
+
+ Connection->Flags |= CONNECTION_FLAGS_RECEIVE_WAKEUP;
+ Connection->IndicationInProgress = FALSE;
+ RELEASE_SPIN_LOCK (&Connection->SpinLock,oldirql);
+ irp->CancelIrql = cancelirql;
+ StCancelReceive((PDEVICE_OBJECT)deviceContext, irp);
+
+ return STATUS_SUCCESS;
+
+ } else {
+
+ irp->CancelRoutine = StCancelReceive;
+
+ status = STATUS_MORE_PROCESSING_REQUIRED;
+
+ //
+ // Make a note so we know to release the cancel
+ // spinlock below.
+ //
+
+ CancelSpinLockHeld = TRUE;
+
+ }
+
+ } else {
+
+ //
+ // An unknown return code has been returned by the
+ // client's event handler. This is a client programming
+ // error. Because this can only occur when kernel-mode
+ // clients have been coded incorrectly, we should beat
+ // him with a stick. We have to do SOMETHING, or this
+ // Connection will HANG.
+ //
+
+ Connection->IndicationInProgress = FALSE;
+ return STATUS_SUCCESS;
+
+ }
+
+ } else {
+
+ //
+ // A receive is active, set the status to show
+ // that so far.
+ //
+
+ status = STATUS_SUCCESS;
+
+ }
+
+
+NormalReceive:;
+
+ //
+ // NOTE: The connection spinlock is held here.
+ //
+ // We should only get through here if a receive is active
+ // and we have not released the lock since checking or
+ // making one active.
+ //
+
+ ASSERT(Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE);
+
+ //
+ // The status should be SUCCESS (we found an active receive)
+ // or MORE_PROCESSING_REQUIRED (we made a new receive active).
+ //
+
+ ASSERT ((status == STATUS_SUCCESS) || (status == STATUS_MORE_PROCESSING_REQUIRED));
+
+ destBytes = Connection->ReceiveLength - Connection->MessageBytesReceived;
+ StReferenceRequest ("Transfer Data", Connection->CurrentReceiveRequest);
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ if (CancelSpinLockHeld) {
+ IoReleaseCancelSpinLock (cancelirql);
+ }
+
+ //
+ // get a packet for the coming transfer
+ //
+
+ linkage = ExInterlockedPopEntryList(
+ &deviceContext->ReceivePacketPool,
+ &deviceContext->Interlock);
+
+ if (linkage != NULL) {
+ ndisPacket = CONTAINING_RECORD( linkage, NDIS_PACKET, ProtocolReserved[0] );
+ } else {
+ (VOID)InterlockedIncrement((PLONG)&deviceContext->ReceivePacketExhausted);
+
+ StDereferenceRequest ("No receive packet", Connection->CurrentReceiveRequest);
+
+ // We could not get a receive packet.
+ //
+
+ Connection->IndicationInProgress = FALSE;
+ return status;
+ }
+
+ //
+ // Initialize the receive packet.
+ //
+
+ receiveTag = (PRECEIVE_PACKET_TAG)(ndisPacket->ProtocolReserved);
+ receiveTag->PacketType = TYPE_AT_INDICATE;
+ receiveTag->Connection = Connection;
+ receiveTag->TransferDataPended = TRUE;
+
+
+ //
+ // Determine how much data remains to be transferred.
+ //
+
+ BytesToTransfer = DataTotalLength - indicateBytesTransferred;
+ ASSERT (BytesToTransfer >= 0);
+
+ if (destBytes < BytesToTransfer) {
+
+ //
+ // If the data overflows the current receive, then make a
+ // note that we should complete the receive at the end of
+ // transfer data, but with EOR false.
+ //
+
+ receiveTag->EndOfMessage = FALSE;
+ receiveTag->CompleteReceive = TRUE;
+ BytesToTransfer = destBytes;
+
+ } else if (destBytes == BytesToTransfer) {
+
+ //
+ // If the data just fills the current receive, then complete
+ // the receive; EOR depends on whether this is a DOL or not.
+ //
+
+ receiveTag->EndOfMessage = Last;
+ receiveTag->CompleteReceive = TRUE;
+
+ } else {
+
+ //
+ // Complete the receive if this is a DOL.
+ //
+
+ receiveTag->EndOfMessage = Last;
+ receiveTag->CompleteReceive = Last;
+
+ }
+
+ //
+ // if we've got zero bytes left, avoid the TransferData below and
+ // just deliver.
+ //
+
+ if (BytesToTransfer <= 0) {
+ Connection->IndicationInProgress = FALSE;
+ receiveTag->NdisStatus = NDIS_STATUS_SUCCESS;
+ receiveTag->TransferDataPended = FALSE;
+ StTransferDataComplete (
+ deviceContext,
+ ndisPacket,
+ NDIS_STATUS_SUCCESS,
+ 0);
+
+ return status;
+ }
+
+ //
+ // describe the right part of the user buffer to NDIS. If we can't get
+ // the mdl for the packet, drop it. Bump the request reference count
+ // so that we know we need to hold open receives until the NDIS transfer
+ // data requests complete.
+ //
+
+ SavedCurrentMdl = Connection->CurrentReceiveMdl;
+ SavedCurrentByteOffset = Connection->ReceiveByteOffset;
+
+ if ((Connection->ReceiveByteOffset == 0) &&
+ (receiveTag->CompleteReceive)) {
+
+ //
+ // If we are transferring into the beginning of
+ // the current MDL, and we will be completing the
+ // receive after the transfer, then we don't need to
+ // copy it.
+ //
+
+ ndisBuffer = (PNDIS_BUFFER)Connection->CurrentReceiveMdl;
+ bufferChainLength = BytesToTransfer;
+ Connection->CurrentReceiveMdl = NULL;
+ Connection->ReceiveByteOffset = 0;
+ receiveTag->AllocatedNdisBuffer = FALSE;
+ tmpstatus = STATUS_SUCCESS;
+
+ } else {
+
+ tmpstatus = BuildBufferChainFromMdlChain (
+ deviceContext->NdisBufferPoolHandle,
+ Connection->CurrentReceiveMdl,
+ Connection->ReceiveByteOffset,
+ BytesToTransfer,
+ &ndisBuffer,
+ &Connection->CurrentReceiveMdl,
+ &Connection->ReceiveByteOffset,
+ &bufferChainLength);
+
+ receiveTag->AllocatedNdisBuffer = TRUE;
+
+ }
+
+
+ if ((!NT_SUCCESS (tmpstatus)) || (bufferChainLength != BytesToTransfer)) {
+
+ DumpData[0] = bufferChainLength;
+ DumpData[1] = BytesToTransfer;
+
+ StWriteGeneralErrorLog(
+ deviceContext,
+ EVENT_TRANSPORT_TRANSFER_DATA,
+ 604,
+ tmpstatus,
+ NULL,
+ 2,
+ DumpData);
+
+ StDereferenceRequest ("No MDL chain", Connection->CurrentReceiveRequest);
+
+ //
+ // Restore our old state.
+ //
+
+ Connection->CurrentReceiveMdl = SavedCurrentMdl;
+ Connection->ReceiveByteOffset = SavedCurrentByteOffset;
+
+ Connection->IndicationInProgress = FALSE;
+
+ ExInterlockedPushEntryList(
+ &deviceContext->ReceivePacketPool,
+ (PSINGLE_LIST_ENTRY)&receiveTag->Linkage,
+ &deviceContext->Interlock);
+
+ return status;
+ }
+
+ NdisChainBufferAtFront (ndisPacket, ndisBuffer);
+
+ //
+ // set up async return status so we can tell when it has happened;
+ // can never get return of NDIS_STATUS_PENDING in synch completion routine
+ // for NdisTransferData, so we know it has completed when this status
+ // changes
+ //
+
+ receiveTag->NdisStatus = NDIS_STATUS_PENDING;
+
+ //
+ // update the number of bytes received; OK to do this
+ // unprotected since IndicationInProgress is still FALSE.
+ //
+ //
+
+ Connection->MessageBytesReceived += BytesToTransfer;
+
+ //
+ // We have now updated all the connection counters (BUG,
+ // assuming the TransferData will succeed) and this
+ // packet's location in the request is secured, so we
+ // can be reentered.
+ //
+
+ Connection->IndicationInProgress = FALSE;
+
+ NdisTransferData (
+ &ndisStatus,
+ deviceContext->NdisBindingHandle,
+ ReceiveContext,
+ sizeof (ST_HEADER) + indicateBytesTransferred,
+ BytesToTransfer,
+ ndisPacket,
+ (PUINT)&ndisBytesTransferred);
+
+ //
+ // handle the various completion codes
+ //
+
+ switch (ndisStatus) {
+
+ case NDIS_STATUS_SUCCESS:
+
+ receiveTag->NdisStatus = NDIS_STATUS_SUCCESS;
+ if (ndisBytesTransferred != BytesToTransfer) { // Did we get the entire packet?
+
+ DumpData[0] = ndisBytesTransferred;
+ DumpData[1] = BytesToTransfer;
+
+ StWriteGeneralErrorLog(
+ deviceContext,
+ EVENT_TRANSPORT_TRANSFER_DATA,
+ 604,
+ ndisStatus,
+ NULL,
+ 2,
+ DumpData);
+
+ if (receiveTag->AllocatedNdisBuffer) {
+ NdisUnchainBufferAtFront (ndisPacket, &ndisBuffer);
+ while (ndisBuffer != NULL) {
+ NdisFreeBuffer (ndisBuffer);
+ NdisUnchainBufferAtFront (ndisPacket, &ndisBuffer);
+ }
+ } else {
+ NdisReinitializePacket (ndisPacket);
+ }
+
+ ExInterlockedPushEntryList(
+ &deviceContext->ReceivePacketPool,
+ (PSINGLE_LIST_ENTRY)&receiveTag->Linkage,
+ &deviceContext->Interlock);
+
+ StDereferenceRequest ("Bad byte count", Connection->CurrentReceiveRequest);
+
+ //
+ // Restore our old state.
+ //
+
+ Connection->CurrentReceiveMdl = SavedCurrentMdl;
+ Connection->ReceiveByteOffset = SavedCurrentByteOffset;
+ Connection->MessageBytesReceived -= BytesToTransfer;
+
+ return status;
+ }
+
+ //
+ // deallocate the buffers and such that we've used if at indicate
+ //
+
+ receiveTag->TransferDataPended = FALSE;
+
+ StTransferDataComplete (
+ deviceContext,
+ ndisPacket,
+ ndisStatus,
+ BytesToTransfer);
+ break;
+
+ case NDIS_STATUS_PENDING: // waiting async complete from NdisTransferData
+
+ //
+ // Because TransferDataPended stays TRUE, this reference will
+ // be removed in TransferDataComplete. It is OK to do this
+ // now, even though TransferDataComplete may already have been
+ // called, because we also hold the ProcessIIndicate reference
+ // so there will be no "bounce".
+ //
+
+ StReferenceConnection ("TransferData pended", Connection);
+ break;
+
+ default:
+
+ //
+ // Something broke; certainly we'll never get NdisTransferData
+ // asynch completion.
+ //
+ // BUGBUG: The driver should recover from this situation.
+ //
+
+ StWriteGeneralErrorLog(
+ deviceContext,
+ EVENT_TRANSPORT_TRANSFER_DATA,
+ 604,
+ ndisStatus,
+ NULL,
+ 0,
+ NULL);
+
+ if (receiveTag->AllocatedNdisBuffer) {
+ NdisUnchainBufferAtFront (ndisPacket, &ndisBuffer);
+ while (ndisBuffer != NULL) {
+ NdisFreeBuffer (ndisBuffer);
+ NdisUnchainBufferAtFront (ndisPacket, &ndisBuffer);
+ }
+ } else {
+ NdisReinitializePacket (ndisPacket);
+ }
+
+ ExInterlockedPushEntryList(
+ &deviceContext->ReceivePacketPool,
+ (PSINGLE_LIST_ENTRY)&receiveTag->Linkage,
+ &deviceContext->Interlock);
+
+ StDereferenceRequest ("TransferData failed", Connection->CurrentReceiveRequest);
+
+ //
+ // Restore our old state.
+ //
+
+ Connection->CurrentReceiveMdl = SavedCurrentMdl;
+ Connection->ReceiveByteOffset = SavedCurrentByteOffset;
+ Connection->MessageBytesReceived -= BytesToTransfer;
+
+ return status;
+ } // switch ndisStatus
+
+ return status; // which only means we've dealt with the packet
+
+} /* ProcessIIndicate */
diff --git a/private/ntos/tdi/st/ind.c b/private/ntos/tdi/st/ind.c
new file mode 100644
index 000000000..68dc3bffb
--- /dev/null
+++ b/private/ntos/tdi/st/ind.c
@@ -0,0 +1,829 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ ind.c
+
+Abstract:
+
+ This module contains code which implements the indication handler
+ for the NT Sample transport provider.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+
+NDIS_STATUS
+StReceiveIndication (
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a frame has been received on the physical link.
+ This routine is time critical, so we only allocate a
+ buffer and copy the packet into it. We also perform minimal
+ validation on this packet. It gets queued to the device context
+ to allow for processing later.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+ ReceiveContext - A magic cookie for the MAC.
+
+ HeaderBuffer - pointer to a buffer containing the packet header.
+
+ HeaderBufferSize - the size of the header.
+
+ LookaheadBuffer - pointer to a buffer containing the negotiated minimum
+ amount of buffer I get to look at (not including header).
+
+ LookaheadBufferSize - the size of the above. May be less than asked
+ for, if that's all there is.
+
+ PacketSize - Overall size of the packet (not including header).
+
+Return Value:
+
+ NDIS_STATUS - status of operation, one of:
+
+ NDIS_STATUS_SUCCESS if packet accepted,
+ NDIS_STATUS_NOT_RECOGNIZED if not recognized by protocol,
+ NDIS_any_other_thing if I understand, but can't handle.
+
+--*/
+{
+ PDEVICE_CONTEXT DeviceContext;
+ HARDWARE_ADDRESS SourceAddressBuffer;
+ PHARDWARE_ADDRESS SourceAddress;
+ UINT RealPacketSize;
+ PST_HEADER StHeader;
+
+ DeviceContext = (PDEVICE_CONTEXT)BindingContext;
+
+ RealPacketSize = 0;
+
+ //
+ // Obtain the packet length; this may optionally adjust
+ // the lookahead buffer forward if the header we wish
+ // to remove spills over into what the MAC considers
+ // data. If it determines that the header is not
+ // valid, it keeps RealPacketSize at 0.
+ //
+
+ MacReturnPacketLength(
+ &DeviceContext->MacInfo,
+ HeaderBuffer,
+ HeaderBufferSize,
+ PacketSize,
+ &RealPacketSize
+ );
+
+ if (RealPacketSize < 2) {
+ return NDIS_STATUS_NOT_RECOGNIZED;
+ }
+
+ //
+ // We've negotiated at least a contiguous DLC header passed back in the
+ // lookahead buffer. Check it to see if we want this packet.
+ //
+
+ StHeader = (PST_HEADER)LookaheadBuffer;
+
+ if (StHeader->Signature != ST_SIGNATURE) {
+ return NDIS_STATUS_NOT_RECOGNIZED; // packet was processed.
+ }
+
+
+ //
+ // Check that the packet is not too long.
+ //
+
+ if (PacketSize > DeviceContext->MaxReceivePacketSize) {
+#if DBG
+ StPrint2("StReceiveIndication: Ignoring packet length %d, max %d\n",
+ PacketSize, DeviceContext->MaxReceivePacketSize);
+#endif
+ return NDIS_STATUS_NOT_RECOGNIZED;
+ }
+
+ MacReturnSourceAddress(
+ &DeviceContext->MacInfo,
+ HeaderBuffer,
+ &SourceAddressBuffer,
+ &SourceAddress
+ );
+
+
+ return StGeneralReceiveHandler(
+ DeviceContext,
+ ReceiveContext,
+ SourceAddress,
+ HeaderBuffer, // header
+ RealPacketSize, // total data length in packet
+ (PST_HEADER)LookaheadBuffer, // lookahead data
+ LookaheadBufferSize // lookahead data length
+ );
+
+}
+
+
+NDIS_STATUS
+StGeneralReceiveHandler (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PVOID HeaderBuffer,
+ IN UINT PacketSize,
+ IN PST_HEADER StHeader,
+ IN UINT StSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from StReceiveIndication.
+ It continues the processing of indicated data.
+
+ This routine is time critical, so we only allocate a
+ buffer and copy the packet into it. We also perform minimal
+ validation on this packet. It gets queued to the device context
+ to allow for processing later.
+
+Arguments:
+
+ DeviceContext - The device context of this adapter.
+
+ ReceiveContext - A magic cookie for the MAC.
+
+ SourceAddress - The source address of the packet.
+
+ HeaderBuffer - pointer to the packet header.
+
+ PacketSize - Overall size of the packet (not including header).
+
+ DlcHeader - Points to the DLC header of the packet.
+
+ DlcSize - The length of the packet indicated, starting from DlcHeader.
+
+Return Value:
+
+ NDIS_STATUS - status of operation, one of:
+
+ NDIS_STATUS_SUCCESS if packet accepted,
+ NDIS_STATUS_NOT_RECOGNIZED if not recognized by protocol,
+ NDIS_any_other_thing if I understand, but can't handle.
+
+--*/
+{
+
+ KIRQL oldirql;
+ NTSTATUS Status;
+ NDIS_STATUS NdisStatus;
+ PNDIS_PACKET NdisPacket;
+ PNDIS_BUFFER NdisBuffer;
+ PSINGLE_LIST_ENTRY linkage;
+ UINT BytesTransferred;
+ PRECEIVE_PACKET_TAG ReceiveTag;
+ PBUFFER_TAG BufferTag;
+ PUCHAR SourceRouting;
+ UINT SourceRoutingLength;
+ PTP_ADDRESS DatagramAddress;
+ UINT NdisBufferLength;
+ PTP_CONNECTION Connection;
+ PVOID BufferPointer;
+
+
+ INCREMENT_COUNTER (DeviceContext, PacketsReceived);
+
+ Status = STATUS_SUCCESS; // assume no further processing required
+
+
+ //
+ // See what type of frame this is.
+ //
+
+ if ((StHeader->Command == ST_CMD_CONNECT) ||
+ (StHeader->Command == ST_CMD_DATAGRAM)) {
+
+ MacReturnSourceRouting(
+ &DeviceContext->MacInfo,
+ HeaderBuffer,
+ &SourceRouting,
+ &SourceRoutingLength);
+
+ Status = StProcessConnectionless (
+ DeviceContext,
+ SourceAddress,
+ StHeader,
+ StSize,
+ SourceRouting,
+ SourceRoutingLength,
+ &DatagramAddress);
+
+ } else if ((StHeader->Command == ST_CMD_INFORMATION) ||
+ (StHeader->Command == ST_CMD_DISCONNECT)) {
+
+ //
+ // If successful this adds a connection reference.
+ //
+
+ if (!(Connection = StFindConnection(DeviceContext, StHeader->Destination, StHeader->Source))) {
+ return NDIS_STATUS_NOT_RECOGNIZED;
+ }
+
+
+ if (StHeader->Command == ST_CMD_INFORMATION) {
+
+ Status = StProcessIIndicate (
+ Connection,
+ StHeader,
+ StSize,
+ PacketSize,
+ ReceiveContext,
+ (BOOLEAN)((StHeader->Flags & ST_FLAGS_LAST) != 0)
+ );
+
+ if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
+ StDereferenceConnection ("Information done", Connection);
+ } else {
+ Status = STATUS_SUCCESS;
+ }
+
+ } else {
+
+ StStopConnection (Connection, STATUS_REMOTE_DISCONNECT);
+ StDereferenceConnection ("Disconnect done", Connection);
+ Status = STATUS_SUCCESS;
+
+ }
+
+ } else {
+
+ //
+ // An unrecognized frame.
+ //
+
+ Status = STATUS_SUCCESS;
+
+ }
+
+
+ //
+ // If the above routines return success, the packet has been processed
+ // and can be discarded. If they return anything else, the packet needs
+ // to be copied to local storage for handling in a more lesurely
+ // fashion.
+ //
+
+ if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ linkage = ExInterlockedPopEntryList(
+ &DeviceContext->ReceivePacketPool,
+ &DeviceContext->Interlock);
+
+ if (linkage != NULL) {
+ NdisPacket = CONTAINING_RECORD( linkage, NDIS_PACKET, ProtocolReserved[0] );
+ } else {
+ (VOID)InterlockedIncrement((PLONG)&DeviceContext->ReceivePacketExhausted);
+
+ return NDIS_STATUS_RESOURCES;
+ }
+ ReceiveTag = (PRECEIVE_PACKET_TAG)(NdisPacket->ProtocolReserved);
+
+ linkage = ExInterlockedPopEntryList(
+ &DeviceContext->ReceiveBufferPool,
+ &DeviceContext->Interlock);
+
+ if (linkage != NULL) {
+ BufferTag = CONTAINING_RECORD( linkage, BUFFER_TAG, Linkage);
+ } else {
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceivePacketPool,
+ (PSINGLE_LIST_ENTRY)&ReceiveTag->Linkage,
+ &DeviceContext->Interlock);
+ (VOID)InterlockedIncrement((PLONG)&DeviceContext->ReceiveBufferExhausted);
+
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ NdisAdjustBufferLength (BufferTag->NdisBuffer, PacketSize);
+ NdisChainBufferAtFront (NdisPacket, (PNDIS_BUFFER)BufferTag->NdisBuffer);
+
+ //
+ // DatagramAddress has a reference added already.
+ //
+
+ BufferTag->Address = DatagramAddress;
+
+ //
+ // set up async return status so we can tell when it has happened;
+ // can never get return of NDIS_STATUS_PENDING in synch completion routine
+ // for NdisTransferData, so we know it has completed when this status
+ // changes
+ //
+
+ ReceiveTag->NdisStatus = NDIS_STATUS_PENDING;
+ ReceiveTag->PacketType = TYPE_AT_COMPLETE;
+
+ ExInterlockedInsertTailList(
+ &DeviceContext->ReceiveInProgress,
+ &ReceiveTag->Linkage,
+ &DeviceContext->SpinLock);
+
+ //
+ // receive packet is mapped at initalize
+ //
+
+ NdisTransferData (
+ &NdisStatus,
+ DeviceContext->NdisBindingHandle,
+ ReceiveContext,
+ 0,
+ PacketSize,
+ NdisPacket,
+ &BytesTransferred);
+
+ //
+ // handle the various error codes
+ //
+
+ switch (NdisStatus) {
+ case NDIS_STATUS_SUCCESS: // received packet
+ ReceiveTag->NdisStatus = NDIS_STATUS_SUCCESS;
+ if (BytesTransferred == PacketSize) { // Did we get the entire packet?
+ return NDIS_STATUS_SUCCESS;
+ }
+ break;
+
+ case NDIS_STATUS_PENDING: // waiting async complete from NdisTransferData
+ return NDIS_STATUS_SUCCESS;
+ break;
+
+ default: // something broke; certainly we'll never get NdisTransferData
+ // asynch completion with this error status...
+ break;
+ }
+
+ //
+ // receive failed, for some reason; cleanup and fail return
+ //
+
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+ RemoveEntryList (&ReceiveTag->Linkage);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ ReceiveTag->PacketType = TYPE_AT_INDICATE;
+
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceivePacketPool,
+ (PSINGLE_LIST_ENTRY)&ReceiveTag->Linkage,
+ &DeviceContext->Interlock);
+
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ NdisQueryBuffer (NdisBuffer, &BufferPointer, &NdisBufferLength);
+ BufferTag = CONTAINING_RECORD (
+ BufferPointer,
+ BUFFER_TAG,
+ Buffer[0]
+ );
+ NdisAdjustBufferLength (NdisBuffer, BufferTag->Length); // reset to good value
+
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceiveBufferPool,
+ &BufferTag->Linkage,
+ &DeviceContext->Interlock);
+
+ if (DatagramAddress) {
+ StDereferenceAddress ("DG TransferData failed", DatagramAddress);
+ }
+
+ return NDIS_STATUS_FAILURE;
+
+} // StReceiveIndication
+
+
+
+VOID
+StTransferDataComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus,
+ IN UINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that an NdisTransferData has completed. We use this indication
+ to start stripping buffers from the receive queue.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+ NdisPacket/RequestHandle - An identifier for the request that completed.
+
+ NdisStatus - The completion status for the request.
+
+ BytesTransferred - Number of bytes actually transferred.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ PRECEIVE_PACKET_TAG ReceiveTag;
+ PTP_CONNECTION Connection;
+ PNDIS_BUFFER NdisBuffer;
+ KIRQL oldirql, cancelirql;
+
+ //
+ // Put the NDIS status into a place we can use in packet processing.
+ // Note that this complete indication may be occuring during the call
+ // to NdisTransferData in the receive indication.
+ //
+
+ ReceiveTag = (PRECEIVE_PACKET_TAG)(NdisPacket->ProtocolReserved);
+
+ //
+ // note that the processing below depends on having only one packet
+ // transfer outstanding at a time. NDIS is supposed to guarentee this.
+ //
+
+ switch (ReceiveTag->PacketType) {
+
+ case TYPE_AT_COMPLETE: // normal handling
+ ReceiveTag->NdisStatus = NdisStatus;
+ break;
+
+ case TYPE_AT_INDICATE:
+
+ DeviceContext = (PDEVICE_CONTEXT)BindingContext;
+ Connection = ReceiveTag->Connection;
+
+ //
+ // The transfer for this packet is complete. Was it successful??
+ //
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ ULONG DumpData[1];
+ DumpData[0] = BytesTransferred;
+
+ StWriteGeneralErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_TRANSFER_DATA,
+ 603,
+ NdisStatus,
+ NULL,
+ 1,
+ DumpData);
+
+ //
+ // Drop the packet. BUGBUG: The driver should recover
+ // from this, but this transport has no way to cause
+ // the remote to resend.
+ //
+
+ }
+
+ //
+ // Now dereference the request to say we've got no more local
+ // references to the memory owned by it.
+ //
+
+ Connection->CurrentReceiveRequest->IoRequestPacket->IoStatus.Information += BytesTransferred;
+ StDereferenceRequest ("TransferData complete", Connection->CurrentReceiveRequest);
+
+ //
+ // see if we've completed the current receive. If so, move to the next one.
+ //
+
+ if (ReceiveTag->CompleteReceive) {
+
+ if (ReceiveTag->EndOfMessage) {
+
+ //
+ // The messages has been completely received, ack it.
+ //
+ // We set DEFERRED_ACK and DEFERRED_NOT_Q here, which
+ // will cause an ack to be piggybacked if any data is
+ // sent during the call to CompleteReceive. If this
+ // does not happen, then we will call AcknowledgeDataOnlyLast
+ // which will will send a DATA ACK or queue a request for
+ // a piggyback ack. We do this *after* calling CompleteReceive
+ // so we know that we will complete the receive back to
+ // the client before we ack the data, to prevent the
+ // next receive from being sent before this one is
+ // completed.
+ //
+
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_RC_PENDING;
+
+ } else {
+
+ //
+ // If there is a receive posted, make it current and
+ // send a receive outstanding.
+ //
+
+ ActivateReceive (Connection);
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ }
+
+ //
+ // NOTE: This releases the cancel and connection locks.
+ //
+
+ CompleteReceive (Connection, ReceiveTag->EndOfMessage, oldirql, cancelirql);
+
+ }
+
+ //
+ // dereference the connection to say we've done the I frame processing.
+ // This reference was done before calling NdisTransferData.
+ //
+
+ if (ReceiveTag->TransferDataPended) {
+ StDereferenceConnection("TransferData done", Connection);
+ }
+
+
+ //
+ // rip all of the NDIS_BUFFERs we've used off the chain and return them.
+ //
+
+ if (ReceiveTag->AllocatedNdisBuffer) {
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ while (NdisBuffer != NULL) {
+ NdisFreeBuffer (NdisBuffer);
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ }
+ } else {
+ NdisReinitializePacket (NdisPacket);
+ }
+
+
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceivePacketPool,
+ (PSINGLE_LIST_ENTRY)&ReceiveTag->Linkage,
+ &DeviceContext->Interlock);
+
+ break;
+
+ default:
+
+ break;
+ }
+
+ return;
+
+} /* StTransferDataComplete */
+
+
+VOID
+StReceiveComplete (
+ IN NDIS_HANDLE BindingContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a connection(less) frame has been received on the
+ physical link. We dispatch to the correct packet handler here.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+ ST uses the DeviceContext for this parameter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ NTSTATUS Status;
+ KIRQL oldirql, oldirql1;
+ PLIST_ENTRY linkage;
+ PNDIS_PACKET NdisPacket;
+ PNDIS_BUFFER NdisBuffer;
+ UINT NdisBufferLength;
+ PVOID BufferPointer;
+ PRECEIVE_PACKET_TAG ReceiveTag;
+ PBUFFER_TAG BufferTag;
+ PTP_ADDRESS Address;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+ PTP_CONNECTION Connection;
+
+
+ DeviceContext = (PDEVICE_CONTEXT) BindingContext;
+
+ //
+ // Complete all pending receives. Do a quick check
+ // without the lock.
+ //
+
+ while (!IsListEmpty (&DeviceContext->IrpCompletionQueue)) {
+
+ linkage = ExInterlockedRemoveHeadList(
+ &DeviceContext->IrpCompletionQueue,
+ &DeviceContext->SpinLock);
+
+ if (linkage != NULL) {
+
+ Irp = CONTAINING_RECORD (linkage, IRP, Tail.Overlay.ListEntry);
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ Connection = (PTP_CONNECTION)IrpSp->FileObject->FsContext;
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
+
+ if (Connection->Flags2 & CONNECTION_FLAGS2_RC_PENDING) {
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_RC_PENDING;
+ }
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+
+ StDereferenceConnection ("receive completed", Connection);
+
+ } else {
+
+ //
+ // ExInterlockedRemoveHeadList returned NULL, so don't
+ // bother looping back.
+ //
+
+ break;
+
+ }
+
+ }
+
+
+ //
+ // Packetize all waiting connections
+ //
+
+ if (!IsListEmpty(&DeviceContext->PacketizeQueue)) {
+
+ PacketizeConnections (DeviceContext);
+
+ }
+
+
+ //
+ // Get every waiting packet, in order...
+ //
+
+
+ if (!IsListEmpty (&DeviceContext->ReceiveInProgress)) {
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ while (!IsListEmpty (&DeviceContext->ReceiveInProgress)) {
+
+ linkage = RemoveHeadList (&DeviceContext->ReceiveInProgress);
+ NdisPacket = CONTAINING_RECORD( linkage, NDIS_PACKET, ProtocolReserved[0]);
+
+ //
+ // NdisTransferData may have failed at async completion; check and
+ // see. If it did, then we discard this packet. If we're still waiting
+ // for transfer to complete, go back to sleep and hope (no guarantee!)
+ // we get waken up later.
+ //
+
+ ReceiveTag = (PRECEIVE_PACKET_TAG)(NdisPacket->ProtocolReserved);
+ if (ReceiveTag->NdisStatus == NDIS_STATUS_PENDING) {
+ InsertHeadList (&DeviceContext->ReceiveInProgress, linkage);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ return;
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ if (ReceiveTag->NdisStatus != NDIS_STATUS_SUCCESS) {
+ goto FreePacket; // skip the packet, continue with while loop
+ }
+
+ NdisQueryPacket (NdisPacket, NULL, NULL, &NdisBuffer, NULL);
+
+ //
+ // Have a packet. Since I allocated the storage for it, I know it's
+ // virtually contiguous and can treat it that way, which I will
+ // henceforth.
+ //
+
+ NdisQueryBuffer (NdisBuffer, &BufferPointer, &NdisBufferLength);
+
+ //
+ // Determine what address this is for, which is stored
+ // in the buffer tag header.
+ //
+
+ BufferTag = CONTAINING_RECORD( BufferPointer, BUFFER_TAG, Buffer[0]);
+ Address = BufferTag->Address;
+
+ //
+ // Process the frame as a UI frame; only datagrams should
+ // be processed here. If Address is NULL then this datagram
+ // is not needed for any bound address and should be given
+ // to RAS only.
+ //
+
+ ASSERT (Address != NULL);
+
+ //
+ // Indicate it or complete posted datagrams.
+ //
+
+ Status = StIndicateDatagram (
+ DeviceContext,
+ Address,
+ BufferPointer,
+ NdisBufferLength);
+
+
+ //
+ // Dereference the address.
+ //
+
+ StDereferenceAddress ("Datagram done", Address);
+
+ //
+ // Finished with packet; return to pool.
+ //
+
+FreePacket:;
+
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ ReceiveTag->PacketType = TYPE_AT_INDICATE;
+
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceivePacketPool,
+ (PSINGLE_LIST_ENTRY)&ReceiveTag->Linkage,
+ &DeviceContext->Interlock);
+
+ NdisAdjustBufferLength (NdisBuffer, BufferTag->Length);
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceiveBufferPool,
+ &BufferTag->Linkage,
+ &DeviceContext->Interlock);
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ } // if queue not empty
+
+ return;
+
+} /* StReceiveComplete */
+
diff --git a/private/ntos/tdi/st/info.c b/private/ntos/tdi/st/info.c
new file mode 100644
index 000000000..2a2122753
--- /dev/null
+++ b/private/ntos/tdi/st/info.c
@@ -0,0 +1,865 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ info.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiQueryInformation
+ o TdiSetInformation
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+//
+// Useful macro to obtain the total length of an MDL chain.
+//
+
+#define StGetMdlChainLength(Mdl, Length) { \
+ PMDL _Mdl = (Mdl); \
+ *(Length) = 0; \
+ while (_Mdl) { \
+ *(Length) += MmGetMdlByteCount(_Mdl); \
+ _Mdl = _Mdl->Next; \
+ } \
+}
+
+//
+// Local functions used to satisfy various requests.
+//
+
+VOID
+StStoreProviderStatistics(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTDI_PROVIDER_STATISTICS ProviderStatistics
+ );
+
+VOID
+StStoreAdapterStatus(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN PVOID StatusBuffer
+ );
+
+VOID
+StStoreNameBuffers(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PVOID Buffer,
+ IN ULONG BufferLength,
+ IN ULONG NamesToSkip,
+ OUT PULONG NamesWritten,
+ OUT PULONG TotalNameCount OPTIONAL,
+ OUT PBOOLEAN Truncated
+ );
+
+
+NTSTATUS
+StTdiQueryInformation(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiQueryInformation request for the transport
+ provider.
+
+Arguments:
+
+ Irp - the Irp for the requested operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PIO_STACK_LOCATION irpSp;
+ PVOID adapterStatus;
+ PTDI_REQUEST_KERNEL_QUERY_INFORMATION query;
+ PTA_NETBIOS_ADDRESS broadcastAddress;
+ PTDI_PROVIDER_STATISTICS ProviderStatistics;
+ PTDI_CONNECTION_INFO ConnectionInfo;
+ ULONG TargetBufferLength;
+ LARGE_INTEGER timeout = {0,0};
+ PTP_CONNECTION Connection;
+ PTP_ADDRESS_FILE AddressFile;
+ PTP_ADDRESS Address;
+ struct {
+ ULONG ActivityCount;
+ TA_NETBIOS_ADDRESS TaAddressBuffer;
+ } AddressInfo;
+ ULONG NamesWritten, TotalNameCount, BytesWritten;
+ PLIST_ENTRY p;
+ KIRQL oldirql;
+ BOOLEAN Truncated;
+ BOOLEAN UsedConnection;
+
+ //
+ // what type of status do we want?
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&irpSp->Parameters;
+
+ switch (query->QueryType) {
+
+ case TDI_QUERY_CONNECTION_INFO:
+
+ //
+ // Connection info is queried on a connection,
+ // verify this.
+ //
+
+ Connection = irpSp->FileObject->FsContext;
+
+ status = StVerifyConnectionObject (Connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ ConnectionInfo = ExAllocatePool (
+ NonPagedPool,
+ sizeof (TDI_CONNECTION_INFO));
+
+ if (ConnectionInfo == NULL) {
+
+ PANIC ("StQueryInfo: Cannot allocate connection info!\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TDI_CONNECTION_INFO), 6);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else if ((Connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
+
+ status = Connection->Status;
+ ExFreePool (ConnectionInfo);
+
+ } else if ((Connection->Flags & CONNECTION_FLAGS_READY) == 0) {
+
+ status = STATUS_INVALID_CONNECTION;
+ ExFreePool (ConnectionInfo);
+
+ } else {
+
+ RtlZeroMemory ((PVOID)ConnectionInfo, sizeof(TDI_CONNECTION_INFO));
+
+ //
+ // Fill in connection information here.
+ //
+
+ status = TdiCopyBufferToMdl (
+ (PVOID)ConnectionInfo,
+ 0L,
+ sizeof(TDI_CONNECTION_INFO),
+ Irp->MdlAddress,
+ 0,
+ &(Irp->IoStatus.Information));
+
+ ExFreePool (ConnectionInfo);
+ }
+
+ StDereferenceConnection ("query connection info", Connection);
+
+ break;
+
+ case TDI_QUERY_ADDRESS_INFO:
+
+ //
+ // Information about an address, can also be queried on a
+ // connection object to get information about its address.
+ //
+
+ if (irpSp->FileObject->FsContext2 == (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
+
+ AddressFile = irpSp->FileObject->FsContext;
+
+ status = StVerifyAddressObject(AddressFile);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ UsedConnection = FALSE;
+
+ } else if (irpSp->FileObject->FsContext2 == (PVOID)TDI_CONNECTION_FILE) {
+
+ Connection = irpSp->FileObject->FsContext;
+
+ status = StVerifyConnectionObject (Connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ AddressFile = Connection->AddressFile;
+
+ UsedConnection = TRUE;
+
+ } else {
+
+ return STATUS_INVALID_ADDRESS;
+
+ }
+
+ Address = AddressFile->Address;
+
+ TdiBuildNetbiosAddress(
+ Address->NetworkName->NetbiosName,
+ (BOOLEAN)(Address->Flags & ADDRESS_FLAGS_GROUP ? TRUE : FALSE),
+ &AddressInfo.TaAddressBuffer);
+
+ //
+ // Count the active addresses.
+ //
+
+ AddressInfo.ActivityCount = 0;
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+ ++AddressInfo.ActivityCount;
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ status = TdiCopyBufferToMdl (
+ &AddressInfo,
+ 0,
+ sizeof(ULONG) + sizeof(TA_NETBIOS_ADDRESS),
+ Irp->MdlAddress,
+ 0,
+ &Irp->IoStatus.Information);
+
+ if (UsedConnection) {
+
+ StDereferenceConnection ("query address info", Connection);
+
+ } else {
+
+ StDereferenceAddress ("query address info", Address);
+
+ }
+
+ break;
+
+ case TDI_QUERY_BROADCAST_ADDRESS:
+
+ //
+ // for this provider, the broadcast address is a zero byte name,
+ // contained in a Transport address structure.
+ //
+
+ broadcastAddress = ExAllocatePool (
+ NonPagedPool,
+ sizeof (TA_NETBIOS_ADDRESS));
+ if (broadcastAddress == NULL) {
+ PANIC ("StQueryInfo: Cannot allocate broadcast address!\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TA_NETBIOS_ADDRESS), 2);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ } else {
+
+ broadcastAddress->TAAddressCount = 1;
+ broadcastAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ broadcastAddress->Address[0].AddressLength = 0;
+
+ Irp->IoStatus.Information =
+ sizeof (broadcastAddress->TAAddressCount) +
+ sizeof (broadcastAddress->Address[0].AddressType) +
+ sizeof (broadcastAddress->Address[0].AddressLength);
+
+ status = TdiCopyBufferToMdl (
+ (PVOID)broadcastAddress,
+ 0L,
+ Irp->IoStatus.Information,
+ Irp->MdlAddress,
+ 0,
+ &(Irp->IoStatus.Information));
+
+ ExFreePool (broadcastAddress);
+ }
+
+ break;
+
+ case TDI_QUERY_PROVIDER_INFO:
+
+ status = TdiCopyBufferToMdl (
+ &(DeviceContext->Information),
+ 0,
+ sizeof (TDI_PROVIDER_INFO),
+ Irp->MdlAddress,
+ 0,
+ &Irp->IoStatus.Information);
+ break;
+
+ case TDI_QUERY_PROVIDER_STATISTICS:
+
+ StGetMdlChainLength (Irp->MdlAddress, &TargetBufferLength);
+
+ if (TargetBufferLength < sizeof(TDI_PROVIDER_STATISTICS) + ((ST_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS))) {
+
+ Irp->IoStatus.Information = 0;
+ status = STATUS_BUFFER_OVERFLOW;
+
+ } else {
+
+ ProviderStatistics = ExAllocatePool(
+ NonPagedPool,
+ sizeof(TDI_PROVIDER_STATISTICS) +
+ ((ST_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS)));
+
+ if (ProviderStatistics == NULL) {
+
+ PANIC ("StQueryInfo: Cannot allocate provider statistics!\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TDI_PROVIDER_STATISTICS), 7);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ StStoreProviderStatistics (DeviceContext, ProviderStatistics);
+
+ status = TdiCopyBufferToMdl (
+ (PVOID)ProviderStatistics,
+ 0L,
+ sizeof(TDI_PROVIDER_STATISTICS) +
+ ((ST_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS)),
+ Irp->MdlAddress,
+ 0,
+ &(Irp->IoStatus.Information));
+
+ ExFreePool (ProviderStatistics);
+ }
+
+ }
+
+ break;
+
+ case TDI_QUERY_SESSION_STATUS:
+
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ case TDI_QUERY_ADAPTER_STATUS:
+
+ StGetMdlChainLength (Irp->MdlAddress, &TargetBufferLength);
+
+ //
+ // Determine if this is a local or remote query. It is
+ // local if there is no remote address specific at all,
+ // or if it is equal to our reserved address.
+ //
+
+ if ((query->RequestConnectionInformation != NULL) &&
+ (!RtlEqualMemory(
+ ((PTA_NETBIOS_ADDRESS)(query->RequestConnectionInformation->RemoteAddress))->
+ Address[0].Address[0].NetbiosName,
+ DeviceContext->ReservedNetBIOSAddress,
+ NETBIOS_NAME_LENGTH))) {
+
+ //
+ // Remote, not supported here.
+ //
+
+ status = STATUS_NOT_IMPLEMENTED;
+
+ } else {
+
+ //
+ // Local.
+ //
+
+ adapterStatus = ExAllocatePool (
+ NonPagedPool,
+ TargetBufferLength);
+
+ if (adapterStatus == NULL) {
+ PANIC("StQueryInfo: PANIC! Could not allocate adapter status buffer\n");
+ StWriteResourceErrorLog (DeviceContext, TargetBufferLength, 3);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ StStoreAdapterStatus (
+ DeviceContext,
+ NULL,
+ 0,
+ adapterStatus);
+
+ StStoreNameBuffers (
+ DeviceContext,
+ (PUCHAR)adapterStatus + sizeof(ADAPTER_STATUS),
+ TargetBufferLength - sizeof(ADAPTER_STATUS),
+ 0,
+ &NamesWritten,
+ &TotalNameCount,
+ &Truncated);
+
+ ((PADAPTER_STATUS)adapterStatus)->name_count = (WORD)TotalNameCount;
+
+ BytesWritten = sizeof(ADAPTER_STATUS) + (NamesWritten * sizeof(NAME_BUFFER));
+
+ status = TdiCopyBufferToMdl (
+ adapterStatus,
+ 0,
+ BytesWritten,
+ Irp->MdlAddress,
+ 0,
+ &Irp->IoStatus.Information);
+
+ if (Truncated) {
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+
+ ExFreePool (adapterStatus);
+
+ }
+
+ break;
+
+ case TDI_QUERY_FIND_NAME:
+
+ //
+ // Find name, not supported here.
+ //
+
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ default:
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ return status;
+
+} /* StTdiQueryInformation */
+
+//
+// Quick macros, assumes DeviceContext and ProviderStatistics exist.
+//
+
+#define STORE_RESOURCE_STATS_1(_ResourceNum,_ResourceId,_ResourceName) \
+{ \
+ PTDI_PROVIDER_RESOURCE_STATS RStats = &ProviderStatistics->ResourceStats[_ResourceNum]; \
+ RStats->ResourceId = (_ResourceId); \
+ RStats->MaximumResourceUsed = DeviceContext->_ResourceName ## MaxInUse; \
+ if (DeviceContext->_ResourceName ## Samples > 0) { \
+ RStats->AverageResourceUsed = DeviceContext->_ResourceName ## Total / DeviceContext->_ResourceName ## Samples; \
+ } else { \
+ RStats->AverageResourceUsed = 0; \
+ } \
+ RStats->ResourceExhausted = DeviceContext->_ResourceName ## Exhausted; \
+}
+
+#define STORE_RESOURCE_STATS_2(_ResourceNum,_ResourceId,_ResourceName) \
+{ \
+ PTDI_PROVIDER_RESOURCE_STATS RStats = &ProviderStatistics->ResourceStats[_ResourceNum]; \
+ RStats->ResourceId = (_ResourceId); \
+ RStats->MaximumResourceUsed = DeviceContext->_ResourceName ## Allocated; \
+ RStats->AverageResourceUsed = DeviceContext->_ResourceName ## Allocated; \
+ RStats->ResourceExhausted = DeviceContext->_ResourceName ## Exhausted; \
+}
+
+
+VOID
+StStoreProviderStatistics(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTDI_PROVIDER_STATISTICS ProviderStatistics
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes the TDI_PROVIDER_STATISTICS structure
+ from the device context into ProviderStatistics.
+
+Arguments:
+
+ DeviceContext - a pointer to the device context.
+
+ ProviderStatistics - The buffer that holds the result. It is assumed
+ that it is long enough.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ProviderStatistics->Version = 0x0100;
+
+ //
+ // Copy all the statistics from OpenConnections to WastedSpace
+ // Packets in one move.
+ //
+
+ RtlCopyMemory(
+ (PVOID)&(ProviderStatistics->OpenConnections),
+ (PVOID)&(DeviceContext->OpenConnections),
+ sizeof(TDI_PROVIDER_STATISTICS));
+
+ //
+ // Copy the resource statistics.
+ //
+
+ ProviderStatistics->NumberOfResources = ST_TDI_RESOURCES;
+
+ STORE_RESOURCE_STATS_1 (0, 12, Address);
+ STORE_RESOURCE_STATS_1 (1, 13, AddressFile);
+ STORE_RESOURCE_STATS_1 (2, 14, Connection);
+ STORE_RESOURCE_STATS_1 (3, 15, Request);
+
+ STORE_RESOURCE_STATS_2 (4, 22, Packet);
+ STORE_RESOURCE_STATS_2 (5, 23, ReceivePacket);
+ STORE_RESOURCE_STATS_2 (6, 24, ReceiveBuffer);
+
+} /* StStoreProviderStatistics */
+
+
+VOID
+StStoreAdapterStatus(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN PVOID StatusBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes the ADAPTER_STATUS structure for the
+ device context into StatusBuffer. The name_count field is
+ initialized to zero; StStoreNameBuffers is used to write
+ name buffers.
+
+Arguments:
+
+ DeviceContext - a pointer to the device context.
+
+ SourceRouting - If this is a remote request, the source
+ routing information from the frame.
+
+ SourceRoutingLength - The length of SourceRouting.
+
+ StatusBuffer - The buffer that holds the result. It is assumed
+ that it is at least sizeof(ADAPTER_STATUS) bytes long.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PADAPTER_STATUS AdapterStatus = (PADAPTER_STATUS)StatusBuffer;
+ UINT MaxUserData;
+
+ RtlZeroMemory ((PVOID)AdapterStatus, sizeof(ADAPTER_STATUS));
+
+ RtlCopyMemory (AdapterStatus->adapter_address, DeviceContext->LocalAddress.Address, 6);
+ AdapterStatus->rev_major = 0x03;
+
+ switch (DeviceContext->MacInfo.MediumType) {
+ case NdisMedium802_5: AdapterStatus->adapter_type = 0xff; break;
+ default: AdapterStatus->adapter_type = 0xfe; break;
+ }
+
+ AdapterStatus->frmr_recv = 0;
+ AdapterStatus->frmr_xmit = 0;
+
+ AdapterStatus->recv_buff_unavail = (WORD)(DeviceContext->ReceivePacketExhausted + DeviceContext->ReceiveBufferExhausted);
+ AdapterStatus->xmit_buf_unavail = (WORD)DeviceContext->PacketExhausted;
+
+ AdapterStatus->xmit_success = (WORD)(DeviceContext->IFramesSent - DeviceContext->IFramesResent);
+ AdapterStatus->recv_success = (WORD)DeviceContext->IFramesReceived;
+ AdapterStatus->iframe_recv_err = (WORD)DeviceContext->IFramesRejected;
+ AdapterStatus->iframe_xmit_err = (WORD)DeviceContext->IFramesResent;
+
+ AdapterStatus->t1_timeouts = 0;
+ AdapterStatus->ti_timeouts = 0;
+ AdapterStatus->xmit_aborts = 0;
+
+
+ AdapterStatus->free_ncbs = 0xffff;
+ AdapterStatus->max_cfg_ncbs = 0xffff;
+ AdapterStatus->max_ncbs = 0xffff;
+ AdapterStatus->pending_sess = (WORD)DeviceContext->OpenConnections;
+ AdapterStatus->max_cfg_sess = 0xffff;
+ AdapterStatus->max_sess = 0xffff;
+
+
+ MacReturnMaxDataSize(
+ &DeviceContext->MacInfo,
+ SourceRouting,
+ SourceRoutingLength,
+ DeviceContext->MaxSendPacketSize,
+ &MaxUserData);
+
+ AdapterStatus->max_dgram_size = (WORD)(MaxUserData - sizeof(ST_HEADER));
+ AdapterStatus->max_sess_pkt_size = (WORD)(MaxUserData - sizeof(ST_HEADER));
+
+ return;
+
+} /* StStoreAdapterStatus */
+
+
+VOID
+StStoreNameBuffers(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PVOID Buffer,
+ IN ULONG BufferLength,
+ IN ULONG NamesToSkip,
+ OUT PULONG NamesWritten,
+ OUT PULONG TotalNameCount OPTIONAL,
+ OUT PBOOLEAN Truncated
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes NAME_BUFFER structures for the
+ device context into NameBuffer. It can skip a specified
+ number of names at the beginning, and returns the number
+ of names written into NameBuffer. If a name will only
+ partially fit, it is not written.
+
+Arguments:
+
+ DeviceContext - a pointer to the device context.
+
+ NameBuffer - The buffer to write the names into.
+
+ NameBufferLength - The length of NameBuffer.
+
+ NamesToSkip - The number of names to skip.
+
+ NamesWritten - Returns the number of names written.
+
+ TotalNameCount - Returns the total number of names available,
+ if specified.
+
+ Truncated - More names are available than were written.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG NameCount = 0;
+ ULONG BytesWritten = 0;
+ KIRQL oldirql;
+ PLIST_ENTRY p;
+ PNAME_BUFFER NameBuffer = (PNAME_BUFFER)Buffer;
+ PTP_ADDRESS address;
+
+
+ //
+ // Spin through the address list for this device context.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ p = DeviceContext->AddressDatabase.Flink;
+
+ for (p = DeviceContext->AddressDatabase.Flink;
+ p != &DeviceContext->AddressDatabase;
+ p = p->Flink) {
+
+ address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+
+ //
+ // Ignore addresses that are shutting down.
+ //
+
+ if ((address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ continue;
+ }
+
+ //
+ // Ignore the broadcast address.
+ //
+
+ if (address->NetworkName == NULL) {
+ continue;
+ }
+
+ //
+ // Ignore the reserved address.
+ //
+
+ if ((address->NetworkName->NetbiosName[0] == 0) &&
+ (RtlEqualMemory(
+ address->NetworkName->NetbiosName,
+ DeviceContext->ReservedNetBIOSAddress,
+ NETBIOS_NAME_LENGTH))) {
+
+ continue;
+ }
+
+ //
+ // Check if we are still skipping.
+ //
+
+ if (NameCount < NamesToSkip) {
+ ++NameCount;
+ continue;
+ }
+
+ //
+ // Make sure we still have room.
+ //
+
+ if (BytesWritten + sizeof(NAME_BUFFER) > BufferLength) {
+ break;
+ }
+
+ RtlCopyMemory(
+ NameBuffer->name,
+ address->NetworkName->NetbiosName,
+ NETBIOS_NAME_LENGTH);
+
+ ++NameCount;
+ NameBuffer->name_num = (UCHAR)NameCount;
+
+ NameBuffer->name_flags = REGISTERED;
+ if (address->Flags & ADDRESS_FLAGS_GROUP) {
+ NameBuffer->name_flags |= GROUP_NAME;
+ }
+
+ // BUGBUG: name_flags should be done more accurately.
+
+ BytesWritten += sizeof(NAME_BUFFER);
+ ++NameBuffer;
+
+ }
+
+ *NamesWritten = NameBuffer - (PNAME_BUFFER)Buffer;
+
+ if (p == &DeviceContext->AddressDatabase) {
+
+ *Truncated = FALSE;
+ if (ARGUMENT_PRESENT(TotalNameCount)) {
+ *TotalNameCount = NameCount;
+ }
+
+ } else {
+
+ *Truncated = TRUE;
+
+ //
+ // If requested, continue through the list and count
+ // all the addresses.
+ //
+
+ if (ARGUMENT_PRESENT(TotalNameCount)) {
+
+ for ( ;
+ p != &DeviceContext->AddressDatabase;
+ p = p->Flink) {
+
+ address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+
+ //
+ // Ignore addresses that are shutting down.
+ //
+
+ if ((address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ continue;
+ }
+
+ //
+ // Ignore the broadcast address.
+ //
+
+ if (address->NetworkName == NULL) {
+ continue;
+ }
+
+ //
+ // Ignore the reserved address, since we count it no matter what.
+ //
+
+ if ((address->NetworkName->NetbiosName[0] == 0) &&
+ (RtlEqualMemory(
+ address->NetworkName->NetbiosName,
+ DeviceContext->ReservedNetBIOSAddress,
+ NETBIOS_NAME_LENGTH))) {
+
+ continue;
+ }
+
+ ++NameCount;
+
+ }
+
+ *TotalNameCount = NameCount;
+
+ }
+
+ }
+
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ return;
+
+} /* StStoreNameBuffers */
+
+
+NTSTATUS
+StTdiSetInformation(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetInformation request for the transport
+ provider.
+
+Arguments:
+
+ Irp - the Irp for the requested operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (Irp);
+
+ return STATUS_NOT_IMPLEMENTED;
+
+} /* StTdiQueryInformation */
+
diff --git a/private/ntos/tdi/st/makefile b/private/ntos/tdi/st/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/st/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/st/oemnxpts.inf b/private/ntos/tdi/st/oemnxpts.inf
new file mode 100644
index 000000000..da0cdaab7
--- /dev/null
+++ b/private/ntos/tdi/st/oemnxpts.inf
@@ -0,0 +1,446 @@
+[Identification]
+ OptionType = NetTransport
+[Options]
+ ST
+[FileConstants]
+UtilityInf = "UTILITY.INF"
+subroutineinf = "SUBROUTN.INF"
+SoftwareType = "transport"
+Exit_Code = 0
+NetEventDLL = "%SystemRoot%\System32\netevent.dll"
+Manufacturer = "Microsoft"
+ProductMajorVersion = "3"
+ProductMinorVersion = "1"
+ProductVersion = $(ProductMajorVersion)"."$(ProductMinorVersion)
+ProductSoftwareName = "St"
+ProductSoftwareImagePath = "\SystemRoot\System32\drivers\st.sys"
+NetRuleSoftwareType = "st netBiosTransport"
+NetRuleSoftwareClass = {"netBiosTransport"}
+NetRuleSoftwareUse = $(SoftwareType)" yes yes"
+NetRuleSoftwareBindForm = """St"" yes yes simple"
+ProductKeyName = $(!NTN_SoftwareBase)"\"$(Manufacturer)"\"$(ProductSoftwareName)"\CurrentVersion"
+ParamKeyName = $(!NTN_ServiceBase)"\"$(ProductSoftwareName)"\Parameters"
+[GeneralConstants]
+from = ""
+to = ""
+ExitCodeOk = 0
+ExitCodeCancel = 1
+ExitCodeFatal = 2
+KeyNull = ""
+MAXIMUM_ALLOWED = 33554432
+RegistryErrorIndex = NO_ERROR
+KeyProduct = ""
+KeyParameters = ""
+TRUE = 1
+FALSE = 0
+NoTitle = 0
+ExitState = "Active"
+OldVersionExisted = $(FALSE)
+DriverPath = $(!STF_NTPATH)\drivers
+[date]
+ Now = {} ? $(!LIBHANDLE) GetSystemDate
+[Identify]
+ read-syms Identification
+ set Status = STATUS_SUCCESSFUL
+ set Identifier = $(OptionType)
+ set Media = #("Source Media Descriptions", 1, 1)
+ Return $(Status) $(Identifier) $(Media)
+[ReturnOptions]
+ set Status = STATUS_FAILED
+ set OptionList = {}
+ set OptionTextList = {}
+ set LanguageList = ^(LanguagesSupported, 1)
+ Ifcontains(i) $($0) in $(LanguageList)
+ goto returnoptions
+ else
+ set Status = STATUS_NOLANGUAGE
+ goto finish_ReturnOptions
+ endif
+returnoptions = +
+ set OptionList = ^(Options, 1)
+ set OptionTextList = ^(OptionsText$($0), 1)
+ set Status = STATUS_SUCCESSFUL
+finish_ReturnOptions = +
+ Return $(Status) $(OptionList) $(OptionTextList)
+[InstallOption]
+ set Option = $($1)
+ set SrcDir = $($2)
+ set AddCopy = $($3)
+ set DoCopy = $($4)
+ set DoConfig = $($5)
+ set LanguageList = ^(LanguagesSupported, 1)
+ Ifcontains(i) $($0) NOT-IN $(LanguageList)
+ Return STATUS_NOLANGUAGE
+ endif
+ Debug-Output "OEMNXPNB.INF: STF_CWDDIR is: "$(!STF_CWDDIR)
+ Debug-Output "OEMNXPNB.INF: STF_LANGUAGE is: "$(!STF_LANGUAGE)
+ set-subst LF = "\n"
+ read-syms GeneralConstants
+ read-syms FileConstants
+ read-syms DialogConstants$(!STF_LANGUAGE)
+ ifstr(i) $(!NTN_Origination) == "NCPA"
+ set Continue = $(OK)
+ endif
+ read-syms FileConstants$(!STF_LANGUAGE)
+ detect date
+ set-title $(FunctionTitle)
+ set to = Begin
+ set from = Begin
+ set CommonStatus = STATUS_SUCCESSFUL
+ EndWait
+Begin = +
+ Ifstr(i) $(!NTN_InstallMode) == deinstall
+ set StartLabel = removeadapter
+ else-Ifstr(i) $(!NTN_InstallMode) == Update
+ set StartLabel = UpgradeSoftware
+ else-Ifstr(i) $(!NTN_InstallMode) == bind
+ set StartLabel = bindingadapter
+ else-Ifstr(i) $(!NTN_InstallMode) == configure
+ Shell $(UtilityInf),RegistryErrorString,CANNOT_CONFIGURE_SOFTWARE
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "OEMNXPNB.INF: ShellCode error: cannot get an error string."
+ goto ShellCodeError
+ endif
+ set Error = $($R0)
+ set from = end
+ set to = end
+ goto nonfatalinfo
+ else
+ set StartLabel = installadapter
+ endif
+ set RadioDefault = 2
+ set RadioIn = {$(RadioDefault)}
+ set Size = 2
+ set from = $(fatal)
+ set to = $(fatal)
+ goto $(StartLabel)
+installadapter = +
+ OpenRegKey $(!REG_H_LOCAL) "" $(ProductKeyName) $(MAXIMUM_ALLOWED) KeyProduct
+ Ifstr $(KeyProduct) != $(KeyNull)
+ CloseRegKey $(KeyProduct)
+ Shell $(UtilityInf), VerExistedDlg, $(ProductSoftwareTitle),+
+ $(ProductVersion)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "ShellCode error: cannot get an error string."
+ goto ShellCodeError
+ endif
+ goto end
+ endif
+ CloseRegKey $(KeyProduct)
+ goto installproduct
+installproduct = +
+ StartWait
+ ifint $(OldVersionExisted) == $(FALSE)
+ Ifstr(i) $(DoCopy) == "YES"
+ Shell $(UtilityInf), DoAskSource, $(!STF_CWDDIR), $(SrcDir) YES
+ Ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Goto ShellCodeError
+ Else-Ifstr(i) $($R0) == STATUS_FAILED
+ Shell $(UtilityInf) RegistryErrorString "ASK_SOURCE_FAIL"
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ set Error = $($R0)
+ Goto fatal
+ Else-Ifstr(i) $($R0) == STATUS_USERCANCEL
+ Goto successful
+ Endif
+ Set SrcDir = $($R1)
+ Endif
+ install "Install-Option"
+ ifstr(i) $(STF_INSTALL_OUTCOME) != STF_SUCCESS
+ Shell $(UtilityInf) RegistryErrorString "UNABLE_COPY_FILE"
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ set Error = $($R0)
+ goto fatal
+ endif
+ set OEM_ABANDON_ON = TRUE
+ Shell $(UtilityInf), AddSoftwareComponent, $(Manufacturer), +
+ $(ProductSoftwareName), +
+ $(ProductSoftwareName), +
+ $(ProductSoftwareDisplayName), $(STF_CONTEXTINFNAME), +
+ $(ProductSoftwareImagePath), "kernel", "TDI", {}, "",+
+ $(NetEventDLL)
+ set RegistryErrorIndex = $($R0)
+ Ifstr(i) $(RegistryErrorIndex) != NO_ERROR
+ EndWait
+ CloseRegKey $($R1)
+ CloseRegKey $($R2)
+ CloseRegKey $($R3)
+ CloseRegKey $($R4)
+ CloseRegKey $($R5)
+ goto fatalRegistry
+ endif
+ Set SoftProductKey = $($R1)
+ Set SoftNetRuleKey = $($R2)
+ Set SoftServiceKey = $($R3)
+ set KeyParameters = $($R4)
+ Set SoftLinkageKey = $($R5)
+ set NewValueList = {{SoftwareType,$(NoTitle),$(!REG_VT_SZ),$(SoftwareType)},+
+ {MajorVersion,$(NoTitle),$(!REG_VT_DWORD),$(ProductMajorVersion)},+
+ {MinorVersion,$(NoTitle),$(!REG_VT_DWORD),$(ProductMinorVersion)},+
+ {Title,$(NoTitle),$(!REG_VT_SZ),$(ProductSoftwareTitle)},+
+ {Description,$(NoTitle),$(!REG_VT_SZ),$(ProductSoftwareDescription)},+
+ {ServiceName,$(NoTitle),$(!REG_VT_SZ),$(ProductSoftwareName)},+
+ {InstallDate,$(NoTitle),$(!REG_VT_DWORD),*($(Now),1)}}
+ Shell $(UtilityInf), AddValueList, $(SoftProductKey), $(NewValueList)
+ set RegistryErrorIndex = $($R0)
+ Ifstr $(RegistryErrorIndex) != NO_ERROR
+ CloseRegKey $(SoftProductKey)
+ CloseRegKey $(SoftNetRuleKey)
+ CloseRegKey $(SoftServiceKey)
+ CloseRegKey $(SoftLinkageKey)
+ CloseRegKey $(KeyParameters)
+ goto fatalRegistry
+ endif
+ set NewValueList = {{type ,$(NoTitle),$(!REG_VT_SZ),$(NetRuleSoftwareType)}, +
+ {use ,$(NoTitle),$(!REG_VT_SZ),$(NetRuleSoftwareUse)}, +
+ {class,$(NoTitle),$(!REG_VT_MULTI_SZ),$(NetRuleSoftwareClass)}, +
+ {bindform,$(NoTitle),$(!REG_VT_SZ),$(NetRuleSoftwareBindForm)}, +
+ {InfOption,$(NoTitle),$(!REG_VT_SZ),$(Option)}}
+ Shell $(UtilityInf), AddValueList, $(SoftNetRuleKey), $(NewValueList)
+ set RegistryErrorIndex = $($R0)
+ Ifstr $(RegistryErrorIndex) != NO_ERROR
+ CloseRegKey $(SoftProductKey)
+ CloseRegKey $(SoftNetRuleKey)
+ CloseRegKey $(SoftServiceKey)
+ CloseRegKey $(SoftLinkageKey)
+ CloseRegKey $(KeyParameters)
+ goto fatalRegistry
+ endif
+ Set NewValueList = {{NbProvider,$(NoTitle),$(!REG_VT_SZ),"_nb"}}
+ Shell $(UtilityInf), AddValueList, $(KeyParameters), $(NewValueList)
+ Ifstr $(RegistryErrorIndex) != NO_ERROR
+ CloseRegKey $(SoftProductKey)
+ CloseRegKey $(SoftNetRuleKey)
+ CloseRegKey $(SoftServiceKey)
+ CloseRegKey $(SoftLinkageKey)
+ goto fatalRegistry
+ endif
+ CreateRegKey $(SoftServiceKey) {"Performance",$(NoTitle),GenericClass} "" +
+ $(MAXIMUM_ALLOWED) "" KeyPerformance
+ set NewValueList = {{Library,$(NoTitle),$(!REG_VT_SZ),"Perfctrs.dll"},+
+ {Open,$(NoTitle),$(!REG_VT_SZ),"OpenNbfPerformanceData"},+
+ {Collect,$(NoTitle),$(!REG_VT_SZ),"CollectNbfPerformanceData"},+
+ {Close,$(NoTitle),$(!REG_VT_SZ),"CloseNbfPerformanceData"}}
+ Shell $(UtilityInf), AddValueList, $(KeyPerformance), $(NewValueList)
+ set RegistryErrorIndex = $($R0)
+ Ifstr $(RegistryErrorIndex) != NO_ERROR
+ CloseRegKey $(SoftProductKey)
+ CloseRegKey $(SoftNetRuleKey)
+ CloseRegKey $(SoftServiceKey)
+ CloseRegKey $(SoftLinkageKey)
+ CloseRegKey $(KeyParameters)
+ goto fatalRegistry
+ endif
+ CloseRegKey $(KeyPerformance)
+ CloseRegKey $(SoftProductKey)
+ CloseRegKey $(SoftNetRuleKey)
+ CloseRegKey $(SoftServiceKey)
+ CloseRegKey $(SoftLinkageKey)
+ endif
+ goto writeparameters
+writeparameters = +
+ set NewValueList = {{Size,$(NoTitle),$(!REG_VT_DWORD),$(Size)}}
+ ifint $(OldVersionExisted) == $(TRUE)
+ OpenRegKey $(!REG_H_LOCAL) "" $(ParamKeyName) $(MAXIMUM_ALLOWED) KeyParameters
+ endif
+ Shell $(UtilityInf), AddValueList, $(KeyParameters), $(NewValueList)
+ set RegistryErrorIndex = $($R0)
+ CloseRegKey $(KeyParameters)
+ Ifstr(i) $(RegistryErrorIndex) != NO_ERROR
+ goto fatalRegistry
+ endif
+ EndWait
+ goto successful
+bindingadapter =+
+ set Error = "Binding: Sorry, not yet implemented."
+ goto fatal
+removeadapter = +
+ Shell $(UtilityInf), RemoveSoftwareComponent, $(Manufacturer), +
+ $(ProductSoftwareName)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "ShellCode error"
+ goto ShellCodeError
+ endif
+ set RegistryErrorIndex = $($R0)
+ Ifstr(i) $(RegistryErrorIndex) != NO_ERROR
+ goto fatalregistry
+ endif
+ goto end
+UpgradeSoftware = +
+ ifstr(i) $(ProductKeyName) == $(!NTN_RegBase)
+ OpenRegKey $(!REG_H_LOCAL) "" $(ProductKeyName) $(MAXIMUM_ALLOWED) KeyProduct
+ Ifstr $(KeyProduct) != $(KeyNull)
+ GetRegValue $(KeyProduct),"MajorVersion", VersionInfo
+ set Version = *($(VersionInfo), 4)
+ Shell $(UtilityInf), GetInfFileNameFromRegistry, $(KeyProduct)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "ShellCode error"
+ goto ShellCodeError
+ endif
+ set !UG_Filename = $($R0)
+ ifstr(i) $(!UG_Filename) != ""
+ install "Install-Update"
+ ifstr(i) $(STF_INSTALL_OUTCOME) != STF_SUCCESS
+ goto fatal
+ endif
+ endif
+ SetRegValue $(KeyProduct) {MajorVersion,$(NoTitle),$(!REG_VT_SZ),$(ProductMajorVersion)}
+ SetRegValue $(KeyProduct) {MinorVersion,$(NoTitle),$(!REG_VT_SZ),$(ProductMinorVersion)}
+ ifint $(Version) != $(ProductVersion)
+ endif
+ CloseRegKey $(KeyProduct)
+ else
+ goto fatalregistry
+ endif
+ endif
+ goto end
+successful = +
+ goto end
+warning = +
+ Shell $(subroutineinf) SetupMessage, $(!STF_LANGUAGE), "WARNING", $(Error)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ ifstr(i) $($R1) == "OK"
+ goto $(to)
+ else-ifstr(i) $($R1) == "CANCEL"
+ goto $(from)
+ else
+ goto "end"
+ endif
+nonfatalinfo = +
+ Set CommonStatus = STATUS_USERCANCEL
+ Set Severity = STATUS
+ goto nonfatalmsg
+nonfatal = +
+ Set Severity = NONFATAL
+ goto nonfatalmsg
+nonfatalmsg = +
+ ifstr(i) $(Error) == ""
+ Shell $(UtilityInf) RegistryErrorString "SETUP_FAIL"
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ set Error = $($R0)
+ endif
+ Shell $(subroutineinf) SetupMessage, $(!STF_LANGUAGE), $(Severity), $(Error)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ ifstr(i) $($R1) == "OK"
+ goto $(from)
+ else
+ goto "end"
+ endif
+fatalregistry = +
+ Shell $(UtilityInf) RegistryErrorString $(RegistryErrorIndex)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ set Error = $($R0)
+ goto fatal
+fatal = +
+ ifstr(i) $(Error) == ""
+ Shell $(UtilityInf) RegistryErrorString "SETUP_FAIL"
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ set Error = $($R0)
+ endif
+ Shell $(subroutineinf) SetupMessage, $(!STF_LANGUAGE), "FATAL", $(Error)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ goto setfailed
+ShellCodeError = +
+ set DlgType = "MessageBox"
+ set STF_MB_TITLE = $(ShellCodeErrorTitle)
+ set STF_MB_TEXT = $(ShellCodeErrorText)
+ set STF_MB_TYPE = 1
+ set STF_MB_ICON = 3
+ set STF_MB_DEF = 1
+ ui start "Error Message"
+ goto setfailed
+setfailed = +
+ set CommonStatus = STATUS_FAILED
+ ifstr(i) $(OEM_ABANDON_ON) == TRUE
+ set OEM_ABANDON_ON = FALSE
+ goto removeadapter
+ endif
+ goto end
+end = +
+ goto term
+term = +
+ Return $(CommonStatus)
+[Install-Option]
+ set STF_VITAL = ""
+ ifstr(i) $(AddCopy) == "YES"
+ AddSectionFilesToCopyList Files-$(Option) $(SrcDir) $(!STF_WINDOWSSYSPATH)\drivers
+ endif
+ ifstr(i) $(DoCopy) == "YES"
+ set !STF_NCPA_FLUSH_COPYLIST = TRUE
+ CopyFilesInCopyList
+ endif
+ ifstr(i) $(DoConfig) == "YES"
+ endif
+ Exit
+[Install-Update]
+ set STF_VITAL = ""
+ set STF_OVERWRITE = "VERIFYSOURCEOLDER"
+ AddSectionFilesToCopyList Files-$(Option) $(SrcDir) $(!STF_WINDOWSSYSPATH)\drivers
+ AddSectionFilesToCopyList Files-Inf $(SrcDir) $(!STF_WINDOWSSYSPATH)
+ set !STF_NCPA_FLUSH_COPYLIST = TRUE
+ CopyFilesInCopyList
+ exit
+[Source Media Descriptions]
+ 1 = "Windows NT Setup Disk #1" , TAGFILE = disk1
+ 2 = "Windows NT Setup CD-ROM Disk" , TAGFILE = disk2
+[ProductType]
+STF_PRODUCT = Winnt
+STF_PLATFORM = Mips
+[Files-Inf]
+2, oemsetup.inf, SIZE=1000, RENAME=$(!UG_Filename)
+[Files-ST]
+2,ST.SYS , SIZE=88888
+[LanguagesSupported]
+ ENG
+[OptionsTextENG]
+ ST = "Sample Transport"
+[FileConstantsENG]
+ProCaption = "Windows NT Setup"
+ProCancel = "Cancel"
+ProCancelMsg = "Windows NT Networking is not correctly installed. "+
+ "Are you sure you want to cancel copying files?"
+ProCancelCap = "Network Setup Message"
+ProText1 = "Copying:"
+ProText2 = "To:"
+FunctionTitle = "Sample Transport"
+ProductSoftwareDescription = "Microsoft Sample TDI Transport"
+ProductSoftwareDisplayName = "Sample Transport"
+ProductSoftwareTitle = "Sample Transport"
+ShellCodeErrorTitle = "Error: "$(FunctionTitle)
+ShellCodeErrorText = "Shell Code Error."
+[DialogConstantsENG]
+Help = "&Help"
+Exit = "Cancel"
+OK = "OK"
+HelpContext = ""
+Continue = "Continue"
+Cancel = "Cancel"
+[FileDependentDlgENG]
+GroupLabel = "Optimization:"
+Radio1 = "&Minimize Memory Used"
+Radio2 = "&Balance"
+Radio3 = "M&aximize Throughput && Connections"
+DlgType = "Radio"
+DlgTemplate = "ST"
+Caption = $(FunctionTitle)
+OptionsGreyed = {}
+HelpContext = $(!IDH_DB_OEMNXPNB_INS)
+
+
+
diff --git a/private/ntos/tdi/st/packet.c b/private/ntos/tdi/st/packet.c
new file mode 100644
index 000000000..29e9fe1b8
--- /dev/null
+++ b/private/ntos/tdi/st/packet.c
@@ -0,0 +1,597 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ packet.c
+
+Abstract:
+
+ This module contains code that implements the TP_PACKET object, which
+ describes an NDIS packet.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+//
+// This is temporary; this is the quota that we charge for a receive
+// packet for now, until we fix the problem with token-ring needing
+// big packets and using all the memory. The number is the actual
+// value for Ethernet.
+//
+
+#if 1
+#define RECEIVE_BUFFER_QUOTA(_DeviceContext) 1533
+#else
+#define RECEIVE_BUFFER_QUOTA(_DeviceContext) (_DeviceContext)->ReceiveBufferLength
+#endif
+
+
+
+
+VOID
+StAllocateSendPacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_PACKET *TransportSendPacket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for a send packet. Some initialization
+ is done here.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ TransportSendPacket - Returns a pointer to the packet, or NULL if no
+ storage can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PTP_PACKET Packet;
+ NDIS_STATUS NdisStatus;
+ PNDIS_PACKET NdisPacket;
+ PSEND_PACKET_TAG SendTag;
+ PNDIS_BUFFER NdisBuffer;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + DeviceContext->PacketLength) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("ST: Could not allocate send packet: limit\n");
+ StWriteResourceErrorLog (DeviceContext, DeviceContext->PacketLength, 107);
+ *TransportSendPacket = NULL;
+ return;
+ }
+
+ Packet = (PTP_PACKET)ExAllocatePool (NonPagedPool, DeviceContext->PacketLength);
+ if (Packet == NULL) {
+ PANIC("ST: Could not allocate send packet: no pool\n");
+ StWriteResourceErrorLog (DeviceContext, DeviceContext->PacketLength, 207);
+ *TransportSendPacket = NULL;
+ return;
+ }
+ RtlZeroMemory (Packet, DeviceContext->PacketLength);
+
+ DeviceContext->MemoryUsage += DeviceContext->PacketLength;
+
+ NdisAllocatePacket (
+ &NdisStatus,
+ &NdisPacket,
+ DeviceContext->SendPacketPoolHandle);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ ExFreePool (Packet);
+ StWriteResourceErrorLog (DeviceContext, 0, 307);
+ *TransportSendPacket = NULL;
+ return;
+ }
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ DeviceContext->NdisBufferPoolHandle,
+ Packet->Header,
+ DeviceContext->PacketHeaderLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NdisFreePacket (NdisPacket);
+ ExFreePool (Packet);
+ *TransportSendPacket = NULL;
+ return;
+ }
+
+ NdisChainBufferAtFront (NdisPacket, NdisBuffer);
+
+ Packet->NdisPacket = NdisPacket;
+ SendTag = (PSEND_PACKET_TAG)NdisPacket->ProtocolReserved;
+ SendTag->Type = TYPE_I_FRAME;
+ SendTag->Packet = Packet;
+ SendTag->Owner = NULL;
+
+ Packet->Type = ST_PACKET_SIGNATURE;
+ Packet->Size = sizeof (TP_PACKET);
+ Packet->Provider = DeviceContext;
+
+ ++DeviceContext->PacketAllocated;
+
+ *TransportSendPacket = Packet;
+
+} /* StAllocateSendPacket */
+
+
+VOID
+StDeallocateSendPacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_PACKET TransportSendPacket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for a send packet.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ TransportSendPacket - A pointer to the send packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PACKET NdisPacket = TransportSendPacket->NdisPacket;
+ PNDIS_BUFFER NdisBuffer;
+
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ if (NdisBuffer != NULL) {
+ NdisFreeBuffer (NdisBuffer);
+ }
+
+ NdisFreePacket (NdisPacket);
+ ExFreePool (TransportSendPacket);
+
+ --DeviceContext->PacketAllocated;
+ DeviceContext->MemoryUsage -= DeviceContext->PacketLength;
+
+} /* StDeallocateSendPacket */
+
+
+VOID
+StAllocateReceivePacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PNDIS_PACKET *TransportReceivePacket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for a receive packet. Some initialization
+ is done here.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ TransportReceivePacket - Returns a pointer to the packet, or NULL if no
+ storage can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS NdisStatus;
+ PNDIS_PACKET NdisPacket;
+ PRECEIVE_PACKET_TAG ReceiveTag;
+
+ //
+ // This does not count in DeviceContext->MemoryUsage because
+ // the storage is allocated when we allocate the packet pool.
+ //
+
+ NdisAllocatePacket (
+ &NdisStatus,
+ &NdisPacket,
+ DeviceContext->ReceivePacketPoolHandle);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ StWriteResourceErrorLog (DeviceContext, 0, 309);
+ *TransportReceivePacket = NULL;
+ return;
+ }
+
+ ReceiveTag = (PRECEIVE_PACKET_TAG)(NdisPacket->ProtocolReserved);
+ ReceiveTag->PacketType = TYPE_AT_INDICATE;
+
+ ++DeviceContext->ReceivePacketAllocated;
+
+ *TransportReceivePacket = NdisPacket;
+
+} /* StAllocateReceivePacket */
+
+
+VOID
+StDeallocateReceivePacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNDIS_PACKET TransportReceivePacket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for a receive packet.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ TransportReceivePacket - A pointer to the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NdisFreePacket (TransportReceivePacket);
+
+ --DeviceContext->ReceivePacketAllocated;
+
+} /* StDeallocateReceivePacket */
+
+
+VOID
+StAllocateReceiveBuffer(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PBUFFER_TAG *TransportReceiveBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for a receive buffer. Some initialization
+ is done here.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ TransportReceiveBuffer - Returns a pointer to the buffer, or NULL if no
+ storage can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PBUFFER_TAG BufferTag;
+ NDIS_STATUS NdisStatus;
+ PNDIS_BUFFER NdisBuffer;
+
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + RECEIVE_BUFFER_QUOTA(DeviceContext)) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("ST: Could not allocate receive buffer: limit\n");
+ StWriteResourceErrorLog (DeviceContext, RECEIVE_BUFFER_QUOTA(DeviceContext), 108);
+ *TransportReceiveBuffer = NULL;
+ return;
+ }
+
+ BufferTag = (PBUFFER_TAG)ExAllocatePool (
+ NonPagedPoolCacheAligned,
+ DeviceContext->ReceiveBufferLength);
+
+ if (BufferTag == NULL) {
+ PANIC("ST: Could not allocate receive buffer: no pool\n");
+ StWriteResourceErrorLog (DeviceContext, DeviceContext->ReceiveBufferLength, 208);
+ *TransportReceiveBuffer = NULL;
+ return;
+ }
+
+ DeviceContext->MemoryUsage += RECEIVE_BUFFER_QUOTA(DeviceContext);
+
+ //
+ // point to the buffer for NDIS
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ DeviceContext->NdisBufferPoolHandle,
+ BufferTag->Buffer,
+ DeviceContext->MaxReceivePacketSize);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ ExFreePool (BufferTag);
+ *TransportReceiveBuffer = NULL;
+ return;
+ }
+
+ BufferTag->Length = DeviceContext->MaxReceivePacketSize;
+ BufferTag->NdisBuffer = NdisBuffer;
+
+ ++DeviceContext->ReceiveBufferAllocated;
+
+ *TransportReceiveBuffer = BufferTag;
+
+} /* StAllocateReceiveBuffer */
+
+
+VOID
+StDeallocateReceiveBuffer(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PBUFFER_TAG TransportReceiveBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for a receive buffer.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ TransportReceiveBuffer - A pointer to the buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NdisFreeBuffer (TransportReceiveBuffer->NdisBuffer);
+ ExFreePool (TransportReceiveBuffer);
+
+ --DeviceContext->ReceiveBufferAllocated;
+ DeviceContext->MemoryUsage -= RECEIVE_BUFFER_QUOTA(DeviceContext);
+
+} /* StDeallocateReceiveBuffer */
+
+
+NTSTATUS
+StCreatePacket(
+ PDEVICE_CONTEXT DeviceContext,
+ PTP_PACKET *Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool,
+ and prepares the MAC and DLC headers for use by the connection.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ Packet - Pointer to a place where we will return a pointer to the
+ allocated packet.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PSINGLE_LIST_ENTRY s;
+ PTP_PACKET ThePacket;
+
+ s = ExInterlockedPopEntryList (
+ &DeviceContext->PacketPool,
+ &DeviceContext->Interlock);
+
+ if (s == NULL) {
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+ ++DeviceContext->PacketExhausted;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ ThePacket = CONTAINING_RECORD (s, TP_PACKET, Linkage);
+
+ ThePacket->Provider = DeviceContext; // who owns this packet
+ ThePacket->PacketSent = FALSE;
+ ThePacket->PacketNoNdisBuffer = FALSE;
+
+ *Packet = ThePacket; // return pointer to the packet.
+ return STATUS_SUCCESS;
+} /* StCreatePacket */
+
+
+VOID
+StDestroyPacket(
+ PTP_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a packet, thereby returning it to the pool. If
+ it is determined that there is at least one connection waiting for a
+ packet to become available (and it just has), then the connection is
+ removed from the device context's list and AdvanceSend is called to
+ prep the connection further.
+
+Arguments:
+
+ Packet - Pointer to a packet to be returned to the pool.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql1;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_CONNECTION Connection;
+ PLIST_ENTRY p;
+ PNDIS_BUFFER HeaderBuffer;
+ PNDIS_BUFFER NdisBuffer;
+
+
+ //
+ // Strip off and unmap the buffers describing data and header.
+ //
+
+ NdisUnchainBufferAtFront (Packet->NdisPacket, &HeaderBuffer);
+
+ // data buffers get thrown away
+
+ if (Packet->PacketNoNdisBuffer) {
+
+ //
+ // If the NDIS_BUFFER chain is not ours, then we can't
+ // start unchaining since that would mess up the queue;
+ // instead we just drop the rest of the chain.
+ //
+
+ NdisReinitializePacket (Packet->NdisPacket);
+
+ } else {
+
+ //
+ // Return all the NDIS_BUFFERs to the system.
+ //
+
+ NdisUnchainBufferAtFront (Packet->NdisPacket, &NdisBuffer);
+ while (NdisBuffer != NULL) {
+ NdisFreeBuffer (NdisBuffer);
+ NdisUnchainBufferAtFront (Packet->NdisPacket, &NdisBuffer);
+ }
+
+ }
+
+ ASSERT (HeaderBuffer != NULL);
+ NDIS_BUFFER_LINKAGE(HeaderBuffer) = (PNDIS_BUFFER)NULL;
+
+ NdisChainBufferAtFront (Packet->NdisPacket, HeaderBuffer);
+
+
+ //
+ // Put the packet back for use again.
+ //
+
+ DeviceContext = Packet->Provider;
+
+ ExInterlockedPushEntryList (
+ &DeviceContext->PacketPool,
+ (PSINGLE_LIST_ENTRY)&Packet->Linkage,
+ &DeviceContext->Interlock);
+
+ //
+ // If there is a connection waiting to ship out more packets, then
+ // wake it up and start packetizing again.
+ //
+ // We do a quick check without the lock; there is a small
+ // window where we may not take someone off, but this
+ // window exists anyway and we assume that more packets
+ // will be freed in the future.
+ //
+
+ if (IsListEmpty (&DeviceContext->PacketWaitQueue)) {
+ return;
+ }
+
+ p = ExInterlockedRemoveHeadList(
+ &DeviceContext->PacketWaitQueue,
+ &DeviceContext->SpinLock);
+
+ if (p != NULL) {
+
+ //
+ // Remove a connection from the "packet starved" queue.
+ //
+
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, PacketWaitLinkage);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
+ Connection->Flags &= ~CONNECTION_FLAGS_SUSPENDED;
+
+ //
+ // Place the connection on the packetize queue and start
+ // packetizing the next connection to be serviced. If he
+ // is already on the packetize queue for some reason, then
+ // don't do this.
+ //
+
+ Connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
+
+ if (!(Connection->Flags & CONNECTION_FLAGS_STOPPING) &&
+ !(Connection->Flags & CONNECTION_FLAGS_PACKETIZE)) {
+
+ Connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
+
+ StReferenceConnection ("Packet available", Connection);
+
+ ExInterlockedInsertTailList(
+ &DeviceContext->PacketizeQueue,
+ &Connection->PacketizeLinkage,
+ &DeviceContext->SpinLock);
+ }
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+ PacketizeConnections (DeviceContext);
+
+ }
+
+} /* StDestroyPacket */
+
diff --git a/private/ntos/tdi/st/rcv.c b/private/ntos/tdi/st/rcv.c
new file mode 100644
index 000000000..b2f0e779d
--- /dev/null
+++ b/private/ntos/tdi/st/rcv.c
@@ -0,0 +1,247 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ rcv.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiReceive
+ o TdiReceiveDatagram
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+NTSTATUS
+StTdiReceive(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiReceive request for the transport provider.
+
+Arguments:
+
+ Irp - I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTP_CONNECTION connection;
+ KIRQL oldirql, cancelirql;
+ PTP_REQUEST tpRequest;
+ LARGE_INTEGER timeout = {0,0};
+ PIO_STACK_LOCATION irpSp;
+ PMDL ReceiveBuffer;
+ ULONG ReceiveBufferLength;
+ PTDI_REQUEST_KERNEL_RECEIVE parameters;
+
+ //
+ // verify that the operation is taking place on a connection. At the same
+ // time we do this, we reference the connection. This ensures it does not
+ // get removed out from under us. Note also that we do the connection
+ // lookup within a try/except clause, thus protecting ourselves against
+ // really bogus handles
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+ connection = irpSp->FileObject->FsContext;
+
+ status = StVerifyConnectionObject (connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ //
+ // Initialize bytes transferred here.
+ //
+
+ Irp->IoStatus.Information = 0; // reset byte transfer count.
+
+
+ parameters = (PTDI_REQUEST_KERNEL_RECEIVE)(&irpSp->Parameters);
+ ReceiveBuffer = Irp->MdlAddress;
+ ReceiveBufferLength =parameters->ReceiveLength;
+
+ //
+ // Queue up this receive to the connection object.
+ //
+
+ status = StCreateRequest (
+ Irp, // IRP for this request.
+ connection, // context.
+ REQUEST_FLAGS_CONNECTION, // partial flags.
+ ReceiveBuffer,
+ ReceiveBufferLength,
+ timeout,
+ &tpRequest);
+
+ //
+ // We have a request, now queue it. If the connection has gone south on us
+ // while we were getting things going, we will avoid actually queing the
+ // request.
+ //
+
+ if (NT_SUCCESS (status)) {
+
+ // This reference is removed by StDestroyRequest.
+
+ StReferenceConnection("TdiReceive request", connection);
+ tpRequest->Owner = ConnectionType;
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock,&oldirql);
+ if ((connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
+ RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+ StCompleteRequest (
+ tpRequest,
+ connection->Status,
+ 0);
+ status = STATUS_PENDING;
+ } else {
+
+ //
+ // Insert onto the receive queue, and make the IRP
+ // cancellable.
+ //
+
+ InsertTailList (&connection->ReceiveQueue,&tpRequest->Linkage);
+ RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
+
+ //
+ // If this IRP has been cancelled, then call the
+ // cancel routine.
+ //
+
+ if (Irp->Cancel) {
+ Irp->CancelIrql = cancelirql;
+ StCancelReceive((PDEVICE_OBJECT)(connection->Provider), Irp);
+ StDereferenceConnection ("IRP cancelled", connection); // release lookup hold.
+ return STATUS_PENDING;
+ }
+
+ Irp->CancelRoutine = StCancelReceive;
+ IoReleaseCancelSpinLock(cancelirql);
+
+ AwakenReceive (connection); // awaken if sleeping.
+
+ status = STATUS_PENDING;
+ }
+ }
+
+ StDereferenceConnection("temp TdiReceive", connection);
+
+ return status;
+} /* TdiReceive */
+
+
+NTSTATUS
+StTdiReceiveDatagram(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiReceiveDatagram request for the transport
+ provider. Receive datagrams just get queued up to an address, and are
+ completed when a DATAGRAM or DATAGRAM_BROADCAST frame is received at
+ the address.
+
+Arguments:
+
+ Irp - I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ KIRQL oldirql;
+ PTP_ADDRESS address;
+ PTP_ADDRESS_FILE addressFile;
+ PTP_REQUEST tpRequest;
+ LARGE_INTEGER timeout = {0,0};
+ PIO_STACK_LOCATION irpSp;
+ PMDL ReceiveBuffer;
+ ULONG ReceiveBufferLength;
+
+ //
+ // verify that the operation is taking place on an address. At the same
+ // time we do this, we reference the address. This ensures it does not
+ // get removed out from under us. Note also that we do the address
+ // lookup within a try/except clause, thus protecting ourselves against
+ // really bogus handles
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+ addressFile = irpSp->FileObject->FsContext;
+
+ status = StVerifyAddressObject (addressFile);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ address = addressFile->Address;
+
+ ReceiveBuffer = Irp->MdlAddress;
+ ReceiveBufferLength =
+ ((PTDI_REQUEST_KERNEL_RECEIVEDG)(&irpSp->Parameters))->ReceiveLength;
+
+ status = StCreateRequest (
+ Irp, // IRP for this request.
+ address, // context
+ REQUEST_FLAGS_ADDRESS, // partial flags.
+ ReceiveBuffer,
+ ReceiveBufferLength,
+ timeout,
+ &tpRequest);
+
+ if (NT_SUCCESS (status)) {
+ StReferenceAddress ("Receive datagram", address);
+ tpRequest->Owner = AddressType;
+ ACQUIRE_SPIN_LOCK (&address->SpinLock,&oldirql);
+ if ((address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
+ StCompleteRequest (tpRequest, STATUS_NETWORK_NAME_DELETED, 0);
+ status = STATUS_PENDING;
+ } else {
+ InsertTailList (&addressFile->ReceiveDatagramQueue,&tpRequest->Linkage);
+ RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
+ }
+
+ status = STATUS_PENDING;
+ }
+
+ StDereferenceAddress ("Temp rcv datagram", address);
+
+ return status;
+} /* TdiReceiveDatagram */
+
diff --git a/private/ntos/tdi/st/rcveng.c b/private/ntos/tdi/st/rcveng.c
new file mode 100644
index 000000000..8e104a954
--- /dev/null
+++ b/private/ntos/tdi/st/rcveng.c
@@ -0,0 +1,383 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ rcveng.c
+
+Abstract:
+
+ This module contains code that implements the receive engine for the
+ Sample transport provider.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+VOID
+ActivateReceive(
+ PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine activates the next TdiReceive request on the specified
+ connection object if there is no active request on that connection
+ already. This allows the request to accept data on the connection.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PTP_REQUEST Request;
+
+ //
+ // The ACTIVE_RECEIVE bitflag will be set on the connection if
+ // the receive-fields in the CONNECTION object are valid. If
+ // this flag is cleared, then we try to make the next TdiReceive
+ // request in the ReceiveQueue the active request.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ if (!(Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE)) {
+ if (!IsListEmpty (&Connection->ReceiveQueue)) {
+
+ //
+ // Found a receive, so make it the active one.
+ //
+
+ Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
+
+ Request = CONTAINING_RECORD (
+ Connection->ReceiveQueue.Flink,
+ TP_REQUEST,
+ Linkage);
+ Connection->MessageBytesReceived = 0;
+ Connection->MessageBytesAcked = 0;
+ Connection->CurrentReceiveRequest = Request;
+ Connection->CurrentReceiveMdl = Request->Buffer2;
+ Connection->ReceiveLength = Request->Buffer2Length;
+ Connection->ReceiveByteOffset = 0;
+ }
+ }
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+} /* ActivateReceive */
+
+
+VOID
+AwakenReceive(
+ PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to reactivate a sleeping connection with the
+ RECEIVE_WAKEUP bitflag set because data arrived for which no receive
+ was available. The caller has made a receive available at the connection,
+ so here we activate the next receive, and send the appropriate protocol
+ to restart the message at the first byte offset past the one received
+ by the last receive.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+
+ //
+ // If the RECEIVE_WAKEUP bitflag is set, then awaken the connection.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ if (Connection->Flags & CONNECTION_FLAGS_RECEIVE_WAKEUP) {
+ if (Connection->ReceiveQueue.Flink != &Connection->ReceiveQueue) {
+ Connection->Flags &= ~CONNECTION_FLAGS_RECEIVE_WAKEUP;
+
+ //
+ // Found a receive, so turn off the wakeup flag, and activate
+ // the next receive.
+ //
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ ActivateReceive (Connection);
+
+ return;
+ }
+ }
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+} /* AwakenReceive */
+
+
+VOID
+CompleteReceive(
+ PTP_CONNECTION Connection,
+ BOOLEAN EndOfRecord,
+ KIRQL ConnectionIrql,
+ KIRQL CancelIrql
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by ProcessIncomingData when the current receive
+ must be completed. Depending on whether the current frame being
+ processed is a DATA_FIRST_MIDDLE or DATA_ONLY_LAST, and also whether
+ all of the data was processed, the EndOfRecord flag will be set accordingly
+ by the caller to indicate that a message boundary was received.
+
+ NOTE: This function is called with the connection and cancel
+ IRQLs held, and returns with them released.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+ EndOfRecord - BOOLEAN set to true if TDI_END_OF_RECORD should be reported.
+
+ ConnectionIrql - The IRQL at which the connection spinlock was acquired.
+
+ CancelIrql - The IRQL at which the cancel spinlock was acquired.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PTP_REQUEST Request;
+ KIRQL oldirql = ConnectionIrql;
+ KIRQL cancelirql = CancelIrql;
+ ULONG BytesReceived;
+
+
+ if (IsListEmpty (&Connection->ReceiveQueue)) {
+
+ ASSERT ((Connection->Flags & CONNECTION_FLAGS_STOPPING) != 0);
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+ return;
+ }
+
+ Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE;
+ BytesReceived = Connection->MessageBytesReceived;
+
+
+ //
+ // Complete the TdiReceive request at the head of the
+ // connection's ReceiveQueue.
+ //
+
+ p = RemoveHeadList (&Connection->ReceiveQueue);
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+
+ Request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL;
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+
+ Request->Flags |= REQUEST_FLAGS_DELAY;
+
+ StCompleteRequest(
+ Request,
+ EndOfRecord ? STATUS_SUCCESS : STATUS_BUFFER_OVERFLOW,
+ BytesReceived);
+
+} /* CompleteReceive */
+
+
+VOID
+StCancelReceive(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a receive.
+ The receive is found on the connection's receive queue; if it
+ is the current request it is cancelled and the connection
+ goes into "cancelled receive" mode, otherwise it is cancelled
+ silently.
+
+ In "cancelled receive" mode the connection makes it appear to
+ the remote the data is being received, but in fact it is not
+ indicated to the transport or buffered on our end
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PIO_STACK_LOCATION IrpSp;
+ PTP_CONNECTION Connection;
+ PTP_REQUEST Request;
+ PLIST_ENTRY p;
+ ULONG BytesReceived;
+ BOOLEAN Found;
+
+ UNREFERENCED_PARAMETER (DeviceObject);
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (IrpSp->MinorFunction == TDI_RECEIVE));
+
+ Connection = IrpSp->FileObject->FsContext;
+
+ //
+ // Since this IRP is still in the cancellable state, we know
+ // that the connection is still around (although it may be in
+ // the process of being torn down).
+ //
+
+ //
+ // See if this is the IRP for the current receive request.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ BytesReceived = Connection->MessageBytesReceived;
+
+ p = Connection->ReceiveQueue.Flink;
+
+ //
+ // If there is a receive active, then see if this is it.
+ //
+
+ if ((Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE) != 0) {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+
+ if (Request->IoRequestPacket == Irp) {
+
+ //
+ // yes, it is the active receive. Turn on the RCV_CANCELLED
+ // bit instructing the connection to drop the rest of the
+ // data received (until the DOL comes in).
+ //
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_RCV_CANCELLED;
+ Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE;
+
+ (VOID)RemoveHeadList (&Connection->ReceiveQueue);
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ //
+ // The following dereference will complete the I/O, provided removes
+ // the last reference on the request object. The I/O will complete
+ // with the status and information stored in the Irp. Therefore,
+ // we set those values here before the dereference.
+ //
+
+ StCompleteRequest (Request, STATUS_CANCELLED, 0);
+ return;
+
+ }
+
+ }
+
+
+ //
+ // If we fall through to here, the IRP was not the active receive.
+ // Scan through the list, looking for this IRP.
+ //
+
+ Found = FALSE;
+
+ while (p != &Connection->ReceiveQueue) {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ if (Request->IoRequestPacket == Irp) {
+
+ //
+ // Found it, remove it from the list here.
+ //
+
+ RemoveEntryList (p);
+ Found = TRUE;
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ //
+ // The following dereference will complete the I/O, provided removes
+ // the last reference on the request object. The I/O will complete
+ // with the status and information stored in the Irp. Therefore,
+ // we set those values here before the dereference.
+ //
+
+ StCompleteRequest (Request, STATUS_CANCELLED, 0);
+ break;
+
+ }
+
+ p = p->Flink;
+
+ }
+
+ if (!Found) {
+
+ //
+ // We didn't find it!
+ //
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+ }
+
+}
diff --git a/private/ntos/tdi/st/request.c b/private/ntos/tdi/st/request.c
new file mode 100644
index 000000000..de553c0cc
--- /dev/null
+++ b/private/ntos/tdi/st/request.c
@@ -0,0 +1,801 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ request.c
+
+Abstract:
+
+ This module contains code which implements the TP_REQUEST object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport request objects.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "st.h"
+
+
+VOID
+StTdiRequestTimeoutHandler(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is executed as a DPC at DISPATCH_LEVEL when a request
+ such as TdiSend, TdiReceive, TdiSendDatagram, TdiReceiveDatagram, etc.,
+ encounters a timeout. This routine cleans up the activity and cancels it.
+
+Arguments:
+
+ Dpc - Pointer to a system DPC object.
+
+ DeferredContext - Pointer to the TP_REQUEST block representing the
+ request that has timed out.
+
+ SystemArgument1 - Not used.
+
+ SystemArgument2 - Not used.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PTP_REQUEST Request;
+ PTP_CONNECTION Connection;
+ PIO_STACK_LOCATION IrpSp;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(SystemArgument1);
+ UNREFERENCED_PARAMETER(SystemArgument2);
+
+
+ Request = (PTP_REQUEST)DeferredContext;
+
+ ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql);
+ Request->Flags &= ~REQUEST_FLAGS_TIMER;
+ if ((Request->Flags & REQUEST_FLAGS_STOPPING) == 0) {
+
+ //
+ // find reason for timeout
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket);
+ if (IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) {
+ switch (IrpSp->MinorFunction) {
+
+ //
+ // none of these should time out.
+ //
+
+ case TDI_SEND:
+ case TDI_ACCEPT:
+ case TDI_SET_INFORMATION:
+ case TDI_SET_EVENT_HANDLER:
+ case TDI_SEND_DATAGRAM:
+ case TDI_RECEIVE_DATAGRAM:
+ case TDI_RECEIVE:
+
+ ASSERT (FALSE);
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ StCompleteRequest (Request, STATUS_IO_TIMEOUT, 0);
+ break;
+
+
+ case TDI_LISTEN:
+ case TDI_CONNECT:
+
+ Connection = (PTP_CONNECTION)(Request->Context);
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+
+ //
+ // Since these requests are part of the connection
+ // itself, we just stop the connection and the
+ // request will get torn down then. If we get the
+ // situation where the request times out before
+ // it is queued to the connection, then the code
+ // that is about to queue it will check the STOPPING
+ // flag and complete it then.
+ //
+
+ StStopConnection (Connection, STATUS_IO_TIMEOUT);
+ break;
+
+ case TDI_DISCONNECT:
+
+ //
+ // We don't create requests for TDI_DISCONNECT any more.
+ //
+
+ ASSERT(FALSE);
+ break;
+
+ default:
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ break;
+
+ } // end of switch
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+
+ }
+
+ StDereferenceRequest ("Timeout", Request); // for the timeout
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ StDereferenceRequest ("Timeout: stopping", Request); // for the timeout
+
+ }
+
+ return;
+
+} /* RequestTimeoutHandler */
+
+
+VOID
+StAllocateRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_REQUEST *TransportRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a request packet from nonpaged pool and initializes
+ it to a known state.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ TransportRequest - Pointer to a place where this routine will return
+ a pointer to a transport request structure. It returns NULL if no
+ storage can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PTP_REQUEST Request;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + sizeof(TP_REQUEST)) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("ST: Could not allocate request: limit\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_REQUEST), 104);
+ *TransportRequest = NULL;
+ return;
+ }
+
+ Request = (PTP_REQUEST)ExAllocatePool (NonPagedPool, sizeof (TP_REQUEST));
+ if (Request == NULL) {
+ PANIC("ST: Could not allocate request: no pool\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_REQUEST), 204);
+ *TransportRequest = NULL;
+ return;
+ }
+ RtlZeroMemory (Request, sizeof(TP_REQUEST));
+
+ DeviceContext->MemoryUsage += sizeof(TP_REQUEST);
+ ++DeviceContext->RequestAllocated;
+
+ Request->Type = ST_REQUEST_SIGNATURE;
+ Request->Size = sizeof (TP_REQUEST);
+
+ Request->Provider = DeviceContext;
+ Request->ProviderInterlock = &DeviceContext->Interlock;
+ KeInitializeSpinLock (&Request->SpinLock);
+ KeInitializeDpc (&Request->Dpc, StTdiRequestTimeoutHandler, (PVOID)Request);
+ KeInitializeTimer (&Request->Timer); // set to not-signaled state.
+
+ *TransportRequest = Request;
+
+} /* StAllocateRequest */
+
+
+VOID
+StDeallocateRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_REQUEST TransportRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees a request packet.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ TransportRequest - Pointer to a transport request structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ExFreePool (TransportRequest);
+ --DeviceContext->RequestAllocated;
+ DeviceContext->MemoryUsage -= sizeof(TP_REQUEST);
+
+} /* StDeallocateRequest */
+
+
+NTSTATUS
+StCreateRequest(
+ IN PIRP Irp,
+ IN PVOID Context,
+ IN ULONG Flags,
+ IN PMDL Buffer2,
+ IN ULONG Buffer2Length,
+ IN LARGE_INTEGER Timeout,
+ OUT PTP_REQUEST * TpRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a transport request and associates it with the
+ specified IRP, context, and queue. All major requests, including
+ TdiSend, TdiSendDatagram, TdiReceive, and TdiReceiveDatagram requests,
+ are composed in this manner.
+
+Arguments:
+
+ Irp - Pointer to an IRP which was received by the transport for this
+ request.
+
+ Context - Pointer to anything to associate this request with. This
+ value is not interpreted except at request cancelation time.
+
+ Flags - A set of bitflags indicating the disposition of this request.
+
+ Timeout - Timeout value (if non-zero) to start a timer for this request.
+ If zero, then no timer is activated for the request.
+
+ TpRequest - If the function returns STATUS_SUCCESS, this will return
+ pointer to the TP_REQUEST structure allocated.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_REQUEST Request;
+ PLIST_ENTRY p;
+ PIO_STACK_LOCATION irpSp;
+
+
+ irpSp = IoGetCurrentIrpStackLocation(Irp);
+ DeviceContext = (PDEVICE_CONTEXT)irpSp->FileObject->DeviceObject;
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ p = RemoveHeadList (&DeviceContext->RequestPool);
+ if (p == &DeviceContext->RequestPool) {
+
+ if ((DeviceContext->RequestMaxAllocated == 0) ||
+ (DeviceContext->RequestAllocated < DeviceContext->RequestMaxAllocated)) {
+
+ StAllocateRequest (DeviceContext, &Request);
+
+ } else {
+
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_REQUEST), 404);
+ Request = NULL;
+
+ }
+
+ if (Request == NULL) {
+ ++DeviceContext->RequestExhausted;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ PANIC ("StCreateConnection: Could not allocate request object!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ } else {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+
+ }
+
+ ++DeviceContext->RequestInUse;
+ if (DeviceContext->RequestInUse > DeviceContext->RequestMaxInUse) {
+ ++DeviceContext->RequestMaxInUse;
+ }
+
+ DeviceContext->RequestTotal += DeviceContext->RequestInUse;
+ ++DeviceContext->RequestSamples;
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+
+ //
+ // fill out the request.
+ //
+
+ // Request->Provider = DeviceContext;
+ Request->IoRequestPacket = Irp;
+ Request->Buffer2 = Buffer2;
+ Request->Buffer2Length = Buffer2Length;
+ Request->Flags = Flags;
+ Request->Context = Context;
+ Request->ReferenceCount = 1; // initialize reference count.
+
+ if ((Timeout.LowPart == 0) && (Timeout.HighPart == 0)) {
+
+ // no timeout
+ } else {
+
+ Request->Flags |= REQUEST_FLAGS_TIMER; // there is a timeout on this request.
+ KeInitializeTimer (&Request->Timer); // set to not-signaled state.
+ StReferenceRequest ("Create: timer", Request); // one for the timer
+ KeSetTimer (&Request->Timer, Timeout, &Request->Dpc);
+ }
+
+ *TpRequest = Request;
+
+ return STATUS_SUCCESS;
+} /* StCreateRequest */
+
+
+VOID
+StDestroyRequest(
+ IN PTP_REQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns a request block to the free pool.
+
+Arguments:
+
+ Request - Pointer to a TP_REQUEST block to return to the free pool.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PIO_STACK_LOCATION irpSp;
+ PDEVICE_CONTEXT DeviceContext;
+
+ //
+ // Return the request to the caller with whatever status is in the IRP.
+ //
+
+ //
+ // Now dereference the owner of this request so that we are safe when
+ // we finally tear down the {connection, address}. The problem we're
+ // facing here is that we can't allow the user to assume semantics;
+ // the end of life for a connection must truly be the real end of life.
+ // for that to occur, we reference the owning object when the request is
+ // created and we dereference it just before we return it to the pool.
+ //
+
+ switch (Request->Owner) {
+ case ConnectionType:
+ if (!(Request->Flags & REQUEST_FLAGS_DELAY)) {
+ StDereferenceConnection ("Removing Connection",((PTP_CONNECTION)Request->Context));
+ }
+ break;
+
+ case AddressType:
+ StDereferenceAddress ("Removing Address", ((PTP_ADDRESS)Request->Context));
+ break;
+
+ case DeviceContextType:
+ StDereferenceDeviceContext ("Removing Address", ((PDEVICE_CONTEXT)Request->Context));
+ break;
+ }
+
+ irpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket);
+ DeviceContext = Request->Provider;
+
+ if (Request->Flags & REQUEST_FLAGS_DELAY) {
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ InsertTailList(
+ &DeviceContext->IrpCompletionQueue,
+ &Request->IoRequestPacket->Tail.Overlay.ListEntry);
+
+ } else {
+
+ IoCompleteRequest (Request->IoRequestPacket, IO_NETWORK_INCREMENT);
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ }
+
+ //
+ // Put the request back on the free list. NOTE: we have the
+ // lock held here.
+ //
+
+
+ DeviceContext->RequestTotal += DeviceContext->RequestInUse;
+ ++DeviceContext->RequestSamples;
+ --DeviceContext->RequestInUse;
+
+ if ((DeviceContext->RequestAllocated - DeviceContext->RequestInUse) >
+ DeviceContext->RequestInitAllocated) {
+ StDeallocateRequest (DeviceContext, Request);
+ } else {
+ InsertTailList (&DeviceContext->RequestPool, &Request->Linkage);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+} /* StDestroyRequest */
+
+
+VOID
+StRefRequest(
+ IN PTP_REQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport request.
+
+Arguments:
+
+ Request - Pointer to a TP_REQUEST block.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ASSERT (Request->ReferenceCount > 0);
+
+ InterlockedIncrement (&Request->ReferenceCount);
+
+} /* StRefRequest */
+
+
+VOID
+StDerefRequest(
+ IN PTP_REQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport request by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ StDestroyRequest to remove it from the system.
+
+Arguments:
+
+ Request - Pointer to a transport request object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&Request->ReferenceCount);
+
+ ASSERT (result >= 0);
+
+ //
+ // If we have deleted all references to this request, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the request any longer.
+ //
+
+ if (result == 0) {
+ StDestroyRequest (Request);
+ }
+
+} /* StDerefRequest */
+
+
+VOID
+StCompleteRequest(
+ IN PTP_REQUEST Request,
+ IN NTSTATUS Status,
+ IN ULONG Information
+ )
+
+/*++
+
+Routine Description:
+
+ This routine completes a transport request object, completing the I/O,
+ stopping the timeout, and freeing up the request object itself.
+
+Arguments:
+
+ Request - Pointer to a transport request object.
+
+ Status - Actual return status to be assigned to the request. This
+ value may be overridden if the timed-out bitflag is set in the request.
+
+ Information - the information field for the I/O Status Block.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PIRP Irp;
+ NTSTATUS FinalStatus = Status;
+ BOOLEAN TimerWasSet;
+
+ ASSERT (Status != STATUS_PENDING);
+
+ if (Request->Flags & REQUEST_FLAGS_SEND_RCV) {
+
+ //
+ // Sends and receives we check for since we know
+ // they don't have timers and should only complete
+ // once.
+ //
+
+ Request->Flags |= REQUEST_FLAGS_STOPPING;
+ Irp = Request->IoRequestPacket;
+ Irp->IoStatus.Status = FinalStatus;
+ Irp->IoStatus.Information = Information;
+
+ StDereferenceRequest ("Complete", Request); // remove creation reference.
+ return;
+ }
+
+
+ ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql);
+
+ if ((Request->Flags & REQUEST_FLAGS_STOPPING) == 0) {
+ Request->Flags |= REQUEST_FLAGS_STOPPING;
+
+ //
+ // Cancel the pending timeout on this request. Not all requests
+ // have their timer set. If this request has the TIMER bit set,
+ // then the timer needs to be cancelled. If it cannot be cancelled,
+ // then the timer routine will be run, so we just return and let
+ // the timer routine worry about cleaning up this request.
+ //
+
+ if ((Request->Flags & REQUEST_FLAGS_TIMER) != 0) {
+ Request->Flags &= ~REQUEST_FLAGS_TIMER;
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ TimerWasSet = KeCancelTimer (&Request->Timer);
+
+ if (TimerWasSet) {
+ StDereferenceRequest ("Complete: stop timer", Request);
+ }
+
+ } else {
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ }
+
+ Irp = Request->IoRequestPacket;
+
+
+ //
+ // Install the return code in the IRP so that when we call StDestroyRequest,
+ // it will get completed with the proper return status.
+ //
+
+ Irp->IoStatus.Status = FinalStatus;
+ Irp->IoStatus.Information = Information;
+
+ //
+ // The entire transport is done with this request.
+ //
+
+ StDereferenceRequest ("Complete", Request); // remove creation reference.
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+
+ }
+
+} /* StCompleteRequest */
+
+
+VOID
+StRefSendIrp(
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a send IRP.
+
+Arguments:
+
+ IrpSp - Pointer to the IRP's stack location.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ASSERT (IRP_REFCOUNT(IrpSp) > 0);
+
+ InterlockedIncrement (&IRP_REFCOUNT(IrpSp));
+
+} /* StRefSendIrp */
+
+
+VOID
+StDerefSendIrp(
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport send IRP by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IoCompleteRequest to actually complete the IRP.
+
+ NOTE: This assume that IRP_CONNECTION(IrpSp) has been changed
+ to point to the IRP instead of the connection.
+
+Arguments:
+
+ Request - Pointer to a transport send IRP's stack location.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&IRP_REFCOUNT(IrpSp));
+
+ ASSERT (result >= 0);
+
+ //
+ // If we have deleted all references to this request, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the request any longer.
+ //
+
+ if (result == 0) {
+
+ PIRP Irp = (PIRP)IRP_CONNECTION(IrpSp);
+
+ IRP_REFCOUNT(IrpSp) = 0;
+ IRP_CONNECTION (IrpSp) = NULL;
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ }
+
+} /* StDerefSendIrp */
+
+
+VOID
+StCompleteSendIrp(
+ IN PIRP Irp,
+ IN NTSTATUS Status,
+ IN ULONG Information
+ )
+
+/*++
+
+Routine Description:
+
+ This routine completes a transport send IRP.
+
+Arguments:
+
+ Irp - Pointer to a send IRP.
+
+ Status - Actual return status to be assigned to the request. This
+ value may be overridden if the timed-out bitflag is set in the request.
+
+ Information - the information field for the I/O Status Block.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ PTP_CONNECTION Connection;
+
+ ASSERT (Status != STATUS_PENDING);
+
+ Connection = IRP_CONNECTION(IrpSp);
+
+
+ //
+ // Sends and receives we check for since we know
+ // they don't have timers and should only complete
+ // once.
+ //
+
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = Information;
+
+ IRP_CONNECTION(IrpSp) = Irp;
+
+ StDereferenceSendIrp ("Complete", IrpSp); // remove creation reference.
+
+ StDereferenceConnection ("Removing Connection", Connection);
+
+} /* StCompleteSendIrp */
diff --git a/private/ntos/tdi/st/send.c b/private/ntos/tdi/st/send.c
new file mode 100644
index 000000000..0e6a2b9f6
--- /dev/null
+++ b/private/ntos/tdi/st/send.c
@@ -0,0 +1,385 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiSend
+ o TdiSendDatagram
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+NTSTATUS
+StTdiSend(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSend request for the transport provider.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql, cancelirql;
+ NTSTATUS status;
+ PTP_CONNECTION connection;
+ PMDL SendBuffer;
+ ULONG SendBufferLength;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL_SEND parameters;
+ PIRP TempIrp;
+
+ //
+ // Determine which connection this send belongs on.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // Check that this is really a connection.
+ //
+
+ if ((connection->Size != sizeof (TP_CONNECTION)) ||
+ (connection->Type != ST_CONNECTION_SIGNATURE)) {
+ return STATUS_INVALID_CONNECTION;
+ }
+
+ //
+ // Now map the data in to SVA space.
+ //
+
+ parameters = (PTDI_REQUEST_KERNEL_SEND)(&irpSp->Parameters);
+ SendBuffer = Irp->MdlAddress;
+ SendBufferLength = parameters->SendLength;
+
+ //
+ // Interpret send options.
+ //
+
+ //
+ // Now we have a reference on the connection object. Queue up this
+ // send to the connection object.
+ //
+
+
+ // This reference is removed by TdiDestroyRequest
+
+ StReferenceConnection("TdiSend", connection);
+
+ IRP_CONNECTION(irpSp) = connection;
+ IRP_REFCOUNT(irpSp) = 1;
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock,&oldirql);
+
+ if ((connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
+ RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+ StCompleteSendIrp(
+ Irp,
+ connection->Status,
+ 0);
+ status = STATUS_PENDING;
+ } else {
+
+ StReferenceConnection ("Verify Temp Use", connection);
+
+ //
+ // Insert onto the send queue, and make the IRP
+ // cancellable.
+ //
+
+ InsertTailList (&connection->SendQueue,&Irp->Tail.Overlay.ListEntry);
+
+
+ //
+ // If this IRP has been cancelled, then call the
+ // cancel routine.
+ //
+
+ if (Irp->Cancel) {
+ RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
+ Irp->CancelIrql = cancelirql;
+ StCancelSend((PDEVICE_OBJECT)(connection->Provider), Irp);
+ StDereferenceConnection ("IRP cancelled", connection); // release lookup hold.
+ return STATUS_PENDING;
+ }
+
+ Irp->CancelRoutine = StCancelSend;
+
+ //
+ // If this connection is waiting for an EOR to appear because a non-EOR
+ // send failed at some point in the past, fail this send. Clear the
+ // flag that causes this if this request has the EOR set.
+ //
+ // BUGBUG: Should the FailSend status be clearer here?
+ //
+
+ if ((connection->Flags & CONNECTION_FLAGS_FAILING_TO_EOR) != 0) {
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ //
+ // BUGBUG: Should we save status from real failure?
+ //
+
+ FailSend (connection, STATUS_LINK_FAILED, TRUE);
+
+ if ( (parameters->SendFlags & TDI_SEND_PARTIAL) == 0) {
+ connection->Flags &= ~CONNECTION_FLAGS_FAILING_TO_EOR;
+ }
+
+ StDereferenceConnection ("Failing to EOR", connection); // release lookup hold.
+ return STATUS_PENDING;
+ }
+
+
+ //
+ // If the send state is either IDLE or W_EOR, then we should
+ // begin packetizing this send. Otherwise, some other event
+ // will cause it to be packetized.
+ //
+
+ //
+ // NOTE: If we call StartPacketizingConnection, we make
+ // sure that it is the last operation we do on this
+ // connection. This allows us to "hand off" the reference
+ // we have to that function, which converts it into
+ // a reference for being on the packetize queue.
+ //
+
+ switch (connection->SendState) {
+
+ case CONNECTION_SENDSTATE_IDLE:
+
+ InitializeSend (connection); // sets state to PACKETIZE
+
+ //
+ // If we can, packetize right now.
+ //
+
+ if ((!(connection->Flags & CONNECTION_FLAGS_PACKETIZE)) &&
+ (!(connection->Flags & CONNECTION_FLAGS_STOPPING))) {
+
+ connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ PacketizeSend (connection);
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ StDereferenceConnection ("Stopping or already packetizing", connection); // release lookup hold.
+
+ }
+
+ break;
+
+ case CONNECTION_SENDSTATE_W_EOR:
+ connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
+
+ //
+ // Adjust the send variables on the connection so that
+ // they correctly point to this new send. We can't call
+ // InitializeSend to do that, because we need to keep
+ // track of the other outstanding sends on this connection
+ // which have been sent but are a part of this message.
+ //
+
+ TempIrp = CONTAINING_RECORD(
+ connection->SendQueue.Flink,
+ IRP,
+ Tail.Overlay.ListEntry);
+
+ connection->sp.CurrentSendIrp = TempIrp;
+ connection->sp.CurrentSendMdl = TempIrp->MdlAddress;
+ connection->sp.SendByteOffset = 0;
+ connection->CurrentSendLength +=
+ IRP_SEND_LENGTH(IoGetCurrentIrpStackLocation(TempIrp));
+
+ StartPacketizingConnection (connection, TRUE, oldirql, cancelirql);
+ break;
+
+ default:
+
+ //
+ // The connection is in another state (such as
+ // W_ACK or W_LINK), we just need to make sure
+ // to call InitializeSend if the new one is
+ // the first one on the list.
+ //
+
+ //
+ // BUGBUG: Currently InitializeSend sets SendState,
+ // we should fix this.
+ //
+
+ if (connection->SendQueue.Flink == &Irp->Tail.Overlay.ListEntry) {
+ ULONG SavedSendState;
+ SavedSendState = connection->SendState;
+ InitializeSend (connection);
+ connection->SendState = SavedSendState;
+ }
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ StDereferenceConnection("temp TdiSend", connection);
+
+ }
+
+ }
+
+ status = STATUS_PENDING;
+
+
+ return status;
+} /* TdiSend */
+
+
+NTSTATUS
+StTdiSendDatagram(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSendDatagram request for the transport
+ provider.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ KIRQL oldirql;
+ PTP_REQUEST tpRequest;
+ PTP_ADDRESS_FILE addressFile;
+ PTP_ADDRESS address;
+ PMDL SendBuffer;
+ ULONG SendBufferLength;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL_SENDDG parameters;
+ LARGE_INTEGER timeout = {0,0};
+ UINT MaxUserData;
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+ addressFile = irpSp->FileObject->FsContext;
+
+ status = StVerifyAddressObject (addressFile);
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ address = addressFile->Address;
+ parameters = (PTDI_REQUEST_KERNEL_SENDDG)(&irpSp->Parameters);
+ SendBuffer = Irp->MdlAddress;
+ SendBufferLength = parameters->SendLength;
+
+ //
+ // Check that the length is short enough.
+ //
+
+ MacReturnMaxDataSize(
+ &address->Provider->MacInfo,
+ NULL,
+ 0,
+ address->Provider->MaxSendPacketSize,
+ &MaxUserData);
+
+ if (SendBufferLength >
+ (MaxUserData - sizeof(ST_HEADER))) {
+
+ return STATUS_INVALID_PARAMETER;
+
+ }
+
+ //
+ // We need a request object to keep track of this TDI request.
+ // Attach this request to the address object.
+ //
+
+ status = StCreateRequest (
+ Irp, // IRP for this request.
+ address, // context.
+ REQUEST_FLAGS_ADDRESS, // partial flags.
+ SendBuffer, // the data to be sent.
+ SendBufferLength, // length of the data.
+ timeout,
+ &tpRequest);
+
+ if (!NT_SUCCESS (status)) {
+ StDereferenceAddress ("no send request", address);
+ return status; // if we couldn't queue the request.
+ }
+
+ StReferenceAddress ("Send datagram", address);
+ tpRequest->Owner = AddressType;
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock,&oldirql);
+
+ if ((address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
+ StCompleteRequest (tpRequest, STATUS_NETWORK_NAME_DELETED, 0);
+ return STATUS_PENDING;
+ } else {
+ InsertTailList (
+ &address->SendDatagramQueue,
+ &tpRequest->Linkage);
+ RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
+ }
+
+ //
+ // The request is queued. Ship the next request at the head of the queue,
+ // provided the completion handler is not active. We serialize this so
+ // that only one MDL and ST datagram header needs to be statically
+ // allocated for reuse by all send datagram requests.
+ //
+
+ (VOID)StSendDatagramsOnAddress (address);
+
+ StDereferenceAddress("tmp send datagram", address);
+
+ return STATUS_PENDING;
+
+} /* StTdiSendDatagram */
diff --git a/private/ntos/tdi/st/sendeng.c b/private/ntos/tdi/st/sendeng.c
new file mode 100644
index 000000000..4019291de
--- /dev/null
+++ b/private/ntos/tdi/st/sendeng.c
@@ -0,0 +1,1505 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ sendeng.c
+
+Abstract:
+
+ This module contains code that implements the send engine for the
+ Sample transport provider.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "st.h"
+#if 27
+ULONG StNoisySend = 0;
+ULONG StSndLoc = 0;
+ULONG StSnds[10];
+#endif
+
+
+VOID
+StartPacketizingConnection(
+ PTP_CONNECTION Connection,
+ IN BOOLEAN Immediate,
+ IN KIRQL ConnectionIrql,
+ IN KIRQL CancelIrql
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to place a connection on the PacketizeQueue
+ of its device context object. Then this routine starts packetizing
+ the first connection on that queue.
+
+ *** The Connection spin lock must be held on entry to this routine.
+ Optionally, the cancel spin lock may be held. If so, the cancel
+ spin lock must have been acquired first.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+ Immediate - TRUE if the connection should be packetized
+ immediately; FALSE if the connection should be queued
+ up for later packetizing (implies that ReceiveComplete
+ will be called in the future, which packetizes always).
+
+ NOTE: If this is TRUE, it also implies that we have
+ a connection reference.
+
+ ConnectionIrql - The OldIrql value when the connection spin lock
+ was acquired.
+
+ CancelIrql - The OldIrql value when the cancel spin lock was
+ acquired. -1 means that the cancel spin lock isn't held.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+
+ DeviceContext = Connection->Provider;
+
+ //
+ // If this connection's SendState is set to PACKETIZE and if
+ // we are not already on the PacketizeQueue, then go ahead and
+ // append us to the end of that queue, and remember that we're
+ // on it by setting the CONNECTION_FLAGS_PACKETIZE bitflag.
+ //
+ // Also don't queue it if the connection is stopping.
+ //
+
+ if ((Connection->SendState == CONNECTION_SENDSTATE_PACKETIZE) &&
+ !(Connection->Flags &
+ (CONNECTION_FLAGS_PACKETIZE | CONNECTION_FLAGS_STOPPING))) {
+
+ Connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
+
+ if (!Immediate) {
+ StReferenceConnection ("Packetize", Connection);
+ }
+
+ ExInterlockedInsertTailList(
+ &DeviceContext->PacketizeQueue,
+ &Connection->PacketizeLinkage,
+ &DeviceContext->SpinLock);
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, ConnectionIrql);
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, ConnectionIrql);
+ if (Immediate) {
+ StDereferenceConnection("temp TdiSend", Connection);
+ }
+ }
+
+ if (CancelIrql != (KIRQL)-1) {
+ IoReleaseCancelSpinLock (CancelIrql);
+ }
+
+ if (Immediate) {
+ PacketizeConnections (DeviceContext);
+ }
+
+} /* StartPacketizingConnection */
+
+
+VOID
+PacketizeConnections(
+ PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to packetize all connections waiting on the
+ PacketizeQueue of the DeviceContext.
+
+
+Arguments:
+
+ DeviceContext - Pointer to a DEVICE_CONTEXT object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PTP_CONNECTION Connection;
+
+ //
+ // Pick connections off of the device context's packetization queue
+ // until there are no more left to pick off. For each one, we call
+ // PacketizeSend. Note this routine can be executed concurrently
+ // on multiple processors and it doesn't matter; multiple connections
+ // may be packetized concurrently.
+ //
+
+ while (TRUE) {
+
+ p = ExInterlockedRemoveHeadList(
+ &DeviceContext->PacketizeQueue,
+ &DeviceContext->SpinLock);
+
+ if (p == NULL) {
+ break;
+ }
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, PacketizeLinkage);
+ PacketizeSend (Connection);
+ }
+
+} /* PacketizeConnections */
+
+
+VOID
+PacketizeSend(
+ PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine packetizes the current TdiSend request on the specified
+ connection as much as limits will permit. A given here is that there
+ is an active send on the connection that needs further packetization.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ ULONG MaxFrameSize, FrameSize;
+ ULONG PacketBytes;
+ TP_SEND_POINTER SavedSendPointer;
+ PNDIS_BUFFER PacketDescriptor;
+ PUCHAR SourceRouting;
+ UINT SourceRoutingLength;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_PACKET Packet;
+ NTSTATUS Status;
+ PST_HEADER StHeader;
+ UINT HeaderLength;
+ PIO_STACK_LOCATION IrpSp;
+ PSEND_PACKET_TAG SendTag;
+ ULONG LastPacketLength;
+
+ DeviceContext = Connection->Provider;
+
+ //
+ // Just loop until one of three events happens: (1) we run out of
+ // packets from StCreatePacket, (2) we completely packetize the send.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ if (Connection->SendState != CONNECTION_SENDSTATE_PACKETIZE) {
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ StDereferenceConnection ("No longer packetizing", Connection);
+ return;
+ }
+
+ MaxFrameSize = Connection->MaximumDataSize;
+
+ //
+ // It is possible for a frame to arrive during the middle of this loop
+ // (such as a NO_RECEIVE) that will put us into a new state (such as
+ // W_RCVCONT). For this reason, we have to check the state every time
+ // (at the end of the loop).
+ //
+
+ do {
+
+ if (!NT_SUCCESS (StCreatePacket (DeviceContext, &Packet))) {
+
+ //
+ // We need a packet to finish packetizing the current send, but
+ // there are no more packets available in the pool right now.
+ // Set our send state to W_PACKET, and put this connection on
+ // the PacketWaitQueue of the device context object. Then,
+ // when StDestroyPacket frees up a packet, it will check this
+ // queue for starved connections, and if it finds one, it will
+ // take a connection off the list and set its send state to
+ // SENDSTATE_PACKETIZE and put it on the PacketizeQueue.
+ //
+
+ Connection->SendState = CONNECTION_SENDSTATE_W_PACKET;
+
+ //
+ // Clear the PACKETIZE flag, indicating that we're no longer
+ // on the PacketizeQueue or actively packetizing. The flag
+ // was set by StartPacketizingConnection to indicate that
+ // the connection was already on the PacketizeQueue.
+ //
+ // Don't queue him if the connection is stopping.
+ //
+
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+
+ if (!(Connection->Flags & CONNECTION_FLAGS_STOPPING)) {
+ Connection->Flags |= CONNECTION_FLAGS_SUSPENDED;
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql1);
+ InsertTailList (&DeviceContext->PacketWaitQueue, &Connection->PacketWaitLinkage);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql1);
+ }
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ StDereferenceConnection ("No packet", Connection);
+ return;
+
+ }
+
+ //
+ // Add a reference count to the IRP, and keep track of
+ // which request it is. Send completion will remove the
+ // reference.
+
+ IrpSp = IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp);
+
+ SendTag = (PSEND_PACKET_TAG)(Packet->NdisPacket->ProtocolReserved);
+ SendTag->Type = TYPE_I_FRAME;
+ SendTag->Packet = Packet;
+ SendTag->Owner = (PVOID)IrpSp;
+
+ Packet->CompleteSend = FALSE;
+
+
+ //
+ // Build the MAC header. All frames go out as
+ // single-route source routing.
+ //
+
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SourceRouting,
+ &SourceRoutingLength);
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ DeviceContext->MulticastAddress.Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof(ST_HEADER),
+ SourceRouting,
+ SourceRoutingLength,
+ &HeaderLength);
+
+ //
+ // Build the header: 'I', dest, source
+ //
+
+ StHeader = (PST_HEADER)(&Packet->Header[HeaderLength]);
+
+ StHeader->Signature = ST_SIGNATURE;
+ StHeader->Command = ST_CMD_INFORMATION;
+ StHeader->Flags = 0;
+
+ RtlCopyMemory (StHeader->Destination, Connection->CalledAddress.NetbiosName, 16);
+ RtlCopyMemory (StHeader->Source, Connection->AddressFile->Address->NetworkName->NetbiosName, 16);
+
+ HeaderLength += sizeof(ST_HEADER);
+
+
+ //
+ // Modify the packet length and send the it.
+ //
+
+ StSetNdisPacketLength(Packet->NdisPacket, HeaderLength);
+
+ StReferenceSendIrp ("Packetize", IrpSp);
+
+ //
+ // Save our complex send pointer in case we have to restore it
+ // because StNdisSend fails.
+ //
+
+ SavedSendPointer = Connection->sp;
+
+ //
+ // build an NDIS_BUFFER chain that describes the buffer we're using, and
+ // thread it off the NdisBuffer. This chain may not complete the
+ // packet, as the remaining part of the MDL chain may be shorter than
+ // the packet.
+ //
+
+ FrameSize = MaxFrameSize;
+
+ //
+ // Check if we have less than FrameSize left to send.
+ //
+
+ if (Connection->sp.MessageBytesSent + FrameSize > Connection->CurrentSendLength) {
+
+ FrameSize = Connection->CurrentSendLength - Connection->sp.MessageBytesSent;
+
+ }
+#if 27
+ if (StNoisySend) {
+ DbgPrint ("Send %d of %d\n", FrameSize, Connection->CurrentSendLength);
+ }
+ if (FrameSize > 1000) {
+ StSnds[StSndLoc] = FrameSize;
+ StSndLoc = (StSndLoc + 1) % 10;
+ }
+#endif
+
+
+ //
+ // Make a copy of the MDL chain for this send, unless
+ // there are zero bytes left.
+ //
+
+ if (FrameSize != 0) {
+
+ //
+ // If the whole send will fit inside one packet,
+ // then there is no need to duplicate the MDL
+ // (note that this may include multi-MDL sends).
+ //
+
+ if ((Connection->sp.SendByteOffset == 0) &&
+ (Connection->CurrentSendLength == FrameSize)) {
+
+ PacketDescriptor = (PNDIS_BUFFER)Connection->sp.CurrentSendMdl;
+ PacketBytes = FrameSize;
+ Connection->sp.CurrentSendMdl = NULL;
+ Connection->sp.SendByteOffset = FrameSize;
+ Packet->PacketNoNdisBuffer = TRUE;
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ Status = BuildBufferChainFromMdlChain (
+ DeviceContext->NdisBufferPoolHandle,
+ Connection->sp.CurrentSendMdl,
+ Connection->sp.SendByteOffset,
+ FrameSize,
+ &PacketDescriptor,
+ &Connection->sp.CurrentSendMdl,
+ &Connection->sp.SendByteOffset,
+ &PacketBytes);
+
+ }
+
+ } else {
+
+ PacketBytes = 0;
+ Connection->sp.CurrentSendMdl = NULL;
+ Status = STATUS_SUCCESS;
+
+ }
+
+ if (NT_SUCCESS (Status)) {
+
+ Connection->sp.MessageBytesSent += PacketBytes;
+
+ //
+ // Chain the buffers to the packet, unless there
+ // are zero bytes of data.
+ //
+
+ if (FrameSize != 0) {
+ NdisChainBufferAtBack (Packet->NdisPacket, PacketDescriptor);
+ }
+
+
+ //
+ // Have we run out of Mdl Chain in this request?
+ //
+
+ if ((PacketBytes < FrameSize) ||
+ (Connection->sp.CurrentSendMdl == NULL) ||
+ (Connection->CurrentSendLength <= Connection->sp.MessageBytesSent)) {
+
+ //
+ // Yep. We know that we've exhausted the current request's buffer
+ // here, so see if there's another request without EOF set that we
+ // can build start throwing into this packet.
+ //
+
+
+ if (!(IRP_SEND_FLAGS(IrpSp) & TDI_SEND_PARTIAL)) {
+
+ //
+ // We are sending the last packet in a message. Change
+ // the packet type to a "last" frame.
+ //
+
+ StHeader->Flags |= ST_FLAGS_LAST;
+ Packet->CompleteSend = TRUE;
+ Connection->SendState = CONNECTION_SENDSTATE_IDLE;
+
+ } else {
+
+ //
+ // We are sending the last packet in this request. If there
+ // are more requests in the connection's SendQueue, then
+ // advance complex send pointer to point to the next one
+ // in line. Otherwise, if there aren't any more requests
+ // ready to packetize, then we enter the W_EOR state and
+ // stop packetizing. Note that we're waiting here for the TDI
+ // client to come up with data to send; we're just hanging out
+ // until then.
+ //
+
+ if (Connection->sp.CurrentSendIrp->Tail.Overlay.ListEntry.Flink == &Connection->SendQueue) {
+
+ Connection->SendState = CONNECTION_SENDSTATE_W_EOR;
+
+ } else {
+
+ Connection->sp.CurrentSendIrp =
+ CONTAINING_RECORD (
+ Connection->sp.CurrentSendIrp->Tail.Overlay.ListEntry.Flink,
+ IRP,
+ Tail.Overlay.ListEntry);
+ Connection->sp.CurrentSendMdl =
+ Connection->sp.CurrentSendIrp->MdlAddress;
+ Connection->sp.SendByteOffset = 0;
+ Connection->CurrentSendLength +=
+ IRP_SEND_LENGTH(IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp));
+ }
+ }
+ }
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ LastPacketLength = sizeof(ST_HEADER) + PacketBytes;
+
+ MacModifyHeader(
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ LastPacketLength);
+
+ Packet->NdisIFrameLength = LastPacketLength;
+
+ StNdisSend (Packet);
+
+ //
+ // Update our counters (this is done unprotected by a lock).
+ //
+
+ ADD_TO_LARGE_INTEGER(
+ &DeviceContext->IFrameBytesSent,
+ PacketBytes);
+ ++DeviceContext->IFramesSent;
+
+ } else {
+
+ //
+ // BuildBufferChainFromMdlChain failed; we need to
+ // release the lock since the long if() above
+ // exits with it released.
+ //
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ }
+
+ //
+ // Note that we may have fallen out of the BuildBuffer... if above with
+ // Status set to STATUS_INSUFFICIENT_RESOURCES. if we have, we'll just
+ // stick this connection back onto the packetize queue and hope the
+ // system gets more resources later.
+ //
+
+
+ if (!NT_SUCCESS (Status)) {
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ //
+ // Restore old complex send pointer.
+ //
+
+ Connection->sp = SavedSendPointer;
+
+
+ //
+ // Indicate we're waiting on favorable link conditions.
+ //
+
+ Connection->SendState = CONNECTION_SENDSTATE_W_LINK;
+
+ //
+ // Clear the PACKETIZE flag, indicating that we're no longer
+ // on the PacketizeQueue or actively packetizing. The flag
+ // was set by StartPacketizingConnection to indicate that
+ // the connection was already on the PacketizeQueue.
+ //
+
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ StDestroyPacket (Packet);
+ StDereferenceSendIrp("Send failed", IrpSp);
+ StDereferenceConnection ("Send failed", Connection);
+
+ return;
+ }
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ //
+ // It is probable that a frame arrived while we released
+ // the connection's spin lock, so our state has probably changed.
+ // When we cycle around this loop again, we will have the lock
+ // again, so we can test the connection's send state.
+ //
+
+ } while (Connection->SendState == CONNECTION_SENDSTATE_PACKETIZE);
+
+ //
+ // Clear the PACKETIZE flag, indicating that we're no longer on the
+ // PacketizeQueue or actively packetizing. The flag was set by
+ // StartPacketizingConnection to indicate that the connection was
+ // already on the PacketizeQueue.
+ //
+
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ StDereferenceConnection ("PacketizeSend done", Connection);
+
+} /* PacketizeSend */
+
+
+VOID
+CompleteSend(
+ PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to complete a TDI send back to the
+ caller. In the sample transport we assume that all sends
+ complete successfully, but in other transports we would
+ wait for a response from the remote.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql, cancelirql;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+ PLIST_ENTRY p;
+ BOOLEAN EndOfRecord;
+
+ //
+ // Pick off TP_REQUEST objects from the connection's SendQueue until
+ // we find one with an END_OF_RECORD mark embedded in it.
+ //
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ while (TRUE) {
+
+ //
+ // We know for a fact that we wouldn't be calling this routine if
+ // we hadn't completed sending an entire message, since we
+ // only set the ST_LAST bit in that case. Therefore, we
+ // know that we will run into a request with the END_OF_RECORD
+ // mark set BEFORE we will run out of requests on that queue,
+ // so there is no reason to check to see if we ran off the end.
+ // Note that it's possible that the send has been failed and the
+ // connection not yet torn down; if this has happened, we could be
+ // removing from an empty queue here. Make sure that doesn't happen.
+ //
+
+ if (Connection->SendQueue.Flink == &Connection->SendQueue) {
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ //
+ // no requests to complete, things must have failed; just get out.
+ //
+
+ break;
+ }
+
+ p = RemoveHeadList (&Connection->SendQueue);
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ EndOfRecord = !(IRP_SEND_FLAGS(IrpSp) & TDI_SEND_PARTIAL);
+
+ Irp->CancelRoutine = (PDRIVER_CANCEL)NULL;
+ IoReleaseCancelSpinLock(cancelirql);
+
+ //
+ // Complete the send. Note that this may not actually call
+ // IoCompleteRequest for the Irp until sometime later, if the
+ // in-progress LLC resending going on below us needs to complete.
+ //
+
+ StCompleteSendIrp (
+ Irp,
+ STATUS_SUCCESS,
+ IRP_SEND_LENGTH(IrpSp));
+
+ if (EndOfRecord) {
+ break;
+ }
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ };
+
+ //
+ // Acquire the lock that we will return with.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ //
+ // We've finished processing the current send. Update our state.
+ //
+
+ Connection->SendState = CONNECTION_SENDSTATE_IDLE;
+
+ //
+ // If there is another send pending on the connection, then initialize
+ // it and start packetizing it.
+ //
+
+ if (!(IsListEmpty (&Connection->SendQueue))) {
+
+ InitializeSend (Connection);
+
+ //
+ // This code is similar to calling StartPacketizingConnection
+ // with the second parameter FALSE.
+ //
+
+ if ((!(Connection->Flags & CONNECTION_FLAGS_PACKETIZE)) &&
+ (!(Connection->Flags & CONNECTION_FLAGS_STOPPING))) {
+
+ Connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
+
+ StReferenceConnection ("Packetize", Connection);
+
+ ExInterlockedInsertTailList(
+ &Connection->Provider->PacketizeQueue,
+ &Connection->PacketizeLinkage,
+ &Connection->Provider->SpinLock);
+
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+} /* CompleteSend */
+
+
+VOID
+FailSend(
+ IN PTP_CONNECTION Connection,
+ IN NTSTATUS RequestStatus,
+ IN BOOLEAN StopConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called because something on the link caused this send to be
+ unable to complete. There are a number of possible reasons for this to have
+ happened, but all will fail with the common error STATUS_LINK_FAILED.
+ or NO_RECEIVE response where the number of bytes specified exactly
+ Here we retire all of the TdiSends on the connection's SendQueue up to
+ and including the current one, which is the one that failed.
+
+ Later - Actually, a send failing is cause for the entire circuit to wave
+ goodbye to this life. We now simply tear down the connection completly.
+ Any future sends on this connection will be blown away.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql, cancelirql;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+ PLIST_ENTRY p;
+ BOOLEAN EndOfRecord;
+ BOOLEAN GotCurrent = FALSE;
+
+
+ //
+ // Pick off IRP objects from the connection's SendQueue until
+ // we get to this one. If this one does NOT have an EOF mark set, we'll
+ // need to keep going until we hit one that does have EOF set. Note that
+ // this may cause us to continue failing sends that have not yet been
+ // queued. (We do all this because ST does not provide stream mode sends.)
+ //
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ StReferenceConnection ("Failing Send", Connection);
+
+ do {
+ if (IsListEmpty (&Connection->SendQueue)) {
+
+ //
+ // got an empty list, so we've run out of send requests to fail
+ // without running into an EOR. Set the connection flag that will
+ // cause all further sends to be failed up to an EOR and get out
+ // of here.
+ //
+
+ Connection->Flags |= CONNECTION_FLAGS_FAILING_TO_EOR;
+ break;
+ }
+ p = RemoveHeadList (&Connection->SendQueue);
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ if (Irp == Connection->sp.CurrentSendIrp) {
+ GotCurrent = TRUE;
+ }
+ EndOfRecord = !(IRP_SEND_FLAGS(IrpSp) & TDI_SEND_PARTIAL);
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ Irp->CancelRoutine = (PDRIVER_CANCEL)NULL;
+ IoReleaseCancelSpinLock(cancelirql);
+
+
+ //
+ // The following dereference will complete the I/O, provided removes
+ // the last reference on the request object. The I/O will complete
+ // with the status and information stored in the Irp. Therefore,
+ // we set those values here before the dereference.
+ //
+
+ StCompleteSendIrp (Irp, RequestStatus, 0);
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ } while (!EndOfRecord & !GotCurrent);
+
+ //
+ // We've finished processing the current send. Update our state.
+ //
+
+ Connection->SendState = CONNECTION_SENDSTATE_IDLE;
+ Connection->sp.CurrentSendIrp = NULL;
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+
+ if (StopConnection) {
+ StStopConnection (Connection, STATUS_LINK_FAILED);
+ }
+
+ StDereferenceConnection ("FailSend", Connection);
+
+} /* FailSend */
+
+
+VOID
+InitializeSend(
+ PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called whenever the next send on a connection should
+ be initialized; that is, all of the fields associated with the state
+ of the current send are set to refer to the first send on the SendQueue.
+
+ WARNING: This routine is executed with the Connection lock acquired
+ since it must be atomically executed with the caller's setup.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ if (Connection->SendQueue.Flink != &Connection->SendQueue) {
+ Connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
+ Connection->FirstSendIrp =
+ CONTAINING_RECORD (Connection->SendQueue.Flink, IRP, Tail.Overlay.ListEntry);
+ Connection->FirstSendMdl = Connection->FirstSendIrp->MdlAddress;
+ Connection->FirstSendByteOffset = 0;
+ Connection->sp.MessageBytesSent = 0;
+ Connection->sp.CurrentSendIrp = Connection->FirstSendIrp;
+ Connection->sp.CurrentSendMdl = Connection->FirstSendMdl;
+ Connection->sp.SendByteOffset = Connection->FirstSendByteOffset;
+ Connection->CurrentSendLength =
+ IRP_SEND_LENGTH(IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp));
+
+ }
+} /* InitializeSend */
+
+
+VOID
+StCancelSend(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a send.
+ The send is found on the connection's send queue; if it is the
+ current request it is cancelled and the connection is torn down,
+ otherwise it is silently cancelled.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PIO_STACK_LOCATION IrpSp;
+ PTP_CONNECTION Connection;
+ PIRP SendIrp;
+ PLIST_ENTRY p;
+ BOOLEAN Found;
+
+ UNREFERENCED_PARAMETER (DeviceObject);
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (IrpSp->MinorFunction == TDI_SEND));
+
+ Connection = IrpSp->FileObject->FsContext;
+
+ //
+ // Since this IRP is still in the cancellable state, we know
+ // that the connection is still around (although it may be in
+ // the process of being torn down).
+ //
+
+ //
+ // See if this is the IRP for the current send request.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ StReferenceConnection ("Cancelling Send", Connection);
+
+ p = Connection->SendQueue.Flink;
+ SendIrp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+
+ if (SendIrp == Irp) {
+
+ //
+ // yes, it is the first one on the send queue, so
+ // trash the send/connection.
+ //
+
+ p = RemoveHeadList (&Connection->SendQueue);
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+
+ //
+ // The following dereference will complete the I/O, provided removes
+ // the last reference on the request object. The I/O will complete
+ // with the status and information stored in the Irp. Therefore,
+ // we set those values here before the dereference.
+ //
+
+ StCompleteSendIrp (SendIrp, STATUS_CANCELLED, 0);
+
+ //
+ // Since we are cancelling the current send, blow away
+ // the connection.
+ //
+
+ StStopConnection (Connection, STATUS_CANCELLED);
+
+ } else {
+
+ //
+ // Scan through the list, looking for this IRP.
+ //
+
+ Found = FALSE;
+ p = p->Flink;
+ while (p != &Connection->SendQueue) {
+
+ SendIrp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ if (SendIrp == Irp) {
+
+ //
+ // Found it, remove it from the list here.
+ //
+
+ RemoveEntryList (p);
+
+ Found = TRUE;
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ //
+ // The following dereference will complete the I/O, provided removes
+ // the last reference on the request object. The I/O will complete
+ // with the status and information stored in the Irp. Therefore,
+ // we set those values here before the dereference.
+ //
+
+ StCompleteSendIrp (SendIrp, STATUS_CANCELLED, 0);
+ break;
+
+ }
+
+ p = p->Flink;
+
+ }
+
+ if (!Found) {
+
+ //
+ // We didn't find it!
+ //
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+ }
+
+ }
+
+ StDereferenceConnection ("Cancelling Send", Connection);
+
+}
+
+
+
+VOID
+StSendCompletionHandler(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to indicate that a connection-
+ oriented packet has been shipped and is no longer needed by the Physical
+ Provider.
+
+Arguments:
+
+ NdisContext - the value associated with the adapter binding at adapter
+ open time (which adapter we're talking on).
+
+ NdisPacket/RequestHandle - A pointer to the NDIS_PACKET that we sent.
+
+ NdisStatus - the completion status of the send.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PSEND_PACKET_TAG SendContext;
+ PTP_PACKET Packet;
+ KIRQL oldirql, cancelirql;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_CONNECTION Connection;
+ PLIST_ENTRY p;
+ PIO_STACK_LOCATION IrpSp;
+ PTP_REQUEST request;
+ TA_NETBIOS_ADDRESS TempAddress;
+ ULONG returnLength;
+ NTSTATUS status;
+ PTDI_CONNECTION_INFORMATION remoteInformation;
+
+ UNREFERENCED_PARAMETER(ProtocolBindingContext);
+
+ SendContext = (PSEND_PACKET_TAG)&NdisPacket->ProtocolReserved[0];
+ Packet = SendContext->Packet;
+
+ DeviceContext = Packet->Provider;
+
+ Packet->PacketSent = TRUE;
+
+ switch (SendContext->Type) {
+
+ case TYPE_I_FRAME:
+
+ //
+ // Dereference the IRP that this packet was sent for.
+ //
+
+ IrpSp = (PIO_STACK_LOCATION)(SendContext->Owner);
+
+ if (Packet->CompleteSend) {
+ CompleteSend(IRP_CONNECTION(IrpSp));
+ }
+ StDereferenceSendIrp("Destroy packet", IrpSp);
+ break;
+
+ case TYPE_D_FRAME:
+
+ //
+ // Finish tearing down the connection.
+ //
+
+ StDereferenceConnection("Disconnect completed", (PTP_CONNECTION)(SendContext->Owner));
+ break;
+
+ case TYPE_G_FRAME:
+
+ //
+ // Addresses get their own frames; let the address know it's ok to
+ // use the frame again, and exit to avoid normal packet completion.
+ //
+
+ StSendDatagramCompletion ((PTP_ADDRESS)(SendContext->Owner),
+ NdisPacket,
+ NdisStatus);
+ return;
+
+ case TYPE_C_FRAME:
+
+ //
+ // Complete the TdiConnect request; note that he better
+ // have accepted it quickly since we will immediately
+ // start sending data if required.
+ //
+
+ Connection = (PTP_CONNECTION)(SendContext->Owner);
+
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ p = RemoveHeadList (&Connection->InProgressRequest);
+
+ //
+ // Turn off the connection request timer if there is one, and set
+ // this connection's state to READY.
+ //
+
+ Connection->Flags |= CONNECTION_FLAGS_READY;
+
+ INCREMENT_COUNTER (Connection->Provider, OpenConnections);
+
+ //
+ // Record that the connect request has been successfully
+ // completed by TpCompleteRequest.
+ //
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ //
+ // Now complete the request and get out.
+ //
+
+ if (p == &Connection->InProgressRequest) {
+ Connection->IndicationInProgress = FALSE;
+ PANIC ("ProcessSessionConfirm: TdiConnect evaporated!\n");
+ IoReleaseCancelSpinLock (cancelirql);
+ break;
+ }
+
+ //
+ // We have a completed connection with a queued connect. Complete
+ // the connect.
+ //
+
+ request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL;
+ IoReleaseCancelSpinLock(cancelirql);
+
+ IrpSp = IoGetCurrentIrpStackLocation (request->IoRequestPacket);
+ remoteInformation =
+ ((PTDI_REQUEST_KERNEL)(&IrpSp->Parameters))->ReturnConnectionInformation;
+ if (remoteInformation != NULL) {
+ try {
+ if (remoteInformation->RemoteAddressLength != 0) {
+
+ //
+ // Build a temporary TA_NETBIOS_ADDRESS, then
+ // copy over as many bytes as fit.
+ //
+
+ TdiBuildNetbiosAddress(
+ Connection->CalledAddress.NetbiosName,
+ (BOOLEAN)(Connection->CalledAddress.NetbiosNameType ==
+ TDI_ADDRESS_NETBIOS_TYPE_GROUP),
+ &TempAddress);
+
+ if (remoteInformation->RemoteAddressLength >=
+ sizeof (TA_NETBIOS_ADDRESS)) {
+
+ returnLength = sizeof(TA_NETBIOS_ADDRESS);
+ remoteInformation->RemoteAddressLength = returnLength;
+
+ } else {
+
+ returnLength = remoteInformation->RemoteAddressLength;
+
+ }
+
+ RtlCopyMemory(
+ (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress,
+ &TempAddress,
+ returnLength);
+
+ } else {
+
+ returnLength = 0;
+ }
+
+ status = STATUS_SUCCESS;
+
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+
+ returnLength = 0;
+ status = GetExceptionCode ();
+
+ }
+
+ } else {
+
+ status = STATUS_SUCCESS;
+ returnLength = 0;
+
+ }
+
+ RtlCopyMemory( Connection->RemoteName, Connection->CalledAddress.NetbiosName, 16 );
+ Connection->Flags2 |= CONNECTION_FLAGS2_REMOTE_VALID;
+
+ //
+ // Reference the connection so it stays around after
+ // the request is completed.
+ //
+
+ StReferenceConnection("Connect completed", Connection);
+
+ StCompleteRequest (request, status, returnLength);
+
+ break;
+
+ }
+
+ StDestroyPacket(Packet);
+
+} /* StSendCompletionHandler */
+
+
+VOID
+StNdisSend(
+ IN PTP_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends an NDIS packet
+ This routine is used to ensure that receive sequence numbers on
+ packets are numbered correctly. It is called in place of NdisSend
+ and after assigning the receive sequence number it locks out other
+ sends until the NdisSend call has returned (not necessarily completed),
+ insuring that the packets with increasing receive sequence numbers
+ are queue in the right order by the MAC.
+
+ NOTE: This routine is called with the link spinlock held,
+ and it returns with it released.
+
+Arguments:
+
+ Packet - Pointer to a TP_PACKET object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+
+ NdisSend (
+ &NdisStatus,
+ ((PDEVICE_CONTEXT)(Packet->Provider))->NdisBindingHandle,
+ Packet->NdisPacket);
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+
+ StSendCompletionHandler(
+ Packet->Provider,
+ Packet->NdisPacket,
+ NdisStatus);
+ }
+
+} /* StNdisSend */
+
+
+
+NTSTATUS
+BuildBufferChainFromMdlChain (
+ IN NDIS_HANDLE BufferPoolHandle,
+ IN PMDL CurrentMdl,
+ IN ULONG ByteOffset,
+ IN ULONG DesiredLength,
+ OUT PNDIS_BUFFER *Destination,
+ OUT PMDL *NewCurrentMdl,
+ OUT ULONG *NewByteOffset,
+ OUT ULONG *TrueLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to build an NDIS_BUFFER chain from a source Mdl chain and
+ offset into it. We assume we don't know the length of the source Mdl chain,
+ and we must allocate the NDIS_BUFFERs for the destination chain, which
+ we do from the NDIS buffer pool.
+
+ The NDIS_BUFFERs that are returned are mapped and locked. (Actually, the pages in
+ them are in the same state as those in the source MDLs.)
+
+ If the system runs out of memory while we are building the destination
+ NDIS_BUFFER chain, we completely clean up the built chain and return with
+ NewCurrentMdl and NewByteOffset set to the current values of CurrentMdl
+ and ByteOffset. TrueLength is set to 0.
+
+Environment:
+
+ Kernel Mode, Source Mdls locked. It is recommended, although not required,
+ that the source Mdls be mapped and locked prior to calling this routine.
+
+Arguments:
+
+ BufferPoolHandle - The buffer pool to allocate buffers from.
+
+ CurrentMdl - Points to the start of the Mdl chain from which to draw the
+ packet.
+
+ ByteOffset - Offset within this MDL to start the packet at.
+
+ DesiredLength - The number of bytes to insert into the packet.
+
+ Destination - returned pointer to the NDIS_BUFFER chain describing the packet.
+
+ NewCurrentMdl - returned pointer to the Mdl that would be used for the next
+ byte of packet. NULL if the source Mdl chain was exhausted.
+
+ NewByteOffset - returned offset into the NewCurrentMdl for the next byte of
+ packet. NULL if the source Mdl chain was exhausted.
+
+ TrueLength - The actual length of the returned NDIS_BUFFER Chain. If less than
+ DesiredLength, the source Mdl chain was exhausted.
+
+Return Value:
+
+ STATUS_SUCCESS if the build of the returned NDIS_BUFFER chain succeeded (even if
+ shorter than the desired chain).
+
+ STATUS_INSUFFICIENT_RESOURCES if we ran out of NDIS_BUFFERs while building the
+ destination chain.
+
+--*/
+{
+ ULONG AvailableBytes;
+ PMDL OldMdl;
+ PNDIS_BUFFER NewNdisBuffer;
+ NDIS_STATUS NdisStatus;
+
+
+ AvailableBytes = MmGetMdlByteCount (CurrentMdl) - ByteOffset;
+ if (AvailableBytes > DesiredLength) {
+ AvailableBytes = DesiredLength;
+ }
+
+ OldMdl = CurrentMdl;
+ *NewCurrentMdl = OldMdl;
+ *NewByteOffset = ByteOffset + AvailableBytes;
+ *TrueLength = AvailableBytes;
+
+
+ //
+ // Build the first NDIS_BUFFER, which could conceivably be the only one...
+ //
+
+ NdisCopyBuffer(
+ &NdisStatus,
+ &NewNdisBuffer,
+ BufferPoolHandle,
+ OldMdl,
+ ByteOffset,
+ AvailableBytes);
+
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ *NewByteOffset = ByteOffset;
+ *TrueLength = 0;
+ *Destination = NULL;
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ *Destination = NewNdisBuffer;
+
+ //
+ // Was the first NDIS_BUFFER enough data, or are we out of Mdls?
+ //
+
+ if ((AvailableBytes == DesiredLength) || (OldMdl->Next == NULL)) {
+ if (*NewByteOffset >= MmGetMdlByteCount (OldMdl)) {
+ *NewCurrentMdl = OldMdl->Next;
+ *NewByteOffset = 0;
+ }
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Need more data, so follow the in Mdl chain to create a packet.
+ //
+
+ OldMdl = OldMdl->Next;
+ *NewCurrentMdl = OldMdl;
+
+ while (OldMdl != NULL) {
+ AvailableBytes = DesiredLength - *TrueLength;
+ if (AvailableBytes > MmGetMdlByteCount (OldMdl)) {
+ AvailableBytes = MmGetMdlByteCount (OldMdl);
+ }
+
+ NdisCopyBuffer(
+ &NdisStatus,
+ &(NDIS_BUFFER_LINKAGE(NewNdisBuffer)),
+ BufferPoolHandle,
+ OldMdl,
+ 0,
+ AvailableBytes);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // ran out of resources. put back what we've used in this call and
+ // return the error.
+ //
+
+ while (*Destination != NULL) {
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE(*Destination);
+ NdisFreeBuffer (*Destination);
+ *Destination = NewNdisBuffer;
+ }
+
+ *NewByteOffset = ByteOffset;
+ *TrueLength = 0;
+ *NewCurrentMdl = CurrentMdl;
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE(NewNdisBuffer);
+
+ *TrueLength += AvailableBytes;
+ *NewByteOffset = AvailableBytes;
+
+ if (*TrueLength == DesiredLength) {
+ if (*NewByteOffset == MmGetMdlByteCount (OldMdl)) {
+ *NewCurrentMdl = OldMdl->Next;
+ *NewByteOffset = 0;
+ }
+ return STATUS_SUCCESS;
+ }
+ OldMdl = OldMdl->Next;
+ *NewCurrentMdl = OldMdl;
+
+ } // while (mdl chain exists)
+
+ *NewCurrentMdl = NULL;
+ *NewByteOffset = 0;
+ return STATUS_SUCCESS;
+
+} // BuildBufferChainFromMdlChain
+
diff --git a/private/ntos/tdi/st/sources b/private/ntos/tdi/st/sources
new file mode 100644
index 000000000..f47518792
--- /dev/null
+++ b/private/ntos/tdi/st/sources
@@ -0,0 +1,62 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=st
+
+TARGETNAME=st
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\tdi.lib \
+ $(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..\..\inc;..\..\..\inc
+
+SOURCES=\
+ address.c \
+ connect.c \
+ connobj.c \
+ devctx.c \
+ event.c \
+ framesnd.c \
+ iframes.c \
+ ind.c \
+ info.c \
+ packet.c \
+ rcv.c \
+ rcveng.c \
+ request.c \
+ send.c \
+ sendeng.c \
+ st.rc \
+ stcnfg.c \
+ stdrvr.c \
+ stmac.c \
+ stndis.c \
+ uframes.c
+
+!IFNDEF 386_WARNING_LEVEL
+386_WARNING_LEVEL=/W3
+!ENDIF
diff --git a/private/ntos/tdi/st/st.h b/private/ntos/tdi/st/st.h
new file mode 100644
index 000000000..590ccac89
--- /dev/null
+++ b/private/ntos/tdi/st/st.h
@@ -0,0 +1,46 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ st.h
+
+Abstract:
+
+ Private include file for the NT Sample transport provider.
+
+Revision History:
+
+--*/
+
+#ifndef _ST_
+#define _ST_
+
+#include <ntddk.h>
+
+#include <windef.h> // these two are needed by info.c
+#include <nb30.h>
+
+#include <tdikrnl.h> // Transport Driver Interface.
+#include <ndis.h> // Network Driver Interface.
+
+#if DEVL
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+#include "stconst.h" // private constants.
+#include "stmac.h" // mac-specific definitions
+#include "sthdrs.h" // private protocol headers.
+#include "sttypes.h" // private types.
+#include "stcnfg.h" // configuration information.
+#include "stprocs.h" // private function prototypes.
+
+
+#define ACQUIRE_SPIN_LOCK(lock,irql) KeAcquireSpinLock(lock,irql)
+#define RELEASE_SPIN_LOCK(lock,irql) KeReleaseSpinLock(lock,irql)
+
+
+#endif // def _ST_
diff --git a/private/ntos/tdi/st/st.rc b/private/ntos/tdi/st/st.rc
new file mode 100644
index 000000000..591897aa9
--- /dev/null
+++ b/private/ntos/tdi/st/st.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "Sample TDI 3.0 Transport Driver"
+#define VER_INTERNALNAME_STR "st.sys"
+#define VER_ORIGINALFILENAME_STR "st.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/tdi/st/stcnfg.c b/private/ntos/tdi/st/stcnfg.c
new file mode 100644
index 000000000..40438eedb
--- /dev/null
+++ b/private/ntos/tdi/st/stcnfg.c
@@ -0,0 +1,1277 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ stcnfg.c
+
+Abstract:
+
+ This contains all routines necessary for the support of the dynamic
+ configuration of ST.
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+//
+// Local functions used to access the registry.
+//
+
+NTSTATUS
+StConfigureTransport (
+ IN PUNICODE_STRING RegistryPath,
+ IN PCONFIG_DATA * ConfigurationInfoPtr
+ );
+
+VOID
+StFreeConfigurationInfo (
+ IN PCONFIG_DATA ConfigurationInfo
+ );
+
+NTSTATUS
+StOpenParametersKey(
+ IN HANDLE StConfigHandle,
+ OUT PHANDLE ParametersHandle
+ );
+
+VOID
+StCloseParametersKey(
+ IN HANDLE ParametersHandle
+ );
+
+NTSTATUS
+StCountEntries(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+StAddBind(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+StAddExport(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+VOID
+StReadLinkageInformation(
+ IN PWSTR RegistryPathBuffer,
+ IN PCONFIG_DATA * ConfigurationInfo
+ );
+
+UINT
+StReadSizeInformation(
+ IN HANDLE ParametersHandle
+ );
+
+ULONG
+StReadSingleParameter(
+ IN HANDLE ParametersHandle,
+ IN PWCHAR ValueName,
+ IN ULONG DefaultValue
+ );
+
+VOID
+StWriteSingleParameter(
+ IN HANDLE ParametersHandle,
+ IN PWCHAR ValueName,
+ IN ULONG ValueData
+ );
+
+VOID
+StSaveConfigInRegistry(
+ IN HANDLE ParametersHandle,
+ IN PCONFIG_DATA ConfigurationInfo
+ );
+
+UINT
+StWstrLength(
+ IN PWSTR Wstr
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,StWstrLength)
+#pragma alloc_text(INIT,StConfigureTransport)
+#pragma alloc_text(INIT,StFreeConfigurationInfo)
+#pragma alloc_text(INIT,StOpenParametersKey)
+#pragma alloc_text(INIT,StCloseParametersKey)
+#pragma alloc_text(INIT,StCountEntries)
+#pragma alloc_text(INIT,StAddBind)
+#pragma alloc_text(INIT,StAddExport)
+#pragma alloc_text(INIT,StReadLinkageInformation)
+#pragma alloc_text(INIT,StReadSingleParameter)
+#pragma alloc_text(INIT,StWriteSingleParameter)
+#pragma alloc_text(INIT,StSaveConfigInRegistry)
+#endif
+
+
+UINT
+StWstrLength(
+ IN PWSTR Wstr
+ )
+{
+ UINT Length = 0;
+ while (*Wstr++) {
+ Length += sizeof(WCHAR);
+ }
+ return Length;
+}
+
+#define InsertAdapter(ConfigurationInfo, Subscript, Name) \
+{ \
+ PWSTR _S; \
+ PWSTR _N = (Name); \
+ UINT _L = StWstrLength(_N)+sizeof(WCHAR); \
+ _S = (PWSTR)ExAllocatePool(NonPagedPool, _L); \
+ if (_S != NULL) { \
+ RtlCopyMemory(_S, _N, _L); \
+ RtlInitUnicodeString (&(ConfigurationInfo)->Names[Subscript], _S); \
+ } \
+}
+
+#define InsertDevice(ConfigurationInfo, Subscript, Name) \
+{ \
+ PWSTR _S; \
+ PWSTR _N = (Name); \
+ UINT _L = StWstrLength(_N)+sizeof(WCHAR); \
+ _S = (PWSTR)ExAllocatePool(NonPagedPool, _L); \
+ if (_S != NULL) { \
+ RtlCopyMemory(_S, _N, _L); \
+ RtlInitUnicodeString (&(ConfigurationInfo)->Names[(ConfigurationInfo)->DevicesOffset+Subscript], _S); \
+ } \
+}
+
+
+#define RemoveAdapter(ConfigurationInfo, Subscript) \
+ ExFreePool ((ConfigurationInfo)->Names[Subscript].Buffer)
+
+#define RemoveDevice(ConfigurationInfo, Subscript) \
+ ExFreePool ((ConfigurationInfo)->Names[(ConfigurationInfo)->DevicesOffset+Subscript].Buffer)
+
+
+
+//
+// These strings are used in various places by the registry.
+//
+
+#define DECLARE_STRING(_str_) STATIC WCHAR Str ## _str_[] = L#_str_
+
+DECLARE_STRING(Large);
+DECLARE_STRING(Medium);
+DECLARE_STRING(Small);
+
+DECLARE_STRING(InitRequests);
+DECLARE_STRING(InitConnections);
+DECLARE_STRING(InitAddressFiles);
+DECLARE_STRING(InitAddresses);
+
+DECLARE_STRING(MaxRequests);
+DECLARE_STRING(MaxConnections);
+DECLARE_STRING(MaxAddressFiles);
+DECLARE_STRING(MaxAddresses);
+
+DECLARE_STRING(InitPackets);
+DECLARE_STRING(InitReceivePackets);
+DECLARE_STRING(InitReceiveBuffers);
+
+DECLARE_STRING(SendPacketPoolSize);
+DECLARE_STRING(ReceivePacketPoolSize);
+DECLARE_STRING(MaxMemoryUsage);
+
+
+#define READ_HIDDEN_CONFIG(_Field) \
+{ \
+ ConfigurationInfo->_Field = \
+ StReadSingleParameter( \
+ ParametersHandle, \
+ Str ## _Field, \
+ ConfigurationInfo->_Field); \
+}
+
+#define WRITE_HIDDEN_CONFIG(_Field) \
+{ \
+ StWriteSingleParameter( \
+ ParametersHandle, \
+ Str ## _Field, \
+ ConfigurationInfo->_Field); \
+}
+
+
+
+NTSTATUS
+StConfigureTransport (
+ IN PUNICODE_STRING RegistryPath,
+ IN PCONFIG_DATA * ConfigurationInfoPtr
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by ST to get information from the configuration
+ management routines. We read the registry, starting at RegistryPath,
+ to get the parameters. If they don't exist, we use the defaults
+ set in nbfcnfg.h file.
+
+Arguments:
+
+ RegistryPath - The name of ST's node in the registry.
+
+ ConfigurationInfoPtr - A pointer to the configuration information structure.
+
+Return Value:
+
+ Status - STATUS_SUCCESS if everything OK, STATUS_INSUFFICIENT_RESOURCES
+ otherwise.
+
+--*/
+{
+
+ NTSTATUS OpenStatus;
+ HANDLE ParametersHandle;
+ UINT StSize;
+ HANDLE StConfigHandle;
+ NTSTATUS Status;
+ ULONG Disposition;
+ PWSTR RegistryPathBuffer;
+ OBJECT_ATTRIBUTES TmpObjectAttributes;
+ PCONFIG_DATA ConfigurationInfo;
+
+
+ //
+ // Open the registry.
+ //
+
+ InitializeObjectAttributes(
+ &TmpObjectAttributes,
+ RegistryPath, // name
+ OBJ_CASE_INSENSITIVE, // attributes
+ NULL, // root
+ NULL // security descriptor
+ );
+
+ Status = ZwCreateKey(
+ &StConfigHandle,
+ KEY_WRITE,
+ &TmpObjectAttributes,
+ 0, // title index
+ NULL, // class
+ 0, // create options
+ &Disposition); // disposition
+
+ if (!NT_SUCCESS(Status)) {
+ StPrint1("ST: Could not open/create ST key: %lx\n", Status);
+ return Status;
+ }
+
+
+ OpenStatus = StOpenParametersKey (StConfigHandle, &ParametersHandle);
+
+ if (OpenStatus != STATUS_SUCCESS) {
+ return OpenStatus;
+ }
+
+ //
+ // Read in the NDIS binding information (if none is present
+ // the array will be filled with all known drivers).
+ //
+ // StReadLinkageInformation expects a null-terminated path,
+ // so we have to create one from the UNICODE_STRING.
+ //
+
+ RegistryPathBuffer = (PWSTR)ExAllocatePool(
+ NonPagedPool,
+ RegistryPath->Length + sizeof(WCHAR));
+ if (RegistryPathBuffer == NULL) {
+ StCloseParametersKey (ParametersHandle);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ RtlCopyMemory (RegistryPathBuffer, RegistryPath->Buffer, RegistryPath->Length);
+ *(PWCHAR)(((PUCHAR)RegistryPathBuffer)+RegistryPath->Length) = (WCHAR)'\0';
+
+ StReadLinkageInformation (RegistryPathBuffer, ConfigurationInfoPtr);
+
+ if (*ConfigurationInfoPtr == NULL) {
+ ExFreePool (RegistryPathBuffer);
+ StCloseParametersKey (ParametersHandle);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ ConfigurationInfo = *ConfigurationInfoPtr;
+
+
+ //
+ // Read the size parameter; this returns 0 if none is
+ // present, or 1 (Small), 2 (Medium) and 3 (Large).
+ //
+
+ StSize = StReadSizeInformation (ParametersHandle);
+
+ switch (StSize) {
+
+ case 0:
+ case 1:
+
+ //
+ // Default is Small.
+ //
+
+ //
+ // These are the initial value used; the comment after
+ // each one shows the expected maximum (if every resource
+ // is at the expected maximum, ST should be very close
+ // to being out of memory).
+ //
+ // For now the "Max" values default to 0 (no limit).
+ //
+
+ ConfigurationInfo->InitRequests = 5; // 30
+ ConfigurationInfo->InitConnections = 1; // 10
+ ConfigurationInfo->InitAddressFiles = 0; // 10
+ ConfigurationInfo->InitAddresses = 0; // 10
+
+ //
+ // These are the initial values; remember that the
+ // resources above also allocate some of these each
+ // time they are allocated (shown in the comment).
+ //
+
+ ConfigurationInfo->InitPackets = 30; // + link + conn (40)
+ ConfigurationInfo->InitReceivePackets = 10; // + link + addr (30)
+ ConfigurationInfo->InitReceiveBuffers = 5; // + addr (15)
+
+ //
+ // Set the size of the packet pools and the total
+ // allocateable by ST.
+ //
+
+ ConfigurationInfo->SendPacketPoolSize = 100;
+ ConfigurationInfo->ReceivePacketPoolSize = 30;
+ ConfigurationInfo->MaxMemoryUsage = 100000;
+
+ break;
+
+ case 2:
+
+ //
+ // Medium ST.
+ //
+
+ //
+ // These are the initial value used; the comment after
+ // each one shows the expected maximum (if every resource
+ // is at the expected maximum, ST should be very close
+ // to being out of memory).
+ //
+ // For now the "Max" values default to 0 (no limit).
+ //
+
+ ConfigurationInfo->InitRequests = 10; // 100
+ ConfigurationInfo->InitConnections = 2; // 64
+ ConfigurationInfo->InitAddressFiles = 1; // 20
+ ConfigurationInfo->InitAddresses = 1; // 20
+
+ //
+ // These are the initial values; remember that the
+ // resources above also allocate some of these each
+ // time they are allocated (shown in the comment).
+ //
+
+ ConfigurationInfo->InitPackets = 50; // + link + conn (150)
+ ConfigurationInfo->InitReceivePackets = 15; // + link + addr (100)
+ ConfigurationInfo->InitReceiveBuffers = 10; // + addr (30)
+
+ //
+ // Set the size of the packet pools and the total
+ // allocateable by ST.
+ //
+
+ ConfigurationInfo->SendPacketPoolSize = 250;
+ ConfigurationInfo->ReceivePacketPoolSize = 100;
+ ConfigurationInfo->MaxMemoryUsage = 250000;
+
+ break;
+
+ case 3:
+
+ //
+ // Big ST.
+ //
+
+ //
+ // These are the initial value used.
+ //
+ // For now the "Max" values default to 0 (no limit).
+ //
+
+ ConfigurationInfo->InitRequests = 15;
+ ConfigurationInfo->InitConnections = 3;
+ ConfigurationInfo->InitAddressFiles = 2;
+ ConfigurationInfo->InitAddresses = 2;
+
+ //
+ // These are the initial values; remember that the
+ // resources above also allocate some of these each
+ // time they are allocated (shown in the comment).
+ //
+
+ ConfigurationInfo->InitPackets = 75; // + link + conn
+ ConfigurationInfo->InitReceivePackets = 25; // + link + addr
+ ConfigurationInfo->InitReceiveBuffers = 20; // + addr
+
+ //
+ // Set the size of the packet pools and the total
+ // allocateable by ST.
+ //
+
+ ConfigurationInfo->SendPacketPoolSize = 500;
+ ConfigurationInfo->ReceivePacketPoolSize = 200;
+ ConfigurationInfo->MaxMemoryUsage = 0; // no limit
+
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+
+ //
+ // Now read the optional "hidden" parameters; if these do
+ // not exist then the current values are used. Note that
+ // the current values will be 0 unless they have been
+ // explicitly initialized above.
+ //
+ // NOTE: These macros expect "ConfigurationInfo" and
+ // "ParametersHandle" to exist when they are expanded.
+ //
+
+ READ_HIDDEN_CONFIG (InitRequests);
+ READ_HIDDEN_CONFIG (InitConnections);
+ READ_HIDDEN_CONFIG (InitAddressFiles);
+ READ_HIDDEN_CONFIG (InitAddresses);
+
+ READ_HIDDEN_CONFIG (MaxRequests);
+ READ_HIDDEN_CONFIG (MaxConnections);
+ READ_HIDDEN_CONFIG (MaxAddressFiles);
+ READ_HIDDEN_CONFIG (MaxAddresses);
+
+ READ_HIDDEN_CONFIG (InitPackets);
+ READ_HIDDEN_CONFIG (InitReceivePackets);
+ READ_HIDDEN_CONFIG (InitReceiveBuffers);
+
+ READ_HIDDEN_CONFIG (SendPacketPoolSize);
+ READ_HIDDEN_CONFIG (ReceivePacketPoolSize);
+ READ_HIDDEN_CONFIG (MaxMemoryUsage);
+
+
+ //
+ // Now that we are completely configured, save the information
+ // in the registry.
+ //
+
+ StSaveConfigInRegistry (ParametersHandle, ConfigurationInfo);
+
+ ExFreePool (RegistryPathBuffer);
+ StCloseParametersKey (ParametersHandle);
+ ZwClose (StConfigHandle);
+
+ return STATUS_SUCCESS;
+
+} /* StConfigureTransport */
+
+
+VOID
+StFreeConfigurationInfo (
+ IN PCONFIG_DATA ConfigurationInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by ST to get free any storage that was allocated
+ by StConfigureTransport in producing the specified CONFIG_DATA structure.
+
+Arguments:
+
+ ConfigurationInfo - A pointer to the configuration information structure.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UINT i;
+
+ for (i=0; i<ConfigurationInfo->NumAdapters; i++) {
+ RemoveAdapter (ConfigurationInfo, i);
+ RemoveDevice (ConfigurationInfo, i);
+ }
+ ExFreePool (ConfigurationInfo);
+
+} /* StFreeConfigurationInfo */
+
+
+NTSTATUS
+StOpenParametersKey(
+ IN HANDLE StConfigHandle,
+ OUT PHANDLE ParametersHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by ST to open the ST "Parameters" key.
+
+Arguments:
+
+ ParametersHandle - Returns the handle used to read parameters.
+
+Return Value:
+
+ The status of the request.
+
+--*/
+{
+
+ NTSTATUS Status;
+ HANDLE ParamHandle;
+ PWSTR ParametersString = L"Parameters";
+ UNICODE_STRING ParametersKeyName;
+ OBJECT_ATTRIBUTES TmpObjectAttributes;
+
+ //
+ // Open the ST parameters key.
+ //
+
+ RtlInitUnicodeString (&ParametersKeyName, ParametersString);
+
+ InitializeObjectAttributes(
+ &TmpObjectAttributes,
+ &ParametersKeyName, // name
+ OBJ_CASE_INSENSITIVE, // attributes
+ StConfigHandle, // root
+ NULL // security descriptor
+ );
+
+
+ Status = ZwOpenKey(
+ &ParamHandle,
+ KEY_READ,
+ &TmpObjectAttributes);
+
+ if (!NT_SUCCESS(Status)) {
+
+ StPrint1("Could not open parameters key: %lx\n", Status);
+ return Status;
+
+ }
+
+ *ParametersHandle = ParamHandle;
+
+
+ //
+ // All keys successfully opened or created.
+ //
+
+ return STATUS_SUCCESS;
+
+} /* StOpenParametersKey */
+
+VOID
+StCloseParametersKey(
+ IN HANDLE ParametersHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by ST to close the "Parameters" key.
+ It closes the handles passed in and does any other work needed.
+
+Arguments:
+
+ ParametersHandle - The handle used to read other parameters.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ZwClose (ParametersHandle);
+
+} /* StCloseParametersKey */
+
+
+NTSTATUS
+StCountEntries(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called with the "Bind" and "Export" multi-strings.
+ It counts the number of name entries required in the
+ CONFIGURATION_DATA structure and then allocates it.
+
+Arguments:
+
+ ValueName - The name of the value ("Bind" or "Export" -- ignored).
+
+ ValueType - The type of the value (REG_MULTI_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to a pointer to the ConfigurationInfo structure.
+ When the "Export" callback is made this is filled in
+ with the allocate structure.
+
+ EntryContext - A pointer to a counter holding the total number
+ of name entries required.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ ULONG StringCount;
+ PWCHAR ValuePointer = (PWCHAR)ValueData;
+ PCONFIG_DATA * ConfigurationInfo = (PCONFIG_DATA *)Context;
+ PULONG TotalCount = ((PULONG)EntryContext);
+ ULONG OldTotalCount = *TotalCount;
+
+ ASSERT (ValueType == REG_MULTI_SZ);
+
+ //
+ // Count the number of strings in the multi-string; first
+ // check that it is NULL-terminated to make the rest
+ // easier.
+ //
+
+ if ((ValueLength < 2) ||
+ (ValuePointer[(ValueLength/2)-1] != (WCHAR)'\0')) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ StringCount = 0;
+ while (*ValuePointer != (WCHAR)'\0') {
+ while (*ValuePointer != (WCHAR)'\0') {
+ ++ValuePointer;
+ }
+ ++StringCount;
+ ++ValuePointer;
+ if ((ULONG)((PUCHAR)ValuePointer - (PUCHAR)ValueData) >= ValueLength) {
+ break;
+ }
+ }
+
+ (*TotalCount) += StringCount;
+
+ if (*ValueName == (WCHAR)'E') {
+
+ //
+ // This is "Export", allocate the config data structure.
+ //
+
+ *ConfigurationInfo = ExAllocatePool(
+ NonPagedPool,
+ sizeof (CONFIG_DATA) +
+ ((*TotalCount-1) * sizeof(NDIS_STRING)));
+
+ if (*ConfigurationInfo == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(
+ *ConfigurationInfo,
+ sizeof(CONFIG_DATA) + ((*TotalCount-1) * sizeof(NDIS_STRING)));
+
+ (*ConfigurationInfo)->DevicesOffset = OldTotalCount;
+
+ }
+
+ return STATUS_SUCCESS;
+
+} /* StCountEntries */
+
+
+NTSTATUS
+StAddBind(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Bind" multi-string and
+ saves the information in a ConfigurationInfo structure.
+
+Arguments:
+
+ ValueName - The name of the value ("Bind" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to the ConfigurationInfo structure.
+
+ EntryContext - A pointer to a count of binds that is incremented.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG_DATA ConfigurationInfo = *(PCONFIG_DATA *)Context;
+ PULONG CurBindNum = ((PULONG)EntryContext);
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+
+ InsertAdapter(
+ ConfigurationInfo,
+ *CurBindNum,
+ (PWSTR)(ValueData));
+
+ ++(*CurBindNum);
+
+ return STATUS_SUCCESS;
+
+} /* StAddBind */
+
+
+NTSTATUS
+StAddExport(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Export" multi-string and
+ saves the information in a ConfigurationInfo structure.
+
+Arguments:
+
+ ValueName - The name of the value ("Export" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to the ConfigurationInfo structure.
+
+ EntryContext - A pointer to a count of exports that is incremented.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG_DATA ConfigurationInfo = *(PCONFIG_DATA *)Context;
+ PULONG CurExportNum = ((PULONG)EntryContext);
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+
+ InsertDevice(
+ ConfigurationInfo,
+ *CurExportNum,
+ (PWSTR)(ValueData));
+
+ ++(*CurExportNum);
+
+ return STATUS_SUCCESS;
+
+} /* StAddExport */
+
+
+VOID
+StReadLinkageInformation(
+ IN PWSTR RegistryPathBuffer,
+ IN PCONFIG_DATA * ConfigurationInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by ST to read its linkage information
+ from the registry. If there is none present, then ConfigData
+ is filled with a list of all the adapters that are known
+ to ST.
+
+Arguments:
+
+ RegistryPathBuffer - The null-terminated root of the ST registry tree.
+
+ ConfigurationInfo - Returns ST's current configuration.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UINT ConfigBindings;
+ UINT NameCount = 0;
+ NTSTATUS Status;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[6];
+ PWSTR Subkey = L"Linkage";
+ PWSTR Bind = L"Bind";
+ PWSTR Export = L"Export";
+ ULONG BindCount, ExportCount;
+ UINT i;
+
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Linkage key below ST
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Subkey;
+
+ //
+ // 2) Call StCountEntries for the "Bind" multi-string
+ //
+
+ QueryTable[1].QueryRoutine = StCountEntries;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ QueryTable[1].Name = Bind;
+ QueryTable[1].EntryContext = (PVOID)&NameCount;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Call StCountEntries for the "Export" multi-string
+ //
+
+ QueryTable[2].QueryRoutine = StCountEntries;
+ QueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ QueryTable[2].Name = Export;
+ QueryTable[2].EntryContext = (PVOID)&NameCount;
+ QueryTable[2].DefaultType = REG_NONE;
+
+ //
+ // 4) Call StAddBind for each string in "Bind"
+ //
+
+ QueryTable[3].QueryRoutine = StAddBind;
+ QueryTable[3].Flags = 0;
+ QueryTable[3].Name = Bind;
+ QueryTable[3].EntryContext = (PVOID)&BindCount;
+ QueryTable[3].DefaultType = REG_NONE;
+
+ //
+ // 5) Call StAddExport for each string in "Export"
+ //
+
+ QueryTable[4].QueryRoutine = StAddExport;
+ QueryTable[4].Flags = 0;
+ QueryTable[4].Name = Export;
+ QueryTable[4].EntryContext = (PVOID)&ExportCount;
+ QueryTable[4].DefaultType = REG_NONE;
+
+ //
+ // 6) Stop
+ //
+
+ QueryTable[5].QueryRoutine = NULL;
+ QueryTable[5].Flags = 0;
+ QueryTable[5].Name = NULL;
+
+
+ BindCount = 0;
+ ExportCount = 0;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ RegistryPathBuffer,
+ QueryTable,
+ (PVOID)ConfigurationInfo,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+ return;
+ }
+
+ //
+ // Make sure that BindCount and ExportCount match, if not
+ // remove the extras.
+ //
+
+ if (BindCount < ExportCount) {
+
+ for (i=BindCount; i<ExportCount; i++) {
+ RemoveDevice (*ConfigurationInfo, i);
+ }
+ ConfigBindings = BindCount;
+
+ } else if (ExportCount < BindCount) {
+
+ for (i=ExportCount; i<BindCount; i++) {
+ RemoveAdapter (*ConfigurationInfo, i);
+ }
+ ConfigBindings = ExportCount;
+
+ } else {
+
+ ConfigBindings = BindCount; // which is equal to ExportCount
+
+ }
+
+ (*ConfigurationInfo)->NumAdapters = ConfigBindings;
+
+} /* StReadLinkageInformation */
+
+
+UINT
+StReadSizeInformation(
+ IN HANDLE ParametersHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by ST to read the Size information
+ from the registry.
+
+Arguments:
+
+ RegistryHandle - A pointer to the open registry.
+
+Return Value:
+
+ 0 - no Size specified
+ 1 - Small
+ 2 - Medium
+ 3 - Big / Large
+
+--*/
+
+{
+
+ UINT SizeToReturn;
+// STRING KeywordName;
+// PCONFIG_KEYWORD Keyword;
+
+ ULONG InformationBuffer[16]; // declare ULONG to get it aligned
+ PKEY_VALUE_FULL_INFORMATION Information =
+ (PKEY_VALUE_FULL_INFORMATION)InformationBuffer;
+ ULONG InformationLength;
+ WCHAR SizeString[] = L"Size";
+ UNICODE_STRING SizeValueName;
+ NTSTATUS Status;
+ PUCHAR InformationData;
+ ULONG InformationLong;
+
+
+ //
+ // Read the size parameter out of the registry.
+ //
+
+ RtlInitUnicodeString (&SizeValueName, SizeString);
+
+ Status = ZwQueryValueKey(
+ ParametersHandle,
+ &SizeValueName,
+ KeyValueFullInformation,
+ (PVOID)Information,
+ sizeof (InformationBuffer),
+ &InformationLength);
+
+ //
+ // Compare to the expected values.
+ //
+
+ if (Status == STATUS_SUCCESS) {
+
+ InformationData = ((PUCHAR)Information) + Information->DataOffset;
+ InformationLong = *((PULONG)InformationData);
+
+ if ((Information->DataLength == sizeof(ULONG)) &&
+ (InformationLong >= 1 && InformationLong <= 3)) {
+
+ SizeToReturn = InformationLong;
+
+ } else {
+
+ if ((Information->DataLength >= 10) &&
+ (RtlEqualMemory (StrLarge, InformationData, 10))) {
+
+ SizeToReturn = 3;
+
+ } else if ((Information->DataLength >= 12) &&
+ (RtlEqualMemory (StrMedium, InformationData, 12))) {
+
+ SizeToReturn = 2;
+
+ } else if ((Information->DataLength >= 10) &&
+ (RtlEqualMemory (StrSmall, InformationData, 10))) {
+
+ SizeToReturn = 1;
+
+ } else {
+
+ SizeToReturn = 0;
+
+ }
+
+ }
+
+ } else {
+
+ SizeToReturn = 0;
+
+ }
+
+ return SizeToReturn;
+
+} /* StReadSizeInformation */
+
+
+ULONG
+StReadSingleParameter(
+ IN HANDLE ParametersHandle,
+ IN PWCHAR ValueName,
+ IN ULONG DefaultValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by ST to read a single parameter
+ from the registry. If the parameter is found it is stored
+ in Data.
+
+Arguments:
+
+ ParametersHandle - A pointer to the open registry.
+
+ ValueName - The name of the value to search for.
+
+ DefaultValue - The default value.
+
+Return Value:
+
+ The value to use; will be the default if the value is not
+ found or is not in the correct range.
+
+--*/
+
+{
+ ULONG InformationBuffer[16]; // declare ULONG to get it aligned
+ PKEY_VALUE_FULL_INFORMATION Information =
+ (PKEY_VALUE_FULL_INFORMATION)InformationBuffer;
+ UNICODE_STRING ValueKeyName;
+ ULONG InformationLength;
+ ULONG ReturnValue;
+ NTSTATUS Status;
+
+ RtlInitUnicodeString (&ValueKeyName, ValueName);
+
+ Status = ZwQueryValueKey(
+ ParametersHandle,
+ &ValueKeyName,
+ KeyValueFullInformation,
+ (PVOID)Information,
+ sizeof (InformationBuffer),
+ &InformationLength);
+
+ if ((Status == STATUS_SUCCESS) && (Information->DataLength == sizeof(ULONG))) {
+
+ RtlCopyMemory(
+ (PVOID)&ReturnValue,
+ ((PUCHAR)Information) + Information->DataOffset,
+ sizeof(ULONG));
+
+ if (ReturnValue < 0) {
+
+ ReturnValue = DefaultValue;
+
+ }
+
+ } else {
+
+ ReturnValue = DefaultValue;
+
+ }
+
+ return ReturnValue;
+
+} /* StReadSingleParameter */
+
+
+VOID
+StWriteSingleParameter(
+ IN HANDLE ParametersHandle,
+ IN PWCHAR ValueName,
+ IN ULONG ValueData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by ST to write a single parameter
+ from the registry.
+
+Arguments:
+
+ ParametersHandle - A pointer to the open registry.
+
+ ValueName - The name of the value to store.
+
+ ValueData - The data to store at the value.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UNICODE_STRING ValueKeyName;
+ NTSTATUS Status;
+ ULONG TmpValueData = ValueData;
+
+ RtlInitUnicodeString (&ValueKeyName, ValueName);
+
+ Status = ZwSetValueKey(
+ ParametersHandle,
+ &ValueKeyName,
+ 0,
+ REG_DWORD,
+ (PVOID)&TmpValueData,
+ sizeof(ULONG));
+
+ if (!NT_SUCCESS(Status)) {
+ StPrint1("ST: Could not write dword key: %lx\n", Status);
+ }
+
+} /* StWriteSingleParameter */
+
+
+VOID
+StSaveConfigInRegistry(
+ IN HANDLE ParametersHandle,
+ IN PCONFIG_DATA ConfigurationInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by ST to save its configuraition
+ information in the registry. It saves the information if
+ the registry structure did not exist before this boot.
+
+Arguments:
+
+ ParametersHandle - The handle used to read other parameters.
+
+ ConfigurationInfo - Describes ST's current configuration.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Save the "hidden" parameters, these may not exist in
+ // the registry.
+ //
+ // NOTE: These macros expect "ConfigurationInfo" and
+ // "ParametersHandle" to exist when they are expanded.
+ //
+
+ //
+ // Don't write the parameters that are set
+ // based on Size, since otherwise these will overwrite
+ // those values since hidden parameters are set up
+ // after the Size-based configuration is done.
+ //
+
+ WRITE_HIDDEN_CONFIG (MaxRequests);
+ WRITE_HIDDEN_CONFIG (MaxConnections);
+ WRITE_HIDDEN_CONFIG (MaxAddressFiles);
+ WRITE_HIDDEN_CONFIG (MaxAddresses);
+
+} /* StSaveConfigInRegistry */
+
diff --git a/private/ntos/tdi/st/stcnfg.h b/private/ntos/tdi/st/stcnfg.h
new file mode 100644
index 000000000..d09098a6c
--- /dev/null
+++ b/private/ntos/tdi/st/stcnfg.h
@@ -0,0 +1,57 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ stcnfg.h
+
+Abstract:
+
+ Private include file for the NT Sample transport. This
+ file defines all constants and structures necessary for support of
+ the dynamic configuration of ST.
+
+Revision History:
+
+--*/
+
+#ifndef _STCONFIG_
+#define _STCONFIG_
+
+//
+// configuration structure.
+//
+
+typedef struct {
+
+ ULONG InitRequests;
+ ULONG InitConnections;
+ ULONG InitAddressFiles;
+ ULONG InitAddresses;
+ ULONG MaxRequests;
+ ULONG MaxConnections;
+ ULONG MaxAddressFiles;
+ ULONG MaxAddresses;
+ ULONG InitPackets;
+ ULONG InitReceivePackets;
+ ULONG InitReceiveBuffers;
+ ULONG SendPacketPoolSize;
+ ULONG ReceivePacketPoolSize;
+ ULONG MaxMemoryUsage;
+
+ //
+ // Names contains NumAdapters pairs of NDIS adapter names (which
+ // nbf binds to) and device names (which nbf exports). The nth
+ // adapter name is in location n and the device name is in
+ // DevicesOffset+n (DevicesOffset may be different from NumAdapters
+ // if the registry Bind and Export strings are different sizes).
+ //
+
+ ULONG NumAdapters;
+ ULONG DevicesOffset;
+ NDIS_STRING Names[1];
+
+} CONFIG_DATA, *PCONFIG_DATA;
+
+#endif
diff --git a/private/ntos/tdi/st/stconst.h b/private/ntos/tdi/st/stconst.h
new file mode 100644
index 000000000..45837dc71
--- /dev/null
+++ b/private/ntos/tdi/st/stconst.h
@@ -0,0 +1,127 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ stconst.h
+
+Abstract:
+
+ This header file defines manifest constants for the NT Sample transport
+ provider. It is included by st.h.
+
+Revision History:
+
+--*/
+
+#ifndef _STCONST_
+#define _STCONST_
+
+
+//
+// some convenient constants used for timing. All values are in clock ticks.
+//
+
+#define MICROSECONDS 10
+#define MILLISECONDS 10000 // MICROSECONDS*1000
+#define SECONDS 10000000 // MILLISECONDS*1000
+
+
+//
+// MAJOR PROTOCOL IDENTIFIERS THAT CHARACTERIZE THIS DRIVER.
+//
+
+#define ST_DEVICE_NAME "\\Device\\St" // name of our driver.
+#define ST_DEVICE_NAME_LENGTH 10
+#define MAX_SOURCE_ROUTE_LENGTH 32 // max. bytes of SR. info.
+#define MAX_NETWORK_NAME_LENGTH 128 // # bytes in netname in TP_ADDRESS.
+#define MAX_USER_PACKET_DATA 1500 // max. user bytes per DFM/DOL.
+
+#define ST_FILE_TYPE_CONTROL (ULONG)0x4701 // file is type control
+
+
+//
+// MAJOR CONFIGURATION PARAMETERS THAT WILL BE MOVED TO THE INIT-LARGE_INTEGER
+// CONFIGURATION MANAGER.
+//
+
+#define MAX_REQUESTS 30
+#define MAX_UI_FRAMES 25
+#define MAX_SEND_PACKETS 40
+#define MAX_RECEIVE_PACKETS 30
+#define MAX_RECEIVE_BUFFERS 15
+#define MAX_LINKS 10
+#define MAX_CONNECTIONS 10
+#define MAX_ADDRESSFILES 10
+#define MAX_ADDRESSES 10
+
+#define MIN_UI_FRAMES 5 // + one per address + one per connection
+#define MIN_SEND_PACKETS 20 // + one per link + one per connection
+#define MIN_RECEIVE_PACKETS 10 // + one per link + one per address
+#define MIN_RECEIVE_BUFFERS 5 // + one per address
+
+#define SEND_PACKET_RESERVED_LENGTH (sizeof (SEND_PACKET_TAG))
+#define RECEIVE_PACKET_RESERVED_LENGTH (sizeof (RECEIVE_PACKET_TAG))
+
+
+#define ETHERNET_HEADER_SIZE 14 // BUGBUG: used for current NDIS compliance
+#define ETHERNET_PACKET_SIZE 1514
+
+
+//
+// NETBIOS PROTOCOL CONSTANTS.
+//
+
+//
+// TDI defined timeouts
+//
+
+#define TDI_TIMEOUT_SEND 60L // sends go 120 seconds
+#define TDI_TIMEOUT_RECEIVE 0L // receives
+#define TDI_TIMEOUT_CONNECT 60L
+#define TDI_TIMEOUT_LISTEN 0L // listens default to never.
+#define TDI_TIMEOUT_DISCONNECT 60L // should be 30
+#define TDI_TIMEOUT_NAME_REGISTRATION 60L
+
+
+
+//
+// GENERAL CAPABILITIES STATEMENTS THAT CANNOT CHANGE.
+//
+
+#define ST_MAX_TSDU_SIZE 65535 // maximum TSDU size supported by NetBIOS.
+#define ST_MAX_DATAGRAM_SIZE 512 // maximum Datagram size supported by NetBIOS.
+#define ST_MAX_CONNECTION_USER_DATA 0 // no user data supported on connect.
+#define ST_SERVICE_FLAGS ( \
+ TDI_SERVICE_CONNECTION_MODE | \
+ TDI_SERVICE_CONNECTIONLESS_MODE | \
+ TDI_SERVICE_ERROR_FREE_DELIVERY | \
+ TDI_SERVICE_BROADCAST_SUPPORTED | \
+ TDI_SERVICE_MULTICAST_SUPPORTED | \
+ TDI_SERVICE_DELAYED_ACCEPTANCE )
+
+#define ST_MIN_LOOKAHEAD_DATA 256 // minimum guaranteed lookahead data.
+#define ST_MAX_LOOKAHEAD_DATA 256 // maximum guaranteed lookahead data.
+
+#define ST_MAX_LOOPBACK_LOOKAHEAD 192 // how much is copied over for loopback
+
+//
+// Number of TDI resources that we report.
+//
+
+#define ST_TDI_RESOURCES 7
+
+
+//
+// More debugging stuff
+//
+
+#define ST_REQUEST_SIGNATURE ((CSHORT)0x5501)
+#define ST_CONNECTION_SIGNATURE ((CSHORT)0x5502)
+#define ST_ADDRESSFILE_SIGNATURE ((CSHORT)0x5503)
+#define ST_ADDRESS_SIGNATURE ((CSHORT)0x5504)
+#define ST_DEVICE_CONTEXT_SIGNATURE ((CSHORT)0x5505)
+#define ST_PACKET_SIGNATURE ((CSHORT)0x5506)
+
+#endif // _STCONST_
diff --git a/private/ntos/tdi/st/stdrvr.c b/private/ntos/tdi/st/stdrvr.c
new file mode 100644
index 000000000..d04fcd2a1
--- /dev/null
+++ b/private/ntos/tdi/st/stdrvr.c
@@ -0,0 +1,1627 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ stdrvr.c
+
+Abstract:
+
+ This module contains code which defines the NT Sample
+ transport provider's device object.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "st.h"
+
+
+//
+// This is a list of all the device contexts that ST owns,
+// used while unloading.
+//
+
+LIST_ENTRY StDeviceList = {0,0}; // initialized for real at runtime.
+
+
+
+//
+// Forward declaration of various routines used in this module.
+//
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+VOID
+StUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+NTSTATUS
+StConfigureTransport (
+ IN PUNICODE_STRING RegistryPath,
+ IN PCONFIG_DATA * ConfigData
+ );
+
+VOID
+StFreeConfigurationInfo (
+ IN PCONFIG_DATA ConfigurationInfo
+ );
+
+NTSTATUS
+StDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+StOpenAddress(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+StCloseAddress(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+StOpenConnection(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+StCloseConnection(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+StTdiAccept(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiConnect(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiDisconnect(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiDisassociateAddress (
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiAssociateAddress(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiListen(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiQueryInformation(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiReceive(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiReceiveDatagram(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiSend(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiSendDatagram(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiSetEventHandler(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiSetInformation(
+ IN PIRP Irp
+ );
+
+VOID
+StDeallocateResources(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,DriverEntry)
+#endif
+
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs initialization of the sample
+ transport driver. It creates the device objects for the transport
+ provider and performs other driver initialization.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+ RegistryPath - The name of ST's node in the registry.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ ULONG i, j;
+ STRING nameString;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_REQUEST Request;
+ PTP_CONNECTION Connection;
+ PTP_ADDRESS_FILE AddressFile;
+ PTP_ADDRESS Address;
+ PTP_PACKET Packet;
+ PNDIS_PACKET NdisPacket;
+ PRECEIVE_PACKET_TAG ReceiveTag;
+ PBUFFER_TAG BufferTag;
+ NTSTATUS status;
+ UINT SuccessfulOpens;
+ UINT MaxUserData;
+
+ PCONFIG_DATA StConfig = NULL;
+
+
+ ASSERT (sizeof (SHORT) == 2);
+
+ //
+ // This allocates the CONFIG_DATA structure and returns
+ // it in StConfig.
+ //
+
+ status = StConfigureTransport(RegistryPath, &StConfig);
+
+ if (!NT_SUCCESS (status)) {
+ PANIC (" Failed to initialize transport, St initialization failed.\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // make ourselves known to the NDIS wrapper.
+ //
+
+ RtlInitString( &nameString, ST_DEVICE_NAME );
+
+ status = StRegisterProtocol (&nameString);
+
+ if (!NT_SUCCESS (status)) {
+
+ StFreeConfigurationInfo(StConfig);
+ PANIC ("StInitialize: RegisterProtocol failed!\n");
+
+ StWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_REGISTER_FAILED,
+ 607,
+ status,
+ NULL,
+ 0,
+ NULL);
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+
+ //
+ // Initialize the driver object with this driver's entry points.
+ //
+
+ DriverObject->MajorFunction [IRP_MJ_CREATE] = StDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLOSE] = StDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLEANUP] = StDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL] = StDispatchInternal;
+ DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = StDispatch;
+
+ DriverObject->DriverUnload = StUnload;
+
+ //
+ // Initialize the global list of devices.
+ //
+
+ InitializeListHead (&StDeviceList);
+
+ SuccessfulOpens = 0;
+
+ for (j=0;j<StConfig->NumAdapters;j++ ) {
+
+
+ //
+ // Loop through all the adapters that are in the configuration
+ // information structure. Allocate a device object for each
+ // one that we find.
+ //
+
+ status = StCreateDeviceContext (DriverObject, &StConfig->Names[StConfig->DevicesOffset+j], &DeviceContext);
+
+ if (!NT_SUCCESS (status)) {
+ continue;
+ }
+
+ //
+ // Initialize our counter that records memory usage.
+ //
+
+ DeviceContext->MemoryUsage = 0;
+ DeviceContext->MemoryLimit = StConfig->MaxMemoryUsage;
+
+ //
+ // Now fire up NDIS so this adapter talks
+ //
+
+ status = StInitializeNdis (DeviceContext,
+ StConfig,
+ j);
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // Log an error.
+ //
+
+ StWriteGeneralErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_BINDING_FAILED,
+ 601,
+ status,
+ StConfig->Names[j].Buffer,
+ 0,
+ NULL);
+
+ StDereferenceDeviceContext ("Initialize NDIS failed", DeviceContext);
+ continue;
+
+ }
+
+
+ //
+ // Initialize our provider information structure; since it
+ // doesn't change, we just keep it around and copy it to
+ // whoever requests it.
+ //
+
+
+ MacReturnMaxDataSize(
+ &DeviceContext->MacInfo,
+ NULL,
+ 0,
+ DeviceContext->MaxSendPacketSize,
+ &MaxUserData);
+
+ DeviceContext->Information.Version = 0x0100;
+ DeviceContext->Information.MaxSendSize = 0x1fffe; // 128k - 2
+ DeviceContext->Information.MaxConnectionUserData = 0;
+ DeviceContext->Information.MaxDatagramSize = MaxUserData - sizeof(ST_HEADER);
+ DeviceContext->Information.ServiceFlags = ST_SERVICE_FLAGS;
+ DeviceContext->Information.MinimumLookaheadData = 128;
+ DeviceContext->Information.MaximumLookaheadData =
+ DeviceContext->MaxReceivePacketSize - sizeof(ST_HEADER);
+ DeviceContext->Information.NumberOfResources = ST_TDI_RESOURCES;
+ KeQuerySystemTime (&DeviceContext->Information.StartTime);
+
+
+ //
+ // Allocate various structures we will need.
+ //
+
+
+ //
+ // The TP_PACKET structure has a CHAR[1] field at the end
+ // which we expand upon to include all the headers needed;
+ // the size of the MAC header depends on what the adapter
+ // told us about its max header size.
+ //
+
+ DeviceContext->PacketHeaderLength =
+ DeviceContext->MacInfo.MaxHeaderLength +
+ sizeof (ST_HEADER);
+
+ DeviceContext->PacketLength =
+ FIELD_OFFSET(TP_PACKET, Header[0]) +
+ DeviceContext->PacketHeaderLength;
+
+
+ //
+ // The BUFFER_TAG structure has a CHAR[1] field at the end
+ // which we expand upong to include all the frame data.
+ //
+
+ DeviceContext->ReceiveBufferLength =
+ DeviceContext->MaxReceivePacketSize +
+ FIELD_OFFSET(BUFFER_TAG, Buffer[0]);
+
+
+ for (i=0; i<StConfig->InitRequests; i++) {
+
+ StAllocateRequest (DeviceContext, &Request);
+
+ if (Request == NULL) {
+ PANIC ("StInitialize: insufficient memory to allocate requests.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ InsertTailList (&DeviceContext->RequestPool, &Request->Linkage);
+ }
+
+ DeviceContext->RequestInitAllocated = StConfig->InitRequests;
+ DeviceContext->RequestMaxAllocated = StConfig->MaxRequests;
+
+
+ for (i=0; i<StConfig->InitConnections; i++) {
+
+ StAllocateConnection (DeviceContext, &Connection);
+
+ if (Connection == NULL) {
+ PANIC ("StInitialize: insufficient memory to allocate connections.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ InsertTailList (&DeviceContext->ConnectionPool, &Connection->LinkList);
+ }
+
+ DeviceContext->ConnectionInitAllocated = StConfig->InitConnections;
+ DeviceContext->ConnectionMaxAllocated = StConfig->MaxConnections;
+
+
+ for (i=0; i<StConfig->InitAddressFiles; i++) {
+
+ StAllocateAddressFile (DeviceContext, &AddressFile);
+
+ if (AddressFile == NULL) {
+ PANIC ("StInitialize: insufficient memory to allocate Address Files.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ InsertTailList (&DeviceContext->AddressFilePool, &AddressFile->Linkage);
+ }
+
+ DeviceContext->AddressFileInitAllocated = StConfig->InitAddressFiles;
+ DeviceContext->AddressFileMaxAllocated = StConfig->MaxAddressFiles;
+
+
+ for (i=0; i<StConfig->InitAddresses; i++) {
+
+ StAllocateAddress (DeviceContext, &Address);
+ if (Address == NULL) {
+ PANIC ("StInitialize: insufficient memory to allocate addresses.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ InsertTailList (&DeviceContext->AddressPool, &Address->Linkage);
+ }
+
+ DeviceContext->AddressInitAllocated = StConfig->InitAddresses;
+ DeviceContext->AddressMaxAllocated = StConfig->MaxAddresses;
+
+
+ for (i=0; i<StConfig->InitPackets; i++) {
+
+ StAllocateSendPacket (DeviceContext, &Packet);
+ if (Packet == NULL) {
+ PANIC ("StInitialize: insufficient memory to allocate packets.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ PushEntryList (&DeviceContext->PacketPool, (PSINGLE_LIST_ENTRY)&Packet->Linkage);
+ }
+
+ DeviceContext->PacketInitAllocated = StConfig->InitPackets;
+
+
+ for (i=0; i<StConfig->InitReceivePackets; i++) {
+
+ StAllocateReceivePacket (DeviceContext, &NdisPacket);
+
+ if (NdisPacket == NULL) {
+ PANIC ("StInitialize: insufficient memory to allocate packet MDLs.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ ReceiveTag = (PRECEIVE_PACKET_TAG)NdisPacket->ProtocolReserved;
+ PushEntryList (&DeviceContext->ReceivePacketPool, (PSINGLE_LIST_ENTRY)&ReceiveTag->Linkage);
+
+ }
+
+ DeviceContext->ReceivePacketInitAllocated = StConfig->InitReceivePackets;
+
+
+ for (i=0; i<StConfig->InitReceiveBuffers; i++) {
+
+ StAllocateReceiveBuffer (DeviceContext, &BufferTag);
+
+ if (BufferTag == NULL) {
+ PANIC ("StInitialize: Unable to allocate receive packet.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ PushEntryList (&DeviceContext->ReceiveBufferPool, &BufferTag->Linkage);
+
+ }
+
+ DeviceContext->ReceiveBufferInitAllocated = StConfig->InitReceiveBuffers;
+
+
+ //
+ // Now link the device into the global list.
+ //
+
+ InsertTailList (&StDeviceList, &DeviceContext->Linkage);
+
+ DeviceContext->State = DEVICECONTEXT_STATE_OPEN;
+
+ ++SuccessfulOpens;
+
+ continue;
+
+cleanup:
+
+ StWriteResourceErrorLog (DeviceContext, DeviceContext->MemoryUsage, 501);
+
+ //
+ // Cleanup whatever device context we were initializing
+ // when we failed.
+ //
+
+ StFreeResources (DeviceContext);
+ StCloseNdis (DeviceContext);
+ StDereferenceDeviceContext ("Load failed", DeviceContext);
+
+ }
+
+ StFreeConfigurationInfo(StConfig);
+
+ return ((SuccessfulOpens > 0) ? STATUS_SUCCESS : STATUS_DEVICE_DOES_NOT_EXIST);
+
+}
+
+VOID
+StUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unloads the sample transport driver.
+ It unbinds from any NDIS drivers that are open and frees all resources
+ associated with the transport. The I/O system will not call us until
+ nobody above has ST open.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ None. When the function returns, the driver is unloaded.
+
+--*/
+
+{
+
+ PDEVICE_CONTEXT DeviceContext;
+ PLIST_ENTRY p;
+
+
+ UNREFERENCED_PARAMETER (DriverObject);
+
+ //
+ // Walk the list of device contexts.
+ //
+
+ while (!IsListEmpty (&StDeviceList)) {
+
+ p = RemoveHeadList (&StDeviceList);
+ DeviceContext = CONTAINING_RECORD (p, DEVICE_CONTEXT, Linkage);
+
+ //
+ // Remove all the storage associated with the device.
+ //
+
+ StFreeResources (DeviceContext);
+
+ //
+ // Free the packet pools, etc. and close the
+ // adapter.
+ //
+
+ StCloseNdis (DeviceContext);
+
+ //
+ // And remove the creation reference from the device
+ // context.
+ //
+
+ StDereferenceDeviceContext ("Unload", DeviceContext);
+
+ }
+
+
+ //
+ // Finally, remove ourselves as an NDIS protocol.
+ //
+
+ StDeregisterProtocol();
+
+ return;
+
+}
+
+
+VOID
+StFreeResources (
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by ST to clean up the data structures associated
+ with a given DeviceContext. When this routine exits, the DeviceContext
+ should be deleted as it no longer has any assocaited resources.
+
+Arguments:
+
+ DeviceContext - Pointer to the DeviceContext we wish to clean up.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY s;
+ PTP_PACKET packet;
+ PTP_ADDRESS address;
+ PTP_CONNECTION connection;
+ PTP_REQUEST request;
+ PTP_ADDRESS_FILE addressFile;
+ PNDIS_PACKET ndisPacket;
+ PBUFFER_TAG BufferTag;
+
+
+ //
+ // Clean up packet pool.
+ //
+
+ while ( DeviceContext->PacketPool.Next != NULL ) {
+ s = PopEntryList( &DeviceContext->PacketPool );
+ packet = CONTAINING_RECORD( s, TP_PACKET, Linkage );
+
+ StDeallocateSendPacket (DeviceContext, packet);
+ }
+
+ //
+ // Clean up address pool.
+ //
+
+ while ( !IsListEmpty (&DeviceContext->AddressPool) ) {
+ p = RemoveHeadList (&DeviceContext->AddressPool);
+ address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+
+ StDeallocateAddress (DeviceContext, address);
+ }
+
+ //
+ // Clean up address file pool.
+ //
+
+ while ( !IsListEmpty (&DeviceContext->AddressFilePool) ) {
+ p = RemoveHeadList (&DeviceContext->AddressFilePool);
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+
+ StDeallocateAddressFile (DeviceContext, addressFile);
+ }
+
+ //
+ // Clean up connection pool.
+ //
+
+ while ( !IsListEmpty (&DeviceContext->ConnectionPool) ) {
+ p = RemoveHeadList (&DeviceContext->ConnectionPool);
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+
+ StDeallocateConnection (DeviceContext, connection);
+ }
+
+ //
+ // Clean up request pool.
+ //
+
+ while ( !IsListEmpty( &DeviceContext->RequestPool ) ) {
+ p = RemoveHeadList( &DeviceContext->RequestPool );
+ request = CONTAINING_RECORD (p, TP_REQUEST, Linkage );
+
+ StDeallocateRequest (DeviceContext, request);
+ }
+
+ //
+ // Clean up receive packet pool
+ //
+
+ while ( DeviceContext->ReceivePacketPool.Next != NULL) {
+ s = PopEntryList (&DeviceContext->ReceivePacketPool);
+
+ //
+ // HACK: This works because Linkage is the first field in
+ // ProtocolReserved for a receive packet.
+ //
+
+ ndisPacket = CONTAINING_RECORD (s, NDIS_PACKET, ProtocolReserved[0]);
+
+ StDeallocateReceivePacket (DeviceContext, ndisPacket);
+ }
+
+
+ //
+ // Clean up receive buffer pool.
+ //
+
+ while ( DeviceContext->ReceiveBufferPool.Next != NULL ) {
+ s = PopEntryList( &DeviceContext->ReceiveBufferPool );
+ BufferTag = CONTAINING_RECORD (s, BUFFER_TAG, Linkage );
+
+ StDeallocateReceiveBuffer (DeviceContext, BufferTag);
+ }
+
+
+ return;
+
+} /* StFreeResources */
+
+
+NTSTATUS
+StDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the ST device driver.
+ It accepts an I/O Request Packet, performs the request, and then
+ returns with the appropriate status.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IrpSp;
+ PDEVICE_CONTEXT DeviceContext;
+
+ //
+ // Check to see if ST has been initialized; if not, don't allow any use.
+ // Note that this only covers any user mode code use; kernel TDI clients
+ // will fail on their creation of an endpoint.
+ //
+
+ DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+ if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ IoMarkIrpPending (Irp);
+ Irp->IoStatus.Status = STATUS_PENDING;
+ Irp->IoStatus.Information = 0;
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ //
+ // Case on the function that is being performed by the requestor. If the
+ // operation is a valid one for this device, then make it look like it was
+ // successfully completed, where possible.
+ //
+
+
+ switch (IrpSp->MajorFunction) {
+
+ case IRP_MJ_DEVICE_CONTROL:
+ Status = StDeviceControl (DeviceObject, Irp, IrpSp);
+ break;
+
+ default:
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ } /* major function switch */
+
+ if (Status != STATUS_PENDING) {
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ return Status;
+} /* StDispatch */
+
+
+NTSTATUS
+StDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the ST device driver.
+ It accepts an I/O Request Packet, performs the request, and then
+ returns with the appropriate status.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PDEVICE_CONTEXT DeviceContext;
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IrpSp;
+ PFILE_FULL_EA_INFORMATION openType;
+ USHORT i;
+ BOOLEAN found;
+ PTP_ADDRESS_FILE AddressFile;
+ PTP_CONNECTION Connection;
+
+ //
+ // Check to see if ST has been initialized; if not, don't allow any use.
+ // Note that this only covers any user mode code use; kernel TDI clients
+ // will fail on their creation of an endpoint.
+ //
+
+ DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+ if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ IoMarkIrpPending (Irp);
+ Irp->IoStatus.Status = STATUS_PENDING;
+ Irp->IoStatus.Information = 0;
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ //
+ // Case on the function that is being performed by the requestor. If the
+ // operation is a valid one for this device, then make it look like it was
+ // successfully completed, where possible.
+ //
+
+
+ switch (IrpSp->MajorFunction) {
+
+ //
+ // The Create function opens a transport object (either address or
+ // connection). Access checking is performed on the specified
+ // address to ensure security of transport-layer addresses.
+ //
+
+ case IRP_MJ_CREATE:
+
+ openType =
+ (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+
+ if (openType != NULL) {
+
+ found = TRUE;
+
+ for (i=0;i<(USHORT)openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiTransportAddress[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = StOpenAddress (DeviceObject, Irp, IrpSp);
+ break;
+ }
+
+ //
+ // Connection?
+ //
+
+ found = TRUE;
+
+ for (i=0;i<(USHORT)openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiConnectionContext[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = StOpenConnection (DeviceObject, Irp, IrpSp);
+ break;
+ }
+
+ } else {
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ IrpSp->FileObject->FsContext = (PVOID)(DeviceContext->ControlChannelIdentifier);
+ ++DeviceContext->ControlChannelIdentifier;
+ if (DeviceContext->ControlChannelIdentifier == 0) {
+ DeviceContext->ControlChannelIdentifier = 1;
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ IrpSp->FileObject->FsContext2 = (PVOID)ST_FILE_TYPE_CONTROL;
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case IRP_MJ_CLOSE:
+
+ //
+ // The Close function closes a transport endpoint, terminates
+ // all outstanding transport activity on the endpoint, and unbinds
+ // the endpoint from its transport address, if any. If this
+ // is the last transport endpoint bound to the address, then
+ // the address is removed from the provider.
+ //
+
+ switch ((ULONG)IrpSp->FileObject->FsContext2) {
+ case TDI_TRANSPORT_ADDRESS_FILE:
+ AddressFile = (PTP_ADDRESS_FILE)IrpSp->FileObject->FsContext;
+
+ //
+ // This creates a reference to AddressFile->Address
+ // which is removed by StCloseAddress.
+ //
+
+ Status = StVerifyAddressObject(AddressFile);
+
+ if (!NT_SUCCESS (Status)) {
+ Status = STATUS_INVALID_HANDLE;
+ } else {
+ Status = StCloseAddress (DeviceObject, Irp, IrpSp);
+ }
+
+ break;
+
+ case TDI_CONNECTION_FILE:
+
+ //
+ // This is a connection
+ //
+
+ Connection = (PTP_CONNECTION)IrpSp->FileObject->FsContext;
+ Status = StVerifyConnectionObject (Connection);
+ if (NT_SUCCESS (Status)) {
+
+ Status = StCloseConnection (DeviceObject, Irp, IrpSp);
+ StDereferenceConnection ("Temporary Use",Connection);
+
+ }
+
+ break;
+
+ case ST_FILE_TYPE_CONTROL:
+
+ //
+ // this always succeeds
+ //
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ break;
+
+ case IRP_MJ_CLEANUP:
+
+ //
+ // Handle the two stage IRP for a file close operation. When the first
+ // stage hits, run down all activity on the object of interest. This
+ // do everything to it but remove the creation hold. Then, when the
+ // CLOSE irp hits, actually close the object.
+ //
+
+ switch ((ULONG)IrpSp->FileObject->FsContext2) {
+ case TDI_TRANSPORT_ADDRESS_FILE:
+ AddressFile = (PTP_ADDRESS_FILE)IrpSp->FileObject->FsContext;
+ Status = StVerifyAddressObject(AddressFile);
+ if (!NT_SUCCESS (Status)) {
+
+ Status = STATUS_INVALID_HANDLE;
+
+ } else {
+
+ StStopAddressFile (AddressFile, AddressFile->Address);
+ StDereferenceAddress ("IRP_MJ_CLEANUP", AddressFile->Address);
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case TDI_CONNECTION_FILE:
+
+ Connection = (PTP_CONNECTION)IrpSp->FileObject->FsContext;
+ Status = StVerifyConnectionObject (Connection);
+ if (NT_SUCCESS (Status)) {
+ StStopConnection (Connection, STATUS_LOCAL_DISCONNECT);
+ Status = STATUS_SUCCESS;
+ StDereferenceConnection ("Temporary Use",Connection);
+ }
+
+ break;
+
+ case ST_FILE_TYPE_CONTROL:
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ break;
+
+ default:
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ } /* major function switch */
+
+ if (Status != STATUS_PENDING) {
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ }
+
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ return Status;
+} /* StDispatchOpenClose */
+
+
+NTSTATUS
+StDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+ IrpSp - Pointer to current IRP stack frame.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+
+
+ //
+ // Branch to the appropriate request handler. Preliminary checking of
+ // the size of the request block is performed here so that it is known
+ // in the handlers that the minimum input parameters are readable. It
+ // is *not* determined here whether variable length input fields are
+ // passed correctly; this is a check which must be made within each routine.
+ //
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+
+ default:
+
+ //
+ // Convert the user call to the proper internal device call.
+ //
+
+ Status = TdiMapUserRequest (DeviceObject, Irp, IrpSp);
+
+ if (Status == STATUS_SUCCESS) {
+
+ //
+ // If TdiMapUserRequest returns SUCCESS then the IRP
+ // has been converted into an IRP_MJ_INTERNAL_DEVICE_CONTROL
+ // IRP, so we dispatch it as usual. The IRP will
+ // be completed by this call.
+ //
+ // StDispatchInternal expects to complete the IRP,
+ // so we change Status to PENDING so we don't.
+ //
+
+ (VOID)StDispatchInternal (DeviceObject, Irp);
+ Status = STATUS_PENDING;
+
+ }
+ }
+
+ return Status;
+} /* StDeviceControl */
+
+
+NTSTATUS
+StDispatchInternal (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE_CONTEXT DeviceContext;
+ PIO_STACK_LOCATION IrpSp;
+
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+
+
+ if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ IoMarkIrpPending (Irp);
+ Irp->IoStatus.Status = STATUS_PENDING;
+ Irp->IoStatus.Information = 0;
+
+
+ //
+ // Branch to the appropriate request handler. Preliminary checking of
+ // the size of the request block is performed here so that it is known
+ // in the handlers that the minimum input parameters are readable. It
+ // is *not* determined here whether variable length input fields are
+ // passed correctly; this is a check which must be made within each routine.
+ //
+
+ switch (IrpSp->MinorFunction) {
+
+ case TDI_ACCEPT:
+ Status = StTdiAccept (Irp);
+ break;
+
+ case TDI_ACTION:
+ Status = STATUS_SUCCESS;
+ break;
+
+ case TDI_ASSOCIATE_ADDRESS:
+ Status = StTdiAssociateAddress (Irp);
+ break;
+
+ case TDI_DISASSOCIATE_ADDRESS:
+ Status = StTdiDisassociateAddress (Irp);
+ break;
+
+ case TDI_CONNECT:
+ Status = StTdiConnect (Irp);
+ break;
+
+ case TDI_DISCONNECT:
+ Status = StTdiDisconnect (Irp);
+ break;
+
+ case TDI_LISTEN:
+ Status = StTdiListen (Irp);
+ break;
+
+ case TDI_QUERY_INFORMATION:
+ Status = StTdiQueryInformation (DeviceContext, Irp);
+ break;
+
+ case TDI_RECEIVE:
+ Status = StTdiReceive (Irp);
+ break;
+
+ case TDI_RECEIVE_DATAGRAM:
+ Status = StTdiReceiveDatagram (Irp);
+ break;
+
+ case TDI_SEND:
+ Status = StTdiSend (Irp);
+ break;
+
+ case TDI_SEND_DATAGRAM:
+ Status = StTdiSendDatagram (Irp);
+ break;
+
+ case TDI_SET_EVENT_HANDLER:
+
+ //
+ // Because this request will enable direct callouts from the
+ // transport provider at DISPATCH_LEVEL to a client-specified
+ // routine, this request is only valid in kernel mode, denying
+ // access to this request in user mode.
+ //
+
+ Status = StTdiSetEventHandler (Irp);
+ break;
+
+ case TDI_SET_INFORMATION:
+ Status = StTdiSetInformation (Irp);
+ break;
+
+
+ //
+ // Something we don't know about was submitted.
+ //
+
+ default:
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ if (Status != STATUS_PENDING) {
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ }
+
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ return Status;
+
+} /* StDispatchInternal */
+
+
+VOID
+StWriteResourceErrorLog(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ an out of resources condition.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context.
+
+ BytesNeeded - If applicable, the number of bytes that could not
+ be allocated.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ PUCHAR StringLoc;
+ ULONG TempUniqueError;
+ static WCHAR UniqueErrorBuffer[4] = L"000";
+ UINT i;
+
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ DeviceContext->DeviceNameLength +
+ sizeof(UniqueErrorBuffer);
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)DeviceContext,
+ EntrySize
+ );
+
+ //
+ // Convert the error value into a buffer.
+ //
+
+ TempUniqueError = UniqueErrorValue;
+ for (i=1; i>=0; i--) {
+ UniqueErrorBuffer[i] = (WCHAR)((TempUniqueError % 10) + L'0');
+ TempUniqueError /= 10;
+ }
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = sizeof(ULONG);
+ errorLogEntry->NumberOfStrings = 2;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = EVENT_TRANSPORT_RESOURCE_POOL;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+ errorLogEntry->DumpData[0] = BytesNeeded;
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ RtlCopyMemory (StringLoc, DeviceContext->DeviceName, DeviceContext->DeviceNameLength);
+
+ StringLoc += DeviceContext->DeviceNameLength;
+ RtlCopyMemory (StringLoc, UniqueErrorBuffer, sizeof(UniqueErrorBuffer));
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* StWriteResourceErrorLog */
+
+
+VOID
+StWriteGeneralErrorLog(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN ULONG DumpDataCount,
+ IN ULONG DumpData[]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ a general problem as indicated by the parameters. It handles
+ event codes REGISTER_FAILED, BINDING_FAILED, ADAPTER_NOT_FOUND,
+ TRANSFER_DATA, TOO_MANY_LINKS, and BAD_PROTOCOL. All these
+ events have messages with one or two strings in them.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context, or this may be
+ a driver object instead.
+
+ ErrorCode - The transport event code.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet.
+
+ FinalStatus - Used as the FinalStatus in the error log packet.
+
+ SecondString - If not NULL, the string to use as the %3
+ value in the error log packet.
+
+ DumpDataCount - The number of ULONGs of dump data.
+
+ DumpData - Dump data for the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG SecondStringSize;
+ PUCHAR StringLoc;
+ static WCHAR DriverName[3] = L"St";
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ (DumpDataCount * sizeof(ULONG));
+
+ if (DeviceContext->Type == IO_TYPE_DEVICE) {
+ EntrySize += (UCHAR)DeviceContext->DeviceNameLength;
+ } else {
+ EntrySize += sizeof(DriverName);
+ }
+
+ if (SecondString) {
+ SecondStringSize = (wcslen(SecondString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize += (UCHAR)SecondStringSize;
+ }
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)DeviceContext,
+ EntrySize
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = (USHORT)(DumpDataCount * sizeof(ULONG));
+ errorLogEntry->NumberOfStrings = (SecondString == NULL) ? 1 : 2;
+ errorLogEntry->StringOffset =
+ sizeof(IO_ERROR_LOG_PACKET) + ((DumpDataCount-1) * sizeof(ULONG));
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ if (DumpDataCount) {
+ RtlCopyMemory(errorLogEntry->DumpData, DumpData, DumpDataCount * sizeof(ULONG));
+ }
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ if (DeviceContext->Type == IO_TYPE_DEVICE) {
+ RtlCopyMemory (StringLoc, DeviceContext->DeviceName, DeviceContext->DeviceNameLength);
+ StringLoc += DeviceContext->DeviceNameLength;
+ } else {
+ RtlCopyMemory (StringLoc, DriverName, sizeof(DriverName));
+ StringLoc += sizeof(DriverName);
+ }
+ if (SecondString) {
+ RtlCopyMemory (StringLoc, SecondString, SecondStringSize);
+ }
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* StWriteGeneralErrorLog */
+
+
+VOID
+StWriteOidErrorLog(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NTSTATUS ErrorCode,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR AdapterString,
+ IN ULONG OidValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ a problem querying or setting an OID on an adapter. It handles
+ event codes SET_OID_FAILED and QUERY_OID_FAILED.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context.
+
+ ErrorCode - Used as the ErrorCode in the error log packet.
+
+ FinalStatus - Used as the FinalStatus in the error log packet.
+
+ AdapterString - The name of the adapter we were bound to.
+
+ OidValue - The OID which could not be set or queried.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG AdapterStringSize;
+ PUCHAR StringLoc;
+ static WCHAR OidBuffer[9] = L"00000000";
+ UINT i;
+ UINT CurrentDigit;
+
+ AdapterStringSize = (wcslen(AdapterString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) -
+ sizeof(ULONG) +
+ DeviceContext->DeviceNameLength +
+ AdapterStringSize +
+ sizeof(OidBuffer);
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)DeviceContext,
+ EntrySize
+ );
+
+ //
+ // Convert the OID into a buffer.
+ //
+
+ for (i=7; i>=0; i--) {
+ CurrentDigit = OidValue & 0xf;
+ OidValue >>= 4;
+ if (CurrentDigit >= 0xa) {
+ OidBuffer[i] = (WCHAR)(CurrentDigit - 0xa + L'A');
+ } else {
+ OidBuffer[i] = (WCHAR)(CurrentDigit + L'0');
+ }
+ }
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = 0;
+ errorLogEntry->NumberOfStrings = 3;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) - sizeof(ULONG);
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ RtlCopyMemory (StringLoc, DeviceContext->DeviceName, DeviceContext->DeviceNameLength);
+ StringLoc += DeviceContext->DeviceNameLength;
+
+ RtlCopyMemory (StringLoc, OidBuffer, sizeof(OidBuffer));
+ StringLoc += sizeof(OidBuffer);
+
+ RtlCopyMemory (StringLoc, AdapterString, AdapterStringSize);
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* StWriteOidErrorLog */
diff --git a/private/ntos/tdi/st/sthdrs.h b/private/ntos/tdi/st/sthdrs.h
new file mode 100644
index 000000000..737832fc1
--- /dev/null
+++ b/private/ntos/tdi/st/sthdrs.h
@@ -0,0 +1,69 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ sthdrs.h
+
+Abstract:
+
+ This module defines private structure definitions describing the layout
+ of the NT Sample Transport frames.
+
+Revision History:
+
+--*/
+
+#ifndef _STHDRS_
+#define _STHDRS_
+
+//
+// Pack these headers, as they are sent fully packed on the network.
+//
+
+#ifdef PACKING
+
+#ifdef __STDC__
+#pragma Off(Align_members)
+#else
+#pragma pack(1)
+#endif // def __STDC__
+
+#endif // def PACKING
+
+#define ST_SIGNATURE 0x37
+
+#define ST_CMD_CONNECT 'C'
+#define ST_CMD_DISCONNECT 'D'
+#define ST_CMD_INFORMATION 'I'
+#define ST_CMD_DATAGRAM 'G'
+
+#define ST_FLAGS_LAST 0x0001 // for information frames
+#define ST_FLAGS_BROADCAST 0x0002 // for datagrams
+
+typedef struct _ST_HEADER {
+ UCHAR Signature; // set to ST_SIGNATURE
+ UCHAR Command; // command byte
+ UCHAR Flags; // packet flags
+ UCHAR Reserved; // unused
+ UCHAR Destination[16]; // destination Netbios address
+ UCHAR Source[16]; // source Netbios address
+} ST_HEADER, *PST_HEADER;
+
+
+//
+// Resume previous structure packing method.
+//
+
+#ifdef PACKING
+
+#ifdef __STDC__
+#pragma Pop(Align_members)
+#else
+#pragma pack()
+#endif // def __STDC__
+
+#endif // def PACKING
+
+#endif // def _STHDRS_
diff --git a/private/ntos/tdi/st/stmac.c b/private/ntos/tdi/st/stmac.c
new file mode 100644
index 000000000..157c96a17
--- /dev/null
+++ b/private/ntos/tdi/st/stmac.c
@@ -0,0 +1,356 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ nbfmac.c
+
+Abstract:
+
+ This module contains code which implements Mac type dependent code for
+ the ST transport.
+
+Environment:
+
+ Kernel mode (Actually, unimportant)
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+UCHAR SingleRouteSourceRouting[] = { 0xc2, 0x70 };
+UCHAR GeneralRouteSourceRouting[] = { 0x82, 0x70 };
+ULONG DefaultSourceRoutingLength = 2;
+
+VOID
+MacInitializeMacInfo(
+ IN NDIS_MEDIUM MacType,
+ OUT PST_NDIS_IDENTIFICATION MacInfo
+ );
+
+//
+// This is the interpretation of the length bits in
+// the 802.5 source-routing information.
+//
+
+ULONG SR802_5Lengths[8] = { 516, 1500, 2052, 4472,
+ 8144, 11407, 17800, 17800 };
+
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,MacInitializeMacInfo)
+#pragma alloc_text(INIT,MacSetMulticastAddress)
+#endif
+
+
+
+VOID
+MacInitializeMacInfo(
+ IN NDIS_MEDIUM MacType,
+ OUT PST_NDIS_IDENTIFICATION MacInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Fills in the MacInfo table based on MacType.
+
+Arguments:
+
+ MacType - The MAC type we wish to decode.
+
+ MacInfo - The MacInfo structure to fill in.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ switch (MacType) {
+ case NdisMedium802_3:
+ MacInfo->DestinationOffset = 0;
+ MacInfo->SourceOffset = 6;
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->AddressLength = 6;
+ MacInfo->MaxHeaderLength = 14;
+ MacInfo->MediumType = NdisMedium802_3;
+ break;
+ case NdisMedium802_5:
+ MacInfo->DestinationOffset = 2;
+ MacInfo->SourceOffset = 8;
+ MacInfo->SourceRouting = TRUE;
+ MacInfo->AddressLength = 6;
+ MacInfo->MaxHeaderLength = 32;
+ MacInfo->MediumType = NdisMedium802_5;
+ break;
+ case NdisMediumFddi:
+ MacInfo->DestinationOffset = 1;
+ MacInfo->SourceOffset = 7;
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->AddressLength = 6;
+ MacInfo->MaxHeaderLength = 13;
+ MacInfo->MediumType = NdisMediumFddi;
+ break;
+ default:
+ ASSERT(FALSE);
+ }
+}
+
+VOID
+MacConstructHeader (
+ IN PST_NDIS_IDENTIFICATION MacInfo,
+ IN PUCHAR Buffer,
+ IN PUCHAR DestinationAddress,
+ IN PUCHAR SourceAddress,
+ IN UINT PacketLength,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ OUT PUINT HeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to construct the Mac header for the particular
+ network type we're talking to.
+
+Arguments:
+
+ MacInfo - Describes the mac we wish to build a header for.
+
+ Buffer - Where to build the header.
+
+ DestinationAddress - the address this packet is to be sent to.
+
+ SourceAddress - Our address. Passing it in as a parameter allows us to play
+ games with source if we need to.
+
+ PacketLength - The length of this packet. Note that this does not
+ includes the Mac header.
+
+ SourceRouting - Optional source routing information.
+
+ SourceRoutingLength - The length of SourceRouting.
+
+ HeaderLength - Returns the length of the constructed header.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Note network order of bytes.
+ //
+
+ switch (MacInfo->MediumType) {
+
+ case NdisMedium802_3:
+
+ *(ULONG UNALIGNED *)&Buffer[6] = *(ULONG UNALIGNED *)&SourceAddress[0];
+ Buffer[10] = SourceAddress[4];
+ Buffer[11] = SourceAddress[5];
+
+ *(ULONG UNALIGNED *)&Buffer[0] = *(ULONG UNALIGNED *)&DestinationAddress[0];
+ Buffer[4] = DestinationAddress[4];
+ Buffer[5] = DestinationAddress[5];
+
+ Buffer[12] = (UCHAR)(PacketLength >> 8);
+ Buffer[13] = (UCHAR)PacketLength;
+
+ *HeaderLength = 14;
+
+ break;
+
+ case NdisMedium802_5:
+
+ Buffer[0] = TR_HEADER_BYTE_0;
+ Buffer[1] = TR_HEADER_BYTE_1;
+
+ ASSERT (TR_ADDRESS_LENGTH == 6);
+
+ *(ULONG UNALIGNED *)&Buffer[8] = *(ULONG UNALIGNED *)&SourceAddress[0];
+ Buffer[12] = SourceAddress[4];
+ Buffer[13] = SourceAddress[5];
+
+ *(ULONG UNALIGNED *)&Buffer[2] = *(ULONG UNALIGNED *)&DestinationAddress[0];
+ Buffer[6] = DestinationAddress[4];
+ Buffer[7] = DestinationAddress[5];
+
+ *HeaderLength = 14;
+ if (SourceRouting != NULL) {
+ RtlCopyMemory (&Buffer[14], SourceRouting, SourceRoutingLength);
+ Buffer[8] |= 0x80; // add SR bit in source address
+ *HeaderLength = 14 + SourceRoutingLength;
+ }
+
+ break;
+
+ case NdisMediumFddi:
+
+ Buffer[0] = FDDI_HEADER_BYTE;
+
+ *(ULONG UNALIGNED *)&Buffer[7] = *(ULONG UNALIGNED *)&SourceAddress[0];
+ Buffer[11] = SourceAddress[4];
+ Buffer[12] = SourceAddress[5];
+
+ *(ULONG UNALIGNED *)&Buffer[1] = *(ULONG UNALIGNED *)&DestinationAddress[0];
+ Buffer[5] = DestinationAddress[4];
+ Buffer[6] = DestinationAddress[5];
+
+ *HeaderLength = 13;
+
+ break;
+
+ default:
+ PANIC ("MacConstructHeader: PANIC! called with unsupported Mac type.\n");
+ }
+}
+
+
+VOID
+MacReturnMaxDataSize(
+ IN PST_NDIS_IDENTIFICATION MacInfo,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN UINT DeviceMaxFrameSize,
+ OUT PUINT MaxFrameSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the space available for user data in a MAC packet.
+ This will be the available space after the MAC header; all headers
+ headers will be included in this space.
+
+Arguments:
+
+ MacInfo - Describes the MAC we wish to decode.
+
+ SourceRouting - If we are concerned about a reply to a specific
+ frame, then this information is used.
+
+ SourceRouting - The length of SourceRouting.
+
+ MaxFrameSize - The maximum frame size as returned by the adapter.
+
+ MaxDataSize - The maximum data size computed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ switch (MacInfo->MediumType) {
+
+ case NdisMedium802_3:
+
+ //
+ // For 802.3, we always have a 14-byte MAC header.
+ //
+
+ *MaxFrameSize = DeviceMaxFrameSize - 14;
+ break;
+
+ case NdisMedium802_5:
+
+ //
+ // For 802.5, if we have source routing information then
+ // use that, otherwise assume the worst.
+ //
+
+ if (SourceRouting && SourceRoutingLength >= 2) {
+
+ UINT SRLength;
+
+ SRLength = SR802_5Lengths[(SourceRouting[1] & 0x70) >> 4];
+ DeviceMaxFrameSize -= (SourceRoutingLength + 14);
+
+ if (DeviceMaxFrameSize < SRLength) {
+ *MaxFrameSize = DeviceMaxFrameSize;
+ } else {
+ *MaxFrameSize = SRLength;
+ }
+
+ } else {
+
+ if (DeviceMaxFrameSize < 548) {
+ *MaxFrameSize = DeviceMaxFrameSize - 32;
+ } else {
+ *MaxFrameSize = 516;
+ }
+ }
+
+ break;
+
+ case NdisMediumFddi:
+
+ //
+ // For FDDI, we always have a 13-byte MAC header.
+ //
+
+ *MaxFrameSize = DeviceMaxFrameSize - 13;
+ break;
+
+ }
+}
+
+
+
+VOID
+MacSetMulticastAddress (
+ IN NDIS_MEDIUM Type,
+ IN PUCHAR Buffer
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the multicast address into a buffer provided
+ by the user.
+
+Arguments:
+
+ Type the Mac Medium type.
+
+ Buffer the buffer to put the multicast address in.
+
+
+Return Value:
+
+ none.
+
+--*/
+{
+ switch (Type) {
+ case NdisMedium802_3:
+ case NdisMediumFddi:
+ Buffer[0] = 0x03;
+ Buffer[1] = 0x07;
+ Buffer[2] = 0x03;
+ Buffer[3] = 0x07;
+ Buffer[4] = 0x03;
+ Buffer[5] = 0x07;
+ break;
+
+ case NdisMedium802_5:
+ Buffer[0] = 0xc0;
+ Buffer[3] = 0x20;
+ break;
+
+ default:
+ PANIC ("MacSetMulticastAddress: PANIC! called with unsupported Mac type.\n");
+ }
+}
diff --git a/private/ntos/tdi/st/stmac.h b/private/ntos/tdi/st/stmac.h
new file mode 100644
index 000000000..cea2feff0
--- /dev/null
+++ b/private/ntos/tdi/st/stmac.h
@@ -0,0 +1,635 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ stmac.h
+
+Abstract:
+
+ This header file defines manifest constants and necessary macros for use
+ by transports dealing with multiple MAC cards through the NDIS interface.
+
+Revision History:
+
+--*/
+
+#ifndef _STMAC_
+#define _STMAC_
+
+//
+// MAC-specific definitions, some of which get used below
+//
+
+#define MAX_MAC_HEADER_LENGTH 32
+#define MAX_SOURCE_ROUTING 18
+#define MAX_DEFAULT_SR 2
+
+#define ETHERNET_ADDRESS_LENGTH 6
+#define ETHERNET_PACKET_LENGTH 1514 // max size of an ethernet packet
+#define ETHERNET_HEADER_LENGTH 14 // size of the ethernet MAC header
+#define ETHERNET_DATA_LENGTH_OFFSET 12
+#define ETHERNET_DESTINATION_OFFSET 0
+#define ETHERNET_SOURCE_OFFSET 6
+
+#define TR_ADDRESS_LENGTH 6
+#define TR_ADDRESS_OFFSET 2
+#define TR_SPECIFIC_OFFSET 0
+#define TR_PACKET_LENGTH 1514 // max size of a TR packet //BUGBUG
+#define TR_HEADER_LENGTH 36 // size of the MAC header w/o source routing
+#define TR_DATA_LENGTH_OFFSET 0
+#define TR_DESTINATION_OFFSET 2
+#define TR_SOURCE_OFFSET 8
+#define TR_ROUTING_OFFSET 14 // starts at the 14th byte
+#define TR_GR_BCAST_LENGTH 2
+#define TR_GR_BROADCAST 0xC270 // what a general route b'cast looks like
+#define TR_ROUTING_LENGTH_MASK 0x1F // low 5 bits in byte
+#define TR_DIRECTION_MASK 0x80 // returns direction bit
+
+#define TR_PREAMBLE_AC 0x10 // how would these be specified?
+#define TR_PREAMBLE_FC 0x40
+
+#define TR_HEADER_BYTE_0 0x10
+#define TR_HEADER_BYTE_1 0x40
+
+#define FDDI_ADDRESS_LENGTH 6
+#define FDDI_HEADER_BYTE 0x57
+
+
+
+//
+// We need this to define information about the MAC. Note that
+// it is a strange structure in that the first four elements
+// are for use internally by the stmac routines, while the
+// DeviceContext knows about and uses the last two.
+//
+
+typedef struct _ST_NDIS_IDENTIFICATION {
+ NDIS_MEDIUM MediumType;
+ BOOLEAN SourceRouting;
+ BOOLEAN MediumAsync;
+ BOOLEAN CopyLookahead;
+ ULONG DestinationOffset;
+ ULONG SourceOffset;
+ ULONG AddressLength;
+ ULONG MaxHeaderLength;
+} ST_NDIS_IDENTIFICATION, *PST_NDIS_IDENTIFICATION;
+
+
+
+VOID
+MacConstructHeader(
+ IN PST_NDIS_IDENTIFICATION MacInfo,
+ IN PUCHAR Buffer,
+ IN PUCHAR DestinationAddress,
+ IN PUCHAR SourceAddress,
+ IN UINT PacketLength,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ OUT PUINT HeaderLength
+ );
+
+VOID
+MacReturnMaxDataSize(
+ IN PST_NDIS_IDENTIFICATION MacInfo,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN UINT DeviceMaxFrameSize,
+ OUT PUINT MaxFrameSize
+ );
+
+VOID
+MacInitializeMacInfo(
+ IN NDIS_MEDIUM MacType,
+ OUT PST_NDIS_IDENTIFICATION MacInfo
+ );
+
+
+extern UCHAR SingleRouteSourceRouting[];
+extern UCHAR GeneralRouteSourceRouting[];
+extern ULONG DefaultSourceRoutingLength;
+
+
+//++
+//
+// VOID
+// MacReturnDestinationAddress(
+// IN PST_NDIS_IDENTIFICATION MacInfo,
+// IN PVOID Packet,
+// OUT PVOID * DestinationAddress
+// );
+//
+// Routine Description:
+//
+// Returns the a pointer to the destination address in the packet.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// Packet - The packet data.
+//
+// DestinationAddress - Returns the start of the destination address.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacReturnDestinationAddress(_MacInfo, _Packet, _DestinationAddress) \
+ *(_DestinationAddress) = ((PUCHAR)(_Packet)) + (_MacInfo)->DestinationOffset
+
+
+//++
+//
+// VOID
+// MacReturnSourceAddress(
+// IN PST_NDIS_IDENTIFICATION MacInfo,
+// IN PVOID Packet,
+// OUT PHARDWARE_ADDRESS SourceAddressBuffer,
+// OUT PHARDWARE_ADDRESS * SourceAddress,
+// );
+//
+// Routine Description:
+//
+// Copies the source address in the packet into SourceAddress.
+// NOTE THAT IT MAY COPY THE DATA, UNLIKE ReturnDestinationAddress
+// AND ReturnSourceRouting. Optionally, indicates whether the
+// destination address is a multicast address.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// Packet - The packet data.
+//
+// SourceAddressBuffer - A buffer to hold the source address,
+// if needed.
+//
+// SourceAddress - Returns a pointer to the source address.
+//
+// Multicast - Optional pointer to a BOOLEAN to receive indication
+// of whether the destination was a multicast address.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+//
+// NOTE: The default case below handles Ethernet and FDDI.
+//
+
+#define MacReturnSourceAddress(_MacInfo, _Packet, _SourceAddressBuffer, _SourceAddress) \
+{ \
+ PUCHAR TmpPacket = (PUCHAR)(_Packet); \
+ PUCHAR SrcBuffer = (PUCHAR)(_SourceAddressBuffer); \
+ \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_5: \
+ *(PULONG)SrcBuffer = *(ULONG UNALIGNED *)(&TmpPacket[8]) & ~0x80;\
+ SrcBuffer[4] = TmpPacket[12]; \
+ SrcBuffer[5] = TmpPacket[13]; \
+ *(_SourceAddress) = (PHARDWARE_ADDRESS)SrcBuffer; \
+ break; \
+ default: \
+ *(_SourceAddress) = (PHARDWARE_ADDRESS)(TmpPacket + \
+ (_MacInfo)->SourceOffset); \
+ break; \
+ } \
+}
+
+
+//++
+//
+// VOID
+// MacReturnSourceRouting(
+// IN PST_NDIS_IDENTIFICATION MacInfo,
+// IN PVOID Packet,
+// OUT PVOID * SourceRouting
+// OUT PUINT SourceRoutingLength
+// );
+//
+// Routine Description:
+//
+// Returns the a pointer to the source routing info in the packet.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// Packet - The packet data.
+//
+// SourceRouting - Returns the start of the source routing information,
+// or NULL if none is present.
+//
+// SourceRoutingLength - Returns the length of the source routing
+// information.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacReturnSourceRouting(_MacInfo, _Packet, _SourceRouting, _SourceRoutingLength) \
+{ \
+ PUCHAR TmpPacket = (PUCHAR)(_Packet); \
+ if ((_MacInfo)->SourceRouting) { \
+ if (TmpPacket[8] & 0x80) { \
+ *(_SourceRouting) = TmpPacket + 14; \
+ *(_SourceRoutingLength) = TmpPacket[14] & 0x1f; \
+ } else { \
+ *(_SourceRouting) = NULL; \
+ } \
+ } else { \
+ *(_SourceRouting) = NULL; \
+ } \
+}
+
+//++
+//
+// VOID
+// MacReturnPacketLength(
+// IN PST_NDIS_IDENTIFICATION MacInfo,
+// IN PVOID Header,
+// IN UINT PacketLength,
+// OUT PUINT DataLength
+// );
+//
+// Routine Description:
+//
+// Returns the length of data in the packet given the header.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// Header - The packet header.
+//
+// PacketLength - The length of the data (not including header).
+//
+// DataLength - Returns the length of the data. Unchanged if the
+// packet is not recognized. Should be initialized by caller to 0.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacReturnPacketLength(_MacInfo, _Header, _HeaderLength, _PacketLength, _DataLength) \
+{ \
+ PUCHAR TmpPacket = (PUCHAR)(_Header); \
+ UINT TmpLength; \
+ \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_3: \
+ if ((_HeaderLength) >= 14) { \
+ TmpLength = (TmpPacket[12] << 8) | TmpPacket[13]; \
+ if (TmpLength <= 0x600) { \
+ if (TmpLength <= (_PacketLength)) { \
+ *(_DataLength) = TmpLength; \
+ } \
+ } \
+ } \
+ break; \
+ case NdisMedium802_5: \
+ if (((_HeaderLength) >= 14) && \
+ (!(TmpPacket[8] & 0x80) || \
+ ((_HeaderLength) >= \
+ (UINT)(14 + (TmpPacket[14] & 0x1f))))) { \
+ *(_DataLength) = (_PacketLength); \
+ } \
+ break; \
+ case NdisMediumFddi: \
+ if ((_HeaderLength) >= 13) { \
+ *(_DataLength) = (_PacketLength); \
+ } \
+ break; \
+ } \
+}
+
+//++
+//
+// VOID
+// MacReturnHeaderLength(
+// IN PST_NDIS_IDENTIFICATION MacInfo,
+// IN PVOID Packet,
+// OUT PVOID HeaderLength,
+// );
+//
+// Routine Description:
+//
+// Returns the length of the MAC header in a packet (this
+// is used for loopback indications to separate header
+// and data).
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// Header - The packet header.
+//
+// HeaderLength - Returns the length of the header.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacReturnHeaderLength(_MacInfo, _Header, _HeaderLength) \
+{ \
+ PUCHAR TmpPacket = (PUCHAR)(_Header); \
+ \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_3: \
+ *(_HeaderLength) = 14; \
+ break; \
+ case NdisMedium802_5: \
+ if (TmpPacket[8] & 0x80) { \
+ *(_HeaderLength) = (TmpPacket[14] & 0x1f) + 14; \
+ } else { \
+ *(_HeaderLength) = 14; \
+ } \
+ break; \
+ case NdisMediumFddi: \
+ *(_HeaderLength) = 13; \
+ break; \
+ } \
+}
+
+//++
+//
+// VOID
+// MacReturnSingleRouteSR(
+// IN PST_NDIS_IDENTIFICATION MacInfo,
+// OUT PVOID * SingleRouteSR,
+// OUT PUINT SingleRouteSRLength
+// );
+//
+// Routine Description:
+//
+// Returns the a pointer to the standard single route broadcast
+// source routing information for the media type. This is used
+// for ADD_NAME_QUERY, DATAGRAM, NAME_IN_CONFLICT, NAME_QUERY,
+// and STATUS_QUERY frames.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// SingleRouteSR - Returns a pointer to the data.
+//
+// SingleRouteSRLength - The length of SingleRouteSR.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacReturnSingleRouteSR(_MacInfo, _SingleRouteSR, _SingleRouteSRLength) \
+{ \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_5: \
+ *(_SingleRouteSR) = SingleRouteSourceRouting; \
+ *(_SingleRouteSRLength) = DefaultSourceRoutingLength; \
+ break; \
+ default: \
+ *(_SingleRouteSR) = NULL; \
+ break; \
+ } \
+}
+
+
+//++
+//
+// VOID
+// MacReturnGeneralRouteSR(
+// IN PST_NDIS_IDENTIFICATION MacInfo,
+// OUT PVOID * GeneralRouteSR,
+// OUT PUINT GeneralRouteSRLength
+// );
+//
+// Routine Description:
+//
+// Returns the a pointer to the standard general route broadcast
+// source routing information for the media type. This is used
+// for NAME_RECOGNIZED frames.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// GeneralRouteSR - Returns a pointer to the data.
+//
+// GeneralRouteSRLength - The length of GeneralRouteSR.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacReturnGeneralRouteSR(_MacInfo, _GeneralRouteSR, _GeneralRouteSRLength) \
+{ \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_5: \
+ *(_GeneralRouteSR) = GeneralRouteSourceRouting; \
+ *(_GeneralRouteSRLength) = DefaultSourceRoutingLength; \
+ break; \
+ default: \
+ *(_GeneralRouteSR) = NULL; \
+ break; \
+ } \
+}
+
+#if 0
+
+//++
+//
+// VOID
+// MacCreateGeneralRouteReplySR(
+// IN PST_NDIS_IDENTIFICATION MacInfo,
+// IN PUCHAR ExistingSR,
+// IN UINT ExistingSRLength,
+// OUT PUCHAR * NewSR
+// );
+//
+// Routine Description:
+//
+// This modifies an existing source routing entry to make
+// it into a general-route source routing entry. The assumption
+// is that is to reply to existing source routing, so the
+// direction bit is also reversed. In addition, if it is
+// determined that no source routing is needed in the reply,
+// then NULL is returned.
+//
+// Note that the information is modified in-place, but a
+// separate pointer is returned (to allow NULL to be returned).
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// ExistingSR - The existing source routing to be modified.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacCreateGeneralRouteReplySR(_MacInfo, _ExistingSR, _ExistingSRLength, _NewSR) \
+{ \
+ if (_ExistingSR) { \
+ PUCHAR TmpSR = (PUCHAR)(_ExistingSR); \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_5: \
+ TmpSR[0] = (TmpSR[0] & 0x1f) | 0x80; \
+ TmpSR[1] = (TmpSR[1] ^ 0x80) | 0x70; \
+ *(_NewSR) = (_ExistingSR); \
+ break; \
+ default: \
+ *(_NewSR) = (_ExistingSR); \
+ break; \
+ } \
+ } else { \
+ *(_NewSR) = NULL; \
+ } \
+}
+#endif
+
+
+//++
+//
+// VOID
+// MacCreateNonBroadcastReplySR(
+// IN PST_NDIS_IDENTIFICATION MacInfo,
+// IN PUCHAR ExistingSR,
+// IN UINT ExistingSRLength,
+// OUT PUCHAR * NewSR
+// );
+//
+// Routine Description:
+//
+// This modifies an existing source routing entry to make
+// it into a non-broadcast source routing entry. The assumption
+// is that is to reply to existing source routing, so the
+// direction bit is also reversed. In addition, if it is
+// determined that no source routing is needed in the reply,
+// then NULL is returned.
+//
+// Note that the information is modified in-place, but a
+// separate pointer is returned (to allow NULL to be returned).
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// ExistingSR - The existing source routing to be modified.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacCreateNonBroadcastReplySR(_MacInfo, _ExistingSR, _ExistingSRLength, _NewSR) \
+{ \
+ if (_ExistingSR) { \
+ PUCHAR TmpSR = (PUCHAR)(_ExistingSR); \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_5: \
+ if ((_ExistingSRLength) == 2) { \
+ *(_NewSR) = NULL; \
+ } else { \
+ TmpSR[0] = (TmpSR[0] & 0x1f); \
+ TmpSR[1] = (TmpSR[1] ^ 0x80) | 0x70; \
+ *(_NewSR) = (_ExistingSR); \
+ } \
+ break; \
+ default: \
+ *(_NewSR) = (_ExistingSR); \
+ break; \
+ } \
+ } else { \
+ *(_NewSR) = NULL; \
+ } \
+}
+
+
+//++
+//
+// VOID
+// MacModifyHeader(
+// IN PST_NDIS_IDENTIFICATION MacInfo,
+// IN PUCHAR Header,
+// IN UINT PacketLength
+// );
+//
+// Routine Description:
+//
+// Modifies a pre-built packet header to include the
+// packet length. Used for connection-oriented traffic
+// where the header is pre-built.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// Header - The header to modify.
+//
+// PacketLength - Packet length (not including the header).
+// Currently this is the only field that cannot be pre-built.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacModifyHeader(_MacInfo, _Header, _PacketLength) \
+{ \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_3: \
+ (_Header)[12] = (UCHAR)((_PacketLength) >> 8); \
+ (_Header)[13] = (UCHAR)((_PacketLength) & 0xff); \
+ break; \
+ } \
+}
+
+
+VOID
+MacSetMulticastAddress(
+ IN NDIS_MEDIUM Type,
+ IN PUCHAR Buffer
+ );
+
+
+
+// VOID
+// StSetNdisPacketLength (
+// IN NDIS_PACKET Packet,
+// IN ULONG Length
+// );
+//
+// NB: This is not a general purpose macro; it assumes that we are setting the
+// length of an NDIS packet with only one NDIS_BUFFER chained. We do
+// this to save time during the sending of short control packets.
+//
+
+#define StSetNdisPacketLength(_packet,_length) { \
+ PNDIS_BUFFER NdisBuffer; \
+ NdisQueryPacket((_packet), NULL, NULL, &NdisBuffer, NULL); \
+ NdisAdjustBufferLength(NdisBuffer, (_length)); \
+ NdisRecalculatePacketCounts(_packet); \
+}
+
+#endif // ifdef _STMAC_
+
diff --git a/private/ntos/tdi/st/stndis.c b/private/ntos/tdi/st/stndis.c
new file mode 100644
index 000000000..43279f815
--- /dev/null
+++ b/private/ntos/tdi/st/stndis.c
@@ -0,0 +1,986 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ stndis.c
+
+Abstract:
+
+ This module contains code which implements the routines used to interface
+ ST and NDIS. All callback routines (except for Transfer Data,
+ Send Complete, and ReceiveIndication) are here, as well as those routines
+ called to initialize NDIS.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include "st.h"
+
+
+//
+// This is a one-per-driver variable used in binding
+// to the NDIS interface.
+//
+
+NDIS_HANDLE StNdisProtocolHandle = (NDIS_HANDLE)NULL;
+
+NDIS_STATUS
+StSubmitNdisRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN PNDIS_STRING AdapterString
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,StRegisterProtocol)
+#pragma alloc_text(INIT,StSubmitNdisRequest)
+#pragma alloc_text(INIT,StInitializeNdis)
+#endif
+
+
+NTSTATUS
+StRegisterProtocol (
+ IN STRING *NameString
+ )
+
+/*++
+
+Routine Description:
+
+ This routine introduces this transport to the NDIS interface.
+
+Arguments:
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+ STATUS_SUCCESS if all goes well,
+ Failure status if we tried to register and couldn't,
+ STATUS_INSUFFICIENT_RESOURCES if we couldn't even try to register.
+
+--*/
+
+{
+ NDIS_STATUS ndisStatus;
+
+ NDIS_PROTOCOL_CHARACTERISTICS ProtChars; // Used temporarily to register
+
+
+ //
+ // Set up the characteristics of this protocol
+ //
+
+ ProtChars.MajorNdisVersion = 3;
+ ProtChars.MinorNdisVersion = 0;
+
+ ProtChars.Name.Length = NameString->Length;
+ ProtChars.Name.Buffer = (PVOID)NameString->Buffer;
+
+ ProtChars.OpenAdapterCompleteHandler = StOpenAdapterComplete;
+ ProtChars.CloseAdapterCompleteHandler = StCloseAdapterComplete;
+ ProtChars.ResetCompleteHandler = StResetComplete;
+ ProtChars.RequestCompleteHandler = StRequestComplete;
+
+ ProtChars.SendCompleteHandler = StSendCompletionHandler;
+ ProtChars.TransferDataCompleteHandler = StTransferDataComplete;
+
+ ProtChars.ReceiveHandler = StReceiveIndication;
+ ProtChars.ReceiveCompleteHandler = StReceiveComplete;
+ ProtChars.StatusHandler = StStatusIndication;
+ ProtChars.StatusCompleteHandler = StStatusComplete;
+
+ NdisRegisterProtocol (
+ &ndisStatus,
+ &StNdisProtocolHandle,
+ &ProtChars,
+ (UINT)sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + NameString->Length);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS) {
+ return (NTSTATUS)ndisStatus;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+VOID
+StDeregisterProtocol (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes this transport to the NDIS interface.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS ndisStatus;
+
+ if (StNdisProtocolHandle != (NDIS_HANDLE)NULL) {
+ NdisDeregisterProtocol (
+ &ndisStatus,
+ StNdisProtocolHandle);
+ StNdisProtocolHandle = (NDIS_HANDLE)NULL;
+ }
+}
+
+
+NDIS_STATUS
+StSubmitNdisRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN PNDIS_STRING AdapterString
+ )
+
+/*++
+
+Routine Description:
+
+ This routine passed an NDIS_REQUEST to the MAC and waits
+ until it has completed before returning the final status.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context for this driver.
+
+ NdisRequest - Pointer to the NDIS_REQUEST to submit.
+
+ AdapterString - The name of the adapter, in case an error needs
+ to be logged.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NDIS_STATUS NdisStatus;
+
+ NdisRequest(
+ &NdisStatus,
+ DeviceContext->NdisBindingHandle,
+ NdisRequest);
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &DeviceContext->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = DeviceContext->NdisRequestStatus;
+
+ KeResetEvent(
+ &DeviceContext->NdisRequestEvent
+ );
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ StWriteOidErrorLog(
+ DeviceContext,
+ NdisRequest->RequestType == NdisRequestSetInformation ?
+ EVENT_TRANSPORT_SET_OID_FAILED : EVENT_TRANSPORT_QUERY_OID_FAILED,
+ NdisStatus,
+ AdapterString->Buffer,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid);
+ }
+
+ return NdisStatus;
+}
+
+
+NTSTATUS
+StInitializeNdis (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PCONFIG_DATA StConfig,
+ IN UINT ConfigInfoNameIndex
+ )
+
+/*++
+
+Routine Description:
+
+ This routine introduces this transport to the NDIS interface and sets up
+ any necessary NDIS data structures (Buffer pools and such). It will be
+ called for each adapter opened by this transport.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ ULONG SendPacketReservedLength;
+ ULONG ReceivePacketReservedLen;
+ ULONG SendPacketPoolSize;
+ ULONG ReceivePacketPoolSize;
+ NDIS_STATUS NdisStatus;
+ NDIS_STATUS OpenErrorStatus;
+ NDIS_MEDIUM StSupportedMedia[] = { NdisMedium802_3, NdisMedium802_5, NdisMediumFddi };
+ UINT SelectedMedium;
+ NDIS_REQUEST StRequest;
+ UCHAR StDataBuffer[6];
+ NDIS_OID StOid;
+ ULONG MinimumLookahead = 128 + sizeof(ST_HEADER);
+ ULONG ProtocolOptions, MacOptions;
+ PNDIS_STRING AdapterString;
+
+ //
+ // Initialize this adapter for ST use through NDIS
+ //
+
+ //
+ // This event is used in case any of the NDIS requests
+ // pend; we wait until it is set by the completion
+ // routine, which also sets NdisRequestStatus.
+ //
+
+ KeInitializeEvent(
+ &DeviceContext->NdisRequestEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ DeviceContext->NdisBindingHandle = NULL;
+ AdapterString = (PNDIS_STRING)&StConfig->Names[ConfigInfoNameIndex];
+
+ NdisOpenAdapter (
+ &NdisStatus,
+ &OpenErrorStatus,
+ &DeviceContext->NdisBindingHandle,
+ &SelectedMedium,
+ StSupportedMedia,
+ sizeof (StSupportedMedia) / sizeof(NDIS_MEDIUM),
+ StNdisProtocolHandle,
+ (NDIS_HANDLE)DeviceContext,
+ AdapterString,
+ 0,
+ NULL);
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &DeviceContext->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = DeviceContext->NdisRequestStatus;
+
+ KeResetEvent(
+ &DeviceContext->NdisRequestEvent
+ );
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ StWriteGeneralErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_ADAPTER_NOT_FOUND,
+ 807,
+ NdisStatus,
+ AdapterString->Buffer,
+ 0,
+ NULL);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Get the information we need about the adapter, based on
+ // the media type.
+ //
+
+ MacInitializeMacInfo(
+ StSupportedMedia[SelectedMedium],
+ &DeviceContext->MacInfo);
+
+
+ //
+ // Set the multicast/functional addresses first so we avoid windows where we
+ // receive only part of the addresses.
+ //
+
+ MacSetMulticastAddress (
+ DeviceContext->MacInfo.MediumType,
+ DeviceContext->MulticastAddress.Address);
+
+
+ switch (DeviceContext->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+
+ //
+ // Fill in the data for our multicast list.
+ //
+
+ RtlCopyMemory(StDataBuffer, DeviceContext->MulticastAddress.Address, 6);
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ StRequest.RequestType = NdisRequestSetInformation;
+ StRequest.DATA.SET_INFORMATION.Oid = OID_802_3_MULTICAST_LIST;
+ StRequest.DATA.SET_INFORMATION.InformationBuffer = &StDataBuffer;
+ StRequest.DATA.SET_INFORMATION.InformationBufferLength = 6;
+
+ break;
+
+ case NdisMedium802_5:
+
+ //
+ // For token-ring, we pass the last four bytes of the
+ // Netbios functional address.
+ //
+
+ //
+ // Fill in the data for our functional address.
+ //
+
+ RtlCopyMemory(StDataBuffer, ((PUCHAR)(DeviceContext->MulticastAddress.Address)) + 2, 4);
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ StRequest.RequestType = NdisRequestSetInformation;
+ StRequest.DATA.SET_INFORMATION.Oid = OID_802_5_CURRENT_FUNCTIONAL;
+ StRequest.DATA.SET_INFORMATION.InformationBuffer = &StDataBuffer;
+ StRequest.DATA.SET_INFORMATION.InformationBufferLength = 4;
+
+ break;
+
+ case NdisMediumFddi:
+
+ //
+ // Fill in the data for our multicast list.
+ //
+
+ RtlCopyMemory(StDataBuffer, DeviceContext->MulticastAddress.Address, 6);
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ StRequest.RequestType = NdisRequestSetInformation;
+ StRequest.DATA.SET_INFORMATION.Oid = OID_FDDI_LONG_MULTICAST_LIST;
+ StRequest.DATA.SET_INFORMATION.InformationBuffer = &StDataBuffer;
+ StRequest.DATA.SET_INFORMATION.InformationBufferLength = 6;
+
+ break;
+
+ }
+
+ NdisStatus = StSubmitNdisRequest (DeviceContext, &StRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ StCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+
+ switch (DeviceContext->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+
+ StOid = OID_802_3_CURRENT_ADDRESS;
+ break;
+
+ case NdisMedium802_5:
+
+ StOid = OID_802_5_CURRENT_ADDRESS;
+ break;
+
+ case NdisMediumFddi:
+
+ StOid = OID_FDDI_LONG_CURRENT_ADDR;
+ break;
+
+ default:
+
+ NdisStatus = NDIS_STATUS_FAILURE;
+ break;
+
+ }
+
+ StRequest.RequestType = NdisRequestQueryInformation;
+ StRequest.DATA.QUERY_INFORMATION.Oid = StOid;
+ StRequest.DATA.QUERY_INFORMATION.InformationBuffer = DeviceContext->LocalAddress.Address;
+ StRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 6;
+
+ NdisStatus = StSubmitNdisRequest (DeviceContext, &StRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ StCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Set up the reserved Netbios address.
+ //
+
+ RtlZeroMemory(DeviceContext->ReservedNetBIOSAddress, 10);
+ RtlCopyMemory(&DeviceContext->ReservedNetBIOSAddress[10], DeviceContext->LocalAddress.Address, 6);
+
+
+ //
+ // Now query the maximum packet sizes.
+ //
+
+ StRequest.RequestType = NdisRequestQueryInformation;
+ StRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_FRAME_SIZE;
+ StRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(DeviceContext->MaxReceivePacketSize);
+ StRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = StSubmitNdisRequest (DeviceContext, &StRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ StCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ StRequest.RequestType = NdisRequestQueryInformation;
+ StRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
+ StRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(DeviceContext->MaxSendPacketSize);
+ StRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = StSubmitNdisRequest (DeviceContext, &StRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ StCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now set the minimum lookahead size.
+ //
+
+ StRequest.RequestType = NdisRequestSetInformation;
+ StRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_CURRENT_LOOKAHEAD;
+ StRequest.DATA.QUERY_INFORMATION.InformationBuffer = &MinimumLookahead;
+ StRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = StSubmitNdisRequest (DeviceContext, &StRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ StCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now query the link speed
+ //
+
+ StRequest.RequestType = NdisRequestQueryInformation;
+ StRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_LINK_SPEED;
+ StRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(DeviceContext->MediumSpeed);
+ StRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = StSubmitNdisRequest (DeviceContext, &StRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ StCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now query the MAC's optional characteristics.
+ //
+
+ StRequest.RequestType = NdisRequestQueryInformation;
+ StRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAC_OPTIONS;
+ StRequest.DATA.QUERY_INFORMATION.InformationBuffer = &MacOptions;
+ StRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = StSubmitNdisRequest (DeviceContext, &StRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ StCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Since the sample transport does not try to optimize for the
+ // cases where transfer data is always synchronous or indications
+ // are not reentered, we ignore those bits in MacOptions.
+ //
+
+ DeviceContext->MacInfo.CopyLookahead =
+ (BOOLEAN)((MacOptions & NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA) != 0);
+
+
+ //
+ // Now set our options if needed. We can only support
+ // partial indications if running over 802.3 where the
+ // real packet length can be obtained from the header.
+ //
+
+ if (DeviceContext->MacInfo.MediumType == NdisMedium802_3) {
+
+ ProtocolOptions = NDIS_PROT_OPTION_ESTIMATED_LENGTH;
+
+ StRequest.RequestType = NdisRequestSetInformation;
+ StRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_PROTOCOL_OPTIONS;
+ StRequest.DATA.QUERY_INFORMATION.InformationBuffer = &ProtocolOptions;
+ StRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = StSubmitNdisRequest (DeviceContext, &StRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ StCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ }
+
+
+ //
+ // Calculate the NDIS-related stuff.
+ //
+
+ SendPacketReservedLength = sizeof (SEND_PACKET_TAG);
+ ReceivePacketReservedLen = sizeof (RECEIVE_PACKET_TAG);
+
+ //
+ // The send packet pool is used for UI frames and regular packets.
+ //
+
+ SendPacketPoolSize = StConfig->SendPacketPoolSize;
+
+ //
+ // The receive packet pool is used in transfer data.
+ //
+
+ ReceivePacketPoolSize = StConfig->ReceivePacketPoolSize;
+
+
+ NdisAllocatePacketPool (
+ &NdisStatus,
+ &DeviceContext->SendPacketPoolHandle,
+ SendPacketPoolSize,
+ SendPacketReservedLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ DeviceContext->SendPacketPoolHandle = NULL;
+ StCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ DeviceContext->MemoryUsage +=
+ (SendPacketPoolSize *
+ (sizeof(NDIS_PACKET) + SendPacketReservedLength));
+
+
+ NdisAllocatePacketPool(
+ &NdisStatus,
+ &DeviceContext->ReceivePacketPoolHandle,
+ ReceivePacketPoolSize,
+ ReceivePacketReservedLen);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ DeviceContext->ReceivePacketPoolHandle = NULL;
+ StCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ DeviceContext->MemoryUsage +=
+ (ReceivePacketPoolSize *
+ (sizeof(NDIS_PACKET) + ReceivePacketReservedLen));
+
+
+ //
+ // Allocate the buffer pool; as an estimate, allocate
+ // one per send or receive packet.
+ //
+
+ NdisAllocateBufferPool (
+ &NdisStatus,
+ &DeviceContext->NdisBufferPoolHandle,
+ SendPacketPoolSize + ReceivePacketPoolSize);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ DeviceContext->NdisBufferPoolHandle = NULL;
+ StCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now that everything is set up, we enable the filter
+ // for packet reception.
+ //
+
+ //
+ // Fill in the OVB for packet filter.
+ //
+
+ switch (DeviceContext->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+ case NdisMediumFddi:
+
+ RtlStoreUlong((PULONG)StDataBuffer,
+ (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_MULTICAST));
+ break;
+
+ case NdisMedium802_5:
+
+ RtlStoreUlong((PULONG)StDataBuffer,
+ (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_FUNCTIONAL));
+ break;
+
+ default:
+
+ ASSERT (FALSE);
+ break;
+
+ }
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ StRequest.RequestType = NdisRequestSetInformation;
+ StRequest.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ StRequest.DATA.SET_INFORMATION.InformationBuffer = &StDataBuffer;
+ StRequest.DATA.SET_INFORMATION.InformationBufferLength = sizeof(ULONG);
+
+ NdisStatus = StSubmitNdisRequest (DeviceContext, &StRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ StCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ return STATUS_SUCCESS;
+
+} /* StInitializeNdis */
+
+
+VOID
+StCloseNdis (
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unbinds the transport from the NDIS interface and does
+ any other work required to undo what was done in StInitializeNdis.
+ It is written so that it can be called from within StInitializeNdis
+ if it fails partway through.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NDIS_STATUS ndisStatus;
+
+ //
+ // Close the NDIS binding.
+ //
+
+ if (DeviceContext->NdisBindingHandle != (NDIS_HANDLE)NULL) {
+
+ //
+ // This event is used in case any of the NDIS requests
+ // pend; we wait until it is set by the completion
+ // routine, which also sets NdisRequestStatus.
+ //
+
+ KeInitializeEvent(
+ &DeviceContext->NdisRequestEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ NdisCloseAdapter(
+ &ndisStatus,
+ DeviceContext->NdisBindingHandle);
+
+ if (ndisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &DeviceContext->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ ndisStatus = DeviceContext->NdisRequestStatus;
+
+ KeResetEvent(
+ &DeviceContext->NdisRequestEvent
+ );
+
+ }
+
+ //
+ // We ignore ndisStatus.
+ //
+
+ }
+
+ if (DeviceContext->SendPacketPoolHandle != NULL) {
+ NdisFreePacketPool (DeviceContext->SendPacketPoolHandle);
+ }
+
+ if (DeviceContext->ReceivePacketPoolHandle != NULL) {
+ NdisFreePacketPool (DeviceContext->ReceivePacketPoolHandle);
+ }
+
+ if (DeviceContext->NdisBufferPoolHandle != NULL) {
+ NdisFreeBufferPool (DeviceContext->NdisBufferPoolHandle);
+ }
+
+} /* StCloseNdis */
+
+
+VOID
+StOpenAdapterComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN NDIS_STATUS OpenErrorStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that an open adapter
+ is complete. Since we only ever have one outstanding, and then only
+ during initialization, all we do is record the status and set
+ the event to signalled to unblock the initialization thread.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+ OpenErrorStatus - More status information.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)BindingContext;
+
+ DeviceContext->NdisRequestStatus = NdisStatus;
+ KeSetEvent(
+ &DeviceContext->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+ return;
+}
+
+VOID
+StCloseAdapterComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a close adapter
+ is complete. Currently we don't close adapters, so this is not
+ a problem.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)BindingContext;
+
+ DeviceContext->NdisRequestStatus = NdisStatus;
+ KeSetEvent(
+ &DeviceContext->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+ return;
+}
+
+VOID
+StResetComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a reset adapter
+ is complete. Currently we don't reset adapters, so this is not
+ a problem.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(BindingContext);
+ UNREFERENCED_PARAMETER(NdisStatus);
+
+ return;
+}
+
+VOID
+StRequestComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a request is complete.
+ Since we only ever have one request outstanding, and then only
+ during initialization, all we do is record the status and set
+ the event to signalled to unblock the initialization thread.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisRequest - The object describing the request.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)BindingContext;
+
+ DeviceContext->NdisRequestStatus = NdisStatus;
+ KeSetEvent(
+ &DeviceContext->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+ return;
+}
+
+VOID
+StStatusIndication (
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ )
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+
+ DeviceContext = (PDEVICE_CONTEXT)NdisBindingContext;
+
+ switch (NdisStatus) {
+
+ //
+ // Handle various status codes here.
+ //
+
+ default:
+ break;
+
+ }
+}
+
+
+VOID
+StStatusComplete (
+ IN NDIS_HANDLE NdisBindingContext
+ )
+{
+ UNREFERENCED_PARAMETER (NdisBindingContext);
+
+}
diff --git a/private/ntos/tdi/st/stprocs.h b/private/ntos/tdi/st/stprocs.h
new file mode 100644
index 000000000..480927f48
--- /dev/null
+++ b/private/ntos/tdi/st/stprocs.h
@@ -0,0 +1,923 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ stprocs.h
+
+Abstract:
+
+ This header file defines private functions for the NT Sample transport
+ provider.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Revision History:
+
+--*/
+
+#ifndef _STPROCS_
+#define _STPROCS_
+
+//
+// MACROS.
+//
+//
+// Debugging aids
+//
+
+//
+// VOID
+// IF_STDBG(
+// IN PSZ Message
+// );
+//
+
+#if DBG
+#define IF_STDBG(flags) \
+ if (StDebug & (flags))
+#else
+#define IF_STDBG(flags) \
+ if (0)
+#endif
+
+//
+// VOID
+// PANIC(
+// IN PSZ Message
+// );
+//
+
+#if DBG
+#define PANIC(Msg) \
+ DbgPrint ((Msg))
+#else
+#define PANIC(Msg)
+#endif
+
+
+//
+// These are define to allow DbgPrints that disappear when
+// DBG is 0.
+//
+
+#if DBG
+#define StPrint0(fmt) DbgPrint(fmt)
+#define StPrint1(fmt,v0) DbgPrint(fmt,v0)
+#define StPrint2(fmt,v0,v1) DbgPrint(fmt,v0,v1)
+#define StPrint3(fmt,v0,v1,v2) DbgPrint(fmt,v0,v1,v2)
+#define StPrint4(fmt,v0,v1,v2,v3) DbgPrint(fmt,v0,v1,v2,v3)
+#define StPrint5(fmt,v0,v1,v2,v3,v4) DbgPrint(fmt,v0,v1,v2,v3,v4)
+#define StPrint6(fmt,v0,v1,v2,v3,v4,v5) DbgPrint(fmt,v0,v1,v2,v3,v4,v5)
+#else
+#define StPrint0(fmt)
+#define StPrint1(fmt,v0)
+#define StPrint2(fmt,v0,v1)
+#define StPrint3(fmt,v0,v1,v2)
+#define StPrint4(fmt,v0,v1,v2,v3)
+#define StPrint5(fmt,v0,v1,v2,v3,v4)
+#define StPrint6(fmt,v0,v1,v2,v3,v4,v5)
+#endif
+
+//
+// The REFCOUNTS message take up a lot of room, so make
+// removing them easy.
+//
+
+#if 1
+#define IF_REFDBG IF_STDBG (ST_DEBUG_REFCOUNTS)
+#else
+#define IF_REFDBG if (0)
+#endif
+
+#define StReferenceConnection(Reason, Connection)\
+ StRefConnection (Connection)
+
+#define StDereferenceConnection(Reason, Connection)\
+ StDerefConnection (Connection)
+
+#define StDereferenceConnectionSpecial(Reason, Connection)\
+ StDerefConnectionSpecial (Connection)
+
+#define StReferenceRequest(Reason, Request)\
+ (VOID)InterlockedIncrement( \
+ &(Request)->ReferenceCount)
+
+#define StDereferenceRequest(Reason, Request)\
+ StDerefRequest (Request)
+
+#define StReferenceSendIrp(Reason, IrpSp)\
+ (VOID)InterlockedIncrement( \
+ &IRP_REFCOUNT(IrpSp))
+
+#define StDereferenceSendIrp(Reason, IrpSp)\
+ StDerefSendIrp (IrpSp)
+
+#define StReferenceAddress(Reason, Address)\
+ (VOID)InterlockedIncrement( \
+ &(Address)->ReferenceCount)
+
+#define StDereferenceAddress(Reason, Address)\
+ StDerefAddress (Address)
+
+#define StReferenceDeviceContext(Reason, DeviceContext)\
+ StRefDeviceContext (DeviceContext)
+
+#define StDereferenceDeviceContext(Reason, DeviceContext)\
+ StDerefDeviceContext (DeviceContext)
+
+#define StReferencePacket(Packet) \
+ (VOID)InterlockedIncrement( \
+ &(Packet)->ReferenceCount)
+
+//
+// These macros are used to create and destroy packets, due
+// to the allocation or deallocation of structure which
+// need them.
+//
+
+
+#define StAddSendPacket(DeviceContext) { \
+ PTP_PACKET _SendPacket; \
+ StAllocateSendPacket ((DeviceContext), &_SendPacket); \
+ if (_SendPacket != NULL) { \
+ ExInterlockedPushEntryList( \
+ &(DeviceContext)->PacketPool, \
+ (PSINGLE_LIST_ENTRY)&_SendPacket->Linkage, \
+ &(DeviceContext)->Interlock); \
+ } \
+}
+
+#define StRemoveSendPacket(DeviceContext) { \
+ PSINGLE_LIST_ENTRY s; \
+ if (DeviceContext->PacketAllocated > DeviceContext->PacketInitAllocated) { \
+ s = ExInterlockedPopEntryList( \
+ &(DeviceContext)->PacketPool, \
+ &(DeviceContext)->Interlock); \
+ if (s != NULL) { \
+ StDeallocateSendPacket((DeviceContext), \
+ (PTP_PACKET)CONTAINING_RECORD(s, TP_PACKET, Linkage)); \
+ } \
+ } \
+}
+
+
+#define StAddReceivePacket(DeviceContext) { \
+ PNDIS_PACKET _ReceivePacket; \
+ StAllocateReceivePacket ((DeviceContext), &_ReceivePacket); \
+ if (_ReceivePacket != NULL) { \
+ ExInterlockedPushEntryList( \
+ &(DeviceContext)->ReceivePacketPool, \
+ (PSINGLE_LIST_ENTRY)&((PRECEIVE_PACKET_TAG)_ReceivePacket->ProtocolReserved)->Linkage, \
+ &(DeviceContext)->Interlock); \
+ } \
+}
+
+#define StRemoveReceivePacket(DeviceContext) { \
+ PSINGLE_LIST_ENTRY s; \
+ if (DeviceContext->ReceivePacketAllocated > DeviceContext->ReceivePacketInitAllocated) { \
+ s = ExInterlockedPopEntryList( \
+ &(DeviceContext)->ReceivePacketPool, \
+ &(DeviceContext)->Interlock); \
+ if (s != NULL) { \
+ StDeallocateReceivePacket((DeviceContext), \
+ (PNDIS_PACKET)CONTAINING_RECORD(s, NDIS_PACKET, ProtocolReserved[0])); \
+ } \
+ } \
+}
+
+
+#define StAddReceiveBuffer(DeviceContext) { \
+ PBUFFER_TAG _ReceiveBuffer; \
+ StAllocateReceiveBuffer ((DeviceContext), &_ReceiveBuffer); \
+ if (_ReceiveBuffer != NULL) { \
+ ExInterlockedPushEntryList( \
+ &(DeviceContext)->ReceiveBufferPool, \
+ &_ReceiveBuffer->Linkage, \
+ &(DeviceContext)->Interlock); \
+ } \
+}
+
+#define StRemoveReceiveBuffer(DeviceContext) { \
+ PSINGLE_LIST_ENTRY s; \
+ if (DeviceContext->ReceiveBufferAllocated > DeviceContext->ReceiveBufferInitAllocated) { \
+ s = ExInterlockedPopEntryList( \
+ &(DeviceContext)->ReceiveBufferPool, \
+ &(DeviceContext)->Interlock); \
+ if (s != NULL) { \
+ StDeallocateReceiveBuffer(DeviceContext, \
+ (PBUFFER_TAG)CONTAINING_RECORD(s, BUFFER_TAG, Linkage)); \
+ } \
+ } \
+}
+
+
+//
+// These routines are used to maintain counters.
+//
+
+#define INCREMENT_COUNTER(_DeviceContext,_Field) \
+ ++(_DeviceContext)->_Field
+
+#define DECREMENT_COUNTER(_DeviceContext,_Field) \
+ --(_DeviceContext)->_Field
+
+#define ADD_TO_LARGE_INTEGER(_LargeInteger,_Ulong) \
+ ExInterlockedAddLargeStatistic((_LargeInteger), (ULONG)(_Ulong))
+
+
+
+//
+// Routines in PACKET.C (TP_PACKET object manager).
+//
+
+VOID
+StAllocateSendPacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_PACKET *TransportSendPacket
+ );
+
+VOID
+StAllocateReceivePacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PNDIS_PACKET *TransportReceivePacket
+ );
+
+VOID
+StAllocateReceiveBuffer(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PBUFFER_TAG *TransportReceiveBuffer
+ );
+
+VOID
+StDeallocateSendPacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_PACKET TransportSendPacket
+ );
+
+VOID
+StDeallocateReceivePacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNDIS_PACKET TransportReceivePacket
+ );
+
+VOID
+StDeallocateReceiveBuffer(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PBUFFER_TAG TransportReceiveBuffer
+ );
+
+NTSTATUS
+StCreatePacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_PACKET *Packet
+ );
+
+VOID
+StDestroyPacket(
+ IN PTP_PACKET Packet
+ );
+
+VOID
+StWaitPacket(
+ IN PTP_CONNECTION Connection,
+ IN ULONG Flags
+ );
+
+//
+// Routines in RCVENG.C (Receive engine).
+//
+
+VOID
+AwakenReceive(
+ IN PTP_CONNECTION Connection
+ );
+
+VOID
+ActivateReceive(
+ IN PTP_CONNECTION Connection
+ );
+
+VOID
+CompleteReceive (
+ IN PTP_CONNECTION Connection,
+ IN BOOLEAN EndOfRecord,
+ KIRQL ConnectionIrql,
+ KIRQL CancelIrql
+ );
+
+VOID
+StCancelReceive(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+//
+// Routines in SENDENG.C (Send engine).
+//
+
+VOID
+InitializeSend(
+ PTP_CONNECTION Connection
+ );
+
+VOID
+StartPacketizingConnection(
+ PTP_CONNECTION Connection,
+ IN BOOLEAN Immediate,
+ IN KIRQL ConnectionIrql,
+ IN KIRQL CancelIrql
+ );
+
+VOID
+PacketizeConnections(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+VOID
+PacketizeSend(
+ IN PTP_CONNECTION Connection
+ );
+
+VOID
+CompleteSend(
+ IN PTP_CONNECTION Connection
+ );
+
+VOID
+FailSend(
+ IN PTP_CONNECTION Connection,
+ IN NTSTATUS RequestStatus,
+ IN BOOLEAN StopConnection
+ );
+
+VOID
+StCancelSend(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+StNdisSend(
+ IN PTP_PACKET Packet
+ );
+
+VOID
+StSendCompletionHandler(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ );
+
+NTSTATUS
+BuildBufferChainFromMdlChain (
+ IN NDIS_HANDLE BufferPoolHandle,
+ IN PMDL CurrentMdl,
+ IN ULONG ByteOffset,
+ IN ULONG DesiredLength,
+ OUT PNDIS_BUFFER *Destination,
+ OUT PMDL *NewCurrentMdl,
+ OUT ULONG *NewByteOffset,
+ OUT ULONG *TrueLength
+ );
+
+//
+// Routines in DEVCTX.C (TP_DEVCTX object manager).
+//
+
+VOID
+StRefDeviceContext(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+VOID
+StDerefDeviceContext(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+NTSTATUS
+StCreateDeviceContext(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN OUT PDEVICE_CONTEXT *DeviceContext
+ );
+
+VOID
+StDestroyDeviceContext(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+
+//
+// Routines in ADDRESS.C (TP_ADDRESS object manager).
+//
+
+VOID
+StRefAddress(
+ IN PTP_ADDRESS Address
+ );
+
+VOID
+StDerefAddress(
+ IN PTP_ADDRESS Address
+ );
+
+VOID
+StAllocateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS_FILE *TransportAddressFile
+ );
+
+VOID
+StDeallocateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS_FILE TransportAddressFile
+ );
+
+NTSTATUS
+StCreateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS_FILE * AddressFile
+ );
+
+VOID
+StReferenceAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile
+ );
+
+VOID
+StDereferenceAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile
+ );
+
+VOID
+StStopAddress(
+ IN PTP_ADDRESS Address
+ );
+
+VOID
+StRegisterAddress(
+ IN PTP_ADDRESS Address
+ );
+
+BOOLEAN
+StMatchNetbiosAddress(
+ IN PTP_ADDRESS Address,
+ IN PUCHAR NetBIOSName
+ );
+
+VOID
+StAllocateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS *TransportAddress
+ );
+
+VOID
+StDeallocateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS TransportAddress
+ );
+
+NTSTATUS
+StCreateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PST_NETBIOS_ADDRESS NetworkName,
+ OUT PTP_ADDRESS *Address
+ );
+
+PTP_ADDRESS
+StLookupAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PST_NETBIOS_ADDRESS NetworkName
+ );
+
+PTP_CONNECTION
+StLookupRemoteName(
+ IN PTP_ADDRESS Address,
+ IN PUCHAR RemoteName
+ );
+
+NTSTATUS
+StStopAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile,
+ IN PTP_ADDRESS Address
+ );
+
+NTSTATUS
+StVerifyAddressObject (
+ IN PTP_ADDRESS_FILE AddressFile
+ );
+
+NTSTATUS
+StSendDatagramsOnAddress(
+ PTP_ADDRESS Address
+ );
+
+//
+//
+// Routines in CONNOBJ.C (TP_CONNECTION object manager).
+//
+
+VOID
+StRefConnection(
+ IN PTP_CONNECTION TransportConnection
+ );
+
+VOID
+StDerefConnection(
+ IN PTP_CONNECTION TransportConnection
+ );
+
+VOID
+StDerefConnectionSpecial(
+ IN PTP_CONNECTION TransportConnection
+ );
+
+VOID
+StStopConnection(
+ IN PTP_CONNECTION TransportConnection,
+ IN NTSTATUS Status
+ );
+
+VOID
+StCancelConnection(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+PTP_CONNECTION
+StLookupListeningConnection(
+ IN PTP_ADDRESS Address
+ );
+
+VOID
+StAllocateConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_CONNECTION *TransportConnection
+ );
+
+VOID
+StDeallocateConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_CONNECTION TransportConnection
+ );
+
+NTSTATUS
+StCreateConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_CONNECTION *TransportConnection
+ );
+
+PTP_CONNECTION
+StLookupConnectionByContext(
+ IN PTP_ADDRESS Address,
+ IN CONNECTION_CONTEXT ConnectionContext
+ );
+
+PTP_CONNECTION
+StFindConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR LocalName,
+ IN PUCHAR RemoteName
+ );
+
+NTSTATUS
+StVerifyConnectionObject (
+ IN PTP_CONNECTION Connection
+ );
+
+//
+// Routines in REQUEST.C (TP_REQUEST object manager).
+//
+
+
+VOID
+TdiRequestTimeoutHandler(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+VOID
+StRefRequest(
+ IN PTP_REQUEST Request
+ );
+
+VOID
+StDerefRequest(
+ IN PTP_REQUEST Request
+ );
+
+VOID
+StCompleteRequest(
+ IN PTP_REQUEST Request,
+ IN NTSTATUS Status,
+ IN ULONG Information
+ );
+
+VOID
+StRefSendIrp(
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+VOID
+StDerefSendIrp(
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+VOID
+StCompleteSendIrp(
+ IN PIRP Irp,
+ IN NTSTATUS Status,
+ IN ULONG Information
+ );
+
+VOID
+StAllocateRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_REQUEST *TransportRequest
+ );
+
+VOID
+StDeallocateRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_REQUEST TransportRequest
+ );
+
+NTSTATUS
+StCreateRequest(
+ IN PIRP Irp,
+ IN PVOID Context,
+ IN ULONG Flags,
+ IN PMDL Buffer2,
+ IN ULONG Buffer2Length,
+ IN LARGE_INTEGER Timeout,
+ OUT PTP_REQUEST * TpRequest
+ );
+
+//
+// Routines in DLC.C (entrypoints from NDIS interface).
+//
+
+NDIS_STATUS
+StReceiveIndication(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+NDIS_STATUS
+StGeneralReceiveHandler (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PVOID HeaderBuffer,
+ IN UINT PacketSize,
+ IN PST_HEADER StHeader,
+ IN UINT StSize
+ );
+
+VOID
+StReceiveComplete (
+ IN NDIS_HANDLE BindingContext
+ );
+
+VOID
+StTransferDataComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ );
+
+//
+// Routines in UFRAMES.C, the UI-frame ST frame processor.
+//
+
+NTSTATUS
+StIndicateDatagram(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address,
+ IN PUCHAR Header,
+ IN ULONG Length
+ );
+
+NTSTATUS
+StProcessConnectionless(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PST_HEADER StHeader,
+ IN ULONG StLength,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ OUT PTP_ADDRESS * DatagramAddress
+ );
+
+//
+// Routines in IFRAMES.C, the I-frame ST frame processor.
+//
+
+NTSTATUS
+StProcessIIndicate(
+ IN PTP_CONNECTION Connection,
+ IN PST_HEADER StHeader,
+ IN UINT StIndicatedLength,
+ IN UINT StTotalLength,
+ IN NDIS_HANDLE ReceiveContext,
+ IN BOOLEAN Last
+ );
+
+//
+// Routines in RCV.C (data copying routines for receives).
+//
+
+NTSTATUS
+StCopyMdlToBuffer(
+ IN PMDL SourceMdlChain,
+ IN ULONG SourceOffset,
+ IN PVOID DestinationBuffer,
+ IN ULONG DestinationOffset,
+ IN ULONG DestinationBufferSize,
+ IN PULONG BytesCopied
+ );
+
+//
+// Routines in FRAMESND.C, the UI-frame (non-link) shipper.
+//
+
+NTSTATUS
+StSendConnect(
+ IN PTP_CONNECTION Connection
+ );
+
+NTSTATUS
+StSendDisconnect(
+ IN PTP_CONNECTION Connection
+ );
+
+NTSTATUS
+StSendAddressFrame(
+ IN PTP_ADDRESS Address
+ );
+
+VOID
+StSendDatagramCompletion(
+ IN PTP_ADDRESS Address,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ );
+
+
+//
+// Routines in stdrvr.c
+//
+
+NTSTATUS
+StDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StDispatchInternal(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+//
+// Routine in stndis.c
+//
+
+VOID
+StOpenAdapterComplete(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status,
+ IN NDIS_STATUS OpenErrorStatus
+ );
+
+VOID
+StCloseAdapterComplete(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+StResetComplete(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+StRequestComplete(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+StStatusIndication (
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength
+ );
+
+VOID
+StStatusComplete (
+ IN NDIS_HANDLE NdisBindingContext
+ );
+
+#if DBG
+PUCHAR
+StGetNdisStatus (
+ IN NDIS_STATUS NdisStatus
+ );
+#endif
+
+VOID
+StWriteResourceErrorLog(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue
+ );
+
+VOID
+StWriteGeneralErrorLog(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN ULONG DumpDataCount,
+ IN ULONG DumpData[]
+ );
+
+VOID
+StWriteOidErrorLog(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NTSTATUS ErrorCode,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR AdapterString,
+ IN ULONG OidValue
+ );
+
+VOID
+StFreeResources(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+
+//
+// routines in stcnfg.c
+//
+
+NTSTATUS
+StConfigureProvider(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+//
+// Routines in stndis.c
+//
+
+NTSTATUS
+StRegisterProtocol (
+ IN STRING *NameString
+ );
+
+VOID
+StDeregisterProtocol (
+ VOID
+ );
+
+
+NTSTATUS
+StInitializeNdis (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PCONFIG_DATA ConfigInfo,
+ IN UINT ConfigInfoNameIndex
+ );
+
+VOID
+StCloseNdis (
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+
+#endif // def _STPROCS_
diff --git a/private/ntos/tdi/st/sttypes.h b/private/ntos/tdi/st/sttypes.h
new file mode 100644
index 000000000..fdbc2195a
--- /dev/null
+++ b/private/ntos/tdi/st/sttypes.h
@@ -0,0 +1,1103 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ sttypes.h
+
+Abstract:
+
+ This module defines private data structures and types for the NT
+ Sample transport provider.
+
+Revision History:
+
+--*/
+
+#ifndef _STTYPES_
+#define _STTYPES_
+
+//
+// This structure defines a NETBIOS name as a character array for use when
+// passing preformatted NETBIOS names between internal routines. It is
+// not a part of the external interface to the transport provider.
+//
+
+#define NETBIOS_NAME_LENGTH 16
+
+typedef struct _ST_NETBIOS_ADDRESS {
+ UCHAR NetbiosName[NETBIOS_NAME_LENGTH];
+ USHORT NetbiosNameType;
+} ST_NETBIOS_ADDRESS, *PST_NETBIOS_ADDRESS;
+
+
+//
+// This structure defines things associated with a TP_REQUEST, or outstanding
+// TDI request, maintained on a queue somewhere in the transport. All
+// requests other than open/close require that a TP_REQUEST block be built.
+//
+
+//
+// the types of potential owners of requests
+//
+
+typedef enum _REQUEST_OWNER {
+ ConnectionType,
+ AddressType,
+ DeviceContextType
+} REQUEST_OWNER;
+
+//
+// The request itself
+//
+
+typedef struct _TP_REQUEST {
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+ LIST_ENTRY Linkage; // used by ExInterlocked routines.
+ KSPIN_LOCK SpinLock; // spinlock for other fields.
+ // (used in KeAcquireSpinLock calls)
+ LONG ReferenceCount; // reasons why we can't destroy this req.
+
+ struct _DEVICE_CONTEXT *Provider; // pointer to the device context.
+ PKSPIN_LOCK ProviderInterlock; // &Provider->Interlock.
+
+ PIRP IoRequestPacket; // pointer to IRP for this request.
+
+ //
+ // The following two fields are used to quickly reference the basic
+ // components of the requests without worming through the IRP's stack.
+ //
+
+ PVOID Buffer2; // second buffer in the request.
+ ULONG Buffer2Length; // length of the second buffer.
+
+ //
+ // The following two fields (Flags and Context) are used to clean up
+ // queued requests which must be canceled or abnormally completed.
+ // The Flags field contains bitflags indicating the state of the request,
+ // and the specific queue type that the request is located on. The
+ // Context field contains a pointer to the owning structure (TP_CONNECTION
+ // or TP_ADDRESS) so that the cleanup routines can perform post-cleanup
+ // operations on the owning structure, such as dereferencing, etc.
+ //
+
+ ULONG Flags; // disposition of this request.
+ PVOID Context; // context of this request.
+ REQUEST_OWNER Owner; // what type of owner this request has.
+
+ KTIMER Timer; // kernel timer for this request.
+ KDPC Dpc; // DPC object for timeouts.
+
+} TP_REQUEST, *PTP_REQUEST;
+
+#define REQUEST_FLAGS_TIMER 0x0001 // a timer is active for this request.
+#define REQUEST_FLAGS_TIMED_OUT 0x0002 // a timer expiration occured on this request.
+#define REQUEST_FLAGS_ADDRESS 0x0004 // request is attached to a TP_ADDRESS.
+#define REQUEST_FLAGS_CONNECTION 0x0008 // request is attached to a TP_CONNECTION.
+#define REQUEST_FLAGS_STOPPING 0x0010 // request is being killed.
+#define REQUEST_FLAGS_EOR 0x0020 // TdiSend request has END_OF_RECORD mark.
+#define REQUEST_FLAGS_DC 0x0080 // request is attached to a TP_DEVICE_CONTEXT
+#define REQUEST_FLAGS_SEND_RCV 0x0100 // request is a TdiSend or TdiReceive
+#define REQUEST_FLAGS_DELAY 0x0200 // delay IoCompleteRequest until later
+
+//
+// This defines the TP_IRP_PARAMETERS, which is masked onto the
+// Parameters section of a send IRP's stack location.
+//
+
+typedef struct _TP_IRP_PARAMETERS {
+ TDI_REQUEST_KERNEL_SEND Request;
+ LONG ReferenceCount;
+ PVOID Connection;
+} TP_IRP_PARAMETERS, *PTP_IRP_PARAMETERS;
+
+#define IRP_SEND_LENGTH(_IrpSp) \
+ (((PTP_IRP_PARAMETERS)&(_IrpSp)->Parameters)->Request.SendLength)
+
+#define IRP_SEND_FLAGS(_IrpSp) \
+ (((PTP_IRP_PARAMETERS)&(_IrpSp)->Parameters)->Request.SendFlags)
+
+#define IRP_REFCOUNT(_IrpSp) \
+ (((PTP_IRP_PARAMETERS)&(_IrpSp)->Parameters)->ReferenceCount)
+
+#define IRP_CONNECTION(_IrpSp) \
+ (((PTP_IRP_PARAMETERS)&(_IrpSp)->Parameters)->Connection)
+
+#define IRP_DEVICE_CONTEXT(_IrpSp) \
+ ((PDEVICE_CONTEXT)((_IrpSp)->DeviceObject))
+
+
+//
+// This structure defines the packet object, used to represent a packet
+// in some portion of its lifetime. The PACKET.C module contains routines
+// to manage this object.
+//
+
+typedef struct _TP_PACKET {
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+ PNDIS_PACKET NdisPacket; // ptr to owning Ndis Packet
+ ULONG NdisIFrameLength; // Length of NdisPacket
+
+ LIST_ENTRY Linkage; // used to chain packets together.
+ BOOLEAN PacketSent; // packet completed by NDIS.
+ BOOLEAN PacketNoNdisBuffer; // chain on this packet was not allocated.
+ BOOLEAN CompleteSend; // last packet in send.
+ PVOID Provider; // The device context of this packet.
+
+ UCHAR Header[1]; // the headers
+
+} TP_PACKET, *PTP_PACKET;
+
+
+
+//
+// This structure defines a TP_CONNECTION, or active transport connection,
+// maintained on a transport address.
+//
+
+//
+// This structure holds our "complex send pointer" indicating
+// where we are in the packetization of a send.
+//
+
+typedef struct _TP_SEND_POINTER {
+ ULONG MessageBytesSent; // up count, bytes sent/this msg.
+ PIRP CurrentSendIrp; // ptr, current send request in chain.
+ PMDL CurrentSendMdl; // ptr, current MDL in send chain.
+ ULONG SendByteOffset; // current byte offset in current MDL.
+} TP_SEND_POINTER, *PTP_SEND_POINTER;
+
+typedef struct _TP_CONNECTION {
+
+ CSHORT Type;
+ USHORT Size;
+
+ LIST_ENTRY LinkList; // used for link thread or for free
+ // resource list
+ KSPIN_LOCK SpinLock; // spinlock for connection protection.
+
+ LONG ReferenceCount; // number of references to this object.
+ LONG SpecialRefCount; // controls freeing of connection.
+
+ //
+ // The following lists are used to associate this connection with a
+ // particular address.
+ //
+
+ LIST_ENTRY AddressList; // list of connections for given address
+ LIST_ENTRY AddressFileList; // list for connections bound to a
+ // given address reference
+
+ //
+ // The following field is used as linkage in the device context's
+ // PacketizeQueue
+ //
+
+ LIST_ENTRY PacketizeLinkage;
+
+ //
+ // The following field is used as linkage in the device context's
+ // PacketWaitQueue.
+ //
+
+ LIST_ENTRY PacketWaitLinkage;
+
+ //
+ // The following field points to the TP_LINK object that describes the
+ // (active) data link connection for this transport connection. To be
+ // valid, this field is non-NULL.
+ //
+
+ struct _TP_ADDRESS_FILE *AddressFile; // pointer to owning Address.
+ struct _DEVICE_CONTEXT *Provider; // device context to which we are attached.
+ PKSPIN_LOCK ProviderInterlock; // &Provider->Interlock
+ PFILE_OBJECT FileObject; // easy backlink to file object.
+
+ //
+ // The following field is specified by the user at connection open time.
+ // It is the context that the user associates with the connection so that
+ // indications to and from the client can be associated with a particular
+ // connection.
+ //
+
+ CONNECTION_CONTEXT Context; // client-specified value.
+
+ //
+ // The following two queues are used to associate TdiSend and TdiReceive
+ // requests with this connection. New arrivals are placed at the end of
+ // the queues (really a linked list) and requests are processed at the
+ // front of the queues. The first TdiSend request on the SendQueue is
+ // the current TdiSend being processed, and the first TdiReceive request
+ // on the ReceiveQueue is the first TdiReceive being processed, PROVIDED
+ // the CONNECTION_FLAGS_ACTIVE_RECEIVE flag is set. If this flag is not
+ // set, then the first TdiReceive request on the ReceiveQueue is not active.
+ // These queues are managed by the EXECUTIVE interlocked list manipuation
+ // routines. The actual objects that are on the queues are request control
+ // blocks (TP_REQUESTs).
+ //
+
+ LIST_ENTRY SendQueue; // FIFO of outstanding TdiSends.
+ LIST_ENTRY ReceiveQueue; // FIFO of outstanding TdiReceives.
+
+ //
+ // The following fields are used to maintain state for the current receive.
+ //
+
+ ULONG MessageBytesReceived; // up count, bytes recd/this msg.
+ ULONG MessageBytesAcked; // bytes acked (NR or RO) this msg.
+
+ //
+ // These fields are only valid if the CONNECTION_FLAGS_ACTIVE_RECEIVE
+ // flag is set.
+ //
+
+ PIRP SpecialReceiveIrp; // a "no-request" receive IRP exists.
+ PTP_REQUEST CurrentReceiveRequest; // ptr, current receive request.
+ PMDL CurrentReceiveMdl; // ptr, current MDL in receive chain.
+ ULONG ReceiveByteOffset; // current byte offset in current MDL.
+ ULONG ReceiveLength; // current receive length, in bytes (total)
+
+ //
+ // The following fields are used to maintain state for the active send.
+ // They only have meaning if the connection's SendState is not IDLE.
+ // Because the TDI client may submit multiple TdiSend requests to comprise
+ // a full message, we have to keep a complex pointer to the first byte of
+ // unACKed data (hence the first three fields). We also have a complex
+ // pointer to the first byte of unsent data (hence the last three fields).
+ //
+
+ ULONG SendState; // send state machine variable.
+
+ PIRP FirstSendIrp; // ptr, 1st TdiSend's IRP.
+ PMDL FirstSendMdl; // ptr, 1st unacked MDL in chain/this msg.
+ ULONG FirstSendByteOffset; // pre-acked bytes in that MDL.
+
+ TP_SEND_POINTER sp; // current send loc, defined above.
+ ULONG CurrentSendLength; // how long is this send (total)
+
+ //
+ // This field will be TRUE if we are in the middle of
+ // processing a receive indication on this connection and
+ // we are not yet in a state where another indication
+ // can be handled.
+ //
+
+ UINT IndicationInProgress;
+
+ //
+ // The following list head is used as a pointer to a TdiListen/TdiConnect
+ // request which is in progress. Although manipulated
+ // with queue instructions, there will only be one request in the queue.
+ // This is done for consistency with respect to TpCreateRequest, which
+ // does a great job of creating a request and associating it atomically
+ // with a supervisory object.
+ //
+
+ LIST_ENTRY InProgressRequest; // TdiListen/TdiConnect
+
+ //
+ // If the connection is being disconnected as a result of
+ // a TdiDisconnect call (RemoteDisconnect is FALSE) then this
+ // will hold the IRP passed to TdiDisconnect. It is needed
+ // when the TdiDisconnect request is completed.
+ //
+
+ PIRP DisconnectIrp;
+
+ //
+ // If the connection is being closed, this will hold
+ // the IRP passed to TdiCloseConnection. It is needed
+ // when the request is completed.
+ //
+
+ PIRP CloseIrp;
+
+ //
+ // The following fields are used for connection housekeeping.
+ //
+
+ ULONG Flags; // attributes of the connection.
+ ULONG Flags2; // more attributes of the connection.
+ NTSTATUS Status; // status code for connection rundown.
+ ST_NETBIOS_ADDRESS CalledAddress; // TdiConnect request's T.A.
+ USHORT MaximumDataSize; // maximum I-frame data size.
+
+ CHAR RemoteName[16];
+
+} TP_CONNECTION, *PTP_CONNECTION;
+
+
+#define CONNECTION_FLAGS_REMOTE_BUSY 0x00000002 // remote netbios reported NO RECEIVE.
+#define CONNECTION_FLAGS_VERSION2 0x00000004 // remote netbios is version 2.0.
+#define CONNECTION_FLAGS_RECEIVE_WAKEUP 0x00000008 // send a RECEIVE_OUTSTANDING when a receive arrives.
+#define CONNECTION_FLAGS_ACTIVE_RECEIVE 0x00000010 // a receive is active.
+#define CONNECTION_FLAGS_LISTENER 0x00000020 // we were the passive listener.
+#define CONNECTION_FLAGS_CONNECTOR 0x00000040 // we were the active connector.
+#define CONNECTION_FLAGS_WAIT_LISTEN 0x00001000 // waiting for listen.
+#define CONNECTION_FLAGS_DESTROY 0x00002000 // destroy this connection.
+#define CONNECTION_FLAGS_ABORT 0x00004000 // abort this connection.
+#define CONNECTION_FLAGS_ORDREL 0x00008000 // we're in orderly release.
+#define CONNECTION_FLAGS_STOPPING 0x00020000 // connection is running down.
+#define CONNECTION_FLAGS_READY 0x00040000 // sends/rcvs/discons valid.
+#define CONNECTION_FLAGS_SUSPENDED 0x00100000 // we're on the PacketWaitQueue.
+#define CONNECTION_FLAGS_PACKETIZE 0x00200000 // we're on the PacketizeQueue.
+#define CONNECTION_FLAGS_NO_INDICATE 0x40000000 // don't take packets at indication time
+#define CONNECTION_FLAGS_FAILING_TO_EOR 0x80000000 // wait for an EOF in an incoming request before sending
+
+#define CONNECTION_FLAGS2_CLOSING 0x00000002 // connection is closing
+#define CONNECTION_FLAGS2_ASSOCIATED 0x00000004 // associated with address
+#define CONNECTION_FLAGS2_DISCONNECT 0x00000008 // disconnect done on connection
+#define CONNECTION_FLAGS2_ACCEPTED 0x00000010 // accept done on connection
+#define CONNECTION_FLAGS2_INDICATING 0x00000020 // connection was manipulated while
+ // indication was in progress
+#define CONNECTION_FLAGS2_WAIT_ACCEPT 0x00000040 // the connection is waiting for
+ // and accept to send the
+ // session confirm
+#define CONNECTION_FLAGS2_REQ_COMPLETED 0x00000080 // Listen/Connect request completed.
+#define CONNECTION_FLAGS2_DISASSOCIATED 0x00000100 // associate CRef has been removed
+#define CONNECTION_FLAGS2_DISCONNECTED 0x00000200 // disconnect has been indicated
+#define CONNECTION_FLAGS2_REMOTE_VALID 0x00000800 // Connection->RemoteName is valid
+#define CONNECTION_FLAGS2_RCV_CANCELLED 0x00002000 // current receive was cancelled
+#define CONNECTION_FLAGS2_PRE_ACCEPT 0x00008000 // no TdiAccept after listen completes
+#define CONNECTION_FLAGS2_RC_PENDING 0x00010000 // a receive is pending completion
+#define CONNECTION_FLAGS2_PEND_INDICATE 0x00020000 // new data received during RC_PENDING
+
+
+#define CONNECTION_SENDSTATE_IDLE 0 // no sends being processed.
+#define CONNECTION_SENDSTATE_PACKETIZE 1 // send being packetized.
+#define CONNECTION_SENDSTATE_W_PACKET 2 // waiting for free packet.
+#define CONNECTION_SENDSTATE_W_LINK 3 // waiting for good link conditions.
+#define CONNECTION_SENDSTATE_W_EOR 4 // waiting for TdiSend(EOR).
+#define CONNECTION_SENDSTATE_W_ACK 5 // waiting for DATA_ACK.
+
+
+//
+// This structure is pointed to by the FsContext field in the FILE_OBJECT
+// for this Address. This structure is the base for all activities on
+// the open file object within the transport provider. All active connections
+// on the address point to this structure, although no queues exist here to do
+// work from. This structure also maintains a reference to a TP_ADDRESS
+// structure, which describes the address that it is bound to. Thus, a
+// connection will point to this structure, which describes the address the
+// connection was associated with. When the address file closes, all connections
+// opened on this address file get closed, too. Note that this may leave an
+// address hanging around, with other references.
+//
+
+typedef struct _TP_ADDRESS_FILE {
+
+ CSHORT Type;
+ CSHORT Size;
+
+ LIST_ENTRY Linkage; // next address file on this address.
+ // also used for linkage in the
+ // look-aside list
+
+ LONG ReferenceCount; // number of references to this object.
+
+ //
+ // This structure is edited after taking the Address spinlock for the
+ // owning address. This ensures that the address and this structure
+ // will never get out of syncronization with each other.
+ //
+
+ //
+ // The following field points to a list of TP_CONNECTION structures,
+ // one per connection open on this address. This list of connections
+ // is used to help the cleanup process if a process closes an address
+ // before disassociating all connections on it. By design, connections
+ // will stay around until they are explicitly
+ // closed; we use this database to ensure that we clean up properly.
+ //
+
+ LIST_ENTRY ConnectionDatabase; // list of defined transport connections.
+
+ //
+ // the current state of the address file structure; this is either open or
+ // closing
+ //
+
+ UCHAR State;
+
+ //
+ // The following fields are kept for housekeeping purposes.
+ //
+
+ PIRP Irp; // the irp used for open or close
+ struct _TP_ADDRESS *Address; // address to which we are bound.
+ PFILE_OBJECT FileObject; // easy backlink to file object.
+ struct _DEVICE_CONTEXT *Provider; // device context to which we are attached.
+
+ //
+ // The following queue is used to queue receive datagram requests
+ // on this address file. Send datagram requests are queued on the
+ // address itself. These queues are managed by the EXECUTIVE interlocked
+ // list management routines. The actual objects which get queued to this
+ // structure are request control blocks (RCBs).
+ //
+
+ LIST_ENTRY ReceiveDatagramQueue; // FIFO of outstanding TdiReceiveDatagrams.
+
+ //
+ // This holds the Irp used to close this address file,
+ // for pended completion.
+ //
+
+ PIRP CloseIrp;
+
+ //
+ // is this address file currently indicating a connection request? if yes, we
+ // need to mark connections that are manipulated during this time.
+ //
+
+ BOOLEAN ConnectIndicationInProgress;
+
+ //
+ // handler for kernel event actions. First we have a set of booleans that
+ // indicate whether or not this address has an event handler of the given
+ // type registered.
+ //
+
+ BOOLEAN RegisteredConnectionHandler;
+ BOOLEAN RegisteredDisconnectHandler;
+ BOOLEAN RegisteredReceiveHandler;
+ BOOLEAN RegisteredReceiveDatagramHandler;
+ BOOLEAN RegisteredExpeditedDataHandler;
+ BOOLEAN RegisteredErrorHandler;
+
+ //
+ // This function pointer points to a connection indication handler for this
+ // Address. Any time a connect request is received on the address, this
+ // routine is invoked.
+ //
+ //
+
+ PTDI_IND_CONNECT ConnectionHandler;
+ PVOID ConnectionHandlerContext;
+
+ //
+ // The following function pointer always points to a TDI_IND_DISCONNECT
+ // handler for the address. If the NULL handler is specified in a
+ // TdiSetEventHandler, this this points to an internal routine which
+ // simply returns successfully.
+ //
+
+ PTDI_IND_DISCONNECT DisconnectHandler;
+ PVOID DisconnectHandlerContext;
+
+ //
+ // The following function pointer always points to a TDI_IND_RECEIVE
+ // event handler for connections on this address. If the NULL handler
+ // is specified in a TdiSetEventHandler, then this points to an internal
+ // routine which does not accept the incoming data.
+ //
+
+ PTDI_IND_RECEIVE ReceiveHandler;
+ PVOID ReceiveHandlerContext;
+
+ //
+ // The following function pointer always points to a TDI_IND_RECEIVE_DATAGRAM
+ // event handler for the address. If the NULL handler is specified in a
+ // TdiSetEventHandler, this this points to an internal routine which does
+ // not accept the incoming data.
+ //
+
+ PTDI_IND_RECEIVE_DATAGRAM ReceiveDatagramHandler;
+ PVOID ReceiveDatagramHandlerContext;
+
+ //
+ // An expedited data handler. This handler is used if expedited data is
+ // expected; it never is in ST, thus this handler should always point to
+ // the default handler.
+ //
+
+ PTDI_IND_RECEIVE_EXPEDITED ExpeditedDataHandler;
+ PVOID ExpeditedDataHandlerContext;
+
+ //
+ // The following function pointer always points to a TDI_IND_ERROR
+ // handler for the address. If the NULL handler is specified in a
+ // TdiSetEventHandler, this this points to an internal routine which
+ // simply returns successfully.
+ //
+
+ PTDI_IND_ERROR ErrorHandler;
+ PVOID ErrorHandlerContext;
+ PVOID ErrorHandlerOwner;
+
+
+} TP_ADDRESS_FILE, *PTP_ADDRESS_FILE;
+
+#define ADDRESSFILE_STATE_OPENING 0x00 // not yet open for business
+#define ADDRESSFILE_STATE_OPEN 0x01 // open for business
+#define ADDRESSFILE_STATE_CLOSING 0x02 // closing
+
+
+//
+// This structure defines a TP_ADDRESS, or active transport address,
+// maintained by the transport provider. It contains all the visible
+// components of the address (such as the TSAP and network name components),
+// and it also contains other maintenance parts, such as a reference count,
+// ACL, and so on. All outstanding connection-oriented and connectionless
+// data transfer requests are queued here.
+//
+
+typedef struct _TP_ADDRESS {
+
+ USHORT Size;
+ CSHORT Type;
+
+ LIST_ENTRY Linkage; // next address/this device object.
+ LONG ReferenceCount; // number of references to this object.
+
+ //
+ // The following spin lock is acquired to edit this TP_ADDRESS structure
+ // or to scan down or edit the list of address files.
+ //
+
+ KSPIN_LOCK SpinLock; // lock to manipulate this structure.
+
+ //
+ // The following fields comprise the actual address itself.
+ //
+
+ PIRP Irp; // pointer to address creation IRP.
+ PST_NETBIOS_ADDRESS NetworkName; // this address
+
+ //
+ // The following fields are used to maintain state about this address.
+ //
+
+ ULONG Flags; // attributes of the address.
+ struct _DEVICE_CONTEXT *Provider; // device context to which we are attached.
+
+ //
+ // The following queues is used to hold send datagrams for this
+ // address. Receive datagrams are queued to the address file. Requests are
+ // processed in a first-in, first-out manner, so that the very next request
+ // to be serviced is always at the head of its respective queue. These
+ // queues are managed by the EXECUTIVE interlocked list management routines.
+ // The actual objects which get queued to this structure are request control
+ // blocks (RCBs).
+ //
+
+ LIST_ENTRY SendDatagramQueue; // FIFO of outstanding TdiSendDatagrams.
+
+ //
+ // The following field points to a list of TP_CONNECTION structures,
+ // one per active, connecting, or disconnecting connections on this
+ // address. By definition, if a connection is on this list, then
+ // it is visible to the client in terms of receiving events and being
+ // able to post requests by naming the ConnectionId. If the connection
+ // is not on this list, then it is not valid, and it is guaranteed that
+ // no indications to the client will be made with reference to it, and
+ // no requests specifying its ConnectionId will be accepted by the transport.
+ //
+
+ LIST_ENTRY ConnectionDatabase; // list of defined transport connections.
+ LIST_ENTRY AddressFileDatabase; // list of defined address file objects
+
+ //
+ // The following structure contains statistics counters for use
+ // by TdiQueryInformation and TdiSetInformation. They should not
+ // be used for maintenance of internal data structures.
+ //
+
+ PTP_PACKET Packet; // header for datagram sends.
+
+ //
+ // This structure is used for checking share access.
+ //
+
+ SHARE_ACCESS ShareAccess;
+
+ //
+ // This structure is used to hold ACLs on the address.
+ // WARNING: It is allocated from paged pool and can
+ // only be accessed at IRQL 0.
+ //
+
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+
+ //
+ // Used for delaying StDestroyAddress to a thread so
+ // we can access the security descriptor.
+ //
+
+ WORK_QUEUE_ITEM DestroyAddressQueueItem;
+
+} TP_ADDRESS, *PTP_ADDRESS;
+
+#define ADDRESS_FLAGS_GROUP 0x00000001 // set if group, otherwise unique.
+#define ADDRESS_FLAGS_CONFLICT 0x00000002 // address in conflict detected.
+#define ADDRESS_FLAGS_REGISTERING 0x00000004 // registration in progress.
+#define ADDRESS_FLAGS_DEREGISTERING 0x00000008 // deregistration in progress.
+#define ADDRESS_FLAGS_DUPLICATE_NAME 0x00000010 // duplicate name was found on net.
+#define ADDRESS_FLAGS_NEEDS_REG 0x00000020 // address must be registered.
+#define ADDRESS_FLAGS_STOPPING 0x00000040 // TpStopAddress is in progress.
+#define ADDRESS_FLAGS_BAD_ADDRESS 0x00000080 // name in conflict on associated address.
+#define ADDRESS_FLAGS_SEND_IN_PROGRESS 0x00000100 // send datagram process active.
+#define ADDRESS_FLAGS_CLOSED 0x00000200 // address has been closed;
+ // existing activity can
+ // complete, nothing new can start
+
+
+
+//
+// This structure defines the DEVICE_OBJECT and its extension allocated at
+// the time the transport provider creates its device object.
+//
+
+typedef struct _DEVICE_CONTEXT {
+
+ DEVICE_OBJECT DeviceObject; // the I/O system's device object.
+
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+ LIST_ENTRY Linkage; // links them on StDeviceList;
+
+ KSPIN_LOCK Interlock; // GLOBAL spinlock for reference count.
+ // (used in ExInterlockedXxx calls)
+ LONG ReferenceCount; // activity count/this provider.
+
+
+ //
+ // The queue of (currently receive only) IRPs waiting to complete.
+ //
+
+ LIST_ENTRY IrpCompletionQueue;
+
+ //
+ // Following are protected by Global Device Context SpinLock
+ //
+
+ KSPIN_LOCK SpinLock; // lock to manipulate this object.
+ // (used in KeAcquireSpinLock calls)
+
+ //
+ // the device context state, among open, closing
+ //
+
+ UCHAR State;
+
+
+ //
+ // The following queue holds free TP_ADDRESS objects available for allocation.
+ //
+
+ LIST_ENTRY AddressPool;
+
+ //
+ // These counters keep track of resources uses by TP_ADDRESS objects.
+ //
+
+ ULONG AddressAllocated;
+ ULONG AddressInitAllocated;
+ ULONG AddressMaxAllocated;
+ ULONG AddressInUse;
+ ULONG AddressMaxInUse;
+ ULONG AddressExhausted;
+ ULONG AddressTotal;
+ ULONG AddressSamples;
+
+
+ //
+ // The following queue holds free TP_ADDRESS_FILE objects available for allocation.
+ //
+
+ LIST_ENTRY AddressFilePool;
+
+ //
+ // These counters keep track of resources uses by TP_ADDRESS_FILE objects.
+ //
+
+ ULONG AddressFileAllocated;
+ ULONG AddressFileInitAllocated;
+ ULONG AddressFileMaxAllocated;
+ ULONG AddressFileInUse;
+ ULONG AddressFileMaxInUse;
+ ULONG AddressFileExhausted;
+ ULONG AddressFileTotal;
+ ULONG AddressFileSamples;
+
+
+ //
+ // The following queue holds free TP_CONNECTION objects available for allocation.
+ //
+
+ LIST_ENTRY ConnectionPool;
+
+ //
+ // These counters keep track of resources uses by TP_CONNECTION objects.
+ //
+
+ ULONG ConnectionAllocated;
+ ULONG ConnectionInitAllocated;
+ ULONG ConnectionMaxAllocated;
+ ULONG ConnectionInUse;
+ ULONG ConnectionMaxInUse;
+ ULONG ConnectionExhausted;
+ ULONG ConnectionTotal;
+ ULONG ConnectionSamples;
+
+
+ //
+ // The following is a free list of TP_REQUEST blocks which have been
+ // previously allocated and are available for use.
+ //
+
+ LIST_ENTRY RequestPool; // free request block pool.
+
+ //
+ // These counters keep track of resources uses by TP_REQUEST objects.
+ //
+
+ ULONG RequestAllocated;
+ ULONG RequestInitAllocated;
+ ULONG RequestMaxAllocated;
+ ULONG RequestInUse;
+ ULONG RequestMaxInUse;
+ ULONG RequestExhausted;
+ ULONG RequestTotal;
+ ULONG RequestSamples;
+
+
+ //
+ // The following queue holds I-frame Send packets managed by PACKET.C.
+ //
+
+ SINGLE_LIST_ENTRY PacketPool;
+
+ //
+ // These counters keep track of resources uses by TP_PACKET objects.
+ //
+
+ ULONG PacketLength;
+ ULONG PacketHeaderLength;
+ ULONG PacketAllocated;
+ ULONG PacketInitAllocated;
+ ULONG PacketExhausted;
+
+
+ //
+ // The following queue contains Receive packets
+ //
+
+ SINGLE_LIST_ENTRY ReceivePacketPool;
+
+ //
+ // These counters keep track of resources uses by NDIS_PACKET objects.
+ //
+
+ ULONG ReceivePacketAllocated;
+ ULONG ReceivePacketInitAllocated;
+ ULONG ReceivePacketExhausted;
+
+
+ //
+ // This queue contains pre-allocated receive buffers
+ //
+
+ SINGLE_LIST_ENTRY ReceiveBufferPool;
+
+ //
+ // These counters keep track of resources uses by TP_PACKET objects.
+ //
+
+ ULONG ReceiveBufferLength;
+ ULONG ReceiveBufferAllocated;
+ ULONG ReceiveBufferInitAllocated;
+ ULONG ReceiveBufferExhausted;
+
+
+ //
+ // This holds the total memory allocated for the above structures.
+ //
+
+ ULONG MemoryUsage;
+ ULONG MemoryLimit;
+
+
+ //
+ // The following field is a head of a list of TP_ADDRESS objects that
+ // are defined for this transport provider. To edit the list, you must
+ // hold the spinlock of the device context object.
+ //
+
+ LIST_ENTRY AddressDatabase; // list of defined transport addresses.
+
+ //
+ // The following queue holds connections which are waiting on available
+ // packets. As each new packet becomes available, a connection is removed
+ // from this queue and placed on the PacketizeQueue.
+ //
+
+ LIST_ENTRY PacketWaitQueue; // queue of packet-starved connections.
+ LIST_ENTRY PacketizeQueue; // queue of ready-to-packetize connections.
+
+ //
+ // This queue contains receives that are in progress
+ //
+
+ LIST_ENTRY ReceiveInProgress;
+
+ //
+ // NDIS fields
+ //
+
+ //
+ // following is used to keep adapter information.
+ //
+
+ NDIS_HANDLE NdisBindingHandle;
+
+ //
+ // The following fields are used for talking to NDIS. They keep information
+ // for the NDIS wrapper to use when determining what pool to use for
+ // allocating storage.
+ //
+
+ NDIS_HANDLE SendPacketPoolHandle;
+ NDIS_HANDLE ReceivePacketPoolHandle;
+ NDIS_HANDLE NdisBufferPoolHandle;
+ PVOID BufferPoolPointer;
+
+ //
+ // These are kept around for error logging, and stored right
+ // after this structure.
+ //
+
+ PWCHAR DeviceName;
+ ULONG DeviceNameLength;
+
+ //
+ // This is the Mac type we must build the packet header for and know the
+ // offsets for.
+ //
+
+ ST_NDIS_IDENTIFICATION MacInfo; // MAC type and other info
+ ULONG MaxReceivePacketSize; // does not include the MAC header
+ ULONG MaxSendPacketSize; // includes the MAC header
+
+ //
+ // some MAC addresses we use in the transport
+ //
+
+ HARDWARE_ADDRESS LocalAddress; // our local hardware address.
+ HARDWARE_ADDRESS MulticastAddress; // used as dest in all send
+
+ //
+ // The reserved Netbios address; consists of 10 zeroes
+ // followed by LocalAddress;
+ //
+
+ UCHAR ReservedNetBIOSAddress[NETBIOS_NAME_LENGTH];
+
+ //
+ // These are used while initializing the MAC driver.
+ //
+
+ KEVENT NdisRequestEvent; // used for pended requests.
+ NDIS_STATUS NdisRequestStatus; // records request status.
+
+ //
+ // This contains the next unique indentified to use as
+ // the FsContext in the file object associated with an
+ // open of the control channel.
+ //
+
+ USHORT ControlChannelIdentifier;
+
+ //
+ // This information is used to keep track of the speed of
+ // the underlying medium.
+ //
+
+ ULONG MediumSpeed; // in units of 100 bytes/sec
+
+
+ //
+ // Counters for most of the statistics that ST maintains;
+ // some of these are kept elsewhere.
+ //
+ // *** NOTE: THE ELEMENTS THAT FOLLOW MATCH THE ***
+ // *** TDI_PROVIDER_STATISTICS STRUCTURE EXACTLY, ***
+ // *** ALLOWING THEM TO BE COPIED EASILY. DO NOT ***
+ // *** CHANGE THEM UNLESS THAT STRUCTURE CHANGES. ***
+ //
+
+ //
+ // Basic connections counters.
+ //
+
+ ULONG OpenConnections;
+ ULONG ConnectionsAfterNoRetry;
+ ULONG ConnectionsAfterRetry;
+
+ //
+ // Counters of previous connections, by disconnect reason.
+ //
+
+ ULONG LocalDisconnects;
+ ULONG RemoteDisconnects;
+ ULONG LinkFailures;
+ ULONG AdapterFailures;
+ ULONG SessionTimeouts;
+ ULONG CancelledConnections;
+
+ //
+ // Keep track of why connect attempts failed.
+ //
+
+ ULONG RemoteResourceFailures;
+ ULONG LocalResourceFailures;
+ ULONG NotFoundFailures;
+ ULONG NoListenFailures; // where WE sent "no listen" response
+
+ //
+ // Counters for datagrams.
+ //
+
+ ULONG DatagramsSent;
+ LARGE_INTEGER DatagramBytesSent;
+ ULONG DatagramsReceived;
+ LARGE_INTEGER DatagramBytesReceived;
+
+ //
+ // Counters for NDIS packets.
+ //
+
+ ULONG PacketsSent;
+ ULONG PacketsReceived;
+
+ //
+ // Counters for data packets.
+ //
+
+ ULONG IFramesSent;
+ LARGE_INTEGER IFrameBytesSent;
+ ULONG IFramesReceived;
+ LARGE_INTEGER IFrameBytesReceived;
+ ULONG IFramesResent;
+ LARGE_INTEGER IFrameBytesResent;
+ ULONG IFramesRejected;
+ LARGE_INTEGER IFrameBytesRejected;
+
+
+ //
+ // LLC stats.
+ //
+
+ ULONG T1Expirations;
+ ULONG T2Expirations;
+ ULONG MaximumSendWindow;
+ ULONG AverageSendWindow;
+
+ //
+ // Netbios stats.
+ //
+
+ ULONG PiggybackAckQueued;
+ ULONG PiggybackAckTimeouts;
+
+ //
+ // Keeps track of "wasted" packet space.
+ //
+
+ LARGE_INTEGER WastedPacketSpace;
+ ULONG WastedSpacePackets;
+
+ //
+ // *** END OF SECTION THAT MATCHES TDI_PROVIDER_STATISTICS ***
+ //
+
+ //
+ // Counters for "active" time.
+ //
+
+ LARGE_INTEGER StStartTime;
+
+ //
+ // This resource guards access to the ShareAccess
+ // and SecurityDescriptor fields in addresses.
+ //
+
+ ERESOURCE AddressResource;
+
+ //
+ // The following structure contains statistics counters for use
+ // by TdiQueryInformation and TdiSetInformation. They should not
+ // be used for maintenance of internal data structures.
+ //
+
+ TDI_PROVIDER_INFO Information; // information about this provider.
+
+} DEVICE_CONTEXT, *PDEVICE_CONTEXT;
+
+//
+// device context state definitions
+//
+
+#define DEVICECONTEXT_STATE_CLOSED 0x00
+#define DEVICECONTEXT_STATE_OPEN 0x01
+#define DEVICECONTEXT_STATE_STOPPING 0x02
+
+
+
+//
+// Types used to hold information in the send and receive NDIS packets.
+// These are storied in the ProtocolReserved section of the packet.
+//
+
+typedef struct _SEND_PACKET_TAG {
+ USHORT Type; // identifier for packet type
+ PTP_PACKET Packet; // backpointer to owning TP_PACKET
+ PVOID Owner; // backpointer to owning structure
+} SEND_PACKET_TAG, *PSEND_PACKET_TAG;
+
+//
+// Packet types used in send completion
+//
+
+#define TYPE_I_FRAME 1 // information
+#define TYPE_G_FRAME 2 // datagram
+#define TYPE_C_FRAME 3 // connect
+#define TYPE_D_FRAME 4 // disconnect
+
+
+//
+// receive packet used to hold information about this receive
+//
+
+typedef struct _RECEIVE_PACKET_TAG {
+ LIST_ENTRY Linkage; // used for threading on receive queue
+ NDIS_STATUS NdisStatus; // completion status for send
+ PTP_CONNECTION Connection; // connection this receive is occuring on
+ UCHAR PacketType; // the type of packet we're processing
+ BOOLEAN AllocatedNdisBuffer; // did we allocate our own NDIS_BUFFERs
+ BOOLEAN EndOfMessage; // does this receive complete the message
+ BOOLEAN CompleteReceive; // complete the receive after TransferData?
+ BOOLEAN TransferDataPended; // TRUE if TransferData returned PENDING
+} RECEIVE_PACKET_TAG, *PRECEIVE_PACKET_TAG;
+
+#define TYPE_AT_INDICATE 1
+#define TYPE_AT_COMPLETE 2
+
+//
+// receive buffer descriptor (built in memory at the beginning of the buffer)
+//
+
+typedef struct _BUFFER_TAG {
+ SINGLE_LIST_ENTRY Linkage; // so we always know where it is
+ PTP_ADDRESS Address; // the address this datagram is for.
+ PNDIS_BUFFER NdisBuffer; // describes the rest of the buffer
+ ULONG Length; // the length of the buffer
+ UCHAR Buffer[1]; // the actual storage (accessed through the NDIS_BUFFER)
+} BUFFER_TAG, *PBUFFER_TAG;
+
+#endif // def _TYPES_
+
diff --git a/private/ntos/tdi/st/uframes.c b/private/ntos/tdi/st/uframes.c
new file mode 100644
index 000000000..c05f6eaa6
--- /dev/null
+++ b/private/ntos/tdi/st/uframes.c
@@ -0,0 +1,980 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ uframes.c
+
+Abstract:
+
+ This module contains a routine called StProcessConnectionless,
+ that gets control from routines in IND.C when a connectionless
+ frame is received.
+
+Environment:
+
+ Kernel mode, DISPATCH_LEVEL.
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+
+NTSTATUS
+StIndicateDatagram(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address,
+ IN PUCHAR Header,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an incoming DATAGRAM or DATAGRAM_BROADCAST frame.
+ BROADCAST and normal datagrams have the same receive logic, except
+ for broadcast datagrams Address will be the broadcast address.
+
+ When we return STATUS_MORE_PROCESSING_REQUIRED, the caller of
+ this routine will continue to call us for each address for the device
+ context. When we return STATUS_SUCCESS, the caller will switch to the
+ next address. When we return any other status code, including
+ STATUS_ABANDONED, the caller will stop distributing the frame.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ Address - Pointer to the transport address object.
+
+ StHeader - Pointer to a buffer that contains the receive datagram.
+ The first byte of information is the ST header.
+
+ Length - The length of the MDL pointed to by StHeader.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PLIST_ENTRY p, q;
+ PIRP irp;
+ PIO_STACK_LOCATION irpSp;
+ PTP_REQUEST Request;
+ ULONG IndicateBytesCopied, MdlBytesCopied;
+ KIRQL oldirql;
+ TA_NETBIOS_ADDRESS SourceName;
+ TA_NETBIOS_ADDRESS DestinationName;
+ PTDI_CONNECTION_INFORMATION remoteInformation;
+ ULONG returnLength;
+ PTP_ADDRESS_FILE addressFile, prevaddressFile;
+ PST_HEADER StHeader;
+
+ //
+ // If this datagram wasn't big enough for a transport header, then don't
+ // let the caller look at any data.
+ //
+
+ if (Length < sizeof(ST_HEADER)) {
+ return STATUS_ABANDONED;
+ }
+
+ //
+ // Update our statistics.
+ //
+
+ ++DeviceContext->DatagramsReceived;
+ ADD_TO_LARGE_INTEGER(
+ &DeviceContext->DatagramBytesReceived,
+ Length - sizeof(ST_HEADER));
+
+
+ //
+ // Call the client's ReceiveDatagram indication handler. He may
+ // want to accept the datagram that way.
+ //
+
+ StHeader = (PST_HEADER)Header;
+
+ TdiBuildNetbiosAddress (StHeader->Source, FALSE, &SourceName);
+ TdiBuildNetbiosAddress (StHeader->Destination, FALSE, &DestinationName);
+
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ //
+ // Find the first open address file in the list.
+ //
+
+ p = Address->AddressFileDatabase.Flink;
+ while (p != &Address->AddressFileDatabase) {
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+ if (addressFile->State != ADDRESSFILE_STATE_OPEN) {
+ p = p->Flink;
+ continue;
+ }
+ StReferenceAddressFile(addressFile);
+ break;
+ }
+
+ while (p != &Address->AddressFileDatabase) {
+
+ //
+ // do we have a datagram receive request outstanding? If so, we will
+ // satisfy it first.
+ //
+ // NOTE: We should check if this receive dataframs is for
+ // a specific address.
+ //
+
+ q = RemoveHeadList (&addressFile->ReceiveDatagramQueue);
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ if (q != &addressFile->ReceiveDatagramQueue) {
+
+ Request = CONTAINING_RECORD (q, TP_REQUEST, Linkage);
+
+ //
+ // Copy the actual user data.
+ //
+
+ MdlBytesCopied = 0;
+
+ status = TdiCopyBufferToMdl (
+ StHeader,
+ sizeof(ST_HEADER), // offset
+ Length - sizeof(ST_HEADER), // length
+ Request->IoRequestPacket->MdlAddress,
+ 0,
+ &MdlBytesCopied);
+
+ irpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket);
+ remoteInformation =
+ ((PTDI_REQUEST_KERNEL_RECEIVEDG)(&irpSp->Parameters))->
+ ReturnDatagramInformation;
+ if (remoteInformation != NULL) {
+ try {
+ if (remoteInformation->RemoteAddressLength != 0) {
+ if (remoteInformation->RemoteAddressLength >=
+ sizeof (TA_NETBIOS_ADDRESS)) {
+
+ RtlCopyMemory (
+ (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress,
+ &SourceName,
+ sizeof (TA_NETBIOS_ADDRESS));
+
+ returnLength = sizeof(TA_NETBIOS_ADDRESS);
+ remoteInformation->RemoteAddressLength = returnLength;
+
+ } else {
+
+ RtlCopyMemory (
+ (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress,
+ &SourceName,
+ remoteInformation->RemoteAddressLength);
+
+ returnLength = remoteInformation->RemoteAddressLength;
+ remoteInformation->RemoteAddressLength = returnLength;
+
+ }
+
+ } else {
+
+ returnLength = 0;
+ }
+
+ status = STATUS_SUCCESS;
+
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+
+ returnLength = 0;
+ status = GetExceptionCode ();
+
+ }
+
+ }
+
+ StCompleteRequest (Request, STATUS_SUCCESS, MdlBytesCopied);
+
+ } else {
+
+ //
+ // no receive datagram requests; is there a kernel client?
+ //
+
+ if (addressFile->RegisteredReceiveDatagramHandler) {
+
+ IndicateBytesCopied = 0;
+
+ //
+ // Note that we can always set the COPY_LOOKAHEAD
+ // flag because we are indicating from our own
+ // buffer, not directly from a lookahead indication.
+ //
+
+ status = (*addressFile->ReceiveDatagramHandler)(
+ addressFile->ReceiveDatagramHandlerContext,
+ sizeof (TA_NETBIOS_ADDRESS),
+ &SourceName,
+ 0,
+ NULL,
+ TDI_RECEIVE_COPY_LOOKAHEAD,
+ Length - sizeof(ST_HEADER), // indicated
+ Length - sizeof(ST_HEADER), // available
+ &IndicateBytesCopied,
+ Header + sizeof(ST_HEADER),
+ &irp);
+
+ if (status == STATUS_SUCCESS) {
+
+ //
+ // The client accepted the datagram and so we're done.
+ //
+
+ } else if (status == STATUS_DATA_NOT_ACCEPTED) {
+
+ //
+ // The client did not accept the datagram and we need to satisfy
+ // a TdiReceiveDatagram, if possible.
+ //
+
+ status = STATUS_MORE_PROCESSING_REQUIRED;
+
+ } else if (status == STATUS_MORE_PROCESSING_REQUIRED) {
+
+ //
+ // The client returned an IRP that we should queue up to the
+ // address to satisfy the request.
+ //
+
+ irp->IoStatus.Status = STATUS_PENDING; // init status information.
+ irp->IoStatus.Information = 0;
+ irpSp = IoGetCurrentIrpStackLocation (irp); // get current stack loctn.
+ if ((irpSp->MajorFunction != IRP_MJ_INTERNAL_DEVICE_CONTROL) ||
+ (irpSp->MinorFunction != TDI_RECEIVE_DATAGRAM)) {
+ irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+ return status;
+ }
+
+ //
+ // Now copy the actual user data.
+ //
+
+ MdlBytesCopied = 0;
+
+ status = TdiCopyBufferToMdl (
+ StHeader,
+ sizeof(ST_HEADER) + IndicateBytesCopied,
+ Length - sizeof(ST_HEADER) - IndicateBytesCopied,
+ irp->MdlAddress,
+ 0,
+ &MdlBytesCopied);
+
+ irp->IoStatus.Information = MdlBytesCopied;
+ irp->IoStatus.Status = status;
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+ }
+ }
+ }
+
+ //
+ // Save this to dereference it later.
+ //
+
+ prevaddressFile = addressFile;
+
+ //
+ // Reference the next address file on the list, so it
+ // stays around.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ p = p->Flink;
+ while (p != &Address->AddressFileDatabase) {
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+ if (addressFile->State != ADDRESSFILE_STATE_OPEN) {
+ p = p->Flink;
+ continue;
+ }
+ StReferenceAddressFile(addressFile);
+ break;
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ //
+ // Now dereference the previous address file with
+ // the lock released.
+ //
+
+ StDereferenceAddressFile (prevaddressFile);
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ } // end of while loop
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return status; // to dispatcher.
+} /* StIndicateDatagram */
+
+
+NTSTATUS
+StProcessConnect(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address,
+ IN PST_HEADER Header,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an incoming connect frame. It scans for
+ posted listens, otherwise it indicates to connect handlers
+ on this address if they are registered.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ Address - Pointer to the transport address object.
+
+ Header - Pointer to the ST header of the frame.
+
+ SourceAddress - Pointer to the source hardware address in the received
+ frame.
+
+ SourceRouting - Pointer to the source routing information in
+ the frame.
+
+ SourceRoutingLength - Length of the source routing information.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1, cancelirql;
+ NTSTATUS status;
+ PTP_CONNECTION Connection;
+ BOOLEAN ConnectIndicationBlocked = FALSE;
+ PLIST_ENTRY p;
+ BOOLEAN UsedListeningConnection = FALSE;
+ PTP_ADDRESS_FILE addressFile, prevaddressFile;
+
+ PTP_REQUEST request;
+ PIO_STACK_LOCATION irpSp;
+ ULONG returnLength;
+ PTDI_CONNECTION_INFORMATION remoteInformation;
+ TA_NETBIOS_ADDRESS TempAddress;
+ PIRP acceptIrp;
+
+ CONNECTION_CONTEXT connectionContext;
+
+ //
+ // If we are just registering or deregistering this address, then don't
+ // allow state changes. Just throw the packet away, and let the frame
+ // distributor try the next address.
+ //
+
+ if (Address->Flags & (ADDRESS_FLAGS_REGISTERING | ADDRESS_FLAGS_DEREGISTERING)) {
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // This is an incoming connection request. If we have a listening
+ // connection on this address, then continue with the connection setup.
+ // If there is no outstanding listen, then indicate any kernel mode
+ // clients that want to know about this frame. If a listen was posted,
+ // then a connection has already been set up for it.
+ //
+
+ //
+ // First, check if we already have an active connection with
+ // this remote on this address. If so, we ignore this
+ // (NOTE: This is not the correct behaviour for a real
+ // transport).
+ //
+
+ //
+ // If successful this adds a reference.
+ //
+
+ if (Connection = StLookupRemoteName(Address, Header->Source)) {
+
+ StDereferenceConnection ("Lookup done", Connection);
+ return STATUS_ABANDONED;
+
+ }
+
+ // If successful, this adds a reference which is removed before
+ // this function returns.
+
+ Connection = StLookupListeningConnection (Address);
+ if (Connection == NULL) {
+
+ //
+ // not having a listening connection is not reason to bail out here.
+ // we need to indicate to the user that a connect attempt occurred,
+ // and see if there is a desire to use this connection. We
+ // indicate in order to all address files that are
+ // using this address.
+ //
+ // If we already have an indication pending on this address,
+ // we ignore this frame (the NAME_QUERY may have come from
+ // a different address, but we can't know that). Also, if
+ // there is already an active connection on this remote
+ // name, then we ignore the frame.
+ //
+
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ p = Address->AddressFileDatabase.Flink;
+ while (p != &Address->AddressFileDatabase) {
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+ if (addressFile->State != ADDRESSFILE_STATE_OPEN) {
+ p = p->Flink;
+ continue;
+ }
+ StReferenceAddressFile(addressFile);
+ break;
+ }
+
+ while (p != &Address->AddressFileDatabase) {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ if ((addressFile->RegisteredConnectionHandler == TRUE) &&
+ (!addressFile->ConnectIndicationInProgress)) {
+
+
+ TdiBuildNetbiosAddress (
+ Header->Source,
+ FALSE,
+ &TempAddress);
+
+ addressFile->ConnectIndicationInProgress = TRUE;
+
+ //
+ // we have a connection handler, now indicate that a connection
+ // attempt occurred.
+ //
+
+ status = (addressFile->ConnectionHandler)(
+ addressFile->ConnectionHandlerContext,
+ sizeof (TDI_ADDRESS_NETBIOS),
+ &TempAddress,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ &connectionContext,
+ &acceptIrp);
+
+ if (status == STATUS_MORE_PROCESSING_REQUIRED) {
+
+ // the user has connected a currently open connection, but
+ // we have to figure out which one it is.
+ //
+
+ //
+ // If successful this adds a reference of type LISTENING
+ // (the same what StLookupListeningConnection adds).
+ //
+
+ Connection = StLookupConnectionByContext (
+ Address,
+ connectionContext);
+
+ if (Connection == NULL) {
+
+ //
+ // BUGBUG: We have to tell the client that
+ // his connection is bogus (or has this
+ // already happened??).
+ //
+
+ StPrint0("MORE_PROCESSING_REQUIRED, connection not found\n");
+ addressFile->ConnectIndicationInProgress = FALSE;
+ acceptIrp->IoStatus.Status = STATUS_INVALID_CONNECTION;
+ IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT);
+
+ goto whileend; // try next address file
+
+ } else {
+
+ if (Connection->AddressFile->Address != Address) {
+ addressFile->ConnectIndicationInProgress = FALSE;
+
+ StPrint0("MORE_PROCESSING_REQUIRED, address wrong\n");
+ StStopConnection (Connection, STATUS_INVALID_ADDRESS);
+ StDereferenceConnection("Bad Address", Connection);
+ Connection = NULL;
+ acceptIrp->IoStatus.Status = STATUS_INVALID_CONNECTION;
+ IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT);
+
+ goto whileend; // try next address file
+ }
+
+ //
+ // OK, we have a valid connection. If the response to
+ // this connection was disconnect, we need to reject
+ // the connection request and return. If it was accept
+ // or not specified (to be done later), we simply
+ // fall through and continue processing on the U Frame.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_DISCONNECT) != 0) {
+
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_DISCONNECT;
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+ StPrint0("MORE_PROCESSING_REQUIRED, disconnect\n");
+ addressFile->ConnectIndicationInProgress = FALSE;
+ StDereferenceConnection("Disconnecting", Connection);
+ Connection = NULL;
+ acceptIrp->IoStatus.Status = STATUS_INVALID_CONNECTION;
+ IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT);
+
+ goto whileend; // try next address file
+ }
+
+ }
+
+ //
+ // This connection is ready.
+ //
+
+ Connection->Flags &= ~CONNECTION_FLAGS_STOPPING;
+ Connection->Status = STATUS_PENDING;
+ Connection->Flags2 |= CONNECTION_FLAGS2_ACCEPTED;
+
+ Connection->Flags |= CONNECTION_FLAGS_READY;
+ INCREMENT_COUNTER (Connection->Provider, OpenConnections);
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+
+ StReferenceConnection("Indication completed", Connection);
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+
+ //
+ // Make a note that we have to set
+ // addressFile->ConnectIndicationInProgress to
+ // FALSE once the address is safely stored
+ // in the connection.
+ //
+
+ ConnectIndicationBlocked = TRUE;
+ StDereferenceAddressFile (addressFile);
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ break; // exit the while
+
+ } else if (status == STATUS_INSUFFICIENT_RESOURCES) {
+
+ //
+ // we know the address, but can't create a connection to
+ // use on it. This gets passed to the network as a response
+ // saying I'm here, but can't help.
+ //
+
+ addressFile->ConnectIndicationInProgress = FALSE;
+
+ StDereferenceAddressFile (addressFile);
+ return STATUS_ABANDONED;
+
+ } else {
+
+ addressFile->ConnectIndicationInProgress = FALSE;
+ goto whileend; // try next address file
+
+ } // end status ifs
+
+ } else {
+
+ goto whileend; // try next address file
+
+ } // end no indication handler
+
+whileend:
+ //
+ // Jumping here is like a continue, except that the
+ // addressFile pointer is advanced correctly.
+ //
+
+ //
+ // Save this to dereference it later.
+ //
+
+ prevaddressFile = addressFile;
+
+ //
+ // Reference the next address file on the list, so it
+ // stays around.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ p = p->Flink;
+ while (p != &Address->AddressFileDatabase) {
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+ if (addressFile->State != ADDRESSFILE_STATE_OPEN) {
+ p = p->Flink;
+ continue;
+ }
+ StReferenceAddressFile(addressFile);
+ break;
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ //
+ // Now dereference the previous address file with
+ // the lock released.
+ //
+
+ StDereferenceAddressFile (prevaddressFile);
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ } // end of loop through the address files.
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ if (Connection == NULL) {
+
+ //
+ // We used to return MORE_PROCESSING_REQUIRED, but
+ // since we matched with this address, no other
+ // address is going to match, so abandon it.
+ //
+
+ return STATUS_ABANDONED;
+
+ }
+
+ } else { // end connection == null
+
+ UsedListeningConnection = TRUE;
+
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ p = RemoveHeadList (&Connection->InProgressRequest);
+ if (p == &Connection->InProgressRequest) {
+
+ Connection->IndicationInProgress = FALSE;
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock (cancelirql);
+ return STATUS_SUCCESS;
+
+ }
+
+ //
+ // If this listen indicated that we should wait for a
+ // TdiAccept, then do that, otherwise the connection is
+ // ready.
+ //
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_PRE_ACCEPT) == 0) {
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_WAIT_ACCEPT;
+
+ } else {
+
+ Connection->Flags |= CONNECTION_FLAGS_READY;
+ INCREMENT_COUNTER (Connection->Provider, OpenConnections);
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+
+ StReferenceConnection("Listen completed", Connection);
+
+ }
+
+ //
+ // We have a completed connection with a queued listen. Complete
+ // the listen and let the user do an accept at some time down the
+ // road.
+ //
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL;
+ IoReleaseCancelSpinLock (cancelirql);
+
+ irpSp = IoGetCurrentIrpStackLocation (request->IoRequestPacket);
+ remoteInformation =
+ ((PTDI_REQUEST_KERNEL)(&irpSp->Parameters))->ReturnConnectionInformation;
+ if (remoteInformation != NULL) {
+ try {
+ if (remoteInformation->RemoteAddressLength != 0) {
+
+ //
+ // Build a temporary TA_NETBIOS_ADDRESS, then
+ // copy over as many bytes as fit.
+ //
+
+ TdiBuildNetbiosAddress(
+ Connection->CalledAddress.NetbiosName,
+ (BOOLEAN)(Connection->CalledAddress.NetbiosNameType ==
+ TDI_ADDRESS_NETBIOS_TYPE_GROUP),
+ &TempAddress);
+
+ if (remoteInformation->RemoteAddressLength >=
+ sizeof (TA_NETBIOS_ADDRESS)) {
+
+ returnLength = sizeof(TA_NETBIOS_ADDRESS);
+ remoteInformation->RemoteAddressLength = returnLength;
+
+ } else {
+
+ returnLength = remoteInformation->RemoteAddressLength;
+
+ }
+
+ RtlCopyMemory(
+ (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress,
+ &TempAddress,
+ returnLength);
+
+ } else {
+
+ returnLength = 0;
+ }
+
+ status = STATUS_SUCCESS;
+
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+
+ returnLength = 0;
+ status = GetExceptionCode ();
+
+ }
+
+ } else {
+
+ status = STATUS_SUCCESS;
+ returnLength = 0;
+
+ }
+
+ //
+ // Don't clear this until now, so that the connection is all
+ // set up before we allow more indications.
+ //
+
+ Connection->IndicationInProgress = FALSE;
+
+ StCompleteRequest (request, status, 0);
+
+ }
+
+
+ //
+ // Before we continue, store the remote guy's transport address
+ // into the TdiListen's TRANSPORT_CONNECTION buffer. This allows
+ // the client to determine who called him.
+ //
+
+ Connection->CalledAddress.NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ NdisMoveFromMappedMemory(
+ Connection->CalledAddress.NetbiosName,
+ Header->Source,
+ 16);
+
+ NdisMoveFromMappedMemory(
+ Connection->RemoteName,
+ Header->Source,
+ 16);
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_REMOTE_VALID;
+
+ if (ConnectIndicationBlocked) {
+ addressFile->ConnectIndicationInProgress = FALSE;
+ }
+
+ StDereferenceConnection("ProcessNameQuery done", Connection);
+
+ return STATUS_ABANDONED;
+
+} /* StProcessConnect */
+
+
+NTSTATUS
+StProcessConnectionless(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PST_HEADER StHeader,
+ IN ULONG StLength,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ OUT PTP_ADDRESS * DatagramAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the data link provider as an
+ indication that a connectionless frame has been received on the data link.
+ Here we dispatch to the correct handler.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ SourceAddress - Pointer to the source hardware address in the received
+ frame.
+
+ StHeader - Points to the ST header of the incoming packet.
+
+ StLength - Actual length in bytes of the packet, starting at the
+ StHeader.
+
+ SourceRouting - Source routing information in the MAC header.
+
+ SourceRoutingLength - The length of SourceRouting.
+
+ DatagramAddress - If this function returns STATUS_MORE_PROCESSING_
+ REQUIRED, this will be the address the datagram should be
+ indicated to.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_ADDRESS Address;
+ KIRQL oldirql;
+ NTSTATUS status;
+ PLIST_ENTRY Flink;
+ BOOLEAN MatchedAddress;
+ PUCHAR MatchName;
+
+ //
+ // Verify that this frame is long enough to examine.
+ //
+
+ if (StLength < sizeof(ST_HEADER)) {
+ return STATUS_ABANDONED; // frame too small.
+ }
+
+ //
+ // We have a valid connectionless protocol frame that's not a
+ // datagram, so deliver it to every address which matches the
+ // destination name in the frame.
+ //
+
+ MatchedAddress = FALSE;
+
+ //
+ // Search for the address; for broadcast datagrams we
+ // search for the special "broadcast" address.
+ //
+
+ if ((StHeader->Command == ST_CMD_DATAGRAM) &&
+ (StHeader->Flags & ST_FLAGS_BROADCAST)) {
+
+ MatchName = NULL;
+
+ } else {
+
+ MatchName = StHeader->Destination;
+
+ }
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ for (Flink = DeviceContext->AddressDatabase.Flink;
+ Flink != &DeviceContext->AddressDatabase;
+ Flink = Flink->Flink) {
+
+ Address = CONTAINING_RECORD (
+ Flink,
+ TP_ADDRESS,
+ Linkage);
+
+ if ((Address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ continue;
+ }
+
+ if (StMatchNetbiosAddress (Address, MatchName)) {
+
+ StReferenceAddress ("UI Frame", Address); // prevent address from being destroyed.
+ MatchedAddress = TRUE;
+ break;
+
+ }
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ if (MatchedAddress) {
+
+ //
+ // Deliver the frame to the current address.
+ //
+
+ switch (StHeader->Command) {
+
+ case ST_CMD_CONNECT:
+
+ status = StProcessConnect (
+ DeviceContext,
+ Address,
+ StHeader,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+
+ break;
+
+ case ST_CMD_DATAGRAM:
+
+ //
+ // Reference the datagram so it sticks around until the
+ // ReceiveComplete, when it is processed.
+ //
+
+ StReferenceAddress ("Datagram indicated", Address);
+ *DatagramAddress = Address;
+ status = STATUS_MORE_PROCESSING_REQUIRED;
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+
+ } /* switch on frame command code */
+
+ StDereferenceAddress ("Done", Address); // done with previous address.
+
+ } else {
+
+ status = STATUS_ABANDONED;
+
+ }
+
+ return status;
+
+} /* StProcessConnectionless */
+
diff --git a/private/ntos/tdi/tcpip/dirs b/private/ntos/tdi/tcpip/dirs
new file mode 100644
index 000000000..1ada6a1e5
--- /dev/null
+++ b/private/ntos/tdi/tcpip/dirs
@@ -0,0 +1,28 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS= \
+ ip \
+ tcp
+
+OPTIONAL_DIRS=
+
diff --git a/private/ntos/tdi/tcpip/h/oscfg.h b/private/ntos/tdi/tcpip/h/oscfg.h
new file mode 100644
index 000000000..5544d5b40
--- /dev/null
+++ b/private/ntos/tdi/tcpip/h/oscfg.h
@@ -0,0 +1,72 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1992 **/
+/********************************************************************/
+/* :ts=4 */
+
+#ifndef OSCFG_INCLUDED
+#define OSCFG_INCLUDED
+
+
+#define net_short(x) ((((x)&0xff) << 8) | (((x)&0xff00) >> 8))
+
+//#define net_long(x) (((net_short((x)&0xffff)) << 16) | net_short((((x)&0xffff0000L)>>16)))
+#define net_long(x) (((((ulong)(x))&0xffL)<<24) | \
+ ((((ulong)(x))&0xff00L)<<8) | \
+ ((((ulong)(x))&0xff0000L)>>8) | \
+ ((((ulong)(x))&0xff000000L)>>24))
+
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+
+
+#ifdef VXD
+/////////////////////////////////////////////////////////////////////////////
+//
+// VXD definitions
+//
+////////////////////////////////////////////////////////////////////////////
+
+#include <stddef.h>
+
+#pragma code_seg("_LTEXT", "LCODE")
+#pragma data_seg("_LDATA", "LCODE")
+
+//* pragma bodies for bracketing of initialization code.
+
+#define BEGIN_INIT code_seg("_ITEXT", "ICODE")
+#define BEGIN_INIT_DATA data_seg("_IDATA", "ICODE")
+#define END_INIT code_seg()
+#define END_INIT_DATA data_seg()
+
+#else // VXD
+#ifdef NT
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// NT definitions
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#include <ntos.h>
+#include <zwapi.h>
+
+#define BEGIN_INIT
+#define END_INIT
+
+#else // NT
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Definitions for additional environments go here
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#error Environment specific definitions missing
+
+#endif // NT
+
+#endif // VXD
+
+
+#endif // OSCFG_INCLUDED
diff --git a/private/ntos/tdi/tcpip/h/packoff.h b/private/ntos/tdi/tcpip/h/packoff.h
new file mode 100644
index 000000000..c47cd038f
--- /dev/null
+++ b/private/ntos/tdi/tcpip/h/packoff.h
@@ -0,0 +1,37 @@
+/*++
+
+Copyright (c) 1990,91 Microsoft Corporation
+
+Module Name:
+
+ packoff.h
+
+Abstract:
+
+ This file turns packing of structures off. (That is, it enables
+ automatic alignment of structure fields.) An include file is needed
+ because various compilers do this in different ways.
+
+ packoff.h is the complement to packon.h. An inclusion of packoff.h
+ MUST ALWAYS be preceded by an inclusion of packon.h, in one-to-one
+ correspondence.
+
+Author:
+
+ Chuck Lenzmeier (chuckl) 4-Mar-1990
+
+Revision History:
+
+ 15-Apr-1991 JohnRo
+ Created lint-able variant.
+--*/
+
+#if ! (defined(lint) || defined(_lint))
+
+#ifndef VXD
+#if i386
+#pragma warning(disable:4103)
+#endif
+#endif
+#pragma pack() // x86, MS compiler; MIPS, MIPS compiler
+#endif // ! (defined(lint) || defined(_lint))
diff --git a/private/ntos/tdi/tcpip/h/packon.h b/private/ntos/tdi/tcpip/h/packon.h
new file mode 100644
index 000000000..f2c73cb85
--- /dev/null
+++ b/private/ntos/tdi/tcpip/h/packon.h
@@ -0,0 +1,35 @@
+/*++
+
+Copyright (c) 1990,91 Microsoft Corporation
+
+Module Name:
+
+ packon.h
+
+Abstract:
+
+ This file turns packing of structures on. (That is, it disables
+ automatic alignment of structure fields.) An include file is needed
+ because various compilers do this in different ways.
+
+ The file packoff.h is the complement to this file.
+
+Author:
+
+ Chuck Lenzmeier (chuckl) 4-Mar-1990
+
+Revision History:
+
+ 15-Apr-1991 JohnRo
+ Created lint-able variant.
+--*/
+
+#if ! (defined(lint) || defined(_lint))
+
+#ifndef VXD
+#if i386
+#pragma warning(disable:4103)
+#endif
+#endif
+#pragma pack(1) // x86, MS compiler; MIPS, MIPS compiler
+#endif // ! (defined(lint) || defined(_lint))
diff --git a/private/ntos/tdi/tcpip/h/queue.h b/private/ntos/tdi/tcpip/h/queue.h
new file mode 100644
index 000000000..f1e23d682
--- /dev/null
+++ b/private/ntos/tdi/tcpip/h/queue.h
@@ -0,0 +1,87 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** QUEUE.H - TCP/UDP queuing definitons.
+//
+// This file contains the definitions for the queue functions used
+// by the TCP/UDP code.
+//
+
+//* Definition of a queue linkage field.
+struct Queue {
+ struct Queue *q_next;
+ struct Queue *q_prev;
+}; /* Queue */
+
+typedef struct Queue Queue;
+
+//* Initialize queue macro.
+
+#define INITQ(q) { (q)->q_next = (q);\
+ (q)->q_prev = (q); }
+
+//* Macro to check for queue empty.
+#define EMPTYQ(q) ((q)->q_next == (q))
+
+//* Place an element onto the end of the queue.
+
+#define ENQUEUE(q, e) { (q)->q_prev->q_next = (e);\
+ (e)->q_prev = (q)->q_prev;\
+ (q)->q_prev = (e);\
+ (e)->q_next = (q); }
+
+//* Remove an element from the head of the queue. This macro assumes the queue
+// is not empty. The element is returned as type t, queued through linkage
+// l.
+
+#define DEQUEUE(q, ptr, t, l) {\
+ Queue *__tmp__;\
+ \
+ __tmp__ = (q)->q_next;\
+ (q)->q_next = __tmp__->q_next;\
+ __tmp__->q_next->q_prev = (q);\
+ (ptr) = STRUCT_OF(t, __tmp__, l);\
+ }
+
+//* Peek at an element at the head of the queue. We return a pointer to it
+// without removing anything.
+
+#define PEEKQ(q, ptr, t, l) {\
+ Queue *__tmp__;\
+ \
+ __tmp__ = (q)->q_next;\
+ (ptr) = STRUCT_OF(t, __tmp__, l);\
+ }
+
+//* Macro to push an element onto the head of a queue.
+
+#define PUSHQ(q, e) { (e)->q_next = (q)->q_next;\
+ (q)->q_next->q_prev = (e);\
+ (e)->q_prev = (q);\
+ (q)->q_next = e; }
+
+//* Macro to remove an element from the middle of a queue.
+#define REMOVEQ(q) { (q)->q_next->q_prev = (q)->q_prev;\
+ (q)->q_prev->q_next = (q)->q_next; }
+
+//** The following macros define methods for working with queue without
+// dequeueing, mostly dealing with Queue structures directly.
+
+//* Macro to define the end of a Q, used in walking a queue sequentially.
+#define QEND(q) (q)
+
+//* Macro to get the first on a queue.
+#define QHEAD(q) (q)->q_next
+
+//* Macro to get a structure, given a queue.
+
+#define QSTRUCT(t, q, l) STRUCT_OF(t, (q), l)
+
+//* Macro to get the next thing on q queue.
+
+#define QNEXT(q) (q)->q_next
+
+
diff --git a/private/ntos/tdi/tcpip/h/tdint.h b/private/ntos/tdi/tcpip/h/tdint.h
new file mode 100644
index 000000000..852f29c2a
--- /dev/null
+++ b/private/ntos/tdi/tcpip/h/tdint.h
@@ -0,0 +1,41 @@
+/*++ BUILD Version: 0001 // Increment this if a change has global effects
+
+Copyright (c) 1991-1993 Microsoft Corporation
+
+Module Name:
+
+ tdint.h
+
+Abstract:
+
+ This file defines TDI types specific to the NT environment.
+
+Author:
+
+ Mike Massa (mikemas) August 13, 1993
+
+Revision History:
+
+--*/
+
+#ifndef _TDINT_
+#define _TDINT_
+
+#include <tdikrnl.h>
+
+typedef PTDI_IND_CONNECT PConnectEvent;
+typedef PTDI_IND_DISCONNECT PDisconnectEvent;
+typedef PTDI_IND_ERROR PErrorEvent;
+typedef PTDI_IND_RECEIVE PRcvEvent;
+typedef PTDI_IND_RECEIVE_DATAGRAM PRcvDGEvent;
+typedef PTDI_IND_RECEIVE_EXPEDITED PRcvExpEvent;
+
+typedef IRP EventRcvBuffer;
+typedef IRP ConnectEventInfo;
+
+//
+// BUGBUG: What about SEND_POSSIBLE????
+//
+
+#endif // ifndef _TDINT_
+
diff --git a/private/ntos/tdi/tcpip/ip/arp.c b/private/ntos/tdi/tcpip/ip/arp.c
new file mode 100644
index 000000000..3c8253566
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/arp.c
@@ -0,0 +1,4839 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1992 **/
+/********************************************************************/
+/* :ts=4 */
+
+//*** arp.c - ARP VxD routines.
+//
+// This file containes all of the ARP related routines, including
+// table lookup, registration, etc.
+//
+// ARP is architected to support multiple protocols, but for now
+// it in only implemented to take one protocol (IP). This is done
+// for simplicity and ease of implementation. In the future we may
+// split ARP out into a seperate driver.
+
+#include "oscfg.h"
+#ifdef VXD
+#include <string.h>
+#endif
+#include "ndis.h"
+#include "cxport.h"
+#include "ip.h"
+#include "ipdef.h"
+#include "llipif.h"
+#include "arp.h"
+#include "arpdef.h"
+#include "tdiinfo.h"
+#include "ipinfo.h"
+#include "llinfo.h"
+#include "tdistat.h"
+#include "iproute.h"
+#include "iprtdef.h"
+#include "arpinfo.h"
+#include "ipinit.h"
+
+#ifndef CHICAGO
+#ifndef _PNP_POWER
+#define NDIS_MAJOR_VERSION 0x03
+#define NDIS_MINOR_VERSION 0
+#else
+#define NDIS_MAJOR_VERSION 0x04
+#define NDIS_MINOR_VERSION 0
+#endif
+#endif
+
+#ifndef NDIS_API
+#define NDIS_API
+#endif
+
+
+static ulong ARPLookahead = LOOKAHEAD_SIZE;
+
+static uchar ENetBcst[] = "\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x08\x06";
+static uchar TRBcst[] = "\x10\x40\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x82\x70";
+static uchar FDDIBcst[] = "\x57\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00";
+static uchar ARCBcst[] = "\x00\x00\xd5";
+
+static uchar ENetMcst[] = "\x01\x00\x5E\x00\x00\x00";
+static uchar FDDIMcst[] = "\x57\x01\x00\x5E\x00\x00\x00";
+static uchar ARPSNAP[] = "\xAA\xAA\x03\x00\x00\x00\x08\x06";
+
+#ifdef NT
+static WCHAR ARPName[] = TCP_NAME;
+#else // NT
+static uchar ARPName[] = TCP_NAME;
+#endif // NT
+
+NDIS_HANDLE ARPHandle; // Our NDIS protocol handle.
+
+uint ArpCacheLife;
+uint sArpAlwaysSourceRoute; // True if we always send ARP requests
+ // with source route info on token ring.
+uint sIPAlwaysSourceRoute;
+extern uchar TrRii;
+
+extern PDRIVER_OBJECT IPDriverObject;
+
+extern void IPRcv(void *, void *, uint, uint, NDIS_HANDLE, uint, uint);
+extern void IPTDComplete(void *, PNDIS_PACKET, NDIS_STATUS, uint);
+extern void IPSendComplete(void *, PNDIS_PACKET, NDIS_STATUS);
+extern void IPStatus(void *, NDIS_STATUS, void *, uint);
+extern void IPRcvComplete(void);
+extern PNDIS_BUFFER CopyToNdis(PNDIS_BUFFER DestBuf, uchar *SrcBuf, uint Size,
+ uint *StartOffset);
+
+extern void NDIS_API ARPSendComplete(NDIS_HANDLE, PNDIS_PACKET, NDIS_STATUS);
+extern void IPULUnloadNotify(void);
+
+#ifdef _PNP_POWER
+extern IP_STATUS IPAddInterface(PNDIS_STRING ConfigName, void *PNP,
+ void *Context, LLIPRegRtn RegRtn, LLIPBindInfo *BindInfo);
+extern void IPDelInterface(void *Context);
+
+extern void NotifyOfUnload(void);
+
+
+extern uint OpenIFConfig(PNDIS_STRING ConfigName, NDIS_HANDLE *Handle);
+extern int IsLLInterfaceValueNull (NDIS_HANDLE Handle) ;
+extern void CloseIFConfig(NDIS_HANDLE Handle);
+
+#endif
+
+
+// Tables for bitswapping.
+
+uchar SwapTableLo[] = {
+ 0, // 0
+ 0x08, // 1
+ 0x04, // 2
+ 0x0c, // 3
+ 0x02, // 4
+ 0x0a, // 5,
+ 0x06, // 6,
+ 0x0e, // 7,
+ 0x01, // 8,
+ 0x09, // 9,
+ 0x05, // 10,
+ 0x0d, // 11,
+ 0x03, // 12,
+ 0x0b, // 13,
+ 0x07, // 14,
+ 0x0f // 15
+};
+
+uchar SwapTableHi[] = {
+ 0, // 0
+ 0x80, // 1
+ 0x40, // 2
+ 0xc0, // 3
+ 0x20, // 4
+ 0xa0, // 5,
+ 0x60, // 6,
+ 0xe0, // 7,
+ 0x10, // 8,
+ 0x90, // 9,
+ 0x50, // 10,
+ 0xd0, // 11,
+ 0x30, // 12,
+ 0xb0, // 13,
+ 0x70, // 14,
+ 0xf0 // 15
+};
+
+// Table of source route maximum I-field lengths for token ring.
+ushort IFieldSize[] = {
+ 516,
+ 1500,
+ 2052,
+ 4472,
+ 8191
+};
+
+#define LF_BIT_SHIFT 4
+#define MAX_LF_BITS 4
+
+#ifdef NT
+#ifdef ALLOC_PRAGMA
+//
+// Disposable init code.
+//
+void FreeARPInterface(ARPInterface *Interface);
+void ARPOpen(void *Context);
+
+#pragma alloc_text(INIT, ARPInit)
+#ifndef _PNP_POWER
+#pragma alloc_text(INIT, FreeARPInterface)
+#pragma alloc_text(INIT, ARPOpen)
+#pragma alloc_text(INIT, ARPRegister)
+#else
+#pragma alloc_text(PAGE, ARPOpen)
+#pragma alloc_text(PAGE, ARPRegister)
+
+#endif
+
+//
+// Paged code
+//
+void NotifyConflictProc(CTEEvent *Event, void *Context);
+
+#pragma alloc_text(PAGE, NotifyConflictProc)
+
+#endif // ALLOC_PRAGMA
+#endif // NT
+
+#ifdef VXD
+extern void EnableInts(void);
+#endif
+
+//* DoNDISRequest - Submit a request to an NDIS driver.
+//
+// This is a utility routine to submit a general request to an NDIS
+// driver. The caller specifes the request code (OID), a buffer and
+// a length. This routine allocates a request structure,
+// fills it in, and submits the request.
+//
+// Entry:
+// Adapter - A pointer to the ARPInterface adapter structure.
+// Request - Type of request to be done (Set or Query)
+// OID - Value to be set/queried.
+// Info - A pointer to the buffer to be passed.
+// Length - Length of data in the buffer.
+// Needed - On return, filled in with bytes needed in buffer.
+//
+// Exit:
+//
+NDIS_STATUS
+DoNDISRequest(ARPInterface *Adapter, NDIS_REQUEST_TYPE RT, NDIS_OID OID,
+ void *Info, uint Length, uint *Needed)
+{
+ NDIS_REQUEST Request; // Request structure we'll use.
+ NDIS_STATUS Status;
+
+ // Now fill it in.
+ Request.RequestType = RT;
+ if (RT == NdisRequestSetInformation) {
+ Request.DATA.SET_INFORMATION.Oid = OID;
+ Request.DATA.SET_INFORMATION.InformationBuffer = Info;
+ Request.DATA.SET_INFORMATION.InformationBufferLength = Length;
+ } else {
+ Request.DATA.QUERY_INFORMATION.Oid = OID;
+ Request.DATA.QUERY_INFORMATION.InformationBuffer = Info;
+ Request.DATA.QUERY_INFORMATION.InformationBufferLength = Length;
+ }
+
+ // Initialize the block structure.
+ CTEInitBlockStruc(&Adapter->ai_block);
+#ifdef VXD
+ EnableInts();
+#endif
+
+ // Submit the request.
+ NdisRequest(&Status, Adapter->ai_handle, &Request);
+
+ // Wait for it to finish
+ if (Status == NDIS_STATUS_PENDING)
+ Status = (NDIS_STATUS)CTEBlock(&Adapter->ai_block);
+
+ if (Needed != NULL)
+ *Needed = Request.DATA.QUERY_INFORMATION.BytesNeeded;
+
+ return Status;
+}
+//* FreeARPBuffer - Free a header and buffer descriptor pair.
+//
+// Called when we're done with a buffer. We'll free the buffer and the
+// buffer descriptor pack to the interface.
+//
+// Entry: Interface - Interface buffer/bd came frome.
+// Buffer - NDIS_BUFFER to be freed.
+//
+// Returns: Nothing.
+//
+void
+FreeARPBuffer(ARPInterface *Interface, PNDIS_BUFFER Buffer)
+{
+ CTELockHandle lhandle;
+ uchar **Header; // header buffer to be freed.
+ uint Size;
+
+ Size = NdisBufferLength(Buffer);
+
+ if (Size <= Interface->ai_sbsize) {
+#ifdef VXD
+ // A small buffer, put him on the list.
+ NDIS_BUFFER_LINKAGE(Buffer) = Interface->ai_sblist;
+ Interface->ai_sblist = Buffer;
+#else
+ ExInterlockedPushEntrySList(
+ &Interface->ai_sblist,
+ STRUCT_OF(SINGLE_LIST_ENTRY, &(Buffer->Next), Next),
+ &Interface->ai_lock
+ );
+
+#endif
+
+ return;
+ } else {
+ // A big buffer. Get the buffer pointer, link it on, and free the
+ // NDIS buffer.
+ Header = (uchar **)NdisBufferVirtualAddress(Buffer);
+
+ CTEGetLock(&Interface->ai_lock, &lhandle);
+ *Header = Interface->ai_bblist;
+ Interface->ai_bblist = (uchar *)Header;
+ CTEFreeLock(&Interface->ai_lock, lhandle);
+
+ NdisFreeBuffer(Buffer);
+ }
+}
+
+//* GrowARPHeaders - Grow the ARP header buffer list.
+//
+// Called when we need to grow the ARP header buffer list. Called with the
+// interface lock held.
+//
+// Input: Interface - Interface on which to grow.
+//
+// Returns: Pointer to newly allocated buffer, or NULL.
+//
+PNDIS_BUFFER
+GrowARPHeaders(ARPInterface *Interface)
+{
+ ARPBufferTracker *NewTracker;
+ PNDIS_BUFFER Buffer, ReturnBuffer;
+ uchar *Header;
+ uint i;
+ NDIS_STATUS Status;
+ CTELockHandle Handle;
+
+ CTEGetLock(&Interface->ai_lock, &Handle);
+
+ // Make sure we're allowed to allocate.
+ if (Interface->ai_curhdrs >= Interface->ai_maxhdrs)
+ goto failure;
+
+ NewTracker = CTEAllocMem(sizeof(ARPBufferTracker));
+ if (NewTracker == NULL)
+ goto failure; // We're out of memory.
+
+ NdisAllocateBufferPool(&Status, &NewTracker->abt_handle,
+ ARP_HDRBUF_GROW_SIZE);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ CTEFreeMem(NewTracker);
+ goto failure;
+ }
+
+ Header = CTEAllocMem((uint)Interface->ai_sbsize * ARP_HDRBUF_GROW_SIZE);
+ if (Header == NULL) {
+ NdisFreeBufferPool(NewTracker->abt_handle);
+ CTEFreeMem(NewTracker);
+ goto failure;
+ }
+
+ // Got the resources we need, allocate the buffers.
+ NewTracker->abt_buffer = Header;
+ NewTracker->abt_next = Interface->ai_buflist;
+ Interface->ai_buflist = NewTracker;
+ ReturnBuffer = NULL;
+ Interface->ai_curhdrs += ARP_HDRBUF_GROW_SIZE;
+ CTEFreeLock(&Interface->ai_lock, Handle);
+
+ for (i = 0; i < ARP_HDRBUF_GROW_SIZE; i++) {
+ NdisAllocateBuffer(&Status, &Buffer, NewTracker->abt_handle,
+ Header + (i * Interface->ai_sbsize), Interface->ai_sbsize);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ CTEAssert(FALSE);
+ break;
+ }
+ if (i != 0) {
+ FreeARPBuffer(Interface, Buffer);
+ } else
+ ReturnBuffer = Buffer;
+ }
+
+ // Update for what we didn't allocate, if any.
+ CTEInterlockedAddUlong(&Interface->ai_curhdrs, i - ARP_HDRBUF_GROW_SIZE,
+ &Interface->ai_lock);
+
+ return ReturnBuffer;
+
+failure:
+ CTEFreeLock(&Interface->ai_lock, Handle);
+ return NULL;
+}
+
+//* GetARPBuffer - Get a buffer and descriptor
+//
+// Returns a pointer to an NDIS_BUFFER and a pointer to a buffer
+// of the specified size.
+//
+// Entry: Interface - Pointer to ARPInterface structure to allocate buffer from.
+// BufPtr - Pointer to where to return buf address.
+// Size - Size in bytes of buffer needed.
+//
+// Returns: Pointer to NDIS_BUFFER if successfull, NULL if not
+//
+PNDIS_BUFFER
+GetARPBuffer(ARPInterface *Interface, uchar **BufPtr, uchar size)
+{
+ CTELockHandle lhandle; // Lock handle
+ NDIS_STATUS Status;
+ PNDIS_BUFFER Buffer; // NDIS buffer allocated.
+
+ if (size <= Interface->ai_sbsize) {
+#ifdef VXD
+ Buffer = Interface->ai_sblist;
+ if (Buffer != NULL) {
+ Interface->ai_sblist = NDIS_BUFFER_LINKAGE(Buffer);
+ NDIS_BUFFER_LINKAGE(Buffer) = NULL;
+ NdisBufferLength(Buffer) = size;
+ *BufPtr = NdisBufferVirtualAddress(Buffer);
+ return Buffer;
+#else
+ PSINGLE_LIST_ENTRY BufferLink;
+
+ BufferLink = ExInterlockedPopEntrySList(
+ &Interface->ai_sblist,
+ &Interface->ai_lock
+ );
+ if (BufferLink != NULL) {
+ Buffer = STRUCT_OF(NDIS_BUFFER, BufferLink, Next);
+ NDIS_BUFFER_LINKAGE(Buffer) = NULL;
+ NdisBufferLength(Buffer) = size;
+ *BufPtr = NdisBufferVirtualAddress(Buffer);
+ return Buffer;
+#endif
+
+ } else {
+ Buffer = GrowARPHeaders(Interface);
+ if (Buffer != NULL) {
+ NDIS_BUFFER_LINKAGE(Buffer) = NULL;
+ NdisBufferLength(Buffer) = size;
+ *BufPtr = NdisBufferVirtualAddress(Buffer);
+ }
+ return Buffer;
+ }
+ } else {
+ // Need a 'big' buffer.
+ CTEGetLock(&Interface->ai_lock, &lhandle);
+ if ((*BufPtr = Interface->ai_bblist) != (uchar *)NULL) {
+ Interface->ai_bblist = *(uchar **)*BufPtr;
+ CTEFreeLock(&Interface->ai_lock, lhandle); // Got a buffer.
+ NdisAllocateBuffer(&Status, &Buffer, Interface->ai_bpool, *BufPtr,
+ size);
+ if (Status == NDIS_STATUS_SUCCESS)
+ return Buffer;
+ else { // Couldn't get NDIS buffer, free our buffer.
+ CTEGetLock(&Interface->ai_lock, &lhandle);
+ *(uchar **)&**BufPtr = Interface->ai_bblist;
+ Interface->ai_bblist = *BufPtr;
+ CTEFreeLock(&Interface->ai_lock, lhandle);
+ return (PNDIS_BUFFER)NULL;
+ }
+ }
+
+ // Couldn't get a header buffer, free lock and return NULL.
+ CTEFreeLock(&Interface->ai_lock, lhandle);
+ return (PNDIS_BUFFER)NULL;
+ }
+}
+
+
+//* BitSwap - Bit swap two strings.
+//
+// A routine to bitswap two strings.
+//
+// Input: Dest - Destination of swap.
+// Src - Src string to be swapped.
+// Length - Length in bytes to swap.
+//
+// Returns: Nothing.
+//
+void
+BitSwap(uchar *Dest, uchar *Src, uint Length)
+{
+ uint i;
+ uchar Temp, TempSrc;
+
+ for (i = 0; i < Length; i++, Dest++, Src++) {
+ TempSrc = *Src;
+ Temp = SwapTableLo[TempSrc >> 4] | SwapTableHi[TempSrc & 0x0f];
+ *Dest = Temp;
+ }
+
+}
+
+
+//* SendARPPacket - Build a header, and send a packet.
+//
+// A utility routine to build and ARP header and send a packet. We assume
+// the media specific header has been built.
+//
+// Entry: Interface - Interface for NDIS drive.
+// Packet - Pointer to packet to be sent
+// Header - Pointer to header to fill in.
+// Opcode - Opcode for packet.
+// Address - Source HW address.
+// SrcAddr - Address to use as our source h/w address.
+// Destination - Destination IP address.
+// Src - Source IP address.
+// HWType - Hardware type.
+// CheckIF - TRUE iff we are to check the I/F status before
+// sending.
+//
+// Returns: NDIS_STATUS of send.
+//
+NDIS_STATUS
+SendARPPacket(ARPInterface *Interface, PNDIS_PACKET Packet, ARPHeader *Header, ushort Opcode,
+ uchar *Address, uchar *SrcAddr, IPAddr Destination, IPAddr Src,
+ ushort HWType, uint CheckIF)
+{
+ NDIS_STATUS Status;
+ PNDIS_BUFFER Buffer;
+ uint PacketDone;
+ uchar *AddrPtr;
+
+ Header->ah_hw = HWType;
+ Header->ah_pro = net_short(ARP_ETYPE_IP);
+ Header->ah_hlen = Interface->ai_addrlen;
+ Header->ah_plen = sizeof(IPAddr);
+ Header->ah_opcode = Opcode;
+ AddrPtr = Header->ah_shaddr;
+
+ if (SrcAddr == NULL)
+ SrcAddr = Interface->ai_addr;
+
+ CTEMemCopy(AddrPtr, SrcAddr, Interface->ai_addrlen);
+
+ AddrPtr += Interface->ai_addrlen;
+ *(IPAddr UNALIGNED *)AddrPtr = Src;
+ AddrPtr += sizeof(IPAddr);
+
+ if (Address != (uchar *)NULL)
+ CTEMemCopy(AddrPtr, Address, Interface->ai_addrlen);
+ else
+ CTEMemSet(AddrPtr, 0, Interface->ai_addrlen);
+
+ AddrPtr += Interface->ai_addrlen;
+ *(IPAddr UNALIGNED *)AddrPtr = Destination;
+
+ PacketDone = FALSE;
+
+ if (!CheckIF || Interface->ai_state == INTERFACE_UP) {
+
+ Interface->ai_qlen++;
+ NdisSend(&Status, Interface->ai_handle, Packet);
+
+ if (Status != NDIS_STATUS_PENDING) {
+ PacketDone = TRUE;
+ Interface->ai_qlen--;
+#ifdef VXD
+ CTEAssert(*(int *)&Interface->ai_qlen >= 0);
+#endif
+ if (Status == NDIS_STATUS_SUCCESS)
+ Interface->ai_outoctets += Packet->Private.TotalLength;
+ else {
+ if (Status == NDIS_STATUS_RESOURCES)
+ Interface->ai_outdiscards++;
+ else
+ Interface->ai_outerrors++;
+ }
+ }
+ } else {
+ PacketDone = TRUE;
+ Status = NDIS_STATUS_ADAPTER_NOT_READY;
+ }
+
+ if (PacketDone) {
+ NdisUnchainBufferAtFront(Packet, &Buffer);
+ FreeARPBuffer(Interface, Buffer);
+ NdisFreePacket(Packet);
+ }
+ return Status;
+}
+
+//* SendARPRequest - Send an ARP packet
+//
+// Called when we need to ARP an IP address, or respond to a request. We'll send out
+// the packet, and the receiving routines will process the response.
+//
+// Entry: Interface - Interface to send the request on.
+// Destination - The IP address to be ARPed.
+// Type - Either RESOLVING_GLOBAL or RESOLVING_LOCAL
+// SrcAddr - NULL if we're sending from ourselves, the value
+// to use otherwise.
+// CheckIF - Flag passed through to SendARPPacket().
+//
+// Returns: Status of attempt to send ARP request.
+//
+NDIS_STATUS
+SendARPRequest(ARPInterface *Interface, IPAddr Destination, uchar Type,
+ uchar *SrcAddr, uint CheckIF)
+{
+ uchar *MHeader; // Pointer to media header.
+ PNDIS_BUFFER Buffer; // NDIS buffer descriptor.
+ uchar MHeaderSize; // Size of media header.
+ uchar *MAddr; // Pointer to media address structure.
+ uint SAddrOffset; // Offset into media address of source address.
+ uchar SRFlag = 0; // Source routing flag.
+ uchar SNAPLength = 0;
+ uchar *SNAPAddr; // Address of SNAP header.
+ PNDIS_PACKET Packet; // Packet for sending.
+ NDIS_STATUS Status;
+ ushort HWType;
+ IPAddr Src;
+ CTELockHandle Handle;
+ ARPIPAddr *Addr;
+
+ // First, get a source address we can use.
+ CTEGetLock(&Interface->ai_lock, &Handle);
+ Addr = &Interface->ai_ipaddr;
+ Src = NULL_IP_ADDR;
+ do {
+ if (!IP_ADDR_EQUAL(Addr->aia_addr, NULL_IP_ADDR)) {
+ //
+ // This is a valid address. See if it is the same as the
+ // target address - i.e. arp'ing for ourselves. If it is,
+ // we want to use that as our source address.
+ //
+ if (IP_ADDR_EQUAL(Addr->aia_addr, Destination)) {
+ Src = Addr->aia_addr;
+ break;
+ }
+
+ // See if the target is on this subnet.
+ if (IP_ADDR_EQUAL(
+ Addr->aia_addr & Addr->aia_mask,
+ Destination & Addr->aia_mask
+ ))
+ {
+ //
+ // See if we've already found a suitable candidate on the
+ // same subnet. If we haven't, we'll use this one.
+ //
+ if (!IP_ADDR_EQUAL(
+ Addr->aia_addr & Addr->aia_mask,
+ Src & Addr->aia_mask
+ ))
+ {
+ Src = Addr->aia_addr;
+ }
+ }
+ else {
+ // He's not on our subnet. If we haven't already found a valid
+ // address save this one in case we don't find a match for the
+ // subnet.
+ if (IP_ADDR_EQUAL(Src, NULL_IP_ADDR)) {
+ Src = Addr->aia_addr;
+ }
+ }
+ }
+
+ Addr = Addr->aia_next;
+
+ } while (Addr != NULL);
+
+ CTEFreeLock(&Interface->ai_lock, Handle);
+
+ // If we didn't find a source address, give up.
+ if (IP_ADDR_EQUAL(Src, NULL_IP_ADDR))
+ return NDIS_STATUS_SUCCESS;
+
+ NdisAllocatePacket(&Status, &Packet, Interface->ai_ppool);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ Interface->ai_outdiscards++;
+ return Status;
+ }
+
+ ((PacketContext *)Packet->ProtocolReserved)->pc_common.pc_owner = PACKET_OWNER_LINK;
+ (Interface->ai_outpcount[AI_NONUCAST_INDEX])++;
+
+ // Figure out what type of media this is, and do the appropriate thing.
+ switch (Interface->ai_media) {
+ case NdisMedium802_3:
+ MHeaderSize = ARP_MAX_MEDIA_ENET;
+ MAddr = ENetBcst;
+ if (Interface->ai_snapsize == 0) {
+ SNAPAddr = (uchar *)NULL;
+ HWType = net_short(ARP_HW_ENET);
+ } else {
+ SNAPLength = sizeof(SNAPHeader);
+ SNAPAddr = ARPSNAP;
+ HWType = net_short(ARP_HW_802);
+ }
+
+ SAddrOffset = offsetof(struct ENetHeader, eh_saddr);
+ break;
+ case NdisMedium802_5:
+ // Token ring. We have logic for dealing with the second transmit
+ // of an arp request.
+ MAddr = TRBcst;
+ SAddrOffset = offsetof(struct TRHeader, tr_saddr);
+ SNAPLength = sizeof(SNAPHeader);
+ SNAPAddr = ARPSNAP;
+ MHeaderSize = sizeof(TRHeader);
+ HWType = net_short(ARP_HW_802);
+ if (Type == ARP_RESOLVING_GLOBAL) {
+ MHeaderSize += sizeof(RC);
+ SRFlag = TR_RII;
+ }
+ break;
+ case NdisMediumFddi:
+ MHeaderSize = sizeof(FDDIHeader);
+ MAddr = FDDIBcst;
+ SNAPAddr = ARPSNAP;
+ SNAPLength = sizeof(SNAPHeader);
+ SAddrOffset = offsetof(struct FDDIHeader, fh_saddr);
+ HWType = net_short(ARP_HW_ENET);
+ break;
+ case NdisMediumArcnet878_2:
+ MHeaderSize = ARP_MAX_MEDIA_ARC;
+ MAddr = ARCBcst;
+ SNAPAddr = (uchar *)NULL;
+ SAddrOffset = offsetof(struct ARCNetHeader, ah_saddr);
+ HWType = net_short(ARP_HW_ARCNET);
+ break;
+ default:
+ DEBUGCHK;
+ Interface->ai_outerrors++;
+ return NDIS_STATUS_UNSUPPORTED_MEDIA;
+ }
+
+
+
+ if ((Buffer = GetARPBuffer(Interface, &MHeader,
+ (uchar)(sizeof(ARPHeader) + MHeaderSize + SNAPLength))) == (PNDIS_BUFFER)NULL) {
+ NdisFreePacket(Packet);
+ Interface->ai_outdiscards++;
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ if (Interface->ai_media == NdisMediumArcnet878_2)
+ NdisBufferLength(Buffer) -= ARCNET_ARPHEADER_ADJUSTMENT;
+
+ // Copy broadcast address into packet.
+ CTEMemCopy(MHeader, MAddr, MHeaderSize);
+ // Fill in source address.
+ if (SrcAddr == NULL) {
+ SrcAddr = Interface->ai_addr;
+ }
+
+ if (Interface->ai_media == NdisMedium802_3 && Interface->ai_snapsize != 0) {
+ ENetHeader *Hdr = (ENetHeader *)MHeader;
+
+ // Using SNAP on ethernet. Adjust the etype to a length.
+ Hdr->eh_type = net_short(sizeof(ARPHeader) + sizeof(SNAPHeader));
+ }
+
+ CTEMemCopy(&MHeader[SAddrOffset], SrcAddr, Interface->ai_addrlen);
+ if ((Interface->ai_media == NdisMedium802_5) && (Type == ARP_RESOLVING_GLOBAL)) {
+ // Turn on source routing.
+ MHeader[SAddrOffset] |= SRFlag;
+ MHeader[SAddrOffset + Interface->ai_addrlen] |= TrRii;
+ }
+ // Copy in SNAP header, if any.
+ CTEMemCopy(&MHeader[MHeaderSize], SNAPAddr, SNAPLength);
+
+ // Media header is filled in. Now do ARP packet itself.
+ NdisChainBufferAtFront(Packet, Buffer);
+ return SendARPPacket(Interface, Packet,(ARPHeader *)&MHeader[MHeaderSize + SNAPLength],
+ net_short(ARP_REQUEST), (uchar *)NULL, SrcAddr, Destination, Src,
+ HWType, CheckIF);
+}
+
+//* SendARPReply - Reply to an ARP request.
+//
+// Called by our receive packet handler when we need to reply. We build a packet
+// and buffer and call SendARPPacket to send it.
+//
+// Entry: Interface - Pointer to interface to reply on.
+// Destination - IPAddress to reply to.
+// Src - Source address to reply from.
+// HWAddress - Hardware address to reply to.
+// SourceRoute - Source Routing information, if any.
+// SourceRouteSize - Size in bytes of soure routing.
+// UseSNAP - Whether or not to use SNAP for this reply.
+//
+// Returns: Nothing.
+//
+void
+SendARPReply(ARPInterface *Interface, IPAddr Destination, IPAddr Src, uchar *HWAddress,
+ RC UNALIGNED *SourceRoute, uint SourceRouteSize, uint UseSNAP)
+{
+ PNDIS_PACKET Packet; // Buffer and packet to be used.
+ PNDIS_BUFFER Buffer;
+ uchar *Header; // Pointer to media header.
+ NDIS_STATUS Status;
+ uchar Size = 0; // Size of media header buffer.
+ ushort HWType;
+ ENetHeader *EH;
+ FDDIHeader *FH;
+ ARCNetHeader *AH;
+ TRHeader *TRH;
+
+ // Allocate a packet for this.
+ NdisAllocatePacket(&Status, &Packet, Interface->ai_ppool);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ Interface->ai_outdiscards++;
+ return;
+ }
+
+ ((PacketContext *)Packet->ProtocolReserved)->pc_common.pc_owner = PACKET_OWNER_LINK;
+ (Interface->ai_outpcount[AI_UCAST_INDEX])++;
+
+ Size = Interface->ai_hdrsize;
+
+ if (UseSNAP)
+ Size += Interface->ai_snapsize;
+
+ if (Interface->ai_media == NdisMedium802_5)
+ Size += SourceRouteSize;
+
+ if ((Buffer = GetARPBuffer(Interface, &Header, (uchar)(Size + sizeof(ARPHeader)))) ==
+ (PNDIS_BUFFER)NULL) {
+ Interface->ai_outdiscards++;
+ NdisFreePacket(Packet);
+ return;
+ }
+
+ // Decide how to build the header based on the media type.
+ switch (Interface->ai_media) {
+ case NdisMedium802_3:
+ EH = (ENetHeader *)Header;
+ CTEMemCopy(EH->eh_daddr, HWAddress, ARP_802_ADDR_LENGTH);
+ CTEMemCopy(EH->eh_saddr, Interface->ai_addr, ARP_802_ADDR_LENGTH);
+ if (!UseSNAP) {
+ EH->eh_type = net_short(ARP_ETYPE_ARP);
+ HWType = net_short(ARP_HW_ENET);
+ } else {
+ // Using SNAP on ethernet.
+ EH->eh_type = net_short(sizeof(ARPHeader) + sizeof(SNAPHeader));
+ HWType = net_short(ARP_HW_802);
+ CTEMemCopy(Header + sizeof(ENetHeader), ARPSNAP,
+ sizeof(SNAPHeader));
+ }
+ break;
+ case NdisMedium802_5:
+ TRH = (TRHeader *)Header;
+ TRH->tr_ac = ARP_AC;
+ TRH->tr_fc = ARP_FC;
+ CTEMemCopy(TRH->tr_daddr, HWAddress, ARP_802_ADDR_LENGTH);
+ CTEMemCopy(TRH->tr_saddr, Interface->ai_addr, ARP_802_ADDR_LENGTH);
+ if (SourceRouteSize) {// If we have source route info, deal with
+ // it.
+ CTEMemCopy(Header + sizeof(TRHeader), SourceRoute,
+ SourceRouteSize);
+ // Convert to directed response.
+ ((RC *)&Header[sizeof(TRHeader)])->rc_blen &= RC_LENMASK;
+
+ ((RC *)&Header[sizeof(TRHeader)])->rc_dlf ^= RC_DIR;
+ TRH->tr_saddr[0] |= TR_RII;
+ }
+ CTEMemCopy(Header + sizeof(TRHeader) + SourceRouteSize, ARPSNAP,
+ sizeof(SNAPHeader));
+ HWType = net_short(ARP_HW_802);
+ break;
+ case NdisMediumFddi:
+ FH = (FDDIHeader *)Header;
+ FH->fh_pri = ARP_FDDI_PRI;
+ CTEMemCopy(FH->fh_daddr, HWAddress, ARP_802_ADDR_LENGTH);
+ CTEMemCopy(FH->fh_saddr, Interface->ai_addr, ARP_802_ADDR_LENGTH);
+ CTEMemCopy(Header + sizeof(FDDIHeader), ARPSNAP, sizeof(SNAPHeader));
+ HWType = net_short(ARP_HW_ENET);
+ break;
+ case NdisMediumArcnet878_2:
+ AH = (ARCNetHeader *)Header;
+ AH->ah_saddr = Interface->ai_addr[0];
+ AH->ah_daddr = *HWAddress;
+ AH->ah_prot = ARP_ARCPROT_ARP;
+ NdisBufferLength(Buffer) -= ARCNET_ARPHEADER_ADJUSTMENT;
+ HWType = net_short(ARP_HW_ARCNET);
+ break;
+ default:
+ DEBUGCHK;
+ Interface->ai_outerrors++;
+ FreeARPBuffer(Interface, Buffer);
+ NdisFreePacket(Packet);
+ return;
+ }
+
+ NdisChainBufferAtFront(Packet, Buffer);
+ SendARPPacket(Interface, Packet,(ARPHeader *)(Header + Size), net_short(ARP_RESPONSE),
+ HWAddress, NULL, Destination, Src, HWType, TRUE);
+}
+
+
+//* ARPRemoveRCE - Remove an RCE from the ATE list.
+//
+// This funtion removes a specified RCE from a given ATE. It assumes the ate_lock
+// is held by the caller.
+//
+// Entry: ATE - ATE from which RCE is to be removed.
+// RCE - RCE to be removed.
+//
+// Returns: Nothing
+//
+void
+ARPRemoveRCE(ARPTableEntry *ATE, RouteCacheEntry *RCE)
+{
+ ARPContext *CurrentAC; // Current ARP Context being checked.
+#ifdef DEBUG
+ uint Found = FALSE;
+#endif
+
+ CurrentAC = (ARPContext *)(((char *)&ATE->ate_rce) -
+ offsetof(struct ARPContext, ac_next));
+
+ while (CurrentAC->ac_next != (RouteCacheEntry *)NULL)
+ if (CurrentAC->ac_next == RCE) {
+ ARPContext *DummyAC = (ARPContext *)RCE->rce_context;
+ CurrentAC->ac_next = DummyAC->ac_next;
+ DummyAC->ac_ate = (ARPTableEntry *)NULL;
+#ifdef DEBUG
+ Found = TRUE;
+#endif
+ break;
+ }
+ else
+ CurrentAC = (ARPContext *)CurrentAC->ac_next->rce_context;
+
+ CTEAssert(Found);
+}
+//* ARPLookup - Look up an entry in the ARP table.
+//
+// Called to look up an entry in an interface's ARP table. If we find it, we'll
+// lock the entry and return a pointer to it, otherwise we return NULL. We
+// assume that the caller has the ARP table locked when we are called.
+//
+// The ARP table entry is structured as a hash table of pointers to
+// ARPTableEntrys.After hashing on the IP address, a linear search is done to
+// lookup the entry.
+//
+// If we find the entry, we lock it for the caller. If we don't find
+// the entry, we leave the ARP table locked so that the caller may atomically
+// insert a new entry without worrying about a duplicate being inserted between
+// the time the table was checked and the time the caller went to insert the
+// entry.
+//
+// Entry: Interface - The interface to be searched upon.
+// Address - The IP address we're looking up.
+// Handle - Pointer to lock handle to be used to lock entry.
+//
+// Returns: Pointer to ARPTableEntry if found, or NULL if not.
+//
+ARPTableEntry *
+ARPLookup(ARPInterface *Interface, IPAddr Address, CTELockHandle *Handle)
+{
+ int i = ARP_HASH(Address); // Index into hash table.
+ ARPTableEntry *Current; // Current ARP Table entry being
+ // examined.
+
+ Current = (*Interface->ai_ARPTbl)[i];
+
+ while (Current != (ARPTableEntry *)NULL) {
+ CTEGetLock(&Current->ate_lock, Handle);
+ if (IP_ADDR_EQUAL(Current->ate_dest, Address)) { // Found a match.
+ return Current;
+ }
+ CTEFreeLock(&Current->ate_lock, *Handle);
+ Current = Current->ate_next;
+ }
+ // If we got here, we didn't find the entry. Leave the table locked and
+ // return the handle.
+ return (ARPTableEntry *)NULL;
+}
+
+//* IsBCastOnIF- See it an address is a broadcast address on an interface.
+//
+// Called to see if a particular address is a broadcast address on an
+// interface. We'll check the global, net, and subnet broadcasts. We assume
+// the caller holds the lock on the interface.
+//
+// Entry: Interface - Interface to check.
+// Addr - Address to check.
+//
+// Returns: TRUE if it it a broadcast, FALSE otherwise.
+//
+uint
+IsBCastOnIF(ARPInterface *Interface, IPAddr Addr)
+{
+ IPAddr BCast;
+ IPMask Mask;
+ ARPIPAddr *ARPAddr;
+ IPAddr LocalAddr;
+
+ // First get the interface broadcast address.
+ BCast = Interface->ai_bcast;
+
+ // First check for global broadcast.
+ if (IP_ADDR_EQUAL(BCast, Addr) || CLASSD_ADDR(Addr))
+ return TRUE;
+
+ // Now walk the local addresses, and check for net/subnet bcast on each
+ // one.
+ ARPAddr = &Interface->ai_ipaddr;
+ do {
+ // See if this one is valid.
+ LocalAddr = ARPAddr->aia_addr;
+ if (!IP_ADDR_EQUAL(LocalAddr, NULL_IP_ADDR)) {
+ // He's valid.
+ Mask = ARPAddr->aia_mask;
+
+ // First check for subnet bcast.
+ if (IP_ADDR_EQUAL((LocalAddr & Mask) | (BCast & ~Mask), Addr))
+ return TRUE;
+
+ // Now check all nets broadcast.
+ Mask = IPNetMask(LocalAddr);
+ if (IP_ADDR_EQUAL((LocalAddr & Mask) | (BCast & ~Mask), Addr))
+ return TRUE;
+ }
+
+ ARPAddr = ARPAddr->aia_next;
+
+ } while (ARPAddr != NULL);
+
+ // If we're here, it's not a broadcast.
+ return FALSE;
+
+}
+
+
+//* ARPSendBCast - See if this is a bcast or mcast frame, and send it.
+//
+// Called when we have a packet to send and we want to see if it's a broadcast
+// or multicast frame on this interface. We'll search the local addresses and
+// see if we can determine if it is. If it is, we'll send it here. Otherwise
+// we return FALSE, and the caller will try to resolve the address.
+//
+// Entry: Interface - A pointer to an AI structure.
+// Dest - Destination of datagram.
+// Packet - Packet to be sent.
+// Status - Place to return status of send attempt.
+//
+// Returns: TRUE if is was a bcast or mcast send, FALSE otherwise.
+//
+uint
+ARPSendBCast(ARPInterface *Interface, IPAddr Dest, PNDIS_PACKET Packet,
+ PNDIS_STATUS Status)
+{
+ uint IsBCast;
+ CTELockHandle Handle;
+ PNDIS_BUFFER ARPBuffer; // ARP Header buffer.
+ uchar *BufAddr; // Address of NDIS buffer
+ NDIS_STATUS MyStatus;
+ ENetHeader *Hdr;
+ FDDIHeader *FHdr;
+ TRHeader *TRHdr;
+ SNAPHeader UNALIGNED *SNAPPtr;
+ RC UNALIGNED *RCPtr;
+ ARCNetHeader *AHdr;
+ uint DataLength;
+
+ // Get the lock, and see if it's a broadcast.
+ CTEGetLock(&Interface->ai_lock, &Handle);
+ IsBCast = IsBCastOnIF(Interface, Dest);
+ CTEFreeLock(&Interface->ai_lock, Handle);
+
+ if (IsBCast) {
+ if (Interface->ai_state == INTERFACE_UP) {
+ uchar Size;
+
+ Size = Interface->ai_hdrsize + Interface->ai_snapsize;
+
+ if (Interface->ai_media == NdisMedium802_5)
+ Size += sizeof(RC);
+
+ ARPBuffer = GetARPBuffer(Interface, &BufAddr, Size);
+ if (ARPBuffer != NULL) {
+ uint UNALIGNED *Temp;
+
+ // Got the buffer we need.
+ switch (Interface->ai_media) {
+
+ case NdisMedium802_3:
+
+ Hdr = (ENetHeader *)BufAddr;
+ if (!CLASSD_ADDR(Dest))
+ CTEMemCopy(Hdr, ENetBcst, ARP_802_ADDR_LENGTH);
+ else {
+ CTEMemCopy(Hdr, ENetMcst, ARP_802_ADDR_LENGTH);
+ Temp = (uint UNALIGNED *)&Hdr->eh_daddr[2];
+ *Temp |= (Dest & ARP_MCAST_MASK);
+ }
+
+ CTEMemCopy(Hdr->eh_saddr, Interface->ai_addr,
+ ARP_802_ADDR_LENGTH);
+
+ if (Interface->ai_snapsize == 0) {
+ // No snap on this interface, so just use ETypr.
+ Hdr->eh_type = net_short(ARP_ETYPE_IP);
+ } else {
+ ushort ShortDataLength;
+
+ // We're using SNAP. Find the size of the packet.
+ NdisQueryPacket(Packet, NULL, NULL, NULL,
+ &DataLength);
+ ShortDataLength = (ushort)(DataLength +
+ sizeof(SNAPHeader));
+ Hdr->eh_type = net_short(ShortDataLength);
+ SNAPPtr = (SNAPHeader UNALIGNED *)
+ (BufAddr + sizeof(ENetHeader));
+ CTEMemCopy(SNAPPtr, ARPSNAP, sizeof(SNAPHeader));
+ SNAPPtr->sh_etype = net_short(ARP_ETYPE_IP);
+ }
+
+ break;
+
+ case NdisMedium802_5:
+
+ // This is token ring. We'll have to screw around with
+ // source routing.
+
+ // BUGBUG Need to support 'real' TR functional address
+ // for multicast - see RFC 1469.
+
+ TRHdr = (TRHeader *)BufAddr;
+
+ CTEMemCopy(TRHdr, TRBcst, offsetof(TRHeader, tr_saddr));
+ CTEMemCopy(TRHdr->tr_saddr, Interface->ai_addr,
+ ARP_802_ADDR_LENGTH);
+
+ if (sIPAlwaysSourceRoute)
+ {
+ TRHdr->tr_saddr[0] |= TR_RII;
+
+ RCPtr = (RC UNALIGNED *)((uchar *)TRHdr + sizeof(TRHeader));
+ RCPtr->rc_blen = TrRii | RC_LEN;
+ RCPtr->rc_dlf = RC_BCST_LEN;
+ SNAPPtr = (SNAPHeader UNALIGNED *)((uchar *)RCPtr + sizeof(RC));
+ }
+ else
+ {
+
+ //
+ // Adjust the size of the buffer to account for the
+ // fact that we don't have the RC field.
+ //
+ NdisAdjustBufferLength(ARPBuffer,(Size - sizeof(RC)));
+ SNAPPtr = (SNAPHeader UNALIGNED *)((uchar *)TRHdr + sizeof(TRHeader));
+ }
+ CTEMemCopy(SNAPPtr, ARPSNAP, sizeof(SNAPHeader));
+ SNAPPtr->sh_etype = net_short(ARP_ETYPE_IP);
+
+ break;
+ case NdisMediumFddi:
+ FHdr = (FDDIHeader *)BufAddr;
+
+ if (!CLASSD_ADDR(Dest))
+ CTEMemCopy(FHdr, FDDIBcst,
+ offsetof(FDDIHeader, fh_saddr));
+ else {
+ CTEMemCopy(FHdr, FDDIMcst,
+ offsetof(FDDIHeader, fh_saddr));
+ Temp = (uint UNALIGNED *)&FHdr->fh_daddr[2];
+ *Temp |= (Dest & ARP_MCAST_MASK);
+ }
+
+ CTEMemCopy(FHdr->fh_saddr, Interface->ai_addr,
+ ARP_802_ADDR_LENGTH);
+
+ SNAPPtr = (SNAPHeader UNALIGNED *)(BufAddr + sizeof(FDDIHeader));
+ CTEMemCopy(SNAPPtr, ARPSNAP, sizeof(SNAPHeader));
+ SNAPPtr->sh_etype = net_short(ARP_ETYPE_IP);
+
+ break;
+ case NdisMediumArcnet878_2:
+ AHdr = (ARCNetHeader *)BufAddr;
+ AHdr->ah_saddr = Interface->ai_addr[0];
+ AHdr->ah_daddr = 0;
+ AHdr->ah_prot = ARP_ARCPROT_IP;
+ break;
+ default:
+ DEBUGCHK;
+ *Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
+ FreeARPBuffer(Interface, ARPBuffer);
+ return FALSE;
+
+ }
+
+ (Interface->ai_outpcount[AI_NONUCAST_INDEX])++;
+ Interface->ai_qlen++;
+ NdisChainBufferAtFront(Packet, ARPBuffer);
+ NdisSend(&MyStatus, Interface->ai_handle, Packet);
+
+ *Status = MyStatus;
+
+ if (MyStatus != NDIS_STATUS_PENDING) { // Send finished
+ // immediately.
+ if (MyStatus == NDIS_STATUS_SUCCESS) {
+ Interface->ai_outoctets += Packet->Private.TotalLength;
+ } else {
+ if (MyStatus == NDIS_STATUS_RESOURCES)
+ Interface->ai_outdiscards++;
+ else
+ Interface->ai_outerrors++;
+ }
+
+ Interface->ai_qlen--;
+#ifdef VXD
+ CTEAssert(*(int *)&Interface->ai_qlen >= 0);
+#endif
+ NdisUnchainBufferAtFront(Packet, &ARPBuffer);
+ FreeARPBuffer(Interface, ARPBuffer);
+ }
+ } else
+ *Status = NDIS_STATUS_RESOURCES;
+ } else
+ *Status = NDIS_STATUS_ADAPTER_NOT_READY;
+
+ return TRUE;
+
+ } else
+ return FALSE;
+}
+
+//* ARPSendData - Send a frame to a specific destination address.
+//
+// Called when we need to send a frame to a particular address, after the
+// ATE has been looked up. We take in an ATE and a packet, validate the state of the
+// ATE, and either send or ARP for the address if it's not done resolving. We assume
+// the lock on the ATE is held where we're called, and we'll free it before returning.
+//
+// Entry: Interface - A pointer to the AI structure.
+// Packet - A pointer to the BufDesc chain to be sent.
+// entry - A pointer to the ATE for the send.
+// lhandle - Pointer to a lock handle for the ATE.
+//
+// Returns: Status of the transmit - success, an error, or pending.
+//
+NDIS_STATUS
+ARPSendData(ARPInterface *Interface, PNDIS_PACKET Packet, ARPTableEntry *entry,
+ CTELockHandle lhandle)
+{
+ PNDIS_BUFFER ARPBuffer; // ARP Header buffer.
+ uchar *BufAddr; // Address of NDIS buffer
+ NDIS_STATUS Status; // Status of send.
+
+ if (Interface->ai_state == INTERFACE_UP) {
+
+ if (entry->ate_state == ARP_GOOD) { // Entry is valid
+
+ entry->ate_useticks = ArpCacheLife;
+ if ((ARPBuffer = GetARPBuffer(Interface, &BufAddr,
+ entry->ate_addrlength)) != (PNDIS_BUFFER)NULL) {
+
+ // Everything's in good shape, copy header and send packet.
+
+ (Interface->ai_outpcount[AI_UCAST_INDEX])++;
+ Interface->ai_qlen++;
+ CTEMemCopy(BufAddr, entry->ate_addr, entry->ate_addrlength);
+
+ // If we're on Ethernet, see if we're using SNAP here.
+ if (Interface->ai_media == NdisMedium802_3 &&
+ entry->ate_addrlength != sizeof(ENetHeader)) {
+ ENetHeader *Header;
+ uint DataSize;
+ ushort ShortDataSize;
+
+ // We're apparently using SNAP on Ethernet. Query the
+ // packet for the size, and set the length properly.
+ NdisQueryPacket(Packet, NULL, NULL, NULL, &DataSize);
+ ShortDataSize = (ushort)(DataSize + sizeof(SNAPHeader));
+ Header = (ENetHeader *)BufAddr;
+ Header->eh_type = net_short(ShortDataSize);
+ }
+
+ CTEFreeLock(&entry->ate_lock, lhandle);
+ NdisChainBufferAtFront(Packet, ARPBuffer);
+ NdisSend(&Status, Interface->ai_handle, Packet);
+ if (Status != NDIS_STATUS_PENDING) { // Send finished
+ // immediately.
+ if (Status == NDIS_STATUS_SUCCESS) {
+ Interface->ai_outoctets += Packet->Private.TotalLength;
+ } else {
+ if (Status == NDIS_STATUS_RESOURCES)
+ Interface->ai_outdiscards++;
+ else
+ Interface->ai_outerrors++;
+ }
+
+ Interface->ai_qlen--;
+#ifdef VXD
+ CTEAssert(*(int *)&Interface->ai_qlen >= 0);
+#endif
+ NdisUnchainBufferAtFront(Packet, &ARPBuffer);
+ FreeARPBuffer(Interface, ARPBuffer);
+ }
+ return Status;
+ } else { // No buffer, free lock and return.
+ CTEFreeLock(&entry->ate_lock, lhandle);
+ Interface->ai_outdiscards++;
+ return NDIS_STATUS_RESOURCES;
+ }
+ }
+ // The IP addresses match, but the state of the ARP entry indicates
+ // it's not valid. If the address is marked as resolving, we'll replace
+ // the current cached packet with this one. If it's been more than
+ // ARP_FLOOD_RATE ms. since we last sent an ARP request, we'll send
+ // another one now.
+ if (entry->ate_state <= ARP_RESOLVING) {
+ PNDIS_PACKET OldPacket = entry->ate_packet;
+ ulong Now = CTESystemUpTime();
+ entry->ate_packet = Packet;
+ if ((Now - entry->ate_valid) > ARP_FLOOD_RATE) {
+ IPAddr Dest = entry->ate_dest;
+
+ entry->ate_valid = Now;
+ entry->ate_state = ARP_RESOLVING_GLOBAL; // We're done this
+ // at least once.
+ CTEFreeLock(&entry->ate_lock, lhandle);
+ SendARPRequest(Interface, Dest, ARP_RESOLVING_GLOBAL,
+ NULL, TRUE); // Send a request.
+ } else
+ CTEFreeLock(&entry->ate_lock, lhandle);
+
+ if (OldPacket)
+ IPSendComplete(Interface->ai_context, OldPacket,
+ NDIS_STATUS_SUCCESS);
+
+ return NDIS_STATUS_PENDING;
+ } else {
+ DEBUGCHK;
+ CTEFreeLock(&entry->ate_lock, lhandle);
+ Interface->ai_outerrors++;
+ return NDIS_STATUS_INVALID_PACKET;
+ }
+ } else {
+ // Adapter is down. Just return the error.
+ CTEFreeLock(&entry->ate_lock, lhandle);
+ return NDIS_STATUS_ADAPTER_NOT_READY;
+ }
+}
+
+//* CreateARPTableEntry - Create a new entry in the ARP table.
+//
+// A function to put an entry into the ARP table. We allocate memory if we
+// need to.
+//
+// The first thing to do is get the lock on the ARP table, and see if the
+// entry already exists. If it does, we're done. Otherwise we need to allocate
+// memory and create a new entry.
+//
+// Entry: Interface - Interface for ARP table.
+// Destination - Destination address to be mapped.
+// Handle - Pointer to lock handle for entry.
+//
+// Returns: Pointer to newly created entry.
+//
+ARPTableEntry *
+CreateARPTableEntry(ARPInterface *Interface, IPAddr Destination,
+ CTELockHandle *Handle)
+{
+ ARPTableEntry *NewEntry, *Entry;
+ CTELockHandle TableHandle;
+ int i = ARP_HASH(Destination);
+ int Size;
+
+ // First look for it, and if we don't find it return try to create one.
+ CTEGetLock(&Interface->ai_ARPTblLock, &TableHandle);
+ if ((Entry = ARPLookup(Interface, Destination, Handle)) !=
+ (ARPTableEntry *)NULL) {
+ CTEFreeLock(&Interface->ai_ARPTblLock, *Handle);
+ *Handle = TableHandle;
+ return Entry;
+ }
+
+ // Allocate memory for the entry. If we can't, fail the request.
+ Size = sizeof(ARPTableEntry) - 1 +
+ (Interface->ai_media == NdisMedium802_5 ?
+ ARP_MAX_MEDIA_TR : (Interface->ai_hdrsize +
+ Interface->ai_snapsize));
+
+ if ((NewEntry = CTEAllocMem(Size)) == (ARPTableEntry *)NULL) {
+ CTEFreeLock(&Interface->ai_ARPTblLock, TableHandle);
+ return (ARPTableEntry *)NULL;
+ }
+
+ CTEMemSet(NewEntry, 0, Size);
+ NewEntry->ate_dest = Destination;
+ if (Interface->ai_media != NdisMedium802_5 || sArpAlwaysSourceRoute)
+ NewEntry->ate_state = ARP_RESOLVING_GLOBAL;
+ else
+ NewEntry->ate_state = ARP_RESOLVING_LOCAL;
+
+ NewEntry->ate_rce = NULL;
+
+ NewEntry->ate_valid = CTESystemUpTime();
+ NewEntry->ate_useticks = ArpCacheLife;
+ CTEInitLock(&NewEntry->ate_lock);
+
+ // Entry does not exist. Insert the new entry into the table at the appropriate spot.
+ // ARPLookup returns with the table lock held if it fails.
+ NewEntry->ate_next = (*Interface->ai_ARPTbl)[i];
+ (*Interface->ai_ARPTbl)[i] = NewEntry;
+ Interface->ai_count++;
+ CTEGetLock(&NewEntry->ate_lock, Handle);
+ CTEFreeLock(&Interface->ai_ARPTblLock, *Handle);
+ *Handle = TableHandle;
+ return NewEntry;
+}
+
+
+//* ARPTransmit - Send a frame.
+//
+// The main ARP transmit routine, called by the upper layer. This routine
+// takes as input a buf desc chain, RCE, and size. We validate the cached
+// information in the RCE. If it is valid, we use it to send the frame. Otherwise
+// we do a table lookup. If we find it in the table, we'll update the RCE and continue.
+// Otherwise we'll queue the packet and start an ARP resolution.
+//
+// Entry: Context - A pointer to the AI structure.
+// Packet - A pointer to the BufDesc chain to be sent.
+// Destination - IP address of destination we're trying to reach,
+// RCE - A pointer to an RCE which may have cached information.
+//
+// Returns: Status of the transmit - success, an error, or pending.
+//
+NDIS_STATUS
+ARPTransmit(void *Context, PNDIS_PACKET Packet, IPAddr Destination,
+ RouteCacheEntry *RCE)
+{
+ ARPInterface *ai = (ARPInterface *)Context; // Set up as AI pointer.
+ ARPContext *ac; // ARP context pointer.
+ ARPTableEntry *entry; // Pointer to ARP tbl. entry
+ CTELockHandle lhandle; // Lock handle
+ CTELockHandle tlhandle; // Lock handle for ARP table.
+ NDIS_STATUS Status;
+
+ CTEGetLock(&ai->ai_ARPTblLock, &tlhandle);
+ if (RCE != (RouteCacheEntry *)NULL) { // Have a valid RCE.
+ ac = (ARPContext *)RCE->rce_context; // Get pointer to context
+ entry = ac->ac_ate;
+ if (entry != (ARPTableEntry *)NULL) { // Have a valid ATE.
+ CTEGetLockAtDPC(&entry->ate_lock, &lhandle); // Lock this structure
+ if (IP_ADDR_EQUAL(entry->ate_dest, Destination)) {
+ CTEFreeLockFromDPC(&ai->ai_ARPTblLock, lhandle);
+ return ARPSendData(ai, Packet, entry, tlhandle); // Send the data
+ }
+
+ // We have an RCE that identifies the wrong ATE. We'll free it from
+ // this list and try and find an ATE that is valid.
+ ARPRemoveRCE(entry, RCE);
+ CTEFreeLock(&entry->ate_lock, lhandle);
+ // Fall through to 'no valid entry' code.
+ }
+ }
+
+ // Here we have no valid ATE, either because the RCE is NULL or the ATE
+ // specified by the RCE was invalid. We'll try and find one in the table. If
+ // we find one, we'll fill in this RCE and send the packet. Otherwise we'll
+ // try to create one. At this point we hold the lock on the ARP table.
+
+ if ((entry = ARPLookup(ai, Destination, &lhandle)) != (ARPTableEntry *)NULL) {
+ // Found a matching entry. ARPLookup returns with the ATE lock held.
+ if (RCE != (RouteCacheEntry *)NULL) {
+ ac->ac_next = entry->ate_rce; // Fill in context for next time.
+ entry->ate_rce = RCE;
+ ac->ac_ate = entry;
+ }
+ CTEFreeLockFromDPC(&ai->ai_ARPTblLock, lhandle);
+ return ARPSendData(ai, Packet, entry, tlhandle);
+ }
+
+ // No valid entry in the ARP table. First we'll see if we're sending to a
+ // broadcast address or multicast address. If not, we'll try to create
+ // an entry in the table and get an ARP resolution going. ARPLookup returns
+ // with the table lock held when it fails, we'll free it here.
+ CTEFreeLock(&ai->ai_ARPTblLock, tlhandle);
+
+ if (ARPSendBCast(ai, Destination, Packet, &Status))
+ return Status;
+
+ entry = CreateARPTableEntry(ai, Destination, &lhandle);
+ if (entry != NULL) {
+ if (entry->ate_state <= ARP_RESOLVING) { // Newly created entry.
+
+ // Someone else could have raced in and created the entry between
+ // the time we free the lock and the time we called
+ // CreateARPTableEntry(). We check this by looking at the packet
+ // on the entry. If there is no old packet we'll ARP. If there is,
+ // we'll call ARPSendData to figure out what to do.
+
+ if (entry->ate_packet == NULL) {
+ entry->ate_packet = Packet;
+ CTEFreeLock(&entry->ate_lock, lhandle);
+ SendARPRequest(ai, Destination, entry->ate_state, NULL, TRUE);
+ // We don't know the state of the entry - we've freed the lock
+ // and yielded, and it could conceivably have timed out by now,
+ // or SendARPRequest could have failed, etc. We could take the
+ // lock, check the status from SendARPRequest, see if it's
+ // still the same packet, and then make a decision on the
+ // return value, but it's easiest just to return pending. If
+ // SendARPRequest failed, the entry will time out anyway.
+ return NDIS_STATUS_PENDING;
+ } else
+ return ARPSendData(ai, Packet, entry, lhandle);
+
+ } else {
+ if (entry->ate_state == ARP_GOOD) // Yow! A valid entry.
+ return ARPSendData(ai, Packet, entry, lhandle);
+ else { // An invalid entry!
+ CTEFreeLock(&entry->ate_lock, lhandle);
+ return NDIS_STATUS_RESOURCES;
+ }
+ }
+ } else // Couldn't create an entry.
+ return NDIS_STATUS_RESOURCES;
+
+}
+
+//* RemoveARPTableEntry - Delete an entry from the ARP table.
+//
+// This is a simple utility function to delete an entry from the ATP table. We
+// assume locks are held on both the table and the entry.
+//
+// Entry: Previous - The entry immediately before the one to be deleted.
+// Entry - The entry to be deleted.
+//
+// Returns: Nothing.
+//
+void
+RemoveARPTableEntry(ARPTableEntry *Previous, ARPTableEntry *Entry)
+{
+ RouteCacheEntry *RCE; // Pointer to route cache entry
+ ARPContext *AC;
+
+ RCE = Entry->ate_rce;
+ // Loop through and invalidate all RCEs on this ATE.
+ while (RCE != (RouteCacheEntry *)NULL) {
+ AC = (ARPContext *)RCE->rce_context;
+ AC->ac_ate = (ARPTableEntry *)NULL;
+ RCE = AC->ac_next;
+ }
+
+ // Splice this guy out of the list.
+ Previous->ate_next = Entry->ate_next;
+}
+
+//* ARPXferData - Transfer data on behalf on an upper later protocol.
+//
+// This routine is called by the upper layer when it needs to transfer data
+// from an NDIS driver. We just map his call down.
+//
+// Entry: Context - Context value we gave to IP (really a pointer to an AI).
+// MACContext - Context value MAC gave us on a receive.
+// MyOffset - Packet offset we gave to the protocol earlier.
+// ByteOffset - Byte offset into packet protocol wants transferred.
+// BytesWanted - Number of bytes to transfer.
+// Packet - Pointer to packet to be used for transferring.
+// Transferred - Pointer to where to return bytes transferred.
+//
+// Returns: NDIS_STATUS of command.
+//
+NDIS_STATUS
+ARPXferData(void *Context, NDIS_HANDLE MACContext, uint MyOffset, uint ByteOffset,
+ uint BytesWanted, PNDIS_PACKET Packet, uint *Transferred)
+{
+ ARPInterface *Interface = (ARPInterface *)Context;
+ NDIS_STATUS Status;
+
+ NdisTransferData(&Status, Interface->ai_handle, MACContext, ByteOffset+MyOffset,
+ BytesWanted, Packet, Transferred);
+
+ return Status;
+}
+
+
+//* ARPClose - Close an adapter.
+//
+// Called by IP when it wants to close an adapter, presumably due to an error condition.
+// We'll close the adapter, but we won't free any memory.
+//
+// Entry: Context - Context value we gave him earlier.
+//
+// Returns: Nothing.
+//
+void
+ARPClose(void *Context)
+{
+ ARPInterface *Interface = (ARPInterface *)Context;
+ NDIS_STATUS Status;
+ CTELockHandle LockHandle;
+ NDIS_HANDLE Handle;
+
+ Interface->ai_operstate = IF_STATUS_DOWN;
+ Interface->ai_state = INTERFACE_DOWN;
+ CTEInitBlockStruc(&Interface->ai_block);
+
+ CTEGetLock(&Interface->ai_lock, &LockHandle);
+ if (Interface->ai_handle != (NDIS_HANDLE)NULL) {
+ Handle = Interface->ai_handle;
+ Interface->ai_handle = NULL;
+ CTEFreeLock(&Interface->ai_lock, LockHandle);
+
+ NdisCloseAdapter(&Status, Handle);
+
+ if (Status == NDIS_STATUS_PENDING)
+ Status = CTEBlock(&Interface->ai_block);
+
+ } else {
+ CTEFreeLock(&Interface->ai_lock, LockHandle);
+ }
+}
+
+//* ARPInvalidate - Notification that an RCE is invalid.
+//
+// Called by IP when an RCE is closed or otherwise invalidated. We look up the ATE for
+// the specified RCE, and then remove the RCE from the ATE list.
+//
+// Entry: Context - Context value we gave him earlier.
+// RCE - RCE to be invalidated
+//
+// Returns: Nothing.
+//
+void
+ARPInvalidate(void *Context, RouteCacheEntry *RCE)
+{
+ ARPInterface *Interface = (ARPInterface *)Context;
+ ARPTableEntry *ATE;
+ CTELockHandle Handle, ATEHandle;
+ ARPContext *AC = (ARPContext *)RCE->rce_context;
+
+ CTEGetLock(&Interface->ai_ARPTblLock, &Handle);
+ if ((ATE = AC->ac_ate) == (ARPTableEntry *)NULL) {
+ CTEFreeLock(&Interface->ai_ARPTblLock, Handle); // No matching ATE.
+ return;
+ }
+
+ CTEGetLock(&ATE->ate_lock, &ATEHandle);
+ ARPRemoveRCE(ATE, RCE);
+ CTEMemSet(RCE->rce_context, 0, RCE_CONTEXT_SIZE);
+ CTEFreeLock(&Interface->ai_ARPTblLock, ATEHandle);
+ CTEFreeLock(&ATE->ate_lock, Handle);
+
+}
+
+//* ARPSetMCastList - Set the multicast address list for the adapter.
+//
+// Called to try and set the multicast reception list for the adapter.
+// We allocate a buffer big enough to hold the new address list, and format
+// the address list into the buffer. Then we submit the NDIS request to set
+// the list. If we can't set the list because the multicast address list is
+// full we'll put the card into all multicast mode.
+//
+// Input: Interface - Interface on which to set list.
+//
+// Returns: NDIS_STATUS of attempt.
+//
+NDIS_STATUS
+ARPSetMCastList(ARPInterface *Interface)
+{
+ CTELockHandle Handle;
+ uchar *MCastBuffer, *CurrentPtr;
+ uint MCastSize;
+ NDIS_STATUS Status;
+ uint i;
+ ARPMCastAddr *AddrPtr;
+ IPAddr UNALIGNED *Temp;
+
+ CTEGetLock(&Interface->ai_lock, &Handle);
+ MCastSize = Interface->ai_mcastcnt * ARP_802_ADDR_LENGTH;
+ if (MCastSize != 0)
+ MCastBuffer = CTEAllocMem(MCastSize);
+ else
+ MCastBuffer = NULL;
+
+ if (MCastBuffer != NULL || MCastSize == 0) {
+ // Got the buffer. Loop through, building the list.
+ AddrPtr = Interface->ai_mcast;
+
+ CurrentPtr = MCastBuffer;
+
+ for (i = 0; i < Interface->ai_mcastcnt; i++) {
+ CTEAssert(AddrPtr != NULL);
+
+ if (Interface->ai_media == NdisMedium802_3) {
+
+ CTEMemCopy(CurrentPtr, ENetMcst, ARP_802_ADDR_LENGTH);
+ Temp = (IPAddr UNALIGNED *)(CurrentPtr + 2);
+ *Temp |= AddrPtr->ama_addr;
+ } else
+ if (Interface->ai_media == NdisMediumFddi) {
+ CTEMemCopy(CurrentPtr, ((FDDIHeader *)FDDIMcst)->fh_daddr,
+ ARP_802_ADDR_LENGTH);
+ Temp = (IPAddr UNALIGNED *)(CurrentPtr + 2);
+ *Temp |= AddrPtr->ama_addr;
+ } else
+ DEBUGCHK;
+
+ CurrentPtr += ARP_802_ADDR_LENGTH;
+ AddrPtr = AddrPtr->ama_next;
+ }
+
+ CTEFreeLock(&Interface->ai_lock, Handle);
+
+ // We're built the list. Now give it to the driver to handle.
+ if (Interface->ai_media == NdisMedium802_3) {
+ Status = DoNDISRequest(Interface, NdisRequestSetInformation,
+ OID_802_3_MULTICAST_LIST, MCastBuffer, MCastSize, NULL);
+ } else
+ if (Interface->ai_media == NdisMediumFddi) {
+ Status = DoNDISRequest(Interface, NdisRequestSetInformation,
+ OID_FDDI_LONG_MULTICAST_LIST, MCastBuffer, MCastSize, NULL);
+ } else
+ DEBUGCHK;
+
+ if (MCastBuffer != NULL) {
+ CTEFreeMem(MCastBuffer);
+ }
+
+ if (Status == NDIS_STATUS_MULTICAST_FULL) {
+ // Multicast list is full. Try to set the filter to all multicasts.
+ Interface->ai_pfilter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
+
+ Status = DoNDISRequest(Interface, NdisRequestSetInformation,
+ OID_GEN_CURRENT_PACKET_FILTER, &Interface->ai_pfilter,
+ sizeof(uint), NULL);
+ }
+
+ } else {
+ CTEFreeLock(&Interface->ai_lock, Handle);
+ Status = NDIS_STATUS_RESOURCES;
+ }
+
+ return Status;
+
+}
+
+//* ARPFindMCast - Find a multicast address structure on our list.
+//
+// Called as a utility to find a multicast address structure. If we find
+// it, we return a pointer to it and it's predecessor. Otherwise we return
+// NULL. We assume the caller holds the lock on the interface already.
+//
+// Input: Interface - Interface to search.
+// Addr - Addr to find.
+// Prev - Where to return previous pointer.
+//
+// Returns: Pointer if we find one, NULL otherwise.
+//
+ARPMCastAddr *
+ARPFindMCast(ARPInterface *Interface, IPAddr Addr, ARPMCastAddr **Prev)
+{
+ ARPMCastAddr *AddrPtr, *PrevPtr;
+
+ PrevPtr = STRUCT_OF(ARPMCastAddr, &Interface->ai_mcast, ama_next);
+ AddrPtr = PrevPtr->ama_next;
+ while (AddrPtr != NULL) {
+ if (IP_ADDR_EQUAL(AddrPtr->ama_addr, Addr))
+ break;
+ else {
+ PrevPtr = AddrPtr;
+ AddrPtr = PrevPtr->ama_next;
+ }
+ }
+
+ *Prev = PrevPtr;
+ return AddrPtr;
+}
+
+//* ARPDelMCast - Delete a multicast address.
+//
+// Called when we want to delete a multicast address. We look for a matching
+// (masked) address. If we find one, we'll dec. the reference count and if
+// it goes to 0 we'll pull him from the list and reset the multicast list.
+//
+// Input: Interface - Interface on which to act.
+// Addr - Address to be deleted.
+//
+// Returns: TRUE if it worked, FALSE otherwise.
+//
+uint
+ARPDelMCast(ARPInterface *Interface, IPAddr Addr)
+{
+ ARPMCastAddr *AddrPtr, *PrevPtr;
+ CTELockHandle Handle;
+ uint Status = TRUE;
+
+ // When we support TR (RFC 1469) fully we'll need to change this.
+ if (Interface->ai_media == NdisMedium802_3 || Interface->ai_media ==
+ NdisMediumFddi) {
+ // This is an interface that supports mcast addresses.
+ Addr &= ARP_MCAST_MASK;
+
+ CTEGetLock(&Interface->ai_lock, &Handle);
+ AddrPtr = ARPFindMCast(Interface, Addr, &PrevPtr);
+ if (AddrPtr != NULL) {
+ // We found one. Dec. his refcnt, and if it's 0 delete him.
+ (AddrPtr->ama_refcnt)--;
+ if (AddrPtr->ama_refcnt == 0) {
+ // He's done.
+ PrevPtr->ama_next = AddrPtr->ama_next;
+ (Interface->ai_mcastcnt)--;
+ CTEFreeLock(&Interface->ai_lock, Handle);
+ CTEFreeMem(AddrPtr);
+ ARPSetMCastList(Interface);
+ CTEGetLock(&Interface->ai_lock, &Handle);
+ }
+ } else
+ Status = FALSE;
+
+ CTEFreeLock(&Interface->ai_lock, Handle);
+ }
+
+ return Status;
+}
+//* ARPAddMCast - Add a multicast address.
+//
+// Called when we want to start receiving a multicast address. We'll mask
+// the address and look it up in our address list. If we find it, we'll just
+// bump the reference count. Otherwise we'll try to create one and put him
+// on the list. In that case we'll need to set the multicast address list for
+// the adapter.
+//
+// Input: Interface - Interface to set on.
+// Addr - Address to set.
+//
+// Returns: TRUE if we succeed, FALSE if we fail.
+//
+uint
+ARPAddMCast(ARPInterface *Interface, IPAddr Addr)
+{
+ ARPMCastAddr *AddrPtr, *PrevPtr;
+ CTELockHandle Handle;
+ uint Status = TRUE;
+
+
+ if (Interface->ai_state != INTERFACE_UP)
+ return FALSE;
+
+ // BUGBUG Currently we don't do anything with token ring, since we send
+ // all mcasts as TR broadcasts. When we comply with RFC 1469 we'll need to
+ // fix this.
+ if (Interface->ai_media == NdisMedium802_3 || Interface->ai_media ==
+ NdisMediumFddi) {
+ // This is an interface that supports mcast addresses.
+ Addr &= ARP_MCAST_MASK;
+
+ CTEGetLock(&Interface->ai_lock, &Handle);
+ AddrPtr = ARPFindMCast(Interface, Addr, &PrevPtr);
+ if (AddrPtr != NULL) {
+ // We found one, just bump refcnt.
+ (AddrPtr->ama_refcnt)++;
+ } else {
+ // Didn't find one. Allocate space for one, link him in, and
+ // try to set the list.
+ AddrPtr = CTEAllocMem(sizeof(ARPMCastAddr));
+ if (AddrPtr != NULL) {
+ // Got one. Link him in.
+ AddrPtr->ama_addr = Addr;
+ AddrPtr->ama_refcnt = 1;
+ AddrPtr->ama_next = Interface->ai_mcast;
+ Interface->ai_mcast = AddrPtr;
+ (Interface->ai_mcastcnt)++;
+ CTEFreeLock(&Interface->ai_lock, Handle);
+
+ // Now try to set the list.
+ if (ARPSetMCastList(Interface) != NDIS_STATUS_SUCCESS) {
+ // Couldn't set the list. Call the delete routine to delete
+ // the address we just tried to set.
+ Status = ARPDelMCast(Interface, Addr);
+ if (!Status)
+ DEBUGCHK;
+ Status = FALSE;
+ }
+ CTEGetLock(&Interface->ai_lock, &Handle);
+ } else
+ Status = FALSE; // Couldn't get memory.
+ }
+
+ // We've done out best. Free the lock and return.
+ CTEFreeLock(&Interface->ai_lock, Handle);
+ }
+
+ return Status;
+}
+
+//* ARPAddAddr - Add an address to the ARP table.
+//
+// This routine is called by IP to add an address as a local address, or
+// or specify the broadcast address for this interface.
+//
+// Entry: Context - Context we gave IP earlier (really an ARPInterface pointer)
+// Type - Type of address (local, p-arp, multicast, or
+// broadcast).
+// Address - Broadcast IP address to be added.
+// Mask - Mask for address.
+//
+// Returns: 0 if we failed, non-zero otherwise
+//
+uint
+ARPAddAddr(void *Context, uint Type, IPAddr Address, IPMask Mask, void *Context2)
+{
+ ARPInterface *Interface = (ARPInterface *)Context;
+ CTELockHandle Handle;
+
+ if (Type != LLIP_ADDR_LOCAL && Type != LLIP_ADDR_PARP) {
+ // Not a local address, must be broadcast or multicast.
+
+ if (Type == LLIP_ADDR_BCAST) {
+ Interface->ai_bcast = Address;
+ return TRUE;
+ } else
+ if (Type == LLIP_ADDR_MCAST) {
+ return ARPAddMCast(Interface, Address);
+ } else
+ return FALSE;
+ } else { // This is a local address.
+ CTEGetLock(&Interface->ai_lock, &Handle);
+ if (Type != LLIP_ADDR_PARP) {
+ uint RetStatus = FALSE;
+ uint ArpForSelf = FALSE;
+
+ if (IP_ADDR_EQUAL(Interface->ai_ipaddr.aia_addr, 0)) {
+ Interface->ai_ipaddr.aia_addr = Address;
+ Interface->ai_ipaddr.aia_mask = Mask;
+ Interface->ai_ipaddr.aia_age = ARPADDR_NEW_LOCAL;
+ if (Interface->ai_state == INTERFACE_UP) {
+ Interface->ai_ipaddr.aia_context = Context2;
+ ArpForSelf = TRUE;
+ } else {
+ Interface->ai_ipaddr.aia_context = NULL;
+ }
+ RetStatus = TRUE;
+ } else {
+ ARPIPAddr *NewAddr;
+
+ NewAddr = CTEAllocMem(sizeof(ARPIPAddr));
+ if (NewAddr != (ARPIPAddr *)NULL) {
+ NewAddr->aia_addr = Address;
+ NewAddr->aia_mask = Mask;
+ NewAddr->aia_age = ARPADDR_NEW_LOCAL;
+ NewAddr->aia_next = Interface->ai_ipaddr.aia_next;
+ if (Interface->ai_state == INTERFACE_UP) {
+ NewAddr->aia_context = Context2;
+ ArpForSelf = TRUE;
+ } else {
+ NewAddr->aia_context = NULL;
+ }
+
+ Interface->ai_ipaddr.aia_next = NewAddr;
+ RetStatus = TRUE;
+ }
+ }
+
+ CTEFreeLock(&Interface->ai_lock, Handle);
+ // ARP for the address we've added, to see it it already exists.
+ if (RetStatus == TRUE && ArpForSelf == TRUE) {
+ SendARPRequest(Interface, Address, ARP_RESOLVING_GLOBAL,
+ NULL, TRUE);
+ return IP_PENDING;
+ }
+
+ return RetStatus;
+ } else if (Type == LLIP_ADDR_PARP) {
+ ARPPArpAddr *NewPArp;
+
+ // He's adding a proxy arp address.
+ NewPArp = CTEAllocMem(sizeof(ARPPArpAddr));
+ if (NewPArp != NULL) {
+ NewPArp->apa_addr = Address;
+ NewPArp->apa_mask = Mask;
+ NewPArp->apa_next = Interface->ai_parpaddr;
+ Interface->ai_parpaddr = NewPArp;
+ Interface->ai_parpcount++;
+ CTEFreeLock(&Interface->ai_lock, Handle);
+ return TRUE;
+ }
+ CTEFreeLock(&Interface->ai_lock, Handle);
+ return FALSE;
+ }
+ }
+
+}
+
+//* ARPDeleteAddr - Delete a local or proxy address.
+//
+// Called to delete a local or proxy address.
+//
+// Entry: Context - An ARPInterface pointer.
+// Type - Type of address (local or p-arp).
+// Address - IP address to be deleted.
+// Mask - Mask for address. Used only for deleting proxy-ARP
+// entries.
+//
+// Returns: 0 if we failed, non-zero otherwise
+//
+uint
+ARPDeleteAddr(void *Context, uint Type, IPAddr Address, IPMask Mask)
+{
+ ARPInterface *Interface = (ARPInterface *)Context;
+ CTELockHandle Handle;
+ ARPIPAddr *DelAddr, *PrevAddr;
+ ARPPArpAddr *DelPAddr, *PrevPAddr;
+
+ if (Type == LLIP_ADDR_LOCAL) {
+ CTEGetLock(&Interface->ai_lock, &Handle);
+
+ if (IP_ADDR_EQUAL(Interface->ai_ipaddr.aia_addr, Address)) {
+ Interface->ai_ipaddr.aia_addr = NULL_IP_ADDR;
+ CTEFreeLock(&Interface->ai_lock, Handle);
+ return TRUE;
+ } else {
+ PrevAddr = STRUCT_OF(ARPIPAddr, &Interface->ai_ipaddr, aia_next);
+ DelAddr = PrevAddr->aia_next;
+ while (DelAddr != NULL)
+ if (IP_ADDR_EQUAL(DelAddr->aia_addr, Address))
+ break;
+ else {
+ PrevAddr = DelAddr;
+ DelAddr = DelAddr->aia_next;
+ }
+
+ if (DelAddr != NULL) {
+ PrevAddr->aia_next = DelAddr->aia_next;
+ CTEFreeMem(DelAddr);
+ }
+ CTEFreeLock(&Interface->ai_lock, Handle);
+ return (DelAddr != NULL);
+ }
+ } else if (Type == LLIP_ADDR_PARP) {
+ CTEGetLock(&Interface->ai_lock, &Handle);
+ PrevPAddr = STRUCT_OF(ARPPArpAddr, &Interface->ai_parpaddr, apa_next);
+ DelPAddr = PrevPAddr->apa_next;
+ while (DelPAddr != NULL)
+ if (IP_ADDR_EQUAL(DelPAddr->apa_addr, Address) &&
+ DelPAddr->apa_mask == Mask)
+ break;
+ else {
+ PrevPAddr = DelPAddr;
+ DelPAddr = DelPAddr->apa_next;
+ }
+
+ if (DelPAddr != NULL) {
+ PrevPAddr->apa_next = DelPAddr->apa_next;
+ Interface->ai_parpcount--;
+ CTEFreeMem(DelPAddr);
+ }
+ CTEFreeLock(&Interface->ai_lock, Handle);
+ return (DelPAddr != NULL);
+ } else
+ if (Type == LLIP_ADDR_MCAST)
+ return ARPDelMCast(Interface, Address);
+ else
+ return FALSE;
+}
+
+//* ARPTimeout - ARP timeout routine.
+//
+// This is the timeout routine that is called periodically. We scan the ARP table, looking
+// for invalid entries that can be removed.
+//
+// Entry: Timer - Pointer to the timer that just fired.
+// Context - Pointer to the interface to be timed out.
+//
+// Returns: Nothing.
+//
+void
+ARPTimeout(CTEEvent *Timer, void *Context)
+{
+ ARPInterface *Interface = (ARPInterface *)Context; // Our interface.
+ ARPTable *Table;
+ ARPTableEntry *Current, *Previous;
+ int i; // Index variable.
+ ulong Now = CTESystemUpTime(), ValidTime;
+ CTELockHandle tblhandle, entryhandle;
+ uchar Deleted;
+ PNDIS_PACKET PList = (PNDIS_PACKET)NULL;
+ ARPIPAddr *Addr;
+
+ // Walk down the list of addresses, decrementing the age.
+ CTEGetLock(&Interface->ai_lock, &tblhandle);
+
+ Addr = &Interface->ai_ipaddr;
+
+ do {
+ if (Addr->aia_age != ARPADDR_OLD_LOCAL) {
+ (Addr->aia_age)--;
+ if (Addr->aia_age == ARPADDR_OLD_LOCAL) {
+ if (Addr->aia_context != NULL) {
+ SetAddrControl *SAC;
+ SetAddrRtn Rtn;
+
+ SAC = (SetAddrControl *)Addr->aia_context;
+ Rtn = (SetAddrRtn)SAC->sac_rtn;
+ CTEFreeLock(&Interface->ai_lock, tblhandle);
+ (*Rtn)(SAC, IP_SUCCESS);
+ CTEGetLock(&Interface->ai_lock, &tblhandle);
+ Addr->aia_context = NULL;
+ }
+ } else {
+ CTEFreeLock(&Interface->ai_lock, tblhandle);
+ SendARPRequest(Interface, Addr->aia_addr, ARP_RESOLVING_GLOBAL,
+ NULL, TRUE);
+ CTEGetLock(&Interface->ai_lock, &tblhandle);
+ }
+ }
+
+ Addr = Addr->aia_next;
+ } while (Addr != NULL);
+
+ CTEFreeLock(&Interface->ai_lock, tblhandle);
+
+ // Loop through the ARP table for this interface, and delete stale entries.
+ CTEGetLock(&Interface->ai_ARPTblLock, &tblhandle);
+ Table = Interface->ai_ARPTbl;
+ for (i = 0; i < ARP_TABLE_SIZE;i++) {
+ Previous = (ARPTableEntry *)((uchar *)&((*Table)[i]) - offsetof(struct ARPTableEntry, ate_next));
+ Current = (*Table)[i];
+ while (Current != (ARPTableEntry *)NULL) {
+ CTEGetLock(&Current->ate_lock, &entryhandle);
+ Deleted = 0;
+
+ if (Current->ate_state == ARP_GOOD) {
+ //
+ // The ARP entry is valid for ARP_VALID_TIMEOUT by default.
+ // If a cache life greater than ARP_VALID_TIMEOUT has been
+ // configured, we'll make the entry valid for that time.
+ //
+ ValidTime = ArpCacheLife * ARP_TIMER_TIME;
+
+ if (ValidTime < ARP_MIN_VALID_TIMEOUT) {
+ ValidTime = ARP_MIN_VALID_TIMEOUT;
+ }
+ }
+ else {
+ ValidTime = ARP_RESOLVE_TIMEOUT;
+ }
+
+ if (Current->ate_valid != ALWAYS_VALID &&
+ ( ((Now - Current->ate_valid) > ValidTime) ||
+ (Current->ate_state == ARP_GOOD &&
+ !(--(Current->ate_useticks))))) {
+
+ if (Current->ate_state != ARP_RESOLVING_LOCAL) {
+ // Really need to delete this guy.
+ PNDIS_PACKET Packet = Current->ate_packet;
+
+ if (Packet != (PNDIS_PACKET)NULL) {
+ ((PacketContext *)Packet->ProtocolReserved)->pc_common.pc_link
+ = PList;
+ PList = Packet;
+ }
+ RemoveARPTableEntry(Previous, Current);
+ Interface->ai_count--;
+ Deleted = 1;
+ } else {
+ IPAddr Dest = Current->ate_dest;
+ // This entry is only resoving locally, presumably this is
+ // token ring. We'll need to transmit a 'global' resolution
+ // now.
+ CTEAssert(Interface->ai_media == NdisMedium802_5);
+
+ Now = CTESystemUpTime();
+ Current->ate_valid = Now;
+ Current->ate_state = ARP_RESOLVING_GLOBAL;
+ CTEFreeLock(&Current->ate_lock, entryhandle);
+ CTEFreeLock(&Interface->ai_ARPTblLock, tblhandle);
+ // Send a global request.
+ SendARPRequest(Interface, Dest, ARP_RESOLVING_GLOBAL,
+ NULL, TRUE);
+ CTEGetLock(&Interface->ai_ARPTblLock, &tblhandle);
+
+ // Since we've freed the locks, we need to start over from
+ // the start of this chain.
+ Previous = STRUCT_OF(ARPTableEntry, &((*Table)[i]),
+ ate_next);
+ Current = (*Table)[i];
+ continue;
+
+ }
+ }
+
+ // If we deleted the entry, leave the previous pointer alone, advance the
+ // current pointer, and free the memory. Otherwise move both pointers forward.
+ // We can free the entry lock now because the next pointers are protected by
+ // the table lock, and we've removed it from the list so nobody else should
+ // find it anyway.
+ CTEFreeLock(&Current->ate_lock, entryhandle);
+ if (Deleted) {
+ ARPTableEntry *Temp = Current;
+ Current = Current->ate_next;
+ CTEFreeMem(Temp);
+ } else {
+ Previous = Current;
+ Current = Current->ate_next;
+ }
+ }
+ }
+
+ CTEFreeLock(&Interface->ai_ARPTblLock, tblhandle);
+
+ while (PList != (PNDIS_PACKET)NULL) {
+ PNDIS_PACKET Packet = PList;
+
+ PList = ((PacketContext *)Packet->ProtocolReserved)->pc_common.pc_link;
+ IPSendComplete(Interface->ai_context, Packet, NDIS_STATUS_SUCCESS);
+ }
+
+ CTEStartTimer(&Interface->ai_timer, ARP_TIMER_TIME, ARPTimeout, Interface);
+}
+
+//* IsLocalAddr - Return info. about local status of address.
+//
+// Called when we need info. about whether or not a particular address is
+// local. We return info about whether or not it is, and if it is how old
+// it is.
+//
+// Entry: Interface - Pointer to interface structure to be searched.
+// Address - Address in question.
+//
+// Returns: ARPADDR_*, for how old it is.
+//
+//
+uint
+IsLocalAddr(ARPInterface *Interface, IPAddr Address)
+{
+ CTELockHandle Handle;
+ ARPIPAddr *CurrentAddr;
+ uint Age;
+
+ CTEGetLock(&Interface->ai_lock, &Handle);
+
+ CurrentAddr = &Interface->ai_ipaddr;
+ Age = ARPADDR_NOT_LOCAL;
+
+ do {
+ if (CurrentAddr->aia_addr == Address) {
+ Age = CurrentAddr->aia_age;
+ break;
+ }
+ CurrentAddr = CurrentAddr->aia_next;
+ } while (CurrentAddr != NULL);
+
+ CTEFreeLock(&Interface->ai_lock, Handle);
+ return Age;
+}
+
+//* ARPLocalAddr - Determine whether or not a given address if local.
+//
+// This routine is called when we receive an incoming packet and need to determine whether
+// or not it's local. We look up the provided address on the specified interface.
+//
+// Entry: Interface - Pointer to interface structure to be searched.
+// Address - Address in question.
+//
+// Returns: TRUE if it is a local address, FALSE if it's not.
+//
+uchar
+ARPLocalAddr(ARPInterface *Interface, IPAddr Address)
+{
+ CTELockHandle Handle;
+ ARPPArpAddr *CurrentPArp;
+ IPMask Mask, NetMask;
+ IPAddr MatchAddress;
+
+ // First, see if he's a local (not-proxy) address.
+ if (IsLocalAddr(Interface, Address) != ARPADDR_NOT_LOCAL)
+ return TRUE;
+
+ CTEGetLock(&Interface->ai_lock, &Handle);
+
+ // Didn't find him in out local address list. See if he exists on our
+ // proxy ARP list.
+ for (CurrentPArp = Interface->ai_parpaddr; CurrentPArp != NULL;
+ CurrentPArp = CurrentPArp->apa_next) {
+ // See if this guy matches.
+ Mask = CurrentPArp->apa_mask;
+ MatchAddress = Address & Mask;
+ if (IP_ADDR_EQUAL(CurrentPArp->apa_addr, MatchAddress)) {
+ // He matches. We need to make a few more checks to make sure
+ // we don't reply to a broadcast address.
+ if (Mask == HOST_MASK) {
+ // We're matching the whole address, so it's OK.
+ CTEFreeLock(&Interface->ai_lock, Handle);
+ return TRUE;
+ }
+ // See if the non-mask part it all-zeros. Since the mask presumably
+ // covers a subnet, this trick will prevent us from replying to
+ // a zero host part.
+ if (IP_ADDR_EQUAL(MatchAddress, Address))
+ continue;
+
+ // See if the host part is all ones.
+ if (IP_ADDR_EQUAL(Address, MatchAddress | (IP_LOCAL_BCST & ~Mask)))
+ continue;
+
+ // If the mask we were given is not the net mask for this address,
+ // we'll need to repeat the above checks.
+ NetMask = IPNetMask(Address);
+ if (NetMask != Mask) {
+
+ MatchAddress = Address & NetMask;
+ if (IP_ADDR_EQUAL(MatchAddress, Address))
+ continue;
+
+ if (IP_ADDR_EQUAL(Address, MatchAddress |
+ (IP_LOCAL_BCST & ~NetMask)))
+ continue;
+ }
+
+ // If we get to this point we've passed all the tests, so it's
+ // local.
+ CTEFreeLock(&Interface->ai_lock, Handle);
+ return TRUE;
+ }
+ }
+
+ CTEFreeLock(&Interface->ai_lock, Handle);
+ return FALSE;
+
+}
+
+
+#ifdef VXD
+
+
+#ifndef CHICAGO
+extern void DisplayPopup(uchar *Msg);
+uchar CMsg1[] = "The system has detected a conflict for IP address ";
+uchar CMsg2[] = " with the system having hardware address ";
+uchar CMsg3[] = ". The local interface has been disabled";
+
+uchar CMsg[sizeof(CMsg1) - 1 + sizeof(CMsg2) - 1 + sizeof(CMsg3) - 1 +
+ ((sizeof(IPAddr) * 4) - 1) + ((ARP_802_ADDR_LENGTH * 3) - 1)
+ + 1 + 1];
+#else
+extern void NotifyConflictProc(CTEEvent *Event, void *Context);
+extern void DisplayConflictPopup(uchar *IPAddr, uchar *HWAddr, uint Shutoff);
+#endif // CHICAGO
+
+#endif // NT
+
+//* NotifyConflictProc - Notify the user of an address conflict.
+//
+// Called when we need to notify the user of an address conflict. The
+// exact mechanism is system dependent, but generally involves a popup.
+//
+// Input: Event - Event that fired.
+// Context - Pointer to ARPNotifyStructure.
+//
+// Returns: Nothing.
+//
+void
+#ifndef CHICAGO
+NotifyConflictProc(CTEEvent *Event, void *Context)
+#else
+DisplayConflictProc(void *Context)
+#endif
+{
+#ifdef VXD
+ uchar IPAddrBuffer[(sizeof(IPAddr) * 4)];
+ uchar HWAddrBuffer[(ARP_802_ADDR_LENGTH * 3)];
+ uint i;
+ uint IPAddrCharCount;
+ ARPNotifyStruct *NotifyStruct = (ARPNotifyStruct *)Context;
+
+#ifndef CHICAGO
+ uint TotalSize;
+
+ CTEMemCopy(CMsg, CMsg1, sizeof(CMsg1) - 1);
+ TotalSize = sizeof(CMsg1) - 1;
+#endif
+
+ // Convert the IP address into a string.
+ IPAddrCharCount = 0;
+
+ for (i = 0; i < sizeof(IPAddr); i++) {
+ uint CurrentByte;
+
+ CurrentByte = NotifyStruct->ans_addr & 0xff;
+ if (CurrentByte > 99) {
+ IPAddrBuffer[IPAddrCharCount++] = (CurrentByte / 100) + '0';
+ CurrentByte %= 100;
+ IPAddrBuffer[IPAddrCharCount++] = (CurrentByte / 10) + '0';
+ CurrentByte %= 10;
+ } else if (CurrentByte > 9) {
+ IPAddrBuffer[IPAddrCharCount++] = (CurrentByte / 10) + '0';
+ CurrentByte %= 10;
+ }
+
+ IPAddrBuffer[IPAddrCharCount++] = CurrentByte + '0';
+ if (i != (sizeof(IPAddr) - 1))
+ IPAddrBuffer[IPAddrCharCount++] = '.';
+
+ NotifyStruct->ans_addr >>= 8;
+ }
+
+#ifndef CHICAGO
+ CTEMemCopy(&CMsg[TotalSize], IPAddrBuffer, IPAddrCharCount);
+ TotalSize += IPAddrCharCount;
+
+ CTEMemCopy(&CMsg[TotalSize], CMsg2, sizeof(CMsg2) - 1);
+ TotalSize += sizeof(CMsg2) - 1;
+#else
+ IPAddrBuffer[IPAddrCharCount] = '\0';
+#endif
+
+ for (i = 0; i < NotifyStruct->ans_hwaddrlen; i++) {
+ uchar CurrentHalf;
+
+ CurrentHalf = NotifyStruct->ans_hwaddr[i] >> 4;
+ HWAddrBuffer[i*3] = (uchar)(CurrentHalf < 10 ? CurrentHalf + '0' :
+ (CurrentHalf - 10) + 'A');
+ CurrentHalf = NotifyStruct->ans_hwaddr[i] & 0x0f;
+ HWAddrBuffer[(i*3)+1] = (uchar)(CurrentHalf < 10 ? CurrentHalf + '0' :
+ (CurrentHalf - 10) + 'A');
+ if (i != (NotifyStruct->ans_hwaddrlen - 1))
+ HWAddrBuffer[(i*3)+2] = ':';
+ }
+
+#ifndef CHICAGO
+ CTEMemCopy(&CMsg[TotalSize], HWAddrBuffer,
+ (NotifyStruct->ans_hwaddrlen * 3) - 1);
+ TotalSize += (NotifyStruct->ans_hwaddrlen * 3) - 1;
+
+ if (NotifyStruct->ans_shutoff) {
+ CTEMemCopy(&CMsg[TotalSize], CMsg3, sizeof(CMsg3) - 1);
+ TotalSize += sizeof(CMsg3) - 1;
+ }
+
+ CMsg[TotalSize] = '.';
+ CMsg[TotalSize+1] = '\0';
+
+ DisplayPopup(CMsg);
+#else
+ HWAddrBuffer[((NotifyStruct->ans_hwaddrlen * 3) - 1)] = '\0';
+ DisplayConflictPopup(IPAddrBuffer, HWAddrBuffer, NotifyStruct->ans_shutoff);
+ CTEFreeMem(NotifyStruct);
+#endif
+
+#else // VXD
+
+ ARPNotifyStruct *NotifyStruct = (ARPNotifyStruct *)Context;
+ PWCHAR stringList[2];
+ uchar IPAddrBuffer[(sizeof(IPAddr) * 4)];
+ uchar HWAddrBuffer[(ARP_802_ADDR_LENGTH * 3)];
+ WCHAR unicodeIPAddrBuffer[((sizeof(IPAddr) * 4) + 1)];
+ WCHAR unicodeHWAddrBuffer[(ARP_802_ADDR_LENGTH * 3)];
+ uint i;
+ uint IPAddrCharCount;
+ UNICODE_STRING unicodeString;
+ ANSI_STRING ansiString;
+
+
+ PAGED_CODE();
+
+ //
+ // Convert the IP address into a string.
+ //
+ IPAddrCharCount = 0;
+
+ for (i = 0; i < sizeof(IPAddr); i++) {
+ uint CurrentByte;
+
+ CurrentByte = NotifyStruct->ans_addr & 0xff;
+ if (CurrentByte > 99) {
+ IPAddrBuffer[IPAddrCharCount++] = (CurrentByte / 100) + '0';
+ CurrentByte %= 100;
+ IPAddrBuffer[IPAddrCharCount++] = (CurrentByte / 10) + '0';
+ CurrentByte %= 10;
+ } else if (CurrentByte > 9) {
+ IPAddrBuffer[IPAddrCharCount++] = (CurrentByte / 10) + '0';
+ CurrentByte %= 10;
+ }
+
+ IPAddrBuffer[IPAddrCharCount++] = CurrentByte + '0';
+ if (i != (sizeof(IPAddr) - 1))
+ IPAddrBuffer[IPAddrCharCount++] = '.';
+
+ NotifyStruct->ans_addr >>= 8;
+ }
+
+ //
+ // Convert the hardware address into a string.
+ //
+ for (i = 0; i < NotifyStruct->ans_hwaddrlen; i++) {
+ uchar CurrentHalf;
+
+ CurrentHalf = NotifyStruct->ans_hwaddr[i] >> 4;
+ HWAddrBuffer[i*3] = (uchar)(CurrentHalf < 10 ? CurrentHalf + '0' :
+ (CurrentHalf - 10) + 'A');
+ CurrentHalf = NotifyStruct->ans_hwaddr[i] & 0x0f;
+ HWAddrBuffer[(i*3)+1] = (uchar)(CurrentHalf < 10 ? CurrentHalf + '0' :
+ (CurrentHalf - 10) + 'A');
+ if (i != (NotifyStruct->ans_hwaddrlen - 1))
+ HWAddrBuffer[(i*3)+2] = ':';
+ }
+
+ //
+ // Unicode the strings.
+ //
+ *unicodeIPAddrBuffer = *unicodeHWAddrBuffer = UNICODE_NULL;
+
+ unicodeString.Buffer = unicodeIPAddrBuffer;
+ unicodeString.Length = 0;
+ unicodeString.MaximumLength = sizeof(WCHAR) * ((sizeof(IPAddr) * 4) + 1);
+ ansiString.Buffer = IPAddrBuffer;
+ ansiString.Length = IPAddrCharCount;
+ ansiString.MaximumLength = IPAddrCharCount;
+
+ RtlAnsiStringToUnicodeString(
+ &unicodeString,
+ &ansiString,
+ FALSE
+ );
+
+ stringList[0] = unicodeIPAddrBuffer;
+
+ unicodeString.Buffer = unicodeHWAddrBuffer;
+ unicodeString.Length = 0;
+ unicodeString.MaximumLength = sizeof(WCHAR) * (ARP_802_ADDR_LENGTH * 3);
+ ansiString.Buffer = HWAddrBuffer;
+ ansiString.Length = (NotifyStruct->ans_hwaddrlen * 3) - 1;
+ ansiString.MaximumLength = NotifyStruct->ans_hwaddrlen * 3;
+
+ RtlAnsiStringToUnicodeString(
+ &unicodeString,
+ &ansiString,
+ FALSE
+ );
+
+ stringList[1] = unicodeHWAddrBuffer;
+
+ //
+ // Kick off a popup and log an event.
+ //
+ if (NotifyStruct->ans_shutoff) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_ADDRESS_CONFLICT1,
+ 0,
+ 2,
+ stringList,
+ 0,
+ NULL
+ );
+
+ IoRaiseInformationalHardError(
+ STATUS_IP_ADDRESS_CONFLICT1,
+ NULL,
+ NULL
+ );
+ }
+ else {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_ADDRESS_CONFLICT2,
+ 0,
+ 2,
+ stringList,
+ 0,
+ NULL
+ );
+
+ IoRaiseInformationalHardError(
+ STATUS_IP_ADDRESS_CONFLICT2,
+ NULL,
+ NULL
+ );
+ }
+
+ CTEFreeMem(NotifyStruct);
+
+#endif // VXD
+
+ return;
+}
+
+
+//* HandleARPPacket - Process an incoming ARP packet.
+//
+// This is the main routine to process an incoming ARP packet. We look at all ARP frames,
+// and update our cache entry for the source address if one exists. Else, if we are the
+// target we create an entry if one doesn't exist. Finally, we'll handle the opcode,
+// responding if this is a request or sending pending packets if this is a response.
+//
+// Entry: Interface - Pointer to interface structure for this adapter.
+// Header - Pointer to header buffer.
+// HeaderSize - Size of header buffer.
+// ARPHdr - ARP packet header.
+// ARPHdrSize - Size of ARP header.
+// ProtOffset - Offset into original data field of arp header.
+// Will be non-zero if we're using SNAP.
+//
+// Returns: An NDIS_STATUS value to be returned to the NDIS driver.
+//
+NDIS_STATUS
+HandleARPPacket(ARPInterface *Interface, void *Header, uint HeaderSize,
+ ARPHeader UNALIGNED *ARPHdr, uint ARPHdrSize, uint ProtOffset)
+{
+ ARPTableEntry *Entry; // Entry in ARP table
+ CTELockHandle LHandle, TableHandle;
+ RC UNALIGNED *SourceRoute = (RC UNALIGNED *)NULL; // Pointer to Source Route info, if any.
+ uint SourceRouteSize = 0;
+ ulong Now = CTESystemUpTime();
+ uchar LocalAddr;
+ uint LocalAddrAge;
+ uchar *SHAddr, *DHAddr;
+ IPAddr UNALIGNED *SPAddr, *DPAddr;
+ ENetHeader *ENetHdr;
+ TRHeader *TRHdr;
+ FDDIHeader *FHdr;
+ ARCNetHeader *AHdr;
+ ushort MaxMTU;
+ uint UseSNAP;
+ SetAddrControl *SAC;
+ SetAddrRtn Rtn = NULL;
+
+ // We examine all ARP frames. If we find the source address in the ARP table, we'll
+ // update the hardware address and set the state to valid. If we're the
+ // target and he's not in the table, we'll add him. Otherwise if we're the
+ // target and this is a response we'll send any pending packets to him.
+ if (Interface->ai_media != NdisMediumArcnet878_2) {
+ if (ARPHdrSize < sizeof(ARPHeader))
+ return NDIS_STATUS_NOT_RECOGNIZED; // Frame is too small.
+
+ if (ARPHdr->ah_hw != net_short(ARP_HW_ENET) &&
+ ARPHdr->ah_hw != net_short(ARP_HW_802))
+ return NDIS_STATUS_NOT_RECOGNIZED; // Wrong HW type
+
+ if (ARPHdr->ah_hlen != ARP_802_ADDR_LENGTH)
+ return NDIS_STATUS_NOT_RECOGNIZED; // Wrong address length.
+
+ if (Interface->ai_media == NdisMedium802_3 && Interface->ai_snapsize == 0)
+ UseSNAP = FALSE;
+ else
+ UseSNAP = (ProtOffset != 0);
+
+ // Figure out SR size on TR.
+ if (Interface->ai_media == NdisMedium802_5) {
+ // Check for source route information. SR is present if the header
+ // size is greater than the standard TR header size. If the SR is
+ // only an RC field, we ignore it because it came from the same
+ // ring which is the same as no SR.
+
+ if ((HeaderSize - sizeof(TRHeader)) > sizeof(RC)) {
+ SourceRouteSize = HeaderSize - sizeof(TRHeader);
+ SourceRoute = (RC UNALIGNED *)((uchar *)Header +
+ sizeof(TRHeader));
+ }
+ }
+
+ SHAddr = ARPHdr->ah_shaddr;
+ SPAddr = (IPAddr UNALIGNED *) &ARPHdr->ah_spaddr;
+ DHAddr = ARPHdr->ah_dhaddr;
+ DPAddr = (IPAddr UNALIGNED *) &ARPHdr->ah_dpaddr;
+
+ } else {
+ if (ARPHdrSize < (sizeof(ARPHeader) - ARCNET_ARPHEADER_ADJUSTMENT))
+ return NDIS_STATUS_NOT_RECOGNIZED; // Frame is too small.
+
+ if (ARPHdr->ah_hw != net_short(ARP_HW_ARCNET))
+ return NDIS_STATUS_NOT_RECOGNIZED; // Wrong HW type
+
+ if (ARPHdr->ah_hlen != 1)
+ return NDIS_STATUS_NOT_RECOGNIZED; // Wrong address length.
+
+ UseSNAP = FALSE;
+ SHAddr = ARPHdr->ah_shaddr;
+ SPAddr = (IPAddr UNALIGNED *)(SHAddr + 1);
+ DHAddr = (uchar *)SPAddr + sizeof(IPAddr);
+ DPAddr = (IPAddr UNALIGNED *)(DHAddr + 1);
+ }
+
+ if (ARPHdr->ah_pro != net_short(ARP_ETYPE_IP))
+ return NDIS_STATUS_NOT_RECOGNIZED; // Unsupported protocol type.
+
+ if (ARPHdr->ah_plen != sizeof(IPAddr))
+ return NDIS_STATUS_NOT_RECOGNIZED;
+
+ if (IP_ADDR_EQUAL(*SPAddr, NULL_IP_ADDR))
+ return NDIS_STATUS_NOT_RECOGNIZED;
+
+ // First, let's see if we have an address conflict.
+ LocalAddrAge = IsLocalAddr(Interface, *SPAddr);
+ if (LocalAddrAge != ARPADDR_NOT_LOCAL) {
+ // The source IP address is one of ours. See if the source h/w address
+ // is ours also.
+ if (ARPHdr->ah_hlen != Interface->ai_addrlen ||
+ CTEMemCmp(SHAddr, Interface->ai_addr, Interface->ai_addrlen) != 0) {
+
+ uint Shutoff;
+ ARPNotifyStruct *NotifyStruct;
+
+ // This isn't from us; we must have an address conflict somewhere.
+ // We always log an error about this. If what triggered this is a
+ // response and the address in conflict is young, we'll turn off
+ // the interface.
+ if (LocalAddrAge != ARPADDR_OLD_LOCAL &&
+ ARPHdr->ah_opcode == net_short(ARP_RESPONSE)) {
+ // Send an arp request with the owner's address to reset the
+ // caches.
+
+ CTEGetLock(&Interface->ai_lock, &LHandle);
+ Interface->ai_state = INTERFACE_DOWN;
+ Interface->ai_adminstate = IF_STATUS_DOWN;
+ if (Interface->ai_ipaddr.aia_context != NULL) {
+ SAC = (SetAddrControl *)Interface->ai_ipaddr.aia_context;
+ Rtn = (SetAddrRtn)SAC->sac_rtn;
+ Interface->ai_ipaddr.aia_context = NULL;
+ }
+ CTEFreeLock(&Interface->ai_lock, LHandle);
+
+ SendARPRequest(Interface, *SPAddr, ARP_RESOLVING_GLOBAL,
+ SHAddr, FALSE); // Send a request.
+
+ Shutoff = TRUE;
+
+ if (Rtn != NULL) {
+ //
+ // this is a dhcp adapter. report the conflict to
+ // CompleteIPSetNTEAddrRequest so IOCTL_IP_SET_ADDRESS will
+ // be completed
+ //
+
+ (*Rtn)(SAC, IP_GENERAL_FAILURE);
+
+ //
+ // don't display a warning dialog in this case - DHCP will
+ // alert the user
+ //
+
+ goto no_dialog;
+ }
+ } else {
+ if (ARPHdr->ah_opcode == net_short(ARP_REQUEST) &&
+ (IsLocalAddr(Interface, *DPAddr) != ARPADDR_NOT_LOCAL)) {
+ // Send a response.
+ SendARPReply(Interface, *SPAddr, *DPAddr, SHAddr,
+ SourceRoute, SourceRouteSize, UseSNAP);
+ }
+ Shutoff = FALSE;
+ }
+
+ // Now allocate a structure, and schedule an event to notify
+ // the user.
+ NotifyStruct = CTEAllocMem(offsetof(ARPNotifyStruct, ans_hwaddr) +
+ ARPHdr->ah_hlen);
+ if (NotifyStruct != NULL) {
+ NotifyStruct->ans_addr = *SPAddr;
+ NotifyStruct->ans_shutoff = Shutoff;
+ NotifyStruct->ans_hwaddrlen = (uint)ARPHdr->ah_hlen;
+ CTEMemCopy(NotifyStruct->ans_hwaddr, SHAddr,
+ ARPHdr->ah_hlen);
+ CTEInitEvent(&NotifyStruct->ans_event, NotifyConflictProc);
+ CTEScheduleEvent(&NotifyStruct->ans_event, NotifyStruct);
+ }
+
+
+ no_dialog:
+ ;
+
+ }
+ return NDIS_STATUS_NOT_RECOGNIZED;
+ }
+
+ CTEGetLock(&Interface->ai_ARPTblLock, &TableHandle);
+ MaxMTU = Interface->ai_mtu;
+
+ LocalAddr = ARPLocalAddr(Interface, *DPAddr);
+ Entry = ARPLookup(Interface, *SPAddr, &LHandle);
+ if (Entry == (ARPTableEntry *)NULL) {
+
+ // Didn't find him, create one if it's for us. The call to ARPLookup
+ // returned with the ARPTblLock held, so we need to free it.
+
+ CTEFreeLock(&Interface->ai_ARPTblLock, TableHandle);
+ if (LocalAddr)
+ Entry = CreateARPTableEntry(Interface, *SPAddr, &LHandle);
+ else
+ return NDIS_STATUS_NOT_RECOGNIZED; // Not in our table, and not for us.
+ } else {
+ CTEFreeLock(&Interface->ai_ARPTblLock, LHandle);
+ LHandle = TableHandle;
+ }
+
+ // At this point, entry should be valid, and we hold the lock on the entry
+ // in LHandle.
+
+ if (Entry != (ARPTableEntry *)NULL) {
+ PNDIS_PACKET Packet; // Packet to be sent.
+
+ // If the entry is already static, we'll want to leave it as static.
+ if (Entry->ate_valid == ALWAYS_VALID)
+ Now = ALWAYS_VALID;
+
+ // OK, we have an entry to use, and hold the lock on it. Fill in the
+ // required fields.
+ switch (Interface->ai_media) {
+
+ case NdisMedium802_3:
+
+ // This is an Ethernet.
+ ENetHdr = (ENetHeader *)Entry->ate_addr;
+
+ CTEMemCopy(ENetHdr->eh_daddr, SHAddr, ARP_802_ADDR_LENGTH);
+ CTEMemCopy(ENetHdr->eh_saddr, Interface->ai_addr,
+ ARP_802_ADDR_LENGTH);
+ ENetHdr->eh_type = net_short(ARP_ETYPE_IP);
+
+ // If we're using SNAP on this entry, copy in the SNAP header.
+ if (UseSNAP) {
+ CTEMemCopy(&Entry->ate_addr[sizeof(ENetHeader)], ARPSNAP,
+ sizeof(SNAPHeader));
+ Entry->ate_addrlength = (uchar)(sizeof(ENetHeader) +
+ sizeof(SNAPHeader));
+ *(ushort UNALIGNED *)&Entry->ate_addr[Entry->ate_addrlength-2] =
+ net_short(ARP_ETYPE_IP);
+ } else
+ Entry->ate_addrlength = sizeof(ENetHeader);
+
+ Entry->ate_state = ARP_GOOD;
+ Entry->ate_valid = Now; // Mark last time he was
+ // valid.
+ break;
+
+ case NdisMedium802_5:
+
+ // This is TR.
+ // For token ring we have to deal with source routing. There's
+ // a special case to handle multiple responses for an all-routes
+ // request - if the entry is currently good and we knew it was
+ // valid recently, we won't update the entry.
+
+
+ if (Entry->ate_state != ARP_GOOD ||
+ (Now - Entry->ate_valid) > ARP_RESOLVE_TIMEOUT) {
+
+ TRHdr = (TRHeader *)Entry->ate_addr;
+
+ // We need to update a TR entry.
+ TRHdr->tr_ac = ARP_AC;
+ TRHdr->tr_fc = ARP_FC;
+ CTEMemCopy(TRHdr->tr_daddr, SHAddr, ARP_802_ADDR_LENGTH);
+ CTEMemCopy(TRHdr->tr_saddr, Interface->ai_addr,
+ ARP_802_ADDR_LENGTH);
+ if (SourceRoute != (RC UNALIGNED *)NULL) {
+ uchar MaxIFieldBits;
+
+ // We have source routing information.
+ CTEMemCopy(&Entry->ate_addr[sizeof(TRHeader)],
+ SourceRoute, SourceRouteSize);
+ MaxIFieldBits = (SourceRoute->rc_dlf & RC_LF_MASK) >>
+ LF_BIT_SHIFT;
+ MaxIFieldBits = MIN(MaxIFieldBits, MAX_LF_BITS);
+ MaxMTU = IFieldSize[MaxIFieldBits];
+
+ // The new MTU we've computed is the max I-field size,
+ // which doesn't include source routing info but
+ // does include SNAP info. Subtract off the SNAP size.
+ MaxMTU -= sizeof(SNAPHeader);
+
+ TRHdr->tr_saddr[0] |= TR_RII;
+ (*(RC UNALIGNED *)&Entry->ate_addr[sizeof(TRHeader)]).rc_dlf ^=
+ RC_DIR;
+ // Make sure it's non-broadcast.
+ (*(RC UNALIGNED *)&Entry->ate_addr[sizeof(TRHeader)]).rc_blen &=
+ RC_LENMASK;
+
+ }
+ CTEMemCopy(&Entry->ate_addr[sizeof(TRHeader)+SourceRouteSize],
+ ARPSNAP, sizeof(SNAPHeader));
+ Entry->ate_state = ARP_GOOD;
+ Entry->ate_valid = Now;
+ Entry->ate_addrlength = (uchar)(sizeof(TRHeader) +
+ SourceRouteSize + sizeof(SNAPHeader));
+ *(ushort *)&Entry->ate_addr[Entry->ate_addrlength-2] =
+ net_short(ARP_ETYPE_IP);
+ }
+ break;
+ case NdisMediumFddi:
+ FHdr = (FDDIHeader *)Entry->ate_addr;
+
+ FHdr->fh_pri = ARP_FDDI_PRI;
+ CTEMemCopy(FHdr->fh_daddr, SHAddr, ARP_802_ADDR_LENGTH);
+ CTEMemCopy(FHdr->fh_saddr, Interface->ai_addr,
+ ARP_802_ADDR_LENGTH);
+ CTEMemCopy(&Entry->ate_addr[sizeof(FDDIHeader)], ARPSNAP,
+ sizeof(SNAPHeader));
+ Entry->ate_addrlength = (uchar)(sizeof(FDDIHeader) +
+ sizeof(SNAPHeader));
+ *(ushort UNALIGNED *)&Entry->ate_addr[Entry->ate_addrlength-2] =
+ net_short(ARP_ETYPE_IP);
+ Entry->ate_state = ARP_GOOD;
+ Entry->ate_valid = Now; // Mark last time he was
+ // valid.
+ break;
+ case NdisMediumArcnet878_2:
+ AHdr = (ARCNetHeader *)Entry->ate_addr;
+ AHdr->ah_saddr = Interface->ai_addr[0];
+ AHdr->ah_daddr = *SHAddr;
+ AHdr->ah_prot = ARP_ARCPROT_IP;
+ Entry->ate_addrlength = sizeof(ARCNetHeader);
+ Entry->ate_state = ARP_GOOD;
+ Entry->ate_valid = Now; // Mark last time he was
+ // valid.
+ break;
+ default:
+ DEBUGCHK;
+ break;
+ }
+
+ // At this point we've updated the entry, and we still hold the lock
+ // on it. If we have a packet that was pending to be sent, send it now.
+ // Otherwise just free the lock.
+
+ Packet = Entry->ate_packet;
+
+ if (Packet != NULL) {
+ // We have a packet to send.
+ CTEAssert(Entry->ate_state == ARP_GOOD);
+
+ Entry->ate_packet = NULL;
+
+ if (ARPSendData(Interface, Packet, Entry, LHandle) != NDIS_STATUS_PENDING)
+ IPSendComplete(Interface->ai_context, Packet, NDIS_STATUS_SUCCESS);
+ } else
+ CTEFreeLock(&Entry->ate_lock, LHandle);
+ }
+
+ // See if the MTU is less than our local one. This should only happen
+ // in the case of token ring source routing.
+ if (MaxMTU < Interface->ai_mtu) {
+ LLIPAddrMTUChange LAM;
+
+ LAM.lam_mtu = MaxMTU;
+ LAM.lam_addr = *SPAddr;
+
+ // It is less. Notify IP.
+ CTEAssert(Interface->ai_media == NdisMedium802_5);
+ IPStatus(Interface->ai_context, LLIP_STATUS_ADDR_MTU_CHANGE,
+ &LAM, sizeof(LLIPAddrMTUChange));
+
+ }
+
+ // At this point we've updated the entry (if we had one), and we've free
+ // all locks. If it's for a local address and it's a request, reply to
+ // it.
+ if (LocalAddr) { // It's for us.
+ if (ARPHdr->ah_opcode == net_short(ARP_REQUEST)) {
+ // It's a request, and we need to respond.
+ SendARPReply(Interface, *SPAddr, *DPAddr,
+ SHAddr, SourceRoute, SourceRouteSize, UseSNAP);
+ }
+ }
+
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+//* InitAdapter - Initialize an adapter.
+//
+// Called when an adapter is open to finish initialization. We set
+// up our lookahead size and packet filter, and we're ready to go.
+//
+// Entry:
+// adapter - Pointer to an adapter structure for the adapter to be
+// initialized.
+//
+// Exit: Nothing
+//
+void
+InitAdapter(ARPInterface *Adapter)
+{
+ NDIS_STATUS Status;
+ CTELockHandle Handle;
+ ARPIPAddr *Addr, *OldAddr;
+
+ if ((Status = DoNDISRequest(Adapter, NdisRequestSetInformation,
+ OID_GEN_CURRENT_LOOKAHEAD, &ARPLookahead, sizeof(ARPLookahead), NULL))
+ != NDIS_STATUS_SUCCESS) {
+ Adapter->ai_state = INTERFACE_DOWN;
+ return;
+ }
+
+ if ((Status = DoNDISRequest(Adapter, NdisRequestSetInformation,
+ OID_GEN_CURRENT_PACKET_FILTER, &Adapter->ai_pfilter, sizeof(uint),
+ NULL)) == NDIS_STATUS_SUCCESS) {
+ Adapter->ai_adminstate = IF_STATUS_UP;
+ Adapter->ai_operstate = IF_STATUS_UP;
+ Adapter->ai_state = INTERFACE_UP;
+ // Now walk through any addresses we have, and ARP for them.
+ CTEGetLock(&Adapter->ai_lock, &Handle);
+ OldAddr = NULL;
+ Addr = &Adapter->ai_ipaddr;
+ do {
+ if (!IP_ADDR_EQUAL(Addr->aia_addr, NULL_IP_ADDR)) {
+ IPAddr Address = Addr->aia_addr;
+
+ Addr->aia_age = ARPADDR_NEW_LOCAL;
+ CTEFreeLock(&Adapter->ai_lock, Handle);
+ OldAddr = Addr;
+ SendARPRequest(Adapter, Address, ARP_RESOLVING_GLOBAL,
+ NULL, TRUE);
+ CTEGetLock(&Adapter->ai_lock, &Handle);
+ }
+ Addr = &Adapter->ai_ipaddr;
+ while (Addr != OldAddr && Addr != NULL)
+ Addr = Addr->aia_next;
+ if (Addr != NULL)
+ Addr = Addr->aia_next;
+ } while (Addr != NULL);
+
+ CTEFreeLock(&Adapter->ai_lock, Handle);
+
+ } else
+ Adapter->ai_state = INTERFACE_DOWN;
+
+}
+
+//** ARPOAComplete - ARP Open adapter complete handler.
+//
+// This routine is called by the NDIS driver when an open adapter
+// call completes. Presumably somebody is blocked waiting for this, so
+// we'll wake him up now.
+//
+// Entry:
+// Handle - The binding handle we specified (really a pointer to an AI).
+// Status - Final status of command.
+// ErrorStatus - Final error status.
+//
+// Exit: Nothing.
+//
+void NDIS_API
+ARPOAComplete(NDIS_HANDLE Handle, NDIS_STATUS Status, NDIS_STATUS ErrorStatus)
+{
+ ARPInterface *ai = (ARPInterface *)Handle; // For compiler.
+
+ CTESignal(&ai->ai_block, (uint)Status); // Wake him up, and return status.
+
+}
+
+//** ARPCAComplete - ARP close adapter complete handler.
+//
+// This routine is called by the NDIS driver when a close adapter
+// call completes.
+//
+// Entry:
+// Handle - The binding handle we specified (really a pointer to an AI).
+// Status - Final status of command.
+//
+// Exit: Nothing.
+//
+void NDIS_API
+ARPCAComplete(NDIS_HANDLE Handle, NDIS_STATUS Status)
+{
+ ARPInterface *ai = (ARPInterface *)Handle; // For compiler.
+
+ CTESignal(&ai->ai_block, (uint)Status); // Wake him up, and return status.
+
+}
+
+//** ARPSendComplete - ARP send complete handler.
+//
+// This routine is called by the NDIS driver when a send completes.
+// This is a pretty time critical operation, we need to get through here
+// quickly. We'll strip our buffer off and put it back, and call the upper
+// later send complete handler.
+//
+// Entry:
+// Handle - The binding handle we specified (really a pointer to an AI).
+// Packet - A pointer to the packet that was sent.
+// Status - Final status of command.
+//
+// Exit: Nothing.
+//
+void NDIS_API
+ARPSendComplete(NDIS_HANDLE Handle, PNDIS_PACKET Packet, NDIS_STATUS Status)
+{
+ ARPInterface *Interface = (ARPInterface *)Handle;
+ PacketContext *PC = (PacketContext *)Packet->ProtocolReserved;
+ PNDIS_BUFFER Buffer;
+
+ Interface->ai_qlen--;
+#ifdef VXD
+ CTEAssert(*(int *)&Interface->ai_qlen >= 0);
+#endif
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ Interface->ai_outoctets += Packet->Private.TotalLength;
+ } else {
+ if (Status == NDIS_STATUS_RESOURCES)
+ Interface->ai_outdiscards++;
+ else
+ Interface->ai_outerrors++;
+ }
+
+ // Get first buffer on packet.
+ NdisUnchainBufferAtFront(Packet, &Buffer);
+#ifdef DEBUG
+ if (Buffer == (PNDIS_BUFFER)NULL) // No buffer!
+ DEBUGCHK;
+#endif
+
+ FreeARPBuffer(Interface, Buffer); // Free it up.
+ if (PC->pc_common.pc_owner != PACKET_OWNER_LINK) { // We don't own this one.
+ IPSendComplete(Interface->ai_context, Packet, Status);
+ return;
+ }
+
+ // This packet belongs to us, so free it.
+ NdisFreePacket(Packet);
+
+}
+
+//** ARPTDComplete - ARP transfer data complete handler.
+//
+// This routine is called by the NDIS driver when a transfer data
+// call completes. Since we never transfer data ourselves, this must be
+// from the upper layer. We'll just call his routine and let him deal
+// with it.
+//
+// Entry:
+// Handle - The binding handle we specified (really a pointer to an AI).
+// Packet - A pointer to the packet used for the TD.
+// Status - Final status of command.
+// BytesCopied - Count of bytes copied.
+//
+// Exit: Nothing.
+//
+void NDIS_API
+ARPTDComplete(NDIS_HANDLE Handle, PNDIS_PACKET Packet, NDIS_STATUS Status,
+ uint BytesCopied)
+{
+ ARPInterface *ai = (ARPInterface *)Handle;
+
+ IPTDComplete(ai->ai_context, Packet, Status, BytesCopied);
+
+}
+
+//** ARPResetComplete - ARP reset complete handler.
+//
+// This routine is called by the NDIS driver when a reset completes.
+//
+// Entry:
+// Handle - The binding handle we specified (really a pointer to an AI).
+// Status - Final status of command.
+//
+// Exit: Nothing.
+//
+void NDIS_API
+ARPResetComplete(NDIS_HANDLE Handle, NDIS_STATUS Status)
+{
+}
+
+//** ARPRequestComplete - ARP request complete handler.
+//
+// This routine is called by the NDIS driver when a general request
+// completes. ARP blocks on all requests, so we'll just wake up
+// whoever's blocked on this request.
+//
+// Entry:
+// Handle - The binding handle we specified (really a pointer to an AI).
+// Request - A pointer to the request that completed.
+// Status - Final status of command.
+//
+// Exit: Nothing.
+//
+void NDIS_API
+ARPRequestComplete(NDIS_HANDLE Handle, PNDIS_REQUEST Request,
+ NDIS_STATUS Status)
+{
+ ARPInterface *ai = (ARPInterface *)Handle;
+
+ CTESignal(&ai->ai_block, (uint)Status);
+}
+
+//** ARPRcv - ARP receive data handler.
+//
+// This routine is called when data arrives from the NDIS driver.
+//
+// Entry:
+// Handle - The binding handle we specified (really a pointer to an AI).
+// Context - NDIS context to be used for TD.
+// Header - Pointer to header
+// HeaderSize - Size of header
+// Data - Pointer to buffer of received data
+// Size - Byte count of data in buffer.
+// TotalSize - Byte count of total packet size.
+//
+// Exit: Status indicating whether or not we took the packet.
+//
+NDIS_STATUS NDIS_API
+ARPRcv(NDIS_HANDLE Handle, NDIS_HANDLE Context, void *Header, uint HeaderSize,
+ void *Data, uint Size, uint TotalSize)
+{
+ ARPInterface *Interface = Handle; // Interface for this driver.
+ ENetHeader UNALIGNED *EHdr = (ENetHeader UNALIGNED *)Header;
+ SNAPHeader UNALIGNED *SNAPHdr;
+ ushort type; // Protocol type
+ uint ProtOffset; // Offset in Data to non-media info.
+ uint NUCast; // TRUE if the frame is not
+ // a unicast frame.
+
+ if (Interface->ai_state == INTERFACE_UP &&
+ HeaderSize >= (uint)Interface->ai_hdrsize) {
+
+ Interface->ai_inoctets += TotalSize;
+
+ if (Interface->ai_media != NdisMediumArcnet878_2) {
+ if (Interface->ai_media == NdisMedium802_3 &&
+ (type = net_short(EHdr->eh_type)) >= MIN_ETYPE)
+ ProtOffset = 0;
+ else {
+ SNAPHdr = (SNAPHeader UNALIGNED *)Data;
+
+ if (Size >= sizeof(SNAPHeader) &&
+ SNAPHdr->sh_dsap == SNAP_SAP &&
+ SNAPHdr->sh_ssap == SNAP_SAP &&
+ SNAPHdr->sh_ctl == SNAP_UI) {
+ type = net_short(SNAPHdr->sh_etype);
+ ProtOffset = sizeof(SNAPHeader);
+ } else {
+ // BUGBUG handle XID/TEST here.
+ Interface->ai_uknprotos++;
+ return NDIS_STATUS_NOT_RECOGNIZED;
+ }
+ }
+ } else {
+ ARCNetHeader UNALIGNED *AH = (ARCNetHeader UNALIGNED *)Header;
+
+ ProtOffset = 0;
+ if (AH->ah_prot == ARP_ARCPROT_IP)
+ type = ARP_ETYPE_IP;
+ else
+ if (AH->ah_prot == ARP_ARCPROT_ARP)
+ type = ARP_ETYPE_ARP;
+ else
+ type = 0;
+ }
+
+ NUCast = ((*((uchar UNALIGNED *)EHdr + Interface->ai_bcastoff) &
+ Interface->ai_bcastmask) == Interface->ai_bcastval) ?
+ AI_NONUCAST_INDEX : AI_UCAST_INDEX;
+
+ if (type == ARP_ETYPE_IP) {
+
+ (Interface->ai_inpcount[NUCast])++;
+ IPRcv(Interface->ai_context, (uchar *)Data+ProtOffset,
+ Size-ProtOffset, TotalSize-ProtOffset, Context, ProtOffset,
+ NUCast);
+ return NDIS_STATUS_SUCCESS;
+ }
+ else {
+ if (type == ARP_ETYPE_ARP) {
+ (Interface->ai_inpcount[NUCast])++;
+ return HandleARPPacket(Interface, Header, HeaderSize,
+ (ARPHeader *)((uchar *)Data+ProtOffset), Size-ProtOffset,
+ ProtOffset);
+ } else {
+ Interface->ai_uknprotos++;
+ return NDIS_STATUS_NOT_RECOGNIZED;
+ }
+ }
+ } else {
+ // Interface is marked as down.
+ return NDIS_STATUS_NOT_RECOGNIZED;
+ }
+}
+
+//** ARPRcvComplete - ARP receive complete handler.
+//
+// This routine is called by the NDIS driver after some number of
+// receives. In some sense, it indicates 'idle time'.
+//
+// Entry:
+// Handle - The binding handle we specified (really a pointer to an AI).
+//
+// Exit: Nothing.
+//
+void NDIS_API
+ARPRcvComplete(NDIS_HANDLE Handle)
+{
+ IPRcvComplete();
+
+}
+
+
+//** ARPStatus - ARP status handler.
+//
+// Called by the NDIS driver when some sort of status change occurs.
+// We take action depending on the type of status.
+//
+// Entry:
+// Handle - The binding handle we specified (really a pointer to an AI).
+// GStatus - General type of status that caused the call.
+// Status - Pointer to a buffer of status specific information.
+// StatusSize - Size of the status buffer.
+//
+// Exit: Nothing.
+//
+void NDIS_API
+ARPStatus(NDIS_HANDLE Handle, NDIS_STATUS GStatus, void *Status, uint
+ StatusSize)
+{
+ ARPInterface *ai = (ARPInterface *)Handle;
+
+ IPStatus(ai->ai_context, GStatus, Status, StatusSize);
+
+}
+
+//** ARPStatusComplete - ARP status complete handler.
+//
+// A routine called by the NDIS driver so that we can do postprocessing
+// after a status event.
+//
+// Entry:
+// Handle - The binding handle we specified (really a pointer to an AI).
+//
+// Exit: Nothing.
+//
+void NDIS_API
+ARPStatusComplete(NDIS_HANDLE Handle)
+{
+
+}
+
+extern void NDIS_API ARPBindAdapter(PNDIS_STATUS RetStatus,
+ NDIS_HANDLE BindContext, PNDIS_STRING AdapterName, PVOID SS1, PVOID SS2);
+
+extern void NDIS_API ARPUnbindAdapter(PNDIS_STATUS RetStatus,
+ NDIS_HANDLE ProtBindContext, NDIS_HANDLE UnbindContext);
+extern void NDIS_API ARPUnloadProtocol(void);
+
+#ifndef NT
+NDIS_PROTOCOL_CHARACTERISTICS ARPCharacteristics = {
+ NDIS_MAJOR_VERSION,
+ NDIS_MINOR_VERSION,
+ 0,
+ ARPOAComplete,
+ ARPCAComplete,
+ ARPSendComplete,
+ ARPTDComplete,
+ ARPResetComplete,
+ ARPRequestComplete,
+ ARPRcv,
+ ARPRcvComplete,
+ ARPStatus,
+ ARPStatusComplete,
+#ifdef CHICAGO
+ ARPBindAdapter,
+ ARPUnbindAdapter,
+ ARPUnloadProtocol,
+#endif
+ { sizeof(TCP_NAME),
+ sizeof(TCP_NAME),
+ 0
+ }
+};
+#else // NT
+NDIS_PROTOCOL_CHARACTERISTICS ARPCharacteristics = {
+ NDIS_MAJOR_VERSION,
+ NDIS_MINOR_VERSION,
+ 0,
+ ARPOAComplete,
+ ARPCAComplete,
+ ARPSendComplete,
+ ARPTDComplete,
+ ARPResetComplete,
+ ARPRequestComplete,
+ ARPRcv,
+ ARPRcvComplete,
+ ARPStatus,
+ ARPStatusComplete,
+ { sizeof(TCP_NAME),
+ sizeof(TCP_NAME),
+ 0
+#ifdef _PNP_POWER
+ },
+ NULL,
+ ARPBindAdapter,
+ ARPUnbindAdapter,
+ NULL
+#else
+ }
+#endif
+};
+#endif
+
+//* ARPReadNext - Read the next entry in the ARP table.
+//
+// Called by the GetInfo code to read the next ATE in the table. We assume
+// the context passed in is valid, and the caller has the ARP TableLock.
+//
+// Input: Context - Pointer to a IPNMEContext.
+// Interface - Pointer to interface for table to read on.
+// Buffer - Pointer to an IPNetToMediaEntry structure.
+//
+// Returns: TRUE if more data is available to be read, FALSE is not.
+//
+uint
+ARPReadNext(void *Context, ARPInterface *Interface, void *Buffer)
+{
+ IPNMEContext *NMContext = (IPNMEContext *)Context;
+ IPNetToMediaEntry *IPNMEntry = (IPNetToMediaEntry *)Buffer;
+ CTELockHandle Handle;
+ ARPTableEntry *CurrentATE;
+ uint i;
+ ARPTable *Table = Interface->ai_ARPTbl;
+ uint AddrOffset;
+
+ CurrentATE = NMContext->inc_entry;
+
+ // Fill in the buffer.
+ CTEGetLock(&CurrentATE->ate_lock, &Handle);
+ IPNMEntry->inme_index = Interface->ai_index;
+ IPNMEntry->inme_physaddrlen = Interface->ai_addrlen;
+
+
+ switch (Interface->ai_media) {
+ case NdisMedium802_3:
+ AddrOffset = 0;
+ break;
+ case NdisMedium802_5:
+ AddrOffset = offsetof(struct TRHeader, tr_daddr);
+ break;
+ case NdisMediumFddi:
+ AddrOffset = offsetof(struct FDDIHeader, fh_daddr);
+ break;
+ case NdisMediumArcnet878_2:
+ AddrOffset = offsetof(struct ARCNetHeader, ah_daddr);
+ break;
+ default:
+ AddrOffset = 0;
+ break;
+ }
+
+ CTEMemCopy(IPNMEntry->inme_physaddr, &CurrentATE->ate_addr[AddrOffset],
+ Interface->ai_addrlen);
+ IPNMEntry->inme_addr = CurrentATE->ate_dest;
+
+ if (CurrentATE->ate_state == ARP_GOOD)
+ IPNMEntry->inme_type = (CurrentATE->ate_valid == ALWAYS_VALID ?
+ INME_TYPE_STATIC : INME_TYPE_DYNAMIC);
+ else
+ IPNMEntry->inme_type = INME_TYPE_INVALID;
+ CTEFreeLock(&CurrentATE->ate_lock, Handle);
+
+ // We've filled it in. Now update the context.
+ if (CurrentATE->ate_next != NULL) {
+ NMContext->inc_entry = CurrentATE->ate_next;
+ return TRUE;
+ } else {
+ // The next ATE is NULL. Loop through the ARP Table looking for a new
+ // one.
+ i = NMContext->inc_index + 1;
+ while (i < ARP_TABLE_SIZE) {
+ if ((*Table)[i] != NULL) {
+ NMContext->inc_entry = (*Table)[i];
+ NMContext->inc_index = i;
+ return TRUE;
+ break;
+ } else
+ i++;
+ }
+
+ NMContext->inc_index = 0;
+ NMContext->inc_entry = NULL;
+ return FALSE;
+ }
+
+}
+
+//* ARPValidateContext - Validate the context for reading an ARP table.
+//
+// Called to start reading an ARP table sequentially. We take in
+// a context, and if the values are 0 we return information about the
+// first route in the table. Otherwise we make sure that the context value
+// is valid, and if it is we return TRUE.
+// We assume the caller holds the ARPInterface lock.
+//
+// Input: Context - Pointer to a RouteEntryContext.
+// Interface - Pointer to an interface
+// Valid - Where to return information about context being
+// valid.
+//
+// Returns: TRUE if more data to be read in table, FALSE if not. *Valid set
+// to TRUE if input context is valid
+//
+uint
+ARPValidateContext(void *Context, ARPInterface *Interface, uint *Valid)
+{
+ IPNMEContext *NMContext = (IPNMEContext *)Context;
+ uint i;
+ ARPTableEntry *TargetATE;
+ ARPTableEntry *CurrentATE;
+ ARPTable *Table = Interface->ai_ARPTbl;
+
+ i = NMContext->inc_index;
+ TargetATE = NMContext->inc_entry;
+
+ // If the context values are 0 and NULL, we're starting from the beginning.
+ if (i == 0 && TargetATE == NULL) {
+ *Valid = TRUE;
+ do {
+ if ((CurrentATE = (*Table)[i]) != NULL) {
+ break;
+ }
+ i++;
+ } while (i < ARP_TABLE_SIZE);
+
+ if (CurrentATE != NULL) {
+ NMContext->inc_index = i;
+ NMContext->inc_entry = CurrentATE;
+ return TRUE;
+ } else
+ return FALSE;
+
+ } else {
+
+ // We've been given a context. We just need to make sure that it's
+ // valid.
+
+ if (i < ARP_TABLE_SIZE) {
+ CurrentATE = (*Table)[i];
+ while (CurrentATE != NULL) {
+ if (CurrentATE == TargetATE) {
+ *Valid = TRUE;
+ return TRUE;
+ break;
+ } else {
+ CurrentATE = CurrentATE->ate_next;
+ }
+ }
+
+ }
+
+ // If we get here, we didn't find the matching ATE.
+ *Valid = FALSE;
+ return FALSE;
+
+ }
+
+}
+
+#define IFE_FIXED_SIZE offsetof(struct IFEntry, if_descr)
+
+//* ARPQueryInfo - ARP query information handler.
+//
+// Called to query information about the ARP table or statistics about the
+// actual interface.
+//
+// Input: IFContext - Interface context (pointer to an ARPInterface).
+// ID - TDIObjectID for object.
+// Buffer - Buffer to put data into.
+// Size - Pointer to size of buffer. On return, filled with
+// bytes copied.
+// Context - Pointer to context block.
+//
+// Returns: Status of attempt to query information.
+//
+int
+ARPQueryInfo(void *IFContext, TDIObjectID *ID, PNDIS_BUFFER Buffer, uint *Size,
+ void *Context)
+{
+ ARPInterface *AI = (ARPInterface *)IFContext;
+ uint Offset = 0;
+ uint BufferSize = *Size;
+ CTELockHandle Handle;
+ uint ContextValid, DataLeft;
+ uint BytesCopied = 0;
+ uchar InfoBuff[sizeof(IFEntry)];
+ uint Entity;
+ uint Instance;
+
+
+ Entity = ID->toi_entity.tei_entity;
+ Instance = ID->toi_entity.tei_instance;
+
+ // First, make sure it's possibly an ID we can handle.
+ if ((Entity != AT_ENTITY || Instance != AI->ai_atinst) &&
+ (Entity != IF_ENTITY || Instance != AI->ai_ifinst)) {
+ return TDI_INVALID_REQUEST;
+ }
+
+ *Size = 0; // In case of an error.
+
+ if (ID->toi_type != INFO_TYPE_PROVIDER)
+ return TDI_INVALID_PARAMETER;
+
+ if (ID->toi_class == INFO_CLASS_GENERIC) {
+ if (ID->toi_id == ENTITY_TYPE_ID) {
+ // He's trying to see what type we are.
+ if (BufferSize >= sizeof(uint)) {
+ *(uint *)&InfoBuff[0] = (Entity == AT_ENTITY) ? AT_ARP :
+ IF_MIB;
+ (void)CopyToNdis(Buffer, InfoBuff, sizeof(uint), &Offset);
+ return TDI_SUCCESS;
+ } else
+ return TDI_BUFFER_TOO_SMALL;
+ }
+ return TDI_INVALID_PARAMETER;
+ }
+
+ // Might be able to handle this.
+ if (Entity == AT_ENTITY) {
+ // It's an address translation object. It could be a MIB object or
+ // an implementation specific object (the generic objects were handled
+ // above).
+
+ if (ID->toi_class == INFO_CLASS_IMPLEMENTATION) {
+ ARPPArpAddr *PArpAddr;
+
+ // It's an implementation specific ID. The only ones we handle
+ // are the PARP_COUNT_ID and the PARP_ENTRY ID.
+
+ if (ID->toi_id == AT_ARP_PARP_COUNT_ID) {
+ // He wants to know the count. Just return that to him.
+ if (BufferSize >= sizeof(uint)) {
+
+ CTEGetLock(&AI->ai_lock, &Handle);
+
+ (void)CopyToNdis(Buffer, (uchar *)&AI->ai_parpcount,
+ sizeof(uint), &Offset);
+
+ CTEFreeLock(&AI->ai_lock, Handle);
+ return TDI_SUCCESS;
+ } else
+ return TDI_BUFFER_TOO_SMALL;
+ }
+
+ if (ID->toi_id != AT_ARP_PARP_ENTRY_ID)
+ return TDI_INVALID_PARAMETER;
+
+ // It's for Proxy ARP entries. The context should be either NULL
+ // or a pointer to the next one to be read.
+ CTEGetLock(&AI->ai_lock, &Handle);
+
+ PArpAddr = *(ARPPArpAddr **)Context;
+
+ if (PArpAddr != NULL) {
+ ARPPArpAddr *CurrentPARP;
+
+ // Loop through the P-ARP addresses on the interface, and
+ // see if we can find this one.
+ CurrentPARP = AI->ai_parpaddr;
+ while (CurrentPARP != NULL) {
+ if (CurrentPARP == PArpAddr)
+ break;
+ else
+ CurrentPARP = CurrentPARP->apa_next;
+ }
+
+ // If we found a match, PARPAddr points to where to begin
+ // reading. Otherwise, fail the request.
+ if (CurrentPARP == NULL) {
+ // Didn't find a match, so fail the request.
+ CTEFreeLock(&AI->ai_lock, Handle);
+ return TDI_INVALID_PARAMETER;
+ }
+ } else
+ PArpAddr = AI->ai_parpaddr;
+
+ // PARPAddr points to the next entry to put in the buffer, if
+ // there is one.
+ while (PArpAddr != NULL) {
+ if ((int)(BufferSize - BytesCopied) >=
+ (int)sizeof(ProxyArpEntry)) {
+ ProxyArpEntry *TempPArp;
+
+ TempPArp = (ProxyArpEntry *)InfoBuff;
+ TempPArp->pae_status = PAE_STATUS_VALID;
+ TempPArp->pae_addr = PArpAddr->apa_addr;
+ TempPArp->pae_mask = PArpAddr->apa_mask;
+ BytesCopied += sizeof(ProxyArpEntry);
+ Buffer = CopyToNdis(Buffer, (uchar *)TempPArp,
+ sizeof(ProxyArpEntry), &Offset);
+ PArpAddr = PArpAddr->apa_next;
+ } else
+ break;
+ }
+
+ // We're done copying. Free the lock and return the correct
+ // status.
+ CTEFreeLock(&AI->ai_lock, Handle);
+ *Size = BytesCopied;
+ **(ARPPArpAddr ***)&Context = PArpAddr;
+ return (PArpAddr == NULL) ? TDI_SUCCESS : TDI_BUFFER_OVERFLOW;
+ }
+
+ if (ID->toi_id == AT_MIB_ADDRXLAT_INFO_ID) {
+ AddrXlatInfo *AXI;
+
+ // It's for the count. Just return the number of entries in the
+ // table.
+ if (BufferSize >= sizeof(AddrXlatInfo)) {
+ *Size = sizeof(AddrXlatInfo);
+ AXI = (AddrXlatInfo *)InfoBuff;
+ AXI->axi_count = AI->ai_count;
+ AXI->axi_index = AI->ai_index;
+ (void)CopyToNdis(Buffer, (uchar *)AXI, sizeof(AddrXlatInfo),
+ &Offset);
+ return TDI_SUCCESS;
+ } else
+ return TDI_BUFFER_TOO_SMALL;
+ }
+
+ if (ID->toi_id == AT_MIB_ADDRXLAT_ENTRY_ID) {
+ // He's trying to read the table.
+ // Make sure we have a valid context.
+ CTEGetLock(&AI->ai_ARPTblLock, &Handle);
+ DataLeft = ARPValidateContext(Context, AI, &ContextValid);
+
+ // If the context is valid, we'll continue trying to read.
+ if (!ContextValid) {
+ CTEFreeLock(&AI->ai_ARPTblLock, Handle);
+ return TDI_INVALID_PARAMETER;
+ }
+
+ while (DataLeft) {
+ // The invariant here is that there is data in the table to
+ // read. We may or may not have room for it. So DataLeft
+ // is TRUE, and BufferSize - BytesCopied is the room left
+ // in the buffer.
+ if ((int)(BufferSize - BytesCopied) >=
+ (int)sizeof(IPNetToMediaEntry)) {
+ DataLeft = ARPReadNext(Context, AI, InfoBuff);
+ BytesCopied += sizeof(IPNetToMediaEntry);
+ Buffer = CopyToNdis(Buffer, InfoBuff,
+ sizeof(IPNetToMediaEntry), &Offset);
+ } else
+ break;
+
+ }
+
+ *Size = BytesCopied;
+
+ CTEFreeLock(&AI->ai_ARPTblLock, Handle);
+ return (!DataLeft ? TDI_SUCCESS : TDI_BUFFER_OVERFLOW);
+ }
+
+ return TDI_INVALID_PARAMETER;
+ }
+
+ if (ID->toi_class != INFO_CLASS_PROTOCOL)
+ return TDI_INVALID_PARAMETER;
+
+ // He must be asking for interface level information. See if we support
+ // what he's asking for.
+ if (ID->toi_id == IF_MIB_STATS_ID) {
+ IFEntry *IFE = (IFEntry *)InfoBuff;
+
+
+ // He's asking for statistics. Make sure his buffer is at least big
+ // enough to hold the fixed part.
+
+ if (BufferSize < IFE_FIXED_SIZE) {
+ return TDI_BUFFER_TOO_SMALL;
+ }
+
+ // He's got enough to hold the fixed part. Build the IFEntry structure,
+ // and copy it to his buffer.
+ IFE->if_index = AI->ai_index;
+ switch (AI->ai_media) {
+ case NdisMedium802_3:
+ IFE->if_type = IF_TYPE_ETHERNET;
+ break;
+ case NdisMedium802_5:
+ IFE->if_type = IF_TYPE_TOKENRING;
+ break;
+ case NdisMediumFddi:
+ IFE->if_type = IF_TYPE_FDDI;
+ break;
+ case NdisMediumArcnet878_2:
+ default:
+ IFE->if_type = IF_TYPE_OTHER;
+ break;
+ }
+ IFE->if_mtu = AI->ai_mtu;
+ IFE->if_speed = AI->ai_speed;
+ IFE->if_physaddrlen = AI->ai_addrlen;
+ CTEMemCopy(IFE->if_physaddr,AI->ai_addr, AI->ai_addrlen);
+ IFE->if_adminstatus = (uint)AI->ai_adminstate;
+ IFE->if_operstatus = (uint)AI->ai_operstate;
+ IFE->if_lastchange = AI->ai_lastchange;
+ IFE->if_inoctets = AI->ai_inoctets;
+ IFE->if_inucastpkts = AI->ai_inpcount[AI_UCAST_INDEX];
+ IFE->if_innucastpkts = AI->ai_inpcount[AI_NONUCAST_INDEX];
+ IFE->if_indiscards = AI->ai_indiscards;
+ IFE->if_inerrors = AI->ai_inerrors;
+ IFE->if_inunknownprotos = AI->ai_uknprotos;
+ IFE->if_outoctets = AI->ai_outoctets;
+ IFE->if_outucastpkts = AI->ai_outpcount[AI_UCAST_INDEX];
+ IFE->if_outnucastpkts = AI->ai_outpcount[AI_NONUCAST_INDEX];
+ IFE->if_outdiscards = AI->ai_outdiscards;
+ IFE->if_outerrors = AI->ai_outerrors;
+ IFE->if_outqlen = AI->ai_qlen;
+ IFE->if_descrlen = AI->ai_desclen;
+ Buffer = CopyToNdis(Buffer, (uchar *)IFE, IFE_FIXED_SIZE, &Offset);
+
+ // See if he has room for the descriptor string.
+ if (BufferSize >= (IFE_FIXED_SIZE + AI->ai_desclen)) {
+ // He has room. Copy it.
+ if (AI->ai_desclen != 0) {
+ (void)CopyToNdis(Buffer, AI->ai_desc, AI->ai_desclen, &Offset);
+ }
+ *Size = IFE_FIXED_SIZE + AI->ai_desclen;
+ return TDI_SUCCESS;
+ } else {
+ // Not enough room to copy the desc. string.
+ *Size = IFE_FIXED_SIZE;
+ return TDI_BUFFER_OVERFLOW;
+ }
+
+ }
+
+ return TDI_INVALID_PARAMETER;
+
+}
+
+//* ARPSetInfo - ARP set information handler.
+//
+// The ARP set information handler. We support setting of an I/F admin
+// status, and setting/deleting of ARP table entries.
+//
+// Input: Context - Pointer to I/F to set on.
+// ID - The object ID
+// Buffer - Pointer to buffer containing value to set.
+// Size - Size in bytes of Buffer.
+//
+// Returns: Status of attempt to set information.
+//
+int
+ARPSetInfo(void *Context, TDIObjectID *ID, void *Buffer, uint Size)
+{
+ ARPInterface *Interface = (ARPInterface *)Context;
+ CTELockHandle Handle, EntryHandle;
+ int Status;
+ IFEntry *IFE = (IFEntry *)Buffer;
+ IPNetToMediaEntry *IPNME;
+ ARPTableEntry *PrevATE, *CurrentATE;
+ ARPTable *Table;
+ ENetHeader *Header;
+ uint Entity, Instance;
+
+ Entity = ID->toi_entity.tei_entity;
+ Instance = ID->toi_entity.tei_instance;
+
+ // First, make sure it's possibly an ID we can handle.
+ if ((Entity != AT_ENTITY || Instance != Interface->ai_atinst) &&
+ (Entity != IF_ENTITY || Instance != Interface->ai_ifinst)) {
+ return TDI_INVALID_REQUEST;
+ }
+
+ if (ID->toi_type != INFO_TYPE_PROVIDER) {
+ return TDI_INVALID_PARAMETER;
+ }
+
+ // Might be able to handle this.
+ if (Entity == IF_ENTITY) {
+
+ // It's for the I/F level, see if it's for the statistics.
+ if (ID->toi_class != INFO_CLASS_PROTOCOL)
+ return TDI_INVALID_PARAMETER;
+
+ if (ID->toi_id == IF_MIB_STATS_ID) {
+ // It's for the stats. Make sure it's a valid size.
+ if (Size >= IFE_FIXED_SIZE) {
+ // It's a valid size. See what he wants to do.
+ CTEGetLock(&Interface->ai_lock, &Handle);
+ switch (IFE->if_adminstatus) {
+ case IF_STATUS_UP:
+ // He's marking it up. If the operational state is
+ // alse up, mark the whole interface as up.
+ Interface->ai_adminstate = IF_STATUS_UP;
+ if (Interface->ai_operstate == IF_STATUS_UP)
+ Interface->ai_state = INTERFACE_UP;
+ Status = TDI_SUCCESS;
+ break;
+ case IF_STATUS_DOWN:
+ // He's taking it down. Mark both the admin state and
+ // the interface state down.
+ Interface->ai_adminstate = IF_STATUS_DOWN;
+ Interface->ai_state = INTERFACE_DOWN;
+ Status = TDI_SUCCESS;
+ break;
+ case IF_STATUS_TESTING:
+ // He's trying to cause up to do testing, which we
+ // don't support. Just return success.
+ Status = TDI_SUCCESS;
+ break;
+ default:
+ Status = TDI_INVALID_PARAMETER;
+ break;
+ }
+ CTEFreeLock(&Interface->ai_lock, Handle);
+ return Status;
+ } else
+ return TDI_INVALID_PARAMETER;
+ } else {
+ return TDI_INVALID_PARAMETER;
+ }
+ }
+
+ // Not for the interface level. See if it's an implementation or protocol
+ // class.
+ if (ID->toi_class == INFO_CLASS_IMPLEMENTATION) {
+ ProxyArpEntry *PArpEntry;
+ ARPIPAddr *Addr;
+ IPAddr AddAddr;
+ IPMask Mask;
+
+ // It's for the implementation. It should be the proxy-ARP ID.
+ if (ID->toi_id != AT_ARP_PARP_ENTRY_ID || Size < sizeof(ProxyArpEntry))
+ return TDI_INVALID_PARAMETER;
+
+ PArpEntry = (ProxyArpEntry *)Buffer;
+ AddAddr = PArpEntry->pae_addr;
+ Mask = PArpEntry->pae_mask;
+
+ // See if he's trying to add or delete a proxy arp entry.
+ if (PArpEntry->pae_status == PAE_STATUS_VALID) {
+ // We're trying to add an entry. We won't allow an entry
+ // to be added that we believe to be invalid or conflicting
+ // with our local addresses.
+
+ if (!IP_ADDR_EQUAL(AddAddr & Mask, AddAddr) ||
+ IP_ADDR_EQUAL(AddAddr, NULL_IP_ADDR) ||
+ IP_ADDR_EQUAL(AddAddr, IP_LOCAL_BCST) ||
+ CLASSD_ADDR(AddAddr))
+ return TDI_INVALID_PARAMETER;
+
+ // Walk through the list of addresses on the interface, and see
+ // if they would match the AddAddr. If so, fail the request.
+ CTEGetLock(&Interface->ai_lock, &Handle);
+
+ if (IsBCastOnIF(Interface, AddAddr & Mask)) {
+ CTEFreeLock(&Interface->ai_lock, Handle);
+ return TDI_INVALID_PARAMETER;
+ }
+
+ Addr = &Interface->ai_ipaddr;
+ do {
+ if (!IP_ADDR_EQUAL(Addr->aia_addr, NULL_IP_ADDR)) {
+ if (IP_ADDR_EQUAL(Addr->aia_addr & Mask, AddAddr))
+ break;
+ }
+ Addr = Addr->aia_next;
+ } while (Addr != NULL);
+
+ CTEFreeLock(&Interface->ai_lock, Handle);
+ if (Addr != NULL)
+ return TDI_INVALID_PARAMETER;
+
+ // At this point, we believe we're ok. Try to add the address.
+ if (ARPAddAddr(Interface, LLIP_ADDR_PARP, AddAddr, Mask, NULL))
+ return TDI_SUCCESS;
+ else
+ return TDI_NO_RESOURCES;
+ } else {
+ if (PArpEntry->pae_status == PAE_STATUS_INVALID) {
+ // He's trying to delete a proxy ARP address.
+ if (ARPDeleteAddr(Interface, LLIP_ADDR_PARP, AddAddr, Mask))
+ return TDI_SUCCESS;
+ }
+ return TDI_INVALID_PARAMETER;
+ }
+
+ }
+
+ if (ID->toi_class != INFO_CLASS_PROTOCOL)
+ return TDI_INVALID_PARAMETER;
+
+
+ if (ID->toi_id == AT_MIB_ADDRXLAT_ENTRY_ID &&
+ Size >= sizeof(IPNetToMediaEntry)) {
+ // He does want to set an ARP table entry. See if he's trying to
+ // create or delete one.
+
+ IPNME = (IPNetToMediaEntry *)Buffer;
+ if (IPNME->inme_type == INME_TYPE_INVALID) {
+ uint Index = ARP_HASH(IPNME->inme_addr);
+
+ // We're trying to delete an entry. See if we can find it,
+ // and then delete it.
+ CTEGetLock(&Interface->ai_ARPTblLock, &Handle);
+ Table = Interface->ai_ARPTbl;
+ PrevATE = STRUCT_OF(ARPTableEntry, &((*Table)[Index]), ate_next);
+ CurrentATE = (*Table)[Index];
+ while (CurrentATE != (ARPTableEntry *)NULL) {
+ if (CurrentATE->ate_dest == IPNME->inme_addr) {
+ // Found him. Break out of the loop.
+ break;
+ } else {
+ PrevATE = CurrentATE;
+ CurrentATE = CurrentATE->ate_next;
+ }
+ }
+
+ if (CurrentATE != NULL) {
+ CTEGetLock(&CurrentATE->ate_lock, &EntryHandle);
+ RemoveARPTableEntry(PrevATE, CurrentATE);
+ Interface->ai_count--;
+ CTEFreeLock(&CurrentATE->ate_lock, EntryHandle);
+
+ if (CurrentATE->ate_packet != NULL)
+ IPSendComplete(Interface->ai_context, CurrentATE->ate_packet,
+ NDIS_STATUS_SUCCESS);
+
+ CTEFreeMem(CurrentATE);
+ Status = TDI_SUCCESS;
+ } else
+ Status = TDI_INVALID_PARAMETER;
+
+ CTEFreeLock(&Interface->ai_ARPTblLock, Handle);
+ return Status;
+ }
+
+ // We're not trying to delete. See if we're trying to create.
+ if (IPNME->inme_type != INME_TYPE_DYNAMIC &&
+ IPNME->inme_type != INME_TYPE_STATIC) {
+ // Not creating, return an error.
+ return TDI_INVALID_PARAMETER;
+ }
+
+ // Make sure he's trying to create a valid address.
+ if (IPNME->inme_physaddrlen != Interface->ai_addrlen)
+ return TDI_INVALID_PARAMETER;
+
+ // We're trying to create an entry. Call CreateARPTableEntry to create
+ // one, and fill it in.
+ CurrentATE = CreateARPTableEntry(Interface, IPNME->inme_addr, &Handle);
+ if (CurrentATE == NULL) {
+ return TDI_NO_RESOURCES;
+ }
+
+ // We've created or found an entry. Fill it in.
+ Header = (ENetHeader *)CurrentATE->ate_addr;
+
+ switch (Interface->ai_media) {
+ case NdisMedium802_5:
+ {
+ TRHeader *Temp = (TRHeader *)Header;
+
+ // Fill in the TR specific parts, and set the length to the
+ // size of a TR header.
+
+ Temp->tr_ac = ARP_AC;
+ Temp->tr_fc = ARP_FC;
+ CTEMemCopy(&Temp->tr_saddr[ARP_802_ADDR_LENGTH], ARPSNAP,
+ sizeof(SNAPHeader));
+
+ Header = (ENetHeader *)&Temp->tr_daddr;
+ CurrentATE->ate_addrlength = sizeof(TRHeader) +
+ sizeof(SNAPHeader);
+ }
+ break;
+ case NdisMedium802_3:
+ CurrentATE->ate_addrlength = sizeof(ENetHeader);
+ break;
+ case NdisMediumFddi:
+ {
+ FDDIHeader *Temp = (FDDIHeader *)Header;
+
+ Temp->fh_pri = ARP_FDDI_PRI;
+ CTEMemCopy(&Temp->fh_saddr[ARP_802_ADDR_LENGTH], ARPSNAP,
+ sizeof(SNAPHeader));
+ Header = (ENetHeader *)&Temp->fh_daddr;
+ CurrentATE->ate_addrlength = sizeof(FDDIHeader) +
+ sizeof(SNAPHeader);
+ }
+ break;
+ case NdisMediumArcnet878_2:
+ {
+ ARCNetHeader *Temp = (ARCNetHeader *)Header;
+
+ Temp->ah_saddr = Interface->ai_addr[0];
+ Temp->ah_daddr = IPNME->inme_physaddr[0];
+ Temp->ah_prot = ARP_ARCPROT_IP;
+ CurrentATE->ate_addrlength = sizeof(ARCNetHeader);
+ }
+ break;
+ default:
+ DEBUGCHK;
+ break;
+ }
+
+
+ // Copy in the source and destination addresses.
+
+ if (Interface->ai_media != NdisMediumArcnet878_2) {
+ CTEMemCopy(Header->eh_daddr, IPNME->inme_physaddr,
+ ARP_802_ADDR_LENGTH);
+ CTEMemCopy(Header->eh_saddr, Interface->ai_addr,
+ ARP_802_ADDR_LENGTH);
+
+ // Now fill in the Ethertype.
+ *(ushort *)&CurrentATE->ate_addr[CurrentATE->ate_addrlength-2] =
+ net_short(ARP_ETYPE_IP);
+ }
+
+ // If he's creating a static entry, mark it as always valid. Otherwise
+ // mark him as valid now.
+ if (IPNME->inme_type == INME_TYPE_STATIC)
+ CurrentATE->ate_valid = ALWAYS_VALID;
+ else
+ CurrentATE->ate_valid = CTESystemUpTime();
+
+ CurrentATE->ate_state = ARP_GOOD;
+
+ CTEFreeLock(&CurrentATE->ate_lock, Handle);
+ return TDI_SUCCESS;
+
+ }
+
+ return TDI_INVALID_PARAMETER;
+
+
+}
+
+
+static uint ARPPackets = ARP_DEFAULT_PACKETS;
+static uint ARPBuffers = ARP_DEFAULT_BUFFERS;
+
+#pragma BEGIN_INIT
+//** ARPInit - Initialize the ARP module.
+//
+// This functions intializes all of the ARP module, including allocating
+// the ARP table and any other necessary data structures.
+//
+// Entry: nothing.
+//
+// Exit: Returns 0 if we fail to init., !0 if we succeed.
+//
+int
+ARPInit()
+{
+ NDIS_STATUS Status; // Status for NDIS calls.
+
+// BUGBUG - Get configuration information dynamically.
+
+#ifdef NT
+ RtlInitUnicodeString(&(ARPCharacteristics.Name), ARPName);
+#else // NT
+ ARPCharacteristics.Name.Buffer = ARPName;
+#endif // NT
+
+ NdisRegisterProtocol(&Status, &ARPHandle, (NDIS_PROTOCOL_CHARACTERISTICS *)
+ &ARPCharacteristics, sizeof(ARPCharacteristics));
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ return(1);
+ }
+ else {
+ return(0);
+ }
+}
+#pragma END_INIT
+
+#ifndef CHICAGO
+#pragma BEGIN_INIT
+#else
+#pragma code_seg("_LTEXT", "LCODE")
+#endif
+
+//* FreeARPInterface - Free an ARP interface
+//
+// Called in the event of some sort of initialization failure. We free all
+// the memory associated with an ARP interface.
+//
+// Entry: Interface - Pointer to interface structure to be freed.
+//
+// Returns: Nothing.
+//
+void
+FreeARPInterface(ARPInterface *Interface)
+{
+ NDIS_STATUS Status;
+ ARPBufferTracker *Tracker;
+ ARPTable *Table; // ARP table.
+ uint i; // Index variable.
+ ARPTableEntry *ATE;
+ CTELockHandle LockHandle;
+ NDIS_HANDLE Handle;
+
+ CTEStopTimer(&Interface->ai_timer);
+
+// If we're bound to the adapter, close it now.
+ CTEInitBlockStruc(&Interface->ai_block);
+
+ CTEGetLock(&Interface->ai_lock, &LockHandle);
+ if (Interface->ai_handle != (NDIS_HANDLE)NULL) {
+ Handle = Interface->ai_handle;
+ Interface->ai_handle = NULL;
+ CTEFreeLock(&Interface->ai_lock, LockHandle);
+
+ NdisCloseAdapter(&Status, Handle);
+
+ if (Status == NDIS_STATUS_PENDING)
+ Status = CTEBlock(&Interface->ai_block);
+ } else {
+ CTEFreeLock(&Interface->ai_lock, LockHandle);
+ }
+
+ // First free any outstanding ARP table entries.
+ Table = Interface->ai_ARPTbl;
+ if (Table != NULL) {
+ for (i = 0; i < ARP_TABLE_SIZE;i++) {
+ while ((*Table)[i] != NULL) {
+ ATE = (*Table)[i];
+ RemoveARPTableEntry(STRUCT_OF(ARPTableEntry, &((*Table)[i]),
+ ate_next),ATE);
+ CTEFreeMem(ATE);
+ }
+ }
+ CTEFreeMem(Table);
+ }
+
+ Interface->ai_ARPTbl = NULL;
+
+ if (Interface->ai_ppool != (NDIS_HANDLE)NULL)
+ NdisFreePacketPool(Interface->ai_ppool);
+
+ if (Interface->ai_bpool != (NDIS_HANDLE)NULL)
+ NdisFreeBufferPool(Interface->ai_bpool);
+
+ Tracker = Interface->ai_buflist;
+ while (Tracker != NULL) {
+ Interface->ai_buflist = Tracker->abt_next;
+ NdisFreeBufferPool(Tracker->abt_handle);
+ CTEFreeMem(Tracker->abt_buffer);
+ CTEFreeMem(Tracker);
+ Tracker = Interface->ai_buflist;
+ }
+
+ if (Interface->ai_bbbase != (uchar *)NULL)
+ CTEFreeMem(Interface->ai_bbbase);
+
+ // Free the interface itself.
+ CTEFreeMem(Interface);
+}
+
+//** ARPOpen - Open an adapter for reception.
+//
+// This routine is called when the upper layer is done initializing and wishes to
+// begin receiveing packets. The adapter is actually 'open', we just call InitAdapter
+// to set the packet filter and lookahead size.
+//
+// Input: Context - Interface pointer we gave to IP earlier.
+//
+// Returns: Nothing
+//
+void
+ARPOpen(void *Context)
+{
+ ARPInterface *Interface = (ARPInterface *)Context;
+ InitAdapter(Interface); // Set the packet filter - we'll begin receiving.
+}
+
+//* ARPGetEList - Get the entity list.
+//
+// Called at init time to get an entity list. We fill our stuff in, and
+// then call the interfaces below us to allow them to do the same.
+//
+// Input: EntityList - Pointer to entity list to be filled in.
+// Count - Pointer to number of entries in the list.
+//
+// Returns Status of attempt to get the info.
+//
+int
+ARPGetEList(void *Context, TDIEntityID *EntityList, uint *Count)
+{
+ ARPInterface *Interface = (ARPInterface *)Context;
+ uint ECount;
+ uint MyATBase;
+ uint MyIFBase;
+ uint i;
+
+ ECount = *Count;
+
+ // Walk down the list, looking for existing AT or IF entities, and
+ // adjust our base instance accordingly.
+
+ MyATBase = 0;
+ MyIFBase = 0;
+ for (i = 0; i < ECount; i++, EntityList++) {
+ if (EntityList->tei_entity == AT_ENTITY)
+ MyATBase = MAX(MyATBase, EntityList->tei_instance + 1);
+ else
+ if (EntityList->tei_entity == IF_ENTITY)
+ MyIFBase = MAX(MyIFBase, EntityList->tei_instance + 1);
+ }
+
+ // EntityList points to the start of where we want to begin filling in.
+ // Make sure we have enough room. We need one for the ICMP instance,
+ // and one for the CL_NL instance.
+
+ if ((ECount + 2) > MAX_TDI_ENTITIES)
+ return FALSE;
+
+ // At this point we've figure out our base instance. Save for later use.
+ Interface->ai_atinst = MyATBase;
+ Interface->ai_ifinst = MyIFBase;
+
+ // Now fill it in.
+ EntityList->tei_entity = AT_ENTITY;
+ EntityList->tei_instance = MyATBase;
+ EntityList++;
+ EntityList->tei_entity = IF_ENTITY;
+ EntityList->tei_instance = MyIFBase;
+ *Count += 2;
+
+ return TRUE;
+}
+
+
+extern uint UseEtherSNAP(PNDIS_STRING Name);
+extern void GetAlwaysSourceRoute(uint *pArpAlwaysSourceRoute, uint *pIPAlwaysSourceRoute);
+extern uint GetArpCacheLife(void);
+
+
+//** ARPRegister - Register a protocol with the ARP module.
+//
+// We register a protocol for ARP processing. We also open the
+// NDIS adapter here.
+//
+// Note that much of the information passed in here is unused, as
+// ARP currently only works with IP.
+//
+// Entry:
+// Adapter - Name of the adapter to bind to.
+// IPContext - Value to be passed to IP on upcalls.
+//
+#ifndef _PNP_POWER
+int
+ARPRegister(PNDIS_STRING Adapter, void *IPContext, IPRcvRtn RcvRtn,
+ IPTxCmpltRtn TxCmpltRtn, IPStatusRtn StatusRtn, IPTDCmpltRtn TDCmpltRtn,
+ IPRcvCmpltRtn RcvCmpltRtn, struct LLIPBindInfo *Info, uint NumIFBound)
+#else
+int
+ARPRegister(PNDIS_STRING Adapter, uint *Flags, struct ARPInterface **Interface)
+#endif
+{
+ ARPInterface *ai; // Pointer to interface struct. for this
+ // interface.
+ NDIS_STATUS Status, OpenStatus; // Status values.
+ uint i = 0; // Medium index.
+ NDIS_MEDIUM MediaArray[MAX_MEDIA];
+ uchar sbsize;
+ uchar *buffer; // Pointer to our buffers.
+ uint mss;
+ uint speed;
+ uint Needed;
+ uint MacOpts;
+ uchar bcastmask, bcastval, bcastoff, addrlen, hdrsize, snapsize;
+ uint OID;
+ uint PF;
+ PNDIS_BUFFER Buffer;
+
+ if ((ai = CTEAllocMem(sizeof(ARPInterface))) == (ARPInterface *)NULL)
+ return FALSE; // Couldn't allocate memory for this one.
+
+#ifdef _PNP_POWER
+ *Interface = ai;
+#endif
+
+ CTEMemSet(ai, 0, sizeof(ARPInterface));
+ CTEInitTimer(&ai->ai_timer);
+
+#ifdef NT
+ ExInitializeSListHead(&ai->ai_sblist);
+#endif
+
+
+ MediaArray[MEDIA_DIX] = NdisMedium802_3;
+ MediaArray[MEDIA_TR] = NdisMedium802_5;
+ MediaArray[MEDIA_FDDI] = NdisMediumFddi;
+ MediaArray[MEDIA_ARCNET] = NdisMediumArcnet878_2;
+
+ // Initialize this adapter interface structure.
+ ai->ai_state = INTERFACE_INIT;
+ ai->ai_adminstate = IF_STATUS_DOWN;
+ ai->ai_operstate = IF_STATUS_DOWN;
+ ai->ai_bcast = IP_LOCAL_BCST;
+ ai->ai_maxhdrs = ARP_DEFAULT_MAXHDRS;
+
+#ifndef _PNP_POWER
+ ai->ai_index = NumIFBound + 1;
+ ai->ai_context = IPContext;
+ Info->lip_context = ai;
+ Info->lip_transmit = ARPTransmit;
+ Info->lip_transfer = ARPXferData;
+ Info->lip_close = ARPClose;
+ Info->lip_addaddr = ARPAddAddr;
+ Info->lip_deladdr = ARPDeleteAddr;
+ Info->lip_invalidate = ARPInvalidate;
+ Info->lip_open = ARPOpen;
+ Info->lip_qinfo = ARPQueryInfo;
+ Info->lip_setinfo = ARPSetInfo;
+ Info->lip_getelist = ARPGetEList;
+
+ Info->lip_index = ai->ai_index;
+#endif
+
+ // Initialize the locks.
+ CTEInitLock(&ai->ai_lock);
+ CTEInitLock(&ai->ai_ARPTblLock);
+
+ GetAlwaysSourceRoute(&sArpAlwaysSourceRoute, &sIPAlwaysSourceRoute);
+
+ ArpCacheLife = GetArpCacheLife();
+
+ if (!ArpCacheLife) {
+ ArpCacheLife = 1;
+ }
+
+ ArpCacheLife = (ArpCacheLife * 1000L) / ARP_TIMER_TIME;
+
+ // Allocate the buffer and packet pools.
+ NdisAllocatePacketPool(&Status, &ai->ai_ppool, ARPPackets, sizeof(struct PCCommon));
+ if (Status != NDIS_STATUS_SUCCESS) {
+ FreeARPInterface(ai);
+ return FALSE;
+ }
+
+ NdisAllocateBufferPool(&Status, &ai->ai_bpool, ARPBuffers);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ FreeARPInterface(ai);
+ return FALSE;
+ }
+
+ // Allocate the ARP table
+ if ((ai->ai_ARPTbl = (ARPTable *)CTEAllocMem(ARP_TABLE_SIZE * sizeof(ARPTableEntry *))) ==
+ (ARPTable *)NULL) {
+ FreeARPInterface(ai);
+ return FALSE;
+ }
+
+ //
+ // NULL out the pointers
+ //
+ CTEMemSet(ai->ai_ARPTbl, 0, ARP_TABLE_SIZE * sizeof(ARPTableEntry *));
+
+ CTEInitBlockStruc(&ai->ai_block);
+
+ // Open the NDIS adapter.
+ NdisOpenAdapter(&Status, &OpenStatus, &ai->ai_handle, &i, MediaArray,
+ MAX_MEDIA, ARPHandle, ai, Adapter, 0, NULL);
+
+ // Block for open to complete.
+ if (Status == NDIS_STATUS_PENDING)
+ Status = (NDIS_STATUS)CTEBlock(&ai->ai_block);
+
+ ai->ai_media = MediaArray[i]; // Fill in media type.
+
+ // Open adapter completed. If it succeeded, we'll finish our intialization.
+ // If it failed, bail out now.
+ if (Status != NDIS_STATUS_SUCCESS) {
+ ai->ai_handle = NULL;
+ FreeARPInterface(ai);
+ return FALSE;
+ }
+
+ // Read the local address.
+ switch (ai->ai_media) {
+ case NdisMedium802_3:
+ addrlen = ARP_802_ADDR_LENGTH;
+ bcastmask = ENET_BCAST_MASK;
+ bcastval = ENET_BCAST_VAL;
+ bcastoff = ENET_BCAST_OFF;
+ OID = OID_802_3_CURRENT_ADDRESS;
+ sbsize = ARP_MAX_MEDIA_ENET;
+ hdrsize = sizeof(ENetHeader);
+ if (!UseEtherSNAP(Adapter)) {
+ snapsize = 0;
+ } else {
+ snapsize = sizeof(SNAPHeader);
+ sbsize += sizeof(SNAPHeader);
+ }
+
+ PF = NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_DIRECTED |
+ NDIS_PACKET_TYPE_MULTICAST;
+ break;
+ case NdisMedium802_5:
+ addrlen = ARP_802_ADDR_LENGTH;
+ bcastmask = TR_BCAST_MASK;
+ bcastval = TR_BCAST_VAL;
+ bcastoff = TR_BCAST_OFF;
+ OID = OID_802_5_CURRENT_ADDRESS;
+ sbsize = ARP_MAX_MEDIA_TR;
+ hdrsize = sizeof(TRHeader);
+ snapsize = sizeof(SNAPHeader);
+ PF = NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_DIRECTED;
+ break;
+ case NdisMediumFddi:
+ addrlen = ARP_802_ADDR_LENGTH;
+ bcastmask = FDDI_BCAST_MASK;
+ bcastval = FDDI_BCAST_VAL;
+ bcastoff = FDDI_BCAST_OFF;
+ OID = OID_FDDI_LONG_CURRENT_ADDR;
+ sbsize = ARP_MAX_MEDIA_FDDI;
+ hdrsize = sizeof(FDDIHeader);
+ snapsize = sizeof(SNAPHeader);
+ PF = NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_DIRECTED |
+ NDIS_PACKET_TYPE_MULTICAST;
+ break;
+ case NdisMediumArcnet878_2:
+ addrlen = 1;
+ bcastmask = ARC_BCAST_MASK;
+ bcastval = ARC_BCAST_VAL;
+ bcastoff = ARC_BCAST_OFF;
+ OID = OID_ARCNET_CURRENT_ADDRESS;
+ sbsize = ARP_MAX_MEDIA_ARC;
+ hdrsize = sizeof(ARCNetHeader);
+ snapsize = 0;
+ PF = NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_DIRECTED;
+ break;
+ default:
+ DEBUGCHK;
+ FreeARPInterface(ai);
+ return FALSE;
+ }
+
+ ai->ai_bcastmask = bcastmask;
+ ai->ai_bcastval = bcastval;
+ ai->ai_bcastoff = bcastoff;
+ ai->ai_addrlen = addrlen;
+ ai->ai_hdrsize = hdrsize;
+ ai->ai_snapsize = snapsize;
+ ai->ai_pfilter = PF;
+
+ Status = DoNDISRequest(ai, NdisRequestQueryInformation, OID,
+ ai->ai_addr, addrlen, NULL);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ FreeARPInterface(ai);
+ return FALSE;
+ }
+
+#ifndef _PNP_POWER
+ Info->lip_addrlen = addrlen;
+ Info->lip_addr = ai->ai_addr;
+#endif
+
+ // Read the maximum frame size.
+ if ((Status = DoNDISRequest(ai, NdisRequestQueryInformation,
+ OID_GEN_MAXIMUM_FRAME_SIZE, &mss, sizeof(mss), NULL)) != NDIS_STATUS_SUCCESS) {
+ FreeARPInterface(ai);
+ return FALSE;
+ }
+
+ // If this is token ring, figure out the RC len stuff now.
+ mss -= (uint)ai->ai_snapsize;
+
+ if (ai->ai_media == NdisMedium802_5) {
+ mss -= (sizeof(RC) + (ARP_MAX_RD * sizeof(ushort)));
+ } else {
+ if (ai->ai_media == NdisMediumFddi) {
+ mss = MIN(mss, ARP_FDDI_MSS);
+ }
+ }
+
+ ai->ai_mtu = (ushort)mss;
+
+#ifndef _PNP_POWER
+ Info->lip_mss = mss;
+#endif
+
+ // Read the speed for local purposes.
+ if ((Status = DoNDISRequest(ai, NdisRequestQueryInformation,
+ OID_GEN_LINK_SPEED, &speed, sizeof(speed), NULL)) == NDIS_STATUS_SUCCESS) {
+ ai->ai_speed = speed * 100L;
+#ifndef _PNP_POWER
+ Info->lip_speed = ai->ai_speed;
+#endif
+ }
+
+ // Read and save the options.
+ Status = DoNDISRequest(ai, NdisRequestQueryInformation, OID_GEN_MAC_OPTIONS,
+ &MacOpts, sizeof(MacOpts), NULL);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+#ifndef _PNP_POWER
+ Info->lip_flags = 0;
+#else
+ *Flags = 0;
+#endif
+ else
+#ifndef _PNP_POWER
+ Info->lip_flags =
+#else
+ *Flags =
+#endif
+ (MacOpts & NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA) ? LIP_COPY_FLAG : 0;
+
+ // Read and store the vendor description string.
+ Status = DoNDISRequest(ai, NdisRequestQueryInformation,
+ OID_GEN_VENDOR_DESCRIPTION, &ai->ai_desc, 0, &Needed);
+
+ if ((Status == NDIS_STATUS_INVALID_LENGTH) ||
+ (Status == NDIS_STATUS_BUFFER_TOO_SHORT)) {
+ // We know the size we need. Allocate a buffer.
+ buffer = CTEAllocMem(Needed);
+ if (buffer != NULL) {
+ Status = DoNDISRequest(ai, NdisRequestQueryInformation,
+ OID_GEN_VENDOR_DESCRIPTION, buffer, Needed, NULL);
+ if (Status == NDIS_STATUS_SUCCESS) {
+ ai->ai_desc = buffer;
+ ai->ai_desclen = Needed;
+ }
+ }
+ }
+
+ // Allocate our small and big buffer pools.
+
+ if ((sbsize & 0x3)) {
+ //
+ // Must 32 bit align the buffers so pointers to them will be aligned.
+ //
+ sbsize = ((sbsize >> 2) + 1) << 2;
+ }
+
+ ai->ai_sbsize = sbsize;
+
+ // Pre-prime the ARP header buffer list.
+ Buffer = GrowARPHeaders(ai);
+ if (Buffer != NULL) {
+ FreeARPBuffer(ai, Buffer);
+ }
+
+
+ if ((buffer = CTEAllocMem((sbsize+sizeof(ARPHeader)) * ARPPackets)) == (uchar *)NULL) {
+ FreeARPInterface(ai);
+ return FALSE;
+ }
+
+ // Link big buffers into the list.
+ ai->ai_bbbase = buffer;
+ ai->ai_bblist = (uchar *)NULL;
+ for (i = 0; i < ARPPackets; i++) {
+ *(char **)&*buffer = ai->ai_bblist;
+ ai->ai_bblist = buffer;
+ buffer += sbsize+sizeof(ARPHeader);
+ }
+
+ // Everything's set up, so get the ARP timer running.
+ CTEStartTimer(&ai->ai_timer, ARP_TIMER_TIME, ARPTimeout, ai);
+
+ return TRUE;
+
+}
+
+#ifndef CHICAGO
+#pragma END_INIT
+#endif
+
+#ifdef _PNP_POWER
+
+//* ARPDynRegister - Dynamically register IP.
+//
+// Called by IP when he's about done binding to register with us. Since we
+// call him directly, we don't save his info here. We do keep his context
+// and index number.
+//
+// Input: See ARPRegister
+//
+// Returns: Nothing.
+//
+int
+ARPDynRegister(PNDIS_STRING Adapter, void *IPContext, IPRcvRtn RcvRtn,
+ IPTxCmpltRtn TxCmpltRtn, IPStatusRtn StatusRtn, IPTDCmpltRtn TDCmpltRtn,
+ IPRcvCmpltRtn RcvCmpltRtn, struct LLIPBindInfo *Info, uint NumIFBound)
+{
+ ARPInterface *Interface = (ARPInterface *)Info->lip_context;
+
+ Interface->ai_context = IPContext;
+ Interface->ai_index = NumIFBound;
+
+ return TRUE;
+}
+
+//* ARPBindAdapter - Bind and initialize an adapter.
+//
+// Called in a PNP environment to initialize and bind an adapter. We open
+// the adapter and get it running, and then we call up to IP to tell him
+// about it. IP will initialize, and if all goes well call us back to start
+// receiving.
+//
+// Input: RetStatus - Where to return the status of this call.
+// BindContext - Handle to use for calling BindAdapterComplete.
+// AdapterName - Pointer to name of adapter.
+// SS1 - System specific 1 parameter.
+// SS2 - System specific 2 parameter.
+//
+// Returns: Nothing.
+//
+void NDIS_API
+ARPBindAdapter(PNDIS_STATUS RetStatus, NDIS_HANDLE BindContext,
+ PNDIS_STRING AdapterName, PVOID SS1, PVOID SS2)
+{
+ uint Flags; // MAC binding flags.
+ ARPInterface *Interface; // Newly created interface.
+ PNDIS_STRING ConfigName; // Name used by IP for config. info.
+ IP_STATUS Status; // State of IPAddInterface call.
+ LLIPBindInfo BindInfo; // Binding informatio for IP.
+ NDIS_HANDLE Handle ;
+
+ CTERefillMem();
+
+ if (!OpenIFConfig(SS1, &Handle)) {
+ *RetStatus = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ // If IsLLInterfaceValueNull is FALSE then this means that some other ARP module is
+ // used for this device so we skip it.
+ //
+ if (IsLLInterfaceValueNull(Handle) == FALSE) {
+ *RetStatus = NDIS_STATUS_FAILURE;
+ CloseIFConfig(Handle);
+ return ;
+ }
+
+ CloseIFConfig(Handle);
+
+
+ // First, open the adapter and get the info.
+ if (!ARPRegister(AdapterName, &Flags, &Interface)) {
+ *RetStatus = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ CTERefillMem();
+
+ // OK, we're opened the adapter. Call IP to tell him about it.
+ BindInfo.lip_context = Interface;
+ BindInfo.lip_transmit = ARPTransmit;
+ BindInfo.lip_transfer = ARPXferData;
+ BindInfo.lip_close = ARPClose;
+ BindInfo.lip_addaddr = ARPAddAddr;
+ BindInfo.lip_deladdr = ARPDeleteAddr;
+ BindInfo.lip_invalidate = ARPInvalidate;
+ BindInfo.lip_open = ARPOpen;
+ BindInfo.lip_qinfo = ARPQueryInfo;
+ BindInfo.lip_setinfo = ARPSetInfo;
+ BindInfo.lip_getelist = ARPGetEList;
+ BindInfo.lip_mss = Interface->ai_mtu;
+ BindInfo.lip_speed = Interface->ai_speed;
+ BindInfo.lip_flags = Flags;
+ BindInfo.lip_addrlen = Interface->ai_addrlen;
+ BindInfo.lip_addr = Interface->ai_addr;
+
+ Status = IPAddInterface((PNDIS_STRING)SS1, SS2, Interface, ARPDynRegister,
+ &BindInfo);
+
+ if (Status != IP_SUCCESS) {
+ // Need to close the binding. FreeARPInterface will do that, as well
+ // as freeing resources.
+
+ FreeARPInterface(Interface);
+ *RetStatus = NDIS_STATUS_FAILURE;
+ } else
+ *RetStatus = NDIS_STATUS_SUCCESS;
+
+}
+
+//* ARPUnbindAdapter - Unbind from an adapter.
+//
+// Called when we need to unbind from an adapter. We'll call up to IP to tell
+// him. When he's done, we'll free our memory and return.
+//
+// Input: RetStatus - Where to return status from call.
+// ProtBindContext - The context we gave NDIS earlier - really a
+// pointer to an ARPInterface structure.
+// UnbindContext - Context for completeing this request.
+//
+// Returns: Nothing.
+//
+void NDIS_API
+ARPUnbindAdapter(PNDIS_STATUS RetStatus, NDIS_HANDLE ProtBindContext,
+ NDIS_HANDLE UnbindContext)
+{
+ ARPInterface *Interface = (ARPInterface *)ProtBindContext;
+ NDIS_STATUS Status; // Status of close call.
+ CTELockHandle LockHandle;
+ NDIS_HANDLE Handle;
+
+ // Shut him up, so we don't get any more frames.
+ Interface->ai_pfilter = 0;
+ DoNDISRequest(Interface, NdisRequestSetInformation,
+ OID_GEN_CURRENT_PACKET_FILTER, &Interface->ai_pfilter, sizeof(uint),
+ NULL);
+
+ // Mark him as down.
+ Interface->ai_state = INTERFACE_DOWN;
+ Interface->ai_adminstate = IF_STATUS_DOWN;
+
+ // Now tell IP he's gone. We need to make sure that we don't tell him twice.
+ // To do this we set the context to NULL after we tell him the first time,
+ // and we check to make sure it's non-NULL before notifying him.
+
+ if (Interface->ai_context != NULL) {
+ IPDelInterface(Interface->ai_context);
+ Interface->ai_context = NULL;
+ }
+
+ // Finally, close him. We do this here so we can return a valid status.
+
+ CTEGetLock(&Interface->ai_lock, &LockHandle);
+
+ if (Interface->ai_handle != NULL) {
+ Handle = Interface->ai_handle;
+ Interface->ai_handle = NULL;
+ CTEFreeLock(&Interface->ai_lock, LockHandle);
+
+ CTEInitBlockStruc(&Interface->ai_block);
+ NdisCloseAdapter(&Status, Handle);
+
+ // Block for close to complete.
+ if (Status == NDIS_STATUS_PENDING)
+ Status = (NDIS_STATUS)CTEBlock(&Interface->ai_block);
+ } else {
+ CTEFreeLock(&Interface->ai_lock, LockHandle);
+ Status = NDIS_STATUS_SUCCESS;
+ }
+
+ *RetStatus = Status;
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ FreeARPInterface(Interface);
+ }
+}
+
+extern ulong VIPTerminate;
+
+//* ARPUnloadProtocol - Unload.
+//
+// Called when we need to unload. All we do is call up to IP, and return.
+//
+// Input: Nothing.
+//
+// Returns: Nothing.
+//
+void NDIS_API
+ARPUnloadProtocol(void)
+{
+ NDIS_STATUS Status;
+
+#ifdef CHICAGO
+
+ IPULUnloadNotify();
+
+ if (VIPTerminate) {
+ NdisDeregisterProtocol(&Status, ARPHandle);
+ CTEUnload(NULL);
+ }
+
+#endif
+
+}
+
+#endif
+
diff --git a/private/ntos/tdi/tcpip/ip/arp.h b/private/ntos/tdi/tcpip/ip/arp.h
new file mode 100644
index 000000000..d294b2dce
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/arp.h
@@ -0,0 +1,21 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1992 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** ARP.H - Exports from ARP.
+//
+// This file contains the public definitons from ARP.
+extern int ARPInit(void);
+#ifndef _PNP_POWER
+extern int ARPRegister(PNDIS_STRING, void *, IPRcvRtn, IPTxCmpltRtn,
+ IPStatusRtn, IPTDCmpltRtn, IPRcvCmpltRtn, struct LLIPBindInfo *,
+ uint);
+#else
+int
+ARPRegister(PNDIS_STRING Adapter, uint *Flags, struct ARPInterface **Interface);
+#endif
+
+
+
diff --git a/private/ntos/tdi/tcpip/ip/arpdef.h b/private/ntos/tdi/tcpip/ip/arpdef.h
new file mode 100644
index 000000000..6278fdb60
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/arpdef.h
@@ -0,0 +1,340 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1992 **/
+/********************************************************************/
+/* :ts=4 */
+
+//*** arpdef.h - ARP definitions
+//
+// This file containes all of the private ARP related definitions.
+
+
+#define MEDIA_DIX 0
+#define MEDIA_TR 1
+#define MEDIA_FDDI 2
+#define MEDIA_ARCNET 3
+
+#define MAX_MEDIA 4
+
+#define INTERFACE_UP 0 // Interface is up.
+#define INTERFACE_INIT 1 // Interface is initializing.
+#define INTERFACE_DOWN 2 // Interface is down.
+
+#define LOOKAHEAD_SIZE 128 // A reasonable lookahead size
+
+// Definitions for state of an ATE. The 'RESOLVING' indicators must occur first.
+#define ARP_RESOLVING_LOCAL 0 // Address is being resolved (on local ring, if TR)
+#define ARP_RESOLVING_GLOBAL 1 // Address is being resolved globally.
+#define ARP_RESOLVING ARP_RESOLVING_GLOBAL
+#define ARP_GOOD 2 // ATE is good.
+#define ARP_BAD 3 // ATE is bad.
+#define ARP_FLOOD_RATE 1000L // No more than once a second.
+#define ARP_802_ADDR_LENGTH 6 // Length of an 802 address.
+
+#define MIN_ETYPE 0x600 // Minimum valid Ethertype
+#define SNAP_SAP 170
+#define SNAP_UI 3
+
+
+//* Structure of an Ethernet header.
+struct ENetHeader {
+ uchar eh_daddr[ARP_802_ADDR_LENGTH];
+ uchar eh_saddr[ARP_802_ADDR_LENGTH];
+ ushort eh_type;
+}; /* ENetHeader */
+
+typedef struct ENetHeader ENetHeader;
+
+//* Structure of a token ring header.
+struct TRHeader {
+ uchar tr_ac;
+ uchar tr_fc;
+ uchar tr_daddr[ARP_802_ADDR_LENGTH];
+ uchar tr_saddr[ARP_802_ADDR_LENGTH];
+}; /* TRHeader */
+#define ARP_AC 0x10
+#define ARP_FC 0x40
+#define TR_RII 0x80
+
+typedef struct TRHeader TRHeader;
+struct RC {
+ uchar rc_blen; // Broadcast indicator and length.
+ uchar rc_dlf; // Direction and largest frame.
+}; /* RC */
+#define RC_DIR 0x80
+#define RC_LENMASK 0x1f
+#define RC_SRBCST 0xc2 // Single route broadcast RC.
+#define RC_ARBCST 0x82 // All route broadcast RC.
+#define RC_LMASK 0x1F // Mask for length field for route
+ // information
+#define RC_LEN 0x2 // Length to put in the length bits
+ // when sending source routed
+ // frames
+#define RC_BCST_LEN 0x70 // Length for a broadcast.
+#define RC_LF_MASK 0x70 // Mask for length bits.
+
+typedef struct RC RC;
+
+//* Structure of source routing information.
+struct SRInfo {
+ RC sri_rc; // Routing control info.
+ ushort sri_rd[1]; // Routing designators.
+}; /* SRInfo */
+
+#define ARP_MAX_RD 8
+
+typedef struct SRInfo SRInfo;
+
+//* Structure of an FDDI header.
+struct FDDIHeader {
+ uchar fh_pri;
+ uchar fh_daddr[ARP_802_ADDR_LENGTH];
+ uchar fh_saddr[ARP_802_ADDR_LENGTH];
+}; /* FDDIHeader */
+
+typedef struct FDDIHeader FDDIHeader;
+
+#define ARP_FDDI_PRI 0x57
+#define ARP_FDDI_MSS 4352
+
+//* Structure of an ARCNET header.
+struct ARCNetHeader {
+ uchar ah_saddr;
+ uchar ah_daddr;
+ uchar ah_prot;
+}; /* ARCNetHeader */
+
+typedef struct ARCNetHeader ARCNetHeader;
+
+//* Structure of a SNAP header.
+struct SNAPHeader {
+ uchar sh_dsap;
+ uchar sh_ssap;
+ uchar sh_ctl;
+ uchar sh_protid[3];
+ ushort sh_etype;
+}; /* SNAPHeader */
+
+typedef struct SNAPHeader SNAPHeader;
+
+#define ARP_MAX_MEDIA_ENET sizeof(ENetHeader)
+#define ARP_MAX_MEDIA_TR (sizeof(TRHeader)+sizeof(RC)+(ARP_MAX_RD*sizeof(ushort))+sizeof(SNAPHeader))
+#define ARP_MAX_MEDIA_FDDI (sizeof(FDDIHeader)+sizeof(SNAPHeader))
+#define ARP_MAX_MEDIA_ARC sizeof(ARCNetHeader)
+
+#define ENET_BCAST_MASK 0x01
+#define TR_BCAST_MASK 0x80
+#define FDDI_BCAST_MASK 0x01
+#define ARC_BCAST_MASK 0xff
+
+#define ENET_BCAST_VAL 0x01
+#define TR_BCAST_VAL 0x80
+#define FDDI_BCAST_VAL 0x01
+#define ARC_BCAST_VAL 0x00
+
+#define ENET_BCAST_OFF 0x00
+#define TR_BCAST_OFF offsetof(struct TRHeader, tr_daddr)
+#define FDDI_BCAST_OFF offsetof(struct FDDIHeader, fh_daddr)
+#define ARC_BCAST_OFF offsetof(struct ARCNetHeader, ah_daddr)
+
+//* Structure of an ARP table entry.
+typedef struct ARPTableEntry {
+ struct ARPTableEntry *ate_next; // Next ATE in hash chain
+ ulong ate_valid; // Last time ATE was known to be valid.
+ IPAddr ate_dest; // IP address represented.
+ PNDIS_PACKET ate_packet; // Packet (if any) queued for resolution
+ RouteCacheEntry *ate_rce; // List of RCEs that reference this ATE.
+ DEFINE_LOCK_STRUCTURE(ate_lock) // Lock for this ATE.
+ uint ate_useticks; // Number of ticks left until this
+ // goes away.
+ uchar ate_addrlength; // Length of the address.
+ uchar ate_state; // State of this entry
+ uchar ate_addr[1]; // Address that maps to dest
+} ARPTableEntry;
+
+#define ALWAYS_VALID 0xffffffff
+
+//* Structure of the ARP table.
+#define ARP_TABLE_SIZE 32
+#define ARP_HASH(x) ((((uchar *)&(x))[3]) % ARP_TABLE_SIZE)
+typedef ARPTableEntry *ARPTable[];
+
+//* List structure for local representation of an IPAddress.
+typedef struct ARPIPAddr {
+ struct ARPIPAddr *aia_next; // Next in list.
+ uint aia_age;
+ IPAddr aia_addr; // The address.
+ IPMask aia_mask;
+ void *aia_context;
+} ARPIPAddr;
+
+#define ARPADDR_NOT_LOCAL 4
+#define ARPADDR_NEW_LOCAL 3
+#define ARPADDR_OLD_LOCAL 0
+
+//* List structure for Proxy-ARP addresses.
+typedef struct ARPPArpAddr {
+ struct ARPPArpAddr *apa_next; // Next in list.
+ IPAddr apa_addr; // The address.
+ IPMask apa_mask; // And the mask.
+} ARPPArpAddr;
+
+//* List structure for a multicast IP address.
+typedef struct ARPMCastAddr {
+ struct ARPMCastAddr *ama_next; // Next in list.
+ IPAddr ama_addr; // The (masked) address.
+ uint ama_refcnt; // Reference count for this address.
+} ARPMCastAddr;
+
+#define ARP_MCAST_MASK 0xffff7f00
+
+#define ARP_TIMER_TIME 1000L
+#define ARP_RESOLVE_TIMEOUT 1000L
+#define ARP_MIN_VALID_TIMEOUT 600000L
+
+#ifdef VXD
+#define ARP_DEFAULT_MAXHDRS 100
+#else
+#define ARP_DEFAULT_MAXHDRS 0xffffffff
+#endif
+
+typedef struct ARPBufferTracker {
+ struct ARPBufferTracker *abt_next;
+ NDIS_HANDLE abt_handle;
+ uchar *abt_buffer;
+} ARPBufferTracker;
+
+//* Structure of information we keep on a per-interface basis.
+typedef struct ARPInterface {
+ void *ai_context; // Upper layer context info.
+ NDIS_HANDLE ai_handle; // NDIS bind handle.
+ NDIS_MEDIUM ai_media; // Media type.
+ NDIS_HANDLE ai_bpool; // Handle for buffer pool.
+ NDIS_HANDLE ai_ppool; // Handle for packet pool.
+ DEFINE_LOCK_STRUCTURE(ai_lock) // Lock for this structure.
+ DEFINE_LOCK_STRUCTURE(ai_ARPTblLock) // ARP Table lock for this structure.
+#ifdef NT
+ SLIST_HEADER ai_sblist; // Free list of header buffers.
+#else
+ PNDIS_BUFFER ai_sblist; // Free list of header buffers.
+#endif
+ uchar *ai_bblist; // Free list of 'big' buffers.
+ ARPTable *ai_ARPTbl; // Pointer to the ARP table for this interface
+ ARPIPAddr ai_ipaddr; // Local IP address list.
+ ARPPArpAddr *ai_parpaddr; // Proxy ARP address list.
+ IPAddr ai_bcast; // Broadcast mask for this interface.
+ // SNMP required counters
+ uint ai_inoctets; // Input octets.
+ uint ai_inpcount[2]; // Count of nonunicast and unicast
+ // packets received.
+ uint ai_outoctets; // Output octets
+ uint ai_outpcount[2];// Count of nonunicast and unicast
+ // packets sent.
+ uint ai_qlen; // Output q length.
+ uchar ai_addr[ARP_802_ADDR_LENGTH]; // Local HW address.
+ uchar ai_sbsize; // Size of a small buffer
+ uchar ai_state; // State of the interface. Union of
+ // admin and operational states.
+ uchar ai_addrlen; // Length of ai_addr.
+ uchar ai_bcastmask; // Mask for checking unicast.
+ uchar ai_bcastval; // Value to check against.
+ uchar ai_bcastoff; // Offset in frame to check against.
+ uchar ai_hdrsize; // Size of 'typical' header.
+ uchar ai_snapsize; // Size of snap header, if any.
+ uchar ai_pad[2]; // PAD PAD
+ uint ai_pfilter; // Packet filter for this i/f.
+ uint ai_count; // Number of entries in the ARPTable.
+ uint ai_parpcount; // Number of proxy ARP entries.
+ CTETimer ai_timer; // ARP timer for this interface.
+ CTEBlockStruc ai_block; // Structure for blocking on.
+ ushort ai_mtu; // MTU for this interface.
+ uchar ai_adminstate; // Admin state.
+ uchar ai_operstate; // Operational state;
+ uint ai_speed; // Speed.
+ uint ai_lastchange; // Last change time.
+ uint ai_indiscards; // In discards.
+ uint ai_inerrors; // Input errors.
+ uint ai_uknprotos; // Unknown protocols received.
+ uint ai_outdiscards; // Output packets discarded.
+ uint ai_outerrors; // Output errors.
+ uint ai_desclen; // Length of desc. string.
+ uint ai_index; // Global I/F index ID.
+ uint ai_atinst; // AT instance number.
+ uint ai_ifinst; // IF instance number.
+ char *ai_desc; // Descriptor string.
+ ARPMCastAddr *ai_mcast; // Multicast list.
+ uint ai_mcastcnt; // Count of elements on mcast list.
+ void *ai_bbbase; // Base of big buffers.
+ uint ai_curhdrs; // Current number of headers.
+ uint ai_maxhdrs; // Maximum allowed number of headers.
+ ARPBufferTracker *ai_buflist; // List of header buffer handles.
+} ARPInterface;
+
+typedef struct ARPNotifyStruct {
+ CTEEvent ans_event;
+ uint ans_shutoff;
+ IPAddr ans_addr;
+ uint ans_hwaddrlen;
+ uchar ans_hwaddr[1];
+} ARPNotifyStruct;
+
+//* NOTE: These two values MUST stay at 0 and 1.
+#define AI_UCAST_INDEX 0
+#define AI_NONUCAST_INDEX 1
+
+#define ARP_DEFAULT_PACKETS 10 // Default to this many packets.
+#define ARP_DEFAULT_BUFFERS 50 // And this many buffers.
+
+#define ARP_HDRBUF_GROW_SIZE 32 // This many header buffers.
+
+//* Structure of information passed as context in RCE.
+typedef struct ARPContext {
+ RouteCacheEntry *ac_next; // Next RCE in ARP table chain.
+ ARPTableEntry *ac_ate; // Back pointer to ARP table entry.
+} ARPContext;
+
+typedef struct IPNMEContext {
+ uint inc_index;
+ ARPTableEntry *inc_entry;
+} IPNMEContext;
+
+#ifdef NT
+//
+// This structure must be packed under NT.
+//
+#include <packon.h>
+#endif // NT
+
+// Structure of an ARP header.
+struct ARPHeader {
+ ushort ah_hw; // Hardware address space.
+ ushort ah_pro; // Protocol address space.
+ uchar ah_hlen; // Hardware address length.
+ uchar ah_plen; // Protocol address length.
+ ushort ah_opcode; // Opcode.
+ uchar ah_shaddr[ARP_802_ADDR_LENGTH]; // Source HW address.
+ IPAddr ah_spaddr; // Source protocol address.
+ uchar ah_dhaddr[ARP_802_ADDR_LENGTH]; // Destination HW address.
+ IPAddr ah_dpaddr; // Destination protocol address.
+}; /* ARPHeader */
+
+#ifdef NT
+#include <packoff.h>
+#endif // NT
+
+typedef struct ARPHeader ARPHeader;
+
+#define ARP_ETYPE_IP 0x800
+#define ARP_ETYPE_ARP 0x806
+#define ARP_REQUEST 1
+#define ARP_RESPONSE 2
+#define ARP_HW_ENET 1
+#define ARP_HW_802 6
+#define ARP_HW_ARCNET 7
+
+#define ARP_ARCPROT_ARP 0xd5
+#define ARP_ARCPROT_IP 0xd4
+
+// The size we need to back off the buffer length because ARCNet address
+// are one bytes instead of six.
+#define ARCNET_ARPHEADER_ADJUSTMENT 10
diff --git a/private/ntos/tdi/tcpip/ip/dirs b/private/ntos/tdi/tcpip/ip/dirs
new file mode 100644
index 000000000..0dab2f056
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/dirs
@@ -0,0 +1,22 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=up mp
diff --git a/private/ntos/tdi/tcpip/ip/icmp.c b/private/ntos/tdi/tcpip/ip/icmp.c
new file mode 100644
index 000000000..5faafa486
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/icmp.c
@@ -0,0 +1,1698 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1992 **/
+/********************************************************************/
+/* :ts=4 */
+
+//*** icmp.c - IP ICMP routines.
+//
+// This module contains all of the ICMP related routines.
+//
+
+#include "oscfg.h"
+#include "cxport.h"
+#include "ndis.h"
+#include "ip.h"
+#include "ipdef.h"
+#include "icmp.h"
+#include "info.h"
+#include "iproute.h"
+#include "ipinit.h"
+#include "ipxmit.h"
+#include <icmpif.h>
+
+extern ProtInfo IPProtInfo[]; // Protocol information table.
+
+extern void *IPRegisterProtocol(uchar, void *, void *, void *, void *);
+extern ULStatusProc FindULStatus(uchar);
+extern uchar IPUpdateRcvdOptions(IPOptInfo *, IPOptInfo *, IPAddr, IPAddr);
+extern void IPInitOptions(IPOptInfo *);
+extern IP_STATUS IPCopyOptions(uchar *, uint, IPOptInfo *);
+extern IP_STATUS IPFreeOptions(IPOptInfo *);
+extern uchar IPGetLocalAddr(IPAddr, IPAddr *);
+void ICMPRouterTimer(NetTableEntry *);
+
+extern NDIS_HANDLE BufferPool;
+
+extern NetTableEntry *NetTableList; // Pointer to the net table list.
+extern ProtInfo *RawPI; // Raw IP protinfo
+
+DEFINE_LOCK_STRUCTURE(ICMPHeaderLock)
+ICMPHeader *ICMPHeaderList;
+uint CurrentICMPHeaders;
+uint MaxICMPHeaders;
+
+ICMPStats ICMPInStats;
+ICMPStats ICMPOutStats;
+
+
+#ifdef NT
+#ifdef ALLOC_PRAGMA
+
+void ICMPInit(uint NumBuffers);
+
+IP_STATUS
+ICMPEchoRequest(
+ void *InputBuffer,
+ uint InputBufferLength,
+ EchoControl *ControlBlock,
+ EchoRtn Callback
+ );
+
+#pragma alloc_text(INIT, ICMPInit)
+#pragma alloc_text(PAGE, ICMPEchoRequest)
+
+#endif // ALLOC_PRAGMA
+#endif // NT
+
+
+//* UpdateICMPStats - Update ICMP statistics.
+//
+// A routine to update the ICMP statistics.
+//
+// Input: Stats - Pointer to stat. structure to update (input or output).
+// Type - Type of stat to update.
+//
+// Returns: Nothing.
+//
+void
+UpdateICMPStats(ICMPStats *Stats, uchar Type)
+{
+ switch (Type) {
+ case ICMP_DEST_UNREACH:
+ Stats->icmps_destunreachs++;
+ break;
+ case ICMP_TIME_EXCEED:
+ Stats->icmps_timeexcds++;
+ break;
+ case ICMP_PARAM_PROBLEM:
+ Stats->icmps_parmprobs++;
+ break;
+ case ICMP_SOURCE_QUENCH:
+ Stats->icmps_srcquenchs++;
+ break;
+ case ICMP_REDIRECT:
+ Stats->icmps_redirects++;
+ break;
+ case ICMP_TIMESTAMP:
+ Stats->icmps_timestamps++;
+ break;
+ case ICMP_TIMESTAMP_RESP:
+ Stats->icmps_timestampreps++;
+ break;
+ case ICMP_ECHO:
+ Stats->icmps_echos++;
+ break;
+ case ICMP_ECHO_RESP:
+ Stats->icmps_echoreps++;
+ break;
+ case ADDR_MASK_REQUEST:
+ Stats->icmps_addrmasks++;
+ break;
+ case ADDR_MASK_REPLY:
+ Stats->icmps_addrmaskreps++;
+ break;
+ default:
+ break;
+ }
+
+}
+
+//** GetICMPBuffer - Get an ICMP buffer, and allocate an NDIS_BUFFER that maps it.
+//
+// A routine to allocate an ICMP buffer and map an NDIS_BUFFER to it.
+//
+// Entry: Size - Size in bytes header buffer should be mapped as.
+// Buffer - Pointer to pointer to NDIS_BUFFER to return.
+//
+// Returns: Pointer to ICMP buffer if allocated, or NULL.
+//
+ICMPHeader *
+GetICMPBuffer(uint Size, PNDIS_BUFFER *Buffer)
+{
+ CTELockHandle Handle;
+ ICMPHeader **Header;
+ NDIS_STATUS Status;
+
+
+ CTEGetLock(&ICMPHeaderLock, &Handle);
+
+ Header = (ICMPHeader **)ICMPHeaderList;
+
+ if (Header == NULL) {
+ // Couldn't get a header from our free list. Try to allocate one.
+ Header = CTEAllocMem(sizeof(ICMPHeader) + sizeof(IPHeader) +
+ sizeof(IPHeader) + MAX_OPT_SIZE + 8);
+ if (Header == NULL) {
+ CTEFreeLock(&ICMPHeaderLock, Handle);
+ return (ICMPHeader *) NULL;
+ }
+ CurrentICMPHeaders++;
+ }
+ else {
+ ICMPHeaderList = *Header;
+ }
+
+ CTEFreeLock(&ICMPHeaderLock, Handle);
+
+ NdisAllocateBuffer(&Status, Buffer, BufferPool, Header, Size
+ + sizeof(IPHeader));
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ NdisBufferLength(*Buffer) = Size;
+ Header = (ICMPHeader **)((uchar *)Header + sizeof(IPHeader));
+
+ (*(ICMPHeader **)&Header)->ich_xsum = 0;
+ return (ICMPHeader *)Header;
+ }
+
+ // Couldn't get an NDIS_BUFFER, free the ICMP buffer.
+ CTEGetLock(&ICMPHeaderLock, &Handle);
+
+ if (CurrentICMPHeaders > MaxICMPHeaders) {
+ CurrentICMPHeaders--;
+ CTEFreeMem(Header);
+ } else {
+ *Header = ICMPHeaderList;
+ ICMPHeaderList = (ICMPHeader *)Header;
+ }
+
+ CTEFreeLock(&ICMPHeaderLock, Handle);
+
+ return (ICMPHeader *)NULL;
+}
+
+//** FreeICMPBuffer - Free an ICMP buffer.
+//
+// This routine puts an ICMP buffer back on our free list.
+//
+// Entry: Buffer - Pointer to NDIS_BUFFER to be freed.
+//
+// Returns: Nothing.
+//
+void
+FreeICMPBuffer(PNDIS_BUFFER Buffer)
+{
+ CTELockHandle Handle;
+ ICMPHeader **Header;
+ uint Length;
+
+ NdisQueryBuffer(Buffer, (PVOID *)&Header, &Length);
+ CTEGetLock(&ICMPHeaderLock, &Handle);
+ if (CurrentICMPHeaders > MaxICMPHeaders) {
+ CurrentICMPHeaders--;
+ CTEFreeMem(Header);
+ } else {
+ *Header = ICMPHeaderList;
+ ICMPHeaderList = (ICMPHeader *)Header;
+ }
+
+ CTEFreeLock(&ICMPHeaderLock, Handle);
+ NdisFreeBuffer(Buffer);
+}
+
+//** DeleteEC - Remove an EchoControl from an NTE, and return a pointer to it.
+//
+// This routine is called when we need to remove an echo control structure from
+// an NTE. We walk the list of EC structures on the NTE, and if we find a match
+// we remove it and return a pointer to it.
+//
+// Entry: NTE - Pointer to NTE to be searched.
+// Seq - Seq. # identifting the EC.
+//
+// Returns: Pointer to the EC if it finds it.
+//
+EchoControl *
+DeleteEC(NetTableEntry *NTE, ushort Seq)
+{
+ EchoControl *Prev, *Current;
+ CTELockHandle Handle;
+
+ CTEGetLock(&NTE->nte_lock, &Handle);
+ Prev = STRUCT_OF(EchoControl, &NTE->nte_echolist, ec_next);
+ Current = NTE->nte_echolist;
+ while(Current != (EchoControl *)NULL)
+ if (Current->ec_seq == Seq) {
+ Prev->ec_next = Current->ec_next;
+ break;
+ }
+ else {
+ Prev = Current;
+ Current = Current->ec_next;
+ }
+
+ CTEFreeLock(&NTE->nte_lock, Handle);
+ return Current;
+
+}
+
+//** ICMPSendComplete< - Complete an ICMP send.
+//
+// This routine is called when an ICMP send completes. We free the header buffer,
+// the data buffer if there is one, and the NDIS_BUFFER chain.
+//
+// Entry: DataPtr - Pointer to data buffer, if any.
+// BufferChain - Pointer to NDIS_BUFFER chain.
+//
+// Returns: Nothing
+//
+void
+ICMPSendComplete(void *DataPtr, PNDIS_BUFFER BufferChain)
+{
+ PNDIS_BUFFER DataBuffer;
+
+ NdisGetNextBuffer(BufferChain, &DataBuffer);
+ FreeICMPBuffer(BufferChain);
+
+ if (DataBuffer != (PNDIS_BUFFER)NULL) { // We had data with this ICMP send.
+#ifdef DEBUG
+ if (DataPtr == (void *)NULL)
+ DEBUGCHK;
+#endif
+ CTEFreeMem(DataPtr);
+ NdisFreeBuffer(DataBuffer);
+ }
+
+}
+
+//* XsumBufChain - Checksum a chain of buffers.
+//
+// Called when we need to checksum an IPRcvBuf chain.
+//
+// Input: BufChain - Buffer chain to be checksummed.
+//
+// Returns: The checksum.
+//
+ushort
+XsumBufChain(IPRcvBuf *BufChain)
+{
+ ulong CheckSum = 0;
+
+ if (BufChain == NULL)
+ DEBUGCHK;
+
+ do {
+ CheckSum += (ulong)xsum(BufChain->ipr_buffer, BufChain->ipr_size);
+ BufChain = BufChain->ipr_next;
+ } while (BufChain != NULL);
+
+ // Fold the checksum down.
+ CheckSum = (CheckSum >> 16) + (CheckSum & 0xffff);
+ CheckSum += (CheckSum >> 16);
+
+ return (ushort)CheckSum;
+}
+
+
+//** SendEcho - Send an ICMP Echo or Echo response.
+//
+// This routine sends an ICMP echo or echo response. The Echo/EchoResponse may
+// carry data. If it does we'll copy the data here. The request may also have
+// options. Options are not copied, as the IPTransmit routine will copy options.
+//
+// Entry: Dest - Destination to send to.
+// Source - Source to send from.
+// Type - Type of request (ECHO or ECHO_RESP)
+// ID - ID of request.
+// Seq - Seq. # of request.
+// Data - Pointer to data (NULL if none).
+// DataLength - Length in bytes of data
+// OptInfo - Pointer to IP Options structure.
+//
+// Returns: IP_STATUS of request.
+//
+IP_STATUS
+SendEcho(IPAddr Dest, IPAddr Source, uchar Type, ushort ID, ushort Seq,
+ IPRcvBuf *Data, uint DataLength, IPOptInfo *OptInfo)
+{
+ uchar *DataBuffer = (uchar *)NULL; // Pointer to data buffer.
+ PNDIS_BUFFER HeaderBuffer, Buffer; // Buffers for our header and user data.
+ NDIS_STATUS Status;
+ ICMPHeader *Header;
+ ushort header_xsum;
+ IP_STATUS IStatus; // Status of transmit
+
+ ICMPOutStats.icmps_msgs++;
+
+ Header = GetICMPBuffer(sizeof(ICMPHeader), &HeaderBuffer);
+ if (Header == (ICMPHeader *)NULL) {
+ ICMPOutStats.icmps_errors++;
+ return IP_NO_RESOURCES;
+ }
+
+#ifdef DEBUG
+ if (Type != ICMP_ECHO_RESP && Type != ICMP_ECHO)
+ DEBUGCHK;
+#endif
+
+ Header->ich_type = Type;
+ Header->ich_code = 0;
+ *(ushort *)&Header->ich_param = ID;
+ *((ushort *)&Header->ich_param + 1) = Seq;
+ header_xsum = xsum(Header, sizeof(ICMPHeader));
+ Header->ich_xsum = ~header_xsum;
+
+ // If there's data, get a buffer and copy it now. If we can't do this fail the request.
+ if (DataLength != 0) {
+ ulong TempXsum;
+ uint BytesToCopy, CopyIndex;
+
+ DataBuffer = CTEAllocMem(DataLength);
+ if (DataBuffer == (void *)NULL) { // Couldn't get a buffer
+ FreeICMPBuffer(HeaderBuffer);
+ ICMPOutStats.icmps_errors++;
+ return IP_NO_RESOURCES;
+ }
+
+ BytesToCopy = DataLength;
+ CopyIndex = 0;
+ do {
+ uint CopyLength;
+#ifdef DEBUG
+ if (Data == NULL) {
+ DEBUGCHK;
+ break;
+ }
+#endif
+
+ CopyLength = MIN(BytesToCopy, Data->ipr_size);
+
+ CTEMemCopy(DataBuffer + CopyIndex, Data->ipr_buffer, CopyLength);
+ Data = Data->ipr_next;
+ CopyIndex += CopyLength;
+ BytesToCopy -= CopyLength;
+ } while (BytesToCopy);
+
+ NdisAllocateBuffer(&Status, &Buffer, BufferPool, DataBuffer, DataLength);
+ if (Status != NDIS_STATUS_SUCCESS) { // Couldn't get an NDIS_BUFFER
+ CTEFreeMem(DataBuffer);
+ FreeICMPBuffer(HeaderBuffer);
+ ICMPOutStats.icmps_errors++;
+ return IP_NO_RESOURCES;
+ }
+
+ // Compute rest of xsum.
+ TempXsum = (ulong)header_xsum + (ulong)xsum(DataBuffer, DataLength);
+ TempXsum = (TempXsum >> 16) + (TempXsum & 0xffff);
+ TempXsum += (TempXsum >> 16);
+ Header->ich_xsum = ~(ushort)TempXsum;
+ NDIS_BUFFER_LINKAGE(HeaderBuffer) = Buffer;
+ }
+
+
+ UpdateICMPStats(&ICMPOutStats, Type);
+
+ IStatus = IPTransmit(IPProtInfo, DataBuffer, HeaderBuffer,
+ DataLength + sizeof(ICMPHeader), Dest, Source, OptInfo, NULL,
+ PROT_ICMP);
+
+ if (IStatus != IP_PENDING)
+ ICMPSendComplete(DataBuffer, HeaderBuffer);
+
+ return IStatus;
+}
+
+//** SendICMPMsg - Send an ICMP message
+//
+// This is the general ICMP message sending routine, called for most ICMP sends besides
+// echo. Basically, all we do is get a buffer, format the info, copy the input
+// header, and send the message.
+//
+// Entry: Src - IPAddr of source.
+// Dest - IPAddr of destination
+// Type - Type of request.
+// Code - Subcode of request.
+// Pointer - Pointer value for request.
+// Data - Pointer to data (NULL if none).
+// DataLength - Length in bytes of data
+//
+// Returns: IP_STATUS of request.
+//
+IP_STATUS
+SendICMPMsg(IPAddr Src, IPAddr Dest, uchar Type, uchar Code, ulong Pointer,
+ uchar *Data, uchar DataLength)
+{
+ PNDIS_BUFFER HeaderBuffer; // Buffer for our header
+ ICMPHeader *Header;
+ IP_STATUS IStatus; // Status of transmit
+ IPOptInfo OptInfo; // Options for this transmit.
+
+
+ ICMPOutStats.icmps_msgs++;
+
+ Header = GetICMPBuffer(sizeof(ICMPHeader) + DataLength, &HeaderBuffer);
+ if (Header == (ICMPHeader *)NULL) {
+ ICMPOutStats.icmps_errors++;
+ return IP_NO_RESOURCES;
+ }
+
+
+ Header->ich_type = Type;
+ Header->ich_code = Code;
+ Header->ich_param = Pointer;
+ if (Data)
+ CTEMemCopy(Header + 1, Data, DataLength);
+ Header->ich_xsum = ~xsum(Header, sizeof(ICMPHeader) + DataLength);
+
+ IPInitOptions(&OptInfo);
+
+ UpdateICMPStats(&ICMPOutStats, Type);
+
+ IStatus = IPTransmit(IPProtInfo, NULL, HeaderBuffer,
+ DataLength + sizeof(ICMPHeader), Dest, Src, &OptInfo, NULL,
+ PROT_ICMP);
+
+ if (IStatus != IP_PENDING)
+ ICMPSendComplete(NULL, HeaderBuffer);
+
+ return IStatus;
+
+}
+
+//** SendICMPErr - Send an ICMP error message
+//
+// This is the routine used to send an ICMP error message, such as Destination Unreachable.
+// We examine the header to find the length of the data, and also make sure we're not
+// replying to another ICMP error message or a broadcast message. Then we call SendICMPMsg
+// to send it.
+//
+// Entry: Src - IPAddr of source.
+// Header - Pointer to IP Header that caused the problem.
+// Type - Type of request.
+// Code - Subcode of request.
+// Pointer - Pointer value for request.
+//
+// Returns: IP_STATUS of request.
+//
+IP_STATUS
+SendICMPErr(IPAddr Src, IPHeader UNALIGNED *Header, uchar Type, uchar Code,
+ ulong Pointer)
+{
+ uchar HeaderLength; // Length in bytes if header.
+ uchar DType;
+
+ HeaderLength = (Header->iph_verlen & (uchar)~IP_VER_FLAG) << 2;
+
+ if (Header->iph_protocol == PROT_ICMP) {
+ ICMPHeader UNALIGNED *ICH = (ICMPHeader UNALIGNED *)
+ ((uchar *)Header + HeaderLength);
+
+ if (ICH->ich_type != ICMP_ECHO)
+ return IP_SUCCESS;
+ }
+
+ // Don't respond to sends to a broadcast destination.
+ DType = GetAddrType(Header->iph_dest);
+ if (DType == DEST_INVALID || IS_BCAST_DEST(DType))
+ return IP_SUCCESS;
+
+ // Don't respond if the source address is bad.
+ DType = GetAddrType(Header->iph_src);
+ if (DType == DEST_INVALID || IS_BCAST_DEST(DType) ||
+ (IP_LOOPBACK(Header->iph_dest) && DType != DEST_LOCAL))
+ return IP_SUCCESS;
+
+ // Make sure the source we're sending from is good.
+ if (IP_ADDR_EQUAL(Src, NULL_IP_ADDR) || GetAddrType(Src) != DEST_LOCAL)
+ return IP_SUCCESS;
+
+ // Double check to make sure it's an initial fragment.
+ if ((Header->iph_offset & IP_OFFSET_MASK) != 0)
+ return IP_SUCCESS;
+
+ return SendICMPMsg(Src, Header->iph_src, Type, Code, Pointer, (uchar *)Header,
+ (uchar)(HeaderLength + 8));
+
+}
+
+
+//** ICMPTimer - Timer for ICMP
+//
+// This is the timer routine called periodically by global IP timer. We walk through
+// the list of pending pings, and if we find one that's timed out we remove it and
+// call the finish routine.
+//
+// Entry: NTE - Pointer to NTE being timed out.
+//
+// Returns: Nothing
+//
+void
+ICMPTimer(NetTableEntry *NTE)
+{
+ CTELockHandle Handle;
+ EchoControl *TimeoutList = (EchoControl *)NULL; // Timed out entries.
+ EchoControl *Prev, *Current;
+ ulong Now = CTESystemUpTime();
+
+ CTEGetLock(&NTE->nte_lock, &Handle);
+ Prev = STRUCT_OF(EchoControl, &NTE->nte_echolist, ec_next);
+ Current = NTE->nte_echolist;
+ while(Current != (EchoControl *)NULL)
+ if ((Current->ec_active) && (Current->ec_to < Now)) { // This one's timed out.
+ Prev->ec_next = Current->ec_next;
+ // Link him on timed out list.
+ Current->ec_next = TimeoutList;
+ TimeoutList = Current;
+ Current = Prev->ec_next;
+ }
+ else {
+ Prev = Current;
+ Current = Current->ec_next;
+ }
+
+ CTEFreeLock(&NTE->nte_lock, Handle);
+
+ // Now go through the timed out entries, and call the completion routine.
+ while (TimeoutList != (EchoControl *)NULL) {
+ EchoRtn Rtn;
+
+ Current = TimeoutList;
+ TimeoutList = Current->ec_next;
+
+ Rtn = (EchoRtn)Current->ec_rtn;
+ (*Rtn)(Current, IP_REQ_TIMED_OUT, NULL, 0, NULL);
+ }
+
+ //
+ // [BUGBUG] Disabled for 4.0 sp2
+ //
+ // ICMPRouterTimer(NTE);
+
+}
+
+//* CompleteEcho - Complete an echo request.
+//
+// Called when we need to complete an echo request, either because of a response
+// or a received ICMP error message. We look it up, and then call the completion routine.
+//
+// Input: Header - Pointer to ICMP header causing completion.
+// Status - Final status of request.
+// Data - Data to be returned, if any.
+// DataSize - Size in bytes of data.
+// OptInfo - Option info structure.
+//
+// Returns: Nothing.
+//
+void
+CompleteEcho(ICMPHeader UNALIGNED *Header, IP_STATUS Status, IPRcvBuf *Data, uint DataSize,
+ IPOptInfo *OptInfo)
+{
+ ushort NTEContext;
+ EchoControl *EC;
+ EchoRtn Rtn;
+ NetTableEntry *NTE;
+
+ // Look up and remove the matching echo control block.
+ NTEContext = (*(ushort UNALIGNED *)&Header->ich_param);
+
+ for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next)
+ if (NTEContext == NTE->nte_context)
+ break;
+
+ if (NTE == NULL)
+ return; // Bad context value.
+
+ EC = DeleteEC(NTE, *(((ushort UNALIGNED *)&Header->ich_param) + 1));
+ if (EC != (EchoControl *)NULL) { // Found a match.
+ Rtn = (EchoRtn)EC->ec_rtn;
+ (*Rtn)(EC, Status, Data, DataSize, OptInfo);
+ }
+
+
+}
+
+//** ICMPStatus - ICMP status handling procedure.
+//
+// This is the procedure called during a status change, either from an incoming ICMP
+// message or a hardware status change. ICMP ignores most of these, unless we get an
+// ICMP status message that was caused be an echo request. In that case we will complete
+// the corresponding echo request with the appropriate error code.
+//
+// Input: StatusType - Type of status (NET or HW)
+// StatusCode - Code identifying IP_STATUS.
+// OrigDest - If this is net status, the original dest. of DG that triggered it.
+// OrigSrc - " " " " " , the original src.
+// Src - IP address of status originator (could be local or remote).
+// Param - Additional information for status - i.e. the param field of
+// an ICMP message.
+// Data - Data pertaining to status - for net status, this is the first
+// 8 bytes of the original DG.
+//
+// Returns: Nothing
+//
+void
+ICMPStatus(uchar StatusType, IP_STATUS StatusCode, IPAddr OrigDest, IPAddr OrigSrc, IPAddr Src,
+ ulong Param, void *Data)
+{
+ if (StatusType == IP_NET_STATUS) {
+ ICMPHeader UNALIGNED *ICH = (ICMPHeader UNALIGNED *)Data;
+ // ICH is the datagram that caused the message.
+
+ if (ICH->ich_type == ICMP_ECHO) { // And it was an echo request.
+ IPRcvBuf RcvBuf;
+
+ RcvBuf.ipr_next = NULL;
+ RcvBuf.ipr_buffer = (uchar *)&Src;
+ RcvBuf.ipr_size = sizeof(IPAddr);
+ CompleteEcho(ICH, StatusCode, &RcvBuf, sizeof(IPAddr), NULL);
+ }
+ }
+
+}
+
+//* ICMPMapStatus - Map an ICMP error to an IP status code.
+//
+// Called by ICMP status when we need to map from an incoming ICMP error code and type
+// to an ICMP status.
+//
+// Entry: Type - Type of ICMP error.
+// Code - Subcode of error.
+//
+// Returns: Corresponding IP status.
+//
+IP_STATUS
+ICMPMapStatus(uchar Type, uchar Code)
+{
+ switch (Type) {
+
+ case ICMP_DEST_UNREACH:
+ switch (Code) {
+ case NET_UNREACH:
+ case HOST_UNREACH:
+ case PROT_UNREACH:
+ case PORT_UNREACH:
+ return IP_DEST_UNREACH_BASE + Code;
+ break;
+ case FRAG_NEEDED:
+ return IP_PACKET_TOO_BIG;
+ break;
+ case SR_FAILED:
+ return IP_BAD_ROUTE;
+ break;
+ case DEST_NET_UNKNOWN:
+ case SRC_ISOLATED:
+ case DEST_NET_ADMIN:
+ case NET_UNREACH_TOS:
+ return IP_DEST_NET_UNREACHABLE;
+ break;
+ case DEST_HOST_UNKNOWN:
+ case DEST_HOST_ADMIN:
+ case HOST_UNREACH_TOS:
+ return IP_DEST_HOST_UNREACHABLE;
+ break;
+ default:
+ return IP_DEST_NET_UNREACHABLE;
+ }
+ break;
+ case ICMP_TIME_EXCEED:
+ if (Code == TTL_IN_TRANSIT)
+ return IP_TTL_EXPIRED_TRANSIT;
+ else
+ return IP_TTL_EXPIRED_REASSEM;
+ break;
+ case ICMP_PARAM_PROBLEM:
+ return IP_PARAM_PROBLEM;
+ break;
+ case ICMP_SOURCE_QUENCH:
+ return IP_SOURCE_QUENCH;
+ break;
+ default:
+ return IP_GENERAL_FAILURE;
+ break;
+ }
+
+}
+
+void
+SendRouterSolicitation(NetTableEntry *NTE)
+{
+ if (NTE->nte_rtrdiscovery) {
+ SendICMPMsg(NTE->nte_addr, NTE->nte_rtrdiscaddr, ICMP_ROUTER_SOLICITATION,
+ 0, 0, NULL, 0);
+ }
+}
+
+//** ICMPRouterTimer - Timeout default gateway entries
+//
+// This is the router advertisement timeout handler. When a router
+// advertisement is received, we add the routers to our default gateway
+// list if applicable. We then run a timer on the entries and refresh
+// the list as new advertisements are received. If we fail to hear an
+// update for a router within the specified lifetime we will delete the
+// route from our routing tables.
+//
+
+void
+ICMPRouterTimer(NetTableEntry *NTE)
+{
+ CTELockHandle Handle;
+ IPRtrEntry *rtrentry;
+ IPRtrEntry *temprtrentry;
+ IPRtrEntry *lastrtrentry = NULL;
+ uint SendIt = FALSE;
+
+ CTEGetLock(&NTE->nte_lock, &Handle);
+ rtrentry = NTE->nte_rtrlist;
+ while (rtrentry != NULL) {
+ if (--rtrentry->ire_lifetime == 0) {
+ if (lastrtrentry == NULL) {
+ NTE->nte_rtrlist = rtrentry->ire_next;
+ } else {
+ lastrtrentry->ire_next = rtrentry->ire_next;
+ }
+ temprtrentry = rtrentry;
+ rtrentry = rtrentry->ire_next;
+// DbgPrint("DeleteRoute: RtrAddr = %08x\n",temprtrentry->ire_addr);
+ DeleteRoute(NULL_IP_ADDR, DEFAULT_MASK,
+ temprtrentry->ire_addr, NTE->nte_if);
+ CTEFreeMem(temprtrentry);
+ } else {
+ lastrtrentry = rtrentry;
+ rtrentry = rtrentry->ire_next;
+ }
+ }
+ if (NTE->nte_rtrdisccount != 0) {
+ NTE->nte_rtrdisccount--;
+ if ((NTE->nte_rtrdiscstate == NTE_RTRDISC_SOLICITING) &&
+ ((NTE->nte_rtrdisccount%SOLICITATION_INTERVAL) == 0)) {
+ SendIt = TRUE;
+ }
+ if ((NTE->nte_rtrdiscstate == NTE_RTRDISC_DELAYING) &&
+ (NTE->nte_rtrdisccount == 0)) {
+ NTE->nte_rtrdisccount = (SOLICITATION_INTERVAL)*(MAX_SOLICITATIONS-1);
+ NTE->nte_rtrdiscstate = NTE_RTRDISC_SOLICITING;
+ SendIt = TRUE;
+ }
+ }
+ CTEFreeLock(&NTE->nte_lock, Handle);
+ if (SendIt) {
+ SendRouterSolicitation(NTE);
+ }
+
+}
+
+//** ProcessRouterAdvertisement - Process a router advertisement
+//
+// This is the router advertisement handler. When a router advertisement
+// is received, we add the routers to our default gateway list if applicable.
+//
+
+uint
+ProcessRouterAdvertisement(IPAddr Src, IPAddr LocalAddr, NetTableEntry *NTE,
+ ICMPRouterAdHeader UNALIGNED *AdHeader, IPRcvBuf *RcvBuf, uint Size)
+{
+ uchar NumAddrs = AdHeader->irah_numaddrs;
+ uchar AddrEntrySize = AdHeader->irah_addrentrysize;
+ ushort Lifetime = net_short(AdHeader->irah_lifetime);
+ ICMPRouterAdAddrEntry UNALIGNED *RouterAddr = (ICMPRouterAdAddrEntry UNALIGNED *)RcvBuf->ipr_buffer;
+ uint i;
+ CTELockHandle Handle;
+ IPRtrEntry *rtrentry;
+ IPRtrEntry *lastrtrentry = NULL;
+ int Update = FALSE;
+
+// DbgPrint("ProcessRouterAdvertisement: NumAddrs = %d\n",NumAddrs);
+// DbgPrint("ProcessRouterAdvertisement: AddrEntrySize = %d\n",AddrEntrySize);
+// DbgPrint("ProcessRouterAdvertisement: Lifetime = %d\n",Lifetime);
+
+ if ((NumAddrs == 0) || (AddrEntrySize < 2)) // per rfc 1256
+ return FALSE;
+
+ CTEGetLock(&NTE->nte_lock, &Handle);
+ for ( i=0; i<NumAddrs; i++, RouterAddr++) {
+ if ((RouterAddr->irae_addr & NTE->nte_mask) != (NTE->nte_addr & NTE->nte_mask)) {
+ continue;
+ }
+ if (!IsRouteICMP(NULL_IP_ADDR, DEFAULT_MASK, RouterAddr->irae_addr, NTE->nte_if)) {
+ continue;
+ }
+
+// DbgPrint("ProcessRouterAdvertisement: RtrAddr = %08x\n",RouterAddr->irae_addr);
+// DbgPrint("ProcessRouterAdvertisement: RtrPreference = %d\n",net_long(RouterAddr->irae_preference));
+ rtrentry = NTE->nte_rtrlist;
+ while (rtrentry != NULL) {
+ if (rtrentry->ire_addr == RouterAddr->irae_addr) {
+ rtrentry->ire_lifetime = Lifetime*2;
+ if (rtrentry->ire_preference != RouterAddr->irae_preference) {
+ rtrentry->ire_preference = RouterAddr->irae_preference;
+ Update = TRUE;
+ }
+ break;
+ }
+ lastrtrentry = rtrentry;
+ rtrentry = rtrentry->ire_next;
+ }
+
+ if (rtrentry == NULL) {
+ rtrentry = (IPRtrEntry *) CTEAllocMem(sizeof(IPRtrEntry));
+ if (rtrentry == NULL) {
+ return FALSE;
+ }
+ rtrentry->ire_next = NULL;
+ rtrentry->ire_addr = RouterAddr->irae_addr;
+ rtrentry->ire_preference = RouterAddr->irae_preference;
+ rtrentry->ire_lifetime = Lifetime*2;
+ if (lastrtrentry == NULL) {
+ NTE->nte_rtrlist = rtrentry;
+ } else {
+ lastrtrentry->ire_next = rtrentry;
+ }
+ Update = TRUE;
+ }
+
+ if (Update && (RouterAddr->irae_preference != (long)0x00000080)) { // per rfc 1256
+// DbgPrint("AddRoute: RtrAddr = %08x\n",RouterAddr->irae_addr);
+ AddRoute(NULL_IP_ADDR, DEFAULT_MASK, RouterAddr->irae_addr,
+ NTE->nte_if, NTE->nte_mss,
+ (uint)(1000-net_long(RouterAddr->irae_preference)), // invert for metric
+ IRE_PROTO_ICMP, ATYPE_OVERRIDE, NULL);
+ }
+ Update = FALSE;
+ }
+ CTEFreeLock(&NTE->nte_lock, Handle);
+
+ return TRUE;
+}
+
+//** ICMPRcv - Receive an ICMP datagram.
+//
+// Called by the main IP code when we receive an ICMP datagram. The action we
+// take depends on what the DG is. For some DGs, we call upper layer status
+// handlers. For Echo Requests, we call the echo responder.
+//
+// Entry: NTE - Pointer to NTE on which ICMP message was received.
+// Dest - IPAddr of destionation.
+// Src - IPAddr of source
+// LocalAddr - Local address of network which caused this to be
+// received.
+// SrcAddr - Address of local interface which received the
+// packet
+// IPHdr - Pointer to IP Header
+// IPHdrLength - Bytes in Header.
+// RcvBuf - ICMP message buffer.
+// Size - Size in bytes of ICMP message.
+// IsBCast - Boolean indicator of whether or not this came in
+// as a bcast.
+// Protocol - Protocol this came in on.
+// OptInfo - Pointer to info structure for received options.
+//
+// Returns: Status of reception
+//
+IP_STATUS
+ICMPRcv(NetTableEntry *NTE, IPAddr Dest, IPAddr Src, IPAddr LocalAddr,
+ IPAddr SrcAddr, IPHeader UNALIGNED *IPHdr, uint IPHdrLength,
+ IPRcvBuf *RcvBuf, uint Size, uchar IsBCast, uchar Protocol,
+ IPOptInfo *OptInfo)
+{
+ ICMPHeader UNALIGNED *Header;
+ void *Data; // Pointer to data received.
+ IPHeader UNALIGNED *IPH; // Pointer to IP Header in error messages.
+ uint HeaderLength; // Size of IP header.
+ ULStatusProc ULStatus; // Pointer to upper layer status procedure.
+ IPOptInfo NewOptInfo;
+ uchar DType;
+ uint PassUp = FALSE;
+
+
+ ICMPInStats.icmps_msgs++;
+
+ DType = GetAddrType(Src);
+ if (Size < sizeof(ICMPHeader) || DType == DEST_INVALID ||
+ IS_BCAST_DEST(DType) || (IP_LOOPBACK(Dest) && DType != DEST_LOCAL) ||
+ XsumBufChain(RcvBuf) != (ushort)0xffff) {
+ ICMPInStats.icmps_errors++;
+ return IP_SUCCESS; // Bad checksum.
+ }
+
+ Header = (ICMPHeader UNALIGNED *)RcvBuf->ipr_buffer;
+
+
+ RcvBuf->ipr_buffer += sizeof(ICMPHeader);
+ RcvBuf->ipr_size -= sizeof(ICMPHeader);
+
+ // Set up the data pointer for most requests, i.e. those that take less
+ // than MIN_FIRST_SIZE data.
+
+ if (Size -= sizeof(ICMPHeader))
+ Data = (void *)(Header + 1);
+ else
+ Data = (void *)NULL;
+
+ switch (Header->ich_type) {
+
+ case ICMP_DEST_UNREACH:
+ case ICMP_TIME_EXCEED:
+ case ICMP_PARAM_PROBLEM:
+ case ICMP_SOURCE_QUENCH:
+ case ICMP_REDIRECT:
+
+ if (IsBCast)
+ return IP_SUCCESS; // ICMP doesn't respond to bcast requests.
+
+ if (Data == NULL || Size < sizeof(IPHeader)) {
+ ICMPInStats.icmps_errors++;
+ return IP_SUCCESS; // No data, error.
+ }
+
+ IPH = (IPHeader UNALIGNED *)Data;
+ HeaderLength = (IPH->iph_verlen & (uchar)~IP_VER_FLAG) << 2;
+ if (Size < (HeaderLength + MIN_ERRDATA_LENGTH)) {
+ ICMPInStats.icmps_errors++;
+ return IP_SUCCESS; // Not enough data for this
+ // ICMP message.
+ }
+
+ // Make sure that the source address of the datagram that triggered
+ // the message is one of ours.
+
+ if (GetAddrType(IPH->iph_src) != DEST_LOCAL) {
+ ICMPInStats.icmps_errors++;
+ return IP_SUCCESS; // Bad src in header.
+ }
+
+ if (Header->ich_type != ICMP_REDIRECT) {
+
+ UpdateICMPStats(&ICMPInStats, Header->ich_type);
+
+ if (ULStatus = FindULStatus(IPH->iph_protocol)) {
+ (void)(*ULStatus)(IP_NET_STATUS,
+ ICMPMapStatus(Header->ich_type, Header->ich_code),
+ IPH->iph_dest, IPH->iph_src, Src, Header->ich_param,
+ (uchar *)IPH + HeaderLength);
+ }
+ if (Header->ich_code == FRAG_NEEDED)
+ RouteFragNeeded(
+ IPH,
+ (ushort)net_short(
+ *((ushort UNALIGNED *)&Header->ich_param + 1)
+ )
+ );
+ } else {
+ ICMPInStats.icmps_redirects++;
+ Redirect(NTE, Src, IPH->iph_dest, IPH->iph_src,
+ Header->ich_param);
+ }
+
+ PassUp = TRUE;
+
+ break;
+
+
+ case ICMP_ECHO_RESP:
+ if (IsBCast)
+ return IP_SUCCESS; // ICMP doesn't respond to bcast requests.
+ ICMPInStats.icmps_echoreps++;
+ // Look up and remove the matching echo control block.
+ CompleteEcho(Header, IP_SUCCESS, RcvBuf, Size, OptInfo);
+
+ PassUp = TRUE;
+
+ break;
+
+ case ICMP_ECHO:
+ if (IsBCast)
+ return IP_SUCCESS; // ICMP doesn't respond to bcast requests.
+ ICMPInStats.icmps_echos++;
+
+ // Create our new optinfo structure.
+ IPInitOptions(&NewOptInfo);
+ NewOptInfo.ioi_tos = OptInfo->ioi_tos;
+ NewOptInfo.ioi_flags = OptInfo->ioi_flags;
+
+ // If we have options, we need to reverse them and update any
+ // record route info. We can use the option buffer supplied by the
+ // IP layer, since we're part of him.
+ if (OptInfo->ioi_options != (uchar *)NULL)
+ IPUpdateRcvdOptions(OptInfo, &NewOptInfo, Src, LocalAddr);
+
+
+ SendEcho(Src, LocalAddr, ICMP_ECHO_RESP,
+ *(ushort UNALIGNED *)&Header->ich_param,
+ *((ushort UNALIGNED *)&Header->ich_param + 1),
+ RcvBuf, Size, &NewOptInfo);
+
+ IPFreeOptions(&NewOptInfo);
+ break;
+
+ case ADDR_MASK_REQUEST:
+ if (IsBCast)
+ return IP_SUCCESS; // ICMP doesn't respond to bcast requests.
+ ICMPInStats.icmps_addrmasks++;
+
+ Dest = Src;
+
+ SendICMPMsg(LocalAddr, Dest, ADDR_MASK_REPLY, 0, Header->ich_param,
+ (uchar *)&NTE->nte_mask, sizeof(IPMask));
+ break;
+
+ case ICMP_ROUTER_ADVERTISEMENT:
+ if (Header->ich_code != 0)
+ return IP_SUCCESS; // Code must be 0 as per RFC1256
+ if (NTE->nte_rtrdiscovery) {
+ if (!ProcessRouterAdvertisement(Src, LocalAddr, NTE,
+ (ICMPRouterAdHeader *)&Header->ich_param, RcvBuf, Size))
+ return IP_SUCCESS; // An error was returned
+ }
+ PassUp = TRUE;
+ break;
+
+ case ICMP_ROUTER_SOLICITATION:
+ if (Header->ich_code != 0)
+ return IP_SUCCESS; // Code must be 0 as per RFC1256
+ PassUp = TRUE;
+ break;
+
+ default:
+ PassUp = TRUE;
+ UpdateICMPStats(&ICMPInStats, Header->ich_type);
+ break;
+ }
+
+ //
+ // Pass the packet up to the raw layer if applicable.
+ //
+ if (PassUp && (RawPI != NULL)) {
+ if (RawPI->pi_rcv != NULL) {
+ //
+ // Restore the original values.
+ //
+ RcvBuf->ipr_buffer -= sizeof(ICMPHeader);
+ RcvBuf->ipr_size += sizeof(ICMPHeader);
+ Size += sizeof(ICMPHeader);
+ Data = (void *) Header;
+
+ (*(RawPI->pi_rcv))(NTE, Dest, Src, LocalAddr, SrcAddr, IPHdr,
+ IPHdrLength, RcvBuf, Size, IsBCast, Protocol, OptInfo);
+ }
+ }
+
+ return IP_SUCCESS;
+}
+
+
+//** ICMPEcho - Send an echo to the specified address.
+//
+// Entry: ControlBlock - Pointer to an EchoControl structure. This structure
+// must remain valid until the req. completes.
+// Timeout - Time in milliseconds to wait for response.
+// Data - Pointer to data to send with echo.
+// DataSize - Size in bytes of data.
+// Callback - Routine to call when request is responded to or times out.
+// Dest - Address to be pinged.
+// OptInfo - Pointer to opt info structure to use for ping.
+//
+// Returns: IP_STATUS of attempt to ping..
+//
+IP_STATUS
+ICMPEcho(EchoControl *ControlBlock, ulong Timeout, void *Data, uint DataSize, EchoRtn Callback,
+ IPAddr Dest, IPOptInfo *OptInfo)
+{
+ IPAddr Dummy;
+ NetTableEntry *NTE;
+ CTELockHandle Handle;
+ ushort Seq;
+ IP_STATUS Status;
+ IPOptInfo NewOptInfo;
+ IPRcvBuf RcvBuf;
+ uint MTU;
+ Interface *IF;
+ uchar DType;
+ EchoControl *Current;
+
+ if (OptInfo->ioi_ttl == 0)
+ return IP_BAD_OPTION;
+
+ IPInitOptions(&NewOptInfo);
+ NewOptInfo.ioi_ttl = OptInfo->ioi_ttl;
+ NewOptInfo.ioi_flags = OptInfo->ioi_flags;
+ NewOptInfo.ioi_tos = OptInfo->ioi_tos & 0xfc;
+
+ if (OptInfo->ioi_optlength != 0) {
+ Status = IPCopyOptions(OptInfo->ioi_options, OptInfo->ioi_optlength,
+ &NewOptInfo);
+
+ if (Status != IP_SUCCESS)
+ return Status;
+ }
+
+ if (!IP_ADDR_EQUAL(NewOptInfo.ioi_addr, NULL_IP_ADDR))
+ Dest = NewOptInfo.ioi_addr;
+
+ DType = GetAddrType(Dest);
+ if (DType == DEST_INVALID) {
+ IPFreeOptions(&NewOptInfo);
+ return IP_BAD_DESTINATION;
+ }
+
+ if ((IF = LookupNextHopWithBuffer(Dest, NULL_IP_ADDR, &Dummy, &MTU, 0x1, NULL, 0)) == NULL) {
+ IPFreeOptions(&NewOptInfo);
+ return IP_DEST_HOST_UNREACHABLE; // Don't know how to get there.
+ }
+
+ // Loop through the NetTable, looking for a matching NTE.
+ CTEGetLock(&RouteTableLock, &Handle);
+ if (DHCPActivityCount != 0)
+ NTE = NULL;
+ else
+ NTE = BestNTEForIF(Dummy, IF);
+ CTEFreeLock(&RouteTableLock, Handle);
+
+#ifdef _PNP_POWER
+ // We're done with the interface, so dereference it.
+ DerefIF(IF);
+#endif
+
+ if (NTE == NULL) {
+ // Couldn't find a matching NTE. This is very bad.
+ //DEBUGCHK;
+
+ DbgPrint("ICMP: Failed to find NTE when going to %x\n",Dest);
+
+ IPFreeOptions(&NewOptInfo);
+ return IP_DEST_HOST_UNREACHABLE;
+ }
+
+ // Figure out the timeout.
+ ControlBlock->ec_to = CTESystemUpTime() + Timeout;
+ ControlBlock->ec_rtn = Callback;
+ ControlBlock->ec_active = 0; // Prevent from timing out until sent
+ CTEGetLock(&NTE->nte_lock, &Handle);
+ // Link onto ping list, and get seq. # */
+ Seq = ++NTE->nte_icmpseq;
+ ControlBlock->ec_seq = Seq;
+ ControlBlock->ec_next = NTE->nte_echolist;
+ NTE->nte_echolist = ControlBlock;
+ CTEFreeLock(&NTE->nte_lock, Handle);
+ RcvBuf.ipr_next = NULL;
+ RcvBuf.ipr_buffer = Data;
+ RcvBuf.ipr_size = DataSize;
+ Status = SendEcho(Dest, NTE->nte_addr, ICMP_ECHO, NTE->nte_context,
+ Seq, &RcvBuf, DataSize, &NewOptInfo);
+
+ IPFreeOptions(&NewOptInfo);
+
+ if (Status != IP_PENDING && Status != IP_SUCCESS) { // We had an error on the send.
+ if (DeleteEC(NTE, Seq) != (EchoControl *)NULL)
+ return Status; // We found it.
+ }
+
+ //
+ // If the request is still pending, activate the timer
+ //
+ CTEGetLock(&NTE->nte_lock, &Handle);
+
+ for (
+ Current = NTE->nte_echolist;
+ Current != (EchoControl *)NULL;
+ Current = Current->ec_next
+ ) {
+ if (Current == ControlBlock) {
+ ControlBlock->ec_active = 1; // start the timer
+ break;
+ }
+ }
+
+ CTEFreeLock(&NTE->nte_lock, Handle);
+
+ return IP_PENDING;
+
+}
+
+
+//** ICMPEchoRequest - Common dispatch routine for echo requests
+//
+// This is the routine called by the OS-specific code on behalf of a user to issue an
+// echo request.
+//
+// Entry: InputBuffer - Pointer to an ICMP_ECHO_REQUEST structure.
+// InputBufferLength - Size in bytes of the InputBuffer.
+// ControlBlock - Pointer to an EchoControl structure. This
+// structure must remain valid until the
+// request completes.
+// Callback - Routine to call when request is responded to
+// or times out.
+//
+// Returns: IP_STATUS of attempt to ping.
+//
+IP_STATUS
+ICMPEchoRequest(
+ void *InputBuffer,
+ uint InputBufferLength,
+ EchoControl *ControlBlock,
+ EchoRtn Callback
+ )
+{
+ PICMP_ECHO_REQUEST requestBuffer;
+ struct IPOptInfo optionInfo;
+ PUCHAR endOfRequestBuffer;
+ IP_STATUS status;
+
+
+#ifdef NT
+
+ PAGED_CODE();
+
+#endif //NT
+
+ requestBuffer = (PICMP_ECHO_REQUEST) InputBuffer;
+ endOfRequestBuffer = ((PUCHAR) requestBuffer) + InputBufferLength;
+
+ //
+ // Validate the request.
+ //
+ if (InputBufferLength < sizeof(ICMP_ECHO_REQUEST)) {
+ status = IP_BUF_TOO_SMALL;
+ goto common_echo_exit;
+ }
+
+ if (requestBuffer->DataSize > 0) {
+ if ( (requestBuffer->DataOffset < sizeof(ICMP_ECHO_REQUEST))
+ ||
+ ( ( ((PUCHAR)requestBuffer) + requestBuffer->DataOffset +
+ requestBuffer->DataSize
+ )
+ >
+ endOfRequestBuffer
+ )
+ ) {
+ status = IP_GENERAL_FAILURE;
+ goto common_echo_exit;
+ }
+ }
+
+ if (requestBuffer->OptionsSize > 0) {
+ if ( (requestBuffer->OptionsOffset < sizeof(ICMP_ECHO_REQUEST))
+ ||
+ ( ( ((PUCHAR)requestBuffer) + requestBuffer->OptionsOffset +
+ requestBuffer->OptionsSize
+ )
+ >
+ endOfRequestBuffer
+ )
+ ) {
+ status = IP_GENERAL_FAILURE;
+ goto common_echo_exit;
+ }
+ }
+
+ //
+ // Copy the options to a local structure.
+ //
+ if (requestBuffer->OptionsValid) {
+ optionInfo.ioi_optlength = requestBuffer->OptionsSize;
+
+ if (requestBuffer->OptionsSize > 0) {
+ optionInfo.ioi_options = ((uchar *) requestBuffer) +
+ requestBuffer->OptionsOffset;
+ }
+ else {
+ optionInfo.ioi_options = NULL;
+ }
+ optionInfo.ioi_addr = 0;
+ optionInfo.ioi_ttl = requestBuffer->Ttl;
+ optionInfo.ioi_tos = requestBuffer->Tos;
+ optionInfo.ioi_flags = requestBuffer->Flags;
+ }
+ else {
+ optionInfo.ioi_optlength = 0;
+ optionInfo.ioi_options = NULL;
+ optionInfo.ioi_addr = 0;
+ optionInfo.ioi_ttl = DEFAULT_TTL;
+ optionInfo.ioi_tos = 0;
+ optionInfo.ioi_flags = 0;
+ }
+
+ status = ICMPEcho(
+ ControlBlock,
+ requestBuffer->Timeout,
+ ((uchar *)requestBuffer) + requestBuffer->DataOffset,
+ requestBuffer->DataSize,
+ Callback,
+ (IPAddr) requestBuffer->Address,
+ &optionInfo
+ );
+
+common_echo_exit:
+
+ return(status);
+
+} // ICMPEchoRequest
+
+
+//** ICMPEchoComplete - Common completion routine for echo requests
+//
+// This is the routine is called by the OS-specific code to process an
+// ICMP echo response.
+//
+// Entry: OutputBuffer - Pointer to an ICMP_ECHO_REPLY structure.
+// OutputBufferLength - Size in bytes of the OutputBuffer.
+// Status - The status of the reply.
+// Data - The reply data (may be NULL).
+// DataSize - The amount of reply data.
+// OptionInfo - A pointer to the reply options
+//
+// Returns: The number of bytes written to the output buffer
+//
+ulong
+ICMPEchoComplete(
+ EchoControl *ControlBlock,
+ IP_STATUS Status,
+ void *Data,
+ uint DataSize,
+ struct IPOptInfo *OptionInfo
+ )
+{
+ PICMP_ECHO_REPLY replyBuffer;
+ IPRcvBuf *dataBuffer;
+ uchar optionsLength;
+ uchar *tmp;
+ ulong bytesReturned = sizeof(ICMP_ECHO_REPLY);
+
+
+ replyBuffer = (PICMP_ECHO_REPLY) ControlBlock->ec_replybuf;
+ dataBuffer = (IPRcvBuf *) Data;
+
+ if (OptionInfo != NULL) {
+ optionsLength = OptionInfo->ioi_optlength;
+ }
+ else {
+ optionsLength = 0;
+ }
+
+ //
+ // Initialize the reply buffer
+ //
+ replyBuffer->Options.OptionsSize = 0;
+ replyBuffer->Options.OptionsData = (unsigned char FAR *) (replyBuffer + 1);
+ replyBuffer->DataSize = 0;
+ replyBuffer->Data = replyBuffer->Options.OptionsData;
+
+ if ( (Status != IP_SUCCESS) && (DataSize == 0)) {
+ //
+ // Timed out or internal error.
+ //
+ replyBuffer->Reserved = 0; // indicate no replies.
+ replyBuffer->Status = Status;
+ }
+ else {
+ if (Status != IP_SUCCESS) {
+ //
+ // A message other than an echo reply was received.
+ // The IP Address of the system that reported the error is
+ // in the data buffer. There is no other data.
+ //
+ CTEAssert(dataBuffer->ipr_size == sizeof(IPAddr));
+
+ CTEMemCopy(
+ &(replyBuffer->Address),
+ dataBuffer->ipr_buffer,
+ sizeof(IPAddr)
+ );
+
+ DataSize = 0;
+ dataBuffer = NULL;
+ }
+ // else {
+ //
+ // BUGBUG - we currently depend on the fact that the destination
+ // address is still in the request buffer. The reply address
+ // should just be a parameter to this function. In NT, this
+ // just works since the input and output buffers are the same.
+ // In the VXD, the destination address must be put into the
+ // reply buffer by the OS-specific code.
+ // }
+
+ //
+ // Check that the reply buffer is large enough to hold all the data.
+ //
+ if ( ControlBlock->ec_replybuflen <
+ (sizeof(ICMP_ECHO_REPLY) + DataSize + optionsLength)
+ ) {
+ //
+ // Not enough space to hold the reply.
+ //
+ replyBuffer->Reserved = 0; // indicate no replies
+ replyBuffer->Status = IP_BUF_TOO_SMALL;
+ }
+ else {
+ replyBuffer->Reserved = 1; // indicate one reply
+ replyBuffer->Status = Status;
+ replyBuffer->RoundTripTime = CTESystemUpTime() -
+ ControlBlock->ec_starttime;
+
+ //
+ // Copy the reply options.
+ //
+ if (OptionInfo != NULL) {
+ replyBuffer->Options.Ttl = OptionInfo->ioi_ttl;
+ replyBuffer->Options.Tos = OptionInfo->ioi_tos;
+ replyBuffer->Options.Flags = OptionInfo->ioi_flags;
+ replyBuffer->Options.OptionsSize = optionsLength;
+
+ if (optionsLength > 0) {
+
+ CTEMemCopy(
+ replyBuffer->Options.OptionsData,
+ OptionInfo->ioi_options,
+ optionsLength
+ );
+ }
+ }
+
+ //
+ // Copy the reply data
+ //
+ replyBuffer->DataSize = (ushort) DataSize;
+ replyBuffer->Data = replyBuffer->Options.OptionsData +
+ replyBuffer->Options.OptionsSize;
+
+ if (DataSize > 0) {
+ uint bytesToCopy;
+
+ CTEAssert(Data != NULL);
+
+ tmp = replyBuffer->Data;
+
+ while (DataSize) {
+ CTEAssert(dataBuffer != NULL);
+
+ bytesToCopy = (DataSize > dataBuffer->ipr_size) ?
+ dataBuffer->ipr_size : DataSize;
+
+ CTEMemCopy(
+ tmp,
+ dataBuffer->ipr_buffer,
+ bytesToCopy
+ );
+
+ tmp += bytesToCopy;
+ DataSize -= bytesToCopy;
+ dataBuffer = dataBuffer->ipr_next;
+ }
+ }
+
+ bytesReturned += replyBuffer->DataSize + optionsLength;
+
+ //
+ // Convert the kernel pointers to offsets from start of reply buffer.
+ //
+ replyBuffer->Options.OptionsData = (unsigned char FAR *)
+ (((unsigned long) replyBuffer->Options.OptionsData) -
+ ((unsigned long) replyBuffer));
+
+ replyBuffer->Data = (void FAR *)
+ (((unsigned long) replyBuffer->Data) -
+ ((unsigned long) replyBuffer));
+ }
+ }
+
+ return(bytesReturned);
+}
+
+
+#ifdef VXD
+
+struct _pending_echo {
+ EchoControl ControlBlock;
+ CTEBlockStruc BlockStruc;
+};
+
+typedef struct _pending_echo PendingEcho;
+
+
+//** VXDEchoComplete - OS-specific icmp echo completion routine.
+//
+// This routine is called by the OS-indepenent code to process a completed
+// ICMP echo request. It calls common code to package the response.
+//
+// Entry: Context - A pointer to an EchoControl structure.
+// Status - The status of the request
+// Data - A pointer to the response data.
+// DataSize - The amount of response data.
+// OptionInfo - A pointer to the options contained in the reply.
+//
+// Returns: Nothing.
+//
+void
+VXDEchoComplete(
+ void *Context,
+ IP_STATUS Status,
+ void *Data,
+ uint DataSize,
+ struct IPOptInfo *OptionInfo
+ )
+{
+ PendingEcho *pendingEcho;
+ EchoControl *controlBlock;
+ ulong bytesReturned;
+
+
+ controlBlock = (EchoControl *) Context;
+
+ bytesReturned = ICMPEchoComplete(
+ controlBlock,
+ Status,
+ Data,
+ DataSize,
+ OptionInfo
+ );
+
+ //
+ // The request thread will copy the returned byte count from
+ // the control block.
+ //
+ controlBlock->ec_replybuflen = bytesReturned;
+
+ //
+ // Signal waiting request thread.
+ //
+ pendingEcho = STRUCT_OF(PendingEcho, controlBlock, ControlBlock);
+ CTESignal(&(pendingEcho->BlockStruc), Status);
+
+ return;
+}
+
+
+//** VXDEchoRequest - Send an echo to the specified address.
+//
+// This routine dispatches an echo request on the VXD platform to the
+// common code
+//
+// Entry: InBuf - Pointer to input buffer.
+// InBufLen - Pointer to input buffer length.
+// OutBuf - Pointer to output buffer.
+// OutBufLen - Pointer to output buffer length.
+//
+// Returns: DWORD Win32 completion status.
+//
+ULONG
+VXDEchoRequest(
+ void * InBuf,
+ ulong * InBufLen,
+ void * OutBuf,
+ ulong * OutBufLen
+ )
+{
+ IP_STATUS ipStatus;
+ PendingEcho pendingEcho;
+
+ pendingEcho.ControlBlock.ec_starttime = CTESystemUpTime();
+ pendingEcho.ControlBlock.ec_replybuf = OutBuf;
+ pendingEcho.ControlBlock.ec_replybuflen = *OutBufLen;
+ CTEInitBlockStruc(&pendingEcho.BlockStruc);
+
+ ipStatus = ICMPEchoRequest(
+ InBuf,
+ *InBufLen,
+ &(pendingEcho.ControlBlock),
+ VXDEchoComplete
+ );
+
+ if (ipStatus == IP_PENDING) {
+ ipStatus = CTEBlock(&(pendingEcho.BlockStruc));
+
+ if (ipStatus == IP_SUCCESS) {
+ PICMP_ECHO_REQUEST requestBuffer;
+ PICMP_ECHO_REPLY replyBuffer;
+
+ //
+ // BUGBUG:
+ //
+ // It is necessary to copy the original destination address into
+ // the reply buffer because the src address is not provided to
+ // the completion routine for an echo response. This is the only
+ // reason why the signalling status is the reply status instead
+ // of just success.
+ //
+ requestBuffer = (PICMP_ECHO_REQUEST) InBuf;
+ replyBuffer = (PICMP_ECHO_REPLY) OutBuf;
+
+ replyBuffer->Address = requestBuffer->Address;
+ }
+
+ //
+ // The ioctl is considered successful as long as we can submit
+ // the request. The status of the request is contained in the
+ // reply buffer. The completion routine stuffed the return
+ // buffer length back into the control block.
+ //
+ ipStatus = IP_SUCCESS;
+ *OutBufLen = pendingEcho.ControlBlock.ec_replybuflen;
+ }
+ else {
+ //
+ // An internal error of some kind occurred. Since the VXD can
+ // return the IP_STATUS directly, do so.
+ //
+ CTEAssert(ipStatus != IP_SUCCESS);
+
+ *OutBufLen = 0;
+ }
+
+ return(ipStatus);
+}
+
+#endif // VXD
+
+
+#pragma BEGIN_INIT
+//** ICMPInit - Initialize ICMP.
+//
+// This routine initializes ICMP. All we do is allocate and link up some header buffers,
+/// and register our protocol with IP.
+//
+// Entry: NumBuffers - Number of ICMP buffers to allocate.
+//
+// Returns: Nothing
+//
+void
+ICMPInit(uint NumBuffers)
+{
+ ICMPHeader **IHP; // Pointer to current ICMP header.
+
+
+ CTEInitLock(&ICMPHeaderLock);
+ MaxICMPHeaders = NumBuffers;
+ CurrentICMPHeaders = 0;
+ ICMPHeaderList= (ICMPHeader *)NULL;
+
+ while (NumBuffers--) {
+ IHP = (ICMPHeader **) CTEAllocMem(
+ sizeof(ICMPHeader) + sizeof(IPHeader) +
+ sizeof(IPHeader) + MAX_OPT_SIZE + 8
+ );
+
+ if (IHP == (ICMPHeader **)NULL) {
+ break;
+ }
+
+ *IHP = ICMPHeaderList;
+ ICMPHeaderList = (ICMPHeader *)IHP;
+ CurrentICMPHeaders++;
+ }
+
+ IPRegisterProtocol(PROT_ICMP, ICMPRcv, ICMPSendComplete, ICMPStatus, NULL);
+
+}
+
+#pragma END_INIT
diff --git a/private/ntos/tdi/tcpip/ip/icmp.h b/private/ntos/tdi/tcpip/ip/icmp.h
new file mode 100644
index 000000000..f45dac536
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/icmp.h
@@ -0,0 +1,70 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1992 **/
+/********************************************************************/
+/* :ts=4 */
+
+//*** icmp.h - IP ICMP header.
+//
+// This module contains private ICMP definitions.
+//
+
+#define PROT_ICMP 1
+
+#define ICMP_ECHO_RESP 0
+#define ICMP_ECHO 8
+#define ICMP_TIMESTAMP 13
+#define ICMP_TIMESTAMP_RESP 14
+
+#define MIN_ERRDATA_LENGTH 8 // Minimum amount of data we need.
+
+// Structure of an ICMP header.
+
+struct ICMPHeader {
+ uchar ich_type; // Type of ICMP packet.
+ uchar ich_code; // Subcode of type.
+ ushort ich_xsum; // Checksum of packet.
+ ulong ich_param; // Type-specific parameter field.
+}; /* ICMPHeader */
+
+struct ICMPRouterAdHeader {
+ uchar irah_numaddrs; // Number of addresses
+ uchar irah_addrentrysize; // Address Entry Size
+ ushort irah_lifetime; // Lifetime
+}; /* ICMPRouterAdHeader */
+
+struct ICMPRouterAdAddrEntry {
+ IPAddr irae_addr; // Router Address
+ long irae_preference; // Preference Level
+}; /* ICMPRouterAdAddrEntry */
+
+/*NOINC*/
+typedef struct ICMPHeader ICMPHeader;
+typedef struct ICMPRouterAdHeader ICMPRouterAdHeader;
+typedef struct ICMPRouterAdAddrEntry ICMPRouterAdAddrEntry;
+
+typedef void (*EchoRtn)(void *, IP_STATUS, void *, uint, IPOptInfo *);
+/*INC*/
+
+struct EchoControl {
+ struct EchoControl *ec_next; // Next control structure in list.
+ ulong ec_to; // Timeout
+ void *ec_rtn; // Pointer to routine to call when completing request.
+ ushort ec_seq; // Seq. # of this ping request.
+ uchar ec_active; // Set when packet has been sent
+ uchar ec_pad; // Pad.
+ ulong ec_starttime; // time request was issued
+ void *ec_replybuf; // buffer to store replies
+ ulong ec_replybuflen; // size of reply buffer
+}; /* EchoControl */
+
+/*NOINC*/
+typedef struct EchoControl EchoControl;
+/*INC*/
+
+extern ICMPHeader *GetICMPBuffer(uint Size, PNDIS_BUFFER *Buffer);
+extern void FreeICMPBuffer(PNDIS_BUFFER Buffer);
+extern void ICMPSendComplete(void *DataPtr, PNDIS_BUFFER BufferChain);
+
+
+
diff --git a/private/ntos/tdi/tcpip/ip/igmp.c b/private/ntos/tdi/tcpip/ip/igmp.c
new file mode 100644
index 000000000..340f0380f
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/igmp.c
@@ -0,0 +1,799 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1992 **/
+/********************************************************************/
+/* :ts=4 */
+
+//*** igmp.c - IP multicast routines.
+//
+// This file contains all the routines related to the IGMP protocol.
+
+#include "oscfg.h"
+#include "cxport.h"
+#include "ndis.h"
+#include "ip.h"
+#include "ipdef.h"
+#include "igmp.h"
+#include "icmp.h"
+#include "ipxmit.h"
+#include "llipif.h"
+#include "iproute.h"
+
+
+#define IGMP_QUERY 0x11 //Membership query
+#define IGMP_REPORT_V1 0x12 //Version 1 membership report
+#define IGMP_REPORT_V2 0x16 //Version 2 membership report
+#define IGMP_LEAVE 0x17 //Leave Group
+
+
+#define IGMPV1 2 //IGMP version 1
+#define IGMPV2 3 //IGMP version 2
+
+//
+// undefine for 4.0 sp2
+//
+#undef IGMPV2
+
+#define ALL_HOST_MCAST 0x010000E0
+
+#define MAX_DELAY_TICKS 20 //used when sending a report after a
+ //mcast group has been added. The
+ //report is sent at a interval of
+ //500 msecs to 9.5 secs
+
+//
+// The following values are used to initialize counters that keep time in
+// 1/2 a sec.
+//
+#define MAX_DELAY_IGMPV1_QUERY_RESP 20 //10 secs
+
+//
+// The amount of time we stay in the "IGMPV1 Router Present" state in the
+// absence of an IGMPV1 query
+//
+#define VERSION1_ROUTER_TIMEOUT 800 //400 secs
+
+int RandomValue;
+int Seed;
+
+// Structure of an IGMP header.
+typedef struct IGMPHeader {
+ uchar igh_vertype; // Type of igmp message
+ uchar igh_rsvd; // max. resp. time for igmpv2 messages; will be 0
+ // for igmpv1 messages
+ ushort igh_xsum;
+ IPAddr igh_addr;
+} IGMPHeader;
+
+
+typedef struct IGMPBlockStruct {
+ struct IGMPBlockStruct *ibs_next;
+ CTEBlockStruc ibs_block;
+} IGMPBlockStruct;
+
+void *IGMPProtInfo;
+
+IGMPBlockStruct *IGMPBlockList;
+uchar IGMPBlockFlag;
+
+DEFINE_LOCK_STRUCTURE(IGMPLock)
+
+extern ProtInfo *RawPI; // Raw IP protinfo
+
+extern IP_STATUS IPCopyOptions(uchar *, uint, IPOptInfo *);
+extern void IPInitOptions(IPOptInfo *);
+extern void *IPRegisterProtocol(uchar Protocol, void *RcvHandler,
+ void *XmitHandler, void *StatusHandler, void *RcvCmpltHandler);
+
+
+#ifdef NT
+
+//
+// All of the init code can be discarded
+//
+#ifdef ALLOC_PRAGMA
+
+uint IGMPInit(void);
+
+#pragma alloc_text(INIT, IGMPInit)
+
+#endif // ALLOC_PRAGMA
+
+#endif // NT
+
+//* IGMPRandomTicks - Generate a random value of timer ticks.
+//
+// A random number routine to generate a random number of timer ticks,
+// between 1 and time (in units of half secs) passed. The random number
+// algorithm is adapted from the book 'System Simulation' by Geoffrey Gordon.
+//
+// Input: Nothing.
+//
+// Returns: A random value between 1 and TimeDelayInHalfSec.
+//
+uint
+IGMPRandomTicks(uint TimeDelayInHalfSec)
+{
+
+ RandomValue = RandomValue * 1220703125;
+
+ if (RandomValue < 0) {
+ RandomValue += 2147483647; // inefficient, but avoids warnings.
+ RandomValue++;
+ }
+
+ // Not sure if RandomValue can get to 0, but if it does the algorithm
+ // degenerates, so fix this if it happens.
+ if (RandomValue == 0)
+ RandomValue = ((Seed + (int)CTESystemUpTime()) % 100000000) | 1;
+
+ return (uint)(((uint)RandomValue % TimeDelayInHalfSec) + 1);
+}
+
+
+//* FindIGMPAddr - Find an mcast entry on an NTE.
+//
+// Called to search an NTE for an IGMP entry for a given class D address.
+// We walk down the chain on the NTE looking for it. If we find it,
+// we return a pointer to it and the one immediately preceding it. If we
+// don't find it we return NULL. We assume the caller has taken the lock
+// on the NTE before calling us.
+//
+// Input: NTE - NTE on which to search.
+// Addr - Class D address to find.
+// PrevPtr - Where to return pointer to preceding entry.
+//
+// Returns: Pointer to matching IGMPAddr structure if found, or NULL if not
+// found.
+//
+IGMPAddr *
+FindIGMPAddr(NetTableEntry *NTE, IPAddr Addr, IGMPAddr **PrevPtr)
+{
+ IGMPAddr *Current, *Temp;
+
+ Temp = STRUCT_OF(IGMPAddr, &NTE->nte_igmplist, iga_next);
+ Current = NTE->nte_igmplist;
+
+ while (Current != NULL) {
+ if (IP_ADDR_EQUAL(Current->iga_addr, Addr)) {
+ // Found a match, so return it.
+ *PrevPtr = Temp;
+ break;
+ }
+ Temp = Current;
+ Current = Current->iga_next;
+ }
+
+ return Current;
+
+}
+
+//** IGMPRcv - Receive an IGMP datagram.
+//
+// Called by IP when we receive an IGMP datagram. We validate it to make sure
+// it's reasonable. Then if it it's a query for a group to which we belong
+// we'll start a response timer. If it's a report to a group to which we belong
+// we'll stop any running timer.
+//
+// The IGMP header is only 8 bytes long, and so should always fit in exactly
+// one IP rcv buffer. We check this to make sure, and if it takes multiple
+// buffers we discard it.
+//
+// Entry: NTE - Pointer to NTE on which IGMP message was received.
+// Dest - IPAddr of destination (should be a Class D address).
+// Src - IPAddr of source
+// LocalAddr - Local address of network which caused this to be
+// received.
+// SrcAddr - Address of local interface which received the
+// packet
+// IPHdr - Pointer to the IP Header.
+// IPHdrLength - Bytes in IPHeader.
+// RcvBuf - Pointer to IP receive buffer chain.
+// Size - Size in bytes of IGMP message.
+// IsBCast - Boolean indicator of whether or not this came in
+// as a bcast (should always be true).
+// Protocol - Protocol this came in on.
+// OptInfo - Pointer to info structure for received options.
+//
+// Returns: Status of reception
+IP_STATUS
+IGMPRcv(NetTableEntry *NTE, IPAddr Dest, IPAddr Src, IPAddr LocalAddr,
+ IPAddr SrcAddr, IPHeader UNALIGNED *IPHdr, uint IPHdrLength,
+ IPRcvBuf *RcvBuf, uint Size, uchar IsBCast, uchar Protocol,
+ IPOptInfo *OptInfo)
+{
+ IGMPHeader UNALIGNED *IGH;
+ CTELockHandle Handle;
+ IGMPAddr *AddrPtr, *PrevPtr;
+ uchar DType;
+ uint ReportingDelayInHalfSec;
+
+
+ CTEAssert(CLASSD_ADDR(Dest));
+ CTEAssert(IsBCast);
+
+ // Make sure we're running at least level 2 of IGMP support.
+ if (IGMPLevel != 2)
+ return IP_SUCCESS;
+
+ // Discard packets with invalid or broadcast source addresses.
+ DType = GetAddrType(Src);
+ if (DType == DEST_INVALID || IS_BCAST_DEST(DType))
+ return IP_SUCCESS;
+
+ // Check the size to make sure it's valid.
+ if (Size != sizeof(IGMPHeader) || RcvBuf->ipr_size != sizeof(IGMPHeader))
+ return IP_SUCCESS;
+
+ // Now get the pointer to the header, and validate the xsum.
+ IGH = (IGMPHeader UNALIGNED *)RcvBuf->ipr_buffer;
+
+ if (xsum(IGH, sizeof(IGMPHeader)) != 0xffff) {
+ // Bad checksum, so fail.
+ return IP_SUCCESS;
+ }
+
+ // If we sent it, don't process this message.
+ if (IP_ADDR_EQUAL(Src, LocalAddr))
+ return IP_SUCCESS;
+
+ // OK, we may need to process this. See if we are a member of the
+ // destination group. If we aren't, there's no need to proceed further.
+ CTEGetLock(&NTE->nte_lock, &Handle);
+
+ if (NTE->nte_flags & NTE_VALID) {
+ //
+ // The NTE is valid. Demux on type.
+ //
+ switch (IGH->igh_vertype) {
+
+ case IGMP_QUERY:
+
+ //
+ // If it is an IGMPV1 query, set the timer value for staying in
+ // igmpv1 mode
+ //
+#ifdef IGMPV2
+ if (IGH->igh_rsvd == 0) {
+ //
+ // Since for any interface we always get notified with
+ // same NTE, locking the NTE is fine. We don't have to
+ // lock the interface structure
+ //
+ if (NTE->nte_if->IgmpVersion == IGMPV2) {
+ NTE->nte_if->IgmpVersion = IGMPV1;
+ }
+ NTE->nte_if->IgmpVer1Timeout = VERSION1_ROUTER_TIMEOUT;
+ ReportingDelayInHalfSec = MAX_DELAY_IGMPV1_QUERY_RESP;
+ }
+ else {
+ ReportingDelayInHalfSec = IGH->igh_rsvd * 5; //field's unit are in 100ms
+ }
+#else
+ ReportingDelayInHalfSec = MAX_DELAY_IGMPV1_QUERY_RESP;
+#endif
+
+ //
+ // This is a query. Walk our list and set a random report timer for
+ // all those class D addresses that don't already have one running
+ // (except for the all host's address).
+ //
+ for (AddrPtr = NTE->nte_igmplist; AddrPtr != NULL; AddrPtr = AddrPtr->iga_next) {
+ if (!IP_ADDR_EQUAL(AddrPtr->iga_addr, ALL_HOST_MCAST)) {
+ if (AddrPtr->iga_timer == 0) {
+ AddrPtr->iga_timer = IGMPRandomTicks(ReportingDelayInHalfSec);
+ }
+ }
+ }
+
+ break;
+
+ case IGMP_REPORT_V1:
+ case IGMP_REPORT_V2:
+ //
+ // This is a report. Check it's validity and see if we have a
+ // report timer running for that address. If we do, stop it.
+ // Make sure the destination address matches the address in the
+ // IGMP header.
+ //
+ if (IP_ADDR_EQUAL(Dest, IGH->igh_addr)) {
+ // The addresses match. See if we have a membership in this
+ // group.
+ AddrPtr = FindIGMPAddr(NTE, IGH->igh_addr, &PrevPtr);
+ if (AddrPtr != NULL) {
+ // We found a matching class D address. Stop the timer.
+ AddrPtr->iga_timer = 0;
+ }
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ CTEFreeLock(&NTE->nte_lock, Handle);
+
+ //
+ // Pass the packet up to the raw layer if applicable.
+ //
+ if (RawPI != NULL) {
+ if (RawPI->pi_rcv != NULL) {
+ (*(RawPI->pi_rcv))(NTE, Dest, Src, LocalAddr, SrcAddr, IPHdr,
+ IPHdrLength, RcvBuf, Size, IsBCast, Protocol, OptInfo);
+ }
+ }
+
+ return IP_SUCCESS;
+ }
+
+ CTEFreeLock(&NTE->nte_lock, Handle);
+
+ return IP_SUCCESS;
+}
+
+//* SendIGMPReport - Send an IGMP report.
+//
+// Called when we want to send an IGMP report for some reason. For this
+// purpose we steal ICMP buffers. What we'll do is get one, fill it in,
+// and send it.
+//
+// Input: Dest - Destination to send to.
+// Src - Source to send from.
+//
+// Returns: Nothing.
+//
+void
+SendIGMPReport(uint ChangeType, uint IgmpVersion, IPAddr Dest, IPAddr Src)
+{
+ IGMPHeader *IGH;
+ PNDIS_BUFFER Buffer;
+ IPOptInfo OptInfo; // Options for this transmit.
+ IP_STATUS Status;
+ int ReportType;
+
+ CTEAssert(CLASSD_ADDR(Dest));
+ CTEAssert(!IP_ADDR_EQUAL(Src, NULL_IP_ADDR));
+
+ // Make sure we never send a report for the all-hosts mcast address.
+ if (IP_ADDR_EQUAL(Dest, ALL_HOST_MCAST)) {
+ DEBUGCHK;
+ return;
+ }
+ //
+ // If the report to be sent is a "Leave Group" report but we have
+ // detected an igmp v1 router on this net, do not send the report
+ //
+#ifdef IGMPV2
+ if (IgmpVersion == IGMPV1) {
+ if (ChangeType == IGMP_DELETE) {
+ return;
+ } else {
+#endif
+ ReportType = IGMP_REPORT_V1;
+#ifdef IGMPV2
+ }
+ } else {
+ if (ChangeType == IGMP_DELETE) {
+ ReportType = IGMP_LEAVE;
+ } else {
+ ReportType = IGMP_REPORT_V2;
+ }
+ }
+#endif
+
+ IGH = (IGMPHeader *)GetICMPBuffer(sizeof(IGMPHeader), &Buffer);
+ if (IGH != NULL) {
+ // We got the buffer. Fill it in and send it.
+ IGH->igh_vertype = ReportType;
+ IGH->igh_rsvd = 0;
+ IGH->igh_xsum = 0;
+ IGH->igh_addr = Dest;
+ IGH->igh_xsum = ~xsum(IGH, sizeof(IGMPHeader));
+
+ IPInitOptions(&OptInfo);
+ OptInfo.ioi_ttl = 1;
+
+ Status = IPTransmit(IGMPProtInfo, NULL, Buffer, sizeof(IGMPHeader),
+ Dest, Src, &OptInfo, NULL, PROT_IGMP);
+
+ if (Status != IP_PENDING)
+ ICMPSendComplete(NULL, Buffer);
+ }
+
+}
+
+//* IGMPAddrChange - Change the IGMP address list on an NTE.
+//
+// Called to add or delete an IGMP address. We're given the relevant NTE,
+// the address, and the action to be performed. We validate the NTE, the
+// address, and the IGMP level, and then attempt to perform the action.
+//
+// There are a bunch of strange race conditions that can occur during adding/
+// deleting addresses, related to trying to add the same address twice and
+// having it fail, or adding and deleting the same address simultaneously. Most
+// of these happen because we have to free the lock to call the interface,
+// and the call to the interface can fail. To prevent this we serialize all
+// access to this routine. Only one thread of execution can go through here
+// at a time, all others are blocked.
+//
+// Input: NTE - NTE with list to be altered.
+// Addr - Address affected.
+// ChangeType - Type of change - IGMP_ADD, IGMP_DELETE,
+// IGMP_DELETE_ALL.
+//
+// Returns: IP_STATUS of attempt to perform action.
+//
+IP_STATUS
+IGMPAddrChange(NetTableEntry *NTE, IPAddr Addr, uint ChangeType)
+{
+ CTELockHandle Handle;
+ IGMPAddr *AddrPtr, *PrevPtr;
+ IP_STATUS Status;
+ Interface *IF;
+ uint AddrAdded;
+ IGMPBlockStruct Block;
+ IGMPBlockStruct *BlockPtr;
+ uint IgmpVersion;
+
+ // First make sure we're at level 2 of IGMP support.
+
+ if (IGMPLevel != 2)
+ return IP_BAD_REQ;
+
+ CTEInitBlockStruc(&Block.ibs_block);
+
+ // Make sure we're the only ones in this routine. If someone else is
+ // already here, block.
+
+ CTEGetLock(&IGMPLock, &Handle);
+ if (IGMPBlockFlag) {
+
+ // Someone else is already here. Walk down the block list, and
+ // put ourselves on the end. Then free the lock and block on our
+ // IGMPBlock structure.
+ BlockPtr = STRUCT_OF(IGMPBlockStruct, &IGMPBlockList, ibs_next);
+ while (BlockPtr->ibs_next != NULL)
+ BlockPtr = BlockPtr->ibs_next;
+
+ Block.ibs_next = NULL;
+ BlockPtr->ibs_next = &Block;
+ CTEFreeLock(&IGMPLock, Handle);
+ CTEBlock(&Block.ibs_block);
+ } else {
+ // Noone else here, set the flag so noone else gets in and free the
+ // lock.
+ IGMPBlockFlag = 1;
+ CTEFreeLock(&IGMPLock, Handle);
+ }
+
+ // Now we're in the routine, and we won't be reentered here by another
+ // thread of execution. Make sure everything's valid, and figure out
+ // what to do.
+
+ Status = IP_SUCCESS;
+
+ // Now get the lock on the NTE and make sure it's valid.
+ CTEGetLock(&NTE->nte_lock, &Handle);
+ if ((NTE->nte_flags & NTE_VALID) || ChangeType == IGMP_DELETE_ALL) {
+ // The NTE is valid. Try to find an existing IGMPAddr structure
+ // that matches the input address.
+ AddrPtr = FindIGMPAddr(NTE, Addr, &PrevPtr);
+ IF = NTE->nte_if;
+
+#ifdef IGMPV2
+ IgmpVersion = IF->IgmpVersion;
+#else
+ IgmpVersion = IGMPV1;
+#endif
+ // Now figure out the action to be performed.
+ switch (ChangeType) {
+
+ case IGMP_ADD:
+
+ // We're to add this. If AddrPtr is NULL, we'll need to
+ // allocate memory and link the new IGMP address in. Otherwise
+ // we can just increment the reference count on the existing
+ // address structure.
+ if (AddrPtr == NULL) {
+ // AddrPtr is NULL, i.e. the address doesn't currently
+ // exist. Allocate memory for it, then try to add the
+ // address locally.
+
+ CTEFreeLock(&NTE->nte_lock, Handle);
+
+ // If this is not a class D address, fail the request.
+ if (!CLASSD_ADDR(Addr)) {
+ Status = IP_BAD_REQ;
+ break;
+ }
+
+ AddrPtr = CTEAllocMem(sizeof(IGMPAddr));
+ if (AddrPtr != NULL) {
+
+ // Got memory. Try to add the address locally.
+ AddrAdded = (*IF->if_addaddr)(IF->if_lcontext,
+ LLIP_ADDR_MCAST, Addr, 0, NULL);
+
+ // See if we added it succesfully. If we did, fill in
+ // the stucture and link it in.
+
+ if (AddrAdded) {
+
+ AddrPtr->iga_addr = Addr;
+ AddrPtr->iga_refcnt = 1;
+ AddrPtr->iga_timer = 0;
+
+ CTEGetLock(&NTE->nte_lock, &Handle);
+ AddrPtr->iga_next = NTE->nte_igmplist;
+ NTE->nte_igmplist = AddrPtr;
+ CTEFreeLock(&NTE->nte_lock, Handle);
+
+ if (!IP_ADDR_EQUAL(Addr, ALL_HOST_MCAST)) {
+ // This isn't the all host address, so send a
+ // report for it.
+ AddrPtr->iga_timer = IGMPRandomTicks(MAX_DELAY_TICKS);
+ SendIGMPReport(ChangeType, IgmpVersion, Addr,
+ NTE->nte_addr);
+ }
+ } else {
+ // Couldn't add the local address. Free the memory
+ // and fail the request.
+ CTEFreeMem(AddrPtr);
+ Status = IP_NO_RESOURCES;
+ }
+
+ } else {
+ Status = IP_NO_RESOURCES;
+ }
+ } else {
+ // Already have this one. Bump his count.
+ (AddrPtr->iga_refcnt)++;
+ CTEFreeLock(&NTE->nte_lock, Handle);
+ }
+ break;
+ case IGMP_DELETE:
+
+ // This is a delete request. If we didn't find the requested
+ // address, fail the request. Otherwise dec his refcnt, and if
+ // it goes to 0 delete the address locally.
+ if (AddrPtr != NULL) {
+ // Have one. We won't let the all-hosts mcast address go
+ // away, but for other's we'll check to see if it's time
+ // to delete them.
+ if (!IP_ADDR_EQUAL(Addr, ALL_HOST_MCAST) &&
+ --(AddrPtr->iga_refcnt) == 0) {
+ // This one is to be deleted. Pull him from the
+ // list, and call the lower interface to delete him.
+ PrevPtr->iga_next = AddrPtr->iga_next;
+ CTEFreeLock(&NTE->nte_lock, Handle);
+
+ CTEFreeMem(AddrPtr);
+ (*IF->if_deladdr)(IF->if_lcontext, LLIP_ADDR_MCAST,
+ Addr, 0);
+ //
+ // Send a report to indicate that we are leaving the
+ // group
+ //
+
+#ifdef IGMPV2
+ SendIGMPReport(ChangeType, IgmpVersion, Addr,
+ NTE->nte_addr);
+#endif
+ } else
+ CTEFreeLock(&NTE->nte_lock, Handle);
+ } else {
+ CTEFreeLock(&NTE->nte_lock, Handle);
+ Status = IP_BAD_REQ;
+ }
+ break;
+ case IGMP_DELETE_ALL:
+ // We've been called to delete all of this addresses,
+ // regardless of their reference count. This should only
+ // happen when the NTE is going away.
+ AddrPtr = NTE->nte_igmplist;
+ NTE->nte_igmplist = NULL;
+ CTEFreeLock(&NTE->nte_lock, Handle);
+
+ // Walk down the list, deleteing each one.
+ while (AddrPtr != NULL) {
+ (*IF->if_deladdr)(IF->if_lcontext, LLIP_ADDR_MCAST,
+ AddrPtr->iga_addr, 0);
+#ifdef IGMPV2
+ if (!IP_ADDR_EQUAL(AddrPtr->iga_addr, ALL_HOST_MCAST)) {
+ SendIGMPReport(IGMP_DELETE, IgmpVersion, AddrPtr->iga_addr, NTE->nte_addr);
+ }
+#endif
+ PrevPtr = AddrPtr;
+ AddrPtr = AddrPtr->iga_next;
+ CTEFreeMem(PrevPtr);
+ }
+
+ // All done.
+ break;
+ default:
+ DEBUGCHK;
+ break;
+ }
+ } else {
+ // NTE isn't valid.
+ CTEFreeLock(&NTE->nte_lock, Handle);
+ Status = IP_BAD_REQ;
+ }
+
+
+ // We finished the request, and Status contains the completion status.
+ // If there are any pending blocks for this routine, signal the next
+ // one now. Otherwise clear the block flag.
+ CTEGetLock(&IGMPLock, &Handle);
+ if ((BlockPtr = IGMPBlockList) != NULL) {
+ // Someone is blocking. Pull him from the list and signal him.
+ IGMPBlockList = BlockPtr->ibs_next;
+ CTEFreeLock(&IGMPLock, Handle);
+
+ CTESignal(&BlockPtr->ibs_block, IP_SUCCESS);
+ } else {
+ // No one blocking, just clear the flag.
+ IGMPBlockFlag = 0;
+ CTEFreeLock(&IGMPLock, Handle);
+ }
+
+ return Status;
+
+}
+
+//* IGMPTimer - Handle an IGMP timer event.
+//
+// This function is called every 500 ms. by IP. If we're at level 2 of
+// IGMP functionality we run down the NTE looking for running timers. If
+// we find one, we see if it has expired and if so we send an
+// IGMP report.
+//
+// Input: NTE - Pointer to NTE to check.
+//
+// Returns: Nothing.
+//
+void
+IGMPTimer(NetTableEntry *NTE)
+{
+ CTELockHandle Handle;
+ IGMPAddr *AddrPtr, *PrevPtr;
+ uint IgmpVersion;
+
+ if (IGMPLevel == 2) {
+ // We are doing IGMP. Run down the addresses active on this NTE.
+ CTEGetLock(&NTE->nte_lock, &Handle);
+
+ //
+ // if we haven't heard any query or report from an igmpv1 router or
+ // host during timeout period, revert to igmpv2. No need to check
+ // whether NTE is valid or not
+ //
+#ifdef IGMPV2
+ if ((NTE->nte_if->IgmpVer1Timeout != 0) && (--(NTE->nte_if->IgmpVer1Timeout) == 0)) {
+ NTE->nte_if->IgmpVersion = IGMPV2;
+ }
+#endif
+ PrevPtr = STRUCT_OF(IGMPAddr, &NTE->nte_igmplist, iga_next);
+ AddrPtr = PrevPtr->iga_next;
+ while (AddrPtr != NULL) {
+ // We have one. See if it's running.
+ if (AddrPtr->iga_timer != 0) {
+ // It's running. See if it's expired.
+ if (--(AddrPtr->iga_timer) == 0 && NTE->nte_flags & NTE_VALID) {
+ // It's expired. Increment the ref count so it
+ // doesn't go away while we're here, and send a report.
+ AddrPtr->iga_refcnt++;
+#ifdef IGMPV2
+ IgmpVersion = NTE->nte_if->IgmpVersion;
+#else
+ IgmpVersion = IGMPV1;
+#endif
+
+ CTEFreeLock(&NTE->nte_lock, Handle);
+
+ SendIGMPReport(IGMP_ADD, IgmpVersion, AddrPtr->iga_addr,
+ NTE->nte_addr);
+ // Now get the lock, and decrement the refcnt. If it goes
+ // to 0, it's been deleted so we need to free it.
+ CTEGetLock(&NTE->nte_lock, &Handle);
+ if (--(AddrPtr->iga_refcnt) == 0) {
+ // It's been deleted.
+ PrevPtr->iga_next = AddrPtr->iga_next;
+ CTEFreeMem(AddrPtr);
+ AddrPtr = PrevPtr->iga_next;
+ continue;
+ }
+ }
+ }
+ // Either the timer isn't running or hasn't fired. Try the next
+ // one.
+ PrevPtr = AddrPtr;
+ AddrPtr = AddrPtr->iga_next;
+ }
+
+ CTEFreeLock(&NTE->nte_lock, Handle);
+ }
+
+}
+
+//* InitIGMPForNTE - Called to do per-NTE initialization.
+//
+// Called when an NTE becomes valid. If we're at level 2, we put the all-host
+// mcast on the list and add the address to the interface.
+//
+// Input: NTE - NTE on which to act.
+//
+// Returns: Nothing.
+//
+void
+InitIGMPForNTE(NetTableEntry *NTE)
+{
+ if (IGMPLevel == 2) {
+ IGMPAddrChange(NTE, ALL_HOST_MCAST, IGMP_ADD);
+ if (NTE->nte_rtrdiscovery && (NTE->nte_rtrdiscaddr == ALL_ROUTER_MCAST)) {
+ IGMPAddrChange(NTE, ALL_ROUTER_MCAST, IGMP_ADD);
+ }
+ }
+ if (Seed == 0) {
+ // No random seed yet.
+ Seed = (int)NTE->nte_addr;
+
+ // Make sure the inital value is odd, and less than 9 decimal digits.
+ RandomValue = ((Seed + (int)CTESystemUpTime()) % 100000000) | 1;
+ }
+}
+
+//* StopIGMPForNTE - Called to do per-NTE shutdown.
+//
+// Called when we're shutting down and NTE, and want to stop IGMP on hi,
+//
+// Input: NTE - NTE on which to act.
+//
+// Returns: Nothing.
+//
+void
+StopIGMPForNTE(NetTableEntry *NTE)
+{
+ if (IGMPLevel == 2) {
+ IGMPAddrChange(NTE, NULL_IP_ADDR, IGMP_DELETE_ALL);
+ }
+}
+
+#pragma BEGIN_INIT
+
+//** IGMPInit - Initialize IGMP.
+//
+// This bit of code initializes IGMP generally. There is also some amount
+// of work done on a per-NTE basis that we do when each one is initialized.
+//
+// Input: Nothing.
+///
+// Returns: TRUE if we init, FALSE if we don't.
+//
+uint
+IGMPInit(void)
+{
+
+ if (IGMPLevel != 2)
+ return TRUE;
+
+ CTEInitLock(&IGMPLock);
+ IGMPBlockList = NULL;
+ IGMPBlockFlag = 0;
+ Seed = 0;
+
+ // We fake things a little bit. We register our receive handler, but
+ // since we steal buffers from ICMP we register the ICMP send complete
+ // handler.
+ IGMPProtInfo = IPRegisterProtocol(PROT_IGMP, IGMPRcv, ICMPSendComplete,
+ NULL, NULL);
+
+ if (IGMPProtInfo != NULL)
+ return TRUE;
+ else
+ return FALSE;
+
+}
+
+#pragma END_INIT
diff --git a/private/ntos/tdi/tcpip/ip/igmp.h b/private/ntos/tdi/tcpip/ip/igmp.h
new file mode 100644
index 000000000..ea7aefce5
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/igmp.h
@@ -0,0 +1,42 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1992 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** IGMP.H - IP multicast definitions.
+//
+// This file contains definitions related to IP multicast.
+
+#define PROT_IGMP 2
+
+extern uint IGMPLevel;
+
+// Structure used for local mcast address tracking.
+typedef struct IGMPAddr {
+ struct IGMPAddr *iga_next;
+ IPAddr iga_addr;
+ uint iga_refcnt;
+ uint iga_timer;
+} IGMPAddr;
+
+#define IGMP_ADD 0
+#define IGMP_DELETE 1
+#define IGMP_DELETE_ALL 2
+
+#define IGMPV1 2 //IGMP version 1
+#define IGMPV2 3 //IGMP version 2
+
+//
+// disable for 4.0 sp2
+//
+#undef IGMPV2
+
+
+extern void InitIGMPForNTE(NetTableEntry *NTE);
+extern void StopIGMPForNTE(NetTableEntry *NTE);
+extern IP_STATUS IGMPAddrChange(NetTableEntry *NTE, IPAddr Addr,
+ uint ChangeType);
+extern void IGMPTimer(NetTableEntry *NTE);
+
+
diff --git a/private/ntos/tdi/tcpip/ip/info.c b/private/ntos/tdi/tcpip/ip/info.c
new file mode 100644
index 000000000..a866c0cba
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/info.c
@@ -0,0 +1,609 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** INFO.C - Routines for querying and setting IP information.
+//
+// This file contains the code for dealing with Query/Set information
+// calls.
+//
+
+#include "oscfg.h"
+#include "ndis.h"
+#include "cxport.h"
+#include "ip.h"
+#include "ipdef.h"
+#include "info.h"
+#include "tdi.h"
+#include "tdiinfo.h"
+#include "llinfo.h"
+#include "tdistat.h"
+#include "iproute.h"
+#include "igmp.h"
+#include "ipfilter.h"
+#include "iprtdef.h"
+
+extern Interface *IFList;
+extern NetTableEntry *NetTableList;
+extern uint LoopIndex; // Index of loopback I/F.
+extern uint DefaultTTL;
+extern uint NumIF;
+extern uint NumNTE;
+extern RouteInterface DummyInterface; // Dummy interface.
+
+EXTERNAL_LOCK(RouteTableLock)
+
+extern uint RTEReadNext(void *Context, void *Buffer);
+extern uint RTValidateContext(void *Context, uint *Valid);
+extern uint RTReadNext(void *Context, void *Buffer);
+
+uint IPInstance;
+uint ICMPInstance;
+
+//* CopyToNdis - Copy a flat buffer to an NDIS_BUFFER chain.
+//
+// A utility function to copy a flat buffer to an NDIS buffer chain. We
+// assume that the NDIS_BUFFER chain is big enough to hold the copy amount;
+// in a debug build we'll debugcheck if this isn't true. We return a pointer
+// to the buffer where we stopped copying, and an offset into that buffer.
+// This is useful for copying in pieces into the chain.
+//
+// Input: DestBuf - Destination NDIS_BUFFER chain.
+// SrcBuf - Src flat buffer.
+// Size - Size in bytes to copy.
+// StartOffset - Pointer to start of offset into first buffer in
+// chain. Filled in on return with the offset to
+// copy into next.
+//
+// Returns: Pointer to next buffer in chain to copy into.
+//
+PNDIS_BUFFER
+CopyToNdis(PNDIS_BUFFER DestBuf, uchar *SrcBuf, uint Size,
+ uint *StartOffset)
+{
+ uint CopySize;
+ uchar *DestPtr;
+ uint DestSize;
+ uint Offset = *StartOffset;
+ uchar *VirtualAddress;
+ uint Length;
+
+ CTEAssert(DestBuf != NULL);
+ CTEAssert(SrcBuf != NULL);
+
+ NdisQueryBuffer(DestBuf, &VirtualAddress, &Length);
+ CTEAssert(Length >= Offset);
+ DestPtr = VirtualAddress + Offset;
+ DestSize = Length - Offset;
+
+ for (;;) {
+ CopySize = MIN(Size, DestSize);
+ CTEMemCopy(DestPtr, SrcBuf, CopySize);
+
+ DestPtr += CopySize;
+ SrcBuf += CopySize;
+
+ if ((Size -= CopySize) == 0)
+ break;
+
+ if ((DestSize -= CopySize) == 0) {
+ DestBuf = NDIS_BUFFER_LINKAGE(DestBuf);
+ CTEAssert(DestBuf != NULL);
+ NdisQueryBuffer(DestBuf, &VirtualAddress, &Length);
+ DestPtr = VirtualAddress;
+ DestSize = Length;
+ }
+ }
+
+ *StartOffset = DestPtr - VirtualAddress;
+
+ return DestBuf;
+
+}
+
+
+//* IPQueryInfo - IP query information handler.
+//
+// Called by the upper layer when it wants to query information about us.
+// We take in an ID, a buffer and length, and a context value, and return
+// whatever information we can.
+//
+// Input: ID - Pointer to ID structure.
+// Buffer - Pointer to buffer chain.
+// Size - Pointer to size in bytes of buffer. On return, filled
+// in with bytes read.
+// Context - Pointer to context value.
+//
+// Returns: TDI_STATUS of attempt to read information.
+//
+long
+IPQueryInfo(TDIObjectID *ID, PNDIS_BUFFER Buffer, uint *Size, void *Context)
+{
+ uint BufferSize = *Size;
+ uint BytesCopied = 0;
+ uint Offset = 0;
+ TDI_STATUS Status;
+ ushort NTEContext;
+ uchar InfoBuff[sizeof(IPRouteEntry)];
+ IPAddrEntry *AddrEntry;
+ NetTableEntry *CurrentNTE;
+ uint Valid, DataLeft;
+ CTELockHandle Handle;
+ Interface *LowerIF;
+ IPInterfaceInfo *IIIPtr;
+ uint LLID = 0;
+ uint Entity;
+ uint Instance;
+ IPAddr IFAddr;
+
+
+ Entity = ID->toi_entity.tei_entity;
+ Instance = ID->toi_entity.tei_instance;
+
+ // See if it's something we might handle.
+
+ if (Entity != CL_NL_ENTITY && Entity != ER_ENTITY) {
+ // We need to pass this down to the lower layer. Loop through until
+ // we find one that takes it. If noone does, error out.
+ for (LowerIF = IFList; LowerIF != NULL; LowerIF = LowerIF->if_next) {
+ Status = (*LowerIF->if_qinfo)(LowerIF->if_lcontext, ID, Buffer,
+ Size, Context);
+ if (Status != TDI_INVALID_REQUEST)
+ return Status;
+ }
+ // If we get here, noone took it. Return an error.
+ return TDI_INVALID_REQUEST;
+
+ }
+
+ if ((Entity == CL_NL_ENTITY && Instance != IPInstance) ||
+ Instance != ICMPInstance)
+ return TDI_INVALID_REQUEST;
+
+ // The request is for us.
+ *Size = 0; // Set to 0 in case of an error.
+
+ // Make sure it's something we support.
+ if (ID->toi_class == INFO_CLASS_GENERIC) {
+ if (ID->toi_type == INFO_TYPE_PROVIDER && ID->toi_id == ENTITY_TYPE_ID) {
+ // He's trying to see what type we are.
+ if (BufferSize >= sizeof(uint)) {
+ *(uint *)&InfoBuff[0] = (Entity == CL_NL_ENTITY) ? CL_NL_IP :
+ ER_ICMP;
+ (void)CopyToNdis(Buffer, InfoBuff, sizeof(uint), &Offset);
+ return TDI_SUCCESS;
+ } else
+ return TDI_BUFFER_TOO_SMALL;
+ }
+ return TDI_INVALID_PARAMETER;
+ } else
+ if (ID->toi_class != INFO_CLASS_PROTOCOL ||
+ ID->toi_type != INFO_TYPE_PROVIDER)
+ return TDI_INVALID_PARAMETER;
+
+ // If it's ICMP, just copy the statistics.
+ if (Entity == ER_ENTITY) {
+
+ // It is ICMP. Make sure the ID is valid.
+ if (ID->toi_id != ICMP_MIB_STATS_ID)
+ return TDI_INVALID_PARAMETER;
+
+ // He wants the stats. Copy what we can.
+ if (BufferSize < sizeof(ICMPSNMPInfo))
+ return TDI_BUFFER_TOO_SMALL;
+
+ Buffer = CopyToNdis(Buffer, (uchar *)&ICMPInStats, sizeof(ICMPStats),
+ &Offset);
+ (void)CopyToNdis(Buffer, (uchar *)&ICMPOutStats, sizeof(ICMPStats),
+ &Offset);
+
+ *Size = sizeof(ICMPSNMPInfo);
+ return TDI_SUCCESS;
+ }
+
+ // It's not ICMP. We need to figure out what it is, and take the
+ // appropriate action.
+
+ switch (ID->toi_id) {
+
+ case IP_MIB_STATS_ID:
+ if (BufferSize < sizeof(IPSNMPInfo))
+ return TDI_BUFFER_TOO_SMALL;
+ IPSInfo.ipsi_numif = NumIF;
+ IPSInfo.ipsi_numaddr = NumNTE;
+ IPSInfo.ipsi_defaultttl = DefaultTTL;
+ IPSInfo.ipsi_forwarding = ForwardPackets ? IP_FORWARDING :
+ IP_NOT_FORWARDING;
+ CopyToNdis(Buffer, (uchar *)&IPSInfo, sizeof(IPSNMPInfo), &Offset);
+ BytesCopied = sizeof(IPSNMPInfo);
+ Status = TDI_SUCCESS;
+ break;
+ case IP_MIB_ADDRTABLE_ENTRY_ID:
+ // He wants to read the address table. Figure out where we're
+ // starting from, and if it's valid begin copying from there.
+ NTEContext = *(ushort *)Context;
+ CurrentNTE = NetTableList;
+
+ if (NTEContext != 0) {
+ for (;CurrentNTE != NULL; CurrentNTE = CurrentNTE->nte_next)
+ if (CurrentNTE->nte_context == NTEContext)
+ break;
+ if (CurrentNTE == NULL)
+ return TDI_INVALID_PARAMETER;
+ }
+
+ AddrEntry = (IPAddrEntry *)InfoBuff;
+ for (; CurrentNTE != NULL; CurrentNTE = CurrentNTE->nte_next) {
+ if ((int)(BufferSize - BytesCopied) >= (int)sizeof(IPAddrEntry)) {
+ // We have room to copy it. Build the entry, and copy
+ // it.
+ if (CurrentNTE->nte_flags & NTE_ACTIVE) {
+ if (CurrentNTE->nte_flags & NTE_VALID) {
+ AddrEntry->iae_addr = CurrentNTE->nte_addr;
+ AddrEntry->iae_mask = CurrentNTE->nte_mask;
+ } else {
+ AddrEntry->iae_addr = NULL_IP_ADDR;
+ AddrEntry->iae_mask = NULL_IP_ADDR;
+ }
+
+ AddrEntry->iae_index = CurrentNTE->nte_if->if_index;
+ AddrEntry->iae_bcastaddr =
+ *(int *)&(CurrentNTE->nte_if->if_bcast) & 1;
+ AddrEntry->iae_reasmsize = 0xffff;
+ AddrEntry->iae_context = CurrentNTE->nte_context;
+ Buffer = CopyToNdis(Buffer, (uchar *)AddrEntry,
+ sizeof(IPAddrEntry), &Offset);
+ BytesCopied += sizeof(IPAddrEntry);
+ }
+ } else
+ break;
+ }
+
+ if (CurrentNTE == NULL)
+ Status = TDI_SUCCESS;
+ else {
+ Status = TDI_BUFFER_OVERFLOW;
+ **(ushort **)&Context = CurrentNTE->nte_context;
+ }
+
+ break;
+ case IP_MIB_RTTABLE_ENTRY_ID:
+ // Make sure we have a valid context.
+ CTEGetLock(&RouteTableLock, &Handle);
+ DataLeft = RTValidateContext(Context, &Valid);
+
+ // If the context is valid, we'll continue trying to read.
+ if (!Valid) {
+ CTEFreeLock(&RouteTableLock, Handle);
+ return TDI_INVALID_PARAMETER;
+ }
+
+ while (DataLeft) {
+ // The invariant here is that there is data in the table to
+ // read. We may or may not have room for it. So DataLeft
+ // is TRUE, and BufferSize - BytesCopied is the room left
+ // in the buffer.
+ if ((int)(BufferSize - BytesCopied) >= (int)sizeof(IPRouteEntry)) {
+ DataLeft = RTReadNext(Context, InfoBuff);
+ BytesCopied += sizeof(IPRouteEntry);
+ Buffer = CopyToNdis(Buffer, InfoBuff, sizeof(IPRouteEntry),
+ &Offset);
+ } else
+ break;
+
+ }
+
+ CTEFreeLock(&RouteTableLock, Handle);
+ Status = (!DataLeft ? TDI_SUCCESS : TDI_BUFFER_OVERFLOW);
+ break;
+ case IP_INTFC_INFO_ID:
+
+ IFAddr = *(IPAddr *)Context;
+ // Loop through the NTE table, looking for a match.
+ for (CurrentNTE = NetTableList; CurrentNTE != NULL; CurrentNTE = CurrentNTE->nte_next) {
+ if ((CurrentNTE->nte_flags & NTE_VALID) &&
+ IP_ADDR_EQUAL(CurrentNTE->nte_addr, IFAddr))
+ break;
+ }
+ if (CurrentNTE == NULL) {
+ Status = TDI_INVALID_PARAMETER;
+ break;
+ }
+
+ if (BufferSize < offsetof(IPInterfaceInfo, iii_addr)) {
+ Status = TDI_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ // We have the NTE. Get the interface, fill in a structure,
+ // and we're done.
+ LowerIF = CurrentNTE->nte_if;
+ IIIPtr = (IPInterfaceInfo *)InfoBuff;
+ IIIPtr->iii_flags = LowerIF->if_flags & IF_FLAGS_P2P ?
+ IP_INTFC_FLAG_P2P : 0;
+ IIIPtr->iii_mtu = LowerIF->if_mtu;
+ IIIPtr->iii_speed = LowerIF->if_speed;
+ IIIPtr->iii_addrlength = LowerIF->if_addrlen;
+ BytesCopied = offsetof(IPInterfaceInfo, iii_addr);
+ if (BufferSize >= (offsetof(IPInterfaceInfo, iii_addr) +
+ LowerIF->if_addrlen)) {
+ Status = TDI_SUCCESS;
+ Buffer = CopyToNdis(Buffer, InfoBuff,
+ offsetof(IPInterfaceInfo, iii_addr), &Offset);
+ CopyToNdis(Buffer, LowerIF->if_addr, LowerIF->if_addrlen,
+ &Offset);
+ BytesCopied += LowerIF->if_addrlen;
+ } else {
+ Status = TDI_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ default:
+ return TDI_INVALID_PARAMETER;
+ break;
+ }
+
+ *Size = BytesCopied;
+ return Status;
+}
+
+//* IPSetInfo - IP set information handler.
+//
+// Called by the upper layer when it wants to set an object, which could
+// be a route table entry, an ARP table entry, or something else.
+//
+// Input: ID - Pointer to ID structure.
+// Buffer - Pointer to buffer containing element to set..
+// Size - Pointer to size in bytes of buffer.
+//
+// Returns: TDI_STATUS of attempt to read information.
+//
+long
+IPSetInfo(TDIObjectID *ID, void *Buffer, uint Size)
+{
+ uint Entity;
+ uint Instance;
+ Interface *LowerIF;
+ Interface *OutIF;
+ uint MTU;
+ IPRouteEntry *IRE;
+ NetTableEntry *OutNTE, *LocalNTE;
+ IP_STATUS Status;
+ IPAddr FirstHop, Dest, NextHop;
+
+ Entity = ID->toi_entity.tei_entity;
+ Instance = ID->toi_entity.tei_instance;
+
+ // If it's not for us, pass it down.
+ if (Entity != CL_NL_ENTITY) {
+ // We need to pass this down to the lower layer. Loop through until
+ // we find one that takes it. If noone does, error out.
+ for (LowerIF = IFList; LowerIF != NULL; LowerIF = LowerIF->if_next) {
+ Status = (*LowerIF->if_setinfo)(LowerIF->if_lcontext, ID, Buffer,
+ Size);
+ if (Status != TDI_INVALID_REQUEST)
+ return Status;
+ }
+ // If we get here, noone took it. Return an error.
+ return TDI_INVALID_REQUEST;
+ }
+
+ if (Instance != IPInstance)
+ return TDI_INVALID_REQUEST;
+
+ // We're identified as the entity. Make sure the ID is correct.
+ if (ID->toi_id == IP_MIB_RTTABLE_ENTRY_ID) {
+ NetTableEntry *TempNTE;
+
+ // This is an attempt to set a route table entry. Make sure the
+ // size if correct.
+ if (Size < sizeof(IPRouteEntry))
+ return TDI_INVALID_PARAMETER;
+
+ IRE = (IPRouteEntry *)Buffer;
+
+ OutNTE = NULL;
+ LocalNTE = NULL;
+
+ Dest = IRE->ire_dest;
+ NextHop = IRE->ire_nexthop;
+
+ // Make sure that the nexthop is sensible. We don't allow nexthops
+ // to be broadcast or invalid or loopback addresses.
+ if (IP_ADDR_EQUAL(NextHop, NULL_IP_ADDR) || IP_LOOPBACK(NextHop) ||
+ CLASSD_ADDR(NextHop) || CLASSE_ADDR(NextHop))
+ return TDI_INVALID_PARAMETER;
+
+ // Also make sure that the destination we're routing to is sensible.
+ // Don't allow routes to be added to Class D or E or loopback
+ // addresses.
+ if (IP_LOOPBACK(Dest) || CLASSD_ADDR(Dest) || CLASSE_ADDR(Dest))
+ return TDI_INVALID_PARAMETER;
+
+ if (IRE->ire_index == LoopIndex)
+ return TDI_INVALID_PARAMETER;
+
+ if (IRE->ire_index != INVALID_IF_INDEX) {
+
+ // First thing to do is to find the outgoing NTE for specified
+ // interface, and also make sure that it matches the destination
+ // if the destination is one of my addresses.
+ for (TempNTE = NetTableList; TempNTE != NULL;
+ TempNTE = TempNTE->nte_next) {
+ if (OutNTE == NULL && IRE->ire_index == TempNTE->nte_if->if_index)
+ OutNTE = TempNTE;
+ if (IP_ADDR_EQUAL(NextHop, TempNTE->nte_addr) &&
+ (TempNTE->nte_flags & NTE_VALID))
+ LocalNTE = TempNTE;
+
+ // Don't let a route be set through a broadcast address.
+ if (IsBCastOnNTE(NextHop, TempNTE) != DEST_LOCAL)
+ return TDI_INVALID_PARAMETER;
+
+ // Don't let a route to a broadcast address be added or deleted.
+ if (IsBCastOnNTE(Dest, TempNTE) != DEST_LOCAL)
+ return TDI_INVALID_PARAMETER;
+ }
+
+ // At this point OutNTE points to the outgoing NTE, and LocalNTE
+ // points to the NTE for the local address, if this is a direct route.
+ // Make sure they point to the same interface, and that the type is
+ // reasonable.
+ if (OutNTE == NULL)
+ return TDI_INVALID_PARAMETER;
+
+ if (LocalNTE != NULL) {
+ // He's routing straight out a local interface. The interface for
+ // the local address must match the interface passed in, and the
+ // type must be DIRECT (if we're adding) or INVALID (if we're
+ // deleting).
+ if (LocalNTE->nte_if->if_index != IRE->ire_index)
+ return TDI_INVALID_PARAMETER;
+
+ if (IRE->ire_type != IRE_TYPE_DIRECT &&
+ IRE->ire_type != IRE_TYPE_INVALID)
+ return TDI_INVALID_PARAMETER;
+
+ OutNTE = LocalNTE;
+ }
+
+
+ // Figure out what the first hop should be. If he's routing straight
+ // through a local interface, or the next hop is equal to the
+ // destination, then the first hop is IPADDR_LOCAL. Otherwise it's the
+ // address of the gateway.
+ if (LocalNTE != NULL)
+ FirstHop = IPADDR_LOCAL;
+ else
+ if (IP_ADDR_EQUAL(Dest, NextHop))
+ FirstHop = IPADDR_LOCAL;
+ else
+ FirstHop = NextHop;
+
+ MTU = OutNTE->nte_mss;
+ OutIF = OutNTE->nte_if;
+
+ } else {
+ OutIF = (Interface *)&DummyInterface;
+ MTU = DummyInterface.ri_if.if_mtu - sizeof(IPHeader);
+ if (IP_ADDR_EQUAL(Dest, NextHop))
+ FirstHop = IPADDR_LOCAL;
+ else
+ FirstHop = NextHop;
+ }
+
+ // We've done the validation. See if he's adding or deleting a route.
+ if (IRE->ire_type != IRE_TYPE_INVALID) {
+ // He's adding a route.
+ Status = AddRoute(Dest, IRE->ire_mask, FirstHop, OutIF,
+ MTU, IRE->ire_metric1, IRE->ire_proto,
+ ATYPE_OVERRIDE, IRE->ire_context);
+
+ } else {
+ // He's deleting a route.
+ Status = DeleteRoute(Dest, IRE->ire_mask, FirstHop, OutIF);
+ }
+
+ if (Status == IP_SUCCESS)
+ return TDI_SUCCESS;
+ else
+ if (Status == IP_NO_RESOURCES)
+ return TDI_NO_RESOURCES;
+ else
+ return TDI_INVALID_PARAMETER;
+
+ } else {
+ if (ID->toi_id == IP_MIB_STATS_ID) {
+ IPSNMPInfo *Info = (IPSNMPInfo *)Buffer;
+
+ // Setting information about TTL and/or routing.
+ if (Info->ipsi_defaultttl > 255 || (!RouterConfigured &&
+ Info->ipsi_forwarding == IP_FORWARDING)) {
+ return TDI_INVALID_PARAMETER;
+ }
+
+ DefaultTTL = Info->ipsi_defaultttl;
+ ForwardPackets = Info->ipsi_forwarding == IP_FORWARDING ? TRUE :
+ FALSE;
+
+ return TDI_SUCCESS;
+ }
+ return TDI_INVALID_PARAMETER;
+ }
+
+}
+#ifndef CHICAGO
+#pragma BEGIN_INIT
+#endif
+
+//* IPGetEList - Get the entity list.
+//
+// Called at init time to get an entity list. We fill our stuff in, and
+// then call the interfaces below us to allow them to do the same.
+//
+// Input: EntityList - Pointer to entity list to be filled in.
+// Count - Pointer to number of entries in the list.
+//
+// Returns Status of attempt to get the info.
+//
+long
+IPGetEList(TDIEntityID *EList, uint *Count)
+{
+ uint ECount;
+ uint MyIPBase;
+ uint MyERBase;
+ int Status;
+ uint i;
+ Interface *LowerIF;
+ TDIEntityID *EntityList;
+
+ ECount = *Count;
+ EntityList = EList;
+
+ // Walk down the list, looking for existing CL_NL or ER entities, and
+ // adjust our base instance accordingly.
+
+ MyIPBase = 0;
+ MyERBase = 0;
+ for (i = 0; i < ECount; i++, EntityList++) {
+ if (EntityList->tei_entity == CL_NL_ENTITY)
+ MyIPBase = MAX(MyIPBase, EntityList->tei_instance + 1);
+ else
+ if (EntityList->tei_entity == ER_ENTITY)
+ MyERBase = MAX(MyERBase, EntityList->tei_instance + 1);
+ }
+
+ // At this point we've figure out our base instance. Save for later use.
+ IPInstance = MyIPBase;
+ ICMPInstance = MyERBase;
+
+ // EntityList points to the start of where we want to begin filling in.
+ // Make sure we have enough room. We need one for the ICMP instance,
+ // and one for the CL_NL instance.
+
+ if ((ECount + 2) > MAX_TDI_ENTITIES)
+ return TDI_REQ_ABORTED;
+
+ // Now fill it in.
+ EntityList->tei_entity = CL_NL_ENTITY;
+ EntityList->tei_instance = IPInstance;
+ EntityList++;
+ EntityList->tei_entity = ER_ENTITY;
+ EntityList->tei_instance = ICMPInstance;
+ *Count += 2;
+
+ // Loop through the interfaces, querying each of them.
+ for (LowerIF = IFList; LowerIF != NULL; LowerIF = LowerIF->if_next) {
+ Status = (*LowerIF->if_getelist)(LowerIF->if_lcontext, EList, Count);
+ if (!Status)
+ return TDI_BUFFER_TOO_SMALL;
+ }
+
+ return TDI_SUCCESS;
+}
+
+#ifndef CHICAGO
+#pragma END_INIT
+#endif
diff --git a/private/ntos/tdi/tcpip/ip/info.h b/private/ntos/tdi/tcpip/ip/info.h
new file mode 100644
index 000000000..e8de293e0
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/info.h
@@ -0,0 +1,22 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1992 **/
+/********************************************************************/
+/* :ts=4 */
+
+#include "ipinfo.h"
+
+extern IPSNMPInfo IPSInfo;
+extern ICMPStats ICMPInStats;
+extern ICMPStats ICMPOutStats;
+
+typedef struct RouteEntryContext {
+ uint rec_index;
+ struct RouteTableEntry *rec_rte;
+} RouteEntryContext;
+
+extern long IPQueryInfo(struct TDIObjectID *ID, PNDIS_BUFFER Buffer,
+ uint *Size, void *Context);
+extern long IPSetInfo(struct TDIObjectID *ID, void *Buffer, uint Size);
+extern long IPGetEList(struct TDIEntityID *Buffer, uint *Count);
+
diff --git a/private/ntos/tdi/tcpip/ip/init.c b/private/ntos/tdi/tcpip/ip/init.c
new file mode 100644
index 000000000..3f032a50a
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/init.c
@@ -0,0 +1,3509 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1992 **/
+/********************************************************************/
+/* :ts=4 */
+
+//*** Init.c - IP VxD init routines.
+//
+// All C init routines are located in this file. We get
+// config. information, allocate structures, and generally get things going.
+
+#include "oscfg.h"
+#include "cxport.h"
+#include "ndis.h"
+#include "ip.h"
+#include "ipdef.h"
+#include "ipinit.h"
+#include "llipif.h"
+#include "arp.h"
+#include "info.h"
+#include "iproute.h"
+#include "iprtdef.h"
+#include "ipxmit.h"
+#include "igmp.h"
+#include "icmp.h"
+#include <tdiinfo.h>
+
+#ifdef NT
+#include <tdi.h>
+#include <tdikrnl.h>
+#endif
+
+
+#define NUM_IP_NONHDR_BUFFERS 50
+
+#define DEFAULT_RA_TIMEOUT 60
+
+#define DEFAULT_ICMP_BUFFERS 5
+
+extern IPConfigInfo *IPGetConfig(void);
+extern void IPFreeConfig(IPConfigInfo *);
+extern int IsIPBCast(IPAddr, uchar);
+
+extern uint OpenIFConfig(PNDIS_STRING ConfigName, NDIS_HANDLE *Handle);
+extern void CloseIFConfig(NDIS_HANDLE Handle);
+
+// The IPRcv routine.
+extern void IPRcv(void *, void *, uint , uint , NDIS_HANDLE , uint , uint );
+// The transmit complete routine.
+extern void IPSendComplete(void *, PNDIS_PACKET , NDIS_STATUS );
+// Status indication routine.
+extern void IPStatus(void *, NDIS_STATUS, void *, uint);
+// Transfer data complete routine.
+extern void IPTDComplete(void *, PNDIS_PACKET , NDIS_STATUS , uint );
+
+extern void IPRcvComplete(void);
+
+extern void ICMPInit(uint);
+extern uint IGMPInit(void);
+extern void ICMPTimer(NetTableEntry *);
+extern IP_STATUS SendICMPErr(IPAddr, IPHeader UNALIGNED *, uchar, uchar, ulong);
+extern void TDUserRcv(void *, PNDIS_PACKET, NDIS_STATUS, uint);
+extern void FreeRH(ReassemblyHeader *);
+extern PNDIS_PACKET GrowIPPacketList(void);
+extern PNDIS_BUFFER FreeIPPacket(PNDIS_PACKET Packet);
+
+extern ulong GetGMTDelta(void);
+extern ulong GetTime(void);
+extern ulong GetUnique32BitValue(void);
+
+extern void NotifyAddrChange(IPAddr Addr, IPMask Mask, void *Context,
+ ushort IPContext, PVOID *Handle, PNDIS_STRING ConfigName, uint Added);
+
+uint IPSetNTEAddr(ushort Context, IPAddr Addr, IPMask Mask, SetAddrControl *ControlBlock, SetAddrRtn Rtn);
+
+extern NDIS_HANDLE BufferPool;
+EXTERNAL_LOCK(HeaderLock)
+#ifdef NT
+extern SLIST_HEADER PacketList;
+extern SLIST_HEADER HdrBufList;
+#endif
+
+extern NetTableEntry *LoopNTE;
+
+extern uchar RouterConfigured;
+
+//NetTableEntry *NetTable; // Pointer to the net table.
+
+NetTableEntry *NetTableList; // List of NTEs.
+int NumNTE; // Number of NTEs.
+
+AddrTypeCache ATCache[ATC_SIZE];
+uint ATCIndex;
+
+uchar RATimeout; // Number of seconds to time out a
+ // reassembly.
+ushort NextNTEContext; // Next NTE context to use.
+
+#if 0
+DEFINE_LOCK_STRUCTURE(PILock)
+#endif
+
+ProtInfo IPProtInfo[MAX_IP_PROT]; // Protocol information table.
+ProtInfo *LastPI; // Last protinfo structure looked at.
+int NextPI; // Next PI field to be used.
+ProtInfo *RawPI = NULL; // Raw IP protinfo
+
+ulong TimeStamp;
+ulong TSFlag;
+
+uint DefaultTTL;
+uint DefaultTOS;
+uchar TrRii = TR_RII_ALL;
+
+// Interface *IFTable[MAX_IP_NETS];
+Interface *IFList; // List of interfaces active.
+Interface *FirstIF; // First 'real' IF.
+ulong NumIF;
+
+#ifdef _PNP_POWER
+#define BITS_PER_WORD 32
+ulong IFBitMask[(MAX_TDI_ENTITIES / BITS_PER_WORD) + 1];
+#endif // _PNP_POWER
+
+IPSNMPInfo IPSInfo;
+uint DHCPActivityCount = 0;
+uint IGMPLevel;
+
+#ifdef NT
+
+#ifndef _PNP_POWER
+
+extern NameMapping *AdptNameTable;
+extern DriverRegMapping *DriverNameTable;
+
+#endif // _PNP_POWER
+
+VOID
+SetPersistentRoutesForNTE(
+ IPAddr Address,
+ IPMask Mask,
+ ULONG IFIndex
+ );
+
+#else // NT
+
+#ifndef _PNP_POWER
+
+extern NameMapping AdptNameTable[];
+extern DriverRegMapping DriverNameTable[];
+
+#endif // _PNP_POWER
+
+#endif // NT
+
+#ifndef _PNP_POWER
+extern uint NumRegDrivers;
+uint MaxIPNets = 0;
+#endif // _PNP_POWER
+
+uint InterfaceSize; // Size of a net interface.
+NetTableEntry *DHCPNTE = NULL;
+
+
+#ifdef NT
+
+#ifdef ALLOC_PRAGMA
+//
+// Make init code disposable.
+//
+void InitTimestamp();
+int InitNTE(NetTableEntry *NTE);
+int InitInterface(NetTableEntry *NTE);
+LLIPRegRtn GetLLRegPtr(PNDIS_STRING Name);
+LLIPRegRtn FindRegPtr(PNDIS_STRING Name);
+uint IPRegisterDriver(PNDIS_STRING Name, LLIPRegRtn Ptr);
+void CleanAdaptTable();
+void OpenAdapters();
+int IPInit();
+
+#if 0 // BUGBUG: These can eventually be made init time only.
+
+#pragma alloc_text(INIT, IPGetInfo)
+#pragma alloc_text(INIT, IPTimeout)
+
+#endif // 0
+
+#pragma alloc_text(INIT, InitTimestamp)
+#ifndef _PNP_POWER
+#pragma alloc_text(INIT, InitNTE)
+#pragma alloc_text(INIT, InitInterface)
+#endif
+#pragma alloc_text(INIT, CleanAdaptTable)
+#pragma alloc_text(INIT, OpenAdapters)
+#pragma alloc_text(INIT, IPRegisterDriver)
+#pragma alloc_text(INIT, GetLLRegPtr)
+#pragma alloc_text(INIT, FindRegPtr)
+#pragma alloc_text(INIT, IPInit)
+
+
+//
+// Pagable code
+//
+uint
+IPAddDynamicNTE(ushort InterfaceContext, IPAddr NewAddr, IPMask NewMask,
+ ushort *NTEContext, ulong *NTEInstance);
+
+#pragma alloc_text(PAGE, IPAddDynamicNTE)
+
+#endif // ALLOC_PRAGMA
+
+extern PDRIVER_OBJECT IPDriverObject;
+
+NTSTATUS
+SetRegDWORDValue(
+ HANDLE KeyHandle,
+ PWCHAR ValueName,
+ PULONG ValueData
+ );
+
+//
+// Debugging macros
+//
+#if DBG
+
+#define TCPTRACE(many_args) DbgPrint many_args
+
+#else // DBG
+
+#define TCPTRACE(many_args)
+
+#endif // DBG
+
+
+// SetIFContext - Set the context on a particular interface.
+//
+// A routine to set the filter context on a particular interface.
+//
+// Input: Index - Interface index of i/f to be set.
+// Context - Context to set.
+//
+// Returns: Status of attempt.
+//
+IP_STATUS
+SetIFContext(uint Index, INTERFACE_CONTEXT *Context)
+{
+ Interface *IF;
+
+ // Walk the list, looking for a matching index.
+ for (IF = IFList; IF != NULL; IF = IF->if_next) {
+ if (IF->if_index == Index) {
+ IF->if_filtercontext = Context;
+ break;
+ }
+ }
+
+ // If we found one, return success. Otherwise fail.
+ if (IF != NULL) {
+ return IP_SUCCESS;
+ } else {
+ return IP_GENERAL_FAILURE;
+ }
+}
+
+// SetFilterPtr - A routine to set the filter pointer.
+//
+// This routine sets the IP forwarding filter callout.
+//
+// Input: FilterPtr - Pointer to routine to call when filtering. May
+// be NULL.
+//
+// Returns: IP_SUCCESS.
+//
+IP_STATUS
+SetFilterPtr(IPPacketFilterPtr FilterPtr)
+{
+ Interface *IF;
+
+ //
+ // If the pointer is being set to NULL, means filtering is
+ // being turned off. Remove all the contexts we have
+ //
+
+ if(FilterPtr == NULL)
+ {
+
+ for (IF = IFList; IF != NULL; IF = IF->if_next)
+ {
+ IF->if_filtercontext = NULL;
+ }
+ }
+
+ ForwardFilterPtr = FilterPtr;
+
+ return IP_SUCCESS;
+}
+
+// SetMapRoutePtr - A routine to set the dial on demand callout pointer.
+//
+// This routine sets the IP dial on demand callout.
+//
+// Input: MapRoutePtr - Pointer to routine to call when we need to bring
+// up a link. May be NULL
+//
+// Returns: IP_SUCCESS.
+//
+IP_STATUS
+SetMapRoutePtr(IPMapRouteToInterfacePtr MapRoutePtr)
+{
+ DODCallout = MapRoutePtr;
+ return IP_SUCCESS;
+}
+
+#endif // NT
+
+
+//** SetDHCPNTE
+//
+// Routine to identify which NTE is currently being DHCP'ed. We take as input
+// an nte_context. If the context is less than the max NTE context, we look
+// for a matching NTE and if we find him we save a pointer. If we don't we
+// fail. If the context > max NTE context we're disabling DHCPing, and
+// we NULL out the save pointer.
+//
+// Input: Context - NTE context value.
+//
+// Returns: TRUE if we succeed, FALSE if we don't.
+//
+uint
+SetDHCPNTE(uint Context)
+{
+ CTELockHandle Handle;
+ NetTableEntry *NTE;
+ ushort NTEContext;
+ uint RetCode;
+
+ CTEGetLock(&RouteTableLock, &Handle);
+
+ if (Context <= 0xffff) {
+ // We're setting the DHCP NTE. Look for one matching the context.
+
+ NTEContext = (ushort)Context;
+
+ for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
+ if (NTE != LoopNTE && NTE->nte_context == NTEContext) {
+ // Found one. Save it and break out.
+ DHCPNTE = NTE;
+ break;
+ }
+ }
+
+ RetCode = (NTE != NULL);
+ } else {
+ // The context is invalid, so we're deleting the DHCP NTE.
+ DHCPNTE = NULL;
+ RetCode = TRUE;
+ }
+
+ CTEFreeLock(&RouteTableLock, Handle);
+
+ return RetCode;
+}
+
+
+//** SetDHCPNTE
+//
+// Routine for upper layers to call to check if the IPContext value passed
+// up to a RcvHandler identifies an interface that is currently being
+// DHCP'd.
+//
+// Input: Context - Pointer to an NTE
+//
+// Returns: TRUE if we succeed, FALSE if we don't.
+//
+uint
+IsDHCPInterface(void *IPContext)
+{
+// CTELockHandle Handle;
+ uint RetCode;
+ NetTableEntry *NTE = (NetTableEntry *) IPContext;
+
+
+// CTEGetLock(&RouteTableLock, &Handle);
+
+ if (DHCPNTE == NTE) {
+ RetCode = TRUE;
+ }
+ else {
+ RetCode = FALSE;
+ }
+
+// CTEFreeLock(&RouteTableLock, Handle);
+
+ return(RetCode);
+}
+
+
+//** CloseNets - Close active nets.
+//
+// Called when we need to close some lower layer interfaces.
+//
+// Entry: Nothing
+//
+// Returns: Nothing
+//
+void
+CloseNets(void)
+{
+ NetTableEntry *nt;
+
+ for (nt = NetTableList; nt != NULL; nt = nt->nte_next)
+ (*nt->nte_if->if_close)(nt->nte_if->if_lcontext); // Call close routine for this net.
+}
+
+//** IPRegisterProtocol - Register a protocol with IP.
+//
+// Called by upper layer software to register a protocol. The UL supplies
+// pointers to receive routines and a protocol value to be used on xmits/receives.
+//
+// Entry:
+// Protocol - Protocol value to be returned.
+// RcvHandler - Receive handler to be called when frames for Protocol are received.
+// XmitHandler - Xmit. complete handler to be called when frames from Protocol are completed.
+// StatusHandler - Handler to be called when status indication is to be delivered.
+//
+// Returns:
+// Pointer to ProtInfo,
+//
+void *
+IPRegisterProtocol(uchar Protocol, void *RcvHandler, void *XmitHandler,
+ void *StatusHandler, void *RcvCmpltHandler)
+{
+ ProtInfo *PI = (ProtInfo *)NULL;
+ int i;
+ int Incr;
+#if 0
+ CTELockHandle Handle;
+
+
+ CTEGetLock(&PILock, &Handle);
+#endif
+
+ // First check to see if it's already registered. If it is just replace it.
+ for (i = 0; i < NextPI; i++)
+ if (IPProtInfo[i].pi_protocol == Protocol) {
+ PI = &IPProtInfo[i];
+ Incr = 0;
+ break;
+ }
+
+ if (PI == (ProtInfo *)NULL) {
+ if (NextPI >= MAX_IP_PROT) {
+#if 0
+ CTEFreeLock(&PILock, Handle);
+#endif
+ return NULL;
+ }
+
+ PI = &IPProtInfo[NextPI];
+ Incr = 1;
+
+ if (Protocol == PROTOCOL_ANY) {
+ RawPI = PI;
+ }
+ }
+
+ PI->pi_protocol = Protocol;
+ PI->pi_rcv = RcvHandler;
+ PI->pi_xmitdone = XmitHandler;
+ PI->pi_status = StatusHandler;
+ PI->pi_rcvcmplt = RcvCmpltHandler;
+ NextPI += Incr;
+
+#if 0
+ CTEFreeLock(&PILock, Handle);
+#endif
+
+#ifndef _PNP_POWER
+#ifdef SECFLTR
+
+ //
+ // If this was a registration, call the status routine of each protocol
+ // to inform it of all existing interfaces. Yes, this is a hack, but
+ // it will work until PnP is turned on in NT.
+ //
+ // It is assumed that none of the upper layer status routines call back
+ // into IP.
+ //
+ // Note that we don't hold any locks here since no one manipulates the
+ // NTE list in a non-PNP build during the init phase.
+ //
+ if (StatusHandler != NULL) {
+ NetTableEntry *NTE;
+ NDIS_HANDLE ConfigHandle = NULL;
+ int i;
+
+
+ for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
+ if ( !(IP_ADDR_EQUAL(NTE->nte_addr, NULL_IP_ADDR)) &&
+ !(IP_LOOPBACK_ADDR(NTE->nte_addr))
+ )
+ {
+ //
+ // Open a configuration key
+ //
+ if (!OpenIFConfig(&(NTE->nte_if->if_configname), &ConfigHandle))
+ {
+ //
+ // Not much we can do. The transports will have
+ // to handle this.
+ //
+ CTEAssert(ConfigHandle == NULL);
+ }
+
+ (* ((ULStatusProc) StatusHandler))(IP_HW_STATUS, IP_ADDR_ADDED,
+ NTE->nte_addr, NULL_IP_ADDR, NULL_IP_ADDR, 0, ConfigHandle );
+
+ if (ConfigHandle != NULL) {
+ CloseIFConfig(ConfigHandle);
+ ConfigHandle = NULL;
+ }
+ }
+ }
+ }
+
+#endif // SECFLTR
+#endif // _PNP_POWER
+
+ return PI;
+}
+
+//** IPSetMCastAddr - Set/Delete a multicast address.
+//
+// Called by an upper layer protocol or client to set or delete an IP multicast
+// address.
+//
+// Input: Address - Address to be set/deleted.
+// IF - IP Address of interface to set/delete on.
+// Action - TRUE if we're setting, FALSE if we're deleting.
+//
+// Returns: IP_STATUS of set/delete attempt.
+//
+IP_STATUS
+IPSetMCastAddr(IPAddr Address, IPAddr IF, uint Action)
+{
+ NetTableEntry *LocalNTE;
+
+ // Don't let him do this on the loopback address, since we don't have a
+ // route table entry for class D address on the loopback interface and
+ // we don't want a packet with a loopback source address to show up on
+ // the wire.
+ if (IP_LOOPBACK_ADDR(IF))
+ return IP_BAD_REQ;
+
+ for (LocalNTE = NetTableList; LocalNTE != NULL;
+ LocalNTE = LocalNTE->nte_next) {
+ if (LocalNTE != LoopNTE && ((LocalNTE->nte_flags & NTE_VALID) &&
+ (IP_ADDR_EQUAL(IF, NULL_IP_ADDR) ||
+ IP_ADDR_EQUAL(IF, LocalNTE->nte_addr))))
+ break;
+ }
+
+ if (LocalNTE == NULL) {
+ // Couldn't find a matching NTE.
+ return IP_BAD_REQ;
+ }
+
+ return IGMPAddrChange(LocalNTE, Address, Action ? IGMP_ADD : IGMP_DELETE);
+
+
+}
+
+//** IPGetAddrType - Return the type of a address.
+//
+// Called by the upper layer to determine the type of a remote address.
+//
+// Input: Address - The address in question.
+//
+// Returns: The DEST type of the address.
+//
+uchar
+IPGetAddrType(IPAddr Address)
+{
+ return GetAddrType(Address);
+}
+
+//** IPGetLocalMTU - Return the MTU for a local address
+//
+// Called by the upper layer to get the local MTU for a local address.
+//
+// Input: LocalAddr - Local address in question.
+// MTU - Where to return the local MTU.
+//
+// Returns: TRUE if we found the MTU, FALSE otherwise.
+//
+uchar
+IPGetLocalMTU(IPAddr LocalAddr, ushort *MTU)
+{
+ NetTableEntry *NTE;
+
+ for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
+ if (IP_ADDR_EQUAL(NTE->nte_addr, LocalAddr) &&
+ (NTE->nte_flags & NTE_VALID)) {
+ *MTU = NTE->nte_mss;
+ return TRUE;
+ }
+ }
+
+ // Special case in case the local address is a loopback address other than
+ // 127.0.0.1.
+ if (IP_LOOPBACK_ADDR(LocalAddr)) {
+ *MTU = LoopNTE->nte_mss;
+ return TRUE;
+ }
+
+ return FALSE;
+
+}
+
+//** IPUpdateRcvdOptions - Update options for use in replying.
+//
+// A routine to update options for use in a reply. We reverse any source route options,
+// and optionally update the record route option. We also return the index into the
+// options of the record route options (if we find one). The options are assumed to be
+// correct - no validation is performed on them. We fill in the caller provided
+// IPOptInfo with the new option buffer.
+//
+// Input: Options - Pointer to option info structure with buffer to be reversed.
+// NewOptions - Pointer to option info structure to be filled in.
+// Src - Source address of datagram that generated the options.
+// LocalAddr - Local address responding. If this != NULL_IP_ADDR, then
+// record route and timestamp options will be updated with this
+// address.
+//
+//
+// Returns: Index into options of record route option, if any.
+//
+IP_STATUS
+IPUpdateRcvdOptions(IPOptInfo *OldOptions, IPOptInfo *NewOptions, IPAddr Src, IPAddr LocalAddr)
+{
+ uchar Length, Ptr;
+ uchar i; // Index variable
+ IPAddr UNALIGNED *LastAddr; // First address in route.
+ IPAddr UNALIGNED *FirstAddr; // Last address in route.
+ IPAddr TempAddr; // Temp used in exchange.
+ uchar *Options, OptLength;
+ OptIndex Index; // Optindex used by UpdateOptions.
+
+ Options = CTEAllocMem(OptLength = OldOptions->ioi_optlength);
+
+ if (!Options)
+ return IP_NO_RESOURCES;
+
+ CTEMemCopy(Options, OldOptions->ioi_options, OptLength);
+ Index.oi_srindex = MAX_OPT_SIZE;
+ Index.oi_rrindex = MAX_OPT_SIZE;
+ Index.oi_tsindex = MAX_OPT_SIZE;
+
+ NewOptions->ioi_flags &= ~IP_FLAG_SSRR;
+
+ i = 0;
+ while(i < OptLength) {
+ if (Options[i] == IP_OPT_EOL)
+ break;
+
+ if (Options[i] == IP_OPT_NOP) {
+ i++;
+ continue;
+ }
+
+ Length = Options[i+IP_OPT_LENGTH];
+ switch (Options[i]) {
+ case IP_OPT_SSRR:
+ NewOptions->ioi_flags |= IP_FLAG_SSRR;
+ case IP_OPT_LSRR:
+ // Have a source route. We save the last gateway we came through as
+ // the new address, reverse the list, shift the list forward one address,
+ // and set the Src address as the last gateway in the list.
+
+ // First, check for an empty source route. If the SR is empty
+ // we'll skip most of this.
+ if (Length != (MIN_RT_PTR - 1)) {
+ // A non empty source route.
+ // First reverse the list in place.
+ Ptr = Options[i+IP_OPT_PTR] - 1 - sizeof(IPAddr);
+ LastAddr = (IPAddr *)(&Options[i + Ptr]);
+ FirstAddr = (IPAddr *)(&Options[i + IP_OPT_PTR + 1]);
+ NewOptions->ioi_addr = *LastAddr; // Save Last address as
+ // first hop of new route.
+ while (LastAddr > FirstAddr) {
+ TempAddr = *LastAddr;
+ *LastAddr-- = *FirstAddr;
+ *FirstAddr++ = TempAddr;
+ }
+
+ // Shift the list forward one address. We'll copy all but
+ // one IP address.
+ CTEMemCopy(&Options[i + IP_OPT_PTR + 1],
+ &Options[i + IP_OPT_PTR + 1 + sizeof(IPAddr)],
+ Length - (sizeof(IPAddr) + (MIN_RT_PTR -1)));
+
+ // Set source as last address of route.
+ *(IPAddr UNALIGNED *)(&Options[i + Ptr]) = Src;
+ }
+
+ Options[i+IP_OPT_PTR] = MIN_RT_PTR; // Set pointer to min legal value.
+ i += Length;
+ break;
+ case IP_OPT_RR:
+ // Save the index in case LocalAddr is specified. If it isn't specified,
+ // reset the pointer and zero the option.
+ Index.oi_rrindex = i;
+ if (LocalAddr == NULL_IP_ADDR) {
+ CTEMemSet(&Options[i+MIN_RT_PTR-1], 0, Length - (MIN_RT_PTR-1));
+ Options[i+IP_OPT_PTR] = MIN_RT_PTR;
+ }
+ i += Length;
+ break;
+ case IP_OPT_TS:
+ Index.oi_tsindex = i;
+
+ // We have a timestamp option. If we're not going to update, reinitialize
+ // it for next time. For the 'unspecified' options, just zero the buffer.
+ // For the 'specified' options, we need to zero the timestamps without
+ // zeroing the specified addresses.
+ if (LocalAddr == NULL_IP_ADDR) { // Not going to update, reinitialize.
+ uchar Flags;
+
+ Options[i+IP_OPT_PTR] = MIN_TS_PTR; // Reinitialize pointer.
+ Flags = Options[i+IP_TS_OVFLAGS] & IP_TS_FLMASK; // Get option type.
+ Options[i+IP_TS_OVFLAGS] = Flags; // Clear overflow count.
+ switch (Flags) {
+ uchar j;
+ ulong UNALIGNED *TSPtr;
+
+ // The unspecified types. Just clear the buffer.
+ case TS_REC_TS:
+ case TS_REC_ADDR:
+ CTEMemSet(&Options[i+MIN_TS_PTR-1], 0, Length - (MIN_TS_PTR-1));
+ break;
+
+ // We have a list of addresses specified. Just clear the timestamps.
+ case TS_REC_SPEC:
+ // j starts off as the offset in bytes from start of buffer to
+ // first timestamp.
+ j = MIN_TS_PTR-1+sizeof(IPAddr);
+ // TSPtr points at timestamp.
+ TSPtr = (ulong UNALIGNED *)&Options[i+j];
+
+ // Now j is offset of end of timestamp being zeroed.
+ j += sizeof(ulong);
+ while (j <= Length) {
+ *TSPtr++ = 0;
+ j += sizeof(ulong);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ i += Length;
+ break;
+
+ default:
+ i += Length;
+ break;
+ }
+
+ }
+
+ if (LocalAddr != NULL_IP_ADDR) {
+ UpdateOptions(Options, &Index, LocalAddr);
+ }
+
+ NewOptions->ioi_optlength = OptLength;
+ NewOptions->ioi_options = Options;
+ return IP_SUCCESS;
+
+}
+
+//* ValidRouteOption - Validate a source or record route option.
+//
+// Called to validate that a user provided source or record route option is good.
+//
+// Entry: Option - Pointer to option to be checked.
+// NumAddr - NumAddr that need to fit in option.
+// BufSize - Maximum size of option.
+//
+// Returns: 1 if option is good, 0 if not.
+//
+uchar
+ValidRouteOption(uchar *Option, uint NumAddr, uint BufSize)
+{
+ if (Option[IP_OPT_LENGTH] < (3 + (sizeof(IPAddr)*NumAddr)) ||
+ Option[IP_OPT_LENGTH] > BufSize ||
+ ((Option[IP_OPT_LENGTH] - 3) % sizeof(IPAddr))) // Routing options is too small.
+ return 0;
+
+ if (Option[IP_OPT_PTR] != MIN_RT_PTR) // Pointer isn't correct.
+ return 0;
+
+ return 1;
+}
+
+//** IPInitOptions - Initialize an option buffer.
+//
+// Called by an upper layer routine to initialize an option buffer. We fill
+// in the default values for TTL, TOS, and flags, and NULL out the options
+// buffer and size.
+//
+// Input: Options - Pointer to IPOptInfo structure.
+//
+// Returns: Nothing.
+//
+void
+IPInitOptions(IPOptInfo *Options)
+{
+ Options->ioi_addr = NULL_IP_ADDR;
+
+ Options->ioi_ttl = (uchar)DefaultTTL;
+ Options->ioi_tos = (uchar)DefaultTOS;
+ Options->ioi_flags = 0;
+
+ Options->ioi_options = (uchar *)NULL;
+ Options->ioi_optlength = 0;
+
+}
+
+//** IPCopyOptions - Copy the user's options into IP header format.
+//
+// This routine takes an option buffer supplied by an IP client, validates it, and
+// creates an IPOptInfo structure that can be passed to the IP layer for transmission. This
+// includes allocating a buffer for the options, munging any source route
+// information into the real IP format.
+//
+// Note that we never lock this structure while we're using it. This may cause transitory
+// incosistencies while the structure is being updated if it is in use during the update.
+// This shouldn't be a problem - a packet or too might get misrouted, but it should
+// straighten itself out quickly. If this is a problem the client should make sure not
+// to call this routine while it's in the IPTransmit routine.
+//
+// Entry: Options - Pointer to buffer of user supplied options.
+// Size - Size in bytes of option buffer
+// OptInfoPtr - Pointer to IPOptInfo structure to be filled in.
+//
+// Returns: A status, indicating whether or not the options were valid and copied.
+//
+IP_STATUS
+IPCopyOptions(uchar *Options, uint Size, IPOptInfo *OptInfoPtr)
+{
+ uchar *TempOptions; // Buffer of options we'll build
+ uint TempSize; // Size of options.
+ IP_STATUS TempStatus; // Temporary status
+ uchar OptSeen = 0; // Indicates which options we've seen.
+
+
+ OptInfoPtr->ioi_addr = NULL_IP_ADDR;
+
+ OptInfoPtr->ioi_flags &= ~IP_FLAG_SSRR;
+
+ if (Size == 0) {
+ CTEAssert(FALSE);
+ OptInfoPtr->ioi_options = (uchar *)NULL;
+ OptInfoPtr->ioi_optlength = 0;
+ return IP_SUCCESS;
+ }
+
+
+ // Option size needs to be rounded to multiple of 4.
+ if ((TempOptions = CTEAllocMem(((Size & 3) ? (Size & ~3) + 4 : Size))) == (uchar *)NULL)
+ return IP_NO_RESOURCES; // Couldn't get a buffer, return error.
+
+ CTEMemSet(TempOptions, 0, ((Size & 3) ? (Size & ~3) + 4 : Size));
+
+ // OK, we have a buffer. Loop through the provided buffer, copying options.
+ TempSize = 0;
+ TempStatus = IP_PENDING;
+ while (Size && TempStatus == IP_PENDING) {
+ uint SRSize; // Size of a source route option.
+
+ switch (*Options) {
+ case IP_OPT_EOL:
+ TempStatus = IP_SUCCESS;
+ break;
+ case IP_OPT_NOP:
+ TempOptions[TempSize++] = *Options++;
+ Size--;
+ break;
+ case IP_OPT_SSRR:
+ if (OptSeen & (OPT_LSRR | OPT_SSRR)) {
+ TempStatus = IP_BAD_OPTION; // We've already seen a record route.
+ break;
+ }
+ OptInfoPtr->ioi_flags |= IP_FLAG_SSRR;
+ OptSeen |= OPT_SSRR; // Fall through to LSRR code.
+ case IP_OPT_LSRR:
+ if ( (*Options == IP_OPT_LSRR) &&
+ (OptSeen & (OPT_LSRR | OPT_SSRR))
+ ) {
+ TempStatus = IP_BAD_OPTION; // We've already seen a record route.
+ break;
+ }
+ if (*Options == IP_OPT_LSRR)
+ OptSeen |= OPT_LSRR;
+ if (!ValidRouteOption(Options, 2, Size)) {
+ TempStatus = IP_BAD_OPTION;
+ break;
+ }
+
+ // Option is valid. Copy the first hop address to NewAddr, and move all
+ // of the other addresses forward.
+ TempOptions[TempSize++] = *Options++; // Copy option type.
+ SRSize = *Options++;
+ Size -= SRSize;
+ SRSize -= sizeof(IPAddr);
+ TempOptions[TempSize++] = SRSize;
+ TempOptions[TempSize++] = *Options++; // Copy pointer.
+ OptInfoPtr->ioi_addr = *(IPAddr UNALIGNED *)Options;
+ Options += sizeof(IPAddr); // Point to address beyond first hop.
+ CTEMemCopy(&TempOptions[TempSize], Options, SRSize - 3);
+ TempSize += (SRSize - 3);
+ Options += (SRSize - 3);
+ break;
+ case IP_OPT_RR:
+ if (OptSeen & OPT_RR) {
+ TempStatus = IP_BAD_OPTION; // We've already seen a record route.
+ break;
+ }
+ OptSeen |= OPT_RR;
+ if (!ValidRouteOption(Options, 1, Size)) {
+ TempStatus = IP_BAD_OPTION;
+ break;
+ }
+ SRSize = Options[IP_OPT_LENGTH];
+ CTEMemCopy(&TempOptions[TempSize], Options, SRSize);
+ TempSize += SRSize;
+ Options += SRSize;
+ Size -= SRSize;
+ break;
+ case IP_OPT_TS:
+ {
+ uchar Overflow, Flags;
+
+ if (OptSeen & OPT_TS) {
+ TempStatus = IP_BAD_OPTION; // We've already seen a time stamp
+ break;
+ }
+ OptSeen |= OPT_TS;
+ Flags = Options[IP_TS_OVFLAGS] & IP_TS_FLMASK;
+ Overflow = (Options[IP_TS_OVFLAGS] & IP_TS_OVMASK) >> 4;
+
+ if (Overflow || (Flags != TS_REC_TS && Flags != TS_REC_ADDR &&
+ Flags != TS_REC_SPEC)) {
+ TempStatus = IP_BAD_OPTION; // Bad flags or overflow value.
+ break;
+ }
+
+ SRSize = Options[IP_OPT_LENGTH];
+ if (SRSize > Size || SRSize < 8 ||
+ Options[IP_OPT_PTR] != MIN_TS_PTR) {
+ TempStatus = IP_BAD_OPTION; // Option size isn't good.
+ break;
+ }
+ CTEMemCopy(&TempOptions[TempSize], Options, SRSize);
+ TempSize += SRSize;
+ Options += SRSize;
+ Size -= SRSize;
+ }
+ break;
+ default:
+ TempStatus = IP_BAD_OPTION; // Unknown option, error.
+ break;
+ }
+ }
+
+ if (TempStatus == IP_PENDING) // We broke because we hit the end of the buffer.
+ TempStatus = IP_SUCCESS; // that's OK.
+
+ if (TempStatus != IP_SUCCESS) { // We had some sort of an error.
+ CTEFreeMem(TempOptions);
+ return TempStatus;
+ }
+
+ // Check the option size here to see if it's too big. We check it here at the end
+ // instead of at the start because the option size may shrink if there are source route
+ // options, and we don't want to accidentally error out a valid option.
+ TempSize = (TempSize & 3 ? (TempSize & ~3) + 4 : TempSize);
+ if (TempSize > MAX_OPT_SIZE) {
+ CTEFreeMem(TempOptions);
+ return IP_OPTION_TOO_BIG;
+ }
+ OptInfoPtr->ioi_options = TempOptions;
+ OptInfoPtr->ioi_optlength = TempSize;
+
+ return IP_SUCCESS;
+
+}
+
+//** IPFreeOptions - Free options we're done with.
+//
+// Called by the upper layer when we're done with options. All we need to do is free
+// the options.
+//
+// Input: OptInfoPtr - Pointer to IPOptInfo structure to be freed.
+//
+// Returns: Status of attempt to free options.
+//
+IP_STATUS
+IPFreeOptions(IPOptInfo *OptInfoPtr)
+{
+ if (OptInfoPtr->ioi_options) {
+ // We have options to free. Save the pointer and zero the structure field before
+ // freeing the memory to try and present race conditions with it's use.
+ uchar *TempPtr = OptInfoPtr->ioi_options;
+
+ OptInfoPtr->ioi_options = (uchar *)NULL;
+ CTEFreeMem(TempPtr);
+ OptInfoPtr->ioi_optlength = 0;
+ OptInfoPtr->ioi_addr = NULL_IP_ADDR;
+ OptInfoPtr->ioi_flags &= ~IP_FLAG_SSRR;
+ }
+ return IP_SUCCESS;
+}
+
+
+//BUGBUG - After we're done testing, move BEGIN_INIT up here.
+
+//** ipgetinfo - Return pointers to our NetInfo structures.
+//
+// Called by upper layer software during init. time. The caller
+// passes a buffer, which we fill in with pointers to NetInfo
+// structures.
+//
+// Entry:
+// Buffer - Pointer to buffer to be filled in.
+// Size - Size in bytes of buffer.
+//
+// Returns:
+// Status of command.
+//
+IP_STATUS
+IPGetInfo(IPInfo *Buffer, int Size)
+{
+ if (Size < sizeof(IPInfo))
+ return IP_BUF_TOO_SMALL; // Not enough buffer space.
+
+ Buffer->ipi_version = IP_DRIVER_VERSION;
+ Buffer->ipi_hsize = sizeof(IPHeader);
+ Buffer->ipi_xmit = IPTransmit;
+ Buffer->ipi_protreg = IPRegisterProtocol;
+ Buffer->ipi_openrce = OpenRCE;
+ Buffer->ipi_closerce = CloseRCE;
+ Buffer->ipi_getaddrtype = IPGetAddrType;
+ Buffer->ipi_getlocalmtu = IPGetLocalMTU;
+ Buffer->ipi_getpinfo = IPGetPInfo;
+ Buffer->ipi_checkroute = IPCheckRoute;
+ Buffer->ipi_initopts = IPInitOptions;
+ Buffer->ipi_updateopts = IPUpdateRcvdOptions;
+ Buffer->ipi_copyopts = IPCopyOptions;
+ Buffer->ipi_freeopts = IPFreeOptions;
+ Buffer->ipi_qinfo = IPQueryInfo;
+ Buffer->ipi_setinfo = IPSetInfo;
+ Buffer->ipi_getelist = IPGetEList;
+ Buffer->ipi_setmcastaddr = IPSetMCastAddr;
+ Buffer->ipi_invalidsrc = InvalidSourceAddress;
+ Buffer->ipi_isdhcpinterface = IsDHCPInterface;
+
+ return IP_SUCCESS;
+
+}
+
+//** IPTimeout - IP timeout handler.
+//
+// The timeout routine called periodically to time out various things, such as entries
+// being reassembled and ICMP echo requests.
+//
+// Entry: Timer - Timer being fired.
+// Context - Pointer to NTE being time out.
+//
+// Returns: Nothing.
+//
+void
+IPTimeout(CTEEvent *Timer, void *Context)
+{
+ NetTableEntry *NTE = STRUCT_OF(NetTableEntry, Timer, nte_timer);
+ CTELockHandle NTEHandle;
+ ReassemblyHeader *PrevRH, *CurrentRH, *TempList = (ReassemblyHeader *)NULL;
+
+ ICMPTimer(NTE);
+ IGMPTimer(NTE);
+ if (Context) {
+ CTEGetLock(&NTE->nte_lock, &NTEHandle);
+ PrevRH = STRUCT_OF(ReassemblyHeader, &NTE->nte_ralist, rh_next);
+ CurrentRH = PrevRH->rh_next;
+ while (CurrentRH) {
+ if (--CurrentRH->rh_ttl == 0) { // This guy timed out.
+ PrevRH->rh_next = CurrentRH->rh_next; // Take him out.
+ CurrentRH->rh_next = TempList; // And save him for later.
+ TempList = CurrentRH;
+ IPSInfo.ipsi_reasmfails++;
+ } else
+ PrevRH = CurrentRH;
+
+ CurrentRH = PrevRH->rh_next;
+ }
+
+ // We've run the list. If we need to free anything, do it now. This may
+ // include sending an ICMP message.
+ CTEFreeLock(&NTE->nte_lock, NTEHandle);
+ while (TempList) {
+ CurrentRH = TempList;
+ TempList = CurrentRH->rh_next;
+ // If this wasn't sent to a bcast address and we already have the first fragment,
+ // send a time exceeded message.
+ if (CurrentRH->rh_headersize != 0)
+ SendICMPErr(NTE->nte_addr, (IPHeader *)CurrentRH->rh_header, ICMP_TIME_EXCEED,
+ TTL_IN_REASSEM, 0);
+ FreeRH(CurrentRH);
+ }
+
+ CTEStartTimer(&NTE->nte_timer, IP_TIMEOUT, IPTimeout, NULL);
+ } else
+ CTEStartTimer(&NTE->nte_timer, IP_TIMEOUT, IPTimeout, NTE);
+
+}
+
+//* IPpSetNTEAddr - Set the IP address of an NTE.
+//
+// Called by the DHCP client to set or delete the IP address of an NTE. We
+// make sure he's specifiying a valid NTE, then mark it up or down as needed,
+// notify the upper layers of the change if necessary, and then muck with
+// the routing tables.
+//
+// Input: Context - Context of NTE to alter.
+// Addr - IP address to set.
+// Mask - Subnet mask for Addr.
+//
+// Returns: TRUE if we changed the address, FALSE otherwise.
+//
+IP_STATUS
+IPpSetNTEAddr(NetTableEntry *NTE, IPAddr Addr, IPMask Mask,
+ CTELockHandle *RouteTableHandle, SetAddrControl *ControlBlock, SetAddrRtn Rtn)
+{
+ Interface *IF;
+ uint (*CallFunc)(struct RouteTableEntry *, void *, void *);
+
+ IF = NTE->nte_if;
+ DHCPActivityCount++;
+
+ if (IP_ADDR_EQUAL(Addr, NULL_IP_ADDR)) {
+ // We're deleting an address.
+ if (NTE->nte_flags & NTE_VALID) {
+ // The address is currently valid. Fix that.
+
+ NTE->nte_flags &= ~NTE_VALID;
+
+ //
+ // If the old address is in the ATCache, flush it out.
+ //
+ FlushATCache(NTE->nte_addr);
+
+ if (--(IF->if_ntecount) == 0) {
+ // This is the last one, so we'll need to delete relevant
+ // routes.
+ CallFunc = DeleteRTEOnIF;
+ } else
+ CallFunc = InvalidateRCEOnIF;
+
+ CTEFreeLock(&RouteTableLock, *RouteTableHandle);
+
+ StopIGMPForNTE(NTE);
+
+ // Now call the upper layers, and tell them that address is
+ // gone. We really need to do something about locking here.
+#ifdef _PNP_POWER
+
+ NotifyAddrChange(NTE->nte_addr, NTE->nte_mask, NTE->nte_pnpcontext,
+ NTE->nte_context, &NTE->nte_addrhandle, NULL, FALSE);
+
+#else // _PNP_POWER
+
+ NotifyAddrChange(NTE->nte_addr, NTE->nte_mask, NULL,
+ NTE->nte_context, NULL, NULL, FALSE);
+
+#endif // _PNP_POWER
+
+ // Call RTWalk to take the appropriate action on the RTEs.
+ RTWalk(CallFunc, IF, NULL);
+
+ // Delete the route to the address itself.
+ DeleteRoute(NTE->nte_addr, HOST_MASK, IPADDR_LOCAL,
+ LoopNTE->nte_if);
+
+ // Tell the lower interface this address is gone.
+ (*IF->if_deladdr)(IF->if_lcontext, LLIP_ADDR_LOCAL, NTE->nte_addr,
+ NULL_IP_ADDR);
+
+ CTEGetLock(&RouteTableLock, RouteTableHandle);
+ }
+
+ DHCPActivityCount--;
+ CTEFreeLock(&RouteTableLock, *RouteTableHandle);
+ return IP_SUCCESS;
+ } else {
+ uint Status;
+
+ // We're not deleting, we're setting the address.
+ if (!(NTE->nte_flags & NTE_VALID)) {
+ uint index;
+
+ // The address is invalid. Save the info, mark him as valid,
+ // and add the routes.
+ NTE->nte_addr = Addr;
+ NTE->nte_mask = Mask;
+ NTE->nte_flags |= NTE_VALID;
+ IF->if_ntecount++;
+ index = IF->if_index;
+
+ //
+ // If the new address is in the ATCache, flush it out, otherwise
+ // TdiOpenAddress may fail.
+ //
+ FlushATCache(Addr);
+
+ CTEFreeLock(&RouteTableLock, *RouteTableHandle);
+
+ if (AddNTERoutes(NTE))
+ Status = TRUE;
+ else
+ Status = FALSE;
+
+ // Need to tell the lower layer about it.
+ if (Status) {
+ Interface *IF = NTE->nte_if;
+
+ ControlBlock->sac_rtn = Rtn;
+ Status = (*IF->if_addaddr)(IF->if_lcontext, LLIP_ADDR_LOCAL,
+ Addr, Mask, ControlBlock );
+ }
+
+ if (Status == FALSE) {
+ // Couldn't add the routes. Recurively mark this NTE as down.
+ IPSetNTEAddr(NTE->nte_context, NULL_IP_ADDR, 0, NULL, NULL);
+ } else {
+ InitIGMPForNTE(NTE);
+
+ // Now call the upper layers, and tell them that address is
+ // is here. We really need to do something about locking here.
+#ifdef _PNP_POWER
+
+#ifdef SECFLTR
+ NotifyAddrChange(NTE->nte_addr, NTE->nte_mask,
+ NTE->nte_pnpcontext, NTE->nte_context, &NTE->nte_addrhandle,
+ &(IF->if_configname), TRUE);
+
+#else // SECFLTR
+
+ NotifyAddrChange(NTE->nte_addr, NTE->nte_mask,
+ NTE->nte_pnpcontext, NTE->nte_context, &NTE->nte_addrhandle,
+ NULL, TRUE);
+#endif // SECFLTR
+
+#else // _PNP_POWER
+
+#ifdef SECFLTR
+
+ NotifyAddrChange(NTE->nte_addr, NTE->nte_mask, NULL,
+ NTE->nte_context, NULL, &(IF->if_configname), TRUE);
+
+#else // SECFLTR
+
+ NotifyAddrChange(NTE->nte_addr, NTE->nte_mask, NULL,
+ NTE->nte_context, NULL, NULL, TRUE);
+
+#endif // SECFLTR
+#endif // _PNP_POWER
+
+#ifdef NT
+ if (!IP_ADDR_EQUAL(Addr, NULL_IP_ADDR)) {
+ SetPersistentRoutesForNTE(
+ net_long(Addr),
+ net_long(Mask),
+ index
+ );
+ }
+#endif // NT
+
+ if ( (Status != IP_PENDING) && (Rtn != NULL) ) {
+ (*Rtn)(ControlBlock, IP_SUCCESS);
+ }
+ }
+
+ CTEGetLock(&RouteTableLock, RouteTableHandle);
+ NTE->nte_rtrdisccount = MAX_SOLICITATION_DELAY;
+ NTE->nte_rtrdiscstate = NTE_RTRDISC_DELAYING;
+ } else
+ Status = FALSE;
+
+ DHCPActivityCount--;
+ CTEFreeLock(&RouteTableLock, *RouteTableHandle);
+ if (Status) {
+ return IP_PENDING;
+ } else {
+ return IP_GENERAL_FAILURE;
+ }
+ }
+}
+
+//* IPSetNTEAddr - Set the IP address of an NTE.
+//
+// Wrapper routine for IPpSetNTEAddr
+//
+// Input: Context - Context of NTE to alter.
+// Addr - IP address to set.
+// Mask - Subnet mask for Addr.
+//
+// Returns: TRUE if we changed the address, FALSE otherwise.
+//
+uint
+IPSetNTEAddr(ushort Context, IPAddr Addr, IPMask Mask, SetAddrControl *ControlBlock, SetAddrRtn Rtn)
+{
+ CTELockHandle Handle;
+ uint Status;
+ NetTableEntry *NTE;
+
+
+ CTEGetLock(&RouteTableLock, &Handle);
+
+ for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next)
+ if (NTE->nte_context == Context)
+ break;
+
+ if (NTE == NULL || NTE == LoopNTE) {
+ // Can't alter the loopback NTE, or one we didn't find.
+ CTEFreeLock(&RouteTableLock, Handle);
+ return IP_GENERAL_FAILURE;
+ }
+
+ Status = IPpSetNTEAddr(NTE, Addr, Mask, &Handle, ControlBlock, Rtn);
+
+ return(Status);
+}
+
+
+#pragma BEGIN_INIT
+
+extern NetTableEntry *InitLoopback(IPConfigInfo *);
+
+//** InitTimestamp - Intialize the timestamp for outgoing packets.
+//
+// Called at initialization time to setup our first timestamp. The timestamp we use
+// is the in ms since midnite GMT at which the system started.
+//
+// Input: Nothing.
+//
+// Returns: Nothing.
+//
+void
+InitTimestamp()
+{
+ ulong GMTDelta; // Delta in ms from GMT.
+ ulong Now; // Milliseconds since midnight.
+
+ TimeStamp = 0;
+
+ if ((GMTDelta = GetGMTDelta()) == 0xffffffff) { // Had some sort of error.
+ TSFlag = 0x80000000;
+ return;
+ }
+
+ if ((Now = GetTime()) > (24L*3600L*1000L)) { // Couldn't get time since midnight.
+ TSFlag = net_long(0x80000000);
+ return;
+ }
+
+ TimeStamp = Now + GMTDelta - CTESystemUpTime();
+ TSFlag = 0;
+
+}
+#pragma END_INIT
+
+#ifndef CHICAGO
+#pragma BEGIN_INIT
+#else
+#pragma code_seg("_LTEXT", "LCODE")
+#endif
+
+//** InitNTE - Initialize an NTE.
+//
+// This routine is called during initialization to initialize an NTE. We
+// allocate memory, NDIS resources, etc.
+//
+//
+// Entry: NTE - Pointer to NTE to be initalized.
+//
+// Returns: 0 if initialization failed, non-zero if it succeeds.
+//
+int
+InitNTE(NetTableEntry *NTE)
+{
+ Interface *IF;
+ NetTableEntry *PrevNTE;
+
+ NTE->nte_ralist = NULL;
+ NTE->nte_echolist = NULL;
+
+ //
+ // Taken together, the context and instance numbers uniquely identify
+ // a network entry, even across boots of the system. The instance number
+ // will have to become dynamic if contexts are ever reused.
+ //
+ NTE->nte_context = NextNTEContext++;
+ NTE->nte_rtrlist = NULL;
+ NTE->nte_instance = GetUnique32BitValue();
+
+ // Now link him on the IF chain, and bump the count.
+ IF = NTE->nte_if;
+ PrevNTE = STRUCT_OF(NetTableEntry, &IF->if_nte, nte_ifnext);
+ while (PrevNTE->nte_ifnext != NULL)
+ PrevNTE = PrevNTE->nte_ifnext;
+
+ PrevNTE->nte_ifnext = NTE;
+ NTE->nte_ifnext = NULL;
+
+ if (NTE->nte_flags & NTE_VALID) {
+ IF->if_ntecount++;
+ }
+
+ CTEInitTimer(&NTE->nte_timer);
+ CTEStartTimer(&NTE->nte_timer, IP_TIMEOUT, IPTimeout, (void *)NULL);
+ return TRUE;
+}
+
+//** InitInterface - Initialize with an interface.
+//
+// Called when we need to initialize with an interface. We set the appropriate NTE
+// info, then register our local address and any appropriate broadcast addresses
+// with the interface. We assume the NTE being initialized already has an interface
+// pointer set up for it. We also allocate at least one TD buffer for use on the interface.
+//
+// Input: NTE - NTE to initialize with the interface.
+//
+// Returns: TRUE is we succeeded, FALSE if we fail.
+//
+int
+InitInterface(NetTableEntry *NTE)
+{
+ IPMask netmask = IPNetMask(NTE->nte_addr);
+ uchar *TDBuffer; // Pointer to tdbuffer
+ PNDIS_PACKET Packet;
+ NDIS_HANDLE TDbpool; // Handle for TD buffer pool.
+ NDIS_HANDLE TDppool;
+ PNDIS_BUFFER TDBufDesc; // Buffer descriptor for TDBuffer.
+ NDIS_STATUS Status;
+ Interface *IF; // Interface for this NTE.
+ CTELockHandle Handle;
+
+
+ IF = NTE->nte_if;
+
+ CTEAssert(NTE->nte_mss > sizeof(IPHeader));
+ CTEAssert(IF->if_mtu > 0);
+
+ NTE->nte_mss = MIN((NTE->nte_mss - sizeof(IPHeader)), IF->if_mtu);
+
+ CTERefillMem();
+
+ // Allocate resources needed for xfer data calls. The TD buffer has to be as large
+ // as any frame that can be received, even though our MSS may be smaller, because we
+ // can't control what might be sent at us.
+ TDBuffer = CTEAllocMem(IF->if_mtu);
+ if (TDBuffer == (uchar *)NULL)
+ return FALSE;
+
+ NdisAllocatePacketPool(&Status, &TDppool, 1, sizeof(TDContext));
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ CTEFreeMem(TDBuffer);
+ return FALSE;
+ }
+
+ NdisAllocatePacket(&Status, &Packet, TDppool);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ NdisFreePacketPool(TDppool);
+ CTEFreeMem(TDBuffer);
+ return FALSE;
+ }
+
+ CTEMemSet(Packet->ProtocolReserved, 0, sizeof(TDContext));
+
+ NdisAllocateBufferPool(&Status, &TDbpool, 1);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ NdisFreePacketPool(TDppool);
+ CTEFreeMem(TDBuffer);
+ return FALSE;
+ }
+
+ NdisAllocateBuffer(&Status,&TDBufDesc, TDbpool, TDBuffer,
+ (IF->if_mtu + sizeof(IPHeader)));
+ if (Status != NDIS_STATUS_SUCCESS) {
+ NdisFreeBufferPool(TDbpool);
+ NdisFreePacketPool(TDppool);
+ CTEFreeMem(TDBuffer);
+ return FALSE;
+ }
+
+ NdisChainBufferAtFront(Packet, TDBufDesc);
+
+ ((TDContext *)Packet->ProtocolReserved)->tdc_buffer = TDBuffer;
+
+
+ if (NTE->nte_flags & NTE_VALID) {
+
+ // Add our local IP address.
+ if (!(*IF->if_addaddr)(IF->if_lcontext, LLIP_ADDR_LOCAL,
+ NTE->nte_addr, NTE->nte_mask, NULL)) {
+ NdisFreeBufferPool(TDbpool);
+ NdisFreePacketPool(TDppool);
+ CTEFreeMem(TDBuffer);
+ return FALSE; // Couldn't add local address.
+ }
+ }
+
+ // Set up the broadcast addresses for this interface, iff we're the
+ // 'primary' NTE on the interface.
+ if (NTE->nte_flags & NTE_PRIMARY) {
+
+ if (!(*IF->if_addaddr)(IF->if_lcontext, LLIP_ADDR_BCAST,
+ NTE->nte_if->if_bcast, 0, NULL)) {
+ NdisFreeBufferPool(TDbpool);
+ NdisFreePacketPool(TDppool);
+ CTEFreeMem(TDBuffer);
+ return FALSE; // Couldn't add broadcast address.
+ }
+ }
+
+ if (IF->if_llipflags & LIP_COPY_FLAG) {
+ NTE->nte_flags |= NTE_COPY;
+ }
+
+ CTEGetLock(&IF->if_lock, &Handle);
+ ((TDContext *)Packet->ProtocolReserved)->tdc_common.pc_link = IF->if_tdpacket;
+ IF->if_tdpacket = Packet;
+ CTEFreeLock(&IF->if_lock, Handle);
+
+ return TRUE;
+}
+
+#ifndef _PNP_POWER
+//* CleanAdaptTable - Clean up the adapter name table.
+//
+//
+void
+CleanAdaptTable()
+{
+ int i = 0;
+
+ while (AdptNameTable[i].nm_arpinfo != NULL) {
+ CTEFreeMem(AdptNameTable[i].nm_arpinfo);
+ CTEFreeString(&AdptNameTable[i].nm_name);
+ if (AdptNameTable[i].nm_driver.Buffer != NULL)
+ CTEFreeString(&AdptNameTable[i].nm_driver);
+ i++;
+ }
+}
+
+
+//* OpenAdapters - Clean up the adapter name table.
+//
+// Used at the end of initialization. We loop through and 'open' all the adapters.
+//
+// Input: Nothing.
+//
+// Returns: Nothing.
+//
+void
+OpenAdapters()
+{
+ int i = 0;
+ LLIPBindInfo *ABI;
+
+ while ((ABI = AdptNameTable[i++].nm_arpinfo) != NULL) {
+ (*(ABI->lip_open))(ABI->lip_context);
+ }
+}
+
+
+//* IPRegisterDriver - Called during init time to register a driver.
+//
+// Called during init time when we have a non-LAN (or non-ARPable) driver
+// that wants to register with us. We try to find a free slot in the table
+// to register him.
+//
+// Input: Name - Pointer to the name of the driver to be registered.
+// Ptr - Pointer to driver's registration function.
+//
+// Returns: TRUE if we succeeded, FALSE if we fail.
+//
+uint
+IPRegisterDriver(PNDIS_STRING Name, LLIPRegRtn Ptr)
+{
+ uint i;
+
+ CTERefillMem();
+
+ // First, find a slot for him.
+ for (i = 0; i < MaxIPNets; i++) {
+ if (DriverNameTable[i].drm_driver.Buffer == NULL) {
+ // Found a slot. Try and allocate and copy a string for him.
+ if (!CTEAllocateString(&DriverNameTable[i].drm_driver,
+ CTELengthString(Name)))
+ return FALSE;
+ // Got the space. Copy the string and the pointer.
+ CTECopyString(&DriverNameTable[i].drm_driver, Name);
+ DriverNameTable[i].drm_regptr = Ptr;
+ NumRegDrivers++;
+ return TRUE;
+ }
+ }
+
+
+}
+
+
+#ifdef NT
+
+//* GetLLRegPtr - Called during init time to get a lower driver's registration
+// routine.
+//
+// Called during init time to locate the registration function of a
+// non-LAN (or non-ARPable) driver.
+//
+// Input: Name - Pointer to the name of the driver to be registered.
+//
+// Returns: A pointer to the driver's registration routine or NULL on failure.
+//
+LLIPRegRtn
+GetLLRegPtr(PNDIS_STRING Name)
+{
+ NTSTATUS status;
+ PFILE_OBJECT fileObject;
+ PDEVICE_OBJECT deviceObject;
+ LLIPIF_REGISTRATION_DATA registrationData;
+ IO_STATUS_BLOCK ioStatusBlock;
+ PIRP irp;
+ KEVENT ioctlEvent;
+extern POBJECT_TYPE *IoDeviceObjectType;
+
+
+ registrationData.RegistrationFunction = NULL;
+
+ KeInitializeEvent(&ioctlEvent, SynchronizationEvent, FALSE);
+
+ status = IoGetDeviceObjectPointer(
+ Name,
+ SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
+ &fileObject,
+ &deviceObject
+ );
+
+ if (status != STATUS_SUCCESS) {
+ CTEPrint("IP failed to open the lower layer driver\n");
+ return(NULL);
+ }
+
+ //
+ // Reference the device object.
+ //
+ ObReferenceObject(deviceObject);
+
+ //
+ // IoGetDeviceObjectPointer put a reference on the file object.
+ //
+ ObDereferenceObject(fileObject);
+
+ irp = IoBuildDeviceIoControlRequest(
+ IOCTL_LLIPIF_REGISTER,
+ deviceObject,
+ NULL, // input Buffer
+ 0, // input buffer length
+ &registrationData,
+ sizeof(LLIPIF_REGISTRATION_DATA),
+ FALSE, // not an InternalDeviceControl
+ &ioctlEvent,
+ &ioStatusBlock
+ );
+
+ if (irp == NULL) {
+ ObDereferenceObject(deviceObject);
+ return(NULL);
+ }
+
+ status = IoCallDriver(deviceObject, irp);
+
+ if (status == STATUS_PENDING) {
+ status = KeWaitForSingleObject(
+ &ioctlEvent,
+ Executive,
+ KernelMode,
+ FALSE, // not alertable
+ NULL // no timeout
+ );
+
+ }
+
+ ObDereferenceObject(deviceObject);
+
+ if (status != STATUS_SUCCESS) {
+ return(NULL);
+ }
+
+ if (registrationData.RegistrationFunction != NULL) {
+ //
+ // Cache the driver registration for future reference.
+ //
+ IPRegisterDriver(Name, registrationData.RegistrationFunction);
+ }
+
+ return(registrationData.RegistrationFunction);
+
+} // GetLLRegPtr
+
+#endif // NT
+#endif // _PNP_POWER
+
+
+#ifndef _PNP_POWER
+
+//* FindRegPtr - Find a driver's registration routine.
+//
+// Called during init time when we have a non-LAN (or non-ARPable) driver to
+// register with. We take in the driver name, and try to find a registration
+// pointer for the driver.
+//
+// Input: Name - Pointer to the name of the driver to be found.
+//
+// Returns: Pointer to the registration routine, or NULL if there is none.
+//
+LLIPRegRtn
+FindRegPtr(PNDIS_STRING Name)
+{
+ uint i;
+
+ for (i = 0; i < NumRegDrivers; i++) {
+ if (CTEEqualString(&(DriverNameTable[i].drm_driver), Name))
+ return (LLIPRegRtn)(DriverNameTable[i].drm_regptr);
+ }
+
+#ifdef NT
+ //
+ // For NT, we open the lower driver and issue an IOCTL to get a pointer to
+ // its registration function. We then cache this in the table for future
+ // reference.
+ //
+ return(GetLLRegPtr(Name));
+#else
+ return NULL;
+#endif // NT
+}
+
+#endif // _PNP_POWER
+
+#ifdef CHICAGO
+#pragma BEGIN_INIT
+#endif
+
+//* FreeNets - Free nets we have allocated.
+//
+// Called during init time if initialization fails. We walk down our list
+// of nets, and free them.
+//
+// Input: Nothing.
+//
+// Returns: Nothing.
+//
+void
+FreeNets(void)
+{
+ NetTableEntry *NTE;
+
+ for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next)
+ CTEFreeMem(NTE);
+}
+
+#ifdef CHICAGO
+#pragma END_INIT
+#pragma code_seg("_LTEXT", "LCODE")
+#endif
+
+
+#ifdef _PNP_POWER
+
+extern uint GetGeneralIFConfig(IFGeneralConfig *GConfigInfo, NDIS_HANDLE Handle);
+extern IFAddrList *GetIFAddrList(uint *NumAddr, NDIS_HANDLE Handle);
+
+
+#ifdef CHICAGO
+
+extern void RequestDHCPAddr(ushort context);
+
+#define MAX_NOTIFY_CLIENTS 8
+
+typedef void (*AddrNotifyRtn)(IPAddr Addr, IPMask Mask, void *Context,
+ ushort IPContext, uint Added);
+
+AddrNotifyRtn AddrNotifyTable[MAX_NOTIFY_CLIENTS];
+
+typedef void (*InterfaceNotifyRtn)(ushort Context, uint Added);
+
+InterfaceNotifyRtn InterfaceNotifyTable[MAX_NOTIFY_CLIENTS];
+
+//* RegisterAddrNotify - Register an address notify routine.
+//
+// A routine called to register an address notify routine.
+//
+// Input: Rtn - Routine to register.
+// Register - True to register, False to deregister.
+//
+// Returns: TRUE if we succeed, FALSE if we don't/
+//
+uint
+RegisterAddrNotify(AddrNotifyRtn Rtn, uint Register)
+{
+ uint i;
+ AddrNotifyRtn NewRtn, OldRtn;
+
+ if (Register) {
+ NewRtn = Rtn;
+ OldRtn = NULL;
+ } else {
+ NewRtn = NULL;
+ OldRtn = Rtn;
+ }
+
+ for (i = 0; i < MAX_NOTIFY_CLIENTS; i++) {
+ if (AddrNotifyTable[i] == OldRtn) {
+ AddrNotifyTable[i] = NewRtn;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+//* NotifyInterfaceChange - Notify clients of a change in an interface.
+//
+// Called when we want to notify registered clients that an interface has come
+// or gone. We loop through our InterfaceNotify table, calling each one.
+//
+// Input: Context - Context for interface that has changed.
+// Added - True if the interface is coming, False if it's
+// going.
+//
+// Returns: Nothing.
+//
+void
+NotifyInterfaceChange(ushort IPContext, uint Added)
+{
+ uint i;
+
+ for (i = 0; i < MAX_NOTIFY_CLIENTS; i++) {
+ if (InterfaceNotifyTable[i] != NULL)
+ (*(InterfaceNotifyTable[i]))(IPContext, Added);
+ }
+}
+
+//* RegisterInterfaceNotify - Register an interface notify routine.
+//
+// A routine called to register an interface notify routine.
+//
+// Input: Rtn - Routine to register.
+// Register - True to register, False to deregister.
+//
+// Returns: TRUE if we succeed, FALSE if we don't/
+//
+uint
+RegisterInterfaceNotify(InterfaceNotifyRtn Rtn, uint Register)
+{
+ uint i;
+ InterfaceNotifyRtn NewRtn, OldRtn;
+
+ if (Register) {
+ NewRtn = Rtn;
+ OldRtn = NULL;
+ } else {
+ NewRtn = NULL;
+ OldRtn = Rtn;
+ }
+
+ for (i = 0; i < MAX_NOTIFY_CLIENTS; i++) {
+ if (InterfaceNotifyTable[i] == OldRtn) {
+ InterfaceNotifyTable[i] = NewRtn;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+//* NotifyAddrChange - Notify clients of a change in addresses.
+//
+// Called when we want to notify registered clients that an address has come
+// or gone. We loop through our AddrNotify table, calling each one.
+//
+// Input: Addr - Addr that has changed.
+// Mask - Mask that has changed.
+// Context - PNP context for address
+// IPContext - NTE context for NTE
+// Handle - Pointer to where to get/set address registration
+// handle
+// ConfigName - Registry name to use to retrieve config info.
+// Added - True if the addr is coming, False if it's going.
+//
+// Returns: Nothing.
+//
+void
+NotifyAddrChange(IPAddr Addr, IPMask Mask, void *Context, ushort IPContext,
+ PVOID *Handle, PNDIS_STRING ConfigName, uint Added)
+{
+ uint i;
+
+ for (i = 0; i < MAX_NOTIFY_CLIENTS; i++) {
+ if (AddrNotifyTable[i] != NULL)
+ (*(AddrNotifyTable[i]))(Addr, Mask, Context, IPContext, Added);
+ }
+}
+
+
+#else // CHICAGO
+
+//* NotifyAddrChange - Notify clients of a change in addresses.
+//
+// Called when we want to notify registered clients that an address has come
+// or gone. We call TDI to perform this function.
+//
+// Input: Addr - Addr that has changed.
+// Mask - Mask that has changed.
+// Context - PNP context for address
+// IPContext - NTE context for NTE
+// Handle - Pointer to where to get/set address registration
+// handle
+// ConfigName - Registry name to use to retrieve config info.
+// Added - True if the addr is coming, False if it's going.
+//
+// Returns: Nothing.
+//
+void
+NotifyAddrChange(IPAddr Addr, IPMask Mask, void *Context, ushort IPContext,
+ PVOID *Handle, PNDIS_STRING ConfigName, uint Added)
+{
+ uchar Address[sizeof(TA_ADDRESS) + sizeof(TDI_ADDRESS_IP)];
+ PTA_ADDRESS AddressPtr;
+ PTDI_ADDRESS_IP IPAddressPtr;
+ NTSTATUS Status;
+
+#ifdef SECFLTR
+
+ IP_STATUS StatusType;
+ NDIS_HANDLE ConfigHandle = NULL;
+ int i;
+ ULStatusProc StatProc;
+
+#endif // SECFLTR
+
+
+ AddressPtr = (PTA_ADDRESS)Address;
+
+ AddressPtr->AddressLength = sizeof(TDI_ADDRESS_IP);
+ AddressPtr->AddressType = TDI_ADDRESS_TYPE_IP;
+
+ IPAddressPtr = (PTDI_ADDRESS_IP)AddressPtr->Address;
+
+ CTEMemSet(IPAddressPtr, 0, sizeof(TDI_ADDRESS_IP));
+
+ IPAddressPtr->in_addr = Addr;
+
+#ifdef SECFLTR
+
+ //
+ // Call the status entrypoint of the transports so they can
+ // adjust their security filters.
+ //
+ if (Added) {
+ StatusType = IP_ADDR_ADDED;
+
+ //
+ // Open a configuration key
+ //
+ if (!OpenIFConfig(ConfigName, &ConfigHandle)) {
+ //
+ // Not much we can do. The transports will have
+ // to handle this.
+ //
+ CTEAssert(ConfigHandle == NULL);
+ }
+ }
+ else {
+ StatusType = IP_ADDR_DELETED;
+ }
+
+ for ( i = 0; i < NextPI; i++) {
+ StatProc = IPProtInfo[i].pi_status;
+ if (StatProc != NULL)
+ (*StatProc)(IP_HW_STATUS, StatusType, Addr, NULL_IP_ADDR,
+ NULL_IP_ADDR, 0, ConfigHandle );
+ }
+
+ if (ConfigHandle != NULL) {
+ CloseIFConfig(ConfigHandle);
+ }
+
+#endif // SECFLTR
+
+ //
+ // Notify any interested parties via TDI. The transports all register
+ // for this notification as well.
+ //
+ if (Added) {
+ Status = TdiRegisterNetAddress(AddressPtr, Handle);
+ if (Status != STATUS_SUCCESS) {
+ *Handle = NULL;
+ }
+ } else {
+ if (*Handle != NULL) {
+ TdiDeregisterNetAddress(*Handle);
+ *Handle = NULL;
+ }
+ }
+
+}
+
+#endif // CHICAGO
+
+
+//* IPAddNTE - Add a new NTE to an interface
+//
+// Called to create a new network entry on an interface.
+//
+// Input: GConfigInfo - Configuration information for the interface
+// PNPContext - The PNP context value associated with the interface
+// RegRtn - Routine to call to register with ARP.
+// BindInfo - Pointer to NDIS bind information.
+// IF - The interface on which to create the NTE.
+// NewAddr - The address of the new NTE.
+// NewMask - The subnet mask for the new NTE.
+// IsPrimary - TRUE if this NTE is the primary one on the interface
+// IsDynamic - TRUE if this NTE is being created on an
+// existing interface instead of a new one.
+//
+// Returns: A pointer to the new NTE if the operation succeeds.
+// NULL if the operation fails.
+//
+NetTableEntry *
+IPAddNTE(IFGeneralConfig *GConfigInfo, void * PNPContext, LLIPRegRtn RegRtn,
+ LLIPBindInfo *BindInfo, Interface *IF, IPAddr NewAddr, IPMask NewMask,
+ uint IsPrimary, uint IsDynamic)
+{
+ NetTableEntry *NTE, *PrevNTE;
+ CTELockHandle Handle;
+
+
+ // If the address is invalid we're done. Fail the request.
+ if (CLASSD_ADDR(NewAddr) || CLASSE_ADDR(NewAddr)) {
+ return NULL;
+ }
+
+ // See if we have an inactive NTE on the NetTableList. If we do, we'll
+ // just recycle that. We will pull him out of the list. This is not
+ // strictly MP safe, since other people could be walking the list while
+ // we're doing this without holding a lock, but it should be harmless.
+ // The removed NTE is marked as invalid, and his next pointer will
+ // be nulled, so anyone walking the list might hit the end too soon,
+ // but that's all. The memory is never freed, and the next pointer is
+ // never pointed at freed memory.
+
+ CTEGetLock(&RouteTableLock, &Handle);
+
+ PrevNTE = STRUCT_OF(NetTableEntry, &NetTableList, nte_next);
+ for (NTE = NetTableList; NTE != NULL; PrevNTE = NTE, NTE = NTE->nte_next)
+ if (!(NTE->nte_flags & NTE_ACTIVE)) {
+ PrevNTE->nte_next = NTE->nte_next;
+ NTE->nte_next = NULL;
+ NumNTE--;
+ break;
+ }
+
+ CTEFreeLock(&RouteTableLock, Handle);
+
+ // See if we got one.
+ if (NTE == NULL) {
+ // Didn't get one. Try to allocate one.
+ NTE = CTEAllocMem(sizeof(NetTableEntry));
+ if (NTE == NULL)
+ return NULL;
+ CTEMemSet(NTE, 0, sizeof(NetTableEntry));
+ }
+
+ // Initialize the address and mask stuff
+ NTE->nte_addr = NewAddr;
+ NTE->nte_mask = NewMask;
+ NTE->nte_mss = MAX(GConfigInfo->igc_mtu, 68);
+ NTE->nte_rtrdiscaddr = GConfigInfo->igc_rtrdiscaddr;
+ NTE->nte_rtrdiscstate = NTE_RTRDISC_UNINIT;
+ NTE->nte_rtrdisccount = 0;
+ NTE->nte_rtrdiscovery = (uchar)GConfigInfo->igc_rtrdiscovery;
+ NTE->nte_rtrlist = NULL;
+ NTE->nte_pnpcontext = PNPContext;
+ NTE->nte_if = IF;
+ NTE->nte_flags = NTE_ACTIVE;
+
+ //
+ // If the new address is in the ATCache, flush it out, otherwise
+ // TdiOpenAddress may fail.
+ //
+ FlushATCache(NewAddr);
+
+ if (!IP_ADDR_EQUAL(NTE->nte_addr, NULL_IP_ADDR)) {
+ NTE->nte_flags |= NTE_VALID;
+ NTE->nte_rtrdisccount = MAX_SOLICITATION_DELAY;
+ NTE->nte_rtrdiscstate = NTE_RTRDISC_DELAYING;
+ }
+
+ if (IsDynamic) {
+ NTE->nte_flags |= NTE_DYNAMIC;
+ }
+
+ NTE->nte_ralist = NULL;
+ NTE->nte_echolist = NULL;
+ NTE->nte_icmpseq = 0;
+ NTE->nte_igmplist = NULL;
+ CTEInitLock(&NTE->nte_lock);
+ CTEInitTimer(&NTE->nte_timer);
+
+ if (IsPrimary) {
+ //
+ // This is the first (primary) NTE on the interface.
+ //
+ NTE->nte_flags |= NTE_PRIMARY;
+
+ // Pass our information to the underlying code.
+ if (!(*RegRtn)(&(IF->if_configname), NTE, IPRcv, IPSendComplete,
+ IPStatus, IPTDComplete, IPRcvComplete, BindInfo,
+ IF->if_index)) {
+
+ // Couldn't register.
+ goto failure;
+ }
+ }
+
+ //
+ // Link the NTE onto the global NTE list.
+ //
+ CTEGetLock(&RouteTableLock, &Handle);
+
+ NTE->nte_next = NetTableList;
+ NetTableList = NTE;
+ NumNTE++;
+
+ CTEFreeLock(&RouteTableLock, Handle);
+
+ if (!InitInterface(NTE)) {
+ goto failure;
+ }
+
+ if (!InitNTE(NTE)) {
+ goto failure;
+ }
+
+ if (!InitNTERouting(NTE, GConfigInfo->igc_numgws, GConfigInfo->igc_gw)) {
+ // Couldn't add the routes for this NTE. Mark him as not valid.
+ // Probably should log an event here.
+ if (NTE->nte_flags & NTE_VALID) {
+ NTE->nte_flags &= ~NTE_VALID;
+ NTE->nte_if->if_ntecount--;
+ }
+ }
+
+#ifdef NT
+
+ if (!IP_ADDR_EQUAL(NTE->nte_addr, NULL_IP_ADDR)) {
+ SetPersistentRoutesForNTE(
+ net_long(NTE->nte_addr),
+ net_long(NTE->nte_mask),
+ NTE->nte_if->if_index
+ );
+ }
+
+#endif // NT
+
+ return(NTE);
+
+failure:
+
+ //
+ // BUGBUG - what should we do with the NTE here????
+ //
+
+ return(NULL);
+}
+
+
+//* IPAddDynamicNTE - Add a new "dynamic" NTE to an existing interface
+//
+// Called to dynamically create a new network entry on an existing interface.
+// This entry was not configured when the interaface was originally created
+// and will not persist if the interface is unbound.
+//
+// Input: InterfaceContext - The context value which identifies the
+// interface on which to create the NTE.
+// NewAddr - The address of the new NTE.
+// NewMask - The subnet mask for the new NTE.
+//
+// Output: NTEContext - The context identifying the new NTE.
+// NTEInstance - The instance number which (reasonably) uniquely
+// identifies this NTE in time.
+//
+// Returns: Nonzero if the operation succeeded. Zero if it failed.
+//
+uint
+IPAddDynamicNTE(ushort InterfaceContext, IPAddr NewAddr, IPMask NewMask,
+ ushort *NTEContext, ulong *NTEInstance)
+{
+ IFGeneralConfig GConfigInfo; // General config info structure.
+ NDIS_HANDLE Handle; // Configuration handle.
+ NetTableEntry *NTE;
+ Interface *IF;
+ ushort MTU;
+ uint Flags = 0;
+
+
+#ifdef NT
+ PAGED_CODE();
+#endif
+
+ for (IF = IFList; IF != NULL; IF = IF->if_next) {
+ if (IF->if_index == InterfaceContext) {
+ break;
+ }
+ }
+
+ //* Try to get the network configuration information.
+ if (!OpenIFConfig(&(IF->if_configname), &Handle))
+ return FALSE;
+
+ // Try to get our general config information.
+ if (!GetGeneralIFConfig(&GConfigInfo, Handle)) {
+ goto failure;
+ }
+
+ NTE = IPAddNTE(
+ &GConfigInfo,
+ NULL, // PNPContext - BUGBUG needed?
+ NULL, // RegRtn - not needed if not primary
+ NULL, // BindInfo - not needed if not primary
+ IF,
+ NewAddr,
+ NewMask,
+ FALSE, // not primary
+ TRUE // is dynamic
+ );
+
+ if (NTE == NULL) {
+ goto failure;
+ }
+
+ CloseIFConfig(Handle);
+
+ //
+ // Notify upper layers of the new address.
+ //
+#ifdef SECFLTR
+
+ NotifyAddrChange(NTE->nte_addr, NTE->nte_mask, NTE->nte_pnpcontext,
+ NTE->nte_context, &NTE->nte_addrhandle, &(IF->if_configname), TRUE);
+
+#else // SECFLTR
+
+ NotifyAddrChange(NTE->nte_addr, NTE->nte_mask, NTE->nte_pnpcontext,
+ NTE->nte_context, &NTE->nte_addrhandle, NULL, TRUE);
+
+#endif // SECFLTR
+
+ if (!IP_ADDR_EQUAL(NTE->nte_addr, NULL_IP_ADDR)) {
+ InitIGMPForNTE(NTE);
+ }
+ else {
+#ifdef CHICAGO
+ // Call DHCP to get an address for this guy.
+
+ //
+ // BUGBUG (mikemas 8/28/96)
+ // we may not always want to do this!
+ //
+ RequestDHCPAddr(NTE->nte_context);
+#endif
+ }
+
+ //
+ // Fill in the out parameter value.
+ //
+ *NTEContext = NTE->nte_context;
+ *NTEInstance = NTE->nte_instance;
+
+ return(TRUE);
+
+failure:
+
+ CloseIFConfig(Handle);
+
+ return(IP_GENERAL_FAILURE);
+}
+
+
+//* IPAddInterface - Add an interface.
+//
+// Called when someone has an interface they want us to add. We read our
+// configuration information, and see if we have it listed. If we do,
+// we'll try to allocate memory for the structures we need. Then we'll
+// call back to the guy who called us to get things going. Finally, we'll
+// see if we have an address that needs to be DHCP'ed.
+//
+// Input: ConfigName - Name of config info we're to read.
+// Context - Context to pass to i/f on calls.
+// RegRtn - Routine to call to register.
+// BindInfo - Pointer to bind information.
+//
+// Returns: Status of attempt to add the interface.
+//
+IP_STATUS
+IPAddInterface(PNDIS_STRING ConfigName, void *PNPContext, void *Context,
+ LLIPRegRtn RegRtn, LLIPBindInfo *BindInfo)
+{
+ IFGeneralConfig GConfigInfo; // General config info structure.
+ IFAddrList *AddrList; // List of addresses for this I/F.
+ uint NumAddr; // Number of IP addresses on this
+ // interface
+ NetTableEntry *NTE; // Current NTE being initialized.
+ uint i; // Index variable.
+ uint IndexMask; // Mask for searching IFBitMask.
+ Interface *IF; // Interface being added.
+ NDIS_HANDLE Handle; // Configuration handle.
+ NetTableEntry *PrimaryNTE; // The primary NTE for this I/F.
+ uint IFIndex; // Index to be assigned to this I/F.
+ NetTableEntry *LastNTE; // Last NTE created.
+
+
+ CTERefillMem();
+
+ PrimaryNTE = NULL;
+ AddrList = NULL;
+ IF = NULL;
+ LastNTE = NULL;
+
+ //* First, try to get the network configuration information.
+ if (!OpenIFConfig(ConfigName, &Handle))
+ return IP_GENERAL_FAILURE; // Couldn't get IFConfig.
+
+ // Try to get our general config information.
+ if (!GetGeneralIFConfig(&GConfigInfo, Handle)) {
+ goto failure;
+ }
+
+ // We got the general config info. Now allocate an interface.
+ IF = CTEAllocMem(InterfaceSize + ConfigName->MaximumLength);
+
+ if (IF == NULL) {
+ goto failure;
+ }
+
+ CTEMemSet(IF, 0, InterfaceSize);
+ CTEInitLock(&IF->if_lock);
+
+ // Initialize the broadcast we'll use.
+ if (GConfigInfo.igc_zerobcast)
+ IF->if_bcast = IP_ZERO_BCST;
+ else
+ IF->if_bcast = IP_LOCAL_BCST;
+
+ if (RouterConfigured) {
+ RouteInterface *RtIF = (RouteInterface *)IF;
+
+
+ RtIF->ri_q.rsq_qh.fq_next = &RtIF->ri_q.rsq_qh;
+ RtIF->ri_q.rsq_qh.fq_prev = &RtIF->ri_q.rsq_qh;
+ RtIF->ri_q.rsq_running = FALSE;
+ RtIF->ri_q.rsq_pending = 0;
+ RtIF->ri_q.rsq_maxpending = GConfigInfo.igc_maxpending;
+ RtIF->ri_q.rsq_qlength = 0;
+ CTEInitLock(&RtIF->ri_q.rsq_lock);
+ }
+
+ IF->if_xmit = BindInfo->lip_transmit;
+ IF->if_transfer = BindInfo->lip_transfer;
+ IF->if_close = BindInfo->lip_close;
+ IF->if_invalidate = BindInfo->lip_invalidate;
+ IF->if_lcontext = BindInfo->lip_context;
+ IF->if_addaddr = BindInfo->lip_addaddr;
+ IF->if_deladdr = BindInfo->lip_deladdr;
+ IF->if_qinfo = BindInfo->lip_qinfo;
+ IF->if_setinfo = BindInfo->lip_setinfo;
+ IF->if_getelist = BindInfo->lip_getelist;
+ IF->if_tdpacket = NULL;
+ CTEAssert(BindInfo->lip_mss > sizeof(IPHeader));
+ IF->if_mtu = BindInfo->lip_mss - sizeof(IPHeader);
+ IF->if_speed = BindInfo->lip_speed;
+ IF->if_flags = BindInfo->lip_flags & LIP_P2P_FLAG ? IF_FLAGS_P2P : 0;
+ IF->if_addrlen = BindInfo->lip_addrlen;
+ IF->if_addr = BindInfo->lip_addr;
+ IF->if_pnpcontext = PNPContext;
+ IF->if_llipflags = BindInfo->lip_flags;
+
+ // Initialize the reference count to 1, for the open.
+ IF->if_refcount = 1;
+
+#ifdef IGMPV2
+ IF->IgmpVersion = IGMPV2;
+#else
+ IF->IgmpVersion = IGMPV1;
+#endif
+
+
+ //
+ // No need to do the following since IF structure is inited to 0 through
+ // memset above
+ //
+ // IF->IgmpVer1Timeout = 0;
+
+ //
+ // Copy the config string for use later when DHCP enables an address
+ // on this interface or when an NTE is added dynamically.
+ //
+ IF->if_configname.Buffer = (PVOID) (((uchar *)IF) + InterfaceSize);
+ IF->if_configname.Length = 0;
+ IF->if_configname.MaximumLength = ConfigName->MaximumLength;
+
+ CTECopyString(
+ &(IF->if_configname),
+ ConfigName
+ );
+
+ // Find out how many addresses we have, and get the address list.
+ AddrList = GetIFAddrList(&NumAddr, Handle);
+
+ if (AddrList == NULL) {
+ CTEFreeMem(IF);
+ goto failure;
+ }
+
+ //
+ //Link this interface onto the global interface list
+ //
+ IF->if_next = IFList;
+ IFList = IF;
+
+ if (FirstIF == NULL)
+ FirstIF = IF;
+
+ NumIF++;
+ IndexMask = 1;
+
+ for (i = 0; i < MAX_TDI_ENTITIES; i++) {
+ if ((IFBitMask[i/BITS_PER_WORD] & IndexMask) == 0) {
+ IFIndex = i+ 1;
+ IFBitMask[i/BITS_PER_WORD] |= IndexMask;
+ break;
+ }
+ if (((i+1) % BITS_PER_WORD) == 0) {
+ IndexMask = 1;
+ } else {
+ IndexMask = IndexMask << 1;
+ }
+ }
+
+ if (i == MAX_TDI_ENTITIES) {
+ // Too many interfaces bound.
+ goto failure;
+ }
+
+ IF->if_index = IFIndex;
+
+ // Now loop through, initializing each NTE as we go. We don't hold any
+ // locks while we do this, since NDIS won't reenter us here and no one
+ // else manipulates the NetTableList.
+
+ for (i = 0;i < NumAddr;i++) {
+ NetTableEntry *PrevNTE;
+ IPAddr NewAddr;
+ uint isPrimary;
+
+ if (i == 0) {
+ isPrimary = TRUE;
+ }
+ else {
+ isPrimary = FALSE;
+ }
+
+ NTE = IPAddNTE(
+ &GConfigInfo,
+ PNPContext,
+ RegRtn,
+ BindInfo,
+ IF,
+ net_long(AddrList[i].ial_addr),
+ net_long(AddrList[i].ial_mask),
+ isPrimary,
+ FALSE // not dynamic
+ );
+
+ if (NTE == NULL) {
+ goto failure;
+ }
+
+ if (isPrimary) {
+ PrimaryNTE = NTE;
+
+#ifdef NT
+
+ //
+ // Write the context of the first interface to the registry.
+ //
+ if (isPrimary) {
+ NTSTATUS writeStatus;
+ ulong context = (ulong) NTE->nte_context;
+
+ writeStatus = SetRegDWORDValue(
+ Handle,
+ L"IPInterfaceContext",
+ &context
+ );
+
+ if (!NT_SUCCESS(writeStatus)) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_DHCP_INIT_FAILED,
+ 2,
+ 1,
+ &(ConfigName->Buffer),
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP: Unable to write IPInterfaceContext value for adapter %ws\n"
+ " (status %lx). DHCP will be unable to configure this \n"
+ " adapter.\n",
+ ConfigName->Buffer,
+ writeStatus
+ ));
+ }
+ }
+
+#endif // NT
+
+ }
+
+ LastNTE = NTE;
+ }
+
+#ifdef NT
+
+ if (LastNTE != NULL) {
+
+ NTSTATUS writeStatus;
+ ulong context = (ulong) LastNTE->nte_context;
+
+ writeStatus = SetRegDWORDValue(
+ Handle,
+ L"IPInterfaceContextMax",
+ &context
+ );
+
+ if (!NT_SUCCESS(writeStatus)) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_DHCP_INIT_FAILED,
+ 3,
+ 1,
+ &(ConfigName->Buffer),
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP: Unable to write IPInterfaceContextMax value for adapter %ws\n"
+ " (status %lx). DHCP will be unable to configure this \n"
+ " adapter.\n",
+ ConfigName->Buffer,
+ writeStatus
+ ));
+ }
+ }
+
+#endif // NT
+
+ CloseIFConfig(Handle);
+
+ // We've initialized our NTEs. Now get the adapter open, and go through
+ // again, calling DHCP if we need to.
+
+ (*(BindInfo->lip_open))(BindInfo->lip_context);
+
+ if (PrimaryNTE != NULL) {
+#ifdef CHICAGO
+ NotifyInterfaceChange(PrimaryNTE->nte_context, TRUE);
+#endif
+ }
+
+ // Now walk through the NTEs we've added, and get addresses for them (or
+ // tell clients about them). This code assumes that no one else has mucked
+ // with the list while we're here.
+ for (i = 0; i < NumAddr; i++, NTE = NTE->nte_next) {
+
+//
+// BUGBUG - Doesn't this send up a notification of zero for a DHCP'd
+// address on chicago??? (mikemas, 2/5/96)
+//
+#ifdef SECFLTR
+
+ NotifyAddrChange(NTE->nte_addr, NTE->nte_mask, NTE->nte_pnpcontext,
+ NTE->nte_context, &NTE->nte_addrhandle, &(IF->if_configname), TRUE);
+
+#else // SECFLTR
+
+ NotifyAddrChange(NTE->nte_addr, NTE->nte_mask, NTE->nte_pnpcontext,
+ NTE->nte_context, &NTE->nte_addrhandle, NULL, TRUE);
+
+#endif // SECFLTR
+
+ if (IP_ADDR_EQUAL(NTE->nte_addr, NULL_IP_ADDR)) {
+ // Call DHCP to get an address for this guy.
+#ifdef CHICAGO
+ RequestDHCPAddr(NTE->nte_context);
+#endif
+ } else {
+ InitIGMPForNTE(NTE);
+ }
+ }
+
+
+ CTEFreeMem(AddrList);
+ return IP_SUCCESS;
+
+failure:
+ CloseIFConfig(Handle);
+
+ if (AddrList != NULL)
+ CTEFreeMem(AddrList);
+
+ return IP_GENERAL_FAILURE;
+}
+
+extern uint BCastMinMTU;
+
+
+//* IPDelNTE - Delete an active NTE
+//
+// Called to delete an active NTE from the system. The RouteTableLock
+// must be acquired before calling this routine. It will be freed upon
+// return.
+//
+// Input: NTE - A pointer to the network entry to delete.
+// RouteTableHandle - A pointer to the lock handle for the
+// route table lock, which the caller has
+// acquired.
+//
+// Returns: Nothing
+//
+void
+IPDelNTE(NetTableEntry *NTE, CTELockHandle *RouteTableHandle)
+{
+ Interface *IF = NTE->nte_if;
+ ReassemblyHeader *RH, *RHNext;
+ EchoControl *EC, *ECNext;
+ EchoRtn Rtn;
+ CTELockHandle Handle;
+ PNDIS_PACKET Packet;
+ PNDIS_BUFFER Buffer;
+ uchar *TDBuffer;
+
+
+ if (NTE->nte_flags & NTE_VALID) {
+ (void) IPpSetNTEAddr(NTE, NULL_IP_ADDR, NULL_IP_ADDR, RouteTableHandle, NULL, NULL);
+
+ } else {
+ CTEFreeLock(&RouteTableLock, *RouteTableHandle);
+
+ NotifyAddrChange(NULL_IP_ADDR, NULL_IP_ADDR,
+ NTE->nte_pnpcontext, NTE->nte_context,
+ &NTE->nte_addrhandle, NULL, FALSE);
+ }
+
+ CTEGetLock(&RouteTableLock, RouteTableHandle);
+
+ if (DHCPNTE == NTE)
+ DHCPNTE = NULL;
+
+ NTE->nte_flags = 0;
+
+ CTEFreeLock(&RouteTableLock, *RouteTableHandle);
+
+ CTEStopTimer(&NTE->nte_timer);
+
+ CTEGetLock(&NTE->nte_lock, &Handle);
+
+ RH = NTE->nte_ralist;
+ NTE->nte_ralist = NULL;
+ EC = NTE->nte_echolist;
+ NTE->nte_echolist = NULL;
+
+ CTEFreeLock(&NTE->nte_lock, Handle);
+
+ // Free any reassembly resources.
+ while (RH != NULL) {
+ RHNext = RH->rh_next;
+ FreeRH(RH);
+ RH = RHNext;
+ }
+
+ // Now free any pending echo requests.
+ while (EC != NULL) {
+ ECNext= EC->ec_next;
+ Rtn = (EchoRtn)EC->ec_rtn;
+ (*Rtn)(EC, IP_ADDR_DELETED, NULL, 0, NULL);
+ EC = ECNext;
+ }
+
+ //
+ // Free the TD resource allocated for this NTE.
+ //
+ CTEGetLock(&(IF->if_lock), &Handle);
+
+ Packet = IF->if_tdpacket;
+
+ if (Packet != NULL) {
+
+ IF->if_tdpacket =
+ ((TDContext *)Packet->ProtocolReserved)->tdc_common.pc_link;
+
+ CTEFreeLock(&(IF->if_lock), Handle);
+
+ Buffer = Packet->Private.Head;
+ TDBuffer = NdisBufferVirtualAddress(Buffer);
+ NdisFreePacketPool(Packet->Private.Pool);
+
+#ifdef CHICAGO
+ NdisFreeBufferPool(Buffer->Pool);
+#endif
+ CTEFreeMem(TDBuffer);
+ }
+ else {
+ CTEFreeLock(&(IF->if_lock), Handle);
+ }
+
+ return;
+}
+
+
+//* IPDeleteDynamicNTE - Deletes a "dynamic" NTE.
+//
+// Called to delete a network entry which was dynamically created on an
+// existing interface.
+//
+// Input: NTEContext - The context value identifying the NTE to delete.
+//
+// Returns: Nonzero if the operation succeeded. Zero if it failed.
+//
+uint
+IPDeleteDynamicNTE(ushort NTEContext)
+{
+ NetTableEntry *NTE;
+ Interface *IF;
+ CTELockHandle Handle;
+
+
+ CTEGetLock(&RouteTableLock, &Handle);
+
+ for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
+ if ( (NTE->nte_context == NTEContext) &&
+ (NTE->nte_flags & NTE_DYNAMIC) &&
+ (NTE->nte_flags & NTE_ACTIVE)
+ )
+ {
+ CTEAssert(NTE != LoopNTE);
+ CTEAssert(!(NTE->nte_flags & NTE_PRIMARY));
+
+ IPDelNTE(NTE, &Handle);
+
+ //
+ // Route table lock was freed by IPDelNTE
+ //
+
+ return(TRUE);
+ }
+ }
+
+ CTEFreeLock(&RouteTableLock, Handle);
+
+ return(FALSE);
+}
+
+
+//* IPGetNTEInfo - Retrieve information about a network entry.
+//
+// Called to retrieve context information about a network entry.
+//
+// Input: NTEContext - The context value which identifies the NTE to query.
+//
+// Output: NTEInstance - The instance number associated with the NTE.
+// Address - The address assigned to the NTE.
+// SubnetMask - The subnet mask assigned to the NTE.
+// NTEFlags - The flag values associated with the NTE.
+//
+// Returns: Nonzero if the operation succeeded. Zero if it failed.
+//
+uint
+IPGetNTEInfo(ushort NTEContext, ulong *NTEInstance, IPAddr *Address,
+ IPMask *SubnetMask, ushort *NTEFlags)
+{
+ NetTableEntry *NTE;
+ CTELockHandle Handle;
+ uint retval = FALSE;
+
+
+ CTEGetLock(&RouteTableLock, &Handle);
+
+ for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
+ if ((NTE->nte_context == NTEContext) &&
+ (NTE->nte_flags & NTE_ACTIVE)
+ )
+ {
+ *NTEInstance = NTE->nte_instance;
+
+ if (NTE->nte_flags & NTE_VALID) {
+ *Address = NTE->nte_addr;
+ *SubnetMask = NTE->nte_mask;
+ }
+ else {
+ *Address = NULL_IP_ADDR;
+ *SubnetMask = NULL_IP_ADDR;
+ }
+
+ *NTEFlags = NTE->nte_flags;
+ retval = TRUE;
+ }
+ }
+
+ CTEFreeLock(&RouteTableLock, Handle);
+
+ return(retval);
+}
+
+
+//* IPDelInterface - Delete an interface.
+//
+// Called when we need to delete an interface that's gone away. We'll walk
+// the NTE list, looking for NTEs that are on the interface that's going
+// away. For each of those, we'll invalidate the NTE, delete routes on it,
+// and notify the upper layers that it's gone. When that's done we'll pull
+// the interface out of the list and free the memory.
+//
+// Note that this code probably isn't MP safe. We'll need to fix that for
+// the port to NT.
+//
+// Input: Context - Pointer to primary NTE on the interface.
+//
+// Returns: Nothing.
+//
+void
+IPDelInterface(void *Context)
+{
+ NetTableEntry *NTE = (NetTableEntry *)Context;
+ NetTableEntry *FoundNTE = NULL;
+ Interface *IF, *PrevIF;
+ CTELockHandle Handle;
+ PNDIS_PACKET Packet;
+ PNDIS_BUFFER Buffer;
+ uchar *TDBuffer;
+ ReassemblyHeader *RH;
+ EchoControl *EC;
+ EchoRtn Rtn;
+ CTEBlockStruc Block;
+
+ IF = NTE->nte_if;
+
+ CTEGetLock(&RouteTableLock, &Handle);
+
+ IF->if_flags |= IF_FLAGS_DELETING;
+
+ for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
+ if (NTE->nte_if == IF) {
+
+ if (FoundNTE == NULL) {
+ FoundNTE = NTE;
+ }
+
+ // This guy is on the interface, and needs to be deleted.
+ IPDelNTE(NTE, &Handle);
+
+ CTEGetLock(&RouteTableLock, &Handle);
+ }
+ }
+
+ CTEFreeLock(&RouteTableLock, Handle);
+
+ // Clear this index from the IFBitMask.
+ CTEAssert(IFBitMask[(IF->if_index-1)/BITS_PER_WORD] & (1 << ((IF->if_index - 1)%BITS_PER_WORD)));
+
+ IFBitMask[(IF->if_index-1)/BITS_PER_WORD] &= ~(1 << ((IF->if_index - 1)%BITS_PER_WORD));
+
+ if (FoundNTE != NULL) {
+#ifdef CHICAGO
+ NotifyInterfaceChange(FoundNTE->nte_context, FALSE);
+#endif
+ }
+
+ //
+ // Free the TD resources on the IF.
+ //
+
+ while ((Packet = IF->if_tdpacket) != NULL) {
+
+ IF->if_tdpacket =
+ ((TDContext *)Packet->ProtocolReserved)->tdc_common.pc_link;
+
+ Buffer = Packet->Private.Head;
+ TDBuffer = NdisBufferVirtualAddress(Buffer);
+ NdisFreePacketPool(Packet->Private.Pool);
+
+#ifdef CHICAGO
+ NdisFreeBufferPool(Buffer->Pool);
+#endif
+ CTEFreeMem(TDBuffer);
+ }
+
+ // If this was the 'first' IF, set that to NULL and delete the broadcast
+ // route that goes through him.
+ if (FirstIF == IF) {
+ DeleteRoute(IP_LOCAL_BCST, HOST_MASK, IPADDR_LOCAL,
+ FirstIF);
+ DeleteRoute(IP_ZERO_BCST, HOST_MASK, IPADDR_LOCAL,
+ FirstIF);
+ FirstIF = NULL;
+ BCastMinMTU = 0xffff;
+ }
+
+ // OK, we've cleaned up all the routes through this guy.
+ // Get ready to block waiting for all reference to go
+ // away, then dereference our reference. After this, go
+ // ahead and try to block. Mostly likely our reference was
+ // the last one, so we won't block - we'll wake up immediately.
+ CTEInitBlockStruc(&Block);
+ IF->if_block = &Block;
+
+ DerefIF(IF);
+
+ (void)CTEBlock(&Block);
+
+ // OK, we've cleaned up all references, so there shouldn't be
+ // any more transmits pending through this interface. Close the
+ // adapter to force synchronization with any receives in process.
+
+
+ (*(IF->if_close))(IF->if_lcontext);
+
+ // Now walk the IFList, looking for this guy. When we find him, free him.
+ PrevIF = STRUCT_OF(Interface, &IFList, if_next);
+ while (PrevIF->if_next != IF && PrevIF->if_next != NULL)
+ PrevIF = PrevIF->if_next;
+
+ if (PrevIF->if_next != NULL) {
+ PrevIF->if_next = IF->if_next;
+ NumIF--;
+ CTEFreeMem(IF);
+ } else
+ CTEAssert(FALSE);
+
+ // If we've deleted the first interface but still have other valid
+ // interfaces, we need to create a new FirstIF and read broadcast routes
+ // through it. NumIF is always at least one because of the loopback
+ // interface.
+ if (FirstIF == NULL && NumIF != 1) {
+
+ FirstIF = IFList;
+
+ for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
+ if ((NTE->nte_flags & NTE_VALID) && NTE != LoopNTE) {
+ BCastMinMTU = MIN(BCastMinMTU, NTE->nte_mss);
+ AddRoute(NTE->nte_if->if_bcast, HOST_MASK, IPADDR_LOCAL,
+ FirstIF, BCastMinMTU, 1, IRE_PROTO_LOCAL, ATYPE_OVERRIDE,
+ NULL);
+ }
+ }
+ }
+
+}
+
+
+#else // _PNP_POWER
+
+
+//* NotifyAddrChange - Notify clients of a change in addresses.
+//
+// Called when we want to notify registered clients that an address has come
+// or gone. We call TDI to perform this function.
+//
+// Input: Addr - Addr that has changed.
+// Mask - Ignored - Mask that has changed.
+// Context - Ignored - PNP context for address
+// IPContext - NTE context for NTE
+// Handle - Pointer to where to get/set address registration
+// handle
+// ConfigName - Registry name to use to retrieve config info.
+// Added - True if the addr is coming, False if it's going.
+//
+// Returns: Nothing.
+//
+void
+NotifyAddrChange(IPAddr Addr, IPMask Mask, void *Context, ushort IPContext,
+ PVOID *Handle, PNDIS_STRING ConfigName, uint Added)
+
+{
+ IP_STATUS StatusType;
+ NDIS_HANDLE ConfigHandle = NULL;
+ int i;
+ ULStatusProc StatProc;
+
+
+ if (Added) {
+ StatusType = IP_ADDR_ADDED;
+
+#ifdef SECFLTR
+ //
+ // Open a configuration key
+ //
+ if (!OpenIFConfig(ConfigName, &ConfigHandle)) {
+ //
+ // Not much we can do. The transports will have
+ // to handle this.
+ //
+ CTEAssert(ConfigHandle == NULL);
+ }
+#endif // SECFLTR
+
+ }
+ else {
+ StatusType = IP_ADDR_DELETED;
+ }
+
+ for ( i = 0; i < NextPI; i++) {
+ StatProc = IPProtInfo[i].pi_status;
+ if (StatProc != NULL)
+ (*StatProc)(IP_HW_STATUS, StatusType, Addr, NULL_IP_ADDR,
+ NULL_IP_ADDR, 0, ConfigHandle );
+ }
+
+#ifdef SECFLTR
+
+ if (ConfigHandle != NULL) {
+ CloseIFConfig(ConfigHandle);
+ }
+
+#endif // SECFLTR
+
+}
+
+
+#endif // _PNP_POWER
+
+
+#pragma BEGIN_INIT
+
+//** ipinit - Initialize ourselves.
+//
+// This routine is called during initialization from the OS-specific
+// init code. We need to check for the presence of the common xport
+// environment first.
+//
+//
+// Entry: Nothing.
+//
+// Returns: 0 if initialization failed, non-zero if it succeeds.
+//
+int
+IPInit()
+{
+ IPConfigInfo *ci; // Pointer to our IP configuration info.
+ int numnets; // Number of nets active.
+ int i;
+ uint j; // Counter variables.
+ NetTableEntry *nt; // Pointer to current NTE.
+ LLIPBindInfo *ARPInfo; // Info. returned from ARP.
+ NDIS_STATUS Status;
+ Interface *NetInterface; // Interface for a particular net.
+ LLIPRegRtn RegPtr;
+ NetTableEntry *lastNTE;
+
+
+ if (!CTEInitialize())
+ return IP_INIT_FAILURE;
+
+ CTERefillMem();
+
+ if ((ci = IPGetConfig()) == NULL)
+ return IP_INIT_FAILURE;
+
+#ifndef _PNP_POWER
+ MaxIPNets = ci->ici_numnets + 1;
+#endif // _PNP_POWER
+
+ for (ATCIndex=0; ATCIndex < ATC_SIZE; ATCIndex++) {
+ ATCache[ATCIndex].atc_flags = 0;
+ }
+ ATCIndex = 0;
+
+ // First, initalize our loopback stuff.
+ NetTableList = InitLoopback(ci);
+ if (NetTableList == NULL)
+ return IP_INIT_FAILURE;
+
+ if (!ARPInit()) {
+ CTEFreeMem(NetTableList);
+ return IP_INIT_FAILURE; // Couldn't initialize ARP.
+ }
+
+ CTERefillMem();
+ if (!InitRouting(ci)) {
+ CTEFreeMem(NetTableList);
+ return IP_INIT_FAILURE;
+ }
+
+ RATimeout = DEFAULT_RA_TIMEOUT;
+#if 0
+ CTEInitLock(&PILock);
+#endif
+ LastPI = IPProtInfo;
+
+
+ if (!ci->ici_gateway)
+ InterfaceSize = sizeof(Interface);
+ else
+ InterfaceSize = sizeof(RouteInterface);
+
+ DeadGWDetect = ci->ici_deadgwdetect;
+ PMTUDiscovery = ci->ici_pmtudiscovery;
+ IGMPLevel = ci->ici_igmplevel;
+ DefaultTTL = MIN(ci->ici_ttl, 255);
+ DefaultTOS = ci->ici_tos & 0xfc;
+ if (IGMPLevel > 2)
+ IGMPLevel = 0;
+
+ InitTimestamp();
+
+#ifndef _PNP_POWER
+ numnets = ci->ici_numnets;
+
+ lastNTE = NetTableList; // loopback is only one on the list
+ CTEAssert(lastNTE != NULL);
+ CTEAssert(lastNTE->nte_next == NULL);
+
+ // Loop through the config. info, copying the addresses and masks.
+ for (i = 0; i < numnets; i++) {
+
+ CTERefillMem();
+ nt = CTEAllocMem(sizeof(NetTableEntry));
+ if (nt == NULL)
+ continue;
+
+ CTEMemSet(nt, 0, sizeof(NetTableEntry));
+
+ nt->nte_addr = net_long(ci->ici_netinfo[i].nci_addr);
+ nt->nte_mask = net_long(ci->ici_netinfo[i].nci_mask);
+ nt->nte_mss = MAX(ci->ici_netinfo[i].nci_mtu, 68);
+ nt->nte_flags = (IP_ADDR_EQUAL(nt->nte_addr, NULL_IP_ADDR) ? 0 :
+ NTE_VALID);
+ nt->nte_flags |= NTE_ACTIVE;
+
+ CTEInitLock(&nt->nte_lock);
+ // If the address is invalid, skip it.
+ if (CLASSD_ADDR(nt->nte_addr) || CLASSE_ADDR(nt->nte_addr)) {
+ CTEFreeMem(nt);
+ continue;
+ }
+
+ // See if we're already bound to this adapter. If we are, use the same
+ // interface. Otherwise assign a new one. We assume that the loopback
+ // interface is IF 1, so there is one less than NumIF in the table.
+ for (j = 0; j < NumIF - 1; j++) {
+ if (CTEEqualString(&(AdptNameTable[j].nm_name),
+ &(ci->ici_netinfo[i].nci_name))) {
+
+ // Names match. Now check driver/types.
+ if (((ci->ici_netinfo[i].nci_type == NET_TYPE_LAN) &&
+ (AdptNameTable[j].nm_driver.Buffer == NULL)) ||
+ (CTEEqualString(&(AdptNameTable[j].nm_driver),
+ &(ci->ici_netinfo[i].nci_driver))))
+ break; // Found a match
+ }
+ }
+
+ if (j < (NumIF - 1)) {
+
+ // Found a match above, so use that interface.
+ CTERefillMem();
+ nt->nte_if = AdptNameTable[j].nm_interface;
+ ARPInfo = AdptNameTable[j].nm_arpinfo;
+ // If the Init of the interface or the NTE fails, we don't want to
+ // close the interface, because another net is using it.
+
+ if (!InitInterface(nt)) {
+ CTEFreeMem(nt);
+ continue;
+ }
+ if (!InitNTE(nt)) {
+ CTEFreeMem(nt);
+ continue;
+ }
+
+ } else { // No match, create a new interface
+
+ CTEAssert(NumIF <= MaxIPNets);
+
+ if (NumIF == MaxIPNets) {
+ continue; // too many adapters
+ }
+
+ CTERefillMem();
+
+ ARPInfo = CTEAllocMem(sizeof(LLIPBindInfo));
+
+ if (ARPInfo == NULL) {
+ CTEFreeMem(nt);
+ continue;
+ }
+
+ NetInterface = CTEAllocMem(
+ InterfaceSize +
+ ci->ici_netinfo[i].nci_configname.MaximumLength
+ );
+
+ if (!NetInterface) {
+ CTEFreeMem(ARPInfo);
+ CTEFreeMem(nt);
+ continue;
+ }
+
+ CTEMemSet(NetInterface, 0, InterfaceSize);
+
+ nt->nte_if = NetInterface;
+ nt->nte_flags |= NTE_PRIMARY; // He is the primary NTE.
+
+ CTEInitLock(&NetInterface->if_lock);
+
+ if (ci->ici_gateway) {
+ // Hack in the max pending value here. Probably should be
+ // done in iproute.c, but it's easier to do it here.
+
+ RouteInterface *RtIF;
+
+ RtIF = (RouteInterface *)NetInterface;
+ RtIF->ri_q.rsq_maxpending = ci->ici_netinfo[i].nci_maxpending;
+ }
+
+ // If this is a LAN, register with ARP.
+ if (ci->ici_netinfo[i].nci_type == NET_TYPE_LAN)
+ RegPtr = ARPRegister;
+ else
+ RegPtr = FindRegPtr(&ci->ici_netinfo[i].nci_driver);
+
+ if (RegPtr == NULL || !((*RegPtr)(&ci->ici_netinfo[i].nci_name,
+ nt, IPRcv, IPSendComplete, IPStatus, IPTDComplete,
+ IPRcvComplete, ARPInfo, NumIF))) {
+ CTEFreeMem(ARPInfo);
+ CTEFreeMem(NetInterface);
+ CTEFreeMem(nt);
+ continue; // We're hosed, skip this net.
+ }
+ else {
+
+ if (ci->ici_netinfo[i].nci_zerobcast)
+ NetInterface->if_bcast = IP_ZERO_BCST;
+ else
+ NetInterface->if_bcast = IP_LOCAL_BCST;
+
+ NetInterface->if_xmit = ARPInfo->lip_transmit;
+ NetInterface->if_transfer = ARPInfo->lip_transfer;
+ NetInterface->if_close = ARPInfo->lip_close;
+ NetInterface->if_invalidate = ARPInfo->lip_invalidate;
+ NetInterface->if_lcontext = ARPInfo->lip_context;
+ NetInterface->if_addaddr = ARPInfo->lip_addaddr;
+ NetInterface->if_deladdr = ARPInfo->lip_deladdr;
+ NetInterface->if_qinfo = ARPInfo->lip_qinfo;
+ NetInterface->if_setinfo = ARPInfo->lip_setinfo;
+ NetInterface->if_getelist = ARPInfo->lip_getelist;
+ NetInterface->if_tdpacket = NULL;
+ NetInterface->if_index = ARPInfo->lip_index;
+ NetInterface->if_mtu = ARPInfo->lip_mss - sizeof(IPHeader);
+ NetInterface->if_speed = ARPInfo->lip_speed;
+ NetInterface->if_flags = ARPInfo->lip_flags & LIP_P2P_FLAG ?
+ IF_FLAGS_P2P : 0;
+ NetInterface->if_addrlen = ARPInfo->lip_addrlen;
+ NetInterface->if_addr = ARPInfo->lip_addr;
+ NetInterface->if_pnpcontext = PNPContext;
+ NetInterface->if_llipflags = ArpInfo->lip_flags
+
+ NetInterface->if_configname.Buffer =
+ (PVOID) (((uchar *)NetInterface) + InterfaceSize);
+
+ NetInterface->if_configname.Length = 0;
+ NetInterface->if_configname.MaximumLength =
+ ci->ici_netinfo[i].nci_configname.MaximumLength;
+
+ CTECopyString(
+ &(NetInterface->if_configname),
+ &(ci->ici_netinfo[i].nci_configname)
+ );
+
+ CTERefillMem();
+
+ if (!InitInterface(nt)) {
+ CTEFreeMem(ARPInfo);
+ CTEFreeMem(NetInterface);
+ CTEFreeMem(nt);
+ continue;
+ }
+
+ if (!InitNTE(nt)) {
+ CTEFreeMem(ARPInfo);
+ CTEFreeMem(NetInterface);
+ CTEFreeMem(nt);
+ continue;
+ }
+
+ CTERefillMem();
+ if (!CTEAllocateString(&AdptNameTable[j].nm_name,
+ CTELengthString(&ci->ici_netinfo[i].nci_name))) {
+ CTEFreeMem(ARPInfo);
+ CTEFreeMem(NetInterface);
+ CTEFreeMem(nt);
+ continue;
+ }
+
+ if (ci->ici_netinfo[i].nci_type != NET_TYPE_LAN) {
+ if (!CTEAllocateString(&AdptNameTable[j].nm_driver,
+ CTELengthString(&ci->ici_netinfo[i].nci_driver))) {
+ CTEFreeString(&AdptNameTable[j].nm_name);
+ CTEFreeMem(ARPInfo);
+ CTEFreeMem(NetInterface);
+ CTEFreeMem(nt);
+ continue;
+ }
+ CTECopyString(&(AdptNameTable[j].nm_driver),
+ &(ci->ici_netinfo[i].nci_driver));
+ }
+
+ CTECopyString(&(AdptNameTable[j].nm_name),
+ &(ci->ici_netinfo[i].nci_name));
+ AdptNameTable[j].nm_interface = NetInterface;
+ AdptNameTable[j].nm_arpinfo = ARPInfo;
+ NetInterface->if_next = IFList;
+ IFList = NetInterface;
+ if (FirstIF == NULL)
+ FirstIF = NetInterface;
+ NumIF++;
+
+#ifdef NT
+ //
+ // Write the interface context to the registry for DHCP et al
+ //
+ if (ci->ici_netinfo[i].nci_reghandle != NULL) {
+ NTSTATUS writeStatus;
+ ulong context = (ulong) nt->nte_context;
+
+ writeStatus = SetRegDWORDValue(
+ ci->ici_netinfo[i].nci_reghandle,
+ L"IPInterfaceContext",
+ &context
+ );
+
+ if (!NT_SUCCESS(writeStatus)) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_DHCP_INIT_FAILED,
+ 2,
+ 1,
+ &(ci->ici_netinfo[i].nci_name.Buffer),
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP: Unable to write IPInterfaceContext value for adapter %ws\n"
+ " (status %lx). DHCP will be unable to configure this \n"
+ " adapter.\n",
+ ci->ici_netinfo[i].nci_name.Buffer,
+ writeStatus
+ ));
+ }
+ }
+#endif // NT
+ }
+ }
+
+ nt->nte_next = NULL;
+ lastNTE->nte_next = nt;
+ lastNTE = nt;
+ NumNTE++;
+
+ if (!InitNTERouting(nt, ci->ici_netinfo[i].nci_numgws,
+ ci->ici_netinfo[i].nci_gw)) {
+ // Couldn't add the routes for this NTE. Mark has as not valid.
+ // Probably should log an event here.
+ if (nt->nte_flags & NTE_VALID) {
+ nt->nte_flags &= ~NTE_VALID;
+ nt->nte_if->if_ntecount--;
+ }
+ }
+
+#ifdef NT
+ if (!IP_ADDR_EQUAL(nt->nte_addr, NULL_IP_ADDR)) {
+ SetPersistentRoutesForNTE(
+ net_long(nt->nte_addr),
+ net_long(nt->nte_mask),
+ nt->nte_if->if_index
+ );
+ }
+#endif // NT
+
+ }
+
+#endif // ndef PNP_POWER
+
+ if (NumNTE != 0) { // We have an NTE, and loopback initialized.
+ PNDIS_PACKET Packet;
+
+#ifdef _PNP_POWER
+ for (i=0; i<MAX_TDI_ENTITIES; i++) {
+ IFBitMask[i/BITS_PER_WORD] = 0;
+ }
+ IFBitMask[0] = 1;
+#endif
+
+ IPSInfo.ipsi_forwarding = (ci->ici_gateway ? IP_FORWARDING :
+ IP_NOT_FORWARDING);
+ IPSInfo.ipsi_defaultttl = DefaultTTL;
+ IPSInfo.ipsi_reasmtimeout = DEFAULT_RA_TIMEOUT;
+
+ // Allocate our packet pools.
+ CTEInitLock(&HeaderLock);
+#ifdef NT
+ ExInitializeSListHead(&PacketList);
+ ExInitializeSListHead(&HdrBufList);
+#endif
+
+
+ Packet = GrowIPPacketList();
+
+ if (Packet == NULL) {
+ CloseNets();
+ FreeNets();
+ IPFreeConfig(ci);
+ return IP_INIT_FAILURE;
+ }
+
+ (void)FreeIPPacket(Packet);
+
+ NdisAllocateBufferPool(&Status, &BufferPool, NUM_IP_NONHDR_BUFFERS);
+ if (Status != NDIS_STATUS_SUCCESS) {
+#ifdef DEBUG
+ DEBUGCHK;
+#endif
+ }
+
+ CTERefillMem();
+
+ ICMPInit(DEFAULT_ICMP_BUFFERS);
+ if (!IGMPInit())
+ IGMPLevel = 1;
+
+ // Should check error code, and log an event here if this fails.
+ CTERefillMem();
+ InitGateway(ci);
+
+ IPFreeConfig(ci);
+ CTERefillMem();
+
+#ifndef _PNP_POWER
+ OpenAdapters();
+ CleanAdaptTable(); // Clean up the adapter info we don't need.
+#endif
+
+ CTERefillMem();
+
+ // Loop through, initialize IGMP for each NTE.
+ for (nt = NetTableList; nt != NULL; nt = nt->nte_next)
+ InitIGMPForNTE(nt);
+
+ return IP_INIT_SUCCESS;
+ }
+ else {
+ FreeNets();
+ IPFreeConfig(ci);
+ return IP_INIT_FAILURE; // Couldn't initialize anything.
+ }
+}
+
+#pragma END_INIT
+
+
diff --git a/private/ntos/tdi/tcpip/ip/ipdef.h b/private/ntos/tdi/tcpip/ip/ipdef.h
new file mode 100644
index 000000000..9d93d0616
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/ipdef.h
@@ -0,0 +1,371 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1992 **/
+/********************************************************************/
+/* :ts=4 */
+#include "ipfilter.h"
+
+//** IPDEF.H - IP private definitions.
+//
+// This file contains all of the definitions for IP that
+// are private to IP, i.e. not visible to outside layers.
+
+// Internal error codes, not seen by IP uses.
+#define IP_OPTION_STRICT (MAX_IP_STATUS+1)
+
+#define CLASSA_ADDR(a) (( (*((uchar *)&(a))) & 0x80) == 0)
+#define CLASSB_ADDR(a) (( (*((uchar *)&(a))) & 0xc0) == 0x80)
+#define CLASSC_ADDR(a) (( (*((uchar *)&(a))) & 0xe0) == 0xc0)
+#define CLASSE_ADDR(a) ((( (*((uchar *)&(a))) & 0xf0) == 0xf0) && \
+ ((a) != 0xffffffff))
+
+#define CLASSA_MASK 0x000000ff
+#define CLASSB_MASK 0x0000ffff
+#define CLASSC_MASK 0x00ffffff
+#define CLASSD_MASK 0x000000e0
+#define CLASSE_MASK 0xffffffff
+
+#define IP_OPT_COPIED 0x80 // Bit indicating options is to be copied.
+#define IP_OPT_TYPE 0
+#define IP_OPT_LENGTH 1
+#define IP_OPT_DATA 2
+#define IP_OPT_PTR 2 // Pointer offset, for those options that have it.
+#define IP_TS_OVFLAGS 3 // Offset for overflow and flags.
+#define IP_TS_FLMASK 0xf // Mask for flags
+#define IP_TS_OVMASK 0xf0 // Mask for overflow field.
+#define IP_TS_MAXOV 0xf0 // Maximum value for the overflow field.
+#define IP_TS_INC 0x10 // Increment used on overflow field.
+
+#define MIN_RT_PTR 4
+#define MIN_TS_PTR 5
+
+#define TS_REC_TS 0 // Record TS option.
+#define TS_REC_ADDR 1 // Record TS and address.
+#define TS_REC_SPEC 3 // Only specified addresses record.
+
+#define OPT_SSRR 1 // We've seen a SSRR in this option buffer
+#define OPT_LSRR 2 // We've seen a LSRR in this option buffer
+#define OPT_RR 4 // We've seen a RR
+#define OPT_TS 8 // We've seen a TS.
+
+#define MAX_OPT_SIZE 40
+
+#define ALL_ROUTER_MCAST 0x020000E0
+
+// Received option index structure.
+struct OptIndex {
+ uchar oi_srindex;
+ uchar oi_rrindex;
+ uchar oi_tsindex;
+ uchar oi_srtype;
+}; /* OptIndex */
+
+typedef struct OptIndex OptIndex;
+
+#define MAX_HDR_SIZE (sizeof(IPHeader) + MAX_OPT_SIZE)
+
+#define DEFAULT_VERLEN 0x45 // Default version and length.
+
+#define IP_VERSION 0x40
+#define IP_VER_FLAG 0xF0
+
+#define IP_RSVD_FLAG 0x0080 // Reserved.
+#define IP_DF_FLAG 0x0040 // 'Don't fragment' flag
+#define IP_MF_FLAG 0x0020 // 'More fragments flag'
+
+
+#define IP_OFFSET_MASK ~0x00E0 // Mask for extracting offset field.
+
+typedef IP_STATUS (*ULRcvProc)(void *, IPAddr, IPAddr, IPAddr, IPAddr,
+ IPHeader UNALIGNED *, uint, IPRcvBuf *, uint,
+ uchar, uchar, IPOptInfo *);
+
+typedef uint (*ULStatusProc)(uchar, IP_STATUS, IPAddr, IPAddr, IPAddr, ulong, void *);
+
+//* Protocol information structure. These is one of there for each protocol bound
+// to an NTE.
+struct ProtInfo {
+ void (*pi_xmitdone)(void *, PNDIS_BUFFER); // Pointer to xmit done routine.
+ ULRcvProc pi_rcv; // Pointer to receive routine.
+ ULStatusProc pi_status; // Pointer to status handler.
+ void (*pi_rcvcmplt)(void); // Pointer to recv. cmplt handler.
+ uchar pi_protocol; // Protocol type.
+ uchar pi_pad[3]; // Pad to dword
+}; /* ProtInfo */
+
+typedef struct ProtInfo ProtInfo;
+
+//* Per-net information. We keep a variety of information for
+// each net, including the IP address, subnet mask, and reassembly
+// information.
+
+#define MAX_IP_PROT 5 // ICMP, IGMP, TCP, UDP, & Raw
+
+struct IPRtrEntry {
+ struct IPRtrEntry *ire_next;
+ IPAddr ire_addr;
+ long ire_preference;
+ ushort ire_lifetime;
+ ushort ire_pad;
+}; /* IPRtrEntry */
+
+typedef struct IPRtrEntry IPRtrEntry;
+
+struct NetTableEntry {
+ struct NetTableEntry *nte_next; // Next NTE of I/F.
+ IPAddr nte_addr; // IP address for this net.
+ IPMask nte_mask; // Subnet mask for this net.
+ struct Interface *nte_if; // Pointer to interface for this net.
+ struct NetTableEntry *nte_ifnext; // Linkage on if chain.
+ ushort nte_flags; // Flags for NTE.
+ ushort nte_context; // Context passed to upper layers.
+ ulong nte_instance; // Unique instance ID for this net
+ void *nte_pnpcontext; // PNP context.
+ DEFINE_LOCK_STRUCTURE(nte_lock)
+ struct ReassemblyHeader *nte_ralist; // Reassembly list.
+ struct EchoControl *nte_echolist; // List of pending echo control blocks
+ CTETimer nte_timer; // Timer for this net.
+ ushort nte_mss;
+ ushort nte_icmpseq; // ICMP seq. #
+ struct IGMPAddr *nte_igmplist; // List of mcast addresses.
+#ifdef _PNP_POWER
+ void *nte_addrhandle; // Handle for address registration.
+#endif
+ IPAddr nte_rtrdiscaddr; // Address used for Router Discovery
+ uchar nte_rtrdiscstate; // state of router solicitations
+ uchar nte_rtrdisccount; // router solicitation count
+ uchar nte_rtrdiscovery;
+ IPRtrEntry *nte_rtrlist;
+
+}; /* NetTableEntry */
+
+typedef struct NetTableEntry NetTableEntry;
+
+#define NTE_VALID 0x0001 // NTE is valid.
+#define NTE_COPY 0x0002 // For NDIS copy lookahead stuff.
+#define NTE_PRIMARY 0x0004 // This is the 'primary' NTE on the I/F.
+#define NTE_ACTIVE 0x0008 // NTE is active, i.e. interface is valid.
+#define NTE_DYNAMIC 0x0010 // NTE is was created dynamically
+
+#define IP_TIMEOUT 500
+
+#define NTE_RTRDISC_UNINIT 0
+#define NTE_RTRDISC_DELAYING 1
+#define NTE_RTRDISC_SOLICITING 2
+
+#define MAX_SOLICITATION_DELAY 2 // ticks to delay
+#define SOLICITATION_INTERVAL 6 // ticks between solicitations
+#define MAX_SOLICITATIONS 3 // number of solicitations
+
+struct AddrTypeCache {
+ IPAddr atc_addr; // IP Addr of cache entry
+ uchar atc_flags; // Valid flag
+ uchar atc_type; // Addr Type
+};
+
+typedef struct AddrTypeCache AddrTypeCache;
+
+#define ATC_SIZE 8
+#define ATC_MASK 7 // mask used to make sure indexes are less than ATC_SIZE
+
+//* Buffer reference structure. Used by broadcast and fragmentation code to
+// track multiple references to a single user buffer.
+struct BufferReference {
+ PNDIS_BUFFER br_buffer; // Pointer to uses buffer.
+ DEFINE_LOCK_STRUCTURE(br_lock)
+ int br_refcount; // Count of references to user's buffer.
+}; /* BufferReference */
+
+typedef struct BufferReference BufferReference;
+
+// Definitions of flags in pc_flags field
+#define PACKET_FLAG_OPTIONS 1 // Set if packet has an options buffer.
+#define PACKET_FLAG_IPBUF 2 // Set if packet is composed of IP buffers.
+#define PACKET_FLAG_RA 4 // Set if packet is being used for reassembly.
+#define PACKET_FLAG_FW 8 // Set if packet is a forwarding packet.
+#define PACKET_FLAG_IPHDR 0x10 // Packet uses an IP hdr buffer.
+
+//* Transfer data packet context. Used when TD'ing a packet - we store information for the
+// callback here.
+struct TDContext {
+ struct PCCommon tdc_common;
+ void *tdc_buffer; // Pointer to buffer containing data.
+ NetTableEntry *tdc_nte; // NTE to receive this on.
+ struct RABufDesc *tdc_rbd; // Pointer to RBD, if any.
+ uchar tdc_dtype; // Destination type of original address.
+ uchar tdc_hlength; // Length in bytes of header.
+ uchar tdc_pad[2];
+ uchar tdc_header[MAX_HDR_SIZE + 8];
+}; /* TDContext */
+
+typedef struct TDContext TDContext;
+
+//* Information about net interfaces. There can be multiple nets for each interface,
+// but there is exactly one interface per net.
+
+struct Interface {
+ struct Interface *if_next; // Next interface in chain.
+ void *if_lcontext; // Link layer context.
+ NDIS_STATUS (*if_xmit)(void *, PNDIS_PACKET, IPAddr, RouteCacheEntry *);
+ NDIS_STATUS (*if_transfer)(void *, NDIS_HANDLE, uint, uint, uint, PNDIS_PACKET,
+ uint *);
+ void (*if_close)(void *);
+ void (*if_invalidate)(void *, RouteCacheEntry *);
+ uint (*if_addaddr)(void *, uint, IPAddr, IPMask, void *);
+ void (*if_deladdr)(void *, uint, IPAddr, IPMask);
+ int (*if_qinfo)(void *, struct TDIObjectID *,
+ PNDIS_BUFFER, uint *, void *);
+ int (*if_setinfo)(void *, struct TDIObjectID *, void *,
+ uint);
+ int (*if_getelist)(void *, void *, uint *);
+ PNDIS_PACKET if_tdpacket; // Packet used for transferring data.
+ uint if_index; // Index of this interface.
+ uint if_ntecount; // Valid NTEs on this interface.
+ NetTableEntry *if_nte; // Pointer to list of NTE on interface.
+ IPAddr if_bcast; // Broadcast address for this interface.
+ uint if_mtu; // True maximum MTU for the interface.
+ uint if_speed; // Speed in bits/sec of this interface.
+ uint if_flags; // Flags for this interface.
+ INTERFACE_CONTEXT if_filtercontext; // Filter context for this i/f.
+ uint if_addrlen; // Length of i/f addr.
+ uchar *if_addr; // Pointer to addr.
+
+ uint IgmpVersion; //igmp version active on this interface
+ uint IgmpVer1Timeout; //Version 1 router present timeout
+#ifdef _PNP_POWER
+ uint if_refcount; // Reference count for this i/f.
+ CTEBlockStruc *if_block; // Block structure for PnP.
+ void *if_pnpcontext; // Context to pass to upper layers.
+#endif // _PNP_POWER
+
+ uint if_llipflags; // Lower layer flags
+#ifdef SECFLTR
+ NDIS_STRING if_configname; // Name of the i/f config section
+#endif //SECFLTR
+ DEFINE_LOCK_STRUCTURE(if_lock)
+}; /* Interface */
+
+typedef struct Interface Interface;
+
+/*NOINC*/
+extern void DerefIF(Interface *IF);
+/*INC*/
+
+#define IF_FLAGS_P2P 1 // Point to point interface
+#define IF_FLAGS_DELETING 2 // Interface is in the process of going
+ // away.
+
+// Structure of a reassembly buffer descriptor. Each RBD describes a fragment of the total
+// datagram
+struct RABufDesc {
+ IPRcvBuf rbd_buf; // IP receive buffer for this fragment.
+ ushort rbd_start; // Offset of first byte of this fragment.
+ ushort rbd_end; // Offset of last byte of this fragment.
+}; /* RABufDesc */
+
+typedef struct RABufDesc RABufDesc;
+
+// Reassembly header. The includes the information needed for the lookup, as well as space
+// for the received header and a chain of reassembly buffer descriptors.
+struct ReassemblyHeader {
+ struct ReassemblyHeader *rh_next; // Next header in chain.
+ IPAddr rh_dest; // Destination address of fragment.
+ IPAddr rh_src; // Source address of fragment.
+ ushort rh_id; // ID of datagram.
+ uchar rh_protocol; // Protocol of datagram.
+ uchar rh_ttl; // Remaining time of datagram.
+ RABufDesc *rh_rbd; // Chain of RBDs for this datagram.
+ ushort rh_datasize; // Total size of data.
+ ushort rh_datarcvd; // Amount of data received so far.
+ uint rh_headersize; // Size in bytes of header.
+ uchar rh_header[MAX_HDR_SIZE+8]; // Saved IP header of first fragment.
+}; /* ReassemblyHeader */
+
+typedef struct ReassemblyHeader ReassemblyHeader;
+
+// ICMP type and code definitions
+#define IP_DEST_UNREACH_BASE IP_DEST_NET_UNREACHABLE
+
+#define ICMP_REDIRECT 5 // Redirect
+#define ADDR_MASK_REQUEST 17 // Address mask request
+#define ADDR_MASK_REPLY 18
+#define ICMP_DEST_UNREACH 3 // Destination unreachable
+#define ICMP_TIME_EXCEED 11 // Time exceeded during reassembly
+#define ICMP_PARAM_PROBLEM 12 // Parameter problem
+#define ICMP_SOURCE_QUENCH 4 // Source quench
+#define ICMP_ROUTER_ADVERTISEMENT 9 // Router Advertisement
+#define ICMP_ROUTER_SOLICITATION 10 // Router Solicitation
+
+#define NET_UNREACH 0
+#define HOST_UNREACH 1
+#define PROT_UNREACH 2
+#define PORT_UNREACH 3
+#define FRAG_NEEDED 4
+#define SR_FAILED 5
+#define DEST_NET_UNKNOWN 6
+#define DEST_HOST_UNKNOWN 7
+#define SRC_ISOLATED 8
+#define DEST_NET_ADMIN 9
+#define DEST_HOST_ADMIN 10
+#define NET_UNREACH_TOS 11
+#define HOST_UNREACH_TOS 12
+
+#define TTL_IN_TRANSIT 0 // TTL expired in transit
+#define TTL_IN_REASSEM 1 // Time exceeded in reassembly
+
+
+#define PTR_VALID 0
+#define REQ_OPTION_MISSING 1
+
+#define REDIRECT_NET 0
+#define REDIRECT_HOST 1
+#define REDIRECT_NET_TOS 2
+#define REDIRECT_HOST_TOS 3
+
+extern uint DHCPActivityCount;
+
+extern IP_STATUS SetIFContext(uint Index, INTERFACE_CONTEXT *Context);
+
+extern IP_STATUS SetFilterPtr(IPPacketFilterPtr FilterPtr);
+
+extern IP_STATUS SetMapRoutePtr(IPMapRouteToInterfacePtr MapRoutePtr);
+
+#ifdef NT
+
+#ifdef POOL_TAGGING
+
+#ifdef ExAllocatePool
+#undef ExAllocatePool
+#endif
+
+#define ExAllocatePool(type, size) ExAllocatePoolWithTag(type, size, 'iPCT')
+
+#ifndef CTEAllocMem
+#error "CTEAllocMem is not already defined - will override tagging"
+#else
+#undef CTEAllocMem
+#endif
+
+#define CTEAllocMem(size) ExAllocatePoolWithTag(NonPagedPool, size, 'iPCT')
+
+#endif // POOL_TAGGING
+
+//
+// Use the TCP core checksum routine.
+//
+
+ULONG
+tcpxsum (
+ IN ULONG Checksum,
+ IN PUCHAR Source,
+ IN ULONG Length
+ );
+
+#define xsum(Buffer, Length) ((ushort) tcpxsum(0, (PUCHAR) (Buffer), (Length)))
+
+#else // NT
+
+extern ushort xsum(void *, int);
+
+#endif // NT
+
diff --git a/private/ntos/tdi/tcpip/ip/ipinit.h b/private/ntos/tdi/tcpip/ip/ipinit.h
new file mode 100644
index 000000000..d1d730915
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/ipinit.h
@@ -0,0 +1,155 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1992 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** IPINIT.H - IP initialization definitions.
+//
+// This file contains all of the definitions for IP that are
+// init. time specific.
+
+#define IP_INIT_FAILURE 0 // If we fail.
+#define IP_INIT_SUCCESS 1
+#define CFG_REQUIRED 1
+#define CFG_OPTIONAL 0
+
+
+#define NET_TYPE_LAN 0 // The local net interface is a LAN.
+#define NET_TYPE_WAN 1 // Point to point or other non-LAN network.
+#define DEFAULT_TTL 128
+#define DEFAULT_TOS 0
+
+#define MAX_DEFAULT_GWS 5 // Maximum number of default gateways per net.
+#define MAX_NAME_SIZE 32 // Maximum length of an adapter name.
+
+#define DEFAULT_FW_PACKETS 50 // Default number of packets for forwarding.
+#define DEFAULT_FW_BUFSIZE 74240 // Enough for 50 1480-byte Ethernet packets,
+ // rounded up to a multiple of 256.
+
+#define DEFAULT_MAX_FW_PACKETS 0xffffffff
+#define DEFAULT_MAX_FW_BUFSIZE 0xffffffff
+
+#define DEFAULT_MAX_PENDING 5000
+
+#define TR_RII_ALL 0x80
+#define TR_RII_SINGLE 0xC0
+
+#define DEFAULT_ARP_CACHE_LIFE (2L*60L) // 2 minutes
+
+#ifndef _PNP_POWER
+
+//* Per net config. information.
+struct NetConfigInfo {
+ IPAddr nci_addr; // IPAddr for this net.
+ IPMask nci_mask; // Net mask for this net.
+ uint nci_type; // Type of this net - Enet, TR, SLIP., etc.
+ NDIS_STRING nci_driver; // Device name for lower layer driver.
+ // Unused for NET_TYPE_LAN.
+ NDIS_STRING nci_name; // Name of adapter for this net.
+
+#ifdef SECFLTR
+ NDIS_STRING nci_configname; // Name of config section in registry.
+#endif // SECFLTR
+
+ uint nci_zerobcast; // Type of broadcast to be used on this net.
+
+#ifdef NT
+ HANDLE nci_reghandle; // Open handle to the registry key for
+ // this adapter.
+#endif // NT
+
+ uint nci_mtu; // Max MSS for this net.
+ uint nci_maxpending; // Max routing packets pending.
+ uint nci_numgws; // Number of default gateways for this interface.
+ IPAddr nci_gw[MAX_DEFAULT_GWS]; // Array of IPaddresses for gateways
+ uint nci_rtrdiscovery; // Router discovery enabled
+ IPAddr nci_rtrdiscaddr; // Multicast or BCast?
+}; /* NetConfigInfo */
+
+typedef struct NetConfigInfo NetConfigInfo;
+
+
+#else // _PNP_POWER
+
+/*NOINC*/
+
+
+// Per-net config structures for Chicago.
+typedef struct IFGeneralConfig {
+ uint igc_zerobcast; // Type of broadcast to be used on this net.
+ uint igc_mtu; // Max MSS for this net.
+ uint igc_maxpending; // Max FW pending on this IF.
+ uint igc_numgws; // Number of default gateways for this
+ // interface.
+ IPAddr igc_gw[MAX_DEFAULT_GWS]; // Array of IPaddresses for gateways
+ uint igc_rtrdiscovery; // Router discovery enabled
+ IPAddr igc_rtrdiscaddr; // Multicast or BCast?
+} IFGeneralConfig;
+
+typedef struct IFAddrList {
+ IPAddr ial_addr; // Address for this interface.
+ IPMask ial_mask; // Mask to go with this.
+} IFAddrList;
+
+
+/*INC*/
+
+#endif // _PNP_POWER
+
+//* Structure of configuration information. A pointer to this information
+// is returned from a system-specific config. information routine.
+struct IPConfigInfo {
+ uint ici_gateway; // 1 if we are a gateway, 0 otherwise
+ uint ici_fwbcast; // 1 if bcasts should be forwarded. Else 0.
+ uint ici_fwbufsize; // Total size of FW buf size.
+ uint ici_fwpackets; // Total number of FW packets to have.
+ uint ici_maxfwbufsize; // Maximum size of FW buffer.
+ uint ici_maxfwpackets; // Maximum number of FW packets.
+ uint ici_deadgwdetect; // True if we're doing dead GW detection.
+ uint ici_pmtudiscovery; // True if we're doing Path MTU discovery.
+ uint ici_igmplevel; // Level of IGMP we're doing.
+ uint ici_ttl; // Default TTL.
+ uint ici_tos; // Default TOS;
+
+#ifndef _PNP_POWER
+ int ici_numnets; // Number of nets present.
+ struct NetConfigInfo *ici_netinfo; // Per net config. info
+#endif // _PNP_POWER
+
+}; /* IPConfigInfo */
+
+typedef struct IPConfigInfo IPConfigInfo;
+
+
+#ifndef _PNP_POWER
+
+struct NameMapping {
+ NDIS_STRING nm_driver;
+ NDIS_STRING nm_name;
+ void *nm_interface;
+ void *nm_arpinfo;
+}; /* NameMapping */
+
+typedef struct NameMapping NameMapping;
+
+struct DriverRegMapping {
+ NDIS_STRING drm_driver;
+ void *drm_regptr;
+}; /* DriverRegMapping */
+
+typedef struct DriverRegMapping DriverRegMapping;
+
+#endif // _PNP_POWER
+extern uchar TrRii;
+
+
+struct SetAddrControl {
+ void *sac_rtn; // Pointer to routine to call when completing request.
+}; /* SetAddrControl */
+
+/*NOINC*/
+typedef struct SetAddrControl SetAddrControl;
+typedef void (*SetAddrRtn)(void *, IP_STATUS);
+/*INC*/
+
diff --git a/private/ntos/tdi/tcpip/ip/iploop.c b/private/ntos/tdi/tcpip/ip/iploop.c
new file mode 100644
index 000000000..b47676876
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/iploop.c
@@ -0,0 +1,665 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1992 **/
+/********************************************************************/
+/* :ts=4 */
+
+//*** iploop.c - IP loopback routines.
+//
+// This file contains all the routines related to loopback
+
+#include "oscfg.h"
+#include "cxport.h"
+#include "ndis.h"
+#include "ip.h"
+#include "tdistat.h"
+#include "ipdef.h"
+#include "ipinit.h"
+#include "llipif.h"
+#include "iprtdef.h"
+#include "iproute.h"
+#include "tdiinfo.h"
+#include "llinfo.h"
+
+#define LOOP_LOOKAHEAD MAX_HDR_SIZE + 8
+
+extern int NumNTE;
+
+extern Interface *IFList;
+extern uint NumIF;
+
+extern void IPRcv(void *, void *, uint, uint, NDIS_HANDLE, uint, uint);
+extern void IPSendComplete(void *, PNDIS_PACKET, NDIS_STATUS);
+extern void IPRcvComplete(void);
+extern PNDIS_BUFFER CopyToNdis(PNDIS_BUFFER DestBuf, uchar *SrcBuf, uint Size,
+ uint *StartOffset);
+
+DEFINE_LOCK_STRUCTURE(LoopLock)
+PNDIS_PACKET LoopXmitHead = (PNDIS_PACKET)NULL;
+PNDIS_PACKET LoopXmitTail = (PNDIS_PACKET)NULL;
+CTEEvent LoopXmitEvent;
+RouteInterface LoopInterface; // Loopback interface.
+uint LoopXmitRtnRunning = 0;
+
+
+#ifdef NT
+#ifdef ALLOC_PRAGMA
+//
+// Make init code disposable.
+//
+NetTableEntry *InitLoopback(IPConfigInfo *ConfigInfo);
+
+#pragma alloc_text(INIT, InitLoopback)
+
+#endif // ALLOC_PRAGMA
+#endif // NT
+
+
+uint LoopIndex; // Index of loop I/F.
+uint LoopInstance; // I/F instance of loopback I/F.
+NetTableEntry *LoopNTE; // Pointer to loopback NTE.
+
+IFEntry LoopIFE; // Loopback IF Entry.
+
+uchar LoopName[] = "MS TCP Loopback interface";
+
+uint LoopEntityType = IF_MIB;
+
+//* LoopXmitRtn - Loopback xmit event routine.
+//
+// This is the delayed event routine called for a loopback transmit.
+//
+// Entry: Event - Pointer to event structure.
+// Context - Pointer to loopback NTE
+//
+// Returns: Nothing.
+//
+void
+LoopXmitRtn(CTEEvent *Event, void *Context)
+{
+ PNDIS_PACKET Packet; // Pointer to packet being transmitted
+ CTELockHandle Handle;
+ PNDIS_BUFFER Buffer; // Current NDIS buffer being processed.
+ uint TotalLength; // Total length of send.
+ uint LookaheadLength; // Bytes in lookahead.
+ uint Copied; // Bytes copied so far.
+ uchar *CopyPtr; // Pointer to buffer being copied into.
+ uchar *SrcPtr; // Pointer to buffer being copied from.
+ uint SrcLength; // Length of src buffer.
+ uchar LookaheadBuffer[LOOP_LOOKAHEAD];
+ uchar Rcvd = FALSE;
+#ifdef NT
+ KIRQL OldIrql;
+
+
+ ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ //
+ // Raise IRQL so we can acquire locks at DPC level in the receive code.
+ //
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+#endif // NT
+
+ CTEGetLock(&LoopLock, &Handle);
+
+ if (LoopXmitRtnRunning) {
+ CTEFreeLock(&LoopLock, Handle);
+#ifdef NT
+ KeLowerIrql(OldIrql);
+#endif // NT
+ return;
+ }
+
+ LoopXmitRtnRunning = 1;
+
+ for (;;) {
+
+ Packet = LoopXmitHead; // Get the next packet from the list.
+ if (Packet != (PNDIS_PACKET)NULL) {
+ LoopXmitHead = *(PNDIS_PACKET *)Packet->MacReserved;
+ LoopIFE.if_outqlen--;
+ CTEFreeLock(&LoopLock, Handle);
+ } else { // Nothing left to do.
+ LoopXmitRtnRunning = 0;
+ CTEFreeLock(&LoopLock, Handle);
+ break;
+ }
+
+ NdisQueryPacket(Packet, NULL, NULL, &Buffer, &TotalLength);
+ LoopIFE.if_outoctets += TotalLength;
+ LoopIFE.if_inoctets += TotalLength;
+
+ // See if the interface is up. If it's not, we can't deliver it.
+ if (LoopIFE.if_adminstatus == IF_STATUS_UP) {
+ LookaheadLength = MIN(LOOP_LOOKAHEAD, TotalLength);
+ Copied = 0;
+ CopyPtr = LookaheadBuffer;
+ while (Copied < LookaheadLength) {
+ uint ThisCopy; // Bytes to copy this time.
+
+#ifdef DEBUG
+ if (!Buffer) {
+ DEBUGCHK;
+ CTEGetLock(&LoopLock, &Handle);
+ LoopXmitRtnRunning = 0;
+ CTEFreeLock(&LoopLock, Handle);
+#ifdef NT
+ KeLowerIrql(OldIrql);
+#endif // NT
+ return;
+ }
+#endif
+
+ NdisQueryBuffer(Buffer, &SrcPtr, &SrcLength);
+ ThisCopy = MIN(SrcLength, LookaheadLength - Copied);
+ CTEMemCopy(CopyPtr, SrcPtr, ThisCopy);
+ Copied += ThisCopy;
+ CopyPtr += ThisCopy;
+ NdisGetNextBuffer(Buffer, &Buffer);
+ }
+
+ Rcvd = TRUE;
+ LoopIFE.if_inucastpkts++;
+
+ IPRcv(Context, LookaheadBuffer, LookaheadLength, TotalLength,
+ (NDIS_HANDLE) Packet, 0, FALSE);
+
+ } else {
+ LoopIFE.if_indiscards++;
+ }
+
+ IPSendComplete(Context, Packet, NDIS_STATUS_SUCCESS);
+
+#ifdef NT
+ //
+ // Give other threads a chance to run.
+ //
+ KeLowerIrql(OldIrql);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+#endif // NT
+
+ CTEGetLock(&LoopLock, &Handle);
+ }
+
+ if (Rcvd) {
+ IPRcvComplete();
+ }
+
+#ifdef NT
+ KeLowerIrql(OldIrql);
+#endif // NT
+
+}
+
+//** LoopXmit - Transmit a loopback packet.
+//
+// This is the routine called when we need to transmit a packet to ourselves. We put
+// the packet on our loopback list, and schedule an event to deal with it.
+//
+// Entry: Context - Pointer to the loopback NTE.
+// Packet - Pointer to packet to be transmitted.
+// Dest - Destination addres of packet.
+// RCE - Pointer to RCE (should be NULL).
+//
+// Returns: NDIS_STATUS_PENDING
+//
+NDIS_STATUS
+LoopXmit(void *Context, PNDIS_PACKET Packet, IPAddr Dest, RouteCacheEntry *RCE)
+{
+ PNDIS_PACKET *PacketPtr;
+ CTELockHandle Handle;
+
+ LoopIFE.if_outucastpkts++;
+
+ if (LoopIFE.if_adminstatus == IF_STATUS_UP) {
+ PacketPtr = (PNDIS_PACKET *)Packet->MacReserved;
+ *PacketPtr = (PNDIS_PACKET)NULL;
+
+
+ CTEGetLock(&LoopLock, &Handle);
+ if (LoopXmitHead == (PNDIS_PACKET)NULL) { // Xmit. Q is empty
+ LoopXmitHead = Packet;
+ } else { // Xmit. Q is not empty
+ PacketPtr = (PNDIS_PACKET *)LoopXmitTail->MacReserved;
+ *PacketPtr = Packet;
+ }
+ LoopXmitTail = Packet;
+ LoopIFE.if_outqlen++;
+ if (!LoopXmitRtnRunning) {
+ CTEScheduleEvent(&LoopXmitEvent, Context);
+ }
+ CTEFreeLock(&LoopLock, Handle);
+ return NDIS_STATUS_PENDING;
+ } else {
+ LoopIFE.if_outdiscards++;
+ return NDIS_STATUS_SUCCESS;
+ }
+}
+
+//* LoopXfer - Loopback transfer data routine.
+//
+// Called when we need to transfer data for the loopback net. The input TDContext is
+// the original packet.
+//
+// Entry: Context - Pointer to loopback NTE.
+// TDContext - Original packet that was sent.
+// Dummy - Unused
+// Offset - Offset in frame from which to start copying.
+// BytesToCopy - Number of bytes to copy.
+// DestPacket - Packet describing buffer to copy into.
+// BytesCopied - Place to return bytes copied.
+//
+// Returns: NDIS_STATUS_SUCCESS
+//
+NDIS_STATUS
+LoopXfer(void *Context, NDIS_HANDLE TDContext, uint Dummy, uint Offset, uint BytesToCopy,
+ PNDIS_PACKET DestPacket, uint *BytesCopied)
+{
+ PNDIS_BUFFER SrcBuffer; // Current buffer we're copying from.
+ PNDIS_PACKET SrcPacket = (PNDIS_PACKET)TDContext;
+ uchar *SrcPtr; // Where we're copying from.
+ uint SrcLength; // Length of current src buffer.
+ PNDIS_BUFFER DestBuffer; // Buffer we're copying to.
+ uchar *DestPtr; // Where we're copying to.
+ uint DestLength; // Length of current dest. buffer.
+ uint Copied; // Length we've copied so far.
+
+ // First, skip over Offset bytes in the packet.
+ NdisQueryPacket(SrcPacket, NULL, NULL, &SrcBuffer, NULL);
+#ifdef DEBUG
+ if (!SrcBuffer)
+ DEBUGCHK;
+#endif
+ NdisQueryBuffer(SrcBuffer, &SrcPtr, &SrcLength);
+ while (Offset >= SrcLength) {
+ Offset -= SrcLength;
+ NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
+#ifdef DEBUG
+ if (!SrcBuffer)
+ DEBUGCHK;
+#endif
+ NdisQueryBuffer(SrcBuffer, &SrcPtr, &SrcLength);
+ }
+ // Update Src pointer and length.
+ SrcPtr += Offset;
+ SrcLength -= Offset;
+
+ // Set up the destination pointers and lengths.
+ NdisQueryPacket(DestPacket, NULL, NULL, &DestBuffer, NULL);
+ NdisQueryBuffer(DestBuffer, &DestPtr, &DestLength);
+ Copied = 0;
+
+ while (BytesToCopy) {
+ uint ThisCopy; // What we're copying this time.
+
+ ThisCopy = MIN(SrcLength, DestLength);
+ CTEMemCopy(DestPtr, SrcPtr, ThisCopy);
+ Copied += ThisCopy;
+ DestPtr += ThisCopy;
+ SrcPtr += ThisCopy;
+ BytesToCopy -= ThisCopy;
+ SrcLength -= ThisCopy;
+ DestLength -= ThisCopy;
+ if (!SrcLength) { // We've exhausted the source buffer.
+ NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
+ if (!SrcBuffer) {
+#ifdef DEBUG
+ if (BytesToCopy)
+ DEBUGCHK;
+#endif
+ break; // Copy is done.
+ }
+ NdisQueryBuffer(SrcBuffer, &SrcPtr, &SrcLength);
+ }
+ if (!DestLength) { // We've exhausted the destination buffer.
+ NdisGetNextBuffer(DestBuffer, &DestBuffer);
+ if (!DestBuffer) {
+#ifdef DEBUG
+ if (BytesToCopy)
+ DEBUGCHK;
+#endif
+ break; // Copy is done.
+ }
+ NdisQueryBuffer(DestBuffer, &DestPtr, &DestLength);
+ }
+ }
+
+ *BytesCopied = Copied;
+ return NDIS_STATUS_SUCCESS;
+
+
+}
+
+//* LoopClose - Loopback close routine.
+//
+// This is the loopback close routine. It does nothing but return.
+//
+// Entry: Context - Unused.
+//
+// Returns: Nothing.
+//
+void
+LoopClose(void *Context)
+{
+
+}
+
+//* LoopInvalidate - Invalidate an RCE.
+//
+// The loopback invalidate RCE routine. It also does nothing.
+//
+// Entry: Context - Unused.
+// RCE - Pointer to RCE to be invalidated.
+//
+// Returns: Nothing.
+//
+void
+LoopInvalidate(void *Context, RouteCacheEntry *RCE)
+{
+
+}
+
+//* LoopQInfo - Loopback query information handler.
+//
+// Called when the upper layer wants to query information about the loopback
+// interface.
+//
+// Input: IFContext - Interface context (unused).
+// ID - TDIObjectID for object.
+// Buffer - Buffer to put data into.
+// Size - Pointer to size of buffer. On return, filled with
+// bytes copied.
+// Context - Pointer to context block.
+//
+// Returns: Status of attempt to query information.
+//
+int
+LoopQInfo(void *IFContext, TDIObjectID *ID, PNDIS_BUFFER Buffer, uint *Size,
+ void *Context)
+{
+ uint Offset = 0;
+ uint BufferSize = *Size;
+ uint Entity;
+ uint Instance;
+
+
+ Entity = ID->toi_entity.tei_entity;
+ Instance = ID->toi_entity.tei_instance;
+
+ // First, make sure it's possibly an ID we can handle.
+ if (Entity != IF_ENTITY || Instance != LoopInstance) {
+ return TDI_INVALID_REQUEST;
+ }
+
+ *Size = 0; // In case of an error.
+
+ if (ID->toi_type != INFO_TYPE_PROVIDER)
+ return TDI_INVALID_PARAMETER;
+
+ if (ID->toi_class == INFO_CLASS_GENERIC) {
+ if (ID->toi_id == ENTITY_TYPE_ID) {
+ // He's trying to see what type we are.
+ if (BufferSize >= sizeof(uint)) {
+ (void)CopyToNdis(Buffer, (uchar *)&LoopEntityType, sizeof(uint),
+ &Offset);
+ return TDI_SUCCESS;
+ } else
+ return TDI_BUFFER_TOO_SMALL;
+ }
+ return TDI_INVALID_PARAMETER;
+ } else
+ if (ID->toi_class != INFO_CLASS_PROTOCOL)
+ return TDI_INVALID_PARAMETER;
+
+ // If he's asking for MIB statistics, then return them, otherwise fail
+ // the request.
+
+ if (ID->toi_id == IF_MIB_STATS_ID) {
+
+
+ // He's asking for statistics. Make sure his buffer is at least big
+ // enough to hold the fixed part.
+
+ if (BufferSize < IFE_FIXED_SIZE) {
+ return TDI_BUFFER_TOO_SMALL;
+ }
+
+ // He's got enough to hold the fixed part. Copy our IFE structure
+ // into his buffer.
+ Buffer = CopyToNdis(Buffer, (uchar *)&LoopIFE, IFE_FIXED_SIZE, &Offset);
+
+ // See if he has room for the descriptor string.
+ if (BufferSize >= (IFE_FIXED_SIZE + sizeof(LoopName))) {
+ // He has room. Copy it.
+ (void)CopyToNdis(Buffer, LoopName, sizeof(LoopName), &Offset);
+ *Size = IFE_FIXED_SIZE + sizeof(LoopName);
+ return TDI_SUCCESS;
+ } else {
+ // Not enough room to copy the desc. string.
+ *Size = IFE_FIXED_SIZE;
+ return TDI_BUFFER_OVERFLOW;
+ }
+
+ }
+
+ return TDI_INVALID_PARAMETER;
+
+}
+
+//* LoopSetInfo - Loopback set information handler.
+//
+// The loopback set information handler. We support setting of an I/F admin
+// status.
+//
+// Input: Context - Pointer to I/F to set on.
+// ID - The object ID
+// Buffer - Pointer to buffer containing value to set.
+// Size - Size in bytes of Buffer.
+//
+// Returns: Status of attempt to set information.
+//
+int
+LoopSetInfo(void *Context, TDIObjectID *ID, void *Buffer, uint Size)
+{
+ IFEntry *IFE = (IFEntry *)Buffer;
+ uint Entity, Instance, Status;
+
+ Entity = ID->toi_entity.tei_entity;
+ Instance = ID->toi_entity.tei_instance;
+
+ // First, make sure it's possibly an ID we can handle.
+ if (Entity != IF_ENTITY || Instance != LoopInstance) {
+ return TDI_INVALID_REQUEST;
+ }
+
+ if (ID->toi_class != INFO_CLASS_PROTOCOL ||
+ ID->toi_type != INFO_TYPE_PROVIDER) {
+ return TDI_INVALID_PARAMETER;
+ }
+
+ // It's for the I/F level, see if it's for the statistics.
+ if (ID->toi_id == IF_MIB_STATS_ID) {
+ // It's for the stats. Make sure it's a valid size.
+ if (Size >= IFE_FIXED_SIZE) {
+ // It's a valid size. See what he wants to do.
+ Status = IFE->if_adminstatus;
+ if (Status == IF_STATUS_UP || Status == IF_STATUS_DOWN)
+ LoopIFE.if_adminstatus = Status;
+ else
+ if (Status != IF_STATUS_TESTING)
+ return TDI_INVALID_PARAMETER;
+
+ return TDI_SUCCESS;
+
+ } else
+ return TDI_INVALID_PARAMETER;
+ }
+
+ return TDI_INVALID_PARAMETER;
+}
+
+//* LoopAddAddr - Dummy loopback add address routine.
+//
+// Called at init time when we need to initialize ourselves.
+//
+uint
+LoopAddAddr(void *Context, uint Type, IPAddr Address, IPMask Mask, void *Context2)
+{
+
+ return TRUE;
+}
+
+//* LoopDelAddr - Dummy loopback del address routine.
+//
+// Called at init time when we need to initialize ourselves.
+//
+uint
+LoopDelAddr(void *Context, uint Type, IPAddr Address, IPMask Mask)
+{
+
+ return TRUE;
+}
+
+#pragma BEGIN_INIT
+
+extern int InitNTE(NetTableEntry *);
+extern int InitInterface(NetTableEntry *);
+
+#ifdef CHICAGO
+#pragma END_INIT
+#pragma code_seg("_LTEXT", "LCODE")
+#endif
+
+//* LoopGetEList - Get the entity list.
+//
+// Called at init time to get an entity list. We fill our stuff in and return.
+//
+// Input: Context - Unused.
+// EntityList - Pointer to entity list to be filled in.
+// Count - Pointer to number of entries in the list.
+//
+// Returns Status of attempt to get the info.
+//
+int
+LoopGetEList(void *Context, TDIEntityID *EntityList, uint *Count)
+{
+ uint ECount;
+ uint MyIFBase;
+ uint i;
+
+ ECount = *Count;
+
+ // Walk down the list, looking for existing IF entities, and
+ // adjust our base instance accordingly.
+
+ MyIFBase = 0;
+ for (i = 0; i < ECount; i++, EntityList++) {
+ if (EntityList->tei_entity == IF_ENTITY)
+ MyIFBase = MAX(MyIFBase, EntityList->tei_instance + 1);
+ }
+
+ // EntityList points to the start of where we want to begin filling in.
+ // Make sure we have enough room.
+
+ if ((ECount + 1) > MAX_TDI_ENTITIES)
+ return FALSE;
+
+ // At this point we've figure out our base instance. Save for later use.
+ LoopInstance = MyIFBase;
+
+ // Now fill it in.
+ EntityList->tei_entity = IF_ENTITY;
+ EntityList->tei_instance = MyIFBase;
+ (*Count)++;
+
+ return TRUE;
+}
+
+#ifdef CHICAGO
+#pragma BEGIN_INIT
+#endif
+
+
+//** InitLoopback - Initialize the loopback NTE.
+//
+// This function initialized the loopback NTE. We set up the the MSS and pointer to
+// the various pseudo-link routines, then call InitNTE and return.
+//
+// Entry: ConfigInfo - Pointer to config. info structure.
+//
+// Returns: TRUE if we initialized, FALSE if we didn't.
+//
+NetTableEntry *
+InitLoopback(IPConfigInfo *ConfigInfo)
+{
+ LLIPBindInfo ARPInfo;
+
+ CTERefillMem();
+ LoopNTE = CTEAllocMem(sizeof(NetTableEntry));
+ if (LoopNTE == NULL)
+ return LoopNTE;
+
+ CTEMemSet(LoopNTE, 0, sizeof(NetTableEntry));
+
+ LoopNTE->nte_addr = LOOPBACK_ADDR;
+ LoopNTE->nte_mask = CLASSA_MASK;
+ LoopNTE->nte_icmpseq = 1;
+ LoopNTE->nte_flags = NTE_VALID | NTE_ACTIVE | NTE_PRIMARY;
+
+ CTEInitLock(&LoopNTE->nte_lock);
+ CTEInitLock(&LoopInterface.ri_if.if_lock);
+ LoopNTE->nte_mss = LOOPBACK_MSS;
+ LoopNTE->nte_if = (Interface *)&LoopInterface;
+ LoopInterface.ri_if.if_lcontext = LoopNTE;
+ LoopInterface.ri_if.if_xmit = LoopXmit;
+ LoopInterface.ri_if.if_transfer = LoopXfer;
+ LoopInterface.ri_if.if_close = LoopClose;
+ LoopInterface.ri_if.if_invalidate = LoopInvalidate;
+ LoopInterface.ri_if.if_qinfo = LoopQInfo;
+ LoopInterface.ri_if.if_setinfo = LoopSetInfo;
+ LoopInterface.ri_if.if_getelist = LoopGetEList;
+ LoopInterface.ri_if.if_addaddr = LoopAddAddr;
+ LoopInterface.ri_if.if_deladdr = LoopDelAddr;
+ LoopInterface.ri_if.if_bcast = IP_LOCAL_BCST;
+ LoopInterface.ri_if.if_speed = 10000000;
+ LoopInterface.ri_if.if_mtu = LOOPBACK_MSS;
+ LoopInterface.ri_if.if_llipflags = LIP_COPY_FLAG;
+#ifdef _PNP_POWER
+ LoopInterface.ri_if.if_refcount = 1;
+ LoopInterface.ri_if.if_pnpcontext = 0;
+#endif
+
+ ARPInfo.lip_mss = LOOPBACK_MSS + sizeof(IPHeader);
+ ARPInfo.lip_index = LoopIndex;
+ ARPInfo.lip_close = LoopClose;
+ ARPInfo.lip_addaddr = LoopAddAddr;
+ ARPInfo.lip_deladdr = LoopDelAddr;
+ ARPInfo.lip_flags = LIP_COPY_FLAG;
+ LoopIndex = NumIF + 1;
+ LoopInterface.ri_if.if_index = LoopIndex;
+ CTEInitEvent(&LoopXmitEvent, LoopXmitRtn);
+ CTEInitLock(&LoopLock);
+ LoopIFE.if_index = LoopIndex;
+ LoopIFE.if_type = IF_TYPE_LOOPBACK;
+ LoopIFE.if_mtu = ARPInfo.lip_mss;
+ LoopIFE.if_speed = 10000000;
+ LoopIFE.if_adminstatus = IF_STATUS_UP;
+ LoopIFE.if_operstatus = IF_STATUS_UP;
+ LoopIFE.if_descrlen = sizeof(LoopName);
+
+ IFList = (Interface *)&LoopInterface;
+ NumIF++;
+
+ NumNTE++;
+
+ if (!InitInterface(LoopNTE))
+ return NULL;
+
+ if (!InitNTE(LoopNTE))
+ return NULL;
+
+ return LoopNTE;
+}
+
+#pragma END_INIT
+
diff --git a/private/ntos/tdi/tcpip/ip/iprcv.c b/private/ntos/tdi/tcpip/ip/iprcv.c
new file mode 100644
index 000000000..791bc58f6
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/iprcv.c
@@ -0,0 +1,1145 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1992 **/
+/********************************************************************/
+/* :ts=4 */
+
+//*** iprcv.c - IP receive routines.
+//
+// This module contains all receive related IP routines.
+//
+
+
+#include "oscfg.h"
+#include "cxport.h"
+#include "ndis.h"
+#include "ip.h"
+#include "ipdef.h"
+#include "info.h"
+#include "iproute.h"
+#include "ipfilter.h"
+
+extern IP_STATUS SendICMPErr(IPAddr, IPHeader UNALIGNED *, uchar, uchar, ulong);
+
+extern uchar RATimeout;
+extern NDIS_HANDLE BufferPool;
+#if 0
+EXTERNAL_LOCK(PILock)
+#endif
+extern ProtInfo IPProtInfo[]; // Protocol information table.
+extern ProtInfo *LastPI; // Last protinfo structure looked at.
+extern int NextPI; // Next PI field to be used.
+extern ProtInfo *RawPI; // Raw IP protinfo
+extern NetTableEntry *NetTableList; // Pointer to the net table.
+
+DEBUGSTRING(RcvFile, "iprcv.c");
+
+#ifdef CHICAGO
+extern void RefillReasmMem(void);
+#endif
+
+//* FindUserRcv - Find the receive handler to be called for a particular protocol.
+//
+// This functions takes as input a protocol value, and returns a pointer to
+// the receive routine for that protocol.
+//
+// Input: NTE - Pointer to NetTableEntry to be searched
+// Protocol - Protocol to be searched for.
+// UContext - Place to returns UL Context value.
+//
+// Returns: Pointer to the receive routine.
+//
+ULRcvProc
+FindUserRcv(uchar Protocol)
+{
+ ULRcvProc RcvProc;
+ int i;
+#if 0
+ CTELockHandle Handle;
+
+
+ CTEGetLock(&PILock, &Handle);
+#endif
+
+ if (LastPI->pi_protocol == Protocol) {
+ RcvProc = LastPI->pi_rcv;
+#if 0
+ CTEFreeLock(&PILock, Handle);
+#endif
+ return RcvProc;
+ }
+
+ RcvProc = (ULRcvProc)NULL;
+ for ( i = 0; i < NextPI; i++) {
+ if (IPProtInfo[i].pi_protocol == Protocol) {
+ LastPI = &IPProtInfo[i];
+ RcvProc = IPProtInfo[i].pi_rcv;
+#if 0
+ CTEFreeLock(&PILock, Handle);
+#endif
+ return RcvProc;
+ }
+ }
+
+ //
+ // Didn't find a match. Use the raw protocol if it is registered.
+ //
+ if (RawPI != NULL) {
+ RcvProc = RawPI->pi_rcv;
+ }
+
+#if 0
+ CTEFreeLock(&PILock, Handle);
+#endif
+ return RcvProc;
+
+}
+
+//* IPRcvComplete - Handle a receive complete.
+//
+// Called by the lower layer when receives are temporarily done.
+//
+// Entry: Nothing.
+//
+// Returns: Nothing.
+//
+void
+IPRcvComplete(void)
+{
+ void (*ULRcvCmpltProc)(void);
+ int i;
+#if 0
+ CTELockHandle Handle;
+
+
+ CTEGetLock(&PILock, &Handle);
+#endif
+ for (i = 0; i < NextPI; i++) {
+ if ((ULRcvCmpltProc = IPProtInfo[i].pi_rcvcmplt) != NULL) {
+#if 0
+ CTEFreeLock(&PILock, Handle);
+#endif
+ (*ULRcvCmpltProc)();
+#if 0
+ CTEGetLock(&PILock, &Handle);
+#endif
+ }
+ }
+#if 0
+ CTEFreeLock(&PILock, Handle);
+#endif
+
+}
+//* FindRH - Look up a reassembly header on an NTE.
+//
+// A utility function to look up a reassembly header. We assume the lock on the NTE
+// is taken when we are called. If we find a matching RH we'll take the lock on it.
+// We also return the predeccessor of the RH, for use in insertion or deletion.
+//
+// Input: PrevRH - Place to return pointer to previous RH
+// NTE - NTE to be searched.
+// Dest - Destination IP address
+// Src - Src IP address
+// ID - ID of RH
+// Protocol - Protocol of RH
+//
+// Returns: Pointer to RH, or NULL if none.
+//
+ReassemblyHeader *
+FindRH(ReassemblyHeader **PrevRH, NetTableEntry *NTE, IPAddr Dest, IPAddr Src, ushort Id,
+ uchar Protocol)
+{
+ ReassemblyHeader *TempPrev, *Current;
+
+ TempPrev = STRUCT_OF(ReassemblyHeader, &NTE->nte_ralist, rh_next);
+ Current = NTE->nte_ralist;
+ while (Current != (ReassemblyHeader *)NULL) {
+ if (Current->rh_dest == Dest && Current->rh_src == Src && Current->rh_id == Id &&
+ Current->rh_protocol == Protocol)
+ break;
+ TempPrev = Current;
+ Current = Current->rh_next;
+ }
+
+ *PrevRH = TempPrev;
+ return Current;
+
+}
+
+//* ParseRcvdOptions - Validate incoming options.
+//
+// Called during reception handling to validate incoming options. We make sure that everything
+// is OK as best we can, and find indices for any source route option.
+//
+// Input: OptInfo - Pointer to option info. structure.
+// Index - Pointer to optindex struct to be filled in.
+//
+//
+// Returns: Index of error if any, MAX_OPT_SIZE if no errors.
+//
+uchar
+ParseRcvdOptions(IPOptInfo *OptInfo, OptIndex *Index)
+{
+ uint i= 0; // Index variable.
+ uchar *Options = OptInfo->ioi_options;
+ uint OptLength = (uint)OptInfo->ioi_optlength;
+ uchar Length; // Length of option.
+ uchar Pointer; // Pointer field, for options that use it.
+
+ while(i < OptLength && *Options != IP_OPT_EOL) {
+ if (*Options == IP_OPT_NOP) {
+ i++;
+ Options++;
+ continue;
+ }
+ if (((Length = Options[IP_OPT_LENGTH]) + i) > OptLength) {
+ return (uchar)i + (uchar)IP_OPT_LENGTH; // Length exceeds options length.
+ }
+
+ Pointer = Options[IP_OPT_DATA] - 1;
+
+ if (*Options == IP_OPT_TS) {
+ if (Length < (MIN_TS_PTR - 1))
+ return (uchar)i + (uchar)IP_OPT_LENGTH;
+ Index->oi_tsindex = (uchar)i;
+ } else {
+ if (Length < (MIN_RT_PTR - 1))
+ return (uchar)i + (uchar)IP_OPT_LENGTH;
+
+ if (*Options == IP_OPT_LSRR || *Options == IP_OPT_SSRR) {
+ // A source route option
+ if (Pointer < Length) { // Route not complete
+
+ if ((Length - Pointer) < sizeof(IPAddr))
+ return (uchar)i + (uchar)IP_OPT_LENGTH;
+
+ Index->oi_srtype = *Options;
+ Index->oi_srindex = (uchar)i;
+ }
+ } else {
+ if (*Options == IP_OPT_RR) {
+ if (Pointer < Length)
+ Index->oi_rrindex = (uchar)i;
+ }
+ }
+ }
+
+ i += Length;
+ Options += Length;
+ }
+
+ return MAX_OPT_SIZE;
+}
+
+//* BCastRcv - Receive a broadcast or multicast packet.
+//
+// Called when we have to receive a broadcast packet. We loop through the NTE table,
+// calling the upper layer receive protocol for each net which matches the receive I/F
+// and for which the destination address is a broadcast.
+//
+// Input: RcvProc - The receive procedure to be called.
+// SrcNTE - NTE on which the packet was originally received.
+// DestAddr - Destination address.
+// SrcAddr - Source address of packet.
+// Data - Pointer to received data.
+// DataLength - Size in bytes of data
+// Protocol - Upper layer protocol being called.
+// OptInfo - Pointer to received IP option info.
+//
+// Returns: Nothing.
+//
+void
+BCastRcv(ULRcvProc RcvProc, NetTableEntry *SrcNTE, IPAddr DestAddr,
+ IPAddr SrcAddr, IPHeader UNALIGNED *Header, uint HeaderLength,
+ IPRcvBuf *Data, uint DataLength, uchar Protocol, IPOptInfo *OptInfo)
+{
+ NetTableEntry *CurrentNTE;
+ const Interface *SrcIF = SrcNTE->nte_if;
+ ulong Delivered = 0;
+
+
+ for (CurrentNTE = NetTableList;
+ CurrentNTE != NULL;
+ CurrentNTE = CurrentNTE->nte_next)
+ {
+ if ((CurrentNTE->nte_flags & NTE_ACTIVE) &&
+ (CurrentNTE->nte_if == SrcIF) &&
+ IS_BCAST_DEST(IsBCastOnNTE(DestAddr, CurrentNTE)))
+ {
+ Delivered = 1;
+
+ (*RcvProc)(CurrentNTE, DestAddr, SrcAddr, CurrentNTE->nte_addr,
+ SrcNTE->nte_addr, Header, HeaderLength, Data, DataLength,
+ TRUE, Protocol, OptInfo);
+ }
+ }
+
+ if (Delivered) {
+ IPSInfo.ipsi_indelivers++;
+ }
+}
+
+//* DeliverToUser - Deliver data to a user protocol.
+//
+// This procedure is called when we have determined that an incoming packet belongs
+// here, and any options have been processed. We accept it for upper layer processing,
+// which means looking up the receive procedure and calling it, or passing it to BCastRcv
+// if neccessary.
+//
+// Input: SrcNTE - Pointer to NTE on which packet arrived.
+// DestNTE - Pointer to NTE that is accepting packet.
+// Header - Pointer to IP header of packet.
+// HeaderLength - Length of Header in bytes.
+// Data - Pointer to IPRcvBuf chain.
+// DataLength - Length in bytes of upper layer data.
+// OptInfo - Pointer to Option information for this receive.
+// DestType - Type of destination - LOCAL, BCAST.
+//
+// Returns: Nothing.
+void
+DeliverToUser(NetTableEntry *SrcNTE, NetTableEntry *DestNTE,
+ IPHeader UNALIGNED *Header, uint HeaderLength, IPRcvBuf *Data,
+ uint DataLength, IPOptInfo *OptInfo, uchar DestType)
+{
+ ULRcvProc rcv;
+
+#ifdef DEBUG
+ if (DestType >= DEST_REMOTE)
+ DEBUGCHK;
+#endif
+
+ // Process this request right now. Look up the protocol. If we
+ // find it, copy the data if we need to, and call the protocol's
+ // receive handler. If we don't find it, send an ICMP
+ // 'protocol unreachable' message.
+ rcv = FindUserRcv(Header->iph_protocol);
+ if (rcv != NULL) {
+ IP_STATUS Status;
+
+ if (DestType == DEST_LOCAL) {
+ Status = (*rcv)(SrcNTE,Header->iph_dest, Header->iph_src,
+ DestNTE->nte_addr, SrcNTE->nte_addr, Header,
+ HeaderLength, Data, DataLength, FALSE,
+ Header->iph_protocol, OptInfo);
+
+ if (Status == IP_SUCCESS) {
+ IPSInfo.ipsi_indelivers++;
+ return;
+ }
+
+ if (Status == IP_DEST_PROT_UNREACHABLE) {
+ IPSInfo.ipsi_inunknownprotos++;
+ SendICMPErr(DestNTE->nte_addr, Header, ICMP_DEST_UNREACH,
+ PROT_UNREACH, 0);
+ }
+ else {
+ IPSInfo.ipsi_indelivers++;
+ SendICMPErr(DestNTE->nte_addr, Header, ICMP_DEST_UNREACH,
+ PORT_UNREACH, 0);
+ }
+
+ return; // Just return out of here now.
+ }
+ else {
+ BCastRcv(rcv, SrcNTE, Header->iph_dest, Header->iph_src,
+ Header, HeaderLength, Data, DataLength,
+ Header->iph_protocol, OptInfo);
+ }
+
+ } else {
+ IPSInfo.ipsi_inunknownprotos++;
+ // If we get here, we didn't find a matching protocol. Send an ICMP message.
+ SendICMPErr(DestNTE->nte_addr, Header, ICMP_DEST_UNREACH, PROT_UNREACH, 0);
+ }
+
+}
+
+//* FreeRH - Free a reassembly header.
+//
+// Called when we need to free a reassembly header, either because of a timeout or because
+// we're done with it.
+//
+// Input: RH - RH to be freed.
+//
+// Returns: Nothing.
+//
+void
+FreeRH(ReassemblyHeader *RH)
+{
+ RABufDesc *RBD, *TempRBD;
+
+ RBD = RH->rh_rbd;
+ while (RBD != NULL) {
+ TempRBD = RBD;
+ RBD = (RABufDesc *)RBD->rbd_buf.ipr_next;
+ CTEFreeMem(TempRBD);
+ }
+ CTEFreeMem(RH);
+
+}
+
+//* ReassembleFragment - Put a fragment into the reassembly list.
+//
+// This routine is called once we've put a fragment into the proper buffer. We look for
+// a reassembly header for the fragment. If we don't find one, we create one. Otherwise
+// we search the reassembly list, and insert the datagram in it's proper place.
+//
+// Input: NTE - NTE to reassemble on.
+// SrcNTE - NTE datagram arrived on.
+// NewRBD - New RBD to be inserted.
+// IPH - Pointer to header of datagram.
+// HeaderSize - Size in bytes of header.
+// DestType - Type of destination address.
+//
+// Returns: Nothing.
+//
+void
+ReassembleFragment(NetTableEntry *NTE, NetTableEntry *SrcNTE, RABufDesc *NewRBD,
+ IPHeader UNALIGNED *IPH, uint HeaderSize, uchar DestType)
+{
+ CTELockHandle NTEHandle; // Lock handle used for NTE
+ ReassemblyHeader *RH, *PrevRH; // Current and previous reassembly headers.
+ RABufDesc *PrevRBD; // Previous RBD in reassembly header list.
+ RABufDesc *CurrentRBD;
+ ushort DataLength = (ushort)NewRBD->rbd_buf.ipr_size, DataOffset;
+ ushort Offset; // Offset of this fragment.
+ ushort NewOffset; // Offset we'll copy from after checking RBD list.
+ ushort NewEnd; // End offset of fragment, after trimming (if any).
+
+ // If this is a broadcast, go ahead and forward it now.
+ if (IS_BCAST_DEST(DestType))
+ IPForward(SrcNTE, IPH, HeaderSize, NewRBD->rbd_buf.ipr_buffer,
+ NewRBD->rbd_buf.ipr_size, NULL, 0, DestType);
+
+
+ // We've got the buffer we need. Now get the reassembly header, if there is one. If
+ // there isn't, create one.
+ CTEGetLockAtDPC(&NTE->nte_lock, &NTEHandle);
+ RH = FindRH(&PrevRH, NTE, IPH->iph_dest, IPH->iph_src, IPH->iph_id, IPH->iph_protocol);
+ if (RH == (ReassemblyHeader *)NULL) { // Didn't find one, so create one.
+ ReassemblyHeader *NewRH;
+
+ CTEFreeLockFromDPC(&NTE->nte_lock, NTEHandle);
+ RH = CTEAllocMem(sizeof(ReassemblyHeader));
+ if (RH == (ReassemblyHeader *)NULL) { // Couldn't get a buffer.
+#ifdef CHICAGO
+ RefillReasmMem();
+#endif
+ IPSInfo.ipsi_reasmfails++;
+ CTEFreeMem(NewRBD);
+ return;
+ }
+
+ CTEGetLockAtDPC(&NTE->nte_lock, &NTEHandle);
+ // Need to look it up again - it could have changed during above call.
+ NewRH = FindRH(&PrevRH, NTE, IPH->iph_dest, IPH->iph_src, IPH->iph_id, IPH->iph_protocol);
+ if (NewRH != (ReassemblyHeader *)NULL) {
+ CTEFreeMem(RH);
+ RH = NewRH;
+ } else {
+
+ RH->rh_next = PrevRH->rh_next;
+ PrevRH->rh_next = RH;
+
+
+ // Initialize our new reassembly header.
+ RH->rh_dest = IPH->iph_dest;
+ RH->rh_src = IPH->iph_src;
+ RH->rh_id = IPH->iph_id;
+ RH->rh_protocol = IPH->iph_protocol;
+ RH->rh_ttl = RATimeout;
+ RH->rh_datasize = 0xffff; // Default datasize to maximum.
+ RH->rh_rbd = (RABufDesc *)NULL; // And nothing on chain.
+ RH->rh_datarcvd = 0; // Haven't received any data yet.
+ RH->rh_headersize = 0;
+
+ }
+ }
+
+ // When we reach here RH points to the reassembly header we want to use.
+ // and we hold locks on the NTE and the RH. If this is the first fragment we'll save
+ // the options and header information here.
+
+ Offset = IPH->iph_offset & IP_OFFSET_MASK;
+ Offset = net_short(Offset) * 8;
+
+ if (Offset == 0) { // First fragment.
+ RH->rh_headersize = HeaderSize;
+ CTEMemCopy(RH->rh_header, IPH, HeaderSize + 8);
+ }
+
+ // If this is the last fragment, update the amount of data we expect to received.
+ if (!(IPH->iph_offset & IP_MF_FLAG))
+ RH->rh_datasize = Offset + DataLength;
+
+ // Update the TTL value with the maximum of the current TTL and the incoming
+ // TTL (+1, to deal with rounding errors).
+ RH->rh_ttl = MAX(RH->rh_ttl, MIN(254, IPH->iph_ttl) + 1);
+
+ // Now we need to see where in the RBD list to put this.
+ //
+ // The idea is to go through the list of RBDs one at a time. The RBD currently
+ // being examined is CurrentRBD. If the start offset of the new fragment is less
+ // than (i.e. in front of) the offset of CurrentRBD, we need to insert the NewRBD
+ // in front of the CurrentRBD. If this is the case we need to check and see if the
+ // end of the new fragment overlaps some or all of the fragment described by
+ // CurrentRBD, and possibly subsequent fragment. If it overlaps part of a fragment
+ // we'll adjust our end down to be in front of the existing fragment. If it overlaps
+ // all of the fragment we'll free the old fragment.
+ //
+ // If the new fragment does not start in front of the current fragment we'll check
+ // to see if it starts somewhere in the middle of the current fragment. If this
+ // isn't the case, we move on the the next fragment. If this is the case, we check
+ // to see if the current fragment completely covers the new fragment. If not we
+ // move our start up and continue with the next fragment.
+
+ NewOffset = Offset;
+ NewEnd = Offset + DataLength - 1;
+ PrevRBD = STRUCT_OF(RABufDesc, STRUCT_OF(IPRcvBuf, &RH->rh_rbd, ipr_next), rbd_buf);
+ CurrentRBD = RH->rh_rbd;
+ for (; CurrentRBD != NULL; PrevRBD = CurrentRBD, CurrentRBD = (RABufDesc *)CurrentRBD->rbd_buf.ipr_next) {
+
+ // See if it starts in front of this fragment.
+ if (NewOffset < CurrentRBD->rbd_start) {
+ // It does start in front. Check to see if there's any overlap.
+
+ if (NewEnd < CurrentRBD->rbd_start)
+ break; // No overlap, so get out.
+ else {
+ // It does overlap. While we have overlap, walk down the list
+ // looking for RBDs we overlap completely. If we find one, put it
+ // on our deletion list. If we have overlap but not complete overlap,
+ // move our end down if front of the fragment we overlap.
+ do {
+ if (NewEnd > CurrentRBD->rbd_end) { // This overlaps completely.
+ RABufDesc *TempRBD;
+
+ RH->rh_datarcvd -= CurrentRBD->rbd_buf.ipr_size;
+ TempRBD = CurrentRBD;
+ CurrentRBD = (RABufDesc *)CurrentRBD->rbd_buf.ipr_next;
+ CTEFreeMem(TempRBD);
+ } else // Only partial ovelap.
+ NewEnd = CurrentRBD->rbd_start - 1;
+ // Update of NewEnd will force us out of loop.
+
+ } while (CurrentRBD != NULL && NewEnd >= CurrentRBD->rbd_start);
+ break;
+ }
+ } else {
+ // This fragment doesn't go in front of the current RBD. See if it is
+ // entirely beyond the end of the current fragment. If it is, just
+ // continue. Otherwise see if the current fragment completely subsumes
+ // us. If it does, get out, otherwise update our start offset and
+ // continue.
+
+ if (NewOffset > CurrentRBD->rbd_end)
+ continue; // No overlap at all.
+ else {
+ if (NewEnd <= CurrentRBD->rbd_end) {
+ // The current fragment overlaps the new fragment totally. Set
+ // our offsets so that we'll skip the copy below.
+ NewEnd = NewOffset - 1;
+ break;
+ } else // Only partial overlap.
+ NewOffset = CurrentRBD->rbd_end + 1;
+ }
+ }
+ } // End of for loop.
+
+ // Adjust the length and offset fields in the new RBD.
+ DataLength = NewEnd - NewOffset + 1;
+ DataOffset = NewOffset - Offset;
+ // Link him in chain.
+ NewRBD->rbd_buf.ipr_size = (uint)DataLength;
+ NewRBD->rbd_end = NewEnd;
+ NewRBD->rbd_start = NewOffset;
+ RH->rh_datarcvd += DataLength;
+ NewRBD->rbd_buf.ipr_buffer += DataOffset;
+ NewRBD->rbd_buf.ipr_next = (IPRcvBuf *)CurrentRBD;
+ PrevRBD->rbd_buf.ipr_next = &NewRBD->rbd_buf;
+
+ // If we've received all the data, deliver it to the user.
+ if (RH->rh_datarcvd == RH->rh_datasize) { // We have it all.
+ IPOptInfo OptInfo;
+ IPHeader *Header;
+ IPRcvBuf *FirstBuf;
+
+ PrevRH->rh_next = RH->rh_next;
+ CTEFreeLockFromDPC(&NTE->nte_lock, NTEHandle);
+ Header = (IPHeader *)RH->rh_header;
+ OptInfo.ioi_ttl = Header->iph_ttl;
+ OptInfo.ioi_tos = Header->iph_tos;
+ OptInfo.ioi_flags = 0; // Flags must be 0 - DF can't be set, this was reassembled.
+
+ if (RH->rh_headersize != sizeof(IPHeader)) { // We had options.
+ OptInfo.ioi_options = (uchar *)(Header + 1);
+ OptInfo.ioi_optlength = RH->rh_headersize - sizeof(IPHeader);
+ } else {
+ OptInfo.ioi_options = (uchar *)NULL;
+ OptInfo.ioi_optlength = 0;
+ }
+
+ // Make sure that the first buffer contains enough data.
+ FirstBuf = (IPRcvBuf *)RH->rh_rbd;
+ while (FirstBuf->ipr_size < MIN_FIRST_SIZE) {
+ IPRcvBuf *NextBuf = FirstBuf->ipr_next;
+ uint CopyLength;
+
+ if (NextBuf == NULL)
+ break;
+
+ CopyLength = MIN(MIN_FIRST_SIZE - FirstBuf->ipr_size,
+ NextBuf->ipr_size);
+ CTEMemCopy(FirstBuf->ipr_buffer + FirstBuf->ipr_size,
+ NextBuf->ipr_buffer, CopyLength);
+ FirstBuf->ipr_size += CopyLength;
+ NextBuf->ipr_buffer += CopyLength;
+ NextBuf->ipr_size -= CopyLength;
+ if (NextBuf->ipr_size == 0) {
+ FirstBuf->ipr_next = NextBuf->ipr_next;
+ CTEFreeMem(NextBuf);
+ }
+ }
+
+ IPSInfo.ipsi_reasmoks++;
+ DeliverToUser(SrcNTE, NTE, Header, RH->rh_headersize, FirstBuf,
+ RH->rh_datasize, &OptInfo, DestType);
+ FreeRH(RH);
+ } else
+ CTEFreeLockFromDPC(&NTE->nte_lock, NTEHandle);
+
+
+}
+
+//* RATDComplete - Completion routing for a reassembly transfer data.
+//
+// This is the completion handle for TDs invoked because we are reassembling a fragment.
+//
+// Input: NetContext - Pointer to the net table entry on which we received this.
+// Packet - Packet we received into.
+// Status - Final status of copy.
+// DataSize - Size in bytes of data transferred.
+//
+// Returns: Nothing
+//
+void
+RATDComplete(void *NetContext, PNDIS_PACKET Packet, NDIS_STATUS Status, uint DataSize)
+{
+ NetTableEntry *NTE = (NetTableEntry *)NetContext;
+ Interface *SrcIF;
+ TDContext *Context = (TDContext *)Packet->ProtocolReserved;
+ CTELockHandle Handle;
+ PNDIS_BUFFER Buffer;
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ Context->tdc_rbd->rbd_buf.ipr_size = DataSize;
+ ReassembleFragment(Context->tdc_nte, NTE, Context->tdc_rbd,
+ (IPHeader *)Context->tdc_header, Context->tdc_hlength, Context->tdc_dtype);
+ }
+
+ NdisUnchainBufferAtFront(Packet, &Buffer);
+ NdisFreeBuffer(Buffer);
+ Context->tdc_common.pc_flags &= ~PACKET_FLAG_RA;
+ SrcIF = NTE->nte_if;
+ CTEGetLockAtDPC(&SrcIF->if_lock, &Handle);
+
+ Context->tdc_common.pc_link = SrcIF->if_tdpacket;
+ SrcIF->if_tdpacket = Packet;
+ CTEFreeLockFromDPC(&SrcIF->if_lock, Handle);
+
+ return;
+
+}
+
+//* IPReassemble - Reassemble an incoming datagram.
+//
+// Called when we receive an incoming fragment. The first thing we do is get a buffer
+// to put the fragment in. If we can't we'll exit. Then we copy the data, either via
+// transfer data or directly if it all fits.
+//
+// Input: SrcNTE - Pointer to NTE that received the datagram.
+// NTE - Pointer to NTE on which to reassemble.
+// IPH - Pointer to header of packet.
+// HeaderSize - Size in bytes of header.
+// Data - Pointer to data part of fragment.
+// BufferLength - Length in bytes of user data available in the buffer.
+// DataLength - Length in bytes of the (upper-layer) data.
+// DestType - Type of destination
+// LContext1, LContext2 - Link layer context values.
+//
+// Returns: Nothing.
+//
+void
+IPReassemble(NetTableEntry *SrcNTE, NetTableEntry *NTE, IPHeader UNALIGNED *IPH,
+ uint HeaderSize,
+ uchar *Data, uint BufferLength, uint DataLength, uchar DestType, NDIS_HANDLE LContext1,
+ uint LContext2)
+{
+ Interface *RcvIF;
+ PNDIS_PACKET TDPacket; // NDIS packet used for TD.
+ TDContext *TDC = (TDContext *)NULL; // Transfer data context.
+ NDIS_STATUS Status;
+ PNDIS_BUFFER Buffer;
+ RABufDesc *NewRBD; // Pointer to new RBD to hold arriving fragment.
+ CTELockHandle Handle;
+ uint AllocSize;
+
+ IPSInfo.ipsi_reasmreqds++;
+
+ // First, get a new RBD to hold the arriving fragment. If we can't, then just skip
+ // the rest. The RBD has the buffer implicitly at the end of it. The buffer for the
+ // first fragment must be at least MIN_FIRST_SIZE bytes.
+ if ((IPH->iph_offset & IP_OFFSET_MASK) == 0)
+ AllocSize = MAX(MIN_FIRST_SIZE, DataLength);
+ else
+ AllocSize = DataLength;
+
+ NewRBD = CTEAllocMem(sizeof(RABufDesc) + AllocSize);
+
+ if (NewRBD != (RABufDesc *)NULL) {
+
+ NewRBD->rbd_buf.ipr_buffer = (uchar *)(NewRBD + 1);
+ NewRBD->rbd_buf.ipr_size = DataLength;
+ NewRBD->rbd_buf.ipr_owner = IPR_OWNER_IP;
+
+ // Copy the data into the buffer. If we need to call transfer data do so now.
+ if (DataLength > BufferLength) { // Need to call transfer data.
+ NdisAllocateBuffer(&Status, &Buffer, BufferPool, NewRBD + 1, DataLength);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ IPSInfo.ipsi_reasmfails++;
+ CTEFreeMem(NewRBD);
+ return;
+ }
+
+ // Now get a packet for transferring the frame.
+ RcvIF = SrcNTE->nte_if;
+ CTEGetLockAtDPC(&RcvIF->if_lock, &Handle);
+ TDPacket = RcvIF->if_tdpacket;
+
+ if (TDPacket != (PNDIS_PACKET)NULL) {
+
+ TDC = (TDContext *)TDPacket->ProtocolReserved;
+ RcvIF->if_tdpacket = TDC->tdc_common.pc_link;
+ CTEFreeLockFromDPC(&RcvIF->if_lock, Handle);
+
+ TDC->tdc_common.pc_flags |= PACKET_FLAG_RA;
+ TDC->tdc_nte = NTE;
+ TDC->tdc_dtype = DestType;
+ TDC->tdc_hlength = (uchar)HeaderSize;
+ TDC->tdc_rbd = NewRBD;
+ CTEMemCopy(TDC->tdc_header, IPH, HeaderSize + 8);
+ NdisChainBufferAtFront(TDPacket, Buffer);
+ Status = (*(RcvIF->if_transfer))(RcvIF->if_lcontext, LContext1, LContext2,
+ HeaderSize, DataLength, TDPacket, &DataLength);
+ if (Status != NDIS_STATUS_PENDING)
+ RATDComplete(SrcNTE, TDPacket, Status, DataLength);
+ else
+ return;
+ } else { // Couldn't get a TD packet.
+ CTEFreeLockFromDPC(&RcvIF->if_lock, Handle);
+ CTEFreeMem(NewRBD);
+ IPSInfo.ipsi_reasmfails++;
+ return;
+ }
+ } else { // It all fits, copy it.
+ CTEMemCopy(NewRBD + 1, Data, DataLength);
+ ReassembleFragment(NTE, SrcNTE, NewRBD, IPH, HeaderSize, DestType);
+ }
+ } else {
+#ifdef CHICAGO
+ RefillReasmMem();
+#endif
+
+ IPSInfo.ipsi_reasmfails++;
+ }
+
+ return;
+}
+
+
+
+//* CheckLocalOptions - Check the options received with a packet.
+//
+// A routine called when we've received a packet for this host and want to examine
+// it for options. We process the options, and return TRUE or FALSE depending on whether
+// or not it's for us.
+//
+// Input: SrcNTE - Pointer to NTE this came in on.
+// Header - Pointer to incoming header.
+// OptInfo - Place to put opt info.
+// DestType - Type of incoming packet.
+//
+// Returns: DestType - Local or remote.
+//
+uchar
+CheckLocalOptions(NetTableEntry *SrcNTE, IPHeader UNALIGNED *Header,
+ IPOptInfo *OptInfo, uchar DestType)
+{
+ uint HeaderLength; // Length in bytes of header.
+ OptIndex Index;
+ uchar ErrIndex;
+
+#ifdef DEBUG
+ if (DestType >= DEST_REMOTE)
+ DEBUGCHK;
+#endif
+
+
+ HeaderLength = (Header->iph_verlen & (uchar)~IP_VER_FLAG) << 2;
+
+#ifdef DEBUG
+ if (HeaderLength <= sizeof(IPHeader))
+ DEBUGCHK;
+#endif
+
+ OptInfo->ioi_options = (uchar *)(Header + 1);
+ OptInfo->ioi_optlength = HeaderLength - sizeof(IPHeader);
+
+
+ // We have options of some sort. The packet may or may not be bound for us.
+ Index.oi_srindex = MAX_OPT_SIZE;
+ if ((ErrIndex = ParseRcvdOptions(OptInfo, &Index)) < MAX_OPT_SIZE) {
+ SendICMPErr(SrcNTE->nte_addr, Header, ICMP_PARAM_PROBLEM, PTR_VALID,
+ ((ulong)ErrIndex + sizeof(IPHeader)));
+ return DEST_INVALID; // Parameter error.
+ }
+
+ // If there's no source route, or if the destination is a broadcast, we'll take
+ // it. If it is a broadcast DeliverToUser will forward it when it's done, and
+ // the forwarding code will reprocess the options.
+ if (Index.oi_srindex == MAX_OPT_SIZE || IS_BCAST_DEST(DestType))
+ return DEST_LOCAL;
+ else
+ return DEST_REMOTE;
+
+}
+
+//* TDUserRcv - Completion routing for a user transfer data.
+//
+// This is the completion handle for TDs invoked because we need to give data to a
+// upper layer client. All we really do is call the upper layer handler with
+// the data.
+//
+// Input: NetContext - Pointer to the net table entry on which we received this.
+// Packet - Packet we received into.
+// Status - Final status of copy.
+// DataSize - Size in bytes of data transferred.
+//
+// Returns: Nothing
+//
+void
+TDUserRcv(void *NetContext, PNDIS_PACKET Packet, NDIS_STATUS Status,
+ uint DataSize)
+{
+ NetTableEntry *NTE = (NetTableEntry *)NetContext;
+ Interface *SrcIF;
+ TDContext *Context = (TDContext *)Packet->ProtocolReserved;
+ CTELockHandle Handle;
+ uchar DestType;
+ IPRcvBuf RcvBuf;
+ IPOptInfo OptInfo;
+ IPHeader *Header;
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ Header = (IPHeader *)Context->tdc_header;
+ OptInfo.ioi_ttl = Header->iph_ttl;
+ OptInfo.ioi_tos = Header->iph_tos;
+ OptInfo.ioi_flags = (net_short(Header->iph_offset) >> 13) & IP_FLAG_DF;
+ if (Context->tdc_hlength != sizeof(IPHeader)) {
+ OptInfo.ioi_options = (uchar *)(Header + 1);
+ OptInfo.ioi_optlength = Context->tdc_hlength - sizeof(IPHeader);
+ } else {
+ OptInfo.ioi_options = (uchar *)NULL;
+ OptInfo.ioi_optlength = 0;
+ }
+
+ DestType = Context->tdc_dtype;
+ RcvBuf.ipr_next = NULL;
+ RcvBuf.ipr_owner = IPR_OWNER_IP;
+ RcvBuf.ipr_buffer = (uchar *)Context->tdc_buffer;
+ RcvBuf.ipr_size = DataSize;
+
+ DeliverToUser(NTE, Context->tdc_nte, Header, Context->tdc_hlength,
+ &RcvBuf, DataSize, &OptInfo, DestType);
+ // If it's a broadcast packet forward it on.
+ if (IS_BCAST_DEST(DestType))
+ IPForward(NTE, Header, Context->tdc_hlength, RcvBuf.ipr_buffer, DataSize,
+ NULL, 0, DestType);
+ }
+
+ SrcIF = NTE->nte_if;
+ CTEGetLockAtDPC(&SrcIF->if_lock, &Handle);
+
+ Context->tdc_common.pc_link = SrcIF->if_tdpacket;
+ SrcIF->if_tdpacket = Packet;
+ CTEFreeLockFromDPC(&SrcIF->if_lock, Handle);
+
+ return;
+
+}
+
+
+//* IPRcv - Receive an incoming IP datagram.
+//
+// This is the routine called by the link layer module when an incoming IP
+// datagram is to be processed. We validate the datagram (including doing
+// the xsum), copy and process incoming options, and decide what to do with it.
+//
+// Entry: MyContext - The context valued we gave to the link layer.
+// Data - Pointer to the data buffer.
+// DataSize - Size in bytes of the data buffer.
+// TotalSize - Total size in bytes available.
+// LContext1 - 1st link context.
+// LContext2 - 2nd link context.
+// BCast - Indicates whether or not packet was received on bcast address.
+//
+// Returns: Nothing.
+//
+void
+IPRcv(void *MyContext, void *Data, uint DataSize, uint TotalSize, NDIS_HANDLE LContext1,
+ uint LContext2, uint BCast)
+{
+ IPHeader UNALIGNED *IPH = (IPHeader UNALIGNED *)Data;
+ NetTableEntry *NTE = (NetTableEntry *)MyContext; // Local NTE received on
+ NetTableEntry *DestNTE; // NTE to receive on.
+ Interface *RcvIF; // Interface corresponding to NTE.
+ CTELockHandle Handle;
+ PNDIS_PACKET TDPacket; // NDIS packet used for TD.
+ TDContext *TDC = (TDContext *)NULL; // Transfer data context.
+ NDIS_STATUS Status;
+ IPAddr DAddr; // Dest. IP addr. of received packet.
+ uint HeaderLength; // Size in bytes of received header.
+ uint IPDataLength; // Length in bytes of IP (including UL) data in packet.
+ IPOptInfo OptInfo; // Incoming header information.
+ uchar DestType; // Type (LOCAL, REMOTE, SR) of Daddr.
+ IPRcvBuf RcvBuf;
+
+#if 0
+ CTECheckMem(RcvFile); // Check heap status.
+#endif
+
+ IPSInfo.ipsi_inreceives++;
+
+ // Make sure we actually have data.
+ if (DataSize) {
+
+ // Check the header length, the xsum and the version. If any of these
+ // checks fail silently discard the packet.
+ HeaderLength = ((IPH->iph_verlen & (uchar)~IP_VER_FLAG) << 2);
+ if (HeaderLength >= sizeof(IPHeader) && HeaderLength <= DataSize &&
+ xsum(Data, HeaderLength) == (ushort)0xffff) {
+
+ // Check the version, and sanity check the total length.
+ IPDataLength = (uint)net_short(IPH->iph_length);
+ if ((IPH->iph_verlen & IP_VER_FLAG) == IP_VERSION &&
+ IPDataLength > sizeof(IPHeader) && IPDataLength <= TotalSize) {
+
+ IPDataLength -= HeaderLength;
+ Data = (uchar *)Data + HeaderLength;
+ DataSize -= HeaderLength;
+
+ DAddr = IPH->iph_dest;
+ DestNTE = NTE;
+
+ // Find local NTE, if any.
+ DestType = GetLocalNTE(DAddr, &DestNTE);
+
+ // Check to see if this is a non-broadcast IP address that
+ // came in as a link layer broadcast. If it is, throw it out.
+ // This is an important check for DHCP, since if we're
+ // DHCPing an interface all otherwise unknown addresses will
+ // come in as DEST_LOCAL. This check here will throw them out
+ // if they didn't come in as unicast.
+
+ if (BCast && !IS_BCAST_DEST(DestType)) {
+ IPSInfo.ipsi_inhdrerrors++;
+ return; // Non bcast packet on bcast address.
+ }
+
+ OptInfo.ioi_ttl = IPH->iph_ttl;
+ OptInfo.ioi_tos = IPH->iph_tos;
+ OptInfo.ioi_flags = (net_short(IPH->iph_offset) >> 13) &
+ IP_FLAG_DF;
+ OptInfo.ioi_options = (uchar *)NULL;
+ OptInfo.ioi_optlength = 0;
+
+ if (DestType < DEST_REMOTE) {
+ // It's either local or some sort of broadcast.
+
+ // The data probably belongs at this station. If there
+ // aren't any options, it definetly belongs here, and we'll
+ // dispatch it either to our reasssmbly code or to the
+ // deliver to user code. If there are options, we'll check
+ // them and then either handle the packet locally or pass it
+ // to our forwarding code.
+
+ if (HeaderLength != sizeof(IPHeader)) {
+ // We have options.
+
+ uchar NewDType;
+ NewDType = CheckLocalOptions(NTE, IPH, &OptInfo,
+ DestType);
+ if (NewDType != DEST_LOCAL) {
+ if (NewDType == DEST_REMOTE)
+ goto forward;
+ else {
+ IPSInfo.ipsi_inhdrerrors++;
+ return; // Bad Options.
+ }
+ }
+ }
+
+ // Before we go further, if we have a filter installed
+ // call it to see if we should take this.
+
+ if (ForwardFilterPtr != NULL) {
+ FORWARD_ACTION Action;
+
+ Action = (*ForwardFilterPtr)(IPH,
+ Data,
+ DataSize,
+ NTE->nte_if->if_filtercontext,
+ NULL);
+
+ if (Action != FORWARD) {
+ IPSInfo.ipsi_indiscards++;
+ return;
+ }
+ }
+
+ // No options. See if it's a fragment. If it is, call our
+ // reassembly handler.
+ if ((IPH->iph_offset & ~(IP_DF_FLAG | IP_RSVD_FLAG)) == 0) {
+
+ // We don't have a fragment. If the data all fits,
+ // handle it here. Otherwise transfer data it.
+
+#ifdef VXD
+ if (IPDataLength > DataSize) {
+ // Data isn't all in the buffer.
+#else
+ // Make sure data is all in buffer, and directly
+ // accesible.
+ if ((IPDataLength > DataSize) ||
+ !(NTE->nte_flags & NTE_COPY)) {
+#endif
+ // The data isn't all here. Transfer data it.
+ RcvIF = NTE->nte_if;
+ CTEGetLockAtDPC(&RcvIF->if_lock, &Handle);
+ TDPacket = RcvIF->if_tdpacket;
+
+ if (TDPacket != (PNDIS_PACKET)NULL) {
+
+ TDC = (TDContext *)TDPacket->ProtocolReserved;
+ RcvIF->if_tdpacket = TDC->tdc_common.pc_link;
+ CTEFreeLockFromDPC(&RcvIF->if_lock, Handle);
+
+ TDC->tdc_nte = DestNTE;
+ TDC->tdc_dtype = DestType;
+ TDC->tdc_hlength = (uchar)HeaderLength;
+ CTEMemCopy(TDC->tdc_header, IPH,
+ HeaderLength + 8);
+ Status = (*(RcvIF->if_transfer))(
+ RcvIF->if_lcontext, LContext1,
+ LContext2, HeaderLength, IPDataLength,
+ TDPacket, &IPDataLength);
+
+ // Check the status. If it's success, call the
+ // receive procedure. Otherwise, if it's pending
+ // wait for the callback.
+ Data = TDC->tdc_buffer;
+ if (Status != NDIS_STATUS_PENDING) {
+ if (Status != NDIS_STATUS_SUCCESS) {
+ IPSInfo.ipsi_indiscards++;
+ CTEGetLockAtDPC(&RcvIF->if_lock, &Handle);
+ TDC->tdc_common.pc_link =
+ RcvIF->if_tdpacket;
+ RcvIF->if_tdpacket = TDPacket;
+ CTEFreeLockFromDPC(&RcvIF->if_lock,
+ Handle);
+ return;
+ }
+ } else
+ return; // Status is pending.
+ } else { // Couldn't get a packet.
+ IPSInfo.ipsi_indiscards++;
+ CTEFreeLockFromDPC(&RcvIF->if_lock, Handle);
+ return;
+ }
+ }
+
+ RcvBuf.ipr_next = NULL;
+ RcvBuf.ipr_owner = IPR_OWNER_IP;
+ RcvBuf.ipr_buffer = (uchar *)Data;
+ RcvBuf.ipr_size = IPDataLength;
+ // When we get here, we have the whole packet. Deliver
+ // it.
+ DeliverToUser(NTE, DestNTE, IPH, HeaderLength, &RcvBuf,
+ IPDataLength, &OptInfo, DestType);
+ // When we're here, we're through with the packet
+ // locally. If it's a broadcast packet forward it on.
+ if (IS_BCAST_DEST(DestType)) {
+ IPForward(NTE, IPH, HeaderLength, Data, IPDataLength,
+ NULL, 0, DestType);
+ }
+ if (TDC != NULL) {
+ CTEGetLockAtDPC(&RcvIF->if_lock, &Handle);
+ TDC->tdc_common.pc_link = RcvIF->if_tdpacket;
+ RcvIF->if_tdpacket = TDPacket;
+ CTEFreeLockFromDPC(&RcvIF->if_lock, Handle);
+ }
+ return;
+ } else {
+ // This is a fragment. Reassemble it.
+ IPReassemble(NTE, DestNTE, IPH, HeaderLength, Data,
+ DataSize, IPDataLength, DestType, LContext1,
+ LContext2);
+ return;
+ }
+
+ }
+
+ // Not for us, may need to be forwarded. It might be an outgoing
+ // broadcast that came in through a source route, so we need to
+ // check that.
+forward:
+ if (DestType != DEST_INVALID)
+ IPForward(NTE, IPH, HeaderLength, Data, DataSize,
+ LContext1, LContext2, DestType);
+ else
+ IPSInfo.ipsi_inaddrerrors++;
+ return;
+ } // Bad version
+ } // Bad checksum
+
+ } // No data
+
+ IPSInfo.ipsi_inhdrerrors++;
+}
+
+//* IPTDComplete - IP Transfer data complete handler.
+//
+// This is the routine called by the link layer when a transfer data completes.
+//
+// Entry: MyContext - Context value we gave to the link layer.
+// Packet - Packet we originally gave to transfer data.
+// Status - Final status of command.
+// BytesCopied - Number of bytes copied.
+//
+// Exit: Nothing
+//
+void
+IPTDComplete(void *MyContext, PNDIS_PACKET Packet, NDIS_STATUS Status, uint BytesCopied)
+{
+ TDContext *TDC = (TDContext *)Packet->ProtocolReserved;
+
+ if (!(TDC->tdc_common.pc_flags & PACKET_FLAG_FW))
+ if (!(TDC->tdc_common.pc_flags & PACKET_FLAG_RA))
+ TDUserRcv(MyContext, Packet, Status, BytesCopied);
+ else
+ RATDComplete(MyContext, Packet, Status, BytesCopied);
+ else
+ SendFWPacket(Packet, Status, BytesCopied);
+
+
+}
diff --git a/private/ntos/tdi/tcpip/ip/iproute.c b/private/ntos/tdi/tcpip/ip/iproute.c
new file mode 100644
index 000000000..3a0bb109d
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/iproute.c
@@ -0,0 +1,4703 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1995 **/
+/********************************************************************/
+/* :ts=4 */
+
+//*** iproute.c - IP routing routines.
+//
+// This file contains all the routines related to IP routing, including
+// routing table lookup and management routines.
+
+#include "oscfg.h"
+#include "cxport.h"
+#include "ndis.h"
+#include "ip.h"
+#include "ipdef.h"
+#include "ipinit.h"
+#include "info.h"
+#include "tdistat.h"
+#include "iproute.h"
+#include "iprtdef.h"
+#include "ipxmit.h"
+#include "igmp.h"
+#include "tdiinfo.h"
+#include "ipfilter.h"
+
+extern NetTableEntry *NetTableList; // Pointer to the net table.
+extern NetTableEntry *DHCPNTE; // Pointer to NTE being DHCP'd.
+
+extern NetTableEntry *LoopNTE; // Pointer to loopback NTE.
+extern Interface LoopInterface; // Pointer to loopback interface.
+
+extern AddrTypeCache ATCache[];
+extern int ATCIndex;
+
+extern IP_STATUS SendICMPErr(IPAddr, IPHeader UNALIGNED *, uchar, uchar, ulong);
+extern uchar ParseRcvdOptions(IPOptInfo *, OptIndex *);
+extern void ULMTUNotify(IPAddr Dest, IPAddr Src, uchar Prot, void *Ptr,
+ uint NewMTU);
+
+extern Interface *IFList;
+extern Interface *FirstIF;
+
+#define ROUTE_TABLE_SIZE 32 // Size of the route table.
+DEFINE_LOCK_STRUCTURE(RouteTableLock)
+
+#define FWPACKET_GROW_AMOUNT 20
+
+#define FW_BUF_SIZE 256 // Size of a forwarding buffer.
+
+#define FW_BUF_GROW_AMOUNT 30720 // Enough for 20 Ethernet packets.
+
+#define NO_SR 0
+
+RouteTableEntry *RouteTable[ROUTE_TABLE_SIZE];
+
+DEFINE_LOCK_STRUCTURE(FWPacketFreeLock)
+DEFINE_LOCK_STRUCTURE(FWBufFreeLock)
+
+PNDIS_PACKET FWPacketFree; // Free list of forwarding packets.
+PNDIS_BUFFER FWBufFree; // Free list of forwarding buffers.
+
+uint MaxFWPackets; // Maximum number of forward packets allowed.
+uint CurrentFWPackets; // Number of forwarding packets currently
+ // allocated.
+uint MaxFWBufferSize; // Maximum number of forwarding buffers allowed.
+uint CurrentFWBufferSize; // Number of forwarding buffers allocated.
+
+uchar ForwardPackets; // Flag indicating whether we should forward.
+uchar RouterConfigured; // TRUE if we were initially
+ // configured as a router.
+uchar ForwardBCast; // Flag indicating if we should forward bcasts.
+RouteSendQ *BCastRSQ;
+
+uint DefGWConfigured; // Number of default gateways configed.
+uint DefGWActive; // Number of def. gateways active.
+
+uint DeadGWDetect;
+uint PMTUDiscovery;
+
+ProtInfo *RtPI = NULL;
+
+IPMask IPMaskTable[] = {
+ CLASSA_MASK,
+ CLASSA_MASK,
+ CLASSA_MASK,
+ CLASSA_MASK,
+ CLASSA_MASK,
+ CLASSA_MASK,
+ CLASSA_MASK,
+ CLASSA_MASK,
+ CLASSB_MASK,
+ CLASSB_MASK,
+ CLASSB_MASK,
+ CLASSB_MASK,
+ CLASSC_MASK,
+ CLASSC_MASK,
+ CLASSD_MASK,
+ CLASSE_MASK };
+
+extern void TransmitFWPacket(PNDIS_PACKET, uint);
+
+uint MTUTable[] = {
+
+ 65535 - sizeof(IPHeader),
+ 32000 - sizeof(IPHeader),
+ 17914 - sizeof(IPHeader),
+ 8166 - sizeof(IPHeader),
+ 4352 - sizeof(IPHeader),
+ 2002 - sizeof(IPHeader),
+ 1492 - sizeof(IPHeader),
+ 1006 - sizeof(IPHeader),
+ 508 - sizeof(IPHeader),
+ 296 - sizeof(IPHeader),
+ MIN_VALID_MTU - sizeof(IPHeader)
+};
+
+CTETimer IPRouteTimer;
+
+// Pointer to callout routine for dial on demand.
+IPMapRouteToInterfacePtr DODCallout;
+
+// Pointer to packet filter handler.
+IPPacketFilterPtr ForwardFilterPtr;
+
+RouteInterface DummyInterface; // Dummy interface.
+
+#ifdef NT
+#ifdef ALLOC_PRAGMA
+//
+// Make init code disposable.
+//
+int InitRouting(IPConfigInfo *ci);
+
+#pragma alloc_text(INIT, InitRouting)
+
+#endif // ALLOC_PRAGMA
+#endif // NT
+
+
+#define InsertAfterRTE(P, R) (R)->rte_next = (P)->rte_next;\
+ (P)->rte_next = (R)
+
+#define InsertRTE(R) {\
+ RouteTableEntry *__P__; \
+ __P__ = FindInsertPoint((R)); \
+ InsertAfterRTE(__P__, (R)); \
+ }
+
+#define RemoveRTE(P, R) (P)->rte_next = (R)->rte_next;
+
+//** DuumyXmit - Dummy interface transmit handler.
+//
+// A dummy routine that should never be called.
+//
+// Entry: Context - NULL.
+// Packet - Pointer to packet to be transmitted.
+// Dest - Destination addres of packet.
+// RCE - Pointer to RCE (should be NULL).
+//
+// Returns: NDIS_STATUS_PENDING
+//
+NDIS_STATUS
+DummyXmit(void *Context, PNDIS_PACKET Packet, IPAddr Dest, RouteCacheEntry *RCE)
+{
+ DbgPrint("TCPIP: Dummy Xmit called - NOT GOOD\n");
+ CTEAssert(FALSE);
+ return NDIS_STATUS_SUCCESS;
+}
+
+//* DummyXfer - Dummy interface transfer data routine.
+//
+// A dummy routine that should never be called.
+//
+// Entry: Context - NULL.
+// TDContext - Original packet that was sent.
+// Dummy - Unused
+// Offset - Offset in frame from which to start copying.
+// BytesToCopy - Number of bytes to copy.
+// DestPacket - Packet describing buffer to copy into.
+// BytesCopied - Place to return bytes copied.
+//
+// Returns: NDIS_STATUS_SUCCESS
+//
+NDIS_STATUS
+DummyXfer(void *Context, NDIS_HANDLE TDContext, uint Dummy, uint Offset, uint BytesToCopy,
+ PNDIS_PACKET DestPacket, uint *BytesCopied)
+{
+ DbgPrint("TCPIP: DummyXfer called - NOT GOOD\n");
+
+ CTEAssert(FALSE);
+
+ return NDIS_STATUS_FAILURE;
+}
+
+//* DummyClose - Dummy close routine.
+//
+// A dummy routine that should never be called.
+//
+// Entry: Context - Unused.
+//
+// Returns: Nothing.
+//
+void
+DummyClose(void *Context)
+{
+ DbgPrint("TCPIP: Dummy Close called - NOT GOOD\n");
+
+ CTEAssert(FALSE);
+}
+
+//* DummyInvalidate - .
+//
+// A dummy routine that should never be called.
+//
+// Entry: Context - Unused.
+// RCE - Pointer to RCE to be invalidated.
+//
+// Returns: Nothing.
+//
+void
+DummyInvalidate(void *Context, RouteCacheEntry *RCE)
+{
+ DbgPrint("TCPIP: Dummy Invalidate called - NOT GOOD\n");
+
+ CTEAssert(FALSE);
+
+}
+
+//* DummyQInfo - Dummy query information handler.
+//
+// A dummy routine that should never be called.
+//
+// Input: IFContext - Interface context (unused).
+// ID - TDIObjectID for object.
+// Buffer - Buffer to put data into.
+// Size - Pointer to size of buffer. On return, filled with
+// bytes copied.
+// Context - Pointer to context block.
+//
+// Returns: Status of attempt to query information.
+//
+int
+DummyQInfo(void *IFContext, TDIObjectID *ID, PNDIS_BUFFER Buffer, uint *Size,
+ void *Context)
+{
+ DbgPrint("TCPIP: DummyQInfo called - NOT GOOD\n");
+
+ CTEAssert(FALSE);
+
+ return TDI_INVALID_REQUEST;
+}
+
+//* DummySetInfo - Dummy query information handler.
+//
+// A dummy routine that should never be called.
+//
+// Input: IFContext - Interface context (unused).
+// ID - TDIObjectID for object.
+// Buffer - Buffer to put data into.
+// Size - Pointer to size of buffer. On return, filled with
+// bytes copied.
+//
+// Returns: Status of attempt to query information.
+//
+int
+DummySetInfo(void *IFContext, TDIObjectID *ID, void *Buffer, uint Size)
+{
+ DbgPrint("TCPIP: DummySetInfo called - NOT GOOD\n");
+
+ CTEAssert(FALSE);
+
+ return TDI_INVALID_REQUEST;
+}
+
+//* DummyAddAddr - Dummy add address routine.
+//
+// Called at init time when we need to initialize ourselves.
+//
+uint
+DummyAddAddr(void *Context, uint Type, IPAddr Address, IPMask Mask, void *Context2)
+{
+ CTEAssert(FALSE);
+
+ return TRUE;
+}
+
+//* DummyDelAddr - Dummy del address routine.
+//
+// Called at init time when we need to initialize ourselves.
+//
+uint
+DummyDelAddr(void *Context, uint Type, IPAddr Address, IPMask Mask)
+{
+ DbgPrint("TCPIP: DummyAddAddr called - NOT GOOD\n");
+
+ CTEAssert(FALSE);
+
+ return TRUE;
+}
+
+//* DummyGetEList - Dummy get entity list.
+//
+// A dummy routine that should never be called.
+//
+// Input: Context - Unused.
+// EntityList - Pointer to entity list to be filled in.
+// Count - Pointer to number of entries in the list.
+//
+// Returns Status of attempt to get the info.
+//
+int
+DummyGetEList(void *Context, TDIEntityID *EntityList, uint *Count)
+{
+ DbgPrint("TCPIP: DummyGetEList called - NOT GOOD\n");
+
+ CTEAssert(FALSE);
+
+ return FALSE;
+}
+
+#ifdef _PNP_POWER
+//* DerefIF - Dereference an interface.
+//
+// Called when we need to dereference an interface. We decrement the
+// refcount, and if it goes to zero we signal whoever is blocked on
+// it.
+//
+// Input: IF - Interfaec to be dereferenced.
+//
+// Returns: Nothing.
+//
+void
+DerefIF(Interface *IF)
+{
+ uint Original;
+
+ Original = CTEInterlockedAddUlong(
+ &IF->if_refcount,
+ (ULONG)-1,
+ &RouteTableLock
+ );
+ if (Original != 1) {
+ return;
+ } else {
+ // We just decremented the last reference. Wake whoever is
+ // blocked on it.
+ CTEAssert(IF->if_block != NULL);
+ CTESignal(IF->if_block, NDIS_STATUS_SUCCESS);
+ }
+}
+
+//* LockedDerefIF - Dereference an interface w/RouteTableLock held.
+//
+// Called when we need to dereference an interface. We decrement the
+// refcount, and if it goes to zero we signal whoever is blocked on
+// it. The difference here is that we assume the caller already holds
+// the RouteTableLock.
+//
+// Input: IF - Interfaec to be dereferenced.
+//
+// Returns: Nothing.
+//
+void
+LockedDerefIF(Interface *IF)
+{
+ uint Original;
+
+ IF->if_refcount--;
+
+ if (IF->if_refcount != 0) {
+ return;
+ } else {
+ // We just decremented the last reference. Wake whoever is
+ // blocked on it.
+ CTEAssert(IF->if_block != NULL);
+ CTESignal(IF->if_block, NDIS_STATUS_SUCCESS);
+ }
+}
+#endif
+
+//* GetHashMask - Get mask to use with address when hashing.
+//
+// Called when we need to decide on the mask to use when hashing. If the
+// supplied mask is the host mask or the default mask, we'll use that. Else
+// if the supplied mask is at least as specific as the net mask, we'll use the
+// net mask. Otherwise we drop back to the default mask.
+//
+// Input: Destination - Destination we'll be hashing on.
+// Mask - Caller supplied mask.
+//
+// Returns: Mask to use.
+//
+IPMask
+GetHashMask(IPAddr Destination, IPMask Mask)
+{
+ IPMask NetMask;
+
+ if (Mask == HOST_MASK || Mask == DEFAULT_MASK)
+ return Mask;
+
+ NetMask = IPNetMask(Destination);
+
+ if ((NetMask & Mask) == NetMask)
+ return NetMask;
+
+ return DEFAULT_MASK;
+
+}
+
+//** AddrOnIF - Check to see if a given address is local to an IF
+//
+// Called when we want to see if a given address is a valid local address
+// for an interface. We walk down the chain of NTEs in the interface, and
+// see if we get a match. We assume the caller holds the RouteTableLock
+// at this point.
+//
+// Input: IF - Interface to check.
+// Addr - Address to check.
+//
+// Returns: TRUE if Addr is an address for IF, FALSE otherwise.
+//
+uint
+AddrOnIF(Interface *IF, IPAddr Addr)
+{
+ NetTableEntry *NTE;
+
+ NTE = IF->if_nte;
+ while (NTE != NULL) {
+ if ((NTE->nte_flags & NTE_VALID) && IP_ADDR_EQUAL(NTE->nte_addr, Addr))
+ return TRUE;
+ else
+ NTE = NTE->nte_ifnext;
+ }
+
+ return FALSE;
+}
+
+//** BestNTEForIF - Find the 'best match' NTE on a given interface.
+//
+// This is a utility function that takes an address and tries to find the
+// 'best match' NTE on a given interface. This is really only useful when we
+// have multiple IP addresses on a single interface.
+//
+// Input: Address - Source address of packet.
+// IF - Pointer to IF to be searched.
+//
+// Returns: The 'best match' NTE.
+//
+NetTableEntry *
+BestNTEForIF(IPAddr Address, Interface *IF)
+{
+ NetTableEntry *CurrentNTE, *FoundNTE;
+
+ if (IF->if_nte != NULL) {
+ // Walk the list of NTEs, looking for a valid one.
+ CurrentNTE = IF->if_nte;
+ FoundNTE = NULL;
+ do {
+ if (CurrentNTE->nte_flags & NTE_VALID) {
+ if (IP_ADDR_EQUAL(Address & CurrentNTE->nte_mask,
+ CurrentNTE->nte_addr & CurrentNTE->nte_mask))
+ return CurrentNTE;
+ else
+ if (FoundNTE == NULL)
+ FoundNTE = CurrentNTE;
+
+ }
+
+ CurrentNTE = CurrentNTE->nte_ifnext;
+ } while (CurrentNTE != NULL);
+
+ // If we found a match, or we didn't and the destination is not
+ // a broadcast, return the result. We have special case code to
+ // handle broadcasts, since the interface doesn't really matter there.
+ if (FoundNTE != NULL || (!IP_ADDR_EQUAL(Address, IP_LOCAL_BCST) &&
+ !IP_ADDR_EQUAL(Address, IP_ZERO_BCST)))
+ return FoundNTE;
+
+ }
+
+ // An 'anonymous' I/F, or the address we're reaching is a broadcast and the
+ // first interface has no address. Find a valid (non-loopback) address.
+ for (CurrentNTE = NetTableList; CurrentNTE != NULL;
+ CurrentNTE = CurrentNTE->nte_next) {
+ if (CurrentNTE != LoopNTE && (CurrentNTE->nte_flags & NTE_VALID))
+ return CurrentNTE;
+
+ }
+
+ return NULL;
+
+}
+
+//** IsBCastonNTE - Determine if the specified addr. is a bcast on a spec. NTE.
+//
+// This routine is called when we need to know if an address is a broadcast
+// on a particular net. We check in the order we expect to be most common - a
+// subnet bcast, an all ones broadcast, and then an all subnets broadcast. We
+// return the type of broadcast it is, or return DEST_LOCAL if it's not a
+// broadcast.
+//
+// Entry: Address - Address in question.
+// NTE - NetTableEntry to check Address against.
+//
+// Returns: Type of broadcast.
+//
+uchar
+IsBCastOnNTE(IPAddr Address, NetTableEntry *NTE)
+{
+ IPMask Mask;
+ IPAddr BCastAddr;
+
+ BCastAddr = NTE->nte_if->if_bcast;
+
+ if (NTE->nte_flags & NTE_VALID) {
+
+ Mask = NTE->nte_mask;
+
+ if(Mask != 0xFFFFFFFF)
+ {
+ if (IP_ADDR_EQUAL(Address, (NTE->nte_addr & Mask) | (BCastAddr & ~Mask)))
+ return DEST_SN_BCAST;
+ }
+
+ // See if it's an all subnet's broadcast.
+ if (!CLASSD_ADDR(Address)) {
+ Mask = IPNetMask(Address);
+
+ if (IP_ADDR_EQUAL(Address,
+ (NTE->nte_addr & Mask) | (BCastAddr & ~Mask)))
+ return DEST_BCAST;
+ } else {
+ // This is a class D address. If we're allowed to receive
+ // mcast datagrams, check our list.
+
+ if (IGMPLevel == 2) {
+ IGMPAddr *AddrPtr;
+ CTELockHandle Handle;
+
+ CTEGetLock(&NTE->nte_lock, &Handle);
+ AddrPtr = NTE->nte_igmplist;
+ while (AddrPtr != NULL) {
+ if (IP_ADDR_EQUAL(Address, AddrPtr->iga_addr))
+ break;
+ else
+ AddrPtr = AddrPtr->iga_next;
+ }
+
+ CTEFreeLock(&NTE->nte_lock, Handle);
+ if (AddrPtr != NULL)
+ return DEST_MCAST;
+ }
+ }
+ }
+
+ // A global bcast is certainly a bcast on this net.
+ if (IP_ADDR_EQUAL(Address, BCastAddr))
+ return DEST_BCAST;
+
+ return DEST_LOCAL;
+
+}
+
+//** InvalidSourceAddress - Check to see if a source address is invalid.
+//
+// This function takes an input address and checks to see if it is valid
+// if used as the source address of an incoming packet. An address is invalid
+// if it's 0, -1, a Class D or Class E address, is a net or subnet broadcast,
+// or has a 0 subnet or host part.
+//
+// Input: Address - Address to be check.
+//
+// Returns: FALSE if the address is not invalid, TRUE if it is invalid.
+//
+uint
+InvalidSourceAddress(IPAddr Address)
+{
+ NetTableEntry *NTE; // Pointer to current NTE.
+ IPMask Mask; // Mask for address.
+ uchar Result; // Result of broadcast check.
+ IPMask SNMask;
+ IPAddr MaskedAddress;
+ IPAddr LocalAddress;
+
+
+ if ( !CLASSD_ADDR(Address) &&
+ !CLASSE_ADDR(Address) &&
+ !IP_ADDR_EQUAL(Address, IP_ZERO_BCST) &&
+ !IP_ADDR_EQUAL(Address, IP_LOCAL_BCST)
+ ) {
+ // It's not an obvious broadcast. See if it's an all subnets
+ // broadcast, or has a zero host part.
+ Mask = IPNetMask(Address);
+ MaskedAddress = Address & Mask;
+
+ if (!IP_ADDR_EQUAL(Address, MaskedAddress) &&
+ !IP_ADDR_EQUAL(Address, (MaskedAddress | ~Mask))
+ ) {
+ // It's not an all subnet's broadcast, and it has a non-zero
+ // host/subnet part. Walk our local IP addresses, and see if it's
+ // a subnet broadcast.
+ NTE = NetTableList;
+ do {
+
+ LocalAddress = NTE->nte_addr;
+
+ if ((NTE->nte_flags & NTE_VALID) &&
+ !IP_LOOPBACK(LocalAddress)) {
+
+ Mask = NTE->nte_mask;
+ MaskedAddress = LocalAddress & Mask;
+
+ if (IP_ADDR_EQUAL(Address, MaskedAddress) ||
+ IP_ADDR_EQUAL(Address,
+ (MaskedAddress |
+ (NTE->nte_if->if_bcast & ~Mask)))) {
+ return TRUE;
+ }
+ }
+
+
+ NTE = NTE->nte_next;
+ } while (NTE != NULL);
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+//** FlushATCache - Flush an address from the ATCache
+//
+// This function takes an input address, and removes it from the ATCache,
+// if it is present.
+//
+// Input: Address - Address to be check.
+//
+// Returns: Destination type.
+//
+void
+FlushATCache(IPAddr Address)
+{
+ uint i;
+
+
+ for (i=0; i<ATC_SIZE; i++) {
+ if (ATCache[i].atc_flags & (ATCache[i].atc_addr == Address)) {
+ ATCache[i].atc_flags = 0;
+ }
+ }
+}
+
+//** GetAddrType - Return the type of a specified address.
+//
+// This function takes an input address, and determines what type it is. An
+// address can be local, bcast, remote, or remote bcast.
+//
+// Input: Address - Address to be check.
+//
+// Returns: Destination type.
+//
+uchar
+GetAddrType(IPAddr Address)
+{
+ NetTableEntry *NTE; // Pointer to current NTE.
+ IPMask Mask; // Mask for address.
+ uchar Result; // Result of broadcast check.
+ IPMask SNMask;
+ uint saveATCIndex;
+ uint i;
+
+ saveATCIndex = ATCIndex & ATC_MASK;
+ i = saveATCIndex;
+
+ do {
+ if (ATCache[i].atc_flags && (ATCache[i].atc_addr == Address)) {
+ Result = ATCache[i].atc_type;
+ if (ATCache[i].atc_flags && (ATCache[i].atc_addr == Address)) {
+ return(Result);
+ }
+ }
+ i = (--i) & ATC_MASK;
+ } while (i != saveATCIndex );
+
+
+
+ if (!CLASSE_ADDR(Address)) {
+ // See if it's one of our local addresses, or a broadcast
+ // on a local address.
+ NTE = NetTableList;
+ do {
+
+ if (IP_ADDR_EQUAL(NTE->nte_addr, Address) &&
+ (NTE->nte_flags & NTE_VALID)) {
+ Result = DEST_LOCAL;
+ goto gat_exit;
+ }
+
+ if ((Result = IsBCastOnNTE(Address, NTE)) != DEST_LOCAL) {
+ goto gat_exit;
+ }
+
+ // See if the destination has a valid host part.
+ if (NTE->nte_flags & NTE_VALID) {
+ SNMask = NTE->nte_mask;
+ if (IP_ADDR_EQUAL(Address & SNMask, NTE->nte_addr & SNMask)) {
+ // On this subnet. See if the host part is invalid.
+
+ if (IP_ADDR_EQUAL(Address & SNMask, Address)) {
+ Result = DEST_INVALID; // Invalid 0 host part.
+ goto gat_exit;
+ }
+ }
+ }
+ NTE = NTE->nte_next;
+ } while (NTE != NULL);
+
+ // It's not a local address, see if it's loopback.
+ if (IP_LOOPBACK(Address)) {
+ Result = DEST_LOCAL;
+ goto gat_exit;
+ }
+
+ // If we're doing IGMP, see if it's a Class D address. If it it,
+ // return that.
+ if (CLASSD_ADDR(Address)) {
+ if (IGMPLevel != 0) {
+ Result = DEST_REM_MCAST;
+ goto gat_exit;
+ }
+ else {
+ Result = DEST_INVALID;
+ goto gat_exit;
+ }
+ }
+
+ Mask = IPNetMask(Address);
+
+ // Now check remote broadcast. When we get here we know that the
+ // address is not a global broadcast, a subnet broadcast for a subnet
+ // of which we're a member, or an all-subnets broadcast for a net of
+ // which we're a member. Since we're avoiding making assumptions about
+ // all subnet of a net having the same mask, we can't really check for
+ // a remote subnet broadcast. We'll use the net mask and see if it's
+ // a remote all-subnet's broadcast.
+ if (IP_ADDR_EQUAL(Address, (Address & Mask) | (IP_LOCAL_BCST & ~Mask))) {
+ Result = DEST_REM_BCAST;
+ goto gat_exit;
+ }
+
+ // Check for invalid 0 parts. All we can do from here is see if he's
+ // sending to a remote net with all zero subnet and host parts. We
+ // can't check to see if he's sending to a remote subnet with an all
+ // zero host part.
+ if (IP_ADDR_EQUAL(Address, Address & Mask) ||
+ IP_ADDR_EQUAL(Address, NULL_IP_ADDR)) {
+ Result = DEST_INVALID;
+ goto gat_exit;
+ }
+
+ // Must be remote.
+ Result = DEST_REMOTE;
+ goto gat_exit;
+ }
+
+ Result = DEST_INVALID;
+
+gat_exit:
+
+ ++ATCIndex;
+
+ i = ATCIndex & ATC_MASK;
+
+ ATCache[i].atc_addr = Address;
+ ATCache[i].atc_type = Result;
+ ATCache[i].atc_flags = 1;
+ return(Result);
+
+}
+
+//** IPHash - IP hash function.
+//
+// This is the function to compute the hash index from a masked address.
+//
+// Input: Address - Masked address to be hashed.
+//
+// Returns: Hashed value.
+//
+uint
+IPHash(IPAddr Address)
+{
+ uchar *i = (uchar *)&Address;
+ return (i[0] + i[1] + i[2] + i[3]) & (ROUTE_TABLE_SIZE-1);
+}
+
+//** GetLocalNTE - Get the local NTE for an incoming packet.
+//
+// Called during receive processing to find a matching NTE for a packet.
+// First we check against the NTE we received it on, then against any NTE.
+//
+// Input: Address - The dest. address of the packet.
+// NTE - Pointer to NTE packet was received on - filled in on
+// exit w/correct NTE.
+//
+// Returns: DEST_LOCAL if the packet is destined for this host, DEST_REMOTE if it needs to
+// be routed, DEST_SN_BCAST or DEST_BCAST if it's some sort of a broadcast.
+uchar
+GetLocalNTE(IPAddr Address, NetTableEntry **NTE)
+{
+ NetTableEntry *LocalNTE = *NTE;
+ IPMask Mask;
+ uchar Result;
+ int i;
+ Interface *LocalIF;
+ NetTableEntry *OriginalNTE;
+
+ // Quick check to see if it is for the NTE it came in on (the common case).
+ if (IP_ADDR_EQUAL(Address, LocalNTE->nte_addr) &&
+ (LocalNTE->nte_flags & NTE_VALID))
+ return DEST_LOCAL; // For us, just return.
+
+ // Now check to see if it's a broadcast of some sort on the interface it
+ // came in on.
+ if ((Result = IsBCastOnNTE(Address, LocalNTE)) != DEST_LOCAL)
+ return Result;
+
+ // The common cases failed us. Loop through the NetTable and see if
+ // it is either a valid local address or is a broadcast on one of the NTEs
+ // on the incoming interface. We won't check the NTE we've already looked
+ // at. We look at all NTEs, including the loopback NTE, because a loopback
+ // frame could come through here. Also, frames from ourselves to ourselves
+ // will come in on the loopback NTE.
+
+ i = 0;
+ LocalIF = LocalNTE->nte_if;
+ OriginalNTE = LocalNTE;
+ LocalNTE = NetTableList;
+ do {
+ if (LocalNTE != OriginalNTE) {
+ if (IP_ADDR_EQUAL(Address, LocalNTE->nte_addr) &&
+ (LocalNTE->nte_flags & NTE_VALID)) {
+ *NTE = LocalNTE;
+ return DEST_LOCAL; // For us, just return.
+ }
+
+ // If this NTE is on the same interface as the NTE it arrived on,
+ // see if it's a broadcast.
+ if (LocalIF == LocalNTE->nte_if)
+ if ((Result = IsBCastOnNTE(Address, LocalNTE)) != DEST_LOCAL) {
+ *NTE = LocalNTE;
+ return Result;
+ }
+
+ }
+
+ LocalNTE = LocalNTE->nte_next;
+
+ } while (LocalNTE != NULL);
+
+ // It's not a local address, see if it's loopback.
+ if (IP_LOOPBACK(Address)) {
+ *NTE = LoopNTE;
+ return DEST_LOCAL;
+ }
+
+ // If it's a class D address and we're receiveing multicasts, handle it
+ // here.
+ if (CLASSD_ADDR(Address)) {
+ if (IGMPLevel != 0)
+ return DEST_REM_MCAST;
+ else
+ return DEST_INVALID;
+ }
+
+ // It's not local. Check to see if maybe it's a net broadcast for a net
+ // of which we're not a member. If so, return remote bcast. We can't check
+ // for subnet broadcast of subnets for which we're not a member, since we're
+ // not making assumptions about all subnets of a single net having the
+ // same mask. If we're here it's not a subnet broadcast for a net of which
+ // we're a member, so we don't know a subnet mask for it. We'll just use
+ // the net mask.
+ Mask = IPNetMask(Address);
+ if (IP_ADDR_EQUAL(Address, (Address & Mask) |
+ ((*NTE)->nte_if->if_bcast & ~Mask)))
+ return DEST_REM_BCAST;
+
+ // If it's to the 0 address, or a Class E address, or has an all-zero
+ // subnet and net part, it's invalid.
+
+
+ if (IP_ADDR_EQUAL(Address, IP_ZERO_BCST) ||
+ IP_ADDR_EQUAL(Address, (Address & Mask)) ||
+ CLASSE_ADDR(Address))
+ return DEST_INVALID;
+
+ // If we're DHCPing the interface on which this came in we'll accept this.
+ // If it came in as a broadcast a check in IPRcv() will reject it. If it's
+ // a unicast to us we'll pass it up.
+ if (DHCPNTE != NULL && DHCPNTE == *NTE) {
+ return DEST_LOCAL;
+ }
+
+ return DEST_REMOTE;
+}
+
+
+//** FindSpecificRTE - Look for a particular RTE.
+//
+// Called when we're adding a route and want to find a particular RTE.
+// We take in the destination, mask, first hop, and src addr, and search
+// the appropriate routeing table chain. We assume the caller has the
+// RouteTableLock held. If we find the match, we'll return a pointer to the
+// RTE with the RTE lock held, as well as a pointer to the previous RTE in
+// the chain.
+//
+// Input: Dest - Destination to search for.
+// Mask - Mask for destination.
+// FirstHop - FirstHop to Dest.
+// OutIF - Pointer to outgoing interface structure.
+// PrevRTE - Place to put PrevRTE, if found.
+//
+// Returns: Pointer to matching RTE if found, or NULL if not.
+//
+RouteTableEntry *
+FindSpecificRTE(IPAddr Dest, IPMask Mask, IPAddr FirstHop, Interface *OutIF,
+ RouteTableEntry **PrevRTE)
+{
+ uint Index;
+ IPMask HashMask;
+ RouteTableEntry *TempRTE, *CurrentRTE;
+
+ HashMask = GetHashMask(Dest, Mask);
+
+ Index = IPHash(Dest & HashMask);
+ TempRTE = STRUCT_OF(RouteTableEntry, &RouteTable[Index], rte_next);
+ CurrentRTE = TempRTE->rte_next;
+
+ //
+ // If this has been called because user mode was trying to set the route
+ // to INVALID, then the OUTIF will be DummyInterface, but we want to match
+ // any interface, since the IF will have already been plumbed by DODCallOut
+ //
+
+ if(OutIF == (Interface *)&DummyInterface)
+ {
+ //
+ // Match everything but the interface
+ //
+
+ while (CurrentRTE != NULL)
+ {
+ if (IP_ADDR_EQUAL(CurrentRTE->rte_dest,Dest) &&
+ CurrentRTE->rte_mask == Mask &&
+ IP_ADDR_EQUAL(CurrentRTE->rte_addr, FirstHop))
+ {
+ break;
+ }
+
+ TempRTE = CurrentRTE;
+ CurrentRTE = CurrentRTE->rte_next;
+ }
+ }
+ else
+ {
+ // Walk the table, looking for a match.
+ while (CurrentRTE != NULL) {
+ // See if everything matches.
+ if (IP_ADDR_EQUAL(CurrentRTE->rte_dest,Dest) &&
+ CurrentRTE->rte_mask == Mask &&
+ IP_ADDR_EQUAL(CurrentRTE->rte_addr, FirstHop) &&
+ CurrentRTE->rte_if == OutIF)
+ break;
+
+ TempRTE = CurrentRTE;
+ CurrentRTE = CurrentRTE->rte_next;
+ }
+ }
+
+ *PrevRTE = TempRTE;
+ return CurrentRTE;
+
+}
+
+//** IsRouteICMP - This function is used by Router Discovery to determine
+// how we learned about the route. We are not allowed to update or timeout
+// routes that were not learned about via icmp. If the route is new then
+// we treat it as icmp and add a new entry.
+// Input: Dest - Destination to search for.
+// Mask - Mask for destination.
+// FirstHop - FirstHop to Dest.
+// OutIF - Pointer to outgoing interface structure.
+//
+// Returns: TRUE if learned via ICMP, FALSE otherwise.
+//
+uint
+IsRouteICMP(IPAddr Dest, IPMask Mask, IPAddr FirstHop, Interface *OutIF)
+{
+ RouteTableEntry *RTE;
+ RouteTableEntry *TempRTE;
+
+ RTE = FindSpecificRTE(Dest, Mask, FirstHop, OutIF, &TempRTE);
+
+ if (RTE == NULL)
+ return(TRUE);
+
+ if (RTE->rte_proto == IRE_PROTO_ICMP) {
+ return(TRUE);
+ } else {
+ return(FALSE);
+ }
+}
+
+
+//** FindRTE - Find a matching RTE in a hash table chain.
+//
+// Called when we want to find a matching RTE. We take in a destination,
+// a source, a hash index, and a maximum priority, and walk down the
+// chain specified by the index looking for a matching RTE. If we can find
+// one, we'll keep looking hoping for a match on the source address.
+//
+// The caller must hold the RouteTableLock before calling this function.
+//
+// Input: Dest - Destination we're trying to reach.
+// Source - Source address to match.
+// Index - Index of chain to search.
+// MaxPri - Maximum acceptable priority.
+// MinPri - Minimum acceptable priority.
+//
+// Returns: Pointer to RTE if found, or NULL if not.
+//
+RouteTableEntry *
+FindRTE(IPAddr Dest, IPAddr Source, uint Index, uint MaxPri, uint MinPri)
+{
+ RouteTableEntry *CurrentRTE;
+ uint RTEPri;
+ uint Metric;
+ RouteTableEntry *FoundRTE;
+
+ // First walk down the chain, skipping those RTEs that have a
+ // a priority greater than what we want.
+
+ CurrentRTE = RouteTable[Index];
+
+ for (;;) {
+ if (CurrentRTE == NULL)
+ return NULL; // Hit end of chain, bounce out.
+
+ if (CurrentRTE->rte_priority <= MaxPri)
+ break; // He's a possible match.
+
+ // Priority is too big. Try the next one.
+ CurrentRTE = CurrentRTE->rte_next;
+ }
+
+ FoundRTE = NULL;
+
+ // When we get here, we have a locked RTE with a priority less than or
+ // equal to what was specifed.
+ // Examine it, and if it doesn't match try the next one. If it does match
+ // we'll stash it temporarily and keep looking for one that matches the
+ // specifed source.
+ for (;;) {
+
+ // The invariant at the top of this loop is that CurrentRTE points to
+ // a candidate RTE, locked with the handle in CurrentHandle.
+
+ if (CurrentRTE->rte_flags & RTE_VALID) {
+ // He's valid. Make sure he's at least the priority we need. If
+ // he is, see if he matches. Otherwise we're done.
+
+ if (CurrentRTE->rte_priority < MinPri) {
+ // His priority is too small. Since the list is in sorted order,
+ // all following routes must have too low a priority, so we're
+ // done.
+ return NULL;
+ }
+
+ if (IP_ADDR_EQUAL(Dest & CurrentRTE->rte_mask, CurrentRTE->rte_dest)) {
+ // He's valid for this route. Save the current information,
+ // and look for a matching source.
+ FoundRTE = CurrentRTE;
+
+ if (!IP_ADDR_EQUAL(Source, NULL_IP_ADDR) &&
+ !AddrOnIF(CurrentRTE->rte_if, Source)) {
+ RTEPri = CurrentRTE->rte_priority;
+ Metric = CurrentRTE->rte_metric;
+
+ CurrentRTE = CurrentRTE->rte_next;
+
+ // We've save the info. Starting at the next RTE, look for
+ // an RTE that matches both the mask criteria and the source
+ // address. The search will terminate when we hit the end
+ // of the list, or the RTE we're examing has a different
+ // (presumably lesser) priority (or greater metric), or we
+ // find a match.
+ while (CurrentRTE != NULL &&
+ CurrentRTE->rte_priority == RTEPri &&
+ CurrentRTE->rte_metric == Metric) {
+
+
+ // Skip invalid route types.
+ if (CurrentRTE->rte_flags & RTE_VALID) {
+ if (IP_ADDR_EQUAL(Dest & CurrentRTE->rte_mask,
+ CurrentRTE->rte_dest)) {
+ if (AddrOnIF(CurrentRTE->rte_if, Source)) {
+ // He matches the source. Free the old lock,
+ // and break out.
+ FoundRTE = CurrentRTE;
+ break;
+ }
+ }
+
+ }
+ CurrentRTE = CurrentRTE->rte_next;
+ }
+ }
+
+ // At this point, FoundRTE points to the RTE we want to return,
+ // and *Handle has the lock handle for the RTE. Break out.
+ break;
+ }
+
+ }
+
+ CurrentRTE = CurrentRTE->rte_next;
+
+ if (CurrentRTE != NULL) {
+ continue;
+ } else
+ break;
+ }
+
+ return FoundRTE;
+}
+
+//* ValidateDefaultGWs - Mark all default gateways as valid.
+//
+// Called to one or all of our default gateways as up. The caller specifies
+// the IP address of the one to mark as up, or NULL_IP_ADDR if they're all
+// supposed to be marked up. We return a count of how many we marked as
+// valid.
+//
+// Input: IP address of G/W to mark as up.
+//
+// Returns: Count of gateways marked as up.
+//
+uint
+ValidateDefaultGWs(IPAddr Addr)
+{
+ RouteTableEntry *RTE;
+ uint Count = 0;
+ uint Now = CTESystemUpTime() / 1000L;
+
+ RTE = RouteTable[IPHash(0)];
+
+ while (RTE != NULL) {
+ if (RTE->rte_mask == DEFAULT_MASK && !(RTE->rte_flags & RTE_VALID) &&
+ (IP_ADDR_EQUAL(Addr, NULL_IP_ADDR) ||
+ IP_ADDR_EQUAL(Addr, RTE->rte_addr))) {
+ RTE->rte_flags |= RTE_VALID;
+ RTE->rte_valid = Now;
+ Count++;
+ }
+ RTE = RTE->rte_next;
+ }
+
+ DefGWActive += Count;
+ return Count;
+}
+
+//* InvalidateRCEChain - Invalidate the RCEs on an RCE.
+//
+// Called to invalidate the RCE chain on an RTE. We assume the caller holds
+// the route table lock.
+//
+// Input: RTE - RTE on which to invalidate RCEs.
+//
+// Returns: Nothing.
+//
+void
+InvalidateRCEChain(RouteTableEntry *RTE)
+{
+ CTELockHandle RCEHandle; // Lock handle for RCE being updated.
+ RouteCacheEntry *TempRCE, *CurrentRCE;
+ Interface *OutIF;
+
+ OutIF = RTE->rte_if;
+
+ // If there is an RCE chain on this RCE, invalidate the RCEs on it. We still
+ // hold the RouteTableLock, so RCE closes can't happen.
+
+
+ CurrentRCE = RTE->rte_rcelist;
+ RTE->rte_rcelist = NULL;
+
+ // Walk down the list, nuking each RCE.
+ while (CurrentRCE != NULL) {
+
+ CTEGetLock(&CurrentRCE->rce_lock, &RCEHandle);
+
+ if (CurrentRCE->rce_flags & RCE_VALID) {
+ CTEAssert(CurrentRCE->rce_rte == RTE);
+ CurrentRCE->rce_flags &= ~RCE_VALID;
+ CurrentRCE->rce_rte = (RouteTableEntry *)OutIF;
+ if ((CurrentRCE->rce_flags & RCE_CONNECTED) &&
+ CurrentRCE->rce_usecnt == 0) {
+
+ (*(OutIF->if_invalidate))(OutIF->if_lcontext, CurrentRCE);
+#ifdef _PNP_POWER
+ if (CurrentRCE->rce_flags & RCE_REFERENCED) {
+ LockedDerefIF(OutIF);
+ CurrentRCE->rce_flags &= ~RCE_REFERENCED;
+ }
+#endif
+ }
+ } else
+ CTEAssert(FALSE);
+
+ TempRCE = CurrentRCE->rce_next;
+ CTEFreeLock(&CurrentRCE->rce_lock, RCEHandle);
+ CurrentRCE = TempRCE;
+ }
+
+}
+
+//** FindValidIFForRTE - Find a valid inteface for an RTE.
+//
+// Called when we're going to send a packet out a route that currently marked
+// as disconnected. If we have a valid callout routine we'll call it to find
+// the outgoing interface index, and set up the RTE to point at that interface.
+// This routine is called with the RouteTableLock held.
+//
+// Input: RTE - A pointer to the RTE for the route being used.
+// Destination - Destination IP address we're trying to reach.
+// Source - Source IP address we're sending from.
+// Protocol - Protocol type of packet that caused send.
+// Buffer - Pointer to first part of packet that caused send.
+// Length - Length of buffer.
+//
+// Returns: A pointer to the RTE, or NULL if that RTE couldn't be connected.
+//
+RouteTableEntry *
+FindValidIFForRTE(RouteTableEntry *RTE, IPAddr Destination, IPAddr Source,
+ uchar Protocol, uchar *Buffer, uint Length)
+{
+ uint NewIFIndex;
+ Interface *NewIF;
+ NetTableEntry *NewNTE;
+
+ if (DODCallout != NULL) {
+ // There is a callout. See if it can help us.
+ NewIFIndex = (*DODCallout)(RTE->rte_context, Destination, Source,
+ Protocol, Buffer, Length);
+ if (NewIFIndex != INVALID_IF_INDEX) {
+ // We got what should be a valid index. Walk our interface table list
+ // and see if we can find a matching interface structure.
+ for (NewIF = IFList; NewIF != NULL; NewIF = NewIF->if_next) {
+ if (NewIF->if_index == NewIFIndex) {
+ // Found one.
+ break;
+ }
+ }
+ if (NewIF != NULL) {
+ // We found a matching structure. Set the RTE interface to point
+ // to this, and mark as connected.
+ if (RTE->rte_addr != IPADDR_LOCAL) {
+ // See if the first hop of the route is a local address on this
+ // new interface. If it is, mark it as local.
+ for (NewNTE = NewIF->if_nte; NewNTE != NULL;
+ NewNTE = NewNTE->nte_ifnext) {
+
+ // Don't look at him if he's not valid.
+ if (!(NewNTE->nte_flags & NTE_VALID)) {
+ continue;
+ }
+
+ // See if the first hop in the RTE is equal to this IP
+ // address.
+ if (IP_ADDR_EQUAL(NewNTE->nte_addr, RTE->rte_addr)) {
+ // It is, so mark as local and quit looking.
+ RTE->rte_addr = IPADDR_LOCAL;
+ RTE->rte_type = IRE_TYPE_DIRECT;
+ break;
+ }
+ }
+ }
+
+ // Set the RTE to the new interface, and mark him as valid.
+ RTE->rte_if = NewIF;
+ RTE->rte_flags |= RTE_IF_VALID;
+ RTE->rte_mtu = NewIF->if_mtu - sizeof(IPHeader);
+ return RTE;
+ } else
+ CTEAssert(FALSE);
+ }
+ }
+
+ // Either the callout is NULL, or the callout couldn't map a inteface index.
+ return NULL;
+}
+
+//** LookupRTE - Lookup a routing table entry.
+//
+// This routine looks up a routing table entry, and returns with the entry
+// locked if it finds one. If it doesn't find one, it returns NULL. This
+// routine assumes that the routing table is locked when it is called.
+//
+// The routeing table is organized as an open hash table. The table contains
+// routes to hosts, subnets, and nets. Host routes are hashed on the host
+// address, other non-default routes on the destination anded with the net
+// mask, and default routes wind up in bucket 0. Within each bucket chain
+// the routes are sorted with the greatest priority (i.e. number of bits in the
+// route mask) first, and within each priority class the routes are sorted
+// with the lowest metric first. The caller may specify a maximum priority
+// for the route to be found. We look for routes in order of most specific to
+// least specifc, i.e. first host routes, then other non-default routes, and
+// finally default routes. We give preference to routes that are going out
+// on an interface with an address that matches the input source address.
+//
+// It might be worthile in the future to split this up into multiple tables,
+// so that we have a table for host routes, a table for non-default routes,
+// and a list of default routes.
+//
+// Entry: Address - Address for which a route is to be found.
+// Src - IPAddr of source (may be 0).
+// MaxPri - Maximum priority of route to find.
+//
+// Returns: A pointer to the locked RTE if we find one, or NULL if we don't
+//
+RouteTableEntry *
+LookupRTE(IPAddr Address, IPAddr Src, uint MaxPri)
+{
+ RouteTableEntry *RTE;
+
+ // First try to find a host route, if we're allowed to.
+ if (MaxPri == HOST_ROUTE_PRI) {
+ RTE = FindRTE(Address, Src, IPHash(Address), MaxPri, MaxPri);
+ if (RTE != NULL) {
+ return RTE;
+ }
+ }
+
+ // Don't have or weren't allowed to find a host route. See if we can
+ // find a non-default route.
+ if (MaxPri > DEFAULT_ROUTE_PRI) {
+ RTE = FindRTE(Address, Src, IPHash(Address & IPNetMask(Address)),
+ MaxPri, DEFAULT_ROUTE_PRI + 1);
+ if (RTE != NULL) {
+ return RTE;
+ }
+ }
+
+ // No non-default route. Try a default route.
+ RTE = FindRTE(Address, Src, IPHash(0), MaxPri, DEFAULT_ROUTE_PRI);
+
+ return RTE;
+
+}
+
+//** GetRouteContext - Routine to get the route context for a specific route.
+//
+// Called when we need to get the route context for a path, usually when we're adding
+// a route derived from an existing route. We return the route context for the
+// existing route, or NULL if we can't find one.
+//
+// Input: Destination - Destination address of path.
+// Source - Source address of path.
+//
+// Returns: A ROUTE_CONTEXT, or NULL.
+//
+void *
+GetRouteContext(IPAddr Destination, IPAddr Source)
+{
+ CTELockHandle Handle;
+ RouteTableEntry *RTE;
+ ROUTE_CONTEXT Context;
+
+ CTEGetLock(&RouteTableLock, &Handle);
+ RTE = LookupRTE(Destination, Source, HOST_ROUTE_PRI);
+ if (RTE != NULL) {
+ Context = RTE->rte_context;
+ } else
+ Context = NULL;
+
+ CTEFreeLock(&RouteTableLock, Handle);
+
+ return(Context);
+}
+
+//* FindInsertPoint - Find out where to insert an RTE in the table.
+//
+// Called to find out where to insert an RTE. We hash into the table,
+// and walk the chain until we hit the end or we find an RTE with a
+// lesser priority or a greater metric. Once we find the appropriate spot
+// we return a pointer to the RTE immediately prior to the one we want to
+// insert. We assume the caller holds the lock on the route table when calling
+// this function.
+//
+// Input: InsertRTE - RTE we're going to (eventually) insert.
+//
+// Returns: Pointer to RTE in insert after.
+//
+RouteTableEntry *
+FindInsertPoint(RouteTableEntry *InsertRTE)
+{
+ RouteTableEntry *PrevRTE, *CurrentRTE;
+ IPMask HashMask, Mask;
+ uint Priority, Metric;
+ uint Index;
+
+ Priority = InsertRTE->rte_priority;
+ Metric = InsertRTE->rte_metric;
+
+ // First figure out where he should go. We'll hash on the whole address
+ // if the mask allows us to, or on the net portion if this is a non-default
+ // route.
+
+ Mask = InsertRTE->rte_mask;
+ HashMask = GetHashMask(InsertRTE->rte_dest, Mask);
+
+ Index = IPHash(InsertRTE->rte_dest & HashMask);
+
+ PrevRTE = STRUCT_OF(RouteTableEntry, &RouteTable[Index], rte_next);
+ CurrentRTE = PrevRTE->rte_next;
+
+ // Walk the table, looking for a place to insert it.
+ while (CurrentRTE != NULL) {
+ if (CurrentRTE->rte_priority < Priority) {
+ break;
+ }
+
+ if (CurrentRTE->rte_priority == Priority) {
+ // Priorities match. Check the metrics.
+ if (CurrentRTE->rte_metric > Metric) {
+ // Our metric is smaller than his, so we're done.
+ break;
+ }
+ }
+
+ // Either his priority is greater than ours or his metric is less
+ // than or equal to ours. Check the next one.
+ PrevRTE = CurrentRTE;
+ CurrentRTE = CurrentRTE->rte_next;
+ }
+
+ // At this point, we've either found the correct spot or hit the end
+ // of the list.
+ return PrevRTE;
+
+}
+
+
+//** LookupNextHop - Look up the next hop
+//
+// Called when we need to find the next hop on our way to a destination. We
+// call LookupRTE to find it, and return the appropriate information.
+//
+// In a PnP build, the interface is referenced here.
+//
+// Entry: Destination - IP address we're trying to reach.
+// Src - Source address of datagram being routed.
+// NextHop - Pointer to IP address of next hop (returned).
+// MTU - Pointer to where to return max MTU used on the
+// route.
+//
+// Returns: Pointer to outgoing interface if we found one, NULL otherwise.
+//
+Interface *
+LookupNextHop(IPAddr Destination, IPAddr Src, IPAddr *NextHop, uint *MTU)
+{
+ CTELockHandle TableLock; // Lock handle for routing table.
+ RouteTableEntry *Route; // Pointer to route table entry for route.
+ Interface *IF;
+
+ CTEGetLock(&RouteTableLock, &TableLock);
+ Route = LookupRTE(Destination, Src, HOST_ROUTE_PRI);
+
+ if (Route != (RouteTableEntry *)NULL) {
+ IF = Route->rte_if;
+
+ // If this is a direct route, send straight to the destination.
+ *NextHop = IP_ADDR_EQUAL(Route->rte_addr, IPADDR_LOCAL) ? Destination :
+ Route->rte_addr;
+
+ *MTU = Route->rte_mtu;
+#ifdef _PNP_POWER
+ IF->if_refcount++;
+#endif
+ CTEFreeLock(&RouteTableLock, TableLock);
+ return IF;
+ } else { // Couldn't find a route.
+ CTEFreeLock(&RouteTableLock, TableLock);
+ return NULL;
+ }
+}
+
+//** LookupNextHopWithBuffer - Look up the next hop, with packet information.
+//
+// Called when we need to find the next hop on our way to a destination and we
+// have packet information that we may use for dial on demand support. We call
+// LookupRTE to find it, and return the appropriate information. We may bring up
+// the link if neccessary.
+//
+// In a PnP build, the interface is referenced here.
+//
+// Entry: Destination - IP address we're trying to reach.
+// Src - Source address of datagram being routed.
+// NextHop - Pointer to IP address of next hop (returned).
+// MTU - Pointer to where to return max MTU used on the
+// route.
+// Protocol - Protocol type for packet that's causing this lookup.
+// Buffer - Pointer to first part of packet causing lookup.
+// Length - Length of Buffer.
+//
+// Returns: Pointer to outgoing interface if we found one, NULL otherwise.
+//
+Interface *
+LookupNextHopWithBuffer(IPAddr Destination, IPAddr Src, IPAddr *NextHop,
+ uint *MTU, uchar Protocol, uchar *Buffer, uint Length)
+{
+ CTELockHandle TableLock; // Lock handle for routing table.
+ RouteTableEntry *Route; // Pointer to route table entry for route.
+ Interface *IF;
+
+ CTEGetLock(&RouteTableLock, &TableLock);
+ Route = LookupRTE(Destination, Src, HOST_ROUTE_PRI);
+
+ if (Route != (RouteTableEntry *)NULL) {
+
+ // If this is a direct route, send straight to the destination.
+ *NextHop = IP_ADDR_EQUAL(Route->rte_addr, IPADDR_LOCAL) ? Destination :
+ Route->rte_addr;
+
+
+ // See if the route we found is connected. If not, try to connect it.
+ if (!(Route->rte_flags & RTE_IF_VALID)) {
+ Route = FindValidIFForRTE(Route, Destination, Src, Protocol, Buffer,
+ Length);
+ if (Route == NULL) {
+ // Couldn't bring it up.
+ CTEFreeLock(&RouteTableLock, TableLock);
+ return NULL;
+ } else
+ IF = Route->rte_if;
+ } else
+ IF = Route->rte_if;
+
+ *MTU = Route->rte_mtu;
+#ifdef _PNP_POWER
+ IF->if_refcount++;
+#endif
+ CTEFreeLock(&RouteTableLock, TableLock);
+ return IF;
+ } else { // Couldn't find a route.
+ CTEFreeLock(&RouteTableLock, TableLock);
+ return NULL;
+ }
+}
+
+//* RTReadNext - Read the next route in the table.
+//
+// Called by the GetInfo code to read the next route in the table. We assume
+// the context passed in is valid, and the caller has the RouteTableLock.
+//
+// Input: Context - Pointer to a RouteEntryContext.
+// Buffer - Pointer to an IPRouteEntry structure.
+//
+// Returns: TRUE if more data is available to be read, FALSE is not.
+//
+uint
+RTReadNext(void *Context, void *Buffer)
+{
+ RouteEntryContext *REContext = (RouteEntryContext *)Context;
+ IPRouteEntry *IPREntry = (IPRouteEntry *)Buffer;
+ RouteTableEntry *CurrentRTE;
+ uint i;
+ uint Now = CTESystemUpTime() / 1000L;
+ Interface *IF;
+ NetTableEntry *SrcNTE;
+
+ CurrentRTE = REContext->rec_rte;
+
+ // Fill in the buffer.
+ IF = CurrentRTE->rte_if;
+
+ IPREntry->ire_dest = CurrentRTE->rte_dest;
+ IPREntry->ire_index = IF->if_index;
+ IPREntry->ire_metric1 = CurrentRTE->rte_metric;
+ IPREntry->ire_metric2 = IRE_METRIC_UNUSED;
+ IPREntry->ire_metric3 = IRE_METRIC_UNUSED;
+ IPREntry->ire_metric4 = IRE_METRIC_UNUSED;
+ IPREntry->ire_metric5 = IRE_METRIC_UNUSED;
+ if (IP_ADDR_EQUAL(CurrentRTE->rte_addr, IPADDR_LOCAL)) {
+ SrcNTE = BestNTEForIF(CurrentRTE->rte_dest, IF);
+ if (IF->if_nte != NULL && SrcNTE != NULL)
+ IPREntry->ire_nexthop = SrcNTE->nte_addr;
+ else
+ IPREntry->ire_nexthop = IPREntry->ire_dest;
+ } else {
+ IPREntry->ire_nexthop = CurrentRTE->rte_addr;
+ }
+ IPREntry->ire_type = (CurrentRTE->rte_flags & RTE_VALID ?
+ CurrentRTE->rte_type : IRE_TYPE_INVALID);
+ IPREntry->ire_proto = CurrentRTE->rte_proto;
+ IPREntry->ire_age = Now - CurrentRTE->rte_valid;
+ IPREntry->ire_mask = CurrentRTE->rte_mask;
+ IPREntry->ire_context = CurrentRTE->rte_context;
+
+ // We've filled it in. Now update the context.
+ if (CurrentRTE->rte_next != NULL) {
+ REContext->rec_rte = CurrentRTE->rte_next;
+ return TRUE;
+ } else {
+ // The next RTE is NULL. Loop through the RouteTable looking for a new
+ // one.
+ i = REContext->rec_index + 1;
+ while (i < ROUTE_TABLE_SIZE) {
+ if (RouteTable[i] != NULL) {
+ REContext->rec_rte = RouteTable[i];
+ REContext->rec_index = i;
+ return TRUE;
+ break;
+ } else
+ i++;
+ }
+
+ REContext->rec_index = 0;
+ REContext->rec_rte = NULL;
+ return FALSE;
+ }
+
+}
+
+//* RTValidateContext - Validate the context for reading the route table.
+//
+// Called to start reading the route table sequentially. We take in
+// a context, and if the values are 0 we return information about the
+// first route in the table. Otherwise we make sure that the context value
+// is valid, and if it is we return TRUE.
+// We assume the caller holds the route table lock.
+//
+// Input: Context - Pointer to a RouteEntryContext.
+// Valid - Where to return information about context being
+// valid.
+//
+// Returns: TRUE if more data to be read in table, FALSE if not. *Valid set
+// to TRUE if input context is valid
+//
+uint
+RTValidateContext(void *Context, uint *Valid)
+{
+ RouteEntryContext *REContext = (RouteEntryContext *)Context;
+ uint i;
+ RouteTableEntry *TargetRTE;
+ RouteTableEntry *CurrentRTE;
+
+ i = REContext->rec_index;
+ TargetRTE = REContext->rec_rte;
+
+ // If the context values are 0 and NULL, we're starting from the beginning.
+ if (i == 0 && TargetRTE == NULL) {
+ *Valid = TRUE;
+ do {
+ if ((CurrentRTE = RouteTable[i]) != NULL) {
+ break;
+ }
+ i++;
+ } while (i < ROUTE_TABLE_SIZE);
+
+ if (CurrentRTE != NULL) {
+ REContext->rec_index = i;
+ REContext->rec_rte = CurrentRTE;
+ return TRUE;
+ } else
+ return FALSE;
+
+ } else {
+
+ // We've been given a context. We just need to make sure that it's
+ // valid.
+
+ if (i < ROUTE_TABLE_SIZE) {
+ CurrentRTE = RouteTable[i];
+ while (CurrentRTE != NULL) {
+ if (CurrentRTE == TargetRTE) {
+ *Valid = TRUE;
+ return TRUE;
+ break;
+ } else {
+ CurrentRTE = CurrentRTE->rte_next;
+ }
+ }
+
+ }
+
+ // If we get here, we didn't find the matching RTE.
+ *Valid = FALSE;
+ return FALSE;
+
+ }
+
+}
+
+
+//* DeleteRTE - Delete an RTE.
+//
+// Called when we need to delete an RTE. We assume the caller has the
+// RouteTableLock. We'll splice out the RTE, invalidate his RCEs, and
+// free the memory.
+//
+// Input: PrevRTE - RTE in 'front' of one being deleted.
+// RTE - RTE to be deleted.
+//
+// Returns: Nothing.
+//
+void
+DeleteRTE(RouteTableEntry *PrevRTE, RouteTableEntry *RTE)
+{
+ PrevRTE->rte_next = RTE->rte_next; // Splice him from the table.
+ IPSInfo.ipsi_numroutes--;
+
+ if (RTE->rte_mask == DEFAULT_MASK) {
+ // We're deleting a default route.
+ DefGWConfigured--;
+ if (RTE->rte_flags & RTE_VALID)
+ DefGWActive--;
+ if (DefGWActive == 0)
+ ValidateDefaultGWs(NULL_IP_ADDR);
+ }
+
+ InvalidateRCEChain(RTE);
+ // Free the old route.
+ CTEFreeMem(RTE);
+
+}
+
+//* DeleteRTEOnIF - Delete all RTEs on a particular IF.
+//
+// A function called by RTWalk when we want to delete all RTEs on a particular
+// inteface. We just check the I/F of each RTE, and if it matches we return
+// FALSE.
+//
+// Input: RTE - RTE to check.
+// Context - Interface on which we're deleting.
+//
+// Returns: FALSE if we want to delete it, TRUE otherwise.
+//
+uint
+DeleteRTEOnIF(RouteTableEntry *RTE, void *Context, void *Context1)
+{
+ Interface *IF = (Interface *)Context;
+
+ if (RTE->rte_if == IF && !IP_ADDR_EQUAL(RTE->rte_dest, IF->if_bcast))
+ return FALSE;
+ else
+ return TRUE;
+
+}
+
+//* InvalidateRCEOnIF - Invalidate all RCEs on a particular IF.
+//
+// A function called by RTWalk when we want to invalidate all RCEs on a
+// particular inteface. We just check the I/F of each RTE, and if it
+// matches we call InvalidateRCEChain to invalidate the RCEs.
+//
+// Input: RTE - RTE to check.
+// Context - Interface on which we're invalidating.
+//
+// Returns: TRUE.
+//
+uint
+InvalidateRCEOnIF(RouteTableEntry *RTE, void *Context, void *Context1)
+{
+ Interface *IF = (Interface *)Context;
+
+ if (RTE->rte_if == IF)
+ InvalidateRCEChain(RTE);
+
+ return TRUE;
+
+}
+
+//* SetMTUOnIF - Set the MTU on an interface.
+//
+// Called when we need to set the MTU on an interface.
+//
+// Input: RTE - RTE to check.
+// Context - Pointer to a context.
+// Context1 - Pointer to the new MTU.
+//
+// Returns: TRUE.
+//
+uint
+SetMTUOnIF(RouteTableEntry *RTE, void *Context, void *Context1)
+{
+ uint NewMTU = *(uint *)Context1;
+ Interface *IF = (Interface *)Context;
+
+ if (RTE->rte_if == IF)
+ RTE->rte_mtu = NewMTU;
+
+ return TRUE;
+}
+
+//* SetMTUToAddr - Set the MTU to a specific address.
+//
+// Called when we need to set the MTU to a specific address. We set the MTU
+// for all routes that use the specified address as a first hop to the new
+// MTU.
+//
+// Input: RTE - RTE to check.
+// Context - Pointer to a context.
+// Context1 - Pointer to the new MTU.
+//
+// Returns: TRUE.
+//
+uint
+SetMTUToAddr(RouteTableEntry *RTE, void *Context, void *Context1)
+{
+ uint NewMTU = *(uint *)Context1;
+ IPAddr Addr = *(IPAddr *)Context;
+
+ if (IP_ADDR_EQUAL(RTE->rte_addr, Addr))
+ RTE->rte_mtu = NewMTU;
+
+ return TRUE;
+}
+
+//* RTWalk - Routine to walk the route table.
+//
+// This routine walks the route table, calling the specified function
+// for each entry. If the called function returns FALSE, the RTE is
+// deleted.
+//
+// Input: CallFunc - Function to call for each entry.
+// Context - Context value to pass to each call.
+//
+// Returns: Nothing.
+//
+void
+RTWalk(uint (*CallFunc)(struct RouteTableEntry *, void *, void *),
+ void *Context, void *Context1)
+{
+ uint i;
+ CTELockHandle Handle;
+ RouteTableEntry *RTE, *PrevRTE;
+
+ CTEGetLock(&RouteTableLock, &Handle);
+
+ for (i = 0; i < ROUTE_TABLE_SIZE; i++) {
+
+ PrevRTE = STRUCT_OF(RouteTableEntry, &RouteTable[i], rte_next);
+ RTE = RouteTable[i];
+ while (RTE != NULL) {
+ if (!(*CallFunc)(RTE, Context, Context1)) {
+ DeleteRTE(PrevRTE, RTE);
+ } else {
+ PrevRTE = RTE;
+ }
+ RTE = PrevRTE->rte_next;
+ }
+ }
+
+ CTEFreeLock(&RouteTableLock, Handle);
+}
+
+//** AttachRCEToRTE - Attach an RCE to an RTE.
+//
+// This procedure takes an RCE, finds the appropriate RTE, and attaches it.
+// We check to make sure that the source address is still valid.
+//
+// Entry: RCE - RCE to be attached.
+// Protocol - Protocol type for packet causing this call.
+// Buffer - Pointer to buffer for packet causing this
+// call.
+// Length - Length of buffer.
+//
+// Returns: TRUE if we attach it, false if we don't.
+//
+uint
+AttachRCEToRTE(RouteCacheEntry *RCE, uchar Protocol, uchar *Buffer, uint Length)
+{
+ CTELockHandle TableHandle, RCEHandle;
+ RouteTableEntry *RTE;
+ NetTableEntry *NTE;
+ uint Status;
+
+
+ CTEGetLock(&RouteTableLock, &TableHandle);
+
+ for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next)
+ if ((NTE->nte_flags & NTE_VALID) &&
+ IP_ADDR_EQUAL(RCE->rce_src, NTE->nte_addr))
+ break;
+
+ if (NTE == NULL) {
+ // Didn't find a match.
+ CTEFreeLock(&RouteTableLock, TableHandle);
+ return FALSE;
+ }
+
+ RTE = LookupRTE(RCE->rce_dest, RCE->rce_src, HOST_ROUTE_PRI);
+
+ // See if we found an RTE.
+ if (RTE != NULL) {
+
+ Status = TRUE;
+
+ // Yep, we found one. Get the lock on the RCE, and make sure he's
+ // not pointing at an RTE already. We also need to make sure that the usecnt
+ // is 0, so that we can invalidate the RCE at the low level. If we set valid
+ // to TRUE without doing this we may get into a wierd situation where we
+ // link the RCE onto an RTE but the lower layer information is wrong, so we
+ // send to IP address X at mac address Y. So to be safe we don't set valid
+ // to TRUE until both usecnt is 0 and valid is FALSE. We'll keep coming
+ // through this routine on every send until that happens.
+
+ CTEGetLock(&RCE->rce_lock, &RCEHandle);
+ if (RCE->rce_usecnt == 0) {
+ // Nobody is using him, so we can link him up.
+ if (!(RCE->rce_flags & RCE_VALID)) {
+ Interface *IF;
+ // He's not valid. Invalidate the lower layer info, just in
+ // case. Make sure he's connected before we try to do this. If
+ // he's not marked as connected, don't bother to try and invalidate
+ // him as there is no interface.
+ if (RCE->rce_flags & RCE_CONNECTED) {
+ IF = (Interface *)RCE->rce_rte;
+ (*(IF->if_invalidate))(IF->if_lcontext, RCE);
+#ifdef _PNP_POWER
+ if (RCE->rce_flags & RCE_REFERENCED) {
+ LockedDerefIF(IF);
+ RCE->rce_flags &= ~RCE_REFERENCED;
+ }
+#endif
+ } else {
+ CTEAssert(!(RCE->rce_flags & RCE_REFERENCED));
+ }
+
+ // Link the RCE on the RTE, and set up the back pointer.
+ RCE->rce_rte = RTE;
+ RCE->rce_flags |= RCE_VALID;
+ RCE->rce_next = RTE->rte_rcelist;
+ RTE->rte_rcelist = RCE;
+
+ // Make sure the RTE is connected. If not, try to connect him.
+ if (!(RTE->rte_flags & RTE_IF_VALID)) {
+ // Not connected. Try to connect him.
+ RTE = FindValidIFForRTE(RTE, RCE->rce_dest, RCE->rce_src,
+ Protocol, Buffer, Length);
+ if (RTE != NULL) {
+ // Got one, so mark as connected.
+ CTEAssert(!(RCE->rce_flags & RCE_REFERENCED));
+#ifdef _PNP_POWER
+ RCE->rce_flags |= (RCE_CONNECTED | RCE_REFERENCED);
+ RTE->rte_if->if_refcount++;
+#else
+ RCE->rce_flags |= RCE_CONNECTED;
+
+#endif
+ } else {
+
+ // Couldn't get a valid i/f. Mark the RCE as not connected,
+ // and set up to fail this call.
+ CTEAssert(FALSE);
+ RCE->rce_flags &= ~RCE_CONNECTED;
+ Status = FALSE;
+ }
+ } else {
+ // The RTE is connected, mark the RCE as connected.
+ CTEAssert(!(RCE->rce_flags & RCE_REFERENCED));
+#ifdef _PNP_POWER
+ RCE->rce_flags |= (RCE_CONNECTED | RCE_REFERENCED);
+ RTE->rte_if->if_refcount++;
+#else
+ RCE->rce_flags |= RCE_CONNECTED;
+#endif
+ }
+ } else {
+ // The RCE is valid. See if it's connected.
+ if (!(RCE->rce_flags & RCE_CONNECTED)) {
+
+ // Not connected, try to get a valid i/f.
+ if (!(RTE->rte_flags & RTE_IF_VALID)) {
+ RTE = FindValidIFForRTE(RTE, RCE->rce_dest, RCE->rce_src,
+ Protocol, Buffer, Length);
+ if (RTE != NULL) {
+ RCE->rce_flags |= RCE_CONNECTED;
+#ifdef _PNP_POWER
+ CTEAssert(!(RCE->rce_flags & RCE_REFERENCED));
+ RCE->rce_flags |= RCE_REFERENCED;
+ RTE->rte_if->if_refcount++;
+#endif
+ } else {
+
+ // Couldn't connect, so fail.
+ CTEAssert(FALSE);
+ Status = FALSE;
+ }
+ } else { // Already connected, just mark as valid.
+ RCE->rce_flags |= RCE_CONNECTED;
+#ifdef _PNP_POWER
+ if (!(RCE->rce_flags & RCE_REFERENCED)) {
+ RCE->rce_flags |= RCE_REFERENCED;
+ RTE->rte_if->if_refcount++;
+ }
+#endif
+ }
+ }
+ }
+ }
+
+ // Free the locks and we're done.
+ CTEFreeLock(&RCE->rce_lock, RCEHandle);
+ CTEFreeLock(&RouteTableLock, TableHandle);
+ return Status;
+ } else {
+ // No route! Fail the call.
+ CTEFreeLock(&RouteTableLock, TableHandle);
+ return FALSE;
+ }
+
+}
+//** IPGetPInfo - Get information..
+//
+// Called by an upper layer to get information about a path. We return the
+// MTU of the path and the maximum link speed to be expected on the path.
+//
+// Input: Dest - Destination address.
+// Src - Src address.
+// NewMTU - Where to store path MTU (may be NULL).
+// MaxPathSpeed - Where to store maximum path speed (may be NULL).
+//
+// Returns: Status of attempt to get new MTU.
+//
+IP_STATUS
+IPGetPInfo(IPAddr Dest, IPAddr Src, uint *NewMTU, uint *MaxPathSpeed)
+{
+ CTELockHandle Handle;
+ RouteTableEntry *RTE;
+ IP_STATUS Status;
+
+ CTEGetLock(&RouteTableLock, &Handle);
+ RTE = LookupRTE(Dest, Src, HOST_ROUTE_PRI);
+ if (RTE != NULL) {
+ if (NewMTU != NULL)
+ *NewMTU = RTE->rte_mtu;
+ if (MaxPathSpeed != NULL)
+ *MaxPathSpeed = RTE->rte_if->if_speed;
+ Status = IP_SUCCESS;
+ } else
+ Status = IP_DEST_HOST_UNREACHABLE;
+
+ CTEFreeLock(&RouteTableLock, Handle);
+ return Status;
+
+}
+
+//** IPCheckRoute - Check that a route is valid.
+//
+// Called by an upper layer when it believes a route might be invalid.
+// We'll check if we can. If the upper layer is getting there through a
+// route derived via ICMP (presumably a redirect) we'll check to see
+// if it's been learned within the last minute. If it has, it's assumed
+// to still be valid. Otherwise, we'll mark it as down and try to find
+// another route there. If we can, we'll delete the old route. Otherwise
+// we'll leave it. If the route is through a default gateway we'll switch
+// to another one if we can. Otherwise, we'll just leave - we don't mess
+// with manually configured routes.
+//
+// Input: Dest - Destination to be reached.
+// Src - Src we're sending from.
+//
+// Returns: Nothing.
+//
+void
+IPCheckRoute(IPAddr Dest, IPAddr Src)
+{
+ RouteTableEntry *RTE;
+ RouteTableEntry *NewRTE;
+ RouteTableEntry *TempRTE;
+ CTELockHandle Handle;
+ uint Now = CTESystemUpTime() / 1000L;
+
+ if (DeadGWDetect) {
+ // We are doing dead G/W detection. Get the lock, and try and
+ // find the route.
+ CTEGetLock(&RouteTableLock, &Handle);
+ RTE = LookupRTE(Dest, Src, HOST_ROUTE_PRI);
+ if (RTE != NULL && ((Now - RTE->rte_valid) > MIN_RT_VALID)) {
+
+ // Found a route, and it's older than the minimum valid time. If it
+ // goes through a G/W, and is a route we learned via ICMP or is a
+ // default route, do something with it.
+ if (!IP_ADDR_EQUAL(RTE->rte_addr, IPADDR_LOCAL)) {
+ // It's not through a G/W.
+
+ if (RTE->rte_proto == IRE_PROTO_ICMP) {
+
+ // Came from ICMP. Mark as invalid, and then make sure
+ // we have another route there.
+ RTE->rte_flags &= ~RTE_VALID;
+ NewRTE = LookupRTE(Dest, Src, HOST_ROUTE_PRI);
+
+ if (NewRTE == NULL) {
+ // Can't get there any other way so leave this
+ // one alone.
+ RTE->rte_flags |= RTE_VALID;
+ } else {
+ // There is another route, so destroy this one. Use
+ // FindSpecificRTE to find the previous RTE.
+ TempRTE = FindSpecificRTE(RTE->rte_dest, RTE->rte_mask,
+ RTE->rte_addr, RTE->rte_if, &NewRTE);
+ CTEAssert(TempRTE == RTE);
+ DeleteRTE(NewRTE, TempRTE);
+ }
+ } else {
+ if (RTE->rte_mask == DEFAULT_MASK) {
+
+ // This is a default gateway. If we have more than one
+ // configured move to the next one.
+
+ if (DefGWConfigured > 1) {
+ // Have more than one. Try the next one. First
+ // invalidate any RCEs on this G/W.
+
+ InvalidateRCEChain(RTE);
+ if (DefGWActive == 1) {
+ // No more active. Revalidate all of them,
+ // and try again.
+ ValidateDefaultGWs(NULL_IP_ADDR);
+ CTEAssert(DefGWActive == DefGWConfigured);
+ } else {
+ // More than one active, so invalidate this
+ // one, and move to the next one. Stamp the
+ // next one with a valid time of Now, so we
+ // don't move from him too easily.
+ --DefGWActive;
+ RTE->rte_flags &= ~RTE_VALID;
+ RTE = FindRTE(Dest, Src, IPHash(0),
+ DEFAULT_ROUTE_PRI, DEFAULT_ROUTE_PRI);
+ if (RTE == NULL) {
+ // No more default gateways! This is bad.
+ CTEAssert(FALSE);
+ ValidateDefaultGWs(NULL_IP_ADDR);
+ CTEAssert(DefGWActive == DefGWConfigured);
+ } else {
+ CTEAssert(RTE->rte_mask == DEFAULT_MASK);
+ RTE->rte_valid = Now;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ CTEFreeLock(&RouteTableLock, Handle);
+ }
+}
+
+
+//** FindRCE - Find an RCE on an RTE.
+//
+// A routine to find an RCE that's chained on an RTE. We assume the lock
+// is held on the RTE.
+//
+// Entry: RTE - RTE to search.
+// Dest - Destination address of RTE to find.
+// Src - Source address of RTE to find.
+//
+// Returns: Pointer to RTE found, or NULL.
+//
+RouteCacheEntry *
+FindRCE(RouteTableEntry *RTE, IPAddr Dest, IPAddr Src)
+{
+ RouteCacheEntry *CurrentRCE;
+
+ CTEAssert(!IP_ADDR_EQUAL(Src, NULL_IP_ADDR));
+ for (CurrentRCE = RTE->rte_rcelist; CurrentRCE != NULL;
+ CurrentRCE = CurrentRCE->rce_next) {
+ if ( IP_ADDR_EQUAL(CurrentRCE->rce_dest, Dest) &&
+ IP_ADDR_EQUAL(CurrentRCE->rce_src, Src)) {
+ break;
+ }
+ }
+ return CurrentRCE;
+
+}
+
+//** OpenRCE - Open an RCE for a specific route.
+//
+// Called by the upper layer to open an RCE. We look up the type of the address
+// - if it's invalid, we return 'Destination invalid'. If not, we look up the
+// route, fill in the RCE, and link it on the correct RTE.
+//
+// As an added bonus, this routine will return the local address to use
+// to reach the destination.
+//
+// Entry: Address - Address for which we are to open an RCE.
+// Src - Source address we'll be using.
+// RCE - Pointer to where to return pointer to RCE.
+// Type - Pointer to where to return destination type.
+// MSS - Pointer to where to return MSS for route.
+// OptInfo - Pointer to option information, such as TOS and
+// any source routing info.
+//
+// Returns: Source IP address to use. This will be NULL_IP_ADDR if the
+// specified destination is unreachable for any reason.
+//
+IPAddr
+OpenRCE(IPAddr Address, IPAddr Src, RouteCacheEntry **RCE, uchar *Type,
+ ushort *MSS, IPOptInfo *OptInfo)
+{
+ RouteTableEntry *RTE; // Pointer to RTE to put RCE on.
+ CTELockHandle TableLock;
+ uchar LocalType;
+
+
+ if (!IP_ADDR_EQUAL(OptInfo->ioi_addr, NULL_IP_ADDR))
+ Address = OptInfo->ioi_addr;
+
+ CTEGetLock(&RouteTableLock, &TableLock);
+
+ // Make sure we're not in DHCP update.
+ if (DHCPActivityCount != 0) {
+ // We are updating DHCP. Just fail this now, since we're in an
+ // indeterminate state.
+ CTEFreeLock(&RouteTableLock, TableLock);
+ return NULL_IP_ADDR;
+ }
+
+ LocalType = GetAddrType(Address);
+
+ *Type = LocalType;
+
+ // If the specified address isn't invalid, continue.
+ if (LocalType != DEST_INVALID) {
+ RouteCacheEntry *NewRCE;
+
+ // If he's specified a source address, loop through the NTE table
+ // now and make sure it's valid.
+ if (!IP_ADDR_EQUAL(Src, NULL_IP_ADDR)) {
+ NetTableEntry *NTE;
+
+ for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next)
+ if ((NTE->nte_flags & NTE_VALID) &&
+ IP_ADDR_EQUAL(Src, NTE->nte_addr))
+ break;
+
+ if (NTE == NULL) {
+ // Didn't find a match.
+ CTEFreeLock(&RouteTableLock, TableLock);
+ return NULL_IP_ADDR;
+ }
+ }
+
+ // Find the route for this guy. If we can't find one, return NULL.
+ RTE = LookupRTE(Address, Src, HOST_ROUTE_PRI);
+
+ if (RTE != (RouteTableEntry *)NULL) {
+ CTELockHandle RCEHandle;
+ RouteCacheEntry *OldRCE;
+
+ // We found one.
+ *MSS = (ushort)RTE->rte_mtu; // Return the route MTU.
+
+ if (IP_LOOPBACK_ADDR(Src) && (RTE->rte_if != &LoopInterface)) {
+ // The upper layer is sending from a loopback address, but the
+ // destination isn't reachable through the loopback interface.
+ // Fail the request.
+ CTEFreeLock(&RouteTableLock, TableLock);
+ return NULL_IP_ADDR;
+ }
+
+ // We have the RTE. Fill in the RCE, and link it on the RTE.
+ if (!IP_ADDR_EQUAL(RTE->rte_addr, IPADDR_LOCAL))
+ *Type |= DEST_OFFNET_BIT; // Tell upper layer it's off
+ // net.
+
+ //
+ // If no source address was specified, then use the best address
+ // for the interface. This will generally prevent dynamic NTE's from
+ // being chosen as the source for wildcard binds.
+ //
+ if (IP_ADDR_EQUAL(Src, NULL_IP_ADDR)) {
+
+ if (LocalType == DEST_LOCAL)
+ Src = Address;
+ else {
+ NetTableEntry *SrcNTE;
+
+ SrcNTE = BestNTEForIF(
+ ADDR_FROM_RTE(RTE, Address),
+ RTE->rte_if
+ );
+
+ if (SrcNTE == NULL) {
+ // Can't find an address! Fail the request.
+ CTEFreeLock(&RouteTableLock, TableLock);
+ return NULL_IP_ADDR;
+ }
+
+ Src = SrcNTE->nte_addr;
+ }
+ }
+
+ // Now, see if an RCE already exists for this.
+ if ((OldRCE = FindRCE(RTE, Address, Src)) == NULL) {
+
+ // Don't have an existing RCE. See if we can get a new one,
+ // and fill it in.
+
+ NewRCE = CTEAllocMem(sizeof(RouteCacheEntry));
+ *RCE = NewRCE;
+
+ if (NewRCE != NULL) {
+ CTEMemSet(NewRCE, 0, sizeof(RouteCacheEntry));
+
+ NewRCE->rce_src = Src;
+ NewRCE->rce_dtype = LocalType;
+ NewRCE->rce_cnt = 1;
+ CTEInitLock(&NewRCE->rce_lock);
+ NewRCE->rce_dest = Address;
+ NewRCE->rce_rte = RTE;
+ NewRCE->rce_flags = RCE_VALID;
+ if (RTE->rte_flags & RTE_IF_VALID) {
+ NewRCE->rce_flags |= RCE_CONNECTED;
+#ifdef _PNP_POWER
+ //* Update the ref. count for this interface.
+ NewRCE->rce_flags |= RCE_REFERENCED;
+ RTE->rte_if->if_refcount++;
+#endif
+ }
+ NewRCE->rce_next = RTE->rte_rcelist;
+ RTE->rte_rcelist = NewRCE;
+ }
+
+ CTEFreeLock(&RouteTableLock, TableLock);
+ return Src;
+ } else {
+ // We have an existing RCE. We'll return his source as the
+ // valid source, bump the reference count, free the locks
+ // and return.
+ CTEGetLock(&OldRCE->rce_lock, &RCEHandle);
+ OldRCE->rce_cnt++;
+ *RCE = OldRCE;
+ CTEFreeLock(&OldRCE->rce_lock, RCEHandle);
+ CTEFreeLock(&RouteTableLock, TableLock);
+ return Src;
+ }
+ } else {
+ CTEFreeLock(&RouteTableLock, TableLock);
+ return NULL_IP_ADDR;
+ }
+ }
+
+ CTEFreeLock(&RouteTableLock, TableLock);
+ return NULL_IP_ADDR;
+}
+
+//* CloseRCE - Close an RCE.
+//
+// Called by the upper layer when it wants to close the RCE. We unlink it from
+// the RTE.
+//
+// Entry: RCE - Pointer to the RCE to be closed.
+//
+// Exit: Nothing.
+//
+void
+CloseRCE(RouteCacheEntry *RCE)
+{
+ RouteTableEntry *RTE; // Route on which RCE is linked.
+ RouteCacheEntry *PrevRCE;
+ CTELockHandle TableLock; // Lock handles used.
+ CTELockHandle RCEHandle;
+ Interface *IF;
+
+ if (RCE != NULL) {
+ CTEGetLock(&RouteTableLock, &TableLock);
+ CTEGetLock(&RCE->rce_lock, &RCEHandle);
+
+ if (--RCE->rce_cnt == 0) {
+ CTEAssert(RCE->rce_usecnt == 0);
+ if (RCE->rce_flags & RCE_VALID) {
+ // The RCE is valid, so we have a valid RTE in the pointer
+ // field. Walk down the RTE rcelist, looking for this guy.
+
+ RTE = RCE->rce_rte;
+ IF = RTE->rte_if;
+
+ PrevRCE = STRUCT_OF(RouteCacheEntry, &RTE->rte_rcelist,
+ rce_next);
+
+ // Walk down the list until we find him.
+ while (PrevRCE != NULL) {
+ if (PrevRCE->rce_next == RCE)
+ break;
+ PrevRCE = PrevRCE->rce_next;
+ }
+
+ CTEAssert(PrevRCE != NULL);
+ PrevRCE->rce_next = RCE->rce_next;
+ } else
+ IF = (Interface *)RCE->rce_rte;
+
+ if (RCE->rce_flags & RCE_CONNECTED) {
+ (*(IF->if_invalidate))(IF->if_lcontext, RCE);
+ }
+
+#ifdef _PNP_POWER
+ if (RCE->rce_flags & RCE_REFERENCED) {
+ LockedDerefIF(IF);
+ }
+#endif
+ CTEFreeLock(&RCE->rce_lock, RCEHandle);
+ CTEFreeMem(RCE);
+ }
+ else {
+ CTEFreeLock(&RCE->rce_lock, RCEHandle);
+ }
+
+ CTEFreeLock(&RouteTableLock, TableLock);
+
+ }
+
+}
+
+
+//* LockedAddRoute - Add a route to the routing table.
+//
+// Called by AddRoute to add a route to the routing table. We assume the
+// route table lock is already held. If the route to be added already exists
+// we update it. Routes are identified by a (Destination, Mask, FirstHop,
+// Interface) tuple. If an exact match exists we'll update the metric, which
+// may cause us to promote RCEs from other RTEs, or we may be demoted in which
+// case we'll invalidate our RCEs and let them be reassigned at transmission
+// time.
+//
+// If we have to create a new RTE we'll do so, and find the best previous
+// RTE, and promote RCEs from that one to the new one.
+//
+// The route table is an open hash structure. Within each hash chain the
+// RTEs with the longest masks (the 'priority') come first, and within
+// each priority the RTEs with the smallest metric come first.
+//
+//
+// Entry: Destination - Destination address for which route is being
+// added.
+// Mask - Mask for destination.
+// FirstHop - First hop for address. Could be IPADDR_LOCAL.
+// OutIF - Pointer to outgoing I/F.
+// MTU - Maximum MTU for this route.
+// Metric - Metric for this route.
+// Proto - Protocol type to store in route.
+// AType - Administrative type of route.
+//
+// Returns: Status of attempt to add route.
+//
+IP_STATUS
+LockedAddRoute(IPAddr Destination, IPMask Mask, IPAddr FirstHop,
+ Interface *OutIF, uint MTU, uint Metric, uint Proto, uint AType,
+ ROUTE_CONTEXT Context)
+{
+ uint RouteType; // SNMP route type.
+ RouteTableEntry *NewRTE, *OldRTE; // Entries for new and previous
+ // RTEs.
+ RouteTableEntry *PrevRTE; // Pointer to previous RTE.
+ CTELockHandle RCEHandle; // Lock handle for RCEs.
+ uint OldMetric; // Previous metric in use.
+ uint OldPriority; // Priority of previous route to
+ // destination.
+ RouteCacheEntry *CurrentRCE; // Current RCE being examined.
+ RouteCacheEntry *PrevRCE; // Previous RCE examined.
+ Interface *IF; // Interface being added on.
+ uint Priority; // Priority of the route.
+ uint TempMask; // Temporary copy of the mask.
+ uint Now = CTESystemUpTime() / 1000L; // System up time,
+ // in seconds.
+ uint MoveAny; // TRUE if we'll move any RCE.
+ ushort OldFlags;
+
+ // First do some consistency checks. Make sure that the Mask and
+ // Destination agree.
+ if (!IP_ADDR_EQUAL(Destination & Mask, Destination))
+ return IP_BAD_DESTINATION;
+
+ if (AType != ATYPE_PERM && AType != ATYPE_OVERRIDE && AType != ATYPE_TEMP)
+ return IP_BAD_REQ;
+
+#ifdef _PNP_POWER
+ // If the interface is marked as going away, fail this.
+ if (OutIF->if_flags & IF_FLAGS_DELETING) {
+ return IP_BAD_REQ;
+ }
+#endif
+
+ RouteType = IP_ADDR_EQUAL(FirstHop, IPADDR_LOCAL) ? IRE_TYPE_DIRECT :
+ IRE_TYPE_INDIRECT;
+
+
+ MTU = MAX(MTU, MIN_VALID_MTU);
+
+ // If the outgoing interface has NTEs attached but none are valid, fail
+ // this request unless it's a request to add the broadcast route.
+ if (OutIF != (Interface *)&DummyInterface) {
+ if (OutIF->if_ntecount == 0 && OutIF->if_nte != NULL &&
+ !IP_ADDR_EQUAL(Destination, OutIF->if_bcast) ) {
+ // This interface has NTEs attached, but none are valid. Fail the
+ // request.
+ return IP_BAD_REQ;
+ }
+ }
+
+
+ // First look and see if the RTE already exists.
+ NewRTE = FindSpecificRTE(Destination, Mask, FirstHop, OutIF, &PrevRTE);
+
+ if (NewRTE != NULL) {
+
+ // The RTE already exists, and we have a lock on it. See if we're
+ // updating the metric. If we're not, just return. Otherwise
+ // we'll remove the RTE and update the metric. If the metric is
+ // increasing, walk down the RCE chain on the RTE and invalidate
+ // the RCE back pointers so that they'll be revalidated upon
+ // transmits, and then reinsert the RTE. If the metric is
+ // decreasing we'll just fall through to the case below where we'll
+ // promote RCEs and insert the RTE.
+
+
+ // Update the things that won't cause routing table motion.
+ NewRTE->rte_mtu = MTU;
+ NewRTE->rte_proto = Proto;
+ NewRTE->rte_valid = Now;
+ NewRTE->rte_mtuchange = Now;
+ NewRTE->rte_context = Context;
+ OldFlags = NewRTE->rte_flags;
+
+ // We always turn off the increase flag when a route is updated, so
+ // that we take the long timeout to try to increase it. We also
+ // always turn on the valid flag.
+ NewRTE->rte_flags = (OldFlags & ~RTE_INCREASE) | RTE_VALID;
+ if (OutIF != (Interface *)&DummyInterface) {
+ NewRTE->rte_flags |= RTE_IF_VALID;
+ } else {
+
+ //
+ // Invalidating a previously valid route
+ //
+
+ NewRTE->rte_flags &= ~RTE_IF_VALID;
+ }
+
+ // If the RTE is for a default gateway and the old flags indicate
+ // he wasn't valid then we're essentially creating a new active
+ // default gateway. In the case bump the active default gateway count.
+ if (NewRTE->rte_mask == DEFAULT_MASK && !(OldFlags & RTE_VALID))
+ DefGWActive++;
+
+ // Need to update the metric, which will cause this RTE to move
+ // in the table.
+ OldMetric = NewRTE->rte_metric; // Save the old one.
+ RemoveRTE(PrevRTE, NewRTE); // Pull him from the chain.
+ NewRTE->rte_metric = Metric;
+
+ // Now see if we're increasing or decreasing the metric, or
+ // re-validating a previously invalid route. By definition, if the
+ // route wasn't valid before this there can't have been any RCEs
+ // attached to it, so we'll fall through to the promotion code
+ // and see if we can move any onto it. Otherwise, if we're
+ // demoting this route invalidate any RCEs on it.
+
+ if (Metric >= OldMetric && (OldFlags & RTE_VALID)) {
+ // We're increasing it, or leaving it the same. His valid state
+ // may have changed, so we'll we'll invalidate any RCEs on him
+ // now in any case.
+ InsertRTE(NewRTE);
+
+ InvalidateRCEChain(NewRTE);
+
+ //
+ // Whether the IF has changed or not, we can always overwrite it
+ // We wait till here to overwrite because if old rte_if was
+ // not dummy if, then we will want to invalidate RCEChain
+ // Since the invalidate function is stored in the interface
+ // structure we want to keep it around
+ //
+
+ NewRTE->rte_if = OutIF;
+
+ return IP_SUCCESS;
+ }
+
+
+ NewRTE->rte_if = OutIF;
+
+ // The metric is less than the old metric, so we're promoting this
+ // RTE. Fall through to the code below that deals with this, after
+ // saving the priority of the RTE.
+ Priority = NewRTE->rte_priority;
+
+ } else {
+
+ // Didn't find a matching RTE. Allocate a new one, and fill it in.
+ NewRTE = CTEAllocMem(sizeof(RouteTableEntry));
+
+ if (NewRTE == NULL) {
+ // Couldn't get the memory.
+ return IP_NO_RESOURCES;
+ }
+
+ IPSInfo.ipsi_numroutes++;
+
+ // Fill him in, and take the lock on him. To do this we'll need to
+ // calculate the priority.
+ Priority = 0;
+ TempMask = Mask;
+
+ while (TempMask) {
+ Priority += TempMask & 1;
+ TempMask >>= 1;
+ }
+
+ // Now initialize all of his fields.
+ NewRTE->rte_priority = Priority;
+
+ NewRTE->rte_dest = Destination;
+ NewRTE->rte_mask = Mask;
+ if (Mask == DEFAULT_MASK) {
+ // We're adding a default route.
+ DefGWConfigured++;
+ DefGWActive++;
+ }
+ NewRTE->rte_addr = FirstHop;
+ NewRTE->rte_metric = Metric;
+ NewRTE->rte_mtu = MTU;
+ NewRTE->rte_if = OutIF;
+ NewRTE->rte_rcelist = NULL;
+ NewRTE->rte_type = (ushort)RouteType;
+ NewRTE->rte_flags = RTE_VALID;
+ if (OutIF != (Interface *)&DummyInterface) {
+ NewRTE->rte_flags |= RTE_IF_VALID;
+ }
+ NewRTE->rte_proto = Proto;
+ NewRTE->rte_valid = Now;
+ NewRTE->rte_mtuchange = Now;
+ NewRTE->rte_admintype = AType;
+ NewRTE->rte_context = Context;
+ }
+
+ // At this point, NewRTE points to an initialized RTE that is not in the
+ // table. We hold the lock on NewRTE and on the RouteTable. First we'll
+ // find where we'll eventually insert the new RTE (we can't insert it
+ // yet, because we'll still need to search the table again and we can't
+ // do that while we hold a lock on an element in the table). Then we'll
+ // search the table for the next best route (i.e. a route with a priority
+ // less than or equal to ours), and if we find one we'll promote RCEs from
+ // that route to us. We'll actually have to search a chain of RTEs.
+
+ PrevRTE = FindInsertPoint(NewRTE);
+ OldRTE = LookupRTE(Destination, NULL_IP_ADDR, Priority);
+
+ // If we found one, try to promote from him.
+ if (OldRTE != NULL) {
+
+ // Found another RTE, and we have the lock on it. Starting with him,
+ // walk down the chain. At the start of this loop we know that the
+ // route described by OldRTE can reach our destination. If his metric
+ // is better than ours, we're done and we'll just insert our route.
+ // If his priority and metric are equal to ours we'll promote only
+ // those RCEs that exactly match our source address. Otherwise either
+ // his priority or metric is worse than ours, and we'll promote all
+ // appropriate RCEs.
+ //
+ // Since we specified the maximum priority in the call to LookupRTE
+ // as our priority, we know the priority of the route we found
+ // can't be greater than our priority.
+
+ OldMetric = OldRTE->rte_metric;
+ OldPriority = OldRTE->rte_priority;
+
+ // We'll do the search if his priority is less than ours, or his
+ // metric is > (i.e. worse than) our metric, or his metric equals
+ // our metric and the old route is on a different interface. We
+ // know OldPriority is <= our Priority, since we specified our
+ // priority in the call to LookupRTE above.
+
+ CTEAssert(OldPriority <= Priority);
+
+ if (OldPriority < Priority || OldMetric > Metric ||
+ (OldMetric == Metric && OldRTE->rte_if != OutIF)) {
+
+ // We're going to search. Figure out the mask to use in comparing
+ // source addresses.
+ if (OldPriority == Priority && OldMetric == Metric)
+ MoveAny = FALSE; // Only promote an exact match.
+ else
+ MoveAny = TRUE; // Promote any match.
+
+ for (;;) {
+ IF = OldRTE->rte_if;
+
+ PrevRCE = STRUCT_OF(RouteCacheEntry, &OldRTE->rte_rcelist,
+ rce_next);
+ CurrentRCE = PrevRCE->rce_next;
+ // Walk the list, promoting any that match.
+ while (CurrentRCE != NULL) {
+ CTEGetLock(&CurrentRCE->rce_lock, &RCEHandle);
+
+ // If the masked source address matches our masked address,
+ // and the destinations match, promote him.
+ if ((MoveAny || AddrOnIF(OutIF, CurrentRCE->rce_src)) &&
+ IP_ADDR_EQUAL(CurrentRCE->rce_dest & Mask, Destination)) {
+ // He matches. Pull him from the list and mark him as invalid.
+ // This will force a new lookup of the route next time he's
+ // used, which as a side effect will cause the route to be
+ // connected in the dial-on-demand case.
+ CTEAssert(CurrentRCE->rce_flags & RCE_VALID);
+ PrevRCE->rce_next = CurrentRCE->rce_next;
+ CurrentRCE->rce_flags &= ~RCE_VALID;
+ CurrentRCE->rce_rte = (RouteTableEntry *)IF;
+ if (CurrentRCE->rce_usecnt == 0) {
+ // No one's currently using him, so invalidate him.
+ if (CurrentRCE->rce_flags & RCE_CONNECTED) {
+ (*(IF->if_invalidate))(IF->if_lcontext, CurrentRCE);
+#ifdef _PNP_POWER
+ if (CurrentRCE->rce_flags & RCE_REFERENCED) {
+ LockedDerefIF(IF);
+ CurrentRCE->rce_flags &= ~RCE_REFERENCED;
+ }
+#endif
+ } else {
+#ifdef _PNP_POWER
+ CTEAssert(!(CurrentRCE->rce_flags & RCE_REFERENCED));
+#endif
+ }
+ }
+
+ } else {
+ // Doesn't match. Try the next one.
+ PrevRCE = CurrentRCE;
+ }
+ CTEFreeLock(&CurrentRCE->rce_lock, RCEHandle);
+ CurrentRCE = PrevRCE->rce_next;
+ }
+
+ // We've walked the RCE list on that old RTE. Look at the
+ // next one. If it has the same priority and metric as the
+ // old one, and also matches our destination, check it also. We
+ // don't need to RTEs that don't match this criteria, since we know
+ // RCEs are always kept on the 'best' RTE.
+ OldRTE = OldRTE->rte_next;
+ if (OldRTE != NULL) {
+ // We have another one. Check it out.
+ if (OldRTE->rte_priority == Priority &&
+ OldRTE->rte_metric == OldMetric &&
+ IP_ADDR_EQUAL(Destination & OldRTE->rte_mask,
+ OldRTE->rte_dest))
+ continue; // It matches, so try to promote
+ // RCEs.
+ }
+ break; // Exit out of the for (;;) loop.
+ }
+ } else {
+ // OldRTE is a better route than the one we're inserting, so don't
+ // do anything.
+ }
+ }
+
+ // At this point we're promoted any routes we need to, we hold the lock
+ // on NewRTE which still isn't inserted, and PrevRTE describes where to
+ // insert NewRTE. Insert it, free the lock, and return success.
+ InsertAfterRTE(PrevRTE, NewRTE);
+ return IP_SUCCESS;
+
+}
+
+//* AddRoute - Add a route to the routing table.
+//
+// This is just a shell for the real add route routine. All we do is take
+// the route table lock, and call the LockedAddRoute routine to deal with
+// the request. This is done this way because there are certain routines that
+// need to be able to atomically examine and add routes.
+//
+// Entry: Destination - Destination address for which route is being
+// added.
+// Mask - Mask for destination.
+// FirstHop - First hop for address. Could be IPADDR_LOCAL.
+// OutIF - Pointer to outgoing I/F.
+// MTU - Maximum MTU for this route.
+// Metric - Metric for this route.
+// Proto - Protocol type to store in route.
+// AType - Administrative type of route.
+// Context - Context for this route.
+//
+// Returns: Status of attempt to add route.
+//
+IP_STATUS
+AddRoute(IPAddr Destination, IPMask Mask, IPAddr FirstHop,
+ Interface *OutIF, uint MTU, uint Metric, uint Proto, uint AType,
+ ROUTE_CONTEXT Context)
+{
+ CTELockHandle TableHandle;
+ IP_STATUS Status;
+
+ CTEGetLock(&RouteTableLock, &TableHandle);
+ Status = LockedAddRoute(Destination, Mask, FirstHop, OutIF, MTU, Metric,
+ Proto, AType, Context);
+
+ CTEFreeLock(&RouteTableLock, TableHandle);
+ return Status;
+}
+
+//* DeleteRoute - Delete a route from the routing table.
+//
+// Called by upper layer or management code to delete a route from the routing
+// table. If we can't find the route we return an error. If we do find it, we
+// remove it, and invalidate any RCEs associated with it. These RCEs will be
+// reassigned the next time they're used. A route is uniquely identified by
+// a (Destination, Mask, FirstHop, Interface) tuple.
+//
+// Entry: Destination - Destination address for which route is being
+// deleted.
+// Mask - Mask for destination.
+// FirstHop - First hop on way to Destination. -1 means route is
+// local.
+// OutIF - Outgoing interface for route.
+//
+// Returns: Status of attempt to delete route.
+//
+IP_STATUS
+DeleteRoute(IPAddr Destination, IPMask Mask, IPAddr FirstHop, Interface *OutIF)
+{
+ RouteTableEntry *RTE; // RTE being deleted.
+ RouteTableEntry *PrevRTE; // Pointer to RTE in front of one
+ // being deleted.
+ CTELockHandle TableLock; // Lock handle for table.
+
+
+ // Look up the route by calling FindSpecificRTE. If we can't find it,
+ // fail the call.
+ CTEGetLock(&RouteTableLock, &TableLock);
+ RTE = FindSpecificRTE(Destination, Mask, FirstHop, OutIF, &PrevRTE);
+
+ if (RTE == NULL) {
+ // Didn't find the route, so fail the call.
+ CTEFreeLock(&RouteTableLock, TableLock);
+ return IP_BAD_ROUTE;
+ }
+
+#ifndef NT
+//
+// Disable admin check for NT, because the RAS server needs to be able to
+// delete a subnet route. This ability is restricted to Administrators only
+// by NT security checks.
+//
+//
+ if (RTE->rte_admintype == ATYPE_PERM) {
+ // Can't delete a permanent route.
+ CTEFreeLock(&RouteTableLock, TableLock);
+ return IP_BAD_REQ;
+ }
+#endif
+
+ // When we reach here we hold the lock on the RTE to be deleted, and
+ // PrevRTE points to the RTE immediately ahead of ours in the table.
+ // Call DeleteRTE to delete him.
+ DeleteRTE(PrevRTE, RTE);
+
+ CTEFreeLock(&RouteTableLock, TableLock);
+ return IP_SUCCESS;
+
+
+}
+
+//** Redirect - Process a redirect request.
+//
+// This is the redirect handler . We treat all redirects as host redirects as per the
+// host requirements RFC. We make a few sanity checks on the new first hop address, and then
+// we look up the current route. If it's not through the source of the redirect, just return.
+// If the current route to the destination is a host route, update the first hop and return.
+// If the route is not a host route, remove any RCE for this route from the RTE, create a
+// host route and place the RCE (if any) on the new RTE.
+//
+// Entry: NTE - Pointer to NetTableEntry for net on which Redirect
+// arrived.
+// RDSrc - IPAddress of source of redirect.
+// Target - IPAddress being redirected.
+// Src - Src IP address of DG that triggered RD.
+// FirstHop - New first hop for Target.
+//
+// Returns: Nothing.
+//
+void
+Redirect(NetTableEntry *NTE, IPAddr RDSrc, IPAddr Target, IPAddr Src,
+ IPAddr FirstHop)
+{
+ uint MTU;
+ RouteTableEntry *RTE;
+ CTELockHandle Handle;
+
+ if (IP_ADDR_EQUAL(FirstHop, NULL_IP_ADDR) || IP_LOOPBACK(FirstHop))
+ return; // Can't redirect to loopback
+ // address.
+
+ CTEAssert(IP_ADDR_EQUAL(NTE->nte_addr, Src));
+
+ // First make sure that this came from the gateway we're currently using to
+ // get to Target, and then lookup up the route to the new first hop. The new
+ // firsthop must be directly reachable, and on the same subnetwork or
+ // physical interface on which we received the redirect.
+
+
+ CTEGetLock(&RouteTableLock, &Handle);
+
+ // Make sure the source of the redirect is the current first hop gateway.
+ RTE = LookupRTE(Target, Src, HOST_ROUTE_PRI);
+ if (RTE == NULL || IP_ADDR_EQUAL(RTE->rte_addr, IPADDR_LOCAL) ||
+ !IP_ADDR_EQUAL(RTE->rte_addr, RDSrc)) {
+ CTEFreeLock(&RouteTableLock, Handle);
+ return; // A bad redirect.
+ }
+
+ CTEAssert(RTE->rte_flags & RTE_IF_VALID);
+
+ // If the current first hop gateway is a default gateway, see if we have
+ // another default gateway at FirstHop that is down. If so, mark him as
+ // up and invalidate the RCEs on this guy.
+ if (RTE->rte_mask == DEFAULT_MASK && ValidateDefaultGWs(FirstHop) != 0) {
+ // Have a default gateway that's been newly activated. Invalidate RCEs
+ // on the route, and we're done.
+ InvalidateRCEChain(RTE);
+ CTEFreeLock(&RouteTableLock, Handle);
+ return;
+ }
+
+ // We really need to add a host route through FirstHop. Make sure he's
+ // a valid first hop.
+ RTE = LookupRTE(FirstHop, Src, HOST_ROUTE_PRI);
+ if (RTE == NULL) {
+ CTEFreeLock(&RouteTableLock, Handle);
+ return; // Can't get there from here.
+ }
+
+ CTEAssert(RTE->rte_flags & RTE_IF_VALID);
+
+
+ // Check to make sure the new first hop is directly reachable, and is on the
+ // same subnet or physical interface we received the redirect on.
+ if (!IP_ADDR_EQUAL(RTE->rte_addr, IPADDR_LOCAL) || // Not directly reachable
+ // or wrong subnet.
+ ((NTE->nte_addr & NTE->nte_mask) != (FirstHop & NTE->nte_mask))) {
+ CTEFreeLock(&RouteTableLock, Handle);
+ return;
+ }
+
+ MTU = RTE->rte_mtu;
+
+ // Now add a host route. AddRoute will do the correct things with shifting
+ // RCEs around. We know that FirstHop is on the same subnet as NTE (from
+ // the check above), so it's valid to add the route to FirstHop as out
+ // going through NTE.
+ LockedAddRoute(Target, HOST_MASK, IP_ADDR_EQUAL(FirstHop, Target) ? IPADDR_LOCAL :
+ FirstHop, NTE->nte_if, MTU, 1, IRE_PROTO_ICMP, ATYPE_OVERRIDE,
+ RTE->rte_context);
+
+ CTEFreeLock(&RouteTableLock, Handle);
+}
+
+//* GetRaisedMTU - Get the next largest MTU in table..
+//
+// A utility function to search the MTU table for a larger value.
+//
+// Input: PrevMTU - MTU we're currently using. We want the
+// next largest one.
+//
+// Returns: New MTU size.
+//
+uint
+GetRaisedMTU(uint PrevMTU)
+{
+ uint i;
+
+ for (i = (sizeof(MTUTable)/sizeof(uint)) - 1; i != 0; i--) {
+ if (MTUTable[i] > PrevMTU)
+ break;
+ }
+
+ return MTUTable[i];
+}
+
+//* GuessNewMTU - Guess a new MTU, giving a DG size too big.
+//
+// A utility function to search the MTU table. As input we take in an MTU
+// size we believe to be too large, and search the table looking for the
+// next smallest one.
+//
+// Input: TooBig - Size that's too big.
+//
+// Returns: New MTU size.
+//
+uint
+GuessNewMTU(uint TooBig)
+{
+ uint i;
+
+ for (i = 0; i < ((sizeof(MTUTable)/sizeof(uint)) - 1); i++)
+ if (MTUTable[i] < TooBig)
+ break;
+
+ return MTUTable[i];
+}
+
+//* RouteFragNeeded - Handle being told we need to fragment.
+//
+// Called when we receive some external indication that we need to fragment
+// along a particular path. If we're doing MTU discovery we'll try to
+// update the route, if we can. We'll also notify the upper layers about
+// the new MTU.
+//
+// Input: IPH - Pointer to IP Header of datagram needing
+// fragmentation.
+// NewMTU - New MTU to be used (may be 0).
+//
+// Returns: Nothing.
+//
+void
+RouteFragNeeded(IPHeader UNALIGNED *IPH, ushort NewMTU)
+{
+ uint OldMTU;
+ CTELockHandle Handle;
+ RouteTableEntry *RTE;
+ ushort HeaderLength;
+
+ // If we're not doing PMTU discovery, don't do anything.
+ if (PMTUDiscovery) {
+
+ // We're doing PMTU discovery. Correct the given new MTU for the IP
+ // header size, which we don't save as we track MTUs.
+ if (NewMTU != 0) {
+ // Make sure the new MTU we got is at least the minimum valid size.
+ NewMTU = MAX(NewMTU, MIN_VALID_MTU);
+ NewMTU -= sizeof(IPHeader);
+ }
+
+ HeaderLength = (IPH->iph_verlen & (uchar)~IP_VER_FLAG) << 2;
+
+ // Get the current routing information.
+
+ CTEGetLock(&RouteTableLock, &Handle);
+
+ // Find an RTE for the destination.
+ RTE = LookupRTE(IPH->iph_dest, IPH->iph_src, HOST_ROUTE_PRI);
+
+ // If we couldn't find one, or the existing MTU is less than the new
+ // MTU, give up now.
+
+ if (RTE == NULL || (OldMTU = RTE->rte_mtu) < NewMTU) {
+ // No RTE, or an invalid new MTU. Just bail out now.
+ CTEFreeLock(&RouteTableLock, Handle);
+ return;
+ }
+
+ // If the new MTU is zero, figure out what the new MTU should be.
+ if (NewMTU == 0) {
+ ushort DGLength;
+
+ // The new MTU is zero. We'll make a best guess what the new
+ // MTU should be. We have the RTE for this route already.
+
+
+ // Get the length of the datagram that triggered this. Since we'll
+ // be comparing it against MTU values that we track without the
+ // IP header size included, subtract off that amount.
+ DGLength = (ushort)net_short(IPH->iph_length) - sizeof(IPHeader);
+
+ // We may need to correct this as per RFC 1191 for dealing with
+ // old style routers.
+ if (DGLength >= OldMTU) {
+ // The length of the datagram sent is not less than our
+ // current MTU estimate, so we need to back it down (assuming
+ // that the sending route has incorrectly added in the header
+ // length).
+ DGLength -= HeaderLength;
+
+ }
+
+ // If it's still larger than our current MTU, use the current
+ // MTU. This could happen if the upper layer sends a burst of
+ // packets which generate a sequence of ICMP discard messages. The
+ // first one we receive will cause us to lower our MTU. We then
+ // want to discard subsequent messages to avoid lowering it
+ // too much. This could conceivably be a problem if our
+ // first adjustment still results in an MTU that's too big,
+ // but we should converge adequately fast anyway, and it's
+ // better than accidentally underestimating the MTU.
+
+ if (DGLength > OldMTU)
+ NewMTU = OldMTU;
+ else
+ // Move down the table to the next lowest MTU.
+ NewMTU = GuessNewMTU(DGLength);
+ }
+
+ // We have the new MTU. Now add it to the table as a host route.
+ if (NewMTU != OldMTU)
+ LockedAddRoute(IPH->iph_dest, HOST_MASK, RTE->rte_addr, RTE->rte_if,
+ NewMTU, RTE->rte_metric, IRE_PROTO_ICMP, ATYPE_OVERRIDE,
+ RTE->rte_context);
+
+ CTEFreeLock(&RouteTableLock, Handle);
+
+ // We've added the route. Now notify the upper layers of the change.
+ ULMTUNotify(IPH->iph_dest, IPH->iph_src, IPH->iph_protocol,
+ (void *)((uchar *)IPH + HeaderLength), NewMTU);
+
+ }
+}
+
+//** IPRouteTimeout - IP routeing timeout handler.
+//
+// The IP routeing timeout routine, called once a minute. We look at all
+// host routes, and if we raise the MTU on them we do so.
+//
+// Entry: Timer - Timer being fired.
+// Context - Pointer to NTE being time out.
+//
+// Returns: Nothing.
+//
+void
+IPRouteTimeout(CTEEvent *Timer, void *Context)
+{
+ uint Now = CTESystemUpTime() / 1000L;
+ CTELockHandle Handle;
+ uint i;
+ RouteTableEntry *RTE, *PrevRTE;
+ uint RaiseMTU, Delta;
+ Interface *IF;
+ IPAddr Dest;
+ uint NewMTU;
+ NetTableEntry *NTE;
+
+ CTEGetLock(&RouteTableLock, &Handle);
+
+ for (i = 0; i < ROUTE_TABLE_SIZE; i++) {
+ // Walk down each chain, looking at the host routes. If we're
+ // doing PMTU discovery, see if we can raise the MTU.
+ PrevRTE = STRUCT_OF(RouteTableEntry, &RouteTable[i], rte_next);
+ RTE = RouteTable[i];
+ while (RTE != NULL && RTE->rte_mask == HOST_MASK) {
+ // Make sure he's valid.
+ if (RTE->rte_flags & RTE_VALID) {
+ if (PMTUDiscovery) {
+ // Check to see if we can raise the MTU on this guy.
+ Delta = Now - RTE->rte_mtuchange;
+
+ if (RTE->rte_flags & RTE_INCREASE)
+ RaiseMTU = (Delta >= MTU_INCREASE_TIME ? 1 : 0);
+ else
+ RaiseMTU = (Delta >= MTU_DECREASE_TIME ? 1 : 0);
+
+ if (RaiseMTU) {
+ // We need to raise this MTU. Set his change time to
+ // Now, so we don't do this again, and figure out
+ // what the new MTU should be.
+ RTE->rte_mtuchange = Now;
+ IF = RTE->rte_if;
+ if (RTE->rte_mtu < IF->if_mtu) {
+
+ RTE->rte_flags |= RTE_INCREASE;
+ // This is a candidate for change. Figure out
+ // what it should be.
+ NewMTU = MIN(GetRaisedMTU(RTE->rte_mtu),
+ IF->if_mtu);
+ RTE->rte_mtu = NewMTU;
+ Dest = RTE->rte_dest;
+
+ // We have the new MTU. Free the lock, and walk
+ // down the NTEs on the I/F. For each NTE,
+ // call up to the upper layer and tell him what
+ // his new MTU is.
+ CTEFreeLock(&RouteTableLock, Handle);
+ NTE = IF->if_nte;
+ while (NTE != NULL) {
+ if (NTE->nte_flags & NTE_VALID) {
+ ULMTUNotify(Dest, NTE->nte_addr, 0, NULL,
+ MIN(NewMTU, NTE->nte_mss));
+ }
+ NTE = NTE->nte_ifnext;
+ }
+
+ // We've notified everyone. Get the lock again,
+ // and start from the first element of this
+ // chain in case something's changed after we
+ // free the lock. We've updated the mtuchange
+ // time of this RTE, so we won't hit him again.
+ CTEGetLock(&RouteTableLock, &Handle);
+ PrevRTE = STRUCT_OF(RouteTableEntry, &RouteTable[i],
+ rte_next);
+ RTE = RouteTable[i];
+ continue;
+ } else
+ RTE->rte_flags &= ~RTE_INCREASE;
+ }
+ }
+ // If this route came in via ICMP, and we have no RCEs on it,
+ // and it's at least 10 minutes old, delete it.
+ if (RTE->rte_proto == IRE_PROTO_ICMP &&
+ RTE->rte_rcelist == NULL &&
+ (Now - RTE->rte_valid) > MAX_ICMP_ROUTE_VALID) {
+ // He needs to be deleted. Call DeleteRTE to do this.
+ DeleteRTE(PrevRTE, RTE);
+ RTE = PrevRTE->rte_next;
+ continue;
+ }
+ }
+ PrevRTE = RTE;
+ RTE = RTE->rte_next;
+ }
+ }
+
+ CTEFreeLock(&RouteTableLock, Handle);
+ CTEStartTimer(&IPRouteTimer, IP_ROUTE_TIMEOUT, IPRouteTimeout, NULL);
+
+}
+
+//* FreeFWPacket - Free a forwarding packet when we're done with it.
+//
+//
+// Input: Packet - Packet to be freed.
+//
+// Returns: Nothing.
+//
+void
+FreeFWPacket(PNDIS_PACKET Packet)
+{
+ CTELockHandle Handle;
+ FWContext *FWC;
+
+// BUGBUG - Portability issue
+
+#ifdef VXD
+ Packet->Private.Head = (PNDIS_BUFFER)NULL;
+ Packet->Private.Count = 0;
+ Packet->Private.PhysicalCount = 0;
+ Packet->Private.TotalLength = 0;
+#else // VXD
+#ifdef NT
+ //
+ // BUGBUG: This is inefficient. Need something better.
+ //
+ NdisReinitializePacket(Packet);
+#else // NT
+#error Need portable way to do this.
+#endif // NT
+#endif // VXD
+
+ FWC = (FWContext *)Packet->ProtocolReserved;
+ if (FWC->fc_options) {
+ CTEFreeMem(FWC->fc_options);
+ FWC->fc_options = (uchar *)NULL;
+ }
+
+ if (FWC->fc_buffhead) {
+ CTEGetLock(&FWBufFreeLock, &Handle);
+ FWC->fc_bufftail->Next = FWBufFree; // BUGBUG more portable.
+ FWBufFree = FWC->fc_buffhead;
+ CTEFreeLock(&FWBufFreeLock, Handle);
+ FWC->fc_buffhead = (PNDIS_BUFFER)NULL;
+ }
+#ifdef _PNP_POWER
+ // If there's an interface pointer here, dereference in now.
+ if (FWC->fc_if != NULL) {
+ DerefIF(FWC->fc_if);
+ FWC->fc_if = NULL;
+ }
+#endif
+
+ CTEGetLock(&FWPacketFreeLock, &Handle);
+ FWC->fc_pc.pc_common.pc_link = FWPacketFree;
+ FWPacketFree = Packet;
+ CTEFreeLock(&FWPacketFreeLock, Handle);
+
+}
+
+//* GrowFWPackets - Grow the FW packet list, if we can.
+//
+// Called when we need to allocate a FW packet, but don't have one. We'll try to grow the
+// FWPacket list now.
+//
+// Input: Nothing.
+//
+// Returns: TRUE if we succeeded in growing the list, FALSE otherwise.
+//
+uint
+GrowFWPackets(void)
+{
+ CTELockHandle Handle;
+ IPHeader *HeaderPtr;
+ NDIS_HANDLE BufferPool;
+ NDIS_HANDLE PacketPool;
+ PNDIS_BUFFER Buffer;
+ PNDIS_PACKET Packet;
+ NDIS_STATUS Status;
+ uint i;
+ uint AmountToGrow;
+
+ CTEGetLock(&FWPacketFreeLock, &Handle);
+
+ AmountToGrow = MIN(MaxFWPackets - CurrentFWPackets, FWPACKET_GROW_AMOUNT);
+ HeaderPtr = NULL;
+
+ if (AmountToGrow != 0) {
+
+ // We have room to grow yet, so try to. First get the memory for our header buffers.
+ HeaderPtr = CTEAllocMem(AmountToGrow * sizeof(IPHeader));
+ if (HeaderPtr == (IPHeader *)NULL)
+ goto failure; // Couldn't get it.
+
+ // Now try to get NDIS buffers for the headers.
+ NdisAllocateBufferPool(&Status, &BufferPool, AmountToGrow);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ goto failure;
+ }
+
+ // Now try to get the packets themselves.
+ NdisAllocatePacketPool(&Status, &PacketPool, AmountToGrow, sizeof(FWContext));
+ if (Status != NDIS_STATUS_SUCCESS) {
+ NdisFreeBufferPool(BufferPool);
+ goto failure;
+ }
+
+ // Since we have everything we need, update the current count.
+ CurrentFWPackets += AmountToGrow;
+
+ CTEFreeLock(&FWPacketFreeLock, Handle);
+
+ // We got the resources we need. Loop through and put them on.
+ for (i = 0; i < AmountToGrow; i++) {
+ FWContext *FWC;
+
+ NdisAllocateBuffer(&Status, &Buffer, BufferPool, HeaderPtr,
+ sizeof(IPHeader));
+ if (Status != NDIS_STATUS_SUCCESS)
+ CTEAssert(FALSE);
+ NdisAllocatePacket(&Status, &Packet, PacketPool);
+ if (Status != NDIS_STATUS_SUCCESS)
+ CTEAssert(FALSE);
+
+ CTEMemSet(Packet->ProtocolReserved, 0, sizeof(FWContext));
+ FWC = (FWContext *)Packet->ProtocolReserved;
+ FWC->fc_hndisbuff = Buffer;
+ FWC->fc_hbuff = HeaderPtr;
+ FWC->fc_pc.pc_common.pc_flags = PACKET_FLAG_FW;
+ FWC->fc_pc.pc_common.pc_owner = PACKET_OWNER_IP;
+ FWC->fc_pc.pc_pi = RtPI;
+ FWC->fc_pc.pc_context = Packet;
+
+ FreeFWPacket(Packet);
+ HeaderPtr++;
+ }
+ return TRUE;
+ }
+
+failure:
+ CTEFreeLock(&FWPacketFreeLock, Handle);
+ if (HeaderPtr != NULL) {
+ CTEFreeMem(HeaderPtr);
+ }
+ return FALSE;
+}
+
+//* GrowFWBuffer - Grow the FW buffer pool, if we can.
+//
+// Called when we need to grow the FW buffer pool. We'll grow it up to the maximum size
+// specified by the user.
+//
+// Input: Nothing.
+//
+// Returns: TRUE if we succeeded in growing the pool, FALSE otherwise.
+//
+uint
+GrowFWBuffer(void)
+{
+ CTELockHandle Handle;
+ uint AvailableBufferSpace;
+ uint NewBufferCount;
+ uint i;
+ uchar *BufferPtr = NULL;
+ NDIS_STATUS Status;
+ PNDIS_BUFFER Buffer;
+ NDIS_HANDLE BufferPool;
+
+ CTEGetLock(&FWPacketFreeLock, &Handle);
+ AvailableBufferSpace = MIN(MaxFWBufferSize - CurrentFWBufferSize, FW_BUF_GROW_AMOUNT);
+
+ // If we have room to grow, do so.
+ if (AvailableBufferSpace >= FW_BUF_SIZE) {
+ // We have room to grow the buffer, so do so. First, round to a multiple of our
+ // FW buffer size.
+ NewBufferCount = AvailableBufferSpace / FW_BUF_SIZE;
+ AvailableBufferSpace = NewBufferCount * FW_BUF_SIZE;
+
+ // Allocate the resources we need.
+ BufferPtr = CTEAllocMem(AvailableBufferSpace);
+ if (BufferPtr == NULL) {
+ goto failure;
+ }
+
+ NdisAllocateBufferPool(&Status, &BufferPool, NewBufferCount);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ goto failure;
+ }
+
+ // We got what we needed. Now loop through and put them on the list.
+ for (i = 0; i < NewBufferCount; i++) {
+ NdisAllocateBuffer(&Status, &Buffer, BufferPool, BufferPtr, FW_BUF_SIZE);
+ if (Status != NDIS_STATUS_SUCCESS)
+ CTEAssert(FALSE);
+
+ Buffer->Next = FWBufFree;
+ FWBufFree = Buffer;
+ BufferPtr += FW_BUF_SIZE;
+ }
+
+ CurrentFWBufferSize += AvailableBufferSpace;
+ CTEFreeLock(&FWPacketFreeLock, Handle);
+ return TRUE;
+
+ }
+
+failure:
+ CTEFreeLock(&FWPacketFreeLock, Handle);
+ if (BufferPtr != NULL) {
+ CTEFreeMem(BufferPtr);
+ }
+ return FALSE;
+
+}
+
+//* FWSendComplete - Complete the transmission of a forwarded packet.
+//
+// This is called when the send of a forwarded packet is done. We'll free the resources
+// and get the next send going, if there is one. If there isn't, we'll decrement the pending
+// count.
+//
+// Input: Packet - Packet being completed.
+// Buffer - Pointer to buffer chain being completed.
+//
+// Returns: Nothing.
+//
+void
+FWSendComplete(void *SendContext, PNDIS_BUFFER Buffer)
+{
+ PNDIS_PACKET Packet = (PNDIS_PACKET)SendContext;
+ FWContext *FWC = (FWContext *)Packet->ProtocolReserved;
+ RouteSendQ *RSQ;
+ CTELockHandle Handle;
+ FWQ *NewFWQ;
+ PNDIS_PACKET NewPacket;
+
+
+#ifdef DEBUG
+ if (!Buffer)
+ DEBUGCHK;
+#endif
+
+ if (!IS_BCAST_DEST(FWC->fc_dtype))
+ RSQ = &((RouteInterface *)FWC->fc_if)->ri_q;
+ else
+ RSQ = BCastRSQ;
+
+ FreeFWPacket(Packet);
+
+ CTEGetLock(&RSQ->rsq_lock, &Handle);
+ CTEAssert(RSQ->rsq_pending <= RSQ->rsq_maxpending);
+
+ RSQ->rsq_pending--;
+
+ CTEAssert(*(int *)&RSQ->rsq_pending >= 0);
+
+ if (RSQ->rsq_qlength != 0) { // Have more to send.
+ // Make sure we're not already running through this. If we are, quit.
+ if (!RSQ->rsq_running) {
+
+ // We could schedule this off for an event, but under NT that
+ // could me a context switch for every completing packet in the
+ // normal case. For now, just do it in a loop guarded with
+ // rsq_running.
+ RSQ->rsq_running = TRUE;
+
+ // Loop while we haven't hit our send limit and we still have
+ // stuff to send.
+ while (RSQ->rsq_pending < RSQ->rsq_maxpending &&
+ RSQ->rsq_qlength != 0) {
+#ifdef DEBUG
+ if (RSQ->rsq_qh.fq_next == &RSQ->rsq_qh)
+ DEBUGCHK; // Empty Q!
+#endif
+ // Pull one off the queue, and update qlength.
+ NewFWQ = RSQ->rsq_qh.fq_next;
+ RSQ->rsq_qh.fq_next = NewFWQ->fq_next;
+ NewFWQ->fq_next->fq_prev = NewFWQ->fq_prev;
+ RSQ->rsq_qlength--;
+
+ // Update pending before we send.
+ RSQ->rsq_pending++;
+ CTEFreeLock(&RSQ->rsq_lock, Handle);
+ NewPacket = PACKET_FROM_FWQ(NewFWQ);
+ TransmitFWPacket(NewPacket,
+ ((FWContext *)NewPacket->ProtocolReserved)->fc_datalength);
+ CTEGetLock(&RSQ->rsq_lock, &Handle);
+ }
+
+ RSQ->rsq_running = FALSE;
+ }
+ }
+
+ CTEFreeLock(&RSQ->rsq_lock, Handle);
+
+}
+
+//* TransmitFWPacket - Transmit a forwarded packet on a link.
+//
+// Called when we know we can send a packet. We fix up the header, and send it.
+//
+// Input: Packet - Packet to be sent.
+// DataLength - Length of data.
+//
+// Returns: Nothing.
+//
+void
+TransmitFWPacket(PNDIS_PACKET Packet, uint DataLength)
+{
+ FWContext *FC = (FWContext *)Packet->ProtocolReserved;
+ PNDIS_BUFFER HBuffer, Buffer;
+ IP_STATUS Status;
+ PVOID VirtualAddress;
+ UINT BufLen;
+
+ // Fix up the packet. Remove the existing buffer chain, and put our header on
+ // the front.
+
+ // BUGBUG - Get NDIS fixed to make this portable.
+#ifdef VXD
+ Buffer = Packet->Private.Head;
+ HBuffer = FC->fc_hndisbuff;
+ Packet->Private.Head = HBuffer;
+ Packet->Private.Tail = HBuffer;
+ HBuffer->Next = (PNDIS_BUFFER)NULL;
+ Packet->Private.TotalLength = sizeof(IPHeader);
+ Packet->Private.Count = 1;
+
+ Packet->Private.PhysicalCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(HBuffer->VirtualAddress,
+ sizeof(IPHeader));
+#else // VXD
+#ifdef NT
+ Buffer = Packet->Private.Head;
+ HBuffer = FC->fc_hndisbuff;
+ Packet->Private.Head = HBuffer;
+ Packet->Private.Tail = HBuffer;
+ NDIS_BUFFER_LINKAGE(HBuffer) = (PNDIS_BUFFER)NULL;
+ Packet->Private.TotalLength = sizeof(IPHeader);
+ Packet->Private.Count = 1;
+
+ NdisQueryBuffer(HBuffer, &VirtualAddress, &BufLen);
+
+ Packet->Private.PhysicalCount =
+ ADDRESS_AND_SIZE_TO_SPAN_PAGES(
+ VirtualAddress,
+ sizeof(IPHeader)
+ );
+#else // NT
+#error HELP! Need to make this code portable.
+#endif // NT
+#endif // VXD
+
+ // Figure out how to send it. If it's not a broadcast we'll either send it or
+ // have it fragmented. If it is a broadcast we'll let our send broadcast routine
+ // handle it.
+ if (FC->fc_dtype != DEST_BCAST) {
+
+ if ((DataLength + (uint)FC->fc_optlength) <= FC->fc_mtu)
+ Status = SendIPPacket(FC->fc_if, FC->fc_nexthop, Packet, Buffer,
+ FC->fc_hbuff, FC->fc_options, (uint)FC->fc_optlength);
+ else { // Need to fragment this.
+ BufferReference *BR = CTEAllocMem(sizeof(BufferReference));
+
+ if (BR == (BufferReference *)NULL) { // Couldn't get a BufferReference
+ FWSendComplete(Packet, Buffer);
+ return;
+ }
+ BR->br_buffer = Buffer;
+ BR->br_refcount = 0;
+ CTEInitLock(&BR->br_lock);
+ FC->fc_pc.pc_br = BR;
+ Status = IPFragment(FC->fc_if, FC->fc_mtu, FC->fc_nexthop, Packet,
+ FC->fc_hbuff, Buffer, DataLength, FC->fc_options,
+ (uint)FC->fc_optlength, (int *)NULL);
+
+ //
+ // Fragmentation needed with the DF flag set should have been
+ // handled in IPForward. We don't have the original header
+ // any longer, so silently drop the packet.
+ //
+ CTEAssert(Status != IP_PACKET_TOO_BIG);
+ }
+ } else
+ Status = SendIPBCast(FC->fc_srcnte, FC->fc_nexthop, Packet, FC->fc_hbuff,
+ Buffer, DataLength, FC->fc_options, (uint)FC->fc_optlength,
+ FC->fc_sos, &FC->fc_index);
+
+ if (Status != IP_PENDING)
+ FWSendComplete(Packet, Buffer);
+}
+
+//* SendFWPacket - Send a packet that needs to be forwarded.
+//
+// This routine is invoked when we actually get around to sending a packet.
+// We look and see if we can give another queued send to the outgoing link,
+// and if so we send on that link. Otherwise we put it on the outgoing queue
+// and remove it later.
+//
+// Input: SrcNTE - Source NTE of packet.
+// Packet - Packet to be send, containg all needed context info.
+// Status - Status of transfer data.
+// DataLength - Length in bytes of data to be send.
+//
+// Returns: Nothing.
+//
+void
+SendFWPacket(PNDIS_PACKET Packet, NDIS_STATUS Status, uint DataLength)
+{
+
+ FWContext *FC = (FWContext *)Packet->ProtocolReserved;
+ Interface *IF = FC->fc_if;
+ RouteSendQ *RSQ;
+ CTELockHandle Handle;
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ // Figure out which logical queue it belongs on, and if we don't already
+ // have too many things going there, send it. If we can't send it now we'll
+ // queue it for later.
+ if (IS_BCAST_DEST(FC->fc_dtype))
+ RSQ = BCastRSQ;
+ else
+ RSQ = &((RouteInterface *)IF)->ri_q;
+
+ CTEGetLock(&RSQ->rsq_lock, &Handle);
+
+ if (RSQ->rsq_pending < RSQ->rsq_maxpending && RSQ->rsq_qlength == 0) {
+ // We can send on this interface.
+ RSQ->rsq_pending++;
+ CTEFreeLock(&RSQ->rsq_lock, Handle);
+
+ TransmitFWPacket(Packet, DataLength);
+
+ } else { // Need to queue this packet for later.
+
+ FC->fc_datalength = DataLength;
+ FC->fc_q.fq_next = &RSQ->rsq_qh;
+ FC->fc_q.fq_prev = RSQ->rsq_qh.fq_prev;
+ RSQ->rsq_qh.fq_prev->fq_next = &FC->fc_q;
+ RSQ->rsq_qh.fq_prev = &FC->fc_q;
+ RSQ->rsq_qlength++;
+ CTEFreeLock(&RSQ->rsq_lock, Handle);
+ }
+ } else{
+ IPSInfo.ipsi_outdiscards++;
+ FreeFWPacket(Packet);
+ }
+
+}
+
+//* RemoveRandomFWPacket - Remove a random packet from the FW queue.
+//
+// Called when we run out of resources. We pick a random packet from the FW queue,
+// free it, and return. The caller will hopefully then get it for his own use.
+//
+// Input: RSQ - Pointer to outgoing route send q..
+//
+// Returns: TRUE if we free a packet, false if we didn't.
+//
+uchar
+RemoveRandomFWPacket(RouteSendQ *RSQ)
+{
+ uint Now = (uint)CTESystemUpTime();
+ CTELockHandle Handle;
+ uint PacketCount;
+ PNDIS_PACKET FreedPacket;
+ FWQ *CurrentFWQ;
+#ifdef DEBUG
+ FWQ *FirstFWQ;
+#endif
+
+#ifdef DEBUG
+ FirstFWQ = &RSQ->rsq_qh;
+#endif
+
+ CTEGetLock(&RSQ->rsq_lock, &Handle);
+ if (RSQ->rsq_qlength) { // We have a least one in the list.
+
+
+ PacketCount = Now % (RSQ->rsq_qlength + 1);
+ if (PacketCount == RSQ->rsq_qlength) {
+ CTEFreeLock(&RSQ->rsq_lock, Handle);
+ return FALSE;
+ }
+
+ CurrentFWQ = RSQ->rsq_qh.fq_next;
+ while (PacketCount--) {
+#ifdef DEBUG
+ if (CurrentFWQ == FirstFWQ)
+ DEBUGCHK;
+#endif
+ CurrentFWQ = CurrentFWQ->fq_next;
+ }
+
+ // We've got the proper packet. Splice him out.
+ CurrentFWQ->fq_next->fq_prev = CurrentFWQ->fq_prev;
+ CurrentFWQ->fq_prev->fq_next = CurrentFWQ->fq_next;
+ RSQ->rsq_qlength--;
+ CTEFreeLock(&RSQ->rsq_lock, Handle);
+ FreedPacket = PACKET_FROM_FWQ(CurrentFWQ);
+ FreeFWPacket(FreedPacket);
+ IPSInfo.ipsi_outdiscards++;
+ return TRUE;
+ }
+ CTEFreeLock(&RSQ->rsq_lock, Handle);
+ return FALSE;
+
+
+}
+
+//* GetFWBuffer - Get a list of buffers for forwarding.
+//
+// This routine gets a list of buffers for forwarding, and puts the data into it. This
+// may involve calling TransferData, or we may be able to copy directly into them
+// ourselves.
+//
+// Input: SrcNTE - Pointer to NTE on which packet was received.
+// Packet - Packet being forwarded, used for TD.
+// Data - Pointer to data buffer being forwarded.
+// DataLength - Length in bytes of Data.
+// BufferLength - Length in bytes available in buffer pointer to by Data.
+// Offset - Offset into original data from which to transfer.
+// LContext1, LContext2 - Context values for the link layer.
+//
+// Returns: NDIS_STATUS of attempt to get buffer.
+//
+NDIS_STATUS
+GetFWBuffer(NetTableEntry *SrcNTE, PNDIS_PACKET Packet, uchar *Data,
+ uint DataLength, uint BufferLength, uint Offset, NDIS_HANDLE LContext1,
+ uint LContext2)
+{
+ CTELockHandle Handle;
+ uint BufNeeded, i;
+ PNDIS_BUFFER FirstBuffer, CurrentBuffer;
+ void *DestPtr;
+ Interface *SrcIF;
+ FWContext *FWC;
+ uint BufLen;
+ uint LastBufSize;
+#ifdef DEBUG
+ uint TotalBufferSize;
+ PNDIS_BUFFER TempBuffer;
+#endif
+
+ // Figure out how many buffers we need.
+ BufNeeded = DataLength / FW_BUF_SIZE;
+ LastBufSize = DataLength % FW_BUF_SIZE;
+ if (LastBufSize != 0)
+ BufNeeded++;
+
+#ifdef DEBUG
+ if (!BufNeeded)
+ DEBUGCHK;
+#endif
+ FWC = (FWContext *)Packet->ProtocolReserved;
+
+ // Now run down the buffer free list, getting the buffers we need. If we
+ // can't get enough the first time, we'll free a random packet from our
+ // pending list and try again.
+ for (;;) {
+ CTEGetLock(&FWBufFreeLock, &Handle);
+ FirstBuffer = FWBufFree;
+ CurrentBuffer = STRUCT_OF(NDIS_BUFFER, &FWBufFree, Next);
+ i = 0;
+ do {
+ CurrentBuffer = NDIS_BUFFER_LINKAGE(CurrentBuffer);
+ if (!CurrentBuffer)
+ break;
+
+ // Zap this buffer length to the full buffer size, since it may
+ // have been modified from a previous send.
+ NdisAdjustBufferLength(CurrentBuffer, FW_BUF_SIZE);
+ i++;
+ } while (i < BufNeeded);
+
+ if (i != BufNeeded) { // We ran out of buffers. Free a packet and try again.
+ RouteSendQ *RSQ;
+
+ if ((MaxFWBufferSize - CurrentFWBufferSize) <= FW_BUF_SIZE) {
+ CTEFreeLock(&FWBufFreeLock, Handle);
+ if (GrowFWBuffer()) {
+ continue;
+ }
+ } else
+ CTEFreeLock(&FWBufFreeLock, Handle);
+
+ if (!IS_BCAST_DEST(FWC->fc_dtype))
+ RSQ = &((RouteInterface *)FWC->fc_if)->ri_q;
+ else
+ RSQ = BCastRSQ;
+
+ if (!RemoveRandomFWPacket(RSQ)) {
+ if (IS_BCAST_DEST(FWC->fc_dtype))
+ return NDIS_STATUS_RESOURCES;
+
+ // Couldn't get one for a non-broadcast packet. If the qlen is
+ // 0 on the outgoing queue, we'll try other queues, on the
+ // presumption that traffic through some other interface is
+ // starving this one.
+ if (RSQ->rsq_qlength == 0) {
+ Interface *IF;
+ for (IF = IFList; IF != NULL; IF = IF->if_next) {
+ RSQ = &((RouteInterface *)IF)->ri_q;
+ if (RemoveRandomFWPacket(RSQ))
+ break;
+ }
+ if (IF == NULL)
+ return NDIS_STATUS_RESOURCES;
+ } else
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ // Otherwise we'll fall through and try again, now that we have
+ // hopefully put some more on the free queue.
+
+ } else {
+ // We have as many as we need. Update the free list.
+ FWBufFree = NDIS_BUFFER_LINKAGE(CurrentBuffer);
+ CTEFreeLock(&FWBufFreeLock, Handle);
+ NDIS_BUFFER_LINKAGE(CurrentBuffer) = (PNDIS_BUFFER)NULL;
+
+ // If we have a non-full last buffer, adjust it's size.
+ if (LastBufSize != 0)
+ NdisAdjustBufferLength(CurrentBuffer, LastBufSize);
+
+ FWC->fc_buffhead = FirstBuffer;
+ FWC->fc_bufftail = CurrentBuffer;
+ break;
+ }
+ }
+
+ NdisChainBufferAtFront(Packet, FirstBuffer);
+
+#ifdef DEBUG
+ // Sanity check the buffer chain and packet.
+ TempBuffer = FirstBuffer;
+ TotalBufferSize = 0;
+ while (TempBuffer != NULL) {
+ TotalBufferSize += NdisBufferLength(TempBuffer);
+ TempBuffer = NDIS_BUFFER_LINKAGE(TempBuffer);
+ }
+
+ CTEAssert(TotalBufferSize == DataLength);
+ NdisQueryPacket(Packet, NULL, NULL, NULL, &TotalBufferSize);
+ CTEAssert(TotalBufferSize == DataLength);
+#endif
+
+ // First buffer points to the list of buffers we have. If we can copy the
+ // data here, do so, otherwise invoke the link's transfer data routine.
+ if ((DataLength <= BufferLength) && (SrcNTE->nte_flags & NTE_COPY)) {
+ while (DataLength) {
+ uint CopyLength;
+
+#ifdef VXD
+ DestPtr = FirstBuffer->VirtualAddress;
+#else
+ //
+ // BUGBUG: This is inefficient.
+ //
+ NdisQueryBuffer(FirstBuffer, &DestPtr, &BufLen);
+#endif
+ CopyLength = MIN(DataLength, FW_BUF_SIZE);
+ CTEAssert(CopyLength == NdisBufferLength(FirstBuffer));
+ CTEMemCopy(DestPtr, Data, CopyLength);
+ Data += CopyLength;
+ DataLength -= CopyLength;
+ FirstBuffer = NDIS_BUFFER_LINKAGE(FirstBuffer);
+ }
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ // We need to call transfer data for this.
+
+ SrcIF = SrcNTE->nte_if;
+ return (*(SrcIF->if_transfer))(SrcIF->if_lcontext, LContext1, LContext2,
+ Offset, DataLength, Packet, &DataLength);
+
+
+}
+
+
+//* GetFWPacket - Get a packet for forwarding.
+//
+// Called when we need to get a packet to forward a datagram.
+//
+// Entry: Packet - Pointer to where to return a packet.
+// IF - Outgoing I/F for packet.
+// DestType - Type of outgoing packet.
+//
+// Returns: Pointer to header buffer.
+//
+//
+IPHeader *
+GetFWPacket(PNDIS_PACKET *Packet, Interface *IF, uchar DestType)
+{
+ CTELockHandle Handle;
+ PNDIS_PACKET NewPacket;
+ RouteSendQ *RSQ;
+
+ for (;;) {
+ CTEGetLock(&FWPacketFreeLock, &Handle);
+ if ((NewPacket = FWPacketFree) != (PNDIS_PACKET)NULL) {
+ FWContext *FWC;
+
+ FWC = (FWContext *)NewPacket->ProtocolReserved;
+ FWPacketFree = FWC->fc_pc.pc_common.pc_link;
+ FWC->fc_pc.pc_common.pc_flags |= PACKET_FLAG_IPHDR;
+ FWC->fc_pc.pc_br = NULL;
+ *Packet = NewPacket;
+ CTEFreeLock(&FWPacketFreeLock, Handle);
+ return FWC->fc_hbuff;
+ }
+
+ // If we couldn't get one, try to grow the list if we can.
+ if (MaxFWPackets > CurrentFWPackets) {
+ CTEFreeLock(&FWPacketFreeLock, Handle);
+ // We're allowed to grow, so try to.
+ if (GrowFWPackets()) {
+ continue; // If we grew it, try again.
+ }
+ } else
+ CTEFreeLock(&FWPacketFreeLock, Handle);
+
+ // Either we weren't allowed to grow the list, or we tried to but couldn't. Try yo
+ // get one that's on the queue already.
+ if (!IS_BCAST_DEST(DestType))
+ RSQ = &((RouteInterface *)IF)->ri_q;
+ else
+ RSQ = BCastRSQ;
+
+ if (!RemoveRandomFWPacket(RSQ))
+ break;
+ }
+
+ return (IPHeader *)NULL;
+}
+
+
+//** IPForward - Forward a packet.
+//
+// The routine called when we need to forward a packet. We check if we're supposed
+// to act as a gateway, and if we are and the incoming packet is a bcast we check
+// and see if we're supposed to forward broadcasts. Assuming we're supposed to
+// forward it, we will process any options. If we find some, we do some validation
+// to make sure everything is good. After that, we look up the next hop. If we can't
+// find one, we'll issue an error. Then we get a packet and buffers, and send it.
+//
+// Input: SrcNTE - NTE for net on which we received this.
+// Header - Pointer to received IPheader.
+// HeaderLength - Length of header.
+// Data - Pointer to data to be forwarded.
+// BufferLength - Length in bytes available in the buffer.
+// DestType - Type of destination.
+//
+// Returns: Nothing.
+//
+void
+IPForward(NetTableEntry *SrcNTE, IPHeader UNALIGNED *Header, uint HeaderLength,
+ void *Data, uint BufferLength, NDIS_HANDLE LContext1, uint LContext2,
+ uchar DestType)
+{
+ uchar *Options;
+ uchar OptLength;
+ OptIndex Index;
+ IPAddr DestAddr; // IP address we're routing towards.
+ uchar SendOnSource = FALSE;
+ IPAddr NextHop; // Next hop IP address.
+ PNDIS_PACKET Packet;
+ FWContext *FWC;
+ IPHeader *NewHeader; // New header.
+ NDIS_STATUS Status;
+ uint DataLength;
+ CTELockHandle TableHandle;
+ uchar ErrIndex;
+ IPAddr OutAddr; // Address of interface we're send out on.
+ Interface *IF; // Interface we're sending out on.
+ uint MTU;
+
+ if (ForwardPackets) {
+
+ DestAddr = Header->iph_dest;
+
+ // If it's a broadcast, see if we can forward it. We won't forward it if broadcast
+ // forwarding is turned off, or the destination if the local (all one's) broadcast,
+ // or it's a multicast (Class D address). We'll pass through subnet broadcasts in
+ // case there's a source route. This would be odd - maybe we should disable this?
+ if (IS_BCAST_DEST(DestType)) {
+ if (!ForwardBCast) {
+ if (DestType > DEST_REMOTE)
+ IPSInfo.ipsi_inaddrerrors++;
+ return;
+ }
+ if ((DestAddr == IP_LOCAL_BCST) ||
+ (DestAddr == IP_ZERO_BCST) ||
+ (DestType == DEST_SN_BCAST) ||
+ CLASSD_ADDR(DestAddr)) {
+ return;
+ }
+ } else
+ if (DestType == DEST_REMOTE) {
+ SrcNTE = BestNTEForIF(Header->iph_src, SrcNTE->nte_if);
+ if (SrcNTE == NULL) {
+ // Something bad happened.
+ return;
+ }
+ }
+
+ // If the TTL would expire, send a message.
+ if (Header->iph_ttl <= 1) {
+ IPSInfo.ipsi_inhdrerrors++;
+ SendICMPErr(SrcNTE->nte_addr, Header, ICMP_TIME_EXCEED, TTL_IN_TRANSIT,0);
+ return;
+ }
+
+ DataLength = net_short(Header->iph_length) - HeaderLength;
+
+ Index.oi_srtype = NO_SR; // So we know we don't have a source route.
+ Index.oi_srindex = MAX_OPT_SIZE;
+ Index.oi_rrindex = MAX_OPT_SIZE;
+ Index.oi_tsindex = MAX_OPT_SIZE;
+
+ // Now check for options, and process any we find.
+ if (HeaderLength != sizeof(IPHeader)) {
+ IPOptInfo OptInfo;
+
+ OptInfo.ioi_options = (uchar *)(Header + 1);
+ OptInfo.ioi_optlength = HeaderLength - sizeof(IPHeader);
+ // Validate options, and set up indices.
+ if ((ErrIndex = ParseRcvdOptions(&OptInfo, &Index)) < MAX_OPT_SIZE) {
+ IPSInfo.ipsi_inhdrerrors++;
+ SendICMPErr(SrcNTE->nte_addr, Header, ICMP_PARAM_PROBLEM,
+ PTR_VALID, ((ulong)ErrIndex + sizeof(IPHeader)));
+ return;
+ }
+
+ Options = CTEAllocMem(OptInfo.ioi_optlength);
+ if (!Options) {
+ IPSInfo.ipsi_outdiscards++;
+ return; // Couldn't get an
+ } // option buffer, return;
+
+ // Now copy into our buffer.
+ CTEMemCopy(Options, OptInfo.ioi_options, OptLength = OptInfo.ioi_optlength);
+
+ // See if we have a source routing option, and if so we may need to process it. If
+ // we have one, and the destination in the header is us, we need to update the
+ // route and the header.
+ if (Index.oi_srindex != MAX_OPT_SIZE) {
+ if (DestType >= DEST_REMOTE) { // Not for us.
+ if (Index.oi_srtype == IP_OPT_SSRR) {
+ // This packet is strict source routed, but we're not the destination!
+ // We can't continue from here - perhaps we should send an ICMP, but
+ // I'm not sure which one it would be.
+ CTEFreeMem(Options);
+ IPSInfo.ipsi_inaddrerrors++;
+ return;
+ }
+ Index.oi_srindex = MAX_OPT_SIZE; // Don't need to update this.
+
+ } else { // This came here, we need to update the destination address.
+ uchar *SROpt = Options + Index.oi_srindex;
+ uchar Pointer;
+
+ Pointer = SROpt[IP_OPT_PTR] - 1; // Index starts from one.
+
+ // Get the next hop address, and see if it's a broadcast.
+ DestAddr = *(IPAddr UNALIGNED *)&SROpt[Pointer];
+ DestType = GetAddrType(DestAddr); // Find address type.
+ if (DestType == DEST_INVALID) {
+ SendICMPErr(SrcNTE->nte_addr, Header, ICMP_DEST_UNREACH, SR_FAILED, 0);
+ IPSInfo.ipsi_inhdrerrors++;
+ CTEFreeMem(Options);
+ return;
+ }
+
+ // If we came through here, any sort of broadcast needs to be sent out
+ // the way it came, so update that flag.
+ SendOnSource = TRUE;
+ }
+ }
+ } else { // No options.
+ Options = (uchar *)NULL;
+ OptLength = 0;
+ }
+
+ IPSInfo.ipsi_forwdatagrams++;
+
+ // We've processed the options. Now look up the next hop. If we can't
+ // find one, send back an error.
+ IF = LookupNextHopWithBuffer(DestAddr, SrcNTE->nte_addr, &NextHop, &MTU,
+ Header->iph_protocol, (uchar *)Data, BufferLength);
+
+ if (IF == NULL) {
+ // Couldn't find an outgoing route.
+ IPSInfo.ipsi_outnoroutes++;
+ SendICMPErr(SrcNTE->nte_addr, Header, ICMP_DEST_UNREACH,
+ HOST_UNREACH, 0);
+ if (Options)
+ CTEFreeMem(Options);
+ return;
+ }
+
+ //
+ // If the DF flag is set, make sure the packet doesn't need
+ // fragmentation. If this is the case, send an ICMP error
+ // now while we still have the original IP header. The ICMP
+ // message includes the MTU so the source host can perform
+ // Path MTU discovery.
+ //
+ if ( (Header->iph_offset & IP_DF_FLAG) &&
+ ((DataLength + (uint)OptLength) > MTU)
+ )
+ {
+ CTEAssert((MTU + sizeof(IPHeader)) >= 68);
+ CTEAssert((MTU + sizeof(IPHeader)) <= 0xFFFF);
+
+ IPSInfo.ipsi_fragfails++;
+ SendICMPErr(SrcNTE->nte_addr, Header, ICMP_DEST_UNREACH,
+ FRAG_NEEDED, net_long((ulong)(MTU + sizeof(IPHeader)))
+ );
+
+ if (Options)
+ CTEFreeMem(Options);
+#ifdef _PNP_POWER
+ DerefIF(IF);
+#endif
+ return;
+ }
+
+ // See if we need to filter this packet. If we do, call the filter routine
+ // to see if it's OK to forward it.
+ if (ForwardFilterPtr != NULL) {
+ FORWARD_ACTION Action;
+
+ Action = (*ForwardFilterPtr)(Header, Data, BufferLength,
+ SrcNTE->nte_if->if_filtercontext, IF->if_filtercontext);
+
+ if (Action != FORWARD) {
+ IPSInfo.ipsi_outdiscards++;
+ if (Options)
+ CTEFreeMem(Options);
+#ifdef _PNP_POWER
+ DerefIF(IF);
+#endif
+ return;
+ }
+ }
+
+ // If we have a strict source route and the next hop is not the one
+ // specified, send back an error.
+ if (Index.oi_srtype == IP_OPT_SSRR) {
+ if (DestAddr != NextHop) {
+ IPSInfo.ipsi_outnoroutes++;
+ SendICMPErr(SrcNTE->nte_addr, Header, ICMP_DEST_UNREACH,
+ SR_FAILED, 0);
+ CTEFreeMem(Options);
+#ifdef _PNP_POWER
+ DerefIF(IF);
+#endif
+ return;
+ }
+ }
+
+ // Update the options, if we can and we need to.
+ if ((DestType != DEST_BCAST) && Options != NULL) {
+ NetTableEntry *OutNTE;
+
+ // Need to find a valid source address for the outgoing interface.
+ CTEGetLock(&RouteTableLock, &TableHandle);
+ OutNTE = BestNTEForIF(DestAddr, IF);
+ if (OutNTE == NULL) {
+ // No NTE for this IF. Something's wrong, just bail out.
+ CTEFreeLock(&RouteTableLock, TableHandle);
+ CTEFreeMem(Options);
+#ifdef _PNP_POWER
+ DerefIF(IF);
+#endif
+ return;
+ } else {
+ OutAddr = OutNTE->nte_addr;
+ CTEFreeLock(&RouteTableLock, TableHandle);
+ }
+
+ ErrIndex = UpdateOptions(Options, &Index,
+ (IP_LOOPBACK(OutAddr) ? DestAddr : OutAddr));
+
+ if (ErrIndex != MAX_OPT_SIZE) {
+ IPSInfo.ipsi_inhdrerrors++;
+ SendICMPErr(OutAddr, Header, ICMP_PARAM_PROBLEM, PTR_VALID,
+ ((ulong)ErrIndex + sizeof(IPHeader)));
+ CTEFreeMem(Options);
+#ifdef _PNP_POWER
+ DerefIF(IF);
+#endif
+ return;
+ }
+ }
+
+
+ // Send a redirect, if we need to. We'll send a redirect if the packet
+ // is going out on the interface it came in on and the next hop address
+ // is on the same subnet as the NTE we received it on, and if there
+ // are no source route options. We also need to make sure that the
+ // source of the datagram is on the I/F we received it on, so we don't
+ // send a redirect to another gateway.
+ // SendICMPErr will check and not send a redirect if this is a broadcast.
+ if ((SrcNTE->nte_if == IF) &&
+ IP_ADDR_EQUAL(SrcNTE->nte_addr & SrcNTE->nte_mask,
+ NextHop & SrcNTE->nte_mask) &&
+ IP_ADDR_EQUAL(SrcNTE->nte_addr & SrcNTE->nte_mask,
+ Header->iph_src & SrcNTE->nte_mask))
+ {
+ if (Index.oi_srindex == MAX_OPT_SIZE)
+ {
+
+#ifdef REDIRECT_DEBUG
+
+#define PR_IP_ADDR(x) \
+ ((x)&0x000000ff),(((x)&0x0000ff00)>>8),(((x)&0x00ff0000)>>16),(((x)&0xff000000)>>24)
+
+
+ DbgPrint("IP: Sending Redirect. IF = %x SRC_NTE = %x SrcNteIF = %x\n",
+ IF,SrcNTE,SrcNTE->nte_if);
+
+ DbgPrint("IP: SrcNteAddr = %d.%d.%d.%d Mask = %d.%d.%d.%d\n",
+ PR_IP_ADDR(SrcNTE->nte_addr), PR_IP_ADDR(SrcNTE->nte_mask));
+
+ DbgPrint("IP: NextHop = %d.%d.%d.%d Header Src = %d.%d.%d.%d, Dst = %d.%d.%d.%d\n",
+ PR_IP_ADDR(NextHop),
+ PR_IP_ADDR(Header->iph_src),
+ PR_IP_ADDR(Header->iph_dest));
+
+#endif
+
+ SendICMPErr(SrcNTE->nte_addr, Header, ICMP_REDIRECT,
+ REDIRECT_HOST, NextHop);
+ }
+ }
+
+ // We have the next hop. Now get a forwarding packet.
+ if ((NewHeader = GetFWPacket(&Packet, IF, DestType)) !=
+ (IPHeader *)NULL) {
+
+ // Got the header. Fill it in.
+
+ NewHeader->iph_verlen = Header->iph_verlen;
+ NewHeader->iph_tos = Header->iph_tos;
+ NewHeader->iph_length = Header->iph_length;
+ NewHeader->iph_id = Header->iph_id;
+ NewHeader->iph_offset = Header->iph_offset;
+ NewHeader->iph_protocol = Header->iph_protocol;
+ NewHeader->iph_src = Header->iph_src;
+
+ NewHeader->iph_dest = DestAddr;
+ NewHeader->iph_ttl = Header->iph_ttl - 1;
+ NewHeader->iph_xsum = 0;
+
+ // Save the packet forwarding context info.
+ FWC = (FWContext *)Packet->ProtocolReserved;
+ FWC->fc_options = Options;
+ FWC->fc_optlength = OptLength;
+ FWC->fc_if = IF;
+ FWC->fc_mtu = MTU;
+ FWC->fc_srcnte = SrcNTE;
+ FWC->fc_nexthop = NextHop;
+ FWC->fc_sos = SendOnSource;
+ FWC->fc_dtype = DestType;
+ FWC->fc_index = Index;
+
+ // Now that we have a packet, go ahead and transfer data the
+ // data in if we need to.
+ Status = GetFWBuffer(SrcNTE, Packet, Data, DataLength, BufferLength,
+ HeaderLength, LContext1, LContext2);
+
+ // If the status is pending, don't do anything now. Otherwise,
+ // if the status is success send the packet.
+ if (Status != NDIS_STATUS_PENDING)
+ if (Status == NDIS_STATUS_SUCCESS) {
+ SendFWPacket(Packet, Status, DataLength);
+ } else {
+ // Some sort of failure. Free the packet.
+ IPSInfo.ipsi_outdiscards++;
+ FreeFWPacket(Packet);
+ }
+ } else { // Couldn't get a packet, so drop this.
+ IPSInfo.ipsi_outdiscards++;
+ if (Options)
+ CTEFreeMem(Options);
+#ifdef _PNP_POWER
+ DerefIF(IF);
+#endif
+ }
+ } else { // Forward called, but forwarding
+ // turned off.
+ if (DestType != DEST_BCAST && DestType != DEST_SN_BCAST) {
+ // No need to go through here for strictly broadcast packets,
+ // although we want to bump the counters for remote bcast stuff.
+ IPSInfo.ipsi_inaddrerrors++;
+
+ if (!IS_BCAST_DEST(DestType)) {
+ if (DestType == DEST_LOCAL) // Called when local, must be SR.
+ SendICMPErr(SrcNTE->nte_addr, Header,
+ ICMP_DEST_UNREACH, SR_FAILED, 0);
+ }
+ }
+ }
+
+}
+
+//* AddNTERoutes - Add the routes for an NTE.
+//
+// Called during initalization or during DHCP address assignment to add
+// routes. We add routes for the address of the NTE, including routes
+// to the subnet and the address itself.
+//
+// Input: NTE - NTE for which to add routes.
+//
+// Returns: TRUE if they were all added, FALSE if not.
+//
+uint
+AddNTERoutes(NetTableEntry *NTE)
+{
+ IPMask Mask, SNMask;
+ Interface *IF;
+ CTELockHandle Handle;
+ IPAddr AllSNBCast;
+ IP_STATUS Status;
+
+ // First, add the route to the address itself. This is a route through
+ // the loopback interface.
+
+ if (AddRoute(NTE->nte_addr, HOST_MASK, IPADDR_LOCAL, LoopNTE->nte_if,
+ LOOPBACK_MSS, 1, IRE_PROTO_LOCAL, ATYPE_OVERRIDE, NULL) != IP_SUCCESS)
+ return FALSE;
+
+ Mask = IPNetMask(NTE->nte_addr);
+ IF = NTE->nte_if;
+
+ // Now add the route for the all-subnet's broadcast, if one doesn't already
+ // exist. There is special case code to handle this in SendIPBCast, so the
+ // exact interface we add this on doesn't really matter.
+
+ CTEGetLock(&RouteTableLock, &Handle);
+ AllSNBCast = (NTE->nte_addr & Mask) | (IF->if_bcast & ~Mask);
+ if (LookupRTE(AllSNBCast, NULL_IP_ADDR, HOST_ROUTE_PRI) == NULL) {
+
+ Status = LockedAddRoute(AllSNBCast, HOST_MASK, IPADDR_LOCAL, IF,
+ NTE->nte_mss, 1, IRE_PROTO_LOCAL, ATYPE_PERM, NULL);
+
+ } else
+ Status = IP_SUCCESS;
+
+ CTEFreeLock(&RouteTableLock, Handle);
+
+ if (Status != IP_SUCCESS)
+ return FALSE;
+
+ // If we're doing IGMP, add the route to the multicast address.
+ if (IGMPLevel != 0) {
+ if (AddRoute(CLASSD_MASK, CLASSD_MASK, IPADDR_LOCAL, NTE->nte_if,
+ NTE->nte_mss, 1, IRE_PROTO_LOCAL, ATYPE_PERM, NULL) != IP_SUCCESS)
+ return FALSE;
+ }
+
+ if(NTE->nte_mask != HOST_MASK)
+ {
+ // And finally the route to the subnet.
+ SNMask = NTE->nte_mask;
+ if (AddRoute(NTE->nte_addr & SNMask, SNMask, IPADDR_LOCAL, NTE->nte_if,
+ NTE->nte_mss, 1, IRE_PROTO_LOCAL, ATYPE_PERM, NULL) != IP_SUCCESS)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+#ifndef CHICAGO
+#pragma BEGIN_INIT
+#endif
+
+uint BCastMinMTU = 0xffff;
+
+//* InitNTERouting - do per NTE route initialization.
+//
+// Called when we need to initialize per-NTE routing. For the specified NTE,
+// call AddNTERoutes to add a route for a net bcast, subnet bcast, and local
+// attached subnet. The net bcast entry is sort of a filler - net and
+// global bcasts are always handled specially. For this reason we specify
+// the FirstInterface when adding the route. Subnet bcasts are assumed to
+// only go out on one interface, so the actual interface to be used is
+// specifed. If two interfaces are on the same subnet the last interface is
+// the one that will be used.
+//
+// Input: NTE - NTE for which routing is to be initialized.
+// NumGWs - Number of default gateways to add.
+// GWList - List of default gateways.
+//
+// Returns: TRUE if we succeed, FALSE if we don't.
+//
+uint
+InitNTERouting(NetTableEntry *NTE, uint NumGWs, IPAddr *GWList)
+{
+ uint i;
+ Interface *IF;
+
+ CTERefillMem();
+ if (NTE != LoopNTE) {
+ BCastMinMTU = MIN(BCastMinMTU, NTE->nte_mss);
+
+ IF = NTE->nte_if;
+ AddRoute(IF->if_bcast, HOST_MASK, IPADDR_LOCAL, FirstIF,
+ BCastMinMTU, 1, IRE_PROTO_LOCAL, ATYPE_OVERRIDE, NULL);// Route for local
+ // bcast.
+ if (NTE->nte_flags & NTE_VALID) {
+ if (!AddNTERoutes(NTE))
+ return FALSE;
+
+ // Now add the default routes that are present on this net. We
+ // don't check for errors here, but we should probably
+ // log an error.
+ for (i = 0; i < NumGWs;i++) {
+ IPAddr GWAddr;
+
+ GWAddr = net_long(GWList[i]);
+
+ if (IP_ADDR_EQUAL(GWAddr, NTE->nte_addr)) {
+ AddRoute(NULL_IP_ADDR, DEFAULT_MASK,
+ IPADDR_LOCAL, NTE->nte_if, NTE->nte_mss, 1,
+ IRE_PROTO_LOCAL, ATYPE_OVERRIDE, NULL);
+ } else
+ AddRoute(NULL_IP_ADDR, DEFAULT_MASK,
+ net_long(GWList[i]), NTE->nte_if, NTE->nte_mss, 1,
+ IRE_PROTO_LOCAL, ATYPE_OVERRIDE, NULL);
+ }
+ }
+ }
+ return TRUE;
+}
+
+#ifdef CHICAGO
+#pragma BEGIN_INIT
+#endif
+
+//* InitRouting - Initialize our routing table.
+//
+// Called during initialization to initialize the routing table.
+//
+// Entry: Nothing.
+//
+// Returns: True if we succeeded, False if we didn't.
+//
+int
+InitRouting(IPConfigInfo *ci)
+{
+ int i;
+
+ CTERefillMem();
+
+ CTEInitLock(&RouteTableLock);
+
+ DefGWConfigured = 0;
+ DefGWActive = 0;
+
+ CTEMemSet(&DummyInterface, 0, sizeof(DummyInterface));
+ DummyInterface.ri_if.if_xmit = DummyXmit;
+ DummyInterface.ri_if.if_transfer = DummyXfer;
+ DummyInterface.ri_if.if_close = DummyClose;
+ DummyInterface.ri_if.if_invalidate = DummyInvalidate;
+ DummyInterface.ri_if.if_qinfo = DummyQInfo;
+ DummyInterface.ri_if.if_setinfo = DummySetInfo;
+ DummyInterface.ri_if.if_getelist = DummyGetEList;
+ DummyInterface.ri_if.if_addaddr = DummyAddAddr;
+ DummyInterface.ri_if.if_deladdr = DummyDelAddr;
+ DummyInterface.ri_if.if_bcast = IP_LOCAL_BCST;
+ DummyInterface.ri_if.if_speed = 10000000;
+ DummyInterface.ri_if.if_mtu = 1500;
+ DummyInterface.ri_if.if_index = INVALID_IF_INDEX;
+
+ for (i = 0; i < ROUTE_TABLE_SIZE; i++)
+ RouteTable[i] = (RouteTableEntry *)NULL;
+
+ // We've created at least one net. We need to add routing table entries for
+ // the global broadcast address, as well as for subnet and net broadcasts,
+ // and routing entries for the local subnet. We alse need to add a loopback
+ // route for the loopback net. Below, we'll add a host route for ourselves
+ // through the loopback net.
+ AddRoute(LOOPBACK_ADDR & CLASSA_MASK, CLASSA_MASK, IPADDR_LOCAL,
+ LoopNTE->nte_if, LOOPBACK_MSS, 1, IRE_PROTO_LOCAL, ATYPE_PERM, NULL);
+ // Route for loopback.
+ RouterConfigured = (uchar)ci->ici_gateway;
+
+ CTEInitTimer(&IPRouteTimer);
+
+ CTEStartTimer(&IPRouteTimer, IP_ROUTE_TIMEOUT, IPRouteTimeout, NULL);
+ return TRUE;
+
+}
+
+//* InitGateway - Initialize our gateway functionality.
+//
+// Called during init. time to initialize our gateway functionality. If we're
+// not connfigured as a router, we do nothing. If we are, we allocate the
+// resources we need and do other router initialization.
+//
+// Input: ci - Config info.
+//
+// Returns: TRUE if we succeed, FALSE if don't.
+//
+uint
+InitGateway(IPConfigInfo *ci)
+{
+ uint FWBufSize, FWPackets;
+ uint FWBufCount;
+ NDIS_STATUS Status;
+ NDIS_HANDLE BufferPool, FWBufferPool, PacketPool;
+ IPHeader *HeaderPtr = NULL;
+ uchar *FWBuffer = NULL;
+ PNDIS_BUFFER Buffer;
+ PNDIS_PACKET Packet;
+ RouteInterface *RtIF;
+ NetTableEntry *NTE;
+ uint i;
+
+ // If we're going to be a router, allocate and initialize the resources we
+ // need for that.
+ BCastRSQ = NULL;
+ if (RouterConfigured) {
+
+
+ CTERefillMem();
+ RtPI = CTEAllocMem(sizeof(ProtInfo));
+ if (RtPI == (ProtInfo *)NULL)
+ goto failure;
+
+ RtPI->pi_xmitdone = FWSendComplete;
+
+ CTEInitLock(&FWPacketFreeLock);
+ CTEInitLock(&FWBufFreeLock);
+
+ MaxFWBufferSize = ci->ici_maxfwbufsize;
+ MaxFWPackets = ci->ici_maxfwpackets;
+ FWBufSize = MIN(ci->ici_fwbufsize, MaxFWBufferSize);
+ FWPackets = MIN(ci->ici_fwpackets, MaxFWPackets);
+
+ for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
+ RtIF = (RouteInterface *)NTE->nte_if;
+
+ RtIF->ri_q.rsq_qh.fq_next = &RtIF->ri_q.rsq_qh;
+ RtIF->ri_q.rsq_qh.fq_prev = &RtIF->ri_q.rsq_qh;
+ RtIF->ri_q.rsq_running = FALSE;
+ RtIF->ri_q.rsq_pending = 0;
+ RtIF->ri_q.rsq_qlength = 0;
+ CTEInitLock(&RtIF->ri_q.rsq_lock);
+ }
+
+ BCastRSQ = CTEAllocMem(sizeof(RouteSendQ));
+
+ if (BCastRSQ == (RouteSendQ *)NULL)
+ goto failure;
+
+ BCastRSQ->rsq_qh.fq_next = &BCastRSQ->rsq_qh;
+ BCastRSQ->rsq_qh.fq_prev = &BCastRSQ->rsq_qh;
+ BCastRSQ->rsq_pending = 0;
+ BCastRSQ->rsq_maxpending = DEFAULT_MAX_PENDING;
+ BCastRSQ->rsq_qlength = 0;
+ BCastRSQ->rsq_running = FALSE;
+ CTEInitLock(&BCastRSQ->rsq_lock);
+
+ RtIF = (RouteInterface *)&LoopInterface;
+ RtIF->ri_q.rsq_maxpending = DEFAULT_MAX_PENDING;
+
+ // Round the specified size down to a multiple of our FW buf size.
+ CTERefillMem();
+ FWBufCount = FWBufSize / FW_BUF_SIZE;
+ FWBufSize = FWBufCount * FW_BUF_SIZE;
+
+ // Allocate the buffers, packets, and memory for our header buffers.
+ HeaderPtr = CTEAllocMem(FWPackets * sizeof(IPHeader));
+ if (HeaderPtr == (IPHeader *)NULL)
+ goto failure;
+
+ NdisAllocateBufferPool(&Status, &BufferPool, FWPackets);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ goto failure; // Couldn't be a router, fail.
+ }
+
+ NdisAllocatePacketPool(&Status, &PacketPool, FWPackets, sizeof(FWContext));
+ if (Status != NDIS_STATUS_SUCCESS) {
+ NdisFreeBufferPool(BufferPool);
+ goto failure;
+ }
+
+ // Allocate resources for our the buffer pool.
+ CTERefillMem();
+ FWBuffer = CTEAllocMem(FWBufSize);
+ if (FWBuffer == NULL) { // Couldn't get buffer space.
+ NdisFreePacketPool(PacketPool);
+ NdisFreeBufferPool(BufferPool);
+ goto failure;
+ }
+
+ NdisAllocateBufferPool(&Status, &FWBufferPool, FWBufCount);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ NdisFreePacketPool(PacketPool);
+ NdisFreeBufferPool(BufferPool);
+ goto failure;
+ }
+
+ // Everythings allocated. Put it all together and stick them on the
+ // free list.
+ for (i = 0; i < FWPackets; i++) {
+ FWContext *FWC;
+
+ NdisAllocateBuffer(&Status, &Buffer, BufferPool, HeaderPtr,
+ sizeof(IPHeader));
+ if (Status != NDIS_STATUS_SUCCESS)
+ DEBUGCHK;
+ NdisAllocatePacket(&Status, &Packet, PacketPool);
+ if (Status != NDIS_STATUS_SUCCESS)
+ DEBUGCHK;
+
+ CTEMemSet(Packet->ProtocolReserved, 0, sizeof(FWContext));
+ FWC = (FWContext *)Packet->ProtocolReserved;
+ FWC->fc_hndisbuff = Buffer;
+ FWC->fc_hbuff = HeaderPtr;
+ FWC->fc_pc.pc_common.pc_flags = PACKET_FLAG_FW;
+ FWC->fc_pc.pc_common.pc_owner = PACKET_OWNER_IP;
+ FWC->fc_pc.pc_pi = RtPI;
+ FWC->fc_pc.pc_context = Packet;
+
+ FreeFWPacket(Packet);
+ HeaderPtr++;
+ }
+
+ for (i = 0; i < FWBufCount; i++) {
+ NdisAllocateBuffer(&Status, &Buffer, FWBufferPool, FWBuffer,
+ FW_BUF_SIZE);
+ if (Status != NDIS_STATUS_SUCCESS)
+ DEBUGCHK;
+
+ Buffer->Next = FWBufFree; // BUGBUG portability
+ FWBufFree = Buffer;
+ FWBuffer += FW_BUF_SIZE;
+ }
+
+ CurrentFWPackets = FWPackets;
+ CurrentFWBufferSize = FWBufSize;
+
+
+#if 0
+ ForwardBCast = (uchar)ci->ici_fwbcast;
+#else
+ ForwardBCast = FALSE;
+#endif
+ ForwardPackets = TRUE;
+ }
+
+ return TRUE;
+
+failure:
+ if (RtPI != NULL)
+ CTEFreeMem(RtPI);
+ if (BCastRSQ != NULL)
+ CTEFreeMem(BCastRSQ);
+ if (HeaderPtr != NULL)
+ CTEFreeMem(HeaderPtr);
+ if (FWBuffer != NULL)
+ CTEFreeMem(FWBuffer);
+
+ ForwardBCast = FALSE;
+ ForwardPackets = FALSE;
+ RouterConfigured = FALSE;
+ return FALSE;
+
+}
+#pragma END_INIT
diff --git a/private/ntos/tdi/tcpip/ip/iproute.h b/private/ntos/tdi/tcpip/ip/iproute.h
new file mode 100644
index 000000000..e06af7100
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/iproute.h
@@ -0,0 +1,107 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1992 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** IPROUTE.H - IP routing definitions.
+//
+// This file contains all of the definitions for routing code that are
+// visible to modules outside iproute.c
+
+
+extern struct Interface *LookupNextHop(IPAddr Dest, IPAddr Src,
+ IPAddr *FirstHop, uint *MTU);
+extern struct Interface *LookupNextHopWithBuffer(IPAddr Dest, IPAddr Src,
+ IPAddr *FirstHop, uint *MTU, uchar Protocol,
+ uchar *Buffer, uint Length);
+
+extern void FlushATCache(IPAddr Address);
+extern uchar GetAddrType(IPAddr Address);
+extern uint InvalidSourceAddress(IPAddr Address);
+extern uchar GetLocalNTE(IPAddr Address, NetTableEntry **NTE);
+extern uchar IsBCastOnNTE(IPAddr Address, NetTableEntry *NTE);
+extern void SendFWPacket(PNDIS_PACKET Packet, NDIS_STATUS Status,
+ uint DataLength);
+extern void IPForward(NetTableEntry *SrcNTE,
+ IPHeader UNALIGNED *Header, uint HeaderLength,
+ void *Data, uint BufferLength,
+ NDIS_HANDLE LContext1, uint LContext2,
+ uchar DestType);
+
+extern uint AttachRCEToRTE(RouteCacheEntry *RCE, uchar Protocol,
+ uchar *Buffer, uint Length);
+extern void Redirect(NetTableEntry *NTE, IPAddr RDSrc,
+ IPAddr Target, IPAddr Src, IPAddr FirstHop);
+extern IP_STATUS AddRoute(IPAddr Destination, IPMask Mask,
+ IPAddr FirstHop, Interface *OutIF, uint MTU,
+ uint Metric, uint Proto, uint AType,
+ void *Context);
+extern IP_STATUS DeleteRoute(IPAddr Destination, IPMask Mask,
+ IPAddr FirstHop, Interface *OutIF);
+extern void *GetRouteContext(IPAddr Destination, IPAddr Source);
+
+extern NetTableEntry *BestNTEForIF(IPAddr Dest, Interface *IF);
+extern void RTWalk(uint (*CallFunc)(struct RouteTableEntry *,
+ void *, void *), void *Context, void *Context1);
+
+extern uint DeleteRTEOnIF(struct RouteTableEntry *RTE,
+ void *Context, void *Context1);
+extern uint InvalidateRCEOnIF(struct RouteTableEntry *RTE,
+ void *Context, void *Context1);
+extern uint SetMTUOnIF(struct RouteTableEntry *RTE, void *Context,
+ void *Context1);
+extern uint SetMTUToAddr(struct RouteTableEntry *RTE, void *Context,
+ void *Context1);
+extern uint AddNTERoutes(struct NetTableEntry *NTE);
+extern void IPCheckRoute(IPAddr Dest, IPAddr Src);
+extern void RouteFragNeeded(IPHeader UNALIGNED *IPH, ushort NewMTU);
+extern IP_STATUS IPGetPInfo(IPAddr Dest, IPAddr Src, uint *NewMTU,
+ uint *MaxPathSpeed);
+extern int InitRouting(struct IPConfigInfo *ci);
+extern uint InitNTERouting(NetTableEntry *NTE, uint NumGWs,
+ IPAddr *GW);
+extern uint InitGateway(struct IPConfigInfo *ci);
+extern IPAddr OpenRCE(IPAddr Address, IPAddr Src, RouteCacheEntry **RCE,
+ uchar *Type, ushort *MSS, IPOptInfo *OptInfo);
+extern void CloseRCE(RouteCacheEntry *RCE);
+extern uint IsRouteICMP(IPAddr Dest, IPMask Mask, IPAddr FirstHop,
+ Interface *OutIF);
+
+EXTERNAL_LOCK(RouteTableLock)
+
+extern uint DeadGWDetect;
+extern uint PMTUDiscovery;
+extern uchar ForwardPackets;
+extern uchar RouterConfigured;
+// Pointer to callout routine for dial on demand.
+extern IPMapRouteToInterfacePtr DODCallout;
+
+// Pointer to packet filter handler.
+extern IPPacketFilterPtr ForwardFilterPtr;
+
+#define IPADDR_LOCAL 0xffffffff // Indicates that IP address is
+ // directly connected.
+
+#define IP_LOCAL_BCST 0xffffffff
+#define IP_ZERO_BCST 0
+
+#define HOST_MASK 0xffffffff
+#define DEFAULT_MASK 0
+
+
+#ifdef NT
+#define LOOPBACK_MSS (1500 - sizeof(IPHeader))
+#else // NT
+#define LOOPBACK_MSS 256
+#endif // NT
+
+
+#define LOOPBACK_ADDR 0x0100007f
+#define IP_LOOPBACK(x) (((x) & CLASSA_MASK) == 0x7f)
+
+#define ATYPE_PERM 0 // A permanent route.
+#define ATYPE_OVERRIDE 1 // Semi-permanent - can be
+ // overriden.
+#define ATYPE_TEMP 2 // A temporary route.
+
diff --git a/private/ntos/tdi/tcpip/ip/iprtdef.h b/private/ntos/tdi/tcpip/ip/iprtdef.h
new file mode 100644
index 000000000..1082646ba
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/iprtdef.h
@@ -0,0 +1,135 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1992 **/
+/********************************************************************/
+/* :ts=4 */
+
+#include "ipfilter.h"
+
+//** IPRTDEF.H - IP private routing definitions.
+//
+// This file contains all of the definitions private to the routing
+// module.
+
+//* Route table entry.
+
+struct RouteTableEntry {
+ struct RouteTableEntry *rte_next; // Next in hash chain.
+ IPAddr rte_dest; // Destination of route.
+ IPMask rte_mask; // Mask to use when examining route.
+ IPAddr rte_addr; // First hop for this route.
+ uint rte_priority; // Priority of this route:
+ // essentially the number
+ // of bits set in mask.
+ uint rte_metric; // Metric of route. Lower
+ // is better.
+ uint rte_mtu; // MTU for this route.
+ struct Interface *rte_if; // Outbound interface.
+ RouteCacheEntry *rte_rcelist;
+ ushort rte_type; // Type of route.
+ ushort rte_flags; // Flags for route.
+ uint rte_admintype; // Admin type of route.
+ uint rte_proto; // How we learned about the
+ // route.
+ uint rte_valid; // Up time (in seconds)
+ // route was last known to be
+ // valid.
+ uint rte_mtuchange; // System up time (in seconds)
+ // MTU was changed.
+ ROUTE_CONTEXT rte_context; // Dial-on-demand context for this route.
+}; /* RouteTableEntry */
+
+#define ADDR_FROM_RTE(R, A) (IP_ADDR_EQUAL((R)->rte_addr, IPADDR_LOCAL) ? (A) : \
+ (R)->rte_addr)
+#define IF_FROM_RTE(R) ((R)->rte_if)
+#define MTU_FROM_RTE(R) ((R)->rte_mtu)
+#define SRC_FROM_RTE(R) ((R)->rte_src)
+
+#define RTE_VALID 1
+#define RTE_INCREASE 2 // Set if last MTU change was an
+ // increase.
+#define RTE_IF_VALID 4 // Set to TRUE if rte_if is valid.
+
+#define IP_ROUTE_TIMEOUT 60L*1000L // Route timer fires once a minute.
+
+#define MTU_INCREASE_TIME 120 // Number of seconds after increase
+ // to re-increase.
+#define MTU_DECREASE_TIME 600 // Number of seconds after decrease
+ // to re-increase.
+
+#define MAX_ICMP_ROUTE_VALID 600 // Time to timeout an unused ICMP
+ // derived route, in seconds.
+
+#define MIN_RT_VALID 60 // Minimum time a route is assumed
+ // to be valid, in seconds.
+
+#define MIN_VALID_MTU 68 // Minimum valid MTU we can have.
+#define HOST_ROUTE_PRI 32
+#define DEFAULT_ROUTE_PRI 0
+
+typedef struct RouteTableEntry RouteTableEntry;
+
+//* Forward Q linkage structure.
+struct FWQ {
+ struct FWQ *fq_next;
+ struct FWQ *fq_prev;
+}; /* FWQ */
+
+typedef struct FWQ FWQ;
+
+
+//* Forward context structure, used when TD'ing a packet to be forwarded.
+struct FWContext {
+ PacketContext fc_pc; // Dummy packet context for send routines.
+ FWQ fc_q; // Queue structure.
+ PNDIS_BUFFER fc_hndisbuff; // Pointer to NDIS buffer for header.
+ IPHeader *fc_hbuff; // Header buffer.
+ PNDIS_BUFFER fc_buffhead; // Head of list of NDIS buffers.
+ PNDIS_BUFFER fc_bufftail; // Tail of list of NDIS buffers.
+ uchar *fc_options; // Options,
+ Interface *fc_if; // Destination interface.
+ IPAddr fc_outaddr; // IP address of interface.
+ uint fc_mtu; // Max MTU outgoing.
+ NetTableEntry *fc_srcnte; // Source NTE.
+ IPAddr fc_nexthop; // Next hop.
+ uint fc_datalength; // Length in bytes of data.
+ OptIndex fc_index; // Index of relevant options.
+ uchar fc_optlength; // Length of options.
+ uchar fc_sos; // Send on source indicator.
+ uchar fc_dtype; // Dest type.
+ uchar fc_pad;
+}; /* FWContext */
+
+typedef struct FWContext FWContext;
+
+#define PACKET_FROM_FWQ(_fwq_) (PNDIS_PACKET)((uchar *)(_fwq_) - (offsetof(struct FWContext, fc_q) + \
+ offsetof(NDIS_PACKET, ProtocolReserved)))
+
+//* Route send queue structure. This consists of a dummy FWContext for use as
+// a queue head, a count of sends pending on the interface, and a count of packets
+// in the queue.
+struct RouteSendQ {
+ FWQ rsq_qh;
+ uint rsq_pending;
+ uint rsq_maxpending;
+ uint rsq_qlength;
+ uint rsq_running;
+ DEFINE_LOCK_STRUCTURE(rsq_lock)
+}; /* RouteSendQ */
+
+typedef struct RouteSendQ RouteSendQ;
+
+
+//* Routing interface, a superset of the ordinary interface when we're configured as a router.
+struct RouteInterface {
+ Interface ri_if;
+ RouteSendQ ri_q;
+}; /* RouteInterface */
+
+typedef struct RouteInterface RouteInterface;
+
+extern IPMask IPMaskTable[];
+
+#define IPNetMask(a) IPMaskTable[(*(uchar *)&(a)) >> 4]
+
+
diff --git a/private/ntos/tdi/tcpip/ip/ipstatus.c b/private/ntos/tdi/tcpip/ip/ipstatus.c
new file mode 100644
index 000000000..e71e36280
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/ipstatus.c
@@ -0,0 +1,205 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1992 **/
+/********************************************************************/
+/* :ts=4 */
+
+//*** ipstatus.c - IP status routines.
+//
+// This module contains all routines related to status indications.
+//
+
+
+#include "oscfg.h"
+#include "cxport.h"
+#include "ndis.h"
+#include "ip.h"
+#include "ipdef.h"
+#include "llipif.h"
+#include "iproute.h"
+#include "ipinfo.h"
+
+#if 0
+EXTERNAL_LOCK(PILock)
+#endif
+extern ProtInfo IPProtInfo[]; // Protocol information table.
+extern int NextPI; // Next PI field to be used.
+extern ProtInfo *RawPI; // Raw IP protinfo
+
+//* FindULStatus - Find the upper layer status handler.
+//
+// Called when we need to find the upper layer status handler for a particular
+// protocol.
+//
+// Entry: Protocol - Protocol to look up
+//
+// Returns: A pointer to the ULStatus proc, or NULL if it can't find one.
+//
+ULStatusProc
+FindULStatus(uchar Protocol)
+{
+ ULStatusProc StatusProc = (ULStatusProc)NULL;
+ int i;
+#if 0
+ CTELockHandle Handle;
+
+
+ CTEGetLock(&PILock, &Handle);
+#endif
+ for ( i = 0; i < NextPI; i++) {
+ if (IPProtInfo[i].pi_protocol == Protocol) {
+ StatusProc = IPProtInfo[i].pi_status;
+#if 0
+ CTEFreeLock(&PILock, Handle);
+#endif
+ return StatusProc;
+ }
+ }
+
+ if (RawPI != NULL) {
+ StatusProc = RawPI->pi_status;
+ }
+
+#if 0
+ CTEFreeLock(&PILock, Handle);
+#endif
+
+ return StatusProc;
+}
+
+
+//* ULMTUNotify - Notify the upper layers of an MTU change.
+//
+// Called when we need to notify the upper layers of an MTU change. We'll
+// loop through the status table, calling each status proc with the info.
+//
+// This routine doesn't do any locking of the protinfo table. We might need
+// to check this.
+//
+// Input: Dest - Destination address affected.
+// Src - Source address affected.
+// Prot - Protocol that triggered change, if any.
+// Ptr - Pointer to protocol info, if any.
+// NewMTU - New MTU to tell them about.
+//
+// Returns: Nothing.
+//
+void
+ULMTUNotify(IPAddr Dest, IPAddr Src, uchar Prot, void *Ptr, uint NewMTU)
+{
+ ULStatusProc StatusProc;
+ int i;
+
+ // First, notify the specific client that a frame has been dropped
+ // and needs to be retransmitted.
+
+ StatusProc = FindULStatus(Prot);
+ if (StatusProc != NULL)
+ (*StatusProc)(IP_NET_STATUS, IP_SPEC_MTU_CHANGE, Dest, Src,
+ NULL_IP_ADDR, NewMTU, Ptr);
+
+ // Now notify all UL entities that the MTU has changed.
+ for (i = 0; i < NextPI; i++) {
+ StatusProc = IPProtInfo[i].pi_status;
+
+ if (StatusProc != NULL)
+ (*StatusProc)(IP_HW_STATUS, IP_MTU_CHANGE, Dest, Src, NULL_IP_ADDR,
+ NewMTU, Ptr);
+ }
+}
+
+#ifdef CHICAGO
+
+//* IPULUnloadNotify - Notify clients that we're unloading.
+//
+// Called when we receive an unload message. We'll notify the upper layers
+// that we're unloading.
+//
+// Input: Nothing.
+//
+// Returns: Nothing.
+//
+void
+IPULUnloadNotify(void)
+{
+ ULStatusProc StatusProc;
+ int i;
+
+ // Now notify all UL entities that the MTU has changed.
+ for (i = 0; i < NextPI; i++) {
+ StatusProc = IPProtInfo[i].pi_status;
+
+ if (StatusProc != NULL)
+ (*StatusProc)(IP_HW_STATUS, IP_UNLOAD, NULL_IP_ADDR, NULL_IP_ADDR,
+ NULL_IP_ADDR, 0, NULL);
+ }
+}
+
+#endif
+
+//* IPStatus - Handle a link layer status call.
+//
+// This is the routine called by the link layer when some sort of 'important'
+// status change occurs.
+//
+// Entry: Context - Context value we gave to the link layer.
+// Status - Status change code.
+// Buffer - Pointer to buffer of status information.
+// BufferSize - Size of Buffer.
+//
+// Returns: Nothing.
+//
+void
+IPStatus(void *Context, uint Status, void *Buffer, uint BufferSize)
+{
+ NetTableEntry *NTE = (NetTableEntry *)Context;
+ LLIPSpeedChange *LSC;
+ LLIPMTUChange *LMC;
+ LLIPAddrMTUChange *LAM;
+ uint NewMTU;
+ Interface *IF;
+
+
+ switch (Status) {
+
+ case LLIP_STATUS_SPEED_CHANGE:
+ if (BufferSize < sizeof(LLIPSpeedChange))
+ break;
+ LSC = (LLIPSpeedChange *)Buffer;
+ NTE->nte_if->if_speed = LSC->lsc_speed;
+ break;
+ case LLIP_STATUS_MTU_CHANGE:
+ if (BufferSize < sizeof(LLIPMTUChange))
+ break;
+ // Walk through the NTEs on the IF, updating their MTUs.
+ IF = NTE->nte_if;
+ LMC = (LLIPMTUChange *)Buffer;
+ IF->if_mtu = LMC->lmc_mtu;
+ NewMTU = LMC->lmc_mtu - sizeof(IPHeader);
+ NTE = IF->if_nte;
+ while (NTE != NULL) {
+ NTE->nte_mss = NewMTU;
+ NTE = NTE->nte_ifnext;
+ }
+ RTWalk(SetMTUOnIF, IF, &NewMTU);
+ break;
+ case LLIP_STATUS_ADDR_MTU_CHANGE:
+ if (BufferSize < sizeof(LLIPAddrMTUChange))
+ break;
+ // The MTU for a specific remote address has changed. Update all
+ // routes that use that remote address as a first hop, and then
+ // add a host route to that remote address, specifying the new
+ // MTU.
+ LAM = (LLIPAddrMTUChange *)Buffer;
+ NewMTU = LAM->lam_mtu - sizeof(IPHeader);
+ RTWalk(SetMTUToAddr, &LAM->lam_addr, &NewMTU);
+ AddRoute(LAM->lam_addr, HOST_MASK, IPADDR_LOCAL, NTE->nte_if, NewMTU,
+ 1, IRE_PROTO_LOCAL, ATYPE_OVERRIDE, GetRouteContext(LAM->lam_addr,
+ NTE->nte_addr));
+ break;
+ default:
+ break;
+ }
+
+}
+
diff --git a/private/ntos/tdi/tcpip/ip/ipxmit.c b/private/ntos/tdi/tcpip/ip/ipxmit.c
new file mode 100644
index 000000000..61ee32b90
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/ipxmit.c
@@ -0,0 +1,1949 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1992 **/
+/********************************************************************/
+/* :ts=4 */
+
+//*** ipxmit.c - IP transmit routines.
+//
+// This module contains all transmit related IP routines.
+//
+
+#include "oscfg.h"
+#include "cxport.h"
+#include "ndis.h"
+#include "ip.h"
+#include "ipdef.h"
+#include "ipinit.h"
+#include "info.h"
+#include "iproute.h"
+#include "iprtdef.h"
+#include "ipfilter.h"
+
+typedef struct NdisResEntry {
+ struct NdisResEntry *nre_next;
+ NDIS_HANDLE nre_handle;
+ uchar *nre_buffer;
+} NdisResEntry;
+
+extern BufferReference *GetBufferReference(void);
+
+extern NetTableEntry *NetTableList; // Pointer to the net table.
+extern NetTableEntry *LoopNTE; // Pointer to loopback NTE.
+extern NetTableEntry *DHCPNTE; // Pointer to NTE currently being
+ // DHCP'd.
+
+extern ulong TimeStamp; // Starting timestamp.
+extern ulong TSFlag; // Mask to use on this.
+extern uint NumNTE;
+
+//* Global variables for buffers and packets.
+DEFINE_LOCK_STRUCTURE(HeaderLock)
+#ifdef NT
+SLIST_HEADER PacketList;
+SLIST_HEADER HdrBufList;
+#else
+PNDIS_PACKET PacketList;
+PNDIS_BUFFER HdrBufList = NULL;
+#endif
+
+NdisResEntry *PacketPoolList = NULL;
+NdisResEntry *HdrPoolList = NULL;
+
+uint CurrentPacketCount = 0;
+uint MaxPacketCount = 0xfffffff;
+
+uint CurrentHdrBufCount = 0;
+uint MaxHdrBufCount = 0xffffffff;
+
+NDIS_HANDLE BufferPool;
+
+#define HDR_BUF_GROW_COUNT 16
+#define PACKET_GROW_COUNT 16
+
+//* Global IP ID.
+ulong IPID;
+
+//** FreeIPHdrBuffer - Free a buffer back to the pool.
+//
+// Input: Buffer - Hdr buffer to be freed.
+//
+// Returns: Nothing.
+//
+void
+FreeIPHdrBuffer(PNDIS_BUFFER Buffer)
+{
+
+#ifdef VXD
+ NDIS_BUFFER_LINKAGE(Buffer) = HdrBufList;
+ HdrBufList = Buffer;
+#else
+
+ ExInterlockedPushEntrySList(
+ &HdrBufList,
+ STRUCT_OF(SINGLE_LIST_ENTRY, &(Buffer->Next), Next),
+ &HeaderLock
+ );
+
+#endif
+
+}
+
+//** FreeIPBufferChain - Free a chain of IP buffers.
+//
+// This routine takes a chain of NDIS_BUFFERs, and frees them all.
+//
+// Entry: Buffer - Pointer to buffer chain to be freed.
+//
+// Returns: Nothing.
+//
+void
+FreeIPBufferChain(PNDIS_BUFFER Buffer)
+{
+ PNDIS_BUFFER NextBuffer;
+
+ while (Buffer != (PNDIS_BUFFER)NULL) {
+ NdisGetNextBuffer(Buffer, &NextBuffer);
+ NdisFreeBuffer(Buffer);
+ Buffer = NextBuffer;
+ }
+}
+
+//* FreeIPPacket - Free an IP packet when we're done with it.
+//
+// Called when a send completes and a packet needs to be freed. We look at the
+// packet, decide what to do with it, and free the appropriate components.
+//
+// Entry: Packet - Packet to be freed.
+//
+// Returns: Pointer to next unfreed buffer on packet, or NULL if all buffers freed
+// (i.e. this was a fragmented packet).
+//
+PNDIS_BUFFER
+FreeIPPacket(PNDIS_PACKET Packet)
+{
+ PNDIS_BUFFER NextBuffer, OldBuffer;
+ PacketContext *pc = (PacketContext *)Packet->ProtocolReserved;
+
+
+ // BUGBUG - Get NDIS fixed to make this portable.
+#ifdef VXD
+ NextBuffer = Packet->Private.Head;
+#else // VXD
+ NdisQueryPacket(Packet, NULL, NULL, &NextBuffer, NULL);
+#endif // VXD
+
+ // If there's no IP header on this packet, we have nothing else to do.
+ if (!(pc->pc_common.pc_flags & (PACKET_FLAG_IPHDR | PACKET_FLAG_FW))) {
+ CTEAssert(pc->pc_common.pc_flags == 0);
+
+ NdisReinitializePacket(Packet);
+
+#ifdef VXD
+ pc->pc_common.pc_link = PacketList;
+ PacketList = Packet;
+#else
+ ExInterlockedPushEntrySList(
+ &PacketList,
+ STRUCT_OF(SINGLE_LIST_ENTRY, &(pc->pc_common.pc_link), Next),
+ &HeaderLock
+ );
+#endif
+
+ return NextBuffer;
+ }
+
+ pc->pc_common.pc_flags &= ~PACKET_FLAG_IPHDR;
+
+ OldBuffer = NextBuffer;
+ CTEAssert(OldBuffer != NULL);
+
+ NextBuffer = NDIS_BUFFER_LINKAGE(NextBuffer);
+
+ if (pc->pc_common.pc_flags & PACKET_FLAG_OPTIONS) { // Have options with
+ // this packet.
+ PNDIS_BUFFER OptBuffer;
+ void *Options;
+ uint OptSize;
+
+ OptBuffer = NextBuffer;
+ CTEAssert(OptBuffer != NULL);
+
+ NdisGetNextBuffer(OptBuffer,&NextBuffer);
+
+ CTEAssert(NextBuffer != NULL);
+
+ NdisQueryBuffer(OptBuffer, &Options, &OptSize);
+ // If this is a FW packet, the options don't really belong to us, so
+ // don't free them.
+ if (!(pc->pc_common.pc_flags & PACKET_FLAG_FW))
+ CTEFreeMem(Options);
+ NdisFreeBuffer(OptBuffer);
+ pc->pc_common.pc_flags &= ~PACKET_FLAG_OPTIONS;
+ }
+
+ if (pc->pc_common.pc_flags & PACKET_FLAG_IPBUF) { // This packet is all
+ // IP buffers.
+ (void)FreeIPBufferChain(NextBuffer);
+ NextBuffer = (PNDIS_BUFFER)NULL;
+ pc->pc_common.pc_flags &= ~PACKET_FLAG_IPBUF;
+ }
+
+
+ if (!(pc->pc_common.pc_flags & PACKET_FLAG_FW)) {
+ FreeIPHdrBuffer(OldBuffer);
+ NdisReinitializePacket(Packet);
+#ifdef _PNP_POWER
+ pc->pc_if = NULL;
+#endif
+
+#ifdef VXD
+ pc->pc_common.pc_link = PacketList;
+ PacketList = Packet;
+#else
+ ExInterlockedPushEntrySList(
+ &PacketList,
+ STRUCT_OF(SINGLE_LIST_ENTRY, &(pc->pc_common.pc_link), Next),
+ &HeaderLock
+ );
+#endif
+ }
+
+ return NextBuffer;
+}
+
+//** GrowIPPacketList - Grow the number of packets in our list.
+//
+// Called when we need to grow the number of packets in our list. We assume
+// this routine is called with the HeaderLock held. We check to see if
+// we've reached our limit on the number of packets, and if we haven't we'll
+// grow the free list.
+//
+// Input: Nothing.
+//
+// Returns: Pointer to newly allocated packet, or NULL if this faild.
+//
+PNDIS_PACKET
+GrowIPPacketList(void)
+{
+ NdisResEntry *NewEntry;
+ NDIS_STATUS Status;
+ PNDIS_PACKET Packet, ReturnPacket;
+ uint i;
+ CTELockHandle Handle;
+
+ CTEGetLock(&HeaderLock, &Handle);
+
+ if (CurrentPacketCount >= MaxPacketCount)
+ goto failure;
+
+ // First, allocate a tracking structure.
+ NewEntry = CTEAllocMem(sizeof(NdisResEntry));
+ if (NewEntry == NULL)
+ goto failure;
+
+ // Got a tracking structure. Now allocate a packet pool.
+ NdisAllocatePacketPool(&Status, &NewEntry->nre_handle, PACKET_GROW_COUNT,
+ sizeof(PacketContext));
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ CTEFreeMem(NewEntry);
+ goto failure;
+ }
+
+ // We've allocated the pool. Now initialize the packets, and link them
+ // on the free list.
+ ReturnPacket = NULL;
+
+ // Link the new NDIS resource tracker entry onto the list.
+ NewEntry->nre_next = PacketPoolList;
+ PacketPoolList = NewEntry;
+ CurrentPacketCount += PACKET_GROW_COUNT;
+ CTEFreeLock(&HeaderLock, Handle);
+
+ for (i = 0; i < PACKET_GROW_COUNT; i++) {
+ PacketContext *PC;
+
+ NdisAllocatePacket(&Status, &Packet, NewEntry->nre_handle);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ CTEAssert(FALSE);
+ break;
+ }
+
+ CTEMemSet(Packet->ProtocolReserved, 0, sizeof(PacketContext));
+ PC = (PacketContext *)Packet->ProtocolReserved;
+ PC->pc_common.pc_owner = PACKET_OWNER_IP;
+ if (i != 0) {
+ (void)FreeIPPacket(Packet);
+ } else
+ ReturnPacket = Packet;
+
+ }
+
+ // We've put all but the first one on the list. Return the first one.
+ return ReturnPacket;
+
+failure:
+ CTEFreeLock(&HeaderLock, Handle);
+ return NULL;
+
+}
+
+
+//** GrowHdrBufList - Grow the our IP header buffer list.
+//
+// Called when we need to grow our header buffer list. We allocate a tracking
+// structure, a buffer pool and a bunch of buffers. Put them all together
+// and link them on the list.
+//
+// Input: Nothing.
+//
+// Returns: Pointer to newly header buffer, or NULL if this faild.
+//
+PNDIS_BUFFER
+GrowHdrBufList(void)
+{
+ NdisResEntry *NewEntry;
+ NDIS_STATUS Status;
+ PNDIS_BUFFER Buffer, ReturnBuffer;
+ uchar *Hdr;
+ uint i;
+ CTELockHandle Handle;
+
+ CTEGetLock(&HeaderLock, &Handle);
+
+ // Make sure we can grow.
+ if (CurrentHdrBufCount >= MaxHdrBufCount)
+ goto failure;
+
+ // First, allocate a tracking structure.
+ NewEntry = CTEAllocMem(sizeof(NdisResEntry));
+ if (NewEntry == NULL)
+ goto failure;
+
+ // Got a tracking structure. Now allocate a buffer pool.
+ NdisAllocateBufferPool(&Status, &NewEntry->nre_handle, HDR_BUF_GROW_COUNT);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ CTEFreeMem(NewEntry);
+ goto failure;
+ }
+
+ // We've allocated the pool. Now allocate memory for the buffers.
+ Hdr = CTEAllocMem(sizeof(IPHeader) * HDR_BUF_GROW_COUNT);
+ if (Hdr == NULL) {
+ // Couldn't get memory for the headers.
+ NdisFreeBufferPool(NewEntry->nre_handle);
+ CTEFreeMem(NewEntry);
+ goto failure;
+ }
+
+ NewEntry->nre_buffer = Hdr;
+
+ NewEntry->nre_next = HdrPoolList;
+ HdrPoolList = NewEntry;
+ ReturnBuffer = NULL;
+ CurrentHdrBufCount += HDR_BUF_GROW_COUNT;
+ CTEFreeLock(&HeaderLock, Handle);
+
+ for (i = 0; i < HDR_BUF_GROW_COUNT; i++) {
+
+ NdisAllocateBuffer(&Status, &Buffer, NewEntry->nre_handle,
+ Hdr, sizeof(IPHeader));
+ if (Status != NDIS_STATUS_SUCCESS) {
+ CTEAssert(FALSE);
+ break;
+ }
+ if (i != 0) {
+ FreeIPHdrBuffer(Buffer);
+ } else
+ ReturnBuffer = Buffer;
+
+ Hdr += sizeof(IPHeader);
+
+ }
+
+ // Update the count for any we didn't actually allocate.
+ CTEInterlockedAddUlong(&CurrentHdrBufCount, i - HDR_BUF_GROW_COUNT,
+ &HeaderLock);
+
+ // We've put all but the first one on the list. Return the first one.
+ return ReturnBuffer;
+
+failure:
+ CTEFreeLock(&HeaderLock, Handle);
+ return NULL;
+
+}
+
+//** GetIPPacket - Get an NDIS packet to use.
+//
+// A routine to allocate an NDIS packet.
+//
+// Entry: Nothing.
+//
+// Returns: Pointer to NDIS_PACKET if allocated, or NULL.
+//
+PNDIS_PACKET
+GetIPPacket(void)
+{
+ PNDIS_PACKET Packet;
+
+
+#ifdef VXD
+ Packet = PacketList;
+ if (Packet != (PNDIS_PACKET)NULL) {
+ PacketContext *PC;
+
+ PC = (PacketContext *)Packet->ProtocolReserved;
+ PacketList = PC->pc_common.pc_link;
+ return Packet;
+#else
+ PSINGLE_LIST_ENTRY Link;
+ PacketContext *PC;
+ struct PCCommon *Common;
+
+ Link = ExInterlockedPopEntrySList(
+ &PacketList,
+ &HeaderLock
+ );
+ if (Link != NULL) {
+ Common = STRUCT_OF(struct PCCommon, Link, pc_link);
+ PC = STRUCT_OF(PacketContext, Common, pc_common);
+ Packet = STRUCT_OF(NDIS_PACKET, PC, ProtocolReserved);
+
+ return Packet;
+#endif
+
+
+ } else {
+ // Couldn't get a packet. Try to grow the list.
+ Packet = GrowIPPacketList();
+ }
+
+ return Packet;
+}
+
+
+//** GetIPHdrBuffer - Get an IP header buffer.
+//
+// A routine to allocate an IP header buffer, with an NDIS buffer.
+//
+// Entry: Nothing.
+//
+// Returns: Pointer to NDIS_BUFFER if allocated, or NULL.
+//
+PNDIS_BUFFER
+GetIPHdrBuffer(void)
+{
+ PNDIS_BUFFER Buffer;
+
+#ifdef VXD
+ Buffer = HdrBufList;
+ if (Buffer != NULL) {
+
+ HdrBufList = NDIS_BUFFER_LINKAGE(Buffer);
+ NDIS_BUFFER_LINKAGE(Buffer) = NULL;
+#else
+ PSINGLE_LIST_ENTRY BufferLink;
+
+ BufferLink = ExInterlockedPopEntrySList(
+ &HdrBufList,
+ &HeaderLock
+ );
+ if (BufferLink != NULL) {
+ Buffer = STRUCT_OF(NDIS_BUFFER, BufferLink, Next);
+ NDIS_BUFFER_LINKAGE(Buffer) = NULL;
+
+ return Buffer;
+
+#endif
+
+ } else {
+ Buffer = GrowHdrBufList();
+ }
+
+ return Buffer;
+
+}
+
+
+//** GetIPHeader - Get a header buffer and packet.
+//
+// Called when we need to get a header buffer and packet. We allocate both,
+// and chain them together.
+//
+// Input: Pointer to where to store packet.
+//
+// Returns: Pointer to IP header.
+//
+IPHeader *
+GetIPHeader(PNDIS_PACKET *PacketPtr)
+{
+ PNDIS_BUFFER Buffer;
+ PNDIS_PACKET Packet;
+
+
+ Packet = GetIPPacket();
+ if (Packet != NULL) {
+ Buffer = GetIPHdrBuffer();
+ if (Buffer != NULL) {
+ PacketContext *PC = (PacketContext *)Packet->ProtocolReserved;
+
+ NdisChainBufferAtBack(Packet, Buffer);
+ *PacketPtr = Packet;
+ PC->pc_common.pc_flags |= PACKET_FLAG_IPHDR;
+ return (IPHeader *)NdisBufferVirtualAddress(Buffer);
+
+ } else
+ FreeIPPacket(Packet);
+ }
+ return NULL;
+}
+
+
+//** ReferenceBuffer - Reference a buffer.
+//
+// Called when we need to update the count of a BufferReference strucutre, either
+// by a positive or negative value. If the count goes to 0, we'll free the buffer
+// reference and return success. Otherwise we'll return pending.
+//
+// Entry: BR - Pointer to buffer reference.
+// Count - Amount to adjust refcount by.
+//
+// Returns: Success, or pending.
+//
+int
+ReferenceBuffer(BufferReference *BR, int Count)
+{
+ CTELockHandle handle;
+ int NewCount;
+
+ CTEGetLock(&BR->br_lock, &handle);
+ BR->br_refcount += Count;
+ NewCount = BR->br_refcount;
+ CTEFreeLock(&BR->br_lock, handle);
+ return NewCount;
+}
+
+//* IPSendComplete - IP send complete handler.
+//
+// Called by the link layer when a send completes. We're given a pointer to a
+// net structure, as well as the completing send packet and the final status of
+// the send.
+//
+// Entry: Context - Context we gave to the link layer.
+// Packet - Completing send packet.
+// Status - Final status of send.
+//
+// Returns: Nothing.
+//
+void
+IPSendComplete(void *Context, PNDIS_PACKET Packet, NDIS_STATUS Status)
+{
+ NetTableEntry *NTE = (NetTableEntry *)Context;
+ PacketContext *PContext = (PacketContext *)Packet->ProtocolReserved;
+ PNDIS_BUFFER Buffer;
+ void (*xmitdone)(void *, PNDIS_BUFFER); // Pointer to xmit done routine.
+ void *UContext; // Upper layer context.
+ BufferReference *BufRef; // Buffer reference, if any.
+#ifdef _PNP_POWER
+ Interface *IF; // The interface on which this
+ // completed.
+#endif
+
+ xmitdone = PContext->pc_pi->pi_xmitdone; // Copy useful information from packet.
+ UContext = PContext->pc_context;
+ BufRef = PContext->pc_br;
+#ifdef _PNP_POWER
+ IF = PContext->pc_if;
+#endif
+
+ Buffer = FreeIPPacket(Packet);
+ if (BufRef == (BufferReference *)NULL) {
+#ifdef DEBUG
+ if (!Buffer)
+ DEBUGCHK;
+#endif
+ (*xmitdone)(UContext, Buffer);
+ } else {
+ if (!ReferenceBuffer(BufRef, -1)) {
+ Buffer = BufRef->br_buffer;
+#ifdef DEBUG
+ if (!Buffer)
+ DEBUGCHK;
+#endif
+ CTEFreeMem(BufRef);
+ (*xmitdone)(UContext, Buffer);
+ } else {
+#ifdef _PNP_POWER
+ // We're not done with the send yet, so NULL the IF to
+ // prevent dereferencing it.
+ IF = NULL;
+#endif
+ }
+ }
+
+#ifdef _PNP_POWER
+ // We're done with the packet now, we may need to dereference
+ // the interface.
+ if (IF == NULL) {
+ return;
+ } else {
+ DerefIF(IF);
+ }
+#endif
+
+}
+
+
+#ifndef NT
+
+//** xsum - Checksum a flat buffer.
+//
+// This is the lowest level checksum routine. It returns the uncomplemented
+// checksum of a flat buffer.
+//
+// Entry: Buffer - Buffer to be checksummed.
+// Size - Size in bytes of Buffer.
+//
+// Returns: The uncomplemented checksum of buffer.
+//
+ushort
+xsum(void *Buffer, int Size)
+{
+ ushort UNALIGNED *Buffer1 = (ushort UNALIGNED *)Buffer; // Buffer expressed as shorts.
+ ulong csum = 0;
+
+ while (Size > 1) {
+ csum += *Buffer1++;
+ Size -= sizeof(ushort);
+ }
+
+ if (Size)
+ csum += *(uchar *)Buffer1; // For odd buffers, add in last byte.
+
+ csum = (csum >> 16) + (csum & 0xffff);
+ csum += (csum >> 16);
+ return (ushort)csum;
+}
+
+#endif // NT
+
+
+//** SendIPPacket - Send an IP packet.
+//
+// Called when we have a filled in IP packet we need to send. Basically, we
+// compute the xsum and send the thing.
+//
+// Entry: IF - Interface to send it on.
+// FirstHop - First hop address to send it to.
+// Packet - Packet to be sent.
+// Buffer - Buffer to be sent.
+// Header - Pointer to IP Header of packet.
+// Options - Pointer to option buffer.
+// OptionLength - Length of options.
+//
+// Returns: IP_STATUS of attempt to send.
+IP_STATUS
+SendIPPacket(Interface *IF, IPAddr FirstHop, PNDIS_PACKET Packet,
+ PNDIS_BUFFER Buffer, IPHeader *Header, uchar *Options, uint OptionSize)
+{
+ ulong csum;
+ NDIS_STATUS Status;
+
+
+ csum = xsum(Header, sizeof(IPHeader));
+ if (Options) { // We have options, oh boy.
+ PNDIS_BUFFER OptBuffer;
+ PacketContext *pc = (PacketContext *)Packet->ProtocolReserved;
+ NdisAllocateBuffer(&Status, &OptBuffer, BufferPool, Options, OptionSize);
+ if (Status != NDIS_STATUS_SUCCESS) { // Couldn't get the needed
+ // option buffer.
+ CTEFreeMem(Options);
+ FreeIPPacket(Packet);
+ return IP_NO_RESOURCES;
+ }
+ pc->pc_common.pc_flags |= PACKET_FLAG_OPTIONS;
+ NdisChainBufferAtBack(Packet, OptBuffer);
+ csum += xsum(Options, OptionSize);
+ csum = (csum >> 16) + (csum & 0xffff);
+ csum += (csum >> 16);
+ }
+ Header->iph_xsum = ~(ushort)csum;
+ NdisChainBufferAtBack(Packet,Buffer);
+
+ Status = (*(IF->if_xmit))(IF->if_lcontext, Packet, FirstHop, NULL);
+
+ if (Status == NDIS_STATUS_PENDING)
+ return IP_PENDING;
+
+ // Status wasn't pending. Free the packet, and map the status.
+ FreeIPPacket(Packet);
+ if (Status == NDIS_STATUS_SUCCESS)
+ return IP_SUCCESS;
+ else
+ return IP_HW_ERROR;
+}
+
+//* SendDHCPPacket - Send a broadcast for DHCP.
+//
+// Called when somebody is sending a broadcast packet with a NULL source
+// address. We assume this means they're sending a DHCP packet. We loop
+// through the NTE table, and when we find an entry that's not valid we
+// send out the interface associated with that entry.
+//
+// Input: Dest - Destination of packet.
+// Packet - Packet to be send.
+// Buffer - Buffer chain to be sent.
+// Header - Pointer to header buffer being sent.
+//
+// Return: Status of send attempt.
+//
+IP_STATUS
+SendDHCPPacket(IPAddr Dest, PNDIS_PACKET Packet, PNDIS_BUFFER Buffer,
+ IPHeader *IPH)
+{
+ if (DHCPNTE != NULL && ((DHCPNTE->nte_flags & (NTE_VALID | NTE_ACTIVE))
+ == NTE_ACTIVE)) {
+ // The DHCP NTE is currently invalid, and active. Send on that
+ // interface.
+ return SendIPPacket(DHCPNTE->nte_if, Dest, Packet, Buffer, IPH, NULL,
+ 0);
+ }
+
+ // Didn't find an invalid NTE! Free the resources, and return the failure.
+ FreeIPPacket(Packet);
+ IPSInfo.ipsi_outdiscards++;
+ return IP_DEST_HOST_UNREACHABLE;
+
+}
+
+
+//
+// Macros needed by IpCopyBuffer
+//
+#ifdef VXD
+
+#define NdisBufferLength(Buffer) (Buffer)->Length
+#define NdisBufferVirtualAddress(Buffer) (Buffer)->VirtualAddress
+
+#else // VXD
+#ifdef NT
+
+#define NdisBufferLength(Buffer) MmGetMdlByteCount(Buffer)
+#define NdisBufferVirtualAddress(Buffer) MmGetSystemAddressForMdl(Buffer)
+
+#else // NT
+
+#error Need appropriate NDIS macros here
+
+#endif NT
+#endif // VXD
+//* IPCopyBuffer - Copy an NDIS buffer chain at a specific offset.
+//
+// This is the IP version of the function NdisCopyBuffer, which didn't
+// get done properly in NDIS3. We take in an NDIS buffer chain, an offset,
+// and a length, and produce a buffer chain describing that subset of the
+// input buffer chain.
+//
+// This routine is not particularly efficient. Since only IPFragment uses
+// it currently, it might be better to just incorporate this functionality
+// directly into IPFragment.
+//
+// Input: OriginalBuffer - Original buffer chain to copy from.
+// Offset - Offset from start to dup.
+// Length - Length in bytes to dup.
+//
+// Returns: Pointer to new chain if we can make one, NULL if we can't.
+//
+PNDIS_BUFFER
+IPCopyBuffer(PNDIS_BUFFER OriginalBuffer,uint Offset, uint Length)
+{
+
+ PNDIS_BUFFER CurrentBuffer; // Pointer to current buffer.
+ PNDIS_BUFFER *NewBuffer; // Pointer to pointer to current new buffer.
+ PNDIS_BUFFER FirstBuffer; // First buffer in new chain.
+ UINT CopyLength; // Length of current copy.
+ NDIS_STATUS NewStatus; // Status of NdisAllocateBuffer operation.
+
+ // First skip over the number of buffers we need to to reach Offset.
+ CurrentBuffer = OriginalBuffer;
+
+ while (Offset >= NdisBufferLength(CurrentBuffer)) {
+ Offset -= NdisBufferLength(CurrentBuffer);
+ CurrentBuffer = NDIS_BUFFER_LINKAGE(CurrentBuffer);
+ if (CurrentBuffer == (PNDIS_BUFFER)NULL)
+ return NULL;
+ }
+
+ // Now CurrentBuffer is the buffer from which we start building the new chain, and
+ // Offset is the offset into CurrentBuffer from which to start.
+ FirstBuffer = NULL;
+ NewBuffer = &FirstBuffer;
+
+ do {
+
+ CopyLength = MIN(
+ Length,
+ NdisBufferLength(CurrentBuffer) - Offset
+ );
+ NdisAllocateBuffer(&NewStatus, NewBuffer, BufferPool,
+ ((uchar *)NdisBufferVirtualAddress(CurrentBuffer)) + Offset,
+ CopyLength);
+ if (NewStatus != NDIS_STATUS_SUCCESS)
+ break;
+
+ Offset = 0; // No offset from next buffer.
+ NewBuffer = &(NDIS_BUFFER_LINKAGE(*NewBuffer));
+ CurrentBuffer = NDIS_BUFFER_LINKAGE(CurrentBuffer);
+ Length -= CopyLength;
+ } while (Length != 0 && CurrentBuffer != (PNDIS_BUFFER)NULL);
+
+ if (Length == 0) { // We succeeded
+ return FirstBuffer;
+ } else { // We exited the loop because of an error.
+
+ // We need to free any allocated buffers, and return.
+ CurrentBuffer = FirstBuffer;
+ while (CurrentBuffer != (PNDIS_BUFFER)NULL) {
+ PNDIS_BUFFER Temp = CurrentBuffer;
+ CurrentBuffer = NDIS_BUFFER_LINKAGE(CurrentBuffer);
+ NdisFreeBuffer(Temp);
+ }
+ return NULL;
+ }
+}
+
+//** IPFragment - Fragment and send an IP datagram.
+//
+// Called when an outgoing datagram is larger than the local MTU, and needs to be
+// fragmented. This is a somewhat complicated operation. The caller gives us a
+// prebuilt IP header, packet, and options. We use the header and packet on
+// the last fragment of the send, as the passed in header already has the more
+// fragments bit set correctly for the last fragment.
+//
+// The basic idea is to figure out the maximum size which we can send as a multiple
+// of 8. Then, while we can send a maximum size fragment we'll allocate a header, packet,
+// etc. and send it. At the end we'll send the final fragment using the provided header
+// and packet.
+//
+// Entry: DestIF - Outbound interface of datagram.
+// MTU - MTU to use in transmitting.
+// FirstHop - First (or next) hop for this datagram.
+// Packet - Packet to be sent.
+// Header - Prebuilt IP header.
+// Buffer - Buffer chain for data to be sent.
+// DataSize - Size in bytes of data.
+// Options - Pointer to option buffer, if any.
+// OptionSize - Size in bytes of option buffer.
+// SentCount - Pointer to where to return pending send count (may be NULL).
+//
+// Returns: IP_STATUS of send.
+//
+IP_STATUS
+IPFragment(Interface *DestIF, uint MTU, IPAddr FirstHop,
+ PNDIS_PACKET Packet, IPHeader *Header, PNDIS_BUFFER Buffer, uint DataSize,
+ uchar *Options, uint OptionSize, int *SentCount)
+{
+ BufferReference *BR; // Buffer reference we'll use.
+ PacketContext *PContext = (PacketContext *)Packet->ProtocolReserved;
+ PacketContext *CurrentContext; // Current Context in use.
+ uint MaxSend; // Maximum size (in bytes) we can send here.
+ uint PendingSends = 0; // Counter of how many pending sends we have.
+ PNDIS_BUFFER CurrentBuffer; // Current buffer to be sent.
+ PNDIS_PACKET CurrentPacket; // Current packet we're using.
+ IP_STATUS SendStatus; // Status of send command.
+ IPHeader *CurrentHeader; // Current header buffer we're using.
+ ushort Offset = 0; // Current offset into fragmented packet.
+ ushort StartOffset; // Starting offset of packet.
+ ushort RealOffset; // Offset of new fragment.
+ uint FragOptSize = 0; // Size (in bytes) of fragment options.
+ uchar FragmentOptions[MAX_OPT_SIZE]; // Master copy of options sent for fragments.
+ uchar Error = FALSE; // Set if we get an error in our main loop.
+
+ MaxSend = (MTU - OptionSize) & ~7; // Determine max send size.
+
+#ifdef DEBUG
+ if (MaxSend >= DataSize)
+ DEBUGCHK;
+#endif
+
+ BR = PContext->pc_br; // Get the buffer reference we'll need.
+
+#ifdef DEBUG
+ if (!BR)
+ DEBUGCHK;
+#endif
+
+ if (Header->iph_offset & IP_DF_FLAG) { // Don't fragment flag set.
+ // Error out.
+ FreeIPPacket(Packet);
+ if (Options)
+ CTEFreeMem(Options);
+ if (SentCount == (int *)NULL) // No sent count is to be
+ // returned.
+ CTEFreeMem(BR);
+ IPSInfo.ipsi_fragfails++;
+ return IP_PACKET_TOO_BIG;
+ }
+
+ StartOffset = Header->iph_offset & IP_OFFSET_MASK;
+ StartOffset = net_short(StartOffset) * 8;
+
+ // If we have any options, copy the ones that need to be copied, and figure
+ // out the size of these new copied options.
+
+ if (Options != (uchar *)NULL) { // We have options.
+ uchar *TempOptions = Options;
+ const uchar *EndOptions = (const uchar *)(Options+OptionSize);
+
+ // Copy the options into the fragment options buffer.
+ CTEMemSet(FragmentOptions, IP_OPT_EOL, MAX_OPT_SIZE);
+ while ((TempOptions[IP_OPT_TYPE] != IP_OPT_EOL) &&
+ (TempOptions < EndOptions)) {
+ if (TempOptions[IP_OPT_TYPE] & IP_OPT_COPIED) { // This option needs
+ // to be copied.
+ uint TempOptSize;
+
+ TempOptSize = TempOptions[IP_OPT_LENGTH];
+ CTEMemCopy(&FragmentOptions[FragOptSize], TempOptions,
+ TempOptSize);
+ FragOptSize += TempOptSize;
+ TempOptions += TempOptSize;
+ } else { // A non-copied option, just
+ // skip over it.
+ if (TempOptions[IP_OPT_TYPE] == IP_OPT_NOP)
+ TempOptions++;
+ else
+ TempOptions += TempOptions[IP_OPT_LENGTH];
+ }
+ }
+ // Round the copied size up to a multiple of 4.
+ FragOptSize = ((FragOptSize & 3) ? ((FragOptSize & ~3) + 4) : FragOptSize);
+ }
+
+ PContext->pc_common.pc_flags |= PACKET_FLAG_IPBUF;
+
+ // Now, while we can build maximum size fragments, do so.
+ do {
+ if ((CurrentHeader = GetIPHeader(&CurrentPacket)) == (IPHeader *)NULL) {
+ // Couldn't get a buffer. Break out, since no point in sending others.
+ Error = TRUE;
+ break;
+ }
+
+ // Copy the buffer into a new one, if we can.
+ CurrentBuffer = IPCopyBuffer(Buffer, Offset, MaxSend);
+ if (CurrentBuffer == NULL) { // No buffer, free resources and
+ // break.
+ FreeIPPacket(CurrentPacket);
+ Error = TRUE;
+ break;
+ }
+
+ // Options for this send are set up when we get here, either from the
+ // entry from the loop, or from the allocation below.
+
+ // We have all the pieces we need. Put the packet together and send it.
+ CurrentContext = (PacketContext *)CurrentPacket->ProtocolReserved;
+ *CurrentContext = *PContext;
+ *CurrentHeader = *Header;
+ CurrentContext->pc_common.pc_flags &= ~PACKET_FLAG_FW;
+ CurrentHeader->iph_verlen = IP_VERSION +
+ ((OptionSize + sizeof(IPHeader)) >> 2);
+ CurrentHeader->iph_length = net_short(MaxSend+OptionSize+sizeof(IPHeader));
+ RealOffset = (StartOffset + Offset) >> 3;
+ CurrentHeader->iph_offset = net_short(RealOffset) | IP_MF_FLAG;
+
+ SendStatus = SendIPPacket(DestIF, FirstHop, CurrentPacket,
+ CurrentBuffer, CurrentHeader, Options, OptionSize);
+ if (SendStatus == IP_PENDING)
+ PendingSends++;
+
+ IPSInfo.ipsi_fragcreates++;
+ Offset += MaxSend;
+ DataSize -= MaxSend;
+
+ // If we have any fragmented options, set up to use them next time.
+ if (FragOptSize) {
+ Options = CTEAllocMem(OptionSize = FragOptSize);
+ if (Options == (uchar *)NULL) { // Can't get an option
+ // buffer.
+ Error = TRUE;
+ break;
+ }
+ CTEMemCopy(Options, FragmentOptions, OptionSize);
+ } else {
+ Options = (uchar *)NULL;
+ OptionSize = 0;
+ }
+ } while (DataSize > MaxSend);
+
+ // We've sent all of the previous fragments, now send the last one. We already
+ // have the packet and header buffer, as well as options if there are any -
+ // we need to copy the appropriate data.
+ if (!Error) { // Everything went OK above.
+ CurrentBuffer = IPCopyBuffer(Buffer, Offset, DataSize);
+ if (CurrentBuffer == NULL) { // No buffer, free resources
+ // and stop.
+ if (Options)
+ CTEFreeMem(Options); // Free the option buffer
+ FreeIPPacket(Packet);
+ IPSInfo.ipsi_outdiscards++;
+ } else { // Everything's OK, send it.
+ Header->iph_verlen = IP_VERSION + ((OptionSize + sizeof(IPHeader)) >> 2);
+ Header->iph_length = net_short(DataSize+OptionSize+sizeof(IPHeader));
+ RealOffset = (StartOffset + Offset) >> 3;
+ Header->iph_offset = net_short(RealOffset) |
+ (Header->iph_offset & IP_MF_FLAG);
+ SendStatus = SendIPPacket(DestIF, FirstHop, Packet,
+ CurrentBuffer, Header, Options, OptionSize);
+ if (SendStatus == IP_PENDING)
+ PendingSends++;
+ IPSInfo.ipsi_fragcreates++;
+ IPSInfo.ipsi_fragoks++;
+ }
+ } else { // We had some sort of error.
+ // Free resources.
+ FreeIPPacket(Packet);
+ if (Options)
+ CTEFreeMem(Options);
+ IPSInfo.ipsi_outdiscards++;
+ }
+
+
+ // Now, figure out what error code to return and whether or not we need to
+ // free the BufferReference.
+
+ if (SentCount == (int *)NULL) { // No sent count is to be
+ // returned.
+ if (!ReferenceBuffer(BR, PendingSends)) {
+ CTEFreeMem(BR);
+ return IP_SUCCESS;
+ }
+ return IP_PENDING;
+ } else
+ *SentCount += PendingSends;
+
+ return IP_PENDING;
+
+}
+
+//* UpdateRouteOption - Update a SR or RR options.
+//
+// Called by UpdateOptions when it needs to update a route option.
+//
+// Input: RTOption - Pointer to route option to be updated.
+// Address - Address to update with.
+//
+// Returns: TRUE if we updated, FALSE if we didn't.
+//
+uchar
+UpdateRouteOption(uchar *RTOption, IPAddr Address)
+{
+ uchar Pointer; // Pointer value of option.
+
+ Pointer = RTOption[IP_OPT_PTR] - 1;
+ if (Pointer < RTOption[IP_OPT_LENGTH]) {
+ if ((RTOption[IP_OPT_LENGTH] - Pointer) < sizeof(IPAddr)) {
+ return FALSE;
+ }
+ *(IPAddr UNALIGNED *)&RTOption[Pointer] = Address;
+ RTOption[IP_OPT_PTR] += sizeof(IPAddr);
+ }
+
+ return TRUE;
+
+}
+
+//* UpdateOptions - Update an options buffer.
+//
+// Called when we need to update an options buffer outgoing. We stamp the indicated
+// options with our local address.
+//
+// Input: Options - Pointer to options buffer to be updated.
+// Index - Pointer to information about which ones to update.
+// Address - Local address with which to update the options.
+//
+// Returns: Index of option causing the error, or MAX_OPT_SIZE if all goes well.
+//
+uchar
+UpdateOptions(uchar *Options, OptIndex *Index, IPAddr Address)
+{
+ uchar *LocalOption;
+ uchar LocalIndex;
+
+ // If we have both options and an index, update the options.
+ if (Options != (uchar *)NULL && Index != (OptIndex *)NULL) {
+
+ // If we have a source route to update, update it. If this fails return the index
+ // of the source route.
+ LocalIndex = Index->oi_srindex;
+ if (LocalIndex != MAX_OPT_SIZE)
+ if (!UpdateRouteOption(Options+LocalIndex, Address))
+ return LocalIndex;
+
+ // Do the same thing for any record route option.
+ LocalIndex = Index->oi_rrindex;
+ if (LocalIndex != MAX_OPT_SIZE)
+ if (!UpdateRouteOption(Options+LocalIndex, Address))
+ return LocalIndex;
+
+ // Now handle timestamp.
+ if ((LocalIndex = Index->oi_tsindex) != MAX_OPT_SIZE) {
+ uchar Flags, Length, Pointer;
+
+ LocalOption = Options + LocalIndex;
+ Pointer = LocalOption[IP_OPT_PTR] - 1;
+ Flags = LocalOption[IP_TS_OVFLAGS] & IP_TS_FLMASK;
+
+ // If we have room in the option, update it.
+ if (Pointer < (Length = LocalOption[IP_OPT_LENGTH])) {
+ ulong Now;
+ ulong UNALIGNED *TSPtr;
+
+ // Get the current time as milliseconds from midnight GMT, mod the number
+ // of milliseconds in 24 hours.
+ Now = ((TimeStamp + CTESystemUpTime()) | TSFlag) % (24*3600*1000);
+ Now = net_long(Now);
+ TSPtr = (ulong UNALIGNED *)&LocalOption[Pointer];
+
+ switch (Flags) {
+
+ // Just record the TS. If there is some room but not enough for an IP
+ // address we have an error.
+ case TS_REC_TS:
+ if ((Length - Pointer) < sizeof(IPAddr))
+ return LocalIndex; // Error - not enough room.
+ *TSPtr = Now;
+ LocalOption[IP_OPT_PTR] += sizeof(ulong);
+ break;
+
+ // Record only matching addresses.
+ case TS_REC_SPEC:
+ // If we're not the specified address, break out, else fall through
+ // to the record address case.
+ if (*(IPAddr UNALIGNED *)TSPtr != Address)
+ break;
+
+ // Record an address and timestamp pair. If there is some room
+ // but not enough for the address/timestamp pait, we have an error,
+ // so bail out.
+ case TS_REC_ADDR:
+ if ((Length - Pointer) < (sizeof(IPAddr) + sizeof(ulong)))
+ return LocalIndex; // Not enough room.
+ *(IPAddr UNALIGNED *)TSPtr = Address; // Store the address.
+ TSPtr++; // Update to where to put TS.
+ *TSPtr = Now; // Store TS
+ LocalOption[IP_OPT_PTR] += (sizeof(ulong) + sizeof(IPAddr));
+ break;
+ default: // Unknown flag type. Just ignore it.
+ break;
+ }
+ } else { // Have overflow.
+ // We have an overflow. If the overflow field isn't maxed, increment it. If
+ // it is maxed we have an error.
+ if ((LocalOption[IP_TS_OVFLAGS] & IP_TS_OVMASK) != IP_TS_MAXOV) // Not maxed.
+ LocalOption[IP_TS_OVFLAGS] += IP_TS_INC; // So increment it.
+ else
+ return LocalIndex; // Would have overflowed.
+ }
+ }
+ }
+ return MAX_OPT_SIZE;
+}
+
+
+typedef struct {
+ IPAddr bsl_addr;
+ Interface *bsl_if;
+ uint bsl_mtu;
+ ushort bsl_flags;
+} BCastSendList;
+
+//** SendIPBcast - Send a local BCast IP packet.
+//
+// This routine is called when we need to send a bcast packet. This may
+// involve sending on multiple interfaces. We figure out which interfaces
+// to send on, then loop through sending on them.
+//
+// Some care is needed to avoid sending the packet onto the same physical media
+// multiple times. What we do is loop through the NTE table, deciding in we
+// should send on the interface. As we go through we build up a list of
+// interfaces to send on. Then we loop through this list, sending on each
+// interface. This is a little cumbersome, but allows us to localize the
+// decision on where to send datagrams into one spot. If SendOnSource is FALSE
+// coming in we assume we've already sent on the specified source NTE and
+// initialize data structures accordingly. This feature is used in routing
+// datagrams.
+//
+// Entry: SrcNTE - NTE for source of send (unused if SendOnSource == TRUE).
+// Destination - Destination address
+// Packet - Prebuilt packet to broadcast.
+// IPH - Pointer to header buffer
+// Buffer - Buffer of data to be sent.
+// DataSize - Size of data to be sent.
+// Options - Pointer to options buffer.
+// OptionSize - Size in bytes of options.
+// SendOnSource - Indicator of whether or not this should be sent on the source net.
+// Index - Pointer to opt index array; may be NULL;
+//
+// Returns: Status of attempt to send.
+//
+IP_STATUS
+SendIPBCast(NetTableEntry *SrcNTE, IPAddr Destination, PNDIS_PACKET Packet,
+ IPHeader *IPH, PNDIS_BUFFER Buffer, uint DataSize, uchar *Options,
+ uint OptionSize, uchar SendOnSource, OptIndex *Index)
+{
+ BufferReference *BR; // Buffer reference to use for this
+ // buffer.
+ PacketContext *PContext = (PacketContext *)Packet->ProtocolReserved;
+ NetTableEntry *TempNTE;
+ uint i, j;
+ uint NeedFragment; // TRUE if we think we'll need to
+ // fragment.
+ int Sent = 0; // Count of how many we've sent.
+ IP_STATUS Status;
+ uchar *NewOptions; // Options we'll use on each send.
+ IPHeader *NewHeader;
+ PNDIS_BUFFER NewUserBuffer;
+ PNDIS_PACKET NewPacket;
+ BCastSendList *SendList;
+ uint NetsToSend;
+ IPAddr SrcAddr;
+ Interface *SrcIF;
+ IPHeader *Temp;
+ FORWARD_ACTION Action;
+
+
+ SendList = CTEAllocMem(sizeof(BCastSendList) * NumNTE);
+
+ if (SendList == NULL) {
+ return(IP_NO_RESOURCES);
+ }
+
+ CTEMemSet(SendList, 0, sizeof(BCastSendList) * NumNTE);
+
+ // If SendOnSource, initalize SrcAddr and SrcIF to be non-matching.
+ // Otherwise initialize them to the masked source address and source
+ // interface.
+ if (SendOnSource) {
+ SrcAddr = NULL_IP_ADDR;
+ SrcIF = NULL;
+ } else {
+ CTEAssert(SrcNTE != NULL);
+ SrcAddr = (SrcNTE->nte_addr & SrcNTE->nte_mask);
+ SrcIF = SrcNTE->nte_if;
+ }
+
+
+ NeedFragment = FALSE;
+ // Loop through the NTE table, making a list of interfaces and
+ // corresponding addresses to send on.
+ for (NetsToSend = 0, TempNTE = NetTableList; TempNTE != NULL;
+ TempNTE = TempNTE->nte_next) {
+ IPAddr TempAddr;
+
+ // Don't send through invalid or the loopback NTE.
+ if (!(TempNTE->nte_flags & NTE_VALID) || TempNTE == LoopNTE)
+ continue;
+
+ TempAddr = TempNTE->nte_addr & TempNTE->nte_mask;
+
+ // If he matches the source address or SrcIF, skip him.
+ if (IP_ADDR_EQUAL(TempAddr, SrcAddr) || TempNTE->nte_if == SrcIF)
+ continue;
+
+ // If the destination isn't a broadcast on this NTE, skip him.
+ if (!IS_BCAST_DEST(IsBCastOnNTE(Destination, TempNTE)))
+ continue;
+
+ // if this NTE is P2P then always add him to bcast list.
+ if ((TempNTE->nte_if)->if_flags & IF_FLAGS_P2P) {
+ j = NetsToSend ;
+ } else {
+ // Go through the list we've already build, looking for a match.
+ for (j = 0; j < NetsToSend; j++) {
+
+ // if P2P NTE then skip it - we want to send bcasts to all P2P interfaces in
+ // addition to 1 non P2P interface even if they are on the same subnet.
+ if ((SendList[j].bsl_if)->if_flags & IF_FLAGS_P2P)
+ continue ;
+
+ if (IP_ADDR_EQUAL(SendList[j].bsl_addr & TempNTE->nte_mask, TempAddr)
+ || SendList[j].bsl_if == TempNTE->nte_if) {
+
+ // He matches this send list element. Shrink the MSS if
+ // we need to, and then break out.
+ SendList[j].bsl_mtu = MIN(SendList[j].bsl_mtu, TempNTE->nte_mss);
+ if ((DataSize + OptionSize) > SendList[j].bsl_mtu)
+ NeedFragment = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (j == NetsToSend) {
+ // This is a new one. Fill him in, and bump NetsToSend.
+
+ SendList[j].bsl_addr = TempNTE->nte_addr;
+ SendList[j].bsl_if = TempNTE->nte_if;
+ SendList[j].bsl_mtu = TempNTE->nte_mss;
+ SendList[j].bsl_flags = TempNTE->nte_flags;
+ if ((DataSize + OptionSize) > SendList[j].bsl_mtu)
+ NeedFragment = TRUE;
+ NetsToSend++;
+ }
+
+ }
+
+ if (NetsToSend == 0) {
+ CTEFreeMem(SendList);
+ return IP_SUCCESS; // Nothing to send on.
+ }
+
+ // OK, we've got the list. If we've got more than one interface to send
+ // on or we need to fragment, get a BufferReference.
+ if (NetsToSend > 1 || NeedFragment) {
+ if ((BR = CTEAllocMem(sizeof(BufferReference))) ==
+ (BufferReference *)NULL) {
+ CTEFreeMem(SendList);
+ return IP_NO_RESOURCES;
+ }
+
+ BR->br_buffer = Buffer;
+ BR->br_refcount = 0;
+ CTEInitLock(&BR->br_lock);
+ PContext->pc_br = BR;
+ } else {
+ BR = NULL;
+ PContext->pc_br = NULL;
+ }
+
+ //
+ // We need to pass up the options and IP hdr in a contiguous buffer.
+ // Allocate the buffer once and re-use later.
+ //
+ if (ForwardFilterPtr != NULL) {
+ if (Options == NULL) {
+#if FWD_DBG
+ DbgPrint("Options==NULL\n");
+#endif
+ Temp = IPH;
+ } else {
+ Temp = CTEAllocMem(sizeof(IPHeader) + OptionSize);
+ if (Temp == NULL) {
+ CTEFreeMem(SendList);
+ return IP_NO_RESOURCES;
+ }
+
+ *Temp = *IPH;
+#if FWD_DBG
+ DbgPrint("Options!=NULL : alloced temp @ %lx\n", Temp);
+#endif
+
+ //
+ // done later...
+ // CTEMemCopy((uchar *)(Temp + 1), Options, OptionSize);
+ }
+ }
+
+ // Now, loop through the list. For each entry, send.
+
+ for (i = 0; i < NetsToSend; i++) {
+
+ // For all nets except the last one we're going to send on we need
+ // to make a copy of the header, packet, buffers, and any options.
+ // On the last net we'll use the user provided information.
+
+ if (i != (NetsToSend - 1)) {
+ if ((NewHeader = GetIPHeader(&NewPacket)) == (IPHeader *)NULL) {
+ IPSInfo.ipsi_outdiscards++;
+ continue; // Couldn't get a header, skip this
+ // send.
+ }
+
+ NewUserBuffer = IPCopyBuffer(Buffer, 0, DataSize);
+ if (NewUserBuffer == NULL) { // Couldn't get user buffer
+ // copied.
+ FreeIPPacket(NewPacket);
+ IPSInfo.ipsi_outdiscards++;
+ continue;
+ }
+
+ *(PacketContext *)NewPacket->ProtocolReserved = *PContext;
+ *NewHeader = *IPH;
+ (*(PacketContext*)NewPacket->ProtocolReserved).pc_common.pc_flags |= PACKET_FLAG_IPBUF;
+ (*(PacketContext*)NewPacket->ProtocolReserved).pc_common.pc_flags &= ~PACKET_FLAG_FW;
+ if (Options) {
+ // We have options, make a copy.
+ if ((NewOptions = CTEAllocMem(OptionSize)) == (uchar *)NULL) {
+ FreeIPBufferChain(NewUserBuffer);
+ FreeIPPacket(NewPacket);
+ IPSInfo.ipsi_outdiscards++;
+ continue;
+ }
+ CTEMemCopy(NewOptions, Options, OptionSize);
+ }
+ else {
+ NewOptions = NULL;
+ }
+ } else {
+ NewHeader = IPH;
+ NewPacket = Packet;
+ NewOptions = Options;
+ NewUserBuffer = Buffer;
+ }
+
+ UpdateOptions(NewOptions, Index, SendList[i].bsl_addr);
+
+ // See if we need to filter this packet. If we
+ // do, call the filter routine to see if it's
+ // OK to send it.
+ if (ForwardFilterPtr != NULL) {
+ //
+ // Copy over the options.
+ //
+ if (NewOptions) {
+ CTEMemCopy((uchar *)(Temp + 1), NewOptions, OptionSize);
+ }
+
+ Action = (*ForwardFilterPtr)(Temp,
+ NdisBufferVirtualAddress(NewUserBuffer),
+ NdisBufferLength(NewUserBuffer),
+ NULL, SendList[i].bsl_if->if_filtercontext);
+
+#if FWD_DBG
+ DbgPrint("ForwardFilterPtr: %lx, FORWARD is %lx\n", Action, FORWARD);
+#endif
+
+ if (Action != FORWARD) {
+ if (i != (NetsToSend - 1)) {
+ FreeIPBufferChain(NewUserBuffer);
+ if (NewOptions) {
+ CTEFreeMem(NewOptions);
+ }
+ }
+ continue;
+ }
+ }
+
+ if ((DataSize + OptionSize) > SendList[i].bsl_mtu) {// This is too big
+ // Don't need to update Sent when fragmenting, as IPFragment
+ // will update the br_refcount field itself. It will also free
+ // the option buffer.
+ Status = IPFragment(SendList[i].bsl_if, SendList[i].bsl_mtu,
+ Destination, NewPacket, NewHeader,NewUserBuffer, DataSize,
+ NewOptions, OptionSize, &Sent);
+
+ // IPFragment is done with the descriptor chain, so if this is
+ // a locally allocated chain free it now.
+ if (i != (NetsToSend - 1))
+ FreeIPBufferChain(NewUserBuffer);
+ }
+ else {
+ Status = SendIPPacket(SendList[i].bsl_if, Destination, NewPacket,
+ NewUserBuffer, NewHeader, NewOptions, OptionSize);
+ if (Status == IP_PENDING)
+ Sent++;
+ }
+ }
+
+ if (ForwardFilterPtr && Options) {
+ CTEFreeMem(Temp);
+ }
+
+ // Alright, we've sent everything we need to. We'll adjust the reference count
+ // by the number we've sent. IPFragment may also have put some references
+ // on it. If the reference count goes to 0, we're done and we'll free the
+ // BufferReference structure.
+
+ if (BR != NULL) {
+ if (!ReferenceBuffer(BR, Sent)) {
+ CTEFreeMem(SendList);
+ CTEFreeMem(BR); // Reference is 0, free the BR structure.
+ return IP_SUCCESS;
+ } else {
+ CTEFreeMem(SendList);
+ return IP_PENDING;
+ }
+ } else {
+ // Had only one I/F to send on. Just return the status.
+ CTEFreeMem(SendList);
+ return Status;
+ }
+
+}
+
+//** IPTransmit - Transmit a packet.
+//
+// This is the main transmit routine called by the upper layer. Conceptually,
+// we process any options, look up the route to the destination, fragment the
+// packet if needed, and send it. In reality, we use an RCE to cache the best
+// route, and we have special case code here for dealing with the common
+// case of no options, with everything fitting into one buffer.
+//
+// Entry: Context - Pointer to ProtInfo struc for protocol.
+// SendContext - User provided send context, passed back on send cmplt.
+// Protocol - Protocol field for packet.
+// Buffer - NDIS_BUFFER chain of data to be sent.
+// DataSize - Size in bytes of data to be sent.
+// OptInfo - Pointer to optinfo structure.
+// Dest - Destination to send to.
+// Source - Source address to use.
+// RCE - Pointer to an RCE structure that caches info. about path.
+//
+// Returns: Status of transmit command.
+//
+IP_STATUS
+IPTransmit(void *Context, void *SendContext, PNDIS_BUFFER Buffer, uint DataSize,
+ IPAddr Dest, IPAddr Source, IPOptInfo *OptInfo, RouteCacheEntry *RCE,
+ uchar Protocol)
+{
+ ProtInfo *PInfo = (ProtInfo *)Context;
+ PacketContext *pc;
+ Interface *DestIF; // Outgoing interface to use.
+ IPAddr FirstHop; // First hop address of
+ // destination.
+ uint MTU; // MTU of route.
+ NDIS_STATUS Status;
+ IPHeader *IPH;
+ PNDIS_PACKET Packet;
+ PNDIS_BUFFER HeaderBuffer;
+ CTELockHandle LockHandle;
+ uchar *Options;
+ uint OptionSize;
+ BufferReference *BR;
+ RouteTableEntry *RTE;
+ uchar DType;
+ IP_STATUS SendStatus;
+#ifdef _PNP_POWER
+ Interface *RoutedIF;
+#endif
+
+ IPSInfo.ipsi_outrequests++;
+
+ // Allocate a packet that we need for all cases, and fill
+ // in the common stuff. If everything goes well, we'll send it
+ // here. Otherwise we'll break out into special case code for
+ // broadcasts, fragments, etc.
+ if ((Packet = GetIPPacket()) != (PNDIS_PACKET)NULL) { // Got a packet.
+ pc = (PacketContext *)Packet->ProtocolReserved;
+ pc->pc_br = (BufferReference *)NULL;
+ pc->pc_pi = PInfo;
+ pc->pc_context = SendContext;
+#ifdef _PNP_POWER
+ CTEAssert(pc->pc_if == NULL);
+#endif
+
+ // Make sure that we have an RCE, that it's valid, etc.
+
+ if (RCE != NULL) {
+ // We have an RCE. Make sure it's valid.
+ CTEGetLock(&RCE->rce_lock, &LockHandle);
+ if (RCE->rce_flags == RCE_ALL_VALID) {
+
+ // The RTE is valid.
+ CTEInterlockedIncrementLong(&RCE->rce_usecnt);
+ RTE = RCE->rce_rte;
+ FirstHop = ADDR_FROM_RTE(RTE, Dest);
+ DestIF = IF_FROM_RTE(RTE);
+ MTU = MTU_FROM_RTE(RTE);
+
+ CTEFreeLock(&RCE->rce_lock, LockHandle);
+
+ // Check that we have no options, this isn't a broadcast, and
+ // that everything will fit into one link level MTU. If this
+ // is the case, we'll send it in a hurry.
+ if (OptInfo->ioi_options == (uchar *)NULL) {
+ if (RCE->rce_dtype != DEST_BCAST) {
+ if (DataSize <= MTU) {
+
+
+ NdisBufferLength(Buffer) += sizeof(IPHeader);
+ NdisChainBufferAtBack(Packet, Buffer);
+ IPH = (IPHeader *)NdisBufferVirtualAddress(Buffer);
+
+ IPH->iph_protocol = Protocol;
+ IPH->iph_xsum = 0;
+ IPH->iph_dest = Dest;
+ IPH->iph_src = Source;
+ IPH->iph_ttl = OptInfo->ioi_ttl;
+ IPH->iph_tos = OptInfo->ioi_tos;
+ IPH->iph_offset =
+ net_short(((OptInfo->ioi_flags & IP_FLAG_DF)
+ << 13));
+ IPH->iph_id =
+ (ushort)CTEInterlockedExchangeAdd(&IPID, 1);
+ IPH->iph_verlen = DEFAULT_VERLEN;
+ IPH->iph_length = net_short(DataSize+sizeof(IPHeader));
+ IPH->iph_xsum = ~xsum(IPH, sizeof(IPHeader));
+
+ // See if we need to filter this packet. If we
+ // do, call the filter routine to see if it's
+ // OK to send it.
+
+ if (ForwardFilterPtr == NULL) {
+ Status = (*(DestIF->if_xmit))(DestIF->if_lcontext,
+ Packet, FirstHop, RCE);
+
+ CTEInterlockedDecrementLong(&RCE->rce_usecnt);
+
+ if (Status != NDIS_STATUS_PENDING) {
+ FreeIPPacket(Packet);
+ return IP_SUCCESS; // BUGBUG - should map error
+ // code.
+ }
+ return IP_PENDING;
+
+ } else {
+ FORWARD_ACTION Action;
+
+ Action = (*ForwardFilterPtr)(IPH,
+ (uchar *)(IPH + 1),
+ NdisBufferLength(Buffer) -
+ sizeof(IPHeader),
+ NULL, DestIF->if_filtercontext);
+
+ if (Action == FORWARD) {
+ Status = (*(DestIF->if_xmit))(
+ DestIF->if_lcontext,
+ Packet, FirstHop, RCE);
+ } else {
+ Status = NDIS_STATUS_SUCCESS;
+ IPSInfo.ipsi_outdiscards++;
+ }
+
+ CTEInterlockedDecrementLong(&RCE->rce_usecnt);
+
+ if (Status != NDIS_STATUS_PENDING) {
+ FreeIPPacket(Packet);
+ return IP_SUCCESS; // BUGBUG - should map error
+ // code.
+ }
+ return IP_PENDING;
+ }
+ }
+ }
+ }
+ CTEInterlockedDecrementLong(&RCE->rce_usecnt);
+ DType = RCE->rce_dtype;
+ } else {
+ // We have an RCE, but there is no RTE for it. Call the
+ // routing code to fix this.
+ CTEFreeLock(&RCE->rce_lock, LockHandle);
+ if (!AttachRCEToRTE(RCE, PInfo->pi_protocol,
+ (uchar *)NdisBufferVirtualAddress(Buffer) + sizeof(IPHeader),
+ NdisBufferLength(Buffer))) {
+ IPSInfo.ipsi_outnoroutes++;
+ FreeIPPacket(Packet);
+ return IP_DEST_HOST_UNREACHABLE;
+ }
+
+ // See if the RCE is now valid.
+ CTEGetLock(&RCE->rce_lock, &LockHandle);
+ if (RCE->rce_flags == RCE_ALL_VALID) {
+
+ // The RCE is now valid, so use his info.
+ RTE = RCE->rce_rte;
+ FirstHop = ADDR_FROM_RTE(RTE, Dest);
+ DestIF = IF_FROM_RTE(RTE);
+ MTU = MTU_FROM_RTE(RTE);
+ DType = RCE->rce_dtype;
+ } else
+ FirstHop = NULL_IP_ADDR;
+ CTEFreeLock(&RCE->rce_lock, LockHandle);
+ }
+ } else {
+ // We had no RCE, so we'll have to look it up the hard way.
+ FirstHop = NULL_IP_ADDR;
+ }
+
+ // We bailed out of the fast path for some reason. Allocate a header
+ // buffer, and copy the data in the first buffer forward. Then figure
+ // out why we're off the fast path, and deal with it. If we don't have
+ // the next hop info, look it up now.
+
+ HeaderBuffer = GetIPHdrBuffer();
+ if (HeaderBuffer == NULL) {
+ FreeIPPacket(Packet);
+ IPSInfo.ipsi_outdiscards++;
+ return IP_NO_RESOURCES;
+ } else {
+ uchar *Temp1, *Temp2;
+
+ // Got a buffer, copy the upper layer data forward.
+
+ Temp1 = (uchar *)NdisBufferVirtualAddress(Buffer);
+ Temp2 = Temp1 + sizeof(IPHeader);
+ CTEMemCopy(Temp1, Temp2, NdisBufferLength(Buffer));
+ }
+
+ NdisChainBufferAtBack(Packet, HeaderBuffer);
+
+ IPH = (IPHeader *)NdisBufferVirtualAddress(HeaderBuffer);
+ IPH->iph_protocol = Protocol;
+ IPH->iph_xsum = 0;
+ IPH->iph_src = Source;
+ IPH->iph_ttl = OptInfo->ioi_ttl;
+ IPH->iph_tos = OptInfo->ioi_tos;
+ IPH->iph_offset = net_short(((OptInfo->ioi_flags & IP_FLAG_DF) << 13));
+ IPH->iph_id = (ushort)CTEInterlockedExchangeAdd(&IPID, 1);
+ pc = (PacketContext *)Packet->ProtocolReserved;
+ pc->pc_common.pc_flags |= PACKET_FLAG_IPHDR;
+
+ if (IP_ADDR_EQUAL(OptInfo->ioi_addr, NULL_IP_ADDR)) {
+ IPH->iph_dest = Dest;
+ }
+ else {
+ //
+ // We have a source route, so we need to redo the
+ // destination and first hop information.
+ //
+ Dest = OptInfo->ioi_addr;
+ IPH->iph_dest = Dest;
+
+ if (RCE != NULL) {
+ // We have an RCE. Make sure it's valid.
+ CTEGetLock(&RCE->rce_lock, &LockHandle);
+
+ if (RCE->rce_flags == RCE_ALL_VALID) {
+
+ // The RTE is valid.
+ RTE = RCE->rce_rte;
+ FirstHop = ADDR_FROM_RTE(RTE, Dest);
+ DestIF = IF_FROM_RTE(RTE);
+ MTU = MTU_FROM_RTE(RTE);
+ }
+ else {
+ FirstHop = NULL_IP_ADDR;
+ }
+
+ CTEFreeLock(&RCE->rce_lock, LockHandle);
+ }
+ }
+
+ if (IP_ADDR_EQUAL(FirstHop, NULL_IP_ADDR)) {
+ DestIF = LookupNextHopWithBuffer(Dest, Source, &FirstHop, &MTU,
+ PInfo->pi_protocol, (uchar *)NdisBufferVirtualAddress(Buffer),
+ NdisBufferLength(Buffer));
+#ifdef _PNP_POWER
+ pc->pc_if = DestIF;
+ RoutedIF = DestIF;
+#endif
+ if (DestIF == NULL) {
+ // Lookup failed. Return an error.
+ FreeIPPacket(Packet);
+ IPSInfo.ipsi_outnoroutes++;
+ return IP_DEST_HOST_UNREACHABLE;
+ }
+
+ DType = GetAddrType(Dest);
+#ifdef DEBUG
+ if (DType == DEST_INVALID)
+ DEBUGCHK;
+#endif
+ } else {
+#ifdef _PNP_POWER
+ RoutedIF = NULL;
+#endif
+ }
+
+ // See if we have any options. If we do, copy them now.
+ if (OptInfo->ioi_options != NULL) {
+ // If we have a SSRR, make sure that we're sending straight to the
+ // first hop.
+ if (OptInfo->ioi_flags & IP_FLAG_SSRR) {
+ if (!IP_ADDR_EQUAL(Dest, FirstHop)) {
+ FreeIPPacket(Packet);
+#ifdef _PNP_POWER
+ if (RoutedIF != NULL) {
+ DerefIF(RoutedIF);
+ }
+#endif
+ IPSInfo.ipsi_outnoroutes++;
+ return IP_DEST_HOST_UNREACHABLE;
+ }
+ }
+ Options = CTEAllocMem(OptionSize = OptInfo->ioi_optlength);
+ if (Options == (uchar *)NULL) {
+ FreeIPPacket(Packet);
+#ifdef _PNP_POWER
+ if (RoutedIF != NULL) {
+ DerefIF(RoutedIF);
+ }
+#endif
+ IPSInfo.ipsi_outdiscards++;
+ return IP_NO_RESOURCES;
+ }
+ CTEMemCopy(Options, OptInfo->ioi_options, OptionSize);
+ } else {
+ Options = (uchar *)NULL;
+ OptionSize = 0;
+ }
+
+ // The options have been taken care of. Now see if it's some sort
+ // of broadcast.
+ IPH->iph_verlen = IP_VERSION + ((OptionSize + sizeof(IPHeader)) >> 2);
+ IPH->iph_length = net_short(DataSize+OptionSize+sizeof(IPHeader));
+
+ // See if we need to filter this packet. If we
+ // do, call the filter routine to see if it's
+ // OK to send it.
+
+ if (ForwardFilterPtr != NULL) {
+ IPHeader *Temp;
+ FORWARD_ACTION Action;
+
+ if (Options == NULL) {
+ Temp = IPH;
+ } else {
+ Temp = CTEAllocMem(sizeof(IPHeader) + OptionSize);
+ if (Temp == NULL) {
+ FreeIPPacket(Packet);
+#ifdef _PNP_POWER
+ if (RoutedIF != NULL) {
+ DerefIF(RoutedIF);
+ }
+#endif
+ CTEFreeMem(Options);
+ IPSInfo.ipsi_outdiscards++;
+ return IP_NO_RESOURCES;
+ }
+
+ *Temp = *IPH;
+ CTEMemCopy((uchar *)(Temp + 1), Options, OptionSize);
+ }
+
+ Action = (*ForwardFilterPtr)(Temp,
+ NdisBufferVirtualAddress(Buffer),
+ NdisBufferLength(Buffer),
+ NULL, DestIF->if_filtercontext);
+
+ if (Options != NULL) {
+ CTEFreeMem(Temp);
+ }
+
+ if (Action != FORWARD) {
+ //
+ // If this is a bcast pkt, dont fail the send here since we might send this
+ // pkt over some other NTE; instead, let SendIPBCast deal with the Filtering
+ // for broadcast pkts.
+ //
+ // NOTE: We shd actually not call into ForwardFilterPtr here at all since we
+ // deal with it in BCast, but we do so in order to avoid a check above and hence
+ // take a double call hit in the bcast case.
+ //
+ if (DType != DEST_BCAST) {
+
+ if (Options)
+ CTEFreeMem(Options);
+ FreeIPPacket(Packet);
+
+#ifdef _PNP_POWER
+ if (RoutedIF != NULL) {
+ DerefIF(RoutedIF);
+ }
+#endif
+
+ IPSInfo.ipsi_outdiscards++;
+ return IP_DEST_HOST_UNREACHABLE;
+ }
+#if FWD_DBG
+ else {
+ DbgPrint("IPTransmit: ignoring return %lx\n", Action);
+ }
+#endif
+
+ }
+ }
+
+ // If this is a broadcast address, call our broadcast send handler
+ // to deal with this. The broadcast address handler will free the
+ // option buffer for us, if needed. Otherwise if it's a fragment, call
+ // the fragmentation handler.
+ if (DType == DEST_BCAST) {
+ if (IP_ADDR_EQUAL(Source, NULL_IP_ADDR)) {
+ SendStatus = SendDHCPPacket(Dest, Packet, Buffer, IPH);
+
+#ifdef _PNP_POWER
+ if (SendStatus != IP_PENDING && RoutedIF != NULL) {
+ DerefIF(RoutedIF);
+ }
+#endif
+
+ return SendStatus;
+ } else {
+ SendStatus= SendIPBCast(NULL, Dest, Packet, IPH, Buffer, DataSize,
+ Options, OptionSize, TRUE, NULL);
+
+#ifdef _PNP_POWER
+ if (SendStatus != IP_PENDING && RoutedIF != NULL) {
+ DerefIF(RoutedIF);
+ }
+#endif
+
+ return SendStatus;
+ }
+ }
+
+ // Not a broadcast. If it needs to be fragmented, call our
+ // fragmenter to do it. The fragmentation routine needs a
+ // BufferReference structure, so we'll need one of those first.
+ if ((DataSize + OptionSize) > MTU) {
+ BR = CTEAllocMem(sizeof(BufferReference));
+ if (BR == (BufferReference *)NULL) {
+ // Couldn't get a BufferReference
+ if (Options)
+ CTEFreeMem(Options);
+ FreeIPPacket(Packet);
+
+#ifdef _PNP_POWER
+ if (RoutedIF != NULL) {
+ DerefIF(RoutedIF);
+ }
+#endif
+
+ IPSInfo.ipsi_outdiscards++;
+ return IP_NO_RESOURCES;
+ }
+ BR->br_buffer = Buffer;
+ BR->br_refcount = 0;
+ CTEInitLock(&BR->br_lock);
+ pc->pc_br = BR;
+ SendStatus = IPFragment(DestIF, MTU, FirstHop, Packet, IPH, Buffer,
+ DataSize, Options, OptionSize, (int *)NULL);
+
+#ifdef _PNP_POWER
+ if (SendStatus != IP_PENDING && RoutedIF != NULL) {
+ DerefIF(RoutedIF);
+ }
+#endif
+
+ return SendStatus;
+ }
+
+ // If we've reached here, we aren't sending a broadcast and don't need to
+ // fragment anything. Presumably we got here because we have options.
+ // In any case, we're ready now.
+
+ SendStatus = SendIPPacket(DestIF, FirstHop, Packet, Buffer, IPH, Options,
+ OptionSize);
+
+#ifdef _PNP_POWER
+ if (SendStatus != IP_PENDING && RoutedIF != NULL) {
+ DerefIF(RoutedIF);
+ }
+#endif
+
+ return SendStatus;
+ }
+
+ // Couldn't get a buffer. Return 'no resources'
+ IPSInfo.ipsi_outdiscards++;
+ return IP_NO_RESOURCES;
+}
+
+
+
diff --git a/private/ntos/tdi/tcpip/ip/ipxmit.h b/private/ntos/tdi/tcpip/ip/ipxmit.h
new file mode 100644
index 000000000..65842967e
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/ipxmit.h
@@ -0,0 +1,34 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1992 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** IPXMIT.H - IP transmit definitions.
+//
+// This file contains all of the definitions for the transmit code visible
+// to modules outside IPXMIT.C
+extern IP_STATUS SendIPPacket(Interface *IF, IPAddr FirstHop,
+ PNDIS_PACKET Packet, PNDIS_BUFFER Buffer,
+ IPHeader *Header, uchar *Options,
+ uint OptionSize);
+extern IP_STATUS IPFragment(Interface *DestIF, uint MTU,
+ IPAddr FirstHop, PNDIS_PACKET Packet,
+ IPHeader *Header, PNDIS_BUFFER Buffer,
+ uint DataSize, uchar *Options,
+ uint OptionSize, int *SentCount);
+extern uchar UpdateOptions(uchar *Options, OptIndex *Index,
+ IPAddr Address);
+extern IP_STATUS SendIPBCast(NetTableEntry *SrcNTE, IPAddr Destination,
+ PNDIS_PACKET Packet, IPHeader *IPH,
+ PNDIS_BUFFER Buffer, uint DataSize,
+ uchar *Options, uint OptionSize,
+ uchar SendOnSource, OptIndex *Index);
+extern IP_STATUS IPTransmit(void *Context, void *SendContext,
+ PNDIS_BUFFER Buffer, uint DataSize,
+ IPAddr Dest, IPAddr Source,
+ IPOptInfo *OptInfo, RouteCacheEntry *RCE,
+ uchar Protocol);
+
+
+
diff --git a/private/ntos/tdi/tcpip/ip/mp/makefile b/private/ntos/tdi/tcpip/ip/mp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/mp/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/tcpip/ip/mp/sources b/private/ntos/tdi/tcpip/ip/mp/sources
new file mode 100644
index 000000000..301687c9a
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/mp/sources
@@ -0,0 +1,27 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+NT_UP=0
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/tcpip/ip/ntip.c b/private/ntos/tdi/tcpip/ip/ntip.c
new file mode 100644
index 000000000..040f025e3
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/ntip.c
@@ -0,0 +1,3361 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ntip.c
+
+Abstract:
+
+ NT specific routines for loading and configuring the IP driver.
+
+Author:
+
+ Mike Massa (mikemas) Aug 13, 1993
+
+Revision History:
+
+ Who When What
+ -------- -------- ----------------------------------------------
+ mikemas 08-13-93 created
+
+Notes:
+
+--*/
+
+#define _CTYPE_DISABLE_MACROS
+
+#include <oscfg.h>
+#include <ndis.h>
+#include <cxport.h>
+#include <ip.h>
+#include "ipdef.h"
+#include "ipinit.h"
+#include <ntddip.h>
+#include <tdiinfo.h>
+#include <ipinfo.h>
+
+//
+// Debugging macros
+//
+#if DBG
+
+#define TCPTRACE(many_args) DbgPrint many_args
+
+#else // DBG
+
+#define TCPTRACE(many_args) DbgPrint many_args
+
+#endif // DBG
+
+
+//
+// definitions needed by inet_addr.
+//
+#define INADDR_NONE 0xffffffff
+#define INADDR_ANY 0
+#define htonl(x) net_long(x)
+
+//
+// Other local constants
+//
+#define WORK_BUFFER_SIZE 256
+
+//
+// Configuration defaults
+//
+#define DEFAULT_IGMP_LEVEL 2
+#define DEFAULT_IP_NETS 8
+
+
+//
+// Local types
+//
+typedef struct _PerNetConfigInfo {
+ uint UseZeroBroadcast;
+ uint Mtu;
+ uint NumberOfGateways;
+ uint MaxForwardPending; // max routing packets pending
+} PER_NET_CONFIG_INFO, *PPER_NET_CONFIG_INFO;
+
+
+//
+// Global variables.
+//
+PDRIVER_OBJECT IPDriverObject;
+PDEVICE_OBJECT IPDeviceObject;
+IPConfigInfo *IPConfiguration;
+uint ArpUseEtherSnap = FALSE;
+uint ArpAlwaysSourceRoute = FALSE;
+uint IPAlwaysSourceRoute = TRUE;
+uint ArpCacheLife = DEFAULT_ARP_CACHE_LIFE;
+PWCHAR TempAdapterName;
+
+#ifndef _PNP_POWER
+
+NameMapping *AdptNameTable;
+DriverRegMapping *DriverNameTable;
+uint NumRegDrivers = 0;
+uint NetConfigSize = DEFAULT_IP_NETS;
+
+#endif // _PNP_POWER
+
+// Used in the conversion of 100ns times to milliseconds.
+static LARGE_INTEGER Magic10000 = {0xe219652c, 0xd1b71758};
+
+
+//
+// External variables
+//
+extern LIST_ENTRY PendingEchoList; // def needed for initialization
+extern LIST_ENTRY PendingIPSetNTEAddrList; // def needed for initialization
+extern IPSNMPInfo IPSInfo;
+EXTERNAL_LOCK(RouteTableLock)
+
+//
+// Macros
+//
+
+//++
+//
+// LARGE_INTEGER
+// CTEConvertMillisecondsTo100ns(
+// IN LARGE_INTEGER MsTime
+// );
+//
+// Routine Description:
+//
+// Converts time expressed in hundreds of nanoseconds to milliseconds.
+//
+// Arguments:
+//
+// MsTime - Time in milliseconds.
+//
+// Return Value:
+//
+// Time in hundreds of nanoseconds.
+//
+//--
+
+#define CTEConvertMillisecondsTo100ns(MsTime) \
+ RtlExtendedIntegerMultiply(MsTime, 10000)
+
+
+//++
+//
+// LARGE_INTEGER
+// CTEConvert100nsToMilliseconds(
+// IN LARGE_INTEGER HnsTime
+// );
+//
+// Routine Description:
+//
+// Converts time expressed in hundreds of nanoseconds to milliseconds.
+//
+// Arguments:
+//
+// HnsTime - Time in hundreds of nanoseconds.
+//
+// Return Value:
+//
+// Time in milliseconds.
+//
+//--
+
+#define SHIFT10000 13
+extern LARGE_INTEGER Magic10000;
+
+#define CTEConvert100nsToMilliseconds(HnsTime) \
+ RtlExtendedMagicDivide((HnsTime), Magic10000, SHIFT10000)
+
+
+//
+// External function prototypes
+//
+extern int
+IPInit(
+ void
+ );
+
+long
+IPSetInfo(
+ TDIObjectID *ID,
+ void *Buffer,
+ uint Size
+ );
+
+NTSTATUS
+IPDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+OpenRegKey(
+ PHANDLE HandlePtr,
+ PWCHAR KeyName
+ );
+
+NTSTATUS
+GetRegDWORDValue(
+ HANDLE KeyHandle,
+ PWCHAR ValueName,
+ PULONG ValueData
+ );
+
+NTSTATUS
+SetRegDWORDValue(
+ HANDLE KeyHandle,
+ PWCHAR ValueName,
+ PULONG ValueData
+ );
+
+NTSTATUS
+GetRegSZValue(
+ HANDLE KeyHandle,
+ PWCHAR ValueName,
+ PUNICODE_STRING ValueData,
+ PULONG ValueType
+ );
+
+NTSTATUS
+GetRegMultiSZValue(
+ HANDLE KeyHandle,
+ PWCHAR ValueName,
+ PUNICODE_STRING ValueData
+ );
+
+NTSTATUS
+InitRegDWORDParameter(
+ HANDLE RegKey,
+ PWCHAR ValueName,
+ ULONG *Value,
+ ULONG DefaultValue
+ );
+
+uint
+RTReadNext(
+ void *Context,
+ void *Buffer
+ );
+
+uint
+RTValidateContext(
+ void *Context,
+ uint *Valid
+ );
+
+//
+// Local funcion prototypes
+//
+NTSTATUS
+IPDriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+NTSTATUS
+IPProcessConfiguration(
+ VOID
+ );
+
+NTSTATUS
+IPProcessAdapterSection(
+ WCHAR *DeviceName,
+ WCHAR *AdapterName
+ );
+
+#ifndef _PNP_POWER
+
+NTSTATUS
+IPProcessIPAddressList(
+ HANDLE AdapterKey,
+ WCHAR *DeviceName,
+ WCHAR *AdapterName,
+ WCHAR *IpAddressList,
+ WCHAR *SubnetMaskList,
+ NDIS_STRING *LowerInterfaceString,
+ uint LowerInterfaceType,
+ PPER_NET_CONFIG_INFO PerNetConfigInfo
+ );
+
+#else // _PNP_POWER
+
+uint
+GetGeneralIFConfig(
+ IFGeneralConfig *ConfigInfo,
+ NDIS_HANDLE Handle
+ );
+
+int
+IsLLInterfaceValueNull(
+ NDIS_HANDLE Handle
+ );
+
+IFAddrList *
+GetIFAddrList(
+ UINT *NumAddr,
+ NDIS_HANDLE Handle
+ );
+
+#endif // _PNP_POWER
+
+UINT
+OpenIFConfig(
+ PNDIS_STRING ConfigName,
+ NDIS_HANDLE *Handle
+ );
+
+VOID
+CloseIFConfig(
+ NDIS_HANDLE Handle
+ );
+
+IPConfigInfo *
+IPGetConfig(
+ void
+ );
+
+void
+IPFreeConfig(
+ IPConfigInfo *ConfigInfo
+ );
+
+ulong
+GetGMTDelta(
+ void
+ );
+
+ulong
+GetTime(
+ void
+ );
+
+BOOLEAN
+IPConvertStringToAddress(
+ IN PWCHAR AddressString,
+ OUT PULONG IpAddress
+ );
+
+uint
+UseEtherSNAP(
+ PNDIS_STRING Name
+ );
+
+void
+GetAlwaysSourceRoute(
+ uint *pArpAlwaysSourceRoute,
+ uint *pIPAlwaysSourceRoute
+ );
+
+uint
+GetArpCacheLife(
+ void
+ );
+
+ULONG
+RouteMatch(
+ IN WCHAR *RouteString,
+ IN IPAddr Address,
+ IN IPMask Mask,
+ OUT IPAddr *DestVal,
+ OUT IPMask *DestMask,
+ OUT IPAddr *GateVal,
+ OUT ULONG *Metric
+ );
+
+VOID
+SetPersistentRoutesForNTE(
+ IPAddr Address,
+ IPMask Mask,
+ ULONG IFIndex
+ );
+
+ULONG
+GetCurrentRouteTable(
+ IPRouteEntry **ppRouteTable
+ );
+
+
+#ifdef ALLOC_PRAGMA
+
+#pragma alloc_text(INIT, IPDriverEntry)
+#pragma alloc_text(INIT, IPProcessConfiguration)
+#pragma alloc_text(INIT, IPProcessAdapterSection)
+#pragma alloc_text(INIT, IPGetConfig)
+#pragma alloc_text(INIT, IPFreeConfig)
+#pragma alloc_text(INIT, GetGMTDelta)
+#pragma alloc_text(INIT, GetTime)
+
+#ifndef _PNP_POWER
+
+#pragma alloc_text(INIT, IPProcessIPAddressList)
+#pragma alloc_text(INIT, UseEtherSNAP)
+#pragma alloc_text(INIT, GetAlwaysSourceRoute)
+#pragma alloc_text(INIT, GetArpCacheLife)
+
+#else // _PNP_POWER
+
+#pragma alloc_text(PAGE, GetGeneralIFConfig)
+#pragma alloc_text(PAGE, IsLLInterfaceValueNull)
+#pragma alloc_text(PAGE, GetIFAddrList)
+#pragma alloc_text(PAGE, UseEtherSNAP)
+#pragma alloc_text(PAGE, GetAlwaysSourceRoute)
+#pragma alloc_text(PAGE, GetArpCacheLife)
+
+#endif // _PNP_POWER
+
+#pragma alloc_text(PAGE, OpenIFConfig)
+#pragma alloc_text(PAGE, CloseIFConfig)
+#pragma alloc_text(PAGE, RouteMatch)
+#pragma alloc_text(PAGE, SetPersistentRoutesForNTE)
+#pragma alloc_text(PAGE, IPConvertStringToAddress)
+
+#endif // ALLOC_PRAGMA
+
+//
+// Function definitions
+//
+NTSTATUS
+IPDriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ Initialization routine for the IP driver.
+
+Arguments:
+
+ DriverObject - Pointer to the IP driver object created by the system.
+ DeviceDescription - The name of IP's node in the registry.
+
+Return Value:
+
+ The final status from the initialization operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ UNICODE_STRING deviceName;
+
+
+ IPDriverObject = DriverObject;
+
+ //
+ // Create the device object. IoCreateDevice zeroes the memory
+ // occupied by the object.
+ //
+
+ RtlInitUnicodeString(&deviceName, DD_IP_DEVICE_NAME);
+
+ status = IoCreateDevice(
+ DriverObject,
+ 0,
+ &deviceName,
+ FILE_DEVICE_NETWORK,
+ 0,
+ FALSE,
+ &IPDeviceObject
+ );
+
+ if (!NT_SUCCESS(status)) {
+ TCPTRACE((
+ "IP initialization failed: Unable to create device object %ws, status %lx.",
+ DD_IP_DEVICE_NAME,
+ status
+ ));
+
+ CTELogEvent(
+ DriverObject,
+ EVENT_TCPIP_CREATE_DEVICE_FAILED,
+ 1,
+ 1,
+ &deviceName.Buffer,
+ 0,
+ NULL
+ );
+
+ return(status);
+ }
+
+ //
+ // Intialize the device object.
+ //
+ IPDeviceObject->Flags |= DO_DIRECT_IO;
+
+ //
+ // Initialize the list of pending echo request IRPs.
+ //
+ InitializeListHead(&PendingEchoList);
+
+ //
+ // Initialize the list of pending SetAddr request IRPs.
+ //
+ InitializeListHead(&PendingIPSetNTEAddrList);
+
+ //
+ // Finally, read our configuration parameters from the registry.
+ //
+ status = IPProcessConfiguration();
+
+ if (status != STATUS_SUCCESS) {
+ IoDeleteDevice(IPDeviceObject);
+ }
+
+ return(status);
+}
+
+NTSTATUS
+IPProcessConfiguration(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Reads the IP configuration information from the registry and constructs
+ the configuration structure expected by the IP driver.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ STATUS_SUCCESS or an error status if an operation fails.
+
+--*/
+
+{
+ NTSTATUS status;
+ HANDLE myRegKey = NULL;
+ UNICODE_STRING bindString;
+ WCHAR *aName,
+ *endOfString;
+ WCHAR IPParametersRegistryKey[] =
+ L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Parameters";
+ WCHAR IPLinkageRegistryKey[] =
+ L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Linkage";
+ uint ArpTRSingleRoute;
+
+
+ bindString.Buffer = NULL;
+
+ IPConfiguration = CTEAllocMem(sizeof(IPConfigInfo));
+
+ if (IPConfiguration == NULL) {
+
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_NO_RESOURCES_FOR_INIT,
+ 1,
+ 0,
+ NULL,
+ 0,
+ NULL
+ );
+
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ CTEMemSet(IPConfiguration, 0, sizeof(IPConfigInfo));
+
+#ifndef _PNP_POWER
+
+ IPConfiguration->ici_netinfo = CTEAllocMem(
+ sizeof(NetConfigInfo) * DEFAULT_IP_NETS
+ );
+
+ if (IPConfiguration->ici_netinfo == NULL) {
+
+ CTEFreeMem(IPConfiguration);
+
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_NO_RESOURCES_FOR_INIT,
+ 2,
+ 0,
+ NULL,
+ 0,
+ NULL
+ );
+
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ CTEMemSet(
+ IPConfiguration->ici_netinfo,
+ 0,
+ sizeof(NetConfigInfo) * DEFAULT_IP_NETS
+ );
+
+#endif // _PNP_POWER
+
+ //
+ // Process the Ip\Parameters section of the registry
+ //
+ status = OpenRegKey(&myRegKey, IPParametersRegistryKey);
+
+ if (NT_SUCCESS(status)) {
+ //
+ // Expected configuration values. We use reasonable defaults if they
+ // aren't available for some reason.
+ //
+ status = GetRegDWORDValue(
+ myRegKey,
+ L"IpEnableRouter",
+ &(IPConfiguration->ici_gateway)
+ );
+
+ if (!NT_SUCCESS(status)) {
+ TCPTRACE((
+ "IP: Unable to read IpEnableRouter value from the registry.\n"
+ " Routing will be disabled.\n"
+ ));
+ IPConfiguration->ici_gateway = 0;
+ }
+
+ //
+ // Optional (hidden) values
+ //
+ (VOID)InitRegDWORDParameter(
+ myRegKey,
+ L"ForwardBufferMemory",
+ &(IPConfiguration->ici_fwbufsize),
+ DEFAULT_FW_BUFSIZE
+ );
+
+ (VOID)InitRegDWORDParameter(
+ myRegKey,
+ L"MaxForwardBufferMemory",
+ &(IPConfiguration->ici_maxfwbufsize),
+ DEFAULT_MAX_FW_BUFSIZE
+ );
+
+ (VOID)InitRegDWORDParameter(
+ myRegKey,
+ L"ForwardBroadcasts",
+ &(IPConfiguration->ici_fwbcast),
+ FALSE
+ );
+
+ (VOID)InitRegDWORDParameter(
+ myRegKey,
+ L"NumForwardPackets",
+ &(IPConfiguration->ici_fwpackets),
+ DEFAULT_FW_PACKETS
+ );
+
+ (VOID)InitRegDWORDParameter(
+ myRegKey,
+ L"MaxNumForwardPackets",
+ &(IPConfiguration->ici_maxfwpackets),
+ DEFAULT_MAX_FW_PACKETS
+ );
+
+ (VOID)InitRegDWORDParameter(
+ myRegKey,
+ L"IGMPLevel",
+ &(IPConfiguration->ici_igmplevel),
+ DEFAULT_IGMP_LEVEL
+ );
+
+ (VOID)InitRegDWORDParameter(
+ myRegKey,
+ L"EnableDeadGWDetect",
+ &(IPConfiguration->ici_deadgwdetect),
+ TRUE
+ );
+
+ (VOID)InitRegDWORDParameter(
+ myRegKey,
+ L"EnablePMTUDiscovery",
+ &(IPConfiguration->ici_pmtudiscovery),
+ TRUE
+ );
+
+ (VOID)InitRegDWORDParameter(
+ myRegKey,
+ L"DefaultTTL",
+ &(IPConfiguration->ici_ttl),
+ DEFAULT_TTL
+ );
+
+ (VOID)InitRegDWORDParameter(
+ myRegKey,
+ L"DefaultTOS",
+ &(IPConfiguration->ici_tos),
+ DEFAULT_TOS
+ );
+
+ (VOID)InitRegDWORDParameter(
+ myRegKey,
+ L"ArpUseEtherSnap",
+ &ArpUseEtherSnap,
+ FALSE
+ );
+
+ //
+ // we check for the return status here because if this parameter was
+ // not defined, then we want the default behavior for both arp
+ // and ip broadcasts. For arp, the behavior is to not source route
+ // and source router alternately. For ip, it is to always source
+ // route. If the parameter is defined and is 0, then for arp the
+ // behavior does not change. For ip however, we do not source route
+ // at all. Ofcourse, when the parameter is set to a non-zero value,
+ // we always source route for both.
+ //
+ status = InitRegDWORDParameter(
+ myRegKey,
+ L"ArpAlwaysSourceRoute",
+ &ArpAlwaysSourceRoute,
+ FALSE
+ );
+
+ if (NT_SUCCESS(status))
+ {
+ IPAlwaysSourceRoute = ArpAlwaysSourceRoute;
+ }
+ (VOID)InitRegDWORDParameter(
+ myRegKey,
+ L"ArpTRSingleRoute",
+ &ArpTRSingleRoute,
+ FALSE
+ );
+
+ if (ArpTRSingleRoute) {
+ TrRii = TR_RII_SINGLE;
+ } else {
+ TrRii = TR_RII_ALL;
+ }
+
+ (VOID)InitRegDWORDParameter(
+ myRegKey,
+ L"ArpCacheLife",
+ &ArpCacheLife,
+ DEFAULT_ARP_CACHE_LIFE
+ );
+
+ ZwClose(myRegKey);
+ myRegKey = NULL;
+ }
+ else {
+ //
+ // Use reasonable defaults.
+ //
+ IPConfiguration->ici_fwbcast = 0;
+ IPConfiguration->ici_gateway = 0;
+ IPConfiguration->ici_fwbufsize = DEFAULT_FW_BUFSIZE;
+ IPConfiguration->ici_fwpackets = DEFAULT_FW_PACKETS;
+ IPConfiguration->ici_maxfwbufsize = DEFAULT_MAX_FW_BUFSIZE;
+ IPConfiguration->ici_maxfwpackets = DEFAULT_MAX_FW_PACKETS;
+ IPConfiguration->ici_igmplevel = DEFAULT_IGMP_LEVEL;
+ IPConfiguration->ici_deadgwdetect = FALSE;
+ IPConfiguration->ici_pmtudiscovery = FALSE;
+ IPConfiguration->ici_ttl = DEFAULT_TTL;
+ IPConfiguration->ici_tos = DEFAULT_TOS;
+
+ TCPTRACE((
+ "IP: Unable to open Tcpip\\Parameters registry key. Using defaults.\n"
+ ));
+ }
+
+
+ //
+ // Process the Ip\Linkage section of the registry
+ //
+ status = OpenRegKey(&myRegKey, IPLinkageRegistryKey);
+
+ if (NT_SUCCESS(status)) {
+
+ bindString.Buffer = CTEAllocMem(WORK_BUFFER_SIZE * sizeof(WCHAR));
+
+ if (bindString.Buffer == NULL) {
+
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_NO_RESOURCES_FOR_INIT,
+ 3,
+ 0,
+ NULL,
+ 0,
+ NULL
+ );
+
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto error_exit;
+ }
+
+ bindString.Buffer[0] = UNICODE_NULL;
+ bindString.Length = 0;
+ bindString.MaximumLength = WORK_BUFFER_SIZE * sizeof(WCHAR);
+
+ status = GetRegMultiSZValue(
+ myRegKey,
+ L"Bind",
+ &bindString
+ );
+
+ if (NT_SUCCESS(status)) {
+ aName = bindString.Buffer;
+
+ if (bindString.Length > 0) {
+ //
+ // bindString is a MULTI_SZ which is a series of strings separated
+ // by NULL's with a double NULL at the end.
+ //
+ while (*aName != UNICODE_NULL) {
+ PWCHAR deviceName;
+
+ deviceName = aName;
+
+ //
+ // Find the end of the current string in the MULTI_SZ.
+ //
+ while (*aName != UNICODE_NULL) {
+ aName++;
+ ASSERT(
+ aName <
+ (PWCHAR) ( ((PUCHAR)bindString.Buffer) +
+ bindString.MaximumLength
+ )
+ );
+ }
+
+ endOfString = aName;
+
+ //
+ // Backtrack to the first backslash.
+ //
+ while ((aName >= bindString.Buffer) && (*aName-- != L'\\'));
+
+ aName += 2;
+
+ status = IPProcessAdapterSection(
+ deviceName,
+ aName
+ );
+
+ aName = endOfString + 1;
+ }
+ }
+ }
+#ifndef _PNP_POWER
+ else {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_NO_BINDINGS,
+ 1,
+ 0,
+ NULL,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP: Unable to open Tcpip\\Linkage\\Bind registry value.\n"
+ " Only the local loopback interface will be accessible.\n"
+ ));
+
+ }
+#endif _PNP_POWER
+ }
+ else {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_NO_BINDINGS,
+ 2,
+ 0,
+ NULL,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP: Unable to open registry key Tcpip\\Linkage.\n"
+ " Only the local loopback interface will be accessible.\n"
+ ));
+ }
+
+
+#ifndef _PNP_POWER
+
+ //
+ // Allocate the Driver and Adapter name tables
+ //
+
+ DriverNameTable = (DriverRegMapping *) CTEAllocMem(
+ (IPConfiguration->ici_numnets + 1) *
+ sizeof(DriverRegMapping)
+ );
+
+ AdptNameTable = (NameMapping *) CTEAllocMem(
+ (IPConfiguration->ici_numnets + 1) *
+ sizeof(NameMapping)
+ );
+
+ if ((DriverNameTable != NULL) && (AdptNameTable != NULL)) {
+ CTEMemSet(
+ DriverNameTable,
+ 0,
+ sizeof(DriverRegMapping) * (IPConfiguration->ici_numnets + 1)
+ );
+ CTEMemSet(
+ AdptNameTable,
+ 0,
+ sizeof(NameMapping) * (IPConfiguration->ici_numnets + 1)
+ );
+
+#endif // _PNP_POWER
+
+ if (!IPInit()) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_IP_INIT_FAILED,
+ 1,
+ 0,
+ NULL,
+ 0,
+ NULL
+ );
+
+ TCPTRACE(("IP initialization failed.\n"));
+ status = STATUS_UNSUCCESSFUL;
+ }
+ else {
+ status = STATUS_SUCCESS;
+ }
+
+#ifndef _PNP_POWER
+
+ }
+ else {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_IP_INIT_FAILED,
+ 1,
+ 0,
+ NULL,
+ 0,
+ NULL
+ );
+
+ TCPTRACE(("IP initialization failed.\n"));
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+#endif // _PNP_POWER
+
+error_exit:
+
+ if (bindString.Buffer != NULL) {
+ CTEFreeMem(bindString.Buffer);
+ }
+
+#ifndef _PNP_POWER
+
+ if (AdptNameTable != NULL) {
+ CTEFreeMem(AdptNameTable);
+ }
+
+ if (DriverNameTable != NULL) {
+ CTEFreeMem(DriverNameTable);
+ }
+
+#endif // _PNP_POWER
+
+ if (myRegKey != NULL) {
+ ZwClose(myRegKey);
+ }
+
+ if (IPConfiguration != NULL) {
+ IPFreeConfig(IPConfiguration);
+ }
+
+ return(status);
+}
+
+
+NTSTATUS
+IPProcessAdapterSection(
+ WCHAR *DeviceName,
+ WCHAR *AdapterName
+ )
+
+/*++
+
+Routine Description:
+
+ Reads all of the information needed under the Parameters\TCPIP section
+ of an adapter to which IP is bound.
+
+Arguments:
+
+ DeviceName - The name of the IP device.
+ AdapterName - The registry key for the adapter for this IP net.
+
+Return Value:
+
+ STATUS_SUCCESS or an error status if an operation fails.
+
+--*/
+
+{
+ HANDLE myRegKey;
+ UNICODE_STRING valueString;
+ NTSTATUS status;
+ ULONG valueType;
+ ulong invalidNetContext = 0xFFFF;
+ WCHAR TcpipParametersKey[] = L"\\Parameters\\TCPIP";
+ WCHAR ServicesRegistryKey[] =
+ L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
+#ifndef _PNP_POWER
+ uint numberOfGateways = 0;
+ uint llInterfaceType;
+ WCHAR *ipAddressBuffer = NULL;
+ WCHAR *subnetMaskBuffer = NULL;
+ NDIS_STRING llInterfaceString;
+ PER_NET_CONFIG_INFO perNetConfigInfo;
+ NetConfigInfo *NetConfiguration;
+ PWCHAR temp;
+
+
+ RtlInitUnicodeString(&llInterfaceString, NULL);
+
+ NetConfiguration = IPConfiguration->ici_netinfo +
+ IPConfiguration->ici_numnets;
+
+#endif // _PNP_POWER
+
+ //
+ // Get the size of the AdapterName string the easy way.
+ //
+ RtlInitUnicodeString(&valueString, AdapterName);
+
+ valueString.MaximumLength += sizeof(ServicesRegistryKey) +
+ sizeof(TcpipParametersKey);
+
+ valueString.Buffer = CTEAllocMem(valueString.MaximumLength);
+
+ if (valueString.Buffer == NULL) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_NO_ADAPTER_RESOURCES,
+ 4,
+ 1,
+ &AdapterName,
+ 0,
+ NULL
+ );
+
+ TCPTRACE(("IP: Unable to allocate memory for reg key name\n"));
+
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ valueString.Length = 0;
+ valueString.Buffer[0] = UNICODE_NULL;
+
+ //
+ // Build the key name for the tcpip parameters section and open key.
+ //
+ status = RtlAppendUnicodeToString(&valueString, ServicesRegistryKey);
+
+ if (!NT_SUCCESS(status)) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_ADAPTER_REG_FAILURE,
+ 1,
+ 1,
+ &AdapterName,
+ 0,
+ NULL
+ );
+
+ TCPTRACE(("IP: Unable to append services name to key string\n"));
+
+ goto exit2;
+ }
+
+ status = RtlAppendUnicodeToString(&valueString, AdapterName);
+
+ if (!NT_SUCCESS(status)) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_ADAPTER_REG_FAILURE,
+ 2,
+ 1,
+ &AdapterName,
+ 0,
+ NULL
+ );
+
+ TCPTRACE(("IP: Unable to append adapter name to key string\n"));
+
+ goto exit2;
+ }
+
+ status = RtlAppendUnicodeToString(&valueString, TcpipParametersKey);
+
+ if (!NT_SUCCESS(status)) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_ADAPTER_REG_FAILURE,
+ 3,
+ 1,
+ &AdapterName,
+ 0,
+ NULL
+ );
+
+ TCPTRACE(("IP: Unable to append parameters name to key string\n"));
+
+ goto exit2;
+ }
+
+ status = OpenRegKey(&myRegKey, valueString.Buffer);
+
+ if (!NT_SUCCESS(status)) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_ADAPTER_REG_FAILURE,
+ 4,
+ 1,
+ &AdapterName,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP: Unable to open adapter registry key %ws\n",
+ valueString.Buffer
+ ));
+
+ goto exit2;
+ }
+
+ //
+ // Invalidate the interface context for DHCP.
+ // When the first net is successfully configured, we'll write in the
+ // proper values.
+ //
+ status = SetRegDWORDValue(
+ myRegKey,
+ L"IPInterfaceContext",
+ &(invalidNetContext)
+ );
+
+ if (!NT_SUCCESS(status)) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_DHCP_INIT_FAILED,
+ 1,
+ 1,
+ &AdapterName,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP: Unable to Invalidate IPInterfaceContext value for adapter %ws.\n"
+ " DHCP may fail on this adapter.\n",
+ AdapterName
+ ));
+
+ goto exit1;
+ }
+
+#ifndef _PNP_POWER
+
+ //
+ // Process the gateway MultiSZ. The end is signified by a double NULL.
+ // This list currently only applies to the first IP address configured
+ // on this interface.
+ //
+ status = GetRegMultiSZValue(
+ myRegKey,
+ L"DefaultGateway",
+ &valueString
+ );
+
+ if (NT_SUCCESS(status)) {
+ PWCHAR addressString = valueString.Buffer;
+
+ while (*addressString != UNICODE_NULL) {
+ IPAddr addressValue;
+ BOOLEAN conversionStatus;
+
+ if (numberOfGateways >= MAX_DEFAULT_GWS) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_TOO_MANY_GATEWAYS,
+ 1,
+ 1,
+ &AdapterName,
+ 0,
+ NULL
+ );
+
+ break;
+ }
+
+ conversionStatus = IPConvertStringToAddress(
+ addressString,
+ &addressValue
+ );
+
+ if (conversionStatus && (addressValue != 0xFFFFFFFF)) {
+ if (addressValue != INADDR_ANY) {
+ NetConfiguration->nci_gw[numberOfGateways++] = addressValue;
+ }
+ }
+ else {
+ PWCHAR stringList[2];
+
+ stringList[0] = addressString;
+ stringList[1] = AdapterName;
+
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_INVALID_DEFAULT_GATEWAY,
+ 1,
+ 2,
+ stringList,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP: Invalid default gateway address %ws specified for adapter %ws.\n"
+ " Remote networks may not be reachable as a result.\n",
+ addressString,
+ AdapterName
+ ));
+ }
+
+ //
+ // Walk over the entry we just processed.
+ //
+ while (*addressString++ != UNICODE_NULL);
+ }
+ }
+ else {
+ TCPTRACE((
+ "IP: Unable to read DefaultGateway value for adapter %ws.\n"
+ " Initialization will continue.\n",
+ AdapterName
+ ));
+ }
+
+ perNetConfigInfo.NumberOfGateways = numberOfGateways;
+
+ //
+ // Figure out which lower layer driver to bind.
+ //
+ status = GetRegSZValue(
+ myRegKey,
+ L"LLInterface",
+ &valueString,
+ &valueType
+ );
+
+ if (NT_SUCCESS(status) && (*(valueString.Buffer) != UNICODE_NULL)) {
+ llInterfaceType = NET_TYPE_WAN;
+
+ if (!CTEAllocateString(
+ &llInterfaceString,
+ CTELengthString(&valueString)
+ )
+ ) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_NO_ADAPTER_RESOURCES,
+ 1,
+ 1,
+ &AdapterName,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP initialization failure: Unable to allocate memory "
+ "for LLInterface string for adapter %ws.\n",
+ AdapterName
+ ));
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto exit1;
+ }
+
+ CTECopyString(
+ &llInterfaceString,
+ &valueString
+ );
+ }
+ else {
+ //
+ // If the key isn't present or is empty, we use ARP
+ //
+ llInterfaceType = NET_TYPE_LAN;
+ }
+
+ //
+ // Are we using zeros broadcasts?
+ //
+ status = GetRegDWORDValue(
+ myRegKey,
+ L"UseZeroBroadcast",
+ &(perNetConfigInfo.UseZeroBroadcast)
+ );
+
+ if (!NT_SUCCESS(status)) {
+ TCPTRACE((
+ "IP: Unable to read UseZeroBroadcast value for adapter %ws.\n"
+ " All-nets broadcasts will be addressed to 255.255.255.255.\n",
+ AdapterName
+ ));
+ perNetConfigInfo.UseZeroBroadcast = FALSE; // default to off
+ }
+
+ //
+ // Has anyone specified an MTU?
+ //
+ status = GetRegDWORDValue(
+ myRegKey,
+ L"MTU",
+ &(perNetConfigInfo.Mtu)
+ );
+
+ if (!NT_SUCCESS(status)) {
+ perNetConfigInfo.Mtu = 0xFFFFFFF; // The stack will pick one.
+ }
+
+ //
+ // Have we been configured for more routing packets?
+ //
+ status = GetRegDWORDValue(
+ myRegKey,
+ L"MaxForwardPending",
+ &(perNetConfigInfo.MaxForwardPending)
+ );
+
+ if (!NT_SUCCESS(status)) {
+ perNetConfigInfo.MaxForwardPending = DEFAULT_MAX_PENDING;
+ }
+
+ //
+ // Read the IP address and Subnet Mask lists
+ //
+ status = GetRegMultiSZValue(
+ myRegKey,
+ L"IpAddress",
+ &valueString
+ );
+
+ if (!NT_SUCCESS(status)) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_NO_ADDRESS_LIST,
+ 1,
+ 1,
+ &AdapterName,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP: Unable to read the IP address list for adapter %ws.\n"
+ " IP will not be operational on this adapter\n",
+ AdapterName
+ ));
+ goto exit1;
+ }
+
+ ipAddressBuffer = ExAllocatePool(NonPagedPool, valueString.Length);
+
+ if (ipAddressBuffer == NULL) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_NO_ADAPTER_RESOURCES,
+ 2,
+ 1,
+ &AdapterName,
+ 0,
+ NULL
+ );
+
+ TCPTRACE(("IP: Unable to allocate memory for IP address list\n"));
+ goto exit1;
+ }
+
+ RtlCopyMemory(ipAddressBuffer, valueString.Buffer, valueString.Length);
+
+ status = GetRegMultiSZValue(
+ myRegKey,
+ L"Subnetmask",
+ &valueString
+ );
+
+ if (!NT_SUCCESS(status)) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_NO_MASK_LIST,
+ 1,
+ 1,
+ &AdapterName,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP: Unable to read the subnet mask list for adapter %ws.\n"
+ " IP will not be operational on this adapter.\n",
+ AdapterName
+ ));
+ goto exit1;
+ }
+
+ subnetMaskBuffer = ExAllocatePool(NonPagedPool, valueString.Length);
+
+ if (subnetMaskBuffer == NULL) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_NO_ADAPTER_RESOURCES,
+ 3,
+ 1,
+ &AdapterName,
+ 0,
+ NULL
+ );
+
+ TCPTRACE(("IP: Unable to allocate memory for subnet mask list\n"));
+ goto exit1;
+ }
+
+ RtlCopyMemory(subnetMaskBuffer, valueString.Buffer, valueString.Length);
+
+ //
+ // Initialize each net in the list
+ //
+ status = IPProcessIPAddressList(
+ myRegKey,
+ DeviceName,
+ AdapterName,
+ ipAddressBuffer,
+ subnetMaskBuffer,
+ &llInterfaceString,
+ llInterfaceType,
+ &perNetConfigInfo
+ );
+
+ if (status == STATUS_SUCCESS) {
+ //
+ // We leave the registry key open. It will be closed when
+ // initialization is completed.
+ //
+ goto exit2;
+ }
+
+#endif // ndef _PNP_POWER
+
+
+exit1:
+
+ ZwClose(myRegKey);
+
+exit2:
+
+ if (valueString.Buffer != NULL) {
+ CTEFreeMem(valueString.Buffer);
+ }
+
+#ifndef _PNP_POWER
+
+ if (ipAddressBuffer != NULL) {
+ ExFreePool(ipAddressBuffer);
+ }
+
+ if (subnetMaskBuffer != NULL) {
+ ExFreePool(subnetMaskBuffer);
+ }
+
+ if (llInterfaceString.Buffer != NULL) {
+ CTEFreeString(&llInterfaceString);
+ }
+
+#endif // _PNP_POWER
+
+ return(status);
+}
+
+#ifndef _PNP_POWER
+
+NTSTATUS
+IPProcessIPAddressList(
+ HANDLE AdapterKey,
+ WCHAR *DeviceName,
+ WCHAR *AdapterName,
+ WCHAR *IpAddressList,
+ WCHAR *SubnetMaskList,
+ NDIS_STRING *LowerInterfaceString,
+ uint LowerInterfaceType,
+ PPER_NET_CONFIG_INFO PerNetConfigInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Processes the IP address string for an adapter and creates entries
+ in the IP configuration structure for each interface.
+
+Arguments:
+
+ AdapterKey - The registry key for the adapter for this IP net.
+ DeviceName - The name of the IP device.
+ AdapterName - The name of the adapter being configured.
+ IpAddressList - The REG_MULTI_SZ list of IP address strings for
+ this adapter.
+ SubnetMaskList - The REG_MULTI_SZ list of subnet masks to match the
+ the addresses in IpAddressList.
+ LowerInterfaceString - The name of the link layer interface driver
+ supporting this adapter.
+ LowerInterfaceType - The type of link layer interface (LAN, WAN, etc).
+ PerNetConfigInfo - Miscellaneous information that applies to all
+ network interfaces on an adapter.
+
+Return Value:
+
+ An error status if an error occurs which prevents configuration
+ from continuing, else STATUS_SUCCESS. Events will be logged for
+ non-fatal errors.
+
+--*/
+
+{
+ IPAddr addressValue;
+ BOOLEAN firstTime = TRUE;
+ BOOLEAN configuredOne = FALSE;
+ NetConfigInfo *NetConfiguration;
+ UNICODE_STRING adapterString;
+ UNICODE_STRING configString;
+ PWCHAR configName = L"\\Parameters\\Tcpip";
+
+
+ while (*IpAddressList != UNICODE_NULL) {
+ BOOLEAN conversionStatus;
+
+
+ if (IPConfiguration->ici_numnets >= ((int) (NetConfigSize - 1))) {
+ NetConfigInfo *NewInfo;
+
+ NewInfo = CTEAllocMem(
+ (NetConfigSize + DEFAULT_IP_NETS) *
+ sizeof(NetConfigInfo)
+ );
+
+ if (NewInfo == NULL) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_TOO_MANY_NETS,
+ 1,
+ 1,
+ &AdapterName,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP: bound to too many nets. Further bindings, starting with\n"
+ " network %ws on adapter %ws cannot be made\n",
+ IpAddressList,
+ AdapterName
+ ));
+
+ break;
+ }
+
+ CTEMemCopy(
+ NewInfo,
+ IPConfiguration->ici_netinfo,
+ NetConfigSize * sizeof(NetConfigInfo)
+ );
+
+ CTEMemSet(
+ (NewInfo + NetConfigSize),
+ 0,
+ DEFAULT_IP_NETS
+ );
+
+ CTEFreeMem(IPConfiguration->ici_netinfo);
+ IPConfiguration->ici_netinfo = NewInfo;
+ NetConfigSize += DEFAULT_IP_NETS;
+ }
+
+ NetConfiguration = IPConfiguration->ici_netinfo +
+ IPConfiguration->ici_numnets;
+
+ if (*SubnetMaskList == UNICODE_NULL) {
+ PWCHAR stringList[2];
+
+ stringList[0] = IpAddressList;
+ stringList[1] = AdapterName;
+
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_NO_MASK,
+ 1,
+ 2,
+ stringList,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP: No subnet specified for IP address %ws and all\n"
+ " subsequent IP addresses on adapter %ws. These\n"
+ " interfaces will not be initialized.\n",
+ IpAddressList,
+ AdapterName
+ ));
+
+ break;
+ }
+
+ conversionStatus = IPConvertStringToAddress(
+ IpAddressList,
+ &addressValue
+ );
+
+ if (!conversionStatus || (addressValue == 0xFFFFFFFF)) {
+ PWCHAR stringList[2];
+
+ stringList[0] = IpAddressList;
+ stringList[1] = AdapterName;
+
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_INVALID_ADDRESS,
+ 1,
+ 2,
+ stringList,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP: Invalid IP address %ws specified for adapter %ws.\n"
+ " This interface will not be initialized.\n",
+ IpAddressList,
+ AdapterName
+ ));
+ firstTime = FALSE;
+ goto next_entry;
+ }
+
+ NetConfiguration->nci_addr = addressValue;
+
+ conversionStatus = IPConvertStringToAddress(
+ SubnetMaskList,
+ &addressValue
+ );
+
+ if (!conversionStatus || (addressValue == 0xFFFFFFFF)) {
+ PWCHAR stringList[3];
+
+ stringList[0] = SubnetMaskList;
+ stringList[1] = IpAddressList;
+ stringList[2] = AdapterName;
+
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_INVALID_MASK,
+ 1,
+ 3,
+ stringList,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP: Invalid subnet Mask %ws specified for IP address %ws "
+ "on adapter %ws\n"
+ " This interface will not be initialized\n",
+ SubnetMaskList,
+ IpAddressList,
+ AdapterName
+ ));
+ firstTime = FALSE;
+ goto next_entry;
+ }
+
+ NetConfiguration->nci_mask = addressValue;
+
+ NetConfiguration->nci_mtu = PerNetConfigInfo->Mtu;
+ NetConfiguration->nci_maxpending = PerNetConfigInfo->MaxForwardPending;
+ NetConfiguration->nci_zerobcast = PerNetConfigInfo->UseZeroBroadcast;
+ NetConfiguration->nci_type = LowerInterfaceType;
+
+ NetConfiguration->nci_numgws = PerNetConfigInfo->NumberOfGateways;
+ PerNetConfigInfo->NumberOfGateways = 0;
+ // this only applies to the first interface.
+
+ NetConfiguration->nci_type = LowerInterfaceType;
+
+ RtlInitUnicodeString(
+ &(NetConfiguration->nci_name),
+ DeviceName
+ );
+
+ RtlInitUnicodeString(&configString, configName);
+ RtlInitUnicodeString(&adapterString, AdapterName);
+
+ if (!CTEAllocateString(
+ &(NetConfiguration->nci_configname),
+ (adapterString.Length + configString.Length)
+ )
+ )
+ {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_NO_ADAPTER_RESOURCES,
+ 4,
+ 1,
+ &AdapterName,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP: Unable to allocate ConfigName string for interface\n"
+ " %ws on adapter %ws. This interface and all subsequent\n"
+ " interfaces on this adapter will be unavailable.\n",
+ IpAddressList,
+ AdapterName
+ ));
+ break;
+ }
+
+ CTECopyString(
+ &(NetConfiguration->nci_configname),
+ &adapterString
+ );
+
+ RtlAppendUnicodeStringToString(
+ &(NetConfiguration->nci_configname),
+ &configString
+ );
+
+ if (LowerInterfaceType != NET_TYPE_LAN) {
+
+ if (!CTEAllocateString(
+ &(NetConfiguration->nci_driver),
+ CTELengthString(LowerInterfaceString)
+ )
+ ) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_NO_ADAPTER_RESOURCES,
+ 4,
+ 1,
+ &AdapterName,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP: Unable to allocate LLInterface string for interface\n"
+ " %ws on adapter %ws. This interface and all subsequent\n"
+ " interfaces on this adapter will be unavailable.\n",
+ IpAddressList,
+ AdapterName
+ ));
+ break;
+ }
+
+ CTECopyString(
+ &(NetConfiguration->nci_driver),
+ LowerInterfaceString
+ );
+ }
+ else {
+ RtlInitUnicodeString(&(NetConfiguration->nci_driver), NULL);
+ }
+
+ if (firstTime) {
+ firstTime = FALSE;
+ NetConfiguration->nci_reghandle = AdapterKey;
+ }
+ else {
+ NetConfiguration->nci_reghandle = NULL;
+ }
+
+ IPConfiguration->ici_numnets++;
+ configuredOne = TRUE;
+
+next_entry:
+
+ while(*IpAddressList++ != UNICODE_NULL);
+ while(*SubnetMaskList++ != UNICODE_NULL);
+ }
+
+ if (configuredOne == FALSE) {
+ ZwClose(AdapterKey);
+ }
+
+ return(STATUS_SUCCESS);
+}
+
+
+#else // ndef _PNP_POWER
+
+
+uint
+GetGeneralIFConfig(
+ IFGeneralConfig *ConfigInfo,
+ NDIS_HANDLE Handle
+ )
+
+/*++
+
+ Routine Description:
+
+ A routine to get the general per-interface config info, such as MTU,
+ type of broadcast, etc. The caller gives us a structure to be filled in
+ and a handle, and we fill in the structure if we can.
+
+ Arguments:
+ ConfigInfo - Structure to be filled in.
+ Handle - Config handle from OpenIFConfig().
+
+ Return Value:
+ TRUE if we got all the required info, FALSE otherwise.
+
+--*/
+
+{
+ UNICODE_STRING valueString;
+ NTSTATUS status;
+ UINT numberOfGateways = 0;
+ UCHAR TempBuffer[WORK_BUFFER_SIZE];
+ ULONG ulAddGateway,ulTemp;
+
+ PAGED_CODE();
+
+ //
+ // Process the gateway MultiSZ. The end is signified by a double NULL.
+ // This list currently only applies to the first IP address configured
+ // on this interface.
+ //
+
+ ConfigInfo->igc_numgws = 0;
+
+ ulAddGateway = TRUE;
+
+ CTEMemSet(ConfigInfo->igc_gw, 0, sizeof(IPAddr) * MAX_DEFAULT_GWS);
+
+ valueString.Length = 0;
+ valueString.MaximumLength = WORK_BUFFER_SIZE;
+ valueString.Buffer = (PWCHAR)TempBuffer;
+
+ ulTemp = 0;
+
+ status = GetRegDWORDValue(Handle,
+ L"DontAddDefaultGateway",
+ &ulTemp);
+
+ if(NT_SUCCESS(status))
+ {
+ if(ulTemp == 1)
+ {
+ ulAddGateway = FALSE;
+ }
+ }
+
+ if(ulAddGateway)
+ {
+ status = GetRegMultiSZValue(
+ Handle,
+ L"DefaultGateway",
+ &valueString
+ );
+
+ if (NT_SUCCESS(status)) {
+ PWCHAR addressString = valueString.Buffer;
+
+ while (*addressString != UNICODE_NULL) {
+ IPAddr addressValue;
+ BOOLEAN conversionStatus;
+
+ if (numberOfGateways >= MAX_DEFAULT_GWS) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_TOO_MANY_GATEWAYS,
+ 1,
+ 1,
+ &TempAdapterName,
+ 0,
+ NULL
+ );
+
+ break;
+ }
+
+ conversionStatus = IPConvertStringToAddress(
+ addressString,
+ &addressValue
+ );
+
+ if (conversionStatus && (addressValue != 0xFFFFFFFF)) {
+ if (addressValue != INADDR_ANY) {
+ ConfigInfo->igc_gw[numberOfGateways++] = addressValue;
+ }
+ }
+ else {
+ PWCHAR stringList[2];
+
+ stringList[0] = addressString;
+ stringList[1] = TempAdapterName;
+
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_INVALID_DEFAULT_GATEWAY,
+ 1,
+ 2,
+ stringList,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP: Invalid default gateway address %ws specified for adapter %ws.\n"
+ " Remote networks may not be reachable as a result.\n",
+ addressString,
+ TempAdapterName
+ ));
+ }
+
+ //
+ // Walk over the entry we just processed.
+ //
+ while (*addressString++ != UNICODE_NULL);
+ }
+ }
+ else {
+ TCPTRACE((
+ "IP: Unable to read DefaultGateway value for adapter %ws.\n"
+ " Initialization will continue.\n",
+ TempAdapterName
+ ));
+ }
+
+ ConfigInfo->igc_numgws = numberOfGateways;
+ }
+
+ //
+ // Are we using zeros broadcasts?
+ //
+ status = GetRegDWORDValue(
+ Handle,
+ L"UseZeroBroadcast",
+ &(ConfigInfo->igc_zerobcast)
+ );
+
+ if (!NT_SUCCESS(status)) {
+ TCPTRACE((
+ "IP: Unable to read UseZeroBroadcast value for adapter %ws.\n"
+ " All-nets broadcasts will be addressed to 255.255.255.255.\n",
+ TempAdapterName
+ ));
+ ConfigInfo->igc_zerobcast = FALSE; // default to off
+ }
+
+ //
+ // Has anyone specified an MTU?
+ //
+ status = GetRegDWORDValue(
+ Handle,
+ L"MTU",
+ &(ConfigInfo->igc_mtu)
+ );
+
+ if (!NT_SUCCESS(status)) {
+ ConfigInfo->igc_mtu = 0xFFFFFFF; // The stack will pick one.
+ }
+
+ //
+ // Have we been configured for more routing packets?
+ //
+ status = GetRegDWORDValue(
+ Handle,
+ L"MaxForwardPending",
+ &(ConfigInfo->igc_maxpending)
+ );
+
+ if (!NT_SUCCESS(status)) {
+ ConfigInfo->igc_maxpending = DEFAULT_MAX_PENDING;
+ }
+ //
+ // Has Router Discovery been configured?
+ //
+
+ status = GetRegDWORDValue(
+ Handle,
+ L"PerformRouterDiscovery",
+ &(ConfigInfo->igc_rtrdiscovery)
+ );
+
+ if (!NT_SUCCESS(status)) {
+ ConfigInfo->igc_rtrdiscovery = 1;
+ }
+
+ //
+ // [BUGBUG] Only for 4.0 sp2 Turn off ICMP rtr discovery.
+ //
+ ConfigInfo->igc_rtrdiscovery = 0;
+
+ //
+ // Has Router Discovery Address been configured?
+ //
+
+ status = GetRegDWORDValue(
+ Handle,
+ L"SolicitationAddressBCast",
+ &ulTemp
+ );
+
+ if (!NT_SUCCESS(status)) {
+ ConfigInfo->igc_rtrdiscaddr = ALL_ROUTER_MCAST;
+ } else {
+ if (ulTemp == 1) {
+ ConfigInfo->igc_rtrdiscaddr = 0xffffffff;
+ } else {
+ ConfigInfo->igc_rtrdiscaddr = ALL_ROUTER_MCAST;
+ }
+ }
+
+ return TRUE;
+}
+
+
+int
+IsLLInterfaceValueNull(
+ NDIS_HANDLE Handle
+ )
+/*++
+
+ Routine Description:
+
+ Called to see if the LLInterface value in the registry key for which the
+ handle is provided, is NULL or not.
+
+ Arguments:
+ Handle - Handle to use for reading config.
+
+ Return Value:
+
+ FALSE if value is not null
+ TRUE if it is null
+
+--*/
+{
+ UNICODE_STRING valueString ;
+ ULONG valueType ;
+ NTSTATUS status ;
+
+
+ PAGED_CODE();
+
+ valueString.MaximumLength = 200 ;
+ valueString.Buffer = CTEAllocMem(valueString.MaximumLength) ;
+
+ status = GetRegSZValue(
+ Handle,
+ L"LLInterface",
+ &valueString,
+ &valueType
+ );
+
+ if (NT_SUCCESS(status) && (*(valueString.Buffer) != UNICODE_NULL)) {
+ CTEFreeMem (valueString.Buffer) ;
+ return FALSE ;
+ } else {
+ CTEFreeMem (valueString.Buffer) ;
+ return TRUE ;
+ }
+}
+
+
+IFAddrList *
+GetIFAddrList(
+ UINT *NumAddr,
+ NDIS_HANDLE Handle
+ )
+/*++
+
+ Routine Description:
+
+ Called to read the list of IF addresses and masks for an interface.
+ We'll get the address pointer first, then walk the list counting
+ to find out how many addresses we have. Then we allocate memory for the
+ list, and walk down the list converting them. After that we'll get
+ the mask list and convert it.
+
+ Arguments:
+ NumAddr - Where to return number of address we have.
+ Handle - Handle to use for reading config.
+
+ Return Value:
+
+ Pointer to IF address list if we get one, or NULL otherwise.
+
+--*/
+{
+ UNICODE_STRING ValueString;
+ NTSTATUS Status;
+ UINT AddressCount = 0;
+ UINT GoodAddresses = 0;
+ PWCHAR CurrentAddress;
+ PWCHAR CurrentMask;
+ PWCHAR AddressString;
+ PWCHAR MaskString;
+ IFAddrList *AddressList;
+ UINT i;
+ BOOLEAN ConversionStatus;
+ IPAddr AddressValue;
+ IPAddr MaskValue;
+ UCHAR TempBuffer[WORK_BUFFER_SIZE];
+
+
+ PAGED_CODE();
+
+ ValueString.Length = 0;
+ ValueString.MaximumLength = WORK_BUFFER_SIZE;
+ ValueString.Buffer = (PWCHAR)CTEAllocMem(WORK_BUFFER_SIZE);
+
+ if (ValueString.Buffer == NULL) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_NO_ADAPTER_RESOURCES,
+ 2,
+ 1,
+ &TempAdapterName,
+ 0,
+ NULL
+ );
+
+ TCPTRACE(("IP: Unable to allocate memory for IP address list WB\n"));
+ return NULL;
+ }
+
+ // First, try to read the IpAddress string.
+
+ Status = GetRegMultiSZValue(
+ Handle,
+ L"IpAddress",
+ &ValueString
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_NO_ADDRESS_LIST,
+ 1,
+ 1,
+ &TempAdapterName,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP: Unable to read the IP address list for adapter %ws.\n"
+ " IP will not be operational on this adapter\n",
+ TempAdapterName
+ ));
+ ExFreePool(ValueString.Buffer);
+ return NULL;
+ }
+
+ AddressString = ExAllocatePool(NonPagedPool, ValueString.MaximumLength);
+
+ if (AddressString == NULL) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_NO_ADAPTER_RESOURCES,
+ 2,
+ 1,
+ &TempAdapterName,
+ 0,
+ NULL
+ );
+
+ TCPTRACE(("IP: Unable to allocate memory for IP address list\n"));
+ ExFreePool(ValueString.Buffer);
+ return NULL;
+ }
+
+ RtlCopyMemory(AddressString, ValueString.Buffer, ValueString.MaximumLength);
+
+ Status = GetRegMultiSZValue(
+ Handle,
+ L"Subnetmask",
+ &ValueString
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_NO_MASK_LIST,
+ 1,
+ 1,
+ &TempAdapterName,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP: Unable to read the subnet mask list for adapter %ws.\n"
+ " IP will not be operational on this adapter.\n",
+ TempAdapterName
+ ));
+
+ ExFreePool(AddressString);
+ ExFreePool(ValueString.Buffer);
+ return NULL;
+ }
+
+ MaskString = ExAllocatePool(NonPagedPool, ValueString.MaximumLength);
+
+ if (MaskString == NULL) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_NO_ADAPTER_RESOURCES,
+ 3,
+ 1,
+ &TempAdapterName,
+ 0,
+ NULL
+ );
+
+ TCPTRACE(("IP: Unable to allocate memory for subnet mask list\n"));
+ ExFreePool(AddressString);
+ ExFreePool(ValueString.Buffer);
+ return NULL;
+ }
+
+ RtlCopyMemory(MaskString, ValueString.Buffer, ValueString.MaximumLength);
+
+
+ CurrentAddress = AddressString;
+ CurrentMask = MaskString;
+
+ while (*CurrentAddress != UNICODE_NULL &&
+ *CurrentMask != UNICODE_NULL) {
+
+ // We have a potential IP address.
+
+ AddressCount++;
+
+ // Skip this one.
+ while (*CurrentAddress++ != UNICODE_NULL);
+ while (*CurrentMask++ != UNICODE_NULL);
+ }
+
+ if (AddressCount == 0) {
+
+ ExFreePool(AddressString);
+ ExFreePool(MaskString);
+ ExFreePool(ValueString.Buffer);
+ return NULL;
+ }
+
+ // Allocate memory.
+ AddressList = CTEAllocMem(sizeof(IFAddrList) * AddressCount);
+
+ if (AddressList == NULL) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_NO_ADAPTER_RESOURCES,
+ 2,
+ 1,
+ &TempAdapterName,
+ 0,
+ NULL
+ );
+
+ TCPTRACE(("IP: Unable to allocate memory for IP address list\n"));
+ ExFreePool(AddressString);
+ ExFreePool(MaskString);
+ ExFreePool(ValueString.Buffer);
+ return NULL;
+ }
+
+ // Walk the list again, converting each address.
+
+ CurrentAddress = AddressString;
+ CurrentMask = MaskString;
+
+ for (i = 0; i < AddressCount; i++) {
+ ConversionStatus = IPConvertStringToAddress(
+ CurrentAddress,
+ &AddressValue
+ );
+
+ if (!ConversionStatus || (AddressValue == 0xFFFFFFFF)) {
+ PWCHAR stringList[2];
+
+ stringList[0] = CurrentAddress;
+ stringList[1] = TempAdapterName;
+
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_INVALID_ADDRESS,
+ 1,
+ 2,
+ stringList,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP: Invalid IP address %ws specified for adapter %ws.\n"
+ " This interface will not be initialized.\n",
+ CurrentAddress,
+ TempAdapterName
+ ));
+
+ goto nextone;
+
+ }
+
+ // Now do the current mask.
+
+ ConversionStatus = IPConvertStringToAddress(
+ CurrentMask,
+ &MaskValue
+ );
+
+ if (!ConversionStatus) {
+ PWCHAR stringList[3];
+
+ stringList[0] = CurrentMask;
+ stringList[1] = CurrentAddress;
+ stringList[2] = TempAdapterName;
+
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_INVALID_MASK,
+ 1,
+ 3,
+ stringList,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP: Invalid subnet Mask %ws specified for IP address %ws "
+ "on adapter %ws\n"
+ " This interface will not be initialized\n",
+ CurrentMask,
+ CurrentAddress,
+ TempAdapterName
+ ));
+ } else {
+ AddressList[GoodAddresses].ial_addr = AddressValue;
+ AddressList[GoodAddresses].ial_mask = MaskValue;
+ GoodAddresses++;
+ }
+
+nextone:
+ while(*CurrentAddress++ != UNICODE_NULL);
+ while(*CurrentMask++ != UNICODE_NULL);
+
+ }
+
+ ExFreePool(AddressString);
+ ExFreePool(MaskString);
+ ExFreePool(ValueString.Buffer);
+
+ *NumAddr = GoodAddresses;
+
+ if (GoodAddresses == 0) {
+ ExFreePool(AddressList);
+ AddressList = NULL;
+ }
+
+ return AddressList;
+}
+
+#endif // PNP_POWER
+
+
+UINT
+OpenIFConfig(
+ PNDIS_STRING ConfigName,
+ NDIS_HANDLE *Handle
+ )
+
+/*++
+
+ Routine Description:
+
+ Called when we want to open our per-info config info. We do so if we can,
+ otherwise we fail the request.
+
+ Arguments:
+ ConfigName - Name of interface to open.
+ Handle - Where to return the handle.
+
+ Return Value:
+ TRUE if we succeed, FALSE if we don't.
+
+
+--*/
+
+{
+ NTSTATUS status;
+ HANDLE myRegKey;
+ UNICODE_STRING valueString;
+ WCHAR ServicesRegistryKey[] =
+ L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
+ UINT RetStatus = FALSE;
+
+
+ PAGED_CODE();
+
+ TempAdapterName = ConfigName->Buffer;
+
+ //
+ // Get the size of the ConfigName string the easy way.
+ //
+ RtlInitUnicodeString(&valueString, (PWCHAR)ConfigName->Buffer);
+
+ valueString.MaximumLength += sizeof(ServicesRegistryKey);
+
+ valueString.Buffer = ExAllocatePool(
+ NonPagedPool,
+ valueString.MaximumLength
+ );
+
+ if (valueString.Buffer == NULL) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_NO_ADAPTER_RESOURCES,
+ 4,
+ 1,
+ &ConfigName->Buffer,
+ 0,
+ NULL
+ );
+
+ TCPTRACE(("IP: Unable to allocate memory for reg key name\n"));
+
+ return(FALSE);
+ }
+
+ valueString.Length = 0;
+ valueString.Buffer[0] = UNICODE_NULL;
+
+ //
+ // Build the key name for the tcpip parameters section and open key.
+ //
+ status = RtlAppendUnicodeToString(&valueString, ServicesRegistryKey);
+
+ if (!NT_SUCCESS(status)) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_ADAPTER_REG_FAILURE,
+ 1,
+ 1,
+ &ConfigName->Buffer,
+ 0,
+ NULL
+ );
+
+ TCPTRACE(("IP: Unable to append services name to key string\n"));
+
+ goto done;
+ }
+
+ status = RtlAppendUnicodeToString(&valueString, ConfigName->Buffer);
+
+ if (!NT_SUCCESS(status)) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_ADAPTER_REG_FAILURE,
+ 2,
+ 1,
+ &ConfigName->Buffer,
+ 0,
+ NULL
+ );
+
+ TCPTRACE(("IP: Unable to append adapter name to key string\n"));
+
+ goto done;
+ }
+
+ status = OpenRegKey(&myRegKey, valueString.Buffer);
+
+ if (!NT_SUCCESS(status)) {
+ CTELogEvent(
+ IPDriverObject,
+ EVENT_TCPIP_ADAPTER_REG_FAILURE,
+ 4,
+ 1,
+ &ConfigName->Buffer,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "IP: Unable to open adapter registry key %ws\n",
+ valueString.Buffer
+ ));
+
+ } else {
+ RetStatus = TRUE;
+ *Handle = myRegKey;
+ }
+
+done:
+ ExFreePool(valueString.Buffer);
+
+ return RetStatus;
+}
+
+
+VOID
+CloseIFConfig(
+ NDIS_HANDLE Handle
+ )
+
+/*++
+
+ Routine Description:
+
+ Close a per-interface config handle opened via OpenIFConfig().
+
+ Arguments:
+ Handle - Handle to be closed.
+
+ Return Value:
+
+
+--*/
+
+{
+ PAGED_CODE();
+
+ ZwClose(Handle);
+}
+
+
+IPConfigInfo *
+IPGetConfig(
+ void
+ )
+
+/*++
+
+Routine Description:
+
+ Provides IP configuration information for the NT environment.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ A pointer to a structure containing the configuration information.
+
+--*/
+
+{
+ return(IPConfiguration);
+}
+
+
+void
+IPFreeConfig(
+ IPConfigInfo *ConfigInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Frees the IP configuration structure allocated by IPGetConfig.
+
+Arguments:
+
+ ConfigInfo - Pointer to the IP configuration information structure to free.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ int i;
+
+#ifndef _PNP_POWER
+
+ NetConfigInfo *netConfiguration;
+
+
+ if (IPConfiguration != NULL) {
+ for (i = 0; i < IPConfiguration->ici_numnets; i++ ) {
+ netConfiguration = &(IPConfiguration->ici_netinfo[i]);
+
+ if (netConfiguration->nci_driver.Buffer != NULL) {
+ CTEFreeString(&(netConfiguration->nci_driver));
+ }
+
+ if (netConfiguration->nci_configname.Buffer != NULL) {
+ CTEFreeString(&(netConfiguration->nci_configname));
+ }
+
+ if (netConfiguration->nci_reghandle != NULL) {
+ ZwClose(netConfiguration->nci_reghandle);
+ }
+ }
+
+ CTEFreeMem(IPConfiguration->ici_netinfo);
+ CTEFreeMem(IPConfiguration);
+ }
+
+#else // _PNP_POWER
+
+ if (IPConfiguration != NULL) {
+ CTEFreeMem(IPConfiguration);
+ }
+
+#endif // _PNP_POWER
+
+ IPConfiguration = NULL;
+
+ return;
+}
+
+ulong
+GetGMTDelta(
+ void
+ )
+
+/*++
+
+Routine Description:
+
+ Returns the offset in milliseconds of the time zone of this machine
+ from GMT.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Time in milliseconds between this time zone and GMT.
+
+--*/
+
+{
+ LARGE_INTEGER localTime, systemTime;
+
+ //
+ // Get time zone bias in 100ns.
+ //
+ localTime.LowPart = 0;
+ localTime.HighPart = 0;
+ ExLocalTimeToSystemTime(&localTime, &systemTime);
+
+ if ((localTime.LowPart != 0) || (localTime.HighPart != 0)) {
+ localTime = CTEConvert100nsToMilliseconds(systemTime);
+ }
+
+ ASSERT(localTime.HighPart == 0);
+
+ return(localTime.LowPart);
+}
+
+
+ulong
+GetTime(
+ void
+ )
+
+/*++
+
+Routine Description:
+
+ Returns the time in milliseconds since midnight.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Time in milliseconds since midnight.
+
+--*/
+
+{
+ LARGE_INTEGER ntTime;
+ TIME_FIELDS breakdownTime;
+ ulong returnValue;
+
+ KeQuerySystemTime(&ntTime);
+ RtlTimeToTimeFields(&ntTime, &breakdownTime);
+
+ returnValue = breakdownTime.Hour * 60;
+ returnValue = (returnValue + breakdownTime.Minute) * 60;
+ returnValue = (returnValue + breakdownTime.Second) * 1000;
+ returnValue = returnValue + breakdownTime.Milliseconds;
+
+ return(returnValue);
+}
+
+
+ulong
+GetUnique32BitValue(
+ void
+ )
+
+/*++
+
+Routine Description:
+
+ Returns a reasonably unique 32-bit number based on the system clock.
+ In NT, we take the current system time, convert it to milliseconds,
+ and return the low 32 bits.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A reasonably unique 32-bit value.
+
+--*/
+
+{
+ LARGE_INTEGER ntTime, tmpTime;
+
+ KeQuerySystemTime(&ntTime);
+
+ tmpTime = CTEConvert100nsToMilliseconds(ntTime);
+
+ return(tmpTime.LowPart);
+}
+
+
+uint
+UseEtherSNAP(
+ PNDIS_STRING Name
+ )
+
+/*++
+
+Routine Description:
+
+ Determines whether the EtherSNAP protocol should be used on an interface.
+
+Arguments:
+
+ Name - The device name of the interface in question.
+
+Return Value:
+
+ Nonzero if SNAP is to be used on the interface. Zero otherwise.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(Name);
+
+ //
+ // We currently set this on a global basis.
+ //
+ return(ArpUseEtherSnap);
+}
+
+
+void
+GetAlwaysSourceRoute(
+ uint *pArpAlwaysSourceRoute,
+ uint *pIPAlwaysSourceRoute
+ )
+
+/*++
+
+Routine Description:
+
+ Determines whether ARP should always turn on source routing in queries.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Nonzero if source routing is always to be used. Zero otherwise.
+
+--*/
+
+{
+ //
+ // We currently set this on a global basis.
+ //
+ *pArpAlwaysSourceRoute = ArpAlwaysSourceRoute;
+ *pIPAlwaysSourceRoute = IPAlwaysSourceRoute;
+ return;
+}
+
+
+uint
+GetArpCacheLife(
+ void
+ )
+
+/*++
+
+Routine Description:
+
+ Get ArpCacheLife in seconds.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Set to default if not found.
+
+--*/
+
+{
+ //
+ // We currently set this on a global basis.
+ //
+ return(ArpCacheLife);
+}
+
+
+#define IP_ADDRESS_STRING_LENGTH (16+2) // +2 for double NULL on MULTI_SZ
+
+
+BOOLEAN
+IPConvertStringToAddress(
+ IN PWCHAR AddressString,
+ OUT PULONG IpAddress
+ )
+
+/*++
+
+Routine Description
+
+ This function converts an Internet standard 4-octet dotted decimal
+ IP address string into a numeric IP address. Unlike inet_addr(), this
+ routine does not support address strings of less than 4 octets nor does
+ it support octal and hexadecimal octets.
+
+Arguments
+
+ AddressString - IP address in dotted decimal notation
+ IpAddress - Pointer to a variable to hold the resulting address
+
+Return Value:
+
+ TRUE if the address string was converted. FALSE otherwise.
+
+--*/
+
+{
+ UNICODE_STRING unicodeString;
+ STRING aString;
+ UCHAR dataBuffer[IP_ADDRESS_STRING_LENGTH];
+ NTSTATUS status;
+ PUCHAR addressPtr, cp, startPointer, endPointer;
+ ULONG digit, multiplier;
+ int i;
+
+
+ PAGED_CODE();
+
+ aString.Length = 0;
+ aString.MaximumLength = IP_ADDRESS_STRING_LENGTH;
+ aString.Buffer = dataBuffer;
+
+ RtlInitUnicodeString(&unicodeString, AddressString);
+
+ status = RtlUnicodeStringToAnsiString(
+ &aString,
+ &unicodeString,
+ FALSE
+ );
+
+ if (!NT_SUCCESS(status)) {
+ return(FALSE);
+ }
+
+ *IpAddress = 0;
+ addressPtr = (PUCHAR) IpAddress;
+ startPointer = dataBuffer;
+ endPointer = dataBuffer;
+ i = 3;
+
+ while (i >= 0) {
+ //
+ // Collect the characters up to a '.' or the end of the string.
+ //
+ while ((*endPointer != '.') && (*endPointer != '\0')) {
+ endPointer++;
+ }
+
+ if (startPointer == endPointer) {
+ return(FALSE);
+ }
+
+ //
+ // Convert the number.
+ //
+
+ for ( cp = (endPointer - 1), multiplier = 1, digit = 0;
+ cp >= startPointer;
+ cp--, multiplier *= 10
+ ) {
+
+ if ((*cp < '0') || (*cp > '9') || (multiplier > 100)) {
+ return(FALSE);
+ }
+
+ digit += (multiplier * ((ULONG) (*cp - '0')));
+ }
+
+ if (digit > 255) {
+ return(FALSE);
+ }
+
+ addressPtr[i] = (UCHAR) digit;
+
+ //
+ // We are finished if we have found and converted 4 octets and have
+ // no other characters left in the string.
+ //
+ if ( (i-- == 0) &&
+ ((*endPointer == '\0') || (*endPointer == ' '))
+ ) {
+ return(TRUE);
+ }
+
+ if (*endPointer == '\0') {
+ return(FALSE);
+ }
+
+ startPointer = ++endPointer;
+ }
+
+ return(FALSE);
+}
+
+
+ULONG
+RouteMatch(
+ IN WCHAR *RouteString,
+ IN IPAddr Address,
+ IN IPMask Mask,
+ OUT IPAddr *DestVal,
+ OUT IPMask *DestMask,
+ OUT IPAddr *GateVal,
+ OUT ULONG *Metric
+ )
+
+/*++
+
+Routine Description
+
+ This function checks if a perisitent route should be assigned to
+ a given interface based on the interface address & mask.
+
+Arguments
+
+ RouteString - A NULL-terminated route laid out as Dest,Mask,Gate.
+ Address - The IP address of the interface being processed.
+ Mask - The subnet mask of the interface being processed.
+ DestVal - A pointer to the decoded destination IP address.
+ DestVal - A pointer to the decoded destination subnet mask.
+ DestVal - A pointer to the decoded destination first hop gateway.
+ Metric - A pointer to the decoded route metric.
+
+Return Value:
+
+ The route type, IRE_TYPE_DIRECT or IRE_TYPE_INDIRECT, if the route
+ should be added to the interface, IRE_TYPE_INVALID otherwise.
+
+--*/
+
+{
+#define ROUTE_SEPARATOR L','
+
+ WCHAR *labelPtr;
+ WCHAR *indexPtr = RouteString;
+ ULONG i;
+ UNICODE_STRING ustring;
+ NTSTATUS status;
+ BOOLEAN noMetric = FALSE;
+
+
+ PAGED_CODE();
+
+ //
+ // The route is laid out in the string as "Dest,Mask,Gateway,Metric".
+ // The metric may not be there if this system was upgraded from
+ // NT 3.51.
+ //
+ // Parse the string and convert each label.
+ //
+
+ for (i=0; i<4; i++) {
+
+ labelPtr = indexPtr;
+
+ while (1) {
+
+ if (*indexPtr == UNICODE_NULL) {
+ if ((i < 2) || (indexPtr == labelPtr)) {
+ return(IRE_TYPE_INVALID);
+ }
+
+ if (i == 2) {
+ //
+ // Old route - no metric.
+ //
+ noMetric = TRUE;
+ }
+
+ break;
+ }
+
+ if (*indexPtr == ROUTE_SEPARATOR) {
+ *indexPtr = UNICODE_NULL;
+ break;
+ }
+
+ indexPtr++;
+ }
+
+ switch(i) {
+ case 0:
+ if (!IPConvertStringToAddress(labelPtr, DestVal)) {
+ return(IRE_TYPE_INVALID);
+ }
+ break;
+
+ case 1:
+ if (!IPConvertStringToAddress(labelPtr, DestMask)) {
+ return(IRE_TYPE_INVALID);
+ }
+ break;
+
+ case 2:
+ if (!IPConvertStringToAddress(labelPtr, GateVal)) {
+ return(IRE_TYPE_INVALID);
+ }
+ break;
+
+ case 3:
+ RtlInitUnicodeString(&ustring, labelPtr);
+
+ status = RtlUnicodeStringToInteger(
+ &ustring,
+ 0,
+ Metric
+ );
+
+ if (!NT_SUCCESS(status)) {
+ return(IRE_TYPE_INVALID);
+ }
+
+ break;
+
+ default:
+ ASSERT(0);
+ return(IRE_TYPE_INVALID);
+ }
+
+ if (noMetric) {
+ //
+ // Default to 1.
+ //
+ *Metric = 1;
+ break;
+ }
+
+ indexPtr++;
+ }
+
+ if (IP_ADDR_EQUAL(*GateVal, Address)) {
+ return(IRE_TYPE_DIRECT);
+ }
+
+ if ( IP_ADDR_EQUAL((*GateVal & Mask), (Address & Mask)) ) {
+ return(IRE_TYPE_INDIRECT);
+ }
+
+ return(IRE_TYPE_INVALID);
+}
+
+ULONG
+GetCurrentRouteTable(
+ IPRouteEntry **ppRouteTable
+ )
+/*++
+ Routine Description
+ Allocates memory from non paged pool and fills it with the current route table
+ The caller must free the memory to non-paged pool
+
+ Arguments
+ ppRouteTable Pointer to pointer to array of routes
+
+ Return Value:
+ Count of routes in the table. If memory is allocated, *ppRouteTable will be non NULL
+
+--*/
+{
+ ULONG ulTableCount,ulRouteCount;
+ uint uiValid,uiDataLeft;
+ IPRouteEntry routeEntry;
+ CTELockHandle Handle;
+ UCHAR ucContext[CONTEXT_SIZE];
+
+#define ROUTE_TABLE_OVERFLOW 20 // This MUST NOT be zero
+
+ ulTableCount = IPSInfo.ipsi_numroutes + ROUTE_TABLE_OVERFLOW;
+
+ *ppRouteTable = ExAllocatePoolWithTag(NonPagedPool,
+ ulTableCount * sizeof(IPRouteEntry),
+ 'pI');
+ ulRouteCount = 0;
+
+ if(*ppRouteTable == NULL)
+ {
+ TCPTRACE(("IP: Couldnt allocate memory for route table\n"));
+ }
+ else
+ {
+ CTEGetLock(&RouteTableLock, &Handle);
+
+ RtlZeroMemory((PVOID)ucContext,CONTEXT_SIZE);
+
+ uiDataLeft = RTValidateContext((PVOID)ucContext, &uiValid);
+
+ if(!uiValid)
+ {
+ CTEFreeLock(&RouteTableLock, Handle);
+ }
+ else
+ {
+ while(uiDataLeft)
+ {
+ if(ulRouteCount < ulTableCount)
+ {
+ uiDataLeft = RTReadNext((PVOID)ucContext, &routeEntry);
+
+ (*ppRouteTable)[ulRouteCount++] = routeEntry;
+ }
+ else
+ {
+ TCPTRACE(("IP: Couldnt read out all routes. Increase ROUTE_TABLE_OVERFLOW\n"));
+ }
+ }
+
+ CTEFreeLock(&RouteTableLock, Handle);
+ }
+ }
+
+ return ulRouteCount;
+}
+
+
+VOID
+SetPersistentRoutesForNTE(
+ IPAddr Address,
+ IPMask Mask,
+ ULONG IFIndex
+ )
+
+/*++
+
+Routine Description
+
+ Adds persistent routes that match an interface. The routes are read
+ from a list in the registry.
+
+Arguments
+
+ Address - The address of the new interface
+ Mask - The subnet mask of the new interface.
+ IFIndex - The index of the new interface.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+#define ROUTE_DATA_STRING_SIZE (51 * sizeof(WCHAR))
+#define BASIC_INFO_SIZE ( sizeof(KEY_VALUE_BASIC_INFORMATION) - \
+ sizeof(WCHAR) + ROUTE_DATA_STRING_SIZE )
+ IPAddr destVal;
+ IPMask destMask;
+ IPAddr gateVal;
+ ULONG metric;
+ ULONG enumIndex = 0;
+ UCHAR workbuf[BASIC_INFO_SIZE];
+ PKEY_VALUE_BASIC_INFORMATION basicInfo =
+ (PKEY_VALUE_BASIC_INFORMATION) workbuf;
+ ULONG resultLength;
+ HANDLE regKey;
+ WCHAR IPRoutesRegistryKey[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Parameters\\PersistentRoutes";
+ TDIObjectID id;
+ IPRouteEntry routeEntry,*pRouteTable;
+ ULONG ulRouteCount,i;
+ NTSTATUS status;
+
+ PAGED_CODE();
+
+ pRouteTable = NULL;
+
+ ulRouteCount = GetCurrentRouteTable(&pRouteTable);
+
+ id.toi_entity.tei_entity = CL_NL_ENTITY;
+ id.toi_entity.tei_instance = 0;
+ id.toi_class = INFO_CLASS_PROTOCOL;
+ id.toi_type = INFO_TYPE_PROVIDER;
+ id.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
+
+ routeEntry.ire_index = IFIndex;
+ routeEntry.ire_metric2 = (ULONG) -1;
+ routeEntry.ire_metric3 = (ULONG) -1;
+ routeEntry.ire_metric4 = (ULONG) -1;
+ routeEntry.ire_proto = IRE_PROTO_LOCAL;
+ routeEntry.ire_age = 0;
+ routeEntry.ire_metric5 = (ULONG) -1;
+
+ status = OpenRegKey(&regKey, IPRoutesRegistryKey);
+
+ if (NT_SUCCESS(status)) {
+ ULONG type;
+
+ do {
+ status = ZwEnumerateValueKey(
+ regKey,
+ enumIndex,
+ KeyValueBasicInformation,
+ basicInfo,
+ BASIC_INFO_SIZE - sizeof(WCHAR),
+ &resultLength
+ );
+
+ if (!NT_SUCCESS(status)) {
+ if (status == STATUS_BUFFER_OVERFLOW) {
+ continue;
+ }
+
+ break;
+ }
+
+ if (basicInfo->Type != REG_SZ) {
+ continue;
+ }
+
+ //
+ // Ensure NULL termination
+ //
+ basicInfo->Name[basicInfo->NameLength/sizeof(WCHAR)] = UNICODE_NULL;
+ basicInfo->NameLength += sizeof(WCHAR);
+
+ type = RouteMatch(
+ basicInfo->Name,
+ Address,
+ Mask,
+ &destVal,
+ &destMask,
+ &gateVal,
+ &metric
+ );
+
+ if (type != IRE_TYPE_INVALID)
+ {
+ long setStatus;
+ ULONG ulFound;
+
+ routeEntry.ire_dest = net_long(destVal),
+ routeEntry.ire_mask = net_long(destMask),
+ routeEntry.ire_nexthop = net_long(gateVal);
+ routeEntry.ire_type = type;
+ routeEntry.ire_metric1 = metric;
+
+ ulFound = FALSE;
+
+ for(i = 0; i < ulRouteCount; i++)
+ {
+ if((routeEntry.ire_dest == pRouteTable[i].ire_dest) &&
+ (routeEntry.ire_mask == pRouteTable[i].ire_mask))
+ {
+ ulFound = TRUE;
+
+ break;
+ }
+ }
+
+ if(!ulFound)
+ {
+
+ setStatus = IPSetInfo(
+ &id,
+ &routeEntry,
+ sizeof(IPRouteEntry)
+ );
+#if DBG
+ if (setStatus != IP_SUCCESS)
+ {
+ TCPTRACE((
+ "IP: set of sticky route [%x, %x, %x] failed, status %d\n",
+ destVal,
+ destMask,
+ gateVal,
+ metric,
+ setStatus
+ ));
+ }
+#endif // DBG
+ }
+
+ }
+
+ } while (++enumIndex);
+
+ ZwClose(regKey);
+ }
+
+ if(pRouteTable)
+ {
+ ExFreePool(pRouteTable);
+ }
+}
+
diff --git a/private/ntos/tdi/tcpip/ip/ntirp.c b/private/ntos/tdi/tcpip/ip/ntirp.c
new file mode 100644
index 000000000..3dd34565b
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/ntirp.c
@@ -0,0 +1,1458 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ntirp.c
+
+Abstract:
+
+ NT specific routines for dispatching and handling IRPs.
+
+Author:
+
+ Mike Massa (mikemas) Aug 13, 1993
+
+Revision History:
+
+ Who When What
+ -------- -------- ----------------------------------------------
+ mikemas 08-13-93 created
+
+Notes:
+
+--*/
+
+#include <oscfg.h>
+#include <ndis.h>
+#include <cxport.h>
+#include <ip.h>
+#include "ipdef.h"
+#include "ipinit.h"
+#include "icmp.h"
+#include <ntddip.h>
+#include <llipif.h>
+#include <ipfilter.h>
+
+
+//
+// Local structures.
+//
+typedef struct pending_irp {
+ LIST_ENTRY Linkage;
+ PIRP Irp;
+ PFILE_OBJECT FileObject;
+ PVOID Context;
+} PENDING_IRP, *PPENDING_IRP;
+
+
+//
+// Global variables
+//
+LIST_ENTRY PendingEchoList;
+LIST_ENTRY PendingIPSetNTEAddrList;
+
+
+//
+// External prototypes
+//
+IP_STATUS
+ICMPEchoRequest(
+ void *InputBuffer,
+ uint InputBufferLength,
+ EchoControl *ControlBlock,
+ EchoRtn Callback
+ );
+
+ulong
+ICMPEchoComplete(
+ EchoControl *ControlBlock,
+ IP_STATUS Status,
+ void *Data,
+ uint DataSize,
+ struct IPOptInfo *OptionInfo
+ );
+
+IP_STATUS
+IPSetNTEAddr(
+ uint Index,
+ IPAddr Addr,
+ IPMask Mask,
+ SetAddrControl *ControlBlock,
+ SetAddrRtn Callback
+ );
+
+uint
+IPAddDynamicNTE(
+ ushort InterfaceContext,
+ IPAddr NewAddr,
+ IPMask NewMask,
+ ushort *NTEContext,
+ ulong *NTEInstance
+ );
+
+uint
+IPDeleteDynamicNTE(
+ ushort NTEContext
+ );
+
+uint
+IPGetNTEInfo(
+ ushort NTEContext,
+ ulong *NTEInstance,
+ IPAddr *Address,
+ IPMask *SubnetMask,
+ ushort *NTEFlags
+ );
+
+uint
+SetDHCPNTE(
+ uint Context
+ );
+
+//
+// Local prototypes
+//
+NTSTATUS
+IPDispatch (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+IPDispatchDeviceControl(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+IPDispatchInternalDeviceControl(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+IPCreate(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+IPCleanup(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+IPClose(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+DispatchEchoRequest(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+void
+CompleteEchoRequest(
+ void *Context,
+ IP_STATUS Status,
+ void *Data,
+ uint DataSize,
+ struct IPOptInfo *OptionInfo
+ );
+
+NTSTATUS
+DispatchIPSetNTEAddrRequest(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+void
+CompleteIPSetNTEAddrRequest(
+ void *Context,
+ IP_STATUS Status
+ );
+
+
+#ifdef _PNP_POWER
+extern IP_STATUS IPAddInterface(PNDIS_STRING ConfigName, void *PNPContext, void *Context, LLIPRegRtn RegRtn, LLIPBindInfo *BindInfo) ;
+extern void IPDelInterface(void *Context) ;
+#endif
+
+
+//
+// All of this code is pageable.
+//
+#ifdef ALLOC_PRAGMA
+
+#pragma alloc_text(PAGE, IPDispatch)
+#pragma alloc_text(PAGE, IPDispatchDeviceControl)
+#pragma alloc_text(PAGE, IPDispatchInternalDeviceControl)
+#pragma alloc_text(PAGE, IPCreate)
+#pragma alloc_text(PAGE, IPClose)
+#pragma alloc_text(PAGE, DispatchEchoRequest)
+
+#endif // ALLOC_PRAGMA
+
+
+//
+// Dispatch function definitions
+//
+NTSTATUS
+IPDispatch (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the dispatch routine for IP.
+
+Arguments:
+
+ DeviceObject - Pointer to device object for target device
+ Irp - Pointer to I/O request packet
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+--*/
+
+{
+ PIO_STACK_LOCATION irpSp;
+ NTSTATUS status;
+
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+ PAGED_CODE();
+
+ irpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ switch (irpSp->MajorFunction) {
+
+ case IRP_MJ_DEVICE_CONTROL:
+ return IPDispatchDeviceControl(Irp, irpSp);
+
+ case IRP_MJ_INTERNAL_DEVICE_CONTROL:
+ return IPDispatchDeviceControl(Irp, irpSp);
+
+ case IRP_MJ_CREATE:
+ status = IPCreate(Irp, irpSp);
+ break;
+
+ case IRP_MJ_CLEANUP:
+ status = IPCleanup(Irp, irpSp);
+ break;
+
+ case IRP_MJ_CLOSE:
+ status = IPClose(Irp, irpSp);
+ break;
+
+ default:
+ CTEPrint("IPDispatch: Invalid major function ");
+ CTEPrintNum(irpSp->MajorFunction );
+ CTEPrintCRLF();
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ Irp->IoStatus.Status = status;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ return(status);
+
+} // IPDispatch
+
+
+NTSTATUS
+IPDispatchDeviceControl(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+--*/
+
+{
+ NTSTATUS status;
+ ULONG code;
+
+
+ PAGED_CODE();
+
+ Irp->IoStatus.Information = 0;
+
+ code = IrpSp->Parameters.DeviceIoControl.IoControlCode;
+
+ switch(code) {
+
+ case IOCTL_ICMP_ECHO_REQUEST:
+ return(DispatchEchoRequest(Irp, IrpSp));
+
+ case IOCTL_IP_SET_ADDRESS:
+ return(DispatchIPSetNTEAddrRequest(Irp, IrpSp));
+
+ case IOCTL_IP_ADD_NTE:
+ {
+ PIP_ADD_NTE_REQUEST request;
+ PIP_ADD_NTE_RESPONSE response;
+ BOOLEAN retval;
+
+
+ request = Irp->AssociatedIrp.SystemBuffer;
+ response = (PIP_ADD_NTE_RESPONSE) request;
+
+ //
+ // Validate input parameters
+ //
+ if ( (IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
+ sizeof(IP_ADD_NTE_REQUEST)
+ )
+ &&
+ (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >=
+ sizeof(IP_ADD_NTE_RESPONSE))
+
+ )
+ {
+ retval = IPAddDynamicNTE(
+ request->InterfaceContext,
+ request->Address,
+ request->SubnetMask,
+ &(response->Context),
+ &(response->Instance)
+ );
+
+ if (retval == FALSE) {
+ status = STATUS_UNSUCCESSFUL;
+ }
+ else {
+ Irp->IoStatus.Information = sizeof(IP_ADD_NTE_RESPONSE);
+ status = STATUS_SUCCESS;
+ }
+ }
+ else {
+ status = STATUS_INVALID_PARAMETER;
+ }
+ }
+ break;
+
+ case IOCTL_IP_DELETE_NTE:
+ {
+ PIP_DELETE_NTE_REQUEST request;
+ BOOLEAN retval;
+
+
+ request = Irp->AssociatedIrp.SystemBuffer;
+
+ //
+ // Validate input parameters
+ //
+ if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
+ sizeof(IP_DELETE_NTE_REQUEST)
+ )
+ {
+ retval = IPDeleteDynamicNTE(
+ request->Context
+ );
+
+ if (retval == FALSE) {
+ status = STATUS_UNSUCCESSFUL;
+ }
+ else {
+ status = STATUS_SUCCESS;
+ }
+ }
+ else {
+ status = STATUS_INVALID_PARAMETER;
+ }
+ }
+ break;
+
+ case IOCTL_IP_GET_NTE_INFO:
+ {
+ PIP_GET_NTE_INFO_REQUEST request;
+ PIP_GET_NTE_INFO_RESPONSE response;
+ BOOLEAN retval;
+ ushort nteFlags;
+
+
+ request = Irp->AssociatedIrp.SystemBuffer;
+ response = (PIP_GET_NTE_INFO_RESPONSE) request;
+
+ //
+ // Validate input parameters
+ //
+ if ( (IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
+ sizeof(IP_GET_NTE_INFO_REQUEST)
+ )
+ &&
+ (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >=
+ sizeof(IP_GET_NTE_INFO_RESPONSE))
+
+ )
+ {
+ retval = IPGetNTEInfo(
+ request->Context,
+ &(response->Instance),
+ &(response->Address),
+ &(response->SubnetMask),
+ &nteFlags
+ );
+
+ if (retval == FALSE) {
+ status = STATUS_UNSUCCESSFUL;
+ }
+ else {
+ status = STATUS_SUCCESS;
+ Irp->IoStatus.Information =
+ sizeof(IP_GET_NTE_INFO_RESPONSE);
+ response->Flags = 0;
+
+ if (nteFlags & NTE_DYNAMIC) {
+ response->Flags |= IP_NTE_DYNAMIC;
+ }
+ }
+ }
+ else {
+ status = STATUS_INVALID_PARAMETER;
+ }
+ }
+ break;
+
+ case IOCTL_IP_SET_DHCP_INTERFACE:
+ {
+ PIP_SET_DHCP_INTERFACE_REQUEST request;
+ BOOLEAN retval;
+
+ request = Irp->AssociatedIrp.SystemBuffer;
+ retval = SetDHCPNTE(
+ request->Context
+ );
+
+ if (retval == FALSE) {
+ status = STATUS_UNSUCCESSFUL;
+ }
+ else {
+ status = STATUS_SUCCESS;
+ }
+ }
+ break;
+
+ case IOCTL_IP_SET_IF_CONTEXT:
+ {
+ PIP_SET_IF_CONTEXT_INFO info;
+
+
+ info = Irp->AssociatedIrp.SystemBuffer;
+ status = (NTSTATUS) SetIFContext(info->Index, info->Context);
+
+ if (status != IP_SUCCESS) {
+ ASSERT(status != IP_PENDING);
+ //
+ // Map status
+ //
+ status = STATUS_UNSUCCESSFUL;
+ }
+ else {
+ status = STATUS_SUCCESS;
+ }
+ }
+ break;
+
+ case IOCTL_IP_SET_FILTER_POINTER:
+ {
+ PIP_SET_FILTER_HOOK_INFO info;
+
+ if (Irp->RequestorMode != KernelMode) {
+ status = STATUS_ACCESS_DENIED;
+ break;
+ }
+
+ info = Irp->AssociatedIrp.SystemBuffer;
+ status = (NTSTATUS) SetFilterPtr(info->FilterPtr);
+
+ if (status != IP_SUCCESS) {
+ ASSERT(status != IP_PENDING);
+ //
+ // Map status
+ //
+ status = STATUS_UNSUCCESSFUL;
+ }
+ else {
+ status = STATUS_SUCCESS;
+ }
+ }
+ break;
+
+ case IOCTL_IP_SET_MAP_ROUTE_POINTER:
+ {
+ PIP_SET_MAP_ROUTE_HOOK_INFO info;
+
+ if (Irp->RequestorMode != KernelMode) {
+ status = STATUS_ACCESS_DENIED;
+ break;
+ }
+
+ info = Irp->AssociatedIrp.SystemBuffer;
+ status = (NTSTATUS) SetMapRoutePtr(info->MapRoutePtr);
+
+ if (status != IP_SUCCESS) {
+ ASSERT(status != IP_PENDING);
+ //
+ // Map status
+ //
+ status = STATUS_UNSUCCESSFUL;
+ }
+ else {
+ status = STATUS_SUCCESS;
+ }
+ }
+ break;
+
+#ifdef _PNP_POWER
+
+ case IOCTL_IP_GET_PNP_ARP_POINTERS:
+ {
+ PIP_GET_PNP_ARP_POINTERS info = (PIP_GET_PNP_ARP_POINTERS) Irp->AssociatedIrp.SystemBuffer;
+
+ if (Irp->RequestorMode != KernelMode) {
+ status = STATUS_ACCESS_DENIED;
+ break;
+ }
+
+ info->IPAddInterface = (IPAddInterfacePtr)IPAddInterface ;
+ info->IPDelInterface = (IPDelInterfacePtr)IPDelInterface ;
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = sizeof(IP_GET_PNP_ARP_POINTERS);
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+ return STATUS_SUCCESS;;
+
+ }
+ break;
+#endif
+
+ default:
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ if (status != IP_PENDING) {
+ Irp->IoStatus.Status = status;
+ // Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+ }
+ return status;
+
+} // IPDispatchDeviceControl
+
+NTSTATUS
+IPDispatchInternalDeviceControl(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+--*/
+
+{
+ NTSTATUS status;
+
+
+ PAGED_CODE();
+
+ status = STATUS_SUCCESS;
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ return status;
+
+} // IPDispatchDeviceControl
+
+
+NTSTATUS
+IPCreate(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ return(STATUS_SUCCESS);
+
+} // IPCreate
+
+
+NTSTATUS
+IPCleanup(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+--*/
+
+{
+ PPENDING_IRP pendingIrp;
+ PLIST_ENTRY entry, nextEntry;
+ KIRQL oldIrql;
+ LIST_ENTRY completeList;
+ PIRP cancelledIrp;
+
+
+ InitializeListHead(&completeList);
+
+ //
+ // Collect all of the pending IRPs on this file object.
+ //
+ IoAcquireCancelSpinLock(&oldIrql);
+
+ entry = PendingEchoList.Flink;
+
+ while ( entry != &PendingEchoList ) {
+ pendingIrp = CONTAINING_RECORD(entry, PENDING_IRP, Linkage);
+
+ if (pendingIrp->FileObject == IrpSp->FileObject) {
+ nextEntry = entry->Flink;
+ RemoveEntryList(entry);
+ IoSetCancelRoutine(pendingIrp->Irp, NULL);
+ InsertTailList(&completeList, &(pendingIrp->Linkage));
+ entry = nextEntry;
+ }
+ else {
+ entry = entry->Flink;
+ }
+ }
+
+ IoReleaseCancelSpinLock(oldIrql);
+
+ //
+ // Complete them.
+ //
+ entry = completeList.Flink;
+
+ while ( entry != &completeList ) {
+ pendingIrp = CONTAINING_RECORD(entry, PENDING_IRP, Linkage);
+ cancelledIrp = pendingIrp->Irp;
+ entry = entry->Flink;
+
+ //
+ // Free the PENDING_IRP structure. The control block will be freed
+ // when the request completes.
+ //
+ CTEFreeMem(pendingIrp);
+
+ //
+ // Complete the IRP.
+ //
+ cancelledIrp->IoStatus.Information = 0;
+ cancelledIrp->IoStatus.Status = STATUS_CANCELLED;
+ IoCompleteRequest(cancelledIrp, IO_NETWORK_INCREMENT);
+ }
+
+ InitializeListHead(&completeList);
+
+ //
+ // Collect all of the pending IRPs on this file object.
+ //
+ IoAcquireCancelSpinLock(&oldIrql);
+
+ entry = PendingIPSetNTEAddrList.Flink;
+
+ while ( entry != &PendingIPSetNTEAddrList ) {
+ pendingIrp = CONTAINING_RECORD(entry, PENDING_IRP, Linkage);
+
+ if (pendingIrp->FileObject == IrpSp->FileObject) {
+ nextEntry = entry->Flink;
+ RemoveEntryList(entry);
+ IoSetCancelRoutine(pendingIrp->Irp, NULL);
+ InsertTailList(&completeList, &(pendingIrp->Linkage));
+ entry = nextEntry;
+ }
+ else {
+ entry = entry->Flink;
+ }
+ }
+
+ IoReleaseCancelSpinLock(oldIrql);
+
+ //
+ // Complete them.
+ //
+ entry = completeList.Flink;
+
+ while ( entry != &completeList ) {
+ pendingIrp = CONTAINING_RECORD(entry, PENDING_IRP, Linkage);
+ cancelledIrp = pendingIrp->Irp;
+ entry = entry->Flink;
+
+ //
+ // Free the PENDING_IRP structure. The control block will be freed
+ // when the request completes.
+ //
+ CTEFreeMem(pendingIrp);
+
+ //
+ // Complete the IRP.
+ //
+ cancelledIrp->IoStatus.Information = 0;
+ cancelledIrp->IoStatus.Status = STATUS_CANCELLED;
+ IoCompleteRequest(cancelledIrp, IO_NETWORK_INCREMENT);
+ }
+
+ return(STATUS_SUCCESS);
+
+} // IPCleanup
+
+
+NTSTATUS
+IPClose(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ return(STATUS_SUCCESS);
+
+} // IPClose
+
+
+//
+// ICMP Echo function definitions
+//
+VOID
+CancelEchoRequest(
+ IN PDEVICE_OBJECT Device,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ Cancels an outstanding Echo request Irp.
+
+Arguments:
+
+ Device - The device on which the request was issued.
+ Irp - Pointer to I/O request packet to cancel.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ This function is called with cancel spinlock held. It must be
+ released before the function returns.
+
+ The echo control block associated with this request cannot be
+ freed until the request completes. The completion routine will
+ free it.
+
+--*/
+
+{
+ PPENDING_IRP pendingIrp = NULL;
+ PPENDING_IRP item;
+ PLIST_ENTRY entry;
+
+
+ for ( entry = PendingEchoList.Flink;
+ entry != &PendingEchoList;
+ entry = entry->Flink
+ ) {
+ item = CONTAINING_RECORD(entry, PENDING_IRP, Linkage);
+ if (item->Irp == Irp) {
+ pendingIrp = item;
+ RemoveEntryList(entry);
+ IoSetCancelRoutine(pendingIrp->Irp, NULL);
+ break;
+ }
+ }
+
+ IoReleaseCancelSpinLock(Irp->CancelIrql);
+
+ if (pendingIrp != NULL) {
+ //
+ // Free the PENDING_IRP structure. The control block will be freed
+ // when the request completes.
+ //
+ CTEFreeMem(pendingIrp);
+
+ //
+ // Complete the IRP.
+ //
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+ }
+
+ return;
+
+} // CancelEchoRequest
+
+//
+// IP Set Addr function definitions
+//
+VOID
+CancelIPSetNTEAddrRequest(
+ IN PDEVICE_OBJECT Device,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ Cancels an outstanding IP Set Addr request Irp.
+
+Arguments:
+
+ Device - The device on which the request was issued.
+ Irp - Pointer to I/O request packet to cancel.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ This function is called with cancel spinlock held. It must be
+ released before the function returns.
+
+ The IP Set Addr control block associated with this request cannot be
+ freed until the request completes. The completion routine will
+ free it.
+
+--*/
+
+{
+ PPENDING_IRP pendingIrp = NULL;
+ PPENDING_IRP item;
+ PLIST_ENTRY entry;
+
+
+ for ( entry = PendingIPSetNTEAddrList.Flink;
+ entry != &PendingIPSetNTEAddrList;
+ entry = entry->Flink
+ ) {
+ item = CONTAINING_RECORD(entry, PENDING_IRP, Linkage);
+ if (item->Irp == Irp) {
+ pendingIrp = item;
+ RemoveEntryList(entry);
+ IoSetCancelRoutine(pendingIrp->Irp, NULL);
+ break;
+ }
+ }
+
+ IoReleaseCancelSpinLock(Irp->CancelIrql);
+
+ if (pendingIrp != NULL) {
+ //
+ // Free the PENDING_IRP structure. The control block will be freed
+ // when the request completes.
+ //
+ CTEFreeMem(pendingIrp);
+
+ //
+ // Complete the IRP.
+ //
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+ }
+
+ return;
+
+} // CancelIPSetNTEAddrRequest
+
+
+void
+CompleteEchoRequest(
+ void *Context,
+ IP_STATUS Status,
+ void *Data, OPTIONAL
+ uint DataSize,
+ struct IPOptInfo *OptionInfo OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ Handles the completion of an ICMP Echo request
+
+Arguments:
+
+ Context - Pointer to the EchoControl structure for this request.
+ Status - The IP status of the transmission.
+ Data - A pointer to data returned in the echo reply.
+ DataSize - The length of the returned data.
+ OptionInfo - A pointer to the IP options in the echo reply.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ KIRQL oldIrql;
+ PIRP irp;
+ PIO_STACK_LOCATION irpSp;
+ EchoControl *controlBlock;
+ PPENDING_IRP pendingIrp = NULL;
+ PPENDING_IRP item;
+ PLIST_ENTRY entry;
+ ULONG bytesReturned;
+
+
+ controlBlock = (EchoControl *) Context;
+
+ //
+ // Find the echo request IRP on the pending list.
+ //
+ IoAcquireCancelSpinLock(&oldIrql);
+
+ for ( entry = PendingEchoList.Flink;
+ entry != &PendingEchoList;
+ entry = entry->Flink
+ ) {
+ item = CONTAINING_RECORD(entry, PENDING_IRP, Linkage);
+ if (item->Context == controlBlock) {
+ pendingIrp = item;
+ irp = pendingIrp->Irp;
+ IoSetCancelRoutine(irp, NULL);
+ RemoveEntryList(entry);
+ break;
+ }
+ }
+
+ IoReleaseCancelSpinLock(oldIrql);
+
+ if (pendingIrp == NULL) {
+ //
+ // IRP must have been cancelled. PENDING_IRP struct
+ // was freed by cancel routine. Free control block.
+ //
+ CTEFreeMem(controlBlock);
+ return;
+ }
+
+ irpSp = IoGetCurrentIrpStackLocation(irp);
+
+ bytesReturned = ICMPEchoComplete(
+ controlBlock,
+ Status,
+ Data,
+ DataSize,
+ OptionInfo
+ );
+
+ CTEFreeMem(pendingIrp);
+ CTEFreeMem(controlBlock);
+
+ //
+ // Complete the IRP.
+ //
+ irp->IoStatus.Information = (ULONG) bytesReturned;
+ irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(irp, IO_NETWORK_INCREMENT);
+ return;
+
+} // CompleteEchoRequest
+
+void
+CompleteIPSetNTEAddrRequest(
+ void *Context,
+ IP_STATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ Handles the completion of an IP Set Addr request
+
+Arguments:
+
+ Context - Pointer to the SetAddrControl structure for this request.
+ Status - The IP status of the transmission.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ KIRQL oldIrql;
+ PIRP irp;
+ PIO_STACK_LOCATION irpSp;
+ SetAddrControl *controlBlock;
+ PPENDING_IRP pendingIrp = NULL;
+ PPENDING_IRP item;
+ PLIST_ENTRY entry;
+ ULONG bytesReturned;
+
+
+ controlBlock = (SetAddrControl *) Context;
+
+ //
+ // Find the echo request IRP on the pending list.
+ //
+ IoAcquireCancelSpinLock(&oldIrql);
+
+ for ( entry = PendingIPSetNTEAddrList.Flink;
+ entry != &PendingIPSetNTEAddrList;
+ entry = entry->Flink
+ ) {
+ item = CONTAINING_RECORD(entry, PENDING_IRP, Linkage);
+ if (item->Context == controlBlock) {
+ pendingIrp = item;
+ irp = pendingIrp->Irp;
+ IoSetCancelRoutine(irp, NULL);
+ RemoveEntryList(entry);
+ break;
+ }
+ }
+
+ IoReleaseCancelSpinLock(oldIrql);
+
+ if (pendingIrp == NULL) {
+ //
+ // IRP must have been cancelled. PENDING_IRP struct
+ // was freed by cancel routine. Free control block.
+ //
+ CTEFreeMem(controlBlock);
+ return;
+ }
+
+ CTEFreeMem(pendingIrp);
+ CTEFreeMem(controlBlock);
+
+ //
+ // Complete the IRP.
+ //
+ irp->IoStatus.Information = 0;
+ if (Status == IP_SUCCESS) {
+ irp->IoStatus.Status = STATUS_SUCCESS;
+ } else {
+ irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+ }
+ IoCompleteRequest(irp, IO_NETWORK_INCREMENT);
+ return;
+
+} // CompleteIPSetNTEAddrRequest
+
+
+BOOLEAN
+PrepareEchoIrpForCancel(
+ PIRP Irp,
+ PPENDING_IRP PendingIrp
+ )
+/*++
+
+Routine Description:
+
+ Prepares an Echo IRP for cancellation.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet to initialize for cancellation.
+ PendingIrp - Pointer to the PENDING_IRP structure for this IRP.
+
+Return Value:
+
+ TRUE if the IRP was cancelled before this routine was called.
+ FALSE otherwise.
+
+--*/
+
+{
+ BOOLEAN cancelled = TRUE;
+ KIRQL oldIrql;
+
+
+ IoAcquireCancelSpinLock(&oldIrql);
+
+ ASSERT(Irp->CancelRoutine == NULL);
+
+ if (!Irp->Cancel) {
+ IoSetCancelRoutine(Irp, CancelEchoRequest);
+ InsertTailList(&PendingEchoList, &(PendingIrp->Linkage));
+ cancelled = FALSE;
+ }
+
+ IoReleaseCancelSpinLock(oldIrql);
+
+ return(cancelled);
+
+} // PrepareEchoIrpForCancel
+
+BOOLEAN
+PrepareIPSetNTEAddrIrpForCancel(
+ PIRP Irp,
+ PPENDING_IRP PendingIrp
+ )
+/*++
+
+Routine Description:
+
+ Prepares an IPSetNTEAddr IRP for cancellation.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet to initialize for cancellation.
+ PendingIrp - Pointer to the PENDING_IRP structure for this IRP.
+
+Return Value:
+
+ TRUE if the IRP was cancelled before this routine was called.
+ FALSE otherwise.
+
+--*/
+
+{
+ BOOLEAN cancelled = TRUE;
+ KIRQL oldIrql;
+
+
+ IoAcquireCancelSpinLock(&oldIrql);
+
+ ASSERT(Irp->CancelRoutine == NULL);
+
+ if (!Irp->Cancel) {
+ IoSetCancelRoutine(Irp, CancelIPSetNTEAddrRequest);
+ InsertTailList(&PendingIPSetNTEAddrList, &(PendingIrp->Linkage));
+ cancelled = FALSE;
+ }
+
+ IoReleaseCancelSpinLock(oldIrql);
+
+ return(cancelled);
+
+} // PrepareIPSetNTEAddrIrpForCancel
+
+
+NTSTATUS
+DispatchEchoRequest(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ Processes an ICMP request.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether NT-specific processing of the request was
+ successful. The status of the actual request is returned in
+ the request buffers.
+
+--*/
+
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ IP_STATUS ipStatus;
+ PPENDING_IRP pendingIrp;
+ EchoControl *controlBlock;
+ PICMP_ECHO_REPLY replyBuffer;
+ BOOLEAN cancelled;
+
+
+ PAGED_CODE();
+
+ pendingIrp = CTEAllocMem(sizeof(PENDING_IRP));
+
+ if (pendingIrp == NULL) {
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ goto echo_error;
+ }
+
+ controlBlock = CTEAllocMem(sizeof(EchoControl));
+
+ if (controlBlock == NULL) {
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ CTEFreeMem(pendingIrp);
+ goto echo_error;
+ }
+
+ pendingIrp->Irp = Irp;
+ pendingIrp->FileObject = IrpSp->FileObject;
+ pendingIrp->Context = controlBlock;
+
+ controlBlock->ec_starttime = CTESystemUpTime();
+ controlBlock->ec_replybuf = Irp->AssociatedIrp.SystemBuffer;
+ controlBlock->ec_replybuflen =
+ IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+
+ IoMarkIrpPending(Irp);
+
+ cancelled = PrepareEchoIrpForCancel(Irp, pendingIrp);
+
+ if (!cancelled) {
+ ipStatus = ICMPEchoRequest(
+ Irp->AssociatedIrp.SystemBuffer, // request buf
+ IrpSp->Parameters.DeviceIoControl.InputBufferLength, // request len
+ controlBlock, // echo ctrl
+ CompleteEchoRequest // cmplt rtn
+ );
+
+ if (ipStatus == IP_PENDING) {
+ ntStatus = STATUS_PENDING;
+ }
+ else {
+ ASSERT(ipStatus != IP_SUCCESS);
+
+ //
+ // An internal error of some kind occurred. Complete the
+ // request.
+ //
+ CompleteEchoRequest(
+ controlBlock,
+ ipStatus,
+ NULL,
+ 0,
+ NULL
+ );
+
+ //
+ // The NT ioctl was successful, even if the request failed. The
+ // request status was passed back in the first reply block.
+ //
+ ntStatus = STATUS_SUCCESS;
+ }
+
+ return(ntStatus);
+ }
+
+ //
+ // Irp has already been cancelled.
+ //
+ ntStatus = STATUS_CANCELLED;
+ CTEFreeMem(pendingIrp);
+ CTEFreeMem(controlBlock);
+
+
+echo_error:
+
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = ntStatus;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ return(ntStatus);
+
+} // DispatchEchoRequest
+
+
+NTSTATUS
+DispatchIPSetNTEAddrRequest(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ Processes an IP Set Addr request.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether NT-specific processing of the request was
+ successful. The status of the actual request is returned in
+ the request buffers.
+
+--*/
+
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ IP_STATUS ipStatus;
+ PPENDING_IRP pendingIrp;
+ SetAddrControl *controlBlock;
+ BOOLEAN cancelled;
+
+
+ PAGED_CODE();
+
+ pendingIrp = CTEAllocMem(sizeof(PENDING_IRP));
+
+ if (pendingIrp == NULL) {
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ goto setnteaddr_error;
+ }
+
+ controlBlock = CTEAllocMem(sizeof(SetAddrControl));
+
+ if (controlBlock == NULL) {
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ CTEFreeMem(pendingIrp);
+ goto setnteaddr_error;
+ }
+
+ pendingIrp->Irp = Irp;
+ pendingIrp->FileObject = IrpSp->FileObject;
+ pendingIrp->Context = controlBlock;
+
+ IoMarkIrpPending(Irp);
+
+ cancelled = PrepareIPSetNTEAddrIrpForCancel(Irp, pendingIrp);
+
+ if (!cancelled) {
+
+ PIP_SET_ADDRESS_REQUEST request;
+
+ request = Irp->AssociatedIrp.SystemBuffer;
+ ipStatus = IPSetNTEAddr(
+ request->Context,
+ request->Address,
+ request->SubnetMask,
+ controlBlock,
+ CompleteIPSetNTEAddrRequest
+ );
+
+ if (ipStatus == IP_PENDING) {
+ ntStatus = STATUS_PENDING;
+ }
+ else {
+
+ //
+ // A request completed which did not pend.
+ //
+ CompleteIPSetNTEAddrRequest(
+ controlBlock,
+ ipStatus
+ );
+
+ //
+ // The NT ioctl was successful, even if the request failed. The
+ // request status was passed back in the first reply block.
+ //
+ ntStatus = STATUS_SUCCESS;
+ }
+
+ return(ntStatus);
+ }
+
+ //
+ // Irp has already been cancelled.
+ //
+ ntStatus = STATUS_CANCELLED;
+ CTEFreeMem(pendingIrp);
+ CTEFreeMem(controlBlock);
+
+
+setnteaddr_error:
+
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = ntStatus;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ return(ntStatus);
+
+} // DispatchIPSetNTEAddrRequest
diff --git a/private/ntos/tdi/tcpip/ip/ntreg.c b/private/ntos/tdi/tcpip/ip/ntreg.c
new file mode 100644
index 000000000..e9c53c208
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/ntreg.c
@@ -0,0 +1,672 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ntreg.c
+
+Abstract:
+
+ This source file contains the routines to to access the NT Registry for
+ configuration info.
+
+
+Author:
+
+ Mike Massa (mikemas) September 3, 1993
+
+ (taken from routines by jballard)
+
+Revision History:
+
+--*/
+
+
+#include <oscfg.h>
+#include <ndis.h>
+#include <cxport.h>
+
+
+#define WORK_BUFFER_SIZE 512
+
+
+//
+// Local function prototypes
+//
+NTSTATUS
+OpenRegKey(
+ PHANDLE HandlePtr,
+ PWCHAR KeyName
+ );
+
+NTSTATUS
+GetRegDWORDValue(
+ HANDLE KeyHandle,
+ PWCHAR ValueName,
+ PULONG ValueData
+ );
+
+NTSTATUS
+SetRegDWORDValue(
+ HANDLE KeyHandle,
+ PWCHAR ValueName,
+ PULONG ValueData
+ );
+
+NTSTATUS
+GetRegStringValue(
+ HANDLE KeyHandle,
+ PWCHAR ValueName,
+ PKEY_VALUE_PARTIAL_INFORMATION *ValueData,
+ PUSHORT ValueSize
+ );
+
+NTSTATUS
+GetRegSZValue(
+ HANDLE KeyHandle,
+ PWCHAR ValueName,
+ PUNICODE_STRING ValueData,
+ PULONG ValueType
+ );
+
+NTSTATUS
+GetRegMultiSZValue(
+ HANDLE KeyHandle,
+ PWCHAR ValueName,
+ PUNICODE_STRING ValueData
+ );
+
+VOID
+InitRegDWORDParameter(
+ HANDLE RegKey,
+ PWCHAR ValueName,
+ ULONG *Value,
+ ULONG DefaultValue
+ );
+
+
+#ifdef ALLOC_PRAGMA
+//
+// All of the init code can be discarded
+//
+
+#ifndef _PNP_POWER
+
+#pragma alloc_text(INIT, GetRegDWORDValue)
+#pragma alloc_text(INIT, SetRegDWORDValue)
+#pragma alloc_text(INIT, InitRegDWORDParameter)
+
+#else // _PNP_POWER
+
+#pragma alloc_text(PAGE, GetRegDWORDValue)
+#pragma alloc_text(PAGE, SetRegDWORDValue)
+#pragma alloc_text(PAGE, InitRegDWORDParameter)
+
+#endif // _PNP_POWER
+
+//
+// This code is pagable.
+//
+#pragma alloc_text(PAGE, OpenRegKey)
+#pragma alloc_text(PAGE, GetRegStringValue)
+#pragma alloc_text(PAGE, GetRegSZValue)
+#pragma alloc_text(PAGE, GetRegMultiSZValue)
+
+
+#endif // ALLOC_PRAGMA
+
+
+
+//
+// Function definitions
+//
+NTSTATUS
+OpenRegKey(
+ PHANDLE HandlePtr,
+ PWCHAR KeyName
+ )
+
+/*++
+
+Routine Description:
+
+ Opens a Registry key and returns a handle to it.
+
+Arguments:
+
+ HandlePtr - The varible into which to write the opened handle.
+ KeyName - The name of the Registry key to open.
+
+Return Value:
+
+ STATUS_SUCCESS or an appropriate failure code.
+
+--*/
+
+{
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING UKeyName;
+
+
+ PAGED_CODE();
+
+ RtlInitUnicodeString(&UKeyName, KeyName);
+
+ memset(&ObjectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
+ InitializeObjectAttributes(&ObjectAttributes,
+ &UKeyName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = ZwOpenKey(HandlePtr,
+ KEY_READ,
+ &ObjectAttributes);
+
+ return Status;
+}
+
+
+
+NTSTATUS
+GetRegDWORDValue(
+ HANDLE KeyHandle,
+ PWCHAR ValueName,
+ PULONG ValueData
+ )
+
+/*++
+
+Routine Description:
+
+ Reads a REG_DWORD value from the registry into the supplied variable.
+
+Arguments:
+
+ KeyHandle - Open handle to the parent key of the value to read.
+ ValueName - The name of the value to read.
+ ValueData - The variable into which to read the data.
+
+Return Value:
+
+ STATUS_SUCCESS or an appropriate failure code.
+
+--*/
+
+{
+ NTSTATUS status;
+ ULONG resultLength;
+ PKEY_VALUE_FULL_INFORMATION keyValueFullInformation;
+ UCHAR keybuf[WORK_BUFFER_SIZE];
+ UNICODE_STRING UValueName;
+
+
+#ifdef _PNP_POWER
+ PAGED_CODE();
+#endif // _PNP_POWER
+
+ RtlInitUnicodeString(&UValueName, ValueName);
+
+ keyValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)keybuf;
+ RtlZeroMemory(keyValueFullInformation, sizeof(keyValueFullInformation));
+
+
+ status = ZwQueryValueKey(KeyHandle,
+ &UValueName,
+ KeyValueFullInformation,
+ keyValueFullInformation,
+ WORK_BUFFER_SIZE,
+ &resultLength);
+
+ if (NT_SUCCESS(status)) {
+ if (keyValueFullInformation->Type != REG_DWORD) {
+ status = STATUS_INVALID_PARAMETER_MIX;
+ } else {
+ *ValueData = *((ULONG UNALIGNED *)((PCHAR)keyValueFullInformation +
+ keyValueFullInformation->DataOffset));
+ }
+ }
+
+ return status;
+}
+
+
+
+NTSTATUS
+SetRegDWORDValue(
+ HANDLE KeyHandle,
+ PWCHAR ValueName,
+ PULONG ValueData
+ )
+
+/*++
+
+Routine Description:
+
+ Writes the contents of a variable to a REG_DWORD value.
+
+Arguments:
+
+ KeyHandle - Open handle to the parent key of the value to write.
+ ValueName - The name of the value to write.
+ ValueData - The variable from which to write the data.
+
+Return Value:
+
+ STATUS_SUCCESS or an appropriate failure code.
+
+--*/
+
+{
+ NTSTATUS status;
+ UNICODE_STRING UValueName;
+
+
+#ifdef _PNP_POWER
+ PAGED_CODE();
+#endif // _PNP_POWER
+
+ RtlInitUnicodeString(&UValueName, ValueName);
+
+ status = ZwSetValueKey(KeyHandle,
+ &UValueName,
+ 0,
+ REG_DWORD,
+ ValueData,
+ sizeof(ULONG));
+
+ return status;
+}
+
+
+
+NTSTATUS
+GetRegStringValue(
+ HANDLE KeyHandle,
+ PWCHAR ValueName,
+ PKEY_VALUE_PARTIAL_INFORMATION *ValueData,
+ PUSHORT ValueSize
+ )
+
+/*++
+
+Routine Description:
+
+ Reads a REG_*_SZ string value from the Registry into the supplied
+ key value buffer. If the buffer string buffer is not large enough,
+ it is reallocated.
+
+Arguments:
+
+ KeyHandle - Open handle to the parent key of the value to read.
+ ValueName - The name of the value to read.
+ ValueData - Destination for the read data.
+ ValueSize - Size of the ValueData buffer. Updated on output.
+
+Return Value:
+
+ STATUS_SUCCESS or an appropriate failure code.
+
+--*/
+
+{
+ NTSTATUS status;
+ ULONG resultLength;
+ UNICODE_STRING UValueName;
+
+
+ PAGED_CODE();
+
+ RtlInitUnicodeString(&UValueName, ValueName);
+
+ status = ZwQueryValueKey(
+ KeyHandle,
+ &UValueName,
+ KeyValuePartialInformation,
+ *ValueData,
+ (ULONG) *ValueSize,
+ &resultLength
+ );
+
+ if ( (status == STATUS_BUFFER_OVERFLOW) ||
+ (status == STATUS_BUFFER_TOO_SMALL)
+ )
+ {
+ PVOID temp;
+
+ //
+ // Free the old buffer and allocate a new one of the
+ // appropriate size.
+ //
+
+ ASSERT(resultLength > (ULONG) *ValueSize);
+
+ if (resultLength <= 0xFFFF) {
+
+ temp = CTEAllocMem(resultLength);
+
+ if (temp != NULL) {
+
+ if (*ValueData != NULL) {
+ CTEFreeMem(*ValueData);
+ }
+
+ *ValueData = temp;
+ *ValueSize = (USHORT) resultLength;
+
+ status = ZwQueryValueKey(KeyHandle,
+ &UValueName,
+ KeyValuePartialInformation,
+ *ValueData,
+ *ValueSize,
+ &resultLength
+ );
+
+ ASSERT( (status != STATUS_BUFFER_OVERFLOW) &&
+ (status != STATUS_BUFFER_TOO_SMALL)
+ );
+ }
+ else {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ else {
+ status = STATUS_BUFFER_TOO_SMALL;
+ }
+ }
+
+ return(status);
+}
+
+
+
+NTSTATUS
+GetRegMultiSZValue(
+ HANDLE KeyHandle,
+ PWCHAR ValueName,
+ PUNICODE_STRING ValueData
+ )
+
+/*++
+
+Routine Description:
+
+ Reads a REG_MULTI_SZ string value from the Registry into the supplied
+ Unicode string. If the Unicode string buffer is not large enough,
+ it is reallocated.
+
+Arguments:
+
+ KeyHandle - Open handle to the parent key of the value to read.
+ ValueName - The name of the value to read.
+ ValueData - Destination Unicode string for the value data.
+
+Return Value:
+
+ STATUS_SUCCESS or an appropriate failure code.
+
+--*/
+
+{
+ NTSTATUS status;
+ ULONG resultLength;
+ PKEY_VALUE_PARTIAL_INFORMATION keyValuePartialInformation;
+ UNICODE_STRING UValueName;
+
+
+ PAGED_CODE();
+
+ ValueData->Length = 0;
+
+ status = GetRegStringValue(
+ KeyHandle,
+ ValueName,
+ (PKEY_VALUE_PARTIAL_INFORMATION *) &(ValueData->Buffer),
+ &(ValueData->MaximumLength)
+ );
+
+ if (NT_SUCCESS(status)) {
+
+ keyValuePartialInformation =
+ (PKEY_VALUE_PARTIAL_INFORMATION) ValueData->Buffer;
+
+ if (keyValuePartialInformation->Type == REG_MULTI_SZ) {
+
+ ValueData->Length = (USHORT)
+ keyValuePartialInformation->DataLength;
+
+ RtlCopyMemory(
+ ValueData->Buffer,
+ &(keyValuePartialInformation->Data),
+ ValueData->Length
+ );
+ }
+ else {
+ status = STATUS_INVALID_PARAMETER_MIX;
+ }
+ }
+
+ return status;
+
+} // GetRegMultiSZValue
+
+
+
+NTSTATUS
+GetRegSZValue(
+ HANDLE KeyHandle,
+ PWCHAR ValueName,
+ PUNICODE_STRING ValueData,
+ PULONG ValueType
+ )
+
+/*++
+
+Routine Description:
+
+ Reads a REG_SZ string value from the Registry into the supplied
+ Unicode string. If the Unicode string buffer is not large enough,
+ it is reallocated.
+
+Arguments:
+
+ KeyHandle - Open handle to the parent key of the value to read.
+ ValueName - The name of the value to read.
+ ValueData - Destination Unicode string for the value data.
+ ValueType - On return, contains the Registry type of the value read.
+
+Return Value:
+
+ STATUS_SUCCESS or an appropriate failure code.
+
+--*/
+
+{
+ NTSTATUS status;
+ ULONG resultLength;
+ PKEY_VALUE_PARTIAL_INFORMATION keyValuePartialInformation;
+ UNICODE_STRING UValueName;
+
+
+ PAGED_CODE();
+
+ ValueData->Length = 0;
+
+ status = GetRegStringValue(
+ KeyHandle,
+ ValueName,
+ (PKEY_VALUE_PARTIAL_INFORMATION *) &(ValueData->Buffer),
+ &(ValueData->MaximumLength)
+ );
+
+ if (NT_SUCCESS(status)) {
+
+ keyValuePartialInformation =
+ (PKEY_VALUE_PARTIAL_INFORMATION)ValueData->Buffer;
+
+ if ((keyValuePartialInformation->Type == REG_SZ) ||
+ (keyValuePartialInformation->Type == REG_EXPAND_SZ)
+ )
+ {
+ WCHAR *src;
+ WCHAR *dst;
+ ULONG dataLength;
+
+
+ *ValueType = keyValuePartialInformation->Type;
+ dataLength = keyValuePartialInformation->DataLength;
+
+ ASSERT(dataLength <= ValueData->MaximumLength);
+
+ dst = ValueData->Buffer;
+ src = (PWCHAR) &(keyValuePartialInformation->Data);
+
+ while (ValueData->Length <= dataLength) {
+
+ if ( (*dst++ = *src++) == UNICODE_NULL ) {
+ break;
+ }
+
+ ValueData->Length += sizeof(WCHAR);
+ }
+
+ if (ValueData->Length < (ValueData->MaximumLength - 1)) {
+ ValueData->Buffer[ValueData->Length/sizeof(WCHAR)] =
+ UNICODE_NULL;
+ }
+ }
+ else {
+ status = STATUS_INVALID_PARAMETER_MIX;
+ }
+ }
+
+ return status;
+}
+
+
+
+VOID
+InitRegDWORDParameter(
+ HANDLE RegKey,
+ PWCHAR ValueName,
+ ULONG *Value,
+ ULONG DefaultValue
+ )
+
+/*++
+
+Routine Description:
+
+ Reads a REG_DWORD parameter from the Registry into a variable. If the
+ read fails, the variable is initialized to a default.
+
+Arguments:
+
+ RegKey - Open handle to the parent key of the value to read.
+ ValueName - The name of the value to read.
+ Value - Destination variable into which to read the data.
+ DefaultValue - Default to assign if the read fails.
+
+Return Value:
+
+ STATUS_SUCCESS or an appropriate failure code.
+
+--*/
+
+{
+ NTSTATUS status;
+
+
+#ifdef _PNP_POWER
+ PAGED_CODE();
+#endif // _PNP_POWER
+
+ status = GetRegDWORDValue(
+ RegKey,
+ ValueName,
+ Value
+ );
+
+ if (!NT_SUCCESS(status)) {
+ //
+ // These registry parameters override the defaults, so their
+ // absence is not an error.
+ //
+ *Value = DefaultValue;
+ }
+
+ return;
+}
+
+
+PWCHAR
+EnumRegMultiSz(
+ IN PWCHAR MszString,
+ IN ULONG MszStringLength,
+ IN ULONG StringIndex
+ )
+/*++
+
+ Routine Description:
+
+ Parses a REG_MULTI_SZ string and returns the specified substring.
+
+ Arguments:
+
+ MszString - A pointer to the REG_MULTI_SZ string.
+
+ MszStringLength - The length of the REG_MULTI_SZ string, including the
+ terminating null character.
+
+ StringIndex - Index number of the substring to return. Specifiying
+ index 0 retrieves the first substring.
+
+ Return Value:
+
+ A pointer to the specified substring.
+
+ Notes:
+
+ This code is called at raised IRQL. It is not pageable.
+
+--*/
+{
+ PWCHAR string = MszString;
+
+ if ( MszStringLength < (2 * sizeof(WCHAR)) ) {
+ return(NULL);
+ }
+
+ //
+ // Find the start of the desired string.
+ //
+ while (StringIndex) {
+
+ while (MszStringLength >= sizeof(WCHAR)) {
+ MszStringLength -= sizeof(WCHAR);
+
+ if (*string++ == UNICODE_NULL) {
+ break;
+ }
+ }
+
+ //
+ // Check for index out of range.
+ //
+ if ( MszStringLength < (2 * sizeof(UNICODE_NULL)) ) {
+ return(NULL);
+ }
+
+ StringIndex--;
+ }
+
+ if ( MszStringLength < (2 * sizeof(UNICODE_NULL)) ) {
+ return(NULL);
+ }
+
+ return(string);
+}
+
+
diff --git a/private/ntos/tdi/tcpip/ip/sources.inc b/private/ntos/tdi/tcpip/ip/sources.inc
new file mode 100644
index 000000000..87a099a83
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/sources.inc
@@ -0,0 +1,59 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ip
+
+NTPROFILEINPUT=yes
+
+TARGETNAME=ip
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+TARGETLIBS=
+
+INCLUDES=..\..\..\..\inc;..\..\..\..\..\inc;..\..\h
+
+C_DEFINES=$(C_DEFINES) -DNT -D_NTDRIVER_ -D_PNP_POWER -DSECFLTR
+
+!IFDEF BUILD_FOR_3_51
+C_DEFINES= $(C_DEFINES) -D_NTIFS_
+!ENDIF
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES= \
+ ..\arp.c \
+ ..\icmp.c \
+ ..\igmp.c \
+ ..\info.c \
+ ..\init.c \
+ ..\iploop.c \
+ ..\iprcv.c \
+ ..\iproute.c \
+ ..\ipstatus.c \
+ ..\ipxmit.c \
+ ..\ntip.c \
+ ..\ntirp.c \
+ ..\ntreg.c
diff --git a/private/ntos/tdi/tcpip/ip/up/makefile b/private/ntos/tdi/tcpip/ip/up/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/up/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/tcpip/ip/up/sources b/private/ntos/tdi/tcpip/ip/up/sources
new file mode 100644
index 000000000..91036a15a
--- /dev/null
+++ b/private/ntos/tdi/tcpip/ip/up/sources
@@ -0,0 +1,27 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+UP_DRIVER=yes
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/tcpip/tcp/addr.c b/private/ntos/tdi/tcpip/tcp/addr.c
new file mode 100644
index 000000000..eec1997db
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/addr.c
@@ -0,0 +1,2061 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** ADDR.C - TDI address object procedures
+//
+// This file contains the TDI address object related procedures,
+// including TDI open address, TDI close address, etc.
+//
+// The local address objects are stored in a hash table, protected
+// by the AddrObjTableLock. In order to insert or delete from the
+// hash table this lock must be held, as well as the address object
+// lock. The table lock must always be taken before the object lock.
+//
+
+#include "oscfg.h"
+#include "ndis.h"
+#include "tdi.h"
+#include "tdistat.h"
+#include "cxport.h"
+#include "ip.h"
+#ifdef VXD
+#include "tdivxd.h"
+#endif
+#ifdef NT
+#include "tdint.h"
+#include "tdistat.h"
+#endif
+#include "queue.h"
+#include "addr.h"
+#include "udp.h"
+#include "raw.h"
+#ifndef UDP_ONLY
+#include "tcp.h"
+#include "tcpconn.h"
+#else
+#include "tcpdeb.h"
+#endif
+#include "info.h"
+#include "tcpinfo.h"
+#include "tcpcfg.h"
+
+
+extern IPInfo LocalNetInfo; // Information about the local nets.
+EXTERNAL_LOCK(DGSendReqLock)
+
+#ifndef UDP_ONLY
+EXTERNAL_LOCK(ConnTableLock)
+#endif
+
+extern void FreeAORequest(AORequest *Request);
+
+//* Addess object hash table.
+AddrObj *AddrObjTable[AO_TABLE_SIZE];
+AddrObj *LastAO; // one element lookup cache.
+DEFINE_LOCK_STRUCTURE(AddrObjTableLock)
+
+//* AORequest free list.
+AORequest *AORequestFree;
+
+ushort NextUserPort = MIN_USER_PORT;
+
+#define NUM_AO_REQUEST 5
+DEFINE_LOCK_STRUCTURE(AORequestLock)
+
+#define AO_HASH(a, p) ((*(uint *)&(a) + (uint)(p)) % AO_TABLE_SIZE)
+
+#ifdef VXD
+
+#define DEFAULT_AO_INDEX_SIZE 32
+#define AO_INDEX_INCR 16 // How much to grow by.
+
+typedef AddrObj *AOIndexTbl[];
+
+ushort AOInstance; // Global AO instance count.
+
+uint AOIndexSize; // # of entries in AOIndex.
+uint NextAOIndex; // Next AO index to use.
+AOIndexTbl *AOIndex;
+
+#define AO_INDEX(i) ((i) & 0xffff)
+#define AO_INST(i) ((i) >> 16)
+#define MAKE_AO_INDEX(s, i) (uint)(((s) << 16) | ((i) & 0xffff))
+
+#define MAX_INDEX_SIZE 256
+
+#define INVALID_INDEX 0xffffffff
+
+#endif
+
+
+//
+// All of the init code can be discarded.
+//
+#ifdef NT
+#ifdef ALLOC_PRAGMA
+
+int InitAddr();
+
+#pragma alloc_text(INIT, InitAddr)
+
+#endif // ALLOC_PRAGMA
+#endif
+
+
+#ifdef VXD
+
+//* GetIndexedAO - Get an AddrObj from an index.
+//
+// Called by the UDP routines that access an AO to find the AO by it's
+// index. We look it up in the table, and compare the high 16 bits against
+// the instance # in the AddrObj.
+//
+// Input: Index - Index of AddrObj.
+//
+// Returns: Pointer to AO, or NULL if it's not valid.
+//
+AddrObj *
+GetIndexedAO(uint Index)
+{
+ AddrObj *AO;
+
+ if (AO_INDEX(Index) < AOIndexSize) {
+ AO = (*AOIndex)[AO_INDEX(Index)];
+ if (AO != NULL && AO->ao_inst == AO_INST(Index))
+ return AO;
+ }
+ return NULL;
+
+}
+
+//* GetAOIndex - Get an index value for an AddrObj.
+//
+// Called when we're creating an index value for an AddrObj. We go through
+// the table, looking for a valid index. If we find one, we'll make an index
+// out of it and the AOInstance variable, and bump the instance field.
+// Otherwise we may grow the table.
+//
+// Input: AO - AddrObj to put into table.
+//
+// Returns: Index to use, or INVALID_INDEX if we can't find one.
+//
+uint
+GetAOIndex(AddrObj *AO)
+{
+ uint i; // Index variable.
+ uint CurrentIndex; // Current index being checked.
+
+ for (;;) {
+ CurrentIndex = NextAOIndex;
+ for (i = 0; i < AOIndexSize; i++) {
+ if (CurrentIndex == AOIndexSize)
+ CurrentIndex = 0; // Set it back to beginning.
+
+ if ((*AOIndex)[CurrentIndex] == NULL)
+ break; // Found the one we needed.
+
+ CurrentIndex++;
+ }
+
+ if (i < AOIndexSize) {
+ uint NewIndex;
+
+ // We came out because we found an empty slot.
+ AO->ao_inst = AOInstance;
+ AO->ao_index = (uchar)CurrentIndex;
+ (*AOIndex)[CurrentIndex] = AO;
+ NextAOIndex = CurrentIndex + 1; // Bump the next one to look at.
+ NewIndex = MAKE_AO_INDEX(AOInstance, CurrentIndex);
+ AOInstance++;
+ return NewIndex;
+ } else {
+ // Couldn't find a slot, so grow the table.
+ if (AOIndexSize != MAX_INDEX_SIZE) {
+ // Table isn't already at max size. Try and grow it.
+
+ uint NewIndexSize;
+ AOIndexTbl *NewIndexTbl, *OldIndexTbl;
+
+ NewIndexSize = MIN(MAX_INDEX_SIZE, AOIndexSize + AO_INDEX_INCR);
+ NewIndexTbl = CTEAllocMem(sizeof(AddrObj *) * NewIndexSize);
+ if (NewIndexTbl != NULL) {
+ // We allocated it.
+ CTEMemCopy(NewIndexTbl, AOIndex,
+ AOIndexSize * sizeof(AddrObj *));
+ OldIndexTbl = AOIndex;
+ AOIndex = NewIndexTbl;
+ AOIndexSize = NewIndexSize;
+ CTEFreeMem(OldIndexTbl); // Loop around, and try again.
+ } else
+ return INVALID_INDEX;
+ } else
+ return INVALID_INDEX;
+ }
+ }
+
+}
+
+#endif
+
+//* ReadNextAO - Read the next AddrObj in the table.
+//
+// Called to read the next AddrObj in the table. The needed information
+// is derived from the incoming context, which is assumed to be valid.
+// We'll copy the information, and then update the context value with
+// the next AddrObj to be read.
+//
+// Input: Context - Poiner to a UDPContext.
+// Buffer - Pointer to a UDPEntry structure.
+//
+// Returns: TRUE if more data is available to be read, FALSE is not.
+//
+uint
+ReadNextAO(void *Context, void *Buffer)
+{
+ UDPContext *UContext = (UDPContext *)Context;
+ UDPEntry *UEntry = (UDPEntry *)Buffer;
+ AddrObj *CurrentAO;
+ uint i;
+
+ CurrentAO = UContext->uc_ao;
+ CTEStructAssert(CurrentAO, ao);
+
+ UEntry->ue_localaddr = CurrentAO->ao_addr;
+ UEntry->ue_localport = CurrentAO->ao_port;
+
+ // We've filled it in. Now update the context.
+ CurrentAO = CurrentAO->ao_next;
+ if (CurrentAO != NULL && CurrentAO->ao_prot == PROTOCOL_UDP) {
+ UContext->uc_ao = CurrentAO;
+ return TRUE;
+ } else {
+ // The next AO is NULL, or not a UDP AO. Loop through the AddrObjTable
+ // looking for a new one.
+ i = UContext->uc_index;
+
+ for (;;) {
+ while (CurrentAO != NULL) {
+ if (CurrentAO->ao_prot == PROTOCOL_UDP)
+ break;
+ else
+ CurrentAO = CurrentAO->ao_next;
+ }
+
+ if (CurrentAO != NULL)
+ break; // Get out of for (;;) loop.
+
+ CTEAssert(CurrentAO == NULL);
+
+ // Didn't find one on this chain. Walk down the table, looking
+ // for the next one.
+ while (++i < AO_TABLE_SIZE) {
+ if (AddrObjTable[i] != NULL) {
+ CurrentAO = AddrObjTable[i];
+ break; // Out of while loop.
+ }
+ }
+
+ if (i == AO_TABLE_SIZE)
+ break; // Out of for (;;) loop.
+ }
+
+ // If we found one, return it.
+ if (CurrentAO != NULL) {
+ UContext->uc_ao = CurrentAO;
+ UContext->uc_index = i;
+ return TRUE;
+ } else {
+ UContext->uc_index = 0;
+ UContext->uc_ao = NULL;
+ return FALSE;
+ }
+ }
+
+}
+
+//* ValidateAOContext - Validate the context for reading the AddrObj table.
+//
+// Called to start reading the AddrObj table sequentially. We take in
+// a context, and if the values are 0 we return information about the
+// first AddrObj in the table. Otherwise we make sure that the context value
+// is valid, and if it is we return TRUE.
+// We assume the caller holds the AddrObjTable lock.
+//
+// Input: Context - Pointer to a UDPContext.
+// Valid - Where to return information about context being
+// valid.
+//
+// Returns: TRUE if data in table, FALSE if not. *Valid set to true if the
+// context is valid.
+//
+uint
+ValidateAOContext(void *Context, uint *Valid)
+{
+ UDPContext *UContext = (UDPContext *)Context;
+ uint i;
+ AddrObj *TargetAO;
+ AddrObj *CurrentAO;
+
+ i = UContext->uc_index;
+ TargetAO = UContext->uc_ao;
+
+ // If the context values are 0 and NULL, we're starting from the beginning.
+ if (i == 0 && TargetAO == NULL) {
+ *Valid = TRUE;
+ do {
+ if ((CurrentAO = AddrObjTable[i]) != NULL) {
+ CTEStructAssert(CurrentAO, ao);
+ while (CurrentAO != NULL && CurrentAO->ao_prot != PROTOCOL_UDP)
+ CurrentAO = CurrentAO->ao_next;
+
+ if (CurrentAO != NULL)
+ break;
+ }
+ i++;
+ } while (i < AO_TABLE_SIZE);
+
+ if (CurrentAO != NULL) {
+ UContext->uc_index = i;
+ UContext->uc_ao = CurrentAO;
+ return TRUE;
+ } else
+ return FALSE;
+
+ } else {
+
+ // We've been given a context. We just need to make sure that it's
+ // valid.
+
+ if (i < AO_TABLE_SIZE) {
+ CurrentAO = AddrObjTable[i];
+ while (CurrentAO != NULL) {
+ if (CurrentAO == TargetAO) {
+ if (CurrentAO->ao_prot == PROTOCOL_UDP) {
+ *Valid = TRUE;
+ return TRUE;
+ }
+ break;
+ } else {
+ CurrentAO = CurrentAO->ao_next;
+ }
+ }
+
+ }
+
+ // If we get here, we didn't find the matching AddrObj.
+ *Valid = FALSE;
+ return FALSE;
+
+ }
+
+}
+
+
+//** GetAddrObj - Find a local address object.
+//
+// This is the local address object lookup routine. We take as input the local
+// address and port and a pointer to a 'previous' address object. The hash
+// table entries in each bucket are sorted in order of increasing address, and
+// we skip over any object that has an address lower than the 'previous'
+// address. To get the first address object, pass in a previous value of NULL.
+//
+// We assume that the table lock is held while we're in this routine. We don't
+// take each object lock, since the local address and port can't change while
+// the entry is in the table and the table lock is held so nothing can be
+// inserted or deleted.
+//
+// Input: LocalAddr - Local IP address of object to find (may be NULL);
+// LocalPort - Local port of object to find.
+// Protocol - Protocol to find.
+// PreviousAO - Pointer to last address object found.
+//
+// Returns: A pointer to the Address object, or NULL if none.
+//
+AddrObj *
+GetAddrObj(IPAddr LocalAddr, ushort LocalPort, uchar Protocol,
+ AddrObj *PreviousAO)
+{
+ AddrObj *CurrentAO; // Current address object we're examining.
+
+
+#ifdef DEBUG
+ if (PreviousAO != NULL)
+ CTEStructAssert(PreviousAO, ao);
+#endif
+
+#if 0
+ //
+ // Check our 1-element cache for a match
+ //
+ if ((PreviousAO == NULL) && (LastAO != NULL)) {
+ CTEStructAssert(LastAO, ao);
+ if ( (LastAO->ao_prot == Protocol) &&
+ IP_ADDR_EQUAL(LastAO->ao_addr, LocalAddr) &&
+ (LastAO->ao_port == LocalPort)
+ )
+ {
+ return LastAO;
+ }
+ }
+#endif
+
+ // Find the appropriate bucket in the hash table, and search for a match.
+ // If we don't find one the first time through, we'll try again with a
+ // wildcard local address.
+
+ for (;;) {
+
+ CurrentAO = AddrObjTable[AO_HASH(LocalAddr, LocalPort)];
+ // While we haven't hit the end of the list, examine each element.
+
+ while (CurrentAO != NULL) {
+
+ CTEStructAssert(CurrentAO, ao);
+
+ // If the current one is greater than one we were given, check it.
+ //
+ // #62710: Return only valid AO's since we might have stale AO's lying
+ // around.
+ //
+ if ((CurrentAO > PreviousAO) &&
+ (AO_VALID(CurrentAO))) {
+ if (!(CurrentAO->ao_flags & AO_RAW_FLAG)) {
+ if ( IP_ADDR_EQUAL(CurrentAO->ao_addr, LocalAddr) &&
+ (CurrentAO->ao_port == LocalPort) &&
+ (CurrentAO->ao_prot == Protocol)
+ )
+ {
+ LastAO = CurrentAO;
+ return CurrentAO;
+ }
+ }
+ else {
+ if ( (Protocol != PROTOCOL_UDP)
+#ifndef UDP_ONLY
+ && (Protocol != PROTOCOL_TCP)
+#endif
+ )
+ {
+ IF_TCPDBG(TCP_DEBUG_RAW) {
+ TCPTRACE((
+ "matching <p, a> <%u, %lx> ao %lx <%u, %lx>\n",
+ Protocol, LocalAddr, CurrentAO,
+ CurrentAO->ao_prot, CurrentAO->ao_addr
+ ));
+
+ }
+
+ if ( IP_ADDR_EQUAL(CurrentAO->ao_addr, LocalAddr) &&
+ ( (CurrentAO->ao_prot == Protocol) ||
+ (CurrentAO->ao_prot == 0)
+ )
+ )
+ {
+ LastAO = CurrentAO;
+ return CurrentAO;
+ }
+ }
+ }
+ }
+ // Either it was less than the previous one, or they didn't match.
+ CurrentAO = CurrentAO->ao_next;
+ }
+ // When we get here, we've hit the end of the list we were examining.
+ // If we weren't examining a wildcard address, look for a wild card
+ // address.
+ if (!IP_ADDR_EQUAL(LocalAddr, NULL_IP_ADDR)) {
+ LocalAddr = NULL_IP_ADDR;
+ PreviousAO = NULL;
+ } else
+ return NULL; // We looked for a wildcard and couldn't find
+ // one, so fail.
+ }
+}
+
+
+//* GetNextAddrObj - Get the next address object in a sequential search.
+//
+// This is the 'get next' routine, called when we are reading the address
+// object table sequentially. We pull the appropriate parameters from the
+// search context, call GetAddrObj, and update the search context with what
+// we find. This routine assumes the AddrObjTableLock is held by the caller.
+//
+// Input: SearchContext - Pointer to seach context for search taking place.
+//
+// Returns: Pointer to AddrObj, or NULL if search failed.
+//
+AddrObj *
+GetNextAddrObj(AOSearchContext *SearchContext)
+{
+ AddrObj *FoundAO; // Pointer to the address object we found.
+
+ CTEAssert(SearchContext != NULL);
+
+ // Try and find a match.
+ FoundAO = GetAddrObj(SearchContext->asc_addr, SearchContext->asc_port,
+ SearchContext->asc_prot, SearchContext->asc_previous);
+
+ // Found a match. Update the search context for next time.
+ if (FoundAO != NULL) {
+ SearchContext->asc_previous = FoundAO;
+ SearchContext->asc_addr = FoundAO->ao_addr;
+ // Don't bother to update port or protocol, they don't change.
+ }
+ return FoundAO;
+}
+
+//* GetFirstAddrObj - Get the first matching address object.
+//
+// The routine called to start a sequential read of the AddrObj table. We
+// initialize the provided search context and then call GetNextAddrObj to do
+// the actual read. We assume that the AddrObjTableLock is held by the caller.
+//
+// Input: LocalAddr - Local IP address of object to be found.
+// LocalPort - Local port of AO to be found.
+// Protocol - Protocol to be found.
+// SearchContext - Pointer to search context to be used during
+// search.
+//
+// Returns: Pointer to AO found, or NULL if we couldn't find any.
+//
+AddrObj *
+GetFirstAddrObj(IPAddr LocalAddr, ushort LocalPort, uchar Protocol,
+ AOSearchContext *SearchContext)
+{
+ CTEAssert(SearchContext != NULL);
+
+ // Fill in the search context.
+ SearchContext->asc_previous = NULL; // Haven't found one yet.
+ SearchContext->asc_addr = LocalAddr;
+ SearchContext->asc_port = LocalPort;
+ SearchContext->asc_prot = Protocol;
+ return GetNextAddrObj(SearchContext);
+}
+
+//* InsertAddrObj - Insert an address object into the AddrObj table.
+//
+// Called to insert an AO into the table, assuming the table lock is held. We
+// hash on the addr and port, and then insert in into the correct place
+// (sorted by address of the objects).
+//
+// Input: NewAO - Pointer to AddrObj to be inserted.
+//
+// Returns: Nothing.
+//
+void
+InsertAddrObj(AddrObj *NewAO)
+{
+ AddrObj *PrevAO; // Pointer to previous address object in hash
+ // chain.
+ AddrObj *CurrentAO; // Pointer to current AO in table.
+
+ CTEStructAssert(NewAO, ao);
+
+ PrevAO = STRUCT_OF(AddrObj,
+ &AddrObjTable[AO_HASH(NewAO->ao_addr, NewAO->ao_port)], ao_next);
+ CurrentAO = PrevAO->ao_next;
+
+ // Loop through the chain until we hit the end or until we find an entry
+ // whose address is greater than ours.
+
+ while (CurrentAO != NULL) {
+
+ CTEStructAssert(CurrentAO, ao);
+ CTEAssert(CurrentAO != NewAO); // Debug check to make sure we aren't
+ // inserting the same entry.
+ if (NewAO < CurrentAO)
+ break;
+ PrevAO = CurrentAO;
+ CurrentAO = CurrentAO->ao_next;
+ }
+
+ // At this point, PrevAO points to the AO before the new one. Insert it
+ // there.
+ CTEAssert(PrevAO != NULL);
+ CTEAssert(PrevAO->ao_next == CurrentAO);
+
+ NewAO->ao_next = CurrentAO;
+ PrevAO->ao_next = NewAO;
+ if (NewAO->ao_prot == PROTOCOL_UDP)
+ UStats.us_numaddrs++;
+}
+
+//* RemoveAddrObj - Remove an address object from the table.
+//
+// Called when we need to remove an address object from the table. We hash on
+// the addr and port, then walk the table looking for the object. We assume
+// that the table lock is held.
+//
+// The AddrObj may have already been removed from the table if it was
+// invalidated for some reason, so we need to check for the case of not
+// finding it.
+//
+// Input: DeletedAO - AddrObj to delete.
+//
+// Returns: Nothing.
+//
+void
+RemoveAddrObj(AddrObj *RemovedAO)
+{
+ AddrObj *PrevAO; // Pointer to previous address object in hash
+ // chain.
+ AddrObj *CurrentAO; // Pointer to current AO in table.
+
+ CTEStructAssert(RemovedAO, ao);
+
+ PrevAO = STRUCT_OF(AddrObj,
+ &AddrObjTable[AO_HASH(RemovedAO->ao_addr, RemovedAO->ao_port)],
+ ao_next);
+ CurrentAO = PrevAO->ao_next;
+
+ // Walk the table, looking for a match.
+ while (CurrentAO != NULL) {
+ CTEStructAssert(CurrentAO, ao);
+
+ if (CurrentAO == RemovedAO) {
+ PrevAO->ao_next = CurrentAO->ao_next;
+ if (CurrentAO->ao_prot == PROTOCOL_UDP) {
+ UStats.us_numaddrs--;
+ }
+ if (CurrentAO == LastAO) {
+ LastAO = NULL;
+ }
+ return;
+ } else {
+ PrevAO = CurrentAO;
+ CurrentAO = CurrentAO->ao_next;
+ }
+ }
+
+ // If we get here, we didn't find him. This is OK, but we should say
+ // something about it.
+ CTEPrint("RemoveAddrObj: Object not found.\r\n");
+}
+
+//* FindAnyAddrObj - Find an AO with matching port on any local address.
+//
+// Called for wildcard address opens. We go through the entire addrobj table,
+// and see if anyone has the specified port. We assume that the lock is
+// already held on the table.
+//
+// Input: Port - Port to be looked for.
+// Protocol - Protocol on which to look.
+//
+// Returns: Pointer to AO found, or NULL is noone has it.
+//
+AddrObj *
+FindAnyAddrObj(ushort Port, uchar Protocol)
+{
+ int i; // Index variable.
+ AddrObj *CurrentAO; // Current AddrObj being examined.
+
+ for (i = 0; i < AO_TABLE_SIZE; i++) {
+ CurrentAO = AddrObjTable[i];
+ while (CurrentAO != NULL) {
+ CTEStructAssert(CurrentAO, ao);
+
+ if (CurrentAO->ao_port == Port && CurrentAO->ao_prot == Protocol)
+ return CurrentAO;
+ else
+ CurrentAO = CurrentAO->ao_next;
+ }
+ }
+
+ return NULL;
+
+}
+
+//* GetAddress - Get an IP address and port from a TDI address structure.
+//
+// Called when we need to get our addressing information from a TDI
+// address structure. We go through the structure, and return what we
+// find.
+//
+// Input: AddrList - Pointer to TRANSPORT_ADDRESS structure to search.
+// Addr - Pointer to where to return IP address.
+// Port - Pointer to where to return Port.
+//
+// Return: TRUE if we find an address, FALSE if we don't.
+//
+uchar
+GetAddress(TRANSPORT_ADDRESS UNALIGNED *AddrList, IPAddr *Addr, ushort *Port)
+{
+ int i; // Index variable.
+ TA_ADDRESS UNALIGNED *CurrentAddr; // Address we're examining and may use.
+
+ // First, verify that someplace in Address is an address we can use.
+ CurrentAddr = (TA_ADDRESS UNALIGNED *)AddrList->Address;
+
+ for (i = 0; i < AddrList->TAAddressCount; i++) {
+ if (CurrentAddr->AddressType == TDI_ADDRESS_TYPE_IP) {
+ if (CurrentAddr->AddressLength >= TDI_ADDRESS_LENGTH_IP) {
+ TDI_ADDRESS_IP UNALIGNED *ValidAddr =
+ (TDI_ADDRESS_IP UNALIGNED *)CurrentAddr->Address;
+
+ *Port = ValidAddr->sin_port;
+ *Addr = ValidAddr->in_addr;
+ return TRUE;
+
+ } else
+ return FALSE; // Wrong length for address.
+ } else
+ CurrentAddr = (TA_ADDRESS UNALIGNED *)(CurrentAddr->Address +
+ CurrentAddr->AddressLength);
+ }
+
+ return FALSE; // Didn't find a match.
+
+
+}
+
+//* InvalidateAddrs - Invalidate all AOs for a specific address.
+//
+// Called when we need to invalidate all AOs for a specific address. Walk
+// down the table with the lock held, and take the lock on each AddrObj.
+// If the address matches, mark it as invalid, pull off all requests,
+// and continue. At the end we'll complete all requests with an error.
+//
+// Input: Addr - Addr to be invalidated.
+//
+// Returns: Nothing.
+//
+void
+InvalidateAddrs(IPAddr Addr)
+{
+ Queue SendQ;
+ Queue RcvQ;
+ AORequest *ReqList;
+ CTELockHandle TableHandle, AOHandle;
+ uint i;
+ AddrObj *AO;
+ DGSendReq *SendReq;
+ DGRcvReq *RcvReq;
+ AOMCastAddr *MA;
+
+ INITQ(&SendQ);
+ INITQ(&RcvQ);
+ ReqList = NULL;
+
+ CTEGetLock(&AddrObjTableLock, &TableHandle);
+ for (i = 0; i < AO_TABLE_SIZE; i++) {
+ // Walk down each hash bucket, looking for a match.
+ AO = AddrObjTable[i];
+ while (AO != NULL) {
+ CTEStructAssert(AO, ao);
+
+ CTEGetLock(&AO->ao_lock, &AOHandle);
+ if (IP_ADDR_EQUAL(AO->ao_addr, Addr) && AO_VALID(AO)) {
+ // This one matches. Mark as invalid, then pull his requests.
+ SET_AO_INVALID(AO);
+
+ // Free any IP options we have.
+ (*LocalNetInfo.ipi_freeopts)(&AO->ao_opt);
+
+ // If he has a request on him, pull him off.
+ if (AO->ao_request != NULL) {
+ AORequest *Temp;
+
+ Temp = STRUCT_OF(AORequest, &AO->ao_request, aor_next);
+ do {
+ Temp = Temp->aor_next;
+ } while (Temp->aor_next != NULL);
+
+ Temp->aor_next = ReqList;
+ ReqList = AO->ao_request;
+ AO->ao_request = NULL;
+ }
+
+ // Go down his send list, pulling things off the send q and
+ // putting them on our local queue.
+ while (!EMPTYQ(&AO->ao_sendq)) {
+ DEQUEUE(&AO->ao_sendq, SendReq, DGSendReq, dsr_q);
+ CTEStructAssert(SendReq, dsr);
+ ENQUEUE(&SendQ, &SendReq->dsr_q);
+ }
+
+ // Do the same for the receive queue.
+ while (!EMPTYQ(&AO->ao_rcvq)) {
+ DEQUEUE(&AO->ao_rcvq, RcvReq, DGRcvReq, drr_q);
+ CTEStructAssert(RcvReq, drr);
+ ENQUEUE(&RcvQ, &RcvReq->drr_q);
+ }
+
+ // Free any multicast addresses he may have. IP will have
+ // deleted them at that level before we get here, so all we need
+ // to do if free the memory.
+ MA = AO->ao_mcastlist;
+ while (MA != NULL) {
+ AOMCastAddr *Temp;
+
+ Temp = MA;
+ MA = MA->ama_next;
+ CTEFreeMem(Temp);
+ }
+ AO->ao_mcastlist = NULL;
+
+ }
+ CTEFreeLock(&AO->ao_lock, AOHandle);
+ AO = AO->ao_next; // Go to the next one.
+ }
+ }
+ CTEFreeLock(&AddrObjTableLock, TableHandle);
+
+ // OK, now walk what we've collected, complete it, and free it.
+ while (ReqList != NULL) {
+ AORequest *Req;
+
+ Req = ReqList;
+ ReqList = Req->aor_next;
+ (*Req->aor_rtn)(Req->aor_context, (uint) TDI_ADDR_INVALID, 0);
+ FreeAORequest(Req);
+ }
+
+ // Walk down the rcv. q, completing and freeing requests.
+ while (!EMPTYQ(&RcvQ)) {
+
+ DEQUEUE(&RcvQ, RcvReq, DGRcvReq, drr_q);
+ CTEStructAssert(RcvReq, drr);
+
+ (*RcvReq->drr_rtn)(RcvReq->drr_context, (uint) TDI_ADDR_INVALID, 0);
+
+ FreeDGRcvReq(RcvReq);
+
+ }
+
+ // Now do the same for sends.
+ while (!EMPTYQ(&SendQ)) {
+
+ DEQUEUE(&SendQ, SendReq, DGSendReq, dsr_q);
+ CTEStructAssert(SendReq, dsr);
+
+ (*SendReq->dsr_rtn)(SendReq->dsr_context, (uint) TDI_ADDR_INVALID, 0);
+
+ CTEGetLock(&DGSendReqLock, &TableHandle);
+ if (SendReq->dsr_header != NULL)
+ FreeDGHeader(SendReq->dsr_header);
+ FreeDGSendReq(SendReq);
+ CTEFreeLock(&DGSendReqLock, TableHandle);
+
+ }
+}
+
+//* RequestEventProc - Handle a deferred request event.
+//
+// Called when the event scheduled by DelayDerefAO is called.
+// We just call ProcessAORequest.
+//
+// Input: Event - Event that fired.
+// Context - Pointer to AddrObj.
+//
+// Returns: Nothing.
+//
+void
+RequestEventProc(CTEEvent *Event, void *Context)
+{
+ AddrObj *AO = (AddrObj *)Context;
+
+ CTEStructAssert(AO, ao);
+ CTEAssert(AO_BUSY(AO));
+
+ ProcessAORequests(AO);
+
+}
+
+//* GetAddrOptions - Get the address options.
+//
+// Called when we're opening an address. We take in a pointer, and walk
+// down it looking for address options we know about.
+//
+// Input: Ptr - Ptr to search.
+// Reuse - Pointer to reuse variable.
+// DHCPAddr - Pointer to DHCP addr.
+//
+// Returns: Nothing.
+//
+void
+GetAddrOptions(void *Ptr, uchar *Reuse, uchar *DHCPAddr)
+{
+ uchar *OptPtr;
+
+ *Reuse = 0;
+ *DHCPAddr = 0;
+
+ if (Ptr == NULL)
+ return;
+
+ OptPtr = (uchar *)Ptr;
+
+ while (*OptPtr != TDI_OPTION_EOL) {
+ if (*OptPtr == TDI_ADDRESS_OPTION_REUSE)
+ *Reuse = 1;
+ else
+ if (*OptPtr == TDI_ADDRESS_OPTION_DHCP)
+ *DHCPAddr = 1;
+
+ OptPtr++;
+ }
+
+}
+
+//* TdiOpenAddress - Open a TDI address object.
+//
+// This is the external interface to open an address. The caller provides a
+// TDI_REQUEST structure and a TRANSPORT_ADDRESS structure, as well a pointer
+// to a variable identifying whether or not we are to allow reuse of an
+// address while it's still open.
+//
+// Input: Request - Pointer to a TDI request structure for this request.
+// AddrList - Pointer to TRANSPORT_ADDRESS structure describing
+// address to be opened.
+// Protocol - Protocol on which to open the address. Only the
+// least significant byte is used.
+// Ptr - Pointer to option buffer.
+//
+// Returns: TDI_STATUS code of attempt.
+//
+TDI_STATUS
+TdiOpenAddress(PTDI_REQUEST Request, TRANSPORT_ADDRESS UNALIGNED *AddrList,
+ uint Protocol, void *Ptr)
+{
+ uint i; // Index variable
+ ushort Port; // Local Port we'll use.
+ IPAddr LocalAddr; // Actual address we'll use.
+ AddrObj *NewAO; // New AO we'll use.
+ AddrObj *ExistingAO; // Pointer to existing AO, if any.
+ CTELockHandle Handle;
+ uchar Reuse, DHCPAddr;
+
+
+ if (!GetAddress(AddrList, &LocalAddr, &Port))
+ return TDI_BAD_ADDR;
+
+ // Find the address options we might need.
+ GetAddrOptions(Ptr, &Reuse, &DHCPAddr);
+
+ // Allocate the new addr obj now, assuming that
+ // we need it, so we don't have to do it with locks held later.
+ NewAO = CTEAllocMem(sizeof(AddrObj));
+
+ if (NewAO != NULL) {
+#ifdef VXD
+ uint NewAOIndex;
+#endif
+ CTEMemSet(NewAO, 0, sizeof(AddrObj));
+
+ // Check to make sure IP address is one of our local addresses. This
+ // is protected with the address table lock, so we can interlock an IP
+ // address going away through DHCP.
+ CTEGetLock(&AddrObjTableLock, &Handle);
+
+ if (!IP_ADDR_EQUAL(LocalAddr, NULL_IP_ADDR)) { // Not a wildcard.
+
+ // Call IP to find out if this is a local address.
+
+ if ((*LocalNetInfo.ipi_getaddrtype)(LocalAddr) != DEST_LOCAL) {
+ // Not a local address. Fail the request.
+ CTEFreeLock(&AddrObjTableLock, Handle);
+ CTEFreeMem(NewAO);
+ return TDI_BAD_ADDR;
+ }
+ }
+
+ // The specified IP address is a valid local address. Now we do
+ // protocol-specific processing.
+
+ switch (Protocol) {
+
+#ifndef UDP_ONLY
+ case PROTOCOL_TCP:
+#endif
+ case PROTOCOL_UDP:
+
+ // If no port is specified we have to assign one. If there is a
+ // port specified, we need to make sure that the IPAddress/Port
+ // combo isn't already open (unless Reuse is specified). If the
+ // input address is a wildcard, we need to make sure the address
+ // isn't open on any local ip address.
+
+ if (Port == WILDCARD_PORT) { // Have a wildcard port, need to assign an
+ // address.
+ Port = NextUserPort;
+
+ for (i = 0; i < NUM_USER_PORTS; i++, Port++) {
+ ushort NetPort; // Port in net byte order.
+
+ if (Port > MaxUserPort)
+ Port = MIN_USER_PORT;
+
+ NetPort = net_short(Port);
+
+ if (IP_ADDR_EQUAL(LocalAddr, NULL_IP_ADDR)) // Wildcard IP
+ // address.
+ ExistingAO = FindAnyAddrObj(NetPort, (uchar)Protocol);
+ else
+ ExistingAO = GetBestAddrObj(LocalAddr, NetPort, (uchar)Protocol);
+
+ if (ExistingAO == NULL)
+ break; // Found an unused port.
+ }
+
+ if (i == NUM_USER_PORTS) { // Couldn't find a free port.
+ CTEFreeLock(&AddrObjTableLock, Handle);
+ CTEFreeMem(NewAO);
+ return TDI_NO_FREE_ADDR;
+ }
+ NextUserPort = Port + 1;
+ Port = net_short(Port);
+ } else { // Address was specificed
+
+ // Don't check if a DHCP address is specified.
+ if (!DHCPAddr) {
+ if (IP_ADDR_EQUAL(LocalAddr, NULL_IP_ADDR)) // Wildcard IP
+ ExistingAO = FindAnyAddrObj(Port, (uchar)Protocol); // address.
+ else
+ ExistingAO = GetBestAddrObj(LocalAddr, Port, (uchar)Protocol);
+
+ if (ExistingAO != NULL) { // We already have this address open.
+ // If the caller hasn't asked for Reuse, fail the request.
+ if (!Reuse) {
+ CTEFreeLock(&AddrObjTableLock, Handle);
+ CTEFreeMem(NewAO);
+ return TDI_ADDR_IN_USE;
+ }
+ }
+ }
+ }
+
+ //
+ // We have a new AO. Set up the protocol specific portions
+ //
+ if (Protocol == PROTOCOL_UDP) {
+ NewAO->ao_dgsend = UDPSend;
+ NewAO->ao_maxdgsize = 0xFFFF - sizeof(UDPHeader);
+ }
+
+ SET_AO_XSUM(NewAO); // Checksumming defaults to on.
+
+ break;
+ // end case TCP & UDP
+
+ default:
+ //
+ // All other protocols are opened over Raw IP. For now we don't
+ // do any duplicate checks.
+ //
+
+ CTEAssert(!DHCPAddr);
+
+ //
+ // We must set the port to zero. This puts all the raw sockets
+ // in one hash bucket, which is necessary for GetAddrObj to
+ // work correctly. It wouldn't be a bad idea to come up with
+ // a better scheme...
+ //
+ Port = 0;
+ NewAO->ao_dgsend = RawSend;
+ NewAO->ao_maxdgsize = 0xFFFF;
+ NewAO->ao_flags |= AO_RAW_FLAG;
+
+ IF_TCPDBG(TCP_DEBUG_RAW) {
+ TCPTRACE(("raw open protocol %u AO %lx\n", Protocol, NewAO));
+ }
+ break;
+ }
+
+ // When we get here, we know we're creating a brand new address object.
+ // Port contains the port in question, and NewAO points to the newly
+ // created AO.
+
+ (*LocalNetInfo.ipi_initopts)(&NewAO->ao_opt);
+
+ (*LocalNetInfo.ipi_initopts)(&NewAO->ao_mcastopt);
+
+ NewAO->ao_mcastopt.ioi_ttl = 1;
+ NewAO->ao_mcastaddr = NULL_IP_ADDR;
+
+ CTEInitLock(&NewAO->ao_lock);
+ CTEInitEvent(&NewAO->ao_event, RequestEventProc);
+ INITQ(&NewAO->ao_sendq);
+ INITQ(&NewAO->ao_rcvq);
+ INITQ(&NewAO->ao_activeq);
+ INITQ(&NewAO->ao_idleq);
+ INITQ(&NewAO->ao_listenq);
+ NewAO->ao_port = Port;
+ NewAO->ao_addr = LocalAddr;
+ NewAO->ao_prot = (uchar)Protocol;
+#ifdef DEBUG
+ NewAO->ao_sig = ao_signature;
+#endif
+ NewAO->ao_flags |= AO_VALID_FLAG; // AO is valid.
+
+ if (DHCPAddr)
+ NewAO->ao_flags |= AO_DHCP_FLAG;
+
+#ifdef VXD
+ NewAOIndex = GetAOIndex(NewAO);
+ if (NewAOIndex == INVALID_INDEX) {
+ CTEFreeLock(&AddrObjTableLock, Handle);
+ CTEFreeMem(NewAO);
+ return TDI_NO_RESOURCES;
+ }
+#endif
+
+ InsertAddrObj(NewAO);
+ CTEFreeLock(&AddrObjTableLock, Handle);
+#ifdef VXD
+ Request->Handle.AddressHandle = (PVOID)NewAOIndex;
+#else
+ Request->Handle.AddressHandle = NewAO;
+#endif
+ return TDI_SUCCESS;
+ } else { // Couldn't allocate an address object.
+ return TDI_NO_RESOURCES;
+ }
+
+
+}
+
+//* DeleteAO - Delete an address object.
+//
+// The internal routine to delete an address object. We complete any pending
+// requests with errors, and remove and free the address object.
+//
+// Input: DeletedAO - AddrObj to be deleted.
+//
+// Returns: Nothing.
+//
+void
+DeleteAO(AddrObj *DeletedAO)
+{
+ CTELockHandle TableHandle, AOHandle; // Lock handles we'll use here.
+ CTELockHandle HeaderHandle;
+#ifndef UDP_ONLY
+ CTELockHandle ConnHandle, TCBHandle;
+ TCB *TCBHead = NULL, *CurrentTCB;
+ TCPConn *Conn;
+ Queue *Temp;
+ Queue *CurrentQ;
+#endif
+ AOMCastAddr *AMA;
+
+ CTEStructAssert(DeletedAO, ao);
+ CTEAssert(!AO_VALID(DeletedAO));
+ CTEAssert(DeletedAO->ao_usecnt == 0);
+
+ CTEGetLock(&AddrObjTableLock, &TableHandle);
+#ifndef UDP_ONLY
+ CTEGetLock(&ConnTableLock, &ConnHandle);
+#endif
+ CTEGetLock(&DGSendReqLock, &HeaderHandle);
+ CTEGetLock(&DeletedAO->ao_lock, &AOHandle);
+
+ // If he's on an oor queue, remove him.
+ if (AO_OOR(DeletedAO))
+ REMOVEQ(&DeletedAO->ao_pendq);
+
+#ifdef VXD
+ (*AOIndex)[DeletedAO->ao_index] = NULL;
+#endif
+
+ RemoveAddrObj(DeletedAO);
+
+#ifndef UDP_ONLY
+ // Walk down the list of associated connections and zap their AO pointers.
+ // For each connection, we need to shut down the connection if it's active.
+ // If the connection isn't already closing, we'll put a reference on it
+ // so that it can't go away while we're dealing with the AO, and put it
+ // on a list. On our way out we'll walk down that list and zap each
+ // connection.
+ CurrentQ = &DeletedAO->ao_activeq;
+
+ for (;;) {
+ Temp = QHEAD(CurrentQ);
+ while (Temp != QEND(CurrentQ)) {
+ Conn = QSTRUCT(TCPConn, Temp, tc_q);
+
+ CTEStructAssert(Conn, tc);
+ CurrentTCB = Conn->tc_tcb;
+ if (CurrentTCB != NULL) {
+ // We have a TCB.
+ CTEStructAssert(CurrentTCB, tcb);
+ CTEGetLock(&CurrentTCB->tcb_lock, &TCBHandle);
+ if (CurrentTCB->tcb_state != TCB_CLOSED && !CLOSING(CurrentTCB)) {
+ // It's not closing. Put a reference on it and save it on the
+ // list.
+ CurrentTCB->tcb_refcnt++;
+ CurrentTCB->tcb_aonext = TCBHead;
+ TCBHead = CurrentTCB;
+ }
+ CurrentTCB->tcb_conn = NULL;
+ CurrentTCB->tcb_rcvind = NULL;
+ CTEFreeLock(&CurrentTCB->tcb_lock, TCBHandle);
+ }
+
+ // Destroy the pointers to the TCB and the AO.
+ Conn->tc_ao = NULL;
+ Conn->tc_tcb = NULL;
+ Temp = QNEXT(Temp);
+ }
+
+ if (CurrentQ == &DeletedAO->ao_activeq) {
+ CurrentQ = &DeletedAO->ao_idleq;
+ } else if (CurrentQ == &DeletedAO->ao_idleq) {
+ CurrentQ = &DeletedAO->ao_listenq;
+ } else {
+ CTEAssert(CurrentQ == &DeletedAO->ao_listenq);
+ break;
+ }
+ }
+#endif
+
+ // We've removed him from the queues, and he's marked as invalid. Return
+ // pending requests with errors.
+
+#ifndef UDP_ONLY
+ CTEFreeLock(&DGSendReqLock, AOHandle);
+ CTEFreeLock(&ConnTableLock, HeaderHandle);
+ CTEFreeLock(&AddrObjTableLock, ConnHandle);
+#else
+ CTEFreeLock(&DGSendReqLock, AOHandle);
+ CTEFreeLock(&AddrObjTableLock, HeaderHandle);
+#endif
+
+ // We still hold the lock on the AddrObj, although this may not be
+ // neccessary.
+
+ while (!EMPTYQ(&DeletedAO->ao_rcvq)) {
+ DGRcvReq *Rcv;
+
+ DEQUEUE(&DeletedAO->ao_rcvq, Rcv, DGRcvReq, drr_q);
+ CTEStructAssert(Rcv, drr);
+
+ CTEFreeLock(&DeletedAO->ao_lock, TableHandle);
+ (*Rcv->drr_rtn)(Rcv->drr_context, (uint) TDI_ADDR_DELETED, 0);
+
+ FreeDGRcvReq(Rcv);
+
+ CTEGetLock(&DeletedAO->ao_lock, &TableHandle);
+ }
+
+ // Now destroy any sends.
+ while (!EMPTYQ(&DeletedAO->ao_sendq)) {
+ DGSendReq *Send;
+
+ DEQUEUE(&DeletedAO->ao_sendq, Send, DGSendReq, dsr_q);
+ CTEStructAssert(Send, dsr);
+
+ CTEFreeLock(&DeletedAO->ao_lock, TableHandle);
+ (*Send->dsr_rtn)(Send->dsr_context, (uint) TDI_ADDR_DELETED, 0);
+
+ CTEGetLock(&DGSendReqLock, &HeaderHandle);
+ if (Send->dsr_header != NULL)
+ FreeDGHeader(Send->dsr_header);
+ FreeDGSendReq(Send);
+ CTEFreeLock(&DGSendReqLock, HeaderHandle);
+
+ CTEGetLock(&DeletedAO->ao_lock, &TableHandle);
+ }
+
+ CTEFreeLock(&DeletedAO->ao_lock, TableHandle);
+
+ // Free any IP options we have.
+ (*LocalNetInfo.ipi_freeopts)(&DeletedAO->ao_opt);
+
+ // Free any associated multicast addresses.
+
+ AMA = DeletedAO->ao_mcastlist;
+ while (AMA != NULL) {
+ AOMCastAddr *Temp;
+
+ (*LocalNetInfo.ipi_setmcastaddr)(AMA->ama_addr, AMA->ama_if, FALSE);
+ Temp = AMA;
+ AMA = AMA->ama_next;
+ CTEFreeMem(Temp);
+ }
+
+ CTEFreeMem(DeletedAO);
+
+#ifndef UDP_ONLY
+ // Now go down the TCB list, and destroy any we need to.
+ CurrentTCB = TCBHead;
+ while (CurrentTCB != NULL) {
+ TCB *NextTCB;
+ CTEGetLock(&CurrentTCB->tcb_lock, &TCBHandle);
+ CurrentTCB->tcb_refcnt--;
+ CurrentTCB->tcb_flags |= NEED_RST; // Make sure we send a RST.
+ NextTCB = CurrentTCB->tcb_aonext;
+ TryToCloseTCB(CurrentTCB, TCB_CLOSE_ABORTED, TCBHandle);
+ CurrentTCB = NextTCB;
+ }
+#endif
+
+
+}
+
+//* GetAORequest - Get an AO request structure.
+//
+// A routine to allocate a request structure from our free list.
+//
+// Input: Nothing.
+//
+// Returns: Pointer to request structure, or NULL if we couldn't get one.
+//
+AORequest *
+GetAORequest()
+{
+ AORequest *NewRequest;
+ CTELockHandle Handle;
+
+ CTEGetLock(&AORequestLock, &Handle);
+
+ NewRequest = AORequestFree;
+ if (NewRequest != NULL) {
+ AORequestFree = (AORequest *)NewRequest->aor_rtn;
+ CTEStructAssert(NewRequest, aor);
+ }
+
+ CTEFreeLock(&AORequestLock, Handle);
+ return NewRequest;
+}
+
+//* FreeAORequest - Free an AO request structure.
+//
+// Called to free an AORequest structure.
+//
+// Input: Request - AORequest structure to be freed.
+//
+// Returns: Nothing.
+//
+void
+FreeAORequest(AORequest *Request)
+{
+ CTELockHandle Handle;
+
+ CTEStructAssert(Request, aor);
+
+ CTEGetLock(&AORequestLock, &Handle);
+
+ *(AORequest **)&Request->aor_rtn = AORequestFree;
+ AORequestFree = Request;
+
+ CTEFreeLock(&AORequestLock, Handle);
+}
+
+
+
+//* TDICloseAddress - Close an address.
+//
+// The user API to delete an address. Basically, we destroy the local address
+// object if we can.
+//
+// This routine is interlocked with the AO busy bit - if the busy bit is set,
+// we'll just flag the AO for later deletion.
+//
+// Input: Request - TDI_REQUEST structure for this request.
+//
+// Returns: Status of attempt to delete the address - either pending or
+// success.
+//
+TDI_STATUS
+TdiCloseAddress(PTDI_REQUEST Request)
+{
+ AddrObj *DeletingAO;
+ CTELockHandle AOHandle;
+
+#ifdef VXD
+ DeletingAO = GetIndexedAO((uint)Request->Handle.AddressHandle);
+ if (DeletingAO == NULL)
+ return TDI_ADDR_INVALID;
+#else
+ DeletingAO = Request->Handle.AddressHandle;
+#endif
+
+ CTEStructAssert(DeletingAO, ao);
+
+ CTEGetLock(&DeletingAO->ao_lock, &AOHandle);
+
+ if (!AO_BUSY(DeletingAO) && !(DeletingAO->ao_usecnt)) {
+ SET_AO_BUSY(DeletingAO);
+ SET_AO_INVALID(DeletingAO); // This address object is
+ // deleting.
+ CTEFreeLock(&DeletingAO->ao_lock, AOHandle);
+ DeleteAO(DeletingAO);
+ return TDI_SUCCESS;
+ } else {
+
+ AORequest *NewRequest, *OldRequest;
+ CTEReqCmpltRtn CmpltRtn;
+ PVOID ReqContext;
+ TDI_STATUS Status;
+
+ // Check and see if we already have a delete in progress. If we don't
+ // allocate and link up a delete request structure.
+ if (!AO_REQUEST(DeletingAO, AO_DELETE)) {
+
+ OldRequest = DeletingAO->ao_request;
+
+ NewRequest = GetAORequest();
+
+ if (NewRequest != NULL) { // Got a request.
+ NewRequest->aor_rtn = Request->RequestNotifyObject;
+ NewRequest->aor_context = Request->RequestContext;
+ CLEAR_AO_REQUEST(DeletingAO, AO_OPTIONS); // Clear the option
+ // request,
+ // if there is one.
+ SET_AO_REQUEST(DeletingAO, AO_DELETE);
+ SET_AO_INVALID(DeletingAO); // This address
+ // object is
+ // deleting.
+ DeletingAO->ao_request = NewRequest;
+ NewRequest->aor_next = NULL;
+ CTEFreeLock(&DeletingAO->ao_lock, AOHandle);
+
+ while (OldRequest != NULL) {
+ AORequest *Temp;
+
+ CmpltRtn = OldRequest->aor_rtn;
+ ReqContext = OldRequest->aor_context;
+
+ (*CmpltRtn)(ReqContext, (uint) TDI_ADDR_DELETED, 0);
+ Temp = OldRequest;
+ OldRequest = OldRequest->aor_next;
+ FreeAORequest(Temp);
+ }
+
+ return TDI_PENDING;
+ } else
+ Status = TDI_NO_RESOURCES;
+ } else // Delete already in progress.
+ Status = TDI_ADDR_INVALID;
+
+ CTEFreeLock(&DeletingAO->ao_lock, AOHandle);
+ return Status;
+ }
+
+}
+
+//* FindAOMCastAddr - Find a multicast address on an AddrObj.
+//
+// A utility routine to find a multicast address on an AddrObj. We also return
+// a pointer to it's predecessor, for use in deleting.
+//
+// Input: AO - AddrObj to search.
+// Addr - MCast address to search for.
+// IF - IPAddress of interface
+// PrevAMA - Pointer to where to return predecessor.
+//
+// Returns: Pointer to matching AMA structure, or NULL if there is none.
+//
+AOMCastAddr *
+FindAOMCastAddr(AddrObj *AO, IPAddr Addr, IPAddr IF, AOMCastAddr **PrevAMA)
+{
+ AOMCastAddr *FoundAMA, *Temp;
+
+ Temp = STRUCT_OF(AOMCastAddr, &AO->ao_mcastlist, ama_next);
+ FoundAMA = AO->ao_mcastlist;
+
+ while (FoundAMA != NULL) {
+ if (IP_ADDR_EQUAL(Addr, FoundAMA->ama_addr) &&
+ IP_ADDR_EQUAL(IF, FoundAMA->ama_if))
+ break;
+ Temp = FoundAMA;
+ FoundAMA = FoundAMA->ama_next;
+ }
+
+ *PrevAMA = Temp;
+ return FoundAMA;
+}
+
+//* MCastAddrOnAO - Test to see if a multicast address on an AddrObj.
+//
+// A utility routine to test to see if a multicast address is on an AddrObj.
+//
+// Input: AO - AddrObj to search.
+// Addr - MCast address to search for.
+//
+// Returns: TRUE is Addr is on AO.
+//
+uint
+MCastAddrOnAO(AddrObj *AO, IPAddr Addr)
+{
+ AOMCastAddr *FoundAMA;
+
+ FoundAMA = AO->ao_mcastlist;
+
+ while (FoundAMA != NULL) {
+ if (IP_ADDR_EQUAL(Addr, FoundAMA->ama_addr))
+ return(TRUE);
+ FoundAMA = FoundAMA->ama_next;
+ }
+ return(FALSE);
+}
+
+//* SetAOOptions - Set AddrObj options.
+//
+// The set options worker routine, called when we've validated the buffer
+// and know that the AddrObj isn't busy.
+//
+// Input: OptionAO - AddrObj for which options are being set.
+// Options - AOOption buffer of options.
+//
+// Returns: TDI_STATUS of attempt.
+//
+TDI_STATUS
+SetAOOptions(AddrObj *OptionAO, uint ID, uint Length, uchar *Options)
+{
+ IP_STATUS IPStatus; // Status of IP option set request.
+ CTELockHandle Handle;
+ TDI_STATUS Status;
+ AOMCastAddr *AMA, *PrevAMA;
+
+ CTEAssert(AO_BUSY(OptionAO));
+
+ // First, see if there are IP options.
+
+ if (ID == AO_OPTION_IPOPTIONS) {
+ IF_TCPDBG(TCP_DEBUG_OPTIONS) {
+ TCPTRACE(("processing IP_IOTIONS on AO %lx\n", OptionAO));
+ }
+ // These are IP options. Pass them down.
+ (*LocalNetInfo.ipi_freeopts)(&OptionAO->ao_opt);
+
+ IPStatus = (*LocalNetInfo.ipi_copyopts)(Options, Length,
+ &OptionAO->ao_opt);
+
+ if (IPStatus == IP_SUCCESS)
+ return TDI_SUCCESS;
+ else if (IPStatus == IP_NO_RESOURCES)
+ return TDI_NO_RESOURCES;
+ else
+ return TDI_BAD_OPTION;
+ }
+
+ // These are UDP/TCP options.
+ if (Length == 0)
+ return TDI_BAD_OPTION;
+
+ Status = TDI_SUCCESS;
+ CTEGetLock(&OptionAO->ao_lock, &Handle);
+
+ switch (ID) {
+
+ case AO_OPTION_XSUM:
+ if (Options[0])
+ SET_AO_XSUM(OptionAO);
+ else
+ CLEAR_AO_XSUM(OptionAO);
+ break;
+
+ case AO_OPTION_IP_DONTFRAGMENT:
+ IF_TCPDBG(TCP_DEBUG_OPTIONS) {
+ TCPTRACE((
+ "DF opt %u, initial flags %lx on AO %lx\n",
+ (int) Options[0], OptionAO->ao_opt.ioi_flags, OptionAO
+ ));
+ }
+
+ if (Options[0])
+ OptionAO->ao_opt.ioi_flags |= IP_FLAG_DF;
+ else
+ OptionAO->ao_opt.ioi_flags &= ~IP_FLAG_DF;
+
+ IF_TCPDBG(TCP_DEBUG_OPTIONS) {
+ TCPTRACE((
+ "New flags %lx on AO %lx\n",
+ OptionAO->ao_opt.ioi_flags, OptionAO
+ ));
+ }
+
+ break;
+
+ case AO_OPTION_TTL:
+ IF_TCPDBG(TCP_DEBUG_OPTIONS) {
+ TCPTRACE((
+ "setting TTL to %d on AO %lx\n", Options[0], OptionAO
+ ));
+ }
+ OptionAO->ao_opt.ioi_ttl = Options[0];
+ break;
+
+ case AO_OPTION_TOS:
+ IF_TCPDBG(TCP_DEBUG_OPTIONS) {
+ TCPTRACE((
+ "setting TOS to %d on AO %lx\n", Options[0], OptionAO
+ ));
+ }
+ OptionAO->ao_opt.ioi_tos = Options[0];
+ break;
+
+ case AO_OPTION_MCASTTTL:
+ OptionAO->ao_mcastopt.ioi_ttl = Options[0];
+ break;
+
+ case AO_OPTION_MCASTIF:
+ if (Length >= sizeof(UDPMCastIFReq)) {
+ UDPMCastIFReq *Req;
+ IPAddr Addr;
+
+ Req = (UDPMCastIFReq *)Options;
+ Addr = Req->umi_addr;
+ if (!IP_ADDR_EQUAL(Addr, NULL_IP_ADDR) &&
+ (*LocalNetInfo.ipi_getaddrtype)(Addr) != DEST_LOCAL)
+ {
+ Status = TDI_BAD_OPTION;
+ }
+ else {
+ OptionAO->ao_mcastaddr = Addr;
+ }
+ } else
+ Status = TDI_BAD_OPTION;
+ break;
+
+ case AO_OPTION_ADD_MCAST:
+ case AO_OPTION_DEL_MCAST:
+ if (Length >= sizeof(UDPMCastReq)) {
+ UDPMCastReq *Req = (UDPMCastReq *)Options;
+
+ AMA = FindAOMCastAddr(OptionAO, Req->umr_addr, Req->umr_if,
+ &PrevAMA);
+
+ if (ID == AO_OPTION_ADD_MCAST) {
+ if (AMA != NULL) {
+ Status = TDI_BAD_OPTION;
+ break;
+ }
+ AMA = CTEAllocMem(sizeof(AOMCastAddr));
+ if (AMA == NULL) {
+ // Couldn't get the resource we need.
+ Status = TDI_NO_RESOURCES;
+ break;
+ }
+
+ AMA->ama_next = OptionAO->ao_mcastlist;
+ OptionAO->ao_mcastlist = AMA;
+
+ AMA->ama_addr = Req->umr_addr;
+ AMA->ama_if = Req->umr_if;
+
+ } else {
+ // This is a delete request. Fail it if it's not there.
+ if (AMA == NULL) {
+ Status = TDI_BAD_OPTION;
+ break;
+ }
+
+ PrevAMA->ama_next = AMA->ama_next;
+ CTEFreeMem(AMA);
+ }
+
+ IPStatus = (*LocalNetInfo.ipi_setmcastaddr)(Req->umr_addr,
+ Req->umr_if, ID == AO_OPTION_ADD_MCAST ? TRUE : FALSE);
+
+ if (IPStatus != TDI_SUCCESS) {
+ // Some problem adding or deleting. If we were adding, we
+ // need to free the one we just added.
+ if (ID == AO_OPTION_ADD_MCAST) {
+ AMA = FindAOMCastAddr(OptionAO, Req->umr_addr,
+ Req->umr_if, &PrevAMA);
+ if (AMA != NULL) {
+ PrevAMA->ama_next = AMA->ama_next;
+ CTEFreeMem(AMA);
+ } else
+ DEBUGCHK;
+ }
+
+ Status = (IPStatus == IP_NO_RESOURCES ? TDI_NO_RESOURCES :
+ TDI_BAD_OPTION);
+ }
+
+ } else
+ Status = TDI_BAD_OPTION;
+ break;
+
+ default:
+ Status = TDI_BAD_OPTION;
+ break;
+ }
+
+ CTEFreeLock(&OptionAO->ao_lock, Handle);
+
+ return Status;
+
+}
+
+//* SetAddrOptions - Set options on an address object.
+//
+// Called to set options on an address object. We validate the buffer,
+// and if everything is OK we'll check the status of the AddrObj. If
+// it's OK then we'll set them, otherwise we'll mark it for later use.
+//
+// Input: Request - Request describing AddrObj for option set.
+// ID - ID for option to be set.
+// OptLength - Length of options.
+// Options - Pointer to options.
+//
+// Returns: TDI_STATUS of attempt.
+//
+TDI_STATUS
+SetAddrOptions(PTDI_REQUEST Request, uint ID, uint OptLength, void *Options)
+{
+ AddrObj *OptionAO;
+ TDI_STATUS Status;
+
+ CTELockHandle AOHandle;
+
+#ifdef VXD
+ OptionAO = GetIndexedAO((uint)Request->Handle.AddressHandle);
+ if (OptionAO == NULL)
+ return TDI_ADDR_INVALID;
+#else
+ OptionAO = Request->Handle.AddressHandle;
+#endif
+
+ CTEStructAssert(OptionAO, ao);
+
+ CTEGetLock(&OptionAO->ao_lock, &AOHandle);
+
+ if (AO_VALID(OptionAO)) {
+ if (!AO_BUSY(OptionAO) && OptionAO->ao_usecnt == 0) {
+ SET_AO_BUSY(OptionAO);
+ CTEFreeLock(&OptionAO->ao_lock, AOHandle);
+
+ Status = SetAOOptions(OptionAO, ID, OptLength, Options);
+
+ CTEGetLock(&OptionAO->ao_lock, &AOHandle);
+ if (!AO_PENDING(OptionAO)) {
+ CLEAR_AO_BUSY(OptionAO);
+ CTEFreeLock(&OptionAO->ao_lock, AOHandle);
+ return Status;
+ } else {
+ CTEFreeLock(&OptionAO->ao_lock, AOHandle);
+ ProcessAORequests(OptionAO);
+ return Status;
+ }
+ } else {
+ AORequest *NewRequest, *OldRequest;
+
+ // The AddrObj is busy somehow. We need to get a request, and link
+ // him on the request list.
+
+ NewRequest = GetAORequest();
+
+ if (NewRequest != NULL) { // Got a request.
+ NewRequest->aor_rtn = Request->RequestNotifyObject;
+ NewRequest->aor_context = Request->RequestContext;
+ NewRequest->aor_id = ID;
+ NewRequest->aor_length = OptLength;
+ NewRequest->aor_buffer = Options;
+ SET_AO_REQUEST(OptionAO, AO_OPTIONS); // Set the
+ // option request,
+ OldRequest = STRUCT_OF(AORequest, &OptionAO->ao_request,
+ aor_next);
+
+ while (OldRequest->aor_next != NULL)
+ OldRequest = OldRequest->aor_next;
+
+ OldRequest->aor_next = NewRequest;
+ CTEFreeLock(&OptionAO->ao_lock, AOHandle);
+
+ return TDI_PENDING;
+ } else
+ Status = TDI_NO_RESOURCES;
+
+ }
+ } else
+ Status = TDI_ADDR_INVALID;
+
+ CTEFreeLock(&OptionAO->ao_lock, AOHandle);
+ return Status;
+
+}
+
+//* TDISetEvent - Set a handler for a particular event.
+//
+// This is the user API to set an event. It's pretty simple, we just
+// grab the lock on the AddrObj and fill in the event.
+//
+//
+// Input: Handle - Pointer to address object.
+// Type - Event being set.
+// Handler - Handler to call for event.
+// Context - Context to pass to event.
+//
+// Returns: TDI_SUCCESS if it works, an error if it doesn't. This routine
+// never pends.
+//
+TDI_STATUS
+TdiSetEvent(PVOID Handle, int Type, PVOID Handler, PVOID Context)
+{
+ AddrObj *EventAO;
+ CTELockHandle AOHandle;
+ TDI_STATUS Status;
+
+#ifdef VXD
+ EventAO = GetIndexedAO((uint)Handle);
+
+ CTEStructAssert(EventAO, ao);
+ if (EventAO == NULL || !AO_VALID(EventAO))
+ return TDI_ADDR_INVALID;
+#else
+ EventAO = (AddrObj *)Handle;
+
+ CTEStructAssert(EventAO, ao);
+ if (!AO_VALID(EventAO))
+ return TDI_ADDR_INVALID;
+#endif
+
+
+ CTEGetLock(&EventAO->ao_lock, &AOHandle);
+
+ Status = TDI_SUCCESS;
+ switch (Type) {
+
+ case TDI_EVENT_CONNECT:
+ EventAO->ao_connect = Handler;
+ EventAO->ao_conncontext = Context;
+ break;
+ case TDI_EVENT_DISCONNECT:
+ EventAO->ao_disconnect = Handler;
+ EventAO->ao_disconncontext = Context;
+ break;
+ case TDI_EVENT_ERROR:
+ EventAO->ao_error = Handler;
+ EventAO->ao_errcontext = Context;
+ break;
+ case TDI_EVENT_RECEIVE:
+ EventAO->ao_rcv = Handler;
+ EventAO->ao_rcvcontext = Context;
+ break;
+ case TDI_EVENT_RECEIVE_DATAGRAM:
+ EventAO->ao_rcvdg = Handler;
+ EventAO->ao_rcvdgcontext = Context;
+ break;
+ case TDI_EVENT_RECEIVE_EXPEDITED:
+ EventAO->ao_exprcv = Handler;
+ EventAO->ao_exprcvcontext = Context;
+ break;
+ default:
+ Status = TDI_BAD_EVENT_TYPE;
+ break;
+ }
+
+ CTEFreeLock(&EventAO->ao_lock, AOHandle);
+ return Status;
+
+
+}
+
+//* ProcessAORequests - Process pending requests on an AddrObj.
+//
+// This is the delayed request processing routine, called when we've
+// done something that used the busy bit. We examine the pending
+// requests flags, and dispatch the requests appropriately.
+//
+// Input: RequestAO - AddrObj to be processed.
+//
+// Returns: Nothing.
+//
+void
+ProcessAORequests(AddrObj *RequestAO)
+{
+ CTELockHandle AOHandle;
+ AORequest *Request;
+
+ CTEStructAssert(RequestAO, ao);
+ CTEAssert(AO_BUSY(RequestAO));
+ CTEAssert(RequestAO->ao_usecnt == 0);
+
+ CTEGetLock(&RequestAO->ao_lock, &AOHandle);
+
+ while (AO_PENDING(RequestAO)) {
+ Request = RequestAO->ao_request;
+
+ if (AO_REQUEST(RequestAO, AO_DELETE)) {
+ CTEAssert(Request != NULL);
+ CTEAssert(!AO_REQUEST(RequestAO, AO_OPTIONS));
+ CTEFreeLock(&RequestAO->ao_lock, AOHandle);
+ DeleteAO(RequestAO);
+ (*Request->aor_rtn)(Request->aor_context, TDI_SUCCESS, 0);
+ FreeAORequest(Request);
+ return; // Deleted him, so get out.
+ }
+
+ // Now handle options request.
+ while (AO_REQUEST(RequestAO, AO_OPTIONS)) {
+ TDI_STATUS Status;
+
+ // Have an option request.
+ Request = RequestAO->ao_request;
+ RequestAO->ao_request = Request->aor_next;
+ if (RequestAO->ao_request == NULL)
+ CLEAR_AO_REQUEST(RequestAO, AO_OPTIONS);
+
+ CTEAssert(Request != NULL);
+ CTEFreeLock(&RequestAO->ao_lock, AOHandle);
+
+ Status = SetAOOptions(RequestAO, Request->aor_id,
+ Request->aor_length, Request->aor_buffer);
+ (*Request->aor_rtn)(Request->aor_context, Status, 0);
+ FreeAORequest(Request);
+
+ CTEGetLock(&RequestAO->ao_lock, &AOHandle);
+ }
+
+ // We've done options, now try sends.
+ if (AO_REQUEST(RequestAO, AO_SEND)) {
+ DGSendReq *SendReq;
+
+ // Need to send. Clear the busy flag, bump the send count, and
+ // get the send request.
+ if (!EMPTYQ(&RequestAO->ao_sendq)) {
+ DEQUEUE(&RequestAO->ao_sendq, SendReq, DGSendReq, dsr_q);
+ CLEAR_AO_BUSY(RequestAO);
+ RequestAO->ao_usecnt++;
+ CTEFreeLock(&RequestAO->ao_lock, AOHandle);
+ UDPSend(RequestAO, SendReq);
+ CTEGetLock(&RequestAO->ao_lock, &AOHandle);
+ // If there aren't any other pending sends, set the busy bit.
+ if (!(--RequestAO->ao_usecnt))
+ SET_AO_BUSY(RequestAO);
+ else
+ break; // Still sending, so get out.
+ } else {
+ // Had the send request set, but no send! Odd....
+ DEBUGCHK;
+ CLEAR_AO_REQUEST(RequestAO, AO_SEND);
+ }
+
+ }
+ }
+
+ // We're done here.
+ CLEAR_AO_BUSY(RequestAO);
+ CTEFreeLock(&RequestAO->ao_lock, AOHandle);
+
+}
+
+
+//* DelayDerefAO - Derefrence an AddrObj, and schedule an event.
+//
+// Called when we are done with an address object, and need to
+// derefrence it. We dec the usecount, and if it goes to 0 and
+// if there are pending actions we'll schedule an event to deal
+// with them.
+//
+// Input: RequestAO - AddrObj to be processed.
+//
+// Returns: Nothing.
+//
+void
+DelayDerefAO(AddrObj *RequestAO)
+{
+ CTELockHandle Handle;
+
+ CTEGetLock(&RequestAO->ao_lock, &Handle);
+
+ RequestAO->ao_usecnt--;
+
+ if (!RequestAO->ao_usecnt && !AO_BUSY(RequestAO)) {
+ if (AO_PENDING(RequestAO)) {
+ SET_AO_BUSY(RequestAO);
+ CTEFreeLock(&RequestAO->ao_lock, Handle);
+ CTEScheduleEvent(&RequestAO->ao_event, RequestAO);
+ return;
+ }
+ }
+ CTEFreeLock(&RequestAO->ao_lock, Handle);
+
+}
+
+//* DerefAO - Derefrence an AddrObj.
+//
+// Called when we are done with an address object, and need to
+// derefrence it. We dec the usecount, and if it goes to 0 and
+// if there are pending actions we'll call the process AO handler.
+//
+// Input: RequestAO - AddrObj to be processed.
+//
+// Returns: Nothing.
+//
+void
+DerefAO(AddrObj *RequestAO)
+{
+ CTELockHandle Handle;
+
+ CTEGetLock(&RequestAO->ao_lock, &Handle);
+
+ RequestAO->ao_usecnt--;
+
+ if (!RequestAO->ao_usecnt && !AO_BUSY(RequestAO)) {
+ if (AO_PENDING(RequestAO)) {
+ SET_AO_BUSY(RequestAO);
+ CTEFreeLock(&RequestAO->ao_lock, Handle);
+ ProcessAORequests(RequestAO);
+ return;
+ }
+ }
+
+ CTEFreeLock(&RequestAO->ao_lock, Handle);
+
+}
+
+#pragma BEGIN_INIT
+
+//* InitAddr - Initialize the address object stuff.
+//
+// Called during init time to initalize the address object stuff.
+//
+// Input: Nothing
+//
+// Returns: True if we succeed, False if we fail.
+//
+int
+InitAddr()
+{
+ AORequest *RequestPtr;
+ int i;
+
+ CTEInitLock(&AddrObjTableLock);
+ CTEInitLock(&AORequestLock);
+
+#ifdef VXD
+ AOInstance = 1;
+
+ AOIndexSize = DEFAULT_AO_INDEX_SIZE;
+ NextAOIndex = 0;
+
+ AOIndex = CTEAllocMem(sizeof(AddrObj *) * DEFAULT_AO_INDEX_SIZE);
+ if (AOIndex == NULL)
+ return FALSE;
+
+#endif
+
+ RequestPtr = CTEAllocMem(sizeof(AORequest)*NUM_AO_REQUEST);
+ if (RequestPtr == NULL) {
+#ifdef VXD
+ CTEFreeMem(AOIndex);
+#endif
+ return FALSE;
+ }
+
+ AORequestFree = NULL;
+
+ for (i = 0; i < NUM_AO_REQUEST; i++, RequestPtr++) {
+#ifdef DEBUG
+ RequestPtr->aor_sig = aor_signature;
+#endif
+ FreeAORequest(RequestPtr);
+ }
+
+ for (i = 0; i < AO_TABLE_SIZE; i++)
+ AddrObjTable[i] = NULL;
+
+ LastAO = NULL;
+
+ return TRUE;
+
+}
+#pragma END_INIT
diff --git a/private/ntos/tdi/tcpip/tcp/addr.h b/private/ntos/tdi/tcpip/tcp/addr.h
new file mode 100644
index 000000000..78ec23ce3
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/addr.h
@@ -0,0 +1,211 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** ADDR.H - TDI address object definitions.
+//
+// This file contains the definitions of TDI address objects and related
+// constants and structures.
+
+#define ao_signature 0x20204F41 // 'AO '
+
+#define AO_TABLE_SIZE 16 // Address object hash table size.
+
+#define WILDCARD_PORT 0 // 0 means assign a port.
+
+#define MIN_USER_PORT 1025 // Minimum value for a wildcard port
+#define MAX_USER_PORT 5000 // Maximim value for a user port.
+#define NUM_USER_PORTS (uint)(MaxUserPort - MIN_USER_PORT + 1)
+
+#define NETBT_SESSION_PORT 139
+
+typedef struct AddrObj AddrObj;
+
+//* Datagram transport-specific send function.
+typedef void (*DGSendProc)(AddrObj *SrcAO, void *SendReq);
+
+//* Definition of the structure of an address object. Each object represents
+// a local address, and the IP portion may be a wildcard.
+
+struct AddrObj {
+#ifdef DEBUG
+ ulong ao_sig;
+#endif
+ struct AddrObj *ao_next; // Pointer to next address object in chain.
+ DEFINE_LOCK_STRUCTURE(ao_lock) // Lock for this object.
+ struct AORequest *ao_request;// Pointer to pending request.
+ Queue ao_sendq; // Queue of sends waiting for transmission.
+ Queue ao_pendq; // Linkage for pending queue.
+ Queue ao_rcvq; // Receive queue.
+ IPOptInfo ao_opt; // Opt info for this address object.
+ IPAddr ao_addr; // IP address for this address object.
+ ushort ao_port; // Local port for this address object.
+ ushort ao_flags; // Flags for this object.
+ uchar ao_prot; // Protocol for this AO.
+ uchar ao_index; // Index into table of this AO.
+ uchar ao_pad[2]; // PAD PAD PAD
+ uint ao_listencnt; // Number of listening connections.
+ ushort ao_usecnt; // Count of 'uses' on AO.
+ ushort ao_inst; // 'Instance' number of this AO.
+ IPOptInfo ao_mcastopt;// MCast opt info.
+ IPAddr ao_mcastaddr; // Source address for MCast from
+ // this addr object..
+ Queue ao_activeq; // Queue of active connections.
+ Queue ao_idleq; // Queue of inactive (no TCB) connections.
+ Queue ao_listenq; // Queue of listening connections.
+ CTEEvent ao_event; // Event to use for this AO.
+ PConnectEvent ao_connect; // Connect event handle.
+ PVOID ao_conncontext; // Receive DG context.
+ PDisconnectEvent ao_disconnect; // Disconnect event routine.
+ PVOID ao_disconncontext; // Disconnect event context.
+ PErrorEvent ao_error; // Error event routine.
+ PVOID ao_errcontext; // Error event context.
+ PRcvEvent ao_rcv; // Receive event handler
+ PVOID ao_rcvcontext; // Receive context.
+ PRcvDGEvent ao_rcvdg; // Receive DG event handler
+ PVOID ao_rcvdgcontext; // Receive DG context.
+ PRcvEvent ao_exprcv; // Expedited receive event handler
+ PVOID ao_exprcvcontext; // Expedited receive context.
+ struct AOMCastAddr *ao_mcastlist; // List of active multicast
+ // addresses.
+ DGSendProc ao_dgsend; // Datagram transport send function.
+ ushort ao_maxdgsize; // maximum user datagram size.
+#ifdef SYN_ATTACK
+ BOOLEAN ConnLimitReached; //set when there are no
+ //connections left
+#endif
+}; /* AddrObj */
+
+typedef struct AddrObj AddrObj;
+
+#define AO_RAW_FLAG 0x0200 // AO is for a raw endpoint.
+#define AO_DHCP_FLAG 0x0100 // AO is bound to real 0 address.
+
+#define AO_VALID_FLAG 0x0080 // AddrObj is valid.
+#define AO_BUSY_FLAG 0x0040 // AddrObj is busy (i.e., has it
+ // exclusive).
+#define AO_OOR_FLAG 0x0020 // AddrObj is out of resources, and on
+ // either the pending or delayed queue.
+#define AO_QUEUED_FLAG 0x0010 // AddrObj is on the pending queue.
+
+
+#define AO_XSUM_FLAG 0x0008 // Xsums are used on this AO.
+#define AO_SEND_FLAG 0x0004 // Send is pending.
+#define AO_OPTIONS_FLAG 0x0002 // Option set pending.
+#define AO_DELETE_FLAG 0x0001 // Delete pending.
+
+
+#define AO_VALID(A) ((A)->ao_flags & AO_VALID_FLAG)
+#define SET_AO_INVALID(A) (A)->ao_flags &= ~AO_VALID_FLAG
+
+#define AO_BUSY(A) ((A)->ao_flags & AO_BUSY_FLAG)
+#define SET_AO_BUSY(A) (A)->ao_flags |= AO_BUSY_FLAG
+#define CLEAR_AO_BUSY(A) (A)->ao_flags &= ~AO_BUSY_FLAG
+
+#define AO_OOR(A) ((A)->ao_flags & AO_OOR_FLAG)
+#define SET_AO_OOR(A) (A)->ao_flags |= AO_OOR_FLAG
+#define CLEAR_AO_OOR(A) (A)->ao_flags &= ~AO_OOR_FLAG
+
+#define AO_QUEUED(A) ((A)->ao_flags & AO_QUEUED_FLAG)
+#define SET_AO_QUEUED(A) (A)->ao_flags |= AO_QUEUED_FLAG
+#define CLEAR_AO_QUEUED(A) (A)->ao_flags &= ~AO_QUEUED_FLAG
+
+#define AO_XSUM(A) ((A)->ao_flags & AO_XSUM_FLAG)
+#define SET_AO_XSUM(A) (A)->ao_flags |= AO_XSUM_FLAG
+#define CLEAR_AO_XSUM(A) (A)->ao_flags &= ~AO_XSUM_FLAG
+
+#define AO_REQUEST(A, f) ((A)->ao_flags & f##_FLAG)
+#define SET_AO_REQUEST(A, f) (A)->ao_flags |= f##_FLAG
+#define CLEAR_AO_REQUEST(A, f) (A)->ao_flags &= ~f##_FLAG
+#define AO_PENDING(A) ((A)->ao_flags & (AO_DELETE_FLAG | AO_OPTIONS_FLAG | AO_SEND_FLAG))
+
+//* Definition of an address object search context. This is a data structure used
+// when the address object table is to be read sequentially.
+
+struct AOSearchContext {
+ AddrObj *asc_previous; // Previous AO found.
+ IPAddr asc_addr; // IPAddress to be found.
+ ushort asc_port; // Port to be found.
+ uchar asc_prot; // Protocol
+ uchar asc_pad; // Pad to dword boundary.
+}; /* AOSearchContext */
+
+typedef struct AOSearchContext AOSearchContext;
+
+//* Definition of an AO request structure. There structures are used only for
+// queuing delete and option set requests.
+
+#define aor_signature 0x20524F41
+
+struct AORequest {
+#ifdef DEBUG
+ ulong aor_sig;
+#endif
+ struct AORequest *aor_next; // Next pointer in chain.
+ uint aor_id; // ID for the request.
+ uint aor_length; // Length of buffer.
+ void *aor_buffer; // Buffer for this request.
+ CTEReqCmpltRtn aor_rtn; // Request complete routine for this request.
+ PVOID aor_context; // Request context;
+}; /* AORequest */
+
+typedef struct AORequest AORequest;
+
+typedef struct AOMCastAddr {
+ struct AOMCastAddr *ama_next; // Next in list.
+ IPAddr ama_addr; // The address.
+ IPAddr ama_if; // The interface.
+} AOMCastAddr;
+
+//* External declarations for exported functions.
+
+extern AddrObj *GetAddrObj(IPAddr LocalAddr, ushort LocalPort, uchar Prot,
+ AddrObj *PreviousAO);
+extern AddrObj *GetNextAddrObj(AOSearchContext *SearchContext);
+extern AddrObj *GetFirstAddrObj(IPAddr LocalAddr, ushort LocalPort, uchar Prot,
+ AOSearchContext *SearchContext);
+extern TDI_STATUS TdiOpenAddress(PTDI_REQUEST Request,
+ TRANSPORT_ADDRESS UNALIGNED *AddrList, uint Protocol,
+ void *Reuse);
+extern TDI_STATUS TdiCloseAddress(PTDI_REQUEST Request);
+extern TDI_STATUS SetAddrOptions(PTDI_REQUEST Request, uint ID, uint OptLength,
+ void *Options);
+extern TDI_STATUS TdiSetEvent(PVOID Handle, int Type, PVOID Handler,
+ PVOID Context);
+extern uchar GetAddress(TRANSPORT_ADDRESS UNALIGNED *AddrList,
+ IPAddr *Addr, ushort *Port);
+extern int InitAddr(void);
+extern void ProcessAORequests(AddrObj *RequestAO);
+extern void DelayDerefAO(AddrObj *RequestAO);
+extern void DerefAO(AddrObj *RequestAO);
+extern void FreeAORequest(AORequest *FreedRequest);
+#ifdef VXD
+extern AddrObj *GetIndexedAO(uint Index);
+#endif
+extern uint ValidateAOContext(void *Context, uint *Valid);
+extern uint ReadNextAO(void *Context, void *OutBuf);
+extern void InvalidateAddrs(IPAddr Addr);
+
+extern uint MCastAddrOnAO(AddrObj *AO, IPAddr Addr);
+
+#define GetBestAddrObj(addr, port, prot) GetAddrObj(addr, port, prot, NULL)
+
+#define REF_AO(a) (a)->ao_usecnt++
+
+#define DELAY_DEREF_AO(a) DelayDerefAO((a))
+#define DEREF_AO(a) DerefAO((a))
+#define LOCKED_DELAY_DEREF_AO(a) (a)->ao_usecnt--; \
+\
+ if (!(a)->ao_usecnt && !AO_BUSY((a)) && AO_PENDING((a))) { \
+ SET_AO_BUSY((a)); \
+ CTEScheduleEvent(&(a)->ao_event, (a)); \
+ }
+
+
+
+
+
+
+
diff --git a/private/ntos/tdi/tcpip/tcp/alpha/sources b/private/ntos/tdi/tcpip/tcp/alpha/sources
new file mode 100644
index 000000000..6a4917025
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/alpha/sources
@@ -0,0 +1,3 @@
+ALPHA_SOURCES= \
+ ..\alpha\xsum.s
+
diff --git a/private/ntos/tdi/tcpip/tcp/alpha/xsum.s b/private/ntos/tdi/tcpip/tcp/alpha/xsum.s
new file mode 100644
index 000000000..032d40747
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/alpha/xsum.s
@@ -0,0 +1,271 @@
+// TITLE("Compute Checksum")
+//++
+//
+// Copyright (c) 1994 Microsoft Corporation
+//
+// Module Name:
+//
+// xsum.s
+//
+// Abstract:
+//
+// This module implements a function to compute the checksum of a buffer.
+//
+// Author:
+//
+// John Vert (jvert) 11-Jul-1994
+//
+// Environment:
+//
+// Revision History:
+//
+//--
+
+#include "ksalpha.h"
+
+
+ SBTTL("Compute Checksum")
+//++
+//
+// ULONG
+// tcpxsum (
+// IN ULONG Checksum,
+// IN PUSHORT Source,
+// IN ULONG Length
+// )
+//
+// Routine Description:
+//
+// This function computes the checksum of the specified buffer.
+//
+// Arguments:
+//
+// Checksum (a0) - Supplies the initial checksum value.
+//
+// Source (a1) - Supplies a pointer to the checksum buffer
+//
+// Length (a2) - Supplies the length of the buffer in words.
+//
+// Return Value:
+//
+// The computed checksum is returned as the function value.
+//
+//--
+
+ LEAF_ENTRY(tcpxsum)
+ zap a0, 0xf0, a0 // clear high half of a0
+ bis a1, zero, t6 // save initial buffer address
+ bis zero, zero, v0 // clear accumulated checksum
+
+//
+// Check if the buffer is quadword aligned.
+//
+// If the buffer is not quadword aligned, then add the leading words to the
+// checksum.
+//
+ ldq_u t0, 0(a1) // get containing quadword of first part
+ blbc a1, 10f // check for word alignment
+ beq a2, 65f // if zero bytes, don't do anything
+ extbl t0, a1, t1 // get leading byte
+ sll t1, 8, v0 // shift it to correct spot for later byte swap
+ addq a1, 1, a1 // increment buffer to first full word
+ subq a2, 1, a2 // decrement byte count
+
+10:
+ and a1, 6, t2 // check if buffer quadword aligned
+ beq t2, 20f // if eq, quadword aligned
+ extql t0, t2, t0 // extract bytes to checksum
+ and a1, 7, t3 // compute bytes summed
+ subq zero, t3, t3
+ addq t3, 8, t3
+ addq a1, 8, a1 // advance buffer address to next qword
+ bic a1, 7, a1 //
+ subq a2, t3, t2
+ blt t2, 55f // if ltz, too many, jump to residual code
+
+ addq v0, t0, v0 // add bytes to partial checksum
+ cmpult v0, t0, t1 // generate carry
+ addq t1, v0, v0 // add carry back into checksum
+
+ bis t2, zero, a2 // reduce count of bytes to checksum
+ beq t2, 60f // if eq, no more bytes
+
+20:
+//
+// Compute the checksum in 64-byte blocks
+//
+ bic a2, 7, t4 // subtract out residual bytes
+ beq t4, 40f // if eq, no quadwords to checksum
+ subq zero, t4, t2 // compute negative of byte count
+ and t2, 15 << 2, t3 // compute bytes in first iteration
+ ldq t0, 0(a1) // get first quadword to checksum
+ beq t3, 35f // if eq, full 64-byte block
+ subq a1, t3, a1 // bias buffer address by offset
+ bic t4, 64-1, t4 // subtract out bytes in first iteration
+ lda t2, 30f // get base address of code vector
+ addl t3, t3, t3 //
+ addq t3, t2, t2 // compute code vector offset
+ bis t0, zero, t1 // copy first quadword to checksum
+ jmp (t2) // dispatch
+
+
+30:
+//
+// The following code vector computes the checksum of a 64-byte block.
+//
+.set noreorder
+ ldq t1, 8(a1)
+ addq v0, t0, v0
+ cmpult v0, t0, t2
+ addq v0, t2, v0
+
+ ldq t0, 16(a1)
+ addq v0, t1, v0
+ cmpult v0, t1, t2
+ addq v0, t2, v0
+
+ ldq t1, 24(a1)
+ addq v0, t0, v0
+ cmpult v0, t0, t2
+ addq v0, t2, v0
+
+ ldq t0, 32(a1)
+ addq v0, t1, v0
+ cmpult v0, t1, t2
+ addq v0, t2, v0
+
+ ldq t1, 40(a1)
+ addq v0, t0, v0
+ cmpult v0, t0, t2
+ addq v0, t2, v0
+
+ ldq t0, 48(a1)
+ addq v0, t1, v0
+ cmpult v0, t1, t2
+ addq v0, t2, v0
+
+ ldq t1, 56(a1)
+ addq v0, t0, v0
+ cmpult v0, t0, t2
+ addq v0, t2, v0
+
+ addq a1, 64, a1
+ addq v0, t1, v0
+ cmpult v0, t1, t2
+ addq v0, t2, v0
+.set reorder
+
+ beq t4, 40f // if zero, end of block
+
+35:
+ ldq t0, 0(a1)
+//
+// The following loop is allowed to be reordered by the assembler for
+// optimal scheduling. It is never branched into.
+//
+ subq t4, 64, t4 // reduce byte count of longwords
+
+ ldq t1, 8(a1)
+ addq v0, t0, v0
+ cmpult v0, t0, t2
+ addq v0, t2, v0
+
+ ldq t0, 16(a1)
+ addq v0, t1, v0
+ cmpult v0, t1, t2
+ addq v0, t2, v0
+
+ ldq t1, 24(a1)
+ addq v0, t0, v0
+ cmpult v0, t0, t2
+ addq v0, t2, v0
+
+ ldq t0, 32(a1)
+ addq v0, t1, v0
+ cmpult v0, t1, t2
+ addq v0, t2, v0
+
+ ldq t1, 40(a1)
+ addq v0, t0, v0
+ cmpult v0, t0, t2
+ addq v0, t2, v0
+
+ ldq t0, 48(a1)
+ addq v0, t1, v0
+ cmpult v0, t1, t2
+ addq v0, t2, v0
+
+ ldq t1, 56(a1)
+ addq v0, t0, v0
+ cmpult v0, t0, t2
+ addq v0, t2, v0
+
+ addq a1, 64, a1
+ addq v0, t1, v0
+ cmpult v0, t1, t2
+ addq v0, t2, v0
+
+ bne t4, 35b // if ne zero, not end of block
+
+40:
+//
+// Check for any remaining bytes.
+//
+ and a2, 7, a2 // isolate residual bytes
+ beq a2, 60f // if eq, no residual bytes
+50:
+//
+// Checksum remaining bytes.
+//
+// The technique we use here is to load the final quadword, then
+// zero out the bytes that are not included.
+//
+ ldq t0, 0(a1) // get quadword surrounding remainder
+55:
+ ornot zero, zero, t1 // get FF mask
+ sll t1, a2, t2 // shift to produce byte mask
+ zap t0, t2, t0 // zero out bytes past end of buffer
+ addq v0, t0, v0 // add quadword to partial checksum
+ cmpult v0, t0, t1 // generate carry
+ addq t1, v0, v0 // add carry back into checksum
+60:
+//
+// Byte swap the 64-bit checksum if the start of the buffer was not word aligned
+//
+ blbc t6, 65f
+ zap v0, 0xAA, t0 // isolate even bytes
+ sll t0, 8, t0 // shift even bytes into odd positions
+ srl v0, 8, t1 // shift odd bytes into even positions
+ zap t1, 0xAA, t1 // isolate odd bytes
+ bis t0, t1, v0 // merge bytes back together
+
+65:
+//
+// add computed checksum to original checksum, and fold the 64-bit
+// result down to 16 bits.
+//
+ addq v0, a0, v0 // add computed checksum to original
+ cmpult v0, a0, t0 // generate carry
+ addq v0, t0, v0 // add carry back into checksum
+
+//
+// swap the longwords in order to sum two longwords and their carry in one add.
+//
+ sll v0, 32, t0 // shift low longword into high
+ srl v0, 32, t1 // shift high longword into low
+ bis t1, t0, t5 // merge back together
+
+ addq v0, t5, t0 // produce sum + carry in high longword
+ srl t0, 32, t1 // shift back down to low half
+//
+// swap the words in order to sum two words and their carry in one add
+//
+ sll t1, 16, t2 // shift high word into low
+ srl t1, 16, t3 // shift low word into high
+ bis t2, t3, t4 // merge back together
+ addq t4, t1, t2 // produce sum and carry in high word
+ extwl t2, 2, v0 // extract result.
+ ret zero, (ra) // return
+
+ .end tcpxsum
+
diff --git a/private/ntos/tdi/tcpip/tcp/dgram.c b/private/ntos/tdi/tcpip/tcp/dgram.c
new file mode 100644
index 000000000..c0ada18c5
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/dgram.c
@@ -0,0 +1,990 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** DGRAM.C - Common datagram protocol code.
+//
+// This file contains the code common to both UDP and Raw IP.
+//
+
+#include "oscfg.h"
+#include "ndis.h"
+#include "cxport.h"
+#include "ip.h"
+#include "tdi.h"
+#include "tdistat.h"
+#ifdef VXD
+#include "tdivxd.h"
+#endif
+#ifdef NT
+#include "tdint.h"
+#include "tdistat.h"
+#endif
+#include "queue.h"
+#include "addr.h"
+#include "dgram.h"
+#include "tlcommon.h"
+#include "info.h"
+
+#define NO_TCP_DEFS 1
+#include "tcpdeb.h"
+
+#ifdef NT
+
+#ifdef POOL_TAGGING
+
+#ifdef ExAllocatePool
+#undef ExAllocatePool
+#endif
+
+#define ExAllocatePool(type, size) ExAllocatePoolWithTag(type, size, 'dPCT')
+
+#ifndef CTEAllocMem
+#error "CTEAllocMem is not already defined - will override tagging"
+#else
+#undef CTEAllocMem
+#endif
+
+#define CTEAllocMem(size) ExAllocatePoolWithTag(NonPagedPool, size, 'dPCT')
+
+#endif // POOL_TAGGING
+
+#endif // NT
+
+#define NUM_DG_HEADERS 5
+
+#ifdef NT
+#define DG_MAX_HDRS 0xffff
+#else
+#define DG_MAX_HDRS 100
+#endif
+
+ulong DGCurrentSendFree = 0;
+ulong DGMaxSendFree = DG_MAX_HDRS;
+
+EXTERNAL_LOCK(AddrObjTableLock)
+
+DGSendReq *DGSendReqFree;
+DEFINE_LOCK_STRUCTURE(DGSendReqLock)
+
+#ifndef NT
+DGRcvReq *DGRcvReqFree;
+#else
+SLIST_HEADER DGRcvReqFree;
+#endif
+
+DEFINE_LOCK_STRUCTURE(DGRcvReqFreeLock)
+
+#ifdef DEBUG
+uint NumSendReq = 0;
+uint NumRcvReq = 0;
+#endif
+
+// Information for maintaining the DG Header structures and
+// pending queue.
+uint DGHeaderSize;
+PNDIS_BUFFER DGHeaderList;
+Queue DGHeaderPending;
+Queue DGDelayed;
+
+CTEEvent DGDelayedEvent;
+
+extern IPInfo LocalNetInfo;
+
+typedef struct DGHdrBPoolEntry {
+ struct DGHdrBPoolEntry *uhe_next;
+ NDIS_HANDLE uhe_handle;
+ uchar *uhe_buffer;
+} DGHdrBPoolEntry;
+
+DGHdrBPoolEntry *DGHdrBPoolList = NULL;
+
+//
+// All of the init code can be discarded.
+//
+#ifdef NT
+#ifdef ALLOC_PRAGMA
+
+int InitDG(uint MaxHeaderSize);
+
+#pragma alloc_text(INIT, InitDG)
+
+#endif // ALLOC_PRAGMA
+#endif
+
+#ifdef CHICAGO
+extern int RegisterAddrChangeHndlr(void *Handler, uint Add);
+extern void AddrChange(IPAddr Addr, IPMask Mask, void *Context,
+ uint Added);
+#endif
+
+
+
+//* GrowDGHeaderList - Try to grow the DG header list.
+//
+// Called when we run out of buffers on the DG header list, and need
+// to grow it. We look to see if we're already at the maximum size, and
+// if not we'll allocate the need structures and free them to the list.
+// This routine must be called with the SendReq lock held.
+//
+// Input: Nothing.
+//
+// Returns: A pointer to a new DG header buffer if we have one, or NULL.
+//
+PNDIS_BUFFER
+GrowDGHeaderList(void)
+{
+ DGHdrBPoolEntry *NewEntry;
+ NDIS_STATUS Status;
+ uint HeaderSize;
+ uchar *DGSendHP;
+ uint i;
+ PNDIS_BUFFER Buffer;
+ PNDIS_BUFFER ReturnBuffer = NULL;
+
+ if (DGCurrentSendFree < DGMaxSendFree) {
+
+ // Still room to grow the list.
+ NewEntry = CTEAllocMem(sizeof(DGHdrBPoolEntry));
+
+ if (NewEntry == NULL) {
+ // Couldn't get the memory.
+ return NULL;
+ }
+
+ NdisAllocateBufferPool(&Status, &NewEntry->uhe_handle,
+ NUM_DG_HEADERS);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ // Couldn't get a new set of buffers. Fail.
+ CTEFreeMem(NewEntry);
+ return NULL;
+ }
+
+ HeaderSize = DGHeaderSize + LocalNetInfo.ipi_hsize;
+
+ DGSendHP = CTEAllocMem(HeaderSize * NUM_DG_HEADERS);
+
+ if (DGSendHP == NULL) {
+ NdisFreeBufferPool(NewEntry->uhe_handle);
+ CTEFreeMem(NewEntry);
+ return NULL;
+ }
+
+ NewEntry->uhe_buffer = DGSendHP;
+
+ for (i = 0; i < NUM_DG_HEADERS; i++) {
+ NdisAllocateBuffer(&Status, &Buffer, NewEntry->uhe_handle,
+ DGSendHP + (i * HeaderSize), HeaderSize);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ NdisFreeBufferPool(NewEntry->uhe_handle);
+ CTEFreeMem(NewEntry);
+ CTEFreeMem(DGSendHP);
+ return NULL;
+ }
+ if (i != 0)
+ FreeDGHeader(Buffer);
+ else
+ ReturnBuffer = Buffer;
+ }
+
+ DGCurrentSendFree += NUM_DG_HEADERS;
+ NewEntry->uhe_next = DGHdrBPoolList;
+ DGHdrBPoolList = NewEntry;
+
+ } else {
+ // At the limit already.
+ ReturnBuffer = NULL;
+ }
+
+ return ReturnBuffer;
+
+
+}
+//* GetDGHeader - Get a DG header buffer.
+//
+// The get header buffer routine. Called with the SendReqLock held.
+//
+// Input: Nothing.
+//
+// Output: A pointer to an NDIS buffer, or NULL.
+//
+_inline PNDIS_BUFFER
+GetDGHeader(void)
+{
+ PNDIS_BUFFER NewBuffer;
+
+ NewBuffer = DGHeaderList;
+ if (NewBuffer != NULL)
+ DGHeaderList = NDIS_BUFFER_LINKAGE(NewBuffer);
+ else
+ NewBuffer = GrowDGHeaderList();
+
+ return NewBuffer;
+}
+
+//* FreeDGHeader - Free a DG header buffer.
+//
+// The free header buffer routine. Called with the SendReqLock held.
+//
+// Input: Buffer to be freed.
+//
+// Output: Nothing.
+//
+void
+FreeDGHeader(PNDIS_BUFFER FreedBuffer)
+{
+ NDIS_BUFFER_LINKAGE(FreedBuffer) = DGHeaderList;
+ DGHeaderList = FreedBuffer;
+}
+
+//* PutPendingQ - Put an address object on the pending queue.
+//
+// Called when we've experienced a header buffer out of resources condition,
+// and want to queue an AddrObj for later processing. We put the specified
+// address object on the DGHeaderPending queue, set the OOR flag and clear
+// the 'send request' flag. It is invariant in the system that the send
+// request flag and the OOR flag are not set at the same time.
+//
+// This routine assumes that the caller holds the DGSendReqLock and the
+// lock on the particular AddrObj.
+//
+// Input: QueueingAO - Pointer to address object to be queued.
+//
+// Returns: Nothing.
+//
+void
+PutPendingQ(AddrObj *QueueingAO)
+{
+ CTEStructAssert(QueueingAO, ao);
+
+ if (!AO_OOR(QueueingAO)) {
+ CLEAR_AO_REQUEST(QueueingAO, AO_SEND);
+ SET_AO_OOR(QueueingAO);
+
+ ENQUEUE(&DGHeaderPending, &QueueingAO->ao_pendq);
+ }
+}
+
+//* GetDGSendReq - Get a DG send request.
+//
+// Called when someone wants to allocate a DG send request. We assume
+// the send request lock is held when we are called.
+//
+// Note: This routine and the corresponding free routine might
+// be good candidates for inlining.
+//
+// Input: Nothing.
+//
+// Returns: Pointer to the SendReq, or NULL if none.
+//
+DGSendReq *
+GetDGSendReq()
+{
+ DGSendReq *NewReq;
+
+
+ NewReq = DGSendReqFree;
+ if (NewReq != NULL) {
+ CTEStructAssert(NewReq, dsr);
+ DGSendReqFree = (DGSendReq *)NewReq->dsr_q.q_next;
+ } else {
+ // Couldn't get a request, grow it. This is one area where we'll try
+ // to allocate memory with a lock held. Because of this, we've
+ // got to be careful about where we call this routine from.
+
+ NewReq = CTEAllocMem(sizeof(DGSendReq));
+ if (NewReq != NULL) {
+#ifdef DEBUG
+ NewReq->dsr_sig = dsr_signature;
+ NumSendReq++;
+#endif
+ }
+ }
+
+ return NewReq;
+}
+
+//* FreeDGSendReq - Free a DG send request.
+//
+// Called when someone wants to free a DG send request. It's assumed
+// that the caller holds the SendRequest lock.
+//
+// Input: SendReq - SendReq to be freed.
+//
+// Returns: Nothing.
+//
+void
+FreeDGSendReq(DGSendReq *SendReq)
+{
+ CTEStructAssert(SendReq, dsr);
+
+ *(DGSendReq **)&SendReq->dsr_q.q_next = DGSendReqFree;
+ DGSendReqFree = SendReq;
+}
+
+//* GetDGRcvReq - Get a DG receive request.
+//
+// Called when we need to get a DG receive request.
+//
+// Input: Nothing.
+//
+// Returns: Pointer to new request, or NULL if none.
+//
+DGRcvReq *
+GetDGRcvReq()
+{
+ DGRcvReq *NewReq;
+
+#ifdef VXD
+ NewReq = DGRcvReqFree;
+ if (NewReq != NULL) {
+ CTEStructAssert(NewReq, drr);
+ DGRcvReqFree = (DGRcvReq *)NewReq->drr_q.q_next;
+ } else {
+ // Couldn't get a request, grow it.
+ NewReq = CTEAllocMem(sizeof(DGRcvReq));
+ if (NewReq != NULL) {
+#ifdef DEBUG
+ NewReq->drr_sig = drr_signature;
+ NumRcvReq++;
+#endif
+ }
+ }
+
+#endif // VXD
+
+#ifdef NT
+ PSINGLE_LIST_ENTRY BufferLink;
+ Queue *QueuePtr;
+
+ BufferLink = ExInterlockedPopEntrySList(
+ &DGRcvReqFree,
+ &DGRcvReqFreeLock
+ );
+
+ if (BufferLink != NULL) {
+ QueuePtr = STRUCT_OF(Queue, BufferLink, q_next);
+ NewReq = STRUCT_OF(DGRcvReq, QueuePtr, drr_q);
+ CTEStructAssert(NewReq, drr);
+ }
+ else {
+ // Couldn't get a request, grow it.
+ NewReq = CTEAllocMem(sizeof(DGRcvReq));
+ if (NewReq != NULL) {
+#ifdef DEBUG
+ NewReq->drr_sig = drr_signature;
+ ExInterlockedAddUlong(&NumRcvReq, 1, &DGRcvReqFreeLock);
+#endif
+ }
+ }
+
+#endif // NT
+
+ return NewReq;
+}
+
+//* FreeDGRcvReq - Free a DG rcv request.
+//
+// Called when someone wants to free a DG rcv request.
+//
+// Input: RcvReq - RcvReq to be freed.
+//
+// Returns: Nothing.
+//
+void
+FreeDGRcvReq(DGRcvReq *RcvReq)
+{
+#ifdef VXD
+
+ CTEStructAssert(RcvReq, drr);
+
+ *(DGRcvReq **)&RcvReq->drr_q.q_next = DGRcvReqFree;
+ DGRcvReqFree = RcvReq;
+
+#endif // VXD
+
+#ifdef NT
+
+ PSINGLE_LIST_ENTRY BufferLink;
+
+ CTEStructAssert(RcvReq, drr);
+
+ BufferLink = STRUCT_OF(SINGLE_LIST_ENTRY, &(RcvReq->drr_q.q_next), Next);
+ ExInterlockedPushEntrySList(
+ &DGRcvReqFree,
+ BufferLink,
+ &DGRcvReqFreeLock
+ );
+
+#endif // NT
+}
+
+
+//* DGDelayedEventProc - Handle a delayed event.
+//
+// This is the delayed event handler, used for out-of-resources conditions
+// on AddrObjs. We pull from the delayed queue, and is the addr obj is
+// not already busy we'll send the datagram.
+//
+// Input: Event - Pointer to the event structure.
+// Context - Nothing.
+//
+// Returns: Nothing
+//
+void
+DGDelayedEventProc(CTEEvent *Event, void *Context)
+{
+ CTELockHandle HeaderHandle, AOHandle;
+ AddrObj *SendingAO;
+ DGSendProc SendProc;
+
+ CTEGetLock(&DGSendReqLock, &HeaderHandle);
+ while (!EMPTYQ(&DGDelayed)) {
+ DEQUEUE(&DGDelayed, SendingAO, AddrObj, ao_pendq);
+ CTEStructAssert(SendingAO, ao);
+
+ CTEGetLock(&SendingAO->ao_lock, &AOHandle);
+
+ CLEAR_AO_OOR(SendingAO);
+ if (!AO_BUSY(SendingAO)) {
+ DGSendReq *SendReq;
+
+ if (!EMPTYQ(&SendingAO->ao_sendq)) {
+ DEQUEUE(&SendingAO->ao_sendq, SendReq, DGSendReq, dsr_q);
+
+ CTEStructAssert(SendReq, dsr);
+ CTEAssert(SendReq->dsr_header != NULL);
+
+ SendingAO->ao_usecnt++;
+ SendProc = SendingAO->ao_dgsend;
+ CTEFreeLock(&SendingAO->ao_lock, AOHandle);
+ CTEFreeLock(&DGSendReqLock, HeaderHandle);
+
+ (*SendProc)(SendingAO, SendReq);
+ DEREF_AO(SendingAO);
+ CTEGetLock(&DGSendReqLock, &HeaderHandle);
+ } else {
+ CTEAssert(FALSE);
+ CTEFreeLock(&SendingAO->ao_lock, AOHandle);
+ }
+
+ } else {
+ SET_AO_REQUEST(SendingAO, AO_SEND);
+ CTEFreeLock(&SendingAO->ao_lock, AOHandle);
+ }
+ }
+
+ CTEFreeLock(&DGSendReqLock, HeaderHandle);
+
+}
+
+//* DGSendComplete - DG send complete handler.
+//
+// This is the routine called by IP when a send completes. We
+// take the context passed back as a pointer to a SendRequest
+// structure, and complete the caller's send.
+//
+// Input: Context - Context we gave on send (really a
+// SendRequest structure).
+// BufferChain - Chain of buffers sent.
+//
+// Returns: Nothing.
+void
+DGSendComplete(void *Context, PNDIS_BUFFER BufferChain)
+{
+ DGSendReq *FinishedSR = (DGSendReq *)Context;
+ CTELockHandle HeaderHandle, AOHandle;
+ CTEReqCmpltRtn Callback; // Completion routine.
+ PVOID CallbackContext; // User context.
+ ushort SentSize;
+ AddrObj *AO;
+
+ CTEStructAssert(FinishedSR, dsr);
+ CTEGetLock(&DGSendReqLock, &HeaderHandle);
+
+ Callback = FinishedSR->dsr_rtn;
+ CallbackContext = FinishedSR->dsr_context;
+ SentSize = FinishedSR->dsr_size;
+
+ // If there's nothing on the header pending queue, just free the
+ // header buffer. Otherwise pull from the pending queue, give him the
+ // resource, and schedule an event to deal with him.
+ if (EMPTYQ(&DGHeaderPending)) {
+ FreeDGHeader(BufferChain);
+ } else {
+ DEQUEUE(&DGHeaderPending, AO, AddrObj, ao_pendq);
+ CTEStructAssert(AO, ao);
+ CTEGetLock(&AO->ao_lock, &AOHandle);
+ if (!EMPTYQ(&AO->ao_sendq)) {
+ DGSendReq *SendReq;
+
+ PEEKQ(&AO->ao_sendq, SendReq, DGSendReq, dsr_q);
+ SendReq->dsr_header = BufferChain; // Give him this buffer.
+
+ ENQUEUE(&DGDelayed, &AO->ao_pendq);
+ CTEFreeLock(&AO->ao_lock, AOHandle);
+ CTEScheduleEvent(&DGDelayedEvent, NULL);
+ } else {
+ // On the pending queue, but no sends!
+ DEBUGCHK;
+ CLEAR_AO_OOR(AO);
+ CTEFreeLock(&AO->ao_lock, AOHandle);
+ }
+
+ }
+
+ FreeDGSendReq(FinishedSR);
+ CTEFreeLock(&DGSendReqLock, HeaderHandle);
+ if (Callback != NULL)
+ (*Callback)(CallbackContext, TDI_SUCCESS, (uint)SentSize);
+
+}
+
+
+#ifdef NT
+//
+// NT supports cancellation of DG send/receive requests.
+//
+
+#define TCP_DEBUG_SEND_DGRAM 0x00000100
+#define TCP_DEBUG_RECEIVE_DGRAM 0x00000200
+
+extern ULONG TCPDebug;
+
+
+VOID
+TdiCancelSendDatagram(
+ AddrObj *SrcAO,
+ PVOID Context
+ )
+{
+ CTELockHandle lockHandle;
+ DGSendReq *sendReq = NULL;
+ Queue *qentry;
+ BOOLEAN found = FALSE;
+
+
+ CTEStructAssert(SrcAO, ao);
+
+ CTEGetLock(&SrcAO->ao_lock, &lockHandle);
+
+ // Search the send list for the specified request.
+ for ( qentry = QNEXT(&(SrcAO->ao_sendq));
+ qentry != &(SrcAO->ao_sendq);
+ qentry = QNEXT(qentry)
+ ) {
+
+ sendReq = STRUCT_OF(DGSendReq, qentry, dsr_q);
+
+ CTEStructAssert(sendReq, dsr);
+
+ if (sendReq->dsr_context == Context) {
+ //
+ // Found it. Dequeue
+ //
+ REMOVEQ(qentry);
+ found = TRUE;
+
+ IF_TCPDBG(TCP_DEBUG_SEND_DGRAM) {
+ TCPTRACE((
+ "TdiCancelSendDatagram: Dequeued item %lx\n",
+ Context
+ ));
+ }
+
+ break;
+ }
+ }
+
+ CTEFreeLock(&SrcAO->ao_lock, lockHandle);
+
+ if (found) {
+ //
+ // Complete the request and free its resources.
+ //
+ (*sendReq->dsr_rtn)(sendReq->dsr_context, (uint) TDI_CANCELLED, 0);
+
+ CTEGetLock(&DGSendReqLock, &lockHandle);
+
+ if (sendReq->dsr_header != NULL) {
+ FreeDGHeader(sendReq->dsr_header);
+ }
+
+ FreeDGSendReq(sendReq);
+
+ CTEFreeLock(&DGSendReqLock, lockHandle);
+ }
+
+} // TdiCancelSendDatagram
+
+
+VOID
+TdiCancelReceiveDatagram(
+ AddrObj *SrcAO,
+ PVOID Context
+ )
+{
+ CTELockHandle lockHandle;
+ DGRcvReq *rcvReq = NULL;
+ Queue *qentry;
+ BOOLEAN found = FALSE;
+
+
+ CTEStructAssert(SrcAO, ao);
+
+ CTEGetLock(&SrcAO->ao_lock, &lockHandle);
+
+ // Search the send list for the specified request.
+ for ( qentry = QNEXT(&(SrcAO->ao_rcvq));
+ qentry != &(SrcAO->ao_rcvq);
+ qentry = QNEXT(qentry)
+ ) {
+
+ rcvReq = STRUCT_OF(DGRcvReq, qentry, drr_q);
+
+ CTEStructAssert(rcvReq, drr);
+
+ if (rcvReq->drr_context == Context) {
+ //
+ // Found it. Dequeue
+ //
+ REMOVEQ(qentry);
+ found = TRUE;
+
+ IF_TCPDBG(TCP_DEBUG_SEND_DGRAM) {
+ TCPTRACE((
+ "TdiCancelReceiveDatagram: Dequeued item %lx\n",
+ Context
+ ));
+ }
+
+ break;
+ }
+ }
+
+ CTEFreeLock(&SrcAO->ao_lock, lockHandle);
+
+ if (found) {
+ //
+ // Complete the request and free its resources.
+ //
+ (*rcvReq->drr_rtn)(rcvReq->drr_context, (uint) TDI_CANCELLED, 0);
+
+ FreeDGRcvReq(rcvReq);
+ }
+
+} // TdiCancelReceiveDatagram
+
+
+#endif // NT
+
+
+//** TdiSendDatagram - TDI send datagram function.
+//
+// This is the user interface to the send datagram function. The
+// caller specified a request structure, a connection info
+// structure containing the address, and data to be sent.
+// This routine gets a DG Send request structure to manage the
+// send, fills the structure in, and calls DGSend to deal with
+// it.
+//
+// Input: Request - Pointer to request structure.
+// ConnInfo - Pointer to ConnInfo structure which points to
+// remote address.
+// DataSize - Size in bytes of data to be sent.
+// BytesSent - Pointer to where to return size sent.
+// Buffer - Pointer to buffer chain.
+//
+// Returns: Status of attempt to send.
+//
+TDI_STATUS
+TdiSendDatagram(PTDI_REQUEST Request, PTDI_CONNECTION_INFORMATION ConnInfo,
+ uint DataSize, uint *BytesSent, PNDIS_BUFFER Buffer)
+{
+ AddrObj *SrcAO; // Pointer to AddrObj for src.
+ DGSendReq *SendReq; // Pointer to send req for this request.
+ CTELockHandle Handle, SRHandle; // Lock handles for the AO and the
+ // send request.
+ TDI_STATUS ReturnValue;
+ DGSendProc SendProc;
+
+ // First, get a send request. We do this first because of MP issues
+ // if we port this to NT. We need to take the SendRequest lock before
+ // we take the AddrObj lock, to prevent deadlock and also because
+ // GetDGSendReq might yield, and the state of the AddrObj might
+ // change on us, so we don't want to yield after we've validated
+ // it.
+
+ CTEGetLock(&DGSendReqLock, &SRHandle);
+ SendReq = GetDGSendReq();
+
+ // Now get the lock on the AO, and make sure it's valid. We do this
+ // to make sure we return the correct error code.
+
+#ifdef VXD
+ SrcAO = GetIndexedAO((uint)Request->Handle.AddressHandle);
+
+ if (SrcAO != NULL) {
+#else
+ SrcAO = Request->Handle.AddressHandle;
+#endif
+
+ CTEStructAssert(SrcAO, ao);
+
+ CTEGetLock(&SrcAO->ao_lock, &Handle);
+
+ if (AO_VALID(SrcAO)) {
+
+ // Make sure the size is reasonable.
+ if (DataSize <= SrcAO->ao_maxdgsize) {
+
+ // The AddrObj is valid. Now fill the address into the send request,
+ // if we've got one. If this works, we'll continue with the
+ // send.
+
+ if (SendReq != NULL) { // Got a send request.
+ if (GetAddress(ConnInfo->RemoteAddress, &SendReq->dsr_addr,
+ &SendReq->dsr_port)) {
+
+ SendReq->dsr_rtn = Request->RequestNotifyObject;
+ SendReq->dsr_context = Request->RequestContext;
+ SendReq->dsr_buffer = Buffer;
+ SendReq->dsr_size = (ushort)DataSize;
+
+ // We've filled in the send request. If the AO isn't
+ // already busy, try to get a DG header buffer and send
+ // this. If the AO is busy, or we can't get a buffer, queue
+ // until later. We try to get the header buffer here, as
+ // an optimazation to avoid having to retake the lock.
+
+ if (!AO_OOR(SrcAO)) { // AO isn't out of resources
+ if (!AO_BUSY(SrcAO)) { // or or busy
+
+ if ((SendReq->dsr_header = GetDGHeader()) != NULL) {
+ REF_AO(SrcAO); // Lock out exclusive
+ // activities.
+ SendProc = SrcAO->ao_dgsend;
+
+ CTEFreeLock(&SrcAO->ao_lock, Handle);
+ CTEFreeLock(&DGSendReqLock, SRHandle);
+
+ // Allright, just send it.
+ (*SendProc)(SrcAO, SendReq);
+
+ // See if any pending requests occured during
+ // the send. If so, call the request handler.
+ DEREF_AO(SrcAO);
+
+ return TDI_PENDING;
+ } else {
+ // We couldn't get a header buffer. Put this
+ // guy on the pending queue, and then fall
+ // through to the 'queue request' code.
+ PutPendingQ(SrcAO);
+ }
+ } else {
+ // AO is busy, set request for later
+ SET_AO_REQUEST(SrcAO, AO_SEND);
+ }
+ }
+
+ // AO is busy, or out of resources. Queue the send request
+ // for later.
+ SendReq->dsr_header = NULL;
+ ENQUEUE(&SrcAO->ao_sendq, &SendReq->dsr_q);
+ SendReq = NULL;
+ ReturnValue = TDI_PENDING;
+ }
+ else {
+ // The remote address was invalid.
+ ReturnValue = TDI_BAD_ADDR;
+ }
+ }
+ else {
+ // Send request was null, return no resources.
+ ReturnValue = TDI_NO_RESOURCES;
+ }
+ }
+ else {
+ // Buffer was too big, return an error.
+ ReturnValue = TDI_BUFFER_TOO_BIG;
+ }
+ }
+ else {
+ // The addr object is invalid, possibly because it's deleting.
+ ReturnValue = TDI_ADDR_INVALID;
+ }
+
+ CTEFreeLock(&SrcAO->ao_lock, Handle);
+
+#ifdef VXD
+ }
+ else {
+ ReturnValue = TDI_ADDR_INVALID;
+ }
+#endif
+
+ if (SendReq != NULL)
+ FreeDGSendReq(SendReq);
+
+ CTEFreeLock(&DGSendReqLock, SRHandle);
+
+ return TDI_ADDR_INVALID;
+}
+
+//** TdiReceiveDatagram - TDI receive datagram function.
+//
+// This is the user interface to the receive datagram function. The
+// caller specifies a request structure, a connection info
+// structure that acts as a filter on acceptable datagrams, a connection
+// info structure to be filled in, and other parameters. We get a DGRcvReq
+// structure, fill it in, and hang it on the AddrObj, where it will be removed
+// later by incomig datagram handler.
+//
+// Input: Request - Pointer to request structure.
+// ConnInfo - Pointer to ConnInfo structure which points to
+// remote address.
+// ReturnInfo - Pointer to ConnInfo structure to be filled in.
+// RcvSize - Total size in bytes receive buffer.
+// BytesRcvd - Pointer to where to return size received.
+// Buffer - Pointer to buffer chain.
+//
+// Returns: Status of attempt to receive.
+//
+TDI_STATUS
+TdiReceiveDatagram(PTDI_REQUEST Request, PTDI_CONNECTION_INFORMATION ConnInfo,
+ PTDI_CONNECTION_INFORMATION ReturnInfo, uint RcvSize, uint *BytesRcvd,
+ PNDIS_BUFFER Buffer)
+{
+ AddrObj *RcvAO; // AddrObj that is receiving.
+ DGRcvReq *RcvReq; // Receive request structure.
+ CTELockHandle AOHandle;
+ uchar AddrValid;
+
+ RcvReq = GetDGRcvReq();
+
+#ifdef VXD
+ RcvAO = GetIndexedAO((uint)Request->Handle.AddressHandle);
+
+ if (RcvAO != NULL) {
+ CTEStructAssert(RcvAO, ao);
+
+#else
+ RcvAO = Request->Handle.AddressHandle;
+ CTEStructAssert(RcvAO, ao);
+#endif
+
+ CTEGetLock(&RcvAO->ao_lock, &AOHandle);
+ if (AO_VALID(RcvAO)) {
+
+ IF_TCPDBG(TCP_DEBUG_RAW) {
+ TCPTRACE(("posting receive on AO %lx\n", RcvAO));
+ }
+
+ if (RcvReq != NULL) {
+ if (ConnInfo != NULL && ConnInfo->RemoteAddressLength != 0)
+ AddrValid = GetAddress(ConnInfo->RemoteAddress,
+ &RcvReq->drr_addr, &RcvReq->drr_port);
+ else {
+ AddrValid = TRUE;
+ RcvReq->drr_addr = NULL_IP_ADDR;
+ RcvReq->drr_port = 0;
+ }
+
+ if (AddrValid) {
+
+ // Everything'd valid. Fill in the receive request and queue it.
+ RcvReq->drr_conninfo = ReturnInfo;
+ RcvReq->drr_rtn = Request->RequestNotifyObject;
+ RcvReq->drr_context = Request->RequestContext;
+ RcvReq->drr_buffer = Buffer;
+ RcvReq->drr_size = RcvSize;
+ ENQUEUE(&RcvAO->ao_rcvq, &RcvReq->drr_q);
+ CTEFreeLock(&RcvAO->ao_lock, AOHandle);
+
+ return TDI_PENDING;
+ } else {
+ // Have an invalid filter address.
+ CTEFreeLock(&RcvAO->ao_lock, AOHandle);
+ FreeDGRcvReq(RcvReq);
+ return TDI_BAD_ADDR;
+ }
+ } else {
+ // Couldn't get a receive request.
+ CTEFreeLock(&RcvAO->ao_lock, AOHandle);
+ return TDI_NO_RESOURCES;
+ }
+ } else {
+ // The AddrObj isn't valid.
+ CTEFreeLock(&RcvAO->ao_lock, AOHandle);
+ }
+
+#ifdef VXD
+ }
+#endif
+
+ // The AddrObj is invalid or non-existent.
+ if (RcvReq != NULL)
+ FreeDGRcvReq(RcvReq);
+
+ return TDI_ADDR_INVALID;
+}
+
+
+#pragma BEGIN_INIT
+
+//* InitDG - Initialize the DG stuff.
+//
+// Called during init time to initalize the DG code. We initialize
+// our locks and request lists.
+//
+// Input: MaxHeaderSize - The maximum size of a datagram transport header,
+// not including the IP header.
+//
+// Returns: True if we succeed, False if we fail.
+//
+int
+InitDG(uint MaxHeaderSize)
+{
+ PNDIS_BUFFER Buffer;
+ CTELockHandle Handle;
+
+
+ DGHeaderSize = MaxHeaderSize;
+
+ CTEInitLock(&DGSendReqLock);
+ CTEInitLock(&DGRcvReqFreeLock);
+
+ DGSendReqFree = NULL;
+
+#ifndef NT
+ DGRcvReqFree = NULL;
+#else
+ ExInitializeSListHead(&DGRcvReqFree);
+#endif
+
+
+ CTEGetLock(&DGSendReqLock, &Handle);
+
+ Buffer = GrowDGHeaderList();
+
+ if (Buffer != NULL) {
+ FreeDGHeader(Buffer);
+ CTEFreeLock(&DGSendReqLock, Handle);
+ } else {
+ CTEFreeLock(&DGSendReqLock, Handle);
+ return FALSE;
+ }
+
+ INITQ(&DGHeaderPending);
+ INITQ(&DGDelayed);
+
+ CTEInitEvent(&DGDelayedEvent, DGDelayedEventProc);
+
+ return TRUE;
+}
+
+#pragma END_INIT
diff --git a/private/ntos/tdi/tcpip/tcp/dgram.h b/private/ntos/tdi/tcpip/tcp/dgram.h
new file mode 100644
index 000000000..a637a75e3
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/dgram.h
@@ -0,0 +1,89 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** DGRAM.H - Common datagram protocol definitions.
+//
+// This file contains definitions for the functions common to
+// both UDP and Raw IP.
+//
+
+#ifndef _DGRAM_INCLUDED_
+#define _DGRAM_INCLUDED_ 1
+
+
+//* Structure used for maintaining DG send requests.
+
+#define dsr_signature 0x20525338
+
+struct DGSendReq {
+#ifdef DEBUG
+ ulong dsr_sig;
+#endif
+ Queue dsr_q; // Queue linkage when pending.
+ IPAddr dsr_addr; // Remote IPAddr.
+ PNDIS_BUFFER dsr_buffer; // Buffer of data to send.
+ PNDIS_BUFFER dsr_header; // Pointer to header buffer.
+ CTEReqCmpltRtn dsr_rtn; // Completion routine.
+ PVOID dsr_context; // User context.
+ ushort dsr_size; // Size of buffer.
+ ushort dsr_port; // Remote port.
+}; /* DGSendReq */
+
+typedef struct DGSendReq DGSendReq;
+
+//* Structure used for maintaining DG receive requests.
+
+#define drr_signature 0x20525238
+
+struct DGRcvReq {
+#ifdef DEBUG
+ ulong drr_sig;
+#endif
+ Queue drr_q; // Queue linkage on AddrObj.
+ IPAddr drr_addr; // Remote IPAddr acceptable.
+ PNDIS_BUFFER drr_buffer; // Buffer to be filled in.
+ PTDI_CONNECTION_INFORMATION drr_conninfo; // Pointer to conn. info.
+ CTEReqCmpltRtn drr_rtn; // Completion routine.
+ PVOID drr_context; // User context.
+ ushort drr_size; // Size of buffer.
+ ushort drr_port; // Remote port acceptable.
+}; /* DGRcvReq */
+
+typedef struct DGRcvReq DGRcvReq;
+
+
+//* External definition of exported variables.
+EXTERNAL_LOCK(DGSendReqLock)
+EXTERNAL_LOCK(DGRcvReqFreeLock)
+extern CTEEvent DGDelayedEvent;
+
+
+//* External definition of exported functions.
+extern void DGSendComplete(void *Context, PNDIS_BUFFER BufferChain);
+
+extern TDI_STATUS TdiSendDatagram(PTDI_REQUEST Request,
+ PTDI_CONNECTION_INFORMATION ConnInfo, uint DataSize,
+ uint *BytesSent, PNDIS_BUFFER Buffer);
+
+extern TDI_STATUS TdiReceiveDatagram(PTDI_REQUEST Request,
+ PTDI_CONNECTION_INFORMATION ConnInfo,
+ PTDI_CONNECTION_INFORMATION ReturnInfo, uint RcvSize,
+ uint *BytesRcvd, PNDIS_BUFFER Buffer);
+
+extern IP_STATUS DGRcv(void *IPContext, IPAddr Dest, IPAddr Src, IPAddr LocalAddr,
+ IPRcvBuf *RcvBuf, uint Size, uchar IsBCast, uchar Protocol,
+ IPOptInfo *OptInfo);
+
+extern void FreeDGRcvReq(DGRcvReq *RcvReq);
+extern void FreeDGSendReq(DGSendReq *SendReq);
+extern int InitDG(uint MaxHeaderSize);
+extern _inline PNDIS_BUFFER GetDGHeader(void);
+extern void FreeDGHeader(PNDIS_BUFFER FreedBuffer);
+extern void PutPendingQ(AddrObj *QueueingAO);
+
+
+#endif // ifndef _DGRAM_INCLUDED_
+
diff --git a/private/ntos/tdi/tcpip/tcp/dirs b/private/ntos/tdi/tcpip/tcp/dirs
new file mode 100644
index 000000000..0dab2f056
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/dirs
@@ -0,0 +1,22 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=up mp
diff --git a/private/ntos/tdi/tcpip/tcp/i386/sources b/private/ntos/tdi/tcpip/tcp/i386/sources
new file mode 100644
index 000000000..9c19718ea
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/i386/sources
@@ -0,0 +1,4 @@
+i386_SOURCES= \
+ ..\i386\xsum.asm
+
+
diff --git a/private/ntos/tdi/tcpip/tcp/i386/xsum.asm b/private/ntos/tdi/tcpip/tcp/i386/xsum.asm
new file mode 100644
index 000000000..7cb03bce2
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/i386/xsum.asm
@@ -0,0 +1,259 @@
+ title "Compute Checksum"
+
+;/*++
+;
+; Copyright (c) 1992 Microsoft Corporation
+;
+; Module Name:
+;
+; cksy.asm
+;
+; Abstract:
+;
+; This module implements a function to compute the checksum of a buffer.
+;
+; Author:
+;
+; David N. Cutler (davec) 27-Jan-1992
+;
+; Revision History:
+;
+; Who When What
+; -------- -------- ----------------------------------------------
+; mikeab 01-22-94 Pentium optimization
+;
+; Environment:
+;
+; Any mode.
+;
+; Revision History:
+;
+;--*/
+
+LOOP_UNROLLING_BITS equ 5
+LOOP_UNROLLING equ (1 SHL LOOP_UNROLLING_BITS)
+
+ .386
+ .model small,c
+
+ assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT
+ assume fs:nothing,gs:nothing
+
+ .xlist
+ include callconv.inc
+ include ks386.inc
+ .list
+
+ .code
+
+;++
+;
+; ULONG
+; tcpxsum(
+; IN ULONG cksum,
+; IN PUCHAR buf,
+; IN ULONG len
+; )
+;
+; Routine Description:
+;
+; This function computes the checksum of the specified buffer.
+;
+; Arguments:
+;
+; cksum - Suppiles the initial checksum value, in 16-bit form,
+; with the high word set to 0.
+;
+; buf - Supplies a pointer to the buffer to the checksum buffer.
+;
+; len - Supplies the length of the buffer in bytes.
+;
+; Return Value:
+;
+; The computed checksum in 32-bit two-partial-accumulators form, added to
+; the initial checksum, is returned as the function value.
+;
+;--
+
+cksum equ 12 ; stack offset to initial checksum
+buf equ 16 ; stack offset to source address
+len equ 20 ; stack offset to length in words
+
+to_checksum_last_word:
+ jmp checksum_last_word
+
+to_checksum_done:
+ jmp checksum_done
+
+to_checksum_dword_loop_done:
+ jmp checksum_dword_loop_done
+
+cPublicProc tcpxsum,3
+
+ push ebx ; save nonvolatile register
+ push esi ; save nonvolatile register
+
+ mov ecx,[esp + len] ; get length in bytes
+ sub eax,eax ; clear computed checksum
+ test ecx,ecx ; any bytes to checksum at all?
+ jz short to_checksum_done ; no bytes to checksum
+
+;
+; if the checksum buffer is not word aligned, then add the first byte of
+; the buffer to the input checksum.
+;
+
+ mov esi,[esp + buf] ; get source address
+ sub edx,edx ; set up to load word into EDX below
+ test esi,1 ; check if buffer word aligned
+ jz short checksum_word_aligned ; if zf, buffer word aligned
+ mov ah,[esi] ; get first byte (we know we'll have
+ ; to swap at the end)
+ inc esi ; increment buffer address
+ dec ecx ; decrement number of bytes
+ jz short to_checksum_done ; if zf set, no more bytes
+
+;
+; If the buffer is not an even number of of bytes, then initialize
+; the computed checksum with the last byte of the buffer.
+;
+
+checksum_word_aligned: ;
+ shr ecx,1 ; convert to word count
+ jnc short checksum_start ; if nc, even number of bytes
+ mov al,[esi+ecx*2] ; initialize the computed checksum
+ jz short to_checksum_done ; if zf set, no more bytes
+
+;
+; Compute checksum in large blocks of dwords, with one partial word up front if
+; necessary to get dword alignment, and another partial word at the end if
+; needed.
+;
+
+;
+; Compute checksum on the leading word, if that's necessary to get dword
+; alignment.
+;
+
+checksum_start: ;
+ test esi,02h ; check if source dword aligned
+ jz short checksum_dword_aligned ; source is already dword aligned
+ mov dx,[esi] ; get first word to checksum
+ add esi,2 ; update source address
+ add eax,edx ; update partial checksum
+ ; (no carry is possible, because EAX
+ ; and EDX are both 16-bit values)
+ dec ecx ; count off this word (zero case gets
+ ; picked up below)
+
+;
+; Checksum as many words as possible by processing a dword at a time.
+;
+
+checksum_dword_aligned:
+ push ecx ; so we can tell if there's a trailing
+ ; word later
+ shr ecx,1 ; # of dwords to checksum
+ jz short to_checksum_last_word ; no dwords to checksum
+
+ mov edx,[esi] ; preload the first dword
+ add esi,4 ; point to the next dword
+ dec ecx ; count off the dword we just loaded
+ jz short to_checksum_dword_loop_done
+ ; skip the loop if that was the only
+ ; dword
+ mov ebx,ecx ; EBX = # of dwords left to checksum
+ add ecx,LOOP_UNROLLING-1 ; round up loop count
+ shr ecx,LOOP_UNROLLING_BITS ; convert from word count to unrolled
+ ; loop count
+ and ebx,LOOP_UNROLLING-1 ; # of partial dwords to do in first
+ ; loop
+ jz short checksum_dword_loop ; special-case when no partial loop,
+ ; because fixup below doesn't work
+ ; in that case (carry flag is
+ ; cleared at this point, as required
+ ; at loop entry)
+ lea esi,[esi+ebx*4-(LOOP_UNROLLING*4)]
+ ; adjust buffer pointer back to
+ ; compensate for hardwired displacement
+ ; at loop entry point
+ ; ***doesn't change carry flag***
+ jmp loop_entry[ebx*4] ; enter the loop to do the first,
+ ; partial iteration, after which we can
+ ; just do 64-word blocks
+ ; ***doesn't change carry flag***
+
+checksum_dword_loop:
+
+DEFLAB macro pre,suf
+pre&suf:
+ endm
+
+TEMP=0
+ REPT LOOP_UNROLLING
+ deflab loop_entry_,%TEMP
+ adc eax,edx
+ mov edx,[esi + TEMP]
+TEMP=TEMP+4
+ ENDM
+
+checksum_dword_loop_end:
+
+ lea esi,[esi + LOOP_UNROLLING * 4] ; update source address
+ ; ***doesn't change carry flag***
+ dec ecx ; count off unrolled loop iteration
+ ; ***doesn't change carry flag***
+ jnz checksum_dword_loop ; do more blocks
+
+checksum_dword_loop_done label proc
+ adc eax,edx ; finish dword checksum
+ mov edx,0 ; prepare to load trailing word
+ adc eax,edx
+
+;
+; Compute checksum on the trailing word, if there is one.
+; High word of EDX = 0 at this point
+; Carry flag set iff there's a trailing word to do at this point
+;
+
+checksum_last_word label proc ; "proc" so not scoped to function
+ pop ecx ; get back word count
+ test ecx,1 ; is there a trailing word?
+ jz short checksum_done ; no trailing word
+ add ax,[esi] ; add in the trailing word
+ adc eax,0 ;
+
+checksum_done label proc ; "proc" so not scoped to function
+ mov ecx,eax ; fold the checksum to 16 bits
+ ror ecx,16
+ add eax,ecx
+ mov ebx,[esp + buf]
+ shr eax,16
+ test ebx,1 ; check if buffer word aligned
+ jz short checksum_combine ; if zf set, buffer word aligned
+ ror ax,8 ; byte aligned--swap bytes back
+checksum_combine label proc ; "proc" so not scoped to function
+ add ax,word ptr [esp + cksum] ; combine checksums
+ pop esi ; restore nonvolatile register
+ adc eax,0 ;
+ pop ebx ; restore nonvolatile register
+ stdRET tcpxsum
+
+
+REFLAB macro pre,suf
+ dd pre&suf
+ endm
+
+ align 4
+loop_entry label dword
+ dd 0
+TEMP=LOOP_UNROLLING*4
+ REPT LOOP_UNROLLING-1
+TEMP=TEMP-4
+ reflab loop_entry_,%TEMP
+ ENDM
+
+stdENDP tcpxsum
+
+ end
+ \ No newline at end of file
diff --git a/private/ntos/tdi/tcpip/tcp/info.c b/private/ntos/tdi/tcpip/tcp/info.c
new file mode 100644
index 000000000..99fff25bf
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/info.c
@@ -0,0 +1,917 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** INFO.C - TDI Query/SetInformation routines.
+//
+// This file contains the code for dealing with TDI Query/Set information
+// calls.
+//
+
+#include "oscfg.h"
+#include "ndis.h"
+#include "cxport.h"
+#include "ip.h"
+#include "tdi.h"
+#ifdef VXD
+#include "tdivxd.h"
+#include "tdistat.h"
+#endif
+#ifdef NT
+#include "tdint.h"
+#include "tdistat.h"
+#endif
+#include "queue.h"
+#include "addr.h"
+#include "tcp.h"
+#include "tcb.h"
+#include "tcpconn.h"
+#include "tlcommon.h"
+#include "info.h"
+#include "tdiinfo.h"
+#include "tcpcfg.h"
+#include "udp.h"
+#include "tcpsend.h"
+
+#ifndef UDP_ONLY
+#define MY_SERVICE_FLAGS (TDI_SERVICE_CONNECTION_MODE | \
+ TDI_SERVICE_ORDERLY_RELEASE | \
+ TDI_SERVICE_CONNECTIONLESS_MODE | \
+ TDI_SERVICE_ERROR_FREE_DELIVERY | \
+ TDI_SERVICE_BROADCAST_SUPPORTED | \
+ TDI_SERVICE_DELAYED_ACCEPTANCE | \
+ TDI_SERVICE_EXPEDITED_DATA | \
+ TDI_SERVICE_NO_ZERO_LENGTH)
+#else
+#define MY_SERVICE_FLAGS (TDI_SERVICE_CONNECTIONLESS_MODE | \
+ TDI_SERVICE_BROADCAST_SUPPORTED)
+#endif
+
+extern uint StartTime;
+EXTERNAL_LOCK(AddrObjTableLock)
+
+#ifndef UDP_ONLY
+TCPStats TStats;
+#endif
+
+UDPStats UStats;
+
+struct ReadTableStruct {
+ uint (*rts_validate)(void *Context, uint *Valid);
+ uint (*rts_readnext)(void *Context, void *OutBuf);
+};
+
+struct ReadTableStruct ReadAOTable =
+ {ValidateAOContext, ReadNextAO};
+
+#ifndef UDP_ONLY
+
+struct ReadTableStruct ReadTCBTable =
+ {ValidateTCBContext, ReadNextTCB};
+
+EXTERNAL_LOCK(TCBTableLock)
+#endif
+
+EXTERNAL_LOCK(AddrObjTableLock)
+
+extern IPInfo LocalNetInfo;
+
+struct TDIEntityID *EntityList;
+uint EntityCount;
+
+//* TdiQueryInformation - Query Information handler.
+//
+// The TDI QueryInformation routine. Called when the client wants to
+// query information on a connection, the provider as a whole, or to
+// get statistics.
+//
+// Input: Request - The request structure for this command.
+// QueryType - The type of query to be performed.
+// Buffer - Buffer to place data into.
+// BufferSize - Pointer to size in bytes of buffer. On return,
+// filled in with bytes copied.
+// IsConn - Valid only for TDI_QUERY_ADDRESS_INFO. TRUE
+// if we are querying the address info on
+// a connection.
+//
+// Returns: Status of attempt to query information.
+//
+TDI_STATUS
+TdiQueryInformation(PTDI_REQUEST Request, uint QueryType, PNDIS_BUFFER Buffer,
+ uint *BufferSize, uint IsConn)
+{
+ union {
+ TDI_CONNECTION_INFO ConnInfo;
+ TDI_ADDRESS_INFO AddrInfo;
+ TDI_PROVIDER_INFO ProviderInfo;
+ TDI_PROVIDER_STATISTICS ProviderStats;
+ } InfoBuf;
+
+ uint InfoSize;
+ CTELockHandle ConnTableHandle, TCBHandle, AddrHandle, AOHandle;
+#ifndef UDP_ONLY
+ TCPConn *Conn;
+ TCB *InfoTCB;
+#endif
+ AddrObj *InfoAO;
+ void *InfoPtr = NULL;
+ uint Offset;
+ uint Size;
+ uint BytesCopied;
+
+ switch (QueryType) {
+
+ case TDI_QUERY_BROADCAST_ADDRESS:
+ return TDI_INVALID_QUERY;
+ break;
+
+ case TDI_QUERY_PROVIDER_INFO:
+ InfoBuf.ProviderInfo.Version = 0x100;
+#ifndef UDP_ONLY
+ InfoBuf.ProviderInfo.MaxSendSize = 0xffffffff;
+#else
+ InfoBuf.ProviderInfo.MaxSendSize = 0;
+#endif
+ InfoBuf.ProviderInfo.MaxConnectionUserData = 0;
+ InfoBuf.ProviderInfo.MaxDatagramSize = 0xffff - sizeof(UDPHeader);
+ InfoBuf.ProviderInfo.ServiceFlags = MY_SERVICE_FLAGS;
+ InfoBuf.ProviderInfo.MinimumLookaheadData = 1;
+ InfoBuf.ProviderInfo.MaximumLookaheadData = 0xffff;
+ InfoBuf.ProviderInfo.NumberOfResources = 0;
+ InfoBuf.ProviderInfo.StartTime.LowPart = StartTime;
+ InfoBuf.ProviderInfo.StartTime.HighPart = 0;
+ InfoSize = sizeof(TDI_PROVIDER_INFO);
+ InfoPtr = &InfoBuf.ProviderInfo;
+ break;
+
+ case TDI_QUERY_ADDRESS_INFO:
+ InfoSize = sizeof(TDI_ADDRESS_INFO) - sizeof(TRANSPORT_ADDRESS) +
+ TCP_TA_SIZE;
+ CTEMemSet(&InfoBuf.AddrInfo, 0, TCP_TA_SIZE);
+ InfoBuf.AddrInfo.ActivityCount = 1; // Since noone knows what
+ // this means, we'll set
+ // it to one.
+
+ if (IsConn) {
+#ifdef UDP_ONLY
+ return TDI_INVALID_QUERY;
+#else
+
+ CTEGetLock(&AddrObjTableLock, &AddrHandle);
+ CTEGetLock(&ConnTableLock, &ConnTableHandle);
+ Conn = GetConnFromConnID((uint)Request->Handle.ConnectionContext);
+
+ if (Conn != NULL) {
+ CTEStructAssert(Conn, tc);
+
+ InfoTCB = Conn->tc_tcb;
+ // If we have a TCB we'll
+ // return information about that TCB. Otherwise we'll return
+ // info about the address object.
+ if (InfoTCB != NULL) {
+ CTEStructAssert(InfoTCB, tcb);
+ CTEGetLock(&InfoTCB->tcb_lock, &TCBHandle);
+ CTEFreeLock(&ConnTableLock, TCBHandle);
+ CTEFreeLock(&AddrObjTableLock, ConnTableHandle);
+ BuildTDIAddress((uchar *)&InfoBuf.AddrInfo.Address,
+ InfoTCB->tcb_saddr, InfoTCB->tcb_sport);
+ CTEFreeLock(&InfoTCB->tcb_lock, AddrHandle);
+ InfoPtr = &InfoBuf.AddrInfo;
+ break;
+ } else {
+ // No TCB, return info on the AddrObj.
+ InfoAO = Conn->tc_ao;
+ if (InfoAO != NULL) {
+ // We have an AddrObj.
+ CTEStructAssert(InfoAO, ao);
+ CTEGetLock(&InfoAO->ao_lock, &AOHandle);
+ BuildTDIAddress((uchar *)&InfoBuf.AddrInfo.Address,
+ InfoAO->ao_addr, InfoAO->ao_port);
+ CTEFreeLock(&InfoAO->ao_lock, AOHandle);
+ CTEFreeLock(&ConnTableLock, ConnTableHandle);
+ CTEFreeLock(&AddrObjTableLock, AddrHandle);
+ InfoPtr = &InfoBuf.AddrInfo;
+ break;
+ }
+ }
+
+ }
+
+ // Fall through to here when we can't find the connection, or
+ // the connection isn't associated.
+ CTEFreeLock(&ConnTableLock, ConnTableHandle);
+ CTEFreeLock(&AddrObjTableLock, AddrHandle);
+ return TDI_INVALID_CONNECTION;
+ break;
+
+#endif
+ } else {
+ // Asking for information on an addr. object.
+#ifdef VXD
+ InfoAO = GetIndexedAO((uint)Request->Handle.AddressHandle);
+
+ if (InfoAO == NULL)
+ return TDI_ADDR_INVALID;
+#else
+ InfoAO = Request->Handle.AddressHandle;
+#endif
+
+ CTEStructAssert(InfoAO, ao);
+
+ CTEGetLock(&InfoAO->ao_lock, &AOHandle);
+
+ if (!AO_VALID(InfoAO)) {
+ CTEFreeLock(&InfoAO->ao_lock, AOHandle);
+ return TDI_ADDR_INVALID;
+ }
+
+ BuildTDIAddress((uchar *)&InfoBuf.AddrInfo.Address,
+ InfoAO->ao_addr, InfoAO->ao_port);
+ CTEFreeLock(&InfoAO->ao_lock, AOHandle);
+ InfoPtr = &InfoBuf.AddrInfo;
+ break;
+ }
+
+ break;
+
+ case TDI_QUERY_CONNECTION_INFO:
+#ifndef UDP_ONLY
+ InfoSize = sizeof(TDI_CONNECTION_INFO);
+ CTEGetLock(&ConnTableLock, &ConnTableHandle);
+ Conn = GetConnFromConnID((uint)Request->Handle.ConnectionContext);
+
+ if (Conn != NULL) {
+ CTEStructAssert(Conn, tc);
+
+ InfoTCB = Conn->tc_tcb;
+ // If we have a TCB we'll return the information. Otherwise
+ // we'll error out.
+ if (InfoTCB != NULL) {
+
+ ulong TotalTime;
+ ulong BPS, PathBPS;
+ IP_STATUS IPStatus;
+ CTEULargeInt TempULargeInt;
+
+ CTEStructAssert(InfoTCB, tcb);
+ CTEGetLock(&InfoTCB->tcb_lock, &TCBHandle);
+ CTEFreeLock(&ConnTableLock, TCBHandle);
+ CTEMemSet(&InfoBuf.ConnInfo, 0, sizeof(TDI_CONNECTION_INFO));
+ InfoBuf.ConnInfo.State = (ulong)InfoTCB->tcb_state;
+ IPStatus = (*LocalNetInfo.ipi_getpinfo)(InfoTCB->tcb_daddr,
+ InfoTCB->tcb_saddr, NULL, &PathBPS);
+
+ if (IPStatus != IP_SUCCESS) {
+ InfoBuf.ConnInfo.Throughput.LowPart = 0xFFFFFFFF;
+ InfoBuf.ConnInfo.Throughput.HighPart = 0xFFFFFFFF;
+ } else {
+ InfoBuf.ConnInfo.Throughput.HighPart = 0;
+ TotalTime = InfoTCB->tcb_totaltime /
+ (1000 / MS_PER_TICK);
+ if (TotalTime != 0) {
+ TempULargeInt.LowPart = InfoTCB->tcb_bcountlow;
+ TempULargeInt.HighPart = InfoTCB->tcb_bcounthi;
+
+ BPS = CTEEnlargedUnsignedDivide(TempULargeInt,
+ TotalTime, NULL);
+ InfoBuf.ConnInfo.Throughput.LowPart =
+ MIN(BPS, PathBPS);
+ } else
+ InfoBuf.ConnInfo.Throughput.LowPart = PathBPS;
+ }
+
+
+
+ // To figure the delay we use the rexmit timeout. Our
+ // rexmit timeout is roughly the round trip time plus
+ // some slop, so we use half of that as the one way delay.
+#ifdef VXD
+ InfoBuf.ConnInfo.Delay.LowPart =
+ (REXMIT_TO(InfoTCB) * MS_PER_TICK) / 2;
+ InfoBuf.ConnInfo.Throughput.HighPart = 0;
+#else // VXD
+ InfoBuf.ConnInfo.Delay.LowPart =
+ (REXMIT_TO(InfoTCB) * MS_PER_TICK) / 2;
+ InfoBuf.ConnInfo.Delay.HighPart = 0;
+ //
+ // Convert milliseconds to 100ns and negate for relative
+ // time.
+ //
+ InfoBuf.ConnInfo.Delay =
+ RtlExtendedIntegerMultiply(
+ InfoBuf.ConnInfo.Delay,
+ 10000
+ );
+
+ CTEAssert(InfoBuf.ConnInfo.Delay.HighPart == 0);
+
+ InfoBuf.ConnInfo.Delay.QuadPart =
+ -InfoBuf.ConnInfo.Delay.QuadPart;
+
+#endif // VXD
+ CTEFreeLock(&InfoTCB->tcb_lock, ConnTableHandle);
+ InfoPtr = &InfoBuf.ConnInfo;
+ break;
+ }
+
+ }
+
+ // Come through here if we can't find the connection or it has
+ // no TCB.
+ CTEFreeLock(&ConnTableLock, ConnTableHandle);
+ return TDI_INVALID_CONNECTION;
+ break;
+
+#else // UDP_ONLY
+ return TDI_INVALID_QUERY;
+ break;
+#endif // UDP_ONLY
+ case TDI_QUERY_PROVIDER_STATISTICS:
+ CTEMemSet(&InfoBuf.ProviderStats, 0, sizeof(TDI_PROVIDER_STATISTICS));
+ InfoBuf.ProviderStats.Version = 0x100;
+ InfoSize = sizeof(TDI_PROVIDER_STATISTICS);
+ InfoPtr = &InfoBuf.ProviderStats;
+ break;
+ default:
+ return TDI_INVALID_QUERY;
+ break;
+ }
+
+ // When we get here, we've got the pointers set up and the information
+ // filled in.
+
+ CTEAssert(InfoPtr != NULL);
+ Offset = 0;
+ Size = *BufferSize;
+ (void)CopyFlatToNdis(Buffer, InfoPtr, MIN(InfoSize, Size), &Offset,
+ &BytesCopied);
+ if (Size < InfoSize)
+ return TDI_BUFFER_OVERFLOW;
+ else {
+ *BufferSize = InfoSize;
+ return TDI_SUCCESS;
+ }
+}
+
+//* TdiSetInformation - Set Information handler.
+//
+// The TDI SetInformation routine. Currently we don't allow anything to be
+// set.
+//
+// Input: Request - The request structure for this command.
+// SetType - The type of set to be performed.
+// Buffer - Buffer to set from.
+// BufferSize - Size in bytes of buffer.
+// IsConn - Valid only for TDI_QUERY_ADDRESS_INFO. TRUE
+// if we are setting the address info on
+// a connection.
+//
+// Returns: Status of attempt to set information.
+//
+TDI_STATUS
+TdiSetInformation(PTDI_REQUEST Request, uint SetType, PNDIS_BUFFER Buffer,
+ uint BufferSize, uint IsConn)
+{
+ return TDI_INVALID_REQUEST;
+}
+
+//* TdiAction - Action handler.
+//
+// The TDI Action routine. Currently we don't support any actions.
+//
+// Input: Request - The request structure for this command.
+// ActionType - The type of action to be performed.
+// Buffer - Buffer of action info.
+// BufferSize - Size in bytes of buffer.
+//
+// Returns: Status of attempt to perform action.
+//
+TDI_STATUS
+TdiAction(PTDI_REQUEST Request, uint ActionType, PNDIS_BUFFER Buffer,
+ uint BufferSize)
+{
+ return TDI_INVALID_REQUEST;
+}
+
+//* TdiQueryInfoEx - Extended TDI query information.
+//
+// This is the new TDI query information handler. We take in a TDIObjectID
+// structure, a buffer and length, and some context information, and return
+// the requested information if possible.
+//
+// Input: Request - The request structure for this command.
+// ID - The object ID
+// Buffer - Pointer to buffer to be filled in.
+// Size - Pointer to size in bytes of Buffer. On exit,
+// filled in with bytes written.
+// Context - Pointer to context buffer.
+//
+// Returns: Status of attempt to get information.
+//
+TDI_STATUS
+TdiQueryInformationEx(PTDI_REQUEST Request, TDIObjectID *ID,
+ PNDIS_BUFFER Buffer, uint *Size, void *Context)
+{
+ uint BufferSize = *Size;
+ uint InfoSize;
+ void *InfoPtr;
+ uint Fixed;
+ CTELockHandle Handle;
+#ifndef VXD
+ CTELock *LockPtr;
+#else
+#ifdef DEBUG
+ CTELock *LockPtr;
+#endif
+#endif
+ uint Offset = 0;
+ uchar InfoBuffer[sizeof(TCPConnTableEntry)];
+ uint BytesRead;
+ uint Valid;
+ uint Entity;
+ uint BytesCopied;
+
+ // First check to see if he's querying for list of entities.
+ Entity = ID->toi_entity.tei_entity;
+ if (Entity == GENERIC_ENTITY) {
+ *Size = 0;
+
+ if (ID->toi_class != INFO_CLASS_GENERIC ||
+ ID->toi_type != INFO_TYPE_PROVIDER ||
+ ID->toi_id != ENTITY_LIST_ID) {
+ return TDI_INVALID_PARAMETER;
+ }
+
+ // Make sure we have room for it the list in the buffer.
+ InfoSize = EntityCount * sizeof(TDIEntityID);
+
+ if (BufferSize < InfoSize) {
+ // Not enough room.
+ return TDI_BUFFER_TOO_SMALL;
+ }
+
+ *Size = InfoSize;
+
+ // Copy it in, free our temp. buffer, and return success.
+ (void)CopyFlatToNdis(Buffer, (uchar *)EntityList, InfoSize, &Offset,
+ &BytesCopied);
+ return TDI_SUCCESS;
+ }
+
+
+ //* Check the level. If it can't be for us, pass it down.
+#ifndef UDP_ONLY
+ if (Entity != CO_TL_ENTITY && Entity != CL_TL_ENTITY) {
+#else
+ if (Entity != CL_TL_ENTITY) {
+#endif
+
+ // When we support multiple lower entities at this layer we'll have
+ // to figure out which one to dispatch to. For now, just pass it
+ // straight down.
+ return (*LocalNetInfo.ipi_qinfo)(ID, Buffer, Size, Context);
+ }
+
+ if (ID->toi_entity.tei_instance != TL_INSTANCE) {
+ // We only support a single instance.
+ return TDI_INVALID_REQUEST;
+ }
+
+ // Zero returned parameters in case of an error below.
+ *Size = 0;
+
+ if (ID->toi_class == INFO_CLASS_GENERIC) {
+ // This is a generic request.
+ if (ID->toi_type == INFO_TYPE_PROVIDER && ID->toi_id == ENTITY_TYPE_ID) {
+ if (BufferSize >= sizeof(uint)) {
+ *(uint *)&InfoBuffer[0] = (Entity == CO_TL_ENTITY) ? CO_TL_TCP
+ : CL_TL_UDP;
+ (void)CopyFlatToNdis(Buffer, InfoBuffer, sizeof(uint), &Offset,
+ &BytesCopied);
+ return TDI_SUCCESS;
+ } else
+ return TDI_BUFFER_TOO_SMALL;
+ }
+ return TDI_INVALID_PARAMETER;
+ }
+
+ if (ID->toi_class == INFO_CLASS_PROTOCOL) {
+ // Handle protocol specific class of information. For us, this is
+ // the MIB-2 stuff or the minimal stuff we do for oob_inline support.
+
+#ifndef UDP_ONLY
+ if (ID->toi_type == INFO_TYPE_CONNECTION) {
+ TCPConn *Conn;
+ TCB *QueryTCB;
+ TCPSocketAMInfo *AMInfo;
+ CTELockHandle TCBHandle;
+
+ if (BufferSize < sizeof(TCPSocketAMInfo) ||
+ ID->toi_id != TCP_SOCKET_ATMARK)
+ return TDI_INVALID_PARAMETER;
+
+ AMInfo = (TCPSocketAMInfo *)InfoBuffer;
+ CTEGetLock(&ConnTableLock, &Handle);
+
+ Conn = GetConnFromConnID((uint)Request->Handle.ConnectionContext);
+
+ if (Conn != NULL) {
+ CTEStructAssert(Conn, tc);
+
+ QueryTCB = Conn->tc_tcb;
+ if (QueryTCB != NULL) {
+ CTEStructAssert(QueryTCB, tcb);
+ CTEGetLock(&QueryTCB->tcb_lock, &TCBHandle);
+ if ((QueryTCB->tcb_flags & (URG_INLINE | URG_VALID)) ==
+ (URG_INLINE | URG_VALID)) {
+ // We're in inline mode, and the urgent data fields are
+ // valid.
+ AMInfo->tsa_size = QueryTCB->tcb_urgend -
+ QueryTCB->tcb_urgstart + 1;
+ // Rcvnext - pendingcnt is the sequence number of the
+ // next byte of data that will be delivered to the
+ // client. Urgend - that value is the offset in the
+ // data stream of the end of urgent data.
+ AMInfo->tsa_offset = QueryTCB->tcb_urgend -
+ (QueryTCB->tcb_rcvnext - QueryTCB->tcb_pendingcnt);
+ } else {
+ AMInfo->tsa_size = 0;
+ AMInfo->tsa_offset = 0;
+ }
+ CTEFreeLock(&QueryTCB->tcb_lock, TCBHandle);
+ *Size = sizeof(TCPSocketAMInfo);
+ CopyFlatToNdis(Buffer, InfoBuffer, sizeof(TCPSocketAMInfo),
+ &Offset, &BytesCopied);
+ return TDI_SUCCESS;
+ }
+ }
+ return TDI_INVALID_PARAMETER;
+
+ }
+
+#endif
+ if (ID->toi_type != INFO_TYPE_PROVIDER)
+ return TDI_INVALID_PARAMETER;
+
+ switch (ID->toi_id) {
+
+ case UDP_MIB_STAT_ID:
+#if UDP_MIB_STAT_ID != TCP_MIB_STAT_ID
+ case TCP_MIB_STAT_ID:
+#endif
+ Fixed = TRUE;
+ if (Entity == CL_TL_ENTITY) {
+ InfoSize = sizeof(UDPStats);
+ InfoPtr = &UStats;
+ } else {
+#ifndef UDP_ONLY
+ InfoSize = sizeof(TCPStats);
+ InfoPtr = &TStats;
+#else
+ return TDI_INVALID_PARAMETER;
+#endif
+ }
+ break;
+ case UDP_MIB_TABLE_ID:
+#if UDP_MIB_TABLE_ID != TCP_MIB_TABLE_ID
+ case TCP_MIB_TABLE_ID:
+#endif
+ Fixed = FALSE;
+ if (Entity == CL_TL_ENTITY) {
+ InfoSize = sizeof(UDPEntry);
+ InfoPtr = &ReadAOTable;
+ CTEGetLock(&AddrObjTableLock, &Handle);
+#ifndef VXD
+ LockPtr = &AddrObjTableLock;
+#else
+#ifdef DEBUG
+ LockPtr = &AddrObjTableLock;
+#endif
+#endif
+ } else {
+#ifndef UDP_ONLY
+ InfoSize = sizeof(TCPConnTableEntry);
+ InfoPtr = &ReadTCBTable;
+ CTEGetLock(&TCBTableLock, &Handle);
+#ifndef VXD
+ LockPtr = &TCBTableLock;
+#else
+#ifdef DEBUG
+ LockPtr = &TCBTableLock;
+#endif
+#endif
+
+#else
+ return TDI_INVALID_PARAMETER;
+#endif
+ }
+ break;
+ default:
+ return TDI_INVALID_PARAMETER;
+ break;
+ }
+
+ if (Fixed) {
+ if (BufferSize < InfoSize)
+ return TDI_BUFFER_TOO_SMALL;
+
+ *Size = InfoSize;
+
+ (void)CopyFlatToNdis(Buffer, InfoPtr, InfoSize, &Offset,
+ &BytesCopied);
+ return TDI_SUCCESS;
+ } else {
+ struct ReadTableStruct *RTSPtr;
+ uint ReadStatus;
+
+ // Have a variable length (or mult-instance) structure to copy.
+ // InfoPtr points to the structure describing the routines to
+ // call to read the table.
+ // Loop through up to CountWanted times, calling the routine
+ // each time.
+ BytesRead = 0;
+
+ RTSPtr = InfoPtr;
+
+ ReadStatus = (*(RTSPtr->rts_validate))(Context, &Valid);
+
+ // If we successfully read something we'll continue. Otherwise
+ // we'll bail out.
+ if (!Valid) {
+ CTEFreeLock(LockPtr, Handle);
+ return TDI_INVALID_PARAMETER;
+ }
+
+ while (ReadStatus) {
+ // The invariant here is that there is data in the table to
+ // read. We may or may not have room for it. So ReadStatus
+ // is TRUE, and BufferSize - BytesRead is the room left
+ // in the buffer.
+ if ((int)(BufferSize - BytesRead) >= (int)InfoSize) {
+ ReadStatus = (*(RTSPtr->rts_readnext))(Context,
+ InfoBuffer);
+ BytesRead += InfoSize;
+ Buffer = CopyFlatToNdis(Buffer, InfoBuffer, InfoSize,
+ &Offset, &BytesCopied);
+ } else
+ break;
+
+ }
+
+ *Size = BytesRead;
+ CTEFreeLock(LockPtr, Handle);
+ return (!ReadStatus ? TDI_SUCCESS : TDI_BUFFER_OVERFLOW);
+ }
+
+ }
+
+ if (ID->toi_class == INFO_CLASS_IMPLEMENTATION) {
+ // We want to return implementation specific info. For now, error out.
+ return TDI_INVALID_PARAMETER;
+ }
+
+ return TDI_INVALID_PARAMETER;
+
+}
+
+//* TdiSetInfoEx - Extended TDI set information.
+//
+// This is the new TDI set information handler. We take in a TDIObjectID
+// structure, a buffer and length. We set the object specifed by the ID
+// (and possibly by the Request) to the value specified in the buffer.
+//
+// Input: Request - The request structure for this command.
+// ID - The object ID
+// Buffer - Pointer to buffer containing value to set.
+// Size - Size in bytes of Buffer.
+//
+// Returns: Status of attempt to get information.
+//
+TDI_STATUS
+TdiSetInformationEx(PTDI_REQUEST Request, TDIObjectID *ID, void *Buffer,
+ uint Size)
+{
+ TCPConnTableEntry *TCPEntry;
+ CTELockHandle TableHandle, TCBHandle;
+ TCB *SetTCB;
+ uint Entity;
+ TCPConn *Conn;
+ TDI_STATUS Status;
+
+
+ //* Check the level. If it can't be for us, pass it down.
+ Entity = ID->toi_entity.tei_entity;
+
+ if (Entity != CO_TL_ENTITY && Entity != CL_TL_ENTITY) {
+ // Someday we'll have to figure out how to dispatch. For now, just pass
+ // it down.
+ return (*LocalNetInfo.ipi_setinfo)(ID, Buffer, Size);
+ }
+
+ if (ID->toi_entity.tei_instance != TL_INSTANCE)
+ return TDI_INVALID_REQUEST;
+
+ if (ID->toi_class == INFO_CLASS_GENERIC) {
+ // Fill this in when we have generic class defines.
+ return TDI_INVALID_PARAMETER;
+ }
+
+ //* Now look at the rest of it.
+ if (ID->toi_class == INFO_CLASS_PROTOCOL) {
+ // Handle protocol specific class of information. For us, this is
+ // the MIB-2 stuff, as well as common sockets options,
+ // and in particular the setting of the state of a TCP connection.
+
+ if (ID->toi_type == INFO_TYPE_CONNECTION) {
+ TCPSocketOption *Option;
+ uint Flag;
+ uint Value;
+
+#ifndef UDP_ONLY
+ // A connection type. Get the connection, and then figure out
+ // what to do with it.
+ Status = TDI_INVALID_PARAMETER;
+
+ if (Size < sizeof(TCPSocketOption))
+ return Status;
+
+ CTEGetLock(&ConnTableLock, &TableHandle);
+
+ Conn = GetConnFromConnID((uint)Request->Handle.ConnectionContext);
+
+ if (Conn != NULL) {
+ CTEStructAssert(Conn, tc);
+
+ Status = TDI_SUCCESS;
+
+ if (ID->toi_id == TCP_SOCKET_WINDOW) {
+ // This is a funny option, because it doesn't involve
+ // flags. Handle this specially.
+ Option = (TCPSocketOption *)Buffer;
+
+ // We don't allow anyone to shrink the window, as this
+ // gets too weird from a protocol point of view. Also,
+ // make sure they don't try and set anything too big.
+ if (Option->tso_value > 0xffff)
+ Status = TDI_INVALID_PARAMETER;
+ else if (Option->tso_value > Conn->tc_window ||
+ Conn->tc_tcb == NULL) {
+ Conn->tc_flags |= CONN_WINSET;
+ Conn->tc_window = Option->tso_value;
+ SetTCB = Conn->tc_tcb;
+
+ if (SetTCB != NULL) {
+ CTEStructAssert(SetTCB, tcb);
+ CTEGetLock(&SetTCB->tcb_lock, &TCBHandle);
+ CTEAssert(Option->tso_value > SetTCB->tcb_defaultwin);
+ if (DATA_RCV_STATE(SetTCB->tcb_state) &&
+ !CLOSING(SetTCB)) {
+ SetTCB->tcb_flags |= WINDOW_SET;
+ SetTCB->tcb_defaultwin = Option->tso_value;
+ SetTCB->tcb_refcnt++;
+ CTEFreeLock(&SetTCB->tcb_lock, TCBHandle);
+ SendACK(SetTCB);
+ CTEGetLock(&SetTCB->tcb_lock, &TCBHandle);
+ DerefTCB(SetTCB, TCBHandle);
+ } else {
+ CTEFreeLock(&SetTCB->tcb_lock, TCBHandle);
+ }
+ }
+ }
+ CTEFreeLock(&ConnTableLock, TableHandle);
+ return Status;
+ }
+
+ Flag = 0;
+ Option = (TCPSocketOption *)Buffer;
+ Value = Option->tso_value;
+ // We have the connection, so figure out which flag to set.
+ switch (ID->toi_id) {
+
+ case TCP_SOCKET_NODELAY:
+ Value = !Value;
+ Flag = NAGLING;
+ break;
+ case TCP_SOCKET_KEEPALIVE:
+ Flag = KEEPALIVE;
+ break;
+ case TCP_SOCKET_BSDURGENT:
+ Flag = BSD_URGENT;
+ break;
+ case TCP_SOCKET_OOBINLINE:
+ Flag = URG_INLINE;
+ break;
+ default:
+ Status = TDI_INVALID_PARAMETER;
+ break;
+ }
+
+ if (Status == TDI_SUCCESS) {
+ if (Value)
+ Conn->tc_tcbflags |= Flag;
+ else
+ Conn->tc_tcbflags &= ~Flag;
+
+ SetTCB = Conn->tc_tcb;
+ if (SetTCB != NULL) {
+ CTEStructAssert(SetTCB, tcb);
+ CTEGetLock(&SetTCB->tcb_lock, &TCBHandle);
+ if (Value)
+ SetTCB->tcb_flags |= Flag;
+ else
+ SetTCB->tcb_flags &= ~Flag;
+
+ if (ID->toi_id == TCP_SOCKET_KEEPALIVE) {
+ SetTCB->tcb_alive = TCPTime;
+ SetTCB->tcb_kacount = 0;
+ }
+
+ CTEFreeLock(&SetTCB->tcb_lock, TCBHandle);
+ }
+ }
+ }
+
+ CTEFreeLock(&ConnTableLock, TableHandle);
+ return Status;
+#else
+ return TDI_INVALID_PARAMETER;
+#endif
+ }
+
+ if (ID->toi_type == INFO_TYPE_ADDRESS_OBJECT) {
+ // We're setting information on an address object. This is
+ // pretty simple.
+
+ return SetAddrOptions(Request, ID->toi_id, Size, Buffer);
+
+ }
+
+
+ if (ID->toi_type != INFO_TYPE_PROVIDER)
+ return TDI_INVALID_PARAMETER;
+
+#ifndef UDP_ONLY
+ if (ID->toi_id == TCP_MIB_TABLE_ID) {
+ if (Size != sizeof(TCPConnTableEntry))
+ return TDI_INVALID_PARAMETER;
+
+ TCPEntry = (TCPConnTableEntry *)Buffer;
+
+ if (TCPEntry->tct_state != TCP_DELETE_TCB)
+ return TDI_INVALID_PARAMETER;
+
+ // We have an apparently valid request. Look up the TCB.
+ CTEGetLock(&TCBTableLock, &TableHandle);
+ SetTCB = FindTCB(TCPEntry->tct_localaddr,
+ TCPEntry->tct_remoteaddr, (ushort)TCPEntry->tct_remoteport,
+ (ushort)TCPEntry->tct_localport);
+
+ // We found him. If he's not closing or closed, close him.
+ if (SetTCB != NULL) {
+ CTEGetLock(&SetTCB->tcb_lock, &TCBHandle);
+ CTEFreeLock(&TCBTableLock, TCBHandle);
+
+ // We've got him. Bump his ref. count, and call TryToCloseTCB
+ // to mark him as closing. Then notify the upper layer client
+ // of the disconnect.
+ SetTCB->tcb_refcnt++;
+ if (SetTCB->tcb_state != TCB_CLOSED && !CLOSING(SetTCB)) {
+ SetTCB->tcb_flags |= NEED_RST;
+ TryToCloseTCB(SetTCB, TCB_CLOSE_ABORTED, TableHandle);
+ CTEGetLock(&SetTCB->tcb_lock, &TableHandle);
+
+ if (SetTCB->tcb_state != TCB_TIME_WAIT) {
+ // Remove him from the TCB, and notify the client.
+ CTEFreeLock(&SetTCB->tcb_lock, TableHandle);
+ RemoveTCBFromConn(SetTCB);
+ NotifyOfDisc(SetTCB, NULL, TDI_CONNECTION_RESET);
+ CTEGetLock(&SetTCB->tcb_lock, &TableHandle);
+ }
+
+ }
+
+ DerefTCB(SetTCB, TableHandle);
+ return TDI_SUCCESS;
+ } else {
+ CTEFreeLock(&TCBTableLock, TableHandle);
+ return TDI_INVALID_PARAMETER;
+ }
+ } else
+ return TDI_INVALID_PARAMETER;
+#else
+ return TDI_INVALID_PARAMETER;
+#endif
+
+ }
+
+ if (ID->toi_class == INFO_CLASS_IMPLEMENTATION) {
+ // We want to return implementation specific info. For now, error out.
+ return TDI_INVALID_REQUEST;
+ }
+
+ return TDI_INVALID_REQUEST;
+
+
+}
diff --git a/private/ntos/tdi/tcpip/tcp/info.h b/private/ntos/tdi/tcpip/tcp/info.h
new file mode 100644
index 000000000..f5274160f
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/info.h
@@ -0,0 +1,51 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** INFO.H - TDI Query/SetInfo and Action definitons.
+//
+// This file contains definitions for the file info.c.
+//
+
+#include "tcpinfo.h"
+
+#define TL_INSTANCE 0
+
+#ifndef UDP_ONLY
+extern TCPStats TStats;
+
+typedef struct TCPConnContext {
+ uint tcc_index;
+ struct TCB *tcc_tcb;
+} TCPConnContext;
+
+#define TCB_STATE_DELTA 1
+
+#endif
+
+typedef struct UDPContext {
+ uint uc_index;
+ struct AddrObj *uc_ao;
+} UDPContext;
+
+extern UDPStats UStats;
+extern struct TDIEntityID *EntityList;
+extern uint EntityCount;
+
+extern TDI_STATUS TdiQueryInformation(PTDI_REQUEST Request, uint QueryType,
+ PNDIS_BUFFER Buffer, uint *BufferSize, uint IsConn);
+
+extern TDI_STATUS TdiSetInformation(PTDI_REQUEST Request, uint SetType,
+ PNDIS_BUFFER Buffer, uint BufferSize, uint IsConn);
+
+extern TDI_STATUS TdiAction(PTDI_REQUEST Request, uint ActionType,
+ PNDIS_BUFFER Buffer, uint BufferSize);
+
+extern TDI_STATUS TdiQueryInformationEx(PTDI_REQUEST Request,
+ struct TDIObjectID *ID, PNDIS_BUFFER Buffer, uint *Size, void *Context);
+
+extern TDI_STATUS TdiSetInformationEx(PTDI_REQUEST Request,
+ struct TDIObjectID *ID, void *Buffer, uint Size);
+
diff --git a/private/ntos/tdi/tcpip/tcp/init.c b/private/ntos/tdi/tcpip/tcp/init.c
new file mode 100644
index 000000000..2a889d88a
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/init.c
@@ -0,0 +1,597 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** INIT.C - TCP/UDP init code.
+//
+// This file contain init code for the TCP/UDP driver. Some things
+// here are ifdef'ed for building a UDP only version.
+//
+
+#include "oscfg.h"
+#include "ndis.h"
+#include "cxport.h"
+#include "ip.h"
+#include "tdi.h"
+#ifdef NT
+#include <tdikrnl.h>
+#endif
+#ifdef VXD
+#include "tdivxd.h"
+#include "tdistat.h"
+#endif
+#ifdef NT
+#include "tdint.h"
+#include "tdistat.h"
+#endif
+#include "queue.h"
+#include "addr.h"
+#include "udp.h"
+#include "raw.h"
+#include "info.h"
+#ifndef UDP_ONLY
+#include "tcp.h"
+#include "tcpsend.h"
+#include "tcb.h"
+#include "tcpconn.h"
+#include "tcpdeliv.h"
+#include "tlcommon.h"
+
+extern int InitTCPRcv(void);
+extern void UnInitTCPRcv(void);
+#endif // UDP_ONLY
+
+#include "tdiinfo.h"
+#include "tcpcfg.h"
+
+
+//* Definitions of global variables.
+IPInfo LocalNetInfo;
+
+uint DeadGWDetect;
+uint PMTUDiscovery;
+uint PMTUBHDetect;
+uint KeepAliveTime;
+uint KAInterval;
+uint DefaultRcvWin;
+uint MaxConnections;
+uint MaxConnectRexmitCount;
+uint MaxConnectResponseRexmitCount;
+#ifdef SYN_ATTACK
+uint MaxConnectResponseRexmitCountTmp;
+#endif
+uint MaxDataRexmitCount;
+uint BSDUrgent;
+uint FinWait2TO;
+uint NTWMaxConnectCount;
+uint NTWMaxConnectTime;
+uint MaxUserPort;
+
+#ifdef SECFLTR
+uint SecurityFilteringEnabled;
+#endif // SECFLTR
+
+#ifdef VXD
+uint PreloadCount;
+#endif
+
+#ifdef _PNP_POWER
+HANDLE AddressChangeHandle;
+#endif
+
+#ifdef VXD
+TDIDispatchTable TLDispatch;
+
+#ifndef CHICAGO
+char TransportName[] = "MSTCP";
+#else
+char TransportName[] = TCP_NAME;
+#endif
+
+#ifdef CHICAGO
+extern int RegisterAddrChangeHndlr(void *Handler, uint Add);
+#endif
+
+#endif
+
+uint StartTime;
+
+extern void *UDPProtInfo;
+extern void *RawProtInfo;
+
+extern int InitTCPConn(void);
+extern void UnInitTCPConn(void);
+extern IP_STATUS TLGetIPInfo(IPInfo *Buffer, int Size);
+
+
+
+//
+// All of the init code can be discarded.
+//
+#ifdef NT
+#ifdef ALLOC_PRAGMA
+
+int tlinit();
+
+#pragma alloc_text(INIT, tlinit)
+
+#endif // ALLOC_PRAGMA
+#endif
+
+//* Dummy routines for UDP only version. All of these routines return
+// 'Invalid Request'.
+
+#ifdef UDP_ONLY
+TDI_STATUS
+TdiOpenConnection(PTDI_REQUEST Request, PVOID Context)
+{
+ return TDI_INVALID_REQUEST;
+}
+TDI_STATUS
+TdiCloseConnection(PTDI_REQUEST Request)
+{
+ return TDI_INVALID_REQUEST;
+}
+
+TDI_STATUS
+TdiAssociateAddress(PTDI_REQUEST Request, HANDLE AddrHandle)
+{
+ return TDI_INVALID_REQUEST;
+}
+TDI_STATUS TdiDisAssociateAddress(PTDI_REQUEST Request)
+{
+ return TDI_INVALID_REQUEST;
+}
+TDI_STATUS TdiConnect(PTDI_REQUEST Request, void *Timeout,
+ PTDI_CONNECTION_INFORMATION RequestAddr,
+ PTDI_CONNECTION_INFORMATION ReturnAddr)
+{
+ return TDI_INVALID_REQUEST;
+}
+TDI_STATUS TdiListen(PTDI_REQUEST Request, ushort Flags,
+ PTDI_CONNECTION_INFORMATION AcceptableAddr,
+ PTDI_CONNECTION_INFORMATION ConnectedAddr)
+{
+ return TDI_INVALID_REQUEST;
+}
+TDI_STATUS TdiAccept(PTDI_REQUEST Request,
+ PTDI_CONNECTION_INFORMATION AcceptInfo,
+ PTDI_CONNECTION_INFORMATION ConnectedInfo)
+{
+ return TDI_INVALID_REQUEST;
+}
+TDI_STATUS TdiReceive(PTDI_REQUEST Request, ushort *Flags,
+ uint *RcvLength, PNDIS_BUFFER Buffer)
+{
+ return TDI_INVALID_REQUEST;
+}
+
+TDI_STATUS TdiSend(PTDI_REQUEST Request, ushort Flags, uint SendLength,
+ PNDIS_BUFFER Buffer)
+{
+ return TDI_INVALID_REQUEST;
+}
+
+TDI_STATUS TdiDisconnect(PTDI_REQUEST Request, PVOID Timeout, ushort Flags,
+ PTDI_CONNECTION_INFORMATION DisconnectInfo,
+ PTDI_CONNECTION_INFORMATION ReturnInfo)
+{
+ return TDI_INVALID_REQUEST;
+}
+
+#endif
+
+#ifdef VXD
+
+extern void *ConvertPtr(void *Ptr);
+
+//** Routines to handle incoming QueryInformation requests, and dispatch
+//** them.
+
+struct ClientReq {
+ ushort cr_opcode;
+ void *cr_ID;
+ void *cr_buffer;
+ void *cr_length;
+ void *cr_context;
+};
+
+//* VxDQueryInfo - VxD thunk to query information.
+//
+// The VxD thunk to TdiQueryInformationEx. All we do it convert the pointers
+// and call in.
+//
+// Input: Req - A pointer to a ClientReq structure.
+//
+// Returns: Status of command.
+//
+TDI_STATUS
+VxDQueryInfo(struct ClientReq *Req)
+{
+ NDIS_BUFFER Buffer;
+ TDI_REQUEST Request;
+ uint *Size;
+ TDIObjectID *ID;
+ void *Context;
+
+ CTEAssert(Req->cr_opcode == 0);
+
+ CTEMemSet(&Request, 0, sizeof(TDI_REQUEST));
+
+ ID = (TDIObjectID *)ConvertPtr(Req->cr_ID);
+ Size = (uint *)ConvertPtr(Req->cr_length);
+
+#ifdef DEBUG
+ Buffer.Signature = BUFFER_SIGN;
+#endif
+
+ Buffer.VirtualAddress = ConvertPtr(Req->cr_buffer);
+ Buffer.Length = *Size;
+ Buffer.Next = NULL;
+
+ return TdiQueryInformationEx(&Request, ID, &Buffer, Size,
+ ConvertPtr(Req->cr_context));
+
+}
+
+//* VxDSetInfo - VxD thunk to set information.
+//
+// The VxD thunk to TdiSetInformationEx. All we do it convert the pointers
+// and call in.
+//
+// Input: Req - A pointer to a ClientReq structure.
+//
+// Returns: Status of command.
+//
+TDI_STATUS
+VxDSetInfo(struct ClientReq *Req)
+{
+ TDIObjectID *ID;
+ uint *Size;
+ void *Buffer;
+ TDI_REQUEST Request;
+
+ CTEAssert(Req->cr_opcode == 1);
+
+ CTEMemSet(&Request, 0, sizeof(TDI_REQUEST));
+
+ ID = (TDIObjectID *)ConvertPtr(Req->cr_ID);
+ Size = (uint *)ConvertPtr(Req->cr_length);
+ Buffer = ConvertPtr(Req->cr_buffer);
+
+ return TdiSetInformationEx(&Request, ID, Buffer, *Size);
+
+}
+#endif
+
+#ifdef CHICAGO
+//* AddrChange - Receive notification of an IP address change.
+//
+// Called by IP when an address comes or goes. We get the address
+// and mask, and depending on what's actually happened we may close address
+// and connections.
+//
+// Input: Addr - IP address that's coming or going.
+// Mask - Mask for Addr.
+// Context - PNP context (unused)
+// IPContext - IP context (unused)
+// Added - True if the address is coming, False if it's going.
+//
+// Returns: Nothing.
+//
+void
+AddrChange(IPAddr Addr, IPMask Mask, void *Context, ushort IPContext,
+ uint Added)
+{
+ if (Added) {
+ // He's adding an address. Re-query the entity list now.
+ EntityList[0].tei_entity = CO_TL_ENTITY;
+ EntityList[0].tei_instance = 0;
+ EntityList[1].tei_entity = CL_TL_ENTITY;
+ EntityList[1].tei_instance = 0;
+ EntityCount = 2;
+
+ // When we have multiple networks under us, we'll want to loop through
+ // here calling them all. For now just call the one we have.
+ (*LocalNetInfo.ipi_getelist)(EntityList, &EntityCount);
+ } else {
+ // He's deleting an address.
+ if (!IP_ADDR_EQUAL(Addr, NULL_IP_ADDR)) {
+#ifndef UDP_ONLY
+ TCBWalk(DeleteTCBWithSrc, &Addr, NULL, NULL);
+#endif
+ InvalidateAddrs(Addr);
+ }
+
+ }
+}
+#endif
+
+#ifdef NT
+#ifdef _PNP_POWER
+
+//* AddressArrival - Handle an IP address arriving
+//
+// Called by TDI when an address arrives. All we do is query the
+// EntityList.
+//
+// Input: Addr - IP address that's coming.
+//
+// Returns: Nothing.
+//
+void
+AddressArrival(PTA_ADDRESS Addr)
+{
+ if (Addr->AddressType == TDI_ADDRESS_TYPE_IP) {
+ // He's adding an address. Re-query the entity list now.
+ EntityList[0].tei_entity = CO_TL_ENTITY;
+ EntityList[0].tei_instance = 0;
+ EntityList[1].tei_entity = CL_TL_ENTITY;
+ EntityList[1].tei_instance = 0;
+ EntityCount = 2;
+
+ // When we have multiple networks under us, we'll want to loop through
+ // here calling them all. For now just call the one we have.
+ (*LocalNetInfo.ipi_getelist)(EntityList, &EntityCount);
+ }
+}
+
+//* AddressDeletion - Handle an IP address going away.
+//
+// Called by TDI when an address is deleted. If it's an address we
+// care about we'll clean up appropriately.
+//
+// Input: Addr - IP address that's going.
+//
+// Returns: Nothing.
+//
+void
+AddressDeletion(PTA_ADDRESS Addr)
+{
+ PTDI_ADDRESS_IP MyAddress;
+ IPAddr LocalAddress;
+
+ if (Addr->AddressType == TDI_ADDRESS_TYPE_IP) {
+ // He's deleting an address.
+
+ MyAddress = (PTDI_ADDRESS_IP)Addr->Address;
+ LocalAddress = MyAddress->in_addr;
+
+ if (!IP_ADDR_EQUAL(LocalAddress, NULL_IP_ADDR)) {
+#ifndef UDP_ONLY
+ TCBWalk(DeleteTCBWithSrc, &LocalAddress, NULL, NULL);
+#endif
+ InvalidateAddrs(LocalAddress);
+ }
+ }
+}
+
+#endif // _PNP_POWER
+#endif // NT
+
+#pragma BEGIN_INIT
+
+extern uchar TCPGetConfigInfo(void);
+
+extern uchar IPPresent(void);
+
+//** tlinit - Initialize the transport layer.
+//
+// The main transport layer initialize routine. We get whatever config
+// info we need, initialize some data structures, get information
+// from IP, do some more initialization, and finally register our
+// protocol values with IP.
+//
+// Input: Nothing
+//
+// Returns: True is we succeeded, False if we fail to initialize.
+//
+int
+tlinit()
+{
+#ifdef VXD
+ void *PreloadPtrs[MAX_PRELOAD_COUNT];
+ uint i;
+#endif
+
+ uint TCBInitialized = 0;
+
+ if (!CTEInitialize())
+ return FALSE;
+
+#ifdef VXD
+ if (!IPPresent())
+ return FALSE;
+#endif
+
+ if (!TCPGetConfigInfo())
+ return FALSE;
+
+ StartTime = CTESystemUpTime();
+
+#ifndef UDP_ONLY
+ KeepAliveTime = MS_TO_TICKS(KeepAliveTime);
+ KAInterval = MS_TO_TICKS(KAInterval);
+
+#endif
+
+ CTERefillMem();
+
+ // Get net information from IP.
+ if (TLGetIPInfo(&LocalNetInfo, sizeof(IPInfo)) != IP_SUCCESS)
+ goto failure;
+
+ if (LocalNetInfo.ipi_version != IP_DRIVER_VERSION)
+ goto failure; // Wrong version of IP.
+
+#ifdef CHICAGO
+ if (!RegisterAddrChangeHndlr(AddrChange, TRUE))
+ goto failure;
+#endif
+
+#ifdef NT
+#ifdef _PNP_POWER
+
+ (void)TdiRegisterAddressChangeHandler(
+ AddressArrival,
+ AddressDeletion,
+ &AddressChangeHandle
+ );
+
+#endif // _PNP_POWER
+#endif // NT
+
+ //* Initialize addr obj management code.
+ if (!InitAddr())
+ goto failure;
+
+ CTERefillMem();
+ if (!InitDG(sizeof(UDPHeader)))
+ goto failure;
+
+#ifndef UDP_ONLY
+ MaxConnections = MIN(MaxConnections, INVALID_CONN_INDEX - 1);
+ CTERefillMem();
+ if (!InitTCPConn())
+ goto failure;
+
+ CTERefillMem();
+ if (!InitTCB())
+ goto failure;
+
+ TCBInitialized = 1;
+
+ CTERefillMem();
+ if (!InitTCPRcv())
+ goto failure;
+
+ CTERefillMem();
+ if (!InitTCPSend())
+ goto failure;
+
+ CTEMemSet(&TStats, 0, sizeof(TCPStats));
+
+ TStats.ts_rtoalgorithm = TCP_RTO_VANJ;
+ TStats.ts_rtomin = MIN_RETRAN_TICKS * MS_PER_TICK;
+ TStats.ts_rtomax = MAX_REXMIT_TO * MS_PER_TICK;
+ TStats.ts_maxconn = (ulong) TCP_MAXCONN_DYNAMIC;
+
+#endif
+
+ CTEMemSet(&UStats,0, sizeof(UDPStats));
+
+
+ // Register our UDP protocol handler.
+ UDPProtInfo = TLRegisterProtocol(PROTOCOL_UDP, UDPRcv, DGSendComplete,
+ UDPStatus, NULL);
+
+ if (UDPProtInfo == NULL)
+ goto failure; // Failed to register!
+
+ // Register the Raw IP (wildcard) protocol handler.
+ RawProtInfo = TLRegisterProtocol(PROTOCOL_ANY, RawRcv, DGSendComplete,
+ RawStatus, NULL);
+
+ if (RawProtInfo == NULL) {
+ CTEPrint(("failed to register raw prot with IP\n"));
+ goto failure; // Failed to register!
+ }
+
+#ifdef VXD
+ TLDispatch.TdiOpenAddressEntry = TdiOpenAddress;
+ TLDispatch.TdiCloseAddressEntry = TdiCloseAddress;
+ TLDispatch.TdiSendDatagramEntry = TdiSendDatagram;
+ TLDispatch.TdiReceiveDatagramEntry = TdiReceiveDatagram;
+ TLDispatch.TdiSetEventEntry = TdiSetEvent;
+
+ TLDispatch.TdiOpenConnectionEntry = TdiOpenConnection;
+ TLDispatch.TdiCloseConnectionEntry = TdiCloseConnection;
+ TLDispatch.TdiAssociateAddressEntry = TdiAssociateAddress;
+ TLDispatch.TdiDisAssociateAddressEntry = TdiDisAssociateAddress;
+ TLDispatch.TdiConnectEntry = TdiConnect;
+ TLDispatch.TdiDisconnectEntry = TdiDisconnect;
+ TLDispatch.TdiListenEntry = TdiListen;
+ TLDispatch.TdiAcceptEntry = TdiAccept;
+ TLDispatch.TdiReceiveEntry = TdiReceive;
+ TLDispatch.TdiSendEntry = TdiSend;
+ TLDispatch.TdiQueryInformationEntry = TdiQueryInformation;
+ TLDispatch.TdiSetInformationEntry = TdiSetInformation;
+ TLDispatch.TdiActionEntry = TdiAction;
+ TLDispatch.TdiQueryInformationExEntry = TdiQueryInformationEx;
+ TLDispatch.TdiSetInformationExEntry = TdiSetInformationEx;
+
+ if (!TLRegisterDispatch(TransportName, &TLDispatch))
+ goto failure;
+
+#endif
+
+ CTERefillMem();
+
+ // Now query the lower layer entities, and save the information.
+ EntityList = CTEAllocMem(sizeof(TDIEntityID) * MAX_TDI_ENTITIES);
+ if (EntityList == NULL)
+ goto failure;
+
+ EntityList[0].tei_entity = CO_TL_ENTITY;
+ EntityList[0].tei_instance = 0;
+ EntityList[1].tei_entity = CL_TL_ENTITY;
+ EntityList[1].tei_instance = 0;
+ EntityCount = 2;
+
+ // When we have multiple networks under us, we'll want to loop through
+ // here calling them all. For now just call the one we have.
+ (*LocalNetInfo.ipi_getelist)(EntityList, &EntityCount);
+
+ CTERefillMem();
+
+#ifdef VXD
+ // Allocate memory as needed to satisfy the heap preload requirements. We'll
+ // allocate a bunch of memory from the IFSMgr and then free it, so
+ // hopefully it'll be there later when we need it.
+ PreloadCount = MIN(PreloadCount, MAX_PRELOAD_COUNT);
+ for (i = 0; i < PreloadCount; i++) {
+ void *Temp;
+
+ Temp = CTEAllocMem(PRELOAD_BLOCK_SIZE);
+ if (Temp != NULL)
+ PreloadPtrs[i] = Temp;
+ else
+ break;
+ CTERefillMem();
+ }
+
+ PreloadCount = i;
+ for (i = 0; i < PreloadCount; i++) {
+ CTEFreeMem(PreloadPtrs[i]);
+ }
+
+#endif
+
+ return TRUE;
+
+ // Come here to handle all failure cases.
+failure:
+
+ // If we've registered Raw IP, unregister it now.
+ if (RawProtInfo != NULL)
+ TLRegisterProtocol(PROTOCOL_ANY, NULL, NULL, NULL, NULL);
+
+ // If we've registered UDP, unregister it now.
+ if (UDPProtInfo != NULL)
+ TLRegisterProtocol(PROTOCOL_UDP, NULL, NULL, NULL, NULL);
+#ifndef UDP_ONLY
+ UnInitTCPSend();
+ UnInitTCPRcv();
+ if (TCBInitialized) {
+ UnInitTCB();
+ }
+ UnInitTCPConn();
+#endif
+
+ CTERefillMem();
+ return FALSE;
+}
+
+#pragma END_INIT
diff --git a/private/ntos/tdi/tcpip/tcp/mips/sources b/private/ntos/tdi/tcpip/tcp/mips/sources
new file mode 100644
index 000000000..e4f0fd9fa
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/mips/sources
@@ -0,0 +1,4 @@
+MIPS_SOURCES= \
+ ..\mips\xsum.s
+
+
diff --git a/private/ntos/tdi/tcpip/tcp/mips/xsum.s b/private/ntos/tdi/tcpip/tcp/mips/xsum.s
new file mode 100644
index 000000000..1463a897b
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/mips/xsum.s
@@ -0,0 +1,243 @@
+// TITLE("Compute Checksum")
+//++
+//
+// Copyright (c) 1992-1994 Microsoft Corporation
+//
+// Module Name:
+//
+// tcpxsum.s
+//
+// Abstract:
+//
+// This module implement a function to compute the checksum of a buffer.
+//
+// Author:
+//
+// David N. Cutler (davec) 27-Jan-1992
+//
+// Environment:
+//
+// User mode.
+//
+// Revision History:
+//
+//--
+
+#include "ksmips.h"
+
+ SBTTL("Compute Checksum")
+//++
+//
+// ULONG
+// tcpxsum (
+// IN ULONG Checksum,
+// IN PUCHAR Source,
+// IN ULONG Length
+// )
+//
+// Routine Description:
+//
+// This function computes the checksum of the specified buffer.
+//
+// Arguments:
+//
+// Checksum (a0) - Supplies the initial checksum value.
+//
+// Source (a1) - Supplies a pointer to the checksum buffer.
+//
+// Length (a2) - Supplies the length of the buffer in bytes.
+//
+// Return Value:
+//
+// The computed checksum is returned as the function value.
+//
+//--
+
+ LEAF_ENTRY(tcpxsum)
+
+//
+// Clear the computed checksum and check if the buffer is word aligned.
+//
+
+ move a3,zero // clear computed checksum
+ and v1,a1,1 // check if buffer word aligned
+ beq zero,a2,90f // if eq, no bytes to checksum
+ and t1,a2,1 // check if length is even
+ beq zero,v1,10f // if eq, buffer word aligned
+
+//
+// Initialize the checksum to the first byte shifted up by a byte.
+//
+
+ lbu t2,0(a1) // get first byte of buffer
+ addu a1,a1,1 // advance buffer address
+ subu a2,a2,1 // reduce count of bytes to checksum
+ dsll a3,t2,8 // shift byte up in computed checksum
+ beq zero,a2,90f // if eq, no more bytes in buffer
+ and t1,a2,1 // check if length is even
+
+//
+// Check if the length of the buffer if an even number of bytes.
+//
+// If the buffer is not an even number of bytes, then add the last byte
+// to the computed checksum.
+//
+
+10: and t3,a1,2 // check if buffer long aligned
+ beq zero,t1,20f // if eq, even number of bytes
+ addu t0,a1,a2 // compute address of ending byte + 1
+ lbu t2,-1(t0) // get last byte of buffer
+ subu a2,a2,1 // reduce count of bytes to checksum
+ daddu a3,a3,t2 // add last byte to computed checksum
+ beq zero,a2,90f // if eq, no more bytes in buffer
+
+//
+// Check if the buffer is long aligned.
+//
+// If the buffer is not long aligned, then long align the buffer.
+//
+
+20: and t0,a2,8 - 1 // compute residual bytes
+ beq zero,t3,30f // if eq, buffer long aligned
+ lhu t2,0(a1) // get next word of buffer
+ addu a1,a1,2 // advance buffer address
+ subu a2,a2,2 // reduce count of bytes to checksum
+ daddu a3,a3,t2 // add next word to computed checksum
+ beq zero,a2,90f // if eq, no more bytes in buffer
+ and t0,a2,8 - 1 // compute residual bytes
+
+//
+// Compute checksum.
+//
+
+ .set noreorder
+ .set at
+30: subu t9,a2,t0 // subtract out residual bytes
+ beq zero,t9,70f // if eq, no large blocks
+ addu t8,a1,t9 // compute ending block address
+ move a2,t0 // set residual number of bytes
+ and v0,t9,1 << 3 // check for initial 8-byte block
+ beq zero,v0,40f // if eq, no 8-byte block
+ and v0,t9,1 << 4 // check for initial 16-byte block
+ lwu t0,0(a1) // load 8-byte block
+ lwu t1,4(a1) //
+ addu a1,a1,8 // advance source address
+ daddu a3,a3,t0 // compute 8-byte checksum
+ beq t8,a1,70f // if eq, end of block
+ daddu a3,a3,t1 //
+40: beq zero,v0,50f // if eq, no 16-byte block
+ and v0,t9,1 << 5 // check for initial 32-byte block
+ lwu t0,0(a1) // load 16-byte data block
+ lwu t1,4(a1) //
+ lwu t2,8(a1) //
+ lwu t3,12(a1) //
+ addu a1,a1,16 // advance source address
+ daddu a3,a3,t0 // compute 16-byte block checksum
+ daddu a3,a3,t1 //
+ daddu a3,a3,t2 //
+ beq t8,a1,70f // if eq, end of block
+ daddu a3,a3,t3 //
+50: beq zero,v0,60f // if eq, no 32-byte block
+ lwu t0,0(a1) // load 32-byte data block
+ lwu t1,4(a1) //
+ lwu t2,8(a1) //
+ lwu t3,12(a1) //
+ lwu t4,16(a1) //
+ lwu t5,20(a1) //
+ lwu t6,24(a1) //
+ lwu t7,28(a1) //
+ addu a1,a1,32 // advance source address
+ daddu a3,a3,t0 // compute 32-byte block checksum
+ daddu a3,a3,t1 //
+ daddu a3,a3,t2 //
+ daddu a3,a3,t3 //
+ daddu a3,a3,t4 //
+ daddu a3,a3,t5 //
+ daddu a3,a3,t6 //
+ beq t8,a1,70f // if eq, end of block
+ daddu a3,a3,t7 //
+55: lwu t0,0(a1) // load 32-byte data block
+60: lwu t1,4(a1) //
+ lwu t2,8(a1) //
+ lwu t3,12(a1) //
+ lwu t4,16(a1) //
+ lwu t5,20(a1) //
+ lwu t6,24(a1) //
+ lwu t7,28(a1) //
+ daddu a3,a3,t0 // compute 32-byte block checksum
+ daddu a3,a3,t1 //
+ daddu a3,a3,t2 //
+ daddu a3,a3,t3 //
+ daddu a3,a3,t4 //
+ daddu a3,a3,t5 //
+ daddu a3,a3,t6 //
+ daddu a3,a3,t7 //
+ lwu t0,32(a1) // load 32-byte data block
+ lwu t1,36(a1) //
+ lwu t2,40(a1) //
+ lwu t3,44(a1) //
+ lwu t4,48(a1) //
+ lwu t5,52(a1) //
+ lwu t6,56(a1) //
+ lwu t7,60(a1) //
+ addu a1,a1,64 // advance source address
+ daddu a3,a3,t0 // compute 32-byte block checksum
+ daddu a3,a3,t1 //
+ daddu a3,a3,t2 //
+ daddu a3,a3,t3 //
+ daddu a3,a3,t4 //
+ daddu a3,a3,t5 //
+ daddu a3,a3,t6 //
+ bne t8,a1,55b // if ne, not end of block
+ daddu a3,a3,t7 //
+ .set at
+ .set reorder
+
+//
+// Compute the checksum of in 2-byte blocks.
+//
+
+70: addu t8,a1,a2 // compute ending block address
+ beq zero,a2,90f // if eq, no bytes to checksum
+
+ .set noreorder
+ .set noat
+80: lhu t0,0(a1) // compute checksum of 2-byte block
+ addu a1,a1,2 // advance source address
+ bne t8,a1,80b // if ne, more 2-byte blocks
+ daddu a3,a3,t0 //
+ .set at
+ .set reorder
+
+//
+// Combine input checksum and paritial checksum.
+//
+// If the input buffer was byte aligned, then word swap bytes in computed
+// checksum before combination with the input checksum.
+//
+
+90: beq zero,v1,100f // if eq, buffer word aligned
+ li t6,0xff00ff // get byte swap mask
+ dsll t7,t6,32 //
+ or t6,t6,t7 //
+ and t3,a3,t6 // isolate bytes 0, 2, 4, and 6
+ dsll t3,t3,8 // shift bytes 0, 2, 4, and 6 into position
+ dsrl t4,a3,8 // shift bytes 1, 3, 5, and 7 into position
+ and t4,t4,t6 // isolate bytes 1, 3, 5, and 7
+ or a3,t4,t3 // merge checksum bytes
+100: dsll a0,a0,32 // make sure upper 32 bits are clear
+ dsrl a0,a0,32 //
+ daddu v0,a0,a3 // combine checksums
+ dsrl t0,v0,32 // swap checksum longs
+ dsll t1,v0,32 //
+ or t0,t0,t1 //
+ daddu v0,v0,t0 // compute 32-bit checksum with carry
+ dsrl v0,v0,32 //
+ srl t0,v0,16 // swap checksum words
+ sll t1,v0,16 //
+ or t0,t0,t1 //
+ addu v0,v0,t0 // add words with carry into high word
+ srl v0,v0,16 // extract final checksum
+ j ra // return
+
+ .end tcpxsum
diff --git a/private/ntos/tdi/tcpip/tcp/mp/makefile b/private/ntos/tdi/tcpip/tcp/mp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/mp/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/tcpip/tcp/mp/sources b/private/ntos/tdi/tcpip/tcp/mp/sources
new file mode 100644
index 000000000..dfff2b249
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/mp/sources
@@ -0,0 +1,30 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+NT_UP=0
+
+LINKLIBS=..\..\ip\mp\obj\*\ip.lib
+TARGETPATH=\nt\public\sdk\lib
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/tcpip/tcp/mp/tcpip.prf b/private/ntos/tdi/tcpip/tcp/mp/tcpip.prf
new file mode 100644
index 000000000..4f03cef97
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/mp/tcpip.prf
@@ -0,0 +1,297 @@
+TdiQueryInformation@20
+TCPDispatchInternalDeviceControl@8
+DerefTCB@8
+FreeARPBuffer@8
+ProcessTCBDelayQ@0
+ARPTransmit@16
+TCPRcv@48
+IPRcv@28
+IPRcvComplete@0
+GetARPBuffer@12
+FreeIPPacket@4
+TCBTimeout@8
+ARPTimeout@8
+ICMPTimer@4
+IPTimeout@8
+IGMPTimer@4
+IndicateData@16
+TCPSendComplete@8
+GetSendReq@0
+FreeSendReq@4
+FillTCPHeader@8
+RcvWin@4
+IPTransmit@36
+GetRcvReq@0
+GetTCPHeader@0
+FindTCB@16
+TCPSendData@8
+TdiSend@16
+TCPSend@8
+ACKData@8
+FreeRBChain@4
+FreeRcvReq@4
+TCPDataRequestComplete@12
+FindUserRcv@4
+TCPRcvComplete@0
+GetLocalNTE@8
+GetConnFromConnID@4
+ARPSendData@16
+XsumRcvBuf@8
+FreeTCPHeader@4
+ARPRcv@28
+XsumSendChain@8
+CTEStartTimer@16
+DeliverToUser@32
+GetIPPacket@0
+ARPRcvComplete@4
+CTESystemUpTime@0
+ARPSendComplete@12
+IPSendComplete@12
+DelayAction@8
+TCPPrepareIrpForCancel@12
+BufferData@16
+SendACK@4
+CompleteRcvs@4
+FreePartialRB@8
+GetAddrObj@16
+AddrOnIF@8
+FindRTE@20
+TdiCopyBufferToMdl@24
+TCPGetMdlChainByteCount@4
+IPHash@4
+LookupRTE@12
+OpenRCE@24
+TCPQueryInformation@8
+CopyFlatToNdis@20
+FindListenConn@16
+DummyDone@8
+GetAddrType@4
+InitTCBFromConn@16
+tcpxsum@12
+FindMSS@4
+DelayDerefAO@4
+FindRCE@12
+TryToCloseTCB@12
+InitRCE@4
+NotifyOfDisc@12
+UpdateConnInfo@16
+GoToEstab@4
+TCPDisconnect@8
+FreeConnReq@4
+TdiDisconnect@20
+IPGetLocalMTU@8
+CloseRCE@4
+IPInitOptions@4
+AdjustRcvWin@4
+BuildTDIAddress@12
+SendSYN@8
+AllocTCB@0
+ProcessUserOptions@8
+FreeTCB@4
+RemoveTCBFromConn@4
+InitSendState@4
+CompleteConnReq@12
+IPFreeOptions@4
+TCPRequestComplete@12
+InvalidSourceAddress@4
+AcceptConn@8
+RemoveTCB@4
+GetConnReq@0
+CloseTCB@8
+RemoveConnFromTCB@4
+FinishRemoveTCBFromConn@4
+IsBCastOnNTE@8
+InsertTCB@4
+ResetSendNext@8
+ARPLookup@12
+BCastRcv@40
+IPGetAddrType@4
+UDPRcv@48
+GetFirstAddrObj@16
+IPForward@32
+GetNextAddrObj@4
+UDPDeliver@32
+LockedDerefIF@4
+BestNTEForIF@8
+ARPInvalidate@8
+IsBCastOnIF@8
+ARPSendBCast@16
+UDPSendDatagram@8
+DGSendComplete@8
+TdiSendDatagram@20
+DerefAO@4
+FreeDGSendReq@4
+GetDGSendReq@0
+FreeDGHeader@4
+UDPSend@8
+GetAddress@12
+ARPRemoveRCE@8
+HandleARPPacket@24
+IsLocalAddr@8
+ARPLocalAddr@8
+IPRouteTimeout@8
+GetConnID@4
+TdiAssociateAddress@8
+FindEA@12
+TCPCreate@12
+TCPAssociateAddress@8
+TdiOpenConnection@8
+TCPDispatch@8
+TdiMapUserRequest@12
+IPGetPInfo@16
+SendARPPacket@40
+RemoveARPTableEntry@8
+CreateARPTableEntry@12
+SendARPRequest@20
+GrowARPHeaders@4
+GrowTCPHeaderList@0
+TdiCloseConnection@4
+RemoveConnFromAO@8
+TCPCloseObjectComplete@12
+TCPClose@8
+CloseDone@8
+TCPCleanup@12
+FreeConnID@4
+DummyCmplt@12
+LoopAddAddr@16
+FindIGMPAddr@12
+CTEInitEvent@8
+TdiSetEvent@16
+ARPSetMCastList@4
+IPGetInfo@8
+IGMPAddrChange@12
+ICMPInit@4
+IGMPInit@0
+ARPRequestComplete@12
+FreeAORequest@4
+TCPQueryInformationEx@8
+ARPFindMCast@12
+InitAdapter@4
+CTESignal@8
+CTEBlock@4
+CTEInitTimer@4
+InsertAddrObj@4
+TdiQueryInformationEx@20
+ARPAddAddr@16
+TdiOpenAddress@16
+InitNTERouting@12
+ARPAddMCast@8
+InitIGMPForNTE@4
+FindAnyAddrObj@8
+GrowDGHeaderList@0
+FindSpecificRTE@20
+InitNTE@4
+CopyToNdis@16
+IPRegisterProtocol@20
+GetAddrOptions@12
+InitInterface@8
+TdiSetInformationEx@16
+TCPConnect@8
+TCPQueryInformationExComplete@12
+TCPSetInformationEx@8
+LockedAddRoute@36
+TCPAcdBind@0
+AddRoute@36
+TdiConnect@16
+LoopXmit@16
+AddValueSecurityFilter@12
+InitGateway@4
+ARPOAComplete@12
+CTEScheduleEvent@8
+GetHashMask@8
+InitLoopback@4
+RawStatus@28
+FindInterfaceEntry@4
+FindProtocolEntry@8
+AddProtocolSecurityFilter@12
+TdiRegisterNetAddress@8
+UDPStatus@28
+ARPDynRegister@36
+FindInsertPoint@4
+IPAddInterface@20
+NotifyAddrChange@28
+TCPStatus@28
+TdiInitialize@0
+TdiRegisterDeviceObject@8
+TdiRegisterAddressChangeHandler@12
+CTEInitialize@0
+ARPBindAdapter@20
+ICMPStatus@28
+IPQueryInfo@16
+DeleteProtocolValueEntries@4
+ModifyProtocolEntry@12
+ModifyInterfaceEntry@16
+ModifySecurityFilter@16
+DoNDISRequest@24
+LoopGetEList@12
+TCPDisassociateAddress@8
+TdiDisAssociateAddress@4
+EnumRegMultiSz@12
+AddressArrival@4
+ARPGetEList@12
+GrowIPPacketList@0
+IPGetEList@8
+RTValidateContext@8
+RTReadNext@8
+GetCurrentRouteTable@4
+AddNTERoutes@4
+GetSecurityFilterList@12
+LoopXmitRtn@8
+InitDG@4
+IPGetConfig@0
+InitTimestamp@0
+IPProcessAdapterSection@8
+TCPInitializeParameter@12
+TLGetIPInfo@8
+InitializeSecurityFilters@0
+IPFreeConfig@4
+InitTCPRcv@0
+InitAddr@0
+IPInit@0
+GetTime@0
+ARPInit@0
+InitTCPConn@0
+IPProcessConfiguration@0
+IPDriverEntry@8
+tlinit@0
+InitTCPSend@0
+InitTCB@0
+GetIFAddrList@8
+ARPOpen@4
+TCPDispatchDeviceControl@8
+TCPSetEventHandler@8
+ARPRegister@12
+GetRegStringValue@16
+IsDHCPZeroAddress@4
+EnumSecurityFilterValue@12
+CloseIFConfig@4
+UseEtherSNAP@4
+OpenIFConfig@8
+IPConvertStringToAddress@8
+SetRegDWORDValue@12
+GetArpCacheLife@0
+InitRegDWORDParameter@16
+GetRegMultiSZValue@12
+OpenRegKey@8
+GetGeneralIFConfig@8
+GetAlwaysSourceRoute@0
+GetRegSZValue@16
+GetRegDWORDValue@12
+IsLLInterfaceValueNull@4
+DerefIF@4
+ARPQueryInfo@20
+DriverEntry@8
+TCPGetConfigInfo@0
+SendIPPacket@28
+GetIPHdrBuffer@0
+GrowHdrBufList@0
+FreeIPHdrBuffer@4
+InitRouting@4
+TLRegisterProtocol@20
+LookupNextHopWithBuffer@28
+SetPersistentRoutesForNTE@12
+SendARPReply@28
+GetGMTDelta@0
+SendRSTFromHeader@20
+InvalidateRCEChain@4
+LoopQInfo@20
diff --git a/private/ntos/tdi/tcpip/tcp/ntautodl.c b/private/ntos/tdi/tcpip/tcp/ntautodl.c
new file mode 100644
index 000000000..0c244aff7
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/ntautodl.c
@@ -0,0 +1,258 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntautodl.c
+
+Abstract:
+
+ NT specific routines for interfacing with the
+ RAS AutoDial driver (acd.sys).
+
+Author:
+
+ Anthony Discolo (adiscolo) Aug 30, 1995
+
+Revision History:
+
+ Who When What
+ -------- -------- ----------------------------------------------
+ adiscolo 08-30-95 created
+
+Notes:
+
+--*/
+
+#include <oscfg.h>
+#include <ntrtl.h>
+#include <ntddip.h>
+#include <ndis.h>
+#include <cxport.h>
+#include <tdikrnl.h>
+#include <tdint.h>
+#include <tdistat.h>
+#include <tdiinfo.h>
+#include <ip.h>
+#include <acd.h>
+#include <acdapi.h>
+
+#include "queue.h"
+#include "addr.h"
+#include "tcp.h"
+#include "tcb.h"
+#include "tcpconn.h"
+#include "udp.h"
+#include "tlcommon.h"
+#include <ntddtcp.h>
+
+//
+// Macro for calculating
+// an IP address component.
+//
+#define UC(pIpAddr, i) ((ULONG)(((PCHAR)(pIpAddr))[i]) & 0xff)
+
+//
+// Global variables
+//
+BOOLEAN fAcdLoadedG;
+ACD_DRIVER AcdDriverG;
+ULONG ulDriverIdG = 'Tcp ';
+
+
+
+VOID
+TCPNoteNewConnection(
+ IN TCB *pTCB,
+ IN CTELockHandle Handle
+ )
+{
+ ACD_ADDR addr;
+ ACD_ADAPTER adapter;
+
+ //
+ // If there is a NULL source
+ // or destination IP address, then return.
+ //
+ if (!pTCB->tcb_saddr || !pTCB->tcb_daddr) {
+ CTEFreeLock(&pTCB->tcb_lock, Handle);
+ return;
+ }
+ //
+ // We also know we aren't interested in
+ // any connections on the 127 network.
+ //
+ if (UC(&pTCB->tcb_daddr, 0) == 127) {
+ CTEFreeLock(&pTCB->tcb_lock, Handle);
+ return;
+ }
+ //
+ // Get the address of the connection.
+ //
+ addr.fType = ACD_ADDR_IP;
+ addr.ulIpaddr = pTCB->tcb_daddr;
+ adapter.fType = ACD_ADAPTER_IP;
+ adapter.ulIpaddr = pTCB->tcb_saddr;
+ //
+ // Release the TCB lock handle before
+ // calling out of this driver.
+ //
+ CTEFreeLock(&pTCB->tcb_lock, Handle);
+ //
+ // Inform the automatic connection driver
+ // of the new connection.
+ //
+ (*AcdDriverG.lpfnNewConnection)(&addr, &adapter);
+} // TCPNoteNewConnection
+
+
+
+VOID
+TCPAcdBind()
+{
+ NTSTATUS status;
+ UNICODE_STRING nameString;
+ IO_STATUS_BLOCK ioStatusBlock;
+ PIRP pIrp;
+ PFILE_OBJECT pAcdFileObject;
+ PDEVICE_OBJECT pAcdDeviceObject;
+ PACD_DRIVER pDriver = &AcdDriverG;
+
+ //
+ // Initialize the name of the automatic
+ // connection device.
+ //
+ RtlInitUnicodeString(&nameString, ACD_DEVICE_NAME);
+ //
+ // Get the file and device objects for the
+ // device.
+ //
+ status = IoGetDeviceObjectPointer(
+ &nameString,
+ SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
+ &pAcdFileObject,
+ &pAcdDeviceObject);
+ if (status != STATUS_SUCCESS)
+ return;
+ //
+ // Reference the device object.
+ //
+ ObReferenceObject(pAcdDeviceObject);
+ //
+ // Remove the reference IoGetDeviceObjectPointer()
+ // put on the file object.
+ //
+ ObDereferenceObject(pAcdFileObject);
+ //
+ // Initialize our part of the ACD_DRIVER
+ // structure.
+ //
+ KeInitializeSpinLock(&AcdDriverG.SpinLock);
+ AcdDriverG.ulDriverId = ulDriverIdG;
+ AcdDriverG.fEnabled = FALSE;
+ //
+ // Build a request to get the automatic
+ // connection driver entry points.
+ //
+ pIrp = IoBuildDeviceIoControlRequest(
+ IOCTL_INTERNAL_ACD_BIND,
+ pAcdDeviceObject,
+ (PVOID)&pDriver,
+ sizeof (pDriver),
+ NULL,
+ 0,
+ TRUE,
+ NULL,
+ &ioStatusBlock);
+ if (pIrp == NULL) {
+ ObDereferenceObject(pAcdDeviceObject);
+ return;
+ }
+ //
+ // Submit the request to the
+ // automatic connection driver.
+ //
+ status = IoCallDriver(pAcdDeviceObject, pIrp);
+ fAcdLoadedG = (status == STATUS_SUCCESS);
+ //
+ // Close the device.
+ //
+ ObDereferenceObject(pAcdDeviceObject);
+} // TCPAcdBind
+
+
+
+VOID
+TCPAcdUnbind()
+{
+ NTSTATUS status;
+ UNICODE_STRING nameString;
+ IO_STATUS_BLOCK ioStatusBlock;
+ PIRP pIrp;
+ PFILE_OBJECT pAcdFileObject;
+ PDEVICE_OBJECT pAcdDeviceObject;
+ PACD_DRIVER pDriver = &AcdDriverG;
+
+ //
+ // Don't bother to unbind if we
+ // didn't successfully bind in the
+ // first place.
+ //
+ if (!fAcdLoadedG)
+ return;
+ //
+ // Initialize the name of the automatic
+ // connection device.
+ //
+ RtlInitUnicodeString(&nameString, ACD_DEVICE_NAME);
+ //
+ // Get the file and device objects for the
+ // device.
+ //
+ status = IoGetDeviceObjectPointer(
+ &nameString,
+ SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
+ &pAcdFileObject,
+ &pAcdDeviceObject);
+ if (status != STATUS_SUCCESS)
+ return;
+ //
+ // Reference the device object.
+ //
+ ObReferenceObject(pAcdDeviceObject);
+ //
+ // Remove the reference IoGetDeviceObjectPointer()
+ // put on the file object.
+ //
+ ObDereferenceObject(pAcdFileObject);
+ //
+ // Build a request to unbind from
+ // the automatic connection driver.
+ //
+ pIrp = IoBuildDeviceIoControlRequest(
+ IOCTL_INTERNAL_ACD_UNBIND,
+ pAcdDeviceObject,
+ (PVOID)&pDriver,
+ sizeof (pDriver),
+ NULL,
+ 0,
+ TRUE,
+ NULL,
+ &ioStatusBlock);
+ if (pIrp == NULL) {
+ ObDereferenceObject(pAcdDeviceObject);
+ return;
+ }
+ //
+ // Submit the request to the
+ // automatic connection driver.
+ //
+ status = IoCallDriver(pAcdDeviceObject, pIrp);
+ //
+ // Close the device.
+ //
+ ObDereferenceObject(pAcdDeviceObject);
+} // TCPAcdUnbind
+
+
diff --git a/private/ntos/tdi/tcpip/tcp/ntdisp.c b/private/ntos/tdi/tcpip/tcp/ntdisp.c
new file mode 100644
index 000000000..15c6f10cc
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/ntdisp.c
@@ -0,0 +1,4063 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ntdisp.c
+
+Abstract:
+
+ NT specific routines for dispatching and handling IRPs.
+
+Author:
+
+ Mike Massa (mikemas) Aug 13, 1993
+
+Revision History:
+
+ Who When What
+ -------- -------- ----------------------------------------------
+ mikemas 08-13-93 created
+
+Notes:
+
+--*/
+
+#include <oscfg.h>
+#include <ntrtl.h>
+#include <ntddip.h>
+#include <ndis.h>
+#include <cxport.h>
+#include <tdikrnl.h>
+#include <tdint.h>
+#include <tdistat.h>
+#include <tdiinfo.h>
+#include <ip.h>
+#include "queue.h"
+#include "addr.h"
+#include "tcp.h"
+#include "udp.h"
+#include "raw.h"
+#include <tcpinfo.h>
+#include <ntddtcp.h>
+#include "tcpcfg.h"
+#include "secfltr.h"
+#include "tcpconn.h"
+
+//
+// Macros
+//
+//++
+//
+// LARGE_INTEGER
+// CTEConvert100nsToMilliseconds(
+// IN LARGE_INTEGER HnsTime
+// );
+//
+// Routine Description:
+//
+// Converts time expressed in hundreds of nanoseconds to milliseconds.
+//
+// Arguments:
+//
+// HnsTime - Time in hundreds of nanoseconds.
+//
+// Return Value:
+//
+// Time in milliseconds.
+//
+//--
+
+#define SHIFT10000 13
+static LARGE_INTEGER Magic10000 = {0xe219652c, 0xd1b71758};
+
+#define CTEConvert100nsToMilliseconds(HnsTime) \
+ RtlExtendedMagicDivide((HnsTime), Magic10000, SHIFT10000)
+
+
+//
+// Global variables
+//
+extern PDEVICE_OBJECT TCPDeviceObject, UDPDeviceObject;
+extern PDEVICE_OBJECT IPDeviceObject;
+extern PDEVICE_OBJECT RawIPDeviceObject;
+
+
+//
+// Local types
+//
+typedef struct {
+ PIRP Irp;
+ PMDL InputMdl;
+ PMDL OutputMdl;
+ TCP_REQUEST_QUERY_INFORMATION_EX QueryInformation;
+} TCP_QUERY_CONTEXT, *PTCP_QUERY_CONTEXT;
+
+
+
+//
+// General external function prototypes
+//
+extern
+NTSTATUS
+IPDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+//
+// External TDI function prototypes
+//
+extern TDI_STATUS
+TdiOpenAddress(
+ PTDI_REQUEST Request,
+ TRANSPORT_ADDRESS UNALIGNED *AddrList,
+ uint protocol,
+ void *Reuse
+ );
+
+extern TDI_STATUS
+TdiCloseAddress(
+ PTDI_REQUEST Request
+ );
+
+extern TDI_STATUS
+TdiOpenConnection(
+ PTDI_REQUEST Request,
+ PVOID Context
+ );
+
+extern TDI_STATUS
+TdiCloseConnection(
+ PTDI_REQUEST Request
+ );
+
+extern TDI_STATUS
+TdiAssociateAddress(
+ PTDI_REQUEST Request,
+ HANDLE AddrHandle
+ );
+
+extern TDI_STATUS
+TdiCancelDisAssociateAddress(
+ PTDI_REQUEST Request
+ );
+
+extern TDI_STATUS
+TdiDisAssociateAddress(
+ PTDI_REQUEST Request
+ );
+
+extern TDI_STATUS
+TdiConnect(
+ PTDI_REQUEST Request,
+ void *Timeout,
+ PTDI_CONNECTION_INFORMATION RequestAddr,
+ PTDI_CONNECTION_INFORMATION ReturnAddr
+ );
+
+extern TDI_STATUS
+TdiListen(
+ PTDI_REQUEST Request,
+ ushort Flags,
+ PTDI_CONNECTION_INFORMATION AcceptableAddr,
+ PTDI_CONNECTION_INFORMATION ConnectedAddr
+ );
+
+extern TDI_STATUS
+TdiAccept(
+ PTDI_REQUEST Request,
+ PTDI_CONNECTION_INFORMATION AcceptInfo,
+ PTDI_CONNECTION_INFORMATION ConnectedInfo
+ );
+
+extern TDI_STATUS
+TdiDisconnect(
+ PTDI_REQUEST Request,
+ void *TO,
+ ushort Flags,
+ PTDI_CONNECTION_INFORMATION DiscConnInfo,
+ PTDI_CONNECTION_INFORMATION ReturnInfo
+ );
+
+extern TDI_STATUS
+TdiSend(
+ PTDI_REQUEST Request,
+ ushort Flags,
+ uint SendLength,
+ PNDIS_BUFFER SendBuffer
+ );
+
+extern TDI_STATUS
+TdiReceive(
+ PTDI_REQUEST Request,
+ ushort *Flags,
+ uint *RcvLength,
+ PNDIS_BUFFER Buffer
+ );
+
+extern TDI_STATUS
+TdiSendDatagram(
+ PTDI_REQUEST Request,
+ PTDI_CONNECTION_INFORMATION ConnInfo,
+ uint DataSize,
+ uint *BytesSent,
+ PNDIS_BUFFER Buffer
+ );
+
+VOID
+TdiCancelSendDatagram(
+ AddrObj *SrcAO,
+ PVOID Context
+ );
+
+extern TDI_STATUS
+TdiReceiveDatagram(
+ PTDI_REQUEST Request,
+ PTDI_CONNECTION_INFORMATION ConnInfo,
+ PTDI_CONNECTION_INFORMATION ReturnInfo,
+ uint RcvSize,
+ uint *BytesRcvd,
+ PNDIS_BUFFER Buffer
+ );
+
+VOID
+TdiCancelReceiveDatagram(
+ AddrObj *SrcAO,
+ PVOID Context
+ );
+
+extern TDI_STATUS
+TdiSetEvent(
+ PVOID Handle,
+ int Type,
+ PVOID Handler,
+ PVOID Context
+ );
+
+extern TDI_STATUS
+TdiQueryInformation(
+ PTDI_REQUEST Request,
+ uint QueryType,
+ PNDIS_BUFFER Buffer,
+ uint *BytesReturned,
+ uint IsConn
+ );
+
+extern TDI_STATUS
+TdiSetInformation(
+ PTDI_REQUEST Request,
+ uint SetType,
+ PNDIS_BUFFER Buffer,
+ uint BufferSize,
+ uint IsConn
+ );
+
+extern TDI_STATUS
+TdiQueryInformationEx(
+ PTDI_REQUEST Request,
+ struct TDIObjectID *ID,
+ PNDIS_BUFFER Buffer,
+ uint *Size,
+ void *Context
+ );
+
+extern TDI_STATUS
+TdiSetInformationEx(
+ PTDI_REQUEST Request,
+ struct TDIObjectID *ID,
+ void *Buffer,
+ uint Size
+ );
+
+extern TDI_STATUS
+TdiAction(
+ PTDI_REQUEST Request,
+ uint ActionType,
+ PNDIS_BUFFER Buffer,
+ uint BufferSize
+ );
+
+//
+// Other external functions
+//
+void
+TCPAbortAndIndicateDisconnect(
+ uint ConnnectionContext
+ );
+
+
+//
+// Local pageable function prototypes
+//
+NTSTATUS
+TCPDispatchDeviceControl(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+TCPCreate(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+TCPAssociateAddress(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+TCPSetEventHandler(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+TCPQueryInformation(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+FILE_FULL_EA_INFORMATION UNALIGNED *
+FindEA(
+ PFILE_FULL_EA_INFORMATION StartEA,
+ CHAR *TargetName,
+ USHORT TargetNameLength
+ );
+
+BOOLEAN
+IsDHCPZeroAddress(
+ TRANSPORT_ADDRESS UNALIGNED *AddrList
+ );
+
+ULONG
+RawExtractProtocolNumber(
+ IN PUNICODE_STRING FileName
+ );
+
+#ifdef SECFLTR
+
+NTSTATUS
+TCPControlSecurityFilter(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+TCPProcessSecurityFilterRequest(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+TCPEnumerateSecurityFilter(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+#endif // SECFLTR
+
+NTSTATUS
+TCPEnumerateConnectionList(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+//
+// Local helper routine prototypes.
+//
+ULONG
+TCPGetMdlChainByteCount(
+ PMDL Mdl
+ );
+
+
+//
+// All of this code is pageable.
+//
+#ifdef ALLOC_PRAGMA
+
+#pragma alloc_text(PAGE, TCPDispatchDeviceControl)
+#pragma alloc_text(PAGE, TCPCreate)
+#pragma alloc_text(PAGE, TCPAssociateAddress)
+#pragma alloc_text(PAGE, TCPSetEventHandler)
+#pragma alloc_text(PAGE, FindEA)
+#pragma alloc_text(PAGE, IsDHCPZeroAddress)
+#pragma alloc_text(PAGE, RawExtractProtocolNumber)
+
+#ifdef SECFLTR
+
+#pragma alloc_text(PAGE, TCPControlSecurityFilter)
+#pragma alloc_text(PAGE, TCPProcessSecurityFilterRequest)
+#pragma alloc_text(PAGE, TCPEnumerateSecurityFilter)
+
+#endif // SECFLTR
+
+#pragma alloc_text(PAGE, TCPEnumerateSecurityFilter)
+
+#endif // ALLOC_PRAGMA
+
+
+
+//
+// Generic Irp completion and cancellation routines.
+//
+
+void
+TCPDataRequestComplete(
+ void *Context,
+ unsigned int Status,
+ unsigned int ByteCount
+ )
+
+/*++
+
+Routine Description:
+
+ Completes a UDP/TCP send/receive request.
+
+Arguments:
+
+ Context - A pointer to the IRP for this request.
+ Status - The final TDI status of the request.
+ ByteCount - Bytes sent/received information.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ KIRQL oldIrql;
+ PIRP irp;
+ PIO_STACK_LOCATION irpSp;
+ PTCP_CONTEXT tcpContext;
+ PIRP item = NULL;
+
+
+ irp = (PIRP) Context;
+ irpSp = IoGetCurrentIrpStackLocation(irp);
+ tcpContext = (PTCP_CONTEXT) irpSp->FileObject->FsContext;
+
+ IoAcquireCancelSpinLock(&oldIrql);
+
+#if DBG
+
+ IF_TCPDBG(TCP_DEBUG_CANCEL) {
+
+ PLIST_ENTRY entry, listHead;
+ PIRP item = NULL;
+
+ if (irp->Cancel) {
+ CTEAssert(irp->CancelRoutine == NULL);
+ listHead = &(tcpContext->CancelledIrpList);
+ }
+ else {
+ listHead = &(tcpContext->PendingIrpList);
+ }
+
+ //
+ // Verify that the Irp is on the appropriate list
+ //
+ for ( entry = listHead->Flink;
+ entry != listHead;
+ entry = entry->Flink
+ ) {
+
+ item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
+
+ if (item == irp) {
+ RemoveEntryList(&(irp->Tail.Overlay.ListEntry));
+ break;
+ }
+ }
+
+ CTEAssert(item == irp);
+ }
+
+#endif
+
+ IoSetCancelRoutine(irp, NULL);
+
+ CTEAssert(tcpContext->ReferenceCount > 0);
+
+ if (--(tcpContext->ReferenceCount) == 0) {
+
+ IF_TCPDBG(TCP_DEBUG_CANCEL) {
+ CTEAssert(IsListEmpty(&(tcpContext->CancelledIrpList)));
+ CTEAssert(IsListEmpty(&(tcpContext->PendingIrpList)));
+ }
+
+ //
+ // Set the cleanup event.
+ //
+ KeSetEvent(&(tcpContext->CleanupEvent), 0, FALSE);
+ }
+
+ IF_TCPDBG(TCP_DEBUG_IRP) {
+ TCPTRACE((
+ "TCPDataRequestComplete: Irp %lx fileobj %lx refcnt dec to %u\n",
+ irp,
+ irpSp->FileObject,
+ tcpContext->ReferenceCount
+ ));
+ }
+
+ if (irp->Cancel || tcpContext->CancelIrps) {
+
+ IF_TCPDBG(TCP_DEBUG_IRP) {
+ TCPTRACE(("TCPDataRequestComplete: Irp %lx was cancelled\n", irp));
+ }
+
+ Status = (unsigned int) STATUS_CANCELLED;
+ ByteCount = 0;
+ }
+
+ IoReleaseCancelSpinLock(oldIrql);
+
+ IF_TCPDBG(TCP_DEBUG_IRP) {
+ TCPTRACE((
+ "TCPDataRequestComplete: completing irp %lx, status %lx, byte count %lx\n",
+ irp,
+ Status,
+ ByteCount
+ ));
+ }
+
+ irp->IoStatus.Status = (NTSTATUS) Status;
+ irp->IoStatus.Information = ByteCount;
+
+ IoCompleteRequest(irp, IO_NETWORK_INCREMENT);
+
+ return;
+
+} // TCPDataRequestComplete
+
+
+void
+TCPRequestComplete(
+ void *Context,
+ unsigned int Status,
+ unsigned int UnUsed
+ )
+
+/*++
+
+Routine Description:
+
+ Completes a cancellable TDI request which returns no data by
+ calling TCPDataRequestComplete with a ByteCount of zero.
+
+Arguments:
+
+ Context - A pointer to the IRP for this request.
+ Status - The final TDI status of the request.
+ UnUsed - An unused parameter
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(UnUsed);
+
+ TCPDataRequestComplete(Context, Status, 0);
+
+} // TCPRequestComplete
+
+
+
+void
+TCPNonCancellableRequestComplete(
+ void *Context,
+ unsigned int Status,
+ unsigned int UnUsed
+ )
+
+/*++
+
+Routine Description:
+
+ Completes a TDI request which cannot be cancelled.
+
+Arguments:
+
+ Context - A pointer to the IRP for this request.
+ Status - The final TDI status of the request.
+ UnUsed - An unused parameter
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ PIRP irp;
+ PIO_STACK_LOCATION irpSp;
+
+
+ UNREFERENCED_PARAMETER(UnUsed);
+
+ irp = (PIRP) Context;
+ irpSp = IoGetCurrentIrpStackLocation(irp);
+
+ IF_TCPDBG(TCP_DEBUG_CLOSE) {
+ TCPTRACE((
+ "TCPNonCancellableRequestComplete: irp %lx status %lx\n",
+ irp,
+ Status
+ ));
+ }
+
+ //
+ // Complete the IRP
+ //
+ irp->IoStatus.Status = (NTSTATUS) Status;
+ irp->IoStatus.Information = 0;
+ IoCompleteRequest(irp, IO_NETWORK_INCREMENT);
+
+ return;
+
+} // TCPNonCancellableRequestComplete
+
+
+
+void
+TCPCancelComplete(
+ void *Context,
+ unsigned int Unused1,
+ unsigned int Unused2
+ )
+{
+ PFILE_OBJECT fileObject = (PFILE_OBJECT) Context;
+ PTCP_CONTEXT tcpContext = (PTCP_CONTEXT) fileObject->FsContext;
+ KIRQL oldIrql;
+
+
+ UNREFERENCED_PARAMETER(Unused1);
+ UNREFERENCED_PARAMETER(Unused2);
+
+ IoAcquireCancelSpinLock(&oldIrql);
+
+ //
+ // Remove the reference placed on the endpoint by the cancel routine.
+ // The cancelled Irp will be completed by the completion routine for the
+ // request.
+ //
+ if (--(tcpContext->ReferenceCount) == 0) {
+
+ IF_TCPDBG(TCP_DEBUG_CANCEL) {
+ CTEAssert(IsListEmpty(&(tcpContext->CancelledIrpList)));
+ CTEAssert(IsListEmpty(&(tcpContext->PendingIrpList)));
+ }
+
+ //
+ // Set the cleanup event.
+ //
+ KeSetEvent(&(tcpContext->CleanupEvent), 0, FALSE);
+ }
+
+ IF_TCPDBG(TCP_DEBUG_IRP) {
+ TCPTRACE((
+ "TCPCancelComplete: fileobj %lx refcnt dec to %u\n",
+ fileObject,
+ tcpContext->ReferenceCount
+ ));
+ }
+
+ IoReleaseCancelSpinLock(oldIrql);
+
+ return;
+
+} // TCPCancelComplete
+
+
+VOID
+TCPCancelRequest(
+ PDEVICE_OBJECT Device,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ Cancels an outstanding Irp.
+
+Arguments:
+
+ Device - Pointer to the device object for this request.
+ Irp - Pointer to I/O request packet
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_STACK_LOCATION irpSp;
+ PTCP_CONTEXT tcpContext;
+ NTSTATUS status = STATUS_SUCCESS;
+ PFILE_OBJECT fileObject;
+ UCHAR minorFunction;
+ TDI_REQUEST request;
+
+
+ irpSp = IoGetCurrentIrpStackLocation(Irp);
+ fileObject = irpSp->FileObject;
+ tcpContext = (PTCP_CONTEXT) fileObject->FsContext;
+ minorFunction = irpSp->MinorFunction;
+
+ CTEAssert(Irp->Cancel);
+ IoSetCancelRoutine(Irp, NULL);
+
+ IF_TCPDBG(TCP_DEBUG_IRP) {
+ TCPTRACE((
+ "TCPCancelRequest: cancelling irp %lx, file object %lx\n",
+ Irp,
+ fileObject
+ ));
+ }
+
+#if DBG
+
+ IF_TCPDBG(TCP_DEBUG_CANCEL) {
+ //
+ // Verify that the Irp is on the pending list
+ //
+ PLIST_ENTRY entry;
+ PIRP item = NULL;
+
+
+ for ( entry = tcpContext->PendingIrpList.Flink;
+ entry != &(tcpContext->PendingIrpList);
+ entry = entry->Flink
+ ) {
+
+ item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
+
+ if (item == Irp) {
+ RemoveEntryList( &(Irp->Tail.Overlay.ListEntry));
+ break;
+ }
+ }
+
+ CTEAssert(item == Irp);
+
+ InsertTailList(
+ &(tcpContext->CancelledIrpList),
+ &(Irp->Tail.Overlay.ListEntry)
+ );
+ }
+
+#endif // DBG
+
+ //
+ // Add a reference so the object can't be closed while the cancel routine
+ // is executing.
+ //
+ CTEAssert(tcpContext->ReferenceCount > 0);
+ tcpContext->ReferenceCount++;
+
+ IF_TCPDBG(TCP_DEBUG_IRP) {
+ TCPTRACE((
+ "TCPCancelRequest: Irp %lx fileobj %lx refcnt inc to %u\n",
+ Irp,
+ fileObject,
+ tcpContext->ReferenceCount
+ ));
+ }
+
+ IoReleaseCancelSpinLock(Irp->CancelIrql);
+
+ //
+ // Try to cancel the request.
+ //
+ switch(minorFunction) {
+
+ case TDI_SEND:
+ case TDI_RECEIVE:
+
+ CTEAssert(((int)fileObject->FsContext2) == TDI_CONNECTION_FILE);
+
+ TCPAbortAndIndicateDisconnect(
+ (uint) tcpContext->Handle.ConnectionContext
+ );
+ break;
+
+ case TDI_SEND_DATAGRAM:
+
+ CTEAssert(((int)fileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE);
+
+ TdiCancelSendDatagram(tcpContext->Handle.AddressHandle, Irp);
+ break;
+
+ case TDI_RECEIVE_DATAGRAM:
+
+ CTEAssert(((int)fileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE);
+
+ TdiCancelReceiveDatagram(tcpContext->Handle.AddressHandle, Irp);
+ break;
+
+ case TDI_DISASSOCIATE_ADDRESS:
+
+ CTEAssert(((int)fileObject->FsContext2) == TDI_CONNECTION_FILE);
+ //
+ // This pends but is not cancellable. We put it thru the cancel code
+ // anyway so a reference is made for it and so it can be tracked in
+ // a debug build.
+ //
+ break;
+
+ default:
+
+ //
+ // Initiate a disconnect to cancel the request.
+ //
+ request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
+ request.RequestNotifyObject = TCPCancelComplete;
+ request.RequestContext = fileObject;
+
+ status = TdiDisconnect(
+ &request,
+ NULL,
+ TDI_DISCONNECT_ABORT,
+ NULL,
+ NULL
+ );
+ break;
+ }
+
+ if (status != TDI_PENDING) {
+ TCPCancelComplete(fileObject, 0, 0);
+ }
+
+ return;
+
+} // TCPCancelRequest
+
+
+
+NTSTATUS
+TCPPrepareIrpForCancel(
+ PTCP_CONTEXT TcpContext,
+ PIRP Irp,
+ PDRIVER_CANCEL CancelRoutine
+ )
+{
+ KIRQL oldIrql;
+
+ //
+ // Set up for cancellation
+ //
+ IoAcquireCancelSpinLock(&oldIrql);
+
+ CTEAssert(Irp->CancelRoutine == NULL);
+
+ if (!Irp->Cancel) {
+
+ IoMarkIrpPending(Irp);
+ IoSetCancelRoutine(Irp, CancelRoutine);
+ TcpContext->ReferenceCount++;
+
+ IF_TCPDBG(TCP_DEBUG_IRP) {
+ TCPTRACE((
+ "TCPPrepareIrpForCancel: irp %lx fileobj %lx refcnt inc to %u\n",
+ Irp,
+ (IoGetCurrentIrpStackLocation(Irp))->FileObject,
+ TcpContext->ReferenceCount
+ ));
+ }
+
+#if DBG
+ IF_TCPDBG(TCP_DEBUG_CANCEL) {
+ PLIST_ENTRY entry;
+ PIRP item = NULL;
+
+ //
+ // Verify that the Irp has not already been submitted.
+ //
+ for ( entry = TcpContext->PendingIrpList.Flink;
+ entry != &(TcpContext->PendingIrpList);
+ entry = entry->Flink
+ ) {
+
+ item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
+
+ CTEAssert(item != Irp);
+ }
+
+ for ( entry = TcpContext->CancelledIrpList.Flink;
+ entry != &(TcpContext->CancelledIrpList);
+ entry = entry->Flink
+ ) {
+
+ item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
+
+ CTEAssert(item != Irp);
+ }
+
+ InsertTailList(
+ &(TcpContext->PendingIrpList),
+ &(Irp->Tail.Overlay.ListEntry)
+ );
+ }
+#endif // DBG
+
+ IoReleaseCancelSpinLock(oldIrql);
+
+ return(STATUS_SUCCESS);
+ }
+
+ //
+ // The IRP has already been cancelled. Complete it now.
+ //
+
+ IF_TCPDBG(TCP_DEBUG_IRP) {
+ TCPTRACE(("TCP: irp %lx already cancelled, completing.\n", Irp));
+ }
+
+ IoReleaseCancelSpinLock(oldIrql);
+
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ Irp->IoStatus.Information = 0;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ return(STATUS_CANCELLED);
+
+} // TCPPrepareIrpForCancel
+
+
+
+//
+// TDI functions
+//
+NTSTATUS
+TCPAssociateAddress(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ Converts a TDI Associate Address IRP into a call to TdiAssociateAddress.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successful.
+
+Notes:
+
+ This routine does not pend.
+
+--*/
+
+{
+ NTSTATUS status;
+ TDI_REQUEST request;
+ PTCP_CONTEXT tcpContext;
+ PTDI_REQUEST_KERNEL_ASSOCIATE associateInformation;
+ PFILE_OBJECT fileObject;
+
+
+ PAGED_CODE();
+
+ tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
+ request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
+ associateInformation = (PTDI_REQUEST_KERNEL_ASSOCIATE) &(IrpSp->Parameters);
+
+ //
+ // Get the file object for the address. Then extract the Address Handle
+ // from the TCP_CONTEXT associated with it.
+ //
+ status = ObReferenceObjectByHandle(
+ associateInformation->AddressHandle,
+ 0,
+ NULL,
+ KernelMode,
+ &fileObject,
+ NULL
+ );
+
+ if (NT_SUCCESS(status)) {
+
+ if ( (fileObject->DeviceObject == TCPDeviceObject) &&
+ (((int)fileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE)
+ ) {
+
+ tcpContext = (PTCP_CONTEXT) fileObject->FsContext;
+
+ status = TdiAssociateAddress(
+ &request,
+ tcpContext->Handle.AddressHandle
+ );
+
+ CTEAssert(status != STATUS_PENDING);
+
+ ObDereferenceObject(fileObject);
+
+ IF_TCPDBG(TCP_DEBUG_ASSOCIATE) {
+ TCPTRACE((
+ "TCPAssociateAddress complete on file object %lx\n",
+ IrpSp->FileObject
+ ));
+ }
+ }
+ else {
+ ObDereferenceObject(fileObject);
+ status = STATUS_INVALID_HANDLE;
+
+ IF_TCPDBG(TCP_DEBUG_ASSOCIATE) {
+ TCPTRACE((
+ "TCPAssociateAddress: ObReference failed on object %lx, status %lx\n",
+ associateInformation->AddressHandle,
+ status
+ ));
+ }
+ }
+ }
+ else {
+ IF_TCPDBG(TCP_DEBUG_ASSOCIATE) {
+ TCPTRACE((
+ "TCPAssociateAddress: ObReference failed on object %lx, status %lx\n",
+ associateInformation->AddressHandle,
+ status
+ ));
+ }
+ }
+
+ return(status);
+}
+
+
+NTSTATUS
+TCPDisassociateAddress(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ Converts a TDI Associate Address IRP into a call to TdiAssociateAddress.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successful.
+
+--*/
+
+{
+ NTSTATUS status;
+ TDI_REQUEST request;
+ PTCP_CONTEXT tcpContext;
+
+ IF_TCPDBG(TCP_DEBUG_ASSOCIATE) {
+ TCPTRACE(("TCP disassociating address\n"));
+ }
+
+ CTEAssert( ((int)IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE );
+ tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
+ request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
+ request.RequestNotifyObject = TCPRequestComplete;
+ request.RequestContext = Irp;
+
+ status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
+
+ if (NT_SUCCESS(status)) {
+
+ status = TdiDisAssociateAddress(&request);
+
+ if (status != TDI_PENDING) {
+ TCPRequestComplete(Irp, status, 0);
+ }
+ //
+ // return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
+ //
+ return(TDI_PENDING);
+ }
+
+ return(status);
+
+} // TCPDisassociateAddress
+
+
+
+NTSTATUS
+TCPConnect(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ Converts a TDI Connect IRP into a call to TdiConnect.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTCP_CONTEXT tcpContext;
+ TDI_REQUEST request;
+ PTDI_CONNECTION_INFORMATION requestInformation, returnInformation;
+ PTDI_REQUEST_KERNEL_CONNECT connectRequest;
+ LARGE_INTEGER millisecondTimeout;
+ PLARGE_INTEGER requestTimeout;
+
+
+ IF_TCPDBG(TCP_DEBUG_CONNECT) {
+ TCPTRACE((
+ "TCPConnect irp %lx, file object %lx\n",
+ Irp,
+ IrpSp->FileObject
+ ));
+ }
+
+ CTEAssert( ((int)IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
+
+ connectRequest = (PTDI_REQUEST_KERNEL_CONNECT) &(IrpSp->Parameters);
+ requestInformation = connectRequest->RequestConnectionInformation;
+ returnInformation = connectRequest->ReturnConnectionInformation;
+ tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
+ request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
+ request.RequestNotifyObject = TCPRequestComplete;
+ request.RequestContext = Irp;
+
+ requestTimeout = (PLARGE_INTEGER) connectRequest->RequestSpecific;
+
+ if (requestTimeout != NULL) {
+ //
+ // NT relative timeouts are negative. Negate first to get a positive
+ // value to pass to the transport.
+ //
+ millisecondTimeout.QuadPart = -((*requestTimeout).QuadPart);
+ millisecondTimeout = CTEConvert100nsToMilliseconds(
+ millisecondTimeout
+ );
+ }
+ else {
+ millisecondTimeout.LowPart = 0;
+ millisecondTimeout.HighPart = 0;
+ }
+
+
+ CTEAssert(millisecondTimeout.HighPart == 0);
+
+ status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
+
+ if (NT_SUCCESS(status)) {
+
+ status = TdiConnect(
+ &request,
+ ((millisecondTimeout.LowPart != 0) ?
+ &(millisecondTimeout.LowPart) : NULL),
+ requestInformation,
+ returnInformation
+ );
+
+ if (status != STATUS_PENDING) {
+ TCPRequestComplete(Irp, status, 0);
+ }
+ //
+ // return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
+ //
+ return(STATUS_PENDING);
+ }
+
+ return(status);
+
+} // TCPConnect
+
+
+NTSTATUS
+TCPDisconnect(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ Converts a TDI Disconnect IRP into a call to TdiDisconnect.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+Notes:
+
+ Abortive disconnects may pend, but cannot be cancelled.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTCP_CONTEXT tcpContext;
+ TDI_REQUEST request;
+ PTDI_CONNECTION_INFORMATION requestInformation, returnInformation;
+ PTDI_REQUEST_KERNEL_DISCONNECT disconnectRequest;
+ LARGE_INTEGER millisecondTimeout;
+ PLARGE_INTEGER requestTimeout;
+ BOOLEAN abortive = FALSE;
+
+
+ CTEAssert( ((int)IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
+
+ disconnectRequest = (PTDI_REQUEST_KERNEL_CONNECT) &(IrpSp->Parameters);
+ requestInformation = disconnectRequest->RequestConnectionInformation;
+ returnInformation = disconnectRequest->ReturnConnectionInformation;
+ tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
+ request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
+ request.RequestContext = Irp;
+
+ //
+ // Set up the timeout value.
+ //
+ if (disconnectRequest->RequestSpecific != NULL) {
+ requestTimeout = (PLARGE_INTEGER) disconnectRequest->RequestSpecific;
+
+ if ((requestTimeout->LowPart == -1) && (requestTimeout->HighPart == -1)) {
+ millisecondTimeout.LowPart = requestTimeout->LowPart;
+ millisecondTimeout.HighPart = 0;
+ }
+ else {
+ //
+ // NT relative timeouts are negative. Negate first to get a
+ // positive value to pass to the transport.
+ //
+ millisecondTimeout.QuadPart = -((*requestTimeout).QuadPart);
+ millisecondTimeout = CTEConvert100nsToMilliseconds(
+ millisecondTimeout
+ );
+ }
+ }
+ else {
+ millisecondTimeout.LowPart = 0;
+ millisecondTimeout.HighPart = 0;
+ }
+
+ CTEAssert(millisecondTimeout.HighPart == 0);
+
+ if (disconnectRequest->RequestFlags & TDI_DISCONNECT_ABORT) {
+ //
+ // Abortive disconnects cannot be cancelled and must use
+ // a specific completion routine.
+ //
+ abortive = TRUE;
+ IoMarkIrpPending(Irp);
+ request.RequestNotifyObject = TCPNonCancellableRequestComplete;
+ status = STATUS_SUCCESS;
+ }
+ else {
+ //
+ // Non-abortive disconnects can use the generic cancellation and
+ // completion routines.
+ //
+ status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
+ request.RequestNotifyObject = TCPRequestComplete;
+ }
+
+ IF_TCPDBG(TCP_DEBUG_CLOSE) {
+ TCPTRACE((
+ "TCPDisconnect irp %lx, flags %lx, fileobj %lx, abortive = %d\n",
+ Irp,
+ disconnectRequest->RequestFlags,
+ IrpSp->FileObject,
+ abortive
+ ));
+ }
+
+ if (NT_SUCCESS(status)) {
+ status = TdiDisconnect(
+ &request,
+ ((millisecondTimeout.LowPart != 0) ?
+ &(millisecondTimeout.LowPart) : NULL),
+ (ushort) disconnectRequest->RequestFlags,
+ requestInformation,
+ returnInformation
+ );
+
+ if (status != STATUS_PENDING) {
+ if (abortive) {
+ TCPNonCancellableRequestComplete(Irp, status, 0);
+ }
+ else {
+ TCPRequestComplete(Irp, status, 0);
+ }
+ }
+ else {
+ IF_TCPDBG(TCP_DEBUG_CLOSE) {
+ TCPTRACE(("TCPDisconnect pending irp %lx\n", Irp));
+ }
+ }
+ //
+ // return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
+ //
+ return(STATUS_PENDING);
+ }
+
+ return(status);
+
+} // TCPDisconnect
+
+
+NTSTATUS
+TCPListen(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ Converts a TDI Listen IRP into a call to TdiListen.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successful.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTCP_CONTEXT tcpContext;
+ TDI_REQUEST request;
+ PTDI_CONNECTION_INFORMATION requestInformation, returnInformation;
+ PTDI_REQUEST_KERNEL_LISTEN listenRequest;
+
+
+ IF_TCPDBG(TCP_DEBUG_CONNECT) {
+ TCPTRACE((
+ "TCPListen irp %lx on file object %lx\n",
+ Irp,
+ IrpSp->FileObject
+ ));
+ }
+
+ CTEAssert( ((int)IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
+
+ listenRequest = (PTDI_REQUEST_KERNEL_CONNECT) &(IrpSp->Parameters);
+ requestInformation = listenRequest->RequestConnectionInformation;
+ returnInformation = listenRequest->ReturnConnectionInformation;
+ tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
+ request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
+ request.RequestNotifyObject = TCPRequestComplete;
+ request.RequestContext = Irp;
+
+ status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
+
+ if (NT_SUCCESS(status)) {
+
+ status = TdiListen(
+ &request,
+ (ushort) listenRequest->RequestFlags,
+ requestInformation,
+ returnInformation
+ );
+
+ if (status != TDI_PENDING) {
+ TCPRequestComplete(Irp, status, 0);
+ }
+ //
+ // return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
+ //
+ return(TDI_PENDING);
+ }
+
+ return(status);
+
+} // TCPListen
+
+
+NTSTATUS
+TCPAccept(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ Converts a TDI Accept IRP into a call to TdiAccept.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTCP_CONTEXT tcpContext;
+ TDI_REQUEST request;
+ PTDI_CONNECTION_INFORMATION requestInformation, returnInformation;
+ PTDI_REQUEST_KERNEL_ACCEPT acceptRequest;
+
+
+ IF_TCPDBG(TCP_DEBUG_CONNECT) {
+ TCPTRACE((
+ "TCPAccept irp %lx on file object %lx\n", Irp,
+ IrpSp->FileObject
+ ));
+ }
+
+ CTEAssert( ((int)IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
+
+ acceptRequest = (PTDI_REQUEST_KERNEL_ACCEPT) &(IrpSp->Parameters);
+ requestInformation = acceptRequest->RequestConnectionInformation;
+ returnInformation = acceptRequest->ReturnConnectionInformation;
+ tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
+ request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
+ request.RequestNotifyObject = TCPRequestComplete;
+ request.RequestContext = Irp;
+
+ status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
+
+ if (NT_SUCCESS(status)) {
+
+ status = TdiAccept(
+ &request,
+ requestInformation,
+ returnInformation
+ );
+
+ if (status != TDI_PENDING) {
+ TCPRequestComplete(Irp, status, 0);
+ }
+ //
+ // return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
+ //
+ return(TDI_PENDING);
+ }
+
+ return(status);
+
+} // TCPAccept
+
+
+
+NTSTATUS
+TCPSendData(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ Converts a TDI Send IRP into a call to TdiSend.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successful.
+
+--*/
+
+{
+ TDI_STATUS status;
+ TDI_REQUEST request;
+ PTCP_CONTEXT tcpContext;
+ PTDI_REQUEST_KERNEL_SEND requestInformation;
+ KIRQL oldIrql;
+
+
+ tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
+ CTEAssert( ((int)IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE );
+ requestInformation = (PTDI_REQUEST_KERNEL_SEND) &(IrpSp->Parameters);
+
+ request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
+ request.RequestNotifyObject = TCPDataRequestComplete;
+ request.RequestContext = Irp;
+
+ IoAcquireCancelSpinLock(&oldIrql);
+
+ CTEAssert(Irp->CancelRoutine == NULL);
+
+ if (!Irp->Cancel) {
+ //
+ // Set up for cancellation
+ //
+
+ IoMarkIrpPending(Irp);
+ IoSetCancelRoutine(Irp, TCPCancelRequest);
+
+ tcpContext->ReferenceCount++;
+
+ IF_TCPDBG(TCP_DEBUG_IRP) {
+ TCPTRACE((
+ "TCPSendData: irp %lx fileobj %lx refcnt inc to %u\n",
+ Irp,
+ IrpSp,
+ tcpContext->ReferenceCount
+ ));
+ }
+
+#if DBG
+ IF_TCPDBG(TCP_DEBUG_CANCEL) {
+ PLIST_ENTRY entry;
+ PIRP item = NULL;
+
+ //
+ // Verify that the Irp has not already been submitted.
+ //
+ for ( entry = tcpContext->PendingIrpList.Flink;
+ entry != &(tcpContext->PendingIrpList);
+ entry = entry->Flink
+ ) {
+
+ item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
+
+ CTEAssert(item != Irp);
+ }
+
+ for ( entry = tcpContext->CancelledIrpList.Flink;
+ entry != &(tcpContext->CancelledIrpList);
+ entry = entry->Flink
+ ) {
+
+ item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
+
+ CTEAssert(item != Irp);
+ }
+
+ InsertTailList(
+ &(tcpContext->PendingIrpList),
+ &(Irp->Tail.Overlay.ListEntry)
+ );
+ }
+#endif // DBG
+
+ IoReleaseCancelSpinLock(oldIrql);
+
+ IF_TCPDBG(TCP_DEBUG_SEND) {
+ TCPTRACE((
+ "TCPSendData irp %lx sending %d bytes, flags %lx, fileobj %lx\n",
+ Irp,
+ requestInformation->SendLength,
+ requestInformation->SendFlags,
+ IrpSp->FileObject
+ ));
+ }
+
+ status = TdiSend(
+ &request,
+ (ushort) requestInformation->SendFlags,
+ requestInformation->SendLength,
+ (PNDIS_BUFFER) Irp->MdlAddress
+ );
+
+ if (status == TDI_PENDING) {
+ IF_TCPDBG(TCP_DEBUG_SEND) {
+ TCPTRACE(("TCPSendData pending irp %lx\n", Irp));
+ }
+
+ return(status);
+ }
+
+ //
+ // The status is not pending. We reset the pending bit
+ //
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+
+ if (status == TDI_SUCCESS) {
+ CTEAssert(requestInformation->SendLength == 0);
+
+ TCPDataRequestComplete(Irp, status, requestInformation->SendLength);
+ }
+ else {
+
+ IF_TCPDBG(TCP_DEBUG_SEND) {
+ TCPTRACE((
+ "TCPSendData - irp %lx send failed, status %lx\n",
+ Irp,
+ status
+ ));
+ }
+
+ TCPDataRequestComplete(Irp, status, 0);
+ }
+
+
+ }
+ else {
+ //
+ // Irp was cancelled previously.
+ //
+ IoReleaseCancelSpinLock(oldIrql);
+
+ IF_TCPDBG(TCP_DEBUG_SEND) {
+ TCPTRACE((
+ "TCPSendData: Irp %lx on fileobj %lx was cancelled\n",
+ Irp,
+ IrpSp->FileObject
+ ));
+ }
+
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ status = STATUS_CANCELLED;
+ }
+
+ return(status);
+
+} // TCPSendData
+
+
+
+NTSTATUS
+TCPReceiveData(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ Converts a TDI Receive IRP into a call to TdiReceive.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successful.
+
+--*/
+
+{
+ TDI_STATUS status;
+ TDI_REQUEST request;
+ PTCP_CONTEXT tcpContext;
+ PTDI_REQUEST_KERNEL_RECEIVE requestInformation;
+ KIRQL oldIrql;
+
+
+ tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
+ CTEAssert( ((int)IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE );
+ requestInformation = (PTDI_REQUEST_KERNEL_RECEIVE) &(IrpSp->Parameters);
+
+ request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
+ request.RequestNotifyObject = TCPDataRequestComplete;
+ request.RequestContext = Irp;
+
+ IoAcquireCancelSpinLock(&oldIrql);
+
+ CTEAssert(Irp->CancelRoutine == NULL);
+
+ if (!Irp->Cancel) {
+ //
+ // Set up for cancellation
+ //
+
+ IoMarkIrpPending(Irp);
+ IoSetCancelRoutine(Irp, TCPCancelRequest);
+
+ tcpContext->ReferenceCount++;
+
+ IF_TCPDBG(TCP_DEBUG_IRP) {
+ TCPTRACE((
+ "TCPReceiveData: irp %lx fileobj %lx refcnt inc to %u\n",
+ Irp,
+ IrpSp->FileObject,
+ tcpContext->ReferenceCount
+ ));
+ }
+
+#if DBG
+ IF_TCPDBG(TCP_DEBUG_CANCEL) {
+ PLIST_ENTRY entry;
+ PIRP item = NULL;
+
+ //
+ // Verify that the Irp has not already been submitted.
+ //
+ for ( entry = tcpContext->PendingIrpList.Flink;
+ entry != &(tcpContext->PendingIrpList);
+ entry = entry->Flink
+ ) {
+
+ item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
+
+ CTEAssert(item != Irp);
+ }
+
+ for ( entry = tcpContext->CancelledIrpList.Flink;
+ entry != &(tcpContext->CancelledIrpList);
+ entry = entry->Flink
+ ) {
+
+ item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
+
+ CTEAssert(item != Irp);
+ }
+
+ InsertTailList(
+ &(tcpContext->PendingIrpList),
+ &(Irp->Tail.Overlay.ListEntry)
+ );
+ }
+#endif // DBG
+
+ IoReleaseCancelSpinLock(oldIrql);
+
+ IF_TCPDBG(TCP_DEBUG_RECEIVE) {
+ TCPTRACE((
+ "TCPReceiveData irp %lx receiving %d bytes flags %lx filobj %lx\n",
+ Irp,
+ requestInformation->ReceiveLength,
+ requestInformation->ReceiveFlags,
+ IrpSp->FileObject
+ ));
+ }
+
+ status = TdiReceive(
+ &request,
+ (ushort *) &(requestInformation->ReceiveFlags),
+ &(requestInformation->ReceiveLength),
+ (PNDIS_BUFFER) Irp->MdlAddress
+ );
+
+ if (status == TDI_PENDING) {
+ IF_TCPDBG(TCP_DEBUG_RECEIVE) {
+ TCPTRACE(("TCPReceiveData: pending irp %lx\n", Irp));
+ }
+
+ return(status);
+ }
+
+ //
+ // The status is not pending. We reset the pending bit
+ //
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+
+ CTEAssert(status != TDI_SUCCESS);
+
+ IF_TCPDBG(TCP_DEBUG_RECEIVE) {
+ TCPTRACE((
+ "TCPReceiveData - irp %lx failed, status %lx\n",
+ Irp,
+ status
+ ));
+ }
+
+ TCPDataRequestComplete(Irp, status, 0);
+ }
+ else {
+ //
+ // Irp was cancelled previously.
+ //
+ IoReleaseCancelSpinLock(oldIrql);
+
+ IF_TCPDBG(TCP_DEBUG_SEND) {
+ TCPTRACE((
+ "TCPReceiveData: Irp %lx on fileobj %lx was cancelled\n",
+ Irp,
+ IrpSp->FileObject
+ ));
+ }
+
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ status = STATUS_CANCELLED;
+ }
+
+ return status;
+
+} // TCPReceiveData
+
+
+
+NTSTATUS
+UDPSendDatagram(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+--*/
+
+{
+ TDI_STATUS status;
+ TDI_REQUEST request;
+ PTCP_CONTEXT tcpContext;
+ PTDI_REQUEST_KERNEL_SENDDG datagramInformation;
+ ULONG bytesSent = 0;
+
+
+ tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
+ datagramInformation = (PTDI_REQUEST_KERNEL_SENDDG) &(IrpSp->Parameters);
+ CTEAssert(((int)IrpSp->FileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE);
+
+ request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
+ request.RequestNotifyObject = TCPDataRequestComplete;
+ request.RequestContext = Irp;
+
+ IF_TCPDBG(TCP_DEBUG_SEND_DGRAM) {
+ TCPTRACE((
+ "UDPSendDatagram irp %lx sending %d bytes\n",
+ Irp,
+ datagramInformation->SendLength
+ ));
+ }
+
+ status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
+
+ if (NT_SUCCESS(status)) {
+
+ status = TdiSendDatagram(
+ &request,
+ datagramInformation->SendDatagramInformation,
+ datagramInformation->SendLength,
+ &bytesSent,
+ (PNDIS_BUFFER) Irp->MdlAddress
+ );
+
+ if (status == TDI_PENDING) {
+ return(status);
+ }
+
+ CTEAssert(status != TDI_SUCCESS);
+ CTEAssert(bytesSent == 0);
+
+ TCPTRACE((
+ "UDPSendDatagram - irp %lx send failed, status %lx\n",
+ Irp,
+ status
+ ));
+
+ TCPDataRequestComplete(Irp, status, bytesSent);
+ //
+ // return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
+ //
+ return(TDI_PENDING);
+ }
+
+ return status;
+
+} // UDPSendDatagram
+
+
+
+NTSTATUS
+UDPReceiveDatagram(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ Converts a TDI ReceiveDatagram IRP into a call to TdiReceiveDatagram.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successful.
+
+--*/
+
+{
+ TDI_STATUS status;
+ TDI_REQUEST request;
+ PTCP_CONTEXT tcpContext;
+ PTDI_REQUEST_KERNEL_RECEIVEDG datagramInformation;
+ uint bytesReceived = 0;
+
+
+ tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
+ datagramInformation = (PTDI_REQUEST_KERNEL_RECEIVEDG) &(IrpSp->Parameters);
+ CTEAssert(((int)IrpSp->FileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE);
+
+ request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
+ request.RequestNotifyObject = TCPDataRequestComplete;
+ request.RequestContext = Irp;
+
+ IF_TCPDBG(TCP_DEBUG_RECEIVE_DGRAM) {
+ TCPTRACE((
+ "UDPReceiveDatagram: irp %lx receiveing %d bytes\n",
+ Irp,
+ datagramInformation->ReceiveLength
+ ));
+ }
+
+ status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
+
+ if (NT_SUCCESS(status)) {
+
+ status = TdiReceiveDatagram(
+ &request,
+ datagramInformation->ReceiveDatagramInformation,
+ datagramInformation->ReturnDatagramInformation,
+ datagramInformation->ReceiveLength,
+ &bytesReceived,
+ Irp->MdlAddress
+ );
+
+ if (status == TDI_PENDING) {
+ return(status);
+ }
+
+ CTEAssert(status != TDI_SUCCESS);
+ CTEAssert(bytesReceived == 0);
+
+ TCPTRACE((
+ "UDPReceiveDatagram: irp %lx send failed, status %lx\n",
+ Irp,
+ status
+ ));
+
+ TCPDataRequestComplete(Irp, status, bytesReceived);
+ //
+ // return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
+ //
+ return(TDI_PENDING);
+ }
+
+ return status;
+
+} // UDPReceiveDatagram
+
+
+
+NTSTATUS
+TCPSetEventHandler(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ Converts a TDI SetEventHandler IRP into a call to TdiSetEventHandler.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successful.
+
+Notes:
+
+ This routine does not pend.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTDI_REQUEST_KERNEL_SET_EVENT event;
+ PTCP_CONTEXT tcpContext;
+
+ PAGED_CODE();
+
+ tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
+ event = (PTDI_REQUEST_KERNEL_SET_EVENT) &(IrpSp->Parameters);
+
+ IF_TCPDBG(TCP_DEBUG_EVENT_HANDLER) {
+ TCPTRACE((
+ "TCPSetEventHandler: irp %lx event %lx handler %lx context %lx\n",
+ Irp,
+ event->EventType,
+ event->EventHandler,
+ event->EventContext
+ ));
+ }
+
+ status = TdiSetEvent(
+ tcpContext->Handle.AddressHandle,
+ event->EventType,
+ event->EventHandler,
+ event->EventContext
+ );
+
+ CTEAssert(status != TDI_PENDING);
+
+ return(status);
+
+} // TCPSetEventHandler
+
+
+
+NTSTATUS
+TCPQueryInformation(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ Converts a TDI QueryInformation IRP into a call to TdiQueryInformation.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successful.
+
+Notes:
+
+--*/
+
+{
+ TDI_REQUEST request;
+ TDI_STATUS status = STATUS_SUCCESS;
+ PTCP_CONTEXT tcpContext;
+ PTDI_REQUEST_KERNEL_QUERY_INFORMATION queryInformation;
+ uint isConn = FALSE;
+ uint dataSize = 0;
+
+
+ tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
+ queryInformation = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)
+ &(IrpSp->Parameters);
+
+ request.RequestNotifyObject = TCPDataRequestComplete;
+ request.RequestContext = Irp;
+
+ switch(queryInformation->QueryType) {
+
+ case TDI_QUERY_BROADCAST_ADDRESS:
+ CTEAssert( ((int) IrpSp->FileObject->FsContext2) ==
+ TDI_CONTROL_CHANNEL_FILE
+ );
+ request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
+ break;
+
+ case TDI_QUERY_PROVIDER_INFO:
+//
+// NetBT does this. Reinstate the CTEAssert when it is fixed.
+//
+// CTEAssert( ((int) IrpSp->FileObject->FsContext2) ==
+// TDI_CONTROL_CHANNEL_FILE
+// );
+ request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
+ break;
+
+ case TDI_QUERY_ADDRESS_INFO:
+ if (((int) IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE) {
+ //
+ // This is a TCP connection object.
+ //
+ isConn = TRUE;
+ request.Handle.ConnectionContext =
+ tcpContext->Handle.ConnectionContext;
+ }
+ else {
+ //
+ // This is an address object
+ //
+ request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
+ }
+ break;
+
+ case TDI_QUERY_CONNECTION_INFO:
+ CTEAssert(((int) IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
+ isConn = TRUE;
+ request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
+ break;
+
+ case TDI_QUERY_PROVIDER_STATISTICS:
+ CTEAssert( ((int) IrpSp->FileObject->FsContext2) ==
+ TDI_CONTROL_CHANNEL_FILE
+ );
+ request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
+ break;
+
+ default:
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ if (NT_SUCCESS(status)) {
+ //
+ // This request isn't cancellable, but we put it through
+ // the cancel path because it handles some checks for us
+ // and tracks the irp.
+ //
+ status = TCPPrepareIrpForCancel(tcpContext, Irp, NULL);
+
+ if (NT_SUCCESS(status)) {
+ dataSize = TCPGetMdlChainByteCount(Irp->MdlAddress);
+
+ status = TdiQueryInformation(
+ &request,
+ queryInformation->QueryType,
+ Irp->MdlAddress,
+ &dataSize,
+ isConn
+ );
+
+ if (status != TDI_PENDING) {
+ TCPDataRequestComplete(Irp, status, dataSize);
+ return(status);
+
+ }
+
+ return(STATUS_PENDING);
+ }
+
+ return(status);
+ }
+
+ Irp->IoStatus.Status = (NTSTATUS) status;
+ Irp->IoStatus.Information = 0;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ return(status);
+
+} // TCPQueryInformation
+
+
+
+void
+TCPQueryInformationExComplete(
+ void *Context,
+ unsigned int Status,
+ unsigned int ByteCount
+ )
+
+/*++
+
+Routine Description:
+
+ Completes a TdiQueryInformationEx request.
+
+Arguments:
+
+ Context - A pointer to the IRP for this request.
+ Status - The final TDI status of the request.
+ ByteCount - Bytes returned in output buffer.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+{
+ PTCP_QUERY_CONTEXT queryContext = (PTCP_QUERY_CONTEXT) Context;
+ ULONG bytesCopied;
+
+
+ if (NT_SUCCESS(Status)) {
+ //
+ // Copy the returned context to the input buffer.
+ //
+ TdiCopyBufferToMdl(
+ &(queryContext->QueryInformation.Context),
+ 0,
+ CONTEXT_SIZE,
+ queryContext->InputMdl,
+ FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX, Context),
+ &bytesCopied
+ );
+
+ CTEAssert(bytesCopied == CONTEXT_SIZE);
+ }
+
+ //
+ // Unlock the user's buffers and free the MDLs describing them.
+ //
+ MmUnlockPages(queryContext->InputMdl);
+ IoFreeMdl(queryContext->InputMdl);
+ MmUnlockPages(queryContext->OutputMdl);
+ IoFreeMdl(queryContext->OutputMdl);
+
+ //
+ // Complete the request
+ //
+ TCPDataRequestComplete(queryContext->Irp, Status, ByteCount);
+
+ CTEFreeMem(queryContext);
+
+ return;
+}
+
+
+
+NTSTATUS
+TCPQueryInformationEx(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ Converts a TDI QueryInformationEx IRP into a call to TdiQueryInformationEx.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successful.
+
+Notes:
+
+--*/
+
+{
+ TDI_REQUEST request;
+ TDI_STATUS status = STATUS_SUCCESS;
+ PTCP_CONTEXT tcpContext;
+ uint size;
+ PTCP_REQUEST_QUERY_INFORMATION_EX InputBuffer;
+ PVOID OutputBuffer;
+ PMDL inputMdl = NULL;
+ PMDL outputMdl = NULL;
+ ULONG InputBufferLength,
+ OutputBufferLength;
+ PTCP_QUERY_CONTEXT queryContext;
+ BOOLEAN inputLocked = FALSE;
+ BOOLEAN outputLocked = FALSE;
+
+
+ PAGED_CODE();
+
+ IF_TCPDBG(TCP_DEBUG_INFO) {
+ TCPTRACE((
+ "QueryInformationEx starting - irp %lx fileobj %lx\n",
+ Irp,
+ IrpSp->FileObject
+ ));
+ }
+
+ tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
+
+ switch ((int) IrpSp->FileObject->FsContext2) {
+
+ case TDI_TRANSPORT_ADDRESS_FILE:
+ request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
+ break;
+
+ case TDI_CONNECTION_FILE:
+ request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
+ break;
+
+ case TDI_CONTROL_CHANNEL_FILE:
+ request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
+ break;
+
+ default:
+ CTEAssert(0);
+
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ Irp->IoStatus.Information = 0;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ return(STATUS_INVALID_PARAMETER);
+ }
+
+ InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ //
+ // Validate the input parameters
+ //
+ if ( (InputBufferLength == sizeof(TCP_REQUEST_QUERY_INFORMATION_EX)) &&
+ (OutputBufferLength != 0)
+ )
+ {
+ OutputBuffer = Irp->UserBuffer;
+ InputBuffer = (PTCP_REQUEST_QUERY_INFORMATION_EX)
+ IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+
+ queryContext = CTEAllocMem(sizeof(TCP_QUERY_CONTEXT));
+
+ if (queryContext != NULL) {
+ status = TCPPrepareIrpForCancel(tcpContext, Irp, NULL);
+
+ if (!NT_SUCCESS(status)) {
+ CTEFreeMem(queryContext);
+ return(status);
+ }
+
+ //
+ // Allocate Mdls to describe the input and output buffers.
+ // Probe and lock the buffers.
+ //
+ try {
+ inputMdl = IoAllocateMdl(
+ InputBuffer,
+ sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
+ FALSE,
+ TRUE,
+ NULL
+ );
+
+ outputMdl = IoAllocateMdl(
+ OutputBuffer,
+ OutputBufferLength,
+ FALSE,
+ TRUE,
+ NULL
+ );
+
+ if ((inputMdl != NULL) && (outputMdl != NULL)) {
+
+ MmProbeAndLockPages(
+ inputMdl,
+ Irp->RequestorMode,
+ IoModifyAccess
+ );
+
+ inputLocked = TRUE;
+
+ MmProbeAndLockPages(
+ outputMdl,
+ Irp->RequestorMode,
+ IoWriteAccess
+ );
+
+ outputLocked = TRUE;
+
+ //
+ // Copy the input parameter to our pool block so
+ // TdiQueryInformationEx can manipulate it directly.
+ //
+ RtlCopyMemory(
+ &(queryContext->QueryInformation),
+ InputBuffer,
+ sizeof(TCP_REQUEST_QUERY_INFORMATION_EX)
+ );
+ }
+ else {
+
+ IF_TCPDBG(TCP_DEBUG_INFO) {
+ TCPTRACE(("QueryInfoEx: Couldn't allocate MDL\n"));
+ }
+
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+
+ IF_TCPDBG(TCP_DEBUG_INFO) {
+ TCPTRACE((
+ "QueryInfoEx: exception copying input params %lx\n",
+ GetExceptionCode()
+ ));
+ }
+
+ status = GetExceptionCode();
+ }
+
+ if (NT_SUCCESS(status)) {
+ //
+ // It's finally time to do this thing.
+ //
+ size = TCPGetMdlChainByteCount(outputMdl);
+
+ queryContext->Irp = Irp;
+ queryContext->InputMdl = inputMdl;
+ queryContext->OutputMdl = outputMdl;
+
+ request.RequestNotifyObject = TCPQueryInformationExComplete;
+ request.RequestContext = queryContext;
+
+ status = TdiQueryInformationEx(
+ &request,
+ &(queryContext->QueryInformation.ID),
+ outputMdl,
+ &size,
+ &(queryContext->QueryInformation.Context)
+ );
+
+ if (status != TDI_PENDING) {
+ TCPQueryInformationExComplete(
+ queryContext,
+ status,
+ size
+ );
+
+ return(status);
+ }
+
+ IF_TCPDBG(TCP_DEBUG_INFO) {
+ TCPTRACE((
+ "QueryInformationEx - pending irp %lx fileobj %lx\n",
+ Irp,
+ IrpSp->FileObject
+ ));
+ }
+
+ return(STATUS_PENDING);
+ }
+
+ //
+ // If we get here, something failed. Clean up.
+ //
+ if (inputMdl != NULL) {
+ if (inputLocked) {
+ MmUnlockPages(inputMdl);
+ }
+
+ IoFreeMdl(inputMdl);
+ }
+
+ if (outputMdl != NULL) {
+ if (outputLocked) {
+ MmUnlockPages(outputMdl);
+ }
+
+ IoFreeMdl(outputMdl);
+ }
+
+ CTEFreeMem(queryContext);
+
+ TCPDataRequestComplete(Irp, status, 0);
+
+ return(status);
+
+ }
+ else {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+
+ IF_TCPDBG(TCP_DEBUG_INFO) {
+ TCPTRACE(("QueryInfoEx: Unable to allocate query context\n"));
+ }
+ }
+ }
+ else {
+ status = STATUS_INVALID_PARAMETER;
+
+ IF_TCPDBG(TCP_DEBUG_INFO) {
+ TCPTRACE((
+ "QueryInfoEx: Bad buffer len, OBufLen %d, InBufLen %d\n",
+ OutputBufferLength, InputBufferLength
+ ));
+ }
+ }
+
+
+ IF_TCPDBG(TCP_DEBUG_INFO) {
+ TCPTRACE((
+ "QueryInformationEx complete - irp %lx, status %lx\n",
+ Irp,
+ status
+ ));
+ }
+
+ Irp->IoStatus.Status = (NTSTATUS) status;
+ Irp->IoStatus.Information = 0;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+
+ return(status);
+}
+
+
+
+NTSTATUS
+TCPSetInformationEx(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ Converts a TDI SetInformationEx IRP into a call to TdiSetInformationEx.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successful.
+
+Notes:
+
+ This routine does not pend.
+
+--*/
+
+{
+ TDI_REQUEST request;
+ TDI_STATUS status;
+ PTCP_CONTEXT tcpContext;
+ PTCP_REQUEST_SET_INFORMATION_EX setInformation;
+
+
+ PAGED_CODE();
+
+ IF_TCPDBG(TCP_DEBUG_INFO) {
+ TCPTRACE((
+ "SetInformationEx - irp %lx fileobj %lx\n",
+ Irp,
+ IrpSp->FileObject
+ ));
+ }
+
+ tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
+ setInformation = (PTCP_REQUEST_SET_INFORMATION_EX)
+ Irp->AssociatedIrp.SystemBuffer;
+
+ switch ((int) IrpSp->FileObject->FsContext2) {
+
+ case TDI_TRANSPORT_ADDRESS_FILE:
+ request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
+ break;
+
+ case TDI_CONNECTION_FILE:
+ request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
+ break;
+
+ case TDI_CONTROL_CHANNEL_FILE:
+ request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
+ break;
+
+ default:
+ CTEAssert(0);
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ Irp->IoStatus.Information = 0;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ return(STATUS_INVALID_PARAMETER);
+ }
+
+ status = TCPPrepareIrpForCancel(tcpContext, Irp, NULL);
+
+ if (NT_SUCCESS(status)) {
+ request.RequestNotifyObject = TCPDataRequestComplete;
+ request.RequestContext = Irp;
+
+ status = TdiSetInformationEx(
+ &request,
+ &(setInformation->ID),
+ &(setInformation->Buffer[0]),
+ setInformation->BufferSize
+ );
+
+ if (status != TDI_PENDING) {
+ TCPDataRequestComplete(
+ Irp,
+ status,
+ 0
+ );
+
+ return(status);
+ }
+
+ IF_TCPDBG(TCP_DEBUG_INFO) {
+ TCPTRACE((
+ "SetInformationEx - pending irp %lx fileobj %lx\n",
+ Irp,
+ IrpSp->FileObject
+ ));
+ }
+
+ return(STATUS_PENDING);
+ }
+
+ IF_TCPDBG(TCP_DEBUG_INFO) {
+ TCPTRACE((
+ "SetInformationEx complete - irp %lx\n",
+ Irp
+ ));
+ }
+
+ //
+ // The irp has already been completed.
+ //
+ return(status);
+}
+
+
+#ifdef SECFLTR
+
+
+
+NTSTATUS
+TCPControlSecurityFilter(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ Processes a request to query or set the status of security filtering.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successful.
+
+Notes:
+
+ This routine does not pend.
+
+--*/
+
+{
+
+ PTCP_SECURITY_FILTER_STATUS request;
+ ULONG requestLength;
+ ULONG requestCode;
+ TDI_STATUS status = STATUS_SUCCESS;
+
+
+ PAGED_CODE();
+
+ Irp->IoStatus.Information = 0;
+
+ request = (PTCP_SECURITY_FILTER_STATUS) Irp->AssociatedIrp.SystemBuffer;
+ requestCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
+
+ if (requestCode == IOCTL_TCP_QUERY_SECURITY_FILTER_STATUS) {
+ requestLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ if (requestLength < sizeof(TCP_SECURITY_FILTER_STATUS)) {
+ status = STATUS_INVALID_PARAMETER;
+ }
+ else {
+ request->FilteringEnabled = IsSecurityFilteringEnabled();
+ Irp->IoStatus.Information = sizeof(TCP_SECURITY_FILTER_STATUS);
+ }
+ }
+ else {
+ CTEAssert(requestCode == IOCTL_TCP_SET_SECURITY_FILTER_STATUS);
+
+ requestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+
+ if (requestLength < sizeof(TCP_SECURITY_FILTER_STATUS)) {
+ status = STATUS_INVALID_PARAMETER;
+ }
+ else {
+ ControlSecurityFiltering(request->FilteringEnabled);
+ }
+ }
+
+ Irp->IoStatus.Status = status;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ return(status);
+}
+
+
+
+NTSTATUS
+TCPProcessSecurityFilterRequest(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ Processes a request to add or delete a transport security filter.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successful.
+
+Notes:
+
+ This routine does not pend.
+
+--*/
+
+{
+ TCPSecurityFilterEntry *request;
+ ULONG requestLength;
+ ULONG i;
+ ULONG requestCode;
+ NTSTATUS status = STATUS_SUCCESS;
+
+
+ PAGED_CODE();
+
+ Irp->IoStatus.Information = 0;
+
+ request = (TCPSecurityFilterEntry *) Irp->AssociatedIrp.SystemBuffer;
+ requestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ requestCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
+
+ if (requestLength < sizeof(TCPSecurityFilterEntry)) {
+ status = STATUS_INVALID_PARAMETER;
+ }
+ else {
+ if (requestCode == IOCTL_TCP_ADD_SECURITY_FILTER) {
+ status = AddValueSecurityFilter(
+ net_long(request->tsf_address),
+ request->tsf_protocol,
+ request->tsf_value
+ );
+ }
+ else {
+ CTEAssert(requestCode == IOCTL_TCP_DELETE_SECURITY_FILTER);
+ status = DeleteValueSecurityFilter(
+ net_long(request->tsf_address),
+ request->tsf_protocol,
+ request->tsf_value
+ );
+ }
+ }
+
+ Irp->IoStatus.Status = status;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ return(status);
+}
+
+
+
+NTSTATUS
+TCPEnumerateSecurityFilter(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ Processes a request to enumerate a transport security filter list.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successful.
+
+Notes:
+
+ This routine does not pend.
+
+--*/
+
+{
+
+ TCPSecurityFilterEntry *request;
+ TCPSecurityFilterEnum *response;
+ ULONG requestLength, responseLength;
+ NTSTATUS status;
+
+
+ PAGED_CODE();
+
+ request = (TCPSecurityFilterEntry *) Irp->AssociatedIrp.SystemBuffer;
+ response = (TCPSecurityFilterEnum *) request;
+ requestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ responseLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ if (requestLength < sizeof(TCPSecurityFilterEntry)) {
+ status = STATUS_INVALID_PARAMETER;
+ Irp->IoStatus.Information = 0;
+ }
+ else if (responseLength < sizeof(TCPSecurityFilterEnum)) {
+ status = STATUS_BUFFER_TOO_SMALL;
+ Irp->IoStatus.Information = 0;
+ }
+ else {
+ EnumerateSecurityFilters(
+ net_long(request->tsf_address),
+ request->tsf_protocol,
+ request->tsf_value,
+ (uchar *) (response + 1),
+ responseLength - sizeof(TCPSecurityFilterEnum),
+ &(response->tfe_entries_returned),
+ &(response->tfe_entries_available)
+ );
+
+ status = TDI_SUCCESS;
+ Irp->IoStatus.Information =
+ sizeof(TCPSecurityFilterEnum) +
+ (response->tfe_entries_returned * sizeof(TCPSecurityFilterEntry));
+
+
+ }
+
+ Irp->IoStatus.Status = status;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ return(status);
+}
+
+#endif // SECFLTR
+
+
+NTSTATUS
+TCPEnumerateConnectionList(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ Processes a request to enumerate the workstation connection list.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successful.
+
+Notes:
+
+ This routine does not pend.
+
+--*/
+
+{
+
+ TCPConnectionListEntry *request;
+ TCPConnectionListEnum *response;
+ ULONG requestLength, responseLength;
+ NTSTATUS status;
+
+
+ PAGED_CODE();
+
+ request = (TCPConnectionListEntry *) Irp->AssociatedIrp.SystemBuffer;
+ response = (TCPConnectionListEnum *) request;
+ requestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ responseLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ if (responseLength < sizeof(TCPConnectionListEnum)) {
+ status = STATUS_BUFFER_TOO_SMALL;
+ Irp->IoStatus.Information = 0;
+ }
+ else {
+ EnumerateConnectionList(
+ (uchar *) (response + 1),
+ responseLength - sizeof(TCPConnectionListEnum),
+ &(response->tce_entries_returned),
+ &(response->tce_entries_available)
+ );
+
+ status = TDI_SUCCESS;
+ Irp->IoStatus.Information =
+ sizeof(TCPConnectionListEnum) +
+ (response->tce_entries_returned * sizeof(TCPConnectionListEntry));
+
+
+ }
+
+ Irp->IoStatus.Status = status;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ return(status);
+}
+
+
+
+NTSTATUS
+TCPCreate(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this request.
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+--*/
+
+{
+ TDI_REQUEST Request;
+ NTSTATUS status;
+ FILE_FULL_EA_INFORMATION *ea;
+ FILE_FULL_EA_INFORMATION UNALIGNED *targetEA;
+ PTCP_CONTEXT tcpContext;
+ uint protocol;
+
+
+ PAGED_CODE();
+
+ tcpContext = ExAllocatePool(NonPagedPool, sizeof(TCP_CONTEXT));
+
+ if (tcpContext == NULL) {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+#if DBG
+ InitializeListHead(&(tcpContext->PendingIrpList));
+ InitializeListHead(&(tcpContext->CancelledIrpList));
+#endif
+
+ tcpContext->ReferenceCount = 1; // put initial reference on open object
+ tcpContext->CancelIrps = FALSE;
+ KeInitializeEvent(&(tcpContext->CleanupEvent), SynchronizationEvent, FALSE);
+
+ ea = (PFILE_FULL_EA_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
+
+ //
+ // See if this is a Control Channel open.
+ //
+ if (!ea) {
+ IF_TCPDBG(TCP_DEBUG_OPEN) {
+ TCPTRACE((
+ "TCPCreate: Opening control channel for file object %lx\n",
+ IrpSp->FileObject
+ ));
+ }
+
+ tcpContext->Handle.ControlChannel = NULL;
+ IrpSp->FileObject->FsContext = tcpContext;
+ IrpSp->FileObject->FsContext2 = (PVOID) TDI_CONTROL_CHANNEL_FILE;
+
+ return(STATUS_SUCCESS);
+ }
+
+ //
+ // See if this is an Address Object open.
+ //
+ targetEA = FindEA(
+ ea,
+ TdiTransportAddress,
+ TDI_TRANSPORT_ADDRESS_LENGTH
+ );
+
+ if (targetEA != NULL) {
+ UCHAR optionsBuffer[3];
+ PUCHAR optionsPointer = optionsBuffer;
+
+
+ if (DeviceObject == TCPDeviceObject) {
+ protocol = PROTOCOL_TCP;
+ }
+ else if (DeviceObject == UDPDeviceObject) {
+ protocol = PROTOCOL_UDP;
+
+ CTEAssert(optionsPointer - optionsBuffer <= 3);
+
+ if (IsDHCPZeroAddress(
+ (TRANSPORT_ADDRESS UNALIGNED *)
+ &(targetEA->EaName[targetEA->EaNameLength + 1])
+ )) {
+ *optionsPointer = TDI_ADDRESS_OPTION_DHCP;
+ optionsPointer++;
+ }
+
+ CTEAssert(optionsPointer - optionsBuffer <= 3);
+ }
+ else {
+ //
+ // This is a raw ip open
+ //
+ protocol = RawExtractProtocolNumber(
+ &(IrpSp->FileObject->FileName)
+ );
+
+ if (protocol == 0xFFFFFFFF) {
+ ExFreePool(tcpContext);
+ return(STATUS_INVALID_PARAMETER);
+ }
+ }
+
+ if ( (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)
+ ) {
+ *optionsPointer = TDI_ADDRESS_OPTION_REUSE;
+ optionsPointer++;
+ }
+
+ *optionsPointer = TDI_OPTION_EOL;
+
+ IF_TCPDBG(TCP_DEBUG_OPEN) {
+ TCPTRACE((
+ "TCPCreate: Opening address for file object %lx\n",
+ IrpSp->FileObject
+ ));
+ }
+
+ status = TdiOpenAddress(
+ &Request,
+ (TRANSPORT_ADDRESS UNALIGNED *)
+ &(targetEA->EaName[targetEA->EaNameLength + 1]),
+ protocol,
+ optionsBuffer
+ );
+
+ if (NT_SUCCESS(status)) {
+ //
+ // Save off the handle to the AO passed back.
+ //
+ tcpContext->Handle.AddressHandle = Request.Handle.AddressHandle;
+ IrpSp->FileObject->FsContext = tcpContext;
+ IrpSp->FileObject->FsContext2 =
+ (PVOID) TDI_TRANSPORT_ADDRESS_FILE;
+ }
+ else {
+ ExFreePool(tcpContext);
+ TCPTRACE(("TdiOpenAddress failed, status %lx\n", status));
+ if (status == STATUS_ADDRESS_ALREADY_EXISTS) {
+ status = STATUS_SHARING_VIOLATION;
+ }
+ }
+
+ CTEAssert(status != TDI_PENDING);
+
+ return(status);
+ }
+
+ //
+ // See if this is a Connection Object open.
+ //
+ targetEA = FindEA(
+ ea,
+ TdiConnectionContext,
+ TDI_CONNECTION_CONTEXT_LENGTH
+ );
+
+ if (targetEA != NULL) {
+ //
+ // This is an open of a Connection Object.
+ //
+
+ if (DeviceObject == TCPDeviceObject) {
+
+ IF_TCPDBG(TCP_DEBUG_OPEN) {
+ TCPTRACE((
+ "TCPCreate: Opening connection for file object %lx\n",
+ IrpSp->FileObject
+ ));
+ }
+
+ status = TdiOpenConnection(
+ &Request,
+ *((CONNECTION_CONTEXT UNALIGNED *)
+ &(targetEA->EaName[targetEA->EaNameLength + 1]))
+ );
+
+ if (NT_SUCCESS(status)) {
+ //
+ // Save off the Connection Context passed back.
+ //
+ tcpContext->Handle.ConnectionContext =
+ Request.Handle.ConnectionContext;
+ IrpSp->FileObject->FsContext = tcpContext;
+ IrpSp->FileObject->FsContext2 =
+ (PVOID) TDI_CONNECTION_FILE;
+ }
+ else {
+ ExFreePool(tcpContext);
+ TCPTRACE((
+ "TdiOpenConnection failed, status %lx\n",
+ status
+ ));
+ }
+ }
+ else {
+ TCPTRACE((
+ "TCP: TdiOpenConnection issued on UDP device!\n"
+ ));
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ ExFreePool(tcpContext);
+ }
+
+ CTEAssert(status != TDI_PENDING);
+
+ return(status);
+ }
+
+ TCPTRACE(("TCPCreate: didn't find any useful ea's\n"));
+ status = STATUS_INVALID_EA_NAME;
+ ExFreePool(tcpContext);
+
+
+ CTEAssert(status != TDI_PENDING);
+
+ return(status);
+
+} // TCPCreate
+
+
+
+void
+TCPCloseObjectComplete(
+ void *Context,
+ unsigned int Status,
+ unsigned int UnUsed
+ )
+
+/*++
+
+Routine Description:
+
+ Completes a TdiCloseConnectoin or TdiCloseAddress request.
+
+Arguments:
+
+ Context - A pointer to the IRP for this request.
+ Status - The final status of the operation.
+ UnUsed - An unused parameter
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ KIRQL oldIrql;
+ PIRP irp;
+ PIO_STACK_LOCATION irpSp;
+ PTCP_CONTEXT tcpContext;
+
+
+ UNREFERENCED_PARAMETER(UnUsed);
+
+ irp = (PIRP) Context;
+ irpSp = IoGetCurrentIrpStackLocation(irp);
+ tcpContext = (PTCP_CONTEXT) irpSp->FileObject->FsContext;
+ irp->IoStatus.Status = Status;
+
+ IF_TCPDBG(TCP_DEBUG_CLEANUP) {
+ TCPTRACE((
+ "TCPCloseObjectComplete on file object %lx\n",
+ irpSp->FileObject
+ ));
+ }
+
+ IoAcquireCancelSpinLock(&oldIrql);
+
+ CTEAssert(tcpContext->ReferenceCount > 0);
+ CTEAssert(tcpContext->CancelIrps);
+
+ //
+ // Remove the initial reference that was put on by TCPCreate.
+ //
+ CTEAssert(tcpContext->ReferenceCount > 0);
+
+ if (--(tcpContext->ReferenceCount) == 0) {
+
+ IF_TCPDBG(TCP_DEBUG_CANCEL) {
+ CTEAssert(IsListEmpty(&(tcpContext->CancelledIrpList)));
+ CTEAssert(IsListEmpty(&(tcpContext->PendingIrpList)));
+ }
+
+ KeSetEvent(&(tcpContext->CleanupEvent), 0, FALSE);
+ }
+
+ IF_TCPDBG(TCP_DEBUG_IRP) {
+ TCPTRACE((
+ "TCPCloseObjectComplete: irp %lx fileobj %lx refcnt dec to %u\n",
+ irp,
+ irpSp,
+ tcpContext->ReferenceCount
+ ));
+ }
+
+ IoReleaseCancelSpinLock(oldIrql);
+
+ return;
+
+} // TCPCleanupComplete
+
+
+
+NTSTATUS
+TCPCleanup(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ Cancels all outstanding Irps on a TDI object by calling the close
+ routine for the object. It then waits for them to be completed
+ before returning.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+Notes:
+
+ This routine blocks, but does not pend.
+
+--*/
+
+{
+ KIRQL oldIrql;
+ PIRP cancelIrp = NULL;
+ PTCP_CONTEXT tcpContext;
+ NTSTATUS status;
+ TDI_REQUEST request;
+
+
+ tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
+
+ IoAcquireCancelSpinLock(&oldIrql);
+
+ tcpContext->CancelIrps = TRUE;
+ KeResetEvent(&(tcpContext->CleanupEvent));
+
+ IoReleaseCancelSpinLock(oldIrql);
+
+ //
+ // Now call the TDI close routine for this object to force all of its Irps
+ // to complete.
+ //
+ request.RequestNotifyObject = TCPCloseObjectComplete;
+ request.RequestContext = Irp;
+
+ switch ((int) IrpSp->FileObject->FsContext2) {
+
+ case TDI_TRANSPORT_ADDRESS_FILE:
+ IF_TCPDBG(TCP_DEBUG_CLOSE) {
+ TCPTRACE((
+ "TCPCleanup: Closing address object on file object %lx\n",
+ IrpSp->FileObject
+ ));
+ }
+ request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
+ status = TdiCloseAddress(&request);
+ break;
+
+ case TDI_CONNECTION_FILE:
+ IF_TCPDBG(TCP_DEBUG_CLOSE) {
+ TCPTRACE((
+ "TCPCleanup: Closing Connection object on file object %lx\n",
+ IrpSp->FileObject
+ ));
+ }
+ request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
+ status = TdiCloseConnection(&request);
+ break;
+
+ case TDI_CONTROL_CHANNEL_FILE:
+ IF_TCPDBG(TCP_DEBUG_CLOSE) {
+ TCPTRACE((
+ "TCPCleanup: Closing Control Channel object on file object %lx\n",
+ IrpSp->FileObject
+ ));
+ }
+ status = STATUS_SUCCESS;
+ break;
+
+ default:
+ //
+ // This should never happen.
+ //
+ CTEAssert(FALSE);
+
+ IoAcquireCancelSpinLock(&oldIrql);
+ tcpContext->CancelIrps = FALSE;
+ IoReleaseCancelSpinLock(oldIrql);
+
+ return(STATUS_INVALID_PARAMETER);
+ }
+
+ if (status != TDI_PENDING) {
+ TCPCloseObjectComplete(Irp, status, 0);
+ }
+
+ IF_TCPDBG(TCP_DEBUG_CLEANUP) {
+ TCPTRACE((
+ "TCPCleanup: waiting for completion of Irps on file object %lx\n",
+ IrpSp->FileObject
+ ));
+ }
+
+ status = KeWaitForSingleObject(
+ &(tcpContext->CleanupEvent),
+ UserRequest,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ CTEAssert(NT_SUCCESS(status));
+
+ IF_TCPDBG(TCP_DEBUG_CLEANUP) {
+ TCPTRACE((
+ "TCPCleanup: Wait on file object %lx finished\n",
+ IrpSp->FileObject
+ ));
+ }
+
+ //
+ // The cleanup Irp will be completed by the dispatch routine.
+ //
+
+ return(Irp->IoStatus.Status);
+
+} // TCPCleanup
+
+
+NTSTATUS
+TCPClose(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ Dispatch routine for MJ_CLOSE IRPs. Performs final cleanup of the
+ open endpoint.
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+Notes:
+
+ This request does not pend.
+
+--*/
+
+{
+ PTCP_CONTEXT tcpContext;
+
+
+ tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
+
+#if DBG
+
+ IF_TCPDBG(TCP_DEBUG_CANCEL) {
+
+ KIRQL oldIrql;
+
+ IoAcquireCancelSpinLock(&oldIrql);
+
+ CTEAssert(tcpContext->ReferenceCount == 0);
+ CTEAssert(IsListEmpty(&(tcpContext->PendingIrpList)));
+ CTEAssert(IsListEmpty(&(tcpContext->CancelledIrpList)));
+
+ IoReleaseCancelSpinLock(oldIrql);
+ }
+#endif // DBG
+
+ IF_TCPDBG(TCP_DEBUG_CLOSE) {
+ TCPTRACE(("TCPClose on file object %lx\n", IrpSp->FileObject));
+ }
+
+ ExFreePool(tcpContext);
+
+ return(STATUS_SUCCESS);
+
+} // TCPClose
+
+
+
+NTSTATUS
+TCPDispatchDeviceControl(
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+ Irp - Pointer to I/O request packet
+ IrpSp - Pointer to the current stack location in the Irp.
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+--*/
+
+{
+ NTSTATUS status;
+
+
+ PAGED_CODE();
+
+ //
+ // Set this in advance. Any IOCTL dispatch routine that cares about it
+ // will modify it itself.
+ //
+ Irp->IoStatus.Information = 0;
+
+ switch(IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+
+ case IOCTL_TCP_QUERY_INFORMATION_EX:
+ return(TCPQueryInformationEx(Irp, IrpSp));
+ break;
+
+ case IOCTL_TCP_SET_INFORMATION_EX:
+ return(TCPSetInformationEx(Irp, IrpSp));
+ break;
+
+#ifdef SECFLTR
+
+ case IOCTL_TCP_QUERY_SECURITY_FILTER_STATUS:
+ case IOCTL_TCP_SET_SECURITY_FILTER_STATUS:
+ return(TCPControlSecurityFilter(Irp, IrpSp));
+ break;
+
+ case IOCTL_TCP_ADD_SECURITY_FILTER:
+ case IOCTL_TCP_DELETE_SECURITY_FILTER:
+ return(TCPProcessSecurityFilterRequest(Irp, IrpSp));
+ break;
+
+ case IOCTL_TCP_ENUMERATE_SECURITY_FILTER:
+ return(TCPEnumerateSecurityFilter(Irp, IrpSp));
+ break;
+
+#endif // SECFLTR
+
+ default:
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ Irp->IoStatus.Status = status;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ return status;
+
+} // TCPDispatchDeviceControl
+
+
+
+NTSTATUS
+TCPDispatchInternalDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the dispatch routine for Internal Device Control IRPs.
+ This is the hot path for kernel-mode clients.
+
+Arguments:
+
+ DeviceObject - Pointer to device object for target device
+ Irp - Pointer to I/O request packet
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+--*/
+
+{
+ PIO_STACK_LOCATION irpSp;
+ NTSTATUS status;
+
+
+ if (DeviceObject != IPDeviceObject) {
+
+ irpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ if (((int)irpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE) {
+ //
+ // Send and receive are the performance path, so check for them
+ // right away.
+ //
+ if (irpSp->MinorFunction == TDI_SEND) {
+ return(TCPSendData(Irp, irpSp));
+ }
+
+ if (irpSp->MinorFunction == TDI_RECEIVE) {
+ return(TCPReceiveData(Irp, irpSp));
+ }
+
+ switch(irpSp->MinorFunction) {
+
+ case TDI_ASSOCIATE_ADDRESS:
+ status = TCPAssociateAddress(Irp, irpSp);
+ Irp->IoStatus.Status = status;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ return(status);
+
+ case TDI_DISASSOCIATE_ADDRESS:
+ return(TCPDisassociateAddress(Irp, irpSp));
+
+ case TDI_CONNECT:
+ return(TCPConnect(Irp, irpSp));
+
+ case TDI_DISCONNECT:
+ return(TCPDisconnect(Irp, irpSp));
+
+ case TDI_LISTEN:
+ return(TCPListen(Irp, irpSp));
+
+ case TDI_ACCEPT:
+ return(TCPAccept(Irp, irpSp));
+
+ default:
+ break;
+ }
+
+ //
+ // Fall through.
+ //
+ }
+ else if ( ((int)irpSp->FileObject->FsContext2) ==
+ TDI_TRANSPORT_ADDRESS_FILE
+ )
+ {
+ if (irpSp->MinorFunction == TDI_SEND_DATAGRAM) {
+ return(UDPSendDatagram(Irp, irpSp));
+ }
+
+ if (irpSp->MinorFunction == TDI_RECEIVE_DATAGRAM) {
+ return(UDPReceiveDatagram(Irp, irpSp));
+ }
+
+ if (irpSp->MinorFunction == TDI_SET_EVENT_HANDLER) {
+ status = TCPSetEventHandler(Irp, irpSp);
+
+ Irp->IoStatus.Status = status;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ return(status);
+ }
+
+ //
+ // Fall through.
+ //
+ }
+
+ CTEAssert(
+ (((int)irpSp->FileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE)
+ ||
+ (((int)irpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE)
+ ||
+ (((int)irpSp->FileObject->FsContext2) == TDI_CONTROL_CHANNEL_FILE)
+ );
+
+ //
+ // These functions are common to all endpoint types.
+ //
+ switch(irpSp->MinorFunction) {
+
+ case TDI_QUERY_INFORMATION:
+ return(TCPQueryInformation(Irp, irpSp));
+
+ case TDI_SET_INFORMATION:
+ case TDI_ACTION:
+ TCPTRACE((
+ "TCP: Call to unimplemented TDI function 0x%x\n",
+ irpSp->MinorFunction
+ ));
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ default:
+ TCPTRACE((
+ "TCP: call to invalid TDI function 0x%x\n",
+ irpSp->MinorFunction
+ ));
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ CTEAssert(status != TDI_PENDING);
+
+ Irp->IoStatus.Status = status;
+ Irp->IoStatus.Information = 0;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ return status;
+ }
+
+ return(IPDispatch(DeviceObject, Irp));
+}
+
+
+
+NTSTATUS
+TCPDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the generic dispatch routine for TCP/UDP/RawIP.
+
+Arguments:
+
+ DeviceObject - Pointer to device object for target device
+ Irp - Pointer to I/O request packet
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+--*/
+
+{
+ PIO_STACK_LOCATION irpSp;
+ NTSTATUS status;
+
+
+ if (DeviceObject != IPDeviceObject) {
+
+ irpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ CTEAssert(irpSp->MajorFunction != IRP_MJ_INTERNAL_DEVICE_CONTROL);
+
+ switch (irpSp->MajorFunction) {
+
+ case IRP_MJ_CREATE:
+ status = TCPCreate(DeviceObject, Irp, irpSp);
+ break;
+
+ case IRP_MJ_CLEANUP:
+ status = TCPCleanup(DeviceObject, Irp, irpSp);
+ break;
+
+ case IRP_MJ_CLOSE:
+ status = TCPClose(Irp, irpSp);
+ break;
+
+ case IRP_MJ_DEVICE_CONTROL:
+ status = TdiMapUserRequest(DeviceObject, Irp, irpSp);
+
+ if (status == STATUS_SUCCESS) {
+ return(TCPDispatchInternalDeviceControl(DeviceObject, Irp));
+ }
+
+ return(TCPDispatchDeviceControl(
+ Irp,
+ IoGetCurrentIrpStackLocation(Irp)
+ ));
+ break;
+
+ case IRP_MJ_QUERY_SECURITY:
+ //
+ // This is generated on Raw endpoints. We don't do anything
+ // for it.
+ //
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+
+ case IRP_MJ_WRITE:
+ case IRP_MJ_READ:
+
+ default:
+ TCPTRACE((
+ "TCPDispatch: Irp %lx unsupported major function 0x%lx\n",
+ irpSp,
+ irpSp->MajorFunction
+ ));
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ CTEAssert(status != TDI_PENDING);
+
+ Irp->IoStatus.Status = status;
+ Irp->IoStatus.Information = 0;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ return status;
+
+ }
+
+ return(IPDispatch(DeviceObject, Irp));
+
+
+} // TCPDispatch
+
+
+
+//
+// Private utility functions
+//
+FILE_FULL_EA_INFORMATION UNALIGNED *
+FindEA(
+ PFILE_FULL_EA_INFORMATION StartEA,
+ CHAR *TargetName,
+ USHORT TargetNameLength
+ )
+
+/*++
+
+Routine Description:
+
+ Parses and extended attribute list for a given target attribute.
+
+Arguments:
+
+ StartEA - the first extended attribute in the list.
+ TargetName - the name of the target attribute.
+ TargetNameLength - the length of the name of the target attribute.
+
+Return Value:
+
+ A pointer to the requested attribute or NULL if the target wasn't found.
+
+--*/
+
+{
+ USHORT i;
+ BOOLEAN found;
+ FILE_FULL_EA_INFORMATION UNALIGNED *CurrentEA;
+
+
+ PAGED_CODE();
+
+ do {
+ found = TRUE;
+
+ CurrentEA = StartEA;
+ StartEA += CurrentEA->NextEntryOffset;
+
+ if (CurrentEA->EaNameLength != TargetNameLength) {
+ continue;
+ }
+
+ for (i=0; i < CurrentEA->EaNameLength; i++) {
+ if (CurrentEA->EaName[i] == TargetName[i]) {
+ continue;
+ }
+ found = FALSE;
+ break;
+ }
+
+ if (found) {
+ return(CurrentEA);
+ }
+
+ } while(CurrentEA->NextEntryOffset != 0);
+
+ return(NULL);
+}
+
+
+
+BOOLEAN
+IsDHCPZeroAddress(
+ TRANSPORT_ADDRESS UNALIGNED *AddrList
+ )
+
+/*++
+
+Routine Description:
+
+ Checks a TDI IP address list for an address from DHCP binding
+ to the IP address zero. Normally, binding to zero means wildcard.
+ For DHCP, it really means bind to an interface with an address of
+ zero. This semantic is flagged by a special value in an unused
+ portion of the address structure (ie. this is a kludge).
+
+Arguments:
+
+ AddrList - The TDI transport address list passed in the create IRP.
+
+Return Value:
+
+ TRUE if the first IP address found had the flag set. FALSE otherwise.
+
+--*/
+
+{
+ int i; // Index variable.
+ TA_ADDRESS UNALIGNED *CurrentAddr; // Address we're examining and may use.
+
+
+ // First, verify that someplace in Address is an address we can use.
+ CurrentAddr = (TA_ADDRESS UNALIGNED *)AddrList->Address;
+
+ for (i = 0; i < AddrList->TAAddressCount; i++) {
+ if (CurrentAddr->AddressType == TDI_ADDRESS_TYPE_IP) {
+ if (CurrentAddr->AddressLength == TDI_ADDRESS_LENGTH_IP) {
+ TDI_ADDRESS_IP UNALIGNED *ValidAddr;
+
+ ValidAddr = (TDI_ADDRESS_IP UNALIGNED *)CurrentAddr->Address;
+
+ if (*((ULONG UNALIGNED *) ValidAddr->sin_zero) == 0x12345678) {
+ return TRUE;
+ }
+
+ } else {
+ return FALSE; // Wrong length for address.
+ }
+ } else {
+ CurrentAddr = (TA_ADDRESS UNALIGNED *)
+ (CurrentAddr->Address + CurrentAddr->AddressLength);
+ }
+ }
+
+ return FALSE; // Didn't find a match.
+}
+
+
+
+ULONG
+TCPGetMdlChainByteCount(
+ PMDL Mdl
+ )
+
+/*++
+
+Routine Description:
+
+ Sums the byte counts of each MDL in a chain.
+
+Arguments:
+
+ Mdl - Pointer to the MDL chain to sum.
+
+Return Value:
+
+ The byte count of the MDL chain.
+
+--*/
+
+{
+ ULONG count = 0;
+
+ while (Mdl != NULL) {
+ count += MmGetMdlByteCount(Mdl);
+ Mdl = Mdl->Next;
+ }
+
+ return(count);
+}
+
+
+
+
+ULONG
+RawExtractProtocolNumber(
+ IN PUNICODE_STRING FileName
+ )
+
+/*++
+
+Routine Description:
+
+ Extracts the protocol number from the file object name.
+
+Arguments:
+
+ FileName - The unicode file name.
+
+Return Value:
+
+ The protocol number or 0xFFFFFFFF on error.
+
+--*/
+
+{
+ PWSTR name;
+ UNICODE_STRING unicodeString;
+ USHORT length;
+ ULONG protocol;
+ NTSTATUS status;
+
+
+ PAGED_CODE();
+
+ name = FileName->Buffer;
+
+ if ( FileName->Length <
+ (sizeof(OBJ_NAME_PATH_SEPARATOR) + sizeof(WCHAR))
+ )
+ {
+ return(0xFFFFFFFF);
+ }
+
+ //
+ // Step over separator
+ //
+ if (*name++ != OBJ_NAME_PATH_SEPARATOR) {
+ return(0xFFFFFFFF);
+ }
+
+ if (*name == UNICODE_NULL) {
+ return(0xFFFFFFFF);
+ }
+
+ //
+ // Convert the remaining name into a number.
+ //
+ RtlInitUnicodeString(&unicodeString, name);
+
+ status = RtlUnicodeStringToInteger(
+ &unicodeString,
+ 10,
+ &protocol
+ );
+
+ if (!NT_SUCCESS(status)) {
+ return(0xFFFFFFFF);
+ }
+
+ if (protocol > 255) {
+ return(0xFFFFFFFF);
+ }
+
+ return(protocol);
+
+}
+
diff --git a/private/ntos/tdi/tcpip/tcp/ntinit.c b/private/ntos/tdi/tcpip/tcp/ntinit.c
new file mode 100644
index 000000000..e1fdbd7f7
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/ntinit.c
@@ -0,0 +1,1038 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ntinit.c
+
+Abstract:
+
+ NT specific routines for loading and configuring the TCP/UDP driver.
+
+Author:
+
+ Mike Massa (mikemas) Aug 13, 1993
+
+Revision History:
+
+ Who When What
+ -------- -------- ----------------------------------------------
+ mikemas 08-13-93 created
+
+Notes:
+
+--*/
+
+#include <oscfg.h>
+#include <ntddip.h>
+#include <ndis.h>
+#include <cxport.h>
+#include <tdi.h>
+#include <tdikrnl.h>
+#include <tdint.h>
+#include <tdistat.h>
+#include <tdiinfo.h>
+#include <ip.h>
+
+#include "queue.h"
+#include "addr.h"
+#include "tcp.h"
+#include "tcb.h"
+#include "udp.h"
+#include "raw.h"
+#include "tcpconn.h"
+#include "tcpcfg.h"
+#include <ntddtcp.h>
+#include "secfltr.h"
+
+//
+// Global variables.
+//
+PDRIVER_OBJECT TCPDriverObject = NULL;
+PDEVICE_OBJECT TCPDeviceObject = NULL;
+PDEVICE_OBJECT UDPDeviceObject = NULL;
+PDEVICE_OBJECT RawIPDeviceObject = NULL;
+extern PDEVICE_OBJECT IPDeviceObject;
+
+//
+//Place holder for Maximum duplicate acks we would like
+//to see before we do fast retransmit
+//
+#if FAST_RETRANSMIT
+uint MaxDupAcks;
+#endif
+
+
+#ifdef _PNP_POWER
+
+HANDLE TCPRegistrationHandle;
+HANDLE UDPRegistrationHandle;
+HANDLE IPRegistrationHandle;
+
+#endif
+
+#ifdef SYN_ATTACK
+BOOLEAN SynAttackProtect; //if TRUE, syn-att protection checks
+ // are made
+uint TCPPortsExhausted; //# of ports exhausted
+uint TCPMaxPortsExhausted; //Max # of ports that must be exhausted
+ // for syn-att protection to kick in
+uint TCPMaxPortsExhaustedLW; //Low-watermark of # of ports exhausted
+ //When reached, we revert to normal
+ // count for syn-ack retries
+uint TCPMaxHalfOpen; //Max # of half-open connections allowed
+ // before we dec. the syn-ack retries
+uint TCPMaxHalfOpenRetried; //Max # of half-open conn. that have
+ // been retried at least 1 time
+uint TCPMaxHalfOpenRetriedLW; //Low-watermark of the above. When
+ // go down to it, we revert to normal
+ // # of retries for syn-acks
+uint TCPHalfOpen; //# of half-open connections
+uint TCPHalfOpenRetried; //# of half-open conn. that have been
+ //retried at least once
+#endif
+//
+// External function prototypes
+//
+
+int
+tlinit(
+ void
+ );
+
+NTSTATUS
+TCPDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+TCPDispatchInternalDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+IPDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+IPDriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+NTSTATUS
+GetRegMultiSZValue(
+ HANDLE KeyHandle,
+ PWCHAR ValueName,
+ PUNICODE_STRING ValueData
+ );
+
+PWCHAR
+EnumRegMultiSz(
+ IN PWCHAR MszString,
+ IN ULONG MszStringLength,
+ IN ULONG StringIndex
+ );
+
+//
+// Local funcion prototypes
+//
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+void *
+TLRegisterProtocol(
+ uchar Protocol,
+ void *RcvHandler,
+ void *XmitHandler,
+ void *StatusHandler,
+ void *RcvCmpltHandler
+ );
+
+IP_STATUS
+TLGetIPInfo(
+ IPInfo *Buffer,
+ int Size
+ );
+
+uchar
+TCPGetConfigInfo(
+ void
+ );
+
+NTSTATUS
+TCPInitializeParameter(
+ HANDLE KeyHandle,
+ PWCHAR ValueName,
+ PULONG Value
+ );
+
+#ifdef SECFLTR
+
+uint
+EnumSecurityFilterValue(
+ PNDIS_STRING FilterList,
+ ulong Index,
+ ulong *FilterValue
+ );
+
+#endif // SECFLTR
+
+#ifdef RASAUTODIAL
+VOID
+TCPAcdBind();
+#endif // RASAUTODIAL
+
+
+#ifdef ALLOC_PRAGMA
+
+#pragma alloc_text(INIT, DriverEntry)
+#pragma alloc_text(INIT, TLRegisterProtocol)
+#pragma alloc_text(INIT, TLGetIPInfo)
+#pragma alloc_text(INIT, TCPGetConfigInfo)
+#pragma alloc_text(INIT, TCPInitializeParameter)
+
+#ifdef SECFLTR
+#pragma alloc_text(PAGE, EnumSecurityFilterValue)
+#endif // SECFLTR
+
+#ifdef RASAUTODIAL
+#pragma alloc_text(INIT, TCPAcdBind)
+#endif // RASAUTODIAL
+
+#endif // ALLOC_PRAGMA
+
+
+//
+// Function definitions
+//
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ Initialization routine for the TCP/UDP driver.
+
+Arguments:
+
+ DriverObject - Pointer to the TCP driver object created by the system.
+ DeviceDescription - The name of TCP's node in the registry.
+
+Return Value:
+
+ The final status from the initialization operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ UNICODE_STRING deviceName;
+ USHORT i;
+ int initStatus;
+
+
+#ifdef _PNP_POWER
+ TdiInitialize();
+#endif
+
+#ifdef SECFLTR
+ //
+ // IP calls the security filter code, so initialize it first.
+ //
+ InitializeSecurityFilters();
+
+#endif // SECFLTR
+
+ //
+ // Initialize IP
+ //
+ status = IPDriverEntry(DriverObject, RegistryPath);
+
+ if (!NT_SUCCESS(status)) {
+ TCPTRACE(("Tcpip: IP initialization failed, status %lx\n", status));
+ return(status);
+ }
+
+ //
+ // Initialize TCP, UDP, and RawIP
+ //
+ TCPDriverObject = DriverObject;
+
+ //
+ // Create the device objects. IoCreateDevice zeroes the memory
+ // occupied by the object.
+ //
+
+ RtlInitUnicodeString(&deviceName, DD_TCP_DEVICE_NAME);
+
+ status = IoCreateDevice(
+ DriverObject,
+ 0,
+ &deviceName,
+ FILE_DEVICE_NETWORK,
+ 0,
+ FALSE,
+ &TCPDeviceObject
+ );
+
+ if (!NT_SUCCESS(status)) {
+ CTELogEvent(
+ DriverObject,
+ EVENT_TCPIP_CREATE_DEVICE_FAILED,
+ 1,
+ 1,
+ &deviceName.Buffer,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "TCP: Failed to create TCP device object, status %lx\n",
+ status
+ ));
+ goto init_failed;
+ }
+
+ RtlInitUnicodeString(&deviceName, DD_UDP_DEVICE_NAME);
+
+ status = IoCreateDevice(
+ DriverObject,
+ 0,
+ &deviceName,
+ FILE_DEVICE_NETWORK,
+ 0,
+ FALSE,
+ &UDPDeviceObject
+ );
+
+ if (!NT_SUCCESS(status)) {
+ CTELogEvent(
+ DriverObject,
+ EVENT_TCPIP_CREATE_DEVICE_FAILED,
+ 1,
+ 1,
+ &deviceName.Buffer,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "TCP: Failed to create UDP device object, status %lx\n",
+ status
+ ));
+ goto init_failed;
+ }
+
+ RtlInitUnicodeString(&deviceName, DD_RAW_IP_DEVICE_NAME);
+
+ status = IoCreateDevice(
+ DriverObject,
+ 0,
+ &deviceName,
+ FILE_DEVICE_NETWORK,
+ 0,
+ FALSE,
+ &RawIPDeviceObject
+ );
+
+ if (!NT_SUCCESS(status)) {
+ CTELogEvent(
+ DriverObject,
+ EVENT_TCPIP_CREATE_DEVICE_FAILED,
+ 1,
+ 1,
+ &deviceName.Buffer,
+ 0,
+ NULL
+ );
+
+ TCPTRACE((
+ "TCP: Failed to create Raw IP device object, status %lx\n",
+ status
+ ));
+ goto init_failed;
+ }
+
+ //
+ // Initialize the driver object
+ //
+ DriverObject->DriverUnload = NULL;
+ DriverObject->FastIoDispatch = NULL;
+ for (i=0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
+ DriverObject->MajorFunction[i] = TCPDispatch;
+ }
+
+ //
+ // We special case Internal Device Controls because they are the
+ // hot path for kernel-mode clients.
+ //
+ DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
+ TCPDispatchInternalDeviceControl;
+
+ //
+ // Intialize the device objects.
+ //
+ TCPDeviceObject->Flags |= DO_DIRECT_IO;
+ UDPDeviceObject->Flags |= DO_DIRECT_IO;
+ RawIPDeviceObject->Flags |= DO_DIRECT_IO;
+
+ //
+ // Finally, initialize the stack.
+ //
+ initStatus = tlinit();
+
+ if (initStatus == TRUE) {
+#ifdef RASAUTODIAL
+ //
+ // Get the automatic connection driver
+ // entry points.
+ //
+ TCPAcdBind();
+#endif // RASAUTODIAL
+
+
+#ifdef _PNP_POWER
+
+ RtlInitUnicodeString(&deviceName, DD_TCP_DEVICE_NAME);
+ (void)TdiRegisterDeviceObject(&deviceName,&TCPRegistrationHandle);
+
+ RtlInitUnicodeString(&deviceName, DD_UDP_DEVICE_NAME);
+ (void)TdiRegisterDeviceObject(&deviceName,&UDPRegistrationHandle);
+
+ RtlInitUnicodeString(&deviceName, DD_RAW_IP_DEVICE_NAME);
+ (void)TdiRegisterDeviceObject(&deviceName,&IPRegistrationHandle);
+
+#endif
+ return(STATUS_SUCCESS);
+ }
+
+ TCPTRACE((
+ "Tcpip: TCP/UDP initialization failed, but IP will be available.\n"
+ ));
+
+ CTELogEvent(
+ DriverObject,
+ EVENT_TCPIP_TCP_INIT_FAILED,
+ 1,
+ 0,
+ NULL,
+ 0,
+ NULL
+ );
+ status = STATUS_UNSUCCESSFUL;
+
+
+init_failed:
+
+ //
+ // IP has successfully started, but TCP & UDP failed. Set the
+ // Dispatch routine to point to IP only, since the TCP and UDP
+ // devices don't exist.
+ //
+
+ if (TCPDeviceObject != NULL) {
+ IoDeleteDevice(TCPDeviceObject);
+ }
+
+ if (UDPDeviceObject != NULL) {
+ IoDeleteDevice(UDPDeviceObject);
+ }
+
+ if (RawIPDeviceObject != NULL) {
+ IoDeleteDevice(RawIPDeviceObject);
+ }
+
+ for (i=0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
+ DriverObject->MajorFunction[i] = IPDispatch;
+ }
+
+ return(STATUS_SUCCESS);
+}
+
+
+IP_STATUS
+TLGetIPInfo(
+ IPInfo *Buffer,
+ int Size
+ )
+
+/*++
+
+Routine Description:
+
+ Returns information necessary for TCP to call into IP.
+
+Arguments:
+
+ Buffer - A pointer to the IP information structure.
+
+ Size - The size of Buffer.
+
+Return Value:
+
+ The IP status of the operation.
+
+--*/
+
+{
+ return(IPGetInfo(Buffer, Size));
+}
+
+
+void *
+TLRegisterProtocol(
+ uchar Protocol,
+ void *RcvHandler,
+ void *XmitHandler,
+ void *StatusHandler,
+ void *RcvCmpltHandler
+ )
+
+/*++
+
+Routine Description:
+
+ Calls the IP driver's protocol registration function.
+
+Arguments:
+
+ Protocol - The protocol number to register.
+
+ RcvHandler - Transport's packet receive handler.
+
+ XmitHandler - Transport's packet transmit complete handler.
+
+ StatusHandler - Transport's status update handler.
+
+ RcvCmpltHandler - Transport's receive complete handler
+
+Return Value:
+
+ A context value for the protocol to pass to IP when transmitting.
+
+--*/
+
+{
+ return(IPRegisterProtocol(
+ Protocol,
+ RcvHandler,
+ XmitHandler,
+ StatusHandler,
+ RcvCmpltHandler
+ )
+ );
+}
+
+
+//
+// Interval in milliseconds between keepalive transmissions until a
+// response is received.
+//
+#define DEFAULT_KEEPALIVE_INTERVAL 1000
+
+//
+// time to first keepalive transmission. 2 hours == 7,200,000 milliseconds
+//
+#define DEFAULT_KEEPALIVE_TIME 7200000
+
+#ifdef SYN_ATTACK
+#define MIN_THRESHOLD_MAX_HO 100
+#define MIN_THRESHOLD_MAX_HO_RETRIED 80
+#endif
+
+uchar
+TCPGetConfigInfo(
+ void
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes TCP global configuration parameters.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Zero on failure, nonzero on success.
+
+--*/
+
+{
+ HANDLE keyHandle;
+ NTSTATUS status;
+ OBJECT_ATTRIBUTES objectAttributes;
+ UNICODE_STRING UKeyName;
+ ULONG maxConnectRexmits = 0;
+ ULONG maxConnectResponseRexmits = 0;
+ ULONG maxDataRexmits = 0;
+ ULONG pptpmaxDataRexmits = 0;
+ ULONG useRFC1122UrgentPointer = 0;
+ BOOLEAN AsSystem;
+
+
+ //
+ // Initialize to the defaults in case an error occurs somewhere.
+ //
+ KAInterval = DEFAULT_KEEPALIVE_INTERVAL;
+ KeepAliveTime = DEFAULT_KEEPALIVE_TIME;
+ PMTUDiscovery = TRUE;
+ PMTUBHDetect = FALSE;
+ DeadGWDetect = TRUE;
+ DefaultRcvWin = 0; // Automagically pick a reasonable one.
+ MaxConnections = DEFAULT_MAX_CONNECTIONS;
+ maxConnectRexmits = MAX_CONNECT_REXMIT_CNT;
+ maxConnectResponseRexmits = MAX_CONNECT_RESPONSE_REXMIT_CNT;
+ pptpmaxDataRexmits = maxDataRexmits = MAX_REXMIT_CNT;
+ BSDUrgent = TRUE;
+ FinWait2TO = FIN_WAIT2_TO;
+ NTWMaxConnectCount = NTW_MAX_CONNECT_COUNT;
+ NTWMaxConnectTime = NTW_MAX_CONNECT_TIME;
+ MaxUserPort = MAX_USER_PORT;
+
+
+#if FAST_RETRANSMIT
+// Default number of duplicate acks
+ MaxDupAcks = 2;
+#endif
+
+
+#ifdef SYN_ATTACK
+ SynAttackProtect = FALSE; //by default it is always off
+ if (MmIsThisAnNtAsSystem()) {
+ TCPMaxPortsExhausted = 5;
+ TCPMaxHalfOpen = 100;
+ TCPMaxHalfOpenRetried = 80;
+ }
+ else {
+ TCPMaxPortsExhausted = 5;
+ TCPMaxHalfOpen = 500;
+ TCPMaxHalfOpenRetried = 400;
+ }
+#endif
+
+#ifdef SECFLTR
+ SecurityFilteringEnabled = FALSE;
+#endif // SECFLTR
+
+
+ //
+ // Read the TCP optional (hidden) registry parameters.
+ //
+ RtlInitUnicodeString(
+ &UKeyName,
+ L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Parameters"
+ );
+
+ memset(&objectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
+
+ InitializeObjectAttributes(
+ &objectAttributes,
+ &UKeyName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+ status = ZwOpenKey(
+ &keyHandle,
+ KEY_READ,
+ &objectAttributes
+ );
+
+ if (NT_SUCCESS(status)) {
+
+ TCPInitializeParameter(
+ keyHandle,
+ L"KeepAliveInterval",
+ &KAInterval
+ );
+
+ TCPInitializeParameter(
+ keyHandle,
+ L"KeepAliveTime",
+ &KeepAliveTime
+ );
+
+ TCPInitializeParameter(
+ keyHandle,
+ L"EnablePMTUBHDetect",
+ &PMTUBHDetect
+ );
+
+ TCPInitializeParameter(
+ keyHandle,
+ L"TcpWindowSize",
+ &DefaultRcvWin
+ );
+
+ TCPInitializeParameter(
+ keyHandle,
+ L"TcpNumConnections",
+ &MaxConnections
+ );
+
+ TCPInitializeParameter(
+ keyHandle,
+ L"TcpMaxConnectRetransmissions",
+ &maxConnectRexmits
+ );
+
+ if (maxConnectRexmits > 255) {
+ maxConnectRexmits = 255;
+ }
+
+ TCPInitializeParameter(
+ keyHandle,
+ L"TcpMaxConnectResponseRetransmissions",
+ &maxConnectResponseRexmits
+ );
+
+ if (maxConnectResponseRexmits > 255) {
+ maxConnectResponseRexmits = 255;
+ }
+
+ TCPInitializeParameter(
+ keyHandle,
+ L"TcpMaxDataRetransmissions",
+ &maxDataRexmits
+ );
+
+ if (maxDataRexmits > 255) {
+ maxDataRexmits = 255;
+ }
+
+
+#if FAST_RETRANSMIT
+ // Limit the MaxDupAcks to 3
+
+ TCPInitializeParameter(
+ keyHandle,
+ L"TcpMaxDupAcks",
+ &MaxDupAcks
+ );
+
+ if (MaxDupAcks > 3) {
+ MaxDupAcks = 3;
+ }
+ if (MaxDupAcks < 0) {
+ MaxDupAcks = 1;
+ }
+#endif
+
+
+
+#ifdef SYN_ATTACK
+
+ TCPInitializeParameter(
+ keyHandle,
+ L"SynAttackProtect",
+ (unsigned long *)&SynAttackProtect
+ );
+
+
+ if (SynAttackProtect) {
+
+ //
+ // We don't want syn-attack protection to kick in if the user
+ // has set the MaxConnectResponseRetransmissions to lower than
+ // a certain threshold.
+ //
+ if (maxConnectResponseRexmits >= MAX_CONNECT_RESPONSE_REXMIT_CNT){
+
+ TCPInitializeParameter(
+ keyHandle,
+ L"TCPMaxPortsExhausted",
+ &TCPMaxPortsExhausted
+ );
+
+ TCPMaxPortsExhaustedLW = MAX((TCPMaxPortsExhausted >> 1) + (TCPMaxPortsExhausted >> 2), 1);
+
+ TCPInitializeParameter(
+ keyHandle,
+ L"TCPMaxHalfOpen",
+ &TCPMaxHalfOpen
+ );
+
+ if (TCPMaxHalfOpen < MIN_THRESHOLD_MAX_HO) {
+ TCPMaxHalfOpen = MIN_THRESHOLD_MAX_HO;
+ }
+
+ TCPInitializeParameter(
+ keyHandle,
+ L"TCPMaxHalfOpenRetried",
+ &TCPMaxHalfOpenRetried
+ );
+
+ if (
+ (TCPMaxHalfOpenRetried > TCPMaxHalfOpen) ||
+ (TCPMaxHalfOpenRetried < MIN_THRESHOLD_MAX_HO_RETRIED)
+ )
+
+ {
+ TCPMaxHalfOpenRetried = MIN_THRESHOLD_MAX_HO_RETRIED;
+ }
+
+ TCPMaxHalfOpenRetriedLW = (TCPMaxHalfOpenRetried >> 1) +
+ (TCPMaxHalfOpenRetried >> 2);
+ }
+ else {
+ SynAttackProtect = FALSE;
+ }
+
+ }
+#endif
+
+ //
+ // If we fail, then set to same value as maxDataRexmit so that the
+ // max(pptpmaxDataRexmit,maxDataRexmit) is a decent value
+ // Need this since TCPInitializeParameter no longer "initializes"
+ // to a default value
+ //
+
+ if(TCPInitializeParameter(keyHandle,
+ L"PPTPTcpMaxDataRetransmissions",
+ &pptpmaxDataRexmits) != STATUS_SUCCESS)
+ {
+ pptpmaxDataRexmits = maxDataRexmits;
+ }
+
+ if (pptpmaxDataRexmits > 255) {
+ pptpmaxDataRexmits = 255;
+ }
+
+ TCPInitializeParameter(
+ keyHandle,
+ L"TcpUseRFC1122UrgentPointer",
+ &useRFC1122UrgentPointer
+ );
+
+ if (useRFC1122UrgentPointer) {
+ BSDUrgent = FALSE;
+ }
+
+ TCPInitializeParameter(
+ keyHandle,
+ L"TcpTimedWaitDelay",
+ &FinWait2TO
+ );
+
+ if (FinWait2TO < 30) {
+ FinWait2TO = 30;
+ }
+ if (FinWait2TO > 300) {
+ FinWait2TO = 300;
+ }
+ FinWait2TO = MS_TO_TICKS(FinWait2TO*1000);
+
+ NTWMaxConnectTime = MS_TO_TICKS(NTWMaxConnectTime*1000);
+
+ TCPInitializeParameter(
+ keyHandle,
+ L"MaxUserPort",
+ &MaxUserPort
+ );
+
+ if (MaxUserPort < 5000) {
+ MaxUserPort = 5000;
+ }
+ if (MaxUserPort > 65534) {
+ MaxUserPort = 65534;
+ }
+
+ //
+ // Read a few IP optional (hidden) registry parameters that TCP
+ // cares about.
+ //
+ TCPInitializeParameter(
+ keyHandle,
+ L"EnablePMTUDiscovery",
+ &PMTUDiscovery
+ );
+
+ TCPInitializeParameter(
+ keyHandle,
+ L"EnableDeadGWDetect",
+ &DeadGWDetect
+ );
+
+#ifdef SECFLTR
+ TCPInitializeParameter(
+ keyHandle,
+ L"EnableSecurityFilters",
+ &SecurityFilteringEnabled
+ );
+#endif // SECFLTR
+
+ ZwClose(keyHandle);
+ }
+
+ MaxConnectRexmitCount = maxConnectRexmits;
+ MaxConnectResponseRexmitCount = maxConnectResponseRexmits;
+#ifdef SYN_ATTACK
+ MaxConnectResponseRexmitCountTmp = MaxConnectResponseRexmitCount;
+#endif
+
+ //
+ // Use the greater of the two, hence both values should be valid
+ //
+
+ MaxDataRexmitCount = (maxDataRexmits > pptpmaxDataRexmits ? maxDataRexmits : pptpmaxDataRexmits) ;
+
+ return(1);
+}
+
+
+#define WORK_BUFFER_SIZE 256
+
+NTSTATUS
+TCPInitializeParameter(
+ HANDLE KeyHandle,
+ PWCHAR ValueName,
+ PULONG Value
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes a ULONG parameter from the registry or to a default
+ parameter if accessing the registry value fails.
+
+Arguments:
+
+ KeyHandle - An open handle to the registry key for the parameter.
+ ValueName - The UNICODE name of the registry value to read.
+ Value - The ULONG into which to put the data.
+ DefaultValue - The default to assign if reading the registry fails.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NTSTATUS status;
+ ULONG resultLength;
+ PKEY_VALUE_FULL_INFORMATION keyValueFullInformation;
+ UCHAR keybuf[WORK_BUFFER_SIZE];
+ UNICODE_STRING UValueName;
+
+
+ RtlInitUnicodeString(&UValueName, ValueName);
+
+ keyValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)keybuf;
+ RtlZeroMemory(keyValueFullInformation, sizeof(keyValueFullInformation));
+
+ status = ZwQueryValueKey(
+ KeyHandle,
+ &UValueName,
+ KeyValueFullInformation,
+ keyValueFullInformation,
+ WORK_BUFFER_SIZE,
+ &resultLength
+ );
+
+ if (status == STATUS_SUCCESS) {
+ if (keyValueFullInformation->Type == REG_DWORD) {
+ *Value = *((ULONG UNALIGNED *) ((PCHAR)keyValueFullInformation +
+ keyValueFullInformation->DataOffset));
+ }
+ }
+
+ return(status);
+}
+
+
+#ifdef SECFLTR
+
+TDI_STATUS
+GetSecurityFilterList(
+ NDIS_HANDLE ConfigHandle,
+ ulong Protocol,
+ PNDIS_STRING FilterList
+ )
+{
+ PWCHAR parameterName;
+ TDI_STATUS status;
+
+
+ if (Protocol == PROTOCOL_TCP) {
+ parameterName = L"TcpAllowedPorts";
+ }
+ else if (Protocol == PROTOCOL_UDP) {
+ parameterName = L"UdpAllowedPorts";
+ }
+ else {
+ parameterName = L"RawIpAllowedProtocols";
+ }
+
+ status = GetRegMultiSZValue(
+ ConfigHandle,
+ parameterName,
+ FilterList
+ );
+
+ if (!NT_SUCCESS(status)) {
+ FilterList->Length = 0;
+ }
+
+ return(status);
+}
+
+
+uint
+EnumSecurityFilterValue(
+ PNDIS_STRING FilterList,
+ ulong Index,
+ ulong *FilterValue
+ )
+{
+ PWCHAR valueString;
+ UNICODE_STRING unicodeString;
+ NTSTATUS status;
+
+
+ PAGED_CODE();
+
+
+ valueString = EnumRegMultiSz(
+ FilterList->Buffer,
+ FilterList->Length,
+ Index
+ );
+
+ if ((valueString == NULL) || (valueString[0] == UNICODE_NULL)) {
+ return(FALSE);
+ }
+
+ RtlInitUnicodeString(&unicodeString, valueString);
+
+ status = RtlUnicodeStringToInteger(&unicodeString, 0, FilterValue);
+
+ if (!(NT_SUCCESS(status))) {
+ TCPTRACE(("TCP: Invalid filter value %ws\n", valueString));
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+#endif // SECFLTR
diff --git a/private/ntos/tdi/tcpip/tcp/ppc/sources b/private/ntos/tdi/tcpip/tcp/ppc/sources
new file mode 100644
index 000000000..3fd3f6b3b
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/ppc/sources
@@ -0,0 +1,4 @@
+PPC_SOURCES= \
+ ..\ppc\xsum.s
+
+
diff --git a/private/ntos/tdi/tcpip/tcp/ppc/xsum.s b/private/ntos/tdi/tcpip/tcp/ppc/xsum.s
new file mode 100644
index 000000000..831ef6b53
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/ppc/xsum.s
@@ -0,0 +1,257 @@
+// TITLE("Compute Checksum")
+//++
+//
+// Copyright (c) 1994 IBM Corporation
+//
+// Module Name:
+//
+// xsum.s
+//
+// Abstract:
+//
+// This module implement a function to compute the checksum of a buffer.
+//
+// Author:
+//
+// David N. Cutler (davec) 27-Jan-1992
+//
+// Environment:
+//
+// User mode.
+//
+// Revision History:
+//
+// Michael W. Thomas 02/14/94 Converted from MIPS
+// Peter L. Johnston 07/19/94 Updated for Daytona Lvl 734 and
+// optimized for PowerPC.
+//
+//--
+
+#include "ksppc.h"
+
+ SBTTL("Compute Checksum")
+//++
+//
+// ULONG
+// tcpxsum (
+// IN ULONG Checksum,
+// IN PUCHAR Source,
+// IN ULONG Length
+// )
+//
+// Routine Description:
+//
+// This function computes the checksum of the specified buffer.
+//
+// N.B. The checksum is the 16 bit checksum of the 16 bit aligned
+// buffer. If the buffer is not 16 bit aligned the first byte is
+// moved to high order position to be added to the correct half.
+//
+// Arguments:
+//
+// Checksum (r3) - Supplies the initial checksum value.
+//
+// Source (r4) - Supplies a pointer to the checksum buffer.
+//
+// Length (r5) - Supplies the length of the buffer in bytes.
+//
+// Return Value:
+//
+// The computed checksum is returned as the function value.
+//
+//--
+
+ LEAF_ENTRY(tcpxsum)
+
+ cmpwi r.5, 0 // check if bytes to checksum
+ mtcrf 0x01, r.4 // set up for alignment check
+ li r.6, 0 // initialize partial checksum
+ beqlr- // return if no bytes to checksum
+
+ andi. r.7, r.5, 1 // check if length is even
+ crmove 7, 31 // remember original alignment
+ bf 31, evenalign // jif 16 bit aligned
+
+//
+// Initialize the checksum to the first byte shifted up a byte.
+//
+ lbz r.6, 0(r.4) // get first byte of buffer
+ subi r.5, r.5, 1 // reduce count of bytes to checksum
+ cmpwi cr.6, r.5, 0 // check if done
+ crnot eq, eq // invert odd/even length check
+ addi r.4, r.4, 1 // advance buffer address
+ mtcrf 0x01, r.4 // reset 32 bit alignment check
+ slwi r.6, r.6, 8 // shift byte up in computed checksum
+ // max current checksum is 0x0ff00
+ beq cr.6, combine // jif no more bytes to checksum
+
+evenalign:
+
+//
+// Check if the length of the buffer is an even number of bytes.
+//
+// If the buffer is not an even number of bytes, add the last byte to the
+// computed checksum.
+//
+
+ beq evenlength
+ subic. r.5, r.5, 1 // reduce count of bytes to checksum
+ lbzx r.7, r.4, r.5 // get last byte from buffer
+ add r.6, r.6, r.7 // add last byte to computed checksum
+ // max current checksum is 0x0ffff
+ beq combine // jif no more bytes in buffer
+
+evenlength:
+
+//
+// Check if we are 4 byte aligned, if not add first 2 byte word into
+// checksum so the buffer is then 4 byte aligned.
+//
+
+ bf 30, fourbytealigned // jif 4 byte aligned
+
+ lhz r.7, 0(r.4) // get 2 byte word
+ subic. r.5, r.5, 2 // reduce length
+ addi r.4, r.4, 2 // bump address
+ add r.6, r.6, r.7 // add 2 bytes to computed checksum
+ // max current checksum is 0x1fffe
+ beq combine // jif no more bytes to checksum
+
+//
+// Attempt to sum the remainder of the buffer in sets of 32 bytes. This
+// should achieve 2 bytes per clock on 601 and 603, and 3.2 bytes per clock
+// on 604. (A seperate implementation will be required to take advantage
+// of 64 bit loads on the 620).
+//
+
+fourbytealigned:
+
+ srwi. r.7, r.5, 5 // get count of 32 byte sets
+ mtcrf 0x03, r.5 // break length into block for
+ // various run lengths.
+ subi r.4, r.4, 4 // adjust buffer address for lwzu
+ mtctr r.7
+ addic r.6, r.6, 0 // clear carry bit
+ beq try16 // jif no 32 byte sets
+
+do32: lwz r.8, 4(r.4) // get 1st 4 bytes in set
+ lwz r.9, 8(r.4) // get 2nd 4
+ adde r.6, r.6, r.8 // add 1st 4 to checksum
+ lwz r.10, 12(r.4) // get 3rd 4
+ adde r.6, r.6, r.9 // add 2nd 4
+ lwz r.11, 16(r.4) // get 4th 4
+ adde r.6, r.6, r.10 // add 3rd 4
+ lwz r.8, 20(r.4) // get 5th 4
+ adde r.6, r.6, r.11 // add 4th 4
+ lwz r.9, 24(r.4) // get 6th 4
+ adde r.6, r.6, r.8 // add 5th 4
+ lwz r.10, 28(r.4) // get 7th 4
+ adde r.6, r.6, r.9 // add 6th 4
+ lwzu r.11, 32(r.4) // get 8th 4 and update address
+ adde r.6, r.6, r.10 // add 7th 4
+ adde r.6, r.6, r.11 // add 8th 4
+ bdnz do32
+
+try16: bf 27, try8 // jif no 16 byte block
+
+ lwz r.8, 4(r.4) // get 1st 4
+ lwz r.9, 8(r.4) // get 2nd 4
+ adde r.6, r.6, r.8 // add 1st 4
+ lwz r.10, 12(r.4) // get 3rd 4
+ adde r.6, r.6, r.9 // add 2nd 4
+ lwzu r.11, 16(r.4) // get 4th 4 and update address
+ adde r.6, r.6, r.10 // add 3rd 4
+ adde r.6, r.6, r.11 // add 4th 4
+
+try8: bf 28, try4 // jif no 8 byte block
+ lwz r.8, 4(r.4) // get 1st 4
+ lwzu r.9, 8(r.4) // get 2nd 4 and update address
+ adde r.6, r.6, r.8 // add 1st 4
+ adde r.6, r.6, r.9 // add 2nd 4
+
+try4: bf 29, try2 // jif no 4 byte block
+ lwzu r.8, 4(r.4) // get 4 bytes and update address
+ adde r.6, r.6, r.8
+
+try2: bf 30, fold // jif no 2 byte block
+
+//
+// At this point, r.4 is pointing at the last 4 byte block processed (or
+// not processed if there were no 4 byte blocks). We need to add when we
+// pull the last two bytes.
+//
+ lhz r.8, 4(r.4) // get last two bytes
+ adde r.6, r.6, r.8 // add last two bytes
+
+//
+// Collapse 33 bit (1 carry bit, 32 bits in r.6) into 17 bit checksum.
+//
+
+fold: rlwinm r.7, r.6, 16, 0xffff // get 16 most significant bits (upper)
+ rlwinm r.6, r.6, 0, 0xffff // get least significant 16 bits (lower)
+ adde r.6, r.6, r.7 // upper + lower + carry
+ // max current checksum is 0x1ffff
+
+//
+// Combine input checksum and partial checksum.
+//
+// If the input buffer was byte aligned, then word swap bytes in computed
+// checksum before combination with input chewcksum.
+//
+
+combine:
+
+ bf 7, waseven // jif original alignment was 16 bit
+
+//
+// Swap bytes within upper and lower halves.
+// eg: AA BB CC DD becomes BB AA DD CC
+//
+// As the current maximum partial checksum is 0x1ffff don't worry about AA.
+// ie: want BB 00 DD CC
+//
+
+ rlwimi r.6, r.6, 16, 0xff000000// r.7 = CC BB CC DD
+ rlwinm r.6, r.6, 8, 0xff00ffff// r.7 = BB 00 DD CC
+
+waseven:
+
+ add r.3, r.3, r.6 // combine checksums
+ // max current checksum is 0x101fffe
+ rotlwi r.4, r.3, 16 // swap checksum words
+ add r.3, r.3, r.4 // add words with carry into high word
+ srwi r.3, r.3, 16 // extract final checksum
+
+ LEAF_EXIT(tcpxsum)
+
+ .debug$S
+ .ualong 1
+
+ .uashort 15
+ .uashort 0x9 # S_OBJNAME
+ .ualong 0
+ .byte 8, "xsum.obj"
+
+ .uashort 24
+ .uashort 0x1 # S_COMPILE
+ .byte 0x42 # Target processor = PPC 604
+ .byte 3 # Language = ASM
+ .byte 0
+ .byte 0
+ .byte 17, "PowerPC Assembler"
+
+ .uashort 43
+ .uashort 0x205 # S_GPROC32
+ .ualong 0
+ .ualong 0
+ .ualong 0
+ .ualong tcpxsum.end-..tcpxsum
+ .ualong 0
+ .ualong tcpxsum.end-..tcpxsum
+ .ualong [secoff]..tcpxsum
+ .uashort [secnum]..tcpxsum
+ .uashort 0x1000
+ .byte 0x00
+ .byte 7, "tcpxsum"
+
+ .uashort 2, 0x6 # S_END
diff --git a/private/ntos/tdi/tcpip/tcp/raw.c b/private/ntos/tdi/tcpip/tcp/raw.c
new file mode 100644
index 000000000..6b59f9dd1
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/raw.c
@@ -0,0 +1,693 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** RAW.C - Raw IP interface code.
+//
+// This file contains the code for the Raw IP interface functions,
+// principally send and receive datagram.
+//
+
+#include "oscfg.h"
+#include "ndis.h"
+#include "cxport.h"
+#include "ip.h"
+#include "tdi.h"
+#include "tdistat.h"
+#ifdef VXD
+#include "tdivxd.h"
+#endif
+#ifdef NT
+#include "tdint.h"
+#include "tdistat.h"
+#endif
+#include "queue.h"
+#include "addr.h"
+#include "raw.h"
+#include "tlcommon.h"
+#include "info.h"
+#include "tcpcfg.h"
+#include "secfltr.h"
+
+
+#define NO_TCP_DEFS 1
+#include "tcpdeb.h"
+
+
+#ifdef NT
+
+#ifdef POOL_TAGGING
+
+#ifdef ExAllocatePool
+#undef ExAllocatePool
+#endif
+
+#define ExAllocatePool(type, size) ExAllocatePoolWithTag(type, size, 'rPCT')
+
+#ifndef CTEAllocMem
+#error "CTEAllocMem is not already defined - will override tagging"
+#else
+#undef CTEAllocMem
+#endif
+
+#define CTEAllocMem(size) ExAllocatePoolWithTag(NonPagedPool, size, 'rPCT')
+
+#endif // POOL_TAGGING
+
+#endif // NT
+
+EXTERNAL_LOCK(AddrObjTableLock)
+
+void *RawProtInfo = NULL;
+
+extern IPInfo LocalNetInfo;
+
+#ifdef CHICAGO
+extern uchar TransportName[];
+#endif
+
+#ifdef CHICAGO
+extern int RegisterAddrChangeHndlr(void *Handler, uint Add);
+extern void AddrChange(IPAddr Addr, IPMask Mask, void *Context,
+ uint Added);
+#endif
+
+
+
+//** RawSend - Send a datagram.
+//
+// The real send datagram routine. We assume that the busy bit is
+// set on the input AddrObj, and that the address of the SendReq
+// has been verified.
+//
+// We start by sending the input datagram, and we loop until there's
+// nothing left on the send q.
+//
+// Input: SrcAO - Pointer to AddrObj doing the send.
+// SendReq - Pointer to sendreq describing send.
+//
+// Returns: Nothing
+//
+void
+RawSend(AddrObj *SrcAO, DGSendReq *SendReq)
+{
+ PNDIS_BUFFER RawBuffer;
+ CTELockHandle HeaderHandle, AOHandle;
+ RouteCacheEntry *RCE; // RCE used for each send.
+ IPAddr SrcAddr; // Source address IP thinks we should
+ // use.
+ uchar DestType; // Type of destination address.
+ IP_STATUS SendStatus; // Status of send attempt.
+ ushort MSS;
+ uint AddrValid;
+ IPOptInfo *OptInfo;
+ IPAddr OrigSrc;
+ uchar protocol;
+
+
+ CTEStructAssert(SrcAO, ao);
+ CTEAssert(SrcAO->ao_usecnt != 0);
+
+ protocol = SrcAO->ao_prot;
+
+ IF_TCPDBG(TCP_DEBUG_RAW) {
+ TCPTRACE((
+ "RawSend called, prot %u\n", protocol
+ ));
+ }
+
+ //* Loop while we have something to send, and can get
+ // resources to send.
+ for (;;) {
+
+ CTEStructAssert(SendReq, dsr);
+
+ // Make sure we have a Raw header buffer for this send. If we
+ // don't, try to get one.
+ if ((RawBuffer = SendReq->dsr_header) == NULL) {
+ // Don't have one, so try to get one.
+ CTEGetLock(&DGSendReqLock, &HeaderHandle);
+ RawBuffer = GetDGHeader();
+ if (RawBuffer != NULL)
+ SendReq->dsr_header = RawBuffer;
+ else {
+ // Couldn't get a header buffer. Push the send request
+ // back on the queue, and queue the addr object for when
+ // we get resources.
+ CTEGetLock(&SrcAO->ao_lock, &AOHandle);
+ PUSHQ(&SrcAO->ao_sendq, &SendReq->dsr_q);
+ PutPendingQ(SrcAO);
+ CTEFreeLock(&SrcAO->ao_lock, AOHandle);
+ CTEFreeLock(&DGSendReqLock, HeaderHandle);
+ return;
+ }
+ CTEFreeLock(&DGSendReqLock, HeaderHandle);
+ }
+
+ // At this point, we have the buffer we need. Call IP to get an
+ // RCE (along with the source address if we need it), then
+ // send the data.
+ CTEAssert(RawBuffer != NULL);
+
+ if (!CLASSD_ADDR(SendReq->dsr_addr)) {
+ // This isn't a multicast send, so we'll use the ordinary
+ // information.
+ OrigSrc = SrcAO->ao_addr;
+ OptInfo = &SrcAO->ao_opt;
+ } else {
+ OrigSrc = SrcAO->ao_mcastaddr;
+ OptInfo = &SrcAO->ao_mcastopt;
+ }
+
+ CTEAssert(!(SrcAO->ao_flags & AO_DHCP_FLAG));
+
+ SrcAddr = (*LocalNetInfo.ipi_openrce)(SendReq->dsr_addr,
+ OrigSrc, &RCE, &DestType, &MSS, OptInfo);
+
+ AddrValid = !IP_ADDR_EQUAL(SrcAddr, NULL_IP_ADDR);
+
+ if (AddrValid) {
+ // The OpenRCE worked. Send it.
+
+ if (!IP_ADDR_EQUAL(OrigSrc, NULL_IP_ADDR))
+ SrcAddr = OrigSrc;
+
+ NdisBufferLength(RawBuffer) = 0;
+ NDIS_BUFFER_LINKAGE(RawBuffer) = SendReq->dsr_buffer;
+
+ // Now send the packet.
+ IF_TCPDBG(TCP_DEBUG_RAW) {
+ TCPTRACE(("RawSend transmitting\n"));
+ }
+
+ UStats.us_outdatagrams++;
+ SendStatus = (*LocalNetInfo.ipi_xmit)(RawProtInfo, SendReq,
+ RawBuffer, (uint)SendReq->dsr_size, SendReq->dsr_addr, SrcAddr,
+ OptInfo, RCE, protocol);
+
+ (*LocalNetInfo.ipi_closerce)(RCE);
+
+ // If it completed immediately, give it back to the user.
+ // Otherwise we'll complete it when the SendComplete happens.
+ // Currently, we don't map the error code from this call - we
+ // might need to in the future.
+ if (SendStatus != IP_PENDING)
+ DGSendComplete(SendReq, RawBuffer);
+
+ } else {
+ TDI_STATUS Status;
+
+ if (DestType == DEST_INVALID)
+ Status = TDI_BAD_ADDR;
+ else
+ Status = TDI_DEST_UNREACHABLE;
+
+ // Complete the request with an error.
+ (*SendReq->dsr_rtn)(SendReq->dsr_context, Status, 0);
+ // Now free the request.
+ SendReq->dsr_rtn = NULL;
+ DGSendComplete(SendReq, RawBuffer);
+ }
+
+ CTEGetLock(&SrcAO->ao_lock, &AOHandle);
+
+ if (!EMPTYQ(&SrcAO->ao_sendq)) {
+ DEQUEUE(&SrcAO->ao_sendq, SendReq, DGSendReq, dsr_q);
+ CTEFreeLock(&SrcAO->ao_lock, AOHandle);
+ } else {
+ CLEAR_AO_REQUEST(SrcAO, AO_SEND);
+ CTEFreeLock(&SrcAO->ao_lock, AOHandle);
+ return;
+ }
+
+ }
+}
+
+
+//* RawDeliver - Deliver a datagram to a user.
+//
+// This routine delivers a datagram to a Raw user. We're called with
+// the AddrObj to deliver on, and with the AddrObjTable lock held.
+// We try to find a receive on the specified AddrObj, and if we do
+// we remove it and copy the data into the buffer. Otherwise we'll
+// call the receive datagram event handler, if there is one. If that
+// fails we'll discard the datagram.
+//
+// Input: RcvAO - AO to receive the datagram.
+// SrcIP - Source IP address of datagram.
+// IPH - IP Header
+// IPHLength - Bytes in IPH.
+// RcvBuf - The IPReceive buffer containing the data.
+// RcvSize - Size received, including the Raw header.
+// TableHandle - Lock handle for AddrObj table.
+//
+// Returns: Nothing.
+//
+void
+RawDeliver(AddrObj *RcvAO, IPAddr SrcIP, IPHeader UNALIGNED *IPH,
+ uint IPHLength, IPRcvBuf *RcvBuf, uint RcvSize, IPOptInfo *OptInfo,
+ CTELockHandle TableHandle)
+{
+ Queue *CurrentQ;
+ CTELockHandle AOHandle;
+ DGRcvReq *RcvReq;
+ uint BytesTaken = 0;
+ uchar AddressBuffer[TCP_TA_SIZE];
+ uint RcvdSize;
+ EventRcvBuffer *ERB = NULL;
+
+ CTEStructAssert(RcvAO, ao);
+
+ CTEGetLock(&RcvAO->ao_lock, &AOHandle);
+ CTEFreeLock(&AddrObjTableLock, AOHandle);
+
+ if (AO_VALID(RcvAO)) {
+
+ IF_TCPDBG(TCP_DEBUG_RAW) {
+ TCPTRACE((
+ "Raw delivering %u byte header + %u data bytes to AO %lx\n",
+ IPHLength, RcvSize, RcvAO
+ ));
+ }
+
+ CurrentQ = QHEAD(&RcvAO->ao_rcvq);
+
+ // Walk the list, looking for a receive buffer that matches.
+ while (CurrentQ != QEND(&RcvAO->ao_rcvq)) {
+ RcvReq = QSTRUCT(DGRcvReq, CurrentQ, drr_q);
+
+ CTEStructAssert(RcvReq, drr);
+
+ // If this request is a wildcard request, or matches the source IP
+ // address, deliver it.
+
+ if (IP_ADDR_EQUAL(RcvReq->drr_addr, NULL_IP_ADDR) ||
+ IP_ADDR_EQUAL(RcvReq->drr_addr, SrcIP)) {
+
+ TDI_STATUS Status;
+ PNDIS_BUFFER DestBuf = RcvReq->drr_buffer;
+ uint DestOffset = 0;
+
+
+ // Remove this from the queue.
+ REMOVEQ(&RcvReq->drr_q);
+
+ // We're done. We can free the AddrObj lock now.
+ CTEFreeLock(&RcvAO->ao_lock, TableHandle);
+
+ IF_TCPDBG(TCP_DEBUG_RAW) {
+ TCPTRACE(("Copying to posted receive\n"));
+ }
+
+ // Copy the header
+ DestBuf = CopyFlatToNdis(DestBuf, (uchar *)IPH, IPHLength,
+ &DestOffset, &RcvdSize);
+
+ // Copy the data and then complete the request.
+ RcvdSize += CopyRcvToNdis(RcvBuf, DestBuf,
+ RcvSize, 0, DestOffset);
+
+ CTEAssert(RcvdSize <= RcvReq->drr_size);
+
+ IF_TCPDBG(TCP_DEBUG_RAW) {
+ TCPTRACE(("Copied %u bytes\n", RcvdSize));
+ }
+
+ Status = UpdateConnInfo(RcvReq->drr_conninfo, OptInfo,
+ SrcIP, 0);
+
+ UStats.us_indatagrams++;
+
+ (*RcvReq->drr_rtn)(RcvReq->drr_context, Status, RcvdSize);
+
+ FreeDGRcvReq(RcvReq);
+
+ return;
+
+ }
+
+ // Either the IP address or the port didn't match. Get the next
+ // one.
+ CurrentQ = QNEXT(CurrentQ);
+ }
+
+ // We've walked the list, and not found a buffer. Call the recv.
+ // handler now.
+
+ if (RcvAO->ao_rcvdg != NULL) {
+ PRcvDGEvent RcvEvent = RcvAO->ao_rcvdg;
+ PVOID RcvContext = RcvAO->ao_rcvdgcontext;
+ TDI_STATUS RcvStatus;
+ CTELockHandle OldLevel;
+ uint IndicateSize;
+ uint DestOffset;
+ PNDIS_BUFFER DestBuf;
+
+
+
+ REF_AO(RcvAO);
+ CTEFreeLock(&RcvAO->ao_lock, TableHandle);
+
+ BuildTDIAddress(AddressBuffer, SrcIP, 0);
+
+ IndicateSize = IPHLength;
+
+ if (((uchar *)IPH + IPHLength) == RcvBuf->ipr_buffer) {
+ //
+ // The header is contiguous with the data
+ //
+ IndicateSize += RcvBuf->ipr_size;
+
+ IF_TCPDBG(TCP_DEBUG_RAW) {
+ TCPTRACE(("RawRcv: header & data are contiguous\n"));
+ }
+ }
+
+ IF_TCPDBG(TCP_DEBUG_RAW) {
+ TCPTRACE(("Indicating %u bytes\n", IndicateSize));
+ }
+
+ UStats.us_indatagrams++;
+ RcvStatus = (*RcvEvent)(RcvContext, TCP_TA_SIZE,
+ (PTRANSPORT_ADDRESS)AddressBuffer, 0,
+ NULL, TDI_RECEIVE_COPY_LOOKAHEAD,
+ IndicateSize,
+ IPHLength + RcvSize, &BytesTaken,
+ (uchar *)IPH, &ERB);
+
+ if (RcvStatus == TDI_MORE_PROCESSING) {
+ CTEAssert(ERB != NULL);
+
+ // We were passed back a receive buffer. Copy the data in now.
+
+ // He can't have taken more than was in the indicated
+ // buffer, but in debug builds we'll check to make sure.
+
+ CTEAssert(BytesTaken <= RcvBuf->ipr_size);
+
+ IF_TCPDBG(TCP_DEBUG_RAW) {
+ TCPTRACE(("ind took %u bytes\n", BytesTaken));
+ }
+
+#ifdef NT
+ {
+ PIO_STACK_LOCATION IrpSp;
+ PTDI_REQUEST_KERNEL_RECEIVEDG DatagramInformation;
+
+ IrpSp = IoGetCurrentIrpStackLocation(ERB);
+ DatagramInformation = (PTDI_REQUEST_KERNEL_RECEIVEDG)
+ &(IrpSp->Parameters);
+
+ DestBuf = ERB->MdlAddress;
+#else // NT
+ DestBuf = ERB->erb_buffer;
+#endif // NT
+ DestOffset = 0;
+
+ if (BytesTaken < IPHLength) {
+
+ // Copy the rest of the IP header
+ DestBuf = CopyFlatToNdis(
+ DestBuf,
+ (uchar *)IPH + BytesTaken,
+ IPHLength - BytesTaken,
+ &DestOffset,
+ &RcvdSize
+ );
+
+ BytesTaken = 0;
+ }
+ else {
+ BytesTaken -= IPHLength;
+ RcvdSize = 0;
+ }
+
+ // Copy the data
+ RcvdSize += CopyRcvToNdis(
+ RcvBuf,
+ DestBuf,
+ RcvSize - BytesTaken,
+ BytesTaken,
+ DestOffset
+ );
+
+ IF_TCPDBG(TCP_DEBUG_RAW) {
+ TCPTRACE(("Copied %u bytes\n", RcvdSize));
+ }
+
+#ifdef NT
+ //
+ // Update the return address info
+ //
+ RcvStatus = UpdateConnInfo(
+ DatagramInformation->ReturnDatagramInformation,
+ OptInfo, SrcIP, 0);
+
+ //
+ // Complete the IRP.
+ //
+ ERB->IoStatus.Information = RcvdSize;
+ ERB->IoStatus.Status = RcvStatus;
+ IoCompleteRequest(ERB, 2);
+ }
+
+#else // NT
+ //
+ // Call the completion routine.
+ //
+ (*ERB->erb_rtn)(ERB->erb_context, TDI_SUCCESS, RcvdSize);
+
+#endif // NT
+
+ }
+ else {
+ CTEAssert(
+ (RcvStatus == TDI_SUCCESS) ||
+ (RcvStatus == TDI_NOT_ACCEPTED)
+ );
+
+ IF_TCPDBG(TCP_DEBUG_RAW) {
+ TCPTRACE((
+ "Data %s taken\n",
+ (RcvStatus == TDI_SUCCESS) ? "all" : "not"
+ ));
+ }
+
+ CTEAssert(ERB == NULL);
+ }
+
+ DELAY_DEREF_AO(RcvAO);
+
+ return;
+
+ } else
+ UStats.us_inerrors++;
+
+ // When we get here, we didn't have a buffer to put this data into.
+ // Fall through to the return case.
+ } else
+ UStats.us_inerrors++;
+
+ CTEFreeLock(&RcvAO->ao_lock, TableHandle);
+
+}
+
+
+//* RawRcv - Receive a Raw datagram.
+//
+// The routine called by IP when a Raw datagram arrived. We
+// look up the port/local address pair in our address table,
+// and deliver the data to a user if we find one. For broadcast
+// frames we may deliver it to multiple users.
+//
+// Entry: IPContext - IPContext identifying physical i/f that
+// received the data.
+// Dest - IPAddr of destionation.
+// Src - IPAddr of source.
+// LocalAddr - Local address of network which caused this to be
+// received.
+// SrcAddr - Address of local interface which received the packet
+// IPH - IP Header.
+// IPHLength - Bytes in IPH.
+// RcvBuf - Pointer to receive buffer chain containing data.
+// Size - Size in bytes of data received.
+// IsBCast - Boolean indicator of whether or not this came in as
+// a bcast.
+// Protocol - Protocol this came in on - should be Raw.
+// OptInfo - Pointer to info structure for received options.
+//
+// Returns: Status of reception. Anything other than IP_SUCCESS will cause
+// IP to send a 'port unreachable' message.
+//
+IP_STATUS
+RawRcv(void *IPContext, IPAddr Dest, IPAddr Src, IPAddr LocalAddr,
+ IPAddr SrcAddr, IPHeader UNALIGNED *IPH, uint IPHLength, IPRcvBuf *RcvBuf,
+ uint Size, uchar IsBCast, uchar Protocol, IPOptInfo *OptInfo)
+{
+ CTELockHandle AOTableHandle;
+ AddrObj *ReceiveingAO;
+ uchar DType;
+ AOSearchContext Search;
+ IP_STATUS Status = IP_DEST_PROT_UNREACHABLE;
+
+
+ IF_TCPDBG(TCP_DEBUG_RAW) {
+ TCPTRACE(("RawRcv prot %u size %u\n", IPH->iph_protocol, Size));
+ }
+
+ DType = (*LocalNetInfo.ipi_getaddrtype)(Src);
+
+ // The following code relies on DEST_INVALID being a broadcast dest type.
+ // If this is changed the code here needs to change also.
+ if (IS_BCAST_DEST(DType)) {
+ if (!IP_ADDR_EQUAL(Src, NULL_IP_ADDR) || !IsBCast) {
+ UStats.us_inerrors++;
+ return IP_SUCCESS; // Bad src address.
+ }
+ }
+
+ // Get the AddrObjTable lock, and then try to find some AddrObj(s) to give
+ // this to. We deliver to all addr objs registered for the protocol and
+ // address.
+ CTEGetLock(&AddrObjTableLock, &AOTableHandle);
+
+#ifdef SECFLTR
+
+ if ( !SecurityFilteringEnabled ||
+ IsPermittedSecurityFilter(SrcAddr, IPContext, PROTOCOL_RAW, Protocol)
+ )
+ {
+
+#endif // SECFLTR
+
+ ReceiveingAO = GetFirstAddrObj(
+ LocalAddr,
+ 0, // port is zero
+ Protocol,
+ &Search
+ );
+
+ if (ReceiveingAO != NULL) {
+ do {
+ RawDeliver(
+ ReceiveingAO, Src, IPH, IPHLength, RcvBuf, Size,
+ OptInfo, AOTableHandle
+ );
+ CTEGetLock(&AddrObjTableLock, &AOTableHandle);
+ ReceiveingAO = GetNextAddrObj(&Search);
+ } while (ReceiveingAO != NULL);
+ Status = IP_SUCCESS;
+ } else {
+ UStats.us_noports++;
+ }
+
+#ifdef SECFLTR
+
+ }
+#endif SECFLTR
+
+
+ CTEFreeLock(&AddrObjTableLock, AOTableHandle);
+
+ return Status;
+}
+
+
+//* RawStatus - Handle a status indication.
+//
+// This is the Raw status handler, called by IP when a status event
+// occurs. For most of these we do nothing. For certain severe status
+// events we will mark the local address as invalid.
+//
+// Entry: StatusType - Type of status (NET or HW). NET status
+// is usually caused by a received ICMP
+// message. HW status indicate a HW
+// problem.
+// StatusCode - Code identifying IP_STATUS.
+// OrigDest - If this is NET status, the original dest. of
+// DG that triggered it.
+// OrigSrc - " " " " " , the original src.
+// Src - IP address of status originator (could be local
+// or remote).
+// Param - Additional information for status - i.e. the
+// param field of an ICMP message.
+// Data - Data pertaining to status - for NET status, this
+// is the first 8 bytes of the original DG.
+//
+// Returns: Nothing
+//
+void
+RawStatus(uchar StatusType, IP_STATUS StatusCode, IPAddr OrigDest,
+ IPAddr OrigSrc, IPAddr Src, ulong Param, void *Data)
+{
+
+ IF_TCPDBG(TCP_DEBUG_RAW) {
+ TCPTRACE(("RawStatus called\n"));
+ }
+
+ // If this is a HW status, it could be because we've had an address go
+ // away.
+ if (StatusType == IP_HW_STATUS) {
+
+ if (StatusCode == IP_ADDR_DELETED) {
+
+ // An address has gone away. OrigDest identifies the address.
+
+#ifndef _PNP_POWER
+ //
+ // This is done via TDI notifications in the PNP world.
+ //
+ InvalidateAddrs(OrigDest);
+
+#endif // _PNP_POWER
+
+#ifdef SECFLTR
+ //
+ // Delete any security filters associated with this address
+ //
+ DeleteProtocolSecurityFilter(OrigDest, PROTOCOL_RAW);
+
+#endif // SECFLTR
+
+ return;
+ }
+
+ if (StatusCode == IP_ADDR_ADDED) {
+
+#ifdef SECFLTR
+ //
+ // An address has materialized. OrigDest identifies the address.
+ // Data is a handle to the IP configuration information for the
+ // interface on which the address is instantiated.
+ //
+ AddProtocolSecurityFilter(OrigDest, PROTOCOL_RAW,
+ (NDIS_HANDLE) Data);
+#endif // SECFLTR
+
+ return;
+ }
+
+#ifdef CHICAGO
+ if (StatusCode == IP_UNLOAD) {
+ // IP is telling us we're being unloaded. First, deregister
+ // with VTDI, and then call CTEUnload().
+ (void)TLRegisterProtocol(PROTOCOL_ANY, NULL, NULL, NULL, NULL);
+
+#ifdef UDP_ONLY
+ // Only do the following in the UDP_ONLY version. TCP does it in
+ // the generic version.
+ TLRegisterDispatch(TransportName, NULL);
+ (void)RegisterAddrChangeHndlr(AddrChange, FALSE);
+ CTEUnload(TransportName);
+#endif // UDP_ONLY
+
+ return;
+ }
+#endif // CHICAGO
+ }
+}
+
+
+
diff --git a/private/ntos/tdi/tcpip/tcp/raw.h b/private/ntos/tdi/tcpip/tcp/raw.h
new file mode 100644
index 000000000..8619dc30f
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/raw.h
@@ -0,0 +1,34 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** RAW.H - Raw IP interface definitions.
+//
+// This file contains definitions for the Raw IP interface functions.
+//
+
+#include "dgram.h"
+
+
+//
+// This value is used to identify the RAW transport for security filtering.
+// It is out of the range of valid IP protocols.
+//
+#define PROTOCOL_RAW 255
+
+
+//* External definitions.
+extern IP_STATUS RawRcv(void *IPContext, IPAddr Dest, IPAddr Src,
+ IPAddr LocalAddr, IPAddr SrcAddr,
+ IPHeader UNALIGNED *IPH, uint IPHLength,
+ IPRcvBuf *RcvBuf, uint Size, uchar IsBCast,
+ uchar Protocol, IPOptInfo *OptInfo);
+
+extern void RawStatus(uchar StatusType, IP_STATUS StatusCode, IPAddr OrigDest,
+ IPAddr OrigSrc, IPAddr Src, ulong Param, void *Data);
+
+extern void RawSend(AddrObj *SrcAO, DGSendReq *SendReq);
+
+
diff --git a/private/ntos/tdi/tcpip/tcp/secfltr.c b/private/ntos/tdi/tcpip/tcp/secfltr.c
new file mode 100644
index 000000000..df64419e9
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/secfltr.c
@@ -0,0 +1,1425 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+#ifdef SECFLTR
+
+
+//** SECFLTR.C - Security Filter Support
+//
+//
+// Security filters provide a mechanism by which the transport protocol
+// traffic accepted on IP interfaces may be controlled. Security filtering
+// is globally enabled or disabled for all IP interfaces and transports.
+// If filtering is enabled, incoming traffic is filtered based on registered
+// {interface, protocol, transport value} tuples. The tuples specify
+// permissible traffic. All other values will be rejected. For UDP datagrams
+// and TCP connections, the transport value is the port number. For RawIP
+// datagrams, the transport value is the IP protocol number. An entry exists
+// in the filter database for all active interfaces and protocols in the
+// system.
+//
+// The initial status of security filtering - enabled or disabled, is
+// controlled by the registry parameter
+//
+// Services\Tcpip\Parameters\EnableSecurityFilters
+//
+// If the parameter is not found, filtering is disabled.
+//
+// The list of permissible values for each protocol is stored in the registry
+// under the <Adaptername>\Parameters\Tcpip key in MULTI_SZ parameters.
+// The parameter names are TCPAllowedPorts, UDPAllowedPorts and
+// RawIPAllowedProtocols. If no parameter is found for a particular protocol,
+// all values are permissible. If a parameter is found, the string identifies
+// the permissible values. If the string is empty, no values are permissible.
+//
+// Filter Operation (Filtering Enabled):
+//
+// IF ( Match(interface, protocol) AND ( AllValuesPermitted(Protocol) OR
+// Match(Value) ))
+// THEN operation permitted.
+// ELSE operation rejected.
+//
+// Database Implementation:
+//
+// The filter database is implemented as a three-level structure. The top
+// level is a list of interface entries. Each interface entry points to
+// a list of protocol entries. Each protocol entry contains a bucket hash
+// table used to store transport value entries.
+//
+
+// The following calls may be used to access the security filter database:
+//
+// InitializeSecurityFilters
+// CleanupSecurityFilters
+// IsSecurityFilteringEnabled
+// ControlSecurityFiltering
+// AddProtocolSecurityFilter
+// DeleteProtocolSecurityFilter
+// AddValueSecurityFilter
+// DeleteValueSecurityFilter
+// EnumerateSecurityFilters
+// IsPermittedSecurityFilter
+//
+
+#include "oscfg.h"
+#include "queue.h"
+#include "ndis.h"
+#include "cxport.h"
+#include "ip.h"
+#include "tdi.h"
+#include "tdistat.h"
+
+#ifdef NT
+
+#include "tdikrnl.h"
+#include "tdint.h"
+#include "tdistat.h"
+
+#endif // NT
+
+#include "addr.h"
+#include "tlcommon.h"
+#include "udp.h"
+#include "tcp.h"
+#include "raw.h"
+#include "tcpcfg.h"
+#include "tcpinfo.h"
+#include "secfltr.h"
+
+
+//
+// All of the init code can be discarded.
+//
+#ifdef NT
+#ifdef ALLOC_PRAGMA
+
+#pragma alloc_text(INIT, InitializeSecurityFilters)
+
+#endif // ALLOC_PRAGMA
+#endif // NT
+
+//
+// The following routines must be supplied by each platform which implements
+// security filters.
+//
+extern TDI_STATUS
+GetSecurityFilterList(
+ IN NDIS_HANDLE ConfigHandle,
+ IN ulong Protocol,
+ IN OUT PNDIS_STRING FilterList
+ );
+
+extern uint
+EnumSecurityFilterValue(
+ IN PNDIS_STRING FilterList,
+ IN ulong Index,
+ OUT ulong *FilterValue
+ );
+
+//
+// Constants
+//
+
+#define DHCP_CLIENT_PORT 68
+
+
+//
+// Modification Opcodes
+//
+#define ADD_VALUE_SECURITY_FILTER 0
+#define DELETE_VALUE_SECURITY_FILTER 1
+
+
+//
+// Types
+//
+
+//
+// Structure for a transport value entry.
+//
+struct value_entry {
+ struct Queue ve_link;
+ ulong ve_value;
+};
+
+typedef struct value_entry VALUE_ENTRY, *PVALUE_ENTRY;
+
+
+#define VALUE_ENTRY_HASH_SIZE 16
+#define VALUE_ENTRY_HASH(value) (value % VALUE_ENTRY_HASH_SIZE)
+
+//
+// Structure for a protocol entry.
+//
+struct protocol_entry {
+ struct Queue pe_link;
+ ulong pe_protocol;
+ ULONG pe_accept_all; // TRUE if all values are accepted.
+ struct Queue pe_entries[VALUE_ENTRY_HASH_SIZE];
+};
+
+typedef struct protocol_entry PROTOCOL_ENTRY, *PPROTOCOL_ENTRY;
+
+//
+// Structure for an interface entry.
+//
+struct interface_entry {
+ struct Queue ie_link;
+ IPAddr ie_address;
+ struct Queue ie_protocol_list; // list of protocols to filter
+};
+
+typedef struct interface_entry INTERFACE_ENTRY, *PINTERFACE_ENTRY;
+
+
+//
+// Global Data
+//
+
+//
+// This list of interface entries is the root of the filter database.
+//
+struct Queue InterfaceEntryList;
+
+//
+// The filter operations are synchronized using the AddrObjTableLock.
+//
+EXTERNAL_LOCK(AddrObjTableLock)
+
+extern IPInfo LocalNetInfo;
+
+
+//
+// Filter Database Helper Functions
+//
+
+//* FindInterfaceEntry - Search for an interface entry.
+//
+// This utility routine searches the security filter database
+// for the specified interface entry.
+//
+//
+// Input: InterfaceAddress - The address of the interface to search for.
+//
+//
+// Returns: A pointer to the database entry for the Interface,
+// or NULL if no match was found.
+//
+//
+PINTERFACE_ENTRY
+FindInterfaceEntry(ULONG InterfaceAddress)
+{
+ PINTERFACE_ENTRY ientry;
+ struct Queue *qentry;
+
+
+ for ( qentry = InterfaceEntryList.q_next;
+ qentry != &InterfaceEntryList;
+ qentry = qentry->q_next
+ )
+ {
+ ientry = STRUCT_OF(INTERFACE_ENTRY, qentry, ie_link);
+
+ if (ientry->ie_address == InterfaceAddress) {
+ return(ientry);
+ }
+ }
+
+ return(NULL);
+}
+
+
+//* FindProtocolEntry - Search for a protocol associated with an interface.
+//
+// This utility routine searches the security filter database
+// for the specified protocol registered under the specified interface.
+//
+//
+// Input: InterfaceEntry - A pointer to an interface entry to search under.
+// Protocol - The protocol value to search for.
+//
+//
+// Returns: A pointer to the database entry for the <Address, Protocol>,
+// or NULL if no match was found.
+//
+//
+PPROTOCOL_ENTRY
+FindProtocolEntry(PINTERFACE_ENTRY InterfaceEntry, ULONG Protocol)
+
+{
+ PPROTOCOL_ENTRY pentry;
+ struct Queue *qentry;
+
+
+ for ( qentry = InterfaceEntry->ie_protocol_list.q_next;
+ qentry != &(InterfaceEntry->ie_protocol_list);
+ qentry = qentry->q_next
+ )
+ {
+ pentry = STRUCT_OF(PROTOCOL_ENTRY, qentry, pe_link);
+
+ if (pentry->pe_protocol == Protocol) {
+ return(pentry);
+ }
+ }
+
+ return(NULL);
+}
+
+
+//* FindValueEntry - Search for a value on a particular protocol.
+//
+// This utility routine searches the security filter database
+// for the specified value registered under the specified protocol.
+//
+//
+// Input: ProtocolEntry - A pointer to the database structure for the
+// Protocol to search.
+// FilterValue - The value to search for.
+//
+//
+// Returns: A pointer to the database entry for the <Protocol, Value>,
+// or NULL if no match was found.
+//
+//
+PVALUE_ENTRY
+FindValueEntry(PPROTOCOL_ENTRY ProtocolEntry, ULONG FilterValue)
+{
+ PVALUE_ENTRY ventry;
+ ulong hash_value = VALUE_ENTRY_HASH(FilterValue);
+ struct Queue *qentry;
+
+
+ for ( qentry = ProtocolEntry->pe_entries[hash_value].q_next;
+ qentry != &(ProtocolEntry->pe_entries[hash_value]);
+ qentry = qentry->q_next
+ )
+ {
+ ventry = STRUCT_OF(VALUE_ENTRY, qentry, ve_link);
+
+ if (ventry->ve_value == FilterValue) {
+ return(ventry);
+ }
+ }
+
+ return(NULL);
+}
+
+
+//* DeleteProtocolValueEntries
+//
+// This utility routine deletes all the value entries associated with
+// a protocol filter entry.
+//
+//
+// Input: ProtocolEntry - The protocol filter entry for which to
+// delete the value entries.
+//
+//
+// Returns: Nothing
+//
+void
+DeleteProtocolValueEntries(PPROTOCOL_ENTRY ProtocolEntry)
+{
+ ulong i;
+ PVALUE_ENTRY entry;
+
+
+ for (i=0; i < VALUE_ENTRY_HASH_SIZE; i++) {
+ while (!EMPTYQ(&(ProtocolEntry->pe_entries[i]))) {
+
+ DEQUEUE(&(ProtocolEntry->pe_entries[i]), entry, VALUE_ENTRY, ve_link);
+ CTEFreeMem(entry);
+ }
+ }
+
+ return;
+}
+
+
+//* ModifyProtocolEntry
+//
+// This utility routine modifies one or more filter values associated
+// with a protocol.
+//
+//
+// Input: Operation - The operation to perform (add or delete)
+//
+// ProtocolEntry - A pointer to the protocol entry structure on
+// which to operate.
+//
+// FilterValue - The value to add or delete.
+//
+//
+// Returns: TDI_STATUS code
+//
+TDI_STATUS
+ModifyProtocolEntry(ulong Operation, PPROTOCOL_ENTRY ProtocolEntry,
+ ulong FilterValue)
+{
+ TDI_STATUS status = TDI_SUCCESS;
+
+
+ if (FilterValue == 0) {
+ if (Operation == ADD_VALUE_SECURITY_FILTER) {
+ //
+ // Accept all values for the protocol
+ //
+ ProtocolEntry->pe_accept_all = TRUE;
+ }
+ else {
+ //
+ // Reject all values for the protocol
+ //
+ ProtocolEntry->pe_accept_all = FALSE;
+ }
+
+ DeleteProtocolValueEntries(ProtocolEntry);
+ }
+ else {
+ PVALUE_ENTRY ventry;
+ ulong hash_value;
+
+ //
+ // This request modifies an individual entry.
+ //
+ ventry = FindValueEntry(ProtocolEntry, FilterValue);
+
+ if (Operation == ADD_VALUE_SECURITY_FILTER) {
+
+ if (ventry == NULL) {
+
+ ventry = CTEAllocMem(sizeof(VALUE_ENTRY));
+
+ if (ventry != NULL) {
+ ventry->ve_value = FilterValue;
+ hash_value = VALUE_ENTRY_HASH(FilterValue);
+
+ ENQUEUE(&(ProtocolEntry->pe_entries[hash_value]),
+ &(ventry->ve_link));
+
+ ProtocolEntry->pe_accept_all = FALSE;
+ }
+ else {
+ status = TDI_NO_RESOURCES;
+ }
+ }
+ }
+ else {
+ if (ventry != NULL) {
+ REMOVEQ(&(ventry->ve_link));
+ CTEFreeMem(ventry);
+ }
+ }
+ }
+
+ return(status);
+}
+
+
+//* ModifyInterfaceEntry
+//
+// This utility routine modifies the value entries of one or more protocol
+// entries associated with an interface.
+//
+//
+// Input: Operation - The operation to perform (add or delete)
+//
+// ProtocolEntry - A pointer to the interface entry structure on
+// which to operate.
+//
+// Protocol - The protocol on which to operate.
+//
+// FilterValue - The value to add or delete.
+//
+//
+// Returns: TDI_STATUS code
+//
+TDI_STATUS
+ModifyInterfaceEntry(ulong Operation, PINTERFACE_ENTRY InterfaceEntry,
+ ulong Protocol, ulong FilterValue)
+{
+ PPROTOCOL_ENTRY pentry;
+ TDI_STATUS status;
+ TDI_STATUS returnStatus = TDI_SUCCESS;
+
+
+ if (Protocol == 0) {
+ struct Queue *qentry;
+
+
+ //
+ // Modify all protocols on the interface
+ //
+ for ( qentry = InterfaceEntry->ie_protocol_list.q_next;
+ qentry != &(InterfaceEntry->ie_protocol_list);
+ qentry = qentry->q_next
+ )
+ {
+ pentry = STRUCT_OF(PROTOCOL_ENTRY, qentry, pe_link);
+ status = ModifyProtocolEntry(Operation, pentry, FilterValue);
+
+ if (status != TDI_SUCCESS) {
+ returnStatus = status;
+ }
+ }
+ }
+ else {
+ //
+ // Modify a specific protocol on the interface
+ //
+ pentry = FindProtocolEntry(InterfaceEntry, Protocol);
+
+ if (pentry != NULL) {
+ returnStatus = ModifyProtocolEntry(Operation, pentry, FilterValue);
+ }
+ else {
+ returnStatus = TDI_INVALID_PARAMETER;
+ }
+ }
+
+ return(returnStatus);
+}
+
+
+//* ModifySecurityFilter - Add or delete an entry.
+//
+// This routine adds or deletes an entry to/from the security filter database.
+//
+//
+// Input: Operation - The operation to perform (Add or Delete)
+// InterfaceAddress - The interface address to modify.
+// Protocol - The protocol to modify.
+// FilterValue - The transport value to add/delete.
+//
+// Returns: A TDI status code:
+// TDI_INVALID_PARAMETER if the protocol is not in the database.
+// TDI_ADDR_INVALID if the interface is not in the database.
+// TDI_NO_RESOURCES if memory could not be allocated.
+// TDI_SUCCESS otherwise
+//
+// NOTES:
+//
+TDI_STATUS
+ModifySecurityFilter(ulong Operation, IPAddr InterfaceAddress, ulong Protocol,
+ ulong FilterValue)
+{
+ PINTERFACE_ENTRY ientry;
+ TDI_STATUS status;
+ TDI_STATUS returnStatus = TDI_SUCCESS;
+
+
+ if (InterfaceAddress == 0) {
+ struct Queue *qentry;
+
+ //
+ // Modify on all interfaces
+ //
+ for ( qentry = InterfaceEntryList.q_next;
+ qentry != &InterfaceEntryList;
+ qentry = qentry->q_next
+ )
+ {
+ ientry = STRUCT_OF(INTERFACE_ENTRY, qentry, ie_link);
+ status = ModifyInterfaceEntry(Operation, ientry, Protocol,
+ FilterValue);
+
+ if (status != TDI_SUCCESS) {
+ returnStatus = status;
+ }
+ }
+ }
+ else {
+ ientry = FindInterfaceEntry(InterfaceAddress);
+
+ if (ientry != NULL) {
+ returnStatus = ModifyInterfaceEntry(Operation, ientry, Protocol,
+ FilterValue);
+ }
+ else {
+ returnStatus = TDI_ADDR_INVALID;
+ }
+ }
+
+ return(returnStatus);
+}
+
+
+//* FillInEnumerationEntry
+//
+// This utility routine fills in an enumeration entry for a particular
+// filter value entry.
+//
+//
+// Input: InterfaceAddress - The address of the associated interface.
+//
+// Protocol - The associated protocol number.
+//
+// Value - The enumerated value.
+//
+// Buffer - Pointer to the user's enumeration buffer.
+//
+// BufferSize - Pointer to the size of the enumeration buffer.
+//
+// EntriesReturned - Pointer to a running count of enumerated
+// entries stored in Buffer.
+//
+// EntriesAvailable - Pointer to a running count of entries available
+// for enumeration.
+//
+// Returns: Nothing.
+//
+// Note: Values written to enumeration entry are in host byte order.
+//
+void
+FillInEnumerationEntry(IPAddr InterfaceAddress, ulong Protocol, ulong Value,
+ uchar **Buffer, ulong *BufferSize,
+ ulong *EntriesReturned, ulong *EntriesAvailable)
+{
+ TCPSecurityFilterEntry *entry = (TCPSecurityFilterEntry *) *Buffer;
+
+
+ if (*BufferSize >= sizeof(TCPSecurityFilterEntry)) {
+ entry->tsf_address = net_long(InterfaceAddress);
+ entry->tsf_protocol = Protocol;
+ entry->tsf_value = Value;
+
+ *Buffer += sizeof(TCPSecurityFilterEntry);
+ *BufferSize -= sizeof(TCPSecurityFilterEntry);
+ (*EntriesReturned)++;
+ }
+
+ (*EntriesAvailable)++;
+
+ return;
+}
+
+
+//* EnumerateProtocolValues
+//
+// This utility routine enumerates values associated with a
+// protocol on an interface.
+//
+//
+// Input: InterfaceEntry - Pointer to the associated interface entry.
+//
+// ProtocolEntry - Pointer to the protocol being enumerated.
+//
+// Value - The value to enumerate.
+//
+// Buffer - Pointer to the user's enumeration buffer.
+//
+// BufferSize - Pointer to the size of the enumeration buffer.
+//
+// EntriesReturned - Pointer to a running count of enumerated
+// entries stored in Buffer.
+//
+// EntriesAvailable - Pointer to a running count of entries available
+// for enumeration.
+//
+// Returns: Nothing.
+//
+void
+EnumerateProtocolValues(PINTERFACE_ENTRY InterfaceEntry,
+ PPROTOCOL_ENTRY ProtocolEntry, ulong Value,
+ uchar **Buffer, ulong *BufferSize,
+ ulong *EntriesReturned, ulong *EntriesAvailable)
+{
+ struct Queue *qentry;
+ TDI_STATUS status = TDI_SUCCESS;
+ PVALUE_ENTRY ventry;
+ ulong i;
+
+
+ if (Value == 0) {
+ //
+ // Enumerate all values
+ //
+ if (ProtocolEntry->pe_accept_all == TRUE) {
+ //
+ // All values permitted.
+ //
+ FillInEnumerationEntry(
+ InterfaceEntry->ie_address,
+ ProtocolEntry->pe_protocol,
+ 0,
+ Buffer,
+ BufferSize,
+ EntriesReturned,
+ EntriesAvailable
+ );
+ }
+ else {
+ for (i=0; i < VALUE_ENTRY_HASH_SIZE; i++) {
+ for ( qentry = ProtocolEntry->pe_entries[i].q_next;
+ qentry != &(ProtocolEntry->pe_entries[i]);
+ qentry = qentry->q_next
+ )
+ {
+ ventry = STRUCT_OF(VALUE_ENTRY, qentry, ve_link);
+
+ FillInEnumerationEntry(
+ InterfaceEntry->ie_address,
+ ProtocolEntry->pe_protocol,
+ ventry->ve_value,
+ Buffer,
+ BufferSize,
+ EntriesReturned,
+ EntriesAvailable
+ );
+ }
+ }
+ }
+ }
+ else {
+ //
+ // Enumerate a specific value, if it is registered.
+ //
+ ventry = FindValueEntry(ProtocolEntry, Value);
+
+ if (ventry != NULL) {
+ FillInEnumerationEntry(
+ InterfaceEntry->ie_address,
+ ProtocolEntry->pe_protocol,
+ ventry->ve_value,
+ Buffer,
+ BufferSize,
+ EntriesReturned,
+ EntriesAvailable
+ );
+ }
+ }
+
+ return;
+}
+
+
+//* EnumerateInterfaceProtocols
+//
+// This utility routine enumerates protocols associated with
+// an interface.
+//
+//
+// Input: InterfaceEntry - Pointer to the associated interface entry.
+//
+// Protocol - Protocol number to enumerate.
+//
+// Value - The filter value to enumerate.
+//
+// Buffer - Pointer to the user's enumeration buffer.
+//
+// BufferSize - Pointer to the size of the enumeration buffer.
+//
+// EntriesReturned - Pointer to a running count of enumerated
+// entries stored in Buffer.
+//
+// EntriesAvailable - Pointer to a running count of entries available
+// for enumeration.
+//
+// Returns: Nothing.
+//
+void
+EnumerateInterfaceProtocols(PINTERFACE_ENTRY InterfaceEntry, ulong Protocol,
+ ulong Value, uchar **Buffer, ulong *BufferSize,
+ ulong *EntriesReturned, ulong *EntriesAvailable)
+{
+ PPROTOCOL_ENTRY pentry;
+
+
+ if (Protocol == 0) {
+ struct Queue *qentry;
+
+ //
+ // Enumerate all protocols.
+ //
+ for ( qentry = InterfaceEntry->ie_protocol_list.q_next;
+ qentry != &(InterfaceEntry->ie_protocol_list);
+ qentry = qentry->q_next
+ )
+ {
+ pentry = STRUCT_OF(PROTOCOL_ENTRY, qentry, pe_link);
+
+ EnumerateProtocolValues(
+ InterfaceEntry,
+ pentry,
+ Value,
+ Buffer,
+ BufferSize,
+ EntriesReturned,
+ EntriesAvailable
+ );
+ }
+ }
+ else {
+ //
+ // Enumerate a specific protocol
+ //
+
+ pentry = FindProtocolEntry(InterfaceEntry, Protocol);
+
+ if (pentry != NULL) {
+ EnumerateProtocolValues(
+ InterfaceEntry,
+ pentry,
+ Value,
+ Buffer,
+ BufferSize,
+ EntriesReturned,
+ EntriesAvailable
+ );
+ }
+ }
+
+ return;
+}
+
+
+//
+// Filter Database Public API.
+//
+
+//* InitializeSecurityFilters - Initializes the security filter database.
+//
+// The routine performs the initialization necessary to enable the
+// security filter database for operation.
+//
+// Input: None.
+//
+// Returns: Nothing.
+//
+//
+void
+InitializeSecurityFilters(void)
+{
+ INITQ(&InterfaceEntryList);
+
+ return;
+}
+
+
+//* CleanupSecurityFilters - Deletes the entire security filter database.
+//
+// This routine deletes all entries from the security filter database.
+//
+//
+// Input: None.
+//
+// Returns: Nothing.
+//
+// NOTE: This routine acquires the AddrObjTableLock.
+//
+//
+void
+CleanupSecurityFilters(void)
+{
+ PPROTOCOL_ENTRY pentry;
+ PINTERFACE_ENTRY ientry;
+ CTELockHandle handle;
+
+
+ CTEGetLock(&AddrObjTableLock, &handle);
+
+ while (!EMPTYQ(&InterfaceEntryList)) {
+ DEQUEUE(&InterfaceEntryList, ientry, INTERFACE_ENTRY, ie_link);
+
+ while (!EMPTYQ(&(ientry->ie_protocol_list))) {
+ DEQUEUE(&(ientry->ie_protocol_list), pentry, PROTOCOL_ENTRY,
+ pe_link);
+
+ DeleteProtocolValueEntries(pentry);
+
+ CTEFreeMem(pentry);
+ }
+
+ CTEFreeMem(ientry);
+ }
+
+ SecurityFilteringEnabled = FALSE;
+
+ CTEFreeLock(&AddrObjTableLock, handle);
+
+ return;
+}
+
+
+//* IsSecurityFilteringEnabled
+//
+// This routine returns the current global status of security filtering.
+//
+// Entry: Nothing
+//
+// Returns: 0 if filtering is disabled, !0 if filtering is enabled.
+//
+extern uint
+IsSecurityFilteringEnabled(void)
+{
+ uint enabled;
+ CTELockHandle handle;
+
+
+ CTEGetLock(&AddrObjTableLock, &handle);
+
+ enabled = SecurityFilteringEnabled;
+
+ CTEFreeLock(&AddrObjTableLock, handle);
+
+ return(enabled);
+}
+
+
+//* ControlSecurityFiltering
+//
+// This routine globally enables/disables security filtering.
+//
+// Entry: IsEnabled - 0 disabled filtering, !0 enables filtering.
+//
+// Returns: Nothing
+//
+extern void
+ControlSecurityFiltering(uint IsEnabled)
+{
+ CTELockHandle handle;
+
+
+ CTEGetLock(&AddrObjTableLock, &handle);
+
+ if (IsEnabled) {
+ SecurityFilteringEnabled = TRUE;
+ }
+ else {
+ SecurityFilteringEnabled = FALSE;
+ }
+
+ CTEFreeLock(&AddrObjTableLock, handle);
+
+ return;
+}
+
+
+//* AddProtocolSecurityFilter
+//
+// This routine enables security filtering for a specified protocol
+// on a specified IP interface.
+//
+// Entry: InterfaceAddress - The interface on which to enable the protocol.
+// (in network byte order)
+// Protocol - The protocol to enable.
+// ConfigName - The configuration key from which to read
+// the filter value information.
+//
+// Returns: Nothing
+//
+void
+AddProtocolSecurityFilter(IPAddr InterfaceAddress, ulong Protocol,
+ NDIS_HANDLE ConfigHandle)
+{
+ NDIS_STRING filterList;
+ ulong filterValue;
+ ulong i;
+ PINTERFACE_ENTRY ientry;
+ PPROTOCOL_ENTRY pentry;
+ PVOID temp;
+ CTELockHandle handle;
+ TDI_STATUS status;
+
+
+ if ( IP_ADDR_EQUAL(InterfaceAddress, NULL_IP_ADDR) ||
+ IP_LOOPBACK_ADDR(InterfaceAddress)
+ )
+ {
+ return;
+ }
+
+ CTEAssert( (Protocol != 0) && (Protocol <= 0xFF) );
+
+ //
+ // Read the protocol-specific filter value list from the registry.
+ //
+ filterList.MaximumLength = filterList.Length = 0;
+ filterList.Buffer = NULL;
+
+ if (ConfigHandle != NULL) {
+ status = GetSecurityFilterList(ConfigHandle, Protocol, &filterList);
+ }
+
+ //
+ // Preallocate interface & protocol structures. We abort on failure.
+ // The interface & protocol will be protected by default.
+ //
+ ientry = CTEAllocMem(sizeof(INTERFACE_ENTRY));
+
+ if (ientry == NULL) {
+ return;
+ }
+
+ ientry->ie_address = InterfaceAddress;
+ INITQ(&(ientry->ie_protocol_list));
+
+ pentry = CTEAllocMem(sizeof(PROTOCOL_ENTRY));
+
+ if (pentry == NULL) {
+ CTEFreeMem(ientry);
+ return;
+ }
+
+ pentry->pe_protocol = Protocol;
+ pentry->pe_accept_all = FALSE;
+
+ for (i=0; i<VALUE_ENTRY_HASH_SIZE; i++) {
+ INITQ(&(pentry->pe_entries[i]));
+ }
+
+ //
+ // Now go set everything up. First create the interface and protocol
+ // structures.
+ //
+ CTEGetLock(&AddrObjTableLock, &handle);
+
+ temp = FindInterfaceEntry(InterfaceAddress);
+
+ if (temp == NULL) {
+ //
+ // New interface & protocol.
+ //
+ ENQUEUE(&InterfaceEntryList, &(ientry->ie_link));
+ ENQUEUE(&(ientry->ie_protocol_list), &(pentry->pe_link));
+ }
+ else {
+ //
+ // Existing interface
+ //
+ CTEFreeMem(ientry);
+ ientry = temp;
+
+ temp = FindProtocolEntry(ientry, Protocol);
+
+ if (temp == NULL) {
+ //
+ // New protocol
+ //
+ ENQUEUE(&(ientry->ie_protocol_list), &(pentry->pe_link));
+ }
+ else {
+ //
+ // Existing protocol
+ //
+ CTEFreeMem(pentry);
+ }
+ }
+
+ CTEFreeLock(&AddrObjTableLock, handle);
+
+ //
+ // At this point, the protocol entry is installed, but no values
+ // are permitted. This is the safest default.
+ //
+
+ if (ConfigHandle != NULL) {
+ //
+ // Process the filter value list.
+ //
+ if (status == TDI_SUCCESS) {
+ for ( i=0;
+ EnumSecurityFilterValue(&filterList, i, &filterValue);
+ i++
+ )
+ {
+ AddValueSecurityFilter(InterfaceAddress, Protocol,
+ filterValue);
+ }
+ }
+ else if (status == TDI_ITEM_NOT_FOUND) {
+ //
+ // No filter registered, permit everything.
+ //
+ AddValueSecurityFilter(InterfaceAddress, Protocol, 0);
+ }
+ }
+
+ if (filterList.Buffer != NULL) {
+ CTEFreeMem(filterList.Buffer);
+ }
+
+ return;
+}
+
+
+//* DeleteProtocolSecurityFilter
+//
+// This routine disables security filtering for a specified protocol
+// on a specified IP interface.
+//
+// Entry: InterfaceAddress - The interface on which to disable the protocol.
+// (in network byte order)
+// Protocol - The protocol to disable.
+//
+// Returns: Nothing
+//
+void
+DeleteProtocolSecurityFilter(IPAddr InterfaceAddress, ulong Protocol)
+{
+ PINTERFACE_ENTRY ientry;
+ PPROTOCOL_ENTRY pentry;
+ CTELockHandle handle;
+ BOOLEAN deleteInterface = FALSE;
+
+
+ CTEGetLock(&AddrObjTableLock, &handle);
+
+ ientry = FindInterfaceEntry(InterfaceAddress);
+
+ if (ientry != NULL) {
+
+ CTEAssert(!EMPTYQ(&(ientry->ie_protocol_list)));
+
+ pentry = FindProtocolEntry(ientry, Protocol);
+
+ if (pentry != NULL) {
+ REMOVEQ(&(pentry->pe_link));
+ }
+
+ if (EMPTYQ(&(ientry->ie_protocol_list))) {
+ //
+ // Last protocol, delete interface as well.
+ //
+ REMOVEQ(&(ientry->ie_link));
+ deleteInterface = TRUE;
+ }
+
+ CTEFreeLock(&AddrObjTableLock, handle);
+
+ DeleteProtocolValueEntries(pentry);
+ CTEFreeMem(pentry);
+
+ if (deleteInterface) {
+ CTEAssert(EMPTYQ(&(ientry->ie_protocol_list)));
+ CTEFreeMem(ientry);
+ }
+ }
+ else {
+ CTEFreeLock(&AddrObjTableLock, handle);
+ }
+
+ return;
+}
+
+
+//* AddValueSecurityFilter - Add an entry.
+//
+// This routine adds a value entry for a specified protocol on a specified
+// interface in the security filter database.
+//
+//
+// Input: InterfaceAddress - The interface address to which to add.
+// (in network byte order)
+// Protocol - The protocol to which to add.
+// FilterValue - The transport value to add.
+// (in host byte order)
+//
+// Returns: A TDI status code:
+// TDI_INVALID_PARAMETER if the protocol is not in the database.
+// TDI_ADDR_INVALID if the interface is not in the database.
+// TDI_NO_RESOURCES if memory could not be allocated.
+// TDI_SUCCESS otherwise
+//
+// NOTES:
+//
+// This routine acquires AddrObjTableLock.
+//
+// Zero is a wildcard value. Supplying a zero value for the
+// InterfaceAddress and/or Protocol causes the operation to be applied
+// to all interfaces and/or protocols, as appropriate. Supplying a
+// non-zero value causes the operation to be applied to only the
+// specified interface and/or protocol. Supplying a FilterValue parameter
+// of zero causes all values to be acceptable. Any previously
+// registered values are deleted from the database.
+//
+TDI_STATUS
+AddValueSecurityFilter(IPAddr InterfaceAddress, ulong Protocol, ulong FilterValue)
+{
+ CTELockHandle handle;
+ TDI_STATUS status;
+
+
+ CTEGetLock(&AddrObjTableLock, &handle);
+
+ status = ModifySecurityFilter(ADD_VALUE_SECURITY_FILTER, InterfaceAddress,
+ Protocol, FilterValue);
+
+ CTEFreeLock(&AddrObjTableLock, handle);
+
+ return(status);
+}
+
+
+//* DeleteValueSecurityFilter - Delete an entry.
+//
+// This routine deletes a value entry for a specified protocol on a specified
+// interface in the security filter database.
+//
+//
+// Input: InterfaceAddress - The interface address from which to delete.
+// (in network byte order)
+// Protocol - The protocol from which to delete.
+// FilterValue - The transport value to delete.
+// (in host byte order)
+//
+// Returns: A TDI status code:
+// TDI_INVALID_PARAMETER if the protocol is not in the database.
+// TDI_ADDR_INVALID if the interface is not in the database.
+// TDI_NO_RESOURCES if memory could not be allocated.
+// TDI_SUCCESS otherwise
+//
+// NOTES:
+//
+// This routine acquires AddrObjTableLock.
+//
+// Zero is a wildcard value. Supplying a zero value for the
+// InterfaceAddress and/or Protocol causes the operation to be applied
+// to all interfaces and/or protocols, as appropriate. Supplying a
+// non-zero value causes the operation to be applied to only the
+// specified interface and/or protocol. Supplying a FilterValue parameter
+// of zero causes all values to be rejected. Any previously
+// registered values are deleted from the database.
+//
+TDI_STATUS
+DeleteValueSecurityFilter(IPAddr InterfaceAddress, ulong Protocol,
+ ulong FilterValue)
+{
+ CTELockHandle handle;
+ TDI_STATUS status;
+
+
+ CTEGetLock(&AddrObjTableLock, &handle);
+
+ status = ModifySecurityFilter(DELETE_VALUE_SECURITY_FILTER,
+ InterfaceAddress, Protocol, FilterValue);
+
+ CTEFreeLock(&AddrObjTableLock, handle);
+
+ return(status);
+}
+
+
+//* EnumerateSecurityFilters - Enumerate security filter database.
+//
+// This routine enumerates the contents of the security filter database
+// for the specified protocol and IP interface.
+//
+// Input: InterfaceAddress - The interface address to enumerate. A value
+// of zero means enumerate all interfaces.
+// (in network byte order)
+//
+// Protocol - The protocol to enumerate. A value of zero
+// means enumerate all protocols.
+//
+// Value - The Protocol value to enumerate. A value of
+// zero means enumerate all protocol values.
+// (in host byte order)
+//
+// Buffer - A pointer to a buffer into which to put
+// the returned filter entries.
+//
+// BufferSize - On input, the size in bytes of Buffer.
+// On output, the number of bytes written.
+//
+// EntriesAvailable - On output, the total number of filter entries
+// available in the database.
+//
+// Returns: A TDI status code:
+//
+// TDI_ADDR_INVALID if the address is not a valid IP interface.
+// TDI_SUCCESS otherwise.
+//
+// NOTES:
+//
+// This routine acquires AddrObjTableLock.
+//
+// Entries written to output buffer are in host byte order.
+//
+void
+EnumerateSecurityFilters(IPAddr InterfaceAddress, ulong Protocol,
+ ulong Value, uchar *Buffer, ulong BufferSize,
+ ulong *EntriesReturned, ulong *EntriesAvailable)
+{
+ PINTERFACE_ENTRY ientry;
+ TDI_STATUS status = TDI_SUCCESS;
+ CTELockHandle handle;
+
+
+ *EntriesAvailable = *EntriesReturned = 0;
+
+ CTEGetLock(&AddrObjTableLock, &handle);
+
+ if (InterfaceAddress == 0) {
+ struct Queue *qentry;
+
+ //
+ // Enumerate all interfaces.
+ //
+ for ( qentry = InterfaceEntryList.q_next;
+ qentry != &InterfaceEntryList;
+ qentry = qentry->q_next
+ )
+ {
+ ientry = STRUCT_OF(INTERFACE_ENTRY, qentry, ie_link);
+
+ EnumerateInterfaceProtocols(
+ ientry,
+ Protocol,
+ Value,
+ &Buffer,
+ &BufferSize,
+ EntriesReturned,
+ EntriesAvailable
+ );
+ }
+ }
+ else {
+ //
+ // Enumerate a specific interface.
+ //
+
+ ientry = FindInterfaceEntry(InterfaceAddress);
+
+ if (ientry != NULL) {
+ EnumerateInterfaceProtocols(
+ ientry,
+ Protocol,
+ Value,
+ &Buffer,
+ &BufferSize,
+ EntriesReturned,
+ EntriesAvailable
+ );
+ }
+ }
+
+ CTEFreeLock(&AddrObjTableLock, handle);
+
+ return;
+}
+
+
+//* IsPermittedSecurityFilter
+//
+// This routine determines if communications addressed to
+// {Protocol, InterfaceAddress, Value} are permitted by the security filters.
+// It looks up the tuple in the security filter database.
+//
+// Input: InterfaceAddress - The IP interface address to check
+// (in network byte order)
+// IPContext - The IPContext value passed to the transport
+// Protocol - The protocol to check
+// Value - The value to check (in host byte order)
+//
+// Returns: A boolean indicating whether or not the communication is permitted.
+//
+// NOTES:
+//
+// This routine must be called with AddrObjTableLock held.
+//
+//
+BOOLEAN
+IsPermittedSecurityFilter(IPAddr InterfaceAddress, void *IPContext,
+ ulong Protocol, ulong FilterValue)
+{
+ PINTERFACE_ENTRY ientry;
+ PPROTOCOL_ENTRY pentry;
+ PVALUE_ENTRY ventry;
+ ulong hash_value;
+ struct Queue *qentry;
+
+
+ CTEAssert(Protocol <= 0xFF);
+
+ for ( qentry = InterfaceEntryList.q_next;
+ qentry != &InterfaceEntryList;
+ qentry = qentry->q_next
+ )
+ {
+ ientry = STRUCT_OF(INTERFACE_ENTRY, qentry, ie_link);
+
+ if (ientry->ie_address == InterfaceAddress) {
+
+ for ( qentry = ientry->ie_protocol_list.q_next;
+ qentry != &(ientry->ie_protocol_list);
+ qentry = qentry->q_next
+ )
+ {
+ pentry = STRUCT_OF(PROTOCOL_ENTRY, qentry, pe_link);
+
+ if (pentry->pe_protocol == Protocol) {
+
+ if (pentry->pe_accept_all == TRUE) {
+ //
+ // All values accepted. Permit operation.
+ //
+ return(TRUE);
+ }
+
+ hash_value = VALUE_ENTRY_HASH(FilterValue);
+
+ for ( qentry = pentry->pe_entries[hash_value].q_next;
+ qentry != &(pentry->pe_entries[hash_value]);
+ qentry = qentry->q_next
+ )
+ {
+ ventry = STRUCT_OF(VALUE_ENTRY, qentry, ve_link);
+
+ if (ventry->ve_value == FilterValue) {
+ //
+ // Found it. Operation is permitted.
+ //
+ return(TRUE);
+ }
+ }
+
+ //
+ // {Interface, Protocol} protected, but no value found.
+ // Reject operation.
+ //
+ return(FALSE);
+ }
+ }
+
+ //
+ // Protocol not registered. Reject operation
+ //
+ return(FALSE);
+ }
+ }
+
+ //
+ // If this packet is on the loopback interface, let it through.
+ //
+ if (IP_LOOPBACK_ADDR(InterfaceAddress)) {
+ return(TRUE);
+ }
+
+ //
+ // Special check to allow the DHCP client to receive its packets.
+ // It is safe to make this check all the time because IP will
+ // not permit a packet to get through on an NTE with a zero address
+ // unless DHCP is in the process of configuring that NTE.
+ //
+ if ( (Protocol == PROTOCOL_UDP) &&
+ (FilterValue == DHCP_CLIENT_PORT) &&
+ (*LocalNetInfo.ipi_isdhcpinterface)(IPContext)
+ )
+ {
+ return(TRUE);
+ }
+
+ //
+ // Interface not registered. Deny operation.
+ //
+ return(FALSE);
+}
+
+
+#endif // SECFLTR
+
diff --git a/private/ntos/tdi/tcpip/tcp/secfltr.h b/private/ntos/tdi/tcpip/tcp/secfltr.h
new file mode 100644
index 000000000..ef05de497
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/secfltr.h
@@ -0,0 +1,61 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+#ifndef _SECFLTR_INCLUDED
+#define _SECFLTR_INCLUDED 1
+
+#ifdef SECFLTR
+
+
+//** SECFLTR.H - Security filtering support
+//
+// This file contains definitions related to security filtering.
+//
+
+//
+// Functions
+//
+extern void
+InitializeSecurityFilters(void);
+
+extern void
+CleanupSecurityFilters(void);
+
+extern uint
+IsSecurityFilteringEnabled(void);
+
+extern void
+ControlSecurityFiltering(uint IsEnabled);
+
+extern void
+AddProtocolSecurityFilter(IPAddr InterfaceAddress, ulong Protocol,
+ NDIS_HANDLE ConfigHandle);
+
+extern void
+DeleteProtocolSecurityFilter(IPAddr InterfaceAddress, ulong Protocol);
+
+extern TDI_STATUS
+AddValueSecurityFilter(IPAddr InterfaceAddress, ulong Protocol,
+ ulong FilterValue);
+
+extern TDI_STATUS
+DeleteValueSecurityFilter(IPAddr InterfaceAddress, ulong Protocol,
+ ulong FilterValue);
+
+extern void
+EnumerateSecurityFilters(IPAddr InterfaceAddress, ulong Protocol,
+ ulong Value, uchar *Buffer, ulong BufferSize,
+ ulong *EntriesReturned, ulong *EntriesAvailable);
+
+extern BOOLEAN
+IsPermittedSecurityFilter(IPAddr InterfaceAddress, void *IPContext,
+ ulong Protocol, ulong FilterValue);
+
+
+#endif // SECFLTR
+
+#endif // _SECFLTR_INCLUDED
+
diff --git a/private/ntos/tdi/tcpip/tcp/sources.inc b/private/ntos/tdi/tcpip/tcp/sources.inc
new file mode 100644
index 000000000..ad8aeff0f
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/sources.inc
@@ -0,0 +1,67 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=tcp
+
+NTPROFILEINPUT=yes
+
+TARGETNAME=tcpip
+TARGETTYPE=EXPORT_DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\tdi.lib \
+ $(BASEDIR)\public\sdk\lib\*\ndis.lib \
+ $(TARGETLIBS)
+
+INCLUDES=..\..\..\..\inc;..\..\..\..\..\inc;..\..\h
+
+C_DEFINES=$(C_DEFINES) -DNT -D_NTDRIVER_ -DRASAUTODIAL -D_PNP_POWER -DSECFLTR -DFAST_RETRANSMIT=1
+
+!IFDEF BUILD_FOR_3_51
+C_DEFINES= $(C_DEFINES) -D_NTIFS_
+!ENDIF
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES= \
+ ..\tcpip.rc \
+ ..\addr.c \
+ ..\dgram.c \
+ ..\info.c \
+ ..\init.c \
+ ..\ntdisp.c \
+ ..\ntinit.c \
+ ..\ntautodl.c \
+ ..\raw.c \
+ ..\secfltr.c \
+ ..\tcb.c \
+ ..\tcpconn.c \
+ ..\tcpdeb.c \
+ ..\tcpdeliv.c \
+ ..\tcprcv.c \
+ ..\tcpsend.c \
+ ..\tlcommon.c \
+ ..\udp.c
+
+DLLDEF=..\tcpip.def
diff --git a/private/ntos/tdi/tcpip/tcp/tcb.c b/private/ntos/tdi/tcpip/tcp/tcb.c
new file mode 100644
index 000000000..4b01c66d3
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/tcb.c
@@ -0,0 +1,1524 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** TCB.C - TCP TCB management code.
+//
+// This file contains the code for managing TCBs.
+//
+
+#include "oscfg.h"
+#include "ndis.h"
+#include "cxport.h"
+#include "ip.h"
+#include "tdi.h"
+#ifdef VXD
+#include "tdivxd.h"
+#include "tdistat.h"
+#endif
+#ifdef NT
+#include "tdint.h"
+#include "tdistat.h"
+#endif
+#include "queue.h"
+#include "tcp.h"
+#include "tcb.h"
+#include "tcpconn.h"
+#include "tcpsend.h"
+#include "tcprcv.h"
+#include "info.h"
+#include "tcpcfg.h"
+#include "tcpdeliv.h"
+#ifdef RASAUTODIAL
+#include <acd.h>
+#include <acdapi.h>
+#endif // RASAUTODIAL
+
+DEFINE_LOCK_STRUCTURE(TCBTableLock)
+
+uint TCPTime;
+uint TCBWalkCount;
+
+TCB *TCBTable[TCB_TABLE_SIZE];
+
+TCB *LastTCB;
+
+TCB *PendingFreeList;
+
+#ifndef NT
+TCB *FreeTCBList = NULL; // TCB free list
+#else
+SLIST_HEADER FreeTCBList;
+#endif
+
+DEFINE_LOCK_STRUCTURE(FreeTCBListLock) // Lock to protect TCB free list.
+
+EXTERNAL_LOCK(AddrObjTableLock)
+
+uint CurrentTCBs = 0;
+uint MaxTCBs = 0xffffffff;
+
+#ifdef NT
+#define MAX_FREE_TCBS 1000
+#else
+#define MAX_FREE_TCBS 10
+#endif
+
+#define NUM_DEADMAN_TICKS MS_TO_TICKS(1000)
+
+uint MaxFreeTCBs = MAX_FREE_TCBS;
+uint DeadmanTicks;
+
+CTETimer TCBTimer;
+
+extern IPInfo LocalNetInfo;
+
+//
+// All of the init code can be discarded.
+//
+#ifdef NT
+#ifdef ALLOC_PRAGMA
+
+int InitTCB(void);
+void UnInitTCB(void);
+
+#pragma alloc_text(INIT, InitTCB)
+#pragma alloc_text(INIT, UnInitTCB)
+
+#endif // ALLOC_PRAGMA
+#endif
+
+#ifdef RASAUTODIAL
+extern ACD_DRIVER AcdDriverG;
+
+VOID
+TCPNoteNewConnection(
+ IN TCB *pTCB,
+ IN CTELockHandle Handle
+ );
+#endif // RASAUTODIAL
+
+
+//* ReadNextTCB - Read the next TCB in the table.
+//
+// Called to read the next TCB in the table. The needed information
+// is derived from the incoming context, which is assumed to be valid.
+// We'll copy the information, and then update the context value with
+// the next TCB to be read.
+//
+// Input: Context - Poiner to a TCPConnContext.
+// Buffer - Pointer to a TCPConnTableEntry structure.
+//
+// Returns: TRUE if more data is available to be read, FALSE is not.
+//
+uint
+ReadNextTCB(void *Context, void *Buffer)
+{
+ TCPConnContext *TCContext = (TCPConnContext *)Context;
+ TCPConnTableEntry *TCEntry = (TCPConnTableEntry *)Buffer;
+ CTELockHandle Handle;
+ TCB *CurrentTCB;
+ uint i;
+
+
+ CurrentTCB = TCContext->tcc_tcb;
+ CTEStructAssert(CurrentTCB, tcb);
+
+ CTEGetLock(&CurrentTCB->tcb_lock, &Handle);
+ if (CLOSING(CurrentTCB))
+ TCEntry->tct_state = TCP_CONN_CLOSED;
+ else
+ TCEntry->tct_state = (uint)CurrentTCB->tcb_state +
+ TCB_STATE_DELTA;
+ TCEntry->tct_localaddr = CurrentTCB->tcb_saddr;
+ TCEntry->tct_localport = CurrentTCB->tcb_sport;
+ TCEntry->tct_remoteaddr = CurrentTCB->tcb_daddr;
+ TCEntry->tct_remoteport = CurrentTCB->tcb_dport;
+ CTEFreeLock(&CurrentTCB->tcb_lock, Handle);
+
+ // We've filled it in. Now update the context.
+ if (CurrentTCB->tcb_next != NULL) {
+ TCContext->tcc_tcb = CurrentTCB->tcb_next;
+ return TRUE;
+ } else {
+ // NextTCB is NULL. Loop through the TCBTable looking for a new
+ // one.
+ i = TCContext->tcc_index + 1;
+ while (i < TCB_TABLE_SIZE) {
+ if (TCBTable[i] != NULL) {
+ TCContext->tcc_tcb = TCBTable[i];
+ TCContext->tcc_index = i;
+ return TRUE;
+ break;
+ } else
+ i++;
+ }
+
+ TCContext->tcc_index = 0;
+ TCContext->tcc_tcb = NULL;
+ return FALSE;
+ }
+
+}
+
+//* ValidateTCBContext - Validate the context for reading a TCB table.
+//
+// Called to start reading the TCB table sequentially. We take in
+// a context, and if the values are 0 we return information about the
+// first TCB in the table. Otherwise we make sure that the context value
+// is valid, and if it is we return TRUE.
+// We assume the caller holds the TCB table lock.
+//
+// Input: Context - Pointer to a TCPConnContext.
+// Valid - Where to return information about context being
+// valid.
+//
+// Returns: TRUE if data in table, FALSE if not. *Valid set to true if the
+// context is valid.
+//
+uint
+ValidateTCBContext(void *Context, uint *Valid)
+{
+ TCPConnContext *TCContext = (TCPConnContext *)Context;
+ uint i;
+ TCB *TargetTCB;
+ TCB *CurrentTCB;
+
+ i = TCContext->tcc_index;
+ TargetTCB = TCContext->tcc_tcb;
+
+ // If the context values are 0 and NULL, we're starting from the beginning.
+ if (i == 0 && TargetTCB == NULL) {
+ *Valid = TRUE;
+ do {
+ if ((CurrentTCB = TCBTable[i]) != NULL) {
+ CTEStructAssert(CurrentTCB, tcb);
+ break;
+ }
+ i++;
+ } while (i < TCB_TABLE_SIZE);
+
+ if (CurrentTCB != NULL) {
+ TCContext->tcc_index = i;
+ TCContext->tcc_tcb = CurrentTCB;
+ return TRUE;
+ } else
+ return FALSE;
+
+ } else {
+
+ // We've been given a context. We just need to make sure that it's
+ // valid.
+
+ if (i < TCB_TABLE_SIZE) {
+ CurrentTCB = TCBTable[i];
+ while (CurrentTCB != NULL) {
+ if (CurrentTCB == TargetTCB) {
+ *Valid = TRUE;
+ return TRUE;
+ break;
+ } else {
+ CurrentTCB = CurrentTCB->tcb_next;
+ }
+ }
+
+ }
+
+ // If we get here, we didn't find the matching TCB.
+ *Valid = FALSE;
+ return FALSE;
+
+ }
+
+}
+
+//* FindNextTCB - Find the next TCB in a particular chain.
+//
+// This routine is used to find the 'next' TCB in a chain. Since we keep
+// the chain in ascending order, we look for a TCB which is greater than
+// the input TCB. When we find one, we return it.
+//
+// This routine is mostly used when someone is walking the table and needs
+// to free the various locks to perform some action.
+//
+// Input: Index - Index into TCBTable
+// Current - Current TCB - we find the one after this one.
+//
+// Returns: Pointer to the next TCB, or NULL.
+//
+TCB *
+FindNextTCB(uint Index, TCB *Current)
+{
+ TCB *Next;
+
+ CTEAssert(Index < TCB_TABLE_SIZE);
+
+ Next = TCBTable[Index];
+
+ while (Next != NULL && (Next <= Current))
+ Next = Next->tcb_next;
+
+ return Next;
+}
+
+//* ResetSendNext - Set the sendnext value of a TCB.
+//
+// Called to set the send next value of a TCB. We do that, and adjust all
+// pointers to the appropriate places. We assume the caller holds the lock
+// on the TCB.
+//
+// Input: SeqTCB - Pointer to TCB to be updated.
+// NewSeq - Sequence number to set.
+//
+// Returns: Nothing.
+//
+void
+ResetSendNext(TCB *SeqTCB, SeqNum NewSeq)
+{
+ TCPSendReq *SendReq;
+ uint AmtForward;
+ Queue *CurQ;
+ PNDIS_BUFFER Buffer;
+ uint Offset;
+
+ CTEStructAssert(SeqTCB, tcb);
+ CTEAssert(SEQ_GTE(NewSeq, SeqTCB->tcb_senduna));
+
+ // The new seq must be less than send max, or NewSeq, senduna, sendnext,
+ // and sendmax must all be equal. (The latter case happens when we're
+ // called exiting TIME_WAIT, or possibly when we're retransmitting
+ // during a flow controlled situation).
+ CTEAssert(SEQ_LT(NewSeq, SeqTCB->tcb_sendmax) ||
+ (SEQ_EQ(SeqTCB->tcb_senduna, SeqTCB->tcb_sendnext) &&
+ SEQ_EQ(SeqTCB->tcb_senduna, SeqTCB->tcb_sendmax) &&
+ SEQ_EQ(SeqTCB->tcb_senduna, NewSeq)));
+
+ AmtForward = NewSeq - SeqTCB->tcb_senduna;
+
+ SeqTCB->tcb_sendnext = NewSeq;
+
+ // If we're backing off send next, turn off the FIN_OUTSTANDING flag to
+ // maintain a consistent state.
+ if (!SEQ_EQ(NewSeq, SeqTCB->tcb_sendmax))
+ SeqTCB->tcb_flags &= ~FIN_OUTSTANDING;
+
+ if (SYNC_STATE(SeqTCB->tcb_state) && SeqTCB->tcb_state != TCB_TIME_WAIT) {
+ // In these states we need to update the send queue.
+
+ if (!EMPTYQ(&SeqTCB->tcb_sendq)) {
+ CurQ = QHEAD(&SeqTCB->tcb_sendq);
+
+ SendReq = (TCPSendReq *)STRUCT_OF(TCPReq, CurQ, tr_q);
+
+ // SendReq points to the first send request on the send queue.
+ // Move forward AmtForward bytes on the send queue, and set the
+ // TCB pointers to the resultant SendReq, buffer, offset, size.
+ while (AmtForward) {
+
+ CTEStructAssert(SendReq, tsr);
+
+ if (AmtForward >= SendReq->tsr_unasize) {
+ // We're going to move completely past this one. Subtract
+ // his size from AmtForward and get the next one.
+
+ AmtForward -= SendReq->tsr_unasize;
+ CurQ = QNEXT(CurQ);
+ CTEAssert(CurQ != QEND(&SeqTCB->tcb_sendq));
+ SendReq = (TCPSendReq *)STRUCT_OF(TCPReq, CurQ, tr_q);
+ } else {
+ // We're pointing at the proper send req now. Break out
+ // of this loop and save the information. Further down
+ // we'll need to walk down the buffer chain to find
+ // the proper buffer and offset.
+ break;
+ }
+ }
+
+ // We're pointing at the proper send req now. We need to go down
+ // the buffer chain here to find the proper buffer and offset.
+ SeqTCB->tcb_cursend = SendReq;
+ SeqTCB->tcb_sendsize = SendReq->tsr_unasize - AmtForward;
+ Buffer = SendReq->tsr_buffer;
+ Offset = SendReq->tsr_offset;
+
+ while (AmtForward) {
+ // Walk the buffer chain.
+ uint Length;
+
+ // We'll need the length of this buffer. Use the portable
+ // macro to get it. We have to adjust the length by the offset
+ // into it, also.
+ CTEAssert((Offset < NdisBufferLength(Buffer)) ||
+ ((Offset == 0) && (NdisBufferLength(Buffer) == 0)));
+
+ Length = NdisBufferLength(Buffer) - Offset;
+
+ if (AmtForward >= Length) {
+ // We're moving past this one. Skip over him, and 0 the
+ // Offset we're keeping.
+
+ AmtForward -= Length;
+ Offset = 0;
+ Buffer = NDIS_BUFFER_LINKAGE(Buffer);
+ CTEAssert(Buffer != NULL);
+ } else
+ break;
+ }
+
+ // Save the buffer we found, and the offset into that buffer.
+ SeqTCB->tcb_sendbuf = Buffer;
+ SeqTCB->tcb_sendofs = Offset + AmtForward;
+
+ } else {
+ CTEAssert(SeqTCB->tcb_cursend == NULL);
+ CTEAssert(AmtForward == 0);
+ }
+
+ }
+
+ CheckTCBSends(SeqTCB);
+
+}
+
+#ifdef NT
+
+//* TCPAbortAndIndicateDisconnect
+//
+// Abortively closes a TCB and issues a disconnect indication up the the
+// transport user. This function is used to support cancellation of
+// TDI send and receive requests.
+//
+// Input: ConnectionContext - The connection ID to find a TCB for.
+//
+// Returns: Nothing.
+//
+void
+TCPAbortAndIndicateDisconnect(
+ uint ConnectionContext
+ )
+{
+ TCB *AbortTCB;
+ CTELockHandle ConnTableHandle, TCBHandle;
+ TCPConn *Conn;
+
+
+ CTEGetLock(&ConnTableLock, &ConnTableHandle);
+
+ Conn = GetConnFromConnID(ConnectionContext);
+
+ if (Conn != NULL) {
+ CTEStructAssert(Conn, tc);
+
+ AbortTCB = Conn->tc_tcb;
+
+ if (AbortTCB != NULL) {
+
+ // If it's CLOSING or CLOSED, skip it.
+ if ((AbortTCB->tcb_state != TCB_CLOSED) && !CLOSING(AbortTCB)) {
+ CTEStructAssert(AbortTCB, tcb);
+ CTEGetLock(&AbortTCB->tcb_lock, &TCBHandle);
+ CTEFreeLock(&ConnTableLock, TCBHandle);
+
+ AbortTCB->tcb_refcnt++;
+ AbortTCB->tcb_flags |= NEED_RST; // send a reset if connected
+ TryToCloseTCB(AbortTCB, TCB_CLOSE_ABORTED, ConnTableHandle);
+
+ RemoveTCBFromConn(AbortTCB);
+
+ IF_TCPDBG(TCP_DEBUG_IRP) {
+ TCPTRACE((
+ "TCPAbortAndIndicateDisconnect, indicating discon\n"
+ ));
+ }
+
+ NotifyOfDisc(AbortTCB, NULL, TDI_CONNECTION_ABORTED);
+
+ CTEGetLock(&AbortTCB->tcb_lock, &TCBHandle);
+ DerefTCB(AbortTCB, TCBHandle);
+
+ // TCB lock freed by DerefTCB.
+
+ return;
+ }
+ }
+ }
+
+ CTEFreeLock(&ConnTableLock, ConnTableHandle);
+}
+
+#endif // NT
+
+
+//* TCBTimeout - Do timeout events on TCBs.
+//
+// Called every MS_PER_TICKS milliseconds to do timeout processing on TCBs.
+// We run throught the TCB table, decrementing timers. If one goes to zero
+// we look at it's state to decide what to do.
+//
+// Input: Timer - Event structure for timer that fired.
+// Context - Context for timer (NULL in this case.
+//
+// Returns: Nothing.
+//
+void
+TCBTimeout(CTEEvent *Timer, void *Context)
+{
+ CTELockHandle TableHandle, TCBHandle;
+ uint i;
+ TCB *CurrentTCB;
+ uint Delayed = FALSE;
+ uint CallRcvComplete;
+
+
+ // Update our free running counter.
+
+ TCPTime++;
+
+ CTEInterlockedAddUlong(&TCBWalkCount, 1, &TCBTableLock);
+
+
+#ifndef VXD
+ TCBHandle = DISPATCH_LEVEL;
+#endif
+
+ // Loop through each bucket in the table, going down the chain of
+ // TCBs on the bucket.
+ for (i = 0; i < TCB_TABLE_SIZE; i++) {
+ TCB *TempTCB;
+ uint maxRexmitCnt;
+
+ CurrentTCB = TCBTable[i];
+
+ while (CurrentTCB != NULL) {
+ CTEStructAssert(CurrentTCB, tcb);
+ CTEGetLockAtDPC(&CurrentTCB->tcb_lock, &TCBHandle);
+
+ // If it's CLOSING or CLOSED, skip it.
+ if (CurrentTCB->tcb_state == TCB_CLOSED || CLOSING(CurrentTCB)) {
+
+ TempTCB = CurrentTCB->tcb_next;
+ CTEFreeLockFromDPC(&CurrentTCB->tcb_lock, TCBHandle);
+ CurrentTCB = TempTCB;
+ continue;
+ }
+
+ CheckTCBSends(CurrentTCB);
+ CheckTCBRcv(CurrentTCB);
+
+ // First check the rexmit timer.
+ if (TCB_TIMER_RUNNING(CurrentTCB->tcb_rexmittimer)) {
+ // The timer is running.
+ if (--(CurrentTCB->tcb_rexmittimer) == 0) {
+
+ // And it's fired. Figure out what to do now.
+
+ // If we've had too many retransits, abort now.
+ CurrentTCB->tcb_rexmitcnt++;
+
+ if (CurrentTCB->tcb_state == TCB_SYN_SENT) {
+ maxRexmitCnt = MaxConnectRexmitCount;
+ }
+ else {
+ if (CurrentTCB->tcb_state == TCB_SYN_RCVD) {
+#ifdef SYN_ATTACK
+ //
+ // Save on locking. Though MaxConnectRexmitCountTmp may
+ // be changing, we are assured that we will not use
+ // more than the MaxConnectRexmitCount.
+ //
+ maxRexmitCnt = MIN(MaxConnectResponseRexmitCountTmp, MaxConnectResponseRexmitCount);
+#else
+ maxRexmitCnt = MaxConnectResponseRexmitCount;
+
+#endif
+ }
+ else {
+ maxRexmitCnt = MaxDataRexmitCount;
+ }
+ }
+
+ // If we've run out of retransmits or we're in FIN_WAIT2,
+ // time out.
+ if (CurrentTCB->tcb_rexmitcnt > maxRexmitCnt) {
+
+ CTEAssert(CurrentTCB->tcb_state > TCB_LISTEN);
+
+ // This connection has timed out. Abort it. First
+ // reference him, then mark as closed, notify the
+ // user, and finally dereference and close him.
+
+TimeoutTCB:
+ CurrentTCB->tcb_refcnt++;
+ TryToCloseTCB(CurrentTCB, TCB_CLOSE_TIMEOUT, TCBHandle);
+
+ RemoveTCBFromConn(CurrentTCB);
+ NotifyOfDisc(CurrentTCB, NULL, TDI_TIMED_OUT);
+
+#ifdef SYN_ATTACK
+ if (SynAttackProtect) {
+
+ CTELockHandle Handle;
+
+ CTEGetLockAtDPC(&SynAttLock, &Handle);
+ //
+ // We have put the connection in the closed state.
+ // Decrement the counters for keeping track of half
+ // open connections
+ //
+ CTEAssert((TCPHalfOpen > 0) && (TCPHalfOpenRetried > 0));
+ TCPHalfOpen--;
+ TCPHalfOpenRetried--;
+ CTEFreeLockFromDPC(&SynAttLock, Handle);
+ }
+#endif
+
+ CTEGetLockAtDPC(&CurrentTCB->tcb_lock, &TCBHandle);
+ DerefTCB(CurrentTCB, TCBHandle);
+
+ CurrentTCB = FindNextTCB(i, CurrentTCB);
+ continue;
+ }
+
+ CurrentTCB->tcb_rtt = 0; // Stop round trip time
+ // measurement.
+
+
+ // Figure out what our new retransmit timeout should be. We
+ // double it each time we get a retransmit, and reset it
+ // back when we get an ack for new data.
+ CurrentTCB->tcb_rexmit = MIN(CurrentTCB->tcb_rexmit << 1,
+ MAX_REXMIT_TO);
+
+ // Reset the sequence number, and reset the congestion
+ // window.
+ ResetSendNext(CurrentTCB, CurrentTCB->tcb_senduna);
+
+ if (!(CurrentTCB->tcb_flags & FLOW_CNTLD)) {
+ // Don't let the slow start threshold go below 2
+ // segments
+ CurrentTCB->tcb_ssthresh =
+ MAX(
+ MIN(
+ CurrentTCB->tcb_cwin,
+ CurrentTCB->tcb_sendwin
+ ) / 2,
+ (uint) CurrentTCB->tcb_mss * 2
+ );
+ CurrentTCB->tcb_cwin = CurrentTCB->tcb_mss;
+ } else {
+ // We're probing, and the probe timer has fired. We
+ // need to set the FORCE_OUTPUT bit here.
+ CurrentTCB->tcb_flags |= FORCE_OUTPUT;
+ }
+
+ // See if we need to probe for a PMTU black hole.
+ if (PMTUBHDetect &&
+ CurrentTCB->tcb_rexmitcnt == ((maxRexmitCnt+1)/2)) {
+ // We may need to probe for a black hole. If we're
+ // doing MTU discovery on this connection and we
+ // are retransmitting more than a minimum segment
+ // size, or we are probing for a PMTU BH already, turn
+ // off the DF flag and bump the probe count. If the
+ // probe count gets too big we'll assume it's not
+ // a PMTU black hole, and we'll try to switch the
+ // router.
+ if ((CurrentTCB->tcb_flags & PMTU_BH_PROBE) ||
+ ((CurrentTCB->tcb_opt.ioi_flags & IP_FLAG_DF) &&
+ (CurrentTCB->tcb_sendmax - CurrentTCB->tcb_senduna)
+ > 8)) {
+ // May need to probe. If we haven't exceeded our
+ // probe count, do so, otherwise restore those
+ // values.
+ if (CurrentTCB->tcb_bhprobecnt++ < 2) {
+
+ // We're going to probe. Turn on the flag,
+ // drop the MSS, and turn off the don't
+ // fragment bit.
+ if (!(CurrentTCB->tcb_flags & PMTU_BH_PROBE)) {
+ CurrentTCB->tcb_flags |= PMTU_BH_PROBE;
+ CurrentTCB->tcb_slowcount++;
+ CurrentTCB->tcb_fastchk |= TCP_FLAG_SLOW;
+
+ // Drop the MSS to the minimum. Save the old
+ // one in case we need it later.
+ CurrentTCB->tcb_mss = MIN(MAX_REMOTE_MSS -
+ CurrentTCB->tcb_opt.ioi_optlength,
+ CurrentTCB->tcb_remmss);
+
+ CTEAssert(CurrentTCB->tcb_mss > 0);
+
+ CurrentTCB->tcb_cwin = CurrentTCB->tcb_mss;
+ CurrentTCB->tcb_opt.ioi_flags &= ~IP_FLAG_DF;
+ }
+
+ // Drop the rexmit count so we come here again,
+ // and don't retrigger DeadGWDetect.
+
+ CurrentTCB->tcb_rexmitcnt--;
+ } else {
+ // Too many probes. Stop probing, and allow fallover
+ // to the next gateway.
+ //
+ // Currently this code won't do BH probing on the 2nd
+ // gateway. The MSS will stay at the minimum size. This
+ // might be a little suboptimal, but it's
+ // easy to implement for the Sept. 95 service pack
+ // and will keep connections alive if possible.
+ //
+ // In the future we should investigate doing
+ // dead g/w detect on a per-connection basis, and then
+ // doing PMTU probing for each connection.
+
+ if (CurrentTCB->tcb_flags & PMTU_BH_PROBE) {
+ CurrentTCB->tcb_flags &= ~PMTU_BH_PROBE;
+ if (--(CurrentTCB->tcb_slowcount) == 0)
+ CurrentTCB->tcb_fastchk &=
+ ~TCP_FLAG_SLOW;
+
+ }
+ CurrentTCB->tcb_bhprobecnt = 0;
+ }
+ }
+ }
+
+ // Check to see if we're doing dead gateway detect. If we
+ // are, see if it's time to ask IP.
+ if (DeadGWDetect &&
+ (CurrentTCB->tcb_rexmitcnt == ((maxRexmitCnt+1)/2))) {
+ (*LocalNetInfo.ipi_checkroute)(CurrentTCB->tcb_daddr,
+ CurrentTCB->tcb_saddr);
+ }
+
+ // Now handle the various cases.
+ switch (CurrentTCB->tcb_state) {
+
+ // In SYN-SENT or SYN-RCVD we'll need to retransmit
+ // the SYN.
+ case TCB_SYN_SENT:
+ case TCB_SYN_RCVD:
+ SendSYN(CurrentTCB, TCBHandle);
+ CurrentTCB = FindNextTCB(i, CurrentTCB);
+ continue;
+
+ case TCB_FIN_WAIT1:
+ case TCB_CLOSING:
+ case TCB_LAST_ACK:
+ // The call to ResetSendNext (above) will have
+ // turned off the FIN_OUTSTANDING flag.
+ CurrentTCB->tcb_flags |= FIN_NEEDED;
+ case TCB_CLOSE_WAIT:
+ case TCB_ESTAB:
+ // In this state we have data to retransmit, unless
+ // the window is zero (in which case we need to
+ // probe), or we're just sending a FIN.
+
+ CheckTCBSends(CurrentTCB);
+
+ Delayed = TRUE;
+ DelayAction(CurrentTCB, NEED_OUTPUT);
+ break;
+
+
+ // If it's fired in TIME-WAIT, we're all done and
+ // can clean up. We'll call TryToCloseTCB even
+ // though he's already sort of closed. TryToCloseTCB
+ // will figure this out and do the right thing.
+ case TCB_TIME_WAIT:
+ TryToCloseTCB(CurrentTCB, TCB_CLOSE_SUCCESS,
+ TCBHandle);
+ CurrentTCB = FindNextTCB(i, CurrentTCB);
+ continue;
+ default:
+ break;
+ }
+ }
+ }
+
+
+ // Now check the SWS deadlock timer..
+ if (TCB_TIMER_RUNNING(CurrentTCB->tcb_swstimer)) {
+ // The timer is running.
+ if (--(CurrentTCB->tcb_swstimer) == 0) {
+ // And it's fired. Force output now.
+
+ CurrentTCB->tcb_flags |= FORCE_OUTPUT;
+ Delayed = TRUE;
+ DelayAction(CurrentTCB, NEED_OUTPUT);
+ }
+ }
+
+ // Check the push data timer.
+ if (TCB_TIMER_RUNNING(CurrentTCB->tcb_pushtimer)) {
+ // The timer is running. Decrement it.
+ if (--(CurrentTCB->tcb_pushtimer) == 0) {
+ // It's fired.
+ PushData(CurrentTCB);
+ Delayed = TRUE;
+ }
+ }
+
+ // Check the delayed ack timer.
+ if (TCB_TIMER_RUNNING(CurrentTCB->tcb_delacktimer)) {
+ // The timer is running.
+ if (--(CurrentTCB->tcb_delacktimer) == 0) {
+ // And it's fired. Set up to send an ACK.
+
+ Delayed = TRUE;
+ DelayAction(CurrentTCB, NEED_ACK);
+ }
+
+ }
+
+ // Finally check the keepalive timer.
+ if (CurrentTCB->tcb_state == TCB_ESTAB) {
+ if (CurrentTCB->tcb_flags & KEEPALIVE) {
+ uint Delta;
+
+ Delta = TCPTime - CurrentTCB->tcb_alive;
+ if (Delta > KeepAliveTime) {
+ Delta -= KeepAliveTime;
+ if (Delta > (CurrentTCB->tcb_kacount * KAInterval)) {
+ if (CurrentTCB->tcb_kacount < MaxDataRexmitCount) {
+ SendKA(CurrentTCB, TCBHandle);
+ CurrentTCB = FindNextTCB(i, CurrentTCB);
+ continue;
+ } else
+ goto TimeoutTCB;
+ }
+ } else
+ CurrentTCB->tcb_kacount = 0;
+ }
+ }
+
+
+
+ // If this is an active open connection in SYN-SENT or SYN-RCVD,
+ // or we have a FIN pending, check the connect timer.
+ if (CurrentTCB->tcb_flags & (ACTIVE_OPEN | FIN_NEEDED | FIN_SENT)) {
+ TCPConnReq *ConnReq = CurrentTCB->tcb_connreq;
+
+ CTEAssert(ConnReq != NULL);
+ if (TCB_TIMER_RUNNING(ConnReq->tcr_timeout)) {
+ // Timer is running.
+ if (--(ConnReq->tcr_timeout) == 0) {
+ // The connection timer has timed out.
+ TryToCloseTCB(CurrentTCB, TCB_CLOSE_TIMEOUT,
+ TCBHandle);
+ CurrentTCB = FindNextTCB(i, CurrentTCB);
+ continue;
+ }
+ }
+ }
+
+#ifdef RASAUTODIAL
+ //
+ // Check to see if we have to notify the
+ // automatic connection driver about this
+ // connection.
+ //
+ if (CurrentTCB->tcb_flags & ACD_CONN_NOTIF) {
+ BOOLEAN fEnabled;
+ CTELockHandle AcdHandle;
+
+ //
+ // Clear the ACD_CONN_NOTIF flag
+ // and release the TCB table lock.
+ //
+ CurrentTCB->tcb_flags &= ~ACD_CONN_NOTIF;
+ //
+ // Determine if we need to notify
+ // the automatic connection driver.
+ //
+ CTEGetLockAtDPC(&AcdDriverG.SpinLock, &AcdHandle);
+ fEnabled = AcdDriverG.fEnabled;
+ CTEFreeLockFromDPC(&AcdDriverG.SpinLock, AcdHandle);
+ if (fEnabled)
+ TCPNoteNewConnection(CurrentTCB, TCBHandle);
+ else
+ CTEFreeLockFromDPC(&CurrentTCB->tcb_lock, TCBHandle);
+ //
+ // Reacquire the TCB table lock
+ // and get the next TCB to process.
+ //
+ CurrentTCB = FindNextTCB(i, CurrentTCB);
+ continue;
+ }
+#endif // RASAUTODIAL
+
+ // Timer isn't running, or didn't fire.
+ TempTCB = CurrentTCB->tcb_next;
+ CTEFreeLockFromDPC(&CurrentTCB->tcb_lock, TCBHandle);
+ CurrentTCB = TempTCB;
+ }
+ }
+
+
+ // See if we need to call receive complete as part of deadman processing.
+ // We do this now because we want to restart the timer before calling
+ // receive complete, in case that takes a while. If we make this check
+ // while the timer is running we'd have to lock, so we'll check and save
+ // the result now before we start the timer.
+ if (DeadmanTicks == TCPTime) {
+ CallRcvComplete = TRUE;
+ DeadmanTicks += NUM_DEADMAN_TICKS;
+ } else
+ CallRcvComplete = FALSE;
+
+
+ // Now check the pending free list. If it's not null, walk down the
+ // list and decrement the walk count. If the count goes below 2, pull it
+ // from the list. If the count goes to 0, free the TCB. If the count is
+ // at 1 it'll be freed by whoever called RemoveTCB.
+
+ CTEGetLockAtDPC(&TCBTableLock, &TableHandle);
+ if (PendingFreeList != NULL) {
+ TCB *PrevTCB;
+
+ PrevTCB = STRUCT_OF(TCB, &PendingFreeList, tcb_delayq.q_next);
+
+ do {
+ CurrentTCB = (TCB *)PrevTCB->tcb_delayq.q_next;
+
+ CTEStructAssert(CurrentTCB, tcb);
+
+ CurrentTCB->tcb_walkcount--;
+ if (CurrentTCB->tcb_walkcount <= 1) {
+ *(TCB **)&PrevTCB->tcb_delayq.q_next =
+ (TCB *)CurrentTCB->tcb_delayq.q_next;
+
+ if (CurrentTCB->tcb_walkcount == 0) {
+ FreeTCB(CurrentTCB);
+ }
+ } else {
+ PrevTCB = CurrentTCB;
+ }
+ } while (PrevTCB->tcb_delayq.q_next != NULL);
+ }
+
+ TCBWalkCount--;
+ CTEFreeLockFromDPC(&TCBTableLock, TableHandle);
+
+ // Do AddrCheckTable cleanup
+
+ if (AddrCheckTable) {
+
+ TCPAddrCheckElement *Temp;
+
+ CTEGetLockAtDPC(&AddrObjTableLock, &TableHandle);
+
+ for (Temp=AddrCheckTable; Temp<AddrCheckTable+NTWMaxConnectCount; Temp++) {
+ if (Temp->TickCount > 0) {
+ if ((--(Temp->TickCount)) == 0) {
+ Temp->SourceAddress = 0;
+ }
+ }
+ }
+
+ CTEFreeLockFromDPC(&AddrObjTableLock, TableHandle);
+ }
+
+ // Restart the timer again.
+ CTEStartTimer(&TCBTimer, MS_PER_TICK, TCBTimeout, NULL);
+
+ if (Delayed)
+ ProcessTCBDelayQ();
+
+ if (CallRcvComplete)
+ TCPRcvComplete();
+
+}
+
+//* SetTCBMTU - Set TCB MTU values.
+//
+// A function called by TCBWalk to set the MTU values of all TCBs using
+// a particular path.
+//
+// Input: CheckTCB - TCB to be checked.
+// DestPtr - Ptr to destination address.
+// SrcPtr - Ptr to source address.
+// MTUPtr - Ptr to new MTU.
+//
+// Returns: TRUE.
+//
+uint
+SetTCBMTU(TCB *CheckTCB, void *DestPtr, void *SrcPtr, void *MTUPtr)
+{
+ IPAddr DestAddr = *(IPAddr *)DestPtr;
+ IPAddr SrcAddr = *(IPAddr *)SrcPtr;
+ CTELockHandle TCBHandle;
+
+ CTEStructAssert(CheckTCB, tcb);
+
+ CTEGetLock(&CheckTCB->tcb_lock, &TCBHandle);
+
+ if (IP_ADDR_EQUAL(CheckTCB->tcb_daddr,DestAddr) &&
+ IP_ADDR_EQUAL(CheckTCB->tcb_saddr,SrcAddr) &&
+ (CheckTCB->tcb_opt.ioi_flags & IP_FLAG_DF)) {
+ uint MTU = *(uint *)MTUPtr - CheckTCB->tcb_opt.ioi_optlength;;
+
+ CheckTCB->tcb_mss = (ushort)MIN(MTU, (uint)CheckTCB->tcb_remmss);
+
+ CTEAssert(CheckTCB->tcb_mss > 0);
+
+ //
+ // Reset the Congestion Window if necessary
+ //
+ if (CheckTCB->tcb_cwin < CheckTCB->tcb_mss) {
+ CheckTCB->tcb_cwin = CheckTCB->tcb_mss;
+
+ //
+ // Make sure the slow start threshold is at least
+ // 2 segments
+ //
+ if ( CheckTCB->tcb_ssthresh <
+ ((uint) CheckTCB->tcb_mss*2)
+ ) {
+ CheckTCB->tcb_ssthresh = CheckTCB->tcb_mss * 2;
+ }
+ }
+ }
+
+ CTEFreeLock(&CheckTCB->tcb_lock, TCBHandle);
+
+ return TRUE;
+}
+
+
+//* DeleteTCBWithSrc - Delete tcbs with a particular src address.
+//
+// A function called by TCBWalk to delete all TCBs with a particular source
+// address.
+//
+// Input: CheckTCB - TCB to be checked.
+// AddrPtr - Ptr to address.
+//
+// Returns: FALSE if CheckTCB is to be deleted, TRUE otherwise.
+//
+uint
+DeleteTCBWithSrc(TCB *CheckTCB, void *AddrPtr, void *Unused1, void *Unused3)
+{
+ IPAddr Addr = *(IPAddr *)AddrPtr;
+
+ CTEStructAssert(CheckTCB, tcb);
+
+ if (IP_ADDR_EQUAL(CheckTCB->tcb_saddr,Addr))
+ return FALSE;
+ else
+ return TRUE;
+}
+
+
+//* TCBWalk - Walk the TCBs in the table, and call a function for each of them.
+//
+// Called when we need to repetively do something to each TCB in the table.
+// We call the specified function with a pointer to the TCB and the input
+// context for each TCB in the table. If the function returns FALSE, we
+// delete the TCB.
+//
+// Input: CallRtn - Routine to be called.
+// Context1 - Context to pass to CallRtn.
+// Context2 - Second context to pass to call routine.
+// Context3 - Third context to pass to call routine.
+//
+// Returns: Nothing.
+//
+void
+TCBWalk(uint (*CallRtn)(struct TCB *, void *, void *, void *), void *Context1,
+ void *Context2, void *Context3)
+{
+ uint i;
+ TCB *CurTCB;
+ CTELockHandle Handle, TCBHandle;
+
+ // Loop through each bucket in the table, going down the chain of
+ // TCBs on the bucket. For each one call CallRtn.
+ CTEGetLock(&TCBTableLock, &Handle);
+
+ for (i = 0; i < TCB_TABLE_SIZE; i++) {
+
+ CurTCB = TCBTable[i];
+
+ // Walk down the chain on this bucket.
+ while (CurTCB != NULL) {
+ if (!(*CallRtn)(CurTCB, Context1, Context2, Context3)) {
+ // He failed the call. Notify the client and close the
+ // TCB.
+ CTEGetLock(&CurTCB->tcb_lock, &TCBHandle);
+ if (!CLOSING(CurTCB)) {
+ CurTCB->tcb_refcnt++;
+ CTEFreeLock(&TCBTableLock, TCBHandle);
+ TryToCloseTCB(CurTCB, TCB_CLOSE_ABORTED, Handle);
+
+ RemoveTCBFromConn(CurTCB);
+ if (CurTCB->tcb_state != TCB_TIME_WAIT)
+ NotifyOfDisc(CurTCB, NULL, TDI_CONNECTION_ABORTED);
+
+ CTEGetLock(&CurTCB->tcb_lock, &TCBHandle);
+ DerefTCB(CurTCB, TCBHandle);
+ CTEGetLock(&TCBTableLock, &Handle);
+ } else
+ CTEFreeLock(&CurTCB->tcb_lock, TCBHandle);
+
+ CurTCB = FindNextTCB(i, CurTCB);
+ } else {
+ CurTCB = CurTCB->tcb_next;
+ }
+ }
+ }
+
+ CTEFreeLock(&TCBTableLock, Handle);
+}
+
+
+//* FindTCB - Find a TCB in the tcb table.
+//
+// Called when we need to find a TCB in the TCB table. We take a quick
+// look at the last TCB we found, and if it matches we return it. Otherwise
+// we hash into the TCB table and look for it. We assume the TCB table lock
+// is held when we are called.
+//
+// Input: Src - Source IP address of TCB to be found.
+// Dest - Dest. "" "" "" "" "" "" ""
+// DestPort - Destination port of TCB to be found.
+// SrcPort - Source port of TCB to be found.
+//
+// Returns: Pointer to TCB found, or NULL if none.
+//
+TCB *
+FindTCB(IPAddr Src, IPAddr Dest, ushort DestPort, ushort SrcPort)
+{
+ TCB *FoundTCB;
+
+ if (LastTCB != NULL) {
+ CTEStructAssert(LastTCB, tcb);
+ if (IP_ADDR_EQUAL(LastTCB->tcb_daddr, Dest) &&
+ LastTCB->tcb_dport == DestPort &&
+ IP_ADDR_EQUAL(LastTCB->tcb_saddr, Src) &&
+ LastTCB->tcb_sport == SrcPort)
+ return LastTCB;
+ }
+
+ // Didn't find it in our 1 element cache.
+ FoundTCB = TCBTable[TCB_HASH(Dest, Src, DestPort, SrcPort)];
+ while (FoundTCB != NULL) {
+ CTEStructAssert(FoundTCB, tcb);
+ if (IP_ADDR_EQUAL(FoundTCB->tcb_daddr, Dest) &&
+ FoundTCB->tcb_dport == DestPort &&
+ IP_ADDR_EQUAL(FoundTCB->tcb_saddr, Src) &&
+ FoundTCB->tcb_sport == SrcPort) {
+
+ // Found it. Update the cache for next time, and return.
+ LastTCB = FoundTCB;
+ return FoundTCB;
+ } else
+ FoundTCB = FoundTCB->tcb_next;
+ }
+
+ return FoundTCB;
+
+
+}
+
+
+//* InsertTCB - Insert a TCB in the tcb table.
+//
+// This routine inserts a TCB in the TCB table. No locks need to be held
+// when this routine is called. We insert TCBs in ascending address order.
+// Before inserting we make sure that the TCB isn't already in the table.
+//
+// Input: NewTCB - TCB to be inserted.
+//
+// Returns: TRUE if we inserted, false if we didn't.
+//
+uint
+InsertTCB(TCB *NewTCB)
+{
+ uint TCBIndex;
+ CTELockHandle TableHandle, TCBHandle;
+ TCB *PrevTCB, *CurrentTCB;
+ TCB *WhereToInsert;
+
+ CTEAssert(NewTCB != NULL);
+ CTEStructAssert(NewTCB, tcb);
+ TCBIndex = TCB_HASH(NewTCB->tcb_daddr, NewTCB->tcb_saddr,
+ NewTCB->tcb_dport, NewTCB->tcb_sport);
+
+ CTEGetLock(&TCBTableLock, &TableHandle);
+ CTEGetLockAtDPC(&NewTCB->tcb_lock, &TCBHandle);
+
+ // Find the proper place in the table to insert him. While
+ // we're walking we'll check to see if a dupe already exists.
+ // When we find the right place to insert, we'll remember it, and
+ // keep walking looking for a duplicate.
+
+ PrevTCB = STRUCT_OF(TCB, &TCBTable[TCBIndex], tcb_next);
+ WhereToInsert = NULL;
+
+ while (PrevTCB->tcb_next != NULL) {
+ CurrentTCB = PrevTCB->tcb_next;
+
+ if (IP_ADDR_EQUAL(CurrentTCB->tcb_daddr, NewTCB->tcb_daddr) &&
+ IP_ADDR_EQUAL(CurrentTCB->tcb_saddr, NewTCB->tcb_saddr) &&
+ (CurrentTCB->tcb_sport == NewTCB->tcb_sport) &&
+ (CurrentTCB->tcb_dport == NewTCB->tcb_dport)) {
+
+ CTEFreeLockFromDPC(&NewTCB->tcb_lock, TCBHandle);
+ CTEFreeLock(&TCBTableLock, TableHandle);
+ return FALSE;
+
+ } else {
+
+ if (WhereToInsert == NULL && CurrentTCB > NewTCB) {
+ WhereToInsert = PrevTCB;
+ }
+
+ CTEStructAssert(PrevTCB->tcb_next, tcb);
+ PrevTCB = PrevTCB->tcb_next;
+ }
+
+ }
+
+ if (WhereToInsert == NULL) {
+ WhereToInsert = PrevTCB;
+ }
+
+ NewTCB->tcb_next = WhereToInsert->tcb_next;
+ WhereToInsert->tcb_next = NewTCB;
+ NewTCB->tcb_flags |= IN_TCB_TABLE;
+ TStats.ts_numconns++;
+
+ CTEFreeLockFromDPC(&NewTCB->tcb_lock, TCBHandle);
+ CTEFreeLock(&TCBTableLock, TableHandle);
+ return TRUE;
+
+}
+
+//* RemoveTCB - Remove a TCB from the tcb table.
+//
+// Called when we need to remove a TCB from the TCB table. We assume the
+// TCB table lock and the TCB lock are held when we are called. If the
+// TCB isn't in the table we won't try to remove him.
+//
+// Input: RemovedTCB - TCB to be removed.
+//
+// Returns: TRUE if it's OK to free it, FALSE otherwise.
+//
+uint
+RemoveTCB(TCB *RemovedTCB)
+{
+ uint TCBIndex;
+ TCB *PrevTCB;
+#ifdef DEBUG
+ uint Found = FALSE;
+#endif
+
+ CTEStructAssert(RemovedTCB, tcb);
+
+ if (RemovedTCB->tcb_flags & IN_TCB_TABLE) {
+ TCBIndex = TCB_HASH(RemovedTCB->tcb_daddr, RemovedTCB->tcb_saddr,
+ RemovedTCB->tcb_dport, RemovedTCB->tcb_sport);
+
+ PrevTCB = STRUCT_OF(TCB, &TCBTable[TCBIndex], tcb_next);
+
+ do {
+ if (PrevTCB->tcb_next == RemovedTCB) {
+ // Found him.
+ PrevTCB->tcb_next = RemovedTCB->tcb_next;
+ RemovedTCB->tcb_flags &= ~IN_TCB_TABLE;
+ TStats.ts_numconns--;
+#ifdef DEBUG
+ Found = TRUE;
+#endif
+ break;
+ }
+ PrevTCB = PrevTCB->tcb_next;
+#ifdef DEBUG
+ if (PrevTCB != NULL)
+ CTEStructAssert(PrevTCB, tcb);
+#endif
+ } while (PrevTCB != NULL);
+
+ CTEAssert(Found);
+
+ }
+
+ if (LastTCB == RemovedTCB)
+ LastTCB = NULL;
+
+ if (TCBWalkCount == 0) {
+ return TRUE;
+ } else {
+ RemovedTCB->tcb_walkcount = TCBWalkCount + 1;
+ *(TCB **)&RemovedTCB->tcb_delayq.q_next = PendingFreeList;
+ PendingFreeList = RemovedTCB;
+ return FALSE;
+
+ }
+
+
+
+}
+
+
+//* ScavengeTCB - Scavenge a TCB that's in the TIME_WAIT state.
+//
+// Called when we're running low on TCBs, and need to scavenge one from
+// TIME_WAIT state. We'll walk through the TCB table, looking for the oldest
+// TCB in TIME_WAIT. We'll remove and return a pointer to that TCB. If we
+// don't find any TCBs in TIME_WAIT, we'll return NULL.
+//
+// Input: Nothing.
+//
+// Returns: Pointer to a reusable TCB, or NULL.
+//
+TCB *
+ScavengeTCB(void)
+{
+ CTELockHandle TableHandle, TCBHandle, FoundLock;
+ uint Now = CTESystemUpTime();
+ uint Delta = 0;
+ uint i;
+ TCB *FoundTCB = NULL, *PrevFound;
+ TCB *CurrentTCB, *PrevTCB;
+
+ CTEGetLock(&TCBTableLock, &TableHandle);
+
+ if (TCBWalkCount != 0) {
+ CTEFreeLock(&TCBTableLock, TableHandle);
+ return NULL;
+ }
+
+ for (i = 0; i < TCB_TABLE_SIZE; i++) {
+
+ PrevTCB = STRUCT_OF(TCB, &TCBTable[i], tcb_next);
+ CurrentTCB = PrevTCB->tcb_next;
+
+ while (CurrentTCB != NULL) {
+ CTEStructAssert(CurrentTCB, tcb);
+
+ CTEGetLock(&CurrentTCB->tcb_lock, &TCBHandle);
+ if (CurrentTCB->tcb_state == TCB_TIME_WAIT &&
+ (CurrentTCB->tcb_refcnt == 0) && !CLOSING(CurrentTCB)){
+ if (FoundTCB == NULL || ((Now - CurrentTCB->tcb_alive) > Delta)) {
+ // Found a new 'older' TCB. If we already have one, free
+ // the lock on him and get the lock on the new one.
+ if (FoundTCB != NULL)
+ CTEFreeLock(&FoundTCB->tcb_lock, TCBHandle);
+ else
+ FoundLock = TCBHandle;
+
+ PrevFound = PrevTCB;
+ FoundTCB = CurrentTCB;
+ Delta = Now - FoundTCB->tcb_alive;
+ } else
+ CTEFreeLock(&CurrentTCB->tcb_lock, TCBHandle);
+ } else
+ CTEFreeLock(&CurrentTCB->tcb_lock, TCBHandle);
+
+ // Look at the next one.
+ PrevTCB = CurrentTCB;
+ CurrentTCB = PrevTCB->tcb_next;
+ }
+ }
+
+ // If we have one, pull him from the list.
+ if (FoundTCB != NULL) {
+ PrevFound->tcb_next = FoundTCB->tcb_next;
+ FoundTCB->tcb_flags &= ~IN_TCB_TABLE;
+ // Close the RCE on this guy.
+ (*LocalNetInfo.ipi_closerce)(FoundTCB->tcb_rce);
+ TStats.ts_numconns--;
+ if (LastTCB == FoundTCB) {
+ LastTCB = NULL;
+ }
+ CTEFreeLock(&FoundTCB->tcb_lock, FoundLock);
+ }
+
+ CTEFreeLock(&TCBTableLock, TableHandle);
+ return FoundTCB;
+}
+
+//* AllocTCB - Allocate a TCB.
+//
+// Called whenever we need to allocate a TCB. We try to pull one off the
+// free list, or allocate one if we need one. We then initialize it, etc.
+//
+// Input: Nothing.
+//
+// Returns: Pointer to the new TCB, or NULL if we couldn't get one.
+//
+TCB *
+AllocTCB(void)
+{
+ TCB *NewTCB;
+
+ // First, see if we have one on the free list. The code for doing this
+ // is a little different between the NT and VxD worlds.
+#ifdef NT
+ PSINGLE_LIST_ENTRY BufferLink;
+
+ BufferLink = ExInterlockedPopEntrySList(&FreeTCBList, &FreeTCBListLock);
+
+ if (BufferLink != NULL) {
+ NewTCB = STRUCT_OF(TCB, BufferLink, tcb_next);
+ CTEStructAssert(NewTCB, tcb);
+ }
+#else // NT
+ NewTCB = FreeTCBList;
+ if (NewTCB != NULL) {
+ CTEStructAssert(NewTCB, tcb);
+ FreeTCBList = NewTCB->tcb_next;
+ }
+#endif // NT
+
+ else {
+
+ // We have none on the free list. If the total number of TCBs
+ // outstanding is more than we like to keep on the free list, try
+ // to scavenge a TCB from time wait.
+ if (CurrentTCBs < MaxFreeTCBs || ((NewTCB = ScavengeTCB()) == NULL)) {
+ if (CurrentTCBs < MaxTCBs) {
+ NewTCB = CTEAllocMem(sizeof(TCB));
+ if (NewTCB == NULL) {
+ return NewTCB;
+ }
+ else {
+ CTEInterlockedAddUlong(&CurrentTCBs, 1, &FreeTCBListLock);
+ }
+ } else
+ return NULL;
+ }
+ }
+
+ CTEAssert(NewTCB != NULL);
+
+ CTEMemSet(NewTCB, 0, sizeof(TCB));
+#ifdef DEBUG
+ NewTCB->tcb_sig = tcb_signature;
+#endif
+ INITQ(&NewTCB->tcb_sendq);
+ NewTCB->tcb_cursend = NULL;
+ NewTCB->tcb_alive = TCPTime;
+ // Initially we're not on the fast path because we're not established. Set
+ // the slowcount to one and set up the fastchk fields so we don't take the
+ // fast path.
+ NewTCB->tcb_slowcount = 1;
+ NewTCB->tcb_fastchk = TCP_FLAG_ACK | TCP_FLAG_SLOW;
+
+#if FAST_RETRANSMIT
+ NewTCB->tcb_dup = 0;
+#endif
+
+ CTEInitLock(&NewTCB->tcb_lock);
+
+ return NewTCB;
+}
+
+//* FreeTCB - Free a TCB.
+//
+// Called whenever we need to free a TCB.
+//
+// Note: This routine may be called with the TCBTableLock held.
+//
+// Input: FreedTCB - TCB to be freed.
+//
+// Returns: Nothing.
+//
+void
+FreeTCB(TCB *FreedTCB)
+{
+#ifdef NT
+ PSINGLE_LIST_ENTRY BufferLink;
+#endif // NT
+
+
+#ifndef NT
+ //
+ // Since we've moved to using sequenced lists for these resources,
+ // it's risky to actually free the memory here, so we won't do this
+ // for NT unless it becomes a problem.
+ if (CurrentTCBs > MaxFreeTCBs) {
+ CTEInterlockedAddUlong(&CurrentTCBs, (ulong) -1, &FreeTCBListLock);
+ CTEFreeMem(FreedTCB);
+ return;
+ }
+#endif
+
+#ifdef NT
+
+ CTEStructAssert(FreedTCB, tcb);
+
+ BufferLink = STRUCT_OF(SINGLE_LIST_ENTRY, &(FreedTCB->tcb_next), Next);
+ ExInterlockedPushEntrySList(
+ &FreeTCBList,
+ BufferLink,
+ &FreeTCBListLock
+ );
+
+#else // NT
+
+ CTEStructAssert(FreedTCB, tcb);
+
+ FreedTCB->tcb_next = FreeTCBList;
+ FreeTCBList = FreedTCB;
+
+#endif // NT
+}
+
+#pragma BEGIN_INIT
+
+//* InitTCB - Initialize our TCB code.
+//
+// Called during init time to initialize our TCB code. We initialize
+// the TCB table, etc, then return.
+//
+// Input: Nothing.
+//
+// Returns: TRUE if we did initialize, false if we didn't.
+//
+int
+InitTCB(void)
+{
+ int i;
+
+ for (i = 0; i < TCB_TABLE_SIZE; i++)
+ TCBTable[i] = NULL;
+
+ LastTCB = NULL;
+
+#ifdef NT
+ ExInitializeSListHead(&FreeTCBList);
+#endif
+
+ CTEInitLock(&TCBTableLock);
+ CTEInitLock(&FreeTCBListLock);
+
+ TCPTime = 0;
+ TCBWalkCount = 0;
+ DeadmanTicks = NUM_DEADMAN_TICKS;
+ CTEInitTimer(&TCBTimer);
+ CTEStartTimer(&TCBTimer, MS_PER_TICK, TCBTimeout, NULL);
+
+ return TRUE;
+}
+
+//* UnInitTCB - UnInitialize our TCB code.
+//
+// Called during init time if we're going to fail the init. We don't actually
+// do anything here.
+//
+// Input: Nothing.
+//
+// Returns: Nothing.
+//
+void
+UnInitTCB(void)
+{
+ CTEStopTimer(&TCBTimer);
+ return;
+}
+
+#pragma END_INIT
+
diff --git a/private/ntos/tdi/tcpip/tcp/tcb.h b/private/ntos/tdi/tcpip/tcp/tcb.h
new file mode 100644
index 000000000..3d273e50e
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/tcb.h
@@ -0,0 +1,67 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** TCB.H - TCB management definitions.
+//
+// This file contains the definitons needed for TCB management.
+//
+
+#define TCB_TABLE_SIZE 64
+
+#define MAX_REXMIT_CNT 5
+#define MAX_CONNECT_REXMIT_CNT 3
+#define MAX_CONNECT_RESPONSE_REXMIT_CNT 3
+#ifdef SYN_ATTACK
+#define ADAPTED_MAX_CONNECT_RESPONSE_REXMIT_CNT 1
+#endif
+
+extern uint TCPTime;
+
+#ifdef OLDHASH1
+#define TCB_HASH(DA,SA,DP,SP) ((uint)(*(uchar *)&(DA) + *((uchar *)&(DA) + 1) \
+ + *((uchar *)&(DA) + 2) + *((uchar *)&(DA) + 3)) % TCB_TABLE_SIZE)
+#endif
+
+#ifdef OLDHASH
+#define TCB_HASH(DA,SA,DP,SP) (((DA) + (SA) + (uint)(DP) + (uint)(SP)) % \
+ TCB_TABLE_SIZE)
+#endif
+
+#define ROR8(x) (uchar)(((uchar)(x) >> 1) | (uchar)(((uchar)(x) & 1) << 7))
+
+#define TCB_HASH(DA,SA,DP,SP) (((uint)(ROR8(ROR8(ROR8(ROR8(*((uchar *)&(DP) + 1) + \
+*((uchar *)&(DP))) + \
+*((uchar *)&(DA) + 3)) + \
+*((uchar *)&(DA) + 2)) + \
+*((uchar *)&(DA) + 1)) + \
+*((uchar *)&(DA)) )) % TCB_TABLE_SIZE)
+
+extern struct TCB *FindTCB(IPAddr Src, IPAddr Dest, ushort DestPort,
+ ushort SrcPort);
+extern uint InsertTCB(struct TCB *NewTCB);
+extern struct TCB *AllocTCB(void);
+extern void FreeTCB(struct TCB *FreedTCB);
+extern uint RemoveTCB(struct TCB *RemovedTCB);
+
+extern uint ValidateTCBContext(void *Context, uint *Valid);
+extern uint ReadNextTCB(void *Context, void *OutBuf);
+
+extern int InitTCB(void);
+extern void UnInitTCB(void);
+extern void TCBWalk(uint (*CallRtn)(struct TCB *, void *, void *,
+ void *), void *Context1, void *Context2,
+ void *Context3);
+extern uint DeleteTCBWithSrc(struct TCB *CheckTCB, void *AddrPtr,
+ void *Unused1, void *Unused2);
+extern uint SetTCBMTU(struct TCB *CheckTCB, void *DestPtr,
+ void *SrcPtr, void *MTUPtr);
+extern void ReetSendNext(struct TCB *SeqTCB, SeqNum DropSeq);
+
+extern uint TCBWalkCount;
+
+
+
+
diff --git a/private/ntos/tdi/tcpip/tcp/tcp.h b/private/ntos/tdi/tcpip/tcp/tcp.h
new file mode 100644
index 000000000..d88d3443e
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/tcp.h
@@ -0,0 +1,426 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+#ifndef _TCP_INCLUDED_
+#define _TCP_INCLUDED_
+
+//** TCP.H - TCP definitions.
+//
+// This file contains the definitions of TCP protocol specific options, such
+// as the sequence numbers and TCB.
+//
+
+#define PROTOCOL_TCP 6
+#define MAX_REMOTE_MSS 536
+
+//* Timer stuff. We keep timers as ticks.
+#define MS_PER_TICK 100
+#define MS_TO_TICKS(m) ((m) / MS_PER_TICK)
+#define MIN_RETRAN_TICKS 3
+
+#define DEL_ACK_TICKS 2
+// Define MAX_REXMIT_TO to be number of ticks in 2MSL (=240 seconds)
+
+#define MAX_REXMIT_TO ((ushort)FinWait2TO)
+
+#define SWS_TO MS_TO_TICKS(5000)
+
+#define FIN_WAIT2_TO 240
+#define PUSH_TO MS_TO_TICKS(500)
+
+typedef ulong TCP_TIME;
+#define MAX_CONN_TO_TICKS 0xffff
+#define INFINITE_CONN_TO(t) ((t) == 0)
+#define TCP_TIME_TO_TICKS(t) (((t)/MS_PER_TICK)+1)
+
+
+// Sequence numbers are kept as signed 32 bit quantities, with macros
+// defined to do wraparound comparisons on them.
+
+typedef int SeqNum; // A sequence number.
+
+//* Macros for comparions on sequence numbers.
+
+#define SEQ_GT(a, b) (((a) - (b)) > 0)
+#define SEQ_GTE(a, b) (((a) - (b)) >= 0)
+#define SEQ_LT(a, b) (((a) - (b)) < 0)
+#define SEQ_LTE(a, b) (((a) - (b)) <= 0)
+#define SEQ_EQ(a, b) ((a) == (b))
+
+//* The TCB - transport control block structure. This is the
+// structure that contains all of the state for the transport
+// connection, including sequence numbers, flow control information,
+// pending sends and receives, etc.
+
+#define tcb_signature 0x20424354 // 'TCB '
+
+struct TCB {
+
+#ifdef DEBUG
+ ulong tcb_sig; // Debug signature.
+#endif
+ struct TCB *tcb_next; // Next pointer in TCB table.
+ DEFINE_LOCK_STRUCTURE(tcb_lock)
+ // Send sequence variables.
+ SeqNum tcb_senduna; // Sequence number of first unack'd
+ // data.
+ SeqNum tcb_sendnext; // Sequence number of next byte to
+ // send.
+ SeqNum tcb_sendmax; // Max value of sendnext this
+ // epoch.
+ uint tcb_sendwin; // Send window.
+ uint tcb_unacked; // Total number of bytes of unacked
+ // data.
+ uint tcb_maxwin; // Max send window seen.
+ uint tcb_cwin; // Congestion window.
+ uint tcb_ssthresh; // Slow start threshold.
+ uint tcb_phxsum; // Precomputed pseudo-header xsum.
+ struct TCPSendReq *tcb_cursend; // Current send in use.
+ PNDIS_BUFFER tcb_sendbuf; // Current buffer chain being sent.
+ uint tcb_sendofs; // Offset into start of chain.
+ uint tcb_sendsize; // Number of bytes unsent in current
+ // send.
+ Queue tcb_sendq; // Queue of send requests.
+
+ // Receive sequence variables.
+ SeqNum tcb_rcvnext; // Next byte we expect to receive.
+ int tcb_rcvwin; // Receive window we're offering.
+ SeqNum tcb_sendwl1; // Window update sequence number.
+ SeqNum tcb_sendwl2; // Window update ack number.
+ struct TCPRcvReq *tcb_currcv; // Current receive buffer.
+ uint tcb_indicated; // Bytes of data indicated.
+ uint tcb_flags; // Flags for this TCB.
+ uint tcb_fastchk; // Fast receive path check field.
+ uint (*tcb_rcvhndlr)(struct TCB *, uint,
+ struct IPRcvBuf *, uint Size);
+ // Addressing info.
+ IPAddr tcb_daddr; // Destination IP address.
+ IPAddr tcb_saddr; // Source IP address.
+ ushort tcb_dport; // Destination port.
+ ushort tcb_sport; // Source port.
+
+ ushort tcb_mss; // MSS for this connection.
+ ushort tcb_rexmit; // Rexmit value.
+ uint tcb_refcnt; // Reference count for TCB.
+ SeqNum tcb_rttseq; // Sequence number being measured
+ // for RTT.
+
+ // Retransmit timer information. These are stored as ticks, where by
+ // default each tick is 100ms.
+ ushort tcb_smrtt; // Smoothed rtt value.
+ ushort tcb_delta; // Delta value.
+
+ ushort tcb_remmss; // MSS advertised by peer.
+ uchar tcb_slowcount; // Count of reasons why we're on
+ // the slow path.
+ uchar tcb_pushtimer; // The 'push' timer.
+
+ // State information.
+ uchar tcb_state; // State of this TCB.
+ uchar tcb_rexmitcnt; // Count of rexmits on this TCB.
+ uchar tcb_pending; // Pending actions on this TCB.
+ uchar tcb_kacount; // Count of keep alive probes sent.
+ IP_STATUS tcb_error; // Last error we heard about from
+ // IP.
+
+ uint tcb_rtt; // Current round trip time TS.
+
+ ushort tcb_rexmittimer; // Timer for rexmit.
+ ushort tcb_delacktimer; // Timer for delayed ack.
+
+
+ uint tcb_defaultwin; // Default rcv. window.
+ uint tcb_alive; // Keep alive time value.
+
+ struct TCPRAHdr *tcb_raq; // Reassembly queue.
+ struct TCPRcvReq *tcb_rcvhead; // Head of recv. buffer queue.
+ struct TCPRcvReq *tcb_rcvtail; // Tail of recv. buffer queue.
+ uint tcb_pendingcnt; // Bytes waiting to be received.
+ struct IPRcvBuf *tcb_pendhead; // Head of pending recv. queue.
+ struct IPRcvBuf *tcb_pendtail; // Tail of pending recv. queue.
+
+ struct TCPConnReq *tcb_connreq; // Connection-type request for
+ // this connection.
+ void *tcb_conncontext; // Connection context for this
+ // connection.
+
+ uint tcb_bcountlow; // Low part of byte count.
+ uint tcb_bcounthi; // High part of bytecount.
+ uint tcb_totaltime; // Total number of ticks spent
+ // sending.
+ struct TCB *tcb_aonext; // Next pointer on AddrObj.
+ struct TCPConn *tcb_conn; // Back pointer to conn for TCB.
+ Queue tcb_delayq; // Queue linkage for delay queue.
+ uchar tcb_closereason; // Reason we're closing.
+ uchar tcb_bhprobecnt; // BH probe count.
+ ushort tcb_swstimer; // Timer for SWS override.
+ void *tcb_rcvind; // Receive indication handler.
+ void *tcb_ricontext; // Receive indication context.
+ // Miscellaneous info, for IP.
+ IPOptInfo tcb_opt; // Option information.
+ RouteCacheEntry *tcb_rce; // RCE for this connection.
+ struct TCPConnReq *tcb_discwait; // Disc-Wait req., if there is one.
+ struct TCPRcvReq *tcb_exprcv; // Head of expedited recv. buffer
+ // queue.
+ struct IPRcvBuf *tcb_urgpending; // Urgent data queue.
+ uint tcb_urgcnt; // Byte count of data on urgent q.
+ uint tcb_urgind; // Urgent bytes indicated.
+ SeqNum tcb_urgstart; // Start of urgent data.
+ SeqNum tcb_urgend; // End of urgent data.
+ uint tcb_walkcount; // Count of number of people
+ // 'walking' this TCB.
+#if FAST_RETRANSMIT
+ ushort tcb_dup; // For Fast recovery algorithm
+ ushort tcb_force; // Force next send after fast send
+#endif
+
+};
+
+//* Definitions for TCP states.
+#define TCB_CLOSED 0 // Closed.
+#define TCB_LISTEN 1 // Listening.
+#define TCB_SYN_SENT 2 // SYN Sent.
+#define TCB_SYN_RCVD 3 // SYN received.
+#define TCB_ESTAB 4 // Established.
+#define TCB_FIN_WAIT1 5 // FIN-WAIT-1
+#define TCB_FIN_WAIT2 6 // FIN-WAIT-2
+#define TCB_CLOSE_WAIT 7 // Close waiting.
+#define TCB_CLOSING 8 // Closing state.
+#define TCB_LAST_ACK 9 // Last ack state.
+#define TCB_TIME_WAIT 10 // Time wait state.
+
+typedef struct TCB TCB;
+
+#define SYNC_STATE(s) ((s) > TCB_SYN_RCVD)
+#define GRACEFUL_CLOSED_STATE(s) ((s) >= TCB_LAST_ACK)
+#define DATA_RCV_STATE(s) ((s) >= TCB_ESTAB && (s) <= TCB_FIN_WAIT2)
+#define DATA_SEND_STATE(s) ((s) == TCB_ESTAB || (s) == TCB_CLOSE_WAIT)
+
+//* Definitions for flags.
+#define WINDOW_SET 0x00000001 // Window explictly set.
+#define CLIENT_OPTIONS 0x00000002 // Have client IP options on conn.
+#define CONN_ACCEPTED 0x00000004 // Connection was accepted.
+#define ACTIVE_OPEN 0x00000008 // Connection came from an active
+ // open.
+#define DISC_NOTIFIED 0x00000010 // Client has been notified of a
+ // disconnect.
+#define IN_DELAY_Q 0x00000020 // We're in the delayed action Q.
+#define RCV_CMPLTING 0x00000040 // We're completeing rcvs.
+#define IN_RCV_IND 0x00000080 // We're calling a rcv. indicate
+ // handler.
+#define NEED_RCV_CMPLT 0x00000100 // We need to have recvs. completed.
+#define NEED_ACK 0x00000200 // We need to send an ACK.
+#define NEED_OUTPUT 0x00000400 // We need to output.
+
+#define DELAYED_FLAGS (NEED_RCV_CMPLT | NEED_ACK | NEED_OUTPUT)
+
+
+#define ACK_DELAYED 0x00000800 // We've delayed sending an ACK.
+
+#define PMTU_BH_PROBE 0x00001000 // We're probing for a PMTU BH.
+#define BSD_URGENT 0x00002000 // We're using BSD urgent semantics.
+#define IN_DELIV_URG 0x00004000 // We're in the DeliverUrgent routine.
+#define URG_VALID 0x00008000 // We've seen urgent data, and
+ // the urgent data fields are valid.
+
+#define FIN_NEEDED 0x00010000 // We need to send a FIN.
+#define NAGLING 0x00020000 // We are using Nagle's algorithm.
+#define IN_TCP_SEND 0x00040000 // We're in TCPSend.
+#define FLOW_CNTLD 0x00080000 // We've received a zero window
+ // from our peer.
+#define DISC_PENDING 0x00100000 // A disconnect notification is
+ // pending.
+#define TW_PENDING 0x00200000 // We're waiting to finish going
+ // to TIME-WAIT.
+#define FORCE_OUTPUT 0x00400000 // Output is being forced.
+#define FORCE_OUT_SHIFT 22 // Shift to get FORCE_OUTPUT into
+ // low bit.
+#define SEND_AFTER_RCV 0x00800000 // We need to send after we get out
+ // of recv.
+#define GC_PENDING 0x01000000 // A graceful close is pending.
+#define KEEPALIVE 0x02000000 // Doing keepalives on this TCB.
+#define URG_INLINE 0x04000000 // Urgent data to be processed
+ // inline.
+
+#ifdef RASAUTODIAL
+#define ACD_CONN_NOTIF 0x08000000 // inform automatic connection
+ // driver about this connection
+#endif // RASAUTODIAL
+
+#define FIN_OUTSTANDING 0x10000000 // We've sent a FIN 'recently', i.e.
+ // since the last retransmit. When
+ // this flag is set sendnext ==
+ // sendmax.
+
+#define FIN_OUTS_SHIFT 28 // Shift to FIN_OUTSTANDING bit into
+ // low bit.
+#define FIN_SENT 0x20000000 // We've sent a FIN that hasn't
+ // been acknowledged. Once this
+ // bit has been turned on in
+ // FIN-WAIT-1 the sequence number
+ // of the FIN will be sendmax-1.
+#define NEED_RST 0x40000000 // We need to send a RST when
+ // closing.
+#define IN_TCB_TABLE 0x80000000 // TCB is in the TCB table.
+
+//* The defintion of the 'slow flags'. If any of these flags are set we'll
+// be forced off of the fast path.
+
+#define TCP_SLOW_FLAGS (URG_VALID | FLOW_CNTLD | GC_PENDING | \
+ TW_PENDING | DISC_NOTIFIED | IN_DELIV_URG | \
+ FIN_NEEDED | FIN_SENT | FIN_OUTSTANDING | \
+ DISC_PENDING | PMTU_BH_PROBE)
+
+//* Close reasons.
+#define TCB_CLOSE_RST 0x80 // Received a RST segment.
+#define TCB_CLOSE_ABORTED 0x40 // Had a local abort.
+#define TCB_CLOSE_TIMEOUT 0x20 // Connection timed out.
+#define TCB_CLOSE_REFUSED 0x10 // Connect attempt was refused.
+#define TCB_CLOSE_UNREACH 0x08 // Remote destination unreachable.
+#define TCB_CLOSE_SUCCESS 0x01 // Successfull close.
+
+//* TCB Timer macros.
+#define START_TCB_TIMER(t, v) (t) = (v)
+#define STOP_TCB_TIMER(t) (t) = 0
+#define TCB_TIMER_RUNNING(t) ((t) != 0)
+
+// Macro to compute retransmit timeout.
+#define REXMIT_TO(t) ((((t)->tcb_smrtt >> 2) + (t)->tcb_delta) >> 1)
+
+//* Definitons for pending actions. We define a PENDING_ACTION macro
+// that can be used to decide whether or not we can proceed with an
+// activity. The only pending action we really care about is DELETE - others
+// are low priority and can be put off.
+#define PENDING_ACTION(t) ((t)->tcb_pending & DEL_PENDING)
+#define DEL_PENDING 0x01 // Delete is pending.
+#define OPT_PENDING 0x02 // Option set is pending.
+
+//* Macro to see if a TCB is closing.
+#define CLOSING(t) ((t)->tcb_pending & DEL_PENDING)
+
+//* Structure of a TCP packet header.
+
+struct TCPHeader {
+ ushort tcp_src; // Source port.
+ ushort tcp_dest; // Destination port.
+ SeqNum tcp_seq; // Sequence number.
+ SeqNum tcp_ack; // Ack number.
+ ushort tcp_flags; // Flags and data offset.
+ ushort tcp_window; // Window offered.
+ ushort tcp_xsum; // Checksum.
+ ushort tcp_urgent; // Urgent pointer.
+};
+
+typedef struct TCPHeader TCPHeader;
+
+//* Definitions for header flags.
+#define TCP_FLAG_FIN 0x00000100
+#define TCP_FLAG_SYN 0x00000200
+#define TCP_FLAG_RST 0x00000400
+#define TCP_FLAG_PUSH 0x00000800
+#define TCP_FLAG_ACK 0x00001000
+#define TCP_FLAG_URG 0x00002000
+
+#define TCP_FLAGS_ALL (TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_RST | \
+ TCP_FLAG_ACK | TCP_FLAG_URG)
+
+//* Flags in the tcb_fastchk field that are not in the TCP header proper.
+// Setting these flags forces us off the fast path.
+#define TCP_FLAG_SLOW 0x00000001 // Need to be on slow path.
+#define TCP_FLAG_IN_RCV 0x00000002 // In recv. path already.
+
+#if FAST_RETRANSMIT
+#define TCP_FLAG_FASTREC 0x00000004 // This is used to mark tcb
+#endif // when Fast retransmit is in progress
+ // Debugging purpose only
+
+#define TCP_OFFSET_MASK 0xf0
+#define TCP_HDR_SIZE(t) (uint)(((*(uchar *)&(t)->tcp_flags) & TCP_OFFSET_MASK) >> 2)
+
+#define MAKE_TCP_FLAGS(o, f) ((f) | ((o) << 4))
+
+#define TCP_OPT_EOL 0
+#define TCP_OPT_NOP 1
+#define TCP_OPT_MSS 2
+#define MSS_OPT_SIZE 4
+
+//* Convenient byte swapped structure for receives.
+struct TCPRcvInfo {
+ SeqNum tri_seq; // Sequence number.
+ SeqNum tri_ack; // Ack number.
+ uint tri_window; // Window.
+ uint tri_urgent; // Urgent pointer.
+ uint tri_flags; // Flags.
+};
+
+typedef struct TCPRcvInfo TCPRcvInfo;
+
+
+
+//* General structure, at the start of all command specific request structures.
+
+#define tr_signature 0x20205254 // 'TR '
+
+struct TCPReq {
+#ifdef DEBUG
+ ulong tr_sig;
+#endif
+ struct Queue tr_q; // Q linkage.
+ CTEReqCmpltRtn tr_rtn; // Completion routine.
+ PVOID tr_context; // User context.
+ int tr_status; // Final complete status.
+};
+
+typedef struct TCPReq TCPReq;
+
+
+#ifdef NT
+
+#ifdef POOL_TAGGING
+
+#ifdef ExAllocatePool
+#undef ExAllocatePool
+#endif
+
+#define ExAllocatePool(type, size) ExAllocatePoolWithTag(type, size, 'tPCT')
+
+#ifndef CTEAllocMem
+#error "CTEAllocMem is not already defined - will override tagging"
+#else
+#undef CTEAllocMem
+#endif
+
+#define CTEAllocMem(size) ExAllocatePoolWithTag(NonPagedPool, size, 'tPCT')
+
+#endif // POOL_TAGGING
+
+//
+// TCP endpoint context structure allocated for each open of TCP/UDP.
+// A pointer to this structure is stored in FileObject->FsContext.
+//
+typedef struct _TCP_CONTEXT {
+ union {
+ HANDLE AddressHandle;
+ CONNECTION_CONTEXT ConnectionContext;
+ HANDLE ControlChannel;
+ } Handle;
+ ULONG ReferenceCount;
+ BOOLEAN CancelIrps;
+#if DBG
+ LIST_ENTRY PendingIrpList;
+ LIST_ENTRY CancelledIrpList;
+#endif
+ KEVENT CleanupEvent;
+} TCP_CONTEXT, *PTCP_CONTEXT;
+
+#endif // NT
+
+
+#include "tcpdeb.h"
+
+#endif // _TCP_INCLUDED_
+
+
diff --git a/private/ntos/tdi/tcpip/tcp/tcpcfg.h b/private/ntos/tdi/tcpip/tcp/tcpcfg.h
new file mode 100644
index 000000000..e3ee3ab01
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/tcpcfg.h
@@ -0,0 +1,86 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1992 **/
+/********************************************************************/
+/* :ts=4 */
+
+//* TCPCFG.H - Definitions of configuration information for TCP.
+//
+
+/*NOINC*/
+extern uint DeadGWDetect;
+extern uint PMTUDiscovery;
+extern uint PMTUBHDetect;
+extern uint KeepAliveTime;
+extern uint KAInterval;
+extern uint DefaultRcvWin;
+extern uint MaxConnections;
+extern uint MaxConnectRexmitCount;
+extern uint MaxConnectResponseRexmitCount;
+extern uint MaxDataRexmitCount;
+
+#ifdef SYN_ATTACK
+
+extern BOOLEAN SynAttackProtect;
+extern uint TCPHalfOpen;
+extern uint TCPHalfOpenRetried;
+extern uint TCPMaxHalfOpen;
+extern uint TCPMaxHalfOpenRetried;
+extern uint TCPMaxHalfOpenRetriedLW;
+extern uint TCPPortsExhausted;
+extern uint TCPMaxPortsExhausted;
+extern uint TCPMaxPortsExhaustedLW;
+extern uint MaxConnectResponseRexmitCountTmp;
+EXTERNAL_LOCK(SynAttLock)
+#endif
+
+
+extern uint BSDUrgent;
+extern uint PreloadCount;
+extern uint FinWait2TO;
+extern uint NTWMaxConnectCount;
+extern uint NTWMaxConnectTime;
+extern uint MaxUserPort;
+
+#ifdef SECFLTR
+extern uint SecurityFilteringEnabled;
+#endif // SECFLTR
+
+/*INC*/
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#define DEFAULT_DEAD_GW_DETECT TRUE
+#define DEFAULT_PMTU_DISCOVERY TRUE
+#define DEFAULT_PMTU_BHDETECT FALSE
+#define DEFAULT_KA_TIME 7200000
+#define DEFAULT_KA_INTERVAL 1000
+#define DEFAULT_RCV_WIN 8192
+#define DEFAULT_PRELOAD_COUNT 0
+#define MAX_PRELOAD_COUNT 32
+#define PRELOAD_BLOCK_SIZE 16384
+
+/*NOINC*/
+#ifndef VXD
+#define DEFAULT_MAX_CONNECTIONS (INVALID_CONN_INDEX - 1)
+#define NTW_MAX_CONNECT_TIME 600
+#define NTW_MAX_CONNECT_COUNT 15
+#else
+
+/*INC*/
+#define DEFAULT_MAX_CONNECTIONS 100
+
+/*NOINC*/
+#endif
+/*INC*/
+
+#define DEFAULT_CONNECT_REXMIT_CNT 3
+#define DEFAULT_DATA_REXMIT_CNT 5
+#define DEFAULT_BSD_URGENT TRUE
+
diff --git a/private/ntos/tdi/tcpip/tcp/tcpconn.c b/private/ntos/tdi/tcpip/tcp/tcpconn.c
new file mode 100644
index 000000000..daeadf85c
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/tcpconn.c
@@ -0,0 +1,2344 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** TCPCONN.C - TCP connection mgmt code.
+//
+// This file contains the code handling TCP connection related requests,
+// such as connecting and disconnecting.
+//
+
+#include "oscfg.h"
+#include "ndis.h"
+#include "cxport.h"
+#include "ip.h"
+#include "tdi.h"
+#ifdef VXD
+#include "tdivxd.h"
+#include "tdistat.h"
+#endif
+#ifdef NT
+#include "tdint.h"
+#include "tdistat.h"
+#endif
+#include "queue.h"
+#include "addr.h"
+#include "tcp.h"
+#include "tcb.h"
+#include "tcpconn.h"
+#include "tcpsend.h"
+#include "tcprcv.h"
+#include "tcpdeliv.h"
+#include "tlcommon.h"
+#include "info.h"
+#include "tcpcfg.h"
+
+#define CONN_INDEX(c) ((c) & 0xffffff)
+#define CONN_INST(c) ((uchar)((c) >> 24))
+#define MAKE_CONN_ID(i, s) ((((uint)(s)) << 24) | ((uint)(i)))
+#define GROW_DELTA 16
+#define INVALID_CONN_ID MAKE_CONN_ID(INVALID_CONN_INDEX, 0xff)
+
+
+#ifndef NT
+TCPConnReq *ConnReqFree; // Connection request free list.
+#else
+SLIST_HEADER ConnReqFree; // Connection request free list.
+extern PDRIVER_OBJECT TCPDriverObject;
+#endif
+
+DEFINE_LOCK_STRUCTURE(ConnReqFreeLock) // Lock to protect conn req free list.
+uint NumConnReq; // Current number of ConnReqs in system.
+uint MaxConnReq = 0xffffffff; // Maximum allowed number of ConnReqs.
+
+TCPConnTable *ConnTable = NULL; // The current connection table.
+
+uint ConnTableSize; // Current number of entries in the
+ // ConnTable.
+uchar ConnInst; // Current conn inst in use.
+uint NextConnIndex; // Next conn. index to use.
+
+DEFINE_LOCK_STRUCTURE(ConnTableLock)
+EXTERNAL_LOCK(AddrObjTableLock)
+EXTERNAL_LOCK(TCBTableLock)
+
+TCPAddrCheckElement *AddrCheckTable = NULL; // The current check table
+
+extern IPInfo LocalNetInfo;
+extern void RemoveConnFromAO(AddrObj *AO, TCPConn *Conn);
+
+
+//
+// All of the init code can be discarded.
+//
+#ifdef NT
+#ifdef ALLOC_PRAGMA
+
+int InitTCPConn(void);
+void UnInitTCPConn(void);
+void NotifyConnLimitProc(CTEEvent *Event, void *Context);
+
+typedef struct ConnLimitExceededStruct {
+ CTEEvent cle_event;
+ IPAddr cle_addr;
+ ulong cle_port;
+} ConnLimitExceededStruct;
+
+
+#pragma alloc_text(INIT, InitTCPConn)
+#pragma alloc_text(INIT, UnInitTCPConn)
+#pragma alloc_text(PAGE, NotifyConnLimitProc)
+
+#endif // ALLOC_PRAGMA
+#endif
+
+void CompleteConnReq(TCB *CmpltTCB, IPOptInfo *OptInfo, TDI_STATUS Status);
+
+
+//** Routines for handling conn refcount going to 0.
+
+//* DummyDone - Called when nothing to do.
+//
+// Input: Conn - Conn goint to 0.
+// Handle - Lock handle for conn table lock.
+//
+// Returns: Nothing.
+//
+void
+DummyDone(TCPConn *Conn, CTELockHandle Handle)
+{
+ CTEFreeLock(&ConnTableLock, Handle);
+}
+
+//* DummyCmplt - Dummy close completion routine.
+void
+DummyCmplt(PVOID Dummy1, uint Dummy2, uint Dummy3)
+{
+}
+
+//* CloseDone - Called when we need to complete a close.
+//
+// Input: Conn - Conn going to 0.
+// Handle - Lock handle for conn table lock.
+//
+// Returns: Nothing.
+//
+void
+CloseDone(TCPConn *Conn, CTELockHandle Handle)
+{
+ CTEReqCmpltRtn Rtn; // Completion routine.
+ PVOID Context; // User context for completion routine.
+ CTELockHandle AOTableHandle, ConnTableHandle, AOHandle;
+ AddrObj *AO;
+
+ CTEAssert(Conn->tc_flags & CONN_CLOSING);
+
+ Rtn = Conn->tc_rtn;
+ Context = Conn->tc_rtncontext;
+ CTEFreeLock(&ConnTableLock, Handle);
+
+ CTEGetLock(&AddrObjTableLock, &AOTableHandle);
+ CTEGetLock(&ConnTableLock, &ConnTableHandle);
+
+ if ((AO = Conn->tc_ao) != NULL) {
+
+ CTEStructAssert(AO, ao);
+
+ // It's associated.
+ CTEGetLock(&AO->ao_lock, &AOHandle);
+ RemoveConnFromAO(AO, Conn);
+ // We've pulled him from the AO, we can free the lock now.
+ CTEFreeLock(&AO->ao_lock, AOHandle);
+ }
+
+ CTEFreeLock(&ConnTableLock, ConnTableHandle);
+ CTEFreeLock(&AddrObjTableLock, AOTableHandle);
+
+ CTEFreeMem(Conn);
+
+ (*Rtn)(Context, TDI_SUCCESS, 0);
+
+}
+
+//* DisassocDone - Called when we need to complete a disassociate.
+//
+// Input: Conn - Conn going to 0.
+// Handle - Lock handle for conn table lock.
+//
+// Returns: Nothing.
+//
+void
+DisassocDone(TCPConn *Conn, CTELockHandle Handle)
+{
+ CTEReqCmpltRtn Rtn; // Completion routine.
+ PVOID Context; // User context for completion routine.
+ AddrObj *AO;
+ CTELockHandle AOTableHandle, ConnTableHandle, AOHandle;
+ uint NeedClose = FALSE;
+
+ CTEAssert(Conn->tc_flags & CONN_DISACC);
+ CTEAssert(!(Conn->tc_flags & CONN_CLOSING));
+ CTEAssert(Conn->tc_refcnt == 0);
+
+ Rtn = Conn->tc_rtn;
+ Context = Conn->tc_rtncontext;
+ Conn->tc_refcnt = 1;
+ CTEFreeLock(&ConnTableLock, Handle);
+
+ CTEGetLock(&AddrObjTableLock, &AOTableHandle);
+ CTEGetLock(&ConnTableLock, &ConnTableHandle);
+ if (!(Conn->tc_flags & CONN_CLOSING)) {
+
+ AO = Conn->tc_ao;
+ if (AO != NULL) {
+ CTEGetLock(&AO->ao_lock, &AOHandle);
+ RemoveConnFromAO(AO, Conn);
+ CTEFreeLock(&AO->ao_lock, AOHandle);
+ }
+
+ CTEAssert(Conn->tc_refcnt == 1);
+ Conn->tc_flags &= ~CONN_DISACC;
+ } else
+ NeedClose = TRUE;
+
+ Conn->tc_refcnt = 0;
+ CTEFreeLock(&AddrObjTableLock, ConnTableHandle);
+
+ if (NeedClose) {
+ CloseDone(Conn, AOTableHandle);
+ } else {
+ CTEFreeLock(&ConnTableLock, AOTableHandle);
+ (*Rtn)(Context, TDI_SUCCESS, 0);
+ }
+
+}
+
+
+//* FreeConnReq - Free a connection request structure.
+//
+// Called to free a connection request structure.
+//
+// Input: FreedReq - Connection request structure to be freed.
+//
+// Returns: Nothing.
+//
+void
+FreeConnReq(TCPConnReq *FreedReq)
+{
+#ifdef NT
+ PSINGLE_LIST_ENTRY BufferLink;
+
+ CTEStructAssert(FreedReq, tcr);
+
+ BufferLink = STRUCT_OF(
+ SINGLE_LIST_ENTRY,
+ &(FreedReq->tcr_req.tr_q.q_next),
+ Next
+ );
+
+ ExInterlockedPushEntrySList(
+ &ConnReqFree,
+ BufferLink,
+ &ConnReqFreeLock
+ );
+
+#else // NT
+ TCPConnReq **Temp;
+
+ CTEStructAssert(FreedReq, tcr);
+
+ Temp = (TCPConnReq **)&FreedReq->tcr_req.tr_q.q_next;
+ *Temp = ConnReqFree;
+ ConnReqFree = FreedReq;
+
+#endif // NT
+}
+
+//* GetConnReq - Get a connection request structure.
+//
+// Called to get a connection request structure.
+//
+// Input: Nothing.
+//
+// Returns: Pointer to ConnReq structure, or NULL if none.
+//
+TCPConnReq *
+GetConnReq(void)
+{
+ TCPConnReq *Temp;
+
+#ifdef NT
+ PSINGLE_LIST_ENTRY BufferLink;
+ Queue *QueuePtr;
+ TCPReq *ReqPtr;
+
+ BufferLink = ExInterlockedPopEntrySList(
+ &ConnReqFree,
+ &ConnReqFreeLock
+ );
+
+ if (BufferLink != NULL) {
+ QueuePtr = STRUCT_OF(Queue, BufferLink, q_next);
+ ReqPtr = STRUCT_OF(TCPReq, QueuePtr, tr_q);
+ Temp = STRUCT_OF(TCPConnReq, ReqPtr, tcr_req);
+ CTEStructAssert(Temp, tcr);
+ }
+ else {
+ if (NumConnReq < MaxConnReq)
+ Temp = CTEAllocMem(sizeof(TCPConnReq));
+ else
+ Temp = NULL;
+
+ if (Temp != NULL) {
+ ExInterlockedAddUlong(&NumConnReq, 1, &ConnReqFreeLock);
+#ifdef DEBUG
+ Temp->tcr_req.tr_sig = tr_signature;
+ Temp->tcr_sig = tcr_signature;
+#endif
+ }
+ }
+
+#else // NT
+
+ Temp = ConnReqFree;
+ if (Temp != NULL)
+ ConnReqFree = (TCPConnReq *)Temp->tcr_req.tr_q.q_next;
+ else {
+ if (NumConnReq < MaxConnReq)
+ Temp = CTEAllocMem(sizeof(TCPConnReq));
+ else
+ Temp = NULL;
+
+ if (Temp != NULL) {
+ NumConnReq++;
+#ifdef DEBUG
+ Temp->tcr_req.tr_sig = tr_signature;
+ Temp->tcr_sig = tcr_signature;
+#endif
+ }
+ }
+
+#endif // NT
+
+ return Temp;
+}
+
+//* GetConnFromConnID - Get a Connection from a connection ID.
+//
+// Called to obtain a Connection pointer from a ConnID. We don't actually
+// check the connection pointer here, but we do bounds check the input ConnID
+// and make sure the instance fields match.
+// We assume the caller has taken the ConnTable lock.
+//
+// Input: ConnID - Connection ID to find a pointer for.
+//
+// Returns: Pointer to the TCPConn, or NULL.
+//
+TCPConn *
+GetConnFromConnID(uint ConnID)
+{
+ uint ConnIndex = CONN_INDEX(ConnID);
+ TCPConn *MatchingConn;
+
+ if (ConnIndex < ConnTableSize) {
+ MatchingConn = (*ConnTable)[ConnIndex];
+ if (MatchingConn != NULL) {
+ CTEStructAssert(MatchingConn, tc);
+ if (MatchingConn->tc_inst != CONN_INST(ConnID))
+ MatchingConn = NULL;
+ }
+ } else
+ MatchingConn = NULL;
+
+ return MatchingConn;
+
+
+}
+
+//* GetConnID - Get a ConnTable slot.
+//
+// Called during OpenConnection to find a free slot in the ConnTable and
+// set it up with a connection. We assume the caller holds the lock on the
+// TCB ConnTable when we are called.
+//
+// Input: NewConn - Connection to enter into slot..
+//
+// Returns: A ConnId to use.
+//
+uint
+GetConnID(TCPConn *NewConn)
+{
+ uint CurrConnID;
+ uint i; // Index variable.
+
+ // Keep doing this until it works.
+ for (;;) {
+ CurrConnID = NextConnIndex;
+
+ for (i = 0; i < ConnTableSize; i++ ) {
+ if (CurrConnID == ConnTableSize)
+ CurrConnID = 0; // Wrapped, start at 0.
+
+ if ((*ConnTable)[CurrConnID] == NULL)
+ break; // Found a free one.
+
+ ++CurrConnID;
+ }
+
+ if (i < ConnTableSize) {
+ // We found a free slot.
+ (*ConnTable)[CurrConnID] = NewConn;
+ NextConnIndex = CurrConnID + 1;
+ ConnInst++;
+ NewConn->tc_inst = ConnInst;
+ return MAKE_CONN_ID(CurrConnID, ConnInst);
+ }
+
+ // Didn't find a free slot. Grow the table.
+ if (ConnTableSize != MaxConnections) {
+ uint NewTableSize;
+ TCPConnTable *NewTable;
+
+ NewTableSize = MIN(ConnTableSize + GROW_DELTA, MaxConnections);
+ NewTable = CTEAllocMem(NewTableSize * sizeof(TCPConn *));
+ if (NewTable != NULL) {
+ TCPConnTable *OldTable;
+ // We allocated it. Copy the old table in, and update ptrs and
+ // size.
+ CTEMemSet(NewTable, 0, NewTableSize * sizeof(TCPConn *));
+ CTEMemCopy(NewTable, ConnTable, ConnTableSize *
+ (sizeof (TCPConn *)));
+ OldTable = ConnTable;
+ ConnTable = NewTable;
+ ConnTableSize = NewTableSize;
+ if (OldTable != NULL)
+ CTEFreeMem(OldTable);
+ // Try it again, from the top.
+ continue;
+ } else {
+ // Couldn't grow the table.
+ return INVALID_CONN_ID;
+ }
+
+ } else {
+ // Table's already at the maximum allowable size.
+ return INVALID_CONN_ID;
+ }
+ }
+
+
+}
+
+//* FreeConnID - Free a ConnTable slot.
+//
+// Called when we're done with a ConnID. We assume the caller holds the lock
+// on the TCB ConnTable when we are called.
+//
+// Input: ConnID - Connection ID to be freed.
+//
+// Returns: Nothing.
+//
+void
+FreeConnID(uint ConnID)
+{
+ uint Index = CONN_INDEX(ConnID); // Index into conn table.
+
+ CTEAssert(Index < ConnTableSize);
+ CTEAssert((*ConnTable)[Index] != NULL);
+ CTEStructAssert((*ConnTable)[Index], tc);
+
+ FREE_CONN_INDEX(Index);
+
+}
+
+//* MapIPError - Map an IP error to a TDI error.
+//
+// Called to map an input IP error code to a TDI error code. If we can't,
+// we return the provided default.
+//
+// Input: IPError - Error code to be mapped.
+// Default - Default error code to return.
+//
+// Returns: Mapped TDI error.
+//
+TDI_STATUS
+MapIPError(IP_STATUS IPError, TDI_STATUS Default)
+{
+ switch (IPError) {
+
+ case IP_DEST_NET_UNREACHABLE:
+ return TDI_DEST_NET_UNREACH;
+ case IP_DEST_HOST_UNREACHABLE:
+ return TDI_DEST_HOST_UNREACH;
+ case IP_DEST_PROT_UNREACHABLE:
+ return TDI_DEST_PROT_UNREACH;
+ case IP_DEST_PORT_UNREACHABLE:
+ return TDI_DEST_PORT_UNREACH;
+ default:
+ return Default;
+ }
+}
+
+//* FinishRemoveTCBFromConn - Finish removing a TCB from a conn structure.
+//
+// Called when we have the locks we need and we just want to pull the
+// TCB off the connection. The caller must hold the ConnTableLock before
+// calling this.
+//
+// Input: RemovedTCB - TCB to be removed.
+//
+// Returns: Nothing.
+//
+void
+FinishRemoveTCBFromConn(TCB *RemovedTCB)
+{
+ TCPConn *Conn;
+ CTELockHandle AOHandle, TCBHandle;
+ AddrObj *AO;
+
+ if ((( Conn = RemovedTCB->tcb_conn ) != NULL ) &&
+ ( Conn->tc_tcb == RemovedTCB ) ) {
+ CTEStructAssert(Conn, tc);
+
+ AO = Conn->tc_ao;
+
+ if (AO != NULL) {
+ CTEGetLockAtDPC(&AO->ao_lock, &AOHandle);
+ CTEGetLockAtDPC(&RemovedTCB->tcb_lock, &TCBHandle);
+
+ // Need to double check this is still correct.
+
+ if (Conn == RemovedTCB->tcb_conn) {
+ // Everything still looks good.
+ REMOVEQ(&Conn->tc_q);
+ ENQUEUE(&AO->ao_idleq, &Conn->tc_q);
+ } else
+ Conn = RemovedTCB->tcb_conn;
+
+ CTEFreeLockFromDPC(&AO->ao_lock, TCBHandle);
+ } else {
+ CTEGetLockAtDPC(&RemovedTCB->tcb_lock, &AOHandle);
+ Conn = RemovedTCB->tcb_conn;
+ }
+
+ if (Conn != NULL) {
+ if (Conn->tc_tcb == RemovedTCB)
+ Conn->tc_tcb = NULL;
+ else
+ CTEAssert(Conn->tc_tcb == NULL);
+ }
+
+ CTEFreeLockFromDPC(&RemovedTCB->tcb_lock, AOHandle);
+ }
+}
+
+//* RemoveTCBFromConn - Remove a TCB from a Conn structure.
+//
+// Called when we need to disassociate a TCB from a connection structure.
+// All we do is get the appropriate locks and call FinishRemoveTCBFromConn.
+//
+// Input: RemovedTCB - TCB to be removed.
+//
+// Returns: Nothing.
+//
+void
+RemoveTCBFromConn(TCB *RemovedTCB)
+{
+ CTELockHandle ConnHandle, TCBHandle;
+
+ CTEStructAssert(RemovedTCB, tcb);
+
+ CTEGetLock(&ConnTableLock, &ConnHandle);
+
+ FinishRemoveTCBFromConn(RemovedTCB);
+
+ CTEFreeLock(&ConnTableLock, ConnHandle);
+
+}
+
+//* RemoveConnFromTCB - Remove a conn from a TCB.
+//
+// Called when we want to break the final association between a connection
+// and a TCB.
+//
+// Input: RemoveTCB - TCB to be removed.
+//
+// Returns: Nothing.
+//
+void
+RemoveConnFromTCB(TCB *RemoveTCB)
+{
+ ConnDoneRtn DoneRtn = NULL;
+ CTELockHandle ConnHandle, TCBHandle;
+ TCPConn *Conn;
+
+ CTEGetLock(&ConnTableLock, &ConnHandle);
+ CTEGetLock(&RemoveTCB->tcb_lock, &TCBHandle);
+
+
+ if ((Conn = RemoveTCB->tcb_conn) != NULL) {
+
+ CTEStructAssert(Conn, tc);
+
+ if (--(Conn->tc_refcnt) == 0)
+ DoneRtn = Conn->tc_donertn;
+
+ RemoveTCB->tcb_conn = NULL;
+ }
+
+ CTEFreeLock(&RemoveTCB->tcb_lock, TCBHandle);
+
+ if (DoneRtn != NULL)
+ (*DoneRtn)(Conn, ConnHandle);
+ else
+ CTEFreeLock(&ConnTableLock, ConnHandle);
+}
+
+
+//* CloseTCB - Close a TCB.
+//
+// Called when we are done with a TCB, and want to free it. We'll remove
+// him from any tables that he's in, and destroy any outstanding requests.
+//
+// Input: ClosedTCB - TCB to be closed.
+// Handle - Lock handle for TCB.
+//
+// Returns: Nothing.
+//
+void
+CloseTCB(TCB *ClosedTCB, CTELockHandle Handle)
+{
+ CTELockHandle ConnTableHandle, TCBTableHandle;
+ uchar OrigState = ClosedTCB->tcb_state;
+ TDI_STATUS Status;
+ uint OKToFree;
+
+
+ CTEStructAssert(ClosedTCB, tcb);
+ CTEAssert(ClosedTCB->tcb_refcnt == 0);
+ CTEAssert(ClosedTCB->tcb_state != TCB_CLOSED);
+ CTEAssert(ClosedTCB->tcb_pending & DEL_PENDING);
+
+ CTEFreeLock(&ClosedTCB->tcb_lock, Handle);
+
+ // We need to get the ConnTable, TCBTable, and TCB locks to pull
+ // this guy from all the appropriate tables.
+ CTEGetLock(&ConnTableLock, &ConnTableHandle);
+
+ // We'll check to make sure that our state isn't CLOSED. This should never
+ // happen, since nobody should call TryToCloseTCB when the state is
+ // closed, or take the reference count if we're closing. Nevertheless,
+ // we'll double check as a safety measure.
+ if (ClosedTCB->tcb_state == TCB_CLOSED) {
+ DEBUGCHK;
+ CTEFreeLock(&ConnTableLock, ConnTableHandle);
+ return;
+ }
+
+ // Update SNMP counters. If we're in SYN-SENT or SYN-RCVD, this is a failed
+ // connection attempt. If we're in ESTABLISED or CLOSE-WAIT, treat this
+ // as an 'Established Reset' event.
+ if (ClosedTCB->tcb_state == TCB_SYN_SENT ||
+ ClosedTCB->tcb_state == TCB_SYN_RCVD)
+ TStats.ts_attemptfails++;
+ else
+ if (ClosedTCB->tcb_state == TCB_ESTAB ||
+ ClosedTCB->tcb_state == TCB_CLOSE_WAIT) {
+ TStats.ts_estabresets++;
+ TStats.ts_currestab--;
+ CTEAssert(*(int *)&TStats.ts_currestab >= 0);
+ }
+
+ ClosedTCB->tcb_state = TCB_CLOSED;
+
+
+ // Remove the TCB from it's associated TCPConn structure, if it has one.
+ FinishRemoveTCBFromConn(ClosedTCB);
+
+ CTEGetLockAtDPC(&TCBTableLock, &TCBTableHandle);
+ CTEGetLockAtDPC(&ClosedTCB->tcb_lock, &Handle);
+
+ OKToFree = RemoveTCB(ClosedTCB);
+
+ // He's been pulled from the appropriate places so nobody can find him.
+ // Free the locks, and proceed to destroy any requests, etc.
+ CTEFreeLockFromDPC(&ClosedTCB->tcb_lock, Handle);
+ CTEFreeLockFromDPC(&TCBTableLock, TCBTableHandle);
+ CTEFreeLock(&ConnTableLock, ConnTableHandle);
+
+ if (SYNC_STATE(OrigState) && !GRACEFUL_CLOSED_STATE(OrigState)) {
+ if (ClosedTCB->tcb_flags & NEED_RST)
+ SendRSTFromTCB(ClosedTCB);
+ }
+
+ (*LocalNetInfo.ipi_freeopts)(&ClosedTCB->tcb_opt);
+ (*LocalNetInfo.ipi_closerce)(ClosedTCB->tcb_rce);
+
+ if (ClosedTCB->tcb_closereason & TCB_CLOSE_RST)
+ Status = TDI_CONNECTION_RESET;
+ else if (ClosedTCB->tcb_closereason & TCB_CLOSE_ABORTED)
+ Status = TDI_CONNECTION_ABORTED;
+ else if (ClosedTCB->tcb_closereason & TCB_CLOSE_TIMEOUT)
+ Status = MapIPError(ClosedTCB->tcb_error, TDI_TIMED_OUT);
+ else if (ClosedTCB->tcb_closereason & TCB_CLOSE_REFUSED)
+ Status = TDI_CONN_REFUSED;
+ else if (ClosedTCB->tcb_closereason & TCB_CLOSE_UNREACH)
+ Status = MapIPError(ClosedTCB->tcb_error, TDI_DEST_UNREACHABLE);
+ else
+ Status = TDI_SUCCESS;
+
+ // Now complete any outstanding requests on the TCB.
+ if (ClosedTCB->tcb_connreq != NULL) {
+ TCPConnReq *ConnReq = ClosedTCB->tcb_connreq;
+ CTEStructAssert(ConnReq, tcr);
+
+ (*ConnReq->tcr_req.tr_rtn)(ConnReq->tcr_req.tr_context, Status, 0);
+ FreeConnReq(ConnReq);
+ }
+
+ if (ClosedTCB->tcb_discwait != NULL) {
+ TCPConnReq *ConnReq = ClosedTCB->tcb_discwait;
+ CTEStructAssert(ConnReq, tcr);
+
+ (*ConnReq->tcr_req.tr_rtn)(ConnReq->tcr_req.tr_context, Status, 0);
+ FreeConnReq(ConnReq);
+ }
+
+ while (!EMPTYQ(&ClosedTCB->tcb_sendq)) {
+ TCPReq *Req;
+ TCPSendReq *SendReq;
+ long Result;
+
+ DEQUEUE(&ClosedTCB->tcb_sendq, Req, TCPReq, tr_q);
+
+ CTEStructAssert(Req, tr);
+ SendReq = (TCPSendReq *)Req;
+ CTEStructAssert(SendReq, tsr);
+
+ // Decrement the initial reference put on the buffer when it was
+ // allocated. This reference would have been decremented if the
+ // send had been acknowledged, but then the send would not still
+ // be on the tcb_sendq.
+ Result = CTEInterlockedDecrementLong(
+ &(SendReq->tsr_refcnt)
+ );
+
+ CTEAssert(Result >= 0);
+
+ if (Result <= 0) {
+ // If we've sent directly from this send, NULL out the next
+ // pointer for the last buffer in the chain.
+ if (SendReq->tsr_lastbuf != NULL) {
+ NDIS_BUFFER_LINKAGE(SendReq->tsr_lastbuf) = NULL;
+ SendReq->tsr_lastbuf = NULL;
+ }
+
+ (*Req->tr_rtn)(Req->tr_context, Status, 0);
+ FreeSendReq(SendReq);
+ } else {
+ // The send request will be freed when all outstanding references
+ // to it have completed.
+ SendReq->tsr_req.tr_status = Status;
+ }
+ }
+
+ while (ClosedTCB->tcb_rcvhead != NULL) {
+ TCPRcvReq *RcvReq;
+
+ RcvReq = ClosedTCB->tcb_rcvhead;
+ CTEStructAssert(RcvReq, trr);
+ ClosedTCB->tcb_rcvhead = RcvReq->trr_next;
+ (*RcvReq->trr_rtn)(RcvReq->trr_context, Status, 0);
+ FreeRcvReq(RcvReq);
+ }
+
+ while (ClosedTCB->tcb_exprcv != NULL) {
+ TCPRcvReq *RcvReq;
+
+ RcvReq = ClosedTCB->tcb_exprcv;
+ CTEStructAssert(RcvReq, trr);
+ ClosedTCB->tcb_exprcv = RcvReq->trr_next;
+ (*RcvReq->trr_rtn)(RcvReq->trr_context, Status, 0);
+ FreeRcvReq(RcvReq);
+ }
+
+ if (ClosedTCB->tcb_pendhead != NULL)
+ FreeRBChain(ClosedTCB->tcb_pendhead);
+
+ if (ClosedTCB->tcb_urgpending != NULL)
+ FreeRBChain(ClosedTCB->tcb_urgpending);
+
+ while (ClosedTCB->tcb_raq != NULL) {
+ TCPRAHdr *Hdr;
+
+ Hdr = ClosedTCB->tcb_raq;
+ CTEStructAssert(Hdr, trh);
+ ClosedTCB->tcb_raq = Hdr->trh_next;
+ if (Hdr->trh_buffer != NULL)
+ FreeRBChain(Hdr->trh_buffer);
+
+ CTEFreeMem(Hdr);
+ }
+
+ RemoveConnFromTCB(ClosedTCB);
+
+ if (OKToFree) {
+ FreeTCB(ClosedTCB);
+ } else {
+ CTEGetLock(&TCBTableLock, &TCBTableHandle);
+ ClosedTCB->tcb_walkcount--;
+ if (ClosedTCB->tcb_walkcount == 0) {
+ FreeTCB(ClosedTCB);
+ }
+ CTEFreeLock(&TCBTableLock, TCBTableHandle);
+ }
+
+}
+
+//* TryToCloseTCB - Try to close a TCB.
+//
+// Called when we need to close a TCB, but don't know if we can. If
+// the reference count is 0, we'll call CloseTCB to deal with it.
+// Otherwise we'll set the DELETE_PENDING bit and deal with it when
+// the ref. count goes to 0. We assume the TCB is locked when we are called.
+//
+// Input: ClosedTCB - TCB to be closed.
+// Reason - Reason we're closing.
+// Handle - Lock handle for TCB.
+//
+// Returns: Nothing.
+//
+void
+TryToCloseTCB(TCB *ClosedTCB, uchar Reason, CTELockHandle Handle)
+{
+ CTEStructAssert(ClosedTCB, tcb);
+ CTEAssert(ClosedTCB->tcb_state != TCB_CLOSED);
+
+ ClosedTCB->tcb_closereason |= Reason;
+
+ if (ClosedTCB->tcb_pending & DEL_PENDING) {
+ DEBUGCHK;
+ CTEFreeLock(&ClosedTCB->tcb_lock, Handle);
+ return;
+ }
+
+ ClosedTCB->tcb_pending |= DEL_PENDING;
+ ClosedTCB->tcb_slowcount++;
+ ClosedTCB->tcb_fastchk |= TCP_FLAG_SLOW;
+
+ if (ClosedTCB->tcb_refcnt == 0)
+ CloseTCB(ClosedTCB, Handle);
+ else {
+ CTEFreeLock(&ClosedTCB->tcb_lock, Handle);
+ }
+}
+
+
+//* DerefTCB - Dereference a TCB.
+//
+// Called when we're done with a TCB, and want to let exclusive user
+// have a shot. We dec. the refcount, and if it goes to zero and there
+// are pending actions, we'll perform one of the pending actions.
+//
+// Input: DoneTCB - TCB to be dereffed.
+// Handle - Lock handle to be used when freeing TCB lock.
+//
+// Returns: Nothing.
+//
+void
+DerefTCB(TCB *DoneTCB, CTELockHandle Handle)
+{
+
+ CTEAssert(DoneTCB->tcb_refcnt != 0);
+ if (--DoneTCB->tcb_refcnt == 0) {
+ if (DoneTCB->tcb_pending == 0) {
+ CTEFreeLock(&DoneTCB->tcb_lock, Handle);
+ return;
+ } else {
+ // BUGBUG handle pending actions.
+ if (DoneTCB->tcb_pending & DEL_PENDING)
+ CloseTCB(DoneTCB, Handle);
+ else
+ DEBUGCHK;
+ return;
+ }
+ }
+
+ CTEFreeLock(&DoneTCB->tcb_lock, Handle);
+ return;
+}
+
+
+//** TdiOpenConnection - Open a connection.
+//
+// This is the TDI Open Connection entry point. We open a connection,
+// and save the caller's connection context. A TCPConn structure is allocated
+// here, but a TCB isn't allocated until the Connect or Listen is done.
+//
+// Input: Request - Pointed to a TDI request structure.
+// Context - Connection context to be saved for connection.
+//
+// Returns: Status of attempt to open the connection.
+//
+TDI_STATUS
+TdiOpenConnection(PTDI_REQUEST Request, PVOID Context)
+{
+ TCPConn *NewConn; // The newly opened connection.
+ CTELockHandle Handle; // Lock handle for TCPConnTable.
+ uint ConnID; // New ConnID.
+ TDI_STATUS Status; // Status of this request.
+
+ NewConn = CTEAllocMem(sizeof(TCPConn));
+
+ if (NewConn != NULL) { // We allocated a connection.
+ CTEMemSet(NewConn, 0, sizeof(TCPConn));
+#ifdef DEBUG
+ NewConn->tc_sig = tc_signature;
+#endif
+ NewConn->tc_tcb = NULL;
+ NewConn->tc_ao = NULL;
+ NewConn->tc_context = Context;
+
+ CTEGetLock(&ConnTableLock, &Handle);
+ ConnID = GetConnID(NewConn);
+ if (ConnID != INVALID_CONN_ID) {
+ // We successfully got a ConnID.
+ Request->Handle.ConnectionContext = (CONNECTION_CONTEXT)ConnID;
+ NewConn->tc_refcnt = 0;
+ NewConn->tc_flags = 0;
+ NewConn->tc_tcbflags = NAGLING | (BSDUrgent ? BSD_URGENT : 0);
+ if (DefaultRcvWin != 0) {
+ NewConn->tc_window = DefaultRcvWin;
+ NewConn->tc_flags |= CONN_WINSET;
+ } else
+ NewConn->tc_window = DEFAULT_RCV_WIN;
+
+ NewConn->tc_donertn = DummyDone;
+ Status = TDI_SUCCESS;
+ } else {
+ CTEFreeMem(NewConn);
+ Status = TDI_NO_RESOURCES;
+ }
+
+ CTEFreeLock(&ConnTableLock, Handle);
+ return Status;
+ }
+
+ // Couldn't get a connection.
+ return TDI_NO_RESOURCES;
+
+}
+
+//* RemoveConnFromAO - Remove a connection from an AddrObj.
+//
+// A little utility routine to remove a connection from an AddrObj.
+// We run down the connections on the AO, and when we find him we splice
+// him out. We assume the caller holds the locks on the AddrObj and the
+// TCPConnTable lock.
+//
+// Input: AO - AddrObj to remove from.
+// Conn - Conn to remove.
+//
+// Returns: Nothing.
+//
+void
+RemoveConnFromAO(AddrObj *AO, TCPConn *Conn)
+{
+
+ CTEStructAssert(AO, ao);
+ CTEStructAssert(Conn, tc);
+
+ REMOVEQ(&Conn->tc_q);
+ Conn->tc_ao = NULL;
+
+
+}
+
+//* TdiCloseConnection - Close a connection.
+//
+// Called when the user is done with a connection, and wants to close it.
+// We look the connection up in our table, and if we find it we'll remove
+// the connection from the AddrObj it's associate with (if any). If there's
+// a TCB associated with the connection we'll close it also.
+//
+// There are some interesting wrinkles related to closing while a TCB
+// is still referencing the connection (i.e. tc_refcnt != 0) or while a
+// disassociate address is in progress. See below for more details.
+//
+// Input: Request - Request identifying connection to be closed.
+//
+// Returns: Status of attempt to close.
+//
+TDI_STATUS
+TdiCloseConnection(PTDI_REQUEST Request)
+{
+ uint ConnID = (uint)Request->Handle.ConnectionContext;
+ CTELockHandle TableHandle;
+ TCPConn *Conn;
+ TDI_STATUS Status;
+
+ CTEGetLock(&ConnTableLock, &TableHandle);
+
+ // We have the locks we need. Try to find a connection.
+ Conn = GetConnFromConnID(ConnID);
+
+ if (Conn != NULL) {
+ CTELockHandle TCBHandle;
+ TCB *ConnTCB;
+
+ // We found the connection. Free the ConnID and mark the connection
+ // as closing.
+
+ CTEStructAssert(Conn, tc);
+
+ FreeConnID(ConnID);
+
+ Conn->tc_flags |= CONN_CLOSING;
+
+ // See if there's a TCB referencing this connection.
+ // If there is, we'll need to wait until he's done before closing him.
+ // We'll hurry the process along if we still have a pointer to him.
+
+ if (Conn->tc_refcnt != 0) {
+ CTEReqCmpltRtn Rtn;
+ PVOID Context;
+
+ // A connection still references him. Save the current rtn stuff
+ // in case we are in the middle of disassociating him from an
+ // address, and store the caller's callback routine and our done
+ // routine.
+ Rtn = Conn->tc_rtn;
+ Context = Conn->tc_rtncontext;
+
+ Conn->tc_rtn = Request->RequestNotifyObject;
+ Conn->tc_rtncontext = Request->RequestContext;
+ Conn->tc_donertn = CloseDone;
+
+ // See if we're in the middle of disassociating him
+ if (Conn->tc_flags & CONN_DISACC) {
+
+ // We are disassociating him. We'll free the conn table lock
+ // now and fail the disassociate request. Note that when
+ // we free the lock the refcount could go to zero. This is
+ // OK, because we've already stored the neccessary info. in
+ // the connection so the caller will get called back if it
+ // does. From this point out we return PENDING, so a callback
+ // is OK. We've marked him as closing, so the disassoc done
+ // routine will bail out if we've interrupted him. If the ref.
+ // count does go to zero, Conn->tc_tcb would have to be NULL,
+ // so in that case we'll just fall out of this routine.
+
+ CTEFreeLock(&ConnTableLock, TableHandle);
+ (*Rtn)(Context, (uint) TDI_REQ_ABORTED, 0);
+ CTEGetLock(&ConnTableLock, &TableHandle);
+ }
+
+
+ ConnTCB = Conn->tc_tcb;
+ if (ConnTCB != NULL) {
+ CTEStructAssert(ConnTCB, tcb);
+ // We have a TCB. Take the lock on him and get ready to
+ // close him.
+ CTEGetLock(&ConnTCB->tcb_lock, &TCBHandle);
+ if (ConnTCB->tcb_state != TCB_CLOSED) {
+ ConnTCB->tcb_flags |= NEED_RST;
+ CTEFreeLock(&ConnTableLock, TCBHandle);
+ if (!CLOSING(ConnTCB))
+ TryToCloseTCB(ConnTCB, TCB_CLOSE_ABORTED, TableHandle);
+ else
+ CTEFreeLock(&ConnTCB->tcb_lock, TableHandle);
+ return TDI_PENDING;
+ } else {
+ // He's already closing. This should be harmless, but check
+ // this case.
+ DEBUGCHK;
+ CTEFreeLock(&ConnTCB->tcb_lock, TCBHandle);
+ }
+ }
+ Status = TDI_PENDING;
+
+ } else {
+ // We have a connection that we can close. Finish the close.
+ Conn->tc_rtn = DummyCmplt;
+ CloseDone(Conn, TableHandle);
+ return TDI_SUCCESS;
+ }
+
+
+ } else
+ Status = TDI_INVALID_CONNECTION;
+
+ // We're done with the connection. Go ahead and free him.
+ CTEFreeLock(&ConnTableLock, TableHandle);
+
+ return Status;
+
+}
+
+
+//* TdiAssociateAddress - Associate an address with a connection.
+//
+// Called to associate an address with a connection. We do a minimal
+// amount of sanity checking, and then put the connection on the AddrObj's
+// list.
+//
+// Input: Request - Pointer to request structure for this request.
+// AddrHandle - Address handle to associate connection with.
+//
+// Returns: Status of attempt to associate.
+//
+TDI_STATUS
+TdiAssociateAddress(PTDI_REQUEST Request, HANDLE AddrHandle)
+{
+ CTELockHandle TableHandle, AOHandle;
+ AddrObj *AO;
+ uint ConnID = (uint)Request->Handle.ConnectionContext;
+ TCPConn *Conn;
+ TDI_STATUS Status;
+
+#ifdef VXD
+ AO = GetIndexedAO((uint)AddrHandle);
+ if (AO == NULL)
+ return TDI_ADDR_INVALID;
+#else
+ AO = (AddrObj *)AddrHandle;
+#endif
+ CTEStructAssert(AO, ao);
+
+ CTEGetLock(&ConnTableLock, &TableHandle);
+ CTEGetLock(&AO->ao_lock, &AOHandle);
+
+ Conn = GetConnFromConnID(ConnID);
+ if (Conn != NULL) {
+ CTEStructAssert(Conn, tc);
+
+ if (Conn->tc_ao != NULL) {
+ // It's already associated. Error out.
+ DEBUGCHK;
+ Status = TDI_ALREADY_ASSOCIATED;
+ } else {
+ Conn->tc_ao = AO;
+ CTEAssert(Conn->tc_tcb == NULL);
+ ENQUEUE(&AO->ao_idleq, &Conn->tc_q);
+ Status = TDI_SUCCESS;
+ }
+ } else
+ Status = TDI_INVALID_CONNECTION;
+
+ CTEFreeLock(&AO->ao_lock, AOHandle);
+ CTEFreeLock(&ConnTableLock, TableHandle);
+ return Status;
+}
+
+//* TdiDisAssociateAddress - Disassociate a connection from an address.
+//
+// The TDI entry point to disassociate a connection from an address. The
+// connection must actually be associated and not connected to anything.
+//
+// Input: Request - Pointer to the request structure for this
+// command.
+//
+// Returns: Status of request.
+//
+TDI_STATUS
+TdiDisAssociateAddress(PTDI_REQUEST Request)
+{
+ uint ConnID = (uint)Request->Handle.ConnectionContext;
+ CTELockHandle AOTableHandle, ConnTableHandle, AOHandle;
+ TCPConn *Conn;
+ AddrObj *AO;
+ TDI_STATUS Status;
+
+ CTEGetLock(&AddrObjTableLock, &AOTableHandle);
+ CTEGetLock(&ConnTableLock, &ConnTableHandle);
+ Conn = GetConnFromConnID(ConnID);
+
+ if (Conn != NULL) {
+ // The connection actually exists!
+
+ CTEStructAssert(Conn, tc);
+ AO = Conn->tc_ao;
+ if (AO != NULL) {
+ CTEStructAssert(AO, ao);
+ // And it's associated.
+ CTEGetLock(&AO->ao_lock, &AOHandle);
+ // If there's no connection currently active, go ahead and remove
+ // him from the AddrObj. If a connection is active error the
+ // request out.
+ if (Conn->tc_tcb == NULL) {
+ if (Conn->tc_refcnt == 0) {
+ RemoveConnFromAO(AO, Conn);
+ Status = TDI_SUCCESS;
+ } else {
+ // He shouldn't be closing, or we couldn't have found him.
+ CTEAssert(!(Conn->tc_flags & CONN_CLOSING));
+
+ Conn->tc_rtn = Request->RequestNotifyObject;
+ Conn->tc_rtncontext = Request->RequestContext;
+ Conn->tc_donertn = DisassocDone;
+ Conn->tc_flags |= CONN_DISACC;
+ Status = TDI_PENDING;
+ }
+
+ } else
+ Status = TDI_CONNECTION_ACTIVE;
+ CTEFreeLock(&AO->ao_lock, AOHandle);
+ } else
+ Status = TDI_NOT_ASSOCIATED;
+ } else
+ Status = TDI_INVALID_CONNECTION;
+
+ CTEFreeLock(&ConnTableLock, ConnTableHandle);
+ CTEFreeLock(&AddrObjTableLock, AOTableHandle);
+
+ return Status;
+
+}
+
+//* ProcessUserOptions - Process options from the user.
+//
+// A utility routine to process options from the user. We fill in the
+// optinfo structure, and if we have options we call ip to check on them.
+//
+// Input: Info - Info structure containing options to be processed.
+// OptInfo - Info structure to be filled in.
+//
+// Returns: TDI_STATUS of attempt.
+//
+TDI_STATUS
+ProcessUserOptions(PTDI_CONNECTION_INFORMATION Info, IPOptInfo *OptInfo)
+{
+ TDI_STATUS Status;
+
+ (*LocalNetInfo.ipi_initopts)(OptInfo);
+
+ if (Info != NULL && Info->Options != NULL) {
+ IP_STATUS OptStatus;
+
+ OptStatus = (*LocalNetInfo.ipi_copyopts)(Info->Options,
+ Info->OptionsLength, OptInfo);
+ if (OptStatus != IP_SUCCESS) {
+ if (OptStatus == IP_NO_RESOURCES)
+ Status = TDI_NO_RESOURCES;
+ else
+ Status = TDI_BAD_OPTION;
+ } else
+ Status = TDI_SUCCESS;
+ } else {
+ Status = TDI_SUCCESS;
+ }
+
+ return Status;
+
+
+}
+
+//* InitTCBFromConn - Initialize a TCB from information in a Connection.
+//
+// Called from Connect and Listen processing to initialize a new TCB from
+// information in the connection. We assume the AddrObjTableLock and
+// ConnTableLocks are held when we are called, or that the caller has some
+// other way of making sure that the referenced AO doesn't go away in the middle
+// of operation.
+//
+// Input: Conn - Connection to initialize from.
+// NewTCB - TCB to be initialized.
+// Addr - Remote addressing and option info for NewTCB.
+// AOLocked - True if the called has the address object locked.
+//
+// Returns: TDI_STATUS of init attempt.
+//
+TDI_STATUS
+InitTCBFromConn(TCPConn *Conn, TCB *NewTCB,
+ PTDI_CONNECTION_INFORMATION Addr, uint AOLocked)
+{
+ CTELockHandle AOHandle;
+ TDI_STATUS Status;
+
+ CTEStructAssert(Conn, tc);
+
+ // We have a connection. Make sure it's associated with an address and
+ // doesn't already have a TCB attached.
+
+ if (Conn->tc_flags & CONN_INVALID)
+ return TDI_INVALID_CONNECTION;
+
+ if (Conn->tc_tcb == NULL) {
+ AddrObj *ConnAO;
+
+ ConnAO = Conn->tc_ao;
+ if (ConnAO != NULL) {
+ CTEStructAssert(ConnAO, ao);
+
+ if (!AOLocked) {
+ CTEGetLock(&ConnAO->ao_lock, &AOHandle);
+ }
+ NewTCB->tcb_saddr = ConnAO->ao_addr;
+ NewTCB->tcb_sport = ConnAO->ao_port;
+ NewTCB->tcb_rcvind = ConnAO->ao_rcv;
+ NewTCB->tcb_ricontext = ConnAO->ao_rcvcontext;
+ if (NewTCB->tcb_rcvind == NULL)
+ NewTCB->tcb_rcvhndlr = PendData;
+ else
+ NewTCB->tcb_rcvhndlr = IndicateData;
+
+ NewTCB->tcb_conncontext = Conn->tc_context;
+ NewTCB->tcb_flags |= Conn->tc_tcbflags;
+ NewTCB->tcb_defaultwin = Conn->tc_window;
+ NewTCB->tcb_rcvwin = Conn->tc_window;
+
+ if (Conn->tc_flags & CONN_WINSET)
+ NewTCB->tcb_flags |= WINDOW_SET;
+
+ if (NewTCB->tcb_flags & KEEPALIVE) {
+ NewTCB->tcb_alive = TCPTime;
+ NewTCB->tcb_kacount = 0;
+ }
+
+ if (!AOLocked) {
+ CTEFreeLock(&ConnAO->ao_lock, AOHandle);
+ }
+
+ // If we've been given options, we need to process them now.
+ if (Addr != NULL && Addr->Options != NULL)
+ NewTCB->tcb_flags |= CLIENT_OPTIONS;
+ Status = ProcessUserOptions(Addr, &NewTCB->tcb_opt);
+
+ return Status;
+ } else
+ return TDI_NOT_ASSOCIATED;
+ } else
+ return TDI_CONNECTION_ACTIVE;
+
+}
+
+//* TdiConnect - Establish a connection.
+//
+// The TDI connection establishment routine. Called when the client wants to
+// establish a connection, we validate his incoming parameters and kick
+// things off by sending a SYN.
+//
+// Input: Request - The request structure for this command.
+// Timeout - How long to wait for the request. The format
+// of this time is system specific - we use
+// a macro to convert to ticks.
+// RequestAddr - Pointer to a TDI_CONNECTION_INFORMATION
+// structure describing the destination.
+// ReturnAddr - Pointer to where to return information.
+//
+// Returns: Status of attempt to connect.
+//
+TDI_STATUS
+TdiConnect(PTDI_REQUEST Request, void *TO,
+ PTDI_CONNECTION_INFORMATION RequestAddr,
+ PTDI_CONNECTION_INFORMATION ReturnAddr)
+{
+ TCPConnReq *ConnReq; // Connection request to use.
+ IPAddr DestAddr;
+ ushort DestPort;
+ uchar AddrType;
+ TCPConn *Conn;
+ TCB *NewTCB;
+ uint ConnID = (uint)Request->Handle.ConnectionContext;
+ CTELockHandle AOTableHandle, ConnTableHandle, AOHandle;
+ AddrObj *AO;
+ TDI_STATUS Status;
+ CTELockHandle TCBHandle;
+ IPAddr SrcAddr;
+ ushort MSS;
+ TCP_TIME *Timeout;
+
+ // First, get and validate the remote address.
+ if (RequestAddr == NULL || RequestAddr->RemoteAddress == NULL ||
+ !GetAddress((PTRANSPORT_ADDRESS)RequestAddr->RemoteAddress, &DestAddr,
+ &DestPort))
+ return TDI_BAD_ADDR;
+
+ AddrType = (*LocalNetInfo.ipi_getaddrtype)(DestAddr);
+
+ if (AddrType == DEST_INVALID || IS_BCAST_DEST(AddrType) || DestPort == 0)
+ return TDI_BAD_ADDR;
+
+ // Now get a connection request. If we can't, bail out now.
+ ConnReq = GetConnReq();
+ if (ConnReq == NULL)
+ return TDI_NO_RESOURCES;
+
+ // Get a TCB, assuming we'll need one.
+ NewTCB = AllocTCB();
+ if (NewTCB == NULL) {
+ // Couldn't get a TCB.
+ FreeConnReq(ConnReq);
+ return TDI_NO_RESOURCES;
+ }
+
+ Timeout = (TCP_TIME *)TO;
+
+ if (Timeout != NULL && !INFINITE_CONN_TO(*Timeout)) {
+ ulong Ticks = TCP_TIME_TO_TICKS(*Timeout);
+ if (Ticks > MAX_CONN_TO_TICKS)
+ Ticks = MAX_CONN_TO_TICKS;
+ else
+ Ticks++;
+ ConnReq->tcr_timeout = (ushort)Ticks;
+ } else
+ ConnReq->tcr_timeout = 0;
+
+ ConnReq->tcr_flags = 0;
+ ConnReq->tcr_conninfo = ReturnAddr;
+ ConnReq->tcr_req.tr_rtn = Request->RequestNotifyObject;
+ ConnReq->tcr_req.tr_context = Request->RequestContext;
+ NewTCB->tcb_daddr = DestAddr;
+ NewTCB->tcb_dport = DestPort;
+
+ // Now find the real connection. If we find it, we'll make sure it's
+ // associated.
+ CTEGetLock(&AddrObjTableLock, &AOTableHandle);
+ CTEGetLock(&ConnTableLock, &ConnTableHandle);
+ Conn = GetConnFromConnID(ConnID);
+ if (Conn != NULL) {
+ uint Inserted;
+
+ CTEStructAssert(Conn, tc);
+
+ AO = Conn->tc_ao;
+
+ if (AO != NULL) {
+ CTEGetLock(&AO->ao_lock, &AOHandle);
+
+ CTEStructAssert(AO, ao);
+ Status = InitTCBFromConn(Conn, NewTCB, RequestAddr, TRUE);
+ if (Status == TDI_SUCCESS) {
+
+ // We've processed the options, and we know the destination
+ // address is good, and we have all the resources we need,
+ // so we can go ahead and open an RCE. If this works we'll
+ // put the TCB into the Connection and send a SYN.
+
+ // We're done with the AddrObjTable now, so we can free it's
+ // lock.
+ NewTCB->tcb_flags |= ACTIVE_OPEN;
+
+ CTEFreeLock(&AddrObjTableLock, AOHandle);
+
+ SrcAddr = (*LocalNetInfo.ipi_openrce)(DestAddr,
+ NewTCB->tcb_saddr, &NewTCB->tcb_rce, &AddrType, &MSS,
+ &NewTCB->tcb_opt);
+
+ if (IP_ADDR_EQUAL(SrcAddr, NULL_IP_ADDR)) {
+ // The request failed. We know the destination is good
+ // (we verified it above), so it must be unreachable.
+ CTEFreeLock(&AO->ao_lock, ConnTableHandle);
+ Status = TDI_DEST_UNREACHABLE;
+ goto error;
+ }
+
+ // OK, the RCE open worked. Enter the TCB into the connection.
+ CTEGetLock(&NewTCB->tcb_lock, &TCBHandle);
+ Conn->tc_tcb = NewTCB;
+ Conn->tc_refcnt++;
+ NewTCB->tcb_conn = Conn;
+ REMOVEQ(&Conn->tc_q);
+ ENQUEUE(&AO->ao_activeq, &Conn->tc_q);
+ CTEFreeLock(&ConnTableLock, TCBHandle);
+ CTEFreeLock(&AO->ao_lock, ConnTableHandle);
+
+
+ // If the caller didn't specify a local address, use what
+ // IP provided.
+ if (IP_ADDR_EQUAL(NewTCB->tcb_saddr, NULL_IP_ADDR))
+ NewTCB->tcb_saddr = SrcAddr;
+
+ // Until we have MTU discovery in place, hold the MSS down
+ // to 536 if we're going off net.
+ MSS -= sizeof(TCPHeader);
+
+ if (!PMTUDiscovery && IS_OFFNET_DEST(AddrType)) {
+ NewTCB->tcb_mss = MIN(MSS, MAX_REMOTE_MSS) -
+ NewTCB->tcb_opt.ioi_optlength;
+
+ CTEAssert(NewTCB->tcb_mss > 0);
+ }
+ else {
+ if (PMTUDiscovery)
+ NewTCB->tcb_opt.ioi_flags = IP_FLAG_DF;
+ NewTCB->tcb_mss = MSS - NewTCB->tcb_opt.ioi_optlength;
+
+ CTEAssert(NewTCB->tcb_mss > 0);
+ }
+
+ //
+ // Initialize the remote mss in case we receive an MTU change
+ // from IP before the remote SYN arrives. The remmms will
+ // be replaced when the remote SYN is processed.
+ //
+ NewTCB->tcb_remmss = NewTCB->tcb_mss;
+
+ // Now initialize our send state.
+ InitSendState(NewTCB);
+ NewTCB->tcb_refcnt = 1;
+ NewTCB->tcb_state = TCB_SYN_SENT;
+ TStats.ts_activeopens++;
+
+ // Need to put the ConnReq on the TCB now, in case the timer fires
+ // after we've inserted.
+
+ NewTCB->tcb_connreq = ConnReq;
+ CTEFreeLock(&NewTCB->tcb_lock, AOTableHandle);
+
+ Inserted = InsertTCB(NewTCB);
+ CTEGetLock(&NewTCB->tcb_lock, &TCBHandle);
+
+ if (!Inserted) {
+ // Insert failed. We must already have a connection. Pull
+ // the connreq from the TCB first, so we can return the correct
+ // error code for it.
+ NewTCB->tcb_connreq = NULL;
+ NewTCB->tcb_refcnt--;
+ TryToCloseTCB(NewTCB, TCB_CLOSE_ABORTED, TCBHandle);
+ FreeConnReq(ConnReq);
+ return TDI_ADDR_IN_USE;
+ }
+
+ // If it's closing somehow, stop now. It can't have gone to
+ // closed, as we hold a reference on it. It could have gone
+ // to some other state (for example SYN-RCVD) so we need to
+ // check that now too.
+ if (!CLOSING(NewTCB) && NewTCB->tcb_state == TCB_SYN_SENT) {
+ SendSYN(NewTCB, TCBHandle);
+ CTEGetLock(&NewTCB->tcb_lock, &TCBHandle);
+ }
+ DerefTCB(NewTCB, TCBHandle);
+
+ return TDI_PENDING;
+ } else
+ CTEFreeLock(&AO->ao_lock, AOHandle);
+
+ } else
+ Status = TDI_NOT_ASSOCIATED;
+ } else
+ Status = TDI_INVALID_CONNECTION;
+
+ CTEFreeLock(&AddrObjTableLock, ConnTableHandle);
+error:
+ CTEFreeLock(&ConnTableLock, AOTableHandle);
+ FreeConnReq(ConnReq);
+ FreeTCB(NewTCB);
+ return Status;
+
+
+}
+
+//* TdiListen - Listen for a connection.
+//
+// The TDI listen handling routine. Called when the client wants to
+// post a listen, we validate his incoming parameters, allocate a TCB
+// and return.
+//
+// Input: Request - The request structure for this command.
+// Flags - Listen flags for the listen.
+// AcceptableAddr - Pointer to a TDI_CONNECTION_INFORMATION
+// structure describing acceptable remote
+// addresses.
+// ConnectedAddr - Pointer to where to return information
+// about the address we connected to.
+//
+// Returns: Status of attempt to connect.
+//
+TDI_STATUS
+TdiListen(PTDI_REQUEST Request, ushort Flags,
+ PTDI_CONNECTION_INFORMATION AcceptableAddr,
+ PTDI_CONNECTION_INFORMATION ConnectedAddr)
+{
+ TCPConnReq *ConnReq; // Connection request to use.
+ IPAddr RemoteAddr; // Remote address to take conn. from.
+ ushort RemotePort; // Acceptable remote port.
+ uchar AddrType; // Type of remote address.
+ TCPConn *Conn; // Pointer to the Connection being
+ // listened upon.
+ TCB *NewTCB; // Pointer to the new TCB we'll use.
+ uint ConnID = (uint)Request->Handle.ConnectionContext;
+ CTELockHandle AOTableHandle, ConnTableHandle;
+ TDI_STATUS Status;
+
+ // If we've been given remote addressing criteria, check it out.
+ if (AcceptableAddr != NULL && AcceptableAddr->RemoteAddress != NULL) {
+ if (!GetAddress((PTRANSPORT_ADDRESS)AcceptableAddr->RemoteAddress,
+ &RemoteAddr, &RemotePort))
+ return TDI_BAD_ADDR;
+
+ if (!IP_ADDR_EQUAL(RemoteAddr, NULL_IP_ADDR)) {
+ AddrType = (*LocalNetInfo.ipi_getaddrtype)(RemoteAddr);
+
+ if (AddrType == DEST_INVALID || IS_BCAST_DEST(AddrType))
+ return TDI_BAD_ADDR;
+ }
+ } else {
+ RemoteAddr = NULL_IP_ADDR;
+ RemotePort = 0;
+ }
+
+ // The remote address is valid. Get a ConnReq, and maybe a TCB.
+ ConnReq = GetConnReq();
+ if (ConnReq == NULL)
+ return TDI_NO_RESOURCES; // Couldn't get one.
+
+ // Now try to get a TCB.
+ NewTCB = AllocTCB();
+ if (NewTCB == NULL) {
+ // Couldn't get a TCB. Return an error.
+ FreeConnReq(ConnReq);
+ return TDI_NO_RESOURCES;
+ }
+
+ // We have the resources we need. Initialize them, and then check the
+ // state of the connection.
+ ConnReq->tcr_flags = Flags;
+ ConnReq->tcr_conninfo = ConnectedAddr;
+ ConnReq->tcr_req.tr_rtn = Request->RequestNotifyObject;
+ ConnReq->tcr_req.tr_context = Request->RequestContext;
+ NewTCB->tcb_connreq = ConnReq;
+ NewTCB->tcb_daddr = RemoteAddr;
+ NewTCB->tcb_dport = RemotePort;
+ NewTCB->tcb_state = TCB_LISTEN;
+
+ // Now find the real connection. If we find it, we'll make sure it's
+ // associated.
+ CTEGetLock(&ConnTableLock, &ConnTableHandle);
+ Conn = GetConnFromConnID(ConnID);
+ if (Conn != NULL) {
+ CTELockHandle AddrHandle;
+ AddrObj *ConnAO;
+
+ CTEStructAssert(Conn, tc);
+ // We have a connection. Make sure it's associated with an address and
+ // doesn't already have a TCB attached.
+ ConnAO = Conn->tc_ao;
+
+ if (ConnAO != NULL) {
+ CTEStructAssert(ConnAO, ao);
+ CTEGetLockAtDPC(&ConnAO->ao_lock, &AddrHandle);
+
+ Status = InitTCBFromConn(Conn, NewTCB, AcceptableAddr, TRUE);
+
+ if (Status == TDI_SUCCESS) {
+
+ // The initialization worked. Assign the new TCB to the connection,
+ // and return.
+
+ REMOVEQ(&Conn->tc_q);
+ ENQUEUE(&ConnAO->ao_listenq, &Conn->tc_q);
+
+ Conn->tc_tcb = NewTCB;
+ NewTCB->tcb_conn = Conn;
+ Conn->tc_refcnt++;
+
+ ConnAO->ao_listencnt++;
+ CTEFreeLockFromDPC(&ConnAO->ao_lock, AddrHandle);
+
+ Status = TDI_PENDING;
+ } else {
+ FreeTCB(NewTCB);
+ CTEFreeLockFromDPC(&ConnAO->ao_lock, AddrHandle);
+ }
+ } else {
+ FreeTCB(NewTCB);
+ Status = TDI_NOT_ASSOCIATED;
+ }
+ } else {
+ FreeTCB(NewTCB);
+ Status = TDI_INVALID_CONNECTION;
+ }
+
+ // We're all done. Free the locks and get out.
+ CTEFreeLock(&ConnTableLock, ConnTableHandle);
+ return Status;
+
+}
+
+//* InitRCE - Initialize an RCE.
+//
+// A utility routine to open and RCE and determine the maximum segment size
+// for a connections. This function is called with the TCB lock held
+// when transitioning out of the SYN_SENT or LISTEN states.
+//
+// Input: NewTCB - TCB for which an RCE is to be opened.
+//
+// Returns: Nothing.
+//
+void
+InitRCE(TCB *NewTCB)
+{
+ uchar DType;
+ ushort MSS;
+
+ // Open an RCE for this connection.
+ (*LocalNetInfo.ipi_openrce)(NewTCB->tcb_daddr, NewTCB->tcb_saddr,
+ &NewTCB->tcb_rce, &DType, &MSS, &NewTCB->tcb_opt);
+
+ // Until we have Dynamic MTU discovery in place, force MTU down.
+ MSS -= sizeof(TCPHeader);
+ if (!PMTUDiscovery && (DType & DEST_OFFNET_BIT)) {
+ NewTCB->tcb_mss = MIN(NewTCB->tcb_remmss, MIN(MSS, MAX_REMOTE_MSS)
+ - NewTCB->tcb_opt.ioi_optlength);
+
+ CTEAssert(NewTCB->tcb_mss > 0);
+ }
+ else {
+ if (PMTUDiscovery)
+ NewTCB->tcb_opt.ioi_flags = IP_FLAG_DF;
+ MSS -= NewTCB->tcb_opt.ioi_optlength;
+ NewTCB->tcb_mss = MIN(NewTCB->tcb_remmss, MSS);
+
+ CTEAssert(NewTCB->tcb_mss > 0);
+
+ }
+
+
+}
+
+//* AcceptConn - Accept a connection on a TCB.
+//
+// Called to accept a connection on a TCB, either from an incoming
+// receive segment or via a user's accept. We initialize the RCE
+// and the send state, and send out a SYN. We assume the TCB is locked
+// and referenced when we get it.
+//
+// Input: AcceptTCB - TCB to accept on.
+// Handle - Lock handle for TCB.
+//
+// Returns: Nothing.
+//
+void
+AcceptConn(TCB *AcceptTCB, CTELockHandle Handle)
+{
+ CTEStructAssert(AcceptTCB, tcb);
+ CTEAssert(AcceptTCB->tcb_refcnt != 0);
+
+ InitRCE(AcceptTCB);
+ InitSendState(AcceptTCB);
+
+ AdjustRcvWin(AcceptTCB);
+ SendSYN(AcceptTCB, Handle);
+
+ CTEGetLock(&AcceptTCB->tcb_lock, &Handle);
+
+ DerefTCB(AcceptTCB, Handle);
+}
+
+//* TdiAccept - Accept a connection.
+//
+// The TDI accept routine. Called when the client wants to
+// accept a connection for which a listen had previously completed. We
+// examine the state of the connection - it has to be in SYN-RCVD, with
+// a TCB, with no pending connreq, etc.
+//
+// Input: Request - The request structure for this command.
+// AcceptInfo - Pointer to a TDI_CONNECTION_INFORMATION
+// structure describing option information
+// for this accept.
+// ConnectedIndo - Pointer to where to return information
+// about the address we connected to.
+//
+// Returns: Status of attempt to connect.
+//
+TDI_STATUS
+TdiAccept(PTDI_REQUEST Request, PTDI_CONNECTION_INFORMATION AcceptInfo,
+ PTDI_CONNECTION_INFORMATION ConnectedInfo)
+{
+ TCPConnReq *ConnReq; // ConnReq we'll use for this connection.
+ uint ConnID = (uint)Request->Handle.ConnectionContext;
+ TCPConn *Conn; // Connection being accepted upon.
+ TCB *AcceptTCB; // TCB for Conn.
+ CTELockHandle ConnTableHandle; // Lock handle for connection table.
+ CTELockHandle TCBHandle; // Lock handle for TCB.
+ TDI_STATUS Status;
+
+ // First, get the ConnReq we'll need.
+ ConnReq = GetConnReq();
+ if (ConnReq == NULL)
+ return TDI_NO_RESOURCES;
+
+ ConnReq->tcr_conninfo = ConnectedInfo;
+ ConnReq->tcr_req.tr_rtn = Request->RequestNotifyObject;
+ ConnReq->tcr_req.tr_context = Request->RequestContext;
+
+ // Now look up the connection.
+ CTEGetLock(&ConnTableLock, &ConnTableHandle);
+ Conn = GetConnFromConnID(ConnID);
+ if (Conn != NULL) {
+ CTEStructAssert(Conn, tc);
+
+ // We have the connection. Make sure is has a TCB, and that the
+ // TCB is in the SYN-RCVD state, etc.
+ AcceptTCB = Conn->tc_tcb;
+
+ if (AcceptTCB != NULL) {
+ CTEStructAssert(AcceptTCB, tcb);
+
+ CTEGetLock(&AcceptTCB->tcb_lock, &TCBHandle);
+ CTEFreeLock(&ConnTableLock, TCBHandle);
+
+ if (!CLOSING(AcceptTCB) && AcceptTCB->tcb_state == TCB_SYN_RCVD) {
+ // State is valid. Make sure this TCB had a delayed accept on
+ // it, and that there is currently no connect request pending.
+ if (!(AcceptTCB->tcb_flags & CONN_ACCEPTED) &&
+ AcceptTCB->tcb_connreq == NULL) {
+
+ // If the caller gave us options, they'll override any
+ // that are already present, if they're valid.
+ if (AcceptInfo != NULL && AcceptInfo->Options != NULL) {
+ IPOptInfo TempOptInfo;
+
+ // We have options. Copy them to make sure they're valid.
+ Status = ProcessUserOptions(AcceptInfo, &TempOptInfo);
+ if (Status == TDI_SUCCESS) {
+ (*LocalNetInfo.ipi_freeopts)(&AcceptTCB->tcb_opt);
+ AcceptTCB->tcb_opt = TempOptInfo;
+ AcceptTCB->tcb_flags |= CLIENT_OPTIONS;
+ } else
+ goto connerror;
+ }
+
+ AcceptTCB->tcb_connreq = ConnReq;
+ AcceptTCB->tcb_flags |= CONN_ACCEPTED;
+ AcceptTCB->tcb_refcnt++;
+ // Everything's set. Accept the connection now.
+ AcceptConn(AcceptTCB, ConnTableHandle);
+ return TDI_PENDING;
+ }
+ }
+connerror:
+ CTEFreeLock(&AcceptTCB->tcb_lock, ConnTableHandle);
+ Status = TDI_INVALID_CONNECTION;
+ goto error;
+ }
+ }
+ Status = TDI_INVALID_CONNECTION;
+ CTEFreeLock(&ConnTableLock, ConnTableHandle);
+
+error:
+ FreeConnReq(ConnReq);
+ return Status;
+
+}
+
+//* TdiDisConnect - Disconnect a connection.
+//
+// The TDI disconnection routine. Called when the client wants to disconnect
+// a connection. There are two types of disconnection we support, graceful
+// and abortive. A graceful close will cause us to send a FIN and not complete
+// the request until we get the ACK back. An abortive close causes us to send
+// a RST. In that case we'll just get things going and return immediately.
+//
+// Input: Request - The request structure for this command.
+// Timeout - How long to wait for the request. The format
+// of this time is system specific - we use
+// a macro to convert to ticks.
+// Flags - Flags indicating type of disconnect.
+// DiscConnInfo - Pointer to a TDI_CONNECTION_INFORMATION
+// structure giving disconnection info. Ignored
+// for this request.
+// ReturnInfo - Pointer to where to return information.
+// Ignored for this request.
+//
+// Returns: Status of attempt to disconnect.
+//
+TDI_STATUS
+TdiDisconnect(PTDI_REQUEST Request, void *TO, ushort Flags,
+ PTDI_CONNECTION_INFORMATION DiscConnInfo,
+ PTDI_CONNECTION_INFORMATION ReturnInfo)
+{
+ TCPConnReq *ConnReq; // Connection request to use.
+ TCPConn *Conn;
+ TCB *DiscTCB;
+ CTELockHandle ConnTableHandle, TCBHandle;
+ TDI_STATUS Status;
+ TCP_TIME *Timeout;
+
+ CTEGetLock(&ConnTableLock, &ConnTableHandle);
+
+ Conn = GetConnFromConnID((uint)Request->Handle.ConnectionContext);
+
+ if (Conn != NULL) {
+ CTEStructAssert(Conn, tc);
+
+ DiscTCB = Conn->tc_tcb;
+ if (DiscTCB != NULL) {
+ CTEStructAssert(DiscTCB, tcb);
+ CTEGetLock(&DiscTCB->tcb_lock, &TCBHandle);
+
+ // We have the TCB. See what kind of disconnect this is.
+ if (Flags & TDI_DISCONNECT_ABORT) {
+ // This is an abortive disconnect. If we're not already
+ // closed or closing, blow the connection away.
+ if (DiscTCB->tcb_state != TCB_CLOSED) {
+ CTEFreeLock(&ConnTableLock, TCBHandle);
+
+ if (!CLOSING(DiscTCB)) {
+ DiscTCB->tcb_flags |= NEED_RST;
+ TryToCloseTCB(DiscTCB, TCB_CLOSE_ABORTED,
+ ConnTableHandle);
+ } else
+ CTEFreeLock(&DiscTCB->tcb_lock, ConnTableHandle);
+
+ return TDI_SUCCESS;
+ } else {
+ // The TCB isn't connected.
+ CTEFreeLock(&ConnTableLock, TCBHandle);
+ CTEFreeLock(&DiscTCB->tcb_lock, ConnTableHandle);
+ DEBUGCHK;
+ return TDI_INVALID_STATE;
+ }
+ } else {
+ // This is not an abortive close. For graceful close we'll need
+ // a ConnReq.
+ CTEFreeLock(&ConnTableLock, TCBHandle);
+
+ // Make sure we aren't in the middle of an abortive close.
+ if (CLOSING(DiscTCB)) {
+ CTEFreeLock(&DiscTCB->tcb_lock, ConnTableHandle);
+ return TDI_INVALID_CONNECTION;
+ }
+
+ ConnReq = GetConnReq();
+ if (ConnReq != NULL) {
+ // Got the ConnReq. See if this is a DISCONNECT_WAIT
+ // primitive or not.
+
+ ConnReq->tcr_flags = 0;
+ ConnReq->tcr_conninfo = NULL;
+ ConnReq->tcr_req.tr_rtn = Request->RequestNotifyObject;
+ ConnReq->tcr_req.tr_context = Request->RequestContext;
+
+ if (!(Flags & TDI_DISCONNECT_WAIT)) {
+ Timeout = (TCP_TIME *)TO;
+
+ if (Timeout != NULL && !INFINITE_CONN_TO(*Timeout)) {
+ ulong Ticks = TCP_TIME_TO_TICKS(*Timeout);
+ if (Ticks > MAX_CONN_TO_TICKS)
+ Ticks = MAX_CONN_TO_TICKS;
+ else
+ Ticks++;
+ ConnReq->tcr_timeout = (ushort)Ticks;
+ } else
+ ConnReq->tcr_timeout = 0;
+
+ // OK, we're just about set. We need to update the TCB
+ // state, and send the FIN.
+ if (DiscTCB->tcb_state == TCB_ESTAB) {
+ DiscTCB->tcb_state = TCB_FIN_WAIT1;
+
+ // Since we left established, we're off the fast
+ // receive path.
+ DiscTCB->tcb_slowcount++;
+ DiscTCB->tcb_fastchk |= TCP_FLAG_SLOW;
+ } else
+ if (DiscTCB->tcb_state == TCB_CLOSE_WAIT)
+ DiscTCB->tcb_state = TCB_LAST_ACK;
+ else {
+ CTEFreeLock(&DiscTCB->tcb_lock, ConnTableHandle);
+ FreeConnReq(ConnReq);
+ return TDI_INVALID_STATE;
+ }
+
+ TStats.ts_currestab--; // Update SNMP info.
+ CTEAssert(*(int *)&TStats.ts_currestab >= 0);
+
+ CTEAssert(DiscTCB->tcb_connreq == NULL);
+ DiscTCB->tcb_connreq = ConnReq;
+ DiscTCB->tcb_flags |= FIN_NEEDED;
+ DiscTCB->tcb_refcnt++;
+#ifdef VXD
+ CTEFreeLock(&DiscTCB->tcb_lock, ConnTableHandle);
+ TCPSend(DiscTCB);
+#else
+ TCPSend(DiscTCB, ConnTableHandle);
+#endif
+ return TDI_PENDING;
+ } else {
+ // This is a DISC_WAIT request.
+ ConnReq->tcr_timeout = 0;
+ if (DiscTCB->tcb_discwait == NULL) {
+ DiscTCB->tcb_discwait = ConnReq;
+ Status = TDI_PENDING;
+ } else
+ Status = TDI_INVALID_STATE;
+
+ CTEFreeLock(&DiscTCB->tcb_lock, ConnTableHandle);
+ return Status;
+ }
+ } else {
+ // Couldn't get a ConnReq.
+ CTEFreeLock(&DiscTCB->tcb_lock, ConnTableHandle);
+ return TDI_NO_RESOURCES;
+ }
+ }
+ }
+ }
+
+ // No Conn, or no TCB on conn. Return an error.
+ CTEFreeLock(&ConnTableLock, ConnTableHandle);
+ return TDI_INVALID_CONNECTION;
+}
+
+//* OKToNotify - See if it's OK to notify about a DISC.
+//
+// A little utility function, called to see it it's OK to notify the client
+// of an incoming FIN.
+//
+// Input: NotifyTCB - TCB to check.
+//
+// Returns: TRUE if it's OK, False otherwise.
+//
+uint
+OKToNotify(TCB *NotifyTCB)
+{
+ CTEStructAssert(NotifyTCB, tcb);
+ if (NotifyTCB->tcb_pendingcnt == 0 && NotifyTCB->tcb_urgcnt == 0 &&
+ NotifyTCB->tcb_rcvhead == NULL && NotifyTCB->tcb_exprcv == NULL)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+//* NotifyOfDisc - Notify a client that a TCB is being disconnected.
+//
+// Called when we're disconnecting a TCB because we've received a FIN or
+// RST from the remote peer, or because we're aborting for some reason.
+// We'll complete a DISCONNECT_WAIT request if we have one, or try and
+// issue an indication otherwise. This is only done if we're in a synchronized
+// state and not in TIMED-WAIT.
+//
+// Input: DiscTCB - Pointer to TCB we're notifying.
+// Status - Status code for notification.
+//
+// Returns: Nothing.
+//
+void
+NotifyOfDisc(TCB *DiscTCB, IPOptInfo *DiscInfo, TDI_STATUS Status)
+{
+ CTELockHandle TCBHandle, AOTHandle, ConnTHandle;
+ TCPConnReq *DiscReq;
+ TCPConn *Conn;
+ AddrObj *DiscAO;
+ PVOID ConnContext;
+
+ CTEStructAssert(DiscTCB, tcb);
+ CTEAssert(DiscTCB->tcb_refcnt != 0);
+
+ CTEGetLock(&DiscTCB->tcb_lock, &TCBHandle);
+ if (SYNC_STATE(DiscTCB->tcb_state) &&
+ !(DiscTCB->tcb_flags & DISC_NOTIFIED)) {
+
+ // We can't notify him if there's still data to be taken.
+ if (Status == TDI_GRACEFUL_DISC && !OKToNotify(DiscTCB)) {
+ DiscTCB->tcb_flags |= DISC_PENDING;
+ CTEFreeLock(&DiscTCB->tcb_lock, TCBHandle);
+ return;
+ }
+
+ DiscTCB->tcb_flags |= DISC_NOTIFIED;
+ DiscTCB->tcb_flags &= ~DISC_PENDING;
+
+ // We're in a state where a disconnect is meaningful, and we haven't
+ // already notified the client.
+
+ // See if we have a DISC-WAIT request pending.
+ if ((DiscReq = DiscTCB->tcb_discwait) != NULL) {
+ // We have a disconnect wait request. Complete it and we're done.
+ DiscTCB->tcb_discwait = NULL;
+ CTEFreeLock(&DiscTCB->tcb_lock, TCBHandle);
+ (*DiscReq->tcr_req.tr_rtn)(DiscReq->tcr_req.tr_context, Status, 0);
+ FreeConnReq(DiscReq);
+ return;
+
+ }
+
+ // No DISC-WAIT. Find the AddrObj for the connection, and see if there
+ // is a disconnect handler registered.
+
+ ConnContext = DiscTCB->tcb_conncontext;
+ CTEFreeLock(&DiscTCB->tcb_lock, TCBHandle);
+
+ CTEGetLock(&AddrObjTableLock, &AOTHandle);
+ CTEGetLock(&ConnTableLock, &ConnTHandle);
+ if ((Conn = DiscTCB->tcb_conn) != NULL) {
+ CTEStructAssert(Conn, tc);
+
+ DiscAO = Conn->tc_ao;
+ if (DiscAO != NULL) {
+ CTELockHandle AOHandle;
+ PDisconnectEvent DiscEvent;
+ PVOID DiscContext;
+
+
+ CTEStructAssert(DiscAO, ao);
+ CTEGetLock(&DiscAO->ao_lock, &AOHandle);
+ CTEFreeLock(&ConnTableLock, AOHandle);
+ CTEFreeLock(&AddrObjTableLock, ConnTHandle);
+
+ DiscEvent = DiscAO->ao_disconnect;
+ DiscContext = DiscAO->ao_disconncontext;
+
+ if (DiscEvent != NULL) {
+ uint InfoLength;
+ PVOID Info;
+
+ REF_AO(DiscAO);
+ CTEFreeLock(&DiscAO->ao_lock, AOTHandle);
+
+ if (DiscInfo != NULL) {
+ InfoLength = (uint)DiscInfo->ioi_optlength;
+ Info = DiscInfo->ioi_options;
+ } else {
+ InfoLength = 0;
+ Info = NULL;
+ }
+
+ IF_TCPDBG(TCP_DEBUG_CLOSE) {
+ TCPTRACE(("TCP: indicating %s disconnect\n",
+ (Status == TDI_GRACEFUL_DISC) ? "graceful" :
+ "abortive"
+ ));
+ }
+
+ (*DiscEvent)(DiscContext,
+ ConnContext, 0,
+ NULL, InfoLength, Info, (Status == TDI_GRACEFUL_DISC) ?
+ TDI_DISCONNECT_RELEASE : TDI_DISCONNECT_ABORT);
+
+ DELAY_DEREF_AO(DiscAO);
+ return;
+ } else {
+ CTEFreeLock(&DiscAO->ao_lock, AOTHandle);
+ return;
+ }
+ }
+ }
+
+ CTEFreeLock(&ConnTableLock, ConnTHandle);
+ CTEFreeLock(&AddrObjTableLock, AOTHandle);
+ return;
+
+ }
+ CTEFreeLock(&DiscTCB->tcb_lock, TCBHandle);
+
+}
+
+//* GracefulClose - Complete the transition to a gracefully closed state.
+//
+// Called when we need to complete the transition to a gracefully closed
+// state, either TIME_WAIT or CLOSED. This completion involves removing
+// the TCB from it's associated connection (if it has one), notifying the
+// upper layer client either via completing a request or calling a disc.
+// notification handler, and actually doing the transition.
+//
+// The tricky part here is if we need to notify him (instead of completing
+// a graceful disconnect request). We can't notify him if there is pending
+// data on the connection, so in that case we have to pend the disconnect
+// notification until we deliver the data.
+//
+// Input: CloseTCB - TCB to transition.
+// ToTimeWait - True if we're going to TIME_WAIT, False if
+// we're going to close the TCB.
+// Notify - True if we're going to transition via notification,
+// False if we're going to transition by completing
+// a disconnect request.
+// Handle - Lock handle for TCB.
+//
+// Returns: Nothing.
+//
+void
+GracefulClose(TCB *CloseTCB, uint ToTimeWait, uint Notify, CTELockHandle Handle)
+{
+
+ CTEStructAssert(CloseTCB, tcb);
+
+ CTEAssert(CloseTCB->tcb_refcnt != 0);
+
+ // First, see if we need to notify the client of a FIN.
+ if (Notify) {
+ // We do need to notify him. See if it's OK to do so.
+ if (OKToNotify(CloseTCB)) {
+ // We can notify him. Change his state, pull him from the conn.,
+ // and notify him.
+ if (ToTimeWait) {
+ // Save the time we went into time wait, in case we need to
+ // scavenge.
+ CloseTCB->tcb_alive = CTESystemUpTime();
+ CloseTCB->tcb_state = TCB_TIME_WAIT;
+ CTEFreeLock(&CloseTCB->tcb_lock, Handle);
+ } else {
+ // He's going to close. Mark him as closing with TryToCloseTCB
+ // (he won't actually close since we have a ref. on him). We
+ // do this so that anyone touching him after we free the
+ // lock will fail.
+ TryToCloseTCB(CloseTCB, TDI_SUCCESS, Handle);
+ }
+
+
+ RemoveTCBFromConn(CloseTCB);
+ NotifyOfDisc(CloseTCB, NULL, TDI_GRACEFUL_DISC);
+
+ } else {
+ // Can't notify him now. Set the appropriate flags, and return.
+ CloseTCB->tcb_flags |= (GC_PENDING | (ToTimeWait ? TW_PENDING : 0));
+ DerefTCB(CloseTCB, Handle);
+ return;
+ }
+ } else {
+ // We're not notifying this guy, we just need to complete a conn. req.
+ // We need to check and see if he's been notified, and if not
+ // we'll complete the request and notify him later.
+ if (CloseTCB->tcb_flags & DISC_NOTIFIED) {
+ // He's been notified.
+ if (ToTimeWait) {
+ // Save the time we went into time wait, in case we need to
+ // scavenge.
+ CloseTCB->tcb_alive = CTESystemUpTime();
+ CloseTCB->tcb_state = TCB_TIME_WAIT;
+ CTEFreeLock(&CloseTCB->tcb_lock, Handle);
+ } else {
+ // Mark him as closed. See comments above.
+ TryToCloseTCB(CloseTCB, TDI_SUCCESS, Handle);
+ }
+
+ RemoveTCBFromConn(CloseTCB);
+
+ CTEGetLock(&CloseTCB->tcb_lock, &Handle);
+ CompleteConnReq(CloseTCB, NULL, TDI_SUCCESS);
+ CTEFreeLock(&CloseTCB->tcb_lock, Handle);
+ } else {
+ // He hasn't been notified. He should be pending already.
+ CTEAssert(CloseTCB->tcb_flags & DISC_PENDING);
+ CloseTCB->tcb_flags |= (GC_PENDING | (ToTimeWait ? TW_PENDING : 0));
+
+ CompleteConnReq(CloseTCB, NULL, TDI_SUCCESS);
+
+ DerefTCB(CloseTCB, Handle);
+ return;
+ }
+ }
+
+ // If we're going to TIME_WAIT, start the TIME_WAIT timer now.
+ // Otherwise close the TCB.
+ CTEGetLock(&CloseTCB->tcb_lock, &Handle);
+ if (!CLOSING(CloseTCB) && ToTimeWait) {
+ START_TCB_TIMER(CloseTCB->tcb_rexmittimer, MAX_REXMIT_TO);
+ CTEFreeLock(&CloseTCB->tcb_lock, Handle);
+ RemoveConnFromTCB(CloseTCB);
+ CTEGetLock(&CloseTCB->tcb_lock, &Handle);
+
+ }
+
+ DerefTCB(CloseTCB, Handle);
+
+}
+
+//* ConnCheckPassed - Check to see if we have exceeded the connect limit
+//
+// Called when a SYN is received to determine whether we will accept
+// the incoming connection. If the is an empty slot or if the IPAddr
+// is already in the table, we accept it.
+//
+// Input: Source Address of incoming connection
+// Destination port of incoming connection
+//
+// Returns: TRUE is connect is to be accepted
+// FALSE if connection is rejected
+//
+int ConnCheckPassed(IPAddr Src, ulong Prt)
+
+{
+ UNREFERENCED_PARAMETER(Src);
+ UNREFERENCED_PARAMETER(Prt);
+
+ return TRUE;
+}
+
+void InitAddrChecks()
+{
+ return;
+}
+
+//* EnumerateConnectionList - Enumerate Connection List database.
+//
+// This routine enumerates the contents of the connection limit database
+//
+// Input:
+//
+// Buffer - A pointer to a buffer into which to put
+// the returned connection list entries.
+//
+// BufferSize - On input, the size in bytes of Buffer.
+// On output, the number of bytes written.
+//
+// EntriesAvailable - On output, the total number of connection entries
+// available in the database.
+//
+// Returns: A TDI status code:
+//
+// TDI_SUCCESS otherwise.
+//
+// NOTES:
+//
+// This routine acquires AddrObjTableLock.
+//
+// Entries written to output buffer are in host byte order.
+//
+void
+EnumerateConnectionList(uchar *Buffer, ulong BufferSize,
+ ulong *EntriesReturned, ulong *EntriesAvailable)
+{
+
+ UNREFERENCED_PARAMETER(Buffer);
+ UNREFERENCED_PARAMETER(BufferSize);
+
+ *EntriesAvailable = 0;
+ *EntriesReturned = 0;
+
+ return;
+}
+
+
+#pragma BEGIN_INIT
+
+//* InitTCPConn - Initialize TCP connection management code.
+//
+// Called during init time to initialize our TCP connection mgmt..
+//
+// Input: Nothing.
+//
+// Returns: TRUE.
+//
+int
+InitTCPConn(void)
+{
+#ifdef NT
+ ExInitializeSListHead(&ConnReqFree);
+#endif
+
+ CTEInitLock(&ConnReqFreeLock);
+ return TRUE;
+}
+
+//* UnInitTCPConn - Uninitialize our connection management code.
+//
+// Called if initialization fails to uninitialize our conn mgmet.
+//
+//
+// Input: Nothing.
+//
+// Returns: Nothing.
+//
+void
+UnInitTCPConn(void)
+{
+
+}
+
+#pragma END_INIT
+
diff --git a/private/ntos/tdi/tcpip/tcp/tcpconn.h b/private/ntos/tdi/tcpip/tcp/tcpconn.h
new file mode 100644
index 000000000..e3eed2c8b
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/tcpconn.h
@@ -0,0 +1,124 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** TCPCONN.H - TCP connection related definitions.
+//
+// This file contains the definitions for connection related structures,
+// such as the TCPConnReq structure.
+//
+
+#define INVALID_CONN_INDEX 0xffffff
+
+//* Structure used for tracking Connect/Listen/Accept/Disconnect requests.
+
+#define tcr_signature 0x20524354 // 'TCR '
+
+struct TCPConnReq {
+ struct TCPReq tcr_req; // General request structure.
+#ifdef DEBUG
+ ulong tcr_sig;
+#endif
+ struct _TDI_CONNECTION_INFORMATION *tcr_conninfo; // Where to return info.
+ ushort tcr_flags; // Flags for this request.
+ ushort tcr_timeout; // Timeout value for this request.
+};
+
+typedef struct TCPConnReq TCPConnReq;
+
+typedef void (*ConnDoneRtn)(struct TCPConn *, CTELockHandle);
+
+//* Structure of a TCB Connection. A TCP Connection points to a TCP and an
+// address object.
+
+#define tc_signature 0x20204354 // 'TC '
+
+struct TCPConn {
+#ifdef DEBUG
+ ulong tc_sig;
+#endif
+ Queue tc_q; // Linkage on AO.
+ struct TCB *tc_tcb; // Pointer to TCB for connection.
+ struct AddrObj *tc_ao; // Back pointer to AddrObj.
+ uchar tc_inst; // Instance number.
+ uchar tc_flags; // Flags for connection.
+ ushort tc_refcnt; // Count of TCBs which reference this
+ // connection.
+ void *tc_context; // User's context.
+ CTEReqCmpltRtn tc_rtn; // Completion routine.
+ PVOID tc_rtncontext; // User context for completion routine.
+ ConnDoneRtn tc_donertn; // Routine to call when refcnt goes to 0.
+ uint tc_tcbflags; // Flags for TCB when it comes in.
+ uint tc_window; // Default window for TCB.
+
+}; /* TCPConn */
+
+typedef struct TCPConn TCPConn;
+
+#define CONN_CLOSING 1 // Connection is closing.
+#define CONN_DISACC 2 // Conn. is disassociating.
+#define CONN_WINSET 4 // Window explictly set.
+
+#define CONN_INVALID (CONN_CLOSING | CONN_DISACC)
+
+//* Structure of a ConnTable.
+typedef struct TCPConn *TCPConnTable[];
+
+extern TCPConnTable *ConnTable;
+
+#define FREE_CONN_INDEX(i) (*ConnTable)[(i)] = NULL
+EXTERNAL_LOCK(ConnTableLock)
+
+struct TCPAddrCheck {
+ IPAddr SourceAddress;
+ uint TickCount;
+}; /* TCPAddrCheck */
+
+typedef struct TCPAddrCheck TCPAddrCheckElement;
+
+extern TCPAddrCheckElement *AddrCheckTable;
+
+//* External definitions for TDI entry points.
+extern TDI_STATUS TdiOpenConnection(PTDI_REQUEST Request, PVOID Context);
+extern TDI_STATUS TdiCloseConnection(PTDI_REQUEST Request);
+extern TDI_STATUS TdiAssociateAddress(PTDI_REQUEST Request, HANDLE AddrHandle);
+extern TDI_STATUS TdiDisAssociateAddress(PTDI_REQUEST Request);
+extern TDI_STATUS TdiConnect(PTDI_REQUEST Request, void *Timeout,
+ PTDI_CONNECTION_INFORMATION RequestAddr,
+ PTDI_CONNECTION_INFORMATION ReturnAddr);
+extern TDI_STATUS TdiListen(PTDI_REQUEST Request, ushort Flags,
+ PTDI_CONNECTION_INFORMATION AcceptableAddr,
+ PTDI_CONNECTION_INFORMATION ConnectedAddr);
+extern TDI_STATUS TdiAccept(PTDI_REQUEST Request,
+ PTDI_CONNECTION_INFORMATION AcceptInfo,
+ PTDI_CONNECTION_INFORMATION ConnectedInfo);
+extern TDI_STATUS TdiDisconnect(PTDI_REQUEST Request, void *TO, ushort Flags,
+ PTDI_CONNECTION_INFORMATION DiscConnInfo,
+ PTDI_CONNECTION_INFORMATION ReturnInfo);
+
+extern struct TCPConnReq *GetConnReq(void);
+extern void FreeConnReq(struct TCPConnReq *FreedReq);
+extern void DerefTCB(struct TCB *DoneTCB, CTELockHandle Handle);
+extern void InitRCE(struct TCB *NewTCB);
+extern void AcceptConn(struct TCB *AcceptTCB, CTELockHandle Handle);
+extern void FreeConnID(uint ConnID);
+extern void NotifyOfDisc(struct TCB *DiscTCB, struct IPOptInfo *DiscInfo,
+ TDI_STATUS Status);
+extern TCPConn *GetConnFromConnID(uint ConnID);
+
+extern void TryToCloseTCB(struct TCB *ClosedTCB, uchar Reason,
+ CTELockHandle Handle);
+extern TDI_STATUS InitTCBFromConn(struct TCPConn *Conn, struct TCB *NewTCB,
+ PTDI_CONNECTION_INFORMATION Addr, uint AOLocked);
+
+extern void PushData(struct TCB *PushTCB);
+extern TDI_STATUS MapIPError(IP_STATUS IPError, TDI_STATUS Default);
+extern void GracefulClose(struct TCB *CloseTCB, uint ToTimeWait, uint Notify,
+ CTELockHandle Handle);
+extern void RemoveTCBFromConn(struct TCB *RemovedTCB);
+extern void InitAddrChecks();
+extern int ConnCheckPassed(IPAddr Src, ulong Prt);
+extern void EnumerateConnectionList(uchar *Buffer, ulong BufferSize,
+ ulong *EntriesReturned, ulong *EntriesAvailable);
diff --git a/private/ntos/tdi/tcpip/tcp/tcpdeb.c b/private/ntos/tdi/tcpip/tcp/tcpdeb.c
new file mode 100644
index 000000000..70478f6ee
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/tcpdeb.c
@@ -0,0 +1,169 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** TCPDEB.C - TCP debug code.
+//
+// This file contains the code for various TCP specific debug routines.
+//
+
+#include "oscfg.h"
+
+
+#include "ndis.h"
+#include "cxport.h"
+#include "ip.h"
+#include "tdi.h"
+#ifdef VXD
+#include "tdivxd.h"
+#include "tdistat.h"
+#endif
+#include "queue.h"
+#include "tcp.h"
+#include "tcpsend.h"
+#include "tlcommon.h"
+
+
+#ifdef DEBUG
+
+#ifdef NT
+
+ULONG TCPDebug = TCP_DEBUG_CANCEL;
+
+#endif
+
+
+//* CheckRBList - Check a list of RBs for the correct size.
+//
+// A routine to walk a list of RBs, making sure the size is what we think
+// it it.
+//
+// Input: RBList - List of RBs to check.
+// Size - Size RBs should be.
+//
+// Returns: Nothing.
+//
+void
+CheckRBList(IPRcvBuf *RBList, uint Size)
+{
+ uint SoFar = 0;
+ IPRcvBuf *List = RBList;
+
+ while (List != NULL) {
+ SoFar += List->ipr_size;
+ List = List->ipr_next;
+ }
+
+ CTEAssert(Size == SoFar);
+
+}
+
+//* CheckTCBRcv - Check receives on a TCB.
+//
+// Check the receive state of a TCB.
+//
+// Input: CheckTCB - TCB to check.
+//
+// Returns: Nothing.
+//
+void
+CheckTCBRcv(TCB *CheckTCB)
+{
+ CTEStructAssert(CheckTCB, tcb);
+
+ CTEAssert(!(CheckTCB->tcb_flags & FLOW_CNTLD) ||
+ (CheckTCB->tcb_sendwin == 0));
+
+ if ((CheckTCB->tcb_fastchk & ~TCP_FLAG_IN_RCV) == TCP_FLAG_ACK) {
+ CTEAssert(CheckTCB->tcb_slowcount == 0);
+ CTEAssert(CheckTCB->tcb_state == TCB_ESTAB);
+ CTEAssert(CheckTCB->tcb_raq == NULL);
+ CTEAssert(!(CheckTCB->tcb_flags & TCP_SLOW_FLAGS));
+ CTEAssert(!CLOSING(CheckTCB));
+ } else {
+ CTEAssert(CheckTCB->tcb_slowcount != 0);
+ CTEAssert( (CheckTCB->tcb_state != TCB_ESTAB) ||
+ (CheckTCB->tcb_raq != NULL) ||
+ (CheckTCB->tcb_flags & TCP_SLOW_FLAGS) ||
+ CLOSING(CheckTCB));
+ }
+
+}
+
+//* CheckTCBSends - Check the send status of a TCB.
+//
+// A routine to check the send status of a TCB. We make sure that all
+// of the SendReqs make sense, as well as making sure that the send seq.
+// variables in the TCB are consistent.
+//
+// Input: CheckTCB - TCB to check.
+//
+// Returns: Nothing.
+//
+void
+CheckTCBSends(TCB *CheckTCB)
+{
+ Queue *End, *Current; // End and current elements.
+ TCPSendReq *CurrentTSR; // Current send req we're
+ // examining.
+ uint Unacked; // Number of unacked bytes.
+ PNDIS_BUFFER CurrentBuffer;
+ TCPSendReq *TCBTsr; // Current send on TCB.
+ uint FoundSendReq;
+
+
+ CTEStructAssert(CheckTCB, tcb);
+
+ // Don't check on unsynchronized TCBs.
+ if (!SYNC_STATE(CheckTCB->tcb_state))
+ return;
+
+ CTEAssert(SEQ_LTE(CheckTCB->tcb_senduna, CheckTCB->tcb_sendnext));
+ CTEAssert(SEQ_LTE(CheckTCB->tcb_sendnext, CheckTCB->tcb_sendmax));
+ CTEAssert(!(CheckTCB->tcb_flags & FIN_OUTSTANDING) ||
+ (CheckTCB->tcb_sendnext == CheckTCB->tcb_sendmax));
+
+ if (CheckTCB->tcb_unacked == 0) {
+ CTEAssert(CheckTCB->tcb_cursend == NULL);
+ CTEAssert(CheckTCB->tcb_sendsize == 0);
+ }
+
+ if (CheckTCB->tcb_sendbuf != NULL)
+ CTEAssert(CheckTCB->tcb_sendofs < NdisBufferLength(CheckTCB->tcb_sendbuf));
+
+ TCBTsr = CheckTCB->tcb_cursend;
+ FoundSendReq = (TCBTsr == NULL) ? TRUE : FALSE;
+
+ End = QEND(&CheckTCB->tcb_sendq);
+ Current = QHEAD(&CheckTCB->tcb_sendq);
+
+ Unacked = 0;
+ while (Current != End) {
+ CurrentTSR = STRUCT_OF(TCPSendReq, QSTRUCT(TCPReq, Current, tr_q),
+ tsr_req);
+ CTEStructAssert(CurrentTSR, tsr);
+
+ if (CurrentTSR == TCBTsr)
+ FoundSendReq = TRUE;
+
+ CTEAssert(CurrentTSR->tsr_unasize <= CurrentTSR->tsr_size);
+
+ CurrentBuffer = CurrentTSR->tsr_buffer;
+ CTEAssert(CurrentBuffer != NULL);
+
+ CTEAssert(CurrentTSR->tsr_offset < NdisBufferLength(CurrentBuffer));
+
+ Unacked += CurrentTSR->tsr_unasize;
+ Current = QNEXT(Current);
+ }
+
+ CTEAssert(FoundSendReq);
+
+ CTEAssert(Unacked == CheckTCB->tcb_unacked);
+ Unacked += ((CheckTCB->tcb_flags & FIN_SENT) ? 1 : 0);
+ CTEAssert((CheckTCB->tcb_sendmax - CheckTCB->tcb_senduna) <= (int) Unacked);
+}
+
+#endif
diff --git a/private/ntos/tdi/tcpip/tcp/tcpdeb.h b/private/ntos/tdi/tcpip/tcp/tcpdeb.h
new file mode 100644
index 000000000..b22e18a1b
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/tcpdeb.h
@@ -0,0 +1,78 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** TCPDEB.H - TCP debug definitions.
+//
+// This file contains the definitions for the debug code.
+//
+
+#ifndef NO_TCP_DEFS
+#ifdef DEBUG
+
+#ifndef UDP_ONLY
+extern void CheckRBList(IPRcvBuf *RBList, uint Size);
+extern void CheckTCBSends(TCB *SendTcb);
+extern void CheckTCBRcv(TCB *RcvTCB);
+#else
+#define CheckRBList(R, S)
+#define CheckTCBSends(T)
+#define CheckTCBRcv(T)
+#endif // UDP_ONLY
+
+#else
+
+#define CheckRBList(R, S)
+#define CheckTCBSends(T)
+#define CheckTCBRcv(T)
+#endif // DEBUG
+#endif // NO_TCP_DEFS
+
+//
+// Additional debugging support for NT
+//
+#ifdef NT
+#if DBG
+
+extern ULONG TCPDebug;
+
+#define TCP_DEBUG_OPEN 0x00000001
+#define TCP_DEBUG_CLOSE 0x00000002
+#define TCP_DEBUG_ASSOCIATE 0x00000004
+#define TCP_DEBUG_CONNECT 0x00000008
+#define TCP_DEBUG_SEND 0x00000010
+#define TCP_DEBUG_RECEIVE 0x00000020
+#define TCP_DEBUG_INFO 0x00000040
+#define TCP_DEBUG_IRP 0x00000080
+#define TCP_DEBUG_SEND_DGRAM 0x00000100
+#define TCP_DEBUG_RECEIVE_DGRAM 0x00000200
+#define TCP_DEBUG_EVENT_HANDLER 0x00000400
+#define TCP_DEBUG_CLEANUP 0x00000800
+#define TCP_DEBUG_CANCEL 0x00001000
+#define TCP_DEBUG_RAW 0x00002000
+#define TCP_DEBUG_OPTIONS 0x00004000
+
+
+#define TCPTRACE(many_args) DbgPrint many_args
+
+#define IF_TCPDBG(flag) if (TCPDebug & flag)
+
+
+#else // DBG
+
+
+#define TCPTRACE(many_args)
+#define IF_TCPDBG(flag) if (0)
+
+
+#endif // DBG
+#else // NT
+
+
+#define TCPTRACE(many_args)
+#define IF_TCPDBG(flag) if (0)
+
+
+#endif // NT
diff --git a/private/ntos/tdi/tcpip/tcp/tcpdeliv.c b/private/ntos/tdi/tcpip/tcp/tcpdeliv.c
new file mode 100644
index 000000000..36d686257
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/tcpdeliv.c
@@ -0,0 +1,1971 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** TCPDELIV.C - TCP deliver data code.
+//
+// This file contains the code for delivering data to the user, including
+// putting data into recv. buffers and calling indication handlers.
+//
+
+#include "oscfg.h"
+#include "ndis.h"
+#include "cxport.h"
+#include "ip.h"
+#include "tdi.h"
+#ifdef VXD
+#include "tdivxd.h"
+#include "tdistat.h"
+#endif
+#ifdef NT
+#include "tdint.h"
+#include "tdistat.h"
+#endif
+#include "queue.h"
+#include "addr.h"
+#include "tcp.h"
+#include "tcb.h"
+#include "tcprcv.h"
+#include "tcpsend.h"
+#include "tcpconn.h"
+#include "tcpdeliv.h"
+#include "tlcommon.h"
+
+EXTERNAL_LOCK(AddrObjTableLock)
+
+extern void
+PutOnRAQ(TCB *RcvTCB, TCPRcvInfo *RcvInfo, IPRcvBuf *RcvBuf, uint Size);
+
+#ifndef NT
+TCPRcvReq *TCPRcvReqFree = NULL; // Rcv req. free list.
+#else
+SLIST_HEADER TCPRcvReqFree; // Rcv req. free list.
+#endif
+
+DEFINE_LOCK_STRUCTURE(TCPRcvReqFreeLock) // Protects rcv req free list.
+uint NumTCPRcvReq = 0; // Current number of RcvReqs in system.
+uint MaxRcvReq = 0xffffffff; // Maximum allowed number of SendReqs.
+
+#ifdef NT
+
+NTSTATUS
+TCPPrepareIrpForCancel(
+ PTCP_CONTEXT TcpContext,
+ PIRP Irp,
+ PDRIVER_CANCEL CancelRoutine
+ );
+
+ULONG
+TCPGetMdlChainByteCount(
+ PMDL Mdl
+ );
+
+void
+TCPDataRequestComplete(
+ void *Context,
+ unsigned int Status,
+ unsigned int ByteCount
+ );
+
+VOID
+TCPCancelRequest(
+ PDEVICE_OBJECT Device,
+ PIRP Irp
+ );
+
+#endif // NT
+
+
+//* FreeRcvReq - Free a rcv request structure.
+//
+// Called to free a rcv request structure.
+//
+// Input: FreedReq - Rcv request structure to be freed.
+//
+// Returns: Nothing.
+//
+void
+FreeRcvReq(TCPRcvReq *FreedReq)
+{
+#ifdef NT
+
+ PSINGLE_LIST_ENTRY BufferLink;
+
+ CTEStructAssert(FreedReq, trr);
+
+ BufferLink = STRUCT_OF(SINGLE_LIST_ENTRY, &(FreedReq->trr_next), Next);
+
+ ExInterlockedPushEntrySList(
+ &TCPRcvReqFree,
+ BufferLink,
+ &TCPRcvReqFreeLock
+ );
+
+#else // NT
+
+ TCPRcvReq **Temp;
+
+ CTEStructAssert(FreedReq, trr);
+
+ FreedReq->trr_next = TCPRcvReqFree;
+ TCPRcvReqFree = FreedReq;
+
+#endif // NT
+}
+
+//* GetRcvReq - Get a recv. request structure.
+//
+// Called to get a rcv. request structure.
+//
+// Input: Nothing.
+//
+// Returns: Pointer to RcvReq structure, or NULL if none.
+//
+TCPRcvReq *
+GetRcvReq(void)
+{
+ TCPRcvReq *Temp;
+
+#ifdef NT
+
+ PSINGLE_LIST_ENTRY BufferLink;
+
+
+ BufferLink = ExInterlockedPopEntrySList(
+ &TCPRcvReqFree,
+ &TCPRcvReqFreeLock
+ );
+
+ if (BufferLink != NULL) {
+ Temp = STRUCT_OF(TCPRcvReq, BufferLink, trr_next);
+ CTEStructAssert(Temp, trr);
+ }
+ else {
+ if (NumTCPRcvReq < MaxRcvReq)
+ Temp = CTEAllocMem(sizeof(TCPRcvReq));
+ else
+ Temp = NULL;
+
+ if (Temp != NULL) {
+ ExInterlockedAddUlong(&NumTCPRcvReq, 1, &TCPRcvReqFreeLock);
+#ifdef DEBUG
+ Temp->trr_sig = trr_signature;
+#endif
+ }
+ }
+
+#else // NT
+
+ Temp = TCPRcvReqFree;
+ if (Temp != NULL)
+ TCPRcvReqFree = Temp->trr_next;
+ else {
+ if (NumTCPRcvReq < MaxRcvReq)
+ Temp = CTEAllocMem(sizeof(TCPRcvReq));
+ else
+ Temp = NULL;
+
+ if (Temp != NULL) {
+ NumTCPRcvReq++;
+#ifdef DEBUG
+ Temp->trr_sig = trr_signature;
+#endif
+ }
+ }
+
+#endif // NT
+
+ return Temp;
+}
+
+
+
+//* FindLastBuffer - Find the last buffer in a chain.
+//
+// A utility routine to find the last buffer in an rb chain.
+//
+// Input: Buf - Pointer to RB chain.
+//
+// Returns: Pointer to last buf in chain.
+//
+IPRcvBuf *
+FindLastBuffer(IPRcvBuf *Buf)
+{
+ CTEAssert(Buf != NULL);
+
+ while (Buf->ipr_next != NULL)
+ Buf = Buf->ipr_next;
+
+ return Buf;
+}
+
+
+//* FreePartialRB - Free part of an RB chain.
+//
+// Called to adjust an free part of an RB chain. We walk down the chain,
+// trying to free buffers.
+//
+// Input: RB - RB chain to be adjusted.
+// Size - Size in bytes to be freed.
+//
+// Returns: Pointer to adjusted RB chain.
+//
+IPRcvBuf *
+FreePartialRB(IPRcvBuf *RB, uint Size)
+{
+ while (Size != 0) {
+ IPRcvBuf *TempBuf;
+
+ CTEAssert(RB != NULL);
+
+ if (Size >= RB->ipr_size) {
+ Size -= RB->ipr_size;
+ TempBuf = RB;
+ RB = RB->ipr_next;
+ if (TempBuf->ipr_owner == IPR_OWNER_TCP)
+ CTEFreeMem(TempBuf);
+ } else {
+ RB->ipr_size -= Size;
+ RB->ipr_buffer += Size;
+ break;
+ }
+ }
+
+ CTEAssert(RB != NULL);
+ return RB;
+
+}
+
+//* CopyRBChain - Copy a chain of IP rcv buffers.
+//
+// Called to copy a chain of IP rcv buffers. We don't copy a buffer if it's
+// already owner by TCP. We assume that all non-TCP owned buffers start
+// before any TCP owner buffers, so we quit when we copy to a TCP owner buffer.
+//
+// Input: OrigBuf - Buffer chain to copy from.
+// LastBuf - Where to return pointer to last buffer in
+// chain.
+// Size - Maximum size in bytes to copy.
+//
+// Returns: Pointer to new buffer chain.
+//
+IPRcvBuf *
+CopyRBChain(IPRcvBuf *OrigBuf, IPRcvBuf **LastBuf, uint Size)
+{
+ IPRcvBuf *FirstBuf, *EndBuf;
+ uint BytesToCopy;
+
+ CTEAssert(OrigBuf != NULL);
+ CTEAssert(Size > 0);
+
+ if (OrigBuf->ipr_owner != IPR_OWNER_TCP) {
+
+ BytesToCopy = MIN(Size, OrigBuf->ipr_size);
+ FirstBuf = CTEAllocMem(sizeof(IPRcvBuf) + BytesToCopy);
+ if (FirstBuf != NULL) {
+ EndBuf = FirstBuf;
+ FirstBuf->ipr_next = NULL;
+ FirstBuf->ipr_owner = IPR_OWNER_TCP;
+ FirstBuf->ipr_size = BytesToCopy;
+ FirstBuf->ipr_buffer = (uchar *)(FirstBuf + 1);
+ CTEMemCopy(FirstBuf->ipr_buffer, OrigBuf->ipr_buffer,
+ BytesToCopy);
+ Size -= BytesToCopy;
+ OrigBuf = OrigBuf->ipr_next;
+ while (OrigBuf != NULL && OrigBuf->ipr_owner != IPR_OWNER_TCP
+ && Size != 0) {
+ IPRcvBuf *NewBuf;
+
+ BytesToCopy = MIN(Size, OrigBuf->ipr_size);
+ NewBuf = CTEAllocMem(sizeof(IPRcvBuf) + BytesToCopy);
+ if (NewBuf != NULL) {
+ NewBuf->ipr_next = NULL;
+ NewBuf->ipr_owner = IPR_OWNER_TCP;
+ NewBuf->ipr_size = BytesToCopy;
+ NewBuf->ipr_buffer = (uchar *)(NewBuf + 1);
+ CTEMemCopy(NewBuf->ipr_buffer, OrigBuf->ipr_buffer,
+ BytesToCopy);
+ EndBuf->ipr_next = NewBuf;
+ EndBuf = NewBuf;
+ Size -= BytesToCopy;
+ OrigBuf = OrigBuf->ipr_next;
+ } else {
+ FreeRBChain(FirstBuf);
+ return NULL;
+ }
+ }
+ EndBuf->ipr_next = OrigBuf;
+ } else
+ return NULL;
+ } else {
+ FirstBuf = OrigBuf;
+ EndBuf = OrigBuf;
+ if (Size < OrigBuf->ipr_size)
+ OrigBuf->ipr_size = Size;
+ Size -= OrigBuf->ipr_size;
+ }
+
+ // Now walk down the chain, until we run out of
+ // Size. At this point, Size is the bytes left to 'copy' (it may be 0),
+ // and the sizes in buffers FirstBuf...EndBuf are correct.
+ while (Size != 0) {
+
+ EndBuf = EndBuf->ipr_next;
+ CTEAssert(EndBuf != NULL);
+
+ if (Size < EndBuf->ipr_size)
+ EndBuf->ipr_size = Size;
+
+ Size -= EndBuf->ipr_size;
+ }
+
+ // If there's anything left in the chain, free it now.
+ if (EndBuf->ipr_next != NULL) {
+ FreeRBChain(EndBuf->ipr_next);
+ EndBuf->ipr_next = NULL;
+ }
+
+ *LastBuf = EndBuf;
+ return FirstBuf;
+
+}
+
+//* PendData - Pend incoming data to a client.
+//
+// Called when we need to buffer data for a client because there's no receive
+// down and we can't indicate.
+//
+// The TCB lock is held throughout this procedure. If this is to be changed,
+// make sure consistency of tcb_pendingcnt is preserved. This routine is
+// always called at DPC level.
+//
+// Input: RcvTCB - TCB on which to receive the data.
+// RcvFlags - TCP flags for the incoming packet.
+// InBuffer - Input buffer of packet.
+// Size - Size in bytes of data in InBuffer.
+//
+// Returns: Number of bytes of data taken.
+//
+uint
+PendData(TCB *RcvTCB, uint RcvFlags, IPRcvBuf *InBuffer, uint Size)
+{
+
+ IPRcvBuf *NewBuf, *LastBuf;
+
+ CTEStructAssert(RcvTCB, tcb);
+ CTEAssert(Size > 0);
+ CTEAssert(InBuffer != NULL);
+
+ CTEAssert(RcvTCB->tcb_refcnt != 0);
+ CTEAssert(RcvTCB->tcb_fastchk & TCP_FLAG_IN_RCV);
+ CTEAssert(RcvTCB->tcb_currcv == NULL);
+ CTEAssert(RcvTCB->tcb_rcvhndlr == PendData);
+
+ CheckRBList(RcvTCB->tcb_pendhead, RcvTCB->tcb_pendingcnt);
+
+ NewBuf = CopyRBChain(InBuffer, &LastBuf, Size);
+ if (NewBuf != NULL) {
+ // We have a duplicate chain. Put it on the end of the
+ // pending q.
+ if (RcvTCB->tcb_pendhead == NULL) {
+ RcvTCB->tcb_pendhead = NewBuf;
+ RcvTCB->tcb_pendtail = LastBuf;
+ } else {
+ RcvTCB->tcb_pendtail->ipr_next = NewBuf;
+ RcvTCB->tcb_pendtail = LastBuf;
+ }
+ RcvTCB->tcb_pendingcnt += Size;
+ } else {
+ FreeRBChain(InBuffer);
+ Size = 0;
+ }
+
+ CheckRBList(RcvTCB->tcb_pendhead, RcvTCB->tcb_pendingcnt);
+
+ return Size;
+
+}
+
+
+
+//* BufferData - Put incoming data into client's buffer.
+//
+// Called when we believe we have a buffer into which we can put data. We put
+// it in there, and if we've filled the buffer or the incoming data has the
+// push flag set we'll mark the TCB to return the buffer. Otherwise we'll
+// get out and return the data later.
+//
+// In NT, this routine is called with the TCB lock held, and holds it for
+// the duration of the call. This is important to ensure consistency of
+// the tcb_pendingcnt field. If we need to change this to free the lock
+// partway through, make sure to take this into account. In particular,
+// TdiReceive zeros pendingcnt before calling this routine, and this routine
+// may update it. If the lock is freed in here there would be a window where
+// we really do have pending data, but it's not on the list or reflected in
+// pendingcnt. This could screw up our windowing computations, and we'd have
+// to be careful not to end up with more data pending than our window allows.
+//
+// Input: RcvTCB - TCB on which to receive the data.
+// RcvFlags - TCP rcv flags for the incoming packet.
+// InBuffer - Input buffer of packet.
+// Size - Size in bytes of data in InBuffer.
+//
+// Returns: Number of bytes of data taken.
+//
+uint
+BufferData(TCB *RcvTCB, uint RcvFlags, IPRcvBuf *InBuffer, uint Size)
+
+{
+ uchar *DestPtr; // Destination pointer.
+ uchar *SrcPtr; // Src pointer.
+ uint SrcSize, DestSize; // Sizes of current source and
+ // destination buffers.
+ uint Copied; // Total bytes to copy.
+ uint BytesToCopy; // Bytes of data to copy this time.
+ TCPRcvReq *DestReq; // Current receive request.
+ IPRcvBuf *SrcBuf; // Current source buffer.
+ PNDIS_BUFFER DestBuf; // Current receive buffer.
+ uint RcvCmpltd;
+ uint Flags;
+
+ CTEStructAssert(RcvTCB, tcb);
+ CTEAssert(Size > 0);
+ CTEAssert(InBuffer != NULL);
+
+ CTEAssert(RcvTCB->tcb_refcnt != 0);
+ CTEAssert(RcvTCB->tcb_rcvhndlr == BufferData);
+
+ Copied = 0;
+ RcvCmpltd = 0;
+
+ DestReq = RcvTCB->tcb_currcv;
+
+ CTEAssert(DestReq != NULL);
+ CTEStructAssert(DestReq, trr);
+
+ DestBuf = DestReq->trr_buffer;
+
+ DestSize = MIN(NdisBufferLength(DestBuf) - DestReq->trr_offset,
+ DestReq->trr_size - DestReq->trr_amt);
+ DestPtr = (uchar *)NdisBufferVirtualAddress(DestBuf) + DestReq->trr_offset;
+
+ SrcBuf = InBuffer;
+ SrcSize = SrcBuf->ipr_size;
+ SrcPtr = SrcBuf->ipr_buffer;
+
+ Flags = (RcvFlags & TCP_FLAG_PUSH) ? TRR_PUSHED : 0;
+ RcvCmpltd = Flags;
+ DestReq->trr_flags |= Flags;
+
+ do {
+
+ BytesToCopy = MIN(Size - Copied, MIN(SrcSize, DestSize));
+
+ CTEMemCopy(DestPtr, SrcPtr, BytesToCopy);
+ Copied += BytesToCopy;
+ DestReq->trr_amt += BytesToCopy;
+
+ // Update our source pointers.
+ if ((SrcSize -= BytesToCopy) == 0) {
+ IPRcvBuf *TempBuf;
+
+ // We've copied everything in this buffer.
+ TempBuf = SrcBuf;
+ SrcBuf = SrcBuf->ipr_next;
+ if (Size != Copied) {
+ CTEAssert(SrcBuf != NULL);
+ SrcSize = SrcBuf->ipr_size;
+ SrcPtr = SrcBuf->ipr_buffer;
+ }
+ if (TempBuf->ipr_owner == IPR_OWNER_TCP)
+ CTEFreeMem(TempBuf);
+ } else
+ SrcPtr += BytesToCopy;
+
+ // Now check the destination pointer, and update it if we need to.
+ if ((DestSize -= BytesToCopy) == 0) {
+ uint DestAvail;
+
+ // Exhausted this buffer. See if there's another one.
+ DestAvail = DestReq->trr_size - DestReq->trr_amt;
+ DestBuf = NDIS_BUFFER_LINKAGE(DestBuf);
+
+ if (DestBuf != NULL && (DestAvail != 0)) {
+ // Have another buffer in the chain. Update things.
+ DestSize = MIN(NdisBufferLength(DestBuf), DestAvail);
+ DestPtr = (uchar *)NdisBufferVirtualAddress(DestBuf);
+ } else {
+ // No more buffers in the chain. See if we have another buffer
+ // on the list.
+ DestReq->trr_flags |= TRR_PUSHED;
+
+ // If we've been told there's to be no back traffic, get an ACK
+ // going right away.
+ if (DestReq->trr_flags & TDI_RECEIVE_NO_RESPONSE_EXP)
+ DelayAction(RcvTCB, NEED_ACK);
+
+ RcvCmpltd = TRUE;
+ DestReq = DestReq->trr_next;
+ if (DestReq != NULL) {
+ DestBuf = DestReq->trr_buffer;
+ DestSize = MIN(NdisBufferLength(DestBuf), DestReq->trr_size);
+ DestPtr = (uchar *)NdisBufferVirtualAddress(DestBuf);
+
+ // If we have more to put into here, set the flags.
+ if (Copied != Size)
+ DestReq->trr_flags |= Flags;
+
+ } else {
+ // All out of buffer space. Reset the data handler pointer.
+ break;
+ }
+ }
+ } else
+ // Current buffer not empty yet.
+ DestPtr += BytesToCopy;
+
+
+ // If we've copied all that we need to, we're done.
+ } while (Copied != Size);
+
+ // We've finished copying, and have a few more things to do. We need to
+ // update the current rcv. pointer and possibly the offset in the
+ // recv. request. If we need to complete any receives we have to schedule
+ // that. If there's any data we couldn't copy we'll need to dispose of
+ // it.
+ RcvTCB->tcb_currcv = DestReq;
+ if (DestReq != NULL) {
+ DestReq->trr_buffer = DestBuf;
+ DestReq->trr_offset = DestPtr - (uchar *) NdisBufferVirtualAddress(DestBuf);
+ RcvTCB->tcb_rcvhndlr = BufferData;
+ } else
+ RcvTCB->tcb_rcvhndlr = PendData;
+
+ RcvTCB->tcb_indicated -= MIN(Copied, RcvTCB->tcb_indicated);
+
+ if (Size != Copied) {
+ IPRcvBuf *NewBuf, *LastBuf;
+
+ CTEAssert(DestReq == NULL);
+
+ // We have data to dispose of. Update the first buffer of the chain
+ // with the current src pointer and size, and copy it.
+ CTEAssert(SrcSize <= SrcBuf->ipr_size);
+ CTEAssert(
+ ((uint) (SrcPtr - SrcBuf->ipr_buffer)) ==
+ (SrcBuf->ipr_size - SrcSize)
+ );
+
+ SrcBuf->ipr_buffer = SrcPtr;
+ SrcBuf->ipr_size = SrcSize;
+
+ NewBuf = CopyRBChain(SrcBuf, &LastBuf, Size - Copied);
+ if (NewBuf != NULL) {
+ // We managed to copy the buffer. Push it on the pending queue.
+ if (RcvTCB->tcb_pendhead == NULL) {
+ RcvTCB->tcb_pendhead = NewBuf;
+ RcvTCB->tcb_pendtail = LastBuf;
+ } else {
+ LastBuf->ipr_next = RcvTCB->tcb_pendhead;
+ RcvTCB->tcb_pendhead = NewBuf;
+ }
+ RcvTCB->tcb_pendingcnt += Size - Copied;
+ Copied = Size;
+
+ CheckRBList(RcvTCB->tcb_pendhead, RcvTCB->tcb_pendingcnt);
+
+ } else
+ FreeRBChain(SrcBuf);
+ } else {
+ // We copied Size bytes, but the chain could be longer than that. Free
+ // it if we need to.
+ if (SrcBuf != NULL)
+ FreeRBChain(SrcBuf);
+ }
+
+
+ if (RcvCmpltd != 0) {
+ DelayAction(RcvTCB, NEED_RCV_CMPLT);
+ } else {
+ START_TCB_TIMER(RcvTCB->tcb_pushtimer, PUSH_TO);
+ }
+
+ return Copied;
+
+}
+
+
+//* IndicateData - Indicate incoming data to a client.
+//
+// Called when we need to indicate data to an upper layer client. We'll pass
+// up a pointer to whatever we have available, and the client may take some
+// or all of it.
+//
+// Input: RcvTCB - TCB on which to receive the data.
+// RcvFlags - TCP rcv flags for the incoming packet.
+// InBuffer - Input buffer of packet.
+// Size - Size in bytes of data in InBuffer.
+//
+// Returns: Number of bytes of data taken.
+//
+uint
+IndicateData(TCB *RcvTCB, uint RcvFlags, IPRcvBuf *InBuffer, uint Size)
+{
+
+ TDI_STATUS Status;
+ PRcvEvent Event;
+ PVOID EventContext, ConnContext;
+ uint BytesTaken = 0;
+#ifdef NT
+ EventRcvBuffer *ERB = NULL;
+ PTDI_REQUEST_KERNEL_RECEIVE RequestInformation;
+ PIO_STACK_LOCATION IrpSp;
+#else
+ EventRcvBuffer ERB;
+#endif
+ TCPRcvReq *RcvReq;
+ IPRcvBuf *NewBuf;
+ ulong IndFlags;
+
+
+ CTEStructAssert(RcvTCB, tcb);
+ CTEAssert(Size > 0);
+ CTEAssert(InBuffer != NULL);
+
+ CTEAssert(RcvTCB->tcb_refcnt != 0);
+ CTEAssert(RcvTCB->tcb_fastchk & TCP_FLAG_IN_RCV);
+ CTEAssert(RcvTCB->tcb_rcvind != NULL);
+ CTEAssert(RcvTCB->tcb_rcvhead == NULL);
+ CTEAssert(RcvTCB->tcb_rcvhndlr == IndicateData);
+
+ RcvReq = GetRcvReq();
+ if (RcvReq != NULL) {
+ // The indicate handler is saved in the TCB. Just call up into it.
+ Event = RcvTCB->tcb_rcvind;
+ EventContext = RcvTCB->tcb_ricontext;
+ ConnContext = RcvTCB->tcb_conncontext;
+ RcvTCB->tcb_indicated = Size;
+ RcvTCB->tcb_flags |= IN_RCV_IND;
+
+#ifndef VXD
+ CTEFreeLockFromDPC(&RcvTCB->tcb_lock, NULL);
+#endif
+
+ IF_TCPDBG(TCP_DEBUG_RECEIVE) {
+ TCPTRACE((
+ "Indicating %lu bytes, %lu available\n",
+ InBuffer->ipr_size, Size
+ ));
+ }
+
+#if TCP_FLAG_PUSH >= TDI_RECEIVE_ENTIRE_MESSAGE
+ IndFlags = TDI_RECEIVE_COPY_LOOKAHEAD | TDI_RECEIVE_NORMAL |
+ TDI_RECEIVE_AT_DISPATCH_LEVEL |
+ ((RcvFlags & TCP_FLAG_PUSH) >>
+ ((TCP_FLAG_PUSH / TDI_RECEIVE_ENTIRE_MESSAGE) - 1));
+#else
+ IndFlags = TDI_RECEIVE_COPY_LOOKAHEAD | TDI_RECEIVE_NORMAL |
+ TDI_RECEIVE_AT_DISPATCH_LEVEL |
+ ((RcvFlags & TCP_FLAG_PUSH) <<
+ ((TDI_RECEIVE_ENTIRE_MESSAGE / TCP_FLAG_PUSH) - 1));
+#endif
+
+ Status = (*Event)(EventContext, ConnContext,
+ IndFlags, InBuffer->ipr_size, Size, &BytesTaken,
+ InBuffer->ipr_buffer, &ERB);
+
+ IF_TCPDBG(TCP_DEBUG_RECEIVE) {
+ TCPTRACE(("%lu bytes taken, status %lx\n", BytesTaken, Status));
+ }
+
+ // See what the client did. If the return status is MORE_PROCESSING,
+ // we've been given a buffer. In that case put it on the front of the
+ // buffer queue, and if all the data wasn't taken go ahead and copy
+ // it into the new buffer chain.
+ //
+ // Note that the size and buffer chain we're concerned with here is
+ // the one that we passed to the client. Since we're in a rcv. handler,
+ // any data that has come in would have been put on the reassembly
+ // queue.
+ if (Status == TDI_MORE_PROCESSING) {
+
+#ifdef NT
+
+ CTEAssert(ERB != NULL);
+
+ IrpSp = IoGetCurrentIrpStackLocation(ERB);
+
+ Status = TCPPrepareIrpForCancel(
+ (PTCP_CONTEXT) IrpSp->FileObject->FsContext,
+ ERB,
+ TCPCancelRequest
+ );
+
+ if (NT_SUCCESS(Status)) {
+
+ RequestInformation = (PTDI_REQUEST_KERNEL_RECEIVE)
+ &(IrpSp->Parameters);
+
+ RcvReq->trr_rtn = TCPDataRequestComplete;
+ RcvReq->trr_context = ERB;
+ RcvReq->trr_buffer = ERB->MdlAddress;
+ RcvReq->trr_size = RequestInformation->ReceiveLength;
+ RcvReq->trr_uflags = (ushort *)
+ &(RequestInformation->ReceiveFlags);
+ RcvReq->trr_flags = (uint)(RequestInformation->ReceiveFlags);
+ RcvReq->trr_offset = 0;
+ RcvReq->trr_amt = 0;
+
+ CTEGetLockAtDPC(&RcvTCB->tcb_lock, NULL);
+
+#else // NT
+
+ RcvReq->trr_rtn = ERB.erb_rtn;
+ RcvReq->trr_context = ERB.erb_context;
+ RcvReq->trr_buffer = ERB.erb_buffer;
+ RcvReq->trr_size = ERB.erb_size;
+ RcvReq->trr_uflags = ERB.erb_flags;
+ CTEAssert(ERB.erb_flags != NULL);
+ RcvReq->trr_flags = (uint)(*ERB.erb_flags);
+ RcvReq->trr_offset = 0;
+ RcvReq->trr_amt = 0;
+
+#endif // NT
+
+ RcvTCB->tcb_flags &= ~IN_RCV_IND;
+
+ CTEAssert(RcvTCB->tcb_rcvhndlr == IndicateData);
+
+ // Push him on the front of the rcv. queue.
+ CTEAssert((RcvTCB->tcb_currcv == NULL) ||
+ (RcvTCB->tcb_currcv->trr_amt == 0));
+
+ if (RcvTCB->tcb_rcvhead == NULL) {
+ RcvTCB->tcb_rcvhead = RcvReq;
+ RcvTCB->tcb_rcvtail = RcvReq;
+ RcvReq->trr_next = NULL;
+ } else {
+ RcvReq->trr_next = RcvTCB->tcb_rcvhead;
+ RcvTCB->tcb_rcvhead = RcvReq;
+ }
+
+ RcvTCB->tcb_currcv = RcvReq;
+ RcvTCB->tcb_rcvhndlr = BufferData;
+
+ CTEAssert(BytesTaken <= Size);
+
+ RcvTCB->tcb_indicated -= BytesTaken;
+ if ((Size -= BytesTaken) != 0) {
+
+ // Not everything was taken. Adjust the buffer chain to point
+ // beyond what was taken.
+ InBuffer = FreePartialRB(InBuffer, BytesTaken);
+
+ CTEAssert(InBuffer != NULL);
+
+ // We've adjusted the buffer chain. Call the BufferData
+ // handler.
+ BytesTaken += BufferData(RcvTCB, RcvFlags, InBuffer, Size);
+
+ } else {
+ // All of the data was taken. Free the buffer chain.
+ FreeRBChain(InBuffer);
+ }
+
+ return BytesTaken;
+#ifdef NT
+ }
+ else {
+ //
+ // The IRP was cancelled before it was handed back to us.
+ // We'll pretend we never saw it. TCPPrepareIrpForCancel
+ // already completed it. The client may have taken data,
+ // so we will act as if success was returned.
+ //
+ ERB = NULL;
+ Status = TDI_SUCCESS;
+ }
+
+#endif // NT
+
+ }
+
+ CTEGetLockAtDPC(&RcvTCB->tcb_lock, NULL);
+
+ RcvTCB->tcb_flags &= ~IN_RCV_IND;
+
+ // Status is not more processing. If it's not SUCCESS, the client
+ // didn't take any of the data. In either case we now need to
+ // see if all of the data was taken. If it wasn't, we'll try and
+ // push it onto the front of the pending queue.
+
+ FreeRcvReq(RcvReq); // This won't be needed.
+ if (Status == TDI_NOT_ACCEPTED)
+ BytesTaken = 0;
+
+ CTEAssert(BytesTaken <= Size);
+
+ RcvTCB->tcb_indicated -= BytesTaken;
+
+ CTEAssert(RcvTCB->tcb_rcvhndlr == IndicateData);
+
+ // Check to see if a rcv. buffer got posted during the indication.
+ // If it did, reset the recv. handler now.
+ if (RcvTCB->tcb_rcvhead != NULL)
+ RcvTCB->tcb_rcvhndlr = BufferData;
+
+
+ // See if all of the data was taken.
+ if (BytesTaken == Size) {
+ CTEAssert(RcvTCB->tcb_indicated == 0);
+
+ FreeRBChain(InBuffer);
+ return BytesTaken; // It was all taken.
+ }
+
+ // It wasn't all taken. Adjust for what was taken, and push
+ // on the front of the pending queue. We also need to check to
+ // see if a receive buffer got posted during the indication. This
+ // would be weird, but not impossible.
+ InBuffer = FreePartialRB(InBuffer, BytesTaken);
+ if (RcvTCB->tcb_rcvhead == NULL) {
+ IPRcvBuf *LastBuf;
+
+ RcvTCB->tcb_rcvhndlr = PendData;
+ NewBuf = CopyRBChain(InBuffer, &LastBuf, Size - BytesTaken);
+ if (NewBuf != NULL) {
+ // We have a duplicate chain. Push it on the front of the
+ // pending q.
+ if (RcvTCB->tcb_pendhead == NULL) {
+ RcvTCB->tcb_pendhead = NewBuf;
+ RcvTCB->tcb_pendtail = LastBuf;
+ } else {
+ LastBuf->ipr_next = RcvTCB->tcb_pendhead;
+ RcvTCB->tcb_pendhead = NewBuf;
+ }
+ RcvTCB->tcb_pendingcnt += Size - BytesTaken;
+ BytesTaken = Size;
+ } else {
+ FreeRBChain(InBuffer);
+ }
+
+ return BytesTaken;
+ } else {
+ // Just great. There's now a rcv. buffer on the TCB. Call the
+ // BufferData handler now.
+ CTEAssert(RcvTCB->tcb_rcvhndlr = BufferData);
+
+ BytesTaken += BufferData(RcvTCB, RcvFlags, InBuffer,
+ Size - BytesTaken);
+
+ return BytesTaken;
+ }
+
+ } else {
+ // Couldn't get a recv. request. We must be really low on resources,
+ // so just bail out now.
+ FreeRBChain(InBuffer);
+ return 0;
+ }
+
+}
+
+
+//* IndicatePendingData - Indicate pending data to a client.
+//
+// Called when we need to indicate pending data to an upper layer client,
+// usually because data arrived when we were in a state that it couldn't
+// be indicated.
+//
+// Many of the comments in the BufferData header about the consistency of
+// tcb_pendingcnt apply here also.
+//
+// Input: RcvTCB - TCB on which to indicate the data.
+// RcvReq - Rcv. req. to use to indicate it.
+//
+// Returns: Nothing.
+//
+void
+#ifdef VXD
+IndicatePendingData(TCB *RcvTCB, TCPRcvReq *RcvReq)
+#else
+IndicatePendingData(TCB *RcvTCB, TCPRcvReq *RcvReq, CTELockHandle TCBHandle)
+#endif
+{
+
+ TDI_STATUS Status;
+ PRcvEvent Event;
+ PVOID EventContext, ConnContext;
+ uint BytesTaken = 0;
+#ifdef NT
+ EventRcvBuffer *ERB = NULL;
+ PTDI_REQUEST_KERNEL_RECEIVE RequestInformation;
+ PIO_STACK_LOCATION IrpSp;
+#else
+ EventRcvBuffer ERB;
+ CTELockHandle TCBHandle; // For debug builds.
+#endif
+ IPRcvBuf *NewBuf;
+ uint Size;
+
+
+ CTEStructAssert(RcvTCB, tcb);
+
+ CTEAssert(RcvTCB->tcb_refcnt != 0);
+ CTEAssert(RcvTCB->tcb_rcvind != NULL);
+ CTEAssert(RcvTCB->tcb_rcvhead == NULL);
+ CTEAssert(RcvTCB->tcb_pendingcnt != 0);
+ CTEAssert(RcvReq != NULL);
+
+#ifdef VXD
+ CTEGetLock(&RcvTCB->tcb_lock, &TCBHandle);
+#endif
+
+ for (;;) {
+ CTEAssert(RcvTCB->tcb_rcvhndlr == PendData);
+
+ // The indicate handler is saved in the TCB. Just call up into it.
+ Event = RcvTCB->tcb_rcvind;
+ EventContext = RcvTCB->tcb_ricontext;
+ ConnContext = RcvTCB->tcb_conncontext;
+ RcvTCB->tcb_indicated = RcvTCB->tcb_pendingcnt;
+ RcvTCB->tcb_flags |= IN_RCV_IND;
+
+ CTEFreeLock(&RcvTCB->tcb_lock, TCBHandle);
+
+ IF_TCPDBG(TCPDebug & TCP_DEBUG_RECEIVE) {
+ TCPTRACE((
+ "Indicating pending %d bytes, %d available\n",
+ RcvTCB->tcb_pendhead->ipr_size, RcvTCB->tcb_pendingcnt
+ ));
+ }
+
+ Status = (*Event)(EventContext, ConnContext,
+ TDI_RECEIVE_COPY_LOOKAHEAD | TDI_RECEIVE_NORMAL |
+ TDI_RECEIVE_ENTIRE_MESSAGE,
+ RcvTCB->tcb_pendhead->ipr_size, RcvTCB->tcb_pendingcnt,
+ &BytesTaken, RcvTCB->tcb_pendhead->ipr_buffer, &ERB);
+
+ IF_TCPDBG(TCPDebug & TCP_DEBUG_RECEIVE) {
+ TCPTRACE(("%d bytes taken\n", BytesTaken));
+ }
+
+ // See what the client did. If the return status is MORE_PROCESSING,
+ // we've been given a buffer. In that case put it on the front of the
+ // buffer queue, and if all the data wasn't taken go ahead and copy
+ // it into the new buffer chain.
+ if (Status == TDI_MORE_PROCESSING) {
+
+#ifdef NT
+
+ IF_TCPDBG(TCP_DEBUG_RECEIVE) {
+ TCPTRACE(("more processing on receive\n"));
+ }
+
+ CTEAssert(ERB != NULL);
+
+ IrpSp = IoGetCurrentIrpStackLocation(ERB);
+
+ Status = TCPPrepareIrpForCancel(
+ (PTCP_CONTEXT) IrpSp->FileObject->FsContext,
+ ERB,
+ TCPCancelRequest
+ );
+
+ if (NT_SUCCESS(Status)) {
+
+ RequestInformation = (PTDI_REQUEST_KERNEL_RECEIVE)
+ &(IrpSp->Parameters);
+
+ RcvReq->trr_rtn = TCPDataRequestComplete;
+ RcvReq->trr_context = ERB;
+ RcvReq->trr_buffer = ERB->MdlAddress;
+ RcvReq->trr_size = RequestInformation->ReceiveLength;
+ RcvReq->trr_uflags = (ushort *)
+ &(RequestInformation->ReceiveFlags);
+ RcvReq->trr_flags = (uint)(RequestInformation->ReceiveFlags);
+ RcvReq->trr_offset = 0;
+ RcvReq->trr_amt = 0;
+
+#else // NT
+
+ RcvReq->trr_rtn = ERB.erb_rtn;
+ RcvReq->trr_context = ERB.erb_context;
+ RcvReq->trr_buffer = ERB.erb_buffer;
+ RcvReq->trr_size = ERB.erb_size;
+ RcvReq->trr_uflags = ERB.erb_flags;
+ RcvReq->trr_flags = (uint)(*ERB.erb_flags);
+ RcvReq->trr_offset = 0;
+ RcvReq->trr_amt = 0;
+
+#endif // NT
+
+ CTEGetLock(&RcvTCB->tcb_lock, &TCBHandle);
+ RcvTCB->tcb_flags &= ~IN_RCV_IND;
+
+ // Push him on the front of the rcv. queue.
+ CTEAssert((RcvTCB->tcb_currcv == NULL) ||
+ (RcvTCB->tcb_currcv->trr_amt == 0));
+
+ if (RcvTCB->tcb_rcvhead == NULL) {
+ RcvTCB->tcb_rcvhead = RcvReq;
+ RcvTCB->tcb_rcvtail = RcvReq;
+ RcvReq->trr_next = NULL;
+ } else {
+ RcvReq->trr_next = RcvTCB->tcb_rcvhead;
+ RcvTCB->tcb_rcvhead = RcvReq;
+ }
+
+ RcvTCB->tcb_currcv = RcvReq;
+ RcvTCB->tcb_rcvhndlr = BufferData;
+
+ // Have to pick up the new size and pointers now, since things could
+ // have changed during the upcall.
+ Size = RcvTCB->tcb_pendingcnt;
+ NewBuf = RcvTCB->tcb_pendhead;
+
+ RcvTCB->tcb_pendingcnt = 0;
+ RcvTCB->tcb_pendhead = NULL;
+
+ CTEAssert(BytesTaken <= Size);
+
+ RcvTCB->tcb_indicated -= BytesTaken;
+ if ((Size -= BytesTaken) != 0) {
+
+ // Not everything was taken. Adjust the buffer chain to point
+ // beyond what was taken.
+ NewBuf = FreePartialRB(NewBuf, BytesTaken);
+
+ CTEAssert(NewBuf != NULL);
+
+ // We've adjusted the buffer chain. Call the BufferData
+ // handler.
+#ifdef VXD
+ CTEFreeLock(&RcvTCB->tcb_lock, TCBHandle);
+ (void)BufferData(RcvTCB, TCP_FLAG_PUSH, NewBuf, Size);
+#else
+ (void)BufferData(RcvTCB, TCP_FLAG_PUSH, NewBuf, Size);
+ CTEFreeLock(&RcvTCB->tcb_lock, TCBHandle);
+#endif
+
+ } else {
+ // All of the data was taken. Free the buffer chain. Since
+ // we were passed a buffer chain which we put on the head of
+ // the list, leave the rcvhandler pointing at BufferData.
+ CTEAssert(RcvTCB->tcb_rcvhndlr == BufferData);
+ CTEAssert(RcvTCB->tcb_indicated == 0);
+ CTEAssert(RcvTCB->tcb_rcvhead != NULL);
+
+ CTEFreeLock(&RcvTCB->tcb_lock, TCBHandle);
+ FreeRBChain(NewBuf);
+ }
+
+ return;
+#ifdef NT
+ }
+ else {
+ //
+ // The IRP was cancelled before it was handed back to us.
+ // We'll pretend we never saw it. TCPPrepareIrpForCancel
+ // already completed it. The client may have taken data,
+ // so we will act as if success was returned.
+ //
+ ERB = NULL;
+ Status = TDI_SUCCESS;
+ }
+
+#endif // NT
+
+ }
+
+ CTEGetLock(&RcvTCB->tcb_lock, &TCBHandle);
+
+ RcvTCB->tcb_flags &= ~IN_RCV_IND;
+
+ // Status is not more processing. If it's not SUCCESS, the client
+ // didn't take any of the data. In either case we now need to
+ // see if all of the data was taken. If it wasn't, we're done.
+
+ if (Status == TDI_NOT_ACCEPTED)
+ BytesTaken = 0;
+
+ CTEAssert(RcvTCB->tcb_rcvhndlr == PendData);
+
+ RcvTCB->tcb_indicated -= BytesTaken;
+ Size = RcvTCB->tcb_pendingcnt;
+ NewBuf = RcvTCB->tcb_pendhead;
+
+ CTEAssert(BytesTaken <= Size);
+
+ // See if all of the data was taken.
+ if (BytesTaken == Size) {
+ // It was all taken. Zap the pending data information.
+ RcvTCB->tcb_pendingcnt = 0;
+ RcvTCB->tcb_pendhead = NULL;
+
+ CTEAssert(RcvTCB->tcb_indicated == 0);
+ if (RcvTCB->tcb_rcvhead == NULL) {
+ if (RcvTCB->tcb_rcvind != NULL)
+ RcvTCB->tcb_rcvhndlr = IndicateData;
+ } else
+ RcvTCB->tcb_rcvhndlr = BufferData;
+
+ CTEFreeLock(&RcvTCB->tcb_lock, TCBHandle);
+ FreeRBChain(NewBuf);
+ break;
+ }
+
+ // It wasn't all taken. Adjust for what was taken, We also need to check
+ // to see if a receive buffer got posted during the indication. This
+ // would be weird, but not impossible.
+ NewBuf = FreePartialRB(NewBuf, BytesTaken);
+
+ CTEAssert(RcvTCB->tcb_rcvhndlr == PendData);
+
+ if (RcvTCB->tcb_rcvhead == NULL) {
+ RcvTCB->tcb_pendhead = NewBuf;
+ RcvTCB->tcb_pendingcnt -= BytesTaken;
+ if (RcvTCB->tcb_indicated != 0 || RcvTCB->tcb_rcvind == NULL) {
+ CTEFreeLock(&RcvTCB->tcb_lock, TCBHandle);
+ break;
+ }
+
+ // From here, we'll loop around and indicate the new data that
+ // presumably came in during the previous indication.
+ } else {
+ // Just great. There's now a rcv. buffer on the TCB. Call the
+ // BufferData handler now.
+ RcvTCB->tcb_rcvhndlr = BufferData;
+ RcvTCB->tcb_pendingcnt = 0;
+ RcvTCB->tcb_pendhead = NULL;
+#ifdef VXD
+ CTEFreeLock(&RcvTCB->tcb_lock, TCBHandle);
+ BytesTaken += BufferData(RcvTCB, TCP_FLAG_PUSH, NewBuf,
+ Size - BytesTaken);
+#else
+ BytesTaken += BufferData(RcvTCB, TCP_FLAG_PUSH, NewBuf,
+ Size - BytesTaken);
+ CTEFreeLock(&RcvTCB->tcb_lock, TCBHandle);
+#endif
+ break;
+ }
+
+ } // for (;;)
+
+ FreeRcvReq(RcvReq); // This isn't needed anymore.
+
+}
+
+//* DeliverUrgent - Deliver urgent data to a client.
+//
+// Called to deliver urgent data to a client. We assume the input
+// urgent data is in a buffer we can keep. The buffer can be NULL, in
+// which case we'll just look on the urgent pending queue for data.
+//
+// Input: RcvTCB - TCB to deliver on.
+// RcvBuf - RcvBuffer for urgent data.
+// Size - Number of bytes of urgent data to deliver.
+//
+// Returns: Nothing.
+//
+void
+DeliverUrgent(TCB *RcvTCB, IPRcvBuf *RcvBuf, uint Size,
+ CTELockHandle *TCBHandle)
+{
+ CTELockHandle AOHandle, AOTblHandle, ConnHandle;
+ TCPRcvReq *RcvReq, *PrevReq;
+ uint BytesTaken = 0;
+ IPRcvBuf *LastBuf;
+#ifdef NT
+ EventRcvBuffer *ERB;
+#else
+ EventRcvBuffer ERB;
+#endif
+ PRcvEvent ExpRcv;
+ PVOID ExpRcvContext;
+ PVOID ConnContext;
+ TDI_STATUS Status;
+
+ CTEStructAssert(RcvTCB, tcb);
+ CTEAssert(RcvTCB->tcb_refcnt != 0);
+
+ CheckRBList(RcvTCB->tcb_urgpending, RcvTCB->tcb_urgcnt);
+
+ // See if we have new data, or are processing old data.
+ if (RcvBuf != NULL) {
+ // We have new data. If the pending queue is not NULL, or we're already
+ // in this routine, just put the buffer on the end of the queue.
+ if (RcvTCB->tcb_urgpending != NULL || (RcvTCB->tcb_flags & IN_DELIV_URG)) {
+ IPRcvBuf *PrevRcvBuf;
+
+ // Put him on the end of the queue.
+ PrevRcvBuf = STRUCT_OF(IPRcvBuf, &RcvTCB->tcb_urgpending, ipr_next);
+ while (PrevRcvBuf->ipr_next != NULL)
+ PrevRcvBuf = PrevRcvBuf->ipr_next;
+
+ PrevRcvBuf->ipr_next = RcvBuf;
+ return;
+ }
+ } else {
+ // The input buffer is NULL. See if we have existing data, or are in
+ // this routine. If we have no existing data or are in this routine
+ // just return.
+ if (RcvTCB->tcb_urgpending == NULL ||
+ (RcvTCB->tcb_flags & IN_DELIV_URG)) {
+ return;
+ } else {
+ RcvBuf = RcvTCB->tcb_urgpending;
+ Size = RcvTCB->tcb_urgcnt;
+ RcvTCB->tcb_urgpending = NULL;
+ RcvTCB->tcb_urgcnt = 0;
+ }
+ }
+
+
+ CTEAssert(RcvBuf != NULL);
+ CTEAssert(!(RcvTCB->tcb_flags & IN_DELIV_URG));
+
+ // We know we have data to deliver, and we have a pointer and a size.
+ // Go into a loop, trying to deliver the data. On each iteration, we'll
+ // try to find a buffer for the data. If we find one, we'll copy and
+ // complete it right away. Otherwise we'll try and indicate it. If we
+ // can't indicate it, we'll put it on the pending queue and leave.
+ RcvTCB->tcb_flags |= IN_DELIV_URG;
+ RcvTCB->tcb_slowcount++;
+ RcvTCB->tcb_fastchk |= TCP_FLAG_SLOW;
+ CheckTCBRcv(RcvTCB);
+
+ do {
+ CheckRBList(RcvTCB->tcb_urgpending, RcvTCB->tcb_urgcnt);
+
+ BytesTaken = 0;
+
+ // First check the expedited queue.
+ if ((RcvReq = RcvTCB->tcb_exprcv) != NULL)
+ RcvTCB->tcb_exprcv = RcvReq->trr_next;
+ else {
+ // Nothing in the expedited rcv. queue. Walk down the ordinary
+ // receive queue, looking for a buffer that we can steal.
+ PrevReq = STRUCT_OF(TCPRcvReq, &RcvTCB->tcb_rcvhead, trr_next);
+ RcvReq = PrevReq->trr_next;
+ while (RcvReq != NULL) {
+ CTEStructAssert(RcvReq, trr);
+ if (RcvReq->trr_flags & TDI_RECEIVE_EXPEDITED) {
+ // This is a candidate.
+ if (RcvReq->trr_amt == 0) {
+
+ CTEAssert(RcvTCB->tcb_rcvhndlr == BufferData);
+
+ // And he has nothing currently in him. Pull him
+ // out of the queue.
+ if (RcvTCB->tcb_rcvtail == RcvReq) {
+ if (RcvTCB->tcb_rcvhead == RcvReq)
+ RcvTCB->tcb_rcvtail = NULL;
+ else
+ RcvTCB->tcb_rcvtail = PrevReq;
+ }
+
+ PrevReq->trr_next = RcvReq->trr_next;
+ if (RcvTCB->tcb_currcv == RcvReq) {
+ RcvTCB->tcb_currcv = RcvReq->trr_next;
+ if (RcvTCB->tcb_currcv == NULL) {
+ // We've taken the last receive from the list.
+ // Reset the rcvhndlr.
+ if (RcvTCB->tcb_rcvind != NULL &&
+ RcvTCB->tcb_indicated == 0)
+ RcvTCB->tcb_rcvhndlr = IndicateData;
+ else
+ RcvTCB->tcb_rcvhndlr = PendData;
+ }
+ }
+
+ break;
+ }
+ }
+ PrevReq = RcvReq;
+ RcvReq = PrevReq->trr_next;
+ }
+ }
+
+ // We've done our best to get a buffer. If we got one, copy into it
+ // now, and complete the request.
+
+ if (RcvReq != NULL) {
+ // Got a buffer.
+ CTEFreeLock(&RcvTCB->tcb_lock, *TCBHandle);
+ BytesTaken = CopyRcvToNdis(RcvBuf, RcvReq->trr_buffer, Size, 0, 0);
+ (*RcvReq->trr_rtn)(RcvReq->trr_context, TDI_SUCCESS, BytesTaken);
+ FreeRcvReq(RcvReq);
+ CTEGetLock(&RcvTCB->tcb_lock, TCBHandle);
+ RcvTCB->tcb_urgind -= MIN(RcvTCB->tcb_urgind, BytesTaken);
+
+ } else {
+ // No posted buffer. If we can indicate, do so.
+ if (RcvTCB->tcb_urgind == 0) {
+ TCPConn *Conn;
+
+ // See if he has an expedited rcv handler.
+ ConnContext = RcvTCB->tcb_conncontext;
+ CTEFreeLock(&RcvTCB->tcb_lock, *TCBHandle);
+ CTEGetLock(&AddrObjTableLock, &AOTblHandle);
+ CTEGetLock(&ConnTableLock, &ConnHandle);
+ CTEGetLock(&RcvTCB->tcb_lock, TCBHandle);
+ if ((Conn = RcvTCB->tcb_conn) != NULL) {
+ CTEStructAssert(Conn, tc);
+ CTEAssert(Conn->tc_tcb == RcvTCB);
+ CTEFreeLock(&RcvTCB->tcb_lock, *TCBHandle);
+ if (Conn->tc_ao != NULL) {
+ AddrObj *AO;
+
+ AO = Conn->tc_ao;
+ CTEGetLock(&AO->ao_lock, &AOHandle);
+ if (AO_VALID(AO) && (ExpRcv = AO->ao_exprcv) != NULL) {
+ ExpRcvContext = AO->ao_exprcvcontext;
+ CTEFreeLock(&AO->ao_lock, AOHandle);
+
+ // We're going to indicate.
+ RcvTCB->tcb_urgind = Size;
+ CTEFreeLock(&ConnTableLock, ConnHandle);
+ CTEFreeLock(&AddrObjTableLock, AOTblHandle);
+
+ Status = (*ExpRcv)(ExpRcvContext, ConnContext,
+ TDI_RECEIVE_COPY_LOOKAHEAD |
+ TDI_RECEIVE_ENTIRE_MESSAGE |
+ TDI_RECEIVE_EXPEDITED,
+ RcvBuf->ipr_size, Size, &BytesTaken,
+ RcvBuf->ipr_buffer, &ERB);
+
+ CTEGetLock(&RcvTCB->tcb_lock, TCBHandle);
+
+ // See what he did with it.
+ if (Status == TDI_MORE_PROCESSING) {
+ uint CopySize;
+
+ // He gave us a buffer.
+ if (BytesTaken == Size) {
+ // He gave us a buffer, but took all of
+ // it. We'll just return it to him.
+ CopySize = 0;
+ } else {
+ // We have some data to copy in.
+ RcvBuf = FreePartialRB(RcvBuf, BytesTaken);
+
+#ifdef NT
+ CopySize = CopyRcvToNdis(RcvBuf,
+ ERB->MdlAddress,
+ TCPGetMdlChainByteCount(ERB->MdlAddress),
+ 0, 0);
+#else // NT
+ CopySize = CopyRcvToNdis(RcvBuf,
+ ERB.erb_buffer, ERB.erb_size, 0, 0);
+#endif // NT
+
+ }
+ BytesTaken += CopySize;
+ RcvTCB->tcb_urgind -= MIN(RcvTCB->tcb_urgind,
+ BytesTaken);
+ CTEFreeLock(&RcvTCB->tcb_lock, *TCBHandle);
+
+#ifdef NT
+
+ ERB->IoStatus.Status = TDI_SUCCESS;
+ ERB->IoStatus.Information = CopySize;
+ IoCompleteRequest(ERB, 2);
+
+#else // NT
+ (*ERB.erb_rtn)(ERB.erb_context, TDI_SUCCESS,
+ CopySize);
+#endif // NT
+
+ CTEGetLock(&RcvTCB->tcb_lock, TCBHandle);
+
+ } else {
+
+ // No buffer to deal with.
+ if (Status == TDI_NOT_ACCEPTED)
+ BytesTaken = 0;
+
+ RcvTCB->tcb_urgind -= MIN(RcvTCB->tcb_urgind,
+ BytesTaken);
+
+ }
+ goto checksize;
+ } else // No rcv. handler.
+ CTEFreeLock(&AO->ao_lock, AOHandle);
+ }
+ // Conn->tc_ao == NULL.
+ CTEFreeLock(&ConnTableLock, ConnHandle);
+ CTEFreeLock(&AddrObjTableLock, AOTblHandle);
+ CTEGetLock(&RcvTCB->tcb_lock, TCBHandle);
+ } else {
+ // RcvTCB has invalid index.
+ CTEFreeLock(&ConnTableLock, *TCBHandle);
+ CTEFreeLock(&AddrObjTableLock, ConnHandle);
+ *TCBHandle = AOTblHandle;
+ }
+
+ }
+
+ // For whatever reason we couldn't indicate the data. At this point
+ // we hold the lock on the TCB. Push the buffer onto the pending
+ // queue and return.
+ CheckRBList(RcvTCB->tcb_urgpending, RcvTCB->tcb_urgcnt);
+
+ LastBuf = FindLastBuffer(RcvBuf);
+ LastBuf->ipr_next = RcvTCB->tcb_urgpending;
+ RcvTCB->tcb_urgpending = RcvBuf;
+ RcvTCB->tcb_urgcnt += Size;
+ break;
+ }
+
+checksize:
+ // See how much we took. If we took it all, check the pending queue.
+ // At this point, we should hold the lock on the TCB.
+ if (Size == BytesTaken) {
+ // Took it all.
+ FreeRBChain(RcvBuf);
+ RcvBuf = RcvTCB->tcb_urgpending;
+ Size = RcvTCB->tcb_urgcnt;
+ } else {
+ // We didn't manage to take it all. Free what we did take,
+ // and then merge with the pending queue.
+ RcvBuf = FreePartialRB(RcvBuf, BytesTaken);
+ Size = Size - BytesTaken + RcvTCB->tcb_urgcnt;
+ if (RcvTCB->tcb_urgpending != NULL) {
+
+ // Find the end of the current RcvBuf chain, so we can
+ // merge.
+
+ LastBuf = FindLastBuffer(RcvBuf);
+ LastBuf->ipr_next = RcvTCB->tcb_urgpending;
+ }
+ }
+
+ RcvTCB->tcb_urgpending = NULL;
+ RcvTCB->tcb_urgcnt = 0;
+
+ } while (RcvBuf != NULL);
+
+ CheckRBList(RcvTCB->tcb_urgpending, RcvTCB->tcb_urgcnt);
+
+ RcvTCB->tcb_flags &= ~IN_DELIV_URG;
+ if (--(RcvTCB->tcb_slowcount) == 0) {
+ RcvTCB->tcb_fastchk &= ~TCP_FLAG_SLOW;
+ CheckTCBRcv(RcvTCB);
+ }
+
+}
+
+//* PushData - Push all data back to the client.
+//
+// Called when we've received a FIN and need to push data to the client.
+//
+// Input: PushTCB - TCB to be pushed.
+//
+// Returns: Nothing.
+//
+void
+PushData(TCB *PushTCB)
+{
+ TCPRcvReq *RcvReq;
+
+ CTEStructAssert(PushTCB, tcb);
+
+ RcvReq = PushTCB->tcb_rcvhead;
+ while (RcvReq != NULL) {
+ CTEStructAssert(RcvReq, trr);
+ RcvReq->trr_flags |= TRR_PUSHED;
+ RcvReq = RcvReq->trr_next;
+ }
+
+ RcvReq = PushTCB->tcb_exprcv;
+ while (RcvReq != NULL) {
+ CTEStructAssert(RcvReq, trr);
+ RcvReq->trr_flags |= TRR_PUSHED;
+ RcvReq = RcvReq->trr_next;
+ }
+
+ if (PushTCB->tcb_rcvhead != NULL || PushTCB->tcb_exprcv != NULL)
+ DelayAction(PushTCB, NEED_RCV_CMPLT);
+
+}
+
+
+
+//* SplitRcvBuf - Split an IPRcvBuf into three pieces.
+//
+// This function takes an input IPRcvBuf and splits it into three pieces.
+// The first piece is the input buffer, which we just skip over. The second
+// and third pieces are actually copied, even if we already own them, so
+// that the may go to different places.
+//
+// Input: RcvBuf - RcvBuf chain to be split.
+// Size - Total size in bytes of rcvbuf chain.
+// Offset - Offset to skip over.
+// SecondSize - Size in bytes of second piece.
+// SecondBuf - Where to return second buffer pointer.
+// ThirdBuf - Where to return third buffer pointer.
+//
+// Returns: Nothing. *SecondBuf and *ThirdBuf are set to NULL if we can't
+// get memory for them.
+//
+void
+SplitRcvBuf(IPRcvBuf *RcvBuf, uint Size, uint Offset, uint SecondSize,
+ IPRcvBuf **SecondBuf, IPRcvBuf **ThirdBuf)
+{
+ IPRcvBuf *TempBuf;
+ uint ThirdSize;
+
+ CTEAssert(Offset < Size);
+ CTEAssert(((Offset + SecondSize) < Size) || (((Offset + SecondSize) == Size)
+ && ThirdBuf == NULL));
+
+ CTEAssert(RcvBuf != NULL);
+
+ // RcvBuf points at the buffer to copy from, and Offset is the offset into
+ // this buffer to copy from.
+ if (SecondBuf != NULL) {
+ // We need to allocate memory for a second buffer.
+ TempBuf = CTEAllocMem(sizeof(IPRcvBuf) + SecondSize);
+ if (TempBuf != NULL) {
+ TempBuf->ipr_size = SecondSize;
+ TempBuf->ipr_owner = IPR_OWNER_TCP;
+ TempBuf->ipr_buffer = (uchar *)(TempBuf + 1);
+ TempBuf->ipr_next = NULL;
+ CopyRcvToBuffer(TempBuf->ipr_buffer, RcvBuf, SecondSize, Offset);
+ *SecondBuf = TempBuf;
+ } else {
+ *SecondBuf = NULL;
+ if (ThirdBuf != NULL)
+ *ThirdBuf = NULL;
+ return;
+ }
+ }
+
+ if (ThirdBuf != NULL) {
+ // We need to allocate memory for a third buffer.
+ ThirdSize = Size - (Offset + SecondSize);
+ TempBuf = CTEAllocMem(sizeof(IPRcvBuf) + ThirdSize);
+
+ if (TempBuf != NULL) {
+ TempBuf->ipr_size = ThirdSize;
+ TempBuf->ipr_owner = IPR_OWNER_TCP;
+ TempBuf->ipr_buffer = (uchar *)(TempBuf + 1);
+ TempBuf->ipr_next = NULL;
+ CopyRcvToBuffer(TempBuf->ipr_buffer, RcvBuf, ThirdSize,
+ Offset + SecondSize);
+ *ThirdBuf = TempBuf;
+ } else
+ *ThirdBuf = NULL;
+ }
+
+
+}
+
+//* HandleUrgent - Handle urgent data.
+//
+// Called when an incoming segment has urgent data in it. We make sure there
+// really is urgent data in the segment, and if there is we try to dispose
+// of it either by putting it into a posted buffer or calling an exp. rcv.
+// indication handler.
+//
+// This routine is called at DPC level, and with the TCP locked.
+//
+// Urgent data handling is a little complicated. Each TCB has the starting
+// and ending sequence numbers of the 'current' (last received) bit of urgent
+// data. It is possible that the start of the current urgent data might be
+// greater than tcb_rcvnext, if urgent data came in, we handled it, and then
+// couldn't take the preceding normal data. The urgent valid flag is cleared
+// when the next byte of data the user would read (rcvnext - pendingcnt) is
+// greater than the end of urgent data - we do this so that we can correctly
+// support SIOCATMARK. We always seperate urgent data out of the data stream.
+// If the urgent valid field is set when we get into this routing we have
+// to play a couple of games. If the incoming segment starts in front of the
+// current urgent data, we truncate it before the urgent data, and put any
+// data after the urgent data on the reassemble queue. These gyrations are
+// done to avoid delivering the same urgent data twice. If the urgent valid
+// field in the TCB is set and the segment starts after the current urgent
+// data the new urgent information will replace the current urgent information.
+//
+// Input: RcvTCB - TCB to recv the data on.
+// RcvInfo - RcvInfo structure for the incoming segment.
+// RcvBuf - Pointer to IPRcvBuf train containing the
+// incoming segment.
+// Size - Pointer to size in bytes of data in the segment.
+//
+// Returns: Nothing.
+//
+void
+HandleUrgent(TCB *RcvTCB, TCPRcvInfo *RcvInfo, IPRcvBuf *RcvBuf, uint *Size)
+{
+ uint BytesInFront, BytesInBack; // Bytes in front of and in
+ // back of the urgent data.
+ uint UrgSize; // Size in bytes of urgent data.
+ SeqNum UrgStart, UrgEnd;
+ IPRcvBuf *EndBuf, *UrgBuf;
+ TCPRcvInfo NewRcvInfo;
+ CTELockHandle TCBHandle;
+
+ CTEStructAssert(RcvTCB, tcb);
+ CTEAssert(RcvTCB->tcb_refcnt != 0);
+ CTEAssert(RcvInfo->tri_flags & TCP_FLAG_URG);
+ CTEAssert(SEQ_EQ(RcvInfo->tri_seq, RcvTCB->tcb_rcvnext));
+
+ // First, validate the urgent pointer.
+ if (RcvTCB->tcb_flags & BSD_URGENT) {
+ // We're using BSD style urgent data. We assume that the urgent
+ // data is one byte long, and that the urgent pointer points one
+ // after the urgent data instead of at the last byte of urgent data.
+ // See if the urgent data is in this segment.
+
+ if (RcvInfo->tri_urgent == 0 || RcvInfo->tri_urgent > *Size) {
+ // Not in this segment. Clear the urgent flag and return.
+ RcvInfo->tri_flags &= ~TCP_FLAG_URG;
+ return;
+ }
+
+ UrgSize = 1;
+ BytesInFront = RcvInfo->tri_urgent - 1;
+
+ } else {
+
+ // This is not BSD style urgent. We assume that the urgent data
+ // starts at the front of the segment and the last byte is pointed
+ // to by the urgent data pointer.
+
+ BytesInFront = 0;
+ UrgSize = MIN(RcvInfo->tri_urgent + 1, *Size);
+
+ }
+
+ BytesInBack = *Size - BytesInFront - UrgSize;
+
+ // UrgStart and UrgEnd are the first and last sequence numbers of the
+ // urgent data in this segment.
+
+ UrgStart = RcvInfo->tri_seq + BytesInFront;
+ UrgEnd = UrgStart + UrgSize - 1;
+
+ if (!(RcvTCB->tcb_flags & URG_INLINE)) {
+
+ EndBuf = NULL;
+
+ // Now see if this overlaps with any urgent data we've already seen.
+ if (RcvTCB->tcb_flags & URG_VALID) {
+ // We have some urgent data still around. See if we've advanced
+ // rcvnext beyond the urgent data. If we have, this is new urgent
+ // data, and we can go ahead and process it (although anyone doing
+ // an SIOCATMARK socket command might get confused). If we haven't
+ // consumed the data in front of the existing urgent data yet, we'll
+ // truncate this seg. to that amount and push the rest onto the
+ // reassembly queue. Note that rcvnext should never fall between
+ // tcb_urgstart and tcb_urgend.
+
+ CTEAssert(SEQ_LT(RcvTCB->tcb_rcvnext, RcvTCB->tcb_urgstart) ||
+ SEQ_GT(RcvTCB->tcb_rcvnext, RcvTCB->tcb_urgend));
+
+ if (SEQ_LT(RcvTCB->tcb_rcvnext, RcvTCB->tcb_urgstart)) {
+
+ // There appears to be some overlap in the data stream. Split
+ // the buffer up into pieces that come before the current urgent
+ // data and after the current urgent data, putting the latter
+ // on the reassembly queue.
+
+ UrgSize = RcvTCB->tcb_urgend - RcvTCB->tcb_urgstart + 1;
+
+ BytesInFront = MIN(RcvTCB->tcb_urgstart - RcvTCB->tcb_rcvnext,
+ (int) *Size);
+
+ if (SEQ_GT(RcvTCB->tcb_rcvnext + *Size, RcvTCB->tcb_urgend)) {
+ // We have data after this piece of urgent data.
+ BytesInBack = RcvTCB->tcb_rcvnext + *Size -
+ RcvTCB->tcb_urgend;
+ } else
+ BytesInBack = 0;
+
+ SplitRcvBuf(RcvBuf, *Size, BytesInFront, UrgSize, NULL,
+ (BytesInBack ? &EndBuf : NULL));
+
+ if (EndBuf != NULL) {
+ NewRcvInfo.tri_seq = RcvTCB->tcb_urgend + 1;
+ NewRcvInfo.tri_flags = RcvInfo->tri_flags;
+ NewRcvInfo.tri_urgent = UrgEnd - NewRcvInfo.tri_seq;
+ if (RcvTCB->tcb_flags & BSD_URGENT)
+ NewRcvInfo.tri_urgent++;
+ NewRcvInfo.tri_ack = RcvInfo->tri_ack;
+ NewRcvInfo.tri_window = RcvInfo->tri_window;
+ PutOnRAQ(RcvTCB, &NewRcvInfo, EndBuf, BytesInBack);
+ }
+
+ *Size = BytesInFront;
+ RcvInfo->tri_flags &= ~TCP_FLAG_URG;
+ return;
+ }
+ }
+
+ // We have urgent data we can process now. Split it into its component
+ // parts, the first part, the urgent data, and the stuff after the
+ // urgent data.
+ SplitRcvBuf(RcvBuf, *Size, BytesInFront, UrgSize, &UrgBuf,
+ (BytesInBack ? &EndBuf : NULL));
+
+ // If we managed to split out the end stuff, put it on the queue now.
+ if (EndBuf != NULL) {
+ NewRcvInfo.tri_seq = RcvInfo->tri_seq + BytesInFront + UrgSize;
+ NewRcvInfo.tri_flags = RcvInfo->tri_flags & ~TCP_FLAG_URG;
+ NewRcvInfo.tri_ack = RcvInfo->tri_ack;
+ NewRcvInfo.tri_window = RcvInfo->tri_window;
+ PutOnRAQ(RcvTCB, &NewRcvInfo, EndBuf, BytesInBack);
+ }
+
+
+ if (UrgBuf != NULL) {
+ // We succesfully split the urgent data out.
+ if (!(RcvTCB->tcb_flags & URG_VALID)) {
+ RcvTCB->tcb_flags |= URG_VALID;
+ RcvTCB->tcb_slowcount++;
+ RcvTCB->tcb_fastchk |= TCP_FLAG_SLOW;
+ CheckTCBRcv(RcvTCB);
+ }
+ RcvTCB->tcb_urgstart = UrgStart;
+ RcvTCB->tcb_urgend = UrgEnd;
+#ifdef VXD
+#ifdef DEBUG
+ TCBHandle = DEFAULT_SIMIRQL;
+#endif
+#else
+ TCBHandle = DISPATCH_LEVEL;
+#endif
+ DeliverUrgent(RcvTCB, UrgBuf, UrgSize, &TCBHandle);
+ }
+
+ *Size = BytesInFront;
+
+ } else {
+ // Urgent data is to be processed inline. We just need to remember
+ // where it is and treat it as normal data. If there's already urgent
+ // data, we remember the latest urgent data.
+
+ RcvInfo->tri_flags &= ~TCP_FLAG_URG;
+
+ if (RcvTCB->tcb_flags & URG_VALID) {
+ // There is urgent data. See if this stuff comes after the existing
+ // urgent data.
+
+ if (SEQ_LTE(UrgEnd, RcvTCB->tcb_urgend)) {
+ // The existing urgent data completely overlaps this stuff,
+ // so ignore this.
+ return;
+ }
+ } else {
+ RcvTCB->tcb_flags |= URG_VALID;
+ RcvTCB->tcb_slowcount++;
+ RcvTCB->tcb_fastchk |= TCP_FLAG_SLOW;
+ CheckTCBRcv(RcvTCB);
+ }
+
+ RcvTCB->tcb_urgstart = UrgStart;
+ RcvTCB->tcb_urgend = UrgEnd;
+ }
+
+ return;
+}
+
+//* TdiReceive - Process a receive request.
+//
+// This is the main TDI receive request handler. We validate the connection
+// and make sure that we have a TCB in the proper state, then we try to
+// allocate a receive request structure. If that succeeds, we'll look and
+// see what's happening on the TCB - if there's pending data, we'll put it
+// in the buffer. Otherwise we'll just queue the receive for later.
+//
+// Input: Request - TDI_REQUEST structure for this request.
+// Flags - Pointer to flags word.
+// RcvLength - Pointer to length in bytes of receive buffer.
+// Buffer - Pointer to buffer to take data.
+//
+// Returns: TDI_STATUS of request.
+//
+TDI_STATUS
+TdiReceive(PTDI_REQUEST Request, ushort *Flags, uint *RcvLength,
+ PNDIS_BUFFER Buffer)
+{
+ TCPConn *Conn;
+ TCB *RcvTCB;
+ TCPRcvReq *RcvReq;
+ CTELockHandle ConnTableHandle, TCBHandle;
+ TDI_STATUS Error;
+ ushort UFlags;
+
+ CTEGetLock(&ConnTableLock, &ConnTableHandle);
+
+ Conn = GetConnFromConnID((uint)Request->Handle.ConnectionContext);
+
+ if (Conn != NULL) {
+ CTEStructAssert(Conn, tc);
+
+ RcvTCB = Conn->tc_tcb;
+ if (RcvTCB != NULL) {
+ CTEStructAssert(RcvTCB, tcb);
+ CTEGetLock(&RcvTCB->tcb_lock, &TCBHandle);
+ CTEFreeLock(&ConnTableLock, TCBHandle);
+ UFlags = *Flags;
+
+ if ((DATA_RCV_STATE(RcvTCB->tcb_state) ||
+ (RcvTCB->tcb_pendingcnt != 0 && (UFlags & TDI_RECEIVE_NORMAL)) ||
+ (RcvTCB->tcb_urgcnt != 0 && (UFlags & TDI_RECEIVE_EXPEDITED)))
+ && !CLOSING(RcvTCB)) {
+ // We have a TCB, and it's valid. Get a receive request now.
+
+ CheckRBList(RcvTCB->tcb_pendhead, RcvTCB->tcb_pendingcnt);
+
+ RcvReq = GetRcvReq();
+ if (RcvReq != NULL) {
+
+ RcvReq->trr_rtn = Request->RequestNotifyObject;
+ RcvReq->trr_context = Request->RequestContext;
+ RcvReq->trr_buffer = Buffer;
+ RcvReq->trr_size = *RcvLength;
+ RcvReq->trr_uflags = Flags;
+ RcvReq->trr_offset = 0;
+ RcvReq->trr_amt = 0;
+ RcvReq->trr_flags = (uint)UFlags;
+ if ((UFlags & (TDI_RECEIVE_NORMAL | TDI_RECEIVE_EXPEDITED))
+ != TDI_RECEIVE_EXPEDITED) {
+ // This is not an expedited only receive. Put him
+ // on the normal receive queue.
+ RcvReq->trr_next = NULL;
+ if (RcvTCB->tcb_rcvhead == NULL) {
+ // The receive queue is empty. Put him on the front.
+ RcvTCB->tcb_rcvhead = RcvReq;
+ RcvTCB->tcb_rcvtail = RcvReq;
+ } else {
+ RcvTCB->tcb_rcvtail->trr_next = RcvReq;
+ RcvTCB->tcb_rcvtail = RcvReq;
+ }
+
+ // If this recv. can't hold urgent data or there isn't
+ // any pending urgent data continue processing.
+ if (!(UFlags & TDI_RECEIVE_EXPEDITED) ||
+ RcvTCB->tcb_urgcnt == 0) {
+ // If tcb_currcv is NULL, there is no currently
+ // active receive. In this case, check to see if
+ // there is pending data and that we are not
+ // currently in a receive indication handler. If
+ // both of these are true then deal with the
+ // pending data.
+ if (RcvTCB->tcb_currcv == NULL) {
+ RcvTCB->tcb_currcv = RcvReq;
+ // No currently active receive.
+ if (!(RcvTCB->tcb_flags & IN_RCV_IND)) {
+ // Not in a rcv. indication.
+ RcvTCB->tcb_rcvhndlr = BufferData;
+ if (RcvTCB->tcb_pendhead == NULL) {
+ CTEFreeLock(&RcvTCB->tcb_lock,
+ ConnTableHandle);
+ return TDI_PENDING;
+ } else {
+ IPRcvBuf *PendBuffer;
+ uint PendSize;
+ uint OldRcvWin;
+
+ // We have pending data to deal with.
+ PendBuffer = RcvTCB->tcb_pendhead;
+ PendSize = RcvTCB->tcb_pendingcnt;
+ RcvTCB->tcb_pendhead = NULL;
+ RcvTCB->tcb_pendingcnt = 0;
+ RcvTCB->tcb_refcnt++;
+
+ // We assume that BufferData holds
+ // the lock (does not yield) during
+ // this call. If this changes for some
+ // reason, we'll have to fix the code
+ // below that does the window update
+ // check. See the comments in the
+ // BufferData() routine for more info.
+#ifdef VXD
+ CTEFreeLock(&RcvTCB->tcb_lock,
+ ConnTableHandle);
+ (void)BufferData(RcvTCB, TCP_FLAG_PUSH,
+ PendBuffer, PendSize);
+ CTEGetLock(&RcvTCB->tcb_lock,
+ &ConnTableHandle);
+#else
+ (void)BufferData(RcvTCB, TCP_FLAG_PUSH,
+ PendBuffer, PendSize);
+#endif
+ CheckTCBRcv(RcvTCB);
+ // Now we need to see if the window
+ // has changed. If it has, send an
+ // ACK.
+ OldRcvWin = RcvTCB->tcb_rcvwin;
+ if (OldRcvWin != RcvWin(RcvTCB)) {
+ // The window has changed, so send
+ // an ACK.
+
+ DelayAction(RcvTCB, NEED_ACK);
+ }
+
+ DerefTCB(RcvTCB, ConnTableHandle);
+ ProcessTCBDelayQ();
+ return TDI_PENDING;
+ }
+ }
+ // In a receive indication. The recv. request
+ // is now on the queue, so just fall through
+ // to the return.
+
+ }
+ // A rcv. is currently active. No need to do
+ // anything else.
+ CTEFreeLock(&RcvTCB->tcb_lock, ConnTableHandle);
+ return TDI_PENDING;
+ } else {
+ // This buffer can hold urgent data and we have
+ // some pending. Deliver it now.
+ RcvTCB->tcb_refcnt++;
+ DeliverUrgent(RcvTCB, NULL, 0, &ConnTableHandle);
+ DerefTCB(RcvTCB, ConnTableHandle);
+ return TDI_PENDING;
+ }
+ } else {
+ TCPRcvReq *Temp;
+
+ // This is an expedited only receive. Just put him
+ // on the end of the expedited receive queue.
+ Temp = STRUCT_OF(TCPRcvReq, &RcvTCB->tcb_exprcv,
+ trr_next);
+ while (Temp->trr_next != NULL)
+ Temp = Temp->trr_next;
+
+ RcvReq->trr_next = NULL;
+ Temp->trr_next = RcvReq;
+ if (RcvTCB->tcb_urgpending != NULL) {
+ RcvTCB->tcb_refcnt++;
+ DeliverUrgent(RcvTCB, NULL, 0, &ConnTableHandle);
+ DerefTCB(RcvTCB, ConnTableHandle);
+ return TDI_PENDING;
+ } else
+ Error = TDI_PENDING;
+ }
+ } else {
+ // Couldn't get a rcv. req.
+ Error = TDI_NO_RESOURCES;
+ }
+ } else {
+ // The TCB is in an invalid state.
+ Error = TDI_INVALID_STATE;
+ }
+ CTEFreeLock(&RcvTCB->tcb_lock, ConnTableHandle);
+ return Error;
+ } else // No TCB for connection.
+ Error = TDI_INVALID_STATE;
+ } else // No connection.
+ Error = TDI_INVALID_CONNECTION;
+
+ CTEFreeLock(&ConnTableLock, ConnTableHandle);
+ return Error;
+
+}
diff --git a/private/ntos/tdi/tcpip/tcp/tcpdeliv.h b/private/ntos/tdi/tcpip/tcp/tcpdeliv.h
new file mode 100644
index 000000000..94fe73a7d
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/tcpdeliv.h
@@ -0,0 +1,44 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** TCPDELIV.H - TCP data delivery definitions.
+//
+// This file contains the definitions for structures used by the data
+// delivery code.
+//
+
+extern void FreeRcvReq(struct TCPRcvReq *FreedReq);
+
+extern uint IndicateData(struct TCB *RcvTCB, uint RcvFlags, IPRcvBuf *InBuffer,
+ uint Size);
+extern uint BufferData(struct TCB *RcvTCB, uint RcvFlags, IPRcvBuf *InBuffer,
+ uint Size);
+extern uint PendData(struct TCB *RcvTCB, uint RcvFlags, IPRcvBuf *InBuffer,
+ uint Size);
+
+#ifdef VXD
+extern void IndicatePendingData(struct TCB *RcvTCB, struct TCPRcvReq *RcvReq);
+#else
+extern void IndicatePendingData(struct TCB *RcvTCB, struct TCPRcvReq *RcvReq,
+ CTELockHandle TCBHandle);
+#endif
+
+extern void HandleUrgent(struct TCB *RcvTCB, struct TCPRcvInfo *RcvInfo,
+ IPRcvBuf *RcvBuf, uint *Size);
+
+extern TDI_STATUS TdiReceive(PTDI_REQUEST Request, ushort *Flags,
+ uint *RcvLength, PNDIS_BUFFER Buffer);
+extern IPRcvBuf *FreePartialRB(IPRcvBuf *RB, uint Size);
+extern void PushData(struct TCB *PushTCB);
+
+EXTERNAL_LOCK(TCPRcvReqFreeLock) // Protects rcv req free list.
+
+#ifdef NT
+extern SLIST_HEADER TCPRcvReqFree;
+#endif
+
+
+
diff --git a/private/ntos/tdi/tcpip/tcp/tcpip.def b/private/ntos/tdi/tcpip/tcp/tcpip.def
new file mode 100644
index 000000000..c02c158c1
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/tcpip.def
@@ -0,0 +1,8 @@
+
+NAME TCPIP.SYS
+
+DESCRIPTION 'TCPIP.SYS'
+
+EXPORTS
+ IPAddInterface
+ IPDelInterface
diff --git a/private/ntos/tdi/tcpip/tcp/tcpip.rc b/private/ntos/tdi/tcpip/tcp/tcpip.rc
new file mode 100644
index 000000000..bd0b7a4ad
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/tcpip.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "TCP/IP driver"
+
+#define VER_INTERNALNAME_STR "tcpip.sys"
+#define VER_ORIGINALFILENAME_STR "tcpip.sys"
+
+#include <common.ver>
diff --git a/private/ntos/tdi/tcpip/tcp/tcprcv.c b/private/ntos/tdi/tcpip/tcp/tcprcv.c
new file mode 100644
index 000000000..46698a2b0
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/tcprcv.c
@@ -0,0 +1,3397 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** TCPRCV.C - TCP receive protocol code.
+//
+// This file contains the code for handling incoming TCP packets.
+//
+
+#include "oscfg.h"
+#include "ndis.h"
+#include "cxport.h"
+#include "ip.h"
+#include "tdi.h"
+#ifdef VXD
+#include "tdivxd.h"
+#include "tdistat.h"
+#endif
+#ifdef NT
+#include "tdint.h"
+#include "tdistat.h"
+#endif
+#include "queue.h"
+#include "addr.h"
+#include "tcp.h"
+#include "tcb.h"
+#include "tcpconn.h"
+#include "tcpsend.h"
+#include "tcprcv.h"
+#include "tcpdeliv.h"
+#include "tlcommon.h"
+#include "info.h"
+#include "tcpcfg.h"
+#include "secfltr.h"
+
+uint RequestCompleteFlags;
+
+Queue ConnRequestCompleteQ;
+Queue SendCompleteQ;
+
+Queue TCBDelayQ;
+
+#ifdef SYN_ATTACK
+DEFINE_LOCK_STRUCTURE(SynAttLock)
+#endif
+DEFINE_LOCK_STRUCTURE(RequestCompleteLock)
+DEFINE_LOCK_STRUCTURE(TCBDelayLock)
+
+ulong TCBDelayRtnCount;
+ulong TCBDelayRtnLimit;
+#define TCB_DELAY_RTN_LIMIT 4
+
+EXTERNAL_LOCK(TCBTableLock)
+EXTERNAL_LOCK(AddrObjTableLock)
+EXTERNAL_LOCK(ConnTableLock)
+
+extern IPInfo LocalNetInfo;
+
+#define PERSIST_TIMEOUT MS_TO_TICKS(500)
+
+
+void ResetSendNext(TCB *SeqTCB, SeqNum NewSeq);
+
+#if FAST_RETRANSMIT
+extern uint MaxDupAcks;
+void ResetAndFastSend(TCB *SeqTCB, SeqNum NewSeq);
+#endif
+
+
+#ifdef NT
+
+NTSTATUS
+TCPPrepareIrpForCancel(
+ PTCP_CONTEXT TcpContext,
+ PIRP Irp,
+ PDRIVER_CANCEL CancelRoutine
+ );
+
+extern void
+TCPRequestComplete(
+ void *Context,
+ unsigned int Status,
+ unsigned int UnUsed
+ );
+
+VOID
+TCPCancelRequest(
+ PDEVICE_OBJECT Device,
+ PIRP Irp
+ );
+
+//
+// All of the init code can be discarded.
+//
+#ifdef ALLOC_PRAGMA
+
+int InitTCPRcv(void);
+void UnInitTCPRcv(void);
+
+#pragma alloc_text(INIT, InitTCPRcv)
+#pragma alloc_text(INIT, UnInitTCPRcv)
+
+#endif // ALLOC_PRAGMA
+
+#ifdef RASAUTODIAL
+extern BOOLEAN fAcdLoadedG;
+#endif
+
+#endif // NT
+
+//* AdjustRcvWin - Adjust the receive window on a TCB.
+//
+// A utility routine that adjusts the receive window to an even multiple of
+// the local segment size. We round it up to the next closest multiple, or
+// leave it alone if it's already an event multiple. We assume we have
+// exclusive access to the input TCB.
+//
+// Input: WinTCB - TCB to be adjusted.
+//
+// Returns: Nothing.
+//
+void
+AdjustRcvWin(TCB *WinTCB)
+{
+ ushort LocalMSS;
+ uchar FoundMSS;
+ ulong SegmentsInWindow;
+
+ CTEAssert(WinTCB->tcb_defaultwin != 0);
+ CTEAssert(WinTCB->tcb_rcvwin != 0);
+ CTEAssert(WinTCB->tcb_remmss != 0);
+
+ if (WinTCB->tcb_flags & WINDOW_SET)
+ return;
+
+ // First, get the local MSS by calling IP.
+
+ FoundMSS = (*LocalNetInfo.ipi_getlocalmtu)(WinTCB->tcb_saddr, &LocalMSS);
+
+ // If we didn't find it, error out.
+ if (!FoundMSS) {
+ CTEAssert(FALSE);
+ return;
+ }
+
+ LocalMSS -= sizeof(TCPHeader);
+ LocalMSS = MIN(LocalMSS, WinTCB->tcb_remmss);
+
+ SegmentsInWindow = WinTCB->tcb_defaultwin / (ulong)LocalMSS;
+
+ // Make sure we have at least 4 segments in window, if that wouldn't make
+ // the window too big.
+ if (SegmentsInWindow < 4) {
+
+ // We have fewer than four segments in the window. Round up to 4
+ // if we can do so without exceeding the maximum window size; otherwise
+ // use the maximum multiple that we can fit in 64K. The exception is if
+ // we can only fit one integral multiple in the window - in that case
+ // we'll use a window of 0xffff.
+ if (LocalMSS <= (0xffff/4)) {
+ WinTCB->tcb_defaultwin = (uint)(4 * LocalMSS);
+ } else {
+ ulong SegmentsInMaxWindow;
+
+ // Figure out the maximum number of segments we could possibly
+ // fit in a window. If this is > 1, use that as the basis for
+ // our window size. Otherwise use a maximum size window.
+
+ SegmentsInMaxWindow = 0xffff/(ulong)LocalMSS;
+ if (SegmentsInMaxWindow != 1)
+ WinTCB->tcb_defaultwin = SegmentsInMaxWindow * (ulong)LocalMSS;
+ else
+ WinTCB->tcb_defaultwin = 0xffff;
+ }
+
+ WinTCB->tcb_rcvwin = WinTCB->tcb_defaultwin;
+
+ } else
+ // If it's not already an even multiple, bump the default and current
+ // windows to the nearest multiple.
+ if ((SegmentsInWindow * (ulong)LocalMSS) != WinTCB->tcb_defaultwin) {
+ ulong NewWindow;
+
+ NewWindow = (SegmentsInWindow + 1) * (ulong)LocalMSS;
+
+ // Don't let the new window be > 64K.
+ if (NewWindow <= 0xffff) {
+ WinTCB->tcb_defaultwin = (uint)NewWindow;
+ WinTCB->tcb_rcvwin = (uint)NewWindow;
+ }
+ }
+
+}
+
+//* CompleteRcvs - Complete rcvs on a TCB.
+//
+// Called when we need to complete rcvs on a TCB. We'll pull things from
+// the TCB's rcv queue, as long as there are rcvs that have the PUSH bit
+// set.
+//
+// Input: CmpltTCB - TCB to complete on.
+//
+// Returns: Nothing.
+//
+void
+CompleteRcvs(TCB *CmpltTCB)
+{
+ CTELockHandle TCBHandle;
+ TCPRcvReq *CurrReq, *NextReq, *IndReq;
+
+ CTEStructAssert(CmpltTCB, tcb);
+ CTEAssert(CmpltTCB->tcb_refcnt != 0);
+
+ CTEGetLock(&CmpltTCB->tcb_lock, &TCBHandle);
+
+ if (!CLOSING(CmpltTCB) && !(CmpltTCB->tcb_flags & RCV_CMPLTING)
+ && (CmpltTCB->tcb_rcvhead != NULL)) {
+
+ CmpltTCB->tcb_flags |= RCV_CMPLTING;
+
+ for (;;) {
+
+ CurrReq = CmpltTCB->tcb_rcvhead;
+ IndReq = NULL;
+ do {
+ CTEStructAssert(CurrReq, trr);
+
+ if (CurrReq->trr_flags & TRR_PUSHED) {
+ // Need to complete this one. If this is the current rcv
+ // advance the current rcv to the next one in the list.
+ // Then set the list head to the next one in the list.
+
+ CTEAssert(CurrReq->trr_amt != 0 ||
+ !DATA_RCV_STATE(CmpltTCB->tcb_state));
+
+ NextReq = CurrReq->trr_next;
+ if (CmpltTCB->tcb_currcv == CurrReq)
+ CmpltTCB->tcb_currcv = NextReq;
+
+ CmpltTCB->tcb_rcvhead = NextReq;
+
+ if (NextReq == NULL) {
+ // We've just removed the last buffer. Set the
+ // rcvhandler to PendData, in case something
+ // comes in during the callback.
+ CTEAssert(CmpltTCB->tcb_rcvhndlr != IndicateData);
+ CmpltTCB->tcb_rcvhndlr = PendData;
+ }
+
+ CTEFreeLock(&CmpltTCB->tcb_lock, TCBHandle);
+ if (CurrReq->trr_uflags != NULL)
+ *(CurrReq->trr_uflags) =
+ TDI_RECEIVE_NORMAL | TDI_RECEIVE_ENTIRE_MESSAGE;
+
+ (*CurrReq->trr_rtn)(CurrReq->trr_context, TDI_SUCCESS,
+ CurrReq->trr_amt);
+ if (IndReq != NULL)
+ FreeRcvReq(CurrReq);
+ else
+ IndReq = CurrReq;
+ CTEGetLock(&CmpltTCB->tcb_lock, &TCBHandle);
+ CurrReq = CmpltTCB->tcb_rcvhead;
+
+ } else
+ // This one isn't to be completed, so bail out.
+ break;
+ } while (CurrReq != NULL);
+
+ // Now see if we've completed all of the requests. If we have, we
+ // may need to deal with pending data and/or reset the rcv. handler.
+ if (CurrReq == NULL) {
+ // We've completed everything that can be, so stop the push
+ // timer. We don't stop it if CurrReq isn't NULL because we
+ // want to make sure later data is eventually pushed.
+ STOP_TCB_TIMER(CmpltTCB->tcb_pushtimer);
+
+ CTEAssert(IndReq != NULL);
+ // No more recv. requests.
+ if (CmpltTCB->tcb_pendhead == NULL) {
+ FreeRcvReq(IndReq);
+ // No pending data. Set the rcv. handler to either PendData
+ // or IndicateData.
+ if (!(CmpltTCB->tcb_flags & (DISC_PENDING | GC_PENDING))) {
+ if (CmpltTCB->tcb_rcvind != NULL &&
+ CmpltTCB->tcb_indicated == 0)
+ CmpltTCB->tcb_rcvhndlr = IndicateData;
+ else
+ CmpltTCB->tcb_rcvhndlr = PendData;
+ } else {
+ goto Complete_Notify;
+ }
+
+ } else {
+ // We have pending data to deal with.
+ if (CmpltTCB->tcb_rcvind != NULL &&
+ CmpltTCB->tcb_indicated == 0) {
+ // There's a rcv. indicate handler on this TCB. Call
+ // the indicate handler with the pending data.
+#ifdef VXD
+ CTEFreeLock(&CmpltTCB->tcb_lock, TCBHandle);
+ IndicatePendingData(CmpltTCB, IndReq);
+ SendACK(CmpltTCB);
+ CTEGetLock(&CmpltTCB->tcb_lock, &TCBHandle);
+#else
+ IndicatePendingData(CmpltTCB, IndReq, TCBHandle);
+ SendACK(CmpltTCB);
+ CTEGetLock(&CmpltTCB->tcb_lock, &TCBHandle);
+#endif
+ // See if a buffer has been posted. If so, we'll need
+ // to check and see if it needs to be completed.
+ if (CmpltTCB->tcb_rcvhead != NULL)
+ continue;
+ else {
+ // If the pending head is now NULL, we've used up
+ // all the data.
+ if (CmpltTCB->tcb_pendhead == NULL &&
+ (CmpltTCB->tcb_flags &
+ (DISC_PENDING | GC_PENDING)))
+ goto Complete_Notify;
+ }
+
+ } else {
+ // No indicate handler, so nothing to do. The rcv.
+ // handler should already be set to PendData.
+ FreeRcvReq(IndReq);
+ CTEAssert(CmpltTCB->tcb_rcvhndlr == PendData);
+ }
+ }
+ } else {
+ if (IndReq != NULL)
+ FreeRcvReq(IndReq);
+ CTEAssert(CmpltTCB->tcb_rcvhndlr == BufferData);
+ }
+
+ break;
+ }
+ CmpltTCB->tcb_flags &= ~RCV_CMPLTING;
+ }
+ CTEFreeLock(&CmpltTCB->tcb_lock, TCBHandle);
+ return;
+
+Complete_Notify:
+ // Something is pending. Figure out what it is, and do
+ // it.
+ if (CmpltTCB->tcb_flags & GC_PENDING) {
+ CmpltTCB->tcb_flags &= ~RCV_CMPLTING;
+ // Bump the refcnt, because GracefulClose will
+ // deref the TCB and we're not really done with
+ // it yet.
+ CmpltTCB->tcb_refcnt++;
+ GracefulClose(CmpltTCB,
+ CmpltTCB->tcb_flags & TW_PENDING, TRUE,
+ TCBHandle);
+
+ } else
+ if (CmpltTCB->tcb_flags & DISC_PENDING) {
+ CmpltTCB->tcb_flags &= ~DISC_PENDING;
+ CTEFreeLock(&CmpltTCB->tcb_lock, TCBHandle);
+ NotifyOfDisc(CmpltTCB, NULL, TDI_GRACEFUL_DISC);
+
+ CTEGetLock(&CmpltTCB->tcb_lock, &TCBHandle);
+ CmpltTCB->tcb_flags &= ~RCV_CMPLTING;
+ CTEFreeLock(&CmpltTCB->tcb_lock, TCBHandle);
+ } else {
+ CTEAssert(FALSE);
+ CTEFreeLock(&CmpltTCB->tcb_lock, TCBHandle);
+ }
+
+ return;
+
+}
+
+//* ProcessTCBDelayQ - Process TCBs on the delayed Q.
+//
+// Called at various times to process TCBs on the delayed Q.
+//
+// Entry: Nothing.
+//
+// Returns: Nothing.
+//
+void
+ProcessTCBDelayQ(void)
+{
+ CTELockHandle QHandle;
+ TCB *DelayTCB;
+ CTELockHandle TCBHandle;
+
+ CTEGetLock(&TCBDelayLock, &QHandle);
+
+ // Check for recursion. We do not stop recursion completely, only
+ // limit it. This is done to allow multiple threads to process the
+ // TCBDelayQ simultaneously.
+
+ TCBDelayRtnCount++;
+ if (TCBDelayRtnCount > TCBDelayRtnLimit) {
+ TCBDelayRtnCount--;
+ CTEFreeLock(&TCBDelayLock, QHandle);
+ return;
+ }
+
+ while (!EMPTYQ(&TCBDelayQ)) {
+
+ DEQUEUE(&TCBDelayQ, DelayTCB, TCB, tcb_delayq);
+ CTEStructAssert(DelayTCB, tcb);
+ CTEAssert(DelayTCB->tcb_refcnt != 0);
+ CTEAssert(DelayTCB->tcb_flags & IN_DELAY_Q);
+ CTEFreeLock(&TCBDelayLock, QHandle);
+
+ CTEGetLock(&DelayTCB->tcb_lock, &TCBHandle);
+
+ while (!CLOSING(DelayTCB) && (DelayTCB->tcb_flags & DELAYED_FLAGS)) {
+
+ if (DelayTCB->tcb_flags & NEED_RCV_CMPLT) {
+ DelayTCB->tcb_flags &= ~NEED_RCV_CMPLT;
+ CTEFreeLock(&DelayTCB->tcb_lock, TCBHandle);
+ CompleteRcvs(DelayTCB);
+ CTEGetLock(&DelayTCB->tcb_lock, &TCBHandle);
+ }
+
+ if (DelayTCB->tcb_flags & NEED_OUTPUT) {
+ DelayTCB->tcb_flags &= ~NEED_OUTPUT;
+ DelayTCB->tcb_refcnt++;
+#ifdef VXD
+ CTEFreeLock(&DelayTCB->tcb_lock, TCBHandle);
+ TCPSend(DelayTCB);
+#else
+ TCPSend(DelayTCB, TCBHandle);
+#endif
+ CTEGetLock(&DelayTCB->tcb_lock, &TCBHandle);
+ }
+
+ if (DelayTCB->tcb_flags & NEED_ACK) {
+ DelayTCB->tcb_flags &= ~NEED_ACK;
+ CTEFreeLock(&DelayTCB->tcb_lock, TCBHandle);
+ SendACK(DelayTCB);
+ CTEGetLock(&DelayTCB->tcb_lock, &TCBHandle);
+ }
+
+ }
+
+ DelayTCB->tcb_flags &= ~IN_DELAY_Q;
+ DerefTCB(DelayTCB, TCBHandle);
+ CTEGetLock(&TCBDelayLock, &QHandle);
+
+ }
+
+ TCBDelayRtnCount--;
+ CTEFreeLock(&TCBDelayLock, QHandle);
+
+}
+
+//* DelayAction - Put a TCB on the queue for a delayed action.
+//
+// Called when we want to put a TCB on the DelayQ for a delayed action at
+// rcv. complete or some other time. The lock on the TCB must be held when
+// this is called.
+//
+// Input: DelayTCB - TCB which we're going to sched.
+// Action - Action we're scheduling.
+//
+// Returns: Nothing.
+//
+void
+DelayAction(TCB *DelayTCB, uint Action)
+{
+ CTELockHandle DQHandle;
+
+ // Schedule the completion.
+ CTEGetLockAtDPC(&TCBDelayLock, &DQHandle);
+ DelayTCB->tcb_flags |= Action;
+ if (!(DelayTCB->tcb_flags & IN_DELAY_Q)) {
+ DelayTCB->tcb_flags |= IN_DELAY_Q;
+ DelayTCB->tcb_refcnt++; // Reference this for later.
+ ENQUEUE(&TCBDelayQ, &DelayTCB->tcb_delayq);
+ }
+ CTEFreeLockFromDPC(&TCBDelayLock, DQHandle);
+
+}
+
+//* TCPRcvComplete - Handle a receive complete.
+//
+// Called by the lower layers when we're done receiving. We look to see if
+// we have and pending requests to complete. If we do, we complete them. Then
+// we look to see if we have any TCBs pending for output. If we do, we
+// get them going.
+//
+// Input: Nothing.
+//
+// Returns: Nothing.
+//
+void
+TCPRcvComplete(void)
+{
+ CTELockHandle CompleteHandle;
+ TCPReq *Req;
+
+ if (RequestCompleteFlags & ANY_REQUEST_COMPLETE) {
+ CTEGetLock(&RequestCompleteLock, &CompleteHandle);
+ if (!(RequestCompleteFlags & IN_RCV_COMPLETE)) {
+ RequestCompleteFlags |= IN_RCV_COMPLETE;
+ do {
+ if (RequestCompleteFlags & CONN_REQUEST_COMPLETE) {
+ if (!EMPTYQ(&ConnRequestCompleteQ)) {
+ DEQUEUE(&ConnRequestCompleteQ, Req, TCPReq, tr_q);
+ CTEStructAssert(Req, tr);
+ CTEStructAssert(*(TCPConnReq **)&Req, tcr);
+
+ CTEFreeLock(&RequestCompleteLock, CompleteHandle);
+ (*Req->tr_rtn)(Req->tr_context, Req->tr_status, 0);
+ FreeConnReq((TCPConnReq *)Req);
+ CTEGetLock(&RequestCompleteLock, &CompleteHandle);
+
+ } else
+ RequestCompleteFlags &= ~CONN_REQUEST_COMPLETE;
+ }
+
+ if (RequestCompleteFlags & SEND_REQUEST_COMPLETE) {
+ if (!EMPTYQ(&SendCompleteQ)) {
+ TCPSendReq *SendReq;
+
+ DEQUEUE(&SendCompleteQ, Req, TCPReq, tr_q);
+ CTEStructAssert(Req, tr);
+ SendReq = (TCPSendReq *)Req;
+ CTEStructAssert(SendReq, tsr);
+
+ CTEFreeLock(&RequestCompleteLock, CompleteHandle);
+ (*Req->tr_rtn)(Req->tr_context, Req->tr_status,
+ Req->tr_status == TDI_SUCCESS ? SendReq->tsr_size
+ : 0);
+ FreeSendReq((TCPSendReq *)Req);
+ CTEGetLock(&RequestCompleteLock, &CompleteHandle);
+
+ } else
+ RequestCompleteFlags &= ~SEND_REQUEST_COMPLETE;
+ }
+
+ } while (RequestCompleteFlags & ANY_REQUEST_COMPLETE);
+
+ RequestCompleteFlags &= ~IN_RCV_COMPLETE;
+ }
+ CTEFreeLock(&RequestCompleteLock, CompleteHandle);
+ }
+
+ ProcessTCBDelayQ();
+
+}
+
+//* CompleteConnReq - Complete a connection request on a TCB.
+//
+// A utility function to complete a connection request on a TCB. We remove
+// the connreq, and put it on the ConnReqCmpltQ where it will be picked
+// off later during RcvCmplt processing. We assume the TCB lock is held when
+// we're called.
+//
+// Input: CmpltTCB - TCB from which to complete.
+// OptInfo - IP OptInfo for completeion.
+// Status - Status to complete with.
+//
+// Returns: Nothing.
+//
+void
+CompleteConnReq(TCB *CmpltTCB, IPOptInfo *OptInfo, TDI_STATUS Status)
+{
+ TCPConnReq *ConnReq;
+ CTELockHandle QueueHandle;
+
+ CTEStructAssert(CmpltTCB, tcb);
+
+ ConnReq = CmpltTCB->tcb_connreq;
+ if (ConnReq != NULL) {
+
+ // There's a connreq on this TCB. Fill in the connection information
+ // before returning it.
+
+ CmpltTCB->tcb_connreq = NULL;
+ UpdateConnInfo(ConnReq->tcr_conninfo, OptInfo, CmpltTCB->tcb_daddr,
+ CmpltTCB->tcb_dport);
+
+ ConnReq->tcr_req.tr_status = Status;
+ CTEGetLockAtDPC(&RequestCompleteLock, &QueueHandle);
+ RequestCompleteFlags |= CONN_REQUEST_COMPLETE;
+ ENQUEUE(&ConnRequestCompleteQ, &ConnReq->tcr_req.tr_q);
+ CTEFreeLockFromDPC(&RequestCompleteLock, QueueHandle);
+ } else
+ DEBUGCHK;
+
+}
+
+
+#ifdef SYN_ATTACK
+void
+SynAttChk ( AddrObj *ListenAO )
+//
+// function to check whether certain thresholds relevant to containing a
+// SYN attack are being crossed.
+//
+// This function is called from FindListenConn when a connection has been
+// found to handle the SYN request
+//
+{
+ BOOLEAN RexmitCntChanged = FALSE;
+ CTELockHandle Handle;
+
+ CTEGetLockAtDPC(&SynAttLock, &Handle);
+
+ //
+ // We are putting a connection in the syn_rcvd state. Check
+ // if we have reached the threshold. If we have reduce the
+ // number of retries to a lower value.
+ //
+ if ((++TCPHalfOpen >= TCPMaxHalfOpen) && (MaxConnectResponseRexmitCountTmp == MAX_CONNECT_RESPONSE_REXMIT_CNT)) {
+ if (TCPHalfOpenRetried >= TCPMaxHalfOpenRetried) {
+ MaxConnectResponseRexmitCountTmp = ADAPTED_MAX_CONNECT_RESPONSE_REXMIT_CNT;
+ RexmitCntChanged = TRUE;
+ }
+ }
+
+ //
+ // if this connection limit for a port was reached earlier.
+ // Check if the lower watermark is getting hit now.
+ //
+
+ if (ListenAO->ConnLimitReached)
+ {
+ ListenAO->ConnLimitReached = FALSE;
+ if (!RexmitCntChanged && (MaxConnectResponseRexmitCountTmp == ADAPTED_MAX_CONNECT_RESPONSE_REXMIT_CNT)) {
+
+ CTEAssert(TCPPortsExhausted > 0);
+ //
+ // The fact that FindListenConn found a connection on the port
+ // indicates that we had a connection available. This port
+ // was therefore not exhausted of connections. Set state
+ // appropriately. If the port has no more connections now,
+ // it will get added to the Exhausted count next time a syn for
+ // the port comes along.
+ //
+ if (--TCPPortsExhausted <= TCPMaxPortsExhaustedLW) {
+ MaxConnectResponseRexmitCountTmp =
+ MAX_CONNECT_RESPONSE_REXMIT_CNT;
+ }
+ }
+ }
+
+ CTEFreeLockFromDPC(&SynAttLock, Handle);
+ return;
+}
+#endif
+
+
+//* FindListenConn - Find (or fabricate) a listening connection.
+//
+// Called by our Receive handler to decide what to do about an incoming
+// SYN. We walk down the list of connections associated with the destination
+// address, and if we find any in the listening state that can be used for
+// the incoming request we'll take them, possibly returning a listen in the
+// process. If we don't find any appropriate listening connections, we'll
+// call the Connect Event handler if one is registerd. If all else fails,
+// we'll return NULL and the SYN will be RST.
+//
+// The caller must hold the AddrObjTableLock before calling this routine,
+// and that lock must have been taken at DPC level. This routine will free
+// that lock back to DPC level.
+//
+// Input: ListenAO - Pointer to AddrObj for local address.
+// Src - Source IP address of SYN.
+// SrcPort - Source port of SYN.
+// OptInfo - IP options info from SYN.
+//
+// Returns: Pointer to found TCB, or NULL if we can't find one.
+//
+TCB *
+FindListenConn(AddrObj *ListenAO, IPAddr Src, ushort SrcPort, IPOptInfo *OptInfo)
+{
+ CTELockHandle Handle; // Lock handle on AO, TCB.
+ TCB *CurrentTCB = NULL;
+ TCPConn *CurrentConn = NULL;
+ TCPConnReq *ConnReq = NULL;
+ CTELockHandle ConnHandle;
+ Queue *Temp;
+ uint FoundConn = FALSE;
+
+ CTEStructAssert(ListenAO, ao);
+
+ CTEGetLockAtDPC(&ConnTableLock, &ConnHandle);
+ CTEGetLockAtDPC(&ListenAO->ao_lock, &Handle);
+
+#ifdef NT
+ CTEFreeLockFromDPC(&AddrObjTableLock, DISPATCH_LEVEL);
+#endif
+
+
+ // We have the lock on the AddrObj. Walk down it's list, looking
+ // for connections in the listening state.
+
+ if (AO_VALID(ListenAO)) {
+ if (ListenAO->ao_listencnt != 0) {
+ CTELockHandle TCBHandle;
+
+ Temp = QHEAD(&ListenAO->ao_listenq);
+ while (Temp != QEND(&ListenAO->ao_listenq)) {
+
+ CurrentConn = QSTRUCT(TCPConn, Temp, tc_q);
+ CTEStructAssert(CurrentConn, tc);
+
+ // If this TCB is in the listening state, with no delete
+ // pending, it's a candidate. Look at the pending listen
+ // info. to see if we should take it.
+ if ((CurrentTCB = CurrentConn->tc_tcb) != NULL) {
+
+ CTEStructAssert(CurrentTCB, tcb);
+ CTEAssert(CurrentTCB->tcb_state == TCB_LISTEN);
+
+ CTEGetLockAtDPC(&CurrentTCB->tcb_lock, &TCBHandle);
+
+ if (CurrentTCB->tcb_state == TCB_LISTEN &&
+ !PENDING_ACTION(CurrentTCB)) {
+
+ // Need to see if we can take it.
+ // See if the addresses specifed in the ConnReq
+ // match.
+ if ((IP_ADDR_EQUAL(CurrentTCB->tcb_daddr,
+ NULL_IP_ADDR) ||
+ IP_ADDR_EQUAL(CurrentTCB->tcb_daddr,
+ Src)) &&
+ (CurrentTCB->tcb_dport == 0 ||
+ CurrentTCB->tcb_dport == SrcPort)) {
+ FoundConn = TRUE;
+ break;
+ }
+
+ // Otherwise, this didn't match, so we'll check the
+ // next one.
+ }
+ CTEFreeLockFromDPC(&CurrentTCB->tcb_lock, TCBHandle);
+ }
+
+ Temp = QNEXT(Temp);;
+ }
+
+ // See why we've exited the loop.
+ if (FoundConn) {
+ CTEStructAssert(CurrentTCB, tcb);
+
+ // We exited because we found a TCB. If it's pre-accepted,
+ // we're done.
+ CurrentTCB->tcb_refcnt++;
+
+ CTEAssert(CurrentTCB->tcb_connreq != NULL);
+
+ ConnReq = CurrentTCB->tcb_connreq;
+ // If QUERY_ACCEPT isn't set, turn on the CONN_ACCEPTED bit.
+ if (!(ConnReq->tcr_flags & TDI_QUERY_ACCEPT))
+ CurrentTCB->tcb_flags |= CONN_ACCEPTED;
+
+ CurrentTCB->tcb_state = TCB_SYN_RCVD;
+
+ ListenAO->ao_listencnt--;
+
+ // Since he's no longer listening, remove him from the listen
+ // queue and put him on the active queue.
+ REMOVEQ(&CurrentConn->tc_q);
+ ENQUEUE(&ListenAO->ao_activeq, &CurrentConn->tc_q);
+#ifdef SYN_ATTACK
+ if (SynAttackProtect) {
+ SynAttChk(ListenAO);
+ }
+#endif
+
+ CTEFreeLockFromDPC(&CurrentTCB->tcb_lock, TCBHandle);
+ CTEFreeLockFromDPC(&ListenAO->ao_lock, Handle);
+ CTEFreeLockFromDPC(&ConnTableLock, ConnHandle);
+ return CurrentTCB;
+ } else {
+ // Since we have a listening count, this should never happen
+ // if that count was non-zero initially.
+ CTEAssert(FALSE);
+ }
+ }
+
+ // We didn't find a matching TCB. If there's a connect indication
+ // handler, call it now to find a connection to accept on.
+
+ CTEAssert(FoundConn == FALSE);
+
+ if (ListenAO->ao_connect != NULL) {
+ uchar TAddress[TCP_TA_SIZE];
+ PVOID ConnContext;
+ PConnectEvent Event;
+ PVOID EventContext;
+ TDI_STATUS Status;
+ TCB *AcceptTCB;
+ TCPConnReq *ConnReq;
+#ifdef NT
+ ConnectEventInfo *EventInfo;
+#else
+ ConnectEventInfo EventInfo;
+#endif
+
+
+ // He has a connect handler. Put the transport address together,
+ // and call him. We also need to get the necessary resources
+ // first.
+ AcceptTCB = AllocTCB();
+ ConnReq = GetConnReq();
+
+ if (AcceptTCB != NULL && ConnReq != NULL) {
+ Event = ListenAO->ao_connect;
+ EventContext = ListenAO->ao_conncontext;
+
+ BuildTDIAddress(TAddress, Src, SrcPort);
+ REF_AO(ListenAO);
+
+ AcceptTCB->tcb_state = TCB_LISTEN;
+ AcceptTCB->tcb_connreq = ConnReq;
+ AcceptTCB->tcb_flags |= CONN_ACCEPTED;
+
+ CTEFreeLockFromDPC(&ListenAO->ao_lock, Handle);
+ CTEFreeLockFromDPC(&ConnTableLock, ConnHandle);
+
+ IF_TCPDBG(TCP_DEBUG_CONNECT) {
+ TCPTRACE(("indicating connect request\n"));
+ }
+
+ Status = (*Event)(EventContext, TCP_TA_SIZE,
+ (PTRANSPORT_ADDRESS)TAddress, 0, NULL,
+ OptInfo->ioi_optlength, OptInfo->ioi_options,
+ &ConnContext, &EventInfo);
+
+ if (Status == TDI_MORE_PROCESSING) {
+#ifdef NT
+ PIO_STACK_LOCATION IrpSp;
+ PTDI_REQUEST_KERNEL_ACCEPT AcceptRequest;
+
+ IrpSp = IoGetCurrentIrpStackLocation(EventInfo);
+
+ Status = TCPPrepareIrpForCancel(
+ (PTCP_CONTEXT) IrpSp->FileObject->FsContext,
+ EventInfo,
+ TCPCancelRequest
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ Status = TDI_NOT_ACCEPTED;
+ EventInfo = NULL;
+ goto AcceptIrpCancelled;
+ }
+
+#endif // NT
+
+ // He accepted it. Find the connection on the AddrObj.
+ CTEGetLockAtDPC(&ConnTableLock, &ConnHandle);
+ CTEGetLockAtDPC(&ListenAO->ao_lock, &Handle);
+#ifdef NT
+ {
+
+ IF_TCPDBG(TCP_DEBUG_CONNECT) {
+ TCPTRACE((
+ "connect indication accepted, queueing request\n"
+ ));
+ }
+
+ AcceptRequest = (PTDI_REQUEST_KERNEL_ACCEPT)
+ &(IrpSp->Parameters);
+ ConnReq->tcr_conninfo =
+ AcceptRequest->ReturnConnectionInformation;
+ ConnReq->tcr_req.tr_rtn = TCPRequestComplete;
+ ConnReq->tcr_req.tr_context = EventInfo;
+
+ }
+#else // NT
+ ConnReq->tcr_req.tr_rtn = EventInfo.cei_rtn;
+ ConnReq->tcr_req.tr_context = EventInfo.cei_context;
+ ConnReq->tcr_conninfo = EventInfo.cei_conninfo;
+#endif // NT
+ Temp = QHEAD(&ListenAO->ao_idleq);;
+ CurrentTCB = NULL;
+ Status = TDI_INVALID_CONNECTION;
+
+ while (Temp != QEND(&ListenAO->ao_idleq)) {
+
+ CurrentConn = QSTRUCT(TCPConn, Temp, tc_q);
+
+ CTEStructAssert(CurrentConn, tc);
+ if ((CurrentConn->tc_context == ConnContext) &&
+ !(CurrentConn->tc_flags & CONN_INVALID)) {
+
+ // We think we have a match. The connection
+ // shouldn't have a TCB associated with it. If it
+ // does, it's an error. InitTCBFromConn will
+ // handle all this.
+
+ AcceptTCB->tcb_refcnt = 1;
+#ifdef NT
+ Status = InitTCBFromConn(CurrentConn, AcceptTCB,
+ AcceptRequest->RequestConnectionInformation,
+ TRUE);
+#else // NT
+ Status = InitTCBFromConn(CurrentConn, AcceptTCB,
+ EventInfo.cei_acceptinfo,
+ TRUE);
+#endif // NT
+
+ if (Status == TDI_SUCCESS) {
+ FoundConn = TRUE;
+ AcceptTCB->tcb_state = TCB_SYN_RCVD;
+ AcceptTCB->tcb_conn = CurrentConn;
+ CurrentConn->tc_tcb = AcceptTCB;
+ CurrentConn->tc_refcnt++;
+
+ // Move him from the idle q to the active
+ // queue.
+ REMOVEQ(&CurrentConn->tc_q);
+ ENQUEUE(&ListenAO->ao_activeq, &CurrentConn->tc_q);
+ }
+
+ // In any case, we're done now.
+ break;
+
+ }
+ Temp = QNEXT(Temp);
+ }
+
+ if (!FoundConn) {
+ // Didn't find a match, or had an error. Status
+ // code is set.
+ // Complete the ConnReq and free the resources.
+ CompleteConnReq(AcceptTCB, OptInfo, Status);
+ FreeTCB(AcceptTCB);
+ AcceptTCB = NULL;
+ }
+#ifdef SYN_ATTACK
+ else {
+ if (SynAttackProtect) {
+ SynAttChk(ListenAO);
+ }
+ }
+#endif
+
+ LOCKED_DELAY_DEREF_AO(ListenAO);
+ CTEFreeLockFromDPC(&ListenAO->ao_lock, Handle);
+ CTEFreeLockFromDPC(&ConnTableLock, ConnHandle);
+
+ return AcceptTCB;
+ }
+#ifdef SYN_ATTACK
+
+ if (SynAttackProtect) {
+ CTELockHandle Handle;
+
+ //
+ // If we need to Trigger to a lower retry count
+ //
+
+ if (!ListenAO->ConnLimitReached) {
+ ListenAO->ConnLimitReached = TRUE;
+ CTEGetLockAtDPC(&SynAttLock, &Handle);
+ if ((++TCPPortsExhausted >= TCPMaxPortsExhausted) &&
+ (MaxConnectResponseRexmitCountTmp == MAX_CONNECT_RESPONSE_REXMIT_CNT)) {
+
+ MaxConnectResponseRexmitCountTmp = ADAPTED_MAX_CONNECT_RESPONSE_REXMIT_CNT;
+ }
+ CTEFreeLockFromDPC(&SynAttLock, Handle);
+ }
+ }
+#endif
+
+#ifdef NT
+
+AcceptIrpCancelled:
+
+#endif // NT
+ // The event handler didn't take it. Dereference it, free
+ // the resources, and return NULL.
+ FreeConnReq(ConnReq);
+ FreeTCB(AcceptTCB);
+ DELAY_DEREF_AO(ListenAO);
+ return NULL;
+
+ } else {
+ // We couldn't get a needed resource. Free any that we
+ // did get, and fall through to the 'return NULL' code.
+ if (ConnReq != NULL)
+ FreeConnReq(ConnReq);
+ if (AcceptTCB != NULL)
+ FreeTCB(AcceptTCB);
+ }
+
+ }
+#ifdef SYN_ATTACK
+ else {
+ if (SynAttackProtect) {
+ CTELockHandle Handle;
+
+ //
+ // If we need to Trigger to a lower retry count
+ //
+
+ if (!ListenAO->ConnLimitReached) {
+ ListenAO->ConnLimitReached = TRUE;
+ CTEGetLockAtDPC(&SynAttLock, &Handle);
+ if ((++TCPPortsExhausted >= TCPMaxPortsExhausted) &&
+ (MaxConnectResponseRexmitCountTmp == MAX_CONNECT_RESPONSE_REXMIT_CNT)) {
+
+ MaxConnectResponseRexmitCountTmp = ADAPTED_MAX_CONNECT_RESPONSE_REXMIT_CNT;
+ }
+ CTEFreeLockFromDPC(&SynAttLock, Handle);
+ }
+ }
+ }
+#endif
+
+ // No event handler, or no resource. Free the locks, and return NULL.
+ CTEFreeLockFromDPC(&ListenAO->ao_lock, Handle);
+ CTEFreeLockFromDPC(&ConnTableLock, ConnHandle);
+ return NULL;
+ }
+
+ // If we get here, the address object wasn't valid.
+ CTEFreeLockFromDPC(&ListenAO->ao_lock, Handle);
+ CTEFreeLockFromDPC(&ConnTableLock, ConnHandle);
+ return NULL;
+}
+
+
+//* FindMSS - Find the MSS option in a segment.
+//
+// Called when a SYN is received to find the MSS option in a segment. If we
+// don't find one, we assume the worst and return 536.
+//
+// Input: TCPH - TCP header to be searched.
+//
+// Returns: MSS to be used.
+//
+ushort
+FindMSS(TCPHeader UNALIGNED *TCPH)
+{
+ uint OptSize;
+ uchar *OptPtr;
+
+ OptSize = TCP_HDR_SIZE(TCPH) - sizeof(TCPHeader);
+
+ OptPtr = (uchar *)(TCPH + 1);
+
+ while (OptSize) {
+
+ if (*OptPtr == TCP_OPT_EOL)
+ break;
+
+ if (*OptPtr == TCP_OPT_NOP) {
+ OptPtr++;
+ OptSize--;
+ continue;
+ }
+
+ if (*OptPtr == TCP_OPT_MSS) {
+ if (OptPtr[1] == MSS_OPT_SIZE) {
+ ushort TempMss = *(ushort UNALIGNED *)(OptPtr + 2);
+ if (TempMss != 0)
+ return net_short(TempMss);
+ else
+ break; // MSS size of 0, use default.
+ } else
+ break; // Bad option size, use default.
+ } else {
+ // Unknown option.
+ if (OptPtr[1] == 0 || OptPtr[1] > OptSize)
+ break; // Bad option length, bail out.
+
+ OptSize -= OptPtr[1];
+ OptPtr += OptPtr[1];
+ }
+ }
+
+ return MAX_REMOTE_MSS;
+
+}
+
+//* ACKAndDrop - Acknowledge a segment, and drop it.
+//
+// Called from within the receive code when we need to drop a segment that's
+// outside the receive window.
+//
+// Input: RI - Receive info for incoming segment.
+// RcvTCB - TCB for incoming segment.
+//
+// Returns: Nothing.
+//
+void
+ACKAndDrop(TCPRcvInfo *RI, TCB *RcvTCB)
+{
+ CTELockHandle Handle;
+
+#ifdef VXD
+#ifdef DEBUG
+ Handle = DEFAULT_SIMIRQL;
+#endif
+#else
+ Handle = DISPATCH_LEVEL;
+#endif
+
+ if (!(RI->tri_flags & TCP_FLAG_RST)) {
+
+ if (RcvTCB->tcb_state == TCB_TIME_WAIT)
+ START_TCB_TIMER(RcvTCB->tcb_rexmittimer, MAX_REXMIT_TO);
+
+ CTEFreeLockFromDPC(&RcvTCB->tcb_lock, Handle);
+
+ SendACK(RcvTCB);
+
+ CTEGetLockAtDPC(&RcvTCB->tcb_lock, &Handle);
+ }
+ DerefTCB(RcvTCB, Handle);
+
+}
+
+//* ACKData - Acknowledge data.
+//
+// Called from the receive handler to acknowledge data. We're given the
+// TCB and the new value of senduna. We walk down the send q. pulling
+// off sends and putting them on the complete q until we hit the end
+// or we acknowledge the specified number of bytes of data.
+//
+// NOTE: We manipulate the send refcnt and acked flag without taking a lock.
+// This is OK in the VxD version where locks don't mean anything anyway, but
+// in the port to NT we'll need to add locking. The lock will have to be
+// taken in the transmit complete routine. We can't use a lock in the TCB,
+// since the TCB could go away before the transmit complete happens, and a lock
+// in the TSR would be overkill, so it's probably best to use a global lock
+// for this. If that causes too much contention, we could use a set of locks
+// and pass a pointer to the appropriate lock back as part of the transmit
+// confirm context. This lock pointer would also need to be stored in the
+// TCB.
+//
+// Input: ACKTcb - TCB from which to pull data.
+// SendUNA - New value of send una.
+//
+// Returns: Nothing.
+//
+void
+ACKData(TCB *ACKTcb, SeqNum SendUNA)
+{
+ Queue *End, *Current; // End and current elements.
+ Queue *TempQ, *EndQ;
+ Queue *LastCmplt; // Last one we completed.
+ TCPSendReq *CurrentTSR; // Current send req we're
+ // looking at.
+ PNDIS_BUFFER CurrentBuffer; // Current NDIS_BUFFER.
+ uint Updated = FALSE;
+ uint BufLength;
+ int Amount, OrigAmount;
+ long Result;
+ CTELockHandle Handle;
+ uint Temp;
+
+ CTEStructAssert(ACKTcb, tcb);
+
+ CheckTCBSends(ACKTcb);
+
+ Amount = SendUNA - ACKTcb->tcb_senduna;
+ CTEAssert(Amount > 0);
+
+ // Do a quick check to see if this acks everything that we have. If it does,
+ // handle it right away. We can only do this in the ESTABLISHED state,
+ // because we blindly update sendnext, and that can only work if we
+ // haven't sent a FIN.
+ if ((Amount == (int) ACKTcb->tcb_unacked) && ACKTcb->tcb_state == TCB_ESTAB) {
+
+ // Everything is acked.
+ CTEAssert(!EMPTYQ(&ACKTcb->tcb_sendq));
+
+ TempQ = ACKTcb->tcb_sendq.q_next;
+
+ INITQ(&ACKTcb->tcb_sendq);
+
+ ACKTcb->tcb_sendnext = SendUNA;
+ ACKTcb->tcb_senduna = SendUNA;
+
+ CTEAssert(ACKTcb->tcb_sendnext == ACKTcb->tcb_sendmax);
+ ACKTcb->tcb_cursend = NULL;
+ ACKTcb->tcb_sendbuf = NULL;
+ ACKTcb->tcb_sendofs = 0;
+ ACKTcb->tcb_sendsize = 0;
+ ACKTcb->tcb_unacked = 0;
+
+ // Now walk down the list of send requests. If the reference count
+ // has gone to 0, put it on the send complete queue.
+ CTEGetLock(&RequestCompleteLock, &Handle);
+ EndQ = &ACKTcb->tcb_sendq;
+ do {
+ CurrentTSR = STRUCT_OF(TCPSendReq, QSTRUCT(TCPReq, TempQ, tr_q),
+ tsr_req);
+
+ CTEStructAssert(CurrentTSR, tsr);
+
+ TempQ = CurrentTSR->tsr_req.tr_q.q_next;
+
+ CurrentTSR->tsr_req.tr_status = TDI_SUCCESS;
+ Result = CTEInterlockedDecrementLong(&CurrentTSR->tsr_refcnt);
+
+ CTEAssert(Result >= 0);
+
+
+ if (Result <= 0) {
+ // No more references are outstanding, the send can be
+ // completed.
+
+ // If we've sent directly from this send, NULL out the next
+ // pointer for the last buffer in the chain.
+ if (CurrentTSR->tsr_lastbuf != NULL) {
+ NDIS_BUFFER_LINKAGE(CurrentTSR->tsr_lastbuf) = NULL;
+ CurrentTSR->tsr_lastbuf = NULL;
+ }
+ ACKTcb->tcb_totaltime += (TCPTime - CurrentTSR->tsr_time);
+ Temp = ACKTcb->tcb_bcountlow;
+ ACKTcb->tcb_bcountlow += CurrentTSR->tsr_size;
+ ACKTcb->tcb_bcounthi += (Temp > ACKTcb->tcb_bcountlow ? 1 : 0);
+
+ ENQUEUE(&SendCompleteQ, &CurrentTSR->tsr_req.tr_q);
+ }
+
+ } while (TempQ != EndQ);
+
+ RequestCompleteFlags |= SEND_REQUEST_COMPLETE;
+ CTEFreeLock(&RequestCompleteLock, Handle);
+
+ CheckTCBSends(ACKTcb);
+ return;
+ }
+
+ OrigAmount = Amount;
+ End = QEND(&ACKTcb->tcb_sendq);
+ Current = QHEAD(&ACKTcb->tcb_sendq);
+
+ LastCmplt = NULL;
+
+ while (Amount > 0 && Current != End) {
+ CurrentTSR = STRUCT_OF(TCPSendReq, QSTRUCT(TCPReq, Current, tr_q),
+ tsr_req);
+ CTEStructAssert(CurrentTSR, tsr);
+
+
+ if (Amount >= (int) CurrentTSR->tsr_unasize) {
+ // This is completely acked. Just advance to the next one.
+ Amount -= CurrentTSR->tsr_unasize;
+
+ LastCmplt = Current;
+
+ Current = QNEXT(Current);
+ continue;
+ }
+
+ // This one is only partially acked. Update his offset and NDIS buffer
+ // pointer, and break out. We know that Amount is < the unacked size
+ // in this buffer, we we can walk the NDIS buffer chain without fear
+ // of falling off the end.
+ CurrentBuffer = CurrentTSR->tsr_buffer;
+ CTEAssert(CurrentBuffer != NULL);
+ CTEAssert(Amount < (int) CurrentTSR->tsr_unasize);
+ CurrentTSR->tsr_unasize -= Amount;
+
+ BufLength = NdisBufferLength(CurrentBuffer) - CurrentTSR->tsr_offset;
+
+ if (Amount >= (int) BufLength) {
+ do {
+ Amount -= BufLength;
+ CurrentBuffer = NDIS_BUFFER_LINKAGE(CurrentBuffer);
+ CTEAssert(CurrentBuffer != NULL);
+ BufLength = NdisBufferLength(CurrentBuffer);
+ } while (Amount >= (int) BufLength);
+
+ CurrentTSR->tsr_offset = Amount;
+ CurrentTSR->tsr_buffer = CurrentBuffer;
+
+ } else
+ CurrentTSR->tsr_offset += Amount;
+
+ Amount = 0;
+
+ break;
+ }
+
+#ifdef DEBUG
+ // We should always be able to remove at least Amount bytes, except in
+ // the case where a FIN has been sent. In that case we should be off
+ // by exactly one. In the debug builds we'll check this.
+ if (Amount != 0 && (!(ACKTcb->tcb_flags & FIN_SENT) || Amount != 1))
+ DEBUGCHK;
+#endif
+
+ if (SEQ_GT(SendUNA, ACKTcb->tcb_sendnext)) {
+
+ if (Current != End) {
+ // Need to reevaluate CurrentTSR, in case we bailed out of the
+ // above loop after updating Current but before updating
+ // CurrentTSR.
+ CurrentTSR = STRUCT_OF(TCPSendReq, QSTRUCT(TCPReq, Current, tr_q),
+ tsr_req);
+ CTEStructAssert(CurrentTSR, tsr);
+ ACKTcb->tcb_cursend = CurrentTSR;
+ ACKTcb->tcb_sendbuf = CurrentTSR->tsr_buffer;
+ ACKTcb->tcb_sendofs = CurrentTSR->tsr_offset;
+ ACKTcb->tcb_sendsize = CurrentTSR->tsr_unasize;
+ } else {
+ ACKTcb->tcb_cursend = NULL;
+ ACKTcb->tcb_sendbuf = NULL;
+ ACKTcb->tcb_sendofs = 0;
+ ACKTcb->tcb_sendsize = 0;
+ }
+
+ ACKTcb->tcb_sendnext = SendUNA;
+ }
+
+ // Now update tcb_unacked with the amount we tried to ack minus the
+ // amount we didn't ack (Amount should be 0 or 1 here).
+ CTEAssert(Amount == 0 || Amount == 1);
+
+ ACKTcb->tcb_unacked -= OrigAmount - Amount;
+ CTEAssert(*(int *)&ACKTcb->tcb_unacked >= 0);
+
+ ACKTcb->tcb_senduna = SendUNA;
+
+ // If we've acked any here, LastCmplt will be non-null, and Current will
+ // point to the send that should be at the start of the queue. Splice
+ // out the completed ones and put them on the end of the send completed
+ // queue, and update the TCB send q.
+ if (LastCmplt != NULL) {
+ Queue *FirstCmplt;
+ TCPSendReq *FirstTSR, *EndTSR;
+
+ CTEAssert(!EMPTYQ(&ACKTcb->tcb_sendq));
+
+ FirstCmplt = QHEAD(&ACKTcb->tcb_sendq);
+
+ // If we've acked everything, just reinit the queue.
+ if (Current == End) {
+ INITQ(&ACKTcb->tcb_sendq);
+ } else {
+ // There's still something on the queue. Just update it.
+ ACKTcb->tcb_sendq.q_next = Current;
+ Current->q_prev = &ACKTcb->tcb_sendq;
+ }
+
+ CheckTCBSends(ACKTcb);
+
+ // Now walk down the lists of things acked. If the refcnt on the send
+ // is 0, go ahead and put him on the send complete Q. Otherwise set
+ // the ACKed bit in the send, and he'll be completed when the count
+ // goes to 0 in the transmit confirm.
+ //
+ // Note that we haven't done any locking here. This will probably
+ // need to change in the port to NT.
+
+ // Set FirstTSR to the first TSR we'll complete, and EndTSR to be
+ // the first TSR that isn't completed.
+
+ FirstTSR = STRUCT_OF(TCPSendReq, QSTRUCT(TCPReq, FirstCmplt, tr_q),
+ tsr_req);
+ EndTSR = STRUCT_OF(TCPSendReq, QSTRUCT(TCPReq, Current, tr_q),
+ tsr_req);
+
+ CTEStructAssert(FirstTSR, tsr);
+ CTEAssert(FirstTSR != EndTSR);
+
+ // Now walk the list of ACKed TSRs. If we can complete one, put him
+ // on the complete queue.
+ CTEGetLockAtDPC(&RequestCompleteLock, &Handle);
+ while (FirstTSR != EndTSR) {
+
+
+ TempQ = QNEXT(&FirstTSR->tsr_req.tr_q);
+
+ CTEStructAssert(FirstTSR, tsr);
+ FirstTSR->tsr_req.tr_status = TDI_SUCCESS;
+
+ // The tsr_lastbuf->Next field is zapped to 0 when the tsr_refcnt
+ // goes to 0, so we don't need to do it here.
+
+ // Decrement the reference put on the send buffer when it was
+ // initialized indicating the send has been acknowledged.
+ Result = CTEInterlockedDecrementLong(&(FirstTSR->tsr_refcnt));
+
+ CTEAssert(Result >= 0);
+ if (Result <= 0) {
+ // No more references are outstanding, the send can be
+ // completed.
+
+ // If we've sent directly from this send, NULL out the next
+ // pointer for the last buffer in the chain.
+ if (FirstTSR->tsr_lastbuf != NULL) {
+ NDIS_BUFFER_LINKAGE(FirstTSR->tsr_lastbuf) = NULL;
+ FirstTSR->tsr_lastbuf = NULL;
+ }
+
+ ACKTcb->tcb_totaltime += (TCPTime - CurrentTSR->tsr_time);
+ Temp = ACKTcb->tcb_bcountlow;
+ ACKTcb->tcb_bcountlow += CurrentTSR->tsr_size;
+ ACKTcb->tcb_bcounthi += (Temp > ACKTcb->tcb_bcountlow ? 1 : 0);
+ ENQUEUE(&SendCompleteQ, &FirstTSR->tsr_req.tr_q);
+ }
+
+ FirstTSR = STRUCT_OF(TCPSendReq, QSTRUCT(TCPReq, TempQ, tr_q),
+ tsr_req);
+ }
+ RequestCompleteFlags |= SEND_REQUEST_COMPLETE;
+ CTEFreeLockFromDPC(&RequestCompleteLock, Handle);
+ }
+
+}
+
+//* TrimRcvBuf - Trim the front edge of a receive buffer.
+//
+// A utility routine to trim the front of a receive buffer. We take in a
+// a count (which may be 0) and adjust the pointer in the first buffer in
+// the chain by that much. If there isn't that much in the first buffer,
+// we move onto the next one. If we run out of buffers we'll return a pointer
+// to the last buffer in the chain, with a size of 0. It's the caller's
+// responsibility to catch this.
+//
+// Input: RcvBuf - Buffer to be trimmed.
+// Count - Amount to be trimmed.
+//
+// Returns: A pointer to the new start, or NULL.
+//
+IPRcvBuf *
+TrimRcvBuf(IPRcvBuf *RcvBuf, uint Count)
+{
+ uint TrimThisTime;
+
+ CTEAssert(RcvBuf != NULL);
+
+ while (Count) {
+ CTEAssert(RcvBuf != NULL);
+
+ TrimThisTime = MIN(Count, RcvBuf->ipr_size);
+ Count -= TrimThisTime;
+ RcvBuf->ipr_buffer += TrimThisTime;
+ if ((RcvBuf->ipr_size -= TrimThisTime) == 0) {
+ if (RcvBuf->ipr_next != NULL)
+ RcvBuf = RcvBuf->ipr_next;
+ else {
+ // Ran out of buffers. Just return this one.
+ break;
+ }
+ }
+ }
+
+ return RcvBuf;
+
+}
+
+//* FreeRBChain - Free an RB chain.
+//
+// Called to free a chain of RBs. If we're the owner of each RB, we'll
+// free it.
+//
+// Input: RBChain - RBChain to be freed.
+//
+// Returns: Nothing.
+//
+void
+FreeRBChain(IPRcvBuf *RBChain)
+{
+ while (RBChain != NULL) {
+
+ if (RBChain->ipr_owner == IPR_OWNER_TCP) {
+ IPRcvBuf *Temp;
+
+ Temp = RBChain->ipr_next;
+ CTEFreeMem(RBChain);
+ RBChain = Temp;
+ } else
+ RBChain = RBChain->ipr_next;
+ }
+
+}
+
+IPRcvBuf DummyBuf;
+
+//* PullFromRAQ - Pull segments from the reassembly queue.
+//
+// Called when we've received frames out of order, and have some segments
+// on the reassembly queue. We'll walk down the reassembly list, segments that
+// are overlapped by the current rcv. next variable. When we get
+// to one that doesn't completely overlap we'll trim it to fit the next
+// rcv. seq. number, and pull it from the queue.
+//
+// Input: RcvTCB - TCB to pull from.
+// RcvInfo - Pointer to TCPRcvInfo structure for current seg.
+// Size - Pointer to size for current segment. We'll update
+// this when we're done.
+//
+// Returns: Nothing.
+//
+IPRcvBuf *
+PullFromRAQ(TCB *RcvTCB, TCPRcvInfo *RcvInfo, uint *Size)
+{
+ TCPRAHdr *CurrentTRH; // Current TCP RA Header being examined.
+ TCPRAHdr *TempTRH; // Temporary variable.
+ SeqNum NextSeq; // Next sequence number we want.
+ IPRcvBuf *NewBuf;
+ SeqNum NextTRHSeq; // Seq. number immediately after
+ // current TRH.
+ int Overlap; // Overlap between current TRH and
+ // NextSeq.
+
+ CTEStructAssert(RcvTCB, tcb);
+
+ CurrentTRH = RcvTCB->tcb_raq;
+ NextSeq = RcvTCB->tcb_rcvnext;
+
+ while (CurrentTRH != NULL) {
+ CTEStructAssert(CurrentTRH, trh);
+ CTEAssert(!(CurrentTRH->trh_flags & TCP_FLAG_SYN));
+
+ // If the flags for the current reassembly segment contains a FIN,
+ // it should be the last segment on the queue. This assert checks
+ // that.
+ CTEAssert(!(CurrentTRH->trh_flags & TCP_FLAG_FIN) ||
+ CurrentTRH->trh_next == NULL);
+
+ if (SEQ_LT(NextSeq, CurrentTRH->trh_start)) {
+#ifdef DEBUG
+ *Size = 0;
+#endif
+ return NULL; // The next TRH starts too far down.
+ }
+
+
+ NextTRHSeq = CurrentTRH->trh_start + CurrentTRH->trh_size +
+ ((CurrentTRH->trh_flags & TCP_FLAG_FIN) ? 1 : 0);
+
+ if (SEQ_GTE(NextSeq, NextTRHSeq)) {
+ // The current TRH is overlapped completely. Free it and continue.
+ FreeRBChain(CurrentTRH->trh_buffer);
+ TempTRH = CurrentTRH->trh_next;
+ CTEFreeMem(CurrentTRH);
+ CurrentTRH = TempTRH;
+ RcvTCB->tcb_raq = TempTRH;
+ if (TempTRH == NULL) {
+ // We've just cleaned off the RAQ. We can go back on the
+ // fast path now.
+ if (--(RcvTCB->tcb_slowcount) == 0) {
+ RcvTCB->tcb_fastchk &= ~TCP_FLAG_SLOW;
+ CheckTCBRcv(RcvTCB);
+ }
+ break;
+ }
+ } else {
+ Overlap = NextSeq - CurrentTRH->trh_start;
+ RcvInfo->tri_seq = NextSeq;
+ RcvInfo->tri_flags = CurrentTRH->trh_flags;
+ RcvInfo->tri_urgent = CurrentTRH->trh_urg;
+
+ if (Overlap != (int) CurrentTRH->trh_size) {
+ NewBuf = FreePartialRB(CurrentTRH->trh_buffer, Overlap);
+ *Size = CurrentTRH->trh_size - Overlap;
+ } else {
+ // This completely overlaps the data in this segment, but the
+ // sequence number doesn't overlap completely. There must
+ // be a FIN in the TRH. If we called FreePartialRB with this
+ // we'd end up returning NULL, which is the signal for failure.
+ // Instead we'll just return some bogus value that nobody
+ // will look at with a size of 0.
+ FreeRBChain(CurrentTRH->trh_buffer);
+ CTEAssert(CurrentTRH->trh_flags & TCP_FLAG_FIN);
+ NewBuf = &DummyBuf;
+ *Size = 0;
+ }
+
+ RcvTCB->tcb_raq = CurrentTRH->trh_next;
+ if (RcvTCB->tcb_raq == NULL) {
+ // We've just cleaned off the RAQ. We can go back on the
+ // fast path now.
+ if (--(RcvTCB->tcb_slowcount) == 0) {
+ RcvTCB->tcb_fastchk &= ~TCP_FLAG_SLOW;
+ CheckTCBRcv(RcvTCB);
+ }
+
+ }
+ CTEFreeMem(CurrentTRH);
+ return NewBuf;
+ }
+
+
+ }
+
+#ifdef DEBUG
+ *Size = 0;
+#endif
+ return NULL;
+
+}
+
+//* CreateTRH - Create a TCP reassembly header.
+//
+// This function tries to create a TCP reassembly header. We take as input
+// a pointer to the previous TRH in the chain, the RcvBuffer to put on,
+// etc. and try to create and link in a TRH. The caller must hold the lock
+// on the TCB when this is called.
+//
+// Input: PrevTRH - Pointer to TRH to insert after.
+// RcvBuf - Pointer to IP RcvBuf chain.
+// RcvInfo - Pointer to RcvInfo for this TRH.
+// Size - Size in bytes of data.
+//
+// Returns: TRUE if we created it, FALSE otherwise.
+//
+uint
+CreateTRH(TCPRAHdr *PrevTRH, IPRcvBuf *RcvBuf, TCPRcvInfo *RcvInfo, int Size)
+{
+ TCPRAHdr *NewTRH;
+ IPRcvBuf *NewRcvBuf;
+
+ CTEAssert((Size > 0) || (RcvInfo->tri_flags & TCP_FLAG_FIN));
+
+ NewTRH = CTEAllocMem(sizeof(TCPRAHdr));
+ if (NewTRH == NULL)
+ return FALSE;
+
+ NewRcvBuf = CTEAllocMem(sizeof(IPRcvBuf) + Size);
+ if (NewRcvBuf == NULL) {
+ CTEFreeMem(NewTRH);
+ return FALSE;
+ }
+
+#ifdef DEBUG
+ NewTRH->trh_sig = trh_signature;
+#endif
+ NewRcvBuf->ipr_owner = IPR_OWNER_TCP;
+ NewRcvBuf->ipr_size = (uint)Size;
+ NewRcvBuf->ipr_next = NULL;
+ NewRcvBuf->ipr_buffer = (uchar *)(NewRcvBuf + 1);
+ if (Size != 0)
+ CopyRcvToBuffer(NewRcvBuf->ipr_buffer, RcvBuf, Size, 0);
+
+ NewTRH->trh_start = RcvInfo->tri_seq;
+ NewTRH->trh_flags = RcvInfo->tri_flags;
+ NewTRH->trh_size = Size;
+ NewTRH->trh_urg = RcvInfo->tri_urgent;
+ NewTRH->trh_buffer = NewRcvBuf;
+ NewTRH->trh_end = NewRcvBuf;
+
+ NewTRH->trh_next = PrevTRH->trh_next;
+ PrevTRH->trh_next = NewTRH;
+ return TRUE;
+
+}
+
+//* PutOnRAQ - Put a segment on the reassembly queue.
+//
+// Called during segment reception to put a segment on the reassembly
+// queue. We try to use as few reassembly headers as possible, so if this
+// segment has some overlap with an existing entry in the queue we'll just
+// update the existing entry. If there is no overlap we'll create a new
+// reassembly header. Combining URGENT data with non-URGENT data is tricky.
+// If we get a segment that has urgent data that overlaps the front of a
+// reassembly header we'll always mark the whole chunk as urgent - the value
+// of the urgent pointer will mark the end of urgent data, so this is OK. If it
+// only overlaps at the end, however, we won't combine, since we would have to
+// mark previously non-urgent data as urgent. We'll trim the
+// front of the incoming segment and create a new reassembly header. Also,
+// if we have non-urgent data that overlaps at the front of a reassembly
+// header containing urgent data we can't combine these two, since again we
+// would mark non-urgent data as urgent.
+// Our search will stop if we find an entry with a FIN.
+// We assume that the TCB lock is held by the caller.
+//
+// Entry: RcvTCB - TCB on which to reassemble.
+// RcvInfo - Pointer to RcvInfo for new segment.
+// RcvBuf - IP RcvBuf chain for this segment.
+// Size - Size in bytes of data in this segment.
+//
+// Returns: Nothing.
+//
+void
+PutOnRAQ(TCB *RcvTCB, TCPRcvInfo *RcvInfo, IPRcvBuf *RcvBuf, uint Size)
+{
+ TCPRAHdr *PrevTRH, *CurrentTRH; // Prev. and current TRH
+ // pointers.
+ SeqNum NextSeq; // Seq. number of first byte
+ // after segment being
+ // reassembled.
+ SeqNum NextTRHSeq; // Seq. number of first byte
+ // after current TRH.
+ uint Created;
+
+ CTEStructAssert(RcvTCB, tcb);
+ CTEAssert(RcvTCB->tcb_rcvnext != RcvInfo->tri_seq);
+ CTEAssert(!(RcvInfo->tri_flags & TCP_FLAG_SYN));
+ NextSeq = RcvInfo->tri_seq + Size +
+ ((RcvInfo->tri_flags & TCP_FLAG_FIN) ? 1 : 0);
+
+ PrevTRH = STRUCT_OF(TCPRAHdr, &RcvTCB->tcb_raq, trh_next);
+ CurrentTRH = PrevTRH->trh_next;
+
+ // Walk down the reassembly queue, looking for the correct place to
+ // insert this, until we hit the end.
+ while (CurrentTRH != NULL) {
+ CTEStructAssert(CurrentTRH, trh);
+
+ CTEAssert(!(CurrentTRH->trh_flags & TCP_FLAG_SYN));
+ NextTRHSeq = CurrentTRH->trh_start + CurrentTRH->trh_size +
+ ((CurrentTRH->trh_flags & TCP_FLAG_FIN) ? 1 : 0);
+
+ // First, see if it starts beyond the end of the current TRH.
+ if (SEQ_LTE(RcvInfo->tri_seq, NextTRHSeq)) {
+ // We know the incoming segment doesn't start beyond the end
+ // of this TRH, so we'll either create a new TRH in front of
+ // this one or we'll merge the new segment onto this TRH.
+ // If the end of the current segment is in front of the start
+ // of the current TRH, we'll need to create a new TRH. Otherwise
+ // we'll merge these two.
+ if (SEQ_LT(NextSeq, CurrentTRH->trh_start))
+ break;
+ else {
+ // There's some overlap. If there's actually data in the
+ // incoming segment we'll merge it.
+ if (Size != 0) {
+ int FrontOverlap, BackOverlap;
+ IPRcvBuf *NewRB;
+
+ // We need to merge. If there's a FIN on the incoming
+ // segment that would fall inside this current TRH, we
+ // have a protocol violation from the remote peer. In this
+ // case just return, discarding the incoming segment.
+ if ((RcvInfo->tri_flags & TCP_FLAG_FIN) &&
+ SEQ_LTE(NextSeq, NextTRHSeq))
+ return;
+
+ // We have some overlap. Figure out how much.
+ FrontOverlap = CurrentTRH->trh_start - RcvInfo->tri_seq;
+ if (FrontOverlap > 0) {
+ // Have overlap in front. Allocate an IPRcvBuf to
+ // to hold it, and copy it, unless we would have to
+ // combine non-urgent with urgent.
+ if (!(RcvInfo->tri_flags & TCP_FLAG_URG) &&
+ (CurrentTRH->trh_flags & TCP_FLAG_URG)) {
+ if (CreateTRH(PrevTRH, RcvBuf, RcvInfo,
+ CurrentTRH->trh_start - RcvInfo->tri_seq)) {
+ PrevTRH = PrevTRH->trh_next;
+ CurrentTRH = PrevTRH->trh_next;
+ }
+ FrontOverlap = 0;
+
+ } else {
+ NewRB = CTEAllocMem(sizeof(IPRcvBuf) + FrontOverlap);
+ if (NewRB == NULL)
+ return; // Couldn't get the buffer.
+
+ NewRB->ipr_owner = IPR_OWNER_TCP;
+ NewRB->ipr_size = FrontOverlap;
+ NewRB->ipr_buffer = (uchar *)(NewRB + 1);
+ CopyRcvToBuffer(NewRB->ipr_buffer, RcvBuf,
+ FrontOverlap, 0);
+ CurrentTRH->trh_size += FrontOverlap;
+ NewRB->ipr_next = CurrentTRH->trh_buffer;
+ CurrentTRH->trh_buffer = NewRB;
+ CurrentTRH->trh_start = RcvInfo->tri_seq;
+ }
+ }
+
+ // We've updated the starting sequence number of this TRH
+ // if we needed to. Now look for back overlap. There can't
+ // be any back overlap if the current TRH has a FIN. Also
+ // we'll need to check for urgent data if there is back
+ // overlap.
+ if (!(CurrentTRH->trh_flags & TCP_FLAG_FIN)) {
+ BackOverlap = RcvInfo->tri_seq + Size - NextTRHSeq;
+ if ((BackOverlap > 0) &&
+ (RcvInfo->tri_flags & TCP_FLAG_URG) &&
+ !(CurrentTRH->trh_flags & TCP_FLAG_URG) &&
+ (FrontOverlap <= 0)) {
+ int AmountToTrim;
+ // The incoming segment has urgent data and overlaps
+ // on the back but not the front, and the current
+ // TRH has no urgent data. We can't combine into
+ // this TRH, so trim the front of the incoming
+ // segment to NextTRHSeq and move to the next
+ // TRH.
+ AmountToTrim = NextTRHSeq - RcvInfo->tri_seq;
+ CTEAssert(AmountToTrim >= 0);
+ CTEAssert(AmountToTrim < (int) Size);
+ RcvBuf = FreePartialRB(RcvBuf, (uint)AmountToTrim);
+ RcvInfo->tri_seq += AmountToTrim;
+ RcvInfo->tri_urgent -= AmountToTrim;
+ PrevTRH = CurrentTRH;
+ CurrentTRH = PrevTRH->trh_next;
+ continue;
+ }
+
+ } else
+ BackOverlap = 0;
+
+ // Now if we have back overlap, copy it.
+ if (BackOverlap > 0) {
+ // We have back overlap. Get a buffer to copy it into.
+ // If we can't get one, we won't just return, because
+ // we may have updated the front and may need to
+ // update the urgent info.
+ NewRB = CTEAllocMem(sizeof(IPRcvBuf) + BackOverlap);
+ if (NewRB != NULL) {
+ // Got the buffer.
+ NewRB->ipr_owner = IPR_OWNER_TCP;
+ NewRB->ipr_size = BackOverlap;
+ NewRB->ipr_buffer = (uchar *)(NewRB + 1);
+ CopyRcvToBuffer(NewRB->ipr_buffer, RcvBuf,
+ BackOverlap, NextTRHSeq - RcvInfo->tri_seq);
+ CurrentTRH->trh_size += BackOverlap;
+ NewRB->ipr_next = CurrentTRH->trh_end->ipr_next;
+ CurrentTRH->trh_end->ipr_next = NewRB;
+ CurrentTRH->trh_end = NewRB;
+ }
+ }
+
+ // Everything should be consistent now. If there's an
+ // urgent data pointer in the incoming segment, update the
+ // one in the TRH now.
+ if (RcvInfo->tri_flags & TCP_FLAG_URG) {
+ SeqNum UrgSeq;
+ // Have an urgent pointer. If the current TRH already
+ // has an urgent pointer, see which is bigger. Otherwise
+ // just use this one.
+ UrgSeq = RcvInfo->tri_seq + RcvInfo->tri_urgent;
+ if (CurrentTRH->trh_flags & TCP_FLAG_URG) {
+ SeqNum TRHUrgSeq;
+
+ TRHUrgSeq = CurrentTRH->trh_start +
+ CurrentTRH->trh_urg;
+ if (SEQ_LT(UrgSeq, TRHUrgSeq))
+ UrgSeq = TRHUrgSeq;
+ } else
+ CurrentTRH->trh_flags |= TCP_FLAG_URG;
+
+ CurrentTRH->trh_urg = UrgSeq - CurrentTRH->trh_start;
+ }
+
+ } else {
+ // We have a 0 length segment. The only interesting thing
+ // here is if there's a FIN on the segment. If there is,
+ // and the seq. # of the incoming segment is exactly after
+ // the current TRH, OR matches the FIN in the current TRH,
+ // we note it.
+ if (RcvInfo->tri_flags & TCP_FLAG_FIN) {
+ if (!(CurrentTRH->trh_flags & TCP_FLAG_FIN)) {
+ if (SEQ_EQ(NextTRHSeq, RcvInfo->tri_seq))
+ CurrentTRH->trh_flags |= TCP_FLAG_FIN;
+ else
+ DEBUGCHK;
+ }
+ else {
+ if ( !(SEQ_EQ((NextTRHSeq-1), RcvInfo->tri_seq)) ) {
+ DEBUGCHK;
+ }
+ }
+ }
+ }
+ return;
+ }
+ } else {
+ // Look at the next TRH, unless the current TRH has a FIN. If he
+ // has a FIN, we won't save any data beyond that anyway.
+ if (CurrentTRH->trh_flags & TCP_FLAG_FIN)
+ return;
+
+ PrevTRH = CurrentTRH;
+ CurrentTRH = PrevTRH->trh_next;
+ }
+ }
+
+ // When we get here, we need to create a new TRH. If we create one and
+ // there was previously nothing on the reassembly queue, we'll have to
+ // move off the fast receive path.
+
+ CurrentTRH = RcvTCB->tcb_raq;
+ Created = CreateTRH(PrevTRH, RcvBuf, RcvInfo, (int)Size);
+
+ if (Created && CurrentTRH == NULL) {
+ RcvTCB->tcb_slowcount++;
+ RcvTCB->tcb_fastchk |= TCP_FLAG_SLOW;
+ CheckTCBRcv(RcvTCB);
+ }
+
+
+}
+
+
+//* TCPRcv - Receive a TCP segment.
+//
+// This is the routine called by IP when we need to receive a TCP segment.
+// In general, we follow the RFC 793 event processing section pretty closely,
+// but there is a 'fast path' where we make some quick checks on the incoming
+// segment, and if it matches we deliver it immediately.
+//
+// Entry: IPContext - IPContext identifying physical i/f that
+// received the data.
+// Dest - IPAddr of destionation.
+// Src - IPAddr of source.
+// LocalAddr - Local address of network which caused this to be
+// received.
+// SrcAddr - Address of local interface which received the packet
+// IPH - IP Header.
+// IPHLength - Bytes in IPH.
+// RcvBuf - Pointer to receive buffer chain containing data.
+// Size - Size in bytes of data received.
+// IsBCast - Boolean indicator of whether or not this came in as
+// a bcast.
+// Protocol - Protocol this came in on - should be TCP.
+// OptInfo - Pointer to info structure for received options.
+//
+// Returns: Status of reception. Anything other than IP_SUCCESS will cause
+// IP to send a 'port unreachable' message.
+//
+IP_STATUS
+TCPRcv(void *IPContext, IPAddr Dest, IPAddr Src, IPAddr LocalAddr,
+ IPAddr SrcAddr, IPHeader UNALIGNED *IPH, uint IPHLength, IPRcvBuf *RcvBuf,
+ uint Size, uchar IsBCast, uchar Protocol, IPOptInfo *OptInfo)
+{
+ TCPHeader UNALIGNED *TCPH; // The TCP header.
+ TCB *RcvTCB; // TCB on which to receive the packet.
+ CTELockHandle TableHandle, TCBHandle;
+ TCPRcvInfo RcvInfo; // Local swapped copy of rcv info.
+ uint DataOffset; // Offset from start of header to data.
+ uint Actions;
+ uint BytesTaken;
+ uint NewSize;
+
+ CheckRBList(RcvBuf, Size);
+
+ TStats.ts_insegs++;
+
+ // Checksum it, to make sure it's valid.
+ TCPH = (TCPHeader *)RcvBuf->ipr_buffer;
+
+ if (!IsBCast) {
+
+ if (Size >= sizeof(TCPHeader) && XsumRcvBuf(PHXSUM(Src, Dest, PROTOCOL_TCP,
+ Size), RcvBuf) == 0xffff) {
+
+ // The packet is valid. Get the info we need and byte swap it,
+ // and then try to find a matching TCB.
+
+ RcvInfo.tri_seq = net_long(TCPH->tcp_seq);
+ RcvInfo.tri_ack = net_long(TCPH->tcp_ack);
+ RcvInfo.tri_window = (uint)net_short(TCPH->tcp_window);
+ RcvInfo.tri_urgent = (uint)net_short(TCPH->tcp_urgent);
+ RcvInfo.tri_flags = (uint)TCPH->tcp_flags;
+ DataOffset = TCP_HDR_SIZE(TCPH);
+
+ if (DataOffset <= Size) {
+
+ Size -= DataOffset;
+ CTEAssert(DataOffset <= RcvBuf->ipr_size);
+ RcvBuf->ipr_size -= DataOffset;
+ RcvBuf->ipr_buffer += DataOffset;
+
+ CTEGetLockAtDPC(&TCBTableLock, &TableHandle);
+ RcvTCB = FindTCB(Dest, Src, TCPH->tcp_src, TCPH->tcp_dest);
+ if (RcvTCB != NULL) {
+ // Found one. Get the lock on it, and continue.
+ CTEGetLockAtDPC(&RcvTCB->tcb_lock, &TCBHandle);
+ CTEFreeLockFromDPC(&TCBTableLock, TCBHandle);
+ } else {
+ uchar DType;
+
+ // Didn't find a matching TCB. If this segment carries a SYN,
+ // find a matching address object and see it it has a listen
+ // indication. If it does, call it. Otherwise send a RST
+ // back to the sender.
+ CTEFreeLockFromDPC(&TCBTableLock, TableHandle);
+
+
+ // Make sure that the source address isn't a broadcast
+ // before proceeding.
+ if ((*LocalNetInfo.ipi_invalidsrc)(Src))
+ return IP_SUCCESS;
+
+ // If it doesn't have a SYN (and only a SYN), we'll send a
+ // reset.
+ if ((RcvInfo.tri_flags & (TCP_FLAG_SYN | TCP_FLAG_ACK | TCP_FLAG_RST)) ==
+ TCP_FLAG_SYN) {
+ AddrObj *AO;
+
+ //
+ // This segment had a SYN.
+ //
+ //
+#ifdef NT
+ CTEGetLockAtDPC(&AddrObjTableLock, &TableHandle);
+#endif
+
+#ifdef SECFLTR
+ // See if we are filtering the
+ // destination interface/port.
+ //
+ if ( (!SecurityFilteringEnabled ||
+ IsPermittedSecurityFilter(
+ LocalAddr,
+ IPContext,
+ PROTOCOL_TCP,
+ (ulong) net_short(TCPH->tcp_dest)
+ ))
+ )
+ {
+#else // SECFLTR
+ if ( 1 ) {
+#endif // SECFLTR
+
+ //
+ // Find a matching address object, and then try and find a
+ // listening connection on that AO.
+ //
+ AO = GetBestAddrObj(Dest, TCPH->tcp_dest, PROTOCOL_TCP);
+ if (AO != NULL) {
+
+ // Found an AO. Try and find a listening connection.
+ // FindListenConn will free the lock on the AddrObjTable.
+ RcvTCB = FindListenConn(AO, Src, TCPH->tcp_src, OptInfo);
+
+ if (RcvTCB != NULL) {
+ uint Inserted;
+
+ CTEStructAssert(RcvTCB, tcb);
+ CTEGetLockAtDPC(&RcvTCB->tcb_lock, &TableHandle);
+
+ // We found a listening connection. Initialize it
+ // now, and if it is actually to be accepted we'll
+ // send a SYN-ACK also.
+
+ CTEAssert(RcvTCB->tcb_state == TCB_SYN_RCVD);
+
+ RcvTCB->tcb_daddr = Src;
+ RcvTCB->tcb_saddr = Dest;
+ RcvTCB->tcb_dport = TCPH->tcp_src;
+ RcvTCB->tcb_sport = TCPH->tcp_dest;
+ RcvTCB->tcb_rcvnext = ++RcvInfo.tri_seq;
+ RcvTCB->tcb_sendwin = RcvInfo.tri_window;
+ RcvTCB->tcb_remmss = FindMSS(TCPH);
+ TStats.ts_passiveopens++;
+ RcvTCB->tcb_fastchk |= TCP_FLAG_IN_RCV;
+ CTEFreeLockFromDPC(&RcvTCB->tcb_lock, TableHandle);
+
+ Inserted = InsertTCB(RcvTCB);
+
+ // Get the lock on it, and see if it's been
+ // accepted.
+ CTEGetLockAtDPC(&RcvTCB->tcb_lock, &TableHandle);
+ if (!Inserted) {
+ // Couldn't insert it!.
+ CompleteConnReq(RcvTCB, OptInfo,
+ TDI_CONNECTION_ABORTED);
+ RcvTCB->tcb_refcnt--;
+#ifdef NT
+ TryToCloseTCB(RcvTCB, TCB_CLOSE_ABORTED, DISPATCH_LEVEL);
+#else
+ TryToCloseTCB(RcvTCB, TCB_CLOSE_ABORTED, TableHandle);
+#endif
+ return IP_SUCCESS;
+ }
+
+
+ RcvTCB->tcb_fastchk &= ~TCP_FLAG_IN_RCV;
+ if (RcvTCB->tcb_flags & SEND_AFTER_RCV) {
+ RcvTCB->tcb_flags &= ~SEND_AFTER_RCV;
+ DelayAction(RcvTCB, NEED_OUTPUT);
+ }
+
+ // We'll need to update the options, in any case.
+ if (OptInfo->ioi_options != NULL) {
+ if (!(RcvTCB->tcb_flags & CLIENT_OPTIONS)) {
+ (*LocalNetInfo.ipi_updateopts)(OptInfo,
+ &RcvTCB->tcb_opt, Src, NULL_IP_ADDR);
+ }
+ }
+
+ if (RcvTCB->tcb_flags & CONN_ACCEPTED) {
+
+ // The connection was accepted. Finish the
+ // initialization, and send the SYN ack.
+
+#ifdef NT
+ AcceptConn(RcvTCB, DISPATCH_LEVEL);
+#else
+ AcceptConn(RcvTCB, TableHandle);
+#endif
+
+ return IP_SUCCESS;
+ } else {
+
+ // We don't know what to do about the
+ // connection yet. Return the pending listen,
+ // dereference the connection, and return.
+
+ CompleteConnReq(RcvTCB, OptInfo, TDI_SUCCESS);
+
+#ifdef NT
+ DerefTCB(RcvTCB, DISPATCH_LEVEL);
+#else
+ DerefTCB(RcvTCB, TableHandle);
+#endif
+
+ return IP_SUCCESS;
+ }
+
+ }
+ // No listening connection. AddrObjTableLock was
+ // released by FindListenConn. Fall through to send
+ // RST code.
+
+ } else {
+ // No address object. Free the lock, and fall through
+ // to the send RST code.
+ CTEFreeLockFromDPC(&AddrObjTableLock, TableHandle);
+ }
+ }
+ else {
+ // Operation not permitted. Free the lock, and fall through
+ // to the send RST code.
+ CTEFreeLockFromDPC(&AddrObjTableLock, TableHandle);
+ }
+
+ }
+
+ // Toss out any segments containing RST.
+ if (RcvInfo.tri_flags & TCP_FLAG_RST)
+ return IP_SUCCESS;
+
+ // Not a SYN, no AddrObj available, or port filtered.
+ // Send a RST back.
+ SendRSTFromHeader(TCPH, Size, Src, Dest, OptInfo);
+
+ return IP_SUCCESS;
+ }
+
+ // Do the fast path check. We can hit the fast path if the incoming
+ // sequence number matches our receive next and the masked flags
+ // match our 'predicted' flags.
+ CheckTCBRcv(RcvTCB);
+ RcvTCB->tcb_alive = TCPTime;
+
+ if (RcvTCB->tcb_rcvnext == RcvInfo.tri_seq &&
+ (RcvInfo.tri_flags & TCP_FLAGS_ALL) == RcvTCB->tcb_fastchk){
+
+ Actions = 0;
+ RcvTCB->tcb_refcnt++;
+
+ // The fast path. We know all we have to do here is ack sends and
+ // deliver data. First try and ack data.
+
+
+ if (SEQ_LT(RcvTCB->tcb_senduna, RcvInfo.tri_ack) &&
+ SEQ_LTE(RcvInfo.tri_ack, RcvTCB->tcb_sendmax)) {
+
+ uint CWin;
+ uint MSS;
+
+ // The ack acknowledes something. Pull the
+ // appropriate amount off the send q.
+ ACKData(RcvTCB, RcvInfo.tri_ack);
+
+ // If this acknowledges something we were running a RTT on,
+ // update that stuff now.
+ if (RcvTCB->tcb_rtt != 0 && SEQ_GT(RcvInfo.tri_ack,
+ RcvTCB->tcb_rttseq)) {
+ short RTT;
+
+ RTT = (short)(TCPTime - RcvTCB->tcb_rtt);
+ RcvTCB->tcb_rtt = 0;
+ RTT -= (RcvTCB->tcb_smrtt >> 3);
+ RcvTCB->tcb_smrtt += RTT;
+ RTT = (RTT >= 0 ? RTT : -RTT);
+ RTT -= (RcvTCB->tcb_delta >> 3);
+ RcvTCB->tcb_delta += RTT;
+ RcvTCB->tcb_rexmit = MIN(MAX(REXMIT_TO(RcvTCB),
+ MIN_RETRAN_TICKS), MAX_REXMIT_TO);
+ }
+
+ // Update the congestion window now.
+ CWin = RcvTCB->tcb_cwin;
+ MSS = RcvTCB->tcb_mss;
+ if (CWin < RcvTCB->tcb_maxwin) {
+ if (CWin < RcvTCB->tcb_ssthresh)
+ CWin += MSS;
+ else
+ CWin += (MSS * MSS)/CWin;
+
+ RcvTCB->tcb_cwin = CWin;
+ }
+
+ CTEAssert(*(int *)&RcvTCB->tcb_cwin > 0);
+
+ // We've acknowledged something, so reset the rexmit count.
+ // If there's still stuff outstanding, restart the rexmit
+ // timer.
+ RcvTCB->tcb_rexmitcnt = 0;
+ if (SEQ_EQ(RcvInfo.tri_ack, RcvTCB->tcb_sendmax))
+ STOP_TCB_TIMER(RcvTCB->tcb_rexmittimer);
+ else
+ START_TCB_TIMER(RcvTCB->tcb_rexmittimer, RcvTCB->tcb_rexmit);
+
+ // Since we've acknowledged data, we need to update the window.
+ RcvTCB->tcb_sendwin = RcvInfo.tri_window;
+ RcvTCB->tcb_maxwin = MAX(RcvTCB->tcb_maxwin, RcvInfo.tri_window);
+ RcvTCB->tcb_sendwl1 = RcvInfo.tri_seq;
+ RcvTCB->tcb_sendwl2 = RcvInfo.tri_ack;
+ // We've updated the window, remember to send some more.
+ Actions = (RcvTCB->tcb_unacked ? NEED_OUTPUT : 0);
+
+#if FAST_RETRANSMIT
+ {
+ // If the receiver has already sent dup acks, but we are not
+ // sending because the SendWin is less than a segment, then
+ // to avoid time outs on the previous send (receiver is waiting for
+ // retransmitted data but we are not sending the segment..) prematurely
+ // timeout (set rexmittimer to 1 tick)
+ //
+
+ int SendWin;
+ uint AmtOutstanding,AmtUnsent;
+
+ AmtOutstanding = (uint)(RcvTCB->tcb_sendnext -
+ RcvTCB->tcb_senduna);
+ AmtUnsent = RcvTCB->tcb_unacked - AmtOutstanding;
+
+ SendWin = (int)(MIN(RcvTCB->tcb_sendwin, RcvTCB->tcb_cwin) -
+ AmtOutstanding);
+
+
+ if ((Size == 0) &&
+ (SendWin < RcvTCB->tcb_mss) && (RcvTCB->tcb_dup > 0)) {
+ STOP_TCB_TIMER(RcvTCB->tcb_rexmittimer);
+ START_TCB_TIMER(RcvTCB->tcb_rexmittimer, 1);
+ }
+ }
+
+ RcvTCB->tcb_dup = 0;
+#endif
+
+ } else {
+ // It doesn't ack anything. If it's an ack for something
+ // larger than we've sent then ACKAndDrop it, otherwise
+ // ignore it.
+ if (SEQ_GT(RcvInfo.tri_ack, RcvTCB->tcb_sendmax)) {
+ ACKAndDrop(&RcvInfo, RcvTCB);
+ return IP_SUCCESS;
+ } else
+
+ //SEQ_EQ(RcvInfo.tri_ack, RcvTCB->tcb_sendmax
+ // If the ack matches our existing UNA, we need to see if
+ // we can update the window.
+ // Or check if fast retransmit is needed
+
+#if FAST_RETRANSMIT
+ // If it is a pure duplicate ack, check if it is
+ // time to retransmit immediately
+
+ if ( (Size == 0) && SEQ_EQ(RcvTCB->tcb_senduna, RcvInfo.tri_ack) &&
+ (RcvTCB->tcb_sendwin == RcvInfo.tri_window) ) {
+
+ RcvTCB->tcb_dup++;
+
+ if ((RcvTCB->tcb_dup == MaxDupAcks) ) {
+
+ //Okay. Time to retransmit the segment the receiver is asking for
+
+ STOP_TCB_TIMER(RcvTCB->tcb_rexmittimer);
+
+ RcvTCB->tcb_rtt = 0;
+
+ if (!(RcvTCB->tcb_flags & FLOW_CNTLD)) {
+
+ // Don't let the slow start threshold go below 2
+ // segments
+
+ RcvTCB->tcb_ssthresh =
+ MAX(
+ MIN(RcvTCB->tcb_cwin,RcvTCB->tcb_sendwin) / 2,
+ (uint) RcvTCB->tcb_mss * 2 );
+ RcvTCB->tcb_cwin = RcvTCB->tcb_mss;
+ }
+
+ // Recall the segment in question and send it out
+ // Note that tcb_lock will be dereferenced by the caller
+
+ ResetAndFastSend (RcvTCB, RcvTCB->tcb_senduna);
+
+ return IP_SUCCESS;
+
+
+ } else if ((RcvTCB->tcb_dup > MaxDupAcks) ) {
+
+ int SendWin;
+ uint AmtOutstanding,AmtUnsent;
+
+ if (SEQ_EQ(RcvTCB->tcb_senduna, RcvInfo.tri_ack) &&
+ (SEQ_LT(RcvTCB->tcb_sendwl1, RcvInfo.tri_seq) ||
+ (SEQ_EQ(RcvTCB->tcb_sendwl1, RcvInfo.tri_seq) &&
+ SEQ_LTE(RcvTCB->tcb_sendwl2, RcvInfo.tri_ack)))) {
+
+ RcvTCB->tcb_sendwin = RcvInfo.tri_window;
+ RcvTCB->tcb_maxwin = MAX(RcvTCB->tcb_maxwin,
+ RcvInfo.tri_window);
+ RcvTCB->tcb_sendwl1 = RcvInfo.tri_seq;
+ RcvTCB->tcb_sendwl2 = RcvInfo.tri_ack;
+
+ // Since we've updated the window, remember to send
+ // some more.
+
+ Actions = (RcvTCB->tcb_unacked ? NEED_OUTPUT : 0);
+ }
+
+ // Update the cwin to reflect the fact that the dup ack
+ // indicates the previous frame was received by the
+ // receiver
+
+
+ RcvTCB->tcb_cwin += RcvTCB->tcb_mss;
+
+ if ((RcvTCB->tcb_cwin+RcvTCB->tcb_mss) < RcvTCB->tcb_sendwin ) {
+ AmtOutstanding = (uint)(RcvTCB->tcb_sendnext -
+ RcvTCB->tcb_senduna);
+ AmtUnsent = RcvTCB->tcb_unacked - AmtOutstanding;
+
+ SendWin = (int)(MIN(RcvTCB->tcb_sendwin, RcvTCB->tcb_cwin) -
+ AmtOutstanding);
+
+ if (SendWin < RcvTCB->tcb_mss) {
+ RcvTCB->tcb_force=1;
+ }
+ }
+
+ Actions = (RcvTCB->tcb_unacked ? NEED_OUTPUT : 0);
+
+ } else if ((RcvTCB->tcb_dup < MaxDupAcks)) {
+
+ int SendWin;
+ uint AmtOutstanding,AmtUnsent;
+
+ if (SEQ_EQ(RcvTCB->tcb_senduna, RcvInfo.tri_ack) &&
+ (SEQ_LT(RcvTCB->tcb_sendwl1, RcvInfo.tri_seq) ||
+ (SEQ_EQ(RcvTCB->tcb_sendwl1, RcvInfo.tri_seq) &&
+ SEQ_LTE(RcvTCB->tcb_sendwl2, RcvInfo.tri_ack)))) {
+
+ RcvTCB->tcb_sendwin = RcvInfo.tri_window;
+ RcvTCB->tcb_maxwin = MAX(RcvTCB->tcb_maxwin,
+ RcvInfo.tri_window);
+ RcvTCB->tcb_sendwl1 = RcvInfo.tri_seq;
+ RcvTCB->tcb_sendwl2 = RcvInfo.tri_ack;
+
+ // Since we've updated the window, remember to send
+ // some more.
+ }
+
+ // Check if we need to set tcb_force.
+
+ if ((RcvTCB->tcb_cwin+RcvTCB->tcb_mss) < RcvTCB->tcb_sendwin ) {
+
+ AmtOutstanding = (uint)(RcvTCB->tcb_sendnext -
+ RcvTCB->tcb_senduna);
+ AmtUnsent = RcvTCB->tcb_unacked - AmtOutstanding;
+
+ SendWin = (int)(MIN(RcvTCB->tcb_sendwin, RcvTCB->tcb_cwin) -
+ AmtOutstanding);
+ if (SendWin < RcvTCB->tcb_mss){
+ RcvTCB->tcb_force=1;
+ }
+ }
+
+ Actions = (RcvTCB->tcb_unacked ? NEED_OUTPUT : 0);
+
+
+ } // End of all MaxDupAck cases
+
+ } else { // not a pure duplicate ack (size == 0 )
+
+ // Size !=0 or recvr is advertizing new window.
+ // update the window and check if
+ // anything needs to be sent
+
+ RcvTCB->tcb_dup = 0;
+
+ if (SEQ_EQ(RcvTCB->tcb_senduna, RcvInfo.tri_ack) &&
+ (SEQ_LT(RcvTCB->tcb_sendwl1, RcvInfo.tri_seq) ||
+ (SEQ_EQ(RcvTCB->tcb_sendwl1, RcvInfo.tri_seq) &&
+ SEQ_LTE(RcvTCB->tcb_sendwl2, RcvInfo.tri_ack)))) {
+ RcvTCB->tcb_sendwin = RcvInfo.tri_window;
+ RcvTCB->tcb_maxwin = MAX(RcvTCB->tcb_maxwin,
+ RcvInfo.tri_window);
+ RcvTCB->tcb_sendwl1 = RcvInfo.tri_seq;
+ RcvTCB->tcb_sendwl2 = RcvInfo.tri_ack;
+ // Since we've updated the window, remember to send
+ // some more.
+ Actions = (RcvTCB->tcb_unacked ? NEED_OUTPUT : 0);
+ }
+
+ } // for SEQ_EQ(RcvInfo.tri_ack, RcvTCB->tcb_sendmax) case
+
+#else //FAST_RETRANSMIT
+
+ if (SEQ_EQ(RcvTCB->tcb_senduna, RcvInfo.tri_ack) &&
+ (SEQ_LT(RcvTCB->tcb_sendwl1, RcvInfo.tri_seq) ||
+ (SEQ_EQ(RcvTCB->tcb_sendwl1, RcvInfo.tri_seq) &&
+ SEQ_LTE(RcvTCB->tcb_sendwl2, RcvInfo.tri_ack)))) {
+ RcvTCB->tcb_sendwin = RcvInfo.tri_window;
+ RcvTCB->tcb_maxwin = MAX(RcvTCB->tcb_maxwin,
+ RcvInfo.tri_window);
+ RcvTCB->tcb_sendwl1 = RcvInfo.tri_seq;
+ RcvTCB->tcb_sendwl2 = RcvInfo.tri_ack;
+ // Since we've updated the window, remember to send
+ // some more.
+ Actions = (RcvTCB->tcb_unacked ? NEED_OUTPUT : 0);
+ }
+#endif //FAST_RETRANSMIT
+
+ }
+
+
+ NewSize = MIN((int) Size, RcvTCB->tcb_rcvwin);
+ if (NewSize != 0) {
+ RcvTCB->tcb_fastchk |= TCP_FLAG_IN_RCV;
+#ifdef VXD
+ CTEFreeLock(&RcvTCB->tcb_lock, TableHandle);
+ BytesTaken = (*RcvTCB->tcb_rcvhndlr)(RcvTCB, RcvInfo.tri_flags,
+ RcvBuf, NewSize);
+ CTEGetLock(&RcvTCB->tcb_lock, &TableHandle);
+#else
+ BytesTaken = (*RcvTCB->tcb_rcvhndlr)(RcvTCB, RcvInfo.tri_flags,
+ RcvBuf, NewSize);
+#endif
+ RcvTCB->tcb_rcvnext += BytesTaken;
+ RcvTCB->tcb_rcvwin -= BytesTaken;
+ CheckTCBRcv(RcvTCB);
+
+ RcvTCB->tcb_fastchk &= ~TCP_FLAG_IN_RCV;
+
+ Actions |= (RcvTCB->tcb_flags & SEND_AFTER_RCV ?
+ NEED_OUTPUT : 0);
+
+ RcvTCB->tcb_flags &= ~SEND_AFTER_RCV;
+ if ((RcvTCB->tcb_flags & ACK_DELAYED) || (BytesTaken != NewSize))
+ Actions |= NEED_ACK;
+ else {
+ RcvTCB->tcb_flags |= ACK_DELAYED;
+ START_TCB_TIMER(RcvTCB->tcb_delacktimer, DEL_ACK_TICKS);
+ }
+ } else {
+ // The new size is 0. If the original size was not 0, we must
+ // have a 0 rcv. win and hence need to send an ACK to this
+ // probe.
+ Actions |= (Size ? NEED_ACK : 0);
+ }
+
+ if (Actions)
+ DelayAction(RcvTCB, Actions);
+
+#ifndef VXD
+ TableHandle = DISPATCH_LEVEL;
+#endif
+ DerefTCB(RcvTCB, TableHandle);
+
+ return IP_SUCCESS;
+ }
+
+#ifndef VXD
+ TableHandle = DISPATCH_LEVEL;
+#endif
+ // Make sure we can handle this frame. We can't handle it if we're
+ // in SYN_RCVD and the accept is still pending, or we're in a
+ // non-established state and already in the receive handler.
+ if ((RcvTCB->tcb_state == TCB_SYN_RCVD &&
+ !(RcvTCB->tcb_flags & CONN_ACCEPTED)) ||
+ (RcvTCB->tcb_state != TCB_ESTAB && (RcvTCB->tcb_fastchk &
+ TCP_FLAG_IN_RCV))) {
+ CTEFreeLockFromDPC(&RcvTCB->tcb_lock, TableHandle);
+ return IP_SUCCESS;
+ }
+
+ // If it's closed, it's a temporary zombie TCB. Reset the sender.
+ if (RcvTCB->tcb_state == TCB_CLOSED || CLOSING(RcvTCB) ||
+ ((RcvTCB->tcb_flags & (GC_PENDING | TW_PENDING)) == GC_PENDING)) {
+ CTEFreeLockFromDPC(&RcvTCB->tcb_lock, TableHandle);
+ SendRSTFromHeader(TCPH, Size, Src, Dest, OptInfo);
+ return IP_SUCCESS;
+ }
+
+ // At this point, we have a connection, and it's locked. Following
+ // the 'Segment Arrives' section of 793, the next thing to check is
+ // if this connection is in SynSent state.
+
+ if (RcvTCB->tcb_state == TCB_SYN_SENT) {
+
+ CTEAssert(RcvTCB->tcb_flags & ACTIVE_OPEN);
+
+ // Check the ACK bit. Since we don't send data with our SYNs, the
+ // check we make is for the ack to exactly match our SND.NXT.
+ if (RcvInfo.tri_flags & TCP_FLAG_ACK) {
+ // ACK is set.
+ if (!SEQ_EQ(RcvInfo.tri_ack, RcvTCB->tcb_sendnext)) {
+ // Bad ACK value.
+ CTEFreeLockFromDPC(&RcvTCB->tcb_lock, TableHandle);
+ // Send a RST back at him.
+ SendRSTFromHeader(TCPH, Size, Src, Dest, OptInfo);
+ return IP_SUCCESS;
+ }
+ }
+
+ if (RcvInfo.tri_flags & TCP_FLAG_RST) {
+ // There's an acceptable RST. We'll persist here, sending
+ // another SYN in PERSIST_TIMEOUT ms, until we fail from too
+ // many retrys.
+ if (RcvTCB->tcb_rexmitcnt == MaxConnectRexmitCount) {
+ // We've had a positive refusal, and one more rexmit
+ // would time us out, so close the connection now.
+ CompleteConnReq(RcvTCB, OptInfo, TDI_CONN_REFUSED);
+
+ TryToCloseTCB(RcvTCB, TCB_CLOSE_REFUSED, TableHandle);
+ } else {
+ START_TCB_TIMER(RcvTCB->tcb_rexmittimer, PERSIST_TIMEOUT);
+ CTEFreeLockFromDPC(&RcvTCB->tcb_lock, TableHandle);
+ }
+ return IP_SUCCESS;
+ }
+
+ // See if we have a SYN. If we do, we're going to change state
+ // somehow (either to ESTABLISHED or SYN_RCVD).
+ if (RcvInfo.tri_flags & TCP_FLAG_SYN) {
+ RcvTCB->tcb_refcnt++;
+
+ // We have a SYN. Go ahead and record the sequence number and
+ // window info.
+ RcvTCB->tcb_rcvnext = ++RcvInfo.tri_seq;
+
+ if (RcvInfo.tri_flags & TCP_FLAG_URG) {
+ // Urgent data. Update the pointer.
+ if (RcvInfo.tri_urgent != 0)
+ RcvInfo.tri_urgent--;
+ else
+ RcvInfo.tri_flags &= ~TCP_FLAG_URG;
+ }
+
+ RcvTCB->tcb_remmss = FindMSS(TCPH);
+
+ // If there are options, update them now. We already have an
+ // RCE open, so if we have new options we'll have to close
+ // it and open a new one.
+ if (OptInfo->ioi_options != NULL) {
+ if (!(RcvTCB->tcb_flags & CLIENT_OPTIONS)) {
+ (*LocalNetInfo.ipi_updateopts)(OptInfo,
+ &RcvTCB->tcb_opt, Src, NULL_IP_ADDR);
+ (*LocalNetInfo.ipi_closerce)(RcvTCB->tcb_rce);
+ InitRCE(RcvTCB);
+ }
+ } else{
+ RcvTCB->tcb_mss = MIN(RcvTCB->tcb_mss, RcvTCB->tcb_remmss);
+
+ CTEAssert(RcvTCB->tcb_mss > 0);
+
+ }
+
+ RcvTCB->tcb_rexmitcnt = 0;
+ STOP_TCB_TIMER(RcvTCB->tcb_rexmittimer);
+
+ AdjustRcvWin(RcvTCB);
+
+ if (RcvInfo.tri_flags & TCP_FLAG_ACK) {
+ // Our SYN has been acked. Update SND.UNA and stop the
+ // retrans timer.
+ RcvTCB->tcb_senduna = RcvInfo.tri_ack;
+ RcvTCB->tcb_sendwin = RcvInfo.tri_window;
+ RcvTCB->tcb_maxwin = RcvInfo.tri_window;
+ RcvTCB->tcb_sendwl1 = RcvInfo.tri_seq;
+ RcvTCB->tcb_sendwl2 = RcvInfo.tri_ack;
+ GoToEstab(RcvTCB);
+
+#ifdef RASAUTODIAL
+ //
+ // Set a bit that informs TCBTimeout to notify
+ // the automatic connection driver of this new
+ // connection. Only set this flag if we
+ // have binded succesfully with the automatic
+ // connection driver.
+ //
+ if (fAcdLoadedG)
+ RcvTCB->tcb_flags |= ACD_CONN_NOTIF;
+#endif // RASAUTODIAL
+
+ // Remove whatever command exists on this connection.
+ CompleteConnReq(RcvTCB, OptInfo, TDI_SUCCESS);
+
+ CTEFreeLockFromDPC(&RcvTCB->tcb_lock, TableHandle);
+ SendACK(RcvTCB);
+
+ // Now handle other data and controls. To do this we need
+ // to reaquire the lock, and make sure we haven't started
+ // closing it.
+ CTEGetLockAtDPC(&RcvTCB->tcb_lock, &TableHandle);
+ if (!CLOSING(RcvTCB)) {
+ // We haven't started closing it. Turn off the
+ // SYN flag and continue processing.
+ RcvInfo.tri_flags &= ~TCP_FLAG_SYN;
+ if ((RcvInfo.tri_flags & TCP_FLAGS_ALL) != TCP_FLAG_ACK ||
+ Size != 0)
+ goto NotSYNSent;
+ }
+ DerefTCB(RcvTCB, TableHandle);
+ return IP_SUCCESS;
+ } else {
+ // A SYN, but not an ACK. Go to SYN_RCVD.
+ RcvTCB->tcb_state = TCB_SYN_RCVD;
+ RcvTCB->tcb_sendnext = RcvTCB->tcb_senduna;
+ SendSYN(RcvTCB, TableHandle);
+
+ CTEGetLockAtDPC(&RcvTCB->tcb_lock, &TableHandle);
+ DerefTCB(RcvTCB, TableHandle);
+ return IP_SUCCESS;
+ }
+
+ } else {
+ // No SYN, just toss the frame.
+ CTEFreeLockFromDPC(&RcvTCB->tcb_lock, TableHandle);
+ return IP_SUCCESS;
+ }
+
+ }
+
+ RcvTCB->tcb_refcnt++;
+
+NotSYNSent:
+ // Not in the SYN-SENT state. Check the sequence number. If my window
+ // is 0, I'll truncate all incoming frames but look at some of the
+ // control fields. Otherwise I'll try and make this segment fit into
+ // the window.
+ if (RcvTCB->tcb_rcvwin != 0) {
+ int StateSize; // Size, including state info.
+ SeqNum LastValidSeq; // Sequence number of last valid
+ // byte at RWE.
+
+ // We are offering a window. If this segment starts in front of my
+ // receive window, clip off the front part.
+#if 1 // Bug #63900
+ //Check for the sanity of received sequence.
+ //This is to fix the 1 bit error(MSB) case in the rcv seq.
+ // Also, check the incoming size.
+
+
+ if ((SEQ_LT(RcvInfo.tri_seq, RcvTCB->tcb_rcvnext)) &&
+ ((int)Size >= 0) &&
+ (RcvTCB->tcb_rcvnext - RcvInfo.tri_seq ) > 0) {
+
+#else
+
+ if (SEQ_LT(RcvInfo.tri_seq, RcvTCB->tcb_rcvnext)) {
+#endif
+
+ int AmountToClip, FinByte;
+
+ if (RcvInfo.tri_flags & TCP_FLAG_SYN) {
+ // Had a SYN. Clip it off and update the sequence number.
+ RcvInfo.tri_flags &= ~TCP_FLAG_SYN;
+ RcvInfo.tri_seq++;
+ RcvInfo.tri_urgent--;
+ }
+
+ // Advance the receive buffer to point at the new data.
+ AmountToClip = RcvTCB->tcb_rcvnext - RcvInfo.tri_seq;
+ CTEAssert(AmountToClip >= 0);
+
+ // If there's a FIN on this segment, we'll need to account for
+ // it.
+ FinByte = ((RcvInfo.tri_flags & TCP_FLAG_FIN) ? 1: 0);
+
+ if (AmountToClip >= (((int) Size) + FinByte)) {
+ // Falls entirely before the window. We have more special
+ // case code here - if the ack. number acks something,
+ // we'll go ahead and take it, faking the sequence number
+ // to be rcvnext. This prevents problems on full duplex
+ // connections, where data has been received but not acked,
+ // and retransmission timers reset the seq. number to
+ // below our rcvnext.
+ if ((RcvInfo.tri_flags & TCP_FLAG_ACK) &&
+ SEQ_LT(RcvTCB->tcb_senduna, RcvInfo.tri_ack) &&
+ SEQ_LTE(RcvInfo.tri_ack, RcvTCB->tcb_sendmax)) {
+ // This contains valid ACK info. Fudge the information
+ // to get through the rest of this.
+ Size = 0;
+ AmountToClip = 0;
+ RcvInfo.tri_seq = RcvTCB->tcb_rcvnext;
+ RcvInfo.tri_flags &= ~(TCP_FLAG_SYN | TCP_FLAG_FIN |
+ TCP_FLAG_RST | TCP_FLAG_URG);
+#ifdef DEBUG
+ FinByte = 1; // Fake out assert below.
+#endif
+ } else {
+ ACKAndDrop(&RcvInfo, RcvTCB);
+ return IP_SUCCESS;
+ }
+ }
+
+ // Trim what we have to. If we can't trim enough, the frame
+ // is too short. This shouldn't happen, but it it does we'll
+ // drop the frame.
+ Size -= AmountToClip;
+ RcvInfo.tri_seq += AmountToClip;
+ RcvInfo.tri_urgent -= AmountToClip;
+ RcvBuf = TrimRcvBuf(RcvBuf, AmountToClip);
+ CTEAssert(RcvBuf != NULL);
+ CTEAssert(RcvBuf->ipr_size != 0 ||
+ (Size == 0 && FinByte));
+
+ if (*(int *)&RcvInfo.tri_urgent < 0) {
+ RcvInfo.tri_urgent = 0;
+ RcvInfo.tri_flags &= ~TCP_FLAG_URG;
+ }
+
+ }
+
+ // We've made sure the front is OK. Now make sure part of it doesn't
+ // fall outside of the right edge of the window. If it does,
+ // we'll truncate the frame (removing the FIN, if any). If we
+ // truncate the whole frame we'll ACKAndDrop it.
+ StateSize = Size + ((RcvInfo.tri_flags & TCP_FLAG_SYN) ? 1: 0) +
+ ((RcvInfo.tri_flags & TCP_FLAG_FIN) ? 1: 0);
+
+ if (StateSize)
+ StateSize--;
+
+ // Now the incoming sequence number (RcvInfo.tri_seq) + StateSize
+ // it the last sequence number in the segment. If this is greater
+ // than the last valid byte in the window, we have some overlap
+ // to chop off.
+
+ CTEAssert(StateSize >= 0);
+ LastValidSeq = RcvTCB->tcb_rcvnext + RcvTCB->tcb_rcvwin - 1;
+ if (SEQ_GT(RcvInfo.tri_seq + StateSize, LastValidSeq)) {
+ int AmountToChop;
+
+ // At least some part of the frame is outside of our window.
+ // See if it starts outside our window.
+
+ if (SEQ_GT(RcvInfo.tri_seq, LastValidSeq)) {
+ // Falls entirely outside the window. We have special
+ // case code to deal with a pure ack that falls exactly at
+ // our right window edge. Otherwise we ack and drop it.
+ if (!SEQ_EQ(RcvInfo.tri_seq, LastValidSeq+1) || Size != 0
+ || (RcvInfo.tri_flags & (TCP_FLAG_SYN | TCP_FLAG_FIN))) {
+ ACKAndDrop(&RcvInfo, RcvTCB);
+ return IP_SUCCESS;
+ }
+ } else {
+
+ // At least some part of it is in the window. If there's a
+ // FIN, chop that off and see if that moves us inside.
+ if (RcvInfo.tri_flags & TCP_FLAG_FIN) {
+ RcvInfo.tri_flags &= ~TCP_FLAG_FIN;
+ StateSize--;
+ }
+
+ // Now figure out how much to chop off.
+ AmountToChop = (RcvInfo.tri_seq + StateSize) - LastValidSeq;
+ CTEAssert(AmountToChop >= 0);
+ Size -= AmountToChop;
+
+ }
+ }
+ } else {
+ if (!SEQ_EQ(RcvTCB->tcb_rcvnext, RcvInfo.tri_seq)) {
+
+ // If there's a RST on this segment, and he's only off by 1,
+ // take it anyway. This can happen if the remote peer is
+ // probing and sends with the seq. # after the probe.
+ if (!(RcvInfo.tri_flags & TCP_FLAG_RST) ||
+ !(SEQ_EQ(RcvTCB->tcb_rcvnext, (RcvInfo.tri_seq - 1)))) {
+ ACKAndDrop(&RcvInfo, RcvTCB);
+ return IP_SUCCESS;
+ } else
+ RcvInfo.tri_seq = RcvTCB->tcb_rcvnext;
+ }
+
+ // He's in sequence, but we have a window of 0. Truncate the
+ // size, and clear any sequence consuming bits.
+ if (Size != 0 ||
+ (RcvInfo.tri_flags & (TCP_FLAG_SYN | TCP_FLAG_FIN))) {
+ RcvInfo.tri_flags &= ~(TCP_FLAG_SYN | TCP_FLAG_FIN);
+ Size = 0;
+ if (!(RcvInfo.tri_flags & TCP_FLAG_RST))
+ DelayAction(RcvTCB, NEED_ACK);
+ }
+ }
+
+ // At this point, the segment is in our window and does not overlap
+ // on either end. If it's the next sequence number we expect, we can
+ // handle the data now. Otherwise we'll queue it for later. In either
+ // case we'll handle RST and ACK information right now.
+ CTEAssert((*(int *)&Size) >= 0);
+
+ // Now, following 793, we check the RST bit.
+ if (RcvInfo.tri_flags & TCP_FLAG_RST) {
+ uchar Reason;
+ // We can't go back into the LISTEN state from SYN-RCVD here,
+ // because we may have notified the client via a listen completing
+ // or a connect indication. So, if came from an active open we'll
+ // give back a 'connection refused' notice. For all other cases
+ // we'll just destroy the connection.
+
+ if (RcvTCB->tcb_state == TCB_SYN_RCVD) {
+ if (RcvTCB->tcb_flags & ACTIVE_OPEN)
+ Reason = TCB_CLOSE_REFUSED;
+ else
+ Reason = TCB_CLOSE_RST;
+ } else
+ Reason = TCB_CLOSE_RST;
+
+ TryToCloseTCB(RcvTCB, Reason, TableHandle);
+ CTEGetLockAtDPC(&RcvTCB->tcb_lock, &TableHandle);
+
+ if (RcvTCB->tcb_state != TCB_TIME_WAIT) {
+ CTEFreeLockFromDPC(&RcvTCB->tcb_lock, TableHandle);
+ RemoveTCBFromConn(RcvTCB);
+ NotifyOfDisc(RcvTCB, OptInfo, TDI_CONNECTION_RESET);
+ CTEGetLockAtDPC(&RcvTCB->tcb_lock, &TableHandle);
+ }
+
+ DerefTCB(RcvTCB, TableHandle);
+ return IP_SUCCESS;
+ }
+
+ // Next check the SYN bit.
+ if (RcvInfo.tri_flags & TCP_FLAG_SYN) {
+ // Again, we can't quietly go back into the LISTEN state here, even
+ // if we came from a passive open.
+ TryToCloseTCB(RcvTCB, TCB_CLOSE_ABORTED, TableHandle);
+ SendRSTFromHeader(TCPH, Size, Src, Dest, OptInfo);
+
+ CTEGetLockAtDPC(&RcvTCB->tcb_lock, &TableHandle);
+
+ if (RcvTCB->tcb_state != TCB_TIME_WAIT) {
+ CTEFreeLockFromDPC(&RcvTCB->tcb_lock, TableHandle);
+ RemoveTCBFromConn(RcvTCB);
+ NotifyOfDisc(RcvTCB, OptInfo, TDI_CONNECTION_RESET);
+ CTEGetLockAtDPC(&RcvTCB->tcb_lock, &TableHandle);
+ }
+
+ DerefTCB(RcvTCB, TableHandle);
+ return IP_SUCCESS;
+ }
+
+ // Check the ACK field. If it's not on drop the segment.
+ if (RcvInfo.tri_flags & TCP_FLAG_ACK) {
+ uint UpdateWindow;
+
+ // If we're in SYN-RCVD, go to ESTABLISHED.
+ if (RcvTCB->tcb_state == TCB_SYN_RCVD) {
+ if (SEQ_LT(RcvTCB->tcb_senduna, RcvInfo.tri_ack) &&
+ SEQ_LTE(RcvInfo.tri_ack, RcvTCB->tcb_sendmax)) {
+ // The ack is valid.
+
+#ifdef SYN_ATTACK
+ if (SynAttackProtect) {
+ CTELockHandle Handle;
+
+ //
+ // We will be reiniting the tcprexmitcnt to 0. If we are
+ // configured for syn-attack protection and the rexmit cnt
+ // is >1, decrement the count of connections that are
+ // in the half-open-retried state. Check whether we are
+ // below a low-watermark. If we are, increase the rexmit
+ // count back to configured values
+ //
+ CTEGetLockAtDPC(&SynAttLock, &Handle);
+ if (RcvTCB->tcb_rexmitcnt >= ADAPTED_MAX_CONNECT_RESPONSE_REXMIT_CNT) {
+ BOOLEAN Trigger;
+ Trigger = (TCPHalfOpen < TCPMaxHalfOpen) ||
+ (--TCPHalfOpenRetried <= TCPMaxHalfOpenRetriedLW);
+ if (Trigger && (MaxConnectResponseRexmitCountTmp == ADAPTED_MAX_CONNECT_RESPONSE_REXMIT_CNT))
+ {
+ MaxConnectResponseRexmitCountTmp = MAX_CONNECT_RESPONSE_REXMIT_CNT;
+ }
+
+ }
+ //
+ // Decrement the # of conn. in half open state
+ //
+ TCPHalfOpen--;
+ CTEFreeLockFromDPC(&SynAttLock, Handle);
+ }
+#endif
+ RcvTCB->tcb_rexmitcnt = 0;
+ STOP_TCB_TIMER(RcvTCB->tcb_rexmittimer);
+ RcvTCB->tcb_senduna++;
+ RcvTCB->tcb_sendwin = RcvInfo.tri_window;
+ RcvTCB->tcb_maxwin = RcvInfo.tri_window;
+ RcvTCB->tcb_sendwl1 = RcvInfo.tri_seq;
+ RcvTCB->tcb_sendwl2 = RcvInfo.tri_ack;
+ GoToEstab(RcvTCB);
+
+ // Now complete whatever we can here.
+ CompleteConnReq(RcvTCB, OptInfo, TDI_SUCCESS);
+ } else {
+ DerefTCB(RcvTCB, TableHandle);
+ SendRSTFromHeader(TCPH, Size, Src, Dest, OptInfo);
+ return IP_SUCCESS;
+ }
+ } else {
+
+ // We're not in SYN-RCVD. See if this acknowledges anything.
+ if (SEQ_LT(RcvTCB->tcb_senduna, RcvInfo.tri_ack) &&
+ SEQ_LTE(RcvInfo.tri_ack, RcvTCB->tcb_sendmax)) {
+ uint CWin;
+
+ // The ack acknowledes something. Pull the
+ // appropriate amount off the send q.
+ ACKData(RcvTCB, RcvInfo.tri_ack);
+
+ // If this acknowledges something we were running a RTT on,
+ // update that stuff now.
+ if (RcvTCB->tcb_rtt != 0 && SEQ_GT(RcvInfo.tri_ack,
+ RcvTCB->tcb_rttseq)) {
+ short RTT;
+
+ RTT = (short)(TCPTime - RcvTCB->tcb_rtt);
+ RcvTCB->tcb_rtt = 0;
+ RTT -= (RcvTCB->tcb_smrtt >> 3);
+ RcvTCB->tcb_smrtt += RTT;
+ RTT = (RTT >= 0 ? RTT : -RTT);
+ RTT -= (RcvTCB->tcb_delta >> 3);
+ RcvTCB->tcb_delta += RTT;
+ RcvTCB->tcb_rexmit = MIN(MAX(REXMIT_TO(RcvTCB),
+ MIN_RETRAN_TICKS), MAX_REXMIT_TO);
+ }
+
+ // If we're probing for a PMTU black hole we've found one, so turn off
+ // the detection. The size is already down, so leave it there.
+ if (RcvTCB->tcb_flags & PMTU_BH_PROBE) {
+ RcvTCB->tcb_flags &= ~PMTU_BH_PROBE;
+ RcvTCB->tcb_bhprobecnt = 0;
+ if (--(RcvTCB->tcb_slowcount) == 0) {
+ RcvTCB->tcb_fastchk &= ~TCP_FLAG_SLOW;
+ CheckTCBRcv(RcvTCB);
+ }
+ }
+
+ // Update the congestion window now.
+ CWin = RcvTCB->tcb_cwin;
+ if (CWin < RcvTCB->tcb_maxwin) {
+ if (CWin < RcvTCB->tcb_ssthresh)
+ CWin += RcvTCB->tcb_mss;
+ else
+ CWin += (RcvTCB->tcb_mss * RcvTCB->tcb_mss)/CWin;
+
+ RcvTCB->tcb_cwin = MIN(CWin, RcvTCB->tcb_maxwin);
+ }
+
+ CTEAssert(*(int *)&RcvTCB->tcb_cwin > 0);
+
+ // We've acknowledged something, so reset the rexmit count.
+ // If there's still stuff outstanding, restart the rexmit
+ // timer.
+ RcvTCB->tcb_rexmitcnt = 0;
+ if (!SEQ_EQ(RcvInfo.tri_ack, RcvTCB->tcb_sendmax))
+ START_TCB_TIMER(RcvTCB->tcb_rexmittimer,
+ RcvTCB->tcb_rexmit);
+ else
+ STOP_TCB_TIMER(RcvTCB->tcb_rexmittimer);
+
+ // If we've sent a FIN, and this acknowledges it, we
+ // need to complete the client's close request and
+ // possibly transition our state.
+
+ if (RcvTCB->tcb_flags & FIN_SENT) {
+ // We have sent a FIN. See if it's been acknowledged.
+ // Once we've sent a FIN, tcb_sendmax
+ // can't advance, so our FIN must have seq. number
+ // tcb_sendmax - 1. Thus our FIN is acknowledged
+ // if the incoming ack is equal to tcb_sendmax.
+ if (SEQ_EQ(RcvInfo.tri_ack, RcvTCB->tcb_sendmax)) {
+ // He's acked our FIN. Turn off the flags,
+ // and complete the request. We'll leave the
+ // FIN_OUTSTANDING flag alone, to force early
+ // outs in the send code.
+ RcvTCB->tcb_flags &= ~(FIN_NEEDED | FIN_SENT);
+
+ CTEAssert(RcvTCB->tcb_unacked == 0);
+ CTEAssert(RcvTCB->tcb_sendnext ==
+ RcvTCB->tcb_sendmax);
+
+ // Now figure out what we need to do. In FIN_WAIT1
+ // or FIN_WAIT, just complete the disconnect req.
+ // and continue. Otherwise, it's a bit trickier,
+ // since we can't complete the connreq until we
+ // remove the TCB from it's connection.
+ switch (RcvTCB->tcb_state) {
+
+ case TCB_FIN_WAIT1:
+ RcvTCB->tcb_state = TCB_FIN_WAIT2;
+ CompleteConnReq(RcvTCB, OptInfo,
+ TDI_SUCCESS);
+
+ // Start a timer in case we never get
+ // out of FIN_WAIT2. Set the retransmit
+ // count high to force a timeout the
+ // first time the timer fires.
+ RcvTCB->tcb_rexmitcnt = MaxDataRexmitCount;
+ START_TCB_TIMER(RcvTCB->tcb_rexmittimer,
+ FinWait2TO);
+
+ // Fall through to FIN-WAIT-2 processing.
+ case TCB_FIN_WAIT2:
+ break;
+ case TCB_CLOSING:
+ GracefulClose(RcvTCB, TRUE, FALSE,
+ TableHandle);
+ return IP_SUCCESS;
+ break;
+ case TCB_LAST_ACK:
+ GracefulClose(RcvTCB, FALSE, FALSE,
+ TableHandle);
+ return IP_SUCCESS;
+ break;
+ default:
+ DEBUGCHK;
+ break;
+ }
+ }
+
+ }
+ UpdateWindow = TRUE;
+ } else {
+ // It doesn't ack anything. If it's an ack for something
+ // larger than we've sent then ACKAndDrop it, otherwise
+ // ignore it. If we're in FIN_WAIT2, we'll restart the timer.
+ // We don't make this check above because we know no
+ // data can be acked when we're in FIN_WAIT2.
+
+ if (RcvTCB->tcb_state == TCB_FIN_WAIT2)
+ START_TCB_TIMER(RcvTCB->tcb_rexmittimer, FinWait2TO);
+
+ if (SEQ_GT(RcvInfo.tri_ack, RcvTCB->tcb_sendmax)) {
+ ACKAndDrop(&RcvInfo, RcvTCB);
+ return IP_SUCCESS;
+ } else {
+ // Now update the window if we can.
+ if (SEQ_EQ(RcvTCB->tcb_senduna, RcvInfo.tri_ack) &&
+ (SEQ_LT(RcvTCB->tcb_sendwl1, RcvInfo.tri_seq) ||
+ (SEQ_EQ(RcvTCB->tcb_sendwl1, RcvInfo.tri_seq) &&
+ SEQ_LTE(RcvTCB->tcb_sendwl2, RcvInfo.tri_ack)))) {
+ UpdateWindow = TRUE;
+ } else
+ UpdateWindow = FALSE;
+ }
+ }
+
+ if (UpdateWindow) {
+ RcvTCB->tcb_sendwin = RcvInfo.tri_window;
+ RcvTCB->tcb_maxwin = MAX(RcvTCB->tcb_maxwin,
+ RcvInfo.tri_window);
+ RcvTCB->tcb_sendwl1 = RcvInfo.tri_seq;
+ RcvTCB->tcb_sendwl2 = RcvInfo.tri_ack;
+ if (RcvInfo.tri_window == 0) {
+ // We've got a zero window.
+ if (!EMPTYQ(&RcvTCB->tcb_sendq)) {
+ RcvTCB->tcb_flags &= ~NEED_OUTPUT;
+ RcvTCB->tcb_rexmitcnt = 0;
+ START_TCB_TIMER(RcvTCB->tcb_rexmittimer,
+ RcvTCB->tcb_rexmit);
+ if (!(RcvTCB->tcb_flags & FLOW_CNTLD)) {
+ RcvTCB->tcb_flags |= FLOW_CNTLD;
+ RcvTCB->tcb_slowcount++;
+ RcvTCB->tcb_fastchk |= TCP_FLAG_SLOW;
+ CheckTCBRcv(RcvTCB);
+ }
+ }
+ } else {
+ if (RcvTCB->tcb_flags & FLOW_CNTLD) {
+ RcvTCB->tcb_rexmitcnt = 0;
+ RcvTCB->tcb_rexmit = MIN(MAX(REXMIT_TO(RcvTCB),
+ MIN_RETRAN_TICKS), MAX_REXMIT_TO);
+ if (TCB_TIMER_RUNNING(RcvTCB->tcb_rexmittimer)) {
+ START_TCB_TIMER(RcvTCB->tcb_rexmittimer,
+ RcvTCB->tcb_rexmit);
+ }
+ RcvTCB->tcb_flags &= ~(FLOW_CNTLD | FORCE_OUTPUT);
+ // Reset send next to the left edge of the window,
+ // because it might be at senduna+1 if we've been
+ // probing.
+ ResetSendNext(RcvTCB, RcvTCB->tcb_senduna);
+ if (--(RcvTCB->tcb_slowcount) == 0) {
+ RcvTCB->tcb_fastchk &= ~TCP_FLAG_SLOW;
+ CheckTCBRcv(RcvTCB);
+ }
+ }
+
+ // Since we've updated the window, see if we can send
+ // some more.
+ if (RcvTCB->tcb_unacked != 0 ||
+ (RcvTCB->tcb_flags & FIN_NEEDED))
+ DelayAction(RcvTCB, NEED_OUTPUT);
+
+ }
+ }
+
+ }
+
+ // We've handled all the acknowledgment stuff. If the size
+ // is greater than 0 or important bits are set process it further,
+ // otherwise it's a pure ack and we're done with it.
+ if (Size > 0 || (RcvInfo.tri_flags & TCP_FLAG_FIN)) {
+
+ // If we're not in a state where we can process incoming data
+ // or FINs, there's no point in going further. Just send an
+ // ack and drop this segment.
+ if (!DATA_RCV_STATE(RcvTCB->tcb_state) ||
+ (RcvTCB->tcb_flags & GC_PENDING)) {
+ ACKAndDrop(&RcvInfo, RcvTCB);
+ return IP_SUCCESS;
+ }
+
+ // If it's in sequence process it now, otherwise reassemble it.
+ if (SEQ_EQ(RcvInfo.tri_seq, RcvTCB->tcb_rcvnext)) {
+
+ // If we're already in the recv. handler, this is a
+ // duplicate. We'll just toss it.
+ if (RcvTCB->tcb_fastchk & TCP_FLAG_IN_RCV) {
+ DerefTCB(RcvTCB, TableHandle);
+ return IP_SUCCESS;
+ }
+
+ RcvTCB->tcb_fastchk |= TCP_FLAG_IN_RCV;
+
+ // Now loop, pulling things from the reassembly queue, until
+ // the queue is empty, or we can't take all of the data,
+ // or we hit a FIN.
+
+ do {
+
+ // Handle urgent data, if any.
+ if (RcvInfo.tri_flags & TCP_FLAG_URG) {
+ HandleUrgent(RcvTCB, &RcvInfo, RcvBuf, &Size);
+
+ // Since we may have freed the lock, we need to recheck
+ // and see if we're closing here.
+ if (CLOSING(RcvTCB))
+ break;
+
+ }
+
+
+ // OK, the data is in sequence, we've updated the
+ // reassembly queue and handled any urgent data. If we
+ // have any data go ahead and process it now.
+ if (Size > 0) {
+
+#ifdef VXD
+ CTEFreeLock(&RcvTCB->tcb_lock, TableHandle);
+ BytesTaken = (*RcvTCB->tcb_rcvhndlr)(RcvTCB,
+ RcvInfo.tri_flags, RcvBuf, Size);
+ CTEGetLock(&RcvTCB->tcb_lock, &TableHandle);
+#else
+ BytesTaken = (*RcvTCB->tcb_rcvhndlr)(RcvTCB,
+ RcvInfo.tri_flags, RcvBuf, Size);
+#endif
+ RcvTCB->tcb_rcvnext += BytesTaken;
+ RcvTCB->tcb_rcvwin -= BytesTaken;
+
+ CheckTCBRcv(RcvTCB);
+ if (RcvTCB->tcb_flags & ACK_DELAYED)
+ DelayAction(RcvTCB, NEED_ACK);
+ else {
+ RcvTCB->tcb_flags |= ACK_DELAYED;
+ START_TCB_TIMER(RcvTCB->tcb_delacktimer,
+ DEL_ACK_TICKS);
+ }
+
+ if (BytesTaken != Size) {
+ // We didn't take everything we could. No
+ // use in further processing, just bail
+ // out.
+ DelayAction(RcvTCB, NEED_ACK);
+ break;
+ }
+
+ // If we're closing now, we're done, so get out.
+ if (CLOSING(RcvTCB))
+ break;
+ }
+
+ // See if we need to advance over some urgent data.
+ if (RcvTCB->tcb_flags & URG_VALID) {
+ uint AdvanceNeeded;
+
+ // We only need to advance if we're not doing
+ // urgent inline. Urgent inline also has some
+ // implications for when we can clear the URG_VALID
+ // flag. If we're not doing urgent inline, we can
+ // clear it when rcvnext advances beyond urgent end.
+ // If we are doing inline, we clear it when rcvnext
+ // advances one receive window beyond urgend.
+ if (!(RcvTCB->tcb_flags & URG_INLINE)) {
+ if (RcvTCB->tcb_rcvnext == RcvTCB->tcb_urgstart)
+ RcvTCB->tcb_rcvnext = RcvTCB->tcb_urgend +
+ 1;
+ else
+ CTEAssert(SEQ_LT(RcvTCB->tcb_rcvnext,
+ RcvTCB->tcb_urgstart) ||
+ SEQ_GT(RcvTCB->tcb_rcvnext,
+ RcvTCB->tcb_urgend));
+ AdvanceNeeded = 0;
+ } else
+ AdvanceNeeded = RcvTCB->tcb_defaultwin;
+
+ // See if we can clear the URG_VALID flag.
+ if (SEQ_GT(RcvTCB->tcb_rcvnext - AdvanceNeeded,
+ RcvTCB->tcb_urgend)) {
+ RcvTCB->tcb_flags &= ~URG_VALID;
+ if (--(RcvTCB->tcb_slowcount) == 0) {
+ RcvTCB->tcb_fastchk &= ~TCP_FLAG_SLOW;
+ CheckTCBRcv(RcvTCB);
+ }
+ }
+
+ }
+
+ // We've handled the data. If the FIN bit is set, we
+ // have more processing.
+ if (RcvInfo.tri_flags & TCP_FLAG_FIN) {
+ uint Notify = FALSE;
+
+ RcvTCB->tcb_rcvnext++;
+ DelayAction(RcvTCB, NEED_ACK);
+
+ PushData(RcvTCB);
+
+ switch (RcvTCB->tcb_state) {
+
+ case TCB_SYN_RCVD:
+ // I don't think we can get here - we
+ // should have discarded the frame if it
+ // had no ACK, or gone to established if
+ // it did.
+ DEBUGCHK;
+ case TCB_ESTAB:
+ RcvTCB->tcb_state = TCB_CLOSE_WAIT;
+ // We left established, we're off the
+ // fast path.
+ RcvTCB->tcb_slowcount++;
+ RcvTCB->tcb_fastchk |= TCP_FLAG_SLOW;
+ CheckTCBRcv(RcvTCB);
+ Notify = TRUE;
+ break;
+ case TCB_FIN_WAIT1:
+ RcvTCB->tcb_state = TCB_CLOSING;
+ Notify = TRUE;
+ break;
+ case TCB_FIN_WAIT2:
+ // Stop the FIN_WAIT2 timer.
+ STOP_TCB_TIMER(RcvTCB->tcb_rexmittimer);
+ RcvTCB->tcb_refcnt++;
+ GracefulClose(RcvTCB, TRUE, TRUE,
+ TableHandle);
+ CTEGetLockAtDPC(&RcvTCB->tcb_lock,
+ &TableHandle);
+ break;
+ default:
+ DEBUGCHK;
+ break;
+ }
+
+ if (Notify) {
+ CTEFreeLockFromDPC(&RcvTCB->tcb_lock,
+ TableHandle);
+ NotifyOfDisc(RcvTCB, OptInfo, TDI_GRACEFUL_DISC);
+ CTEGetLockAtDPC(&RcvTCB->tcb_lock,
+ &TableHandle);
+ }
+
+ break; // Exit out of WHILE loop.
+ }
+
+ // If the reassembly queue isn't empty, get what we
+ // can now.
+ RcvBuf = PullFromRAQ(RcvTCB, &RcvInfo, &Size);
+
+ CheckRBList(RcvBuf, Size);
+
+ } while (RcvBuf != NULL);
+
+ RcvTCB->tcb_fastchk &= ~TCP_FLAG_IN_RCV;
+ if (RcvTCB->tcb_flags & SEND_AFTER_RCV) {
+ RcvTCB->tcb_flags &= ~SEND_AFTER_RCV;
+ DelayAction(RcvTCB, NEED_OUTPUT);
+ }
+
+ DerefTCB(RcvTCB, TableHandle);
+ return IP_SUCCESS;
+
+ } else {
+
+ // It's not in sequence. Since it needs further processing,
+ // put in on the reassembly queue.
+ if (DATA_RCV_STATE(RcvTCB->tcb_state) &&
+ !(RcvTCB->tcb_flags & GC_PENDING)) {
+ PutOnRAQ(RcvTCB, &RcvInfo, RcvBuf, Size);
+ CTEFreeLockFromDPC(&RcvTCB->tcb_lock, TableHandle);
+ SendACK(RcvTCB);
+ CTEGetLockAtDPC(&RcvTCB->tcb_lock, &TableHandle);
+ DerefTCB(RcvTCB, TableHandle);
+ } else
+ ACKAndDrop(&RcvInfo, RcvTCB);
+
+ return IP_SUCCESS;
+ }
+ }
+
+ } else {
+ // No ACK. Just drop the segment and return.
+ DerefTCB(RcvTCB, TableHandle);
+ return IP_SUCCESS;
+ }
+
+ DerefTCB(RcvTCB, TableHandle);
+ } else // DataOffset <= Size
+ TStats.ts_inerrs++;
+ } else {
+ // Bump bad xsum counter.
+ TStats.ts_inerrs++;
+
+ }
+
+ } else // IsBCast
+ TStats.ts_inerrs++;
+
+
+ return IP_SUCCESS;
+
+}
+
+#pragma BEGIN_INIT
+
+//* InitTCPRcv - Initialize TCP receive side.
+//
+// Called during init time to initialize our TCP receive side.
+//
+// Input: Nothing.
+//
+// Returns: TRUE.
+//
+int
+InitTCPRcv(void)
+{
+#ifdef NT
+ ExInitializeSListHead(&TCPRcvReqFree);
+#endif
+
+ CTEInitLock(&RequestCompleteLock);
+ CTEInitLock(&TCBDelayLock);
+ CTEInitLock(&TCPRcvReqFreeLock);
+ INITQ(&ConnRequestCompleteQ);
+ INITQ(&SendCompleteQ);
+ INITQ(&TCBDelayQ);
+ RequestCompleteFlags = 0;
+ TCBDelayRtnCount = 0;
+
+#ifdef VXD
+ TCBDelayRtnLimit = 1;
+#endif
+#ifdef NT
+ TCBDelayRtnLimit = (uint) (** (PCHAR *) &KeNumberProcessors);
+ if (TCBDelayRtnLimit > TCB_DELAY_RTN_LIMIT)
+ TCBDelayRtnLimit = TCB_DELAY_RTN_LIMIT;
+#endif
+
+ DummyBuf.ipr_owner = IPR_OWNER_IP;
+ DummyBuf.ipr_size = 0;
+ DummyBuf.ipr_next = 0;
+ DummyBuf.ipr_buffer = NULL;
+ return TRUE;
+}
+
+//* UnInitTCPRcv - Uninitialize our receive side.
+//
+// Called if initialization fails to uninitialize our receive side.
+//
+//
+// Input: Nothing.
+//
+// Returns: Nothing.
+//
+void
+UnInitTCPRcv(void)
+{
+
+}
+
+
+#pragma END_INIT
+
+
diff --git a/private/ntos/tdi/tcpip/tcp/tcprcv.h b/private/ntos/tdi/tcpip/tcp/tcprcv.h
new file mode 100644
index 000000000..629eb5cf8
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/tcprcv.h
@@ -0,0 +1,74 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** TCPRCV.H - TCP receive protocol definitions.
+//
+// This file contains the definitions for structures used by the receive code.
+//
+
+#define CONN_REQUEST_COMPLETE 0x01
+#define SEND_REQUEST_COMPLETE 0x02
+
+#define IN_RCV_COMPLETE 0x10
+#define ANY_REQUEST_COMPLETE (CONN_REQUEST_COMPLETE | SEND_REQUEST_COMPLETE)
+
+#define trh_signature 0x20485254 // 'TRH '
+
+typedef struct TCPRAHdr {
+#ifdef DEBUG
+ ulong trh_sig; // Signature.
+#endif
+ struct TCPRAHdr *trh_next; // Next pointer.
+ SeqNum trh_start; // First sequence number.
+ uint trh_size; // Size in bytes of data in this TRH.
+ uint trh_flags; // Flags for this segment.
+ uint trh_urg; // Urgent pointer from this seg.
+ IPRcvBuf *trh_buffer; // Head of buffer list for this TRH.
+ IPRcvBuf *trh_end; // End of buffer list for this TRH.
+
+} TCPRAHdr;
+
+//* Structure of a TCP receive request.
+
+#define trr_signature 0x20525254 // 'TRR '
+
+typedef struct TCPRcvReq {
+#ifdef DEBUG
+ ulong trr_sig; // Signature.
+#endif
+ struct TCPRcvReq *trr_next; // Next in chain.
+ CTEReqCmpltRtn trr_rtn; // Completion routine.
+ PVOID trr_context; // User context.
+ uint trr_amt; // Number of bytes currently in buffer.
+ uint trr_offset; // Offset into first buffer on chain
+ // at which to start copying.
+ uint trr_flags; // Flags for this recv.
+ ushort *trr_uflags; // Pointer to user specifed flags.
+ uint trr_size; // Total size of buffer chain.
+ PNDIS_BUFFER trr_buffer; // Pointer to useable NDIS buffer chain.
+} TCPRcvReq;
+
+#define TRR_PUSHED 0x80000000 // This buffer has been pushed.
+
+
+extern uint RequestCompleteFlags;
+
+extern Queue SendCompleteQ;
+extern Queue TCBDelayQ;
+
+EXTERNAL_LOCK(RequestCompleteLock)
+EXTERNAL_LOCK(TCBDelayLock)
+
+extern void TCPRcvComplete(void);
+extern void FreeRBChain(IPRcvBuf *RBChain);
+
+extern void DelayAction(struct TCB *DelayTCB, uint Action);
+extern void ProcessTCBDelayQ(void);
+extern void AdjustRcvWin(struct TCB *WinTCB);
+
+
+
+
diff --git a/private/ntos/tdi/tcpip/tcp/tcpsend.c b/private/ntos/tdi/tcpip/tcp/tcpsend.c
new file mode 100644
index 000000000..6c97e9f8a
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/tcpsend.c
@@ -0,0 +1,2666 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** TCPSEND.C - TCP send protocol code.
+//
+// This file contains the code for sending Data and Control segments.
+//
+
+#include "oscfg.h"
+#include "ndis.h"
+#include "cxport.h"
+#include "ip.h"
+#include "tdi.h"
+#ifdef VXD
+#include "tdivxd.h"
+#include "tdistat.h"
+#endif
+#ifdef NT
+#include "tdint.h"
+#include "tdistat.h"
+#endif
+#include "queue.h"
+#include "addr.h"
+#include "tcp.h"
+#include "tcb.h"
+#include "tcpconn.h"
+#include "tcpsend.h"
+#include "tcprcv.h"
+#include "tlcommon.h"
+#include "info.h"
+#include "tcpcfg.h"
+#include "secfltr.h"
+
+#if FAST_RETRANSMIT
+void
+TCPFastSend(TCB *SendTCB,
+ PNDIS_BUFFER in_SendBuf,
+ uint in_SendOfs,
+ TCPSendReq *in_SendReq,
+ uint in_SendSize);
+#endif
+
+
+
+#ifdef NT
+SLIST_HEADER TCPSendFree;
+#else
+PNDIS_BUFFER TCPSendFree;
+#endif
+
+DEFINE_LOCK_STRUCTURE(TCPSendFreeLock);
+
+ulong TCPCurrentSendFree;
+ulong TCPMaxSendFree = TCP_MAX_HDRS;
+
+void *TCPProtInfo; // TCP protocol info for IP.
+
+#ifdef NT
+SLIST_HEADER TCPSendReqFree; // Send req. free list.
+#else
+TCPSendReq *TCPSendReqFree; // Send req. free list.
+#endif
+
+DEFINE_LOCK_STRUCTURE(TCPSendReqFreeLock);
+DEFINE_LOCK_STRUCTURE(TCPSendReqCompleteLock);
+uint NumTCPSendReq; // Current number of SendReqs in system.
+uint MaxSendReq = 0xffffffff; // Maximum allowed number of SendReqs.
+
+
+NDIS_HANDLE TCPSendBufferPool;
+
+typedef struct TCPHdrBPoolEntry {
+ struct TCPHdrBPoolEntry *the_next;
+ NDIS_HANDLE the_handle;
+ uchar *the_buffer;
+} TCPHdrBPoolEntry;
+
+TCPHdrBPoolEntry *TCPHdrBPoolList;
+
+extern IPInfo LocalNetInfo;
+
+#ifdef CHICAGO
+extern uchar TransportName[];
+#endif // CHICAGO
+
+EXTERNAL_LOCK(TCBTableLock)
+
+//
+// All of the init code can be discarded.
+//
+#ifdef NT
+
+int InitTCPSend(void);
+void UnInitTCPSend(void);
+
+#ifdef ALLOC_PRAGMA
+
+#pragma alloc_text(INIT, InitTCPSend)
+#pragma alloc_text(INIT, UnInitTCPSend)
+
+#endif // ALLOC_PRAGMA
+#endif
+
+#ifdef CHICAGO
+extern int RegisterAddrChangeHndlr(void *Handler, uint Add);
+extern void AddrChange(IPAddr Addr, IPMask Mask, void *Context,
+ uint Added);
+#endif
+
+extern void ResetSendNext(TCB *SeqTCB, SeqNum NewSeq);
+
+
+//* GrowTCPHeaderList - Try to grow the tcp header list.
+//
+// Called when we run out of buffers on the TCP header list, and need
+// to grow it. We look to see if we're already at the maximum size, and
+// if not we'll allocate the need structures and free them to the list.
+//
+// Input: Nothing.
+//
+// Returns: A pointer to a new TCP header buffer if we have one, or NULL.
+//
+PNDIS_BUFFER
+GrowTCPHeaderList(void)
+{
+ TCPHdrBPoolEntry *NewEntry;
+ CTELockHandle Handle;
+ NDIS_STATUS Status;
+ uint HeaderSize;
+ uchar *TCPSendHP;
+ uint i;
+ PNDIS_BUFFER Buffer;
+ PNDIS_BUFFER ReturnBuffer;
+
+ CTEGetLock(&TCPSendFreeLock, &Handle);
+
+ if (TCPCurrentSendFree < TCPMaxSendFree) {
+
+ // Still room to grow the list.
+ NewEntry = CTEAllocMem(sizeof(TCPHdrBPoolEntry));
+
+ if (NewEntry == NULL) {
+ // Couldn't get the memory.
+ CTEFreeLock(&TCPSendFreeLock, Handle);
+ return NULL;
+ }
+
+
+ NdisAllocateBufferPool(&Status, &NewEntry->the_handle,
+ NUM_TCP_HEADERS);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ // Couldn't get a new set of buffers. Fail.
+ CTEFreeMem(NewEntry);
+ CTEFreeLock(&TCPSendFreeLock, Handle);
+ return NULL;
+ }
+
+ HeaderSize = sizeof(TCPHeader) +
+ MAX(MSS_OPT_SIZE, sizeof(SendCmpltContext)) +
+ LocalNetInfo.ipi_hsize;
+
+ TCPSendHP = CTEAllocMem(HeaderSize * NUM_TCP_HEADERS);
+
+ if (TCPSendHP == NULL) {
+ NdisFreeBufferPool(NewEntry->the_handle);
+ CTEFreeMem(NewEntry);
+ CTEFreeLock(&TCPSendFreeLock, Handle);
+ return NULL;
+ }
+
+ NewEntry->the_buffer = TCPSendHP;
+ TCPCurrentSendFree += NUM_TCP_HEADERS;
+ NewEntry->the_next = TCPHdrBPoolList;
+ TCPHdrBPoolList = NewEntry;
+ ReturnBuffer = NULL;
+ CTEFreeLock(&TCPSendFreeLock, Handle);
+
+ for (i = 0; i < NUM_TCP_HEADERS; i++) {
+ NdisAllocateBuffer(&Status, &Buffer, NewEntry->the_handle,
+ TCPSendHP + (i * HeaderSize), HeaderSize);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ CTEAssert(FALSE); // This is probably harmless, but check.
+ break;
+ }
+
+ NdisBufferLength(Buffer) = sizeof(TCPHeader);
+
+ if (i != 0)
+ FreeTCPHeader(Buffer);
+ else
+ ReturnBuffer = Buffer;
+ }
+
+ // Update the count with what we didn't allocate, if any.
+ CTEInterlockedAddUlong(&TCPCurrentSendFree, i - NUM_TCP_HEADERS,
+ &TCPSendFreeLock);
+
+ return ReturnBuffer;
+
+ } else {
+ // At the limit already. It's possible someone snuck in and grew
+ // the list before we got to, so check and see if it's still empty.
+#ifdef VXD
+ if (TCPSendFree != NULL) {
+ ReturnBuffer = TCPSendFree;
+ TCPSendFree = NDIS_BUFFER_LINKAGE(ReturnBuffer);
+
+#else
+ PSINGLE_LIST_ENTRY BufferLink;
+
+ CTEFreeLock(&TCPSendFreeLock, Handle);
+
+ BufferLink = ExInterlockedPopEntrySList(
+ &TCPSendFree,
+ &TCPSendFreeLock
+ );
+
+ if (BufferLink != NULL) {
+ ReturnBuffer = STRUCT_OF(NDIS_BUFFER, BufferLink, Next);
+ } else
+ ReturnBuffer = NULL;
+
+ return ReturnBuffer;
+#endif
+#ifdef VXD
+ } else
+ ReturnBuffer = NULL;
+#endif
+
+ }
+
+ CTEFreeLock(&TCPSendFreeLock, Handle);
+ return ReturnBuffer;
+
+
+}
+
+//* GetTCPHeader - Get a TCP header buffer.
+//
+// Called when we need to get a TCP header buffer. This routine is
+// specific to the particular environment (VxD or NT). All we
+// need to do is pop the buffer from the free list.
+//
+// Input: Nothing.
+//
+// Returns: Pointer to an NDIS buffer, or NULL is none.
+//
+PNDIS_BUFFER
+GetTCPHeader(void)
+{
+ PNDIS_BUFFER NewBuffer;
+
+#ifdef VXD
+ NewBuffer = TCPSendFree;
+ if (NewBuffer != NULL) {
+ TCPSendFree = NDIS_BUFFER_LINKAGE(NewBuffer);
+ return NewBuffer;
+ }
+
+#else
+
+ PSINGLE_LIST_ENTRY BufferLink;
+
+ BufferLink = ExInterlockedPopEntrySList(
+ &TCPSendFree,
+ &TCPSendFreeLock
+ );
+ if (BufferLink != NULL) {
+ NewBuffer = STRUCT_OF(NDIS_BUFFER, BufferLink, Next);
+ return NewBuffer;
+ }
+#endif
+ else
+ return GrowTCPHeaderList();
+}
+
+//* FreeTCPHeader - Free a TCP header buffer.
+//
+// Called to free a TCP header buffer.
+//
+// Input: Buffer to be freed.
+//
+// Returns: Nothing.
+//
+void
+FreeTCPHeader(PNDIS_BUFFER FreedBuffer)
+{
+
+ CTEAssert(FreedBuffer != NULL);
+
+ NdisBufferLength(FreedBuffer) = sizeof(TCPHeader);
+
+#ifdef VXD
+
+ NDIS_BUFFER_LINKAGE(FreedBuffer) = TCPSendFree;
+ TCPSendFree = FreedBuffer;
+
+#else
+
+ ExInterlockedPushEntrySList(
+ &TCPSendFree,
+ STRUCT_OF(SINGLE_LIST_ENTRY, &(FreedBuffer->Next), Next),
+ &TCPSendFreeLock
+ );
+
+#endif
+}
+
+//* FreeSendReq - Free a send request structure.
+//
+// Called to free a send request structure.
+//
+// Input: FreedReq - Connection request structure to be freed.
+//
+// Returns: Nothing.
+//
+void
+FreeSendReq(TCPSendReq *FreedReq)
+{
+#ifdef NT
+ PSINGLE_LIST_ENTRY BufferLink;
+
+ CTEStructAssert(FreedReq, tsr);
+
+ BufferLink = STRUCT_OF(
+ SINGLE_LIST_ENTRY,
+ &(FreedReq->tsr_req.tr_q.q_next),
+ Next
+ );
+
+ ExInterlockedPushEntrySList(
+ &TCPSendReqFree,
+ BufferLink,
+ &TCPSendReqFreeLock
+ );
+
+#else // NT
+
+ TCPSendReq **Temp;
+
+ CTEStructAssert(FreedReq, tsr);
+
+ Temp = (TCPSendReq **)&FreedReq->tsr_req.tr_q.q_next;
+ *Temp = TCPSendReqFree;
+ TCPSendReqFree = FreedReq;
+
+#endif // NT
+}
+
+//* GetSendReq - Get a send request structure.
+//
+// Called to get a send request structure.
+//
+// Input: Nothing.
+//
+// Returns: Pointer to SendReq structure, or NULL if none.
+//
+TCPSendReq *
+GetSendReq(void)
+{
+ TCPSendReq *Temp;
+
+#ifdef NT
+ PSINGLE_LIST_ENTRY BufferLink;
+ Queue *QueuePtr;
+ TCPReq *ReqPtr;
+
+
+ BufferLink = ExInterlockedPopEntrySList(
+ &TCPSendReqFree,
+ &TCPSendReqFreeLock
+ );
+
+ if (BufferLink != NULL) {
+ QueuePtr = STRUCT_OF(Queue, BufferLink, q_next);
+ ReqPtr = STRUCT_OF(TCPReq, QueuePtr, tr_q);
+ Temp = STRUCT_OF(TCPSendReq, ReqPtr, tsr_req);
+ CTEStructAssert(Temp, tsr);
+ }
+ else {
+ if (NumTCPSendReq < MaxSendReq)
+ Temp = CTEAllocMem(sizeof(TCPSendReq));
+ else
+ Temp = NULL;
+
+ if (Temp != NULL) {
+ ExInterlockedAddUlong(&NumTCPSendReq, 1, &TCPSendReqFreeLock);
+#ifdef DEBUG
+ Temp->tsr_req.tr_sig = tr_signature;
+ Temp->tsr_sig = tsr_signature;
+#endif
+ }
+ }
+
+#else // NT
+
+ Temp = TCPSendReqFree;
+ if (Temp != NULL)
+ TCPSendReqFree = (TCPSendReq *)Temp->tsr_req.tr_q.q_next;
+ else {
+ if (NumTCPSendReq < MaxSendReq)
+ Temp = CTEAllocMem(sizeof(TCPSendReq));
+ else
+ Temp = NULL;
+
+ if (Temp != NULL) {
+ NumTCPSendReq++;
+#ifdef DEBUG
+ Temp->tsr_req.tr_sig = tr_signature;
+ Temp->tsr_sig = tsr_signature;
+#endif
+ }
+ }
+
+#endif // NT
+
+ return Temp;
+}
+
+
+
+//* TCPSendComplete - Complete a TCP send.
+//
+// Called by IP when a send we've made is complete. We free the buffer,
+// and possibly complete some sends. Each send queued on a TCB has a ref.
+// count with it, which is the number of times a pointer to a buffer
+// associated with the send has been passed to the underlying IP layer. We
+// can't complete a send until that count it 0. If this send was actually
+// from a send of data, we'll go down the chain of send and decrement the
+// refcount on each one. If we have one going to 0 and the send has already
+// been acked we'll complete the send. If it hasn't been acked we'll leave
+// it until the ack comes in.
+//
+// NOTE: We aren't protecting any of this with locks. When we port this to
+// NT we'll need to fix this, probably with a global lock. See the comments
+// in ACKSend() in TCPRCV.C for more details.
+//
+// Input: Context - Context we gave to IP.
+// BufferChain - BufferChain for send.
+//
+// Returns: Nothing.
+//
+void
+TCPSendComplete(void *Context, PNDIS_BUFFER BufferChain)
+{
+ CTELockHandle SendHandle;
+ PNDIS_BUFFER CurrentBuffer;
+
+
+ if (Context != NULL) {
+ SendCmpltContext *SCContext = (SendCmpltContext *)Context;
+ TCPSendReq *CurrentSend;
+ uint i;
+
+ CTEStructAssert(SCContext, scc);
+
+ // First, loop through and free any NDIS buffers here that need to be.
+ // freed. We'll skip any 'user' buffers, and then free our buffers. We
+ // need to do this before decrementing the reference count to avoid
+ // destroying the buffer chain if we have to zap tsr_lastbuf->Next to
+ // NULL.
+
+ CurrentBuffer = NDIS_BUFFER_LINKAGE(BufferChain);
+ for (i = 0; i < (uint)SCContext->scc_ubufcount; i++) {
+ CTEAssert(CurrentBuffer != NULL);
+ CurrentBuffer = NDIS_BUFFER_LINKAGE(CurrentBuffer);
+ }
+
+ for (i = 0; i < (uint)SCContext->scc_tbufcount; i++) {
+ PNDIS_BUFFER TempBuffer;
+
+ CTEAssert(CurrentBuffer != NULL);
+
+ TempBuffer = CurrentBuffer;
+ CurrentBuffer = NDIS_BUFFER_LINKAGE(CurrentBuffer);
+ NdisFreeBuffer(TempBuffer);
+ }
+
+ CurrentSend = SCContext->scc_firstsend;
+
+ i = 0;
+ while (i < SCContext->scc_count) {
+ Queue *TempQ;
+ long Result;
+
+
+ TempQ = QNEXT(&CurrentSend->tsr_req.tr_q);
+
+ CTEStructAssert(CurrentSend, tsr);
+
+ Result = CTEInterlockedDecrementLong(
+ &(CurrentSend->tsr_refcnt)
+ );
+
+ CTEAssert(Result >= 0);
+
+ if (Result <= 0) {
+
+ // Reference count has gone to 0 which means the send has
+ // been ACK'd or cancelled. Complete it now.
+
+ // If we've sent directly from this send, NULL out the next
+ // pointer for the last buffer in the chain.
+ if (CurrentSend->tsr_lastbuf != NULL) {
+ NDIS_BUFFER_LINKAGE(CurrentSend->tsr_lastbuf) = NULL;
+ CurrentSend->tsr_lastbuf = NULL;
+ }
+
+ CTEGetLock(&RequestCompleteLock, &SendHandle);
+ ENQUEUE(&SendCompleteQ, &CurrentSend->tsr_req.tr_q);
+ RequestCompleteFlags |= SEND_REQUEST_COMPLETE;
+ CTEFreeLock(&RequestCompleteLock, SendHandle);
+ }
+
+ CurrentSend = STRUCT_OF(TCPSendReq, QSTRUCT(TCPReq, TempQ, tr_q),
+ tsr_req);
+
+ i++;
+ }
+
+ }
+
+ FreeTCPHeader(BufferChain);
+
+ if (RequestCompleteFlags & SEND_REQUEST_COMPLETE)
+ TCPRcvComplete();
+
+}
+
+//* RcvWin - Figure out the receive window to offer in an ack.
+//
+// A routine to figure out what window to offer on a connection. We
+// take into account SWS avoidance, what the default connection window is,
+// and what the last window we offered is.
+//
+// Input: WinTCB - TCB on which to perform calculations.
+//
+// Returns: Window to be offered.
+//
+uint
+RcvWin(TCB *WinTCB)
+{
+ int CouldOffer; // The window size we could offer.
+
+ CTEStructAssert(WinTCB, tcb);
+
+ CheckRBList(WinTCB->tcb_pendhead, WinTCB->tcb_pendingcnt);
+
+ CTEAssert(WinTCB->tcb_rcvwin >= 0);
+
+ CouldOffer = WinTCB->tcb_defaultwin - WinTCB->tcb_pendingcnt;
+
+ CTEAssert(CouldOffer >= 0);
+ CTEAssert(CouldOffer >= WinTCB->tcb_rcvwin);
+
+ if ((CouldOffer - WinTCB->tcb_rcvwin) >= (int) MIN(WinTCB->tcb_defaultwin/2,
+ WinTCB->tcb_mss))
+ WinTCB->tcb_rcvwin = CouldOffer;
+
+ return WinTCB->tcb_rcvwin;
+}
+
+//* SendSYN - Send a SYN segment.
+//
+// This is called during connection establishment time to send a SYN
+// segment to the peer. We get a buffer if we can, and then fill
+// it in. There's a tricky part here where we have to build the MSS
+// option in the header - we find the MSS by finding the MSS offered
+// by the net for the local address. After that, we send it.
+//
+// Input: SYNTcb - TCB from which SYN is to be sent.
+// TCBHandle - Handle for lock on TCB.
+//
+// Returns: Nothing.
+//
+void
+SendSYN(TCB *SYNTcb, CTELockHandle TCBHandle)
+{
+ PNDIS_BUFFER HeaderBuffer;
+ TCPHeader *SYNHeader;
+ uchar *OptPtr;
+ IP_STATUS SendStatus;
+
+ CTEStructAssert(SYNTcb, tcb);
+
+ HeaderBuffer = GetTCPHeader();
+
+ // Go ahead and set the retransmission timer now, in case we didn't get a
+ // buffer. In the future we might want to queue the connection for
+ // when we free a buffer.
+ START_TCB_TIMER(SYNTcb->tcb_rexmittimer, SYNTcb->tcb_rexmit);
+ if (HeaderBuffer != NULL) {
+ ushort TempWin;
+ ushort MSS;
+ uchar FoundMSS;
+
+ SYNHeader = (TCPHeader *)(
+ (uchar *)NdisBufferVirtualAddress(HeaderBuffer) +
+ LocalNetInfo.ipi_hsize);
+
+ NDIS_BUFFER_LINKAGE(HeaderBuffer) = NULL;
+ NdisBufferLength(HeaderBuffer) = sizeof(TCPHeader) + MSS_OPT_SIZE;
+ SYNHeader->tcp_src = SYNTcb->tcb_sport;
+ SYNHeader->tcp_dest = SYNTcb->tcb_dport;
+ SYNHeader->tcp_seq = net_long(SYNTcb->tcb_sendnext);
+ SYNTcb->tcb_sendnext++;
+
+ if (SEQ_GT(SYNTcb->tcb_sendnext, SYNTcb->tcb_sendmax)) {
+ TStats.ts_outsegs++;
+ SYNTcb->tcb_sendmax = SYNTcb->tcb_sendnext;
+ } else
+ TStats.ts_retranssegs++;
+
+ SYNHeader->tcp_ack = net_long(SYNTcb->tcb_rcvnext);
+ if (SYNTcb->tcb_state == TCB_SYN_RCVD) {
+ SYNHeader->tcp_flags = MAKE_TCP_FLAGS(6, TCP_FLAG_SYN | TCP_FLAG_ACK);
+#ifdef SYN_ATTACK
+ //
+ // if this is the second time we are trying to send the SYN-ACK,
+ // increment the count of retried half-connections
+ //
+ if (SynAttackProtect && (SYNTcb->tcb_rexmitcnt == ADAPTED_MAX_CONNECT_RESPONSE_REXMIT_CNT)) {
+ CTEInterlockedAddUlong(&TCPHalfOpenRetried, 1, &SynAttLock);
+ }
+#endif
+ } else {
+ SYNHeader->tcp_flags = MAKE_TCP_FLAGS(6, TCP_FLAG_SYN);
+ }
+
+ TempWin = (ushort)SYNTcb->tcb_rcvwin;
+ SYNHeader->tcp_window = net_short(TempWin);
+ SYNHeader->tcp_xsum = 0;
+ OptPtr = (uchar *)(SYNHeader + 1);
+ FoundMSS = (*LocalNetInfo.ipi_getlocalmtu)(SYNTcb->tcb_saddr, &MSS);
+
+ if (!FoundMSS) {
+ DEBUGCHK;
+ CTEFreeLock(&SYNTcb->tcb_lock, TCBHandle);
+ FreeTCPHeader(HeaderBuffer);
+ return;
+ }
+
+ MSS -= sizeof(TCPHeader);
+
+ *OptPtr++ = TCP_OPT_MSS;
+ *OptPtr++ = MSS_OPT_SIZE;
+ **(ushort **)&OptPtr = net_short(MSS);
+
+ SYNTcb->tcb_refcnt++;
+ SYNHeader->tcp_xsum = ~XsumSendChain(SYNTcb->tcb_phxsum +
+ (uint)net_short(sizeof(TCPHeader) + MSS_OPT_SIZE), HeaderBuffer);
+ CTEFreeLock(&SYNTcb->tcb_lock, TCBHandle);
+
+
+ SendStatus = (*LocalNetInfo.ipi_xmit)(TCPProtInfo, NULL, HeaderBuffer,
+ sizeof(TCPHeader) + MSS_OPT_SIZE, SYNTcb->tcb_daddr,
+ SYNTcb->tcb_saddr, &SYNTcb->tcb_opt, SYNTcb->tcb_rce,
+ PROTOCOL_TCP);
+
+ SYNTcb->tcb_error = SendStatus;
+ if (SendStatus != IP_PENDING) {
+ FreeTCPHeader(HeaderBuffer);
+ }
+
+ CTEGetLock(&SYNTcb->tcb_lock, &TCBHandle);
+ DerefTCB(SYNTcb, TCBHandle);
+
+ } else {
+ CTEFreeLock(&SYNTcb->tcb_lock, TCBHandle);
+ return;
+ }
+
+}
+
+//* SendKA - Send a keep alive segment.
+//
+// This is called when we want to send a keep alive.
+//
+// Input: KATcb - TCB from which keep alive is to be sent.
+// Handle - Handle for lock on TCB.
+//
+// Returns: Nothing.
+//
+void
+SendKA(TCB *KATcb, CTELockHandle Handle)
+{
+ PNDIS_BUFFER HeaderBuffer;
+ TCPHeader *Header;
+ IP_STATUS SendStatus;
+
+ CTEStructAssert(KATcb, tcb);
+
+ HeaderBuffer = GetTCPHeader();
+
+ if (HeaderBuffer != NULL) {
+ ushort TempWin;
+ SeqNum TempSeq;
+
+ Header = (TCPHeader *)(
+ (uchar *)NdisBufferVirtualAddress(HeaderBuffer) +
+ LocalNetInfo.ipi_hsize);
+
+ NDIS_BUFFER_LINKAGE(HeaderBuffer) = NULL;
+ NdisBufferLength(HeaderBuffer) = sizeof(TCPHeader) + 1;
+ Header->tcp_src = KATcb->tcb_sport;
+ Header->tcp_dest = KATcb->tcb_dport;
+ TempSeq = KATcb->tcb_senduna - 1;
+ Header->tcp_seq = net_long(TempSeq);
+
+ TStats.ts_retranssegs++;
+
+ Header->tcp_ack = net_long(KATcb->tcb_rcvnext);
+ Header->tcp_flags = MAKE_TCP_FLAGS(5, TCP_FLAG_ACK);
+
+ TempWin = (ushort)RcvWin(KATcb);
+ Header->tcp_window = net_short(TempWin);
+ Header->tcp_xsum = 0;
+
+ Header->tcp_xsum = ~XsumSendChain(KATcb->tcb_phxsum +
+ (uint)net_short(sizeof(TCPHeader) + 1), HeaderBuffer);
+
+ KATcb->tcb_kacount++;
+ CTEFreeLock(&KATcb->tcb_lock, Handle);
+
+
+ SendStatus = (*LocalNetInfo.ipi_xmit)(TCPProtInfo, NULL, HeaderBuffer,
+ sizeof(TCPHeader) + 1, KATcb->tcb_daddr,
+ KATcb->tcb_saddr, &KATcb->tcb_opt, KATcb->tcb_rce, PROTOCOL_TCP);
+
+ if (SendStatus != IP_PENDING) {
+ FreeTCPHeader(HeaderBuffer);
+ }
+
+
+ } else {
+ CTEFreeLock(&KATcb->tcb_lock, Handle);
+ }
+
+}
+
+//* SendACK - Send an ACK segment.
+//
+// This is called whenever we need to send an ACK for some reason. Nothing
+// fancy, we just do it.
+//
+// Input: ACKTcb - TCB from which ACK is to be sent.
+//
+// Returns: Nothing.
+//
+void
+SendACK(TCB *ACKTcb)
+{
+ PNDIS_BUFFER HeaderBuffer;
+ TCPHeader *ACKHeader;
+ IP_STATUS SendStatus;
+ CTELockHandle TCBHandle;
+ SeqNum SendNext;
+
+ CTEStructAssert(ACKTcb, tcb);
+
+ if ((ACKTcb->tcb_state == TCB_TIME_WAIT) &&
+ (ACKTcb->tcb_flags & TW_PENDING)) {
+ CTEGetLock(&ACKTcb->tcb_lock, &TCBHandle);
+ STOP_TCB_TIMER(ACKTcb->tcb_delacktimer);
+ ACKTcb->tcb_flags &= ~(NEED_ACK | ACK_DELAYED);
+ ACKTcb->tcb_error = IP_SUCCESS;
+ CTEFreeLock(&ACKTcb->tcb_lock, TCBHandle);
+ return;
+ }
+
+ HeaderBuffer = GetTCPHeader();
+
+
+ if (HeaderBuffer != NULL) {
+ ushort TempWin;
+
+ CTEGetLock(&ACKTcb->tcb_lock, &TCBHandle);
+
+ ACKHeader = (TCPHeader *)(
+ (uchar *)NdisBufferVirtualAddress(HeaderBuffer) +
+ LocalNetInfo.ipi_hsize);
+ NDIS_BUFFER_LINKAGE(HeaderBuffer) = NULL;
+
+ ACKHeader->tcp_src = ACKTcb->tcb_sport;
+ ACKHeader->tcp_dest = ACKTcb->tcb_dport;
+ ACKHeader->tcp_ack = net_long(ACKTcb->tcb_rcvnext);
+
+ // If the remote peer is advertising a window of zero, we need to
+ // send this ack with a seq. number of his rcv_next (which in that case
+ // should be our senduna). We have code here ifdef'd out that makes
+ // sure that we don't send outside the RWE, but this doesn't work. We
+ // need to be able to send a pure ACK exactly at the RWE.
+
+ if (ACKTcb->tcb_sendwin != 0) {
+ SeqNum MaxValidSeq;
+
+ SendNext = ACKTcb->tcb_sendnext;
+#if 0
+ MaxValidSeq = ACKTcb->tcb_senduna + ACKTcb->tcb_sendwin - 1;
+
+ SendNext = (SEQ_LT(SendNext, MaxValidSeq) ? SendNext : MaxValidSeq);
+#endif
+
+ } else
+ SendNext = ACKTcb->tcb_senduna;
+
+ if ((ACKTcb->tcb_flags & FIN_SENT) &&
+ SEQ_EQ(SendNext, ACKTcb->tcb_sendmax - 1)) {
+ ACKHeader->tcp_flags = MAKE_TCP_FLAGS(5,
+ TCP_FLAG_FIN | TCP_FLAG_ACK);
+ } else
+ ACKHeader->tcp_flags = MAKE_TCP_FLAGS(5, TCP_FLAG_ACK);
+
+ ACKHeader->tcp_seq = net_long(SendNext);
+
+ TempWin = (ushort)RcvWin(ACKTcb);
+ ACKHeader->tcp_window = net_short(TempWin);
+ ACKHeader->tcp_xsum = 0;
+
+ ACKHeader->tcp_xsum = ~XsumSendChain(ACKTcb->tcb_phxsum +
+ (uint)net_short(sizeof(TCPHeader)), HeaderBuffer);
+
+ STOP_TCB_TIMER(ACKTcb->tcb_delacktimer);
+ ACKTcb->tcb_flags &= ~(NEED_ACK | ACK_DELAYED);
+
+ if (ACKTcb->tcb_flags & TW_PENDING) {
+ ACKTcb->tcb_state = TCB_TIME_WAIT;
+ }
+
+ CTEFreeLock(&ACKTcb->tcb_lock, TCBHandle);
+
+ TStats.ts_outsegs++;
+ SendStatus = (*LocalNetInfo.ipi_xmit)(TCPProtInfo, NULL, HeaderBuffer,
+ sizeof(TCPHeader), ACKTcb->tcb_daddr, ACKTcb->tcb_saddr,
+ &ACKTcb->tcb_opt, ACKTcb->tcb_rce, PROTOCOL_TCP);
+
+ ACKTcb->tcb_error = SendStatus;
+ if (SendStatus != IP_PENDING)
+ FreeTCPHeader(HeaderBuffer);
+ }
+
+ return;
+
+
+}
+
+//* SendRSTFromTCB - Send a RST from a TCB.
+//
+// This is called during close when we need to send a RST.
+//
+// Input: RSTTcb - TCB from which RST is to be sent.
+//
+// Returns: Nothing.
+//
+void
+SendRSTFromTCB(TCB *RSTTcb)
+{
+ PNDIS_BUFFER HeaderBuffer;
+ TCPHeader *RSTHeader;
+ IP_STATUS SendStatus;
+
+ CTEStructAssert(RSTTcb, tcb);
+
+ CTEAssert(RSTTcb->tcb_state == TCB_CLOSED);
+
+ HeaderBuffer = GetTCPHeader();
+
+
+ if (HeaderBuffer != NULL) {
+ SeqNum RSTSeq;
+
+ RSTHeader = (TCPHeader *)(
+ (uchar *)NdisBufferVirtualAddress(HeaderBuffer) +
+ LocalNetInfo.ipi_hsize);
+ NDIS_BUFFER_LINKAGE(HeaderBuffer) = NULL;
+
+ RSTHeader->tcp_src = RSTTcb->tcb_sport;
+ RSTHeader->tcp_dest = RSTTcb->tcb_dport;
+
+ // If the remote peer has a window of 0, send with a seq. # equal
+ // to senduna so he'll accept it. Otherwise send with send max.
+ if (RSTTcb->tcb_sendwin != 0)
+ RSTSeq = RSTTcb->tcb_sendmax;
+ else
+ RSTSeq = RSTTcb->tcb_senduna;
+
+ RSTHeader->tcp_seq = net_long(RSTSeq);
+ RSTHeader->tcp_flags = MAKE_TCP_FLAGS(sizeof(TCPHeader)/sizeof(ulong),
+ TCP_FLAG_RST);
+
+ RSTHeader->tcp_window = 0;
+ RSTHeader->tcp_xsum = 0;
+
+ RSTHeader->tcp_xsum = ~XsumSendChain(RSTTcb->tcb_phxsum +
+ (uint)net_short(sizeof(TCPHeader)), HeaderBuffer);
+
+ TStats.ts_outsegs++;
+ TStats.ts_outrsts++;
+ SendStatus = (*LocalNetInfo.ipi_xmit)(TCPProtInfo, NULL, HeaderBuffer,
+ sizeof(TCPHeader), RSTTcb->tcb_daddr, RSTTcb->tcb_saddr,
+ &RSTTcb->tcb_opt, RSTTcb->tcb_rce, PROTOCOL_TCP);
+
+ if (SendStatus != IP_PENDING)
+ FreeTCPHeader(HeaderBuffer);
+ }
+
+ return;
+
+
+}
+//* SendRSTFromHeader - Send a RST back, based on a header.
+//
+// Called when we need to send a RST, but don't necessarily have a TCB.
+//
+// Input: TCPH - TCP header to be RST.
+// Length - Length of the incoming segment.
+// Dest - Destination IP address for RST.
+// Src - Source IP address for RST.
+// OptInfo - IP Options to use on RST.
+//
+// Returns: Nothing.
+//
+void
+SendRSTFromHeader(TCPHeader UNALIGNED *TCPH, uint Length, IPAddr Dest,
+ IPAddr Src, IPOptInfo *OptInfo)
+{
+ PNDIS_BUFFER Buffer;
+ TCPHeader *RSTHdr;
+ IPOptInfo NewInfo;
+ IP_STATUS SendStatus;
+
+ if (TCPH->tcp_flags & TCP_FLAG_RST)
+ return;
+
+ Buffer = GetTCPHeader();
+
+ if (Buffer != NULL) {
+ // Got a buffer. Fill in the header so as to make it believable to
+ // the remote guy, and send it.
+
+ RSTHdr = (TCPHeader *)((uchar *)NdisBufferVirtualAddress(Buffer) +
+ LocalNetInfo.ipi_hsize);
+
+ NDIS_BUFFER_LINKAGE(Buffer) = NULL;
+
+ if (TCPH->tcp_flags & TCP_FLAG_SYN)
+ Length++;
+
+ if (TCPH->tcp_flags & TCP_FLAG_FIN)
+ Length++;
+
+ if (TCPH->tcp_flags & TCP_FLAG_ACK) {
+ RSTHdr->tcp_seq = TCPH->tcp_ack;
+ RSTHdr->tcp_flags = MAKE_TCP_FLAGS(sizeof(TCPHeader)/sizeof(ulong),
+ TCP_FLAG_RST);
+ } else {
+ SeqNum TempSeq;
+
+ RSTHdr->tcp_seq = 0;
+ TempSeq = net_long(TCPH->tcp_seq);
+ TempSeq += Length;
+ RSTHdr->tcp_ack = net_long(TempSeq);
+ RSTHdr->tcp_flags = MAKE_TCP_FLAGS(sizeof(TCPHeader)/sizeof(ulong),
+ TCP_FLAG_RST | TCP_FLAG_ACK);
+ }
+
+ RSTHdr->tcp_window = 0;
+ RSTHdr->tcp_dest = TCPH->tcp_src;
+ RSTHdr->tcp_src = TCPH->tcp_dest;
+ RSTHdr->tcp_xsum = 0;
+
+ RSTHdr->tcp_xsum = ~XsumSendChain(PHXSUM(Src, Dest, PROTOCOL_TCP,
+ sizeof(TCPHeader)), Buffer);
+
+ (*LocalNetInfo.ipi_initopts)(&NewInfo);
+
+ if (OptInfo->ioi_options != NULL)
+ (*LocalNetInfo.ipi_updateopts)(OptInfo, &NewInfo, Dest, NULL_IP_ADDR);
+
+ TStats.ts_outsegs++;
+ TStats.ts_outrsts++;
+ SendStatus = (*LocalNetInfo.ipi_xmit)(TCPProtInfo, NULL, Buffer,
+ sizeof(TCPHeader), Dest, Src, &NewInfo, NULL, PROTOCOL_TCP);
+
+ if (SendStatus != IP_PENDING)
+ FreeTCPHeader(Buffer);
+
+ (*LocalNetInfo.ipi_freeopts)(&NewInfo);
+ }
+
+}
+//* GoToEstab - Transition to the established state.
+//
+// Called when we are going to the established state and need to finish up
+// initializing things that couldn't be done until now. We assume the TCB
+// lock is held by the caller on the TCB we're called with.
+//
+// Input: EstabTCB - TCB to transition.
+//
+// Returns: Nothing.
+//
+void
+GoToEstab(TCB *EstabTCB)
+{
+
+ // Initialize our slow start and congestion control variables.
+ EstabTCB->tcb_cwin = 2 * EstabTCB->tcb_mss;
+ EstabTCB->tcb_ssthresh = 0xffffffff;
+
+ EstabTCB->tcb_state = TCB_ESTAB;
+
+ // We're in established. We'll subtract one from slow count for this fact,
+ // and if the slowcount goes to 0 we'll move onto the fast path.
+
+ if (--(EstabTCB->tcb_slowcount) == 0)
+ EstabTCB->tcb_fastchk &= ~TCP_FLAG_SLOW;
+
+ TStats.ts_currestab++;
+
+ EstabTCB->tcb_flags &= ~ACTIVE_OPEN; // Turn off the active opening flag.
+
+}
+
+//* InitSendState - Initialize the send state of a connection.
+//
+// Called during connection establishment to initialize our send state.
+// (In this case, this refers to all information we'll put on the wire as
+// well as pure send state). We pick an ISS, set up a rexmit timer value,
+// etc. We assume the tcb_lock is held on the TCB when we are called.
+//
+// Input: NewTCB - TCB to be set up.
+//
+// Returns: Nothing.
+void
+InitSendState(TCB *NewTCB)
+{
+ CTEStructAssert(NewTCB, tcb);
+
+ NewTCB->tcb_sendnext = CTESystemUpTime();
+ NewTCB->tcb_senduna = NewTCB->tcb_sendnext;
+ NewTCB->tcb_sendmax = NewTCB->tcb_sendnext;
+ NewTCB->tcb_error = IP_SUCCESS;
+
+ // Initialize pseudo-header xsum.
+ NewTCB->tcb_phxsum = PHXSUM(NewTCB->tcb_saddr, NewTCB->tcb_daddr,
+ PROTOCOL_TCP, 0);
+
+ // Initialize retransmit and delayed ack stuff.
+ NewTCB->tcb_rexmitcnt = 0;
+ NewTCB->tcb_rtt = 0;
+ NewTCB->tcb_smrtt = 0;
+ NewTCB->tcb_delta = MS_TO_TICKS(6000);
+ NewTCB->tcb_rexmit = MS_TO_TICKS(3000);
+ STOP_TCB_TIMER(NewTCB->tcb_rexmittimer);
+ STOP_TCB_TIMER(NewTCB->tcb_delacktimer);
+
+}
+
+//* TCPStatus - Handle a status indication.
+//
+// This is the TCP status handler, called by IP when a status event
+// occurs. For most of these we do nothing. For certain severe status
+// events we will mark the local address as invalid.
+//
+// Entry: StatusType - Type of status (NET or HW). NET status
+// is usually caused by a received ICMP
+// message. HW status indicate a HW
+// problem.
+// StatusCode - Code identifying IP_STATUS.
+// OrigDest - If this is NET status, the original dest. of
+// DG that triggered it.
+// OrigSrc - " " " " " , the original src.
+// Src - IP address of status originator (could be local
+// or remote).
+// Param - Additional information for status - i.e. the
+// param field of an ICMP message.
+// Data - Data pertaining to status - for NET status, this
+// is the first 8 bytes of the original DG.
+//
+// Returns: Nothing
+//
+void
+TCPStatus(uchar StatusType, IP_STATUS StatusCode, IPAddr OrigDest,
+ IPAddr OrigSrc, IPAddr Src, ulong Param, void *Data)
+{
+ CTELockHandle TableHandle, TCBHandle;
+ TCB *StatusTCB;
+ TCPHeader UNALIGNED *Header = (TCPHeader UNALIGNED *)Data;
+ SeqNum DropSeq;
+
+ // Handle NET status codes differently from HW status codes.
+ if (StatusType == IP_NET_STATUS) {
+ // It's a NET code. Find a matching TCB.
+ CTEGetLock(&TCBTableLock, &TableHandle);
+ StatusTCB = FindTCB(OrigSrc, OrigDest, Header->tcp_dest,
+ Header->tcp_src);
+ if (StatusTCB != NULL) {
+ // Found one. Get the lock on it, and continue.
+ CTEStructAssert(StatusTCB, tcb);
+
+ CTEGetLock(&StatusTCB->tcb_lock, &TCBHandle);
+ CTEFreeLock(&TCBTableLock, TCBHandle);
+
+
+ // Make sure the TCB is in a state that is interesting.
+ if (StatusTCB->tcb_state == TCB_CLOSED ||
+ StatusTCB->tcb_state == TCB_TIME_WAIT ||
+ CLOSING(StatusTCB)) {
+ CTEFreeLock(&StatusTCB->tcb_lock, TableHandle);
+ return;
+ }
+
+ switch (StatusCode) {
+ // Hard errors - Destination protocol unreachable. We treat
+ // these as fatal errors. Close the connection now.
+ case IP_DEST_PROT_UNREACHABLE:
+ StatusTCB->tcb_error = StatusCode;
+ StatusTCB->tcb_refcnt++;
+ TryToCloseTCB(StatusTCB, TCB_CLOSE_UNREACH, TableHandle);
+
+ RemoveTCBFromConn(StatusTCB);
+ NotifyOfDisc(StatusTCB, NULL,
+ MapIPError(StatusCode, TDI_DEST_UNREACHABLE));
+ CTEGetLock(&StatusTCB->tcb_lock, &TCBHandle);
+ DerefTCB(StatusTCB, TCBHandle);
+ return;
+ break;
+
+ // Soft errors. Save the error in case it time out.
+ case IP_DEST_NET_UNREACHABLE:
+ case IP_DEST_HOST_UNREACHABLE:
+ case IP_DEST_PORT_UNREACHABLE:
+ case IP_PACKET_TOO_BIG:
+ case IP_BAD_ROUTE:
+ case IP_TTL_EXPIRED_TRANSIT:
+ case IP_TTL_EXPIRED_REASSEM:
+ case IP_PARAM_PROBLEM:
+ StatusTCB->tcb_error = StatusCode;
+ break;
+
+ case IP_SPEC_MTU_CHANGE:
+ // A TCP datagram has triggered an MTU change. Figure out
+ // which connection it is, and update him to retransmit the
+ // segment. The Param value is the new MTU. We'll need to
+ // retransmit if the new MTU is less than our existing MTU
+ // and the sequence of the dropped packet is less than our
+ // current send next.
+
+ Param -= sizeof(TCPHeader) -
+ StatusTCB->tcb_opt.ioi_optlength;
+ DropSeq = net_long(Header->tcp_seq);
+
+ if (*(ushort *)&Param <= StatusTCB->tcb_mss &&
+ (SEQ_GTE(DropSeq, StatusTCB->tcb_senduna) &&
+ SEQ_LT(DropSeq, StatusTCB->tcb_sendnext))) {
+
+ // Need to initiate a retranmsit.
+ ResetSendNext(StatusTCB, DropSeq);
+ // Set the congestion window to allow only one packet.
+ // This may prevent us from sending anything if we
+ // didn't just set sendnext to senduna. This is OK,
+ // we'll retransmit later, or send when we get an ack.
+ StatusTCB->tcb_cwin = Param;
+ DelayAction(StatusTCB, NEED_OUTPUT);
+ }
+
+ StatusTCB->tcb_mss = (ushort)MIN(Param,
+ (ulong)StatusTCB->tcb_remmss);
+
+ CTEAssert(StatusTCB->tcb_mss > 0);
+
+
+ //
+ // Reset the Congestion Window if necessary
+ //
+ if (StatusTCB->tcb_cwin < StatusTCB->tcb_mss) {
+ StatusTCB->tcb_cwin = StatusTCB->tcb_mss;
+
+ //
+ // Make sure the slow start threshold is at least
+ // 2 segments
+ //
+ if ( StatusTCB->tcb_ssthresh <
+ ((uint) StatusTCB->tcb_mss*2)
+ ) {
+ StatusTCB->tcb_ssthresh = StatusTCB->tcb_mss * 2;
+ }
+ }
+
+ break;
+
+ // Source quench. This will cause us to reinitiate our
+ // slow start by resetting our congestion window and
+ // adjusting our slow start threshold.
+ case IP_SOURCE_QUENCH:
+ StatusTCB->tcb_ssthresh =
+ MAX(
+ MIN(
+ StatusTCB->tcb_cwin,
+ StatusTCB->tcb_sendwin
+ ) / 2,
+ (uint) StatusTCB->tcb_mss * 2
+ );
+ StatusTCB->tcb_cwin = StatusTCB->tcb_mss;
+ break;
+
+ default:
+ DEBUGCHK;
+ break;
+ }
+
+ CTEFreeLock(&StatusTCB->tcb_lock, TableHandle);
+ } else {
+ // Couldn't find a matching TCB. Just free the lock and return.
+ CTEFreeLock(&TCBTableLock, TableHandle);
+ }
+ } else {
+ uint NewMTU;
+
+ // 'Hardware' or 'global' status. Figure out what to do.
+ switch (StatusCode) {
+ case IP_ADDR_DELETED:
+ // Local address has gone away. OrigDest is the IPAddr which is
+ // gone.
+
+#ifndef _PNP_POWER
+ //
+ // Delete all TCBs with that as a source address.
+ // This is done via TDI notifications in the PNP world.
+ //
+ TCBWalk(DeleteTCBWithSrc, &OrigDest, NULL, NULL);
+
+#endif // _PNP_POWER
+
+#ifdef SECFLTR
+ //
+ // Delete any security filters associated with this address
+ //
+ DeleteProtocolSecurityFilter(OrigDest, PROTOCOL_TCP);
+
+#endif // SECFLTR
+
+ break;
+
+ case IP_ADDR_ADDED:
+
+#ifdef SECFLTR
+ //
+ // An address has materialized. OrigDest identifies the address.
+ // Data is a handle to the IP configuration information for the
+ // interface on which the address is instantiated.
+ //
+ AddProtocolSecurityFilter(OrigDest, PROTOCOL_TCP,
+ (NDIS_HANDLE) Data);
+#endif // SECFLTR
+
+ break;
+
+ case IP_MTU_CHANGE:
+ NewMTU = Param - sizeof(TCPHeader);
+ TCBWalk(SetTCBMTU, &OrigDest, &OrigSrc, &NewMTU);
+ break;
+#ifdef CHICAGO
+ case IP_UNLOAD:
+ // IP is telling us we're being unloaded. First, deregister
+ // with VTDI, and then call CTEUnload().
+ (void)TLRegisterProtocol(PROTOCOL_TCP, NULL, NULL, NULL, NULL);
+ TLRegisterDispatch(TransportName, NULL);
+ (void)RegisterAddrChangeHndlr(AddrChange, FALSE);
+ CTEUnload(TransportName);
+ break;
+#endif // CHICAGO
+ default:
+ DEBUGCHK;
+ break;
+ }
+ }
+}
+
+//* FillTCPHeader - Fill the TCP header in.
+//
+// A utility routine to fill in the TCP header.
+//
+// Input: SendTCB - TCB to fill from.
+// Header - Header to fill into.
+//
+// Returns: Nothing.
+//
+void
+FillTCPHeader(TCB *SendTCB, TCPHeader *Header)
+{
+#ifdef VXD
+
+// STUPID FUCKING COMPILER generates incorrect code for this. Put it back on
+// the blessed day we get a real compiler.
+
+#if 0
+ _asm {
+ mov edx, dword ptr SendTCB
+ mov ecx, dword ptr Header
+ mov ax, word ptr [edx].tcb_sport
+ xchg al, ah
+ mov word ptr [ecx].tcp_src, ax
+ mov ax, [edx].tcb_dport
+ xchg ah, al
+ mov [ecx].tcp_dest, ax
+
+ mov eax, [edx].tcb_sendnext
+ xchg ah, al
+ ror eax, 16
+ xchg ah, al
+ mov [ecx].tcp_seq, eax
+
+ mov eax, [edx].tcb_rcvnext
+ xchg ah, al
+ ror eax, 16
+ xchg ah, al
+ mov [ecx].tcp_ack, eax
+
+ mov [ecx].tcp_flags, 1050H
+ mov dword ptr [ecx].tcp_xsum, 0
+
+ push edx
+ call near ptr RcvWin
+ add esp, 4
+
+ mov ecx, Header
+ xchg ah, al
+ mov [ecx].tcp_window, ax
+
+ }
+#else
+ ushort S;
+ ulong L;
+
+
+ Header->tcp_src = SendTCB->tcb_sport;
+ Header->tcp_dest = SendTCB->tcb_dport;
+ L = SendTCB->tcb_sendnext;
+ Header->tcp_seq = net_long(L);
+ L = SendTCB->tcb_rcvnext;
+ Header->tcp_ack = net_long(L);
+ Header->tcp_flags = 0x1050;
+ *(ulong *)&Header->tcp_xsum = 0;
+ S = RcvWin(SendTCB);
+ Header->tcp_window = net_short(S);
+#endif
+#else
+
+ //
+ // BUGBUG: Is this worth coding in assembly?
+ //
+ ushort S;
+ ulong L;
+
+
+ Header->tcp_src = SendTCB->tcb_sport;
+ Header->tcp_dest = SendTCB->tcb_dport;
+ L = SendTCB->tcb_sendnext;
+ Header->tcp_seq = net_long(L);
+ L = SendTCB->tcb_rcvnext;
+ Header->tcp_ack = net_long(L);
+ Header->tcp_flags = 0x1050;
+ *(ulong *)&Header->tcp_xsum = 0;
+ S = RcvWin(SendTCB);
+ Header->tcp_window = net_short(S);
+#endif
+
+
+}
+
+//* TCPSend - Send data from a TCP connection.
+//
+// This is the main 'send data' routine. We go into a loop, trying
+// to send data until we can't for some reason. First we compute
+// the useable window, use it to figure the amount we could send. If
+// the amount we could send meets certain criteria we'll build a frame
+// and send it, after setting any appropriate control bits. We assume
+// the caller has put a reference on the TCB.
+//
+// Input: SendTCB - TCB to be sent from.
+// TCBHandle - Lock handle for TCB.
+//
+// Returns: Nothing.
+//
+void
+#ifdef VXD
+TCPSend(TCB *SendTCB)
+#else
+TCPSend(TCB *SendTCB, CTELockHandle TCBHandle)
+#endif
+{
+ int SendWin; // Useable send window.
+ uint AmountToSend; // Amount to send this time.
+ uint AmountLeft;
+ TCPHeader *Header; // TCP header for a send.
+ PNDIS_BUFFER FirstBuffer, CurrentBuffer;
+ TCPSendReq *CurSend;
+ SendCmpltContext *SCC;
+ SeqNum OldSeq;
+ IP_STATUS SendStatus;
+ uint AmtOutstanding, AmtUnsent;
+ int ForceWin; // Window we're force to use.
+#ifdef VXD
+ CTELockHandle TCBHandle;
+
+ CTEGetLock(&SendTCB->tcb_lock, &TCBHandle);
+#endif
+
+
+ CTEStructAssert(SendTCB, tcb);
+ CTEAssert(SendTCB->tcb_refcnt != 0);
+
+ CTEAssert(*(int *)&SendTCB->tcb_sendwin >= 0);
+ CTEAssert(*(int *)&SendTCB->tcb_cwin >= SendTCB->tcb_mss);
+
+ CTEAssert(!(SendTCB->tcb_flags & FIN_OUTSTANDING) ||
+ (SendTCB->tcb_sendnext == SendTCB->tcb_sendmax));
+
+ if (!(SendTCB->tcb_flags & IN_TCP_SEND) &&
+ !(SendTCB->tcb_fastchk & TCP_FLAG_IN_RCV)) {
+ SendTCB->tcb_flags |= IN_TCP_SEND;
+
+ // We'll continue this loop until we send a FIN, or we break out
+ // internally for some other reason.
+ while (!(SendTCB->tcb_flags & FIN_OUTSTANDING)) {
+
+ CheckTCBSends(SendTCB);
+
+ AmtOutstanding = (uint)(SendTCB->tcb_sendnext -
+ SendTCB->tcb_senduna);
+ AmtUnsent = SendTCB->tcb_unacked - AmtOutstanding;
+
+ CTEAssert(*(int *)&AmtUnsent >= 0);
+
+ SendWin = (int)(MIN(SendTCB->tcb_sendwin, SendTCB->tcb_cwin) -
+ AmtOutstanding);
+
+#if FAST_RETRANSMIT
+ // if this send is after the fast recovery
+ // and sendwin is zero because of amt outstanding
+ // then, at least force 1 segment to prevent delayed
+ // ack timeouts from the remote
+
+ if (SendTCB->tcb_force) {
+ SendTCB->tcb_force=0;
+ if (SendWin < SendTCB->tcb_mss ){
+
+ SendWin = SendTCB->tcb_mss;
+ }
+ }
+
+#endif
+
+
+
+ // Since the window could have shrank, need to get it to zero at
+ // least.
+ ForceWin = (int)((SendTCB->tcb_flags & FORCE_OUTPUT) >>
+ FORCE_OUT_SHIFT);
+ SendWin = MAX(SendWin, ForceWin);
+
+ AmountToSend = MIN(MIN((uint)SendWin, AmtUnsent), SendTCB->tcb_mss);
+
+ CTEAssert(SendTCB->tcb_mss > 0);
+
+ // See if we have enough to send. We'll send if we have at least a
+ // segment, or if we really have some data to send and we can send
+ // all that we have, or the send window is > 0 and we need to force
+ // output or send a FIN (note that if we need to force output
+ // SendWin will be at least 1 from the check above), or if we can
+ // send an amount == to at least half the maximum send window
+ // we've seen.
+ if (AmountToSend == SendTCB->tcb_mss ||
+ (AmountToSend != 0 && AmountToSend == AmtUnsent) ||
+ (SendWin != 0 &&
+ ((SendTCB->tcb_flags & (FORCE_OUTPUT | FIN_NEEDED)) ||
+ AmountToSend >= (SendTCB->tcb_maxwin / 2)))) {
+
+ // It's OK to send something. Try to get a header buffer now.
+ FirstBuffer = GetTCPHeader();
+ if (FirstBuffer != NULL) {
+
+ // Got a header buffer. Loop through the sends on the TCB,
+ // building a frame.
+ CurrentBuffer = FirstBuffer;
+ CurSend = SendTCB->tcb_cursend;
+
+ Header = (TCPHeader *)(
+ (uchar *)NdisBufferVirtualAddress(FirstBuffer) +
+ LocalNetInfo.ipi_hsize);
+
+ SCC = (SendCmpltContext *)(Header + 1);
+#ifdef DEBUG
+ SCC->scc_sig = scc_signature;
+#endif
+ FillTCPHeader(SendTCB, Header);
+
+ SCC->scc_ubufcount = 0;
+ SCC->scc_tbufcount = 0;
+ SCC->scc_count = 0;
+
+ AmountLeft = AmountToSend;
+
+ if (AmountToSend != 0) {
+ long Result;
+
+
+ CTEStructAssert(CurSend, tsr);
+ SCC->scc_firstsend = CurSend;
+
+ do {
+ CTEAssert(CurSend->tsr_refcnt > 0);
+ Result = CTEInterlockedIncrementLong(
+ &(CurSend->tsr_refcnt)
+ );
+
+ CTEAssert(Result > 0);
+
+ SCC->scc_count++;
+ // If the current send offset is 0 and the current
+ // send is less than or equal to what we have left
+ // to send, we haven't already put a transport
+ // buffer on this send, and nobody else is using
+ // the buffer chain directly, just use the input
+ // buffers. We check for other people using them
+ // by looking at tsr_lastbuf. If it's NULL,
+ // nobody else is using the buffers. If it's not
+ // NULL, somebody is.
+
+ if (SendTCB->tcb_sendofs == 0 &&
+ (SendTCB->tcb_sendsize <= AmountLeft) &&
+ (SCC->scc_tbufcount == 0) &&
+ CurSend->tsr_lastbuf == NULL) {
+
+ NDIS_BUFFER_LINKAGE(CurrentBuffer) =
+ SendTCB->tcb_sendbuf;
+ do {
+ SCC->scc_ubufcount++;
+ CurrentBuffer = NDIS_BUFFER_LINKAGE(CurrentBuffer);
+ } while (NDIS_BUFFER_LINKAGE(CurrentBuffer) != NULL);
+
+ CurSend->tsr_lastbuf = CurrentBuffer;
+ AmountLeft -= SendTCB->tcb_sendsize;
+ SendTCB->tcb_sendsize = 0;
+ } else {
+ uint AmountToDup;
+ PNDIS_BUFFER NewBuf, Buf;
+ uint Offset;
+ NDIS_STATUS NStatus;
+ uchar *VirtualAddress;
+ uint Length;
+
+ // Either the current send has more data than
+ // we want to send, or the starting offset is
+ // not 0. In either case we'll need to loop
+ // through the current send, allocating buffers.
+ Buf = SendTCB->tcb_sendbuf;
+ Offset = SendTCB->tcb_sendofs;
+
+ do {
+ CTEAssert(Buf != NULL);
+
+ NdisQueryBuffer(Buf, &VirtualAddress,
+ &Length);
+
+ CTEAssert((Offset < Length) ||
+ (Offset == 0 && Length == 0));
+
+ // Adjust the length for the offset into
+ // this buffer.
+
+ Length -= Offset;
+
+ AmountToDup = MIN(AmountLeft, Length);
+
+ NdisAllocateBuffer(&NStatus, &NewBuf,
+ TCPSendBufferPool,
+ VirtualAddress + Offset,
+ AmountToDup);
+ if (NStatus == NDIS_STATUS_SUCCESS) {
+ SCC->scc_tbufcount++;
+
+ NDIS_BUFFER_LINKAGE(CurrentBuffer) =
+ NewBuf;
+
+ CurrentBuffer = NewBuf;
+ if (AmountToDup >= Length) {
+ // Exhausted this buffer.
+ Buf = NDIS_BUFFER_LINKAGE(Buf);
+ Offset = 0;
+ } else {
+ Offset += AmountToDup;
+ CTEAssert(Offset < NdisBufferLength(Buf));
+ }
+
+ SendTCB->tcb_sendsize -= AmountToDup;
+ AmountLeft -= AmountToDup;
+ } else {
+ // Couldn't allocate a buffer. If
+ // the packet is already partly built,
+ // send what we've got, otherwise
+ // bail out.
+ if (SCC->scc_tbufcount == 0 &&
+ SCC->scc_ubufcount == 0) {
+ TCPSendComplete(SCC, FirstBuffer);
+ goto error_oor;
+ }
+ AmountToSend -= AmountLeft;
+ AmountLeft = 0;
+ }
+ } while (AmountLeft && SendTCB->tcb_sendsize);
+
+ SendTCB->tcb_sendbuf = Buf;
+ SendTCB->tcb_sendofs = Offset;
+ }
+
+ if (CurSend->tsr_flags & TSR_FLAG_URG) {
+ ushort UP;
+ // This send is urgent data. We need to figure
+ // out what the urgent data pointer should be.
+ // We know sendnext is the starting sequence
+ // number of the frame, and that at the top of
+ // this do loop sendnext identified a byte in
+ // the CurSend at that time. We advanced CurSend
+ // at the same rate we've decremented
+ // AmountLeft (AmountToSend - AmountLeft ==
+ // AmountBuilt), so sendnext +
+ // (AmountToSend - AmountLeft) identifies a byte
+ // in the current value of CurSend, and that
+ // quantity plus tcb_sendsize is the sequence
+ // number one beyond the current send.
+ UP =
+ (ushort)(AmountToSend - AmountLeft) +
+ (ushort)SendTCB->tcb_sendsize -
+ ((SendTCB->tcb_flags & BSD_URGENT) ? 0 : 1);
+
+ Header->tcp_urgent = net_short(UP);
+
+ Header->tcp_flags |= TCP_FLAG_URG;
+ }
+
+ // See if we've exhausted this send. If we have,
+ // set the PUSH bit in this frame and move on to
+ // the next send. We also need to check the
+ // urgent data bit.
+ if (SendTCB->tcb_sendsize == 0) {
+ Queue *Next;
+ uchar PrevFlags;
+
+ // We've exhausted this send. Set the PUSH bit.
+ Header->tcp_flags |= TCP_FLAG_PUSH;
+ PrevFlags = CurSend->tsr_flags;
+ Next = QNEXT(&CurSend->tsr_req.tr_q);
+ if (Next != QEND(&SendTCB->tcb_sendq)) {
+ CurSend = STRUCT_OF(TCPSendReq,
+ QSTRUCT(TCPReq, Next, tr_q), tsr_req);
+ CTEStructAssert(CurSend, tsr);
+ SendTCB->tcb_sendsize = CurSend->tsr_unasize;
+ SendTCB->tcb_sendofs = CurSend->tsr_offset;
+ SendTCB->tcb_sendbuf = CurSend->tsr_buffer;
+ SendTCB->tcb_cursend = CurSend;
+
+ // Check the urgent flags. We can't combine
+ // new urgent data on to the end of old
+ // non-urgent data.
+ if ((PrevFlags & TSR_FLAG_URG) && !
+ (CurSend->tsr_flags & TSR_FLAG_URG))
+ break;
+ } else {
+ CTEAssert(AmountLeft == 0);
+ SendTCB->tcb_cursend = NULL;
+ SendTCB->tcb_sendbuf = NULL;
+ }
+ }
+ } while (AmountLeft != 0);
+
+ } else {
+
+ // We're in the loop, but AmountToSend is 0. This
+ // should happen only when we're sending a FIN. Check
+ // this, and return if it's not true.
+ CTEAssert(AmtUnsent == 0);
+ if (!(SendTCB->tcb_flags & FIN_NEEDED)) {
+ // DEBUGCHK;
+ FreeTCPHeader(FirstBuffer);
+ break;
+ }
+
+ SCC->scc_firstsend = NULL;
+ NDIS_BUFFER_LINKAGE(FirstBuffer) = NULL;
+ }
+
+ // Adjust for what we're really going to send.
+ AmountToSend -= AmountLeft;
+
+ // Update the sequence numbers, and start a RTT measurement
+ // if needed.
+
+ OldSeq = SendTCB->tcb_sendnext;
+ SendTCB->tcb_sendnext += AmountToSend;
+
+ if (SEQ_EQ(OldSeq, SendTCB->tcb_sendmax)) {
+ // We're sending entirely new data.
+
+ // We can't advance sendmax once FIN_SENT is set.
+ CTEAssert(!(SendTCB->tcb_flags & FIN_SENT));
+ SendTCB->tcb_sendmax = SendTCB->tcb_sendnext;
+ // We've advanced sendmax, so we must be sending some
+ // new data, so bump the outsegs counter.
+ TStats.ts_outsegs++;
+
+ if (SendTCB->tcb_rtt == 0) {
+ // No RTT running, so start one.
+ SendTCB->tcb_rtt = TCPTime;
+ SendTCB->tcb_rttseq = OldSeq;
+ }
+ } else {
+ // We have at least some retransmission.
+
+ TStats.ts_retranssegs++;
+ if (SEQ_GT(SendTCB->tcb_sendnext, SendTCB->tcb_sendmax)) {
+ // But we also have some new data, so check the
+ // rtt stuff.
+ TStats.ts_outsegs++;
+ CTEAssert(!(SendTCB->tcb_flags & FIN_SENT));
+ SendTCB->tcb_sendmax = SendTCB->tcb_sendnext;
+
+ if (SendTCB->tcb_rtt == 0) {
+ // No RTT running, so start one.
+ SendTCB->tcb_rtt = TCPTime;
+ SendTCB->tcb_rttseq = OldSeq;
+ }
+ }
+ }
+
+ // We've built the frame entirely. If we've send everything
+ // we have and their's a FIN pending, OR it in.
+ if (AmtUnsent == AmountToSend) {
+ if (SendTCB->tcb_flags & FIN_NEEDED) {
+ CTEAssert(!(SendTCB->tcb_flags & FIN_SENT) ||
+ (SendTCB->tcb_sendnext == (SendTCB->tcb_sendmax - 1)));
+ // See if we still have room in the window for a FIN.
+ if (SendWin > (int) AmountToSend) {
+ Header->tcp_flags |= TCP_FLAG_FIN;
+ SendTCB->tcb_sendnext++;
+ SendTCB->tcb_sendmax = SendTCB->tcb_sendnext;
+ SendTCB->tcb_flags |= (FIN_SENT | FIN_OUTSTANDING);
+ SendTCB->tcb_flags &= ~FIN_NEEDED;
+ }
+ }
+ }
+
+ AmountToSend += sizeof(TCPHeader);
+
+ if (!TCB_TIMER_RUNNING(SendTCB->tcb_rexmittimer))
+ START_TCB_TIMER(SendTCB->tcb_rexmittimer,
+ SendTCB->tcb_rexmit);
+
+ SendTCB->tcb_flags &= ~(NEED_ACK | ACK_DELAYED |
+ FORCE_OUTPUT);
+ STOP_TCB_TIMER(SendTCB->tcb_delacktimer);
+ STOP_TCB_TIMER(SendTCB->tcb_swstimer);
+ SendTCB->tcb_alive = TCPTime;
+
+ CTEFreeLock(&SendTCB->tcb_lock, TCBHandle);
+
+ // We're all set. Xsum it and send it.
+ Header->tcp_xsum = ~XsumSendChain(SendTCB->tcb_phxsum +
+ (uint)net_short(AmountToSend), FirstBuffer);
+
+ SendStatus = (*LocalNetInfo.ipi_xmit)(TCPProtInfo, SCC,
+ FirstBuffer, AmountToSend, SendTCB->tcb_daddr,
+ SendTCB->tcb_saddr, &SendTCB->tcb_opt, SendTCB->tcb_rce,
+ PROTOCOL_TCP);
+
+ SendTCB->tcb_error = SendStatus;
+ if (SendStatus != IP_PENDING) {
+ TCPSendComplete(SCC, FirstBuffer);
+ if (SendStatus != IP_SUCCESS) {
+ CTEGetLock(&SendTCB->tcb_lock, &TCBHandle);
+ // This packet didn't get sent. If nothing's
+ // changed in the TCB, put sendnext back to
+ // what we just tried to send. Depending on
+ // the error, we may try again.
+ if (SEQ_GTE(OldSeq, SendTCB->tcb_senduna) &&
+ SEQ_LT(OldSeq, SendTCB->tcb_sendnext))
+ ResetSendNext(SendTCB, OldSeq);
+
+ // We know this packet didn't get sent. Start
+ // the retransmit timer now, if it's not already
+ // runnimg, in case someone came in while we
+ // were in IP and stopped it.
+ if (!TCB_TIMER_RUNNING(SendTCB->tcb_rexmittimer))
+ START_TCB_TIMER(SendTCB->tcb_rexmittimer,
+ SendTCB->tcb_rexmit);
+
+ // If it failed because of an MTU problem, get
+ // the new MTU and try again.
+ if (SendStatus == IP_PACKET_TOO_BIG) {
+ uint NewMTU;
+
+ // The MTU has changed. Update it, and try
+ // again.
+ SendStatus = (*LocalNetInfo.ipi_getpinfo)(
+ SendTCB->tcb_daddr, SendTCB->tcb_saddr,
+ &NewMTU, NULL);
+
+ if (SendStatus != IP_SUCCESS)
+ break;
+
+ // We have a new MTU. Make sure it's big enough
+ // to use. If not, correct this and turn off
+ // MTU discovery on this TCB. Otherwise use the
+ // new MTU.
+ if (NewMTU <= (sizeof(TCPHeader) +
+ SendTCB->tcb_opt.ioi_optlength)) {
+
+ // The new MTU is too small to use. Turn off
+ // PMTU discovery on this TCB, and drop to
+ // our off net MTU size.
+ SendTCB->tcb_opt.ioi_flags &= ~IP_FLAG_DF;
+ SendTCB->tcb_mss = MIN((ushort)MAX_REMOTE_MSS,
+ SendTCB->tcb_remmss);
+ } else {
+
+ // The new MTU is adequate. Adjust it for
+ // the header size and options length, and use
+ // it.
+ NewMTU -= sizeof(TCPHeader) -
+ SendTCB->tcb_opt.ioi_optlength;
+ SendTCB->tcb_mss = MIN((ushort)NewMTU,
+ SendTCB->tcb_remmss);
+ }
+
+ CTEAssert(SendTCB->tcb_mss > 0);
+
+ continue;
+ }
+ break;
+ }
+ }
+
+ CTEGetLock(&SendTCB->tcb_lock, &TCBHandle);
+ continue;
+ } else // FirstBuffer != NULL.
+ goto error_oor;
+ } else {
+ // We've decided we can't send anything now. Figure out why, and
+ // see if we need to set a timer.
+ if (SendTCB->tcb_sendwin == 0) {
+ if (!(SendTCB->tcb_flags & FLOW_CNTLD)) {
+ SendTCB->tcb_flags |= FLOW_CNTLD;
+ SendTCB->tcb_rexmitcnt = 0;
+ START_TCB_TIMER(SendTCB->tcb_rexmittimer,
+ SendTCB->tcb_rexmit);
+ SendTCB->tcb_slowcount++;
+ SendTCB->tcb_fastchk |= TCP_FLAG_SLOW;
+ } else
+ if (!TCB_TIMER_RUNNING(SendTCB->tcb_rexmittimer))
+ START_TCB_TIMER(SendTCB->tcb_rexmittimer,
+ SendTCB->tcb_rexmit);
+ } else
+ if (AmountToSend != 0)
+ // We have something to send, but we're not sending
+ // it, presumably due to SWS avoidance.
+ if (!TCB_TIMER_RUNNING(SendTCB->tcb_swstimer))
+ START_TCB_TIMER(SendTCB->tcb_swstimer, SWS_TO);
+
+ break;
+ }
+ } // while (!FIN_OUTSTANDING)
+
+ // We're done sending, so we don't need the output flags set.
+ SendTCB->tcb_flags &= ~(IN_TCP_SEND | NEED_OUTPUT | FORCE_OUTPUT |
+ SEND_AFTER_RCV);
+ } else
+ SendTCB->tcb_flags |= SEND_AFTER_RCV;
+
+ DerefTCB(SendTCB, TCBHandle);
+ return;
+
+// Common case error handling code for out of resource conditions. Start the
+// retransmit timer if it's not already running (so that we try this again
+// later), clean up and return.
+error_oor:
+ if (!TCB_TIMER_RUNNING(SendTCB->tcb_rexmittimer))
+ START_TCB_TIMER(SendTCB->tcb_rexmittimer, SendTCB->tcb_rexmit);
+
+ // We had an out of resource problem, so clear the OUTPUT flags.
+ SendTCB->tcb_flags &= ~(IN_TCP_SEND | NEED_OUTPUT | FORCE_OUTPUT);
+ DerefTCB(SendTCB, TCBHandle);
+ return;
+
+}
+
+
+#if FAST_RETRANSMIT
+//* ResetSendNextAndFastSend - Set the sendnext value of a TCB.
+//
+// Called to handle fast retransmit of the segment which the reveiver
+// is asking for.
+// tcb_lock will be held while entering (called by TCPRcv)
+// and will be released in this routine after doing IP xmit.
+//
+// Input: SeqTCB - Pointer to TCB to be updated.
+// NewSeq - Sequence number to set.
+//
+// Returns: Nothing.
+//
+void
+ResetAndFastSend(TCB *SeqTCB, SeqNum NewSeq)
+{
+
+ TCPSendReq *SendReq;
+ uint AmtForward;
+ Queue *CurQ;
+ PNDIS_BUFFER Buffer;
+ uint Offset;
+ uint SendSize;
+ CTELockHandle TCBHandle;
+
+ CTEStructAssert(SeqTCB, tcb);
+ CTEAssert(SEQ_GTE(NewSeq, SeqTCB->tcb_senduna));
+
+ // The new seq must be less than send max, or NewSeq, senduna, sendnext,
+ // and sendmax must all be equal. (The latter case happens when we're
+ // called exiting TIME_WAIT, or possibly when we're retransmitting
+ // during a flow controlled situation).
+
+ CTEAssert(SEQ_LT(NewSeq, SeqTCB->tcb_sendmax) ||
+ (SEQ_EQ(SeqTCB->tcb_senduna, SeqTCB->tcb_sendnext) &&
+ SEQ_EQ(SeqTCB->tcb_senduna, SeqTCB->tcb_sendmax) &&
+ SEQ_EQ(SeqTCB->tcb_senduna, NewSeq)));
+
+
+
+ //KdPrint(("Resetandfastsend TCB %x, seq %x\n", SeqTCB, NewSeq));
+
+ if (SYNC_STATE(SeqTCB->tcb_state) && SeqTCB->tcb_state != TCB_TIME_WAIT) {
+ // In these states we need to update the send queue.
+
+ if (!EMPTYQ(&SeqTCB->tcb_sendq)) {
+
+ CurQ = QHEAD(&SeqTCB->tcb_sendq);
+
+ SendReq = (TCPSendReq *)STRUCT_OF(TCPReq, CurQ, tr_q);
+
+ // SendReq points to the first send request on the send queue.
+ // We're pointing at the proper send req now. We need to go down
+
+ // SendReq points to the cursend
+ // SendSize point to sendsize in the cursend
+
+ SendSize = SendReq->tsr_unasize;
+
+ Buffer = SendReq->tsr_buffer;
+ Offset = SendReq->tsr_offset;
+
+ // Call the fast retransmit send now
+
+ //KdPrint(("Calling fastsend buf %x, Offset %x\n", Buffer,Offset));
+
+ TCPFastSend(SeqTCB, Buffer, Offset, SendReq, SendSize);
+
+
+ } else {
+
+ CTEAssert(SeqTCB->tcb_cursend == NULL);
+ }
+
+ }
+
+#ifndef VXD
+ TCBHandle = DISPATCH_LEVEL;
+#endif
+
+ DerefTCB(SeqTCB, TCBHandle);
+ return;
+
+}
+
+//* TCPFastSend - To send a segment without changing TCB state
+//
+// Called to handle fast retransmit of the segment
+// tcb_lock will be held while entering (called by TCPRcv)
+//
+// Input: SendTCB - Pointer to TCB
+// in_sendBuf - Pointer to ndis_buffer
+// in_sendofs - Send Offset
+// in_sendreq - current send request
+// in_sendsize - size of this send
+//
+// Returns: Nothing.
+//
+
+void
+TCPFastSend(TCB *SendTCB,
+ PNDIS_BUFFER in_SendBuf,
+ uint in_SendOfs,
+ TCPSendReq *in_SendReq,
+ uint in_SendSize)
+{
+
+ int SendWin; // Useable send window.
+ uint AmountToSend; // Amount to send this time.
+ uint AmountLeft;
+ TCPHeader *Header; // TCP header for a send.
+ PNDIS_BUFFER FirstBuffer, CurrentBuffer;
+ TCPSendReq *CurSend;
+ SendCmpltContext *SCC;
+ SeqNum OldSeq;
+ IP_STATUS SendStatus;
+ uint AmtOutstanding, AmtUnsent;
+ int ForceWin; // Window we're force to use.
+ CTELockHandle TCBHandle;
+
+ uint SendOfs = in_SendOfs;
+ uint SendSize = in_SendSize;
+ PNDIS_BUFFER SendBuf;
+
+#ifndef VXD
+ TCBHandle = DISPATCH_LEVEL;
+#endif
+
+
+ CTEStructAssert(SendTCB, tcb);
+ CTEAssert(SendTCB->tcb_refcnt != 0);
+
+ CTEAssert(*(int *)&SendTCB->tcb_sendwin >= 0);
+ CTEAssert(*(int *)&SendTCB->tcb_cwin >= SendTCB->tcb_mss);
+
+ CTEAssert(!(SendTCB->tcb_flags & FIN_OUTSTANDING) ||
+ (SendTCB->tcb_sendnext == SendTCB->tcb_sendmax));
+
+
+
+ AmtOutstanding = (uint)(SendTCB->tcb_sendnext -
+ SendTCB->tcb_senduna);
+
+ AmtUnsent = SendTCB->tcb_unacked - AmtOutstanding;
+
+ CTEAssert(*(int *)&AmtUnsent >= 0);
+
+ SendWin = SendTCB->tcb_mss;
+
+
+ AmountToSend = MIN(in_SendSize, SendTCB->tcb_mss);
+
+ CTEAssert (AmountToSend >= 0);
+
+
+ CTEAssert(SendTCB->tcb_mss > 0);
+
+ // See if we have enough to send. We'll send if we have at least a
+ // segment, or if we really have some data to send and we can send
+ // all that we have, or the send window is > 0 and we need to force
+ // output or send a FIN (note that if we need to force output
+ // SendWin will be at least 1 from the check above), or if we can
+ // send an amount == to at least half the maximum send window
+ // we've seen.
+
+ //KdPrint(("In fastsend Sendwin %x, Amttosend %x\n", SendWin,AmountToSend));
+
+ if (AmountToSend >= 0) {
+
+
+ // It's OK to send something. Try to get a header buffer now.
+ // Mark the TCB for debugging.
+ // This should be removed for shipping version.
+
+ SendTCB->tcb_fastchk |= TCP_FLAG_FASTREC;
+
+ FirstBuffer = GetTCPHeader();
+
+ if (FirstBuffer != NULL) {
+
+ // Got a header buffer. Loop through the sends on the TCB,
+ // building a frame.
+
+ CurrentBuffer = FirstBuffer;
+ CurSend = in_SendReq;
+ SendOfs = in_SendOfs;
+
+ Header = (TCPHeader *)(
+ (uchar *)NdisBufferVirtualAddress(FirstBuffer) +
+ LocalNetInfo.ipi_hsize);
+
+ SCC = (SendCmpltContext *)(Header + 1);
+
+#ifdef DEBUG
+ SCC->scc_sig = scc_signature;
+#endif
+ FillTCPHeader(SendTCB, Header);
+ {
+ ulong L = SendTCB->tcb_senduna;
+ Header->tcp_seq = net_long(L);
+
+ }
+
+ SCC->scc_ubufcount = 0;
+ SCC->scc_tbufcount = 0;
+ SCC->scc_count = 0;
+
+ AmountLeft = AmountToSend;
+
+ if (AmountToSend != 0) {
+ long Result;
+
+ CTEStructAssert(CurSend, tsr);
+ SCC->scc_firstsend = CurSend;
+
+ do {
+
+ CTEAssert(CurSend->tsr_refcnt > 0);
+
+ Result = CTEInterlockedIncrementLong(
+ &(CurSend->tsr_refcnt)
+ );
+
+ CTEAssert(Result > 0);
+
+ SCC->scc_count++;
+
+ // If the current send offset is 0 and the current
+ // send is less than or equal to what we have left
+ // to send, we haven't already put a transport
+ // buffer on this send, and nobody else is using
+ // the buffer chain directly, just use the input
+ // buffers. We check for other people using them
+ // by looking at tsr_lastbuf. If it's NULL,
+ // nobody else is using the buffers. If it's not
+ // NULL, somebody is.
+
+ if (SendOfs == 0 &&
+ (SendSize <= AmountLeft) &&
+ (SCC->scc_tbufcount == 0) &&
+ CurSend->tsr_lastbuf == NULL) {
+
+ NDIS_BUFFER_LINKAGE(CurrentBuffer) = in_SendBuf;
+
+ do {
+ SCC->scc_ubufcount++;
+ CurrentBuffer = NDIS_BUFFER_LINKAGE(CurrentBuffer);
+ } while (NDIS_BUFFER_LINKAGE(CurrentBuffer) != NULL);
+
+ CurSend->tsr_lastbuf = CurrentBuffer;
+ AmountLeft -= SendSize;
+ //KdPrint(("nobody using this CurSend %x\n",CurSend ));
+ // SendSize = 0;
+ } else {
+ uint AmountToDup;
+ PNDIS_BUFFER NewBuf, Buf;
+ uint Offset;
+ NDIS_STATUS NStatus;
+ uchar *VirtualAddress;
+ uint Length;
+
+ // Either the current send has more data than
+ // we want to send, or the starting offset is
+ // not 0. In either case we'll need to loop
+ // through the current send, allocating buffers.
+
+ Buf = in_SendBuf;
+
+ Offset = SendOfs;
+
+ do {
+ CTEAssert(Buf != NULL);
+
+ NdisQueryBuffer(Buf, &VirtualAddress,
+ &Length);
+
+ CTEAssert((Offset < Length) ||
+ (Offset == 0 && Length == 0));
+
+ // Adjust the length for the offset into
+ // this buffer.
+
+ Length -= Offset;
+
+ AmountToDup = MIN(AmountLeft, Length);
+
+ NdisAllocateBuffer(&NStatus, &NewBuf,
+ TCPSendBufferPool,
+ VirtualAddress + Offset,
+ AmountToDup);
+
+ if (NStatus == NDIS_STATUS_SUCCESS) {
+
+ SCC->scc_tbufcount++;
+
+ NDIS_BUFFER_LINKAGE(CurrentBuffer) = NewBuf;
+
+ CurrentBuffer = NewBuf;
+
+ if (AmountToDup >= Length) {
+
+ // Exhausted this buffer.
+
+ Buf = NDIS_BUFFER_LINKAGE(Buf);
+ Offset = 0;
+
+ } else {
+
+ Offset += AmountToDup;
+ CTEAssert(Offset < NdisBufferLength(Buf));
+ }
+
+ SendSize -= AmountToDup;
+ AmountLeft -= AmountToDup;
+
+ } else {
+
+ // Couldn't allocate a buffer. If
+ // the packet is already partly built,
+ // send what we've got, otherwise
+ // bail out.
+
+ if (SCC->scc_tbufcount == 0 &&
+ SCC->scc_ubufcount == 0) {
+ TCPSendComplete(SCC, FirstBuffer);
+ goto error_oor;
+ }
+
+ AmountToSend -= AmountLeft;
+ AmountLeft = 0;
+
+ }
+ } while (AmountLeft && SendSize);
+
+ SendBuf = Buf;
+ SendOfs = Offset;
+ //KdPrint(("Ready to send. SendBuf %x SendOfs %x\n",SendBuf, SendOfs ));
+
+ }
+
+ if (CurSend->tsr_flags & TSR_FLAG_URG) {
+ ushort UP;
+
+ KdPrint(("Fast send in URG %x\n", CurSend));
+
+ // This send is urgent data. We need to figure
+ // out what the urgent data pointer should be.
+ // We know sendnext is the starting sequence
+ // number of the frame, and that at the top of
+ // this do loop sendnext identified a byte in
+ // the CurSend at that time. We advanced CurSend
+ // at the same rate we've decremented
+ // AmountLeft (AmountToSend - AmountLeft ==
+ // AmountBuilt), so sendnext +
+ // (AmountToSend - AmountLeft) identifies a byte
+ // in the current value of CurSend, and that
+ // quantity plus tcb_sendsize is the sequence
+ // number one beyond the current send.
+
+ UP =
+ (ushort)(AmountToSend - AmountLeft) +
+ (ushort)SendTCB->tcb_sendsize -
+ ((SendTCB->tcb_flags & BSD_URGENT) ? 0 : 1);
+
+ Header->tcp_urgent = net_short(UP);
+
+ Header->tcp_flags |= TCP_FLAG_URG;
+ }
+
+ // See if we've exhausted this send. If we have,
+ // set the PUSH bit in this frame and move on to
+ // the next send. We also need to check the
+ // urgent data bit.
+
+ if (SendSize == 0) {
+ Queue *Next;
+ uchar PrevFlags;
+
+ // We've exhausted this send. Set the PUSH bit.
+ Header->tcp_flags |= TCP_FLAG_PUSH;
+ PrevFlags = CurSend->tsr_flags;
+ Next = QNEXT(&CurSend->tsr_req.tr_q);
+ if (Next != QEND(&SendTCB->tcb_sendq)) {
+ CurSend = STRUCT_OF(TCPSendReq,
+ QSTRUCT(TCPReq, Next, tr_q), tsr_req);
+ CTEStructAssert(CurSend, tsr);
+ SendSize = CurSend->tsr_unasize;
+ SendOfs = CurSend->tsr_offset;
+ SendBuf = CurSend->tsr_buffer;
+ CurSend = CurSend;
+
+ // Check the urgent flags. We can't combine
+ // new urgent data on to the end of old
+ // non-urgent data.
+ if ((PrevFlags & TSR_FLAG_URG) && !
+ (CurSend->tsr_flags & TSR_FLAG_URG))
+ break;
+ } else {
+ CTEAssert(AmountLeft == 0);
+ CurSend = NULL;
+ SendBuf = NULL;
+ }
+ }
+
+ } while (AmountLeft != 0);
+
+ } else {
+
+ // Amt to send is 0.
+ // Just bail out and strat timer.
+
+ if (!TCB_TIMER_RUNNING(SendTCB->tcb_rexmittimer))
+ START_TCB_TIMER(SendTCB->tcb_rexmittimer, SendTCB->tcb_rexmit);
+
+ FreeTCPHeader(FirstBuffer);
+ return;
+
+ }
+
+ // Adjust for what we're really going to send.
+
+ AmountToSend -= AmountLeft;
+
+
+ TStats.ts_retranssegs++;
+
+ // We've built the frame entirely. If we've send everything
+ // we have and their's a FIN pending, OR it in.
+
+ AmountToSend += sizeof(TCPHeader);
+
+
+ SendTCB->tcb_flags &= ~(NEED_ACK | ACK_DELAYED |
+ FORCE_OUTPUT);
+
+
+
+ STOP_TCB_TIMER(SendTCB->tcb_delacktimer);
+ STOP_TCB_TIMER(SendTCB->tcb_swstimer);
+
+ SendTCB->tcb_alive = TCPTime;
+
+ SendTCB->tcb_fastchk &= ~TCP_FLAG_FASTREC;
+
+ CTEFreeLock(&SendTCB->tcb_lock, TCBHandle);
+
+ //KdPrint (("Going out to IP SendTCB %x, Firstbuf %x\n", SendTCB, FirstBuffer));
+ // We're all set. Xsum it and send it.
+
+ Header->tcp_xsum = ~XsumSendChain(SendTCB->tcb_phxsum +
+ (uint)net_short(AmountToSend), FirstBuffer);
+
+ SendStatus = (*LocalNetInfo.ipi_xmit)(TCPProtInfo, SCC,
+ FirstBuffer, AmountToSend, SendTCB->tcb_daddr,
+ SendTCB->tcb_saddr, &SendTCB->tcb_opt, SendTCB->tcb_rce,
+ PROTOCOL_TCP);
+
+ SendTCB->tcb_error = SendStatus;
+ if (!TCB_TIMER_RUNNING(SendTCB->tcb_rexmittimer))
+ START_TCB_TIMER(SendTCB->tcb_rexmittimer, SendTCB->tcb_rexmit);
+
+
+ if (SendStatus != IP_PENDING) {
+ TCPSendComplete(SCC, FirstBuffer);
+ }
+
+ //Reacquire Lock to keep DerefTCB happy
+ //Bug #63904
+
+ CTEGetLock(&SendTCB->tcb_lock, &TCBHandle);
+
+
+ } else { // FirstBuffer != NULL.
+ goto error_oor;
+ }
+ } else{
+
+ SendTCB->tcb_flags |= SEND_AFTER_RCV;
+ if (!TCB_TIMER_RUNNING(SendTCB->tcb_rexmittimer))
+ START_TCB_TIMER(SendTCB->tcb_rexmittimer, SendTCB->tcb_rexmit);
+
+ }
+
+
+ SendTCB->tcb_flags |= NEED_OUTPUT;
+
+ return;
+
+// Common case error handling code for out of resource conditions. Start the
+// retransmit timer if it's not already running (so that we try this again
+// later), clean up and return.
+
+error_oor:
+ if (!TCB_TIMER_RUNNING(SendTCB->tcb_rexmittimer))
+ START_TCB_TIMER(SendTCB->tcb_rexmittimer, SendTCB->tcb_rexmit);
+
+ // We had an out of resource problem, so clear the OUTPUT flags.
+ SendTCB->tcb_flags &= ~(IN_TCP_SEND | NEED_OUTPUT | FORCE_OUTPUT);
+
+ return;
+
+
+}
+
+#endif //FAST_RETRANSMIT
+
+
+
+
+//* TDISend - Send data on a connection.
+//
+// The main TDI send entry point. We take the input parameters, validate them,
+// allocate a send request, etc. We then put the send request on the queue.
+// If we have no other sends on the queue or Nagling is disabled we'll
+// call TCPSend to send the data.
+//
+// Input: Request - The TDI request for the call.
+// Flags - Flags for this send.
+// SendLength - Length in bytes of send.
+// SendBuffer - Pointer to buffer chain to be sent.
+//
+// Returns: Status of attempt to send.
+//
+TDI_STATUS
+TdiSend(PTDI_REQUEST Request, ushort Flags, uint SendLength,
+ PNDIS_BUFFER SendBuffer)
+{
+ TCPConn *Conn;
+ TCB *SendTCB;
+ TCPSendReq *SendReq;
+ CTELockHandle ConnTableHandle, TCBHandle;
+ TDI_STATUS Error;
+ uint EmptyQ;
+
+#ifdef DEBUG
+ uint RealSendSize;
+ PNDIS_BUFFER Temp;
+
+ // Loop through the buffer chain, and make sure that the length matches
+ // up with SendLength.
+
+ Temp = SendBuffer;
+ RealSendSize = 0;
+ do {
+ CTEAssert(Temp != NULL);
+
+ RealSendSize += NdisBufferLength(Temp);
+ Temp = NDIS_BUFFER_LINKAGE(Temp);
+ } while (Temp != NULL);
+
+ CTEAssert(RealSendSize == SendLength);
+
+#endif
+
+
+ CTEGetLock(&ConnTableLock, &ConnTableHandle);
+
+ Conn = GetConnFromConnID((uint)Request->Handle.ConnectionContext);
+
+ if (Conn != NULL) {
+ CTEStructAssert(Conn, tc);
+
+ SendTCB = Conn->tc_tcb;
+ if (SendTCB != NULL) {
+ CTEStructAssert(SendTCB, tcb);
+ CTEGetLockAtDPC(&SendTCB->tcb_lock, &TCBHandle);
+ CTEFreeLockFromDPC(&ConnTableLock, TCBHandle);
+ if (DATA_SEND_STATE(SendTCB->tcb_state) && !CLOSING(SendTCB)) {
+ // We have a TCB, and it's valid. Get a send request now.
+
+ CheckTCBSends(SendTCB);
+
+ if (SendLength != 0) {
+
+ SendReq = GetSendReq();
+ if (SendReq != NULL) {
+ SendReq->tsr_req.tr_rtn = Request->RequestNotifyObject;
+ SendReq->tsr_req.tr_context = Request->RequestContext;
+ SendReq->tsr_buffer = SendBuffer;
+ SendReq->tsr_size = SendLength;
+ SendReq->tsr_unasize = SendLength;
+ SendReq->tsr_refcnt = 1; // ACK will decrement this ref
+ SendReq->tsr_offset = 0;
+ SendReq->tsr_lastbuf = NULL;
+ SendReq->tsr_time = TCPTime;
+ SendReq->tsr_flags = (Flags & TDI_SEND_EXPEDITED) ?
+ TSR_FLAG_URG : 0;
+ SendTCB->tcb_unacked += SendLength;
+
+ EmptyQ = EMPTYQ(&SendTCB->tcb_sendq);
+ ENQUEUE(&SendTCB->tcb_sendq, &SendReq->tsr_req.tr_q);
+ if (SendTCB->tcb_cursend == NULL) {
+ SendTCB->tcb_cursend = SendReq;
+ SendTCB->tcb_sendbuf = SendBuffer;
+ SendTCB->tcb_sendofs = 0;
+ SendTCB->tcb_sendsize = SendLength;
+ }
+ if (EmptyQ) {
+ SendTCB->tcb_refcnt++;
+#ifdef VXD
+ CTEFreeLock(&SendTCB->tcb_lock, ConnTableHandle);
+ TCPSend(SendTCB);
+#else
+ TCPSend(SendTCB, ConnTableHandle);
+#endif
+ } else
+ if (!(SendTCB->tcb_flags & NAGLING) ||
+ (SendTCB->tcb_unacked - (SendTCB->tcb_sendmax -
+ SendTCB->tcb_senduna)) >= SendTCB->tcb_mss) {
+ SendTCB->tcb_refcnt++;
+#ifdef VXD
+ CTEFreeLock(&SendTCB->tcb_lock,
+ ConnTableHandle);
+ TCPSend(SendTCB);
+#else
+ TCPSend(SendTCB, ConnTableHandle);
+#endif
+ } else
+ CTEFreeLock(&SendTCB->tcb_lock,
+ ConnTableHandle);
+
+ return TDI_PENDING;
+ } else
+ Error = TDI_NO_RESOURCES;
+ } else
+ Error = TDI_SUCCESS;
+ } else
+ Error = TDI_INVALID_STATE;
+
+ CTEFreeLock(&SendTCB->tcb_lock, ConnTableHandle);
+ return Error;
+ } else
+ Error = TDI_INVALID_STATE;
+ } else
+ Error = TDI_INVALID_CONNECTION;
+
+ CTEFreeLock(&ConnTableLock, ConnTableHandle);
+ return Error;
+
+}
+
+#pragma BEGIN_INIT
+extern void *TLRegisterProtocol(uchar Protocol, void *RcvHandler,
+ void *XmitHandler, void *StatusHandler,
+ void *RcvCmpltHandler);
+
+extern IP_STATUS TCPRcv(void *IPContext, IPAddr Dest, IPAddr Src,
+ IPAddr LocalAddr, IPAddr SrcAddr,
+ IPHeader UNALIGNED *IPH, uint IPHLength,
+ IPRcvBuf *RcvBuf, uint Size, uchar IsBCast,
+ uchar Protocol, IPOptInfo *OptInfo);
+extern void TCPRcvComplete(void);
+
+uchar SendInited = FALSE;
+
+//* FreeTCPHeaderList - Free the list of TCP header buffers.
+//
+// Called when we want to free the list of TCP header buffers.
+//
+// Input: Nothing.
+//
+// Returns: Nothing.
+//
+void
+FreeTCPHeaderList(void)
+{
+ CTELockHandle Handle;
+ TCPHdrBPoolEntry *Entry;
+
+ CTEGetLock(&TCPSendFreeLock, &Handle);
+
+ Entry = TCPHdrBPoolList;
+ TCPHdrBPoolList = NULL;
+
+ TCPCurrentSendFree = 0;
+
+ while (Entry != NULL) {
+ TCPHdrBPoolEntry *OldEntry;
+
+ NdisFreeBufferPool(Entry->the_handle);
+ CTEFreeMem(Entry->the_buffer);
+ OldEntry = Entry;
+ Entry = Entry->the_next;
+ CTEFreeMem(OldEntry);
+ }
+
+ CTEFreeLock(&TCPSendFreeLock, Handle);
+
+
+}
+
+//* InitTCPSend - Initialize our send side.
+//
+// Called during init time to initialize our TCP send state.
+//
+// Input: Nothing.
+//
+// Returns: TRUE if we inited, false if we didn't.
+//
+int
+InitTCPSend(void)
+{
+ PNDIS_BUFFER Buffer;
+ NDIS_STATUS Status;
+
+
+#ifdef NT
+ ExInitializeSListHead(&TCPSendFree);
+ ExInitializeSListHead(&TCPSendReqFree);
+#endif
+
+ CTEInitLock(&TCPSendReqFreeLock);
+ CTEInitLock(&TCPSendFreeLock);
+ CTEInitLock(&TCPSendReqCompleteLock);
+
+ TCPHdrBPoolList = NULL;
+ TCPCurrentSendFree = 0;
+
+ Buffer = GrowTCPHeaderList();
+
+ if (Buffer != NULL)
+ FreeTCPHeader(Buffer);
+ else
+ return FALSE;
+
+ NdisAllocateBufferPool(&Status, &TCPSendBufferPool, NUM_TCP_BUFFERS);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ FreeTCPHeaderList();
+ return FALSE;
+ }
+
+ TCPProtInfo = TLRegisterProtocol(PROTOCOL_TCP, TCPRcv, TCPSendComplete,
+ TCPStatus, TCPRcvComplete);
+
+ if (TCPProtInfo == NULL) {
+ FreeTCPHeaderList();
+ NdisFreeBufferPool(TCPSendBufferPool);
+ return FALSE;
+ }
+
+ SendInited = TRUE;
+ return TRUE;
+}
+
+//* UnInitTCPSend - UnInitialize our send side.
+//
+// Called during init time if we're going to fail to initialize.
+//
+// Input: Nothing.
+//
+// Returns: TRUE if we inited, false if we didn't.
+//
+void
+UnInitTCPSend(void)
+{
+ if (!SendInited)
+ return;
+
+ TLRegisterProtocol(PROTOCOL_TCP, NULL, NULL, NULL, NULL);
+ FreeTCPHeaderList();
+ NdisFreeBufferPool(TCPSendBufferPool);
+
+}
+#pragma END_INIT
+
diff --git a/private/ntos/tdi/tcpip/tcp/tcpsend.h b/private/ntos/tdi/tcpip/tcp/tcpsend.h
new file mode 100644
index 000000000..b74c69861
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/tcpsend.h
@@ -0,0 +1,105 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** TCPSEND.H - TCP send protocol definitions.
+//
+// This file contains the definitions of TCP send protocol things.
+//
+
+#ifdef NT
+
+#define NUM_TCP_HEADERS 32
+#define NUM_TCP_BUFFERS 150
+#define TCP_MAX_HDRS 0xffffffff
+
+#else // NT
+
+#define NUM_TCP_HEADERS 16
+#define NUM_TCP_BUFFERS 100
+#define TCP_MAX_HDRS 320
+
+#endif // NT
+
+//#define SEND_DEBUG 1
+
+#ifdef SEND_DEBUG
+#define SEND_TICKS 10
+EXTERNAL_LOCK(SendUseLock)
+extern struct TCPSendReq *SendUseList;
+#endif
+
+//* Structure of a TCP send request.
+
+#define tsr_signature 0x20525354 // 'TSR '
+
+typedef struct TCPSendReq {
+ struct TCPReq tsr_req; // General request structure.
+#ifdef DEBUG
+ ulong tsr_sig;
+#endif
+ uint tsr_size; // Size in bytes of data in send.
+ long tsr_refcnt; // Reference count for this send.
+ uchar tsr_flags; // Flags for this send.
+ uchar tsr_pad[3]; // Pad to dword boundary.
+ uint tsr_unasize; // Number of bytes unacked.
+ uint tsr_offset; // Offset into first buffer in chain
+ // of start of unacked data..
+ PNDIS_BUFFER tsr_buffer; // Pointer to start of unacked buffer
+ // chain.
+ PNDIS_BUFFER tsr_lastbuf; // Pointer to last buffer in chain.
+ // Valid iff we've sent directly from
+ // the buffer chain w/o doing an
+ // NdisCopyBuffer.
+ uint tsr_time; // TCP time this was received.
+#ifdef SEND_DEBUG
+ struct TCPSendReq *tsr_next; // Debug next field.
+ uint tsr_timer; // Timer field.
+ uint tsr_cmplt; // Who completed it.
+#endif
+} TCPSendReq;
+
+#define TSR_FLAG_URG 0x01 // Urgent data.
+
+//* Structure defining the context received during a send completes.
+
+#define scc_signature 0x20434353 // 'SCC '
+
+typedef struct SendCmpltContext {
+#ifdef DEBUG
+ ulong scc_sig;
+#endif
+
+ TCPSendReq *scc_firstsend; // First send in this context.
+ uint scc_count; // Number of sends in count.
+ ushort scc_ubufcount; // Number of 'user' buffers in send.
+ ushort scc_tbufcount; // Number of transport buffers in send.
+} SendCmpltContext;
+
+EXTERNAL_LOCK(TCPSendReqCompleteLock)
+
+extern void InitSendState(struct TCB *NewTCB);
+extern void SendSYN(struct TCB *SYNTcb, CTELockHandle);
+extern void SendKA(struct TCB *KATCB, CTELockHandle Handle);
+extern void SendRSTFromHeader(struct TCPHeader UNALIGNED *TCPH, uint Length,
+ IPAddr Dest, IPAddr Src, IPOptInfo *OptInfo);
+extern void SendACK(struct TCB *ACKTcb);
+extern void SendRSTFromTCB(struct TCB *RSTTcb);
+extern void GoToEstab(struct TCB *EstabTCB);
+extern void FreeSendReq(TCPSendReq *FreedReq);
+extern void FreeTCPHeader(PNDIS_BUFFER FreedBuffer);
+
+extern int InitTCPSend(void);
+extern void UnInitTCPSend(void);
+
+#ifdef VXD
+extern void TCPSend(struct TCB *SendTCB);
+#else
+extern void TCPSend(struct TCB *SendTCB, CTELockHandle Handle);
+#endif
+
+extern TDI_STATUS TdiSend(PTDI_REQUEST Request, ushort Flags, uint SendLength,
+ PNDIS_BUFFER SendBuffer);
+extern uint RcvWin(struct TCB *WinTCB);
diff --git a/private/ntos/tdi/tcpip/tcp/tlcommon.c b/private/ntos/tdi/tcpip/tcp/tlcommon.c
new file mode 100644
index 000000000..902378004
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/tlcommon.c
@@ -0,0 +1,553 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** TLCOMMON.C - Common transport layer code.
+//
+// This file contains the code for routines that are common to
+// both TCP and UDP.
+//
+#include "oscfg.h"
+#include "ndis.h"
+#include "cxport.h"
+#include "ip.h"
+#include "tdi.h"
+#include "tdistat.h"
+#ifdef NT
+#include "tdikrnl.h"
+#endif
+#include "tlcommon.h"
+
+extern uint tcpxsum(uint Seed, void *Ptr, uint Length);
+extern IPInfo LocalNetInfo;
+
+//* XsumSendChain - Checksum a chain of NDIS send buffers.
+//
+// Called to xsum a chain of NDIS send buffers. We're given the
+// pseudo-header xsum to start with, and we call xsum on each
+// buffer. We assume that this is a send chain, and that the
+// first buffer of the chain has room for an IP header that we
+// need to skip.
+//
+// Input: PHXsum - Pseudo-header xsum.
+// BufChain - Pointer to NDIS_BUFFER chain.
+//
+// Returns: The computed xsum.
+//
+
+ushort
+XsumSendChain(uint PHXsum, PNDIS_BUFFER BufChain)
+{
+ uint HeaderSize;
+ uint OldLength;
+ uint SwapCount;
+ uchar *Ptr;
+
+ HeaderSize = LocalNetInfo.ipi_hsize;
+ OldLength = 0;
+ SwapCount = 0;
+
+ //
+ // ***** The following line of code can be removed if the pseudo
+ // checksum never has any bits sets in the upper word.
+ //
+
+ PHXsum = (((PHXsum << 16) | (PHXsum >> 16)) + PHXsum) >> 16;
+ do {
+
+ //
+ // If the length of the last buffer was odd, then swap the checksum.
+ //
+
+ if ((OldLength & 1) != 0) {
+ PHXsum = ((PHXsum & 0xff) << 8) | (PHXsum >> 8);
+ SwapCount ^= 1;
+ }
+
+ Ptr = (uchar *)NdisBufferVirtualAddress(BufChain) + HeaderSize;
+ PHXsum = tcpxsum(PHXsum, Ptr, NdisBufferLength(BufChain));
+ HeaderSize = 0;
+ OldLength = NdisBufferLength(BufChain);
+ BufChain = NDIS_BUFFER_LINKAGE(BufChain);
+ } while(BufChain != NULL);
+
+ //
+ // If an odd number of swaps were done, then swap the xsum again.
+ //
+ // N.B. At this point the checksum is only a word.
+ //
+
+ if (SwapCount != 0) {
+ PHXsum = ((PHXsum & 0xff) << 8) | (PHXsum >> 8);
+ }
+
+ return (ushort)PHXsum;
+}
+
+//* XsumRcvBuf - Checksum a chain of IP receive buffers.
+//
+// Called to xsum a chain of IP receive buffers. We're given the
+// pseudo-header xsum to start with, and we call xsum on each buffer.
+//
+// We assume that this rcv buf chain has no odd sized buffers, except
+// possibly the last one.
+//
+// Input: PHXsum - Pseudo-header xsum.
+// BufChain - Pointer to IPRcvBuf chain.
+//
+// Returns: The computed xsum.
+//
+
+ushort
+XsumRcvBuf(uint PHXsum, IPRcvBuf *BufChain)
+{
+
+ //
+ // ***** The following line of code can be removed if the pseudo
+ // checksum never has any bits sets in the upper word.
+ //
+
+ PHXsum = (((PHXsum << 16) | (PHXsum >> 16)) + PHXsum) >> 16;
+ do {
+ CTEAssert(!(BufChain->ipr_size & 1) || (BufChain->ipr_next == NULL));
+
+ PHXsum = tcpxsum(PHXsum, BufChain->ipr_buffer, BufChain->ipr_size);
+ BufChain = BufChain->ipr_next;
+ } while (BufChain != NULL);
+
+ return (ushort)(PHXsum);
+}
+
+
+//* CopyRcvToNdis - Copy from an IPRcvBuf chain to an NDIS buffer chain.
+//
+// This is the function we use to copy from a chain of IP receive buffers
+// to a chain of NDIS buffers. The caller specifies the source and destination,
+// a maximum size to copy, and an offset into the first buffer to start
+// copying from. We copy as much as possible up to the size, and return
+// the size copied.
+//
+// Input: RcvBuf - Pointer to receive buffer chain.
+// DestBuf - Pointer to NDIS buffer chain.
+// Size - Size in bytes to copy.
+// RcvOffset - Offset into first buffer to copy from.
+// DestOffset - Offset into dest buffer to start copying at.
+//
+// Returns: Bytes copied.
+//
+
+#ifdef NT
+
+uint
+CopyRcvToNdis(IPRcvBuf *RcvBuf, PNDIS_BUFFER DestBuf, uint Size,
+ uint RcvOffset, uint DestOffset)
+{
+ uint TotalBytesCopied = 0; // Bytes we've copied so far.
+ uint BytesCopied = 0; // Bytes copied out of each buffer.
+ uint DestSize, RcvSize; // Size left in current destination and
+ // recv. buffers, respectively.
+ uint BytesToCopy; // How many bytes to copy this time.
+ NTSTATUS Status;
+
+
+ CTEAssert(RcvBuf != NULL);
+
+ CTEAssert(RcvOffset <= RcvBuf->ipr_size);
+
+ // The destination buffer can be NULL - this is valid, if odd.
+ if (DestBuf != NULL) {
+
+ RcvSize = RcvBuf->ipr_size - RcvOffset;
+ DestSize = NdisBufferLength(DestBuf);
+
+ if (Size < DestSize) {
+ DestSize = Size;
+ }
+
+ do {
+ // Compute the amount to copy, and then copy from the
+ // appropriate offsets.
+ BytesToCopy = MIN(DestSize, RcvSize);
+
+ Status = TdiCopyBufferToMdl(RcvBuf->ipr_buffer, RcvOffset,
+ BytesToCopy, DestBuf, DestOffset, &BytesCopied);
+
+ if (!NT_SUCCESS(Status)) {
+ break;
+ }
+
+ CTEAssert(BytesCopied == BytesToCopy);
+
+ TotalBytesCopied += BytesCopied;
+ DestSize -= BytesCopied;
+ DestOffset += BytesCopied;
+ RcvSize -= BytesToCopy;
+
+ if (!RcvSize) {
+ // Exhausted this buffer.
+
+ RcvBuf = RcvBuf->ipr_next;
+
+ // If we have another one, use it.
+ if (RcvBuf != NULL) {
+ RcvOffset = 0;
+ RcvSize = RcvBuf->ipr_size;
+ }
+ else {
+ break;
+ }
+ }
+ else { // Buffer not exhausted, update offset.
+ RcvOffset += BytesToCopy;
+ }
+
+ } while (DestSize);
+
+ }
+
+ return TotalBytesCopied;
+
+
+}
+
+#else // NT
+
+uint
+CopyRcvToNdis(IPRcvBuf *RcvBuf, PNDIS_BUFFER DestBuf, uint Size,
+ uint RcvOffset, uint DestOffset)
+{
+ uint BytesCopied = 0; // Bytes we've copied so far.
+ uint DestSize, RcvSize; // Size left in current destination and
+ // recv. buffers, respectively.
+ uint BytesToCopy; // How many bytes to copy this time.
+
+ CTEAssert(RcvBuf != NULL);
+
+ CTEAssert(RcvOffset <= RcvBuf->ipr_size);
+
+ // The destination buffer can be NULL - this is valid, if odd.
+ if (DestBuf != NULL) {
+
+ DestSize = NdisBufferLength(DestBuf);
+ RcvSize = RcvBuf->ipr_size - RcvOffset;
+
+ //
+ // Skip over DestOffset bytes
+ //
+ while (DestOffset >= DestSize) {
+ DestOffset -= DestSize;
+ DestBuf = NDIS_BUFFER_LINKAGE(DestBuf);
+
+ if (DestBuf == NULL) {
+ return(0);
+ }
+
+ DestSize = NdisBufferLength(DestBuf);
+ }
+
+ DestSize -= DestOffset;
+
+ do {
+
+ // Compute the amount to copy, and then copy from the
+ // appropriate offsets.
+ BytesToCopy = MIN(MIN(DestSize, RcvSize), Size);
+
+ // Do the copy using the intrinsic - we might want to
+ // do this with a function that does a smarter job of
+ // copying.
+
+ CTEMemCopy((uchar *)NdisBufferVirtualAddress(DestBuf) + DestOffset,
+ RcvBuf->ipr_buffer + RcvOffset, BytesToCopy);
+
+ BytesCopied += BytesToCopy;
+
+ if (!(RcvSize -= BytesToCopy)) {
+ // Exhausted this buffer.
+
+ RcvBuf = RcvBuf->ipr_next;
+
+ // If we have another one, use it.
+ if (RcvBuf != NULL) {
+ RcvOffset = 0;
+ RcvSize = RcvBuf->ipr_size;
+ } else
+ break;
+ } else // Buffer not exhausted, update offset.
+ RcvOffset += BytesToCopy;
+
+ // Now do the same thing for the destination buffer.
+ if (!(DestSize -= BytesToCopy)) {
+ // Exhausted this buffer.
+
+ DestBuf = NDIS_BUFFER_LINKAGE(DestBuf);
+
+ // If we have another one, use it.
+ if (DestBuf != NULL) {
+ DestOffset = 0;
+ DestSize = NdisBufferLength(DestBuf);
+ } else
+ break;
+ } else // Buffer not exhausted, update offset.
+ DestOffset += BytesToCopy;
+
+ Size -= BytesToCopy; // Decrement amount left to copy.
+ } while (Size);
+
+ }
+
+ return BytesCopied;
+
+
+}
+#endif // NT
+
+
+//* CopyRcvToBuffer - Copy from an IPRcvBuf chain to a flat buffer.
+//
+// Called during receive processing to copy from an IPRcvBuffer chain to a
+// flag buffer. We skip Offset bytes in the src chain, and then
+// copy Size bytes.
+//
+// Input: DestBuf - Pointer to destination buffer.
+// SrcRB - Pointer to SrcRB chain.
+// Size - Size in bytes to copy.
+// SrcOffset - Offset in SrcRB to start copying from.
+//
+// Returns: Nothing.
+//
+void
+CopyRcvToBuffer(uchar *DestBuf, IPRcvBuf *SrcRB, uint Size, uint SrcOffset)
+{
+#ifdef DEBUG
+ IPRcvBuf *TempRB;
+ uint TempSize;
+#endif
+
+ CTEAssert(DestBuf != NULL);
+ CTEAssert(SrcRB != NULL);
+
+ // In debug versions check to make sure we're copying a reasonable size
+ // and from a reasonable offset.
+
+#ifdef DEBUG
+ TempRB = SrcRB;
+ TempSize = 0;
+ while (TempRB != NULL) {
+ TempSize += TempRB->ipr_size;
+ TempRB = TempRB->ipr_next;
+ }
+
+ CTEAssert(SrcOffset < TempSize);
+ CTEAssert((SrcOffset + Size) <= TempSize);
+#endif
+
+ // First, skip Offset bytes.
+ while (SrcOffset >= SrcRB->ipr_size) {
+ SrcOffset -= SrcRB->ipr_size;
+ SrcRB = SrcRB->ipr_next;
+ }
+
+ while (Size != 0) {
+ uint BytesToCopy, SrcSize;
+
+ CTEAssert(SrcRB != NULL);
+
+ SrcSize = SrcRB->ipr_size - SrcOffset;
+ BytesToCopy = MIN(Size, SrcSize);
+ CTEMemCopy(DestBuf, SrcRB->ipr_buffer + SrcOffset, BytesToCopy);
+
+ if (BytesToCopy == SrcSize) {
+ // Copied everything from this buffer.
+ SrcRB = SrcRB->ipr_next;
+ SrcOffset = 0;
+ }
+
+ DestBuf += BytesToCopy;
+ Size -= BytesToCopy;
+ }
+
+}
+
+//* CopyFlatToNdis - Copy a flat buffer to an NDIS_BUFFER chain.
+//
+// A utility function to copy a flat buffer to an NDIS buffer chain. We
+// assume that the NDIS_BUFFER chain is big enough to hold the copy amount;
+// in a debug build we'll debugcheck if this isn't true. We return a pointer
+// to the buffer where we stopped copying, and an offset into that buffer.
+// This is useful for copying in pieces into the chain.
+//
+// Input: DestBuf - Destination NDIS_BUFFER chain.
+// SrcBuf - Src flat buffer.
+// Size - Size in bytes to copy.
+// StartOffset - Pointer to start of offset into first buffer in
+// chain. Filled in on return with the offset to
+// copy into next.
+// BytesCopied - Pointer to a variable into which to store the
+// number of bytes copied by this operation
+//
+// Returns: Pointer to next buffer in chain to copy into.
+//
+
+#ifdef NT
+
+PNDIS_BUFFER
+CopyFlatToNdis(PNDIS_BUFFER DestBuf, uchar *SrcBuf, uint Size,
+ uint *StartOffset, uint *BytesCopied)
+{
+ NTSTATUS Status = 0;
+
+ *BytesCopied = 0;
+
+ Status = TdiCopyBufferToMdl(SrcBuf, 0, Size, DestBuf, *StartOffset,
+ BytesCopied);
+
+ *StartOffset += *BytesCopied;
+
+ //
+ // Always return the first buffer, since the TdiCopy function handles
+ // finding the appropriate buffer based on offset.
+ //
+ return(DestBuf);
+
+}
+
+#else // NT
+
+PNDIS_BUFFER
+CopyFlatToNdis(PNDIS_BUFFER DestBuf, uchar *SrcBuf, uint Size,
+ uint *StartOffset, uint *BytesCopied)
+{
+ uint CopySize;
+ uchar *DestPtr;
+ uint DestSize;
+ uint Offset = *StartOffset;
+ uint bytesCopied = 0;
+
+ CTEAssert(DestBuf != NULL);
+ CTEAssert(SrcBuf != NULL);
+
+ CTEAssert(NdisBufferLength(DestBuf) >= Offset);
+ DestPtr = ((uchar *) NdisBufferVirtualAddress(DestBuf)) + Offset;
+ DestSize = NdisBufferLength(DestBuf) - Offset;
+
+ for (;;) {
+ CopySize = MIN(Size, DestSize);
+ CTEMemCopy(DestPtr, SrcBuf, CopySize);
+
+ DestPtr += CopySize;
+ SrcBuf += CopySize;
+ bytesCopied += CopySize;
+
+ if ((Size -= CopySize) == 0)
+ break;
+
+ if ((DestSize -= CopySize) == 0) {
+ DestBuf = NDIS_BUFFER_LINKAGE(DestBuf);
+ CTEAssert(DestBuf != NULL);
+ DestPtr = NdisBufferVirtualAddress(DestBuf);
+ DestSize = NdisBufferLength(DestBuf);
+ }
+ }
+
+ *StartOffset = DestPtr - NdisBufferVirtualAddress(DestBuf);
+ *BytesCopied = bytesCopied;
+
+ return DestBuf;
+
+}
+
+#endif // NT
+
+
+//* BuildTDIAddress - Build a TDI address structure.
+//
+// Called when we need to build a TDI address structure. We fill in
+// the specifed buffer with the correct information in the correct
+// format.
+//
+// Input: Buffer - Buffer to be filled in as TDI address structure.
+// Addr - IP Address to fill in.
+// Port - Port to be filled in.
+//
+// Returns: Nothing.
+//
+void
+BuildTDIAddress(uchar *Buffer, IPAddr Addr, ushort Port)
+{
+ PTRANSPORT_ADDRESS XportAddr;
+ PTA_ADDRESS TAAddr;
+
+ XportAddr = (PTRANSPORT_ADDRESS)Buffer;
+ XportAddr->TAAddressCount = 1;
+ TAAddr = XportAddr->Address;
+ TAAddr->AddressType = TDI_ADDRESS_TYPE_IP;
+ TAAddr->AddressLength = sizeof(TDI_ADDRESS_IP);
+ ((PTDI_ADDRESS_IP)TAAddr->Address)->sin_port = Port;
+ ((PTDI_ADDRESS_IP)TAAddr->Address)->in_addr = Addr;
+}
+
+//* UpdateConnInfo - Update a connection information structure.
+//
+// Called when we need to update a connection information structure. We
+// copy any options, and create a transport address. If any buffer is
+// too small we return an error.
+//
+// Input: ConnInfo - Pointer to TDI_CONNECTION_INFORMATION struc
+// to be filled in.
+// OptInfo - Pointer to IP options information.
+// SrcAddress - Source IP address.
+// SrcPort - Source port.
+//
+// Returns: TDI_SUCCESS if it worked, TDI_BUFFER_OVERFLOW for an error.
+//
+TDI_STATUS
+UpdateConnInfo(PTDI_CONNECTION_INFORMATION ConnInfo, IPOptInfo *OptInfo,
+ IPAddr SrcAddress, ushort SrcPort)
+{
+ TDI_STATUS Status = TDI_SUCCESS; // Default status to return.
+ uint AddrLength, OptLength;
+
+
+ if (ConnInfo != NULL) {
+ ConnInfo->UserDataLength = 0; // No user data.
+
+ // Fill in the options. If the provided buffer is too small,
+ // we'll truncate the options and return an error. Otherwise
+ // we'll copy the whole IP option buffer.
+ if (ConnInfo->OptionsLength) {
+ if (ConnInfo->OptionsLength < OptInfo->ioi_optlength) {
+ Status = TDI_BUFFER_OVERFLOW;
+ OptLength = ConnInfo->OptionsLength;
+ } else
+ OptLength = OptInfo->ioi_optlength;
+
+ CTEMemCopy(ConnInfo->Options, OptInfo->ioi_options, OptLength);
+
+ ConnInfo->OptionsLength = OptLength;
+ }
+
+ // Options are copied. Build a TRANSPORT_ADDRESS structure in
+ // the buffer.
+ if (AddrLength = ConnInfo->RemoteAddressLength) {
+
+ // Make sure we have at least enough to fill in the count and type.
+ if (AddrLength >= TCP_TA_SIZE) {
+
+ // The address fits. Fill it in.
+ ConnInfo->RemoteAddressLength = TCP_TA_SIZE;
+ BuildTDIAddress(ConnInfo->RemoteAddress, SrcAddress, SrcPort);
+
+ } else {
+ ConnInfo->RemoteAddressLength = 0;
+ Status = TDI_INVALID_PARAMETER;
+ }
+ }
+
+ }
+
+ return Status;
+
+}
diff --git a/private/ntos/tdi/tcpip/tcp/tlcommon.h b/private/ntos/tdi/tcpip/tcp/tlcommon.h
new file mode 100644
index 000000000..29790156c
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/tlcommon.h
@@ -0,0 +1,46 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** TLCOMMON.H - Common transport layer definitions.
+//
+// This file contains definitions for common transport layer items.
+//
+
+#define PHXSUM(s,d,p,l) (uint)( (uint)*(ushort *)&(s) + \
+ (uint)*(ushort *)((char *)&(s) + sizeof(ushort)) + \
+ (uint)*(ushort *)&(d) + \
+ (uint)*(ushort *)((char *)&(d) + sizeof(ushort)) + \
+ (uint)((ushort)net_short((p))) + \
+ (uint)((ushort)net_short((ushort)(l))) )
+
+
+#define TCP_TA_SIZE (offsetof(TRANSPORT_ADDRESS, Address->Address)+ \
+ sizeof(TDI_ADDRESS_IP))
+
+extern ushort XsumSendChain(uint PHXsum, PNDIS_BUFFER BufChain);
+extern ushort XsumRcvBuf(uint PHXsum, IPRcvBuf *BufChain);
+extern uint CopyRcvToNdis(IPRcvBuf *RcvBuf, PNDIS_BUFFER DestBuf,
+ uint Size, uint RcvOffset, uint DestOffset);
+extern TDI_STATUS UpdateConnInfo(PTDI_CONNECTION_INFORMATION ConnInfo,
+ IPOptInfo *OptInfo, IPAddr SrcAddress, ushort SrcPort);
+
+extern void BuildTDIAddress(uchar *Buffer, IPAddr Addr, ushort Port);
+
+extern void CopyRcvToBuffer(uchar *DestBuf, IPRcvBuf *SrcRB, uint Size,
+ uint Offset);
+
+extern PNDIS_BUFFER CopyFlatToNdis(PNDIS_BUFFER DestBuf, uchar *SrcBuf,
+ uint Size, uint *Offset, uint *BytesCopied);
+
+extern void *TLRegisterProtocol(uchar Protocol, void *RcvHandler,
+ void *XmitHandler, void *StatusHandler,
+ void *RcvCmpltHandler);
+
+#ifdef VXD
+extern int TLRegisterDispatch(char *, struct TDIDispatchTable *);
+#endif
+
+
diff --git a/private/ntos/tdi/tcpip/tcp/udp.c b/private/ntos/tdi/tcpip/tcp/udp.c
new file mode 100644
index 000000000..c9c284403
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/udp.c
@@ -0,0 +1,673 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** UDP.C - UDP protocol code.
+//
+// This file contains the code for the UDP protocol functions,
+// principally send and receive datagram.
+//
+
+#include "oscfg.h"
+#include "ndis.h"
+#include "cxport.h"
+#include "ip.h"
+#include "tdi.h"
+#include "tdistat.h"
+#ifdef VXD
+#include "tdivxd.h"
+#endif
+#ifdef NT
+#include "tdint.h"
+#include "tdistat.h"
+#endif
+#include "queue.h"
+#include "addr.h"
+#include "udp.h"
+#include "tlcommon.h"
+#include "info.h"
+#include "tcpcfg.h"
+#include "secfltr.h"
+
+#ifdef NT
+
+#ifdef POOL_TAGGING
+
+#ifdef ExAllocatePool
+#undef ExAllocatePool
+#endif
+
+#define ExAllocatePool(type, size) ExAllocatePoolWithTag(type, size, 'uPCT')
+
+#ifndef CTEAllocMem
+#error "CTEAllocMem is not already defined - will override tagging"
+#else
+#undef CTEAllocMem
+#endif
+
+#define CTEAllocMem(size) ExAllocatePoolWithTag(NonPagedPool, size, 'uPCT')
+
+#endif // POOL_TAGGING
+
+#endif // NT
+
+EXTERNAL_LOCK(AddrObjTableLock)
+
+void *UDPProtInfo = NULL;
+
+extern IPInfo LocalNetInfo;
+
+#ifdef CHICAGO
+extern uchar TransportName[];
+#endif
+
+#ifdef CHICAGO
+extern int RegisterAddrChangeHndlr(void *Handler, uint Add);
+extern void AddrChange(IPAddr Addr, IPMask Mask, void *Context,
+ uint Added);
+#endif
+
+
+
+//** UDPSend - Send a datagram.
+//
+// The real send datagram routine. We assume that the busy bit is
+// set on the input AddrObj, and that the address of the SendReq
+// has been verified.
+//
+// We start by sending the input datagram, and we loop until there's
+// nothing left on the send q.
+//
+// Input: SrcAO - Pointer to AddrObj doing the send.
+// SendReq - Pointer to sendreq describing send.
+//
+// Returns: Nothing
+//
+void
+UDPSend(AddrObj *SrcAO, DGSendReq *SendReq)
+{
+ UDPHeader *UH;
+ PNDIS_BUFFER UDPBuffer;
+ CTELockHandle HeaderHandle, AOHandle;
+ RouteCacheEntry *RCE; // RCE used for each send.
+ IPAddr SrcAddr; // Source address IP thinks we should
+ // use.
+ uchar DestType; // Type of destination address.
+ ushort UDPXsum; // Checksum of packet.
+ ushort SendSize; // Size we're sending.
+ IP_STATUS SendStatus; // Status of send attempt.
+ ushort MSS;
+ uint AddrValid;
+ IPOptInfo *OptInfo;
+ IPAddr OrigSrc;
+
+ CTEStructAssert(SrcAO, ao);
+ CTEAssert(SrcAO->ao_usecnt != 0);
+
+ //* Loop while we have something to send, and can get
+ // resources to send.
+ for (;;) {
+
+ CTEStructAssert(SendReq, dsr);
+
+ // Make sure we have a UDP header buffer for this send. If we
+ // don't, try to get one.
+ if ((UDPBuffer = SendReq->dsr_header) == NULL) {
+ // Don't have one, so try to get one.
+ CTEGetLock(&DGSendReqLock, &HeaderHandle);
+ UDPBuffer = GetDGHeader();
+ if (UDPBuffer != NULL)
+ SendReq->dsr_header = UDPBuffer;
+ else {
+ // Couldn't get a header buffer. Push the send request
+ // back on the queue, and queue the addr object for when
+ // we get resources.
+ CTEGetLock(&SrcAO->ao_lock, &AOHandle);
+ PUSHQ(&SrcAO->ao_sendq, &SendReq->dsr_q);
+ PutPendingQ(SrcAO);
+ CTEFreeLock(&SrcAO->ao_lock, AOHandle);
+ CTEFreeLock(&DGSendReqLock, HeaderHandle);
+ return;
+ }
+ CTEFreeLock(&DGSendReqLock, HeaderHandle);
+ }
+
+ // At this point, we have the buffer we need. Call IP to get an
+ // RCE (along with the source address if we need it), then compute
+ // the checksum and send the data.
+ CTEAssert(UDPBuffer != NULL);
+
+ if (!CLASSD_ADDR(SendReq->dsr_addr)) {
+ // This isn't a multicast send, so we'll use the ordinary
+ // information.
+ OrigSrc = SrcAO->ao_addr;
+ OptInfo = &SrcAO->ao_opt;
+ } else {
+ OrigSrc = SrcAO->ao_mcastaddr;
+ OptInfo = &SrcAO->ao_mcastopt;
+ }
+
+ if (!(SrcAO->ao_flags & AO_DHCP_FLAG)) {
+ SrcAddr = (*LocalNetInfo.ipi_openrce)(SendReq->dsr_addr,
+ OrigSrc, &RCE, &DestType, &MSS, OptInfo);
+
+ AddrValid = !IP_ADDR_EQUAL(SrcAddr, NULL_IP_ADDR);
+ } else {
+ // This is a DHCP send. He really wants to send from the
+ // NULL IP address.
+ SrcAddr = NULL_IP_ADDR;
+ RCE = NULL;
+ AddrValid = TRUE;
+ }
+
+ if (AddrValid) {
+ // The OpenRCE worked. Compute the checksum, and send it.
+
+ if (!IP_ADDR_EQUAL(OrigSrc, NULL_IP_ADDR))
+ SrcAddr = OrigSrc;
+
+ UH = (UDPHeader *)((uchar *)NdisBufferVirtualAddress(UDPBuffer) +
+ LocalNetInfo.ipi_hsize);
+ NdisBufferLength(UDPBuffer) = sizeof(UDPHeader);
+ NDIS_BUFFER_LINKAGE(UDPBuffer) = SendReq->dsr_buffer;
+ UH->uh_src = SrcAO->ao_port;
+ UH->uh_dest = SendReq->dsr_port;
+ SendSize = SendReq->dsr_size + sizeof(UDPHeader);
+ UH->uh_length = net_short(SendSize);
+ UH->uh_xsum = 0;
+
+ if (AO_XSUM(SrcAO)) {
+ // Compute the header xsum, and then call XsumNdisChain
+ UDPXsum = XsumSendChain(PHXSUM(SrcAddr, SendReq->dsr_addr,
+ PROTOCOL_UDP, SendSize), UDPBuffer);
+
+ // We need to negate the checksum, unless it's already all
+ // ones. In that case negating it would take it to 0, and
+ // then we'd have to set it back to all ones.
+ if (UDPXsum != 0xffff)
+ UDPXsum =~UDPXsum;
+
+ UH->uh_xsum = UDPXsum;
+
+ }
+
+ // We've computed the xsum. Now send the packet.
+ UStats.us_outdatagrams++;
+ SendStatus = (*LocalNetInfo.ipi_xmit)(UDPProtInfo, SendReq,
+ UDPBuffer, (uint)SendSize, SendReq->dsr_addr, SrcAddr,
+ OptInfo, RCE, PROTOCOL_UDP);
+
+ (*LocalNetInfo.ipi_closerce)(RCE);
+
+ // If it completed immediately, give it back to the user.
+ // Otherwise we'll complete it when the SendComplete happens.
+ // Currently, we don't map the error code from this call - we
+ // might need to in the future.
+ if (SendStatus != IP_PENDING)
+ DGSendComplete(SendReq, UDPBuffer);
+
+ } else {
+ TDI_STATUS Status;
+
+ if (DestType == DEST_INVALID)
+ Status = TDI_BAD_ADDR;
+ else
+ Status = TDI_DEST_UNREACHABLE;
+
+ // Complete the request with an error.
+ (*SendReq->dsr_rtn)(SendReq->dsr_context, Status, 0);
+ // Now free the request.
+ SendReq->dsr_rtn = NULL;
+ DGSendComplete(SendReq, UDPBuffer);
+ }
+
+ CTEGetLock(&SrcAO->ao_lock, &AOHandle);
+
+ if (!EMPTYQ(&SrcAO->ao_sendq)) {
+ DEQUEUE(&SrcAO->ao_sendq, SendReq, DGSendReq, dsr_q);
+ CTEFreeLock(&SrcAO->ao_lock, AOHandle);
+ } else {
+ CLEAR_AO_REQUEST(SrcAO, AO_SEND);
+ CTEFreeLock(&SrcAO->ao_lock, AOHandle);
+ return;
+ }
+
+ }
+}
+
+
+//* UDPDeliver - Deliver a datagram to a user.
+//
+// This routine delivers a datagram to a UDP user. We're called with
+// the AddrObj to deliver on, and with the AddrObjTable lock held.
+// We try to find a receive on the specified AddrObj, and if we do
+// we remove it and copy the data into the buffer. Otherwise we'll
+// call the receive datagram event handler, if there is one. If that
+// fails we'll discard the datagram.
+//
+// Input: RcvAO - AO to receive the datagram.
+// SrcIP - Source IP address of datagram.
+// SrcPort - Source port of datagram.
+// RcvBuf - The IPReceive buffer containing the data.
+// RcvSize - Size received, including the UDP header.
+// TableHandle - Lock handle for AddrObj table.
+//
+// Returns: Nothing.
+//
+void
+UDPDeliver(AddrObj *RcvAO, IPAddr SrcIP, ushort SrcPort, IPRcvBuf *RcvBuf,
+ uint RcvSize, IPOptInfo *OptInfo, CTELockHandle TableHandle, uchar IsBCast)
+{
+ Queue *CurrentQ;
+ CTELockHandle AOHandle;
+ DGRcvReq *RcvReq;
+ uint BytesTaken = 0;
+ uchar AddressBuffer[TCP_TA_SIZE];
+ uint RcvdSize;
+ EventRcvBuffer *ERB = NULL;
+
+ CTEStructAssert(RcvAO, ao);
+
+ CTEGetLock(&RcvAO->ao_lock, &AOHandle);
+ CTEFreeLock(&AddrObjTableLock, AOHandle);
+
+ if (AO_VALID(RcvAO)) {
+
+ CurrentQ = QHEAD(&RcvAO->ao_rcvq);
+
+ // Walk the list, looking for a receive buffer that matches.
+ while (CurrentQ != QEND(&RcvAO->ao_rcvq)) {
+ RcvReq = QSTRUCT(DGRcvReq, CurrentQ, drr_q);
+
+ CTEStructAssert(RcvReq, drr);
+
+ // If this request is a wildcard request, or matches the source IP
+ // address, check the port.
+
+ if (IP_ADDR_EQUAL(RcvReq->drr_addr, NULL_IP_ADDR) ||
+ IP_ADDR_EQUAL(RcvReq->drr_addr, SrcIP)) {
+
+ // The local address matches, check the port. We'll match
+ // either 0 or the actual port.
+ if (RcvReq->drr_port == 0 || RcvReq->drr_port == SrcPort) {
+
+ TDI_STATUS Status;
+
+ // The ports matched. Remove this from the queue.
+ REMOVEQ(&RcvReq->drr_q);
+
+ // We're done. We can free the AddrObj lock now.
+ CTEFreeLock(&RcvAO->ao_lock, TableHandle);
+
+ // Call CopyRcvToNdis, and then complete the request.
+ RcvdSize = CopyRcvToNdis(RcvBuf, RcvReq->drr_buffer,
+ RcvReq->drr_size, sizeof(UDPHeader), 0);
+
+ CTEAssert(RcvdSize <= RcvReq->drr_size);
+
+ Status = UpdateConnInfo(RcvReq->drr_conninfo, OptInfo,
+ SrcIP, SrcPort);
+
+ UStats.us_indatagrams++;
+
+ (*RcvReq->drr_rtn)(RcvReq->drr_context, Status, RcvdSize);
+
+ FreeDGRcvReq(RcvReq);
+
+ return;
+ }
+ }
+
+ // Either the IP address or the port didn't match. Get the next
+ // one.
+ CurrentQ = QNEXT(CurrentQ);
+ }
+
+ // We've walked the list, and not found a buffer. Call the recv.
+ // handler now.
+
+ if (RcvAO->ao_rcvdg != NULL) {
+ PRcvDGEvent RcvEvent = RcvAO->ao_rcvdg;
+ PVOID RcvContext = RcvAO->ao_rcvdgcontext;
+ TDI_STATUS RcvStatus;
+ CTELockHandle OldLevel;
+ ULONG Flags = TDI_RECEIVE_COPY_LOOKAHEAD;
+
+
+ REF_AO(RcvAO);
+ CTEFreeLock(&RcvAO->ao_lock, TableHandle);
+
+ BuildTDIAddress(AddressBuffer, SrcIP, SrcPort);
+
+ UStats.us_indatagrams++;
+ if (IsBCast) {
+ Flags |= TDI_RECEIVE_BROADCAST;
+ }
+ RcvStatus = (*RcvEvent)(RcvContext, TCP_TA_SIZE,
+ (PTRANSPORT_ADDRESS)AddressBuffer, OptInfo->ioi_optlength,
+ OptInfo->ioi_options, Flags,
+ RcvBuf->ipr_size - sizeof(UDPHeader),
+ RcvSize - sizeof(UDPHeader), &BytesTaken,
+ RcvBuf->ipr_buffer + sizeof(UDPHeader), &ERB);
+
+ if (RcvStatus == TDI_MORE_PROCESSING) {
+ CTEAssert(ERB != NULL);
+
+ // We were passed back a receive buffer. Copy the data in now.
+
+ // He can't have taken more than was in the indicated
+ // buffer, but in debug builds we'll check to make sure.
+
+ CTEAssert(BytesTaken <= (RcvBuf->ipr_size - sizeof(UDPHeader)));
+
+#ifdef VXD
+ RcvdSize = CopyRcvToNdis(RcvBuf, ERB->erb_buffer,
+ ERB->erb_size, sizeof(UDPHeader) + BytesTaken, 0);
+
+ //
+ // Call the completion routine.
+ //
+ (*ERB->erb_rtn)(ERB->erb_context, TDI_SUCCESS, RcvdSize);
+
+#endif // VXD
+
+#ifdef NT
+ {
+ PIO_STACK_LOCATION IrpSp;
+ PTDI_REQUEST_KERNEL_RECEIVEDG DatagramInformation;
+
+ IrpSp = IoGetCurrentIrpStackLocation(ERB);
+ DatagramInformation = (PTDI_REQUEST_KERNEL_RECEIVEDG)
+ &(IrpSp->Parameters);
+
+ //
+ // Copy the remaining data to the IRP.
+ //
+ RcvdSize = CopyRcvToNdis(RcvBuf, ERB->MdlAddress,
+ RcvSize - sizeof(UDPHeader) - BytesTaken,
+ sizeof(UDPHeader) + BytesTaken, 0);
+
+ //
+ // Update the return address info
+ //
+ RcvStatus = UpdateConnInfo(
+ DatagramInformation->ReturnDatagramInformation,
+ OptInfo, SrcIP, SrcPort);
+
+ //
+ // Complete the IRP.
+ //
+ ERB->IoStatus.Information = RcvdSize;
+ ERB->IoStatus.Status = RcvStatus;
+ IoCompleteRequest(ERB, 2);
+ }
+#endif // NT
+
+ }
+ else {
+ CTEAssert(
+ (RcvStatus == TDI_SUCCESS) ||
+ (RcvStatus == TDI_NOT_ACCEPTED)
+ );
+
+ CTEAssert(ERB == NULL);
+ }
+
+ DELAY_DEREF_AO(RcvAO);
+
+ return;
+
+ } else
+ UStats.us_inerrors++;
+
+ // When we get here, we didn't have a buffer to put this data into.
+ // Fall through to the return case.
+ } else
+ UStats.us_inerrors++;
+
+ CTEFreeLock(&RcvAO->ao_lock, TableHandle);
+
+}
+
+
+//* UDPRcv - Receive a UDP datagram.
+//
+// The routine called by IP when a UDP datagram arrived. We
+// look up the port/local address pair in our address table,
+// and deliver the data to a user if we find one. For broadcast
+// frames we may deliver it to multiple users.
+//
+// Entry: IPContext - IPContext identifying physical i/f that
+// received the data.
+// Dest - IPAddr of destionation.
+// Src - IPAddr of source.
+// LocalAddr - Local address of network which caused this to be
+// received.
+// SrcAddr - Address of local interface which received the packet
+// IPH - IP Header.
+// IPHLength - Bytes in IPH.
+// RcvBuf - Pointer to receive buffer chain containing data.
+// Size - Size in bytes of data received.
+// IsBCast - Boolean indicator of whether or not this came in as
+// a bcast.
+// Protocol - Protocol this came in on - should be UDP.
+// OptInfo - Pointer to info structure for received options.
+//
+// Returns: Status of reception. Anything other than IP_SUCCESS will cause
+// IP to send a 'port unreachable' message.
+//
+IP_STATUS
+UDPRcv(void *IPContext, IPAddr Dest, IPAddr Src, IPAddr LocalAddr,
+ IPAddr SrcAddr, IPHeader UNALIGNED *IPH, uint IPHLength, IPRcvBuf *RcvBuf,
+ uint IPSize, uchar IsBCast, uchar Protocol, IPOptInfo *OptInfo)
+{
+ UDPHeader UNALIGNED *UH;
+ CTELockHandle AOTableHandle;
+ AddrObj *ReceiveingAO;
+ uint Size;
+ uchar DType;
+
+ DType = (*LocalNetInfo.ipi_getaddrtype)(Src);
+
+ // The following code relies on DEST_INVALID being a broadcast dest type.
+ // If this is changed the code here needs to change also.
+ if (IS_BCAST_DEST(DType)) {
+ if (!IP_ADDR_EQUAL(Src, NULL_IP_ADDR) || !IsBCast) {
+ UStats.us_inerrors++;
+ return IP_SUCCESS; // Bad src address.
+ }
+ }
+
+ UH = (UDPHeader *)RcvBuf->ipr_buffer;
+
+ Size = (uint)(net_short(UH->uh_length));
+
+ if (Size < sizeof(UDPHeader)) {
+ UStats.us_inerrors++;
+ return IP_SUCCESS; // Size is too small.
+ }
+
+ if (Size != IPSize) {
+ // Size doesn't match IP datagram size. If the size is larger
+ // than the datagram, throw it away. If it's smaller, truncate the
+ // recv. buffer.
+ if (Size < IPSize) {
+ IPRcvBuf *TempBuf = RcvBuf;
+ uint TempSize = Size;
+
+ while (TempBuf != NULL) {
+ TempBuf->ipr_size = MIN(TempBuf->ipr_size, TempSize);
+ TempSize -= TempBuf->ipr_size;
+ TempBuf = TempBuf->ipr_next;
+ }
+ } else {
+ // Size is too big, toss it.
+ UStats.us_inerrors++;
+ return IP_SUCCESS;
+ }
+ }
+
+
+ if (UH->uh_xsum != 0) {
+ if (XsumRcvBuf(PHXSUM(Src, Dest, PROTOCOL_UDP, Size), RcvBuf) != 0xffff) {
+ UStats.us_inerrors++;
+ return IP_SUCCESS; // Checksum failed.
+ }
+ }
+
+ CTEGetLock(&AddrObjTableLock, &AOTableHandle);
+
+#ifdef SECFLTR
+ //
+ // See if we are filtering the destination interface/port.
+ //
+ if ( !SecurityFilteringEnabled ||
+ IsPermittedSecurityFilter(
+ SrcAddr,
+ IPContext,
+ PROTOCOL_UDP,
+ (ulong) net_short(UH->uh_dest)
+ )
+ )
+ {
+#endif // SECFLTR
+
+ // Try to find an AddrObj to give this to. In the broadcast case, we
+ // may have to do this multiple times. If it isn't a broadcast, just
+ // get the best match and deliver it to them.
+
+ if (!IsBCast) {
+ ReceiveingAO = GetBestAddrObj(Dest, UH->uh_dest, PROTOCOL_UDP);
+ if (ReceiveingAO != NULL) {
+ UDPDeliver(ReceiveingAO, Src, UH->uh_src, RcvBuf, Size,
+ OptInfo, AOTableHandle, IsBCast);
+ return IP_SUCCESS;
+ } else {
+ CTEFreeLock(&AddrObjTableLock, AOTableHandle);
+ UStats.us_noports++;
+ return IP_GENERAL_FAILURE;
+ }
+ } else {
+ // This is a broadcast, we'll need to loop.
+
+ AOSearchContext Search;
+
+ DType = (*LocalNetInfo.ipi_getaddrtype)(Dest);
+
+ ReceiveingAO = GetFirstAddrObj(LocalAddr, UH->uh_dest, PROTOCOL_UDP,
+ &Search);
+ if (ReceiveingAO != NULL) {
+ do {
+ if ((DType != DEST_MCAST) ||
+ ((DType == DEST_MCAST) &&
+ MCastAddrOnAO(ReceiveingAO, Dest))) {
+ UDPDeliver(ReceiveingAO, Src, UH->uh_src, RcvBuf, Size,
+ OptInfo, AOTableHandle, IsBCast);
+ CTEGetLock(&AddrObjTableLock, &AOTableHandle);
+ }
+ ReceiveingAO = GetNextAddrObj(&Search);
+ } while (ReceiveingAO != NULL);
+ } else
+ UStats.us_noports++;
+ }
+
+#ifdef SECFLTR
+ }
+#endif // SECFLTR
+
+ CTEFreeLock(&AddrObjTableLock, AOTableHandle);
+
+ return IP_SUCCESS;
+}
+
+//* UDPStatus - Handle a status indication.
+//
+// This is the UDP status handler, called by IP when a status event
+// occurs. For most of these we do nothing. For certain severe status
+// events we will mark the local address as invalid.
+//
+// Entry: StatusType - Type of status (NET or HW). NET status
+// is usually caused by a received ICMP
+// message. HW status indicate a HW
+// problem.
+// StatusCode - Code identifying IP_STATUS.
+// OrigDest - If this is NET status, the original dest. of
+// DG that triggered it.
+// OrigSrc - " " " " " , the original src.
+// Src - IP address of status originator (could be local
+// or remote).
+// Param - Additional information for status - i.e. the
+// param field of an ICMP message.
+// Data - Data pertaining to status - for NET status, this
+// is the first 8 bytes of the original DG.
+//
+// Returns: Nothing
+//
+void
+UDPStatus(uchar StatusType, IP_STATUS StatusCode, IPAddr OrigDest,
+ IPAddr OrigSrc, IPAddr Src, ulong Param, void *Data)
+{
+ // If this is a HW status, it could be because we've had an address go
+ // away.
+ if (StatusType == IP_HW_STATUS) {
+
+ if (StatusCode == IP_ADDR_DELETED) {
+ //
+ // An address has gone away. OrigDest identifies the address.
+ //
+#ifndef _PNP_POWER
+ //
+ // This is done via TDI notifications in the PNP world.
+ //
+ InvalidateAddrs(OrigDest);
+
+#endif // _PNP_POWER
+
+#ifdef SECFLTR
+ //
+ // Delete any security filters associated with this address
+ //
+ DeleteProtocolSecurityFilter(OrigDest, PROTOCOL_UDP);
+
+#endif // SECFLTR
+
+ return;
+ }
+
+ if (StatusCode == IP_ADDR_ADDED) {
+
+#ifdef SECFLTR
+ //
+ // An address has materialized. OrigDest identifies the address.
+ // Data is a handle to the IP configuration information for the
+ // interface on which the address is instantiated.
+ //
+ AddProtocolSecurityFilter(OrigDest, PROTOCOL_UDP,
+ (NDIS_HANDLE) Data);
+#endif // SECFLTR
+
+ return;
+ }
+
+#ifdef CHICAGO
+ if (StatusCode == IP_UNLOAD) {
+ // IP is telling us we're being unloaded. First, deregister
+ // with VTDI, and then call CTEUnload().
+ (void)TLRegisterProtocol(PROTOCOL_UDP, NULL, NULL, NULL, NULL);
+
+#ifdef UDP_ONLY
+ // Only do the following in the UDP_ONLY version. TCP does it in
+ // the generic version.
+ TLRegisterDispatch(TransportName, NULL);
+ (void)RegisterAddrChangeHndlr(AddrChange, FALSE);
+ CTEUnload(TransportName);
+#endif // UDP_ONLY
+
+ return;
+ }
+#endif // CHICAGO
+ }
+}
+
diff --git a/private/ntos/tdi/tcpip/tcp/udp.h b/private/ntos/tdi/tcpip/tcp/udp.h
new file mode 100644
index 000000000..4ba5ec5e0
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/udp.h
@@ -0,0 +1,39 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** UDP. - UDP protocol definitions.
+//
+// This file contains definitions for the UDP protocol functions.
+//
+
+#include "dgram.h"
+
+#define PROTOCOL_UDP 17 // UDP protocol number
+
+//* Structure of a UDP header.
+struct UDPHeader {
+ ushort uh_src; // Source port.
+ ushort uh_dest; // Destination port.
+ ushort uh_length; // Length
+ ushort uh_xsum; // Checksum.
+}; /* UDPHeader */
+
+typedef struct UDPHeader UDPHeader;
+
+
+//* External definition of exported functions.
+extern IP_STATUS UDPRcv(void *IPContext, IPAddr Dest, IPAddr Src,
+ IPAddr LocalAddr, IPAddr SrcAddr,
+ IPHeader UNALIGNED *IPH, uint IPHLength,
+ IPRcvBuf *RcvBuf, uint Size, uchar IsBCast,
+ uchar Protocol, IPOptInfo *OptInfo);
+
+extern void UDPStatus(uchar StatusType, IP_STATUS StatusCode, IPAddr OrigDest,
+ IPAddr OrigSrc, IPAddr Src, ulong Param, void *Data);
+
+extern void UDPSend(AddrObj *SrcAO, DGSendReq *SendReq);
+
+
diff --git a/private/ntos/tdi/tcpip/tcp/up/makefile b/private/ntos/tdi/tcpip/tcp/up/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/up/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/tcpip/tcp/up/sources b/private/ntos/tdi/tcpip/tcp/up/sources
new file mode 100644
index 000000000..75e90b2f7
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/up/sources
@@ -0,0 +1,30 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+UP_DRIVER=yes
+
+LINKLIBS=..\..\ip\up\obj\*\ip.lib
+TARGETPATH=obj
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/tcpip/tcp/up/tcpip.prf b/private/ntos/tdi/tcpip/tcp/up/tcpip.prf
new file mode 100644
index 000000000..4f03cef97
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/up/tcpip.prf
@@ -0,0 +1,297 @@
+TdiQueryInformation@20
+TCPDispatchInternalDeviceControl@8
+DerefTCB@8
+FreeARPBuffer@8
+ProcessTCBDelayQ@0
+ARPTransmit@16
+TCPRcv@48
+IPRcv@28
+IPRcvComplete@0
+GetARPBuffer@12
+FreeIPPacket@4
+TCBTimeout@8
+ARPTimeout@8
+ICMPTimer@4
+IPTimeout@8
+IGMPTimer@4
+IndicateData@16
+TCPSendComplete@8
+GetSendReq@0
+FreeSendReq@4
+FillTCPHeader@8
+RcvWin@4
+IPTransmit@36
+GetRcvReq@0
+GetTCPHeader@0
+FindTCB@16
+TCPSendData@8
+TdiSend@16
+TCPSend@8
+ACKData@8
+FreeRBChain@4
+FreeRcvReq@4
+TCPDataRequestComplete@12
+FindUserRcv@4
+TCPRcvComplete@0
+GetLocalNTE@8
+GetConnFromConnID@4
+ARPSendData@16
+XsumRcvBuf@8
+FreeTCPHeader@4
+ARPRcv@28
+XsumSendChain@8
+CTEStartTimer@16
+DeliverToUser@32
+GetIPPacket@0
+ARPRcvComplete@4
+CTESystemUpTime@0
+ARPSendComplete@12
+IPSendComplete@12
+DelayAction@8
+TCPPrepareIrpForCancel@12
+BufferData@16
+SendACK@4
+CompleteRcvs@4
+FreePartialRB@8
+GetAddrObj@16
+AddrOnIF@8
+FindRTE@20
+TdiCopyBufferToMdl@24
+TCPGetMdlChainByteCount@4
+IPHash@4
+LookupRTE@12
+OpenRCE@24
+TCPQueryInformation@8
+CopyFlatToNdis@20
+FindListenConn@16
+DummyDone@8
+GetAddrType@4
+InitTCBFromConn@16
+tcpxsum@12
+FindMSS@4
+DelayDerefAO@4
+FindRCE@12
+TryToCloseTCB@12
+InitRCE@4
+NotifyOfDisc@12
+UpdateConnInfo@16
+GoToEstab@4
+TCPDisconnect@8
+FreeConnReq@4
+TdiDisconnect@20
+IPGetLocalMTU@8
+CloseRCE@4
+IPInitOptions@4
+AdjustRcvWin@4
+BuildTDIAddress@12
+SendSYN@8
+AllocTCB@0
+ProcessUserOptions@8
+FreeTCB@4
+RemoveTCBFromConn@4
+InitSendState@4
+CompleteConnReq@12
+IPFreeOptions@4
+TCPRequestComplete@12
+InvalidSourceAddress@4
+AcceptConn@8
+RemoveTCB@4
+GetConnReq@0
+CloseTCB@8
+RemoveConnFromTCB@4
+FinishRemoveTCBFromConn@4
+IsBCastOnNTE@8
+InsertTCB@4
+ResetSendNext@8
+ARPLookup@12
+BCastRcv@40
+IPGetAddrType@4
+UDPRcv@48
+GetFirstAddrObj@16
+IPForward@32
+GetNextAddrObj@4
+UDPDeliver@32
+LockedDerefIF@4
+BestNTEForIF@8
+ARPInvalidate@8
+IsBCastOnIF@8
+ARPSendBCast@16
+UDPSendDatagram@8
+DGSendComplete@8
+TdiSendDatagram@20
+DerefAO@4
+FreeDGSendReq@4
+GetDGSendReq@0
+FreeDGHeader@4
+UDPSend@8
+GetAddress@12
+ARPRemoveRCE@8
+HandleARPPacket@24
+IsLocalAddr@8
+ARPLocalAddr@8
+IPRouteTimeout@8
+GetConnID@4
+TdiAssociateAddress@8
+FindEA@12
+TCPCreate@12
+TCPAssociateAddress@8
+TdiOpenConnection@8
+TCPDispatch@8
+TdiMapUserRequest@12
+IPGetPInfo@16
+SendARPPacket@40
+RemoveARPTableEntry@8
+CreateARPTableEntry@12
+SendARPRequest@20
+GrowARPHeaders@4
+GrowTCPHeaderList@0
+TdiCloseConnection@4
+RemoveConnFromAO@8
+TCPCloseObjectComplete@12
+TCPClose@8
+CloseDone@8
+TCPCleanup@12
+FreeConnID@4
+DummyCmplt@12
+LoopAddAddr@16
+FindIGMPAddr@12
+CTEInitEvent@8
+TdiSetEvent@16
+ARPSetMCastList@4
+IPGetInfo@8
+IGMPAddrChange@12
+ICMPInit@4
+IGMPInit@0
+ARPRequestComplete@12
+FreeAORequest@4
+TCPQueryInformationEx@8
+ARPFindMCast@12
+InitAdapter@4
+CTESignal@8
+CTEBlock@4
+CTEInitTimer@4
+InsertAddrObj@4
+TdiQueryInformationEx@20
+ARPAddAddr@16
+TdiOpenAddress@16
+InitNTERouting@12
+ARPAddMCast@8
+InitIGMPForNTE@4
+FindAnyAddrObj@8
+GrowDGHeaderList@0
+FindSpecificRTE@20
+InitNTE@4
+CopyToNdis@16
+IPRegisterProtocol@20
+GetAddrOptions@12
+InitInterface@8
+TdiSetInformationEx@16
+TCPConnect@8
+TCPQueryInformationExComplete@12
+TCPSetInformationEx@8
+LockedAddRoute@36
+TCPAcdBind@0
+AddRoute@36
+TdiConnect@16
+LoopXmit@16
+AddValueSecurityFilter@12
+InitGateway@4
+ARPOAComplete@12
+CTEScheduleEvent@8
+GetHashMask@8
+InitLoopback@4
+RawStatus@28
+FindInterfaceEntry@4
+FindProtocolEntry@8
+AddProtocolSecurityFilter@12
+TdiRegisterNetAddress@8
+UDPStatus@28
+ARPDynRegister@36
+FindInsertPoint@4
+IPAddInterface@20
+NotifyAddrChange@28
+TCPStatus@28
+TdiInitialize@0
+TdiRegisterDeviceObject@8
+TdiRegisterAddressChangeHandler@12
+CTEInitialize@0
+ARPBindAdapter@20
+ICMPStatus@28
+IPQueryInfo@16
+DeleteProtocolValueEntries@4
+ModifyProtocolEntry@12
+ModifyInterfaceEntry@16
+ModifySecurityFilter@16
+DoNDISRequest@24
+LoopGetEList@12
+TCPDisassociateAddress@8
+TdiDisAssociateAddress@4
+EnumRegMultiSz@12
+AddressArrival@4
+ARPGetEList@12
+GrowIPPacketList@0
+IPGetEList@8
+RTValidateContext@8
+RTReadNext@8
+GetCurrentRouteTable@4
+AddNTERoutes@4
+GetSecurityFilterList@12
+LoopXmitRtn@8
+InitDG@4
+IPGetConfig@0
+InitTimestamp@0
+IPProcessAdapterSection@8
+TCPInitializeParameter@12
+TLGetIPInfo@8
+InitializeSecurityFilters@0
+IPFreeConfig@4
+InitTCPRcv@0
+InitAddr@0
+IPInit@0
+GetTime@0
+ARPInit@0
+InitTCPConn@0
+IPProcessConfiguration@0
+IPDriverEntry@8
+tlinit@0
+InitTCPSend@0
+InitTCB@0
+GetIFAddrList@8
+ARPOpen@4
+TCPDispatchDeviceControl@8
+TCPSetEventHandler@8
+ARPRegister@12
+GetRegStringValue@16
+IsDHCPZeroAddress@4
+EnumSecurityFilterValue@12
+CloseIFConfig@4
+UseEtherSNAP@4
+OpenIFConfig@8
+IPConvertStringToAddress@8
+SetRegDWORDValue@12
+GetArpCacheLife@0
+InitRegDWORDParameter@16
+GetRegMultiSZValue@12
+OpenRegKey@8
+GetGeneralIFConfig@8
+GetAlwaysSourceRoute@0
+GetRegSZValue@16
+GetRegDWORDValue@12
+IsLLInterfaceValueNull@4
+DerefIF@4
+ARPQueryInfo@20
+DriverEntry@8
+TCPGetConfigInfo@0
+SendIPPacket@28
+GetIPHdrBuffer@0
+GrowHdrBufList@0
+FreeIPHdrBuffer@4
+InitRouting@4
+TLRegisterProtocol@20
+LookupNextHopWithBuffer@28
+SetPersistentRoutesForNTE@12
+SendARPReply@28
+GetGMTDelta@0
+SendRSTFromHeader@20
+InvalidateRCEChain@4
+LoopQInfo@20
diff --git a/private/ntos/tdi/wrapper/cxport.c b/private/ntos/tdi/wrapper/cxport.c
new file mode 100644
index 000000000..db444df32
--- /dev/null
+++ b/private/ntos/tdi/wrapper/cxport.c
@@ -0,0 +1,723 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ cxport.c
+
+Abstract:
+
+ Common Transport Environment utility functions for the NT environment
+
+Author:
+
+ Mike Massa (mikemas) Aug 11, 1993
+
+Revision History:
+
+ Who When What
+ -------- -------- ----------------------------------------------
+ mikemas 08-11-93 created
+
+Notes:
+
+--*/
+
+#include <ntddk.h>
+#include <ndis.h>
+#include <cxport.h>
+#include <tdistat.h>
+
+
+//
+// Mark pageable code
+//
+#ifdef ALLOC_PRAGMA
+
+#pragma alloc_text(PAGE, CTELogEvent)
+
+#endif // ALLOC_PRAGMA
+
+
+//
+// Local variables
+//
+ULONG CTEpTimeIncrement = 0; // used to convert kernel clock ticks to 100ns.
+
+ // Used in the conversion of 100ns times to milliseconds.
+static LARGE_INTEGER Magic10000 = {0xe219652c, 0xd1b71758};
+
+
+//
+// Macros
+//
+//++
+//
+// LARGE_INTEGER
+// CTEConvertMillisecondsTo100ns(
+// IN LARGE_INTEGER MsTime
+// );
+//
+// Routine Description:
+//
+// Converts time expressed in hundreds of nanoseconds to milliseconds.
+//
+// Arguments:
+//
+// MsTime - Time in milliseconds.
+//
+// Return Value:
+//
+// Time in hundreds of nanoseconds.
+//
+//--
+
+#define CTEConvertMillisecondsTo100ns(MsTime) \
+ RtlExtendedIntegerMultiply(MsTime, 10000)
+
+
+//++
+//
+// LARGE_INTEGER
+// CTEConvert100nsToMilliseconds(
+// IN LARGE_INTEGER HnsTime
+// );
+//
+// Routine Description:
+//
+// Converts time expressed in hundreds of nanoseconds to milliseconds.
+//
+// Arguments:
+//
+// HnsTime - Time in hundreds of nanoseconds.
+//
+// Return Value:
+//
+// Time in milliseconds.
+//
+//--
+
+#define SHIFT10000 13
+extern LARGE_INTEGER Magic10000;
+
+#define CTEConvert100nsToMilliseconds(HnsTime) \
+ RtlExtendedMagicDivide((HnsTime), Magic10000, SHIFT10000)
+
+
+//
+// Local functions
+//
+VOID
+CTEpEventHandler(
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ Internal handler for scheduled CTE Events. Conforms to calling convention
+ for ExWorkerThread handlers. Calls the CTE handler registered for this
+ event.
+
+Arguments:
+
+ Context - Work item to process.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CTEEvent *Event;
+ CTELockHandle Handle;
+
+#if DBG
+ KIRQL StartingIrql;
+
+ StartingIrql = KeGetCurrentIrql();
+#endif
+
+ Event = (CTEEvent *) Context;
+
+ CTEGetLock(&(Event->ce_lock), &Handle);
+ ASSERT(Event->ce_scheduled);
+ Event->ce_scheduled = 0;
+ CTEFreeLock(&(Event->ce_lock), Handle);
+
+ (*Event->ce_handler)(Event, Event->ce_arg);
+
+#if DBG
+ if (KeGetCurrentIrql() != StartingIrql) {
+ DbgPrint(
+ "CTEpEventHandler: routine %lx , event %lx returned at raised IRQL\n",
+ Event->ce_handler, Event
+ );
+ DbgBreakPoint();
+ }
+#endif
+}
+
+
+VOID
+CTEpTimerHandler(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+/*++
+
+Routine Description:
+
+ Internal handler for scheduled CTE Timers. Conforms to calling convention
+ for NT DPC handlers. Calls the CTE handler registered for this timer.
+
+Arguments:
+
+ Dpc - Pointer to the DPC routine being run.
+ DeferredContext - Private context for this instance of the DPC.
+ SystemArgument1 - Additional argument.
+ SystemArgument2 - Additional argument.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CTETimer *Timer;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(SystemArgument1);
+ UNREFERENCED_PARAMETER(SystemArgument2);
+
+ Timer = (CTETimer *) DeferredContext;
+ (*Timer->t_handler)((CTEEvent *)Timer, Timer->t_arg);
+}
+
+
+//
+// Exported functions.
+//
+int
+CTEInitialize(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes the Common Tranport Environment (CTE).
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ 0 if initialization fails. Nonzero otherwise.
+
+--*/
+
+{
+ CTEpTimeIncrement = KeQueryTimeIncrement();
+
+ return(1);
+}
+
+
+void
+CTEInitEvent(
+ CTEEvent *Event,
+ CTEEventRtn Handler
+ )
+/*++
+
+Routine Description:
+
+ Initializes a CTE Event variable.
+
+Arguments:
+
+ Event - Event variable to initialize.
+ Handler - Handler routine for this event variable.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ASSERT(Handler != NULL);
+
+ Event->ce_handler = Handler;
+ Event->ce_scheduled = 0;
+ CTEInitLock(&(Event->ce_lock));
+ ExInitializeWorkItem(&(Event->ce_workitem), CTEpEventHandler, Event);
+}
+
+
+int
+CTEScheduleEvent(
+ IN CTEEvent *Event,
+ IN void *Argument OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ Schedules a routine to be executed later in a different context. In the
+ NT environment, the event is implemented using Executive worker threads.
+
+Arguments:
+
+ Event - Pointer to a CTE Event variable
+ Argument - An argument to pass to the event handler when it is called
+
+Return Value:
+
+ 0 if the event could not be scheduled. Nonzero otherwise.
+
+--*/
+
+{
+ CTELockHandle Handle;
+
+ CTEGetLock(&(Event->ce_lock), &Handle);
+
+ if (!(Event->ce_scheduled)) {
+ Event->ce_scheduled = 1;
+ Event->ce_arg = Argument;
+
+ ExQueueWorkItem(
+ &(Event->ce_workitem),
+ CriticalWorkQueue
+ );
+ }
+
+ CTEFreeLock(&(Event->ce_lock), Handle);
+
+ return(1);
+}
+
+
+void
+CTEInitTimer(
+ CTETimer *Timer
+ )
+/*++
+
+Routine Description:
+
+ Initializes a CTE Timer variable.
+
+Arguments:
+
+ Timer - Timer variable to initialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ Timer->t_handler = NULL;
+ Timer->t_arg = NULL;
+ KeInitializeDpc(&(Timer->t_dpc), CTEpTimerHandler, Timer);
+ KeInitializeTimer(&(Timer->t_timer));
+}
+
+
+void *
+CTEStartTimer(
+ CTETimer *Timer,
+ unsigned long DueTime,
+ CTEEventRtn Handler,
+ void *Context
+ )
+
+/*++
+
+Routine Description:
+
+ Sets a CTE Timer for expiration.
+
+Arguments:
+
+ Timer - Pointer to a CTE Timer variable.
+ DueTime - Time in milliseconds after which the timer should expire.
+ Handler - Timer expiration handler routine.
+ Context - Argument to pass to the handler.
+
+Return Value:
+
+ 0 if the timer could not be set. Nonzero otherwise.
+
+--*/
+
+{
+ LARGE_INTEGER LargeDueTime;
+
+ ASSERT(Handler != NULL);
+
+ //
+ // Convert milliseconds to hundreds of nanoseconds and negate to make
+ // an NT relative timeout.
+ //
+ LargeDueTime.HighPart = 0;
+ LargeDueTime.LowPart = DueTime;
+ LargeDueTime = CTEConvertMillisecondsTo100ns(LargeDueTime);
+ LargeDueTime.QuadPart = -LargeDueTime.QuadPart;
+
+ Timer->t_handler = Handler;
+ Timer->t_arg = Context;
+
+ KeSetTimer(
+ &(Timer->t_timer),
+ LargeDueTime,
+ &(Timer->t_dpc)
+ );
+
+ return((void *) 1);
+}
+
+
+unsigned long
+CTESystemUpTime(
+ void
+ )
+
+/*++
+
+Routine Description:
+
+ Provides the time since system boot in milliseconds.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The time since boot in milliseconds.
+
+--*/
+
+{
+ LARGE_INTEGER TickCount;
+
+ //
+ // Get tick count and convert to hundreds of nanoseconds.
+ //
+ KeQueryTickCount(&TickCount);
+
+ TickCount = RtlExtendedIntegerMultiply(
+ TickCount,
+ (LONG) CTEpTimeIncrement
+ );
+
+ TickCount = CTEConvert100nsToMilliseconds(TickCount);
+
+ ASSERT(TickCount.HighPart == 0);
+
+ return(TickCount.LowPart);
+}
+
+
+extern uint
+CTEBlock(
+ IN CTEBlockStruc *BlockEvent
+ )
+{
+ NTSTATUS Status;
+
+ Status = KeWaitForSingleObject(
+ &(BlockEvent->cbs_event),
+ UserRequest,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ //
+ // BUGBUG: Do something better here.
+ //
+ BlockEvent->cbs_status = Status;
+ }
+
+ return(BlockEvent->cbs_status);
+}
+
+
+extern void
+CTESignal(
+ IN CTEBlockStruc *BlockEvent,
+ IN uint Status
+ )
+{
+ BlockEvent->cbs_status = Status;
+ KeSetEvent(&(BlockEvent->cbs_event), 0, FALSE);
+ return;
+}
+
+
+BOOLEAN
+CTEInitString(
+ IN OUT PNDIS_STRING DestinationString,
+ IN char *SourceString
+ )
+
+/*++
+
+Routine Description:
+
+ Converts a C style ASCII string to an NDIS_STRING. Resources needed for
+ the NDIS_STRING are allocated and must be freed by a call to
+ CTEFreeString.
+
+Arguments:
+
+ DestinationString - A pointer to an NDIS_STRING variable with no
+ associated data buffer.
+
+ SourceString - The C style ASCII string source.
+
+
+Return Value:
+
+ TRUE if the initialization succeeded. FALSE otherwise.
+
+--*/
+
+{
+ STRING AnsiString;
+ ULONG UnicodeLength;
+
+ RtlInitString(&AnsiString, SourceString);
+
+ // calculate size of unicoded ansi string + 2 for NULL terminator
+ UnicodeLength = RtlAnsiStringToUnicodeSize(&AnsiString) + 2;
+ DestinationString->MaximumLength = (USHORT) UnicodeLength;
+
+ // allocate storage for the unicode string
+ DestinationString->Buffer = ExAllocatePool(NonPagedPool, UnicodeLength);
+
+ if (DestinationString->Buffer == NULL) {
+ return(FALSE);
+ }
+
+ // Finally, convert the string to unicode
+ RtlAnsiStringToUnicodeString(DestinationString, &AnsiString, FALSE);
+
+ return(TRUE);
+}
+
+
+BOOLEAN
+CTEAllocateString(
+ PNDIS_STRING String,
+ unsigned short MaximumLength
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates a data buffer for Length characters in an uninitialized
+ NDIS_STRING. The allocated space must be freed by a call to CTEFreeString.
+
+
+Arguments:
+
+ String - A pointer to an NDIS_STRING variable with no
+ associated data buffer.
+
+ Length - The maximum length of the string. In Unicode, this is a
+ byte count.
+
+Return Value:
+
+ TRUE if the initialization succeeded. FALSE otherwise.
+
+--*/
+
+{
+ String->Buffer = ExAllocatePool(
+ NonPagedPool,
+ MaximumLength + sizeof(UNICODE_NULL)
+ );
+
+ if (String->Buffer == NULL) {
+ return(FALSE);
+ }
+
+ String->Length = 0;
+ String->MaximumLength = MaximumLength + sizeof(UNICODE_NULL);
+
+ return(TRUE);
+}
+
+
+
+LONG
+CTELogEvent(
+ IN PVOID LoggerId,
+ IN ULONG EventCode,
+ IN ULONG UniqueEventValue,
+ IN USHORT NumStrings,
+ IN PVOID StringsList, OPTIONAL
+ IN ULONG DataSize,
+ IN PVOID Data OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This function allocates an I/O error log record, fills it in and writes it
+ to the I/O error log.
+
+
+Arguments:
+
+ LoggerId - Pointer to the driver object logging this event.
+
+ EventCode - Identifies the error message.
+
+ UniqueEventValue - Identifies this instance of a given error message.
+
+ NumStrings - Number of unicode strings in strings list.
+
+ DataSize - Number of bytes of data.
+
+ Strings - Array of pointers to unicode strings (PWCHAR).
+
+ Data - Binary dump data for this message, each piece being
+ aligned on word boundaries.
+
+Return Value:
+
+ TDI_SUCCESS - The error was successfully logged.
+ TDI_BUFFER_TOO_SMALL - The error data was too large to be logged.
+ TDI_NO_RESOURCES - Unable to allocate memory.
+
+Notes:
+
+ This code is paged and may not be called at raised IRQL.
+
+--*/
+{
+ PIO_ERROR_LOG_PACKET ErrorLogEntry;
+ ULONG PaddedDataSize;
+ ULONG PacketSize;
+ ULONG TotalStringsSize = 0;
+ USHORT i;
+ PWCHAR *Strings;
+ PWCHAR Tmp;
+
+
+ PAGED_CODE();
+
+ Strings = (PWCHAR *) StringsList;
+
+ //
+ // Sum up the length of the strings
+ //
+ for (i=0; i<NumStrings; i++) {
+ PWCHAR currentString;
+ ULONG stringSize;
+
+ stringSize = sizeof(UNICODE_NULL);
+ currentString = Strings[i];
+
+ while (*currentString++ != UNICODE_NULL) {
+ stringSize += sizeof(WCHAR);
+ }
+
+ TotalStringsSize += stringSize;
+ }
+
+ if (DataSize % sizeof(ULONG)) {
+ PaddedDataSize = DataSize +
+ (sizeof(ULONG) - (DataSize % sizeof(ULONG)));
+ }
+ else {
+ PaddedDataSize = DataSize;
+ }
+
+ PacketSize = TotalStringsSize + PaddedDataSize;
+
+ if (PacketSize > CTE_MAX_EVENT_LOG_DATA_SIZE) {
+ return(TDI_BUFFER_TOO_SMALL); // Too much error data
+ }
+
+ //
+ // Now add in the size of the log packet, but subtract 4 from the data
+ // since the packet struct contains a ULONG for data.
+ //
+ if (PacketSize > sizeof(ULONG)) {
+ PacketSize += sizeof(IO_ERROR_LOG_PACKET) - sizeof(ULONG);
+ }
+ else {
+ PacketSize += sizeof(IO_ERROR_LOG_PACKET);
+ }
+
+ ASSERT(PacketSize <= ERROR_LOG_MAXIMUM_SIZE);
+
+ ErrorLogEntry = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(
+ (PDRIVER_OBJECT) LoggerId,
+ (UCHAR) PacketSize
+ );
+
+ if (ErrorLogEntry == NULL) {
+ return(TDI_NO_RESOURCES);
+ }
+
+ //
+ // Fill in the necessary log packet fields.
+ //
+ ErrorLogEntry->UniqueErrorValue = UniqueEventValue;
+ ErrorLogEntry->ErrorCode = EventCode;
+ ErrorLogEntry->NumberOfStrings = NumStrings;
+ ErrorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) +
+ PaddedDataSize - sizeof(ULONG);
+ ErrorLogEntry->DumpDataSize = (USHORT) PaddedDataSize;
+
+ //
+ // Copy the Dump Data to the packet
+ //
+ if (DataSize > 0) {
+ RtlMoveMemory(
+ (PVOID) ErrorLogEntry->DumpData,
+ Data,
+ DataSize
+ );
+ }
+
+ //
+ // Copy the strings to the packet.
+ //
+ Tmp = (PWCHAR) ((char *) ErrorLogEntry +
+ ErrorLogEntry->StringOffset +
+ PaddedDataSize);
+
+ for (i=0; i<NumStrings; i++) {
+ PWCHAR wchPtr = Strings[i];
+
+ while( (*Tmp++ = *wchPtr++) != UNICODE_NULL);
+ }
+
+ IoWriteErrorLogEntry(ErrorLogEntry);
+
+ return(TDI_SUCCESS);
+}
+
diff --git a/private/ntos/tdi/wrapper/makefile b/private/ntos/tdi/wrapper/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/wrapper/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/wrapper/sources b/private/ntos/tdi/wrapper/sources
new file mode 100644
index 000000000..e315b190c
--- /dev/null
+++ b/private/ntos/tdi/wrapper/sources
@@ -0,0 +1,49 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Dave Beaver (dbeaver) 15 June 1991
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=tdi
+
+TARGETNAME=tdi
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=EXPORT_DRIVER
+
+INCLUDES=..\..\inc;..\..\..\inc
+
+C_DEFINES=-DNT
+
+SOURCES= \
+ tdi.c \
+ cxport.c \
+ tdipnp.c \
+ tdi.rc
+
+DLLDEF=tdi.def
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+!IFNDEF 386_WARNING_LEVEL
+386_WARNING_LEVEL=/W3
+!ENDIF
+
diff --git a/private/ntos/tdi/wrapper/tdi.c b/private/ntos/tdi/wrapper/tdi.c
new file mode 100644
index 000000000..b2a1805f7
--- /dev/null
+++ b/private/ntos/tdi/wrapper/tdi.c
@@ -0,0 +1,1737 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ tdi.c
+
+Abstract:
+
+ This module contains code which assists the process of writing an NT
+ TDI client.
+
+Author:
+
+ David Beaver (dbeaver) 15 June 1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include <ntos.h>
+#include <status.h>
+#include <tdikrnl.h>
+#include <ndis.h>
+#include "tdipnp.h"
+
+#if DBG
+
+#include "tdidebug.h"
+
+ULONG TdiDebug;
+
+#define IF_TDIDBG(sts) \
+ if ((TdiDebug & sts) != 0)
+
+#define TDI_DEBUG_NAMES 0x00000001
+#define TDI_DEBUG_DISPATCH 0x00000002
+#define TDI_DEBUG_MAP 0x00000004
+
+#else
+
+#define IF_TDIDBG(sts) \
+ if (0)
+#endif
+
+ULONG TdiInitializationCount;
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ Temporary entry point needed to initialize the TDI wrapper driver.
+
+Arguments:
+
+ DriverObject - Pointer to the driver object created by the system.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ //
+ // BUGBUG This should not be needed!
+ //
+
+ UNREFERENCED_PARAMETER(DriverObject);
+
+ return STATUS_SUCCESS;
+
+} // DriverEntry
+
+
+NTSTATUS
+TdiMapUserRequest(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine maps a user request from the NtDeviceIoControlFile format
+ to the kernel mode request format. It does this by probing and locking all
+ buffers of interest, copying parameter sets to the stack pointer as
+ appropriate, and generally preparing for the kernel IO form.
+
+Arguments:
+
+ Irp - pointer to the irp containing this request.
+
+Return Value:
+
+ NTSTATUS - status of operation. STATUS_UNSUCCESSFUL if the request could
+ not be mapped, STATUS_NOT_IMPLEMENTED if the IOCTL is not recognized
+ (allowing driver writers to extend the supported IOCTLs if needed), and
+ STATUS_SUCCESS if the request was mapped successfully.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+
+ DeviceObject;
+
+ Status = STATUS_INVALID_PARAMETER;
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+
+ case IOCTL_TDI_ACCEPT:
+ IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IrpSp->MinorFunction = TDI_ACCEPT;
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ case IOCTL_TDI_ACTION:
+
+ IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IrpSp->MinorFunction = TDI_ACTION;
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ case IOCTL_TDI_CONNECT:
+ {
+ PTDI_REQUEST_CONNECT userRequest;
+ PTDI_REQUEST_KERNEL_CONNECT request;
+ PTDI_CONNECTION_INFORMATION connInfo;
+ PCHAR ptr;
+
+ if (Irp->AssociatedIrp.SystemBuffer) {
+
+ IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IrpSp->MinorFunction = TDI_CONNECT;
+
+ userRequest =
+ (PTDI_REQUEST_CONNECT)Irp->AssociatedIrp.SystemBuffer;
+ connInfo = userRequest->RequestConnectionInformation;
+ ptr = (PCHAR)(connInfo + 1);
+ connInfo->UserData = ptr;
+ ptr += connInfo->UserDataLength;
+ connInfo->Options = ptr;
+ ptr += connInfo->OptionsLength;
+ connInfo->RemoteAddress = ptr;
+
+ request = (PTDI_REQUEST_KERNEL_CONNECT)&IrpSp->Parameters;
+ request->RequestConnectionInformation = connInfo;
+
+ //
+ // BUGBUG: Fill this in too?
+ //
+
+ request->ReturnConnectionInformation = NULL;
+
+ Status = STATUS_SUCCESS;
+
+ }
+ break;
+ }
+
+ case IOCTL_TDI_DISCONNECT:
+ {
+ IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IrpSp->MinorFunction = TDI_DISCONNECT;
+
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ case IOCTL_TDI_LISTEN:
+ {
+ PTDI_REQUEST_LISTEN userRequest;
+ PTDI_REQUEST_KERNEL_LISTEN request;
+
+ if (Irp->AssociatedIrp.SystemBuffer) {
+
+ userRequest =
+ (PTDI_REQUEST_LISTEN)Irp->AssociatedIrp.SystemBuffer;
+
+ IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IrpSp->MinorFunction = TDI_LISTEN;
+
+ request = (PTDI_REQUEST_KERNEL_LISTEN)&IrpSp->Parameters;
+ request->RequestFlags = userRequest->ListenFlags;
+
+ Status = STATUS_SUCCESS;
+
+ }
+ break;
+ }
+
+ case IOCTL_TDI_QUERY_INFORMATION:
+ {
+ PTDI_REQUEST_QUERY_INFORMATION userRequest;
+ PTDI_REQUEST_KERNEL_QUERY_INFORMATION request;
+ PTDI_CONNECTION_INFORMATION connInfo;
+ PCHAR ptr;
+
+ if (Irp->AssociatedIrp.SystemBuffer) {
+
+ userRequest =
+ (PTDI_REQUEST_QUERY_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+
+ IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IrpSp->MinorFunction = TDI_QUERY_INFORMATION;
+
+ request = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&IrpSp->Parameters;
+ request->QueryType = userRequest->QueryType;
+ if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >
+ sizeof (TDI_REQUEST_QUERY_INFORMATION))
+ {
+ connInfo = (PTDI_CONNECTION_INFORMATION)(userRequest + 1);
+ ptr = (PCHAR)(connInfo + 1);
+ connInfo->UserData = ptr;
+ ptr += connInfo->UserDataLength;
+ connInfo->Options = ptr;
+ ptr += connInfo->OptionsLength;
+ connInfo->RemoteAddress = ptr;
+ request->RequestConnectionInformation = connInfo;
+ }
+ else
+ request->RequestConnectionInformation = NULL;
+
+ Status = STATUS_SUCCESS;
+
+ }
+ break;
+ }
+
+ case IOCTL_TDI_RECEIVE:
+ {
+ PTDI_REQUEST_RECEIVE userRequest;
+ PTDI_REQUEST_KERNEL_RECEIVE request;
+ ULONG receiveLength;
+
+ if (Irp->AssociatedIrp.SystemBuffer) {
+
+ userRequest =
+ (PTDI_REQUEST_RECEIVE)Irp->AssociatedIrp.SystemBuffer;
+ receiveLength =
+ IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IrpSp->MinorFunction = TDI_RECEIVE;
+
+ request = (PTDI_REQUEST_KERNEL_RECEIVE)&IrpSp->Parameters;
+ request->ReceiveLength = receiveLength;
+ request->ReceiveFlags = userRequest->ReceiveFlags;
+
+ Status = STATUS_SUCCESS;
+
+ }
+ break;
+ }
+
+ case IOCTL_TDI_RECEIVE_DATAGRAM:
+ {
+ PTDI_REQUEST_RECEIVE_DATAGRAM userRequest;
+ PTDI_REQUEST_KERNEL_RECEIVEDG request;
+ ULONG receiveLength;
+
+ if (Irp->AssociatedIrp.SystemBuffer) {
+
+ userRequest =
+ (PTDI_REQUEST_RECEIVE_DATAGRAM)Irp->AssociatedIrp.SystemBuffer;
+ receiveLength =
+ IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IrpSp->MinorFunction = TDI_RECEIVE_DATAGRAM;
+
+ request = (PTDI_REQUEST_KERNEL_RECEIVEDG)&IrpSp->Parameters;
+ request->ReceiveLength = receiveLength;
+ request->ReceiveFlags = userRequest->ReceiveFlags;
+ request->ReceiveDatagramInformation = userRequest->ReceiveDatagramInformation;
+ request->ReturnDatagramInformation = userRequest->ReturnInformation;
+
+ Status = STATUS_SUCCESS;
+
+ }
+ break;
+ }
+
+ case IOCTL_TDI_SEND:
+ {
+ PTDI_REQUEST_SEND userRequest;
+ PTDI_REQUEST_KERNEL_SEND request;
+ ULONG sendLength;
+
+ if (Irp->AssociatedIrp.SystemBuffer) {
+
+ userRequest =
+ (PTDI_REQUEST_SEND)Irp->AssociatedIrp.SystemBuffer;
+ sendLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IrpSp->MinorFunction = TDI_SEND;
+
+ request = (PTDI_REQUEST_KERNEL_SEND)&IrpSp->Parameters;
+ request->SendLength = sendLength;
+ request->SendFlags = userRequest->SendFlags;
+
+ Status = STATUS_SUCCESS;
+
+ }
+ break;
+ }
+
+ case IOCTL_TDI_SEND_DATAGRAM:
+ {
+ PTDI_REQUEST_SEND_DATAGRAM userRequest;
+ PTDI_REQUEST_KERNEL_SENDDG request;
+ ULONG sendLength;
+
+ if (Irp->AssociatedIrp.SystemBuffer) {
+
+ sendLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IrpSp->MinorFunction = TDI_SEND_DATAGRAM;
+
+ request = (PTDI_REQUEST_KERNEL_SENDDG)&IrpSp->Parameters;
+ request->SendLength = sendLength;
+
+ userRequest = (PTDI_REQUEST_SEND_DATAGRAM)Irp->AssociatedIrp.SystemBuffer;
+ request->SendDatagramInformation = userRequest->SendDatagramInformation;
+ Status = STATUS_SUCCESS;
+ }
+ break;
+ }
+
+ case IOCTL_TDI_SET_EVENT_HANDLER:
+
+ //
+ // Because this request will enable direct callouts from the
+ // transport provider at DISPATCH_LEVEL to a client-specified
+ // routine, this request is only valid in kernel mode, denying
+ // access to this request in user mode.
+ //
+
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+
+ case IOCTL_TDI_SET_INFORMATION:
+ {
+ PTDI_REQUEST_SET_INFORMATION userRequest;
+ PTDI_REQUEST_KERNEL_SET_INFORMATION request;
+
+ if (Irp->AssociatedIrp.SystemBuffer) {
+
+ userRequest =
+ (PTDI_REQUEST_SET_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+
+ IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IrpSp->MinorFunction = TDI_SET_INFORMATION;
+
+ request = (PTDI_REQUEST_KERNEL_SET_INFORMATION)&IrpSp->Parameters;
+ request->SetType = userRequest->SetType;
+ request->RequestConnectionInformation = NULL;
+
+ Status = STATUS_SUCCESS;
+
+ }
+ break;
+ }
+
+ case IOCTL_TDI_ASSOCIATE_ADDRESS:
+ {
+ PTDI_REQUEST_ASSOCIATE_ADDRESS userRequest;
+ PTDI_REQUEST_KERNEL_ASSOCIATE request;
+
+ if (Irp->AssociatedIrp.SystemBuffer) {
+
+ IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IrpSp->MinorFunction = TDI_ASSOCIATE_ADDRESS;
+
+ userRequest =
+ (PTDI_REQUEST_ASSOCIATE_ADDRESS)Irp->AssociatedIrp.SystemBuffer;
+ request = (PTDI_REQUEST_KERNEL_ASSOCIATE)&IrpSp->Parameters;
+ request->AddressHandle = userRequest->AddressHandle;
+
+ Status = STATUS_SUCCESS;
+
+ }
+ break;
+ }
+
+ case IOCTL_TDI_DISASSOCIATE_ADDRESS:
+ {
+ IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IrpSp->MinorFunction = TDI_DISASSOCIATE_ADDRESS;
+
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ default:
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ return Status;
+
+}
+
+
+NTSTATUS
+TdiDefaultConnectHandler(
+ IN PVOID TdiEventContext,
+ IN LONG RemoteAddressLength,
+ IN PVOID RemoteAddress,
+ IN LONG UserDataLength,
+ IN PVOID UserData,
+ IN LONG OptionsLength,
+ IN PVOID Options,
+ OUT CONNECTION_CONTEXT *ConnectionContext,
+ OUT PIRP *AcceptIrp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a connect request has completed. The connection
+ is fully functional when the indication occurs.
+
+Arguments:
+
+ TdiEventContext - the context value passed in by the user in the Set Event Handler call
+
+ RemoteAddressLength,
+
+ RemoteAddress,
+
+ UserDataLength,
+
+ UserData,
+
+ OptionsLength,
+
+ Options,
+
+ ConnectionId
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+{
+ UNREFERENCED_PARAMETER (TdiEventContext);
+ UNREFERENCED_PARAMETER (RemoteAddressLength);
+ UNREFERENCED_PARAMETER (RemoteAddress);
+ UNREFERENCED_PARAMETER (UserDataLength);
+ UNREFERENCED_PARAMETER (UserData);
+ UNREFERENCED_PARAMETER (OptionsLength);
+ UNREFERENCED_PARAMETER (Options);
+ UNREFERENCED_PARAMETER (ConnectionContext);
+
+ return STATUS_INSUFFICIENT_RESOURCES; // do nothing
+}
+
+
+NTSTATUS
+TdiDefaultDisconnectHandler(
+ IN PVOID TdiEventContext,
+ IN CONNECTION_CONTEXT ConnectionContext,
+ IN LONG DisconnectDataLength,
+ IN PVOID DisconnectData,
+ IN LONG DisconnectInformationLength,
+ IN PVOID DisconnectInformation,
+ IN ULONG DisconnectFlags
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used as the default disconnect event handler
+ for the transport endpoint. It is pointed to by a field in the
+ TP_ENDPOINT structure for an endpoint when the endpoint is
+ created, and also whenever the TdiSetEventHandler request is
+ submitted with a NULL EventHandler field.
+
+Arguments:
+
+ TransportEndpoint - Pointer to open file object.
+
+ Context - Typeless pointer specifying connection context.
+
+ DisconnectIndicators - Value indicating reason for disconnection indication.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (TdiEventContext);
+ UNREFERENCED_PARAMETER (ConnectionContext);
+ UNREFERENCED_PARAMETER (DisconnectDataLength);
+ UNREFERENCED_PARAMETER (DisconnectData);
+ UNREFERENCED_PARAMETER (DisconnectInformationLength);
+ UNREFERENCED_PARAMETER (DisconnectInformation);
+ UNREFERENCED_PARAMETER (DisconnectFlags);
+
+ return STATUS_SUCCESS; // do nothing but return successfully.
+
+} /* DefaultDisconnectHandler */
+
+
+NTSTATUS
+TdiDefaultErrorHandler(
+ IN PVOID TdiEventContext, // the endpoint's file object.
+ IN NTSTATUS Status // status code indicating error type.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used as the default error event handler for
+ the transport endpoint. It is pointed to by a field in the
+ TP_ENDPOINT structure for an endpoint when the endpoint is
+ created, and also whenever the TdiSetEventHandler request is
+ submitted with a NULL EventHandler field.
+
+Arguments:
+
+ TransportEndpoint - Pointer to open file object.
+
+ Status - Status code indicated by this event.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (TdiEventContext);
+ UNREFERENCED_PARAMETER (Status);
+
+ return STATUS_SUCCESS; // do nothing but return successfully.
+
+} /* DefaultErrorHandler */
+
+
+NTSTATUS
+TdiDefaultReceiveHandler(
+ IN PVOID TdiEventContext,
+ IN CONNECTION_CONTEXT ConnectionContext,
+ IN ULONG ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT ULONG *BytesTaken,
+ IN PVOID Tsdu, // pointer describing this TSDU, typically a lump of bytes
+ OUT PIRP *IoRequestPacket // TdiReceive IRP if MORE_PROCESSING_REQUIRED.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used as the default receive event handler for
+ the transport endpoint. It is pointed to by a field in the
+ TP_ENDPOINT structure for an endpoint when the endpoint is
+ created, and also whenever the TdiSetEventHandler request is
+ submitted with a NULL EventHandler field.
+
+Arguments:
+
+ TdiEventContext - Pointer to the client-provided context value specified
+ in the TdiSetEventHandler call for TDI_EVENT_RECEIVE.
+
+ ConnectionContext - The client-supplied context associated with
+ the connection on which this connection-oriented TSDU was received.
+
+ ReceiveFlags - Bitflags which indicate the circumstances surrounding
+ this TSDU's reception.
+
+ BytesIndicated - The number of bytes of this TSDU that are being presented
+ to the client in this indication.This value is always less than
+ or equal to BytesAvailable.
+
+ BytesAvailable - The total number of bytes of this TSDU presently
+ available from the transport.
+
+ BytesTaken - Return value indicating the number of bytes of data that the
+ client copied from the indication data.
+
+ Tsdu - Pointer to an MDL chain that describes the (first) part of the
+ (partially) received Transport Service Data Unit, less headers.
+
+ IoRequestPacket - Pointer to a location where the event handler may
+ chose to return a pointer to an I/O Request Packet (IRP) to satisfy
+ the incoming data. If returned, this IRP must be formatted as a
+ valid TdiReceive request, except that the ConnectionId field of
+ the TdiRequest is ignored and is automatically filled in by the
+ transport provider.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (TdiEventContext);
+ UNREFERENCED_PARAMETER (ConnectionContext);
+ UNREFERENCED_PARAMETER (ReceiveFlags);
+ UNREFERENCED_PARAMETER (BytesIndicated);
+ UNREFERENCED_PARAMETER (BytesAvailable);
+ UNREFERENCED_PARAMETER (BytesTaken);
+ UNREFERENCED_PARAMETER (Tsdu);
+ UNREFERENCED_PARAMETER (IoRequestPacket);
+
+ return STATUS_DATA_NOT_ACCEPTED; // no handler in place.
+
+} /* DefaultReceiveHandler */
+
+
+NTSTATUS
+TdiDefaultRcvDatagramHandler(
+ IN PVOID TdiEventContext, // the event context
+ IN LONG SourceAddressLength, // length of the originator of the datagram
+ IN PVOID SourceAddress, // string describing the originator of the datagram
+ IN LONG OptionsLength, // options for the receive
+ IN PVOID Options, //
+ IN ULONG ReceiveDatagramFlags, //
+ IN ULONG BytesIndicated, // number of bytes this indication
+ IN ULONG BytesAvailable, // number of bytes in complete Tsdu
+ OUT ULONG *BytesTaken, // number of bytes used
+ IN PVOID Tsdu, // pointer describing this TSDU, typically a lump of bytes
+ OUT PIRP *IoRequestPacket // TdiReceive IRP if MORE_PROCESSING_REQUIRED.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used as the default receive datagram event
+ handler for the transport endpoint. It is pointed to by a
+ field in the TP_ENDPOINT structure for an endpoint when the
+ endpoint is created, and also whenever the TdiSetEventHandler
+ request is submitted with a NULL EventHandler field.
+
+Arguments:
+
+ TdiEventContext - Pointer to the client-provided context value specified
+ in the TdiSetEventHandler call for TDI_EVENT_RECEIVE_DATAGRAM.
+
+ DestinationAddress - Pointer to the network name of the destination
+ to which the datagram was directed.
+
+ SourceAddress - Pointer to the network name of the source from which
+ the datagram originated.
+
+ Tsap - Transport service access point on which this datagram was received.
+
+ ReceiveIndicators - Bitflags which indicate the circumstances surrounding
+ this TSDU's reception.
+
+ Tsdu - Pointer to an MDL chain that describes the (first) part of the
+ (partially) received Transport Service Data Unit, less headers.
+
+ IoRequestPacket - Pointer to a location where the event handler may
+ chose to return a pointer to an I/O Request Packet (IRP) to satisfy
+ the incoming data. If returned, this IRP must be formatted as a
+ valid TdiReceiveDatagram request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (TdiEventContext);
+ UNREFERENCED_PARAMETER (SourceAddressLength);
+ UNREFERENCED_PARAMETER (SourceAddress);
+ UNREFERENCED_PARAMETER (OptionsLength);
+ UNREFERENCED_PARAMETER (Options);
+ UNREFERENCED_PARAMETER (BytesIndicated);
+ UNREFERENCED_PARAMETER (BytesAvailable);
+ UNREFERENCED_PARAMETER (BytesTaken);
+ UNREFERENCED_PARAMETER (Tsdu);
+ UNREFERENCED_PARAMETER (IoRequestPacket);
+
+ return STATUS_DATA_NOT_ACCEPTED; // no handler in place.
+
+} /* DefaultRcvDatagramHandler */
+
+
+NTSTATUS
+TdiDefaultRcvExpeditedHandler(
+ IN PVOID TdiEventContext,
+ IN CONNECTION_CONTEXT ConnectionContext,
+ IN ULONG ReceiveFlags, //
+ IN ULONG BytesIndicated, // number of bytes in this indication
+ IN ULONG BytesAvailable, // number of bytes in complete Tsdu
+ OUT ULONG *BytesTaken, // number of bytes used by indication routine
+ IN PVOID Tsdu, // pointer describing this TSDU, typically a lump of bytes
+ OUT PIRP *IoRequestPacket // TdiReceive IRP if MORE_PROCESSING_REQUIRED.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used as the default expedited receive event handler
+ for the transport endpoint. It is pointed to by a field in the
+ TP_ENDPOINT structure for an endpoint when the endpoint is
+ created, and also whenever the TdiSetEventHandler request is
+ submitted with a NULL EventHandler field.
+
+Arguments:
+
+ TdiEventContext - Pointer to the client-provided context value specified
+ in the TdiSetEventHandler call for TDI_EVENT_RECEIVE.
+
+ ConnectionContext - The client-supplied context associated with
+ the connection on which this connection-oriented TSDU was received.
+
+ ReceiveFlags - Bitflags which indicate the circumstances surrounding
+ this TSDU's reception.
+
+ BytesIndicated - The number of bytes of this TSDU that are being presented
+ to the client in this indication.This value is always less than
+ or equal to BytesAvailable.
+
+ BytesAvailable - The total number of bytes of this TSDU presently
+ available from the transport.
+
+ BytesTaken - Return value indicating the number of bytes of data that the
+ client copied from the indication data.
+
+ Tsdu - Pointer to an MDL chain that describes the (first) part of the
+ (partially) received Transport Service Data Unit, less headers.
+
+ IoRequestPacket - Pointer to a location where the event handler may
+ chose to return a pointer to an I/O Request Packet (IRP) to satisfy
+ the incoming data. If returned, this IRP must be formatted as a
+ valid TdiReceive request, except that the ConnectionId field of
+ the TdiRequest is ignored and is automatically filled in by the
+ transport provider.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+{
+ UNREFERENCED_PARAMETER (TdiEventContext);
+ UNREFERENCED_PARAMETER (ConnectionContext);
+ UNREFERENCED_PARAMETER (ReceiveFlags);
+ UNREFERENCED_PARAMETER (BytesIndicated);
+ UNREFERENCED_PARAMETER (BytesAvailable);
+ UNREFERENCED_PARAMETER (BytesTaken);
+ UNREFERENCED_PARAMETER (Tsdu);
+ UNREFERENCED_PARAMETER (IoRequestPacket);
+
+ return STATUS_DATA_NOT_ACCEPTED;
+
+} /* DefaultRcvExpeditedHandler */
+
+NTSTATUS
+TdiDefaultChainedReceiveHandler (
+ IN PVOID TdiEventContext,
+ IN CONNECTION_CONTEXT ConnectionContext,
+ IN ULONG ReceiveFlags,
+ IN ULONG ReceiveLength,
+ IN ULONG StartingOffset,
+ IN PMDL Tsdu,
+ IN PVOID TsduDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used as the default chanied receive event handler
+ for the transport endpoint. It is pointed to by a field in the
+ TP_ENDPOINT structure for an endpoint when the endpoint is
+ created, and also whenever the TdiSetEventHandler request is
+ submitted with a NULL EventHandler field.
+
+Arguments:
+
+ TdiEventContext - Pointer to the client-provided context value specified
+ in the TdiSetEventHandler call for TDI_EVENT_CHAINED_RECEIVE.
+
+ ConnectionContext - The client-supplied context associated with
+ the connection on which this connection-oriented TSDU was received.
+
+ ReceiveFlags - Bitflags which indicate the circumstances surrounding
+ this TSDU's reception.
+
+ ReceiveLength - The length in bytes of client data in the TSDU.
+
+ StartingOffset - The offset, in bytes from the beginning of the TSDU,
+ at which the client data begins.
+
+ Tsdu - Pointer to an MDL chain that describes the entire received
+ Transport Service Data Unit.
+
+ TsduDescriptor - A descriptor for the TSDU which must be passed to
+ TdiReturnChainedReceives in order to return the TSDU for reuse.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (TdiEventContext);
+ UNREFERENCED_PARAMETER (ConnectionContext);
+ UNREFERENCED_PARAMETER (ReceiveFlags);
+ UNREFERENCED_PARAMETER (ReceiveLength);
+ UNREFERENCED_PARAMETER (StartingOffset);
+ UNREFERENCED_PARAMETER (Tsdu);
+ UNREFERENCED_PARAMETER (TsduDescriptor);
+
+ return STATUS_DATA_NOT_ACCEPTED;
+
+} /* DefaultChainedReceiveHandler */
+
+
+NTSTATUS
+TdiDefaultChainedRcvDatagramHandler(
+ IN PVOID TdiEventContext,
+ IN LONG SourceAddressLength,
+ IN PVOID SourceAddress,
+ IN LONG OptionsLength,
+ IN PVOID Options,
+ IN ULONG ReceiveDatagramFlags,
+ IN ULONG ReceiveDatagramLength,
+ IN ULONG StartingOffset,
+ IN PMDL Tsdu,
+ IN PVOID TsduDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used as the default chained receive datagram
+ event handler for the transport endpoint. It is pointed to by
+ a field in the TP_ENDPOINT structure for an endpoint when the
+ endpoint is created, and also whenever the TdiSetEventHandler
+ request is submitted with a NULL EventHandler field.
+
+Arguments:
+
+ TdiEventContext - Pointer to the client-provided context value specified
+ in the TdiSetEventHandler call for TDI_EVENT_CHAINED_RECEIVE_DATAGRAM.
+
+ SourceAddressLength - The length of the source network address.
+
+ SourceAddress - Pointer to the network address of the source from which
+ the datagram originated.
+
+ OptionsLength - The length of the transport options accompanying this TSDU.
+
+ Options - Pointer to the transport options accompanying this TSDU.
+
+ ReceiveDatagramFlags - Bitflags which indicate the circumstances
+ surrounding this TSDU's reception.
+
+ ReceiveDatagramLength - The length, in bytes, of the client data in
+ this TSDU.
+
+ StartingOffset - The offset, in bytes from the start of the TSDU, at
+ which the client data begins.
+
+ Tsdu - Pointer to an MDL chain that describes the received Transport
+ Service Data Unit.
+
+ TsduDescriptor - A descriptor for the TSDU which must be passed to
+ TdiReturnChainedReceives in order to return the TSDU for reuse.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (TdiEventContext);
+ UNREFERENCED_PARAMETER (SourceAddressLength);
+ UNREFERENCED_PARAMETER (SourceAddress);
+ UNREFERENCED_PARAMETER (OptionsLength);
+ UNREFERENCED_PARAMETER (Options);
+ UNREFERENCED_PARAMETER (ReceiveDatagramLength);
+ UNREFERENCED_PARAMETER (StartingOffset);
+ UNREFERENCED_PARAMETER (Tsdu);
+ UNREFERENCED_PARAMETER (TsduDescriptor);
+
+ return STATUS_DATA_NOT_ACCEPTED;
+
+} /* DefaultChainedRcvDatagramHandler */
+
+
+NTSTATUS
+TdiDefaultChainedRcvExpeditedHandler(
+ IN PVOID TdiEventContext,
+ IN CONNECTION_CONTEXT ConnectionContext,
+ IN ULONG ReceiveFlags,
+ IN ULONG ReceiveLength,
+ IN ULONG StartingOffset,
+ IN PMDL Tsdu,
+ IN PVOID TsduDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used as the default chained expedited receive event
+ handler for the transport endpoint. It is pointed to by a field
+ in the TP_ENDPOINT structure for an endpoint when the endpoint is
+ created, and also whenever the TdiSetEventHandler request is
+ submitted with a NULL EventHandler field.
+
+Arguments:
+
+ TdiEventContext - Pointer to the client-provided context value specified
+ in the TdiSetEventHandler call for TDI_EVENT_CHAINED_RECEIVE_EXPEDITED.
+
+ ConnectionContext - The client-supplied context associated with
+ the connection on which this connection-oriented TSDU was received.
+
+ ReceiveFlags - Bitflags which indicate the circumstances surrounding
+ this TSDU's reception.
+
+ ReceiveLength - The length in bytes of client data in the TSDU.
+
+ StartingOffset - The offset, in bytes from the beginning of the TSDU,
+ at which the client data begins.
+
+ Tsdu - Pointer to an MDL chain that describes the entire received
+ Transport Service Data Unit.
+
+ TsduDescriptor - A descriptor for the TSDU which must be passed to
+ TdiReturnChainedReceives in order to return the TSDU for reuse.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+{
+ UNREFERENCED_PARAMETER (TdiEventContext);
+ UNREFERENCED_PARAMETER (ConnectionContext);
+ UNREFERENCED_PARAMETER (ReceiveFlags);
+ UNREFERENCED_PARAMETER (ReceiveLength);
+ UNREFERENCED_PARAMETER (StartingOffset);
+ UNREFERENCED_PARAMETER (Tsdu);
+ UNREFERENCED_PARAMETER (TsduDescriptor);
+
+ return STATUS_DATA_NOT_ACCEPTED;
+
+} /* DefaultRcvExpeditedHandler */
+
+
+NTSTATUS
+TdiDefaultSendPossibleHandler (
+ IN PVOID TdiEventContext,
+ IN PVOID ConnectionContext,
+ IN ULONG BytesAvailable)
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ TdiEventContext - the context value passed in by the user in the Set Event Handler call
+
+ ConnectionContext - connection context of connection which can be sent on
+
+ BytesAvailable - number of bytes which can now be sent
+
+Return Value:
+
+ ignored by the transport
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (TdiEventContext);
+ UNREFERENCED_PARAMETER (ConnectionContext);
+ UNREFERENCED_PARAMETER (BytesAvailable);
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+TdiBuildNetbiosAddress(
+ IN PUCHAR NetbiosName,
+ IN BOOLEAN IsGroupName,
+ IN OUT PTA_NETBIOS_ADDRESS NetworkName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine builds a TA_NETBIOS_ADDRESS structure in the locations pointed
+ to by NetworkName. All fields are filled out.
+
+Arguments:
+
+ NetbiosName - Pointer to a 16-byte buffer where the a netbios name is
+ supplied.
+
+ IsGroupName - TRUE if this name is a group name, false otherwise.
+
+ NetworkName - A pointer to a TA_NETBIOS_ADDRESS structure that is to
+ receive the buid TDI address.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_TDIDBG (TDI_DEBUG_NAMES) {
+ DbgPrint ("TdiBuildNetBIOSAddress: Entered.\n");
+ }
+
+ NetworkName->TAAddressCount = 1;
+ NetworkName->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ NetworkName->Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
+
+ if (IsGroupName) {
+ NetworkName->Address[0].Address[0].NetbiosNameType =
+ TDI_ADDRESS_NETBIOS_TYPE_GROUP;
+ } else {
+ NetworkName->Address[0].Address[0].NetbiosNameType =
+ TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ }
+
+ RtlCopyMemory (
+ NetworkName->Address[0].Address[0].NetbiosName,
+ NetbiosName,
+ 16);
+
+} /* TdiBuildNetbiosAddress */
+
+
+NTSTATUS
+TdiBuildNetbiosAddressEa (
+ IN PUCHAR Buffer,
+ IN BOOLEAN IsGroupName,
+ IN PUCHAR NetbiosName
+ )
+
+/*++
+
+Routine Description:
+
+ Builds an EA describing a Netbios address in the buffer supplied by the
+ user.
+
+Arguments:
+
+ Buffer - pointer to a buffer that the ea is to be built in. This buffer
+ must be at least 40 bytes long.
+
+ IsGroupName - true if the netbios name is a group name, false otherwise.
+
+ NetbiosName - the netbios name to be inserted in the EA to be built.
+
+Return Value:
+
+ An informative error code if something goes wrong. STATUS_SUCCESS if the
+ ea is built properly.
+
+--*/
+
+{
+ PFILE_FULL_EA_INFORMATION EaBuffer;
+ PTA_NETBIOS_ADDRESS TAAddress;
+ ULONG Length;
+
+ IF_TDIDBG (TDI_DEBUG_NAMES) {
+ DbgPrint ("TdiBuildNetbiosAddressEa: Entered\n ");
+ }
+
+ try {
+ Length = FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) +
+ TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
+ sizeof (TA_NETBIOS_ADDRESS);
+ EaBuffer = (PFILE_FULL_EA_INFORMATION)Buffer;
+
+ if (EaBuffer == NULL) {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ EaBuffer->NextEntryOffset = 0;
+ EaBuffer->Flags = 0;
+ EaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
+ EaBuffer->EaValueLength = sizeof (TA_NETBIOS_ADDRESS);
+
+ RtlCopyMemory (
+ EaBuffer->EaName,
+ TdiTransportAddress,
+ EaBuffer->EaNameLength + 1);
+
+ TAAddress = (PTA_NETBIOS_ADDRESS)&EaBuffer->EaName[EaBuffer->EaNameLength+1];
+
+ TdiBuildNetbiosAddress (
+ NetbiosName,
+ IsGroupName,
+ TAAddress);
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ //
+ // Couldn't touch the passed parameters; just return an error
+ // status.
+ //
+
+ return GetExceptionCode();
+ }
+
+ return STATUS_SUCCESS;
+
+} /* TdiBuildNetbiosAddressEa */
+
+
+VOID
+TdiMapBuffer(
+ IN PMDL MdlChain
+ )
+
+/*++
+
+Routine Description:
+
+ This routine ensures that the MappedSystemVa field of every MDL in an
+ MDL chain is valid; calling MmMapLockedPages where necessary.
+
+ !!! This routine no longer does anything, and should be removed!
+
+Arguments:
+
+ MdlChain - Pointer to a chain of MDLs describing the data to be mapped.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ MdlChain;
+
+ return;
+
+} /* TdiMapBuffer */
+
+
+VOID
+TdiUnmapBuffer(
+ IN PMDL MdlChain
+ )
+
+/*++
+
+Routine Description:
+
+ This routine restores the mapped status of every MDL in an MDL chain
+ where the MappedSystemVa field is equal to StartVa+ByteOffset.
+
+ !!! This routine no longer does anything, and should be removed!
+
+Arguments:
+
+ MdlChain - Pointer to a chain of MDLs describing the data to be unmapped.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ MdlChain;
+
+ return;
+
+} /* TdiUnmapBuffer */
+
+
+NTSTATUS
+TdiCopyMdlToBuffer(
+ IN PMDL SourceMdlChain,
+ IN ULONG SourceOffset,
+ IN PVOID DestinationBuffer,
+ IN ULONG DestinationOffset,
+ IN ULONG DestinationBufferSize,
+ OUT PULONG BytesCopied
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies data described by the source MDL chain starting at
+ the source offset, into a flat buffer specified by the SVA starting at
+ the destination offset. A maximum of DestinationBufferSize bytes can
+ be copied. The actual number of bytes copied is returned in BytesCopied.
+
+Arguments:
+
+ SourceMdlChain - Pointer to a chain of MDLs describing the source data.
+
+ SourceOffset - Number of bytes to skip in the source data.
+
+ DestinationBuffer - Pointer to a flat buffer to copy the data to.
+
+ DestinationOffset - Number of leading bytes to skip in the destination buffer.
+
+ DestinationBufferSize - Size of the output buffer, including the offset.
+
+ BytesCopied - Pointer to a longword where the actual number of bytes
+ transferred will be returned.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PUCHAR Dest, Src;
+ ULONG SrcBytesLeft, DestBytesLeft, BytesSkipped=0;
+
+ IF_TDIDBG (TDI_DEBUG_MAP) {
+ DbgPrint ("TdiCopyMdlToBuffer: Entered.\n");
+ }
+
+ ASSERT( DestinationBufferSize >= DestinationOffset );
+
+ *BytesCopied = 0;
+
+ //
+ // Skip source bytes.
+ //
+
+ Src = MmGetSystemAddressForMdl (SourceMdlChain);
+ SrcBytesLeft = MmGetMdlByteCount (SourceMdlChain);
+ while (BytesSkipped < SourceOffset) {
+ if (SrcBytesLeft > (SourceOffset - BytesSkipped)) {
+ // PANIC ("TdiCopyMdlToBuffer: Skipping part of this MDL.\n");
+ SrcBytesLeft -= (SourceOffset - BytesSkipped);
+ Src += (SourceOffset - BytesSkipped);
+ BytesSkipped = SourceOffset;
+ break;
+ } else if (SrcBytesLeft == (SourceOffset - BytesSkipped)) {
+ // PANIC ("TdiCopyMdlToBuffer: Skipping this exact MDL.\n");
+ SourceMdlChain = SourceMdlChain->Next;
+ if (SourceMdlChain == NULL) {
+ //PANIC ("TdiCopyMdlToBuffer: MDL chain was all header.\n");
+ return STATUS_SUCCESS; // no bytes copied.
+ }
+ BytesSkipped = SourceOffset;
+ Src = MmGetSystemAddressForMdl (SourceMdlChain);
+ SrcBytesLeft = MmGetMdlByteCount (SourceMdlChain);
+ break;
+ } else {
+ // PANIC ("TdiCopyMdlToBuffer: Skipping all of this MDL & more.\n");
+ BytesSkipped += SrcBytesLeft;
+ SourceMdlChain = SourceMdlChain->Next;
+ if (SourceMdlChain == NULL) {
+ //PANIC ("TdiCopyMdlToBuffer: Premature end of MDL chain.\n");
+ return STATUS_SUCCESS; // no bytes copied.
+ }
+ Src = MmGetSystemAddressForMdl (SourceMdlChain);
+ SrcBytesLeft = MmGetMdlByteCount (SourceMdlChain);
+ }
+ }
+
+ // PANIC ("TdiCopyMdlToBuffer: done skipping source bytes.\n");
+
+ //
+ // Skip destination bytes.
+ //
+
+ Dest = (PUCHAR)DestinationBuffer + DestinationOffset;
+ DestBytesLeft = DestinationBufferSize - DestinationOffset;
+
+ //
+ // Copy source data into the destination buffer until it's full or
+ // we run out of data, whichever comes first.
+ //
+
+ while (DestBytesLeft && SourceMdlChain) {
+ if (SrcBytesLeft == 0) {
+ // PANIC ("TdiCopyMdlToBuffer: MDL is empty, skipping to next one.\n");
+ SourceMdlChain = SourceMdlChain->Next;
+ if (SourceMdlChain == NULL) {
+ // PANIC ("TdiCopyMdlToBuffer: But there are no more MDLs.\n");
+ return STATUS_SUCCESS;
+ }
+ Src = MmGetSystemAddressForMdl (SourceMdlChain);
+ SrcBytesLeft = MmGetMdlByteCount (SourceMdlChain);
+ continue; // skip 0-length MDL's.
+ }
+ // PANIC ("TdiCopyMdlToBuffer: Copying a chunk.\n");
+ if (DestBytesLeft == SrcBytesLeft) {
+ // PANIC ("TdiCopyMdlToBuffer: Copying exact amount.\n");
+ RtlCopyBytes (Dest, Src, DestBytesLeft);
+ *BytesCopied += DestBytesLeft;
+ return STATUS_SUCCESS;
+ } else if (DestBytesLeft < SrcBytesLeft) {
+ // PANIC ("TdiCopyMdlToBuffer: Buffer overflow, copying some.\n");
+ RtlCopyBytes (Dest, Src, DestBytesLeft);
+ *BytesCopied += DestBytesLeft;
+ return STATUS_BUFFER_OVERFLOW;
+ } else {
+ // PANIC ("TdiCopyMdlToBuffer: Copying all of this MDL, & more.\n");
+ RtlCopyBytes (Dest, Src, SrcBytesLeft);
+ *BytesCopied += SrcBytesLeft;
+ DestBytesLeft -= SrcBytesLeft;
+ Dest += SrcBytesLeft;
+ SrcBytesLeft = 0;
+ }
+ }
+
+ return SourceMdlChain == NULL ? STATUS_SUCCESS : STATUS_BUFFER_OVERFLOW;
+} /* TdiCopyMdlToBuffer */
+
+
+NTSTATUS
+TdiCopyBufferToMdl (
+ IN PVOID SourceBuffer,
+ IN ULONG SourceOffset,
+ IN ULONG SourceBytesToCopy,
+ IN PMDL DestinationMdlChain,
+ IN ULONG DestinationOffset,
+ IN PULONG BytesCopied
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies data described by the source buffer to the MDL chain
+ described by the DestinationMdlChain. The
+
+Arguments:
+
+ SourceBuffer - pointer to the source buffer
+
+ SourceOffset - Number of bytes to skip in the source data.
+
+ SourceBytesToCopy - number of bytes to copy from the source buffer
+
+ DestinationMdlChain - Pointer to a chain of MDLs describing the
+ destination buffers.
+
+ DestinationOffset - Number of bytes to skip in the destination data.
+
+ BytesCopied - Pointer to a longword where the actual number of bytes
+ transferred will be returned.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PUCHAR Dest, Src;
+ ULONG DestBytesLeft, BytesSkipped=0;
+
+ IF_TDIDBG (TDI_DEBUG_MAP) {
+ DbgPrint ("TdiCopyBufferToMdl: Entered.\n");
+ }
+
+ *BytesCopied = 0;
+
+ //
+ // Skip Destination bytes.
+ //
+
+ Dest = MmGetSystemAddressForMdl (DestinationMdlChain);
+ DestBytesLeft = MmGetMdlByteCount (DestinationMdlChain);
+ while (BytesSkipped < DestinationOffset) {
+ if (DestBytesLeft > (DestinationOffset - BytesSkipped)) {
+ // PANIC ("TdiCopyMdlToBuffer: Skipping part of this MDL.\n");
+ DestBytesLeft -= (DestinationOffset - BytesSkipped);
+ Dest += (DestinationOffset - BytesSkipped);
+ BytesSkipped = DestinationOffset;
+ break;
+ } else if (DestBytesLeft == (DestinationOffset - BytesSkipped)) {
+ // PANIC ("TdiCopyMdlToBuffer: Skipping this exact MDL.\n");
+ DestinationMdlChain = DestinationMdlChain->Next;
+ if (DestinationMdlChain == NULL) {
+ //PANIC ("TdiCopyMdlToBuffer: MDL chain was all header.\n");
+ return STATUS_BUFFER_OVERFLOW; // no bytes copied.
+ }
+ BytesSkipped = DestinationOffset;
+ Dest = MmGetSystemAddressForMdl (DestinationMdlChain);
+ DestBytesLeft = MmGetMdlByteCount (DestinationMdlChain);
+ break;
+ } else {
+ // PANIC ("TdiCopyMdlToBuffer: Skipping all of this MDL & more.\n");
+ BytesSkipped += DestBytesLeft;
+ DestinationMdlChain = DestinationMdlChain->Next;
+ if (DestinationMdlChain == NULL) {
+ //PANIC ("TdiCopyMdlToBuffer: Premature end of MDL chain.\n");
+ return STATUS_BUFFER_OVERFLOW; // no bytes copied.
+ }
+ Dest = MmGetSystemAddressForMdl (DestinationMdlChain);
+ DestBytesLeft = MmGetMdlByteCount (DestinationMdlChain);
+ }
+ }
+
+ // PANIC ("TdiCopyMdlToBuffer: done skipping source bytes.\n");
+
+ //
+ // Skip source bytes.
+ //
+
+ Src = (PUCHAR)SourceBuffer + SourceOffset;
+
+ //
+ // Copy source data into the destination buffer until it's full or
+ // we run out of data, whichever comes first.
+ //
+
+ while ((SourceBytesToCopy != 0) && (DestinationMdlChain != NULL)) {
+ if (DestBytesLeft == 0) {
+ // PANIC ("TdiCopyMdlToBuffer: MDL is empty, skipping to next one.\n");
+ DestinationMdlChain = DestinationMdlChain->Next;
+ if (DestinationMdlChain == NULL) {
+ // PANIC ("TdiCopyMdlToBuffer: But there are no more MDLs.\n");
+ return STATUS_BUFFER_OVERFLOW;
+ }
+ Dest = MmGetSystemAddressForMdl (DestinationMdlChain);
+ DestBytesLeft = MmGetMdlByteCount (DestinationMdlChain);
+ continue; // skip 0-length MDL's.
+ }
+
+ // PANIC ("TdiCopyMdlToBuffer: Copying a chunk.\n");
+ if (DestBytesLeft >= SourceBytesToCopy) {
+ // PANIC ("TdiCopyMdlToBuffer: Copying exact amount.\n");
+ RtlCopyBytes (Dest, Src, SourceBytesToCopy);
+ *BytesCopied += SourceBytesToCopy;
+ return STATUS_SUCCESS;
+ } else {
+ // PANIC ("TdiCopyMdlToBuffer: Copying all of this MDL, & more.\n");
+ RtlCopyBytes (Dest, Src, DestBytesLeft);
+ *BytesCopied += DestBytesLeft;
+ SourceBytesToCopy -= DestBytesLeft;
+ Src += DestBytesLeft;
+ DestBytesLeft = 0;
+ }
+ }
+
+ return SourceBytesToCopy == 0 ? STATUS_SUCCESS : STATUS_BUFFER_OVERFLOW;
+
+} /* TdiCopyBufferToMdl */
+
+
+NTSTATUS
+TdiOpenNetbiosAddress (
+ IN OUT PHANDLE FileHandle,
+ IN PUCHAR Buffer,
+ IN PVOID DeviceName,
+ IN PVOID Address)
+
+/*++
+
+Routine Description:
+
+ Opens an address on the given file handle and device.
+
+Arguments:
+
+ FileHandle - the returned handle to the file object that is opened.
+
+ Buffer - pointer to a buffer that the ea is to be built in. This buffer
+ must be at least 40 bytes long.
+
+ DeviceName - the Unicode string that points to the device object.
+
+ Name - the address to be registered. If this pointer is NULL, the routine
+ will attempt to open a "control channel" to the device; that is, it
+ will attempt to open the file object with a null ea pointer, and if the
+ transport provider allows for that, will return that handle.
+
+Return Value:
+
+ An informative error code if something goes wrong. STATUS_SUCCESS if the
+ returned file handle is valid.
+
+--*/
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PFILE_FULL_EA_INFORMATION EaBuffer;
+ TA_NETBIOS_ADDRESS NetbiosAddress;
+ PSZ Name;
+ ULONG Length;
+
+ IF_TDIDBG (TDI_DEBUG_NAMES) {
+ DbgPrint ("TdiOpenNetbiosAddress: Opening ");
+ if (Address == NULL) {
+ DbgPrint (" Control Channel");
+ } else {
+ DbgPrint (Address);
+ }
+ DbgPrint (".\n");
+ }
+
+ if (Address != NULL) {
+ Name = (PSZ)Address;
+ try {
+ Length = FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) +
+ TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
+ sizeof(TA_NETBIOS_ADDRESS);
+ EaBuffer = (PFILE_FULL_EA_INFORMATION)Buffer;
+
+ if (EaBuffer == NULL) {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ EaBuffer->NextEntryOffset = 0;
+ EaBuffer->Flags = 0;
+ EaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
+ EaBuffer->EaValueLength = sizeof (TA_NETBIOS_ADDRESS);
+
+ RtlCopyMemory(
+ EaBuffer->EaName,
+ TdiTransportAddress,
+ EaBuffer->EaNameLength + 1
+ );
+
+ //
+ // Create a copy of the NETBIOS address descriptor in a local
+ // first, in order to avoid alignment problems.
+ //
+
+ NetbiosAddress.TAAddressCount = 1;
+ NetbiosAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ NetbiosAddress.Address[0].AddressLength =
+ sizeof (TDI_ADDRESS_NETBIOS);
+ NetbiosAddress.Address[0].Address[0].NetbiosNameType =
+ TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ RtlCopyMemory(
+ NetbiosAddress.Address[0].Address[0].NetbiosName,
+ Name,
+ 16
+ );
+
+ RtlCopyMemory (
+ &EaBuffer->EaName[EaBuffer->EaNameLength + 1],
+ &NetbiosAddress,
+ sizeof(TA_NETBIOS_ADDRESS)
+ );
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ //
+ // Couldn't touch the passed parameters; just return an error
+ // status.
+ //
+
+ return GetExceptionCode();
+ }
+ } else {
+ EaBuffer = NULL;
+ Length = 0;
+ }
+
+ InitializeObjectAttributes (
+ &ObjectAttributes,
+ DeviceName,
+ 0,
+ NULL,
+ NULL);
+
+ Status = NtCreateFile (
+ FileHandle,
+ FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, // desired access.
+ &ObjectAttributes, // object attributes.
+ &IoStatusBlock, // returned status information.
+ 0, // block size (unused).
+ 0, // file attributes.
+ FILE_SHARE_READ | FILE_SHARE_WRITE, // share access.
+ FILE_CREATE, // create disposition.
+ 0, // create options.
+ EaBuffer, // EA buffer.
+ Length); // EA length.
+
+ if (!NT_SUCCESS( Status )) {
+ IF_TDIDBG (TDI_DEBUG_NAMES) {
+ DbgPrint ("TdiOpenNetbiosEndpoint: FAILURE, NtCreateFile returned status %lx.\n", Status);
+ }
+ return Status;
+ }
+
+ Status = IoStatusBlock.Status;
+
+ if (!(NT_SUCCESS( Status ))) {
+ IF_TDIDBG (TDI_DEBUG_NAMES) {
+ DbgPrint ("TdiOpenNetbiosEndpoint: FAILURE, IoStatusBlock.Status contains status code=%lx.\n", Status);
+ }
+ }
+
+ return Status;
+} /* TdiOpenNetbiosAddress */
+
+
+
+VOID
+TdiReturnChainedReceives(
+ IN PVOID *TsduDescriptors,
+ IN ULONG NumberOfTsdus
+ )
+
+/*++
+
+Routine Description:
+
+ Used by a TDI client to return ownership of a set of chained receive TSDUs
+ to the NDIS layer. This routine may only be called if the client took
+ ownership of the TSDUs by returning STATUS_PENDING to one of the
+ CHAINED_RECEIVE indications.
+
+Arguments:
+
+ TsduDescriptors - An array of TSDU descriptors. Each descriptor was
+ provided in one of the CHAINED_RECEIVE indications. The descriptors
+ are actually pointers to the NDIS_PACKETS containing the TSDUs.
+
+ NumberOfTsdus - The count of TSDU descriptors in the TsduDescriptors array.
+
+Return Value:
+
+ None.
+--*/
+
+{
+ NdisReturnPackets(
+ (PNDIS_PACKET *) TsduDescriptors,
+ (UINT) NumberOfTsdus
+ );
+}
+
+VOID
+TdiInitialize(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ The TDI initialization routine, since our DriverEntry isn't called.
+ If we're not already initialized we'll initialize our lists heads.
+
+Arguments:
+
+ Nothing.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ // See if we're already initialized. If we're not,
+ // we won't have an initalized spinlock so we can't use that
+ // to serialize this. Instead, we interlocked increment a counter
+ // that is initially 0. If the counter goes to 1, we're the
+ // first one through here, so we'll do the initialization. Otherwise
+ // it's already been done, so we'll decrement the counter back
+ // to it's original state.
+
+ if (InterlockedIncrement(&TdiInitializationCount) == 1) {
+
+ // We're the first ones.
+ // Initialize the variables the register/deregister code uses.
+
+ KeInitializeSpinLock(&TDIListLock);
+
+ InitializeListHead(&BindClientList);
+
+ InitializeListHead(&NetAddressClientList);
+
+ InitializeListHead(&BindProviderList);
+
+ InitializeListHead(&NetAddressProviderList);
+
+ InitializeListHead(&BindRequestList);
+
+ InitializeListHead(&NetAddressRequestList);
+
+ NdisRegisterTdiCallBack(TdiRegisterDeviceObject);
+
+ } else {
+
+ // Already been done, just decrement the counter.
+ InterlockedDecrement(&TdiInitializationCount);
+ }
+}
+
diff --git a/private/ntos/tdi/wrapper/tdi.def b/private/ntos/tdi/wrapper/tdi.def
new file mode 100644
index 000000000..17886834f
--- /dev/null
+++ b/private/ntos/tdi/wrapper/tdi.def
@@ -0,0 +1,44 @@
+NAME TDI.SYS
+
+DESCRIPTION 'TDI.SYS'
+
+EXPORTS
+ TdiBuildNetbiosAddress
+ TdiBuildNetbiosAddressEa
+ TdiCopyBufferToMdl
+ TdiCopyMdlToBuffer
+ TdiDefaultConnectHandler
+ TdiDefaultDisconnectHandler
+ TdiDefaultErrorHandler
+ TdiDefaultRcvDatagramHandler
+ TdiDefaultRcvExpeditedHandler
+ TdiDefaultReceiveHandler
+ TdiMapBuffer
+ TdiMapUserRequest
+ TdiOpenNetbiosAddress
+ TdiUnmapBuffer
+ TdiDefaultSendPossibleHandler
+ CTEInitialize
+ CTEInitEvent
+ CTEScheduleEvent
+ CTEInitTimer
+ CTEStartTimer
+ CTESystemUpTime
+ CTEBlock
+ CTESignal
+ CTEInitString
+ CTEAllocateString
+ CTELogEvent
+ TdiDefaultChainedRcvDatagramHandler
+ TdiDefaultChainedRcvExpeditedHandler
+ TdiDefaultChainedReceiveHandler
+ TdiReturnChainedReceives
+ TdiRegisterNotificationHandler
+ TdiDeregisterNotificationHandler
+ TdiRegisterDeviceObject
+ TdiDeregisterDeviceObject
+ TdiRegisterAddressChangeHandler
+ TdiDeregisterAddressChangeHandler
+ TdiRegisterNetAddress
+ TdiDeregisterNetAddress
+ TdiInitialize
diff --git a/private/ntos/tdi/wrapper/tdi.pnp b/private/ntos/tdi/wrapper/tdi.pnp
new file mode 100644
index 000000000..17886834f
--- /dev/null
+++ b/private/ntos/tdi/wrapper/tdi.pnp
@@ -0,0 +1,44 @@
+NAME TDI.SYS
+
+DESCRIPTION 'TDI.SYS'
+
+EXPORTS
+ TdiBuildNetbiosAddress
+ TdiBuildNetbiosAddressEa
+ TdiCopyBufferToMdl
+ TdiCopyMdlToBuffer
+ TdiDefaultConnectHandler
+ TdiDefaultDisconnectHandler
+ TdiDefaultErrorHandler
+ TdiDefaultRcvDatagramHandler
+ TdiDefaultRcvExpeditedHandler
+ TdiDefaultReceiveHandler
+ TdiMapBuffer
+ TdiMapUserRequest
+ TdiOpenNetbiosAddress
+ TdiUnmapBuffer
+ TdiDefaultSendPossibleHandler
+ CTEInitialize
+ CTEInitEvent
+ CTEScheduleEvent
+ CTEInitTimer
+ CTEStartTimer
+ CTESystemUpTime
+ CTEBlock
+ CTESignal
+ CTEInitString
+ CTEAllocateString
+ CTELogEvent
+ TdiDefaultChainedRcvDatagramHandler
+ TdiDefaultChainedRcvExpeditedHandler
+ TdiDefaultChainedReceiveHandler
+ TdiReturnChainedReceives
+ TdiRegisterNotificationHandler
+ TdiDeregisterNotificationHandler
+ TdiRegisterDeviceObject
+ TdiDeregisterDeviceObject
+ TdiRegisterAddressChangeHandler
+ TdiDeregisterAddressChangeHandler
+ TdiRegisterNetAddress
+ TdiDeregisterNetAddress
+ TdiInitialize
diff --git a/private/ntos/tdi/wrapper/tdi.rc b/private/ntos/tdi/wrapper/tdi.rc
new file mode 100644
index 000000000..6882bb371
--- /dev/null
+++ b/private/ntos/tdi/wrapper/tdi.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "TDI Wrapper"
+#define VER_INTERNALNAME_STR "tdi.sys"
+#define VER_ORIGINALFILENAME_STR "tdi.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/tdi/wrapper/tdidebug.h b/private/ntos/tdi/wrapper/tdidebug.h
new file mode 100644
index 000000000..e4aba7eed
--- /dev/null
+++ b/private/ntos/tdi/wrapper/tdidebug.h
@@ -0,0 +1,52 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ tdidebug.h
+
+Abstract:
+
+ This module contains code which assists the process of debugging an NT
+ TDI client.
+
+Author:
+
+ David Beaver (dbeaver) 28 June 1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ All code moved in from other XNS and NBF locations at creation
+
+
+--*/
+
+#if DBG
+#include <stdarg.h>
+#include <stdio.h>
+
+VOID
+TdiPrintf(
+ char *Format,
+ ...
+ );
+
+VOID
+TdiFormattedDump(
+ PCHAR far_p,
+ ULONG len
+ );
+
+VOID
+TdiHexDumpLine(
+ PCHAR pch,
+ ULONG len,
+ PCHAR s,
+ PCHAR t
+ );
+#endif
diff --git a/private/ntos/tdi/wrapper/tdipnp.c b/private/ntos/tdi/wrapper/tdipnp.c
new file mode 100644
index 000000000..615e19715
--- /dev/null
+++ b/private/ntos/tdi/wrapper/tdipnp.c
@@ -0,0 +1,1029 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ tdipnp.c
+
+Abstract:
+
+ TDI routines for supporting PnP in transports and transport clients.
+
+Author:
+
+ Henry Sanders (henrysa) Oct. 10, 1995
+
+Revision History:
+
+ Who When What
+ -------- -------- ----------------------------------------------
+ henrysa 10-10-95 created
+
+Notes:
+
+--*/
+
+#include <ntddk.h>
+#include <ndis.h>
+#include <tdi.h>
+#include <tdikrnl.h>
+#include "tdipnp.h"
+
+KSPIN_LOCK TDIListLock;
+
+LIST_ENTRY BindClientList;
+
+LIST_ENTRY NetAddressClientList;
+
+LIST_ENTRY BindProviderList;
+
+LIST_ENTRY NetAddressProviderList;
+
+LIST_ENTRY BindRequestList;
+
+LIST_ENTRY NetAddressRequestList;
+
+BOOLEAN BindRequestInProgress;
+
+PETHREAD BindRequestThread;
+
+BOOLEAN AddressRequestInProgress;
+
+PETHREAD AddressRequestThread;
+
+VOID
+TdiNotifyClientList (
+ PLIST_ENTRY ListHead,
+ PVOID Info,
+ BOOLEAN Added
+)
+
+/*++
+
+Routine Description:
+
+ Called when a new provider is added or deleted. We walk the specified
+ client list and notify all of the clients of what just occured.
+
+Arguments:
+
+ ListHead - Head of list to walk.
+ Info - Information describing the provider that changed.
+ Added - True if a provider was added, false otherwise
+
+Return Value:
+
+
+
+--*/
+
+{
+ PLIST_ENTRY Current;
+ PTDI_PROVIDER_COMMON ProviderCommon;
+ PTDI_NOTIFY_ELEMENT NotifyElement;
+ PTDI_PROVIDER_RESOURCE Provider;
+
+ Current = ListHead->Flink;
+
+
+ // The Info parameter is actually a pointer to a PROVIDER_COMMON
+ // structure, so get back to that so that we can find out what kind of
+ // provider this is.
+
+ ProviderCommon = (PTDI_PROVIDER_COMMON)Info;
+
+ Provider = CONTAINING_RECORD(
+ ProviderCommon,
+ TDI_PROVIDER_RESOURCE,
+ Common
+ );
+
+ // Walk the input client list, and for every element in it
+ // notifhy the client.
+
+ while (Current != ListHead) {
+
+ NotifyElement = CONTAINING_RECORD(
+ Current,
+ TDI_NOTIFY_ELEMENT,
+ Common.Linkage
+ );
+
+ if (Provider->Common.Type == TDI_RESOURCE_DEVICE) {
+ // This is a device object provider.
+
+ // This must be a notify bind element.
+
+
+ // If this is a device coming in, call the bind handler,
+ // else call the unbind handler.
+
+ if (Added) {
+ (*(NotifyElement->Specific.BindElement.BindHandler))(
+ &Provider->Specific.Device.DeviceName
+ );
+ } else {
+ (*(NotifyElement->Specific.BindElement.UnbindHandler))(
+ &Provider->Specific.Device.DeviceName
+ );
+ }
+ } else {
+
+ // This is a notify net address element. If this is
+ // an address coming in, call the add address handler,
+ // otherwise call delete address handler.
+
+ if (Added) {
+ (*(NotifyElement->Specific.AddressElement.AddHandler))(
+ &Provider->Specific.NetAddress.Address
+ );
+ } else {
+ (*(NotifyElement->Specific.AddressElement.DeleteHandler))(
+ &Provider->Specific.NetAddress.Address
+ );
+ }
+ }
+
+ // Get the next one.
+
+ Current = Current->Flink;
+
+ }
+}
+
+VOID
+TdiNotifyNewClient (
+ PLIST_ENTRY ListHead,
+ PVOID Info
+)
+
+/*++
+
+Routine Description:
+
+ Called when a new client is added and we want to notify it of existing
+ providers. The client can be for either binds or net addresses. We
+ walk the specified input list, and notify the client about each entry in
+ it.
+
+Arguments:
+
+ ListHead - Head of list to walk.
+ Info - Information describing the new client to be notified.
+
+Return Value:
+
+
+
+--*/
+
+{
+ PLIST_ENTRY CurrentEntry;
+ PTDI_NOTIFY_COMMON NotifyCommon;
+ PTDI_PROVIDER_RESOURCE Provider;
+ PTDI_NOTIFY_ELEMENT NotifyElement;
+
+ CurrentEntry = ListHead->Flink;
+
+ // The info is actually a pointer to a client notify element. Cast
+ // it to the common type.
+
+ NotifyCommon = (PTDI_NOTIFY_COMMON)Info;
+
+ // Walk the input provider list, and for every element in it notify
+ // the new client.
+
+ while (CurrentEntry != ListHead) {
+
+ // If the new client is for bind notifys, set up to call it's bind
+ // handler.
+
+ // Put the current provider element into the proper form.
+
+ Provider = CONTAINING_RECORD(
+ CurrentEntry,
+ TDI_PROVIDER_RESOURCE,
+ Common.Linkage
+ );
+
+ NotifyElement = CONTAINING_RECORD(
+ NotifyCommon,
+ TDI_NOTIFY_ELEMENT,
+ Common
+ );
+
+ if (NotifyCommon->Type == TDI_NOTIFY_DEVICE) {
+
+ // This is a bind notify client.
+
+
+
+ (*(NotifyElement->Specific.BindElement.BindHandler))(
+ &Provider->Specific.Device.DeviceName
+ );
+
+ } else {
+ // This is an address notify client.
+
+ (*(NotifyElement->Specific.AddressElement.AddHandler))(
+ &Provider->Specific.NetAddress.Address
+ );
+ }
+
+ // And do the next one.
+
+ CurrentEntry = CurrentEntry->Flink;
+
+ }
+}
+
+NTSTATUS
+TdiHandleSerializedRequest (
+ PVOID RequestInfo,
+ UINT RequestType
+)
+
+/*++
+
+Routine Description:
+
+ Called when we want to process a request relating to one of the
+ lists we manage. We look to see if we are currently processing such
+ a request - if we are, we queue this for later. Otherwise we'll
+ remember that we are doing this, and we'll process this request.
+ When we're done we'll look to see if any more came in while we were
+ busy.
+
+Arguments:
+
+ RequestInfo - Reqeust specific information.
+ RequestType - The type of the request.
+
+Return Value:
+
+ Request completion status.
+
+
+--*/
+
+{
+ KIRQL OldIrql;
+ PLIST_ENTRY List;
+ PLIST_ENTRY ClientList;
+ PLIST_ENTRY ProviderList;
+ PLIST_ENTRY RequestList;
+ PBOOLEAN SerializeFlag;
+ PETHREAD *RequestThread;
+ PTDI_SERIALIZED_REQUEST Request;
+ PKEVENT BlockedEvent = NULL;
+ PTDI_NOTIFY_COMMON NotifyElement;
+ PTDI_PROVIDER_RESOURCE ProviderElement;
+
+ ExAcquireSpinLock(
+ &TDIListLock,
+ &OldIrql
+ );
+
+ if (RequestType <= TDI_MAX_BIND_REQUEST) {
+ ClientList = &BindClientList;
+ ProviderList = &BindProviderList;
+ RequestList = &BindRequestList;
+ SerializeFlag = &BindRequestInProgress;
+ RequestThread = &BindRequestThread;
+ } else {
+ ClientList = &NetAddressClientList;
+ ProviderList = &NetAddressProviderList;
+ RequestList = &NetAddressRequestList;
+ SerializeFlag = &AddressRequestInProgress;
+ RequestThread = &AddressRequestThread;
+ }
+
+ // If we're not already here, handle it right away.
+
+ if (!(*SerializeFlag)) {
+
+ *SerializeFlag = TRUE;
+
+ // Save the identity of the thread we're doing this in in case someone
+ // tries to delete a client, which needs to block. In that case we'll
+ // check to make sure it's not being done in the same thread we're using
+ // to prevent deadlock.
+
+ *RequestThread = PsGetCurrentThread();
+
+ for (;;) {
+
+ // We're done with the lock for now, so free it.
+
+ ExReleaseSpinLock(
+ &TDIListLock,
+ OldIrql
+ );
+
+ // Figure out the type of request we have here.
+
+ switch (RequestType) {
+ case TDI_REGISTER_BIND_NOTIFY:
+ case TDI_REGISTER_ADDRESS_NOTIFY:
+ // This is a client register bind or address handler request.
+
+ // Insert this one into the registered client list.
+ NotifyElement = (PTDI_NOTIFY_COMMON)RequestInfo;
+ InsertTailList(
+ ClientList,
+ &NotifyElement->Linkage,
+ );
+
+ // Call TdiNotifyNewClient to notify this new client of all
+ // all existing providers.
+
+ TdiNotifyNewClient(
+ ProviderList,
+ RequestInfo
+ );
+
+ break;
+
+ case TDI_DEREGISTER_BIND_NOTIFY:
+ case TDI_DEREGISTER_ADDRESS_NOTIFY:
+
+ // This is a client deregister request. Pull him from the
+ // client list, free it, and we're done.
+
+ NotifyElement = (PTDI_NOTIFY_COMMON)RequestInfo;
+ RemoveEntryList(&NotifyElement->Linkage);
+
+ ExFreePool(NotifyElement);
+
+ break;
+
+ case TDI_REGISTER_DEVICE:
+ case TDI_REGISTER_ADDRESS:
+
+ // A provider is registering a device or address. Add him to
+ // the appropriate provider list, and then notify all
+ // existing clients of the new device.
+
+ ProviderElement = (PTDI_PROVIDER_RESOURCE)RequestInfo;
+
+ InsertTailList(
+ ProviderList,
+ &ProviderElement->Common.Linkage
+ );
+
+ // Call TdiNotifyClientList to do the hard work.
+
+ TdiNotifyClientList(
+ ClientList,
+ RequestInfo,
+ TRUE
+ );
+ break;
+
+ case TDI_DEREGISTER_DEVICE:
+ case TDI_DEREGISTER_ADDRESS:
+
+ // A provider device or address is deregistering. Pull the
+ // resource from the provider list, and notify clients that
+ // he's gone.
+
+ ProviderElement = (PTDI_PROVIDER_RESOURCE)RequestInfo;
+ RemoveEntryList(&ProviderElement->Common.Linkage);
+
+ TdiNotifyClientList(
+ ClientList,
+ RequestInfo,
+ FALSE
+ );
+
+ // Free the tracking structure we had.
+
+ if (RequestType == TDI_DEREGISTER_DEVICE) {
+ ExFreePool(ProviderElement->Specific.Device.DeviceName.Buffer);
+ }
+ ExFreePool(ProviderElement);
+
+ break;
+ default:
+ break;
+ }
+
+ // If there was an event specified with this request, signal
+ // it now. This should only be a client deregister request, which
+ // needs to block until it's completed.
+
+ if (BlockedEvent != NULL) {
+ KeSetEvent(BlockedEvent, 0, FALSE);
+ }
+
+ // Get the lock, and see if more requests have come in while
+ // we've been busy. If they have, we'll service them now, otherwise
+ // we'll clear the in progress flag and exit.
+
+ ExAcquireSpinLock(
+ &TDIListLock,
+ &OldIrql
+ );
+
+ if (!IsListEmpty(RequestList)) {
+
+ // The request list isn't empty. Pull the next one from
+ // the list and process it.
+
+ List = RemoveHeadList(RequestList);
+
+ Request = CONTAINING_RECORD(List, TDI_SERIALIZED_REQUEST, Linkage);
+
+ RequestInfo = Request->Element;
+ RequestType = Request->Type;
+ BlockedEvent = Request->Event;
+
+ ExFreePool(Request);
+
+ } else {
+
+ // The request list is empty. Clear the flag and we're done.
+
+ *SerializeFlag = FALSE;
+
+ ExReleaseSpinLock(
+ &TDIListLock,
+ OldIrql
+ );
+ break;
+ }
+ }
+
+ return STATUS_SUCCESS;
+ } else {
+
+ // We're already running, so we'll have to queue. If this is a
+ // deregister bind or address notify call, we'll see if the issueing
+ // thread is the same one that is currently busy. If so, we'll fail
+ // to avoid deadlock. Otherwise for deregister calls we'll block until
+ // it's done.
+
+ Request = (PTDI_SERIALIZED_REQUEST)ExAllocatePool(
+ NonPagedPool,
+ sizeof(TDI_SERIALIZED_REQUEST)
+ );
+
+ if (Request == NULL) {
+
+ // Couldn't get a request.
+
+ ExReleaseSpinLock(
+ &TDIListLock,
+ OldIrql
+ );
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Got the request.
+ Request->Element = RequestInfo;
+ Request->Type = RequestType;
+ Request->Event = NULL;
+
+ if (
+ RequestType == TDI_DEREGISTER_BIND_NOTIFY ||
+ RequestType == TDI_REGISTER_BIND_NOTIFY ||
+ RequestType == TDI_DEREGISTER_ADDRESS_NOTIFY
+ ) {
+
+ // This is a deregister request. See if it's the same thread
+ // that's busy. If not, block for it to complete.
+
+ if (*RequestThread == PsGetCurrentThread()) {
+
+ // It's the same one, so give up now.
+ ExReleaseSpinLock(
+ &TDIListLock,
+ OldIrql
+ );
+
+ ExFreePool(Request);
+
+ return STATUS_NETWORK_BUSY;
+ } else {
+ // He's not currently busy, go ahead and block.
+
+ KEVENT Event;
+ NTSTATUS Status;
+
+ KeInitializeEvent(
+ &Event,
+ SynchronizationEvent,
+ FALSE
+ );
+
+ Request->Event = &Event;
+
+ // Put this guy on the end of the request list.
+
+ InsertTailList(RequestList, &Request->Linkage);
+
+ ExReleaseSpinLock(
+ &TDIListLock,
+ OldIrql
+ );
+
+ Status = KeWaitForSingleObject(
+ &Event,
+ UserRequest,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ // I don't know what we'd do is the wait failed....
+
+ return STATUS_SUCCESS;
+ }
+ } else {
+
+ // This isn't a deregister request, so there's no special handling
+ // necessary. Just put the request on the end of the list.
+
+ InsertTailList(RequestList, &Request->Linkage);
+
+ ExReleaseSpinLock(
+ &TDIListLock,
+ OldIrql
+ );
+
+ return STATUS_SUCCESS;
+ }
+ }
+
+}
+
+NTSTATUS
+TdiRegisterNotificationHandler(
+ IN TDI_BIND_HANDLER BindHandler,
+ IN TDI_UNBIND_HANDLER UnbindHandler,
+ OUT HANDLE *BindingHandle
+)
+
+/*++
+
+Routine Description:
+
+ This function is called when a TDI client wants to register for
+ notification of the arrival of TDI providers. We allocate a
+ TDI_NOTIFY_ELEMENT for the provider and then call the serialized
+ worker routine to do the real work.
+
+Arguments:
+
+ BindHandler - A pointer to the routine to be called when
+ a new provider arrives.
+ UnbindHandler - A pointer to the routine to be called when a
+ provider leaves.
+ BindingHandle - A handle we pass back that identifies this
+ client to us.
+
+Return Value:
+
+ The status of the attempt to register the client.
+
+--*/
+
+
+{
+ PTDI_NOTIFY_ELEMENT NewElement;
+ NTSTATUS Status;
+
+ //
+ // Make sure Tdi is intialized. If there are no pnp transports, then this is
+ // called by the tdi client and if tdi is not initialized, it is toast
+ // Multiple calls to TdiIntialize are safe since only the first one does
+ // the real work
+ //
+ TdiInitialize();
+
+
+ // First, try and allocate the needed resource.
+
+ NewElement = (PTDI_NOTIFY_ELEMENT)ExAllocatePool(
+ NonPagedPool,
+ sizeof(TDI_NOTIFY_ELEMENT)
+ );
+
+ // If we couldn't get it, fail the request.
+ if (NewElement == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Fill in the basic stuff.
+ NewElement->Common.Type = TDI_NOTIFY_DEVICE;
+ NewElement->Specific.BindElement.BindHandler = BindHandler;
+ NewElement->Specific.BindElement.UnbindHandler = UnbindHandler;
+
+ *BindingHandle = (HANDLE)NewElement;
+
+
+ // Now call HandleBindRequest to handle this one.
+
+ Status = TdiHandleSerializedRequest(
+ NewElement,
+ TDI_REGISTER_BIND_NOTIFY
+ );
+
+ if (Status != STATUS_SUCCESS) {
+ ExFreePool(NewElement);
+ }
+
+ return Status;
+
+
+}
+
+NTSTATUS
+TdiDeregisterNotificationHandler(
+ IN HANDLE BindingHandle
+)
+
+/*++
+
+Routine Description:
+
+ This function is called when a TDI client wants to deregister a
+ previously registered bind notification handler. All we really
+ do is call TdiHandleSerializedRequest, which does the hard work.
+
+Arguments:
+
+ BindingHandle - A handle we passed back to the client
+ on the register call. This is really
+ a pointer to the notify element.
+
+Return Value:
+
+ The status of the attempt to deregister the client.
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ Status = TdiHandleSerializedRequest(
+ BindingHandle,
+ TDI_DEREGISTER_BIND_NOTIFY
+ );
+
+ return Status;
+
+}
+
+NTSTATUS
+TdiRegisterDeviceObject(
+ IN PUNICODE_STRING DeviceName,
+ OUT HANDLE *RegistrationHandle
+)
+
+/*++
+
+Routine Description:
+
+ Called when a TDI provider wants to register a device object.
+
+Arguments:
+
+ DeviceName - Name of the device to be registered.
+
+ RegistrationHandle - A handle we pass back to the provider,
+ identifying this registration.
+
+Return Value:
+
+ The status of the attempt to register the provider.
+
+--*/
+
+
+{
+ PTDI_PROVIDER_RESOURCE NewResource;
+ NTSTATUS Status;
+ PWCHAR Buffer;
+
+ TdiInitialize();
+
+ // First, try and allocate the needed resource.
+
+ NewResource = (PTDI_PROVIDER_RESOURCE)ExAllocatePool(
+ NonPagedPool,
+ sizeof(TDI_PROVIDER_RESOURCE)
+ );
+
+ // If we couldn't get it, fail the request.
+ if (NewResource == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ // Try and get a buffer to hold the name.
+
+ Buffer = (PWCHAR)ExAllocatePool(
+ NonPagedPool,
+ DeviceName->MaximumLength
+ );
+
+ if (Buffer == NULL) {
+ ExFreePool(NewResource);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ // Fill in the basic stuff.
+ NewResource->Common.Type = TDI_RESOURCE_DEVICE;
+ NewResource->Specific.Device.DeviceName.MaximumLength =
+ DeviceName->MaximumLength;
+
+ NewResource->Specific.Device.DeviceName.Buffer = Buffer;
+
+ RtlCopyUnicodeString(
+ &NewResource->Specific.Device.DeviceName,
+ DeviceName
+ );
+
+ *RegistrationHandle = (HANDLE)NewResource;
+
+
+ // Now call HandleBindRequest to handle this one.
+
+ Status = TdiHandleSerializedRequest(
+ NewResource,
+ TDI_REGISTER_DEVICE
+ );
+
+ if (Status != STATUS_SUCCESS) {
+ ExFreePool(Buffer);
+ ExFreePool(NewResource);
+ }
+
+ return Status;
+
+
+}
+
+NTSTATUS
+TdiDeregisterDeviceObject(
+ IN HANDLE RegistrationHandle
+)
+
+/*++
+
+Routine Description:
+
+ This function is called when a TDI provider want's to deregister
+ a device object.
+
+Arguments:
+
+ RegistrationHandle - A handle we passed back to the provider
+ on the register call. This is really
+ a pointer to the resource element.
+
+Return Value:
+
+ The status of the attempt to deregister the provider.
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ Status = TdiHandleSerializedRequest(
+ RegistrationHandle,
+ TDI_DEREGISTER_DEVICE
+ );
+
+ return Status;
+
+}
+
+NTSTATUS
+TdiRegisterAddressChangeHandler(
+ IN TDI_ADD_ADDRESS_HANDLER AddHandler,
+ IN TDI_DEL_ADDRESS_HANDLER DeleteHandler,
+ OUT HANDLE *BindingHandle
+)
+
+/*++
+
+Routine Description:
+
+ This function is called when a TDI client wants to register for
+ notification of the arrival of network addresses. We allocate a
+ TDI_NOTIFY_ELEMENT for the provider and then call the serialized
+ worker routine to do the real work.
+
+Arguments:
+
+ AddHandler - A pointer to the routine to be called when
+ a new address arrives.
+ DeleteHandler - A pointer to the routine to be called when an
+ address leaves.
+ BindingHandle - A handle we pass back that identifies this
+ client to us.
+
+Return Value:
+
+ The status of the attempt to register the client.
+
+--*/
+
+
+{
+ PTDI_NOTIFY_ELEMENT NewElement;
+ NTSTATUS Status;
+
+
+ // First, try and allocate the needed resource.
+
+ NewElement = (PTDI_NOTIFY_ELEMENT)ExAllocatePool(
+ NonPagedPool,
+ sizeof(TDI_NOTIFY_ELEMENT)
+ );
+
+ // If we couldn't get it, fail the request.
+ if (NewElement == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Fill in the basic stuff.
+ NewElement->Common.Type = TDI_NOTIFY_NET_ADDRESS;
+ NewElement->Specific.AddressElement.AddHandler = AddHandler;
+ NewElement->Specific.AddressElement.DeleteHandler = DeleteHandler;
+
+ *BindingHandle = (HANDLE)NewElement;
+
+
+ // Now call HandleBindRequest to handle this one.
+
+ Status = TdiHandleSerializedRequest(
+ NewElement,
+ TDI_REGISTER_ADDRESS_NOTIFY
+ );
+
+ if (Status != STATUS_SUCCESS) {
+ ExFreePool(NewElement);
+ }
+
+ return Status;
+
+
+}
+
+NTSTATUS
+TdiDeregisterAddressChangeHandler(
+ IN HANDLE BindingHandle
+)
+
+/*++
+
+Routine Description:
+
+ This function is called when a TDI client wants to deregister a
+ previously registered address change notification handler. All we
+ really do is call TdiHandleSerializedRequest, which does the hard work.
+
+Arguments:
+
+ BindingHandle - A handle we passed back to the client
+ on the register call. This is really
+ a pointer to the notify element.
+
+Return Value:
+
+ The status of the attempt to deregister the client.
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ Status = TdiHandleSerializedRequest(
+ BindingHandle,
+ TDI_DEREGISTER_ADDRESS_NOTIFY
+ );
+
+ return Status;
+
+}
+
+NTSTATUS
+TdiRegisterNetAddress(
+ IN PTA_ADDRESS Address,
+ OUT HANDLE *RegistrationHandle
+)
+
+/*++
+
+Routine Description:
+
+ Called when a TDI provider wants to register a new net address.
+
+Arguments:
+
+ Address - New net address to be registered.
+
+ RegistrationHandle - A handle we pass back to the provider,
+ identifying this registration.
+
+Return Value:
+
+ The status of the attempt to register the provider.
+
+--*/
+
+
+{
+ PTDI_PROVIDER_RESOURCE NewResource;
+ NTSTATUS Status;
+
+ // First, try and allocate the needed resource.
+
+ NewResource = (PTDI_PROVIDER_RESOURCE)ExAllocatePool(
+ NonPagedPool,
+ FIELD_OFFSET(
+ TDI_PROVIDER_RESOURCE,
+ Specific.NetAddress
+ ) +
+ FIELD_OFFSET(TA_ADDRESS, Address) +
+ Address->AddressLength
+ );
+
+ // If we couldn't get it, fail the request.
+ if (NewResource == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Fill in the basic stuff.
+ NewResource->Common.Type = TDI_RESOURCE_DEVICE;
+ NewResource->Specific.NetAddress.Address.AddressLength =
+ Address->AddressLength;
+
+ NewResource->Specific.NetAddress.Address.AddressType =
+ Address->AddressType;
+
+ RtlCopyMemory(
+ NewResource->Specific.NetAddress.Address.Address,
+ Address->Address,
+ Address->AddressLength
+ );
+
+ *RegistrationHandle = (HANDLE)NewResource;
+
+
+ // Now call HandleBindRequest to handle this one.
+
+ Status = TdiHandleSerializedRequest(
+ NewResource,
+ TDI_REGISTER_ADDRESS
+ );
+
+ if (Status != STATUS_SUCCESS) {
+ ExFreePool(NewResource);
+ }
+
+ return Status;
+
+
+}
+
+NTSTATUS
+TdiDeregisterNetAddress(
+ IN HANDLE RegistrationHandle
+)
+
+/*++
+
+Routine Description:
+
+ This function is called when a TDI provider wants to deregister
+ a net addres.
+
+Arguments:
+
+ RegistrationHandle - A handle we passed back to the provider
+ on the register call. This is really
+ a pointer to the resource element.
+
+Return Value:
+
+ The status of the attempt to deregister the provider.
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ Status = TdiHandleSerializedRequest(
+ RegistrationHandle,
+ TDI_DEREGISTER_ADDRESS
+ );
+
+ return Status;
+
+}
+
diff --git a/private/ntos/tdi/wrapper/tdipnp.h b/private/ntos/tdi/wrapper/tdipnp.h
new file mode 100644
index 000000000..ae98e7d02
--- /dev/null
+++ b/private/ntos/tdi/wrapper/tdipnp.h
@@ -0,0 +1,163 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ tdipnp.h
+
+Abstract:
+
+ This module contains the definitions for the PnP related code
+ in the TDI driver.
+
+Author:
+
+ Henry Sanders (henrysa) 11 Oct 1995
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+
+--*/
+
+#ifndef _TDIPNP_
+#define _TDIPNP_
+
+// Define the types possible for a TDI_NOTIFY_ELEMENT structure.
+
+#define TDI_NOTIFY_DEVICE 0
+#define TDI_NOTIFY_NET_ADDRESS 1
+
+
+// And the types possible for a TDI_PROVIDER_RESOURCE structure.
+
+#define TDI_RESOURCE_DEVICE 0
+#define TDI_RESOURCE_NET_ADDRESS 1
+
+//
+// Define the types of bind requests possible.
+
+#define TDI_REGISTER_BIND_NOTIFY 0
+#define TDI_DEREGISTER_BIND_NOTIFY 1
+#define TDI_REGISTER_DEVICE 2
+#define TDI_DEREGISTER_DEVICE 3
+#define TDI_REGISTER_ADDRESS_NOTIFY 4
+#define TDI_DEREGISTER_ADDRESS_NOTIFY 5
+#define TDI_REGISTER_ADDRESS 6
+#define TDI_DEREGISTER_ADDRESS 7
+
+#define TDI_MAX_BIND_REQUEST TDI_DEREGISTER_DEVICE
+
+//
+// This is the definition of the common part of a TDI_NOTIFY_ELEMENT structure.
+//
+
+typedef struct _TDI_NOTIFY_COMMON {
+ LIST_ENTRY Linkage;
+ UCHAR Type;
+} TDI_NOTIFY_COMMON, *PTDI_NOTIFY_COMMON;
+
+//
+// The definition of the TDI_NOTIFY_BIND structure.
+//
+
+typedef struct _TDI_NOTIFY_BIND {
+ TDI_BIND_HANDLER BindHandler;
+ TDI_UNBIND_HANDLER UnbindHandler;
+} TDI_NOTIFY_BIND, *PTDI_NOTIFY_BIND;
+
+//
+// The definition of a TDI_NOTIFY_ADDRESS structure,
+//
+typedef struct _TDI_NOTIFY_ADDRESS {
+ TDI_ADD_ADDRESS_HANDLER AddHandler;
+ TDI_DEL_ADDRESS_HANDLER DeleteHandler;
+} TDI_NOTIFY_ADDRESS, *PTDI_NOTIFY_ADDRESS;
+
+
+//
+// This is the definition of a TDI_NOTIFY_ELEMENT stucture.
+//
+
+typedef struct _TDI_NOTIFY_ELEMENT {
+ TDI_NOTIFY_COMMON Common;
+ union {
+ TDI_NOTIFY_BIND BindElement;
+ TDI_NOTIFY_ADDRESS AddressElement;
+ } Specific;
+} TDI_NOTIFY_ELEMENT, *PTDI_NOTIFY_ELEMENT;
+
+
+//
+// This is the definition of the common part of a TDI_PROVIDER_RESOURCE structure.
+//
+
+typedef struct _TDI_PROVIDER_COMMON {
+ LIST_ENTRY Linkage;
+ UCHAR Type;
+} TDI_PROVIDER_COMMON, *PTDI_PROVIDER_COMMON;
+
+//
+// The definition of the TDI_PROVIDER_DEVICE structure.
+//
+
+typedef struct _TDI_PROVIDER_DEVICE {
+ UNICODE_STRING DeviceName;
+} TDI_PROVIDER_DEVICE, *PTDI_PROVIDER_DEVICE;
+
+//
+// The definition of the TDI_PROVIDER_NET_ADDRESS structure.
+//
+
+typedef struct _TDI_PROVIDER_NET_ADDRESS {
+ TA_ADDRESS Address;
+} TDI_PROVIDER_NET_ADDRESS, *PTDI_PROVIDER_NET_ADDRESS;
+
+//
+// This is the definition of a TDI_PROVIDER_RESOURCE stucture.
+//
+
+typedef struct _TDI_PROVIDER_RESOURCE {
+ TDI_PROVIDER_COMMON Common;
+ union {
+ TDI_PROVIDER_DEVICE Device;
+ TDI_PROVIDER_NET_ADDRESS NetAddress;
+ } Specific;
+} TDI_PROVIDER_RESOURCE, *PTDI_PROVIDER_RESOURCE;
+
+//
+// Structure of a bind list request.
+//
+
+typedef struct _TDI_SERIALIZED_REQUEST {
+ LIST_ENTRY Linkage;
+ PVOID Element;
+ UINT Type;
+ PKEVENT Event;
+
+} TDI_SERIALIZED_REQUEST, *PTDI_SERIALIZED_REQUEST;
+
+
+// External defintions for global variables.
+
+extern KSPIN_LOCK TDIListLock;
+
+extern LIST_ENTRY BindClientList;
+
+extern LIST_ENTRY NetAddressClientList;
+
+extern LIST_ENTRY BindProviderList;
+
+extern LIST_ENTRY NetAddressProviderList;
+
+extern LIST_ENTRY BindRequestList;
+
+extern LIST_ENTRY NetAddressRequestList;
+
+
+#endif // _TDIPNP